summaryrefslogtreecommitdiffstats
path: root/chromium/cc
diff options
context:
space:
mode:
authorJocelyn Turcotte <jocelyn.turcotte@digia.com>2014-08-08 14:30:41 +0200
committerJocelyn Turcotte <jocelyn.turcotte@digia.com>2014-08-12 13:49:54 +0200
commitab0a50979b9eb4dfa3320eff7e187e41efedf7a9 (patch)
tree498dfb8a97ff3361a9f7486863a52bb4e26bb898 /chromium/cc
parent4ce69f7403811819800e7c5ae1318b2647e778d1 (diff)
Update Chromium to beta version 37.0.2062.68
Change-Id: I188e3b5aff1bec75566014291b654eb19f5bc8ca Reviewed-by: Andras Becsi <andras.becsi@digia.com>
Diffstat (limited to 'chromium/cc')
-rw-r--r--chromium/cc/BUILD.gn789
-rw-r--r--chromium/cc/DEPS8
-rw-r--r--chromium/cc/OWNERS1
-rw-r--r--chromium/cc/PRESUBMIT.py98
-rw-r--r--chromium/cc/animation/animation.cc108
-rw-r--r--chromium/cc/animation/animation.h77
-rw-r--r--chromium/cc/animation/animation_curve.h11
-rw-r--r--chromium/cc/animation/animation_delegate.h4
-rw-r--r--chromium/cc/animation/animation_events.cc2
-rw-r--r--chromium/cc/animation/animation_events.h4
-rw-r--r--chromium/cc/animation/animation_unittest.cc407
-rw-r--r--chromium/cc/animation/keyframed_animation_curve.cc49
-rw-r--r--chromium/cc/animation/keyframed_animation_curve.h4
-rw-r--r--chromium/cc/animation/keyframed_animation_curve_unittest.cc96
-rw-r--r--chromium/cc/animation/layer_animation_controller.cc640
-rw-r--r--chromium/cc/animation/layer_animation_controller.h77
-rw-r--r--chromium/cc/animation/layer_animation_controller_unittest.cc800
-rw-r--r--chromium/cc/animation/layer_animation_value_observer.h2
-rw-r--r--chromium/cc/animation/scroll_offset_animation_curve.cc24
-rw-r--r--chromium/cc/animation/scroll_offset_animation_curve.h9
-rw-r--r--chromium/cc/animation/scrollbar_animation_controller.cc96
-rw-r--r--chromium/cc/animation/scrollbar_animation_controller.h56
-rw-r--r--chromium/cc/animation/scrollbar_animation_controller_linear_fade.cc125
-rw-r--r--chromium/cc/animation/scrollbar_animation_controller_linear_fade.h35
-rw-r--r--chromium/cc/animation/scrollbar_animation_controller_linear_fade_unittest.cc173
-rw-r--r--chromium/cc/animation/scrollbar_animation_controller_thinning.cc129
-rw-r--r--chromium/cc/animation/scrollbar_animation_controller_thinning.h44
-rw-r--r--chromium/cc/animation/scrollbar_animation_controller_thinning_unittest.cc141
-rw-r--r--chromium/cc/animation/timing_function.cc109
-rw-r--r--chromium/cc/animation/timing_function.h7
-rw-r--r--chromium/cc/animation/timing_function_unittest.cc141
-rw-r--r--chromium/cc/animation/transform_operation.cc42
-rw-r--r--chromium/cc/animation/transform_operations.cc101
-rw-r--r--chromium/cc/animation/transform_operations.h19
-rw-r--r--chromium/cc/animation/transform_operations_unittest.cc279
-rw-r--r--chromium/cc/base/completion_event.h10
-rw-r--r--chromium/cc/base/delayed_unique_notifier.cc78
-rw-r--r--chromium/cc/base/delayed_unique_notifier.h61
-rw-r--r--chromium/cc/base/delayed_unique_notifier_unittest.cc266
-rw-r--r--chromium/cc/base/invalidation_region.cc2
-rw-r--r--chromium/cc/base/invalidation_region.h2
-rw-r--r--chromium/cc/base/latency_info_swap_promise.cc4
-rw-r--r--chromium/cc/base/math_util.cc118
-rw-r--r--chromium/cc/base/math_util.h36
-rw-r--r--chromium/cc/base/region.cc16
-rw-r--r--chromium/cc/base/region.h22
-rw-r--r--chromium/cc/base/rolling_time_delta_history.cc (renamed from chromium/cc/scheduler/rolling_time_delta_history.cc)10
-rw-r--r--chromium/cc/base/rolling_time_delta_history.h (renamed from chromium/cc/scheduler/rolling_time_delta_history.h)8
-rw-r--r--chromium/cc/base/rolling_time_delta_history_unittest.cc (renamed from chromium/cc/scheduler/rolling_time_delta_history_unittest.cc)4
-rw-r--r--chromium/cc/base/switches.cc111
-rw-r--r--chromium/cc/base/switches.h24
-rw-r--r--chromium/cc/base/tiling_data.cc398
-rw-r--r--chromium/cc/base/tiling_data.h93
-rw-r--r--chromium/cc/base/tiling_data_unittest.cc3984
-rw-r--r--chromium/cc/base/unique_notifier.cc42
-rw-r--r--chromium/cc/base/unique_notifier.h44
-rw-r--r--chromium/cc/base/unique_notifier_unittest.cc62
-rw-r--r--chromium/cc/cc.gyp97
-rw-r--r--chromium/cc/cc_tests.gyp83
-rw-r--r--chromium/cc/debug/debug_colors.cc48
-rw-r--r--chromium/cc/debug/debug_colors.h16
-rw-r--r--chromium/cc/debug/debug_rect_history.cc132
-rw-r--r--chromium/cc/debug/debug_rect_history.h13
-rw-r--r--chromium/cc/debug/devtools_instrumentation.h40
-rw-r--r--chromium/cc/debug/frame_viewer_instrumentation.h93
-rw-r--r--chromium/cc/debug/invalidation_benchmark.cc139
-rw-r--r--chromium/cc/debug/invalidation_benchmark.h45
-rw-r--r--chromium/cc/debug/lap_timer.cc81
-rw-r--r--chromium/cc/debug/lap_timer.h64
-rw-r--r--chromium/cc/debug/layer_tree_debug_state.cc49
-rw-r--r--chromium/cc/debug/layer_tree_debug_state.h1
-rw-r--r--chromium/cc/debug/micro_benchmark.cc8
-rw-r--r--chromium/cc/debug/micro_benchmark.h5
-rw-r--r--chromium/cc/debug/micro_benchmark_controller.cc34
-rw-r--r--chromium/cc/debug/micro_benchmark_controller.h11
-rw-r--r--chromium/cc/debug/micro_benchmark_controller_unittest.cc69
-rw-r--r--chromium/cc/debug/overdraw_metrics.cc268
-rw-r--r--chromium/cc/debug/overdraw_metrics.h115
-rw-r--r--chromium/cc/debug/picture_record_benchmark.cc6
-rw-r--r--chromium/cc/debug/rasterize_and_record_benchmark.cc79
-rw-r--r--chromium/cc/debug/rasterize_and_record_benchmark.h3
-rw-r--r--chromium/cc/debug/rasterize_and_record_benchmark_impl.cc164
-rw-r--r--chromium/cc/debug/rasterize_and_record_benchmark_impl.h8
-rw-r--r--chromium/cc/debug/rendering_stats.cc30
-rw-r--r--chromium/cc/debug/rendering_stats.h23
-rw-r--r--chromium/cc/debug/rendering_stats_instrumentation.cc65
-rw-r--r--chromium/cc/debug/rendering_stats_instrumentation.h26
-rw-r--r--chromium/cc/debug/traced_picture.cc10
-rw-r--r--chromium/cc/debug/traced_picture.h8
-rw-r--r--chromium/cc/debug/traced_value.cc11
-rw-r--r--chromium/cc/debug/traced_value.h17
-rw-r--r--chromium/cc/debug/unittest_only_benchmark.cc12
-rw-r--r--chromium/cc/debug/unittest_only_benchmark.h2
-rw-r--r--chromium/cc/input/input_handler.h48
-rw-r--r--chromium/cc/input/layer_scroll_offset_delegate.h31
-rw-r--r--chromium/cc/input/page_scale_animation.cc71
-rw-r--r--chromium/cc/input/page_scale_animation.h38
-rw-r--r--chromium/cc/input/scrollbar.h2
-rw-r--r--chromium/cc/input/top_controls_manager.cc2
-rw-r--r--chromium/cc/input/top_controls_manager.h2
-rw-r--r--chromium/cc/input/top_controls_manager_unittest.cc4
-rw-r--r--chromium/cc/layers/append_quads_data.h8
-rw-r--r--chromium/cc/layers/compositing_reasons.h63
-rw-r--r--chromium/cc/layers/content_layer.cc43
-rw-r--r--chromium/cc/layers/content_layer.h4
-rw-r--r--chromium/cc/layers/content_layer_client.h14
-rw-r--r--chromium/cc/layers/content_layer_unittest.cc11
-rw-r--r--chromium/cc/layers/contents_scaling_layer.cc6
-rw-r--r--chromium/cc/layers/contents_scaling_layer.h23
-rw-r--r--chromium/cc/layers/delegated_frame_provider.cc8
-rw-r--r--chromium/cc/layers/delegated_frame_provider_unittest.cc14
-rw-r--r--chromium/cc/layers/delegated_renderer_layer.cc35
-rw-r--r--chromium/cc/layers/delegated_renderer_layer.h10
-rw-r--r--chromium/cc/layers/delegated_renderer_layer_impl.cc95
-rw-r--r--chromium/cc/layers/delegated_renderer_layer_impl.h15
-rw-r--r--chromium/cc/layers/delegated_renderer_layer_impl_unittest.cc503
-rw-r--r--chromium/cc/layers/draw_properties.h35
-rw-r--r--chromium/cc/layers/heads_up_display_layer.cc6
-rw-r--r--chromium/cc/layers/heads_up_display_layer.h4
-rw-r--r--chromium/cc/layers/heads_up_display_layer_impl.cc183
-rw-r--r--chromium/cc/layers/heads_up_display_layer_impl.h23
-rw-r--r--chromium/cc/layers/heads_up_display_layer_impl_unittest.cc13
-rw-r--r--chromium/cc/layers/image_layer.cc3
-rw-r--r--chromium/cc/layers/image_layer.h3
-rw-r--r--chromium/cc/layers/io_surface_layer.cc4
-rw-r--r--chromium/cc/layers/io_surface_layer.h4
-rw-r--r--chromium/cc/layers/io_surface_layer_impl.cc77
-rw-r--r--chromium/cc/layers/io_surface_layer_impl.h7
-rw-r--r--chromium/cc/layers/io_surface_layer_impl_unittest.cc64
-rw-r--r--chromium/cc/layers/layer.cc197
-rw-r--r--chromium/cc/layers/layer.h92
-rw-r--r--chromium/cc/layers/layer_client.h2
-rw-r--r--chromium/cc/layers/layer_impl.cc818
-rw-r--r--chromium/cc/layers/layer_impl.h251
-rw-r--r--chromium/cc/layers/layer_impl_unittest.cc325
-rw-r--r--chromium/cc/layers/layer_iterator.cc130
-rw-r--r--chromium/cc/layers/layer_iterator.h149
-rw-r--r--chromium/cc/layers/layer_iterator_unittest.cc8
-rw-r--r--chromium/cc/layers/layer_lists.h2
-rw-r--r--chromium/cc/layers/layer_perftest.cc16
-rw-r--r--chromium/cc/layers/layer_position_constraint_unittest.cc196
-rw-r--r--chromium/cc/layers/layer_unittest.cc108
-rw-r--r--chromium/cc/layers/layer_utils.cc146
-rw-r--r--chromium/cc/layers/layer_utils.h29
-rw-r--r--chromium/cc/layers/layer_utils_unittest.cc267
-rw-r--r--chromium/cc/layers/nine_patch_layer.cc4
-rw-r--r--chromium/cc/layers/nine_patch_layer.h4
-rw-r--r--chromium/cc/layers/nine_patch_layer_impl.cc294
-rw-r--r--chromium/cc/layers/nine_patch_layer_impl.h4
-rw-r--r--chromium/cc/layers/nine_patch_layer_impl_unittest.cc149
-rw-r--r--chromium/cc/layers/nine_patch_layer_unittest.cc14
-rw-r--r--chromium/cc/layers/painted_scrollbar_layer.cc80
-rw-r--r--chromium/cc/layers/painted_scrollbar_layer.h13
-rw-r--r--chromium/cc/layers/painted_scrollbar_layer_impl.cc28
-rw-r--r--chromium/cc/layers/painted_scrollbar_layer_impl.h1
-rw-r--r--chromium/cc/layers/painted_scrollbar_layer_impl_unittest.cc94
-rw-r--r--chromium/cc/layers/picture_image_layer.cc20
-rw-r--r--chromium/cc/layers/picture_image_layer.h6
-rw-r--r--chromium/cc/layers/picture_image_layer_impl.cc41
-rw-r--r--chromium/cc/layers/picture_image_layer_impl.h15
-rw-r--r--chromium/cc/layers/picture_image_layer_impl_unittest.cc106
-rw-r--r--chromium/cc/layers/picture_layer.cc100
-rw-r--r--chromium/cc/layers/picture_layer.h13
-rw-r--r--chromium/cc/layers/picture_layer_impl.cc1148
-rw-r--r--chromium/cc/layers/picture_layer_impl.h112
-rw-r--r--chromium/cc/layers/picture_layer_impl_perftest.cc114
-rw-r--r--chromium/cc/layers/picture_layer_impl_unittest.cc2061
-rw-r--r--chromium/cc/layers/picture_layer_unittest.cc60
-rw-r--r--chromium/cc/layers/quad_sink.cc55
-rw-r--r--chromium/cc/layers/quad_sink.h47
-rw-r--r--chromium/cc/layers/render_surface.cc4
-rw-r--r--chromium/cc/layers/render_surface.h16
-rw-r--r--chromium/cc/layers/render_surface_impl.cc33
-rw-r--r--chromium/cc/layers/render_surface_impl.h10
-rw-r--r--chromium/cc/layers/render_surface_impl_unittest.cc67
-rw-r--r--chromium/cc/layers/render_surface_unittest.cc20
-rw-r--r--chromium/cc/layers/scrollbar_layer_impl_base.cc87
-rw-r--r--chromium/cc/layers/scrollbar_layer_impl_base.h29
-rw-r--r--chromium/cc/layers/scrollbar_layer_interface.h7
-rw-r--r--chromium/cc/layers/scrollbar_layer_unittest.cc334
-rw-r--r--chromium/cc/layers/scrollbar_theme_painter.h28
-rw-r--r--chromium/cc/layers/solid_color_layer_impl.cc30
-rw-r--r--chromium/cc/layers/solid_color_layer_impl_unittest.cc86
-rw-r--r--chromium/cc/layers/solid_color_scrollbar_layer.cc60
-rw-r--r--chromium/cc/layers/solid_color_scrollbar_layer.h12
-rw-r--r--chromium/cc/layers/solid_color_scrollbar_layer_impl.cc71
-rw-r--r--chromium/cc/layers/solid_color_scrollbar_layer_impl.h10
-rw-r--r--chromium/cc/layers/solid_color_scrollbar_layer_impl_unittest.cc80
-rw-r--r--chromium/cc/layers/surface_layer.cc40
-rw-r--r--chromium/cc/layers/surface_layer.h41
-rw-r--r--chromium/cc/layers/surface_layer_impl.cc75
-rw-r--r--chromium/cc/layers/surface_layer_impl.h47
-rw-r--r--chromium/cc/layers/surface_layer_impl_unittest.cc66
-rw-r--r--chromium/cc/layers/texture_layer.cc187
-rw-r--r--chromium/cc/layers/texture_layer.h61
-rw-r--r--chromium/cc/layers/texture_layer_client.h4
-rw-r--r--chromium/cc/layers/texture_layer_impl.cc219
-rw-r--r--chromium/cc/layers/texture_layer_impl.h44
-rw-r--r--chromium/cc/layers/texture_layer_impl_unittest.cc76
-rw-r--r--chromium/cc/layers/texture_layer_unittest.cc1042
-rw-r--r--chromium/cc/layers/tiled_layer.cc68
-rw-r--r--chromium/cc/layers/tiled_layer.h25
-rw-r--r--chromium/cc/layers/tiled_layer_impl.cc45
-rw-r--r--chromium/cc/layers/tiled_layer_impl.h4
-rw-r--r--chromium/cc/layers/tiled_layer_impl_unittest.cc168
-rw-r--r--chromium/cc/layers/tiled_layer_unittest.cc261
-rw-r--r--chromium/cc/layers/ui_resource_layer.cc3
-rw-r--r--chromium/cc/layers/ui_resource_layer.h2
-rw-r--r--chromium/cc/layers/ui_resource_layer_impl.cc28
-rw-r--r--chromium/cc/layers/ui_resource_layer_impl.h4
-rw-r--r--chromium/cc/layers/ui_resource_layer_impl_unittest.cc94
-rw-r--r--chromium/cc/layers/ui_resource_layer_unittest.cc23
-rw-r--r--chromium/cc/layers/video_frame_provider_client_impl.cc7
-rw-r--r--chromium/cc/layers/video_frame_provider_client_impl.h1
-rw-r--r--chromium/cc/layers/video_layer.cc2
-rw-r--r--chromium/cc/layers/video_layer.h3
-rw-r--r--chromium/cc/layers/video_layer_impl.cc85
-rw-r--r--chromium/cc/layers/video_layer_impl.h2
-rw-r--r--chromium/cc/layers/video_layer_impl_unittest.cc97
-rw-r--r--chromium/cc/output/begin_frame_args.cc37
-rw-r--r--chromium/cc/output/begin_frame_args.h10
-rw-r--r--chromium/cc/output/begin_frame_args_unittest.cc77
-rw-r--r--chromium/cc/output/compositor_frame_metadata.h4
-rw-r--r--chromium/cc/output/context_provider.cc28
-rw-r--r--chromium/cc/output/context_provider.h23
-rw-r--r--chromium/cc/output/copy_output_request.cc11
-rw-r--r--chromium/cc/output/copy_output_request.h6
-rw-r--r--chromium/cc/output/copy_output_result.cc3
-rw-r--r--chromium/cc/output/copy_output_result.h6
-rw-r--r--chromium/cc/output/delegated_frame_data.cc3
-rw-r--r--chromium/cc/output/delegated_frame_data.h3
-rw-r--r--chromium/cc/output/delegating_renderer.cc86
-rw-r--r--chromium/cc/output/delegating_renderer.h24
-rw-r--r--chromium/cc/output/delegating_renderer_unittest.cc19
-rw-r--r--chromium/cc/output/direct_renderer.cc76
-rw-r--r--chromium/cc/output/direct_renderer.h44
-rw-r--r--chromium/cc/output/filter_operation.cc58
-rw-r--r--chromium/cc/output/filter_operation.h43
-rw-r--r--chromium/cc/output/filter_operations.cc4
-rw-r--r--chromium/cc/output/filter_operations_unittest.cc12
-rw-r--r--chromium/cc/output/gl_renderer.cc707
-rw-r--r--chromium/cc/output/gl_renderer.h78
-rw-r--r--chromium/cc/output/gl_renderer_unittest.cc493
-rw-r--r--chromium/cc/output/output_surface.cc238
-rw-r--r--chromium/cc/output/output_surface.h83
-rw-r--r--chromium/cc/output/output_surface_client.h16
-rw-r--r--chromium/cc/output/output_surface_unittest.cc282
-rw-r--r--chromium/cc/output/overlay_candidate.cc42
-rw-r--r--chromium/cc/output/overlay_candidate.h53
-rw-r--r--chromium/cc/output/overlay_candidate_validator.h33
-rw-r--r--chromium/cc/output/overlay_processor.cc45
-rw-r--r--chromium/cc/output/overlay_processor.h51
-rw-r--r--chromium/cc/output/overlay_strategy_single_on_top.cc81
-rw-r--r--chromium/cc/output/overlay_strategy_single_on_top.h33
-rw-r--r--chromium/cc/output/overlay_unittest.cc727
-rw-r--r--chromium/cc/output/render_surface_filters.cc30
-rw-r--r--chromium/cc/output/render_surface_filters.h4
-rw-r--r--chromium/cc/output/renderer.cc29
-rw-r--r--chromium/cc/output/renderer.h47
-rw-r--r--chromium/cc/output/renderer_pixeltest.cc1163
-rw-r--r--chromium/cc/output/renderer_unittest.cc94
-rw-r--r--chromium/cc/output/shader.cc24
-rw-r--r--chromium/cc/output/shader.h20
-rw-r--r--chromium/cc/output/software_frame_data.cc4
-rw-r--r--chromium/cc/output/software_frame_data.h4
-rw-r--r--chromium/cc/output/software_output_device.cc40
-rw-r--r--chromium/cc/output/software_output_device.h15
-rw-r--r--chromium/cc/output/software_renderer.cc153
-rw-r--r--chromium/cc/output/software_renderer.h21
-rw-r--r--chromium/cc/output/software_renderer_unittest.cc289
-rw-r--r--chromium/cc/quads/checkerboard_draw_quad.cc10
-rw-r--r--chromium/cc/quads/checkerboard_draw_quad.h9
-rw-r--r--chromium/cc/quads/content_draw_quad_base.cc16
-rw-r--r--chromium/cc/quads/content_draw_quad_base.h15
-rw-r--r--chromium/cc/quads/debug_border_draw_quad.cc10
-rw-r--r--chromium/cc/quads/debug_border_draw_quad.h9
-rw-r--r--chromium/cc/quads/draw_quad.cc10
-rw-r--r--chromium/cc/quads/draw_quad.h12
-rw-r--r--chromium/cc/quads/draw_quad_unittest.cc174
-rw-r--r--chromium/cc/quads/io_surface_draw_quad.cc16
-rw-r--r--chromium/cc/quads/io_surface_draw_quad.h18
-rw-r--r--chromium/cc/quads/picture_draw_quad.cc36
-rw-r--r--chromium/cc/quads/picture_draw_quad.h19
-rw-r--r--chromium/cc/quads/render_pass.cc34
-rw-r--r--chromium/cc/quads/render_pass.h13
-rw-r--r--chromium/cc/quads/render_pass_draw_quad.cc18
-rw-r--r--chromium/cc/quads/render_pass_draw_quad.h17
-rw-r--r--chromium/cc/quads/render_pass_unittest.cc96
-rw-r--r--chromium/cc/quads/shared_quad_state.cc24
-rw-r--r--chromium/cc/quads/shared_quad_state.h22
-rw-r--r--chromium/cc/quads/solid_color_draw_quad.cc10
-rw-r--r--chromium/cc/quads/solid_color_draw_quad.h9
-rw-r--r--chromium/cc/quads/stream_video_draw_quad.cc12
-rw-r--r--chromium/cc/quads/stream_video_draw_quad.h11
-rw-r--r--chromium/cc/quads/surface_draw_quad.cc54
-rw-r--r--chromium/cc/quads/surface_draw_quad.h45
-rw-r--r--chromium/cc/quads/texture_draw_quad.cc23
-rw-r--r--chromium/cc/quads/texture_draw_quad.h19
-rw-r--r--chromium/cc/quads/tile_draw_quad.cc24
-rw-r--r--chromium/cc/quads/tile_draw_quad.h15
-rw-r--r--chromium/cc/quads/yuv_video_draw_quad.cc30
-rw-r--r--chromium/cc/quads/yuv_video_draw_quad.h30
-rw-r--r--chromium/cc/resources/bitmap_content_layer_updater.cc41
-rw-r--r--chromium/cc/resources/bitmap_content_layer_updater.h18
-rw-r--r--chromium/cc/resources/bitmap_skpicture_content_layer_updater.cc20
-rw-r--r--chromium/cc/resources/bitmap_skpicture_content_layer_updater.h6
-rw-r--r--chromium/cc/resources/caching_bitmap_content_layer_updater.cc61
-rw-r--r--chromium/cc/resources/caching_bitmap_content_layer_updater.h46
-rw-r--r--chromium/cc/resources/content_layer_updater.cc30
-rw-r--r--chromium/cc/resources/content_layer_updater.h17
-rw-r--r--chromium/cc/resources/direct_raster_worker_pool.cc215
-rw-r--r--chromium/cc/resources/direct_raster_worker_pool.h81
-rw-r--r--chromium/cc/resources/etc1_pixel_ref.cc38
-rw-r--r--chromium/cc/resources/etc1_pixel_ref.h44
-rw-r--r--chromium/cc/resources/image_copy_raster_worker_pool.cc260
-rw-r--r--chromium/cc/resources/image_copy_raster_worker_pool.h110
-rw-r--r--chromium/cc/resources/image_layer_updater.cc8
-rw-r--r--chromium/cc/resources/image_layer_updater.h8
-rw-r--r--chromium/cc/resources/image_raster_worker_pool.cc301
-rw-r--r--chromium/cc/resources/image_raster_worker_pool.h74
-rw-r--r--chromium/cc/resources/layer_painter.h2
-rw-r--r--chromium/cc/resources/layer_quad.cc2
-rw-r--r--chromium/cc/resources/layer_quad.h2
-rw-r--r--chromium/cc/resources/layer_tiling_data.cc22
-rw-r--r--chromium/cc/resources/layer_tiling_data.h18
-rw-r--r--chromium/cc/resources/layer_updater.h12
-rw-r--r--chromium/cc/resources/managed_tile_state.cc48
-rw-r--r--chromium/cc/resources/managed_tile_state.h147
-rw-r--r--chromium/cc/resources/picture.cc228
-rw-r--r--chromium/cc/resources/picture.h87
-rw-r--r--chromium/cc/resources/picture_layer_tiling.cc680
-rw-r--r--chromium/cc/resources/picture_layer_tiling.h153
-rw-r--r--chromium/cc/resources/picture_layer_tiling_perftest.cc159
-rw-r--r--chromium/cc/resources/picture_layer_tiling_set.cc65
-rw-r--r--chromium/cc/resources/picture_layer_tiling_set.h32
-rw-r--r--chromium/cc/resources/picture_layer_tiling_set_unittest.cc24
-rw-r--r--chromium/cc/resources/picture_layer_tiling_unittest.cc1109
-rw-r--r--chromium/cc/resources/picture_pile.cc110
-rw-r--r--chromium/cc/resources/picture_pile.h25
-rw-r--r--chromium/cc/resources/picture_pile_base.cc107
-rw-r--r--chromium/cc/resources/picture_pile_base.h41
-rw-r--r--chromium/cc/resources/picture_pile_impl.cc189
-rw-r--r--chromium/cc/resources/picture_pile_impl.h24
-rw-r--r--chromium/cc/resources/picture_pile_impl_perftest.cc89
-rw-r--r--chromium/cc/resources/picture_pile_impl_unittest.cc349
-rw-r--r--chromium/cc/resources/picture_pile_unittest.cc442
-rw-r--r--chromium/cc/resources/picture_unittest.cc297
-rw-r--r--chromium/cc/resources/pixel_buffer_raster_worker_pool.cc865
-rw-r--r--chromium/cc/resources/pixel_buffer_raster_worker_pool.h118
-rw-r--r--chromium/cc/resources/prioritized_resource.cc22
-rw-r--r--chromium/cc/resources/prioritized_resource.h16
-rw-r--r--chromium/cc/resources/prioritized_resource_manager.cc6
-rw-r--r--chromium/cc/resources/prioritized_resource_manager.h4
-rw-r--r--chromium/cc/resources/prioritized_resource_unittest.cc10
-rw-r--r--chromium/cc/resources/prioritized_tile_set.cc13
-rw-r--r--chromium/cc/resources/prioritized_tile_set_unittest.cc34
-rw-r--r--chromium/cc/resources/priority_calculator.cc4
-rw-r--r--chromium/cc/resources/priority_calculator.h4
-rw-r--r--chromium/cc/resources/raster_mode.cc9
-rw-r--r--chromium/cc/resources/raster_mode.h9
-rw-r--r--chromium/cc/resources/raster_worker_pool.cc716
-rw-r--r--chromium/cc/resources/raster_worker_pool.h323
-rw-r--r--chromium/cc/resources/raster_worker_pool_perftest.cc566
-rw-r--r--chromium/cc/resources/raster_worker_pool_unittest.cc409
-rw-r--r--chromium/cc/resources/rasterizer.cc79
-rw-r--r--chromium/cc/resources/rasterizer.h165
-rw-r--r--chromium/cc/resources/release_callback.h3
-rw-r--r--chromium/cc/resources/resource.h7
-rw-r--r--chromium/cc/resources/resource_format.cc8
-rw-r--r--chromium/cc/resources/resource_format.h2
-rw-r--r--chromium/cc/resources/resource_pool.cc22
-rw-r--r--chromium/cc/resources/resource_pool.h13
-rw-r--r--chromium/cc/resources/resource_provider.cc1192
-rw-r--r--chromium/cc/resources/resource_provider.h261
-rw-r--r--chromium/cc/resources/resource_provider_unittest.cc1000
-rw-r--r--chromium/cc/resources/resource_update.cc29
-rw-r--r--chromium/cc/resources/resource_update.h15
-rw-r--r--chromium/cc/resources/resource_update_controller.cc9
-rw-r--r--chromium/cc/resources/resource_update_controller.h1
-rw-r--r--chromium/cc/resources/resource_update_controller_unittest.cc22
-rw-r--r--chromium/cc/resources/scoped_resource.cc10
-rw-r--r--chromium/cc/resources/scoped_resource.h10
-rw-r--r--chromium/cc/resources/scoped_resource_unittest.cc25
-rw-r--r--chromium/cc/resources/shared_bitmap.cc68
-rw-r--r--chromium/cc/resources/shared_bitmap.h25
-rw-r--r--chromium/cc/resources/shared_bitmap_manager.h5
-rw-r--r--chromium/cc/resources/single_release_callback.cc2
-rw-r--r--chromium/cc/resources/single_release_callback.h2
-rw-r--r--chromium/cc/resources/skpicture_content_layer_updater.cc19
-rw-r--r--chromium/cc/resources/skpicture_content_layer_updater.h15
-rw-r--r--chromium/cc/resources/task_graph_runner.cc477
-rw-r--r--chromium/cc/resources/task_graph_runner.h232
-rw-r--r--chromium/cc/resources/task_graph_runner_perftest.cc318
-rw-r--r--chromium/cc/resources/task_graph_runner_unittest.cc331
-rw-r--r--chromium/cc/resources/texture_mailbox.cc93
-rw-r--r--chromium/cc/resources/texture_mailbox.h44
-rw-r--r--chromium/cc/resources/texture_mailbox_deleter.cc12
-rw-r--r--chromium/cc/resources/texture_mailbox_deleter.h15
-rw-r--r--chromium/cc/resources/texture_mailbox_deleter_unittest.cc7
-rw-r--r--chromium/cc/resources/texture_uploader.cc (renamed from chromium/cc/scheduler/texture_uploader.cc)20
-rw-r--r--chromium/cc/resources/texture_uploader.h (renamed from chromium/cc/scheduler/texture_uploader.h)32
-rw-r--r--chromium/cc/resources/texture_uploader_unittest.cc (renamed from chromium/cc/scheduler/texture_uploader_unittest.cc)14
-rw-r--r--chromium/cc/resources/tile.cc48
-rw-r--r--chromium/cc/resources/tile.h66
-rw-r--r--chromium/cc/resources/tile_manager.cc1362
-rw-r--r--chromium/cc/resources/tile_manager.h230
-rw-r--r--chromium/cc/resources/tile_manager_perftest.cc400
-rw-r--r--chromium/cc/resources/tile_manager_unittest.cc833
-rw-r--r--chromium/cc/resources/tile_priority.cc146
-rw-r--r--chromium/cc/resources/tile_priority.h75
-rw-r--r--chromium/cc/resources/tile_priority_unittest.cc76
-rw-r--r--chromium/cc/resources/transferable_resource.cc8
-rw-r--r--chromium/cc/resources/transferable_resource.h7
-rw-r--r--chromium/cc/resources/ui_resource_bitmap.cc32
-rw-r--r--chromium/cc/resources/ui_resource_bitmap.h12
-rw-r--r--chromium/cc/resources/video_resource_updater.cc125
-rw-r--r--chromium/cc/resources/video_resource_updater.h4
-rw-r--r--chromium/cc/resources/video_resource_updater_unittest.cc21
-rw-r--r--chromium/cc/resources/worker_pool.cc433
-rw-r--r--chromium/cc/resources/worker_pool.h143
-rw-r--r--chromium/cc/resources/worker_pool_perftest.cc235
-rw-r--r--chromium/cc/resources/worker_pool_unittest.cc394
-rw-r--r--chromium/cc/scheduler/delay_based_time_source.cc56
-rw-r--r--chromium/cc/scheduler/delay_based_time_source.h36
-rw-r--r--chromium/cc/scheduler/delay_based_time_source_unittest.cc50
-rw-r--r--chromium/cc/scheduler/draw_result.h21
-rw-r--r--chromium/cc/scheduler/frame_rate_controller.cc178
-rw-r--r--chromium/cc/scheduler/frame_rate_controller.h101
-rw-r--r--chromium/cc/scheduler/frame_rate_controller_unittest.cc211
-rw-r--r--chromium/cc/scheduler/scheduler.cc654
-rw-r--r--chromium/cc/scheduler/scheduler.h176
-rw-r--r--chromium/cc/scheduler/scheduler_settings.cc44
-rw-r--r--chromium/cc/scheduler/scheduler_settings.h11
-rw-r--r--chromium/cc/scheduler/scheduler_state_machine.cc653
-rw-r--r--chromium/cc/scheduler/scheduler_state_machine.h113
-rw-r--r--chromium/cc/scheduler/scheduler_state_machine_unittest.cc1387
-rw-r--r--chromium/cc/scheduler/scheduler_unittest.cc1931
-rw-r--r--chromium/cc/scheduler/time_source.h51
-rw-r--r--chromium/cc/surfaces/OWNERS1
-rw-r--r--chromium/cc/surfaces/display.cc163
-rw-r--r--chromium/cc/surfaces/display.h91
-rw-r--r--chromium/cc/surfaces/display_client.h23
-rw-r--r--chromium/cc/surfaces/surface.cc92
-rw-r--r--chromium/cc/surfaces/surface.h75
-rw-r--r--chromium/cc/surfaces/surface_aggregator.cc250
-rw-r--r--chromium/cc/surfaces/surface_aggregator.h70
-rw-r--r--chromium/cc/surfaces/surface_aggregator_test_helpers.cc172
-rw-r--r--chromium/cc/surfaces/surface_aggregator_test_helpers.h95
-rw-r--r--chromium/cc/surfaces/surface_aggregator_unittest.cc708
-rw-r--r--chromium/cc/surfaces/surface_client.h22
-rw-r--r--chromium/cc/surfaces/surface_id.h29
-rw-r--r--chromium/cc/surfaces/surface_manager.cc37
-rw-r--r--chromium/cc/surfaces/surface_manager.h39
-rw-r--r--chromium/cc/surfaces/surface_unittest.cc411
-rw-r--r--chromium/cc/surfaces/surfaces_export.h29
-rw-r--r--chromium/cc/surfaces/surfaces_pixeltest.cc312
-rw-r--r--chromium/cc/trees/blocking_task_runner.cc47
-rw-r--r--chromium/cc/trees/blocking_task_runner.h6
-rw-r--r--chromium/cc/trees/damage_tracker.cc86
-rw-r--r--chromium/cc/trees/damage_tracker.h31
-rw-r--r--chromium/cc/trees/damage_tracker_unittest.cc515
-rw-r--r--chromium/cc/trees/layer_sorter.cc13
-rw-r--r--chromium/cc/trees/layer_sorter.h2
-rw-r--r--chromium/cc/trees/layer_sorter_unittest.cc7
-rw-r--r--chromium/cc/trees/layer_tree_host.cc404
-rw-r--r--chromium/cc/trees/layer_tree_host.h81
-rw-r--r--chromium/cc/trees/layer_tree_host_client.h12
-rw-r--r--chromium/cc/trees/layer_tree_host_common.cc899
-rw-r--r--chromium/cc/trees/layer_tree_host_common.h62
-rw-r--r--chromium/cc/trees/layer_tree_host_common_perftest.cc113
-rw-r--r--chromium/cc/trees/layer_tree_host_common_unittest.cc4895
-rw-r--r--chromium/cc/trees/layer_tree_host_impl.cc1481
-rw-r--r--chromium/cc/trees/layer_tree_host_impl.h249
-rw-r--r--chromium/cc/trees/layer_tree_host_impl_unittest.cc2518
-rw-r--r--chromium/cc/trees/layer_tree_host_perftest.cc88
-rw-r--r--chromium/cc/trees/layer_tree_host_pixeltest_filters.cc13
-rw-r--r--chromium/cc/trees/layer_tree_host_pixeltest_masks.cc39
-rw-r--r--chromium/cc/trees/layer_tree_host_pixeltest_on_demand_raster.cc42
-rw-r--r--chromium/cc/trees/layer_tree_host_pixeltest_readback.cc503
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest.cc1863
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_animation.cc500
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_context.cc968
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc106
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_damage.cc169
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_delegated.cc379
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_no_message_loop.cc235
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_occlusion.cc17
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_proxy.cc135
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_scroll.cc364
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_video.cc12
-rw-r--r--chromium/cc/trees/layer_tree_impl.cc885
-rw-r--r--chromium/cc/trees/layer_tree_impl.h75
-rw-r--r--chromium/cc/trees/layer_tree_impl_unittest.cc2074
-rw-r--r--chromium/cc/trees/layer_tree_settings.cc29
-rw-r--r--chromium/cc/trees/layer_tree_settings.h32
-rw-r--r--chromium/cc/trees/occlusion_tracker.cc219
-rw-r--r--chromium/cc/trees/occlusion_tracker.h43
-rw-r--r--chromium/cc/trees/occlusion_tracker_perftest.cc206
-rw-r--r--chromium/cc/trees/occlusion_tracker_unittest.cc584
-rw-r--r--chromium/cc/trees/proxy.cc31
-rw-r--r--chromium/cc/trees/proxy.h26
-rw-r--r--chromium/cc/trees/proxy_timing_history.cc66
-rw-r--r--chromium/cc/trees/proxy_timing_history.h40
-rw-r--r--chromium/cc/trees/quad_culler.cc108
-rw-r--r--chromium/cc/trees/quad_culler.h49
-rw-r--r--chromium/cc/trees/quad_culler_unittest.cc919
-rw-r--r--chromium/cc/trees/single_thread_proxy.cc229
-rw-r--r--chromium/cc/trees/single_thread_proxy.h61
-rw-r--r--chromium/cc/trees/thread_proxy.cc1367
-rw-r--r--chromium/cc/trees/thread_proxy.h327
-rw-r--r--chromium/cc/trees/tree_synchronizer.cc94
-rw-r--r--chromium/cc/trees/tree_synchronizer.h3
-rw-r--r--chromium/cc/trees/tree_synchronizer_unittest.cc84
513 files changed, 51250 insertions, 30586 deletions
diff --git a/chromium/cc/BUILD.gn b/chromium/cc/BUILD.gn
new file mode 100644
index 00000000000..1a1e7366faa
--- /dev/null
+++ b/chromium/cc/BUILD.gn
@@ -0,0 +1,789 @@
+# 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.
+
+component("cc") {
+ sources = [
+ "animation/animation.cc",
+ "animation/animation.h",
+ "animation/animation_curve.cc",
+ "animation/animation_curve.h",
+ "animation/animation_delegate.h",
+ "animation/animation_events.cc",
+ "animation/animation_events.h",
+ "animation/animation_id_provider.cc",
+ "animation/animation_id_provider.h",
+ "animation/animation_registrar.cc",
+ "animation/animation_registrar.h",
+ "animation/keyframed_animation_curve.cc",
+ "animation/keyframed_animation_curve.h",
+ "animation/layer_animation_controller.cc",
+ "animation/layer_animation_controller.h",
+ "animation/layer_animation_event_observer.h",
+ "animation/layer_animation_value_observer.h",
+ "animation/layer_animation_value_provider.h",
+ "animation/scroll_offset_animation_curve.cc",
+ "animation/scroll_offset_animation_curve.h",
+ "animation/scrollbar_animation_controller.h",
+ "animation/scrollbar_animation_controller.cc",
+ "animation/scrollbar_animation_controller_linear_fade.cc",
+ "animation/scrollbar_animation_controller_linear_fade.h",
+ "animation/scrollbar_animation_controller_thinning.cc",
+ "animation/scrollbar_animation_controller_thinning.h",
+ "animation/timing_function.cc",
+ "animation/timing_function.h",
+ "animation/transform_operation.cc",
+ "animation/transform_operation.h",
+ "animation/transform_operations.cc",
+ "animation/transform_operations.h",
+ "base/completion_event.h",
+ "base/delayed_unique_notifier.cc",
+ "base/delayed_unique_notifier.h",
+ "base/invalidation_region.cc",
+ "base/invalidation_region.h",
+ "base/latency_info_swap_promise.cc",
+ "base/latency_info_swap_promise.h",
+ "base/latency_info_swap_promise_monitor.cc",
+ "base/latency_info_swap_promise_monitor.h",
+ "base/math_util.cc",
+ "base/math_util.h",
+ "base/ref_counted_managed.h",
+ "base/region.cc",
+ "base/region.h",
+ "base/rolling_time_delta_history.cc",
+ "base/rolling_time_delta_history.h",
+ "base/scoped_ptr_algorithm.h",
+ "base/scoped_ptr_deque.h",
+ "base/scoped_ptr_vector.h",
+ "base/swap_promise.h",
+ "base/swap_promise_monitor.cc",
+ "base/swap_promise_monitor.h",
+ "base/switches.cc",
+ "base/switches.h",
+ "base/tiling_data.cc",
+ "base/tiling_data.h",
+ "base/unique_notifier.cc",
+ "base/unique_notifier.h",
+ "base/util.h",
+ "debug/benchmark_instrumentation.cc",
+ "debug/benchmark_instrumentation.h",
+ "debug/debug_colors.cc",
+ "debug/debug_colors.h",
+ "debug/debug_rect_history.cc",
+ "debug/debug_rect_history.h",
+ "debug/devtools_instrumentation.h",
+ "debug/frame_rate_counter.cc",
+ "debug/frame_rate_counter.h",
+ "debug/frame_viewer_instrumentation.h",
+ "debug/invalidation_benchmark.cc",
+ "debug/invalidation_benchmark.h",
+ "debug/lap_timer.cc",
+ "debug/lap_timer.h",
+ "debug/layer_tree_debug_state.cc",
+ "debug/layer_tree_debug_state.h",
+ "debug/micro_benchmark.cc",
+ "debug/micro_benchmark.h",
+ "debug/micro_benchmark_impl.cc",
+ "debug/micro_benchmark_impl.h",
+ "debug/micro_benchmark_controller.cc",
+ "debug/micro_benchmark_controller.h",
+ "debug/micro_benchmark_controller_impl.cc",
+ "debug/micro_benchmark_controller_impl.h",
+ "debug/paint_time_counter.cc",
+ "debug/paint_time_counter.h",
+ "debug/picture_record_benchmark.cc",
+ "debug/picture_record_benchmark.h",
+ "debug/rasterize_and_record_benchmark.cc",
+ "debug/rasterize_and_record_benchmark.h",
+ "debug/rasterize_and_record_benchmark_impl.cc",
+ "debug/rasterize_and_record_benchmark_impl.h",
+ "debug/rendering_stats.cc",
+ "debug/rendering_stats.h",
+ "debug/rendering_stats_instrumentation.cc",
+ "debug/rendering_stats_instrumentation.h",
+ "debug/ring_buffer.h",
+ "debug/traced_picture.cc",
+ "debug/traced_picture.h",
+ "debug/traced_value.cc",
+ "debug/traced_value.h",
+ "debug/unittest_only_benchmark.cc",
+ "debug/unittest_only_benchmark.h",
+ "debug/unittest_only_benchmark_impl.cc",
+ "debug/unittest_only_benchmark_impl.h",
+ "input/input_handler.h",
+ "input/page_scale_animation.cc",
+ "input/page_scale_animation.h",
+ "input/top_controls_manager.cc",
+ "input/top_controls_manager.h",
+ "input/top_controls_manager_client.h",
+ "layers/append_quads_data.h",
+ "layers/content_layer.cc",
+ "layers/content_layer.h",
+ "layers/content_layer_client.h",
+ "layers/contents_scaling_layer.cc",
+ "layers/contents_scaling_layer.h",
+ "layers/delegated_frame_provider.cc",
+ "layers/delegated_frame_provider.h",
+ "layers/delegated_frame_resource_collection.cc",
+ "layers/delegated_frame_resource_collection.h",
+ "layers/delegated_renderer_layer.cc",
+ "layers/delegated_renderer_layer.h",
+ "layers/delegated_renderer_layer_impl.cc",
+ "layers/delegated_renderer_layer_impl.h",
+ "layers/draw_properties.h",
+ "layers/heads_up_display_layer.cc",
+ "layers/heads_up_display_layer.h",
+ "layers/heads_up_display_layer_impl.cc",
+ "layers/heads_up_display_layer_impl.h",
+ "layers/image_layer.cc",
+ "layers/image_layer.h",
+ "layers/io_surface_layer.cc",
+ "layers/io_surface_layer.h",
+ "layers/io_surface_layer_impl.cc",
+ "layers/io_surface_layer_impl.h",
+ "layers/layer.cc",
+ "layers/layer.h",
+ "layers/layer_client.h",
+ "layers/layer_impl.cc",
+ "layers/layer_impl.h",
+ "layers/layer_iterator.h",
+ "layers/layer_lists.cc",
+ "layers/layer_lists.h",
+ "layers/layer_position_constraint.cc",
+ "layers/layer_position_constraint.h",
+ "layers/layer_utils.cc",
+ "layers/layer_utils.h",
+ "layers/nine_patch_layer.cc",
+ "layers/nine_patch_layer.h",
+ "layers/nine_patch_layer_impl.cc",
+ "layers/nine_patch_layer_impl.h",
+ "layers/paint_properties.h",
+ "layers/painted_scrollbar_layer.cc",
+ "layers/painted_scrollbar_layer.h",
+ "layers/painted_scrollbar_layer_impl.cc",
+ "layers/painted_scrollbar_layer_impl.h",
+ "layers/picture_image_layer.cc",
+ "layers/picture_image_layer.h",
+ "layers/picture_image_layer_impl.cc",
+ "layers/picture_image_layer_impl.h",
+ "layers/picture_layer.cc",
+ "layers/picture_layer.h",
+ "layers/picture_layer_impl.cc",
+ "layers/picture_layer_impl.h",
+ "layers/quad_sink.h",
+ "layers/quad_sink.cc",
+ "layers/render_pass_sink.h",
+ "layers/render_surface.cc",
+ "layers/render_surface.h",
+ "layers/render_surface_impl.cc",
+ "layers/render_surface_impl.h",
+ "layers/scrollbar_layer_impl_base.cc",
+ "layers/scrollbar_layer_impl_base.h",
+ "layers/scrollbar_layer_interface.h",
+ "layers/solid_color_layer.cc",
+ "layers/solid_color_layer.h",
+ "layers/solid_color_layer_impl.cc",
+ "layers/solid_color_layer_impl.h",
+ "layers/solid_color_scrollbar_layer.cc",
+ "layers/solid_color_scrollbar_layer.h",
+ "layers/solid_color_scrollbar_layer_impl.cc",
+ "layers/solid_color_scrollbar_layer_impl.h",
+ "layers/surface_layer.cc",
+ "layers/surface_layer.h",
+ "layers/surface_layer_impl.cc",
+ "layers/surface_layer_impl.h",
+ "layers/texture_layer.cc",
+ "layers/texture_layer.h",
+ "layers/texture_layer_client.h",
+ "layers/texture_layer_impl.cc",
+ "layers/texture_layer_impl.h",
+ "layers/tiled_layer.cc",
+ "layers/tiled_layer.h",
+ "layers/tiled_layer_impl.cc",
+ "layers/tiled_layer_impl.h",
+ "layers/ui_resource_layer.cc",
+ "layers/ui_resource_layer.h",
+ "layers/ui_resource_layer_impl.cc",
+ "layers/ui_resource_layer_impl.h",
+ "layers/video_frame_provider.h",
+ "layers/video_frame_provider_client_impl.cc",
+ "layers/video_frame_provider_client_impl.h",
+ "layers/video_layer.cc",
+ "layers/video_layer.h",
+ "layers/video_layer_impl.cc",
+ "layers/video_layer_impl.h",
+ "output/begin_frame_args.cc",
+ "output/begin_frame_args.h",
+ "output/compositor_frame.cc",
+ "output/compositor_frame.h",
+ "output/compositor_frame_ack.cc",
+ "output/compositor_frame_ack.h",
+ "output/compositor_frame_metadata.cc",
+ "output/compositor_frame_metadata.h",
+ "output/context_provider.cc",
+ "output/context_provider.h",
+ "output/copy_output_request.cc",
+ "output/copy_output_request.h",
+ "output/copy_output_result.cc",
+ "output/copy_output_result.h",
+ "output/delegated_frame_data.h",
+ "output/delegated_frame_data.cc",
+ "output/delegating_renderer.cc",
+ "output/delegating_renderer.h",
+ "output/direct_renderer.cc",
+ "output/direct_renderer.h",
+ "output/filter_operation.cc",
+ "output/filter_operation.h",
+ "output/filter_operations.cc",
+ "output/filter_operations.h",
+ "output/geometry_binding.cc",
+ "output/geometry_binding.h",
+ "output/gl_frame_data.h",
+ "output/gl_frame_data.cc",
+ "output/gl_renderer.cc",
+ "output/gl_renderer.h",
+ "output/gl_renderer_draw_cache.cc",
+ "output/gl_renderer_draw_cache.h",
+ "output/managed_memory_policy.cc",
+ "output/managed_memory_policy.h",
+ "output/output_surface.cc",
+ "output/output_surface.h",
+ "output/output_surface_client.h",
+ "output/overlay_candidate.cc",
+ "output/overlay_candidate.h",
+ "output/overlay_candidate_validator.h",
+ "output/overlay_processor.cc",
+ "output/overlay_processor.h",
+ "output/overlay_strategy_single_on_top.cc",
+ "output/overlay_strategy_single_on_top.h",
+ "output/program_binding.cc",
+ "output/program_binding.h",
+ "output/render_surface_filters.cc",
+ "output/render_surface_filters.h",
+ "output/renderer.cc",
+ "output/renderer.h",
+ "output/shader.cc",
+ "output/shader.h",
+ "output/software_frame_data.cc",
+ "output/software_frame_data.h",
+ "output/software_output_device.cc",
+ "output/software_output_device.h",
+ "output/software_renderer.cc",
+ "output/software_renderer.h",
+ "quads/checkerboard_draw_quad.cc",
+ "quads/checkerboard_draw_quad.h",
+ "quads/content_draw_quad_base.cc",
+ "quads/content_draw_quad_base.h",
+ "quads/debug_border_draw_quad.cc",
+ "quads/debug_border_draw_quad.h",
+ "quads/draw_quad.cc",
+ "quads/draw_quad.h",
+ "quads/io_surface_draw_quad.cc",
+ "quads/io_surface_draw_quad.h",
+ "quads/picture_draw_quad.cc",
+ "quads/picture_draw_quad.h",
+ "quads/render_pass.cc",
+ "quads/render_pass.h",
+ "quads/render_pass_draw_quad.cc",
+ "quads/render_pass_draw_quad.h",
+ "quads/shared_quad_state.cc",
+ "quads/shared_quad_state.h",
+ "quads/solid_color_draw_quad.cc",
+ "quads/solid_color_draw_quad.h",
+ "quads/stream_video_draw_quad.cc",
+ "quads/stream_video_draw_quad.h",
+ "quads/surface_draw_quad.cc",
+ "quads/surface_draw_quad.h",
+ "quads/texture_draw_quad.cc",
+ "quads/texture_draw_quad.h",
+ "quads/tile_draw_quad.cc",
+ "quads/tile_draw_quad.h",
+ "quads/yuv_video_draw_quad.cc",
+ "quads/yuv_video_draw_quad.h",
+ "resources/bitmap_content_layer_updater.cc",
+ "resources/bitmap_content_layer_updater.h",
+ "resources/bitmap_skpicture_content_layer_updater.cc",
+ "resources/bitmap_skpicture_content_layer_updater.h",
+ "resources/content_layer_updater.cc",
+ "resources/content_layer_updater.h",
+ "resources/direct_raster_worker_pool.cc",
+ "resources/direct_raster_worker_pool.h",
+ "resources/image_layer_updater.cc",
+ "resources/image_layer_updater.h",
+ "resources/image_raster_worker_pool.cc",
+ "resources/image_raster_worker_pool.h",
+ "resources/image_copy_raster_worker_pool.cc",
+ "resources/image_copy_raster_worker_pool.h",
+ "resources/layer_painter.h",
+ "resources/layer_quad.cc",
+ "resources/layer_quad.h",
+ "resources/layer_tiling_data.cc",
+ "resources/layer_tiling_data.h",
+ "resources/layer_updater.cc",
+ "resources/layer_updater.h",
+ "resources/managed_tile_state.cc",
+ "resources/managed_tile_state.h",
+ "resources/memory_history.cc",
+ "resources/memory_history.h",
+ "resources/picture.cc",
+ "resources/picture.h",
+ "resources/picture_layer_tiling.cc",
+ "resources/picture_layer_tiling.h",
+ "resources/picture_layer_tiling_set.cc",
+ "resources/picture_layer_tiling_set.h",
+ "resources/picture_pile.cc",
+ "resources/picture_pile.h",
+ "resources/picture_pile_base.cc",
+ "resources/picture_pile_base.h",
+ "resources/picture_pile_impl.cc",
+ "resources/picture_pile_impl.h",
+ "resources/pixel_buffer_raster_worker_pool.cc",
+ "resources/pixel_buffer_raster_worker_pool.h",
+ "resources/platform_color.h",
+ "resources/prioritized_resource.cc",
+ "resources/prioritized_resource.h",
+ "resources/prioritized_resource_manager.cc",
+ "resources/prioritized_resource_manager.h",
+ "resources/prioritized_tile_set.cc",
+ "resources/prioritized_tile_set.h",
+ "resources/priority_calculator.cc",
+ "resources/priority_calculator.h",
+ "resources/raster_mode.cc",
+ "resources/raster_mode.h",
+ "resources/raster_worker_pool.cc",
+ "resources/raster_worker_pool.h",
+ "resources/rasterizer.cc",
+ "resources/rasterizer.h",
+ "resources/release_callback.h",
+ "resources/resource.cc",
+ "resources/resource.h",
+ "resources/resource_format.h",
+ "resources/resource_format.cc",
+ "resources/resource_pool.cc",
+ "resources/resource_pool.h",
+ "resources/resource_provider.cc",
+ "resources/resource_provider.h",
+ "resources/resource_update.cc",
+ "resources/resource_update.h",
+ "resources/resource_update_controller.cc",
+ "resources/resource_update_controller.h",
+ "resources/resource_update_queue.cc",
+ "resources/resource_update_queue.h",
+ "resources/returned_resource.h",
+ "resources/scoped_resource.cc",
+ "resources/scoped_resource.h",
+ "resources/scoped_ui_resource.cc",
+ "resources/scoped_ui_resource.h",
+ "resources/shared_bitmap.cc",
+ "resources/shared_bitmap.h",
+ "resources/shared_bitmap_manager.h",
+ "resources/single_release_callback.cc",
+ "resources/single_release_callback.h",
+ "resources/skpicture_content_layer_updater.cc",
+ "resources/skpicture_content_layer_updater.h",
+ "resources/task_graph_runner.cc",
+ "resources/task_graph_runner.h",
+ "resources/texture_mailbox.cc",
+ "resources/texture_mailbox.h",
+ "resources/texture_mailbox_deleter.cc",
+ "resources/texture_mailbox_deleter.h",
+ "resources/texture_uploader.cc",
+ "resources/texture_uploader.h",
+ "resources/tile.cc",
+ "resources/tile.h",
+ "resources/tile_manager.cc",
+ "resources/tile_manager.h",
+ "resources/tile_priority.cc",
+ "resources/tile_priority.h",
+ "resources/transferable_resource.cc",
+ "resources/transferable_resource.h",
+ "resources/ui_resource_bitmap.cc",
+ "resources/ui_resource_bitmap.h",
+ "resources/ui_resource_client.h",
+ "resources/ui_resource_request.cc",
+ "resources/ui_resource_request.h",
+ "resources/video_resource_updater.cc",
+ "resources/video_resource_updater.h",
+ "scheduler/delay_based_time_source.cc",
+ "scheduler/delay_based_time_source.h",
+ "scheduler/draw_result.h",
+ "scheduler/scheduler.cc",
+ "scheduler/scheduler.h",
+ "scheduler/scheduler_settings.cc",
+ "scheduler/scheduler_settings.h",
+ "scheduler/scheduler_state_machine.cc",
+ "scheduler/scheduler_state_machine.h",
+ "scheduler/time_source.h",
+ "trees/blocking_task_runner.cc",
+ "trees/blocking_task_runner.h",
+ "trees/damage_tracker.cc",
+ "trees/damage_tracker.h",
+ "trees/layer_sorter.cc",
+ "trees/layer_sorter.h",
+ "trees/layer_tree_host.cc",
+ "trees/layer_tree_host.h",
+ "trees/layer_tree_host_client.h",
+ "trees/layer_tree_host_common.cc",
+ "trees/layer_tree_host_common.h",
+ "trees/layer_tree_host_impl.cc",
+ "trees/layer_tree_host_impl.h",
+ "trees/layer_tree_impl.cc",
+ "trees/layer_tree_impl.h",
+ "trees/layer_tree_settings.cc",
+ "trees/layer_tree_settings.h",
+ "trees/occlusion_tracker.cc",
+ "trees/occlusion_tracker.h",
+ "trees/proxy.cc",
+ "trees/proxy.h",
+ "trees/proxy_timing_history.cc",
+ "trees/proxy_timing_history.h",
+ "trees/single_thread_proxy.cc",
+ "trees/single_thread_proxy.h",
+ "trees/thread_proxy.cc",
+ "trees/thread_proxy.h",
+ "trees/tree_synchronizer.cc",
+ "trees/tree_synchronizer.h",
+ ]
+
+ if (is_win) {
+ # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+ cflags = [ "/wd4267" ] # size_t -> int
+ }
+
+ deps = [
+ "//base",
+ "//base/third_party/dynamic_annotations",
+ "//gpu",
+ #"//media", TODO(GYP)
+ "//skia",
+ "//ui/events:events_base",
+ "//ui/gfx",
+ "//ui/gfx/geometry",
+ "//ui/gl",
+ ]
+ forward_dependent_configs_from = [
+ "//skia",
+ ]
+
+ defined = [ "CC_IMPLEMENTATION=1" ]
+
+ if (!is_debug && is_win) {
+ configs -= [ "//build/config/compiler:optimize" ]
+ configs += [ "//build/config/compiler:optimize_max" ]
+ }
+}
+
+component("cc_surfaces") {
+ sources = [
+ "surfaces/surface.cc",
+ "surfaces/surface.h",
+ "surfaces/surface_aggregator.cc",
+ "surfaces/surface_aggregator.h",
+ "surfaces/surface_manager.cc",
+ "surfaces/surface_manager.h",
+ "surfaces/surfaces_export.h",
+ ]
+
+ defines = [ "CC_SURFACES_IMPLEMENTATION=1" ]
+
+ deps = [
+ ":cc",
+ "//base",
+ "//base/third_party/dynamic_annotations",
+ "//skia",
+ "//ui/gfx",
+ "//ui/gfx/geometry",
+ ]
+}
+
+source_set("test_support") {
+ sources = [
+ "test/animation_test_common.cc",
+ "test/animation_test_common.h",
+ "test/begin_frame_args_test.cc",
+ "test/begin_frame_args_test.h",
+ "test/fake_content_layer.cc",
+ "test/fake_content_layer.h",
+ "test/fake_content_layer_client.cc",
+ "test/fake_content_layer_client.h",
+ "test/fake_content_layer_impl.cc",
+ "test/fake_content_layer_impl.h",
+ "test/fake_delegated_renderer_layer.cc",
+ "test/fake_delegated_renderer_layer.h",
+ "test/fake_delegated_renderer_layer_impl.cc",
+ "test/fake_delegated_renderer_layer_impl.h",
+ "test/fake_impl_proxy.h",
+ "test/fake_layer_tree_host.cc",
+ "test/fake_layer_tree_host.h",
+ "test/fake_layer_tree_host_client.cc",
+ "test/fake_layer_tree_host_client.h",
+ "test/fake_layer_tree_host_impl.cc",
+ "test/fake_layer_tree_host_impl.h",
+ "test/fake_layer_tree_host_impl_client.cc",
+ "test/fake_layer_tree_host_impl_client.h",
+ "test/fake_output_surface.cc",
+ "test/fake_output_surface.h",
+ "test/fake_output_surface_client.cc",
+ "test/fake_output_surface_client.h",
+ "test/fake_painted_scrollbar_layer.cc",
+ "test/fake_painted_scrollbar_layer.h",
+ "test/fake_picture_layer.cc",
+ "test/fake_picture_layer.h",
+ "test/fake_picture_layer_impl.cc",
+ "test/fake_picture_layer_impl.h",
+ "test/fake_picture_layer_tiling_client.cc",
+ "test/fake_picture_layer_tiling_client.h",
+ "test/fake_picture_pile_impl.cc",
+ "test/fake_picture_pile_impl.h",
+ "test/fake_proxy.cc",
+ "test/fake_proxy.h",
+ "test/fake_renderer_client.cc",
+ "test/fake_renderer_client.h",
+ "test/fake_rendering_stats_instrumentation.h",
+ "test/fake_scoped_ui_resource.cc",
+ "test/fake_scoped_ui_resource.h",
+ "test/fake_scrollbar.cc",
+ "test/fake_scrollbar.h",
+ "test/fake_tile_manager.cc",
+ "test/fake_tile_manager.h",
+ "test/fake_tile_manager_client.cc",
+ "test/fake_tile_manager_client.h",
+ "test/fake_ui_resource_layer_tree_host_impl.cc",
+ "test/fake_ui_resource_layer_tree_host_impl.h",
+ "test/fake_video_frame_provider.cc",
+ "test/fake_video_frame_provider.h",
+ "test/geometry_test_utils.cc",
+ "test/geometry_test_utils.h",
+ "test/test_in_process_context_provider.cc",
+ "test/test_in_process_context_provider.h",
+ "test/impl_side_painting_settings.h",
+ "test/layer_test_common.cc",
+ "test/layer_test_common.h",
+ "test/layer_tree_host_common_test.cc",
+ "test/layer_tree_host_common_test.h",
+ "test/layer_tree_json_parser.cc",
+ "test/layer_tree_json_parser.h",
+ "test/layer_tree_pixel_test.cc",
+ "test/layer_tree_pixel_test.h",
+ "test/layer_tree_test.cc",
+ "test/layer_tree_test.h",
+ "test/mock_occlusion_tracker.h",
+ "test/mock_quad_culler.cc",
+ "test/mock_quad_culler.h",
+ "test/ordered_simple_task_runner.cc",
+ "test/ordered_simple_task_runner.h",
+ "test/ordered_texture_map.cc",
+ "test/ordered_texture_map.h",
+ "test/paths.cc",
+ "test/paths.h",
+ "test/pixel_comparator.cc",
+ "test/pixel_comparator.h",
+ "test/pixel_test.cc",
+ "test/pixel_test.h",
+ "test/pixel_test_output_surface.cc",
+ "test/pixel_test_output_surface.h",
+ "test/pixel_test_software_output_device.cc",
+ "test/pixel_test_software_output_device.h",
+ "test/pixel_test_utils.cc",
+ "test/pixel_test_utils.h",
+ "test/render_pass_test_common.cc",
+ "test/render_pass_test_common.h",
+ "test/render_pass_test_utils.cc",
+ "test/render_pass_test_utils.h",
+ "test/scheduler_test_common.cc",
+ "test/scheduler_test_common.h",
+ "test/skia_common.cc",
+ "test/skia_common.h",
+ "test/solid_color_content_layer_client.cc",
+ "test/solid_color_content_layer_client.h",
+ "test/test_context_provider.cc",
+ "test/test_context_provider.h",
+ "test/test_context_support.cc",
+ "test/test_context_support.h",
+ "test/test_gles2_interface.cc",
+ "test/test_gles2_interface.h",
+ "test/test_occlusion_tracker.h",
+ "test/test_shared_bitmap_manager.cc",
+ "test/test_shared_bitmap_manager.h",
+ "test/test_texture.cc",
+ "test/test_texture.h",
+ "test/test_tile_priorities.cc",
+ "test/test_tile_priorities.h",
+ "test/test_web_graphics_context_3d.cc",
+ "test/test_web_graphics_context_3d.h",
+ "test/tiled_layer_test_common.cc",
+ "test/tiled_layer_test_common.h",
+ ]
+
+ include_dirs = [
+ ".",
+ "test",
+ ]
+
+ deps = [
+ "//base",
+ "//base/third_party/dynamic_annotations",
+ "//gpu:gpu_unittest_utils",
+ "//gpu/command_buffer/client:gles2_c_lib",
+ "//gpu/command_buffer/client:gles2_implementation",
+ "//gpu/command_buffer/client:gl_in_process_context",
+ "//gpu/skia_bindings",
+ "//skia",
+ "//testing/gmock",
+ "//testing/gtest",
+ # TODO(GYP)
+ #"//third_party/mesa/mesa.gyp:osmesa",
+ "//ui/gfx",
+ "//ui/gfx/geometry",
+ "//ui/gfx:gfx_test_support",
+ "//ui/gl",
+ ]
+}
+
+# TODO(GYP) make these tests link when all deps are resolved.
+if (false) {
+
+test("cc_unittests") {
+ sources = [
+ "animation/animation_unittest.cc",
+ "animation/keyframed_animation_curve_unittest.cc",
+ "animation/layer_animation_controller_unittest.cc",
+ "animation/scroll_offset_animation_curve_unittest.cc",
+ "animation/scrollbar_animation_controller_linear_fade_unittest.cc",
+ "animation/scrollbar_animation_controller_thinning_unittest.cc",
+ "animation/transform_operations_unittest.cc",
+ "base/float_quad_unittest.cc",
+ "base/math_util_unittest.cc",
+ "base/region_unittest.cc",
+ "base/rolling_time_delta_history_unittest.cc",
+ "base/scoped_ptr_vector_unittest.cc",
+ "base/tiling_data_unittest.cc",
+ "base/util_unittest.cc",
+ "debug/micro_benchmark_controller_unittest.cc",
+ "input/top_controls_manager_unittest.cc",
+ "layers/content_layer_unittest.cc",
+ "layers/contents_scaling_layer_unittest.cc",
+ "layers/delegated_frame_provider_unittest.cc",
+ "layers/delegated_frame_resource_collection_unittest.cc",
+ "layers/delegated_renderer_layer_impl_unittest.cc",
+ "layers/heads_up_display_unittest.cc",
+ "layers/heads_up_display_layer_impl_unittest.cc",
+ "layers/io_surface_layer_impl_unittest.cc",
+ "layers/layer_impl_unittest.cc",
+ "layers/layer_iterator_unittest.cc",
+ "layers/layer_position_constraint_unittest.cc",
+ "layers/layer_unittest.cc",
+ "layers/layer_utils_unittest.cc",
+ "layers/nine_patch_layer_impl_unittest.cc",
+ "layers/nine_patch_layer_unittest.cc",
+ "layers/painted_scrollbar_layer_impl_unittest.cc",
+ "layers/picture_image_layer_impl_unittest.cc",
+ "layers/picture_layer_impl_unittest.cc",
+ "layers/picture_layer_unittest.cc",
+ "layers/render_surface_unittest.cc",
+ "layers/render_surface_impl_unittest.cc",
+ "layers/scrollbar_layer_unittest.cc",
+ "layers/solid_color_layer_impl_unittest.cc",
+ "layers/solid_color_scrollbar_layer_impl_unittest.cc",
+ "layers/surface_layer_impl_unittest.cc",
+ "layers/texture_layer_unittest.cc",
+ "layers/texture_layer_impl_unittest.cc",
+ "layers/tiled_layer_impl_unittest.cc",
+ "layers/tiled_layer_unittest.cc",
+ "layers/ui_resource_layer_impl_unittest.cc",
+ "layers/ui_resource_layer_unittest.cc",
+ "layers/video_layer_impl_unittest.cc",
+ "output/begin_frame_args_unittest.cc",
+ "output/delegating_renderer_unittest.cc",
+ "output/filter_operations_unittest.cc",
+ "output/gl_renderer_unittest.cc",
+ "output/output_surface_unittest.cc",
+ "output/overlay_unittest.cc",
+ "output/renderer_pixeltest.cc",
+ "output/renderer_unittest.cc",
+ "output/shader_unittest.cc",
+ "output/software_renderer_unittest.cc",
+ "quads/draw_quad_unittest.cc",
+ "quads/render_pass_unittest.cc",
+ "resources/layer_quad_unittest.cc",
+ "resources/picture_layer_tiling_set_unittest.cc",
+ "resources/picture_layer_tiling_unittest.cc",
+ "resources/picture_pile_impl_unittest.cc",
+ "resources/picture_pile_unittest.cc",
+ "resources/picture_unittest.cc",
+ "resources/prioritized_resource_unittest.cc",
+ "resources/prioritized_tile_set_unittest.cc",
+ "resources/raster_worker_pool_unittest.cc",
+ "resources/resource_provider_unittest.cc",
+ "resources/resource_update_controller_unittest.cc",
+ "resources/scoped_resource_unittest.cc",
+ "resources/task_graph_runner_unittest.cc",
+ "resources/texture_mailbox_deleter_unittest.cc",
+ "resources/texture_uploader_unittest.cc",
+ "resources/tile_manager_unittest.cc",
+ "resources/tile_priority_unittest.cc",
+ "resources/video_resource_updater_unittest.cc",
+ "scheduler/delay_based_time_source_unittest.cc",
+ "scheduler/scheduler_state_machine_unittest.cc",
+ "scheduler/scheduler_unittest.cc",
+ "test/layer_tree_json_parser_unittest.cc",
+ "test/test_web_graphics_context_3d_unittest.cc",
+ "trees/damage_tracker_unittest.cc",
+ "trees/layer_sorter_unittest.cc",
+ "trees/layer_tree_host_common_unittest.cc",
+ "trees/layer_tree_host_impl_unittest.cc",
+ "trees/layer_tree_host_pixeltest_blending.cc",
+ "trees/layer_tree_host_pixeltest_filters.cc",
+ "trees/layer_tree_host_pixeltest_masks.cc",
+ "trees/layer_tree_host_pixeltest_on_demand_raster.cc",
+ "trees/layer_tree_host_pixeltest_readback.cc",
+ "trees/layer_tree_host_unittest.cc",
+ "trees/layer_tree_host_unittest_animation.cc",
+ "trees/layer_tree_host_unittest_context.cc",
+ "trees/layer_tree_host_unittest_copyrequest.cc",
+ "trees/layer_tree_host_unittest_damage.cc",
+ "trees/layer_tree_host_unittest_delegated.cc",
+ "trees/layer_tree_host_unittest_occlusion.cc",
+ "trees/layer_tree_host_unittest_no_message_loop.cc",
+ "trees/layer_tree_host_unittest_picture.cc",
+ "trees/layer_tree_host_unittest_proxy.cc",
+ "trees/layer_tree_host_unittest_scroll.cc",
+ "trees/layer_tree_host_unittest_video.cc",
+ "trees/layer_tree_impl_unittest.cc",
+ "trees/occlusion_tracker_unittest.cc",
+ "trees/tree_synchronizer_unittest.cc",
+
+ # Surfaces test files.
+ "surfaces/surface_aggregator_test_helpers.cc",
+ "surfaces/surface_aggregator_test_helpers.h",
+ "surfaces/surface_aggregator_unittest.cc",
+ "surfaces/surface_unittest.cc",
+ "surfaces/surfaces_pixeltest.cc",
+
+ # Setup.
+ "test/run_all_unittests.cc",
+ "test/cc_test_suite.cc",
+ ]
+
+ deps = [
+ ":cc",
+ ":cc_surfaces",
+ ":test_support",
+ "//base/test:test_support",
+ "//gpu",
+ "//gpu:gpu_unittest_utils",
+ # TODO(GYP)
+ #"//media",
+ "//testing/gmock",
+ "//testing/gtest",
+ "//ui/events:events_base",
+ "//ui/gfx",
+ "//ui/gfx/geometry",
+ ]
+}
+
+test("cc_perftests") {
+ # TODO(GYP)
+}
+
+} # if false
diff --git a/chromium/cc/DEPS b/chromium/cc/DEPS
index 2ae5c7bdef5..33793d7aa3f 100644
--- a/chromium/cc/DEPS
+++ b/chromium/cc/DEPS
@@ -3,18 +3,16 @@ include_rules = [
"+gpu/command_buffer/client/context_support.h",
"+gpu/command_buffer/client/gles2_interface.h",
"+gpu/command_buffer/client/gles2_interface_stub.h", # for tests
- "+gpu/command_buffer/common/gpu_memory_allocation.h",
"+gpu/command_buffer/common/capabilities.h",
+ "+gpu/command_buffer/common/gpu_memory_allocation.h",
"+gpu/command_buffer/common/mailbox.h",
+ "+gpu/command_buffer/common/mailbox_holder.h",
"+media",
"+skia/ext",
- "+third_party/skia/include",
"+third_party/khronos/GLES2/gl2.h",
"+third_party/khronos/GLES2/gl2ext.h",
+ "+third_party/skia/include",
"+ui/events/latency_info.h",
"+ui/gfx",
"+ui/gl",
- # DO NOT ADD ANY NEW WEBKIT HEADERS TO THIS LIST.
- # TODO(danakj): Drop dependencies on WebKit Platform API from cc.
- "+third_party/WebKit/public/platform/WebGraphicsContext3D.h",
]
diff --git a/chromium/cc/OWNERS b/chromium/cc/OWNERS
index 57a0e846d3e..fb45ba60b54 100644
--- a/chromium/cc/OWNERS
+++ b/chromium/cc/OWNERS
@@ -28,6 +28,7 @@ jamesr@chromium.org
# scheduling and texture uploading
brianderson@chromium.org
reveman@chromium.org
+skyostil@chromium.org
# tiles and tile management
reveman@chromium.org
diff --git a/chromium/cc/PRESUBMIT.py b/chromium/cc/PRESUBMIT.py
index 5b8100b8266..3397313bd95 100644
--- a/chromium/cc/PRESUBMIT.py
+++ b/chromium/cc/PRESUBMIT.py
@@ -4,8 +4,8 @@
"""Top-level presubmit script for cc.
-See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts for
-details on the presubmit API built into gcl.
+See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
+for more details about the presubmit API built into depot_tools.
"""
import re
@@ -116,13 +116,6 @@ def CheckPassByValue(input_api,
# Well-defined simple classes containing only <= 4 ints, or <= 2 floats.
pass_by_value_types = ['base::Time',
'base::TimeTicks',
- 'gfx::Point',
- 'gfx::PointF',
- 'gfx::Rect',
- 'gfx::Size',
- 'gfx::SizeF',
- 'gfx::Vector2d',
- 'gfx::Vector2dF',
]
for f in input_api.AffectedSourceFiles(source_file_filter):
@@ -156,6 +149,19 @@ def FindUnquotedQuote(contents, pos):
match = re.search(r"(?<!\\)(?P<quote>\")", contents[pos:])
return -1 if not match else match.start("quote") + pos
+def FindUselessIfdefs(input_api, output_api):
+ errors = []
+ source_file_filter = lambda x: x
+ for f in input_api.AffectedSourceFiles(source_file_filter):
+ contents = input_api.ReadFile(f, 'rb')
+ if re.search(r'#if\s*0\s', contents):
+ errors.append(f.LocalPath())
+ if errors:
+ return [output_api.PresubmitError(
+ 'Don\'t use #if '+'0; just delete the code.',
+ items=errors)]
+ return []
+
def FindNamespaceInBlock(pos, namespace, contents, whitelist=[]):
open_brace = -1
close_brace = -1
@@ -219,6 +225,58 @@ def CheckNamespace(input_api, output_api):
items=errors)]
return []
+def CheckForUseOfWrongClock(input_api,
+ output_api,
+ white_list=CC_SOURCE_FILES,
+ black_list=None):
+ """Make sure new lines of code don't use a clock susceptible to skew."""
+ black_list = tuple(black_list or input_api.DEFAULT_BLACK_LIST)
+ source_file_filter = lambda x: input_api.FilterSourceFile(x,
+ white_list,
+ black_list)
+ # Regular expression that should detect any explicit references to the
+ # base::Time type (or base::Clock/DefaultClock), whether in using decls,
+ # typedefs, or to call static methods.
+ base_time_type_pattern = r'(^|\W)base::(Time|Clock|DefaultClock)(\W|$)'
+
+ # Regular expression that should detect references to the base::Time class
+ # members, such as a call to base::Time::Now.
+ base_time_member_pattern = r'(^|\W)(Time|Clock|DefaultClock)::'
+
+ # Regular expression to detect "using base::Time" declarations. We want to
+ # prevent these from triggerring a warning. For example, it's perfectly
+ # reasonable for code to be written like this:
+ #
+ # using base::Time;
+ # ...
+ # int64 foo_us = foo_s * Time::kMicrosecondsPerSecond;
+ using_base_time_decl_pattern = r'^\s*using\s+(::)?base::Time\s*;'
+
+ # Regular expression to detect references to the kXXX constants in the
+ # base::Time class. We want to prevent these from triggerring a warning.
+ base_time_konstant_pattern = r'(^|\W)Time::k\w+'
+
+ problem_re = input_api.re.compile(
+ r'(' + base_time_type_pattern + r')|(' + base_time_member_pattern + r')')
+ exception_re = input_api.re.compile(
+ r'(' + using_base_time_decl_pattern + r')|(' +
+ base_time_konstant_pattern + r')')
+ problems = []
+ for f in input_api.AffectedSourceFiles(source_file_filter):
+ for line_number, line in f.ChangedContents():
+ if problem_re.search(line):
+ if not exception_re.search(line):
+ problems.append(
+ ' %s:%d\n %s' % (f.LocalPath(), line_number, line.strip()))
+
+ if problems:
+ return [output_api.PresubmitPromptOrNotify(
+ 'You added one or more references to the base::Time class and/or one\n'
+ 'of its member functions (or base::Clock/DefaultClock). In cc code,\n'
+ 'it is most certainly incorrect! Instead use base::TimeTicks.\n\n'
+ '\n'.join(problems))]
+ else:
+ return []
def CheckChangeOnUpload(input_api, output_api):
results = []
@@ -228,13 +286,19 @@ def CheckChangeOnUpload(input_api, output_api):
results += CheckChangeLintsClean(input_api, output_api)
results += CheckTodos(input_api, output_api)
results += CheckNamespace(input_api, output_api)
+ results += CheckForUseOfWrongClock(input_api, output_api)
+ results += FindUselessIfdefs(input_api, output_api)
+ results += input_api.canned_checks.CheckPatchFormatted(input_api, output_api)
return results
-def GetPreferredTrySlaves(project, change):
- return [
- 'linux_layout_rel',
- 'win_gpu',
- 'linux_gpu',
- 'mac_gpu',
- 'mac_gpu_retina',
- ]
+def GetPreferredTryMasters(project, change):
+ return {
+ 'tryserver.chromium': {
+ 'linux_blink_rel': set(['defaulttests']),
+ },
+ 'tryserver.chromium.gpu': {
+ 'linux_gpu': set(['defaulttests']),
+ 'mac_gpu': set(['defaulttests']),
+ 'win_gpu': set(['defaulttests']),
+ },
+ }
diff --git a/chromium/cc/animation/animation.cc b/chromium/cc/animation/animation.cc
index f21a1d48486..4adb88a12e5 100644
--- a/chromium/cc/animation/animation.cc
+++ b/chromium/cc/animation/animation.cc
@@ -32,8 +32,8 @@ static const char* const s_targetPropertyNames[] = {
"Transform",
"Opacity",
"Filter",
- "BackgroundColor",
- "ScrollOffset"
+ "ScrollOffset",
+ "BackgroundColor"
};
COMPILE_ASSERT(static_cast<int>(cc::Animation::TargetPropertyEnumSize) ==
@@ -64,23 +64,23 @@ Animation::Animation(scoped_ptr<AnimationCurve> curve,
target_property_(target_property),
run_state_(WaitingForTargetAvailability),
iterations_(1),
- start_time_(0),
- alternates_direction_(false),
- time_offset_(0),
+ direction_(Normal),
needs_synchronized_start_time_(false),
received_finished_event_(false),
suspended_(false),
- pause_time_(0),
- total_paused_time_(0),
is_controlling_instance_(false),
- is_impl_only_(false) {}
+ is_impl_only_(false),
+ affects_active_observers_(true),
+ affects_pending_observers_(true) {
+}
Animation::~Animation() {
if (run_state_ == Running || run_state_ == Paused)
- SetRunState(Aborted, 0);
+ SetRunState(Aborted, base::TimeTicks());
}
-void Animation::SetRunState(RunState run_state, double monotonic_time) {
+void Animation::SetRunState(RunState run_state,
+ base::TimeTicks monotonic_time) {
if (suspended_)
return;
@@ -105,7 +105,7 @@ void Animation::SetRunState(RunState run_state, double monotonic_time) {
const char* old_run_state_name = s_runStateNames[run_state_];
if (run_state == Running && run_state_ == Paused)
- total_paused_time_ += monotonic_time - pause_time_;
+ total_paused_time_ += (monotonic_time - pause_time_);
else if (run_state == Paused)
pause_time_ = monotonic_time;
run_state_ = run_state;
@@ -131,33 +131,32 @@ void Animation::SetRunState(RunState run_state, double monotonic_time) {
TRACE_STR_COPY(state_buffer));
}
-void Animation::Suspend(double monotonic_time) {
+void Animation::Suspend(base::TimeTicks monotonic_time) {
SetRunState(Paused, monotonic_time);
suspended_ = true;
}
-void Animation::Resume(double monotonic_time) {
+void Animation::Resume(base::TimeTicks monotonic_time) {
suspended_ = false;
SetRunState(Running, monotonic_time);
}
-bool Animation::IsFinishedAt(double monotonic_time) const {
+bool Animation::IsFinishedAt(base::TimeTicks monotonic_time) const {
if (is_finished())
return true;
if (needs_synchronized_start_time_)
return false;
- return run_state_ == Running &&
- iterations_ >= 0 &&
- iterations_ * curve_->Duration() <= (monotonic_time -
- start_time() -
- total_paused_time_ +
- time_offset_);
+ return run_state_ == Running && iterations_ >= 0 &&
+ iterations_ * curve_->Duration() <=
+ (monotonic_time + time_offset_ - start_time_ - total_paused_time_)
+ .InSecondsF();
}
-double Animation::TrimTimeToCurrentIteration(double monotonic_time) const {
- double trimmed = monotonic_time + time_offset_;
+double Animation::TrimTimeToCurrentIteration(
+ base::TimeTicks monotonic_time) const {
+ base::TimeTicks trimmed = monotonic_time + time_offset_;
// If we're paused, time is 'stuck' at the pause time.
if (run_state_ == Paused)
@@ -165,16 +164,18 @@ double Animation::TrimTimeToCurrentIteration(double monotonic_time) const {
// Returned time should always be relative to the start time and should
// subtract all time spent paused.
- trimmed -= start_time_ + total_paused_time_;
+ trimmed -= (start_time_ - base::TimeTicks()) + total_paused_time_;
// If we're just starting or we're waiting on receiving a start time,
// time is 'stuck' at the initial state.
if ((run_state_ == Starting && !has_set_start_time()) ||
needs_synchronized_start_time())
- trimmed = time_offset_;
+ trimmed = base::TimeTicks() + time_offset_;
+
+ double trimmed_in_seconds = (trimmed - base::TimeTicks()).InSecondsF();
- // Zero is always the start of the animation.
- if (trimmed <= 0)
+ // Return 0 if we are before the start of the animation
+ if (trimmed_in_seconds < 0)
return 0;
// Always return zero if we have no iterations.
@@ -185,46 +186,49 @@ double Animation::TrimTimeToCurrentIteration(double monotonic_time) const {
if (curve_->Duration() <= 0)
return 0;
- // If less than an iteration duration, just return trimmed.
- if (trimmed < curve_->Duration())
- return trimmed;
-
- // If greater than or equal to the total duration, return iteration duration.
- if (iterations_ >= 0 && trimmed >= curve_->Duration() * iterations_) {
- if (alternates_direction_ && !(iterations_ % 2))
- return 0;
- return curve_->Duration();
- }
+ // check if we are past active interval
+ bool is_past_total_duration =
+ (iterations_ > 0 &&
+ trimmed_in_seconds >= curve_->Duration() * iterations_);
// We need to know the current iteration if we're alternating.
- int iteration = static_cast<int>(trimmed / curve_->Duration());
-
- // Calculate x where trimmed = x + n * curve_->Duration() for some positive
- // integer n.
- trimmed = fmod(trimmed, curve_->Duration());
+ int iteration = 0;
+
+ // If we are past the active interval, return iteration duration.
+ if (is_past_total_duration) {
+ iteration = iterations_ - 1;
+ trimmed_in_seconds = curve_->Duration();
+ } else {
+ iteration = static_cast<int>(trimmed_in_seconds / curve_->Duration());
+ // Calculate x where trimmed = x + n * curve_->Duration() for some positive
+ // integer n.
+ trimmed_in_seconds = fmod(trimmed_in_seconds, curve_->Duration());
+ }
- // If we're alternating and on an odd iteration, reverse the direction.
- if (alternates_direction_ && iteration % 2 == 1)
- return curve_->Duration() - trimmed;
+ // check if we are running the animation in reverse direction for the current
+ // iteration
+ bool reverse = (direction_ == Reverse) ||
+ (direction_ == Alternate && iteration % 2 == 1) ||
+ (direction_ == AlternateReverse && iteration % 2 == 0);
- return trimmed;
-}
+ // if we are running the animation in reverse direction, reverse the result
+ if (reverse)
+ return curve_->Duration() - trimmed_in_seconds;
-scoped_ptr<Animation> Animation::Clone() const {
- return CloneAndInitialize(run_state_, start_time_);
+ return trimmed_in_seconds;
}
-scoped_ptr<Animation> Animation::CloneAndInitialize(RunState initial_run_state,
- double start_time) const {
+scoped_ptr<Animation> Animation::CloneAndInitialize(
+ RunState initial_run_state) const {
scoped_ptr<Animation> to_return(
new Animation(curve_->Clone(), id_, group_, target_property_));
to_return->run_state_ = initial_run_state;
to_return->iterations_ = iterations_;
- to_return->start_time_ = start_time;
+ to_return->start_time_ = start_time_;
to_return->pause_time_ = pause_time_;
to_return->total_paused_time_ = total_paused_time_;
to_return->time_offset_ = time_offset_;
- to_return->alternates_direction_ = alternates_direction_;
+ to_return->direction_ = direction_;
DCHECK(!to_return->is_controlling_instance_);
to_return->is_controlling_instance_ = true;
return to_return.Pass();
diff --git a/chromium/cc/animation/animation.h b/chromium/cc/animation/animation.h
index c7d53c2745e..02bb2c6013c 100644
--- a/chromium/cc/animation/animation.h
+++ b/chromium/cc/animation/animation.h
@@ -7,6 +7,7 @@
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
#include "cc/base/cc_export.h"
namespace cc {
@@ -42,12 +43,14 @@ class CC_EXPORT Animation {
Transform = 0,
Opacity,
Filter,
- BackgroundColor,
ScrollOffset,
+ BackgroundColor,
// This sentinel must be last.
TargetPropertyEnumSize
};
+ enum Direction { Normal, Reverse, Alternate, AlternateReverse };
+
static scoped_ptr<Animation> Create(scoped_ptr<AnimationCurve> curve,
int animation_id,
int group_id,
@@ -60,7 +63,7 @@ class CC_EXPORT Animation {
TargetProperty target_property() const { return target_property_; }
RunState run_state() const { return run_state_; }
- void SetRunState(RunState run_state, double monotonic_time);
+ void SetRunState(RunState run_state, base::TimeTicks monotonic_time);
// This is the number of times that the animation will play. If this
// value is zero the animation will not play. If it is negative, then
@@ -68,24 +71,25 @@ class CC_EXPORT Animation {
int iterations() const { return iterations_; }
void set_iterations(int n) { iterations_ = n; }
- double start_time() const { return start_time_; }
- void set_start_time(double monotonic_time) { start_time_ = monotonic_time; }
- bool has_set_start_time() const { return !!start_time_; }
-
- double time_offset() const { return time_offset_; }
- void set_time_offset(double monotonic_time) { time_offset_ = monotonic_time; }
+ base::TimeTicks start_time() const { return start_time_; }
- void Suspend(double monotonic_time);
- void Resume(double monotonic_time);
+ void set_start_time(base::TimeTicks monotonic_time) {
+ start_time_ = monotonic_time;
+ }
+ bool has_set_start_time() const { return !start_time_.is_null(); }
- // If alternates_direction is true, on odd numbered iterations we reverse the
- // curve.
- bool alternates_direction() const { return alternates_direction_; }
- void set_alternates_direction(bool alternates) {
- alternates_direction_ = alternates;
+ base::TimeDelta time_offset() const { return time_offset_; }
+ void set_time_offset(base::TimeDelta monotonic_time) {
+ time_offset_ = monotonic_time;
}
- bool IsFinishedAt(double monotonic_time) const;
+ void Suspend(base::TimeTicks monotonic_time);
+ void Resume(base::TimeTicks monotonic_time);
+
+ Direction direction() { return direction_; }
+ void set_direction(Direction direction) { direction_ = direction; }
+
+ bool IsFinishedAt(base::TimeTicks monotonic_time) const;
bool is_finished() const {
return run_state_ == Finished ||
run_state_ == Aborted ||
@@ -116,11 +120,10 @@ class CC_EXPORT Animation {
// Takes the given absolute time, and using the start time and the number
// of iterations, returns the relative time in the current iteration.
- double TrimTimeToCurrentIteration(double monotonic_time) const;
+ double TrimTimeToCurrentIteration(base::TimeTicks monotonic_time) const;
+
+ scoped_ptr<Animation> CloneAndInitialize(RunState initial_run_state) const;
- scoped_ptr<Animation> Clone() const;
- scoped_ptr<Animation> CloneAndInitialize(RunState initial_run_state,
- double start_time) const;
bool is_controlling_instance() const { return is_controlling_instance_; }
void PushPropertiesTo(Animation* other) const;
@@ -128,6 +131,16 @@ class CC_EXPORT Animation {
void set_is_impl_only(bool is_impl_only) { is_impl_only_ = is_impl_only; }
bool is_impl_only() const { return is_impl_only_; }
+ void set_affects_active_observers(bool affects_active_observers) {
+ affects_active_observers_ = affects_active_observers;
+ }
+ bool affects_active_observers() const { return affects_active_observers_; }
+
+ void set_affects_pending_observers(bool affects_pending_observers) {
+ affects_pending_observers_ = affects_pending_observers;
+ }
+ bool affects_pending_observers() const { return affects_pending_observers_; }
+
private:
Animation(scoped_ptr<AnimationCurve> curve,
int animation_id,
@@ -149,14 +162,14 @@ class CC_EXPORT Animation {
TargetProperty target_property_;
RunState run_state_;
int iterations_;
- double start_time_;
- bool alternates_direction_;
+ base::TimeTicks start_time_;
+ Direction direction_;
// The time offset effectively pushes the start of the animation back in time.
// This is used for resuming paused animations -- an animation is added with a
// non-zero time offset, causing the animation to skip ahead to the desired
// point in time.
- double time_offset_;
+ base::TimeDelta time_offset_;
bool needs_synchronized_start_time_;
bool received_finished_event_;
@@ -170,8 +183,8 @@ class CC_EXPORT Animation {
// spent while paused. This is not included in AnimationState since it
// there is absolutely no need for clients of this controller to know
// about these values.
- double pause_time_;
- double total_paused_time_;
+ base::TimeTicks pause_time_;
+ base::TimeDelta total_paused_time_;
// Animations lead dual lives. An active animation will be conceptually owned
// by two controllers, one on the impl thread and one on the main. In reality,
@@ -184,6 +197,20 @@ class CC_EXPORT Animation {
bool is_impl_only_;
+ // When pushed from a main-thread controller to a compositor-thread
+ // controller, an animation will initially only affect pending observers
+ // (corresponding to layers in the pending tree). Animations that only
+ // affect pending observers are able to reach the Starting state and tick
+ // pending observers, but cannot proceed any further and do not tick active
+ // observers. After activation, such animations affect both kinds of observers
+ // and are able to proceed past the Starting state. When the removal of
+ // an animation is pushed from a main-thread controller to a
+ // compositor-thread controller, this initially only makes the animation
+ // stop affecting pending observers. After activation, such animations no
+ // longer affect any observers, and are deleted.
+ bool affects_active_observers_;
+ bool affects_pending_observers_;
+
DISALLOW_COPY_AND_ASSIGN(Animation);
};
diff --git a/chromium/cc/animation/animation_curve.h b/chromium/cc/animation/animation_curve.h
index 9bcccba1294..72aadefbf8e 100644
--- a/chromium/cc/animation/animation_curve.h
+++ b/chromium/cc/animation/animation_curve.h
@@ -75,6 +75,16 @@ class CC_EXPORT TransformAnimationCurve : public AnimationCurve {
virtual bool AnimatedBoundsForBox(const gfx::BoxF& box,
gfx::BoxF* bounds) const = 0;
+ // Returns true if this animation affects scale.
+ virtual bool AffectsScale() const = 0;
+
+ // Returns true if this animation is a translation.
+ virtual bool IsTranslation() const = 0;
+
+ // Set |max_scale| to the maximum scale along any dimension during this
+ // animation. Returns false if the maximum scale cannot be computed.
+ virtual bool MaximumScale(float* max_scale) const = 0;
+
// Partial Animation implementation.
virtual CurveType Type() const OVERRIDE;
};
@@ -84,6 +94,7 @@ class CC_EXPORT FilterAnimationCurve : public AnimationCurve {
virtual ~FilterAnimationCurve() {}
virtual FilterOperations GetValue(double t) const = 0;
+ virtual bool HasFilterThatMovesPixels() const = 0;
// Partial Animation implementation.
virtual CurveType Type() const OVERRIDE;
diff --git a/chromium/cc/animation/animation_delegate.h b/chromium/cc/animation/animation_delegate.h
index f1176a36a46..0f83bec44c6 100644
--- a/chromium/cc/animation/animation_delegate.h
+++ b/chromium/cc/animation/animation_delegate.h
@@ -12,14 +12,10 @@ namespace cc {
class AnimationDelegate {
public:
- // TODO(ajuma): Remove wall_clock_time once the legacy implementation of
- // CSS animations and transitions in Blink is removed.
virtual void NotifyAnimationStarted(
- double wall_clock_time,
base::TimeTicks monotonic_time,
Animation::TargetProperty target_property) = 0;
virtual void NotifyAnimationFinished(
- double wall_clock_time,
base::TimeTicks monotonic_time,
Animation::TargetProperty target_property) = 0;
diff --git a/chromium/cc/animation/animation_events.cc b/chromium/cc/animation/animation_events.cc
index 95b0e071a21..40a9031e7c6 100644
--- a/chromium/cc/animation/animation_events.cc
+++ b/chromium/cc/animation/animation_events.cc
@@ -10,7 +10,7 @@ AnimationEvent::AnimationEvent(AnimationEvent::Type type,
int layer_id,
int group_id,
Animation::TargetProperty target_property,
- double monotonic_time)
+ base::TimeTicks monotonic_time)
: type(type),
layer_id(layer_id),
group_id(group_id),
diff --git a/chromium/cc/animation/animation_events.h b/chromium/cc/animation/animation_events.h
index e0cf73645c9..e40ca3f633f 100644
--- a/chromium/cc/animation/animation_events.h
+++ b/chromium/cc/animation/animation_events.h
@@ -21,13 +21,13 @@ struct CC_EXPORT AnimationEvent {
int layer_id,
int group_id,
Animation::TargetProperty target_property,
- double monotonic_time);
+ base::TimeTicks monotonic_time);
Type type;
int layer_id;
int group_id;
Animation::TargetProperty target_property;
- double monotonic_time;
+ base::TimeTicks monotonic_time;
bool is_impl_only;
float opacity;
gfx::Transform transform;
diff --git a/chromium/cc/animation/animation_unittest.cc b/chromium/cc/animation/animation_unittest.cc
index 8223cee5855..1d4b8f7a167 100644
--- a/chromium/cc/animation/animation_unittest.cc
+++ b/chromium/cc/animation/animation_unittest.cc
@@ -11,6 +11,13 @@
namespace cc {
namespace {
+using base::TimeDelta;
+
+static base::TimeTicks TicksFromSecondsF(double seconds) {
+ return base::TimeTicks::FromInternalValue(seconds *
+ base::Time::kMicrosecondsPerSecond);
+}
+
scoped_ptr<Animation> CreateAnimation(int iterations, double duration) {
scoped_ptr<Animation> to_return(Animation::Create(
make_scoped_ptr(
@@ -28,234 +35,370 @@ scoped_ptr<Animation> CreateAnimation(int iterations) {
TEST(AnimationTest, TrimTimeZeroIterations) {
scoped_ptr<Animation> anim(CreateAnimation(0));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(-1.0));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(0.0));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(1.0));
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
}
TEST(AnimationTest, TrimTimeOneIteration) {
scoped_ptr<Animation> anim(CreateAnimation(1));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(-1.0));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(0.0));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(1.0));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(2.0));
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
+ EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
+ EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
}
TEST(AnimationTest, TrimTimeInfiniteIterations) {
scoped_ptr<Animation> anim(CreateAnimation(-1));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(0.0));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(0.5));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(1.0));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(1.5));
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)));
+}
+
+TEST(AnimationTest, TrimTimeReverse) {
+ scoped_ptr<Animation> anim(CreateAnimation(-1));
+ anim->set_direction(Animation::Reverse);
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0)));
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
+ EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75)));
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25)));
+}
+
+TEST(AnimationTest, TrimTimeAlternateInfiniteIterations) {
+ scoped_ptr<Animation> anim(CreateAnimation(-1));
+ anim->set_direction(Animation::Alternate);
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
+ EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75)));
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25)));
}
-TEST(AnimationTest, TrimTimeAlternating) {
+TEST(AnimationTest, TrimTimeAlternateOneIteration) {
+ scoped_ptr<Animation> anim(CreateAnimation(1));
+ anim->set_direction(Animation::Alternate);
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
+ EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75)));
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25)));
+}
+
+TEST(AnimationTest, TrimTimeAlternateTwoIterations) {
+ scoped_ptr<Animation> anim(CreateAnimation(2));
+ anim->set_direction(Animation::Alternate);
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
+ EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75)));
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25)));
+ EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.75)));
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.25)));
+}
+
+TEST(AnimationTest, TrimTimeAlternateReverseInfiniteIterations) {
scoped_ptr<Animation> anim(CreateAnimation(-1));
- anim->set_alternates_direction(true);
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(0.0));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(0.5));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(1.0));
- EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(1.25));
+ anim->set_direction(Animation::AlternateReverse);
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
+ EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75)));
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
+ EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25)));
+}
+
+TEST(AnimationTest, TrimTimeAlternateReverseOneIteration) {
+ scoped_ptr<Animation> anim(CreateAnimation(1));
+ anim->set_direction(Animation::AlternateReverse);
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
+ EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75)));
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25)));
+}
+
+TEST(AnimationTest, TrimTimeAlternateReverseTwoIterations) {
+ scoped_ptr<Animation> anim(CreateAnimation(2));
+ anim->set_direction(Animation::AlternateReverse);
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
+ EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75)));
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
+ EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25)));
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.75)));
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.25)));
}
TEST(AnimationTest, TrimTimeStartTime) {
scoped_ptr<Animation> anim(CreateAnimation(1));
- anim->set_start_time(4);
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(0.0));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(4.0));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(4.5));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(5.0));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(6.0));
+ anim->set_start_time(TicksFromSecondsF(4));
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.0)));
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.5)));
+ EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(5.0)));
+ EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(6.0)));
+}
+
+TEST(AnimationTest, TrimTimeStartTimeReverse) {
+ scoped_ptr<Animation> anim(CreateAnimation(1));
+ anim->set_start_time(TicksFromSecondsF(4));
+ anim->set_direction(Animation::Reverse);
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.0)));
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.5)));
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(5.0)));
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(6.0)));
}
TEST(AnimationTest, TrimTimeTimeOffset) {
scoped_ptr<Animation> anim(CreateAnimation(1));
- anim->set_time_offset(4);
- anim->set_start_time(4);
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(0.0));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(0.5));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(1.0));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(1.0));
+ anim->set_time_offset(TimeDelta::FromMilliseconds(4000));
+ anim->set_start_time(TicksFromSecondsF(4));
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
+ EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
+ EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
+}
+
+TEST(AnimationTest, TrimTimeTimeOffsetReverse) {
+ scoped_ptr<Animation> anim(CreateAnimation(1));
+ anim->set_time_offset(TimeDelta::FromMilliseconds(4000));
+ anim->set_start_time(TicksFromSecondsF(4));
+ anim->set_direction(Animation::Reverse);
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
}
TEST(AnimationTest, TrimTimeNegativeTimeOffset) {
scoped_ptr<Animation> anim(CreateAnimation(1));
- anim->set_time_offset(-4);
+ anim->set_time_offset(TimeDelta::FromMilliseconds(-4000));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(0.0));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(4.0));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(4.5));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(5.0));
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.0)));
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.5)));
+ EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(5.0)));
+}
+
+TEST(AnimationTest, TrimTimeNegativeTimeOffsetReverse) {
+ scoped_ptr<Animation> anim(CreateAnimation(1));
+ anim->set_time_offset(TimeDelta::FromMilliseconds(-4000));
+ anim->set_direction(Animation::Reverse);
+
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.0)));
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.5)));
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(5.0)));
}
TEST(AnimationTest, TrimTimePauseResume) {
scoped_ptr<Animation> anim(CreateAnimation(1));
- anim->SetRunState(Animation::Running, 0.0);
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(0.0));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(0.5));
- anim->SetRunState(Animation::Paused, 0.5);
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(1024.0));
- anim->SetRunState(Animation::Running, 1024.0);
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(1024.0));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(1024.5));
+ anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
+ anim->SetRunState(Animation::Paused, TicksFromSecondsF(0.5));
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0)));
+ anim->SetRunState(Animation::Running, TicksFromSecondsF(1024.0));
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0)));
+ EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.5)));
+}
+
+TEST(AnimationTest, TrimTimePauseResumeReverse) {
+ scoped_ptr<Animation> anim(CreateAnimation(1));
+ anim->set_direction(Animation::Reverse);
+ anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
+ anim->SetRunState(Animation::Paused, TicksFromSecondsF(0.25));
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0)));
+ anim->SetRunState(Animation::Running, TicksFromSecondsF(1024.0));
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0)));
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.75)));
}
TEST(AnimationTest, TrimTimeSuspendResume) {
scoped_ptr<Animation> anim(CreateAnimation(1));
- anim->SetRunState(Animation::Running, 0.0);
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(0.0));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(0.5));
- anim->Suspend(0.5);
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(1024.0));
- anim->Resume(1024);
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(1024.0));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(1024.5));
+ anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
+ anim->Suspend(TicksFromSecondsF(0.5));
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0)));
+ anim->Resume(TicksFromSecondsF(1024));
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0)));
+ EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.5)));
+}
+
+TEST(AnimationTest, TrimTimeSuspendResumeReverse) {
+ scoped_ptr<Animation> anim(CreateAnimation(1));
+ anim->set_direction(Animation::Reverse);
+ anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
+ anim->Suspend(TicksFromSecondsF(0.75));
+ EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0)));
+ anim->Resume(TicksFromSecondsF(1024));
+ EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0)));
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.25)));
}
TEST(AnimationTest, TrimTimeZeroDuration) {
scoped_ptr<Animation> anim(CreateAnimation(0, 0));
- anim->SetRunState(Animation::Running, 0.0);
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(-1.0));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(0.0));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(1.0));
+ anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
}
TEST(AnimationTest, TrimTimeStarting) {
scoped_ptr<Animation> anim(CreateAnimation(1, 5.0));
- anim->SetRunState(Animation::Starting, 0.0);
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(-1.0));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(0.0));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(1.0));
- anim->set_time_offset(2.0);
- EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(-1.0));
- EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(0.0));
- EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(1.0));
- anim->set_start_time(1.0);
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(-1.0));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(0.0));
- EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(1.0));
- EXPECT_EQ(3.0, anim->TrimTimeToCurrentIteration(2.0));
+ anim->SetRunState(Animation::Starting, TicksFromSecondsF(0.0));
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
+ anim->set_time_offset(TimeDelta::FromMilliseconds(2000));
+ EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
+ EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
+ EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
+ anim->set_start_time(TicksFromSecondsF(1.0));
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
+ EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
+ EXPECT_EQ(3.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
}
TEST(AnimationTest, TrimTimeNeedsSynchronizedStartTime) {
scoped_ptr<Animation> anim(CreateAnimation(1, 5.0));
- anim->SetRunState(Animation::Running, 0.0);
+ anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
anim->set_needs_synchronized_start_time(true);
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(-1.0));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(0.0));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(1.0));
- anim->set_time_offset(2.0);
- EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(-1.0));
- EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(0.0));
- EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(1.0));
- anim->set_start_time(1.0);
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
+ anim->set_time_offset(TimeDelta::FromMilliseconds(2000));
+ EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
+ EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
+ EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
+ anim->set_start_time(TicksFromSecondsF(1.0));
anim->set_needs_synchronized_start_time(false);
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(0.0));
- EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(1.0));
- EXPECT_EQ(3.0, anim->TrimTimeToCurrentIteration(2.0));
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
+ EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
+ EXPECT_EQ(3.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
}
TEST(AnimationTest, IsFinishedAtZeroIterations) {
scoped_ptr<Animation> anim(CreateAnimation(0));
- anim->SetRunState(Animation::Running, 0.0);
- EXPECT_FALSE(anim->IsFinishedAt(-1.0));
- EXPECT_TRUE(anim->IsFinishedAt(0.0));
- EXPECT_TRUE(anim->IsFinishedAt(1.0));
+ anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
+ EXPECT_FALSE(anim->IsFinishedAt(TicksFromSecondsF(-1.0)));
+ EXPECT_TRUE(anim->IsFinishedAt(TicksFromSecondsF(0.0)));
+ EXPECT_TRUE(anim->IsFinishedAt(TicksFromSecondsF(1.0)));
}
TEST(AnimationTest, IsFinishedAtOneIteration) {
scoped_ptr<Animation> anim(CreateAnimation(1));
- anim->SetRunState(Animation::Running, 0.0);
- EXPECT_FALSE(anim->IsFinishedAt(-1.0));
- EXPECT_FALSE(anim->IsFinishedAt(0.0));
- EXPECT_TRUE(anim->IsFinishedAt(1.0));
- EXPECT_TRUE(anim->IsFinishedAt(2.0));
+ anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
+ EXPECT_FALSE(anim->IsFinishedAt(TicksFromSecondsF(-1.0)));
+ EXPECT_FALSE(anim->IsFinishedAt(TicksFromSecondsF(0.0)));
+ EXPECT_TRUE(anim->IsFinishedAt(TicksFromSecondsF(1.0)));
+ EXPECT_TRUE(anim->IsFinishedAt(TicksFromSecondsF(2.0)));
}
TEST(AnimationTest, IsFinishedAtInfiniteIterations) {
scoped_ptr<Animation> anim(CreateAnimation(-1));
- anim->SetRunState(Animation::Running, 0.0);
- EXPECT_FALSE(anim->IsFinishedAt(0.0));
- EXPECT_FALSE(anim->IsFinishedAt(0.5));
- EXPECT_FALSE(anim->IsFinishedAt(1.0));
- EXPECT_FALSE(anim->IsFinishedAt(1.5));
+ anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
+ EXPECT_FALSE(anim->IsFinishedAt(TicksFromSecondsF(0.0)));
+ EXPECT_FALSE(anim->IsFinishedAt(TicksFromSecondsF(0.5)));
+ EXPECT_FALSE(anim->IsFinishedAt(TicksFromSecondsF(1.0)));
+ EXPECT_FALSE(anim->IsFinishedAt(TicksFromSecondsF(1.5)));
}
TEST(AnimationTest, IsFinishedNegativeTimeOffset) {
scoped_ptr<Animation> anim(CreateAnimation(1));
- anim->set_time_offset(-0.5);
- anim->SetRunState(Animation::Running, 0.0);
+ anim->set_time_offset(TimeDelta::FromMilliseconds(-500));
+ anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
- EXPECT_FALSE(anim->IsFinishedAt(-1.0));
- EXPECT_FALSE(anim->IsFinishedAt(0.0));
- EXPECT_FALSE(anim->IsFinishedAt(0.5));
- EXPECT_FALSE(anim->IsFinishedAt(1.0));
- EXPECT_TRUE(anim->IsFinishedAt(1.5));
- EXPECT_TRUE(anim->IsFinishedAt(2.0));
- EXPECT_TRUE(anim->IsFinishedAt(2.5));
+ EXPECT_FALSE(anim->IsFinishedAt(TicksFromSecondsF(-1.0)));
+ EXPECT_FALSE(anim->IsFinishedAt(TicksFromSecondsF(0.0)));
+ EXPECT_FALSE(anim->IsFinishedAt(TicksFromSecondsF(0.5)));
+ EXPECT_FALSE(anim->IsFinishedAt(TicksFromSecondsF(1.0)));
+ EXPECT_TRUE(anim->IsFinishedAt(TicksFromSecondsF(1.5)));
+ EXPECT_TRUE(anim->IsFinishedAt(TicksFromSecondsF(2.0)));
+ EXPECT_TRUE(anim->IsFinishedAt(TicksFromSecondsF(2.5)));
}
TEST(AnimationTest, IsFinishedPositiveTimeOffset) {
scoped_ptr<Animation> anim(CreateAnimation(1));
- anim->set_time_offset(0.5);
- anim->SetRunState(Animation::Running, 0.0);
+ anim->set_time_offset(TimeDelta::FromMilliseconds(500));
+ anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
- EXPECT_FALSE(anim->IsFinishedAt(-1.0));
- EXPECT_FALSE(anim->IsFinishedAt(0.0));
- EXPECT_TRUE(anim->IsFinishedAt(0.5));
- EXPECT_TRUE(anim->IsFinishedAt(1.0));
+ EXPECT_FALSE(anim->IsFinishedAt(TicksFromSecondsF(-1.0)));
+ EXPECT_FALSE(anim->IsFinishedAt(TicksFromSecondsF(0.0)));
+ EXPECT_TRUE(anim->IsFinishedAt(TicksFromSecondsF(0.5)));
+ EXPECT_TRUE(anim->IsFinishedAt(TicksFromSecondsF(1.0)));
}
TEST(AnimationTest, IsFinishedAtNotRunning) {
scoped_ptr<Animation> anim(CreateAnimation(0));
- anim->SetRunState(Animation::Running, 0.0);
- EXPECT_TRUE(anim->IsFinishedAt(0.0));
- anim->SetRunState(Animation::Paused, 0.0);
- EXPECT_FALSE(anim->IsFinishedAt(0.0));
- anim->SetRunState(Animation::WaitingForTargetAvailability, 0.0);
- EXPECT_FALSE(anim->IsFinishedAt(0.0));
- anim->SetRunState(Animation::Finished, 0.0);
- EXPECT_TRUE(anim->IsFinishedAt(0.0));
- anim->SetRunState(Animation::Aborted, 0.0);
- EXPECT_TRUE(anim->IsFinishedAt(0.0));
+ anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
+ EXPECT_TRUE(anim->IsFinishedAt(TicksFromSecondsF(0.0)));
+ anim->SetRunState(Animation::Paused, TicksFromSecondsF(0.0));
+ EXPECT_FALSE(anim->IsFinishedAt(TicksFromSecondsF(0.0)));
+ anim->SetRunState(Animation::WaitingForTargetAvailability,
+ TicksFromSecondsF(0.0));
+ EXPECT_FALSE(anim->IsFinishedAt(TicksFromSecondsF(0.0)));
+ anim->SetRunState(Animation::Finished, TicksFromSecondsF(0.0));
+ EXPECT_TRUE(anim->IsFinishedAt(TicksFromSecondsF(0.0)));
+ anim->SetRunState(Animation::Aborted, TicksFromSecondsF(0.0));
+ EXPECT_TRUE(anim->IsFinishedAt(TicksFromSecondsF(0.0)));
}
TEST(AnimationTest, IsFinished) {
scoped_ptr<Animation> anim(CreateAnimation(1));
- anim->SetRunState(Animation::Running, 0.0);
+ anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
EXPECT_FALSE(anim->is_finished());
- anim->SetRunState(Animation::Paused, 0.0);
+ anim->SetRunState(Animation::Paused, TicksFromSecondsF(0.0));
EXPECT_FALSE(anim->is_finished());
- anim->SetRunState(Animation::WaitingForTargetAvailability, 0.0);
+ anim->SetRunState(Animation::WaitingForTargetAvailability,
+ TicksFromSecondsF(0.0));
EXPECT_FALSE(anim->is_finished());
- anim->SetRunState(Animation::Finished, 0.0);
+ anim->SetRunState(Animation::Finished, TicksFromSecondsF(0.0));
EXPECT_TRUE(anim->is_finished());
- anim->SetRunState(Animation::Aborted, 0.0);
+ anim->SetRunState(Animation::Aborted, TicksFromSecondsF(0.0));
EXPECT_TRUE(anim->is_finished());
}
TEST(AnimationTest, IsFinishedNeedsSynchronizedStartTime) {
scoped_ptr<Animation> anim(CreateAnimation(1));
- anim->SetRunState(Animation::Running, 2.0);
+ anim->SetRunState(Animation::Running, TicksFromSecondsF(2.0));
EXPECT_FALSE(anim->is_finished());
- anim->SetRunState(Animation::Paused, 2.0);
+ anim->SetRunState(Animation::Paused, TicksFromSecondsF(2.0));
EXPECT_FALSE(anim->is_finished());
- anim->SetRunState(Animation::WaitingForTargetAvailability, 2.0);
+ anim->SetRunState(Animation::WaitingForTargetAvailability,
+ TicksFromSecondsF(2.0));
EXPECT_FALSE(anim->is_finished());
- anim->SetRunState(Animation::Finished, 0.0);
+ anim->SetRunState(Animation::Finished, TicksFromSecondsF(0.0));
EXPECT_TRUE(anim->is_finished());
- anim->SetRunState(Animation::Aborted, 0.0);
+ anim->SetRunState(Animation::Aborted, TicksFromSecondsF(0.0));
EXPECT_TRUE(anim->is_finished());
}
TEST(AnimationTest, RunStateChangesIgnoredWhileSuspended) {
scoped_ptr<Animation> anim(CreateAnimation(1));
- anim->Suspend(0);
+ anim->Suspend(TicksFromSecondsF(0));
EXPECT_EQ(Animation::Paused, anim->run_state());
- anim->SetRunState(Animation::Running, 0.0);
+ anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
EXPECT_EQ(Animation::Paused, anim->run_state());
- anim->Resume(0);
- anim->SetRunState(Animation::Running, 0.0);
+ anim->Resume(TicksFromSecondsF(0));
+ anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
EXPECT_EQ(Animation::Running, anim->run_state());
}
diff --git a/chromium/cc/animation/keyframed_animation_curve.cc b/chromium/cc/animation/keyframed_animation_curve.cc
index d855decbaf9..4522ca2e6d9 100644
--- a/chromium/cc/animation/keyframed_animation_curve.cc
+++ b/chromium/cc/animation/keyframed_animation_curve.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 <algorithm>
+
#include "cc/animation/keyframed_animation_curve.h"
#include "ui/gfx/animation/tween.h"
#include "ui/gfx/box_f.h"
@@ -333,6 +335,44 @@ bool KeyframedTransformAnimationCurve::AnimatedBoundsForBox(
return true;
}
+bool KeyframedTransformAnimationCurve::AffectsScale() const {
+ for (size_t i = 0; i < keyframes_.size(); ++i) {
+ if (keyframes_[i]->Value().AffectsScale())
+ return true;
+ }
+ return false;
+}
+
+bool KeyframedTransformAnimationCurve::IsTranslation() const {
+ for (size_t i = 0; i < keyframes_.size(); ++i) {
+ if (!keyframes_[i]->Value().IsTranslation() &&
+ !keyframes_[i]->Value().IsIdentity())
+ return false;
+ }
+ return true;
+}
+
+bool KeyframedTransformAnimationCurve::MaximumScale(float* max_scale) const {
+ DCHECK_GE(keyframes_.size(), 2ul);
+ *max_scale = 0.f;
+ for (size_t i = 1; i < keyframes_.size(); ++i) {
+ float min_progress = 0.f;
+ float max_progress = 1.f;
+ if (keyframes_[i - 1]->timing_function())
+ keyframes_[i - 1]->timing_function()->Range(&min_progress, &max_progress);
+
+ float max_scale_for_segment = 0.f;
+ if (!keyframes_[i]->Value().MaximumScale(keyframes_[i - 1]->Value(),
+ min_progress,
+ max_progress,
+ &max_scale_for_segment))
+ return false;
+
+ *max_scale = std::max(*max_scale, max_scale_for_segment);
+ }
+ return true;
+}
+
scoped_ptr<KeyframedFilterAnimationCurve> KeyframedFilterAnimationCurve::
Create() {
return make_scoped_ptr(new KeyframedFilterAnimationCurve);
@@ -369,4 +409,13 @@ FilterOperations KeyframedFilterAnimationCurve::GetValue(double t) const {
return GetCurveValue<FilterOperations, FilterKeyframe>(&keyframes_, t);
}
+bool KeyframedFilterAnimationCurve::HasFilterThatMovesPixels() const {
+ for (size_t i = 0; i < keyframes_.size(); ++i) {
+ if (keyframes_[i]->Value().HasFilterThatMovesPixels()) {
+ return true;
+ }
+ }
+ return false;
+}
+
} // namespace cc
diff --git a/chromium/cc/animation/keyframed_animation_curve.h b/chromium/cc/animation/keyframed_animation_curve.h
index 4b5ac3bf307..ded48c6721f 100644
--- a/chromium/cc/animation/keyframed_animation_curve.h
+++ b/chromium/cc/animation/keyframed_animation_curve.h
@@ -183,6 +183,9 @@ class CC_EXPORT KeyframedTransformAnimationCurve
virtual gfx::Transform GetValue(double t) const OVERRIDE;
virtual bool AnimatedBoundsForBox(const gfx::BoxF& box,
gfx::BoxF* bounds) const OVERRIDE;
+ virtual bool AffectsScale() const OVERRIDE;
+ virtual bool IsTranslation() const OVERRIDE;
+ virtual bool MaximumScale(float* max_scale) const OVERRIDE;
private:
KeyframedTransformAnimationCurve();
@@ -210,6 +213,7 @@ class CC_EXPORT KeyframedFilterAnimationCurve
// FilterAnimationCurve implementation
virtual FilterOperations GetValue(double t) const OVERRIDE;
+ virtual bool HasFilterThatMovesPixels() const OVERRIDE;
private:
KeyframedFilterAnimationCurve();
diff --git a/chromium/cc/animation/keyframed_animation_curve_unittest.cc b/chromium/cc/animation/keyframed_animation_curve_unittest.cc
index 63e98668021..eceba6fc9e5 100644
--- a/chromium/cc/animation/keyframed_animation_curve_unittest.cc
+++ b/chromium/cc/animation/keyframed_animation_curve_unittest.cc
@@ -9,7 +9,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/animation/tween.h"
#include "ui/gfx/box_f.h"
-#include "ui/gfx/test/color_util.h"
+#include "ui/gfx/test/gfx_util.h"
namespace cc {
namespace {
@@ -451,5 +451,99 @@ TEST(KeyframedAnimationCurveTest, AnimatedBounds) {
bounds.ToString());
}
+// Tests that animations that affect scale are correctly identified.
+TEST(KeyframedAnimationCurveTest, AffectsScale) {
+ scoped_ptr<KeyframedTransformAnimationCurve> curve(
+ KeyframedTransformAnimationCurve::Create());
+
+ TransformOperations operations1;
+ curve->AddKeyframe(TransformKeyframe::Create(
+ 0.0, operations1, scoped_ptr<TimingFunction>()));
+ operations1.AppendTranslate(2.0, 3.0, -1.0);
+ TransformOperations operations2;
+ operations2.AppendTranslate(4.0, 1.0, 2.0);
+ curve->AddKeyframe(TransformKeyframe::Create(
+ 1.0, operations2, scoped_ptr<TimingFunction>()));
+
+ EXPECT_FALSE(curve->AffectsScale());
+
+ TransformOperations operations3;
+ operations3.AppendScale(2.f, 2.f, 2.f);
+ curve->AddKeyframe(TransformKeyframe::Create(
+ 2.0, operations3, scoped_ptr<TimingFunction>()));
+
+ EXPECT_TRUE(curve->AffectsScale());
+
+ TransformOperations operations4;
+ operations3.AppendTranslate(2.f, 2.f, 2.f);
+ curve->AddKeyframe(TransformKeyframe::Create(
+ 3.0, operations4, scoped_ptr<TimingFunction>()));
+
+ EXPECT_TRUE(curve->AffectsScale());
+}
+
+// Tests that animations that are translations are correctly identified.
+TEST(KeyframedAnimationCurveTest, IsTranslation) {
+ scoped_ptr<KeyframedTransformAnimationCurve> curve(
+ KeyframedTransformAnimationCurve::Create());
+
+ TransformOperations operations1;
+ curve->AddKeyframe(TransformKeyframe::Create(
+ 0.0, operations1, scoped_ptr<TimingFunction>()));
+ operations1.AppendTranslate(2.0, 3.0, -1.0);
+ TransformOperations operations2;
+ operations2.AppendTranslate(4.0, 1.0, 2.0);
+ curve->AddKeyframe(TransformKeyframe::Create(
+ 1.0, operations2, scoped_ptr<TimingFunction>()));
+
+ EXPECT_TRUE(curve->IsTranslation());
+
+ TransformOperations operations3;
+ operations3.AppendScale(2.f, 2.f, 2.f);
+ curve->AddKeyframe(TransformKeyframe::Create(
+ 2.0, operations3, scoped_ptr<TimingFunction>()));
+
+ EXPECT_FALSE(curve->IsTranslation());
+
+ TransformOperations operations4;
+ operations3.AppendTranslate(2.f, 2.f, 2.f);
+ curve->AddKeyframe(TransformKeyframe::Create(
+ 3.0, operations4, scoped_ptr<TimingFunction>()));
+
+ EXPECT_FALSE(curve->IsTranslation());
+}
+
+// Tests that maximum scale is computed as expected.
+TEST(KeyframedAnimationCurveTest, MaximumScale) {
+ scoped_ptr<KeyframedTransformAnimationCurve> curve(
+ KeyframedTransformAnimationCurve::Create());
+
+ TransformOperations operations1;
+ curve->AddKeyframe(TransformKeyframe::Create(
+ 0.0, operations1, scoped_ptr<TimingFunction>()));
+ operations1.AppendScale(2.f, -3.f, 1.f);
+ curve->AddKeyframe(TransformKeyframe::Create(
+ 1.0, operations1, EaseTimingFunction::Create()));
+
+ float maximum_scale = 0.f;
+ EXPECT_TRUE(curve->MaximumScale(&maximum_scale));
+ EXPECT_EQ(3.f, maximum_scale);
+
+ TransformOperations operations2;
+ operations2.AppendScale(6.f, 3.f, 2.f);
+ curve->AddKeyframe(TransformKeyframe::Create(
+ 2.0, operations2, EaseTimingFunction::Create()));
+
+ EXPECT_TRUE(curve->MaximumScale(&maximum_scale));
+ EXPECT_EQ(6.f, maximum_scale);
+
+ TransformOperations operations3;
+ operations3.AppendRotate(1.f, 0.f, 0.f, 90.f);
+ curve->AddKeyframe(TransformKeyframe::Create(
+ 3.0, operations3, EaseTimingFunction::Create()));
+
+ EXPECT_FALSE(curve->MaximumScale(&maximum_scale));
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/animation/layer_animation_controller.cc b/chromium/cc/animation/layer_animation_controller.cc
index e1ab6464a1f..ddbf35af661 100644
--- a/chromium/cc/animation/layer_animation_controller.cc
+++ b/chromium/cc/animation/layer_animation_controller.cc
@@ -24,9 +24,10 @@ LayerAnimationController::LayerAnimationController(int id)
: registrar_(0),
id_(id),
is_active_(false),
- last_tick_time_(0),
value_provider_(NULL),
- layer_animation_delegate_(NULL) {}
+ layer_animation_delegate_(NULL),
+ needs_to_start_animations_(false) {
+}
LayerAnimationController::~LayerAnimationController() {
if (registrar_)
@@ -39,11 +40,11 @@ scoped_refptr<LayerAnimationController> LayerAnimationController::Create(
}
void LayerAnimationController::PauseAnimation(int animation_id,
- double time_offset) {
- for (size_t i = 0; i < active_animations_.size(); ++i) {
- if (active_animations_[i]->id() == animation_id) {
- active_animations_[i]->SetRunState(
- Animation::Paused, time_offset + active_animations_[i]->start_time());
+ base::TimeDelta time_offset) {
+ for (size_t i = 0; i < animations_.size(); ++i) {
+ if (animations_[i]->id() == animation_id) {
+ animations_[i]->SetRunState(Animation::Paused,
+ time_offset + animations_[i]->start_time());
}
}
}
@@ -59,12 +60,11 @@ struct HasAnimationId {
};
void LayerAnimationController::RemoveAnimation(int animation_id) {
- ScopedPtrVector<Animation>& animations = active_animations_;
- animations.erase(cc::remove_if(&animations,
- animations.begin(),
- animations.end(),
- HasAnimationId(animation_id)),
- animations.end());
+ animations_.erase(cc::remove_if(&animations_,
+ animations_.begin(),
+ animations_.end(),
+ HasAnimationId(animation_id)),
+ animations_.end());
UpdateActivation(NormalActivation);
}
@@ -84,22 +84,21 @@ struct HasAnimationIdAndProperty {
void LayerAnimationController::RemoveAnimation(
int animation_id,
Animation::TargetProperty target_property) {
- ScopedPtrVector<Animation>& animations = active_animations_;
- animations.erase(
- cc::remove_if(&animations,
- animations.begin(),
- animations.end(),
+ animations_.erase(
+ cc::remove_if(&animations_,
+ animations_.begin(),
+ animations_.end(),
HasAnimationIdAndProperty(animation_id, target_property)),
- animations.end());
+ animations_.end());
UpdateActivation(NormalActivation);
}
void LayerAnimationController::AbortAnimations(
Animation::TargetProperty target_property) {
- for (size_t i = 0; i < active_animations_.size(); ++i) {
- if (active_animations_[i]->target_property() == target_property &&
- !active_animations_[i]->is_finished())
- active_animations_[i]->SetRunState(Animation::Aborted, last_tick_time_);
+ for (size_t i = 0; i < animations_.size(); ++i) {
+ if (animations_[i]->target_property() == target_property &&
+ !animations_[i]->is_finished())
+ animations_[i]->SetRunState(Animation::Aborted, last_tick_time_);
}
}
@@ -123,24 +122,25 @@ void LayerAnimationController::PushAnimationUpdatesTo(
UpdateActivation(NormalActivation);
}
-void LayerAnimationController::Animate(double monotonic_time) {
- DCHECK(monotonic_time);
+void LayerAnimationController::Animate(base::TimeTicks monotonic_time) {
+ DCHECK(!monotonic_time.is_null());
if (!HasValueObserver())
return;
- StartAnimations(monotonic_time);
+ if (needs_to_start_animations_)
+ StartAnimations(monotonic_time);
TickAnimations(monotonic_time);
last_tick_time_ = monotonic_time;
}
void LayerAnimationController::AccumulatePropertyUpdates(
- double monotonic_time,
+ base::TimeTicks monotonic_time,
AnimationEventsVector* events) {
if (!events)
return;
- for (size_t i = 0; i < active_animations_.size(); ++i) {
- Animation* animation = active_animations_[i];
+ for (size_t i = 0; i < animations_.size(); ++i) {
+ Animation* animation = animations_[i];
if (!animation->is_impl_only())
continue;
@@ -205,13 +205,14 @@ void LayerAnimationController::UpdateState(bool start_ready_animations,
if (!HasActiveValueObserver())
return;
+ DCHECK(last_tick_time_ != base::TimeTicks());
if (start_ready_animations)
PromoteStartedAnimations(last_tick_time_, events);
MarkFinishedAnimations(last_tick_time_);
MarkAnimationsForDeletion(last_tick_time_, events);
- if (start_ready_animations) {
+ if (needs_to_start_animations_ && start_ready_animations) {
StartAnimations(last_tick_time_);
PromoteStartedAnimations(last_tick_time_, events);
}
@@ -221,34 +222,55 @@ void LayerAnimationController::UpdateState(bool start_ready_animations,
UpdateActivation(NormalActivation);
}
+struct AffectsNoObservers {
+ bool operator()(Animation* animation) const {
+ return !animation->affects_active_observers() &&
+ !animation->affects_pending_observers();
+ }
+};
+
+void LayerAnimationController::ActivateAnimations() {
+ for (size_t i = 0; i < animations_.size(); ++i) {
+ animations_[i]->set_affects_active_observers(
+ animations_[i]->affects_pending_observers());
+ }
+ animations_.erase(cc::remove_if(&animations_,
+ animations_.begin(),
+ animations_.end(),
+ AffectsNoObservers()),
+ animations_.end());
+ UpdateActivation(NormalActivation);
+}
+
void LayerAnimationController::AddAnimation(scoped_ptr<Animation> animation) {
- active_animations_.push_back(animation.Pass());
+ animations_.push_back(animation.Pass());
+ needs_to_start_animations_ = true;
UpdateActivation(NormalActivation);
}
Animation* LayerAnimationController::GetAnimation(
int group_id,
Animation::TargetProperty target_property) const {
- for (size_t i = 0; i < active_animations_.size(); ++i)
- if (active_animations_[i]->group() == group_id &&
- active_animations_[i]->target_property() == target_property)
- return active_animations_[i];
+ for (size_t i = 0; i < animations_.size(); ++i)
+ if (animations_[i]->group() == group_id &&
+ animations_[i]->target_property() == target_property)
+ return animations_[i];
return 0;
}
Animation* LayerAnimationController::GetAnimation(
Animation::TargetProperty target_property) const {
- for (size_t i = 0; i < active_animations_.size(); ++i) {
- size_t index = active_animations_.size() - i - 1;
- if (active_animations_[index]->target_property() == target_property)
- return active_animations_[index];
+ for (size_t i = 0; i < animations_.size(); ++i) {
+ size_t index = animations_.size() - i - 1;
+ if (animations_[index]->target_property() == target_property)
+ return animations_[index];
}
return 0;
}
bool LayerAnimationController::HasActiveAnimation() const {
- for (size_t i = 0; i < active_animations_.size(); ++i) {
- if (!active_animations_[i]->is_finished())
+ for (size_t i = 0; i < animations_.size(); ++i) {
+ if (!animations_[i]->is_finished())
return true;
}
return false;
@@ -256,9 +278,9 @@ bool LayerAnimationController::HasActiveAnimation() const {
bool LayerAnimationController::IsAnimatingProperty(
Animation::TargetProperty target_property) const {
- for (size_t i = 0; i < active_animations_.size(); ++i) {
- if (!active_animations_[i]->is_finished() &&
- active_animations_[i]->target_property() == target_property)
+ for (size_t i = 0; i < animations_.size(); ++i) {
+ if (!animations_[i]->is_finished() &&
+ animations_[i]->target_property() == target_property)
return true;
}
return false;
@@ -280,32 +302,29 @@ void LayerAnimationController::SetAnimationRegistrar(
}
void LayerAnimationController::NotifyAnimationStarted(
- const AnimationEvent& event,
- double wall_clock_time) {
- base::TimeTicks monotonic_time = base::TimeTicks::FromInternalValue(
- event.monotonic_time * base::Time::kMicrosecondsPerSecond);
+ const AnimationEvent& event) {
if (event.is_impl_only) {
FOR_EACH_OBSERVER(LayerAnimationEventObserver, event_observers_,
OnAnimationStarted(event));
if (layer_animation_delegate_)
- layer_animation_delegate_->NotifyAnimationStarted(
- wall_clock_time, monotonic_time, event.target_property);
-
+ layer_animation_delegate_->NotifyAnimationStarted(event.monotonic_time,
+ event.target_property);
return;
}
- for (size_t i = 0; i < active_animations_.size(); ++i) {
- if (active_animations_[i]->group() == event.group_id &&
- active_animations_[i]->target_property() == event.target_property &&
- active_animations_[i]->needs_synchronized_start_time()) {
- active_animations_[i]->set_needs_synchronized_start_time(false);
- active_animations_[i]->set_start_time(event.monotonic_time);
+ for (size_t i = 0; i < animations_.size(); ++i) {
+ if (animations_[i]->group() == event.group_id &&
+ animations_[i]->target_property() == event.target_property &&
+ animations_[i]->needs_synchronized_start_time()) {
+ animations_[i]->set_needs_synchronized_start_time(false);
+ if (!animations_[i]->has_set_start_time())
+ animations_[i]->set_start_time(event.monotonic_time);
FOR_EACH_OBSERVER(LayerAnimationEventObserver, event_observers_,
OnAnimationStarted(event));
if (layer_animation_delegate_)
layer_animation_delegate_->NotifyAnimationStarted(
- wall_clock_time, monotonic_time, event.target_property);
+ event.monotonic_time, event.target_property);
return;
}
@@ -313,24 +332,21 @@ void LayerAnimationController::NotifyAnimationStarted(
}
void LayerAnimationController::NotifyAnimationFinished(
- const AnimationEvent& event,
- double wall_clock_time) {
- base::TimeTicks monotonic_time = base::TimeTicks::FromInternalValue(
- event.monotonic_time * base::Time::kMicrosecondsPerSecond);
+ const AnimationEvent& event) {
if (event.is_impl_only) {
if (layer_animation_delegate_)
- layer_animation_delegate_->NotifyAnimationFinished(
- wall_clock_time, monotonic_time, event.target_property);
+ layer_animation_delegate_->NotifyAnimationFinished(event.monotonic_time,
+ event.target_property);
return;
}
- for (size_t i = 0; i < active_animations_.size(); ++i) {
- if (active_animations_[i]->group() == event.group_id &&
- active_animations_[i]->target_property() == event.target_property) {
- active_animations_[i]->set_received_finished_event(true);
+ for (size_t i = 0; i < animations_.size(); ++i) {
+ if (animations_[i]->group() == event.group_id &&
+ animations_[i]->target_property() == event.target_property) {
+ animations_[i]->set_received_finished_event(true);
if (layer_animation_delegate_)
layer_animation_delegate_->NotifyAnimationFinished(
- wall_clock_time, monotonic_time, event.target_property);
+ event.monotonic_time, event.target_property);
return;
}
@@ -339,23 +355,26 @@ void LayerAnimationController::NotifyAnimationFinished(
void LayerAnimationController::NotifyAnimationAborted(
const AnimationEvent& event) {
- for (size_t i = 0; i < active_animations_.size(); ++i) {
- if (active_animations_[i]->group() == event.group_id &&
- active_animations_[i]->target_property() == event.target_property) {
- active_animations_[i]->SetRunState(Animation::Aborted,
- event.monotonic_time);
+ for (size_t i = 0; i < animations_.size(); ++i) {
+ if (animations_[i]->group() == event.group_id &&
+ animations_[i]->target_property() == event.target_property) {
+ animations_[i]->SetRunState(Animation::Aborted, event.monotonic_time);
}
}
}
void LayerAnimationController::NotifyAnimationPropertyUpdate(
const AnimationEvent& event) {
+ bool notify_active_observers = true;
+ bool notify_pending_observers = true;
switch (event.target_property) {
case Animation::Opacity:
- NotifyObserversOpacityAnimated(event.opacity);
+ NotifyObserversOpacityAnimated(
+ event.opacity, notify_active_observers, notify_pending_observers);
break;
case Animation::Transform:
- NotifyObserversTransformAnimated(event.transform);
+ NotifyObserversTransformAnimated(
+ event.transform, notify_active_observers, notify_pending_observers);
break;
default:
NOTREACHED();
@@ -384,20 +403,50 @@ void LayerAnimationController::RemoveEventObserver(
event_observers_.RemoveObserver(observer);
}
-bool LayerAnimationController::AnimatedBoundsForBox(const gfx::BoxF& box,
- gfx::BoxF* bounds) {
+bool LayerAnimationController::HasFilterAnimationThatInflatesBounds() const {
+ for (size_t i = 0; i < animations_.size(); ++i) {
+ if (!animations_[i]->is_finished() &&
+ animations_[i]->target_property() == Animation::Filter &&
+ animations_[i]
+ ->curve()
+ ->ToFilterAnimationCurve()
+ ->HasFilterThatMovesPixels())
+ return true;
+ }
+
+ return false;
+}
+
+bool LayerAnimationController::HasTransformAnimationThatInflatesBounds() const {
+ return IsAnimatingProperty(Animation::Transform);
+}
+
+bool LayerAnimationController::FilterAnimationBoundsForBox(
+ const gfx::BoxF& box, gfx::BoxF* bounds) const {
+ // TODO(avallee): Implement.
+ return false;
+}
+
+bool LayerAnimationController::TransformAnimationBoundsForBox(
+ const gfx::BoxF& box,
+ gfx::BoxF* bounds) const {
+ DCHECK(HasTransformAnimationThatInflatesBounds())
+ << "TransformAnimationBoundsForBox will give incorrect results if there "
+ << "are no transform animations affecting bounds, non-animated transform "
+ << "is not known";
+
// Compute bounds based on animations for which is_finished() is false.
// Do nothing if there are no such animations; in this case, it is assumed
// that callers will take care of computing bounds based on the owning layer's
// actual transform.
*bounds = gfx::BoxF();
- for (size_t i = 0; i < active_animations_.size(); ++i) {
- if (active_animations_[i]->is_finished() ||
- active_animations_[i]->target_property() != Animation::Transform)
+ for (size_t i = 0; i < animations_.size(); ++i) {
+ if (animations_[i]->is_finished() ||
+ animations_[i]->target_property() != Animation::Transform)
continue;
const TransformAnimationCurve* transform_animation_curve =
- active_animations_[i]->curve()->ToTransformAnimationCurve();
+ animations_[i]->curve()->ToTransformAnimationCurve();
gfx::BoxF animation_bounds;
bool success =
transform_animation_curve->AnimatedBoundsForBox(box, &animation_bounds);
@@ -409,15 +458,63 @@ bool LayerAnimationController::AnimatedBoundsForBox(const gfx::BoxF& box,
return true;
}
+bool LayerAnimationController::HasAnimationThatAffectsScale() const {
+ for (size_t i = 0; i < animations_.size(); ++i) {
+ if (animations_[i]->is_finished() ||
+ animations_[i]->target_property() != Animation::Transform)
+ continue;
+
+ const TransformAnimationCurve* transform_animation_curve =
+ animations_[i]->curve()->ToTransformAnimationCurve();
+ if (transform_animation_curve->AffectsScale())
+ return true;
+ }
+
+ return false;
+}
+
+bool LayerAnimationController::HasOnlyTranslationTransforms() const {
+ for (size_t i = 0; i < animations_.size(); ++i) {
+ if (animations_[i]->is_finished() ||
+ animations_[i]->target_property() != Animation::Transform)
+ continue;
+
+ const TransformAnimationCurve* transform_animation_curve =
+ animations_[i]->curve()->ToTransformAnimationCurve();
+ if (!transform_animation_curve->IsTranslation())
+ return false;
+ }
+
+ return true;
+}
+
+bool LayerAnimationController::MaximumScale(float* max_scale) const {
+ *max_scale = 0.f;
+ for (size_t i = 0; i < animations_.size(); ++i) {
+ if (animations_[i]->is_finished() ||
+ animations_[i]->target_property() != Animation::Transform)
+ continue;
+
+ const TransformAnimationCurve* transform_animation_curve =
+ animations_[i]->curve()->ToTransformAnimationCurve();
+ float animation_scale = 0.f;
+ if (!transform_animation_curve->MaximumScale(&animation_scale))
+ return false;
+ *max_scale = std::max(*max_scale, animation_scale);
+ }
+
+ return true;
+}
+
void LayerAnimationController::PushNewAnimationsToImplThread(
LayerAnimationController* controller_impl) const {
// Any new animations owned by the main thread's controller are cloned and
// add to the impl thread's controller.
- for (size_t i = 0; i < active_animations_.size(); ++i) {
+ for (size_t i = 0; i < animations_.size(); ++i) {
// If the animation is already running on the impl thread, there is no
// need to copy it over.
- if (controller_impl->GetAnimation(active_animations_[i]->group(),
- active_animations_[i]->target_property()))
+ if (controller_impl->GetAnimation(animations_[i]->group(),
+ animations_[i]->target_property()))
continue;
// If the animation is not running on the impl thread, it does not
@@ -426,11 +523,11 @@ void LayerAnimationController::PushNewAnimationsToImplThread(
// have already notified that it has started and the main thread animation
// will no longer need
// a synchronized start time.
- if (!active_animations_[i]->needs_synchronized_start_time())
+ if (!animations_[i]->needs_synchronized_start_time())
continue;
// Scroll animations always start at the current scroll offset.
- if (active_animations_[i]->target_property() == Animation::ScrollOffset) {
+ if (animations_[i]->target_property() == Animation::ScrollOffset) {
gfx::Vector2dF current_scroll_offset;
if (controller_impl->value_provider_) {
current_scroll_offset =
@@ -440,168 +537,194 @@ void LayerAnimationController::PushNewAnimationsToImplThread(
// scroll offset will be up-to-date.
current_scroll_offset = value_provider_->ScrollOffsetForAnimation();
}
- active_animations_[i]->curve()->ToScrollOffsetAnimationCurve()
- ->SetInitialValue(current_scroll_offset);
+ animations_[i]->curve()->ToScrollOffsetAnimationCurve()->SetInitialValue(
+ current_scroll_offset);
}
// The new animation should be set to run as soon as possible.
Animation::RunState initial_run_state =
Animation::WaitingForTargetAvailability;
- double start_time = 0;
- scoped_ptr<Animation> to_add(active_animations_[i]->CloneAndInitialize(
- initial_run_state, start_time));
+ scoped_ptr<Animation> to_add(
+ animations_[i]->CloneAndInitialize(initial_run_state));
DCHECK(!to_add->needs_synchronized_start_time());
+ to_add->set_affects_active_observers(false);
controller_impl->AddAnimation(to_add.Pass());
}
}
-struct IsCompleted {
- explicit IsCompleted(const LayerAnimationController& main_thread_controller)
- : main_thread_controller_(main_thread_controller) {}
- bool operator()(Animation* animation) const {
- if (animation->is_impl_only()) {
- return (animation->run_state() == Animation::WaitingForDeletion);
- } else {
- return !main_thread_controller_.GetAnimation(
- animation->group(),
- animation->target_property());
- }
+static bool IsCompleted(
+ Animation* animation,
+ const LayerAnimationController* main_thread_controller) {
+ if (animation->is_impl_only()) {
+ return (animation->run_state() == Animation::WaitingForDeletion);
+ } else {
+ return !main_thread_controller->GetAnimation(animation->group(),
+ animation->target_property());
}
+}
- private:
- const LayerAnimationController& main_thread_controller_;
-};
+static bool AffectsActiveOnlyAndIsWaitingForDeletion(Animation* animation) {
+ return animation->run_state() == Animation::WaitingForDeletion &&
+ !animation->affects_pending_observers();
+}
void LayerAnimationController::RemoveAnimationsCompletedOnMainThread(
LayerAnimationController* controller_impl) const {
- // Delete all impl thread animations for which there is no corresponding
- // main thread animation. Each iteration,
- // controller->active_animations_.size() is decremented or i is incremented
- // guaranteeing progress towards loop termination.
- ScopedPtrVector<Animation>& animations =
- controller_impl->active_animations_;
+ // Animations removed on the main thread should no longer affect pending
+ // observers, and should stop affecting active observers after the next call
+ // to ActivateAnimations. If already WaitingForDeletion, they can be removed
+ // immediately.
+ ScopedPtrVector<Animation>& animations = controller_impl->animations_;
+ for (size_t i = 0; i < animations.size(); ++i) {
+ if (IsCompleted(animations[i], this))
+ animations[i]->set_affects_pending_observers(false);
+ }
animations.erase(cc::remove_if(&animations,
animations.begin(),
animations.end(),
- IsCompleted(*this)),
+ AffectsActiveOnlyAndIsWaitingForDeletion),
animations.end());
}
void LayerAnimationController::PushPropertiesToImplThread(
LayerAnimationController* controller_impl) const {
- for (size_t i = 0; i < active_animations_.size(); ++i) {
- Animation* current_impl =
- controller_impl->GetAnimation(
- active_animations_[i]->group(),
- active_animations_[i]->target_property());
+ for (size_t i = 0; i < animations_.size(); ++i) {
+ Animation* current_impl = controller_impl->GetAnimation(
+ animations_[i]->group(), animations_[i]->target_property());
if (current_impl)
- active_animations_[i]->PushPropertiesTo(current_impl);
+ animations_[i]->PushPropertiesTo(current_impl);
}
}
-void LayerAnimationController::StartAnimations(double monotonic_time) {
- // First collect running properties.
- TargetProperties blocked_properties;
- for (size_t i = 0; i < active_animations_.size(); ++i) {
- if (active_animations_[i]->run_state() == Animation::Starting ||
- active_animations_[i]->run_state() == Animation::Running)
- blocked_properties.insert(active_animations_[i]->target_property());
+void LayerAnimationController::StartAnimations(base::TimeTicks monotonic_time) {
+ DCHECK(needs_to_start_animations_);
+ needs_to_start_animations_ = false;
+ // First collect running properties affecting each type of observer.
+ TargetProperties blocked_properties_for_active_observers;
+ TargetProperties blocked_properties_for_pending_observers;
+ for (size_t i = 0; i < animations_.size(); ++i) {
+ if (animations_[i]->run_state() == Animation::Starting ||
+ animations_[i]->run_state() == Animation::Running) {
+ if (animations_[i]->affects_active_observers()) {
+ blocked_properties_for_active_observers.insert(
+ animations_[i]->target_property());
+ }
+ if (animations_[i]->affects_pending_observers()) {
+ blocked_properties_for_pending_observers.insert(
+ animations_[i]->target_property());
+ }
+ }
}
- for (size_t i = 0; i < active_animations_.size(); ++i) {
- if (active_animations_[i]->run_state() ==
+ for (size_t i = 0; i < animations_.size(); ++i) {
+ if (animations_[i]->run_state() ==
Animation::WaitingForTargetAvailability) {
// Collect all properties for animations with the same group id (they
// should all also be in the list of animations).
TargetProperties enqueued_properties;
- enqueued_properties.insert(active_animations_[i]->target_property());
- for (size_t j = i + 1; j < active_animations_.size(); ++j) {
- if (active_animations_[i]->group() == active_animations_[j]->group())
- enqueued_properties.insert(active_animations_[j]->target_property());
+ bool affects_active_observers =
+ animations_[i]->affects_active_observers();
+ bool affects_pending_observers =
+ animations_[i]->affects_pending_observers();
+ enqueued_properties.insert(animations_[i]->target_property());
+ for (size_t j = i + 1; j < animations_.size(); ++j) {
+ if (animations_[i]->group() == animations_[j]->group()) {
+ enqueued_properties.insert(animations_[j]->target_property());
+ affects_active_observers |=
+ animations_[j]->affects_active_observers();
+ affects_pending_observers |=
+ animations_[j]->affects_pending_observers();
+ }
}
// Check to see if intersection of the list of properties affected by
- // the group and the list of currently blocked properties is null. In
- // any case, the group's target properties need to be added to the list
- // of blocked properties.
+ // the group and the list of currently blocked properties is null, taking
+ // into account the type(s) of observers affected by the group. In any
+ // case, the group's target properties need to be added to the lists of
+ // blocked properties.
bool null_intersection = true;
for (TargetProperties::iterator p_iter = enqueued_properties.begin();
p_iter != enqueued_properties.end();
++p_iter) {
- if (!blocked_properties.insert(*p_iter).second)
+ if (affects_active_observers &&
+ !blocked_properties_for_active_observers.insert(*p_iter).second)
+ null_intersection = false;
+ if (affects_pending_observers &&
+ !blocked_properties_for_pending_observers.insert(*p_iter).second)
null_intersection = false;
}
// If the intersection is null, then we are free to start the animations
// in the group.
if (null_intersection) {
- active_animations_[i]->SetRunState(
- Animation::Starting, monotonic_time);
- for (size_t j = i + 1; j < active_animations_.size(); ++j) {
- if (active_animations_[i]->group() ==
- active_animations_[j]->group()) {
- active_animations_[j]->SetRunState(
- Animation::Starting, monotonic_time);
+ animations_[i]->SetRunState(Animation::Starting, monotonic_time);
+ for (size_t j = i + 1; j < animations_.size(); ++j) {
+ if (animations_[i]->group() == animations_[j]->group()) {
+ animations_[j]->SetRunState(Animation::Starting, monotonic_time);
}
}
+ } else {
+ needs_to_start_animations_ = true;
}
}
}
}
void LayerAnimationController::PromoteStartedAnimations(
- double monotonic_time,
+ base::TimeTicks monotonic_time,
AnimationEventsVector* events) {
- for (size_t i = 0; i < active_animations_.size(); ++i) {
- if (active_animations_[i]->run_state() == Animation::Starting) {
- active_animations_[i]->SetRunState(Animation::Running, monotonic_time);
- if (!active_animations_[i]->has_set_start_time())
- active_animations_[i]->set_start_time(monotonic_time);
+ for (size_t i = 0; i < animations_.size(); ++i) {
+ if (animations_[i]->run_state() == Animation::Starting &&
+ animations_[i]->affects_active_observers()) {
+ animations_[i]->SetRunState(Animation::Running, monotonic_time);
+ if (!animations_[i]->has_set_start_time() &&
+ !animations_[i]->needs_synchronized_start_time())
+ animations_[i]->set_start_time(monotonic_time);
if (events) {
- AnimationEvent started_event(
- AnimationEvent::Started,
- id_,
- active_animations_[i]->group(),
- active_animations_[i]->target_property(),
- monotonic_time);
- started_event.is_impl_only = active_animations_[i]->is_impl_only();
+ AnimationEvent started_event(AnimationEvent::Started,
+ id_,
+ animations_[i]->group(),
+ animations_[i]->target_property(),
+ monotonic_time);
+ started_event.is_impl_only = animations_[i]->is_impl_only();
events->push_back(started_event);
}
}
}
}
-void LayerAnimationController::MarkFinishedAnimations(double monotonic_time) {
- for (size_t i = 0; i < active_animations_.size(); ++i) {
- if (active_animations_[i]->IsFinishedAt(monotonic_time) &&
- active_animations_[i]->run_state() != Animation::Aborted &&
- active_animations_[i]->run_state() != Animation::WaitingForDeletion)
- active_animations_[i]->SetRunState(Animation::Finished, monotonic_time);
+void LayerAnimationController::MarkFinishedAnimations(
+ base::TimeTicks monotonic_time) {
+ for (size_t i = 0; i < animations_.size(); ++i) {
+ if (animations_[i]->IsFinishedAt(monotonic_time) &&
+ animations_[i]->run_state() != Animation::Aborted &&
+ animations_[i]->run_state() != Animation::WaitingForDeletion)
+ animations_[i]->SetRunState(Animation::Finished, monotonic_time);
}
}
void LayerAnimationController::MarkAnimationsForDeletion(
- double monotonic_time, AnimationEventsVector* events) {
+ base::TimeTicks monotonic_time,
+ AnimationEventsVector* events) {
bool marked_animations_for_deletions = false;
// Non-aborted animations are marked for deletion after a corresponding
// AnimationEvent::Finished event is sent or received. This means that if
// we don't have an events vector, we must ensure that non-aborted animations
// have received a finished event before marking them for deletion.
- for (size_t i = 0; i < active_animations_.size(); i++) {
- int group_id = active_animations_[i]->group();
- if (active_animations_[i]->run_state() == Animation::Aborted) {
- if (events && !active_animations_[i]->is_impl_only()) {
- AnimationEvent aborted_event(
- AnimationEvent::Aborted,
- id_,
- group_id,
- active_animations_[i]->target_property(),
- monotonic_time);
+ for (size_t i = 0; i < animations_.size(); i++) {
+ int group_id = animations_[i]->group();
+ if (animations_[i]->run_state() == Animation::Aborted) {
+ if (events && !animations_[i]->is_impl_only()) {
+ AnimationEvent aborted_event(AnimationEvent::Aborted,
+ id_,
+ group_id,
+ animations_[i]->target_property(),
+ monotonic_time);
events->push_back(aborted_event);
}
- active_animations_[i]->SetRunState(Animation::WaitingForDeletion,
- monotonic_time);
+ animations_[i]->SetRunState(Animation::WaitingForDeletion,
+ monotonic_time);
marked_animations_for_deletions = true;
continue;
}
@@ -612,18 +735,18 @@ void LayerAnimationController::MarkAnimationsForDeletion(
// on the impl thread, we only mark a Finished main thread animation for
// deletion once it has received a Finished event from the impl thread.
bool animation_i_will_send_or_has_received_finish_event =
- events || active_animations_[i]->received_finished_event();
+ events || animations_[i]->received_finished_event();
// If an animation is finished, and not already marked for deletion,
// find out if all other animations in the same group are also finished.
- if (active_animations_[i]->run_state() == Animation::Finished &&
+ if (animations_[i]->run_state() == Animation::Finished &&
animation_i_will_send_or_has_received_finish_event) {
all_anims_with_same_id_are_finished = true;
- for (size_t j = 0; j < active_animations_.size(); ++j) {
+ for (size_t j = 0; j < animations_.size(); ++j) {
bool animation_j_will_send_or_has_received_finish_event =
- events || active_animations_[j]->received_finished_event();
- if (group_id == active_animations_[j]->group() &&
- (!active_animations_[j]->is_finished() ||
- (active_animations_[j]->run_state() == Animation::Finished &&
+ events || animations_[j]->received_finished_event();
+ if (group_id == animations_[j]->group() &&
+ (!animations_[j]->is_finished() ||
+ (animations_[j]->run_state() == Animation::Finished &&
!animation_j_will_send_or_has_received_finish_event))) {
all_anims_with_same_id_are_finished = false;
break;
@@ -634,21 +757,20 @@ void LayerAnimationController::MarkAnimationsForDeletion(
// We now need to remove all animations with the same group id as
// group_id (and send along animation finished notifications, if
// necessary).
- for (size_t j = i; j < active_animations_.size(); j++) {
- if (active_animations_[j]->group() == group_id &&
- active_animations_[j]->run_state() != Animation::Aborted) {
+ for (size_t j = i; j < animations_.size(); j++) {
+ if (animations_[j]->group() == group_id &&
+ animations_[j]->run_state() != Animation::Aborted) {
if (events) {
- AnimationEvent finished_event(
- AnimationEvent::Finished,
- id_,
- active_animations_[j]->group(),
- active_animations_[j]->target_property(),
- monotonic_time);
- finished_event.is_impl_only = active_animations_[j]->is_impl_only();
+ AnimationEvent finished_event(AnimationEvent::Finished,
+ id_,
+ animations_[j]->group(),
+ animations_[j]->target_property(),
+ monotonic_time);
+ finished_event.is_impl_only = animations_[j]->is_impl_only();
events->push_back(finished_event);
}
- active_animations_[j]->SetRunState(Animation::WaitingForDeletion,
- monotonic_time);
+ animations_[j]->SetRunState(Animation::WaitingForDeletion,
+ monotonic_time);
}
}
marked_animations_for_deletions = true;
@@ -663,46 +785,54 @@ static bool IsWaitingForDeletion(Animation* animation) {
}
void LayerAnimationController::PurgeAnimationsMarkedForDeletion() {
- ScopedPtrVector<Animation>& animations = active_animations_;
- animations.erase(cc::remove_if(&animations,
- animations.begin(),
- animations.end(),
- IsWaitingForDeletion),
- animations.end());
-}
-
-void LayerAnimationController::TickAnimations(double monotonic_time) {
- for (size_t i = 0; i < active_animations_.size(); ++i) {
- if (active_animations_[i]->run_state() == Animation::Starting ||
- active_animations_[i]->run_state() == Animation::Running ||
- active_animations_[i]->run_state() == Animation::Paused) {
+ animations_.erase(cc::remove_if(&animations_,
+ animations_.begin(),
+ animations_.end(),
+ IsWaitingForDeletion),
+ animations_.end());
+}
+
+void LayerAnimationController::TickAnimations(base::TimeTicks monotonic_time) {
+ for (size_t i = 0; i < animations_.size(); ++i) {
+ if (animations_[i]->run_state() == Animation::Starting ||
+ animations_[i]->run_state() == Animation::Running ||
+ animations_[i]->run_state() == Animation::Paused) {
double trimmed =
- active_animations_[i]->TrimTimeToCurrentIteration(monotonic_time);
+ animations_[i]->TrimTimeToCurrentIteration(monotonic_time);
- switch (active_animations_[i]->target_property()) {
+ switch (animations_[i]->target_property()) {
case Animation::Transform: {
const TransformAnimationCurve* transform_animation_curve =
- active_animations_[i]->curve()->ToTransformAnimationCurve();
+ animations_[i]->curve()->ToTransformAnimationCurve();
const gfx::Transform transform =
transform_animation_curve->GetValue(trimmed);
- NotifyObserversTransformAnimated(transform);
+ NotifyObserversTransformAnimated(
+ transform,
+ animations_[i]->affects_active_observers(),
+ animations_[i]->affects_pending_observers());
break;
}
case Animation::Opacity: {
const FloatAnimationCurve* float_animation_curve =
- active_animations_[i]->curve()->ToFloatAnimationCurve();
+ animations_[i]->curve()->ToFloatAnimationCurve();
const float opacity = float_animation_curve->GetValue(trimmed);
- NotifyObserversOpacityAnimated(opacity);
+ NotifyObserversOpacityAnimated(
+ opacity,
+ animations_[i]->affects_active_observers(),
+ animations_[i]->affects_pending_observers());
break;
}
case Animation::Filter: {
const FilterAnimationCurve* filter_animation_curve =
- active_animations_[i]->curve()->ToFilterAnimationCurve();
+ animations_[i]->curve()->ToFilterAnimationCurve();
const FilterOperations filter =
filter_animation_curve->GetValue(trimmed);
- NotifyObserversFilterAnimated(filter);
+ NotifyObserversFilterAnimated(
+ filter,
+ animations_[i]->affects_active_observers(),
+ animations_[i]->affects_pending_observers());
break;
}
@@ -713,10 +843,13 @@ void LayerAnimationController::TickAnimations(double monotonic_time) {
case Animation::ScrollOffset: {
const ScrollOffsetAnimationCurve* scroll_offset_animation_curve =
- active_animations_[i]->curve()->ToScrollOffsetAnimationCurve();
+ animations_[i]->curve()->ToScrollOffsetAnimationCurve();
const gfx::Vector2dF scroll_offset =
scroll_offset_animation_curve->GetValue(trimmed);
- NotifyObserversScrollOffsetAnimated(scroll_offset);
+ NotifyObserversScrollOffsetAnimated(
+ scroll_offset,
+ animations_[i]->affects_active_observers(),
+ animations_[i]->affects_pending_observers());
break;
}
@@ -733,8 +866,8 @@ void LayerAnimationController::UpdateActivation(UpdateActivationType type) {
if (registrar_) {
bool was_active = is_active_;
is_active_ = false;
- for (size_t i = 0; i < active_animations_.size(); ++i) {
- if (active_animations_[i]->run_state() != Animation::WaitingForDeletion) {
+ for (size_t i = 0; i < animations_.size(); ++i) {
+ if (animations_[i]->run_state() != Animation::WaitingForDeletion) {
is_active_ = true;
break;
}
@@ -747,31 +880,68 @@ void LayerAnimationController::UpdateActivation(UpdateActivationType type) {
}
}
-void LayerAnimationController::NotifyObserversOpacityAnimated(float opacity) {
- FOR_EACH_OBSERVER(LayerAnimationValueObserver,
- value_observers_,
- OnOpacityAnimated(opacity));
+void LayerAnimationController::NotifyObserversOpacityAnimated(
+ float opacity,
+ bool notify_active_observers,
+ bool notify_pending_observers) {
+ if (value_observers_.might_have_observers()) {
+ ObserverListBase<LayerAnimationValueObserver>::Iterator it(
+ value_observers_);
+ LayerAnimationValueObserver* obs;
+ while ((obs = it.GetNext()) != NULL) {
+ if ((notify_active_observers && obs->IsActive()) ||
+ (notify_pending_observers && !obs->IsActive()))
+ obs->OnOpacityAnimated(opacity);
+ }
+ }
}
void LayerAnimationController::NotifyObserversTransformAnimated(
- const gfx::Transform& transform) {
- FOR_EACH_OBSERVER(LayerAnimationValueObserver,
- value_observers_,
- OnTransformAnimated(transform));
+ const gfx::Transform& transform,
+ bool notify_active_observers,
+ bool notify_pending_observers) {
+ if (value_observers_.might_have_observers()) {
+ ObserverListBase<LayerAnimationValueObserver>::Iterator it(
+ value_observers_);
+ LayerAnimationValueObserver* obs;
+ while ((obs = it.GetNext()) != NULL) {
+ if ((notify_active_observers && obs->IsActive()) ||
+ (notify_pending_observers && !obs->IsActive()))
+ obs->OnTransformAnimated(transform);
+ }
+ }
}
void LayerAnimationController::NotifyObserversFilterAnimated(
- const FilterOperations& filters) {
- FOR_EACH_OBSERVER(LayerAnimationValueObserver,
- value_observers_,
- OnFilterAnimated(filters));
+ const FilterOperations& filters,
+ bool notify_active_observers,
+ bool notify_pending_observers) {
+ if (value_observers_.might_have_observers()) {
+ ObserverListBase<LayerAnimationValueObserver>::Iterator it(
+ value_observers_);
+ LayerAnimationValueObserver* obs;
+ while ((obs = it.GetNext()) != NULL) {
+ if ((notify_active_observers && obs->IsActive()) ||
+ (notify_pending_observers && !obs->IsActive()))
+ obs->OnFilterAnimated(filters);
+ }
+ }
}
void LayerAnimationController::NotifyObserversScrollOffsetAnimated(
- gfx::Vector2dF scroll_offset) {
- FOR_EACH_OBSERVER(LayerAnimationValueObserver,
- value_observers_,
- OnScrollOffsetAnimated(scroll_offset));
+ const gfx::Vector2dF& scroll_offset,
+ bool notify_active_observers,
+ bool notify_pending_observers) {
+ if (value_observers_.might_have_observers()) {
+ ObserverListBase<LayerAnimationValueObserver>::Iterator it(
+ value_observers_);
+ LayerAnimationValueObserver* obs;
+ while ((obs = it.GetNext()) != NULL) {
+ if ((notify_active_observers && obs->IsActive()) ||
+ (notify_pending_observers && !obs->IsActive()))
+ obs->OnScrollOffsetAnimated(scroll_offset);
+ }
+ }
}
void LayerAnimationController::NotifyObserversAnimationWaitingForDeletion() {
diff --git a/chromium/cc/animation/layer_animation_controller.h b/chromium/cc/animation/layer_animation_controller.h
index 564a5933e7f..72f4c46a9cc 100644
--- a/chromium/cc/animation/layer_animation_controller.h
+++ b/chromium/cc/animation/layer_animation_controller.h
@@ -40,7 +40,7 @@ class CC_EXPORT LayerAnimationController
int id() const { return id_; }
void AddAnimation(scoped_ptr<Animation> animation);
- void PauseAnimation(int animation_id, double time_offset);
+ void PauseAnimation(int animation_id, base::TimeDelta time_offset);
void RemoveAnimation(int animation_id);
void RemoveAnimation(int animation_id,
Animation::TargetProperty target_property);
@@ -52,13 +52,18 @@ class CC_EXPORT LayerAnimationController
virtual void PushAnimationUpdatesTo(
LayerAnimationController* controller_impl);
- void Animate(double monotonic_time);
- void AccumulatePropertyUpdates(double monotonic_time,
+ void Animate(base::TimeTicks monotonic_time);
+ void AccumulatePropertyUpdates(base::TimeTicks monotonic_time,
AnimationEventsVector* events);
void UpdateState(bool start_ready_animations,
AnimationEventsVector* events);
+ // Make animations affect active observers if and only if they affect
+ // pending observers. Any animations that no longer affect any observers
+ // are deleted.
+ void ActivateAnimations();
+
// Returns the active animation in the given group, animating the given
// property, if such an animation exists.
Animation* GetAnimation(int group_id,
@@ -73,7 +78,7 @@ class CC_EXPORT LayerAnimationController
bool HasActiveAnimation() const;
// Returns true if there are any animations at all to process.
- bool has_any_animation() const { return !active_animations_.empty(); }
+ bool has_any_animation() const { return !animations_.empty(); }
// Returns true if there is an animation currently animating the given
// property, or if there is an animation scheduled to animate this property in
@@ -83,10 +88,8 @@ class CC_EXPORT LayerAnimationController
void SetAnimationRegistrar(AnimationRegistrar* registrar);
AnimationRegistrar* animation_registrar() { return registrar_; }
- void NotifyAnimationStarted(const AnimationEvent& event,
- double wall_clock_time);
- void NotifyAnimationFinished(const AnimationEvent& event,
- double wall_clock_time);
+ void NotifyAnimationStarted(const AnimationEvent& event);
+ void NotifyAnimationFinished(const AnimationEvent& event);
void NotifyAnimationAborted(const AnimationEvent& event);
void NotifyAnimationPropertyUpdate(const AnimationEvent& event);
@@ -109,7 +112,29 @@ class CC_EXPORT LayerAnimationController
layer_animation_delegate_ = delegate;
}
- bool AnimatedBoundsForBox(const gfx::BoxF& box, gfx::BoxF* bounds);
+ bool HasFilterAnimationThatInflatesBounds() const;
+ bool HasTransformAnimationThatInflatesBounds() const;
+ bool HasAnimationThatInflatesBounds() const {
+ return HasTransformAnimationThatInflatesBounds() ||
+ HasFilterAnimationThatInflatesBounds();
+ }
+
+ bool FilterAnimationBoundsForBox(const gfx::BoxF& box,
+ gfx::BoxF* bounds) const;
+ bool TransformAnimationBoundsForBox(const gfx::BoxF& box,
+ gfx::BoxF* bounds) const;
+
+ bool HasAnimationThatAffectsScale() const;
+
+ bool HasOnlyTranslationTransforms() const;
+
+ // Sets |max_scale| to the maximum scale along any dimension during active
+ // animations. Returns false if the maximum scale cannot be computed.
+ bool MaximumScale(float* max_scale) const;
+
+ bool needs_to_start_animations_for_testing() {
+ return needs_to_start_animations_;
+ }
protected:
friend class base::RefCounted<LayerAnimationController>;
@@ -127,15 +152,15 @@ class CC_EXPORT LayerAnimationController
void PushPropertiesToImplThread(
LayerAnimationController* controller_impl) const;
- void StartAnimations(double monotonic_time);
- void PromoteStartedAnimations(double monotonic_time,
+ void StartAnimations(base::TimeTicks monotonic_time);
+ void PromoteStartedAnimations(base::TimeTicks monotonic_time,
AnimationEventsVector* events);
- void MarkFinishedAnimations(double monotonic_time);
- void MarkAnimationsForDeletion(double monotonic_time,
+ void MarkFinishedAnimations(base::TimeTicks monotonic_time);
+ void MarkAnimationsForDeletion(base::TimeTicks monotonic_time,
AnimationEventsVector* events);
void PurgeAnimationsMarkedForDeletion();
- void TickAnimations(double monotonic_time);
+ void TickAnimations(base::TimeTicks monotonic_time);
enum UpdateActivationType {
NormalActivation,
@@ -143,10 +168,18 @@ class CC_EXPORT LayerAnimationController
};
void UpdateActivation(UpdateActivationType type);
- void NotifyObserversOpacityAnimated(float opacity);
- void NotifyObserversTransformAnimated(const gfx::Transform& transform);
- void NotifyObserversFilterAnimated(const FilterOperations& filter);
- void NotifyObserversScrollOffsetAnimated(gfx::Vector2dF scroll_offset);
+ void NotifyObserversOpacityAnimated(float opacity,
+ bool notify_active_observers,
+ bool notify_pending_observers);
+ void NotifyObserversTransformAnimated(const gfx::Transform& transform,
+ bool notify_active_observers,
+ bool notify_pending_observers);
+ void NotifyObserversFilterAnimated(const FilterOperations& filter,
+ bool notify_active_observers,
+ bool notify_pending_observers);
+ void NotifyObserversScrollOffsetAnimated(const gfx::Vector2dF& scroll_offset,
+ bool notify_active_observers,
+ bool notify_pending_observers);
void NotifyObserversAnimationWaitingForDeletion();
@@ -155,12 +188,12 @@ class CC_EXPORT LayerAnimationController
AnimationRegistrar* registrar_;
int id_;
- ScopedPtrVector<Animation> active_animations_;
+ ScopedPtrVector<Animation> animations_;
// This is used to ensure that we don't spam the registrar.
bool is_active_;
- double last_tick_time_;
+ base::TimeTicks last_tick_time_;
ObserverList<LayerAnimationValueObserver> value_observers_;
ObserverList<LayerAnimationEventObserver> event_observers_;
@@ -169,6 +202,10 @@ class CC_EXPORT LayerAnimationController
AnimationDelegate* layer_animation_delegate_;
+ // Only try to start animations when new animations are added or when the
+ // previous attempt at starting animations failed to start all animations.
+ bool needs_to_start_animations_;
+
DISALLOW_COPY_AND_ASSIGN(LayerAnimationController);
};
diff --git a/chromium/cc/animation/layer_animation_controller_unittest.cc b/chromium/cc/animation/layer_animation_controller_unittest.cc
index f7918cd2bf3..15efdf09856 100644
--- a/chromium/cc/animation/layer_animation_controller_unittest.cc
+++ b/chromium/cc/animation/layer_animation_controller_unittest.cc
@@ -20,10 +20,18 @@
namespace cc {
namespace {
+using base::TimeDelta;
+using base::TimeTicks;
+
+static base::TimeTicks TicksFromSecondsF(double seconds) {
+ return base::TimeTicks::FromInternalValue(seconds *
+ base::Time::kMicrosecondsPerSecond);
+}
+
// A LayerAnimationController cannot be ticked at 0.0, since an animation
// with start time 0.0 is treated as an animation whose start time has
// not yet been set.
-const double kInitialTickTime = 1.0;
+const TimeTicks kInitialTickTime = TicksFromSecondsF(1.0);
scoped_ptr<Animation> CreateAnimation(scoped_ptr<AnimationCurve> curve,
int id,
@@ -43,10 +51,16 @@ TEST(LayerAnimationControllerTest, SyncNewAnimation) {
EXPECT_FALSE(controller_impl->GetAnimation(Animation::Opacity));
+ EXPECT_FALSE(controller->needs_to_start_animations_for_testing());
+ EXPECT_FALSE(controller_impl->needs_to_start_animations_for_testing());
+
AddOpacityTransitionToController(controller.get(), 1, 0, 1, false);
+ EXPECT_TRUE(controller->needs_to_start_animations_for_testing());
int group_id = controller->GetAnimation(Animation::Opacity)->group();
controller->PushAnimationUpdatesTo(controller_impl.get());
+ EXPECT_TRUE(controller_impl->needs_to_start_animations_for_testing());
+ controller_impl->ActivateAnimations();
EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity));
EXPECT_EQ(Animation::WaitingForTargetAvailability,
@@ -72,6 +86,52 @@ TEST(LayerAnimationControllerTest, DoNotClobberStartTimes) {
int group_id = controller->GetAnimation(Animation::Opacity)->group();
controller->PushAnimationUpdatesTo(controller_impl.get());
+ controller_impl->ActivateAnimations();
+
+ EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity));
+ EXPECT_EQ(Animation::WaitingForTargetAvailability,
+ controller_impl->GetAnimation(group_id,
+ Animation::Opacity)->run_state());
+
+ AnimationEventsVector events;
+ controller_impl->Animate(kInitialTickTime);
+ controller_impl->UpdateState(true, &events);
+
+ // Synchronize the start times.
+ EXPECT_EQ(1u, events.size());
+ controller->NotifyAnimationStarted(events[0]);
+ EXPECT_EQ(controller->GetAnimation(group_id,
+ Animation::Opacity)->start_time(),
+ controller_impl->GetAnimation(group_id,
+ Animation::Opacity)->start_time());
+
+ // Start the animation on the main thread. Should not affect the start time.
+ controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(500));
+ controller->UpdateState(true, NULL);
+ EXPECT_EQ(controller->GetAnimation(group_id,
+ Animation::Opacity)->start_time(),
+ controller_impl->GetAnimation(group_id,
+ Animation::Opacity)->start_time());
+}
+
+TEST(LayerAnimationControllerTest, UseSpecifiedStartTimes) {
+ FakeLayerAnimationValueObserver dummy_impl;
+ scoped_refptr<LayerAnimationController> controller_impl(
+ LayerAnimationController::Create(0));
+ controller_impl->AddValueObserver(&dummy_impl);
+ FakeLayerAnimationValueObserver dummy;
+ scoped_refptr<LayerAnimationController> controller(
+ LayerAnimationController::Create(0));
+ controller->AddValueObserver(&dummy);
+
+ AddOpacityTransitionToController(controller.get(), 1, 0, 1, false);
+ int group_id = controller->GetAnimation(Animation::Opacity)->group();
+
+ const TimeTicks start_time = TicksFromSecondsF(123);
+ controller->GetAnimation(Animation::Opacity)->set_start_time(start_time);
+
+ controller->PushAnimationUpdatesTo(controller_impl.get());
+ controller_impl->ActivateAnimations();
EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity));
EXPECT_EQ(Animation::WaitingForTargetAvailability,
@@ -84,15 +144,22 @@ TEST(LayerAnimationControllerTest, DoNotClobberStartTimes) {
// Synchronize the start times.
EXPECT_EQ(1u, events.size());
- controller->NotifyAnimationStarted(events[0], 0.0);
+ controller->NotifyAnimationStarted(events[0]);
+
+ EXPECT_EQ(start_time,
+ controller->GetAnimation(group_id,
+ Animation::Opacity)->start_time());
EXPECT_EQ(controller->GetAnimation(group_id,
Animation::Opacity)->start_time(),
controller_impl->GetAnimation(group_id,
Animation::Opacity)->start_time());
// Start the animation on the main thread. Should not affect the start time.
- controller->Animate(kInitialTickTime + 0.5);
+ controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(500));
controller->UpdateState(true, NULL);
+ EXPECT_EQ(start_time,
+ controller->GetAnimation(group_id,
+ Animation::Opacity)->start_time());
EXPECT_EQ(controller->GetAnimation(group_id,
Animation::Opacity)->start_time(),
controller_impl->GetAnimation(group_id,
@@ -129,6 +196,7 @@ TEST(LayerAnimationControllerTest, Activation) {
EXPECT_EQ(1u, registrar->active_animation_controllers().size());
controller->PushAnimationUpdatesTo(controller_impl.get());
+ controller_impl->ActivateAnimations();
// Both controllers should now be active.
EXPECT_EQ(1u, registrar->active_animation_controllers().size());
EXPECT_EQ(1u, registrar_impl->active_animation_controllers().size());
@@ -136,23 +204,24 @@ TEST(LayerAnimationControllerTest, Activation) {
controller_impl->Animate(kInitialTickTime);
controller_impl->UpdateState(true, events.get());
EXPECT_EQ(1u, events->size());
- controller->NotifyAnimationStarted((*events)[0], 0.0);
+ controller->NotifyAnimationStarted((*events)[0]);
EXPECT_EQ(1u, registrar->active_animation_controllers().size());
EXPECT_EQ(1u, registrar_impl->active_animation_controllers().size());
- controller->Animate(kInitialTickTime + 0.5);
+ controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(500));
controller->UpdateState(true, NULL);
EXPECT_EQ(1u, registrar->active_animation_controllers().size());
- controller->Animate(kInitialTickTime + 1.0);
+ controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1000));
controller->UpdateState(true, NULL);
EXPECT_EQ(Animation::Finished,
controller->GetAnimation(Animation::Opacity)->run_state());
EXPECT_EQ(1u, registrar->active_animation_controllers().size());
events.reset(new AnimationEventsVector);
- controller_impl->Animate(kInitialTickTime + 1.5);
+ controller_impl->Animate(kInitialTickTime +
+ TimeDelta::FromMilliseconds(1500));
controller_impl->UpdateState(true, events.get());
EXPECT_EQ(Animation::WaitingForDeletion,
@@ -161,8 +230,8 @@ TEST(LayerAnimationControllerTest, Activation) {
EXPECT_EQ(0u, registrar_impl->active_animation_controllers().size());
EXPECT_EQ(1u, events->size());
- controller->NotifyAnimationFinished((*events)[0], 0.0);
- controller->Animate(kInitialTickTime + 1.5);
+ controller->NotifyAnimationFinished((*events)[0]);
+ controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1500));
controller->UpdateState(true, NULL);
EXPECT_EQ(Animation::WaitingForDeletion,
@@ -171,6 +240,7 @@ TEST(LayerAnimationControllerTest, Activation) {
EXPECT_EQ(0u, registrar->active_animation_controllers().size());
controller->PushAnimationUpdatesTo(controller_impl.get());
+ controller_impl->ActivateAnimations();
EXPECT_FALSE(controller->has_any_animation());
EXPECT_FALSE(controller_impl->has_any_animation());
EXPECT_EQ(0u, registrar->active_animation_controllers().size());
@@ -197,6 +267,7 @@ TEST(LayerAnimationControllerTest, SyncPause) {
int animation_id = controller->GetAnimation(Animation::Opacity)->id();
controller->PushAnimationUpdatesTo(controller_impl.get());
+ controller_impl->ActivateAnimations();
EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity));
EXPECT_EQ(Animation::WaitingForTargetAvailability,
@@ -217,13 +288,16 @@ TEST(LayerAnimationControllerTest, SyncPause) {
Animation::Opacity)->run_state());
// Pause the main-thread animation.
- controller->PauseAnimation(animation_id, kInitialTickTime + 1.0);
+ controller->PauseAnimation(
+ animation_id,
+ TimeDelta::FromMilliseconds(1000) + TimeDelta::FromMilliseconds(1000));
EXPECT_EQ(Animation::Paused,
controller->GetAnimation(group_id,
Animation::Opacity)->run_state());
// The pause run state change should make it to the impl thread controller.
controller->PushAnimationUpdatesTo(controller_impl.get());
+ controller_impl->ActivateAnimations();
EXPECT_EQ(Animation::Paused,
controller_impl->GetAnimation(group_id,
Animation::Opacity)->run_state());
@@ -246,6 +320,7 @@ TEST(LayerAnimationControllerTest, DoNotSyncFinishedAnimation) {
int group_id = controller->GetAnimation(Animation::Opacity)->group();
controller->PushAnimationUpdatesTo(controller_impl.get());
+ controller_impl->ActivateAnimations();
EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity));
EXPECT_EQ(Animation::WaitingForTargetAvailability,
@@ -258,7 +333,7 @@ TEST(LayerAnimationControllerTest, DoNotSyncFinishedAnimation) {
group_id,
Animation::Opacity,
kInitialTickTime);
- controller->NotifyAnimationStarted(animation_started_event, 0.0);
+ controller->NotifyAnimationStarted(animation_started_event);
// Force animation to complete on impl thread.
controller_impl->RemoveAnimation(animation_id);
@@ -266,6 +341,7 @@ TEST(LayerAnimationControllerTest, DoNotSyncFinishedAnimation) {
EXPECT_FALSE(controller_impl->GetAnimation(group_id, Animation::Opacity));
controller->PushAnimationUpdatesTo(controller_impl.get());
+ controller_impl->ActivateAnimations();
// Even though the main thread has a 'new' animation, it should not be pushed
// because the animation has already completed on the impl thread.
@@ -290,23 +366,25 @@ TEST(LayerAnimationControllerTest, AnimationsAreDeleted) {
controller->Animate(kInitialTickTime);
controller->UpdateState(true, NULL);
controller->PushAnimationUpdatesTo(controller_impl.get());
+ controller_impl->ActivateAnimations();
- controller_impl->Animate(kInitialTickTime + 0.5);
+ controller_impl->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(500));
controller_impl->UpdateState(true, events.get());
// There should be a Started event for the animation.
EXPECT_EQ(1u, events->size());
EXPECT_EQ(AnimationEvent::Started, (*events)[0].type);
- controller->NotifyAnimationStarted((*events)[0], 0.0);
+ controller->NotifyAnimationStarted((*events)[0]);
- controller->Animate(kInitialTickTime + 1.0);
+ controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1000));
controller->UpdateState(true, NULL);
EXPECT_FALSE(dummy.animation_waiting_for_deletion());
EXPECT_FALSE(dummy_impl.animation_waiting_for_deletion());
events.reset(new AnimationEventsVector);
- controller_impl->Animate(kInitialTickTime + 2.0);
+ controller_impl->Animate(kInitialTickTime +
+ TimeDelta::FromMilliseconds(2000));
controller_impl->UpdateState(true, events.get());
EXPECT_TRUE(dummy_impl.animation_waiting_for_deletion());
@@ -319,15 +397,18 @@ TEST(LayerAnimationControllerTest, AnimationsAreDeleted) {
EXPECT_TRUE(controller->GetAnimation(Animation::Opacity));
EXPECT_TRUE(controller_impl->GetAnimation(Animation::Opacity));
- controller->NotifyAnimationFinished((*events)[0], 0.0);
+ controller->NotifyAnimationFinished((*events)[0]);
- controller->Animate(kInitialTickTime + 3.0);
+ controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(3000));
controller->UpdateState(true, NULL);
EXPECT_TRUE(dummy.animation_waiting_for_deletion());
controller->PushAnimationUpdatesTo(controller_impl.get());
- // Both controllers should now have deleted the animation.
+ // Both controllers should now have deleted the animation. The impl controller
+ // should have deleted the animation even though activation has not occurred,
+ // since the animation was already waiting for deletion when
+ // PushAnimationUpdatesTo was called.
EXPECT_FALSE(controller->has_any_animation());
EXPECT_FALSE(controller_impl->has_any_animation());
}
@@ -357,15 +438,18 @@ TEST(LayerAnimationControllerTest, TrivialTransition) {
1,
Animation::Opacity));
+ EXPECT_FALSE(controller->needs_to_start_animations_for_testing());
controller->AddAnimation(to_add.Pass());
+ EXPECT_TRUE(controller->needs_to_start_animations_for_testing());
controller->Animate(kInitialTickTime);
+ EXPECT_FALSE(controller->needs_to_start_animations_for_testing());
controller->UpdateState(true, events.get());
EXPECT_TRUE(controller->HasActiveAnimation());
EXPECT_EQ(0.f, dummy.opacity());
// A non-impl-only animation should not generate property updates.
const AnimationEvent* event = GetMostRecentPropertyUpdateEvent(events.get());
EXPECT_FALSE(event);
- controller->Animate(kInitialTickTime + 1.0);
+ controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1000));
controller->UpdateState(true, events.get());
EXPECT_EQ(1.f, dummy.opacity());
EXPECT_FALSE(controller->HasActiveAnimation());
@@ -397,7 +481,8 @@ TEST(LayerAnimationControllerTest, TrivialTransitionOnImpl) {
GetMostRecentPropertyUpdateEvent(events.get());
EXPECT_EQ(0.f, start_opacity_event->opacity);
- controller_impl->Animate(kInitialTickTime + 1.0);
+ controller_impl->Animate(kInitialTickTime +
+ TimeDelta::FromMilliseconds(1000));
controller_impl->UpdateState(true, events.get());
EXPECT_EQ(1.f, dummy_impl.opacity());
EXPECT_FALSE(controller_impl->HasActiveAnimation());
@@ -451,7 +536,8 @@ TEST(LayerAnimationControllerTest, TrivialTransformOnImpl) {
gfx::Transform expected_transform;
expected_transform.Translate(delta_x, delta_y);
- controller_impl->Animate(kInitialTickTime + 1.0);
+ controller_impl->Animate(kInitialTickTime +
+ TimeDelta::FromMilliseconds(1000));
controller_impl->UpdateState(true, events.get());
EXPECT_EQ(expected_transform, dummy_impl.transform());
EXPECT_FALSE(controller_impl->HasActiveAnimation());
@@ -494,7 +580,7 @@ TEST(LayerAnimationControllerTest, FilterTransition) {
const AnimationEvent* event = GetMostRecentPropertyUpdateEvent(events.get());
EXPECT_FALSE(event);
- controller->Animate(kInitialTickTime + 0.5);
+ controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(500));
controller->UpdateState(true, events.get());
EXPECT_EQ(1u, dummy.filters().size());
EXPECT_EQ(FilterOperation::CreateBrightnessFilter(1.5f),
@@ -502,7 +588,7 @@ TEST(LayerAnimationControllerTest, FilterTransition) {
event = GetMostRecentPropertyUpdateEvent(events.get());
EXPECT_FALSE(event);
- controller->Animate(kInitialTickTime + 1.0);
+ controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1000));
controller->UpdateState(true, events.get());
EXPECT_EQ(end_filters, dummy.filters());
EXPECT_FALSE(controller->HasActiveAnimation());
@@ -548,7 +634,8 @@ TEST(LayerAnimationControllerTest, FilterTransitionOnImplOnly) {
EXPECT_EQ(start_filters, start_filter_event->filters);
EXPECT_TRUE(start_filter_event->is_impl_only);
- controller_impl->Animate(kInitialTickTime + 1.0);
+ controller_impl->Animate(kInitialTickTime +
+ TimeDelta::FromMilliseconds(1000));
controller_impl->UpdateState(true, events.get());
EXPECT_EQ(end_filters, dummy_impl.filters());
EXPECT_FALSE(controller_impl->HasActiveAnimation());
@@ -590,12 +677,16 @@ TEST(LayerAnimationControllerTest, ScrollOffsetTransition) {
dummy_provider_impl.set_scroll_offset(initial_value);
controller->PushAnimationUpdatesTo(controller_impl.get());
+ controller_impl->ActivateAnimations();
EXPECT_TRUE(controller_impl->GetAnimation(Animation::ScrollOffset));
- double duration = controller_impl->GetAnimation(
- Animation::ScrollOffset)->curve()->Duration();
-
+ double duration_in_seconds =
+ controller_impl->GetAnimation(Animation::ScrollOffset)
+ ->curve()
+ ->Duration();
+ TimeDelta duration = TimeDelta::FromMicroseconds(
+ duration_in_seconds * base::Time::kMicrosecondsPerSecond);
EXPECT_EQ(
- duration,
+ duration_in_seconds,
controller->GetAnimation(Animation::ScrollOffset)->curve()->Duration());
controller->Animate(kInitialTickTime);
@@ -611,13 +702,13 @@ TEST(LayerAnimationControllerTest, ScrollOffsetTransition) {
const AnimationEvent* event = GetMostRecentPropertyUpdateEvent(events.get());
EXPECT_FALSE(event);
- controller->NotifyAnimationStarted((*events)[0], 0.0);
- controller->Animate(kInitialTickTime + duration/2.0);
+ controller->NotifyAnimationStarted((*events)[0]);
+ controller->Animate(kInitialTickTime + duration / 2);
controller->UpdateState(true, NULL);
EXPECT_TRUE(controller->HasActiveAnimation());
EXPECT_VECTOR2DF_EQ(gfx::Vector2dF(200.f, 250.f), dummy.scroll_offset());
- controller_impl->Animate(kInitialTickTime + duration/2.0);
+ controller_impl->Animate(kInitialTickTime + duration / 2);
controller_impl->UpdateState(true, events.get());
EXPECT_VECTOR2DF_EQ(gfx::Vector2dF(200.f, 250.f),
dummy_impl.scroll_offset());
@@ -668,12 +759,14 @@ TEST(LayerAnimationControllerTest, ScrollOffsetTransitionNoImplProvider) {
dummy_provider.set_scroll_offset(initial_value);
controller->PushAnimationUpdatesTo(controller_impl.get());
+ controller_impl->ActivateAnimations();
EXPECT_TRUE(controller_impl->GetAnimation(Animation::ScrollOffset));
- double duration = controller_impl->GetAnimation(
- Animation::ScrollOffset)->curve()->Duration();
-
+ double duration_in_seconds =
+ controller_impl->GetAnimation(Animation::ScrollOffset)
+ ->curve()
+ ->Duration();
EXPECT_EQ(
- duration,
+ duration_in_seconds,
controller->GetAnimation(Animation::ScrollOffset)->curve()->Duration());
controller->Animate(kInitialTickTime);
@@ -689,13 +782,16 @@ TEST(LayerAnimationControllerTest, ScrollOffsetTransitionNoImplProvider) {
const AnimationEvent* event = GetMostRecentPropertyUpdateEvent(events.get());
EXPECT_FALSE(event);
- controller->NotifyAnimationStarted((*events)[0], 0.0);
- controller->Animate(kInitialTickTime + duration/2.0);
+ TimeDelta duration = TimeDelta::FromMicroseconds(
+ duration_in_seconds * base::Time::kMicrosecondsPerSecond);
+
+ controller->NotifyAnimationStarted((*events)[0]);
+ controller->Animate(kInitialTickTime + duration / 2);
controller->UpdateState(true, NULL);
EXPECT_TRUE(controller->HasActiveAnimation());
EXPECT_VECTOR2DF_EQ(gfx::Vector2dF(400.f, 150.f), dummy.scroll_offset());
- controller_impl->Animate(kInitialTickTime + duration/2.0);
+ controller_impl->Animate(kInitialTickTime + duration / 2);
controller_impl->UpdateState(true, events.get());
EXPECT_VECTOR2DF_EQ(gfx::Vector2dF(400.f, 150.f),
dummy_impl.scroll_offset());
@@ -730,7 +826,7 @@ TEST(LayerAnimationControllerTest, ScrollOffsetTransitionOnImplOnly) {
target_value,
EaseInOutTimingFunction::Create().Pass()));
curve->SetInitialValue(initial_value);
- double duration = curve->Duration();
+ double duration_in_seconds = curve->Duration();
scoped_ptr<Animation> animation(Animation::Create(
curve.PassAs<AnimationCurve>(), 1, 0, Animation::ScrollOffset));
@@ -745,7 +841,10 @@ TEST(LayerAnimationControllerTest, ScrollOffsetTransitionOnImplOnly) {
const AnimationEvent* event = GetMostRecentPropertyUpdateEvent(events.get());
EXPECT_FALSE(event);
- controller_impl->Animate(kInitialTickTime + duration/2.0);
+ TimeDelta duration = TimeDelta::FromMicroseconds(
+ duration_in_seconds * base::Time::kMicrosecondsPerSecond);
+
+ controller_impl->Animate(kInitialTickTime + duration / 2);
controller_impl->UpdateState(true, events.get());
EXPECT_VECTOR2DF_EQ(gfx::Vector2dF(200.f, 250.f),
dummy_impl.scroll_offset());
@@ -767,15 +866,13 @@ class FakeAnimationDelegate : public AnimationDelegate {
finished_(false) {}
virtual void NotifyAnimationStarted(
- double wall_clock_time,
- base::TimeTicks monotonic_time,
+ TimeTicks monotonic_time,
Animation::TargetProperty target_property) OVERRIDE {
started_ = true;
}
virtual void NotifyAnimationFinished(
- double wall_clock_time,
- base::TimeTicks monotonic_time,
+ TimeTicks monotonic_time,
Animation::TargetProperty target_property) OVERRIDE {
finished_ = true;
}
@@ -826,11 +923,12 @@ TEST(LayerAnimationControllerTest,
// Passing on the start event to the main thread controller should cause the
// delegate to get notified.
EXPECT_FALSE(delegate.started());
- controller->NotifyAnimationStarted((*events)[0], 0.0);
+ controller->NotifyAnimationStarted((*events)[0]);
EXPECT_TRUE(delegate.started());
events.reset(new AnimationEventsVector);
- controller_impl->Animate(kInitialTickTime + 1.0);
+ controller_impl->Animate(kInitialTickTime +
+ TimeDelta::FromMilliseconds(1000));
controller_impl->UpdateState(true, events.get());
// We should receive 2 events (a finished notification and a property update).
@@ -843,7 +941,7 @@ TEST(LayerAnimationControllerTest,
// Passing on the finished event to the main thread controller should cause
// the delegate to get notified.
EXPECT_FALSE(delegate.finished());
- controller->NotifyAnimationFinished((*events)[0], 0.0);
+ controller->NotifyAnimationFinished((*events)[0]);
EXPECT_TRUE(delegate.finished());
}
@@ -871,23 +969,23 @@ TEST(LayerAnimationControllerTest,
controller->UpdateState(true, events.get());
EXPECT_TRUE(controller->HasActiveAnimation());
EXPECT_EQ(0.f, dummy.opacity());
- controller->Animate(kInitialTickTime + 1.0);
+ controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1000));
controller->UpdateState(true, events.get());
EXPECT_TRUE(controller->HasActiveAnimation());
EXPECT_EQ(0.f, dummy.opacity());
- controller->Animate(kInitialTickTime + 2.0);
+ controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(2000));
controller->UpdateState(true, events.get());
EXPECT_TRUE(controller->HasActiveAnimation());
EXPECT_EQ(0.f, dummy.opacity());
// Send the synchronized start time.
- controller->NotifyAnimationStarted(AnimationEvent(AnimationEvent::Started,
- 0,
- 1,
- Animation::Opacity,
- kInitialTickTime + 2),
- 0.0);
- controller->Animate(kInitialTickTime + 5.0);
+ controller->NotifyAnimationStarted(
+ AnimationEvent(AnimationEvent::Started,
+ 0,
+ 1,
+ Animation::Opacity,
+ kInitialTickTime + TimeDelta::FromMilliseconds(2000)));
+ controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(5000));
controller->UpdateState(true, events.get());
EXPECT_EQ(1.f, dummy.opacity());
EXPECT_FALSE(controller->HasActiveAnimation());
@@ -902,6 +1000,8 @@ TEST(LayerAnimationControllerTest, TrivialQueuing) {
LayerAnimationController::Create(0));
controller->AddValueObserver(&dummy);
+ EXPECT_FALSE(controller->needs_to_start_animations_for_testing());
+
controller->AddAnimation(CreateAnimation(
scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
1,
@@ -912,15 +1012,25 @@ TEST(LayerAnimationControllerTest, TrivialQueuing) {
2,
Animation::Opacity));
+ EXPECT_TRUE(controller->needs_to_start_animations_for_testing());
+
controller->Animate(kInitialTickTime);
+
+ // The second animation still needs to be started.
+ EXPECT_TRUE(controller->needs_to_start_animations_for_testing());
+
controller->UpdateState(true, events.get());
EXPECT_TRUE(controller->HasActiveAnimation());
EXPECT_EQ(0.f, dummy.opacity());
- controller->Animate(kInitialTickTime + 1.0);
+
+ controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1000));
+ EXPECT_TRUE(controller->needs_to_start_animations_for_testing());
controller->UpdateState(true, events.get());
+ EXPECT_FALSE(controller->needs_to_start_animations_for_testing());
+
EXPECT_TRUE(controller->HasActiveAnimation());
EXPECT_EQ(1.f, dummy.opacity());
- controller->Animate(kInitialTickTime + 2.0);
+ controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(2000));
controller->UpdateState(true, events.get());
EXPECT_EQ(0.5f, dummy.opacity());
EXPECT_FALSE(controller->HasActiveAnimation());
@@ -953,11 +1063,11 @@ TEST(LayerAnimationControllerTest, Interrupt) {
// Since the previous animation was aborted, the new animation should start
// right in this call to animate.
- controller->Animate(kInitialTickTime + 0.5);
+ controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(500));
controller->UpdateState(true, events.get());
EXPECT_TRUE(controller->HasActiveAnimation());
EXPECT_EQ(1.f, dummy.opacity());
- controller->Animate(kInitialTickTime + 1.5);
+ controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1500));
controller->UpdateState(true, events.get());
EXPECT_EQ(0.5f, dummy.opacity());
EXPECT_FALSE(controller->HasActiveAnimation());
@@ -990,13 +1100,13 @@ TEST(LayerAnimationControllerTest, ScheduleTogetherWhenAPropertyIsBlocked) {
controller->UpdateState(true, events.get());
EXPECT_EQ(0.f, dummy.opacity());
EXPECT_TRUE(controller->HasActiveAnimation());
- controller->Animate(kInitialTickTime + 1.0);
+ controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1000));
controller->UpdateState(true, events.get());
// Should not have started the float transition yet.
EXPECT_TRUE(controller->HasActiveAnimation());
EXPECT_EQ(0.f, dummy.opacity());
// The float animation should have started at time 1 and should be done.
- controller->Animate(kInitialTickTime + 2.0);
+ controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(2000));
controller->UpdateState(true, events.get());
EXPECT_EQ(1.f, dummy.opacity());
EXPECT_FALSE(controller->HasActiveAnimation());
@@ -1035,7 +1145,7 @@ TEST(LayerAnimationControllerTest, ScheduleTogetherWithAnAnimWaiting) {
// The opacity animation should have finished at time 1, but the group
// of animations with id 1 don't finish until time 2 because of the length
// of the transform animation.
- controller->Animate(kInitialTickTime + 2.0);
+ controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(2000));
controller->UpdateState(true, events.get());
// Should not have started the float transition yet.
EXPECT_TRUE(controller->HasActiveAnimation());
@@ -1043,7 +1153,7 @@ TEST(LayerAnimationControllerTest, ScheduleTogetherWithAnAnimWaiting) {
// The second opacity animation should start at time 2 and should be done by
// time 3.
- controller->Animate(kInitialTickTime + 3.0);
+ controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(3000));
controller->UpdateState(true, events.get());
EXPECT_EQ(0.5f, dummy.opacity());
EXPECT_FALSE(controller->HasActiveAnimation());
@@ -1069,29 +1179,29 @@ TEST(LayerAnimationControllerTest, TrivialLooping) {
controller->UpdateState(true, events.get());
EXPECT_TRUE(controller->HasActiveAnimation());
EXPECT_EQ(0.f, dummy.opacity());
- controller->Animate(kInitialTickTime + 1.25);
+ controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1250));
controller->UpdateState(true, events.get());
EXPECT_TRUE(controller->HasActiveAnimation());
EXPECT_EQ(0.25f, dummy.opacity());
- controller->Animate(kInitialTickTime + 1.75);
+ controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1750));
controller->UpdateState(true, events.get());
EXPECT_TRUE(controller->HasActiveAnimation());
EXPECT_EQ(0.75f, dummy.opacity());
- controller->Animate(kInitialTickTime + 2.25);
+ controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(2250));
controller->UpdateState(true, events.get());
EXPECT_TRUE(controller->HasActiveAnimation());
EXPECT_EQ(0.25f, dummy.opacity());
- controller->Animate(kInitialTickTime + 2.75);
+ controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(2750));
controller->UpdateState(true, events.get());
EXPECT_TRUE(controller->HasActiveAnimation());
EXPECT_EQ(0.75f, dummy.opacity());
- controller->Animate(kInitialTickTime + 3.0);
+ controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(3000));
controller->UpdateState(true, events.get());
EXPECT_FALSE(controller->HasActiveAnimation());
EXPECT_EQ(1.f, dummy.opacity());
// Just be extra sure.
- controller->Animate(kInitialTickTime + 4.0);
+ controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(4000));
controller->UpdateState(true, events.get());
EXPECT_EQ(1.f, dummy.opacity());
}
@@ -1117,27 +1227,29 @@ TEST(LayerAnimationControllerTest, InfiniteLooping) {
controller->UpdateState(true, events.get());
EXPECT_TRUE(controller->HasActiveAnimation());
EXPECT_EQ(0.f, dummy.opacity());
- controller->Animate(kInitialTickTime + 1.25);
+ controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1250));
controller->UpdateState(true, events.get());
EXPECT_TRUE(controller->HasActiveAnimation());
EXPECT_EQ(0.25f, dummy.opacity());
- controller->Animate(kInitialTickTime + 1.75);
+ controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1750));
controller->UpdateState(true, events.get());
EXPECT_TRUE(controller->HasActiveAnimation());
EXPECT_EQ(0.75f, dummy.opacity());
- controller->Animate(kInitialTickTime + 1073741824.25);
+ controller->Animate(kInitialTickTime +
+ TimeDelta::FromMilliseconds(1073741824250));
controller->UpdateState(true, events.get());
EXPECT_TRUE(controller->HasActiveAnimation());
EXPECT_EQ(0.25f, dummy.opacity());
- controller->Animate(kInitialTickTime + 1073741824.75);
+ controller->Animate(kInitialTickTime +
+ TimeDelta::FromMilliseconds(1073741824750));
controller->UpdateState(true, events.get());
EXPECT_TRUE(controller->HasActiveAnimation());
EXPECT_EQ(0.75f, dummy.opacity());
EXPECT_TRUE(controller->GetAnimation(id, Animation::Opacity));
controller->GetAnimation(id, Animation::Opacity)->SetRunState(
- Animation::Aborted, kInitialTickTime + 0.75);
+ Animation::Aborted, kInitialTickTime + TimeDelta::FromMilliseconds(750));
EXPECT_FALSE(controller->HasActiveAnimation());
EXPECT_EQ(0.75f, dummy.opacity());
}
@@ -1161,29 +1273,30 @@ TEST(LayerAnimationControllerTest, PauseResume) {
controller->UpdateState(true, events.get());
EXPECT_TRUE(controller->HasActiveAnimation());
EXPECT_EQ(0.f, dummy.opacity());
- controller->Animate(kInitialTickTime + 0.5);
+ controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(500));
controller->UpdateState(true, events.get());
EXPECT_TRUE(controller->HasActiveAnimation());
EXPECT_EQ(0.5f, dummy.opacity());
EXPECT_TRUE(controller->GetAnimation(id, Animation::Opacity));
controller->GetAnimation(id, Animation::Opacity)->SetRunState(
- Animation::Paused, kInitialTickTime + 0.5);
+ Animation::Paused, kInitialTickTime + TimeDelta::FromMilliseconds(500));
- controller->Animate(kInitialTickTime + 1024.0);
+ controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1024000));
controller->UpdateState(true, events.get());
EXPECT_TRUE(controller->HasActiveAnimation());
EXPECT_EQ(0.5f, dummy.opacity());
EXPECT_TRUE(controller->GetAnimation(id, Animation::Opacity));
- controller->GetAnimation(id, Animation::Opacity)->SetRunState(
- Animation::Running, kInitialTickTime + 1024);
-
- controller->Animate(kInitialTickTime + 1024.25);
+ controller->GetAnimation(id, Animation::Opacity)
+ ->SetRunState(Animation::Running,
+ kInitialTickTime + TimeDelta::FromMilliseconds(1024000));
+ controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1024250));
controller->UpdateState(true, events.get());
EXPECT_TRUE(controller->HasActiveAnimation());
EXPECT_EQ(0.75f, dummy.opacity());
- controller->Animate(kInitialTickTime + 1024.5);
+
+ controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1024500));
controller->UpdateState(true, events.get());
EXPECT_FALSE(controller->HasActiveAnimation());
EXPECT_EQ(1.f, dummy.opacity());
@@ -1216,19 +1329,19 @@ TEST(LayerAnimationControllerTest, AbortAGroupedAnimation) {
controller->UpdateState(true, events.get());
EXPECT_TRUE(controller->HasActiveAnimation());
EXPECT_EQ(0.f, dummy.opacity());
- controller->Animate(kInitialTickTime + 1.0);
+ controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1000));
controller->UpdateState(true, events.get());
EXPECT_TRUE(controller->HasActiveAnimation());
EXPECT_EQ(0.5f, dummy.opacity());
EXPECT_TRUE(controller->GetAnimation(id, Animation::Opacity));
controller->GetAnimation(id, Animation::Opacity)->SetRunState(
- Animation::Aborted, kInitialTickTime + 1.0);
- controller->Animate(kInitialTickTime + 1.0);
+ Animation::Aborted, kInitialTickTime + TimeDelta::FromMilliseconds(1000));
+ controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1000));
controller->UpdateState(true, events.get());
EXPECT_TRUE(controller->HasActiveAnimation());
EXPECT_EQ(1.f, dummy.opacity());
- controller->Animate(kInitialTickTime + 2.0);
+ controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(2000));
controller->UpdateState(true, events.get());
EXPECT_TRUE(!controller->HasActiveAnimation());
EXPECT_EQ(0.75f, dummy.opacity());
@@ -1261,6 +1374,7 @@ TEST(LayerAnimationControllerTest, PushUpdatesWhenSynchronizedStartTimeNeeded) {
EXPECT_TRUE(active_animation->needs_synchronized_start_time());
controller->PushAnimationUpdatesTo(controller_impl.get());
+ controller_impl->ActivateAnimations();
active_animation = controller_impl->GetAnimation(0, Animation::Opacity);
EXPECT_TRUE(active_animation);
@@ -1291,9 +1405,9 @@ TEST(LayerAnimationControllerTest, SkipUpdateState) {
Animation::Opacity));
// Animate but don't UpdateState.
- controller->Animate(kInitialTickTime + 1.0);
+ controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1000));
- controller->Animate(kInitialTickTime + 2.0);
+ controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(2000));
events.reset(new AnimationEventsVector);
controller->UpdateState(true, events.get());
@@ -1305,7 +1419,7 @@ TEST(LayerAnimationControllerTest, SkipUpdateState) {
EXPECT_TRUE(controller->HasActiveAnimation());
EXPECT_EQ(0.f, dummy.opacity());
- controller->Animate(kInitialTickTime + 3.0);
+ controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(3000));
controller->UpdateState(true, events.get());
// The float tranisition should now be done.
@@ -1313,13 +1427,13 @@ TEST(LayerAnimationControllerTest, SkipUpdateState) {
EXPECT_FALSE(controller->HasActiveAnimation());
}
-// Tests that an animation controller with only an inactive observer gets ticked
+// Tests that an animation controller with only a pending observer gets ticked
// but doesn't progress animations past the Starting state.
TEST(LayerAnimationControllerTest, InactiveObserverGetsTicked) {
scoped_ptr<AnimationEventsVector> events(
make_scoped_ptr(new AnimationEventsVector));
FakeLayerAnimationValueObserver dummy;
- FakeInactiveLayerAnimationValueObserver inactive_dummy;
+ FakeInactiveLayerAnimationValueObserver pending_dummy;
scoped_refptr<LayerAnimationController> controller(
LayerAnimationController::Create(0));
@@ -1337,46 +1451,46 @@ TEST(LayerAnimationControllerTest, InactiveObserverGetsTicked) {
EXPECT_EQ(Animation::WaitingForTargetAvailability,
controller->GetAnimation(id, Animation::Opacity)->run_state());
- controller->AddValueObserver(&inactive_dummy);
+ controller->AddValueObserver(&pending_dummy);
- // With only an inactive observer, the animation should progress to the
+ // With only a pending observer, the animation should progress to the
// Starting state and get ticked at its starting point, but should not
// progress to Running.
- controller->Animate(kInitialTickTime + 1.0);
+ controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1000));
controller->UpdateState(true, events.get());
EXPECT_EQ(0u, events->size());
EXPECT_EQ(Animation::Starting,
controller->GetAnimation(id, Animation::Opacity)->run_state());
- EXPECT_EQ(0.5f, inactive_dummy.opacity());
+ EXPECT_EQ(0.5f, pending_dummy.opacity());
// Even when already in the Starting state, the animation should stay
// there, and shouldn't be ticked past its starting point.
- controller->Animate(kInitialTickTime + 2.0);
+ controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(2000));
controller->UpdateState(true, events.get());
EXPECT_EQ(0u, events->size());
EXPECT_EQ(Animation::Starting,
controller->GetAnimation(id, Animation::Opacity)->run_state());
- EXPECT_EQ(0.5f, inactive_dummy.opacity());
+ EXPECT_EQ(0.5f, pending_dummy.opacity());
controller->AddValueObserver(&dummy);
// Now that an active observer has been added, the animation should still
// initially tick at its starting point, but should now progress to Running.
- controller->Animate(kInitialTickTime + 3.0);
+ controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(3000));
controller->UpdateState(true, events.get());
EXPECT_EQ(1u, events->size());
EXPECT_EQ(Animation::Running,
controller->GetAnimation(id, Animation::Opacity)->run_state());
- EXPECT_EQ(0.5f, inactive_dummy.opacity());
+ EXPECT_EQ(0.5f, pending_dummy.opacity());
EXPECT_EQ(0.5f, dummy.opacity());
// The animation should now tick past its starting point.
- controller->Animate(kInitialTickTime + 3.5);
- EXPECT_NE(0.5f, inactive_dummy.opacity());
+ controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(3500));
+ EXPECT_NE(0.5f, pending_dummy.opacity());
EXPECT_NE(0.5f, dummy.opacity());
}
-TEST(LayerAnimationControllerTest, AnimatedBounds) {
+TEST(LayerAnimationControllerTest, TransformAnimationBounds) {
scoped_refptr<LayerAnimationController> controller_impl(
LayerAnimationController::Create(0));
@@ -1411,24 +1525,23 @@ TEST(LayerAnimationControllerTest, AnimatedBounds) {
gfx::BoxF box(1.f, 2.f, -1.f, 3.f, 4.f, 5.f);
gfx::BoxF bounds;
- EXPECT_TRUE(controller_impl->AnimatedBoundsForBox(box, &bounds));
+ EXPECT_TRUE(controller_impl->TransformAnimationBoundsForBox(box, &bounds));
EXPECT_EQ(gfx::BoxF(1.f, 2.f, -4.f, 13.f, 19.f, 20.f).ToString(),
bounds.ToString());
controller_impl->GetAnimation(1, Animation::Transform)
- ->SetRunState(Animation::Finished, 0.0);
+ ->SetRunState(Animation::Finished, TicksFromSecondsF(0.0));
// Only the unfinished animation should affect the animated bounds.
- EXPECT_TRUE(controller_impl->AnimatedBoundsForBox(box, &bounds));
+ EXPECT_TRUE(controller_impl->TransformAnimationBoundsForBox(box, &bounds));
EXPECT_EQ(gfx::BoxF(1.f, 2.f, -4.f, 7.f, 16.f, 20.f).ToString(),
bounds.ToString());
controller_impl->GetAnimation(2, Animation::Transform)
- ->SetRunState(Animation::Finished, 0.0);
+ ->SetRunState(Animation::Finished, TicksFromSecondsF(0.0));
// There are no longer any running animations.
- EXPECT_TRUE(controller_impl->AnimatedBoundsForBox(box, &bounds));
- EXPECT_EQ(gfx::BoxF().ToString(), bounds.ToString());
+ EXPECT_FALSE(controller_impl->HasTransformAnimationThatInflatesBounds());
// Add an animation whose bounds we don't yet support computing.
scoped_ptr<KeyframedTransformAnimationCurve> curve3(
@@ -1444,7 +1557,7 @@ TEST(LayerAnimationControllerTest, AnimatedBounds) {
animation = Animation::Create(
curve3.PassAs<AnimationCurve>(), 3, 3, Animation::Transform);
controller_impl->AddAnimation(animation.Pass());
- EXPECT_FALSE(controller_impl->AnimatedBoundsForBox(box, &bounds));
+ EXPECT_FALSE(controller_impl->TransformAnimationBoundsForBox(box, &bounds));
}
// Tests that AbortAnimations aborts all animations targeting the specified
@@ -1480,7 +1593,7 @@ TEST(LayerAnimationControllerTest, AbortAnimations) {
controller->Animate(kInitialTickTime);
controller->UpdateState(true, NULL);
- controller->Animate(kInitialTickTime + 1.0);
+ controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1000));
controller->UpdateState(true, NULL);
EXPECT_EQ(Animation::Finished,
@@ -1524,6 +1637,7 @@ TEST(LayerAnimationControllerTest, MainThreadAbortedAnimationGetsDeleted) {
int group_id = controller->GetAnimation(Animation::Opacity)->group();
controller->PushAnimationUpdatesTo(controller_impl.get());
+ controller_impl->ActivateAnimations();
EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity));
controller->AbortAnimations(Animation::Opacity);
@@ -1539,6 +1653,7 @@ TEST(LayerAnimationControllerTest, MainThreadAbortedAnimationGetsDeleted) {
controller->GetAnimation(Animation::Opacity)->run_state());
controller->PushAnimationUpdatesTo(controller_impl.get());
+ controller_impl->ActivateAnimations();
EXPECT_FALSE(controller->GetAnimation(group_id, Animation::Opacity));
EXPECT_FALSE(controller_impl->GetAnimation(group_id, Animation::Opacity));
}
@@ -1558,6 +1673,7 @@ TEST(LayerAnimationControllerTest, ImplThreadAbortedAnimationGetsDeleted) {
int group_id = controller->GetAnimation(Animation::Opacity)->group();
controller->PushAnimationUpdatesTo(controller_impl.get());
+ controller_impl->ActivateAnimations();
EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity));
controller_impl->AbortAnimations(Animation::Opacity);
@@ -1579,13 +1695,14 @@ TEST(LayerAnimationControllerTest, ImplThreadAbortedAnimationGetsDeleted) {
EXPECT_EQ(Animation::Aborted,
controller->GetAnimation(Animation::Opacity)->run_state());
- controller->Animate(kInitialTickTime + 0.5);
+ controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(500));
controller->UpdateState(true, NULL);
EXPECT_TRUE(dummy.animation_waiting_for_deletion());
EXPECT_EQ(Animation::WaitingForDeletion,
controller->GetAnimation(Animation::Opacity)->run_state());
controller->PushAnimationUpdatesTo(controller_impl.get());
+ controller_impl->ActivateAnimations();
EXPECT_FALSE(controller->GetAnimation(group_id, Animation::Opacity));
EXPECT_FALSE(controller_impl->GetAnimation(group_id, Animation::Opacity));
}
@@ -1619,7 +1736,8 @@ TEST(LayerAnimationControllerTest, FinishedEventsForGroup) {
EXPECT_EQ(AnimationEvent::Started, (*events)[1].type);
events.reset(new AnimationEventsVector);
- controller_impl->Animate(kInitialTickTime + 1.0);
+ controller_impl->Animate(kInitialTickTime +
+ TimeDelta::FromMilliseconds(1000));
controller_impl->UpdateState(true, events.get());
// The opacity animation should be finished, but should not have generated
@@ -1631,7 +1749,8 @@ TEST(LayerAnimationControllerTest, FinishedEventsForGroup) {
controller_impl->GetAnimation(1,
Animation::Transform)->run_state());
- controller_impl->Animate(kInitialTickTime + 2.0);
+ controller_impl->Animate(kInitialTickTime +
+ TimeDelta::FromMilliseconds(2000));
controller_impl->UpdateState(true, events.get());
// Both animations should have generated Finished events.
@@ -1672,7 +1791,8 @@ TEST(LayerAnimationControllerTest, FinishedAndAbortedEventsForGroup) {
controller_impl->AbortAnimations(Animation::Opacity);
events.reset(new AnimationEventsVector);
- controller_impl->Animate(kInitialTickTime + 1.0);
+ controller_impl->Animate(kInitialTickTime +
+ TimeDelta::FromMilliseconds(1000));
controller_impl->UpdateState(true, events.get());
// We should have exactly 2 events: a Finished event for the tranform
@@ -1684,5 +1804,455 @@ TEST(LayerAnimationControllerTest, FinishedAndAbortedEventsForGroup) {
EXPECT_EQ(Animation::Opacity, (*events)[1].target_property);
}
+TEST(LayerAnimationControllerTest, HasAnimationThatAffectsScale) {
+ scoped_refptr<LayerAnimationController> controller_impl(
+ LayerAnimationController::Create(0));
+
+ EXPECT_FALSE(controller_impl->HasAnimationThatAffectsScale());
+
+ controller_impl->AddAnimation(CreateAnimation(
+ scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
+ 1,
+ Animation::Opacity));
+
+ // Opacity animations don't affect scale.
+ EXPECT_FALSE(controller_impl->HasAnimationThatAffectsScale());
+
+ scoped_ptr<KeyframedTransformAnimationCurve> curve1(
+ KeyframedTransformAnimationCurve::Create());
+
+ TransformOperations operations1;
+ curve1->AddKeyframe(TransformKeyframe::Create(
+ 0.0, operations1, scoped_ptr<TimingFunction>()));
+ operations1.AppendTranslate(10.0, 15.0, 0.0);
+ curve1->AddKeyframe(TransformKeyframe::Create(
+ 1.0, operations1, scoped_ptr<TimingFunction>()));
+
+ scoped_ptr<Animation> animation(Animation::Create(
+ curve1.PassAs<AnimationCurve>(), 2, 2, Animation::Transform));
+ controller_impl->AddAnimation(animation.Pass());
+
+ // Translations don't affect scale.
+ EXPECT_FALSE(controller_impl->HasAnimationThatAffectsScale());
+
+ scoped_ptr<KeyframedTransformAnimationCurve> curve2(
+ KeyframedTransformAnimationCurve::Create());
+
+ TransformOperations operations2;
+ curve2->AddKeyframe(TransformKeyframe::Create(
+ 0.0, operations2, scoped_ptr<TimingFunction>()));
+ operations2.AppendScale(2.0, 3.0, 4.0);
+ curve2->AddKeyframe(TransformKeyframe::Create(
+ 1.0, operations2, scoped_ptr<TimingFunction>()));
+
+ animation = Animation::Create(
+ curve2.PassAs<AnimationCurve>(), 3, 3, Animation::Transform);
+ controller_impl->AddAnimation(animation.Pass());
+
+ EXPECT_TRUE(controller_impl->HasAnimationThatAffectsScale());
+
+ controller_impl->GetAnimation(3, Animation::Transform)
+ ->SetRunState(Animation::Finished, TicksFromSecondsF(0.0));
+
+ // Only unfinished animations should be considered by
+ // HasAnimationThatAffectsScale.
+ EXPECT_FALSE(controller_impl->HasAnimationThatAffectsScale());
+}
+
+TEST(LayerAnimationControllerTest, HasOnlyTranslationTransforms) {
+ scoped_refptr<LayerAnimationController> controller_impl(
+ LayerAnimationController::Create(0));
+
+ EXPECT_TRUE(controller_impl->HasOnlyTranslationTransforms());
+
+ controller_impl->AddAnimation(CreateAnimation(
+ scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
+ 1,
+ Animation::Opacity));
+
+ // Opacity animations aren't non-translation transforms.
+ EXPECT_TRUE(controller_impl->HasOnlyTranslationTransforms());
+
+ scoped_ptr<KeyframedTransformAnimationCurve> curve1(
+ KeyframedTransformAnimationCurve::Create());
+
+ TransformOperations operations1;
+ curve1->AddKeyframe(TransformKeyframe::Create(
+ 0.0, operations1, scoped_ptr<TimingFunction>()));
+ operations1.AppendTranslate(10.0, 15.0, 0.0);
+ curve1->AddKeyframe(TransformKeyframe::Create(
+ 1.0, operations1, scoped_ptr<TimingFunction>()));
+
+ scoped_ptr<Animation> animation(Animation::Create(
+ curve1.PassAs<AnimationCurve>(), 2, 2, Animation::Transform));
+ controller_impl->AddAnimation(animation.Pass());
+
+ // The only transform animation we've added is a translation.
+ EXPECT_TRUE(controller_impl->HasOnlyTranslationTransforms());
+
+ scoped_ptr<KeyframedTransformAnimationCurve> curve2(
+ KeyframedTransformAnimationCurve::Create());
+
+ TransformOperations operations2;
+ curve2->AddKeyframe(TransformKeyframe::Create(
+ 0.0, operations2, scoped_ptr<TimingFunction>()));
+ operations2.AppendScale(2.0, 3.0, 4.0);
+ curve2->AddKeyframe(TransformKeyframe::Create(
+ 1.0, operations2, scoped_ptr<TimingFunction>()));
+
+ animation = Animation::Create(
+ curve2.PassAs<AnimationCurve>(), 3, 3, Animation::Transform);
+ controller_impl->AddAnimation(animation.Pass());
+
+ // A scale animation is not a translation.
+ EXPECT_FALSE(controller_impl->HasOnlyTranslationTransforms());
+
+ controller_impl->GetAnimation(3, Animation::Transform)
+ ->SetRunState(Animation::Finished, TicksFromSecondsF(0.0));
+
+ // Only unfinished animations should be considered by
+ // HasOnlyTranslationTransforms.
+ EXPECT_TRUE(controller_impl->HasOnlyTranslationTransforms());
+}
+
+TEST(LayerAnimationControllerTest, MaximumScale) {
+ scoped_refptr<LayerAnimationController> controller_impl(
+ LayerAnimationController::Create(0));
+
+ float max_scale = 0.f;
+ EXPECT_TRUE(controller_impl->MaximumScale(&max_scale));
+ EXPECT_EQ(0.f, max_scale);
+
+ scoped_ptr<KeyframedTransformAnimationCurve> curve1(
+ KeyframedTransformAnimationCurve::Create());
+
+ TransformOperations operations1;
+ curve1->AddKeyframe(TransformKeyframe::Create(
+ 0.0, operations1, scoped_ptr<TimingFunction>()));
+ operations1.AppendScale(2.0, 3.0, 4.0);
+ curve1->AddKeyframe(TransformKeyframe::Create(
+ 1.0, operations1, scoped_ptr<TimingFunction>()));
+
+ scoped_ptr<Animation> animation(Animation::Create(
+ curve1.PassAs<AnimationCurve>(), 1, 1, Animation::Transform));
+ controller_impl->AddAnimation(animation.Pass());
+
+ EXPECT_TRUE(controller_impl->MaximumScale(&max_scale));
+ EXPECT_EQ(4.f, max_scale);
+
+ scoped_ptr<KeyframedTransformAnimationCurve> curve2(
+ KeyframedTransformAnimationCurve::Create());
+
+ TransformOperations operations2;
+ curve2->AddKeyframe(TransformKeyframe::Create(
+ 0.0, operations2, scoped_ptr<TimingFunction>()));
+ operations2.AppendScale(6.0, 5.0, 4.0);
+ curve2->AddKeyframe(TransformKeyframe::Create(
+ 1.0, operations2, scoped_ptr<TimingFunction>()));
+
+ animation = Animation::Create(
+ curve2.PassAs<AnimationCurve>(), 2, 2, Animation::Transform);
+ controller_impl->AddAnimation(animation.Pass());
+
+ EXPECT_TRUE(controller_impl->MaximumScale(&max_scale));
+ EXPECT_EQ(6.f, max_scale);
+
+ scoped_ptr<KeyframedTransformAnimationCurve> curve3(
+ KeyframedTransformAnimationCurve::Create());
+
+ TransformOperations operations3;
+ curve3->AddKeyframe(TransformKeyframe::Create(
+ 0.0, operations3, scoped_ptr<TimingFunction>()));
+ operations3.AppendPerspective(6.0);
+ curve3->AddKeyframe(TransformKeyframe::Create(
+ 1.0, operations3, scoped_ptr<TimingFunction>()));
+
+ animation = Animation::Create(
+ curve3.PassAs<AnimationCurve>(), 3, 3, Animation::Transform);
+ controller_impl->AddAnimation(animation.Pass());
+
+ EXPECT_FALSE(controller_impl->MaximumScale(&max_scale));
+
+ controller_impl->GetAnimation(3, Animation::Transform)
+ ->SetRunState(Animation::Finished, TicksFromSecondsF(0.0));
+ controller_impl->GetAnimation(2, Animation::Transform)
+ ->SetRunState(Animation::Finished, TicksFromSecondsF(0.0));
+
+ // Only unfinished animations should be considered by
+ // MaximumScale.
+ EXPECT_TRUE(controller_impl->MaximumScale(&max_scale));
+ EXPECT_EQ(4.f, max_scale);
+}
+
+TEST(LayerAnimationControllerTest, NewlyPushedAnimationWaitsForActivation) {
+ scoped_ptr<AnimationEventsVector> events(
+ make_scoped_ptr(new AnimationEventsVector));
+ FakeLayerAnimationValueObserver dummy_impl;
+ FakeInactiveLayerAnimationValueObserver pending_dummy_impl;
+ scoped_refptr<LayerAnimationController> controller_impl(
+ LayerAnimationController::Create(0));
+ controller_impl->AddValueObserver(&dummy_impl);
+ controller_impl->AddValueObserver(&pending_dummy_impl);
+ FakeLayerAnimationValueObserver dummy;
+ scoped_refptr<LayerAnimationController> controller(
+ LayerAnimationController::Create(0));
+ controller->AddValueObserver(&dummy);
+
+ EXPECT_FALSE(controller->needs_to_start_animations_for_testing());
+ AddOpacityTransitionToController(controller.get(), 1, 0.5f, 1.f, false);
+ int group_id = controller->GetAnimation(Animation::Opacity)->group();
+ EXPECT_TRUE(controller->needs_to_start_animations_for_testing());
+
+ EXPECT_FALSE(controller_impl->needs_to_start_animations_for_testing());
+ controller->PushAnimationUpdatesTo(controller_impl.get());
+ EXPECT_TRUE(controller_impl->needs_to_start_animations_for_testing());
+
+ EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity));
+ EXPECT_EQ(
+ Animation::WaitingForTargetAvailability,
+ controller_impl->GetAnimation(group_id, Animation::Opacity)->run_state());
+ EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity)
+ ->affects_pending_observers());
+ EXPECT_FALSE(controller_impl->GetAnimation(group_id, Animation::Opacity)
+ ->affects_active_observers());
+
+ controller_impl->Animate(kInitialTickTime);
+ EXPECT_FALSE(controller_impl->needs_to_start_animations_for_testing());
+ controller_impl->UpdateState(true, events.get());
+
+ // Since the animation hasn't been activated, it should still be Starting
+ // rather than Running.
+ EXPECT_EQ(
+ Animation::Starting,
+ controller_impl->GetAnimation(group_id, Animation::Opacity)->run_state());
+
+ // Since the animation hasn't been activated, only the pending observer
+ // should have been ticked.
+ EXPECT_EQ(0.5f, pending_dummy_impl.opacity());
+ EXPECT_EQ(0.f, dummy_impl.opacity());
+
+ controller_impl->ActivateAnimations();
+ EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity)
+ ->affects_pending_observers());
+ EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity)
+ ->affects_active_observers());
+
+ controller_impl->Animate(kInitialTickTime +
+ TimeDelta::FromMilliseconds(1000));
+ controller_impl->UpdateState(true, events.get());
+
+ // Since the animation has been activated, it should have reached the
+ // Running state and the active observer should start to get ticked.
+ EXPECT_EQ(
+ Animation::Running,
+ controller_impl->GetAnimation(group_id, Animation::Opacity)->run_state());
+ EXPECT_EQ(0.5f, pending_dummy_impl.opacity());
+ EXPECT_EQ(0.5f, dummy_impl.opacity());
+}
+
+TEST(LayerAnimationControllerTest, ActivationBetweenAnimateAndUpdateState) {
+ scoped_ptr<AnimationEventsVector> events(
+ make_scoped_ptr(new AnimationEventsVector));
+ FakeLayerAnimationValueObserver dummy_impl;
+ FakeInactiveLayerAnimationValueObserver pending_dummy_impl;
+ scoped_refptr<LayerAnimationController> controller_impl(
+ LayerAnimationController::Create(0));
+ controller_impl->AddValueObserver(&dummy_impl);
+ controller_impl->AddValueObserver(&pending_dummy_impl);
+ FakeLayerAnimationValueObserver dummy;
+ scoped_refptr<LayerAnimationController> controller(
+ LayerAnimationController::Create(0));
+ controller->AddValueObserver(&dummy);
+
+ AddOpacityTransitionToController(controller.get(), 1, 0.5f, 1.f, true);
+ int group_id = controller->GetAnimation(Animation::Opacity)->group();
+
+ controller->PushAnimationUpdatesTo(controller_impl.get());
+
+ EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity));
+ EXPECT_EQ(
+ Animation::WaitingForTargetAvailability,
+ controller_impl->GetAnimation(group_id, Animation::Opacity)->run_state());
+ EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity)
+ ->affects_pending_observers());
+ EXPECT_FALSE(controller_impl->GetAnimation(group_id, Animation::Opacity)
+ ->affects_active_observers());
+
+ controller_impl->Animate(kInitialTickTime);
+
+ // Since the animation hasn't been activated, only the pending observer
+ // should have been ticked.
+ EXPECT_EQ(0.5f, pending_dummy_impl.opacity());
+ EXPECT_EQ(0.f, dummy_impl.opacity());
+
+ controller_impl->ActivateAnimations();
+ EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity)
+ ->affects_pending_observers());
+ EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity)
+ ->affects_active_observers());
+
+ controller_impl->UpdateState(true, events.get());
+
+ // Since the animation has been activated, it should have reached the
+ // Running state.
+ EXPECT_EQ(
+ Animation::Running,
+ controller_impl->GetAnimation(group_id, Animation::Opacity)->run_state());
+
+ controller_impl->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(500));
+
+ // Both observers should have been ticked.
+ EXPECT_EQ(0.75f, pending_dummy_impl.opacity());
+ EXPECT_EQ(0.75f, dummy_impl.opacity());
+}
+
+TEST(LayerAnimationControllerTest, PushedDeletedAnimationWaitsForActivation) {
+ scoped_ptr<AnimationEventsVector> events(
+ make_scoped_ptr(new AnimationEventsVector));
+ FakeLayerAnimationValueObserver dummy_impl;
+ FakeInactiveLayerAnimationValueObserver pending_dummy_impl;
+ scoped_refptr<LayerAnimationController> controller_impl(
+ LayerAnimationController::Create(0));
+ controller_impl->AddValueObserver(&dummy_impl);
+ controller_impl->AddValueObserver(&pending_dummy_impl);
+ FakeLayerAnimationValueObserver dummy;
+ scoped_refptr<LayerAnimationController> controller(
+ LayerAnimationController::Create(0));
+ controller->AddValueObserver(&dummy);
+
+ AddOpacityTransitionToController(controller.get(), 1, 0.5f, 1.f, true);
+ int group_id = controller->GetAnimation(Animation::Opacity)->group();
+
+ controller->PushAnimationUpdatesTo(controller_impl.get());
+ controller_impl->ActivateAnimations();
+ controller_impl->Animate(kInitialTickTime);
+ controller_impl->UpdateState(true, events.get());
+ EXPECT_EQ(
+ Animation::Running,
+ controller_impl->GetAnimation(group_id, Animation::Opacity)->run_state());
+ EXPECT_EQ(0.5f, pending_dummy_impl.opacity());
+ EXPECT_EQ(0.5f, dummy_impl.opacity());
+
+ EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity)
+ ->affects_pending_observers());
+ EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity)
+ ->affects_active_observers());
+
+ // Delete the animation on the main-thread controller.
+ controller->RemoveAnimation(
+ controller->GetAnimation(Animation::Opacity)->id());
+ controller->PushAnimationUpdatesTo(controller_impl.get());
+
+ // The animation should no longer affect pending observers.
+ EXPECT_FALSE(controller_impl->GetAnimation(group_id, Animation::Opacity)
+ ->affects_pending_observers());
+ EXPECT_TRUE(controller_impl->GetAnimation(group_id, Animation::Opacity)
+ ->affects_active_observers());
+
+ controller_impl->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(500));
+ controller_impl->UpdateState(true, events.get());
+
+ // Only the active observer should have been ticked.
+ EXPECT_EQ(0.5f, pending_dummy_impl.opacity());
+ EXPECT_EQ(0.75f, dummy_impl.opacity());
+
+ controller_impl->ActivateAnimations();
+
+ // Activation should cause the animation to be deleted.
+ EXPECT_FALSE(controller_impl->has_any_animation());
+}
+
+// Tests that an animation that affects only active observers won't block
+// an animation that affects only pending observers from starting.
+TEST(LayerAnimationControllerTest, StartAnimationsAffectingDifferentObservers) {
+ scoped_ptr<AnimationEventsVector> events(
+ make_scoped_ptr(new AnimationEventsVector));
+ FakeLayerAnimationValueObserver dummy_impl;
+ FakeInactiveLayerAnimationValueObserver pending_dummy_impl;
+ scoped_refptr<LayerAnimationController> controller_impl(
+ LayerAnimationController::Create(0));
+ controller_impl->AddValueObserver(&dummy_impl);
+ controller_impl->AddValueObserver(&pending_dummy_impl);
+ FakeLayerAnimationValueObserver dummy;
+ scoped_refptr<LayerAnimationController> controller(
+ LayerAnimationController::Create(0));
+ controller->AddValueObserver(&dummy);
+
+ AddOpacityTransitionToController(controller.get(), 1, 0.f, 1.f, true);
+ int first_animation_group_id =
+ controller->GetAnimation(Animation::Opacity)->group();
+
+ controller->PushAnimationUpdatesTo(controller_impl.get());
+ controller_impl->ActivateAnimations();
+ controller_impl->Animate(kInitialTickTime);
+ controller_impl->UpdateState(true, events.get());
+
+ // Remove the first animation from the main-thread controller, and add a
+ // new animation affecting the same property.
+ controller->RemoveAnimation(
+ controller->GetAnimation(Animation::Opacity)->id());
+ AddOpacityTransitionToController(controller.get(), 1, 1.f, 0.5f, true);
+ int second_animation_group_id =
+ controller->GetAnimation(Animation::Opacity)->group();
+ controller->PushAnimationUpdatesTo(controller_impl.get());
+
+ // The original animation should only affect active observers, and the new
+ // animation should only affect pending observers.
+ EXPECT_FALSE(controller_impl->GetAnimation(first_animation_group_id,
+ Animation::Opacity)
+ ->affects_pending_observers());
+ EXPECT_TRUE(controller_impl->GetAnimation(first_animation_group_id,
+ Animation::Opacity)
+ ->affects_active_observers());
+ EXPECT_TRUE(controller_impl->GetAnimation(second_animation_group_id,
+ Animation::Opacity)
+ ->affects_pending_observers());
+ EXPECT_FALSE(controller_impl->GetAnimation(second_animation_group_id,
+ Animation::Opacity)
+ ->affects_active_observers());
+
+ controller_impl->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(500));
+ controller_impl->UpdateState(true, events.get());
+
+ // The original animation should still be running, and the new animation
+ // should be starting.
+ EXPECT_EQ(Animation::Running,
+ controller_impl->GetAnimation(first_animation_group_id,
+ Animation::Opacity)->run_state());
+ EXPECT_EQ(Animation::Starting,
+ controller_impl->GetAnimation(second_animation_group_id,
+ Animation::Opacity)->run_state());
+
+ // The active observer should have been ticked by the original animation,
+ // and the pending observer should have been ticked by the new animation.
+ EXPECT_EQ(1.f, pending_dummy_impl.opacity());
+ EXPECT_EQ(0.5f, dummy_impl.opacity());
+
+ controller_impl->ActivateAnimations();
+
+ // The original animation should have been deleted, and the new animation
+ // should now affect both observers.
+ EXPECT_FALSE(controller_impl->GetAnimation(first_animation_group_id,
+ Animation::Opacity));
+ EXPECT_TRUE(controller_impl->GetAnimation(second_animation_group_id,
+ Animation::Opacity)
+ ->affects_pending_observers());
+ EXPECT_TRUE(controller_impl->GetAnimation(second_animation_group_id,
+ Animation::Opacity)
+ ->affects_active_observers());
+
+ controller_impl->Animate(kInitialTickTime +
+ TimeDelta::FromMilliseconds(1000));
+ controller_impl->UpdateState(true, events.get());
+
+ // 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,
+ controller_impl->GetAnimation(second_animation_group_id,
+ Animation::Opacity)->run_state());
+ EXPECT_EQ(1.f, pending_dummy_impl.opacity());
+ EXPECT_EQ(1.f, dummy_impl.opacity());
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/animation/layer_animation_value_observer.h b/chromium/cc/animation/layer_animation_value_observer.h
index d21ade80f48..e09180620f6 100644
--- a/chromium/cc/animation/layer_animation_value_observer.h
+++ b/chromium/cc/animation/layer_animation_value_observer.h
@@ -16,7 +16,7 @@ class CC_EXPORT LayerAnimationValueObserver {
virtual void OnFilterAnimated(const FilterOperations& filters) = 0;
virtual void OnOpacityAnimated(float opacity) = 0;
virtual void OnTransformAnimated(const gfx::Transform& transform) = 0;
- virtual void OnScrollOffsetAnimated(gfx::Vector2dF scroll_offset) = 0;
+ virtual void OnScrollOffsetAnimated(const gfx::Vector2dF& scroll_offset) = 0;
virtual void OnAnimationWaitingForDeletion() = 0;
virtual bool IsActive() const = 0;
};
diff --git a/chromium/cc/animation/scroll_offset_animation_curve.cc b/chromium/cc/animation/scroll_offset_animation_curve.cc
index 362aa1ed548..a7283b8b5c6 100644
--- a/chromium/cc/animation/scroll_offset_animation_curve.cc
+++ b/chromium/cc/animation/scroll_offset_animation_curve.cc
@@ -16,22 +16,22 @@ const double kDurationDivisor = 60.0;
namespace cc {
scoped_ptr<ScrollOffsetAnimationCurve> ScrollOffsetAnimationCurve::Create(
- gfx::Vector2dF target_value,
+ const gfx::Vector2dF& target_value,
scoped_ptr<TimingFunction> timing_function) {
return make_scoped_ptr(
new ScrollOffsetAnimationCurve(target_value, timing_function.Pass()));
}
ScrollOffsetAnimationCurve::ScrollOffsetAnimationCurve(
- gfx::Vector2dF target_value,
+ const gfx::Vector2dF& target_value,
scoped_ptr<TimingFunction> timing_function)
- : target_value_(target_value),
- duration_(0.0),
- timing_function_(timing_function.Pass()) {}
+ : target_value_(target_value), timing_function_(timing_function.Pass()) {
+}
ScrollOffsetAnimationCurve::~ScrollOffsetAnimationCurve() {}
-void ScrollOffsetAnimationCurve::SetInitialValue(gfx::Vector2dF initial_value) {
+void ScrollOffsetAnimationCurve::SetInitialValue(
+ const gfx::Vector2dF& initial_value) {
initial_value_ = initial_value;
// The duration of a scroll animation depends on the size of the scroll.
@@ -42,17 +42,21 @@ void ScrollOffsetAnimationCurve::SetInitialValue(gfx::Vector2dF initial_value) {
float delta_x = std::abs(target_value_.x() - initial_value_.x());
float delta_y = std::abs(target_value_.y() - initial_value_.y());
float max_delta = std::max(delta_x, delta_y);
- duration_ = std::sqrt(max_delta)/kDurationDivisor;
+ duration_ = base::TimeDelta::FromMicroseconds(
+ (std::sqrt(max_delta) / kDurationDivisor) *
+ base::Time::kMicrosecondsPerSecond);
}
gfx::Vector2dF ScrollOffsetAnimationCurve::GetValue(double t) const {
+ double duration = duration_.InSecondsF();
+
if (t <= 0)
return initial_value_;
- if (t >= duration_)
+ if (t >= duration)
return target_value_;
- double progress = timing_function_->GetValue(t / duration_);
+ double progress = (timing_function_->GetValue(t / duration));
return gfx::Vector2dF(gfx::Tween::FloatValueBetween(
progress, initial_value_.x(), target_value_.x()),
gfx::Tween::FloatValueBetween(
@@ -60,7 +64,7 @@ gfx::Vector2dF ScrollOffsetAnimationCurve::GetValue(double t) const {
}
double ScrollOffsetAnimationCurve::Duration() const {
- return duration_;
+ return duration_.InSecondsF();
}
AnimationCurve::CurveType ScrollOffsetAnimationCurve::Type() const {
diff --git a/chromium/cc/animation/scroll_offset_animation_curve.h b/chromium/cc/animation/scroll_offset_animation_curve.h
index ba4661518e8..543ae373f94 100644
--- a/chromium/cc/animation/scroll_offset_animation_curve.h
+++ b/chromium/cc/animation/scroll_offset_animation_curve.h
@@ -6,6 +6,7 @@
#define CC_ANIMATION_SCROLL_OFFSET_ANIMATION_CURVE_H_
#include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
#include "cc/animation/animation_curve.h"
#include "cc/base/cc_export.h"
@@ -16,12 +17,12 @@ class TimingFunction;
class CC_EXPORT ScrollOffsetAnimationCurve : public AnimationCurve {
public:
static scoped_ptr<ScrollOffsetAnimationCurve> Create(
- gfx::Vector2dF target_value,
+ const gfx::Vector2dF& target_value,
scoped_ptr<TimingFunction> timing_function);
virtual ~ScrollOffsetAnimationCurve();
- void SetInitialValue(gfx::Vector2dF initial_value);
+ void SetInitialValue(const gfx::Vector2dF& initial_value);
gfx::Vector2dF GetValue(double t) const;
// AnimationCurve implementation
@@ -30,12 +31,12 @@ class CC_EXPORT ScrollOffsetAnimationCurve : public AnimationCurve {
virtual scoped_ptr<AnimationCurve> Clone() const OVERRIDE;
private:
- ScrollOffsetAnimationCurve(gfx::Vector2dF target_value,
+ ScrollOffsetAnimationCurve(const gfx::Vector2dF& target_value,
scoped_ptr <TimingFunction> timing_function);
gfx::Vector2dF initial_value_;
gfx::Vector2dF target_value_;
- double duration_;
+ base::TimeDelta duration_;
scoped_ptr<TimingFunction> timing_function_;
diff --git a/chromium/cc/animation/scrollbar_animation_controller.cc b/chromium/cc/animation/scrollbar_animation_controller.cc
new file mode 100644
index 00000000000..910a7d8c139
--- /dev/null
+++ b/chromium/cc/animation/scrollbar_animation_controller.cc
@@ -0,0 +1,96 @@
+// 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/animation/scrollbar_animation_controller.h"
+
+#include <algorithm>
+
+#include "base/time/time.h"
+
+namespace cc {
+
+ScrollbarAnimationController::ScrollbarAnimationController(
+ ScrollbarAnimationControllerClient* client,
+ base::TimeDelta delay_before_starting,
+ base::TimeDelta duration)
+ : client_(client),
+ delay_before_starting_(delay_before_starting),
+ duration_(duration),
+ is_animating_(false),
+ currently_scrolling_(false),
+ scroll_gesture_has_scrolled_(false),
+ weak_factory_(this) {
+}
+
+ScrollbarAnimationController::~ScrollbarAnimationController() {
+}
+
+void ScrollbarAnimationController::Animate(base::TimeTicks now) {
+ if (!is_animating_)
+ return;
+
+ if (last_awaken_time_.is_null())
+ last_awaken_time_ = now;
+
+ float progress = AnimationProgressAtTime(now);
+ RunAnimationFrame(progress);
+
+ if (is_animating_) {
+ delayed_scrollbar_fade_.Cancel();
+ client_->SetNeedsScrollbarAnimationFrame();
+ }
+}
+
+float ScrollbarAnimationController::AnimationProgressAtTime(
+ base::TimeTicks now) {
+ base::TimeDelta delta = now - last_awaken_time_;
+ float progress = delta.InSecondsF() / duration_.InSecondsF();
+ return std::max(std::min(progress, 1.f), 0.f);
+}
+
+void ScrollbarAnimationController::DidScrollBegin() {
+ currently_scrolling_ = true;
+}
+
+void ScrollbarAnimationController::DidScrollUpdate() {
+ StopAnimation();
+ delayed_scrollbar_fade_.Cancel();
+
+ // As an optimization, we avoid spamming fade delay tasks during active fast
+ // scrolls. But if we're not within one, we need to post every scroll update.
+ if (!currently_scrolling_)
+ PostDelayedFade();
+ else
+ scroll_gesture_has_scrolled_ = true;
+}
+
+void ScrollbarAnimationController::DidScrollEnd() {
+ if (scroll_gesture_has_scrolled_) {
+ PostDelayedFade();
+ scroll_gesture_has_scrolled_ = false;
+ }
+
+ currently_scrolling_ = false;
+}
+
+void ScrollbarAnimationController::PostDelayedFade() {
+ delayed_scrollbar_fade_.Reset(
+ base::Bind(&ScrollbarAnimationController::StartAnimation,
+ weak_factory_.GetWeakPtr()));
+ client_->PostDelayedScrollbarFade(delayed_scrollbar_fade_.callback(),
+ delay_before_starting_);
+}
+
+void ScrollbarAnimationController::StartAnimation() {
+ delayed_scrollbar_fade_.Cancel();
+ is_animating_ = true;
+ last_awaken_time_ = base::TimeTicks();
+ client_->SetNeedsScrollbarAnimationFrame();
+}
+
+void ScrollbarAnimationController::StopAnimation() {
+ is_animating_ = false;
+}
+
+} // namespace cc
diff --git a/chromium/cc/animation/scrollbar_animation_controller.h b/chromium/cc/animation/scrollbar_animation_controller.h
index ecef4fb2d97..ad7f631bb9e 100644
--- a/chromium/cc/animation/scrollbar_animation_controller.h
+++ b/chromium/cc/animation/scrollbar_animation_controller.h
@@ -5,30 +5,66 @@
#ifndef CC_ANIMATION_SCROLLBAR_ANIMATION_CONTROLLER_H_
#define CC_ANIMATION_SCROLLBAR_ANIMATION_CONTROLLER_H_
+#include "base/cancelable_callback.h"
+#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "cc/base/cc_export.h"
#include "ui/gfx/vector2d_f.h"
namespace cc {
+class CC_EXPORT ScrollbarAnimationControllerClient {
+ public:
+ virtual ~ScrollbarAnimationControllerClient() {}
+
+ virtual void PostDelayedScrollbarFade(const base::Closure& start_fade,
+ base::TimeDelta delay) = 0;
+ virtual void SetNeedsScrollbarAnimationFrame() = 0;
+};
+
// This abstract class represents the compositor-side analogy of
// ScrollbarAnimator. Individual platforms should subclass it to provide
// specialized implementation.
class CC_EXPORT ScrollbarAnimationController {
public:
- virtual ~ScrollbarAnimationController() {}
+ virtual ~ScrollbarAnimationController();
+
+ void Animate(base::TimeTicks now);
+
+ virtual void DidScrollBegin();
+ virtual void DidScrollUpdate();
+ virtual void DidScrollEnd();
+ virtual void DidMouseMoveOffScrollbar() {}
+ virtual void DidMouseMoveNear(float distance) {}
+
+ protected:
+ ScrollbarAnimationController(ScrollbarAnimationControllerClient* client,
+ base::TimeDelta delay_before_starting,
+ base::TimeDelta duration);
+
+ virtual void RunAnimationFrame(float progress) = 0;
+
+ void StartAnimation();
+ void StopAnimation();
+
+ private:
+ // Returns how far through the animation we are as a progress value from
+ // 0 to 1.
+ float AnimationProgressAtTime(base::TimeTicks now);
+
+ void PostDelayedFade();
- virtual bool IsAnimating() const = 0;
- virtual base::TimeDelta DelayBeforeStart(base::TimeTicks now) const = 0;
+ ScrollbarAnimationControllerClient* client_;
+ base::TimeTicks last_awaken_time_;
+ base::TimeDelta delay_before_starting_;
+ base::TimeDelta duration_;
+ bool is_animating_;
- virtual bool Animate(base::TimeTicks now) = 0;
- virtual void DidScrollGestureBegin() = 0;
- virtual void DidScrollGestureEnd(base::TimeTicks now) = 0;
- virtual void DidMouseMoveOffScrollbar(base::TimeTicks now) = 0;
+ bool currently_scrolling_;
+ bool scroll_gesture_has_scrolled_;
+ base::CancelableClosure delayed_scrollbar_fade_;
- // Returns true if we should start an animation.
- virtual bool DidScrollUpdate(base::TimeTicks now) = 0;
- virtual bool DidMouseMoveNear(base::TimeTicks now, float distance) = 0;
+ base::WeakPtrFactory<ScrollbarAnimationController> weak_factory_;
};
} // namespace cc
diff --git a/chromium/cc/animation/scrollbar_animation_controller_linear_fade.cc b/chromium/cc/animation/scrollbar_animation_controller_linear_fade.cc
index 863959b84c2..a7b220c6419 100644
--- a/chromium/cc/animation/scrollbar_animation_controller_linear_fade.cc
+++ b/chromium/cc/animation/scrollbar_animation_controller_linear_fade.cc
@@ -11,116 +11,51 @@
namespace cc {
scoped_ptr<ScrollbarAnimationControllerLinearFade>
-ScrollbarAnimationControllerLinearFade::Create(LayerImpl* scroll_layer,
- base::TimeDelta fadeout_delay,
- base::TimeDelta fadeout_length) {
+ScrollbarAnimationControllerLinearFade::Create(
+ LayerImpl* scroll_layer,
+ ScrollbarAnimationControllerClient* client,
+ base::TimeDelta delay_before_starting,
+ base::TimeDelta duration) {
return make_scoped_ptr(new ScrollbarAnimationControllerLinearFade(
- scroll_layer, fadeout_delay, fadeout_length));
+ scroll_layer, client, delay_before_starting, duration));
}
ScrollbarAnimationControllerLinearFade::ScrollbarAnimationControllerLinearFade(
LayerImpl* scroll_layer,
- base::TimeDelta fadeout_delay,
- base::TimeDelta fadeout_length)
- : ScrollbarAnimationController(),
- scroll_layer_(scroll_layer),
- scroll_gesture_in_progress_(false),
- scroll_gesture_has_scrolled_(false),
- fadeout_delay_(fadeout_delay),
- fadeout_length_(fadeout_length) {}
+ ScrollbarAnimationControllerClient* client,
+ base::TimeDelta delay_before_starting,
+ base::TimeDelta duration)
+ : ScrollbarAnimationController(client, delay_before_starting, duration),
+ scroll_layer_(scroll_layer) {
+}
ScrollbarAnimationControllerLinearFade::
~ScrollbarAnimationControllerLinearFade() {}
-bool ScrollbarAnimationControllerLinearFade::IsAnimating() const {
- return !last_awaken_time_.is_null();
-}
-
-base::TimeDelta ScrollbarAnimationControllerLinearFade::DelayBeforeStart(
- base::TimeTicks now) const {
- if (now > last_awaken_time_ + fadeout_delay_)
- return base::TimeDelta();
- return fadeout_delay_ - (now - last_awaken_time_);
-}
-
-bool ScrollbarAnimationControllerLinearFade::Animate(base::TimeTicks now) {
- float opacity = OpacityAtTime(now);
- ApplyOpacityToScrollbars(opacity);
- if (!opacity)
- last_awaken_time_ = base::TimeTicks();
- return IsAnimating() && DelayBeforeStart(now) == base::TimeDelta();
-}
-
-void ScrollbarAnimationControllerLinearFade::DidScrollGestureBegin() {
- scroll_gesture_in_progress_ = true;
- scroll_gesture_has_scrolled_ = false;
-}
-
-void ScrollbarAnimationControllerLinearFade::DidScrollGestureEnd(
- base::TimeTicks now) {
- // The animation should not be triggered if no scrolling has occurred.
- if (scroll_gesture_has_scrolled_)
- last_awaken_time_ = now;
- scroll_gesture_has_scrolled_ = false;
- scroll_gesture_in_progress_ = false;
-}
-
-void ScrollbarAnimationControllerLinearFade::DidMouseMoveOffScrollbar(
- base::TimeTicks now) {
- // Ignore mouse move events.
+void ScrollbarAnimationControllerLinearFade::RunAnimationFrame(float progress) {
+ ApplyOpacityToScrollbars(1.f - progress);
+ if (progress == 1.f)
+ StopAnimation();
}
-bool ScrollbarAnimationControllerLinearFade::DidScrollUpdate(
- base::TimeTicks now) {
- ApplyOpacityToScrollbars(1.0f);
- // The animation should only be activated if the scroll updated occurred
- // programatically, outside the scope of a scroll gesture.
- if (scroll_gesture_in_progress_) {
- last_awaken_time_ = base::TimeTicks();
- scroll_gesture_has_scrolled_ = true;
- return false;
- }
-
- last_awaken_time_ = now;
- return true;
-}
-
-bool ScrollbarAnimationControllerLinearFade::DidMouseMoveNear(
- base::TimeTicks now, float distance) {
- // Ignore mouse move events.
- return false;
-}
-
-float ScrollbarAnimationControllerLinearFade::OpacityAtTime(
- base::TimeTicks now) {
- if (scroll_gesture_has_scrolled_)
- return 1.0f;
-
- if (last_awaken_time_.is_null())
- return 0.0f;
-
- base::TimeDelta delta = now - last_awaken_time_;
-
- if (delta <= fadeout_delay_)
- return 1.0f;
- if (delta < fadeout_delay_ + fadeout_length_) {
- return (fadeout_delay_ + fadeout_length_ - delta).InSecondsF() /
- fadeout_length_.InSecondsF();
- }
- return 0.0f;
+void ScrollbarAnimationControllerLinearFade::DidScrollUpdate() {
+ ScrollbarAnimationController::DidScrollUpdate();
+ ApplyOpacityToScrollbars(1.f);
}
void ScrollbarAnimationControllerLinearFade::ApplyOpacityToScrollbars(
float opacity) {
- ScrollbarLayerImplBase* horizontal_scrollbar =
- scroll_layer_->horizontal_scrollbar_layer();
- if (horizontal_scrollbar)
- horizontal_scrollbar->SetOpacity(opacity);
-
- ScrollbarLayerImplBase* vertical_scrollbar =
- scroll_layer_->vertical_scrollbar_layer();
- if (vertical_scrollbar)
- vertical_scrollbar->SetOpacity(opacity);
+ if (!scroll_layer_->scrollbars())
+ return;
+
+ LayerImpl::ScrollbarSet* scrollbars = scroll_layer_->scrollbars();
+ for (LayerImpl::ScrollbarSet::iterator it = scrollbars->begin();
+ it != scrollbars->end();
+ ++it) {
+ ScrollbarLayerImplBase* scrollbar = *it;
+ if (scrollbar->is_overlay_scrollbar())
+ scrollbar->SetOpacity(opacity);
+ }
}
} // namespace cc
diff --git a/chromium/cc/animation/scrollbar_animation_controller_linear_fade.h b/chromium/cc/animation/scrollbar_animation_controller_linear_fade.h
index 85cdada5156..10700499784 100644
--- a/chromium/cc/animation/scrollbar_animation_controller_linear_fade.h
+++ b/chromium/cc/animation/scrollbar_animation_controller_linear_fade.h
@@ -17,40 +17,29 @@ class CC_EXPORT ScrollbarAnimationControllerLinearFade
public:
static scoped_ptr<ScrollbarAnimationControllerLinearFade> Create(
LayerImpl* scroll_layer,
- base::TimeDelta fadeout_delay,
- base::TimeDelta fadeout_length);
+ ScrollbarAnimationControllerClient* client,
+ base::TimeDelta delay_before_starting,
+ base::TimeDelta duration);
virtual ~ScrollbarAnimationControllerLinearFade();
- // ScrollbarAnimationController overrides.
- virtual bool IsAnimating() const OVERRIDE;
- virtual base::TimeDelta DelayBeforeStart(base::TimeTicks now) const OVERRIDE;
-
- virtual bool Animate(base::TimeTicks now) OVERRIDE;
- virtual void DidScrollGestureBegin() OVERRIDE;
- virtual void DidScrollGestureEnd(base::TimeTicks now) OVERRIDE;
- virtual void DidMouseMoveOffScrollbar(base::TimeTicks now) OVERRIDE;
- virtual bool DidScrollUpdate(base::TimeTicks now) OVERRIDE;
- virtual bool DidMouseMoveNear(base::TimeTicks now, float distance) OVERRIDE;
+ virtual void DidScrollUpdate() OVERRIDE;
protected:
- ScrollbarAnimationControllerLinearFade(LayerImpl* scroll_layer,
- base::TimeDelta fadeout_delay,
- base::TimeDelta fadeout_length);
+ ScrollbarAnimationControllerLinearFade(
+ LayerImpl* scroll_layer,
+ ScrollbarAnimationControllerClient* client,
+ base::TimeDelta delay_before_starting,
+ base::TimeDelta duration);
+
+ virtual void RunAnimationFrame(float progress) OVERRIDE;
private:
- float OpacityAtTime(base::TimeTicks now);
+ float OpacityAtTime(base::TimeTicks now) const;
void ApplyOpacityToScrollbars(float opacity);
LayerImpl* scroll_layer_;
- base::TimeTicks last_awaken_time_;
- bool scroll_gesture_in_progress_;
- bool scroll_gesture_has_scrolled_;
-
- base::TimeDelta fadeout_delay_;
- base::TimeDelta fadeout_length_;
-
DISALLOW_COPY_AND_ASSIGN(ScrollbarAnimationControllerLinearFade);
};
diff --git a/chromium/cc/animation/scrollbar_animation_controller_linear_fade_unittest.cc b/chromium/cc/animation/scrollbar_animation_controller_linear_fade_unittest.cc
index b4c1160b081..c5033359362 100644
--- a/chromium/cc/animation/scrollbar_animation_controller_linear_fade_unittest.cc
+++ b/chromium/cc/animation/scrollbar_animation_controller_linear_fade_unittest.cc
@@ -4,91 +4,119 @@
#include "cc/animation/scrollbar_animation_controller_linear_fade.h"
-#include "cc/layers/painted_scrollbar_layer_impl.h"
+#include "cc/layers/solid_color_scrollbar_layer_impl.h"
#include "cc/test/fake_impl_proxy.h"
#include "cc/test/fake_layer_tree_host_impl.h"
+#include "cc/test/test_shared_bitmap_manager.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace cc {
namespace {
-class ScrollbarAnimationControllerLinearFadeTest : public testing::Test {
+class ScrollbarAnimationControllerLinearFadeTest
+ : public testing::Test,
+ public ScrollbarAnimationControllerClient {
public:
- ScrollbarAnimationControllerLinearFadeTest() : host_impl_(&proxy_) {}
+ ScrollbarAnimationControllerLinearFadeTest()
+ : host_impl_(&proxy_, &shared_bitmap_manager_), needs_frame_count_(0) {}
+
+ virtual void PostDelayedScrollbarFade(const base::Closure& start_fade,
+ base::TimeDelta delay) OVERRIDE {
+ start_fade_ = start_fade;
+ }
+ virtual void SetNeedsScrollbarAnimationFrame() OVERRIDE {
+ needs_frame_count_++;
+ }
protected:
virtual void SetUp() {
- scroll_layer_ = LayerImpl::Create(host_impl_.active_tree(), 1);
- scrollbar_layer_ = PaintedScrollbarLayerImpl::Create(
- host_impl_.active_tree(), 2, HORIZONTAL);
-
- scroll_layer_->SetMaxScrollOffset(gfx::Vector2d(50, 50));
- scroll_layer_->SetBounds(gfx::Size(50, 50));
- scroll_layer_->SetHorizontalScrollbarLayer(scrollbar_layer_.get());
+ const int kThumbThickness = 10;
+ const int kTrackStart = 0;
+ const bool kIsLeftSideVerticalScrollbar = false;
+ const bool kIsOverlayScrollbar = true; // Allow opacity animations.
+
+ scoped_ptr<LayerImpl> scroll_layer =
+ LayerImpl::Create(host_impl_.active_tree(), 1);
+ scrollbar_layer_ =
+ SolidColorScrollbarLayerImpl::Create(host_impl_.active_tree(),
+ 2,
+ HORIZONTAL,
+ kThumbThickness,
+ kTrackStart,
+ kIsLeftSideVerticalScrollbar,
+ kIsOverlayScrollbar);
+ clip_layer_ = LayerImpl::Create(host_impl_.active_tree(), 3);
+ scroll_layer->SetScrollClipLayer(clip_layer_->id());
+ LayerImpl* scroll_layer_ptr = scroll_layer.get();
+ clip_layer_->AddChild(scroll_layer.Pass());
+
+ scrollbar_layer_->SetClipLayerById(clip_layer_->id());
+ scrollbar_layer_->SetScrollLayerById(scroll_layer_ptr->id());
+ clip_layer_->SetBounds(gfx::Size(100, 100));
+ scroll_layer_ptr->SetBounds(gfx::Size(50, 50));
scrollbar_controller_ = ScrollbarAnimationControllerLinearFade::Create(
- scroll_layer_.get(),
+ scroll_layer_ptr,
+ this,
base::TimeDelta::FromSeconds(2),
base::TimeDelta::FromSeconds(3));
}
FakeImplProxy proxy_;
+ TestSharedBitmapManager shared_bitmap_manager_;
FakeLayerTreeHostImpl host_impl_;
scoped_ptr<ScrollbarAnimationControllerLinearFade> scrollbar_controller_;
- scoped_ptr<LayerImpl> scroll_layer_;
- scoped_ptr<PaintedScrollbarLayerImpl> scrollbar_layer_;
+ scoped_ptr<LayerImpl> clip_layer_;
+ scoped_ptr<SolidColorScrollbarLayerImpl> scrollbar_layer_;
+
+ base::Closure start_fade_;
+ int needs_frame_count_;
};
TEST_F(ScrollbarAnimationControllerLinearFadeTest, HiddenInBegin) {
+ scrollbar_layer_->SetOpacity(0.0f);
scrollbar_controller_->Animate(base::TimeTicks());
EXPECT_FLOAT_EQ(0.0f, scrollbar_layer_->opacity());
+ EXPECT_EQ(0, needs_frame_count_);
}
TEST_F(ScrollbarAnimationControllerLinearFadeTest,
HiddenAfterNonScrollingGesture) {
- scrollbar_controller_->DidScrollGestureBegin();
- EXPECT_FALSE(scrollbar_controller_->IsAnimating());
- EXPECT_FALSE(scrollbar_controller_->Animate(base::TimeTicks()));
- EXPECT_FLOAT_EQ(0.0f, scrollbar_layer_->opacity());
+ scrollbar_layer_->SetOpacity(0.0f);
+ scrollbar_controller_->DidScrollBegin();
base::TimeTicks time;
time += base::TimeDelta::FromSeconds(100);
- EXPECT_FALSE(scrollbar_controller_->Animate(time));
+ scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(0.0f, scrollbar_layer_->opacity());
- scrollbar_controller_->DidScrollGestureEnd(time);
+ scrollbar_controller_->DidScrollEnd();
+
+ EXPECT_TRUE(start_fade_.Equals(base::Closure()));
time += base::TimeDelta::FromSeconds(100);
- EXPECT_FALSE(scrollbar_controller_->IsAnimating());
- EXPECT_FALSE(scrollbar_controller_->Animate(time));
+ scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(0.0f, scrollbar_layer_->opacity());
+
+ EXPECT_EQ(0, needs_frame_count_);
}
TEST_F(ScrollbarAnimationControllerLinearFadeTest, AwakenByScrollingGesture) {
base::TimeTicks time;
time += base::TimeDelta::FromSeconds(1);
- scrollbar_controller_->DidScrollGestureBegin();
- scrollbar_controller_->Animate(time);
- EXPECT_FALSE(scrollbar_controller_->IsAnimating());
- EXPECT_FLOAT_EQ(0.0f, scrollbar_layer_->opacity());
-
- EXPECT_FALSE(scrollbar_controller_->DidScrollUpdate(time));
- EXPECT_FALSE(scrollbar_controller_->IsAnimating());
- EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
+ scrollbar_controller_->DidScrollBegin();
- time += base::TimeDelta::FromSeconds(100);
- scrollbar_controller_->Animate(time);
- EXPECT_FALSE(scrollbar_controller_->IsAnimating());
+ scrollbar_controller_->DidScrollUpdate();
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
- scrollbar_controller_->DidScrollGestureEnd(time);
- EXPECT_TRUE(scrollbar_controller_->IsAnimating());
- EXPECT_EQ(2, scrollbar_controller_->DelayBeforeStart(time).InSeconds());
+ EXPECT_TRUE(start_fade_.Equals(base::Closure()));
- time += base::TimeDelta::FromSeconds(1);
+ time += base::TimeDelta::FromSeconds(100);
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
+ scrollbar_controller_->DidScrollEnd();
+ start_fade_.Run();
- time += base::TimeDelta::FromSeconds(1);
+ time += base::TimeDelta::FromSeconds(2);
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
@@ -102,15 +130,12 @@ TEST_F(ScrollbarAnimationControllerLinearFadeTest, AwakenByScrollingGesture) {
time += base::TimeDelta::FromSeconds(1);
- scrollbar_controller_->DidScrollGestureBegin();
- EXPECT_FALSE(scrollbar_controller_->DidScrollUpdate(time));
- scrollbar_controller_->DidScrollGestureEnd(time);
-
- time += base::TimeDelta::FromSeconds(1);
- scrollbar_controller_->Animate(time);
- EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
+ scrollbar_controller_->DidScrollBegin();
+ scrollbar_controller_->DidScrollUpdate();
+ scrollbar_controller_->DidScrollEnd();
+ start_fade_.Run();
- time += base::TimeDelta::FromSeconds(1);
+ time += base::TimeDelta::FromSeconds(2);
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
@@ -125,25 +150,23 @@ TEST_F(ScrollbarAnimationControllerLinearFadeTest, AwakenByScrollingGesture) {
time += base::TimeDelta::FromSeconds(1);
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(0.0f, scrollbar_layer_->opacity());
+
+ EXPECT_EQ(8, needs_frame_count_);
}
TEST_F(ScrollbarAnimationControllerLinearFadeTest, AwakenByProgrammaticScroll) {
base::TimeTicks time;
time += base::TimeDelta::FromSeconds(1);
- EXPECT_TRUE(scrollbar_controller_->DidScrollUpdate(time));
- EXPECT_TRUE(scrollbar_controller_->IsAnimating());
- EXPECT_EQ(2, scrollbar_controller_->DelayBeforeStart(time).InSeconds());
+ scrollbar_controller_->DidScrollUpdate();
+ start_fade_.Run();
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
time += base::TimeDelta::FromSeconds(1);
scrollbar_controller_->Animate(time);
- EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
- EXPECT_TRUE(scrollbar_controller_->DidScrollUpdate(time));
-
- time += base::TimeDelta::FromSeconds(1);
- scrollbar_controller_->Animate(time);
- EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
+ EXPECT_FLOAT_EQ(2.0f / 3.0f, scrollbar_layer_->opacity());
+ scrollbar_controller_->DidScrollUpdate();
+ start_fade_.Run();
time += base::TimeDelta::FromSeconds(1);
scrollbar_controller_->Animate(time);
@@ -158,11 +181,8 @@ TEST_F(ScrollbarAnimationControllerLinearFadeTest, AwakenByProgrammaticScroll) {
EXPECT_FLOAT_EQ(1.0f / 3.0f, scrollbar_layer_->opacity());
time += base::TimeDelta::FromSeconds(1);
- EXPECT_TRUE(scrollbar_controller_->DidScrollUpdate(time));
- time += base::TimeDelta::FromSeconds(1);
- scrollbar_controller_->Animate(time);
- EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
-
+ scrollbar_controller_->DidScrollUpdate();
+ start_fade_.Run();
time += base::TimeDelta::FromSeconds(1);
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
@@ -178,53 +198,56 @@ TEST_F(ScrollbarAnimationControllerLinearFadeTest, AwakenByProgrammaticScroll) {
time += base::TimeDelta::FromSeconds(1);
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(0.0f, scrollbar_layer_->opacity());
+
+ EXPECT_EQ(11, needs_frame_count_);
}
TEST_F(ScrollbarAnimationControllerLinearFadeTest,
AnimationPreservedByNonScrollingGesture) {
base::TimeTicks time;
time += base::TimeDelta::FromSeconds(1);
- EXPECT_TRUE(scrollbar_controller_->DidScrollUpdate(time));
- EXPECT_TRUE(scrollbar_controller_->IsAnimating());
+ scrollbar_controller_->DidScrollUpdate();
+ start_fade_.Run();
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
- time += base::TimeDelta::FromSeconds(3);
+ time += base::TimeDelta::FromSeconds(1);
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(2.0f / 3.0f, scrollbar_layer_->opacity());
- scrollbar_controller_->DidScrollGestureBegin();
- EXPECT_TRUE(scrollbar_controller_->IsAnimating());
+ scrollbar_controller_->DidScrollBegin();
EXPECT_FLOAT_EQ(2.0f / 3.0f, scrollbar_layer_->opacity());
time += base::TimeDelta::FromSeconds(1);
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(1.0f / 3.0f, scrollbar_layer_->opacity());
- scrollbar_controller_->DidScrollGestureEnd(time);
- EXPECT_TRUE(scrollbar_controller_->IsAnimating());
+ scrollbar_controller_->DidScrollEnd();
EXPECT_FLOAT_EQ(1.0f / 3.0f, scrollbar_layer_->opacity());
time += base::TimeDelta::FromSeconds(1);
- EXPECT_FALSE(scrollbar_controller_->Animate(time));
+ scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(0.0f, scrollbar_layer_->opacity());
+
+ scrollbar_controller_->Animate(time);
+
+ EXPECT_EQ(4, needs_frame_count_);
}
TEST_F(ScrollbarAnimationControllerLinearFadeTest,
AnimationOverriddenByScrollingGesture) {
base::TimeTicks time;
time += base::TimeDelta::FromSeconds(1);
- EXPECT_TRUE(scrollbar_controller_->DidScrollUpdate(time));
- EXPECT_TRUE(scrollbar_controller_->IsAnimating());
+ scrollbar_controller_->DidScrollUpdate();
+ start_fade_.Run();
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
- time += base::TimeDelta::FromSeconds(3);
+ time += base::TimeDelta::FromSeconds(1);
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(2.0f / 3.0f, scrollbar_layer_->opacity());
- scrollbar_controller_->DidScrollGestureBegin();
- EXPECT_TRUE(scrollbar_controller_->IsAnimating());
+ scrollbar_controller_->DidScrollBegin();
EXPECT_FLOAT_EQ(2.0f / 3.0f, scrollbar_layer_->opacity());
time += base::TimeDelta::FromSeconds(1);
@@ -232,13 +255,11 @@ TEST_F(ScrollbarAnimationControllerLinearFadeTest,
EXPECT_FLOAT_EQ(1.0f / 3.0f, scrollbar_layer_->opacity());
time += base::TimeDelta::FromSeconds(1);
- EXPECT_FALSE(scrollbar_controller_->DidScrollUpdate(time));
- EXPECT_FALSE(scrollbar_controller_->IsAnimating());
+ scrollbar_controller_->DidScrollUpdate();
EXPECT_FLOAT_EQ(1, scrollbar_layer_->opacity());
time += base::TimeDelta::FromSeconds(1);
- scrollbar_controller_->DidScrollGestureEnd(time);
- EXPECT_TRUE(scrollbar_controller_->IsAnimating());
+ scrollbar_controller_->DidScrollEnd();
EXPECT_FLOAT_EQ(1, scrollbar_layer_->opacity());
}
diff --git a/chromium/cc/animation/scrollbar_animation_controller_thinning.cc b/chromium/cc/animation/scrollbar_animation_controller_thinning.cc
index 3de75989d0e..892e3079e46 100644
--- a/chromium/cc/animation/scrollbar_animation_controller_thinning.cc
+++ b/chromium/cc/animation/scrollbar_animation_controller_thinning.cc
@@ -4,8 +4,6 @@
#include "cc/animation/scrollbar_animation_controller_thinning.h"
-#include <algorithm>
-
#include "base/time/time.h"
#include "cc/layers/layer_impl.h"
#include "cc/layers/scrollbar_layer_impl_base.h"
@@ -14,40 +12,31 @@ namespace {
const float kIdleThicknessScale = 0.4f;
const float kIdleOpacity = 0.7f;
const float kDefaultMouseMoveDistanceToTriggerAnimation = 25.f;
-const int kDefaultAnimationDelay = 500;
-const int kDefaultAnimationDuration = 300;
}
namespace cc {
scoped_ptr<ScrollbarAnimationControllerThinning>
-ScrollbarAnimationControllerThinning::Create(LayerImpl* scroll_layer) {
- return make_scoped_ptr(new ScrollbarAnimationControllerThinning(
- scroll_layer,
- base::TimeDelta::FromMilliseconds(kDefaultAnimationDelay),
- base::TimeDelta::FromMilliseconds(kDefaultAnimationDuration)));
-}
-
-scoped_ptr<ScrollbarAnimationControllerThinning>
-ScrollbarAnimationControllerThinning::CreateForTest(LayerImpl* scroll_layer,
- base::TimeDelta animation_delay, base::TimeDelta animation_duration) {
+ScrollbarAnimationControllerThinning::Create(
+ LayerImpl* scroll_layer,
+ ScrollbarAnimationControllerClient* client,
+ base::TimeDelta delay_before_starting,
+ base::TimeDelta duration) {
return make_scoped_ptr(new ScrollbarAnimationControllerThinning(
- scroll_layer, animation_delay, animation_duration));
+ scroll_layer, client, delay_before_starting, duration));
}
ScrollbarAnimationControllerThinning::ScrollbarAnimationControllerThinning(
LayerImpl* scroll_layer,
- base::TimeDelta animation_delay,
- base::TimeDelta animation_duration)
- : ScrollbarAnimationController(),
+ ScrollbarAnimationControllerClient* client,
+ base::TimeDelta delay_before_starting,
+ base::TimeDelta duration)
+ : ScrollbarAnimationController(client, delay_before_starting, duration),
scroll_layer_(scroll_layer),
mouse_is_over_scrollbar_(false),
mouse_is_near_scrollbar_(false),
thickness_change_(NONE),
opacity_change_(NONE),
- should_delay_animation_(false),
- animation_delay_(animation_delay),
- animation_duration_(animation_duration),
mouse_move_distance_to_trigger_animation_(
kDefaultMouseMoveDistanceToTriggerAnimation) {
ApplyOpacityAndThumbThicknessScale(kIdleOpacity, kIdleThicknessScale);
@@ -56,21 +45,7 @@ ScrollbarAnimationControllerThinning::ScrollbarAnimationControllerThinning(
ScrollbarAnimationControllerThinning::~ScrollbarAnimationControllerThinning() {
}
-bool ScrollbarAnimationControllerThinning::IsAnimating() const {
- return !last_awaken_time_.is_null();
-}
-
-base::TimeDelta ScrollbarAnimationControllerThinning::DelayBeforeStart(
- base::TimeTicks now) const {
- if (!should_delay_animation_)
- return base::TimeDelta();
- if (now > last_awaken_time_ + animation_delay_)
- return base::TimeDelta();
- return animation_delay_ - (now - last_awaken_time_);
-}
-
-bool ScrollbarAnimationControllerThinning::Animate(base::TimeTicks now) {
- float progress = AnimationProgressAtTime(now);
+void ScrollbarAnimationControllerThinning::RunAnimationFrame(float progress) {
float opacity = OpacityAtAnimationProgress(progress);
float thumb_thickness_scale = ThumbThicknessScaleAtAnimationProgress(
progress);
@@ -78,49 +53,35 @@ bool ScrollbarAnimationControllerThinning::Animate(base::TimeTicks now) {
if (progress == 1.f) {
opacity_change_ = NONE;
thickness_change_ = NONE;
- last_awaken_time_ = base::TimeTicks();
+ StopAnimation();
}
- return IsAnimating() && DelayBeforeStart(now) == base::TimeDelta();
}
-void ScrollbarAnimationControllerThinning::DidScrollGestureBegin() {
-}
-
-void ScrollbarAnimationControllerThinning::DidScrollGestureEnd(
- base::TimeTicks now) {
-}
-
-void ScrollbarAnimationControllerThinning::DidMouseMoveOffScrollbar(
- base::TimeTicks now) {
+void ScrollbarAnimationControllerThinning::DidMouseMoveOffScrollbar() {
mouse_is_over_scrollbar_ = false;
mouse_is_near_scrollbar_ = false;
- last_awaken_time_ = now;
- should_delay_animation_ = false;
opacity_change_ = DECREASE;
thickness_change_ = DECREASE;
+ StartAnimation();
}
-bool ScrollbarAnimationControllerThinning::DidScrollUpdate(
- base::TimeTicks now) {
+void ScrollbarAnimationControllerThinning::DidScrollUpdate() {
+ ScrollbarAnimationController::DidScrollUpdate();
ApplyOpacityAndThumbThicknessScale(
1, mouse_is_near_scrollbar_ ? 1.f : kIdleThicknessScale);
- last_awaken_time_ = now;
- should_delay_animation_ = true;
if (!mouse_is_over_scrollbar_)
opacity_change_ = DECREASE;
- return true;
}
-bool ScrollbarAnimationControllerThinning::DidMouseMoveNear(
- base::TimeTicks now, float distance) {
+void ScrollbarAnimationControllerThinning::DidMouseMoveNear(float distance) {
bool mouse_is_over_scrollbar = distance == 0.0;
bool mouse_is_near_scrollbar =
distance < mouse_move_distance_to_trigger_animation_;
if (mouse_is_over_scrollbar == mouse_is_over_scrollbar_ &&
mouse_is_near_scrollbar == mouse_is_near_scrollbar_)
- return false;
+ return;
if (mouse_is_over_scrollbar_ != mouse_is_over_scrollbar) {
mouse_is_over_scrollbar_ = mouse_is_over_scrollbar;
@@ -132,21 +93,7 @@ bool ScrollbarAnimationControllerThinning::DidMouseMoveNear(
thickness_change_ = mouse_is_near_scrollbar_ ? INCREASE : DECREASE;
}
- last_awaken_time_ = now;
- should_delay_animation_ = false;
- return true;
-}
-
-float ScrollbarAnimationControllerThinning::AnimationProgressAtTime(
- base::TimeTicks now) {
- if (last_awaken_time_.is_null())
- return 1;
-
- base::TimeDelta delta = now - last_awaken_time_;
- if (should_delay_animation_)
- delta -= animation_delay_;
- float progress = delta.InSecondsF() / animation_duration_.InSecondsF();
- return std::max(std::min(progress, 1.f), 0.f);
+ StartAnimation();
}
float ScrollbarAnimationControllerThinning::OpacityAtAnimationProgress(
@@ -180,28 +127,22 @@ float ScrollbarAnimationControllerThinning::AdjustScale(
void ScrollbarAnimationControllerThinning::ApplyOpacityAndThumbThicknessScale(
float opacity, float thumb_thickness_scale) {
- ScrollbarLayerImplBase* horizontal_scrollbar =
- scroll_layer_->horizontal_scrollbar_layer();
- if (horizontal_scrollbar) {
- horizontal_scrollbar->SetOpacity(
- AdjustScale(opacity, horizontal_scrollbar->opacity(), opacity_change_));
- horizontal_scrollbar->SetThumbThicknessScaleFactor(
- AdjustScale(
- thumb_thickness_scale,
- horizontal_scrollbar->thumb_thickness_scale_factor(),
- thickness_change_));
- }
-
- ScrollbarLayerImplBase* vertical_scrollbar =
- scroll_layer_->vertical_scrollbar_layer();
- if (vertical_scrollbar) {
- vertical_scrollbar->SetOpacity(
- AdjustScale(opacity, vertical_scrollbar->opacity(), opacity_change_));
- vertical_scrollbar->SetThumbThicknessScaleFactor(
- AdjustScale(
- thumb_thickness_scale,
- vertical_scrollbar->thumb_thickness_scale_factor(),
- thickness_change_));
+ if (!scroll_layer_->scrollbars())
+ return;
+
+ LayerImpl::ScrollbarSet* scrollbars = scroll_layer_->scrollbars();
+ for (LayerImpl::ScrollbarSet::iterator it = scrollbars->begin();
+ it != scrollbars->end();
+ ++it) {
+ ScrollbarLayerImplBase* scrollbar = *it;
+ if (scrollbar->is_overlay_scrollbar()) {
+ scrollbar->SetOpacity(
+ AdjustScale(opacity, scrollbar->opacity(), opacity_change_));
+ scrollbar->SetThumbThicknessScaleFactor(
+ AdjustScale(thumb_thickness_scale,
+ scrollbar->thumb_thickness_scale_factor(),
+ thickness_change_));
+ }
}
}
diff --git a/chromium/cc/animation/scrollbar_animation_controller_thinning.h b/chromium/cc/animation/scrollbar_animation_controller_thinning.h
index 07b4515ec31..c0c7a83e2ea 100644
--- a/chromium/cc/animation/scrollbar_animation_controller_thinning.h
+++ b/chromium/cc/animation/scrollbar_animation_controller_thinning.h
@@ -12,17 +12,16 @@
namespace cc {
class LayerImpl;
-// Scrollbar animation that partially fades and thins after an idle delay.
+// Scrollbar animation that partially fades and thins after an idle delay,
+// and reacts to mouse movements.
class CC_EXPORT ScrollbarAnimationControllerThinning
: public ScrollbarAnimationController {
public:
static scoped_ptr<ScrollbarAnimationControllerThinning> Create(
- LayerImpl* scroll_layer);
-
- static scoped_ptr<ScrollbarAnimationControllerThinning> CreateForTest(
LayerImpl* scroll_layer,
- base::TimeDelta animation_delay,
- base::TimeDelta animation_duration);
+ ScrollbarAnimationControllerClient* client,
+ base::TimeDelta delay_before_starting,
+ base::TimeDelta duration);
virtual ~ScrollbarAnimationControllerThinning();
@@ -32,21 +31,18 @@ class CC_EXPORT ScrollbarAnimationControllerThinning
bool mouse_is_over_scrollbar() const { return mouse_is_over_scrollbar_; }
bool mouse_is_near_scrollbar() const { return mouse_is_near_scrollbar_; }
- // ScrollbarAnimationController overrides.
- virtual bool IsAnimating() const OVERRIDE;
- virtual base::TimeDelta DelayBeforeStart(base::TimeTicks now) const OVERRIDE;
-
- virtual bool Animate(base::TimeTicks now) OVERRIDE;
- virtual void DidScrollGestureBegin() OVERRIDE;
- virtual void DidScrollGestureEnd(base::TimeTicks now) OVERRIDE;
- virtual void DidMouseMoveOffScrollbar(base::TimeTicks now) OVERRIDE;
- virtual bool DidScrollUpdate(base::TimeTicks now) OVERRIDE;
- virtual bool DidMouseMoveNear(base::TimeTicks now, float distance) OVERRIDE;
+ virtual void DidScrollUpdate() OVERRIDE;
+ virtual void DidMouseMoveOffScrollbar() OVERRIDE;
+ virtual void DidMouseMoveNear(float distance) OVERRIDE;
protected:
- ScrollbarAnimationControllerThinning(LayerImpl* scroll_layer,
- base::TimeDelta animation_delay,
- base::TimeDelta animation_duration);
+ ScrollbarAnimationControllerThinning(
+ LayerImpl* scroll_layer,
+ ScrollbarAnimationControllerClient* client,
+ base::TimeDelta delay_before_starting,
+ base::TimeDelta duration);
+
+ virtual void RunAnimationFrame(float progress) OVERRIDE;
private:
// Describes whether the current animation should INCREASE (darken / thicken)
@@ -56,9 +52,6 @@ class CC_EXPORT ScrollbarAnimationControllerThinning
INCREASE,
DECREASE
};
- // Returns how far through the animation we are as a progress value from
- // 0 to 1.
- float AnimationProgressAtTime(base::TimeTicks now);
float OpacityAtAnimationProgress(float progress);
float ThumbThicknessScaleAtAnimationProgress(float progress);
float AdjustScale(float new_value,
@@ -69,19 +62,12 @@ class CC_EXPORT ScrollbarAnimationControllerThinning
LayerImpl* scroll_layer_;
- base::TimeTicks last_awaken_time_;
bool mouse_is_over_scrollbar_;
bool mouse_is_near_scrollbar_;
// Are we narrowing or thickening the bars.
AnimationChange thickness_change_;
// Are we darkening or lightening the bars.
AnimationChange opacity_change_;
- // Should the animation be delayed or start immediately.
- bool should_delay_animation_;
- // If |should_delay_animation_| is true, delay the animation by this amount.
- base::TimeDelta animation_delay_;
- // The time for the animation to run.
- base::TimeDelta animation_duration_;
// How close should the mouse be to the scrollbar before we thicken it.
float mouse_move_distance_to_trigger_animation_;
diff --git a/chromium/cc/animation/scrollbar_animation_controller_thinning_unittest.cc b/chromium/cc/animation/scrollbar_animation_controller_thinning_unittest.cc
index c915632f2fc..c0ab5158752 100644
--- a/chromium/cc/animation/scrollbar_animation_controller_thinning_unittest.cc
+++ b/chromium/cc/animation/scrollbar_animation_controller_thinning_unittest.cc
@@ -7,40 +7,68 @@
#include "cc/layers/solid_color_scrollbar_layer_impl.h"
#include "cc/test/fake_impl_proxy.h"
#include "cc/test/fake_layer_tree_host_impl.h"
+#include "cc/test/test_shared_bitmap_manager.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace cc {
namespace {
-class ScrollbarAnimationControllerThinningTest : public testing::Test {
+class ScrollbarAnimationControllerThinningTest
+ : public testing::Test,
+ public ScrollbarAnimationControllerClient {
public:
- ScrollbarAnimationControllerThinningTest() : host_impl_(&proxy_) {}
+ ScrollbarAnimationControllerThinningTest()
+ : host_impl_(&proxy_, &shared_bitmap_manager_) {}
+
+ virtual void PostDelayedScrollbarFade(const base::Closure& start_fade,
+ base::TimeDelta delay) OVERRIDE {
+ start_fade_ = start_fade;
+ }
+ virtual void SetNeedsScrollbarAnimationFrame() OVERRIDE {}
protected:
virtual void SetUp() {
- scroll_layer_ = LayerImpl::Create(host_impl_.active_tree(), 1);
+ scoped_ptr<LayerImpl> scroll_layer =
+ LayerImpl::Create(host_impl_.active_tree(), 1);
+ clip_layer_ = LayerImpl::Create(host_impl_.active_tree(), 3);
+ scroll_layer->SetScrollClipLayer(clip_layer_->id());
+ LayerImpl* scroll_layer_ptr = scroll_layer.get();
+ clip_layer_->AddChild(scroll_layer.Pass());
+
const int kId = 2;
const int kThumbThickness = 10;
+ const int kTrackStart = 0;
const bool kIsLeftSideVerticalScrollbar = false;
- scrollbar_layer_ = SolidColorScrollbarLayerImpl::Create(
- host_impl_.active_tree(), kId, HORIZONTAL, kThumbThickness,
- kIsLeftSideVerticalScrollbar);
-
- scroll_layer_->SetMaxScrollOffset(gfx::Vector2d(50, 50));
- scroll_layer_->SetBounds(gfx::Size(50, 50));
- scroll_layer_->SetHorizontalScrollbarLayer(scrollbar_layer_.get());
-
- scrollbar_controller_ = ScrollbarAnimationControllerThinning::CreateForTest(
- scroll_layer_.get(),
+ const bool kIsOverlayScrollbar = true;
+ scrollbar_layer_ =
+ SolidColorScrollbarLayerImpl::Create(host_impl_.active_tree(),
+ kId,
+ HORIZONTAL,
+ kThumbThickness,
+ kTrackStart,
+ kIsLeftSideVerticalScrollbar,
+ kIsOverlayScrollbar);
+
+ scrollbar_layer_->SetClipLayerById(clip_layer_->id());
+ scrollbar_layer_->SetScrollLayerById(scroll_layer_ptr->id());
+ clip_layer_->SetBounds(gfx::Size(100, 100));
+ scroll_layer_ptr->SetBounds(gfx::Size(50, 50));
+
+ scrollbar_controller_ = ScrollbarAnimationControllerThinning::Create(
+ scroll_layer_ptr,
+ this,
base::TimeDelta::FromSeconds(2),
base::TimeDelta::FromSeconds(3));
}
FakeImplProxy proxy_;
+ TestSharedBitmapManager shared_bitmap_manager_;
FakeLayerTreeHostImpl host_impl_;
scoped_ptr<ScrollbarAnimationControllerThinning> scrollbar_controller_;
- scoped_ptr<LayerImpl> scroll_layer_;
+ scoped_ptr<LayerImpl> clip_layer_;
scoped_ptr<SolidColorScrollbarLayerImpl> scrollbar_layer_;
+
+ base::Closure start_fade_;
};
// Check initialization of scrollbar.
@@ -55,31 +83,24 @@ TEST_F(ScrollbarAnimationControllerThinningTest, Idle) {
TEST_F(ScrollbarAnimationControllerThinningTest, AwakenByProgrammaticScroll) {
base::TimeTicks time;
time += base::TimeDelta::FromSeconds(1);
- EXPECT_TRUE(scrollbar_controller_->DidScrollUpdate(time));
- EXPECT_TRUE(scrollbar_controller_->IsAnimating());
- EXPECT_EQ(2, scrollbar_controller_->DelayBeforeStart(time).InSeconds());
+ scrollbar_controller_->DidScrollUpdate();
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
// Scrollbar doesn't change size if triggered by scroll.
EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
+ start_fade_.Run();
+
time += base::TimeDelta::FromSeconds(1);
- EXPECT_EQ(1, scrollbar_controller_->DelayBeforeStart(time).InSeconds());
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
// Subsequent scroll restarts animation.
- EXPECT_TRUE(scrollbar_controller_->DidScrollUpdate(time));
- EXPECT_EQ(2, scrollbar_controller_->DelayBeforeStart(time).InSeconds());
+ scrollbar_controller_->DidScrollUpdate();
- time += base::TimeDelta::FromSeconds(1);
- EXPECT_EQ(1, scrollbar_controller_->DelayBeforeStart(time).InSeconds());
- scrollbar_controller_->Animate(time);
- EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
- EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
+ start_fade_.Run();
- time += base::TimeDelta::FromSeconds(1);
- EXPECT_EQ(0, scrollbar_controller_->DelayBeforeStart(time).InSeconds());
+ time += base::TimeDelta::FromSeconds(2);
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
@@ -98,8 +119,6 @@ TEST_F(ScrollbarAnimationControllerThinningTest, AwakenByProgrammaticScroll) {
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity());
EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
-
- EXPECT_FALSE(scrollbar_controller_->IsAnimating());
}
// Initiate a scroll when the pointer is already near the scrollbar. It should
@@ -108,22 +127,22 @@ TEST_F(ScrollbarAnimationControllerThinningTest, ScrollWithMouseNear) {
base::TimeTicks time;
time += base::TimeDelta::FromSeconds(1);
- scrollbar_controller_->DidMouseMoveNear(time, 1);
+ scrollbar_controller_->DidMouseMoveNear(1);
+ scrollbar_controller_->Animate(time);
time += base::TimeDelta::FromSeconds(3);
+
scrollbar_controller_->Animate(time);
- EXPECT_FALSE(scrollbar_controller_->IsAnimating());
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
- EXPECT_TRUE(scrollbar_controller_->DidScrollUpdate(time));
- EXPECT_TRUE(scrollbar_controller_->IsAnimating());
- EXPECT_EQ(2, scrollbar_controller_->DelayBeforeStart(time).InSeconds());
+ scrollbar_controller_->DidScrollUpdate();
+ start_fade_.Run();
+ scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
// Scrollbar should still be thick.
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
time += base::TimeDelta::FromSeconds(5);
scrollbar_controller_->Animate(time);
- EXPECT_FALSE(scrollbar_controller_->IsAnimating());
EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity());
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
}
@@ -133,9 +152,8 @@ TEST_F(ScrollbarAnimationControllerThinningTest, ScrollWithMouseNear) {
TEST_F(ScrollbarAnimationControllerThinningTest, MouseNear) {
base::TimeTicks time;
time += base::TimeDelta::FromSeconds(1);
- scrollbar_controller_->DidMouseMoveNear(time, 1);
- EXPECT_TRUE(scrollbar_controller_->IsAnimating());
- EXPECT_EQ(0, scrollbar_controller_->DelayBeforeStart(time).InSeconds());
+ scrollbar_controller_->DidMouseMoveNear(1);
+ scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity());
EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
@@ -154,19 +172,17 @@ TEST_F(ScrollbarAnimationControllerThinningTest, MouseNear) {
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity());
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
- EXPECT_FALSE(scrollbar_controller_->IsAnimating());
// Subsequent moves should not change anything.
- scrollbar_controller_->DidMouseMoveNear(time, 1);
+ scrollbar_controller_->DidMouseMoveNear(1);
+ scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity());
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
- EXPECT_FALSE(scrollbar_controller_->IsAnimating());
// Now move away from bar.
time += base::TimeDelta::FromSeconds(1);
- scrollbar_controller_->DidMouseMoveNear(time, 26);
- EXPECT_TRUE(scrollbar_controller_->IsAnimating());
- EXPECT_EQ(0, scrollbar_controller_->DelayBeforeStart(time).InSeconds());
+ scrollbar_controller_->DidMouseMoveNear(26);
+ scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity());
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
@@ -185,7 +201,6 @@ TEST_F(ScrollbarAnimationControllerThinningTest, MouseNear) {
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity());
EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
- EXPECT_FALSE(scrollbar_controller_->IsAnimating());
}
// Move the pointer over the scrollbar. Make sure it gets thick and dark
@@ -193,9 +208,8 @@ TEST_F(ScrollbarAnimationControllerThinningTest, MouseNear) {
TEST_F(ScrollbarAnimationControllerThinningTest, MouseOver) {
base::TimeTicks time;
time += base::TimeDelta::FromSeconds(1);
- scrollbar_controller_->DidMouseMoveNear(time, 0);
- EXPECT_TRUE(scrollbar_controller_->IsAnimating());
- EXPECT_EQ(0, scrollbar_controller_->DelayBeforeStart(time).InSeconds());
+ scrollbar_controller_->DidMouseMoveNear(0);
+ scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity());
EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
@@ -214,19 +228,17 @@ TEST_F(ScrollbarAnimationControllerThinningTest, MouseOver) {
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
- EXPECT_FALSE(scrollbar_controller_->IsAnimating());
// Subsequent moves should not change anything.
- scrollbar_controller_->DidMouseMoveNear(time, 0);
+ scrollbar_controller_->DidMouseMoveNear(0);
+ scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
- EXPECT_FALSE(scrollbar_controller_->IsAnimating());
// Now move away from bar.
time += base::TimeDelta::FromSeconds(1);
- scrollbar_controller_->DidMouseMoveNear(time, 26);
- EXPECT_TRUE(scrollbar_controller_->IsAnimating());
- EXPECT_EQ(0, scrollbar_controller_->DelayBeforeStart(time).InSeconds());
+ scrollbar_controller_->DidMouseMoveNear(26);
+ scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
@@ -245,7 +257,6 @@ TEST_F(ScrollbarAnimationControllerThinningTest, MouseOver) {
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity());
EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
- EXPECT_FALSE(scrollbar_controller_->IsAnimating());
}
// First move the pointer near the scrollbar, then over it, then back near
@@ -254,9 +265,8 @@ TEST_F(ScrollbarAnimationControllerThinningTest, MouseOver) {
TEST_F(ScrollbarAnimationControllerThinningTest, MouseNearThenOver) {
base::TimeTicks time;
time += base::TimeDelta::FromSeconds(1);
- scrollbar_controller_->DidMouseMoveNear(time, 1);
- EXPECT_TRUE(scrollbar_controller_->IsAnimating());
- EXPECT_EQ(0, scrollbar_controller_->DelayBeforeStart(time).InSeconds());
+ scrollbar_controller_->DidMouseMoveNear(1);
+ scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity());
EXPECT_FLOAT_EQ(0.4f, scrollbar_layer_->thumb_thickness_scale_factor());
@@ -265,12 +275,10 @@ TEST_F(ScrollbarAnimationControllerThinningTest, MouseNearThenOver) {
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(0.7f, scrollbar_layer_->opacity());
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
- EXPECT_FALSE(scrollbar_controller_->IsAnimating());
// Now move over.
- scrollbar_controller_->DidMouseMoveNear(time, 0);
- EXPECT_TRUE(scrollbar_controller_->IsAnimating());
- EXPECT_EQ(0, scrollbar_controller_->DelayBeforeStart(time).InSeconds());
+ scrollbar_controller_->DidMouseMoveNear(0);
+ scrollbar_controller_->Animate(time);
// Should animate to darkened.
time += base::TimeDelta::FromSeconds(1);
@@ -287,24 +295,23 @@ TEST_F(ScrollbarAnimationControllerThinningTest, MouseNearThenOver) {
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->opacity());
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
- EXPECT_FALSE(scrollbar_controller_->IsAnimating());
// This is tricky. The DidMouseMoveOffScrollbar() is sent before the
// subsequent DidMouseMoveNear(), 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);
- scrollbar_controller_->DidMouseMoveOffScrollbar(time);
- EXPECT_TRUE(scrollbar_controller_->IsAnimating());
+ scrollbar_controller_->DidMouseMoveOffScrollbar();
+ scrollbar_controller_->Animate(time);
time += base::TimeDelta::FromSeconds(1);
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(0.9f, scrollbar_layer_->opacity());
EXPECT_FLOAT_EQ(0.8f, scrollbar_layer_->thumb_thickness_scale_factor());
- scrollbar_controller_->DidMouseMoveNear(time, 1);
+ scrollbar_controller_->DidMouseMoveNear(1);
+ scrollbar_controller_->Animate(time);
// A new animation is kicked off.
- EXPECT_TRUE(scrollbar_controller_->IsAnimating());
time += base::TimeDelta::FromSeconds(1);
scrollbar_controller_->Animate(time);
diff --git a/chromium/cc/animation/timing_function.cc b/chromium/cc/animation/timing_function.cc
index 7fdb37fed96..bf11c20fe03 100644
--- a/chromium/cc/animation/timing_function.cc
+++ b/chromium/cc/animation/timing_function.cc
@@ -2,67 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include <algorithm>
-#include <cmath>
-
#include "base/logging.h"
#include "cc/animation/timing_function.h"
namespace cc {
-namespace {
-
-static const double kBezierEpsilon = 1e-7;
-static const int MAX_STEPS = 30;
-
-static double eval_bezier(double x1, double x2, double t) {
- const double x1_times_3 = 3.0 * x1;
- const double x2_times_3 = 3.0 * x2;
- const double h3 = x1_times_3;
- const double h1 = x1_times_3 - x2_times_3 + 1.0;
- const double h2 = x2_times_3 - 6.0 * x1;
- return t * (t * (t * h1 + h2) + h3);
-}
-
-static double bezier_interp(double x1,
- double y1,
- double x2,
- double y2,
- double x) {
- DCHECK_GE(1.0, x1);
- DCHECK_LE(0.0, x1);
- DCHECK_GE(1.0, x2);
- DCHECK_LE(0.0, x2);
-
- x1 = std::min(std::max(x1, 0.0), 1.0);
- x2 = std::min(std::max(x2, 0.0), 1.0);
- x = std::min(std::max(x, 0.0), 1.0);
-
- // Step 1. Find the t corresponding to the given x. I.e., we want t such that
- // eval_bezier(x1, x2, t) = x. There is a unique solution if x1 and x2 lie
- // within (0, 1).
- //
- // We're just going to do bisection for now (for simplicity), but we could
- // easily do some newton steps if this turns out to be a bottleneck.
- double t = 0.0;
- double step = 1.0;
- for (int i = 0; i < MAX_STEPS; ++i, step *= 0.5) {
- const double error = eval_bezier(x1, x2, t) - x;
- if (std::abs(error) < kBezierEpsilon)
- break;
- t += error > 0.0 ? -step : step;
- }
-
- // We should have terminated the above loop because we got close to x, not
- // because we exceeded MAX_STEPS. Do a DCHECK here to confirm.
- DCHECK_GT(kBezierEpsilon, std::abs(eval_bezier(x1, x2, t) - x));
-
- // Step 2. Return the interpolated y values at the t we computed above.
- return eval_bezier(y1, y2, t);
-}
-
-} // namespace
-
TimingFunction::TimingFunction() {}
TimingFunction::~TimingFunction() {}
@@ -80,12 +24,12 @@ CubicBezierTimingFunction::CubicBezierTimingFunction(double x1,
double y1,
double x2,
double y2)
- : x1_(x1), y1_(y1), x2_(x2), y2_(y2) {}
+ : bezier_(x1, y1, x2, y2) {}
CubicBezierTimingFunction::~CubicBezierTimingFunction() {}
float CubicBezierTimingFunction::GetValue(double x) const {
- return static_cast<float>(bezier_interp(x1_, y1_, x2_, y2_, x));
+ return static_cast<float>(bezier_.Solve(x));
}
scoped_ptr<AnimationCurve> CubicBezierTimingFunction::Clone() const {
@@ -94,50 +38,11 @@ scoped_ptr<AnimationCurve> CubicBezierTimingFunction::Clone() const {
}
void CubicBezierTimingFunction::Range(float* min, float* max) const {
- *min = 0.f;
- *max = 1.f;
- if (0.f <= y1_ && y1_ < 1.f && 0.f <= y2_ && y2_ <= 1.f)
- return;
-
- // Represent the function's derivative in the form at^2 + bt + c.
- float a = 3.f * (y1_ - y2_) + 1.f;
- float b = 2.f * (y2_ - 2.f * y1_);
- float c = y1_;
-
- // Check if the derivative is constant.
- if (std::abs(a) < kBezierEpsilon &&
- std::abs(b) < kBezierEpsilon)
- return;
-
- // Zeros of the function's derivative.
- float t_1 = 0.f;
- float t_2 = 0.f;
-
- if (std::abs(a) < kBezierEpsilon) {
- // The function's derivative is linear.
- t_1 = -c / b;
- } else {
- // The function's derivative is a quadratic. We find the zeros of this
- // quadratic using the quadratic formula.
- float discriminant = b * b - 4 * a * c;
- if (discriminant < 0.f)
- return;
- float discriminant_sqrt = sqrt(discriminant);
- t_1 = (-b + discriminant_sqrt) / (2.f * a);
- t_2 = (-b - discriminant_sqrt) / (2.f * a);
- }
-
- float sol_1 = 0.f;
- float sol_2 = 0.f;
-
- if (0.f < t_1 && t_1 < 1.f)
- sol_1 = eval_bezier(y1_, y2_, t_1);
-
- if (0.f < t_2 && t_2 < 1.f)
- sol_2 = eval_bezier(y1_, y2_, t_2);
-
- *min = std::min(std::min(*min, sol_1), sol_2);
- *max = std::max(std::max(*max, sol_1), sol_2);
+ double min_d = 0;
+ double max_d = 1;
+ bezier_.Range(&min_d, &max_d);
+ *min = static_cast<float>(min_d);
+ *max = static_cast<float>(max_d);
}
// These numbers come from
diff --git a/chromium/cc/animation/timing_function.h b/chromium/cc/animation/timing_function.h
index 056ad414193..647701f30ce 100644
--- a/chromium/cc/animation/timing_function.h
+++ b/chromium/cc/animation/timing_function.h
@@ -7,7 +7,7 @@
#include "cc/animation/animation_curve.h"
#include "cc/base/cc_export.h"
-#include "third_party/skia/include/core/SkScalar.h"
+#include "ui/gfx/geometry/cubic_bezier.h"
namespace cc {
@@ -45,10 +45,7 @@ class CC_EXPORT CubicBezierTimingFunction : public TimingFunction {
protected:
CubicBezierTimingFunction(double x1, double y1, double x2, double y2);
- double x1_;
- double y1_;
- double x2_;
- double y2_;
+ gfx::CubicBezier bezier_;
private:
DISALLOW_ASSIGN(CubicBezierTimingFunction);
diff --git a/chromium/cc/animation/timing_function_unittest.cc b/chromium/cc/animation/timing_function_unittest.cc
deleted file mode 100644
index 4be225fd6b9..00000000000
--- a/chromium/cc/animation/timing_function_unittest.cc
+++ /dev/null
@@ -1,141 +0,0 @@
-// Copyright 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/animation/timing_function.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace cc {
-namespace {
-
-TEST(TimingFunctionTest, CubicBezierTimingFunction) {
- scoped_ptr<CubicBezierTimingFunction> function =
- CubicBezierTimingFunction::Create(0.25, 0.0, 0.75, 1.0);
-
- double epsilon = 0.00015;
-
- EXPECT_NEAR(function->GetValue(0), 0, epsilon);
- EXPECT_NEAR(function->GetValue(0.05), 0.01136, epsilon);
- EXPECT_NEAR(function->GetValue(0.1), 0.03978, epsilon);
- EXPECT_NEAR(function->GetValue(0.15), 0.079780, epsilon);
- EXPECT_NEAR(function->GetValue(0.2), 0.12803, epsilon);
- EXPECT_NEAR(function->GetValue(0.25), 0.18235, epsilon);
- EXPECT_NEAR(function->GetValue(0.3), 0.24115, epsilon);
- EXPECT_NEAR(function->GetValue(0.35), 0.30323, epsilon);
- EXPECT_NEAR(function->GetValue(0.4), 0.36761, epsilon);
- EXPECT_NEAR(function->GetValue(0.45), 0.43345, epsilon);
- EXPECT_NEAR(function->GetValue(0.5), 0.5, epsilon);
- EXPECT_NEAR(function->GetValue(0.6), 0.63238, epsilon);
- EXPECT_NEAR(function->GetValue(0.65), 0.69676, epsilon);
- EXPECT_NEAR(function->GetValue(0.7), 0.75884, epsilon);
- EXPECT_NEAR(function->GetValue(0.75), 0.81764, epsilon);
- EXPECT_NEAR(function->GetValue(0.8), 0.87196, epsilon);
- EXPECT_NEAR(function->GetValue(0.85), 0.92021, epsilon);
- EXPECT_NEAR(function->GetValue(0.9), 0.96021, epsilon);
- EXPECT_NEAR(function->GetValue(0.95), 0.98863, epsilon);
- EXPECT_NEAR(function->GetValue(1), 1, epsilon);
-}
-
-// Tests that the bezier timing function works with knots with y not in (0, 1).
-TEST(TimingFunctionTest, CubicBezierTimingFunctionUnclampedYValues) {
- scoped_ptr<CubicBezierTimingFunction> function =
- CubicBezierTimingFunction::Create(0.5, -1.0, 0.5, 2.0);
-
- double epsilon = 0.00015;
-
- EXPECT_NEAR(function->GetValue(0.0), 0.0, epsilon);
- EXPECT_NEAR(function->GetValue(0.05), -0.08954, epsilon);
- EXPECT_NEAR(function->GetValue(0.1), -0.15613, epsilon);
- EXPECT_NEAR(function->GetValue(0.15), -0.19641, epsilon);
- EXPECT_NEAR(function->GetValue(0.2), -0.20651, epsilon);
- EXPECT_NEAR(function->GetValue(0.25), -0.18232, epsilon);
- EXPECT_NEAR(function->GetValue(0.3), -0.11992, epsilon);
- EXPECT_NEAR(function->GetValue(0.35), -0.01672, epsilon);
- EXPECT_NEAR(function->GetValue(0.4), 0.12660, epsilon);
- EXPECT_NEAR(function->GetValue(0.45), 0.30349, epsilon);
- EXPECT_NEAR(function->GetValue(0.5), 0.50000, epsilon);
- EXPECT_NEAR(function->GetValue(0.55), 0.69651, epsilon);
- EXPECT_NEAR(function->GetValue(0.6), 0.87340, epsilon);
- EXPECT_NEAR(function->GetValue(0.65), 1.01672, epsilon);
- EXPECT_NEAR(function->GetValue(0.7), 1.11992, epsilon);
- EXPECT_NEAR(function->GetValue(0.75), 1.18232, epsilon);
- EXPECT_NEAR(function->GetValue(0.8), 1.20651, epsilon);
- EXPECT_NEAR(function->GetValue(0.85), 1.19641, epsilon);
- EXPECT_NEAR(function->GetValue(0.9), 1.15613, epsilon);
- EXPECT_NEAR(function->GetValue(0.95), 1.08954, epsilon);
- EXPECT_NEAR(function->GetValue(1.0), 1.0, epsilon);
-}
-
-TEST(TimingFunctionTest, CubicBezierTimingFunctionRange) {
- double epsilon = 0.00015;
- float min, max;
-
- // Derivative is a constant.
- scoped_ptr<CubicBezierTimingFunction> function =
- CubicBezierTimingFunction::Create(0.25, (1.0 / 3.0), 0.75, (2.0 / 3.0));
- function->Range(&min, &max);
- EXPECT_EQ(0.f, min);
- EXPECT_EQ(1.f, max);
-
- // Derivative is linear.
- function = CubicBezierTimingFunction::Create(0.25, -0.5, 0.75, (-1.0 / 6.0));
- function->Range(&min, &max);
- EXPECT_NEAR(min, -0.225, epsilon);
- EXPECT_EQ(1.f, max);
-
- // Derivative has no real roots.
- function = CubicBezierTimingFunction::Create(0.25, 0.25, 0.75, 0.5);
- function->Range(&min, &max);
- EXPECT_EQ(0.f, min);
- EXPECT_EQ(1.f, max);
-
- // Derivative has exactly one real root.
- function = CubicBezierTimingFunction::Create(0.0, 1.0, 1.0, 0.0);
- function->Range(&min, &max);
- EXPECT_EQ(0.f, min);
- EXPECT_EQ(1.f, max);
-
- // Derivative has one root < 0 and one root > 1.
- function = CubicBezierTimingFunction::Create(0.25, 0.1, 0.75, 0.9);
- function->Range(&min, &max);
- EXPECT_EQ(0.f, min);
- EXPECT_EQ(1.f, max);
-
- // Derivative has two roots in [0,1].
- function = CubicBezierTimingFunction::Create(0.25, 2.5, 0.75, 0.5);
- function->Range(&min, &max);
- EXPECT_EQ(0.f, min);
- EXPECT_NEAR(max, 1.28818, epsilon);
- function = CubicBezierTimingFunction::Create(0.25, 0.5, 0.75, -1.5);
- function->Range(&min, &max);
- EXPECT_NEAR(min, -0.28818, epsilon);
- EXPECT_EQ(1.f, max);
-
- // Derivative has one root < 0 and one root in [0,1].
- function = CubicBezierTimingFunction::Create(0.25, 0.1, 0.75, 1.5);
- function->Range(&min, &max);
- EXPECT_EQ(0.f, min);
- EXPECT_NEAR(max, 1.10755, epsilon);
-
- // Derivative has one root in [0,1] and one root > 1.
- function = CubicBezierTimingFunction::Create(0.25, -0.5, 0.75, 0.9);
- function->Range(&min, &max);
- EXPECT_NEAR(min, -0.10755, epsilon);
- EXPECT_EQ(1.f, max);
-
- // Derivative has two roots < 0.
- function = CubicBezierTimingFunction::Create(0.25, 0.3, 0.75, 0.633);
- function->Range(&min, &max);
- EXPECT_EQ(0.f, min);
- EXPECT_EQ(1.f, max);
-
- // Derivative has two roots > 1.
- function = CubicBezierTimingFunction::Create(0.25, 0.367, 0.75, 0.7);
- function->Range(&min, &max);
- EXPECT_EQ(0.f, min);
- EXPECT_EQ(1.f, max);
-}
-
-} // namespace
-} // namespace cc
diff --git a/chromium/cc/animation/transform_operation.cc b/chromium/cc/animation/transform_operation.cc
index e4d0dadf0eb..f4403fa37e5 100644
--- a/chromium/cc/animation/transform_operation.cc
+++ b/chromium/cc/animation/transform_operation.cc
@@ -314,31 +314,29 @@ static void BoundingBoxForArc(const gfx::Point3F& point,
return;
v1.Scale(1.f / v1_length);
-
gfx::Vector3dF v2 = gfx::CrossProduct(normal, v1);
-
- // Now figure out where (1, 0, 0) and (0, 0, 1) project on the rotation
- // plane.
- gfx::Point3F px(1.f, 0.f, 0.f);
- gfx::Vector3dF to_px = px - center;
- gfx::Point3F px_projected =
- px - gfx::ScaleVector3d(normal, gfx::DotProduct(to_px, normal));
- gfx::Vector3dF vx = px_projected - origin;
-
- gfx::Point3F pz(0.f, 0.f, 1.f);
- gfx::Vector3dF to_pz = pz - center;
- gfx::Point3F pz_projected =
- pz - ScaleVector3d(normal, gfx::DotProduct(to_pz, normal));
- gfx::Vector3dF vz = pz_projected - origin;
-
- double phi_x = atan2(gfx::DotProduct(v2, vx), gfx::DotProduct(v1, vx));
- double phi_z = atan2(gfx::DotProduct(v2, vz), gfx::DotProduct(v1, vz));
-
- candidates[0] = atan2(normal.y(), normal.x() * normal.z()) + phi_x;
+ // v1 is the basis vector in the direction of the point.
+ // i.e. with a rotation of 0, v1 is our +x vector.
+ // v2 is a perpenticular basis vector of our plane (+y).
+
+ // Take the parametric equation of a circle.
+ // x = r*cos(t); y = r*sin(t);
+ // We can treat that as a circle on the plane v1xv2.
+ // From that we get the parametric equations for a circle on the
+ // plane in 3d space of:
+ // x(t) = r*cos(t)*v1.x + r*sin(t)*v2.x + cx
+ // y(t) = r*cos(t)*v1.y + r*sin(t)*v2.y + cy
+ // z(t) = r*cos(t)*v1.z + r*sin(t)*v2.z + cz
+ // Taking the derivative of (x, y, z) and solving for 0 gives us our
+ // maximum/minimum x, y, z values.
+ // x'(t) = r*cos(t)*v2.x - r*sin(t)*v1.x = 0
+ // tan(t) = v2.x/v1.x
+ // t = atan2(v2.x, v1.x) + n*M_PI;
+ candidates[0] = atan2(v2.x(), v1.x());
candidates[1] = candidates[0] + M_PI;
- candidates[2] = atan2(-normal.z(), normal.x() * normal.y()) + phi_x;
+ candidates[2] = atan2(v2.y(), v1.y());
candidates[3] = candidates[2] + M_PI;
- candidates[4] = atan2(normal.y(), -normal.x() * normal.z()) + phi_z;
+ candidates[4] = atan2(v2.z(), v1.z());
candidates[5] = candidates[4] + M_PI;
}
diff --git a/chromium/cc/animation/transform_operations.cc b/chromium/cc/animation/transform_operations.cc
index f8abe441fbf..34c526b9a40 100644
--- a/chromium/cc/animation/transform_operations.cc
+++ b/chromium/cc/animation/transform_operations.cc
@@ -6,6 +6,7 @@
#include <algorithm>
+#include "ui/gfx/animation/tween.h"
#include "ui/gfx/box_f.h"
#include "ui/gfx/transform_util.h"
#include "ui/gfx/vector3d_f.h"
@@ -60,7 +61,11 @@ bool TransformOperations::BlendedBoundsForBox(const gfx::BoxF& box,
size_t num_operations =
std::max(from_identity ? 0 : from.operations_.size(),
to_identity ? 0 : operations_.size());
- for (size_t i = 0; i < num_operations; ++i) {
+
+ // Because we are squashing all of the matrices together when applying
+ // them to the animation, we must apply them in reverse order when
+ // not squashing them.
+ for (int i = num_operations - 1; i >= 0; --i) {
gfx::BoxF bounds_for_operation;
const TransformOperation* from_op =
from_identity ? NULL : &from.operations_[i];
@@ -78,6 +83,100 @@ bool TransformOperations::BlendedBoundsForBox(const gfx::BoxF& box,
return true;
}
+bool TransformOperations::AffectsScale() const {
+ for (size_t i = 0; i < operations_.size(); ++i) {
+ if (operations_[i].type == TransformOperation::TransformOperationScale)
+ return true;
+ if (operations_[i].type == TransformOperation::TransformOperationMatrix &&
+ !operations_[i].matrix.IsIdentityOrTranslation())
+ return true;
+ }
+ return false;
+}
+
+bool TransformOperations::IsTranslation() const {
+ for (size_t i = 0; i < operations_.size(); ++i) {
+ switch (operations_[i].type) {
+ case TransformOperation::TransformOperationIdentity:
+ case TransformOperation::TransformOperationTranslate:
+ continue;
+ case TransformOperation::TransformOperationMatrix:
+ if (!operations_[i].matrix.IsIdentityOrTranslation())
+ return false;
+ continue;
+ case TransformOperation::TransformOperationRotate:
+ case TransformOperation::TransformOperationScale:
+ case TransformOperation::TransformOperationSkew:
+ case TransformOperation::TransformOperationPerspective:
+ return false;
+ }
+ }
+ return true;
+}
+
+bool TransformOperations::MaximumScale(const TransformOperations& from,
+ SkMScalar min_progress,
+ SkMScalar max_progress,
+ float* max_scale) const {
+ if (!MatchesTypes(from))
+ return false;
+
+ gfx::Vector3dF from_scale;
+ gfx::Vector3dF to_scale;
+
+ if (!from.ScaleComponent(&from_scale) || !ScaleComponent(&to_scale))
+ return false;
+
+ gfx::Vector3dF scale_at_min_progress(
+ std::abs(gfx::Tween::FloatValueBetween(
+ min_progress, from_scale.x(), to_scale.x())),
+ std::abs(gfx::Tween::FloatValueBetween(
+ min_progress, from_scale.y(), to_scale.y())),
+ std::abs(gfx::Tween::FloatValueBetween(
+ min_progress, from_scale.z(), to_scale.z())));
+ gfx::Vector3dF scale_at_max_progress(
+ std::abs(gfx::Tween::FloatValueBetween(
+ max_progress, from_scale.x(), to_scale.x())),
+ std::abs(gfx::Tween::FloatValueBetween(
+ max_progress, from_scale.y(), to_scale.y())),
+ std::abs(gfx::Tween::FloatValueBetween(
+ max_progress, from_scale.z(), to_scale.z())));
+
+ gfx::Vector3dF max_scale_3d = scale_at_min_progress;
+ max_scale_3d.SetToMax(scale_at_max_progress);
+ *max_scale =
+ std::max(max_scale_3d.x(), std::max(max_scale_3d.y(), max_scale_3d.z()));
+ return true;
+}
+
+bool TransformOperations::ScaleComponent(gfx::Vector3dF* scale) const {
+ *scale = gfx::Vector3dF(1.f, 1.f, 1.f);
+ bool has_scale_component = false;
+ for (size_t i = 0; i < operations_.size(); ++i) {
+ switch (operations_[i].type) {
+ case TransformOperation::TransformOperationIdentity:
+ case TransformOperation::TransformOperationTranslate:
+ continue;
+ case TransformOperation::TransformOperationMatrix:
+ if (!operations_[i].matrix.IsIdentityOrTranslation())
+ return false;
+ continue;
+ case TransformOperation::TransformOperationRotate:
+ case TransformOperation::TransformOperationSkew:
+ case TransformOperation::TransformOperationPerspective:
+ return false;
+ case TransformOperation::TransformOperationScale:
+ if (has_scale_component)
+ return false;
+ has_scale_component = true;
+ scale->Scale(operations_[i].scale.x,
+ operations_[i].scale.y,
+ operations_[i].scale.z);
+ }
+ }
+ return true;
+}
+
bool TransformOperations::MatchesTypes(const TransformOperations& other) const {
if (IsIdentity() || other.IsIdentity())
return true;
diff --git a/chromium/cc/animation/transform_operations.h b/chromium/cc/animation/transform_operations.h
index 7c509349092..f086eb1baac 100644
--- a/chromium/cc/animation/transform_operations.h
+++ b/chromium/cc/animation/transform_operations.h
@@ -57,6 +57,20 @@ class CC_EXPORT TransformOperations {
SkMScalar max_progress,
gfx::BoxF* bounds) const;
+ // Returns true if these operations affect scale.
+ bool AffectsScale() const;
+
+ // Returns true if these operations are only translations.
+ bool IsTranslation() const;
+
+ // Sets |max_scale| to be the maximum scale in any dimension when calling
+ // Blend on |from| with progress in the range [min_progress, max_progress]. If
+ // this maximum scale cannot be computed, returns false.
+ bool MaximumScale(const TransformOperations& from,
+ SkMScalar min_progress,
+ SkMScalar max_progress,
+ float* max_scale) const;
+
// Returns true if this operation and its descendants have the same types
// as other and its descendants.
bool MatchesTypes(const TransformOperations& other) const;
@@ -84,6 +98,11 @@ class CC_EXPORT TransformOperations {
bool ComputeDecomposedTransform() const;
+ // If these operations have no more than one scale operation, and if the only
+ // other operations are translations, sets |scale| to the scale component
+ // of these operations. Otherwise, returns false.
+ bool ScaleComponent(gfx::Vector3dF* scale) const;
+
// For efficiency, we cache the decomposed transform.
mutable scoped_ptr<gfx::DecomposedTransform> decomposed_transform_;
mutable bool decomposed_transform_dirty_;
diff --git a/chromium/cc/animation/transform_operations_unittest.cc b/chromium/cc/animation/transform_operations_unittest.cc
index 831ce71ce37..87dd69df122 100644
--- a/chromium/cc/animation/transform_operations_unittest.cc
+++ b/chromium/cc/animation/transform_operations_unittest.cc
@@ -1219,15 +1219,39 @@ TEST(TransformOperationTest, BlendedBoundsForSkew) {
}
}
+TEST(TransformOperationTest, NonCommutativeRotations) {
+ TransformOperations operations_from;
+ operations_from.AppendRotate(1.0, 0.0, 0.0, 0.0);
+ operations_from.AppendRotate(0.0, 1.0, 0.0, 0.0);
+ TransformOperations operations_to;
+ operations_to.AppendRotate(1.0, 0.0, 0.0, 45.0);
+ operations_to.AppendRotate(0.0, 1.0, 0.0, 135.0);
+
+ gfx::BoxF box(0, 0, 0, 1, 1, 1);
+ gfx::BoxF bounds;
+
+ SkMScalar min_progress = 0.0f;
+ SkMScalar max_progress = 1.0f;
+ EXPECT_TRUE(operations_to.BlendedBoundsForBox(
+ box, operations_from, min_progress, max_progress, &bounds));
+ gfx::Transform blended_transform =
+ operations_to.Blend(operations_from, max_progress);
+ gfx::Point3F blended_point(0.9f, 0.9f, 0.0f);
+ blended_transform.TransformPoint(&blended_point);
+ gfx::BoxF expanded_bounds = bounds;
+ expanded_bounds.ExpandTo(blended_point);
+ EXPECT_EQ(bounds.ToString(), expanded_bounds.ToString());
+}
+
TEST(TransformOperationTest, BlendedBoundsForSequence) {
TransformOperations operations_from;
- operations_from.AppendTranslate(2.0, 4.0, -1.0);
- operations_from.AppendScale(-1.0, 2.0, 3.0);
operations_from.AppendTranslate(1.0, -5.0, 1.0);
+ operations_from.AppendScale(-1.0, 2.0, 3.0);
+ operations_from.AppendTranslate(2.0, 4.0, -1.0);
TransformOperations operations_to;
- operations_to.AppendTranslate(6.0, -2.0, 3.0);
- operations_to.AppendScale(-3.0, -2.0, 5.0);
operations_to.AppendTranslate(13.0, -1.0, 5.0);
+ operations_to.AppendScale(-3.0, -2.0, 5.0);
+ operations_to.AppendTranslate(6.0, -2.0, 3.0);
gfx::BoxF box(1.f, 2.f, 3.f, 4.f, 4.f, 4.f);
gfx::BoxF bounds;
@@ -1258,5 +1282,252 @@ TEST(TransformOperationTest, BlendedBoundsForSequence) {
bounds.ToString());
}
+TEST(TransformOperationTest, AffectsScaleWithSingleOperation) {
+ TransformOperations empty_operations;
+ EXPECT_FALSE(empty_operations.AffectsScale());
+
+ TransformOperations identity;
+ identity.AppendIdentity();
+ EXPECT_FALSE(identity.AffectsScale());
+
+ TransformOperations translate;
+ translate.AppendTranslate(1.f, 2.f, 3.f);
+ EXPECT_FALSE(translate.AffectsScale());
+
+ TransformOperations rotate;
+ rotate.AppendRotate(1.f, 2.f, 3.f, 4.f);
+ EXPECT_FALSE(rotate.AffectsScale());
+
+ TransformOperations scale;
+ scale.AppendScale(1.f, 2.f, 3.f);
+ EXPECT_TRUE(scale.AffectsScale());
+
+ TransformOperations skew;
+ skew.AppendSkew(1.f, 2.f);
+ EXPECT_FALSE(skew.AffectsScale());
+
+ TransformOperations perspective;
+ perspective.AppendPerspective(1.f);
+ EXPECT_FALSE(perspective.AffectsScale());
+
+ TransformOperations identity_matrix;
+ identity_matrix.AppendMatrix(gfx::Transform());
+ EXPECT_FALSE(identity_matrix.AffectsScale());
+
+ TransformOperations translation_matrix;
+ gfx::Transform translation_transform;
+ translation_transform.Translate3d(1.f, 2.f, 3.f);
+ translation_matrix.AppendMatrix(translation_transform);
+ EXPECT_FALSE(translation_matrix.AffectsScale());
+
+ TransformOperations scaling_matrix;
+ gfx::Transform scaling_transform;
+ scaling_transform.Scale(2.f, 2.f);
+ scaling_matrix.AppendMatrix(scaling_transform);
+ EXPECT_TRUE(scaling_matrix.AffectsScale());
+}
+
+TEST(TransformOperationTest, AffectsScaleWithMultipleOperations) {
+ TransformOperations operations1;
+ operations1.AppendSkew(1.f, 2.f);
+ operations1.AppendTranslate(1.f, 2.f, 3.f);
+ operations1.AppendIdentity();
+ EXPECT_FALSE(operations1.AffectsScale());
+
+ TransformOperations operations2;
+ operations2.AppendPerspective(2.f);
+ operations2.AppendScale(1.f, 2.f, 3.f);
+ operations2.AppendTranslate(3.f, 2.f, 1.f);
+ EXPECT_TRUE(operations2.AffectsScale());
+}
+
+TEST(TransformOperationTest, IsTranslationWithSingleOperation) {
+ TransformOperations empty_operations;
+ EXPECT_TRUE(empty_operations.IsTranslation());
+
+ TransformOperations identity;
+ identity.AppendIdentity();
+ EXPECT_TRUE(identity.IsTranslation());
+
+ TransformOperations translate;
+ translate.AppendTranslate(1.f, 2.f, 3.f);
+ EXPECT_TRUE(translate.IsTranslation());
+
+ TransformOperations rotate;
+ rotate.AppendRotate(1.f, 2.f, 3.f, 4.f);
+ EXPECT_FALSE(rotate.IsTranslation());
+
+ TransformOperations scale;
+ scale.AppendScale(1.f, 2.f, 3.f);
+ EXPECT_FALSE(scale.IsTranslation());
+
+ TransformOperations skew;
+ skew.AppendSkew(1.f, 2.f);
+ EXPECT_FALSE(skew.IsTranslation());
+
+ TransformOperations perspective;
+ perspective.AppendPerspective(1.f);
+ EXPECT_FALSE(perspective.IsTranslation());
+
+ TransformOperations identity_matrix;
+ identity_matrix.AppendMatrix(gfx::Transform());
+ EXPECT_TRUE(identity_matrix.IsTranslation());
+
+ TransformOperations translation_matrix;
+ gfx::Transform translation_transform;
+ translation_transform.Translate3d(1.f, 2.f, 3.f);
+ translation_matrix.AppendMatrix(translation_transform);
+ EXPECT_TRUE(translation_matrix.IsTranslation());
+
+ TransformOperations scaling_matrix;
+ gfx::Transform scaling_transform;
+ scaling_transform.Scale(2.f, 2.f);
+ scaling_matrix.AppendMatrix(scaling_transform);
+ EXPECT_FALSE(scaling_matrix.IsTranslation());
+}
+
+TEST(TransformOperationTest, IsTranslationWithMultipleOperations) {
+ TransformOperations operations1;
+ operations1.AppendSkew(1.f, 2.f);
+ operations1.AppendTranslate(1.f, 2.f, 3.f);
+ operations1.AppendIdentity();
+ EXPECT_FALSE(operations1.IsTranslation());
+
+ TransformOperations operations2;
+ operations2.AppendIdentity();
+ operations2.AppendTranslate(3.f, 2.f, 1.f);
+ gfx::Transform translation_transform;
+ translation_transform.Translate3d(1.f, 2.f, 3.f);
+ operations2.AppendMatrix(translation_transform);
+ EXPECT_TRUE(operations2.IsTranslation());
+}
+
+TEST(TransformOperationTest, MaximumScale) {
+ TransformOperations operations1;
+ operations1.AppendScale(3.f, 2.f, 5.f);
+ TransformOperations operations2;
+ operations2.AppendScale(6.f, 5.f, 2.f);
+
+ float max_scale = 0.f;
+ EXPECT_TRUE(operations2.MaximumScale(operations1, 0.f, 1.f, &max_scale));
+ // x at progress 1.f
+ EXPECT_EQ(6.f, max_scale);
+
+ EXPECT_TRUE(operations2.MaximumScale(operations1, -1.f, 1.f, &max_scale));
+ // z at progress -1.f
+ EXPECT_EQ(8.f, max_scale);
+
+ EXPECT_TRUE(operations2.MaximumScale(operations1, 0.f, 2.f, &max_scale));
+ // x at progress 2.f
+ EXPECT_EQ(9.f, max_scale);
+
+ TransformOperations operations3;
+ operations3.AppendScale(1.f, 4.f, 1.f);
+ TransformOperations operations4;
+
+ EXPECT_TRUE(operations4.MaximumScale(operations3, 0.f, 1.f, &max_scale));
+ // y at progress 0.f
+ EXPECT_EQ(4.f, max_scale);
+
+ EXPECT_TRUE(operations4.MaximumScale(operations3, -1.f, 1.f, &max_scale));
+ // y at progress -1.f
+ EXPECT_EQ(7.f, max_scale);
+
+ EXPECT_TRUE(operations4.MaximumScale(operations3, 0.f, 2.f, &max_scale));
+ // y at progress 0.f
+ EXPECT_EQ(4.f, max_scale);
+
+ TransformOperations operations5;
+ operations5.AppendTranslate(1.f, 2.f, 3.f);
+ operations5.AppendScale(1.f, 1.f, 4.f);
+ gfx::Transform translation_transform;
+ translation_transform.Translate3d(1.f, 2.f, 3.f);
+ operations5.AppendMatrix(translation_transform);
+ TransformOperations operations6;
+ operations6.AppendTranslate(2.f, 3.f, 4.f);
+ operations6.AppendScale(2.f, 5.f, 1.f);
+ operations6.AppendMatrix(translation_transform);
+
+ EXPECT_TRUE(operations6.MaximumScale(operations5, 0.f, 1.f, &max_scale));
+ // y at progress 1.f
+ EXPECT_EQ(5.f, max_scale);
+
+ EXPECT_TRUE(operations6.MaximumScale(operations5, -1.f, 1.f, &max_scale));
+ // z at progress -1.f
+ EXPECT_EQ(7.f, max_scale);
+
+ EXPECT_TRUE(operations6.MaximumScale(operations5, 0.f, 2.f, &max_scale));
+ // y at progress 2.f
+ EXPECT_EQ(9.f, max_scale);
+}
+
+TEST(TransformOperationTest, MaximumScaleCannotBeComputed) {
+ TransformOperations operations1;
+ operations1.AppendScale(2.f, 2.f, 2.f);
+ TransformOperations operations2;
+ operations2.AppendTranslate(1.f, 2.f, 3.f);
+
+ float max_scale = 0.f;
+
+ // Non-matching operations.
+ EXPECT_FALSE(operations2.MaximumScale(operations1, 0.f, 1.f, &max_scale));
+
+ TransformOperations operations3;
+ operations3.AppendScale(2.f, 2.f, 2.f);
+ operations3.AppendTranslate(1.f, 2.f, 3.f);
+ operations3.AppendScale(3.f, 3.f, 3.f);
+ TransformOperations operations4;
+ operations4.AppendScale(4.f, 4.f, 4.f);
+ operations4.AppendTranslate(2.f, 3.f, 4.f);
+ operations4.AppendScale(5.f, 5.f, 5.f);
+
+ // More that one scale operation in a sequence.
+ EXPECT_FALSE(operations4.MaximumScale(operations3, 0.f, 1.f, &max_scale));
+
+ TransformOperations operations5;
+ operations5.AppendScale(2.f, 2.f, 2.f);
+ gfx::Transform scaling_transform;
+ scaling_transform.Scale(2.f, 2.f);
+ operations5.AppendMatrix(scaling_transform);
+ TransformOperations operations6;
+ operations6.AppendScale(3.f, 3.f, 3.f);
+ gfx::Transform translation_transform;
+ translation_transform.Translate3d(1.f, 2.f, 3.f);
+ operations6.AppendMatrix(translation_transform);
+
+ // Non-translation matrix operation.
+ EXPECT_FALSE(operations6.MaximumScale(operations5, 0.f, 1.f, &max_scale));
+
+ TransformOperations operations7;
+ operations7.AppendScale(2.f, 2.f, 2.f);
+ operations7.AppendRotate(1.f, 2.f, 3.f, 4.f);
+ TransformOperations operations8;
+ operations8.AppendScale(3.f, 3.f, 3.f);
+ operations8.AppendRotate(3.f, 4.f, 5.f, 6.f);
+
+ // Rotation operation.
+ EXPECT_FALSE(operations8.MaximumScale(operations7, 0.f, 1.f, &max_scale));
+
+ TransformOperations operations9;
+ operations9.AppendScale(2.f, 2.f, 2.f);
+ operations9.AppendSkew(1.f, 2.f);
+ TransformOperations operations10;
+ operations10.AppendScale(3.f, 3.f, 3.f);
+ operations10.AppendSkew(3.f, 4.f);
+
+ // Skew operation.
+ EXPECT_FALSE(operations10.MaximumScale(operations9, 0.f, 1.f, &max_scale));
+
+ TransformOperations operations11;
+ operations11.AppendScale(2.f, 2.f, 2.f);
+ operations11.AppendPerspective(1.f);
+ TransformOperations operations12;
+ operations12.AppendScale(3.f, 3.f, 3.f);
+ operations12.AppendPerspective(3.f);
+
+ // Perspective operation.
+ EXPECT_FALSE(operations12.MaximumScale(operations11, 0.f, 1.f, &max_scale));
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/base/completion_event.h b/chromium/cc/base/completion_event.h
index 759ce9c3a27..96ccf5417de 100644
--- a/chromium/cc/base/completion_event.h
+++ b/chromium/cc/base/completion_event.h
@@ -19,21 +19,21 @@ class CompletionEvent {
public:
CompletionEvent()
: event_(false /* manual_reset */, false /* initially_signaled */) {
-#ifndef NDEBUG
+#if DCHECK_IS_ON
waited_ = false;
signaled_ = false;
#endif
}
~CompletionEvent() {
-#ifndef NDEBUG
+#if DCHECK_IS_ON
DCHECK(waited_);
DCHECK(signaled_);
#endif
}
void Wait() {
-#ifndef NDEBUG
+#if DCHECK_IS_ON
DCHECK(!waited_);
waited_ = true;
#endif
@@ -42,7 +42,7 @@ class CompletionEvent {
}
void Signal() {
-#ifndef NDEBUG
+#if DCHECK_IS_ON
DCHECK(!signaled_);
signaled_ = true;
#endif
@@ -51,7 +51,7 @@ class CompletionEvent {
private:
base::WaitableEvent event_;
-#ifndef NDEBUG
+#if DCHECK_IS_ON
// Used to assert that Wait() and Signal() are each called exactly once.
bool waited_;
bool signaled_;
diff --git a/chromium/cc/base/delayed_unique_notifier.cc b/chromium/cc/base/delayed_unique_notifier.cc
new file mode 100644
index 00000000000..c2972677da6
--- /dev/null
+++ b/chromium/cc/base/delayed_unique_notifier.cc
@@ -0,0 +1,78 @@
+// 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/base/delayed_unique_notifier.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/location.h"
+#include "base/sequenced_task_runner.h"
+
+namespace cc {
+
+DelayedUniqueNotifier::DelayedUniqueNotifier(
+ base::SequencedTaskRunner* task_runner,
+ const base::Closure& closure,
+ const base::TimeDelta& delay)
+ : task_runner_(task_runner),
+ closure_(closure),
+ delay_(delay),
+ notification_pending_(false),
+ weak_ptr_factory_(this) {
+}
+
+DelayedUniqueNotifier::~DelayedUniqueNotifier() {
+}
+
+void DelayedUniqueNotifier::Schedule() {
+ if (notification_pending_) {
+ next_notification_time_ = Now() + delay_;
+ return;
+ }
+
+ next_notification_time_ = Now() + delay_;
+ task_runner_->PostDelayedTask(FROM_HERE,
+ base::Bind(&DelayedUniqueNotifier::NotifyIfTime,
+ weak_ptr_factory_.GetWeakPtr()),
+ delay_);
+ notification_pending_ = true;
+}
+
+void DelayedUniqueNotifier::Cancel() {
+ next_notification_time_ = base::TimeTicks();
+}
+
+bool DelayedUniqueNotifier::HasPendingNotification() const {
+ return notification_pending_ && !next_notification_time_.is_null();
+}
+
+base::TimeTicks DelayedUniqueNotifier::Now() const {
+ return base::TimeTicks::Now();
+}
+
+void DelayedUniqueNotifier::NotifyIfTime() {
+ // If next notifiaction time is not valid, then this schedule was canceled.
+ if (next_notification_time_.is_null()) {
+ notification_pending_ = false;
+ return;
+ }
+
+ // If the notification was rescheduled or arrived too early for any other
+ // reason, then post another task instead of running the callback.
+ base::TimeTicks now = Now();
+ if (next_notification_time_ > now) {
+ task_runner_->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&DelayedUniqueNotifier::NotifyIfTime,
+ weak_ptr_factory_.GetWeakPtr()),
+ next_notification_time_ - now);
+ return;
+ }
+
+ // Note the order here is important since closure might schedule another run.
+ notification_pending_ = false;
+ closure_.Run();
+}
+
+} // namespace cc
diff --git a/chromium/cc/base/delayed_unique_notifier.h b/chromium/cc/base/delayed_unique_notifier.h
new file mode 100644
index 00000000000..1f93416dd25
--- /dev/null
+++ b/chromium/cc/base/delayed_unique_notifier.h
@@ -0,0 +1,61 @@
+// 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_BASE_DELAYED_UNIQUE_NOTIFIER_H_
+#define CC_BASE_DELAYED_UNIQUE_NOTIFIER_H_
+
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "cc/base/cc_export.h"
+
+namespace base {
+class SequencedTaskRunner;
+} // namespace base
+
+namespace cc {
+
+class CC_EXPORT DelayedUniqueNotifier {
+ public:
+ // Configure this notifier to issue the |closure| notification in |delay| time
+ // from Schedule() call.
+ DelayedUniqueNotifier(base::SequencedTaskRunner* task_runner,
+ const base::Closure& closure,
+ const base::TimeDelta& delay);
+
+ // Destroying the notifier will ensure that no further notifications will
+ // happen from this class.
+ virtual ~DelayedUniqueNotifier();
+
+ // Schedule a notification to be run. If another notification is already
+ // pending, then it will happen in (at least) given delay from now. That is,
+ // if delay is 16ms and a notification has been scheduled 10ms ago (ie, it
+ // should trigger in no less than 6ms), then calling schedule will ensure that
+ // the only notification that arrives will happen in (at least) 16ms from now.
+ void Schedule();
+
+ // Cancel any previously scheduled runs.
+ void Cancel();
+
+ // Returns true if a notification is currently scheduled to run.
+ bool HasPendingNotification() const;
+
+ protected:
+ // Virtual for testing.
+ virtual base::TimeTicks Now() const;
+
+ private:
+ void NotifyIfTime();
+
+ base::SequencedTaskRunner* task_runner_;
+ base::Closure closure_;
+ base::TimeDelta delay_;
+ base::TimeTicks next_notification_time_;
+ bool notification_pending_;
+
+ base::WeakPtrFactory<DelayedUniqueNotifier> weak_ptr_factory_;
+};
+
+} // namespace cc
+
+#endif // CC_BASE_DELAYED_UNIQUE_NOTIFIER_H_
diff --git a/chromium/cc/base/delayed_unique_notifier_unittest.cc b/chromium/cc/base/delayed_unique_notifier_unittest.cc
new file mode 100644
index 00000000000..ffffe353db1
--- /dev/null
+++ b/chromium/cc/base/delayed_unique_notifier_unittest.cc
@@ -0,0 +1,266 @@
+// 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 <deque>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/test/test_pending_task.h"
+#include "base/test/test_simple_task_runner.h"
+#include "cc/base/delayed_unique_notifier.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+namespace {
+
+class TestNotifier : public DelayedUniqueNotifier {
+ public:
+ TestNotifier(base::SequencedTaskRunner* task_runner,
+ const base::Closure& closure,
+ const base::TimeDelta& delay)
+ : DelayedUniqueNotifier(task_runner, closure, delay) {}
+ virtual ~TestNotifier() {}
+
+ // Overridden from DelayedUniqueNotifier:
+ virtual base::TimeTicks Now() const OVERRIDE { return now_; }
+
+ void SetNow(base::TimeTicks now) { now_ = now; }
+
+ private:
+ base::TimeTicks now_;
+};
+
+class DelayedUniqueNotifierTest : public testing::Test {
+ public:
+ DelayedUniqueNotifierTest() : notification_count_(0) {}
+
+ virtual void SetUp() OVERRIDE {
+ notification_count_ = 0;
+ task_runner_ = make_scoped_refptr(new base::TestSimpleTaskRunner);
+ }
+
+ void Notify() { ++notification_count_; }
+
+ int NotificationCount() const { return notification_count_; }
+
+ std::deque<base::TestPendingTask> TakePendingTasks() {
+ std::deque<base::TestPendingTask> tasks = task_runner_->GetPendingTasks();
+ task_runner_->ClearPendingTasks();
+ return tasks;
+ }
+
+ protected:
+ int notification_count_;
+ scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
+};
+
+TEST_F(DelayedUniqueNotifierTest, ZeroDelay) {
+ base::TimeDelta delay = base::TimeDelta::FromInternalValue(0);
+ TestNotifier notifier(
+ task_runner_,
+ base::Bind(&DelayedUniqueNotifierTest::Notify, base::Unretained(this)),
+ delay);
+
+ EXPECT_EQ(0, NotificationCount());
+
+ // Basic schedule for |delay| from now.
+ base::TimeTicks schedule_time =
+ base::TimeTicks() + base::TimeDelta::FromInternalValue(10);
+
+ notifier.SetNow(schedule_time);
+ notifier.Schedule();
+
+ std::deque<base::TestPendingTask> tasks = TakePendingTasks();
+ ASSERT_EQ(1u, tasks.size());
+ EXPECT_EQ(base::TimeTicks() + delay, tasks[0].GetTimeToRun());
+
+ tasks[0].task.Run();
+ EXPECT_EQ(1, NotificationCount());
+
+ // 5 schedules should result in only one run.
+ for (int i = 0; i < 5; ++i)
+ notifier.Schedule();
+
+ tasks = TakePendingTasks();
+ ASSERT_EQ(1u, tasks.size());
+ EXPECT_EQ(base::TimeTicks() + delay, tasks[0].GetTimeToRun());
+
+ tasks[0].task.Run();
+ EXPECT_EQ(2, NotificationCount());
+}
+
+TEST_F(DelayedUniqueNotifierTest, SmallDelay) {
+ base::TimeDelta delay = base::TimeDelta::FromInternalValue(20);
+ TestNotifier notifier(
+ task_runner_,
+ base::Bind(&DelayedUniqueNotifierTest::Notify, base::Unretained(this)),
+ delay);
+
+ EXPECT_EQ(0, NotificationCount());
+
+ // Basic schedule for |delay| from now (now: 30, run time: 50).
+ base::TimeTicks schedule_time =
+ base::TimeTicks() + base::TimeDelta::FromInternalValue(30);
+
+ notifier.SetNow(schedule_time);
+ notifier.Schedule();
+
+ std::deque<base::TestPendingTask> tasks = TakePendingTasks();
+
+ ASSERT_EQ(1u, tasks.size());
+ EXPECT_EQ(base::TimeTicks() + delay, tasks[0].GetTimeToRun());
+
+ // It's not yet time to run, so we expect no notifications.
+ tasks[0].task.Run();
+ EXPECT_EQ(0, NotificationCount());
+
+ tasks = TakePendingTasks();
+
+ ASSERT_EQ(1u, tasks.size());
+ // Now the time should be delay minus whatever the value of now happens to be
+ // (now: 30, run time: 50).
+ base::TimeTicks scheduled_run_time = notifier.Now() + delay;
+ base::TimeTicks scheduled_delay =
+ base::TimeTicks() + (scheduled_run_time - notifier.Now());
+ EXPECT_EQ(scheduled_delay, tasks[0].GetTimeToRun());
+
+ // Move closer to the run time (time: 49, run time: 50).
+ notifier.SetNow(notifier.Now() + base::TimeDelta::FromInternalValue(19));
+
+ // It's not yet time to run, so we expect no notifications.
+ tasks[0].task.Run();
+ EXPECT_EQ(0, NotificationCount());
+
+ tasks = TakePendingTasks();
+ ASSERT_EQ(1u, tasks.size());
+
+ // Now the time should be delay minus whatever the value of now happens to be.
+ scheduled_delay = base::TimeTicks() + (scheduled_run_time - notifier.Now());
+ EXPECT_EQ(scheduled_delay, tasks[0].GetTimeToRun());
+
+ // Move to exactly the run time (time: 50, run time: 50).
+ notifier.SetNow(notifier.Now() + base::TimeDelta::FromInternalValue(1));
+
+ // It's time to run!
+ tasks[0].task.Run();
+ EXPECT_EQ(1, NotificationCount());
+
+ tasks = TakePendingTasks();
+ EXPECT_EQ(0u, tasks.size());
+}
+
+TEST_F(DelayedUniqueNotifierTest, RescheduleDelay) {
+ base::TimeDelta delay = base::TimeDelta::FromInternalValue(20);
+ TestNotifier notifier(
+ task_runner_,
+ base::Bind(&DelayedUniqueNotifierTest::Notify, base::Unretained(this)),
+ delay);
+
+ base::TimeTicks schedule_time;
+ // Move time 19 units forward and reschedule, expecting that we still need to
+ // run in |delay| time and we don't get a notification.
+ for (int i = 0; i < 10; ++i) {
+ EXPECT_EQ(0, NotificationCount());
+
+ // Move time forward 19 units.
+ schedule_time = notifier.Now() + base::TimeDelta::FromInternalValue(19);
+ notifier.SetNow(schedule_time);
+ notifier.Schedule();
+
+ std::deque<base::TestPendingTask> tasks = TakePendingTasks();
+
+ ASSERT_EQ(1u, tasks.size());
+ EXPECT_EQ(base::TimeTicks() + delay, tasks[0].GetTimeToRun());
+
+ // It's not yet time to run, so we expect no notifications.
+ tasks[0].task.Run();
+ EXPECT_EQ(0, NotificationCount());
+ }
+
+ // Move time forward 20 units, expecting a notification.
+ schedule_time = notifier.Now() + base::TimeDelta::FromInternalValue(20);
+ notifier.SetNow(schedule_time);
+
+ std::deque<base::TestPendingTask> tasks = TakePendingTasks();
+
+ ASSERT_EQ(1u, tasks.size());
+ EXPECT_EQ(base::TimeTicks() + delay, tasks[0].GetTimeToRun());
+
+ // Time to run!
+ tasks[0].task.Run();
+ EXPECT_EQ(1, NotificationCount());
+}
+
+TEST_F(DelayedUniqueNotifierTest, CancelAndHasPendingNotification) {
+ base::TimeDelta delay = base::TimeDelta::FromInternalValue(20);
+ TestNotifier notifier(
+ task_runner_,
+ base::Bind(&DelayedUniqueNotifierTest::Notify, base::Unretained(this)),
+ delay);
+
+ EXPECT_EQ(0, NotificationCount());
+
+ // Schedule for |delay| seconds from now.
+ base::TimeTicks schedule_time =
+ notifier.Now() + base::TimeDelta::FromInternalValue(10);
+ notifier.SetNow(schedule_time);
+ notifier.Schedule();
+ EXPECT_TRUE(notifier.HasPendingNotification());
+
+ // Cancel the run.
+ notifier.Cancel();
+ EXPECT_FALSE(notifier.HasPendingNotification());
+
+ std::deque<base::TestPendingTask> tasks = TakePendingTasks();
+
+ ASSERT_EQ(1u, tasks.size());
+ EXPECT_EQ(base::TimeTicks() + delay, tasks[0].GetTimeToRun());
+
+ // Time to run, but a canceled task!
+ tasks[0].task.Run();
+ EXPECT_EQ(0, NotificationCount());
+ EXPECT_FALSE(notifier.HasPendingNotification());
+
+ tasks = TakePendingTasks();
+ EXPECT_EQ(0u, tasks.size());
+
+ notifier.Schedule();
+ EXPECT_TRUE(notifier.HasPendingNotification());
+ tasks = TakePendingTasks();
+
+ ASSERT_EQ(1u, tasks.size());
+ EXPECT_EQ(base::TimeTicks() + delay, tasks[0].GetTimeToRun());
+
+ // Advance the time.
+ notifier.SetNow(notifier.Now() + delay);
+
+ // This should run since it wasn't canceled.
+ tasks[0].task.Run();
+ EXPECT_EQ(1, NotificationCount());
+ EXPECT_FALSE(notifier.HasPendingNotification());
+
+ for (int i = 0; i < 10; ++i) {
+ notifier.Schedule();
+ EXPECT_TRUE(notifier.HasPendingNotification());
+ notifier.Cancel();
+ EXPECT_FALSE(notifier.HasPendingNotification());
+ }
+
+ tasks = TakePendingTasks();
+
+ ASSERT_EQ(1u, tasks.size());
+ EXPECT_EQ(base::TimeTicks() + delay, tasks[0].GetTimeToRun());
+
+ // Time to run, but a canceled task!
+ notifier.SetNow(notifier.Now() + delay);
+ tasks[0].task.Run();
+ EXPECT_EQ(1, NotificationCount());
+
+ tasks = TakePendingTasks();
+ EXPECT_EQ(0u, tasks.size());
+ EXPECT_FALSE(notifier.HasPendingNotification());
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/base/invalidation_region.cc b/chromium/cc/base/invalidation_region.cc
index 6a8f97f78fe..5fbca8d1d18 100644
--- a/chromium/cc/base/invalidation_region.cc
+++ b/chromium/cc/base/invalidation_region.cc
@@ -26,7 +26,7 @@ void InvalidationRegion::Clear() {
region_.Clear();
}
-void InvalidationRegion::Union(gfx::Rect rect) {
+void InvalidationRegion::Union(const gfx::Rect& rect) {
region_.Union(rect);
SimplifyIfNeeded();
}
diff --git a/chromium/cc/base/invalidation_region.h b/chromium/cc/base/invalidation_region.h
index 33be80332ff..9cb2fe386e4 100644
--- a/chromium/cc/base/invalidation_region.h
+++ b/chromium/cc/base/invalidation_region.h
@@ -21,7 +21,7 @@ class CC_EXPORT InvalidationRegion {
void Swap(Region* region);
void Clear();
- void Union(gfx::Rect rect);
+ void Union(const gfx::Rect& rect);
bool IsEmpty() const { return region_.IsEmpty(); }
private:
diff --git a/chromium/cc/base/latency_info_swap_promise.cc b/chromium/cc/base/latency_info_swap_promise.cc
index 41c0e997d11..cc2f1c10292 100644
--- a/chromium/cc/base/latency_info_swap_promise.cc
+++ b/chromium/cc/base/latency_info_swap_promise.cc
@@ -34,9 +34,7 @@ LatencyInfoSwapPromise::~LatencyInfoSwapPromise() {
void LatencyInfoSwapPromise::DidSwap(CompositorFrameMetadata* metadata) {
DCHECK(!latency_.terminated);
- // TODO(miletus): Append the |latency_| into metadata's LatencyInfo list
- // once we remove LatencyInfo merge in GPU side.
- metadata->latency_info.MergeWith(latency_);
+ metadata->latency_info.push_back(latency_);
}
void LatencyInfoSwapPromise::DidNotSwap(DidNotSwapReason reason) {
diff --git a/chromium/cc/base/math_util.cc b/chromium/cc/base/math_util.cc
index 7a1bc1a8674..a619b50698b 100644
--- a/chromium/cc/base/math_util.cc
+++ b/chromium/cc/base/math_util.cc
@@ -23,7 +23,7 @@ const float MathUtil::kPiFloat = 3.14159265358979323846f;
static HomogeneousCoordinate ProjectHomogeneousPoint(
const gfx::Transform& transform,
- gfx::PointF p) {
+ const gfx::PointF& p) {
// In this case, the layer we are trying to project onto is perpendicular to
// ray (point p and z-axis direction) that we are trying to project. This
// happens when the layer is rotated so that it is infinitesimally thin, or
@@ -41,6 +41,15 @@ static HomogeneousCoordinate ProjectHomogeneousPoint(
return result;
}
+static HomogeneousCoordinate ProjectHomogeneousPoint(
+ const gfx::Transform& transform,
+ const gfx::PointF& p,
+ bool* clipped) {
+ HomogeneousCoordinate h = ProjectHomogeneousPoint(transform, p);
+ *clipped = h.w() <= 0;
+ return h;
+}
+
static HomogeneousCoordinate MapHomogeneousPoint(
const gfx::Transform& transform,
const gfx::Point3F& p) {
@@ -87,22 +96,29 @@ static inline void ExpandBoundsToIncludePoint(float* xmin,
float* xmax,
float* ymin,
float* ymax,
- gfx::PointF p) {
+ const gfx::PointF& p) {
*xmin = std::min(p.x(), *xmin);
*xmax = std::max(p.x(), *xmax);
*ymin = std::min(p.y(), *ymin);
*ymax = std::max(p.y(), *ymax);
}
-static inline void AddVertexToClippedQuad(gfx::PointF new_vertex,
+static inline void AddVertexToClippedQuad(const gfx::PointF& new_vertex,
gfx::PointF clipped_quad[8],
int* num_vertices_in_clipped_quad) {
clipped_quad[*num_vertices_in_clipped_quad] = new_vertex;
(*num_vertices_in_clipped_quad)++;
}
-gfx::Rect MathUtil::MapClippedRect(const gfx::Transform& transform,
- gfx::Rect src_rect) {
+gfx::Rect MathUtil::MapEnclosingClippedRect(const gfx::Transform& transform,
+ const gfx::Rect& src_rect) {
+ if (transform.IsIdentityOrIntegerTranslation()) {
+ return src_rect +
+ gfx::Vector2d(
+ static_cast<int>(SkMScalarToFloat(transform.matrix().get(0, 3))),
+ static_cast<int>(
+ SkMScalarToFloat(transform.matrix().get(1, 3))));
+ }
return gfx::ToEnclosingRect(MapClippedRect(transform, gfx::RectF(src_rect)));
}
@@ -136,6 +152,19 @@ gfx::RectF MathUtil::MapClippedRect(const gfx::Transform& transform,
return ComputeEnclosingClippedRect(hc0, hc1, hc2, hc3);
}
+gfx::Rect MathUtil::ProjectEnclosingClippedRect(const gfx::Transform& transform,
+ const gfx::Rect& src_rect) {
+ if (transform.IsIdentityOrIntegerTranslation()) {
+ return src_rect +
+ gfx::Vector2d(
+ static_cast<int>(SkMScalarToFloat(transform.matrix().get(0, 3))),
+ static_cast<int>(
+ SkMScalarToFloat(transform.matrix().get(1, 3))));
+ }
+ return gfx::ToEnclosingRect(
+ ProjectClippedRect(transform, gfx::RectF(src_rect)));
+}
+
gfx::RectF MathUtil::ProjectClippedRect(const gfx::Transform& transform,
const gfx::RectF& src_rect) {
if (transform.IsIdentityOrTranslation()) {
@@ -223,8 +252,9 @@ void MathUtil::MapClippedQuad(const gfx::Transform& transform,
DCHECK_LE(*num_vertices_in_clipped_quad, 8);
}
-gfx::RectF MathUtil::ComputeEnclosingRectOfVertices(gfx::PointF vertices[],
- int num_vertices) {
+gfx::RectF MathUtil::ComputeEnclosingRectOfVertices(
+ const gfx::PointF vertices[],
+ int num_vertices) {
if (num_vertices < 2)
return gfx::RectF();
@@ -356,7 +386,7 @@ gfx::QuadF MathUtil::MapQuad(const gfx::Transform& transform,
}
gfx::PointF MathUtil::MapPoint(const gfx::Transform& transform,
- gfx::PointF p,
+ const gfx::PointF& p,
bool* clipped) {
HomogeneousCoordinate h = MapHomogeneousPoint(transform, gfx::Point3F(p));
@@ -421,30 +451,29 @@ gfx::QuadF MathUtil::ProjectQuad(const gfx::Transform& transform,
}
gfx::PointF MathUtil::ProjectPoint(const gfx::Transform& transform,
- gfx::PointF p,
+ const gfx::PointF& p,
bool* clipped) {
- HomogeneousCoordinate h = ProjectHomogeneousPoint(transform, p);
-
- if (h.w() > 0) {
- // The cartesian coordinates will be valid in this case.
- *clipped = false;
- return h.CartesianPoint2d();
- }
-
- // The cartesian coordinates will be invalid after dividing by w.
- *clipped = true;
-
+ HomogeneousCoordinate h = ProjectHomogeneousPoint(transform, p, clipped);
// Avoid dividing by w if w == 0.
if (!h.w())
return gfx::PointF();
- // This return value will be invalid because clipped == true, but (1) users of
+ // This return value will be invalid if clipped == true, but (1) users of
// this code should be ignoring the return value when clipped == true anyway,
// and (2) this behavior is more consistent with existing behavior of WebKit
// transforms if the user really does not ignore the return value.
return h.CartesianPoint2d();
}
+gfx::Point3F MathUtil::ProjectPoint3D(const gfx::Transform& transform,
+ const gfx::PointF& p,
+ bool* clipped) {
+ HomogeneousCoordinate h = ProjectHomogeneousPoint(transform, p, clipped);
+ if (!h.w())
+ return gfx::Point3F();
+ return h.CartesianPoint3d();
+}
+
gfx::RectF MathUtil::ScaleRectProportional(const gfx::RectF& input_outer_rect,
const gfx::RectF& scale_outer_rect,
const gfx::RectF& scale_inner_rect) {
@@ -465,13 +494,17 @@ gfx::RectF MathUtil::ScaleRectProportional(const gfx::RectF& input_outer_rect,
return output_inner_rect;
}
+static inline bool NearlyZero(double value) {
+ return std::abs(value) < std::numeric_limits<double>::epsilon();
+}
+
static inline float ScaleOnAxis(double a, double b, double c) {
- if (!b && !c)
- return a;
- if (!a && !c)
- return b;
- if (!a && !b)
- return c;
+ if (NearlyZero(b) && NearlyZero(c))
+ return std::abs(a);
+ if (NearlyZero(a) && NearlyZero(c))
+ return std::abs(b);
+ if (NearlyZero(a) && NearlyZero(b))
+ return std::abs(c);
// Do the sqrt as a double to not lose precision.
return static_cast<float>(std::sqrt(a * a + b * b + c * c));
@@ -491,37 +524,37 @@ gfx::Vector2dF MathUtil::ComputeTransform2dScaleComponents(
return gfx::Vector2dF(x_scale, y_scale);
}
-float MathUtil::SmallestAngleBetweenVectors(gfx::Vector2dF v1,
- gfx::Vector2dF v2) {
+float MathUtil::SmallestAngleBetweenVectors(const gfx::Vector2dF& v1,
+ const gfx::Vector2dF& v2) {
double dot_product = gfx::DotProduct(v1, v2) / v1.Length() / v2.Length();
// Clamp to compensate for rounding errors.
dot_product = std::max(-1.0, std::min(1.0, dot_product));
return static_cast<float>(Rad2Deg(std::acos(dot_product)));
}
-gfx::Vector2dF MathUtil::ProjectVector(gfx::Vector2dF source,
- gfx::Vector2dF destination) {
+gfx::Vector2dF MathUtil::ProjectVector(const gfx::Vector2dF& source,
+ const gfx::Vector2dF& destination) {
float projected_length =
gfx::DotProduct(source, destination) / destination.LengthSquared();
return gfx::Vector2dF(projected_length * destination.x(),
projected_length * destination.y());
}
-scoped_ptr<base::Value> MathUtil::AsValue(gfx::Size s) {
+scoped_ptr<base::Value> MathUtil::AsValue(const gfx::Size& s) {
scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue());
res->SetDouble("width", s.width());
res->SetDouble("height", s.height());
return res.PassAs<base::Value>();
}
-scoped_ptr<base::Value> MathUtil::AsValue(gfx::SizeF s) {
+scoped_ptr<base::Value> MathUtil::AsValue(const gfx::SizeF& s) {
scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue());
res->SetDouble("width", s.width());
res->SetDouble("height", s.height());
return res.PassAs<base::Value>();
}
-scoped_ptr<base::Value> MathUtil::AsValue(gfx::Rect r) {
+scoped_ptr<base::Value> MathUtil::AsValue(const gfx::Rect& r) {
scoped_ptr<base::ListValue> res(new base::ListValue());
res->AppendInteger(r.x());
res->AppendInteger(r.y());
@@ -551,13 +584,28 @@ bool MathUtil::FromValue(const base::Value* raw_value, gfx::Rect* out_rect) {
return true;
}
-scoped_ptr<base::Value> MathUtil::AsValue(gfx::PointF pt) {
+scoped_ptr<base::Value> MathUtil::AsValue(const gfx::PointF& pt) {
scoped_ptr<base::ListValue> res(new base::ListValue());
res->AppendDouble(pt.x());
res->AppendDouble(pt.y());
return res.PassAs<base::Value>();
}
+scoped_ptr<base::Value> MathUtil::AsValue(const gfx::Point3F& pt) {
+ scoped_ptr<base::ListValue> res(new base::ListValue());
+ res->AppendDouble(pt.x());
+ res->AppendDouble(pt.y());
+ res->AppendDouble(pt.z());
+ return res.PassAs<base::Value>();
+}
+
+scoped_ptr<base::Value> MathUtil::AsValue(const gfx::Vector2d& v) {
+ scoped_ptr<base::ListValue> res(new base::ListValue());
+ res->AppendInteger(v.x());
+ res->AppendInteger(v.y());
+ return res.PassAs<base::Value>();
+}
+
scoped_ptr<base::Value> MathUtil::AsValue(const gfx::QuadF& q) {
scoped_ptr<base::ListValue> res(new base::ListValue());
res->AppendDouble(q.p1().x());
diff --git a/chromium/cc/base/math_util.h b/chromium/cc/base/math_util.h
index baceb7058fe..3af21021520 100644
--- a/chromium/cc/base/math_util.h
+++ b/chromium/cc/base/math_util.h
@@ -25,6 +25,7 @@ class Rect;
class RectF;
class Transform;
class Vector2dF;
+class Vector2d;
}
namespace cc {
@@ -99,10 +100,12 @@ class CC_EXPORT MathUtil {
//
// These functions return the axis-aligned rect that encloses the correctly
// clipped, transformed polygon.
- static gfx::Rect MapClippedRect(const gfx::Transform& transform,
- gfx::Rect rect);
+ static gfx::Rect MapEnclosingClippedRect(const gfx::Transform& transform,
+ const gfx::Rect& rect);
static gfx::RectF MapClippedRect(const gfx::Transform& transform,
const gfx::RectF& rect);
+ static gfx::Rect ProjectEnclosingClippedRect(const gfx::Transform& transform,
+ const gfx::Rect& rect);
static gfx::RectF ProjectClippedRect(const gfx::Transform& transform,
const gfx::RectF& rect);
@@ -116,7 +119,7 @@ class CC_EXPORT MathUtil {
gfx::PointF clipped_quad[8],
int* num_vertices_in_clipped_quad);
- static gfx::RectF ComputeEnclosingRectOfVertices(gfx::PointF vertices[],
+ static gfx::RectF ComputeEnclosingRectOfVertices(const gfx::PointF vertices[],
int num_vertices);
static gfx::RectF ComputeEnclosingClippedRect(
const HomogeneousCoordinate& h1,
@@ -130,7 +133,7 @@ class CC_EXPORT MathUtil {
const gfx::QuadF& quad,
bool* clipped);
static gfx::PointF MapPoint(const gfx::Transform& transform,
- gfx::PointF point,
+ const gfx::PointF& point,
bool* clipped);
static gfx::Point3F MapPoint(const gfx::Transform&,
const gfx::Point3F&,
@@ -139,8 +142,13 @@ class CC_EXPORT MathUtil {
const gfx::QuadF& quad,
bool* clipped);
static gfx::PointF ProjectPoint(const gfx::Transform& transform,
- gfx::PointF point,
+ const gfx::PointF& point,
bool* clipped);
+ // Identical to the above function, but coerces the homogeneous coordinate to
+ // a 3d rather than a 2d point.
+ static gfx::Point3F ProjectPoint3D(const gfx::Transform& transform,
+ const gfx::PointF& point,
+ bool* clipped);
static gfx::Vector2dF ComputeTransform2dScaleComponents(const gfx::Transform&,
float fallbackValue);
@@ -156,20 +164,22 @@ class CC_EXPORT MathUtil {
// Returns the smallest angle between the given two vectors in degrees.
// Neither vector is assumed to be normalized.
- static float SmallestAngleBetweenVectors(gfx::Vector2dF v1,
- gfx::Vector2dF v2);
+ static float SmallestAngleBetweenVectors(const gfx::Vector2dF& v1,
+ const gfx::Vector2dF& v2);
// Projects the |source| vector onto |destination|. Neither vector is assumed
// to be normalized.
- static gfx::Vector2dF ProjectVector(gfx::Vector2dF source,
- gfx::Vector2dF destination);
+ static gfx::Vector2dF ProjectVector(const gfx::Vector2dF& source,
+ const gfx::Vector2dF& destination);
// Conversion to value.
- static scoped_ptr<base::Value> AsValue(gfx::Size s);
- static scoped_ptr<base::Value> AsValue(gfx::SizeF s);
- static scoped_ptr<base::Value> AsValue(gfx::Rect r);
+ static scoped_ptr<base::Value> AsValue(const gfx::Size& s);
+ static scoped_ptr<base::Value> AsValue(const gfx::SizeF& s);
+ static scoped_ptr<base::Value> AsValue(const gfx::Rect& r);
static bool FromValue(const base::Value*, gfx::Rect* out_rect);
- static scoped_ptr<base::Value> AsValue(gfx::PointF q);
+ static scoped_ptr<base::Value> AsValue(const gfx::PointF& q);
+ static scoped_ptr<base::Value> AsValue(const gfx::Point3F&);
+ static scoped_ptr<base::Value> AsValue(const gfx::Vector2d& v);
static scoped_ptr<base::Value> AsValue(const gfx::QuadF& q);
static scoped_ptr<base::Value> AsValue(const gfx::RectF& rect);
static scoped_ptr<base::Value> AsValue(const gfx::Transform& transform);
diff --git a/chromium/cc/base/region.cc b/chromium/cc/base/region.cc
index 1cda32d3ba2..906bc6e3c9d 100644
--- a/chromium/cc/base/region.cc
+++ b/chromium/cc/base/region.cc
@@ -14,14 +14,14 @@ Region::Region(const Region& region)
: skregion_(region.skregion_) {
}
-Region::Region(gfx::Rect rect)
+Region::Region(const gfx::Rect& rect)
: skregion_(gfx::RectToSkIRect(rect)) {
}
Region::~Region() {
}
-const Region& Region::operator=(gfx::Rect rect) {
+const Region& Region::operator=(const gfx::Rect& rect) {
skregion_ = SkRegion(gfx::RectToSkIRect(rect));
return *this;
}
@@ -47,11 +47,11 @@ int Region::GetRegionComplexity() const {
return skregion_.computeRegionComplexity();
}
-bool Region::Contains(gfx::Point point) const {
+bool Region::Contains(const gfx::Point& point) const {
return skregion_.contains(point.x(), point.y());
}
-bool Region::Contains(gfx::Rect rect) const {
+bool Region::Contains(const gfx::Rect& rect) const {
if (rect.IsEmpty())
return true;
return skregion_.contains(gfx::RectToSkIRect(rect));
@@ -63,7 +63,7 @@ bool Region::Contains(const Region& region) const {
return skregion_.contains(region.skregion_);
}
-bool Region::Intersects(gfx::Rect rect) const {
+bool Region::Intersects(const gfx::Rect& rect) const {
return skregion_.intersects(gfx::RectToSkIRect(rect));
}
@@ -71,7 +71,7 @@ bool Region::Intersects(const Region& region) const {
return skregion_.intersects(region.skregion_);
}
-void Region::Subtract(gfx::Rect rect) {
+void Region::Subtract(const gfx::Rect& rect) {
skregion_.op(gfx::RectToSkIRect(rect), SkRegion::kDifference_Op);
}
@@ -79,7 +79,7 @@ void Region::Subtract(const Region& region) {
skregion_.op(region.skregion_, SkRegion::kDifference_Op);
}
-void Region::Union(gfx::Rect rect) {
+void Region::Union(const gfx::Rect& rect) {
skregion_.op(gfx::RectToSkIRect(rect), SkRegion::kUnion_Op);
}
@@ -87,7 +87,7 @@ void Region::Union(const Region& region) {
skregion_.op(region.skregion_, SkRegion::kUnion_Op);
}
-void Region::Intersect(gfx::Rect rect) {
+void Region::Intersect(const gfx::Rect& rect) {
skregion_.op(gfx::RectToSkIRect(rect), SkRegion::kIntersect_Op);
}
diff --git a/chromium/cc/base/region.h b/chromium/cc/base/region.h
index 26c1d2b1990..06fe7312ff6 100644
--- a/chromium/cc/base/region.h
+++ b/chromium/cc/base/region.h
@@ -24,10 +24,10 @@ class CC_EXPORT Region {
public:
Region();
Region(const Region& region);
- Region(gfx::Rect rect); // NOLINT(runtime/explicit)
+ Region(const gfx::Rect& rect); // NOLINT(runtime/explicit)
~Region();
- const Region& operator=(gfx::Rect rect);
+ const Region& operator=(const gfx::Rect& rect);
const Region& operator=(const Region& region);
void Swap(Region* region);
@@ -35,18 +35,18 @@ class CC_EXPORT Region {
bool IsEmpty() const;
int GetRegionComplexity() const;
- bool Contains(gfx::Point point) const;
- bool Contains(gfx::Rect rect) const;
+ bool Contains(const gfx::Point& point) const;
+ bool Contains(const gfx::Rect& rect) const;
bool Contains(const Region& region) const;
- bool Intersects(gfx::Rect rect) const;
+ bool Intersects(const gfx::Rect& rect) const;
bool Intersects(const Region& region) const;
- void Subtract(gfx::Rect rect);
+ void Subtract(const gfx::Rect& rect);
void Subtract(const Region& region);
- void Union(gfx::Rect rect);
+ void Union(const gfx::Rect& rect);
void Union(const Region& region);
- void Intersect(gfx::Rect rect);
+ void Intersect(const gfx::Rect& rect);
void Intersect(const Region& region);
bool Equals(const Region& other) const {
@@ -100,7 +100,7 @@ inline Region SubtractRegions(const Region& a, const Region& b) {
return result;
}
-inline Region SubtractRegions(const Region& a, gfx::Rect b) {
+inline Region SubtractRegions(const Region& a, const gfx::Rect& b) {
Region result = a;
result.Subtract(b);
return result;
@@ -112,7 +112,7 @@ inline Region IntersectRegions(const Region& a, const Region& b) {
return result;
}
-inline Region IntersectRegions(const Region& a, gfx::Rect b) {
+inline Region IntersectRegions(const Region& a, const gfx::Rect& b) {
Region result = a;
result.Intersect(b);
return result;
@@ -124,7 +124,7 @@ inline Region UnionRegions(const Region& a, const Region& b) {
return result;
}
-inline Region UnionRegions(const Region& a, gfx::Rect b) {
+inline Region UnionRegions(const Region& a, const gfx::Rect& b) {
Region result = a;
result.Union(b);
return result;
diff --git a/chromium/cc/scheduler/rolling_time_delta_history.cc b/chromium/cc/base/rolling_time_delta_history.cc
index 8d8bba5032f..db04f586b0b 100644
--- a/chromium/cc/scheduler/rolling_time_delta_history.cc
+++ b/chromium/cc/base/rolling_time_delta_history.cc
@@ -1,19 +1,17 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
+// 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 <cmath>
-#include "cc/scheduler/rolling_time_delta_history.h"
+#include "cc/base/rolling_time_delta_history.h"
namespace cc {
RollingTimeDeltaHistory::RollingTimeDeltaHistory(size_t max_size)
- : max_size_(max_size) {
-}
+ : max_size_(max_size) {}
-RollingTimeDeltaHistory::~RollingTimeDeltaHistory() {
-}
+RollingTimeDeltaHistory::~RollingTimeDeltaHistory() {}
void RollingTimeDeltaHistory::InsertSample(base::TimeDelta time) {
if (max_size_ == 0)
diff --git a/chromium/cc/scheduler/rolling_time_delta_history.h b/chromium/cc/base/rolling_time_delta_history.h
index b79862d6dae..e51fb86ba96 100644
--- a/chromium/cc/scheduler/rolling_time_delta_history.h
+++ b/chromium/cc/base/rolling_time_delta_history.h
@@ -1,9 +1,9 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
+// 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_SCHEDULER_ROLLING_TIME_DELTA_HISTORY_H_
-#define CC_SCHEDULER_ROLLING_TIME_DELTA_HISTORY_H_
+#ifndef CC_BASE_ROLLING_TIME_DELTA_HISTORY_H_
+#define CC_BASE_ROLLING_TIME_DELTA_HISTORY_H_
#include <deque>
#include <set>
@@ -41,4 +41,4 @@ class CC_EXPORT RollingTimeDeltaHistory {
} // namespace cc
-#endif // CC_SCHEDULER_ROLLING_TIME_DELTA_HISTORY_H_
+#endif // CC_BASE_ROLLING_TIME_DELTA_HISTORY_H_
diff --git a/chromium/cc/scheduler/rolling_time_delta_history_unittest.cc b/chromium/cc/base/rolling_time_delta_history_unittest.cc
index 072c98ab386..5458240bc7b 100644
--- a/chromium/cc/scheduler/rolling_time_delta_history_unittest.cc
+++ b/chromium/cc/base/rolling_time_delta_history_unittest.cc
@@ -1,8 +1,8 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
+// 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/scheduler/rolling_time_delta_history.h"
+#include "cc/base/rolling_time_delta_history.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace cc {
diff --git a/chromium/cc/base/switches.cc b/chromium/cc/base/switches.cc
index ddba9cbd444..4211a35d796 100644
--- a/chromium/cc/base/switches.cc
+++ b/chromium/cc/base/switches.cc
@@ -9,38 +9,28 @@
namespace cc {
namespace switches {
-// On platforms where checkerboards are used, prefer background colors instead
-// of checkerboards.
-const char kBackgroundColorInsteadOfCheckerboard[] =
- "background-color-instead-of-checkerboard";
-
-// Disables LCD text.
-const char kDisableLCDText[] = "disable-lcd-text";
-
const char kDisableThreadedAnimation[] = "disable-threaded-animation";
// Disables layer-edge anti-aliasing in the compositor.
const char kDisableCompositedAntialiasing[] =
"disable-composited-antialiasing";
-// Paint content on the main thread instead of the compositor thread.
-// Overrides the kEnableImplSidePainting flag.
-const char kDisableImplSidePainting[] = "disable-impl-side-painting";
+// Disables sending the next BeginMainFrame before the previous commit has
+// drawn.
+const char kDisableMainFrameBeforeDraw[] = "disable-main-frame-before-draw";
-// Enables LCD text.
-const char kEnableLCDText[] = "enable-lcd-text";
+// Disables sending the next BeginMainFrame before the previous commit
+// activates. Overrides the kEnableMainFrameBeforeActivation flag.
+const char kDisableMainFrameBeforeActivation[] =
+ "disable-main-frame-before-activation";
-// Paint content on the compositor thread instead of the main thread.
-const char kEnableImplSidePainting[] = "enable-impl-side-painting";
+// Enables sending the next BeginMainFrame before the previous commit activates.
+const char kEnableMainFrameBeforeActivation[] =
+ "enable-main-frame-before-activation";
const char kEnableTopControlsPositionCalculation[] =
"enable-top-controls-position-calculation";
-// Allow heuristics to determine when a layer tile should be drawn with
-// the Skia GPU backend. Only valid with GPU accelerated compositing +
-// impl-side painting.
-const char kEnableGPURasterization[] = "enable-gpu-rasterization";
-
// The height of the movable top controls.
const char kTopControlsHeight[] = "top-controls-height";
@@ -50,13 +40,6 @@ const char kTopControlsHideThreshold[] = "top-controls-hide-threshold";
// Percentage of the top controls need to be shown before they will auto show.
const char kTopControlsShowThreshold[] = "top-controls-show-threshold";
-// Number of worker threads used to rasterize content.
-const char kNumRasterThreads[] = "num-raster-threads";
-
-// Show metrics about overdraw in about:tracing recordings, such as the number
-// of pixels culled, and the number of pixels drawn, for each frame.
-const char kTraceOverdraw[] = "trace-overdraw";
-
// Re-rasters everything multiple times to simulate a much slower machine.
// Give a scale factor to cause raster to take that many times longer to
// complete, such as --slow-down-raster-scale-factor=25.
@@ -80,13 +63,13 @@ const char kStrictLayerPropertyChangeChecking[] =
// Virtual viewport for fixed-position elements, scrollbars during pinch.
const char kEnablePinchVirtualViewport[] = "enable-pinch-virtual-viewport";
+const char kDisablePinchVirtualViewport[] = "disable-pinch-virtual-viewport";
-const char kEnablePartialSwap[] = "enable-partial-swap";
// Disable partial swap which is needed for some OpenGL drivers / emulators.
const char kUIDisablePartialSwap[] = "ui-disable-partial-swap";
-const char kEnablePerTilePainting[] = "enable-per-tile-painting";
-const char kUIEnablePerTilePainting[] = "ui-enable-per-tile-painting";
+// Enables the GPU benchmarking extension
+const char kEnableGpuBenchmarking[] = "enable-gpu-benchmarking";
// Renders a border around compositor layers to help debug and study
// layer compositing.
@@ -131,83 +114,15 @@ const char kUIShowOccludingRects[] = "ui-show-occluding-rects";
const char kShowNonOccludingRects[] = "show-nonoccluding-rects";
const char kUIShowNonOccludingRects[] = "ui-show-nonoccluding-rects";
-// Enable rasterizer that writes directly to GPU memory.
-const char kEnableMapImage[] = "enable-map-image";
-
-// Disable rasterizer that writes directly to GPU memory.
-// Overrides the kEnableMapImage flag.
-const char kDisableMapImage[] = "disable-map-image";
-
// Prevents the layer tree unit tests from timing out.
const char kCCLayerTreeTestNoTimeout[] = "cc-layer-tree-test-no-timeout";
// Makes pixel tests write their output instead of read it.
const char kCCRebaselinePixeltests[] = "cc-rebaseline-pixeltests";
-// Disable textures using RGBA_4444 layout.
-const char kDisable4444Textures[] = "disable-4444-textures";
-
// Disable touch hit testing in the compositor.
const char kDisableCompositorTouchHitTesting[] =
"disable-compositor-touch-hit-testing";
-bool IsLCDTextEnabled() {
- const CommandLine* command_line = CommandLine::ForCurrentProcess();
- if (command_line->HasSwitch(switches::kDisableLCDText))
- return false;
- else if (command_line->HasSwitch(switches::kEnableLCDText))
- return true;
-
-#if defined(OS_ANDROID)
- return false;
-#else
- return true;
-#endif
-}
-
-namespace {
-bool CheckImplSidePaintingStatus() {
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
-
- if (command_line.HasSwitch(switches::kDisableImplSidePainting))
- return false;
- else if (command_line.HasSwitch(switches::kEnableImplSidePainting))
- return true;
-
-#if defined(OS_ANDROID)
- return true;
-#else
- return false;
-#endif
-}
-
-bool CheckGPURasterizationStatus() {
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
- return command_line.HasSwitch(switches::kEnableGPURasterization);
-}
-
-} // namespace
-
-bool IsImplSidePaintingEnabled() {
- static bool enabled = CheckImplSidePaintingStatus();
- return enabled;
-}
-
-bool IsGPURasterizationEnabled() {
- static bool enabled = CheckGPURasterizationStatus();
- return enabled;
-}
-
-bool IsMapImageEnabled() {
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
-
- if (command_line.HasSwitch(switches::kDisableMapImage))
- return false;
- else if (command_line.HasSwitch(switches::kEnableMapImage))
- return true;
-
- return false;
-}
-
} // namespace switches
} // namespace cc
diff --git a/chromium/cc/base/switches.h b/chromium/cc/base/switches.h
index 19cba57bb98..be4c1acd40b 100644
--- a/chromium/cc/base/switches.h
+++ b/chromium/cc/base/switches.h
@@ -16,37 +16,28 @@ namespace cc {
namespace switches {
// Switches for the renderer compositor only.
-CC_EXPORT extern const char kBackgroundColorInsteadOfCheckerboard[];
-CC_EXPORT extern const char kDisableLCDText[];
-CC_EXPORT extern const char kDisableImplSidePainting[];
CC_EXPORT extern const char kDisableThreadedAnimation[];
CC_EXPORT extern const char kDisableCompositedAntialiasing[];
-CC_EXPORT extern const char kEnableLCDText[];
-CC_EXPORT extern const char kEnableImplSidePainting[];
+CC_EXPORT extern const char kDisableMainFrameBeforeDraw[];
+CC_EXPORT extern const char kDisableMainFrameBeforeActivation[];
+CC_EXPORT extern const char kEnableMainFrameBeforeActivation[];
CC_EXPORT extern const char kEnableTopControlsPositionCalculation[];
-CC_EXPORT extern const char kEnableGPURasterization[];
CC_EXPORT extern const char kJankInsteadOfCheckerboard[];
-CC_EXPORT extern const char kNumRasterThreads[];
CC_EXPORT extern const char kTopControlsHeight[];
CC_EXPORT extern const char kTopControlsHideThreshold[];
-CC_EXPORT extern const char kTraceOverdraw[];
CC_EXPORT extern const char kTopControlsShowThreshold[];
CC_EXPORT extern const char kSlowDownRasterScaleFactor[];
CC_EXPORT extern const char kCompositeToMailbox[];
CC_EXPORT extern const char kMaxTilesForInterestArea[];
CC_EXPORT extern const char kMaxUnusedResourceMemoryUsagePercentage[];
CC_EXPORT extern const char kEnablePinchVirtualViewport[];
-CC_EXPORT extern const char kEnablePartialSwap[];
+CC_EXPORT extern const char kDisablePinchVirtualViewport[];
CC_EXPORT extern const char kStrictLayerPropertyChangeChecking[];
-CC_EXPORT extern const char kEnableMapImage[];
-CC_EXPORT extern const char kDisableMapImage[];
-CC_EXPORT extern const char kDisable4444Textures[];
CC_EXPORT extern const char kDisableCompositorTouchHitTesting[];
// Switches for both the renderer and ui compositors.
CC_EXPORT extern const char kUIDisablePartialSwap[];
-CC_EXPORT extern const char kEnablePerTilePainting[];
-CC_EXPORT extern const char kUIEnablePerTilePainting[];
+CC_EXPORT extern const char kEnableGpuBenchmarking[];
// Debug visualizations.
CC_EXPORT extern const char kShowCompositedLayerBorders[];
@@ -72,11 +63,6 @@ CC_EXPORT extern const char kUIShowNonOccludingRects[];
CC_EXPORT extern const char kCCLayerTreeTestNoTimeout[];
CC_EXPORT extern const char kCCRebaselinePixeltests[];
-CC_EXPORT bool IsLCDTextEnabled();
-CC_EXPORT bool IsImplSidePaintingEnabled();
-CC_EXPORT bool IsGPURasterizationEnabled();
-CC_EXPORT bool IsMapImageEnabled();
-
} // namespace switches
} // namespace cc
diff --git a/chromium/cc/base/tiling_data.cc b/chromium/cc/base/tiling_data.cc
index 1045d89addd..185bbed4019 100644
--- a/chromium/cc/base/tiling_data.cc
+++ b/chromium/cc/base/tiling_data.cc
@@ -28,32 +28,30 @@ TilingData::TilingData()
RecomputeNumTiles();
}
-TilingData::TilingData(
- gfx::Size max_texture_size,
- gfx::Size total_size,
- bool has_border_texels)
+TilingData::TilingData(const gfx::Size& max_texture_size,
+ const gfx::Rect& tiling_rect,
+ bool has_border_texels)
: max_texture_size_(max_texture_size),
- total_size_(total_size),
+ tiling_rect_(tiling_rect),
border_texels_(has_border_texels ? 1 : 0) {
RecomputeNumTiles();
}
-TilingData::TilingData(
- gfx::Size max_texture_size,
- gfx::Size total_size,
- int border_texels)
+TilingData::TilingData(const gfx::Size& max_texture_size,
+ const gfx::Rect& tiling_rect,
+ int border_texels)
: max_texture_size_(max_texture_size),
- total_size_(total_size),
+ tiling_rect_(tiling_rect),
border_texels_(border_texels) {
RecomputeNumTiles();
}
-void TilingData::SetTotalSize(gfx::Size total_size) {
- total_size_ = total_size;
+void TilingData::SetTilingRect(const gfx::Rect& tiling_rect) {
+ tiling_rect_ = tiling_rect;
RecomputeNumTiles();
}
-void TilingData::SetMaxTextureSize(gfx::Size max_texture_size) {
+void TilingData::SetMaxTextureSize(const gfx::Size& max_texture_size) {
max_texture_size_ = max_texture_size;
RecomputeNumTiles();
}
@@ -72,6 +70,8 @@ int TilingData::TileXIndexFromSrcCoord(int src_position) const {
if (num_tiles_x_ <= 1)
return 0;
+ src_position -= tiling_rect_.x();
+
DCHECK_GT(max_texture_size_.width() - 2 * border_texels_, 0);
int x = (src_position - border_texels_) /
(max_texture_size_.width() - 2 * border_texels_);
@@ -82,6 +82,8 @@ int TilingData::TileYIndexFromSrcCoord(int src_position) const {
if (num_tiles_y_ <= 1)
return 0;
+ src_position -= tiling_rect_.y();
+
DCHECK_GT(max_texture_size_.height() - 2 * border_texels_, 0);
int y = (src_position - border_texels_) /
(max_texture_size_.height() - 2 * border_texels_);
@@ -92,6 +94,8 @@ int TilingData::FirstBorderTileXIndexFromSrcCoord(int src_position) const {
if (num_tiles_x_ <= 1)
return 0;
+ src_position -= tiling_rect_.x();
+
DCHECK_GT(max_texture_size_.width() - 2 * border_texels_, 0);
int inner_tile_size = max_texture_size_.width() - 2 * border_texels_;
int x = (src_position - 2 * border_texels_) / inner_tile_size;
@@ -102,6 +106,8 @@ int TilingData::FirstBorderTileYIndexFromSrcCoord(int src_position) const {
if (num_tiles_y_ <= 1)
return 0;
+ src_position -= tiling_rect_.y();
+
DCHECK_GT(max_texture_size_.height() - 2 * border_texels_, 0);
int inner_tile_size = max_texture_size_.height() - 2 * border_texels_;
int y = (src_position - 2 * border_texels_) / inner_tile_size;
@@ -112,6 +118,8 @@ int TilingData::LastBorderTileXIndexFromSrcCoord(int src_position) const {
if (num_tiles_x_ <= 1)
return 0;
+ src_position -= tiling_rect_.x();
+
DCHECK_GT(max_texture_size_.width() - 2 * border_texels_, 0);
int inner_tile_size = max_texture_size_.width() - 2 * border_texels_;
int x = src_position / inner_tile_size;
@@ -122,48 +130,77 @@ int TilingData::LastBorderTileYIndexFromSrcCoord(int src_position) const {
if (num_tiles_y_ <= 1)
return 0;
+ src_position -= tiling_rect_.y();
+
DCHECK_GT(max_texture_size_.height() - 2 * border_texels_, 0);
int inner_tile_size = max_texture_size_.height() - 2 * border_texels_;
int y = src_position / inner_tile_size;
return std::min(std::max(y, 0), num_tiles_y_ - 1);
}
+gfx::Rect TilingData::ExpandRectToTileBoundsWithBorders(
+ const gfx::Rect& rect) const {
+ if (!rect.Intersects(tiling_rect_) || has_empty_bounds())
+ return gfx::Rect();
+ int index_x = FirstBorderTileXIndexFromSrcCoord(rect.x());
+ int index_y = FirstBorderTileYIndexFromSrcCoord(rect.y());
+ int index_right = LastBorderTileXIndexFromSrcCoord(rect.right() - 1);
+ int index_bottom = LastBorderTileYIndexFromSrcCoord(rect.bottom() - 1);
+
+ gfx::Rect rect_top_left(TileBoundsWithBorder(index_x, index_y));
+ gfx::Rect rect_bottom_right(TileBoundsWithBorder(index_right, index_bottom));
+
+ return gfx::UnionRects(rect_top_left, rect_bottom_right);
+}
+
+gfx::Rect TilingData::ExpandRectToTileBounds(const gfx::Rect& rect) const {
+ if (!rect.Intersects(tiling_rect_) || has_empty_bounds())
+ return gfx::Rect();
+ int index_x = FirstBorderTileXIndexFromSrcCoord(rect.x());
+ int index_y = FirstBorderTileYIndexFromSrcCoord(rect.y());
+ int index_right = LastBorderTileXIndexFromSrcCoord(rect.right() - 1);
+ int index_bottom = LastBorderTileYIndexFromSrcCoord(rect.bottom() - 1);
+
+ gfx::Rect rect_top_left(TileBounds(index_x, index_y));
+ gfx::Rect rect_bottom_right(TileBounds(index_right, index_bottom));
+
+ return gfx::UnionRects(rect_top_left, rect_bottom_right);
+}
+
gfx::Rect TilingData::TileBounds(int i, int j) const {
AssertTile(i, j);
int max_texture_size_x = max_texture_size_.width() - 2 * border_texels_;
int max_texture_size_y = max_texture_size_.height() - 2 * border_texels_;
- int total_size_x = total_size_.width();
- int total_size_y = total_size_.height();
- int lo_x = max_texture_size_x * i;
+ int lo_x = tiling_rect_.x() + max_texture_size_x * i;
if (i != 0)
lo_x += border_texels_;
- int lo_y = max_texture_size_y * j;
+ int lo_y = tiling_rect_.y() + max_texture_size_y * j;
if (j != 0)
lo_y += border_texels_;
- int hi_x = max_texture_size_x * (i + 1) + border_texels_;
+ int hi_x = tiling_rect_.x() + max_texture_size_x * (i + 1) + border_texels_;
if (i + 1 == num_tiles_x_)
hi_x += border_texels_;
- int hi_y = max_texture_size_y * (j + 1) + border_texels_;
+ int hi_y = tiling_rect_.y() + max_texture_size_y * (j + 1) + border_texels_;
if (j + 1 == num_tiles_y_)
hi_y += border_texels_;
- hi_x = std::min(hi_x, total_size_x);
- hi_y = std::min(hi_y, total_size_y);
+ hi_x = std::min(hi_x, tiling_rect_.right());
+ hi_y = std::min(hi_y, tiling_rect_.bottom());
int x = lo_x;
int y = lo_y;
int width = hi_x - lo_x;
int height = hi_y - lo_y;
- DCHECK_GE(x, 0);
- DCHECK_GE(y, 0);
+ DCHECK_GE(x, tiling_rect_.x());
+ DCHECK_GE(y, tiling_rect_.y());
DCHECK_GE(width, 0);
DCHECK_GE(height, 0);
- DCHECK_LE(x, total_size_.width());
- DCHECK_LE(y, total_size_.height());
+ DCHECK_LE(x, tiling_rect_.right());
+ DCHECK_LE(y, tiling_rect_.bottom());
return gfx::Rect(x, y, width, height);
}
@@ -171,28 +208,26 @@ gfx::Rect TilingData::TileBoundsWithBorder(int i, int j) const {
AssertTile(i, j);
int max_texture_size_x = max_texture_size_.width() - 2 * border_texels_;
int max_texture_size_y = max_texture_size_.height() - 2 * border_texels_;
- int total_size_x = total_size_.width();
- int total_size_y = total_size_.height();
- int lo_x = max_texture_size_x * i;
- int lo_y = max_texture_size_y * j;
+ int lo_x = tiling_rect_.x() + max_texture_size_x * i;
+ int lo_y = tiling_rect_.y() + max_texture_size_y * j;
int hi_x = lo_x + max_texture_size_x + 2 * border_texels_;
int hi_y = lo_y + max_texture_size_y + 2 * border_texels_;
- hi_x = std::min(hi_x, total_size_x);
- hi_y = std::min(hi_y, total_size_y);
+ hi_x = std::min(hi_x, tiling_rect_.right());
+ hi_y = std::min(hi_y, tiling_rect_.bottom());
int x = lo_x;
int y = lo_y;
int width = hi_x - lo_x;
int height = hi_y - lo_y;
- DCHECK_GE(x, 0);
- DCHECK_GE(y, 0);
+ DCHECK_GE(x, tiling_rect_.x());
+ DCHECK_GE(y, tiling_rect_.y());
DCHECK_GE(width, 0);
DCHECK_GE(height, 0);
- DCHECK_LE(x, total_size_.width());
- DCHECK_LE(y, total_size_.height());
+ DCHECK_LE(x, tiling_rect_.right());
+ DCHECK_LE(y, tiling_rect_.bottom());
return gfx::Rect(x, y, width, height);
}
@@ -204,6 +239,8 @@ int TilingData::TilePositionX(int x_index) const {
if (x_index != 0)
pos += border_texels_;
+ pos += tiling_rect_.x();
+
return pos;
}
@@ -215,6 +252,8 @@ int TilingData::TilePositionY(int y_index) const {
if (y_index != 0)
pos += border_texels_;
+ pos += tiling_rect_.y();
+
return pos;
}
@@ -223,13 +262,13 @@ int TilingData::TileSizeX(int x_index) const {
DCHECK_LT(x_index, num_tiles_x_);
if (!x_index && num_tiles_x_ == 1)
- return total_size_.width();
+ return tiling_rect_.width();
if (!x_index && num_tiles_x_ > 1)
return max_texture_size_.width() - border_texels_;
if (x_index < num_tiles_x_ - 1)
return max_texture_size_.width() - 2 * border_texels_;
if (x_index == num_tiles_x_ - 1)
- return total_size_.width() - TilePositionX(x_index);
+ return tiling_rect_.right() - TilePositionX(x_index);
NOTREACHED();
return 0;
@@ -240,13 +279,13 @@ int TilingData::TileSizeY(int y_index) const {
DCHECK_LT(y_index, num_tiles_y_);
if (!y_index && num_tiles_y_ == 1)
- return total_size_.height();
+ return tiling_rect_.height();
if (!y_index && num_tiles_y_ > 1)
return max_texture_size_.height() - border_texels_;
if (y_index < num_tiles_y_ - 1)
return max_texture_size_.height() - 2 * border_texels_;
if (y_index == num_tiles_y_ - 1)
- return total_size_.height() - TilePositionY(y_index);
+ return tiling_rect_.bottom() - TilePositionY(y_index);
NOTREACHED();
return 0;
@@ -261,9 +300,9 @@ gfx::Vector2d TilingData::TextureOffset(int x_index, int y_index) const {
void TilingData::RecomputeNumTiles() {
num_tiles_x_ = ComputeNumTiles(
- max_texture_size_.width(), total_size_.width(), border_texels_);
+ max_texture_size_.width(), tiling_rect_.width(), border_texels_);
num_tiles_y_ = ComputeNumTiles(
- max_texture_size_.height(), total_size_.height(), border_texels_);
+ max_texture_size_.height(), tiling_rect_.height(), border_texels_);
}
TilingData::BaseIterator::BaseIterator(const TilingData* tiling_data)
@@ -272,27 +311,39 @@ TilingData::BaseIterator::BaseIterator(const TilingData* tiling_data)
index_y_(-1) {
}
-TilingData::Iterator::Iterator(const TilingData* tiling_data, gfx::Rect rect)
- : BaseIterator(tiling_data),
- left_(-1),
- right_(-1),
- bottom_(-1) {
+TilingData::Iterator::Iterator() : BaseIterator(NULL) { done(); }
+
+TilingData::Iterator::Iterator(const TilingData* tiling_data,
+ const gfx::Rect& tiling_rect,
+ bool include_borders)
+ : BaseIterator(tiling_data), left_(-1), right_(-1), bottom_(-1) {
if (tiling_data_->num_tiles_x() <= 0 || tiling_data_->num_tiles_y() <= 0) {
done();
return;
}
- rect.Intersect(gfx::Rect(tiling_data_->total_size()));
- index_x_ = tiling_data_->FirstBorderTileXIndexFromSrcCoord(rect.x());
- index_y_ = tiling_data_->FirstBorderTileYIndexFromSrcCoord(rect.y());
+ gfx::Rect rect(tiling_rect);
+ rect.Intersect(tiling_data_->tiling_rect());
+
+ gfx::Rect top_left_tile;
+ if (include_borders) {
+ index_x_ = tiling_data_->FirstBorderTileXIndexFromSrcCoord(rect.x());
+ index_y_ = tiling_data_->FirstBorderTileYIndexFromSrcCoord(rect.y());
+ right_ = tiling_data_->LastBorderTileXIndexFromSrcCoord(rect.right() - 1);
+ bottom_ = tiling_data_->LastBorderTileYIndexFromSrcCoord(rect.bottom() - 1);
+ top_left_tile = tiling_data_->TileBoundsWithBorder(index_x_, index_y_);
+ } else {
+ index_x_ = tiling_data_->TileXIndexFromSrcCoord(rect.x());
+ index_y_ = tiling_data_->TileYIndexFromSrcCoord(rect.y());
+ right_ = tiling_data_->TileXIndexFromSrcCoord(rect.right() - 1);
+ bottom_ = tiling_data_->TileYIndexFromSrcCoord(rect.bottom() - 1);
+ top_left_tile = tiling_data_->TileBounds(index_x_, index_y_);
+ }
left_ = index_x_;
- right_ = tiling_data_->LastBorderTileXIndexFromSrcCoord(rect.right() - 1);
- bottom_ = tiling_data_->LastBorderTileYIndexFromSrcCoord(rect.bottom() - 1);
// Index functions always return valid indices, so explicitly check
// for non-intersecting rects.
- gfx::Rect new_rect = tiling_data_->TileBoundsWithBorder(index_x_, index_y_);
- if (!new_rect.Intersects(rect))
+ if (!top_left_tile.Intersects(rect))
done();
}
@@ -313,8 +364,8 @@ TilingData::Iterator& TilingData::Iterator::operator++() {
TilingData::DifferenceIterator::DifferenceIterator(
const TilingData* tiling_data,
- gfx::Rect consider,
- gfx::Rect ignore)
+ const gfx::Rect& consider_rect,
+ const gfx::Rect& ignore_rect)
: BaseIterator(tiling_data),
consider_left_(-1),
consider_top_(-1),
@@ -329,9 +380,10 @@ TilingData::DifferenceIterator::DifferenceIterator(
return;
}
- gfx::Rect bounds(tiling_data_->total_size());
- consider.Intersect(bounds);
- ignore.Intersect(bounds);
+ gfx::Rect consider(consider_rect);
+ gfx::Rect ignore(ignore_rect);
+ consider.Intersect(tiling_data_->tiling_rect());
+ ignore.Intersect(tiling_data_->tiling_rect());
if (consider.IsEmpty()) {
done();
return;
@@ -405,4 +457,234 @@ TilingData::DifferenceIterator& TilingData::DifferenceIterator::operator++() {
return *this;
}
+TilingData::SpiralDifferenceIterator::SpiralDifferenceIterator()
+ : BaseIterator(NULL) {
+ done();
+}
+
+TilingData::SpiralDifferenceIterator::SpiralDifferenceIterator(
+ const TilingData* tiling_data,
+ const gfx::Rect& consider_rect,
+ const gfx::Rect& ignore_rect,
+ const gfx::Rect& center_rect)
+ : BaseIterator(tiling_data),
+ consider_left_(-1),
+ consider_top_(-1),
+ consider_right_(-1),
+ consider_bottom_(-1),
+ ignore_left_(-1),
+ ignore_top_(-1),
+ ignore_right_(-1),
+ ignore_bottom_(-1),
+ direction_(RIGHT),
+ delta_x_(1),
+ delta_y_(0),
+ current_step_(0),
+ horizontal_step_count_(0),
+ vertical_step_count_(0) {
+ if (tiling_data_->num_tiles_x() <= 0 || tiling_data_->num_tiles_y() <= 0) {
+ done();
+ return;
+ }
+
+ gfx::Rect consider(consider_rect);
+ gfx::Rect ignore(ignore_rect);
+ gfx::Rect center(center_rect);
+ consider.Intersect(tiling_data_->tiling_rect());
+ ignore.Intersect(tiling_data_->tiling_rect());
+ if (consider.IsEmpty()) {
+ done();
+ return;
+ }
+
+ consider_left_ =
+ tiling_data_->FirstBorderTileXIndexFromSrcCoord(consider.x());
+ consider_top_ = tiling_data_->FirstBorderTileYIndexFromSrcCoord(consider.y());
+ consider_right_ =
+ tiling_data_->LastBorderTileXIndexFromSrcCoord(consider.right() - 1);
+ consider_bottom_ =
+ tiling_data_->LastBorderTileYIndexFromSrcCoord(consider.bottom() - 1);
+
+ if (!ignore.IsEmpty()) {
+ ignore_left_ = tiling_data_->FirstBorderTileXIndexFromSrcCoord(ignore.x());
+ ignore_top_ = tiling_data_->FirstBorderTileYIndexFromSrcCoord(ignore.y());
+ ignore_right_ =
+ tiling_data_->LastBorderTileXIndexFromSrcCoord(ignore.right() - 1);
+ ignore_bottom_ =
+ tiling_data_->LastBorderTileYIndexFromSrcCoord(ignore.bottom() - 1);
+
+ // Clamp ignore indices to consider indices.
+ ignore_left_ = std::max(ignore_left_, consider_left_);
+ ignore_top_ = std::max(ignore_top_, consider_top_);
+ ignore_right_ = std::min(ignore_right_, consider_right_);
+ ignore_bottom_ = std::min(ignore_bottom_, consider_bottom_);
+ }
+
+ if (ignore_left_ == consider_left_ && ignore_right_ == consider_right_ &&
+ ignore_top_ == consider_top_ && ignore_bottom_ == consider_bottom_) {
+ done();
+ return;
+ }
+
+ // Determine around left, such that it is between -1 and num_tiles_x.
+ int around_left = 0;
+ if (center.x() < tiling_data->tiling_rect().x() || center.IsEmpty())
+ around_left = -1;
+ else if (center.x() > tiling_data->tiling_rect().right())
+ around_left = tiling_data->num_tiles_x();
+ else
+ around_left = tiling_data->FirstBorderTileXIndexFromSrcCoord(center.x());
+
+ // Determine around top, such that it is between -1 and num_tiles_y.
+ int around_top = 0;
+ if (center.y() < tiling_data->tiling_rect().y() || center.IsEmpty())
+ around_top = -1;
+ else if (center.y() > tiling_data->tiling_rect().bottom())
+ around_top = tiling_data->num_tiles_y();
+ else
+ around_top = tiling_data->FirstBorderTileYIndexFromSrcCoord(center.y());
+
+ // Determine around right, such that it is between -1 and num_tiles_x.
+ int right_src_coord = center.right() - 1;
+ int around_right = 0;
+ if (right_src_coord < tiling_data->tiling_rect().x() || center.IsEmpty()) {
+ around_right = -1;
+ } else if (right_src_coord > tiling_data->tiling_rect().right()) {
+ around_right = tiling_data->num_tiles_x();
+ } else {
+ around_right =
+ tiling_data->LastBorderTileXIndexFromSrcCoord(right_src_coord);
+ }
+
+ // Determine around bottom, such that it is between -1 and num_tiles_y.
+ int bottom_src_coord = center.bottom() - 1;
+ int around_bottom = 0;
+ if (bottom_src_coord < tiling_data->tiling_rect().y() || center.IsEmpty()) {
+ around_bottom = -1;
+ } else if (bottom_src_coord > tiling_data->tiling_rect().bottom()) {
+ around_bottom = tiling_data->num_tiles_y();
+ } else {
+ around_bottom =
+ tiling_data->LastBorderTileYIndexFromSrcCoord(bottom_src_coord);
+ }
+
+ vertical_step_count_ = around_bottom - around_top + 1;
+ horizontal_step_count_ = around_right - around_left + 1;
+ current_step_ = horizontal_step_count_ - 1;
+
+ index_x_ = around_right;
+ index_y_ = around_bottom;
+
+ // The current index is the bottom right of the around rect, which is also
+ // ignored. So we have to advance.
+ ++(*this);
+}
+
+TilingData::SpiralDifferenceIterator& TilingData::SpiralDifferenceIterator::
+operator++() {
+ int cannot_hit_consider_count = 0;
+ while (cannot_hit_consider_count < 4) {
+ if (needs_direction_switch())
+ switch_direction();
+
+ index_x_ += delta_x_;
+ index_y_ += delta_y_;
+ ++current_step_;
+
+ if (in_consider_rect()) {
+ cannot_hit_consider_count = 0;
+
+ if (!in_ignore_rect())
+ break;
+
+ // Steps needed to reach the very edge of the ignore rect, while remaining
+ // inside (so that the continue would take us outside).
+ int steps_to_edge = 0;
+ switch (direction_) {
+ case UP:
+ steps_to_edge = index_y_ - ignore_top_;
+ break;
+ case LEFT:
+ steps_to_edge = index_x_ - ignore_left_;
+ break;
+ case DOWN:
+ steps_to_edge = ignore_bottom_ - index_y_;
+ break;
+ case RIGHT:
+ steps_to_edge = ignore_right_ - index_x_;
+ break;
+ }
+
+ // We need to switch directions in |max_steps|.
+ int max_steps = current_step_count() - current_step_;
+
+ int steps_to_take = std::min(steps_to_edge, max_steps);
+ DCHECK_GE(steps_to_take, 0);
+
+ index_x_ += steps_to_take * delta_x_;
+ index_y_ += steps_to_take * delta_y_;
+ current_step_ += steps_to_take;
+ } else {
+ int max_steps = current_step_count() - current_step_;
+ int steps_to_take = max_steps;
+ bool can_hit_consider_rect = false;
+ switch (direction_) {
+ case UP:
+ if (valid_column() && consider_bottom_ < index_y_)
+ steps_to_take = index_y_ - consider_bottom_ - 1;
+ can_hit_consider_rect |= consider_right_ >= index_x_;
+ break;
+ case LEFT:
+ if (valid_row() && consider_right_ < index_x_)
+ steps_to_take = index_x_ - consider_right_ - 1;
+ can_hit_consider_rect |= consider_top_ <= index_y_;
+ break;
+ case DOWN:
+ if (valid_column() && consider_top_ > index_y_)
+ steps_to_take = consider_top_ - index_y_ - 1;
+ can_hit_consider_rect |= consider_left_ <= index_x_;
+ break;
+ case RIGHT:
+ if (valid_row() && consider_left_ > index_x_)
+ steps_to_take = consider_left_ - index_x_ - 1;
+ can_hit_consider_rect |= consider_bottom_ >= index_y_;
+ break;
+ }
+ steps_to_take = std::min(steps_to_take, max_steps);
+ DCHECK_GE(steps_to_take, 0);
+
+ index_x_ += steps_to_take * delta_x_;
+ index_y_ += steps_to_take * delta_y_;
+ current_step_ += steps_to_take;
+
+ if (can_hit_consider_rect)
+ cannot_hit_consider_count = 0;
+ else
+ ++cannot_hit_consider_count;
+ }
+ }
+
+ if (cannot_hit_consider_count >= 4)
+ done();
+ return *this;
+}
+
+bool TilingData::SpiralDifferenceIterator::needs_direction_switch() const {
+ return current_step_ >= current_step_count();
+}
+
+void TilingData::SpiralDifferenceIterator::switch_direction() {
+ int new_delta_x_ = delta_y_;
+ delta_y_ = -delta_x_;
+ delta_x_ = new_delta_x_;
+
+ current_step_ = 0;
+ direction_ = static_cast<Direction>((direction_ + 1) % 4);
+
+ if (direction_ == RIGHT || direction_ == LEFT) {
+ ++vertical_step_count_;
+ ++horizontal_step_count_;
+ }
+}
+
} // namespace cc
diff --git a/chromium/cc/base/tiling_data.h b/chromium/cc/base/tiling_data.h
index 3bf9809579f..8550e5f186e 100644
--- a/chromium/cc/base/tiling_data.h
+++ b/chromium/cc/base/tiling_data.h
@@ -22,20 +22,18 @@ namespace cc {
class CC_EXPORT TilingData {
public:
TilingData();
- TilingData(
- gfx::Size max_texture_size,
- gfx::Size total_size,
- bool has_border_texels);
- TilingData(
- gfx::Size max_texture_size,
- gfx::Size total_size,
- int border_texels);
-
- gfx::Size total_size() const { return total_size_; }
- void SetTotalSize(const gfx::Size total_size);
+ TilingData(const gfx::Size& max_texture_size,
+ const gfx::Rect& tiling_rect,
+ bool has_border_texels);
+ TilingData(const gfx::Size& max_texture_size,
+ const gfx::Rect& tiling_rect,
+ int border_texels);
+
+ gfx::Rect tiling_rect() const { return tiling_rect_; }
+ void SetTilingRect(const gfx::Rect& tiling_rect);
gfx::Size max_texture_size() const { return max_texture_size_; }
- void SetMaxTextureSize(gfx::Size max_texture_size);
+ void SetMaxTextureSize(const gfx::Size& max_texture_size);
int border_texels() const { return border_texels_; }
void SetHasBorderTexels(bool has_border_texels);
@@ -54,6 +52,9 @@ class CC_EXPORT TilingData {
int LastBorderTileXIndexFromSrcCoord(int src_position) const;
int LastBorderTileYIndexFromSrcCoord(int src_position) const;
+ gfx::Rect ExpandRectToTileBoundsWithBorders(const gfx::Rect& rect) const;
+ gfx::Rect ExpandRectToTileBounds(const gfx::Rect& rect) const;
+
gfx::Rect TileBounds(int i, int j) const;
gfx::Rect TileBoundsWithBorder(int i, int j) const;
int TilePositionX(int x_index) const;
@@ -86,10 +87,13 @@ class CC_EXPORT TilingData {
int index_y_;
};
- // Iterate through all indices whose bounds + border intersect with |rect|.
+ // Iterate through tiles whose bounds + optional border intersect with |rect|.
class CC_EXPORT Iterator : public BaseIterator {
public:
- Iterator(const TilingData* tiling_data, gfx::Rect rect);
+ Iterator();
+ Iterator(const TilingData* tiling_data,
+ const gfx::Rect& tiling_rect,
+ bool include_borders);
Iterator& operator++();
private:
@@ -104,8 +108,8 @@ class CC_EXPORT TilingData {
public:
DifferenceIterator(
const TilingData* tiling_data,
- gfx::Rect consider,
- gfx::Rect ignore);
+ const gfx::Rect& consider_rect,
+ const gfx::Rect& ignore_rect);
DifferenceIterator& operator++();
private:
@@ -124,6 +128,61 @@ class CC_EXPORT TilingData {
int ignore_bottom_;
};
+ // Iterate through all indices whose bounds + border intersect with
+ // |consider| but which also do not intersect with |ignore|. The iterator
+ // order is a counterclockwise spiral around the given center.
+ class CC_EXPORT SpiralDifferenceIterator : public BaseIterator {
+ public:
+ SpiralDifferenceIterator();
+ SpiralDifferenceIterator(const TilingData* tiling_data,
+ const gfx::Rect& consider_rect,
+ const gfx::Rect& ignore_rect,
+ const gfx::Rect& center_rect);
+ SpiralDifferenceIterator& operator++();
+
+ private:
+ bool in_consider_rect() const {
+ return index_x_ >= consider_left_ && index_x_ <= consider_right_ &&
+ index_y_ >= consider_top_ && index_y_ <= consider_bottom_;
+ }
+ bool in_ignore_rect() const {
+ return index_x_ >= ignore_left_ && index_x_ <= ignore_right_ &&
+ index_y_ >= ignore_top_ && index_y_ <= ignore_bottom_;
+ }
+ bool valid_column() const {
+ return index_x_ >= consider_left_ && index_x_ <= consider_right_;
+ }
+ bool valid_row() const {
+ return index_y_ >= consider_top_ && index_y_ <= consider_bottom_;
+ }
+
+ int current_step_count() const {
+ return (direction_ == UP || direction_ == DOWN) ? vertical_step_count_
+ : horizontal_step_count_;
+ }
+
+ bool needs_direction_switch() const;
+ void switch_direction();
+
+ int consider_left_;
+ int consider_top_;
+ int consider_right_;
+ int consider_bottom_;
+ int ignore_left_;
+ int ignore_top_;
+ int ignore_right_;
+ int ignore_bottom_;
+
+ enum Direction { UP, LEFT, DOWN, RIGHT };
+
+ Direction direction_;
+ int delta_x_;
+ int delta_y_;
+ int current_step_;
+ int horizontal_step_count_;
+ int vertical_step_count_;
+ };
+
private:
void AssertTile(int i, int j) const {
DCHECK_GE(i, 0);
@@ -135,7 +194,7 @@ class CC_EXPORT TilingData {
void RecomputeNumTiles();
gfx::Size max_texture_size_;
- gfx::Size total_size_;
+ gfx::Rect tiling_rect_;
int border_texels_;
// These are computed values.
diff --git a/chromium/cc/base/tiling_data_unittest.cc b/chromium/cc/base/tiling_data_unittest.cc
index db2d6f215a9..84d9e79dc72 100644
--- a/chromium/cc/base/tiling_data_unittest.cc
+++ b/chromium/cc/base/tiling_data_unittest.cc
@@ -4,6 +4,7 @@
#include "cc/base/tiling_data.h"
+#include <algorithm>
#include <vector>
#include "cc/test/geometry_test_utils.h"
@@ -12,11 +13,10 @@
namespace cc {
namespace {
-int NumTiles(
- gfx::Size max_texture_size,
- gfx::Size total_size,
- bool has_border_texels) {
- TilingData tiling(max_texture_size, total_size, has_border_texels);
+int NumTiles(const gfx::Size& max_texture_size,
+ const gfx::Rect& tiling_rect,
+ bool has_border_texels) {
+ TilingData tiling(max_texture_size, tiling_rect, has_border_texels);
int num_tiles = tiling.num_tiles_x() * tiling.num_tiles_y();
// Assert no overflow.
@@ -27,700 +27,2048 @@ int NumTiles(
return num_tiles;
}
-int XIndex(
- gfx::Size max_texture_size,
- gfx::Size total_size,
- bool has_border_texels,
- int x_coord) {
- TilingData tiling(max_texture_size, total_size, has_border_texels);
+int XIndex(const gfx::Size& max_texture_size,
+ const gfx::Rect& tiling_rect,
+ bool has_border_texels,
+ int x_coord) {
+ TilingData tiling(max_texture_size, tiling_rect, has_border_texels);
return tiling.TileXIndexFromSrcCoord(x_coord);
}
-int YIndex(
- gfx::Size max_texture_size,
- gfx::Size total_size,
- bool has_border_texels,
- int y_coord) {
- TilingData tiling(max_texture_size, total_size, has_border_texels);
+int YIndex(const gfx::Size& max_texture_size,
+ const gfx::Rect& tiling_rect,
+ bool has_border_texels,
+ int y_coord) {
+ TilingData tiling(max_texture_size, tiling_rect, has_border_texels);
return tiling.TileYIndexFromSrcCoord(y_coord);
}
-int MinBorderXIndex(
- gfx::Size max_texture_size,
- gfx::Size total_size,
- bool has_border_texels,
- int x_coord) {
- TilingData tiling(max_texture_size, total_size, has_border_texels);
+int MinBorderXIndex(const gfx::Size& max_texture_size,
+ const gfx::Rect& tiling_rect,
+ bool has_border_texels,
+ int x_coord) {
+ TilingData tiling(max_texture_size, tiling_rect, has_border_texels);
return tiling.FirstBorderTileXIndexFromSrcCoord(x_coord);
}
-int MinBorderYIndex(
- gfx::Size max_texture_size,
- gfx::Size total_size,
- bool has_border_texels,
- int y_coord) {
- TilingData tiling(max_texture_size, total_size, has_border_texels);
+int MinBorderYIndex(const gfx::Size& max_texture_size,
+ const gfx::Rect& tiling_rect,
+ bool has_border_texels,
+ int y_coord) {
+ TilingData tiling(max_texture_size, tiling_rect, has_border_texels);
return tiling.FirstBorderTileYIndexFromSrcCoord(y_coord);
}
-int MaxBorderXIndex(
- gfx::Size max_texture_size,
- gfx::Size total_size,
- bool has_border_texels,
- int x_coord) {
- TilingData tiling(max_texture_size, total_size, has_border_texels);
+int MaxBorderXIndex(const gfx::Size& max_texture_size,
+ const gfx::Rect& tiling_rect,
+ bool has_border_texels,
+ int x_coord) {
+ TilingData tiling(max_texture_size, tiling_rect, has_border_texels);
return tiling.LastBorderTileXIndexFromSrcCoord(x_coord);
}
-int MaxBorderYIndex(
- gfx::Size max_texture_size,
- gfx::Size total_size,
- bool has_border_texels,
- int y_coord) {
- TilingData tiling(max_texture_size, total_size, has_border_texels);
+int MaxBorderYIndex(const gfx::Size& max_texture_size,
+ const gfx::Rect& tiling_rect,
+ bool has_border_texels,
+ int y_coord) {
+ TilingData tiling(max_texture_size, tiling_rect, has_border_texels);
return tiling.LastBorderTileYIndexFromSrcCoord(y_coord);
}
-int PosX(
- gfx::Size max_texture_size,
- gfx::Size total_size,
- bool has_border_texels,
- int x_index) {
- TilingData tiling(max_texture_size, total_size, has_border_texels);
+int PosX(const gfx::Size& max_texture_size,
+ const gfx::Rect& tiling_rect,
+ bool has_border_texels,
+ int x_index) {
+ TilingData tiling(max_texture_size, tiling_rect, has_border_texels);
return tiling.TilePositionX(x_index);
}
-int PosY(
- gfx::Size max_texture_size,
- gfx::Size total_size,
- bool has_border_texels,
- int y_index) {
- TilingData tiling(max_texture_size, total_size, has_border_texels);
+int PosY(const gfx::Size& max_texture_size,
+ const gfx::Rect& tiling_rect,
+ bool has_border_texels,
+ int y_index) {
+ TilingData tiling(max_texture_size, tiling_rect, has_border_texels);
return tiling.TilePositionY(y_index);
}
-int SizeX(
- gfx::Size max_texture_size,
- gfx::Size total_size,
- bool has_border_texels,
- int x_index) {
- TilingData tiling(max_texture_size, total_size, has_border_texels);
+int SizeX(const gfx::Size& max_texture_size,
+ const gfx::Rect& tiling_rect,
+ bool has_border_texels,
+ int x_index) {
+ TilingData tiling(max_texture_size, tiling_rect, has_border_texels);
return tiling.TileSizeX(x_index);
}
-int SizeY(
- gfx::Size max_texture_size,
- gfx::Size total_size,
- bool has_border_texels,
- int y_index) {
- TilingData tiling(max_texture_size, total_size, has_border_texels);
+int SizeY(const gfx::Size& max_texture_size,
+ const gfx::Rect& tiling_rect,
+ bool has_border_texels,
+ int y_index) {
+ TilingData tiling(max_texture_size, tiling_rect, has_border_texels);
return tiling.TileSizeY(y_index);
}
-TEST(TilingDataTest, NumTiles_NoTiling) {
- EXPECT_EQ(1, NumTiles(gfx::Size(16, 16), gfx::Size(16, 16), false));
- EXPECT_EQ(1, NumTiles(gfx::Size(16, 16), gfx::Size(15, 15), true));
- EXPECT_EQ(1, NumTiles(gfx::Size(16, 16), gfx::Size(16, 16), true));
- EXPECT_EQ(1, NumTiles(gfx::Size(16, 16), gfx::Size(1, 16), false));
- EXPECT_EQ(1, NumTiles(gfx::Size(15, 15), gfx::Size(15, 15), true));
- EXPECT_EQ(1, NumTiles(gfx::Size(32, 16), gfx::Size(32, 16), false));
- EXPECT_EQ(1, NumTiles(gfx::Size(32, 16), gfx::Size(32, 16), true));
+class TilingDataTest : public ::testing::TestWithParam<gfx::Point> {};
+
+TEST_P(TilingDataTest, NumTiles_NoTiling) {
+ gfx::Point origin = GetParam();
+
+ EXPECT_EQ(
+ 1,
+ NumTiles(gfx::Size(16, 16), gfx::Rect(origin, gfx::Size(16, 16)), false));
+ EXPECT_EQ(
+ 1,
+ NumTiles(gfx::Size(16, 16), gfx::Rect(origin, gfx::Size(15, 15)), true));
+ EXPECT_EQ(
+ 1,
+ NumTiles(gfx::Size(16, 16), gfx::Rect(origin, gfx::Size(16, 16)), true));
+ EXPECT_EQ(
+ 1,
+ NumTiles(gfx::Size(16, 16), gfx::Rect(origin, gfx::Size(1, 16)), false));
+ EXPECT_EQ(
+ 1,
+ NumTiles(gfx::Size(15, 15), gfx::Rect(origin, gfx::Size(15, 15)), true));
+ EXPECT_EQ(
+ 1,
+ NumTiles(gfx::Size(32, 16), gfx::Rect(origin, gfx::Size(32, 16)), false));
+ EXPECT_EQ(
+ 1,
+ NumTiles(gfx::Size(32, 16), gfx::Rect(origin, gfx::Size(32, 16)), true));
}
-TEST(TilingDataTest, NumTiles_TilingNoBorders) {
- EXPECT_EQ(0, NumTiles(gfx::Size(0, 0), gfx::Size(0, 0), false));
- EXPECT_EQ(0, NumTiles(gfx::Size(0, 0), gfx::Size(4, 0), false));
- EXPECT_EQ(0, NumTiles(gfx::Size(0, 0), gfx::Size(0, 4), false));
- EXPECT_EQ(0, NumTiles(gfx::Size(4, 4), gfx::Size(4, 0), false));
- EXPECT_EQ(0, NumTiles(gfx::Size(4, 4), gfx::Size(0, 4), false));
- EXPECT_EQ(0, NumTiles(gfx::Size(0, 0), gfx::Size(1, 1), false));
-
- EXPECT_EQ(1, NumTiles(gfx::Size(1, 1), gfx::Size(1, 1), false));
- EXPECT_EQ(2, NumTiles(gfx::Size(1, 1), gfx::Size(1, 2), false));
- EXPECT_EQ(2, NumTiles(gfx::Size(1, 1), gfx::Size(2, 1), false));
- EXPECT_EQ(1, NumTiles(gfx::Size(2, 2), gfx::Size(1, 1), false));
- EXPECT_EQ(1, NumTiles(gfx::Size(2, 2), gfx::Size(1, 2), false));
- EXPECT_EQ(1, NumTiles(gfx::Size(2, 2), gfx::Size(2, 1), false));
- EXPECT_EQ(1, NumTiles(gfx::Size(2, 2), gfx::Size(2, 2), false));
- EXPECT_EQ(1, NumTiles(gfx::Size(3, 3), gfx::Size(3, 3), false));
-
- EXPECT_EQ(1, NumTiles(gfx::Size(4, 4), gfx::Size(1, 4), false));
- EXPECT_EQ(1, NumTiles(gfx::Size(4, 4), gfx::Size(2, 4), false));
- EXPECT_EQ(1, NumTiles(gfx::Size(4, 4), gfx::Size(3, 4), false));
- EXPECT_EQ(1, NumTiles(gfx::Size(4, 4), gfx::Size(4, 4), false));
- EXPECT_EQ(2, NumTiles(gfx::Size(4, 4), gfx::Size(5, 4), false));
- EXPECT_EQ(2, NumTiles(gfx::Size(4, 4), gfx::Size(6, 4), false));
- EXPECT_EQ(2, NumTiles(gfx::Size(4, 4), gfx::Size(7, 4), false));
- EXPECT_EQ(2, NumTiles(gfx::Size(4, 4), gfx::Size(8, 4), false));
- EXPECT_EQ(3, NumTiles(gfx::Size(4, 4), gfx::Size(9, 4), false));
- EXPECT_EQ(3, NumTiles(gfx::Size(4, 4), gfx::Size(10, 4), false));
- EXPECT_EQ(3, NumTiles(gfx::Size(4, 4), gfx::Size(11, 4), false));
-
- EXPECT_EQ(1, NumTiles(gfx::Size(5, 5), gfx::Size(1, 5), false));
- EXPECT_EQ(1, NumTiles(gfx::Size(5, 5), gfx::Size(2, 5), false));
- EXPECT_EQ(1, NumTiles(gfx::Size(5, 5), gfx::Size(3, 5), false));
- EXPECT_EQ(1, NumTiles(gfx::Size(5, 5), gfx::Size(4, 5), false));
- EXPECT_EQ(1, NumTiles(gfx::Size(5, 5), gfx::Size(5, 5), false));
- EXPECT_EQ(2, NumTiles(gfx::Size(5, 5), gfx::Size(6, 5), false));
- EXPECT_EQ(2, NumTiles(gfx::Size(5, 5), gfx::Size(7, 5), false));
- EXPECT_EQ(2, NumTiles(gfx::Size(5, 5), gfx::Size(8, 5), false));
- EXPECT_EQ(2, NumTiles(gfx::Size(5, 5), gfx::Size(9, 5), false));
- EXPECT_EQ(2, NumTiles(gfx::Size(5, 5), gfx::Size(10, 5), false));
- EXPECT_EQ(3, NumTiles(gfx::Size(5, 5), gfx::Size(11, 5), false));
-
- EXPECT_EQ(1, NumTiles(gfx::Size(16, 16), gfx::Size(16, 16), false));
- EXPECT_EQ(1, NumTiles(gfx::Size(17, 17), gfx::Size(16, 16), false));
- EXPECT_EQ(4, NumTiles(gfx::Size(15, 15), gfx::Size(16, 16), false));
- EXPECT_EQ(4, NumTiles(gfx::Size(8, 8), gfx::Size(16, 16), false));
- EXPECT_EQ(6, NumTiles(gfx::Size(8, 8), gfx::Size(17, 16), false));
-
- EXPECT_EQ(8, NumTiles(gfx::Size(5, 8), gfx::Size(17, 16), false));
+TEST_P(TilingDataTest, NumTiles_TilingNoBorders) {
+ gfx::Point origin = GetParam();
+
+ EXPECT_EQ(
+ 0, NumTiles(gfx::Size(0, 0), gfx::Rect(origin, gfx::Size(0, 0)), false));
+ EXPECT_EQ(
+ 0, NumTiles(gfx::Size(0, 0), gfx::Rect(origin, gfx::Size(4, 0)), false));
+ EXPECT_EQ(
+ 0, NumTiles(gfx::Size(0, 0), gfx::Rect(origin, gfx::Size(0, 4)), false));
+ EXPECT_EQ(
+ 0, NumTiles(gfx::Size(4, 4), gfx::Rect(origin, gfx::Size(4, 0)), false));
+ EXPECT_EQ(
+ 0, NumTiles(gfx::Size(4, 4), gfx::Rect(origin, gfx::Size(0, 4)), false));
+ EXPECT_EQ(
+ 0, NumTiles(gfx::Size(0, 0), gfx::Rect(origin, gfx::Size(1, 1)), false));
+
+ EXPECT_EQ(
+ 1, NumTiles(gfx::Size(1, 1), gfx::Rect(origin, gfx::Size(1, 1)), false));
+ EXPECT_EQ(
+ 2, NumTiles(gfx::Size(1, 1), gfx::Rect(origin, gfx::Size(1, 2)), false));
+ EXPECT_EQ(
+ 2, NumTiles(gfx::Size(1, 1), gfx::Rect(origin, gfx::Size(2, 1)), false));
+ EXPECT_EQ(
+ 1, NumTiles(gfx::Size(2, 2), gfx::Rect(origin, gfx::Size(1, 1)), false));
+ EXPECT_EQ(
+ 1, NumTiles(gfx::Size(2, 2), gfx::Rect(origin, gfx::Size(1, 2)), false));
+ EXPECT_EQ(
+ 1, NumTiles(gfx::Size(2, 2), gfx::Rect(origin, gfx::Size(2, 1)), false));
+ EXPECT_EQ(
+ 1, NumTiles(gfx::Size(2, 2), gfx::Rect(origin, gfx::Size(2, 2)), false));
+ EXPECT_EQ(
+ 1, NumTiles(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(3, 3)), false));
+
+ EXPECT_EQ(
+ 1, NumTiles(gfx::Size(4, 4), gfx::Rect(origin, gfx::Size(1, 4)), false));
+ EXPECT_EQ(
+ 1, NumTiles(gfx::Size(4, 4), gfx::Rect(origin, gfx::Size(2, 4)), false));
+ EXPECT_EQ(
+ 1, NumTiles(gfx::Size(4, 4), gfx::Rect(origin, gfx::Size(3, 4)), false));
+ EXPECT_EQ(
+ 1, NumTiles(gfx::Size(4, 4), gfx::Rect(origin, gfx::Size(4, 4)), false));
+ EXPECT_EQ(
+ 2, NumTiles(gfx::Size(4, 4), gfx::Rect(origin, gfx::Size(5, 4)), false));
+ EXPECT_EQ(
+ 2, NumTiles(gfx::Size(4, 4), gfx::Rect(origin, gfx::Size(6, 4)), false));
+ EXPECT_EQ(
+ 2, NumTiles(gfx::Size(4, 4), gfx::Rect(origin, gfx::Size(7, 4)), false));
+ EXPECT_EQ(
+ 2, NumTiles(gfx::Size(4, 4), gfx::Rect(origin, gfx::Size(8, 4)), false));
+ EXPECT_EQ(
+ 3, NumTiles(gfx::Size(4, 4), gfx::Rect(origin, gfx::Size(9, 4)), false));
+ EXPECT_EQ(
+ 3, NumTiles(gfx::Size(4, 4), gfx::Rect(origin, gfx::Size(10, 4)), false));
+ EXPECT_EQ(
+ 3, NumTiles(gfx::Size(4, 4), gfx::Rect(origin, gfx::Size(11, 4)), false));
+
+ EXPECT_EQ(
+ 1, NumTiles(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(1, 5)), false));
+ EXPECT_EQ(
+ 1, NumTiles(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(2, 5)), false));
+ EXPECT_EQ(
+ 1, NumTiles(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(3, 5)), false));
+ EXPECT_EQ(
+ 1, NumTiles(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(4, 5)), false));
+ EXPECT_EQ(
+ 1, NumTiles(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(5, 5)), false));
+ EXPECT_EQ(
+ 2, NumTiles(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(6, 5)), false));
+ EXPECT_EQ(
+ 2, NumTiles(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(7, 5)), false));
+ EXPECT_EQ(
+ 2, NumTiles(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(8, 5)), false));
+ EXPECT_EQ(
+ 2, NumTiles(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(9, 5)), false));
+ EXPECT_EQ(
+ 2, NumTiles(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(10, 5)), false));
+ EXPECT_EQ(
+ 3, NumTiles(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(11, 5)), false));
+
+ EXPECT_EQ(
+ 1,
+ NumTiles(gfx::Size(16, 16), gfx::Rect(origin, gfx::Size(16, 16)), false));
+ EXPECT_EQ(
+ 1,
+ NumTiles(gfx::Size(17, 17), gfx::Rect(origin, gfx::Size(16, 16)), false));
+ EXPECT_EQ(
+ 4,
+ NumTiles(gfx::Size(15, 15), gfx::Rect(origin, gfx::Size(16, 16)), false));
+ EXPECT_EQ(
+ 4,
+ NumTiles(gfx::Size(8, 8), gfx::Rect(origin, gfx::Size(16, 16)), false));
+ EXPECT_EQ(
+ 6,
+ NumTiles(gfx::Size(8, 8), gfx::Rect(origin, gfx::Size(17, 16)), false));
+
+ EXPECT_EQ(
+ 8,
+ NumTiles(gfx::Size(5, 8), gfx::Rect(origin, gfx::Size(17, 16)), false));
}
-TEST(TilingDataTest, NumTiles_TilingWithBorders) {
- EXPECT_EQ(0, NumTiles(gfx::Size(0, 0), gfx::Size(0, 0), true));
- EXPECT_EQ(0, NumTiles(gfx::Size(0, 0), gfx::Size(4, 0), true));
- EXPECT_EQ(0, NumTiles(gfx::Size(0, 0), gfx::Size(0, 4), true));
- EXPECT_EQ(0, NumTiles(gfx::Size(4, 4), gfx::Size(4, 0), true));
- EXPECT_EQ(0, NumTiles(gfx::Size(4, 4), gfx::Size(0, 4), true));
- EXPECT_EQ(0, NumTiles(gfx::Size(0, 0), gfx::Size(1, 1), true));
-
- EXPECT_EQ(1, NumTiles(gfx::Size(1, 1), gfx::Size(1, 1), true));
- EXPECT_EQ(0, NumTiles(gfx::Size(1, 1), gfx::Size(1, 2), true));
- EXPECT_EQ(0, NumTiles(gfx::Size(1, 1), gfx::Size(2, 1), true));
- EXPECT_EQ(1, NumTiles(gfx::Size(2, 2), gfx::Size(1, 1), true));
- EXPECT_EQ(1, NumTiles(gfx::Size(2, 2), gfx::Size(1, 2), true));
- EXPECT_EQ(1, NumTiles(gfx::Size(2, 2), gfx::Size(2, 1), true));
- EXPECT_EQ(1, NumTiles(gfx::Size(2, 2), gfx::Size(2, 2), true));
-
- EXPECT_EQ(1, NumTiles(gfx::Size(3, 3), gfx::Size(1, 3), true));
- EXPECT_EQ(1, NumTiles(gfx::Size(3, 3), gfx::Size(2, 3), true));
- EXPECT_EQ(1, NumTiles(gfx::Size(3, 3), gfx::Size(3, 3), true));
- EXPECT_EQ(2, NumTiles(gfx::Size(3, 3), gfx::Size(4, 3), true));
- EXPECT_EQ(3, NumTiles(gfx::Size(3, 3), gfx::Size(5, 3), true));
- EXPECT_EQ(4, NumTiles(gfx::Size(3, 3), gfx::Size(6, 3), true));
- EXPECT_EQ(5, NumTiles(gfx::Size(3, 3), gfx::Size(7, 3), true));
-
- EXPECT_EQ(1, NumTiles(gfx::Size(4, 4), gfx::Size(1, 4), true));
- EXPECT_EQ(1, NumTiles(gfx::Size(4, 4), gfx::Size(2, 4), true));
- EXPECT_EQ(1, NumTiles(gfx::Size(4, 4), gfx::Size(3, 4), true));
- EXPECT_EQ(1, NumTiles(gfx::Size(4, 4), gfx::Size(4, 4), true));
- EXPECT_EQ(2, NumTiles(gfx::Size(4, 4), gfx::Size(5, 4), true));
- EXPECT_EQ(2, NumTiles(gfx::Size(4, 4), gfx::Size(6, 4), true));
- EXPECT_EQ(3, NumTiles(gfx::Size(4, 4), gfx::Size(7, 4), true));
- EXPECT_EQ(3, NumTiles(gfx::Size(4, 4), gfx::Size(8, 4), true));
- EXPECT_EQ(4, NumTiles(gfx::Size(4, 4), gfx::Size(9, 4), true));
- EXPECT_EQ(4, NumTiles(gfx::Size(4, 4), gfx::Size(10, 4), true));
- EXPECT_EQ(5, NumTiles(gfx::Size(4, 4), gfx::Size(11, 4), true));
-
- EXPECT_EQ(1, NumTiles(gfx::Size(5, 5), gfx::Size(1, 5), true));
- EXPECT_EQ(1, NumTiles(gfx::Size(5, 5), gfx::Size(2, 5), true));
- EXPECT_EQ(1, NumTiles(gfx::Size(5, 5), gfx::Size(3, 5), true));
- EXPECT_EQ(1, NumTiles(gfx::Size(5, 5), gfx::Size(4, 5), true));
- EXPECT_EQ(1, NumTiles(gfx::Size(5, 5), gfx::Size(5, 5), true));
- EXPECT_EQ(2, NumTiles(gfx::Size(5, 5), gfx::Size(6, 5), true));
- EXPECT_EQ(2, NumTiles(gfx::Size(5, 5), gfx::Size(7, 5), true));
- EXPECT_EQ(2, NumTiles(gfx::Size(5, 5), gfx::Size(8, 5), true));
- EXPECT_EQ(3, NumTiles(gfx::Size(5, 5), gfx::Size(9, 5), true));
- EXPECT_EQ(3, NumTiles(gfx::Size(5, 5), gfx::Size(10, 5), true));
- EXPECT_EQ(3, NumTiles(gfx::Size(5, 5), gfx::Size(11, 5), true));
-
- EXPECT_EQ(30, NumTiles(gfx::Size(8, 5), gfx::Size(16, 32), true));
+TEST_P(TilingDataTest, NumTiles_TilingWithBorders) {
+ gfx::Point origin = GetParam();
+
+ EXPECT_EQ(
+ 0, NumTiles(gfx::Size(0, 0), gfx::Rect(origin, gfx::Size(0, 0)), true));
+ EXPECT_EQ(
+ 0, NumTiles(gfx::Size(0, 0), gfx::Rect(origin, gfx::Size(4, 0)), true));
+ EXPECT_EQ(
+ 0, NumTiles(gfx::Size(0, 0), gfx::Rect(origin, gfx::Size(0, 4)), true));
+ EXPECT_EQ(
+ 0, NumTiles(gfx::Size(4, 4), gfx::Rect(origin, gfx::Size(4, 0)), true));
+ EXPECT_EQ(
+ 0, NumTiles(gfx::Size(4, 4), gfx::Rect(origin, gfx::Size(0, 4)), true));
+ EXPECT_EQ(
+ 0, NumTiles(gfx::Size(0, 0), gfx::Rect(origin, gfx::Size(1, 1)), true));
+
+ EXPECT_EQ(
+ 1, NumTiles(gfx::Size(1, 1), gfx::Rect(origin, gfx::Size(1, 1)), true));
+ EXPECT_EQ(
+ 0, NumTiles(gfx::Size(1, 1), gfx::Rect(origin, gfx::Size(1, 2)), true));
+ EXPECT_EQ(
+ 0, NumTiles(gfx::Size(1, 1), gfx::Rect(origin, gfx::Size(2, 1)), true));
+ EXPECT_EQ(
+ 1, NumTiles(gfx::Size(2, 2), gfx::Rect(origin, gfx::Size(1, 1)), true));
+ EXPECT_EQ(
+ 1, NumTiles(gfx::Size(2, 2), gfx::Rect(origin, gfx::Size(1, 2)), true));
+ EXPECT_EQ(
+ 1, NumTiles(gfx::Size(2, 2), gfx::Rect(origin, gfx::Size(2, 1)), true));
+ EXPECT_EQ(
+ 1, NumTiles(gfx::Size(2, 2), gfx::Rect(origin, gfx::Size(2, 2)), true));
+
+ EXPECT_EQ(
+ 1, NumTiles(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(1, 3)), true));
+ EXPECT_EQ(
+ 1, NumTiles(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(2, 3)), true));
+ EXPECT_EQ(
+ 1, NumTiles(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(3, 3)), true));
+ EXPECT_EQ(
+ 2, NumTiles(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(4, 3)), true));
+ EXPECT_EQ(
+ 3, NumTiles(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(5, 3)), true));
+ EXPECT_EQ(
+ 4, NumTiles(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(6, 3)), true));
+ EXPECT_EQ(
+ 5, NumTiles(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(7, 3)), true));
+
+ EXPECT_EQ(
+ 1, NumTiles(gfx::Size(4, 4), gfx::Rect(origin, gfx::Size(1, 4)), true));
+ EXPECT_EQ(
+ 1, NumTiles(gfx::Size(4, 4), gfx::Rect(origin, gfx::Size(2, 4)), true));
+ EXPECT_EQ(
+ 1, NumTiles(gfx::Size(4, 4), gfx::Rect(origin, gfx::Size(3, 4)), true));
+ EXPECT_EQ(
+ 1, NumTiles(gfx::Size(4, 4), gfx::Rect(origin, gfx::Size(4, 4)), true));
+ EXPECT_EQ(
+ 2, NumTiles(gfx::Size(4, 4), gfx::Rect(origin, gfx::Size(5, 4)), true));
+ EXPECT_EQ(
+ 2, NumTiles(gfx::Size(4, 4), gfx::Rect(origin, gfx::Size(6, 4)), true));
+ EXPECT_EQ(
+ 3, NumTiles(gfx::Size(4, 4), gfx::Rect(origin, gfx::Size(7, 4)), true));
+ EXPECT_EQ(
+ 3, NumTiles(gfx::Size(4, 4), gfx::Rect(origin, gfx::Size(8, 4)), true));
+ EXPECT_EQ(
+ 4, NumTiles(gfx::Size(4, 4), gfx::Rect(origin, gfx::Size(9, 4)), true));
+ EXPECT_EQ(
+ 4, NumTiles(gfx::Size(4, 4), gfx::Rect(origin, gfx::Size(10, 4)), true));
+ EXPECT_EQ(
+ 5, NumTiles(gfx::Size(4, 4), gfx::Rect(origin, gfx::Size(11, 4)), true));
+
+ EXPECT_EQ(
+ 1, NumTiles(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(1, 5)), true));
+ EXPECT_EQ(
+ 1, NumTiles(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(2, 5)), true));
+ EXPECT_EQ(
+ 1, NumTiles(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(3, 5)), true));
+ EXPECT_EQ(
+ 1, NumTiles(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(4, 5)), true));
+ EXPECT_EQ(
+ 1, NumTiles(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(5, 5)), true));
+ EXPECT_EQ(
+ 2, NumTiles(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(6, 5)), true));
+ EXPECT_EQ(
+ 2, NumTiles(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(7, 5)), true));
+ EXPECT_EQ(
+ 2, NumTiles(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(8, 5)), true));
+ EXPECT_EQ(
+ 3, NumTiles(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(9, 5)), true));
+ EXPECT_EQ(
+ 3, NumTiles(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(10, 5)), true));
+ EXPECT_EQ(
+ 3, NumTiles(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(11, 5)), true));
+
+ EXPECT_EQ(
+ 30,
+ NumTiles(gfx::Size(8, 5), gfx::Rect(origin, gfx::Size(16, 32)), true));
}
-TEST(TilingDataTest, TileXIndexFromSrcCoord) {
- EXPECT_EQ(0, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 0));
- EXPECT_EQ(0, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 1));
- EXPECT_EQ(0, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 2));
- EXPECT_EQ(1, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 3));
- EXPECT_EQ(1, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 4));
- EXPECT_EQ(1, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 5));
- EXPECT_EQ(2, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 6));
- EXPECT_EQ(2, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 7));
- EXPECT_EQ(2, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 8));
- EXPECT_EQ(3, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 9));
- EXPECT_EQ(3, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 10));
- EXPECT_EQ(3, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 11));
-
- EXPECT_EQ(0, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 0));
- EXPECT_EQ(0, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 1));
- EXPECT_EQ(1, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 2));
- EXPECT_EQ(2, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 3));
- EXPECT_EQ(3, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 4));
- EXPECT_EQ(4, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 5));
- EXPECT_EQ(5, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 6));
- EXPECT_EQ(6, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 7));
- EXPECT_EQ(7, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 8));
- EXPECT_EQ(7, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 9));
- EXPECT_EQ(7, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 10));
- EXPECT_EQ(7, XIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 11));
-
- EXPECT_EQ(0, XIndex(gfx::Size(1, 1), gfx::Size(1, 1), false, 0));
- EXPECT_EQ(0, XIndex(gfx::Size(2, 2), gfx::Size(2, 2), false, 0));
- EXPECT_EQ(0, XIndex(gfx::Size(2, 2), gfx::Size(2, 2), false, 1));
- EXPECT_EQ(0, XIndex(gfx::Size(3, 3), gfx::Size(3, 3), false, 0));
- EXPECT_EQ(0, XIndex(gfx::Size(3, 3), gfx::Size(3, 3), false, 1));
- EXPECT_EQ(0, XIndex(gfx::Size(3, 3), gfx::Size(3, 3), false, 2));
-
- EXPECT_EQ(0, XIndex(gfx::Size(3, 3), gfx::Size(4, 3), false, 0));
- EXPECT_EQ(0, XIndex(gfx::Size(3, 3), gfx::Size(4, 3), false, 1));
- EXPECT_EQ(0, XIndex(gfx::Size(3, 3), gfx::Size(4, 3), false, 2));
- EXPECT_EQ(1, XIndex(gfx::Size(3, 3), gfx::Size(4, 3), false, 3));
-
- EXPECT_EQ(0, XIndex(gfx::Size(1, 1), gfx::Size(1, 1), true, 0));
- EXPECT_EQ(0, XIndex(gfx::Size(2, 2), gfx::Size(2, 2), true, 0));
- EXPECT_EQ(0, XIndex(gfx::Size(2, 2), gfx::Size(2, 2), true, 1));
- EXPECT_EQ(0, XIndex(gfx::Size(3, 3), gfx::Size(3, 3), true, 0));
- EXPECT_EQ(0, XIndex(gfx::Size(3, 3), gfx::Size(3, 3), true, 1));
- EXPECT_EQ(0, XIndex(gfx::Size(3, 3), gfx::Size(3, 3), true, 2));
-
- EXPECT_EQ(0, XIndex(gfx::Size(3, 3), gfx::Size(4, 3), true, 0));
- EXPECT_EQ(0, XIndex(gfx::Size(3, 3), gfx::Size(4, 3), true, 1));
- EXPECT_EQ(1, XIndex(gfx::Size(3, 3), gfx::Size(4, 3), true, 2));
- EXPECT_EQ(1, XIndex(gfx::Size(3, 3), gfx::Size(4, 3), true, 3));
+TEST_P(TilingDataTest, TileXIndexFromSrcCoord) {
+ gfx::Point origin = GetParam();
+
+ EXPECT_EQ(0,
+ XIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.x() + 0));
+ EXPECT_EQ(0,
+ XIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.x() + 1));
+ EXPECT_EQ(0,
+ XIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.x() + 2));
+ EXPECT_EQ(1,
+ XIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.x() + 3));
+ EXPECT_EQ(1,
+ XIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.x() + 4));
+ EXPECT_EQ(1,
+ XIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.x() + 5));
+ EXPECT_EQ(2,
+ XIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.x() + 6));
+ EXPECT_EQ(2,
+ XIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.x() + 7));
+ EXPECT_EQ(2,
+ XIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.x() + 8));
+ EXPECT_EQ(3,
+ XIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.x() + 9));
+ EXPECT_EQ(3,
+ XIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.x() + 10));
+ EXPECT_EQ(3,
+ XIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.x() + 11));
+
+ EXPECT_EQ(0,
+ XIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.x()));
+ EXPECT_EQ(0,
+ XIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.x() + 1));
+ EXPECT_EQ(1,
+ XIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.x() + 2));
+ EXPECT_EQ(2,
+ XIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.x() + 3));
+ EXPECT_EQ(3,
+ XIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.x() + 4));
+ EXPECT_EQ(4,
+ XIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.x() + 5));
+ EXPECT_EQ(5,
+ XIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.x() + 6));
+ EXPECT_EQ(6,
+ XIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.x() + 7));
+ EXPECT_EQ(7,
+ XIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.x() + 8));
+ EXPECT_EQ(7,
+ XIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.x() + 9));
+ EXPECT_EQ(7,
+ XIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.x() + 10));
+ EXPECT_EQ(7,
+ XIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.x() + 11));
+
+ EXPECT_EQ(0,
+ XIndex(gfx::Size(1, 1),
+ gfx::Rect(origin, gfx::Size(1, 1)),
+ false,
+ origin.x() + 0));
+ EXPECT_EQ(0,
+ XIndex(gfx::Size(2, 2),
+ gfx::Rect(origin, gfx::Size(2, 2)),
+ false,
+ origin.x() + 0));
+ EXPECT_EQ(0,
+ XIndex(gfx::Size(2, 2),
+ gfx::Rect(origin, gfx::Size(2, 2)),
+ false,
+ origin.x() + 1));
+ EXPECT_EQ(0,
+ XIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 3)),
+ false,
+ origin.x() + 0));
+ EXPECT_EQ(0,
+ XIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 3)),
+ false,
+ origin.x() + 1));
+ EXPECT_EQ(0,
+ XIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 3)),
+ false,
+ origin.x() + 2));
+
+ EXPECT_EQ(0,
+ XIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(4, 3)),
+ false,
+ origin.x() + 0));
+ EXPECT_EQ(0,
+ XIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(4, 3)),
+ false,
+ origin.x() + 1));
+ EXPECT_EQ(0,
+ XIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(4, 3)),
+ false,
+ origin.x() + 2));
+ EXPECT_EQ(1,
+ XIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(4, 3)),
+ false,
+ origin.x() + 3));
+
+ EXPECT_EQ(0,
+ XIndex(gfx::Size(1, 1),
+ gfx::Rect(origin, gfx::Size(1, 1)),
+ true,
+ origin.x() + 0));
+ EXPECT_EQ(0,
+ XIndex(gfx::Size(2, 2),
+ gfx::Rect(origin, gfx::Size(2, 2)),
+ true,
+ origin.x() + 0));
+ EXPECT_EQ(0,
+ XIndex(gfx::Size(2, 2),
+ gfx::Rect(origin, gfx::Size(2, 2)),
+ true,
+ origin.x() + 1));
+ EXPECT_EQ(0,
+ XIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 3)),
+ true,
+ origin.x() + 0));
+ EXPECT_EQ(0,
+ XIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 3)),
+ true,
+ origin.x() + 1));
+ EXPECT_EQ(0,
+ XIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 3)),
+ true,
+ origin.x() + 2));
+
+ EXPECT_EQ(0,
+ XIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(4, 3)),
+ true,
+ origin.x() + 0));
+ EXPECT_EQ(0,
+ XIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(4, 3)),
+ true,
+ origin.x() + 1));
+ EXPECT_EQ(1,
+ XIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(4, 3)),
+ true,
+ origin.x() + 2));
+ EXPECT_EQ(1,
+ XIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(4, 3)),
+ true,
+ origin.x() + 3));
}
-TEST(TilingDataTest, FirstBorderTileXIndexFromSrcCoord) {
- EXPECT_EQ(0, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 0));
- EXPECT_EQ(0, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 1));
- EXPECT_EQ(0, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 2));
- EXPECT_EQ(1, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 3));
- EXPECT_EQ(1, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 4));
- EXPECT_EQ(1, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 5));
- EXPECT_EQ(2, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 6));
- EXPECT_EQ(2, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 7));
- EXPECT_EQ(2, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 8));
- EXPECT_EQ(3, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 9));
- EXPECT_EQ(3, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 10));
- EXPECT_EQ(3, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 11));
-
- EXPECT_EQ(0, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 0));
- EXPECT_EQ(0, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 1));
- EXPECT_EQ(0, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 2));
- EXPECT_EQ(1, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 3));
- EXPECT_EQ(2, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 4));
- EXPECT_EQ(3, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 5));
- EXPECT_EQ(4, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 6));
- EXPECT_EQ(5, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 7));
- EXPECT_EQ(6, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 8));
- EXPECT_EQ(7, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 9));
- EXPECT_EQ(7, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 10));
- EXPECT_EQ(7, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 11));
-
- EXPECT_EQ(0, MinBorderXIndex(gfx::Size(1, 1), gfx::Size(1, 1), false, 0));
- EXPECT_EQ(0, MinBorderXIndex(gfx::Size(2, 2), gfx::Size(2, 2), false, 0));
- EXPECT_EQ(0, MinBorderXIndex(gfx::Size(2, 2), gfx::Size(2, 2), false, 1));
- EXPECT_EQ(0, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(3, 3), false, 0));
- EXPECT_EQ(0, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(3, 3), false, 1));
- EXPECT_EQ(0, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(3, 3), false, 2));
-
- EXPECT_EQ(0, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(4, 3), false, 0));
- EXPECT_EQ(0, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(4, 3), false, 1));
- EXPECT_EQ(0, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(4, 3), false, 2));
- EXPECT_EQ(1, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(4, 3), false, 3));
-
- EXPECT_EQ(0, MinBorderXIndex(gfx::Size(1, 1), gfx::Size(1, 1), true, 0));
- EXPECT_EQ(0, MinBorderXIndex(gfx::Size(2, 2), gfx::Size(2, 2), true, 0));
- EXPECT_EQ(0, MinBorderXIndex(gfx::Size(2, 2), gfx::Size(2, 2), true, 1));
- EXPECT_EQ(0, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(3, 3), true, 0));
- EXPECT_EQ(0, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(3, 3), true, 1));
- EXPECT_EQ(0, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(3, 3), true, 2));
-
- EXPECT_EQ(0, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(4, 3), true, 0));
- EXPECT_EQ(0, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(4, 3), true, 1));
- EXPECT_EQ(0, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(4, 3), true, 2));
- EXPECT_EQ(1, MinBorderXIndex(gfx::Size(3, 3), gfx::Size(4, 3), true, 3));
+TEST_P(TilingDataTest, FirstBorderTileXIndexFromSrcCoord) {
+ gfx::Point origin = GetParam();
+
+ EXPECT_EQ(0,
+ MinBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.x() + 0));
+ EXPECT_EQ(0,
+ MinBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.x() + 1));
+ EXPECT_EQ(0,
+ MinBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.x() + 2));
+ EXPECT_EQ(1,
+ MinBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.x() + 3));
+ EXPECT_EQ(1,
+ MinBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.x() + 4));
+ EXPECT_EQ(1,
+ MinBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.x() + 5));
+ EXPECT_EQ(2,
+ MinBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.x() + 6));
+ EXPECT_EQ(2,
+ MinBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.x() + 7));
+ EXPECT_EQ(2,
+ MinBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.x() + 8));
+ EXPECT_EQ(3,
+ MinBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.x() + 9));
+ EXPECT_EQ(3,
+ MinBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.x() + 10));
+ EXPECT_EQ(3,
+ MinBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.x() + 11));
+
+ EXPECT_EQ(0,
+ MinBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.x() + 0));
+ EXPECT_EQ(0,
+ MinBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.x() + 1));
+ EXPECT_EQ(0,
+ MinBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.x() + 2));
+ EXPECT_EQ(1,
+ MinBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.x() + 3));
+ EXPECT_EQ(2,
+ MinBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.x() + 4));
+ EXPECT_EQ(3,
+ MinBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.x() + 5));
+ EXPECT_EQ(4,
+ MinBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.x() + 6));
+ EXPECT_EQ(5,
+ MinBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.x() + 7));
+ EXPECT_EQ(6,
+ MinBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.x() + 8));
+ EXPECT_EQ(7,
+ MinBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.x() + 9));
+ EXPECT_EQ(7,
+ MinBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.x() + 10));
+ EXPECT_EQ(7,
+ MinBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.x() + 11));
+
+ EXPECT_EQ(0,
+ MinBorderXIndex(gfx::Size(1, 1),
+ gfx::Rect(origin, gfx::Size(1, 1)),
+ false,
+ origin.x() + 0));
+ EXPECT_EQ(0,
+ MinBorderXIndex(gfx::Size(2, 2),
+ gfx::Rect(origin, gfx::Size(2, 2)),
+ false,
+ origin.x() + 0));
+ EXPECT_EQ(0,
+ MinBorderXIndex(gfx::Size(2, 2),
+ gfx::Rect(origin, gfx::Size(2, 2)),
+ false,
+ origin.x() + 1));
+ EXPECT_EQ(0,
+ MinBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 3)),
+ false,
+ origin.x() + 0));
+ EXPECT_EQ(0,
+ MinBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 3)),
+ false,
+ origin.x() + 1));
+ EXPECT_EQ(0,
+ MinBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 3)),
+ false,
+ origin.x() + 2));
+
+ EXPECT_EQ(0,
+ MinBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(4, 3)),
+ false,
+ origin.x() + 0));
+ EXPECT_EQ(0,
+ MinBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(4, 3)),
+ false,
+ origin.x() + 1));
+ EXPECT_EQ(0,
+ MinBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(4, 3)),
+ false,
+ origin.x() + 2));
+ EXPECT_EQ(1,
+ MinBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(4, 3)),
+ false,
+ origin.x() + 3));
+
+ EXPECT_EQ(0,
+ MinBorderXIndex(gfx::Size(1, 1),
+ gfx::Rect(origin, gfx::Size(1, 1)),
+ true,
+ origin.x() + 0));
+ EXPECT_EQ(0,
+ MinBorderXIndex(gfx::Size(2, 2),
+ gfx::Rect(origin, gfx::Size(2, 2)),
+ true,
+ origin.x() + 0));
+ EXPECT_EQ(0,
+ MinBorderXIndex(gfx::Size(2, 2),
+ gfx::Rect(origin, gfx::Size(2, 2)),
+ true,
+ origin.x() + 1));
+ EXPECT_EQ(0,
+ MinBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 3)),
+ true,
+ origin.x() + 0));
+ EXPECT_EQ(0,
+ MinBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 3)),
+ true,
+ origin.x() + 1));
+ EXPECT_EQ(0,
+ MinBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 3)),
+ true,
+ origin.x() + 2));
+
+ EXPECT_EQ(0,
+ MinBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(4, 3)),
+ true,
+ origin.x() + 0));
+ EXPECT_EQ(0,
+ MinBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(4, 3)),
+ true,
+ origin.x() + 1));
+ EXPECT_EQ(0,
+ MinBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(4, 3)),
+ true,
+ origin.x() + 2));
+ EXPECT_EQ(1,
+ MinBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(4, 3)),
+ true,
+ origin.x() + 3));
}
-TEST(TilingDataTest, LastBorderTileXIndexFromSrcCoord) {
- EXPECT_EQ(0, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 0));
- EXPECT_EQ(0, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 1));
- EXPECT_EQ(0, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 2));
- EXPECT_EQ(1, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 3));
- EXPECT_EQ(1, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 4));
- EXPECT_EQ(1, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 5));
- EXPECT_EQ(2, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 6));
- EXPECT_EQ(2, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 7));
- EXPECT_EQ(2, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 8));
- EXPECT_EQ(3, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 9));
- EXPECT_EQ(3, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 10));
- EXPECT_EQ(3, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 11));
-
- EXPECT_EQ(0, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 0));
- EXPECT_EQ(1, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 1));
- EXPECT_EQ(2, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 2));
- EXPECT_EQ(3, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 3));
- EXPECT_EQ(4, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 4));
- EXPECT_EQ(5, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 5));
- EXPECT_EQ(6, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 6));
- EXPECT_EQ(7, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 7));
- EXPECT_EQ(7, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 8));
- EXPECT_EQ(7, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 9));
- EXPECT_EQ(7, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 10));
- EXPECT_EQ(7, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 11));
-
- EXPECT_EQ(0, MaxBorderXIndex(gfx::Size(1, 1), gfx::Size(1, 1), false, 0));
- EXPECT_EQ(0, MaxBorderXIndex(gfx::Size(2, 2), gfx::Size(2, 2), false, 0));
- EXPECT_EQ(0, MaxBorderXIndex(gfx::Size(2, 2), gfx::Size(2, 2), false, 1));
- EXPECT_EQ(0, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(3, 3), false, 0));
- EXPECT_EQ(0, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(3, 3), false, 1));
- EXPECT_EQ(0, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(3, 3), false, 2));
-
- EXPECT_EQ(0, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(4, 3), false, 0));
- EXPECT_EQ(0, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(4, 3), false, 1));
- EXPECT_EQ(0, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(4, 3), false, 2));
- EXPECT_EQ(1, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(4, 3), false, 3));
-
- EXPECT_EQ(0, MaxBorderXIndex(gfx::Size(1, 1), gfx::Size(1, 1), true, 0));
- EXPECT_EQ(0, MaxBorderXIndex(gfx::Size(2, 2), gfx::Size(2, 2), true, 0));
- EXPECT_EQ(0, MaxBorderXIndex(gfx::Size(2, 2), gfx::Size(2, 2), true, 1));
- EXPECT_EQ(0, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(3, 3), true, 0));
- EXPECT_EQ(0, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(3, 3), true, 1));
- EXPECT_EQ(0, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(3, 3), true, 2));
-
- EXPECT_EQ(0, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(4, 3), true, 0));
- EXPECT_EQ(1, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(4, 3), true, 1));
- EXPECT_EQ(1, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(4, 3), true, 2));
- EXPECT_EQ(1, MaxBorderXIndex(gfx::Size(3, 3), gfx::Size(4, 3), true, 3));
+TEST_P(TilingDataTest, LastBorderTileXIndexFromSrcCoord) {
+ gfx::Point origin = GetParam();
+
+ EXPECT_EQ(0,
+ MaxBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.x() + 0));
+ EXPECT_EQ(0,
+ MaxBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.x() + 1));
+ EXPECT_EQ(0,
+ MaxBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.x() + 2));
+ EXPECT_EQ(1,
+ MaxBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.x() + 3));
+ EXPECT_EQ(1,
+ MaxBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.x() + 4));
+ EXPECT_EQ(1,
+ MaxBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.x() + 5));
+ EXPECT_EQ(2,
+ MaxBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.x() + 6));
+ EXPECT_EQ(2,
+ MaxBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.x() + 7));
+ EXPECT_EQ(2,
+ MaxBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.x() + 8));
+ EXPECT_EQ(3,
+ MaxBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.x() + 9));
+ EXPECT_EQ(3,
+ MaxBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.x() + 10));
+ EXPECT_EQ(3,
+ MaxBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.x() + 11));
+
+ EXPECT_EQ(0,
+ MaxBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.x() + 0));
+ EXPECT_EQ(1,
+ MaxBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.x() + 1));
+ EXPECT_EQ(2,
+ MaxBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.x() + 2));
+ EXPECT_EQ(3,
+ MaxBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.x() + 3));
+ EXPECT_EQ(4,
+ MaxBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.x() + 4));
+ EXPECT_EQ(5,
+ MaxBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.x() + 5));
+ EXPECT_EQ(6,
+ MaxBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.x() + 6));
+ EXPECT_EQ(7,
+ MaxBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.x() + 7));
+ EXPECT_EQ(7,
+ MaxBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.x() + 8));
+ EXPECT_EQ(7,
+ MaxBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.x() + 9));
+ EXPECT_EQ(7,
+ MaxBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.x() + 10));
+ EXPECT_EQ(7,
+ MaxBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.x() + 11));
+
+ EXPECT_EQ(0,
+ MaxBorderXIndex(gfx::Size(1, 1),
+ gfx::Rect(origin, gfx::Size(1, 1)),
+ false,
+ origin.x() + 0));
+ EXPECT_EQ(0,
+ MaxBorderXIndex(gfx::Size(2, 2),
+ gfx::Rect(origin, gfx::Size(2, 2)),
+ false,
+ origin.x() + 0));
+ EXPECT_EQ(0,
+ MaxBorderXIndex(gfx::Size(2, 2),
+ gfx::Rect(origin, gfx::Size(2, 2)),
+ false,
+ origin.x() + 1));
+ EXPECT_EQ(0,
+ MaxBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 3)),
+ false,
+ origin.x() + 0));
+ EXPECT_EQ(0,
+ MaxBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 3)),
+ false,
+ origin.x() + 1));
+ EXPECT_EQ(0,
+ MaxBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 3)),
+ false,
+ origin.x() + 2));
+
+ EXPECT_EQ(0,
+ MaxBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(4, 3)),
+ false,
+ origin.x() + 0));
+ EXPECT_EQ(0,
+ MaxBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(4, 3)),
+ false,
+ origin.x() + 1));
+ EXPECT_EQ(0,
+ MaxBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(4, 3)),
+ false,
+ origin.x() + 2));
+ EXPECT_EQ(1,
+ MaxBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(4, 3)),
+ false,
+ origin.x() + 3));
+
+ EXPECT_EQ(0,
+ MaxBorderXIndex(gfx::Size(1, 1),
+ gfx::Rect(origin, gfx::Size(1, 1)),
+ true,
+ origin.x() + 0));
+ EXPECT_EQ(0,
+ MaxBorderXIndex(gfx::Size(2, 2),
+ gfx::Rect(origin, gfx::Size(2, 2)),
+ true,
+ origin.x() + 0));
+ EXPECT_EQ(0,
+ MaxBorderXIndex(gfx::Size(2, 2),
+ gfx::Rect(origin, gfx::Size(2, 2)),
+ true,
+ origin.x() + 1));
+ EXPECT_EQ(0,
+ MaxBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 3)),
+ true,
+ origin.x() + 0));
+ EXPECT_EQ(0,
+ MaxBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 3)),
+ true,
+ origin.x() + 1));
+ EXPECT_EQ(0,
+ MaxBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 3)),
+ true,
+ origin.x() + 2));
+
+ EXPECT_EQ(0,
+ MaxBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(4, 3)),
+ true,
+ origin.x() + 0));
+ EXPECT_EQ(1,
+ MaxBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(4, 3)),
+ true,
+ origin.x() + 1));
+ EXPECT_EQ(1,
+ MaxBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(4, 3)),
+ true,
+ origin.x() + 2));
+ EXPECT_EQ(1,
+ MaxBorderXIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(4, 3)),
+ true,
+ origin.x() + 3));
}
-TEST(TilingDataTest, TileYIndexFromSrcCoord) {
- EXPECT_EQ(0, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 0));
- EXPECT_EQ(0, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 1));
- EXPECT_EQ(0, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 2));
- EXPECT_EQ(1, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 3));
- EXPECT_EQ(1, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 4));
- EXPECT_EQ(1, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 5));
- EXPECT_EQ(2, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 6));
- EXPECT_EQ(2, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 7));
- EXPECT_EQ(2, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 8));
- EXPECT_EQ(3, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 9));
- EXPECT_EQ(3, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 10));
- EXPECT_EQ(3, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 11));
-
- EXPECT_EQ(0, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 0));
- EXPECT_EQ(0, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 1));
- EXPECT_EQ(1, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 2));
- EXPECT_EQ(2, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 3));
- EXPECT_EQ(3, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 4));
- EXPECT_EQ(4, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 5));
- EXPECT_EQ(5, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 6));
- EXPECT_EQ(6, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 7));
- EXPECT_EQ(7, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 8));
- EXPECT_EQ(7, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 9));
- EXPECT_EQ(7, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 10));
- EXPECT_EQ(7, YIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 11));
-
- EXPECT_EQ(0, YIndex(gfx::Size(1, 1), gfx::Size(1, 1), false, 0));
- EXPECT_EQ(0, YIndex(gfx::Size(2, 2), gfx::Size(2, 2), false, 0));
- EXPECT_EQ(0, YIndex(gfx::Size(2, 2), gfx::Size(2, 2), false, 1));
- EXPECT_EQ(0, YIndex(gfx::Size(3, 3), gfx::Size(3, 3), false, 0));
- EXPECT_EQ(0, YIndex(gfx::Size(3, 3), gfx::Size(3, 3), false, 1));
- EXPECT_EQ(0, YIndex(gfx::Size(3, 3), gfx::Size(3, 3), false, 2));
-
- EXPECT_EQ(0, YIndex(gfx::Size(3, 3), gfx::Size(3, 4), false, 0));
- EXPECT_EQ(0, YIndex(gfx::Size(3, 3), gfx::Size(3, 4), false, 1));
- EXPECT_EQ(0, YIndex(gfx::Size(3, 3), gfx::Size(3, 4), false, 2));
- EXPECT_EQ(1, YIndex(gfx::Size(3, 3), gfx::Size(3, 4), false, 3));
-
- EXPECT_EQ(0, YIndex(gfx::Size(1, 1), gfx::Size(1, 1), true, 0));
- EXPECT_EQ(0, YIndex(gfx::Size(2, 2), gfx::Size(2, 2), true, 0));
- EXPECT_EQ(0, YIndex(gfx::Size(2, 2), gfx::Size(2, 2), true, 1));
- EXPECT_EQ(0, YIndex(gfx::Size(3, 3), gfx::Size(3, 3), true, 0));
- EXPECT_EQ(0, YIndex(gfx::Size(3, 3), gfx::Size(3, 3), true, 1));
- EXPECT_EQ(0, YIndex(gfx::Size(3, 3), gfx::Size(3, 3), true, 2));
-
- EXPECT_EQ(0, YIndex(gfx::Size(3, 3), gfx::Size(3, 4), true, 0));
- EXPECT_EQ(0, YIndex(gfx::Size(3, 3), gfx::Size(3, 4), true, 1));
- EXPECT_EQ(1, YIndex(gfx::Size(3, 3), gfx::Size(3, 4), true, 2));
- EXPECT_EQ(1, YIndex(gfx::Size(3, 3), gfx::Size(3, 4), true, 3));
+TEST_P(TilingDataTest, TileYIndexFromSrcCoord) {
+ gfx::Point origin = GetParam();
+
+ EXPECT_EQ(0,
+ YIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.y() + 0));
+ EXPECT_EQ(0,
+ YIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.y() + 1));
+ EXPECT_EQ(0,
+ YIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.y() + 2));
+ EXPECT_EQ(1,
+ YIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.y() + 3));
+ EXPECT_EQ(1,
+ YIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.y() + 4));
+ EXPECT_EQ(1,
+ YIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.y() + 5));
+ EXPECT_EQ(2,
+ YIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.y() + 6));
+ EXPECT_EQ(2,
+ YIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.y() + 7));
+ EXPECT_EQ(2,
+ YIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.y() + 8));
+ EXPECT_EQ(3,
+ YIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.y() + 9));
+ EXPECT_EQ(3,
+ YIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.y() + 10));
+ EXPECT_EQ(3,
+ YIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.y() + 11));
+
+ EXPECT_EQ(0,
+ YIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.y() + 0));
+ EXPECT_EQ(0,
+ YIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.y() + 1));
+ EXPECT_EQ(1,
+ YIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.y() + 2));
+ EXPECT_EQ(2,
+ YIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.y() + 3));
+ EXPECT_EQ(3,
+ YIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.y() + 4));
+ EXPECT_EQ(4,
+ YIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.y() + 5));
+ EXPECT_EQ(5,
+ YIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.y() + 6));
+ EXPECT_EQ(6,
+ YIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.y() + 7));
+ EXPECT_EQ(7,
+ YIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.y() + 8));
+ EXPECT_EQ(7,
+ YIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.y() + 9));
+ EXPECT_EQ(7,
+ YIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.y() + 10));
+ EXPECT_EQ(7,
+ YIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.y() + 11));
+
+ EXPECT_EQ(0,
+ YIndex(gfx::Size(1, 1),
+ gfx::Rect(origin, gfx::Size(1, 1)),
+ false,
+ origin.y() + 0));
+ EXPECT_EQ(0,
+ YIndex(gfx::Size(2, 2),
+ gfx::Rect(origin, gfx::Size(2, 2)),
+ false,
+ origin.y() + 0));
+ EXPECT_EQ(0,
+ YIndex(gfx::Size(2, 2),
+ gfx::Rect(origin, gfx::Size(2, 2)),
+ false,
+ origin.y() + 1));
+ EXPECT_EQ(0,
+ YIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 3)),
+ false,
+ origin.y() + 0));
+ EXPECT_EQ(0,
+ YIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 3)),
+ false,
+ origin.y() + 1));
+ EXPECT_EQ(0,
+ YIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 3)),
+ false,
+ origin.y() + 2));
+
+ EXPECT_EQ(0,
+ YIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 4)),
+ false,
+ origin.y() + 0));
+ EXPECT_EQ(0,
+ YIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 4)),
+ false,
+ origin.y() + 1));
+ EXPECT_EQ(0,
+ YIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 4)),
+ false,
+ origin.y() + 2));
+ EXPECT_EQ(1,
+ YIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 4)),
+ false,
+ origin.y() + 3));
+
+ EXPECT_EQ(0,
+ YIndex(gfx::Size(1, 1),
+ gfx::Rect(origin, gfx::Size(1, 1)),
+ true,
+ origin.y() + 0));
+ EXPECT_EQ(0,
+ YIndex(gfx::Size(2, 2),
+ gfx::Rect(origin, gfx::Size(2, 2)),
+ true,
+ origin.y() + 0));
+ EXPECT_EQ(0,
+ YIndex(gfx::Size(2, 2),
+ gfx::Rect(origin, gfx::Size(2, 2)),
+ true,
+ origin.y() + 1));
+ EXPECT_EQ(0,
+ YIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 3)),
+ true,
+ origin.y() + 0));
+ EXPECT_EQ(0,
+ YIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 3)),
+ true,
+ origin.y() + 1));
+ EXPECT_EQ(0,
+ YIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 3)),
+ true,
+ origin.y() + 2));
+
+ EXPECT_EQ(0,
+ YIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 4)),
+ true,
+ origin.y() + 0));
+ EXPECT_EQ(0,
+ YIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 4)),
+ true,
+ origin.y() + 1));
+ EXPECT_EQ(1,
+ YIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 4)),
+ true,
+ origin.y() + 2));
+ EXPECT_EQ(1,
+ YIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 4)),
+ true,
+ origin.y() + 3));
}
-TEST(TilingDataTest, FirstBorderTileYIndexFromSrcCoord) {
- EXPECT_EQ(0, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 0));
- EXPECT_EQ(0, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 1));
- EXPECT_EQ(0, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 2));
- EXPECT_EQ(1, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 3));
- EXPECT_EQ(1, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 4));
- EXPECT_EQ(1, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 5));
- EXPECT_EQ(2, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 6));
- EXPECT_EQ(2, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 7));
- EXPECT_EQ(2, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 8));
- EXPECT_EQ(3, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 9));
- EXPECT_EQ(3, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 10));
- EXPECT_EQ(3, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 11));
-
- EXPECT_EQ(0, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 0));
- EXPECT_EQ(0, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 1));
- EXPECT_EQ(0, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 2));
- EXPECT_EQ(1, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 3));
- EXPECT_EQ(2, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 4));
- EXPECT_EQ(3, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 5));
- EXPECT_EQ(4, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 6));
- EXPECT_EQ(5, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 7));
- EXPECT_EQ(6, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 8));
- EXPECT_EQ(7, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 9));
- EXPECT_EQ(7, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 10));
- EXPECT_EQ(7, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 11));
-
- EXPECT_EQ(0, MinBorderYIndex(gfx::Size(1, 1), gfx::Size(1, 1), false, 0));
- EXPECT_EQ(0, MinBorderYIndex(gfx::Size(2, 2), gfx::Size(2, 2), false, 0));
- EXPECT_EQ(0, MinBorderYIndex(gfx::Size(2, 2), gfx::Size(2, 2), false, 1));
- EXPECT_EQ(0, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 3), false, 0));
- EXPECT_EQ(0, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 3), false, 1));
- EXPECT_EQ(0, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 3), false, 2));
-
- EXPECT_EQ(0, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 4), false, 0));
- EXPECT_EQ(0, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 4), false, 1));
- EXPECT_EQ(0, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 4), false, 2));
- EXPECT_EQ(1, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 4), false, 3));
-
- EXPECT_EQ(0, MinBorderYIndex(gfx::Size(1, 1), gfx::Size(1, 1), true, 0));
- EXPECT_EQ(0, MinBorderYIndex(gfx::Size(2, 2), gfx::Size(2, 2), true, 0));
- EXPECT_EQ(0, MinBorderYIndex(gfx::Size(2, 2), gfx::Size(2, 2), true, 1));
- EXPECT_EQ(0, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 3), true, 0));
- EXPECT_EQ(0, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 3), true, 1));
- EXPECT_EQ(0, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 3), true, 2));
-
- EXPECT_EQ(0, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 4), true, 0));
- EXPECT_EQ(0, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 4), true, 1));
- EXPECT_EQ(0, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 4), true, 2));
- EXPECT_EQ(1, MinBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 4), true, 3));
+TEST_P(TilingDataTest, FirstBorderTileYIndexFromSrcCoord) {
+ gfx::Point origin = GetParam();
+
+ EXPECT_EQ(0,
+ MinBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.y() + 0));
+ EXPECT_EQ(0,
+ MinBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.y() + 1));
+ EXPECT_EQ(0,
+ MinBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.y() + 2));
+ EXPECT_EQ(1,
+ MinBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.y() + 3));
+ EXPECT_EQ(1,
+ MinBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.y() + 4));
+ EXPECT_EQ(1,
+ MinBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.y() + 5));
+ EXPECT_EQ(2,
+ MinBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.y() + 6));
+ EXPECT_EQ(2,
+ MinBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.y() + 7));
+ EXPECT_EQ(2,
+ MinBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.y() + 8));
+ EXPECT_EQ(3,
+ MinBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.y() + 9));
+ EXPECT_EQ(3,
+ MinBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.y() + 10));
+ EXPECT_EQ(3,
+ MinBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.y() + 11));
+
+ EXPECT_EQ(0,
+ MinBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.y() + 0));
+ EXPECT_EQ(0,
+ MinBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.y() + 1));
+ EXPECT_EQ(0,
+ MinBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.y() + 2));
+ EXPECT_EQ(1,
+ MinBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.y() + 3));
+ EXPECT_EQ(2,
+ MinBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.y() + 4));
+ EXPECT_EQ(3,
+ MinBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.y() + 5));
+ EXPECT_EQ(4,
+ MinBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.y() + 6));
+ EXPECT_EQ(5,
+ MinBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.y() + 7));
+ EXPECT_EQ(6,
+ MinBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.y() + 8));
+ EXPECT_EQ(7,
+ MinBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.y() + 9));
+ EXPECT_EQ(7,
+ MinBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.y() + 10));
+ EXPECT_EQ(7,
+ MinBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.y() + 11));
+
+ EXPECT_EQ(0,
+ MinBorderYIndex(gfx::Size(1, 1),
+ gfx::Rect(origin, gfx::Size(1, 1)),
+ false,
+ origin.y() + 0));
+ EXPECT_EQ(0,
+ MinBorderYIndex(gfx::Size(2, 2),
+ gfx::Rect(origin, gfx::Size(2, 2)),
+ false,
+ origin.y() + 0));
+ EXPECT_EQ(0,
+ MinBorderYIndex(gfx::Size(2, 2),
+ gfx::Rect(origin, gfx::Size(2, 2)),
+ false,
+ origin.y() + 1));
+ EXPECT_EQ(0,
+ MinBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 3)),
+ false,
+ origin.y() + 0));
+ EXPECT_EQ(0,
+ MinBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 3)),
+ false,
+ origin.y() + 1));
+ EXPECT_EQ(0,
+ MinBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 3)),
+ false,
+ origin.y() + 2));
+
+ EXPECT_EQ(0,
+ MinBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 4)),
+ false,
+ origin.y() + 0));
+ EXPECT_EQ(0,
+ MinBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 4)),
+ false,
+ origin.y() + 1));
+ EXPECT_EQ(0,
+ MinBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 4)),
+ false,
+ origin.y() + 2));
+ EXPECT_EQ(1,
+ MinBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 4)),
+ false,
+ origin.y() + 3));
+
+ EXPECT_EQ(0,
+ MinBorderYIndex(gfx::Size(1, 1),
+ gfx::Rect(origin, gfx::Size(1, 1)),
+ true,
+ origin.y() + 0));
+ EXPECT_EQ(0,
+ MinBorderYIndex(gfx::Size(2, 2),
+ gfx::Rect(origin, gfx::Size(2, 2)),
+ true,
+ origin.y() + 0));
+ EXPECT_EQ(0,
+ MinBorderYIndex(gfx::Size(2, 2),
+ gfx::Rect(origin, gfx::Size(2, 2)),
+ true,
+ origin.y() + 1));
+ EXPECT_EQ(0,
+ MinBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 3)),
+ true,
+ origin.y() + 0));
+ EXPECT_EQ(0,
+ MinBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 3)),
+ true,
+ origin.y() + 1));
+ EXPECT_EQ(0,
+ MinBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 3)),
+ true,
+ origin.y() + 2));
+
+ EXPECT_EQ(0,
+ MinBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 4)),
+ true,
+ origin.y() + 0));
+ EXPECT_EQ(0,
+ MinBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 4)),
+ true,
+ origin.y() + 1));
+ EXPECT_EQ(0,
+ MinBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 4)),
+ true,
+ origin.y() + 2));
+ EXPECT_EQ(1,
+ MinBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 4)),
+ true,
+ origin.y() + 3));
}
-TEST(TilingDataTest, LastBorderTileYIndexFromSrcCoord) {
- EXPECT_EQ(0, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 0));
- EXPECT_EQ(0, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 1));
- EXPECT_EQ(0, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 2));
- EXPECT_EQ(1, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 3));
- EXPECT_EQ(1, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 4));
- EXPECT_EQ(1, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 5));
- EXPECT_EQ(2, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 6));
- EXPECT_EQ(2, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 7));
- EXPECT_EQ(2, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 8));
- EXPECT_EQ(3, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 9));
- EXPECT_EQ(3, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 10));
- EXPECT_EQ(3, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), false, 11));
-
- EXPECT_EQ(0, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 0));
- EXPECT_EQ(1, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 1));
- EXPECT_EQ(2, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 2));
- EXPECT_EQ(3, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 3));
- EXPECT_EQ(4, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 4));
- EXPECT_EQ(5, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 5));
- EXPECT_EQ(6, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 6));
- EXPECT_EQ(7, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 7));
- EXPECT_EQ(7, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 8));
- EXPECT_EQ(7, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 9));
- EXPECT_EQ(7, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 10));
- EXPECT_EQ(7, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(10, 10), true, 11));
-
- EXPECT_EQ(0, MaxBorderYIndex(gfx::Size(1, 1), gfx::Size(1, 1), false, 0));
- EXPECT_EQ(0, MaxBorderYIndex(gfx::Size(2, 2), gfx::Size(2, 2), false, 0));
- EXPECT_EQ(0, MaxBorderYIndex(gfx::Size(2, 2), gfx::Size(2, 2), false, 1));
- EXPECT_EQ(0, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 3), false, 0));
- EXPECT_EQ(0, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 3), false, 1));
- EXPECT_EQ(0, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 3), false, 2));
-
- EXPECT_EQ(0, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 4), false, 0));
- EXPECT_EQ(0, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 4), false, 1));
- EXPECT_EQ(0, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 4), false, 2));
- EXPECT_EQ(1, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 4), false, 3));
-
- EXPECT_EQ(0, MaxBorderYIndex(gfx::Size(1, 1), gfx::Size(1, 1), true, 0));
- EXPECT_EQ(0, MaxBorderYIndex(gfx::Size(2, 2), gfx::Size(2, 2), true, 0));
- EXPECT_EQ(0, MaxBorderYIndex(gfx::Size(2, 2), gfx::Size(2, 2), true, 1));
- EXPECT_EQ(0, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 3), true, 0));
- EXPECT_EQ(0, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 3), true, 1));
- EXPECT_EQ(0, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 3), true, 2));
-
- EXPECT_EQ(0, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 4), true, 0));
- EXPECT_EQ(1, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 4), true, 1));
- EXPECT_EQ(1, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 4), true, 2));
- EXPECT_EQ(1, MaxBorderYIndex(gfx::Size(3, 3), gfx::Size(3, 4), true, 3));
+TEST_P(TilingDataTest, LastBorderTileYIndexFromSrcCoord) {
+ gfx::Point origin = GetParam();
+
+ EXPECT_EQ(0,
+ MaxBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.y() + 0));
+ EXPECT_EQ(0,
+ MaxBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.y() + 1));
+ EXPECT_EQ(0,
+ MaxBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.y() + 2));
+ EXPECT_EQ(1,
+ MaxBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.y() + 3));
+ EXPECT_EQ(1,
+ MaxBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.y() + 4));
+ EXPECT_EQ(1,
+ MaxBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.y() + 5));
+ EXPECT_EQ(2,
+ MaxBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.y() + 6));
+ EXPECT_EQ(2,
+ MaxBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.y() + 7));
+ EXPECT_EQ(2,
+ MaxBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.y() + 8));
+ EXPECT_EQ(3,
+ MaxBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.y() + 9));
+ EXPECT_EQ(3,
+ MaxBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.y() + 10));
+ EXPECT_EQ(3,
+ MaxBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ false,
+ origin.y() + 11));
+
+ EXPECT_EQ(0,
+ MaxBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.y() + 0));
+ EXPECT_EQ(1,
+ MaxBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.y() + 1));
+ EXPECT_EQ(2,
+ MaxBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.y() + 2));
+ EXPECT_EQ(3,
+ MaxBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.y() + 3));
+ EXPECT_EQ(4,
+ MaxBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.y() + 4));
+ EXPECT_EQ(5,
+ MaxBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.y() + 5));
+ EXPECT_EQ(6,
+ MaxBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.y() + 6));
+ EXPECT_EQ(7,
+ MaxBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.y() + 7));
+ EXPECT_EQ(7,
+ MaxBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.y() + 8));
+ EXPECT_EQ(7,
+ MaxBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.y() + 9));
+ EXPECT_EQ(7,
+ MaxBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.y() + 10));
+ EXPECT_EQ(7,
+ MaxBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(10, 10)),
+ true,
+ origin.y() + 11));
+
+ EXPECT_EQ(0,
+ MaxBorderYIndex(gfx::Size(1, 1),
+ gfx::Rect(origin, gfx::Size(1, 1)),
+ false,
+ origin.y() + 0));
+ EXPECT_EQ(0,
+ MaxBorderYIndex(gfx::Size(2, 2),
+ gfx::Rect(origin, gfx::Size(2, 2)),
+ false,
+ origin.y() + 0));
+ EXPECT_EQ(0,
+ MaxBorderYIndex(gfx::Size(2, 2),
+ gfx::Rect(origin, gfx::Size(2, 2)),
+ false,
+ origin.y() + 1));
+ EXPECT_EQ(0,
+ MaxBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 3)),
+ false,
+ origin.y() + 0));
+ EXPECT_EQ(0,
+ MaxBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 3)),
+ false,
+ origin.y() + 1));
+ EXPECT_EQ(0,
+ MaxBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 3)),
+ false,
+ origin.y() + 2));
+
+ EXPECT_EQ(0,
+ MaxBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 4)),
+ false,
+ origin.y() + 0));
+ EXPECT_EQ(0,
+ MaxBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 4)),
+ false,
+ origin.y() + 1));
+ EXPECT_EQ(0,
+ MaxBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 4)),
+ false,
+ origin.y() + 2));
+ EXPECT_EQ(1,
+ MaxBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 4)),
+ false,
+ origin.y() + 3));
+
+ EXPECT_EQ(0,
+ MaxBorderYIndex(gfx::Size(1, 1),
+ gfx::Rect(origin, gfx::Size(1, 1)),
+ true,
+ origin.y() + 0));
+ EXPECT_EQ(0,
+ MaxBorderYIndex(gfx::Size(2, 2),
+ gfx::Rect(origin, gfx::Size(2, 2)),
+ true,
+ origin.y() + 0));
+ EXPECT_EQ(0,
+ MaxBorderYIndex(gfx::Size(2, 2),
+ gfx::Rect(origin, gfx::Size(2, 2)),
+ true,
+ origin.y() + 1));
+ EXPECT_EQ(0,
+ MaxBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 3)),
+ true,
+ origin.y() + 0));
+ EXPECT_EQ(0,
+ MaxBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 3)),
+ true,
+ origin.y() + 1));
+ EXPECT_EQ(0,
+ MaxBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 3)),
+ true,
+ origin.y() + 2));
+
+ EXPECT_EQ(0,
+ MaxBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 4)),
+ true,
+ origin.y() + 0));
+ EXPECT_EQ(1,
+ MaxBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 4)),
+ true,
+ origin.y() + 1));
+ EXPECT_EQ(1,
+ MaxBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 4)),
+ true,
+ origin.y() + 2));
+ EXPECT_EQ(1,
+ MaxBorderYIndex(gfx::Size(3, 3),
+ gfx::Rect(origin, gfx::Size(3, 4)),
+ true,
+ origin.y() + 3));
}
-TEST(TilingDataTest, TileSizeX) {
- EXPECT_EQ(5, SizeX(gfx::Size(5, 5), gfx::Size(5, 5), false, 0));
- EXPECT_EQ(5, SizeX(gfx::Size(5, 5), gfx::Size(5, 5), true, 0));
-
- EXPECT_EQ(5, SizeX(gfx::Size(5, 5), gfx::Size(6, 6), false, 0));
- EXPECT_EQ(1, SizeX(gfx::Size(5, 5), gfx::Size(6, 6), false, 1));
- EXPECT_EQ(4, SizeX(gfx::Size(5, 5), gfx::Size(6, 6), true, 0));
- EXPECT_EQ(2, SizeX(gfx::Size(5, 5), gfx::Size(6, 6), true, 1));
-
- EXPECT_EQ(5, SizeX(gfx::Size(5, 5), gfx::Size(8, 8), false, 0));
- EXPECT_EQ(3, SizeX(gfx::Size(5, 5), gfx::Size(8, 8), false, 1));
- EXPECT_EQ(4, SizeX(gfx::Size(5, 5), gfx::Size(8, 8), true, 0));
- EXPECT_EQ(4, SizeX(gfx::Size(5, 5), gfx::Size(8, 8), true, 1));
-
- EXPECT_EQ(5, SizeX(gfx::Size(5, 5), gfx::Size(10, 10), false, 0));
- EXPECT_EQ(5, SizeX(gfx::Size(5, 5), gfx::Size(10, 10), false, 1));
- EXPECT_EQ(4, SizeX(gfx::Size(5, 5), gfx::Size(10, 10), true, 0));
- EXPECT_EQ(3, SizeX(gfx::Size(5, 5), gfx::Size(10, 10), true, 1));
- EXPECT_EQ(3, SizeX(gfx::Size(5, 5), gfx::Size(10, 10), true, 2));
-
- EXPECT_EQ(4, SizeX(gfx::Size(5, 5), gfx::Size(11, 11), true, 2));
- EXPECT_EQ(3, SizeX(gfx::Size(5, 5), gfx::Size(12, 12), true, 2));
-
- EXPECT_EQ(3, SizeX(gfx::Size(5, 9), gfx::Size(12, 17), true, 2));
+TEST_P(TilingDataTest, TileSizeX) {
+ gfx::Point origin = GetParam();
+
+ EXPECT_EQ(
+ 5, SizeX(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(5, 5)), false, 0));
+ EXPECT_EQ(
+ 5, SizeX(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(5, 5)), true, 0));
+
+ EXPECT_EQ(
+ 5, SizeX(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(6, 6)), false, 0));
+ EXPECT_EQ(
+ 1, SizeX(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(6, 6)), false, 1));
+ EXPECT_EQ(
+ 4, SizeX(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(6, 6)), true, 0));
+ EXPECT_EQ(
+ 2, SizeX(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(6, 6)), true, 1));
+
+ EXPECT_EQ(
+ 5, SizeX(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(8, 8)), false, 0));
+ EXPECT_EQ(
+ 3, SizeX(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(8, 8)), false, 1));
+ EXPECT_EQ(
+ 4, SizeX(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(8, 8)), true, 0));
+ EXPECT_EQ(
+ 4, SizeX(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(8, 8)), true, 1));
+
+ EXPECT_EQ(
+ 5,
+ SizeX(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(10, 10)), false, 0));
+ EXPECT_EQ(
+ 5,
+ SizeX(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(10, 10)), false, 1));
+ EXPECT_EQ(
+ 4, SizeX(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(10, 10)), true, 0));
+ EXPECT_EQ(
+ 3, SizeX(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(10, 10)), true, 1));
+ EXPECT_EQ(
+ 3, SizeX(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(10, 10)), true, 2));
+
+ EXPECT_EQ(
+ 4, SizeX(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(11, 11)), true, 2));
+ EXPECT_EQ(
+ 3, SizeX(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(12, 12)), true, 2));
+
+ EXPECT_EQ(
+ 3, SizeX(gfx::Size(5, 9), gfx::Rect(origin, gfx::Size(12, 17)), true, 2));
}
-TEST(TilingDataTest, TileSizeY) {
- EXPECT_EQ(5, SizeY(gfx::Size(5, 5), gfx::Size(5, 5), false, 0));
- EXPECT_EQ(5, SizeY(gfx::Size(5, 5), gfx::Size(5, 5), true, 0));
-
- EXPECT_EQ(5, SizeY(gfx::Size(5, 5), gfx::Size(6, 6), false, 0));
- EXPECT_EQ(1, SizeY(gfx::Size(5, 5), gfx::Size(6, 6), false, 1));
- EXPECT_EQ(4, SizeY(gfx::Size(5, 5), gfx::Size(6, 6), true, 0));
- EXPECT_EQ(2, SizeY(gfx::Size(5, 5), gfx::Size(6, 6), true, 1));
-
- EXPECT_EQ(5, SizeY(gfx::Size(5, 5), gfx::Size(8, 8), false, 0));
- EXPECT_EQ(3, SizeY(gfx::Size(5, 5), gfx::Size(8, 8), false, 1));
- EXPECT_EQ(4, SizeY(gfx::Size(5, 5), gfx::Size(8, 8), true, 0));
- EXPECT_EQ(4, SizeY(gfx::Size(5, 5), gfx::Size(8, 8), true, 1));
-
- EXPECT_EQ(5, SizeY(gfx::Size(5, 5), gfx::Size(10, 10), false, 0));
- EXPECT_EQ(5, SizeY(gfx::Size(5, 5), gfx::Size(10, 10), false, 1));
- EXPECT_EQ(4, SizeY(gfx::Size(5, 5), gfx::Size(10, 10), true, 0));
- EXPECT_EQ(3, SizeY(gfx::Size(5, 5), gfx::Size(10, 10), true, 1));
- EXPECT_EQ(3, SizeY(gfx::Size(5, 5), gfx::Size(10, 10), true, 2));
-
- EXPECT_EQ(4, SizeY(gfx::Size(5, 5), gfx::Size(11, 11), true, 2));
- EXPECT_EQ(3, SizeY(gfx::Size(5, 5), gfx::Size(12, 12), true, 2));
-
- EXPECT_EQ(3, SizeY(gfx::Size(9, 5), gfx::Size(17, 12), true, 2));
+TEST_P(TilingDataTest, TileSizeY) {
+ gfx::Point origin = GetParam();
+
+ EXPECT_EQ(
+ 5, SizeY(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(5, 5)), false, 0));
+ EXPECT_EQ(
+ 5, SizeY(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(5, 5)), true, 0));
+
+ EXPECT_EQ(
+ 5, SizeY(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(6, 6)), false, 0));
+ EXPECT_EQ(
+ 1, SizeY(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(6, 6)), false, 1));
+ EXPECT_EQ(
+ 4, SizeY(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(6, 6)), true, 0));
+ EXPECT_EQ(
+ 2, SizeY(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(6, 6)), true, 1));
+
+ EXPECT_EQ(
+ 5, SizeY(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(8, 8)), false, 0));
+ EXPECT_EQ(
+ 3, SizeY(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(8, 8)), false, 1));
+ EXPECT_EQ(
+ 4, SizeY(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(8, 8)), true, 0));
+ EXPECT_EQ(
+ 4, SizeY(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(8, 8)), true, 1));
+
+ EXPECT_EQ(
+ 5,
+ SizeY(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(10, 10)), false, 0));
+ EXPECT_EQ(
+ 5,
+ SizeY(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(10, 10)), false, 1));
+ EXPECT_EQ(
+ 4, SizeY(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(10, 10)), true, 0));
+ EXPECT_EQ(
+ 3, SizeY(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(10, 10)), true, 1));
+ EXPECT_EQ(
+ 3, SizeY(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(10, 10)), true, 2));
+
+ EXPECT_EQ(
+ 4, SizeY(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(11, 11)), true, 2));
+ EXPECT_EQ(
+ 3, SizeY(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(12, 12)), true, 2));
+
+ EXPECT_EQ(
+ 3, SizeY(gfx::Size(9, 5), gfx::Rect(origin, gfx::Size(17, 12)), true, 2));
}
-TEST(TilingDataTest, TileSizeX_and_TilePositionX) {
+TEST_P(TilingDataTest, TileSizeX_and_TilePositionX) {
+ gfx::Point origin = GetParam();
+
// Single tile cases:
- EXPECT_EQ(1, SizeX(gfx::Size(3, 3), gfx::Size(1, 1), false, 0));
- EXPECT_EQ(0, PosX(gfx::Size(3, 3), gfx::Size(1, 1), false, 0));
- EXPECT_EQ(1, SizeX(gfx::Size(3, 3), gfx::Size(1, 100), false, 0));
- EXPECT_EQ(0, PosX(gfx::Size(3, 3), gfx::Size(1, 100), false, 0));
- EXPECT_EQ(3, SizeX(gfx::Size(3, 3), gfx::Size(3, 1), false, 0));
- EXPECT_EQ(0, PosX(gfx::Size(3, 3), gfx::Size(3, 1), false, 0));
- EXPECT_EQ(3, SizeX(gfx::Size(3, 3), gfx::Size(3, 100), false, 0));
- EXPECT_EQ(0, PosX(gfx::Size(3, 3), gfx::Size(3, 100), false, 0));
- EXPECT_EQ(1, SizeX(gfx::Size(3, 3), gfx::Size(1, 1), true, 0));
- EXPECT_EQ(0, PosX(gfx::Size(3, 3), gfx::Size(1, 1), true, 0));
- EXPECT_EQ(1, SizeX(gfx::Size(3, 3), gfx::Size(1, 100), true, 0));
- EXPECT_EQ(0, PosX(gfx::Size(3, 3), gfx::Size(1, 100), true, 0));
- EXPECT_EQ(3, SizeX(gfx::Size(3, 3), gfx::Size(3, 1), true, 0));
- EXPECT_EQ(0, PosX(gfx::Size(3, 3), gfx::Size(3, 1), true, 0));
- EXPECT_EQ(3, SizeX(gfx::Size(3, 3), gfx::Size(3, 100), true, 0));
- EXPECT_EQ(0, PosX(gfx::Size(3, 3), gfx::Size(3, 100), true, 0));
+ EXPECT_EQ(
+ 1, SizeX(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(1, 1)), false, 0));
+ EXPECT_EQ(
+ origin.x(),
+ PosX(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(1, 1)), false, 0));
+ EXPECT_EQ(
+ 1,
+ SizeX(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(1, 100)), false, 0));
+ EXPECT_EQ(
+ origin.x(),
+ PosX(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(1, 100)), false, 0));
+ EXPECT_EQ(
+ 3, SizeX(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(3, 1)), false, 0));
+ EXPECT_EQ(
+ origin.x(),
+ PosX(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(3, 1)), false, 0));
+ EXPECT_EQ(
+ 3,
+ SizeX(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(3, 100)), false, 0));
+ EXPECT_EQ(
+ origin.x(),
+ PosX(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(3, 100)), false, 0));
+ EXPECT_EQ(
+ 1, SizeX(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(1, 1)), true, 0));
+ EXPECT_EQ(origin.x(),
+ PosX(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(1, 1)), true, 0));
+ EXPECT_EQ(
+ 1, SizeX(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(1, 100)), true, 0));
+ EXPECT_EQ(
+ origin.x(),
+ PosX(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(1, 100)), true, 0));
+ EXPECT_EQ(
+ 3, SizeX(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(3, 1)), true, 0));
+ EXPECT_EQ(origin.x(),
+ PosX(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(3, 1)), true, 0));
+ EXPECT_EQ(
+ 3, SizeX(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(3, 100)), true, 0));
+ EXPECT_EQ(
+ origin.x(),
+ PosX(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(3, 100)), true, 0));
// Multiple tiles:
// no border
// positions 0, 3
- EXPECT_EQ(2, NumTiles(gfx::Size(3, 3), gfx::Size(6, 1), false));
- EXPECT_EQ(3, SizeX(gfx::Size(3, 3), gfx::Size(6, 1), false, 0));
- EXPECT_EQ(3, SizeX(gfx::Size(3, 3), gfx::Size(6, 1), false, 1));
- EXPECT_EQ(0, PosX(gfx::Size(3, 3), gfx::Size(6, 1), false, 0));
- EXPECT_EQ(3, PosX(gfx::Size(3, 3), gfx::Size(6, 1), false, 1));
- EXPECT_EQ(3, SizeX(gfx::Size(3, 3), gfx::Size(6, 100), false, 0));
- EXPECT_EQ(3, SizeX(gfx::Size(3, 3), gfx::Size(6, 100), false, 1));
- EXPECT_EQ(0, PosX(gfx::Size(3, 3), gfx::Size(6, 100), false, 0));
- EXPECT_EQ(3, PosX(gfx::Size(3, 3), gfx::Size(6, 100), false, 1));
+ EXPECT_EQ(
+ 2, NumTiles(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(6, 1)), false));
+ EXPECT_EQ(
+ 3, SizeX(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(6, 1)), false, 0));
+ EXPECT_EQ(
+ 3, SizeX(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(6, 1)), false, 1));
+ EXPECT_EQ(
+ origin.x() + 0,
+ PosX(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(6, 1)), false, 0));
+ EXPECT_EQ(
+ origin.x() + 3,
+ PosX(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(6, 1)), false, 1));
+ EXPECT_EQ(
+ 3,
+ SizeX(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(6, 100)), false, 0));
+ EXPECT_EQ(
+ 3,
+ SizeX(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(6, 100)), false, 1));
+ EXPECT_EQ(
+ origin.x() + 0,
+ PosX(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(6, 100)), false, 0));
+ EXPECT_EQ(
+ origin.x() + 3,
+ PosX(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(6, 100)), false, 1));
// Multiple tiles:
// with border
// positions 0, 2, 3, 4
- EXPECT_EQ(4, NumTiles(gfx::Size(3, 3), gfx::Size(6, 1), true));
- EXPECT_EQ(2, SizeX(gfx::Size(3, 3), gfx::Size(6, 1), true, 0));
- EXPECT_EQ(1, SizeX(gfx::Size(3, 3), gfx::Size(6, 1), true, 1));
- EXPECT_EQ(1, SizeX(gfx::Size(3, 3), gfx::Size(6, 1), true, 2));
- EXPECT_EQ(2, SizeX(gfx::Size(3, 3), gfx::Size(6, 1), true, 3));
- EXPECT_EQ(0, PosX(gfx::Size(3, 3), gfx::Size(6, 1), true, 0));
- EXPECT_EQ(2, PosX(gfx::Size(3, 3), gfx::Size(6, 1), true, 1));
- EXPECT_EQ(3, PosX(gfx::Size(3, 3), gfx::Size(6, 1), true, 2));
- EXPECT_EQ(4, PosX(gfx::Size(3, 3), gfx::Size(6, 1), true, 3));
- EXPECT_EQ(2, SizeX(gfx::Size(3, 7), gfx::Size(6, 100), true, 0));
- EXPECT_EQ(1, SizeX(gfx::Size(3, 7), gfx::Size(6, 100), true, 1));
- EXPECT_EQ(1, SizeX(gfx::Size(3, 7), gfx::Size(6, 100), true, 2));
- EXPECT_EQ(2, SizeX(gfx::Size(3, 7), gfx::Size(6, 100), true, 3));
- EXPECT_EQ(0, PosX(gfx::Size(3, 7), gfx::Size(6, 100), true, 0));
- EXPECT_EQ(2, PosX(gfx::Size(3, 7), gfx::Size(6, 100), true, 1));
- EXPECT_EQ(3, PosX(gfx::Size(3, 7), gfx::Size(6, 100), true, 2));
- EXPECT_EQ(4, PosX(gfx::Size(3, 7), gfx::Size(6, 100), true, 3));
+ EXPECT_EQ(
+ 4, NumTiles(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(6, 1)), true));
+ EXPECT_EQ(
+ 2, SizeX(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(6, 1)), true, 0));
+ EXPECT_EQ(
+ 1, SizeX(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(6, 1)), true, 1));
+ EXPECT_EQ(
+ 1, SizeX(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(6, 1)), true, 2));
+ EXPECT_EQ(
+ 2, SizeX(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(6, 1)), true, 3));
+ EXPECT_EQ(origin.x() + 0,
+ PosX(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(6, 1)), true, 0));
+ EXPECT_EQ(origin.x() + 2,
+ PosX(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(6, 1)), true, 1));
+ EXPECT_EQ(origin.x() + 3,
+ PosX(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(6, 1)), true, 2));
+ EXPECT_EQ(origin.x() + 4,
+ PosX(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(6, 1)), true, 3));
+ EXPECT_EQ(
+ 2, SizeX(gfx::Size(3, 7), gfx::Rect(origin, gfx::Size(6, 100)), true, 0));
+ EXPECT_EQ(
+ 1, SizeX(gfx::Size(3, 7), gfx::Rect(origin, gfx::Size(6, 100)), true, 1));
+ EXPECT_EQ(
+ 1, SizeX(gfx::Size(3, 7), gfx::Rect(origin, gfx::Size(6, 100)), true, 2));
+ EXPECT_EQ(
+ 2, SizeX(gfx::Size(3, 7), gfx::Rect(origin, gfx::Size(6, 100)), true, 3));
+ EXPECT_EQ(
+ origin.x() + 0,
+ PosX(gfx::Size(3, 7), gfx::Rect(origin, gfx::Size(6, 100)), true, 0));
+ EXPECT_EQ(
+ origin.x() + 2,
+ PosX(gfx::Size(3, 7), gfx::Rect(origin, gfx::Size(6, 100)), true, 1));
+ EXPECT_EQ(
+ origin.x() + 3,
+ PosX(gfx::Size(3, 7), gfx::Rect(origin, gfx::Size(6, 100)), true, 2));
+ EXPECT_EQ(
+ origin.x() + 4,
+ PosX(gfx::Size(3, 7), gfx::Rect(origin, gfx::Size(6, 100)), true, 3));
}
-TEST(TilingDataTest, TileSizeY_and_TilePositionY) {
+TEST_P(TilingDataTest, TileSizeY_and_TilePositionY) {
+ gfx::Point origin = GetParam();
+
// Single tile cases:
- EXPECT_EQ(1, SizeY(gfx::Size(3, 3), gfx::Size(1, 1), false, 0));
- EXPECT_EQ(0, PosY(gfx::Size(3, 3), gfx::Size(1, 1), false, 0));
- EXPECT_EQ(1, SizeY(gfx::Size(3, 3), gfx::Size(100, 1), false, 0));
- EXPECT_EQ(0, PosY(gfx::Size(3, 3), gfx::Size(100, 1), false, 0));
- EXPECT_EQ(3, SizeY(gfx::Size(3, 3), gfx::Size(1, 3), false, 0));
- EXPECT_EQ(0, PosY(gfx::Size(3, 3), gfx::Size(1, 3), false, 0));
- EXPECT_EQ(3, SizeY(gfx::Size(3, 3), gfx::Size(100, 3), false, 0));
- EXPECT_EQ(0, PosY(gfx::Size(3, 3), gfx::Size(100, 3), false, 0));
- EXPECT_EQ(1, SizeY(gfx::Size(3, 3), gfx::Size(1, 1), true, 0));
- EXPECT_EQ(0, PosY(gfx::Size(3, 3), gfx::Size(1, 1), true, 0));
- EXPECT_EQ(1, SizeY(gfx::Size(3, 3), gfx::Size(100, 1), true, 0));
- EXPECT_EQ(0, PosY(gfx::Size(3, 3), gfx::Size(100, 1), true, 0));
- EXPECT_EQ(3, SizeY(gfx::Size(3, 3), gfx::Size(1, 3), true, 0));
- EXPECT_EQ(0, PosY(gfx::Size(3, 3), gfx::Size(1, 3), true, 0));
- EXPECT_EQ(3, SizeY(gfx::Size(3, 3), gfx::Size(100, 3), true, 0));
- EXPECT_EQ(0, PosY(gfx::Size(3, 3), gfx::Size(100, 3), true, 0));
+ EXPECT_EQ(
+ 1, SizeY(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(1, 1)), false, 0));
+ EXPECT_EQ(
+ origin.y(),
+ PosY(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(1, 1)), false, 0));
+ EXPECT_EQ(
+ 1,
+ SizeY(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(100, 1)), false, 0));
+ EXPECT_EQ(
+ origin.y(),
+ PosY(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(100, 1)), false, 0));
+ EXPECT_EQ(
+ 3, SizeY(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(1, 3)), false, 0));
+ EXPECT_EQ(
+ origin.y(),
+ PosY(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(1, 3)), false, 0));
+ EXPECT_EQ(
+ 3,
+ SizeY(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(100, 3)), false, 0));
+ EXPECT_EQ(
+ origin.y(),
+ PosY(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(100, 3)), false, 0));
+ EXPECT_EQ(
+ 1, SizeY(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(1, 1)), true, 0));
+ EXPECT_EQ(origin.y(),
+ PosY(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(1, 1)), true, 0));
+ EXPECT_EQ(
+ 1, SizeY(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(100, 1)), true, 0));
+ EXPECT_EQ(
+ origin.y(),
+ PosY(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(100, 1)), true, 0));
+ EXPECT_EQ(
+ 3, SizeY(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(1, 3)), true, 0));
+ EXPECT_EQ(origin.y(),
+ PosY(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(1, 3)), true, 0));
+ EXPECT_EQ(
+ 3, SizeY(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(100, 3)), true, 0));
+ EXPECT_EQ(
+ origin.y(),
+ PosY(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(100, 3)), true, 0));
// Multiple tiles:
// no border
// positions 0, 3
- EXPECT_EQ(2, NumTiles(gfx::Size(3, 3), gfx::Size(1, 6), false));
- EXPECT_EQ(3, SizeY(gfx::Size(3, 3), gfx::Size(1, 6), false, 0));
- EXPECT_EQ(3, SizeY(gfx::Size(3, 3), gfx::Size(1, 6), false, 1));
- EXPECT_EQ(0, PosY(gfx::Size(3, 3), gfx::Size(1, 6), false, 0));
- EXPECT_EQ(3, PosY(gfx::Size(3, 3), gfx::Size(1, 6), false, 1));
- EXPECT_EQ(3, SizeY(gfx::Size(3, 3), gfx::Size(100, 6), false, 0));
- EXPECT_EQ(3, SizeY(gfx::Size(3, 3), gfx::Size(100, 6), false, 1));
- EXPECT_EQ(0, PosY(gfx::Size(3, 3), gfx::Size(100, 6), false, 0));
- EXPECT_EQ(3, PosY(gfx::Size(3, 3), gfx::Size(100, 6), false, 1));
+ EXPECT_EQ(
+ 2, NumTiles(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(1, 6)), false));
+ EXPECT_EQ(
+ 3, SizeY(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(1, 6)), false, 0));
+ EXPECT_EQ(
+ 3, SizeY(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(1, 6)), false, 1));
+ EXPECT_EQ(
+ origin.y() + 0,
+ PosY(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(1, 6)), false, 0));
+ EXPECT_EQ(
+ origin.y() + 3,
+ PosY(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(1, 6)), false, 1));
+ EXPECT_EQ(
+ 3,
+ SizeY(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(100, 6)), false, 0));
+ EXPECT_EQ(
+ 3,
+ SizeY(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(100, 6)), false, 1));
+ EXPECT_EQ(
+ origin.y() + 0,
+ PosY(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(100, 6)), false, 0));
+ EXPECT_EQ(
+ origin.y() + 3,
+ PosY(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(100, 6)), false, 1));
// Multiple tiles:
// with border
// positions 0, 2, 3, 4
- EXPECT_EQ(4, NumTiles(gfx::Size(3, 3), gfx::Size(1, 6), true));
- EXPECT_EQ(2, SizeY(gfx::Size(3, 3), gfx::Size(1, 6), true, 0));
- EXPECT_EQ(1, SizeY(gfx::Size(3, 3), gfx::Size(1, 6), true, 1));
- EXPECT_EQ(1, SizeY(gfx::Size(3, 3), gfx::Size(1, 6), true, 2));
- EXPECT_EQ(2, SizeY(gfx::Size(3, 3), gfx::Size(1, 6), true, 3));
- EXPECT_EQ(0, PosY(gfx::Size(3, 3), gfx::Size(1, 6), true, 0));
- EXPECT_EQ(2, PosY(gfx::Size(3, 3), gfx::Size(1, 6), true, 1));
- EXPECT_EQ(3, PosY(gfx::Size(3, 3), gfx::Size(1, 6), true, 2));
- EXPECT_EQ(4, PosY(gfx::Size(3, 3), gfx::Size(1, 6), true, 3));
- EXPECT_EQ(2, SizeY(gfx::Size(7, 3), gfx::Size(100, 6), true, 0));
- EXPECT_EQ(1, SizeY(gfx::Size(7, 3), gfx::Size(100, 6), true, 1));
- EXPECT_EQ(1, SizeY(gfx::Size(7, 3), gfx::Size(100, 6), true, 2));
- EXPECT_EQ(2, SizeY(gfx::Size(7, 3), gfx::Size(100, 6), true, 3));
- EXPECT_EQ(0, PosY(gfx::Size(7, 3), gfx::Size(100, 6), true, 0));
- EXPECT_EQ(2, PosY(gfx::Size(7, 3), gfx::Size(100, 6), true, 1));
- EXPECT_EQ(3, PosY(gfx::Size(7, 3), gfx::Size(100, 6), true, 2));
- EXPECT_EQ(4, PosY(gfx::Size(7, 3), gfx::Size(100, 6), true, 3));
+ EXPECT_EQ(
+ 4, NumTiles(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(1, 6)), true));
+ EXPECT_EQ(
+ 2, SizeY(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(1, 6)), true, 0));
+ EXPECT_EQ(
+ 1, SizeY(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(1, 6)), true, 1));
+ EXPECT_EQ(
+ 1, SizeY(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(1, 6)), true, 2));
+ EXPECT_EQ(
+ 2, SizeY(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(1, 6)), true, 3));
+ EXPECT_EQ(origin.y() + 0,
+ PosY(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(1, 6)), true, 0));
+ EXPECT_EQ(origin.y() + 2,
+ PosY(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(1, 6)), true, 1));
+ EXPECT_EQ(origin.y() + 3,
+ PosY(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(1, 6)), true, 2));
+ EXPECT_EQ(origin.y() + 4,
+ PosY(gfx::Size(3, 3), gfx::Rect(origin, gfx::Size(1, 6)), true, 3));
+ EXPECT_EQ(
+ 2, SizeY(gfx::Size(7, 3), gfx::Rect(origin, gfx::Size(100, 6)), true, 0));
+ EXPECT_EQ(
+ 1, SizeY(gfx::Size(7, 3), gfx::Rect(origin, gfx::Size(100, 6)), true, 1));
+ EXPECT_EQ(
+ 1, SizeY(gfx::Size(7, 3), gfx::Rect(origin, gfx::Size(100, 6)), true, 2));
+ EXPECT_EQ(
+ 2, SizeY(gfx::Size(7, 3), gfx::Rect(origin, gfx::Size(100, 6)), true, 3));
+ EXPECT_EQ(
+ origin.y() + 0,
+ PosY(gfx::Size(7, 3), gfx::Rect(origin, gfx::Size(100, 6)), true, 0));
+ EXPECT_EQ(
+ origin.y() + 2,
+ PosY(gfx::Size(7, 3), gfx::Rect(origin, gfx::Size(100, 6)), true, 1));
+ EXPECT_EQ(
+ origin.y() + 3,
+ PosY(gfx::Size(7, 3), gfx::Rect(origin, gfx::Size(100, 6)), true, 2));
+ EXPECT_EQ(
+ origin.y() + 4,
+ PosY(gfx::Size(7, 3), gfx::Rect(origin, gfx::Size(100, 6)), true, 3));
}
-TEST(TilingDataTest, SetTotalSize) {
- TilingData data(gfx::Size(5, 5), gfx::Size(5, 5), false);
- EXPECT_EQ(5, data.total_size().width());
- EXPECT_EQ(5, data.total_size().height());
+TEST_P(TilingDataTest, SetTotalSize) {
+ gfx::Point origin = GetParam();
+
+ TilingData data(gfx::Size(5, 5), gfx::Rect(origin, gfx::Size(5, 5)), false);
+ EXPECT_EQ(origin.x(), data.tiling_rect().x());
+ EXPECT_EQ(origin.y(), data.tiling_rect().y());
+ EXPECT_EQ(5, data.tiling_rect().width());
+ EXPECT_EQ(5, data.tiling_rect().height());
EXPECT_EQ(1, data.num_tiles_x());
EXPECT_EQ(5, data.TileSizeX(0));
EXPECT_EQ(1, data.num_tiles_y());
EXPECT_EQ(5, data.TileSizeY(0));
- data.SetTotalSize(gfx::Size(6, 5));
- EXPECT_EQ(6, data.total_size().width());
- EXPECT_EQ(5, data.total_size().height());
+ data.SetTilingRect(gfx::Rect(36, 82, 6, 5));
+ EXPECT_EQ(36, data.tiling_rect().x());
+ EXPECT_EQ(82, data.tiling_rect().y());
+ EXPECT_EQ(6, data.tiling_rect().width());
+ EXPECT_EQ(5, data.tiling_rect().height());
EXPECT_EQ(2, data.num_tiles_x());
EXPECT_EQ(5, data.TileSizeX(0));
EXPECT_EQ(1, data.TileSizeX(1));
EXPECT_EQ(1, data.num_tiles_y());
EXPECT_EQ(5, data.TileSizeY(0));
- data.SetTotalSize(gfx::Size(5, 12));
- EXPECT_EQ(5, data.total_size().width());
- EXPECT_EQ(12, data.total_size().height());
+ data.SetTilingRect(gfx::Rect(4, 22, 5, 12));
+ EXPECT_EQ(4, data.tiling_rect().x());
+ EXPECT_EQ(22, data.tiling_rect().y());
+ EXPECT_EQ(5, data.tiling_rect().width());
+ EXPECT_EQ(12, data.tiling_rect().height());
EXPECT_EQ(1, data.num_tiles_x());
EXPECT_EQ(5, data.TileSizeX(0));
EXPECT_EQ(3, data.num_tiles_y());
@@ -729,8 +2077,10 @@ TEST(TilingDataTest, SetTotalSize) {
EXPECT_EQ(2, data.TileSizeY(2));
}
-TEST(TilingDataTest, SetMaxTextureSizeNoBorders) {
- TilingData data(gfx::Size(8, 8), gfx::Size(16, 32), false);
+TEST_P(TilingDataTest, SetMaxTextureSizeNoBorders) {
+ gfx::Point origin = GetParam();
+
+ TilingData data(gfx::Size(8, 8), gfx::Rect(origin, gfx::Size(16, 32)), false);
EXPECT_EQ(2, data.num_tiles_x());
EXPECT_EQ(4, data.num_tiles_y());
@@ -755,8 +2105,10 @@ TEST(TilingDataTest, SetMaxTextureSizeNoBorders) {
EXPECT_EQ(7, data.num_tiles_y());
}
-TEST(TilingDataTest, SetMaxTextureSizeBorders) {
- TilingData data(gfx::Size(8, 8), gfx::Size(16, 32), true);
+TEST_P(TilingDataTest, SetMaxTextureSizeBorders) {
+ gfx::Point origin = GetParam();
+
+ TilingData data(gfx::Size(8, 8), gfx::Rect(origin, gfx::Size(16, 32)), true);
EXPECT_EQ(3, data.num_tiles_x());
EXPECT_EQ(5, data.num_tiles_y());
@@ -781,31 +2133,172 @@ TEST(TilingDataTest, SetMaxTextureSizeBorders) {
EXPECT_EQ(10, data.num_tiles_y());
}
-TEST(TilingDataTest, Assignment) {
+TEST_P(TilingDataTest, ExpandRectToTileBoundsWithBordersEmpty) {
+ gfx::Point origin = GetParam();
+ TilingData empty_total_size(
+ gfx::Size(0, 0), gfx::Rect(origin, gfx::Size(8, 8)), true);
+ EXPECT_RECT_EQ(
+ gfx::Rect(),
+ empty_total_size.ExpandRectToTileBoundsWithBorders(gfx::Rect()));
+ EXPECT_RECT_EQ(gfx::Rect(),
+ empty_total_size.ExpandRectToTileBoundsWithBorders(
+ gfx::Rect(100, 100, 100, 100)));
+ EXPECT_RECT_EQ(gfx::Rect(),
+ empty_total_size.ExpandRectToTileBoundsWithBorders(
+ gfx::Rect(0, 0, 100, 100)));
+
+ TilingData empty_max_texture_size(
+ gfx::Size(8, 8), gfx::Rect(origin, gfx::Size(0, 0)), true);
+ EXPECT_RECT_EQ(
+ gfx::Rect(),
+ empty_max_texture_size.ExpandRectToTileBoundsWithBorders(gfx::Rect()));
+ EXPECT_RECT_EQ(gfx::Rect(),
+ empty_max_texture_size.ExpandRectToTileBoundsWithBorders(
+ gfx::Rect(100, 100, 100, 100)));
+ EXPECT_RECT_EQ(gfx::Rect(),
+ empty_max_texture_size.ExpandRectToTileBoundsWithBorders(
+ gfx::Rect(0, 0, 100, 100)));
+}
+
+TEST_P(TilingDataTest, ExpandRectToTileBoundsWithBorders) {
+ gfx::Point origin = GetParam();
+ TilingData data(gfx::Size(4, 4), gfx::Rect(origin, gfx::Size(16, 32)), true);
+
+ // Small rect at origin rounds up to tile 0, 0.
+ gfx::Rect at_origin_src(origin, gfx::Size(1, 1));
+ gfx::Rect at_origin_result(data.TileBoundsWithBorder(0, 0));
+ EXPECT_NE(at_origin_src, at_origin_result);
+ EXPECT_RECT_EQ(at_origin_result,
+ data.ExpandRectToTileBoundsWithBorders(at_origin_src));
+
+ // Arbitrary internal rect.
+ gfx::Rect rect_src(origin.x() + 6, origin.y() + 6, 1, 3);
+ // Tile 2, 2 => gfx::Rect(4, 4, 4, 4)
+ // Tile 3, 4 => gfx::Rect(6, 8, 4, 4)
+ gfx::Rect rect_result(gfx::UnionRects(data.TileBoundsWithBorder(2, 2),
+ data.TileBoundsWithBorder(3, 4)));
+ EXPECT_NE(rect_src, rect_result);
+ EXPECT_RECT_EQ(rect_result, data.ExpandRectToTileBoundsWithBorders(rect_src));
+
+ // On tile bounds rounds up to next tile (since border overlaps).
+ gfx::Rect border_rect_src(
+ gfx::UnionRects(data.TileBounds(1, 2), data.TileBounds(3, 4)));
+ gfx::Rect border_rect_result(gfx::UnionRects(
+ data.TileBoundsWithBorder(0, 1), data.TileBoundsWithBorder(4, 5)));
+ EXPECT_RECT_EQ(border_rect_result,
+ data.ExpandRectToTileBoundsWithBorders(border_rect_src));
+
+ // Equal to tiling rect.
+ EXPECT_RECT_EQ(data.tiling_rect(),
+ data.ExpandRectToTileBoundsWithBorders(data.tiling_rect()));
+
+ // Containing, but larger than tiling rect.
+ EXPECT_RECT_EQ(data.tiling_rect(),
+ data.ExpandRectToTileBoundsWithBorders(
+ gfx::Rect(origin, gfx::Size(100, 100))));
+
+ // Non-intersecting with tiling rect.
+ gfx::Rect non_intersect(origin.x() + 200, origin.y() + 200, 100, 100);
+ EXPECT_FALSE(non_intersect.Intersects(data.tiling_rect()));
+ EXPECT_RECT_EQ(gfx::Rect(),
+ data.ExpandRectToTileBoundsWithBorders(non_intersect));
+
+ TilingData data2(gfx::Size(8, 8), gfx::Rect(origin, gfx::Size(32, 64)), true);
+
+ // Inside other tile border texels doesn't include other tiles.
+ gfx::Rect inner_rect_src(data2.TileBounds(1, 1));
+ inner_rect_src.Inset(data2.border_texels(), data.border_texels());
+ gfx::Rect inner_rect_result(data2.TileBoundsWithBorder(1, 1));
+ gfx::Rect expanded = data2.ExpandRectToTileBoundsWithBorders(inner_rect_src);
+ EXPECT_EQ(inner_rect_result.ToString(), expanded.ToString());
+}
+
+TEST_P(TilingDataTest, ExpandRectToTileBounds) {
+ gfx::Point origin = GetParam();
+ TilingData data(gfx::Size(4, 4), gfx::Rect(origin, gfx::Size(16, 32)), true);
+
+ // Small rect at origin rounds up to tile 0, 0.
+ gfx::Rect at_origin_src(origin, gfx::Size(1, 1));
+ gfx::Rect at_origin_result(data.TileBounds(0, 0));
+ EXPECT_NE(at_origin_src, at_origin_result);
+ EXPECT_RECT_EQ(at_origin_result, data.ExpandRectToTileBounds(at_origin_src));
+
+ // Arbitrary internal rect.
+ gfx::Rect rect_src(origin.x() + 6, origin.y() + 6, 1, 3);
+ // Tile 2, 2 => gfx::Rect(4, 4, 4, 4)
+ // Tile 3, 4 => gfx::Rect(6, 8, 4, 4)
+ gfx::Rect rect_result(
+ gfx::UnionRects(data.TileBounds(2, 2), data.TileBounds(3, 4)));
+ EXPECT_NE(rect_src, rect_result);
+ EXPECT_RECT_EQ(rect_result, data.ExpandRectToTileBounds(rect_src));
+
+ // On tile bounds rounds up to next tile (since border overlaps).
+ gfx::Rect border_rect_src(
+ gfx::UnionRects(data.TileBounds(1, 2), data.TileBounds(3, 4)));
+ gfx::Rect border_rect_result(
+ gfx::UnionRects(data.TileBounds(0, 1), data.TileBounds(4, 5)));
+ EXPECT_RECT_EQ(border_rect_result,
+ data.ExpandRectToTileBounds(border_rect_src));
+
+ // Equal to tiling rect.
+ EXPECT_RECT_EQ(data.tiling_rect(),
+ data.ExpandRectToTileBounds(data.tiling_rect()));
+
+ // Containing, but larger than tiling rect.
+ EXPECT_RECT_EQ(
+ data.tiling_rect(),
+ data.ExpandRectToTileBounds(gfx::Rect(origin, gfx::Size(100, 100))));
+
+ // Non-intersecting with tiling rect.
+ gfx::Rect non_intersect(origin.x() + 200, origin.y() + 200, 100, 100);
+ EXPECT_FALSE(non_intersect.Intersects(data.tiling_rect()));
+ EXPECT_RECT_EQ(gfx::Rect(), data.ExpandRectToTileBounds(non_intersect));
+
+ TilingData data2(gfx::Size(8, 8), gfx::Rect(origin, gfx::Size(32, 64)), true);
+
+ // Inside other tile border texels doesn't include other tiles.
+ gfx::Rect inner_rect_src(data2.TileBounds(1, 1));
+ inner_rect_src.Inset(data2.border_texels(), data.border_texels());
+ gfx::Rect inner_rect_result(data2.TileBounds(1, 1));
+ gfx::Rect expanded = data2.ExpandRectToTileBounds(inner_rect_src);
+ EXPECT_EQ(inner_rect_result.ToString(), expanded.ToString());
+}
+
+TEST_P(TilingDataTest, Assignment) {
+ gfx::Point origin = GetParam();
+
{
- TilingData source(gfx::Size(8, 8), gfx::Size(16, 32), true);
+ TilingData source(
+ gfx::Size(8, 8), gfx::Rect(origin, gfx::Size(16, 32)), true);
TilingData dest = source;
EXPECT_EQ(source.border_texels(), dest.border_texels());
EXPECT_EQ(source.max_texture_size(), dest.max_texture_size());
EXPECT_EQ(source.num_tiles_x(), dest.num_tiles_x());
EXPECT_EQ(source.num_tiles_y(), dest.num_tiles_y());
- EXPECT_EQ(source.total_size().width(), dest.total_size().width());
- EXPECT_EQ(source.total_size().height(), dest.total_size().height());
+ EXPECT_EQ(source.tiling_rect().x(), dest.tiling_rect().x());
+ EXPECT_EQ(source.tiling_rect().y(), dest.tiling_rect().y());
+ EXPECT_EQ(source.tiling_rect().width(), dest.tiling_rect().width());
+ EXPECT_EQ(source.tiling_rect().height(), dest.tiling_rect().height());
}
{
- TilingData source(gfx::Size(7, 3), gfx::Size(6, 100), false);
+ TilingData source(
+ gfx::Size(7, 3), gfx::Rect(origin, gfx::Size(6, 100)), false);
TilingData dest(source);
EXPECT_EQ(source.border_texels(), dest.border_texels());
EXPECT_EQ(source.max_texture_size(), dest.max_texture_size());
EXPECT_EQ(source.num_tiles_x(), dest.num_tiles_x());
EXPECT_EQ(source.num_tiles_y(), dest.num_tiles_y());
- EXPECT_EQ(source.total_size().width(), dest.total_size().width());
- EXPECT_EQ(source.total_size().height(), dest.total_size().height());
+ EXPECT_EQ(source.tiling_rect().x(), dest.tiling_rect().x());
+ EXPECT_EQ(source.tiling_rect().y(), dest.tiling_rect().y());
+ EXPECT_EQ(source.tiling_rect().width(), dest.tiling_rect().width());
+ EXPECT_EQ(source.tiling_rect().height(), dest.tiling_rect().height());
}
}
-TEST(TilingDataTest, SetBorderTexels) {
- TilingData data(gfx::Size(8, 8), gfx::Size(16, 32), false);
+TEST_P(TilingDataTest, SetBorderTexels) {
+ gfx::Point origin = GetParam();
+
+ TilingData data(gfx::Size(8, 8), gfx::Rect(origin, gfx::Size(16, 32)), false);
EXPECT_EQ(2, data.num_tiles_x());
EXPECT_EQ(4, data.num_tiles_y());
@@ -813,17 +2306,16 @@ TEST(TilingDataTest, SetBorderTexels) {
EXPECT_EQ(3, data.num_tiles_x());
EXPECT_EQ(5, data.num_tiles_y());
- data.SetHasBorderTexels(true);
- EXPECT_EQ(3, data.num_tiles_x());
- EXPECT_EQ(5, data.num_tiles_y());
-
data.SetHasBorderTexels(false);
EXPECT_EQ(2, data.num_tiles_x());
EXPECT_EQ(4, data.num_tiles_y());
}
-TEST(TilingDataTest, LargeBorders) {
- TilingData data(gfx::Size(100, 80), gfx::Size(200, 145), 30);
+TEST_P(TilingDataTest, LargeBorders) {
+ gfx::Point origin = GetParam();
+
+ TilingData data(
+ gfx::Size(100, 80), gfx::Rect(origin, gfx::Size(200, 145)), 30);
EXPECT_EQ(30, data.border_texels());
EXPECT_EQ(70, data.TileSizeX(0));
@@ -839,87 +2331,96 @@ TEST(TilingDataTest, LargeBorders) {
EXPECT_EQ(35, data.TileSizeY(4));
EXPECT_EQ(5, data.num_tiles_y());
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 70, 50), data.TileBounds(0, 0));
- EXPECT_RECT_EQ(gfx::Rect(70, 50, 40, 20), data.TileBounds(1, 1));
- EXPECT_RECT_EQ(gfx::Rect(110, 110, 40, 35), data.TileBounds(2, 4));
- EXPECT_RECT_EQ(gfx::Rect(150, 70, 50, 20), data.TileBounds(3, 2));
- EXPECT_RECT_EQ(gfx::Rect(150, 110, 50, 35), data.TileBounds(3, 4));
-
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 80), data.TileBoundsWithBorder(0, 0));
- EXPECT_RECT_EQ(gfx::Rect(40, 20, 100, 80), data.TileBoundsWithBorder(1, 1));
- EXPECT_RECT_EQ(gfx::Rect(80, 80, 100, 65), data.TileBoundsWithBorder(2, 4));
- EXPECT_RECT_EQ(gfx::Rect(120, 40, 80, 80), data.TileBoundsWithBorder(3, 2));
- EXPECT_RECT_EQ(gfx::Rect(120, 80, 80, 65), data.TileBoundsWithBorder(3, 4));
-
- EXPECT_EQ(0, data.TileXIndexFromSrcCoord(0));
- EXPECT_EQ(0, data.TileXIndexFromSrcCoord(69));
- EXPECT_EQ(1, data.TileXIndexFromSrcCoord(70));
- EXPECT_EQ(1, data.TileXIndexFromSrcCoord(109));
- EXPECT_EQ(2, data.TileXIndexFromSrcCoord(110));
- EXPECT_EQ(2, data.TileXIndexFromSrcCoord(149));
- EXPECT_EQ(3, data.TileXIndexFromSrcCoord(150));
- EXPECT_EQ(3, data.TileXIndexFromSrcCoord(199));
-
- EXPECT_EQ(0, data.TileYIndexFromSrcCoord(0));
- EXPECT_EQ(0, data.TileYIndexFromSrcCoord(49));
- EXPECT_EQ(1, data.TileYIndexFromSrcCoord(50));
- EXPECT_EQ(1, data.TileYIndexFromSrcCoord(69));
- EXPECT_EQ(2, data.TileYIndexFromSrcCoord(70));
- EXPECT_EQ(2, data.TileYIndexFromSrcCoord(89));
- EXPECT_EQ(3, data.TileYIndexFromSrcCoord(90));
- EXPECT_EQ(3, data.TileYIndexFromSrcCoord(109));
- EXPECT_EQ(4, data.TileYIndexFromSrcCoord(110));
- EXPECT_EQ(4, data.TileYIndexFromSrcCoord(144));
-
- EXPECT_EQ(0, data.FirstBorderTileXIndexFromSrcCoord(0));
- EXPECT_EQ(0, data.FirstBorderTileXIndexFromSrcCoord(99));
- EXPECT_EQ(1, data.FirstBorderTileXIndexFromSrcCoord(100));
- EXPECT_EQ(1, data.FirstBorderTileXIndexFromSrcCoord(139));
- EXPECT_EQ(2, data.FirstBorderTileXIndexFromSrcCoord(140));
- EXPECT_EQ(2, data.FirstBorderTileXIndexFromSrcCoord(179));
- EXPECT_EQ(3, data.FirstBorderTileXIndexFromSrcCoord(180));
- EXPECT_EQ(3, data.FirstBorderTileXIndexFromSrcCoord(199));
-
- EXPECT_EQ(0, data.FirstBorderTileYIndexFromSrcCoord(0));
- EXPECT_EQ(0, data.FirstBorderTileYIndexFromSrcCoord(79));
- EXPECT_EQ(1, data.FirstBorderTileYIndexFromSrcCoord(80));
- EXPECT_EQ(1, data.FirstBorderTileYIndexFromSrcCoord(99));
- EXPECT_EQ(2, data.FirstBorderTileYIndexFromSrcCoord(100));
- EXPECT_EQ(2, data.FirstBorderTileYIndexFromSrcCoord(119));
- EXPECT_EQ(3, data.FirstBorderTileYIndexFromSrcCoord(120));
- EXPECT_EQ(3, data.FirstBorderTileYIndexFromSrcCoord(139));
- EXPECT_EQ(4, data.FirstBorderTileYIndexFromSrcCoord(140));
- EXPECT_EQ(4, data.FirstBorderTileYIndexFromSrcCoord(144));
-
- EXPECT_EQ(0, data.LastBorderTileXIndexFromSrcCoord(0));
- EXPECT_EQ(0, data.LastBorderTileXIndexFromSrcCoord(39));
- EXPECT_EQ(1, data.LastBorderTileXIndexFromSrcCoord(40));
- EXPECT_EQ(1, data.LastBorderTileXIndexFromSrcCoord(79));
- EXPECT_EQ(2, data.LastBorderTileXIndexFromSrcCoord(80));
- EXPECT_EQ(2, data.LastBorderTileXIndexFromSrcCoord(119));
- EXPECT_EQ(3, data.LastBorderTileXIndexFromSrcCoord(120));
- EXPECT_EQ(3, data.LastBorderTileXIndexFromSrcCoord(199));
-
- EXPECT_EQ(0, data.LastBorderTileYIndexFromSrcCoord(0));
- EXPECT_EQ(0, data.LastBorderTileYIndexFromSrcCoord(19));
- EXPECT_EQ(1, data.LastBorderTileYIndexFromSrcCoord(20));
- EXPECT_EQ(1, data.LastBorderTileYIndexFromSrcCoord(39));
- EXPECT_EQ(2, data.LastBorderTileYIndexFromSrcCoord(40));
- EXPECT_EQ(2, data.LastBorderTileYIndexFromSrcCoord(59));
- EXPECT_EQ(3, data.LastBorderTileYIndexFromSrcCoord(60));
- EXPECT_EQ(3, data.LastBorderTileYIndexFromSrcCoord(79));
- EXPECT_EQ(4, data.LastBorderTileYIndexFromSrcCoord(80));
- EXPECT_EQ(4, data.LastBorderTileYIndexFromSrcCoord(144));
+ EXPECT_RECT_EQ(gfx::Rect(origin.x() + 0, origin.y() + 0, 70, 50),
+ data.TileBounds(0, 0));
+ EXPECT_RECT_EQ(gfx::Rect(origin.x() + 70, origin.y() + 50, 40, 20),
+ data.TileBounds(1, 1));
+ EXPECT_RECT_EQ(gfx::Rect(origin.x() + 110, origin.y() + 110, 40, 35),
+ data.TileBounds(2, 4));
+ EXPECT_RECT_EQ(gfx::Rect(origin.x() + 150, origin.y() + 70, 50, 20),
+ data.TileBounds(3, 2));
+ EXPECT_RECT_EQ(gfx::Rect(origin.x() + 150, origin.y() + 110, 50, 35),
+ data.TileBounds(3, 4));
+
+ EXPECT_RECT_EQ(gfx::Rect(origin.x() + 0, origin.y() + 0, 100, 80),
+ data.TileBoundsWithBorder(0, 0));
+ EXPECT_RECT_EQ(gfx::Rect(origin.x() + 40, origin.y() + 20, 100, 80),
+ data.TileBoundsWithBorder(1, 1));
+ EXPECT_RECT_EQ(gfx::Rect(origin.x() + 80, origin.y() + 80, 100, 65),
+ data.TileBoundsWithBorder(2, 4));
+ EXPECT_RECT_EQ(gfx::Rect(origin.x() + 120, origin.y() + 40, 80, 80),
+ data.TileBoundsWithBorder(3, 2));
+ EXPECT_RECT_EQ(gfx::Rect(origin.x() + 120, origin.y() + 80, 80, 65),
+ data.TileBoundsWithBorder(3, 4));
+
+ EXPECT_EQ(0, data.TileXIndexFromSrcCoord(origin.x() + 0));
+ EXPECT_EQ(0, data.TileXIndexFromSrcCoord(origin.x() + 69));
+ EXPECT_EQ(1, data.TileXIndexFromSrcCoord(origin.x() + 70));
+ EXPECT_EQ(1, data.TileXIndexFromSrcCoord(origin.x() + 109));
+ EXPECT_EQ(2, data.TileXIndexFromSrcCoord(origin.x() + 110));
+ EXPECT_EQ(2, data.TileXIndexFromSrcCoord(origin.x() + 149));
+ EXPECT_EQ(3, data.TileXIndexFromSrcCoord(origin.x() + 150));
+ EXPECT_EQ(3, data.TileXIndexFromSrcCoord(origin.x() + 199));
+
+ EXPECT_EQ(0, data.TileYIndexFromSrcCoord(origin.y() + 0));
+ EXPECT_EQ(0, data.TileYIndexFromSrcCoord(origin.y() + 49));
+ EXPECT_EQ(1, data.TileYIndexFromSrcCoord(origin.y() + 50));
+ EXPECT_EQ(1, data.TileYIndexFromSrcCoord(origin.y() + 69));
+ EXPECT_EQ(2, data.TileYIndexFromSrcCoord(origin.y() + 70));
+ EXPECT_EQ(2, data.TileYIndexFromSrcCoord(origin.y() + 89));
+ EXPECT_EQ(3, data.TileYIndexFromSrcCoord(origin.y() + 90));
+ EXPECT_EQ(3, data.TileYIndexFromSrcCoord(origin.y() + 109));
+ EXPECT_EQ(4, data.TileYIndexFromSrcCoord(origin.y() + 110));
+ EXPECT_EQ(4, data.TileYIndexFromSrcCoord(origin.y() + 144));
+
+ EXPECT_EQ(0, data.FirstBorderTileXIndexFromSrcCoord(origin.x() + 0));
+ EXPECT_EQ(0, data.FirstBorderTileXIndexFromSrcCoord(origin.x() + 99));
+ EXPECT_EQ(1, data.FirstBorderTileXIndexFromSrcCoord(origin.x() + 100));
+ EXPECT_EQ(1, data.FirstBorderTileXIndexFromSrcCoord(origin.x() + 139));
+ EXPECT_EQ(2, data.FirstBorderTileXIndexFromSrcCoord(origin.x() + 140));
+ EXPECT_EQ(2, data.FirstBorderTileXIndexFromSrcCoord(origin.x() + 179));
+ EXPECT_EQ(3, data.FirstBorderTileXIndexFromSrcCoord(origin.x() + 180));
+ EXPECT_EQ(3, data.FirstBorderTileXIndexFromSrcCoord(origin.x() + 199));
+
+ EXPECT_EQ(0, data.FirstBorderTileYIndexFromSrcCoord(origin.y() + 0));
+ EXPECT_EQ(0, data.FirstBorderTileYIndexFromSrcCoord(origin.y() + 79));
+ EXPECT_EQ(1, data.FirstBorderTileYIndexFromSrcCoord(origin.y() + 80));
+ EXPECT_EQ(1, data.FirstBorderTileYIndexFromSrcCoord(origin.y() + 99));
+ EXPECT_EQ(2, data.FirstBorderTileYIndexFromSrcCoord(origin.y() + 100));
+ EXPECT_EQ(2, data.FirstBorderTileYIndexFromSrcCoord(origin.y() + 119));
+ EXPECT_EQ(3, data.FirstBorderTileYIndexFromSrcCoord(origin.y() + 120));
+ EXPECT_EQ(3, data.FirstBorderTileYIndexFromSrcCoord(origin.y() + 139));
+ EXPECT_EQ(4, data.FirstBorderTileYIndexFromSrcCoord(origin.y() + 140));
+ EXPECT_EQ(4, data.FirstBorderTileYIndexFromSrcCoord(origin.y() + 144));
+
+ EXPECT_EQ(0, data.LastBorderTileXIndexFromSrcCoord(origin.x() + 0));
+ EXPECT_EQ(0, data.LastBorderTileXIndexFromSrcCoord(origin.x() + 39));
+ EXPECT_EQ(1, data.LastBorderTileXIndexFromSrcCoord(origin.x() + 40));
+ EXPECT_EQ(1, data.LastBorderTileXIndexFromSrcCoord(origin.x() + 79));
+ EXPECT_EQ(2, data.LastBorderTileXIndexFromSrcCoord(origin.x() + 80));
+ EXPECT_EQ(2, data.LastBorderTileXIndexFromSrcCoord(origin.x() + 119));
+ EXPECT_EQ(3, data.LastBorderTileXIndexFromSrcCoord(origin.x() + 120));
+ EXPECT_EQ(3, data.LastBorderTileXIndexFromSrcCoord(origin.x() + 199));
+
+ EXPECT_EQ(0, data.LastBorderTileYIndexFromSrcCoord(origin.y() + 0));
+ EXPECT_EQ(0, data.LastBorderTileYIndexFromSrcCoord(origin.y() + 19));
+ EXPECT_EQ(1, data.LastBorderTileYIndexFromSrcCoord(origin.y() + 20));
+ EXPECT_EQ(1, data.LastBorderTileYIndexFromSrcCoord(origin.y() + 39));
+ EXPECT_EQ(2, data.LastBorderTileYIndexFromSrcCoord(origin.y() + 40));
+ EXPECT_EQ(2, data.LastBorderTileYIndexFromSrcCoord(origin.y() + 59));
+ EXPECT_EQ(3, data.LastBorderTileYIndexFromSrcCoord(origin.y() + 60));
+ EXPECT_EQ(3, data.LastBorderTileYIndexFromSrcCoord(origin.y() + 79));
+ EXPECT_EQ(4, data.LastBorderTileYIndexFromSrcCoord(origin.y() + 80));
+ EXPECT_EQ(4, data.LastBorderTileYIndexFromSrcCoord(origin.y() + 144));
}
-void TestIterate(
- const TilingData& data,
- gfx::Rect rect,
- int expect_left,
- int expect_top,
- int expect_right,
- int expect_bottom) {
-
+void TestIterate(const TilingData& data,
+ gfx::Rect rect,
+ int expect_left,
+ int expect_top,
+ int expect_right,
+ int expect_bottom,
+ bool include_borders) {
EXPECT_GE(expect_left, 0);
EXPECT_GE(expect_top, 0);
EXPECT_LT(expect_right, data.num_tiles_x());
@@ -928,7 +2429,11 @@ void TestIterate(
std::vector<std::pair<int, int> > original_expected;
for (int x = 0; x < data.num_tiles_x(); ++x) {
for (int y = 0; y < data.num_tiles_y(); ++y) {
- gfx::Rect bounds = data.TileBoundsWithBorder(x, y);
+ gfx::Rect bounds;
+ if (include_borders)
+ bounds = data.TileBoundsWithBorder(x, y);
+ else
+ bounds = data.TileBounds(x, y);
if (x >= expect_left && x <= expect_right &&
y >= expect_top && y <= expect_bottom) {
EXPECT_TRUE(bounds.Intersects(rect));
@@ -942,7 +2447,8 @@ void TestIterate(
// Verify with vanilla iterator.
{
std::vector<std::pair<int, int> > expected = original_expected;
- for (TilingData::Iterator iter(&data, rect); iter; ++iter) {
+ for (TilingData::Iterator iter(&data, rect, include_borders); iter;
+ ++iter) {
bool found = false;
for (size_t i = 0; i < expected.size(); ++i) {
if (expected[i] == iter.index()) {
@@ -958,7 +2464,8 @@ void TestIterate(
}
// Make sure this also works with a difference iterator and an empty ignore.
- {
+ // The difference iterator always includes borders, so ignore it otherwise.
+ if (include_borders) {
std::vector<std::pair<int, int> > expected = original_expected;
for (TilingData::DifferenceIterator iter(&data, rect, gfx::Rect());
iter; ++iter) {
@@ -977,74 +2484,282 @@ void TestIterate(
}
}
-TEST(TilingDataTest, IteratorNoBorderTexels) {
- TilingData data(gfx::Size(10, 10), gfx::Size(40, 25), false);
+void TestIterateBorders(const TilingData& data,
+ gfx::Rect rect,
+ int expect_left,
+ int expect_top,
+ int expect_right,
+ int expect_bottom) {
+ bool include_borders = true;
+ TestIterate(data,
+ rect,
+ expect_left,
+ expect_top,
+ expect_right,
+ expect_bottom,
+ include_borders);
+}
+
+void TestIterateNoBorders(const TilingData& data,
+ gfx::Rect rect,
+ int expect_left,
+ int expect_top,
+ int expect_right,
+ int expect_bottom) {
+ bool include_borders = false;
+ TestIterate(data,
+ rect,
+ expect_left,
+ expect_top,
+ expect_right,
+ expect_bottom,
+ include_borders);
+}
+
+void TestIterateAll(const TilingData& data,
+ gfx::Rect rect,
+ int expect_left,
+ int expect_top,
+ int expect_right,
+ int expect_bottom) {
+ TestIterateBorders(
+ data, rect, expect_left, expect_top, expect_right, expect_bottom);
+ TestIterateNoBorders(
+ data, rect, expect_left, expect_top, expect_right, expect_bottom);
+}
+
+TEST_P(TilingDataTest, IteratorNoBorderTexels) {
+ gfx::Point origin = GetParam();
+
+ TilingData data(
+ gfx::Size(10, 10), gfx::Rect(origin, gfx::Size(40, 25)), false);
+ // The following Coordinates are relative to the origin.
// X border index by src coord: [0-10), [10-20), [20, 30), [30, 40)
// Y border index by src coord: [0-10), [10-20), [20, 25)
- TestIterate(data, gfx::Rect(0, 0, 40, 25), 0, 0, 3, 2);
- TestIterate(data, gfx::Rect(15, 15, 8, 8), 1, 1, 2, 2);
+ TestIterateAll(data, gfx::Rect(origin.x(), origin.y(), 40, 25), 0, 0, 3, 2);
+ TestIterateAll(
+ data, gfx::Rect(origin.x() + 15, origin.y() + 15, 8, 8), 1, 1, 2, 2);
// Oversized.
- TestIterate(data, gfx::Rect(-100, -100, 1000, 1000), 0, 0, 3, 2);
- TestIterate(data, gfx::Rect(-100, 20, 1000, 1), 0, 2, 3, 2);
- TestIterate(data, gfx::Rect(29, -100, 31, 1000), 2, 0, 3, 2);
+ TestIterateAll(data,
+ gfx::Rect(origin.x() - 100, origin.y() - 100, 1000, 1000),
+ 0,
+ 0,
+ 3,
+ 2);
+ TestIterateAll(
+ data, gfx::Rect(origin.x() - 100, origin.y() + 20, 1000, 1), 0, 2, 3, 2);
+ TestIterateAll(
+ data, gfx::Rect(origin.x() + 29, origin.y() - 100, 31, 1000), 2, 0, 3, 2);
// Nonintersecting.
- TestIterate(data, gfx::Rect(60, 80, 100, 100), 0, 0, -1, -1);
+ TestIterateAll(data,
+ gfx::Rect(origin.x() + 60, origin.y() + 80, 100, 100),
+ 0,
+ 0,
+ -1,
+ -1);
}
-TEST(TilingDataTest, IteratorOneBorderTexel) {
- TilingData data(gfx::Size(10, 20), gfx::Size(25, 45), true);
+TEST_P(TilingDataTest, BordersIteratorOneBorderTexel) {
+ gfx::Point origin = GetParam();
+
+ TilingData data(
+ gfx::Size(10, 20), gfx::Rect(origin, gfx::Size(25, 45)), true);
+ // The following Coordinates are relative to the origin.
// X border index by src coord: [0-10), [8-18), [16-25)
// Y border index by src coord: [0-20), [18-38), [36-45)
- TestIterate(data, gfx::Rect(0, 0, 25, 45), 0, 0, 2, 2);
- TestIterate(data, gfx::Rect(18, 19, 3, 17), 2, 0, 2, 1);
- TestIterate(data, gfx::Rect(10, 20, 6, 16), 1, 1, 1, 1);
- TestIterate(data, gfx::Rect(9, 19, 8, 18), 0, 0, 2, 2);
+ TestIterateBorders(
+ data, gfx::Rect(origin.x(), origin.y(), 25, 45), 0, 0, 2, 2);
+ TestIterateBorders(
+ data, gfx::Rect(origin.x() + 18, origin.y() + 19, 3, 17), 2, 0, 2, 1);
+ TestIterateBorders(
+ data, gfx::Rect(origin.x() + 10, origin.y() + 20, 6, 16), 1, 1, 1, 1);
+ TestIterateBorders(
+ data, gfx::Rect(origin.x() + 9, origin.y() + 19, 8, 18), 0, 0, 2, 2);
+ // Oversized.
+ TestIterateBorders(data,
+ gfx::Rect(origin.x() - 100, origin.y() - 100, 1000, 1000),
+ 0,
+ 0,
+ 2,
+ 2);
+ TestIterateBorders(
+ data, gfx::Rect(origin.x() - 100, origin.y() + 20, 1000, 1), 0, 1, 2, 1);
+ TestIterateBorders(
+ data, gfx::Rect(origin.x() + 18, origin.y() - 100, 6, 1000), 2, 0, 2, 2);
+ // Nonintersecting.
+ TestIterateBorders(data,
+ gfx::Rect(origin.x() + 60, origin.y() + 80, 100, 100),
+ 0,
+ 0,
+ -1,
+ -1);
+}
+TEST_P(TilingDataTest, NoBordersIteratorOneBorderTexel) {
+ gfx::Point origin = GetParam();
+
+ TilingData data(
+ gfx::Size(10, 20), gfx::Rect(origin, gfx::Size(25, 45)), true);
+ // The following Coordinates are relative to the origin.
+ // X index by src coord: [0-9), [9-17), [17-25)
+ // Y index by src coord: [0-19), [19-37), [37-45)
+ TestIterateNoBorders(
+ data, gfx::Rect(origin.x(), origin.y(), 25, 45), 0, 0, 2, 2);
+ TestIterateNoBorders(
+ data, gfx::Rect(origin.x() + 17, origin.y() + 19, 3, 18), 2, 1, 2, 1);
+ TestIterateNoBorders(
+ data, gfx::Rect(origin.x() + 17, origin.y() + 19, 3, 19), 2, 1, 2, 2);
+ TestIterateNoBorders(
+ data, gfx::Rect(origin.x() + 8, origin.y() + 18, 9, 19), 0, 0, 1, 1);
+ TestIterateNoBorders(
+ data, gfx::Rect(origin.x() + 9, origin.y() + 19, 9, 19), 1, 1, 2, 2);
// Oversized.
- TestIterate(data, gfx::Rect(-100, -100, 1000, 1000), 0, 0, 2, 2);
- TestIterate(data, gfx::Rect(-100, 20, 1000, 1), 0, 1, 2, 1);
- TestIterate(data, gfx::Rect(18, -100, 6, 1000), 2, 0, 2, 2);
+ TestIterateNoBorders(
+ data,
+ gfx::Rect(origin.x() - 100, origin.y() - 100, 1000, 1000),
+ 0,
+ 0,
+ 2,
+ 2);
+ TestIterateNoBorders(
+ data, gfx::Rect(origin.x() - 100, origin.y() + 20, 1000, 1), 0, 1, 2, 1);
+ TestIterateNoBorders(
+ data, gfx::Rect(origin.x() + 18, origin.y() - 100, 6, 1000), 2, 0, 2, 2);
// Nonintersecting.
- TestIterate(data, gfx::Rect(60, 80, 100, 100), 0, 0, -1, -1);
+ TestIterateNoBorders(data,
+ gfx::Rect(origin.x() + 60, origin.y() + 80, 100, 100),
+ 0,
+ 0,
+ -1,
+ -1);
}
-TEST(TilingDataTest, IteratorManyBorderTexels) {
- TilingData data(gfx::Size(50, 60), gfx::Size(65, 110), 20);
+TEST_P(TilingDataTest, BordersIteratorManyBorderTexels) {
+ gfx::Point origin = GetParam();
+
+ TilingData data(gfx::Size(50, 60), gfx::Rect(origin, gfx::Size(65, 110)), 20);
+ // The following Coordinates are relative to the origin.
// X border index by src coord: [0-50), [10-60), [20-65)
// Y border index by src coord: [0-60), [20-80), [40-100), [60-110)
- TestIterate(data, gfx::Rect(0, 0, 65, 110), 0, 0, 2, 3);
- TestIterate(data, gfx::Rect(50, 60, 15, 65), 1, 1, 2, 3);
- TestIterate(data, gfx::Rect(60, 30, 2, 10), 2, 0, 2, 1);
+ TestIterateBorders(
+ data, gfx::Rect(origin.x(), origin.y(), 65, 110), 0, 0, 2, 3);
+ TestIterateBorders(
+ data, gfx::Rect(origin.x() + 50, origin.y() + 60, 15, 65), 1, 1, 2, 3);
+ TestIterateBorders(
+ data, gfx::Rect(origin.x() + 60, origin.y() + 30, 2, 10), 2, 0, 2, 1);
+ // Oversized.
+ TestIterateBorders(data,
+ gfx::Rect(origin.x() - 100, origin.y() - 100, 1000, 1000),
+ 0,
+ 0,
+ 2,
+ 3);
+ TestIterateBorders(
+ data, gfx::Rect(origin.x() - 100, origin.y() + 10, 1000, 10), 0, 0, 2, 0);
+ TestIterateBorders(
+ data, gfx::Rect(origin.x() + 10, origin.y() - 100, 10, 1000), 0, 0, 1, 3);
+ // Nonintersecting.
+ TestIterateBorders(data,
+ gfx::Rect(origin.x() + 65, origin.y() + 110, 100, 100),
+ 0,
+ 0,
+ -1,
+ -1);
+}
+TEST_P(TilingDataTest, NoBordersIteratorManyBorderTexels) {
+ gfx::Point origin = GetParam();
+
+ TilingData data(gfx::Size(50, 60), gfx::Rect(origin, gfx::Size(65, 110)), 20);
+ // The following Coordinates are relative to the origin.
+ // X index by src coord: [0-30), [30-40), [40, 65)
+ // Y index by src coord: [0-40), [40-60), [60, 80), [80-110)
+ TestIterateNoBorders(
+ data, gfx::Rect(origin.x(), origin.y(), 65, 110), 0, 0, 2, 3);
+ TestIterateNoBorders(
+ data, gfx::Rect(origin.x() + 30, origin.y() + 40, 15, 65), 1, 1, 2, 3);
+ TestIterateNoBorders(
+ data, gfx::Rect(origin.x() + 60, origin.y() + 20, 2, 21), 2, 0, 2, 1);
// Oversized.
- TestIterate(data, gfx::Rect(-100, -100, 1000, 1000), 0, 0, 2, 3);
- TestIterate(data, gfx::Rect(-100, 10, 1000, 10), 0, 0, 2, 0);
- TestIterate(data, gfx::Rect(10, -100, 10, 1000), 0, 0, 1, 3);
+ TestIterateNoBorders(
+ data,
+ gfx::Rect(origin.x() - 100, origin.y() - 100, 1000, 1000),
+ 0,
+ 0,
+ 2,
+ 3);
+ TestIterateNoBorders(
+ data, gfx::Rect(origin.x() - 100, origin.y() + 10, 1000, 10), 0, 0, 2, 0);
+ TestIterateNoBorders(
+ data, gfx::Rect(origin.x() + 10, origin.y() - 100, 10, 1000), 0, 0, 0, 3);
// Nonintersecting.
- TestIterate(data, gfx::Rect(65, 110, 100, 100), 0, 0, -1, -1);
+ TestIterateNoBorders(data,
+ gfx::Rect(origin.x() + 65, origin.y() + 110, 100, 100),
+ 0,
+ 0,
+ -1,
+ -1);
}
-TEST(TilingDataTest, IteratorOneTile) {
- TilingData no_border(gfx::Size(1000, 1000), gfx::Size(30, 40), false);
- TestIterate(no_border, gfx::Rect(0, 0, 30, 40), 0, 0, 0, 0);
- TestIterate(no_border, gfx::Rect(10, 10, 20, 20), 0, 0, 0, 0);
- TestIterate(no_border, gfx::Rect(30, 40, 100, 100), 0, 0, -1, -1);
-
- TilingData one_border(gfx::Size(1000, 1000), gfx::Size(30, 40), true);
- TestIterate(one_border, gfx::Rect(0, 0, 30, 40), 0, 0, 0, 0);
- TestIterate(one_border, gfx::Rect(10, 10, 20, 20), 0, 0, 0, 0);
- TestIterate(one_border, gfx::Rect(30, 40, 100, 100), 0, 0, -1, -1);
-
- TilingData big_border(gfx::Size(1000, 1000), gfx::Size(30, 40), 50);
- TestIterate(big_border, gfx::Rect(0, 0, 30, 40), 0, 0, 0, 0);
- TestIterate(big_border, gfx::Rect(10, 10, 20, 20), 0, 0, 0, 0);
- TestIterate(big_border, gfx::Rect(30, 40, 100, 100), 0, 0, -1, -1);
+TEST_P(TilingDataTest, IteratorOneTile) {
+ gfx::Point origin = GetParam();
+
+ TilingData no_border(
+ gfx::Size(1000, 1000), gfx::Rect(origin, gfx::Size(30, 40)), false);
+ TestIterateAll(
+ no_border, gfx::Rect(origin.x(), origin.y(), 30, 40), 0, 0, 0, 0);
+ TestIterateAll(no_border,
+ gfx::Rect(origin.x() + 10, origin.y() + 10, 20, 20),
+ 0,
+ 0,
+ 0,
+ 0);
+ TestIterateAll(no_border,
+ gfx::Rect(origin.x() + 30, origin.y() + 40, 100, 100),
+ 0,
+ 0,
+ -1,
+ -1);
+
+ TilingData one_border(
+ gfx::Size(1000, 1000), gfx::Rect(origin, gfx::Size(30, 40)), true);
+ TestIterateAll(
+ one_border, gfx::Rect(origin.x(), origin.y(), 30, 40), 0, 0, 0, 0);
+ TestIterateAll(one_border,
+ gfx::Rect(origin.x() + 10, origin.y() + 10, 20, 20),
+ 0,
+ 0,
+ 0,
+ 0);
+ TestIterateAll(one_border,
+ gfx::Rect(origin.x() + 30, origin.y() + 40, 100, 100),
+ 0,
+ 0,
+ -1,
+ -1);
+
+ TilingData big_border(
+ gfx::Size(1000, 1000), gfx::Rect(origin, gfx::Size(30, 40)), 50);
+ TestIterateAll(
+ big_border, gfx::Rect(origin.x(), origin.y(), 30, 40), 0, 0, 0, 0);
+ TestIterateAll(big_border,
+ gfx::Rect(origin.x() + 10, origin.y() + 10, 20, 20),
+ 0,
+ 0,
+ 0,
+ 0);
+ TestIterateAll(big_border,
+ gfx::Rect(origin.x() + 30, origin.y() + 40, 100, 100),
+ 0,
+ 0,
+ -1,
+ -1);
}
TEST(TilingDataTest, IteratorNoTiles) {
- TilingData data(gfx::Size(100, 100), gfx::Size(), false);
- TestIterate(data, gfx::Rect(0, 0, 100, 100), 0, 0, -1, -1);
+ TilingData data(gfx::Size(100, 100), gfx::Rect(), false);
+ TestIterateAll(data, gfx::Rect(0, 0, 100, 100), 0, 0, -1, -1);
}
void TestDiff(
@@ -1081,91 +2796,764 @@ void TestDiff(
EXPECT_EQ(0u, expected.size());
}
-TEST(TilingDataTest, DifferenceIteratorIgnoreGeometry) {
+TEST_P(TilingDataTest, DifferenceIteratorIgnoreGeometry) {
// This test is checking that the iterator can handle different geometries of
// ignore rects relative to the consider rect. The consider rect indices
// themselves are mostly tested by the non-difference iterator tests, so the
// full rect is mostly used here for simplicity.
+ gfx::Point origin = GetParam();
+
+ // The following Coordinates are relative to the origin.
// X border index by src coord: [0-10), [10-20), [20, 30), [30, 40)
// Y border index by src coord: [0-10), [10-20), [20, 25)
- TilingData data(gfx::Size(10, 10), gfx::Size(40, 25), false);
+ TilingData data(
+ gfx::Size(10, 10), gfx::Rect(origin, gfx::Size(40, 25)), false);
// Fully ignored
- TestDiff(data, gfx::Rect(0, 0, 40, 25), gfx::Rect(0, 0, 40, 25), 0);
- TestDiff(data, gfx::Rect(0, 0, 40, 25), gfx::Rect(-100, -100, 200, 200), 0);
- TestDiff(data, gfx::Rect(0, 0, 40, 25), gfx::Rect(9, 9, 30, 15), 0);
- TestDiff(data, gfx::Rect(15, 15, 8, 8), gfx::Rect(15, 15, 8, 8), 0);
+ TestDiff(data,
+ gfx::Rect(origin.x(), origin.y(), 40, 25),
+ gfx::Rect(origin.x(), origin.y(), 40, 25),
+ 0);
+ TestDiff(data,
+ gfx::Rect(origin.x(), origin.y(), 40, 25),
+ gfx::Rect(origin.x() - 100, origin.y() - 100, 200, 200),
+ 0);
+ TestDiff(data,
+ gfx::Rect(origin.x(), origin.y(), 40, 25),
+ gfx::Rect(origin.x() + 9, origin.y() + 9, 30, 15),
+ 0);
+ TestDiff(data,
+ gfx::Rect(origin.x() + 15, origin.y() + 15, 8, 8),
+ gfx::Rect(origin.x() + 15, origin.y() + 15, 8, 8),
+ 0);
// Fully un-ignored
- TestDiff(data, gfx::Rect(0, 0, 40, 25), gfx::Rect(-30, -20, 8, 8), 12);
- TestDiff(data, gfx::Rect(0, 0, 40, 25), gfx::Rect(), 12);
+ TestDiff(data,
+ gfx::Rect(origin.x(), origin.y(), 40, 25),
+ gfx::Rect(origin.x() - 30, origin.y() - 20, 8, 8),
+ 12);
+ TestDiff(data, gfx::Rect(origin.x(), origin.y(), 40, 25), gfx::Rect(), 12);
// Top left, remove 2x2 tiles
- TestDiff(data, gfx::Rect(0, 0, 40, 25), gfx::Rect(0, 0, 20, 19), 8);
+ TestDiff(data,
+ gfx::Rect(origin.x(), origin.y(), 40, 25),
+ gfx::Rect(origin.x(), origin.y(), 20, 19),
+ 8);
// Bottom right, remove 2x2 tiles
- TestDiff(data, gfx::Rect(0, 0, 40, 25), gfx::Rect(20, 15, 20, 6), 8);
+ TestDiff(data,
+ gfx::Rect(origin.x(), origin.y(), 40, 25),
+ gfx::Rect(origin.x() + 20, origin.y() + 15, 20, 6),
+ 8);
// Bottom left, remove 2x2 tiles
- TestDiff(data, gfx::Rect(0, 0, 40, 25), gfx::Rect(0, 15, 20, 6), 8);
+ TestDiff(data,
+ gfx::Rect(origin.x(), origin.y(), 40, 25),
+ gfx::Rect(origin.x(), origin.y() + 15, 20, 6),
+ 8);
// Top right, remove 2x2 tiles
- TestDiff(data, gfx::Rect(0, 0, 40, 25), gfx::Rect(20, 0, 20, 19), 8);
+ TestDiff(data,
+ gfx::Rect(origin.x(), origin.y(), 40, 25),
+ gfx::Rect(origin.x() + 20, origin.y(), 20, 19),
+ 8);
// Center, remove only one tile
- TestDiff(data, gfx::Rect(0, 0, 40, 25), gfx::Rect(10, 10, 5, 5), 11);
+ TestDiff(data,
+ gfx::Rect(origin.x(), origin.y(), 40, 25),
+ gfx::Rect(origin.x() + 10, origin.y() + 10, 5, 5),
+ 11);
// Left column, flush left, removing two columns
- TestDiff(data, gfx::Rect(0, 0, 40, 25), gfx::Rect(0, 0, 11, 25), 6);
+ TestDiff(data,
+ gfx::Rect(origin.x(), origin.y(), 40, 25),
+ gfx::Rect(origin.x(), origin.y(), 11, 25),
+ 6);
// Middle column, removing two columns
- TestDiff(data, gfx::Rect(0, 0, 40, 25), gfx::Rect(11, 0, 11, 25), 6);
+ TestDiff(data,
+ gfx::Rect(origin.x(), origin.y(), 40, 25),
+ gfx::Rect(origin.x() + 11, origin.y(), 11, 25),
+ 6);
// Right column, flush right, removing one column
- TestDiff(data, gfx::Rect(0, 0, 40, 25), gfx::Rect(30, 0, 2, 25), 9);
+ TestDiff(data,
+ gfx::Rect(origin.x(), origin.y(), 40, 25),
+ gfx::Rect(origin.x() + 30, origin.y(), 2, 25),
+ 9);
// Top row, flush top, removing one row
- TestDiff(data, gfx::Rect(0, 0, 40, 25), gfx::Rect(0, 5, 40, 5), 8);
+ TestDiff(data,
+ gfx::Rect(origin.x(), origin.y(), 40, 25),
+ gfx::Rect(origin.x(), origin.y() + 5, 40, 5),
+ 8);
// Middle row, removing one row
- TestDiff(data, gfx::Rect(0, 0, 40, 25), gfx::Rect(0, 13, 40, 5), 8);
+ TestDiff(data,
+ gfx::Rect(origin.x(), origin.y(), 40, 25),
+ gfx::Rect(origin.x(), origin.y() + 13, 40, 5),
+ 8);
// Bottom row, flush bottom, removing two rows
- TestDiff(data, gfx::Rect(0, 0, 40, 25), gfx::Rect(0, 13, 40, 12), 4);
+ TestDiff(data,
+ gfx::Rect(origin.x(), origin.y(), 40, 25),
+ gfx::Rect(origin.x(), origin.y() + 13, 40, 12),
+ 4);
// Non-intersecting, but still touching two of the same tiles.
- TestDiff(data, gfx::Rect(8, 0, 32, 25), gfx::Rect(0, 12, 5, 12), 10);
+ TestDiff(data,
+ gfx::Rect(origin.x() + 8, origin.y(), 32, 25),
+ gfx::Rect(origin.x(), origin.y() + 12, 5, 12),
+ 10);
// Intersecting, but neither contains the other. 2x3 with one overlap.
- TestDiff(data, gfx::Rect(5, 2, 20, 10), gfx::Rect(25, 15, 5, 10), 5);
+ TestDiff(data,
+ gfx::Rect(origin.x() + 5, origin.y() + 2, 20, 10),
+ gfx::Rect(origin.x() + 25, origin.y() + 15, 5, 10),
+ 5);
}
-TEST(TilingDataTest, DifferenceIteratorManyBorderTexels) {
+TEST_P(TilingDataTest, DifferenceIteratorManyBorderTexels) {
+ gfx::Point origin = GetParam();
+
+ // The following Coordinates are relative to the origin.
// X border index by src coord: [0-50), [10-60), [20-65)
// Y border index by src coord: [0-60), [20-80), [40-100), [60-110)
- TilingData data(gfx::Size(50, 60), gfx::Size(65, 110), 20);
+ TilingData data(gfx::Size(50, 60), gfx::Rect(origin, gfx::Size(65, 110)), 20);
// Ignore one column, three rows
- TestDiff(data, gfx::Rect(0, 30, 55, 80), gfx::Rect(5, 30, 5, 15), 9);
+ TestDiff(data,
+ gfx::Rect(origin.x(), origin.y() + 30, 55, 80),
+ gfx::Rect(origin.x() + 5, origin.y() + 30, 5, 15),
+ 9);
// Knock out three columns, leaving only one.
- TestDiff(data, gfx::Rect(10, 30, 55, 80), gfx::Rect(30, 59, 20, 1), 3);
+ TestDiff(data,
+ gfx::Rect(origin.x() + 10, origin.y() + 30, 55, 80),
+ gfx::Rect(origin.x() + 30, origin.y() + 59, 20, 1),
+ 3);
// Overlap all tiles with ignore rect.
- TestDiff(data, gfx::Rect(0, 0, 65, 110), gfx::Rect(30, 59, 1, 2), 0);
+ TestDiff(data,
+ gfx::Rect(origin.x(), origin.y(), 65, 110),
+ gfx::Rect(origin.x() + 30, origin.y() + 59, 1, 2),
+ 0);
}
-TEST(TilingDataTest, DifferenceIteratorOneTile) {
- TilingData no_border(gfx::Size(1000, 1000), gfx::Size(30, 40), false);
- TestDiff(no_border, gfx::Rect(0, 0, 30, 40), gfx::Rect(), 1);
- TestDiff(no_border, gfx::Rect(5, 5, 100, 100), gfx::Rect(5, 5, 1, 1), 0);
-
- TilingData one_border(gfx::Size(1000, 1000), gfx::Size(30, 40), true);
- TestDiff(one_border, gfx::Rect(0, 0, 30, 40), gfx::Rect(), 1);
- TestDiff(one_border, gfx::Rect(5, 5, 100, 100), gfx::Rect(5, 5, 1, 1), 0);
-
- TilingData big_border(gfx::Size(1000, 1000), gfx::Size(30, 40), 50);
- TestDiff(big_border, gfx::Rect(0, 0, 30, 40), gfx::Rect(), 1);
- TestDiff(big_border, gfx::Rect(5, 5, 100, 100), gfx::Rect(5, 5, 1, 1), 0);
+TEST_P(TilingDataTest, DifferenceIteratorOneTile) {
+ gfx::Point origin = GetParam();
+
+ TilingData no_border(
+ gfx::Size(1000, 1000), gfx::Rect(origin, gfx::Size(30, 40)), false);
+ TestDiff(
+ no_border, gfx::Rect(origin.x(), origin.y(), 30, 40), gfx::Rect(), 1);
+ TestDiff(no_border,
+ gfx::Rect(origin.x() + 5, origin.y() + 5, 100, 100),
+ gfx::Rect(origin.x() + 5, origin.y() + 5, 1, 1),
+ 0);
+
+ TilingData one_border(
+ gfx::Size(1000, 1000), gfx::Rect(origin, gfx::Size(30, 40)), true);
+ TestDiff(
+ one_border, gfx::Rect(origin.x(), origin.y(), 30, 40), gfx::Rect(), 1);
+ TestDiff(one_border,
+ gfx::Rect(origin.x() + 5, origin.y() + 5, 100, 100),
+ gfx::Rect(origin.x() + 5, origin.y() + 5, 1, 1),
+ 0);
+
+ TilingData big_border(
+ gfx::Size(1000, 1000), gfx::Rect(origin, gfx::Size(30, 40)), 50);
+ TestDiff(
+ big_border, gfx::Rect(origin.x(), origin.y(), 30, 40), gfx::Rect(), 1);
+ TestDiff(big_border,
+ gfx::Rect(origin.x() + 5, origin.y() + 5, 100, 100),
+ gfx::Rect(origin.x() + 5, origin.y() + 5, 1, 1),
+ 0);
}
TEST(TilingDataTest, DifferenceIteratorNoTiles) {
- TilingData data(gfx::Size(100, 100), gfx::Size(), false);
+ TilingData data(gfx::Size(100, 100), gfx::Rect(), false);
TestDiff(data, gfx::Rect(0, 0, 100, 100), gfx::Rect(0, 0, 5, 5), 0);
}
+void TestSpiralIterate(int source_line_number,
+ const TilingData& tiling_data,
+ const gfx::Rect& consider,
+ const gfx::Rect& ignore,
+ const gfx::Rect& center,
+ const std::vector<std::pair<int, int> >& expected) {
+ std::vector<std::pair<int, int> > actual;
+ for (TilingData::SpiralDifferenceIterator it(
+ &tiling_data, consider, ignore, center);
+ it;
+ ++it) {
+ actual.push_back(it.index());
+ }
+
+ EXPECT_EQ(expected.size(), actual.size()) << "error from line "
+ << source_line_number;
+ for (size_t i = 0; i < std::min(expected.size(), actual.size()); ++i) {
+ EXPECT_EQ(expected[i].first, actual[i].first)
+ << "i: " << i << " error from line: " << source_line_number;
+ EXPECT_EQ(expected[i].second, actual[i].second)
+ << "i: " << i << " error from line: " << source_line_number;
+ }
+}
+
+TEST_P(TilingDataTest, SpiralDifferenceIteratorNoIgnoreFullConsider) {
+ gfx::Point origin = GetParam();
+ TilingData tiling_data(
+ gfx::Size(10, 10), gfx::Rect(origin, gfx::Size(30, 30)), false);
+ gfx::Rect consider(origin.x(), origin.y(), 30, 30);
+ gfx::Rect ignore;
+ std::vector<std::pair<int, int> > expected;
+
+ // Center is in the center of the tiling.
+ gfx::Rect center(origin.x() + 15, origin.y() + 15, 1, 1);
+
+ // Layout of the tiling data, and expected return order:
+ // x 0 1 2
+ // y.------
+ // 0| 4 3 2
+ // 1| 5 * 1
+ // 2| 6 7 8
+ expected.push_back(std::make_pair(2, 1));
+ expected.push_back(std::make_pair(2, 0));
+ expected.push_back(std::make_pair(1, 0));
+ expected.push_back(std::make_pair(0, 0));
+ expected.push_back(std::make_pair(0, 1));
+ expected.push_back(std::make_pair(0, 2));
+ expected.push_back(std::make_pair(1, 2));
+ expected.push_back(std::make_pair(2, 2));
+
+ TestSpiralIterate(__LINE__, tiling_data, consider, ignore, center, expected);
+
+ // Center is off to the right side of the tiling (and far away).
+ center = gfx::Rect(origin.x() + 100, origin.y() + 15, 1, 1);
+
+ // Layout of the tiling data, and expected return order:
+ // x 0 1 2
+ // y.------
+ // 0| 7 4 1
+ // 1| 8 5 2 *
+ // 2| 9 6 3
+ expected.clear();
+ expected.push_back(std::make_pair(2, 0));
+ expected.push_back(std::make_pair(2, 1));
+ expected.push_back(std::make_pair(2, 2));
+ expected.push_back(std::make_pair(1, 0));
+ expected.push_back(std::make_pair(1, 1));
+ expected.push_back(std::make_pair(1, 2));
+ expected.push_back(std::make_pair(0, 0));
+ expected.push_back(std::make_pair(0, 1));
+ expected.push_back(std::make_pair(0, 2));
+
+ TestSpiralIterate(__LINE__, tiling_data, consider, ignore, center, expected);
+
+ // Center is the bottom right corner of the tiling.
+ center = gfx::Rect(origin.x() + 25, origin.y() + 25, 1, 1);
+
+ // Layout of the tiling data, and expected return order:
+ // x 0 1 2
+ // y.------
+ // 0| 6 5 4
+ // 1| 7 2 1
+ // 2| 8 3 *
+ expected.clear();
+ expected.push_back(std::make_pair(2, 1));
+ expected.push_back(std::make_pair(1, 1));
+ expected.push_back(std::make_pair(1, 2));
+ expected.push_back(std::make_pair(2, 0));
+ expected.push_back(std::make_pair(1, 0));
+ expected.push_back(std::make_pair(0, 0));
+ expected.push_back(std::make_pair(0, 1));
+ expected.push_back(std::make_pair(0, 2));
+
+ TestSpiralIterate(__LINE__, tiling_data, consider, ignore, center, expected);
+
+ // Center is off the top left side of the tiling.
+ center = gfx::Rect(origin.x() - 60, origin.y() - 50, 1, 1);
+
+ // Layout of the tiling data, and expected return order:
+ // * x 0 1 2
+ // y.------
+ // 0| 1 2 6
+ // 1| 3 4 5
+ // 2| 7 8 9
+ expected.clear();
+ expected.push_back(std::make_pair(0, 0));
+ expected.push_back(std::make_pair(1, 0));
+ expected.push_back(std::make_pair(0, 1));
+ expected.push_back(std::make_pair(1, 1));
+ expected.push_back(std::make_pair(2, 1));
+ expected.push_back(std::make_pair(2, 0));
+ expected.push_back(std::make_pair(0, 2));
+ expected.push_back(std::make_pair(1, 2));
+ expected.push_back(std::make_pair(2, 2));
+
+ TestSpiralIterate(__LINE__, tiling_data, consider, ignore, center, expected);
+
+ // Two tile center.
+ center = gfx::Rect(origin.x() + 15, origin.y() + 15, 1, 10);
+
+ // Layout of the tiling data, and expected return order:
+ // x 0 1 2
+ // y.------
+ // 0| 5 4 3
+ // 1| 6 * 2
+ // 2| 7 * 1
+ expected.clear();
+ expected.push_back(std::make_pair(2, 2));
+ expected.push_back(std::make_pair(2, 1));
+ expected.push_back(std::make_pair(2, 0));
+ expected.push_back(std::make_pair(1, 0));
+ expected.push_back(std::make_pair(0, 0));
+ expected.push_back(std::make_pair(0, 1));
+ expected.push_back(std::make_pair(0, 2));
+
+ TestSpiralIterate(__LINE__, tiling_data, consider, ignore, center, expected);
+}
+
+TEST_P(TilingDataTest, SpiralDifferenceIteratorSmallConsider) {
+ gfx::Point origin = GetParam();
+ TilingData tiling_data(
+ gfx::Size(10, 10), gfx::Rect(origin, gfx::Size(50, 50)), false);
+ gfx::Rect ignore;
+ std::vector<std::pair<int, int> > expected;
+ gfx::Rect center(origin.x() + 15, origin.y() + 15, 1, 1);
+
+ // Consider is one cell.
+ gfx::Rect consider(origin.x(), origin.y(), 1, 1);
+
+ // Layout of the tiling data, and expected return order:
+ // x 0 1 2 3 4
+ // y.----------
+ // 0| 1
+ // 1| *
+ // 2|
+ // 3|
+ // 4|
+ expected.push_back(std::make_pair(0, 0));
+
+ TestSpiralIterate(__LINE__, tiling_data, consider, ignore, center, expected);
+
+ // Consider is bottom right corner.
+ consider = gfx::Rect(origin.x() + 25, origin.y() + 25, 10, 10);
+
+ // Layout of the tiling data, and expected return order:
+ // x 0 1 2 3 4
+ // y.----------
+ // 0|
+ // 1| *
+ // 2| 1 2
+ // 3| 3 4
+ // 4|
+ expected.clear();
+ expected.push_back(std::make_pair(2, 2));
+ expected.push_back(std::make_pair(3, 2));
+ expected.push_back(std::make_pair(2, 3));
+ expected.push_back(std::make_pair(3, 3));
+
+ TestSpiralIterate(__LINE__, tiling_data, consider, ignore, center, expected);
+
+ // Consider is one column.
+ consider = gfx::Rect(origin.x() + 11, origin.y(), 1, 100);
+
+ // Layout of the tiling data, and expected return order:
+ // x 0 1 2 3 4
+ // y.----------
+ // 0| 2
+ // 1| *
+ // 2| 3
+ // 3| 4
+ // 4| 5
+ expected.clear();
+ expected.push_back(std::make_pair(1, 0));
+ expected.push_back(std::make_pair(1, 2));
+ expected.push_back(std::make_pair(1, 3));
+ expected.push_back(std::make_pair(1, 4));
+
+ TestSpiralIterate(__LINE__, tiling_data, consider, ignore, center, expected);
+}
+
+TEST_P(TilingDataTest, SpiralDifferenceIteratorHasIgnore) {
+ gfx::Point origin = GetParam();
+ TilingData tiling_data(
+ gfx::Size(10, 10), gfx::Rect(origin, gfx::Size(50, 50)), false);
+ gfx::Rect consider(origin.x(), origin.y(), 50, 50);
+ std::vector<std::pair<int, int> > expected;
+ gfx::Rect center(origin.x() + 15, origin.y() + 15, 1, 1);
+
+ // Full ignore.
+ gfx::Rect ignore(origin.x(), origin.y(), 50, 50);
+
+ // Layout of the tiling data, and expected return order:
+ // x 0 1 2 3 4
+ // y.----------
+ // 0| . . . . .
+ // 1| . * . . .
+ // 2| . . . . .
+ // 3| . . . . .
+ // 4| . . . . .
+ expected.clear();
+
+ TestSpiralIterate(__LINE__, tiling_data, consider, ignore, center, expected);
+
+ // 3 column ignore.
+ ignore = gfx::Rect(origin.x() + 15, origin.y(), 20, 100);
+
+ // Layout of the tiling data, and expected return order:
+ // x 0 1 2 3 4
+ // y.----------
+ // 0| 1 . . . 8
+ // 1| 2 * . . 7
+ // 2| 3 . . . 6
+ // 3| 4 . . . 5
+ // 4| 9 . . . 10
+ expected.clear();
+
+ expected.push_back(std::make_pair(0, 0));
+ expected.push_back(std::make_pair(0, 1));
+ expected.push_back(std::make_pair(0, 2));
+ expected.push_back(std::make_pair(0, 3));
+ expected.push_back(std::make_pair(4, 3));
+ expected.push_back(std::make_pair(4, 2));
+ expected.push_back(std::make_pair(4, 1));
+ expected.push_back(std::make_pair(4, 0));
+ expected.push_back(std::make_pair(0, 4));
+ expected.push_back(std::make_pair(4, 4));
+
+ TestSpiralIterate(__LINE__, tiling_data, consider, ignore, center, expected);
+
+ // Ignore covers the top half.
+ ignore = gfx::Rect(origin.x(), origin.y(), 50, 25);
+
+ // Layout of the tiling data, and expected return order:
+ // x 0 1 2 3 4
+ // y.----------
+ // 0| . . . . .
+ // 1| . * . . .
+ // 2| . . . . .
+ // 3| 1 2 3 4 5
+ // 4| 6 7 8 9 10
+ expected.clear();
+
+ expected.push_back(std::make_pair(0, 3));
+ expected.push_back(std::make_pair(1, 3));
+ expected.push_back(std::make_pair(2, 3));
+ expected.push_back(std::make_pair(3, 3));
+ expected.push_back(std::make_pair(4, 3));
+ expected.push_back(std::make_pair(0, 4));
+ expected.push_back(std::make_pair(1, 4));
+ expected.push_back(std::make_pair(2, 4));
+ expected.push_back(std::make_pair(3, 4));
+ expected.push_back(std::make_pair(4, 4));
+
+ TestSpiralIterate(__LINE__, tiling_data, consider, ignore, center, expected);
+}
+
+TEST_P(TilingDataTest, SpiralDifferenceIteratorRectangleCenter) {
+ gfx::Point origin = GetParam();
+ TilingData tiling_data(
+ gfx::Size(10, 10), gfx::Rect(origin, gfx::Size(50, 50)), false);
+ gfx::Rect consider(origin.x(), origin.y(), 50, 50);
+ std::vector<std::pair<int, int> > expected;
+ gfx::Rect ignore;
+
+ // Two cell center
+ gfx::Rect center(origin.x() + 25, origin.y() + 25, 1, 10);
+
+ // Layout of the tiling data, and expected return order:
+ // x 0 1 2 3 4
+ // y.----------
+ // 0| J I H G F
+ // 1| K 5 4 3 E
+ // 2| L 6 * 2 D
+ // 3| M 7 * 1 C
+ // 4| N 8 9 A B
+ expected.clear();
+
+ expected.push_back(std::make_pair(3, 3));
+ expected.push_back(std::make_pair(3, 2));
+ expected.push_back(std::make_pair(3, 1));
+ expected.push_back(std::make_pair(2, 1));
+ expected.push_back(std::make_pair(1, 1));
+ expected.push_back(std::make_pair(1, 2));
+ expected.push_back(std::make_pair(1, 3));
+ expected.push_back(std::make_pair(1, 4));
+ expected.push_back(std::make_pair(2, 4));
+ expected.push_back(std::make_pair(3, 4));
+ expected.push_back(std::make_pair(4, 4));
+ expected.push_back(std::make_pair(4, 3));
+ expected.push_back(std::make_pair(4, 2));
+ expected.push_back(std::make_pair(4, 1));
+ expected.push_back(std::make_pair(4, 0));
+ expected.push_back(std::make_pair(3, 0));
+ expected.push_back(std::make_pair(2, 0));
+ expected.push_back(std::make_pair(1, 0));
+ expected.push_back(std::make_pair(0, 0));
+ expected.push_back(std::make_pair(0, 1));
+ expected.push_back(std::make_pair(0, 2));
+ expected.push_back(std::make_pair(0, 3));
+ expected.push_back(std::make_pair(0, 4));
+
+ TestSpiralIterate(__LINE__, tiling_data, consider, ignore, center, expected);
+
+ // Three by two center.
+ center = gfx::Rect(origin.x() + 15, origin.y() + 25, 20, 10);
+
+ // Layout of the tiling data, and expected return order:
+ // x 0 1 2 3 4
+ // y.----------
+ // 0| J I H G F
+ // 1| 7 6 5 4 3
+ // 2| 8 * * * 2
+ // 3| 9 * * * 1
+ // 4| A B C D E
+ expected.clear();
+
+ expected.push_back(std::make_pair(4, 3));
+ expected.push_back(std::make_pair(4, 2));
+ expected.push_back(std::make_pair(4, 1));
+ expected.push_back(std::make_pair(3, 1));
+ expected.push_back(std::make_pair(2, 1));
+ expected.push_back(std::make_pair(1, 1));
+ expected.push_back(std::make_pair(0, 1));
+ expected.push_back(std::make_pair(0, 2));
+ expected.push_back(std::make_pair(0, 3));
+ expected.push_back(std::make_pair(0, 4));
+ expected.push_back(std::make_pair(1, 4));
+ expected.push_back(std::make_pair(2, 4));
+ expected.push_back(std::make_pair(3, 4));
+ expected.push_back(std::make_pair(4, 4));
+ expected.push_back(std::make_pair(4, 0));
+ expected.push_back(std::make_pair(3, 0));
+ expected.push_back(std::make_pair(2, 0));
+ expected.push_back(std::make_pair(1, 0));
+ expected.push_back(std::make_pair(0, 0));
+
+ TestSpiralIterate(__LINE__, tiling_data, consider, ignore, center, expected);
+
+ // Column center off the left side.
+ center = gfx::Rect(origin.x() - 50, origin.y(), 30, 50);
+
+ // Layout of the tiling data, and expected return order:
+ // x 0 1 2 3 4
+ // y.----------
+ // * 0| 5 A F K P
+ // * 1| 4 9 E J O
+ // * 2| 3 8 D I N
+ // * 3| 2 7 C H M
+ // * 4| 1 6 B G L
+ expected.clear();
+
+ expected.push_back(std::make_pair(0, 4));
+ expected.push_back(std::make_pair(0, 3));
+ expected.push_back(std::make_pair(0, 2));
+ expected.push_back(std::make_pair(0, 1));
+ expected.push_back(std::make_pair(0, 0));
+ expected.push_back(std::make_pair(1, 4));
+ expected.push_back(std::make_pair(1, 3));
+ expected.push_back(std::make_pair(1, 2));
+ expected.push_back(std::make_pair(1, 1));
+ expected.push_back(std::make_pair(1, 0));
+ expected.push_back(std::make_pair(2, 4));
+ expected.push_back(std::make_pair(2, 3));
+ expected.push_back(std::make_pair(2, 2));
+ expected.push_back(std::make_pair(2, 1));
+ expected.push_back(std::make_pair(2, 0));
+ expected.push_back(std::make_pair(3, 4));
+ expected.push_back(std::make_pair(3, 3));
+ expected.push_back(std::make_pair(3, 2));
+ expected.push_back(std::make_pair(3, 1));
+ expected.push_back(std::make_pair(3, 0));
+ expected.push_back(std::make_pair(4, 4));
+ expected.push_back(std::make_pair(4, 3));
+ expected.push_back(std::make_pair(4, 2));
+ expected.push_back(std::make_pair(4, 1));
+ expected.push_back(std::make_pair(4, 0));
+
+ TestSpiralIterate(__LINE__, tiling_data, consider, ignore, center, expected);
+}
+
+TEST_P(TilingDataTest, SpiralDifferenceIteratorEdgeCases) {
+ gfx::Point origin = GetParam();
+ TilingData tiling_data(
+ gfx::Size(10, 10), gfx::Rect(origin, gfx::Size(30, 30)), false);
+ std::vector<std::pair<int, int> > expected;
+ gfx::Rect center;
+ gfx::Rect consider;
+ gfx::Rect ignore;
+
+ // Ignore contains, but is not equal to, consider and center.
+ ignore = gfx::Rect(origin.x() + 15, origin.y(), 20, 30);
+ consider = gfx::Rect(origin.x() + 20, origin.y() + 10, 10, 20);
+ center = gfx::Rect(origin.x() + 25, origin.y(), 5, 5);
+
+ // Layout of the tiling data, and expected return order:
+ // x 0 1 2
+ // y.------
+ // 0| . *
+ // 1| . .
+ // 2| . .
+ expected.clear();
+
+ TestSpiralIterate(__LINE__, tiling_data, consider, ignore, center, expected);
+
+ // Center intersects with consider.
+ ignore = gfx::Rect();
+ center = gfx::Rect(origin.x(), origin.y() + 15, 30, 15);
+ consider = gfx::Rect(origin.x(), origin.y(), 15, 30);
+
+ // Layout of the tiling data, and expected return order:
+ // x 0 1 2
+ // y.------
+ // 0| 2 1
+ // 1| * * *
+ // 2| * * *
+ expected.clear();
+
+ expected.push_back(std::make_pair(1, 0));
+ expected.push_back(std::make_pair(0, 0));
+
+ TestSpiralIterate(__LINE__, tiling_data, consider, ignore, center, expected);
+
+ // Consider and ignore are non-intersecting.
+ ignore = gfx::Rect(origin.x(), origin.y(), 5, 30);
+ consider = gfx::Rect(origin.x() + 25, origin.y(), 5, 30);
+ center = gfx::Rect(origin.x() + 15, origin.y(), 1, 1);
+
+ // Layout of the tiling data, and expected return order:
+ // x 0 1 2
+ // y.------
+ // 0| . * 1
+ // 1| . 2
+ // 2| . 3
+ expected.clear();
+
+ expected.push_back(std::make_pair(2, 0));
+ expected.push_back(std::make_pair(2, 1));
+ expected.push_back(std::make_pair(2, 2));
+
+ TestSpiralIterate(__LINE__, tiling_data, consider, ignore, center, expected);
+
+ // Center intersects with ignore.
+ consider = gfx::Rect(origin.x(), origin.y(), 30, 30);
+ center = gfx::Rect(origin.x() + 15, origin.y(), 1, 30);
+ ignore = gfx::Rect(origin.x(), origin.y() + 15, 30, 1);
+
+ // Layout of the tiling data, and expected return order:
+ // x 0 1 2
+ // y.------
+ // 0| 3 * 2
+ // 1| . * .
+ // 2| 4 * 1
+ expected.clear();
+
+ expected.push_back(std::make_pair(2, 2));
+ expected.push_back(std::make_pair(2, 0));
+ expected.push_back(std::make_pair(0, 0));
+ expected.push_back(std::make_pair(0, 2));
+
+ TestSpiralIterate(__LINE__, tiling_data, consider, ignore, center, expected);
+
+ // Center and ignore are the same.
+ consider = gfx::Rect(origin.x(), origin.y(), 30, 30);
+ center = gfx::Rect(origin.x() + 15, origin.y(), 1, 30);
+ ignore = center;
+
+ // Layout of the tiling data, and expected return order:
+ // x 0 1 2
+ // y.------
+ // 0| 4 * 3
+ // 1| 5 * 2
+ // 2| 6 * 1
+ expected.clear();
+
+ expected.push_back(std::make_pair(2, 2));
+ expected.push_back(std::make_pair(2, 1));
+ expected.push_back(std::make_pair(2, 0));
+ expected.push_back(std::make_pair(0, 0));
+ expected.push_back(std::make_pair(0, 1));
+ expected.push_back(std::make_pair(0, 2));
+
+ TestSpiralIterate(__LINE__, tiling_data, consider, ignore, center, expected);
+
+ // Empty tiling data.
+ TilingData empty_data(gfx::Size(0, 0), gfx::Rect(0, 0, 0, 0), false);
+
+ expected.clear();
+ TestSpiralIterate(__LINE__, empty_data, consider, ignore, center, expected);
+
+ // Empty consider.
+ ignore = gfx::Rect();
+ center = gfx::Rect(1, 1, 1, 1);
+ consider = gfx::Rect();
+
+ expected.clear();
+ TestSpiralIterate(__LINE__, tiling_data, consider, ignore, center, expected);
+
+ // Empty center. Note: This arbitrarily puts the center to be off the top-left
+ // corner.
+ consider = gfx::Rect(origin.x(), origin.y(), 30, 30);
+ ignore = gfx::Rect();
+ center = gfx::Rect();
+
+ // Layout of the tiling data, and expected return order:
+ // * x 0 1 2
+ // y.------
+ // 0| 1 2 6
+ // 1| 3 4 5
+ // 2| 7 8 9
+ expected.clear();
+
+ expected.push_back(std::make_pair(0, 0));
+ expected.push_back(std::make_pair(1, 0));
+ expected.push_back(std::make_pair(0, 1));
+ expected.push_back(std::make_pair(1, 1));
+ expected.push_back(std::make_pair(2, 1));
+ expected.push_back(std::make_pair(2, 0));
+ expected.push_back(std::make_pair(0, 2));
+ expected.push_back(std::make_pair(1, 2));
+ expected.push_back(std::make_pair(2, 2));
+
+ TestSpiralIterate(__LINE__, tiling_data, consider, ignore, center, expected);
+
+ // Every rect is empty.
+ ignore = gfx::Rect();
+ center = gfx::Rect();
+ consider = gfx::Rect();
+
+ expected.clear();
+ TestSpiralIterate(__LINE__, tiling_data, consider, ignore, center, expected);
+
+ // Center is just to the left of cover, and off of the tiling's left side.
+ consider = gfx::Rect(origin.x(), origin.y(), 30, 30);
+ ignore = gfx::Rect();
+ center = gfx::Rect(origin.x() - 20, origin.y(), 19, 30);
+
+ // Layout of the tiling data, and expected return order:
+ // x 0 1 2
+ // y.------
+ // *0| 3 6 9
+ // *1| 2 5 8
+ // *2| 1 4 7
+ expected.clear();
+
+ expected.push_back(std::make_pair(0, 2));
+ expected.push_back(std::make_pair(0, 1));
+ expected.push_back(std::make_pair(0, 0));
+ expected.push_back(std::make_pair(1, 2));
+ expected.push_back(std::make_pair(1, 1));
+ expected.push_back(std::make_pair(1, 0));
+ expected.push_back(std::make_pair(2, 2));
+ expected.push_back(std::make_pair(2, 1));
+ expected.push_back(std::make_pair(2, 0));
+
+ TestSpiralIterate(__LINE__, tiling_data, consider, ignore, center, expected);
+}
+
+INSTANTIATE_TEST_CASE_P(TilingData,
+ TilingDataTest,
+ ::testing::Values(gfx::Point(42, 17),
+ gfx::Point(0, 0),
+ gfx::Point(-8, 15),
+ gfx::Point(-12, 4),
+ gfx::Point(-16, -35),
+ gfx::Point(-10000, -15000)));
} // namespace
+
} // namespace cc
diff --git a/chromium/cc/base/unique_notifier.cc b/chromium/cc/base/unique_notifier.cc
new file mode 100644
index 00000000000..0656c6d747b
--- /dev/null
+++ b/chromium/cc/base/unique_notifier.cc
@@ -0,0 +1,42 @@
+// 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/base/unique_notifier.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/location.h"
+#include "base/sequenced_task_runner.h"
+
+namespace cc {
+
+UniqueNotifier::UniqueNotifier(base::SequencedTaskRunner* task_runner,
+ const base::Closure& closure)
+ : task_runner_(task_runner),
+ closure_(closure),
+ notification_pending_(false),
+ weak_ptr_factory_(this) {
+}
+
+UniqueNotifier::~UniqueNotifier() {
+}
+
+void UniqueNotifier::Schedule() {
+ if (notification_pending_)
+ return;
+
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&UniqueNotifier::Notify, weak_ptr_factory_.GetWeakPtr()));
+ notification_pending_ = true;
+}
+
+void UniqueNotifier::Notify() {
+ // Note that the order here is important in case closure schedules another
+ // run.
+ notification_pending_ = false;
+ closure_.Run();
+}
+
+} // namespace cc
diff --git a/chromium/cc/base/unique_notifier.h b/chromium/cc/base/unique_notifier.h
new file mode 100644
index 00000000000..4752f6f6955
--- /dev/null
+++ b/chromium/cc/base/unique_notifier.h
@@ -0,0 +1,44 @@
+// 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_BASE_UNIQUE_NOTIFIER_H_
+#define CC_BASE_UNIQUE_NOTIFIER_H_
+
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "cc/base/cc_export.h"
+
+namespace base {
+class SequencedTaskRunner;
+} // namespace base
+
+namespace cc {
+
+class CC_EXPORT UniqueNotifier {
+ public:
+ // Configure this notifier to issue the |closure| notification when scheduled.
+ UniqueNotifier(base::SequencedTaskRunner* task_runner,
+ const base::Closure& closure);
+
+ // Destroying the notifier will ensure that no further notifications will
+ // happen from this class.
+ ~UniqueNotifier();
+
+ // Schedule a notification to be run. If another notification is already
+ // pending, then only one notification will take place.
+ void Schedule();
+
+ private:
+ void Notify();
+
+ base::SequencedTaskRunner* task_runner_;
+ base::Closure closure_;
+ bool notification_pending_;
+
+ base::WeakPtrFactory<UniqueNotifier> weak_ptr_factory_;
+};
+
+} // namespace cc
+
+#endif // CC_BASE_UNIQUE_NOTIFIER_H_
diff --git a/chromium/cc/base/unique_notifier_unittest.cc b/chromium/cc/base/unique_notifier_unittest.cc
new file mode 100644
index 00000000000..8c7b0d1887a
--- /dev/null
+++ b/chromium/cc/base/unique_notifier_unittest.cc
@@ -0,0 +1,62 @@
+// 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 "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "cc/base/unique_notifier.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+namespace {
+
+class UniqueNotifierTest : public testing::Test {
+ public:
+ UniqueNotifierTest() : notification_count_(0) {}
+
+ virtual void SetUp() OVERRIDE { ResetNotificationCount(); }
+
+ void Notify() { ++notification_count_; }
+
+ int NotificationCount() const { return notification_count_; }
+
+ void ResetNotificationCount() { notification_count_ = 0; }
+
+ protected:
+ int notification_count_;
+};
+
+TEST_F(UniqueNotifierTest, Schedule) {
+ {
+ UniqueNotifier notifier(
+ base::MessageLoopProxy::current(),
+ base::Bind(&UniqueNotifierTest::Notify, base::Unretained(this)));
+
+ EXPECT_EQ(0, NotificationCount());
+
+ // Basic schedule should result in a run.
+ notifier.Schedule();
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(1, NotificationCount());
+
+ // Multiple schedules should only result in one run.
+ for (int i = 0; i < 5; ++i)
+ notifier.Schedule();
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(2, NotificationCount());
+
+ notifier.Schedule();
+ }
+
+ // Notifier went out of scope, so we don't expect to get a notification.
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(2, NotificationCount());
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/cc.gyp b/chromium/cc/cc.gyp
index 7af063df2a6..d2d8338c60b 100644
--- a/chromium/cc/cc.gyp
+++ b/chromium/cc/cc.gyp
@@ -16,11 +16,17 @@
'<(DEPTH)/gpu/gpu.gyp:gpu',
'<(DEPTH)/media/media.gyp:media',
'<(DEPTH)/skia/skia.gyp:skia',
- '<(DEPTH)/third_party/WebKit/public/blink.gyp:blink_minimal',
'<(DEPTH)/ui/events/events.gyp:events_base',
'<(DEPTH)/ui/gfx/gfx.gyp:gfx',
+ '<(DEPTH)/ui/gfx/gfx.gyp:gfx_geometry',
'<(DEPTH)/ui/gl/gl.gyp:gl',
],
+ 'variables': {
+ 'optimize': 'max',
+ },
+ 'export_dependent_settings': [
+ '<(DEPTH)/skia/skia.gyp:skia',
+ ],
'defines': [
'CC_IMPLEMENTATION=1',
],
@@ -46,6 +52,7 @@
'animation/scroll_offset_animation_curve.cc',
'animation/scroll_offset_animation_curve.h',
'animation/scrollbar_animation_controller.h',
+ 'animation/scrollbar_animation_controller.cc',
'animation/scrollbar_animation_controller_linear_fade.cc',
'animation/scrollbar_animation_controller_linear_fade.h',
'animation/scrollbar_animation_controller_thinning.cc',
@@ -57,6 +64,8 @@
'animation/transform_operations.cc',
'animation/transform_operations.h',
'base/completion_event.h',
+ 'base/delayed_unique_notifier.cc',
+ 'base/delayed_unique_notifier.h',
'base/invalidation_region.cc',
'base/invalidation_region.h',
'base/latency_info_swap_promise.cc',
@@ -68,6 +77,8 @@
'base/ref_counted_managed.h',
'base/region.cc',
'base/region.h',
+ 'base/rolling_time_delta_history.cc',
+ 'base/rolling_time_delta_history.h',
'base/scoped_ptr_algorithm.h',
'base/scoped_ptr_deque.h',
'base/scoped_ptr_vector.h',
@@ -78,6 +89,8 @@
'base/switches.h',
'base/tiling_data.cc',
'base/tiling_data.h',
+ 'base/unique_notifier.cc',
+ 'base/unique_notifier.h',
'base/util.h',
'debug/benchmark_instrumentation.cc',
'debug/benchmark_instrumentation.h',
@@ -88,6 +101,11 @@
'debug/devtools_instrumentation.h',
'debug/frame_rate_counter.cc',
'debug/frame_rate_counter.h',
+ 'debug/frame_viewer_instrumentation.h',
+ 'debug/invalidation_benchmark.cc',
+ 'debug/invalidation_benchmark.h',
+ 'debug/lap_timer.cc',
+ 'debug/lap_timer.h',
'debug/layer_tree_debug_state.cc',
'debug/layer_tree_debug_state.h',
'debug/micro_benchmark.cc',
@@ -98,8 +116,6 @@
'debug/micro_benchmark_controller.h',
'debug/micro_benchmark_controller_impl.cc',
'debug/micro_benchmark_controller_impl.h',
- 'debug/overdraw_metrics.cc',
- 'debug/overdraw_metrics.h',
'debug/paint_time_counter.cc',
'debug/paint_time_counter.h',
'debug/picture_record_benchmark.cc',
@@ -128,7 +144,6 @@
'input/top_controls_manager.h',
'input/top_controls_manager_client.h',
'layers/append_quads_data.h',
- 'layers/compositing_reasons.h',
'layers/content_layer.cc',
'layers/content_layer.h',
'layers/content_layer_client.h',
@@ -158,12 +173,13 @@
'layers/layer_client.h',
'layers/layer_impl.cc',
'layers/layer_impl.h',
- 'layers/layer_iterator.cc',
'layers/layer_iterator.h',
'layers/layer_lists.cc',
'layers/layer_lists.h',
'layers/layer_position_constraint.cc',
'layers/layer_position_constraint.h',
+ 'layers/layer_utils.cc',
+ 'layers/layer_utils.h',
'layers/nine_patch_layer.cc',
'layers/nine_patch_layer.h',
'layers/nine_patch_layer_impl.cc',
@@ -182,6 +198,7 @@
'layers/picture_layer_impl.cc',
'layers/picture_layer_impl.h',
'layers/quad_sink.h',
+ 'layers/quad_sink.cc',
'layers/render_pass_sink.h',
'layers/render_surface.cc',
'layers/render_surface.h',
@@ -198,6 +215,10 @@
'layers/solid_color_scrollbar_layer.h',
'layers/solid_color_scrollbar_layer_impl.cc',
'layers/solid_color_scrollbar_layer_impl.h',
+ 'layers/surface_layer.cc',
+ 'layers/surface_layer.h',
+ 'layers/surface_layer_impl.cc',
+ 'layers/surface_layer_impl.h',
'layers/texture_layer.cc',
'layers/texture_layer.h',
'layers/texture_layer_client.h',
@@ -255,6 +276,13 @@
'output/output_surface.cc',
'output/output_surface.h',
'output/output_surface_client.h',
+ 'output/overlay_candidate.cc',
+ 'output/overlay_candidate.h',
+ 'output/overlay_candidate_validator.h',
+ 'output/overlay_processor.cc',
+ 'output/overlay_processor.h',
+ 'output/overlay_strategy_single_on_top.cc',
+ 'output/overlay_strategy_single_on_top.h',
'output/program_binding.cc',
'output/program_binding.h',
'output/render_surface_filters.cc',
@@ -291,6 +319,8 @@
'quads/solid_color_draw_quad.h',
'quads/stream_video_draw_quad.cc',
'quads/stream_video_draw_quad.h',
+ 'quads/surface_draw_quad.cc',
+ 'quads/surface_draw_quad.h',
'quads/texture_draw_quad.cc',
'quads/texture_draw_quad.h',
'quads/tile_draw_quad.cc',
@@ -301,16 +331,16 @@
'resources/bitmap_content_layer_updater.h',
'resources/bitmap_skpicture_content_layer_updater.cc',
'resources/bitmap_skpicture_content_layer_updater.h',
- 'resources/caching_bitmap_content_layer_updater.cc',
- 'resources/caching_bitmap_content_layer_updater.h',
'resources/content_layer_updater.cc',
'resources/content_layer_updater.h',
- 'resources/etc1_pixel_ref.cc',
- 'resources/etc1_pixel_ref.h',
+ 'resources/direct_raster_worker_pool.cc',
+ 'resources/direct_raster_worker_pool.h',
'resources/image_layer_updater.cc',
'resources/image_layer_updater.h',
'resources/image_raster_worker_pool.cc',
'resources/image_raster_worker_pool.h',
+ 'resources/image_copy_raster_worker_pool.cc',
+ 'resources/image_copy_raster_worker_pool.h',
'resources/layer_painter.h',
'resources/layer_quad.cc',
'resources/layer_quad.h',
@@ -349,6 +379,8 @@
'resources/raster_mode.h',
'resources/raster_worker_pool.cc',
'resources/raster_worker_pool.h',
+ 'resources/rasterizer.cc',
+ 'resources/rasterizer.h',
'resources/release_callback.h',
'resources/resource.cc',
'resources/resource.h',
@@ -376,10 +408,14 @@
'resources/single_release_callback.h',
'resources/skpicture_content_layer_updater.cc',
'resources/skpicture_content_layer_updater.h',
+ 'resources/task_graph_runner.cc',
+ 'resources/task_graph_runner.h',
'resources/texture_mailbox.cc',
'resources/texture_mailbox.h',
'resources/texture_mailbox_deleter.cc',
'resources/texture_mailbox_deleter.h',
+ 'resources/texture_uploader.cc',
+ 'resources/texture_uploader.h',
'resources/tile.cc',
'resources/tile.h',
'resources/tile_manager.cc',
@@ -395,23 +431,15 @@
'resources/ui_resource_request.h',
'resources/video_resource_updater.cc',
'resources/video_resource_updater.h',
- 'resources/worker_pool.cc',
- 'resources/worker_pool.h',
'scheduler/delay_based_time_source.cc',
'scheduler/delay_based_time_source.h',
- 'scheduler/frame_rate_controller.cc',
- 'scheduler/frame_rate_controller.h',
- 'scheduler/rolling_time_delta_history.cc',
- 'scheduler/rolling_time_delta_history.h',
+ 'scheduler/draw_result.h',
'scheduler/scheduler.cc',
'scheduler/scheduler.h',
'scheduler/scheduler_settings.cc',
'scheduler/scheduler_settings.h',
'scheduler/scheduler_state_machine.cc',
'scheduler/scheduler_state_machine.h',
- 'scheduler/texture_uploader.cc',
- 'scheduler/texture_uploader.h',
- 'scheduler/time_source.h',
'trees/blocking_task_runner.cc',
'trees/blocking_task_runner.h',
'trees/damage_tracker.cc',
@@ -433,8 +461,8 @@
'trees/occlusion_tracker.h',
'trees/proxy.cc',
'trees/proxy.h',
- 'trees/quad_culler.cc',
- 'trees/quad_culler.h',
+ 'trees/proxy_timing_history.cc',
+ 'trees/proxy_timing_history.h',
'trees/single_thread_proxy.cc',
'trees/single_thread_proxy.h',
'trees/thread_proxy.cc',
@@ -445,5 +473,34 @@
# TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
'msvs_disabled_warnings': [ 4267, ],
},
+ {
+ 'target_name': 'cc_surfaces',
+ 'type': '<(component)',
+ 'dependencies': [
+ 'cc',
+ '<(DEPTH)/base/base.gyp:base',
+ '<(DEPTH)/base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+ '<(DEPTH)/skia/skia.gyp:skia',
+ '<(DEPTH)/ui/gfx/gfx.gyp:gfx',
+ '<(DEPTH)/ui/gfx/gfx.gyp:gfx_geometry',
+ ],
+ 'defines': [
+ 'CC_SURFACES_IMPLEMENTATION=1',
+ ],
+ 'sources': [
+ 'surfaces/display.cc',
+ 'surfaces/display.h',
+ 'surfaces/display_client.h',
+ 'surfaces/surface.cc',
+ 'surfaces/surface.h',
+ 'surfaces/surface_id.h',
+ 'surfaces/surface_aggregator.cc',
+ 'surfaces/surface_aggregator.h',
+ 'surfaces/surface_client.h',
+ 'surfaces/surface_manager.cc',
+ 'surfaces/surface_manager.h',
+ 'surfaces/surfaces_export.h',
+ ],
+ },
],
}
diff --git a/chromium/cc/cc_tests.gyp b/chromium/cc/cc_tests.gyp
index 4974ad39e18..af160850bc1 100644
--- a/chromium/cc/cc_tests.gyp
+++ b/chromium/cc/cc_tests.gyp
@@ -12,13 +12,15 @@
'animation/scroll_offset_animation_curve_unittest.cc',
'animation/scrollbar_animation_controller_linear_fade_unittest.cc',
'animation/scrollbar_animation_controller_thinning_unittest.cc',
- 'animation/timing_function_unittest.cc',
'animation/transform_operations_unittest.cc',
+ 'base/delayed_unique_notifier_unittest.cc',
'base/float_quad_unittest.cc',
'base/math_util_unittest.cc',
'base/region_unittest.cc',
+ 'base/rolling_time_delta_history_unittest.cc',
'base/scoped_ptr_vector_unittest.cc',
'base/tiling_data_unittest.cc',
+ 'base/unique_notifier_unittest.cc',
'base/util_unittest.cc',
'debug/micro_benchmark_controller_unittest.cc',
'input/top_controls_manager_unittest.cc',
@@ -29,28 +31,39 @@
'layers/delegated_renderer_layer_impl_unittest.cc',
'layers/heads_up_display_unittest.cc',
'layers/heads_up_display_layer_impl_unittest.cc',
+ 'layers/io_surface_layer_impl_unittest.cc',
'layers/layer_impl_unittest.cc',
'layers/layer_iterator_unittest.cc',
'layers/layer_position_constraint_unittest.cc',
'layers/layer_unittest.cc',
+ 'layers/layer_utils_unittest.cc',
'layers/nine_patch_layer_impl_unittest.cc',
'layers/nine_patch_layer_unittest.cc',
+ 'layers/painted_scrollbar_layer_impl_unittest.cc',
'layers/picture_image_layer_impl_unittest.cc',
'layers/picture_layer_impl_unittest.cc',
'layers/picture_layer_unittest.cc',
'layers/render_surface_unittest.cc',
+ 'layers/render_surface_impl_unittest.cc',
'layers/scrollbar_layer_unittest.cc',
'layers/solid_color_layer_impl_unittest.cc',
+ 'layers/solid_color_scrollbar_layer_impl_unittest.cc',
+ 'layers/surface_layer_impl_unittest.cc',
'layers/texture_layer_unittest.cc',
+ 'layers/texture_layer_impl_unittest.cc',
'layers/tiled_layer_impl_unittest.cc',
'layers/tiled_layer_unittest.cc',
'layers/ui_resource_layer_impl_unittest.cc',
'layers/ui_resource_layer_unittest.cc',
+ 'layers/video_layer_impl_unittest.cc',
+ 'output/begin_frame_args_unittest.cc',
'output/delegating_renderer_unittest.cc',
'output/filter_operations_unittest.cc',
'output/gl_renderer_unittest.cc',
'output/output_surface_unittest.cc',
+ 'output/overlay_unittest.cc',
'output/renderer_pixeltest.cc',
+ 'output/renderer_unittest.cc',
'output/shader_unittest.cc',
'output/software_renderer_unittest.cc',
'quads/draw_quad_unittest.cc',
@@ -67,18 +80,17 @@
'resources/resource_provider_unittest.cc',
'resources/resource_update_controller_unittest.cc',
'resources/scoped_resource_unittest.cc',
+ 'resources/task_graph_runner_unittest.cc',
'resources/texture_mailbox_deleter_unittest.cc',
+ 'resources/texture_uploader_unittest.cc',
'resources/tile_manager_unittest.cc',
'resources/tile_priority_unittest.cc',
'resources/video_resource_updater_unittest.cc',
- 'resources/worker_pool_unittest.cc',
'scheduler/delay_based_time_source_unittest.cc',
- 'scheduler/frame_rate_controller_unittest.cc',
- 'scheduler/rolling_time_delta_history_unittest.cc',
'scheduler/scheduler_state_machine_unittest.cc',
'scheduler/scheduler_unittest.cc',
- 'scheduler/texture_uploader_unittest.cc',
'test/layer_tree_json_parser_unittest.cc',
+ 'test/ordered_simple_task_runner_unittest.cc',
'test/test_web_graphics_context_3d_unittest.cc',
'trees/damage_tracker_unittest.cc',
'trees/layer_sorter_unittest.cc',
@@ -96,16 +108,27 @@
'trees/layer_tree_host_unittest_damage.cc',
'trees/layer_tree_host_unittest_delegated.cc',
'trees/layer_tree_host_unittest_occlusion.cc',
+ 'trees/layer_tree_host_unittest_no_message_loop.cc',
'trees/layer_tree_host_unittest_picture.cc',
+ 'trees/layer_tree_host_unittest_proxy.cc',
'trees/layer_tree_host_unittest_scroll.cc',
'trees/layer_tree_host_unittest_video.cc',
+ 'trees/layer_tree_impl_unittest.cc',
'trees/occlusion_tracker_unittest.cc',
- 'trees/quad_culler_unittest.cc',
'trees/tree_synchronizer_unittest.cc',
],
+ 'cc_surfaces_unit_tests_source_files': [
+ 'surfaces/surface_aggregator_test_helpers.cc',
+ 'surfaces/surface_aggregator_test_helpers.h',
+ 'surfaces/surface_aggregator_unittest.cc',
+ 'surfaces/surface_unittest.cc',
+ 'surfaces/surfaces_pixeltest.cc',
+ ],
'cc_tests_support_files': [
'test/animation_test_common.cc',
'test/animation_test_common.h',
+ 'test/begin_frame_args_test.cc',
+ 'test/begin_frame_args_test.h',
'test/fake_content_layer.cc',
'test/fake_content_layer.h',
'test/fake_content_layer_client.cc',
@@ -141,6 +164,8 @@
'test/fake_picture_pile_impl.h',
'test/fake_proxy.cc',
'test/fake_proxy.h',
+ 'test/fake_renderer_client.cc',
+ 'test/fake_renderer_client.h',
'test/fake_rendering_stats_instrumentation.h',
'test/fake_scoped_ui_resource.cc',
'test/fake_scoped_ui_resource.h',
@@ -154,22 +179,26 @@
'test/fake_ui_resource_layer_tree_host_impl.h',
'test/fake_video_frame_provider.cc',
'test/fake_video_frame_provider.h',
- 'test/fake_web_graphics_context_3d.cc',
- 'test/fake_web_graphics_context_3d.h',
'test/geometry_test_utils.cc',
'test/geometry_test_utils.h',
+ 'test/test_in_process_context_provider.cc',
+ 'test/test_in_process_context_provider.h',
'test/impl_side_painting_settings.h',
'test/layer_test_common.cc',
'test/layer_test_common.h',
+ 'test/layer_tree_host_common_test.cc',
+ 'test/layer_tree_host_common_test.h',
'test/layer_tree_json_parser.cc',
'test/layer_tree_json_parser.h',
'test/layer_tree_pixel_test.cc',
'test/layer_tree_pixel_test.h',
'test/layer_tree_test.cc',
'test/layer_tree_test.h',
+ 'test/mock_occlusion_tracker.h',
'test/mock_quad_culler.cc',
'test/mock_quad_culler.h',
- 'test/occlusion_tracker_test_common.h',
+ 'test/ordered_simple_task_runner.cc',
+ 'test/ordered_simple_task_runner.h',
'test/ordered_texture_map.cc',
'test/ordered_texture_map.h',
'test/paths.cc',
@@ -200,6 +229,9 @@
'test/test_context_support.h',
'test/test_gles2_interface.cc',
'test/test_gles2_interface.h',
+ 'test/test_occlusion_tracker.h',
+ 'test/test_shared_bitmap_manager.cc',
+ 'test/test_shared_bitmap_manager.h',
'test/test_texture.cc',
'test/test_texture.h',
'test/test_tile_priorities.cc',
@@ -224,21 +256,23 @@
'../testing/gtest.gyp:gtest',
'../ui/events/events.gyp:events_base',
'../ui/gfx/gfx.gyp:gfx',
- '../webkit/common/gpu/webkit_gpu.gyp:webkit_gpu',
+ '../ui/gfx/gfx.gyp:gfx_geometry',
'cc.gyp:cc',
+ 'cc.gyp:cc_surfaces',
'cc_test_support',
],
'sources': [
'test/run_all_unittests.cc',
'test/cc_test_suite.cc',
'<@(cc_unit_tests_source_files)',
+ '<@(cc_surfaces_unit_tests_source_files)',
],
'include_dirs': [
'test',
'.',
],
'conditions': [
- ['OS == "android" and gtest_target_type == "shared_library"',
+ ['OS == "android"',
{
'dependencies': [
'../testing/android/native_test.gyp:native_test_native_code',
@@ -248,7 +282,7 @@
[ 'os_posix == 1 and OS != "mac" and OS != "android" and OS != "ios"',
{
'conditions': [
- [ 'linux_use_tcmalloc==1',
+ [ 'use_allocator!="none"',
{
'dependencies': [
'../base/allocator/allocator.gyp:allocator',
@@ -275,27 +309,30 @@
'../testing/gtest.gyp:gtest',
'../testing/perf/perf_test.gyp:*',
'../ui/gfx/gfx.gyp:gfx',
+ '../ui/gfx/gfx.gyp:gfx_geometry',
'cc.gyp:cc',
'cc_test_support',
],
'sources': [
'layers/layer_perftest.cc',
+ 'layers/picture_layer_impl_perftest.cc',
'resources/picture_layer_tiling_perftest.cc',
+ 'resources/picture_pile_impl_perftest.cc',
'resources/raster_worker_pool_perftest.cc',
+ 'resources/task_graph_runner_perftest.cc',
'resources/tile_manager_perftest.cc',
- 'resources/worker_pool_perftest.cc',
'test/cc_test_suite.cc',
- 'test/lap_timer.cc',
'test/run_all_perftests.cc',
'trees/layer_tree_host_common_perftest.cc',
'trees/layer_tree_host_perftest.cc',
+ 'trees/occlusion_tracker_perftest.cc',
],
'include_dirs': [
'test',
'.',
],
'conditions': [
- ['OS == "android" and gtest_target_type == "shared_library"',
+ ['OS == "android"',
{
'dependencies': [
'../testing/android/native_test.gyp:native_test_native_code',
@@ -303,7 +340,7 @@
}
],
# See http://crbug.com/162998#c4 for why this is needed.
- ['OS=="linux" and linux_use_tcmalloc==1',
+ ['OS=="linux" and use_allocator!="none"',
{
'dependencies': [
'../base/allocator/allocator.gyp:allocator',
@@ -325,15 +362,19 @@
'dependencies': [
'../base/base.gyp:base',
'../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+ '../gpu/gpu.gyp:gles2_c_lib',
+ '../gpu/gpu.gyp:gles2_implementation',
+ '../gpu/gpu.gyp:gl_in_process_context',
'../gpu/gpu.gyp:gpu_unittest_utils',
+ '../gpu/skia_bindings/skia_bindings.gyp:gpu_skia_bindings',
'../skia/skia.gyp:skia',
'../testing/gmock.gyp:gmock',
'../testing/gtest.gyp:gtest',
- '../third_party/WebKit/public/blink.gyp:blink_minimal',
'../third_party/mesa/mesa.gyp:osmesa',
'../ui/gfx/gfx.gyp:gfx',
+ '../ui/gfx/gfx.gyp:gfx_geometry',
+ '../ui/gfx/gfx.gyp:gfx_test_support',
'../ui/gl/gl.gyp:gl',
- '../ui/ui_unittests.gyp:ui_test_support',
],
'sources': [
'<@(cc_tests_support_files)',
@@ -343,9 +384,7 @@
},
],
'conditions': [
- # Special target to wrap a gtest_target_type==shared_library
- # cc_unittests into an android apk for execution.
- ['OS == "android" and gtest_target_type == "shared_library"',
+ ['OS == "android"',
{
'targets': [
{
@@ -356,7 +395,6 @@
],
'variables': {
'test_suite_name': 'cc_unittests',
- 'input_shlib_path': '<(SHARED_LIB_DIR)/<(SHARED_LIB_PREFIX)cc_unittests<(SHARED_LIB_SUFFIX)',
},
'includes': [ '../build/apk_test.gypi' ],
},
@@ -368,7 +406,6 @@
],
'variables': {
'test_suite_name': 'cc_perftests',
- 'input_shlib_path': '<(SHARED_LIB_DIR)/<(SHARED_LIB_PREFIX)cc_perftests<(SHARED_LIB_SUFFIX)',
},
'includes': [ '../build/apk_test.gypi' ],
},
diff --git a/chromium/cc/debug/debug_colors.cc b/chromium/cc/debug/debug_colors.cc
index 9fee7551b3d..6cbbfe9431d 100644
--- a/chromium/cc/debug/debug_colors.cc
+++ b/chromium/cc/debug/debug_colors.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 "base/macros.h"
+
#include "cc/debug/debug_colors.h"
#include "cc/trees/layer_tree_impl.h"
@@ -54,6 +56,14 @@ int DebugColors::ContainerLayerBorderWidth(const LayerTreeImpl* tree_impl) {
return Scale(2, tree_impl);
}
+// Surface layers are a blue-ish green.
+SkColor DebugColors::SurfaceLayerBorderColor() {
+ return SkColorSetARGB(128, 0, 255, 136);
+}
+int DebugColors::SurfaceLayerBorderWidth(const LayerTreeImpl* tree_impl) {
+ return Scale(2, tree_impl);
+}
+
// Render surfaces are blue.
SkColor DebugColors::SurfaceBorderColor() {
return SkColorSetARGB(100, 0, 0, 255);
@@ -112,14 +122,6 @@ int DebugColors::MissingTileBorderWidth(const LayerTreeImpl* tree_impl) {
return Scale(1, tree_impl);
}
-// Culled tile borders are brown.
-SkColor DebugColors::CulledTileBorderColor() {
- return SkColorSetARGB(120, 160, 100, 0);
-}
-int DebugColors::CulledTileBorderWidth(const LayerTreeImpl* tree_impl) {
- return Scale(1, tree_impl);
-}
-
// Solid color tile borders are grey.
SkColor DebugColors::SolidColorTileBorderColor() {
return SkColorSetARGB(128, 128, 128, 128);
@@ -163,13 +165,19 @@ SkColor DebugColors::EvictedTileCheckerboardColor() {
// ======= Debug rect colors =======
-// Paint rects in red.
-SkColor DebugColors::PaintRectBorderColor() {
- return SkColorSetARGB(255, 255, 0, 0);
+static SkColor FadedGreen(int initial_value, int step) {
+ DCHECK_GE(step, 0);
+ DCHECK_LE(step, DebugColors::kFadeSteps);
+ int value = step * initial_value / DebugColors::kFadeSteps;
+ return SkColorSetARGB(value, 0, 195, 0);
+}
+// Paint rects in green.
+SkColor DebugColors::PaintRectBorderColor(int step) {
+ return FadedGreen(255, step);
}
int DebugColors::PaintRectBorderWidth() { return 2; }
-SkColor DebugColors::PaintRectFillColor() {
- return SkColorSetARGB(30, 255, 0, 0);
+SkColor DebugColors::PaintRectFillColor(int step) {
+ return FadedGreen(60, step);
}
// Property-changed rects in blue.
@@ -244,6 +252,15 @@ SkColor DebugColors::WheelEventHandlerRectFillColor() {
return SkColorSetARGB(30, 189, 209, 57);
}
+// Scroll-event-handler rects in teal.
+SkColor DebugColors::ScrollEventHandlerRectBorderColor() {
+ return SkColorSetARGB(255, 24, 167, 181);
+}
+int DebugColors::ScrollEventHandlerRectBorderWidth() { return 2; }
+SkColor DebugColors::ScrollEventHandlerRectFillColor() {
+ return SkColorSetARGB(30, 24, 167, 181);
+}
+
// Non-fast-scrollable rects in orange.
SkColor DebugColors::NonFastScrollableRectBorderColor() {
return SkColorSetARGB(255, 238, 163, 59);
@@ -268,6 +285,11 @@ SkColor DebugColors::NonPaintedFillColor() { return SK_ColorCYAN; }
// Missing picture rects in magenta.
SkColor DebugColors::MissingPictureFillColor() { return SK_ColorMAGENTA; }
+// Missing resize invalidations are in salmon pink.
+SkColor DebugColors::MissingResizeInvalidations() {
+ return SkColorSetARGB(255, 255, 155, 170);
+}
+
// Picture borders in transparent blue.
SkColor DebugColors::PictureBorderColor() {
return SkColorSetARGB(100, 0, 0, 200);
diff --git a/chromium/cc/debug/debug_colors.h b/chromium/cc/debug/debug_colors.h
index 9edfb377bad..3b00d841bb2 100644
--- a/chromium/cc/debug/debug_colors.h
+++ b/chromium/cc/debug/debug_colors.h
@@ -29,6 +29,9 @@ class DebugColors {
static SkColor ContainerLayerBorderColor();
static int ContainerLayerBorderWidth(const LayerTreeImpl* tree_impl);
+ static SkColor SurfaceLayerBorderColor();
+ static int SurfaceLayerBorderWidth(const LayerTreeImpl* tree_impl);
+
static SkColor SurfaceBorderColor();
static int SurfaceBorderWidth(const LayerTreeImpl* tree_impl);
@@ -50,9 +53,6 @@ class DebugColors {
static SkColor MissingTileBorderColor();
static int MissingTileBorderWidth(const LayerTreeImpl* tree_impl);
- static SkColor CulledTileBorderColor();
- static int CulledTileBorderWidth(const LayerTreeImpl* tree_impl);
-
static SkColor SolidColorTileBorderColor();
static int SolidColorTileBorderWidth(const LayerTreeImpl* tree_impl);
@@ -66,9 +66,10 @@ class DebugColors {
static SkColor EvictedTileCheckerboardColor();
static SkColor InvalidatedTileCheckerboardColor();
- static SkColor PaintRectBorderColor();
+ static const int kFadeSteps = 50;
+ static SkColor PaintRectBorderColor(int step);
static int PaintRectBorderWidth();
- static SkColor PaintRectFillColor();
+ static SkColor PaintRectFillColor(int step);
static SkColor PropertyChangedRectBorderColor();
static int PropertyChangedRectBorderWidth();
@@ -102,6 +103,10 @@ class DebugColors {
static int WheelEventHandlerRectBorderWidth();
static SkColor WheelEventHandlerRectFillColor();
+ static SkColor ScrollEventHandlerRectBorderColor();
+ static int ScrollEventHandlerRectBorderWidth();
+ static SkColor ScrollEventHandlerRectFillColor();
+
static SkColor NonFastScrollableRectBorderColor();
static int NonFastScrollableRectBorderWidth();
static SkColor NonFastScrollableRectFillColor();
@@ -112,6 +117,7 @@ class DebugColors {
static SkColor NonPaintedFillColor();
static SkColor MissingPictureFillColor();
+ static SkColor MissingResizeInvalidations();
static SkColor PictureBorderColor();
static SkColor HUDBackgroundColor();
diff --git a/chromium/cc/debug/debug_rect_history.cc b/chromium/cc/debug/debug_rect_history.cc
index 679beafdbb4..e8792e7789e 100644
--- a/chromium/cc/debug/debug_rect_history.cc
+++ b/chromium/cc/debug/debug_rect_history.cc
@@ -6,10 +6,13 @@
#include "cc/base/math_util.h"
#include "cc/layers/layer_impl.h"
+#include "cc/layers/layer_iterator.h"
+#include "cc/layers/layer_utils.h"
#include "cc/layers/render_surface_impl.h"
#include "cc/trees/damage_tracker.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/layer_tree_host_common.h"
+#include "ui/gfx/geometry/rect_conversions.h"
namespace cc {
@@ -24,6 +27,7 @@ DebugRectHistory::~DebugRectHistory() {}
void DebugRectHistory::SaveDebugRectsForCurrentFrame(
LayerImpl* root_layer,
+ LayerImpl* hud_layer,
const LayerImplList& render_surface_layer_list,
const std::vector<gfx::Rect>& occluding_screen_space_rects,
const std::vector<gfx::Rect>& non_occluding_screen_space_rects,
@@ -38,6 +42,9 @@ void DebugRectHistory::SaveDebugRectsForCurrentFrame(
if (debug_state.show_wheel_event_handler_rects)
SaveWheelEventHandlerRects(root_layer);
+ if (debug_state.show_scroll_event_handler_rects)
+ SaveScrollEventHandlerRects(root_layer);
+
if (debug_state.show_non_fast_scrollable_rects)
SaveNonFastScrollableRects(root_layer);
@@ -45,7 +52,7 @@ void DebugRectHistory::SaveDebugRectsForCurrentFrame(
SavePaintRects(root_layer);
if (debug_state.show_property_changed_rects)
- SavePropertyChangedRects(render_surface_layer_list);
+ SavePropertyChangedRects(render_surface_layer_list, hud_layer);
if (debug_state.show_surface_damage_rects)
SaveSurfaceDamageRects(render_surface_layer_list);
@@ -74,12 +81,12 @@ void DebugRectHistory::SavePaintRects(LayerImpl* layer) {
static_cast<float>(layer->bounds().width());
float height_scale = layer->content_bounds().height() /
static_cast<float>(layer->bounds().height());
- gfx::RectF update_content_rect =
- gfx::ScaleRect(layer->update_rect(), width_scale, height_scale);
+ gfx::Rect update_content_rect = gfx::ScaleToEnclosingRect(
+ gfx::ToEnclosingRect(layer->update_rect()), width_scale, height_scale);
debug_rects_.push_back(
DebugRect(PAINT_RECT_TYPE,
- MathUtil::MapClippedRect(layer->screen_space_transform(),
- update_content_rect)));
+ MathUtil::MapEnclosingClippedRect(
+ layer->screen_space_transform(), update_content_rect)));
}
for (unsigned i = 0; i < layer->children().size(); ++i)
@@ -87,7 +94,8 @@ void DebugRectHistory::SavePaintRects(LayerImpl* layer) {
}
void DebugRectHistory::SavePropertyChangedRects(
- const LayerImplList& render_surface_layer_list) {
+ const LayerImplList& render_surface_layer_list,
+ LayerImpl* hud_layer) {
for (int surface_index = render_surface_layer_list.size() - 1;
surface_index >= 0;
--surface_index) {
@@ -105,16 +113,17 @@ void DebugRectHistory::SavePropertyChangedRects(
layer, render_surface_layer->id()))
continue;
- if (layer->LayerIsAlwaysDamaged())
+ if (layer == hud_layer)
continue;
- if (layer->LayerPropertyChanged()) {
- debug_rects_.push_back(
- DebugRect(PROPERTY_CHANGED_RECT_TYPE,
- MathUtil::MapClippedRect(
- layer->screen_space_transform(),
- gfx::RectF(gfx::PointF(), layer->content_bounds()))));
- }
+ if (!layer->LayerPropertyChanged())
+ continue;
+
+ debug_rects_.push_back(
+ DebugRect(PROPERTY_CHANGED_RECT_TYPE,
+ MathUtil::MapEnclosingClippedRect(
+ layer->screen_space_transform(),
+ gfx::Rect(layer->content_bounds()))));
}
}
}
@@ -130,7 +139,7 @@ void DebugRectHistory::SaveSurfaceDamageRects(
debug_rects_.push_back(DebugRect(
SURFACE_DAMAGE_RECT_TYPE,
- MathUtil::MapClippedRect(
+ MathUtil::MapEnclosingClippedRect(
render_surface->screen_space_transform(),
render_surface->damage_tracker()->current_damage_rect())));
}
@@ -145,15 +154,16 @@ void DebugRectHistory::SaveScreenSpaceRects(
RenderSurfaceImpl* render_surface = render_surface_layer->render_surface();
DCHECK(render_surface);
- debug_rects_.push_back(DebugRect(
- SCREEN_SPACE_RECT_TYPE,
- MathUtil::MapClippedRect(render_surface->screen_space_transform(),
- render_surface->content_rect())));
+ debug_rects_.push_back(
+ DebugRect(SCREEN_SPACE_RECT_TYPE,
+ MathUtil::MapEnclosingClippedRect(
+ render_surface->screen_space_transform(),
+ render_surface->content_rect())));
if (render_surface_layer->replica_layer()) {
debug_rects_.push_back(
DebugRect(REPLICA_SCREEN_SPACE_RECT_TYPE,
- MathUtil::MapClippedRect(
+ MathUtil::MapEnclosingClippedRect(
render_surface->replica_screen_space_transform(),
render_surface->content_rect())));
}
@@ -185,13 +195,12 @@ void DebugRectHistory::SaveTouchEventHandlerRectsCallback(LayerImpl* layer) {
for (Region::Iterator iter(layer->touch_event_handler_region());
iter.has_rect();
iter.next()) {
- gfx::RectF touch_rect = gfx::ScaleRect(iter.rect(),
- layer->contents_scale_x(),
- layer->contents_scale_y());
- debug_rects_.push_back(DebugRect(TOUCH_EVENT_HANDLER_RECT_TYPE,
- MathUtil::MapClippedRect(
- layer->screen_space_transform(),
- touch_rect)));
+ gfx::Rect touch_rect = gfx::ScaleToEnclosingRect(
+ iter.rect(), layer->contents_scale_x(), layer->contents_scale_y());
+ debug_rects_.push_back(
+ DebugRect(TOUCH_EVENT_HANDLER_RECT_TYPE,
+ MathUtil::MapEnclosingClippedRect(
+ layer->screen_space_transform(), touch_rect)));
}
}
@@ -206,12 +215,35 @@ void DebugRectHistory::SaveWheelEventHandlerRectsCallback(LayerImpl* layer) {
if (!layer->have_wheel_event_handlers())
return;
- gfx::RectF wheel_rect = gfx::RectF(layer->content_bounds());
- wheel_rect.Scale(layer->contents_scale_x(), layer->contents_scale_y());
- debug_rects_.push_back(DebugRect(WHEEL_EVENT_HANDLER_RECT_TYPE,
- MathUtil::MapClippedRect(
- layer->screen_space_transform(),
- wheel_rect)));
+ gfx::Rect wheel_rect =
+ gfx::ScaleToEnclosingRect(gfx::Rect(layer->content_bounds()),
+ layer->contents_scale_x(),
+ layer->contents_scale_y());
+ debug_rects_.push_back(
+ DebugRect(WHEEL_EVENT_HANDLER_RECT_TYPE,
+ MathUtil::MapEnclosingClippedRect(
+ layer->screen_space_transform(), wheel_rect)));
+}
+
+void DebugRectHistory::SaveScrollEventHandlerRects(LayerImpl* layer) {
+ LayerTreeHostCommon::CallFunctionForSubtree<LayerImpl>(
+ layer,
+ base::Bind(&DebugRectHistory::SaveScrollEventHandlerRectsCallback,
+ base::Unretained(this)));
+}
+
+void DebugRectHistory::SaveScrollEventHandlerRectsCallback(LayerImpl* layer) {
+ if (!layer->have_scroll_event_handlers())
+ return;
+
+ gfx::Rect scroll_rect =
+ gfx::ScaleToEnclosingRect(gfx::Rect(layer->content_bounds()),
+ layer->contents_scale_x(),
+ layer->contents_scale_y());
+ debug_rects_.push_back(
+ DebugRect(SCROLL_EVENT_HANDLER_RECT_TYPE,
+ MathUtil::MapEnclosingClippedRect(
+ layer->screen_space_transform(), scroll_rect)));
}
void DebugRectHistory::SaveNonFastScrollableRects(LayerImpl* layer) {
@@ -225,37 +257,37 @@ void DebugRectHistory::SaveNonFastScrollableRectsCallback(LayerImpl* layer) {
for (Region::Iterator iter(layer->non_fast_scrollable_region());
iter.has_rect();
iter.next()) {
- gfx::RectF scroll_rect = gfx::ScaleRect(iter.rect(),
- layer->contents_scale_x(),
- layer->contents_scale_y());
- debug_rects_.push_back(DebugRect(NON_FAST_SCROLLABLE_RECT_TYPE,
- MathUtil::MapClippedRect(
- layer->screen_space_transform(),
- scroll_rect)));
+ gfx::Rect scroll_rect = gfx::ScaleToEnclosingRect(
+ iter.rect(), layer->contents_scale_x(), layer->contents_scale_y());
+ debug_rects_.push_back(
+ DebugRect(NON_FAST_SCROLLABLE_RECT_TYPE,
+ MathUtil::MapEnclosingClippedRect(
+ layer->screen_space_transform(), scroll_rect)));
}
}
void DebugRectHistory::SaveLayerAnimationBoundsRects(
const LayerImplList& render_surface_layer_list) {
- typedef LayerIterator<LayerImpl,
- LayerImplList,
- RenderSurfaceImpl,
- LayerIteratorActions::FrontToBack> LayerIteratorType;
+ typedef LayerIterator<LayerImpl> LayerIteratorType;
LayerIteratorType end = LayerIteratorType::End(&render_surface_layer_list);
for (LayerIteratorType it =
LayerIteratorType::Begin(&render_surface_layer_list);
it != end; ++it) {
if (!it.represents_itself())
continue;
+
+ // TODO(avallee): Figure out if we should show something for a layer who's
+ // animating bounds but that we can't compute them.
gfx::BoxF inflated_bounds;
- if (!(*it)->GetAnimationBounds(&inflated_bounds))
+ if (!LayerUtils::GetAnimationBounds(**it, &inflated_bounds))
continue;
- debug_rects_.push_back(DebugRect(ANIMATION_BOUNDS_RECT_TYPE,
- gfx::RectF(inflated_bounds.x(),
- inflated_bounds.y(),
- inflated_bounds.width(),
- inflated_bounds.height())));
+ debug_rects_.push_back(
+ DebugRect(ANIMATION_BOUNDS_RECT_TYPE,
+ gfx::ToEnclosingRect(gfx::RectF(inflated_bounds.x(),
+ inflated_bounds.y(),
+ inflated_bounds.width(),
+ inflated_bounds.height()))));
}
}
diff --git a/chromium/cc/debug/debug_rect_history.h b/chromium/cc/debug/debug_rect_history.h
index 0dae431bd5f..278b20865a8 100644
--- a/chromium/cc/debug/debug_rect_history.h
+++ b/chromium/cc/debug/debug_rect_history.h
@@ -10,7 +10,6 @@
#include "base/memory/scoped_ptr.h"
#include "cc/layers/layer_lists.h"
#include "ui/gfx/rect.h"
-#include "ui/gfx/rect_f.h"
namespace cc {
@@ -52,16 +51,17 @@ enum DebugRectType {
NONOCCLUDING_RECT_TYPE,
TOUCH_EVENT_HANDLER_RECT_TYPE,
WHEEL_EVENT_HANDLER_RECT_TYPE,
+ SCROLL_EVENT_HANDLER_RECT_TYPE,
NON_FAST_SCROLLABLE_RECT_TYPE,
ANIMATION_BOUNDS_RECT_TYPE,
};
struct DebugRect {
- DebugRect(DebugRectType new_type, gfx::RectF new_rect)
+ DebugRect(DebugRectType new_type, const gfx::Rect& new_rect)
: type(new_type), rect(new_rect) {}
DebugRectType type;
- gfx::RectF rect;
+ gfx::Rect rect;
};
// This class maintains a history of rects of various types that can be used
@@ -77,6 +77,7 @@ class DebugRectHistory {
// reset.
void SaveDebugRectsForCurrentFrame(
LayerImpl* root_layer,
+ LayerImpl* hud_layer,
const LayerImplList& render_surface_layer_list,
const std::vector<gfx::Rect>& occluding_screen_space_rects,
const std::vector<gfx::Rect>& non_occluding_screen_space_rects,
@@ -88,8 +89,8 @@ class DebugRectHistory {
DebugRectHistory();
void SavePaintRects(LayerImpl* layer);
- void SavePropertyChangedRects(
- const LayerImplList& render_surface_layer_list);
+ void SavePropertyChangedRects(const LayerImplList& render_surface_layer_list,
+ LayerImpl* hud_layer);
void SaveSurfaceDamageRects(
const LayerImplList& render_surface_layer_list);
void SaveScreenSpaceRects(
@@ -102,6 +103,8 @@ class DebugRectHistory {
void SaveTouchEventHandlerRectsCallback(LayerImpl* layer);
void SaveWheelEventHandlerRects(LayerImpl* layer);
void SaveWheelEventHandlerRectsCallback(LayerImpl* layer);
+ void SaveScrollEventHandlerRects(LayerImpl* layer);
+ void SaveScrollEventHandlerRectsCallback(LayerImpl* layer);
void SaveNonFastScrollableRects(LayerImpl* layer);
void SaveNonFastScrollableRectsCallback(LayerImpl* layer);
void SaveLayerAnimationBoundsRects(
diff --git a/chromium/cc/debug/devtools_instrumentation.h b/chromium/cc/debug/devtools_instrumentation.h
index 3caa81ea6d5..85a9850f20b 100644
--- a/chromium/cc/debug/devtools_instrumentation.h
+++ b/chromium/cc/debug/devtools_instrumentation.h
@@ -11,7 +11,9 @@ namespace cc {
namespace devtools_instrumentation {
namespace internal {
-const char kCategory[] = "cc,devtools";
+const char kCategory[] = TRACE_DISABLED_BY_DEFAULT("devtools.timeline");
+const char kCategoryFrame[] =
+ TRACE_DISABLED_BY_DEFAULT("devtools.timeline.frame");
const char kFrameId[] = "frameId";
const char kLayerId[] = "layerId";
const char kLayerTreeId[] = "layerTreeId";
@@ -20,10 +22,13 @@ const char kPixelRefId[] = "pixelRefId";
const char kImageDecodeTask[] = "ImageDecodeTask";
const char kBeginFrame[] = "BeginFrame";
const char kActivateLayerTree[] = "ActivateLayerTree";
+const char kRequestMainThreadFrame[] = "RequestMainThreadFrame";
+const char kDrawFrame[] = "DrawFrame";
} // namespace internal
const char kRasterTask[] = "RasterTask";
const char kPaintSetup[] = "PaintSetup";
+const char kUpdateLayer[] = "UpdateLayer";
class ScopedLayerTask {
public:
@@ -86,19 +91,38 @@ struct ScopedLayerObjectTracker
DISALLOW_COPY_AND_ASSIGN(ScopedLayerObjectTracker);
};
-inline void didActivateLayerTree(int layer_tree_host_id, int frame_id) {
- TRACE_EVENT_INSTANT2(internal::kCategory,
+inline void DidActivateLayerTree(int layer_tree_host_id, int frame_id) {
+ TRACE_EVENT_INSTANT2(internal::kCategoryFrame,
internal::kActivateLayerTree,
TRACE_EVENT_SCOPE_THREAD,
- internal::kLayerTreeId, layer_tree_host_id,
- internal::kFrameId, frame_id);
+ internal::kLayerTreeId,
+ layer_tree_host_id,
+ internal::kFrameId,
+ frame_id);
}
-inline void didBeginFrame(int layer_tree_host_id) {
- TRACE_EVENT_INSTANT1(internal::kCategory,
+inline void DidBeginFrame(int layer_tree_host_id) {
+ TRACE_EVENT_INSTANT1(internal::kCategoryFrame,
internal::kBeginFrame,
TRACE_EVENT_SCOPE_THREAD,
- internal::kLayerTreeId, layer_tree_host_id);
+ internal::kLayerTreeId,
+ layer_tree_host_id);
+}
+
+inline void DidDrawFrame(int layer_tree_host_id) {
+ TRACE_EVENT_INSTANT1(internal::kCategoryFrame,
+ internal::kDrawFrame,
+ TRACE_EVENT_SCOPE_THREAD,
+ internal::kLayerTreeId,
+ layer_tree_host_id);
+}
+
+inline void DidRequestMainThreadFrame(int layer_tree_host_id) {
+ TRACE_EVENT_INSTANT1(internal::kCategoryFrame,
+ internal::kRequestMainThreadFrame,
+ TRACE_EVENT_SCOPE_THREAD,
+ internal::kLayerTreeId,
+ layer_tree_host_id);
}
} // namespace devtools_instrumentation
diff --git a/chromium/cc/debug/frame_viewer_instrumentation.h b/chromium/cc/debug/frame_viewer_instrumentation.h
new file mode 100644
index 00000000000..16cf4335ac2
--- /dev/null
+++ b/chromium/cc/debug/frame_viewer_instrumentation.h
@@ -0,0 +1,93 @@
+// 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_DEBUG_FRAME_VIEWER_INSTRUMENTATION_H_
+#define CC_DEBUG_FRAME_VIEWER_INSTRUMENTATION_H_
+
+#include "base/debug/trace_event.h"
+#include "cc/resources/tile.h"
+
+namespace cc {
+namespace frame_viewer_instrumentation {
+namespace internal {
+
+const char kCategory[] = "cc";
+const char kTileData[] = "tileData";
+const char kLayerId[] = "layerId";
+const char kTileId[] = "tileId";
+const char kTileResolution[] = "tileResolution";
+const char kSourceFrameNumber[] = "sourceFrameNumber";
+const char kRasterMode[] = "rasterMode";
+
+const char kAnalyzeTask[] = "AnalyzeTask";
+const char kRasterTask[] = "RasterTask";
+
+scoped_ptr<base::Value> TileDataAsValue(const void* tile_id,
+ TileResolution tile_resolution,
+ int source_frame_number,
+ int layer_id) {
+ scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue);
+ res->Set(internal::kTileId, TracedValue::CreateIDRef(tile_id).release());
+ res->Set(internal::kTileResolution,
+ TileResolutionAsValue(tile_resolution).release());
+ res->SetInteger(internal::kSourceFrameNumber, source_frame_number);
+ res->SetInteger(internal::kLayerId, layer_id);
+ return res.PassAs<base::Value>();
+}
+
+} // namespace internal
+
+class ScopedAnalyzeTask {
+ public:
+ ScopedAnalyzeTask(const void* tile_id,
+ TileResolution tile_resolution,
+ int source_frame_number,
+ int layer_id) {
+ TRACE_EVENT_BEGIN1(
+ internal::kCategory,
+ internal::kAnalyzeTask,
+ internal::kTileData,
+ TracedValue::FromValue(internal::TileDataAsValue(tile_id,
+ tile_resolution,
+ source_frame_number,
+ layer_id).release()));
+ }
+ ~ScopedAnalyzeTask() {
+ TRACE_EVENT_END0(internal::kCategory, internal::kAnalyzeTask);
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ScopedAnalyzeTask);
+};
+
+class ScopedRasterTask {
+ public:
+ ScopedRasterTask(const void* tile_id,
+ TileResolution tile_resolution,
+ int source_frame_number,
+ int layer_id,
+ RasterMode raster_mode) {
+ TRACE_EVENT_BEGIN2(
+ internal::kCategory,
+ internal::kRasterTask,
+ internal::kTileData,
+ TracedValue::FromValue(internal::TileDataAsValue(tile_id,
+ tile_resolution,
+ source_frame_number,
+ layer_id).release()),
+ internal::kRasterMode,
+ TracedValue::FromValue(RasterModeAsValue(raster_mode).release()));
+ }
+ ~ScopedRasterTask() {
+ TRACE_EVENT_END0(internal::kCategory, internal::kRasterTask);
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ScopedRasterTask);
+};
+
+} // namespace frame_viewer_instrumentation
+} // namespace cc
+
+#endif // CC_DEBUG_FRAME_VIEWER_INSTRUMENTATION_H_
diff --git a/chromium/cc/debug/invalidation_benchmark.cc b/chromium/cc/debug/invalidation_benchmark.cc
new file mode 100644
index 00000000000..f063fe71d74
--- /dev/null
+++ b/chromium/cc/debug/invalidation_benchmark.cc
@@ -0,0 +1,139 @@
+// 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/debug/invalidation_benchmark.h"
+
+#include <algorithm>
+#include <limits>
+
+#include "base/basictypes.h"
+#include "base/rand_util.h"
+#include "base/values.h"
+#include "cc/layers/layer.h"
+#include "cc/layers/picture_layer.h"
+#include "cc/trees/layer_tree_host.h"
+#include "cc/trees/layer_tree_host_common.h"
+#include "ui/gfx/rect.h"
+
+namespace cc {
+
+namespace {
+
+const char* kDefaultInvalidationMode = "viewport";
+
+} // namespace
+
+InvalidationBenchmark::InvalidationBenchmark(
+ scoped_ptr<base::Value> value,
+ const MicroBenchmark::DoneCallback& callback)
+ : MicroBenchmark(callback), seed_(0) {
+ base::DictionaryValue* settings = NULL;
+ value->GetAsDictionary(&settings);
+ if (!settings)
+ return;
+
+ std::string mode_string = kDefaultInvalidationMode;
+
+ if (settings->HasKey("mode"))
+ settings->GetString("mode", &mode_string);
+
+ if (mode_string == "fixed_size") {
+ mode_ = FIXED_SIZE;
+ CHECK(settings->HasKey("width"))
+ << "Must provide a width for fixed_size mode.";
+ CHECK(settings->HasKey("height"))
+ << "Must provide a height for fixed_size mode.";
+ settings->GetInteger("width", &width_);
+ settings->GetInteger("height", &height_);
+ } else if (mode_string == "layer") {
+ mode_ = LAYER;
+ } else if (mode_string == "random") {
+ mode_ = RANDOM;
+ } else if (mode_string == "viewport") {
+ mode_ = VIEWPORT;
+ } else {
+ CHECK(false) << "Invalid mode: " << mode_string
+ << ". One of {fixed_size, layer, viewport, random} expected.";
+ }
+}
+
+InvalidationBenchmark::~InvalidationBenchmark() {
+}
+
+void InvalidationBenchmark::DidUpdateLayers(LayerTreeHost* host) {
+ LayerTreeHostCommon::CallFunctionForSubtree(
+ host->root_layer(),
+ base::Bind(&InvalidationBenchmark::Run, base::Unretained(this)));
+}
+
+void InvalidationBenchmark::Run(Layer* layer) {
+ layer->RunMicroBenchmark(this);
+}
+
+void InvalidationBenchmark::RunOnLayer(PictureLayer* layer) {
+ switch (mode_) {
+ case FIXED_SIZE: {
+ // Invalidation with a random position and fixed size.
+ gfx::Rect visible_content_rect = layer->visible_content_rect();
+ int x = LCGRandom() * (visible_content_rect.width() - width_);
+ int y = LCGRandom() * (visible_content_rect.height() - height_);
+ gfx::Rect invalidation_rect(x, y, width_, height_);
+ layer->SetNeedsDisplayRect(invalidation_rect);
+ break;
+ }
+ case LAYER: {
+ // Invalidate entire layer.
+ layer->SetNeedsDisplay();
+ break;
+ }
+ case RANDOM: {
+ // Random invalidation inside the viewport.
+ gfx::Rect visible_content_rect = layer->visible_content_rect();
+ int x_min = LCGRandom() * visible_content_rect.width();
+ int x_max = LCGRandom() * visible_content_rect.width();
+ int y_min = LCGRandom() * visible_content_rect.height();
+ int y_max = LCGRandom() * visible_content_rect.height();
+ if (x_min > x_max)
+ std::swap(x_min, x_max);
+ if (y_min > y_max)
+ std::swap(y_min, y_max);
+ gfx::Rect invalidation_rect(x_min, y_min, x_max - x_min, y_max - y_min);
+ layer->SetNeedsDisplayRect(invalidation_rect);
+ break;
+ }
+ case VIEWPORT: {
+ // Invalidate entire viewport.
+ layer->SetNeedsDisplayRect(layer->visible_content_rect());
+ break;
+ }
+ }
+}
+
+bool InvalidationBenchmark::ProcessMessage(scoped_ptr<base::Value> value) {
+ base::DictionaryValue* message = NULL;
+ value->GetAsDictionary(&message);
+ if (!message)
+ return false;
+
+ bool notify_done;
+ if (message->HasKey("notify_done")) {
+ message->GetBoolean("notify_done", &notify_done);
+ if (notify_done)
+ NotifyDone(scoped_ptr<base::Value>(base::Value::CreateNullValue()));
+ return true;
+ }
+ return false;
+}
+
+// A simple linear congruential generator. The random numbers don't need to be
+// high quality, but they need to be identical in each run. Therefore, we use a
+// LCG and keep the state locally in the benchmark.
+float InvalidationBenchmark::LCGRandom() {
+ const uint32 a = 1664525;
+ const uint32 c = 1013904223;
+ seed_ = a * seed_ + c;
+ return static_cast<float>(seed_) / std::numeric_limits<uint32>::max();
+}
+
+} // namespace cc
diff --git a/chromium/cc/debug/invalidation_benchmark.h b/chromium/cc/debug/invalidation_benchmark.h
new file mode 100644
index 00000000000..00481ae4c36
--- /dev/null
+++ b/chromium/cc/debug/invalidation_benchmark.h
@@ -0,0 +1,45 @@
+// 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_DEBUG_INVALIDATION_BENCHMARK_H_
+#define CC_DEBUG_INVALIDATION_BENCHMARK_H_
+
+#include <string>
+
+#include "cc/debug/micro_benchmark_controller.h"
+
+namespace cc {
+
+class LayerTreeHost;
+class Layer;
+// NOTE: this benchmark will not measure or return any results, it will simply
+// invalidate a certain area of each layer every frame. It is intended to be
+// used in combination with a telemetry benchmark that does the actual
+// measurement.
+class CC_EXPORT InvalidationBenchmark : public MicroBenchmark {
+ public:
+ explicit InvalidationBenchmark(scoped_ptr<base::Value> value,
+ const MicroBenchmark::DoneCallback& callback);
+ virtual ~InvalidationBenchmark();
+
+ // Implements MicroBenchmark interface.
+ virtual void DidUpdateLayers(LayerTreeHost* host) OVERRIDE;
+ virtual void RunOnLayer(PictureLayer* layer) OVERRIDE;
+ virtual bool ProcessMessage(scoped_ptr<base::Value> value) OVERRIDE;
+
+ private:
+ enum Mode { FIXED_SIZE, LAYER, VIEWPORT, RANDOM };
+
+ void Run(Layer* layer);
+ float LCGRandom();
+
+ Mode mode_;
+ int width_;
+ int height_;
+ uint32 seed_;
+};
+
+} // namespace cc
+
+#endif // CC_DEBUG_INVALIDATION_BENCHMARK_H_
diff --git a/chromium/cc/debug/lap_timer.cc b/chromium/cc/debug/lap_timer.cc
new file mode 100644
index 00000000000..27aaf3499a9
--- /dev/null
+++ b/chromium/cc/debug/lap_timer.cc
@@ -0,0 +1,81 @@
+// 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/debug/lap_timer.h"
+
+#include "base/logging.h"
+
+namespace cc {
+
+namespace {
+
+base::TimeTicks Now() {
+ return base::TimeTicks::IsThreadNowSupported()
+ ? base::TimeTicks::ThreadNow()
+ : base::TimeTicks::HighResNow();
+}
+
+} // namespace
+
+LapTimer::LapTimer(int warmup_laps,
+ base::TimeDelta time_limit,
+ int check_interval)
+ : warmup_laps_(warmup_laps),
+ remaining_warmups_(0),
+ remaining_no_check_laps_(0),
+ time_limit_(time_limit),
+ check_interval_(check_interval) {
+ DCHECK_GT(check_interval, 0);
+ Reset();
+}
+
+void LapTimer::Reset() {
+ accumulator_ = base::TimeDelta();
+ num_laps_ = 0;
+ remaining_warmups_ = warmup_laps_;
+ remaining_no_check_laps_ = check_interval_;
+ Start();
+}
+
+void LapTimer::Start() {
+ start_time_ = Now();
+}
+
+bool LapTimer::IsWarmedUp() { return remaining_warmups_ <= 0; }
+
+void LapTimer::NextLap() {
+ if (!IsWarmedUp()) {
+ --remaining_warmups_;
+ if (IsWarmedUp()) {
+ Start();
+ }
+ return;
+ }
+ ++num_laps_;
+ --remaining_no_check_laps_;
+ if (!remaining_no_check_laps_) {
+ base::TimeTicks now = Now();
+ accumulator_ += now - start_time_;
+ start_time_ = now;
+ remaining_no_check_laps_ = check_interval_;
+ }
+}
+
+bool LapTimer::HasTimeLimitExpired() { return accumulator_ >= time_limit_; }
+
+bool LapTimer::HasTimedAllLaps() { return !(num_laps_ % check_interval_); }
+
+float LapTimer::MsPerLap() {
+ DCHECK(HasTimedAllLaps());
+ return accumulator_.InMillisecondsF() / num_laps_;
+}
+
+float LapTimer::LapsPerSecond() {
+ DCHECK(HasTimedAllLaps());
+ return num_laps_ / accumulator_.InSecondsF();
+}
+
+int LapTimer::NumLaps() { return num_laps_; }
+
+} // namespace cc
diff --git a/chromium/cc/debug/lap_timer.h b/chromium/cc/debug/lap_timer.h
new file mode 100644
index 00000000000..7ec9a8cca5c
--- /dev/null
+++ b/chromium/cc/debug/lap_timer.h
@@ -0,0 +1,64 @@
+// 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_DEBUG_LAP_TIMER_H_
+#define CC_DEBUG_LAP_TIMER_H_
+
+#include "base/time/time.h"
+#include "cc/base/cc_export.h"
+
+namespace cc {
+
+// LapTimer is used to calculate average times per "Lap" in perf tests.
+// Current() reports the time since the last call to Start().
+// Store() adds the time since the last call to Start() to the accumulator, and
+// resets the start time to now. Stored() returns the accumulated time.
+// NextLap increments the lap counter, used in counting the per lap averages.
+// If you initialize the LapTimer with a non zero warmup_laps, it will ignore
+// the times for that many laps at the start.
+// If you set the time_limit then you can use HasTimeLimitExpired() to see if
+// the current accumulated time has crossed that threshold, with an optimization
+// that it only tests this every check_interval laps.
+class CC_EXPORT LapTimer {
+ public:
+ LapTimer(int warmup_laps, base::TimeDelta time_limit, int check_interval);
+ // Resets the timer back to it's starting state.
+ void Reset();
+ // Sets the start point to now.
+ void Start();
+ // Returns true if there are no more warmup laps to do.
+ bool IsWarmedUp();
+ // Advance the lap counter and update the accumulated time.
+ // The accumulated time is only updated every check_interval laps.
+ // If accumulating then the start point will also be updated.
+ void NextLap();
+ // Returns true if the stored time has exceeded the time limit specified.
+ // May cause a call to Store().
+ bool HasTimeLimitExpired();
+ // Returns true if all lap times have been timed. Only true every n'th
+ // lap, where n = check_interval.
+ bool HasTimedAllLaps();
+ // The average milliseconds per lap.
+ float MsPerLap();
+ // The number of laps per second.
+ float LapsPerSecond();
+ // The number of laps recorded.
+ int NumLaps();
+
+ private:
+ base::TimeTicks start_time_;
+ base::TimeDelta accumulator_;
+ int num_laps_;
+ int warmup_laps_;
+ int remaining_warmups_;
+ int remaining_no_check_laps_;
+ base::TimeDelta time_limit_;
+ int check_interval_;
+
+ DISALLOW_COPY_AND_ASSIGN(LapTimer);
+};
+
+} // namespace cc
+
+#endif // CC_DEBUG_LAP_TIMER_H_
diff --git a/chromium/cc/debug/layer_tree_debug_state.cc b/chromium/cc/debug/layer_tree_debug_state.cc
index 95245e0f0b2..d89bca38906 100644
--- a/chromium/cc/debug/layer_tree_debug_state.cc
+++ b/chromium/cc/debug/layer_tree_debug_state.cc
@@ -22,6 +22,7 @@ LayerTreeDebugState::LayerTreeDebugState()
show_non_occluding_rects(false),
show_touch_event_handler_rects(false),
show_wheel_event_handler_rects(false),
+ show_scroll_event_handler_rects(false),
show_non_fast_scrollable_rects(false),
show_layer_animation_bounds_rects(false),
slow_down_raster_scale_factor(0),
@@ -49,8 +50,8 @@ bool LayerTreeDebugState::ShowHudRects() const {
show_surface_damage_rects || show_screen_space_rects ||
show_replica_screen_space_rects || show_occluding_rects ||
show_non_occluding_rects || show_touch_event_handler_rects ||
- show_wheel_event_handler_rects || show_non_fast_scrollable_rects ||
- show_layer_animation_bounds_rects;
+ show_wheel_event_handler_rects || show_scroll_event_handler_rects ||
+ show_non_fast_scrollable_rects || show_layer_animation_bounds_rects;
}
bool LayerTreeDebugState::ShowMemoryStats() const {
@@ -59,30 +60,27 @@ bool LayerTreeDebugState::ShowMemoryStats() const {
bool LayerTreeDebugState::Equal(const LayerTreeDebugState& a,
const LayerTreeDebugState& b) {
- return (a.show_fps_counter == b.show_fps_counter &&
- a.show_debug_borders == b.show_debug_borders &&
- a.continuous_painting == b.continuous_painting &&
- a.show_paint_rects == b.show_paint_rects &&
- a.show_property_changed_rects == b.show_property_changed_rects &&
- a.show_surface_damage_rects == b.show_surface_damage_rects &&
- a.show_screen_space_rects == b.show_screen_space_rects &&
- a.show_replica_screen_space_rects ==
- b.show_replica_screen_space_rects &&
- a.show_occluding_rects == b.show_occluding_rects &&
- a.show_non_occluding_rects == b.show_non_occluding_rects &&
- a.show_touch_event_handler_rects ==
- b.show_touch_event_handler_rects &&
- a.show_wheel_event_handler_rects ==
- b.show_wheel_event_handler_rects &&
- a.show_non_fast_scrollable_rects ==
- b.show_non_fast_scrollable_rects &&
- a.show_layer_animation_bounds_rects ==
+ return (
+ a.show_fps_counter == b.show_fps_counter &&
+ a.show_debug_borders == b.show_debug_borders &&
+ a.continuous_painting == b.continuous_painting &&
+ a.show_paint_rects == b.show_paint_rects &&
+ a.show_property_changed_rects == b.show_property_changed_rects &&
+ a.show_surface_damage_rects == b.show_surface_damage_rects &&
+ a.show_screen_space_rects == b.show_screen_space_rects &&
+ a.show_replica_screen_space_rects == b.show_replica_screen_space_rects &&
+ a.show_occluding_rects == b.show_occluding_rects &&
+ a.show_non_occluding_rects == b.show_non_occluding_rects &&
+ a.show_touch_event_handler_rects == b.show_touch_event_handler_rects &&
+ a.show_wheel_event_handler_rects == b.show_wheel_event_handler_rects &&
+ a.show_scroll_event_handler_rects == b.show_scroll_event_handler_rects &&
+ a.show_non_fast_scrollable_rects == b.show_non_fast_scrollable_rects &&
+ a.show_layer_animation_bounds_rects ==
b.show_layer_animation_bounds_rects &&
- a.slow_down_raster_scale_factor == b.slow_down_raster_scale_factor &&
- a.rasterize_only_visible_content ==
- b.rasterize_only_visible_content &&
- a.show_picture_borders == b.show_picture_borders &&
- a.record_rendering_stats_ == b.record_rendering_stats_);
+ a.slow_down_raster_scale_factor == b.slow_down_raster_scale_factor &&
+ a.rasterize_only_visible_content == b.rasterize_only_visible_content &&
+ a.show_picture_borders == b.show_picture_borders &&
+ a.record_rendering_stats_ == b.record_rendering_stats_);
}
LayerTreeDebugState LayerTreeDebugState::Unite(const LayerTreeDebugState& a,
@@ -102,6 +100,7 @@ LayerTreeDebugState LayerTreeDebugState::Unite(const LayerTreeDebugState& a,
r.show_non_occluding_rects |= b.show_non_occluding_rects;
r.show_touch_event_handler_rects |= b.show_touch_event_handler_rects;
r.show_wheel_event_handler_rects |= b.show_wheel_event_handler_rects;
+ r.show_scroll_event_handler_rects |= b.show_scroll_event_handler_rects;
r.show_non_fast_scrollable_rects |= b.show_non_fast_scrollable_rects;
r.show_layer_animation_bounds_rects |= b.show_layer_animation_bounds_rects;
diff --git a/chromium/cc/debug/layer_tree_debug_state.h b/chromium/cc/debug/layer_tree_debug_state.h
index 24196de13d6..c3970e16549 100644
--- a/chromium/cc/debug/layer_tree_debug_state.h
+++ b/chromium/cc/debug/layer_tree_debug_state.h
@@ -28,6 +28,7 @@ class CC_EXPORT LayerTreeDebugState {
bool show_non_occluding_rects;
bool show_touch_event_handler_rects;
bool show_wheel_event_handler_rects;
+ bool show_scroll_event_handler_rects;
bool show_non_fast_scrollable_rects;
bool show_layer_animation_bounds_rects;
diff --git a/chromium/cc/debug/micro_benchmark.cc b/chromium/cc/debug/micro_benchmark.cc
index 464d0cb625d..05c5c0d1a56 100644
--- a/chromium/cc/debug/micro_benchmark.cc
+++ b/chromium/cc/debug/micro_benchmark.cc
@@ -16,7 +16,9 @@ namespace cc {
MicroBenchmark::MicroBenchmark(const DoneCallback& callback)
: callback_(callback),
is_done_(false),
- processed_for_benchmark_impl_(false) {}
+ processed_for_benchmark_impl_(false),
+ id_(0) {
+}
MicroBenchmark::~MicroBenchmark() {}
@@ -35,6 +37,10 @@ void MicroBenchmark::RunOnLayer(Layer* layer) {}
void MicroBenchmark::RunOnLayer(PictureLayer* layer) {}
+bool MicroBenchmark::ProcessMessage(scoped_ptr<base::Value> value) {
+ return false;
+}
+
bool MicroBenchmark::ProcessedForBenchmarkImpl() const {
return processed_for_benchmark_impl_;
}
diff --git a/chromium/cc/debug/micro_benchmark.h b/chromium/cc/debug/micro_benchmark.h
index f179fb9544d..1654c368f1d 100644
--- a/chromium/cc/debug/micro_benchmark.h
+++ b/chromium/cc/debug/micro_benchmark.h
@@ -29,10 +29,14 @@ class CC_EXPORT MicroBenchmark {
bool IsDone() const;
virtual void DidUpdateLayers(LayerTreeHost* host);
+ int id() const { return id_; }
+ void set_id(int id) { id_ = id; }
virtual void RunOnLayer(Layer* layer);
virtual void RunOnLayer(PictureLayer* layer);
+ virtual bool ProcessMessage(scoped_ptr<base::Value> value);
+
bool ProcessedForBenchmarkImpl() const;
scoped_ptr<MicroBenchmarkImpl> GetBenchmarkImpl(
scoped_refptr<base::MessageLoopProxy> origin_loop);
@@ -47,6 +51,7 @@ class CC_EXPORT MicroBenchmark {
DoneCallback callback_;
bool is_done_;
bool processed_for_benchmark_impl_;
+ int id_;
};
} // namespace cc
diff --git a/chromium/cc/debug/micro_benchmark_controller.cc b/chromium/cc/debug/micro_benchmark_controller.cc
index 7d9025c1c42..8b20bdf197f 100644
--- a/chromium/cc/debug/micro_benchmark_controller.cc
+++ b/chromium/cc/debug/micro_benchmark_controller.cc
@@ -4,11 +4,13 @@
#include "cc/debug/micro_benchmark_controller.h"
+#include <limits>
#include <string>
#include "base/callback.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/values.h"
+#include "cc/debug/invalidation_benchmark.h"
#include "cc/debug/picture_record_benchmark.h"
#include "cc/debug/rasterize_and_record_benchmark.h"
#include "cc/debug/unittest_only_benchmark.h"
@@ -17,13 +19,18 @@
namespace cc {
+int MicroBenchmarkController::next_id_ = 1;
+
namespace {
scoped_ptr<MicroBenchmark> CreateBenchmark(
const std::string& name,
scoped_ptr<base::Value> value,
const MicroBenchmark::DoneCallback& callback) {
- if (name == "picture_record_benchmark") {
+ if (name == "invalidation_benchmark") {
+ return scoped_ptr<MicroBenchmark>(
+ new InvalidationBenchmark(value.Pass(), callback));
+ } else if (name == "picture_record_benchmark") {
return scoped_ptr<MicroBenchmark>(
new PictureRecordBenchmark(value.Pass(), callback));
} else if (name == "rasterize_and_record_benchmark") {
@@ -56,16 +63,37 @@ MicroBenchmarkController::MicroBenchmarkController(LayerTreeHost* host)
MicroBenchmarkController::~MicroBenchmarkController() {}
-bool MicroBenchmarkController::ScheduleRun(
+int MicroBenchmarkController::ScheduleRun(
const std::string& micro_benchmark_name,
scoped_ptr<base::Value> value,
const MicroBenchmark::DoneCallback& callback) {
scoped_ptr<MicroBenchmark> benchmark =
CreateBenchmark(micro_benchmark_name, value.Pass(), callback);
if (benchmark.get()) {
+ int id = GetNextIdAndIncrement();
+ benchmark->set_id(id);
benchmarks_.push_back(benchmark.Pass());
host_->SetNeedsCommit();
- return true;
+ return id;
+ }
+ return 0;
+}
+
+int MicroBenchmarkController::GetNextIdAndIncrement() {
+ int id = next_id_++;
+ // Wrap around to 1 if we overflow (very unlikely).
+ if (next_id_ == std::numeric_limits<int>::max())
+ next_id_ = 1;
+ return id;
+}
+
+bool MicroBenchmarkController::SendMessage(int id,
+ scoped_ptr<base::Value> value) {
+ for (ScopedPtrVector<MicroBenchmark>::iterator it = benchmarks_.begin();
+ it != benchmarks_.end();
+ ++it) {
+ if ((*it)->id() == id)
+ return (*it)->ProcessMessage(value.Pass());
}
return false;
}
diff --git a/chromium/cc/debug/micro_benchmark_controller.h b/chromium/cc/debug/micro_benchmark_controller.h
index 7220dc1778f..88f6d9adad9 100644
--- a/chromium/cc/debug/micro_benchmark_controller.h
+++ b/chromium/cc/debug/micro_benchmark_controller.h
@@ -28,17 +28,22 @@ class CC_EXPORT MicroBenchmarkController {
void DidUpdateLayers();
- bool ScheduleRun(const std::string& micro_benchmark_name,
- scoped_ptr<base::Value> value,
- const MicroBenchmark::DoneCallback& callback);
+ // Returns the id of the benchmark on success, 0 otherwise.
+ int ScheduleRun(const std::string& micro_benchmark_name,
+ scoped_ptr<base::Value> value,
+ const MicroBenchmark::DoneCallback& callback);
+ // Returns true if the message was successfully delivered and handled.
+ bool SendMessage(int id, scoped_ptr<base::Value> value);
void ScheduleImplBenchmarks(LayerTreeHostImpl* host_impl);
private:
void CleanUpFinishedBenchmarks();
+ int GetNextIdAndIncrement();
LayerTreeHost* host_;
ScopedPtrVector<MicroBenchmark> benchmarks_;
+ static int next_id_;
scoped_refptr<base::MessageLoopProxy> main_controller_message_loop_;
DISALLOW_COPY_AND_ASSIGN(MicroBenchmarkController);
diff --git a/chromium/cc/debug/micro_benchmark_controller_unittest.cc b/chromium/cc/debug/micro_benchmark_controller_unittest.cc
index 4894947a6da..83faeabf9a1 100644
--- a/chromium/cc/debug/micro_benchmark_controller_unittest.cc
+++ b/chromium/cc/debug/micro_benchmark_controller_unittest.cc
@@ -20,8 +20,9 @@ class MicroBenchmarkControllerTest : public testing::Test {
public:
virtual void SetUp() OVERRIDE {
impl_proxy_ = make_scoped_ptr(new FakeImplProxy);
- layer_tree_host_impl_ =
- make_scoped_ptr(new FakeLayerTreeHostImpl(impl_proxy_.get()));
+ shared_bitmap_manager_.reset(new TestSharedBitmapManager());
+ layer_tree_host_impl_ = make_scoped_ptr(new FakeLayerTreeHostImpl(
+ impl_proxy_.get(), shared_bitmap_manager_.get()));
layer_tree_host_ = FakeLayerTreeHost::Create();
layer_tree_host_->SetRootLayer(Layer::Create());
@@ -35,6 +36,7 @@ class MicroBenchmarkControllerTest : public testing::Test {
}
scoped_ptr<FakeLayerTreeHost> layer_tree_host_;
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager_;
scoped_ptr<FakeLayerTreeHostImpl> layer_tree_host_impl_;
scoped_ptr<FakeImplProxy> impl_proxy_;
};
@@ -47,26 +49,26 @@ void IncrementCallCount(int* count, scoped_ptr<base::Value> value) {
}
TEST_F(MicroBenchmarkControllerTest, ScheduleFail) {
- bool result = layer_tree_host_->ScheduleMicroBenchmark(
+ int id = layer_tree_host_->ScheduleMicroBenchmark(
"non_existant_benchmark", scoped_ptr<base::Value>(), base::Bind(&Noop));
- EXPECT_FALSE(result);
+ EXPECT_EQ(id, 0);
}
TEST_F(MicroBenchmarkControllerTest, CommitScheduled) {
EXPECT_FALSE(layer_tree_host_->needs_commit());
- bool result = layer_tree_host_->ScheduleMicroBenchmark(
+ int id = layer_tree_host_->ScheduleMicroBenchmark(
"unittest_only_benchmark", scoped_ptr<base::Value>(), base::Bind(&Noop));
- EXPECT_TRUE(result);
+ EXPECT_GT(id, 0);
EXPECT_TRUE(layer_tree_host_->needs_commit());
}
TEST_F(MicroBenchmarkControllerTest, BenchmarkRan) {
int run_count = 0;
- bool result = layer_tree_host_->ScheduleMicroBenchmark(
+ int id = layer_tree_host_->ScheduleMicroBenchmark(
"unittest_only_benchmark",
scoped_ptr<base::Value>(),
base::Bind(&IncrementCallCount, base::Unretained(&run_count)));
- EXPECT_TRUE(result);
+ EXPECT_GT(id, 0);
scoped_ptr<ResourceUpdateQueue> queue(new ResourceUpdateQueue);
layer_tree_host_->SetOutputSurfaceLostForTesting(false);
@@ -77,16 +79,16 @@ TEST_F(MicroBenchmarkControllerTest, BenchmarkRan) {
TEST_F(MicroBenchmarkControllerTest, MultipleBenchmarkRan) {
int run_count = 0;
- bool result = layer_tree_host_->ScheduleMicroBenchmark(
+ int id = layer_tree_host_->ScheduleMicroBenchmark(
"unittest_only_benchmark",
scoped_ptr<base::Value>(),
base::Bind(&IncrementCallCount, base::Unretained(&run_count)));
- EXPECT_TRUE(result);
- result = layer_tree_host_->ScheduleMicroBenchmark(
+ EXPECT_GT(id, 0);
+ id = layer_tree_host_->ScheduleMicroBenchmark(
"unittest_only_benchmark",
scoped_ptr<base::Value>(),
base::Bind(&IncrementCallCount, base::Unretained(&run_count)));
- EXPECT_TRUE(result);
+ EXPECT_GT(id, 0);
scoped_ptr<ResourceUpdateQueue> queue(new ResourceUpdateQueue);
layer_tree_host_->SetOutputSurfaceLostForTesting(false);
@@ -94,16 +96,16 @@ TEST_F(MicroBenchmarkControllerTest, MultipleBenchmarkRan) {
EXPECT_EQ(2, run_count);
- result = layer_tree_host_->ScheduleMicroBenchmark(
+ id = layer_tree_host_->ScheduleMicroBenchmark(
"unittest_only_benchmark",
scoped_ptr<base::Value>(),
base::Bind(&IncrementCallCount, base::Unretained(&run_count)));
- EXPECT_TRUE(result);
- result = layer_tree_host_->ScheduleMicroBenchmark(
+ EXPECT_GT(id, 0);
+ id = layer_tree_host_->ScheduleMicroBenchmark(
"unittest_only_benchmark",
scoped_ptr<base::Value>(),
base::Bind(&IncrementCallCount, base::Unretained(&run_count)));
- EXPECT_TRUE(result);
+ EXPECT_GT(id, 0);
layer_tree_host_->UpdateLayers(queue.get());
EXPECT_EQ(4, run_count);
@@ -118,11 +120,11 @@ TEST_F(MicroBenchmarkControllerTest, BenchmarkImplRan) {
settings->SetBoolean("run_benchmark_impl", true);
// Schedule a main thread benchmark.
- bool result = layer_tree_host_->ScheduleMicroBenchmark(
+ int id = layer_tree_host_->ScheduleMicroBenchmark(
"unittest_only_benchmark",
settings.PassAs<base::Value>(),
base::Bind(&IncrementCallCount, base::Unretained(&run_count)));
- EXPECT_TRUE(result);
+ EXPECT_GT(id, 0);
// Schedule impl benchmarks. In production code, this is run in commit.
layer_tree_host_->GetMicroBenchmarkController()->ScheduleImplBenchmarks(
@@ -137,5 +139,36 @@ TEST_F(MicroBenchmarkControllerTest, BenchmarkImplRan) {
EXPECT_EQ(1, run_count);
}
+TEST_F(MicroBenchmarkControllerTest, SendMessage) {
+ // Send valid message to invalid benchmark (id = 0)
+ scoped_ptr<base::DictionaryValue> message(new base::DictionaryValue);
+ message->SetBoolean("can_handle", true);
+ bool message_handled = layer_tree_host_->SendMessageToMicroBenchmark(
+ 0, message.PassAs<base::Value>());
+ EXPECT_FALSE(message_handled);
+
+ // Schedule a benchmark
+ int run_count = 0;
+ int id = layer_tree_host_->ScheduleMicroBenchmark(
+ "unittest_only_benchmark",
+ scoped_ptr<base::Value>(),
+ base::Bind(&IncrementCallCount, base::Unretained(&run_count)));
+ EXPECT_GT(id, 0);
+
+ // Send valid message to valid benchmark
+ message = scoped_ptr<base::DictionaryValue>(new base::DictionaryValue);
+ message->SetBoolean("can_handle", true);
+ message_handled = layer_tree_host_->SendMessageToMicroBenchmark(
+ id, message.PassAs<base::Value>());
+ EXPECT_TRUE(message_handled);
+
+ // Send invalid message to valid benchmark
+ message = scoped_ptr<base::DictionaryValue>(new base::DictionaryValue);
+ message->SetBoolean("can_handle", false);
+ message_handled = layer_tree_host_->SendMessageToMicroBenchmark(
+ id, message.PassAs<base::Value>());
+ EXPECT_FALSE(message_handled);
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/debug/overdraw_metrics.cc b/chromium/cc/debug/overdraw_metrics.cc
deleted file mode 100644
index a14284d800d..00000000000
--- a/chromium/cc/debug/overdraw_metrics.cc
+++ /dev/null
@@ -1,268 +0,0 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/debug/overdraw_metrics.h"
-
-#include "base/debug/trace_event.h"
-#include "base/metrics/histogram.h"
-#include "cc/base/math_util.h"
-#include "cc/trees/layer_tree_host.h"
-#include "cc/trees/layer_tree_host_impl.h"
-#include "ui/gfx/quad_f.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/transform.h"
-
-namespace cc {
-
-OverdrawMetrics::OverdrawMetrics(bool record_metrics_for_frame)
- : record_metrics_for_frame_(record_metrics_for_frame),
- pixels_painted_(0),
- pixels_uploaded_opaque_(0),
- pixels_uploaded_translucent_(0),
- tiles_culled_for_upload_(0),
- contents_texture_use_bytes_(0),
- render_surface_texture_use_bytes_(0),
- pixels_drawn_opaque_(0),
- pixels_drawn_translucent_(0),
- pixels_culled_for_drawing_(0) {}
-
-static inline float WedgeProduct(gfx::PointF p1, gfx::PointF p2) {
- return p1.x() * p2.y() - p1.y() * p2.x();
-}
-
-// Calculates area of an arbitrary convex polygon with up to 8 points.
-static inline float PolygonArea(gfx::PointF points[8], int num_points) {
- if (num_points < 3)
- return 0;
-
- float area = 0;
- for (int i = 0; i < num_points; ++i)
- area += WedgeProduct(points[i], points[(i+1)%num_points]);
- return std::abs(0.5f * area);
-}
-
-// Takes a given quad, maps it by the given transformation, and gives the area
-// of the resulting polygon.
-static inline float AreaOfMappedQuad(const gfx::Transform& transform,
- const gfx::QuadF& quad) {
- gfx::PointF clipped_quad[8];
- int num_vertices_in_clipped_quad = 0;
- MathUtil::MapClippedQuad(transform,
- quad,
- clipped_quad,
- &num_vertices_in_clipped_quad);
- return PolygonArea(clipped_quad, num_vertices_in_clipped_quad);
-}
-
-void OverdrawMetrics::DidPaint(gfx::Rect painted_rect) {
- if (!record_metrics_for_frame_)
- return;
-
- pixels_painted_ +=
- static_cast<float>(painted_rect.width()) * painted_rect.height();
-}
-
-void OverdrawMetrics::DidCullTilesForUpload(int count) {
- if (record_metrics_for_frame_)
- tiles_culled_for_upload_ += count;
-}
-
-void OverdrawMetrics::DidUpload(const gfx::Transform& transform_to_target,
- gfx::Rect upload_rect,
- gfx::Rect opaque_rect) {
- if (!record_metrics_for_frame_)
- return;
-
- float upload_area =
- AreaOfMappedQuad(transform_to_target, gfx::QuadF(upload_rect));
- float upload_opaque_area =
- AreaOfMappedQuad(transform_to_target,
- gfx::QuadF(gfx::IntersectRects(opaque_rect,
- upload_rect)));
-
- pixels_uploaded_opaque_ += upload_opaque_area;
- pixels_uploaded_translucent_ += upload_area - upload_opaque_area;
-}
-
-void OverdrawMetrics::DidUseContentsTextureMemoryBytes(
- size_t contents_texture_use_bytes) {
- if (!record_metrics_for_frame_)
- return;
-
- contents_texture_use_bytes_ += contents_texture_use_bytes;
-}
-
-void OverdrawMetrics::DidUseRenderSurfaceTextureMemoryBytes(
- size_t render_surface_use_bytes) {
- if (!record_metrics_for_frame_)
- return;
-
- render_surface_texture_use_bytes_ += render_surface_use_bytes;
-}
-
-void OverdrawMetrics::DidCullForDrawing(
- const gfx::Transform& transform_to_target,
- gfx::Rect before_cull_rect,
- gfx::Rect after_cull_rect) {
- if (!record_metrics_for_frame_)
- return;
-
- float before_cull_area =
- AreaOfMappedQuad(transform_to_target, gfx::QuadF(before_cull_rect));
- float after_cull_area =
- AreaOfMappedQuad(transform_to_target, gfx::QuadF(after_cull_rect));
-
- pixels_culled_for_drawing_ += before_cull_area - after_cull_area;
-}
-
-void OverdrawMetrics::DidDraw(const gfx::Transform& transform_to_target,
- gfx::Rect after_cull_rect,
- gfx::Rect opaque_rect) {
- if (!record_metrics_for_frame_)
- return;
-
- float after_cull_area =
- AreaOfMappedQuad(transform_to_target, gfx::QuadF(after_cull_rect));
- float after_cull_opaque_area =
- AreaOfMappedQuad(transform_to_target,
- gfx::QuadF(gfx::IntersectRects(opaque_rect,
- after_cull_rect)));
-
- pixels_drawn_opaque_ += after_cull_opaque_area;
- pixels_drawn_translucent_ += after_cull_area - after_cull_opaque_area;
-}
-
-void OverdrawMetrics::RecordMetrics(
- const LayerTreeHost* layer_tree_host) const {
- if (record_metrics_for_frame_)
- RecordMetricsInternal<LayerTreeHost>(UpdateAndCommit, layer_tree_host);
-}
-
-void OverdrawMetrics::RecordMetrics(
- const LayerTreeHostImpl* layer_tree_host_impl) const {
- if (record_metrics_for_frame_) {
- RecordMetricsInternal<LayerTreeHostImpl>(DrawingToScreen,
- layer_tree_host_impl);
- }
-}
-
-static gfx::Size DrawViewportSize(const LayerTreeHost* host) {
- return host->device_viewport_size();
-}
-static gfx::Size DrawViewportSize(const LayerTreeHostImpl* host_impl) {
- return host_impl->DrawViewportSize();
-}
-
-template <typename LayerTreeHostType>
-void OverdrawMetrics::RecordMetricsInternal(
- MetricsType metrics_type,
- const LayerTreeHostType* layer_tree_host) const {
- // This gives approximately 10x the percentage of pixels to fill the viewport
- // once.
- float normalization = 1000.f / (DrawViewportSize(layer_tree_host).width() *
- DrawViewportSize(layer_tree_host).height());
- // This gives approximately 100x the percentage of tiles to fill the viewport
- // once, if all tiles were 256x256.
- float tile_normalization =
- 10000.f / (DrawViewportSize(layer_tree_host).width() / 256.f *
- DrawViewportSize(layer_tree_host).height() / 256.f);
- // This gives approximately 10x the percentage of bytes to fill the viewport
- // once, assuming 4 bytes per pixel.
- float byte_normalization = normalization / 4;
-
- switch (metrics_type) {
- case DrawingToScreen: {
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "Renderer4.pixelCountOpaque_Draw",
- static_cast<int>(normalization * pixels_drawn_opaque_),
- 100, 1000000, 50);
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "Renderer4.pixelCountTranslucent_Draw",
- static_cast<int>(normalization * pixels_drawn_translucent_),
- 100, 1000000, 50);
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "Renderer4.pixelCountCulled_Draw",
- static_cast<int>(normalization * pixels_culled_for_drawing_),
- 100, 1000000, 50);
-
- TRACE_COUNTER_ID1("cc",
- "DrawPixelsCulled",
- layer_tree_host,
- pixels_culled_for_drawing_);
- TRACE_EVENT2("cc",
- "OverdrawMetrics",
- "PixelsDrawnOpaque",
- pixels_drawn_opaque_,
- "PixelsDrawnTranslucent",
- pixels_drawn_translucent_);
- break;
- }
- case UpdateAndCommit: {
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "Renderer4.pixelCountPainted",
- static_cast<int>(normalization * pixels_painted_),
- 100, 1000000, 50);
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "Renderer4.pixelCountOpaque_Upload",
- static_cast<int>(normalization * pixels_uploaded_opaque_),
- 100, 1000000, 50);
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "Renderer4.pixelCountTranslucent_Upload",
- static_cast<int>(normalization * pixels_uploaded_translucent_),
- 100, 1000000, 50);
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "Renderer4.tileCountCulled_Upload",
- static_cast<int>(tile_normalization * tiles_culled_for_upload_),
- 100, 10000000, 50);
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "Renderer4.renderSurfaceTextureBytes_ViewportScaled",
- static_cast<int>(
- byte_normalization * render_surface_texture_use_bytes_),
- 10, 1000000, 50);
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "Renderer4.renderSurfaceTextureBytes_Unscaled",
- static_cast<int>(render_surface_texture_use_bytes_ / 1000),
- 1000, 100000000, 50);
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "Renderer4.contentsTextureBytes_ViewportScaled",
- static_cast<int>(byte_normalization * contents_texture_use_bytes_),
- 10, 1000000, 50);
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "Renderer4.contentsTextureBytes_Unscaled",
- static_cast<int>(contents_texture_use_bytes_ / 1000),
- 1000, 100000000, 50);
- {
- TRACE_COUNTER_ID1("cc",
- "UploadTilesCulled",
- layer_tree_host,
- tiles_culled_for_upload_);
- TRACE_EVENT2("cc",
- "OverdrawMetrics",
- "PixelsUploadedOpaque",
- pixels_uploaded_opaque_,
- "PixelsUploadedTranslucent",
- pixels_uploaded_translucent_);
- }
- {
- // This must be in a different scope than the TRACE_EVENT2 above.
- TRACE_EVENT1("cc",
- "OverdrawPaintMetrics",
- "PixelsPainted",
- pixels_painted_);
- }
- {
- // This must be in a different scope than the TRACE_EVENTs above.
- TRACE_EVENT2("cc",
- "OverdrawPaintMetrics",
- "ContentsTextureBytes",
- contents_texture_use_bytes_,
- "RenderSurfaceTextureBytes",
- render_surface_texture_use_bytes_);
- }
- break;
- }
- }
-}
-
-} // namespace cc
diff --git a/chromium/cc/debug/overdraw_metrics.h b/chromium/cc/debug/overdraw_metrics.h
deleted file mode 100644
index 43bd19baa73..00000000000
--- a/chromium/cc/debug/overdraw_metrics.h
+++ /dev/null
@@ -1,115 +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_DEBUG_OVERDRAW_METRICS_H_
-#define CC_DEBUG_OVERDRAW_METRICS_H_
-
-#include "base/basictypes.h"
-#include "base/memory/scoped_ptr.h"
-
-namespace gfx {
-class Rect;
-class Transform;
-}
-
-namespace cc {
-class LayerTreeHost;
-class LayerTreeHostImpl;
-
-class OverdrawMetrics {
- public:
- static scoped_ptr<OverdrawMetrics> Create(bool record_metrics_for_frame) {
- return make_scoped_ptr(new OverdrawMetrics(record_metrics_for_frame));
- }
-
- // These methods are used for saving metrics during update/commit.
-
- // Record pixels painted by WebKit into the texture updater, but does not mean
- // the pixels were rasterized in main memory.
- void DidPaint(gfx::Rect painted_rect);
- // Records that an invalid tile was culled and did not need to be
- // painted/uploaded, and did not contribute to other tiles needing to be
- // painted.
- void DidCullTilesForUpload(int count);
- // Records pixels that were uploaded to texture memory.
- void DidUpload(const gfx::Transform& transform_to_target,
- gfx::Rect upload_rect,
- gfx::Rect opaque_rect);
- // Record contents texture(s) behind present using the given number of bytes.
- void DidUseContentsTextureMemoryBytes(size_t contents_texture_use_bytes);
- // Record RenderSurfaceImpl texture(s) being present using the given number of
- // bytes.
- void DidUseRenderSurfaceTextureMemoryBytes(size_t render_surface_use_bytes);
-
- // These methods are used for saving metrics during draw.
-
- // Record pixels that were not drawn to screen.
- void DidCullForDrawing(const gfx::Transform& transform_to_target,
- gfx::Rect before_cull_rect,
- gfx::Rect after_cull_rect);
- // Record pixels that were drawn to screen.
- void DidDraw(const gfx::Transform& transform_to_target,
- gfx::Rect after_cull_rect,
- gfx::Rect opaque_rect);
-
- void RecordMetrics(const LayerTreeHost* layer_tree_host) const;
- void RecordMetrics(const LayerTreeHostImpl* layer_tree_host_impl) const;
-
- // Accessors for tests.
- float pixels_drawn_opaque() const { return pixels_drawn_opaque_; }
- float pixels_drawn_translucent() const { return pixels_drawn_translucent_; }
- float pixels_culled_for_drawing() const { return pixels_culled_for_drawing_; }
- float pixels_painted() const { return pixels_painted_; }
- float pixels_uploaded_opaque() const { return pixels_uploaded_opaque_; }
- float pixels_uploaded_translucent() const {
- return pixels_uploaded_translucent_;
- }
- int tiles_culled_for_upload() const { return tiles_culled_for_upload_; }
-
- private:
- enum MetricsType {
- UpdateAndCommit,
- DrawingToScreen
- };
-
- explicit OverdrawMetrics(bool record_metrics_for_frame);
-
- template <typename LayerTreeHostType>
- void RecordMetricsInternal(MetricsType metrics_type,
- const LayerTreeHostType* layer_tree_host) const;
-
- // When false this class is a giant no-op.
- bool record_metrics_for_frame_;
-
- // These values are used for saving metrics during update/commit.
-
- // Count of pixels that were painted due to invalidation.
- float pixels_painted_;
- // Count of pixels uploaded to textures and known to be opaque.
- float pixels_uploaded_opaque_;
- // Count of pixels uploaded to textures and not known to be opaque.
- float pixels_uploaded_translucent_;
- // Count of tiles that were invalidated but not uploaded.
- int tiles_culled_for_upload_;
- // Count the number of bytes in contents textures.
- uint64 contents_texture_use_bytes_;
- // Count the number of bytes in RenderSurfaceImpl textures.
- uint64 render_surface_texture_use_bytes_;
-
- // These values are used for saving metrics during draw.
-
- // Count of pixels that are opaque (and thus occlude). Ideally this is no more
- // than wiewport width x height.
- float pixels_drawn_opaque_;
- // Count of pixels that are possibly translucent, and cannot occlude.
- float pixels_drawn_translucent_;
- // Count of pixels not drawn as they are occluded by somthing opaque.
- float pixels_culled_for_drawing_;
-
- DISALLOW_COPY_AND_ASSIGN(OverdrawMetrics);
-};
-
-} // namespace cc
-
-#endif // CC_DEBUG_OVERDRAW_METRICS_H_
diff --git a/chromium/cc/debug/picture_record_benchmark.cc b/chromium/cc/debug/picture_record_benchmark.cc
index 430d1d0bcd9..a1528c36d7d 100644
--- a/chromium/cc/debug/picture_record_benchmark.cc
+++ b/chromium/cc/debug/picture_record_benchmark.cc
@@ -91,7 +91,7 @@ void PictureRecordBenchmark::RunOnLayer(PictureLayer* layer) {
ContentLayerClient* painter = layer->client();
gfx::Size content_bounds = layer->content_bounds();
- SkTileGridPicture::TileGridInfo tile_grid_info;
+ SkTileGridFactory::TileGridInfo tile_grid_info;
tile_grid_info.fTileInterval.set(kTileGridSize - 2 * kTileGridBorder,
kTileGridSize - 2 * kTileGridBorder);
tile_grid_info.fMargin.set(kTileGridBorder, kTileGridBorder);
@@ -110,8 +110,8 @@ void PictureRecordBenchmark::RunOnLayer(PictureLayer* layer) {
base::TimeTicks start = base::TimeTicks::HighResNow();
- scoped_refptr<Picture> picture = Picture::Create(rect);
- picture->Record(painter, tile_grid_info);
+ scoped_refptr<Picture> picture = Picture::Create(
+ rect, painter, tile_grid_info, false, 0, Picture::RECORD_NORMALLY);
base::TimeTicks end = base::TimeTicks::HighResNow();
base::TimeDelta duration = end - start;
diff --git a/chromium/cc/debug/rasterize_and_record_benchmark.cc b/chromium/cc/debug/rasterize_and_record_benchmark.cc
index 4646afd6bce..197fb291a05 100644
--- a/chromium/cc/debug/rasterize_and_record_benchmark.cc
+++ b/chromium/cc/debug/rasterize_and_record_benchmark.cc
@@ -6,9 +6,12 @@
#include <algorithm>
#include <limits>
+#include <string>
#include "base/basictypes.h"
+#include "base/strings/stringprintf.h"
#include "base/values.h"
+#include "cc/debug/lap_timer.h"
#include "cc/debug/rasterize_and_record_benchmark_impl.h"
#include "cc/layers/layer.h"
#include "cc/layers/picture_layer.h"
@@ -22,11 +25,8 @@ namespace {
const int kDefaultRecordRepeatCount = 100;
-base::TimeTicks Now() {
- return base::TimeTicks::IsThreadNowSupported()
- ? base::TimeTicks::ThreadNow()
- : base::TimeTicks::HighResNow();
-}
+const char* kModeSuffixes[Picture::RECORDING_MODE_COUNT] = {
+ "", "_sk_null_canvas", "_painting_disabled", "_skrecord"};
} // namespace
@@ -61,8 +61,12 @@ void RasterizeAndRecordBenchmark::DidUpdateLayers(LayerTreeHost* host) {
DCHECK(!results_.get());
results_ = make_scoped_ptr(new base::DictionaryValue);
results_->SetInteger("pixels_recorded", record_results_.pixels_recorded);
- results_->SetDouble("record_time_ms",
- record_results_.total_best_time.InMillisecondsF());
+
+ for (int i = 0; i < Picture::RECORDING_MODE_COUNT; i++) {
+ std::string name = base::StringPrintf("record_time%s_ms", kModeSuffixes[i]);
+ results_->SetDouble(name,
+ record_results_.total_best_time[i].InMillisecondsF());
+ }
main_thread_benchmark_done_ = true;
}
@@ -72,18 +76,9 @@ void RasterizeAndRecordBenchmark::RecordRasterResults(
base::DictionaryValue* results = NULL;
results_value->GetAsDictionary(&results);
-
DCHECK(results);
- DCHECK(results->HasKey("pixels_rasterized"));
- DCHECK(results->HasKey("rasterize_time_ms"));
-
- int pixels_rasterized;
- results->GetInteger("pixels_rasterized", &pixels_rasterized);
- double rasterize_time_ms;
- results->GetDouble("rasterize_time_ms", &rasterize_time_ms);
- results_->SetInteger("pixels_rasterized", pixels_rasterized);
- results_->SetDouble("rasterize_time_ms", rasterize_time_ms);
+ results_->MergeDictionary(results);
NotifyDone(results_.PassAs<base::Value>());
}
@@ -108,7 +103,7 @@ void RasterizeAndRecordBenchmark::RunOnLayer(PictureLayer* layer) {
DCHECK(host_);
gfx::Size tile_grid_size = host_->settings().default_tile_size;
- SkTileGridPicture::TileGridInfo tile_grid_info;
+ SkTileGridFactory::TileGridInfo tile_grid_info;
PicturePileBase::ComputeTileGridInfo(tile_grid_size, &tile_grid_info);
gfx::Rect visible_content_rect = gfx::ScaleToEnclosingRect(
@@ -116,22 +111,40 @@ void RasterizeAndRecordBenchmark::RunOnLayer(PictureLayer* layer) {
if (visible_content_rect.IsEmpty())
return;
- scoped_refptr<Picture> picture = Picture::Create(visible_content_rect);
-
- base::TimeDelta min_time =
- base::TimeDelta::FromInternalValue(std::numeric_limits<int64>::max());
- for (int i = 0; i < record_repeat_count_; ++i) {
- base::TimeTicks start = Now();
- picture->Record(painter, tile_grid_info);
- base::TimeTicks end = Now();
- base::TimeDelta duration = end - start;
- if (duration < min_time)
- min_time = duration;
+ for (int mode_index = 0; mode_index < Picture::RECORDING_MODE_COUNT;
+ mode_index++) {
+ Picture::RecordingMode mode =
+ static_cast<Picture::RecordingMode>(mode_index);
+ base::TimeDelta min_time = base::TimeDelta::Max();
+
+ // Parameters for LapTimer.
+ const int kTimeLimitMillis = 1;
+ const int kWarmupRuns = 0;
+ const int kTimeCheckInterval = 1;
+
+ for (int i = 0; i < record_repeat_count_; ++i) {
+ // Run for a minimum amount of time to avoid problems with timer
+ // quantization when the layer is very small.
+ LapTimer timer(kWarmupRuns,
+ base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
+ kTimeCheckInterval);
+ do {
+ scoped_refptr<Picture> picture = Picture::Create(
+ visible_content_rect, painter, tile_grid_info, false, 0, mode);
+ timer.NextLap();
+ } while (!timer.HasTimeLimitExpired());
+ base::TimeDelta duration =
+ base::TimeDelta::FromMillisecondsD(timer.MsPerLap());
+ if (duration < min_time)
+ min_time = duration;
+ }
+
+ if (mode == Picture::RECORD_NORMALLY) {
+ record_results_.pixels_recorded +=
+ visible_content_rect.width() * visible_content_rect.height();
+ }
+ record_results_.total_best_time[mode_index] += min_time;
}
-
- record_results_.pixels_recorded +=
- visible_content_rect.width() * visible_content_rect.height();
- record_results_.total_best_time += min_time;
}
RasterizeAndRecordBenchmark::RecordResults::RecordResults()
diff --git a/chromium/cc/debug/rasterize_and_record_benchmark.h b/chromium/cc/debug/rasterize_and_record_benchmark.h
index 2cea16a2f4e..e2942d4b3e2 100644
--- a/chromium/cc/debug/rasterize_and_record_benchmark.h
+++ b/chromium/cc/debug/rasterize_and_record_benchmark.h
@@ -12,6 +12,7 @@
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "cc/debug/micro_benchmark_controller.h"
+#include "cc/resources/picture.h"
namespace base {
class DictionaryValue;
@@ -45,7 +46,7 @@ class RasterizeAndRecordBenchmark : public MicroBenchmark {
~RecordResults();
int pixels_recorded;
- base::TimeDelta total_best_time;
+ base::TimeDelta total_best_time[Picture::RECORDING_MODE_COUNT];
};
RecordResults record_results_;
diff --git a/chromium/cc/debug/rasterize_and_record_benchmark_impl.cc b/chromium/cc/debug/rasterize_and_record_benchmark_impl.cc
index f2904a3bebf..a22c2cd4d28 100644
--- a/chromium/cc/debug/rasterize_and_record_benchmark_impl.cc
+++ b/chromium/cc/debug/rasterize_and_record_benchmark_impl.cc
@@ -9,8 +9,10 @@
#include "base/basictypes.h"
#include "base/values.h"
+#include "cc/debug/lap_timer.h"
#include "cc/layers/layer_impl.h"
#include "cc/layers/picture_layer_impl.h"
+#include "cc/resources/raster_worker_pool.h"
#include "cc/trees/layer_tree_host_common.h"
#include "cc/trees/layer_tree_host_impl.h"
#include "ui/gfx/rect.h"
@@ -21,11 +23,72 @@ namespace {
const int kDefaultRasterizeRepeatCount = 100;
-base::TimeTicks Now() {
- return base::TimeTicks::IsThreadNowSupported()
- ? base::TimeTicks::ThreadNow()
- : base::TimeTicks::HighResNow();
-}
+class BenchmarkRasterTask : public Task {
+ public:
+ BenchmarkRasterTask(PicturePileImpl* picture_pile,
+ const gfx::Rect& content_rect,
+ float contents_scale,
+ size_t repeat_count)
+ : picture_pile_(picture_pile),
+ content_rect_(content_rect),
+ contents_scale_(contents_scale),
+ repeat_count_(repeat_count),
+ is_solid_color_(false),
+ best_time_(base::TimeDelta::Max()) {}
+
+ // Overridden from Task:
+ virtual void RunOnWorkerThread() OVERRIDE {
+ PicturePileImpl* picture_pile = picture_pile_->GetCloneForDrawingOnThread(
+ RasterWorkerPool::GetPictureCloneIndexForCurrentThread());
+
+ // Parameters for LapTimer.
+ const int kTimeLimitMillis = 1;
+ const int kWarmupRuns = 0;
+ const int kTimeCheckInterval = 1;
+
+ for (size_t i = 0; i < repeat_count_; ++i) {
+ // Run for a minimum amount of time to avoid problems with timer
+ // quantization when the layer is very small.
+ LapTimer timer(kWarmupRuns,
+ base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
+ kTimeCheckInterval);
+ do {
+ SkBitmap bitmap;
+ bitmap.allocPixels(SkImageInfo::MakeN32Premul(content_rect_.width(),
+ content_rect_.height()));
+ SkCanvas canvas(bitmap);
+ PicturePileImpl::Analysis analysis;
+
+ picture_pile->AnalyzeInRect(
+ content_rect_, contents_scale_, &analysis, NULL);
+ picture_pile->RasterToBitmap(
+ &canvas, content_rect_, contents_scale_, NULL);
+
+ is_solid_color_ = analysis.is_solid_color;
+
+ timer.NextLap();
+ } while (!timer.HasTimeLimitExpired());
+ base::TimeDelta duration =
+ base::TimeDelta::FromMillisecondsD(timer.MsPerLap());
+ if (duration < best_time_)
+ best_time_ = duration;
+
+ }
+ }
+
+ bool IsSolidColor() const { return is_solid_color_; }
+ base::TimeDelta GetBestTime() const { return best_time_; }
+
+ private:
+ virtual ~BenchmarkRasterTask() {}
+
+ PicturePileImpl* picture_pile_;
+ gfx::Rect content_rect_;
+ float contents_scale_;
+ size_t repeat_count_;
+ bool is_solid_color_;
+ base::TimeDelta best_time_;
+};
} // namespace
@@ -54,20 +117,45 @@ void RasterizeAndRecordBenchmarkImpl::DidCompleteCommit(
base::Unretained(this)));
scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue());
- result->SetInteger("pixels_rasterized", rasterize_results_.pixels_rasterized);
result->SetDouble("rasterize_time_ms",
rasterize_results_.total_best_time.InMillisecondsF());
+ result->SetInteger("pixels_rasterized", rasterize_results_.pixels_rasterized);
+ result->SetInteger("pixels_rasterized_with_non_solid_color",
+ rasterize_results_.pixels_rasterized_with_non_solid_color);
+ result->SetInteger("pixels_rasterized_as_opaque",
+ rasterize_results_.pixels_rasterized_as_opaque);
+ result->SetInteger("total_layers", rasterize_results_.total_layers);
+ result->SetInteger("total_picture_layers",
+ rasterize_results_.total_picture_layers);
+ result->SetInteger("total_picture_layers_with_no_content",
+ rasterize_results_.total_picture_layers_with_no_content);
+ result->SetInteger("total_picture_layers_off_screen",
+ rasterize_results_.total_picture_layers_off_screen);
NotifyDone(result.PassAs<base::Value>());
}
void RasterizeAndRecordBenchmarkImpl::Run(LayerImpl* layer) {
+ rasterize_results_.total_layers++;
layer->RunMicroBenchmark(this);
}
void RasterizeAndRecordBenchmarkImpl::RunOnLayer(PictureLayerImpl* layer) {
- if (layer->visible_content_rect().IsEmpty())
+ rasterize_results_.total_picture_layers++;
+ if (!layer->DrawsContent()) {
+ rasterize_results_.total_picture_layers_with_no_content++;
+ return;
+ }
+ if (layer->visible_content_rect().IsEmpty()) {
+ rasterize_results_.total_picture_layers_off_screen++;
return;
+ }
+
+ TaskGraphRunner* task_graph_runner = RasterWorkerPool::GetTaskGraphRunner();
+ DCHECK(task_graph_runner);
+
+ if (!task_namespace_.IsValid())
+ task_namespace_ = task_graph_runner->GetNamespaceToken();
PictureLayerTilingSet tiling_set(layer, layer->content_bounds());
@@ -83,37 +171,51 @@ void RasterizeAndRecordBenchmarkImpl::RunOnLayer(PictureLayerImpl* layer) {
gfx::Rect content_rect = (*it)->content_rect();
float contents_scale = (*it)->contents_scale();
- base::TimeDelta min_time =
- base::TimeDelta::FromInternalValue(std::numeric_limits<int64>::max());
- for (int i = 0; i < rasterize_repeat_count_; ++i) {
- SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config,
- content_rect.width(),
- content_rect.height());
- bitmap.allocPixels();
-
- SkBitmapDevice device(bitmap);
- SkCanvas canvas(&device);
- PicturePileImpl::Analysis analysis;
-
- base::TimeTicks start = Now();
- picture_pile->AnalyzeInRect(
- content_rect, contents_scale, &analysis, NULL);
- picture_pile->RasterToBitmap(&canvas, content_rect, contents_scale, NULL);
- base::TimeTicks end = Now();
- base::TimeDelta duration = end - start;
- if (duration < min_time)
- min_time = duration;
+ scoped_refptr<BenchmarkRasterTask> benchmark_raster_task(
+ new BenchmarkRasterTask(picture_pile,
+ content_rect,
+ contents_scale,
+ rasterize_repeat_count_));
+
+ TaskGraph graph;
+
+ graph.nodes.push_back(
+ TaskGraph::Node(benchmark_raster_task,
+ RasterWorkerPool::kBenchmarkRasterTaskPriority,
+ 0u));
+
+ task_graph_runner->ScheduleTasks(task_namespace_, &graph);
+ task_graph_runner->WaitForTasksToFinishRunning(task_namespace_);
+
+ Task::Vector completed_tasks;
+ task_graph_runner->CollectCompletedTasks(task_namespace_, &completed_tasks);
+ DCHECK_EQ(1u, completed_tasks.size());
+ DCHECK_EQ(completed_tasks[0], benchmark_raster_task);
+
+ int tile_size = content_rect.width() * content_rect.height();
+ base::TimeDelta min_time = benchmark_raster_task->GetBestTime();
+ bool is_solid_color = benchmark_raster_task->IsSolidColor();
+
+ if (layer->contents_opaque())
+ rasterize_results_.pixels_rasterized_as_opaque += tile_size;
+
+ if (!is_solid_color) {
+ rasterize_results_.pixels_rasterized_with_non_solid_color += tile_size;
}
- rasterize_results_.pixels_rasterized +=
- content_rect.width() * content_rect.height();
+ rasterize_results_.pixels_rasterized += tile_size;
rasterize_results_.total_best_time += min_time;
}
}
RasterizeAndRecordBenchmarkImpl::RasterizeResults::RasterizeResults()
- : pixels_rasterized(0) {}
+ : pixels_rasterized(0),
+ pixels_rasterized_with_non_solid_color(0),
+ pixels_rasterized_as_opaque(0),
+ total_layers(0),
+ total_picture_layers(0),
+ total_picture_layers_with_no_content(0),
+ total_picture_layers_off_screen(0) {}
RasterizeAndRecordBenchmarkImpl::RasterizeResults::~RasterizeResults() {}
diff --git a/chromium/cc/debug/rasterize_and_record_benchmark_impl.h b/chromium/cc/debug/rasterize_and_record_benchmark_impl.h
index 0f9de9ba4f4..cceef051698 100644
--- a/chromium/cc/debug/rasterize_and_record_benchmark_impl.h
+++ b/chromium/cc/debug/rasterize_and_record_benchmark_impl.h
@@ -11,6 +11,7 @@
#include "base/time/time.h"
#include "cc/debug/micro_benchmark_impl.h"
+#include "cc/resources/task_graph_runner.h"
namespace cc {
@@ -37,11 +38,18 @@ class RasterizeAndRecordBenchmarkImpl : public MicroBenchmarkImpl {
~RasterizeResults();
int pixels_rasterized;
+ int pixels_rasterized_with_non_solid_color;
+ int pixels_rasterized_as_opaque;
base::TimeDelta total_best_time;
+ int total_layers;
+ int total_picture_layers;
+ int total_picture_layers_with_no_content;
+ int total_picture_layers_off_screen;
};
RasterizeResults rasterize_results_;
int rasterize_repeat_count_;
+ NamespaceToken task_namespace_;
};
} // namespace cc
diff --git a/chromium/cc/debug/rendering_stats.cc b/chromium/cc/debug/rendering_stats.cc
index abce5ae562b..3e123b667c7 100644
--- a/chromium/cc/debug/rendering_stats.cc
+++ b/chromium/cc/debug/rendering_stats.cc
@@ -33,7 +33,10 @@ void MainThreadRenderingStats::Add(const MainThreadRenderingStats& other) {
ImplThreadRenderingStats::ImplThreadRenderingStats()
: frame_count(0),
- rasterized_pixel_count(0) {}
+ rasterized_pixel_count(0),
+ visible_content_area(0),
+ approximated_visible_content_area(0) {
+}
scoped_refptr<base::debug::ConvertableToTraceFormat>
ImplThreadRenderingStats::AsTraceableData() const {
@@ -41,6 +44,9 @@ ImplThreadRenderingStats::AsTraceableData() const {
record_data->SetInteger("frame_count", frame_count);
record_data->SetDouble("rasterize_time", rasterize_time.InSecondsF());
record_data->SetInteger("rasterized_pixel_count", rasterized_pixel_count);
+ record_data->SetInteger("visible_content_area", visible_content_area);
+ record_data->SetInteger("approximated_visible_content_area",
+ approximated_visible_content_area);
return TracedValue::FromValue(record_data.release());
}
@@ -49,26 +55,8 @@ void ImplThreadRenderingStats::Add(const ImplThreadRenderingStats& other) {
rasterize_time += other.rasterize_time;
analysis_time += other.analysis_time;
rasterized_pixel_count += other.rasterized_pixel_count;
-}
-
-void RenderingStats::EnumerateFields(Enumerator* enumerator) const {
- enumerator->AddInt64("frameCount",
- main_stats.frame_count + impl_stats.frame_count);
- enumerator->AddDouble("paintTime",
- main_stats.paint_time.InSecondsF());
- enumerator->AddInt64("paintedPixelCount",
- main_stats.painted_pixel_count);
- enumerator->AddDouble("recordTime",
- main_stats.record_time.InSecondsF());
- enumerator->AddInt64("recordedPixelCount",
- main_stats.recorded_pixel_count);
- // Combine rasterization and analysis time as a precursor to combining
- // them in the same step internally.
- enumerator->AddDouble("rasterizeTime",
- impl_stats.rasterize_time.InSecondsF() +
- impl_stats.analysis_time.InSecondsF());
- enumerator->AddInt64("rasterizedPixelCount",
- impl_stats.rasterized_pixel_count);
+ visible_content_area += other.visible_content_area;
+ approximated_visible_content_area += other.approximated_visible_content_area;
}
void RenderingStats::Add(const RenderingStats& other) {
diff --git a/chromium/cc/debug/rendering_stats.h b/chromium/cc/debug/rendering_stats.h
index d28f1107157..bd3b7c72442 100644
--- a/chromium/cc/debug/rendering_stats.h
+++ b/chromium/cc/debug/rendering_stats.h
@@ -12,22 +12,6 @@
namespace cc {
-// In conjunction with EnumerateFields, this allows the embedder to
-// enumerate the values in this structure without
-// having to embed references to its specific member variables. This
-// simplifies the addition of new fields to this type.
-class RenderingStatsEnumerator {
- public:
- virtual void AddInt64(const char* name, int64 value) = 0;
- virtual void AddDouble(const char* name, double value) = 0;
- virtual void AddInt(const char* name, int value) = 0;
- virtual void AddTimeDeltaInSecondsF(const char* name,
- const base::TimeDelta& value) = 0;
-
- protected:
- virtual ~RenderingStatsEnumerator() {}
-};
-
struct CC_EXPORT MainThreadRenderingStats {
// Note: when adding new members, please remember to update EnumerateFields
// and Add in rendering_stats.cc.
@@ -51,6 +35,8 @@ struct CC_EXPORT ImplThreadRenderingStats {
base::TimeDelta rasterize_time;
base::TimeDelta analysis_time;
int64 rasterized_pixel_count;
+ int64 visible_content_area;
+ int64 approximated_visible_content_area;
ImplThreadRenderingStats();
scoped_refptr<base::debug::ConvertableToTraceFormat> AsTraceableData() const;
@@ -58,14 +44,9 @@ struct CC_EXPORT ImplThreadRenderingStats {
};
struct CC_EXPORT RenderingStats {
- typedef RenderingStatsEnumerator Enumerator;
-
MainThreadRenderingStats main_stats;
ImplThreadRenderingStats impl_stats;
- // Outputs the fields in this structure to the provided enumerator.
- void EnumerateFields(Enumerator* enumerator) const;
-
// Add fields of |other| to the fields in this structure.
void Add(const RenderingStats& other);
};
diff --git a/chromium/cc/debug/rendering_stats_instrumentation.cc b/chromium/cc/debug/rendering_stats_instrumentation.cc
index 63840a35f74..9655241c639 100644
--- a/chromium/cc/debug/rendering_stats_instrumentation.cc
+++ b/chromium/cc/debug/rendering_stats_instrumentation.cc
@@ -18,24 +18,38 @@ RenderingStatsInstrumentation::RenderingStatsInstrumentation()
RenderingStatsInstrumentation::~RenderingStatsInstrumentation() {}
+MainThreadRenderingStats
+RenderingStatsInstrumentation::main_thread_rendering_stats() {
+ base::AutoLock scoped_lock(lock_);
+ return main_thread_rendering_stats_;
+}
+
+ImplThreadRenderingStats
+RenderingStatsInstrumentation::impl_thread_rendering_stats() {
+ base::AutoLock scoped_lock(lock_);
+ return impl_thread_rendering_stats_;
+}
+
RenderingStats RenderingStatsInstrumentation::GetRenderingStats() {
base::AutoLock scoped_lock(lock_);
RenderingStats rendering_stats;
- rendering_stats.main_stats = main_stats_accu_;
- rendering_stats.main_stats.Add(main_stats_);
- rendering_stats.impl_stats = impl_stats_accu_;
- rendering_stats.impl_stats.Add(impl_stats_);
+ rendering_stats.main_stats = main_thread_rendering_stats_accu_;
+ rendering_stats.main_stats.Add(main_thread_rendering_stats_);
+ rendering_stats.impl_stats = impl_thread_rendering_stats_accu_;
+ rendering_stats.impl_stats.Add(impl_thread_rendering_stats_);
return rendering_stats;
}
void RenderingStatsInstrumentation::AccumulateAndClearMainThreadStats() {
- main_stats_accu_.Add(main_stats_);
- main_stats_ = MainThreadRenderingStats();
+ base::AutoLock scoped_lock(lock_);
+ main_thread_rendering_stats_accu_.Add(main_thread_rendering_stats_);
+ main_thread_rendering_stats_ = MainThreadRenderingStats();
}
void RenderingStatsInstrumentation::AccumulateAndClearImplThreadStats() {
- impl_stats_accu_.Add(impl_stats_);
- impl_stats_ = ImplThreadRenderingStats();
+ base::AutoLock scoped_lock(lock_);
+ impl_thread_rendering_stats_accu_.Add(impl_thread_rendering_stats_);
+ impl_thread_rendering_stats_ = ImplThreadRenderingStats();
}
base::TimeTicks RenderingStatsInstrumentation::StartRecording() const {
@@ -64,9 +78,9 @@ void RenderingStatsInstrumentation::IncrementFrameCount(int64 count,
base::AutoLock scoped_lock(lock_);
if (main_thread)
- main_stats_.frame_count += count;
+ main_thread_rendering_stats_.frame_count += count;
else
- impl_stats_.frame_count += count;
+ impl_thread_rendering_stats_.frame_count += count;
}
void RenderingStatsInstrumentation::AddPaint(base::TimeDelta duration,
@@ -75,8 +89,8 @@ void RenderingStatsInstrumentation::AddPaint(base::TimeDelta duration,
return;
base::AutoLock scoped_lock(lock_);
- main_stats_.paint_time += duration;
- main_stats_.painted_pixel_count += pixels;
+ main_thread_rendering_stats_.paint_time += duration;
+ main_thread_rendering_stats_.painted_pixel_count += pixels;
}
void RenderingStatsInstrumentation::AddRecord(base::TimeDelta duration,
@@ -85,8 +99,8 @@ void RenderingStatsInstrumentation::AddRecord(base::TimeDelta duration,
return;
base::AutoLock scoped_lock(lock_);
- main_stats_.record_time += duration;
- main_stats_.recorded_pixel_count += pixels;
+ main_thread_rendering_stats_.record_time += duration;
+ main_thread_rendering_stats_.recorded_pixel_count += pixels;
}
void RenderingStatsInstrumentation::AddRaster(base::TimeDelta duration,
@@ -95,8 +109,8 @@ void RenderingStatsInstrumentation::AddRaster(base::TimeDelta duration,
return;
base::AutoLock scoped_lock(lock_);
- impl_stats_.rasterize_time += duration;
- impl_stats_.rasterized_pixel_count += pixels;
+ impl_thread_rendering_stats_.rasterize_time += duration;
+ impl_thread_rendering_stats_.rasterized_pixel_count += pixels;
}
void RenderingStatsInstrumentation::AddAnalysis(base::TimeDelta duration,
@@ -105,7 +119,24 @@ void RenderingStatsInstrumentation::AddAnalysis(base::TimeDelta duration,
return;
base::AutoLock scoped_lock(lock_);
- impl_stats_.analysis_time += duration;
+ impl_thread_rendering_stats_.analysis_time += duration;
+}
+
+void RenderingStatsInstrumentation::AddVisibleContentArea(int64 area) {
+ if (!record_rendering_stats_)
+ return;
+
+ base::AutoLock scoped_lock(lock_);
+ impl_thread_rendering_stats_.visible_content_area += area;
+}
+
+void RenderingStatsInstrumentation::AddApproximatedVisibleContentArea(
+ int64 area) {
+ if (!record_rendering_stats_)
+ return;
+
+ base::AutoLock scoped_lock(lock_);
+ impl_thread_rendering_stats_.approximated_visible_content_area += area;
}
} // namespace cc
diff --git a/chromium/cc/debug/rendering_stats_instrumentation.h b/chromium/cc/debug/rendering_stats_instrumentation.h
index 68117557e7d..664013186cd 100644
--- a/chromium/cc/debug/rendering_stats_instrumentation.h
+++ b/chromium/cc/debug/rendering_stats_instrumentation.h
@@ -18,20 +18,19 @@ class CC_EXPORT RenderingStatsInstrumentation {
static scoped_ptr<RenderingStatsInstrumentation> Create();
virtual ~RenderingStatsInstrumentation();
- // Return current main thread rendering stats.
- const MainThreadRenderingStats& main_thread_rendering_stats() {
- return main_stats_;
- }
- // Return current impl thread rendering stats.
- const ImplThreadRenderingStats& impl_thread_rendering_stats() {
- return impl_stats_;
- }
+ // Return copy of current main thread rendering stats.
+ MainThreadRenderingStats main_thread_rendering_stats();
+
+ // Return copy of current impl thread rendering stats.
+ ImplThreadRenderingStats impl_thread_rendering_stats();
+
// Return the accumulated, combined rendering stats.
RenderingStats GetRenderingStats();
// Add current main thread rendering stats to accumulator and
// clear current stats.
void AccumulateAndClearMainThreadStats();
+
// Add current impl thread rendering stats to accumulator and
// clear current stats.
void AccumulateAndClearImplThreadStats();
@@ -53,16 +52,17 @@ class CC_EXPORT RenderingStatsInstrumentation {
void AddRecord(base::TimeDelta duration, int64 pixels);
void AddRaster(base::TimeDelta duration, int64 pixels);
void AddAnalysis(base::TimeDelta duration, int64 pixels);
+ void AddVisibleContentArea(int64 area);
+ void AddApproximatedVisibleContentArea(int64 area);
protected:
RenderingStatsInstrumentation();
private:
- // TODO(ernstm): rename to *_thread_rendering_stats_*
- MainThreadRenderingStats main_stats_;
- MainThreadRenderingStats main_stats_accu_;
- ImplThreadRenderingStats impl_stats_;
- ImplThreadRenderingStats impl_stats_accu_;
+ MainThreadRenderingStats main_thread_rendering_stats_;
+ MainThreadRenderingStats main_thread_rendering_stats_accu_;
+ ImplThreadRenderingStats impl_thread_rendering_stats_;
+ ImplThreadRenderingStats impl_thread_rendering_stats_accu_;
bool record_rendering_stats_;
diff --git a/chromium/cc/debug/traced_picture.cc b/chromium/cc/debug/traced_picture.cc
index 143f0b87adb..89d988fec93 100644
--- a/chromium/cc/debug/traced_picture.cc
+++ b/chromium/cc/debug/traced_picture.cc
@@ -11,22 +11,20 @@
namespace cc {
-TracedPicture::TracedPicture(scoped_refptr<Picture> picture)
- : picture_(picture),
- is_alias_(false) {
-}
+TracedPicture::TracedPicture(scoped_refptr<const Picture> picture)
+ : picture_(picture), is_alias_(false) {}
TracedPicture::~TracedPicture() {
}
scoped_refptr<base::debug::ConvertableToTraceFormat>
- TracedPicture::AsTraceablePicture(Picture* picture) {
+TracedPicture::AsTraceablePicture(const Picture* picture) {
return scoped_refptr<base::debug::ConvertableToTraceFormat>(
new TracedPicture(picture));
}
scoped_refptr<base::debug::ConvertableToTraceFormat>
- TracedPicture::AsTraceablePictureAlias(Picture* original) {
+TracedPicture::AsTraceablePictureAlias(const Picture* original) {
scoped_refptr<TracedPicture> ptr = new TracedPicture(original);
ptr->is_alias_ = true;
return scoped_refptr<base::debug::ConvertableToTraceFormat>(ptr);
diff --git a/chromium/cc/debug/traced_picture.h b/chromium/cc/debug/traced_picture.h
index cc212ceed82..638f00bb7dd 100644
--- a/chromium/cc/debug/traced_picture.h
+++ b/chromium/cc/debug/traced_picture.h
@@ -15,13 +15,13 @@ namespace cc {
class TracedPicture : public base::debug::ConvertableToTraceFormat {
public:
- explicit TracedPicture(scoped_refptr<Picture>);
+ explicit TracedPicture(scoped_refptr<const Picture>);
static scoped_refptr<base::debug::ConvertableToTraceFormat>
- AsTraceablePicture(Picture* picture);
+ AsTraceablePicture(const Picture* picture);
static scoped_refptr<base::debug::ConvertableToTraceFormat>
- AsTraceablePictureAlias(Picture* original);
+ AsTraceablePictureAlias(const Picture* original);
virtual void AppendAsTraceFormat(std::string* out) const OVERRIDE;
@@ -31,7 +31,7 @@ class TracedPicture : public base::debug::ConvertableToTraceFormat {
void AppendPicture(std::string* out) const;
void AppendPictureAlias(std::string* out) const;
- scoped_refptr<Picture> picture_;
+ scoped_refptr<const Picture> picture_;
bool is_alias_;
DISALLOW_COPY_AND_ASSIGN(TracedPicture);
diff --git a/chromium/cc/debug/traced_value.cc b/chromium/cc/debug/traced_value.cc
index 5a324148725..3b506ae7e37 100644
--- a/chromium/cc/debug/traced_value.cc
+++ b/chromium/cc/debug/traced_value.cc
@@ -30,6 +30,17 @@ void TracedValue::MakeDictIntoImplicitSnapshotWithCategory(
MakeDictIntoImplicitSnapshot(dict, object_name, id);
}
+void TracedValue::MakeDictIntoImplicitSnapshotWithCategory(
+ const char* category,
+ base::DictionaryValue* dict,
+ const char* object_base_type_name,
+ const char* object_name,
+ const void* id) {
+ dict->SetString("cat", category);
+ dict->SetString("base_type", object_base_type_name);
+ MakeDictIntoImplicitSnapshot(dict, object_name, id);
+}
+
scoped_refptr<base::debug::ConvertableToTraceFormat> TracedValue::FromValue(
base::Value* value) {
return scoped_refptr<base::debug::ConvertableToTraceFormat>(
diff --git a/chromium/cc/debug/traced_value.h b/chromium/cc/debug/traced_value.h
index fe17695a45c..560eaf8307b 100644
--- a/chromium/cc/debug/traced_value.h
+++ b/chromium/cc/debug/traced_value.h
@@ -26,6 +26,12 @@ class TracedValue : public base::debug::ConvertableToTraceFormat {
base::DictionaryValue* dict,
const char* object_name,
const void* id);
+ static void MakeDictIntoImplicitSnapshotWithCategory(
+ const char* category,
+ base::DictionaryValue* dict,
+ const char* object_base_type_name,
+ const char* object_name,
+ const void* id);
static scoped_refptr<base::debug::ConvertableToTraceFormat> FromValue(
base::Value* value);
@@ -40,6 +46,17 @@ class TracedValue : public base::debug::ConvertableToTraceFormat {
DISALLOW_COPY_AND_ASSIGN(TracedValue);
};
+template <class T>
+static scoped_refptr<base::debug::ConvertableToTraceFormat> ToTrace(T* t) {
+ return TracedValue::FromValue(t->AsValue().release());
+}
+
+template <class T>
+static scoped_refptr<base::debug::ConvertableToTraceFormat> ToTrace(
+ const T& t) {
+ return ToTrace(&t);
+}
+
} // namespace cc
#endif // CC_DEBUG_TRACED_VALUE_H_
diff --git a/chromium/cc/debug/unittest_only_benchmark.cc b/chromium/cc/debug/unittest_only_benchmark.cc
index 9c6b17699e3..0f0694ad9df 100644
--- a/chromium/cc/debug/unittest_only_benchmark.cc
+++ b/chromium/cc/debug/unittest_only_benchmark.cc
@@ -36,6 +36,18 @@ void UnittestOnlyBenchmark::DidUpdateLayers(LayerTreeHost* host) {
NotifyDone(scoped_ptr<base::Value>());
}
+bool UnittestOnlyBenchmark::ProcessMessage(scoped_ptr<base::Value> value) {
+ base::DictionaryValue* message = NULL;
+ value->GetAsDictionary(&message);
+ bool can_handle;
+ if (message->HasKey("can_handle")) {
+ message->GetBoolean("can_handle", &can_handle);
+ if (can_handle)
+ return true;
+ }
+ return false;
+}
+
void UnittestOnlyBenchmark::RecordImplResults(scoped_ptr<base::Value> results) {
NotifyDone(results.Pass());
}
diff --git a/chromium/cc/debug/unittest_only_benchmark.h b/chromium/cc/debug/unittest_only_benchmark.h
index 83312859644..8b2c8159b22 100644
--- a/chromium/cc/debug/unittest_only_benchmark.h
+++ b/chromium/cc/debug/unittest_only_benchmark.h
@@ -17,6 +17,7 @@ class CC_EXPORT UnittestOnlyBenchmark : public MicroBenchmark {
virtual ~UnittestOnlyBenchmark();
virtual void DidUpdateLayers(LayerTreeHost* host) OVERRIDE;
+ virtual bool ProcessMessage(scoped_ptr<base::Value> value) OVERRIDE;
protected:
virtual scoped_ptr<MicroBenchmarkImpl> CreateBenchmarkImpl(
@@ -32,4 +33,3 @@ class CC_EXPORT UnittestOnlyBenchmark : public MicroBenchmark {
} // namespace cc
#endif // CC_DEBUG_UNITTEST_ONLY_BENCHMARK_H_
-
diff --git a/chromium/cc/input/input_handler.h b/chromium/cc/input/input_handler.h
index fde89d265d6..7f35ddabb1e 100644
--- a/chromium/cc/input/input_handler.h
+++ b/chromium/cc/input/input_handler.h
@@ -24,12 +24,6 @@ namespace cc {
class LayerScrollOffsetDelegate;
-struct DidOverscrollParams {
- gfx::Vector2dF accumulated_overscroll;
- gfx::Vector2dF latest_overscroll_delta;
- gfx::Vector2dF current_fling_velocity;
-};
-
class CC_EXPORT InputHandlerClient {
public:
virtual ~InputHandlerClient() {}
@@ -41,7 +35,8 @@ class CC_EXPORT InputHandlerClient {
// Called when scroll deltas reaching the root scrolling layer go unused.
// The accumulated overscroll is scoped by the most recent call to
// InputHandler::ScrollBegin.
- virtual void DidOverscroll(const DidOverscrollParams& params) = 0;
+ virtual void DidOverscroll(const gfx::Vector2dF& accumulated_overscroll,
+ const gfx::Vector2dF& latest_overscroll_delta) = 0;
protected:
InputHandlerClient() {}
@@ -56,7 +51,16 @@ class CC_EXPORT InputHandlerClient {
// interface and bind it to the handler on the compositor thread.
class CC_EXPORT InputHandler {
public:
- enum ScrollStatus { ScrollOnMainThread, ScrollStarted, ScrollIgnored };
+ // Note these are used in a histogram. Do not reorder or delete existing
+ // entries.
+ enum ScrollStatus {
+ ScrollOnMainThread = 0,
+ ScrollStarted,
+ ScrollIgnored,
+ ScrollUnknown,
+ // This must be the last entry.
+ ScrollStatusCount
+ };
enum ScrollInputType { Gesture, Wheel, NonBubblingGesture };
// Binds a client to this handler to receive notifications. Only one client
@@ -69,7 +73,7 @@ class CC_EXPORT InputHandler {
// can be scrolled, ScrollOnMainThread if the scroll event should instead be
// delegated to the main thread, or ScrollIgnored if there is nothing to be
// scrolled at the given coordinates.
- virtual ScrollStatus ScrollBegin(gfx::Point viewport_point,
+ virtual ScrollStatus ScrollBegin(const gfx::Point& viewport_point,
ScrollInputType type) = 0;
// Scroll the selected layer starting at the given position. If the scroll
@@ -84,20 +88,17 @@ class CC_EXPORT InputHandler {
// the root overscroll accumulated within this ScrollBegin() scope is reported
// to the client.
// Should only be called if ScrollBegin() returned ScrollStarted.
- virtual bool ScrollBy(gfx::Point viewport_point,
- gfx::Vector2dF scroll_delta) = 0;
+ virtual bool ScrollBy(const gfx::Point& viewport_point,
+ const gfx::Vector2dF& scroll_delta) = 0;
- virtual bool ScrollVerticallyByPage(
- gfx::Point viewport_point,
- ScrollDirection direction) = 0;
+ virtual bool ScrollVerticallyByPage(const gfx::Point& viewport_point,
+ ScrollDirection direction) = 0;
// Returns ScrollStarted if a layer was being actively being scrolled,
// ScrollIgnored if not.
virtual ScrollStatus FlingScrollBegin() = 0;
- virtual void NotifyCurrentFlingVelocity(gfx::Vector2dF velocity) = 0;
-
- virtual void MouseMoveAt(gfx::Point mouse_position) = 0;
+ virtual void MouseMoveAt(const gfx::Point& mouse_position) = 0;
// Stop scrolling the selected layer. Should only be called if ScrollBegin()
// returned ScrollStarted.
@@ -114,18 +115,23 @@ class CC_EXPORT InputHandler {
virtual void OnRootLayerDelegatedScrollOffsetChanged() = 0;
virtual void PinchGestureBegin() = 0;
- virtual void PinchGestureUpdate(float magnify_delta, gfx::Point anchor) = 0;
+ virtual void PinchGestureUpdate(float magnify_delta,
+ const gfx::Point& anchor) = 0;
virtual void PinchGestureEnd() = 0;
- virtual void StartPageScaleAnimation(gfx::Vector2d target_offset,
+ virtual void StartPageScaleAnimation(const gfx::Vector2d& target_offset,
bool anchor_point,
float page_scale,
base::TimeDelta duration) = 0;
// Request another callback to InputHandlerClient::Animate().
- virtual void ScheduleAnimation() = 0;
+ virtual void SetNeedsAnimate() = 0;
+
+ // Whether the layer under |viewport_point| is the currently scrolling layer.
+ virtual bool IsCurrentlyScrollingLayerAt(const gfx::Point& viewport_point,
+ ScrollInputType type) = 0;
- virtual bool HaveTouchEventHandlersAt(gfx::Point viewport_point) = 0;
+ virtual bool HaveTouchEventHandlersAt(const gfx::Point& viewport_point) = 0;
// Calling CreateLatencyInfoSwapPromiseMonitor() to get a scoped
// LatencyInfoSwapPromiseMonitor. During the life time of the
diff --git a/chromium/cc/input/layer_scroll_offset_delegate.h b/chromium/cc/input/layer_scroll_offset_delegate.h
index 54a11c9e2bd..ba11c3839dd 100644
--- a/chromium/cc/input/layer_scroll_offset_delegate.h
+++ b/chromium/cc/input/layer_scroll_offset_delegate.h
@@ -17,14 +17,6 @@ namespace cc {
// The LayerScrollOffsetDelegate is only used on the impl thread.
class LayerScrollOffsetDelegate {
public:
- // This is called by the compositor to notify the delegate what is the upper
- // total scroll offset bound.
- virtual void SetMaxScrollOffset(gfx::Vector2dF max_scroll_offset) = 0;
-
- // This is called by the compositor when the scroll offset of the layer would
- // have otherwise changed.
- virtual void SetTotalScrollOffset(gfx::Vector2dF new_value) = 0;
-
// This is called by the compositor to query the current scroll offset of the
// layer.
// There is no requirement that the return values of this method are
@@ -34,18 +26,25 @@ class LayerScrollOffsetDelegate {
// more than the value passed to the most recent SetMaxScrollOffset call.
virtual gfx::Vector2dF GetTotalScrollOffset() = 0;
+ // This is called by the compositor to notify the delegate of any change to
+ // the following parameters:
+ // |total_scroll_offset| current scroll offset of the root layer,
+ // |max_scroll_offset| total scroll offset upper bound for the root layer,
+ // |scrollable_size| root layer scrollable size,
+ // |page_scale_factor| current page scale,
+ // |min_page_scale_factor| page scale lower limit,
+ // |max_page_scale_factor| page scale upper limit.
+ virtual void UpdateRootLayerState(const gfx::Vector2dF& total_scroll_offset,
+ const gfx::Vector2dF& max_scroll_offset,
+ const gfx::SizeF& scrollable_size,
+ float page_scale_factor,
+ float min_page_scale_factor,
+ float max_page_scale_factor) = 0;
+
// This is called by the compositor to check whether a delegate-managed fling
// is active or not.
virtual bool IsExternalFlingActive() const = 0;
- // This is called by the compositor to notify the delegate what is the current
- // page scale factor is.
- virtual void SetTotalPageScaleFactor(float page_scale_factor) = 0;
-
- // This is called by the compositor to notify the delegate what is the layer's
- // scrollable size is.
- virtual void SetScrollableSize(gfx::SizeF scrollable_size) = 0;
-
protected:
LayerScrollOffsetDelegate() {}
virtual ~LayerScrollOffsetDelegate() {}
diff --git a/chromium/cc/input/page_scale_animation.cc b/chromium/cc/input/page_scale_animation.cc
index 2b7d84c1f54..23bf21bc917 100644
--- a/chromium/cc/input/page_scale_animation.cc
+++ b/chromium/cc/input/page_scale_animation.cc
@@ -16,22 +16,22 @@ namespace {
// This takes a viewport-relative vector and returns a vector whose values are
// between 0 and 1, representing the percentage position within the viewport.
-gfx::Vector2dF NormalizeFromViewport(gfx::Vector2dF denormalized,
- gfx::SizeF viewport_size) {
+gfx::Vector2dF NormalizeFromViewport(const gfx::Vector2dF& denormalized,
+ const gfx::SizeF& viewport_size) {
return gfx::ScaleVector2d(denormalized,
1.f / viewport_size.width(),
1.f / viewport_size.height());
}
-gfx::Vector2dF DenormalizeToViewport(gfx::Vector2dF normalized,
- gfx::SizeF viewport_size) {
+gfx::Vector2dF DenormalizeToViewport(const gfx::Vector2dF& normalized,
+ const gfx::SizeF& viewport_size) {
return gfx::ScaleVector2d(normalized,
viewport_size.width(),
viewport_size.height());
}
-gfx::Vector2dF InterpolateBetween(gfx::Vector2dF start,
- gfx::Vector2dF end,
+gfx::Vector2dF InterpolateBetween(const gfx::Vector2dF& start,
+ const gfx::Vector2dF& end,
float interp) {
return start + gfx::ScaleVector2d(end - start, interp);
}
@@ -40,11 +40,14 @@ gfx::Vector2dF InterpolateBetween(gfx::Vector2dF start,
namespace cc {
+using base::TimeTicks;
+using base::TimeDelta;
+
scoped_ptr<PageScaleAnimation> PageScaleAnimation::Create(
- gfx::Vector2dF start_scroll_offset,
+ const gfx::Vector2dF& start_scroll_offset,
float start_page_scale_factor,
- gfx::SizeF viewport_size,
- gfx::SizeF root_layer_size,
+ const gfx::SizeF& viewport_size,
+ const gfx::SizeF& root_layer_size,
scoped_ptr<TimingFunction> timing_function) {
return make_scoped_ptr(new PageScaleAnimation(start_scroll_offset,
start_page_scale_factor,
@@ -54,10 +57,10 @@ scoped_ptr<PageScaleAnimation> PageScaleAnimation::Create(
}
PageScaleAnimation::PageScaleAnimation(
- gfx::Vector2dF start_scroll_offset,
+ const gfx::Vector2dF& start_scroll_offset,
float start_page_scale_factor,
- gfx::SizeF viewport_size,
- gfx::SizeF root_layer_size,
+ const gfx::SizeF& viewport_size,
+ const gfx::SizeF& root_layer_size,
scoped_ptr<TimingFunction> timing_function)
: start_page_scale_factor_(start_page_scale_factor),
target_page_scale_factor_(0.f),
@@ -66,19 +69,18 @@ PageScaleAnimation::PageScaleAnimation(
target_anchor_(),
viewport_size_(viewport_size),
root_layer_size_(root_layer_size),
- start_time_(-1.0),
- duration_(0.0),
- timing_function_(timing_function.Pass()) {}
+ timing_function_(timing_function.Pass()) {
+}
PageScaleAnimation::~PageScaleAnimation() {}
-void PageScaleAnimation::ZoomTo(gfx::Vector2dF target_scroll_offset,
+void PageScaleAnimation::ZoomTo(const gfx::Vector2dF& target_scroll_offset,
float target_page_scale_factor,
double duration) {
target_page_scale_factor_ = target_page_scale_factor;
target_scroll_offset_ = target_scroll_offset;
ClampTargetScrollOffset();
- duration_ = duration;
+ duration_ = TimeDelta::FromSecondsD(duration);
if (start_page_scale_factor_ == target_page_scale_factor) {
start_anchor_ = start_scroll_offset_;
@@ -92,12 +94,12 @@ void PageScaleAnimation::ZoomTo(gfx::Vector2dF target_scroll_offset,
start_anchor_ = target_anchor_;
}
-void PageScaleAnimation::ZoomWithAnchor(gfx::Vector2dF anchor,
+void PageScaleAnimation::ZoomWithAnchor(const gfx::Vector2dF& anchor,
float target_page_scale_factor,
double duration) {
start_anchor_ = anchor;
target_page_scale_factor_ = target_page_scale_factor;
- duration_ = duration;
+ duration_ = TimeDelta::FromSecondsD(duration);
// We start zooming out from the anchor tapped by the user. But if
// the target scale is impossible to attain without hitting the root layer
@@ -163,36 +165,37 @@ gfx::SizeF PageScaleAnimation::ViewportSizeAt(float interp) const {
}
bool PageScaleAnimation::IsAnimationStarted() const {
- return start_time_ >= 0;
+ return start_time_ > base::TimeTicks();
}
-void PageScaleAnimation::StartAnimation(double time) {
- DCHECK_GT(0, start_time_);
+void PageScaleAnimation::StartAnimation(base::TimeTicks time) {
+ DCHECK(start_time_.is_null());
start_time_ = time;
}
-gfx::Vector2dF PageScaleAnimation::ScrollOffsetAtTime(double time) const {
- DCHECK_GE(start_time_, 0);
+gfx::Vector2dF PageScaleAnimation::ScrollOffsetAtTime(
+ base::TimeTicks time) const {
+ DCHECK(!start_time_.is_null());
return ScrollOffsetAt(InterpAtTime(time));
}
-float PageScaleAnimation::PageScaleFactorAtTime(double time) const {
- DCHECK_GE(start_time_, 0);
+float PageScaleAnimation::PageScaleFactorAtTime(base::TimeTicks time) const {
+ DCHECK(!start_time_.is_null());
return PageScaleFactorAt(InterpAtTime(time));
}
-bool PageScaleAnimation::IsAnimationCompleteAtTime(double time) const {
- DCHECK_GE(start_time_, 0);
+bool PageScaleAnimation::IsAnimationCompleteAtTime(base::TimeTicks time) const {
+ DCHECK(!start_time_.is_null());
return time >= end_time();
}
-float PageScaleAnimation::InterpAtTime(double time) const {
- DCHECK_GE(start_time_, 0);
- DCHECK_GE(time, start_time_);
- if (IsAnimationCompleteAtTime(time))
+float PageScaleAnimation::InterpAtTime(base::TimeTicks monotonic_time) const {
+ DCHECK(!start_time_.is_null());
+ DCHECK(monotonic_time >= start_time_);
+ if (IsAnimationCompleteAtTime(monotonic_time))
return 1.f;
-
- const double normalized_time = (time - start_time_) / duration_;
+ const double normalized_time =
+ (monotonic_time - start_time_).InSecondsF() / duration_.InSecondsF();
return timing_function_->GetValue(normalized_time);
}
diff --git a/chromium/cc/input/page_scale_animation.h b/chromium/cc/input/page_scale_animation.h
index 4c30cdcbc52..c997c567754 100644
--- a/chromium/cc/input/page_scale_animation.h
+++ b/chromium/cc/input/page_scale_animation.h
@@ -7,10 +7,12 @@
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
#include "ui/gfx/size.h"
#include "ui/gfx/vector2d_f.h"
namespace cc {
+
class TimingFunction;
// A small helper class that does the math for zoom animations, primarily for
@@ -25,10 +27,10 @@ class PageScaleAnimation {
public:
// Construct with the state at the beginning of the animation.
static scoped_ptr<PageScaleAnimation> Create(
- gfx::Vector2dF start_scroll_offset,
+ const gfx::Vector2dF& start_scroll_offset,
float start_page_scale_factor,
- gfx::SizeF viewport_size,
- gfx::SizeF root_layer_size,
+ const gfx::SizeF& viewport_size,
+ const gfx::SizeF& root_layer_size,
scoped_ptr<TimingFunction> timing_function);
~PageScaleAnimation();
@@ -37,7 +39,7 @@ class PageScaleAnimation {
// immediately after construction to set the final scroll and page scale.
// Zoom while explicitly specifying the top-left scroll position.
- void ZoomTo(gfx::Vector2dF target_scroll_offset,
+ void ZoomTo(const gfx::Vector2dF& target_scroll_offset,
float target_page_scale_factor,
double duration);
@@ -45,34 +47,34 @@ class PageScaleAnimation {
// at the same position on the physical display throughout the animation,
// unless the edges of the root layer are hit. The anchor is specified
// as an offset from the content layer.
- void ZoomWithAnchor(gfx::Vector2dF anchor,
+ void ZoomWithAnchor(const gfx::Vector2dF& anchor,
float target_page_scale_factor,
double duration);
// These should be called before the first frame of animation to initialize
// the start time. StartAnimation should only be called once after creation.
bool IsAnimationStarted() const;
- void StartAnimation(double time);
+ void StartAnimation(base::TimeTicks time);
// Call these functions while the animation is in progress to output the
// current state.
- gfx::Vector2dF ScrollOffsetAtTime(double time) const;
- float PageScaleFactorAtTime(double time) const;
- bool IsAnimationCompleteAtTime(double time) const;
+ gfx::Vector2dF ScrollOffsetAtTime(base::TimeTicks time) const;
+ float PageScaleFactorAtTime(base::TimeTicks time) const;
+ bool IsAnimationCompleteAtTime(base::TimeTicks time) const;
// The following methods return state which is invariant throughout the
// course of the animation.
- double start_time() const { return start_time_; }
- double duration() const { return duration_; }
- double end_time() const { return start_time_ + duration_; }
+ base::TimeTicks start_time() const { return start_time_; }
+ base::TimeDelta duration() const { return duration_; }
+ base::TimeTicks end_time() const { return start_time_ + duration_; }
gfx::Vector2dF target_scroll_offset() const { return target_scroll_offset_; }
float target_page_scale_factor() const { return target_page_scale_factor_; }
protected:
- PageScaleAnimation(gfx::Vector2dF start_scroll_offset,
+ PageScaleAnimation(const gfx::Vector2dF& start_scroll_offset,
float start_page_scale_factor,
- gfx::SizeF viewport_size,
- gfx::SizeF root_layer_size,
+ const gfx::SizeF& viewport_size,
+ const gfx::SizeF& root_layer_size,
scoped_ptr<TimingFunction> timing_function);
private:
@@ -82,7 +84,7 @@ class PageScaleAnimation {
gfx::SizeF StartViewportSize() const;
gfx::SizeF TargetViewportSize() const;
- float InterpAtTime(double time) const;
+ float InterpAtTime(base::TimeTicks time) const;
gfx::SizeF ViewportSizeAt(float interp) const;
gfx::Vector2dF ScrollOffsetAt(float interp) const;
gfx::Vector2dF AnchorAt(float interp) const;
@@ -100,8 +102,8 @@ class PageScaleAnimation {
gfx::SizeF viewport_size_;
gfx::SizeF root_layer_size_;
- double start_time_;
- double duration_;
+ base::TimeTicks start_time_;
+ base::TimeDelta duration_;
scoped_ptr<TimingFunction> timing_function_;
diff --git a/chromium/cc/input/scrollbar.h b/chromium/cc/input/scrollbar.h
index bfefd430213..8321ae29fe6 100644
--- a/chromium/cc/input/scrollbar.h
+++ b/chromium/cc/input/scrollbar.h
@@ -33,7 +33,7 @@ class Scrollbar {
virtual gfx::Rect TrackRect() const = 0;
virtual void PaintPart(SkCanvas* canvas,
ScrollbarPart part,
- gfx::Rect content_rect) = 0;
+ const gfx::Rect& content_rect) = 0;
};
} // namespace cc
diff --git a/chromium/cc/input/top_controls_manager.cc b/chromium/cc/input/top_controls_manager.cc
index 871d9e6f69c..07a9e19e95e 100644
--- a/chromium/cc/input/top_controls_manager.cc
+++ b/chromium/cc/input/top_controls_manager.cc
@@ -98,7 +98,7 @@ void TopControlsManager::ScrollBegin() {
}
gfx::Vector2dF TopControlsManager::ScrollBy(
- const gfx::Vector2dF pending_delta) {
+ const gfx::Vector2dF& pending_delta) {
if (pinch_gesture_active_)
return pending_delta;
diff --git a/chromium/cc/input/top_controls_manager.h b/chromium/cc/input/top_controls_manager.h
index 246efba5b9a..7d631d85bb1 100644
--- a/chromium/cc/input/top_controls_manager.h
+++ b/chromium/cc/input/top_controls_manager.h
@@ -53,7 +53,7 @@ class CC_EXPORT TopControlsManager
bool animate);
void ScrollBegin();
- gfx::Vector2dF ScrollBy(const gfx::Vector2dF pending_delta);
+ gfx::Vector2dF ScrollBy(const gfx::Vector2dF& pending_delta);
void ScrollEnd();
// The caller should ensure that |Pinch{Begin,End}| are called within
diff --git a/chromium/cc/input/top_controls_manager_unittest.cc b/chromium/cc/input/top_controls_manager_unittest.cc
index 74687adfac0..28155d31bf2 100644
--- a/chromium/cc/input/top_controls_manager_unittest.cc
+++ b/chromium/cc/input/top_controls_manager_unittest.cc
@@ -10,6 +10,7 @@
#include "cc/layers/layer_impl.h"
#include "cc/test/fake_impl_proxy.h"
#include "cc/test/fake_layer_tree_host_impl.h"
+#include "cc/test/test_shared_bitmap_manager.h"
#include "cc/trees/layer_tree_impl.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/frame_time.h"
@@ -24,7 +25,7 @@ class MockTopControlsManagerClient : public TopControlsManagerClient {
public:
MockTopControlsManagerClient(float top_controls_show_threshold,
float top_controls_hide_threshold)
- : host_impl_(&proxy_),
+ : host_impl_(&proxy_, &shared_bitmap_manager_),
redraw_needed_(false),
update_draw_properties_needed_(false),
top_controls_show_threshold_(top_controls_show_threshold),
@@ -60,6 +61,7 @@ class MockTopControlsManagerClient : public TopControlsManagerClient {
private:
FakeImplProxy proxy_;
+ TestSharedBitmapManager shared_bitmap_manager_;
FakeLayerTreeHostImpl host_impl_;
scoped_ptr<LayerTreeImpl> active_tree_;
scoped_ptr<LayerImpl> root_scroll_layer_;
diff --git a/chromium/cc/layers/append_quads_data.h b/chromium/cc/layers/append_quads_data.h
index 5e19731fd28..7c6768f6630 100644
--- a/chromium/cc/layers/append_quads_data.h
+++ b/chromium/cc/layers/append_quads_data.h
@@ -14,17 +14,25 @@ struct AppendQuadsData {
AppendQuadsData()
: had_incomplete_tile(false),
num_missing_tiles(0),
+ visible_content_area(0),
+ approximated_visible_content_area(0),
render_pass_id(0, 0) {}
explicit AppendQuadsData(RenderPass::Id render_pass_id)
: had_incomplete_tile(false),
num_missing_tiles(0),
+ visible_content_area(0),
+ approximated_visible_content_area(0),
render_pass_id(render_pass_id) {}
// Set by the layer appending quads.
bool had_incomplete_tile;
// Set by the layer appending quads.
int64 num_missing_tiles;
+ // Set by the layer appending quads.
+ int64 visible_content_area;
+ // Set by the layer appending quads.
+ int64 approximated_visible_content_area;
// Given to the layer appending quads.
const RenderPass::Id render_pass_id;
};
diff --git a/chromium/cc/layers/compositing_reasons.h b/chromium/cc/layers/compositing_reasons.h
deleted file mode 100644
index 6331a906ada..00000000000
--- a/chromium/cc/layers/compositing_reasons.h
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CC_LAYERS_COMPOSITING_REASONS_H_
-#define CC_LAYERS_COMPOSITING_REASONS_H_
-
-#include "base/port.h"
-
-namespace cc {
-
-// This is a clone of CompositingReasons and WebCompositingReasons from Blink.
-const uint64 kCompositingReasonUnknown = 0;
-const uint64 kCompositingReason3DTransform = GG_UINT64_C(1) << 0;
-const uint64 kCompositingReasonVideo = GG_UINT64_C(1) << 1;
-const uint64 kCompositingReasonCanvas = GG_UINT64_C(1) << 2;
-const uint64 kCompositingReasonPlugin = GG_UINT64_C(1) << 3;
-const uint64 kCompositingReasonIFrame = GG_UINT64_C(1) << 4;
-const uint64 kCompositingReasonBackfaceVisibilityHidden = GG_UINT64_C(1) << 5;
-const uint64 kCompositingReasonAnimation = GG_UINT64_C(1) << 6;
-const uint64 kCompositingReasonFilters = GG_UINT64_C(1) << 7;
-const uint64 kCompositingReasonPositionFixed = GG_UINT64_C(1) << 8;
-const uint64 kCompositingReasonPositionSticky = GG_UINT64_C(1) << 9;
-const uint64 kCompositingReasonOverflowScrollingTouch = GG_UINT64_C(1) << 10;
-const uint64 kCompositingReasonAssumedOverlap = GG_UINT64_C(1) << 12;
-const uint64 kCompositingReasonOverlap = GG_UINT64_C(1) << 13;
-const uint64 kCompositingReasonNegativeZIndexChildren = GG_UINT64_C(1) << 14;
-const uint64 kCompositingReasonTransformWithCompositedDescendants =
- GG_UINT64_C(1) << 15;
-const uint64 kCompositingReasonOpacityWithCompositedDescendants =
- GG_UINT64_C(1) << 16;
-const uint64 kCompositingReasonMaskWithCompositedDescendants =
- GG_UINT64_C(1) << 17;
-const uint64 kCompositingReasonReflectionWithCompositedDescendants =
- GG_UINT64_C(1) << 18;
-const uint64 kCompositingReasonFilterWithCompositedDescendants =
- GG_UINT64_C(1) << 19;
-const uint64 kCompositingReasonBlendingWithCompositedDescendants =
- GG_UINT64_C(1) << 20;
-const uint64 kCompositingReasonClipsCompositingDescendants =
- GG_UINT64_C(1) << 21;
-const uint64 kCompositingReasonPerspective = GG_UINT64_C(1) << 22;
-const uint64 kCompositingReasonPreserve3D = GG_UINT64_C(1) << 23;
-const uint64 kCompositingReasonReflectionOfCompositedParent =
- GG_UINT64_C(1) << 24;
-const uint64 kCompositingReasonRoot = GG_UINT64_C(1) << 25;
-const uint64 kCompositingReasonLayerForClip = GG_UINT64_C(1) << 26;
-const uint64 kCompositingReasonLayerForScrollbar = GG_UINT64_C(1) << 27;
-const uint64 kCompositingReasonLayerForScrollingContainer =
- GG_UINT64_C(1) << 28;
-const uint64 kCompositingReasonLayerForForeground = GG_UINT64_C(1) << 29;
-const uint64 kCompositingReasonLayerForBackground = GG_UINT64_C(1) << 30;
-const uint64 kCompositingReasonLayerForMask = GG_UINT64_C(1) << 31;
-const uint64 kCompositingReasonOverflowScrollingParent = GG_UINT64_C(1) << 32;
-const uint64 kCompositingReasonOutOfFlowClipping = GG_UINT64_C(1) << 33;
-const uint64 kCompositingReasonIsolateCompositedDescendants =
- GG_UINT64_C(1) << 35;
-
-typedef uint64 CompositingReasons;
-
-} // namespace cc
-
-#endif // CC_LAYERS_COMPOSITING_REASONS_H_
diff --git a/chromium/cc/layers/content_layer.cc b/chromium/cc/layers/content_layer.cc
index 24cb8b36361..d720501b56d 100644
--- a/chromium/cc/layers/content_layer.cc
+++ b/chromium/cc/layers/content_layer.cc
@@ -12,6 +12,7 @@
#include "cc/resources/bitmap_skpicture_content_layer_updater.h"
#include "cc/resources/layer_painter.h"
#include "cc/trees/layer_tree_host.h"
+#include "third_party/skia/include/core/SkPictureRecorder.h"
namespace cc {
@@ -24,29 +25,12 @@ scoped_ptr<ContentLayerPainter> ContentLayerPainter::Create(
}
void ContentLayerPainter::Paint(SkCanvas* canvas,
- gfx::Rect content_rect,
+ const gfx::Rect& content_rect,
gfx::RectF* opaque) {
- base::TimeTicks paint_start = base::TimeTicks::HighResNow();
- client_->PaintContents(canvas, content_rect, opaque);
- base::TimeTicks paint_end = base::TimeTicks::HighResNow();
- // The start and end times might be the same if the paint was very fast or if
- // our timer granularity is poor. Treat this as a very short time duration
- // instead of none to avoid dividing by zero.
- if (paint_end == paint_start)
- paint_end += base::TimeDelta::FromMicroseconds(1);
-
- double pixels_per_sec = (content_rect.width() * content_rect.height()) /
- (paint_end - paint_start).InSecondsF();
- UMA_HISTOGRAM_CUSTOM_COUNTS("Renderer4.AccelContentPaintDurationMS",
- (paint_end - paint_start).InMilliseconds(),
- 0,
- 120,
- 30);
- UMA_HISTOGRAM_CUSTOM_COUNTS("Renderer4.AccelContentPaintMegapixPerSecond",
- pixels_per_sec / 1000000,
- 10,
- 210,
- 30);
+ client_->PaintContents(canvas,
+ content_rect,
+ opaque,
+ ContentLayerClient::GRAPHICS_CONTEXT_ENABLED);
}
scoped_refptr<ContentLayer> ContentLayer::Create(ContentLayerClient* client) {
@@ -88,7 +72,7 @@ void ContentLayer::SetTexturePriorities(
}
bool ContentLayer::Update(ResourceUpdateQueue* queue,
- const OcclusionTracker* occlusion) {
+ const OcclusionTracker<Layer>* occlusion) {
{
base::AutoReset<bool> ignore_set_needs_commit(&ignore_set_needs_commit_,
true);
@@ -126,6 +110,8 @@ void ContentLayer::CreateUpdaterIfNeeded() {
id());
}
updater_->SetOpaque(contents_opaque());
+ if (client_)
+ updater_->SetFillsBoundsCompletely(client_->FillsBoundsCompletely());
SetTextureFormat(
layer_tree_host()->GetRendererCapabilities().best_texture_format);
@@ -158,10 +144,13 @@ skia::RefPtr<SkPicture> ContentLayer::GetPicture() const {
int height = bounds().height();
gfx::RectF opaque;
- skia::RefPtr<SkPicture> picture = skia::AdoptRef(new SkPicture);
- SkCanvas* canvas = picture->beginRecording(width, height);
- client_->PaintContents(canvas, gfx::Rect(width, height), &opaque);
- picture->endRecording();
+ SkPictureRecorder recorder;
+ SkCanvas* canvas = recorder.beginRecording(width, height, NULL, 0);
+ client_->PaintContents(canvas,
+ gfx::Rect(width, height),
+ &opaque,
+ ContentLayerClient::GRAPHICS_CONTEXT_ENABLED);
+ skia::RefPtr<SkPicture> picture = skia::AdoptRef(recorder.endRecording());
return picture;
}
diff --git a/chromium/cc/layers/content_layer.h b/chromium/cc/layers/content_layer.h
index 45de86cde71..9bef22bb704 100644
--- a/chromium/cc/layers/content_layer.h
+++ b/chromium/cc/layers/content_layer.h
@@ -22,7 +22,7 @@ class CC_EXPORT ContentLayerPainter : public LayerPainter {
static scoped_ptr<ContentLayerPainter> Create(ContentLayerClient* client);
virtual void Paint(SkCanvas* canvas,
- gfx::Rect content_rect,
+ const gfx::Rect& content_rect,
gfx::RectF* opaque) OVERRIDE;
private:
@@ -45,7 +45,7 @@ class CC_EXPORT ContentLayer : public TiledLayer {
virtual void SetTexturePriorities(const PriorityCalculator& priority_calc)
OVERRIDE;
virtual bool Update(ResourceUpdateQueue* queue,
- const OcclusionTracker* occlusion) OVERRIDE;
+ const OcclusionTracker<Layer>* occlusion) OVERRIDE;
virtual bool NeedMoreUpdates() OVERRIDE;
virtual void SetContentsOpaque(bool contents_opaque) OVERRIDE;
diff --git a/chromium/cc/layers/content_layer_client.h b/chromium/cc/layers/content_layer_client.h
index e59c1d8c3e1..8271cd5e27f 100644
--- a/chromium/cc/layers/content_layer_client.h
+++ b/chromium/cc/layers/content_layer_client.h
@@ -18,14 +18,24 @@ namespace cc {
class CC_EXPORT ContentLayerClient {
public:
+ enum GraphicsContextStatus {
+ GRAPHICS_CONTEXT_DISABLED,
+ GRAPHICS_CONTEXT_ENABLED
+ };
+
virtual void PaintContents(SkCanvas* canvas,
- gfx::Rect clip,
- gfx::RectF* opaque) = 0;
+ const gfx::Rect& clip,
+ gfx::RectF* opaque,
+ GraphicsContextStatus gc_status) = 0;
// Called by the content layer during the update phase.
// If the client paints LCD text, it may want to invalidate the layer.
virtual void DidChangeLayerCanUseLCDText() = 0;
+ // If true the layer may skip clearing the background before rasterizing,
+ // because it will cover any uncleared data with content.
+ virtual bool FillsBoundsCompletely() const = 0;
+
protected:
virtual ~ContentLayerClient() {}
};
diff --git a/chromium/cc/layers/content_layer_unittest.cc b/chromium/cc/layers/content_layer_unittest.cc
index 724845883e9..f450149d4f6 100644
--- a/chromium/cc/layers/content_layer_unittest.cc
+++ b/chromium/cc/layers/content_layer_unittest.cc
@@ -17,15 +17,18 @@ namespace {
class MockContentLayerClient : public ContentLayerClient {
public:
- explicit MockContentLayerClient(gfx::Rect opaque_layer_rect)
+ explicit MockContentLayerClient(const gfx::Rect& opaque_layer_rect)
: opaque_layer_rect_(opaque_layer_rect) {}
- virtual void PaintContents(SkCanvas* canvas,
- gfx::Rect clip,
- gfx::RectF* opaque) OVERRIDE {
+ virtual void PaintContents(
+ SkCanvas* canvas,
+ const gfx::Rect& clip,
+ gfx::RectF* opaque,
+ ContentLayerClient::GraphicsContextStatus gc_status) OVERRIDE {
*opaque = gfx::RectF(opaque_layer_rect_);
}
virtual void DidChangeLayerCanUseLCDText() OVERRIDE {}
+ virtual bool FillsBoundsCompletely() const OVERRIDE { return false; }
private:
gfx::Rect opaque_layer_rect_;
diff --git a/chromium/cc/layers/contents_scaling_layer.cc b/chromium/cc/layers/contents_scaling_layer.cc
index 44a3f372c65..a53482a6727 100644
--- a/chromium/cc/layers/contents_scaling_layer.cc
+++ b/chromium/cc/layers/contents_scaling_layer.cc
@@ -24,6 +24,7 @@ void ContentsScalingLayer::CalculateContentsScale(
float ideal_contents_scale,
float device_scale_factor,
float page_scale_factor,
+ float maximum_animation_contents_scale,
bool animating_transform_to_screen,
float* contents_scale_x,
float* contents_scale_y,
@@ -35,9 +36,8 @@ void ContentsScalingLayer::CalculateContentsScale(
ideal_contents_scale);
}
-bool ContentsScalingLayer::Update(
- ResourceUpdateQueue* queue,
- const OcclusionTracker* occlusion) {
+bool ContentsScalingLayer::Update(ResourceUpdateQueue* queue,
+ const OcclusionTracker<Layer>* occlusion) {
bool updated = Layer::Update(queue, occlusion);
if (draw_properties().contents_scale_x == last_update_contents_scale_x_ &&
diff --git a/chromium/cc/layers/contents_scaling_layer.h b/chromium/cc/layers/contents_scaling_layer.h
index a2648d1e01a..3e959622d75 100644
--- a/chromium/cc/layers/contents_scaling_layer.h
+++ b/chromium/cc/layers/contents_scaling_layer.h
@@ -14,18 +14,17 @@ namespace cc {
// The content bounds are determined by bounds and scale of the contents.
class CC_EXPORT ContentsScalingLayer : public Layer {
public:
- virtual void CalculateContentsScale(
- float ideal_contents_scale,
- float device_scale_factor,
- float page_scale_factor,
- bool animating_transform_to_screen,
- float* contents_scale_x,
- float* contents_scale_y,
- gfx::Size* content_bounds) OVERRIDE;
-
- virtual bool Update(
- ResourceUpdateQueue* queue,
- const OcclusionTracker* occlusion) OVERRIDE;
+ virtual void CalculateContentsScale(float ideal_contents_scale,
+ float device_scale_factor,
+ float page_scale_factor,
+ float maximum_animation_contents_scale,
+ bool animating_transform_to_screen,
+ float* contents_scale_x,
+ float* contents_scale_y,
+ gfx::Size* content_bounds) OVERRIDE;
+
+ virtual bool Update(ResourceUpdateQueue* queue,
+ const OcclusionTracker<Layer>* occlusion) OVERRIDE;
protected:
ContentsScalingLayer();
diff --git a/chromium/cc/layers/delegated_frame_provider.cc b/chromium/cc/layers/delegated_frame_provider.cc
index c97f23171f5..ce9ac596d06 100644
--- a/chromium/cc/layers/delegated_frame_provider.cc
+++ b/chromium/cc/layers/delegated_frame_provider.cc
@@ -28,10 +28,10 @@ DelegatedFrameProvider::~DelegatedFrameProvider() {
}
void DelegatedFrameProvider::AddObserver(DelegatedRendererLayer* layer) {
- if (DCHECK_IS_ON()) {
- for (size_t i = 0; i < observers_.size(); ++i)
- DCHECK(observers_[i].layer != layer);
- }
+#if DCHECK_IS_ON
+ for (size_t i = 0; i < observers_.size(); ++i)
+ DCHECK(observers_[i].layer != layer);
+#endif
observers_.push_back(Observer(layer, gfx::RectF(frame_size_)));
diff --git a/chromium/cc/layers/delegated_frame_provider_unittest.cc b/chromium/cc/layers/delegated_frame_provider_unittest.cc
index 20b355c6192..0655cf36e72 100644
--- a/chromium/cc/layers/delegated_frame_provider_unittest.cc
+++ b/chromium/cc/layers/delegated_frame_provider_unittest.cc
@@ -20,8 +20,9 @@ class DelegatedFrameProviderTest
protected:
DelegatedFrameProviderTest() : resources_available_(false) {}
- scoped_ptr<DelegatedFrameData> CreateFrameData(gfx::Rect root_output_rect,
- gfx::Rect root_damage_rect) {
+ scoped_ptr<DelegatedFrameData> CreateFrameData(
+ const gfx::Rect& root_output_rect,
+ const gfx::Rect& root_damage_rect) {
scoped_ptr<DelegatedFrameData> frame(new DelegatedFrameData);
scoped_ptr<RenderPass> root_pass(RenderPass::Create());
@@ -37,16 +38,18 @@ class DelegatedFrameProviderTest
ResourceProvider::ResourceId resource_id) {
TransferableResource resource;
resource.id = resource_id;
- resource.target = GL_TEXTURE_2D;
+ resource.mailbox_holder.texture_target = GL_TEXTURE_2D;
frame->resource_list.push_back(resource);
}
void AddTextureQuad(DelegatedFrameData* frame,
ResourceProvider::ResourceId resource_id) {
- scoped_ptr<SharedQuadState> sqs = SharedQuadState::Create();
+ SharedQuadState* sqs =
+ frame->render_pass_list[0]->CreateAndAppendSharedQuadState();
scoped_ptr<TextureDrawQuad> quad = TextureDrawQuad::Create();
float vertex_opacity[4] = {1.f, 1.f, 1.f, 1.f};
- quad->SetNew(sqs.get(),
+ quad->SetNew(sqs,
+ gfx::Rect(0, 0, 10, 10),
gfx::Rect(0, 0, 10, 10),
gfx::Rect(0, 0, 10, 10),
resource_id,
@@ -56,7 +59,6 @@ class DelegatedFrameProviderTest
SK_ColorTRANSPARENT,
vertex_opacity,
false);
- frame->render_pass_list[0]->shared_quad_state_list.push_back(sqs.Pass());
frame->render_pass_list[0]->quad_list.push_back(quad.PassAs<DrawQuad>());
}
diff --git a/chromium/cc/layers/delegated_renderer_layer.cc b/chromium/cc/layers/delegated_renderer_layer.cc
index 6616b9b345a..c47206172ce 100644
--- a/chromium/cc/layers/delegated_renderer_layer.cc
+++ b/chromium/cc/layers/delegated_renderer_layer.cc
@@ -67,8 +67,6 @@ void DelegatedRendererLayer::PushPropertiesTo(LayerImpl* impl) {
DelegatedRendererLayerImpl* delegated_impl =
static_cast<DelegatedRendererLayerImpl*>(impl);
- delegated_impl->SetDisplaySize(display_size_);
-
delegated_impl->CreateChildIdIfNeeded(
frame_provider_->GetReturnResourcesCallbackForImplThread());
@@ -86,34 +84,8 @@ void DelegatedRendererLayer::ProviderHasNewFrame() {
SetNextCommitWaitsForActivation();
}
-void DelegatedRendererLayer::SetDisplaySize(gfx::Size size) {
- if (display_size_ == size)
- return;
- display_size_ = size;
- SetNeedsCommit();
-}
-
-static bool FrameDataRequiresFilterContext(const DelegatedFrameData* frame) {
- for (size_t i = 0; i < frame->render_pass_list.size(); ++i) {
- const QuadList& quad_list = frame->render_pass_list[i]->quad_list;
- for (size_t j = 0; j < quad_list.size(); ++j) {
- if (quad_list[j]->shared_quad_state->blend_mode !=
- SkXfermode::kSrcOver_Mode)
- return true;
- if (quad_list[j]->material != DrawQuad::RENDER_PASS)
- continue;
- const RenderPassDrawQuad* render_pass_quad =
- RenderPassDrawQuad::MaterialCast(quad_list[j]);
- if (!render_pass_quad->filters.IsEmpty() ||
- !render_pass_quad->background_filters.IsEmpty())
- return true;
- }
- }
- return false;
-}
-
bool DelegatedRendererLayer::Update(ResourceUpdateQueue* queue,
- const OcclusionTracker* occlusion) {
+ const OcclusionTracker<Layer>* occlusion) {
bool updated = Layer::Update(queue, occlusion);
if (!should_collect_new_frame_)
return updated;
@@ -122,11 +94,6 @@ bool DelegatedRendererLayer::Update(ResourceUpdateQueue* queue,
frame_provider_->GetFrameDataAndRefResources(this, &frame_damage_);
should_collect_new_frame_ = false;
- // If any quad has a filter operation or a blend mode other than normal,
- // then we need an offscreen context to draw this layer's content.
- if (FrameDataRequiresFilterContext(frame_data_))
- layer_tree_host()->set_needs_filter_context();
-
SetNeedsPushProperties();
return true;
}
diff --git a/chromium/cc/layers/delegated_renderer_layer.h b/chromium/cc/layers/delegated_renderer_layer.h
index dc9dfee4705..3bc0aa8758f 100644
--- a/chromium/cc/layers/delegated_renderer_layer.h
+++ b/chromium/cc/layers/delegated_renderer_layer.h
@@ -26,15 +26,9 @@ class CC_EXPORT DelegatedRendererLayer : public Layer {
OVERRIDE;
virtual void SetLayerTreeHost(LayerTreeHost* host) OVERRIDE;
virtual bool Update(ResourceUpdateQueue* queue,
- const OcclusionTracker* occlusion) OVERRIDE;
+ const OcclusionTracker<Layer>* occlusion) OVERRIDE;
virtual void PushPropertiesTo(LayerImpl* impl) OVERRIDE;
- // Set the size at which the frame should be displayed, with the origin at the
- // layer's origin. This must always contain at least the layer's bounds. A
- // value of (0, 0) implies that the frame should be displayed to fit exactly
- // in the layer's bounds.
- void SetDisplaySize(gfx::Size size);
-
// Called by the DelegatedFrameProvider when a new frame is available to be
// picked up.
void ProviderHasNewFrame();
@@ -52,8 +46,6 @@ class CC_EXPORT DelegatedRendererLayer : public Layer {
DelegatedFrameData* frame_data_;
gfx::RectF frame_damage_;
- gfx::Size display_size_;
-
scoped_refptr<BlockingTaskRunner> main_thread_runner_;
base::WeakPtrFactory<DelegatedRendererLayer> weak_ptrs_;
diff --git a/chromium/cc/layers/delegated_renderer_layer_impl.cc b/chromium/cc/layers/delegated_renderer_layer_impl.cc
index 07734585724..a233673263a 100644
--- a/chromium/cc/layers/delegated_renderer_layer_impl.cc
+++ b/chromium/cc/layers/delegated_renderer_layer_impl.cc
@@ -20,10 +20,11 @@
namespace cc {
-DelegatedRendererLayerImpl::DelegatedRendererLayerImpl(
- LayerTreeImpl* tree_impl, int id)
+DelegatedRendererLayerImpl::DelegatedRendererLayerImpl(LayerTreeImpl* tree_impl,
+ int id)
: LayerImpl(tree_impl, id),
have_render_passes_to_push_(false),
+ inverse_device_scale_factor_(1.0f),
child_id_(0),
own_child_id_(false) {
}
@@ -71,11 +72,11 @@ void DelegatedRendererLayerImpl::PushPropertiesTo(LayerImpl* layer) {
// have already deleted its old child_id.
DCHECK(delegated_layer->child_id_ == 0 ||
delegated_layer->child_id_ == child_id_);
+ delegated_layer->inverse_device_scale_factor_ = inverse_device_scale_factor_;
delegated_layer->child_id_ = child_id_;
delegated_layer->own_child_id_ = true;
own_child_id_ = false;
- delegated_layer->SetDisplaySize(display_size_);
if (have_render_passes_to_push_) {
// This passes ownership of the render passes to the active tree.
delegated_layer->SetRenderPasses(&render_passes_in_draw_order_);
@@ -100,7 +101,7 @@ void DelegatedRendererLayerImpl::CreateChildIdIfNeeded(
void DelegatedRendererLayerImpl::SetFrameData(
const DelegatedFrameData* frame_data,
- gfx::RectF damage_in_frame) {
+ const gfx::RectF& damage_in_frame) {
DCHECK(child_id_) << "CreateChildIdIfNeeded must be called first.";
DCHECK(frame_data);
DCHECK(!frame_data->render_pass_list.empty());
@@ -141,27 +142,21 @@ void DelegatedRendererLayerImpl::SetFrameData(
resources_.swap(resources_in_frame);
resource_provider->DeclareUsedResourcesFromChild(child_id_, resources_);
+ inverse_device_scale_factor_ = 1.0f / frame_data->device_scale_factor;
// Display size is already set so we can compute what the damage rect
// will be in layer space. The damage may exceed the visible portion of
// the frame, so intersect the damage to the layer's bounds.
RenderPass* new_root_pass = render_pass_list.back();
gfx::Size frame_size = new_root_pass->output_rect.size();
- gfx::RectF damage_in_layer = MathUtil::MapClippedRect(
- DelegatedFrameToLayerSpaceTransform(frame_size), damage_in_frame);
- set_update_rect(gfx::IntersectRects(
+ gfx::RectF damage_in_layer = damage_in_frame;
+ damage_in_layer.Scale(inverse_device_scale_factor_);
+ SetUpdateRect(gfx::IntersectRects(
gfx::UnionRects(update_rect(), damage_in_layer), gfx::Rect(bounds())));
SetRenderPasses(&render_pass_list);
have_render_passes_to_push_ = true;
}
-void DelegatedRendererLayerImpl::SetDisplaySize(gfx::Size size) {
- if (display_size_ == size)
- return;
- display_size_ = size;
- NoteLayerPropertyChanged();
-}
-
void DelegatedRendererLayerImpl::SetRenderPasses(
ScopedPtrVector<RenderPass>* render_passes_in_draw_order) {
ClearRenderPasses();
@@ -191,22 +186,11 @@ scoped_ptr<LayerImpl> DelegatedRendererLayerImpl::CreateLayerImpl(
tree_impl, id()).PassAs<LayerImpl>();
}
-void DelegatedRendererLayerImpl::DidLoseOutputSurface() {
+void DelegatedRendererLayerImpl::ReleaseResources() {
ClearRenderPasses();
ClearChildId();
}
-gfx::Transform DelegatedRendererLayerImpl::DelegatedFrameToLayerSpaceTransform(
- gfx::Size frame_size) const {
- gfx::Size display_size = display_size_.IsEmpty() ? bounds() : display_size_;
-
- gfx::Transform delegated_frame_to_layer_space_transform;
- delegated_frame_to_layer_space_transform.Scale(
- static_cast<double>(display_size.width()) / frame_size.width(),
- static_cast<double>(display_size.height()) / frame_size.height());
- return delegated_frame_to_layer_space_transform;
-}
-
static inline int IndexToId(int index) { return index + 1; }
static inline int IdToIndex(int id) { return id - 1; }
@@ -242,9 +226,9 @@ void DelegatedRendererLayerImpl::AppendContributingRenderPasses(
const RenderPass* root_delegated_render_pass =
render_passes_in_draw_order_.back();
gfx::Size frame_size = root_delegated_render_pass->output_rect.size();
- gfx::Transform delegated_frame_to_root_transform =
- screen_space_transform() *
- DelegatedFrameToLayerSpaceTransform(frame_size);
+ gfx::Transform delegated_frame_to_root_transform = screen_space_transform();
+ delegated_frame_to_root_transform.Scale(inverse_device_scale_factor_,
+ inverse_device_scale_factor_);
for (size_t i = 0; i < render_passes_in_draw_order_.size() - 1; ++i) {
RenderPass::Id output_render_pass_id(-1, -1);
@@ -319,8 +303,8 @@ void DelegatedRendererLayerImpl::AppendRainbowDebugBorder(
if (!ShowDebugBorders())
return;
- SharedQuadState* shared_quad_state =
- quad_sink->UseSharedQuadState(CreateSharedQuadState());
+ SharedQuadState* shared_quad_state = quad_sink->CreateSharedQuadState();
+ PopulateSharedQuadState(shared_quad_state);
SkColor color;
float border_width;
@@ -364,28 +348,31 @@ void DelegatedRendererLayerImpl::AppendRainbowDebugBorder(
if (!top.IsEmpty()) {
scoped_ptr<SolidColorDrawQuad> top_quad = SolidColorDrawQuad::Create();
- top_quad->SetNew(shared_quad_state, top, colors[i % kNumColors], false);
- quad_sink->Append(top_quad.PassAs<DrawQuad>(), append_quads_data);
+ top_quad->SetNew(
+ shared_quad_state, top, top, colors[i % kNumColors], false);
+ quad_sink->Append(top_quad.PassAs<DrawQuad>());
scoped_ptr<SolidColorDrawQuad> bottom_quad = SolidColorDrawQuad::Create();
bottom_quad->SetNew(shared_quad_state,
bottom,
+ bottom,
colors[kNumColors - 1 - (i % kNumColors)],
false);
- quad_sink->Append(bottom_quad.PassAs<DrawQuad>(), append_quads_data);
+ quad_sink->Append(bottom_quad.PassAs<DrawQuad>());
}
if (!left.IsEmpty()) {
scoped_ptr<SolidColorDrawQuad> left_quad = SolidColorDrawQuad::Create();
left_quad->SetNew(shared_quad_state,
left,
+ left,
colors[kNumColors - 1 - (i % kNumColors)],
false);
- quad_sink->Append(left_quad.PassAs<DrawQuad>(), append_quads_data);
+ quad_sink->Append(left_quad.PassAs<DrawQuad>());
scoped_ptr<SolidColorDrawQuad> right_quad = SolidColorDrawQuad::Create();
right_quad->SetNew(
- shared_quad_state, right, colors[i % kNumColors], false);
- quad_sink->Append(right_quad.PassAs<DrawQuad>(), append_quads_data);
+ shared_quad_state, right, right, colors[i % kNumColors], false);
+ quad_sink->Append(right_quad.PassAs<DrawQuad>());
}
}
}
@@ -394,7 +381,7 @@ void DelegatedRendererLayerImpl::AppendRenderPassQuads(
QuadSink* quad_sink,
AppendQuadsData* append_quads_data,
const RenderPass* delegated_render_pass,
- gfx::Size frame_size) const {
+ const gfx::Size& frame_size) const {
const SharedQuadState* delegated_shared_quad_state = NULL;
SharedQuadState* output_shared_quad_state = NULL;
@@ -404,17 +391,15 @@ void DelegatedRendererLayerImpl::AppendRenderPassQuads(
if (delegated_quad->shared_quad_state != delegated_shared_quad_state) {
delegated_shared_quad_state = delegated_quad->shared_quad_state;
- output_shared_quad_state = quad_sink->UseSharedQuadState(
- delegated_shared_quad_state->Copy());
+ output_shared_quad_state = quad_sink->CreateSharedQuadState();
+ output_shared_quad_state->CopyFrom(delegated_shared_quad_state);
bool is_root_delegated_render_pass =
delegated_render_pass == render_passes_in_draw_order_.back();
if (is_root_delegated_render_pass) {
- // Don't allow areas inside the bounds that are empty.
- DCHECK(display_size_.IsEmpty() ||
- gfx::Rect(display_size_).Contains(gfx::Rect(bounds())));
- gfx::Transform delegated_frame_to_target_transform =
- draw_transform() * DelegatedFrameToLayerSpaceTransform(frame_size);
+ gfx::Transform delegated_frame_to_target_transform = draw_transform();
+ delegated_frame_to_target_transform.Scale(inverse_device_scale_factor_,
+ inverse_device_scale_factor_);
output_shared_quad_state->content_to_target_transform.ConcatTransform(
delegated_frame_to_target_transform);
@@ -423,13 +408,14 @@ void DelegatedRendererLayerImpl::AppendRenderPassQuads(
DCHECK(!is_clipped());
DCHECK(render_surface());
DCHECK_EQ(0, num_unclipped_descendants());
- output_shared_quad_state->clip_rect = MathUtil::MapClippedRect(
- delegated_frame_to_target_transform,
- output_shared_quad_state->clip_rect);
+ output_shared_quad_state->clip_rect =
+ MathUtil::MapEnclosingClippedRect(
+ delegated_frame_to_target_transform,
+ output_shared_quad_state->clip_rect);
} else {
gfx::Rect clip_rect = drawable_content_rect();
if (output_shared_quad_state->is_clipped) {
- clip_rect.Intersect(MathUtil::MapClippedRect(
+ clip_rect.Intersect(MathUtil::MapEnclosingClippedRect(
delegated_frame_to_target_transform,
output_shared_quad_state->clip_rect));
}
@@ -442,9 +428,16 @@ void DelegatedRendererLayerImpl::AppendRenderPassQuads(
}
DCHECK(output_shared_quad_state);
+ gfx::Rect quad_visible_rect = quad_sink->UnoccludedContentRect(
+ delegated_quad->visible_rect,
+ output_shared_quad_state->content_to_target_transform);
+ if (quad_visible_rect.IsEmpty())
+ continue;
+
scoped_ptr<DrawQuad> output_quad;
if (delegated_quad->material != DrawQuad::RENDER_PASS) {
output_quad = delegated_quad->Copy(output_shared_quad_state);
+ output_quad->visible_rect = quad_visible_rect;
} else {
RenderPass::Id delegated_contributing_render_pass_id =
RenderPassDrawQuad::MaterialCast(delegated_quad)->render_pass_id;
@@ -463,11 +456,12 @@ void DelegatedRendererLayerImpl::AppendRenderPassQuads(
output_quad = RenderPassDrawQuad::MaterialCast(delegated_quad)->Copy(
output_shared_quad_state,
output_contributing_render_pass_id).PassAs<DrawQuad>();
+ output_quad->visible_rect = quad_visible_rect;
}
}
if (output_quad)
- quad_sink->Append(output_quad.Pass(), append_quads_data);
+ quad_sink->Append(output_quad.Pass());
}
}
@@ -484,6 +478,7 @@ void DelegatedRendererLayerImpl::ClearChildId() {
provider->DestroyChild(child_id_);
}
+ resources_.clear();
child_id_ = 0;
}
diff --git a/chromium/cc/layers/delegated_renderer_layer_impl.h b/chromium/cc/layers/delegated_renderer_layer_impl.h
index 358b7b9acf4..34d117081af 100644
--- a/chromium/cc/layers/delegated_renderer_layer_impl.h
+++ b/chromium/cc/layers/delegated_renderer_layer_impl.h
@@ -31,7 +31,7 @@ class CC_EXPORT DelegatedRendererLayerImpl : public LayerImpl {
virtual RenderPass::Id FirstContributingRenderPassId() const OVERRIDE;
virtual RenderPass::Id NextContributingRenderPassId(
RenderPass::Id previous) const OVERRIDE;
- virtual void DidLoseOutputSurface() OVERRIDE;
+ virtual void ReleaseResources() OVERRIDE;
virtual bool WillDraw(DrawMode draw_mode,
ResourceProvider* resource_provider) OVERRIDE;
virtual void AppendQuads(QuadSink* quad_sink,
@@ -46,9 +46,11 @@ class CC_EXPORT DelegatedRendererLayerImpl : public LayerImpl {
void CreateChildIdIfNeeded(const ReturnCallback& return_callback);
void SetFrameData(const DelegatedFrameData* frame_data,
- gfx::RectF damage_in_frame);
+ const gfx::RectF& damage_in_frame);
- void SetDisplaySize(gfx::Size size);
+ float inverse_device_scale_factor() const {
+ return inverse_device_scale_factor_;
+ }
protected:
DelegatedRendererLayerImpl(LayerTreeImpl* tree_impl, int id);
@@ -77,24 +79,21 @@ class CC_EXPORT DelegatedRendererLayerImpl : public LayerImpl {
RenderPass::Id delegated_render_pass_id,
RenderPass::Id* output_render_pass_id) const;
- gfx::Transform DelegatedFrameToLayerSpaceTransform(gfx::Size frame_size)
- const;
-
void AppendRenderPassQuads(
QuadSink* quad_sink,
AppendQuadsData* append_quads_data,
const RenderPass* delegated_render_pass,
- gfx::Size frame_size) const;
+ const gfx::Size& frame_size) const;
// LayerImpl overrides.
virtual const char* LayerTypeAsString() const OVERRIDE;
bool have_render_passes_to_push_;
+ float inverse_device_scale_factor_;
ScopedPtrVector<RenderPass> render_passes_in_draw_order_;
base::hash_map<RenderPass::Id, int> render_passes_index_by_id_;
ResourceProvider::ResourceIdArray resources_;
- gfx::Size display_size_;
int child_id_;
bool own_child_id_;
diff --git a/chromium/cc/layers/delegated_renderer_layer_impl_unittest.cc b/chromium/cc/layers/delegated_renderer_layer_impl_unittest.cc
index 8cb0f3e376c..c4bedddd926 100644
--- a/chromium/cc/layers/delegated_renderer_layer_impl_unittest.cc
+++ b/chromium/cc/layers/delegated_renderer_layer_impl_unittest.cc
@@ -5,7 +5,6 @@
#include "cc/layers/delegated_renderer_layer_impl.h"
#include "cc/base/scoped_ptr_vector.h"
-#include "cc/layers/append_quads_data.h"
#include "cc/layers/quad_sink.h"
#include "cc/layers/solid_color_layer_impl.h"
#include "cc/quads/render_pass_draw_quad.h"
@@ -17,9 +16,10 @@
#include "cc/test/fake_proxy.h"
#include "cc/test/fake_rendering_stats_instrumentation.h"
#include "cc/test/geometry_test_utils.h"
-#include "cc/test/mock_quad_culler.h"
+#include "cc/test/layer_test_common.h"
#include "cc/test/render_pass_test_common.h"
#include "cc/test/render_pass_test_utils.h"
+#include "cc/test/test_shared_bitmap_manager.h"
#include "cc/test/test_web_graphics_context_3d.h"
#include "cc/trees/layer_tree_host_impl.h"
#include "cc/trees/layer_tree_impl.h"
@@ -39,8 +39,10 @@ class DelegatedRendererLayerImplTest : public testing::Test {
LayerTreeSettings settings;
settings.minimum_occlusion_tracking_size = gfx::Size();
- host_impl_.reset(new FakeLayerTreeHostImpl(settings, &proxy_));
- host_impl_->InitializeRenderer(CreateFakeOutputSurface());
+ host_impl_.reset(
+ new FakeLayerTreeHostImpl(settings, &proxy_, &shared_bitmap_manager_));
+ host_impl_->InitializeRenderer(
+ FakeOutputSurface::Create3d().PassAs<OutputSurface>());
host_impl_->SetViewportSize(gfx::Size(10, 10));
}
@@ -48,6 +50,7 @@ class DelegatedRendererLayerImplTest : public testing::Test {
FakeProxy proxy_;
DebugScopedSetImplThreadAndMainThreadBlocked
always_impl_thread_and_main_thread_blocked_;
+ TestSharedBitmapManager shared_bitmap_manager_;
scoped_ptr<LayerTreeHostImpl> host_impl_;
};
@@ -106,7 +109,7 @@ class DelegatedRendererLayerImplTestSimple
gfx::Transform(1, 0, 0, 1, 9, 10));
AddRenderPassQuad(pass3, pass2);
delegated_renderer_layer->SetFrameDataForRenderPasses(
- &delegated_render_passes);
+ 1.f, &delegated_render_passes);
// The RenderPasses should be taken by the layer.
EXPECT_EQ(0u, delegated_render_passes.size());
@@ -136,7 +139,7 @@ class DelegatedRendererLayerImplTestSimple
TEST_F(DelegatedRendererLayerImplTestSimple, AddsContributingRenderPasses) {
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
// Each non-DelegatedRendererLayer added one RenderPass. The
// DelegatedRendererLayer added two contributing passes.
@@ -170,7 +173,7 @@ TEST_F(DelegatedRendererLayerImplTestSimple, AddsContributingRenderPasses) {
TEST_F(DelegatedRendererLayerImplTestSimple,
AddsQuadsToContributingRenderPasses) {
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
// Each non-DelegatedRendererLayer added one RenderPass. The
// DelegatedRendererLayer added two contributing passes.
@@ -205,7 +208,7 @@ TEST_F(DelegatedRendererLayerImplTestSimple,
TEST_F(DelegatedRendererLayerImplTestSimple, AddsQuadsToTargetRenderPass) {
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
// Each non-DelegatedRendererLayer added one RenderPass. The
// DelegatedRendererLayer added two contributing passes.
@@ -233,7 +236,7 @@ TEST_F(DelegatedRendererLayerImplTestSimple, AddsQuadsToTargetRenderPass) {
TEST_F(DelegatedRendererLayerImplTestSimple,
QuadsFromRootRenderPassAreModifiedForTheTarget) {
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
// Each non-DelegatedRendererLayer added one RenderPass. The
// DelegatedRendererLayer added two contributing passes.
@@ -242,11 +245,8 @@ TEST_F(DelegatedRendererLayerImplTestSimple,
// The DelegatedRendererLayer is at position 3,3 compared to its target, and
// has a translation transform of 1,1. So its root RenderPass' quads should
// all be transformed by that combined amount.
- // The DelegatedRendererLayer has a size of 10x10, but the root delegated
- // RenderPass has a size of 8x8, so any quads should be scaled by 10/8.
gfx::Transform transform;
transform.Translate(4.0, 4.0);
- transform.Scale(10.0 / 8.0, 10.0 / 8.0);
EXPECT_TRANSFORMATION_MATRIX_EQ(
transform, frame.render_passes[3]->quad_list[0]->quadTransform());
@@ -266,7 +266,7 @@ TEST_F(DelegatedRendererLayerImplTestSimple,
TEST_F(DelegatedRendererLayerImplTestSimple, RenderPassTransformIsModified) {
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
// The delegated layer has a surface between it and the root.
EXPECT_TRUE(delegated_renderer_layer_->render_target()->parent());
@@ -277,12 +277,8 @@ TEST_F(DelegatedRendererLayerImplTestSimple, RenderPassTransformIsModified) {
// The DelegatedRendererLayer is at position 9,9 compared to the root, so all
// render pass' transforms to the root should be shifted by this amount.
- // The DelegatedRendererLayer has a size of 10x10, but the root delegated
- // RenderPass has a size of 8x8, so any render passes should be scaled by
- // 10/8.
gfx::Transform transform;
transform.Translate(9.0, 9.0);
- transform.Scale(10.0 / 8.0, 10.0 / 8.0);
// The first contributing surface has a translation of 5, 6.
gfx::Transform five_six(1, 0, 0, 1, 5, 6);
@@ -302,7 +298,7 @@ TEST_F(DelegatedRendererLayerImplTestSimple, RenderPassTransformIsModified) {
TEST_F(DelegatedRendererLayerImplTestSimple, DoesNotOwnARenderSurface) {
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
// If the DelegatedRendererLayer is axis aligned and has opacity 1, then it
// has no need to be a RenderSurface for the quads it carries.
@@ -316,7 +312,7 @@ TEST_F(DelegatedRendererLayerImplTestSimple, DoesOwnARenderSurfaceForOpacity) {
delegated_renderer_layer_->SetOpacity(0.5f);
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
// This test case has quads from multiple layers in the delegated renderer, so
// if the DelegatedRendererLayer has opacity < 1, it should end up with a
@@ -334,7 +330,7 @@ TEST_F(DelegatedRendererLayerImplTestSimple,
delegated_renderer_layer_->SetTransform(rotation);
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
// This test case has quads from multiple layers in the delegated renderer, so
// if the DelegatedRendererLayer has opacity < 1, it should end up with a
@@ -356,7 +352,7 @@ class DelegatedRendererLayerImplTestOwnSurface
TEST_F(DelegatedRendererLayerImplTestOwnSurface, AddsRenderPasses) {
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
// Each non-DelegatedRendererLayer added one RenderPass. The
// DelegatedRendererLayer added two contributing passes and its owned surface
@@ -395,7 +391,7 @@ TEST_F(DelegatedRendererLayerImplTestOwnSurface, AddsRenderPasses) {
TEST_F(DelegatedRendererLayerImplTestOwnSurface,
AddsQuadsToContributingRenderPasses) {
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
// Each non-DelegatedRendererLayer added one RenderPass. The
// DelegatedRendererLayer added two contributing passes and its owned surface
@@ -431,7 +427,7 @@ TEST_F(DelegatedRendererLayerImplTestOwnSurface,
TEST_F(DelegatedRendererLayerImplTestOwnSurface, AddsQuadsToTargetRenderPass) {
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
// Each non-DelegatedRendererLayer added one RenderPass. The
// DelegatedRendererLayer added two contributing passes and its owned surface
@@ -457,7 +453,7 @@ TEST_F(DelegatedRendererLayerImplTestOwnSurface, AddsQuadsToTargetRenderPass) {
TEST_F(DelegatedRendererLayerImplTestOwnSurface,
QuadsFromRootRenderPassAreNotModifiedForTheTarget) {
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
// Each non-DelegatedRendererLayer added one RenderPass. The
// DelegatedRendererLayer added two contributing passes and its owned surface
@@ -465,12 +461,9 @@ TEST_F(DelegatedRendererLayerImplTestOwnSurface,
ASSERT_EQ(6u, frame.render_passes.size());
// Because the DelegatedRendererLayer owns a RenderSurfaceImpl, its root
- // RenderPass' quads do not need to be translated at all. However, they are
- // scaled from the frame's size (8x8) to the layer's bounds (10x10).
- gfx::Transform transform;
- transform.Scale(10.0 / 8.0, 10.0 / 8.0);
+ // RenderPass' quads do not need to be translated at all.
EXPECT_TRANSFORMATION_MATRIX_EQ(
- transform, frame.render_passes[3]->quad_list[0]->quadTransform());
+ gfx::Transform(), frame.render_passes[3]->quad_list[0]->quadTransform());
// Quads from non-root RenderPasses should not be shifted either.
ASSERT_EQ(2u, frame.render_passes[2]->quad_list.size());
@@ -489,6 +482,10 @@ TEST_F(DelegatedRendererLayerImplTestOwnSurface,
class DelegatedRendererLayerImplTestTransform
: public DelegatedRendererLayerImplTest {
public:
+ DelegatedRendererLayerImplTestTransform()
+ : root_delegated_render_pass_is_clipped_(false),
+ delegated_device_scale_factor_(2.f) {}
+
void SetUpTest() {
host_impl_->SetDeviceScaleFactor(2.f);
@@ -525,26 +522,33 @@ class DelegatedRendererLayerImplTestTransform
RenderPass::Id(10, 7),
child_pass_rect,
gfx::Transform());
- MockQuadCuller quad_sink(&pass->quad_list, &pass->shared_quad_state_list);
- AppendQuadsData data(pass->id);
- SharedQuadState* shared_quad_state = quad_sink.UseSharedQuadState(
- SharedQuadState::Create());
+ SharedQuadState* shared_quad_state =
+ pass->CreateAndAppendSharedQuadState();
shared_quad_state->SetAll(child_pass_transform,
child_pass_content_bounds,
child_pass_rect,
child_pass_clip_rect,
child_pass_clipped,
1.f,
- SkXfermode::kSrcOver_Mode);
+ SkXfermode::kSrcOver_Mode,
+ 0);
scoped_ptr<SolidColorDrawQuad> color_quad;
color_quad = SolidColorDrawQuad::Create();
- color_quad->SetNew(shared_quad_state, gfx::Rect(20, 20, 3, 7), 1u, false);
- quad_sink.Append(color_quad.PassAs<DrawQuad>(), &data);
+ color_quad->SetNew(shared_quad_state,
+ gfx::Rect(20, 20, 3, 7),
+ gfx::Rect(20, 20, 3, 7),
+ 1u,
+ false);
+ pass->AppendDrawQuad(color_quad.PassAs<DrawQuad>());
color_quad = SolidColorDrawQuad::Create();
- color_quad->SetNew(shared_quad_state, gfx::Rect(23, 20, 4, 7), 1u, false);
- quad_sink.Append(color_quad.PassAs<DrawQuad>(), &data);
+ color_quad->SetNew(shared_quad_state,
+ gfx::Rect(23, 20, 4, 7),
+ gfx::Rect(23, 20, 4, 7),
+ 1u,
+ false);
+ pass->AppendDrawQuad(color_quad.PassAs<DrawQuad>());
}
gfx::Size root_pass_content_bounds(100, 100);
@@ -560,51 +564,66 @@ class DelegatedRendererLayerImplTestTransform
RenderPass::Id(9, 6),
root_pass_rect,
gfx::Transform());
- MockQuadCuller quad_sink(&pass->quad_list, &pass->shared_quad_state_list);
- AppendQuadsData data(pass->id);
- SharedQuadState* shared_quad_state =
- quad_sink.UseSharedQuadState(SharedQuadState::Create());
+ SharedQuadState* shared_quad_state = pass->CreateAndAppendSharedQuadState();
shared_quad_state->SetAll(root_pass_transform,
root_pass_content_bounds,
root_pass_rect,
root_pass_clip_rect,
root_pass_clipped,
1.f,
- SkXfermode::kSrcOver_Mode);
+ SkXfermode::kSrcOver_Mode,
+ 0);
scoped_ptr<RenderPassDrawQuad> render_pass_quad =
RenderPassDrawQuad::Create();
render_pass_quad->SetNew(
shared_quad_state,
- gfx::Rect(5, 5, 7, 7), // rect
+ gfx::Rect(5, 5, 7, 7), // quad_rect
+ gfx::Rect(5, 5, 7, 7), // visible_rect
RenderPass::Id(10, 7), // render_pass_id
- false, // is_replica
- 0, // mask_resource_id
- child_pass_rect, // contents_changed_since_last_frame
- gfx::RectF(), // mask_uv_rect
- FilterOperations(), // filters
- FilterOperations()); // background_filters
- quad_sink.Append(render_pass_quad.PassAs<DrawQuad>(), &data);
+ false, // is_replica
+ 0, // mask_resource_id
+ child_pass_rect, // contents_changed_since_last_frame
+ gfx::RectF(), // mask_uv_rect
+ FilterOperations(), // filters
+ FilterOperations()); // background_filters
+ pass->AppendDrawQuad(render_pass_quad.PassAs<DrawQuad>());
scoped_ptr<SolidColorDrawQuad> color_quad;
color_quad = SolidColorDrawQuad::Create();
- color_quad->SetNew(shared_quad_state, gfx::Rect(0, 0, 10, 10), 1u, false);
- quad_sink.Append(color_quad.PassAs<DrawQuad>(), &data);
+ color_quad->SetNew(shared_quad_state,
+ gfx::Rect(0, 0, 10, 10),
+ gfx::Rect(0, 0, 10, 10),
+ 1u,
+ false);
+ pass->AppendDrawQuad(color_quad.PassAs<DrawQuad>());
color_quad = SolidColorDrawQuad::Create();
- color_quad->SetNew(shared_quad_state, gfx::Rect(0, 10, 10, 10), 2u, false);
- quad_sink.Append(color_quad.PassAs<DrawQuad>(), &data);
+ color_quad->SetNew(shared_quad_state,
+ gfx::Rect(0, 10, 10, 10),
+ gfx::Rect(0, 10, 10, 10),
+ 2u,
+ false);
+ pass->AppendDrawQuad(color_quad.PassAs<DrawQuad>());
color_quad = SolidColorDrawQuad::Create();
- color_quad->SetNew(shared_quad_state, gfx::Rect(10, 0, 10, 10), 3u, false);
- quad_sink.Append(color_quad.PassAs<DrawQuad>(), &data);
+ color_quad->SetNew(shared_quad_state,
+ gfx::Rect(10, 0, 10, 10),
+ gfx::Rect(10, 0, 10, 10),
+ 3u,
+ false);
+ pass->AppendDrawQuad(color_quad.PassAs<DrawQuad>());
color_quad = SolidColorDrawQuad::Create();
- color_quad->SetNew(shared_quad_state, gfx::Rect(10, 10, 10, 10), 4u, false);
- quad_sink.Append(color_quad.PassAs<DrawQuad>(), &data);
+ color_quad->SetNew(shared_quad_state,
+ gfx::Rect(10, 10, 10, 10),
+ gfx::Rect(10, 10, 10, 10),
+ 4u,
+ false);
+ pass->AppendDrawQuad(color_quad.PassAs<DrawQuad>());
delegated_renderer_layer->SetFrameDataForRenderPasses(
- &delegated_render_passes);
+ delegated_device_scale_factor_, &delegated_render_passes);
// The RenderPasses should be taken by the layer.
EXPECT_EQ(0u, delegated_render_passes.size());
@@ -662,6 +681,7 @@ class DelegatedRendererLayerImplTestTransform
LayerImpl* root_layer_;
DelegatedRendererLayerImpl* delegated_renderer_layer_;
bool root_delegated_render_pass_is_clipped_;
+ float delegated_device_scale_factor_;
};
TEST_F(DelegatedRendererLayerImplTestTransform, QuadsUnclipped_NoSurface) {
@@ -669,7 +689,7 @@ TEST_F(DelegatedRendererLayerImplTestTransform, QuadsUnclipped_NoSurface) {
SetUpTest();
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
const SharedQuadState* root_delegated_shared_quad_state = NULL;
const SharedQuadState* contrib_delegated_shared_quad_state = NULL;
@@ -690,16 +710,15 @@ TEST_F(DelegatedRendererLayerImplTestTransform, QuadsUnclipped_NoSurface) {
EXPECT_TRUE(root_delegated_shared_quad_state->is_clipped);
gfx::Transform expected;
- // Device scale factor is 2.
+ // Device scale factor.
expected.Scale(2.0, 2.0);
// This is the transform from the layer's space to its target.
- // The position (20) - the width / scale (75 / 2) = 20 - 37.5 = -17.5
- expected.Translate(-17.5, -17.5);
+ expected.Translate(20, 20);
expected.Scale(2.0, 2.0);
expected.Translate(8.0, 8.0);
- // The frame has size 100x100 but the layer's bounds are 75x75.
- expected.Scale(75.0 / 100.0, 75.0 / 100.0);
// This is the transform within the source frame.
+ // Inverse device scale factor to go from physical space to layer space.
+ expected.Scale(0.5, 0.5);
expected.Scale(1.5, 1.5);
expected.Translate(7.0, 7.0);
EXPECT_TRANSFORMATION_MATRIX_EQ(
@@ -725,7 +744,7 @@ TEST_F(DelegatedRendererLayerImplTestTransform, QuadsClipped_NoSurface) {
SetUpTest();
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
const SharedQuadState* root_delegated_shared_quad_state = NULL;
const SharedQuadState* contrib_delegated_shared_quad_state = NULL;
@@ -738,31 +757,27 @@ TEST_F(DelegatedRendererLayerImplTestTransform, QuadsClipped_NoSurface) {
// Since the quads have a clip_rect it should be modified by delegated
// renderer layer's draw_transform.
// The position of the resulting clip_rect is:
- // (clip rect position (10) * scale to layer (75/100) + translate (8)) *
- // layer scale (2) + layer position (20) = 51
- // But the layer is centered, so: 51 - (75 / 2) = 51 - 75 / 2 = 13.5
- // The device scale is 2, so everything gets doubled, giving 27.
+ // (clip rect position (10) * inverse dsf (1/2) + translate (8)) *
+ // layer scale (2) + layer position (20) = 46
+ // The device scale is 2, so everything gets doubled, giving 92.
//
- // The size is 35x35 scaled to fit inside the layer's bounds at 75x75 from
- // a frame at 100x100: 35 * 2 (device scale) * 75 / 100 = 52.5. The device
- // scale doubles this to 105.
- EXPECT_EQ(gfx::Rect(27, 27, 105, 105).ToString(),
+ // The size is 35x35 scaled by the device scale.
+ EXPECT_EQ(gfx::Rect(92, 92, 70, 70).ToString(),
root_delegated_shared_quad_state->clip_rect.ToString());
// The quads had a clip and it should be preserved.
EXPECT_TRUE(root_delegated_shared_quad_state->is_clipped);
gfx::Transform expected;
- // Device scale factor is 2.
+ // Device scale factor.
expected.Scale(2.0, 2.0);
// This is the transform from the layer's space to its target.
- // The position (20) - the width / scale (75 / 2) = 20 - 37.5 = -17.5
- expected.Translate(-17.5, -17.5);
+ expected.Translate(20, 20);
expected.Scale(2.0, 2.0);
expected.Translate(8.0, 8.0);
- // The frame has size 100x100 but the layer's bounds are 75x75.
- expected.Scale(75.0 / 100.0, 75.0 / 100.0);
// This is the transform within the source frame.
+ // Inverse device scale factor to go from physical space to layer space.
+ expected.Scale(0.5, 0.5);
expected.Scale(1.5, 1.5);
expected.Translate(7.0, 7.0);
EXPECT_TRANSFORMATION_MATRIX_EQ(
@@ -790,7 +805,7 @@ TEST_F(DelegatedRendererLayerImplTestTransform, QuadsUnclipped_Surface) {
delegated_renderer_layer_->SetForceRenderSurface(true);
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
const SharedQuadState* root_delegated_shared_quad_state = NULL;
const SharedQuadState* contrib_delegated_shared_quad_state = NULL;
@@ -802,11 +817,7 @@ TEST_F(DelegatedRendererLayerImplTestTransform, QuadsUnclipped_Surface) {
// When the layer owns a surface, then its position and translation are not
// a part of its draw transform.
- // The position of the resulting clip_rect is:
- // (clip rect position (10) * scale to layer (75/100)) * device scale (2) = 15
- // The size is 35x35 scaled to fit inside the layer's bounds at 75x75 from
- // a frame at 100x100: 35 * 2 (device scale) * 75 / 100 = 52.5.
- EXPECT_EQ(gfx::Rect(15, 15, 53, 53).ToString(),
+ EXPECT_EQ(gfx::Rect(10, 10, 35, 35).ToString(),
root_delegated_shared_quad_state->clip_rect.ToString());
// Since the layer owns a surface it doesn't need to clip its quads, so
@@ -814,10 +825,6 @@ TEST_F(DelegatedRendererLayerImplTestTransform, QuadsUnclipped_Surface) {
EXPECT_FALSE(root_delegated_shared_quad_state->is_clipped);
gfx::Transform expected;
- // Device scale factor is 2.
- expected.Scale(2.0, 2.0);
- // The frame has size 100x100 but the layer's bounds are 75x75.
- expected.Scale(75.0 / 100.0, 75.0 / 100.0);
// This is the transform within the source frame.
expected.Scale(1.5, 1.5);
expected.Translate(7.0, 7.0);
@@ -846,7 +853,7 @@ TEST_F(DelegatedRendererLayerImplTestTransform, QuadsClipped_Surface) {
delegated_renderer_layer_->SetForceRenderSurface(true);
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
const SharedQuadState* root_delegated_shared_quad_state = NULL;
const SharedQuadState* contrib_delegated_shared_quad_state = NULL;
@@ -857,22 +864,14 @@ TEST_F(DelegatedRendererLayerImplTestTransform, QuadsClipped_Surface) {
&contrib_delegated_shared_quad_state);
// When the layer owns a surface, then its position and translation are not
- // a part of its draw transform.
- // The position of the resulting clip_rect is:
- // (clip rect position (10) * scale to layer (75/100)) * device scale (2) = 15
- // The size is 35x35 scaled to fit inside the layer's bounds at 75x75 from
- // a frame at 100x100: 35 * 2 (device scale) * 75 / 100 = 52.5.
- EXPECT_EQ(gfx::Rect(15, 15, 53, 53).ToString(),
+ // a part of its draw transform. The clip_rect should be preserved.
+ EXPECT_EQ(gfx::Rect(10, 10, 35, 35).ToString(),
root_delegated_shared_quad_state->clip_rect.ToString());
// The quads had a clip and it should be preserved.
EXPECT_TRUE(root_delegated_shared_quad_state->is_clipped);
gfx::Transform expected;
- // Device scale factor is 2.
- expected.Scale(2.0, 2.0);
- // The frame has size 100x100 but the layer's bounds are 75x75.
- expected.Scale(75.0 / 100.0, 75.0 / 100.0);
// This is the transform within the source frame.
expected.Scale(1.5, 1.5);
expected.Translate(7.0, 7.0);
@@ -894,6 +893,45 @@ TEST_F(DelegatedRendererLayerImplTestTransform, QuadsClipped_Surface) {
host_impl_->DidDrawAllLayers(frame);
}
+TEST_F(DelegatedRendererLayerImplTestTransform, MismatchedDeviceScaleFactor) {
+ root_delegated_render_pass_is_clipped_ = true;
+ delegated_device_scale_factor_ = 1.3f;
+
+ SetUpTest();
+
+ LayerTreeHostImpl::FrameData frame;
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
+
+ const SharedQuadState* root_delegated_shared_quad_state = NULL;
+ const SharedQuadState* contrib_delegated_shared_quad_state = NULL;
+ VerifyRenderPasses(frame,
+ 2,
+ &root_delegated_shared_quad_state,
+ &contrib_delegated_shared_quad_state);
+
+ // The parent tree's device scale factor is 2.0, but the child has submitted a
+ // frame with a device scale factor of 1.3. Absent any better option, the
+ // only thing we can do is scale from 1.3 -> 2.0.
+
+ gfx::Transform expected;
+ // Device scale factor (from parent).
+ expected.Scale(2.0, 2.0);
+ // This is the transform from the layer's space to its target.
+ expected.Translate(20, 20);
+ expected.Scale(2.0, 2.0);
+ expected.Translate(8.0, 8.0);
+ // This is the transform within the source frame.
+ // Inverse device scale factor (from child).
+ expected.Scale(1.0f / 1.3f, 1.0f / 1.3f);
+ expected.Scale(1.5, 1.5);
+ expected.Translate(7.0, 7.0);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(
+ expected, root_delegated_shared_quad_state->content_to_target_transform);
+
+ host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DidDrawAllLayers(frame);
+}
+
class DelegatedRendererLayerImplTestClip
: public DelegatedRendererLayerImplTest {
public:
@@ -929,26 +967,33 @@ class DelegatedRendererLayerImplTestClip
RenderPass::Id(10, 7),
child_pass_rect,
gfx::Transform());
- MockQuadCuller quad_sink(&pass->quad_list, &pass->shared_quad_state_list);
- AppendQuadsData data(pass->id);
SharedQuadState* shared_quad_state =
- quad_sink.UseSharedQuadState(SharedQuadState::Create());
+ pass->CreateAndAppendSharedQuadState();
shared_quad_state->SetAll(child_pass_transform,
child_pass_content_bounds,
child_pass_rect,
child_pass_clip_rect,
child_pass_clipped,
1.f,
- SkXfermode::kSrcOver_Mode);
+ SkXfermode::kSrcOver_Mode,
+ 0);
scoped_ptr<SolidColorDrawQuad> color_quad;
color_quad = SolidColorDrawQuad::Create();
- color_quad->SetNew(shared_quad_state, gfx::Rect(20, 20, 3, 7), 1u, false);
- quad_sink.Append(color_quad.PassAs<DrawQuad>(), &data);
+ color_quad->SetNew(shared_quad_state,
+ gfx::Rect(20, 20, 3, 7),
+ gfx::Rect(20, 20, 3, 7),
+ 1u,
+ false);
+ pass->AppendDrawQuad(color_quad.PassAs<DrawQuad>());
color_quad = SolidColorDrawQuad::Create();
- color_quad->SetNew(shared_quad_state, gfx::Rect(23, 20, 4, 7), 1u, false);
- quad_sink.Append(color_quad.PassAs<DrawQuad>(), &data);
+ color_quad->SetNew(shared_quad_state,
+ gfx::Rect(23, 20, 4, 7),
+ gfx::Rect(23, 20, 4, 7),
+ 1u,
+ false);
+ pass->AppendDrawQuad(color_quad.PassAs<DrawQuad>());
}
gfx::Size root_pass_content_bounds(50, 50);
@@ -962,51 +1007,66 @@ class DelegatedRendererLayerImplTestClip
RenderPass::Id(9, 6),
root_pass_rect,
gfx::Transform());
- MockQuadCuller quad_sink(&pass->quad_list, &pass->shared_quad_state_list);
- AppendQuadsData data(pass->id);
- SharedQuadState* shared_quad_state =
- quad_sink.UseSharedQuadState(SharedQuadState::Create());
+ SharedQuadState* shared_quad_state = pass->CreateAndAppendSharedQuadState();
shared_quad_state->SetAll(root_pass_transform,
root_pass_content_bounds,
root_pass_rect,
root_pass_clip_rect,
root_pass_clipped,
1.f,
- SkXfermode::kSrcOver_Mode);
+ SkXfermode::kSrcOver_Mode,
+ 0);
scoped_ptr<RenderPassDrawQuad> render_pass_quad =
RenderPassDrawQuad::Create();
render_pass_quad->SetNew(
shared_quad_state,
- gfx::Rect(5, 5, 7, 7), // rect
+ gfx::Rect(5, 5, 7, 7), // quad_rect
+ gfx::Rect(5, 5, 7, 7), // visible_quad_rect
RenderPass::Id(10, 7), // render_pass_id
- false, // is_replica
- 0, // mask_resource_id
- child_pass_rect, // contents_changed_since_last_frame
- gfx::RectF(), // mask_uv_rect
- FilterOperations(), // filters
- FilterOperations()); // background_filters
- quad_sink.Append(render_pass_quad.PassAs<DrawQuad>(), &data);
+ false, // is_replica
+ 0, // mask_resource_id
+ child_pass_rect, // contents_changed_since_last_frame
+ gfx::RectF(), // mask_uv_rect
+ FilterOperations(), // filters
+ FilterOperations()); // background_filters
+ pass->AppendDrawQuad(render_pass_quad.PassAs<DrawQuad>());
scoped_ptr<SolidColorDrawQuad> color_quad;
color_quad = SolidColorDrawQuad::Create();
- color_quad->SetNew(shared_quad_state, gfx::Rect(0, 0, 10, 10), 1u, false);
- quad_sink.Append(color_quad.PassAs<DrawQuad>(), &data);
+ color_quad->SetNew(shared_quad_state,
+ gfx::Rect(0, 0, 10, 10),
+ gfx::Rect(0, 0, 10, 10),
+ 1u,
+ false);
+ pass->AppendDrawQuad(color_quad.PassAs<DrawQuad>());
color_quad = SolidColorDrawQuad::Create();
- color_quad->SetNew(shared_quad_state, gfx::Rect(0, 10, 10, 10), 2u, false);
- quad_sink.Append(color_quad.PassAs<DrawQuad>(), &data);
+ color_quad->SetNew(shared_quad_state,
+ gfx::Rect(0, 10, 10, 10),
+ gfx::Rect(0, 10, 10, 10),
+ 2u,
+ false);
+ pass->AppendDrawQuad(color_quad.PassAs<DrawQuad>());
color_quad = SolidColorDrawQuad::Create();
- color_quad->SetNew(shared_quad_state, gfx::Rect(10, 0, 10, 10), 3u, false);
- quad_sink.Append(color_quad.PassAs<DrawQuad>(), &data);
+ color_quad->SetNew(shared_quad_state,
+ gfx::Rect(10, 0, 10, 10),
+ gfx::Rect(10, 0, 10, 10),
+ 3u,
+ false);
+ pass->AppendDrawQuad(color_quad.PassAs<DrawQuad>());
color_quad = SolidColorDrawQuad::Create();
- color_quad->SetNew(shared_quad_state, gfx::Rect(10, 10, 10, 10), 4u, false);
- quad_sink.Append(color_quad.PassAs<DrawQuad>(), &data);
+ color_quad->SetNew(shared_quad_state,
+ gfx::Rect(10, 10, 10, 10),
+ gfx::Rect(10, 10, 10, 10),
+ 4u,
+ false);
+ pass->AppendDrawQuad(color_quad.PassAs<DrawQuad>());
delegated_renderer_layer->SetFrameDataForRenderPasses(
- &delegated_render_passes);
+ 1.f, &delegated_render_passes);
// The RenderPasses should be taken by the layer.
EXPECT_EQ(0u, delegated_render_passes.size());
@@ -1049,7 +1109,7 @@ TEST_F(DelegatedRendererLayerImplTestClip,
SetUpTest();
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
ASSERT_EQ(2u, frame.render_passes.size());
const QuadList& contrib_delegated_quad_list =
@@ -1078,7 +1138,7 @@ TEST_F(DelegatedRendererLayerImplTestClip,
SetUpTest();
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
ASSERT_EQ(2u, frame.render_passes.size());
const QuadList& contrib_delegated_quad_list =
@@ -1107,7 +1167,7 @@ TEST_F(DelegatedRendererLayerImplTestClip,
SetUpTest();
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
ASSERT_EQ(2u, frame.render_passes.size());
const QuadList& contrib_delegated_quad_list =
@@ -1137,7 +1197,7 @@ TEST_F(DelegatedRendererLayerImplTestClip,
SetUpTest();
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
ASSERT_EQ(2u, frame.render_passes.size());
const QuadList& contrib_delegated_quad_list =
@@ -1168,7 +1228,7 @@ TEST_F(DelegatedRendererLayerImplTestClip,
delegated_renderer_layer_->SetForceRenderSurface(true);
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
ASSERT_EQ(3u, frame.render_passes.size());
const QuadList& contrib_delegated_quad_list =
@@ -1197,7 +1257,7 @@ TEST_F(DelegatedRendererLayerImplTestClip,
delegated_renderer_layer_->SetForceRenderSurface(true);
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
ASSERT_EQ(3u, frame.render_passes.size());
const QuadList& contrib_delegated_quad_list =
@@ -1227,7 +1287,7 @@ TEST_F(DelegatedRendererLayerImplTestClip,
delegated_renderer_layer_->SetForceRenderSurface(true);
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
ASSERT_EQ(3u, frame.render_passes.size());
const QuadList& contrib_delegated_quad_list =
@@ -1255,7 +1315,7 @@ TEST_F(DelegatedRendererLayerImplTestClip, QuadsClipped_LayerClipped_Surface) {
delegated_renderer_layer_->SetForceRenderSurface(true);
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
ASSERT_EQ(3u, frame.render_passes.size());
const QuadList& contrib_delegated_quad_list =
@@ -1310,7 +1370,7 @@ TEST_F(DelegatedRendererLayerImplTest, InvalidRenderPassDrawQuad) {
AddRenderPassQuad(pass1, missing_pass.get());
delegated_renderer_layer->SetFrameDataForRenderPasses(
- &delegated_render_passes);
+ 1.f, &delegated_render_passes);
// The RenderPasses should be taken by the layer.
EXPECT_EQ(0u, delegated_render_passes.size());
@@ -1319,7 +1379,7 @@ TEST_F(DelegatedRendererLayerImplTest, InvalidRenderPassDrawQuad) {
host_impl_->active_tree()->SetRootLayer(root_layer.Pass());
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
// The DelegatedRendererLayerImpl should drop the bad RenderPassDrawQuad.
ASSERT_EQ(1u, frame.render_passes.size());
@@ -1331,5 +1391,166 @@ TEST_F(DelegatedRendererLayerImplTest, InvalidRenderPassDrawQuad) {
host_impl_->DidDrawAllLayers(frame);
}
+TEST_F(DelegatedRendererLayerImplTest, Occlusion) {
+ gfx::Size layer_size(1000, 1000);
+ gfx::Size viewport_size(1000, 1000);
+ gfx::Rect quad_rect(200, 300, 400, 500);
+
+ gfx::Transform transform;
+ transform.Translate(11.0, 0.0);
+
+ LayerTestCommon::LayerImplTest impl;
+
+ FakeDelegatedRendererLayerImpl* delegated_renderer_layer_impl =
+ impl.AddChildToRoot<FakeDelegatedRendererLayerImpl>();
+ delegated_renderer_layer_impl->SetBounds(layer_size);
+ delegated_renderer_layer_impl->SetContentBounds(layer_size);
+ delegated_renderer_layer_impl->SetDrawsContent(true);
+
+ ScopedPtrVector<RenderPass> delegated_render_passes;
+ // pass2 is just the size of the quad. It contributes to |pass1| with a
+ // translation of (11,0).
+ RenderPass::Id pass2_id =
+ delegated_renderer_layer_impl->FirstContributingRenderPassId();
+ TestRenderPass* pass2 =
+ AddRenderPass(&delegated_render_passes, pass2_id, quad_rect, transform);
+ AddQuad(pass2, gfx::Rect(quad_rect.size()), SK_ColorRED);
+ // |pass1| covers the whole layer.
+ RenderPass::Id pass1_id = RenderPass::Id(impl.root_layer()->id(), 0);
+ TestRenderPass* pass1 = AddRenderPass(&delegated_render_passes,
+ pass1_id,
+ gfx::Rect(layer_size),
+ gfx::Transform());
+ AddRenderPassQuad(pass1, pass2, 0, FilterOperations(), transform);
+ delegated_renderer_layer_impl->SetFrameDataForRenderPasses(
+ 1.f, &delegated_render_passes);
+
+ impl.CalcDrawProps(viewport_size);
+
+ // The |quad_rect| translated by the |transform|.
+ gfx::Rect quad_screen_rect = quad_rect + gfx::Vector2d(11, 0);
+
+ {
+ SCOPED_TRACE("No occlusion");
+ gfx::Rect occluded;
+
+ {
+ SCOPED_TRACE("Root render pass");
+ impl.AppendQuadsForPassWithOcclusion(
+ delegated_renderer_layer_impl, pass1_id, occluded);
+ LayerTestCommon::VerifyQuadsExactlyCoverRect(impl.quad_list(),
+ quad_screen_rect);
+ ASSERT_EQ(1u, impl.quad_list().size());
+ EXPECT_EQ(DrawQuad::RENDER_PASS, impl.quad_list()[0]->material);
+ }
+ {
+ SCOPED_TRACE("Contributing render pass");
+ impl.AppendQuadsForPassWithOcclusion(
+ delegated_renderer_layer_impl, pass2_id, occluded);
+ LayerTestCommon::VerifyQuadsExactlyCoverRect(impl.quad_list(),
+ gfx::Rect(quad_rect.size()));
+ ASSERT_EQ(1u, impl.quad_list().size());
+ EXPECT_EQ(DrawQuad::SOLID_COLOR, impl.quad_list()[0]->material);
+ }
+ }
+
+ {
+ SCOPED_TRACE("Full occlusion");
+ {
+ gfx::Rect occluded(delegated_renderer_layer_impl->visible_content_rect());
+
+ SCOPED_TRACE("Root render pass");
+ impl.AppendQuadsForPassWithOcclusion(
+ delegated_renderer_layer_impl, pass1_id, occluded);
+ LayerTestCommon::VerifyQuadsExactlyCoverRect(impl.quad_list(),
+ gfx::Rect());
+ EXPECT_EQ(impl.quad_list().size(), 0u);
+ }
+ {
+ gfx::Rect occluded(delegated_renderer_layer_impl->visible_content_rect());
+ // Move the occlusion to where it is in the contributing surface.
+ occluded -= quad_rect.OffsetFromOrigin();
+
+ SCOPED_TRACE("Contributing render pass");
+ impl.AppendQuadsForPassWithOcclusion(
+ delegated_renderer_layer_impl, pass2_id, occluded);
+ LayerTestCommon::VerifyQuadsExactlyCoverRect(impl.quad_list(),
+ gfx::Rect());
+ EXPECT_EQ(impl.quad_list().size(), 0u);
+ }
+ }
+
+ {
+ SCOPED_TRACE("Partial occlusion");
+ {
+ gfx::Rect occluded(0, 0, 500, 1000);
+
+ SCOPED_TRACE("Root render pass");
+ impl.AppendQuadsForPassWithOcclusion(
+ delegated_renderer_layer_impl, pass1_id, occluded);
+ size_t partially_occluded_count = 0;
+ LayerTestCommon::VerifyQuadsCoverRectWithOcclusion(
+ impl.quad_list(),
+ quad_screen_rect,
+ occluded,
+ &partially_occluded_count);
+ // The layer outputs one quad, which is partially occluded.
+ EXPECT_EQ(1u, impl.quad_list().size());
+ EXPECT_EQ(1u, partially_occluded_count);
+ }
+ {
+ gfx::Rect occluded(0, 0, 500, 1000);
+ // Move the occlusion to where it is in the contributing surface.
+ occluded -= quad_rect.OffsetFromOrigin() + gfx::Vector2d(11, 0);
+
+ SCOPED_TRACE("Contributing render pass");
+ impl.AppendQuadsForPassWithOcclusion(
+ delegated_renderer_layer_impl, pass2_id, occluded);
+ size_t partially_occluded_count = 0;
+ LayerTestCommon::VerifyQuadsCoverRectWithOcclusion(
+ impl.quad_list(),
+ gfx::Rect(quad_rect.size()),
+ occluded,
+ &partially_occluded_count);
+ // The layer outputs one quad, which is partially occluded.
+ EXPECT_EQ(1u, impl.quad_list().size());
+ EXPECT_EQ(1u, partially_occluded_count);
+ // The quad in the contributing surface is at (211,300) in the root.
+ // The occlusion extends to 500 in the x-axis, pushing the left of the
+ // visible part of the quad to 500 - 211 = 300 - 11 inside the quad.
+ EXPECT_EQ(gfx::Rect(300 - 11, 0, 100 + 11, 500).ToString(),
+ impl.quad_list()[0]->visible_rect.ToString());
+ }
+ }
+}
+
+TEST_F(DelegatedRendererLayerImplTest, PushPropertiesTo) {
+ gfx::Size layer_size(1000, 1000);
+
+ scoped_ptr<FakeDelegatedRendererLayerImpl> delegated_renderer_layer_impl =
+ FakeDelegatedRendererLayerImpl::Create(host_impl_->active_tree(), 5);
+ delegated_renderer_layer_impl->SetBounds(layer_size);
+ delegated_renderer_layer_impl->SetContentBounds(layer_size);
+ delegated_renderer_layer_impl->SetDrawsContent(true);
+
+ RenderPassList delegated_render_passes;
+ // |pass1| covers the whole layer.
+ RenderPass::Id pass1_id = RenderPass::Id(5, 0);
+ AddRenderPass(&delegated_render_passes,
+ pass1_id,
+ gfx::Rect(layer_size),
+ gfx::Transform());
+ delegated_renderer_layer_impl->SetFrameDataForRenderPasses(
+ 2.f, &delegated_render_passes);
+ EXPECT_EQ(0.5f, delegated_renderer_layer_impl->inverse_device_scale_factor());
+
+ scoped_ptr<DelegatedRendererLayerImpl> other_layer =
+ DelegatedRendererLayerImpl::Create(host_impl_->active_tree(), 6);
+
+ delegated_renderer_layer_impl->PushPropertiesTo(other_layer.get());
+
+ EXPECT_EQ(0.5f, other_layer->inverse_device_scale_factor());
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/layers/draw_properties.h b/chromium/cc/layers/draw_properties.h
index 5fd42a49e94..a0bfc2a6f2f 100644
--- a/chromium/cc/layers/draw_properties.h
+++ b/chromium/cc/layers/draw_properties.h
@@ -29,12 +29,18 @@ struct CC_EXPORT DrawProperties {
num_descendants_that_draw_content(0),
num_unclipped_descendants(0),
layer_or_descendant_has_copy_request(false),
+ layer_or_descendant_has_input_handler(false),
has_child_with_a_scroll_parent(false),
sorted_for_recursion(false),
index_of_first_descendants_addition(0),
num_descendants_added(0),
index_of_first_render_surface_layer_list_addition(0),
- num_render_surfaces_added(0) {}
+ num_render_surfaces_added(0),
+ last_drawn_render_surface_layer_list_id(0),
+ ideal_contents_scale(0.f),
+ maximum_animation_contents_scale(0.f),
+ page_scale_factor(0.f),
+ device_scale_factor(0.f) {}
// Transforms objects from content space to target surface space, where
// this layer would be drawn.
@@ -101,6 +107,9 @@ struct CC_EXPORT DrawProperties {
// present on it.
bool layer_or_descendant_has_copy_request;
+ // If true, the layer or one of its descendants has a wheel or touch handler.
+ bool layer_or_descendant_has_input_handler;
+
// This is true if the layer has any direct child that has a scroll parent.
// This layer will not be the scroll parent in this case. This information
// lets us avoid work in CalculateDrawPropertiesInternal -- if none of our
@@ -118,6 +127,30 @@ struct CC_EXPORT DrawProperties {
size_t num_descendants_added;
size_t index_of_first_render_surface_layer_list_addition;
size_t num_render_surfaces_added;
+
+ // Each time we generate a new render surface layer list, an ID is used to
+ // identify it. |last_drawn_render_surface_layer_list_id| is set to the ID
+ // that marked the render surface layer list generation which last updated
+ // these draw properties and determined that this layer will draw itself.
+ // If these draw properties are not a part of the render surface layer list,
+ // or the layer doesn't contribute anything, then this ID will be either out
+ // of date or 0.
+ int last_drawn_render_surface_layer_list_id;
+
+ // The scale at which content for the layer should be rastered in order to be
+ // perfectly crisp.
+ float ideal_contents_scale;
+
+ // The maximum scale during the layers current animation at which content
+ // should be rastered at to be crisp.
+ float maximum_animation_contents_scale;
+
+ // The page scale factor that is applied to the layer. Since some layers may
+ // have page scale applied and others not, this may differ between layers.
+ float page_scale_factor;
+
+ // The device scale factor that is applied to the layer.
+ float device_scale_factor;
};
} // namespace cc
diff --git a/chromium/cc/layers/heads_up_display_layer.cc b/chromium/cc/layers/heads_up_display_layer.cc
index d9fab902ef9..ca63471e303 100644
--- a/chromium/cc/layers/heads_up_display_layer.cc
+++ b/chromium/cc/layers/heads_up_display_layer.cc
@@ -21,7 +21,7 @@ HeadsUpDisplayLayer::HeadsUpDisplayLayer() {}
HeadsUpDisplayLayer::~HeadsUpDisplayLayer() {}
void HeadsUpDisplayLayer::PrepareForCalculateDrawProperties(
- gfx::Size device_viewport, float device_scale_factor) {
+ const gfx::Size& device_viewport, float device_scale_factor) {
gfx::Size device_viewport_in_layout_pixels = gfx::Size(
device_viewport.width() / device_scale_factor,
device_viewport.height() / device_scale_factor);
@@ -55,8 +55,4 @@ scoped_ptr<LayerImpl> HeadsUpDisplayLayer::CreateLayerImpl(
PassAs<LayerImpl>();
}
-std::string HeadsUpDisplayLayer::DebugName() {
- return std::string("Heads Up Display Layer");
-}
-
} // namespace cc
diff --git a/chromium/cc/layers/heads_up_display_layer.h b/chromium/cc/layers/heads_up_display_layer.h
index f13d56bba67..4750fafc7ed 100644
--- a/chromium/cc/layers/heads_up_display_layer.h
+++ b/chromium/cc/layers/heads_up_display_layer.h
@@ -18,15 +18,13 @@ class CC_EXPORT HeadsUpDisplayLayer : public ContentsScalingLayer {
static scoped_refptr<HeadsUpDisplayLayer> Create();
void PrepareForCalculateDrawProperties(
- gfx::Size device_viewport, float device_scale_factor);
+ const gfx::Size& device_viewport, float device_scale_factor);
virtual bool DrawsContent() const OVERRIDE;
virtual scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl)
OVERRIDE;
- virtual std::string DebugName() OVERRIDE;
-
protected:
HeadsUpDisplayLayer();
diff --git a/chromium/cc/layers/heads_up_display_layer_impl.cc b/chromium/cc/layers/heads_up_display_layer_impl.cc
index da4784074cf..6149a06be0c 100644
--- a/chromium/cc/layers/heads_up_display_layer_impl.cc
+++ b/chromium/cc/layers/heads_up_display_layer_impl.cc
@@ -9,7 +9,6 @@
#include "base/strings/stringprintf.h"
#include "cc/debug/debug_colors.h"
-#include "cc/debug/debug_rect_history.h"
#include "cc/debug/frame_rate_counter.h"
#include "cc/debug/paint_time_counter.h"
#include "cc/debug/traced_value.h"
@@ -44,7 +43,7 @@ static inline SkPaint CreatePaint() {
swizzle_matrix.fMat[3 + 5 * 3] = 1;
skia::RefPtr<SkColorMatrixFilter> filter =
- skia::AdoptRef(new SkColorMatrixFilter(swizzle_matrix));
+ skia::AdoptRef(SkColorMatrixFilter::Create(swizzle_matrix));
paint.setColorFilter(filter.get());
#endif
return paint;
@@ -71,7 +70,8 @@ HeadsUpDisplayLayerImpl::HeadsUpDisplayLayerImpl(LayerTreeImpl* tree_impl,
typeface_(skia::AdoptRef(
SkTypeface::CreateFromName("monospace", SkTypeface::kBold))),
fps_graph_(60.0, 80.0),
- paint_time_graph_(16.0, 48.0) {}
+ paint_time_graph_(16.0, 48.0),
+ fade_step_(0) {}
HeadsUpDisplayLayerImpl::~HeadsUpDisplayLayerImpl() {}
@@ -110,11 +110,12 @@ void HeadsUpDisplayLayerImpl::AppendQuads(QuadSink* quad_sink,
if (!hud_resource_->id())
return;
- SharedQuadState* shared_quad_state =
- quad_sink->UseSharedQuadState(CreateSharedQuadState());
+ SharedQuadState* shared_quad_state = quad_sink->CreateSharedQuadState();
+ PopulateSharedQuadState(shared_quad_state);
gfx::Rect quad_rect(content_bounds());
gfx::Rect opaque_rect(contents_opaque() ? quad_rect : gfx::Rect());
+ gfx::Rect visible_quad_rect(quad_rect);
bool premultiplied_alpha = true;
gfx::PointF uv_top_left(0.f, 0.f);
gfx::PointF uv_bottom_right(1.f, 1.f);
@@ -124,6 +125,7 @@ void HeadsUpDisplayLayerImpl::AppendQuads(QuadSink* quad_sink,
quad->SetNew(shared_quad_state,
quad_rect,
opaque_rect,
+ visible_quad_rect,
hud_resource_->id(),
premultiplied_alpha,
uv_top_left,
@@ -131,7 +133,7 @@ void HeadsUpDisplayLayerImpl::AppendQuads(QuadSink* quad_sink,
SK_ColorTRANSPARENT,
vertex_opacity,
flipped);
- quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
+ quad_sink->Append(quad.PassAs<DrawQuad>());
}
void HeadsUpDisplayLayerImpl::UpdateHudTexture(
@@ -147,7 +149,7 @@ void HeadsUpDisplayLayerImpl::UpdateHudTexture(
canvas_size.set(0, 0);
if (canvas_size.width() != content_bounds().width() ||
- canvas_size.width() != content_bounds().height() || !hud_canvas_) {
+ canvas_size.height() != content_bounds().height() || !hud_canvas_) {
TRACE_EVENT0("cc", "ResizeHudCanvas");
bool opaque = false;
hud_canvas_ = make_scoped_ptr(skia::CreateBitmapCanvas(
@@ -168,21 +170,20 @@ void HeadsUpDisplayLayerImpl::UpdateHudTexture(
}
TRACE_EVENT0("cc", "UploadHudTexture");
- const SkBitmap* bitmap = &hud_canvas_->getDevice()->accessBitmap(false);
- SkAutoLockPixels locker(*bitmap);
-
+ SkImageInfo info;
+ size_t row_bytes = 0;
+ const void* pixels = hud_canvas_->peekPixels(&info, &row_bytes);
+ DCHECK(pixels);
gfx::Rect content_rect(content_bounds());
- DCHECK(bitmap->config() == SkBitmap::kARGB_8888_Config);
+ DCHECK(info.colorType() == kPMColor_SkColorType);
resource_provider->SetPixels(hud_resource_->id(),
- static_cast<const uint8_t*>(bitmap->getPixels()),
+ static_cast<const uint8_t*>(pixels),
content_rect,
content_rect,
gfx::Vector2d());
}
-void HeadsUpDisplayLayerImpl::DidLoseOutputSurface() { hud_resource_.reset(); }
-
-bool HeadsUpDisplayLayerImpl::LayerIsAlwaysDamaged() const { return true; }
+void HeadsUpDisplayLayerImpl::ReleaseResources() { hud_resource_.reset(); }
void HeadsUpDisplayLayerImpl::UpdateHudContents() {
const LayerTreeDebugState& debug_state = layer_tree_impl()->debug_state();
@@ -225,11 +226,15 @@ void HeadsUpDisplayLayerImpl::UpdateHudContents() {
paint_time_graph_.UpdateUpperBound();
}
-void HeadsUpDisplayLayerImpl::DrawHudContents(SkCanvas* canvas) const {
+void HeadsUpDisplayLayerImpl::DrawHudContents(SkCanvas* canvas) {
const LayerTreeDebugState& debug_state = layer_tree_impl()->debug_state();
- if (debug_state.ShowHudRects())
+ if (debug_state.ShowHudRects()) {
DrawDebugRects(canvas, layer_tree_impl()->debug_rect_history());
+ if (IsAnimatingHUDContents()) {
+ layer_tree_impl()->SetNeedsRedraw();
+ }
+ }
SkRect area = SkRect::MakeEmpty();
if (debug_state.continuous_painting) {
@@ -586,12 +591,71 @@ SkRect HeadsUpDisplayLayerImpl::DrawPaintTimeDisplay(
return area;
}
+void HeadsUpDisplayLayerImpl::DrawDebugRect(
+ SkCanvas* canvas,
+ SkPaint& paint,
+ const DebugRect& rect,
+ SkColor stroke_color,
+ SkColor fill_color,
+ float stroke_width,
+ const std::string& label_text) const {
+ gfx::Rect debug_layer_rect = gfx::ScaleToEnclosingRect(
+ rect.rect, 1.0 / contents_scale_x(), 1.0 / contents_scale_y());
+ SkIRect sk_rect = RectToSkIRect(debug_layer_rect);
+ paint.setColor(fill_color);
+ paint.setStyle(SkPaint::kFill_Style);
+ canvas->drawIRect(sk_rect, paint);
+
+ paint.setColor(stroke_color);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(SkFloatToScalar(stroke_width));
+ canvas->drawIRect(sk_rect, paint);
+
+ if (label_text.length()) {
+ const int kFontHeight = 12;
+ const int kPadding = 3;
+
+ // The debug_layer_rect may be huge, and converting to a floating point may
+ // be lossy, so intersect with the HUD layer bounds first to prevent that.
+ gfx::Rect clip_rect = debug_layer_rect;
+ clip_rect.Intersect(gfx::Rect(content_bounds()));
+ SkRect sk_clip_rect = RectToSkRect(clip_rect);
+
+ canvas->save();
+ canvas->clipRect(sk_clip_rect);
+ canvas->translate(sk_clip_rect.x(), sk_clip_rect.y());
+
+ SkPaint label_paint = CreatePaint();
+ label_paint.setTextSize(kFontHeight);
+ label_paint.setTypeface(typeface_.get());
+ label_paint.setColor(stroke_color);
+
+ const SkScalar label_text_width =
+ label_paint.measureText(label_text.c_str(), label_text.length());
+ canvas->drawRect(SkRect::MakeWH(label_text_width + 2 * kPadding,
+ kFontHeight + 2 * kPadding),
+ label_paint);
+
+ label_paint.setAntiAlias(true);
+ label_paint.setColor(SkColorSetARGB(255, 50, 50, 50));
+ canvas->drawText(label_text.c_str(),
+ label_text.length(),
+ kPadding,
+ kFontHeight * 0.8f + kPadding,
+ label_paint);
+
+ canvas->restore();
+ }
+}
+
void HeadsUpDisplayLayerImpl::DrawDebugRects(
SkCanvas* canvas,
- DebugRectHistory* debug_rect_history) const {
- const std::vector<DebugRect>& debug_rects = debug_rect_history->debug_rects();
+ DebugRectHistory* debug_rect_history) {
SkPaint paint = CreatePaint();
+ const std::vector<DebugRect>& debug_rects = debug_rect_history->debug_rects();
+ std::vector<DebugRect> new_paint_rects;
+
for (size_t i = 0; i < debug_rects.size(); ++i) {
SkColor stroke_color = 0;
SkColor fill_color = 0;
@@ -600,10 +664,8 @@ void HeadsUpDisplayLayerImpl::DrawDebugRects(
switch (debug_rects[i].type) {
case PAINT_RECT_TYPE:
- stroke_color = DebugColors::PaintRectBorderColor();
- fill_color = DebugColors::PaintRectFillColor();
- stroke_width = DebugColors::PaintRectBorderWidth();
- break;
+ new_paint_rects.push_back(debug_rects[i]);
+ continue;
case PROPERTY_CHANGED_RECT_TYPE:
stroke_color = DebugColors::PropertyChangedRectBorderColor();
fill_color = DebugColors::PropertyChangedRectFillColor();
@@ -646,6 +708,12 @@ void HeadsUpDisplayLayerImpl::DrawDebugRects(
stroke_width = DebugColors::WheelEventHandlerRectBorderWidth();
label_text = "mousewheel event listener";
break;
+ case SCROLL_EVENT_HANDLER_RECT_TYPE:
+ stroke_color = DebugColors::ScrollEventHandlerRectBorderColor();
+ fill_color = DebugColors::ScrollEventHandlerRectFillColor();
+ stroke_width = DebugColors::ScrollEventHandlerRectBorderWidth();
+ label_text = "scroll event listener";
+ break;
case NON_FAST_SCROLLABLE_RECT_TYPE:
stroke_color = DebugColors::NonFastScrollableRectBorderColor();
fill_color = DebugColors::NonFastScrollableRectFillColor();
@@ -660,47 +728,29 @@ void HeadsUpDisplayLayerImpl::DrawDebugRects(
break;
}
- gfx::RectF debug_layer_rect = gfx::ScaleRect(debug_rects[i].rect,
- 1.0 / contents_scale_x(),
- 1.0 / contents_scale_y());
- SkRect sk_rect = RectFToSkRect(debug_layer_rect);
- paint.setColor(fill_color);
- paint.setStyle(SkPaint::kFill_Style);
- canvas->drawRect(sk_rect, paint);
-
- paint.setColor(stroke_color);
- paint.setStyle(SkPaint::kStroke_Style);
- paint.setStrokeWidth(SkFloatToScalar(stroke_width));
- canvas->drawRect(sk_rect, paint);
-
- if (label_text.length()) {
- const int kFontHeight = 12;
- const int kPadding = 3;
-
- canvas->save();
- canvas->clipRect(sk_rect);
- canvas->translate(sk_rect.x(), sk_rect.y());
-
- SkPaint label_paint = CreatePaint();
- label_paint.setTextSize(kFontHeight);
- label_paint.setTypeface(typeface_.get());
- label_paint.setColor(stroke_color);
-
- const SkScalar label_text_width =
- label_paint.measureText(label_text.c_str(), label_text.length());
- canvas->drawRect(SkRect::MakeWH(label_text_width + 2 * kPadding,
- kFontHeight + 2 * kPadding),
- label_paint);
-
- label_paint.setAntiAlias(true);
- label_paint.setColor(SkColorSetARGB(255, 50, 50, 50));
- canvas->drawText(label_text.c_str(),
- label_text.length(),
- kPadding,
- kFontHeight * 0.8f + kPadding,
- label_paint);
-
- canvas->restore();
+ DrawDebugRect(canvas,
+ paint,
+ debug_rects[i],
+ stroke_color,
+ fill_color,
+ stroke_width,
+ label_text);
+ }
+
+ if (new_paint_rects.size()) {
+ paint_rects_.swap(new_paint_rects);
+ fade_step_ = DebugColors::kFadeSteps;
+ }
+ if (fade_step_ > 0) {
+ fade_step_--;
+ for (size_t i = 0; i < paint_rects_.size(); ++i) {
+ DrawDebugRect(canvas,
+ paint,
+ paint_rects_[i],
+ DebugColors::PaintRectBorderColor(fade_step_),
+ DebugColors::PaintRectFillColor(fade_step_),
+ DebugColors::PaintRectBorderWidth(),
+ "");
}
}
}
@@ -709,4 +759,9 @@ const char* HeadsUpDisplayLayerImpl::LayerTypeAsString() const {
return "cc::HeadsUpDisplayLayerImpl";
}
+void HeadsUpDisplayLayerImpl::AsValueInto(base::DictionaryValue* dict) const {
+ LayerImpl::AsValueInto(dict);
+ dict->SetString("layer_name", "Heads Up Display Layer");
+}
+
} // namespace cc
diff --git a/chromium/cc/layers/heads_up_display_layer_impl.h b/chromium/cc/layers/heads_up_display_layer_impl.h
index fa38f15eafe..ec51b6e5766 100644
--- a/chromium/cc/layers/heads_up_display_layer_impl.h
+++ b/chromium/cc/layers/heads_up_display_layer_impl.h
@@ -6,10 +6,12 @@
#define CC_LAYERS_HEADS_UP_DISPLAY_LAYER_IMPL_H_
#include <string>
+#include <vector>
#include "base/memory/scoped_ptr.h"
#include "base/time/time.h"
#include "cc/base/cc_export.h"
+#include "cc/debug/debug_rect_history.h"
#include "cc/layers/layer_impl.h"
#include "cc/resources/memory_history.h"
#include "cc/resources/scoped_resource.h"
@@ -21,7 +23,6 @@ struct SkRect;
namespace cc {
-class DebugRectHistory;
class FrameRateCounter;
class PaintTimeCounter;
@@ -43,9 +44,9 @@ class CC_EXPORT HeadsUpDisplayLayerImpl : public LayerImpl {
void UpdateHudTexture(DrawMode draw_mode,
ResourceProvider* resource_provider);
- virtual void DidLoseOutputSurface() OVERRIDE;
+ virtual void ReleaseResources() OVERRIDE;
- virtual bool LayerIsAlwaysDamaged() const OVERRIDE;
+ bool IsAnimatingHUDContents() const { return fade_step_ > 0; }
private:
class Graph {
@@ -70,8 +71,10 @@ class CC_EXPORT HeadsUpDisplayLayerImpl : public LayerImpl {
virtual const char* LayerTypeAsString() const OVERRIDE;
+ virtual void AsValueInto(base::DictionaryValue* dict) const OVERRIDE;
+
void UpdateHudContents();
- void DrawHudContents(SkCanvas* canvas) const;
+ void DrawHudContents(SkCanvas* canvas);
void DrawText(SkCanvas* canvas,
SkPaint* paint,
@@ -106,8 +109,14 @@ class CC_EXPORT HeadsUpDisplayLayerImpl : public LayerImpl {
const PaintTimeCounter* paint_time_counter,
int top,
int right) const;
- void DrawDebugRects(SkCanvas* canvas,
- DebugRectHistory* debug_rect_history) const;
+ void DrawDebugRect(SkCanvas* canvas,
+ SkPaint& paint,
+ const DebugRect& rect,
+ SkColor stroke_color,
+ SkColor fill_color,
+ float stroke_width,
+ const std::string& label_text) const;
+ void DrawDebugRects(SkCanvas* canvas, DebugRectHistory* debug_rect_history);
scoped_ptr<ScopedResource> hud_resource_;
scoped_ptr<SkCanvas> hud_canvas_;
@@ -117,6 +126,8 @@ class CC_EXPORT HeadsUpDisplayLayerImpl : public LayerImpl {
Graph fps_graph_;
Graph paint_time_graph_;
MemoryHistory::Entry memory_entry_;
+ int fade_step_;
+ std::vector<DebugRect> paint_rects_;
base::TimeTicks time_of_last_graph_update_;
diff --git a/chromium/cc/layers/heads_up_display_layer_impl_unittest.cc b/chromium/cc/layers/heads_up_display_layer_impl_unittest.cc
index 5afc01956d8..2c58e6a16fa 100644
--- a/chromium/cc/layers/heads_up_display_layer_impl_unittest.cc
+++ b/chromium/cc/layers/heads_up_display_layer_impl_unittest.cc
@@ -8,6 +8,7 @@
#include "cc/test/fake_layer_tree_host_impl.h"
#include "cc/test/fake_output_surface.h"
#include "cc/test/mock_quad_culler.h"
+#include "cc/test/test_shared_bitmap_manager.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace cc {
@@ -16,7 +17,9 @@ namespace {
void CheckDrawLayer(HeadsUpDisplayLayerImpl* layer,
ResourceProvider* resource_provider,
DrawMode draw_mode) {
- MockQuadCuller quad_culler;
+ MockOcclusionTracker<LayerImpl> occlusion_tracker;
+ scoped_ptr<RenderPass> render_pass = RenderPass::Create();
+ MockQuadCuller quad_culler(render_pass.get(), &occlusion_tracker);
AppendQuadsData data;
bool will_draw = layer->WillDraw(draw_mode, resource_provider);
if (will_draw)
@@ -31,9 +34,11 @@ void CheckDrawLayer(HeadsUpDisplayLayerImpl* layer,
TEST(HeadsUpDisplayLayerImplTest, ResourcelessSoftwareDrawAfterResourceLoss) {
FakeImplProxy proxy;
- FakeLayerTreeHostImpl host_impl(&proxy);
+ TestSharedBitmapManager shared_bitmap_manager;
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
host_impl.CreatePendingTree();
- host_impl.InitializeRenderer(CreateFakeOutputSurface());
+ host_impl.InitializeRenderer(
+ FakeOutputSurface::Create3d().PassAs<OutputSurface>());
scoped_ptr<HeadsUpDisplayLayerImpl> layer =
HeadsUpDisplayLayerImpl::Create(host_impl.pending_tree(), 1);
layer->SetContentBounds(gfx::Size(100, 100));
@@ -43,7 +48,7 @@ TEST(HeadsUpDisplayLayerImplTest, ResourcelessSoftwareDrawAfterResourceLoss) {
layer.get(), host_impl.resource_provider(), DRAW_MODE_HARDWARE);
// Simulate a resource loss on transitioning to resourceless software mode.
- layer->DidLoseOutputSurface();
+ layer->ReleaseResources();
// Should skip resourceless software draw and not crash in UpdateHudTexture.
CheckDrawLayer(layer.get(),
diff --git a/chromium/cc/layers/image_layer.cc b/chromium/cc/layers/image_layer.cc
index 2f90bfc50a8..cada84df3cc 100644
--- a/chromium/cc/layers/image_layer.cc
+++ b/chromium/cc/layers/image_layer.cc
@@ -41,7 +41,7 @@ void ImageLayer::SetTexturePriorities(const PriorityCalculator& priority_calc) {
}
bool ImageLayer::Update(ResourceUpdateQueue* queue,
- const OcclusionTracker* occlusion) {
+ const OcclusionTracker<Layer>* occlusion) {
CreateUpdaterIfNeeded();
if (!updater_->UsingBitmap(bitmap_)) {
updater_->SetBitmap(bitmap_);
@@ -67,6 +67,7 @@ LayerUpdater* ImageLayer::Updater() const {
void ImageLayer::CalculateContentsScale(float ideal_contents_scale,
float device_scale_factor,
float page_scale_factor,
+ float maximum_animation_contents_scale,
bool animating_transform_to_screen,
float* contents_scale_x,
float* contents_scale_y,
diff --git a/chromium/cc/layers/image_layer.h b/chromium/cc/layers/image_layer.h
index 6cd82755bfc..2f3255f092a 100644
--- a/chromium/cc/layers/image_layer.h
+++ b/chromium/cc/layers/image_layer.h
@@ -23,10 +23,11 @@ class CC_EXPORT ImageLayer : public TiledLayer {
virtual void SetTexturePriorities(const PriorityCalculator& priority_calc)
OVERRIDE;
virtual bool Update(ResourceUpdateQueue* queue,
- const OcclusionTracker* occlusion) OVERRIDE;
+ const OcclusionTracker<Layer>* occlusion) OVERRIDE;
virtual void CalculateContentsScale(float ideal_contents_scale,
float device_scale_factor,
float page_scale_factor,
+ float maximum_animation_contents_scale,
bool animating_transform_to_screen,
float* contents_scale_x,
float* contents_scale_y,
diff --git a/chromium/cc/layers/io_surface_layer.cc b/chromium/cc/layers/io_surface_layer.cc
index 1e945150a0c..98d3dfef1ba 100644
--- a/chromium/cc/layers/io_surface_layer.cc
+++ b/chromium/cc/layers/io_surface_layer.cc
@@ -17,7 +17,7 @@ IOSurfaceLayer::IOSurfaceLayer() : Layer(), io_surface_id_(0) {}
IOSurfaceLayer::~IOSurfaceLayer() {}
void IOSurfaceLayer::SetIOSurfaceProperties(uint32_t io_surface_id,
- gfx::Size size) {
+ const gfx::Size& size) {
io_surface_id_ = io_surface_id;
io_surface_size_ = size;
SetNeedsCommit();
@@ -41,7 +41,7 @@ void IOSurfaceLayer::PushPropertiesTo(LayerImpl* layer) {
}
bool IOSurfaceLayer::Update(ResourceUpdateQueue* queue,
- const OcclusionTracker* occlusion) {
+ const OcclusionTracker<Layer>* occlusion) {
bool updated = Layer::Update(queue, occlusion);
// This layer doesn't update any resources from the main thread side,
diff --git a/chromium/cc/layers/io_surface_layer.h b/chromium/cc/layers/io_surface_layer.h
index e2e831a7e87..80e5b691737 100644
--- a/chromium/cc/layers/io_surface_layer.h
+++ b/chromium/cc/layers/io_surface_layer.h
@@ -14,14 +14,14 @@ class CC_EXPORT IOSurfaceLayer : public Layer {
public:
static scoped_refptr<IOSurfaceLayer> Create();
- void SetIOSurfaceProperties(uint32_t io_surface_id, gfx::Size size);
+ void SetIOSurfaceProperties(uint32_t io_surface_id, const gfx::Size& size);
virtual scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl)
OVERRIDE;
virtual bool DrawsContent() const OVERRIDE;
virtual void PushPropertiesTo(LayerImpl* layer) OVERRIDE;
virtual bool Update(ResourceUpdateQueue* queue,
- const OcclusionTracker* occlusion) OVERRIDE;
+ const OcclusionTracker<Layer>* occlusion) OVERRIDE;
protected:
IOSurfaceLayer();
diff --git a/chromium/cc/layers/io_surface_layer_impl.cc b/chromium/cc/layers/io_surface_layer_impl.cc
index a70006a69c9..65fb6b22308 100644
--- a/chromium/cc/layers/io_surface_layer_impl.cc
+++ b/chromium/cc/layers/io_surface_layer_impl.cc
@@ -21,32 +21,19 @@ IOSurfaceLayerImpl::IOSurfaceLayerImpl(LayerTreeImpl* tree_impl, int id)
: LayerImpl(tree_impl, id),
io_surface_id_(0),
io_surface_changed_(false),
- io_surface_texture_id_(0),
io_surface_resource_id_(0) {}
IOSurfaceLayerImpl::~IOSurfaceLayerImpl() {
- if (!io_surface_texture_id_)
- return;
-
- DestroyTexture();
+ DestroyResource();
}
-void IOSurfaceLayerImpl::DestroyTexture() {
+void IOSurfaceLayerImpl::DestroyResource() {
if (io_surface_resource_id_) {
ResourceProvider* resource_provider =
layer_tree_impl()->resource_provider();
resource_provider->DeleteResource(io_surface_resource_id_);
io_surface_resource_id_ = 0;
}
-
- if (io_surface_texture_id_) {
- ContextProvider* context_provider =
- layer_tree_impl()->output_surface()->context_provider().get();
- // TODO(skaslev): Implement this path for software compositing.
- if (context_provider)
- context_provider->ContextGL()->DeleteTextures(1, &io_surface_texture_id_);
- io_surface_texture_id_ = 0;
- }
}
scoped_ptr<LayerImpl> IOSurfaceLayerImpl::CreateLayerImpl(
@@ -64,41 +51,13 @@ void IOSurfaceLayerImpl::PushPropertiesTo(LayerImpl* layer) {
bool IOSurfaceLayerImpl::WillDraw(DrawMode draw_mode,
ResourceProvider* resource_provider) {
- if (draw_mode == DRAW_MODE_RESOURCELESS_SOFTWARE)
+ if (draw_mode != DRAW_MODE_HARDWARE)
return false;
if (io_surface_changed_) {
- ContextProvider* context_provider =
- layer_tree_impl()->output_surface()->context_provider().get();
- if (!context_provider) {
- // TODO(skaslev): Implement this path for software compositing.
- return false;
- }
-
- gpu::gles2::GLES2Interface* gl = context_provider->ContextGL();
-
- // TODO(ernstm): Do this in a way that we can track memory usage.
- if (!io_surface_texture_id_) {
- gl->GenTextures(1, &io_surface_texture_id_);
- io_surface_resource_id_ =
- resource_provider->CreateResourceFromExternalTexture(
- GL_TEXTURE_RECTANGLE_ARB,
- io_surface_texture_id_);
- }
-
- GLC(gl, gl->BindTexture(GL_TEXTURE_RECTANGLE_ARB, io_surface_texture_id_));
- gl->TexImageIOSurface2DCHROMIUM(GL_TEXTURE_RECTANGLE_ARB,
- io_surface_size_.width(),
- io_surface_size_.height(),
- io_surface_id_,
- 0);
- // Do not check for error conditions. texImageIOSurface2DCHROMIUM() is
- // supposed to hold on to the last good IOSurface if the new one is already
- // closed. This is only a possibility during live resizing of plugins.
- // However, it seems that this is not sufficient to completely guard against
- // garbage being drawn. If this is found to be a significant issue, it may
- // be necessary to explicitly tell the embedder when to free the surfaces it
- // has allocated.
+ DestroyResource();
+ io_surface_resource_id_ = resource_provider->CreateResourceFromIOSurface(
+ io_surface_size_, io_surface_id_);
io_surface_changed_ = false;
}
@@ -107,31 +66,39 @@ bool IOSurfaceLayerImpl::WillDraw(DrawMode draw_mode,
void IOSurfaceLayerImpl::AppendQuads(QuadSink* quad_sink,
AppendQuadsData* append_quads_data) {
- SharedQuadState* shared_quad_state =
- quad_sink->UseSharedQuadState(CreateSharedQuadState());
- AppendDebugBorderQuad(quad_sink, shared_quad_state, append_quads_data);
+ SharedQuadState* shared_quad_state = quad_sink->CreateSharedQuadState();
+ PopulateSharedQuadState(shared_quad_state);
+
+ AppendDebugBorderQuad(
+ quad_sink, content_bounds(), shared_quad_state, append_quads_data);
gfx::Rect quad_rect(content_bounds());
gfx::Rect opaque_rect(contents_opaque() ? quad_rect : gfx::Rect());
+ gfx::Rect visible_quad_rect = quad_sink->UnoccludedContentRect(
+ quad_rect, draw_properties().target_space_transform);
+ if (visible_quad_rect.IsEmpty())
+ return;
+
scoped_ptr<IOSurfaceDrawQuad> quad = IOSurfaceDrawQuad::Create();
quad->SetNew(shared_quad_state,
quad_rect,
opaque_rect,
+ visible_quad_rect,
io_surface_size_,
io_surface_resource_id_,
IOSurfaceDrawQuad::FLIPPED);
- quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
+ quad_sink->Append(quad.PassAs<DrawQuad>());
}
-void IOSurfaceLayerImpl::DidLoseOutputSurface() {
- // We don't have a valid texture ID in the new context; however,
+void IOSurfaceLayerImpl::ReleaseResources() {
+ // We don't have a valid resource ID in the new context; however,
// the IOSurface is still valid.
- DestroyTexture();
+ DestroyResource();
io_surface_changed_ = true;
}
void IOSurfaceLayerImpl::SetIOSurfaceProperties(unsigned io_surface_id,
- gfx::Size size) {
+ const gfx::Size& size) {
if (io_surface_id_ != io_surface_id)
io_surface_changed_ = true;
diff --git a/chromium/cc/layers/io_surface_layer_impl.h b/chromium/cc/layers/io_surface_layer_impl.h
index 356f5f299a4..8ac9a2511f4 100644
--- a/chromium/cc/layers/io_surface_layer_impl.h
+++ b/chromium/cc/layers/io_surface_layer_impl.h
@@ -21,7 +21,7 @@ class CC_EXPORT IOSurfaceLayerImpl : public LayerImpl {
}
virtual ~IOSurfaceLayerImpl();
- void SetIOSurfaceProperties(unsigned io_surface_id, gfx::Size size);
+ void SetIOSurfaceProperties(unsigned io_surface_id, const gfx::Size& size);
virtual scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl)
OVERRIDE;
@@ -32,19 +32,18 @@ class CC_EXPORT IOSurfaceLayerImpl : public LayerImpl {
virtual bool WillDraw(DrawMode draw_mode,
ResourceProvider* resource_provider) OVERRIDE;
- virtual void DidLoseOutputSurface() OVERRIDE;
+ virtual void ReleaseResources() OVERRIDE;
private:
IOSurfaceLayerImpl(LayerTreeImpl* tree_impl, int id);
- void DestroyTexture();
+ void DestroyResource();
virtual const char* LayerTypeAsString() const OVERRIDE;
unsigned io_surface_id_;
gfx::Size io_surface_size_;
bool io_surface_changed_;
- unsigned io_surface_texture_id_;
unsigned io_surface_resource_id_;
DISALLOW_COPY_AND_ASSIGN(IOSurfaceLayerImpl);
diff --git a/chromium/cc/layers/io_surface_layer_impl_unittest.cc b/chromium/cc/layers/io_surface_layer_impl_unittest.cc
new file mode 100644
index 00000000000..e5ee7897806
--- /dev/null
+++ b/chromium/cc/layers/io_surface_layer_impl_unittest.cc
@@ -0,0 +1,64 @@
+// 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/layers/io_surface_layer_impl.h"
+
+#include "cc/test/layer_test_common.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+namespace {
+
+TEST(IOSurfaceLayerImplTest, Occlusion) {
+ gfx::Size layer_size(1000, 1000);
+ gfx::Size viewport_size(1000, 1000);
+
+ LayerTestCommon::LayerImplTest impl;
+
+ IOSurfaceLayerImpl* io_surface_layer_impl =
+ impl.AddChildToRoot<IOSurfaceLayerImpl>();
+ io_surface_layer_impl->SetBounds(layer_size);
+ io_surface_layer_impl->SetContentBounds(layer_size);
+ io_surface_layer_impl->SetDrawsContent(true);
+
+ impl.CalcDrawProps(viewport_size);
+
+ {
+ SCOPED_TRACE("No occlusion");
+ gfx::Rect occluded;
+ impl.AppendQuadsWithOcclusion(io_surface_layer_impl, occluded);
+
+ LayerTestCommon::VerifyQuadsExactlyCoverRect(impl.quad_list(),
+ gfx::Rect(layer_size));
+ EXPECT_EQ(1u, impl.quad_list().size());
+ }
+
+ {
+ SCOPED_TRACE("Full occlusion");
+ gfx::Rect occluded(io_surface_layer_impl->visible_content_rect());
+ impl.AppendQuadsWithOcclusion(io_surface_layer_impl, occluded);
+
+ LayerTestCommon::VerifyQuadsExactlyCoverRect(impl.quad_list(), gfx::Rect());
+ EXPECT_EQ(impl.quad_list().size(), 0u);
+ }
+
+ {
+ SCOPED_TRACE("Partial occlusion");
+ gfx::Rect occluded(200, 0, 800, 1000);
+ impl.AppendQuadsWithOcclusion(io_surface_layer_impl, occluded);
+
+ size_t partially_occluded_count = 0;
+ LayerTestCommon::VerifyQuadsCoverRectWithOcclusion(
+ impl.quad_list(),
+ gfx::Rect(layer_size),
+ occluded,
+ &partially_occluded_count);
+ // The layer outputs one quad, which is partially occluded.
+ EXPECT_EQ(1u, impl.quad_list().size());
+ EXPECT_EQ(1u, partially_occluded_count);
+ }
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/layers/layer.cc b/chromium/cc/layers/layer.cc
index f7682fd912f..e00d2c5b905 100644
--- a/chromium/cc/layers/layer.cc
+++ b/chromium/cc/layers/layer.cc
@@ -6,26 +6,30 @@
#include <algorithm>
+#include "base/atomic_sequence_num.h"
#include "base/debug/trace_event.h"
#include "base/location.h"
#include "base/metrics/histogram.h"
#include "base/single_thread_task_runner.h"
+#include "base/time/time.h"
#include "cc/animation/animation.h"
#include "cc/animation/animation_events.h"
#include "cc/animation/keyframed_animation_curve.h"
#include "cc/animation/layer_animation_controller.h"
#include "cc/layers/layer_client.h"
#include "cc/layers/layer_impl.h"
+#include "cc/layers/scrollbar_layer_interface.h"
#include "cc/output/copy_output_request.h"
#include "cc/output/copy_output_result.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/layer_tree_impl.h"
#include "third_party/skia/include/core/SkImageFilter.h"
+#include "ui/gfx/geometry/vector2d_conversions.h"
#include "ui/gfx/rect_conversions.h"
namespace cc {
-static int s_next_layer_id = 1;
+base::StaticAtomicSequenceNumber g_next_layer_id;
scoped_refptr<Layer> Layer::Create() {
return make_scoped_refptr(new Layer());
@@ -35,13 +39,16 @@ Layer::Layer()
: needs_push_properties_(false),
num_dependents_need_push_properties_(false),
stacking_order_changed_(false),
- layer_id_(s_next_layer_id++),
+ // Layer IDs start from 1.
+ layer_id_(g_next_layer_id.GetNext() + 1),
ignore_set_needs_commit_(false),
+ sorting_context_id_(0),
parent_(NULL),
layer_tree_host_(NULL),
- scrollable_(false),
+ scroll_clip_layer_id_(INVALID_ID),
should_scroll_on_main_thread_(false),
have_wheel_event_handlers_(false),
+ have_scroll_event_handlers_(false),
user_scrollable_horizontal_(true),
user_scrollable_vertical_(true),
is_root_for_isolated_group_(false),
@@ -51,26 +58,19 @@ Layer::Layer()
masks_to_bounds_(false),
contents_opaque_(false),
double_sided_(true),
- preserves_3d_(false),
+ should_flatten_transform_(true),
use_parent_backface_visibility_(false),
draw_checkerboard_for_missing_tiles_(false),
force_render_surface_(false),
- anchor_point_(0.5f, 0.5f),
+ transform_is_invertible_(true),
background_color_(0),
- compositing_reasons_(kCompositingReasonUnknown),
opacity_(1.f),
blend_mode_(SkXfermode::kSrcOver_Mode),
- anchor_point_z_(0.f),
scroll_parent_(NULL),
clip_parent_(NULL),
replica_layer_(NULL),
raster_scale_(0.f),
client_(NULL) {
- if (layer_id_ < 0) {
- s_next_layer_id = 1;
- layer_id_ = s_next_layer_id++;
- }
-
layer_animation_controller_ = LayerAnimationController::Create(layer_id_);
layer_animation_controller_->AddValueObserver(this);
layer_animation_controller_->set_value_provider(this);
@@ -130,7 +130,6 @@ void Layer::SetLayerTreeHost(LayerTreeHost* host) {
if (host && layer_animation_controller_->has_any_animation())
host->SetNeedsCommit();
- SetNeedsFilterContextIfNeeded();
}
void Layer::SetNeedsUpdate() {
@@ -164,15 +163,6 @@ void Layer::SetNextCommitWaitsForActivation() {
layer_tree_host_->SetNextCommitWaitsForActivation();
}
-void Layer::SetNeedsFilterContextIfNeeded() {
- if (!layer_tree_host_)
- return;
-
- if (!filters_.IsEmpty() || !background_filters_.IsEmpty() ||
- !uses_default_blend_mode())
- layer_tree_host_->set_needs_filter_context();
-}
-
void Layer::SetNeedsPushProperties() {
if (needs_push_properties_)
return;
@@ -325,7 +315,7 @@ int Layer::IndexOfChild(const Layer* reference) {
return -1;
}
-void Layer::SetBounds(gfx::Size size) {
+void Layer::SetBounds(const gfx::Size& size) {
DCHECK(IsPropertyChangeAllowed());
if (bounds() == size)
return;
@@ -377,22 +367,6 @@ void Layer::RequestCopyOfOutput(
SetNeedsCommit();
}
-void Layer::SetAnchorPoint(gfx::PointF anchor_point) {
- DCHECK(IsPropertyChangeAllowed());
- if (anchor_point_ == anchor_point)
- return;
- anchor_point_ = anchor_point;
- SetNeedsCommit();
-}
-
-void Layer::SetAnchorPointZ(float anchor_point_z) {
- DCHECK(IsPropertyChangeAllowed());
- if (anchor_point_z_ == anchor_point_z)
- return;
- anchor_point_z_ = anchor_point_z;
- SetNeedsCommit();
-}
-
void Layer::SetBackgroundColor(SkColor background_color) {
DCHECK(IsPropertyChangeAllowed());
if (background_color_ == background_color)
@@ -420,14 +394,14 @@ SkColor Layer::SafeOpaqueBackgroundColor() const {
return color;
}
-void Layer::CalculateContentsScale(
- float ideal_contents_scale,
- float device_scale_factor,
- float page_scale_factor,
- bool animating_transform_to_screen,
- float* contents_scale_x,
- float* contents_scale_y,
- gfx::Size* content_bounds) {
+void Layer::CalculateContentsScale(float ideal_contents_scale,
+ float device_scale_factor,
+ float page_scale_factor,
+ float maximum_animation_contents_scale,
+ bool animating_transform_to_screen,
+ float* contents_scale_x,
+ float* contents_scale_y,
+ gfx::Size* content_bounds) {
DCHECK(layer_tree_host_);
*contents_scale_x = 1;
@@ -484,7 +458,6 @@ void Layer::SetFilters(const FilterOperations& filters) {
return;
filters_ = filters;
SetNeedsCommit();
- SetNeedsFilterContextIfNeeded();
}
bool Layer::FilterIsAnimating() const {
@@ -497,7 +470,6 @@ void Layer::SetBackgroundFilters(const FilterOperations& filters) {
return;
background_filters_ = filters;
SetNeedsCommit();
- SetNeedsFilterContextIfNeeded();
}
void Layer::SetOpacity(float opacity) {
@@ -563,7 +535,6 @@ void Layer::SetBlendMode(SkXfermode::Mode blend_mode) {
blend_mode_ = blend_mode;
SetNeedsCommit();
- SetNeedsFilterContextIfNeeded();
}
void Layer::SetIsRootForIsolatedGroup(bool root) {
@@ -582,7 +553,7 @@ void Layer::SetContentsOpaque(bool opaque) {
SetNeedsCommit();
}
-void Layer::SetPosition(gfx::PointF position) {
+void Layer::SetPosition(const gfx::PointF& position) {
DCHECK(IsPropertyChangeAllowed());
if (position_ == position)
return;
@@ -593,24 +564,25 @@ void Layer::SetPosition(gfx::PointF position) {
bool Layer::IsContainerForFixedPositionLayers() const {
if (!transform_.IsIdentityOrTranslation())
return true;
- if (parent_ && !parent_->sublayer_transform_.IsIdentityOrTranslation())
+ if (parent_ && !parent_->transform_.IsIdentityOrTranslation())
return true;
return is_container_for_fixed_position_layers_;
}
-void Layer::SetSublayerTransform(const gfx::Transform& sublayer_transform) {
+void Layer::SetTransform(const gfx::Transform& transform) {
DCHECK(IsPropertyChangeAllowed());
- if (sublayer_transform_ == sublayer_transform)
+ if (transform_ == transform)
return;
- sublayer_transform_ = sublayer_transform;
+ transform_ = transform;
+ transform_is_invertible_ = transform.IsInvertible();
SetNeedsCommit();
}
-void Layer::SetTransform(const gfx::Transform& transform) {
+void Layer::SetTransformOrigin(const gfx::Point3F& transform_origin) {
DCHECK(IsPropertyChangeAllowed());
- if (transform_ == transform)
+ if (transform_origin_ == transform_origin)
return;
- transform_ = transform;
+ transform_origin_ = transform_origin;
SetNeedsCommit();
}
@@ -680,13 +652,14 @@ void Layer::RemoveClipChild(Layer* child) {
void Layer::SetScrollOffset(gfx::Vector2d scroll_offset) {
DCHECK(IsPropertyChangeAllowed());
+
if (scroll_offset_ == scroll_offset)
return;
scroll_offset_ = scroll_offset;
SetNeedsCommit();
}
-void Layer::SetScrollOffsetFromImplSide(gfx::Vector2d scroll_offset) {
+void Layer::SetScrollOffsetFromImplSide(const gfx::Vector2d& scroll_offset) {
DCHECK(IsPropertyChangeAllowed());
// This function only gets called during a BeginMainFrame, so there
// is no need to call SetNeedsUpdate here.
@@ -701,19 +674,11 @@ void Layer::SetScrollOffsetFromImplSide(gfx::Vector2d scroll_offset) {
// "this" may have been destroyed during the process.
}
-void Layer::SetMaxScrollOffset(gfx::Vector2d max_scroll_offset) {
+void Layer::SetScrollClipLayerId(int clip_layer_id) {
DCHECK(IsPropertyChangeAllowed());
- if (max_scroll_offset_ == max_scroll_offset)
+ if (scroll_clip_layer_id_ == clip_layer_id)
return;
- max_scroll_offset_ = max_scroll_offset;
- SetNeedsCommit();
-}
-
-void Layer::SetScrollable(bool scrollable) {
- DCHECK(IsPropertyChangeAllowed());
- if (scrollable_ == scrollable)
- return;
- scrollable_ = scrollable;
+ scroll_clip_layer_id_ = clip_layer_id;
SetNeedsCommit();
}
@@ -743,6 +708,14 @@ void Layer::SetHaveWheelEventHandlers(bool have_wheel_event_handlers) {
SetNeedsCommit();
}
+void Layer::SetHaveScrollEventHandlers(bool have_scroll_event_handlers) {
+ DCHECK(IsPropertyChangeAllowed());
+ if (have_scroll_event_handlers_ == have_scroll_event_handlers)
+ return;
+ have_scroll_event_handlers_ = have_scroll_event_handlers;
+ SetNeedsCommit();
+}
+
void Layer::SetNonFastScrollableRegion(const Region& region) {
DCHECK(IsPropertyChangeAllowed());
if (non_fast_scrollable_region_ == region)
@@ -783,6 +756,22 @@ void Layer::SetDoubleSided(bool double_sided) {
SetNeedsCommit();
}
+void Layer::Set3dSortingContextId(int id) {
+ DCHECK(IsPropertyChangeAllowed());
+ if (id == sorting_context_id_)
+ return;
+ sorting_context_id_ = id;
+ SetNeedsCommit();
+}
+
+void Layer::SetShouldFlattenTransform(bool should_flatten) {
+ DCHECK(IsPropertyChangeAllowed());
+ if (should_flatten_transform_ == should_flatten)
+ return;
+ should_flatten_transform_ = should_flatten;
+ SetNeedsCommit();
+}
+
void Layer::SetIsDrawable(bool is_drawable) {
DCHECK(IsPropertyChangeAllowed());
if (is_drawable_ == is_drawable)
@@ -865,8 +854,7 @@ void Layer::PushPropertiesTo(LayerImpl* layer) {
bool use_paint_properties = paint_properties_.source_frame_number ==
layer_tree_host_->source_frame_number();
- layer->SetAnchorPoint(anchor_point_);
- layer->SetAnchorPointZ(anchor_point_z_);
+ layer->SetTransformOrigin(transform_origin_);
layer->SetBackgroundColor(background_color_);
layer->SetBounds(use_paint_properties ? paint_properties_.bounds
: bounds_);
@@ -876,14 +864,9 @@ void Layer::PushPropertiesTo(LayerImpl* layer) {
bool is_tracing;
TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
&is_tracing);
- if (is_tracing) {
- layer->SetDebugName(DebugName());
+ if (is_tracing)
layer->SetDebugInfo(TakeDebugInfo());
- } else {
- layer->SetDebugName(std::string());
- }
- layer->SetCompositingReasons(compositing_reasons_);
layer->SetDoubleSided(double_sided_);
layer->SetDrawCheckerboardForMissingTiles(
draw_checkerboard_for_missing_tiles_);
@@ -897,6 +880,7 @@ void Layer::PushPropertiesTo(LayerImpl* layer) {
layer->SetMasksToBounds(masks_to_bounds_);
layer->SetShouldScrollOnMainThread(should_scroll_on_main_thread_);
layer->SetHaveWheelEventHandlers(have_wheel_event_handlers_);
+ layer->SetHaveScrollEventHandlers(have_scroll_event_handlers_);
layer->SetNonFastScrollableRegion(non_fast_scrollable_region_);
layer->SetTouchEventHandlerRegion(touch_event_handler_region_);
layer->SetContentsOpaque(contents_opaque_);
@@ -908,37 +892,46 @@ void Layer::PushPropertiesTo(LayerImpl* layer) {
layer->SetPosition(position_);
layer->SetIsContainerForFixedPositionLayers(
IsContainerForFixedPositionLayers());
- layer->SetFixedContainerSizeDelta(gfx::Vector2dF());
layer->SetPositionConstraint(position_constraint_);
- layer->SetPreserves3d(preserves_3d());
+ layer->SetShouldFlattenTransform(should_flatten_transform_);
layer->SetUseParentBackfaceVisibility(use_parent_backface_visibility_);
- layer->SetSublayerTransform(sublayer_transform_);
if (!layer->TransformIsAnimatingOnImplOnly() && !TransformIsAnimating())
- layer->SetTransform(transform_);
+ layer->SetTransformAndInvertibility(transform_, transform_is_invertible_);
DCHECK(!(TransformIsAnimating() && layer->TransformIsAnimatingOnImplOnly()));
+ layer->Set3dSortingContextId(sorting_context_id_);
- layer->SetScrollable(scrollable_);
+ layer->SetScrollClipLayer(scroll_clip_layer_id_);
layer->set_user_scrollable_horizontal(user_scrollable_horizontal_);
layer->set_user_scrollable_vertical(user_scrollable_vertical_);
- layer->SetMaxScrollOffset(max_scroll_offset_);
LayerImpl* scroll_parent = NULL;
- if (scroll_parent_)
+ if (scroll_parent_) {
scroll_parent = layer->layer_tree_impl()->LayerById(scroll_parent_->id());
+ DCHECK(scroll_parent);
+ }
layer->SetScrollParent(scroll_parent);
if (scroll_children_) {
std::set<LayerImpl*>* scroll_children = new std::set<LayerImpl*>;
for (std::set<Layer*>::iterator it = scroll_children_->begin();
- it != scroll_children_->end(); ++it)
- scroll_children->insert(layer->layer_tree_impl()->LayerById((*it)->id()));
+ it != scroll_children_->end();
+ ++it) {
+ DCHECK_EQ((*it)->scroll_parent(), this);
+ LayerImpl* scroll_child =
+ layer->layer_tree_impl()->LayerById((*it)->id());
+ DCHECK(scroll_child);
+ scroll_children->insert(scroll_child);
+ }
layer->SetScrollChildren(scroll_children);
+ } else {
+ layer->SetScrollChildren(NULL);
}
LayerImpl* clip_parent = NULL;
if (clip_parent_) {
clip_parent =
layer->layer_tree_impl()->LayerById(clip_parent_->id());
+ DCHECK(clip_parent);
}
layer->SetClipParent(clip_parent);
@@ -946,11 +939,14 @@ void Layer::PushPropertiesTo(LayerImpl* layer) {
std::set<LayerImpl*>* clip_children = new std::set<LayerImpl*>;
for (std::set<Layer*>::iterator it = clip_children_->begin();
it != clip_children_->end(); ++it) {
+ DCHECK_EQ((*it)->clip_parent(), this);
LayerImpl* clip_child = layer->layer_tree_impl()->LayerById((*it)->id());
DCHECK(clip_child);
clip_children->insert(clip_child);
}
layer->SetClipChildren(clip_children);
+ } else {
+ layer->SetClipChildren(NULL);
}
// Adjust the scroll delta to be just the scrolls that have happened since
@@ -989,7 +985,7 @@ void Layer::PushPropertiesTo(LayerImpl* layer) {
// update_rect here. The LayerImpl's update_rect needs to accumulate (i.e.
// union) any update changes that have occurred on the main thread.
update_rect_.Union(layer->update_rect());
- layer->set_update_rect(update_rect_);
+ layer->SetUpdateRect(update_rect_);
layer->SetStackingOrderChanged(stacking_order_changed_);
@@ -1023,7 +1019,7 @@ void Layer::SavePaintProperties() {
}
bool Layer::Update(ResourceUpdateQueue* queue,
- const OcclusionTracker* occlusion) {
+ const OcclusionTracker<Layer>* occlusion) {
DCHECK(layer_tree_host_);
DCHECK_EQ(layer_tree_host_->source_frame_number(),
paint_properties_.source_frame_number) <<
@@ -1035,8 +1031,8 @@ bool Layer::NeedMoreUpdates() {
return false;
}
-std::string Layer::DebugName() {
- return client_ ? client_->DebugName() : std::string();
+bool Layer::IsSuitableForGpuRasterization() const {
+ return true;
}
scoped_refptr<base::debug::ConvertableToTraceFormat> Layer::TakeDebugInfo() {
@@ -1046,11 +1042,6 @@ scoped_refptr<base::debug::ConvertableToTraceFormat> Layer::TakeDebugInfo() {
return NULL;
}
-
-void Layer::SetCompositingReasons(CompositingReasons reasons) {
- compositing_reasons_ = reasons;
-}
-
void Layer::CreateRenderSurface() {
DCHECK(!draw_properties_.render_surface);
draw_properties_.render_surface = make_scoped_ptr(new RenderSurface(this));
@@ -1061,6 +1052,11 @@ void Layer::ClearRenderSurface() {
draw_properties_.render_surface.reset();
}
+void Layer::ClearRenderSurfaceLayerList() {
+ if (draw_properties_.render_surface)
+ draw_properties_.render_surface->layer_list().clear();
+}
+
gfx::Vector2dF Layer::ScrollOffsetForAnimation() const {
return TotalScrollOffset();
}
@@ -1078,10 +1074,13 @@ void Layer::OnOpacityAnimated(float opacity) {
}
void Layer::OnTransformAnimated(const gfx::Transform& transform) {
+ if (transform_ == transform)
+ return;
transform_ = transform;
+ transform_is_invertible_ = transform.IsInvertible();
}
-void Layer::OnScrollOffsetAnimated(gfx::Vector2dF scroll_offset) {
+void Layer::OnScrollOffsetAnimated(const gfx::Vector2dF& scroll_offset) {
// Do nothing. Scroll deltas will be sent from the compositor thread back
// to the main thread in the same manner as during non-animated
// compositor-driven scrolling.
@@ -1108,7 +1107,8 @@ bool Layer::AddAnimation(scoped_ptr <Animation> animation) {
}
void Layer::PauseAnimation(int animation_id, double time_offset) {
- layer_animation_controller_->PauseAnimation(animation_id, time_offset);
+ layer_animation_controller_->PauseAnimation(
+ animation_id, base::TimeDelta::FromSecondsD(time_offset));
SetNeedsCommit();
}
@@ -1186,5 +1186,4 @@ void Layer::RemoveFromClipTree() {
void Layer::RunMicroBenchmark(MicroBenchmark* benchmark) {
benchmark->RunOnLayer(this);
}
-
} // namespace cc
diff --git a/chromium/cc/layers/layer.h b/chromium/cc/layers/layer.h
index f0bca17f47c..ab897a8ac99 100644
--- a/chromium/cc/layers/layer.h
+++ b/chromium/cc/layers/layer.h
@@ -18,19 +18,18 @@
#include "cc/base/region.h"
#include "cc/base/scoped_ptr_vector.h"
#include "cc/debug/micro_benchmark.h"
-#include "cc/layers/compositing_reasons.h"
#include "cc/layers/draw_properties.h"
#include "cc/layers/layer_lists.h"
#include "cc/layers/layer_position_constraint.h"
#include "cc/layers/paint_properties.h"
#include "cc/layers/render_surface.h"
#include "cc/output/filter_operations.h"
-#include "cc/trees/occlusion_tracker.h"
#include "skia/ext/refptr.h"
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkImageFilter.h"
#include "third_party/skia/include/core/SkPicture.h"
#include "third_party/skia/include/core/SkXfermode.h"
+#include "ui/gfx/point3_f.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/rect_f.h"
#include "ui/gfx/transform.h"
@@ -62,6 +61,8 @@ class RenderingStatsInstrumentation;
class ResourceUpdateQueue;
class ScrollbarLayerInterface;
struct AnimationEvent;
+template <typename LayerType>
+class OcclusionTracker;
// Base class for composited layers. Special layer types are derived from
// this class.
@@ -103,12 +104,6 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
return !copy_requests_.empty();
}
- void SetAnchorPoint(gfx::PointF anchor_point);
- gfx::PointF anchor_point() const { return anchor_point_; }
-
- void SetAnchorPointZ(float anchor_point_z);
- float anchor_point_z() const { return anchor_point_z_; }
-
virtual void SetBackgroundColor(SkColor background_color);
SkColor background_color() const { return background_color_; }
// If contents_opaque(), return an opaque color else return a
@@ -117,7 +112,7 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
// A layer's bounds are in logical, non-page-scaled pixels (however, the
// root layer's bounds are in physical pixels).
- void SetBounds(gfx::Size bounds);
+ void SetBounds(const gfx::Size& bounds);
gfx::Size bounds() const { return bounds_; }
void SetMasksToBounds(bool masks_to_bounds);
@@ -166,7 +161,7 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
virtual void SetContentsOpaque(bool opaque);
bool contents_opaque() const { return contents_opaque_; }
- void SetPosition(gfx::PointF position);
+ void SetPosition(const gfx::PointF& position);
gfx::PointF position() const { return position_; }
void SetIsContainerForFixedPositionLayers(bool container);
@@ -177,14 +172,13 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
return position_constraint_;
}
- void SetSublayerTransform(const gfx::Transform& sublayer_transform);
- const gfx::Transform& sublayer_transform() const {
- return sublayer_transform_;
- }
-
void SetTransform(const gfx::Transform& transform);
const gfx::Transform& transform() const { return transform_; }
bool TransformIsAnimating() const;
+ bool transform_is_invertible() const { return transform_is_invertible_; }
+
+ void SetTransformOrigin(const gfx::Point3F&);
+ gfx::Point3F transform_origin() { return transform_origin_; }
void SetScrollParent(Layer* parent);
@@ -268,13 +262,10 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
void SetScrollOffset(gfx::Vector2d scroll_offset);
gfx::Vector2d scroll_offset() const { return scroll_offset_; }
- void SetScrollOffsetFromImplSide(gfx::Vector2d scroll_offset);
+ void SetScrollOffsetFromImplSide(const gfx::Vector2d& scroll_offset);
- void SetMaxScrollOffset(gfx::Vector2d max_scroll_offset);
- gfx::Vector2d max_scroll_offset() const { return max_scroll_offset_; }
-
- void SetScrollable(bool scrollable);
- bool scrollable() const { return scrollable_; }
+ void SetScrollClipLayerId(int clip_layer_id);
+ bool scrollable() const { return scroll_clip_layer_id_ != INVALID_ID; }
void SetUserScrollable(bool horizontal, bool vertical);
bool user_scrollable_horizontal() const {
@@ -290,6 +281,11 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
void SetHaveWheelEventHandlers(bool have_wheel_event_handlers);
bool have_wheel_event_handlers() const { return have_wheel_event_handlers_; }
+ void SetHaveScrollEventHandlers(bool have_scroll_event_handlers);
+ bool have_scroll_event_handlers() const {
+ return have_scroll_event_handlers_;
+ }
+
void SetNonFastScrollableRegion(const Region& non_fast_scrollable_region);
const Region& non_fast_scrollable_region() const {
return non_fast_scrollable_region_;
@@ -305,7 +301,7 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
}
void SetDrawCheckerboardForMissingTiles(bool checkerboard);
- bool DrawCheckerboardForMissingTiles() const {
+ bool draw_checkerboard_for_missing_tiles() const {
return draw_checkerboard_for_missing_tiles_;
}
@@ -321,8 +317,10 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
void SetDoubleSided(bool double_sided);
bool double_sided() const { return double_sided_; }
- void SetPreserves3d(bool preserves_3d) { preserves_3d_ = preserves_3d; }
- bool preserves_3d() const { return preserves_3d_; }
+ void SetShouldFlattenTransform(bool flatten);
+ bool should_flatten_transform() const { return should_flatten_transform_; }
+
+ bool Is3dSorted() const { return sorting_context_id_ != 0; }
void set_use_parent_backface_visibility(bool use) {
use_parent_backface_visibility_ = use;
@@ -357,23 +355,22 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
virtual void SavePaintProperties();
// Returns true iff any resources were updated that need to be committed.
virtual bool Update(ResourceUpdateQueue* queue,
- const OcclusionTracker* occlusion);
+ const OcclusionTracker<Layer>* occlusion);
virtual bool NeedMoreUpdates();
virtual void SetIsMask(bool is_mask) {}
virtual void ReduceMemoryUsage() {}
virtual void OnOutputSurfaceCreated() {}
+ virtual bool IsSuitableForGpuRasterization() const;
- virtual std::string DebugName();
virtual scoped_refptr<base::debug::ConvertableToTraceFormat> TakeDebugInfo();
void SetLayerClient(LayerClient* client) { client_ = client; }
- void SetCompositingReasons(CompositingReasons reasons);
-
virtual void PushPropertiesTo(LayerImpl* layer);
void CreateRenderSurface();
void ClearRenderSurface();
+ void ClearRenderSurfaceLayerList();
// The contents scale converts from logical, non-page-scaled pixels to target
// pixels. The contents scale is 1 for the root layer as it is already in
@@ -386,6 +383,7 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
virtual void CalculateContentsScale(float ideal_contents_scale,
float device_scale_factor,
float page_scale_factor,
+ float maximum_animation_contents_scale,
bool animating_transform_to_screen,
float* contents_scale_x,
float* contents_scale_y,
@@ -401,10 +399,6 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
void PauseAnimation(int animation_id, double time_offset);
void RemoveAnimation(int animation_id);
- bool AnimatedBoundsForBox(const gfx::BoxF& box, gfx::BoxF* bounds) {
- return layer_animation_controller_->AnimatedBoundsForBox(box, bounds);
- }
-
LayerAnimationController* layer_animation_controller() {
return layer_animation_controller_.get();
}
@@ -452,13 +446,20 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
virtual bool SupportsLCDText() const;
+ void SetNeedsPushProperties();
bool needs_push_properties() const { return needs_push_properties_; }
bool descendant_needs_push_properties() const {
return num_dependents_need_push_properties_ > 0;
}
+ void reset_needs_push_properties_for_testing() {
+ needs_push_properties_ = false;
+ }
virtual void RunMicroBenchmark(MicroBenchmark* benchmark);
+ void Set3dSortingContextId(int id);
+ int sorting_context_id() const { return sorting_context_id_; }
+
protected:
friend class LayerImpl;
friend class TreeSynchronizer;
@@ -485,10 +486,6 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
// unused resources on the impl thread are returned before commit completes.
void SetNextCommitWaitsForActivation();
- // Called when the blend mode or filters have been changed.
- void SetNeedsFilterContextIfNeeded();
-
- void SetNeedsPushProperties();
void AddDependentNeedsPushProperties();
void RemoveDependentNeedsPushProperties();
bool parent_should_know_need_push_properties() const {
@@ -535,6 +532,11 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
// will be handled implicitly after the update completes.
bool ignore_set_needs_commit_;
+ // Layers that share a sorting context id will be sorted together in 3d
+ // space. 0 is a special value that means this layer will not be sorted and
+ // will be drawn in paint order.
+ int sorting_context_id_;
+
private:
friend class base::RefCounted<Layer>;
@@ -554,7 +556,8 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
virtual void OnFilterAnimated(const FilterOperations& filters) OVERRIDE;
virtual void OnOpacityAnimated(float opacity) OVERRIDE;
virtual void OnTransformAnimated(const gfx::Transform& transform) OVERRIDE;
- virtual void OnScrollOffsetAnimated(gfx::Vector2dF scroll_offset) OVERRIDE;
+ virtual void OnScrollOffsetAnimated(
+ const gfx::Vector2dF& scroll_offset) OVERRIDE;
virtual void OnAnimationWaitingForDeletion() OVERRIDE;
virtual bool IsActive() const OVERRIDE;
@@ -572,10 +575,13 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
gfx::Size bounds_;
gfx::Vector2d scroll_offset_;
- gfx::Vector2d max_scroll_offset_;
- bool scrollable_ : 1;
+ // This variable indicates which ancestor layer (if any) whose size,
+ // transformed relative to this layer, defines the maximum scroll offset for
+ // this layer.
+ int scroll_clip_layer_id_;
bool should_scroll_on_main_thread_ : 1;
bool have_wheel_event_handlers_ : 1;
+ bool have_scroll_event_handlers_ : 1;
bool user_scrollable_horizontal_ : 1;
bool user_scrollable_vertical_ : 1;
bool is_root_for_isolated_group_ : 1;
@@ -585,21 +591,19 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
bool masks_to_bounds_ : 1;
bool contents_opaque_ : 1;
bool double_sided_ : 1;
- bool preserves_3d_ : 1;
+ bool should_flatten_transform_ : 1;
bool use_parent_backface_visibility_ : 1;
bool draw_checkerboard_for_missing_tiles_ : 1;
bool force_render_surface_ : 1;
+ bool transform_is_invertible_ : 1;
Region non_fast_scrollable_region_;
Region touch_event_handler_region_;
gfx::PointF position_;
- gfx::PointF anchor_point_;
SkColor background_color_;
- CompositingReasons compositing_reasons_;
float opacity_;
SkXfermode::Mode blend_mode_;
FilterOperations filters_;
FilterOperations background_filters_;
- float anchor_point_z_;
LayerPositionConstraint position_constraint_;
Layer* scroll_parent_;
scoped_ptr<std::set<Layer*> > scroll_children_;
@@ -608,7 +612,7 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
scoped_ptr<std::set<Layer*> > clip_children_;
gfx::Transform transform_;
- gfx::Transform sublayer_transform_;
+ gfx::Point3F transform_origin_;
// Replica layer used for reflections.
scoped_refptr<Layer> replica_layer_;
diff --git a/chromium/cc/layers/layer_client.h b/chromium/cc/layers/layer_client.h
index 6ef6efe1c1b..5a20b11f8f4 100644
--- a/chromium/cc/layers/layer_client.h
+++ b/chromium/cc/layers/layer_client.h
@@ -20,8 +20,6 @@ namespace cc {
class CC_EXPORT LayerClient {
public:
- virtual std::string DebugName() = 0;
-
// Returns a pointer to a debug info object, if one has been computed.
// If not, returns NULL. If the returned pointer is non-NULL, the caller takes
// ownership of the pointer.
diff --git a/chromium/cc/layers/layer_impl.cc b/chromium/cc/layers/layer_impl.cc
index 74b69b5572a..fa68275bd73 100644
--- a/chromium/cc/layers/layer_impl.cc
+++ b/chromium/cc/layers/layer_impl.cc
@@ -9,25 +9,27 @@
#include "base/strings/stringprintf.h"
#include "cc/animation/animation_registrar.h"
#include "cc/animation/scrollbar_animation_controller.h"
-#include "cc/animation/scrollbar_animation_controller_linear_fade.h"
-#include "cc/animation/scrollbar_animation_controller_thinning.h"
#include "cc/base/math_util.h"
#include "cc/debug/debug_colors.h"
#include "cc/debug/layer_tree_debug_state.h"
#include "cc/debug/micro_benchmark_impl.h"
#include "cc/debug/traced_value.h"
#include "cc/input/layer_scroll_offset_delegate.h"
+#include "cc/layers/layer_utils.h"
#include "cc/layers/painted_scrollbar_layer_impl.h"
#include "cc/layers/quad_sink.h"
#include "cc/output/copy_output_request.h"
#include "cc/quads/debug_border_draw_quad.h"
+#include "cc/trees/layer_tree_host_common.h"
#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/layer_tree_settings.h"
#include "cc/trees/proxy.h"
#include "ui/gfx/box_f.h"
+#include "ui/gfx/geometry/vector2d_conversions.h"
#include "ui/gfx/point_conversions.h"
#include "ui/gfx/quad_f.h"
#include "ui/gfx/rect_conversions.h"
+#include "ui/gfx/size_conversions.h"
namespace cc {
LayerImpl::LayerImpl(LayerTreeImpl* tree_impl, int id)
@@ -38,35 +40,35 @@ LayerImpl::LayerImpl(LayerTreeImpl* tree_impl, int id)
replica_layer_id_(-1),
layer_id_(id),
layer_tree_impl_(tree_impl),
- anchor_point_(0.5f, 0.5f),
- anchor_point_z_(0.f),
scroll_offset_delegate_(NULL),
- scrollable_(false),
+ scroll_clip_layer_(NULL),
should_scroll_on_main_thread_(false),
have_wheel_event_handlers_(false),
+ have_scroll_event_handlers_(false),
user_scrollable_horizontal_(true),
user_scrollable_vertical_(true),
stacking_order_changed_(false),
double_sided_(true),
+ should_flatten_transform_(true),
layer_property_changed_(false),
masks_to_bounds_(false),
contents_opaque_(false),
is_root_for_isolated_group_(false),
- preserves_3d_(false),
use_parent_backface_visibility_(false),
draw_checkerboard_for_missing_tiles_(false),
draws_content_(false),
hide_layer_and_subtree_(false),
force_render_surface_(false),
+ transform_is_invertible_(true),
is_container_for_fixed_position_layers_(false),
background_color_(0),
opacity_(1.0),
blend_mode_(SkXfermode::kSrcOver_Mode),
draw_depth_(0.f),
- compositing_reasons_(kCompositingReasonUnknown),
- current_draw_mode_(DRAW_MODE_NONE),
- horizontal_scrollbar_layer_(NULL),
- vertical_scrollbar_layer_(NULL) {
+ needs_push_properties_(false),
+ num_dependents_need_push_properties_(0),
+ sorting_context_id_(0),
+ current_draw_mode_(DRAW_MODE_NONE) {
DCHECK_GT(layer_id_, 0);
DCHECK(layer_tree_impl_);
layer_tree_impl_->RegisterLayer(this);
@@ -76,6 +78,7 @@ LayerImpl::LayerImpl(LayerTreeImpl* tree_impl, int id)
layer_animation_controller_->AddValueObserver(this);
if (IsActive())
layer_animation_controller_->set_value_provider(this);
+ SetNeedsPushProperties();
}
LayerImpl::~LayerImpl() {
@@ -88,27 +91,12 @@ LayerImpl::~LayerImpl() {
layer_tree_impl()->RemoveLayerWithCopyOutputRequest(this);
layer_tree_impl_->UnregisterLayer(this);
- if (scroll_children_) {
- for (std::set<LayerImpl*>::iterator it = scroll_children_->begin();
- it != scroll_children_->end(); ++it)
- (*it)->scroll_parent_ = NULL;
- }
-
- if (scroll_parent_)
- scroll_parent_->RemoveScrollChild(this);
-
- if (clip_children_) {
- for (std::set<LayerImpl*>::iterator it = clip_children_->begin();
- it != clip_children_->end(); ++it)
- (*it)->clip_parent_ = NULL;
- }
-
- if (clip_parent_)
- clip_parent_->RemoveClipChild(this);
+ TRACE_EVENT_OBJECT_DELETED_WITH_ID(
+ TRACE_DISABLED_BY_DEFAULT("cc.debug"), "cc::LayerImpl", this);
}
void LayerImpl::AddChild(scoped_ptr<LayerImpl> child) {
- child->set_parent(this);
+ child->SetParent(this);
DCHECK_EQ(layer_tree_impl(), child->layer_tree_impl());
children_.push_back(child.Pass());
layer_tree_impl()->set_needs_update_draw_properties();
@@ -128,6 +116,16 @@ scoped_ptr<LayerImpl> LayerImpl::RemoveChild(LayerImpl* child) {
return scoped_ptr<LayerImpl>();
}
+void LayerImpl::SetParent(LayerImpl* parent) {
+ if (parent_should_know_need_push_properties()) {
+ if (parent_)
+ parent_->RemoveDependentNeedsPushProperties();
+ if (parent)
+ parent->AddDependentNeedsPushProperties();
+ }
+ parent_ = parent;
+}
+
void LayerImpl::ClearChildList() {
if (children_.empty())
return;
@@ -155,51 +153,39 @@ void LayerImpl::SetScrollParent(LayerImpl* parent) {
// Having both a scroll parent and a scroll offset delegate is unsupported.
DCHECK(!scroll_offset_delegate_);
- if (scroll_parent_)
- scroll_parent_->RemoveScrollChild(this);
+ if (parent)
+ DCHECK_EQ(layer_tree_impl()->LayerById(parent->id()), parent);
scroll_parent_ = parent;
+ SetNeedsPushProperties();
}
void LayerImpl::SetDebugInfo(
scoped_refptr<base::debug::ConvertableToTraceFormat> other) {
debug_info_ = other;
+ SetNeedsPushProperties();
}
void LayerImpl::SetScrollChildren(std::set<LayerImpl*>* children) {
if (scroll_children_.get() == children)
return;
scroll_children_.reset(children);
-}
-
-void LayerImpl::RemoveScrollChild(LayerImpl* child) {
- DCHECK(scroll_children_);
- scroll_children_->erase(child);
- if (scroll_children_->empty())
- scroll_children_.reset();
+ SetNeedsPushProperties();
}
void LayerImpl::SetClipParent(LayerImpl* ancestor) {
if (clip_parent_ == ancestor)
return;
- if (clip_parent_)
- clip_parent_->RemoveClipChild(this);
-
clip_parent_ = ancestor;
+ SetNeedsPushProperties();
}
void LayerImpl::SetClipChildren(std::set<LayerImpl*>* children) {
if (clip_children_.get() == children)
return;
clip_children_.reset(children);
-}
-
-void LayerImpl::RemoveClipChild(LayerImpl* child) {
- DCHECK(clip_children_);
- clip_children_->erase(child);
- if (clip_children_->empty())
- clip_children_.reset();
+ SetNeedsPushProperties();
}
void LayerImpl::PassCopyRequests(ScopedPtrVector<CopyOutputRequest>* requests) {
@@ -217,8 +203,8 @@ void LayerImpl::PassCopyRequests(ScopedPtrVector<CopyOutputRequest>* requests) {
void LayerImpl::TakeCopyRequestsAndTransformToTarget(
ScopedPtrVector<CopyOutputRequest>* requests) {
- if (copy_requests_.empty())
- return;
+ DCHECK(!copy_requests_.empty());
+ DCHECK(layer_tree_impl()->IsActiveTree());
size_t first_inserted_request = requests->size();
requests->insert_and_take(requests->end(), copy_requests_);
@@ -232,13 +218,11 @@ void LayerImpl::TakeCopyRequestsAndTransformToTarget(
gfx::Rect request_in_layer_space = request->area();
gfx::Rect request_in_content_space =
LayerRectToContentRect(request_in_layer_space);
- request->set_area(
- MathUtil::MapClippedRect(draw_properties_.target_space_transform,
- request_in_content_space));
+ request->set_area(MathUtil::MapEnclosingClippedRect(
+ draw_properties_.target_space_transform, request_in_content_space));
}
- if (layer_tree_impl()->IsActiveTree())
- layer_tree_impl()->RemoveLayerWithCopyOutputRequest(this);
+ layer_tree_impl()->RemoveLayerWithCopyOutputRequest(this);
}
void LayerImpl::CreateRenderSurface() {
@@ -252,16 +236,20 @@ void LayerImpl::ClearRenderSurface() {
draw_properties_.render_surface.reset();
}
-scoped_ptr<SharedQuadState> LayerImpl::CreateSharedQuadState() const {
- scoped_ptr<SharedQuadState> state = SharedQuadState::Create();
+void LayerImpl::ClearRenderSurfaceLayerList() {
+ if (draw_properties_.render_surface)
+ draw_properties_.render_surface->layer_list().clear();
+}
+
+void LayerImpl::PopulateSharedQuadState(SharedQuadState* state) const {
state->SetAll(draw_properties_.target_space_transform,
draw_properties_.content_bounds,
draw_properties_.visible_content_rect,
draw_properties_.clip_rect,
draw_properties_.is_clipped,
draw_properties_.opacity,
- blend_mode_);
- return state.Pass();
+ blend_mode_,
+ sorting_context_id_);
}
bool LayerImpl::WillDraw(DrawMode draw_mode,
@@ -301,16 +289,22 @@ void LayerImpl::GetDebugBorderProperties(SkColor* color, float* width) const {
void LayerImpl::AppendDebugBorderQuad(
QuadSink* quad_sink,
+ const gfx::Size& content_bounds,
const SharedQuadState* shared_quad_state,
AppendQuadsData* append_quads_data) const {
SkColor color;
float width;
GetDebugBorderProperties(&color, &width);
- AppendDebugBorderQuad(
- quad_sink, shared_quad_state, append_quads_data, color, width);
+ AppendDebugBorderQuad(quad_sink,
+ content_bounds,
+ shared_quad_state,
+ append_quads_data,
+ color,
+ width);
}
void LayerImpl::AppendDebugBorderQuad(QuadSink* quad_sink,
+ const gfx::Size& content_bounds,
const SharedQuadState* shared_quad_state,
AppendQuadsData* append_quads_data,
SkColor color,
@@ -318,11 +312,13 @@ void LayerImpl::AppendDebugBorderQuad(QuadSink* quad_sink,
if (!ShowDebugBorders())
return;
- gfx::Rect content_rect(content_bounds());
+ gfx::Rect quad_rect(content_bounds);
+ gfx::Rect visible_quad_rect(quad_rect);
scoped_ptr<DebugBorderDrawQuad> debug_border_quad =
DebugBorderDrawQuad::Create();
- debug_border_quad->SetNew(shared_quad_state, content_rect, color, width);
- quad_sink->Append(debug_border_quad.PassAs<DrawQuad>(), append_quads_data);
+ debug_border_quad->SetNew(
+ shared_quad_state, quad_rect, visible_quad_rect, color, width);
+ quad_sink->Append(debug_border_quad.PassAs<DrawQuad>());
}
bool LayerImpl::HasDelegatedContent() const {
@@ -347,7 +343,7 @@ ResourceProvider::ResourceId LayerImpl::ContentsResourceId() const {
return 0;
}
-void LayerImpl::SetSentScrollDelta(gfx::Vector2d sent_scroll_delta) {
+void LayerImpl::SetSentScrollDelta(const gfx::Vector2d& sent_scroll_delta) {
// Pending tree never has sent scroll deltas
DCHECK(layer_tree_impl()->IsActiveTree());
@@ -357,10 +353,10 @@ void LayerImpl::SetSentScrollDelta(gfx::Vector2d sent_scroll_delta) {
sent_scroll_delta_ = sent_scroll_delta;
}
-gfx::Vector2dF LayerImpl::ScrollBy(gfx::Vector2dF scroll) {
+gfx::Vector2dF LayerImpl::ScrollBy(const gfx::Vector2dF& scroll) {
DCHECK(scrollable());
gfx::Vector2dF min_delta = -scroll_offset_;
- gfx::Vector2dF max_delta = max_scroll_offset_ - scroll_offset_;
+ gfx::Vector2dF max_delta = MaxScrollOffset() - scroll_offset_;
// Clamp new_delta so that position + delta stays within scroll bounds.
gfx::Vector2dF new_delta = (ScrollDelta() + scroll);
new_delta.SetToMax(min_delta);
@@ -368,9 +364,14 @@ gfx::Vector2dF LayerImpl::ScrollBy(gfx::Vector2dF scroll) {
gfx::Vector2dF unscrolled =
ScrollDelta() + scroll - new_delta;
SetScrollDelta(new_delta);
+
return unscrolled;
}
+void LayerImpl::SetScrollClipLayer(int scroll_clip_layer_id) {
+ scroll_clip_layer_ = layer_tree_impl()->LayerById(scroll_clip_layer_id);
+}
+
void LayerImpl::ApplySentScrollDeltasFromAbortedCommit() {
// Pending tree never has sent scroll deltas
DCHECK(layer_tree_impl()->IsActiveTree());
@@ -411,7 +412,7 @@ void LayerImpl::ApplyScrollDeltasSinceBeginMainFrame() {
}
InputHandler::ScrollStatus LayerImpl::TryScroll(
- gfx::PointF screen_space_point,
+ const gfx::PointF& screen_space_point,
InputHandler::ScrollInputType type) const {
if (should_scroll_on_main_thread()) {
TRACE_EVENT0("cc", "LayerImpl::TryScroll: Failed ShouldScrollOnMainThread");
@@ -460,7 +461,8 @@ InputHandler::ScrollStatus LayerImpl::TryScroll(
return InputHandler::ScrollIgnored;
}
- if (max_scroll_offset_.x() <= 0 && max_scroll_offset_.y() <= 0) {
+ gfx::Vector2d max_scroll_offset = MaxScrollOffset();
+ if (max_scroll_offset.x() <= 0 && max_scroll_offset.y() <= 0) {
TRACE_EVENT0("cc",
"LayerImpl::tryScroll: Ignored. Technically scrollable,"
" but has no affordance in either direction.");
@@ -470,11 +472,6 @@ InputHandler::ScrollStatus LayerImpl::TryScroll(
return InputHandler::ScrollStarted;
}
-bool LayerImpl::DrawCheckerboardForMissingTiles() const {
- return draw_checkerboard_for_missing_tiles_ &&
- !layer_tree_impl()->settings().background_color_instead_of_checkerboard;
-}
-
gfx::Rect LayerImpl::LayerRectToContentRect(
const gfx::RectF& layer_rect) const {
gfx::RectF content_rect =
@@ -489,23 +486,16 @@ skia::RefPtr<SkPicture> LayerImpl::GetPicture() {
return skia::RefPtr<SkPicture>();
}
-bool LayerImpl::AreVisibleResourcesReady() const {
- return true;
-}
-
scoped_ptr<LayerImpl> LayerImpl::CreateLayerImpl(LayerTreeImpl* tree_impl) {
return LayerImpl::Create(tree_impl, layer_id_);
}
void LayerImpl::PushPropertiesTo(LayerImpl* layer) {
- layer->SetAnchorPoint(anchor_point_);
- layer->SetAnchorPointZ(anchor_point_z_);
+ layer->SetTransformOrigin(transform_origin_);
layer->SetBackgroundColor(background_color_);
layer->SetBounds(bounds_);
layer->SetContentBounds(content_bounds());
layer->SetContentsScale(contents_scale_x(), contents_scale_y());
- layer->SetDebugName(debug_name_);
- layer->SetCompositingReasons(compositing_reasons_);
layer->SetDoubleSided(double_sided_);
layer->SetDrawCheckerboardForMissingTiles(
draw_checkerboard_for_missing_tiles_);
@@ -517,6 +507,7 @@ void LayerImpl::PushPropertiesTo(LayerImpl* layer) {
layer->SetMasksToBounds(masks_to_bounds_);
layer->SetShouldScrollOnMainThread(should_scroll_on_main_thread_);
layer->SetHaveWheelEventHandlers(have_wheel_event_handlers_);
+ layer->SetHaveScrollEventHandlers(have_scroll_event_handlers_);
layer->SetNonFastScrollableRegion(non_fast_scrollable_region_);
layer->SetTouchEventHandlerRegion(touch_event_handler_region_);
layer->SetContentsOpaque(contents_opaque_);
@@ -526,39 +517,48 @@ void LayerImpl::PushPropertiesTo(LayerImpl* layer) {
layer->SetPosition(position_);
layer->SetIsContainerForFixedPositionLayers(
is_container_for_fixed_position_layers_);
- layer->SetFixedContainerSizeDelta(fixed_container_size_delta_);
layer->SetPositionConstraint(position_constraint_);
- layer->SetPreserves3d(preserves_3d());
+ layer->SetShouldFlattenTransform(should_flatten_transform_);
layer->SetUseParentBackfaceVisibility(use_parent_backface_visibility_);
- layer->SetSublayerTransform(sublayer_transform_);
- layer->SetTransform(transform_);
+ layer->SetTransformAndInvertibility(transform_, transform_is_invertible_);
- layer->SetScrollable(scrollable_);
+ layer->SetScrollClipLayer(scroll_clip_layer_ ? scroll_clip_layer_->id()
+ : Layer::INVALID_ID);
layer->set_user_scrollable_horizontal(user_scrollable_horizontal_);
layer->set_user_scrollable_vertical(user_scrollable_vertical_);
layer->SetScrollOffsetAndDelta(
scroll_offset_, layer->ScrollDelta() - layer->sent_scroll_delta());
layer->SetSentScrollDelta(gfx::Vector2d());
-
- layer->SetMaxScrollOffset(max_scroll_offset_);
+ layer->Set3dSortingContextId(sorting_context_id_);
LayerImpl* scroll_parent = NULL;
- if (scroll_parent_)
+ if (scroll_parent_) {
scroll_parent = layer->layer_tree_impl()->LayerById(scroll_parent_->id());
+ DCHECK(scroll_parent);
+ }
layer->SetScrollParent(scroll_parent);
if (scroll_children_) {
std::set<LayerImpl*>* scroll_children = new std::set<LayerImpl*>;
for (std::set<LayerImpl*>::iterator it = scroll_children_->begin();
- it != scroll_children_->end(); ++it)
- scroll_children->insert(layer->layer_tree_impl()->LayerById((*it)->id()));
+ it != scroll_children_->end();
+ ++it) {
+ DCHECK_EQ((*it)->scroll_parent(), this);
+ LayerImpl* scroll_child =
+ layer->layer_tree_impl()->LayerById((*it)->id());
+ DCHECK(scroll_child);
+ scroll_children->insert(scroll_child);
+ }
layer->SetScrollChildren(scroll_children);
+ } else {
+ layer->SetScrollChildren(NULL);
}
LayerImpl* clip_parent = NULL;
if (clip_parent_) {
clip_parent = layer->layer_tree_impl()->LayerById(
clip_parent_->id());
+ DCHECK(clip_parent);
}
layer->SetClipParent(clip_parent);
@@ -568,6 +568,8 @@ void LayerImpl::PushPropertiesTo(LayerImpl* layer) {
it != clip_children_->end(); ++it)
clip_children->insert(layer->layer_tree_impl()->LayerById((*it)->id()));
layer->SetClipChildren(clip_children);
+ } else {
+ layer->SetClipChildren(NULL);
}
layer->PassCopyRequests(&copy_requests_);
@@ -577,15 +579,40 @@ void LayerImpl::PushPropertiesTo(LayerImpl* layer) {
// update_rect here. The LayerImpl's update_rect needs to accumulate (i.e.
// union) any update changes that have occurred on the main thread.
update_rect_.Union(layer->update_rect());
- layer->set_update_rect(update_rect_);
+ layer->SetUpdateRect(update_rect_);
layer->SetStackingOrderChanged(stacking_order_changed_);
+ layer->SetDebugInfo(debug_info_);
// Reset any state that should be cleared for the next update.
stacking_order_changed_ = false;
update_rect_ = gfx::RectF();
+ needs_push_properties_ = false;
+ num_dependents_need_push_properties_ = 0;
+}
- layer->SetDebugInfo(debug_info_);
+gfx::Vector2dF LayerImpl::FixedContainerSizeDelta() const {
+ if (!scroll_clip_layer_)
+ return gfx::Vector2dF();
+
+ float scale_delta = layer_tree_impl()->page_scale_delta();
+ float scale = layer_tree_impl()->page_scale_factor();
+
+ gfx::Vector2dF delta_from_scroll = scroll_clip_layer_->BoundsDelta();
+ delta_from_scroll.Scale(1.f / scale);
+
+ // The delta-from-pinch component requires some explanation: A viewport of
+ // size (w,h) will appear to be size (w/s,h/s) under scale s in the content
+ // space. If s -> s' on the impl thread, where s' = s * ds, then the apparent
+ // viewport size change in the content space due to ds is:
+ //
+ // (w/s',h/s') - (w/s,h/s) = (w,h)(1/s' - 1/s) = (w,h)(1 - ds)/(s ds)
+ //
+ gfx::Vector2dF delta_from_pinch =
+ gfx::Rect(scroll_clip_layer_->bounds()).bottom_right() - gfx::PointF();
+ delta_from_pinch.Scale((1.f - scale_delta) / (scale * scale_delta));
+
+ return delta_from_scroll + delta_from_pinch;
}
base::DictionaryValue* LayerImpl::LayerTreeAsJson() const {
@@ -611,14 +638,17 @@ base::DictionaryValue* LayerImpl::LayerTreeAsJson() const {
result->Set("DrawTransform", list);
result->SetBoolean("DrawsContent", draws_content_);
+ result->SetBoolean("Is3dSorted", Is3dSorted());
result->SetDouble("Opacity", opacity());
result->SetBoolean("ContentsOpaque", contents_opaque_);
- if (scrollable_)
- result->SetBoolean("Scrollable", scrollable_);
+ if (scrollable())
+ result->SetBoolean("Scrollable", true);
if (have_wheel_event_handlers_)
result->SetBoolean("WheelHandler", have_wheel_event_handlers_);
+ if (have_scroll_event_handlers_)
+ result->SetBoolean("ScrollHandler", have_scroll_event_handlers_);
if (!touch_event_handler_region_.IsEmpty()) {
scoped_ptr<base::Value> region = touch_event_handler_region_.AsValue();
result->Set("TouchRegion", region.release());
@@ -642,17 +672,28 @@ void LayerImpl::SetStackingOrderChanged(bool stacking_order_changed) {
void LayerImpl::NoteLayerPropertyChanged() {
layer_property_changed_ = true;
layer_tree_impl()->set_needs_update_draw_properties();
+ SetNeedsPushProperties();
}
void LayerImpl::NoteLayerPropertyChangedForSubtree() {
- NoteLayerPropertyChanged();
- NoteLayerPropertyChangedForDescendants();
+ layer_property_changed_ = true;
+ layer_tree_impl()->set_needs_update_draw_properties();
+ for (size_t i = 0; i < children_.size(); ++i)
+ children_[i]->NoteLayerPropertyChangedForDescendantsInternal();
+ SetNeedsPushProperties();
+}
+
+void LayerImpl::NoteLayerPropertyChangedForDescendantsInternal() {
+ layer_property_changed_ = true;
+ for (size_t i = 0; i < children_.size(); ++i)
+ children_[i]->NoteLayerPropertyChangedForDescendantsInternal();
}
void LayerImpl::NoteLayerPropertyChangedForDescendants() {
layer_tree_impl()->set_needs_update_draw_properties();
for (size_t i = 0; i < children_.size(); ++i)
- children_[i]->NoteLayerPropertyChangedForSubtree();
+ children_[i]->NoteLayerPropertyChangedForDescendantsInternal();
+ SetNeedsPushProperties();
}
const char* LayerImpl::LayerTypeAsString() const {
@@ -663,6 +704,7 @@ void LayerImpl::ResetAllChangeTrackingForSubtree() {
layer_property_changed_ = false;
update_rect_ = gfx::RectF();
+ damage_rect_ = gfx::RectF();
if (draw_properties_.render_surface)
draw_properties_.render_surface->ResetPropertyChangedFlag();
@@ -677,10 +719,9 @@ void LayerImpl::ResetAllChangeTrackingForSubtree() {
for (size_t i = 0; i < children_.size(); ++i)
children_[i]->ResetAllChangeTrackingForSubtree();
-}
-bool LayerImpl::LayerIsAlwaysDamaged() const {
- return false;
+ needs_push_properties_ = false;
+ num_dependents_need_push_properties_ = 0;
}
gfx::Vector2dF LayerImpl::ScrollOffsetForAnimation() const {
@@ -699,7 +740,7 @@ void LayerImpl::OnTransformAnimated(const gfx::Transform& transform) {
SetTransform(transform);
}
-void LayerImpl::OnScrollOffsetAnimated(gfx::Vector2dF scroll_offset) {
+void LayerImpl::OnScrollOffsetAnimated(const gfx::Vector2dF& scroll_offset) {
// Only layers in the active tree should need to do anything here, since
// layers in the pending tree will find out about these changes as a
// result of the call to SetScrollDelta.
@@ -717,12 +758,32 @@ bool LayerImpl::IsActive() const {
return layer_tree_impl_->IsActiveTree();
}
-void LayerImpl::SetBounds(gfx::Size bounds) {
+// TODO(wjmaclean) Convert so that bounds returns SizeF.
+gfx::Size LayerImpl::bounds() const {
+ return ToFlooredSize(temporary_impl_bounds_);
+}
+
+void LayerImpl::SetBounds(const gfx::Size& bounds) {
if (bounds_ == bounds)
return;
bounds_ = bounds;
+ temporary_impl_bounds_ = bounds;
+ ScrollbarParametersDidChange();
+ if (masks_to_bounds())
+ NoteLayerPropertyChangedForSubtree();
+ else
+ NoteLayerPropertyChanged();
+}
+
+void LayerImpl::SetTemporaryImplBounds(const gfx::SizeF& bounds) {
+ if (temporary_impl_bounds_ == bounds)
+ return;
+
+ temporary_impl_bounds_ = bounds;
+
+ ScrollbarParametersDidChange();
if (masks_to_bounds())
NoteLayerPropertyChangedForSubtree();
else
@@ -742,7 +803,7 @@ void LayerImpl::SetMaskLayer(scoped_ptr<LayerImpl> mask_layer) {
mask_layer_ = mask_layer.Pass();
mask_layer_id_ = new_layer_id;
if (mask_layer_)
- mask_layer_->set_parent(this);
+ mask_layer_->SetParent(this);
NoteLayerPropertyChangedForSubtree();
}
@@ -764,7 +825,7 @@ void LayerImpl::SetReplicaLayer(scoped_ptr<LayerImpl> replica_layer) {
replica_layer_ = replica_layer.Pass();
replica_layer_id_ = new_layer_id;
if (replica_layer_)
- replica_layer_->set_parent(this);
+ replica_layer_->SetParent(this);
NoteLayerPropertyChangedForSubtree();
}
@@ -793,19 +854,10 @@ void LayerImpl::SetHideLayerAndSubtree(bool hide) {
NoteLayerPropertyChangedForSubtree();
}
-void LayerImpl::SetAnchorPoint(gfx::PointF anchor_point) {
- if (anchor_point_ == anchor_point)
+void LayerImpl::SetTransformOrigin(const gfx::Point3F& transform_origin) {
+ if (transform_origin_ == transform_origin)
return;
-
- anchor_point_ = anchor_point;
- NoteLayerPropertyChangedForSubtree();
-}
-
-void LayerImpl::SetAnchorPointZ(float anchor_point_z) {
- if (anchor_point_z_ == anchor_point_z)
- return;
-
- anchor_point_z_ = anchor_point_z;
+ transform_origin_ = transform_origin;
NoteLayerPropertyChangedForSubtree();
}
@@ -910,9 +962,10 @@ void LayerImpl::SetIsRootForIsolatedGroup(bool root) {
return;
is_root_for_isolated_group_ = root;
+ SetNeedsPushProperties();
}
-void LayerImpl::SetPosition(gfx::PointF position) {
+void LayerImpl::SetPosition(const gfx::PointF& position) {
if (position_ == position)
return;
@@ -920,22 +973,19 @@ void LayerImpl::SetPosition(gfx::PointF position) {
NoteLayerPropertyChangedForSubtree();
}
-void LayerImpl::SetPreserves3d(bool preserves3_d) {
- if (preserves_3d_ == preserves3_d)
+void LayerImpl::SetShouldFlattenTransform(bool flatten) {
+ if (should_flatten_transform_ == flatten)
return;
- preserves_3d_ = preserves3_d;
+ should_flatten_transform_ = flatten;
NoteLayerPropertyChangedForSubtree();
}
-void LayerImpl::SetSublayerTransform(const gfx::Transform& sublayer_transform) {
- if (sublayer_transform_ == sublayer_transform)
+void LayerImpl::Set3dSortingContextId(int id) {
+ if (id == sorting_context_id_)
return;
-
- sublayer_transform_ = sublayer_transform;
- // Sublayer transform does not affect the current layer; it affects only its
- // children.
- NoteLayerPropertyChangedForDescendants();
+ sorting_context_id_ = id;
+ NoteLayerPropertyChangedForSubtree();
}
void LayerImpl::SetTransform(const gfx::Transform& transform) {
@@ -943,6 +993,19 @@ void LayerImpl::SetTransform(const gfx::Transform& transform) {
return;
transform_ = transform;
+ transform_is_invertible_ = transform_.IsInvertible();
+ NoteLayerPropertyChangedForSubtree();
+}
+
+void LayerImpl::SetTransformAndInvertibility(const gfx::Transform& transform,
+ bool transform_is_invertible) {
+ if (transform_ == transform) {
+ DCHECK(transform_is_invertible_ == transform_is_invertible)
+ << "Can't change invertibility if transform is unchanged";
+ return;
+ }
+ transform_ = transform;
+ transform_is_invertible_ = transform_is_invertible;
NoteLayerPropertyChangedForSubtree();
}
@@ -956,7 +1019,16 @@ bool LayerImpl::TransformIsAnimatingOnImplOnly() const {
return transform_animation && transform_animation->is_impl_only();
}
-void LayerImpl::SetContentBounds(gfx::Size content_bounds) {
+void LayerImpl::SetUpdateRect(const gfx::RectF& update_rect) {
+ update_rect_ = update_rect;
+ SetNeedsPushProperties();
+}
+
+void LayerImpl::AddDamageRect(const gfx::RectF& damage_rect) {
+ damage_rect_ = gfx::UnionRects(damage_rect_, damage_rect);
+}
+
+void LayerImpl::SetContentBounds(const gfx::Size& content_bounds) {
if (this->content_bounds() == content_bounds)
return;
@@ -975,61 +1047,8 @@ void LayerImpl::SetContentsScale(float contents_scale_x,
NoteLayerPropertyChanged();
}
-void LayerImpl::CalculateContentsScale(
- float ideal_contents_scale,
- float device_scale_factor,
- float page_scale_factor,
- bool animating_transform_to_screen,
- float* contents_scale_x,
- float* contents_scale_y,
- gfx::Size* content_bounds) {
- // Base LayerImpl has all of its content scales and content bounds pushed
- // from its Layer during commit and just reuses those values as-is.
- *contents_scale_x = this->contents_scale_x();
- *contents_scale_y = this->contents_scale_y();
- *content_bounds = this->content_bounds();
-}
-
-void LayerImpl::UpdateScrollbarPositions() {
- gfx::Vector2dF current_offset = scroll_offset_ + ScrollDelta();
-
- gfx::RectF viewport(PointAtOffsetFromOrigin(current_offset), bounds_);
- gfx::SizeF scrollable_size(max_scroll_offset_.x() + bounds_.width(),
- max_scroll_offset_.y() + bounds_.height());
- if (horizontal_scrollbar_layer_) {
- horizontal_scrollbar_layer_->SetCurrentPos(current_offset.x());
- horizontal_scrollbar_layer_->SetMaximum(max_scroll_offset_.x());
- horizontal_scrollbar_layer_->SetVisibleToTotalLengthRatio(
- viewport.width() / scrollable_size.width());
- }
- if (vertical_scrollbar_layer_) {
- vertical_scrollbar_layer_->SetCurrentPos(current_offset.y());
- vertical_scrollbar_layer_->SetMaximum(max_scroll_offset_.y());
- vertical_scrollbar_layer_->SetVisibleToTotalLengthRatio(
- viewport.height() / scrollable_size.height());
- }
-
- if (current_offset == last_scroll_offset_)
- return;
- last_scroll_offset_ = current_offset;
-
- if (scrollbar_animation_controller_) {
- bool should_animate = scrollbar_animation_controller_->DidScrollUpdate(
- layer_tree_impl_->CurrentPhysicalTimeTicks());
- if (should_animate)
- layer_tree_impl_->StartScrollbarAnimation();
- }
-
- // Get the current_offset_.y() value for a sanity-check on scrolling
- // benchmark metrics. Specifically, we want to make sure
- // BasicMouseWheelSmoothScrollGesture has proper scroll curves.
- if (layer_tree_impl()->IsActiveTree()) {
- TRACE_COUNTER_ID1("gpu", "scroll_offset_y", this->id(), current_offset.y());
- }
-}
-
void LayerImpl::SetScrollOffsetDelegate(
- LayerScrollOffsetDelegate* scroll_offset_delegate) {
+ ScrollOffsetDelegate* scroll_offset_delegate) {
// Having both a scroll parent and a scroll offset delegate is unsupported.
DCHECK(!scroll_parent_);
if (!scroll_offset_delegate && scroll_offset_delegate_) {
@@ -1038,10 +1057,8 @@ void LayerImpl::SetScrollOffsetDelegate(
}
gfx::Vector2dF total_offset = TotalScrollOffset();
scroll_offset_delegate_ = scroll_offset_delegate;
- if (scroll_offset_delegate_) {
- scroll_offset_delegate_->SetMaxScrollOffset(max_scroll_offset_);
+ if (scroll_offset_delegate_)
scroll_offset_delegate_->SetTotalScrollOffset(total_offset);
- }
}
bool LayerImpl::IsExternalFlingActive() const {
@@ -1049,14 +1066,16 @@ bool LayerImpl::IsExternalFlingActive() const {
scroll_offset_delegate_->IsExternalFlingActive();
}
-void LayerImpl::SetScrollOffset(gfx::Vector2d scroll_offset) {
+void LayerImpl::SetScrollOffset(const gfx::Vector2d& scroll_offset) {
SetScrollOffsetAndDelta(scroll_offset, ScrollDelta());
}
-void LayerImpl::SetScrollOffsetAndDelta(gfx::Vector2d scroll_offset,
- gfx::Vector2dF scroll_delta) {
+void LayerImpl::SetScrollOffsetAndDelta(const gfx::Vector2d& scroll_offset,
+ const gfx::Vector2dF& scroll_delta) {
bool changed = false;
+ last_scroll_offset_ = scroll_offset;
+
if (scroll_offset_ != scroll_offset) {
changed = true;
scroll_offset_ = scroll_offset;
@@ -1091,7 +1110,7 @@ void LayerImpl::SetScrollOffsetAndDelta(gfx::Vector2d scroll_offset,
if (changed) {
NoteLayerPropertyChangedForSubtree();
- UpdateScrollbarPositions();
+ ScrollbarParametersDidChange();
}
}
@@ -1101,7 +1120,7 @@ gfx::Vector2dF LayerImpl::ScrollDelta() const {
return scroll_delta_;
}
-void LayerImpl::SetScrollDelta(gfx::Vector2dF scroll_delta) {
+void LayerImpl::SetScrollDelta(const gfx::Vector2dF& scroll_delta) {
SetScrollOffsetAndDelta(scroll_offset_, scroll_delta);
}
@@ -1125,18 +1144,156 @@ Region LayerImpl::VisibleContentOpaqueRegion() const {
void LayerImpl::DidBeginTracing() {}
-void LayerImpl::DidLoseOutputSurface() {}
+void LayerImpl::ReleaseResources() {}
+
+gfx::Vector2d LayerImpl::MaxScrollOffset() const {
+ if (!scroll_clip_layer_ || bounds().IsEmpty())
+ return gfx::Vector2d();
+
+ LayerImpl const* page_scale_layer = layer_tree_impl()->page_scale_layer();
+ DCHECK(this != page_scale_layer);
+ DCHECK(this != layer_tree_impl()->InnerViewportScrollLayer() ||
+ IsContainerForFixedPositionLayers());
+
+ gfx::SizeF scaled_scroll_bounds(bounds());
+
+ float scale_factor = 1.f;
+ for (LayerImpl const* current_layer = this;
+ current_layer != scroll_clip_layer_;
+ current_layer = current_layer->parent()) {
+ DCHECK(current_layer);
+ float current_layer_scale = 1.f;
+
+ const gfx::Transform& layer_transform = current_layer->transform();
+ if (current_layer == page_scale_layer) {
+ DCHECK(layer_transform.IsIdentity());
+ current_layer_scale = layer_tree_impl()->total_page_scale_factor();
+ } else {
+ // TODO(wjmaclean) Should we allow for translation too?
+ DCHECK(layer_transform.IsScale2d());
+ gfx::Vector2dF layer_scale = layer_transform.Scale2d();
+ // TODO(wjmaclean) Allow for non-isotropic scales.
+ DCHECK(layer_scale.x() == layer_scale.y());
+ current_layer_scale = layer_scale.x();
+ }
-void LayerImpl::SetMaxScrollOffset(gfx::Vector2d max_scroll_offset) {
- if (max_scroll_offset_ == max_scroll_offset)
+ scale_factor *= current_layer_scale;
+ }
+ // TODO(wjmaclean) Once we move to a model where the two-viewport model is
+ // turned on in all builds, remove the next two lines. For now however, the
+ // page scale layer may coincide with the clip layer, and so this is
+ // necessary.
+ if (page_scale_layer == scroll_clip_layer_)
+ scale_factor *= layer_tree_impl()->total_page_scale_factor();
+
+ scaled_scroll_bounds.SetSize(scale_factor * scaled_scroll_bounds.width(),
+ scale_factor * scaled_scroll_bounds.height());
+ scaled_scroll_bounds = gfx::ToFlooredSize(scaled_scroll_bounds);
+
+ gfx::Vector2dF max_offset(
+ scaled_scroll_bounds.width() - scroll_clip_layer_->bounds().width(),
+ scaled_scroll_bounds.height() - scroll_clip_layer_->bounds().height());
+ // We need the final scroll offset to be in CSS coords.
+ max_offset.Scale(1 / scale_factor);
+ max_offset.SetToMax(gfx::Vector2dF());
+ return gfx::ToFlooredVector2d(max_offset);
+}
+
+gfx::Vector2dF LayerImpl::ClampScrollToMaxScrollOffset() {
+ gfx::Vector2dF max_offset = MaxScrollOffset();
+ gfx::Vector2dF old_offset = TotalScrollOffset();
+ gfx::Vector2dF clamped_offset = old_offset;
+
+ clamped_offset.SetToMin(max_offset);
+ clamped_offset.SetToMax(gfx::Vector2d());
+ gfx::Vector2dF delta = clamped_offset - old_offset;
+ if (!delta.IsZero())
+ ScrollBy(delta);
+
+ return delta;
+}
+
+void LayerImpl::SetScrollbarPosition(ScrollbarLayerImplBase* scrollbar_layer,
+ LayerImpl* scrollbar_clip_layer) const {
+ DCHECK(scrollbar_layer);
+ LayerImpl* page_scale_layer = layer_tree_impl()->page_scale_layer();
+
+ DCHECK(this != page_scale_layer);
+ DCHECK(scrollbar_clip_layer);
+ DCHECK(this != layer_tree_impl()->InnerViewportScrollLayer() ||
+ IsContainerForFixedPositionLayers());
+ gfx::RectF clip_rect(gfx::PointF(), scrollbar_clip_layer->bounds());
+
+ // See comment in MaxScrollOffset() regarding the use of the content layer
+ // bounds here.
+ gfx::RectF scroll_rect(gfx::PointF(), bounds());
+
+ if (scroll_rect.size().IsEmpty())
return;
- max_scroll_offset_ = max_scroll_offset;
- if (scroll_offset_delegate_)
- scroll_offset_delegate_->SetMaxScrollOffset(max_scroll_offset_);
+ // TODO(wjmaclean) This computation is nearly identical to the one in
+ // MaxScrollOffset. Find some way to combine these.
+ gfx::Vector2dF current_offset;
+ for (LayerImpl const* current_layer = this;
+ current_layer != scrollbar_clip_layer;
+ current_layer = current_layer->parent()) {
+ DCHECK(current_layer);
+ const gfx::Transform& layer_transform = current_layer->transform();
+ if (current_layer == page_scale_layer) {
+ DCHECK(layer_transform.IsIdentity());
+ float scale_factor = layer_tree_impl()->total_page_scale_factor();
+ current_offset.Scale(scale_factor);
+ scroll_rect.Scale(scale_factor);
+ } else {
+ DCHECK(layer_transform.IsScale2d());
+ gfx::Vector2dF layer_scale = layer_transform.Scale2d();
+ DCHECK(layer_scale.x() == layer_scale.y());
+ gfx::Vector2dF new_offset =
+ current_layer->scroll_offset() + current_layer->ScrollDelta();
+ new_offset.Scale(layer_scale.x(), layer_scale.y());
+ current_offset += new_offset;
+ }
+ }
+ // TODO(wjmaclean) Once we move to a model where the two-viewport model is
+ // turned on in all builds, remove the next two lines. For now however, the
+ // page scale layer may coincide with the clip layer, and so this is
+ // necessary.
+ if (page_scale_layer == scrollbar_clip_layer) {
+ scroll_rect.Scale(layer_tree_impl()->total_page_scale_factor());
+ current_offset.Scale(layer_tree_impl()->total_page_scale_factor());
+ }
+
+ scrollbar_layer->SetVerticalAdjust(
+ layer_tree_impl()->VerticalAdjust(scrollbar_clip_layer->id()));
+ if (scrollbar_layer->orientation() == HORIZONTAL) {
+ float visible_ratio = clip_rect.width() / scroll_rect.width();
+ scrollbar_layer->SetCurrentPos(current_offset.x());
+ scrollbar_layer->SetMaximum(scroll_rect.width() - clip_rect.width());
+ scrollbar_layer->SetVisibleToTotalLengthRatio(visible_ratio);
+ } else {
+ float visible_ratio = clip_rect.height() / scroll_rect.height();
+ scrollbar_layer->SetCurrentPos(current_offset.y());
+ scrollbar_layer->SetMaximum(scroll_rect.height() - clip_rect.height());
+ scrollbar_layer->SetVisibleToTotalLengthRatio(visible_ratio);
+ }
layer_tree_impl()->set_needs_update_draw_properties();
- UpdateScrollbarPositions();
+ // TODO(wjmaclean) The scrollbar animator for the pinch-zoom scrollbars should
+ // activate for every scroll on the main frame, not just the scrolls that move
+ // the pinch virtual viewport (i.e. trigger from either inner or outer
+ // viewport).
+ if (scrollbar_animation_controller_) {
+ // When both non-overlay and overlay scrollbars are both present, don't
+ // animate the overlay scrollbars when page scale factor is at the min.
+ // Non-overlay scrollbars also shouldn't trigger animations.
+ bool is_animatable_scrollbar =
+ scrollbar_layer->is_overlay_scrollbar() &&
+ ((layer_tree_impl()->total_page_scale_factor() >
+ layer_tree_impl()->min_page_scale_factor()) ||
+ !layer_tree_impl()->settings().use_pinch_zoom_scrollbars);
+ if (is_animatable_scrollbar)
+ scrollbar_animation_controller_->DidScrollUpdate();
+ }
}
void LayerImpl::DidBecomeActive() {
@@ -1145,8 +1302,7 @@ void LayerImpl::DidBecomeActive() {
return;
}
- bool need_scrollbar_animation_controller = horizontal_scrollbar_layer_ ||
- vertical_scrollbar_layer_;
+ bool need_scrollbar_animation_controller = scrollable() && scrollbars_;
if (!need_scrollbar_animation_controller) {
scrollbar_animation_controller_.reset();
return;
@@ -1155,179 +1311,99 @@ void LayerImpl::DidBecomeActive() {
if (scrollbar_animation_controller_)
return;
- switch (layer_tree_impl_->settings().scrollbar_animator) {
- case LayerTreeSettings::LinearFade: {
- base::TimeDelta fadeout_delay = base::TimeDelta::FromMilliseconds(
- layer_tree_impl_->settings().scrollbar_linear_fade_delay_ms);
- base::TimeDelta fadeout_length = base::TimeDelta::FromMilliseconds(
- layer_tree_impl_->settings().scrollbar_linear_fade_length_ms);
-
- scrollbar_animation_controller_ =
- ScrollbarAnimationControllerLinearFade::Create(
- this, fadeout_delay, fadeout_length)
- .PassAs<ScrollbarAnimationController>();
- break;
- }
- case LayerTreeSettings::Thinning: {
- scrollbar_animation_controller_ =
- ScrollbarAnimationControllerThinning::Create(this)
- .PassAs<ScrollbarAnimationController>();
- break;
- }
- case LayerTreeSettings::NoAnimator:
- NOTREACHED();
- break;
- }
-}
-void LayerImpl::SetHorizontalScrollbarLayer(
- ScrollbarLayerImplBase* scrollbar_layer) {
- horizontal_scrollbar_layer_ = scrollbar_layer;
- if (horizontal_scrollbar_layer_)
- horizontal_scrollbar_layer_->set_scroll_layer_id(id());
-}
-
-void LayerImpl::SetVerticalScrollbarLayer(
- ScrollbarLayerImplBase* scrollbar_layer) {
- vertical_scrollbar_layer_ = scrollbar_layer;
- if (vertical_scrollbar_layer_)
- vertical_scrollbar_layer_->set_scroll_layer_id(id());
+ scrollbar_animation_controller_ =
+ layer_tree_impl_->CreateScrollbarAnimationController(this);
}
-static scoped_ptr<base::Value>
-CompositingReasonsAsValue(CompositingReasons reasons) {
- scoped_ptr<base::ListValue> reason_list(new base::ListValue());
-
- if (reasons == kCompositingReasonUnknown) {
- reason_list->AppendString("No reasons given");
- return reason_list.PassAs<base::Value>();
- }
-
- if (reasons & kCompositingReason3DTransform)
- reason_list->AppendString("Has a 3d Transform");
-
- if (reasons & kCompositingReasonVideo)
- reason_list->AppendString("Is accelerated video");
-
- if (reasons & kCompositingReasonCanvas)
- reason_list->AppendString("Is accelerated canvas");
-
- if (reasons & kCompositingReasonPlugin)
- reason_list->AppendString("Is accelerated plugin");
-
- if (reasons & kCompositingReasonIFrame)
- reason_list->AppendString("Is accelerated iframe");
-
- if (reasons & kCompositingReasonBackfaceVisibilityHidden)
- reason_list->AppendString("Has backface-visibility: hidden");
-
- if (reasons & kCompositingReasonAnimation)
- reason_list->AppendString("Has accelerated animation or transition");
-
- if (reasons & kCompositingReasonFilters)
- reason_list->AppendString("Has accelerated filters");
-
- if (reasons & kCompositingReasonPositionFixed)
- reason_list->AppendString("Is fixed position");
-
- if (reasons & kCompositingReasonPositionSticky)
- reason_list->AppendString("Is sticky position");
-
- if (reasons & kCompositingReasonOverflowScrollingTouch)
- reason_list->AppendString("Is a scrollable overflow element");
-
- if (reasons & kCompositingReasonAssumedOverlap)
- reason_list->AppendString("Might overlap a composited animation");
-
- if (reasons & kCompositingReasonOverlap)
- reason_list->AppendString("Overlaps other composited content");
-
- if (reasons & kCompositingReasonNegativeZIndexChildren) {
- reason_list->AppendString("Might overlap negative z-index "
- "composited content");
- }
-
- if (reasons & kCompositingReasonTransformWithCompositedDescendants) {
- reason_list->AppendString("Has transform needed by a "
- "composited descendant");
- }
-
- if (reasons & kCompositingReasonOpacityWithCompositedDescendants)
- reason_list->AppendString("Has opacity needed by a composited descendant");
-
- if (reasons & kCompositingReasonMaskWithCompositedDescendants)
- reason_list->AppendString("Has a mask needed by a composited descendant");
-
- if (reasons & kCompositingReasonReflectionWithCompositedDescendants)
- reason_list->AppendString("Has a reflection with a composited descendant");
+void LayerImpl::ClearScrollbars() {
+ if (!scrollbars_)
+ return;
- if (reasons & kCompositingReasonFilterWithCompositedDescendants)
- reason_list->AppendString("Has filter effect with a composited descendant");
+ scrollbars_.reset(NULL);
+}
- if (reasons & kCompositingReasonBlendingWithCompositedDescendants)
- reason_list->AppendString("Has a blend mode with a composited descendant");
+void LayerImpl::AddScrollbar(ScrollbarLayerImplBase* layer) {
+ DCHECK(layer);
+ DCHECK(!scrollbars_ || scrollbars_->find(layer) == scrollbars_->end());
+ if (!scrollbars_)
+ scrollbars_.reset(new ScrollbarSet());
- if (reasons & kCompositingReasonClipsCompositingDescendants)
- reason_list->AppendString("Clips a composited descendant");
+ scrollbars_->insert(layer);
+}
- if (reasons & kCompositingReasonPerspective) {
- reason_list->AppendString("Has a perspective transform needed by a "
- "composited 3d descendant");
- }
+void LayerImpl::RemoveScrollbar(ScrollbarLayerImplBase* layer) {
+ DCHECK(scrollbars_);
+ DCHECK(layer);
+ DCHECK(scrollbars_->find(layer) != scrollbars_->end());
- if (reasons & kCompositingReasonPreserve3D) {
- reason_list->AppendString("Has preserves-3d style with composited "
- "3d descendant");
- }
-
- if (reasons & kCompositingReasonReflectionOfCompositedParent)
- reason_list->AppendString("Is the reflection of a composited layer");
+ scrollbars_->erase(layer);
+ if (scrollbars_->empty())
+ scrollbars_.reset();
+}
- if (reasons & kCompositingReasonRoot)
- reason_list->AppendString("Is the root");
+bool LayerImpl::HasScrollbar(ScrollbarOrientation orientation) const {
+ if (!scrollbars_)
+ return false;
- if (reasons & kCompositingReasonLayerForClip)
- reason_list->AppendString("Convenience layer, to clip subtree");
+ for (ScrollbarSet::iterator it = scrollbars_->begin();
+ it != scrollbars_->end();
+ ++it)
+ if ((*it)->orientation() == orientation)
+ return true;
- if (reasons & kCompositingReasonLayerForScrollbar)
- reason_list->AppendString("Convenience layer for rendering scrollbar");
+ return false;
+}
- if (reasons & kCompositingReasonLayerForScrollingContainer)
- reason_list->AppendString("Convenience layer, the scrolling container");
+void LayerImpl::ScrollbarParametersDidChange() {
+ if (!scrollbars_)
+ return;
- if (reasons & kCompositingReasonLayerForForeground) {
- reason_list->AppendString("Convenience layer, foreground when main layer "
- "has negative z-index composited content");
- }
+ for (ScrollbarSet::iterator it = scrollbars_->begin();
+ it != scrollbars_->end();
+ ++it)
+ (*it)->ScrollbarParametersDidChange();
+}
- if (reasons & kCompositingReasonLayerForBackground) {
- reason_list->AppendString("Convenience layer, background when main layer "
- "has a composited background");
- }
+void LayerImpl::SetNeedsPushProperties() {
+ if (needs_push_properties_)
+ return;
+ if (!parent_should_know_need_push_properties() && parent_)
+ parent_->AddDependentNeedsPushProperties();
+ needs_push_properties_ = true;
+}
- if (reasons & kCompositingReasonLayerForMask)
- reason_list->AppendString("Is a mask layer");
+void LayerImpl::AddDependentNeedsPushProperties() {
+ DCHECK_GE(num_dependents_need_push_properties_, 0);
- if (reasons & kCompositingReasonOverflowScrollingParent)
- reason_list->AppendString("Scroll parent is not an ancestor");
+ if (!parent_should_know_need_push_properties() && parent_)
+ parent_->AddDependentNeedsPushProperties();
- if (reasons & kCompositingReasonOutOfFlowClipping)
- reason_list->AppendString("Has clipping ancestor");
+ num_dependents_need_push_properties_++;
+}
- if (reasons & kCompositingReasonIsolateCompositedDescendants)
- reason_list->AppendString("Should isolate composited descendants");
+void LayerImpl::RemoveDependentNeedsPushProperties() {
+ num_dependents_need_push_properties_--;
+ DCHECK_GE(num_dependents_need_push_properties_, 0);
- return reason_list.PassAs<base::Value>();
+ if (!parent_should_know_need_push_properties() && parent_)
+ parent_->RemoveDependentNeedsPushProperties();
}
void LayerImpl::AsValueInto(base::DictionaryValue* state) const {
- TracedValue::MakeDictIntoImplicitSnapshot(state, LayerTypeAsString(), this);
+ TracedValue::MakeDictIntoImplicitSnapshotWithCategory(
+ TRACE_DISABLED_BY_DEFAULT("cc.debug"),
+ state,
+ "cc::LayerImpl",
+ LayerTypeAsString(),
+ this);
state->SetInteger("layer_id", id());
- state->SetString("layer_name", debug_name());
- state->Set("bounds", MathUtil::AsValue(bounds()).release());
+ state->Set("bounds", MathUtil::AsValue(bounds_).release());
+ state->Set("position", MathUtil::AsValue(position_).release());
state->SetInteger("draws_content", DrawsContent());
state->SetInteger("gpu_memory_usage", GPUMemoryUsageInBytes());
- state->Set("compositing_reasons",
- CompositingReasonsAsValue(compositing_reasons_).release());
+ state->Set("scroll_offset", MathUtil::AsValue(scroll_offset_).release());
+ state->Set("transform_origin",
+ MathUtil::AsValue(transform_origin_).release());
bool clipped;
gfx::QuadF layer_quad = MathUtil::MapQuad(
@@ -1346,6 +1422,12 @@ void LayerImpl::AsValueInto(base::DictionaryValue* state) const {
state->Set("wheel_event_handler_region",
wheel_region.AsValue().release());
}
+ if (have_scroll_event_handlers_) {
+ gfx::Rect scroll_rect(content_bounds());
+ Region scroll_region(scroll_rect);
+ state->Set("scroll_event_handler_region",
+ scroll_region.AsValue().release());
+ }
if (!non_fast_scrollable_region_.IsEmpty()) {
state->Set("non_fast_scrollable_region",
non_fast_scrollable_region_.AsValue().release());
@@ -1369,28 +1451,37 @@ void LayerImpl::AsValueInto(base::DictionaryValue* state) const {
state->SetBoolean("can_use_lcd_text", can_use_lcd_text());
state->SetBoolean("contents_opaque", contents_opaque());
- if (layer_animation_controller_->IsAnimatingProperty(Animation::Transform) ||
- layer_animation_controller_->IsAnimatingProperty(Animation::Filter)) {
- gfx::BoxF box(bounds().width(), bounds().height(), 0.f);
- gfx::BoxF inflated;
- if (layer_animation_controller_->AnimatedBoundsForBox(box, &inflated))
- state->Set("animated_bounds", MathUtil::AsValue(inflated).release());
- }
+ state->SetBoolean(
+ "has_animation_bounds",
+ layer_animation_controller()->HasAnimationThatInflatesBounds());
+
+ gfx::BoxF box;
+ if (LayerUtils::GetAnimationBounds(*this, &box))
+ state->Set("animation_bounds", MathUtil::AsValue(box).release());
if (debug_info_.get()) {
std::string str;
debug_info_->AppendAsTraceFormat(&str);
base::JSONReader json_reader;
- // Parsing the JSON and re-encoding it is not very efficient,
- // but it's the simplest way to achieve the desired effect, which
- // is to output:
- // {..., layout_rects: [{geometry_rect: ...}, ...], ...}
- // rather than:
- // {layout_rects: "[{geometry_rect: ...}, ...]", ...}
- state->Set("layout_rects", json_reader.ReadToValue(str));
+ scoped_ptr<base::Value> debug_info_value(json_reader.ReadToValue(str));
+
+ if (debug_info_value->IsType(base::Value::TYPE_DICTIONARY)) {
+ base::DictionaryValue* dictionary_value = NULL;
+ bool converted_to_dictionary =
+ debug_info_value->GetAsDictionary(&dictionary_value);
+ DCHECK(converted_to_dictionary);
+ state->MergeDictionary(dictionary_value);
+ } else {
+ NOTREACHED();
+ }
}
}
+bool LayerImpl::IsDrawnRenderSurfaceLayerListMember() const {
+ return draw_properties_.last_drawn_render_surface_layer_list_id ==
+ layer_tree_impl_->current_render_surface_list_id();
+}
+
size_t LayerImpl::GPUMemoryUsageInBytes() const { return 0; }
scoped_ptr<base::Value> LayerImpl::AsValue() const {
@@ -1402,5 +1493,4 @@ scoped_ptr<base::Value> LayerImpl::AsValue() const {
void LayerImpl::RunMicroBenchmark(MicroBenchmarkImpl* benchmark) {
benchmark->RunOnLayer(this);
}
-
} // namespace cc
diff --git a/chromium/cc/layers/layer_impl.h b/chromium/cc/layers/layer_impl.h
index cfbd353bf54..cb18604ad82 100644
--- a/chromium/cc/layers/layer_impl.h
+++ b/chromium/cc/layers/layer_impl.h
@@ -18,7 +18,6 @@
#include "cc/base/region.h"
#include "cc/base/scoped_ptr_vector.h"
#include "cc/input/input_handler.h"
-#include "cc/layers/compositing_reasons.h"
#include "cc/layers/draw_properties.h"
#include "cc/layers/layer_lists.h"
#include "cc/layers/layer_position_constraint.h"
@@ -31,6 +30,7 @@
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkImageFilter.h"
#include "third_party/skia/include/core/SkPicture.h"
+#include "ui/gfx/point3_f.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/rect_f.h"
#include "ui/gfx/transform.h"
@@ -52,6 +52,7 @@ class QuadSink;
class Renderer;
class ScrollbarAnimationController;
class ScrollbarLayerImplBase;
+class Tile;
struct AppendQuadsData;
@@ -65,10 +66,21 @@ enum DrawMode {
class CC_EXPORT LayerImpl : public LayerAnimationValueObserver,
public LayerAnimationValueProvider {
public:
+ // Allows for the ownership of the total scroll offset to be delegated outside
+ // of the layer.
+ class ScrollOffsetDelegate {
+ public:
+ virtual void SetTotalScrollOffset(const gfx::Vector2dF& new_value) = 0;
+ virtual gfx::Vector2dF GetTotalScrollOffset() = 0;
+ virtual bool IsExternalFlingActive() const = 0;
+ };
+
typedef LayerImplList RenderSurfaceListType;
typedef LayerImplList LayerListType;
typedef RenderSurfaceImpl RenderSurfaceType;
+ enum RenderingContextConstants { NO_RENDERING_CONTEXT = 0 };
+
static scoped_ptr<LayerImpl> Create(LayerTreeImpl* tree_impl, int id) {
return make_scoped_ptr(new LayerImpl(tree_impl, id));
}
@@ -84,7 +96,8 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver,
virtual void OnFilterAnimated(const FilterOperations& filters) OVERRIDE;
virtual void OnOpacityAnimated(float opacity) OVERRIDE;
virtual void OnTransformAnimated(const gfx::Transform& transform) OVERRIDE;
- virtual void OnScrollOffsetAnimated(gfx::Vector2dF scroll_offset) OVERRIDE;
+ virtual void OnScrollOffsetAnimated(
+ const gfx::Vector2dF& scroll_offset) OVERRIDE;
virtual void OnAnimationWaitingForDeletion() OVERRIDE;
virtual bool IsActive() const OVERRIDE;
@@ -96,7 +109,8 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver,
LayerImpl* child_at(size_t index) const { return children_[index]; }
void AddChild(scoped_ptr<LayerImpl> child);
scoped_ptr<LayerImpl> RemoveChild(LayerImpl* child);
- void set_parent(LayerImpl* parent) { parent_ = parent; }
+ void SetParent(LayerImpl* parent);
+
// Warning: This does not preserve tree structure invariants.
void ClearChildList();
@@ -108,7 +122,6 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver,
const LayerImpl* scroll_parent() const { return scroll_parent_; }
void SetScrollChildren(std::set<LayerImpl*>* children);
- void RemoveScrollChild(LayerImpl* child);
std::set<LayerImpl*>* scroll_children() { return scroll_children_.get(); }
const std::set<LayerImpl*>* scroll_children() const {
@@ -125,7 +138,6 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver,
}
void SetClipChildren(std::set<LayerImpl*>* children);
- void RemoveClipChild(LayerImpl* child);
std::set<LayerImpl*>* clip_children() { return clip_children_.get(); }
const std::set<LayerImpl*>* clip_children() const {
@@ -133,6 +145,7 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver,
}
void PassCopyRequests(ScopedPtrVector<CopyOutputRequest>* requests);
+ // Can only be called when the layer has a copy request.
void TakeCopyRequestsAndTransformToTarget(
ScopedPtrVector<CopyOutputRequest>* request);
bool HasCopyRequest() const { return !copy_requests_.empty(); }
@@ -155,7 +168,7 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver,
LayerTreeImpl* layer_tree_impl() const { return layer_tree_impl_; }
- scoped_ptr<SharedQuadState> CreateSharedQuadState() const;
+ void PopulateSharedQuadState(SharedQuadState* state) const;
// WillDraw must be called before AppendQuads. If WillDraw returns false,
// AppendQuads and DidDraw will not be called. If WillDraw returns true,
// DidDraw is guaranteed to be called before another WillDraw or before
@@ -175,7 +188,8 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver,
virtual RenderPass::Id FirstContributingRenderPassId() const;
virtual RenderPass::Id NextContributingRenderPassId(RenderPass::Id id) const;
- virtual void UpdateTilePriorities() {}
+ virtual void UpdateTiles() {}
+ virtual void NotifyTileStateChanged(const Tile* tile) {}
virtual ScrollbarLayerImplBase* ToScrollbarLayer();
@@ -189,11 +203,8 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver,
bool force_render_surface() const { return force_render_surface_; }
void SetForceRenderSurface(bool force) { force_render_surface_ = force; }
- void SetAnchorPoint(gfx::PointF anchor_point);
- gfx::PointF anchor_point() const { return anchor_point_; }
-
- void SetAnchorPointZ(float anchor_point_z);
- float anchor_point_z() const { return anchor_point_z_; }
+ void SetTransformOrigin(const gfx::Point3F& transform_origin);
+ gfx::Point3F transform_origin() const { return transform_origin_; }
void SetBackgroundColor(SkColor background_color);
SkColor background_color() const { return background_color_; }
@@ -233,7 +244,7 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver,
return is_root_for_isolated_group_;
}
- void SetPosition(gfx::PointF position);
+ void SetPosition(const gfx::PointF& position);
gfx::PointF position() const { return position_; }
void SetIsContainerForFixedPositionLayers(bool container) {
@@ -244,12 +255,7 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver,
return is_container_for_fixed_position_layers_;
}
- void SetFixedContainerSizeDelta(gfx::Vector2dF delta) {
- fixed_container_size_delta_ = delta;
- }
- gfx::Vector2dF fixed_container_size_delta() const {
- return fixed_container_size_delta_;
- }
+ gfx::Vector2dF FixedContainerSizeDelta() const;
void SetPositionConstraint(const LayerPositionConstraint& constraint) {
position_constraint_ = constraint;
@@ -258,8 +264,10 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver,
return position_constraint_;
}
- void SetPreserves3d(bool preserves_3d);
- bool preserves_3d() const { return preserves_3d_; }
+ void SetShouldFlattenTransform(bool flatten);
+ bool should_flatten_transform() const { return should_flatten_transform_; }
+
+ bool Is3dSorted() const { return sorting_context_id_ != 0; }
void SetUseParentBackfaceVisibility(bool use) {
use_parent_backface_visibility_ = use;
@@ -268,23 +276,6 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver,
return use_parent_backface_visibility_;
}
- void SetSublayerTransform(const gfx::Transform& sublayer_transform);
- const gfx::Transform& sublayer_transform() const {
- return sublayer_transform_;
- }
-
- // Debug layer name.
- void SetDebugName(const std::string& debug_name) { debug_name_ = debug_name; }
- std::string debug_name() const { return debug_name_; }
-
- void SetCompositingReasons(CompositingReasons reasons) {
- compositing_reasons_ = reasons;
- }
-
- CompositingReasons compositing_reasons() const {
- return compositing_reasons_;
- }
-
bool ShowDebugBorders() const;
// These invalidate the host's render surface layer list. The caller
@@ -292,6 +283,7 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver,
// so that its list can be recreated.
void CreateRenderSurface();
void ClearRenderSurface();
+ void ClearRenderSurfaceLayerList();
DrawProperties<LayerImpl>& draw_properties() {
return draw_properties_;
@@ -351,56 +343,48 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver,
// contents scale to appropriate values. LayerImpl doesn't calculate any of
// them from the other values.
- void SetBounds(gfx::Size bounds);
- gfx::Size bounds() const { return bounds_; }
+ void SetBounds(const gfx::Size& bounds);
+ void SetTemporaryImplBounds(const gfx::SizeF& bounds);
+ gfx::Size bounds() const;
+ gfx::Vector2dF BoundsDelta() const {
+ return gfx::Vector2dF(temporary_impl_bounds_.width() - bounds_.width(),
+ temporary_impl_bounds_.height() - bounds_.height());
+ }
- void SetContentBounds(gfx::Size content_bounds);
+ void SetContentBounds(const gfx::Size& content_bounds);
gfx::Size content_bounds() const { return draw_properties_.content_bounds; }
float contents_scale_x() const { return draw_properties_.contents_scale_x; }
float contents_scale_y() const { return draw_properties_.contents_scale_y; }
void SetContentsScale(float contents_scale_x, float contents_scale_y);
- // Computes a box in screen space that should entirely contain the layer's
- // bounds through the entirety of the layer's current animation. Returns true
- // and sets |out| to the inflation if there are animations that can inflate
- // bounds in the path to the root layer. Returns false otherwise.
- bool GetAnimationBounds(gfx::BoxF* out) const { return false; }
-
- virtual void CalculateContentsScale(float ideal_contents_scale,
- float device_scale_factor,
- float page_scale_factor,
- bool animating_transform_to_screen,
- float* contents_scale_x,
- float* contents_scale_y,
- gfx::Size* content_bounds);
-
- void SetScrollOffsetDelegate(
- LayerScrollOffsetDelegate* scroll_offset_delegate);
+ void SetScrollOffsetDelegate(ScrollOffsetDelegate* scroll_offset_delegate);
bool IsExternalFlingActive() const;
- void SetScrollOffset(gfx::Vector2d scroll_offset);
- void SetScrollOffsetAndDelta(gfx::Vector2d scroll_offset,
- gfx::Vector2dF scroll_delta);
+ void SetScrollOffset(const gfx::Vector2d& scroll_offset);
+ void SetScrollOffsetAndDelta(const gfx::Vector2d& scroll_offset,
+ const gfx::Vector2dF& scroll_delta);
gfx::Vector2d scroll_offset() const { return scroll_offset_; }
- void SetMaxScrollOffset(gfx::Vector2d max_scroll_offset);
- gfx::Vector2d max_scroll_offset() const { return max_scroll_offset_; }
-
- void SetScrollDelta(gfx::Vector2dF scroll_delta);
+ gfx::Vector2d MaxScrollOffset() const;
+ gfx::Vector2dF ClampScrollToMaxScrollOffset();
+ void SetScrollbarPosition(ScrollbarLayerImplBase* scrollbar_layer,
+ LayerImpl* scrollbar_clip_layer) const;
+ void SetScrollDelta(const gfx::Vector2dF& scroll_delta);
gfx::Vector2dF ScrollDelta() const;
gfx::Vector2dF TotalScrollOffset() const;
- void SetSentScrollDelta(gfx::Vector2d sent_scroll_delta);
+ void SetSentScrollDelta(const gfx::Vector2d& sent_scroll_delta);
gfx::Vector2d sent_scroll_delta() const { return sent_scroll_delta_; }
// Returns the delta of the scroll that was outside of the bounds of the
// initial scroll
- gfx::Vector2dF ScrollBy(gfx::Vector2dF scroll);
+ gfx::Vector2dF ScrollBy(const gfx::Vector2dF& scroll);
- void SetScrollable(bool scrollable) { scrollable_ = scrollable; }
- bool scrollable() const { return scrollable_; }
+ void SetScrollClipLayer(int scroll_clip_layer_id);
+ LayerImpl* scroll_clip_layer() const { return scroll_clip_layer_; }
+ bool scrollable() const { return !!scroll_clip_layer_; }
void set_user_scrollable_horizontal(bool scrollable) {
user_scrollable_horizontal_ = scrollable;
@@ -424,6 +408,13 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver,
}
bool have_wheel_event_handlers() const { return have_wheel_event_handlers_; }
+ void SetHaveScrollEventHandlers(bool have_scroll_event_handlers) {
+ have_scroll_event_handlers_ = have_scroll_event_handlers;
+ }
+ bool have_scroll_event_handlers() const {
+ return have_scroll_event_handlers_;
+ }
+
void SetNonFastScrollableRegion(const Region& region) {
non_fast_scrollable_region_ = region;
}
@@ -441,10 +432,12 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver,
void SetDrawCheckerboardForMissingTiles(bool checkerboard) {
draw_checkerboard_for_missing_tiles_ = checkerboard;
}
- bool DrawCheckerboardForMissingTiles() const;
+ bool draw_checkerboard_for_missing_tiles() const {
+ return draw_checkerboard_for_missing_tiles_;
+ }
InputHandler::ScrollStatus TryScroll(
- gfx::PointF screen_space_point,
+ const gfx::PointF& screen_space_point,
InputHandler::ScrollInputType type) const;
void SetDoubleSided(bool double_sided);
@@ -454,75 +447,92 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver,
const gfx::Transform& transform() const { return transform_; }
bool TransformIsAnimating() const;
bool TransformIsAnimatingOnImplOnly() const;
+ void SetTransformAndInvertibility(const gfx::Transform& transform,
+ bool transform_is_invertible);
+ bool transform_is_invertible() const { return transform_is_invertible_; }
// Note this rect is in layer space (not content space).
- void set_update_rect(const gfx::RectF& update_rect) {
- update_rect_ = update_rect;
- }
+ void SetUpdateRect(const gfx::RectF& update_rect);
+
const gfx::RectF& update_rect() const { return update_rect_; }
+ void AddDamageRect(const gfx::RectF& damage_rect);
+
+ const gfx::RectF& damage_rect() const { return damage_rect_; }
+
virtual base::DictionaryValue* LayerTreeAsJson() const;
void SetStackingOrderChanged(bool stacking_order_changed);
- bool LayerPropertyChanged() const {
- return layer_property_changed_ || LayerIsAlwaysDamaged();
- }
+ bool LayerPropertyChanged() const { return layer_property_changed_; }
void ResetAllChangeTrackingForSubtree();
- virtual bool LayerIsAlwaysDamaged() const;
-
LayerAnimationController* layer_animation_controller() {
return layer_animation_controller_.get();
}
+ const LayerAnimationController* layer_animation_controller() const {
+ return layer_animation_controller_.get();
+ }
+
virtual Region VisibleContentOpaqueRegion() const;
virtual void DidBecomeActive();
virtual void DidBeginTracing();
- // Indicates that the surface previously used to render this layer
- // was lost and that a new one has been created. Won't be called
- // until the new surface has been created successfully.
- virtual void DidLoseOutputSurface();
+ // Release resources held by this layer. Called when the output surface
+ // that rendered this layer was lost or a rendering mode switch has occured.
+ virtual void ReleaseResources();
ScrollbarAnimationController* scrollbar_animation_controller() const {
return scrollbar_animation_controller_.get();
}
- void SetHorizontalScrollbarLayer(ScrollbarLayerImplBase* scrollbar_layer);
- ScrollbarLayerImplBase* horizontal_scrollbar_layer() {
- return horizontal_scrollbar_layer_;
- }
-
- void SetVerticalScrollbarLayer(ScrollbarLayerImplBase* scrollbar_layer);
- ScrollbarLayerImplBase* vertical_scrollbar_layer() {
- return vertical_scrollbar_layer_;
+ typedef std::set<ScrollbarLayerImplBase*> ScrollbarSet;
+ ScrollbarSet* scrollbars() { return scrollbars_.get(); }
+ void ClearScrollbars();
+ void AddScrollbar(ScrollbarLayerImplBase* layer);
+ void RemoveScrollbar(ScrollbarLayerImplBase* layer);
+ bool HasScrollbar(ScrollbarOrientation orientation) const;
+ void ScrollbarParametersDidChange();
+ int clip_height() {
+ return scroll_clip_layer_ ? scroll_clip_layer_->bounds().height() : 0;
}
gfx::Rect LayerRectToContentRect(const gfx::RectF& layer_rect) const;
virtual skia::RefPtr<SkPicture> GetPicture();
- virtual bool AreVisibleResourcesReady() const;
-
virtual scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl);
virtual void PushPropertiesTo(LayerImpl* layer);
scoped_ptr<base::Value> AsValue() const;
virtual size_t GPUMemoryUsageInBytes() const;
- // TODO(danakj): Be true only if needed. crbug.com/259511
- bool needs_push_properties() const { return true; }
- bool descendant_needs_push_properties() const { return true; }
+ void SetNeedsPushProperties();
+ void AddDependentNeedsPushProperties();
+ void RemoveDependentNeedsPushProperties();
+ bool parent_should_know_need_push_properties() const {
+ return needs_push_properties() || descendant_needs_push_properties();
+ }
+
+ bool needs_push_properties() const { return needs_push_properties_; }
+ bool descendant_needs_push_properties() const {
+ return num_dependents_need_push_properties_ > 0;
+ }
virtual void RunMicroBenchmark(MicroBenchmarkImpl* benchmark);
virtual void SetDebugInfo(
scoped_refptr<base::debug::ConvertableToTraceFormat> other);
+ bool IsDrawnRenderSurfaceLayerListMember() const;
+
+ void Set3dSortingContextId(int id);
+ int sorting_context_id() { return sorting_context_id_; }
+
protected:
LayerImpl(LayerTreeImpl* layer_impl, int id);
@@ -530,9 +540,11 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver,
virtual void GetDebugBorderProperties(SkColor* color, float* width) const;
void AppendDebugBorderQuad(QuadSink* quad_sink,
+ const gfx::Size& content_bounds,
const SharedQuadState* shared_quad_state,
AppendQuadsData* append_quads_data) const;
void AppendDebugBorderQuad(QuadSink* quad_sink,
+ const gfx::Size& content_bounds,
const SharedQuadState* shared_quad_state,
AppendQuadsData* append_quads_data,
SkColor color,
@@ -547,7 +559,7 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver,
void NoteLayerPropertyChangedForDescendants();
private:
- void UpdateScrollbarPositions();
+ void NoteLayerPropertyChangedForDescendantsInternal();
virtual const char* LayerTypeAsString() const;
@@ -576,19 +588,22 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver,
LayerTreeImpl* layer_tree_impl_;
// Properties synchronized from the associated Layer.
- gfx::PointF anchor_point_;
- float anchor_point_z_;
+ gfx::Point3F transform_origin_;
gfx::Size bounds_;
+ gfx::SizeF temporary_impl_bounds_;
gfx::Vector2d scroll_offset_;
- LayerScrollOffsetDelegate* scroll_offset_delegate_;
+ ScrollOffsetDelegate* scroll_offset_delegate_;
+ LayerImpl* scroll_clip_layer_;
bool scrollable_ : 1;
bool should_scroll_on_main_thread_ : 1;
bool have_wheel_event_handlers_ : 1;
+ bool have_scroll_event_handlers_ : 1;
bool user_scrollable_horizontal_ : 1;
bool user_scrollable_vertical_ : 1;
bool stacking_order_changed_ : 1;
// Whether the "back" of this layer should draw.
bool double_sided_ : 1;
+ bool should_flatten_transform_ : 1;
// Tracks if drawing-related properties have changed since last redraw.
bool layer_property_changed_ : 1;
@@ -596,13 +611,15 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver,
bool masks_to_bounds_ : 1;
bool contents_opaque_ : 1;
bool is_root_for_isolated_group_ : 1;
- bool preserves_3d_ : 1;
bool use_parent_backface_visibility_ : 1;
bool draw_checkerboard_for_missing_tiles_ : 1;
bool draws_content_ : 1;
bool hide_layer_and_subtree_ : 1;
bool force_render_surface_ : 1;
+ // Cache transform_'s invertibility.
+ bool transform_is_invertible_ : 1;
+
// Set for the layer that other layers are fixed to.
bool is_container_for_fixed_position_layers_ : 1;
Region non_fast_scrollable_region_;
@@ -612,32 +629,38 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver,
float opacity_;
SkXfermode::Mode blend_mode_;
gfx::PointF position_;
- gfx::Transform sublayer_transform_;
gfx::Transform transform_;
- // This property is effective when
- // is_container_for_fixed_position_layers_ == true,
- gfx::Vector2dF fixed_container_size_delta_;
-
LayerPositionConstraint position_constraint_;
gfx::Vector2dF scroll_delta_;
gfx::Vector2d sent_scroll_delta_;
- gfx::Vector2d max_scroll_offset_;
gfx::Vector2dF last_scroll_offset_;
// The global depth value of the center of the layer. This value is used
// to sort layers from back to front.
float draw_depth_;
- // Debug layer name.
- std::string debug_name_;
- CompositingReasons compositing_reasons_;
-
FilterOperations filters_;
FilterOperations background_filters_;
protected:
+ friend class TreeSynchronizer;
+
+ // This flag is set when the layer needs to push properties to the active
+ // side.
+ bool needs_push_properties_;
+
+ // The number of direct children or dependent layers that need to be recursed
+ // to in order for them or a descendent of them to push properties to the
+ // active side.
+ int num_dependents_need_push_properties_;
+
+ // Layers that share a sorting context id will be sorted together in 3d
+ // space. 0 is a special value that means this layer will not be sorted and
+ // will be drawn in paint order.
+ int sorting_context_id_;
+
DrawMode current_draw_mode_;
private:
@@ -646,16 +669,16 @@ class CC_EXPORT LayerImpl : public LayerAnimationValueObserver,
// Uses layer (not content) space.
gfx::RectF update_rect_;
+ // This rect is in layer space.
+ gfx::RectF damage_rect_;
+
// Manages animations for this layer.
scoped_refptr<LayerAnimationController> layer_animation_controller_;
// Manages scrollbars for this layer
scoped_ptr<ScrollbarAnimationController> scrollbar_animation_controller_;
- // Weak pointers to this layer's scrollbars, if it has them. Updated during
- // tree synchronization.
- ScrollbarLayerImplBase* horizontal_scrollbar_layer_;
- ScrollbarLayerImplBase* vertical_scrollbar_layer_;
+ scoped_ptr<ScrollbarSet> scrollbars_;
ScopedPtrVector<CopyOutputRequest> copy_requests_;
diff --git a/chromium/cc/layers/layer_impl_unittest.cc b/chromium/cc/layers/layer_impl_unittest.cc
index 9d90c04928e..281a3f12ca5 100644
--- a/chromium/cc/layers/layer_impl_unittest.cc
+++ b/chromium/cc/layers/layer_impl_unittest.cc
@@ -10,6 +10,7 @@
#include "cc/test/fake_layer_tree_host_impl.h"
#include "cc/test/fake_output_surface.h"
#include "cc/test/geometry_test_utils.h"
+#include "cc/test/test_shared_bitmap_manager.h"
#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/single_thread_proxy.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -22,6 +23,9 @@ namespace {
#define EXECUTE_AND_VERIFY_SUBTREE_CHANGED(code_to_test) \
root->ResetAllChangeTrackingForSubtree(); \
code_to_test; \
+ EXPECT_TRUE(root->needs_push_properties()); \
+ EXPECT_FALSE(child->needs_push_properties()); \
+ EXPECT_FALSE(grand_child->needs_push_properties()); \
EXPECT_TRUE(root->LayerPropertyChanged()); \
EXPECT_TRUE(child->LayerPropertyChanged()); \
EXPECT_TRUE(grand_child->LayerPropertyChanged());
@@ -29,23 +33,33 @@ namespace {
#define EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(code_to_test) \
root->ResetAllChangeTrackingForSubtree(); \
code_to_test; \
+ EXPECT_FALSE(root->needs_push_properties()); \
+ EXPECT_FALSE(child->needs_push_properties()); \
+ EXPECT_FALSE(grand_child->needs_push_properties()); \
EXPECT_FALSE(root->LayerPropertyChanged()); \
EXPECT_FALSE(child->LayerPropertyChanged()); \
EXPECT_FALSE(grand_child->LayerPropertyChanged());
-#define EXECUTE_AND_VERIFY_ONLY_LAYER_CHANGED(code_to_test) \
+#define EXECUTE_AND_VERIFY_NEEDS_PUSH_PROPERTIES_AND_SUBTREE_DID_NOT_CHANGE( \
+ code_to_test) \
root->ResetAllChangeTrackingForSubtree(); \
code_to_test; \
- EXPECT_TRUE(root->LayerPropertyChanged()); \
+ EXPECT_TRUE(root->needs_push_properties()); \
+ EXPECT_FALSE(child->needs_push_properties()); \
+ EXPECT_FALSE(grand_child->needs_push_properties()); \
+ EXPECT_FALSE(root->LayerPropertyChanged()); \
EXPECT_FALSE(child->LayerPropertyChanged()); \
EXPECT_FALSE(grand_child->LayerPropertyChanged());
-#define EXECUTE_AND_VERIFY_ONLY_DESCENDANTS_CHANGED(code_to_test) \
+#define EXECUTE_AND_VERIFY_ONLY_LAYER_CHANGED(code_to_test) \
root->ResetAllChangeTrackingForSubtree(); \
code_to_test; \
- EXPECT_FALSE(root->LayerPropertyChanged()); \
- EXPECT_TRUE(child->LayerPropertyChanged()); \
- EXPECT_TRUE(grand_child->LayerPropertyChanged());
+ EXPECT_TRUE(root->needs_push_properties()); \
+ EXPECT_FALSE(child->needs_push_properties()); \
+ EXPECT_FALSE(grand_child->needs_push_properties()); \
+ EXPECT_TRUE(root->LayerPropertyChanged()); \
+ EXPECT_FALSE(child->LayerPropertyChanged()); \
+ EXPECT_FALSE(grand_child->LayerPropertyChanged());
#define VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(code_to_test) \
root->ResetAllChangeTrackingForSubtree(); \
@@ -69,15 +83,36 @@ TEST(LayerImplTest, VerifyLayerChangesAreTrackedProperly) {
// The constructor on this will fake that we are on the correct thread.
// Create a simple LayerImpl tree:
FakeImplProxy proxy;
- FakeLayerTreeHostImpl host_impl(&proxy);
- EXPECT_TRUE(host_impl.InitializeRenderer(CreateFakeOutputSurface()));
- scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl.active_tree(), 1);
- root->AddChild(LayerImpl::Create(host_impl.active_tree(), 2));
+ TestSharedBitmapManager shared_bitmap_manager;
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ EXPECT_TRUE(host_impl.InitializeRenderer(
+ FakeOutputSurface::Create3d().PassAs<OutputSurface>()));
+ scoped_ptr<LayerImpl> root_clip =
+ LayerImpl::Create(host_impl.active_tree(), 1);
+ scoped_ptr<LayerImpl> root_ptr =
+ LayerImpl::Create(host_impl.active_tree(), 2);
+ LayerImpl* root = root_ptr.get();
+ root_clip->AddChild(root_ptr.Pass());
+ scoped_ptr<LayerImpl> scroll_parent =
+ LayerImpl::Create(host_impl.active_tree(), 3);
+ LayerImpl* scroll_child = LayerImpl::Create(host_impl.active_tree(), 4).get();
+ std::set<LayerImpl*>* scroll_children = new std::set<LayerImpl*>();
+ scroll_children->insert(scroll_child);
+ scroll_children->insert(root);
+
+ scoped_ptr<LayerImpl> clip_parent =
+ LayerImpl::Create(host_impl.active_tree(), 5);
+ LayerImpl* clip_child = LayerImpl::Create(host_impl.active_tree(), 6).get();
+ std::set<LayerImpl*>* clip_children = new std::set<LayerImpl*>();
+ clip_children->insert(clip_child);
+ clip_children->insert(root);
+
+ root->AddChild(LayerImpl::Create(host_impl.active_tree(), 7));
LayerImpl* child = root->children()[0];
- child->AddChild(LayerImpl::Create(host_impl.active_tree(), 3));
+ child->AddChild(LayerImpl::Create(host_impl.active_tree(), 8));
LayerImpl* grand_child = child->children()[0];
- root->SetScrollable(true);
+ root->SetScrollClipLayer(root_clip->id());
// Adding children is an internal operation and should not mark layers as
// changed.
@@ -86,6 +121,7 @@ TEST(LayerImplTest, VerifyLayerChangesAreTrackedProperly) {
EXPECT_FALSE(grand_child->LayerPropertyChanged());
gfx::PointF arbitrary_point_f = gfx::PointF(0.125f, 0.25f);
+ gfx::Point3F arbitrary_point_3f = gfx::Point3F(0.125f, 0.25f, 0.f);
float arbitrary_number = 0.352f;
gfx::Size arbitrary_size = gfx::Size(111, 222);
gfx::Point arbitrary_point = gfx::Point(333, 444);
@@ -102,24 +138,24 @@ TEST(LayerImplTest, VerifyLayerChangesAreTrackedProperly) {
// These properties are internal, and should not be considered "change" when
// they are used.
- EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(
- root->set_update_rect(arbitrary_rect_f));
- EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(
- root->SetMaxScrollOffset(arbitrary_vector2d));
+ EXECUTE_AND_VERIFY_NEEDS_PUSH_PROPERTIES_AND_SUBTREE_DID_NOT_CHANGE(
+ root->SetUpdateRect(arbitrary_rect_f));
+ EXECUTE_AND_VERIFY_ONLY_LAYER_CHANGED(root->SetBounds(arbitrary_size));
// Changing these properties affects the entire subtree of layers.
- EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetAnchorPoint(arbitrary_point_f));
- EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetAnchorPointZ(arbitrary_number));
+ EXECUTE_AND_VERIFY_SUBTREE_CHANGED(
+ root->SetTransformOrigin(arbitrary_point_3f));
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetFilters(arbitrary_filters));
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetFilters(FilterOperations()));
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(
- root->SetMaskLayer(LayerImpl::Create(host_impl.active_tree(), 4)));
+ root->SetMaskLayer(LayerImpl::Create(host_impl.active_tree(), 9)));
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetMasksToBounds(true));
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetContentsOpaque(true));
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(
- root->SetReplicaLayer(LayerImpl::Create(host_impl.active_tree(), 5)));
+ root->SetReplicaLayer(LayerImpl::Create(host_impl.active_tree(), 10)));
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetPosition(arbitrary_point_f));
- EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetPreserves3d(true));
+ EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetShouldFlattenTransform(false));
+ EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->Set3dSortingContextId(1));
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(
root->SetDoubleSided(false)); // constructor initializes it to "true".
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->ScrollBy(arbitrary_vector2d));
@@ -140,11 +176,6 @@ TEST(LayerImplTest, VerifyLayerChangesAreTrackedProperly) {
EXECUTE_AND_VERIFY_ONLY_LAYER_CHANGED(
root->SetBackgroundFilters(arbitrary_filters));
- // Changing these properties affects all layer's descendants,
- // but not the layer itself.
- EXECUTE_AND_VERIFY_ONLY_DESCENDANTS_CHANGED(
- root->SetSublayerTransform(arbitrary_transform));
-
// Special case: check that SetBounds changes behavior depending on
// masksToBounds.
root->SetMasksToBounds(false);
@@ -154,19 +185,31 @@ TEST(LayerImplTest, VerifyLayerChangesAreTrackedProperly) {
// changed.
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetBounds(arbitrary_size));
- EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(
+ // Changing this property 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->SetIsRootForIsolatedGroup(true));
+ // Changing these properties should cause the layer to need to push properties
+ EXECUTE_AND_VERIFY_NEEDS_PUSH_PROPERTIES_AND_SUBTREE_DID_NOT_CHANGE(
+ root->SetScrollParent(scroll_parent.get()));
+ EXECUTE_AND_VERIFY_NEEDS_PUSH_PROPERTIES_AND_SUBTREE_DID_NOT_CHANGE(
+ root->SetScrollChildren(scroll_children));
+ EXECUTE_AND_VERIFY_NEEDS_PUSH_PROPERTIES_AND_SUBTREE_DID_NOT_CHANGE(
+ root->SetClipParent(clip_parent.get()));
+ EXECUTE_AND_VERIFY_NEEDS_PUSH_PROPERTIES_AND_SUBTREE_DID_NOT_CHANGE(
+ root->SetClipChildren(clip_children));
+
// After setting all these properties already, setting to the exact same
// values again should not cause any change.
EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(
- root->SetAnchorPoint(arbitrary_point_f));
- EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(
- root->SetAnchorPointZ(arbitrary_number));
+ root->SetTransformOrigin(arbitrary_point_3f));
EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(root->SetMasksToBounds(true));
EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(
root->SetPosition(arbitrary_point_f));
- EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(root->SetPreserves3d(true));
+ EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(
+ root->SetShouldFlattenTransform(false));
+ EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(root->Set3dSortingContextId(1));
EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(
root->SetTransform(arbitrary_transform));
EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(
@@ -186,24 +229,39 @@ TEST(LayerImplTest, VerifyLayerChangesAreTrackedProperly) {
EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(
root->SetIsRootForIsolatedGroup(true));
EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(root->SetDrawsContent(true));
- EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(
- root->SetSublayerTransform(arbitrary_transform));
EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(root->SetBounds(arbitrary_size));
+ EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(
+ root->SetScrollParent(scroll_parent.get()));
+ EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(
+ root->SetScrollChildren(scroll_children));
+ EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(
+ root->SetClipParent(clip_parent.get()));
+ EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(
+ root->SetClipChildren(clip_children));
}
TEST(LayerImplTest, VerifyNeedsUpdateDrawProperties) {
FakeImplProxy proxy;
- FakeLayerTreeHostImpl host_impl(&proxy);
- EXPECT_TRUE(host_impl.InitializeRenderer(CreateFakeOutputSurface()));
- scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl.active_tree(), 1);
- root->SetScrollable(true);
+ TestSharedBitmapManager shared_bitmap_manager;
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ EXPECT_TRUE(host_impl.InitializeRenderer(
+ FakeOutputSurface::Create3d().PassAs<OutputSurface>()));
+ host_impl.active_tree()->SetRootLayer(
+ LayerImpl::Create(host_impl.active_tree(), 1));
+ LayerImpl* root = host_impl.active_tree()->root_layer();
+ scoped_ptr<LayerImpl> layer_ptr =
+ LayerImpl::Create(host_impl.active_tree(), 2);
+ LayerImpl* layer = layer_ptr.get();
+ root->AddChild(layer_ptr.Pass());
+ layer->SetScrollClipLayer(root->id());
+ DCHECK(host_impl.CanDraw());
gfx::PointF arbitrary_point_f = gfx::PointF(0.125f, 0.25f);
float arbitrary_number = 0.352f;
gfx::Size arbitrary_size = gfx::Size(111, 222);
gfx::Point arbitrary_point = gfx::Point(333, 444);
gfx::Vector2d arbitrary_vector2d = gfx::Vector2d(111, 222);
- gfx::Vector2d large_vector2d = gfx::Vector2d(1000, 1000);
+ gfx::Size large_size = gfx::Size(1000, 1000);
gfx::Rect arbitrary_rect = gfx::Rect(arbitrary_point, arbitrary_size);
gfx::RectF arbitrary_rect_f =
gfx::RectF(arbitrary_point_f, gfx::SizeF(1.234f, 5.678f));
@@ -215,89 +273,89 @@ TEST(LayerImplTest, VerifyNeedsUpdateDrawProperties) {
SkXfermode::Mode arbitrary_blend_mode = SkXfermode::kMultiply_Mode;
// Related filter functions.
- VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetFilters(arbitrary_filters));
- VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetFilters(arbitrary_filters));
- VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetFilters(FilterOperations()));
- VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetFilters(arbitrary_filters));
+ VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(layer->SetFilters(arbitrary_filters));
+ VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(layer->SetFilters(arbitrary_filters));
+ VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(layer->SetFilters(FilterOperations()));
+ VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(layer->SetFilters(arbitrary_filters));
// Related scrolling functions.
- VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetMaxScrollOffset(large_vector2d));
- VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(
- root->SetMaxScrollOffset(large_vector2d));
- VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(root->ScrollBy(arbitrary_vector2d));
- VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(root->ScrollBy(gfx::Vector2d()));
- root->SetScrollDelta(gfx::Vector2d(0, 0));
+ VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(layer->SetBounds(large_size));
+ VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(layer->SetBounds(large_size));
+ VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(layer->ScrollBy(arbitrary_vector2d));
+ VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(layer->ScrollBy(gfx::Vector2d()));
+ layer->SetScrollDelta(gfx::Vector2d(0, 0));
host_impl.ForcePrepareToDraw();
- VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetScrollDelta(arbitrary_vector2d));
+ VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(
+ layer->SetScrollDelta(arbitrary_vector2d));
VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(
- root->SetScrollDelta(arbitrary_vector2d));
+ layer->SetScrollDelta(arbitrary_vector2d));
VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(
- root->SetScrollOffset(arbitrary_vector2d));
+ layer->SetScrollOffset(arbitrary_vector2d));
VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(
- root->SetScrollOffset(arbitrary_vector2d));
+ layer->SetScrollOffset(arbitrary_vector2d));
// Unrelated functions, always set to new values, always set needs update.
- VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetAnchorPointZ(arbitrary_number));
VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(
- root->SetMaskLayer(LayerImpl::Create(host_impl.active_tree(), 4)));
- VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetMasksToBounds(true));
- VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetContentsOpaque(true));
+ layer->SetMaskLayer(LayerImpl::Create(host_impl.active_tree(), 4)));
+ VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(layer->SetMasksToBounds(true));
+ VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(layer->SetContentsOpaque(true));
VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(
- root->SetReplicaLayer(LayerImpl::Create(host_impl.active_tree(), 5)));
- VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetPosition(arbitrary_point_f));
- VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetPreserves3d(true));
+ layer->SetReplicaLayer(LayerImpl::Create(host_impl.active_tree(), 5)));
+ VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(layer->SetPosition(arbitrary_point_f));
+ VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(layer->SetShouldFlattenTransform(false));
+ VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(layer->Set3dSortingContextId(1));
+
VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(
- root->SetDoubleSided(false)); // constructor initializes it to "true".
- VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetContentBounds(arbitrary_size));
+ layer->SetDoubleSided(false)); // constructor initializes it to "true".
+ VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(layer->SetContentBounds(arbitrary_size));
VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(
- root->SetContentsScale(arbitrary_number, arbitrary_number));
- VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetDrawsContent(true));
+ layer->SetContentsScale(arbitrary_number, arbitrary_number));
+ VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(layer->SetDrawsContent(true));
VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(
- root->SetBackgroundColor(arbitrary_color));
+ layer->SetBackgroundColor(arbitrary_color));
VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(
- root->SetBackgroundFilters(arbitrary_filters));
- VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetOpacity(arbitrary_number));
- VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetBlendMode(arbitrary_blend_mode));
- VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetTransform(arbitrary_transform));
+ layer->SetBackgroundFilters(arbitrary_filters));
+ VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(layer->SetOpacity(arbitrary_number));
VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(
- root->SetSublayerTransform(arbitrary_transform));
- VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetBounds(arbitrary_size));
+ layer->SetBlendMode(arbitrary_blend_mode));
+ VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(layer->SetTransform(arbitrary_transform));
+ VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(layer->SetBounds(arbitrary_size));
// Unrelated functions, set to the same values, no needs update.
VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(
- root->SetAnchorPointZ(arbitrary_number));
- VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetIsRootForIsolatedGroup(true));
- VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetFilters(arbitrary_filters));
- VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetMasksToBounds(true));
- VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetContentsOpaque(true));
- VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetPosition(arbitrary_point_f));
- VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetPreserves3d(true));
+ layer->SetIsRootForIsolatedGroup(true));
+ VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(layer->SetFilters(arbitrary_filters));
+ VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(layer->SetMasksToBounds(true));
+ VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(layer->SetContentsOpaque(true));
+ VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(layer->SetPosition(arbitrary_point_f));
+ VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(layer->Set3dSortingContextId(1));
VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(
- root->SetDoubleSided(false)); // constructor initializes it to "true".
+ layer->SetDoubleSided(false)); // constructor initializes it to "true".
VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(
- root->SetContentBounds(arbitrary_size));
+ layer->SetContentBounds(arbitrary_size));
VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(
- root->SetContentsScale(arbitrary_number, arbitrary_number));
- VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetDrawsContent(true));
+ layer->SetContentsScale(arbitrary_number, arbitrary_number));
+ VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(layer->SetDrawsContent(true));
VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(
- root->SetBackgroundColor(arbitrary_color));
+ layer->SetBackgroundColor(arbitrary_color));
VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(
- root->SetBackgroundFilters(arbitrary_filters));
- VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetOpacity(arbitrary_number));
+ layer->SetBackgroundFilters(arbitrary_filters));
+ VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(layer->SetOpacity(arbitrary_number));
VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(
- root->SetBlendMode(arbitrary_blend_mode));
- VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetIsRootForIsolatedGroup(true));
+ layer->SetBlendMode(arbitrary_blend_mode));
VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(
- root->SetTransform(arbitrary_transform));
+ layer->SetIsRootForIsolatedGroup(true));
VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(
- root->SetSublayerTransform(arbitrary_transform));
- VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(root->SetBounds(arbitrary_size));
+ layer->SetTransform(arbitrary_transform));
+ VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(layer->SetBounds(arbitrary_size));
}
TEST(LayerImplTest, SafeOpaqueBackgroundColor) {
FakeImplProxy proxy;
- FakeLayerTreeHostImpl host_impl(&proxy);
- EXPECT_TRUE(host_impl.InitializeRenderer(CreateFakeOutputSurface()));
+ TestSharedBitmapManager shared_bitmap_manager;
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ EXPECT_TRUE(host_impl.InitializeRenderer(
+ FakeOutputSurface::Create3d().PassAs<OutputSurface>()));
scoped_ptr<LayerImpl> layer = LayerImpl::Create(host_impl.active_tree(), 1);
for (int contents_opaque = 0; contents_opaque < 2; ++contents_opaque) {
@@ -324,18 +382,60 @@ TEST(LayerImplTest, SafeOpaqueBackgroundColor) {
}
}
+TEST(LayerImplTest, TransformInvertibility) {
+ FakeImplProxy proxy;
+ TestSharedBitmapManager shared_bitmap_manager;
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+
+ scoped_ptr<LayerImpl> layer = LayerImpl::Create(host_impl.active_tree(), 1);
+ EXPECT_TRUE(layer->transform().IsInvertible());
+ EXPECT_TRUE(layer->transform_is_invertible());
+
+ gfx::Transform transform;
+ transform.Scale3d(
+ SkDoubleToMScalar(1.0), SkDoubleToMScalar(1.0), SkDoubleToMScalar(0.0));
+ layer->SetTransform(transform);
+ EXPECT_FALSE(layer->transform().IsInvertible());
+ EXPECT_FALSE(layer->transform_is_invertible());
+
+ transform.MakeIdentity();
+ transform.ApplyPerspectiveDepth(SkDoubleToMScalar(100.0));
+ transform.RotateAboutZAxis(75.0);
+ transform.RotateAboutXAxis(32.2);
+ transform.RotateAboutZAxis(-75.0);
+ transform.Translate3d(SkDoubleToMScalar(50.5),
+ SkDoubleToMScalar(42.42),
+ SkDoubleToMScalar(-100.25));
+
+ layer->SetTransform(transform);
+ EXPECT_TRUE(layer->transform().IsInvertible());
+ EXPECT_TRUE(layer->transform_is_invertible());
+}
+
class LayerImplScrollTest : public testing::Test {
public:
- LayerImplScrollTest() : host_impl_(&proxy_), root_id_(7) {
- host_impl_.active_tree()
- ->SetRootLayer(LayerImpl::Create(host_impl_.active_tree(), root_id_));
- host_impl_.active_tree()->root_layer()->SetScrollable(true);
+ LayerImplScrollTest()
+ : host_impl_(&proxy_, &shared_bitmap_manager_), root_id_(7) {
+ host_impl_.active_tree()->SetRootLayer(
+ LayerImpl::Create(host_impl_.active_tree(), root_id_));
+ host_impl_.active_tree()->root_layer()->AddChild(
+ LayerImpl::Create(host_impl_.active_tree(), root_id_ + 1));
+ layer()->SetScrollClipLayer(root_id_);
+ // Set the max scroll offset by noting that the root layer has bounds (1,1),
+ // thus whatever bounds are set for the layer will be the max scroll
+ // offset plus 1 in each direction.
+ host_impl_.active_tree()->root_layer()->SetBounds(gfx::Size(1, 1));
+ gfx::Vector2d max_scroll_offset(51, 81);
+ layer()->SetBounds(gfx::Size(max_scroll_offset.x(), max_scroll_offset.y()));
}
- LayerImpl* layer() { return host_impl_.active_tree()->root_layer(); }
+ LayerImpl* layer() {
+ return host_impl_.active_tree()->root_layer()->children()[0];
+ }
private:
FakeImplProxy proxy_;
+ TestSharedBitmapManager shared_bitmap_manager_;
FakeLayerTreeHostImpl host_impl_;
int root_id_;
};
@@ -343,8 +443,6 @@ class LayerImplScrollTest : public testing::Test {
TEST_F(LayerImplScrollTest, ScrollByWithZeroOffset) {
// Test that LayerImpl::ScrollBy only affects ScrollDelta and total scroll
// offset is bounded by the range [0, max scroll offset].
- gfx::Vector2d max_scroll_offset(50, 80);
- layer()->SetMaxScrollOffset(max_scroll_offset);
EXPECT_VECTOR_EQ(gfx::Vector2dF(), layer()->TotalScrollOffset());
EXPECT_VECTOR_EQ(gfx::Vector2dF(), layer()->scroll_offset());
@@ -364,9 +462,7 @@ TEST_F(LayerImplScrollTest, ScrollByWithZeroOffset) {
}
TEST_F(LayerImplScrollTest, ScrollByWithNonZeroOffset) {
- gfx::Vector2d max_scroll_offset(50, 80);
gfx::Vector2d scroll_offset(10, 5);
- layer()->SetMaxScrollOffset(max_scroll_offset);
layer()->SetScrollOffset(scroll_offset);
EXPECT_VECTOR_EQ(scroll_offset, layer()->TotalScrollOffset());
@@ -388,30 +484,24 @@ TEST_F(LayerImplScrollTest, ScrollByWithNonZeroOffset) {
EXPECT_VECTOR_EQ(scroll_offset, layer()->scroll_offset());
}
-class ScrollDelegateIgnore : public LayerScrollOffsetDelegate {
+class ScrollDelegateIgnore : public LayerImpl::ScrollOffsetDelegate {
public:
- virtual void SetMaxScrollOffset(gfx::Vector2dF max_scroll_offset) OVERRIDE {}
- virtual void SetTotalScrollOffset(gfx::Vector2dF new_value) OVERRIDE {}
+ virtual void SetTotalScrollOffset(const gfx::Vector2dF& new_value) OVERRIDE {}
virtual gfx::Vector2dF GetTotalScrollOffset() OVERRIDE {
return fixed_offset_;
}
virtual bool IsExternalFlingActive() const OVERRIDE { return false; }
- void set_fixed_offset(gfx::Vector2dF fixed_offset) {
+ void set_fixed_offset(const gfx::Vector2dF& fixed_offset) {
fixed_offset_ = fixed_offset;
}
- virtual void SetTotalPageScaleFactor(float page_scale_factor) OVERRIDE {}
- virtual void SetScrollableSize(gfx::SizeF scrollable_size) OVERRIDE {}
-
private:
gfx::Vector2dF fixed_offset_;
};
TEST_F(LayerImplScrollTest, ScrollByWithIgnoringDelegate) {
- gfx::Vector2d max_scroll_offset(50, 80);
gfx::Vector2d scroll_offset(10, 5);
- layer()->SetMaxScrollOffset(max_scroll_offset);
layer()->SetScrollOffset(scroll_offset);
EXPECT_VECTOR_EQ(scroll_offset, layer()->TotalScrollOffset());
@@ -443,27 +533,22 @@ TEST_F(LayerImplScrollTest, ScrollByWithIgnoringDelegate) {
EXPECT_VECTOR_EQ(scroll_offset, layer()->scroll_offset());
}
-class ScrollDelegateAccept : public LayerScrollOffsetDelegate {
+class ScrollDelegateAccept : public LayerImpl::ScrollOffsetDelegate {
public:
- virtual void SetMaxScrollOffset(gfx::Vector2dF max_scroll_offset) OVERRIDE {}
- virtual void SetTotalScrollOffset(gfx::Vector2dF new_value) OVERRIDE {
+ virtual void SetTotalScrollOffset(const gfx::Vector2dF& new_value) OVERRIDE {
current_offset_ = new_value;
}
virtual gfx::Vector2dF GetTotalScrollOffset() OVERRIDE {
return current_offset_;
}
virtual bool IsExternalFlingActive() const OVERRIDE { return false; }
- virtual void SetTotalPageScaleFactor(float page_scale_factor) OVERRIDE {}
- virtual void SetScrollableSize(gfx::SizeF scrollable_size) OVERRIDE {}
private:
gfx::Vector2dF current_offset_;
};
TEST_F(LayerImplScrollTest, ScrollByWithAcceptingDelegate) {
- gfx::Vector2d max_scroll_offset(50, 80);
gfx::Vector2d scroll_offset(10, 5);
- layer()->SetMaxScrollOffset(max_scroll_offset);
layer()->SetScrollOffset(scroll_offset);
EXPECT_VECTOR_EQ(scroll_offset, layer()->TotalScrollOffset());
@@ -495,12 +580,10 @@ TEST_F(LayerImplScrollTest, ScrollByWithAcceptingDelegate) {
}
TEST_F(LayerImplScrollTest, ApplySentScrollsNoDelegate) {
- gfx::Vector2d max_scroll_offset(50, 80);
gfx::Vector2d scroll_offset(10, 5);
gfx::Vector2dF scroll_delta(20.5f, 8.5f);
gfx::Vector2d sent_scroll_delta(12, -3);
- layer()->SetMaxScrollOffset(max_scroll_offset);
layer()->SetScrollOffset(scroll_offset);
layer()->ScrollBy(scroll_delta);
layer()->SetSentScrollDelta(sent_scroll_delta);
@@ -519,12 +602,10 @@ TEST_F(LayerImplScrollTest, ApplySentScrollsNoDelegate) {
}
TEST_F(LayerImplScrollTest, ApplySentScrollsWithIgnoringDelegate) {
- gfx::Vector2d max_scroll_offset(50, 80);
gfx::Vector2d scroll_offset(10, 5);
gfx::Vector2d sent_scroll_delta(12, -3);
gfx::Vector2dF fixed_offset(32, 12);
- layer()->SetMaxScrollOffset(max_scroll_offset);
layer()->SetScrollOffset(scroll_offset);
ScrollDelegateIgnore delegate;
delegate.set_fixed_offset(fixed_offset);
@@ -543,12 +624,10 @@ TEST_F(LayerImplScrollTest, ApplySentScrollsWithIgnoringDelegate) {
}
TEST_F(LayerImplScrollTest, ApplySentScrollsWithAcceptingDelegate) {
- gfx::Vector2d max_scroll_offset(50, 80);
gfx::Vector2d scroll_offset(10, 5);
gfx::Vector2d sent_scroll_delta(12, -3);
gfx::Vector2dF scroll_delta(20.5f, 8.5f);
- layer()->SetMaxScrollOffset(max_scroll_offset);
layer()->SetScrollOffset(scroll_offset);
ScrollDelegateAccept delegate;
layer()->SetScrollOffsetDelegate(&delegate);
@@ -569,12 +648,10 @@ TEST_F(LayerImplScrollTest, ApplySentScrollsWithAcceptingDelegate) {
// The user-scrollability breaks for zoomed-in pages. So disable this.
// http://crbug.com/322223
TEST_F(LayerImplScrollTest, DISABLED_ScrollUserUnscrollableLayer) {
- gfx::Vector2d max_scroll_offset(50, 80);
gfx::Vector2d scroll_offset(10, 5);
gfx::Vector2dF scroll_delta(20.5f, 8.5f);
layer()->set_user_scrollable_vertical(false);
- layer()->SetMaxScrollOffset(max_scroll_offset);
layer()->SetScrollOffset(scroll_offset);
gfx::Vector2dF unscrolled = layer()->ScrollBy(scroll_delta);
diff --git a/chromium/cc/layers/layer_iterator.cc b/chromium/cc/layers/layer_iterator.cc
deleted file mode 100644
index a52c3f1f39a..00000000000
--- a/chromium/cc/layers/layer_iterator.cc
+++ /dev/null
@@ -1,130 +0,0 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/layers/layer_iterator.h"
-
-#include <vector>
-
-#include "cc/layers/layer.h"
-#include "cc/layers/layer_impl.h"
-#include "cc/layers/render_surface.h"
-#include "cc/layers/render_surface_impl.h"
-
-namespace cc {
-
-template <typename LayerType,
- typename LayerList,
- typename RenderSurfaceType,
- typename ActionType>
-void LayerIteratorActions::FrontToBack::Begin(
- LayerIterator<LayerType, LayerList, RenderSurfaceType, ActionType>* it) {
- it->target_render_surface_layer_index_ = 0;
- it->current_layer_index_ = it->target_render_surface_children().size() - 1;
- GoToHighestInSubtree(it);
-}
-
-template <typename LayerType,
- typename LayerList,
- typename RenderSurfaceType,
- typename ActionType>
-void LayerIteratorActions::FrontToBack::End(
- LayerIterator<LayerType, LayerList, RenderSurfaceType, ActionType>* it) {
- it->target_render_surface_layer_index_ =
- LayerIteratorValue::kInvalidTargetRenderSurfaceLayerIndex;
- it->current_layer_index_ = 0;
-}
-
-template <typename LayerType,
- typename LayerList,
- typename RenderSurfaceType,
- typename ActionType>
-void LayerIteratorActions::FrontToBack::Next(
- LayerIterator<LayerType, LayerList, RenderSurfaceType, ActionType>* it) {
- // Moves to the previous layer in the current RS layer list.
- // Then we check if the new current layer has its own RS,
- // in which case there are things in that RS layer list that are higher,
- // so we find the highest layer in that subtree.
- // If we move back past the front of the list,
- // we jump up to the previous RS layer list, picking up again where we
- // had previously recursed into the current RS layer list.
-
- if (!it->current_layer_represents_target_render_surface()) {
- // Subtracting one here will eventually cause the current layer
- // to become that layer representing the target render surface.
- --it->current_layer_index_;
- GoToHighestInSubtree(it);
- } else {
- while (it->current_layer_represents_target_render_surface()) {
- if (!it->target_render_surface_layer_index_) {
- // End of the list
- it->target_render_surface_layer_index_ =
- LayerIteratorValue::kInvalidTargetRenderSurfaceLayerIndex;
- it->current_layer_index_ = 0;
- return;
- }
- it->target_render_surface_layer_index_ = it->target_render_surface()
- ->target_render_surface_layer_index_history_;
- it->current_layer_index_ =
- it->target_render_surface()->current_layer_index_history_;
- }
- }
-}
-
-template <typename LayerType,
- typename LayerList,
- typename RenderSurfaceType,
- typename ActionType>
-void LayerIteratorActions::FrontToBack::GoToHighestInSubtree(
- LayerIterator<LayerType, LayerList, RenderSurfaceType, ActionType>* it) {
- if (it->current_layer_represents_target_render_surface())
- return;
- while (it->current_layer_represents_contributing_render_surface()) {
- // Save where we were in the current target surface, move to the next one,
- // and save the target surface that we came from there
- // so we can go back to it.
- it->target_render_surface()->current_layer_index_history_ =
- it->current_layer_index_;
- int previous_target_render_surface_layer =
- it->target_render_surface_layer_index_;
-
- for (LayerType* layer = it->current_layer();
- it->target_render_surface_layer() != layer;
- ++it->target_render_surface_layer_index_) {
- }
- it->current_layer_index_ = it->target_render_surface_children().size() - 1;
-
- it->target_render_surface()->target_render_surface_layer_index_history_ =
- previous_target_render_surface_layer;
- }
-}
-
-// Declare each of the above functions for Layer and LayerImpl classes
-// so that they are linked.
-template CC_EXPORT void LayerIteratorActions::FrontToBack::Next(
- LayerIterator<Layer, RenderSurfaceLayerList, RenderSurface, FrontToBack>*
- it);
-template CC_EXPORT void LayerIteratorActions::FrontToBack::End(
- LayerIterator<Layer, RenderSurfaceLayerList, RenderSurface, FrontToBack>*
- it);
-template CC_EXPORT void LayerIteratorActions::FrontToBack::Begin(
- LayerIterator<Layer, RenderSurfaceLayerList, RenderSurface, FrontToBack>*
- it);
-template CC_EXPORT void LayerIteratorActions::FrontToBack::GoToHighestInSubtree(
- LayerIterator<Layer, RenderSurfaceLayerList, RenderSurface, FrontToBack>*
- it);
-
-template CC_EXPORT void LayerIteratorActions::FrontToBack::Next(
- LayerIterator<LayerImpl, LayerImplList, RenderSurfaceImpl, FrontToBack>*
- it);
-template CC_EXPORT void LayerIteratorActions::FrontToBack::End(
- LayerIterator<LayerImpl, LayerImplList, RenderSurfaceImpl, FrontToBack>*
- it);
-template CC_EXPORT void LayerIteratorActions::FrontToBack::Begin(
- LayerIterator<LayerImpl, LayerImplList, RenderSurfaceImpl, FrontToBack>*
- it);
-template CC_EXPORT void LayerIteratorActions::FrontToBack::GoToHighestInSubtree(
- LayerIterator<LayerImpl, LayerImplList, RenderSurfaceImpl, FrontToBack>*
- it);
-
-} // namespace cc
diff --git a/chromium/cc/layers/layer_iterator.h b/chromium/cc/layers/layer_iterator.h
index 5b132732545..fbdb53a25c2 100644
--- a/chromium/cc/layers/layer_iterator.h
+++ b/chromium/cc/layers/layer_iterator.h
@@ -5,7 +5,6 @@
#ifndef CC_LAYERS_LAYER_ITERATOR_H_
#define CC_LAYERS_LAYER_ITERATOR_H_
-#include "base/memory/ref_counted.h"
#include "cc/base/cc_export.h"
#include "cc/trees/layer_tree_host_common.h"
@@ -19,11 +18,7 @@ namespace cc {
//
// void DoStuffOnLayers(
// const RenderSurfaceLayerList& render_surface_layer_list) {
-// typedef LayerIterator<Layer,
-// RenderSurfaceLayerList,
-// RenderSurface,
-// LayerIteratorActions::FrontToBack>
-// LayerIteratorType;
+// typedef LayerIterator<Layer> LayerIteratorType;
//
// LayerIteratorType end =
// LayerIteratorType::End(&render_surface_layer_list);
@@ -105,28 +100,27 @@ template <typename LayerType> struct LayerIteratorPosition {
// An iterator class for walking over layers in the
// RenderSurface-Layer tree.
-template <typename LayerType,
- typename LayerList,
- typename RenderSurfaceType,
- typename IteratorActionType>
+template <typename LayerType>
class LayerIterator {
- typedef LayerIterator<LayerType,
- LayerList,
- RenderSurfaceType,
- IteratorActionType> LayerIteratorType;
+ typedef LayerIterator<LayerType> LayerIteratorType;
+ typedef typename LayerType::LayerListType LayerList;
+ typedef typename LayerType::RenderSurfaceListType RenderSurfaceLayerList;
+ typedef typename LayerType::RenderSurfaceType RenderSurfaceType;
public:
LayerIterator() : render_surface_layer_list_(NULL) {}
- static LayerIteratorType Begin(const LayerList* render_surface_layer_list) {
+ static LayerIteratorType Begin(
+ const RenderSurfaceLayerList* render_surface_layer_list) {
return LayerIteratorType(render_surface_layer_list, true);
}
- static LayerIteratorType End(const LayerList* render_surface_layer_list) {
+ static LayerIteratorType End(
+ const RenderSurfaceLayerList* render_surface_layer_list) {
return LayerIteratorType(render_surface_layer_list, false);
}
LayerIteratorType& operator++() {
- actions_.Next(this);
+ MoveToNext();
return *this;
}
bool operator==(const LayerIterator& other) const {
@@ -170,27 +164,95 @@ class LayerIterator {
}
private:
- LayerIterator(const LayerList* render_surface_layer_list, bool start)
+ LayerIterator(const RenderSurfaceLayerList* render_surface_layer_list,
+ bool start)
: render_surface_layer_list_(render_surface_layer_list),
target_render_surface_layer_index_(0) {
for (size_t i = 0; i < render_surface_layer_list->size(); ++i) {
if (!render_surface_layer_list->at(i)->render_surface()) {
NOTREACHED();
- actions_.End(this);
+ MoveToEnd();
return;
}
}
if (start && !render_surface_layer_list->empty())
- actions_.Begin(this);
+ MoveToBegin();
else
- actions_.End(this);
+ MoveToEnd();
+ }
+
+ void MoveToBegin() {
+ target_render_surface_layer_index_ = 0;
+ current_layer_index_ = target_render_surface_children().size() - 1;
+ MoveToHighestInSubtree();
+ }
+
+ void MoveToEnd() {
+ target_render_surface_layer_index_ =
+ LayerIteratorValue::kInvalidTargetRenderSurfaceLayerIndex;
+ current_layer_index_ = 0;
+ }
+
+ void MoveToNext() {
+ // Moves to the previous layer in the current RS layer list.
+ // Then we check if the new current layer has its own RS,
+ // in which case there are things in that RS layer list that are higher,
+ // so we find the highest layer in that subtree.
+ // If we move back past the front of the list,
+ // we jump up to the previous RS layer list, picking up again where we
+ // had previously recursed into the current RS layer list.
+
+ if (!current_layer_represents_target_render_surface()) {
+ // Subtracting one here will eventually cause the current layer
+ // to become that layer representing the target render surface.
+ --current_layer_index_;
+ MoveToHighestInSubtree();
+ } else {
+ while (current_layer_represents_target_render_surface()) {
+ if (!target_render_surface_layer_index_) {
+ // End of the list.
+ target_render_surface_layer_index_ =
+ LayerIteratorValue::kInvalidTargetRenderSurfaceLayerIndex;
+ current_layer_index_ = 0;
+ return;
+ }
+ target_render_surface_layer_index_ =
+ target_render_surface()->target_render_surface_layer_index_history_;
+ current_layer_index_ =
+ target_render_surface()->current_layer_index_history_;
+ }
+ }
+ }
+
+ void MoveToHighestInSubtree() {
+ if (current_layer_represents_target_render_surface())
+ return;
+ while (current_layer_represents_contributing_render_surface()) {
+ // Save where we were in the current target surface, move to the next one,
+ // and save the target surface that we came from there
+ // so we can go back to it.
+ target_render_surface()->current_layer_index_history_ =
+ current_layer_index_;
+ int previous_target_render_surface_layer =
+ target_render_surface_layer_index_;
+
+ for (LayerType* layer = current_layer();
+ target_render_surface_layer() != layer;
+ ++target_render_surface_layer_index_) {
+ }
+ current_layer_index_ = target_render_surface_children().size() - 1;
+
+ target_render_surface()->target_render_surface_layer_index_history_ =
+ previous_target_render_surface_layer;
+ }
}
inline LayerType* current_layer() const {
return current_layer_represents_target_render_surface()
- ? target_render_surface_layer()
- : target_render_surface_children().at(current_layer_index_);
+ ? target_render_surface_layer()
+ : LayerTreeHostCommon::get_layer_as_raw_ptr(
+ target_render_surface_children(), current_layer_index_);
}
inline bool current_layer_represents_contributing_render_surface() const {
@@ -209,8 +271,7 @@ class LayerIterator {
return target_render_surface()->layer_list();
}
- IteratorActionType actions_;
- const LayerList* render_surface_layer_list_;
+ const RenderSurfaceLayerList* render_surface_layer_list_;
// The iterator's current position.
@@ -228,44 +289,6 @@ class LayerIterator {
// the target surface, this is done by setting the current_layerIndex
// to a value of LayerIteratorValue::LayerRepresentingTargetRenderSurface.
int current_layer_index_;
-
- friend struct LayerIteratorActions;
-};
-
-// Orderings for iterating over the RenderSurface-Layer tree.
-struct CC_EXPORT LayerIteratorActions {
- // Walks layers sorted by z-order from front to back
- class CC_EXPORT FrontToBack {
- public:
- template <typename LayerType,
- typename LayerList,
- typename RenderSurfaceType,
- typename ActionType>
- void Begin(
- LayerIterator<LayerType, LayerList, RenderSurfaceType, ActionType>* it);
-
- template <typename LayerType,
- typename LayerList,
- typename RenderSurfaceType,
- typename ActionType>
- void End(
- LayerIterator<LayerType, LayerList, RenderSurfaceType, ActionType>* it);
-
- template <typename LayerType,
- typename LayerList,
- typename RenderSurfaceType,
- typename ActionType>
- void Next(
- LayerIterator<LayerType, LayerList, RenderSurfaceType, ActionType>* it);
-
- private:
- template <typename LayerType,
- typename LayerList,
- typename RenderSurfaceType,
- typename ActionType>
- void GoToHighestInSubtree(
- LayerIterator<LayerType, LayerList, RenderSurfaceType, ActionType>* it);
- };
};
} // namespace cc
diff --git a/chromium/cc/layers/layer_iterator_unittest.cc b/chromium/cc/layers/layer_iterator_unittest.cc
index c781d28b13f..a7f85b76313 100644
--- a/chromium/cc/layers/layer_iterator_unittest.cc
+++ b/chromium/cc/layers/layer_iterator_unittest.cc
@@ -38,7 +38,6 @@ class TestLayer : public Layer {
TestLayer() : Layer(), draws_content_(true) {
SetBounds(gfx::Size(100, 100));
SetPosition(gfx::Point());
- SetAnchorPoint(gfx::Point());
}
virtual ~TestLayer() {}
@@ -50,10 +49,7 @@ class TestLayer : public Layer {
EXPECT_EQ(contrib, layer->count_representing_contributing_surface_); \
EXPECT_EQ(itself, layer->count_representing_itself_);
-typedef LayerIterator<Layer,
- RenderSurfaceLayerList,
- RenderSurface,
- LayerIteratorActions::FrontToBack> FrontToBack;
+typedef LayerIterator<Layer> FrontToBack;
void ResetCounts(RenderSurfaceLayerList* render_surface_layer_list) {
for (unsigned surface_index = 0;
@@ -71,7 +67,7 @@ void ResetCounts(RenderSurfaceLayerList* render_surface_layer_list) {
layer_index < render_surface->layer_list().size();
++layer_index) {
TestLayer* layer = static_cast<TestLayer*>(
- render_surface->layer_list().at(layer_index));
+ render_surface->layer_list().at(layer_index).get());
layer->count_representing_target_surface_ = -1;
layer->count_representing_contributing_surface_ = -1;
diff --git a/chromium/cc/layers/layer_lists.h b/chromium/cc/layers/layer_lists.h
index 01a7966888f..c0f7bbf0628 100644
--- a/chromium/cc/layers/layer_lists.h
+++ b/chromium/cc/layers/layer_lists.h
@@ -38,6 +38,8 @@ class CC_EXPORT RenderSurfaceLayerList {
LayerList::const_iterator begin() const;
LayerList::const_iterator end() const;
void clear();
+ LayerList& AsLayerList() { return list_; }
+ const LayerList& AsLayerList() const { return list_; }
private:
LayerList list_;
diff --git a/chromium/cc/layers/layer_perftest.cc b/chromium/cc/layers/layer_perftest.cc
index 5a2de60d203..1c4519a45fb 100644
--- a/chromium/cc/layers/layer_perftest.cc
+++ b/chromium/cc/layers/layer_perftest.cc
@@ -4,12 +4,12 @@
#include "cc/layers/layer.h"
+#include "cc/debug/lap_timer.h"
#include "cc/resources/layer_painter.h"
#include "cc/test/fake_impl_proxy.h"
#include "cc/test/fake_layer_tree_host.h"
#include "cc/test/fake_layer_tree_host_client.h"
#include "cc/test/fake_layer_tree_host_impl.h"
-#include "cc/test/lap_timer.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/perf/perf_test.h"
@@ -24,7 +24,7 @@ static const int kTimeCheckInterval = 10;
class MockLayerPainter : public LayerPainter {
public:
virtual void Paint(SkCanvas* canvas,
- gfx::Rect content_rect,
+ const gfx::Rect& content_rect,
gfx::RectF* opaque) OVERRIDE {}
};
@@ -32,7 +32,7 @@ class MockLayerPainter : public LayerPainter {
class LayerPerfTest : public testing::Test {
public:
LayerPerfTest()
- : host_impl_(&proxy_),
+ : host_impl_(&proxy_, &shared_bitmap_manager_),
fake_client_(FakeLayerTreeHostClient::DIRECT_3D),
timer_(kWarmupRuns,
base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
@@ -50,6 +50,7 @@ class LayerPerfTest : public testing::Test {
}
FakeImplProxy proxy_;
+ TestSharedBitmapManager shared_bitmap_manager_;
FakeLayerTreeHostImpl host_impl_;
FakeLayerTreeHostClient fake_client_;
@@ -64,7 +65,7 @@ TEST_F(LayerPerfTest, PushPropertiesTo) {
layer_tree_host_->SetRootLayer(test_layer);
- float anchor_point_z = 0;
+ float transform_origin_z = 0;
bool scrollable = true;
bool contents_opaque = true;
bool double_sided = true;
@@ -75,15 +76,16 @@ TEST_F(LayerPerfTest, PushPropertiesTo) {
timer_.Reset();
do {
test_layer->SetNeedsDisplayRect(gfx::RectF(0.f, 0.f, 5.f, 5.f));
- test_layer->SetAnchorPointZ(anchor_point_z);
+ test_layer->SetTransformOrigin(gfx::Point3F(0.f, 0.f, transform_origin_z));
test_layer->SetContentsOpaque(contents_opaque);
test_layer->SetDoubleSided(double_sided);
test_layer->SetHideLayerAndSubtree(hide_layer_and_subtree);
test_layer->SetMasksToBounds(masks_to_bounds);
- test_layer->SetScrollable(scrollable);
+ test_layer->SetScrollClipLayerId(scrollable ? test_layer->id()
+ : Layer::INVALID_ID);
test_layer->PushPropertiesTo(impl_layer.get());
- anchor_point_z += 0.01f;
+ transform_origin_z += 0.01f;
scrollable = !scrollable;
contents_opaque = !contents_opaque;
double_sided = !double_sided;
diff --git a/chromium/cc/layers/layer_position_constraint_unittest.cc b/chromium/cc/layers/layer_position_constraint_unittest.cc
index 8f6dcb11798..d9e1f64bbc8 100644
--- a/chromium/cc/layers/layer_position_constraint_unittest.cc
+++ b/chromium/cc/layers/layer_position_constraint_unittest.cc
@@ -10,6 +10,7 @@
#include "cc/test/fake_impl_proxy.h"
#include "cc/test/fake_layer_tree_host_impl.h"
#include "cc/test/geometry_test_utils.h"
+#include "cc/test/test_shared_bitmap_manager.h"
#include "cc/trees/layer_tree_host_common.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -18,17 +19,15 @@ namespace {
void SetLayerPropertiesForTesting(LayerImpl* layer,
const gfx::Transform& transform,
- const gfx::Transform& sublayer_transform,
- gfx::PointF anchor,
- gfx::PointF position,
- gfx::Size bounds,
- bool preserves3d) {
+ const gfx::Point3F& transform_origin,
+ const gfx::PointF& position,
+ const gfx::Size& bounds,
+ bool flatten_transform) {
layer->SetTransform(transform);
- layer->SetSublayerTransform(sublayer_transform);
- layer->SetAnchorPoint(anchor);
+ layer->SetTransformOrigin(transform_origin);
layer->SetPosition(position);
layer->SetBounds(bounds);
- layer->SetPreserves3d(preserves3d);
+ layer->SetShouldFlattenTransform(flatten_transform);
layer->SetContentBounds(bounds);
}
@@ -39,13 +38,14 @@ void ExecuteCalculateDrawProperties(LayerImpl* root_layer,
bool can_use_lcd_text) {
gfx::Transform identity_matrix;
std::vector<LayerImpl*> dummy_render_surface_layer_list;
+ LayerImpl* scroll_layer = root_layer->children()[0];
gfx::Size device_viewport_size =
gfx::Size(root_layer->bounds().width() * device_scale_factor,
root_layer->bounds().height() * device_scale_factor);
- // We are probably not testing what is intended if the root_layer bounds are
+ // We are probably not testing what is intended if the scroll_layer bounds are
// empty.
- DCHECK(!root_layer->bounds().IsEmpty());
+ DCHECK(!scroll_layer->bounds().IsEmpty());
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
root_layer, device_viewport_size, &dummy_render_surface_layer_list);
inputs.device_scale_factor = device_scale_factor;
@@ -63,9 +63,9 @@ void ExecuteCalculateDrawProperties(LayerImpl* root_layer) {
class LayerPositionConstraintTest : public testing::Test {
public:
- LayerPositionConstraintTest()
- : host_impl_(&proxy_) {
+ LayerPositionConstraintTest() : host_impl_(&proxy_, &shared_bitmap_manager_) {
root_ = CreateTreeForTest();
+ scroll_ = root_->children()[0];
fixed_to_top_left_.set_is_fixed_position(true);
fixed_to_bottom_right_.set_is_fixed_position(true);
fixed_to_bottom_right_.set_is_fixed_to_right_edge(true);
@@ -74,6 +74,8 @@ class LayerPositionConstraintTest : public testing::Test {
scoped_ptr<LayerImpl> CreateTreeForTest() {
scoped_ptr<LayerImpl> root =
+ LayerImpl::Create(host_impl_.active_tree(), 42);
+ scoped_ptr<LayerImpl> scroll_layer =
LayerImpl::Create(host_impl_.active_tree(), 1);
scoped_ptr<LayerImpl> child =
LayerImpl::Create(host_impl_.active_tree(), 2);
@@ -83,66 +85,75 @@ class LayerPositionConstraintTest : public testing::Test {
LayerImpl::Create(host_impl_.active_tree(), 4);
gfx::Transform IdentityMatrix;
- gfx::PointF anchor;
+ gfx::Point3F transform_origin;
gfx::PointF position;
- gfx::Size bounds(100, 100);
- SetLayerPropertiesForTesting(root.get(),
+ gfx::Size bounds(200, 200);
+ gfx::Size clip_bounds(100, 100);
+ SetLayerPropertiesForTesting(scroll_layer.get(),
IdentityMatrix,
- IdentityMatrix,
- anchor,
+ transform_origin,
position,
bounds,
- false);
- SetLayerPropertiesForTesting(child.get(),
- IdentityMatrix,
- IdentityMatrix,
- anchor,
- position,
- bounds,
- false);
+ true);
+ SetLayerPropertiesForTesting(
+ child.get(), IdentityMatrix, transform_origin, position, bounds, true);
SetLayerPropertiesForTesting(grand_child.get(),
IdentityMatrix,
- IdentityMatrix,
- anchor,
+ transform_origin,
position,
bounds,
- false);
+ true);
SetLayerPropertiesForTesting(great_grand_child.get(),
IdentityMatrix,
- IdentityMatrix,
- anchor,
+ transform_origin,
position,
bounds,
- false);
+ true);
- root->SetMaxScrollOffset(gfx::Vector2d(100, 100));
- root->SetScrollable(true);
- child->SetMaxScrollOffset(gfx::Vector2d(100, 100));
- child->SetScrollable(true);
- grand_child->SetMaxScrollOffset(gfx::Vector2d(100, 100));
- grand_child->SetScrollable(true);
+ root->SetBounds(clip_bounds);
+ scroll_layer->SetScrollClipLayer(root->id());
+ child->SetScrollClipLayer(root->id());
+ grand_child->SetScrollClipLayer(root->id());
grand_child->AddChild(great_grand_child.Pass());
child->AddChild(grand_child.Pass());
- root->AddChild(child.Pass());
+ scroll_layer->AddChild(child.Pass());
+ root->AddChild(scroll_layer.Pass());
return root.Pass();
}
protected:
FakeImplProxy proxy_;
+ TestSharedBitmapManager shared_bitmap_manager_;
FakeLayerTreeHostImpl host_impl_;
scoped_ptr<LayerImpl> root_;
+ LayerImpl* scroll_;
LayerPositionConstraint fixed_to_top_left_;
LayerPositionConstraint fixed_to_bottom_right_;
};
+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();
+ gfx::Size container_size(container_layer->bounds());
+ gfx::Size new_container_size(container_size.width() + delta.x(),
+ container_size.height() + delta.y());
+ container_layer->SetTemporaryImplBounds(new_container_size);
+}
+} // namespace
+
TEST_F(LayerPositionConstraintTest,
ScrollCompensationForFixedPositionLayerWithDirectContainer) {
// This test checks for correct scroll compensation when the fixed-position
// container is the direct parent of the fixed-position layer.
- LayerImpl* child = root_->children()[0];
+ LayerImpl* child = scroll_->children()[0];
LayerImpl* grand_child = child->children()[0];
child->SetIsContainerForFixedPositionLayers(true);
@@ -175,7 +186,7 @@ TEST_F(LayerPositionConstraintTest,
grand_child->draw_transform());
// Case 3: fixed-container size delta of 20, 20
- child->SetFixedContainerSizeDelta(gfx::Vector2d(20, 20));
+ SetFixedContainerSizeDelta(child, gfx::Vector2d(20, 20));
ExecuteCalculateDrawProperties(root_.get());
// Top-left fixed-position layer should not be affected by container size.
@@ -210,7 +221,7 @@ TEST_F(LayerPositionConstraintTest,
// Transforms are in general non-commutative; using something like a
// non-uniform scale helps to verify that translations and non-uniform scales
// are applied in the correct order.
- LayerImpl* child = root_->children()[0];
+ LayerImpl* child = scroll_->children()[0];
LayerImpl* grand_child = child->children()[0];
// This scale will cause child and grand_child to be effectively 200 x 800
@@ -252,7 +263,7 @@ TEST_F(LayerPositionConstraintTest,
grand_child->draw_transform());
// Case 3: fixed-container size delta of 20, 20
- child->SetFixedContainerSizeDelta(gfx::Vector2d(20, 20));
+ SetFixedContainerSizeDelta(child, gfx::Vector2d(20, 20));
ExecuteCalculateDrawProperties(root_.get());
// Top-left fixed-position layer should not be affected by container size.
@@ -282,7 +293,7 @@ TEST_F(LayerPositionConstraintTest,
ScrollCompensationForFixedPositionLayerWithDistantContainer) {
// This test checks for correct scroll compensation when the fixed-position
// container is NOT the direct parent of the fixed-position layer.
- LayerImpl* child = root_->children()[0];
+ LayerImpl* child = scroll_->children()[0];
LayerImpl* grand_child = child->children()[0];
LayerImpl* great_grand_child = grand_child->children()[0];
@@ -326,7 +337,7 @@ TEST_F(LayerPositionConstraintTest,
great_grand_child->draw_transform());
// Case 3: fixed-container size delta of 20, 20
- child->SetFixedContainerSizeDelta(gfx::Vector2d(20, 20));
+ SetFixedContainerSizeDelta(child, gfx::Vector2d(20, 20));
ExecuteCalculateDrawProperties(root_.get());
// Top-left fixed-position layer should not be affected by container size.
@@ -362,7 +373,7 @@ TEST_F(LayerPositionConstraintTest,
// container is NOT the direct parent of the fixed-position layer, and the
// hierarchy has various transforms that have to be processed in the correct
// order.
- LayerImpl* child = root_->children()[0];
+ LayerImpl* child = scroll_->children()[0];
LayerImpl* grand_child = child->children()[0];
LayerImpl* great_grand_child = grand_child->children()[0];
@@ -430,7 +441,7 @@ TEST_F(LayerPositionConstraintTest,
great_grand_child->draw_transform());
// Case 3: fixed-container size delta of 20, 20
- child->SetFixedContainerSizeDelta(gfx::Vector2d(20, 20));
+ SetFixedContainerSizeDelta(child, gfx::Vector2d(20, 20));
ExecuteCalculateDrawProperties(root_.get());
// Top-left fixed-position layer should not be affected by container size.
@@ -474,7 +485,7 @@ TEST_F(LayerPositionConstraintTest,
// container is NOT the direct parent of the fixed-position layer, and the
// hierarchy has various transforms that have to be processed in the correct
// order.
- LayerImpl* child = root_->children()[0];
+ LayerImpl* child = scroll_->children()[0];
LayerImpl* grand_child = child->children()[0];
LayerImpl* great_grand_child = grand_child->children()[0];
@@ -545,7 +556,7 @@ TEST_F(LayerPositionConstraintTest,
great_grand_child->draw_transform());
// Case 3: fixed-container size delta of 20, 20
- child->SetFixedContainerSizeDelta(gfx::Vector2d(20, 20));
+ SetFixedContainerSizeDelta(child, gfx::Vector2d(20, 20));
ExecuteCalculateDrawProperties(root_.get());
// Top-left fixed-position layer should not be affected by container size.
@@ -585,7 +596,7 @@ TEST_F(LayerPositionConstraintTest,
// container contributes to a different render surface than the fixed-position
// layer. In this case, the surface draw transforms also have to be accounted
// for when checking the scroll delta.
- LayerImpl* child = root_->children()[0];
+ LayerImpl* child = scroll_->children()[0];
LayerImpl* grand_child = child->children()[0];
LayerImpl* great_grand_child = grand_child->children()[0];
@@ -664,7 +675,7 @@ TEST_F(LayerPositionConstraintTest,
great_grand_child->draw_transform());
// Case 3: fixed-container size delta of 20, 20
- child->SetFixedContainerSizeDelta(gfx::Vector2d(20, 20));
+ SetFixedContainerSizeDelta(child, gfx::Vector2d(20, 20));
ExecuteCalculateDrawProperties(root_.get());
// Top-left fixed-position layer should not be affected by container size.
@@ -709,7 +720,7 @@ TEST_F(LayerPositionConstraintTest,
// layer, with additional render surfaces in-between. This checks that the
// conversion to ancestor surfaces is accumulated properly in the final matrix
// transform.
- LayerImpl* child = root_->children()[0];
+ LayerImpl* child = scroll_->children()[0];
LayerImpl* grand_child = child->children()[0];
LayerImpl* great_grand_child = grand_child->children()[0];
@@ -720,11 +731,10 @@ TEST_F(LayerPositionConstraintTest,
LayerImpl::Create(host_impl_.active_tree(), 5);
SetLayerPropertiesForTesting(fixed_position_child.get(),
identity,
- identity,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
- false);
+ true);
great_grand_child->AddChild(fixed_position_child.Pass());
}
LayerImpl* fixed_position_child = great_grand_child->children()[0];
@@ -850,7 +860,7 @@ TEST_F(LayerPositionConstraintTest,
// Case 3: fixed-container size delta of 20, 20
- child->SetFixedContainerSizeDelta(gfx::Vector2d(20, 20));
+ SetFixedContainerSizeDelta(child, gfx::Vector2d(20, 20));
ExecuteCalculateDrawProperties(root_.get());
// Top-left fixed-position layer should not be affected by container size.
@@ -896,7 +906,7 @@ TEST_F(LayerPositionConstraintTest,
// should be treated like a layer that contributes to a render target, and
// that render target is completely irrelevant; it should not affect the
// scroll compensation.
- LayerImpl* child = root_->children()[0];
+ LayerImpl* child = scroll_->children()[0];
LayerImpl* grand_child = child->children()[0];
child->SetIsContainerForFixedPositionLayers(true);
@@ -941,7 +951,7 @@ TEST_F(LayerPositionConstraintTest,
grand_child->draw_transform());
// Case 3: fixed-container size delta of 20, 20
- child->SetFixedContainerSizeDelta(gfx::Vector2d(20, 20));
+ SetFixedContainerSizeDelta(child, gfx::Vector2d(20, 20));
ExecuteCalculateDrawProperties(root_.get());
// Top-left fixed-position layer should not be affected by container size.
@@ -974,7 +984,7 @@ TEST_F(LayerPositionConstraintTest,
// This test checks the scenario where a fixed-position layer also happens to
// be a container itself for a descendant fixed position layer. In particular,
// the layer should not accidentally be fixed to itself.
- LayerImpl* child = root_->children()[0];
+ LayerImpl* child = scroll_->children()[0];
LayerImpl* grand_child = child->children()[0];
child->SetIsContainerForFixedPositionLayers(true);
@@ -1009,7 +1019,7 @@ TEST_F(LayerPositionConstraintTest,
grand_child->draw_transform());
// Case 3: fixed-container size delta of 20, 20
- child->SetFixedContainerSizeDelta(gfx::Vector2d(20, 20));
+ SetFixedContainerSizeDelta(child, gfx::Vector2d(20, 20));
ExecuteCalculateDrawProperties(root_.get());
// Top-left fixed-position layer should not be affected by container size.
@@ -1034,67 +1044,6 @@ TEST_F(LayerPositionConstraintTest,
}
TEST_F(LayerPositionConstraintTest,
- ScrollCompensationForFixedPositionLayerThatHasNoContainer) {
- // This test checks scroll compensation when a fixed-position layer does not
- // find any ancestor that is a "containerForFixedPositionLayers". In this
- // situation, the layer should be fixed to the root layer.
- LayerImpl* child = root_->children()[0];
- LayerImpl* grand_child = child->children()[0];
-
- gfx::Transform rotation_by_z;
- rotation_by_z.RotateAboutZAxis(90.0);
-
- root_->SetTransform(rotation_by_z);
- grand_child->SetPositionConstraint(fixed_to_top_left_);
-
- // Case 1: root scroll delta of 0, 0
- root_->SetScrollDelta(gfx::Vector2d(0, 0));
- ExecuteCalculateDrawProperties(root_.get());
-
- gfx::Transform identity_matrix;
-
- EXPECT_TRANSFORMATION_MATRIX_EQ(rotation_by_z, child->draw_transform());
- EXPECT_TRANSFORMATION_MATRIX_EQ(rotation_by_z,
- grand_child->draw_transform());
-
- // Case 2: root scroll delta of 10, 10
- root_->SetScrollDelta(gfx::Vector2d(10, 20));
- ExecuteCalculateDrawProperties(root_.get());
-
- gfx::Transform expected_child_transform;
- expected_child_transform.Translate(-10.0, -20.0);
- expected_child_transform.PreconcatTransform(rotation_by_z);
-
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected_child_transform,
- child->draw_transform());
- EXPECT_TRANSFORMATION_MATRIX_EQ(rotation_by_z,
- grand_child->draw_transform());
-
- // Case 3: fixed-container size delta of 20, 20
- root_->SetFixedContainerSizeDelta(gfx::Vector2d(20, 20));
- ExecuteCalculateDrawProperties(root_.get());
-
- // Top-left fixed-position layer should not be affected by container size.
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected_child_transform,
- child->draw_transform());
- EXPECT_TRANSFORMATION_MATRIX_EQ(rotation_by_z,
- grand_child->draw_transform());
-
- // Case 4: Bottom-right fixed-position layer.
- grand_child->SetPositionConstraint(fixed_to_bottom_right_);
- ExecuteCalculateDrawProperties(root_.get());
-
- gfx::Transform expected_grand_child_transform;
- expected_grand_child_transform.Translate(-20.0, 20.0);
- expected_grand_child_transform.PreconcatTransform(rotation_by_z);
-
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected_child_transform,
- child->draw_transform());
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected_grand_child_transform,
- grand_child->draw_transform());
-}
-
-TEST_F(LayerPositionConstraintTest,
ScrollCompensationForFixedWithinFixedWithSameContainer) {
// This test checks scroll compensation for a fixed-position layer that is
// inside of another fixed-position layer and both share the same container.
@@ -1102,7 +1051,7 @@ TEST_F(LayerPositionConstraintTest,
// the scroll compensation, and the child fixed-position layer does not
// need to compensate further.
- LayerImpl* child = root_->children()[0];
+ LayerImpl* child = scroll_->children()[0];
LayerImpl* grand_child = child->children()[0];
LayerImpl* great_grand_child = grand_child->children()[0];
@@ -1135,7 +1084,7 @@ TEST_F(LayerPositionConstraintTest,
// Case 2: sizeDelta
child->SetScrollDelta(gfx::Vector2d(0, 0));
- child->SetFixedContainerSizeDelta(gfx::Vector2d(20, 20));
+ SetFixedContainerSizeDelta(child, gfx::Vector2d(20, 20));
ExecuteCalculateDrawProperties(root_.get());
expected_child_transform.MakeIdentity();
@@ -1161,7 +1110,7 @@ TEST_F(LayerPositionConstraintTest,
// position containers. In this situation, the child fixed-position element
// would still have to compensate with respect to its container.
- LayerImpl* container1 = root_->children()[0];
+ LayerImpl* container1 = scroll_->children()[0];
LayerImpl* fixed_to_container1 = container1->children()[0];
LayerImpl* container2 = fixed_to_container1->children()[0];
@@ -1208,6 +1157,5 @@ TEST_F(LayerPositionConstraintTest,
EXPECT_TRANSFORMATION_MATRIX_EQ(expected_fixed_to_container2_transform,
fixed_to_container2->draw_transform());
}
-
} // namespace
} // namespace cc
diff --git a/chromium/cc/layers/layer_unittest.cc b/chromium/cc/layers/layer_unittest.cc
index a77a5fb8819..ba77513370e 100644
--- a/chromium/cc/layers/layer_unittest.cc
+++ b/chromium/cc/layers/layer_unittest.cc
@@ -14,6 +14,7 @@
#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_shared_bitmap_manager.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/single_thread_proxy.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -26,13 +27,13 @@ using ::testing::Mock;
using ::testing::StrictMock;
using ::testing::_;
-#define EXPECT_SET_NEEDS_FULL_TREE_SYNC(expect, code_to_test) do { \
+#define EXPECT_SET_NEEDS_FULL_TREE_SYNC(expect, code_to_test) \
+ do { \
EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync()).Times((expect)); \
- code_to_test; \
- Mock::VerifyAndClearExpectations(layer_tree_host_.get()); \
+ code_to_test; \
+ Mock::VerifyAndClearExpectations(layer_tree_host_.get()); \
} while (false)
-
namespace cc {
namespace {
@@ -51,7 +52,7 @@ class MockLayerTreeHost : public LayerTreeHost {
class MockLayerPainter : public LayerPainter {
public:
virtual void Paint(SkCanvas* canvas,
- gfx::Rect content_rect,
+ const gfx::Rect& content_rect,
gfx::RectF* opaque) OVERRIDE {}
};
@@ -59,7 +60,7 @@ class MockLayerPainter : public LayerPainter {
class LayerTest : public testing::Test {
public:
LayerTest()
- : host_impl_(&proxy_),
+ : host_impl_(&proxy_, &shared_bitmap_manager_),
fake_client_(FakeLayerTreeHostClient::DIRECT_3D) {}
protected:
@@ -129,6 +130,7 @@ class LayerTest : public testing::Test {
}
FakeImplProxy proxy_;
+ TestSharedBitmapManager shared_bitmap_manager_;
FakeLayerTreeHostImpl host_impl_;
FakeLayerTreeHostClient fake_client_;
@@ -539,9 +541,8 @@ TEST_F(LayerTest, CheckPropertyChangeCausesCorrectBehavior) {
// Next, test properties that should call SetNeedsCommit (but not
// SetNeedsDisplay). All properties need to be set to new values in order for
// SetNeedsCommit to be called.
- EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetAnchorPoint(
- gfx::PointF(1.23f, 4.56f)));
- EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetAnchorPointZ(0.7f));
+ EXPECT_SET_NEEDS_COMMIT(
+ 1, test_layer->SetTransformOrigin(gfx::Point3F(1.23f, 4.56f, 0.f)));
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetBackgroundColor(SK_ColorLTGRAY));
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetMasksToBounds(true));
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetOpacity(0.5f));
@@ -549,9 +550,9 @@ TEST_F(LayerTest, CheckPropertyChangeCausesCorrectBehavior) {
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetIsRootForIsolatedGroup(true));
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetContentsOpaque(true));
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetPosition(gfx::PointF(4.f, 9.f)));
- EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetSublayerTransform(
- gfx::Transform(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)));
- EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetScrollable(true));
+ // We can use any layer pointer here since we aren't syncing for real.
+ EXPECT_SET_NEEDS_COMMIT(1,
+ test_layer->SetScrollClipLayerId(test_layer->id()));
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetUserScrollable(true, false));
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetScrollOffset(
gfx::Vector2d(10, 10)));
@@ -559,13 +560,16 @@ TEST_F(LayerTest, CheckPropertyChangeCausesCorrectBehavior) {
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetNonFastScrollableRegion(
Region(gfx::Rect(1, 1, 2, 2))));
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetHaveWheelEventHandlers(true));
+ EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetHaveScrollEventHandlers(true));
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetTransform(
gfx::Transform(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)));
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetDoubleSided(false));
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetTouchEventHandlerRegion(
gfx::Rect(10, 10)));
- EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetDrawCheckerboardForMissingTiles(
- !test_layer->DrawCheckerboardForMissingTiles()));
+ EXPECT_SET_NEEDS_COMMIT(
+ 1,
+ test_layer->SetDrawCheckerboardForMissingTiles(
+ !test_layer->draw_checkerboard_for_missing_tiles()));
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetForceRenderSurface(true));
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetHideLayerAndSubtree(true));
@@ -799,27 +803,91 @@ TEST_F(LayerTest, MaskAndReplicaHasParent) {
EXPECT_EQ(replica, replica->mask_layer()->parent());
}
+TEST_F(LayerTest, CheckTranformIsInvertible) {
+ scoped_refptr<Layer> layer = Layer::Create();
+ scoped_ptr<LayerImpl> impl_layer =
+ LayerImpl::Create(host_impl_.active_tree(), 1);
+ EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync()).Times(1);
+ EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AnyNumber());
+ layer_tree_host_->SetRootLayer(layer);
+
+ EXPECT_TRUE(layer->transform_is_invertible());
+
+ gfx::Transform singular_transform;
+ singular_transform.Scale3d(
+ SkDoubleToMScalar(1.0), SkDoubleToMScalar(1.0), SkDoubleToMScalar(0.0));
+
+ layer->SetTransform(singular_transform);
+ layer->PushPropertiesTo(impl_layer.get());
+
+ EXPECT_FALSE(layer->transform_is_invertible());
+ EXPECT_FALSE(impl_layer->transform_is_invertible());
+
+ gfx::Transform rotation_transform;
+ rotation_transform.RotateAboutZAxis(-45.0);
+
+ layer->SetTransform(rotation_transform);
+ layer->PushPropertiesTo(impl_layer.get());
+ EXPECT_TRUE(layer->transform_is_invertible());
+ EXPECT_TRUE(impl_layer->transform_is_invertible());
+
+ Mock::VerifyAndClearExpectations(layer_tree_host_.get());
+}
+
+TEST_F(LayerTest, TranformIsInvertibleAnimation) {
+ scoped_refptr<Layer> layer = Layer::Create();
+ scoped_ptr<LayerImpl> impl_layer =
+ LayerImpl::Create(host_impl_.active_tree(), 1);
+ EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync()).Times(1);
+ EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AnyNumber());
+ layer_tree_host_->SetRootLayer(layer);
+
+ EXPECT_TRUE(layer->transform_is_invertible());
+
+ gfx::Transform singular_transform;
+ singular_transform.Scale3d(
+ SkDoubleToMScalar(1.0), SkDoubleToMScalar(1.0), SkDoubleToMScalar(0.0));
+
+ layer->SetTransform(singular_transform);
+ layer->PushPropertiesTo(impl_layer.get());
+
+ EXPECT_FALSE(layer->transform_is_invertible());
+ EXPECT_FALSE(impl_layer->transform_is_invertible());
+
+ gfx::Transform identity_transform;
+
+ layer->SetTransform(identity_transform);
+ static_cast<LayerAnimationValueObserver*>(layer)
+ ->OnTransformAnimated(singular_transform);
+ layer->PushPropertiesTo(impl_layer.get());
+ EXPECT_FALSE(layer->transform_is_invertible());
+ EXPECT_FALSE(impl_layer->transform_is_invertible());
+
+ Mock::VerifyAndClearExpectations(layer_tree_host_.get());
+}
+
class LayerTreeHostFactory {
public:
LayerTreeHostFactory()
- : client_(FakeLayerTreeHostClient::DIRECT_3D) {}
+ : client_(FakeLayerTreeHostClient::DIRECT_3D),
+ shared_bitmap_manager_(new TestSharedBitmapManager()) {}
scoped_ptr<LayerTreeHost> Create() {
return LayerTreeHost::CreateSingleThreaded(&client_,
&client_,
- NULL,
+ shared_bitmap_manager_.get(),
LayerTreeSettings()).Pass();
}
scoped_ptr<LayerTreeHost> Create(LayerTreeSettings settings) {
- return LayerTreeHost::CreateSingleThreaded(&client_,
- &client_,
- NULL,
- settings).Pass();
+ return LayerTreeHost::CreateSingleThreaded(
+ &client_, &client_, shared_bitmap_manager_.get(), settings)
+ .Pass();
}
private:
FakeLayerTreeHostClient client_;
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager_;
};
void AssertLayerTreeHostMatchesForSubtree(Layer* layer, LayerTreeHost* host) {
diff --git a/chromium/cc/layers/layer_utils.cc b/chromium/cc/layers/layer_utils.cc
new file mode 100644
index 00000000000..9c299c2fe4a
--- /dev/null
+++ b/chromium/cc/layers/layer_utils.cc
@@ -0,0 +1,146 @@
+// 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/layers/layer_utils.h"
+
+#include "cc/layers/layer_impl.h"
+#include "cc/trees/layer_tree_host_common.h"
+#include "ui/gfx/box_f.h"
+
+namespace cc {
+
+namespace {
+
+bool HasAnimationThatInflatesBounds(const LayerImpl& layer) {
+ return layer.layer_animation_controller()->HasAnimationThatInflatesBounds();
+}
+
+bool HasFilterAnimationThatInflatesBounds(const LayerImpl& layer) {
+ return layer.layer_animation_controller()
+ ->HasFilterAnimationThatInflatesBounds();
+}
+
+bool HasTransformAnimationThatInflatesBounds(const LayerImpl& layer) {
+ return layer.layer_animation_controller()
+ ->HasTransformAnimationThatInflatesBounds();
+}
+
+inline bool HasAncestorTransformAnimation(const LayerImpl& layer) {
+ return layer.screen_space_transform_is_animating();
+}
+
+inline bool HasAncestorFilterAnimation(const LayerImpl& layer) {
+ for (const LayerImpl* current = &layer; current;
+ current = current->parent()) {
+ if (HasFilterAnimationThatInflatesBounds(*current))
+ return true;
+ }
+
+ return false;
+}
+
+} // namespace
+
+bool LayerUtils::GetAnimationBounds(const LayerImpl& layer_in, gfx::BoxF* out) {
+ // We don't care about animated bounds for invisible layers.
+ if (!layer_in.DrawsContent())
+ return false;
+
+ // We also don't care for layers that are not animated or a child of an
+ // animated layer.
+ if (!HasAncestorTransformAnimation(layer_in) &&
+ !HasAncestorFilterAnimation(layer_in))
+ return false;
+
+ // To compute the inflated bounds for a layer, we start by taking its bounds
+ // and converting it to a 3d box, and then we transform or inflate it
+ // repeatedly as we walk up the layer tree to the root.
+ //
+ // At each layer we apply the following transformations to the box:
+ // 1) We translate so that the anchor point is the origin.
+ // 2) We either apply the layer's transform or inflate if the layer's
+ // transform is animated.
+ // 3) We undo the translation from step 1 and apply a second translation
+ // to account for the layer's position.
+ //
+ gfx::BoxF box(layer_in.bounds().width(), layer_in.bounds().height(), 0.f);
+
+ // We want to inflate/transform the box as few times as possible. Each time
+ // we do this, we have to make the box axis aligned again, so if we make many
+ // small adjustments to the box by transforming it repeatedly rather than
+ // once by the product of all these matrices, we will accumulate a bunch of
+ // unnecessary inflation because of the the many axis-alignment fixes. This
+ // matrix stores said product.
+ gfx::Transform coalesced_transform;
+
+ for (const LayerImpl* layer = &layer_in; layer; layer = layer->parent()) {
+ int transform_origin_x = layer->transform_origin().x();
+ int transform_origin_y = layer->transform_origin().y();
+ int transform_origin_z = layer->transform_origin().z();
+
+ gfx::PointF position = layer->position();
+ if (layer->parent() && !HasAnimationThatInflatesBounds(*layer)) {
+ // |composite_layer_transform| contains 1 - 4 mentioned above. We compute
+ // it separately and apply afterwards because it's a bit more efficient
+ // because post-multiplication appears a bit more expensive, so we want
+ // to do it only once.
+ gfx::Transform composite_layer_transform;
+
+ composite_layer_transform.Translate3d(transform_origin_x + position.x(),
+ transform_origin_y + position.y(),
+ transform_origin_z);
+ composite_layer_transform.PreconcatTransform(layer->transform());
+ composite_layer_transform.Translate3d(
+ -transform_origin_x, -transform_origin_y, -transform_origin_z);
+
+ // Add this layer's contributions to the |coalesced_transform|.
+ coalesced_transform.ConcatTransform(composite_layer_transform);
+ continue;
+ }
+
+ // First, apply coalesced transform we've been building and reset it.
+ coalesced_transform.TransformBox(&box);
+ coalesced_transform.MakeIdentity();
+
+ // We need to apply the inflation about the layer's anchor point. Rather
+ // than doing this via transforms, we'll just shift the box directly.
+ box.set_origin(box.origin() + gfx::Vector3dF(-transform_origin_x,
+ -transform_origin_y,
+ -transform_origin_z));
+
+ // Perform the inflation
+ if (HasFilterAnimationThatInflatesBounds(*layer)) {
+ gfx::BoxF inflated;
+ if (!layer->layer_animation_controller()->FilterAnimationBoundsForBox(
+ box, &inflated))
+ return false;
+ box = inflated;
+ }
+
+ if (HasTransformAnimationThatInflatesBounds(*layer)) {
+ gfx::BoxF inflated;
+ if (!layer->layer_animation_controller()->TransformAnimationBoundsForBox(
+ box, &inflated))
+ return false;
+ box = inflated;
+ }
+
+ // Apply step 3) mentioned above.
+ box.set_origin(box.origin() +
+ gfx::Vector3dF(transform_origin_x + position.x(),
+ transform_origin_y + position.y(),
+ transform_origin_z));
+ }
+
+ // If we've got an unapplied coalesced transform at this point, it must still
+ // be applied.
+ if (!coalesced_transform.IsIdentity())
+ coalesced_transform.TransformBox(&box);
+
+ *out = box;
+
+ return true;
+}
+
+} // namespace cc
diff --git a/chromium/cc/layers/layer_utils.h b/chromium/cc/layers/layer_utils.h
new file mode 100644
index 00000000000..396f0704109
--- /dev/null
+++ b/chromium/cc/layers/layer_utils.h
@@ -0,0 +1,29 @@
+// 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_LAYERS_LAYER_UTILS_H_
+#define CC_LAYERS_LAYER_UTILS_H_
+
+#include "cc/base/cc_export.h"
+
+namespace gfx {
+ class BoxF;
+} // namespace gfx
+
+namespace cc {
+ class LayerImpl;
+
+ class CC_EXPORT LayerUtils {
+ public:
+ // Computes a box in screen space that should entirely contain the layer's
+ // bounds through the entirety of the layer's current animation. Returns
+ // true and sets |out| to the inflation if there are animations that can
+ // inflate bounds in the path to the root layer and that it was able to
+ // inflate correctly. Returns false otherwise.
+ static bool GetAnimationBounds(const LayerImpl& layer, gfx::BoxF* out);
+ };
+
+} // namespace cc
+
+#endif // CC_LAYERS_LAYER_UTILS_H_
diff --git a/chromium/cc/layers/layer_utils_unittest.cc b/chromium/cc/layers/layer_utils_unittest.cc
new file mode 100644
index 00000000000..bf4e9dba4a7
--- /dev/null
+++ b/chromium/cc/layers/layer_utils_unittest.cc
@@ -0,0 +1,267 @@
+// 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/layers/layer_utils.h"
+
+#include "cc/animation/transform_operations.h"
+#include "cc/layers/layer_impl.h"
+#include "cc/test/animation_test_common.h"
+#include "cc/test/fake_impl_proxy.h"
+#include "cc/test/fake_layer_tree_host_impl.h"
+#include "cc/test/test_shared_bitmap_manager.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/box_f.h"
+#include "ui/gfx/test/gfx_util.h"
+
+namespace cc {
+namespace {
+
+float diagonal(float width, float height) {
+ return std::sqrt(width * width + height * height);
+}
+
+class LayerUtilsGetAnimationBoundsTest : public testing::Test {
+ public:
+ LayerUtilsGetAnimationBoundsTest()
+ : host_impl_(&proxy_, &shared_bitmap_manager_),
+ root_(CreateThreeNodeTree(host_impl_)),
+ parent_(root_->children()[0]),
+ child_(parent_->children()[0]) {}
+
+ LayerImpl* root() { return root_.get(); }
+ LayerImpl* parent() { return parent_; }
+ LayerImpl* child() { return child_; }
+
+ private:
+ static scoped_ptr<LayerImpl> CreateThreeNodeTree(
+ LayerTreeHostImpl& host_impl) {
+ scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl.active_tree(), 1);
+ root->AddChild(LayerImpl::Create(host_impl.active_tree(), 2));
+ root->children()[0]
+ ->AddChild(LayerImpl::Create(host_impl.active_tree(), 3));
+ return root.Pass();
+ }
+
+ FakeImplProxy proxy_;
+ TestSharedBitmapManager shared_bitmap_manager_;
+ FakeLayerTreeHostImpl host_impl_;
+ scoped_ptr<LayerImpl> root_;
+ LayerImpl* parent_;
+ LayerImpl* child_;
+};
+
+TEST_F(LayerUtilsGetAnimationBoundsTest, ScaleRoot) {
+ double duration = 1.0;
+
+ TransformOperations start;
+ start.AppendScale(1.f, 1.f, 1.f);
+ TransformOperations end;
+ end.AppendScale(2.f, 2.f, 1.f);
+ AddAnimatedTransformToLayer(root(), duration, start, end);
+
+ root()->SetPosition(gfx::PointF());
+ parent()->SetPosition(gfx::PointF());
+ parent()->SetBounds(gfx::Size(350, 200));
+
+ child()->SetDrawsContent(true);
+ child()->draw_properties().screen_space_transform_is_animating = true;
+ child()->SetPosition(gfx::PointF(150.f, 50.f));
+ child()->SetBounds(gfx::Size(100, 200));
+
+ gfx::BoxF box;
+ bool success = LayerUtils::GetAnimationBounds(*child(), &box);
+ EXPECT_TRUE(success);
+ gfx::BoxF expected(150.f, 50.f, 0.f, 350.f, 450.f, 0.f);
+ EXPECT_BOXF_EQ(expected, box);
+}
+
+TEST_F(LayerUtilsGetAnimationBoundsTest, TranslateParentLayer) {
+ double duration = 1.0;
+
+ TransformOperations start;
+ start.AppendTranslate(0.f, 0.f, 0.f);
+ TransformOperations end;
+ end.AppendTranslate(50.f, 50.f, 0.f);
+ AddAnimatedTransformToLayer(parent(), duration, start, end);
+
+ parent()->SetBounds(gfx::Size(350, 200));
+
+ child()->SetDrawsContent(true);
+ child()->draw_properties().screen_space_transform_is_animating = true;
+ child()->SetPosition(gfx::PointF(150.f, 50.f));
+ child()->SetBounds(gfx::Size(100, 200));
+
+ gfx::BoxF box;
+ bool success = LayerUtils::GetAnimationBounds(*child(), &box);
+ EXPECT_TRUE(success);
+ gfx::BoxF expected(150.f, 50.f, 0.f, 150.f, 250.f, 0.f);
+ EXPECT_BOXF_EQ(expected, box);
+}
+
+TEST_F(LayerUtilsGetAnimationBoundsTest, TranslateChildLayer) {
+ double duration = 1.0;
+
+ TransformOperations start;
+ start.AppendTranslate(0.f, 0.f, 0.f);
+ TransformOperations end;
+ end.AppendTranslate(50.f, 50.f, 0.f);
+ AddAnimatedTransformToLayer(child(), duration, start, end);
+
+ parent()->SetBounds(gfx::Size(350, 200));
+
+ child()->SetDrawsContent(true);
+ child()->draw_properties().screen_space_transform_is_animating = true;
+ child()->SetPosition(gfx::PointF(150.f, 50.f));
+ child()->SetBounds(gfx::Size(100, 200));
+
+ gfx::BoxF box;
+ bool success = LayerUtils::GetAnimationBounds(*child(), &box);
+ EXPECT_TRUE(success);
+ gfx::BoxF expected(150.f, 50.f, 0.f, 150.f, 250.f, 0.f);
+ EXPECT_BOXF_EQ(expected, box);
+}
+
+TEST_F(LayerUtilsGetAnimationBoundsTest, TranslateBothLayers) {
+ double duration = 1.0;
+
+ TransformOperations start;
+ start.AppendTranslate(0.f, 0.f, 0.f);
+ TransformOperations child_end;
+ child_end.AppendTranslate(50.f, 0.f, 0.f);
+ AddAnimatedTransformToLayer(parent(), duration, start, child_end);
+
+ TransformOperations grand_child_end;
+ grand_child_end.AppendTranslate(0.f, 50.f, 0.f);
+ AddAnimatedTransformToLayer(child(), duration, start, grand_child_end);
+
+ parent()->SetBounds(gfx::Size(350, 200));
+
+ child()->SetDrawsContent(true);
+ child()->draw_properties().screen_space_transform_is_animating = true;
+ child()->SetPosition(gfx::PointF(150.f, 50.f));
+ child()->SetBounds(gfx::Size(100, 200));
+
+ gfx::BoxF box;
+ bool success = LayerUtils::GetAnimationBounds(*child(), &box);
+ EXPECT_TRUE(success);
+ gfx::BoxF expected(150.f, 50.f, 0.f, 150.f, 250.f, 0.f);
+ EXPECT_BOXF_EQ(expected, box);
+}
+
+TEST_F(LayerUtilsGetAnimationBoundsTest, RotateXNoPerspective) {
+ double duration = 1.0;
+
+ TransformOperations start;
+ start.AppendRotate(1.f, 0.f, 0.f, 0.f);
+ TransformOperations end;
+ end.AppendRotate(1.f, 0.f, 0.f, 90.f);
+ AddAnimatedTransformToLayer(child(), duration, start, end);
+
+ parent()->SetBounds(gfx::Size(350, 200));
+
+ gfx::Size bounds(100, 100);
+ child()->SetDrawsContent(true);
+ child()->draw_properties().screen_space_transform_is_animating = true;
+ child()->SetPosition(gfx::PointF(150.f, 50.f));
+ child()->SetBounds(bounds);
+ child()->SetTransformOrigin(
+ gfx::Point3F(bounds.width() * 0.5f, bounds.height() * 0.5f, 0));
+
+ gfx::BoxF box;
+ bool success = LayerUtils::GetAnimationBounds(*child(), &box);
+ EXPECT_TRUE(success);
+ gfx::BoxF expected(150.f, 50.f, -50.f, 100.f, 100.f, 100.f);
+ EXPECT_BOXF_EQ(expected, box);
+}
+
+TEST_F(LayerUtilsGetAnimationBoundsTest, RotateXWithPerspective) {
+ double duration = 1.0;
+
+ TransformOperations start;
+ start.AppendRotate(1.f, 0.f, 0.f, 0.f);
+ TransformOperations end;
+ end.AppendRotate(1.f, 0.f, 0.f, 90.f);
+ AddAnimatedTransformToLayer(child(), duration, start, end);
+
+ // Make the anchor point not the default 0.5 value and line up with the
+ // child center to make the math easier.
+ parent()->SetTransformOrigin(
+ gfx::Point3F(0.375f * 400.f, 0.375f * 400.f, 0.f));
+ parent()->SetBounds(gfx::Size(400, 400));
+
+ gfx::Transform perspective;
+ perspective.ApplyPerspectiveDepth(100.f);
+ parent()->SetTransform(perspective);
+
+ gfx::Size bounds(100, 100);
+ child()->SetDrawsContent(true);
+ child()->draw_properties().screen_space_transform_is_animating = true;
+ child()->SetPosition(gfx::PointF(100.f, 100.f));
+ child()->SetBounds(bounds);
+ child()->SetTransformOrigin(
+ gfx::Point3F(bounds.width() * 0.5f, bounds.height() * 0.5f, 0));
+
+ gfx::BoxF box;
+ bool success = LayerUtils::GetAnimationBounds(*child(), &box);
+ EXPECT_TRUE(success);
+ gfx::BoxF expected(50.f, 50.f, -33.333336f, 200.f, 200.f, 133.333344f);
+ EXPECT_BOXF_EQ(expected, box);
+}
+
+TEST_F(LayerUtilsGetAnimationBoundsTest, RotateZ) {
+ double duration = 1.0;
+
+ TransformOperations start;
+ start.AppendRotate(0.f, 0.f, 1.f, 0.f);
+ TransformOperations end;
+ end.AppendRotate(0.f, 0.f, 1.f, 90.f);
+ AddAnimatedTransformToLayer(child(), duration, start, end);
+
+ parent()->SetBounds(gfx::Size(350, 200));
+
+ gfx::Size bounds(100, 100);
+ child()->SetDrawsContent(true);
+ child()->draw_properties().screen_space_transform_is_animating = true;
+ child()->SetPosition(gfx::PointF(150.f, 50.f));
+ child()->SetBounds(bounds);
+ child()->SetTransformOrigin(
+ gfx::Point3F(bounds.width() * 0.5f, bounds.height() * 0.5f, 0));
+
+ gfx::BoxF box;
+ bool success = LayerUtils::GetAnimationBounds(*child(), &box);
+ EXPECT_TRUE(success);
+ float diag = diagonal(bounds.width(), bounds.height());
+ gfx::BoxF expected(150.f + 0.5f * (bounds.width() - diag),
+ 50.f + 0.5f * (bounds.height() - diag),
+ 0.f,
+ diag,
+ diag,
+ 0.f);
+ EXPECT_BOXF_EQ(expected, box);
+}
+
+TEST_F(LayerUtilsGetAnimationBoundsTest, MismatchedTransforms) {
+ double duration = 1.0;
+
+ TransformOperations start;
+ start.AppendTranslate(5, 6, 7);
+ TransformOperations end;
+ end.AppendRotate(0.f, 0.f, 1.f, 90.f);
+ AddAnimatedTransformToLayer(child(), duration, start, end);
+
+ parent()->SetBounds(gfx::Size(350, 200));
+
+ gfx::Size bounds(100, 100);
+ child()->SetDrawsContent(true);
+ child()->draw_properties().screen_space_transform_is_animating = true;
+ child()->SetPosition(gfx::PointF(150.f, 50.f));
+ child()->SetBounds(bounds);
+
+ gfx::BoxF box;
+ bool success = LayerUtils::GetAnimationBounds(*child(), &box);
+ EXPECT_FALSE(success);
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/layers/nine_patch_layer.cc b/chromium/cc/layers/nine_patch_layer.cc
index f6761318cd8..e63b0002a59 100644
--- a/chromium/cc/layers/nine_patch_layer.cc
+++ b/chromium/cc/layers/nine_patch_layer.cc
@@ -27,14 +27,14 @@ scoped_ptr<LayerImpl> NinePatchLayer::CreateLayerImpl(
return NinePatchLayerImpl::Create(tree_impl, id()).PassAs<LayerImpl>();
}
-void NinePatchLayer::SetBorder(gfx::Rect border) {
+void NinePatchLayer::SetBorder(const gfx::Rect& border) {
if (border == border_)
return;
border_ = border;
SetNeedsCommit();
}
-void NinePatchLayer::SetAperture(gfx::Rect aperture) {
+void NinePatchLayer::SetAperture(const gfx::Rect& aperture) {
if (image_aperture_ == aperture)
return;
diff --git a/chromium/cc/layers/nine_patch_layer.h b/chromium/cc/layers/nine_patch_layer.h
index dc9f81f6e18..61d3e01446a 100644
--- a/chromium/cc/layers/nine_patch_layer.h
+++ b/chromium/cc/layers/nine_patch_layer.h
@@ -28,7 +28,7 @@ class CC_EXPORT NinePatchLayer : public UIResourceLayer {
// size of the left and top boundary, respectively.
// |border.width()-border.x()| and |border.height()-border.y()| are the size
// of the right and bottom boundary, respectively.
- void SetBorder(gfx::Rect border);
+ void SetBorder(const gfx::Rect& border);
// aperture is in the pixel space of the bitmap resource and refers to
// the center patch of the ninepatch (which is unused in this
@@ -36,7 +36,7 @@ class CC_EXPORT NinePatchLayer : public UIResourceLayer {
// on the edges of the layer. The corners are unscaled, the top and bottom
// rects are x-stretched to fit, and the left and right rects are
// y-stretched to fit.
- void SetAperture(gfx::Rect aperture);
+ void SetAperture(const gfx::Rect& aperture);
void SetFillCenter(bool fill_center);
private:
diff --git a/chromium/cc/layers/nine_patch_layer_impl.cc b/chromium/cc/layers/nine_patch_layer_impl.cc
index 2987179ae2e..46bd333c10a 100644
--- a/chromium/cc/layers/nine_patch_layer_impl.cc
+++ b/chromium/cc/layers/nine_patch_layer_impl.cc
@@ -44,8 +44,8 @@ static gfx::RectF NormalizedRect(float x,
height / total_height);
}
-void NinePatchLayerImpl::SetLayout(gfx::Rect aperture,
- gfx::Rect border,
+void NinePatchLayerImpl::SetLayout(const gfx::Rect& aperture,
+ const gfx::Rect& border,
bool fill_center) {
// This check imposes an ordering on the call sequence. An UIResource must
// exist before SetLayout can be called.
@@ -63,41 +63,31 @@ void NinePatchLayerImpl::SetLayout(gfx::Rect aperture,
}
void NinePatchLayerImpl::CheckGeometryLimitations() {
- // TODO(ccameron): the following "greater than or equal to" (GE) checks should
- // be greater than (GT) to avoid degenerate nine-patches. The relaxed
- // condition "equal to" is a workaround for the overhang shadow use case and
- // should be investigated further.
-
// |border| is in layer space. It cannot exceed the bounds of the layer.
- DCHECK(!border_.size().IsEmpty());
DCHECK_GE(bounds().width(), border_.width());
DCHECK_GE(bounds().height(), border_.height());
// Sanity Check on |border|
- DCHECK_LT(border_.x(), border_.width());
- DCHECK_LT(border_.y(), border_.height());
+ DCHECK_LE(border_.x(), border_.width());
+ DCHECK_LE(border_.y(), border_.height());
DCHECK_GE(border_.x(), 0);
DCHECK_GE(border_.y(), 0);
// |aperture| is in image space. It cannot exceed the bounds of the bitmap.
DCHECK(!image_aperture_.size().IsEmpty());
- DCHECK(gfx::Rect(image_bounds_.width(), image_bounds_.height())
- .Contains(image_aperture_));
-
- // Avoid the degenerate cases where the aperture touches the edge of the
- // image.
- DCHECK_LT(image_aperture_.width(), image_bounds_.width() - 1);
- DCHECK_LT(image_aperture_.height(), image_bounds_.height() - 1);
- DCHECK_GT(image_aperture_.x(), 0);
- DCHECK_GT(image_aperture_.y(), 0);
+ DCHECK(gfx::Rect(image_bounds_).Contains(image_aperture_))
+ << "image_bounds_ " << gfx::Rect(image_bounds_).ToString()
+ << " image_aperture_ " << image_aperture_.ToString();
}
void NinePatchLayerImpl::AppendQuads(QuadSink* quad_sink,
AppendQuadsData* append_quads_data) {
CheckGeometryLimitations();
- SharedQuadState* shared_quad_state =
- quad_sink->UseSharedQuadState(CreateSharedQuadState());
- AppendDebugBorderQuad(quad_sink, shared_quad_state, append_quads_data);
+ SharedQuadState* shared_quad_state = quad_sink->CreateSharedQuadState();
+ PopulateSharedQuadState(shared_quad_state);
+
+ AppendDebugBorderQuad(
+ quad_sink, content_bounds(), shared_quad_state, append_quads_data);
if (!ui_resource_id_)
return;
@@ -217,126 +207,170 @@ void NinePatchLayerImpl::AppendQuads(QuadSink* quad_sink,
// Nothing is opaque here.
// TODO(danakj): Should we look at the SkBitmaps to determine opaqueness?
gfx::Rect opaque_rect;
+ gfx::Rect visible_rect;
const float vertex_opacity[] = {1.0f, 1.0f, 1.0f, 1.0f};
scoped_ptr<TextureDrawQuad> quad;
- quad = TextureDrawQuad::Create();
- quad->SetNew(shared_quad_state,
- layer_top_left,
- opaque_rect,
- resource,
- premultiplied_alpha,
- uv_top_left.origin(),
- uv_top_left.bottom_right(),
- SK_ColorTRANSPARENT,
- vertex_opacity,
- flipped);
- quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
-
- quad = TextureDrawQuad::Create();
- quad->SetNew(shared_quad_state,
- layer_top_right,
- opaque_rect,
- resource,
- premultiplied_alpha,
- uv_top_right.origin(),
- uv_top_right.bottom_right(),
- SK_ColorTRANSPARENT,
- vertex_opacity,
- flipped);
- quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
-
- quad = TextureDrawQuad::Create();
- quad->SetNew(shared_quad_state,
- layer_bottom_left,
- opaque_rect,
- resource,
- premultiplied_alpha,
- uv_bottom_left.origin(),
- uv_bottom_left.bottom_right(),
- SK_ColorTRANSPARENT,
- vertex_opacity,
- flipped);
- quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
-
- quad = TextureDrawQuad::Create();
- quad->SetNew(shared_quad_state,
- layer_bottom_right,
- opaque_rect,
- resource,
- premultiplied_alpha,
- uv_bottom_right.origin(),
- uv_bottom_right.bottom_right(),
- SK_ColorTRANSPARENT,
- vertex_opacity,
- flipped);
- quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
-
- quad = TextureDrawQuad::Create();
- quad->SetNew(shared_quad_state,
- layer_top,
- opaque_rect,
- resource,
- premultiplied_alpha,
- uv_top.origin(),
- uv_top.bottom_right(),
- SK_ColorTRANSPARENT,
- vertex_opacity,
- flipped);
- quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
-
- quad = TextureDrawQuad::Create();
- quad->SetNew(shared_quad_state,
- layer_left,
- opaque_rect,
- resource,
- premultiplied_alpha,
- uv_left.origin(),
- uv_left.bottom_right(),
- SK_ColorTRANSPARENT,
- vertex_opacity,
- flipped);
- quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
-
- quad = TextureDrawQuad::Create();
- quad->SetNew(shared_quad_state,
- layer_right,
- opaque_rect,
- resource,
- premultiplied_alpha,
- uv_right.origin(),
- uv_right.bottom_right(),
- SK_ColorTRANSPARENT,
- vertex_opacity,
- flipped);
- quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
-
- quad = TextureDrawQuad::Create();
- quad->SetNew(shared_quad_state,
- layer_bottom,
- opaque_rect,
- resource,
- premultiplied_alpha,
- uv_bottom.origin(),
- uv_bottom.bottom_right(),
- SK_ColorTRANSPARENT,
- vertex_opacity,
- flipped);
- quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
+ visible_rect =
+ quad_sink->UnoccludedContentRect(layer_top_left, draw_transform());
+ if (!visible_rect.IsEmpty()) {
+ quad = TextureDrawQuad::Create();
+ quad->SetNew(shared_quad_state,
+ layer_top_left,
+ opaque_rect,
+ visible_rect,
+ resource,
+ premultiplied_alpha,
+ uv_top_left.origin(),
+ uv_top_left.bottom_right(),
+ SK_ColorTRANSPARENT,
+ vertex_opacity,
+ flipped);
+ quad_sink->Append(quad.PassAs<DrawQuad>());
+ }
- if (fill_center_) {
+ visible_rect =
+ quad_sink->UnoccludedContentRect(layer_top_right, draw_transform());
+ if (!visible_rect.IsEmpty()) {
+ quad = TextureDrawQuad::Create();
+ quad->SetNew(shared_quad_state,
+ layer_top_right,
+ opaque_rect,
+ visible_rect,
+ resource,
+ premultiplied_alpha,
+ uv_top_right.origin(),
+ uv_top_right.bottom_right(),
+ SK_ColorTRANSPARENT,
+ vertex_opacity,
+ flipped);
+ quad_sink->Append(quad.PassAs<DrawQuad>());
+ }
+
+ visible_rect =
+ quad_sink->UnoccludedContentRect(layer_bottom_left, draw_transform());
+ if (!visible_rect.IsEmpty()) {
quad = TextureDrawQuad::Create();
quad->SetNew(shared_quad_state,
- layer_center,
+ layer_bottom_left,
opaque_rect,
+ visible_rect,
resource,
premultiplied_alpha,
- uv_center.origin(),
- uv_center.bottom_right(),
+ uv_bottom_left.origin(),
+ uv_bottom_left.bottom_right(),
SK_ColorTRANSPARENT,
vertex_opacity,
flipped);
- quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
+ quad_sink->Append(quad.PassAs<DrawQuad>());
+ }
+
+ visible_rect =
+ quad_sink->UnoccludedContentRect(layer_bottom_right, draw_transform());
+ if (!visible_rect.IsEmpty()) {
+ quad = TextureDrawQuad::Create();
+ quad->SetNew(shared_quad_state,
+ layer_bottom_right,
+ opaque_rect,
+ visible_rect,
+ resource,
+ premultiplied_alpha,
+ uv_bottom_right.origin(),
+ uv_bottom_right.bottom_right(),
+ SK_ColorTRANSPARENT,
+ vertex_opacity,
+ flipped);
+ quad_sink->Append(quad.PassAs<DrawQuad>());
+ }
+
+ visible_rect = quad_sink->UnoccludedContentRect(layer_top, draw_transform());
+ if (!visible_rect.IsEmpty()) {
+ quad = TextureDrawQuad::Create();
+ quad->SetNew(shared_quad_state,
+ layer_top,
+ opaque_rect,
+ visible_rect,
+ resource,
+ premultiplied_alpha,
+ uv_top.origin(),
+ uv_top.bottom_right(),
+ SK_ColorTRANSPARENT,
+ vertex_opacity,
+ flipped);
+ quad_sink->Append(quad.PassAs<DrawQuad>());
+ }
+
+ visible_rect = quad_sink->UnoccludedContentRect(layer_left, draw_transform());
+ if (!visible_rect.IsEmpty()) {
+ quad = TextureDrawQuad::Create();
+ quad->SetNew(shared_quad_state,
+ layer_left,
+ opaque_rect,
+ visible_rect,
+ resource,
+ premultiplied_alpha,
+ uv_left.origin(),
+ uv_left.bottom_right(),
+ SK_ColorTRANSPARENT,
+ vertex_opacity,
+ flipped);
+ quad_sink->Append(quad.PassAs<DrawQuad>());
+ }
+
+ visible_rect =
+ quad_sink->UnoccludedContentRect(layer_right, draw_transform());
+ if (!visible_rect.IsEmpty()) {
+ quad = TextureDrawQuad::Create();
+ quad->SetNew(shared_quad_state,
+ layer_right,
+ opaque_rect,
+ layer_right,
+ resource,
+ premultiplied_alpha,
+ uv_right.origin(),
+ uv_right.bottom_right(),
+ SK_ColorTRANSPARENT,
+ vertex_opacity,
+ flipped);
+ quad_sink->Append(quad.PassAs<DrawQuad>());
+ }
+
+ visible_rect =
+ quad_sink->UnoccludedContentRect(layer_bottom, draw_transform());
+ if (!visible_rect.IsEmpty()) {
+ quad = TextureDrawQuad::Create();
+ quad->SetNew(shared_quad_state,
+ layer_bottom,
+ opaque_rect,
+ visible_rect,
+ resource,
+ premultiplied_alpha,
+ uv_bottom.origin(),
+ uv_bottom.bottom_right(),
+ SK_ColorTRANSPARENT,
+ vertex_opacity,
+ flipped);
+ quad_sink->Append(quad.PassAs<DrawQuad>());
+ }
+
+ if (fill_center_) {
+ visible_rect =
+ quad_sink->UnoccludedContentRect(layer_center, draw_transform());
+ if (!visible_rect.IsEmpty()) {
+ quad = TextureDrawQuad::Create();
+ quad->SetNew(shared_quad_state,
+ layer_center,
+ opaque_rect,
+ visible_rect,
+ resource,
+ premultiplied_alpha,
+ uv_center.origin(),
+ uv_center.bottom_right(),
+ SK_ColorTRANSPARENT,
+ vertex_opacity,
+ flipped);
+ quad_sink->Append(quad.PassAs<DrawQuad>());
+ }
}
}
diff --git a/chromium/cc/layers/nine_patch_layer_impl.h b/chromium/cc/layers/nine_patch_layer_impl.h
index d85e40f3049..fb3e66e6575 100644
--- a/chromium/cc/layers/nine_patch_layer_impl.h
+++ b/chromium/cc/layers/nine_patch_layer_impl.h
@@ -53,8 +53,8 @@ class CC_EXPORT NinePatchLayerImpl : public UIResourceLayerImpl {
// |image_aperture| = (X, Y, P, Q)
// |border| = (A, C, A + B, C + D)
// |fill_center| indicates whether to draw the center quad or not.
- void SetLayout(gfx::Rect image_aperture,
- gfx::Rect border,
+ void SetLayout(const gfx::Rect& image_aperture,
+ const gfx::Rect& border,
bool fill_center);
virtual scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl)
diff --git a/chromium/cc/layers/nine_patch_layer_impl_unittest.cc b/chromium/cc/layers/nine_patch_layer_impl_unittest.cc
index 60201110a25..b1296769486 100644
--- a/chromium/cc/layers/nine_patch_layer_impl_unittest.cc
+++ b/chromium/cc/layers/nine_patch_layer_impl_unittest.cc
@@ -23,20 +23,22 @@
namespace cc {
namespace {
-gfx::Rect ToRoundedIntRect(gfx::RectF rect_f) {
+gfx::Rect ToRoundedIntRect(const gfx::RectF& rect_f) {
return gfx::Rect(gfx::ToRoundedInt(rect_f.x()),
gfx::ToRoundedInt(rect_f.y()),
gfx::ToRoundedInt(rect_f.width()),
gfx::ToRoundedInt(rect_f.height()));
}
-void NinePatchLayerLayoutTest(gfx::Size bitmap_size,
- gfx::Rect aperture_rect,
- gfx::Size layer_size,
- gfx::Rect border,
+void NinePatchLayerLayoutTest(const gfx::Size& bitmap_size,
+ const gfx::Rect& aperture_rect,
+ const gfx::Size& layer_size,
+ const gfx::Rect& border,
bool fill_center,
size_t expected_quad_size) {
- MockQuadCuller quad_culler;
+ MockOcclusionTracker<LayerImpl> occlusion_tracker;
+ scoped_ptr<RenderPass> render_pass = RenderPass::Create();
+ MockQuadCuller quad_culler(render_pass.get(), &occlusion_tracker);
gfx::Rect visible_content_rect(layer_size);
gfx::Rect expected_remaining(border.x(),
border.y(),
@@ -44,7 +46,8 @@ void NinePatchLayerLayoutTest(gfx::Size bitmap_size,
layer_size.height() - border.height());
FakeImplProxy proxy;
- FakeUIResourceLayerTreeHostImpl host_impl(&proxy);
+ TestSharedBitmapManager shared_bitmap_manager;
+ FakeUIResourceLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
scoped_ptr<NinePatchLayerImpl> layer =
NinePatchLayerImpl::Create(host_impl.active_tree(), 1);
layer->draw_properties().visible_content_rect = visible_content_rect;
@@ -54,12 +57,8 @@ void NinePatchLayerLayoutTest(gfx::Size bitmap_size,
layer->draw_properties().render_target = layer.get();
UIResourceId uid = 1;
- SkBitmap skbitmap;
- skbitmap.setConfig(
- SkBitmap::kARGB_8888_Config, bitmap_size.width(), bitmap_size.height());
- skbitmap.allocPixels();
- skbitmap.setImmutable();
- UIResourceBitmap bitmap(skbitmap);
+ bool is_opaque = false;
+ UIResourceBitmap bitmap(bitmap_size, is_opaque);
host_impl.CreateUIResource(uid, bitmap);
layer->SetUIResourceId(uid);
@@ -156,5 +155,129 @@ TEST(NinePatchLayerImplTest, VerifyDrawQuads) {
expected_quad_size);
}
+TEST(NinePatchLayerImplTest, VerifyDrawQuadsWithEmptyPatches) {
+ // The top component of the 9-patch is empty, so there should be no quads for
+ // the top three components.
+ gfx::Size bitmap_size(100, 100);
+ gfx::Size layer_size(100, 100);
+ gfx::Rect aperture_rect(10, 0, 80, 90);
+ gfx::Rect border(10, 0, 20, 10);
+ bool fill_center = false;
+ size_t expected_quad_size = 5;
+ NinePatchLayerLayoutTest(bitmap_size,
+ aperture_rect,
+ layer_size,
+ border,
+ fill_center,
+ expected_quad_size);
+
+ // The top and left components of the 9-patch are empty, so there should be no
+ // quads for the left and top components.
+ bitmap_size = gfx::Size(100, 100);
+ layer_size = gfx::Size(100, 100);
+ aperture_rect = gfx::Rect(0, 0, 90, 90);
+ border = gfx::Rect(0, 0, 10, 10);
+ fill_center = false;
+ expected_quad_size = 3;
+ NinePatchLayerLayoutTest(bitmap_size,
+ aperture_rect,
+ layer_size,
+ border,
+ fill_center,
+ expected_quad_size);
+
+ // The aperture is the size of the bitmap and the center doesn't draw.
+ bitmap_size = gfx::Size(100, 100);
+ layer_size = gfx::Size(100, 100);
+ aperture_rect = gfx::Rect(0, 0, 100, 100);
+ border = gfx::Rect(0, 0, 0, 0);
+ fill_center = false;
+ expected_quad_size = 0;
+ NinePatchLayerLayoutTest(bitmap_size,
+ aperture_rect,
+ layer_size,
+ border,
+ fill_center,
+ expected_quad_size);
+
+ // The aperture is the size of the bitmap and the center does draw.
+ bitmap_size = gfx::Size(100, 100);
+ layer_size = gfx::Size(100, 100);
+ aperture_rect = gfx::Rect(0, 0, 100, 100);
+ border = gfx::Rect(0, 0, 0, 0);
+ fill_center = true;
+ expected_quad_size = 1;
+ NinePatchLayerLayoutTest(bitmap_size,
+ aperture_rect,
+ layer_size,
+ border,
+ fill_center,
+ expected_quad_size);
+}
+
+TEST(NinePatchLayerImplTest, Occlusion) {
+ gfx::Size layer_size(1000, 1000);
+ gfx::Size viewport_size(1000, 1000);
+
+ LayerTestCommon::LayerImplTest impl;
+
+ SkBitmap sk_bitmap;
+ sk_bitmap.allocN32Pixels(10, 10);
+ sk_bitmap.setImmutable();
+ UIResourceId uid = 5;
+ UIResourceBitmap bitmap(sk_bitmap);
+ impl.host_impl()->CreateUIResource(uid, bitmap);
+
+ NinePatchLayerImpl* nine_patch_layer_impl =
+ impl.AddChildToRoot<NinePatchLayerImpl>();
+ nine_patch_layer_impl->SetBounds(layer_size);
+ nine_patch_layer_impl->SetContentBounds(layer_size);
+ nine_patch_layer_impl->SetDrawsContent(true);
+ nine_patch_layer_impl->SetUIResourceId(uid);
+ nine_patch_layer_impl->SetImageBounds(gfx::Size(10, 10));
+
+ gfx::Rect aperture = gfx::Rect(3, 3, 4, 4);
+ gfx::Rect border = gfx::Rect(300, 300, 400, 400);
+ nine_patch_layer_impl->SetLayout(aperture, border, true);
+
+ impl.CalcDrawProps(viewport_size);
+
+ {
+ SCOPED_TRACE("No occlusion");
+ gfx::Rect occluded;
+ impl.AppendQuadsWithOcclusion(nine_patch_layer_impl, occluded);
+
+ LayerTestCommon::VerifyQuadsExactlyCoverRect(impl.quad_list(),
+ gfx::Rect(layer_size));
+ EXPECT_EQ(9u, impl.quad_list().size());
+ }
+
+ {
+ SCOPED_TRACE("Full occlusion");
+ gfx::Rect occluded(nine_patch_layer_impl->visible_content_rect());
+ impl.AppendQuadsWithOcclusion(nine_patch_layer_impl, occluded);
+
+ LayerTestCommon::VerifyQuadsExactlyCoverRect(impl.quad_list(), gfx::Rect());
+ EXPECT_EQ(impl.quad_list().size(), 0u);
+ }
+
+ {
+ SCOPED_TRACE("Partial occlusion");
+ gfx::Rect occluded(0, 0, 500, 1000);
+ impl.AppendQuadsWithOcclusion(nine_patch_layer_impl, occluded);
+
+ size_t partially_occluded_count = 0;
+ LayerTestCommon::VerifyQuadsCoverRectWithOcclusion(
+ impl.quad_list(),
+ gfx::Rect(layer_size),
+ occluded,
+ &partially_occluded_count);
+ // The layer outputs nine quads, three of which are partially occluded, and
+ // three fully occluded.
+ EXPECT_EQ(6u, impl.quad_list().size());
+ EXPECT_EQ(3u, partially_occluded_count);
+ }
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/layers/nine_patch_layer_unittest.cc b/chromium/cc/layers/nine_patch_layer_unittest.cc
index 41da351088e..4166d8e9cab 100644
--- a/chromium/cc/layers/nine_patch_layer_unittest.cc
+++ b/chromium/cc/layers/nine_patch_layer_unittest.cc
@@ -4,17 +4,16 @@
#include "cc/layers/nine_patch_layer.h"
-#include "cc/debug/overdraw_metrics.h"
#include "cc/resources/prioritized_resource_manager.h"
#include "cc/resources/resource_provider.h"
#include "cc/resources/resource_update_queue.h"
#include "cc/resources/scoped_ui_resource.h"
-#include "cc/scheduler/texture_uploader.h"
#include "cc/test/fake_layer_tree_host.h"
#include "cc/test/fake_layer_tree_host_client.h"
#include "cc/test/fake_output_surface.h"
#include "cc/test/fake_output_surface_client.h"
#include "cc/test/geometry_test_utils.h"
+#include "cc/test/test_shared_bitmap_manager.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/occlusion_tracker.h"
#include "cc/trees/single_thread_proxy.h"
@@ -58,19 +57,16 @@ TEST_F(NinePatchLayerTest, SetLayerProperties) {
EXPECT_EQ(test_layer->layer_tree_host(), layer_tree_host_.get());
ResourceUpdateQueue queue;
- OcclusionTracker occlusion_tracker(gfx::Rect(), false);
+ gfx::Rect screen_space_clip_rect;
+ OcclusionTracker<Layer> occlusion_tracker(screen_space_clip_rect);
test_layer->SavePaintProperties();
test_layer->Update(&queue, &occlusion_tracker);
EXPECT_FALSE(test_layer->DrawsContent());
- SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, 10, 10);
- bitmap.allocPixels();
- bitmap.setImmutable();
-
+ bool is_opaque = false;
scoped_ptr<ScopedUIResource> resource = ScopedUIResource::Create(
- layer_tree_host_.get(), UIResourceBitmap(bitmap));
+ layer_tree_host_.get(), UIResourceBitmap(gfx::Size(10, 10), is_opaque));
gfx::Rect aperture(5, 5, 1, 1);
bool fill_center = true;
test_layer->SetAperture(aperture);
diff --git a/chromium/cc/layers/painted_scrollbar_layer.cc b/chromium/cc/layers/painted_scrollbar_layer.cc
index 6bb76368c48..9c5ab887c6f 100644
--- a/chromium/cc/layers/painted_scrollbar_layer.cc
+++ b/chromium/cc/layers/painted_scrollbar_layer.cc
@@ -33,11 +33,11 @@ scoped_refptr<PaintedScrollbarLayer> PaintedScrollbarLayer::Create(
new PaintedScrollbarLayer(scrollbar.Pass(), scroll_layer_id));
}
-PaintedScrollbarLayer::PaintedScrollbarLayer(
- scoped_ptr<Scrollbar> scrollbar,
- int scroll_layer_id)
+PaintedScrollbarLayer::PaintedScrollbarLayer(scoped_ptr<Scrollbar> scrollbar,
+ int scroll_layer_id)
: scrollbar_(scrollbar.Pass()),
scroll_layer_id_(scroll_layer_id),
+ clip_layer_id_(Layer::INVALID_ID),
thumb_thickness_(scrollbar_->ThumbThickness()),
thumb_length_(scrollbar_->ThumbLength()),
is_overlay_(scrollbar_->IsOverlay()),
@@ -52,11 +52,19 @@ int PaintedScrollbarLayer::ScrollLayerId() const {
return scroll_layer_id_;
}
-void PaintedScrollbarLayer::SetScrollLayerId(int id) {
- if (id == scroll_layer_id_)
+void PaintedScrollbarLayer::SetScrollLayer(int layer_id) {
+ if (layer_id == scroll_layer_id_)
+ return;
+
+ scroll_layer_id_ = layer_id;
+ SetNeedsFullTreeSync();
+}
+
+void PaintedScrollbarLayer::SetClipLayer(int layer_id) {
+ if (layer_id == clip_layer_id_)
return;
- scroll_layer_id_ = id;
+ clip_layer_id_ = layer_id;
SetNeedsFullTreeSync();
}
@@ -92,6 +100,7 @@ void PaintedScrollbarLayer::CalculateContentsScale(
float ideal_contents_scale,
float device_scale_factor,
float page_scale_factor,
+ float maximum_animation_contents_scale,
bool animating_transform_to_screen,
float* contents_scale_x,
float* contents_scale_y,
@@ -100,6 +109,7 @@ void PaintedScrollbarLayer::CalculateContentsScale(
ClampScaleToMaxTextureSize(ideal_contents_scale),
device_scale_factor,
page_scale_factor,
+ maximum_animation_contents_scale,
animating_transform_to_screen,
contents_scale_x,
contents_scale_y,
@@ -109,6 +119,8 @@ void PaintedScrollbarLayer::CalculateContentsScale(
void PaintedScrollbarLayer::PushPropertiesTo(LayerImpl* layer) {
ContentsScalingLayer::PushPropertiesTo(layer);
+ PushScrollClipPropertiesTo(layer);
+
PaintedScrollbarLayerImpl* scrollbar_layer =
static_cast<PaintedScrollbarLayerImpl*>(layer);
@@ -136,6 +148,14 @@ ScrollbarLayerInterface* PaintedScrollbarLayer::ToScrollbarLayer() {
return this;
}
+void PaintedScrollbarLayer::PushScrollClipPropertiesTo(LayerImpl* layer) {
+ PaintedScrollbarLayerImpl* scrollbar_layer =
+ static_cast<PaintedScrollbarLayerImpl*>(layer);
+
+ scrollbar_layer->SetScrollLayerById(scroll_layer_id_);
+ scrollbar_layer->SetClipLayerById(clip_layer_id_);
+}
+
void PaintedScrollbarLayer::SetLayerTreeHost(LayerTreeHost* host) {
// When the LTH is set to null or has changed, then this layer should remove
// all of its associated resources.
@@ -148,11 +168,11 @@ void PaintedScrollbarLayer::SetLayerTreeHost(LayerTreeHost* host) {
}
gfx::Rect PaintedScrollbarLayer::ScrollbarLayerRectToContentRect(
- gfx::Rect layer_rect) const {
+ const gfx::Rect& layer_rect) const {
// Don't intersect with the bounds as in LayerRectToContentRect() because
// layer_rect here might be in coordinates of the containing layer.
gfx::Rect expanded_rect = gfx::ScaleToEnclosingRect(
- layer_rect, contents_scale_y(), contents_scale_y());
+ layer_rect, contents_scale_x(), contents_scale_y());
// We should never return a rect bigger than the content_bounds().
gfx::Size clamped_size = expanded_rect.size();
clamped_size.SetToMin(content_bounds());
@@ -169,7 +189,7 @@ gfx::Rect PaintedScrollbarLayer::OriginThumbRect() const {
thumb_size =
gfx::Size(scrollbar_->ThumbThickness(), scrollbar_->ThumbLength());
}
- return ScrollbarLayerRectToContentRect(gfx::Rect(thumb_size));
+ return gfx::Rect(thumb_size);
}
void PaintedScrollbarLayer::UpdateThumbAndTrackGeometry() {
@@ -184,11 +204,12 @@ void PaintedScrollbarLayer::UpdateThumbAndTrackGeometry() {
}
bool PaintedScrollbarLayer::Update(ResourceUpdateQueue* queue,
- const OcclusionTracker* occlusion) {
+ const OcclusionTracker<Layer>* occlusion) {
UpdateThumbAndTrackGeometry();
+ gfx::Rect track_layer_rect = gfx::Rect(location_, bounds());
gfx::Rect scaled_track_rect = ScrollbarLayerRectToContentRect(
- gfx::Rect(location_, bounds()));
+ track_layer_rect);
if (track_rect_.IsEmpty() || scaled_track_rect.IsEmpty())
return false;
@@ -203,12 +224,16 @@ bool PaintedScrollbarLayer::Update(ResourceUpdateQueue* queue,
return false;
track_resource_ = ScopedUIResource::Create(
- layer_tree_host(), RasterizeScrollbarPart(scaled_track_rect, TRACK));
+ layer_tree_host(),
+ RasterizeScrollbarPart(track_layer_rect, scaled_track_rect, TRACK));
- gfx::Rect thumb_rect = OriginThumbRect();
- if (has_thumb_ && !thumb_rect.IsEmpty()) {
+ gfx::Rect thumb_layer_rect = OriginThumbRect();
+ gfx::Rect scaled_thumb_rect =
+ ScrollbarLayerRectToContentRect(thumb_layer_rect);
+ if (has_thumb_ && !scaled_thumb_rect.IsEmpty()) {
thumb_resource_ = ScopedUIResource::Create(
- layer_tree_host(), RasterizeScrollbarPart(thumb_rect, THUMB));
+ layer_tree_host(),
+ RasterizeScrollbarPart(thumb_layer_rect, scaled_thumb_rect, THUMB));
}
// UI resources changed so push properties is needed.
@@ -217,21 +242,26 @@ bool PaintedScrollbarLayer::Update(ResourceUpdateQueue* queue,
}
UIResourceBitmap PaintedScrollbarLayer::RasterizeScrollbarPart(
- gfx::Rect rect,
+ const gfx::Rect& layer_rect,
+ const gfx::Rect& content_rect,
ScrollbarPart part) {
- DCHECK(!rect.size().IsEmpty());
+ DCHECK(!content_rect.size().IsEmpty());
+ DCHECK(!layer_rect.size().IsEmpty());
SkBitmap skbitmap;
- skbitmap.setConfig(SkBitmap::kARGB_8888_Config, rect.width(), rect.height());
- skbitmap.allocPixels();
-
+ skbitmap.allocN32Pixels(content_rect.width(), content_rect.height());
SkCanvas skcanvas(skbitmap);
- skcanvas.translate(SkFloatToScalar(-rect.x()), SkFloatToScalar(-rect.y()));
- skcanvas.scale(SkFloatToScalar(contents_scale_x()),
- SkFloatToScalar(contents_scale_y()));
- gfx::Rect layer_rect = gfx::ScaleToEnclosingRect(
- rect, 1.f / contents_scale_x(), 1.f / contents_scale_y());
+ float scale_x =
+ content_rect.width() / static_cast<float>(layer_rect.width());
+ float scale_y =
+ content_rect.height() / static_cast<float>(layer_rect.height());
+
+ skcanvas.scale(SkFloatToScalar(scale_x),
+ SkFloatToScalar(scale_y));
+ skcanvas.translate(SkFloatToScalar(-layer_rect.x()),
+ SkFloatToScalar(-layer_rect.y()));
+
SkRect layer_skrect = RectToSkRect(layer_rect);
SkPaint paint;
paint.setAntiAlias(false);
diff --git a/chromium/cc/layers/painted_scrollbar_layer.h b/chromium/cc/layers/painted_scrollbar_layer.h
index 606ad69b905..d684d322fad 100644
--- a/chromium/cc/layers/painted_scrollbar_layer.h
+++ b/chromium/cc/layers/painted_scrollbar_layer.h
@@ -31,18 +31,21 @@ class CC_EXPORT PaintedScrollbarLayer : public ScrollbarLayerInterface,
// ScrollbarLayerInterface
virtual int ScrollLayerId() const OVERRIDE;
- virtual void SetScrollLayerId(int id) OVERRIDE;
+ virtual void SetScrollLayer(int layer_id) OVERRIDE;
+ virtual void SetClipLayer(int layer_id) OVERRIDE;
virtual ScrollbarOrientation orientation() const OVERRIDE;
// Layer interface
virtual bool Update(ResourceUpdateQueue* queue,
- const OcclusionTracker* occlusion) OVERRIDE;
+ const OcclusionTracker<Layer>* occlusion) OVERRIDE;
virtual void SetLayerTreeHost(LayerTreeHost* host) OVERRIDE;
virtual void PushPropertiesTo(LayerImpl* layer) OVERRIDE;
+ virtual void PushScrollClipPropertiesTo(LayerImpl* layer) OVERRIDE;
virtual void CalculateContentsScale(float ideal_contents_scale,
float device_scale_factor,
float page_scale_factor,
+ float maximum_animation_contents_scale,
bool animating_transform_to_screen,
float* contents_scale_x,
float* contents_scale_y,
@@ -62,7 +65,7 @@ class CC_EXPORT PaintedScrollbarLayer : public ScrollbarLayerInterface,
void UpdateThumbAndTrackGeometry();
private:
- gfx::Rect ScrollbarLayerRectToContentRect(gfx::Rect layer_rect) const;
+ gfx::Rect ScrollbarLayerRectToContentRect(const gfx::Rect& layer_rect) const;
gfx::Rect OriginThumbRect() const;
template<typename T> void UpdateProperty(T value, T* prop) {
@@ -75,11 +78,13 @@ class CC_EXPORT PaintedScrollbarLayer : public ScrollbarLayerInterface,
int MaxTextureSize();
float ClampScaleToMaxTextureSize(float scale);
- UIResourceBitmap RasterizeScrollbarPart(gfx::Rect rect,
+ UIResourceBitmap RasterizeScrollbarPart(const gfx::Rect& layer_rect,
+ const gfx::Rect& content_rect,
ScrollbarPart part);
scoped_ptr<Scrollbar> scrollbar_;
int scroll_layer_id_;
+ int clip_layer_id_;
// Snapshot of properties taken in UpdateThumbAndTrackGeometry and used in
// PushPropertiesTo.
diff --git a/chromium/cc/layers/painted_scrollbar_layer_impl.cc b/chromium/cc/layers/painted_scrollbar_layer_impl.cc
index a7fdfa3081d..b83419f90d1 100644
--- a/chromium/cc/layers/painted_scrollbar_layer_impl.cc
+++ b/chromium/cc/layers/painted_scrollbar_layer_impl.cc
@@ -29,7 +29,7 @@ PaintedScrollbarLayerImpl::PaintedScrollbarLayerImpl(
LayerTreeImpl* tree_impl,
int id,
ScrollbarOrientation orientation)
- : ScrollbarLayerImplBase(tree_impl, id, orientation, false),
+ : ScrollbarLayerImplBase(tree_impl, id, orientation, false, false),
track_ui_resource_id_(0),
thumb_ui_resource_id_(0),
thumb_thickness_(0),
@@ -78,24 +78,29 @@ void PaintedScrollbarLayerImpl::AppendQuads(
gfx::Rect bounds_rect(bounds());
gfx::Rect content_bounds_rect(content_bounds());
- SharedQuadState* shared_quad_state =
- quad_sink->UseSharedQuadState(CreateSharedQuadState());
- AppendDebugBorderQuad(quad_sink, shared_quad_state, append_quads_data);
+ SharedQuadState* shared_quad_state = quad_sink->CreateSharedQuadState();
+ PopulateSharedQuadState(shared_quad_state);
+
+ AppendDebugBorderQuad(
+ quad_sink, content_bounds(), shared_quad_state, append_quads_data);
gfx::Rect thumb_quad_rect = ComputeThumbQuadRect();
+ gfx::Rect visible_thumb_quad_rect =
+ quad_sink->UnoccludedContentRect(thumb_quad_rect, draw_transform());
ResourceProvider::ResourceId thumb_resource_id =
layer_tree_impl()->ResourceIdForUIResource(thumb_ui_resource_id_);
ResourceProvider::ResourceId track_resource_id =
layer_tree_impl()->ResourceIdForUIResource(track_ui_resource_id_);
- if (thumb_resource_id && !thumb_quad_rect.IsEmpty()) {
+ if (thumb_resource_id && !visible_thumb_quad_rect.IsEmpty()) {
gfx::Rect opaque_rect;
const float opacity[] = {1.0f, 1.0f, 1.0f, 1.0f};
scoped_ptr<TextureDrawQuad> quad = TextureDrawQuad::Create();
quad->SetNew(shared_quad_state,
thumb_quad_rect,
opaque_rect,
+ visible_thumb_quad_rect,
thumb_resource_id,
premultipled_alpha,
uv_top_left,
@@ -103,17 +108,20 @@ void PaintedScrollbarLayerImpl::AppendQuads(
SK_ColorTRANSPARENT,
opacity,
flipped);
- quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
+ quad_sink->Append(quad.PassAs<DrawQuad>());
}
gfx::Rect track_quad_rect = content_bounds_rect;
- if (track_resource_id && !track_quad_rect.IsEmpty()) {
+ gfx::Rect visible_track_quad_rect =
+ quad_sink->UnoccludedContentRect(track_quad_rect, draw_transform());
+ if (track_resource_id && !visible_track_quad_rect.IsEmpty()) {
gfx::Rect opaque_rect(contents_opaque() ? track_quad_rect : gfx::Rect());
const float opacity[] = {1.0f, 1.0f, 1.0f, 1.0f};
scoped_ptr<TextureDrawQuad> quad = TextureDrawQuad::Create();
quad->SetNew(shared_quad_state,
track_quad_rect,
opaque_rect,
+ visible_track_quad_rect,
track_resource_id,
premultipled_alpha,
uv_top_left,
@@ -121,7 +129,7 @@ void PaintedScrollbarLayerImpl::AppendQuads(
SK_ColorTRANSPARENT,
opacity,
flipped);
- quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
+ quad_sink->Append(quad.PassAs<DrawQuad>());
}
}
@@ -169,6 +177,10 @@ float PaintedScrollbarLayerImpl::TrackLength() const {
return track_length_ + (orientation() == VERTICAL ? vertical_adjust() : 0);
}
+bool PaintedScrollbarLayerImpl::IsThumbResizable() const {
+ return false;
+}
+
const char* PaintedScrollbarLayerImpl::LayerTypeAsString() const {
return "cc::PaintedScrollbarLayerImpl";
}
diff --git a/chromium/cc/layers/painted_scrollbar_layer_impl.h b/chromium/cc/layers/painted_scrollbar_layer_impl.h
index a094416261f..16cfa55680c 100644
--- a/chromium/cc/layers/painted_scrollbar_layer_impl.h
+++ b/chromium/cc/layers/painted_scrollbar_layer_impl.h
@@ -55,6 +55,7 @@ class CC_EXPORT PaintedScrollbarLayerImpl : public ScrollbarLayerImplBase {
virtual int ThumbLength() const OVERRIDE;
virtual float TrackLength() const OVERRIDE;
virtual int TrackStart() const OVERRIDE;
+ virtual bool IsThumbResizable() const OVERRIDE;
private:
virtual const char* LayerTypeAsString() const OVERRIDE;
diff --git a/chromium/cc/layers/painted_scrollbar_layer_impl_unittest.cc b/chromium/cc/layers/painted_scrollbar_layer_impl_unittest.cc
new file mode 100644
index 00000000000..c45af0326ee
--- /dev/null
+++ b/chromium/cc/layers/painted_scrollbar_layer_impl_unittest.cc
@@ -0,0 +1,94 @@
+// 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/layers/painted_scrollbar_layer_impl.h"
+
+#include "cc/test/layer_test_common.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+namespace {
+
+TEST(PaintedScrollbarLayerImplTest, Occlusion) {
+ gfx::Size layer_size(10, 1000);
+ gfx::Size viewport_size(1000, 1000);
+
+ LayerTestCommon::LayerImplTest impl;
+
+ SkBitmap thumb_sk_bitmap;
+ thumb_sk_bitmap.allocN32Pixels(10, 10);
+ thumb_sk_bitmap.setImmutable();
+ UIResourceId thumb_uid = 5;
+ UIResourceBitmap thumb_bitmap(thumb_sk_bitmap);
+ impl.host_impl()->CreateUIResource(thumb_uid, thumb_bitmap);
+
+ SkBitmap track_sk_bitmap;
+ track_sk_bitmap.allocN32Pixels(10, 10);
+ track_sk_bitmap.setImmutable();
+ UIResourceId track_uid = 6;
+ UIResourceBitmap track_bitmap(track_sk_bitmap);
+ impl.host_impl()->CreateUIResource(track_uid, track_bitmap);
+
+ ScrollbarOrientation orientation = VERTICAL;
+
+ PaintedScrollbarLayerImpl* scrollbar_layer_impl =
+ impl.AddChildToRoot<PaintedScrollbarLayerImpl>(orientation);
+ scrollbar_layer_impl->SetBounds(layer_size);
+ scrollbar_layer_impl->SetContentBounds(layer_size);
+ scrollbar_layer_impl->SetDrawsContent(true);
+ scrollbar_layer_impl->SetThumbThickness(layer_size.width());
+ scrollbar_layer_impl->SetThumbLength(500);
+ scrollbar_layer_impl->SetTrackLength(layer_size.height());
+ scrollbar_layer_impl->SetCurrentPos(100.f / 4);
+ scrollbar_layer_impl->SetMaximum(100);
+ scrollbar_layer_impl->SetVisibleToTotalLengthRatio(1.f / 2);
+ scrollbar_layer_impl->set_track_ui_resource_id(track_uid);
+ scrollbar_layer_impl->set_thumb_ui_resource_id(thumb_uid);
+
+ impl.CalcDrawProps(viewport_size);
+
+ gfx::Rect thumb_rect = scrollbar_layer_impl->ComputeThumbQuadRect();
+ EXPECT_EQ(gfx::Rect(0, 500 / 4, 10, layer_size.height() / 2).ToString(),
+ thumb_rect.ToString());
+
+ {
+ SCOPED_TRACE("No occlusion");
+ gfx::Rect occluded;
+ impl.AppendQuadsWithOcclusion(scrollbar_layer_impl, occluded);
+
+ size_t partially_occluded_count = 0;
+ LayerTestCommon::VerifyQuadsCoverRectWithOcclusion(
+ impl.quad_list(),
+ gfx::Rect(layer_size),
+ occluded,
+ &partially_occluded_count);
+ EXPECT_EQ(2u, impl.quad_list().size());
+ EXPECT_EQ(0u, partially_occluded_count);
+ }
+
+ {
+ SCOPED_TRACE("Full occlusion");
+ gfx::Rect occluded(scrollbar_layer_impl->visible_content_rect());
+ impl.AppendQuadsWithOcclusion(scrollbar_layer_impl, occluded);
+
+ LayerTestCommon::VerifyQuadsExactlyCoverRect(impl.quad_list(), gfx::Rect());
+ EXPECT_EQ(impl.quad_list().size(), 0u);
+ }
+
+ {
+ SCOPED_TRACE("Partial occlusion");
+ gfx::Rect occluded(0, 0, 5, 1000);
+ impl.AppendQuadsWithOcclusion(scrollbar_layer_impl, occluded);
+
+ size_t partially_occluded_count = 0;
+ LayerTestCommon::VerifyQuadsCoverRectWithOcclusion(
+ impl.quad_list(), thumb_rect, occluded, &partially_occluded_count);
+ // The layer outputs two quads, which is partially occluded.
+ EXPECT_EQ(2u, impl.quad_list().size());
+ EXPECT_EQ(2u, partially_occluded_count);
+ }
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/layers/picture_image_layer.cc b/chromium/cc/layers/picture_image_layer.cc
index 03e3a9e0157..a65ac8c9318 100644
--- a/chromium/cc/layers/picture_image_layer.cc
+++ b/chromium/cc/layers/picture_image_layer.cc
@@ -40,9 +40,11 @@ void PictureImageLayer::SetBitmap(const SkBitmap& bitmap) {
SetNeedsDisplay();
}
-void PictureImageLayer::PaintContents(SkCanvas* canvas,
- gfx::Rect clip,
- gfx::RectF* opaque) {
+void PictureImageLayer::PaintContents(
+ SkCanvas* canvas,
+ const gfx::Rect& clip,
+ gfx::RectF* opaque,
+ ContentLayerClient::GraphicsContextStatus gc_status) {
if (!bitmap_.width() || !bitmap_.height())
return;
@@ -52,7 +54,17 @@ void PictureImageLayer::PaintContents(SkCanvas* canvas,
SkFloatToScalar(static_cast<float>(bounds().height()) / bitmap_.height());
canvas->scale(content_to_layer_scale_x, content_to_layer_scale_y);
- canvas->drawBitmap(bitmap_, 0, 0);
+ // Because PictureImageLayer always FillsBoundsCompletely it will not clear
+ // before painting on playback. As a result we must configure the paint to
+ // copy over the uncleared destination, rather than blending with it.
+ SkPaint paint;
+ paint.setXfermodeMode(SkXfermode::kSrc_Mode);
+ canvas->drawBitmap(bitmap_, 0, 0, &paint);
+}
+
+bool PictureImageLayer::FillsBoundsCompletely() const {
+ // PictureImageLayer will always paint to the entire layer bounds.
+ return true;
}
} // namespace cc
diff --git a/chromium/cc/layers/picture_image_layer.h b/chromium/cc/layers/picture_image_layer.h
index 09db1df6b3b..69b89d1b68a 100644
--- a/chromium/cc/layers/picture_image_layer.h
+++ b/chromium/cc/layers/picture_image_layer.h
@@ -27,9 +27,11 @@ class CC_EXPORT PictureImageLayer : public PictureLayer, ContentLayerClient {
// ContentLayerClient implementation.
virtual void PaintContents(
SkCanvas* canvas,
- gfx::Rect clip,
- gfx::RectF* opaque) OVERRIDE;
+ const gfx::Rect& clip,
+ gfx::RectF* opaque,
+ ContentLayerClient::GraphicsContextStatus gc_status) OVERRIDE;
virtual void DidChangeLayerCanUseLCDText() OVERRIDE {}
+ virtual bool FillsBoundsCompletely() const OVERRIDE;
private:
PictureImageLayer();
diff --git a/chromium/cc/layers/picture_image_layer_impl.cc b/chromium/cc/layers/picture_image_layer_impl.cc
index b9a57f2b7b0..247c46adbfc 100644
--- a/chromium/cc/layers/picture_image_layer_impl.cc
+++ b/chromium/cc/layers/picture_image_layer_impl.cc
@@ -27,47 +27,32 @@ scoped_ptr<LayerImpl> PictureImageLayerImpl::CreateLayerImpl(
return PictureImageLayerImpl::Create(tree_impl, id()).PassAs<LayerImpl>();
}
-void PictureImageLayerImpl::CalculateContentsScale(
- float ideal_contents_scale,
- float device_scale_factor,
- float page_scale_factor,
- bool animating_transform_to_screen,
- float* contents_scale_x,
- float* contents_scale_y,
- gfx::Size* content_bounds) {
- // CalculateRasterContentsScale always returns 1.f, so make that the ideal
- // scale.
- ideal_contents_scale = 1.f;
- PictureLayerImpl::CalculateContentsScale(ideal_contents_scale,
- device_scale_factor,
- page_scale_factor,
- animating_transform_to_screen,
- contents_scale_x,
- contents_scale_y,
- content_bounds);
-}
-
void PictureImageLayerImpl::GetDebugBorderProperties(
SkColor* color, float* width) const {
*color = DebugColors::ImageLayerBorderColor();
*width = DebugColors::ImageLayerBorderWidth(layer_tree_impl());
}
-bool PictureImageLayerImpl::ShouldAdjustRasterScale(
- bool animating_transform_to_screen) const {
+bool PictureImageLayerImpl::ShouldAdjustRasterScale() const {
return false;
}
-void PictureImageLayerImpl::RecalculateRasterScales(
- bool animating_transform_to_screen) {
- // Defaults from PictureLayerImpl.
- PictureLayerImpl::RecalculateRasterScales(animating_transform_to_screen);
-
+void PictureImageLayerImpl::RecalculateRasterScales() {
// Don't scale images during rastering to ensure image quality, save memory
// and avoid frequent re-rastering on change of scale.
- raster_contents_scale_ = std::max(1.f, MinimumContentsScale());
+ raster_page_scale_ = 1.f;
+ raster_device_scale_ = 1.f;
+ raster_source_scale_ = std::max(1.f, MinimumContentsScale());
+ raster_contents_scale_ = raster_source_scale_;
// We don't need low res tiles.
low_res_raster_contents_scale_ = raster_contents_scale_;
}
+void PictureImageLayerImpl::UpdateIdealScales() {
+ ideal_contents_scale_ = 1.f;
+ ideal_page_scale_ = 1.f;
+ ideal_device_scale_ = 1.f;
+ ideal_source_scale_ = 1.f;
+}
+
} // namespace cc
diff --git a/chromium/cc/layers/picture_image_layer_impl.h b/chromium/cc/layers/picture_image_layer_impl.h
index 0b3b246259d..cb48cf5e509 100644
--- a/chromium/cc/layers/picture_image_layer_impl.h
+++ b/chromium/cc/layers/picture_image_layer_impl.h
@@ -21,24 +21,17 @@ class CC_EXPORT PictureImageLayerImpl : public PictureLayerImpl {
virtual const char* LayerTypeAsString() const OVERRIDE;
virtual scoped_ptr<LayerImpl> CreateLayerImpl(
LayerTreeImpl* tree_impl) OVERRIDE;
- virtual void CalculateContentsScale(float ideal_contents_scale,
- float device_scale_factor,
- float page_scale_factor,
- bool animating_transform_to_screen,
- float* contents_scale_x,
- float* contents_scale_y,
- gfx::Size* content_bounds) OVERRIDE;
protected:
PictureImageLayerImpl(LayerTreeImpl* tree_impl, int id);
- virtual bool ShouldAdjustRasterScale(
- bool animating_transform_to_screen) const OVERRIDE;
- virtual void RecalculateRasterScales(
- bool animating_transform_to_screen) OVERRIDE;
+ virtual bool ShouldAdjustRasterScale() const OVERRIDE;
+ virtual void RecalculateRasterScales() OVERRIDE;
virtual void GetDebugBorderProperties(
SkColor* color, float* width) const OVERRIDE;
+ virtual void UpdateIdealScales() OVERRIDE;
+
private:
DISALLOW_COPY_AND_ASSIGN(PictureImageLayerImpl);
};
diff --git a/chromium/cc/layers/picture_image_layer_impl_unittest.cc b/chromium/cc/layers/picture_image_layer_impl_unittest.cc
index 2910da1d5e7..e8eb8ff6277 100644
--- a/chromium/cc/layers/picture_image_layer_impl_unittest.cc
+++ b/chromium/cc/layers/picture_image_layer_impl_unittest.cc
@@ -12,6 +12,7 @@
#include "cc/test/fake_picture_layer_tiling_client.h"
#include "cc/test/impl_side_painting_settings.h"
#include "cc/test/mock_quad_culler.h"
+#include "cc/test/test_shared_bitmap_manager.h"
#include "cc/trees/layer_tree_impl.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -23,6 +24,9 @@ class TestablePictureImageLayerImpl : public PictureImageLayerImpl {
TestablePictureImageLayerImpl(LayerTreeImpl* tree_impl, int id)
: PictureImageLayerImpl(tree_impl, id) {
}
+ using PictureLayerImpl::UpdateIdealScales;
+ using PictureLayerImpl::MaximumTilingContentsScale;
+ using PictureLayerImpl::DoPostCommitInitializationIfNeeded;
PictureLayerTilingSet* tilings() { return tilings_.get(); }
@@ -32,10 +36,14 @@ class TestablePictureImageLayerImpl : public PictureImageLayerImpl {
class PictureImageLayerImplTest : public testing::Test {
public:
PictureImageLayerImplTest()
- : host_impl_(ImplSidePaintingSettings(), &proxy_) {
+ : proxy_(base::MessageLoopProxy::current()),
+ host_impl_(ImplSidePaintingSettings(),
+ &proxy_,
+ &shared_bitmap_manager_) {
tiling_client_.SetTileSize(ImplSidePaintingSettings().default_tile_size);
host_impl_.CreatePendingTree();
- host_impl_.InitializeRenderer(CreateFakeOutputSurface());
+ host_impl_.InitializeRenderer(
+ FakeOutputSurface::Create3d().PassAs<OutputSurface>());
}
scoped_ptr<TestablePictureImageLayerImpl> CreateLayer(int id,
@@ -55,19 +63,33 @@ class PictureImageLayerImplTest : public testing::Test {
TestablePictureImageLayerImpl* layer =
new TestablePictureImageLayerImpl(tree, id);
layer->SetBounds(gfx::Size(100, 200));
+ layer->SetContentBounds(gfx::Size(100, 200));
layer->tilings_.reset(new PictureLayerTilingSet(&tiling_client_,
layer->bounds()));
layer->pile_ = tiling_client_.pile();
return make_scoped_ptr(layer);
}
- void UpdateDrawProperties() {
- host_impl_.pending_tree()->UpdateDrawProperties();
+ void SetupDrawPropertiesAndUpdateTiles(TestablePictureImageLayerImpl* layer,
+ float ideal_contents_scale,
+ float device_scale_factor,
+ float page_scale_factor,
+ float maximum_animation_contents_scale,
+ bool animating_transform_to_screen) {
+ layer->draw_properties().ideal_contents_scale = ideal_contents_scale;
+ layer->draw_properties().device_scale_factor = device_scale_factor;
+ layer->draw_properties().page_scale_factor = page_scale_factor;
+ layer->draw_properties().maximum_animation_contents_scale =
+ maximum_animation_contents_scale;
+ layer->draw_properties().screen_space_transform_is_animating =
+ animating_transform_to_screen;
+ layer->UpdateTiles();
}
protected:
FakeImplProxy proxy_;
FakeLayerTreeHostImpl host_impl_;
+ TestSharedBitmapManager shared_bitmap_manager_;
FakePictureLayerTilingClient tiling_client_;
};
@@ -75,33 +97,11 @@ TEST_F(PictureImageLayerImplTest, CalculateContentsScale) {
scoped_ptr<TestablePictureImageLayerImpl> layer(CreateLayer(1, PENDING_TREE));
layer->SetDrawsContent(true);
- float contents_scale_x;
- float contents_scale_y;
- gfx::Size content_bounds;
- layer->CalculateContentsScale(2.f, 3.f, 4.f, false,
- &contents_scale_x, &contents_scale_y,
- &content_bounds);
- EXPECT_FLOAT_EQ(1.f, contents_scale_x);
- EXPECT_FLOAT_EQ(1.f, contents_scale_y);
- EXPECT_EQ(layer->bounds(), content_bounds);
-}
-
-TEST_F(PictureImageLayerImplTest, AreVisibleResourcesReady) {
- scoped_ptr<TestablePictureImageLayerImpl> layer(CreateLayer(1, PENDING_TREE));
- layer->SetBounds(gfx::Size(100, 200));
- layer->SetDrawsContent(true);
-
- UpdateDrawProperties();
-
- float contents_scale_x;
- float contents_scale_y;
- gfx::Size content_bounds;
- layer->CalculateContentsScale(2.f, 3.f, 4.f, false,
- &contents_scale_x, &contents_scale_y,
- &content_bounds);
- layer->UpdateTilePriorities();
+ SetupDrawPropertiesAndUpdateTiles(layer.get(), 2.f, 3.f, 4.f, 1.f, false);
- EXPECT_TRUE(layer->AreVisibleResourcesReady());
+ EXPECT_FLOAT_EQ(1.f, layer->contents_scale_x());
+ EXPECT_FLOAT_EQ(1.f, layer->contents_scale_y());
+ EXPECT_FLOAT_EQ(1.f, layer->MaximumTilingContentsScale());
}
TEST_F(PictureImageLayerImplTest, IgnoreIdealContentScale) {
@@ -114,41 +114,41 @@ TEST_F(PictureImageLayerImplTest, IgnoreIdealContentScale) {
const float suggested_ideal_contents_scale = 2.f;
const float device_scale_factor = 3.f;
const float page_scale_factor = 4.f;
+ const float maximum_animation_contents_scale = 1.f;
const bool animating_transform_to_screen = false;
- float contents_scale_x;
- float contents_scale_y;
- gfx::Size content_bounds;
- pending_layer->CalculateContentsScale(suggested_ideal_contents_scale,
- device_scale_factor,
- page_scale_factor,
- animating_transform_to_screen,
- &contents_scale_x,
- &contents_scale_y,
- &content_bounds);
+ SetupDrawPropertiesAndUpdateTiles(pending_layer.get(),
+ suggested_ideal_contents_scale,
+ device_scale_factor,
+ page_scale_factor,
+ maximum_animation_contents_scale,
+ animating_transform_to_screen);
+ EXPECT_EQ(1.f, pending_layer->tilings()->tiling_at(0)->contents_scale());
// Push to active layer.
+ host_impl_.pending_tree()->SetRootLayer(pending_layer.PassAs<LayerImpl>());
host_impl_.ActivatePendingTree();
- scoped_ptr<TestablePictureImageLayerImpl> active_layer(
- CreateLayer(1, ACTIVE_TREE));
- pending_layer->PushPropertiesTo(active_layer.get());
- active_layer->CalculateContentsScale(suggested_ideal_contents_scale,
- device_scale_factor,
- page_scale_factor,
- animating_transform_to_screen,
- &contents_scale_x,
- &contents_scale_y,
- &content_bounds);
+ TestablePictureImageLayerImpl* active_layer =
+ static_cast<TestablePictureImageLayerImpl*>(
+ host_impl_.active_tree()->root_layer());
+ SetupDrawPropertiesAndUpdateTiles(active_layer,
+ suggested_ideal_contents_scale,
+ device_scale_factor,
+ page_scale_factor,
+ maximum_animation_contents_scale,
+ animating_transform_to_screen);
+ EXPECT_EQ(1.f, active_layer->tilings()->tiling_at(0)->contents_scale());
// Create tile and resource.
active_layer->tilings()->tiling_at(0)->CreateAllTilesForTesting();
host_impl_.tile_manager()->InitializeTilesWithResourcesForTesting(
- active_layer->tilings()->tiling_at(0)->AllTilesForTesting(),
- host_impl_.resource_provider());
+ active_layer->tilings()->tiling_at(0)->AllTilesForTesting());
// Draw.
active_layer->draw_properties().visible_content_rect =
gfx::Rect(active_layer->bounds());
- MockQuadCuller quad_culler;
+ MockOcclusionTracker<LayerImpl> occlusion_tracker;
+ scoped_ptr<RenderPass> render_pass = RenderPass::Create();
+ MockQuadCuller quad_culler(render_pass.get(), &occlusion_tracker);
AppendQuadsData data;
active_layer->WillDraw(DRAW_MODE_SOFTWARE, NULL);
active_layer->AppendQuads(&quad_culler, &data);
diff --git a/chromium/cc/layers/picture_layer.cc b/chromium/cc/layers/picture_layer.cc
index 1415c8075c5..5d5457456f0 100644
--- a/chromium/cc/layers/picture_layer.cc
+++ b/chromium/cc/layers/picture_layer.cc
@@ -7,6 +7,7 @@
#include "cc/layers/content_layer_client.h"
#include "cc/layers/picture_layer_impl.h"
#include "cc/trees/layer_tree_impl.h"
+#include "third_party/skia/include/core/SkPictureRecorder.h"
#include "ui/gfx/rect_conversions.h"
namespace cc {
@@ -16,11 +17,12 @@ scoped_refptr<PictureLayer> PictureLayer::Create(ContentLayerClient* client) {
}
PictureLayer::PictureLayer(ContentLayerClient* client)
- : client_(client),
- pile_(make_scoped_refptr(new PicturePile())),
- instrumentation_object_tracker_(id()),
- is_mask_(false),
- update_source_frame_number_(-1) {
+ : client_(client),
+ pile_(make_scoped_refptr(new PicturePile())),
+ instrumentation_object_tracker_(id()),
+ is_mask_(false),
+ update_source_frame_number_(-1),
+ can_use_lcd_text_last_frame_(can_use_lcd_text()) {
}
PictureLayer::~PictureLayer() {
@@ -42,15 +44,18 @@ void PictureLayer::PushPropertiesTo(LayerImpl* base_layer) {
// Update may not get called for an empty layer, so resize here instead.
// Using layer_impl because either bounds() or paint_properties().bounds
// may disagree and either one could have been pushed to layer_impl.
- pile_->Resize(gfx::Size());
- pile_->UpdateRecordedRegion();
+ pile_->SetTilingRect(gfx::Rect());
} else if (update_source_frame_number_ ==
layer_tree_host()->source_frame_number()) {
+ // TODO(ernstm): This DCHECK is only valid as long as the pile's tiling_rect
+ // is identical to the layer_rect.
// If update called, then pile size must match bounds pushed to impl layer.
- DCHECK_EQ(layer_impl->bounds().ToString(), pile_->size().ToString());
+ DCHECK_EQ(layer_impl->bounds().ToString(),
+ pile_->tiling_rect().size().ToString());
}
layer_impl->SetIsMask(is_mask_);
+
// Unlike other properties, invalidation must always be set on layer_impl.
// See PictureLayerImpl::PushPropertiesTo for more details.
layer_impl->invalidation_.Clear();
@@ -63,7 +68,6 @@ void PictureLayer::SetLayerTreeHost(LayerTreeHost* host) {
if (host) {
pile_->SetMinContentsScale(host->settings().minimum_contents_scale);
pile_->SetTileGridSize(host->settings().default_tile_size);
- pile_->set_num_raster_threads(host->settings().num_raster_threads);
pile_->set_slow_down_raster_scale_factor(
host->debug_state().slow_down_raster_scale_factor);
pile_->set_show_debug_picture_borders(
@@ -82,13 +86,19 @@ void PictureLayer::SetNeedsDisplayRect(const gfx::RectF& layer_rect) {
}
bool PictureLayer::Update(ResourceUpdateQueue* queue,
- const OcclusionTracker* occlusion) {
+ const OcclusionTracker<Layer>* occlusion) {
update_source_frame_number_ = layer_tree_host()->source_frame_number();
bool updated = Layer::Update(queue, occlusion);
+ UpdateCanUseLCDText();
+
+ gfx::Rect visible_layer_rect = gfx::ScaleToEnclosingRect(
+ visible_content_rect(), 1.f / contents_scale_x());
+
+ gfx::Rect layer_rect = gfx::Rect(paint_properties().bounds);
+
if (last_updated_visible_content_rect_ == visible_content_rect() &&
- pile_->size() == paint_properties().bounds &&
- pending_invalidation_.IsEmpty()) {
+ pile_->tiling_rect() == layer_rect && pending_invalidation_.IsEmpty()) {
// Only early out if the visible content rect of this layer hasn't changed.
return updated;
}
@@ -96,28 +106,37 @@ bool PictureLayer::Update(ResourceUpdateQueue* queue,
TRACE_EVENT1("cc", "PictureLayer::Update",
"source_frame_number",
layer_tree_host()->source_frame_number());
+ devtools_instrumentation::ScopedLayerTreeTask update_layer(
+ devtools_instrumentation::kUpdateLayer, id(), layer_tree_host()->id());
- pile_->Resize(paint_properties().bounds);
+ pile_->SetTilingRect(layer_rect);
// Calling paint in WebKit can sometimes cause invalidations, so save
// off the invalidation prior to calling update.
pending_invalidation_.Swap(&pile_invalidation_);
pending_invalidation_.Clear();
- gfx::Rect visible_layer_rect = gfx::ScaleToEnclosingRect(
- visible_content_rect(), 1.f / contents_scale_x());
- if (layer_tree_host()->settings().using_synchronous_renderer_compositor) {
+ if (layer_tree_host()->settings().record_full_layer) {
// Workaround for http://crbug.com/235910 - to retain backwards compat
// the full page content must always be provided in the picture layer.
visible_layer_rect = gfx::Rect(bounds());
}
- updated |= pile_->Update(client_,
- SafeOpaqueBackgroundColor(),
- contents_opaque(),
- pile_invalidation_,
- visible_layer_rect,
- update_source_frame_number_,
- rendering_stats_instrumentation());
+
+ // UpdateAndExpandInvalidation will give us an invalidation that covers
+ // anything not explicitly recorded in this frame. We give this region
+ // to the impl side so that it drops tiles that may not have a recording
+ // for them.
+ DCHECK(client_);
+ updated |=
+ pile_->UpdateAndExpandInvalidation(client_,
+ &pile_invalidation_,
+ SafeOpaqueBackgroundColor(),
+ contents_opaque(),
+ client_->FillsBoundsCompletely(),
+ visible_layer_rect,
+ update_source_frame_number_,
+ RecordingMode(),
+ rendering_stats_instrumentation());
last_updated_visible_content_rect_ = visible_content_rect();
if (updated) {
@@ -135,10 +154,30 @@ void PictureLayer::SetIsMask(bool is_mask) {
is_mask_ = is_mask;
}
+Picture::RecordingMode PictureLayer::RecordingMode() const {
+ switch (layer_tree_host()->settings().recording_mode) {
+ case LayerTreeSettings::RecordNormally:
+ return Picture::RECORD_NORMALLY;
+ case LayerTreeSettings::RecordWithSkRecord:
+ return Picture::RECORD_WITH_SKRECORD;
+ }
+ NOTREACHED();
+ return Picture::RECORD_NORMALLY;
+}
+
bool PictureLayer::SupportsLCDText() const {
return true;
}
+void PictureLayer::UpdateCanUseLCDText() {
+ if (can_use_lcd_text_last_frame_ == can_use_lcd_text())
+ return;
+
+ can_use_lcd_text_last_frame_ = can_use_lcd_text();
+ if (client_)
+ client_->DidChangeLayerCanUseLCDText();
+}
+
skia::RefPtr<SkPicture> PictureLayer::GetPicture() const {
// We could either flatten the PicturePile into a single SkPicture,
// or paint a fresh one depending on what we intend to do with the
@@ -150,13 +189,20 @@ skia::RefPtr<SkPicture> PictureLayer::GetPicture() const {
int height = bounds().height();
gfx::RectF opaque;
- skia::RefPtr<SkPicture> picture = skia::AdoptRef(new SkPicture);
- SkCanvas* canvas = picture->beginRecording(width, height);
- client_->PaintContents(canvas, gfx::Rect(width, height), &opaque);
- picture->endRecording();
+ SkPictureRecorder recorder;
+ SkCanvas* canvas = recorder.beginRecording(width, height, NULL, 0);
+ client_->PaintContents(canvas,
+ gfx::Rect(width, height),
+ &opaque,
+ ContentLayerClient::GRAPHICS_CONTEXT_ENABLED);
+ skia::RefPtr<SkPicture> picture = skia::AdoptRef(recorder.endRecording());
return picture;
}
+bool PictureLayer::IsSuitableForGpuRasterization() const {
+ return pile_->is_suitable_for_gpu_rasterization();
+}
+
void PictureLayer::RunMicroBenchmark(MicroBenchmark* benchmark) {
benchmark->RunOnLayer(this);
}
diff --git a/chromium/cc/layers/picture_layer.h b/chromium/cc/layers/picture_layer.h
index d986a9bfbbc..406ffad2f17 100644
--- a/chromium/cc/layers/picture_layer.h
+++ b/chromium/cc/layers/picture_layer.h
@@ -30,21 +30,27 @@ class CC_EXPORT PictureLayer : public Layer {
virtual void SetLayerTreeHost(LayerTreeHost* host) OVERRIDE;
virtual void PushPropertiesTo(LayerImpl* layer) OVERRIDE;
virtual void SetNeedsDisplayRect(const gfx::RectF& layer_rect) OVERRIDE;
- virtual bool Update(
- ResourceUpdateQueue* queue,
- const OcclusionTracker* occlusion) OVERRIDE;
+ virtual bool Update(ResourceUpdateQueue* queue,
+ const OcclusionTracker<Layer>* occlusion) OVERRIDE;
virtual void SetIsMask(bool is_mask) OVERRIDE;
virtual bool SupportsLCDText() const OVERRIDE;
virtual skia::RefPtr<SkPicture> GetPicture() const OVERRIDE;
+ virtual bool IsSuitableForGpuRasterization() const OVERRIDE;
virtual void RunMicroBenchmark(MicroBenchmark* benchmark) OVERRIDE;
ContentLayerClient* client() { return client_; }
+ Picture::RecordingMode RecordingMode() const;
+
+ PicturePile* GetPicturePileForTesting() const { return pile_.get(); }
+
protected:
explicit PictureLayer(ContentLayerClient* client);
virtual ~PictureLayer();
+ void UpdateCanUseLCDText();
+
private:
ContentLayerClient* client_;
scoped_refptr<PicturePile> pile_;
@@ -58,6 +64,7 @@ class CC_EXPORT PictureLayer : public Layer {
bool is_mask_;
int update_source_frame_number_;
+ bool can_use_lcd_text_last_frame_;
DISALLOW_COPY_AND_ASSIGN(PictureLayer);
};
diff --git a/chromium/cc/layers/picture_layer_impl.cc b/chromium/cc/layers/picture_layer_impl.cc
index 2f5ca94ba15..8f6cf29a43b 100644
--- a/chromium/cc/layers/picture_layer_impl.cc
+++ b/chromium/cc/layers/picture_layer_impl.cc
@@ -31,8 +31,18 @@ const float kMaxScaleRatioDuringPinch = 2.0f;
// When creating a new tiling during pinch, snap to an existing
// tiling's scale if the desired scale is within this ratio.
-const float kSnapToExistingTilingRatio = 0.2f;
-}
+const float kSnapToExistingTilingRatio = 1.2f;
+
+// Estimate skewport 60 frames ahead for pre-rasterization on the CPU.
+const float kCpuSkewportTargetTimeInFrames = 60.0f;
+
+// Don't pre-rasterize on the GPU (except for kBackflingGuardDistancePixels in
+// TileManager::BinFromTilePriority).
+const float kGpuSkewportTargetTimeInFrames = 0.0f;
+
+// Minimum width/height of a layer that would require analysis for tiles.
+const int kMinDimensionsForAnalysis = 256;
+} // namespace
namespace cc {
@@ -40,7 +50,6 @@ PictureLayerImpl::PictureLayerImpl(LayerTreeImpl* tree_impl, int id)
: LayerImpl(tree_impl, id),
twin_layer_(NULL),
pile_(PicturePileImpl::Create()),
- last_content_scale_(0),
is_mask_(false),
ideal_page_scale_(0.f),
ideal_device_scale_(0.f),
@@ -51,12 +60,16 @@ PictureLayerImpl::PictureLayerImpl(LayerTreeImpl* tree_impl, int id)
raster_source_scale_(0.f),
raster_contents_scale_(0.f),
low_res_raster_contents_scale_(0.f),
- raster_source_scale_was_animating_(false),
- is_using_lcd_text_(tree_impl->settings().can_use_lcd_text),
+ raster_source_scale_is_fixed_(false),
+ was_screen_space_transform_animating_(false),
needs_post_commit_initialization_(true),
- should_update_tile_priorities_(false) {}
+ should_update_tile_priorities_(false) {
+ layer_tree_impl()->RegisterPictureLayerImpl(this);
+}
-PictureLayerImpl::~PictureLayerImpl() {}
+PictureLayerImpl::~PictureLayerImpl() {
+ layer_tree_impl()->UnregisterPictureLayerImpl(this);
+}
const char* PictureLayerImpl::LayerTypeAsString() const {
return "cc::PictureLayerImpl";
@@ -92,9 +105,13 @@ void PictureLayerImpl::PushPropertiesTo(LayerImpl* base_layer) {
layer_impl->SetIsMask(is_mask_);
layer_impl->pile_ = pile_;
- // Tilings would be expensive to push, so we swap. This optimization requires
- // an extra invalidation in SyncFromActiveLayer.
+ // Tilings would be expensive to push, so we swap.
layer_impl->tilings_.swap(tilings_);
+
+ // Ensure that we don't have any tiles that are out of date.
+ if (tilings_)
+ tilings_->RemoveTilesInRegion(invalidation_);
+
layer_impl->tilings_->SetClient(layer_impl);
if (tilings_)
tilings_->SetClient(this);
@@ -104,8 +121,6 @@ void PictureLayerImpl::PushPropertiesTo(LayerImpl* base_layer) {
layer_impl->raster_source_scale_ = raster_source_scale_;
layer_impl->raster_contents_scale_ = raster_contents_scale_;
layer_impl->low_res_raster_contents_scale_ = low_res_raster_contents_scale_;
-
- layer_impl->UpdateLCDTextStatus(is_using_lcd_text_);
layer_impl->needs_post_commit_initialization_ = false;
// The invalidation on this soon-to-be-recycled layer must be cleared to
@@ -114,20 +129,43 @@ void PictureLayerImpl::PushPropertiesTo(LayerImpl* base_layer) {
layer_impl->invalidation_.Swap(&invalidation_);
invalidation_.Clear();
needs_post_commit_initialization_ = true;
+
+ // We always need to push properties.
+ // See http://crbug.com/303943
+ needs_push_properties_ = true;
}
void PictureLayerImpl::AppendQuads(QuadSink* quad_sink,
AppendQuadsData* append_quads_data) {
DCHECK(!needs_post_commit_initialization_);
- gfx::Rect rect(visible_content_rect());
- gfx::Rect content_rect(content_bounds());
- SharedQuadState* shared_quad_state =
- quad_sink->UseSharedQuadState(CreateSharedQuadState());
+ float max_contents_scale = MaximumTilingContentsScale();
+ gfx::Transform scaled_draw_transform = draw_transform();
+ scaled_draw_transform.Scale(SK_MScalar1 / max_contents_scale,
+ SK_MScalar1 / max_contents_scale);
+ gfx::Size scaled_content_bounds =
+ gfx::ToCeiledSize(gfx::ScaleSize(content_bounds(), max_contents_scale));
+
+ gfx::Rect scaled_visible_content_rect =
+ gfx::ScaleToEnclosingRect(visible_content_rect(), max_contents_scale);
+ scaled_visible_content_rect.Intersect(gfx::Rect(scaled_content_bounds));
+
+ SharedQuadState* shared_quad_state = quad_sink->CreateSharedQuadState();
+ shared_quad_state->SetAll(scaled_draw_transform,
+ scaled_content_bounds,
+ scaled_visible_content_rect,
+ draw_properties().clip_rect,
+ draw_properties().is_clipped,
+ draw_properties().opacity,
+ blend_mode(),
+ sorting_context_id_);
+
+ gfx::Rect rect = scaled_visible_content_rect;
if (current_draw_mode_ == DRAW_MODE_RESOURCELESS_SOFTWARE) {
AppendDebugBorderQuad(
quad_sink,
+ scaled_content_bounds,
shared_quad_state,
append_quads_data,
DebugColors::DirectPictureBorderColor(),
@@ -135,31 +173,37 @@ void PictureLayerImpl::AppendQuads(QuadSink* quad_sink,
gfx::Rect geometry_rect = rect;
gfx::Rect opaque_rect = contents_opaque() ? geometry_rect : gfx::Rect();
+ gfx::Rect visible_geometry_rect =
+ quad_sink->UnoccludedContentRect(geometry_rect, scaled_draw_transform);
+ if (visible_geometry_rect.IsEmpty())
+ return;
+
gfx::Size texture_size = rect.size();
gfx::RectF texture_rect = gfx::RectF(texture_size);
gfx::Rect quad_content_rect = rect;
- float contents_scale = contents_scale_x();
scoped_ptr<PictureDrawQuad> quad = PictureDrawQuad::Create();
quad->SetNew(shared_quad_state,
geometry_rect,
opaque_rect,
+ visible_geometry_rect,
texture_rect,
texture_size,
RGBA_8888,
quad_content_rect,
- contents_scale,
+ max_contents_scale,
pile_);
- if (quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data))
- append_quads_data->num_missing_tiles++;
+ quad_sink->Append(quad.PassAs<DrawQuad>());
+ append_quads_data->num_missing_tiles++;
return;
}
- AppendDebugBorderQuad(quad_sink, shared_quad_state, append_quads_data);
+ AppendDebugBorderQuad(
+ quad_sink, scaled_content_bounds, shared_quad_state, append_quads_data);
if (ShowDebugBorders()) {
for (PictureLayerTilingSet::CoverageIterator iter(
- tilings_.get(), contents_scale_x(), rect, ideal_contents_scale_);
+ tilings_.get(), max_contents_scale, rect, ideal_contents_scale_);
iter;
++iter) {
SkColor color;
@@ -179,7 +223,7 @@ void PictureLayerImpl::AppendQuads(QuadSink* quad_sink,
} else if (iter->priority(ACTIVE_TREE).resolution == LOW_RESOLUTION) {
color = DebugColors::LowResTileBorderColor();
width = DebugColors::LowResTileBorderWidth(layer_tree_impl());
- } else if (iter->contents_scale() > contents_scale_x()) {
+ } else if (iter->contents_scale() > max_contents_scale) {
color = DebugColors::ExtraHighResTileBorderColor();
width = DebugColors::ExtraHighResTileBorderWidth(layer_tree_impl());
} else {
@@ -194,9 +238,13 @@ void PictureLayerImpl::AppendQuads(QuadSink* quad_sink,
scoped_ptr<DebugBorderDrawQuad> debug_border_quad =
DebugBorderDrawQuad::Create();
gfx::Rect geometry_rect = iter.geometry_rect();
- debug_border_quad->SetNew(shared_quad_state, geometry_rect, color, width);
- quad_sink->Append(debug_border_quad.PassAs<DrawQuad>(),
- append_quads_data);
+ gfx::Rect visible_geometry_rect = geometry_rect;
+ debug_border_quad->SetNew(shared_quad_state,
+ geometry_rect,
+ visible_geometry_rect,
+ color,
+ width);
+ quad_sink->Append(debug_border_quad.PassAs<DrawQuad>());
}
}
@@ -204,94 +252,136 @@ void PictureLayerImpl::AppendQuads(QuadSink* quad_sink,
// unused can be considered for removal.
std::vector<PictureLayerTiling*> seen_tilings;
+ size_t missing_tile_count = 0u;
+ size_t on_demand_missing_tile_count = 0u;
for (PictureLayerTilingSet::CoverageIterator iter(
- tilings_.get(), contents_scale_x(), rect, ideal_contents_scale_);
+ tilings_.get(), max_contents_scale, rect, ideal_contents_scale_);
iter;
++iter) {
gfx::Rect geometry_rect = iter.geometry_rect();
- if (!*iter || !iter->IsReadyToDraw()) {
- if (DrawCheckerboardForMissingTiles()) {
- // TODO(enne): Figure out how to show debug "invalidated checker" color
+ gfx::Rect visible_geometry_rect =
+ quad_sink->UnoccludedContentRect(geometry_rect, scaled_draw_transform);
+ if (visible_geometry_rect.IsEmpty())
+ continue;
+
+ append_quads_data->visible_content_area +=
+ visible_geometry_rect.width() * visible_geometry_rect.height();
+
+ scoped_ptr<DrawQuad> draw_quad;
+ if (*iter && iter->IsReadyToDraw()) {
+ const ManagedTileState::TileVersion& tile_version =
+ iter->GetTileVersionForDrawing();
+ switch (tile_version.mode()) {
+ case ManagedTileState::TileVersion::RESOURCE_MODE: {
+ gfx::RectF texture_rect = iter.texture_rect();
+ gfx::Rect opaque_rect = iter->opaque_rect();
+ opaque_rect.Intersect(geometry_rect);
+
+ if (iter->contents_scale() != ideal_contents_scale_)
+ append_quads_data->had_incomplete_tile = true;
+
+ scoped_ptr<TileDrawQuad> quad = TileDrawQuad::Create();
+ quad->SetNew(shared_quad_state,
+ geometry_rect,
+ opaque_rect,
+ visible_geometry_rect,
+ tile_version.get_resource_id(),
+ texture_rect,
+ iter.texture_size(),
+ tile_version.contents_swizzled());
+ draw_quad = quad.PassAs<DrawQuad>();
+ break;
+ }
+ case ManagedTileState::TileVersion::PICTURE_PILE_MODE: {
+ if (!layer_tree_impl()
+ ->GetRendererCapabilities()
+ .allow_rasterize_on_demand) {
+ ++on_demand_missing_tile_count;
+ break;
+ }
+
+ gfx::RectF texture_rect = iter.texture_rect();
+ gfx::Rect opaque_rect = iter->opaque_rect();
+ opaque_rect.Intersect(geometry_rect);
+
+ ResourceProvider* resource_provider =
+ layer_tree_impl()->resource_provider();
+ ResourceFormat format =
+ resource_provider->memory_efficient_texture_format();
+ scoped_ptr<PictureDrawQuad> quad = PictureDrawQuad::Create();
+ quad->SetNew(shared_quad_state,
+ geometry_rect,
+ opaque_rect,
+ visible_geometry_rect,
+ texture_rect,
+ iter.texture_size(),
+ format,
+ iter->content_rect(),
+ iter->contents_scale(),
+ pile_);
+ draw_quad = quad.PassAs<DrawQuad>();
+ break;
+ }
+ case ManagedTileState::TileVersion::SOLID_COLOR_MODE: {
+ scoped_ptr<SolidColorDrawQuad> quad = SolidColorDrawQuad::Create();
+ quad->SetNew(shared_quad_state,
+ geometry_rect,
+ visible_geometry_rect,
+ tile_version.get_solid_color(),
+ false);
+ draw_quad = quad.PassAs<DrawQuad>();
+ break;
+ }
+ }
+ }
+
+ if (!draw_quad) {
+ if (draw_checkerboard_for_missing_tiles()) {
scoped_ptr<CheckerboardDrawQuad> quad = CheckerboardDrawQuad::Create();
SkColor color = DebugColors::DefaultCheckerboardColor();
- quad->SetNew(shared_quad_state, geometry_rect, color);
- if (quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data))
- append_quads_data->num_missing_tiles++;
+ quad->SetNew(
+ shared_quad_state, geometry_rect, visible_geometry_rect, color);
+ quad_sink->Append(quad.PassAs<DrawQuad>());
} else {
SkColor color = SafeOpaqueBackgroundColor();
scoped_ptr<SolidColorDrawQuad> quad = SolidColorDrawQuad::Create();
- quad->SetNew(shared_quad_state, geometry_rect, color, false);
- if (quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data))
- append_quads_data->num_missing_tiles++;
+ quad->SetNew(shared_quad_state,
+ geometry_rect,
+ visible_geometry_rect,
+ color,
+ false);
+ quad_sink->Append(quad.PassAs<DrawQuad>());
}
+ append_quads_data->num_missing_tiles++;
append_quads_data->had_incomplete_tile = true;
+ append_quads_data->approximated_visible_content_area +=
+ visible_geometry_rect.width() * visible_geometry_rect.height();
+ ++missing_tile_count;
continue;
}
- const ManagedTileState::TileVersion& tile_version =
- iter->GetTileVersionForDrawing();
- scoped_ptr<DrawQuad> draw_quad;
- switch (tile_version.mode()) {
- case ManagedTileState::TileVersion::RESOURCE_MODE: {
- gfx::RectF texture_rect = iter.texture_rect();
- gfx::Rect opaque_rect = iter->opaque_rect();
- opaque_rect.Intersect(geometry_rect);
-
- if (iter->contents_scale() != ideal_contents_scale_)
- append_quads_data->had_incomplete_tile = true;
+ quad_sink->Append(draw_quad.Pass());
- scoped_ptr<TileDrawQuad> quad = TileDrawQuad::Create();
- quad->SetNew(shared_quad_state,
- geometry_rect,
- opaque_rect,
- tile_version.get_resource_id(),
- texture_rect,
- iter.texture_size(),
- tile_version.contents_swizzled());
- draw_quad = quad.PassAs<DrawQuad>();
- break;
- }
- case ManagedTileState::TileVersion::PICTURE_PILE_MODE: {
- gfx::RectF texture_rect = iter.texture_rect();
- gfx::Rect opaque_rect = iter->opaque_rect();
- opaque_rect.Intersect(geometry_rect);
-
- ResourceProvider* resource_provider =
- layer_tree_impl()->resource_provider();
- ResourceFormat format =
- resource_provider->memory_efficient_texture_format();
- scoped_ptr<PictureDrawQuad> quad = PictureDrawQuad::Create();
- quad->SetNew(shared_quad_state,
- geometry_rect,
- opaque_rect,
- texture_rect,
- iter.texture_size(),
- format,
- iter->content_rect(),
- iter->contents_scale(),
- pile_);
- draw_quad = quad.PassAs<DrawQuad>();
- break;
- }
- case ManagedTileState::TileVersion::SOLID_COLOR_MODE: {
- scoped_ptr<SolidColorDrawQuad> quad = SolidColorDrawQuad::Create();
- quad->SetNew(shared_quad_state,
- geometry_rect,
- tile_version.get_solid_color(),
- false);
- draw_quad = quad.PassAs<DrawQuad>();
- break;
- }
+ if (iter->priority(ACTIVE_TREE).resolution != HIGH_RESOLUTION) {
+ append_quads_data->approximated_visible_content_area +=
+ visible_geometry_rect.width() * visible_geometry_rect.height();
}
- DCHECK(draw_quad);
- quad_sink->Append(draw_quad.Pass(), append_quads_data);
-
if (seen_tilings.empty() || seen_tilings.back() != iter.CurrentTiling())
seen_tilings.push_back(iter.CurrentTiling());
}
+ if (missing_tile_count) {
+ TRACE_EVENT_INSTANT2("cc",
+ "PictureLayerImpl::AppendQuads checkerboard",
+ TRACE_EVENT_SCOPE_THREAD,
+ "missing_tile_count",
+ missing_tile_count,
+ "on_demand_missing_tile_count",
+ on_demand_missing_tile_count);
+ }
+
// Aggressively remove any tilings that are not seen to save memory. Note
// that this is at the expense of doing cause more frequent re-painting. A
// better scheme would be to maintain a tighter visible_content_rect for the
@@ -299,18 +389,56 @@ void PictureLayerImpl::AppendQuads(QuadSink* quad_sink,
CleanUpTilingsOnActiveLayer(seen_tilings);
}
-void PictureLayerImpl::UpdateTilePriorities() {
- DCHECK(!needs_post_commit_initialization_);
- CHECK(should_update_tile_priorities_);
+void PictureLayerImpl::UpdateTiles() {
+ TRACE_EVENT0("cc", "PictureLayerImpl::UpdateTiles");
- if (!layer_tree_impl()->device_viewport_valid_for_tile_management()) {
- for (size_t i = 0; i < tilings_->num_tilings(); ++i)
- DCHECK(tilings_->tiling_at(i)->has_ever_been_updated());
- return;
+ DoPostCommitInitializationIfNeeded();
+
+ if (layer_tree_impl()->device_viewport_valid_for_tile_management()) {
+ visible_rect_for_tile_priority_ = visible_content_rect();
+ viewport_size_for_tile_priority_ = layer_tree_impl()->DrawViewportSize();
+ screen_space_transform_for_tile_priority_ = screen_space_transform();
}
- if (!tilings_->num_tilings())
+ if (!CanHaveTilings()) {
+ ideal_page_scale_ = 0.f;
+ ideal_device_scale_ = 0.f;
+ ideal_contents_scale_ = 0.f;
+ ideal_source_scale_ = 0.f;
+ SanityCheckTilingState();
return;
+ }
+
+ UpdateIdealScales();
+
+ DCHECK(tilings_->num_tilings() > 0 || raster_contents_scale_ == 0.f)
+ << "A layer with no tilings shouldn't have valid raster scales";
+ if (!raster_contents_scale_ || ShouldAdjustRasterScale()) {
+ RecalculateRasterScales();
+ AddTilingsForRasterScale();
+ }
+
+ DCHECK(raster_page_scale_);
+ DCHECK(raster_device_scale_);
+ DCHECK(raster_source_scale_);
+ DCHECK(raster_contents_scale_);
+ DCHECK(low_res_raster_contents_scale_);
+
+ was_screen_space_transform_animating_ =
+ draw_properties().screen_space_transform_is_animating;
+
+ // TODO(sohanjg): Avoid needlessly update priorities when syncing to a
+ // non-updated tree which will then be updated immediately afterwards.
+ should_update_tile_priorities_ = true;
+
+ UpdateTilePriorities();
+
+ if (layer_tree_impl()->IsPendingTree())
+ MarkVisibleResourcesAsRequired();
+}
+
+void PictureLayerImpl::UpdateTilePriorities() {
+ TRACE_EVENT0("cc", "PictureLayerImpl::UpdateTilePriorities");
double current_frame_time_in_seconds =
(layer_tree_impl()->CurrentFrameTimeTicks() -
@@ -327,48 +455,45 @@ void PictureLayerImpl::UpdateTilePriorities() {
if (!tiling_needs_update)
return;
- UpdateLCDTextStatus(can_use_lcd_text());
-
- gfx::Transform current_screen_space_transform = screen_space_transform();
-
- gfx::Size viewport_size = layer_tree_impl()->DrawViewportSize();
- gfx::Rect viewport_in_content_space;
- gfx::Transform screen_to_layer(gfx::Transform::kSkipInitialization);
- if (screen_space_transform().GetInverse(&screen_to_layer)) {
- viewport_in_content_space =
- gfx::ToEnclosingRect(MathUtil::ProjectClippedRect(
- screen_to_layer, gfx::Rect(viewport_size)));
+ // Use visible_content_rect, unless it's empty. If it's empty, then
+ // try to inverse project the viewport into layer space and use that.
+ gfx::Rect visible_rect_in_content_space = visible_rect_for_tile_priority_;
+ if (visible_rect_in_content_space.IsEmpty()) {
+ gfx::Transform screen_to_layer(gfx::Transform::kSkipInitialization);
+ if (screen_space_transform_for_tile_priority_.GetInverse(
+ &screen_to_layer)) {
+ visible_rect_in_content_space =
+ gfx::ToEnclosingRect(MathUtil::ProjectClippedRect(
+ screen_to_layer, gfx::Rect(viewport_size_for_tile_priority_)));
+ visible_rect_in_content_space.Intersect(gfx::Rect(content_bounds()));
+ }
}
+ gfx::Rect visible_layer_rect = gfx::ScaleToEnclosingRect(
+ visible_rect_in_content_space, 1.f / contents_scale_x());
WhichTree tree =
layer_tree_impl()->IsActiveTree() ? ACTIVE_TREE : PENDING_TREE;
- size_t max_tiles_for_interest_area =
- layer_tree_impl()->settings().max_tiles_for_interest_area;
- tilings_->UpdateTilePriorities(
- tree,
- viewport_size,
- viewport_in_content_space,
- visible_content_rect(),
- last_bounds_,
- bounds(),
- last_content_scale_,
- contents_scale_x(),
- last_screen_space_transform_,
- current_screen_space_transform,
- current_frame_time_in_seconds,
- max_tiles_for_interest_area);
-
- if (layer_tree_impl()->IsPendingTree())
- MarkVisibleResourcesAsRequired();
-
- last_screen_space_transform_ = current_screen_space_transform;
- last_bounds_ = bounds();
- last_content_scale_ = contents_scale_x();
+ for (size_t i = 0; i < tilings_->num_tilings(); ++i) {
+ // TODO(sohanjg): Passing MaximumContentsScale as layer contents scale
+ // in UpdateTilePriorities is wrong and should be ideal contents scale.
+ tilings_->tiling_at(i)->UpdateTilePriorities(tree,
+ visible_layer_rect,
+ MaximumTilingContentsScale(),
+ current_frame_time_in_seconds);
+ }
// Tile priorities were modified.
layer_tree_impl()->DidModifyTilePriorities();
}
+void PictureLayerImpl::NotifyTileStateChanged(const Tile* tile) {
+ if (layer_tree_impl()->IsActiveTree()) {
+ gfx::RectF layer_damage_rect =
+ gfx::ScaleRect(tile->content_rect(), 1.f / tile->contents_scale());
+ AddDamageRect(layer_damage_rect);
+ }
+}
+
void PictureLayerImpl::DidBecomeActive() {
LayerImpl::DidBecomeActive();
tilings_->DidBecomeActive();
@@ -379,100 +504,47 @@ void PictureLayerImpl::DidBeginTracing() {
pile_->DidBeginTracing();
}
-void PictureLayerImpl::DidLoseOutputSurface() {
+void PictureLayerImpl::ReleaseResources() {
if (tilings_)
RemoveAllTilings();
ResetRasterScale();
-}
-
-void PictureLayerImpl::CalculateContentsScale(
- float ideal_contents_scale,
- float device_scale_factor,
- float page_scale_factor,
- bool animating_transform_to_screen,
- float* contents_scale_x,
- float* contents_scale_y,
- gfx::Size* content_bounds) {
- DoPostCommitInitializationIfNeeded();
-
- // This function sets valid raster scales and manages tilings, so tile
- // priorities can now be updated.
- should_update_tile_priorities_ = true;
-
- if (!CanHaveTilings()) {
- ideal_page_scale_ = page_scale_factor;
- ideal_device_scale_ = device_scale_factor;
- ideal_contents_scale_ = ideal_contents_scale;
- ideal_source_scale_ =
- ideal_contents_scale_ / ideal_page_scale_ / ideal_device_scale_;
- *contents_scale_x = ideal_contents_scale_;
- *contents_scale_y = ideal_contents_scale_;
- *content_bounds = gfx::ToCeiledSize(gfx::ScaleSize(bounds(),
- ideal_contents_scale_,
- ideal_contents_scale_));
- return;
- }
-
- float min_contents_scale = MinimumContentsScale();
- DCHECK_GT(min_contents_scale, 0.f);
- float min_page_scale = layer_tree_impl()->min_page_scale_factor();
- DCHECK_GT(min_page_scale, 0.f);
- float min_device_scale = 1.f;
- float min_source_scale =
- min_contents_scale / min_page_scale / min_device_scale;
-
- float ideal_page_scale = page_scale_factor;
- float ideal_device_scale = device_scale_factor;
- float ideal_source_scale =
- ideal_contents_scale / ideal_page_scale / ideal_device_scale;
-
- ideal_contents_scale_ = std::max(ideal_contents_scale, min_contents_scale);
- ideal_page_scale_ = ideal_page_scale;
- ideal_device_scale_ = ideal_device_scale;
- ideal_source_scale_ = std::max(ideal_source_scale, min_source_scale);
- ManageTilings(animating_transform_to_screen);
-
- // The content scale and bounds for a PictureLayerImpl is somewhat fictitious.
- // There are (usually) several tilings at different scales. However, the
- // content bounds is the (integer!) space in which quads are generated.
- // In order to guarantee that we can fill this integer space with any set of
- // tilings (and then map back to floating point texture coordinates), the
- // contents scale must be at least as large as the largest of the tilings.
- float max_contents_scale = min_contents_scale;
- for (size_t i = 0; i < tilings_->num_tilings(); ++i) {
- const PictureLayerTiling* tiling = tilings_->tiling_at(i);
- max_contents_scale = std::max(max_contents_scale, tiling->contents_scale());
- }
-
- *contents_scale_x = max_contents_scale;
- *contents_scale_y = max_contents_scale;
- *content_bounds = gfx::ToCeiledSize(
- gfx::ScaleSize(bounds(), max_contents_scale, max_contents_scale));
+ // To avoid an edge case after lost context where the tree is up to date but
+ // the tilings have not been managed, request an update draw properties
+ // to force tilings to get managed.
+ layer_tree_impl()->set_needs_update_draw_properties();
}
skia::RefPtr<SkPicture> PictureLayerImpl::GetPicture() {
return pile_->GetFlattenedPicture();
}
-bool PictureLayerImpl::ShouldUseGPURasterization() const {
- // TODO(skaslev): Add a proper heuristic for hybrid (software or GPU)
- // tile rasterization. Currently, when --enable-gpu-rasterization is
- // set all tiles get GPU rasterized.
- return layer_tree_impl()->settings().gpu_rasterization;
-}
-
scoped_refptr<Tile> PictureLayerImpl::CreateTile(PictureLayerTiling* tiling,
- gfx::Rect content_rect) {
+ const gfx::Rect& content_rect) {
if (!pile_->CanRaster(tiling->contents_scale(), content_rect))
return scoped_refptr<Tile>();
int flags = 0;
- if (is_using_lcd_text_)
- flags |= Tile::USE_LCD_TEXT;
- if (ShouldUseGPURasterization())
- flags |= Tile::USE_GPU_RASTERIZATION;
+ // We analyze picture before rasterization to detect solid-color tiles.
+ // If the tile is detected as such there is no need to raster or upload.
+ // It is drawn directly as a solid-color quad saving memory, raster and upload
+ // cost. The analysis step is however expensive and may not be justified when
+ // doing gpu rasterization which runs on the compositor thread and where there
+ // is no upload.
+ // TODO(alokp): Revisit the decision to avoid analysis for gpu rasterization
+ // becuase it too can potentially benefit from memory savings.
+ if (!layer_tree_impl()->use_gpu_rasterization()) {
+ // Additionally, we do not want to do the analysis if the layer is too
+ // narrow, since more likely than not the tile would not be solid. Note that
+ // this last optimization is a heuristic that ensures that we don't spend
+ // too much time analyzing tiles on a multitude of small layers, as it is
+ // likely that these layers have some non-solid content.
+ int min_dimension = std::min(bounds().width(), bounds().height());
+ if (min_dimension >= kMinDimensionsForAnalysis)
+ flags |= Tile::USE_PICTURE_ANALYSIS;
+ }
+
return layer_tree_impl()->tile_manager()->CreateTile(
pile_.get(),
content_rect.size(),
@@ -494,7 +566,6 @@ const Region* PictureLayerImpl::GetInvalidation() {
const PictureLayerTiling* PictureLayerImpl::GetTwinTiling(
const PictureLayerTiling* tiling) const {
-
if (!twin_layer_)
return NULL;
for (size_t i = 0; i < twin_layer_->tilings_->num_tilings(); ++i)
@@ -504,8 +575,28 @@ const PictureLayerTiling* PictureLayerImpl::GetTwinTiling(
return NULL;
}
+size_t PictureLayerImpl::GetMaxTilesForInterestArea() const {
+ return layer_tree_impl()->settings().max_tiles_for_interest_area;
+}
+
+float PictureLayerImpl::GetSkewportTargetTimeInSeconds() const {
+ float skewport_target_time_in_frames =
+ layer_tree_impl()->use_gpu_rasterization()
+ ? kGpuSkewportTargetTimeInFrames
+ : kCpuSkewportTargetTimeInFrames;
+ return skewport_target_time_in_frames *
+ layer_tree_impl()->begin_impl_frame_interval().InSecondsF() *
+ layer_tree_impl()->settings().skewport_target_time_multiplier;
+}
+
+int PictureLayerImpl::GetSkewportExtrapolationLimitInContentPixels() const {
+ return layer_tree_impl()
+ ->settings()
+ .skewport_extrapolation_limit_in_content_pixels;
+}
+
gfx::Size PictureLayerImpl::CalculateTileSize(
- gfx::Size content_bounds) const {
+ const gfx::Size& content_bounds) const {
if (is_mask_) {
int max_size = layer_tree_impl()->MaxTextureSize();
return gfx::Size(
@@ -517,6 +608,13 @@ gfx::Size PictureLayerImpl::CalculateTileSize(
layer_tree_impl()->resource_provider()->max_texture_size();
gfx::Size default_tile_size = layer_tree_impl()->settings().default_tile_size;
+ if (layer_tree_impl()->use_gpu_rasterization()) {
+ // TODO(ernstm) crbug.com/365877: We need a unified way to override the
+ // default-tile-size.
+ default_tile_size =
+ gfx::Size(layer_tree_impl()->device_viewport_size().width(),
+ layer_tree_impl()->device_viewport_size().height() / 4);
+ }
default_tile_size.SetToMin(gfx::Size(max_texture_size, max_texture_size));
gfx::Size max_untiled_content_size =
@@ -537,10 +635,12 @@ gfx::Size PictureLayerImpl::CalculateTileSize(
// 500x500 max untiled size would get 500x12 tiles. Also do this
// if the layer is small.
if (any_dimension_one_tile || !any_dimension_too_large) {
- int width =
- std::min(max_untiled_content_size.width(), content_bounds.width());
- int height =
- std::min(max_untiled_content_size.height(), content_bounds.height());
+ int width = std::min(
+ std::max(max_untiled_content_size.width(), default_tile_size.width()),
+ content_bounds.width());
+ int height = std::min(
+ std::max(max_untiled_content_size.height(), default_tile_size.height()),
+ content_bounds.height());
// Round width and height up to the closest multiple of 64, or 56 if
// we should avoid power-of-two textures. This helps reduce the number
// of different textures sizes to help recycling, and also keeps all
@@ -557,11 +657,10 @@ gfx::Size PictureLayerImpl::CalculateTileSize(
}
void PictureLayerImpl::SyncFromActiveLayer(const PictureLayerImpl* other) {
+ TRACE_EVENT0("cc", "SyncFromActiveLayer");
DCHECK(!other->needs_post_commit_initialization_);
DCHECK(other->tilings_);
- UpdateLCDTextStatus(other->is_using_lcd_text_);
-
if (!DrawsContent()) {
RemoveAllTilings();
return;
@@ -573,43 +672,30 @@ void PictureLayerImpl::SyncFromActiveLayer(const PictureLayerImpl* other) {
raster_contents_scale_ = other->raster_contents_scale_;
low_res_raster_contents_scale_ = other->low_res_raster_contents_scale_;
- // Add synthetic invalidations for any recordings that were dropped. As
- // tiles are updated to point to this new pile, this will force the dropping
- // of tiles that can no longer be rastered. This is not ideal, but is a
- // trade-off for memory (use the same pile as much as possible, by switching
- // during DidBecomeActive) and for time (don't bother checking every tile
- // during activation to see if the new pile can still raster it).
- for (int x = 0; x < pile_->num_tiles_x(); ++x) {
- for (int y = 0; y < pile_->num_tiles_y(); ++y) {
- bool previously_had = other->pile_->HasRecordingAt(x, y);
- bool now_has = pile_->HasRecordingAt(x, y);
- if (now_has || !previously_had)
- continue;
- gfx::Rect layer_rect = pile_->tile_bounds(x, y);
- invalidation_.Union(layer_rect);
- }
- }
-
// Union in the other newly exposed regions as invalid.
Region difference_region = Region(gfx::Rect(bounds()));
difference_region.Subtract(gfx::Rect(other->bounds()));
invalidation_.Union(difference_region);
+ bool synced_high_res_tiling = false;
if (CanHaveTilings()) {
- // The recycle tree's tiling set is two frames out of date, so it needs to
- // have both this frame's invalidation and the previous frame's invalidation
- // (stored on the active layer).
- Region tiling_invalidation = other->invalidation_;
- tiling_invalidation.Union(invalidation_);
- tilings_->SyncTilings(*other->tilings_,
- bounds(),
- tiling_invalidation,
- MinimumContentsScale());
+ synced_high_res_tiling = tilings_->SyncTilings(
+ *other->tilings_, bounds(), invalidation_, MinimumContentsScale());
} else {
RemoveAllTilings();
}
- SanityCheckTilingState();
+ // If our MinimumContentsScale has changed to prevent the twin's high res
+ // tiling from being synced, we should reset the raster scale and let it be
+ // recalculated (1) again. This can happen if our bounds shrink to the point
+ // where min contents scale grows.
+ // (1) - TODO(vmpstr) Instead of hoping that this will be recalculated, we
+ // should refactor this code a little bit and actually recalculate this.
+ // However, this is a larger undertaking, so this will work for now.
+ if (!synced_high_res_tiling)
+ ResetRasterScale();
+ else
+ SanityCheckTilingState();
}
void PictureLayerImpl::SyncTiling(
@@ -623,8 +709,9 @@ void PictureLayerImpl::SyncTiling(
// need update draw properties, then its transforms are up to date and
// we can create tiles for this tiling immediately.
if (!layer_tree_impl()->needs_update_draw_properties() &&
- should_update_tile_priorities_)
+ should_update_tile_priorities_) {
UpdateTilePriorities();
+ }
}
void PictureLayerImpl::SetIsMask(bool is_mask) {
@@ -637,7 +724,7 @@ void PictureLayerImpl::SetIsMask(bool is_mask) {
ResourceProvider::ResourceId PictureLayerImpl::ContentsResourceId() const {
gfx::Rect content_rect(content_bounds());
- float scale = contents_scale_x();
+ float scale = MaximumTilingContentsScale();
PictureLayerTilingSet::CoverageIterator iter(
tilings_.get(), scale, content_rect, ideal_contents_scale_);
@@ -660,7 +747,6 @@ ResourceProvider::ResourceId PictureLayerImpl::ContentsResourceId() const {
void PictureLayerImpl::MarkVisibleResourcesAsRequired() const {
DCHECK(layer_tree_impl()->IsPendingTree());
- DCHECK(!layer_tree_impl()->needs_update_draw_properties());
DCHECK(ideal_contents_scale_);
DCHECK_GT(tilings_->num_tilings(), 0u);
@@ -668,6 +754,10 @@ void PictureLayerImpl::MarkVisibleResourcesAsRequired() const {
// be ready to draw in order to activate without flashing content from a
// higher res on the active tree to a lower res on the pending tree.
+ // First, early out for layers with no visible content.
+ if (visible_content_rect().IsEmpty())
+ return;
+
gfx::Rect rect(visible_content_rect());
float min_acceptable_scale =
@@ -714,12 +804,6 @@ void PictureLayerImpl::MarkVisibleResourcesAsRequired() const {
if (!*iter || !iter->IsReadyToDraw())
continue;
- // This iteration is over the visible content rect which is potentially
- // less conservative than projecting the viewport into the layer.
- // Ignore tiles that are know to be outside the viewport.
- if (iter->priority(PENDING_TREE).distance_to_visible_in_pixels != 0)
- continue;
-
missing_region.Subtract(iter.geometry_rect());
iter->MarkRequiredForActivation();
}
@@ -733,29 +817,29 @@ void PictureLayerImpl::MarkVisibleResourcesAsRequired() const {
const PictureLayerTiling* twin_high_res = NULL;
const PictureLayerTiling* twin_low_res = NULL;
- // As a simplification, only allow activating to skip twin tiles that the
- // active layer is also missing when both this layer and its twin have 2
- // tilings (high and low). This avoids having to iterate/track coverage of
- // non-ideal tilings during the last draw call on the active layer.
- if (high_res && low_res && tilings_->num_tilings() == 2 &&
- twin_layer_ && twin_layer_->tilings_->num_tilings() == 2) {
- twin_low_res = GetTwinTiling(low_res);
- if (twin_low_res)
- twin_high_res = GetTwinTiling(high_res);
- }
- // If this layer and its twin have different transforms, then don't compare
- // them and only allow activating to high res tiles, since tiles on each layer
- // will be in different places on screen.
- if (!twin_high_res || !twin_low_res ||
- draw_properties().screen_space_transform !=
- twin_layer_->draw_properties().screen_space_transform) {
- twin_high_res = NULL;
- twin_low_res = NULL;
- }
+ if (twin_layer_) {
+ // As a simplification, only allow activating to skip twin tiles that the
+ // active layer is also missing when both this layer and its twin have
+ // "simple" sets of tilings: only 2 tilings (high and low) or only 1 high
+ // res tiling. This avoids having to iterate/track coverage of non-ideal
+ // tilings during the last draw call on the active layer.
+ if (tilings_->num_tilings() <= 2 &&
+ twin_layer_->tilings_->num_tilings() <= tilings_->num_tilings()) {
+ twin_low_res = low_res ? GetTwinTiling(low_res) : NULL;
+ twin_high_res = high_res ? GetTwinTiling(high_res) : NULL;
+ }
- // TODO(enne): temporarily disable this optimization: http://crbug.com/335289
- twin_high_res = NULL;
- twin_low_res = NULL;
+ // If this layer and its twin have different transforms, then don't compare
+ // them and only allow activating to high res tiles, since tiles on each
+ // layer will be in different places on screen.
+ if (twin_layer_->layer_tree_impl()->RequiresHighResToDraw() ||
+ bounds() != twin_layer_->bounds() ||
+ draw_properties().screen_space_transform !=
+ twin_layer_->draw_properties().screen_space_transform) {
+ twin_high_res = NULL;
+ twin_low_res = NULL;
+ }
+ }
// As a second pass, mark as required any visible high res tiles not filled in
// by acceptable non-ideal tiles from the first pass.
@@ -764,9 +848,11 @@ void PictureLayerImpl::MarkVisibleResourcesAsRequired() const {
// As an optional third pass, if a high res tile was skipped because its
// twin was also missing, then fall back to mark low res tiles as required
// in case the active twin is substituting those for missing high res
- // content.
- MarkVisibleTilesAsRequired(
- low_res, twin_low_res, contents_scale_x(), rect, missing_region);
+ // content. Only suitable, when low res is enabled.
+ if (low_res) {
+ MarkVisibleTilesAsRequired(
+ low_res, twin_low_res, contents_scale_x(), rect, missing_region);
+ }
}
}
@@ -774,7 +860,7 @@ bool PictureLayerImpl::MarkVisibleTilesAsRequired(
PictureLayerTiling* tiling,
const PictureLayerTiling* optional_twin_tiling,
float contents_scale,
- gfx::Rect rect,
+ const gfx::Rect& rect,
const Region& missing_region) const {
bool twin_had_missing_tile = false;
for (PictureLayerTiling::CoverageIterator iter(tiling,
@@ -787,12 +873,6 @@ bool PictureLayerImpl::MarkVisibleTilesAsRequired(
if (!tile)
continue;
- // This iteration is over the visible content rect which is potentially
- // less conservative than projecting the viewport into the layer.
- // Ignore tiles that are know to be outside the viewport.
- if (tile->priority(PENDING_TREE).distance_to_visible_in_pixels != 0)
- continue;
-
// If the missing region doesn't cover it, this tile is fully
// covered by acceptable tiles at other scales.
if (!missing_region.Intersects(iter.geometry_rect()))
@@ -842,8 +922,7 @@ PictureLayerTiling* PictureLayerImpl::AddTiling(float contents_scale) {
PictureLayerTiling* tiling = tilings_->AddTiling(contents_scale);
- const Region& recorded = pile_->recorded_region();
- DCHECK(!recorded.IsEmpty());
+ DCHECK(pile_->HasRecordings());
if (twin_layer_)
twin_layer_->SyncTiling(tiling);
@@ -865,7 +944,8 @@ void PictureLayerImpl::RemoveTiling(float contents_scale) {
}
void PictureLayerImpl::RemoveAllTilings() {
- tilings_->RemoveAllTilings();
+ if (tilings_)
+ tilings_->RemoveAllTilings();
// If there are no tilings, then raster scales are no longer meaningful.
ResetRasterScale();
}
@@ -880,38 +960,7 @@ inline float PositiveRatio(float float1, float float2) {
} // namespace
-void PictureLayerImpl::ManageTilings(bool animating_transform_to_screen) {
- DCHECK(ideal_contents_scale_);
- DCHECK(ideal_page_scale_);
- DCHECK(ideal_device_scale_);
- DCHECK(ideal_source_scale_);
- DCHECK(CanHaveTilings());
- DCHECK(!needs_post_commit_initialization_);
-
- bool change_target_tiling =
- raster_page_scale_ == 0.f ||
- raster_device_scale_ == 0.f ||
- raster_source_scale_ == 0.f ||
- raster_contents_scale_ == 0.f ||
- low_res_raster_contents_scale_ == 0.f ||
- ShouldAdjustRasterScale(animating_transform_to_screen);
-
- if (tilings_->num_tilings() == 0) {
- DCHECK(change_target_tiling)
- << "A layer with no tilings shouldn't have valid raster scales";
- }
-
- // Store the value for the next time ShouldAdjustRasterScale is called.
- raster_source_scale_was_animating_ = animating_transform_to_screen;
-
- if (!change_target_tiling)
- return;
-
- if (!layer_tree_impl()->device_viewport_valid_for_tile_management())
- return;
-
- RecalculateRasterScales(animating_transform_to_screen);
-
+void PictureLayerImpl::AddTilingsForRasterScale() {
PictureLayerTiling* high_res = NULL;
PictureLayerTiling* low_res = NULL;
@@ -939,7 +988,8 @@ void PictureLayerImpl::ManageTilings(bool animating_transform_to_screen) {
// prevents wastefully creating a paired low res tiling for every new high res
// tiling during a pinch or a CSS animation.
bool is_pinching = layer_tree_impl()->PinchGestureActive();
- if (!is_pinching && !animating_transform_to_screen && !low_res &&
+ if (layer_tree_impl()->create_low_res_tiling() && !is_pinching &&
+ !draw_properties().screen_space_transform_is_animating && !low_res &&
low_res != high_res)
low_res = AddTiling(low_res_raster_contents_scale_);
@@ -955,14 +1005,9 @@ void PictureLayerImpl::ManageTilings(bool animating_transform_to_screen) {
SanityCheckTilingState();
}
-bool PictureLayerImpl::ShouldAdjustRasterScale(
- bool animating_transform_to_screen) const {
- // TODO(danakj): Adjust raster source scale closer to ideal source scale at
- // a throttled rate. Possibly make use of invalidation_.IsEmpty() on pending
- // tree. This will allow CSS scale changes to get re-rastered at an
- // appropriate rate.
-
- if (raster_source_scale_was_animating_ && !animating_transform_to_screen)
+bool PictureLayerImpl::ShouldAdjustRasterScale() const {
+ if (was_screen_space_transform_animating_ !=
+ draw_properties().screen_space_transform_is_animating)
return true;
bool is_pinching = layer_tree_impl()->PinchGestureActive();
@@ -986,6 +1031,13 @@ bool PictureLayerImpl::ShouldAdjustRasterScale(
if (raster_device_scale_ != ideal_device_scale_)
return true;
+ // When the source scale changes we want to match it, but not when animating
+ // or when we've fixed the scale in place.
+ if (!draw_properties().screen_space_transform_is_animating &&
+ !raster_source_scale_is_fixed_ &&
+ raster_source_scale_ != ideal_source_scale_)
+ return true;
+
return false;
}
@@ -1004,37 +1056,76 @@ float PictureLayerImpl::SnappedContentsScale(float scale) {
return snapped_contents_scale;
}
-void PictureLayerImpl::RecalculateRasterScales(
- bool animating_transform_to_screen) {
+void PictureLayerImpl::RecalculateRasterScales() {
+ float old_raster_contents_scale = raster_contents_scale_;
+ float old_raster_page_scale = raster_page_scale_;
+ float old_raster_source_scale = raster_source_scale_;
+
raster_device_scale_ = ideal_device_scale_;
+ raster_page_scale_ = ideal_page_scale_;
raster_source_scale_ = ideal_source_scale_;
+ raster_contents_scale_ = ideal_contents_scale_;
+
+ // If we're not animating, or leaving an animation, and the
+ // ideal_source_scale_ changes, then things are unpredictable, and we fix
+ // the raster_source_scale_ in place.
+ if (old_raster_source_scale &&
+ !draw_properties().screen_space_transform_is_animating &&
+ !was_screen_space_transform_animating_ &&
+ old_raster_source_scale != ideal_source_scale_)
+ raster_source_scale_is_fixed_ = true;
+
+ // TODO(danakj): Adjust raster source scale closer to ideal source scale at
+ // a throttled rate. Possibly make use of invalidation_.IsEmpty() on pending
+ // tree. This will allow CSS scale changes to get re-rastered at an
+ // appropriate rate.
+ if (raster_source_scale_is_fixed_) {
+ raster_contents_scale_ /= raster_source_scale_;
+ raster_source_scale_ = 1.f;
+ }
+ // During pinch we completely ignore the current ideal scale, and just use
+ // a multiple of the previous scale.
+ // TODO(danakj): This seems crazy, we should use the current ideal, no?
bool is_pinching = layer_tree_impl()->PinchGestureActive();
- if (!is_pinching || raster_contents_scale_ == 0.f) {
- // When not pinching or when we have no previous scale, we use ideal scale:
- raster_page_scale_ = ideal_page_scale_;
- raster_contents_scale_ = ideal_contents_scale_;
- } else {
+ if (is_pinching && old_raster_contents_scale) {
// See ShouldAdjustRasterScale:
// - When zooming out, preemptively create new tiling at lower resolution.
// - When zooming in, approximate ideal using multiple of kMaxScaleRatio.
- bool zooming_out = raster_page_scale_ > ideal_page_scale_;
+ bool zooming_out = old_raster_page_scale > ideal_page_scale_;
float desired_contents_scale =
- zooming_out ? raster_contents_scale_ / kMaxScaleRatioDuringPinch
- : raster_contents_scale_ * kMaxScaleRatioDuringPinch;
+ zooming_out ? old_raster_contents_scale / kMaxScaleRatioDuringPinch
+ : old_raster_contents_scale * kMaxScaleRatioDuringPinch;
raster_contents_scale_ = SnappedContentsScale(desired_contents_scale);
- raster_page_scale_ = raster_contents_scale_ / raster_device_scale_;
+ raster_page_scale_ =
+ raster_contents_scale_ / raster_device_scale_ / raster_source_scale_;
}
raster_contents_scale_ =
std::max(raster_contents_scale_, MinimumContentsScale());
- // Don't allow animating CSS scales to drop below 1. This is needed because
- // changes in raster source scale aren't handled. See the comment in
- // ShouldAdjustRasterScale.
- if (animating_transform_to_screen) {
- raster_contents_scale_ = std::max(
- raster_contents_scale_, 1.f * ideal_page_scale_ * ideal_device_scale_);
+ // Since we're not re-rasterizing during animation, rasterize at the maximum
+ // scale that will occur during the animation, if the maximum scale is
+ // known. However, to avoid excessive memory use, don't rasterize at a scale
+ // at which this layer would become larger than the viewport.
+ if (draw_properties().screen_space_transform_is_animating) {
+ bool can_raster_at_maximum_scale = false;
+ if (draw_properties().maximum_animation_contents_scale > 0.f) {
+ gfx::Size bounds_at_maximum_scale = gfx::ToCeiledSize(gfx::ScaleSize(
+ bounds(), draw_properties().maximum_animation_contents_scale));
+ if (bounds_at_maximum_scale.GetArea() <=
+ layer_tree_impl()->device_viewport_size().GetArea())
+ can_raster_at_maximum_scale = true;
+ }
+ if (can_raster_at_maximum_scale) {
+ raster_contents_scale_ =
+ std::max(raster_contents_scale_,
+ draw_properties().maximum_animation_contents_scale);
+ } else {
+ raster_contents_scale_ =
+ std::max(raster_contents_scale_,
+ 1.f * ideal_page_scale_ * ideal_device_scale_);
+ }
}
// If this layer would only create one tile at this content scale,
@@ -1065,15 +1156,22 @@ void PictureLayerImpl::CleanUpTilingsOnActiveLayer(
raster_contents_scale_, ideal_contents_scale_);
float max_acceptable_high_res_scale = std::max(
raster_contents_scale_, ideal_contents_scale_);
+ float twin_low_res_scale = 0.f;
PictureLayerImpl* twin = twin_layer_;
- if (twin) {
+ if (twin && twin->CanHaveTilings()) {
min_acceptable_high_res_scale = std::min(
min_acceptable_high_res_scale,
std::min(twin->raster_contents_scale_, twin->ideal_contents_scale_));
max_acceptable_high_res_scale = std::max(
max_acceptable_high_res_scale,
std::max(twin->raster_contents_scale_, twin->ideal_contents_scale_));
+
+ for (size_t i = 0; i < twin->tilings_->num_tilings(); ++i) {
+ PictureLayerTiling* tiling = twin->tilings_->tiling_at(i);
+ if (tiling->resolution() == LOW_RESOLUTION)
+ twin_low_res_scale = tiling->contents_scale();
+ }
}
std::vector<PictureLayerTiling*> to_remove;
@@ -1086,9 +1184,12 @@ void PictureLayerImpl::CleanUpTilingsOnActiveLayer(
tiling->contents_scale() <= max_acceptable_high_res_scale)
continue;
- // Low resolution can't activate, so only keep one around.
- if (tiling->resolution() == LOW_RESOLUTION)
- continue;
+ // Keep low resolution tilings, if the layer should have them.
+ if (layer_tree_impl()->create_low_res_tiling()) {
+ if (tiling->resolution() == LOW_RESOLUTION ||
+ tiling->contents_scale() == twin_low_res_scale)
+ continue;
+ }
// Don't remove tilings that are being used (and thus would cause a flash.)
if (std::find(used_tilings.begin(), used_tilings.end(), tiling) !=
@@ -1104,6 +1205,8 @@ void PictureLayerImpl::CleanUpTilingsOnActiveLayer(
// NON_IDEAL_RESOLUTION.
if (twin_tiling && twin_tiling->resolution() == NON_IDEAL_RESOLUTION)
twin->RemoveTiling(to_remove[i]->contents_scale());
+ // TODO(enne): temporary sanity CHECK for http://crbug.com/358350
+ CHECK_NE(HIGH_RESOLUTION, to_remove[i]->resolution());
tilings_->Remove(to_remove[i]);
}
DCHECK_GT(tilings_->num_tilings(), 0u);
@@ -1125,24 +1228,13 @@ float PictureLayerImpl::MinimumContentsScale() const {
return std::max(1.f / min_dimension, setting_min);
}
-void PictureLayerImpl::UpdateLCDTextStatus(bool new_status) {
- // Once this layer is not using lcd text, don't switch back.
- if (!is_using_lcd_text_)
- return;
-
- if (is_using_lcd_text_ == new_status)
- return;
-
- is_using_lcd_text_ = new_status;
- tilings_->SetCanUseLCDText(is_using_lcd_text_);
-}
-
void PictureLayerImpl::ResetRasterScale() {
raster_page_scale_ = 0.f;
raster_device_scale_ = 0.f;
raster_source_scale_ = 0.f;
raster_contents_scale_ = 0.f;
low_res_raster_contents_scale_ = 0.f;
+ raster_source_scale_is_fixed_ = false;
// When raster scales aren't valid, don't update tile priorities until
// this layer has been updated via UpdateDrawProperties.
@@ -1152,7 +1244,7 @@ void PictureLayerImpl::ResetRasterScale() {
bool PictureLayerImpl::CanHaveTilings() const {
if (!DrawsContent())
return false;
- if (pile_->recorded_region().IsEmpty())
+ if (!pile_->HasRecordings())
return false;
return true;
}
@@ -1166,9 +1258,7 @@ bool PictureLayerImpl::CanHaveTilingWithScale(float contents_scale) const {
}
void PictureLayerImpl::SanityCheckTilingState() const {
- if (!DCHECK_IS_ON())
- return;
-
+#if DCHECK_IS_ON
if (!CanHaveTilings()) {
DCHECK_EQ(0u, tilings_->num_tilings());
return;
@@ -1179,6 +1269,38 @@ void PictureLayerImpl::SanityCheckTilingState() const {
// MarkVisibleResourcesAsRequired depends on having exactly 1 high res
// tiling to mark its tiles as being required for activation.
DCHECK_EQ(1, tilings_->NumHighResTilings());
+#endif
+}
+
+float PictureLayerImpl::MaximumTilingContentsScale() const {
+ float max_contents_scale = MinimumContentsScale();
+ for (size_t i = 0; i < tilings_->num_tilings(); ++i) {
+ const PictureLayerTiling* tiling = tilings_->tiling_at(i);
+ max_contents_scale = std::max(max_contents_scale, tiling->contents_scale());
+ }
+ return max_contents_scale;
+}
+
+void PictureLayerImpl::UpdateIdealScales() {
+ DCHECK(CanHaveTilings());
+
+ float min_contents_scale = MinimumContentsScale();
+ DCHECK_GT(min_contents_scale, 0.f);
+ float min_page_scale = layer_tree_impl()->min_page_scale_factor();
+ DCHECK_GT(min_page_scale, 0.f);
+ float min_device_scale = 1.f;
+ float min_source_scale =
+ min_contents_scale / min_page_scale / min_device_scale;
+
+ float ideal_page_scale = draw_properties().page_scale_factor;
+ float ideal_device_scale = draw_properties().device_scale_factor;
+ float ideal_source_scale = draw_properties().ideal_contents_scale /
+ ideal_page_scale / ideal_device_scale;
+ ideal_contents_scale_ =
+ std::max(draw_properties().ideal_contents_scale, min_contents_scale);
+ ideal_page_scale_ = draw_properties().page_scale_factor;
+ ideal_device_scale_ = draw_properties().device_scale_factor;
+ ideal_source_scale_ = std::max(ideal_source_scale, min_source_scale);
}
void PictureLayerImpl::GetDebugBorderProperties(
@@ -1192,16 +1314,11 @@ void PictureLayerImpl::AsValueInto(base::DictionaryValue* state) const {
const_cast<PictureLayerImpl*>(this)->DoPostCommitInitializationIfNeeded();
LayerImpl::AsValueInto(state);
state->SetDouble("ideal_contents_scale", ideal_contents_scale_);
- state->SetDouble("geometry_contents_scale", contents_scale_x());
+ state->SetDouble("geometry_contents_scale", MaximumTilingContentsScale());
state->Set("tilings", tilings_->AsValue().release());
state->Set("pictures", pile_->AsValue().release());
state->Set("invalidation", invalidation_.AsValue().release());
- Region unrecorded_region(gfx::Rect(pile_->size()));
- unrecorded_region.Subtract(pile_->recorded_region());
- if (!unrecorded_region.IsEmpty())
- state->Set("unrecorded_region", unrecorded_region.AsValue().release());
-
scoped_ptr<base::ListValue> coverage_tiles(new base::ListValue);
for (PictureLayerTilingSet::CoverageIterator iter(tilings_.get(),
contents_scale_x(),
@@ -1218,7 +1335,6 @@ void PictureLayerImpl::AsValueInto(base::DictionaryValue* state) const {
coverage_tiles->Append(tile_data.release());
}
state->Set("coverage_tiles", coverage_tiles.release());
- state->SetBoolean("is_using_lcd_text", is_using_lcd_text_);
}
size_t PictureLayerImpl::GPUMemoryUsageInBytes() const {
@@ -1230,4 +1346,288 @@ void PictureLayerImpl::RunMicroBenchmark(MicroBenchmarkImpl* benchmark) {
benchmark->RunOnLayer(this);
}
+WhichTree PictureLayerImpl::GetTree() const {
+ return layer_tree_impl()->IsActiveTree() ? ACTIVE_TREE : PENDING_TREE;
+}
+
+bool PictureLayerImpl::IsOnActiveOrPendingTree() const {
+ return !layer_tree_impl()->IsRecycleTree();
+}
+
+bool PictureLayerImpl::HasValidTilePriorities() const {
+ return IsOnActiveOrPendingTree() && IsDrawnRenderSurfaceLayerListMember();
+}
+
+bool PictureLayerImpl::AllTilesRequiredForActivationAreReadyToDraw() const {
+ if (!layer_tree_impl()->IsPendingTree())
+ return true;
+
+ if (!HasValidTilePriorities())
+ return true;
+
+ if (!tilings_)
+ return true;
+
+ if (visible_content_rect().IsEmpty())
+ return true;
+
+ for (size_t i = 0; i < tilings_->num_tilings(); ++i) {
+ PictureLayerTiling* tiling = tilings_->tiling_at(i);
+ if (tiling->resolution() != HIGH_RESOLUTION &&
+ tiling->resolution() != LOW_RESOLUTION)
+ continue;
+
+ gfx::Rect rect(visible_content_rect());
+ for (PictureLayerTiling::CoverageIterator iter(
+ tiling, contents_scale_x(), rect);
+ iter;
+ ++iter) {
+ const Tile* tile = *iter;
+ // A null tile (i.e. missing recording) can just be skipped.
+ if (!tile)
+ continue;
+
+ if (tile->required_for_activation() && !tile->IsReadyToDraw())
+ return false;
+ }
+ }
+
+ return true;
+}
+
+PictureLayerImpl::LayerRasterTileIterator::LayerRasterTileIterator()
+ : layer_(NULL) {}
+
+PictureLayerImpl::LayerRasterTileIterator::LayerRasterTileIterator(
+ PictureLayerImpl* layer,
+ bool prioritize_low_res)
+ : layer_(layer), current_stage_(0) {
+ DCHECK(layer_);
+
+ // Early out if the layer has no tilings.
+ if (!layer_->tilings_ || !layer_->tilings_->num_tilings()) {
+ current_stage_ = arraysize(stages_);
+ return;
+ }
+
+ // Tiles without valid priority are treated as having lowest priority and
+ // never considered for raster.
+ if (!layer_->HasValidTilePriorities()) {
+ current_stage_ = arraysize(stages_);
+ return;
+ }
+
+ WhichTree tree =
+ layer_->layer_tree_impl()->IsActiveTree() ? ACTIVE_TREE : PENDING_TREE;
+
+ // Find high and low res tilings and initialize the iterators.
+ for (size_t i = 0; i < layer_->tilings_->num_tilings(); ++i) {
+ PictureLayerTiling* tiling = layer_->tilings_->tiling_at(i);
+ if (tiling->resolution() == HIGH_RESOLUTION) {
+ iterators_[HIGH_RES] =
+ PictureLayerTiling::TilingRasterTileIterator(tiling, tree);
+ }
+
+ if (tiling->resolution() == LOW_RESOLUTION) {
+ iterators_[LOW_RES] =
+ PictureLayerTiling::TilingRasterTileIterator(tiling, tree);
+ }
+ }
+
+ if (prioritize_low_res) {
+ stages_[0].iterator_type = LOW_RES;
+ stages_[0].tile_type = TilePriority::NOW;
+
+ stages_[1].iterator_type = HIGH_RES;
+ stages_[1].tile_type = TilePriority::NOW;
+ } else {
+ stages_[0].iterator_type = HIGH_RES;
+ stages_[0].tile_type = TilePriority::NOW;
+
+ stages_[1].iterator_type = LOW_RES;
+ stages_[1].tile_type = TilePriority::NOW;
+ }
+
+ stages_[2].iterator_type = HIGH_RES;
+ stages_[2].tile_type = TilePriority::SOON;
+
+ stages_[3].iterator_type = HIGH_RES;
+ stages_[3].tile_type = TilePriority::EVENTUALLY;
+
+ IteratorType index = stages_[current_stage_].iterator_type;
+ TilePriority::PriorityBin tile_type = stages_[current_stage_].tile_type;
+ if (!iterators_[index] || iterators_[index].get_type() != tile_type)
+ ++(*this);
+}
+
+PictureLayerImpl::LayerRasterTileIterator::~LayerRasterTileIterator() {}
+
+PictureLayerImpl::LayerRasterTileIterator::operator bool() const {
+ return layer_ && static_cast<size_t>(current_stage_) < arraysize(stages_);
+}
+
+PictureLayerImpl::LayerRasterTileIterator&
+PictureLayerImpl::LayerRasterTileIterator::
+operator++() {
+ IteratorType index = stages_[current_stage_].iterator_type;
+ TilePriority::PriorityBin tile_type = stages_[current_stage_].tile_type;
+
+ // First advance the iterator.
+ if (iterators_[index])
+ ++iterators_[index];
+
+ if (iterators_[index] && iterators_[index].get_type() == tile_type)
+ return *this;
+
+ // Next, advance the stage.
+ int stage_count = arraysize(stages_);
+ ++current_stage_;
+ while (current_stage_ < stage_count) {
+ index = stages_[current_stage_].iterator_type;
+ tile_type = stages_[current_stage_].tile_type;
+
+ if (iterators_[index] && iterators_[index].get_type() == tile_type)
+ break;
+ ++current_stage_;
+ }
+ return *this;
+}
+
+Tile* PictureLayerImpl::LayerRasterTileIterator::operator*() {
+ DCHECK(*this);
+
+ IteratorType index = stages_[current_stage_].iterator_type;
+ DCHECK(iterators_[index]);
+ DCHECK(iterators_[index].get_type() == stages_[current_stage_].tile_type);
+
+ return *iterators_[index];
+}
+
+PictureLayerImpl::LayerEvictionTileIterator::LayerEvictionTileIterator()
+ : iterator_index_(0),
+ iteration_stage_(TilePriority::EVENTUALLY),
+ required_for_activation_(false),
+ layer_(NULL) {}
+
+PictureLayerImpl::LayerEvictionTileIterator::LayerEvictionTileIterator(
+ PictureLayerImpl* layer,
+ TreePriority tree_priority)
+ : iterator_index_(0),
+ iteration_stage_(TilePriority::EVENTUALLY),
+ required_for_activation_(false),
+ layer_(layer) {
+ // Early out if the layer has no tilings.
+ // TODO(vmpstr): Once tile priorities are determined by the iterators, ensure
+ // that layers that don't have valid tile priorities have lowest priorities so
+ // they evict their tiles first (crbug.com/381704)
+ if (!layer_->tilings_ || !layer_->tilings_->num_tilings())
+ return;
+
+ size_t high_res_tiling_index = layer_->tilings_->num_tilings();
+ size_t low_res_tiling_index = layer_->tilings_->num_tilings();
+ for (size_t i = 0; i < layer_->tilings_->num_tilings(); ++i) {
+ PictureLayerTiling* tiling = layer_->tilings_->tiling_at(i);
+ if (tiling->resolution() == HIGH_RESOLUTION)
+ high_res_tiling_index = i;
+ else if (tiling->resolution() == LOW_RESOLUTION)
+ low_res_tiling_index = i;
+ }
+
+ iterators_.reserve(layer_->tilings_->num_tilings());
+
+ // Higher resolution non-ideal goes first.
+ for (size_t i = 0; i < high_res_tiling_index; ++i) {
+ iterators_.push_back(PictureLayerTiling::TilingEvictionTileIterator(
+ layer_->tilings_->tiling_at(i), tree_priority));
+ }
+
+ // Lower resolution non-ideal goes next.
+ for (size_t i = layer_->tilings_->num_tilings() - 1;
+ i > high_res_tiling_index;
+ --i) {
+ PictureLayerTiling* tiling = layer_->tilings_->tiling_at(i);
+ if (tiling->resolution() == LOW_RESOLUTION)
+ continue;
+
+ iterators_.push_back(
+ PictureLayerTiling::TilingEvictionTileIterator(tiling, tree_priority));
+ }
+
+ // Now, put the low res tiling if we have one.
+ if (low_res_tiling_index < layer_->tilings_->num_tilings()) {
+ iterators_.push_back(PictureLayerTiling::TilingEvictionTileIterator(
+ layer_->tilings_->tiling_at(low_res_tiling_index), tree_priority));
+ }
+
+ // Finally, put the high res tiling if we have one.
+ if (high_res_tiling_index < layer_->tilings_->num_tilings()) {
+ iterators_.push_back(PictureLayerTiling::TilingEvictionTileIterator(
+ layer_->tilings_->tiling_at(high_res_tiling_index), tree_priority));
+ }
+
+ DCHECK_GT(iterators_.size(), 0u);
+
+ if (!iterators_[iterator_index_] ||
+ !IsCorrectType(&iterators_[iterator_index_])) {
+ AdvanceToNextIterator();
+ }
+}
+
+PictureLayerImpl::LayerEvictionTileIterator::~LayerEvictionTileIterator() {}
+
+Tile* PictureLayerImpl::LayerEvictionTileIterator::operator*() {
+ DCHECK(*this);
+ return *iterators_[iterator_index_];
+}
+
+PictureLayerImpl::LayerEvictionTileIterator&
+PictureLayerImpl::LayerEvictionTileIterator::
+operator++() {
+ DCHECK(*this);
+ ++iterators_[iterator_index_];
+ if (!iterators_[iterator_index_] ||
+ !IsCorrectType(&iterators_[iterator_index_])) {
+ AdvanceToNextIterator();
+ }
+ return *this;
+}
+
+void PictureLayerImpl::LayerEvictionTileIterator::AdvanceToNextIterator() {
+ ++iterator_index_;
+
+ while (true) {
+ while (iterator_index_ < iterators_.size()) {
+ if (iterators_[iterator_index_] &&
+ IsCorrectType(&iterators_[iterator_index_])) {
+ return;
+ }
+ ++iterator_index_;
+ }
+
+ // If we're NOW and required_for_activation, then this was the last pass
+ // through the iterators.
+ if (iteration_stage_ == TilePriority::NOW && required_for_activation_)
+ break;
+
+ if (!required_for_activation_) {
+ required_for_activation_ = true;
+ } else {
+ required_for_activation_ = false;
+ iteration_stage_ =
+ static_cast<TilePriority::PriorityBin>(iteration_stage_ - 1);
+ }
+ iterator_index_ = 0;
+ }
+}
+
+PictureLayerImpl::LayerEvictionTileIterator::operator bool() const {
+ return iterator_index_ < iterators_.size();
+}
+
+bool PictureLayerImpl::LayerEvictionTileIterator::IsCorrectType(
+ PictureLayerTiling::TilingEvictionTileIterator* it) const {
+ return it->get_type() == iteration_stage_ &&
+ (**it)->required_for_activation() == required_for_activation_;
+}
+
} // namespace cc
diff --git a/chromium/cc/layers/picture_layer_impl.h b/chromium/cc/layers/picture_layer_impl.h
index ab6aad7138b..6b1703e4a6e 100644
--- a/chromium/cc/layers/picture_layer_impl.h
+++ b/chromium/cc/layers/picture_layer_impl.h
@@ -22,11 +22,63 @@ namespace cc {
struct AppendQuadsData;
class QuadSink;
class MicroBenchmarkImpl;
+class Tile;
class CC_EXPORT PictureLayerImpl
: public LayerImpl,
NON_EXPORTED_BASE(public PictureLayerTilingClient) {
public:
+ class CC_EXPORT LayerRasterTileIterator {
+ public:
+ LayerRasterTileIterator();
+ LayerRasterTileIterator(PictureLayerImpl* layer, bool prioritize_low_res);
+ ~LayerRasterTileIterator();
+
+ Tile* operator*();
+ LayerRasterTileIterator& operator++();
+ operator bool() const;
+
+ private:
+ enum IteratorType { LOW_RES, HIGH_RES, NUM_ITERATORS };
+
+ PictureLayerImpl* layer_;
+
+ struct IterationStage {
+ IteratorType iterator_type;
+ TilePriority::PriorityBin tile_type;
+ };
+
+ int current_stage_;
+
+ // One low res stage, and three high res stages.
+ IterationStage stages_[4];
+ PictureLayerTiling::TilingRasterTileIterator iterators_[NUM_ITERATORS];
+ };
+
+ class CC_EXPORT LayerEvictionTileIterator {
+ public:
+ LayerEvictionTileIterator();
+ LayerEvictionTileIterator(PictureLayerImpl* layer,
+ TreePriority tree_priority);
+ ~LayerEvictionTileIterator();
+
+ Tile* operator*();
+ LayerEvictionTileIterator& operator++();
+ operator bool() const;
+
+ private:
+ void AdvanceToNextIterator();
+ bool IsCorrectType(
+ PictureLayerTiling::TilingEvictionTileIterator* it) const;
+
+ std::vector<PictureLayerTiling::TilingEvictionTileIterator> iterators_;
+ size_t iterator_index_;
+ TilePriority::PriorityBin iteration_stage_;
+ bool required_for_activation_;
+
+ PictureLayerImpl* layer_;
+ };
+
static scoped_ptr<PictureLayerImpl> Create(LayerTreeImpl* tree_impl, int id) {
return make_scoped_ptr(new PictureLayerImpl(tree_impl, id));
}
@@ -39,28 +91,26 @@ class CC_EXPORT PictureLayerImpl
virtual void PushPropertiesTo(LayerImpl* layer) OVERRIDE;
virtual void AppendQuads(QuadSink* quad_sink,
AppendQuadsData* append_quads_data) OVERRIDE;
- virtual void UpdateTilePriorities() OVERRIDE;
+ virtual void UpdateTiles() OVERRIDE;
+ virtual void NotifyTileStateChanged(const Tile* tile) OVERRIDE;
virtual void DidBecomeActive() OVERRIDE;
virtual void DidBeginTracing() OVERRIDE;
- virtual void DidLoseOutputSurface() OVERRIDE;
- virtual void CalculateContentsScale(float ideal_contents_scale,
- float device_scale_factor,
- float page_scale_factor,
- bool animating_transform_to_screen,
- float* contents_scale_x,
- float* contents_scale_y,
- gfx::Size* content_bounds) OVERRIDE;
+ virtual void ReleaseResources() OVERRIDE;
virtual skia::RefPtr<SkPicture> GetPicture() OVERRIDE;
// PictureLayerTilingClient overrides.
- virtual scoped_refptr<Tile> CreateTile(PictureLayerTiling* tiling,
- gfx::Rect content_rect) OVERRIDE;
+ virtual scoped_refptr<Tile> CreateTile(
+ PictureLayerTiling* tiling,
+ const gfx::Rect& content_rect) OVERRIDE;
virtual void UpdatePile(Tile* tile) OVERRIDE;
virtual gfx::Size CalculateTileSize(
- gfx::Size content_bounds) const OVERRIDE;
+ const gfx::Size& content_bounds) const OVERRIDE;
virtual const Region* GetInvalidation() OVERRIDE;
virtual const PictureLayerTiling* GetTwinTiling(
const PictureLayerTiling* tiling) const OVERRIDE;
+ virtual size_t GetMaxTilesForInterestArea() const OVERRIDE;
+ virtual float GetSkewportTargetTimeInSeconds() const OVERRIDE;
+ virtual int GetSkewportExtrapolationLimitInContentPixels() const OVERRIDE;
// PushPropertiesTo active tree => pending tree.
void SyncTiling(const PictureLayerTiling* tiling);
@@ -73,29 +123,36 @@ class CC_EXPORT PictureLayerImpl
virtual void RunMicroBenchmark(MicroBenchmarkImpl* benchmark) OVERRIDE;
+ // Functions used by tile manager.
+ PictureLayerImpl* GetTwinLayer() { return twin_layer_; }
+ WhichTree GetTree() const;
+ bool IsOnActiveOrPendingTree() const;
+ bool HasValidTilePriorities() const;
+ bool AllTilesRequiredForActivationAreReadyToDraw() const;
+
protected:
+ friend class LayerRasterTileIterator;
+
PictureLayerImpl(LayerTreeImpl* tree_impl, int id);
PictureLayerTiling* AddTiling(float contents_scale);
void RemoveTiling(float contents_scale);
void RemoveAllTilings();
void SyncFromActiveLayer(const PictureLayerImpl* other);
- void ManageTilings(bool animating_transform_to_screen);
- virtual bool ShouldAdjustRasterScale(
- bool animating_transform_to_screen) const;
- virtual void RecalculateRasterScales(
- bool animating_transform_to_screen);
+ void AddTilingsForRasterScale();
+ void UpdateTilePriorities();
+ virtual bool ShouldAdjustRasterScale() const;
+ virtual void RecalculateRasterScales();
void CleanUpTilingsOnActiveLayer(
std::vector<PictureLayerTiling*> used_tilings);
float MinimumContentsScale() const;
float SnappedContentsScale(float new_contents_scale);
- void UpdateLCDTextStatus(bool new_status);
void ResetRasterScale();
void MarkVisibleResourcesAsRequired() const;
bool MarkVisibleTilesAsRequired(
PictureLayerTiling* tiling,
const PictureLayerTiling* optional_twin_tiling,
float contents_scale,
- gfx::Rect rect,
+ const gfx::Rect& rect,
const Region& missing_region) const;
void DoPostCommitInitializationIfNeeded() {
@@ -107,21 +164,20 @@ class CC_EXPORT PictureLayerImpl
bool CanHaveTilings() const;
bool CanHaveTilingWithScale(float contents_scale) const;
void SanityCheckTilingState() const;
- bool ShouldUseGPURasterization() const;
virtual void GetDebugBorderProperties(
SkColor* color, float* width) const OVERRIDE;
virtual void AsValueInto(base::DictionaryValue* dict) const OVERRIDE;
+ virtual void UpdateIdealScales();
+ float MaximumTilingContentsScale() const;
+
PictureLayerImpl* twin_layer_;
scoped_ptr<PictureLayerTilingSet> tilings_;
scoped_refptr<PicturePileImpl> pile_;
Region invalidation_;
- gfx::Transform last_screen_space_transform_;
- gfx::Size last_bounds_;
- float last_content_scale_;
bool is_mask_;
float ideal_page_scale_;
@@ -135,13 +191,19 @@ class CC_EXPORT PictureLayerImpl
float raster_contents_scale_;
float low_res_raster_contents_scale_;
- bool raster_source_scale_was_animating_;
- bool is_using_lcd_text_;
+ bool raster_source_scale_is_fixed_;
+ bool was_screen_space_transform_animating_;
bool needs_post_commit_initialization_;
// A sanity state check to make sure UpdateTilePriorities only gets called
// after a CalculateContentsScale/ManageTilings.
bool should_update_tile_priorities_;
+ // Save a copy of the visible rect and viewport size of the last frame that
+ // has a valid viewport for prioritizing tiles.
+ gfx::Rect visible_rect_for_tile_priority_;
+ gfx::Size viewport_size_for_tile_priority_;
+ gfx::Transform screen_space_transform_for_tile_priority_;
+
friend class PictureLayer;
DISALLOW_COPY_AND_ASSIGN(PictureLayerImpl);
};
diff --git a/chromium/cc/layers/picture_layer_impl_perftest.cc b/chromium/cc/layers/picture_layer_impl_perftest.cc
new file mode 100644
index 00000000000..26280c10de8
--- /dev/null
+++ b/chromium/cc/layers/picture_layer_impl_perftest.cc
@@ -0,0 +1,114 @@
+// 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/layers/picture_layer_impl.h"
+
+#include "cc/debug/lap_timer.h"
+#include "cc/test/fake_impl_proxy.h"
+#include "cc/test/fake_layer_tree_host_impl.h"
+#include "cc/test/fake_output_surface.h"
+#include "cc/test/fake_picture_layer_impl.h"
+#include "cc/test/fake_picture_pile_impl.h"
+#include "cc/test/impl_side_painting_settings.h"
+#include "cc/test/test_shared_bitmap_manager.h"
+#include "cc/trees/layer_tree_impl.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/perf/perf_test.h"
+
+namespace cc {
+namespace {
+
+static const int kTimeLimitMillis = 2000;
+static const int kWarmupRuns = 5;
+static const int kTimeCheckInterval = 10;
+
+class PictureLayerImplPerfTest : public testing::Test {
+ public:
+ PictureLayerImplPerfTest()
+ : proxy_(base::MessageLoopProxy::current()),
+ host_impl_(ImplSidePaintingSettings(),
+ &proxy_,
+ &shared_bitmap_manager_),
+ timer_(kWarmupRuns,
+ base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
+ kTimeCheckInterval) {}
+
+ virtual void SetUp() OVERRIDE {
+ host_impl_.InitializeRenderer(
+ FakeOutputSurface::Create3d().PassAs<OutputSurface>());
+ }
+
+ void SetupPendingTree(const gfx::Size& layer_bounds,
+ const gfx::Size& tile_size) {
+ scoped_refptr<FakePicturePileImpl> pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+ host_impl_.CreatePendingTree();
+ LayerTreeImpl* pending_tree = host_impl_.pending_tree();
+ pending_tree->DetachLayerTree();
+
+ scoped_ptr<FakePictureLayerImpl> pending_layer =
+ FakePictureLayerImpl::CreateWithPile(pending_tree, 7, pile);
+ pending_layer->SetDrawsContent(true);
+ pending_tree->SetRootLayer(pending_layer.PassAs<LayerImpl>());
+
+ pending_layer_ = static_cast<FakePictureLayerImpl*>(
+ host_impl_.pending_tree()->LayerById(7));
+ pending_layer_->DoPostCommitInitializationIfNeeded();
+ }
+
+ void RunLayerRasterTileIteratorTest(const std::string& test_name,
+ int num_tiles,
+ const gfx::Size& viewport_size) {
+ host_impl_.SetViewportSize(viewport_size);
+ host_impl_.pending_tree()->UpdateDrawProperties();
+
+ timer_.Reset();
+ do {
+ int count = num_tiles;
+ for (PictureLayerImpl::LayerRasterTileIterator it(pending_layer_, false);
+ it && count;
+ ++it) {
+ --count;
+ }
+ timer_.NextLap();
+ } while (!timer_.HasTimeLimitExpired());
+
+ perf_test::PrintResult("layer_raster_tile_iterator",
+ "",
+ test_name,
+ timer_.LapsPerSecond(),
+ "runs/s",
+ true);
+ }
+
+ protected:
+ TestSharedBitmapManager shared_bitmap_manager_;
+ FakeImplProxy proxy_;
+ FakeLayerTreeHostImpl host_impl_;
+ FakePictureLayerImpl* pending_layer_;
+ LapTimer timer_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(PictureLayerImplPerfTest);
+};
+
+TEST_F(PictureLayerImplPerfTest, LayerRasterTileIterator) {
+ SetupPendingTree(gfx::Size(10000, 10000), gfx::Size(256, 256));
+
+ 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);
+
+ RunLayerRasterTileIteratorTest("32_100x100", 32, gfx::Size(100, 100));
+ RunLayerRasterTileIteratorTest("32_500x500", 32, gfx::Size(500, 500));
+ RunLayerRasterTileIteratorTest("64_100x100", 64, gfx::Size(100, 100));
+ RunLayerRasterTileIteratorTest("64_500x500", 64, gfx::Size(500, 500));
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/layers/picture_layer_impl_unittest.cc b/chromium/cc/layers/picture_layer_impl_unittest.cc
index eb3b0597194..36fab900ad1 100644
--- a/chromium/cc/layers/picture_layer_impl_unittest.cc
+++ b/chromium/cc/layers/picture_layer_impl_unittest.cc
@@ -4,6 +4,9 @@
#include "cc/layers/picture_layer_impl.h"
+#include <algorithm>
+#include <limits>
+#include <set>
#include <utility>
#include "cc/layers/append_quads_data.h"
@@ -16,19 +19,21 @@
#include "cc/test/fake_picture_pile_impl.h"
#include "cc/test/geometry_test_utils.h"
#include "cc/test/impl_side_painting_settings.h"
+#include "cc/test/layer_test_common.h"
#include "cc/test/mock_quad_culler.h"
+#include "cc/test/test_shared_bitmap_manager.h"
#include "cc/test/test_web_graphics_context_3d.h"
#include "cc/trees/layer_tree_impl.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/skia/include/core/SkBitmapDevice.h"
#include "ui/gfx/rect_conversions.h"
+#include "ui/gfx/size_conversions.h"
namespace cc {
namespace {
class MockCanvas : public SkCanvas {
public:
- explicit MockCanvas(SkBaseDevice* device) : SkCanvas(device) {}
+ explicit MockCanvas(int w, int h) : SkCanvas(w, h) {}
virtual void drawRect(const SkRect& rect, const SkPaint& paint) OVERRIDE {
// Capture calls before SkCanvas quickReject() kicks in.
@@ -41,10 +46,16 @@ class MockCanvas : public SkCanvas {
class PictureLayerImplTest : public testing::Test {
public:
PictureLayerImplTest()
- : host_impl_(ImplSidePaintingSettings(), &proxy_), id_(7) {}
+ : proxy_(base::MessageLoopProxy::current()),
+ host_impl_(ImplSidePaintingSettings(),
+ &proxy_,
+ &shared_bitmap_manager_),
+ id_(7) {}
explicit PictureLayerImplTest(const LayerTreeSettings& settings)
- : host_impl_(settings, &proxy_), id_(7) {}
+ : proxy_(base::MessageLoopProxy::current()),
+ host_impl_(settings, &proxy_, &shared_bitmap_manager_),
+ id_(7) {}
virtual ~PictureLayerImplTest() {
}
@@ -54,10 +65,11 @@ class PictureLayerImplTest : public testing::Test {
}
virtual void InitializeRenderer() {
- host_impl_.InitializeRenderer(CreateFakeOutputSurface());
+ host_impl_.InitializeRenderer(
+ FakeOutputSurface::Create3d().PassAs<OutputSurface>());
}
- void SetupDefaultTrees(gfx::Size layer_bounds) {
+ void SetupDefaultTrees(const gfx::Size& layer_bounds) {
gfx::Size tile_size(100, 100);
scoped_refptr<FakePicturePileImpl> pending_pile =
@@ -76,8 +88,8 @@ class PictureLayerImplTest : public testing::Test {
host_impl_.active_tree()->LayerById(id_));
}
- void SetupDefaultTreesWithFixedTileSize(gfx::Size layer_bounds,
- gfx::Size tile_size) {
+ void SetupDefaultTreesWithFixedTileSize(const gfx::Size& layer_bounds,
+ const gfx::Size& tile_size) {
SetupDefaultTrees(layer_bounds);
pending_layer_->set_fixed_tile_size(tile_size);
active_layer_->set_fixed_tile_size(tile_size);
@@ -89,6 +101,8 @@ class PictureLayerImplTest : public testing::Test {
SetupPendingTree(active_pile);
ActivateTree();
SetupPendingTree(pending_pile);
+ host_impl_.pending_tree()->SetPageScaleFactorAndLimits(1.f, 0.25f, 100.f);
+ host_impl_.active_tree()->SetPageScaleFactorAndLimits(1.f, 0.25f, 100.f);
}
void CreateHighLowResAndSetAllTilesVisible() {
@@ -110,8 +124,7 @@ class PictureLayerImplTest : public testing::Test {
pending_layer_->tilings()->tiling_at(i)->CreateAllTilesForTesting();
}
- void SetupPendingTree(
- scoped_refptr<PicturePileImpl> pile) {
+ void SetupPendingTree(scoped_refptr<PicturePileImpl> pile) {
host_impl_.CreatePendingTree();
LayerTreeImpl* pending_tree = host_impl_.pending_tree();
// Clear recycled tree.
@@ -127,11 +140,26 @@ class PictureLayerImplTest : public testing::Test {
pending_layer_->DoPostCommitInitializationIfNeeded();
}
+ void SetupDrawPropertiesAndUpdateTiles(FakePictureLayerImpl* layer,
+ float ideal_contents_scale,
+ float device_scale_factor,
+ float page_scale_factor,
+ float maximum_animation_contents_scale,
+ bool animating_transform_to_screen) {
+ layer->draw_properties().ideal_contents_scale = ideal_contents_scale;
+ layer->draw_properties().device_scale_factor = device_scale_factor;
+ layer->draw_properties().page_scale_factor = page_scale_factor;
+ layer->draw_properties().maximum_animation_contents_scale =
+ maximum_animation_contents_scale;
+ layer->draw_properties().screen_space_transform_is_animating =
+ animating_transform_to_screen;
+ layer->UpdateTiles();
+ }
static void VerifyAllTilesExistAndHavePile(
const PictureLayerTiling* tiling,
PicturePileImpl* pile) {
- for (PictureLayerTiling::CoverageIterator
- iter(tiling, tiling->contents_scale(), tiling->ContentRect());
+ for (PictureLayerTiling::CoverageIterator iter(
+ tiling, tiling->contents_scale(), tiling->TilingRect());
iter;
++iter) {
EXPECT_TRUE(*iter);
@@ -142,30 +170,26 @@ class PictureLayerImplTest : public testing::Test {
void SetContentsScaleOnBothLayers(float contents_scale,
float device_scale_factor,
float page_scale_factor,
+ float maximum_animation_contents_scale,
bool animating_transform) {
- float result_scale_x, result_scale_y;
- gfx::Size result_bounds;
- pending_layer_->CalculateContentsScale(
- contents_scale,
- device_scale_factor,
- page_scale_factor,
- animating_transform,
- &result_scale_x,
- &result_scale_y,
- &result_bounds);
- active_layer_->CalculateContentsScale(
- contents_scale,
- device_scale_factor,
- page_scale_factor,
- animating_transform,
- &result_scale_x,
- &result_scale_y,
- &result_bounds);
+ SetupDrawPropertiesAndUpdateTiles(pending_layer_,
+ contents_scale,
+ device_scale_factor,
+ page_scale_factor,
+ maximum_animation_contents_scale,
+ animating_transform);
+
+ SetupDrawPropertiesAndUpdateTiles(active_layer_,
+ contents_scale,
+ device_scale_factor,
+ page_scale_factor,
+ maximum_animation_contents_scale,
+ animating_transform);
}
void ResetTilingsAndRasterScales() {
- pending_layer_->DidLoseOutputSurface();
- active_layer_->DidLoseOutputSurface();
+ pending_layer_->ReleaseResources();
+ active_layer_->ReleaseResources();
}
void AssertAllTilesRequired(PictureLayerTiling* tiling) {
@@ -197,10 +221,7 @@ class PictureLayerImplTest : public testing::Test {
SetupTrees(pending_pile, active_pile);
- float result_scale_x, result_scale_y;
- gfx::Size result_bounds;
- active_layer_->CalculateContentsScale(
- 1.f, 1.f, 1.f, false, &result_scale_x, &result_scale_y, &result_bounds);
+ SetupDrawPropertiesAndUpdateTiles(active_layer_, 1.f, 1.f, 1.f, 1.f, false);
// Add 1x1 rects at the centers of each tile, then re-record pile contents
active_layer_->tilings()->tiling_at(0)->CreateAllTilesForTesting();
@@ -219,13 +240,9 @@ class PictureLayerImplTest : public testing::Test {
active_pile->RemoveRecordingAt(0, 0);
active_pile->AddRecordingAt(0, 0);
- SkBitmap store;
- store.setConfig(SkBitmap::kNo_Config, 1000, 1000);
- SkBitmapDevice device(store);
-
std::vector<SkRect>::const_iterator rect_iter = rects.begin();
for (tile_iter = tiles.begin(); tile_iter < tiles.end(); tile_iter++) {
- MockCanvas mock_canvas(&device);
+ MockCanvas mock_canvas(1000, 1000);
active_pile->RasterDirect(
&mock_canvas, (*tile_iter)->content_rect(), 1.0f, NULL);
@@ -240,6 +257,7 @@ class PictureLayerImplTest : public testing::Test {
}
FakeImplProxy proxy_;
+ TestSharedBitmapManager shared_bitmap_manager_;
FakeLayerTreeHostImpl host_impl_;
int id_;
FakePictureLayerImpl* pending_layer_;
@@ -282,7 +300,7 @@ TEST_F(PictureLayerImplTest, CloneNoInvalidation) {
VerifyAllTilesExistAndHavePile(tilings->tiling_at(i), active_pile.get());
}
-TEST_F(PictureLayerImplTest, SuppressUpdateTilePriorities) {
+TEST_F(PictureLayerImplTest, InvalidViewportForPrioritizingTiles) {
base::TimeTicks time_ticks;
host_impl_.SetCurrentFrameTimeTicks(time_ticks);
@@ -298,44 +316,94 @@ TEST_F(PictureLayerImplTest, SuppressUpdateTilePriorities) {
Region invalidation;
AddDefaultTilingsWithInvalidation(invalidation);
- float dummy_contents_scale_x;
- float dummy_contents_scale_y;
- gfx::Size dummy_content_bounds;
- active_layer_->CalculateContentsScale(1.f,
- 1.f,
- 1.f,
- false,
- &dummy_contents_scale_x,
- &dummy_contents_scale_y,
- &dummy_content_bounds);
-
- EXPECT_TRUE(host_impl_.manage_tiles_needed());
- active_layer_->UpdateTilePriorities();
- host_impl_.ManageTiles();
- EXPECT_FALSE(host_impl_.manage_tiles_needed());
-
+ SetupDrawPropertiesAndUpdateTiles(active_layer_, 1.f, 1.f, 1.f, 1.f, false);
+
+ // UpdateTiles with valid viewport. Should update tile viewport.
+ bool valid_for_tile_management = true;
+ gfx::Rect viewport = gfx::Rect(layer_bounds);
+ gfx::Transform transform;
+ host_impl_.SetExternalDrawConstraints(
+ transform, viewport, viewport, valid_for_tile_management);
+ active_layer_->draw_properties().visible_content_rect = viewport;
+ active_layer_->draw_properties().screen_space_transform = transform;
+ active_layer_->UpdateTiles();
+
+ gfx::Rect visible_rect_for_tile_priority =
+ active_layer_->visible_rect_for_tile_priority();
+ EXPECT_FALSE(visible_rect_for_tile_priority.IsEmpty());
+ gfx::Size viewport_size_for_tile_priority =
+ active_layer_->viewport_size_for_tile_priority();
+ EXPECT_FALSE(viewport_size_for_tile_priority.IsEmpty());
+ gfx::Transform screen_space_transform_for_tile_priority =
+ active_layer_->screen_space_transform_for_tile_priority();
+
+ // Expand viewport and set it as invalid for prioritizing tiles.
+ // Should not update tile viewport.
time_ticks += base::TimeDelta::FromMilliseconds(200);
host_impl_.SetCurrentFrameTimeTicks(time_ticks);
-
- // Setting this boolean should cause an early out in UpdateTilePriorities.
- bool valid_for_tile_management = false;
- host_impl_.SetExternalDrawConstraints(gfx::Transform(),
- gfx::Rect(layer_bounds),
- gfx::Rect(layer_bounds),
- valid_for_tile_management);
- active_layer_->UpdateTilePriorities();
- EXPECT_FALSE(host_impl_.manage_tiles_needed());
-
+ valid_for_tile_management = false;
+ viewport = gfx::ScaleToEnclosingRect(viewport, 2);
+ transform.Translate(1.f, 1.f);
+ active_layer_->draw_properties().visible_content_rect = viewport;
+ active_layer_->draw_properties().screen_space_transform = transform;
+ host_impl_.SetExternalDrawConstraints(
+ transform, viewport, viewport, valid_for_tile_management);
+ active_layer_->UpdateTiles();
+
+ EXPECT_RECT_EQ(visible_rect_for_tile_priority,
+ active_layer_->visible_rect_for_tile_priority());
+ EXPECT_SIZE_EQ(viewport_size_for_tile_priority,
+ active_layer_->viewport_size_for_tile_priority());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(
+ screen_space_transform_for_tile_priority,
+ active_layer_->screen_space_transform_for_tile_priority());
+
+ // Keep expanded viewport but mark it valid. Should update tile viewport.
time_ticks += base::TimeDelta::FromMilliseconds(200);
host_impl_.SetCurrentFrameTimeTicks(time_ticks);
-
valid_for_tile_management = true;
- host_impl_.SetExternalDrawConstraints(gfx::Transform(),
- gfx::Rect(layer_bounds),
- gfx::Rect(layer_bounds),
- valid_for_tile_management);
- active_layer_->UpdateTilePriorities();
- EXPECT_TRUE(host_impl_.manage_tiles_needed());
+ host_impl_.SetExternalDrawConstraints(
+ transform, viewport, viewport, valid_for_tile_management);
+ active_layer_->UpdateTiles();
+
+ EXPECT_FALSE(visible_rect_for_tile_priority ==
+ active_layer_->visible_rect_for_tile_priority());
+ EXPECT_FALSE(viewport_size_for_tile_priority ==
+ active_layer_->viewport_size_for_tile_priority());
+ EXPECT_FALSE(screen_space_transform_for_tile_priority ==
+ active_layer_->screen_space_transform_for_tile_priority());
+}
+
+TEST_F(PictureLayerImplTest, InvalidViewportAfterReleaseResources) {
+ base::TimeTicks time_ticks;
+ host_impl_.SetCurrentFrameTimeTicks(time_ticks);
+
+ gfx::Size tile_size(100, 100);
+ gfx::Size layer_bounds(400, 400);
+
+ scoped_refptr<FakePicturePileImpl> pending_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+ scoped_refptr<FakePicturePileImpl> active_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+
+ SetupTrees(pending_pile, active_pile);
+
+ Region invalidation;
+ AddDefaultTilingsWithInvalidation(invalidation);
+
+ bool valid_for_tile_management = false;
+ gfx::Rect viewport = gfx::Rect(layer_bounds);
+ host_impl_.SetExternalDrawConstraints(
+ gfx::Transform(), viewport, viewport, valid_for_tile_management);
+ ResetTilingsAndRasterScales();
+ host_impl_.pending_tree()->UpdateDrawProperties();
+ host_impl_.active_tree()->UpdateDrawProperties();
+ EXPECT_TRUE(active_layer_->HighResTiling());
+
+ size_t num_tilings = active_layer_->num_tilings();
+ active_layer_->UpdateTiles();
+ pending_layer_->AddTiling(0.5f);
+ EXPECT_EQ(num_tilings + 1, active_layer_->num_tilings());
}
TEST_F(PictureLayerImplTest, ClonePartialInvalidation) {
@@ -360,10 +428,8 @@ TEST_F(PictureLayerImplTest, ClonePartialInvalidation) {
gfx::Rect content_invalidation = gfx::ScaleToEnclosingRect(
layer_invalidation,
tiling->contents_scale());
- for (PictureLayerTiling::CoverageIterator
- iter(tiling,
- tiling->contents_scale(),
- tiling->ContentRect());
+ for (PictureLayerTiling::CoverageIterator iter(
+ tiling, tiling->contents_scale(), tiling->TilingRect());
iter;
++iter) {
EXPECT_TRUE(*iter);
@@ -423,10 +489,8 @@ TEST_F(PictureLayerImplTest, NoInvalidationBoundsChange) {
gfx::Rect active_content_bounds = gfx::ScaleToEnclosingRect(
gfx::Rect(active_layer_bounds),
tiling->contents_scale());
- for (PictureLayerTiling::CoverageIterator
- iter(tiling,
- tiling->contents_scale(),
- tiling->ContentRect());
+ for (PictureLayerTiling::CoverageIterator iter(
+ tiling, tiling->contents_scale(), tiling->TilingRect());
iter;
++iter) {
EXPECT_TRUE(*iter);
@@ -479,20 +543,16 @@ TEST_F(PictureLayerImplTest, AddTilesFromNewRecording) {
for (size_t i = 0; i < tilings->num_tilings(); ++i) {
const PictureLayerTiling* tiling = tilings->tiling_at(i);
- for (PictureLayerTiling::CoverageIterator
- iter(tiling,
- tiling->contents_scale(),
- tiling->ContentRect());
+ for (PictureLayerTiling::CoverageIterator iter(
+ tiling, tiling->contents_scale(), tiling->TilingRect());
iter;
++iter) {
EXPECT_FALSE(iter.full_tile_geometry_rect().IsEmpty());
// Ensure there is a recording for this tile.
- gfx::Rect layer_rect = gfx::ScaleToEnclosingRect(
- iter.full_tile_geometry_rect(), 1.f / tiling->contents_scale());
- layer_rect.Intersect(gfx::Rect(layer_bounds));
-
- bool in_pending = pending_pile->recorded_region().Contains(layer_rect);
- bool in_active = active_pile->recorded_region().Contains(layer_rect);
+ bool in_pending = pending_pile->CanRaster(tiling->contents_scale(),
+ iter.full_tile_geometry_rect());
+ bool in_active = active_pile->CanRaster(tiling->contents_scale(),
+ iter.full_tile_geometry_rect());
if (in_pending && !in_active)
EXPECT_EQ(pending_pile, iter->picture_pile());
@@ -513,13 +573,9 @@ TEST_F(PictureLayerImplTest, ManageTilingsWithNoRecording) {
scoped_refptr<FakePicturePileImpl> active_pile =
FakePicturePileImpl::CreateEmptyPile(tile_size, layer_bounds);
- float result_scale_x, result_scale_y;
- gfx::Size result_bounds;
-
SetupTrees(pending_pile, active_pile);
- pending_layer_->CalculateContentsScale(
- 1.f, 1.f, 1.f, false, &result_scale_x, &result_scale_y, &result_bounds);
+ SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, false);
EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
}
@@ -533,95 +589,63 @@ TEST_F(PictureLayerImplTest, ManageTilingsCreatesTilings) {
scoped_refptr<FakePicturePileImpl> active_pile =
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
- float result_scale_x, result_scale_y;
- gfx::Size result_bounds;
-
SetupTrees(pending_pile, active_pile);
EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
EXPECT_LT(low_res_factor, 1.f);
- pending_layer_->CalculateContentsScale(1.3f, // ideal contents scale
- 1.7f, // device scale
- 3.2f, // page cale
- false,
- &result_scale_x,
- &result_scale_y,
- &result_bounds);
- ASSERT_EQ(2u, pending_layer_->tilings()->num_tilings());
- EXPECT_FLOAT_EQ(
- 1.3f,
- pending_layer_->tilings()->tiling_at(0)->contents_scale());
- EXPECT_FLOAT_EQ(
- 1.3f * low_res_factor,
- pending_layer_->tilings()->tiling_at(1)->contents_scale());
-
- // If we change the layer's CSS scale factor, then we should not get new
- // tilings.
- pending_layer_->CalculateContentsScale(1.8f, // ideal contents scale
- 1.7f, // device scale
- 3.2f, // page cale
- false,
- &result_scale_x,
- &result_scale_y,
- &result_bounds);
+ SetupDrawPropertiesAndUpdateTiles(pending_layer_,
+ 6.f, // ideal contents scale
+ 3.f, // device scale
+ 2.f, // page scale
+ 1.f, // maximum animation scale
+ false);
ASSERT_EQ(2u, pending_layer_->tilings()->num_tilings());
- EXPECT_FLOAT_EQ(
- 1.3f,
- pending_layer_->tilings()->tiling_at(0)->contents_scale());
- EXPECT_FLOAT_EQ(
- 1.3f * low_res_factor,
- pending_layer_->tilings()->tiling_at(1)->contents_scale());
+ EXPECT_FLOAT_EQ(6.f,
+ pending_layer_->tilings()->tiling_at(0)->contents_scale());
+ EXPECT_FLOAT_EQ(6.f * low_res_factor,
+ pending_layer_->tilings()->tiling_at(1)->contents_scale());
// If we change the page scale factor, then we should get new tilings.
- pending_layer_->CalculateContentsScale(1.8f, // ideal contents scale
- 1.7f, // device scale
- 2.2f, // page cale
- false,
- &result_scale_x,
- &result_scale_y,
- &result_bounds);
+ SetupDrawPropertiesAndUpdateTiles(pending_layer_,
+ 6.6f, // ideal contents scale
+ 3.f, // device scale
+ 2.2f, // page scale
+ 1.f, // maximum animation scale
+ false);
ASSERT_EQ(4u, pending_layer_->tilings()->num_tilings());
- EXPECT_FLOAT_EQ(
- 1.8f,
- pending_layer_->tilings()->tiling_at(0)->contents_scale());
- EXPECT_FLOAT_EQ(
- 1.8f * low_res_factor,
- pending_layer_->tilings()->tiling_at(2)->contents_scale());
+ EXPECT_FLOAT_EQ(6.6f,
+ pending_layer_->tilings()->tiling_at(0)->contents_scale());
+ EXPECT_FLOAT_EQ(6.6f * low_res_factor,
+ pending_layer_->tilings()->tiling_at(2)->contents_scale());
// If we change the device scale factor, then we should get new tilings.
- pending_layer_->CalculateContentsScale(1.9f, // ideal contents scale
- 1.4f, // device scale
- 2.2f, // page cale
- false,
- &result_scale_x,
- &result_scale_y,
- &result_bounds);
+ SetupDrawPropertiesAndUpdateTiles(pending_layer_,
+ 7.26f, // ideal contents scale
+ 3.3f, // device scale
+ 2.2f, // page scale
+ 1.f, // maximum animation scale
+ false);
ASSERT_EQ(6u, pending_layer_->tilings()->num_tilings());
- EXPECT_FLOAT_EQ(
- 1.9f,
- pending_layer_->tilings()->tiling_at(0)->contents_scale());
- EXPECT_FLOAT_EQ(
- 1.9f * low_res_factor,
- pending_layer_->tilings()->tiling_at(3)->contents_scale());
+ EXPECT_FLOAT_EQ(7.26f,
+ pending_layer_->tilings()->tiling_at(0)->contents_scale());
+ EXPECT_FLOAT_EQ(7.26f * low_res_factor,
+ pending_layer_->tilings()->tiling_at(3)->contents_scale());
// If we change the device scale factor, but end up at the same total scale
// factor somehow, then we don't get new tilings.
- pending_layer_->CalculateContentsScale(1.9f, // ideal contents scale
- 2.2f, // device scale
- 1.4f, // page cale
- false,
- &result_scale_x,
- &result_scale_y,
- &result_bounds);
+ SetupDrawPropertiesAndUpdateTiles(pending_layer_,
+ 7.26f, // ideal contents scale
+ 2.2f, // device scale
+ 3.3f, // page scale
+ 1.f, // maximum animation scale
+ false);
ASSERT_EQ(6u, pending_layer_->tilings()->num_tilings());
- EXPECT_FLOAT_EQ(
- 1.9f,
- pending_layer_->tilings()->tiling_at(0)->contents_scale());
- EXPECT_FLOAT_EQ(
- 1.9f * low_res_factor,
- pending_layer_->tilings()->tiling_at(3)->contents_scale());
+ EXPECT_FLOAT_EQ(7.26f,
+ pending_layer_->tilings()->tiling_at(0)->contents_scale());
+ EXPECT_FLOAT_EQ(7.26f * low_res_factor,
+ pending_layer_->tilings()->tiling_at(3)->contents_scale());
}
TEST_F(PictureLayerImplTest, CreateTilingsEvenIfTwinHasNone) {
@@ -632,7 +656,7 @@ TEST_F(PictureLayerImplTest, CreateTilingsEvenIfTwinHasNone) {
gfx::Size layer_bounds(1300, 1900);
scoped_refptr<FakePicturePileImpl> empty_pile =
- FakePicturePileImpl::CreateFilledPile(tile_size, gfx::Size(1000, 0));
+ FakePicturePileImpl::CreateEmptyPile(tile_size, layer_bounds);
scoped_refptr<FakePicturePileImpl> valid_pile =
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
@@ -643,17 +667,15 @@ TEST_F(PictureLayerImplTest, CreateTilingsEvenIfTwinHasNone) {
float low_res_scale = high_res_scale * low_res_factor;
float device_scale = 1.7f;
float page_scale = 3.2f;
- float result_scale_x, result_scale_y;
- gfx::Size result_bounds;
+ float maximum_animation_scale = 1.f;
SetupPendingTree(valid_pile);
- pending_layer_->CalculateContentsScale(high_res_scale,
- device_scale,
- page_scale,
- false,
- &result_scale_x,
- &result_scale_y,
- &result_bounds);
+ SetupDrawPropertiesAndUpdateTiles(pending_layer_,
+ high_res_scale,
+ device_scale,
+ page_scale,
+ maximum_animation_scale,
+ false);
ASSERT_EQ(2u, pending_layer_->tilings()->num_tilings());
EXPECT_FLOAT_EQ(high_res_scale,
pending_layer_->HighResTiling()->contents_scale());
@@ -662,34 +684,33 @@ TEST_F(PictureLayerImplTest, CreateTilingsEvenIfTwinHasNone) {
ActivateTree();
SetupPendingTree(empty_pile);
- pending_layer_->CalculateContentsScale(high_res_scale,
- device_scale,
- page_scale,
- false,
- &result_scale_x,
- &result_scale_y,
- &result_bounds);
+ EXPECT_FALSE(pending_layer_->CanHaveTilings());
+ SetupDrawPropertiesAndUpdateTiles(pending_layer_,
+ high_res_scale,
+ device_scale,
+ page_scale,
+ maximum_animation_scale,
+ false);
ASSERT_EQ(2u, active_layer_->tilings()->num_tilings());
ASSERT_EQ(0u, pending_layer_->tilings()->num_tilings());
ActivateTree();
- active_layer_->CalculateContentsScale(high_res_scale,
- device_scale,
- page_scale,
- false,
- &result_scale_x,
- &result_scale_y,
- &result_bounds);
+ EXPECT_FALSE(active_layer_->CanHaveTilings());
+ SetupDrawPropertiesAndUpdateTiles(active_layer_,
+ high_res_scale,
+ device_scale,
+ page_scale,
+ maximum_animation_scale,
+ false);
ASSERT_EQ(0u, active_layer_->tilings()->num_tilings());
SetupPendingTree(valid_pile);
- pending_layer_->CalculateContentsScale(high_res_scale,
- device_scale,
- page_scale,
- false,
- &result_scale_x,
- &result_scale_y,
- &result_bounds);
+ SetupDrawPropertiesAndUpdateTiles(pending_layer_,
+ high_res_scale,
+ device_scale,
+ page_scale,
+ maximum_animation_scale,
+ false);
ASSERT_EQ(2u, pending_layer_->tilings()->num_tilings());
ASSERT_EQ(0u, active_layer_->tilings()->num_tilings());
EXPECT_FLOAT_EQ(high_res_scale,
@@ -710,10 +731,10 @@ TEST_F(PictureLayerImplTest, ZoomOutCrash) {
SetupTrees(pending_pile, active_pile);
EXPECT_EQ(0u, active_layer_->tilings()->num_tilings());
- SetContentsScaleOnBothLayers(32.0f, 1.0f, 32.0f, false);
+ SetContentsScaleOnBothLayers(32.0f, 1.0f, 32.0f, 1.0f, false);
host_impl_.PinchGestureBegin();
- SetContentsScaleOnBothLayers(1.0f, 1.0f, 1.0f, false);
- SetContentsScaleOnBothLayers(1.0f, 1.0f, 1.0f, false);
+ SetContentsScaleOnBothLayers(1.0f, 1.0f, 1.0f, 1.0f, false);
+ SetContentsScaleOnBothLayers(1.0f, 1.0f, 1.0f, 1.0f, false);
EXPECT_EQ(active_layer_->tilings()->NumHighResTilings(), 1);
}
@@ -729,50 +750,89 @@ TEST_F(PictureLayerImplTest, PinchGestureTilings) {
// Set up the high and low res tilings before pinch zoom.
SetupTrees(pending_pile, active_pile);
EXPECT_EQ(0u, active_layer_->tilings()->num_tilings());
- SetContentsScaleOnBothLayers(1.0f, 1.0f, 1.0f, false);
+ SetContentsScaleOnBothLayers(2.0f, 1.0f, 1.0f, 1.0f, false);
float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
EXPECT_EQ(2u, active_layer_->tilings()->num_tilings());
- EXPECT_FLOAT_EQ(
- 1.0f,
- active_layer_->tilings()->tiling_at(0)->contents_scale());
- EXPECT_FLOAT_EQ(
- 1.0f * low_res_factor,
- active_layer_->tilings()->tiling_at(1)->contents_scale());
+ EXPECT_FLOAT_EQ(2.0f,
+ active_layer_->tilings()->tiling_at(0)->contents_scale());
+ EXPECT_FLOAT_EQ(2.0f * low_res_factor,
+ active_layer_->tilings()->tiling_at(1)->contents_scale());
// Start a pinch gesture.
host_impl_.PinchGestureBegin();
// Zoom out by a small amount. We should create a tiling at half
- // the scale (1/kMaxScaleRatioDuringPinch).
- SetContentsScaleOnBothLayers(0.90f, 1.0f, 0.9f, false);
+ // the scale (2/kMaxScaleRatioDuringPinch).
+ SetContentsScaleOnBothLayers(1.8f, 1.0f, 0.9f, 1.0f, false);
EXPECT_EQ(3u, active_layer_->tilings()->num_tilings());
- EXPECT_FLOAT_EQ(
- 1.0f,
- active_layer_->tilings()->tiling_at(0)->contents_scale());
- EXPECT_FLOAT_EQ(
- 0.5f,
- active_layer_->tilings()->tiling_at(1)->contents_scale());
- EXPECT_FLOAT_EQ(
- 1.0f * low_res_factor,
- active_layer_->tilings()->tiling_at(2)->contents_scale());
+ EXPECT_FLOAT_EQ(2.0f,
+ active_layer_->tilings()->tiling_at(0)->contents_scale());
+ EXPECT_FLOAT_EQ(1.0f,
+ active_layer_->tilings()->tiling_at(1)->contents_scale());
+ EXPECT_FLOAT_EQ(2.0f * low_res_factor,
+ active_layer_->tilings()->tiling_at(2)->contents_scale());
// Zoom out further, close to our low-res scale factor. We should
// use that tiling as high-res, and not create a new tiling.
- SetContentsScaleOnBothLayers(low_res_factor, 1.0f, low_res_factor, false);
+ SetContentsScaleOnBothLayers(
+ low_res_factor, 1.0f, low_res_factor / 2.0f, 1.0f, false);
EXPECT_EQ(3u, active_layer_->tilings()->num_tilings());
// Zoom in a lot now. Since we increase by increments of
- // kMaxScaleRatioDuringPinch, this will first use 0.5, then 1.0
- // and then finally create a new tiling at 2.0.
- SetContentsScaleOnBothLayers(2.1f, 1.0f, 2.1f, false);
+ // kMaxScaleRatioDuringPinch, this will first use 1.0, then 2.0
+ // and then finally create a new tiling at 4.0.
+ SetContentsScaleOnBothLayers(4.2f, 1.0f, 2.1f, 1.f, false);
EXPECT_EQ(3u, active_layer_->tilings()->num_tilings());
- SetContentsScaleOnBothLayers(2.1f, 1.0f, 2.1f, false);
+ SetContentsScaleOnBothLayers(4.2f, 1.0f, 2.1f, 1.f, false);
EXPECT_EQ(3u, active_layer_->tilings()->num_tilings());
- SetContentsScaleOnBothLayers(2.1f, 1.0f, 2.1f, false);
+ SetContentsScaleOnBothLayers(4.2f, 1.0f, 2.1f, 1.f, false);
EXPECT_EQ(4u, active_layer_->tilings()->num_tilings());
- EXPECT_FLOAT_EQ(
- 2.0f,
- active_layer_->tilings()->tiling_at(0)->contents_scale());
+ EXPECT_FLOAT_EQ(4.0f,
+ active_layer_->tilings()->tiling_at(0)->contents_scale());
+}
+
+TEST_F(PictureLayerImplTest, SnappedTilingDuringZoom) {
+ gfx::Size tile_size(300, 300);
+ gfx::Size layer_bounds(2600, 3800);
+
+ scoped_refptr<FakePicturePileImpl> pending_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+ scoped_refptr<FakePicturePileImpl> active_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+
+ // Set up the high and low res tilings before pinch zoom.
+ SetupTrees(pending_pile, active_pile);
+ EXPECT_EQ(0u, active_layer_->tilings()->num_tilings());
+ SetContentsScaleOnBothLayers(0.24f, 1.0f, 0.24f, 1.0f, false);
+ EXPECT_EQ(2u, active_layer_->tilings()->num_tilings());
+ EXPECT_FLOAT_EQ(0.24f,
+ active_layer_->tilings()->tiling_at(0)->contents_scale());
+ EXPECT_FLOAT_EQ(0.0625f,
+ active_layer_->tilings()->tiling_at(1)->contents_scale());
+
+ // Start a pinch gesture.
+ host_impl_.PinchGestureBegin();
+
+ // Zoom out by a small amount. We should create a tiling at half
+ // the scale (1/kMaxScaleRatioDuringPinch).
+ SetContentsScaleOnBothLayers(0.2f, 1.0f, 0.2f, 1.0f, false);
+ EXPECT_EQ(3u, active_layer_->tilings()->num_tilings());
+ EXPECT_FLOAT_EQ(0.24f,
+ active_layer_->tilings()->tiling_at(0)->contents_scale());
+ EXPECT_FLOAT_EQ(0.12f,
+ active_layer_->tilings()->tiling_at(1)->contents_scale());
+ EXPECT_FLOAT_EQ(0.0625,
+ active_layer_->tilings()->tiling_at(2)->contents_scale());
+
+ // Zoom out further, close to our low-res scale factor. We should
+ // use that tiling as high-res, and not create a new tiling.
+ SetContentsScaleOnBothLayers(0.1f, 1.0f, 0.1f, 1.0f, false);
+ EXPECT_EQ(3u, active_layer_->tilings()->num_tilings());
+
+ // Zoom in. 0.125(desired_scale) should be snapped to 0.12 during zoom-in
+ // because 0.125(desired_scale) is within the ratio(1.2)
+ SetContentsScaleOnBothLayers(0.5f, 1.0f, 0.5f, 1.0f, false);
+ EXPECT_EQ(3u, active_layer_->tilings()->num_tilings());
}
TEST_F(PictureLayerImplTest, CleanUpTilings) {
@@ -784,8 +844,6 @@ TEST_F(PictureLayerImplTest, CleanUpTilings) {
scoped_refptr<FakePicturePileImpl> active_pile =
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
- float result_scale_x, result_scale_y;
- gfx::Size result_bounds;
std::vector<PictureLayerTiling*> used_tilings;
SetupTrees(pending_pile, active_pile);
@@ -796,8 +854,9 @@ TEST_F(PictureLayerImplTest, CleanUpTilings) {
float device_scale = 1.7f;
float page_scale = 3.2f;
+ float scale = 1.f;
- SetContentsScaleOnBothLayers(1.f, device_scale, page_scale, false);
+ SetContentsScaleOnBothLayers(scale, device_scale, page_scale, 1.f, false);
ASSERT_EQ(2u, active_layer_->tilings()->num_tilings());
// We only have ideal tilings, so they aren't removed.
@@ -805,8 +864,12 @@ TEST_F(PictureLayerImplTest, CleanUpTilings) {
active_layer_->CleanUpTilingsOnActiveLayer(used_tilings);
ASSERT_EQ(2u, active_layer_->tilings()->num_tilings());
+ host_impl_.PinchGestureBegin();
+
// Changing the ideal but not creating new tilings.
- SetContentsScaleOnBothLayers(1.5f, device_scale, page_scale, false);
+ scale *= 1.5f;
+ page_scale *= 1.5f;
+ SetContentsScaleOnBothLayers(scale, device_scale, page_scale, 1.f, false);
ASSERT_EQ(2u, active_layer_->tilings()->num_tilings());
// The tilings are still our target scale, so they aren't removed.
@@ -814,9 +877,12 @@ TEST_F(PictureLayerImplTest, CleanUpTilings) {
active_layer_->CleanUpTilingsOnActiveLayer(used_tilings);
ASSERT_EQ(2u, active_layer_->tilings()->num_tilings());
+ host_impl_.PinchGestureEnd();
+
// Create a 1.2 scale tiling. Now we have 1.0 and 1.2 tilings. Ideal = 1.2.
- page_scale = 1.2f;
- SetContentsScaleOnBothLayers(1.2f, device_scale, page_scale, false);
+ scale /= 4.f;
+ page_scale /= 4.f;
+ SetContentsScaleOnBothLayers(1.2f, device_scale, page_scale, 1.f, false);
ASSERT_EQ(4u, active_layer_->tilings()->num_tilings());
EXPECT_FLOAT_EQ(
1.f,
@@ -833,7 +899,7 @@ TEST_F(PictureLayerImplTest, CleanUpTilings) {
ASSERT_EQ(4u, active_layer_->tilings()->num_tilings());
// Now move the ideal scale to 0.5. Our target stays 1.2.
- SetContentsScaleOnBothLayers(0.5f, device_scale, page_scale, false);
+ SetContentsScaleOnBothLayers(0.5f, device_scale, page_scale, 1.f, false);
// The high resolution tiling is between target and ideal, so is not
// removed. The low res tiling for the old ideal=1.0 scale is removed.
@@ -842,7 +908,7 @@ TEST_F(PictureLayerImplTest, CleanUpTilings) {
ASSERT_EQ(3u, active_layer_->tilings()->num_tilings());
// Now move the ideal scale to 1.0. Our target stays 1.2.
- SetContentsScaleOnBothLayers(1.f, device_scale, page_scale, false);
+ SetContentsScaleOnBothLayers(1.f, device_scale, page_scale, 1.f, false);
// All the tilings are between are target and the ideal, so they are not
// removed.
@@ -851,13 +917,8 @@ TEST_F(PictureLayerImplTest, CleanUpTilings) {
ASSERT_EQ(3u, active_layer_->tilings()->num_tilings());
// Now move the ideal scale to 1.1 on the active layer. Our target stays 1.2.
- active_layer_->CalculateContentsScale(1.1f,
- device_scale,
- page_scale,
- false,
- &result_scale_x,
- &result_scale_y,
- &result_bounds);
+ SetupDrawPropertiesAndUpdateTiles(
+ active_layer_, 1.1f, device_scale, page_scale, 1.f, false);
// Because the pending layer's ideal scale is still 1.0, our tilings fall
// in the range [1.0,1.2] and are kept.
@@ -867,13 +928,8 @@ TEST_F(PictureLayerImplTest, CleanUpTilings) {
// Move the ideal scale on the pending layer to 1.1 as well. Our target stays
// 1.2 still.
- pending_layer_->CalculateContentsScale(1.1f,
- device_scale,
- page_scale,
- false,
- &result_scale_x,
- &result_scale_y,
- &result_bounds);
+ SetupDrawPropertiesAndUpdateTiles(
+ pending_layer_, 1.1f, device_scale, page_scale, 1.f, false);
// Our 1.0 tiling now falls outside the range between our ideal scale and our
// target raster scale. But it is in our used tilings set, so nothing is
@@ -892,8 +948,8 @@ TEST_F(PictureLayerImplTest, CleanUpTilings) {
#define EXPECT_BOTH_EQ(expression, x) \
do { \
- EXPECT_EQ(pending_layer_->expression, x); \
- EXPECT_EQ(active_layer_->expression, x); \
+ EXPECT_EQ(x, pending_layer_->expression); \
+ EXPECT_EQ(x, active_layer_->expression); \
} while (false)
TEST_F(PictureLayerImplTest, DontAddLowResDuringAnimation) {
@@ -909,18 +965,25 @@ TEST_F(PictureLayerImplTest, DontAddLowResDuringAnimation) {
float contents_scale = 1.f;
float device_scale = 1.f;
float page_scale = 1.f;
+ float maximum_animation_scale = 1.f;
bool animating_transform = true;
// Animating, so don't create low res even if there isn't one already.
- SetContentsScaleOnBothLayers(
- contents_scale, device_scale, page_scale, animating_transform);
+ SetContentsScaleOnBothLayers(contents_scale,
+ device_scale,
+ page_scale,
+ maximum_animation_scale,
+ animating_transform);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 1.f);
EXPECT_BOTH_EQ(num_tilings(), 1u);
// Stop animating, low res gets created.
animating_transform = false;
- SetContentsScaleOnBothLayers(
- contents_scale, device_scale, page_scale, animating_transform);
+ SetContentsScaleOnBothLayers(contents_scale,
+ device_scale,
+ page_scale,
+ maximum_animation_scale,
+ animating_transform);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 1.f);
EXPECT_BOTH_EQ(LowResTiling()->contents_scale(), low_res_factor);
EXPECT_BOTH_EQ(num_tilings(), 2u);
@@ -929,16 +992,22 @@ TEST_F(PictureLayerImplTest, DontAddLowResDuringAnimation) {
contents_scale = 2.f;
page_scale = 2.f;
animating_transform = true;
- SetContentsScaleOnBothLayers(
- contents_scale, device_scale, page_scale, animating_transform);
+ SetContentsScaleOnBothLayers(contents_scale,
+ device_scale,
+ page_scale,
+ maximum_animation_scale,
+ animating_transform);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 2.f);
EXPECT_BOTH_EQ(LowResTiling()->contents_scale(), low_res_factor);
EXPECT_BOTH_EQ(num_tilings(), 3u);
// Stop animating, new low res gets created for final page scale.
animating_transform = false;
- SetContentsScaleOnBothLayers(
- contents_scale, device_scale, page_scale, animating_transform);
+ SetContentsScaleOnBothLayers(contents_scale,
+ device_scale,
+ page_scale,
+ maximum_animation_scale,
+ animating_transform);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 2.f);
EXPECT_BOTH_EQ(LowResTiling()->contents_scale(), 2.f * low_res_factor);
EXPECT_BOTH_EQ(num_tilings(), 4u);
@@ -951,12 +1020,16 @@ TEST_F(PictureLayerImplTest, DontAddLowResForSmallLayers) {
float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
float device_scale = 1.f;
float page_scale = 1.f;
+ float maximum_animation_scale = 1.f;
bool animating_transform = false;
// Contents exactly fit on one tile at scale 1, no low res.
float contents_scale = 1.f;
- SetContentsScaleOnBothLayers(
- contents_scale, device_scale, page_scale, animating_transform);
+ SetContentsScaleOnBothLayers(contents_scale,
+ device_scale,
+ page_scale,
+ maximum_animation_scale,
+ animating_transform);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), contents_scale);
EXPECT_BOTH_EQ(num_tilings(), 1u);
@@ -964,8 +1037,11 @@ TEST_F(PictureLayerImplTest, DontAddLowResForSmallLayers) {
// Contents that are smaller than one tile, no low res.
contents_scale = 0.123f;
- SetContentsScaleOnBothLayers(
- contents_scale, device_scale, page_scale, animating_transform);
+ SetContentsScaleOnBothLayers(contents_scale,
+ device_scale,
+ page_scale,
+ maximum_animation_scale,
+ animating_transform);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), contents_scale);
EXPECT_BOTH_EQ(num_tilings(), 1u);
@@ -974,8 +1050,11 @@ TEST_F(PictureLayerImplTest, DontAddLowResForSmallLayers) {
// Any content bounds that would create more than one tile will
// generate a low res tiling.
contents_scale = 2.5f;
- SetContentsScaleOnBothLayers(
- contents_scale, device_scale, page_scale, animating_transform);
+ SetContentsScaleOnBothLayers(contents_scale,
+ device_scale,
+ page_scale,
+ maximum_animation_scale,
+ animating_transform);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), contents_scale);
EXPECT_BOTH_EQ(LowResTiling()->contents_scale(),
contents_scale * low_res_factor);
@@ -986,13 +1065,16 @@ TEST_F(PictureLayerImplTest, DontAddLowResForSmallLayers) {
// Mask layers dont create low res since they always fit on one tile.
pending_layer_->SetIsMask(true);
active_layer_->SetIsMask(true);
- SetContentsScaleOnBothLayers(
- contents_scale, device_scale, page_scale, animating_transform);
+ SetContentsScaleOnBothLayers(contents_scale,
+ device_scale,
+ page_scale,
+ maximum_animation_scale,
+ animating_transform);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), contents_scale);
EXPECT_BOTH_EQ(num_tilings(), 1u);
}
-TEST_F(PictureLayerImplTest, DidLoseOutputSurface) {
+TEST_F(PictureLayerImplTest, ReleaseResources) {
gfx::Size tile_size(400, 400);
gfx::Size layer_bounds(1300, 1900);
@@ -1001,35 +1083,30 @@ TEST_F(PictureLayerImplTest, DidLoseOutputSurface) {
scoped_refptr<FakePicturePileImpl> active_pile =
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
- float result_scale_x, result_scale_y;
- gfx::Size result_bounds;
-
SetupTrees(pending_pile, active_pile);
EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
- pending_layer_->CalculateContentsScale(1.3f, // ideal contents scale
- 2.7f, // device scale
- 3.2f, // page cale
- false,
- &result_scale_x,
- &result_scale_y,
- &result_bounds);
+ SetupDrawPropertiesAndUpdateTiles(pending_layer_,
+ 1.3f, // ideal contents scale
+ 2.7f, // device scale
+ 3.2f, // page scale
+ 1.f, // maximum animation scale
+ false);
EXPECT_EQ(2u, pending_layer_->tilings()->num_tilings());
// All tilings should be removed when losing output surface.
- active_layer_->DidLoseOutputSurface();
+ active_layer_->ReleaseResources();
EXPECT_EQ(0u, active_layer_->tilings()->num_tilings());
- pending_layer_->DidLoseOutputSurface();
+ pending_layer_->ReleaseResources();
EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
// This should create new tilings.
- pending_layer_->CalculateContentsScale(1.3f, // ideal contents scale
- 2.7f, // device scale
- 3.2f, // page cale
- false,
- &result_scale_x,
- &result_scale_y,
- &result_bounds);
+ SetupDrawPropertiesAndUpdateTiles(pending_layer_,
+ 1.3f, // ideal contents scale
+ 2.7f, // device scale
+ 3.2f, // page scale
+ 1.f, // maximum animation scale
+ false);
EXPECT_EQ(2u, pending_layer_->tilings()->num_tilings());
}
@@ -1043,14 +1120,10 @@ TEST_F(PictureLayerImplTest, ClampTilesToToMaxTileSize) {
scoped_refptr<FakePicturePileImpl> active_pile =
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
- float result_scale_x, result_scale_y;
- gfx::Size result_bounds;
-
SetupTrees(pending_pile, active_pile);
EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
- pending_layer_->CalculateContentsScale(
- 1.f, 1.f, 1.f, false, &result_scale_x, &result_scale_y, &result_bounds);
+ SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, false);
ASSERT_EQ(2u, pending_layer_->tilings()->num_tilings());
pending_layer_->tilings()->tiling_at(0)->CreateAllTilesForTesting();
@@ -1063,7 +1136,7 @@ TEST_F(PictureLayerImplTest, ClampTilesToToMaxTileSize) {
EXPECT_EQ(gfx::Size(256, 256).ToString(),
tile->content_rect().size().ToString());
- pending_layer_->DidLoseOutputSurface();
+ pending_layer_->ReleaseResources();
// Change the max texture size on the output surface context.
scoped_ptr<TestWebGraphicsContext3D> context =
@@ -1073,8 +1146,7 @@ TEST_F(PictureLayerImplTest, ClampTilesToToMaxTileSize) {
host_impl_.InitializeRenderer(FakeOutputSurface::Create3d(
context.Pass()).PassAs<OutputSurface>());
- pending_layer_->CalculateContentsScale(
- 1.f, 1.f, 1.f, false, &result_scale_x, &result_scale_y, &result_bounds);
+ SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, false);
ASSERT_EQ(2u, pending_layer_->tilings()->num_tilings());
pending_layer_->tilings()->tiling_at(0)->CreateAllTilesForTesting();
@@ -1095,14 +1167,10 @@ TEST_F(PictureLayerImplTest, ClampSingleTileToToMaxTileSize) {
scoped_refptr<FakePicturePileImpl> active_pile =
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
- float result_scale_x, result_scale_y;
- gfx::Size result_bounds;
-
SetupTrees(pending_pile, active_pile);
EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
- pending_layer_->CalculateContentsScale(
- 1.f, 1.f, 1.f, false, &result_scale_x, &result_scale_y, &result_bounds);
+ SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, false);
ASSERT_LE(1u, pending_layer_->tilings()->num_tilings());
pending_layer_->tilings()->tiling_at(0)->CreateAllTilesForTesting();
@@ -1115,7 +1183,7 @@ TEST_F(PictureLayerImplTest, ClampSingleTileToToMaxTileSize) {
PictureLayerTiling* high_res_tiling = pending_layer_->tilings()->tiling_at(0);
EXPECT_EQ(1u, high_res_tiling->AllTilesForTesting().size());
- pending_layer_->DidLoseOutputSurface();
+ pending_layer_->ReleaseResources();
// Change the max texture size on the output surface context.
scoped_ptr<TestWebGraphicsContext3D> context =
@@ -1125,8 +1193,7 @@ TEST_F(PictureLayerImplTest, ClampSingleTileToToMaxTileSize) {
host_impl_.InitializeRenderer(FakeOutputSurface::Create3d(
context.Pass()).PassAs<OutputSurface>());
- pending_layer_->CalculateContentsScale(
- 1.f, 1.f, 1.f, false, &result_scale_x, &result_scale_y, &result_bounds);
+ SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, false);
ASSERT_LE(1u, pending_layer_->tilings()->num_tilings());
pending_layer_->tilings()->tiling_at(0)->CreateAllTilesForTesting();
@@ -1143,7 +1210,9 @@ TEST_F(PictureLayerImplTest, ClampSingleTileToToMaxTileSize) {
}
TEST_F(PictureLayerImplTest, DisallowTileDrawQuads) {
- MockQuadCuller quad_culler;
+ MockOcclusionTracker<LayerImpl> occlusion_tracker;
+ scoped_ptr<RenderPass> render_pass = RenderPass::Create();
+ MockQuadCuller quad_culler(render_pass.get(), &occlusion_tracker);
gfx::Size tile_size(400, 400);
gfx::Size layer_bounds(1300, 1900);
@@ -1155,7 +1224,6 @@ TEST_F(PictureLayerImplTest, DisallowTileDrawQuads) {
SetupTrees(pending_pile, active_pile);
- active_layer_->SetContentBounds(layer_bounds);
active_layer_->draw_properties().visible_content_rect =
gfx::Rect(layer_bounds);
@@ -1195,7 +1263,7 @@ TEST_F(PictureLayerImplTest, MarkRequiredNullTiles) {
TEST_F(PictureLayerImplTest, MarkRequiredOffscreenTiles) {
gfx::Size tile_size(100, 100);
- gfx::Size layer_bounds(200, 100);
+ gfx::Size layer_bounds(200, 200);
scoped_refptr<FakePicturePileImpl> pending_pile =
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
@@ -1207,12 +1275,12 @@ TEST_F(PictureLayerImplTest, MarkRequiredOffscreenTiles) {
host_impl_.pending_tree()->UpdateDrawProperties();
EXPECT_EQ(tiling->resolution(), HIGH_RESOLUTION);
+ pending_layer_->draw_properties().visible_content_rect =
+ gfx::Rect(0, 0, 100, 200);
+
// Fake set priorities.
- int tile_count = 0;
for (PictureLayerTiling::CoverageIterator iter(
- tiling,
- pending_layer_->contents_scale_x(),
- gfx::Rect(pending_layer_->visible_content_rect()));
+ tiling, pending_layer_->contents_scale_x(), gfx::Rect(layer_bounds));
iter;
++iter) {
if (!*iter)
@@ -1220,12 +1288,13 @@ TEST_F(PictureLayerImplTest, MarkRequiredOffscreenTiles) {
Tile* tile = *iter;
TilePriority priority;
priority.resolution = HIGH_RESOLUTION;
- if (++tile_count % 2) {
- priority.time_to_visible_in_seconds = 0.f;
- priority.distance_to_visible_in_pixels = 0.f;
+ gfx::Rect tile_bounds = iter.geometry_rect();
+ if (pending_layer_->visible_content_rect().Intersects(tile_bounds)) {
+ priority.priority_bin = TilePriority::NOW;
+ priority.distance_to_visible = 0.f;
} else {
- priority.time_to_visible_in_seconds = 1.f;
- priority.distance_to_visible_in_pixels = 1.f;
+ priority.priority_bin = TilePriority::SOON;
+ priority.distance_to_visible = 1.f;
}
tile->SetPriority(PENDING_TREE, priority);
}
@@ -1236,15 +1305,13 @@ TEST_F(PictureLayerImplTest, MarkRequiredOffscreenTiles) {
int num_offscreen = 0;
for (PictureLayerTiling::CoverageIterator iter(
- tiling,
- pending_layer_->contents_scale_x(),
- gfx::Rect(pending_layer_->visible_content_rect()));
+ tiling, pending_layer_->contents_scale_x(), gfx::Rect(layer_bounds));
iter;
++iter) {
if (!*iter)
continue;
const Tile* tile = *iter;
- if (tile->priority(PENDING_TREE).distance_to_visible_in_pixels == 0.f) {
+ if (tile->priority(PENDING_TREE).distance_to_visible == 0.f) {
EXPECT_TRUE(tile->required_for_activation());
num_visible++;
} else {
@@ -1276,8 +1343,28 @@ TEST_F(PictureLayerImplTest, HighResRequiredWhenUnsharedActiveAllReady) {
AssertNoTilesRequired(pending_layer_->LowResTiling());
}
-// TODO(enne): temporarily disabled: http://crbug.com/335289
-TEST_F(PictureLayerImplTest, DISABLED_NothingRequiredIfAllHighResTilesShared) {
+TEST_F(PictureLayerImplTest, HighResRequiredWhenMissingHighResFlagOn) {
+ gfx::Size layer_bounds(400, 400);
+ gfx::Size tile_size(100, 100);
+ SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
+
+ // All tiles shared (no invalidation).
+ CreateHighLowResAndSetAllTilesVisible();
+
+ // Verify active tree not ready.
+ Tile* some_active_tile =
+ active_layer_->HighResTiling()->AllTilesForTesting()[0];
+ EXPECT_FALSE(some_active_tile->IsReadyToDraw());
+
+ // When high res are required, even if the active tree is not ready,
+ // the high res tiles must be ready.
+ host_impl_.active_tree()->SetRequiresHighResToDraw();
+ pending_layer_->MarkVisibleResourcesAsRequired();
+ AssertAllTilesRequired(pending_layer_->HighResTiling());
+ AssertNoTilesRequired(pending_layer_->LowResTiling());
+}
+
+TEST_F(PictureLayerImplTest, NothingRequiredIfAllHighResTilesShared) {
gfx::Size layer_bounds(400, 400);
gfx::Size tile_size(100, 100);
SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
@@ -1295,19 +1382,18 @@ TEST_F(PictureLayerImplTest, DISABLED_NothingRequiredIfAllHighResTilesShared) {
AssertNoTilesRequired(pending_layer_->LowResTiling());
}
-// TODO(enne): temporarily disabled: http://crbug.com/335289
-TEST_F(PictureLayerImplTest, DISABLED_NothingRequiredIfActiveMissingTiles) {
+TEST_F(PictureLayerImplTest, NothingRequiredIfActiveMissingTiles) {
gfx::Size layer_bounds(400, 400);
gfx::Size tile_size(100, 100);
scoped_refptr<FakePicturePileImpl> pending_pile =
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
- // An arbitrary bogus outside the layer recording. Enough for the layer to
- // think it can create tiles, but not in bounds so all tiles are null.
- Region active_recorded_region;
- active_recorded_region.Union(gfx::Rect(1000, 1000, 1, 1));
+ // This pile will create tilings, but has no recordings so will not create any
+ // tiles. This is attempting to simulate scrolling past the end of recorded
+ // content on the active layer, where the recordings are so far away that
+ // no tiles are created.
scoped_refptr<FakePicturePileImpl> active_pile =
- FakePicturePileImpl::CreatePileWithRecordedRegion(
- tile_size, layer_bounds, active_recorded_region);
+ FakePicturePileImpl::CreateEmptyPileThatThinksItHasRecordings(
+ tile_size, layer_bounds);
SetupTrees(pending_pile, active_pile);
pending_layer_->set_fixed_tile_size(tile_size);
active_layer_->set_fixed_tile_size(tile_size);
@@ -1320,8 +1406,7 @@ TEST_F(PictureLayerImplTest, DISABLED_NothingRequiredIfActiveMissingTiles) {
EXPECT_EQ(active_layer_->HighResTiling()->AllTilesForTesting().size(), 0u);
// Since the active layer has no tiles at all, the pending layer doesn't
- // need content in order to activate. This is attempting to simulate
- // scrolling past the end of recorded content on the active layer.
+ // need content in order to activate.
pending_layer_->MarkVisibleResourcesAsRequired();
AssertNoTilesRequired(pending_layer_->HighResTiling());
AssertNoTilesRequired(pending_layer_->LowResTiling());
@@ -1352,6 +1437,25 @@ TEST_F(PictureLayerImplTest, HighResRequiredIfActiveCantHaveTiles) {
AssertNoTilesRequired(pending_layer_->LowResTiling());
}
+TEST_F(PictureLayerImplTest, HighResRequiredWhenActiveHasDifferentBounds) {
+ gfx::Size layer_bounds(200, 200);
+ gfx::Size tile_size(100, 100);
+ SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
+
+ gfx::Size pending_layer_bounds(400, 400);
+ pending_layer_->SetBounds(pending_layer_bounds);
+
+ CreateHighLowResAndSetAllTilesVisible();
+
+ active_layer_->SetAllTilesReady();
+
+ // Since the active layer has different bounds, the pending layer needs all
+ // high res tiles in order to activate.
+ pending_layer_->MarkVisibleResourcesAsRequired();
+ AssertAllTilesRequired(pending_layer_->HighResTiling());
+ AssertNoTilesRequired(pending_layer_->LowResTiling());
+}
+
TEST_F(PictureLayerImplTest, ActivateUninitializedLayer) {
gfx::Size tile_size(100, 100);
gfx::Size layer_bounds(400, 400);
@@ -1373,8 +1477,8 @@ TEST_F(PictureLayerImplTest, ActivateUninitializedLayer) {
// by a sync from the active layer. This could happen because if the
// pending layer has not been post-commit initialized it will attempt
// to sync from the active layer.
- bool default_lcd_text_setting = pending_layer_->is_using_lcd_text();
- pending_layer_->force_set_lcd_text(!default_lcd_text_setting);
+ float raster_page_scale = 10.f * pending_layer_->raster_page_scale();
+ pending_layer_->set_raster_page_scale(raster_page_scale);
EXPECT_TRUE(pending_layer_->needs_post_commit_initialization());
host_impl_.ActivatePendingTree();
@@ -1383,10 +1487,47 @@ TEST_F(PictureLayerImplTest, ActivateUninitializedLayer) {
host_impl_.active_tree()->LayerById(id_));
EXPECT_EQ(0u, active_layer_->num_tilings());
- EXPECT_EQ(!default_lcd_text_setting, active_layer_->is_using_lcd_text());
+ EXPECT_EQ(raster_page_scale, active_layer_->raster_page_scale());
EXPECT_FALSE(active_layer_->needs_post_commit_initialization());
}
+TEST_F(PictureLayerImplTest, RemoveInvalidTilesOnActivation) {
+ SetupDefaultTrees(gfx::Size(1500, 1500));
+ AddDefaultTilingsWithInvalidation(gfx::Rect(0, 0, 1, 1));
+
+ FakePictureLayerImpl* recycled_layer = pending_layer_;
+ host_impl_.ActivatePendingTree();
+
+ active_layer_ = static_cast<FakePictureLayerImpl*>(
+ host_impl_.active_tree()->LayerById(id_));
+
+ EXPECT_EQ(3u, active_layer_->num_tilings());
+ EXPECT_EQ(3u, recycled_layer->num_tilings());
+ EXPECT_FALSE(host_impl_.pending_tree());
+ for (size_t i = 0; i < active_layer_->num_tilings(); ++i) {
+ PictureLayerTiling* active_tiling = active_layer_->tilings()->tiling_at(i);
+ PictureLayerTiling* recycled_tiling =
+ recycled_layer->tilings()->tiling_at(i);
+
+ ASSERT_TRUE(active_tiling);
+ ASSERT_TRUE(recycled_tiling);
+
+ EXPECT_TRUE(active_tiling->TileAt(0, 0));
+ EXPECT_TRUE(active_tiling->TileAt(1, 0));
+ EXPECT_TRUE(active_tiling->TileAt(0, 1));
+ EXPECT_TRUE(active_tiling->TileAt(1, 1));
+
+ EXPECT_FALSE(recycled_tiling->TileAt(0, 0));
+ EXPECT_TRUE(recycled_tiling->TileAt(1, 0));
+ EXPECT_TRUE(recycled_tiling->TileAt(0, 1));
+ EXPECT_TRUE(recycled_tiling->TileAt(1, 1));
+
+ EXPECT_EQ(active_tiling->TileAt(1, 0), recycled_tiling->TileAt(1, 0));
+ EXPECT_EQ(active_tiling->TileAt(0, 1), recycled_tiling->TileAt(0, 1));
+ EXPECT_EQ(active_tiling->TileAt(1, 1), recycled_tiling->TileAt(1, 1));
+ }
+}
+
TEST_F(PictureLayerImplTest, SyncTilingAfterReleaseResource) {
SetupDefaultTrees(gfx::Size(10, 10));
host_impl_.active_tree()->UpdateDrawProperties();
@@ -1395,17 +1536,124 @@ TEST_F(PictureLayerImplTest, SyncTilingAfterReleaseResource) {
// Contrived unit test of a real crash. A layer is transparent during a
// context loss, and later becomes opaque, causing active layer SyncTiling to
// be called.
- const float tile_scale = 2.f;
- active_layer_->DidLoseOutputSurface();
- EXPECT_FALSE(active_layer_->tilings()->TilingAtScale(tile_scale));
- pending_layer_->AddTiling(2.f);
- EXPECT_TRUE(active_layer_->tilings()->TilingAtScale(tile_scale));
+ float new_scale = 1.f;
+ active_layer_->ReleaseResources();
+ pending_layer_->ReleaseResources();
+ EXPECT_FALSE(active_layer_->tilings()->TilingAtScale(new_scale));
+ pending_layer_->AddTiling(new_scale);
+ EXPECT_TRUE(active_layer_->tilings()->TilingAtScale(new_scale));
+
+ // UpdateDrawProperties early-outs if the tree doesn't need it. It is also
+ // responsible for calling ManageTilings. These checks verify that
+ // ReleaseResources has set needs update draw properties so that the
+ // new tiling gets the appropriate resolution set in ManageTilings.
+ EXPECT_TRUE(host_impl_.active_tree()->needs_update_draw_properties());
+ host_impl_.active_tree()->UpdateDrawProperties();
+ PictureLayerTiling* high_res =
+ active_layer_->tilings()->TilingAtScale(new_scale);
+ ASSERT_TRUE(!!high_res);
+ EXPECT_EQ(HIGH_RESOLUTION, high_res->resolution());
+}
+
+TEST_F(PictureLayerImplTest, SyncTilingAfterGpuRasterizationToggles) {
+ SetupDefaultTrees(gfx::Size(10, 10));
+
+ const float kScale = 1.f;
+ pending_layer_->AddTiling(kScale);
+ EXPECT_TRUE(pending_layer_->tilings()->TilingAtScale(kScale));
+ EXPECT_TRUE(active_layer_->tilings()->TilingAtScale(kScale));
+
+ // Gpu rasterization is disabled by default.
+ EXPECT_FALSE(host_impl_.use_gpu_rasterization());
+ // Toggling the gpu rasterization clears all tilings on both trees.
+ host_impl_.SetUseGpuRasterization(true);
+ EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
+ EXPECT_EQ(0u, active_layer_->tilings()->num_tilings());
+
+ // Make sure that we can still add tiling to the pending layer,
+ // that gets synced to the active layer.
+ pending_layer_->AddTiling(kScale);
+ EXPECT_TRUE(pending_layer_->tilings()->TilingAtScale(kScale));
+ EXPECT_TRUE(active_layer_->tilings()->TilingAtScale(kScale));
+
+ // Toggling the gpu rasterization clears all tilings on both trees.
+ EXPECT_TRUE(host_impl_.use_gpu_rasterization());
+ host_impl_.SetUseGpuRasterization(false);
+ EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
+ EXPECT_EQ(0u, active_layer_->tilings()->num_tilings());
+}
+
+TEST_F(PictureLayerImplTest, HighResCreatedWhenBoundsShrink) {
+ SetupDefaultTrees(gfx::Size(10, 10));
+ host_impl_.active_tree()->UpdateDrawProperties();
+ EXPECT_FALSE(host_impl_.active_tree()->needs_update_draw_properties());
+
+ SetupDrawPropertiesAndUpdateTiles(
+ active_layer_, 0.5f, 0.5f, 0.5f, 0.5f, false);
+ active_layer_->tilings()->RemoveAllTilings();
+ PictureLayerTiling* tiling = active_layer_->tilings()->AddTiling(0.5f);
+ active_layer_->tilings()->AddTiling(1.5f);
+ active_layer_->tilings()->AddTiling(0.25f);
+ tiling->set_resolution(HIGH_RESOLUTION);
+
+ // Sanity checks.
+ ASSERT_EQ(3u, active_layer_->tilings()->num_tilings());
+ ASSERT_EQ(tiling, active_layer_->tilings()->TilingAtScale(0.5f));
+
+ // Now, set the bounds to be 1x1 (so that minimum contents scale becomes
+ // 1.0f). Note that we should also ensure that the pending layer needs post
+ // commit initialization, since this is what would happen during commit. In
+ // other words we want the pending layer to sync from the active layer.
+ pending_layer_->SetBounds(gfx::Size(1, 1));
+ pending_layer_->SetNeedsPostCommitInitialization();
+ pending_layer_->set_twin_layer(NULL);
+ active_layer_->set_twin_layer(NULL);
+ EXPECT_TRUE(pending_layer_->needs_post_commit_initialization());
+
+ // Update the draw properties: sync from active tree should happen here.
+ host_impl_.pending_tree()->UpdateDrawProperties();
+
+ // Another sanity check.
+ ASSERT_EQ(1.f, pending_layer_->MinimumContentsScale());
+
+ // Now we should've synced 1.5f tiling, since that's the only one that doesn't
+ // violate minimum contents scale. At the same time, we should've created a
+ // new high res tiling at scale 1.0f.
+ EXPECT_EQ(2u, pending_layer_->tilings()->num_tilings());
+ ASSERT_TRUE(pending_layer_->tilings()->TilingAtScale(1.0f));
+ EXPECT_EQ(HIGH_RESOLUTION,
+ pending_layer_->tilings()->TilingAtScale(1.0f)->resolution());
+ ASSERT_TRUE(pending_layer_->tilings()->TilingAtScale(1.5f));
+ EXPECT_EQ(NON_IDEAL_RESOLUTION,
+ pending_layer_->tilings()->TilingAtScale(1.5f)->resolution());
+}
+
+TEST_F(PictureLayerImplTest, NoLowResTilingWithGpuRasterization) {
+ gfx::Size default_tile_size(host_impl_.settings().default_tile_size);
+ gfx::Size layer_bounds(default_tile_size.width() * 4,
+ default_tile_size.height() * 4);
+
+ SetupDefaultTrees(layer_bounds);
+ EXPECT_FALSE(host_impl_.use_gpu_rasterization());
+ EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
+ SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, false);
+ // Should have a low-res and a high-res tiling.
+ ASSERT_EQ(2u, pending_layer_->tilings()->num_tilings());
+
+ ResetTilingsAndRasterScales();
+
+ host_impl_.SetUseGpuRasterization(true);
+ EXPECT_TRUE(host_impl_.use_gpu_rasterization());
+ SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, false);
+
+ // Should only have the high-res tiling.
+ ASSERT_EQ(1u, pending_layer_->tilings()->num_tilings());
}
TEST_F(PictureLayerImplTest, NoTilingIfDoesNotDrawContent) {
// Set up layers with tilings.
SetupDefaultTrees(gfx::Size(10, 10));
- SetContentsScaleOnBothLayers(1.f, 1.f, 1.f, false);
+ SetContentsScaleOnBothLayers(1.f, 1.f, 1.f, 1.f, false);
pending_layer_->PushPropertiesTo(active_layer_);
EXPECT_TRUE(pending_layer_->DrawsContent());
EXPECT_TRUE(pending_layer_->CanHaveTilings());
@@ -1426,7 +1674,7 @@ TEST_F(PictureLayerImplTest, FirstTilingDuringPinch) {
SetupDefaultTrees(gfx::Size(10, 10));
host_impl_.PinchGestureBegin();
float high_res_scale = 2.3f;
- SetContentsScaleOnBothLayers(high_res_scale, 1.f, 1.f, false);
+ SetContentsScaleOnBothLayers(high_res_scale, 1.f, 1.f, 1.f, false);
ASSERT_GE(pending_layer_->num_tilings(), 0u);
EXPECT_FLOAT_EQ(high_res_scale,
@@ -1439,7 +1687,7 @@ TEST_F(PictureLayerImplTest, FirstTilingTooSmall) {
float high_res_scale = 0.0001f;
EXPECT_GT(pending_layer_->MinimumContentsScale(), high_res_scale);
- SetContentsScaleOnBothLayers(high_res_scale, 1.f, 1.f, false);
+ SetContentsScaleOnBothLayers(high_res_scale, 1.f, 1.f, 1.f, false);
ASSERT_GE(pending_layer_->num_tilings(), 0u);
EXPECT_FLOAT_EQ(pending_layer_->MinimumContentsScale(),
@@ -1450,7 +1698,7 @@ TEST_F(PictureLayerImplTest, PinchingTooSmall) {
SetupDefaultTrees(gfx::Size(10, 10));
float contents_scale = 0.15f;
- SetContentsScaleOnBothLayers(contents_scale, 1.f, 1.f, false);
+ SetContentsScaleOnBothLayers(contents_scale, 1.f, 1.f, 1.f, false);
ASSERT_GE(pending_layer_->num_tilings(), 0u);
EXPECT_FLOAT_EQ(contents_scale,
@@ -1462,8 +1710,7 @@ TEST_F(PictureLayerImplTest, PinchingTooSmall) {
EXPECT_LT(page_scale * contents_scale,
pending_layer_->MinimumContentsScale());
-
- SetContentsScaleOnBothLayers(contents_scale, 1.f, page_scale, false);
+ SetContentsScaleOnBothLayers(contents_scale, 1.f, page_scale, 1.f, false);
ASSERT_GE(pending_layer_->num_tilings(), 0u);
EXPECT_FLOAT_EQ(pending_layer_->MinimumContentsScale(),
pending_layer_->HighResTiling()->contents_scale());
@@ -1471,13 +1718,12 @@ TEST_F(PictureLayerImplTest, PinchingTooSmall) {
class DeferredInitPictureLayerImplTest : public PictureLayerImplTest {
public:
- DeferredInitPictureLayerImplTest()
- : PictureLayerImplTest(ImplSidePaintingSettings()) {}
-
virtual void InitializeRenderer() OVERRIDE {
- host_impl_.InitializeRenderer(FakeOutputSurface::CreateDeferredGL(
- scoped_ptr<SoftwareOutputDevice>(new SoftwareOutputDevice))
- .PassAs<OutputSurface>());
+ bool delegated_rendering = false;
+ host_impl_.InitializeRenderer(
+ FakeOutputSurface::CreateDeferredGL(
+ scoped_ptr<SoftwareOutputDevice>(new SoftwareOutputDevice),
+ delegated_rendering).PassAs<OutputSurface>());
}
virtual void SetUp() OVERRIDE {
@@ -1500,8 +1746,7 @@ class DeferredInitPictureLayerImplTest : public PictureLayerImplTest {
// that trees need update draw properties after deferred initialization.
// However, this is also a regression test for PictureLayerImpl in that
// not having this update will cause a crash.
-TEST_F(DeferredInitPictureLayerImplTest,
- PreventUpdateTilePrioritiesDuringLostContext) {
+TEST_F(DeferredInitPictureLayerImplTest, PreventUpdateTilesDuringLostContext) {
host_impl_.pending_tree()->UpdateDrawProperties();
host_impl_.active_tree()->UpdateDrawProperties();
EXPECT_FALSE(host_impl_.pending_tree()->needs_update_draw_properties());
@@ -1510,7 +1755,7 @@ TEST_F(DeferredInitPictureLayerImplTest,
FakeOutputSurface* fake_output_surface =
static_cast<FakeOutputSurface*>(host_impl_.output_surface());
ASSERT_TRUE(fake_output_surface->InitializeAndSetContext3d(
- TestContextProvider::Create(), NULL));
+ TestContextProvider::Create()));
// These will crash PictureLayerImpl if this is not true.
ASSERT_TRUE(host_impl_.pending_tree()->needs_update_draw_properties());
@@ -1518,5 +1763,1105 @@ TEST_F(DeferredInitPictureLayerImplTest,
host_impl_.active_tree()->UpdateDrawProperties();
}
+TEST_F(PictureLayerImplTest, HighResTilingDuringAnimationForCpuRasterization) {
+ gfx::Size layer_bounds(100, 100);
+ gfx::Size viewport_size(1000, 1000);
+ SetupDefaultTrees(layer_bounds);
+ host_impl_.SetViewportSize(viewport_size);
+
+ float contents_scale = 1.f;
+ float device_scale = 1.3f;
+ float page_scale = 1.4f;
+ float maximum_animation_scale = 1.f;
+ bool animating_transform = false;
+
+ SetContentsScaleOnBothLayers(contents_scale,
+ device_scale,
+ page_scale,
+ maximum_animation_scale,
+ animating_transform);
+ EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 1.f);
+
+ // Since we're CPU-rasterizing, starting an animation should cause tiling
+ // resolution to get set to the maximum animation scale factor.
+ animating_transform = true;
+ maximum_animation_scale = 3.f;
+ contents_scale = 2.f;
+
+ SetContentsScaleOnBothLayers(contents_scale,
+ device_scale,
+ page_scale,
+ maximum_animation_scale,
+ animating_transform);
+ EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 3.f);
+
+ // Further changes to scale during the animation should not cause a new
+ // high-res tiling to get created.
+ contents_scale = 4.f;
+ maximum_animation_scale = 5.f;
+
+ SetContentsScaleOnBothLayers(contents_scale,
+ device_scale,
+ page_scale,
+ maximum_animation_scale,
+ animating_transform);
+ EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 3.f);
+
+ // Once we stop animating, a new high-res tiling should be created.
+ animating_transform = false;
+
+ SetContentsScaleOnBothLayers(contents_scale,
+ device_scale,
+ page_scale,
+ maximum_animation_scale,
+ animating_transform);
+ EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 4.f);
+
+ // When animating with an unknown maximum animation scale factor, a new
+ // high-res tiling should be created at the animation's initial scale.
+ animating_transform = true;
+ contents_scale = 2.f;
+ maximum_animation_scale = 0.f;
+
+ SetContentsScaleOnBothLayers(contents_scale,
+ device_scale,
+ page_scale,
+ maximum_animation_scale,
+ animating_transform);
+ EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 2.f);
+
+ // Further changes to scale during the animation should not cause a new
+ // high-res tiling to get created.
+ contents_scale = 3.f;
+
+ SetContentsScaleOnBothLayers(contents_scale,
+ device_scale,
+ page_scale,
+ maximum_animation_scale,
+ animating_transform);
+ EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 2.f);
+
+ // Once we stop animating, a new high-res tiling should be created.
+ animating_transform = false;
+ contents_scale = 4.f;
+
+ SetContentsScaleOnBothLayers(contents_scale,
+ device_scale,
+ page_scale,
+ maximum_animation_scale,
+ animating_transform);
+ EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 4.f);
+
+ // When animating with a maxmium animation scale factor that is so large
+ // that the layer grows larger than the viewport at this scale, a new
+ // high-res tiling should get created at the animation's initial scale, not
+ // at its maximum scale.
+ animating_transform = true;
+ contents_scale = 2.f;
+ maximum_animation_scale = 11.f;
+
+ SetContentsScaleOnBothLayers(contents_scale,
+ device_scale,
+ page_scale,
+ maximum_animation_scale,
+ animating_transform);
+ EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 2.f);
+
+ // Once we stop animating, a new high-res tiling should be created.
+ animating_transform = false;
+ contents_scale = 11.f;
+
+ SetContentsScaleOnBothLayers(contents_scale,
+ device_scale,
+ page_scale,
+ maximum_animation_scale,
+ animating_transform);
+ EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 11.f);
+
+ // When animating with a maxmium animation scale factor that is so large
+ // that the layer grows larger than the viewport at this scale, and where
+ // the intial source scale is < 1, a new high-res tiling should get created
+ // at source scale 1.
+ animating_transform = true;
+ contents_scale = 0.1f;
+ maximum_animation_scale = 11.f;
+
+ SetContentsScaleOnBothLayers(contents_scale,
+ device_scale,
+ page_scale,
+ maximum_animation_scale,
+ animating_transform);
+ EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), device_scale * page_scale);
+
+ // Once we stop animating, a new high-res tiling should be created.
+ animating_transform = false;
+ contents_scale = 11.f;
+
+ SetContentsScaleOnBothLayers(contents_scale,
+ device_scale,
+ page_scale,
+ maximum_animation_scale,
+ animating_transform);
+ EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 11.f);
+}
+
+TEST_F(PictureLayerImplTest, LayerRasterTileIterator) {
+ gfx::Size tile_size(100, 100);
+ gfx::Size layer_bounds(1000, 1000);
+
+ scoped_refptr<FakePicturePileImpl> pending_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+
+ SetupPendingTree(pending_pile);
+
+ ASSERT_TRUE(pending_layer_->CanHaveTilings());
+
+ float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
+
+ // Empty iterator
+ PictureLayerImpl::LayerRasterTileIterator it;
+ EXPECT_FALSE(it);
+
+ // No tilings.
+ it = PictureLayerImpl::LayerRasterTileIterator(pending_layer_, false);
+ EXPECT_FALSE(it);
+
+ pending_layer_->AddTiling(low_res_factor);
+ pending_layer_->AddTiling(0.3f);
+ pending_layer_->AddTiling(0.7f);
+ PictureLayerTiling* high_res_tiling = pending_layer_->AddTiling(1.0f);
+ pending_layer_->AddTiling(2.0f);
+
+ host_impl_.SetViewportSize(gfx::Size(500, 500));
+ host_impl_.pending_tree()->UpdateDrawProperties();
+
+ std::set<Tile*> unique_tiles;
+ bool reached_prepaint = false;
+ size_t non_ideal_tile_count = 0u;
+ size_t low_res_tile_count = 0u;
+ size_t high_res_tile_count = 0u;
+ for (it = PictureLayerImpl::LayerRasterTileIterator(pending_layer_, false);
+ it;
+ ++it) {
+ Tile* tile = *it;
+ TilePriority priority = tile->priority(PENDING_TREE);
+
+ EXPECT_TRUE(tile);
+
+ // Non-high res tiles only get visible tiles. Also, prepaint should only
+ // come at the end of the iteration.
+ if (priority.resolution != HIGH_RESOLUTION)
+ EXPECT_EQ(TilePriority::NOW, priority.priority_bin);
+ else if (reached_prepaint)
+ EXPECT_NE(TilePriority::NOW, priority.priority_bin);
+ else
+ reached_prepaint = priority.priority_bin != TilePriority::NOW;
+
+ non_ideal_tile_count += priority.resolution == NON_IDEAL_RESOLUTION;
+ low_res_tile_count += priority.resolution == LOW_RESOLUTION;
+ high_res_tile_count += priority.resolution == HIGH_RESOLUTION;
+
+ unique_tiles.insert(tile);
+ }
+
+ EXPECT_TRUE(reached_prepaint);
+ EXPECT_EQ(0u, non_ideal_tile_count);
+ EXPECT_EQ(1u, low_res_tile_count);
+ EXPECT_EQ(16u, high_res_tile_count);
+ EXPECT_EQ(low_res_tile_count + high_res_tile_count + non_ideal_tile_count,
+ unique_tiles.size());
+
+ std::vector<Tile*> high_res_tiles = high_res_tiling->AllTilesForTesting();
+ for (std::vector<Tile*>::iterator tile_it = high_res_tiles.begin();
+ tile_it != high_res_tiles.end();
+ ++tile_it) {
+ Tile* tile = *tile_it;
+ ManagedTileState::TileVersion& tile_version =
+ tile->GetTileVersionForTesting(
+ tile->DetermineRasterModeForTree(ACTIVE_TREE));
+ tile_version.SetSolidColorForTesting(SK_ColorRED);
+ }
+
+ non_ideal_tile_count = 0;
+ low_res_tile_count = 0;
+ high_res_tile_count = 0;
+ for (it = PictureLayerImpl::LayerRasterTileIterator(pending_layer_, false);
+ it;
+ ++it) {
+ Tile* tile = *it;
+ TilePriority priority = tile->priority(PENDING_TREE);
+
+ EXPECT_TRUE(tile);
+
+ non_ideal_tile_count += priority.resolution == NON_IDEAL_RESOLUTION;
+ low_res_tile_count += priority.resolution == LOW_RESOLUTION;
+ high_res_tile_count += priority.resolution == HIGH_RESOLUTION;
+ }
+
+ EXPECT_EQ(0u, non_ideal_tile_count);
+ EXPECT_EQ(1u, low_res_tile_count);
+ EXPECT_EQ(0u, high_res_tile_count);
+}
+
+TEST_F(PictureLayerImplTest, LayerEvictionTileIterator) {
+ gfx::Size tile_size(100, 100);
+ gfx::Size layer_bounds(1000, 1000);
+
+ scoped_refptr<FakePicturePileImpl> pending_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+
+ SetupPendingTree(pending_pile);
+
+ ASSERT_TRUE(pending_layer_->CanHaveTilings());
+
+ float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
+
+ std::vector<PictureLayerTiling*> tilings;
+ tilings.push_back(pending_layer_->AddTiling(low_res_factor));
+ tilings.push_back(pending_layer_->AddTiling(0.3f));
+ tilings.push_back(pending_layer_->AddTiling(0.7f));
+ tilings.push_back(pending_layer_->AddTiling(1.0f));
+ tilings.push_back(pending_layer_->AddTiling(2.0f));
+
+ host_impl_.SetViewportSize(gfx::Size(500, 500));
+ host_impl_.pending_tree()->UpdateDrawProperties();
+
+ std::vector<Tile*> all_tiles;
+ for (std::vector<PictureLayerTiling*>::iterator tiling_iterator =
+ tilings.begin();
+ tiling_iterator != tilings.end();
+ ++tiling_iterator) {
+ std::vector<Tile*> tiles = (*tiling_iterator)->AllTilesForTesting();
+ std::copy(tiles.begin(), tiles.end(), std::back_inserter(all_tiles));
+ }
+
+ std::set<Tile*> all_tiles_set(all_tiles.begin(), all_tiles.end());
+
+ bool mark_required = false;
+ for (std::vector<Tile*>::iterator it = all_tiles.begin();
+ it != all_tiles.end();
+ ++it) {
+ Tile* tile = *it;
+ if (mark_required)
+ tile->MarkRequiredForActivation();
+ mark_required = !mark_required;
+ }
+
+ // Sanity checks.
+ EXPECT_EQ(91u, all_tiles.size());
+ EXPECT_EQ(91u, all_tiles_set.size());
+
+ // Empty iterator.
+ PictureLayerImpl::LayerEvictionTileIterator it;
+ EXPECT_FALSE(it);
+
+ // Tiles don't have resources yet.
+ it = PictureLayerImpl::LayerEvictionTileIterator(
+ pending_layer_, SAME_PRIORITY_FOR_BOTH_TREES);
+ EXPECT_FALSE(it);
+
+ host_impl_.tile_manager()->InitializeTilesWithResourcesForTesting(all_tiles);
+
+ std::set<Tile*> unique_tiles;
+ float expected_scales[] = {2.0f, 0.3f, 0.7f, low_res_factor, 1.0f};
+ size_t scale_index = 0;
+ bool reached_visible = false;
+ bool reached_required = false;
+ Tile* last_tile = NULL;
+ for (it = PictureLayerImpl::LayerEvictionTileIterator(
+ pending_layer_, SAME_PRIORITY_FOR_BOTH_TREES);
+ it;
+ ++it) {
+ Tile* tile = *it;
+ if (!last_tile)
+ last_tile = tile;
+
+ EXPECT_TRUE(tile);
+
+ TilePriority priority = tile->priority(PENDING_TREE);
+
+ if (priority.priority_bin == TilePriority::NOW) {
+ reached_visible = true;
+ last_tile = tile;
+ break;
+ }
+
+ if (reached_required) {
+ EXPECT_TRUE(tile->required_for_activation());
+ } else if (tile->required_for_activation()) {
+ reached_required = true;
+ scale_index = 0;
+ }
+
+ while (std::abs(tile->contents_scale() - expected_scales[scale_index]) >
+ std::numeric_limits<float>::epsilon()) {
+ ++scale_index;
+ ASSERT_LT(scale_index, arraysize(expected_scales));
+ }
+
+ EXPECT_FLOAT_EQ(tile->contents_scale(), expected_scales[scale_index]);
+ unique_tiles.insert(tile);
+
+ // If the tile is the same rough bin as last tile (same activation, bin, and
+ // scale), then distance should be decreasing.
+ if (tile->required_for_activation() ==
+ last_tile->required_for_activation() &&
+ priority.priority_bin ==
+ last_tile->priority(PENDING_TREE).priority_bin &&
+ std::abs(tile->contents_scale() - last_tile->contents_scale()) <
+ std::numeric_limits<float>::epsilon()) {
+ EXPECT_LE(priority.distance_to_visible,
+ last_tile->priority(PENDING_TREE).distance_to_visible);
+ }
+
+ last_tile = tile;
+ }
+
+ EXPECT_TRUE(reached_visible);
+ EXPECT_TRUE(reached_required);
+ EXPECT_EQ(65u, unique_tiles.size());
+
+ scale_index = 0;
+ reached_required = false;
+ for (; it; ++it) {
+ Tile* tile = *it;
+ EXPECT_TRUE(tile);
+
+ TilePriority priority = tile->priority(PENDING_TREE);
+ EXPECT_EQ(TilePriority::NOW, priority.priority_bin);
+
+ if (reached_required) {
+ EXPECT_TRUE(tile->required_for_activation());
+ } else if (tile->required_for_activation()) {
+ reached_required = true;
+ scale_index = 0;
+ }
+
+ while (std::abs(tile->contents_scale() - expected_scales[scale_index]) >
+ std::numeric_limits<float>::epsilon()) {
+ ++scale_index;
+ ASSERT_LT(scale_index, arraysize(expected_scales));
+ }
+
+ EXPECT_FLOAT_EQ(tile->contents_scale(), expected_scales[scale_index]);
+ unique_tiles.insert(tile);
+ }
+
+ EXPECT_TRUE(reached_required);
+ EXPECT_EQ(all_tiles_set.size(), unique_tiles.size());
+}
+
+TEST_F(PictureLayerImplTest, Occlusion) {
+ gfx::Size tile_size(102, 102);
+ gfx::Size layer_bounds(1000, 1000);
+ gfx::Size viewport_size(1000, 1000);
+
+ LayerTestCommon::LayerImplTest impl;
+
+ scoped_refptr<FakePicturePileImpl> pending_pile =
+ FakePicturePileImpl::CreateFilledPile(layer_bounds, layer_bounds);
+ SetupPendingTree(pending_pile);
+ pending_layer_->SetBounds(layer_bounds);
+ ActivateTree();
+ active_layer_->set_fixed_tile_size(tile_size);
+
+ host_impl_.SetViewportSize(viewport_size);
+ host_impl_.active_tree()->UpdateDrawProperties();
+
+ std::vector<Tile*> tiles =
+ active_layer_->HighResTiling()->AllTilesForTesting();
+ host_impl_.tile_manager()->InitializeTilesWithResourcesForTesting(tiles);
+
+ {
+ SCOPED_TRACE("No occlusion");
+ gfx::Rect occluded;
+ impl.AppendQuadsWithOcclusion(active_layer_, occluded);
+
+ LayerTestCommon::VerifyQuadsExactlyCoverRect(impl.quad_list(),
+ gfx::Rect(layer_bounds));
+ EXPECT_EQ(100u, impl.quad_list().size());
+ }
+
+ {
+ SCOPED_TRACE("Full occlusion");
+ gfx::Rect occluded(active_layer_->visible_content_rect());
+ impl.AppendQuadsWithOcclusion(active_layer_, occluded);
+
+ LayerTestCommon::VerifyQuadsExactlyCoverRect(impl.quad_list(), gfx::Rect());
+ EXPECT_EQ(impl.quad_list().size(), 0u);
+ }
+
+ {
+ SCOPED_TRACE("Partial occlusion");
+ gfx::Rect occluded(150, 0, 200, 1000);
+ impl.AppendQuadsWithOcclusion(active_layer_, occluded);
+
+ size_t partially_occluded_count = 0;
+ LayerTestCommon::VerifyQuadsCoverRectWithOcclusion(
+ impl.quad_list(),
+ gfx::Rect(layer_bounds),
+ occluded,
+ &partially_occluded_count);
+ // The layer outputs one quad, which is partially occluded.
+ EXPECT_EQ(100u - 10u, impl.quad_list().size());
+ EXPECT_EQ(10u + 10u, partially_occluded_count);
+ }
+}
+
+TEST_F(PictureLayerImplTest, RasterScaleChangeWithoutAnimation) {
+ gfx::Size tile_size(host_impl_.settings().default_tile_size);
+ SetupDefaultTrees(tile_size);
+
+ float contents_scale = 2.f;
+ float device_scale = 1.f;
+ float page_scale = 1.f;
+ float maximum_animation_scale = 1.f;
+ bool animating_transform = false;
+
+ SetContentsScaleOnBothLayers(contents_scale,
+ device_scale,
+ page_scale,
+ maximum_animation_scale,
+ animating_transform);
+ EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 2.f);
+
+ // Changing the source scale without being in an animation will cause
+ // the layer to reset its source scale to 1.f.
+ contents_scale = 3.f;
+
+ SetContentsScaleOnBothLayers(contents_scale,
+ device_scale,
+ page_scale,
+ maximum_animation_scale,
+ animating_transform);
+ EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 1.f);
+
+ // Further changes to the source scale will no longer be reflected in the
+ // contents scale.
+ contents_scale = 0.5f;
+
+ SetContentsScaleOnBothLayers(contents_scale,
+ device_scale,
+ page_scale,
+ maximum_animation_scale,
+ animating_transform);
+ EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 1.f);
+}
+
+TEST_F(PictureLayerImplTest, LowResReadyToDrawNotEnoughToActivate) {
+ gfx::Size tile_size(100, 100);
+ gfx::Size layer_bounds(1000, 1000);
+
+ SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
+
+ // Make sure some tiles are not shared.
+ pending_layer_->set_invalidation(gfx::Rect(gfx::Point(50, 50), tile_size));
+
+ CreateHighLowResAndSetAllTilesVisible();
+ active_layer_->SetAllTilesReady();
+ pending_layer_->MarkVisibleResourcesAsRequired();
+
+ // All pending layer tiles required are not ready.
+ EXPECT_FALSE(pending_layer_->AllTilesRequiredForActivationAreReadyToDraw());
+
+ // Initialize all low-res tiles.
+ pending_layer_->SetAllTilesReadyInTiling(pending_layer_->LowResTiling());
+
+ // Low-res tiles should not be enough.
+ EXPECT_FALSE(pending_layer_->AllTilesRequiredForActivationAreReadyToDraw());
+
+ // Initialize remaining tiles.
+ pending_layer_->SetAllTilesReady();
+
+ EXPECT_TRUE(pending_layer_->AllTilesRequiredForActivationAreReadyToDraw());
+}
+
+TEST_F(PictureLayerImplTest, HighResReadyToDrawNotEnoughToActivate) {
+ gfx::Size tile_size(100, 100);
+ gfx::Size layer_bounds(1000, 1000);
+
+ SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
+
+ // Make sure some tiles are not shared.
+ pending_layer_->set_invalidation(gfx::Rect(gfx::Point(50, 50), tile_size));
+
+ CreateHighLowResAndSetAllTilesVisible();
+ active_layer_->SetAllTilesReady();
+ pending_layer_->MarkVisibleResourcesAsRequired();
+
+ // All pending layer tiles required are not ready.
+ EXPECT_FALSE(pending_layer_->AllTilesRequiredForActivationAreReadyToDraw());
+
+ // Initialize all high-res tiles.
+ pending_layer_->SetAllTilesReadyInTiling(pending_layer_->HighResTiling());
+
+ // High-res tiles should not be enough.
+ EXPECT_FALSE(pending_layer_->AllTilesRequiredForActivationAreReadyToDraw());
+
+ // Initialize remaining tiles.
+ pending_layer_->SetAllTilesReady();
+
+ EXPECT_TRUE(pending_layer_->AllTilesRequiredForActivationAreReadyToDraw());
+}
+
+class NoLowResTilingsSettings : public ImplSidePaintingSettings {
+ public:
+ NoLowResTilingsSettings() { create_low_res_tiling = false; }
+};
+
+class NoLowResPictureLayerImplTest : public PictureLayerImplTest {
+ public:
+ NoLowResPictureLayerImplTest()
+ : PictureLayerImplTest(NoLowResTilingsSettings()) {}
+};
+
+TEST_F(NoLowResPictureLayerImplTest, ManageTilingsCreatesTilings) {
+ gfx::Size tile_size(400, 400);
+ gfx::Size layer_bounds(1300, 1900);
+
+ scoped_refptr<FakePicturePileImpl> pending_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+ scoped_refptr<FakePicturePileImpl> active_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+
+ SetupTrees(pending_pile, active_pile);
+ EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
+
+ float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
+ EXPECT_LT(low_res_factor, 1.f);
+
+ SetupDrawPropertiesAndUpdateTiles(pending_layer_,
+ 6.f, // ideal contents scale
+ 3.f, // device scale
+ 2.f, // page scale
+ 1.f, // maximum animation scale
+ false);
+ ASSERT_EQ(1u, pending_layer_->tilings()->num_tilings());
+ EXPECT_FLOAT_EQ(6.f,
+ pending_layer_->tilings()->tiling_at(0)->contents_scale());
+
+ // If we change the page scale factor, then we should get new tilings.
+ SetupDrawPropertiesAndUpdateTiles(pending_layer_,
+ 6.6f, // ideal contents scale
+ 3.f, // device scale
+ 2.2f, // page scale
+ 1.f, // maximum animation scale
+ false);
+ ASSERT_EQ(2u, pending_layer_->tilings()->num_tilings());
+ EXPECT_FLOAT_EQ(6.6f,
+ pending_layer_->tilings()->tiling_at(0)->contents_scale());
+
+ // If we change the device scale factor, then we should get new tilings.
+ SetupDrawPropertiesAndUpdateTiles(pending_layer_,
+ 7.26f, // ideal contents scale
+ 3.3f, // device scale
+ 2.2f, // page scale
+ 1.f, // maximum animation scale
+ false);
+ ASSERT_EQ(3u, pending_layer_->tilings()->num_tilings());
+ EXPECT_FLOAT_EQ(7.26f,
+ pending_layer_->tilings()->tiling_at(0)->contents_scale());
+
+ // If we change the device scale factor, but end up at the same total scale
+ // factor somehow, then we don't get new tilings.
+ SetupDrawPropertiesAndUpdateTiles(pending_layer_,
+ 7.26f, // ideal contents scale
+ 2.2f, // device scale
+ 3.3f, // page scale
+ 1.f, // maximum animation scale
+ false);
+ ASSERT_EQ(3u, pending_layer_->tilings()->num_tilings());
+ EXPECT_FLOAT_EQ(7.26f,
+ pending_layer_->tilings()->tiling_at(0)->contents_scale());
+}
+
+TEST_F(NoLowResPictureLayerImplTest, MarkRequiredNullTiles) {
+ gfx::Size tile_size(100, 100);
+ gfx::Size layer_bounds(1000, 1000);
+
+ scoped_refptr<FakePicturePileImpl> pending_pile =
+ FakePicturePileImpl::CreateEmptyPile(tile_size, layer_bounds);
+ // Layers with entirely empty piles can't get tilings.
+ pending_pile->AddRecordingAt(0, 0);
+
+ SetupPendingTree(pending_pile);
+
+ ASSERT_TRUE(pending_layer_->CanHaveTilings());
+ pending_layer_->AddTiling(1.0f);
+ pending_layer_->AddTiling(2.0f);
+
+ // It should be safe to call this (and MarkVisibleResourcesAsRequired)
+ // on a layer with no recordings.
+ host_impl_.pending_tree()->UpdateDrawProperties();
+ pending_layer_->MarkVisibleResourcesAsRequired();
+}
+
+TEST_F(NoLowResPictureLayerImplTest, NothingRequiredIfAllHighResTilesShared) {
+ gfx::Size layer_bounds(400, 400);
+ gfx::Size tile_size(100, 100);
+ SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
+
+ CreateHighLowResAndSetAllTilesVisible();
+
+ Tile* some_active_tile =
+ active_layer_->HighResTiling()->AllTilesForTesting()[0];
+ EXPECT_FALSE(some_active_tile->IsReadyToDraw());
+
+ // All tiles shared (no invalidation), so even though the active tree's
+ // tiles aren't ready, there is nothing required.
+ pending_layer_->MarkVisibleResourcesAsRequired();
+ AssertNoTilesRequired(pending_layer_->HighResTiling());
+ if (host_impl_.settings().create_low_res_tiling) {
+ AssertNoTilesRequired(pending_layer_->LowResTiling());
+ }
+}
+
+TEST_F(NoLowResPictureLayerImplTest, NothingRequiredIfActiveMissingTiles) {
+ gfx::Size layer_bounds(400, 400);
+ gfx::Size tile_size(100, 100);
+ scoped_refptr<FakePicturePileImpl> pending_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+ // This pile will create tilings, but has no recordings so will not create any
+ // tiles. This is attempting to simulate scrolling past the end of recorded
+ // content on the active layer, where the recordings are so far away that
+ // no tiles are created.
+ scoped_refptr<FakePicturePileImpl> active_pile =
+ FakePicturePileImpl::CreateEmptyPileThatThinksItHasRecordings(
+ tile_size, layer_bounds);
+ SetupTrees(pending_pile, active_pile);
+ pending_layer_->set_fixed_tile_size(tile_size);
+ active_layer_->set_fixed_tile_size(tile_size);
+
+ CreateHighLowResAndSetAllTilesVisible();
+
+ // Active layer has tilings, but no tiles due to missing recordings.
+ EXPECT_TRUE(active_layer_->CanHaveTilings());
+ EXPECT_EQ(active_layer_->tilings()->num_tilings(),
+ host_impl_.settings().create_low_res_tiling ? 2u : 1u);
+ EXPECT_EQ(active_layer_->HighResTiling()->AllTilesForTesting().size(), 0u);
+
+ // Since the active layer has no tiles at all, the pending layer doesn't
+ // need content in order to activate.
+ pending_layer_->MarkVisibleResourcesAsRequired();
+ AssertNoTilesRequired(pending_layer_->HighResTiling());
+ if (host_impl_.settings().create_low_res_tiling)
+ AssertNoTilesRequired(pending_layer_->LowResTiling());
+}
+
+TEST_F(NoLowResPictureLayerImplTest, InvalidViewportForPrioritizingTiles) {
+ base::TimeTicks time_ticks;
+ host_impl_.SetCurrentFrameTimeTicks(time_ticks);
+
+ gfx::Size tile_size(100, 100);
+ gfx::Size layer_bounds(400, 400);
+
+ scoped_refptr<FakePicturePileImpl> pending_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+ scoped_refptr<FakePicturePileImpl> active_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+
+ SetupTrees(pending_pile, active_pile);
+
+ Region invalidation;
+ AddDefaultTilingsWithInvalidation(invalidation);
+ SetupDrawPropertiesAndUpdateTiles(active_layer_, 1.f, 1.f, 1.f, 1.f, false);
+
+ // UpdateTiles with valid viewport. Should update tile viewport.
+ bool valid_for_tile_management = true;
+ gfx::Rect viewport = gfx::Rect(layer_bounds);
+ gfx::Transform transform;
+ host_impl_.SetExternalDrawConstraints(
+ transform, viewport, viewport, valid_for_tile_management);
+ active_layer_->draw_properties().visible_content_rect = viewport;
+ active_layer_->draw_properties().screen_space_transform = transform;
+ active_layer_->UpdateTiles();
+
+ gfx::Rect visible_rect_for_tile_priority =
+ active_layer_->visible_rect_for_tile_priority();
+ EXPECT_FALSE(visible_rect_for_tile_priority.IsEmpty());
+ gfx::Size viewport_size_for_tile_priority =
+ active_layer_->viewport_size_for_tile_priority();
+ EXPECT_FALSE(viewport_size_for_tile_priority.IsEmpty());
+ gfx::Transform screen_space_transform_for_tile_priority =
+ active_layer_->screen_space_transform_for_tile_priority();
+
+ // Expand viewport and set it as invalid for prioritizing tiles.
+ // Should not update tile viewport.
+ time_ticks += base::TimeDelta::FromMilliseconds(200);
+ host_impl_.SetCurrentFrameTimeTicks(time_ticks);
+ valid_for_tile_management = false;
+ viewport = gfx::ScaleToEnclosingRect(viewport, 2);
+ transform.Translate(1.f, 1.f);
+ active_layer_->draw_properties().visible_content_rect = viewport;
+ active_layer_->draw_properties().screen_space_transform = transform;
+ host_impl_.SetExternalDrawConstraints(
+ transform, viewport, viewport, valid_for_tile_management);
+ active_layer_->UpdateTiles();
+
+ EXPECT_RECT_EQ(visible_rect_for_tile_priority,
+ active_layer_->visible_rect_for_tile_priority());
+ EXPECT_SIZE_EQ(viewport_size_for_tile_priority,
+ active_layer_->viewport_size_for_tile_priority());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(
+ screen_space_transform_for_tile_priority,
+ active_layer_->screen_space_transform_for_tile_priority());
+
+ // Keep expanded viewport but mark it valid. Should update tile viewport.
+ time_ticks += base::TimeDelta::FromMilliseconds(200);
+ host_impl_.SetCurrentFrameTimeTicks(time_ticks);
+ valid_for_tile_management = true;
+ host_impl_.SetExternalDrawConstraints(
+ transform, viewport, viewport, valid_for_tile_management);
+ active_layer_->UpdateTiles();
+
+ EXPECT_FALSE(visible_rect_for_tile_priority ==
+ active_layer_->visible_rect_for_tile_priority());
+ EXPECT_FALSE(viewport_size_for_tile_priority ==
+ active_layer_->viewport_size_for_tile_priority());
+ EXPECT_FALSE(screen_space_transform_for_tile_priority ==
+ active_layer_->screen_space_transform_for_tile_priority());
+}
+
+TEST_F(NoLowResPictureLayerImplTest, InvalidViewportAfterReleaseResources) {
+ base::TimeTicks time_ticks;
+ host_impl_.SetCurrentFrameTimeTicks(time_ticks);
+
+ gfx::Size tile_size(100, 100);
+ gfx::Size layer_bounds(400, 400);
+
+ scoped_refptr<FakePicturePileImpl> pending_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+ scoped_refptr<FakePicturePileImpl> active_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+
+ SetupTrees(pending_pile, active_pile);
+
+ Region invalidation;
+ AddDefaultTilingsWithInvalidation(invalidation);
+
+ bool valid_for_tile_management = false;
+ gfx::Rect viewport = gfx::Rect(layer_bounds);
+ host_impl_.SetExternalDrawConstraints(
+ gfx::Transform(), viewport, viewport, valid_for_tile_management);
+ ResetTilingsAndRasterScales();
+ host_impl_.pending_tree()->UpdateDrawProperties();
+ host_impl_.active_tree()->UpdateDrawProperties();
+ EXPECT_TRUE(active_layer_->HighResTiling());
+
+ size_t num_tilings = active_layer_->num_tilings();
+ active_layer_->UpdateTiles();
+ pending_layer_->AddTiling(0.5f);
+ EXPECT_EQ(num_tilings + 1, active_layer_->num_tilings());
+}
+
+TEST_F(NoLowResPictureLayerImplTest, CleanUpTilings) {
+ gfx::Size tile_size(400, 400);
+ gfx::Size layer_bounds(1300, 1900);
+
+ scoped_refptr<FakePicturePileImpl> pending_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+ scoped_refptr<FakePicturePileImpl> active_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+
+ std::vector<PictureLayerTiling*> used_tilings;
+
+ SetupTrees(pending_pile, active_pile);
+ EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
+
+ float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
+ EXPECT_LT(low_res_factor, 1.f);
+
+ float device_scale = 1.7f;
+ float page_scale = 3.2f;
+ float scale = 1.f;
+
+ SetContentsScaleOnBothLayers(scale, device_scale, page_scale, 1.f, false);
+ ASSERT_EQ(1u, active_layer_->tilings()->num_tilings());
+
+ // We only have ideal tilings, so they aren't removed.
+ used_tilings.clear();
+ active_layer_->CleanUpTilingsOnActiveLayer(used_tilings);
+ ASSERT_EQ(1u, active_layer_->tilings()->num_tilings());
+
+ host_impl_.PinchGestureBegin();
+
+ // Changing the ideal but not creating new tilings.
+ scale *= 1.5f;
+ page_scale *= 1.5f;
+ SetContentsScaleOnBothLayers(scale, device_scale, page_scale, 1.f, false);
+ ASSERT_EQ(1u, active_layer_->tilings()->num_tilings());
+
+ // The tilings are still our target scale, so they aren't removed.
+ used_tilings.clear();
+ active_layer_->CleanUpTilingsOnActiveLayer(used_tilings);
+ ASSERT_EQ(1u, active_layer_->tilings()->num_tilings());
+
+ host_impl_.PinchGestureEnd();
+
+ // Create a 1.2 scale tiling. Now we have 1.0 and 1.2 tilings. Ideal = 1.2.
+ scale /= 4.f;
+ page_scale /= 4.f;
+ SetContentsScaleOnBothLayers(1.2f, device_scale, page_scale, 1.f, false);
+ ASSERT_EQ(2u, active_layer_->tilings()->num_tilings());
+ EXPECT_FLOAT_EQ(1.f,
+ active_layer_->tilings()->tiling_at(1)->contents_scale());
+
+ // Mark the non-ideal tilings as used. They won't be removed.
+ used_tilings.clear();
+ used_tilings.push_back(active_layer_->tilings()->tiling_at(1));
+ active_layer_->CleanUpTilingsOnActiveLayer(used_tilings);
+ ASSERT_EQ(2u, active_layer_->tilings()->num_tilings());
+
+ // Now move the ideal scale to 0.5. Our target stays 1.2.
+ SetContentsScaleOnBothLayers(0.5f, device_scale, page_scale, 1.f, false);
+
+ // The high resolution tiling is between target and ideal, so is not
+ // removed. The low res tiling for the old ideal=1.0 scale is removed.
+ used_tilings.clear();
+ active_layer_->CleanUpTilingsOnActiveLayer(used_tilings);
+ ASSERT_EQ(2u, active_layer_->tilings()->num_tilings());
+
+ // Now move the ideal scale to 1.0. Our target stays 1.2.
+ SetContentsScaleOnBothLayers(1.f, device_scale, page_scale, 1.f, false);
+
+ // All the tilings are between are target and the ideal, so they are not
+ // removed.
+ used_tilings.clear();
+ active_layer_->CleanUpTilingsOnActiveLayer(used_tilings);
+ ASSERT_EQ(2u, active_layer_->tilings()->num_tilings());
+
+ // Now move the ideal scale to 1.1 on the active layer. Our target stays 1.2.
+ SetupDrawPropertiesAndUpdateTiles(
+ active_layer_, 1.1f, device_scale, page_scale, 1.f, false);
+
+ // Because the pending layer's ideal scale is still 1.0, our tilings fall
+ // in the range [1.0,1.2] and are kept.
+ used_tilings.clear();
+ active_layer_->CleanUpTilingsOnActiveLayer(used_tilings);
+ ASSERT_EQ(2u, active_layer_->tilings()->num_tilings());
+
+ // Move the ideal scale on the pending layer to 1.1 as well. Our target stays
+ // 1.2 still.
+ SetupDrawPropertiesAndUpdateTiles(
+ pending_layer_, 1.1f, device_scale, page_scale, 1.f, false);
+
+ // Our 1.0 tiling now falls outside the range between our ideal scale and our
+ // target raster scale. But it is in our used tilings set, so nothing is
+ // deleted.
+ used_tilings.clear();
+ used_tilings.push_back(active_layer_->tilings()->tiling_at(1));
+ active_layer_->CleanUpTilingsOnActiveLayer(used_tilings);
+ ASSERT_EQ(2u, active_layer_->tilings()->num_tilings());
+
+ // If we remove it from our used tilings set, it is outside the range to keep
+ // so it is deleted.
+ used_tilings.clear();
+ active_layer_->CleanUpTilingsOnActiveLayer(used_tilings);
+ ASSERT_EQ(1u, active_layer_->tilings()->num_tilings());
+}
+
+TEST_F(PictureLayerImplTest, ScaleCollision) {
+ gfx::Size tile_size(400, 400);
+ gfx::Size layer_bounds(1300, 1900);
+
+ scoped_refptr<FakePicturePileImpl> pending_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+ scoped_refptr<FakePicturePileImpl> active_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+
+ std::vector<PictureLayerTiling*> used_tilings;
+
+ SetupTrees(pending_pile, active_pile);
+
+ float pending_contents_scale = 1.f;
+ float active_contents_scale = 2.f;
+ float device_scale_factor = 1.f;
+ float page_scale_factor = 1.f;
+ float maximum_animation_contents_scale = 1.f;
+ bool animating_transform = false;
+
+ EXPECT_TRUE(host_impl_.settings().create_low_res_tiling);
+ float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
+ EXPECT_LT(low_res_factor, 1.f);
+
+ SetupDrawPropertiesAndUpdateTiles(pending_layer_,
+ pending_contents_scale,
+ device_scale_factor,
+ page_scale_factor,
+ maximum_animation_contents_scale,
+ animating_transform);
+ SetupDrawPropertiesAndUpdateTiles(active_layer_,
+ active_contents_scale,
+ device_scale_factor,
+ page_scale_factor,
+ maximum_animation_contents_scale,
+ animating_transform);
+
+ ASSERT_EQ(4u, pending_layer_->tilings()->num_tilings());
+ ASSERT_EQ(4u, active_layer_->tilings()->num_tilings());
+
+ EXPECT_EQ(active_contents_scale,
+ pending_layer_->tilings()->tiling_at(0)->contents_scale());
+ EXPECT_EQ(pending_contents_scale,
+ pending_layer_->tilings()->tiling_at(1)->contents_scale());
+ EXPECT_EQ(active_contents_scale * low_res_factor,
+ pending_layer_->tilings()->tiling_at(2)->contents_scale());
+ EXPECT_EQ(pending_contents_scale * low_res_factor,
+ pending_layer_->tilings()->tiling_at(3)->contents_scale());
+
+ EXPECT_EQ(active_contents_scale,
+ active_layer_->tilings()->tiling_at(0)->contents_scale());
+ EXPECT_EQ(pending_contents_scale,
+ active_layer_->tilings()->tiling_at(1)->contents_scale());
+ EXPECT_EQ(active_contents_scale * low_res_factor,
+ active_layer_->tilings()->tiling_at(2)->contents_scale());
+ EXPECT_EQ(pending_contents_scale * low_res_factor,
+ active_layer_->tilings()->tiling_at(3)->contents_scale());
+
+ // The unused low res tiling from the pending tree must be kept or we may add
+ // it again on the active tree and collide with the pending tree.
+ used_tilings.push_back(active_layer_->tilings()->tiling_at(1));
+ active_layer_->CleanUpTilingsOnActiveLayer(used_tilings);
+ ASSERT_EQ(4u, active_layer_->tilings()->num_tilings());
+
+ EXPECT_EQ(active_contents_scale,
+ active_layer_->tilings()->tiling_at(0)->contents_scale());
+ EXPECT_EQ(pending_contents_scale,
+ active_layer_->tilings()->tiling_at(1)->contents_scale());
+ EXPECT_EQ(active_contents_scale * low_res_factor,
+ active_layer_->tilings()->tiling_at(2)->contents_scale());
+ EXPECT_EQ(pending_contents_scale * low_res_factor,
+ active_layer_->tilings()->tiling_at(3)->contents_scale());
+}
+
+TEST_F(NoLowResPictureLayerImplTest, ReleaseResources) {
+ gfx::Size tile_size(400, 400);
+ gfx::Size layer_bounds(1300, 1900);
+
+ scoped_refptr<FakePicturePileImpl> pending_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+ scoped_refptr<FakePicturePileImpl> active_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+
+ SetupTrees(pending_pile, active_pile);
+ EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
+
+ SetupDrawPropertiesAndUpdateTiles(pending_layer_,
+ 1.3f, // ideal contents scale
+ 2.7f, // device scale
+ 3.2f, // page scale
+ 1.f, // maximum animation scale
+ false);
+ EXPECT_EQ(1u, pending_layer_->tilings()->num_tilings());
+
+ // All tilings should be removed when losing output surface.
+ active_layer_->ReleaseResources();
+ EXPECT_EQ(0u, active_layer_->tilings()->num_tilings());
+ pending_layer_->ReleaseResources();
+ EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
+
+ // This should create new tilings.
+ SetupDrawPropertiesAndUpdateTiles(pending_layer_,
+ 1.3f, // ideal contents scale
+ 2.7f, // device scale
+ 3.2f, // page scale
+ 1.f, // maximum animation scale
+ false);
+ EXPECT_EQ(1u, pending_layer_->tilings()->num_tilings());
+}
+
+TEST_F(PictureLayerImplTest, SharedQuadStateContainsMaxTilingScale) {
+ MockOcclusionTracker<LayerImpl> occlusion_tracker;
+ scoped_ptr<RenderPass> render_pass = RenderPass::Create();
+ MockQuadCuller quad_culler(render_pass.get(), &occlusion_tracker);
+
+ gfx::Size tile_size(400, 400);
+ gfx::Size layer_bounds(1000, 2000);
+
+ scoped_refptr<FakePicturePileImpl> pending_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+ scoped_refptr<FakePicturePileImpl> active_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+
+ SetupTrees(pending_pile, active_pile);
+
+ SetupDrawPropertiesAndUpdateTiles(pending_layer_, 2.5f, 1.f, 1.f, 1.f, false);
+ host_impl_.pending_tree()->UpdateDrawProperties();
+
+ active_layer_->draw_properties().visible_content_rect =
+ gfx::Rect(layer_bounds);
+ host_impl_.active_tree()->UpdateDrawProperties();
+
+ float max_contents_scale = active_layer_->MaximumTilingContentsScale();
+ gfx::Transform scaled_draw_transform = active_layer_->draw_transform();
+ scaled_draw_transform.Scale(SK_MScalar1 / max_contents_scale,
+ SK_MScalar1 / max_contents_scale);
+
+ AppendQuadsData data;
+ active_layer_->AppendQuads(&quad_culler, &data);
+
+ // SharedQuadState should have be of size 1, as we are doing AppenQuad once.
+ EXPECT_EQ(1u, quad_culler.shared_quad_state_list().size());
+ // The content_to_target_transform should be scaled by the
+ // MaximumTilingContentsScale on the layer.
+ EXPECT_EQ(scaled_draw_transform.ToString(),
+ quad_culler.shared_quad_state_list()[0]
+ ->content_to_target_transform.ToString());
+ // The content_bounds should be scaled by the
+ // MaximumTilingContentsScale on the layer.
+ EXPECT_EQ(gfx::Size(2500u, 5000u).ToString(),
+ quad_culler.shared_quad_state_list()[0]->content_bounds.ToString());
+ // The visible_content_rect should be scaled by the
+ // MaximumTilingContentsScale on the layer.
+ EXPECT_EQ(
+ gfx::Rect(0u, 0u, 2500u, 5000u).ToString(),
+ quad_culler.shared_quad_state_list()[0]->visible_content_rect.ToString());
+}
+
+TEST_F(PictureLayerImplTest, UpdateTilesForMasksWithNoVisibleContent) {
+ gfx::Size tile_size(400, 400);
+ gfx::Size bounds(100000, 100);
+
+ host_impl_.CreatePendingTree();
+
+ scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_.pending_tree(), 1);
+
+ scoped_ptr<FakePictureLayerImpl> layer_with_mask =
+ FakePictureLayerImpl::Create(host_impl_.pending_tree(), 2);
+
+ layer_with_mask->SetBounds(bounds);
+ layer_with_mask->SetContentBounds(bounds);
+
+ scoped_refptr<FakePicturePileImpl> pending_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, bounds);
+ scoped_ptr<FakePictureLayerImpl> mask = FakePictureLayerImpl::CreateWithPile(
+ host_impl_.pending_tree(), 3, pending_pile);
+
+ mask->SetIsMask(true);
+ mask->SetBounds(bounds);
+ mask->SetContentBounds(bounds);
+ mask->SetDrawsContent(true);
+
+ FakePictureLayerImpl* pending_mask_content = mask.get();
+ layer_with_mask->SetMaskLayer(mask.PassAs<LayerImpl>());
+
+ scoped_ptr<FakePictureLayerImpl> child_of_layer_with_mask =
+ FakePictureLayerImpl::Create(host_impl_.pending_tree(), 4);
+
+ child_of_layer_with_mask->SetBounds(bounds);
+ child_of_layer_with_mask->SetContentBounds(bounds);
+ child_of_layer_with_mask->SetDrawsContent(true);
+
+ layer_with_mask->AddChild(child_of_layer_with_mask.PassAs<LayerImpl>());
+
+ root->AddChild(layer_with_mask.PassAs<LayerImpl>());
+
+ host_impl_.pending_tree()->SetRootLayer(root.Pass());
+
+ EXPECT_FALSE(pending_mask_content->tilings());
+ host_impl_.pending_tree()->UpdateDrawProperties();
+ EXPECT_NE(0u, pending_mask_content->num_tilings());
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/layers/picture_layer_unittest.cc b/chromium/cc/layers/picture_layer_unittest.cc
index c3dd244c2ef..bc52091b489 100644
--- a/chromium/cc/layers/picture_layer_unittest.cc
+++ b/chromium/cc/layers/picture_layer_unittest.cc
@@ -12,6 +12,7 @@
#include "cc/test/fake_proxy.h"
#include "cc/test/impl_side_painting_settings.h"
#include "cc/trees/occlusion_tracker.h"
+#include "cc/trees/single_thread_proxy.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace cc {
@@ -19,10 +20,15 @@ namespace {
class MockContentLayerClient : public ContentLayerClient {
public:
- virtual void PaintContents(SkCanvas* canvas,
- gfx::Rect clip,
- gfx::RectF* opaque) OVERRIDE {}
+ virtual void PaintContents(
+ SkCanvas* canvas,
+ const gfx::Rect& clip,
+ gfx::RectF* opaque,
+ ContentLayerClient::GraphicsContextStatus gc_status) OVERRIDE {}
virtual void DidChangeLayerCanUseLCDText() OVERRIDE {}
+ virtual bool FillsBoundsCompletely() const OVERRIDE {
+ return false;
+ };
};
TEST(PictureLayerTest, NoTilesIfEmptyBounds) {
@@ -35,7 +41,7 @@ TEST(PictureLayerTest, NoTilesIfEmptyBounds) {
layer->SetIsDrawable(true);
layer->SavePaintProperties();
- OcclusionTracker occlusion(gfx::Rect(0, 0, 1000, 1000), false);
+ OcclusionTracker<Layer> occlusion(gfx::Rect(0, 0, 1000, 1000));
scoped_ptr<ResourceUpdateQueue> queue(new ResourceUpdateQueue);
layer->Update(queue.get(), &occlusion);
@@ -45,11 +51,12 @@ TEST(PictureLayerTest, NoTilesIfEmptyBounds) {
// a layer with empty bounds.
FakeProxy proxy;
-#ifndef NDEBUG
- proxy.SetCurrentThreadIsImplThread(true);
-#endif
{
- FakeLayerTreeHostImpl host_impl(ImplSidePaintingSettings(), &proxy);
+ DebugScopedSetImplThread impl_thread(&proxy);
+
+ TestSharedBitmapManager shared_bitmap_manager;
+ FakeLayerTreeHostImpl host_impl(
+ ImplSidePaintingSettings(), &proxy, &shared_bitmap_manager);
host_impl.CreatePendingTree();
scoped_ptr<FakePictureLayerImpl> layer_impl =
FakePictureLayerImpl::Create(host_impl.pending_tree(), 1);
@@ -57,12 +64,39 @@ TEST(PictureLayerTest, NoTilesIfEmptyBounds) {
layer->PushPropertiesTo(layer_impl.get());
EXPECT_FALSE(layer_impl->CanHaveTilings());
EXPECT_TRUE(layer_impl->bounds() == gfx::Size(0, 0));
- EXPECT_TRUE(layer_impl->pile()->size() == gfx::Size(0, 0));
- EXPECT_TRUE(layer_impl->pile()->recorded_region().IsEmpty());
+ EXPECT_TRUE(layer_impl->pile()->tiling_rect() == gfx::Rect());
+ EXPECT_FALSE(layer_impl->pile()->HasRecordings());
}
-#ifndef NDEBUG
- proxy.SetCurrentThreadIsImplThread(false);
-#endif
+}
+
+TEST(PictureLayerTest, SuitableForGpuRasterization) {
+ MockContentLayerClient client;
+ scoped_refptr<PictureLayer> layer = PictureLayer::Create(&client);
+ PicturePile* pile = layer->GetPicturePileForTesting();
+
+ // Layer is suitable for gpu rasterization by default.
+ EXPECT_TRUE(pile->is_suitable_for_gpu_rasterization());
+ EXPECT_TRUE(layer->IsSuitableForGpuRasterization());
+
+ // Veto gpu rasterization.
+ pile->SetUnsuitableForGpuRasterizationForTesting();
+ EXPECT_FALSE(pile->is_suitable_for_gpu_rasterization());
+ EXPECT_FALSE(layer->IsSuitableForGpuRasterization());
+}
+
+TEST(PictureLayerTest, RecordingModes) {
+ MockContentLayerClient client;
+ scoped_refptr<PictureLayer> layer = PictureLayer::Create(&client);
+
+ LayerTreeSettings settings;
+ scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(settings);
+ host->SetRootLayer(layer);
+ EXPECT_EQ(Picture::RECORD_NORMALLY, layer->RecordingMode());
+
+ settings.recording_mode = LayerTreeSettings::RecordWithSkRecord;
+ host = FakeLayerTreeHost::Create(settings);
+ host->SetRootLayer(layer);
+ EXPECT_EQ(Picture::RECORD_WITH_SKRECORD, layer->RecordingMode());
}
} // namespace
diff --git a/chromium/cc/layers/quad_sink.cc b/chromium/cc/layers/quad_sink.cc
new file mode 100644
index 00000000000..23758afc669
--- /dev/null
+++ b/chromium/cc/layers/quad_sink.cc
@@ -0,0 +1,55 @@
+// 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/layers/quad_sink.h"
+
+#include "cc/debug/debug_colors.h"
+#include "cc/layers/append_quads_data.h"
+#include "cc/layers/layer_impl.h"
+#include "cc/quads/debug_border_draw_quad.h"
+#include "cc/quads/render_pass.h"
+#include "cc/quads/render_pass_draw_quad.h"
+#include "cc/trees/occlusion_tracker.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/gfx/transform.h"
+
+namespace cc {
+
+QuadSink::QuadSink(RenderPass* render_pass,
+ const OcclusionTracker<LayerImpl>* occlusion_tracker)
+ : render_pass_(render_pass),
+ current_shared_quad_state_(NULL),
+ occlusion_tracker_(occlusion_tracker) {
+}
+
+SharedQuadState* QuadSink::CreateSharedQuadState() {
+ current_shared_quad_state_ = render_pass_->CreateAndAppendSharedQuadState();
+ return current_shared_quad_state_;
+}
+
+gfx::Rect QuadSink::UnoccludedContentRect(
+ const gfx::Rect& content_rect,
+ const gfx::Transform& draw_transform) {
+ return occlusion_tracker_->UnoccludedContentRect(content_rect,
+ draw_transform);
+}
+
+gfx::Rect QuadSink::UnoccludedContributingSurfaceContentRect(
+ const gfx::Rect& content_rect,
+ const gfx::Transform& draw_transform) {
+ return occlusion_tracker_->UnoccludedContributingSurfaceContentRect(
+ content_rect, draw_transform);
+}
+
+void QuadSink::Append(scoped_ptr<DrawQuad> draw_quad) {
+ DCHECK(draw_quad->shared_quad_state == current_shared_quad_state_);
+ DCHECK(!render_pass_->shared_quad_state_list.empty());
+ DCHECK(render_pass_->shared_quad_state_list.back() ==
+ current_shared_quad_state_);
+ DCHECK(!draw_quad->rect.IsEmpty());
+ DCHECK(!draw_quad->visible_rect.IsEmpty());
+ render_pass_->quad_list.push_back(draw_quad.Pass());
+}
+
+} // namespace cc
diff --git a/chromium/cc/layers/quad_sink.h b/chromium/cc/layers/quad_sink.h
index 041b655b861..c033bfb489e 100644
--- a/chromium/cc/layers/quad_sink.h
+++ b/chromium/cc/layers/quad_sink.h
@@ -8,27 +8,50 @@
#include "base/memory/scoped_ptr.h"
#include "cc/base/cc_export.h"
+namespace gfx {
+class Rect;
+class Transform;
+}
+
namespace cc {
class DrawQuad;
+class LayerImpl;
+class RenderPass;
+class RenderSurfaceImpl;
class SharedQuadState;
-
-struct AppendQuadsData;
+template <typename LayerType>
+class OcclusionTracker;
class CC_EXPORT QuadSink {
public:
- virtual ~QuadSink() {}
+ QuadSink(RenderPass* render_pass,
+ const OcclusionTracker<LayerImpl>* occlusion_tracker);
+ ~QuadSink() {}
// Call this to add a SharedQuadState before appending quads that refer to it.
- // Returns a pointer to the given SharedQuadState for convenience, that can be
- // set on the quads to append.
- virtual SharedQuadState* UseSharedQuadState(
- scoped_ptr<SharedQuadState> shared_quad_state) = 0;
-
- // Returns true if the quad is added to the list, and false if the quad is
- // entirely culled.
- virtual bool Append(scoped_ptr<DrawQuad> draw_quad,
- AppendQuadsData* append_quads_data) = 0;
+ // Returns a pointer to the given SharedQuadState, that can be set on the
+ // quads to append.
+ virtual SharedQuadState* CreateSharedQuadState();
+
+ virtual gfx::Rect UnoccludedContentRect(const gfx::Rect& content_rect,
+ const gfx::Transform& draw_transform);
+
+ virtual gfx::Rect UnoccludedContributingSurfaceContentRect(
+ const gfx::Rect& content_rect,
+ const gfx::Transform& draw_transform);
+
+ virtual void Append(scoped_ptr<DrawQuad> draw_quad);
+
+ protected:
+ RenderPass* render_pass_;
+
+ SharedQuadState* current_shared_quad_state_;
+
+ private:
+ const OcclusionTracker<LayerImpl>* occlusion_tracker_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuadSink);
};
} // namespace cc
diff --git a/chromium/cc/layers/render_surface.cc b/chromium/cc/layers/render_surface.cc
index 0eab856a956..15e11875ea2 100644
--- a/chromium/cc/layers/render_surface.cc
+++ b/chromium/cc/layers/render_surface.cc
@@ -40,4 +40,8 @@ gfx::RectF RenderSurface::DrawableContentRect() const {
return drawable_content_rect;
}
+void RenderSurface::ClearLayerLists() {
+ layer_list_.clear();
+}
+
} // namespace cc
diff --git a/chromium/cc/layers/render_surface.h b/chromium/cc/layers/render_surface.h
index ef9ba229736..4da8d237942 100644
--- a/chromium/cc/layers/render_surface.h
+++ b/chromium/cc/layers/render_surface.h
@@ -19,6 +19,8 @@
namespace cc {
class Layer;
+template <typename LayerType>
+class LayerIterator;
class CC_EXPORT RenderSurface {
public:
@@ -29,7 +31,9 @@ class CC_EXPORT RenderSurface {
// reflection.
gfx::RectF DrawableContentRect() const;
- void SetContentRect(gfx::Rect content_rect) { content_rect_ = content_rect; }
+ void SetContentRect(const gfx::Rect& content_rect) {
+ content_rect_ = content_rect;
+ }
gfx::Rect content_rect() const { return content_rect_; }
void SetDrawOpacity(float opacity) { draw_opacity_ = opacity; }
@@ -84,7 +88,7 @@ class CC_EXPORT RenderSurface {
void SetIsClipped(bool is_clipped) { is_clipped_ = is_clipped; }
gfx::Rect clip_rect() const { return clip_rect_; }
- void SetClipRect(gfx::Rect clip_rect) { clip_rect_ = clip_rect; }
+ void SetClipRect(const gfx::Rect& clip_rect) { clip_rect_ = clip_rect; }
// When false, the RenderSurface does not contribute to another target
// RenderSurface that is being drawn for the current frame. It could still be
@@ -97,7 +101,7 @@ class CC_EXPORT RenderSurface {
contributes_to_drawn_surface_ = contributes_to_drawn_surface;
}
- RenderSurfaceLayerList& layer_list() { return layer_list_; }
+ LayerList& layer_list() { return layer_list_; }
// A no-op since DelegatedRendererLayers on the main thread don't have any
// RenderPasses so they can't contribute to a surface.
void AddContributingDelegatedRenderPassLayer(Layer* layer) {}
@@ -109,8 +113,10 @@ class CC_EXPORT RenderSurface {
return nearest_occlusion_immune_ancestor_;
}
+ void ClearLayerLists();
+
private:
- friend struct LayerIteratorActions;
+ friend class LayerIterator<Layer>;
Layer* owning_layer_;
@@ -132,7 +138,7 @@ class CC_EXPORT RenderSurface {
// Uses the space of the surface's target surface.
gfx::Rect clip_rect_;
- RenderSurfaceLayerList layer_list_;
+ LayerList layer_list_;
// The nearest ancestor target surface that will contain the contents of this
// surface, and that ignores outside occlusion. This can point to itself.
diff --git a/chromium/cc/layers/render_surface_impl.cc b/chromium/cc/layers/render_surface_impl.cc
index a8336bcaf4f..af8c41a5343 100644
--- a/chromium/cc/layers/render_surface_impl.cc
+++ b/chromium/cc/layers/render_surface_impl.cc
@@ -53,18 +53,12 @@ gfx::RectF RenderSurfaceImpl::DrawableContentRect() const {
return drawable_content_rect;
}
-std::string RenderSurfaceImpl::Name() const {
- return base::StringPrintf("RenderSurfaceImpl(id=%i,owner=%s)",
- owning_layer_->id(),
- owning_layer_->debug_name().data());
-}
-
int RenderSurfaceImpl::OwningLayerId() const {
return owning_layer_ ? owning_layer_->id() : 0;
}
-void RenderSurfaceImpl::SetClipRect(gfx::Rect clip_rect) {
+void RenderSurfaceImpl::SetClipRect(const gfx::Rect& clip_rect) {
if (clip_rect_ == clip_rect)
return;
@@ -76,7 +70,7 @@ bool RenderSurfaceImpl::ContentsChanged() const {
return !damage_tracker_->current_damage_rect().IsEmpty();
}
-void RenderSurfaceImpl::SetContentRect(gfx::Rect content_rect) {
+void RenderSurfaceImpl::SetContentRect(const gfx::Rect& content_rect) {
if (content_rect_ == content_rect)
return;
@@ -136,7 +130,8 @@ void RenderSurfaceImpl::AppendRenderPasses(RenderPassSink* pass_sink) {
scoped_ptr<RenderPass> pass = RenderPass::Create(layer_list_.size());
pass->SetNew(RenderPassId(),
content_rect_,
- damage_tracker_->current_damage_rect(),
+ gfx::IntersectRects(content_rect_,
+ damage_tracker_->current_damage_rect()),
screen_space_transform_);
pass_sink->AppendRenderPass(pass.Pass());
}
@@ -149,15 +144,21 @@ void RenderSurfaceImpl::AppendQuads(QuadSink* quad_sink,
const gfx::Transform& draw_transform =
for_replica ? replica_draw_transform_ : draw_transform_;
- SharedQuadState* shared_quad_state =
- quad_sink->UseSharedQuadState(SharedQuadState::Create());
+ gfx::Rect visible_content_rect =
+ quad_sink->UnoccludedContributingSurfaceContentRect(content_rect_,
+ draw_transform);
+ if (visible_content_rect.IsEmpty())
+ return;
+
+ SharedQuadState* shared_quad_state = quad_sink->CreateSharedQuadState();
shared_quad_state->SetAll(draw_transform,
content_rect_.size(),
content_rect_,
clip_rect_,
is_clipped_,
draw_opacity_,
- owning_layer_->blend_mode());
+ owning_layer_->blend_mode(),
+ owning_layer_->sorting_context_id());
if (owning_layer_->ShowDebugBorders()) {
SkColor color = for_replica ?
@@ -170,8 +171,9 @@ void RenderSurfaceImpl::AppendQuads(QuadSink* quad_sink,
owning_layer_->layer_tree_impl());
scoped_ptr<DebugBorderDrawQuad> debug_border_quad =
DebugBorderDrawQuad::Create();
- debug_border_quad->SetNew(shared_quad_state, content_rect_, color, width);
- quad_sink->Append(debug_border_quad.PassAs<DrawQuad>(), append_quads_data);
+ debug_border_quad->SetNew(
+ shared_quad_state, content_rect_, visible_content_rect, color, width);
+ quad_sink->Append(debug_border_quad.PassAs<DrawQuad>());
}
// TODO(shawnsingh): By using the same RenderSurfaceImpl for both the content
@@ -223,6 +225,7 @@ void RenderSurfaceImpl::AppendQuads(QuadSink* quad_sink,
scoped_ptr<RenderPassDrawQuad> quad = RenderPassDrawQuad::Create();
quad->SetNew(shared_quad_state,
content_rect_,
+ visible_content_rect,
render_pass_id,
for_replica,
mask_resource_id,
@@ -230,7 +233,7 @@ void RenderSurfaceImpl::AppendQuads(QuadSink* quad_sink,
mask_uv_rect,
owning_layer_->filters(),
owning_layer_->background_filters());
- quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
+ quad_sink->Append(quad.PassAs<DrawQuad>());
}
} // namespace cc
diff --git a/chromium/cc/layers/render_surface_impl.h b/chromium/cc/layers/render_surface_impl.h
index c02a3194098..8cbc4fe0661 100644
--- a/chromium/cc/layers/render_surface_impl.h
+++ b/chromium/cc/layers/render_surface_impl.h
@@ -25,6 +25,8 @@ class DelegatedRendererLayerImpl;
class QuadSink;
class RenderPassSink;
class LayerImpl;
+template <typename LayerType>
+class LayerIterator;
struct AppendQuadsData;
@@ -33,8 +35,6 @@ class CC_EXPORT RenderSurfaceImpl {
explicit RenderSurfaceImpl(LayerImpl* owning_layer);
virtual ~RenderSurfaceImpl();
- std::string Name() const;
-
gfx::PointF ContentRectCenter() const {
return gfx::RectF(content_rect_).CenterPoint();
}
@@ -101,7 +101,7 @@ class CC_EXPORT RenderSurfaceImpl {
void SetIsClipped(bool is_clipped) { is_clipped_ = is_clipped; }
bool is_clipped() const { return is_clipped_; }
- void SetClipRect(gfx::Rect clip_rect);
+ void SetClipRect(const gfx::Rect& clip_rect);
gfx::Rect clip_rect() const { return clip_rect_; }
// When false, the RenderSurface does not contribute to another target
@@ -117,7 +117,7 @@ class CC_EXPORT RenderSurfaceImpl {
bool ContentsChanged() const;
- void SetContentRect(gfx::Rect content_rect);
+ void SetContentRect(const gfx::Rect& content_rect);
gfx::Rect content_rect() const { return content_rect_; }
LayerImplList& layer_list() { return layer_list_; }
@@ -176,7 +176,7 @@ class CC_EXPORT RenderSurfaceImpl {
int target_render_surface_layer_index_history_;
int current_layer_index_history_;
- friend struct LayerIteratorActions;
+ friend class LayerIterator<LayerImpl>;
DISALLOW_COPY_AND_ASSIGN(RenderSurfaceImpl);
};
diff --git a/chromium/cc/layers/render_surface_impl_unittest.cc b/chromium/cc/layers/render_surface_impl_unittest.cc
new file mode 100644
index 00000000000..7733240c36c
--- /dev/null
+++ b/chromium/cc/layers/render_surface_impl_unittest.cc
@@ -0,0 +1,67 @@
+// 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/layers/render_surface_impl.h"
+
+#include "cc/test/layer_test_common.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+namespace {
+
+TEST(RenderSurfaceLayerImplTest, Occlusion) {
+ gfx::Size layer_size(1000, 1000);
+ gfx::Size viewport_size(1000, 1000);
+
+ LayerTestCommon::LayerImplTest impl;
+
+ LayerImpl* owning_layer_impl = impl.AddChildToRoot<LayerImpl>();
+ owning_layer_impl->SetBounds(layer_size);
+ owning_layer_impl->SetContentBounds(layer_size);
+ owning_layer_impl->SetDrawsContent(true);
+ owning_layer_impl->SetForceRenderSurface(true);
+
+ impl.CalcDrawProps(viewport_size);
+
+ RenderSurfaceImpl* render_surface_impl = owning_layer_impl->render_surface();
+ ASSERT_TRUE(render_surface_impl);
+
+ {
+ SCOPED_TRACE("No occlusion");
+ gfx::Rect occluded;
+ impl.AppendSurfaceQuadsWithOcclusion(render_surface_impl, occluded);
+
+ LayerTestCommon::VerifyQuadsExactlyCoverRect(impl.quad_list(),
+ gfx::Rect(layer_size));
+ EXPECT_EQ(1u, impl.quad_list().size());
+ }
+
+ {
+ SCOPED_TRACE("Full occlusion");
+ gfx::Rect occluded(owning_layer_impl->visible_content_rect());
+ impl.AppendSurfaceQuadsWithOcclusion(render_surface_impl, occluded);
+
+ LayerTestCommon::VerifyQuadsExactlyCoverRect(impl.quad_list(), gfx::Rect());
+ EXPECT_EQ(impl.quad_list().size(), 0u);
+ }
+
+ {
+ SCOPED_TRACE("Partial occlusion");
+ gfx::Rect occluded(200, 0, 800, 1000);
+ impl.AppendSurfaceQuadsWithOcclusion(render_surface_impl, occluded);
+
+ size_t partially_occluded_count = 0;
+ LayerTestCommon::VerifyQuadsCoverRectWithOcclusion(
+ impl.quad_list(),
+ gfx::Rect(layer_size),
+ occluded,
+ &partially_occluded_count);
+ // The layer outputs one quad, which is partially occluded.
+ EXPECT_EQ(1u, impl.quad_list().size());
+ EXPECT_EQ(1u, partially_occluded_count);
+ }
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/layers/render_surface_unittest.cc b/chromium/cc/layers/render_surface_unittest.cc
index 70f63f7304c..62c88bcc719 100644
--- a/chromium/cc/layers/render_surface_unittest.cc
+++ b/chromium/cc/layers/render_surface_unittest.cc
@@ -12,6 +12,7 @@
#include "cc/test/fake_layer_tree_host_impl.h"
#include "cc/test/geometry_test_utils.h"
#include "cc/test/mock_quad_culler.h"
+#include "cc/test/test_shared_bitmap_manager.h"
#include "cc/trees/single_thread_proxy.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -36,7 +37,8 @@ TEST(RenderSurfaceTest, VerifySurfaceChangesAreTrackedProperly) {
//
FakeImplProxy proxy;
- FakeLayerTreeHostImpl host_impl(&proxy);
+ TestSharedBitmapManager shared_bitmap_manager;
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
scoped_ptr<LayerImpl> owning_layer =
LayerImpl::Create(host_impl.active_tree(), 1);
owning_layer->CreateRenderSurface();
@@ -80,7 +82,8 @@ TEST(RenderSurfaceTest, VerifySurfaceChangesAreTrackedProperly) {
TEST(RenderSurfaceTest, SanityCheckSurfaceCreatesCorrectSharedQuadState) {
FakeImplProxy proxy;
- FakeLayerTreeHostImpl host_impl(&proxy);
+ TestSharedBitmapManager shared_bitmap_manager;
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
scoped_ptr<LayerImpl> root_layer =
LayerImpl::Create(host_impl.active_tree(), 1);
@@ -104,17 +107,17 @@ TEST(RenderSurfaceTest, SanityCheckSurfaceCreatesCorrectSharedQuadState) {
render_surface->SetClipRect(clip_rect);
render_surface->SetDrawOpacity(1.f);
- QuadList quad_list;
- SharedQuadStateList shared_state_list;
- MockQuadCuller mock_quad_culler(&quad_list, &shared_state_list);
+ MockOcclusionTracker<LayerImpl> occlusion_tracker;
+ scoped_ptr<RenderPass> render_pass = RenderPass::Create();
+ MockQuadCuller mock_quad_culler(render_pass.get(), &occlusion_tracker);
AppendQuadsData append_quads_data;
bool for_replica = false;
render_surface->AppendQuads(
&mock_quad_culler, &append_quads_data, for_replica, RenderPass::Id(2, 0));
- ASSERT_EQ(1u, shared_state_list.size());
- SharedQuadState* shared_quad_state = shared_state_list[0];
+ ASSERT_EQ(1u, render_pass->shared_quad_state_list.size());
+ SharedQuadState* shared_quad_state = render_pass->shared_quad_state_list[0];
EXPECT_EQ(
30.0,
@@ -143,7 +146,8 @@ class TestRenderPassSink : public RenderPassSink {
TEST(RenderSurfaceTest, SanityCheckSurfaceCreatesCorrectRenderPass) {
FakeImplProxy proxy;
- FakeLayerTreeHostImpl host_impl(&proxy);
+ TestSharedBitmapManager shared_bitmap_manager;
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
scoped_ptr<LayerImpl> root_layer =
LayerImpl::Create(host_impl.active_tree(), 1);
diff --git a/chromium/cc/layers/scrollbar_layer_impl_base.cc b/chromium/cc/layers/scrollbar_layer_impl_base.cc
index 362465be3b0..9db025407d8 100644
--- a/chromium/cc/layers/scrollbar_layer_impl_base.cc
+++ b/chromium/cc/layers/scrollbar_layer_impl_base.cc
@@ -5,7 +5,7 @@
#include "cc/layers/scrollbar_layer_impl_base.h"
#include <algorithm>
-#include "cc/layers/layer.h"
+#include "cc/trees/layer_tree_impl.h"
#include "ui/gfx/rect_conversions.h"
namespace cc {
@@ -14,10 +14,12 @@ ScrollbarLayerImplBase::ScrollbarLayerImplBase(
LayerTreeImpl* tree_impl,
int id,
ScrollbarOrientation orientation,
- bool is_left_side_vertical_scrollbar)
+ bool is_left_side_vertical_scrollbar,
+ bool is_overlay)
: LayerImpl(tree_impl, id),
- scroll_layer_id_(Layer::INVALID_ID),
- is_overlay_scrollbar_(false),
+ scroll_layer_(NULL),
+ clip_layer_(NULL),
+ is_overlay_scrollbar_(is_overlay),
thumb_thickness_scale_factor_(1.f),
current_pos_(0.f),
maximum_(0),
@@ -26,16 +28,81 @@ ScrollbarLayerImplBase::ScrollbarLayerImplBase(
vertical_adjust_(0.f),
visible_to_total_length_ratio_(1.f) {}
+ScrollbarLayerImplBase::~ScrollbarLayerImplBase() {}
+
void ScrollbarLayerImplBase::PushPropertiesTo(LayerImpl* layer) {
+ float active_opacity = layer->opacity();
LayerImpl::PushPropertiesTo(layer);
+ layer->SetOpacity(active_opacity);
+ DCHECK(layer->ToScrollbarLayer());
+ layer->ToScrollbarLayer()->set_is_overlay_scrollbar(is_overlay_scrollbar_);
+ PushScrollClipPropertiesTo(layer);
+}
+
+void ScrollbarLayerImplBase::PushScrollClipPropertiesTo(LayerImpl* layer) {
+ DCHECK(layer->ToScrollbarLayer());
+ layer->ToScrollbarLayer()->SetScrollLayerById(ScrollLayerId());
+ layer->ToScrollbarLayer()->SetClipLayerById(ClipLayerId());
}
ScrollbarLayerImplBase* ScrollbarLayerImplBase::ToScrollbarLayer() {
return this;
}
+namespace {
+
+typedef void (LayerImpl::*ScrollbarRegistrationOperation)(
+ ScrollbarLayerImplBase*);
+
+void RegisterScrollbarWithLayers(ScrollbarLayerImplBase* scrollbar,
+ LayerImpl* container_layer,
+ LayerImpl* scroll_layer,
+ ScrollbarRegistrationOperation operation) {
+ if (!container_layer || !scroll_layer)
+ return;
+
+ DCHECK(scrollbar);
+
+ // Scrollbars must be notifed of changes to their scroll and container layers
+ // and all scrollable layers in between.
+ for (LayerImpl* current_layer = scroll_layer;
+ current_layer && current_layer != container_layer->parent();
+ current_layer = current_layer->parent()) {
+ // TODO(wjmaclean) We shouldn't need to exempt the scroll_layer from the
+ // scrollable() test below. https://crbug.com/367858.
+ if (current_layer->scrollable() || current_layer == container_layer ||
+ current_layer == scroll_layer)
+ (current_layer->*operation)(scrollbar);
+ }
+}
+} // namespace
+
+void ScrollbarLayerImplBase::SetScrollLayerById(int id) {
+ LayerImpl* scroll_layer = layer_tree_impl()->LayerById(id);
+ if (scroll_layer_ == scroll_layer)
+ return;
+
+ RegisterScrollbarWithLayers(
+ this, clip_layer_, scroll_layer_, &LayerImpl::RemoveScrollbar);
+ scroll_layer_ = scroll_layer;
+ RegisterScrollbarWithLayers(
+ this, clip_layer_, scroll_layer_, &LayerImpl::AddScrollbar);
+}
+
+void ScrollbarLayerImplBase::SetClipLayerById(int id) {
+ LayerImpl* clip_layer = layer_tree_impl()->LayerById(id);
+ if (clip_layer_ == clip_layer)
+ return;
+
+ RegisterScrollbarWithLayers(
+ this, clip_layer_, scroll_layer_, &LayerImpl::RemoveScrollbar);
+ clip_layer_ = clip_layer;
+ RegisterScrollbarWithLayers(
+ this, clip_layer_, scroll_layer_, &LayerImpl::AddScrollbar);
+}
+
gfx::Rect ScrollbarLayerImplBase::ScrollbarLayerRectToContentRect(
- gfx::RectF layer_rect) const {
+ const gfx::RectF& layer_rect) const {
// Don't intersect with the bounds as in LayerRectToContentRect() because
// layer_rect here might be in coordinates of the containing layer.
gfx::RectF content_rect = gfx::ScaleRect(layer_rect,
@@ -66,6 +133,9 @@ void ScrollbarLayerImplBase::SetVerticalAdjust(float vertical_adjust) {
}
void ScrollbarLayerImplBase::SetVisibleToTotalLengthRatio(float ratio) {
+ if (!IsThumbResizable())
+ return;
+
if (visible_to_total_length_ratio_ == ratio)
return;
visible_to_total_length_ratio_ = ratio;
@@ -174,4 +244,11 @@ gfx::Rect ScrollbarLayerImplBase::ComputeThumbQuadRect() const {
return ScrollbarLayerRectToContentRect(thumb_rect);
}
+void ScrollbarLayerImplBase::ScrollbarParametersDidChange() {
+ if (!clip_layer_ || !scroll_layer_)
+ return;
+
+ scroll_layer_->SetScrollbarPosition(this, clip_layer_);
+}
+
} // namespace cc
diff --git a/chromium/cc/layers/scrollbar_layer_impl_base.h b/chromium/cc/layers/scrollbar_layer_impl_base.h
index 360ef970895..e7a2fc7ff9c 100644
--- a/chromium/cc/layers/scrollbar_layer_impl_base.h
+++ b/chromium/cc/layers/scrollbar_layer_impl_base.h
@@ -7,6 +7,7 @@
#include "cc/base/cc_export.h"
#include "cc/input/scrollbar.h"
+#include "cc/layers/layer.h"
#include "cc/layers/layer_impl.h"
namespace cc {
@@ -15,8 +16,16 @@ class LayerTreeImpl;
class CC_EXPORT ScrollbarLayerImplBase : public LayerImpl {
public:
- int ScrollLayerId() const { return scroll_layer_id_; }
- void set_scroll_layer_id(int id) { scroll_layer_id_ = id; }
+ int ScrollLayerId() const {
+ return scroll_layer_ ? scroll_layer_->id() : Layer::INVALID_ID;
+ }
+ void ClearScrollLayer() { scroll_layer_ = NULL; }
+ void SetScrollLayerById(int id);
+ int ClipLayerId() const {
+ return clip_layer_ ? clip_layer_->id() : Layer::INVALID_ID;
+ }
+ void ClearClipLayer() { clip_layer_ = NULL; }
+ void SetClipLayerById(int id);
float current_pos() const { return current_pos_; }
void SetCurrentPos(float current_pos);
@@ -37,6 +46,7 @@ class CC_EXPORT ScrollbarLayerImplBase : public LayerImpl {
virtual void PushPropertiesTo(LayerImpl* layer) OVERRIDE;
virtual ScrollbarLayerImplBase* ToScrollbarLayer() OVERRIDE;
+ void PushScrollClipPropertiesTo(LayerImpl* layer);
void SetVisibleToTotalLengthRatio(float ratio);
virtual gfx::Rect ComputeThumbQuadRect() const;
@@ -46,14 +56,17 @@ class CC_EXPORT ScrollbarLayerImplBase : public LayerImpl {
}
void SetThumbThicknessScaleFactor(float thumb_thickness_scale_factor);
+ void ScrollbarParametersDidChange();
+
protected:
ScrollbarLayerImplBase(LayerTreeImpl* tree_impl,
int id,
ScrollbarOrientation orientation,
- bool is_left_side_vertical_scrollbar);
- virtual ~ScrollbarLayerImplBase() {}
+ bool is_left_side_vertical_scrollbar,
+ bool is_overlay);
+ virtual ~ScrollbarLayerImplBase();
- gfx::Rect ScrollbarLayerRectToContentRect(gfx::RectF layer_rect) const;
+ gfx::Rect ScrollbarLayerRectToContentRect(const gfx::RectF& layer_rect) const;
float visible_to_total_length_ratio() const {
return visible_to_total_length_ratio_;
@@ -64,9 +77,13 @@ class CC_EXPORT ScrollbarLayerImplBase : public LayerImpl {
virtual int ThumbLength() const = 0;
virtual float TrackLength() const = 0;
virtual int TrackStart() const = 0;
+ // Indicates whether the thumb length can be changed without going back to the
+ // main thread.
+ virtual bool IsThumbResizable() const = 0;
private:
- int scroll_layer_id_;
+ LayerImpl* scroll_layer_;
+ LayerImpl* clip_layer_;
bool is_overlay_scrollbar_;
float thumb_thickness_scale_factor_;
diff --git a/chromium/cc/layers/scrollbar_layer_interface.h b/chromium/cc/layers/scrollbar_layer_interface.h
index bbb0da6ae2b..e76fc27aeb7 100644
--- a/chromium/cc/layers/scrollbar_layer_interface.h
+++ b/chromium/cc/layers/scrollbar_layer_interface.h
@@ -10,10 +10,15 @@
namespace cc {
+class Layer;
+class LayerImpl;
+
class CC_EXPORT ScrollbarLayerInterface {
public:
virtual int ScrollLayerId() const = 0;
- virtual void SetScrollLayerId(int id) = 0;
+ virtual void SetScrollLayer(int layer_id) = 0;
+ virtual void SetClipLayer(int layer_id) = 0;
+ virtual void PushScrollClipPropertiesTo(LayerImpl* layer) = 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 53a9fa87b68..2d00e01bb37 100644
--- a/chromium/cc/layers/scrollbar_layer_unittest.cc
+++ b/chromium/cc/layers/scrollbar_layer_unittest.cc
@@ -24,6 +24,7 @@
#include "cc/test/test_web_graphics_context_3d.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/layer_tree_impl.h"
+#include "cc/trees/occlusion_tracker.h"
#include "cc/trees/single_thread_proxy.h"
#include "cc/trees/tree_synchronizer.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -32,23 +33,26 @@
namespace cc {
namespace {
-LayerImpl* LayerImplForScrollAreaAndScrollbar(
- FakeLayerTreeHost* host,
- scoped_ptr<Scrollbar> scrollbar,
- bool reverse_order,
- bool use_solid_color_scrollbar,
- int thumb_thickness) {
+LayerImpl* LayerImplForScrollAreaAndScrollbar(FakeLayerTreeHost* host,
+ scoped_ptr<Scrollbar> scrollbar,
+ bool reverse_order,
+ bool use_solid_color_scrollbar,
+ int thumb_thickness,
+ int track_start) {
scoped_refptr<Layer> layer_tree_root = Layer::Create();
scoped_refptr<Layer> child1 = Layer::Create();
scoped_refptr<Layer> child2;
if (use_solid_color_scrollbar) {
const bool kIsLeftSideVerticalScrollbar = false;
- child2 = SolidColorScrollbarLayer::Create(
- scrollbar->Orientation(), thumb_thickness,
- kIsLeftSideVerticalScrollbar, child1->id());
+ child2 = SolidColorScrollbarLayer::Create(scrollbar->Orientation(),
+ thumb_thickness,
+ track_start,
+ kIsLeftSideVerticalScrollbar,
+ child1->id());
} else {
child2 = PaintedScrollbarLayer::Create(scrollbar.Pass(), child1->id());
}
+ child2->ToScrollbarLayer()->SetClipLayer(layer_tree_root->id());
layer_tree_root->AddChild(child1);
layer_tree_root->InsertChild(child2, reverse_order ? 0 : 1);
host->SetRootLayer(layer_tree_root);
@@ -59,28 +63,30 @@ TEST(ScrollbarLayerTest, ResolveScrollLayerPointer) {
scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create();
scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar);
LayerImpl* layer_impl_tree_root = LayerImplForScrollAreaAndScrollbar(
- host.get(), scrollbar.Pass(), false, false, 0);
+ host.get(), scrollbar.Pass(), false, false, 0, 0);
LayerImpl* cc_child1 = layer_impl_tree_root->children()[0];
PaintedScrollbarLayerImpl* cc_child2 =
static_cast<PaintedScrollbarLayerImpl*>(
layer_impl_tree_root->children()[1]);
- EXPECT_EQ(cc_child1->horizontal_scrollbar_layer(), cc_child2);
+ EXPECT_EQ(cc_child1->scrollbars()->size(), 1UL);
+ EXPECT_EQ(*(cc_child1->scrollbars()->begin()), cc_child2);
}
TEST(ScrollbarLayerTest, ResolveScrollLayerPointer_ReverseOrder) {
scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create();
scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar);
LayerImpl* layer_impl_tree_root = LayerImplForScrollAreaAndScrollbar(
- host.get(), scrollbar.Pass(), true, false, 0);
+ host.get(), scrollbar.Pass(), true, false, 0, 0);
PaintedScrollbarLayerImpl* cc_child1 =
static_cast<PaintedScrollbarLayerImpl*>(
layer_impl_tree_root->children()[0]);
LayerImpl* cc_child2 = layer_impl_tree_root->children()[1];
- EXPECT_EQ(cc_child2->horizontal_scrollbar_layer(), cc_child1);
+ EXPECT_EQ(cc_child2->scrollbars()->size(), 1UL);
+ EXPECT_EQ(*(cc_child2->scrollbars()->begin()), cc_child1);
}
TEST(ScrollbarLayerTest, ShouldScrollNonOverlayOnMainThread) {
@@ -89,7 +95,7 @@ TEST(ScrollbarLayerTest, ShouldScrollNonOverlayOnMainThread) {
// Create and attach a non-overlay scrollbar.
scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar);
LayerImpl* layer_impl_tree_root = LayerImplForScrollAreaAndScrollbar(
- host.get(), scrollbar.Pass(), false, false, 0);
+ host.get(), scrollbar.Pass(), false, false, 0, 0);
PaintedScrollbarLayerImpl* scrollbar_layer_impl =
static_cast<PaintedScrollbarLayerImpl*>(
layer_impl_tree_root->children()[1]);
@@ -105,7 +111,7 @@ TEST(ScrollbarLayerTest, ShouldScrollNonOverlayOnMainThread) {
scrollbar.reset(new FakeScrollbar(false, false, true));
layer_impl_tree_root = LayerImplForScrollAreaAndScrollbar(
- host.get(), scrollbar.Pass(), false, false, 0);
+ host.get(), scrollbar.Pass(), false, false, 0, 0);
scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>(
layer_impl_tree_root->children()[1]);
@@ -121,19 +127,24 @@ TEST(PaintedScrollbarLayerTest, ScrollOffsetSynchronization) {
scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar);
scoped_refptr<Layer> layer_tree_root = Layer::Create();
+ scoped_refptr<Layer> scroll_layer = Layer::Create();
scoped_refptr<Layer> content_layer = Layer::Create();
scoped_refptr<Layer> scrollbar_layer =
PaintedScrollbarLayer::Create(scrollbar.Pass(), layer_tree_root->id());
- layer_tree_root->SetScrollable(true);
- layer_tree_root->SetScrollOffset(gfx::Vector2d(10, 20));
- layer_tree_root->SetMaxScrollOffset(gfx::Vector2d(30, 50));
- layer_tree_root->SetBounds(gfx::Size(100, 200));
+ // Choose bounds to give max_scroll_offset = (30, 50).
+ layer_tree_root->SetBounds(gfx::Size(70, 150));
+ scroll_layer->SetScrollClipLayerId(layer_tree_root->id());
+ scroll_layer->SetScrollOffset(gfx::Vector2d(10, 20));
+ scroll_layer->SetBounds(gfx::Size(100, 200));
content_layer->SetBounds(gfx::Size(100, 200));
host->SetRootLayer(layer_tree_root);
- layer_tree_root->AddChild(content_layer);
+ layer_tree_root->AddChild(scroll_layer);
+ scroll_layer->AddChild(content_layer);
layer_tree_root->AddChild(scrollbar_layer);
+ scrollbar_layer->ToScrollbarLayer()->SetScrollLayer(scroll_layer->id());
+ scrollbar_layer->ToScrollbarLayer()->SetClipLayer(layer_tree_root->id());
layer_tree_root->SavePaintProperties();
content_layer->SavePaintProperties();
@@ -147,10 +158,11 @@ TEST(PaintedScrollbarLayerTest, ScrollOffsetSynchronization) {
EXPECT_EQ(10.f, cc_scrollbar_layer->current_pos());
EXPECT_EQ(30, cc_scrollbar_layer->maximum());
- layer_tree_root->SetScrollOffset(gfx::Vector2d(100, 200));
- layer_tree_root->SetMaxScrollOffset(gfx::Vector2d(300, 500));
- layer_tree_root->SetBounds(gfx::Size(1000, 2000));
+ layer_tree_root->SetBounds(gfx::Size(700, 1500));
layer_tree_root->SavePaintProperties();
+ scroll_layer->SetBounds(gfx::Size(1000, 2000));
+ scroll_layer->SetScrollOffset(gfx::Vector2d(100, 200));
+ scroll_layer->SavePaintProperties();
content_layer->SetBounds(gfx::Size(1000, 2000));
content_layer->SavePaintProperties();
@@ -163,65 +175,73 @@ TEST(PaintedScrollbarLayerTest, ScrollOffsetSynchronization) {
EXPECT_EQ(100.f, cc_scrollbar_layer->current_pos());
EXPECT_EQ(300, cc_scrollbar_layer->maximum());
- layer_impl_tree_root->ScrollBy(gfx::Vector2d(12, 34));
+ LayerImpl* scroll_layer_impl = layer_impl_tree_root->children()[0];
+ scroll_layer_impl->ScrollBy(gfx::Vector2d(12, 34));
EXPECT_EQ(112.f, cc_scrollbar_layer->current_pos());
EXPECT_EQ(300, cc_scrollbar_layer->maximum());
}
+#define UPDATE_AND_EXTRACT_LAYER_POINTERS() \
+ do { \
+ scrollbar_layer->UpdateThumbAndTrackGeometry(); \
+ root_clip_layer_impl = host->CommitAndCreateLayerImplTree(); \
+ root_layer_impl = root_clip_layer_impl->children()[0]; \
+ scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>( \
+ root_layer_impl->children()[1]); \
+ scrollbar_layer_impl->ScrollbarParametersDidChange(); \
+ } while (false)
+
TEST(ScrollbarLayerTest, ThumbRect) {
scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create();
+ scoped_refptr<Layer> root_clip_layer = Layer::Create();
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());
- root_layer->SetScrollable(true);
- root_layer->SetMaxScrollOffset(gfx::Vector2d(80, 0));
+ 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));
root_layer->SetBounds(gfx::Size(100, 50));
content_layer->SetBounds(gfx::Size(100, 50));
- host->SetRootLayer(root_layer);
+ host->SetRootLayer(root_clip_layer);
+ root_clip_layer->AddChild(root_layer);
root_layer->AddChild(content_layer);
root_layer->AddChild(scrollbar_layer);
root_layer->SetScrollOffset(gfx::Vector2d(0, 0));
scrollbar_layer->SetBounds(gfx::Size(70, 10));
+ scrollbar_layer->SetScrollLayer(root_layer->id());
+ scrollbar_layer->SetClipLayer(root_clip_layer->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);
scrollbar_layer->fake_scrollbar()->set_thumb_length(4);
scrollbar_layer->UpdateThumbAndTrackGeometry();
+ LayerImpl* root_clip_layer_impl = NULL;
LayerImpl* root_layer_impl = NULL;
PaintedScrollbarLayerImpl* scrollbar_layer_impl = NULL;
// Thumb is at the edge of the scrollbar (should be inset to
// the start of the track within the scrollbar layer's
// position).
- scrollbar_layer->UpdateThumbAndTrackGeometry();
- root_layer_impl = host->CommitAndCreateLayerImplTree();
- scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>(
- root_layer_impl->children()[1]);
+ UPDATE_AND_EXTRACT_LAYER_POINTERS();
EXPECT_EQ(gfx::Rect(10, 0, 4, 10).ToString(),
scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
// Under-scroll (thumb position should clamp and be unchanged).
root_layer->SetScrollOffset(gfx::Vector2d(-5, 0));
- scrollbar_layer->UpdateThumbAndTrackGeometry();
- root_layer_impl = host->CommitAndCreateLayerImplTree();
- scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>(
- root_layer_impl->children()[1]);
+ UPDATE_AND_EXTRACT_LAYER_POINTERS();
EXPECT_EQ(gfx::Rect(10, 0, 4, 10).ToString(),
scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
// Over-scroll (thumb position should clamp on the far side).
root_layer->SetScrollOffset(gfx::Vector2d(85, 0));
- scrollbar_layer->UpdateThumbAndTrackGeometry();
- root_layer_impl = host->CommitAndCreateLayerImplTree();
- scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>(
- root_layer_impl->children()[1]);
+ UPDATE_AND_EXTRACT_LAYER_POINTERS();
EXPECT_EQ(gfx::Rect(56, 0, 4, 10).ToString(),
scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
@@ -229,10 +249,7 @@ TEST(ScrollbarLayerTest, ThumbRect) {
scrollbar_layer->fake_scrollbar()->set_thumb_thickness(4);
scrollbar_layer->fake_scrollbar()->set_thumb_length(6);
- scrollbar_layer->UpdateThumbAndTrackGeometry();
- root_layer_impl = host->CommitAndCreateLayerImplTree();
- scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>(
- root_layer_impl->children()[1]);
+ UPDATE_AND_EXTRACT_LAYER_POINTERS();
EXPECT_EQ(gfx::Rect(54, 0, 6, 4).ToString(),
scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
@@ -241,10 +258,7 @@ TEST(ScrollbarLayerTest, ThumbRect) {
scrollbar_layer->fake_scrollbar()->set_location(gfx::Point(30, 10));
scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 10, 50, 10));
- scrollbar_layer->UpdateThumbAndTrackGeometry();
- root_layer_impl = host->CommitAndCreateLayerImplTree();
- scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>(
- root_layer_impl->children()[1]);
+ UPDATE_AND_EXTRACT_LAYER_POINTERS();
EXPECT_EQ(gfx::Rect(44, 0, 6, 4).ToString(),
scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
@@ -253,16 +267,14 @@ TEST(ScrollbarLayerTest, ThumbRect) {
// position).
scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 12, 50, 6));
- scrollbar_layer->UpdateThumbAndTrackGeometry();
- root_layer_impl = host->CommitAndCreateLayerImplTree();
- scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>(
- root_layer_impl->children()[1]);
+ UPDATE_AND_EXTRACT_LAYER_POINTERS();
EXPECT_EQ(gfx::Rect(44, 0, 6, 4).ToString(),
scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
}
TEST(ScrollbarLayerTest, SolidColorDrawQuads) {
const int kThumbThickness = 3;
+ const int kTrackStart = 0;
const int kTrackLength = 100;
LayerTreeSettings layer_tree_settings;
@@ -271,7 +283,7 @@ TEST(ScrollbarLayerTest, SolidColorDrawQuads) {
scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar(false, true, true));
LayerImpl* layer_impl_tree_root = LayerImplForScrollAreaAndScrollbar(
- host.get(), scrollbar.Pass(), false, true, kThumbThickness);
+ host.get(), scrollbar.Pass(), false, true, kThumbThickness, kTrackStart);
ScrollbarLayerImplBase* scrollbar_layer_impl =
static_cast<SolidColorScrollbarLayerImpl*>(
layer_impl_tree_root->children()[1]);
@@ -282,7 +294,9 @@ TEST(ScrollbarLayerTest, SolidColorDrawQuads) {
// Thickness should be overridden to 3.
{
- MockQuadCuller quad_culler;
+ MockOcclusionTracker<LayerImpl> occlusion_tracker;
+ scoped_ptr<RenderPass> render_pass = RenderPass::Create();
+ MockQuadCuller quad_culler(render_pass.get(), &occlusion_tracker);
AppendQuadsData data;
scrollbar_layer_impl->AppendQuads(&quad_culler, &data);
@@ -296,7 +310,9 @@ TEST(ScrollbarLayerTest, SolidColorDrawQuads) {
scrollbar_layer_impl->draw_properties().contents_scale_x = 2.f;
scrollbar_layer_impl->draw_properties().contents_scale_y = 2.f;
{
- MockQuadCuller quad_culler;
+ MockOcclusionTracker<LayerImpl> occlusion_tracker;
+ scoped_ptr<RenderPass> render_pass = RenderPass::Create();
+ MockQuadCuller quad_culler(render_pass.get(), &occlusion_tracker);
AppendQuadsData data;
scrollbar_layer_impl->AppendQuads(&quad_culler, &data);
@@ -312,7 +328,9 @@ TEST(ScrollbarLayerTest, SolidColorDrawQuads) {
// current viewport state.
scrollbar_layer_impl->SetVisibleToTotalLengthRatio(0.2f);
{
- MockQuadCuller quad_culler;
+ MockOcclusionTracker<LayerImpl> occlusion_tracker;
+ scoped_ptr<RenderPass> render_pass = RenderPass::Create();
+ MockQuadCuller quad_culler(render_pass.get(), &occlusion_tracker);
AppendQuadsData data;
scrollbar_layer_impl->AppendQuads(&quad_culler, &data);
@@ -325,6 +343,7 @@ TEST(ScrollbarLayerTest, SolidColorDrawQuads) {
TEST(ScrollbarLayerTest, LayerDrivenSolidColorDrawQuads) {
const int kThumbThickness = 3;
+ const int kTrackStart = 0;
const int kTrackLength = 10;
LayerTreeSettings layer_tree_settings;
@@ -332,24 +351,46 @@ TEST(ScrollbarLayerTest, LayerDrivenSolidColorDrawQuads) {
FakeLayerTreeHost::Create(layer_tree_settings);
scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar(false, true, true));
- LayerImpl* layer_impl_tree_root = LayerImplForScrollAreaAndScrollbar(
- host.get(), scrollbar.Pass(), false, true, kThumbThickness);
+
+ {
+ scoped_refptr<Layer> layer_tree_root = Layer::Create();
+ scoped_refptr<Layer> scroll_layer = Layer::Create();
+ 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,
+ child1->id());
+ child2->ToScrollbarLayer()->SetScrollLayer(scroll_layer->id());
+ child2->ToScrollbarLayer()->SetClipLayer(layer_tree_root->id());
+ scroll_layer->AddChild(child1);
+ scroll_layer->InsertChild(child2, 1);
+ layer_tree_root->AddChild(scroll_layer);
+ host->SetRootLayer(layer_tree_root);
+ }
+ LayerImpl* layer_impl_tree_root = host->CommitAndCreateLayerImplTree();
+ LayerImpl* scroll_layer_impl = layer_impl_tree_root->children()[0];
+
ScrollbarLayerImplBase* scrollbar_layer_impl =
- static_cast<PaintedScrollbarLayerImpl*>(
- layer_impl_tree_root->children()[1]);
+ static_cast<PaintedScrollbarLayerImpl*>(scroll_layer_impl->children()[1]);
+
+ // Choose layer bounds to give max_scroll_offset = (8, 8).
+ layer_impl_tree_root->SetBounds(gfx::Size(2, 2));
+ scroll_layer_impl->SetBounds(gfx::Size(10, 10));
+ scroll_layer_impl->ScrollBy(gfx::Vector2dF(4.f, 0.f));
scrollbar_layer_impl->SetBounds(gfx::Size(kTrackLength, kThumbThickness));
scrollbar_layer_impl->SetCurrentPos(4.f);
scrollbar_layer_impl->SetMaximum(8);
- layer_impl_tree_root->SetScrollable(true);
- layer_impl_tree_root->SetHorizontalScrollbarLayer(scrollbar_layer_impl);
- layer_impl_tree_root->SetMaxScrollOffset(gfx::Vector2d(8, 8));
- layer_impl_tree_root->SetBounds(gfx::Size(2, 2));
- layer_impl_tree_root->ScrollBy(gfx::Vector2dF(4.f, 0.f));
-
{
- MockQuadCuller quad_culler;
+ MockOcclusionTracker<LayerImpl> occlusion_tracker;
+ scoped_ptr<RenderPass> render_pass = RenderPass::Create();
+ MockQuadCuller quad_culler(render_pass.get(), &occlusion_tracker);
+
AppendQuadsData data;
scrollbar_layer_impl->AppendQuads(&quad_culler, &data);
@@ -364,21 +405,35 @@ class ScrollbarLayerSolidColorThumbTest : public testing::Test {
public:
ScrollbarLayerSolidColorThumbTest() {
LayerTreeSettings layer_tree_settings;
- host_impl_.reset(new FakeLayerTreeHostImpl(layer_tree_settings, &proxy_));
+ host_impl_.reset(new FakeLayerTreeHostImpl(
+ layer_tree_settings, &proxy_, &shared_bitmap_manager_));
const int kThumbThickness = 3;
+ const int kTrackStart = 0;
const bool kIsLeftSideVerticalScrollbar = false;
-
- horizontal_scrollbar_layer_ = SolidColorScrollbarLayerImpl::Create(
- host_impl_->active_tree(), 1, HORIZONTAL, kThumbThickness,
- kIsLeftSideVerticalScrollbar);
- vertical_scrollbar_layer_ = SolidColorScrollbarLayerImpl::Create(
- host_impl_->active_tree(), 2, VERTICAL, kThumbThickness,
- kIsLeftSideVerticalScrollbar);
+ const bool kIsOverlayScrollbar = false;
+
+ horizontal_scrollbar_layer_ =
+ SolidColorScrollbarLayerImpl::Create(host_impl_->active_tree(),
+ 1,
+ HORIZONTAL,
+ kThumbThickness,
+ kTrackStart,
+ kIsLeftSideVerticalScrollbar,
+ kIsOverlayScrollbar);
+ vertical_scrollbar_layer_ =
+ SolidColorScrollbarLayerImpl::Create(host_impl_->active_tree(),
+ 2,
+ VERTICAL,
+ kThumbThickness,
+ kTrackStart,
+ kIsLeftSideVerticalScrollbar,
+ kIsOverlayScrollbar);
}
protected:
FakeImplProxy proxy_;
+ TestSharedBitmapManager shared_bitmap_manager_;
scoped_ptr<FakeLayerTreeHostImpl> host_impl_;
scoped_ptr<SolidColorScrollbarLayerImpl> horizontal_scrollbar_layer_;
scoped_ptr<SolidColorScrollbarLayerImpl> vertical_scrollbar_layer_;
@@ -453,19 +508,20 @@ class ScrollbarLayerTestMaxTextureSize : public LayerTreeTest {
public:
ScrollbarLayerTestMaxTextureSize() {}
- void SetScrollbarBounds(gfx::Size bounds) { bounds_ = bounds; }
+ void SetScrollbarBounds(const gfx::Size& bounds) { bounds_ = bounds; }
virtual void BeginTest() OVERRIDE {
+ scroll_layer_ = Layer::Create();
+ layer_tree_host()->root_layer()->AddChild(scroll_layer_);
+
scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar);
- scrollbar_layer_ = PaintedScrollbarLayer::Create(scrollbar.Pass(), 1);
+ scrollbar_layer_ =
+ PaintedScrollbarLayer::Create(scrollbar.Pass(), scroll_layer_->id());
+ scrollbar_layer_->SetScrollLayer(scroll_layer_->id());
scrollbar_layer_->SetLayerTreeHost(layer_tree_host());
scrollbar_layer_->SetBounds(bounds_);
layer_tree_host()->root_layer()->AddChild(scrollbar_layer_);
- scroll_layer_ = Layer::Create();
- scrollbar_layer_->SetScrollLayerId(scroll_layer_->id());
- layer_tree_host()->root_layer()->AddChild(scroll_layer_);
-
PostSetNeedsCommitToMainThread();
}
@@ -549,6 +605,13 @@ class MockLayerTreeHost : public LayerTreeHost {
return gfx::Size();
}
+ UIResourceBitmap* ui_resource_bitmap(UIResourceId id) {
+ UIResourceBitmapMap::iterator iter = ui_resource_bitmap_map_.find(id);
+ if (iter != ui_resource_bitmap_map_.end())
+ return &iter->second;
+ return NULL;
+ }
+
private:
typedef base::hash_map<UIResourceId, UIResourceBitmap>
UIResourceBitmapMap;
@@ -579,10 +642,12 @@ class ScrollbarLayerTestResourceCreation : public testing::Test {
scoped_refptr<Layer> scrollbar_layer;
if (use_solid_color_scrollbar) {
const int kThumbThickness = 3;
+ const int kTrackStart = 0;
const bool kIsLeftSideVerticalScrollbar = false;
scrollbar_layer =
SolidColorScrollbarLayer::Create(scrollbar->Orientation(),
kThumbThickness,
+ kTrackStart,
kIsLeftSideVerticalScrollbar,
layer_tree_root->id());
} else {
@@ -592,13 +657,11 @@ class ScrollbarLayerTestResourceCreation : public testing::Test {
layer_tree_root->AddChild(content_layer);
layer_tree_root->AddChild(scrollbar_layer);
- layer_tree_host_->InitializeOutputSurfaceIfNeeded();
layer_tree_host_->SetRootLayer(layer_tree_root);
scrollbar_layer->SetIsDrawable(true);
scrollbar_layer->SetBounds(gfx::Size(100, 100));
layer_tree_root->SetScrollOffset(gfx::Vector2d(10, 20));
- layer_tree_root->SetMaxScrollOffset(gfx::Vector2d(30, 50));
layer_tree_root->SetBounds(gfx::Size(100, 200));
content_layer->SetBounds(gfx::Size(100, 200));
scrollbar_layer->draw_properties().content_bounds = gfx::Size(100, 200);
@@ -611,7 +674,8 @@ class ScrollbarLayerTestResourceCreation : public testing::Test {
EXPECT_EQ(scrollbar_layer->layer_tree_host(), layer_tree_host_.get());
ResourceUpdateQueue queue;
- OcclusionTracker occlusion_tracker(gfx::Rect(), false);
+ gfx::Rect screen_space_clip_rect;
+ OcclusionTracker<Layer> occlusion_tracker(screen_space_clip_rect);
scrollbar_layer->SavePaintProperties();
for (int update_counter = 0; update_counter < num_updates; update_counter++)
@@ -670,7 +734,6 @@ class ScaledScrollbarLayerTestResourceCreation : public testing::Test {
layer_tree_root->AddChild(content_layer);
layer_tree_root->AddChild(scrollbar_layer);
- layer_tree_host_->InitializeOutputSurfaceIfNeeded();
layer_tree_host_->SetRootLayer(layer_tree_root);
scrollbar_layer->SetIsDrawable(true);
@@ -698,7 +761,8 @@ class ScaledScrollbarLayerTestResourceCreation : public testing::Test {
EXPECT_EQ(scrollbar_layer->layer_tree_host(), layer_tree_host_.get());
ResourceUpdateQueue queue;
- OcclusionTracker occlusion_tracker(gfx::Rect(), false);
+ gfx::Rect screen_space_clip_rect;
+ OcclusionTracker<Layer> occlusion_tracker(screen_space_clip_rect);
scrollbar_layer->SavePaintProperties();
scrollbar_layer->Update(&queue, &occlusion_tracker);
@@ -734,5 +798,105 @@ TEST_F(ScaledScrollbarLayerTestResourceCreation, ScaledResourceUpload) {
TestResourceUpload(4.1f);
}
+class ScaledScrollbarLayerTestScaledRasterization : public testing::Test {
+ public:
+ ScaledScrollbarLayerTestScaledRasterization()
+ : fake_client_(FakeLayerTreeHostClient::DIRECT_3D) {}
+
+ void TestScale(const gfx::Rect scrollbar_rect, const float test_scale) {
+ layer_tree_host_.reset(
+ new MockLayerTreeHost(&fake_client_, layer_tree_settings_));
+
+ bool paint_during_update = true;
+ bool has_thumb = false;
+ 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->AddChild(scrollbar_layer);
+
+ layer_tree_host_->SetRootLayer(layer_tree_root);
+
+ scrollbar_layer->SetBounds(scrollbar_rect.size());
+ scrollbar_layer->SetPosition(scrollbar_rect.origin());
+ scrollbar_layer->fake_scrollbar()->set_location(scrollbar_rect.origin());
+ scrollbar_layer->fake_scrollbar()->set_track_rect(scrollbar_rect);
+ gfx::SizeF scaled_size =
+ gfx::ScaleSize(scrollbar_layer->bounds(), test_scale, test_scale);
+ gfx::PointF scaled_location =
+ gfx::ScalePoint(scrollbar_layer->position(), test_scale, test_scale);
+ scrollbar_layer->draw_properties().content_bounds =
+ gfx::Size(scaled_size.width(), scaled_size.height());
+ scrollbar_layer->draw_properties().contents_scale_x = test_scale;
+ scrollbar_layer->draw_properties().contents_scale_y = test_scale;
+ scrollbar_layer->draw_properties().visible_content_rect =
+ gfx::Rect(scaled_location.x(),
+ scaled_location.y(),
+ scaled_size.width(),
+ scaled_size.height());
+
+ ResourceUpdateQueue queue;
+ gfx::Rect screen_space_clip_rect;
+ OcclusionTracker<Layer> occlusion_tracker(screen_space_clip_rect);
+ scrollbar_layer->SavePaintProperties();
+
+ scrollbar_layer->Update(&queue, &occlusion_tracker);
+
+ UIResourceBitmap* bitmap = layer_tree_host_->ui_resource_bitmap(
+ scrollbar_layer->track_resource_id());
+
+ DCHECK(bitmap);
+
+ AutoLockUIResourceBitmap locked_bitmap(*bitmap);
+
+ const SkColor* pixels =
+ reinterpret_cast<const SkColor*>(locked_bitmap.GetPixels());
+ SkColor color = argb_to_skia(
+ scrollbar_layer->fake_scrollbar()->paint_fill_color());
+ int width = bitmap->GetSize().width();
+ int height = bitmap->GetSize().height();
+
+ // Make sure none of the corners of the bitmap were inadvertently clipped.
+ EXPECT_EQ(color, pixels[0])
+ << "Top left pixel doesn't match scrollbar color.";
+
+ EXPECT_EQ(color, pixels[width - 1])
+ << "Top right pixel doesn't match scrollbar color.";
+
+ EXPECT_EQ(color, pixels[width * (height - 1)])
+ << "Bottom left pixel doesn't match scrollbar color.";
+
+ EXPECT_EQ(color, pixels[width * height - 1])
+ << "Bottom right pixel doesn't match scrollbar color.";
+ }
+
+ protected:
+ // On Android, Skia uses ABGR
+ static SkColor argb_to_skia(SkColor c) {
+ return (SkColorGetA(c) << SK_A32_SHIFT) |
+ (SkColorGetR(c) << SK_R32_SHIFT) |
+ (SkColorGetG(c) << SK_G32_SHIFT) |
+ (SkColorGetB(c) << SK_B32_SHIFT);
+ }
+
+ FakeLayerTreeHostClient fake_client_;
+ LayerTreeSettings layer_tree_settings_;
+ scoped_ptr<MockLayerTreeHost> layer_tree_host_;
+};
+
+TEST_F(ScaledScrollbarLayerTestScaledRasterization, TestLostPrecisionInClip) {
+ // Try rasterization at coordinates and scale that caused problematic
+ // rounding and clipping errors.
+ // Vertical Scrollbars.
+ TestScale(gfx::Rect(1240, 0, 15, 1333), 2.7754839f);
+ TestScale(gfx::Rect(1240, 0, 15, 677), 2.46677136f);
+
+ // Horizontal Scrollbars.
+ TestScale(gfx::Rect(0, 1240, 1333, 15), 2.7754839f);
+ TestScale(gfx::Rect(0, 1240, 677, 15), 2.46677136f);
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/layers/scrollbar_theme_painter.h b/chromium/cc/layers/scrollbar_theme_painter.h
index f7553ac0e28..8f3e68d8dcb 100644
--- a/chromium/cc/layers/scrollbar_theme_painter.h
+++ b/chromium/cc/layers/scrollbar_theme_painter.h
@@ -19,16 +19,24 @@ class CC_EXPORT ScrollbarThemePainter {
public:
virtual ~ScrollbarThemePainter() {}
- virtual void PaintScrollbarBackground(SkCanvas* canvas, gfx::Rect rect) = 0;
- virtual void PaintTrackBackground(SkCanvas* canvas, gfx::Rect rect) = 0;
- virtual void PaintBackTrackPart(SkCanvas* canvas, gfx::Rect rect) = 0;
- virtual void PaintForwardTrackPart(SkCanvas* canvas, gfx::Rect rect) = 0;
- virtual void PaintBackButtonStart(SkCanvas* canvas, gfx::Rect rect) = 0;
- virtual void PaintBackButtonEnd(SkCanvas* canvas, gfx::Rect rect) = 0;
- virtual void PaintForwardButtonStart(SkCanvas* canvas, gfx::Rect rect) = 0;
- virtual void PaintForwardButtonEnd(SkCanvas* canvas, gfx::Rect rect) = 0;
- virtual void PaintTickmarks(SkCanvas* canvas, gfx::Rect rect) = 0;
- virtual void PaintThumb(SkCanvas* canvas, gfx::Rect rect) = 0;
+ virtual void PaintScrollbarBackground(SkCanvas* canvas,
+ const gfx::Rect& rect) = 0;
+ virtual void PaintTrackBackground(SkCanvas* canvas,
+ const gfx::Rect& rect) = 0;
+ virtual void PaintBackTrackPart(SkCanvas* canvas,
+ const gfx::Rect& rect) = 0;
+ virtual void PaintForwardTrackPart(SkCanvas* canvas,
+ const gfx::Rect& rect) = 0;
+ virtual void PaintBackButtonStart(SkCanvas* canvas,
+ const gfx::Rect& rect) = 0;
+ virtual void PaintBackButtonEnd(SkCanvas* canvas,
+ const gfx::Rect& rect) = 0;
+ virtual void PaintForwardButtonStart(SkCanvas* canvas,
+ const gfx::Rect& rect) = 0;
+ virtual void PaintForwardButtonEnd(SkCanvas* canvas,
+ const gfx::Rect& rect) = 0;
+ virtual void PaintTickmarks(SkCanvas* canvas, const gfx::Rect& rect) = 0;
+ virtual void PaintThumb(SkCanvas* canvas, const gfx::Rect& rect) = 0;
};
} // namespace cc
diff --git a/chromium/cc/layers/solid_color_layer_impl.cc b/chromium/cc/layers/solid_color_layer_impl.cc
index faa967be279..1f44b383204 100644
--- a/chromium/cc/layers/solid_color_layer_impl.cc
+++ b/chromium/cc/layers/solid_color_layer_impl.cc
@@ -24,9 +24,11 @@ scoped_ptr<LayerImpl> SolidColorLayerImpl::CreateLayerImpl(
void SolidColorLayerImpl::AppendQuads(QuadSink* quad_sink,
AppendQuadsData* append_quads_data) {
- SharedQuadState* shared_quad_state =
- quad_sink->UseSharedQuadState(CreateSharedQuadState());
- AppendDebugBorderQuad(quad_sink, shared_quad_state, append_quads_data);
+ SharedQuadState* shared_quad_state = quad_sink->CreateSharedQuadState();
+ PopulateSharedQuadState(shared_quad_state);
+
+ AppendDebugBorderQuad(
+ quad_sink, content_bounds(), shared_quad_state, append_quads_data);
// We create a series of smaller quads instead of just one large one so that
// the culler can reduce the total pixels drawn.
@@ -34,14 +36,22 @@ void SolidColorLayerImpl::AppendQuads(QuadSink* quad_sink,
int height = content_bounds().height();
for (int x = 0; x < width; x += tile_size_) {
for (int y = 0; y < height; y += tile_size_) {
- gfx::Rect solid_tile_rect(x,
- y,
- std::min(width - x, tile_size_),
- std::min(height - y, tile_size_));
+ gfx::Rect quad_rect(x,
+ y,
+ std::min(width - x, tile_size_),
+ std::min(height - y, tile_size_));
+ gfx::Rect visible_quad_rect = quad_sink->UnoccludedContentRect(
+ quad_rect, draw_properties().target_space_transform);
+ if (visible_quad_rect.IsEmpty())
+ continue;
+
scoped_ptr<SolidColorDrawQuad> quad = SolidColorDrawQuad::Create();
- quad->SetNew(
- shared_quad_state, solid_tile_rect, background_color(), false);
- quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
+ quad->SetNew(shared_quad_state,
+ quad_rect,
+ visible_quad_rect,
+ background_color(),
+ false);
+ quad_sink->Append(quad.PassAs<DrawQuad>());
}
}
}
diff --git a/chromium/cc/layers/solid_color_layer_impl_unittest.cc b/chromium/cc/layers/solid_color_layer_impl_unittest.cc
index 94dd2ffbe9e..b01c343423d 100644
--- a/chromium/cc/layers/solid_color_layer_impl_unittest.cc
+++ b/chromium/cc/layers/solid_color_layer_impl_unittest.cc
@@ -13,6 +13,7 @@
#include "cc/test/fake_layer_tree_host.h"
#include "cc/test/layer_test_common.h"
#include "cc/test/mock_quad_culler.h"
+#include "cc/test/test_shared_bitmap_manager.h"
#include "cc/trees/single_thread_proxy.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -21,12 +22,16 @@ namespace cc {
namespace {
TEST(SolidColorLayerImplTest, VerifyTilingCompleteAndNoOverlap) {
- MockQuadCuller quad_culler;
+ MockOcclusionTracker<LayerImpl> occlusion_tracker;
+ scoped_ptr<RenderPass> render_pass = RenderPass::Create();
+ MockQuadCuller quad_culler(render_pass.get(), &occlusion_tracker);
+
gfx::Size layer_size = gfx::Size(800, 600);
gfx::Rect visible_content_rect = gfx::Rect(layer_size);
FakeImplProxy proxy;
- FakeLayerTreeHostImpl host_impl(&proxy);
+ TestSharedBitmapManager shared_bitmap_manager;
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
scoped_ptr<SolidColorLayerImpl> layer =
SolidColorLayerImpl::Create(host_impl.active_tree(), 1);
layer->draw_properties().visible_content_rect = visible_content_rect;
@@ -45,12 +50,16 @@ TEST(SolidColorLayerImplTest, VerifyTilingCompleteAndNoOverlap) {
TEST(SolidColorLayerImplTest, VerifyCorrectBackgroundColorInQuad) {
SkColor test_color = 0xFFA55AFF;
- MockQuadCuller quad_culler;
+ MockOcclusionTracker<LayerImpl> occlusion_tracker;
+ scoped_ptr<RenderPass> render_pass = RenderPass::Create();
+ MockQuadCuller quad_culler(render_pass.get(), &occlusion_tracker);
+
gfx::Size layer_size = gfx::Size(100, 100);
gfx::Rect visible_content_rect = gfx::Rect(layer_size);
FakeImplProxy proxy;
- FakeLayerTreeHostImpl host_impl(&proxy);
+ TestSharedBitmapManager shared_bitmap_manager;
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
scoped_ptr<SolidColorLayerImpl> layer =
SolidColorLayerImpl::Create(host_impl.active_tree(), 1);
layer->draw_properties().visible_content_rect = visible_content_rect;
@@ -71,12 +80,16 @@ TEST(SolidColorLayerImplTest, VerifyCorrectBackgroundColorInQuad) {
TEST(SolidColorLayerImplTest, VerifyCorrectOpacityInQuad) {
const float opacity = 0.5f;
- MockQuadCuller quad_culler;
+ MockOcclusionTracker<LayerImpl> occlusion_tracker;
+ scoped_ptr<RenderPass> render_pass = RenderPass::Create();
+ MockQuadCuller quad_culler(render_pass.get(), &occlusion_tracker);
+
gfx::Size layer_size = gfx::Size(100, 100);
gfx::Rect visible_content_rect = gfx::Rect(layer_size);
FakeImplProxy proxy;
- FakeLayerTreeHostImpl host_impl(&proxy);
+ TestSharedBitmapManager shared_bitmap_manager;
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
scoped_ptr<SolidColorLayerImpl> layer =
SolidColorLayerImpl::Create(host_impl.active_tree(), 1);
layer->draw_properties().visible_content_rect = visible_content_rect;
@@ -130,7 +143,10 @@ TEST(SolidColorLayerImplTest, VerifyOpaqueRect) {
// should be the full tile.
layer_impl->draw_properties().opacity = 1;
- MockQuadCuller quad_culler;
+ MockOcclusionTracker<LayerImpl> occlusion_tracker;
+ scoped_ptr<RenderPass> render_pass = RenderPass::Create();
+ MockQuadCuller quad_culler(render_pass.get(), &occlusion_tracker);
+
AppendQuadsData data;
layer_impl->AppendQuads(&quad_culler, &data);
@@ -155,7 +171,10 @@ TEST(SolidColorLayerImplTest, VerifyOpaqueRect) {
// should be empty.
layer_impl->draw_properties().opacity = 1;
- MockQuadCuller quad_culler;
+ MockOcclusionTracker<LayerImpl> occlusion_tracker;
+ scoped_ptr<RenderPass> render_pass = RenderPass::Create();
+ MockQuadCuller quad_culler(render_pass.get(), &occlusion_tracker);
+
AppendQuadsData data;
layer_impl->AppendQuads(&quad_culler, &data);
@@ -165,5 +184,56 @@ TEST(SolidColorLayerImplTest, VerifyOpaqueRect) {
}
}
+TEST(SolidColorLayerImplTest, Occlusion) {
+ gfx::Size layer_size(1000, 1000);
+ gfx::Size viewport_size(1000, 1000);
+
+ LayerTestCommon::LayerImplTest impl;
+
+ SolidColorLayerImpl* solid_color_layer_impl =
+ impl.AddChildToRoot<SolidColorLayerImpl>();
+ solid_color_layer_impl->SetBackgroundColor(SkColorSetARGB(255, 10, 20, 30));
+ solid_color_layer_impl->SetBounds(layer_size);
+ solid_color_layer_impl->SetContentBounds(layer_size);
+ solid_color_layer_impl->SetDrawsContent(true);
+
+ impl.CalcDrawProps(viewport_size);
+
+ {
+ SCOPED_TRACE("No occlusion");
+ gfx::Rect occluded;
+ impl.AppendQuadsWithOcclusion(solid_color_layer_impl, occluded);
+
+ LayerTestCommon::VerifyQuadsExactlyCoverRect(impl.quad_list(),
+ gfx::Rect(layer_size));
+ EXPECT_EQ(16u, impl.quad_list().size());
+ }
+
+ {
+ SCOPED_TRACE("Full occlusion");
+ gfx::Rect occluded(solid_color_layer_impl->visible_content_rect());
+ impl.AppendQuadsWithOcclusion(solid_color_layer_impl, occluded);
+
+ LayerTestCommon::VerifyQuadsExactlyCoverRect(impl.quad_list(), gfx::Rect());
+ EXPECT_EQ(impl.quad_list().size(), 0u);
+ }
+
+ {
+ SCOPED_TRACE("Partial occlusion");
+ gfx::Rect occluded(200, 200, 256 * 3, 256 * 3);
+ impl.AppendQuadsWithOcclusion(solid_color_layer_impl, occluded);
+
+ size_t partially_occluded_count = 0;
+ LayerTestCommon::VerifyQuadsCoverRectWithOcclusion(
+ impl.quad_list(),
+ gfx::Rect(layer_size),
+ occluded,
+ &partially_occluded_count);
+ // 4 quads are completely occluded, 8 are partially occluded.
+ EXPECT_EQ(16u - 4u, impl.quad_list().size());
+ EXPECT_EQ(8u, partially_occluded_count);
+ }
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/layers/solid_color_scrollbar_layer.cc b/chromium/cc/layers/solid_color_scrollbar_layer.cc
index d9ed922e5d8..8749398aa68 100644
--- a/chromium/cc/layers/solid_color_scrollbar_layer.cc
+++ b/chromium/cc/layers/solid_color_scrollbar_layer.cc
@@ -12,31 +12,42 @@ namespace cc {
scoped_ptr<LayerImpl> SolidColorScrollbarLayer::CreateLayerImpl(
LayerTreeImpl* tree_impl) {
- return SolidColorScrollbarLayerImpl::Create(
- tree_impl, id(), orientation(), thumb_thickness_,
- is_left_side_vertical_scrollbar_).PassAs<LayerImpl>();
+ const bool kIsOverlayScrollbar = true;
+ return SolidColorScrollbarLayerImpl::Create(tree_impl,
+ id(),
+ orientation(),
+ thumb_thickness_,
+ track_start_,
+ is_left_side_vertical_scrollbar_,
+ kIsOverlayScrollbar)
+ .PassAs<LayerImpl>();
}
scoped_refptr<SolidColorScrollbarLayer> SolidColorScrollbarLayer::Create(
ScrollbarOrientation orientation,
int thumb_thickness,
+ int track_start,
bool is_left_side_vertical_scrollbar,
int scroll_layer_id) {
- return make_scoped_refptr(new SolidColorScrollbarLayer(
- orientation,
- thumb_thickness,
- is_left_side_vertical_scrollbar,
- scroll_layer_id));
+ return make_scoped_refptr(
+ new SolidColorScrollbarLayer(orientation,
+ thumb_thickness,
+ track_start,
+ is_left_side_vertical_scrollbar,
+ scroll_layer_id));
}
SolidColorScrollbarLayer::SolidColorScrollbarLayer(
ScrollbarOrientation orientation,
int thumb_thickness,
+ int track_start,
bool is_left_side_vertical_scrollbar,
int scroll_layer_id)
- : scroll_layer_id_(scroll_layer_id),
+ : scroll_layer_id_(Layer::INVALID_ID),
+ clip_layer_id_(scroll_layer_id),
orientation_(orientation),
thumb_thickness_(thumb_thickness),
+ track_start_(track_start),
is_left_side_vertical_scrollbar_(is_left_side_vertical_scrollbar) {}
SolidColorScrollbarLayer::~SolidColorScrollbarLayer() {}
@@ -45,6 +56,23 @@ ScrollbarLayerInterface* SolidColorScrollbarLayer::ToScrollbarLayer() {
return this;
}
+void SolidColorScrollbarLayer::PushPropertiesTo(LayerImpl* layer) {
+ Layer::PushPropertiesTo(layer);
+ PushScrollClipPropertiesTo(layer);
+}
+
+void SolidColorScrollbarLayer::PushScrollClipPropertiesTo(LayerImpl* layer) {
+ SolidColorScrollbarLayerImpl* scrollbar_layer =
+ static_cast<SolidColorScrollbarLayerImpl*>(layer);
+
+ scrollbar_layer->SetScrollLayerById(scroll_layer_id_);
+ scrollbar_layer->SetClipLayerById(clip_layer_id_);
+}
+
+void SolidColorScrollbarLayer::SetNeedsDisplayRect(const gfx::RectF&) {
+ // Never needs repaint.
+}
+
bool SolidColorScrollbarLayer::OpacityCanAnimateOnImplThread() const {
return true;
}
@@ -53,11 +81,19 @@ int SolidColorScrollbarLayer::ScrollLayerId() const {
return scroll_layer_id_;
}
-void SolidColorScrollbarLayer::SetScrollLayerId(int id) {
- if (id == scroll_layer_id_)
+void SolidColorScrollbarLayer::SetScrollLayer(int layer_id) {
+ if (layer_id == scroll_layer_id_)
+ return;
+
+ scroll_layer_id_ = layer_id;
+ SetNeedsFullTreeSync();
+}
+
+void SolidColorScrollbarLayer::SetClipLayer(int layer_id) {
+ if (layer_id == clip_layer_id_)
return;
- scroll_layer_id_ = id;
+ clip_layer_id_ = layer_id;
SetNeedsFullTreeSync();
}
diff --git a/chromium/cc/layers/solid_color_scrollbar_layer.h b/chromium/cc/layers/solid_color_scrollbar_layer.h
index 9c0dc1ed473..654a6a6ae74 100644
--- a/chromium/cc/layers/solid_color_scrollbar_layer.h
+++ b/chromium/cc/layers/solid_color_scrollbar_layer.h
@@ -20,6 +20,7 @@ class CC_EXPORT SolidColorScrollbarLayer : public ScrollbarLayerInterface,
static scoped_refptr<SolidColorScrollbarLayer> Create(
ScrollbarOrientation orientation,
int thumb_thickness,
+ int track_start,
bool is_left_side_vertical_scrollbar,
int scroll_layer_id);
@@ -27,23 +28,32 @@ class CC_EXPORT SolidColorScrollbarLayer : public ScrollbarLayerInterface,
virtual bool OpacityCanAnimateOnImplThread() const OVERRIDE;
virtual ScrollbarLayerInterface* ToScrollbarLayer() OVERRIDE;
+ virtual void PushPropertiesTo(LayerImpl* layer) OVERRIDE;
+ virtual void PushScrollClipPropertiesTo(LayerImpl* layer) OVERRIDE;
+
+ virtual void SetNeedsDisplayRect(const gfx::RectF&) OVERRIDE;
+
// ScrollbarLayerInterface
virtual int ScrollLayerId() const OVERRIDE;
- virtual void SetScrollLayerId(int id) OVERRIDE;
+ virtual void SetScrollLayer(int layer_id) OVERRIDE;
+ virtual void SetClipLayer(int layer_id) OVERRIDE;
virtual ScrollbarOrientation orientation() const OVERRIDE;
protected:
SolidColorScrollbarLayer(ScrollbarOrientation orientation,
int thumb_thickness,
+ int track_start,
bool is_left_side_vertical_scrollbar,
int scroll_layer_id);
virtual ~SolidColorScrollbarLayer();
private:
int scroll_layer_id_;
+ int clip_layer_id_;
ScrollbarOrientation orientation_;
int thumb_thickness_;
+ int track_start_;
bool is_left_side_vertical_scrollbar_;
DISALLOW_COPY_AND_ASSIGN(SolidColorScrollbarLayer);
diff --git a/chromium/cc/layers/solid_color_scrollbar_layer_impl.cc b/chromium/cc/layers/solid_color_scrollbar_layer_impl.cc
index 9f46a8080f5..1e255ab4192 100644
--- a/chromium/cc/layers/solid_color_scrollbar_layer_impl.cc
+++ b/chromium/cc/layers/solid_color_scrollbar_layer_impl.cc
@@ -15,19 +15,31 @@ scoped_ptr<SolidColorScrollbarLayerImpl> SolidColorScrollbarLayerImpl::Create(
int id,
ScrollbarOrientation orientation,
int thumb_thickness,
- bool is_left_side_vertical_scrollbar) {
- return make_scoped_ptr(new SolidColorScrollbarLayerImpl(
- tree_impl, id, orientation, thumb_thickness,
- is_left_side_vertical_scrollbar));
+ int track_start,
+ bool is_left_side_vertical_scrollbar,
+ bool is_overlay) {
+ return make_scoped_ptr(
+ new SolidColorScrollbarLayerImpl(tree_impl,
+ id,
+ orientation,
+ thumb_thickness,
+ track_start,
+ is_left_side_vertical_scrollbar,
+ is_overlay));
}
SolidColorScrollbarLayerImpl::~SolidColorScrollbarLayerImpl() {}
scoped_ptr<LayerImpl> SolidColorScrollbarLayerImpl::CreateLayerImpl(
LayerTreeImpl* tree_impl) {
- return SolidColorScrollbarLayerImpl::Create(
- tree_impl, id(), orientation(), thumb_thickness_,
- is_left_side_vertical_scrollbar()).PassAs<LayerImpl>();
+ return SolidColorScrollbarLayerImpl::Create(tree_impl,
+ id(),
+ orientation(),
+ thumb_thickness_,
+ track_start_,
+ is_left_side_vertical_scrollbar(),
+ is_overlay_scrollbar())
+ .PassAs<LayerImpl>();
}
SolidColorScrollbarLayerImpl::SolidColorScrollbarLayerImpl(
@@ -35,11 +47,19 @@ SolidColorScrollbarLayerImpl::SolidColorScrollbarLayerImpl(
int id,
ScrollbarOrientation orientation,
int thumb_thickness,
- bool is_left_side_vertical_scrollbar)
- : ScrollbarLayerImplBase(tree_impl, id, orientation,
- is_left_side_vertical_scrollbar),
+ int track_start,
+ bool is_left_side_vertical_scrollbar,
+ bool is_overlay)
+ : ScrollbarLayerImplBase(tree_impl,
+ id,
+ orientation,
+ is_left_side_vertical_scrollbar,
+ is_overlay),
thumb_thickness_(thumb_thickness),
- color_(tree_impl->settings().solid_color_scrollbar_color) {}
+ track_start_(track_start),
+ color_(tree_impl->settings().solid_color_scrollbar_color) {
+ SetOpacity(0.f);
+}
void SolidColorScrollbarLayerImpl::PushPropertiesTo(LayerImpl* layer) {
ScrollbarLayerImplBase::PushPropertiesTo(layer);
@@ -63,26 +83,35 @@ int SolidColorScrollbarLayerImpl::ThumbLength() const {
float SolidColorScrollbarLayerImpl::TrackLength() const {
if (orientation() == HORIZONTAL)
- return bounds().width();
+ return bounds().width() - TrackStart() * 2;
else
- return bounds().height() + vertical_adjust();
+ return bounds().height() + vertical_adjust() - TrackStart() * 2;
}
-int SolidColorScrollbarLayerImpl::TrackStart() const {
- return 0;
+int SolidColorScrollbarLayerImpl::TrackStart() const { return track_start_; }
+
+bool SolidColorScrollbarLayerImpl::IsThumbResizable() const {
+ return true;
}
void SolidColorScrollbarLayerImpl::AppendQuads(QuadSink* quad_sink,
AppendQuadsData* append_quads_data) {
- gfx::Rect thumb_quad_rect = ComputeThumbQuadRect();
+ SharedQuadState* shared_quad_state = quad_sink->CreateSharedQuadState();
+ PopulateSharedQuadState(shared_quad_state);
+
+ AppendDebugBorderQuad(
+ quad_sink, content_bounds(), shared_quad_state, append_quads_data);
- SharedQuadState* shared_quad_state =
- quad_sink->UseSharedQuadState(CreateSharedQuadState());
- AppendDebugBorderQuad(quad_sink, shared_quad_state, append_quads_data);
+ gfx::Rect thumb_quad_rect(ComputeThumbQuadRect());
+ gfx::Rect visible_quad_rect = quad_sink->UnoccludedContentRect(
+ thumb_quad_rect, draw_properties().target_space_transform);
+ if (visible_quad_rect.IsEmpty())
+ return;
scoped_ptr<SolidColorDrawQuad> quad = SolidColorDrawQuad::Create();
- quad->SetNew(shared_quad_state, thumb_quad_rect, color_, false);
- quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
+ quad->SetNew(
+ shared_quad_state, thumb_quad_rect, visible_quad_rect, color_, false);
+ quad_sink->Append(quad.PassAs<DrawQuad>());
}
} // namespace cc
diff --git a/chromium/cc/layers/solid_color_scrollbar_layer_impl.h b/chromium/cc/layers/solid_color_scrollbar_layer_impl.h
index 56cbacd888c..4cea04b4abc 100644
--- a/chromium/cc/layers/solid_color_scrollbar_layer_impl.h
+++ b/chromium/cc/layers/solid_color_scrollbar_layer_impl.h
@@ -17,7 +17,9 @@ class CC_EXPORT SolidColorScrollbarLayerImpl : public ScrollbarLayerImplBase {
int id,
ScrollbarOrientation orientation,
int thumb_thickness,
- bool is_left_side_vertical_scrollbar);
+ int track_start,
+ bool is_left_side_vertical_scrollbar,
+ bool is_overlay);
virtual ~SolidColorScrollbarLayerImpl();
// LayerImpl overrides.
@@ -34,16 +36,20 @@ class CC_EXPORT SolidColorScrollbarLayerImpl : public ScrollbarLayerImplBase {
int id,
ScrollbarOrientation orientation,
int thumb_thickness,
- bool is_left_side_vertical_scrollbar);
+ int track_start,
+ bool is_left_side_vertical_scrollbar,
+ bool is_overlay);
// ScrollbarLayerImplBase implementation.
virtual int ThumbThickness() const OVERRIDE;
virtual int ThumbLength() const OVERRIDE;
virtual float TrackLength() const OVERRIDE;
virtual int TrackStart() const OVERRIDE;
+ virtual bool IsThumbResizable() const OVERRIDE;
private:
int thumb_thickness_;
+ int track_start_;
SkColor color_;
};
diff --git a/chromium/cc/layers/solid_color_scrollbar_layer_impl_unittest.cc b/chromium/cc/layers/solid_color_scrollbar_layer_impl_unittest.cc
new file mode 100644
index 00000000000..5f42636307a
--- /dev/null
+++ b/chromium/cc/layers/solid_color_scrollbar_layer_impl_unittest.cc
@@ -0,0 +1,80 @@
+// 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/layers/solid_color_scrollbar_layer_impl.h"
+
+#include "cc/test/layer_test_common.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+namespace {
+
+TEST(SolidColorScrollbarLayerImplTest, Occlusion) {
+ gfx::Size layer_size(10, 1000);
+ gfx::Size viewport_size(1000, 1000);
+
+ LayerTestCommon::LayerImplTest impl;
+
+ ScrollbarOrientation orientation = VERTICAL;
+ int thumb_thickness = layer_size.width();
+ int track_start = 0;
+ bool is_left_side_vertical_scrollbar = false;
+ bool is_overlay = false;
+
+ SolidColorScrollbarLayerImpl* scrollbar_layer_impl =
+ impl.AddChildToRoot<SolidColorScrollbarLayerImpl>(
+ orientation,
+ thumb_thickness,
+ track_start,
+ is_left_side_vertical_scrollbar,
+ is_overlay);
+ scrollbar_layer_impl->SetBounds(layer_size);
+ scrollbar_layer_impl->SetContentBounds(layer_size);
+ scrollbar_layer_impl->SetDrawsContent(true);
+ scrollbar_layer_impl->SetCurrentPos(100.f / 4);
+ scrollbar_layer_impl->SetMaximum(100);
+ scrollbar_layer_impl->SetVisibleToTotalLengthRatio(1.f / 2);
+ // SolidColorScrollbarLayers construct with opacity = 0.f, so override.
+ scrollbar_layer_impl->SetOpacity(1.f);
+
+ impl.CalcDrawProps(viewport_size);
+
+ gfx::Rect thumb_rect = scrollbar_layer_impl->ComputeThumbQuadRect();
+ EXPECT_EQ(gfx::Rect(0, 500 / 4, 10, layer_size.height() / 2).ToString(),
+ thumb_rect.ToString());
+
+ {
+ SCOPED_TRACE("No occlusion");
+ gfx::Rect occluded;
+ impl.AppendQuadsWithOcclusion(scrollbar_layer_impl, occluded);
+
+ LayerTestCommon::VerifyQuadsExactlyCoverRect(impl.quad_list(), thumb_rect);
+ EXPECT_EQ(1u, impl.quad_list().size());
+ }
+
+ {
+ SCOPED_TRACE("Full occlusion");
+ gfx::Rect occluded(scrollbar_layer_impl->visible_content_rect());
+ impl.AppendQuadsWithOcclusion(scrollbar_layer_impl, occluded);
+
+ LayerTestCommon::VerifyQuadsExactlyCoverRect(impl.quad_list(), gfx::Rect());
+ EXPECT_EQ(impl.quad_list().size(), 0u);
+ }
+
+ {
+ SCOPED_TRACE("Partial occlusion");
+ gfx::Rect occluded(0, 0, 5, 1000);
+ impl.AppendQuadsWithOcclusion(scrollbar_layer_impl, occluded);
+
+ size_t partially_occluded_count = 0;
+ LayerTestCommon::VerifyQuadsCoverRectWithOcclusion(
+ impl.quad_list(), thumb_rect, occluded, &partially_occluded_count);
+ // The layer outputs one quad, which is partially occluded.
+ EXPECT_EQ(1u, impl.quad_list().size());
+ EXPECT_EQ(1u, partially_occluded_count);
+ }
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/layers/surface_layer.cc b/chromium/cc/layers/surface_layer.cc
new file mode 100644
index 00000000000..f345b7423dd
--- /dev/null
+++ b/chromium/cc/layers/surface_layer.cc
@@ -0,0 +1,40 @@
+// 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/layers/surface_layer.h"
+
+#include "cc/layers/surface_layer_impl.h"
+
+namespace cc {
+
+scoped_refptr<SurfaceLayer> SurfaceLayer::Create() {
+ return make_scoped_refptr(new SurfaceLayer);
+}
+
+SurfaceLayer::SurfaceLayer() : Layer() {
+}
+
+SurfaceLayer::~SurfaceLayer() {}
+
+void SurfaceLayer::SetSurfaceId(SurfaceId surface_id) {
+ surface_id_ = surface_id;
+ SetNeedsPushProperties();
+}
+
+scoped_ptr<LayerImpl> SurfaceLayer::CreateLayerImpl(LayerTreeImpl* tree_impl) {
+ return SurfaceLayerImpl::Create(tree_impl, id()).PassAs<LayerImpl>();
+}
+
+bool SurfaceLayer::DrawsContent() const {
+ return !surface_id_.is_null() && Layer::DrawsContent();
+}
+
+void SurfaceLayer::PushPropertiesTo(LayerImpl* layer) {
+ Layer::PushPropertiesTo(layer);
+ SurfaceLayerImpl* layer_impl = static_cast<SurfaceLayerImpl*>(layer);
+
+ layer_impl->SetSurfaceId(surface_id_);
+}
+
+} // namespace cc
diff --git a/chromium/cc/layers/surface_layer.h b/chromium/cc/layers/surface_layer.h
new file mode 100644
index 00000000000..cf150ab480e
--- /dev/null
+++ b/chromium/cc/layers/surface_layer.h
@@ -0,0 +1,41 @@
+// 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_LAYERS_SURFACE_LAYER_H_
+#define CC_LAYERS_SURFACE_LAYER_H_
+
+#include "cc/base/cc_export.h"
+#include "cc/layers/layer.h"
+#include "cc/surfaces/surface_id.h"
+
+namespace cc {
+
+// A layer that renders a surface referencing the output of another compositor
+// instance or client.
+class CC_EXPORT SurfaceLayer : public Layer {
+ public:
+ static scoped_refptr<SurfaceLayer> Create();
+
+ void SetSurfaceId(SurfaceId surface_id);
+
+ // Layer overrides.
+ virtual scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl)
+ OVERRIDE;
+ virtual bool DrawsContent() const OVERRIDE;
+ virtual void PushPropertiesTo(LayerImpl* layer) OVERRIDE;
+
+ protected:
+ SurfaceLayer();
+
+ private:
+ virtual ~SurfaceLayer();
+
+ SurfaceId surface_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(SurfaceLayer);
+};
+
+} // namespace cc
+
+#endif // CC_LAYERS_SURFACE_LAYER_H_
diff --git a/chromium/cc/layers/surface_layer_impl.cc b/chromium/cc/layers/surface_layer_impl.cc
new file mode 100644
index 00000000000..6891c144850
--- /dev/null
+++ b/chromium/cc/layers/surface_layer_impl.cc
@@ -0,0 +1,75 @@
+// 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/layers/surface_layer_impl.h"
+
+#include "cc/debug/debug_colors.h"
+#include "cc/layers/quad_sink.h"
+#include "cc/quads/surface_draw_quad.h"
+
+namespace cc {
+
+SurfaceLayerImpl::SurfaceLayerImpl(LayerTreeImpl* tree_impl, int id)
+ : LayerImpl(tree_impl, id) {
+}
+
+SurfaceLayerImpl::~SurfaceLayerImpl() {}
+
+scoped_ptr<LayerImpl> SurfaceLayerImpl::CreateLayerImpl(
+ LayerTreeImpl* tree_impl) {
+ return SurfaceLayerImpl::Create(tree_impl, id()).PassAs<LayerImpl>();
+}
+
+void SurfaceLayerImpl::SetSurfaceId(SurfaceId surface_id) {
+ if (surface_id_ == surface_id)
+ return;
+
+ surface_id_ = surface_id;
+ NoteLayerPropertyChanged();
+}
+
+void SurfaceLayerImpl::PushPropertiesTo(LayerImpl* layer) {
+ LayerImpl::PushPropertiesTo(layer);
+ SurfaceLayerImpl* layer_impl = static_cast<SurfaceLayerImpl*>(layer);
+
+ layer_impl->SetSurfaceId(surface_id_);
+}
+
+void SurfaceLayerImpl::AppendQuads(QuadSink* quad_sink,
+ AppendQuadsData* append_quads_data) {
+ SharedQuadState* shared_quad_state = quad_sink->CreateSharedQuadState();
+ PopulateSharedQuadState(shared_quad_state);
+
+ AppendDebugBorderQuad(
+ quad_sink, content_bounds(), shared_quad_state, append_quads_data);
+
+ if (surface_id_.is_null())
+ return;
+
+ scoped_ptr<SurfaceDrawQuad> quad = SurfaceDrawQuad::Create();
+ gfx::Rect quad_rect(content_bounds());
+ gfx::Rect visible_quad_rect = quad_sink->UnoccludedContentRect(
+ quad_rect, draw_properties().target_space_transform);
+ if (visible_quad_rect.IsEmpty())
+ return;
+ quad->SetNew(shared_quad_state, quad_rect, visible_quad_rect, surface_id_);
+ quad_sink->Append(quad.PassAs<DrawQuad>());
+}
+
+void SurfaceLayerImpl::GetDebugBorderProperties(SkColor* color,
+ float* width) const {
+ *color = DebugColors::SurfaceLayerBorderColor();
+ *width = DebugColors::SurfaceLayerBorderWidth(layer_tree_impl());
+}
+
+void SurfaceLayerImpl::AsValueInto(base::DictionaryValue* dict) const {
+ LayerImpl::AsValueInto(dict);
+ dict->SetInteger("surface_id", surface_id_.id);
+}
+
+const char* SurfaceLayerImpl::LayerTypeAsString() const {
+ return "cc::SurfaceLayerImpl";
+}
+
+} // namespace cc
diff --git a/chromium/cc/layers/surface_layer_impl.h b/chromium/cc/layers/surface_layer_impl.h
new file mode 100644
index 00000000000..82ac2279e25
--- /dev/null
+++ b/chromium/cc/layers/surface_layer_impl.h
@@ -0,0 +1,47 @@
+// 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_LAYERS_SURFACE_LAYER_IMPL_H_
+#define CC_LAYERS_SURFACE_LAYER_IMPL_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "cc/base/cc_export.h"
+#include "cc/layers/layer_impl.h"
+#include "cc/surfaces/surface_id.h"
+
+namespace cc {
+
+class CC_EXPORT SurfaceLayerImpl : public LayerImpl {
+ public:
+ static scoped_ptr<SurfaceLayerImpl> Create(LayerTreeImpl* tree_impl, int id) {
+ return make_scoped_ptr(new SurfaceLayerImpl(tree_impl, id));
+ }
+ virtual ~SurfaceLayerImpl();
+
+ void SetSurfaceId(SurfaceId surface_id);
+
+ // LayerImpl overrides.
+ virtual scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl)
+ OVERRIDE;
+ virtual void PushPropertiesTo(LayerImpl* layer) OVERRIDE;
+ virtual void AppendQuads(QuadSink* quad_sink,
+ AppendQuadsData* append_quads_data) OVERRIDE;
+
+ protected:
+ SurfaceLayerImpl(LayerTreeImpl* tree_impl, int id);
+
+ private:
+ virtual void GetDebugBorderProperties(SkColor* color,
+ float* width) const OVERRIDE;
+ virtual void AsValueInto(base::DictionaryValue* dict) const OVERRIDE;
+ virtual const char* LayerTypeAsString() const OVERRIDE;
+
+ SurfaceId surface_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(SurfaceLayerImpl);
+};
+
+} // namespace cc
+
+#endif // CC_LAYERS_SURFACE_LAYER_IMPL_H_
diff --git a/chromium/cc/layers/surface_layer_impl_unittest.cc b/chromium/cc/layers/surface_layer_impl_unittest.cc
new file mode 100644
index 00000000000..fb0ed2fe451
--- /dev/null
+++ b/chromium/cc/layers/surface_layer_impl_unittest.cc
@@ -0,0 +1,66 @@
+// 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/layers/surface_layer_impl.h"
+
+#include "cc/test/layer_test_common.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+namespace {
+
+TEST(SurfaceLayerImplTest, Occlusion) {
+ gfx::Size layer_size(1000, 1000);
+ gfx::Size viewport_size(1000, 1000);
+
+ LayerTestCommon::LayerImplTest impl;
+
+ SurfaceLayerImpl* surface_layer_impl =
+ impl.AddChildToRoot<SurfaceLayerImpl>();
+ surface_layer_impl->SetBounds(layer_size);
+ surface_layer_impl->SetContentBounds(layer_size);
+ surface_layer_impl->SetDrawsContent(true);
+ SurfaceId surface_id(9);
+ surface_layer_impl->SetSurfaceId(surface_id);
+
+ impl.CalcDrawProps(viewport_size);
+
+ {
+ SCOPED_TRACE("No occlusion");
+ gfx::Rect occluded;
+ impl.AppendQuadsWithOcclusion(surface_layer_impl, occluded);
+
+ LayerTestCommon::VerifyQuadsExactlyCoverRect(impl.quad_list(),
+ gfx::Rect(layer_size));
+ EXPECT_EQ(1u, impl.quad_list().size());
+ }
+
+ {
+ SCOPED_TRACE("Full occlusion");
+ gfx::Rect occluded(surface_layer_impl->visible_content_rect());
+ impl.AppendQuadsWithOcclusion(surface_layer_impl, occluded);
+
+ LayerTestCommon::VerifyQuadsExactlyCoverRect(impl.quad_list(), gfx::Rect());
+ EXPECT_EQ(impl.quad_list().size(), 0u);
+ }
+
+ {
+ SCOPED_TRACE("Partial occlusion");
+ gfx::Rect occluded(200, 0, 800, 1000);
+ impl.AppendQuadsWithOcclusion(surface_layer_impl, occluded);
+
+ size_t partially_occluded_count = 0;
+ LayerTestCommon::VerifyQuadsCoverRectWithOcclusion(
+ impl.quad_list(),
+ gfx::Rect(layer_size),
+ occluded,
+ &partially_occluded_count);
+ // The layer outputs one quad, which is partially occluded.
+ EXPECT_EQ(1u, impl.quad_list().size());
+ EXPECT_EQ(1u, partially_occluded_count);
+ }
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/layers/texture_layer.cc b/chromium/cc/layers/texture_layer.cc
index 195d05ddaba..05391fe5d63 100644
--- a/chromium/cc/layers/texture_layer.cc
+++ b/chromium/cc/layers/texture_layer.cc
@@ -16,27 +16,20 @@
namespace cc {
-scoped_refptr<TextureLayer> TextureLayer::Create(TextureLayerClient* client) {
- return scoped_refptr<TextureLayer>(new TextureLayer(client, false));
-}
-
scoped_refptr<TextureLayer> TextureLayer::CreateForMailbox(
TextureLayerClient* client) {
- return scoped_refptr<TextureLayer>(new TextureLayer(client, true));
+ return scoped_refptr<TextureLayer>(new TextureLayer(client));
}
-TextureLayer::TextureLayer(TextureLayerClient* client, bool uses_mailbox)
+TextureLayer::TextureLayer(TextureLayerClient* client)
: Layer(),
client_(client),
- uses_mailbox_(uses_mailbox),
flipped_(true),
uv_top_left_(0.f, 0.f),
uv_bottom_right_(1.f, 1.f),
premultiplied_alpha_(true),
blend_background_color_(false),
rate_limit_context_(false),
- content_committed_(false),
- texture_id_(0),
needs_set_mailbox_(false) {
vertex_opacity_[0] = 1.0f;
vertex_opacity_[1] = 1.0f;
@@ -51,15 +44,15 @@ void TextureLayer::ClearClient() {
if (rate_limit_context_ && client_ && layer_tree_host())
layer_tree_host()->StopRateLimiter();
client_ = NULL;
- if (uses_mailbox_)
- SetTextureMailbox(TextureMailbox(), scoped_ptr<SingleReleaseCallback>());
- else
- SetTextureId(0);
+ ClearTexture();
+}
+
+void TextureLayer::ClearTexture() {
+ SetTextureMailbox(TextureMailbox(), scoped_ptr<SingleReleaseCallback>());
}
scoped_ptr<LayerImpl> TextureLayer::CreateLayerImpl(LayerTreeImpl* tree_impl) {
- return TextureLayerImpl::Create(tree_impl, id(), uses_mailbox_).
- PassAs<LayerImpl>();
+ return TextureLayerImpl::Create(tree_impl, id()).PassAs<LayerImpl>();
}
void TextureLayer::SetFlipped(bool flipped) {
@@ -69,7 +62,8 @@ void TextureLayer::SetFlipped(bool flipped) {
SetNeedsCommit();
}
-void TextureLayer::SetUV(gfx::PointF top_left, gfx::PointF bottom_right) {
+void TextureLayer::SetUV(const gfx::PointF& top_left,
+ const gfx::PointF& bottom_right) {
if (uv_top_left_ == top_left && uv_bottom_right_ == bottom_right)
return;
uv_top_left_ = top_left;
@@ -118,33 +112,23 @@ void TextureLayer::SetRateLimitContext(bool rate_limit) {
rate_limit_context_ = rate_limit;
}
-void TextureLayer::SetTextureId(unsigned id) {
- DCHECK(!uses_mailbox_);
- if (texture_id_ == id)
- return;
- if (texture_id_ && layer_tree_host())
- layer_tree_host()->AcquireLayerTextures();
- texture_id_ = id;
- SetNeedsCommit();
- // The texture id needs to be removed from the active tree before the
- // commit is called complete.
- SetNextCommitWaitsForActivation();
-}
-
void TextureLayer::SetTextureMailboxInternal(
const TextureMailbox& mailbox,
scoped_ptr<SingleReleaseCallback> release_callback,
- bool requires_commit) {
- DCHECK(uses_mailbox_);
+ bool requires_commit,
+ bool allow_mailbox_reuse) {
DCHECK(!mailbox.IsValid() || !holder_ref_ ||
- !mailbox.Equals(holder_ref_->holder()->mailbox()));
+ !mailbox.Equals(holder_ref_->holder()->mailbox()) ||
+ allow_mailbox_reuse);
DCHECK_EQ(mailbox.IsValid(), !!release_callback);
// If we never commited the mailbox, we need to release it here.
- if (mailbox.IsValid())
- holder_ref_ = MailboxHolder::Create(mailbox, release_callback.Pass());
- else
+ if (mailbox.IsValid()) {
+ holder_ref_ =
+ TextureMailboxHolder::Create(mailbox, release_callback.Pass());
+ } else {
holder_ref_.reset();
+ }
needs_set_mailbox_ = true;
// If we are within a commit, no need to do it again immediately after.
if (requires_commit)
@@ -160,18 +144,29 @@ void TextureLayer::SetTextureMailboxInternal(
void TextureLayer::SetTextureMailbox(
const TextureMailbox& mailbox,
scoped_ptr<SingleReleaseCallback> release_callback) {
+ bool requires_commit = true;
+ bool allow_mailbox_reuse = false;
SetTextureMailboxInternal(
- mailbox,
- release_callback.Pass(),
- true /* requires_commit */);
+ mailbox, release_callback.Pass(), requires_commit, allow_mailbox_reuse);
}
-void TextureLayer::WillModifyTexture() {
- if (!uses_mailbox_ && layer_tree_host() && (DrawsContent() ||
- content_committed_)) {
- layer_tree_host()->AcquireLayerTextures();
- content_committed_ = false;
- }
+static void IgnoreReleaseCallback(uint32 sync_point, bool lost) {}
+
+void TextureLayer::SetTextureMailboxWithoutReleaseCallback(
+ const TextureMailbox& mailbox) {
+ // We allow reuse of the mailbox if there is a new sync point signalling new
+ // content, and the release callback goes nowhere since we'll be calling it
+ // multiple times for the same mailbox.
+ DCHECK(!mailbox.IsValid() || !holder_ref_ ||
+ !mailbox.Equals(holder_ref_->holder()->mailbox()) ||
+ mailbox.sync_point() != holder_ref_->holder()->mailbox().sync_point());
+ scoped_ptr<SingleReleaseCallback> release;
+ bool requires_commit = true;
+ bool allow_mailbox_reuse = true;
+ if (mailbox.IsValid())
+ release = SingleReleaseCallback::Create(base::Bind(&IgnoreReleaseCallback));
+ SetTextureMailboxInternal(
+ mailbox, release.Pass(), requires_commit, allow_mailbox_reuse);
}
void TextureLayer::SetNeedsDisplayRect(const gfx::RectF& dirty_rect) {
@@ -188,19 +183,13 @@ void TextureLayer::SetLayerTreeHost(LayerTreeHost* host) {
}
if (layer_tree_host()) {
- if (texture_id_) {
- layer_tree_host()->AcquireLayerTextures();
- // The texture id needs to be removed from the active tree before the
- // commit is called complete.
- SetNextCommitWaitsForActivation();
- }
if (rate_limit_context_ && client_)
layer_tree_host()->StopRateLimiter();
}
// If we're removed from the tree, the TextureLayerImpl will be destroyed, and
// we will need to set the mailbox again on a new TextureLayerImpl the next
// time we push.
- if (!host && uses_mailbox_ && holder_ref_) {
+ if (!host && holder_ref_) {
needs_set_mailbox_ = true;
// The active frame needs to be replaced and the mailbox returned before the
// commit is called complete.
@@ -210,34 +199,27 @@ void TextureLayer::SetLayerTreeHost(LayerTreeHost* host) {
}
bool TextureLayer::DrawsContent() const {
- return (client_ || texture_id_ || holder_ref_) && Layer::DrawsContent();
+ return (client_ || holder_ref_) && Layer::DrawsContent();
}
bool TextureLayer::Update(ResourceUpdateQueue* queue,
- const OcclusionTracker* occlusion) {
+ const OcclusionTracker<Layer>* occlusion) {
bool updated = Layer::Update(queue, occlusion);
if (client_) {
- if (uses_mailbox_) {
- TextureMailbox mailbox;
- scoped_ptr<SingleReleaseCallback> release_callback;
- if (client_->PrepareTextureMailbox(
- &mailbox,
- &release_callback,
- layer_tree_host()->UsingSharedMemoryResources())) {
- // Already within a commit, no need to do another one immediately.
- SetTextureMailboxInternal(
- mailbox,
- release_callback.Pass(),
- false /* requires_commit */);
- updated = true;
- }
- } else {
- texture_id_ = client_->PrepareTexture();
+ TextureMailbox mailbox;
+ scoped_ptr<SingleReleaseCallback> release_callback;
+ if (client_->PrepareTextureMailbox(
+ &mailbox,
+ &release_callback,
+ layer_tree_host()->UsingSharedMemoryResources())) {
+ // Already within a commit, no need to do another one immediately.
+ bool requires_commit = false;
+ bool allow_mailbox_reuse = false;
+ SetTextureMailboxInternal(mailbox,
+ release_callback.Pass(),
+ requires_commit,
+ allow_mailbox_reuse);
updated = true;
- SetNeedsPushProperties();
- // The texture id needs to be removed from the active tree before the
- // commit is called complete.
- SetNextCommitWaitsForActivation();
}
}
@@ -251,25 +233,22 @@ void TextureLayer::PushPropertiesTo(LayerImpl* layer) {
Layer::PushPropertiesTo(layer);
TextureLayerImpl* texture_layer = static_cast<TextureLayerImpl*>(layer);
- texture_layer->set_flipped(flipped_);
- texture_layer->set_uv_top_left(uv_top_left_);
- texture_layer->set_uv_bottom_right(uv_bottom_right_);
- texture_layer->set_vertex_opacity(vertex_opacity_);
- texture_layer->set_premultiplied_alpha(premultiplied_alpha_);
- texture_layer->set_blend_background_color(blend_background_color_);
- if (uses_mailbox_ && needs_set_mailbox_) {
+ texture_layer->SetFlipped(flipped_);
+ texture_layer->SetUVTopLeft(uv_top_left_);
+ texture_layer->SetUVBottomRight(uv_bottom_right_);
+ texture_layer->SetVertexOpacity(vertex_opacity_);
+ texture_layer->SetPremultipliedAlpha(premultiplied_alpha_);
+ texture_layer->SetBlendBackgroundColor(blend_background_color_);
+ if (needs_set_mailbox_) {
TextureMailbox texture_mailbox;
scoped_ptr<SingleReleaseCallback> release_callback;
if (holder_ref_) {
- MailboxHolder* holder = holder_ref_->holder();
+ TextureMailboxHolder* holder = holder_ref_->holder();
texture_mailbox = holder->mailbox();
release_callback = holder->GetCallbackForImplThread();
}
texture_layer->SetTextureMailbox(texture_mailbox, release_callback.Pass());
needs_set_mailbox_ = false;
- } else {
- texture_layer->set_texture_id(texture_id_);
- content_committed_ = DrawsContent();
}
}
@@ -283,17 +262,18 @@ Region TextureLayer::VisibleContentOpaqueRegion() const {
return Region();
}
-TextureLayer::MailboxHolder::MainThreadReference::MainThreadReference(
- MailboxHolder* holder)
+TextureLayer::TextureMailboxHolder::MainThreadReference::MainThreadReference(
+ TextureMailboxHolder* holder)
: holder_(holder) {
holder_->InternalAddRef();
}
-TextureLayer::MailboxHolder::MainThreadReference::~MainThreadReference() {
+TextureLayer::TextureMailboxHolder::MainThreadReference::
+ ~MainThreadReference() {
holder_->InternalRelease();
}
-TextureLayer::MailboxHolder::MailboxHolder(
+TextureLayer::TextureMailboxHolder::TextureMailboxHolder(
const TextureMailbox& mailbox,
scoped_ptr<SingleReleaseCallback> release_callback)
: message_loop_(BlockingTaskRunner::current()),
@@ -301,42 +281,42 @@ TextureLayer::MailboxHolder::MailboxHolder(
mailbox_(mailbox),
release_callback_(release_callback.Pass()),
sync_point_(mailbox.sync_point()),
- is_lost_(false) {
-}
+ is_lost_(false) {}
-TextureLayer::MailboxHolder::~MailboxHolder() {
+TextureLayer::TextureMailboxHolder::~TextureMailboxHolder() {
DCHECK_EQ(0u, internal_references_);
}
-scoped_ptr<TextureLayer::MailboxHolder::MainThreadReference>
-TextureLayer::MailboxHolder::Create(
+scoped_ptr<TextureLayer::TextureMailboxHolder::MainThreadReference>
+TextureLayer::TextureMailboxHolder::Create(
const TextureMailbox& mailbox,
scoped_ptr<SingleReleaseCallback> release_callback) {
return scoped_ptr<MainThreadReference>(new MainThreadReference(
- new MailboxHolder(mailbox, release_callback.Pass())));
+ new TextureMailboxHolder(mailbox, release_callback.Pass())));
}
-void TextureLayer::MailboxHolder::Return(unsigned sync_point, bool is_lost) {
+void TextureLayer::TextureMailboxHolder::Return(uint32 sync_point,
+ bool is_lost) {
base::AutoLock lock(arguments_lock_);
sync_point_ = sync_point;
is_lost_ = is_lost;
}
scoped_ptr<SingleReleaseCallback>
-TextureLayer::MailboxHolder::GetCallbackForImplThread() {
+TextureLayer::TextureMailboxHolder::GetCallbackForImplThread() {
// We can't call GetCallbackForImplThread if we released the main thread
// reference.
DCHECK_GT(internal_references_, 0u);
InternalAddRef();
return SingleReleaseCallback::Create(
- base::Bind(&MailboxHolder::ReturnAndReleaseOnImplThread, this));
+ base::Bind(&TextureMailboxHolder::ReturnAndReleaseOnImplThread, this));
}
-void TextureLayer::MailboxHolder::InternalAddRef() {
+void TextureLayer::TextureMailboxHolder::InternalAddRef() {
++internal_references_;
}
-void TextureLayer::MailboxHolder::InternalRelease() {
+void TextureLayer::TextureMailboxHolder::InternalRelease() {
DCHECK(message_loop_->BelongsToCurrentThread());
if (!--internal_references_) {
release_callback_->Run(sync_point_, is_lost_);
@@ -345,11 +325,12 @@ void TextureLayer::MailboxHolder::InternalRelease() {
}
}
-void TextureLayer::MailboxHolder::ReturnAndReleaseOnImplThread(
- unsigned sync_point, bool is_lost) {
+void TextureLayer::TextureMailboxHolder::ReturnAndReleaseOnImplThread(
+ uint32 sync_point,
+ bool is_lost) {
Return(sync_point, is_lost);
- message_loop_->PostTask(FROM_HERE,
- base::Bind(&MailboxHolder::InternalRelease, this));
+ message_loop_->PostTask(
+ FROM_HERE, base::Bind(&TextureMailboxHolder::InternalRelease, this));
}
} // namespace cc
diff --git a/chromium/cc/layers/texture_layer.h b/chromium/cc/layers/texture_layer.h
index 5f137724b23..aa2ed561daa 100644
--- a/chromium/cc/layers/texture_layer.h
+++ b/chromium/cc/layers/texture_layer.h
@@ -21,22 +21,22 @@ class TextureLayerClient;
// A Layer containing a the rendered output of a plugin instance.
class CC_EXPORT TextureLayer : public Layer {
public:
- class CC_EXPORT MailboxHolder
- : public base::RefCountedThreadSafe<MailboxHolder> {
+ class CC_EXPORT TextureMailboxHolder
+ : public base::RefCountedThreadSafe<TextureMailboxHolder> {
public:
class CC_EXPORT MainThreadReference {
public:
- explicit MainThreadReference(MailboxHolder* holder);
+ explicit MainThreadReference(TextureMailboxHolder* holder);
~MainThreadReference();
- MailboxHolder* holder() { return holder_.get(); }
+ TextureMailboxHolder* holder() { return holder_.get(); }
private:
- scoped_refptr<MailboxHolder> holder_;
+ scoped_refptr<TextureMailboxHolder> holder_;
DISALLOW_COPY_AND_ASSIGN(MainThreadReference);
};
const TextureMailbox& mailbox() const { return mailbox_; }
- void Return(unsigned sync_point, bool is_lost);
+ void Return(uint32 sync_point, bool is_lost);
// Gets a ReleaseCallback that can be called from another thread. Note: the
// caller must ensure the callback is called.
@@ -49,17 +49,18 @@ class CC_EXPORT TextureLayer : public Layer {
static scoped_ptr<MainThreadReference> Create(
const TextureMailbox& mailbox,
scoped_ptr<SingleReleaseCallback> release_callback);
- virtual ~MailboxHolder();
+ virtual ~TextureMailboxHolder();
private:
- friend class base::RefCountedThreadSafe<MailboxHolder>;
+ friend class base::RefCountedThreadSafe<TextureMailboxHolder>;
friend class MainThreadReference;
- explicit MailboxHolder(const TextureMailbox& mailbox,
- scoped_ptr<SingleReleaseCallback> release_callback);
+ explicit TextureMailboxHolder(
+ const TextureMailbox& mailbox,
+ scoped_ptr<SingleReleaseCallback> release_callback);
void InternalAddRef();
void InternalRelease();
- void ReturnAndReleaseOnImplThread(unsigned sync_point, bool is_lost);
+ void ReturnAndReleaseOnImplThread(uint32 sync_point, bool is_lost);
// This member is thread safe, and is accessed on main and impl threads.
const scoped_refptr<BlockingTaskRunner> message_loop_;
@@ -75,22 +76,21 @@ class CC_EXPORT TextureLayer : public Layer {
// values of these fields are well-ordered such that the last call to
// ReturnAndReleaseOnImplThread() defines their values.
base::Lock arguments_lock_;
- unsigned sync_point_;
+ uint32 sync_point_;
bool is_lost_;
- DISALLOW_COPY_AND_ASSIGN(MailboxHolder);
+ DISALLOW_COPY_AND_ASSIGN(TextureMailboxHolder);
};
- // If this texture layer requires special preparation logic for each frame
- // driven by the compositor, pass in a non-nil client. Pass in a nil client
- // pointer if texture updates are driven by an external process.
- static scoped_refptr<TextureLayer> Create(TextureLayerClient* client);
-
// Used when mailbox names are specified instead of texture IDs.
static scoped_refptr<TextureLayer> CreateForMailbox(
TextureLayerClient* client);
+ // Resets the client, which also resets the texture.
void ClearClient();
+ // Resets the texture.
+ void ClearTexture();
+
virtual scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl)
OVERRIDE;
@@ -99,7 +99,7 @@ class CC_EXPORT TextureLayer : public Layer {
void SetFlipped(bool flipped);
// Sets a UV transform to be used at draw time. Defaults to (0, 0) and (1, 1).
- void SetUV(gfx::PointF top_left, gfx::PointF bottom_right);
+ void SetUV(const gfx::PointF& top_left, const gfx::PointF& bottom_right);
// Sets an opacity value per vertex. It will be multiplied by the layer
// opacity value.
@@ -121,38 +121,37 @@ class CC_EXPORT TextureLayer : public Layer {
// Requires a non-nil client. Defaults to false.
void SetRateLimitContext(bool rate_limit);
- // Code path for plugins which supply their own texture ID.
- // DEPRECATED. DO NOT USE.
- void SetTextureId(unsigned texture_id);
-
// Code path for plugins which supply their own mailbox.
- bool uses_mailbox() const { return uses_mailbox_; }
void SetTextureMailbox(const TextureMailbox& mailbox,
scoped_ptr<SingleReleaseCallback> release_callback);
- void WillModifyTexture();
+ // Use this for special cases where the same texture is used to back the
+ // TextureLayer across all frames.
+ // WARNING: DON'T ACTUALLY USE THIS WHAT YOU ARE DOING IS WRONG.
+ // TODO(danakj): Remove this when pepper doesn't need it. crbug.com/350204
+ void SetTextureMailboxWithoutReleaseCallback(const TextureMailbox& mailbox);
virtual void SetNeedsDisplayRect(const gfx::RectF& dirty_rect) OVERRIDE;
virtual void SetLayerTreeHost(LayerTreeHost* layer_tree_host) OVERRIDE;
virtual bool DrawsContent() const OVERRIDE;
virtual bool Update(ResourceUpdateQueue* queue,
- const OcclusionTracker* occlusion) OVERRIDE;
+ const OcclusionTracker<Layer>* occlusion) OVERRIDE;
virtual void PushPropertiesTo(LayerImpl* layer) OVERRIDE;
virtual Region VisibleContentOpaqueRegion() const OVERRIDE;
protected:
- TextureLayer(TextureLayerClient* client, bool uses_mailbox);
+ explicit TextureLayer(TextureLayerClient* client);
virtual ~TextureLayer();
private:
void SetTextureMailboxInternal(
const TextureMailbox& mailbox,
scoped_ptr<SingleReleaseCallback> release_callback,
- bool requires_commit);
+ bool requires_commit,
+ bool allow_mailbox_reuse);
TextureLayerClient* client_;
- bool uses_mailbox_;
bool flipped_;
gfx::PointF uv_top_left_;
@@ -162,10 +161,8 @@ class CC_EXPORT TextureLayer : public Layer {
bool premultiplied_alpha_;
bool blend_background_color_;
bool rate_limit_context_;
- bool content_committed_;
- unsigned texture_id_;
- scoped_ptr<MailboxHolder::MainThreadReference> holder_ref_;
+ scoped_ptr<TextureMailboxHolder::MainThreadReference> holder_ref_;
bool needs_set_mailbox_;
DISALLOW_COPY_AND_ASSIGN(TextureLayer);
diff --git a/chromium/cc/layers/texture_layer_client.h b/chromium/cc/layers/texture_layer_client.h
index 47d6ae0e174..0b8b2256fd8 100644
--- a/chromium/cc/layers/texture_layer_client.h
+++ b/chromium/cc/layers/texture_layer_client.h
@@ -13,10 +13,6 @@ class TextureMailbox;
class TextureLayerClient {
public:
- // Called to prepare this layer's texture for compositing.
- // Returns the texture ID to be used for compositing.
- virtual unsigned PrepareTexture() = 0;
-
// Returns true and provides a mailbox if a new frame is available.
// Returns false if no new data is available
// and the old mailbox is to be reused.
diff --git a/chromium/cc/layers/texture_layer_impl.cc b/chromium/cc/layers/texture_layer_impl.cc
index 96b44c75792..abbab25cbc9 100644
--- a/chromium/cc/layers/texture_layer_impl.cc
+++ b/chromium/cc/layers/texture_layer_impl.cc
@@ -17,18 +17,14 @@
namespace cc {
-TextureLayerImpl::TextureLayerImpl(LayerTreeImpl* tree_impl,
- int id,
- bool uses_mailbox)
+TextureLayerImpl::TextureLayerImpl(LayerTreeImpl* tree_impl, int id)
: LayerImpl(tree_impl, id),
- texture_id_(0),
external_texture_resource_(0),
premultiplied_alpha_(true),
blend_background_color_(false),
flipped_(true),
uv_top_left_(0.f, 0.f),
uv_bottom_right_(1.f, 1.f),
- uses_mailbox_(uses_mailbox),
own_mailbox_(false),
valid_texture_copy_(false) {
vertex_opacity_[0] = 1.0f;
@@ -42,37 +38,34 @@ TextureLayerImpl::~TextureLayerImpl() { FreeTextureMailbox(); }
void TextureLayerImpl::SetTextureMailbox(
const TextureMailbox& mailbox,
scoped_ptr<SingleReleaseCallback> release_callback) {
- DCHECK(uses_mailbox_);
DCHECK_EQ(mailbox.IsValid(), !!release_callback);
FreeTextureMailbox();
texture_mailbox_ = mailbox;
release_callback_ = release_callback.Pass();
own_mailbox_ = true;
valid_texture_copy_ = false;
+ SetNeedsPushProperties();
}
scoped_ptr<LayerImpl> TextureLayerImpl::CreateLayerImpl(
LayerTreeImpl* tree_impl) {
- return TextureLayerImpl::Create(tree_impl, id(), uses_mailbox_).
- PassAs<LayerImpl>();
+ return TextureLayerImpl::Create(tree_impl, id()).PassAs<LayerImpl>();
}
void TextureLayerImpl::PushPropertiesTo(LayerImpl* layer) {
LayerImpl::PushPropertiesTo(layer);
TextureLayerImpl* texture_layer = static_cast<TextureLayerImpl*>(layer);
- texture_layer->set_flipped(flipped_);
- texture_layer->set_uv_top_left(uv_top_left_);
- texture_layer->set_uv_bottom_right(uv_bottom_right_);
- texture_layer->set_vertex_opacity(vertex_opacity_);
- texture_layer->set_premultiplied_alpha(premultiplied_alpha_);
- texture_layer->set_blend_background_color(blend_background_color_);
- if (uses_mailbox_ && own_mailbox_) {
+ texture_layer->SetFlipped(flipped_);
+ texture_layer->SetUVTopLeft(uv_top_left_);
+ texture_layer->SetUVBottomRight(uv_bottom_right_);
+ texture_layer->SetVertexOpacity(vertex_opacity_);
+ texture_layer->SetPremultipliedAlpha(premultiplied_alpha_);
+ texture_layer->SetBlendBackgroundColor(blend_background_color_);
+ if (own_mailbox_) {
texture_layer->SetTextureMailbox(texture_mailbox_,
release_callback_.Pass());
own_mailbox_ = false;
- } else {
- texture_layer->set_texture_id(texture_id_);
}
}
@@ -81,76 +74,65 @@ bool TextureLayerImpl::WillDraw(DrawMode draw_mode,
if (draw_mode == DRAW_MODE_RESOURCELESS_SOFTWARE)
return false;
- if (uses_mailbox_) {
- if (own_mailbox_) {
- DCHECK(!external_texture_resource_);
- if ((draw_mode == DRAW_MODE_HARDWARE && texture_mailbox_.IsTexture()) ||
- (draw_mode == DRAW_MODE_SOFTWARE &&
- texture_mailbox_.IsSharedMemory())) {
- external_texture_resource_ =
- resource_provider->CreateResourceFromTextureMailbox(
- texture_mailbox_,
- release_callback_.Pass());
- DCHECK(external_texture_resource_);
- texture_copy_.reset();
- valid_texture_copy_ = false;
- }
- if (external_texture_resource_)
- own_mailbox_ = false;
+ if (own_mailbox_) {
+ DCHECK(!external_texture_resource_);
+ if ((draw_mode == DRAW_MODE_HARDWARE && texture_mailbox_.IsTexture()) ||
+ (draw_mode == DRAW_MODE_SOFTWARE &&
+ texture_mailbox_.IsSharedMemory())) {
+ external_texture_resource_ =
+ resource_provider->CreateResourceFromTextureMailbox(
+ texture_mailbox_, release_callback_.Pass());
+ DCHECK(external_texture_resource_);
+ texture_copy_.reset();
+ valid_texture_copy_ = false;
}
+ if (external_texture_resource_)
+ own_mailbox_ = false;
+ }
- if (!valid_texture_copy_ && draw_mode == DRAW_MODE_HARDWARE &&
- texture_mailbox_.IsSharedMemory()) {
- DCHECK(!external_texture_resource_);
- // Have to upload a copy to a texture for it to be used in a
- // hardware draw.
- if (!texture_copy_)
- texture_copy_ = ScopedResource::Create(resource_provider);
- if (texture_copy_->size() != texture_mailbox_.shared_memory_size() ||
- resource_provider->InUseByConsumer(texture_copy_->id()))
- texture_copy_->Free();
-
- if (!texture_copy_->id()) {
- texture_copy_->Allocate(texture_mailbox_.shared_memory_size(),
- ResourceProvider::TextureUsageAny,
- resource_provider->best_texture_format());
- }
+ if (!valid_texture_copy_ && draw_mode == DRAW_MODE_HARDWARE &&
+ texture_mailbox_.IsSharedMemory()) {
+ DCHECK(!external_texture_resource_);
+ // Have to upload a copy to a texture for it to be used in a
+ // hardware draw.
+ if (!texture_copy_)
+ texture_copy_ = ScopedResource::Create(resource_provider);
+ if (texture_copy_->size() != texture_mailbox_.shared_memory_size() ||
+ resource_provider->InUseByConsumer(texture_copy_->id()))
+ texture_copy_->Free();
+
+ if (!texture_copy_->id()) {
+ texture_copy_->Allocate(texture_mailbox_.shared_memory_size(),
+ ResourceProvider::TextureUsageAny,
+ resource_provider->best_texture_format());
+ }
- if (texture_copy_->id()) {
- std::vector<uint8> swizzled;
- uint8* pixels =
- static_cast<uint8*>(texture_mailbox_.shared_memory()->memory());
-
- if (!PlatformColor::SameComponentOrder(texture_copy_->format())) {
- // Swizzle colors. This is slow, but should be really uncommon.
- swizzled.resize(texture_mailbox_.shared_memory_size_in_bytes());
- for (size_t i = 0; i < texture_mailbox_.shared_memory_size_in_bytes();
- i += 4) {
- swizzled[i] = pixels[i + 2];
- swizzled[i + 1] = pixels[i + 1];
- swizzled[i + 2] = pixels[i];
- swizzled[i + 3] = pixels[i + 3];
- }
- pixels = &swizzled[0];
+ if (texture_copy_->id()) {
+ std::vector<uint8> swizzled;
+ uint8* pixels =
+ static_cast<uint8*>(texture_mailbox_.shared_memory()->memory());
+
+ if (!PlatformColor::SameComponentOrder(texture_copy_->format())) {
+ // Swizzle colors. This is slow, but should be really uncommon.
+ size_t bytes = texture_mailbox_.SharedMemorySizeInBytes();
+ swizzled.resize(bytes);
+ for (size_t i = 0; i < bytes; i += 4) {
+ swizzled[i] = pixels[i + 2];
+ swizzled[i + 1] = pixels[i + 1];
+ swizzled[i + 2] = pixels[i];
+ swizzled[i + 3] = pixels[i + 3];
}
+ pixels = &swizzled[0];
+ }
- resource_provider->SetPixels(
- texture_copy_->id(),
- pixels,
- gfx::Rect(texture_mailbox_.shared_memory_size()),
- gfx::Rect(texture_mailbox_.shared_memory_size()),
- gfx::Vector2d());
+ resource_provider->SetPixels(
+ texture_copy_->id(),
+ pixels,
+ gfx::Rect(texture_mailbox_.shared_memory_size()),
+ gfx::Rect(texture_mailbox_.shared_memory_size()),
+ gfx::Vector2d());
- valid_texture_copy_ = true;
- }
- }
- } else if (texture_id_) {
- DCHECK(!external_texture_resource_);
- if (draw_mode == DRAW_MODE_HARDWARE) {
- external_texture_resource_ =
- resource_provider->CreateResourceFromExternalTexture(
- GL_TEXTURE_2D,
- texture_id_);
+ valid_texture_copy_ = true;
}
}
return (external_texture_resource_ || valid_texture_copy_) &&
@@ -161,9 +143,11 @@ void TextureLayerImpl::AppendQuads(QuadSink* quad_sink,
AppendQuadsData* append_quads_data) {
DCHECK(external_texture_resource_ || valid_texture_copy_);
- SharedQuadState* shared_quad_state =
- quad_sink->UseSharedQuadState(CreateSharedQuadState());
- AppendDebugBorderQuad(quad_sink, shared_quad_state, append_quads_data);
+ SharedQuadState* shared_quad_state = quad_sink->CreateSharedQuadState();
+ PopulateSharedQuadState(shared_quad_state);
+
+ AppendDebugBorderQuad(
+ quad_sink, content_bounds(), shared_quad_state, append_quads_data);
SkColor bg_color = blend_background_color_ ?
background_color() : SK_ColorTRANSPARENT;
@@ -171,12 +155,18 @@ void TextureLayerImpl::AppendQuads(QuadSink* quad_sink,
gfx::Rect quad_rect(content_bounds());
gfx::Rect opaque_rect = opaque ? quad_rect : gfx::Rect();
+ gfx::Rect visible_quad_rect = quad_sink->UnoccludedContentRect(
+ quad_rect, draw_properties().target_space_transform);
+ if (visible_quad_rect.IsEmpty())
+ return;
+
scoped_ptr<TextureDrawQuad> quad = TextureDrawQuad::Create();
ResourceProvider::ResourceId id =
valid_texture_copy_ ? texture_copy_->id() : external_texture_resource_;
quad->SetNew(shared_quad_state,
quad_rect,
opaque_rect,
+ visible_quad_rect,
id,
premultiplied_alpha_,
uv_top_left_,
@@ -184,19 +174,7 @@ void TextureLayerImpl::AppendQuads(QuadSink* quad_sink,
bg_color,
vertex_opacity_,
flipped_);
- quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
-}
-
-void TextureLayerImpl::DidDraw(ResourceProvider* resource_provider) {
- LayerImpl::DidDraw(resource_provider);
- if (uses_mailbox_ || !external_texture_resource_)
- return;
- // TODO(danakj): the following assert will not be true when sending resources
- // to a parent compositor. A synchronization scheme (double-buffering or
- // pipelining of updates) for the client will need to exist to solve this.
- DCHECK(!resource_provider->InUseByConsumer(external_texture_resource_));
- resource_provider->DeleteResource(external_texture_resource_);
- external_texture_resource_ = 0;
+ quad_sink->Append(quad.PassAs<DrawQuad>());
}
Region TextureLayerImpl::VisibleContentOpaqueRegion() const {
@@ -209,25 +187,54 @@ Region TextureLayerImpl::VisibleContentOpaqueRegion() const {
return Region();
}
-void TextureLayerImpl::DidLoseOutputSurface() {
- if (external_texture_resource_ && !uses_mailbox_) {
- ResourceProvider* resource_provider =
- layer_tree_impl()->resource_provider();
- resource_provider->DeleteResource(external_texture_resource_);
- }
+void TextureLayerImpl::ReleaseResources() {
+ FreeTextureMailbox();
texture_copy_.reset();
- texture_id_ = 0;
external_texture_resource_ = 0;
valid_texture_copy_ = false;
}
+void TextureLayerImpl::SetPremultipliedAlpha(bool premultiplied_alpha) {
+ premultiplied_alpha_ = premultiplied_alpha;
+ SetNeedsPushProperties();
+}
+
+void TextureLayerImpl::SetBlendBackgroundColor(bool blend) {
+ blend_background_color_ = blend;
+ SetNeedsPushProperties();
+}
+
+void TextureLayerImpl::SetFlipped(bool flipped) {
+ flipped_ = flipped;
+ SetNeedsPushProperties();
+}
+
+void TextureLayerImpl::SetUVTopLeft(const gfx::PointF top_left) {
+ uv_top_left_ = top_left;
+ SetNeedsPushProperties();
+}
+
+void TextureLayerImpl::SetUVBottomRight(const gfx::PointF bottom_right) {
+ uv_bottom_right_ = bottom_right;
+ SetNeedsPushProperties();
+}
+
+// 1--2
+// | |
+// 0--3
+void TextureLayerImpl::SetVertexOpacity(const float vertex_opacity[4]) {
+ vertex_opacity_[0] = vertex_opacity[0];
+ vertex_opacity_[1] = vertex_opacity[1];
+ vertex_opacity_[2] = vertex_opacity[2];
+ vertex_opacity_[3] = vertex_opacity[3];
+ SetNeedsPushProperties();
+}
+
const char* TextureLayerImpl::LayerTypeAsString() const {
return "cc::TextureLayerImpl";
}
void TextureLayerImpl::FreeTextureMailbox() {
- if (!uses_mailbox_)
- return;
if (own_mailbox_) {
DCHECK(!external_texture_resource_);
if (release_callback_)
diff --git a/chromium/cc/layers/texture_layer_impl.h b/chromium/cc/layers/texture_layer_impl.h
index c20d9604387..82eec95283d 100644
--- a/chromium/cc/layers/texture_layer_impl.h
+++ b/chromium/cc/layers/texture_layer_impl.h
@@ -17,10 +17,8 @@ class ScopedResource;
class CC_EXPORT TextureLayerImpl : public LayerImpl {
public:
- static scoped_ptr<TextureLayerImpl> Create(LayerTreeImpl* tree_impl,
- int id,
- bool uses_mailbox) {
- return make_scoped_ptr(new TextureLayerImpl(tree_impl, id, uses_mailbox));
+ static scoped_ptr<TextureLayerImpl> Create(LayerTreeImpl* tree_impl, int id) {
+ return make_scoped_ptr(new TextureLayerImpl(tree_impl, id));
}
virtual ~TextureLayerImpl();
@@ -32,44 +30,33 @@ class CC_EXPORT TextureLayerImpl : public LayerImpl {
ResourceProvider* resource_provider) OVERRIDE;
virtual void AppendQuads(QuadSink* quad_sink,
AppendQuadsData* append_quads_data) OVERRIDE;
- virtual void DidDraw(ResourceProvider* resource_provider) OVERRIDE;
virtual Region VisibleContentOpaqueRegion() const OVERRIDE;
- virtual void DidLoseOutputSurface() OVERRIDE;
-
- unsigned texture_id() const { return texture_id_; }
- void set_texture_id(unsigned id) { texture_id_ = id; }
- void set_premultiplied_alpha(bool premultiplied_alpha) {
- premultiplied_alpha_ = premultiplied_alpha;
- }
- void set_blend_background_color(bool blend) {
- blend_background_color_ = blend;
- }
- void set_flipped(bool flipped) { flipped_ = flipped; }
- void set_uv_top_left(gfx::PointF top_left) { uv_top_left_ = top_left; }
- void set_uv_bottom_right(gfx::PointF bottom_right) {
- uv_bottom_right_ = bottom_right;
- }
+ virtual void ReleaseResources() OVERRIDE;
+
+ // These setter methods don't cause any implicit damage, so the texture client
+ // must explicitly invalidate if they intend to cause a visible change in the
+ // layer's output.
+ void SetTextureId(unsigned id);
+ void SetPremultipliedAlpha(bool premultiplied_alpha);
+ void SetBlendBackgroundColor(bool blend);
+ void SetFlipped(bool flipped);
+ void SetUVTopLeft(const gfx::PointF top_left);
+ void SetUVBottomRight(const gfx::PointF bottom_right);
// 1--2
// | |
// 0--3
- void set_vertex_opacity(const float vertex_opacity[4]) {
- vertex_opacity_[0] = vertex_opacity[0];
- vertex_opacity_[1] = vertex_opacity[1];
- vertex_opacity_[2] = vertex_opacity[2];
- vertex_opacity_[3] = vertex_opacity[3];
- }
+ void SetVertexOpacity(const float vertex_opacity[4]);
void SetTextureMailbox(const TextureMailbox& mailbox,
scoped_ptr<SingleReleaseCallback> release_callback);
private:
- TextureLayerImpl(LayerTreeImpl* tree_impl, int id, bool uses_mailbox);
+ TextureLayerImpl(LayerTreeImpl* tree_impl, int id);
virtual const char* LayerTypeAsString() const OVERRIDE;
void FreeTextureMailbox();
- unsigned texture_id_;
ResourceProvider::ResourceId external_texture_resource_;
bool premultiplied_alpha_;
bool blend_background_color_;
@@ -82,7 +69,6 @@ class CC_EXPORT TextureLayerImpl : public LayerImpl {
TextureMailbox texture_mailbox_;
scoped_ptr<SingleReleaseCallback> release_callback_;
- bool uses_mailbox_;
bool own_mailbox_;
bool valid_texture_copy_;
diff --git a/chromium/cc/layers/texture_layer_impl_unittest.cc b/chromium/cc/layers/texture_layer_impl_unittest.cc
new file mode 100644
index 00000000000..cd7cf75c283
--- /dev/null
+++ b/chromium/cc/layers/texture_layer_impl_unittest.cc
@@ -0,0 +1,76 @@
+// 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/layers/texture_layer_impl.h"
+
+#include "cc/output/context_provider.h"
+#include "cc/output/output_surface.h"
+#include "cc/test/layer_test_common.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+namespace {
+
+void IgnoreCallback(uint32 sync_point, bool lost) {}
+
+TEST(TextureLayerImplTest, Occlusion) {
+ gfx::Size layer_size(1000, 1000);
+ gfx::Size viewport_size(1000, 1000);
+
+ LayerTestCommon::LayerImplTest impl;
+
+ gpu::Mailbox mailbox;
+ impl.output_surface()->context_provider()->ContextGL()->GenMailboxCHROMIUM(
+ mailbox.name);
+ TextureMailbox texture_mailbox(mailbox, GL_TEXTURE_2D, 0);
+
+ TextureLayerImpl* texture_layer_impl =
+ impl.AddChildToRoot<TextureLayerImpl>();
+ texture_layer_impl->SetBounds(layer_size);
+ texture_layer_impl->SetContentBounds(layer_size);
+ texture_layer_impl->SetDrawsContent(true);
+ texture_layer_impl->SetTextureMailbox(
+ texture_mailbox,
+ SingleReleaseCallback::Create(base::Bind(&IgnoreCallback)));
+
+ impl.CalcDrawProps(viewport_size);
+
+ {
+ SCOPED_TRACE("No occlusion");
+ gfx::Rect occluded;
+ impl.AppendQuadsWithOcclusion(texture_layer_impl, occluded);
+
+ LayerTestCommon::VerifyQuadsExactlyCoverRect(impl.quad_list(),
+ gfx::Rect(layer_size));
+ EXPECT_EQ(1u, impl.quad_list().size());
+ }
+
+ {
+ SCOPED_TRACE("Full occlusion");
+ gfx::Rect occluded(texture_layer_impl->visible_content_rect());
+ impl.AppendQuadsWithOcclusion(texture_layer_impl, occluded);
+
+ LayerTestCommon::VerifyQuadsExactlyCoverRect(impl.quad_list(), gfx::Rect());
+ EXPECT_EQ(impl.quad_list().size(), 0u);
+ }
+
+ {
+ SCOPED_TRACE("Partial occlusion");
+ gfx::Rect occluded(200, 0, 800, 1000);
+ impl.AppendQuadsWithOcclusion(texture_layer_impl, occluded);
+
+ size_t partially_occluded_count = 0;
+ LayerTestCommon::VerifyQuadsCoverRectWithOcclusion(
+ impl.quad_list(),
+ gfx::Rect(layer_size),
+ occluded,
+ &partially_occluded_count);
+ // The layer outputs one quad, which is partially occluded.
+ EXPECT_EQ(1u, impl.quad_list().size());
+ EXPECT_EQ(1u, partially_occluded_count);
+ }
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/layers/texture_layer_unittest.cc b/chromium/cc/layers/texture_layer_unittest.cc
index 3ae0c2944cd..0a529686466 100644
--- a/chromium/cc/layers/texture_layer_unittest.cc
+++ b/chromium/cc/layers/texture_layer_unittest.cc
@@ -37,10 +37,17 @@ using ::testing::Mock;
using ::testing::_;
using ::testing::AtLeast;
using ::testing::AnyNumber;
+using ::testing::InvokeWithoutArgs;
namespace cc {
namespace {
+gpu::Mailbox MailboxFromChar(char value) {
+ gpu::Mailbox mailbox;
+ memset(mailbox.name, value, sizeof(mailbox.name));
+ return mailbox;
+}
+
class MockLayerTreeHost : public LayerTreeHost {
public:
explicit MockLayerTreeHost(FakeLayerTreeHostClient* client)
@@ -48,28 +55,111 @@ class MockLayerTreeHost : public LayerTreeHost {
InitializeSingleThreaded(client);
}
- MOCK_METHOD0(AcquireLayerTextures, void());
MOCK_METHOD0(SetNeedsCommit, void());
MOCK_METHOD0(SetNeedsUpdateLayers, void());
MOCK_METHOD0(StartRateLimiter, void());
MOCK_METHOD0(StopRateLimiter, void());
};
+class FakeTextureLayerClient : public TextureLayerClient {
+ public:
+ FakeTextureLayerClient() : mailbox_changed_(true) {}
+
+ virtual bool PrepareTextureMailbox(
+ TextureMailbox* mailbox,
+ scoped_ptr<SingleReleaseCallback>* release_callback,
+ bool use_shared_memory) OVERRIDE {
+ if (!mailbox_changed_)
+ return false;
+
+ *mailbox = mailbox_;
+ *release_callback = release_callback_.Pass();
+ mailbox_changed_ = false;
+ return true;
+ }
+
+ void set_mailbox(const TextureMailbox& mailbox,
+ scoped_ptr<SingleReleaseCallback> release_callback) {
+ mailbox_ = mailbox;
+ release_callback_ = release_callback.Pass();
+ mailbox_changed_ = true;
+ }
+
+ private:
+ TextureMailbox mailbox_;
+ scoped_ptr<SingleReleaseCallback> release_callback_;
+ bool mailbox_changed_;
+ DISALLOW_COPY_AND_ASSIGN(FakeTextureLayerClient);
+};
+
+class MockMailboxCallback {
+ public:
+ MOCK_METHOD3(Release,
+ void(const gpu::Mailbox& mailbox,
+ uint32 sync_point,
+ bool lost_resource));
+ MOCK_METHOD3(Release2,
+ void(base::SharedMemory* shared_memory,
+ uint32 sync_point,
+ bool lost_resource));
+};
+
+struct CommonMailboxObjects {
+ CommonMailboxObjects()
+ : mailbox_name1_(MailboxFromChar('1')),
+ mailbox_name2_(MailboxFromChar('2')),
+ sync_point1_(1),
+ sync_point2_(2),
+ shared_memory_(new base::SharedMemory) {
+ release_mailbox1_ = base::Bind(&MockMailboxCallback::Release,
+ base::Unretained(&mock_callback_),
+ mailbox_name1_);
+ release_mailbox2_ = base::Bind(&MockMailboxCallback::Release,
+ base::Unretained(&mock_callback_),
+ mailbox_name2_);
+ const uint32 arbitrary_target1 = GL_TEXTURE_2D;
+ const uint32 arbitrary_target2 = GL_TEXTURE_EXTERNAL_OES;
+ mailbox1_ = TextureMailbox(mailbox_name1_, arbitrary_target1, sync_point1_);
+ mailbox2_ = TextureMailbox(mailbox_name2_, arbitrary_target2, sync_point2_);
+ gfx::Size size(128, 128);
+ EXPECT_TRUE(shared_memory_->CreateAndMapAnonymous(4 * size.GetArea()));
+ release_mailbox3_ = base::Bind(&MockMailboxCallback::Release2,
+ base::Unretained(&mock_callback_),
+ shared_memory_.get());
+ mailbox3_ = TextureMailbox(shared_memory_.get(), size);
+ }
+
+ gpu::Mailbox mailbox_name1_;
+ gpu::Mailbox mailbox_name2_;
+ MockMailboxCallback mock_callback_;
+ ReleaseCallback release_mailbox1_;
+ ReleaseCallback release_mailbox2_;
+ ReleaseCallback release_mailbox3_;
+ TextureMailbox mailbox1_;
+ TextureMailbox mailbox2_;
+ TextureMailbox mailbox3_;
+ uint32 sync_point1_;
+ uint32 sync_point2_;
+ scoped_ptr<base::SharedMemory> shared_memory_;
+};
+
class TextureLayerTest : public testing::Test {
public:
TextureLayerTest()
: fake_client_(
- FakeLayerTreeHostClient(FakeLayerTreeHostClient::DIRECT_3D)),
- host_impl_(&proxy_) {}
+ FakeLayerTreeHostClient(FakeLayerTreeHostClient::DIRECT_3D)),
+ host_impl_(&proxy_, &shared_bitmap_manager_) {}
protected:
virtual void SetUp() {
layer_tree_host_.reset(new MockLayerTreeHost(&fake_client_));
+ EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AnyNumber());
+ layer_tree_host_->SetViewportSize(gfx::Size(10, 10));
+ Mock::VerifyAndClearExpectations(layer_tree_host_.get());
}
virtual void TearDown() {
Mock::VerifyAndClearExpectations(layer_tree_host_.get());
- EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(AnyNumber());
EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AnyNumber());
layer_tree_host_->SetRootLayer(NULL);
@@ -79,126 +169,12 @@ class TextureLayerTest : public testing::Test {
scoped_ptr<MockLayerTreeHost> layer_tree_host_;
FakeImplProxy proxy_;
FakeLayerTreeHostClient fake_client_;
+ TestSharedBitmapManager shared_bitmap_manager_;
FakeLayerTreeHostImpl host_impl_;
};
-TEST_F(TextureLayerTest, SyncImplWhenChangingTextureId) {
- scoped_refptr<TextureLayer> test_layer = TextureLayer::Create(NULL);
- ASSERT_TRUE(test_layer.get());
-
- EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(AnyNumber());
- EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AnyNumber());
- layer_tree_host_->SetRootLayer(test_layer);
- Mock::VerifyAndClearExpectations(layer_tree_host_.get());
- EXPECT_EQ(test_layer->layer_tree_host(), layer_tree_host_.get());
-
- EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(0);
- EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
- test_layer->SetTextureId(1);
- Mock::VerifyAndClearExpectations(layer_tree_host_.get());
-
- EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(AtLeast(1));
- EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
- test_layer->SetTextureId(2);
- Mock::VerifyAndClearExpectations(layer_tree_host_.get());
-
- EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(AtLeast(1));
- EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
- test_layer->SetTextureId(0);
- Mock::VerifyAndClearExpectations(layer_tree_host_.get());
-}
-
-TEST_F(TextureLayerTest, SyncImplWhenDrawing) {
- gfx::RectF dirty_rect(0.f, 0.f, 1.f, 1.f);
-
- scoped_refptr<TextureLayer> test_layer = TextureLayer::Create(NULL);
- ASSERT_TRUE(test_layer.get());
- scoped_ptr<TextureLayerImpl> impl_layer;
- impl_layer = TextureLayerImpl::Create(host_impl_.active_tree(), 1, false);
- ASSERT_TRUE(impl_layer);
-
- EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(AnyNumber());
- EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AnyNumber());
- layer_tree_host_->SetRootLayer(test_layer);
- test_layer->SetTextureId(1);
- test_layer->SetIsDrawable(true);
- Mock::VerifyAndClearExpectations(layer_tree_host_.get());
- EXPECT_EQ(test_layer->layer_tree_host(), layer_tree_host_.get());
-
- EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(1);
- EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(0);
- test_layer->WillModifyTexture();
- Mock::VerifyAndClearExpectations(layer_tree_host_.get());
-
- EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(0);
- EXPECT_CALL(*layer_tree_host_, SetNeedsUpdateLayers()).Times(1);
- test_layer->SetNeedsDisplayRect(dirty_rect);
- Mock::VerifyAndClearExpectations(layer_tree_host_.get());
-
- EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(0);
- EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1);
- test_layer->PushPropertiesTo(impl_layer.get()); // fake commit
- test_layer->SetIsDrawable(false);
- Mock::VerifyAndClearExpectations(layer_tree_host_.get());
-
- // Verify that non-drawable layers don't signal the compositor,
- // except for the first draw after last commit, which must acquire
- // the texture.
- EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(1);
- EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(0);
- test_layer->WillModifyTexture();
- test_layer->SetNeedsDisplayRect(dirty_rect);
- test_layer->PushPropertiesTo(impl_layer.get()); // fake commit
- Mock::VerifyAndClearExpectations(layer_tree_host_.get());
-
- // Second draw with layer in non-drawable state: no texture
- // acquisition.
- EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(0);
- EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(0);
- test_layer->WillModifyTexture();
- test_layer->SetNeedsDisplayRect(dirty_rect);
- Mock::VerifyAndClearExpectations(layer_tree_host_.get());
-}
-
-TEST_F(TextureLayerTest, SyncImplWhenRemovingFromTree) {
- scoped_refptr<Layer> root_layer = Layer::Create();
- ASSERT_TRUE(root_layer.get());
- scoped_refptr<Layer> child_layer = Layer::Create();
- ASSERT_TRUE(child_layer.get());
- root_layer->AddChild(child_layer);
- scoped_refptr<TextureLayer> test_layer = TextureLayer::Create(NULL);
- ASSERT_TRUE(test_layer.get());
- test_layer->SetTextureId(0);
- child_layer->AddChild(test_layer);
-
- EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(AnyNumber());
- EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AnyNumber());
- layer_tree_host_->SetRootLayer(root_layer);
- Mock::VerifyAndClearExpectations(layer_tree_host_.get());
-
- EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(0);
- EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
- test_layer->RemoveFromParent();
- Mock::VerifyAndClearExpectations(layer_tree_host_.get());
-
- EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(0);
- EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
- child_layer->AddChild(test_layer);
- Mock::VerifyAndClearExpectations(layer_tree_host_.get());
-
- EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(0);
- EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
- test_layer->SetTextureId(1);
- Mock::VerifyAndClearExpectations(layer_tree_host_.get());
-
- EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(AtLeast(1));
- EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
- test_layer->RemoveFromParent();
- Mock::VerifyAndClearExpectations(layer_tree_host_.get());
-}
-
TEST_F(TextureLayerTest, CheckPropertyChangeCausesCorrectBehavior) {
- scoped_refptr<TextureLayer> test_layer = TextureLayer::Create(NULL);
+ scoped_refptr<TextureLayer> test_layer = TextureLayer::CreateForMailbox(NULL);
EXPECT_SET_NEEDS_COMMIT(1, layer_tree_host_->SetRootLayer(test_layer));
// Test properties that should call SetNeedsCommit. All properties need to
@@ -210,10 +186,6 @@ TEST_F(TextureLayerTest, CheckPropertyChangeCausesCorrectBehavior) {
0.5f, 0.5f, 0.5f, 0.5f));
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetPremultipliedAlpha(false));
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetBlendBackgroundColor(true));
- EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetTextureId(1));
-
- // Calling SetTextureId can call AcquireLayerTextures.
- EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(AnyNumber());
}
TEST_F(TextureLayerTest, VisibleContentOpaqueRegion) {
@@ -221,7 +193,7 @@ TEST_F(TextureLayerTest, VisibleContentOpaqueRegion) {
const gfx::Rect layer_rect(layer_bounds);
const Region layer_region(layer_rect);
- scoped_refptr<TextureLayer> layer = TextureLayer::Create(NULL);
+ scoped_refptr<TextureLayer> layer = TextureLayer::CreateForMailbox(NULL);
layer->SetBounds(layer_bounds);
layer->draw_properties().visible_content_rect = layer_rect;
layer->SetBlendBackgroundColor(true);
@@ -243,27 +215,6 @@ TEST_F(TextureLayerTest, VisibleContentOpaqueRegion) {
layer->VisibleContentOpaqueRegion().ToString());
}
-class FakeTextureLayerClient : public TextureLayerClient {
- public:
- FakeTextureLayerClient() {}
-
- virtual unsigned PrepareTexture() OVERRIDE {
- return 0;
- }
-
- virtual bool PrepareTextureMailbox(
- TextureMailbox* mailbox,
- scoped_ptr<SingleReleaseCallback>* release_callback,
- bool use_shared_memory) OVERRIDE {
- *mailbox = TextureMailbox();
- *release_callback = scoped_ptr<SingleReleaseCallback>();
- return true;
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(FakeTextureLayerClient);
-};
-
TEST_F(TextureLayerTest, RateLimiter) {
FakeTextureLayerClient client;
scoped_refptr<TextureLayer> test_layer = TextureLayer::CreateForMailbox(
@@ -309,65 +260,14 @@ TEST_F(TextureLayerTest, RateLimiter) {
// Stop rate limiter when we're removed from the tree.
EXPECT_CALL(*layer_tree_host_, StopRateLimiter());
+ EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1);
layer_tree_host_->SetRootLayer(NULL);
Mock::VerifyAndClearExpectations(layer_tree_host_.get());
}
-class MockMailboxCallback {
+class TestMailboxHolder : public TextureLayer::TextureMailboxHolder {
public:
- MOCK_METHOD3(Release, void(const std::string& mailbox,
- unsigned sync_point,
- bool lost_resource));
- MOCK_METHOD3(Release2, void(base::SharedMemory* shared_memory,
- unsigned sync_point,
- bool lost_resource));
-};
-
-struct CommonMailboxObjects {
- CommonMailboxObjects()
- : mailbox_name1_(64, '1'),
- mailbox_name2_(64, '2'),
- sync_point1_(1),
- sync_point2_(2),
- shared_memory_(new base::SharedMemory) {
- release_mailbox1_ = base::Bind(&MockMailboxCallback::Release,
- base::Unretained(&mock_callback_),
- mailbox_name1_);
- release_mailbox2_ = base::Bind(&MockMailboxCallback::Release,
- base::Unretained(&mock_callback_),
- mailbox_name2_);
- gpu::Mailbox m1;
- m1.SetName(reinterpret_cast<const int8*>(mailbox_name1_.data()));
- mailbox1_ = TextureMailbox(m1, sync_point1_);
- gpu::Mailbox m2;
- m2.SetName(reinterpret_cast<const int8*>(mailbox_name2_.data()));
- mailbox2_ = TextureMailbox(m2, sync_point2_);
-
- gfx::Size size(128, 128);
- EXPECT_TRUE(shared_memory_->CreateAndMapAnonymous(4 * size.GetArea()));
- release_mailbox3_ = base::Bind(&MockMailboxCallback::Release2,
- base::Unretained(&mock_callback_),
- shared_memory_.get());
- mailbox3_ = TextureMailbox(shared_memory_.get(), size);
- }
-
- std::string mailbox_name1_;
- std::string mailbox_name2_;
- MockMailboxCallback mock_callback_;
- ReleaseCallback release_mailbox1_;
- ReleaseCallback release_mailbox2_;
- ReleaseCallback release_mailbox3_;
- TextureMailbox mailbox1_;
- TextureMailbox mailbox2_;
- TextureMailbox mailbox3_;
- unsigned sync_point1_;
- unsigned sync_point2_;
- scoped_ptr<base::SharedMemory> shared_memory_;
-};
-
-class TestMailboxHolder : public TextureLayer::MailboxHolder {
- public:
- using TextureLayer::MailboxHolder::Create;
+ using TextureLayer::TextureMailboxHolder::Create;
protected:
virtual ~TestMailboxHolder() {}
@@ -391,19 +291,16 @@ TEST_F(TextureLayerWithMailboxTest, ReplaceMailboxOnMainThreadBeforeCommit) {
scoped_refptr<TextureLayer> test_layer = TextureLayer::CreateForMailbox(NULL);
ASSERT_TRUE(test_layer.get());
- EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(0);
EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AnyNumber());
layer_tree_host_->SetRootLayer(test_layer);
Mock::VerifyAndClearExpectations(layer_tree_host_.get());
- EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(0);
EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
test_layer->SetTextureMailbox(
test_data_.mailbox1_,
SingleReleaseCallback::Create(test_data_.release_mailbox1_));
Mock::VerifyAndClearExpectations(layer_tree_host_.get());
- EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(0);
EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
EXPECT_CALL(test_data_.mock_callback_,
Release(test_data_.mailbox_name1_,
@@ -416,7 +313,6 @@ TEST_F(TextureLayerWithMailboxTest, ReplaceMailboxOnMainThreadBeforeCommit) {
Mock::VerifyAndClearExpectations(layer_tree_host_.get());
Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
- EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(0);
EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
EXPECT_CALL(test_data_.mock_callback_,
Release(test_data_.mailbox_name2_,
@@ -428,7 +324,6 @@ TEST_F(TextureLayerWithMailboxTest, ReplaceMailboxOnMainThreadBeforeCommit) {
Mock::VerifyAndClearExpectations(layer_tree_host_.get());
Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
- EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(0);
EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
test_layer->SetTextureMailbox(
test_data_.mailbox3_,
@@ -436,7 +331,6 @@ TEST_F(TextureLayerWithMailboxTest, ReplaceMailboxOnMainThreadBeforeCommit) {
Mock::VerifyAndClearExpectations(layer_tree_host_.get());
Mock::VerifyAndClearExpectations(&test_data_.mock_callback_);
- EXPECT_CALL(*layer_tree_host_, AcquireLayerTextures()).Times(0);
EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
EXPECT_CALL(test_data_.mock_callback_,
Release2(test_data_.shared_memory_.get(),
@@ -454,6 +348,30 @@ TEST_F(TextureLayerWithMailboxTest, ReplaceMailboxOnMainThreadBeforeCommit) {
SingleReleaseCallback::Create(test_data_.release_mailbox1_));
}
+TEST_F(TextureLayerTest, SetTextureMailboxWithoutReleaseCallback) {
+ scoped_refptr<TextureLayer> test_layer = TextureLayer::CreateForMailbox(NULL);
+ ASSERT_TRUE(test_layer.get());
+
+ // These use the same gpu::Mailbox, but different sync points.
+ TextureMailbox mailbox1(MailboxFromChar('a'), GL_TEXTURE_2D, 1);
+ TextureMailbox mailbox2(MailboxFromChar('a'), GL_TEXTURE_2D, 2);
+
+ EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AnyNumber());
+ layer_tree_host_->SetRootLayer(test_layer);
+ Mock::VerifyAndClearExpectations(layer_tree_host_.get());
+
+ // Set the mailbox the first time. It should cause a commit.
+ EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
+ test_layer->SetTextureMailboxWithoutReleaseCallback(mailbox1);
+ Mock::VerifyAndClearExpectations(layer_tree_host_.get());
+
+ // Set the mailbox again with a new sync point, as the backing texture has
+ // been updated. It should cause a new commit.
+ EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(AtLeast(1));
+ test_layer->SetTextureMailboxWithoutReleaseCallback(mailbox2);
+ Mock::VerifyAndClearExpectations(layer_tree_host_.get());
+}
+
class TextureLayerMailboxHolderTest : public TextureLayerTest {
public:
TextureLayerMailboxHolderTest()
@@ -754,7 +672,7 @@ class TextureLayerImplWithMailboxThreadedCallback : public LayerTreeTest {
commit_count_(0) {}
// Make sure callback is received on main and doesn't block the impl thread.
- void ReleaseCallback(unsigned sync_point, bool lost_resource) {
+ void ReleaseCallback(uint32 sync_point, bool lost_resource) {
EXPECT_EQ(true, main_thread_.CalledOnValidThread());
EXPECT_FALSE(lost_resource);
++callback_count_;
@@ -762,12 +680,13 @@ class TextureLayerImplWithMailboxThreadedCallback : public LayerTreeTest {
void SetMailbox(char mailbox_char) {
EXPECT_EQ(true, main_thread_.CalledOnValidThread());
- TextureMailbox mailbox(std::string(64, mailbox_char));
scoped_ptr<SingleReleaseCallback> callback = SingleReleaseCallback::Create(
base::Bind(
&TextureLayerImplWithMailboxThreadedCallback::ReleaseCallback,
base::Unretained(this)));
- layer_->SetTextureMailbox(mailbox, callback.Pass());
+ layer_->SetTextureMailbox(
+ TextureMailbox(MailboxFromChar(mailbox_char), GL_TEXTURE_2D, 0),
+ callback.Pass());
}
virtual void BeginTest() OVERRIDE {
@@ -775,12 +694,10 @@ class TextureLayerImplWithMailboxThreadedCallback : public LayerTreeTest {
gfx::Size bounds(100, 100);
root_ = Layer::Create();
- root_->SetAnchorPoint(gfx::PointF());
root_->SetBounds(bounds);
layer_ = TextureLayer::CreateForMailbox(NULL);
layer_->SetIsDrawable(true);
- layer_->SetAnchorPoint(gfx::PointF());
layer_->SetBounds(bounds);
root_->AddChild(layer_);
@@ -882,162 +799,28 @@ SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(
TextureLayerImplWithMailboxThreadedCallback);
-class TextureLayerNoMailboxIsActivatedDuringCommit : public LayerTreeTest,
- public TextureLayerClient {
- protected:
- TextureLayerNoMailboxIsActivatedDuringCommit()
- : wait_thread_("WAIT"),
- wait_event_(false, false),
- texture_(0u) {
- wait_thread_.Start();
- }
-
- virtual void BeginTest() OVERRIDE {
- activate_count_ = 0;
-
- gfx::Size bounds(100, 100);
- root_ = Layer::Create();
- root_->SetAnchorPoint(gfx::PointF());
- root_->SetBounds(bounds);
-
- layer_ = TextureLayer::Create(this);
- layer_->SetIsDrawable(true);
- layer_->SetAnchorPoint(gfx::PointF());
- layer_->SetBounds(bounds);
-
- root_->AddChild(layer_);
- layer_tree_host()->SetRootLayer(root_);
- layer_tree_host()->SetViewportSize(bounds);
-
- PostSetNeedsCommitToMainThread();
- }
-
- virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback)
- OVERRIDE {
- scoped_refptr<TestContextProvider> provider = TestContextProvider::Create();
- texture_ = provider->UnboundTestContext3d()->createExternalTexture();
- return FakeOutputSurface::Create3d(provider).PassAs<OutputSurface>();
- }
-
- // TextureLayerClient implementation.
- virtual unsigned PrepareTexture() OVERRIDE {
- return texture_;
- }
- virtual bool PrepareTextureMailbox(
- TextureMailbox* mailbox,
- scoped_ptr<SingleReleaseCallback>* release_callback,
- bool use_shared_memory) OVERRIDE {
- return false;
- }
-
- virtual void WillActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
- // Slow down activation so the main thread DidCommit() will run if
- // not blocked.
- wait_thread_.message_loop()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&base::WaitableEvent::Signal,
- base::Unretained(&wait_event_)),
- base::TimeDelta::FromMilliseconds(10));
- wait_event_.Wait();
-
- base::AutoLock lock(activate_lock_);
- ++activate_count_;
- }
-
- virtual void DidActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
- // The main thread is awake now, and will run DidCommit() immediately.
- // Run DidActivate() afterwards by posting it now.
- proxy()->MainThreadTaskRunner()->PostTask(
- FROM_HERE,
- base::Bind(&TextureLayerNoMailboxIsActivatedDuringCommit::DidActivate,
- base::Unretained(this)));
- }
-
- void DidActivate() {
- base::AutoLock lock(activate_lock_);
- switch (activate_count_) {
- case 1:
- // The first texture has been activated. Invalidate the layer so it
- // grabs a new texture id from the client.
- layer_->SetNeedsDisplay();
- // So this commit number should complete after the second activate.
- EXPECT_EQ(1, layer_tree_host()->source_frame_number());
- break;
- case 2:
- // The second mailbox has been activated. Remove the layer from
- // the tree to cause another commit/activation. The commit should
- // finish *after* the layer is removed from the active tree.
- layer_->RemoveFromParent();
- // So this commit number should complete after the third activate.
- EXPECT_EQ(2, layer_tree_host()->source_frame_number());
- break;
- case 3:
- EndTest();
- break;
- }
- }
-
- virtual void DidCommit() OVERRIDE {
- switch (layer_tree_host()->source_frame_number()) {
- case 2: {
- // The activate for the 2nd texture should have happened before now.
- base::AutoLock lock(activate_lock_);
- EXPECT_EQ(2, activate_count_);
- break;
- }
- case 3: {
- // The activate to remove the layer should have happened before now.
- base::AutoLock lock(activate_lock_);
- EXPECT_EQ(3, activate_count_);
- break;
- }
- }
- }
-
-
- virtual void AfterTest() OVERRIDE {}
-
- base::Thread wait_thread_;
- base::WaitableEvent wait_event_;
- base::Lock activate_lock_;
- unsigned texture_;
- int activate_count_;
- scoped_refptr<Layer> root_;
- scoped_refptr<TextureLayer> layer_;
-};
-
-SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(
- TextureLayerNoMailboxIsActivatedDuringCommit);
-
class TextureLayerMailboxIsActivatedDuringCommit : public LayerTreeTest {
protected:
- TextureLayerMailboxIsActivatedDuringCommit()
- : wait_thread_("WAIT"),
- wait_event_(false, false) {
- wait_thread_.Start();
- }
+ TextureLayerMailboxIsActivatedDuringCommit() : activate_count_(0) {}
- static void ReleaseCallback(unsigned sync_point, bool lost_resource) {}
+ static void ReleaseCallback(uint32 sync_point, bool lost_resource) {}
void SetMailbox(char mailbox_char) {
- TextureMailbox mailbox(std::string(64, mailbox_char));
scoped_ptr<SingleReleaseCallback> callback = SingleReleaseCallback::Create(
base::Bind(
&TextureLayerMailboxIsActivatedDuringCommit::ReleaseCallback));
- layer_->SetTextureMailbox(mailbox, callback.Pass());
+ layer_->SetTextureMailbox(
+ TextureMailbox(MailboxFromChar(mailbox_char), GL_TEXTURE_2D, 0),
+ callback.Pass());
}
virtual void BeginTest() OVERRIDE {
- activate_count_ = 0;
-
gfx::Size bounds(100, 100);
root_ = Layer::Create();
- root_->SetAnchorPoint(gfx::PointF());
root_->SetBounds(bounds);
layer_ = TextureLayer::CreateForMailbox(NULL);
layer_->SetIsDrawable(true);
- layer_->SetAnchorPoint(gfx::PointF());
layer_->SetBounds(bounds);
root_->AddChild(layer_);
@@ -1049,45 +832,21 @@ class TextureLayerMailboxIsActivatedDuringCommit : public LayerTreeTest {
}
virtual void WillActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
- // Slow down activation so the main thread DidCommit() will run if
- // not blocked.
- wait_thread_.message_loop()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&base::WaitableEvent::Signal,
- base::Unretained(&wait_event_)),
- base::TimeDelta::FromMilliseconds(10));
- wait_event_.Wait();
-
- base::AutoLock lock(activate_lock_);
++activate_count_;
}
- virtual void DidActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
- // The main thread is awake now, and will run DidCommit() immediately.
- // Run DidActivate() afterwards by posting it now.
- proxy()->MainThreadTaskRunner()->PostTask(
- FROM_HERE,
- base::Bind(&TextureLayerMailboxIsActivatedDuringCommit::DidActivate,
- base::Unretained(this)));
- }
-
- void DidActivate() {
- base::AutoLock lock(activate_lock_);
- switch (activate_count_) {
+ virtual void DidCommit() OVERRIDE {
+ switch (layer_tree_host()->source_frame_number()) {
case 1:
// The first mailbox has been activated. Set a new mailbox, and
// expect the next commit to finish *after* it is activated.
SetMailbox('2');
- // So this commit number should complete after the second activate.
- EXPECT_EQ(1, layer_tree_host()->source_frame_number());
break;
case 2:
// The second mailbox has been activated. Remove the layer from
// the tree to cause another commit/activation. The commit should
// finish *after* the layer is removed from the active tree.
layer_->RemoveFromParent();
- // So this commit number should complete after the third activate.
- EXPECT_EQ(2, layer_tree_host()->source_frame_number());
break;
case 3:
EndTest();
@@ -1095,17 +854,15 @@ class TextureLayerMailboxIsActivatedDuringCommit : public LayerTreeTest {
}
}
- virtual void DidCommit() OVERRIDE {
- switch (layer_tree_host()->source_frame_number()) {
+ virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
+ switch (host_impl->active_tree()->source_frame_number()) {
case 2: {
// The activate for the 2nd mailbox should have happened before now.
- base::AutoLock lock(activate_lock_);
EXPECT_EQ(2, activate_count_);
break;
}
case 3: {
// The activate to remove the layer should have happened before now.
- base::AutoLock lock(activate_lock_);
EXPECT_EQ(3, activate_count_);
break;
}
@@ -1115,9 +872,6 @@ class TextureLayerMailboxIsActivatedDuringCommit : public LayerTreeTest {
virtual void AfterTest() OVERRIDE {}
- base::Thread wait_thread_;
- base::WaitableEvent wait_event_;
- base::Lock activate_lock_;
int activate_count_;
scoped_refptr<Layer> root_;
scoped_refptr<TextureLayer> layer_;
@@ -1135,7 +889,8 @@ class TextureLayerImplWithMailboxTest : public TextureLayerTest {
virtual void SetUp() {
TextureLayerTest::SetUp();
layer_tree_host_.reset(new MockLayerTreeHost(&fake_client_));
- EXPECT_TRUE(host_impl_.InitializeRenderer(CreateFakeOutputSurface()));
+ EXPECT_TRUE(host_impl_.InitializeRenderer(
+ FakeOutputSurface::Create3d().PassAs<OutputSurface>()));
}
bool WillDraw(TextureLayerImpl* layer, DrawMode mode) {
@@ -1164,8 +919,7 @@ TEST_F(TextureLayerImplWithMailboxTest, TestWillDraw) {
// Hardware mode.
{
scoped_ptr<TextureLayerImpl> impl_layer =
- TextureLayerImpl::Create(host_impl_.active_tree(), 1, true);
- impl_layer->SetDrawsContent(true);
+ TextureLayerImpl::Create(host_impl_.active_tree(), 1);
impl_layer->SetTextureMailbox(
test_data_.mailbox1_,
SingleReleaseCallback::Create(test_data_.release_mailbox1_));
@@ -1174,8 +928,7 @@ TEST_F(TextureLayerImplWithMailboxTest, TestWillDraw) {
{
scoped_ptr<TextureLayerImpl> impl_layer =
- TextureLayerImpl::Create(host_impl_.active_tree(), 1, true);
- impl_layer->SetDrawsContent(true);
+ TextureLayerImpl::Create(host_impl_.active_tree(), 1);
impl_layer->SetTextureMailbox(TextureMailbox(),
scoped_ptr<SingleReleaseCallback>());
EXPECT_FALSE(WillDraw(impl_layer.get(), DRAW_MODE_HARDWARE));
@@ -1184,39 +937,17 @@ TEST_F(TextureLayerImplWithMailboxTest, TestWillDraw) {
{
// Software resource.
scoped_ptr<TextureLayerImpl> impl_layer =
- TextureLayerImpl::Create(host_impl_.active_tree(), 1, true);
- impl_layer->SetDrawsContent(true);
+ TextureLayerImpl::Create(host_impl_.active_tree(), 1);
impl_layer->SetTextureMailbox(
test_data_.mailbox3_,
SingleReleaseCallback::Create(test_data_.release_mailbox3_));
EXPECT_TRUE(WillDraw(impl_layer.get(), DRAW_MODE_HARDWARE));
}
- {
- scoped_ptr<TextureLayerImpl> impl_layer =
- TextureLayerImpl::Create(host_impl_.active_tree(), 1, false);
- impl_layer->SetDrawsContent(true);
- ContextProvider* context_provider =
- host_impl_.output_surface()->context_provider();
- unsigned texture =
- context_provider->Context3d()->createTexture();
- impl_layer->set_texture_id(texture);
- EXPECT_TRUE(WillDraw(impl_layer.get(), DRAW_MODE_HARDWARE));
- }
-
- {
- scoped_ptr<TextureLayerImpl> impl_layer =
- TextureLayerImpl::Create(host_impl_.active_tree(), 1, false);
- impl_layer->SetDrawsContent(true);
- impl_layer->set_texture_id(0);
- EXPECT_FALSE(WillDraw(impl_layer.get(), DRAW_MODE_HARDWARE));
- }
-
// Software mode.
{
scoped_ptr<TextureLayerImpl> impl_layer =
- TextureLayerImpl::Create(host_impl_.active_tree(), 1, true);
- impl_layer->SetDrawsContent(true);
+ TextureLayerImpl::Create(host_impl_.active_tree(), 1);
impl_layer->SetTextureMailbox(
test_data_.mailbox1_,
SingleReleaseCallback::Create(test_data_.release_mailbox1_));
@@ -1225,8 +956,7 @@ TEST_F(TextureLayerImplWithMailboxTest, TestWillDraw) {
{
scoped_ptr<TextureLayerImpl> impl_layer =
- TextureLayerImpl::Create(host_impl_.active_tree(), 1, true);
- impl_layer->SetDrawsContent(true);
+ TextureLayerImpl::Create(host_impl_.active_tree(), 1);
impl_layer->SetTextureMailbox(TextureMailbox(),
scoped_ptr<SingleReleaseCallback>());
EXPECT_FALSE(WillDraw(impl_layer.get(), DRAW_MODE_SOFTWARE));
@@ -1235,62 +965,28 @@ TEST_F(TextureLayerImplWithMailboxTest, TestWillDraw) {
{
// Software resource.
scoped_ptr<TextureLayerImpl> impl_layer =
- TextureLayerImpl::Create(host_impl_.active_tree(), 1, true);
- impl_layer->SetDrawsContent(true);
+ TextureLayerImpl::Create(host_impl_.active_tree(), 1);
impl_layer->SetTextureMailbox(
test_data_.mailbox3_,
SingleReleaseCallback::Create(test_data_.release_mailbox3_));
EXPECT_TRUE(WillDraw(impl_layer.get(), DRAW_MODE_SOFTWARE));
}
- {
- scoped_ptr<TextureLayerImpl> impl_layer =
- TextureLayerImpl::Create(host_impl_.active_tree(), 1, false);
- impl_layer->SetDrawsContent(true);
- ContextProvider* context_provider =
- host_impl_.output_surface()->context_provider();
- unsigned texture =
- context_provider->Context3d()->createTexture();
- impl_layer->set_texture_id(texture);
- EXPECT_FALSE(WillDraw(impl_layer.get(), DRAW_MODE_SOFTWARE));
- }
-
- {
- scoped_ptr<TextureLayerImpl> impl_layer =
- TextureLayerImpl::Create(host_impl_.active_tree(), 1, false);
- impl_layer->SetDrawsContent(true);
- impl_layer->set_texture_id(0);
- EXPECT_FALSE(WillDraw(impl_layer.get(), DRAW_MODE_SOFTWARE));
- }
-
// Resourceless software mode.
{
scoped_ptr<TextureLayerImpl> impl_layer =
- TextureLayerImpl::Create(host_impl_.active_tree(), 1, true);
- impl_layer->SetDrawsContent(true);
+ TextureLayerImpl::Create(host_impl_.active_tree(), 1);
impl_layer->SetTextureMailbox(
test_data_.mailbox1_,
SingleReleaseCallback::Create(test_data_.release_mailbox1_));
EXPECT_FALSE(WillDraw(impl_layer.get(), DRAW_MODE_RESOURCELESS_SOFTWARE));
}
-
- {
- scoped_ptr<TextureLayerImpl> impl_layer =
- TextureLayerImpl::Create(host_impl_.active_tree(), 1, false);
- impl_layer->SetDrawsContent(true);
- ContextProvider* context_provider =
- host_impl_.output_surface()->context_provider();
- unsigned texture =
- context_provider->Context3d()->createTexture();
- impl_layer->set_texture_id(texture);
- EXPECT_FALSE(WillDraw(impl_layer.get(), DRAW_MODE_RESOURCELESS_SOFTWARE));
- }
}
TEST_F(TextureLayerImplWithMailboxTest, TestImplLayerCallbacks) {
host_impl_.CreatePendingTree();
scoped_ptr<TextureLayerImpl> pending_layer;
- pending_layer = TextureLayerImpl::Create(host_impl_.pending_tree(), 1, true);
+ pending_layer = TextureLayerImpl::Create(host_impl_.pending_tree(), 1);
ASSERT_TRUE(pending_layer);
scoped_ptr<LayerImpl> active_layer(
@@ -1353,7 +1049,7 @@ TEST_F(TextureLayerImplWithMailboxTest, TestImplLayerCallbacks) {
TEST_F(TextureLayerImplWithMailboxTest,
TestDestructorCallbackOnCreatedResource) {
scoped_ptr<TextureLayerImpl> impl_layer;
- impl_layer = TextureLayerImpl::Create(host_impl_.active_tree(), 1, true);
+ impl_layer = TextureLayerImpl::Create(host_impl_.active_tree(), 1);
ASSERT_TRUE(impl_layer);
EXPECT_CALL(test_data_.mock_callback_,
@@ -1362,7 +1058,6 @@ TEST_F(TextureLayerImplWithMailboxTest,
impl_layer->SetTextureMailbox(
test_data_.mailbox1_,
SingleReleaseCallback::Create(test_data_.release_mailbox1_));
- impl_layer->SetDrawsContent(true);
impl_layer->DidBecomeActive();
EXPECT_TRUE(impl_layer->WillDraw(
DRAW_MODE_HARDWARE, host_impl_.active_tree()->resource_provider()));
@@ -1396,287 +1091,6 @@ TEST_F(TextureLayerImplWithMailboxTest, TestCallbackOnInUseResource) {
provider->ReceiveReturnsFromParent(returned);
}
-// Check that ClearClient correctly clears the state so that the impl side
-// doesn't try to use a texture that could have been destroyed.
-class TextureLayerClientTest
- : public LayerTreeTest,
- public TextureLayerClient {
- public:
- TextureLayerClientTest()
- : texture_(0),
- commit_count_(0),
- expected_used_textures_on_draw_(0),
- expected_used_textures_on_commit_(0) {}
-
- virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback)
- OVERRIDE {
- scoped_refptr<TestContextProvider> provider = TestContextProvider::Create();
- texture_ = provider->UnboundTestContext3d()->createExternalTexture();
- return FakeOutputSurface::Create3d(provider).PassAs<OutputSurface>();
- }
-
- virtual unsigned PrepareTexture() OVERRIDE { return texture_; }
-
- virtual bool PrepareTextureMailbox(
- TextureMailbox* mailbox,
- scoped_ptr<SingleReleaseCallback>* release_callback,
- bool use_shared_memory) OVERRIDE {
- return false;
- }
-
- virtual void SetupTree() OVERRIDE {
- scoped_refptr<Layer> root = Layer::Create();
- root->SetBounds(gfx::Size(10, 10));
- root->SetAnchorPoint(gfx::PointF());
- root->SetIsDrawable(true);
-
- texture_layer_ = TextureLayer::Create(this);
- texture_layer_->SetBounds(gfx::Size(10, 10));
- texture_layer_->SetAnchorPoint(gfx::PointF());
- texture_layer_->SetIsDrawable(true);
- root->AddChild(texture_layer_);
-
- layer_tree_host()->SetRootLayer(root);
- LayerTreeTest::SetupTree();
- {
- base::AutoLock lock(lock_);
- expected_used_textures_on_commit_ = 1;
- }
- }
-
- virtual void BeginTest() OVERRIDE {
- PostSetNeedsCommitToMainThread();
- }
-
- virtual void DidCommitAndDrawFrame() OVERRIDE {
- ++commit_count_;
- switch (commit_count_) {
- case 1:
- texture_layer_->ClearClient();
- texture_layer_->SetNeedsDisplay();
- {
- base::AutoLock lock(lock_);
- expected_used_textures_on_commit_ = 0;
- }
- break;
- case 2:
- EndTest();
- break;
- default:
- NOTREACHED();
- break;
- }
- }
-
- virtual void BeginCommitOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
- base::AutoLock lock(lock_);
- expected_used_textures_on_draw_ = expected_used_textures_on_commit_;
- }
-
- virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
- LayerTreeHostImpl::FrameData* frame_data,
- bool result) OVERRIDE {
- ContextForImplThread(host_impl)->ResetUsedTextures();
- return true;
- }
-
- virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl,
- bool result) OVERRIDE {
- ASSERT_TRUE(result);
- EXPECT_EQ(expected_used_textures_on_draw_,
- ContextForImplThread(host_impl)->NumUsedTextures());
- }
-
- virtual void AfterTest() OVERRIDE {}
-
- private:
- TestWebGraphicsContext3D* ContextForImplThread(LayerTreeHostImpl* host_impl) {
- return static_cast<TestWebGraphicsContext3D*>(
- host_impl->output_surface()->context_provider()->Context3d());
- }
-
- scoped_refptr<TextureLayer> texture_layer_;
- unsigned texture_;
- int commit_count_;
-
- // Used only on thread.
- unsigned expected_used_textures_on_draw_;
-
- // Used on either thread, protected by lock_.
- base::Lock lock_;
- unsigned expected_used_textures_on_commit_;
-};
-
-// The TextureLayerClient does not use mailboxes, so can't use a delegating
-// renderer.
-SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(TextureLayerClientTest);
-
-
-// Checks that changing a texture in the client for a TextureLayer that's
-// invisible correctly works without drawing a deleted texture. See
-// crbug.com/266628
-class TextureLayerChangeInvisibleTest
- : public LayerTreeTest,
- public TextureLayerClient {
- public:
- TextureLayerChangeInvisibleTest()
- : texture_(0u),
- prepare_called_(0),
- commit_count_(0),
- expected_texture_on_draw_(0) {}
-
- virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback)
- OVERRIDE {
- scoped_refptr<TestContextProvider> provider = TestContextProvider::Create();
- texture_ = provider->UnboundTestContext3d()->createExternalTexture();
- return FakeOutputSurface::Create3d(provider).PassAs<OutputSurface>();
- }
-
- // TextureLayerClient implementation.
- virtual unsigned PrepareTexture() OVERRIDE {
- ++prepare_called_;
- return texture_;
- }
- virtual bool PrepareTextureMailbox(
- TextureMailbox* mailbox,
- scoped_ptr<SingleReleaseCallback>* release_callback,
- bool use_shared_memory) OVERRIDE {
- return false;
- }
-
- virtual void SetupTree() OVERRIDE {
- scoped_refptr<Layer> root = Layer::Create();
- root->SetBounds(gfx::Size(10, 10));
- root->SetAnchorPoint(gfx::PointF());
- root->SetIsDrawable(true);
-
- solid_layer_ = SolidColorLayer::Create();
- solid_layer_->SetBounds(gfx::Size(10, 10));
- solid_layer_->SetIsDrawable(true);
- solid_layer_->SetBackgroundColor(SK_ColorWHITE);
- root->AddChild(solid_layer_);
-
- parent_layer_ = Layer::Create();
- parent_layer_->SetBounds(gfx::Size(10, 10));
- parent_layer_->SetIsDrawable(true);
- root->AddChild(parent_layer_);
-
- texture_layer_ = TextureLayer::Create(this);
- texture_layer_->SetBounds(gfx::Size(10, 10));
- texture_layer_->SetAnchorPoint(gfx::PointF());
- texture_layer_->SetIsDrawable(true);
- parent_layer_->AddChild(texture_layer_);
-
- layer_tree_host()->SetRootLayer(root);
- LayerTreeTest::SetupTree();
- }
-
- virtual void BeginTest() OVERRIDE {
- PostSetNeedsCommitToMainThread();
- }
-
- virtual void DidCommitAndDrawFrame() OVERRIDE {
- ++commit_count_;
- switch (commit_count_) {
- case 1:
- // We should have updated the layer, committing the texture.
- EXPECT_EQ(1, prepare_called_);
- // Make layer invisible.
- parent_layer_->SetOpacity(0.f);
- break;
- case 2: {
- // Layer shouldn't have been updated.
- EXPECT_EQ(1, prepare_called_);
- texture_layer_->SetNeedsDisplay();
- // Force a change to make sure we draw a frame.
- solid_layer_->SetBackgroundColor(SK_ColorGRAY);
- break;
- }
- case 3:
- EXPECT_EQ(1, prepare_called_);
- // Make layer visible again.
- parent_layer_->SetOpacity(1.f);
- break;
- case 4: {
- // Layer should have been updated.
- EXPECT_EQ(2, prepare_called_);
- texture_layer_->ClearClient();
- texture_ = 0;
- break;
- }
- case 5:
- EndTest();
- break;
- default:
- NOTREACHED();
- break;
- }
- }
-
- virtual void BeginCommitOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
- ASSERT_TRUE(proxy()->IsMainThreadBlocked());
- // This is the only texture that can be drawn this frame.
- expected_texture_on_draw_ = texture_;
- }
-
- virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
- LayerTreeHostImpl::FrameData* frame_data,
- bool result) OVERRIDE {
- ContextForImplThread(host_impl)->ResetUsedTextures();
- return true;
- }
-
- virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl,
- bool result) OVERRIDE {
- ASSERT_TRUE(result);
- TestWebGraphicsContext3D* context = ContextForImplThread(host_impl);
- int used_textures = context->NumUsedTextures();
- switch (host_impl->active_tree()->source_frame_number()) {
- case 0:
- EXPECT_EQ(1, used_textures);
- EXPECT_TRUE(context->UsedTexture(expected_texture_on_draw_));
- break;
- case 1:
- case 2:
- EXPECT_EQ(0, used_textures);
- break;
- case 3:
- EXPECT_EQ(1, used_textures);
- EXPECT_TRUE(context->UsedTexture(expected_texture_on_draw_));
- break;
- default:
- break;
- }
- }
-
- virtual void AfterTest() OVERRIDE {}
-
- private:
- TestWebGraphicsContext3D* ContextForImplThread(LayerTreeHostImpl* host_impl) {
- return static_cast<TestWebGraphicsContext3D*>(
- host_impl->output_surface()->context_provider()->Context3d());
- }
-
- scoped_refptr<SolidColorLayer> solid_layer_;
- scoped_refptr<Layer> parent_layer_;
- scoped_refptr<TextureLayer> texture_layer_;
-
- // Used on the main thread, and on the impl thread while the main thread is
- // blocked.
- unsigned texture_;
-
- // Used on the main thread.
- int prepare_called_;
- int commit_count_;
-
- // Used on the compositor thread.
- unsigned expected_texture_on_draw_;
-};
-
-// The TextureLayerChangeInvisibleTest does not use mailboxes, so can't use a
-// delegating renderer.
-SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(TextureLayerChangeInvisibleTest);
-
// Checks that TextureLayer::Update does not cause an extra commit when setting
// the texture mailbox.
class TextureLayerNoExtraCommitForMailboxTest
@@ -1684,53 +1098,39 @@ class TextureLayerNoExtraCommitForMailboxTest
public TextureLayerClient {
public:
// TextureLayerClient implementation.
- virtual unsigned PrepareTexture() OVERRIDE {
- NOTREACHED();
- return 0;
- }
virtual bool PrepareTextureMailbox(
- TextureMailbox* mailbox,
+ TextureMailbox* texture_mailbox,
scoped_ptr<SingleReleaseCallback>* release_callback,
bool use_shared_memory) OVERRIDE {
if (layer_tree_host()->source_frame_number() == 1) {
- *mailbox = TextureMailbox();
+ // Once this has been committed, the mailbox will be released.
+ *texture_mailbox = TextureMailbox();
return true;
}
- *mailbox = TextureMailbox(std::string(64, '1'));
+ *texture_mailbox = TextureMailbox(MailboxFromChar('1'), GL_TEXTURE_2D, 0);
*release_callback = SingleReleaseCallback::Create(
base::Bind(&TextureLayerNoExtraCommitForMailboxTest::MailboxReleased,
base::Unretained(this)));
return true;
}
- void MailboxReleased(unsigned sync_point, bool lost_resource) {
- EXPECT_EQ(2, layer_tree_host()->source_frame_number());
+ void MailboxReleased(uint32 sync_point, bool lost_resource) {
+ // Source frame number during callback is the same as the source frame
+ // on which it was released.
+ EXPECT_EQ(1, layer_tree_host()->source_frame_number());
EndTest();
}
virtual void SetupTree() OVERRIDE {
scoped_refptr<Layer> root = Layer::Create();
root->SetBounds(gfx::Size(10, 10));
- root->SetAnchorPoint(gfx::PointF());
root->SetIsDrawable(true);
- solid_layer_ = SolidColorLayer::Create();
- solid_layer_->SetBounds(gfx::Size(10, 10));
- solid_layer_->SetIsDrawable(true);
- solid_layer_->SetBackgroundColor(SK_ColorWHITE);
- root->AddChild(solid_layer_);
-
- parent_layer_ = Layer::Create();
- parent_layer_->SetBounds(gfx::Size(10, 10));
- parent_layer_->SetIsDrawable(true);
- root->AddChild(parent_layer_);
-
texture_layer_ = TextureLayer::CreateForMailbox(this);
texture_layer_->SetBounds(gfx::Size(10, 10));
- texture_layer_->SetAnchorPoint(gfx::PointF());
texture_layer_->SetIsDrawable(true);
- parent_layer_->AddChild(texture_layer_);
+ root->AddChild(texture_layer_);
layer_tree_host()->SetRootLayer(root);
LayerTreeTest::SetupTree();
@@ -1772,14 +1172,11 @@ class TextureLayerNoExtraCommitForMailboxTest
for (size_t i = 0; i < resources_to_return.size(); ++i)
output_surface()->ReturnResource(resources_to_return[i].id, &ack);
host_impl->ReclaimResources(&ack);
- host_impl->OnSwapBuffersComplete();
}
virtual void AfterTest() OVERRIDE {}
private:
- scoped_refptr<SolidColorLayer> solid_layer_;
- scoped_refptr<Layer> parent_layer_;
scoped_refptr<TextureLayer> texture_layer_;
};
@@ -1801,11 +1198,6 @@ class TextureLayerChangeInvisibleMailboxTest
}
// TextureLayerClient implementation.
- virtual unsigned PrepareTexture() OVERRIDE {
- NOTREACHED();
- return 0;
- }
-
virtual bool PrepareTextureMailbox(
TextureMailbox* mailbox,
scoped_ptr<SingleReleaseCallback>* release_callback,
@@ -1821,17 +1213,16 @@ class TextureLayerChangeInvisibleMailboxTest
}
TextureMailbox MakeMailbox(char name) {
- return TextureMailbox(std::string(64, name));
+ return TextureMailbox(MailboxFromChar(name), GL_TEXTURE_2D, 0);
}
- void MailboxReleased(unsigned sync_point, bool lost_resource) {
+ void MailboxReleased(uint32 sync_point, bool lost_resource) {
++mailbox_returned_;
}
virtual void SetupTree() OVERRIDE {
scoped_refptr<Layer> root = Layer::Create();
root->SetBounds(gfx::Size(10, 10));
- root->SetAnchorPoint(gfx::PointF());
root->SetIsDrawable(true);
solid_layer_ = SolidColorLayer::Create();
@@ -1847,7 +1238,6 @@ class TextureLayerChangeInvisibleMailboxTest
texture_layer_ = TextureLayer::CreateForMailbox(this);
texture_layer_->SetBounds(gfx::Size(10, 10));
- texture_layer_->SetAnchorPoint(gfx::PointF());
texture_layer_->SetIsDrawable(true);
parent_layer_->AddChild(texture_layer_);
@@ -1919,7 +1309,6 @@ class TextureLayerChangeInvisibleMailboxTest
for (size_t i = 0; i < resources_to_return.size(); ++i)
output_surface()->ReturnResource(resources_to_return[i].id, &ack);
host_impl->ReclaimResources(&ack);
- host_impl->OnSwapBuffersComplete();
}
virtual void AfterTest() OVERRIDE {}
@@ -1939,83 +1328,84 @@ class TextureLayerChangeInvisibleMailboxTest
SINGLE_AND_MULTI_THREAD_TEST_F(TextureLayerChangeInvisibleMailboxTest);
-// Test recovering from a lost context.
-class TextureLayerLostContextTest
+// Test that TextureLayerImpl::ReleaseResources can be called which releases
+// the mailbox back to TextureLayerClient.
+class TextureLayerReleaseResourcesBase
: public LayerTreeTest,
public TextureLayerClient {
public:
- TextureLayerLostContextTest()
- : context_lost_(false),
- draw_count_(0) {}
-
- virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback)
- OVERRIDE {
- return CreateFakeOutputSurface();
- }
-
- virtual unsigned PrepareTexture() OVERRIDE {
- if (draw_count_ == 0)
- context_lost_ = true;
- if (context_lost_)
- return 0u;
- return 1u;
- }
-
+ // TextureLayerClient implementation.
virtual bool PrepareTextureMailbox(
TextureMailbox* mailbox,
scoped_ptr<SingleReleaseCallback>* release_callback,
bool use_shared_memory) OVERRIDE {
- return false;
+ *mailbox = TextureMailbox(MailboxFromChar('1'), GL_TEXTURE_2D, 0);
+ *release_callback = SingleReleaseCallback::Create(
+ base::Bind(&TextureLayerReleaseResourcesBase::MailboxReleased,
+ base::Unretained(this)));
+ return true;
+ }
+
+ void MailboxReleased(unsigned sync_point, bool lost_resource) {
+ mailbox_released_ = true;
}
virtual void SetupTree() OVERRIDE {
- scoped_refptr<Layer> root = Layer::Create();
- root->SetBounds(gfx::Size(10, 10));
- root->SetIsDrawable(true);
+ LayerTreeTest::SetupTree();
- texture_layer_ = TextureLayer::Create(this);
- texture_layer_->SetBounds(gfx::Size(10, 10));
- texture_layer_->SetIsDrawable(true);
- root->AddChild(texture_layer_);
+ scoped_refptr<TextureLayer> texture_layer =
+ TextureLayer::CreateForMailbox(this);
+ texture_layer->SetBounds(gfx::Size(10, 10));
+ texture_layer->SetIsDrawable(true);
- layer_tree_host()->SetRootLayer(root);
- LayerTreeTest::SetupTree();
+ layer_tree_host()->root_layer()->AddChild(texture_layer);
}
virtual void BeginTest() OVERRIDE {
+ mailbox_released_ = false;
PostSetNeedsCommitToMainThread();
}
- virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
- LayerTreeHostImpl::FrameData* frame_data,
- bool result) OVERRIDE {
- LayerImpl* root = host_impl->RootLayer();
- TextureLayerImpl* texture_layer =
- static_cast<TextureLayerImpl*>(root->children()[0]);
- if (++draw_count_ == 1)
- EXPECT_EQ(0u, texture_layer->texture_id());
- else
- EXPECT_EQ(1u, texture_layer->texture_id());
- return true;
- }
-
virtual void DidCommitAndDrawFrame() OVERRIDE {
EndTest();
}
- virtual void AfterTest() OVERRIDE {}
+ virtual void AfterTest() OVERRIDE {
+ EXPECT_TRUE(mailbox_released_);
+ }
private:
- scoped_refptr<TextureLayer> texture_layer_;
- bool context_lost_;
- int draw_count_;
+ bool mailbox_released_;
+};
+
+class TextureLayerReleaseResourcesAfterCommit
+ : public TextureLayerReleaseResourcesBase {
+ public:
+ virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
+ LayerTreeImpl* tree = NULL;
+ if (host_impl->settings().impl_side_painting)
+ tree = host_impl->pending_tree();
+ else
+ tree = host_impl->active_tree();
+ tree->root_layer()->children()[0]->ReleaseResources();
+ }
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(TextureLayerReleaseResourcesAfterCommit);
+
+class TextureLayerReleaseResourcesAfterActivate
+ : public TextureLayerReleaseResourcesBase {
+ public:
+ virtual void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
+ host_impl->active_tree()->root_layer()->children()[0]->ReleaseResources();
+ }
};
-SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(TextureLayerLostContextTest);
+SINGLE_AND_MULTI_THREAD_TEST_F(TextureLayerReleaseResourcesAfterActivate);
class TextureLayerWithMailboxMainThreadDeleted : public LayerTreeTest {
public:
- void ReleaseCallback(unsigned sync_point, bool lost_resource) {
+ void ReleaseCallback(uint32 sync_point, bool lost_resource) {
EXPECT_EQ(true, main_thread_.CalledOnValidThread());
EXPECT_FALSE(lost_resource);
++callback_count_;
@@ -2024,23 +1414,22 @@ class TextureLayerWithMailboxMainThreadDeleted : public LayerTreeTest {
void SetMailbox(char mailbox_char) {
EXPECT_EQ(true, main_thread_.CalledOnValidThread());
- TextureMailbox mailbox(std::string(64, mailbox_char));
scoped_ptr<SingleReleaseCallback> callback = SingleReleaseCallback::Create(
base::Bind(
&TextureLayerWithMailboxMainThreadDeleted::ReleaseCallback,
base::Unretained(this)));
- layer_->SetTextureMailbox(mailbox, callback.Pass());
+ layer_->SetTextureMailbox(
+ TextureMailbox(MailboxFromChar(mailbox_char), GL_TEXTURE_2D, 0),
+ callback.Pass());
}
virtual void SetupTree() OVERRIDE {
gfx::Size bounds(100, 100);
root_ = Layer::Create();
- root_->SetAnchorPoint(gfx::PointF());
root_->SetBounds(bounds);
layer_ = TextureLayer::CreateForMailbox(NULL);
layer_->SetIsDrawable(true);
- layer_->SetAnchorPoint(gfx::PointF());
layer_->SetBounds(bounds);
root_->AddChild(layer_);
@@ -2087,7 +1476,7 @@ SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(
class TextureLayerWithMailboxImplThreadDeleted : public LayerTreeTest {
public:
- void ReleaseCallback(unsigned sync_point, bool lost_resource) {
+ void ReleaseCallback(uint32 sync_point, bool lost_resource) {
EXPECT_EQ(true, main_thread_.CalledOnValidThread());
EXPECT_FALSE(lost_resource);
++callback_count_;
@@ -2096,23 +1485,22 @@ class TextureLayerWithMailboxImplThreadDeleted : public LayerTreeTest {
void SetMailbox(char mailbox_char) {
EXPECT_EQ(true, main_thread_.CalledOnValidThread());
- TextureMailbox mailbox(std::string(64, mailbox_char));
scoped_ptr<SingleReleaseCallback> callback = SingleReleaseCallback::Create(
base::Bind(
&TextureLayerWithMailboxImplThreadDeleted::ReleaseCallback,
base::Unretained(this)));
- layer_->SetTextureMailbox(mailbox, callback.Pass());
+ layer_->SetTextureMailbox(
+ TextureMailbox(MailboxFromChar(mailbox_char), GL_TEXTURE_2D, 0),
+ callback.Pass());
}
virtual void SetupTree() OVERRIDE {
gfx::Size bounds(100, 100);
root_ = Layer::Create();
- root_->SetAnchorPoint(gfx::PointF());
root_->SetBounds(bounds);
layer_ = TextureLayer::CreateForMailbox(NULL);
layer_->SetIsDrawable(true);
- layer_->SetAnchorPoint(gfx::PointF());
layer_->SetBounds(bounds);
root_->AddChild(layer_);
diff --git a/chromium/cc/layers/tiled_layer.cc b/chromium/cc/layers/tiled_layer.cc
index 24baef526eb..56df6f716ac 100644
--- a/chromium/cc/layers/tiled_layer.cc
+++ b/chromium/cc/layers/tiled_layer.cc
@@ -10,13 +10,13 @@
#include "base/auto_reset.h"
#include "base/basictypes.h"
#include "build/build_config.h"
-#include "cc/debug/overdraw_metrics.h"
#include "cc/layers/layer_impl.h"
#include "cc/layers/tiled_layer_impl.h"
#include "cc/resources/layer_updater.h"
#include "cc/resources/prioritized_resource.h"
#include "cc/resources/priority_calculator.h"
#include "cc/trees/layer_tree_host.h"
+#include "cc/trees/occlusion_tracker.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "ui/gfx/rect_conversions.h"
@@ -142,23 +142,24 @@ void TiledLayer::UpdateTileSizeAndTilingOption() {
}
void TiledLayer::UpdateBounds() {
- gfx::Size old_bounds = tiler_->bounds();
- gfx::Size new_bounds = content_bounds();
- if (old_bounds == new_bounds)
+ gfx::Rect old_tiling_rect = tiler_->tiling_rect();
+ gfx::Rect new_tiling_rect = gfx::Rect(content_bounds());
+ if (old_tiling_rect == new_tiling_rect)
return;
- tiler_->SetBounds(new_bounds);
+ tiler_->SetTilingRect(new_tiling_rect);
// Invalidate any areas that the new bounds exposes.
- Region old_region = gfx::Rect(old_bounds);
- Region new_region = gfx::Rect(new_bounds);
- new_region.Subtract(old_region);
- for (Region::Iterator new_rects(new_region);
- new_rects.has_rect();
+ Region old_region = old_tiling_rect;
+ Region new_region = new_tiling_rect;
+ new_tiling_rect.Subtract(old_tiling_rect);
+ for (Region::Iterator new_rects(new_tiling_rect); new_rects.has_rect();
new_rects.next())
InvalidateContentRect(new_rects.rect());
}
-void TiledLayer::SetTileSize(gfx::Size size) { tiler_->SetTileSize(size); }
+void TiledLayer::SetTileSize(const gfx::Size& size) {
+ tiler_->SetTileSize(size);
+}
void TiledLayer::SetBorderTexelOption(
LayerTilingData::BorderTexelOption border_texel_option) {
@@ -294,7 +295,7 @@ void TiledLayer::SetNeedsDisplayRect(const gfx::RectF& dirty_rect) {
ContentsScalingLayer::SetNeedsDisplayRect(dirty_rect);
}
-void TiledLayer::InvalidateContentRect(gfx::Rect content_rect) {
+void TiledLayer::InvalidateContentRect(const gfx::Rect& content_rect) {
UpdateBounds();
if (tiler_->is_empty() || content_rect.IsEmpty() || skips_draw_)
return;
@@ -324,7 +325,7 @@ bool TiledLayer::UpdateTiles(int left,
int right,
int bottom,
ResourceUpdateQueue* queue,
- const OcclusionTracker* occlusion,
+ const OcclusionTracker<Layer>* occlusion,
bool* updated) {
CreateUpdaterIfNeeded();
@@ -339,9 +340,6 @@ bool TiledLayer::UpdateTiles(int left,
MarkTilesForUpdate(
&update_rect, &paint_rect, left, top, right, bottom, ignore_occlusions);
- if (occlusion)
- occlusion->overdraw_metrics()->DidPaint(paint_rect);
-
if (paint_rect.IsEmpty())
return true;
@@ -356,13 +354,7 @@ void TiledLayer::MarkOcclusionsAndRequestTextures(
int top,
int right,
int bottom,
- const OcclusionTracker* occlusion) {
- // There is some difficult dependancies between occlusions, recording
- // occlusion metrics and requesting memory so those are encapsulated in this
- // function: - We only want to call RequestLate on unoccluded textures (to
- // preserve memory for other layers when near OOM). - We only want to record
- // occlusion metrics if all memory requests succeed.
-
+ const OcclusionTracker<Layer>* occlusion) {
int occluded_tile_count = 0;
bool succeeded = true;
for (int j = top; j <= bottom; ++j) {
@@ -377,10 +369,9 @@ void TiledLayer::MarkOcclusionsAndRequestTextures(
DCHECK(!tile->occluded);
gfx::Rect visible_tile_rect = gfx::IntersectRects(
tiler_->tile_bounds(i, j), visible_content_rect());
- if (occlusion && occlusion->Occluded(render_target(),
- visible_tile_rect,
- draw_transform(),
- draw_transform_is_animating())) {
+ if (!draw_transform_is_animating() && occlusion &&
+ occlusion->Occluded(
+ render_target(), visible_tile_rect, draw_transform())) {
tile->occluded = true;
occluded_tile_count++;
} else {
@@ -388,11 +379,6 @@ void TiledLayer::MarkOcclusionsAndRequestTextures(
}
}
}
-
- if (!succeeded)
- return;
- if (occlusion)
- occlusion->overdraw_metrics()->DidCullTilesForUpload(occluded_tile_count);
}
bool TiledLayer::HaveTexturesForTiles(int left,
@@ -468,14 +454,14 @@ void TiledLayer::MarkTilesForUpdate(gfx::Rect* update_rect,
}
}
-void TiledLayer::UpdateTileTextures(gfx::Rect update_rect,
- gfx::Rect paint_rect,
+void TiledLayer::UpdateTileTextures(const gfx::Rect& update_rect,
+ const gfx::Rect& paint_rect,
int left,
int top,
int right,
int bottom,
ResourceUpdateQueue* queue,
- const OcclusionTracker* occlusion) {
+ const OcclusionTracker<Layer>* occlusion) {
// The update_rect should be in layer space. So we have to convert the
// paint_rect from content space to layer space.
float width_scale =
@@ -564,10 +550,6 @@ void TiledLayer::UpdateTileTextures(gfx::Rect update_rect,
tile->updater_resource()->Update(
queue, source_rect, dest_offset, tile->partial_update);
- if (occlusion) {
- occlusion->overdraw_metrics()->
- DidUpload(gfx::Transform(), source_rect, tile->opaque_rect());
- }
}
}
}
@@ -593,8 +575,8 @@ namespace {
// TODO(epenner): Remove this and make this based on distance once distance can
// be calculated for offscreen layers. For now, prioritize all small animated
// layers after 512 pixels of pre-painting.
-void SetPriorityForTexture(gfx::Rect visible_rect,
- gfx::Rect tile_rect,
+void SetPriorityForTexture(const gfx::Rect& visible_rect,
+ const gfx::Rect& tile_rect,
bool draws_to_root,
bool is_small_animated_layer,
PrioritizedResource* texture) {
@@ -684,7 +666,7 @@ void TiledLayer::ResetUpdateState() {
}
namespace {
-gfx::Rect ExpandRectByDelta(gfx::Rect rect, gfx::Vector2d delta) {
+gfx::Rect ExpandRectByDelta(const gfx::Rect& rect, const gfx::Vector2d& delta) {
int width = rect.width() + std::abs(delta.x());
int height = rect.height() + std::abs(delta.y());
int x = rect.x() + ((delta.x() < 0) ? delta.x() : 0);
@@ -730,7 +712,7 @@ void TiledLayer::UpdateScrollPrediction() {
}
bool TiledLayer::Update(ResourceUpdateQueue* queue,
- const OcclusionTracker* occlusion) {
+ const OcclusionTracker<Layer>* occlusion) {
DCHECK(!skips_draw_ && !failed_update_); // Did ResetUpdateState get skipped?
// Tiled layer always causes commits to wait for activation, as it does
diff --git a/chromium/cc/layers/tiled_layer.h b/chromium/cc/layers/tiled_layer.h
index 82063600c71..e272497e7ef 100644
--- a/chromium/cc/layers/tiled_layer.h
+++ b/chromium/cc/layers/tiled_layer.h
@@ -35,7 +35,7 @@ class CC_EXPORT TiledLayer : public ContentsScalingLayer {
OVERRIDE;
virtual Region VisibleContentOpaqueRegion() const OVERRIDE;
virtual bool Update(ResourceUpdateQueue* queue,
- const OcclusionTracker* occlusion) OVERRIDE;
+ const OcclusionTracker<Layer>* occlusion) OVERRIDE;
virtual void OnOutputSurfaceCreated() OVERRIDE;
protected:
@@ -46,7 +46,7 @@ class CC_EXPORT TiledLayer : public ContentsScalingLayer {
void UpdateBounds();
// Exposed to subclasses for testing.
- void SetTileSize(gfx::Size size);
+ void SetTileSize(const gfx::Size& size);
void SetTextureFormat(ResourceFormat texture_format) {
texture_format_ = texture_format;
}
@@ -57,7 +57,7 @@ class CC_EXPORT TiledLayer : public ContentsScalingLayer {
virtual void CreateUpdaterIfNeeded() = 0;
// Set invalidations to be potentially repainted during Update().
- void InvalidateContentRect(gfx::Rect content_rect);
+ void InvalidateContentRect(const gfx::Rect& content_rect);
// Reset state on tiles that will be used for updating the layer.
void ResetUpdateState();
@@ -85,18 +85,19 @@ class CC_EXPORT TiledLayer : public ContentsScalingLayer {
bool TileOnlyNeedsPartialUpdate(UpdatableTile* tile);
bool TileNeedsBufferedUpdate(UpdatableTile* tile);
- void MarkOcclusionsAndRequestTextures(int left,
- int top,
- int right,
- int bottom,
- const OcclusionTracker* occlusion);
+ void MarkOcclusionsAndRequestTextures(
+ int left,
+ int top,
+ int right,
+ int bottom,
+ const OcclusionTracker<Layer>* occlusion);
bool UpdateTiles(int left,
int top,
int right,
int bottom,
ResourceUpdateQueue* queue,
- const OcclusionTracker* occlusion,
+ const OcclusionTracker<Layer>* occlusion,
bool* did_paint);
bool HaveTexturesForTiles(int left,
int top,
@@ -110,14 +111,14 @@ class CC_EXPORT TiledLayer : public ContentsScalingLayer {
int right,
int bottom,
bool ignore_occlusions);
- void UpdateTileTextures(gfx::Rect update_rect,
- gfx::Rect paint_rect,
+ void UpdateTileTextures(const gfx::Rect& update_rect,
+ const gfx::Rect& paint_rect,
int left,
int top,
int right,
int bottom,
ResourceUpdateQueue* queue,
- const OcclusionTracker* occlusion);
+ const OcclusionTracker<Layer>* occlusion);
void UpdateScrollPrediction();
UpdatableTile* TileAt(int i, int j) const;
diff --git a/chromium/cc/layers/tiled_layer_impl.cc b/chromium/cc/layers/tiled_layer_impl.cc
index 88797c224dd..6aacd1e16b7 100644
--- a/chromium/cc/layers/tiled_layer_impl.cc
+++ b/chromium/cc/layers/tiled_layer_impl.cc
@@ -54,6 +54,12 @@ TiledLayerImpl::~TiledLayerImpl() {
ResourceProvider::ResourceId TiledLayerImpl::ContentsResourceId() const {
// This function is only valid for single texture layers, e.g. masks.
DCHECK(tiler_);
+ // It's possible the mask layer is created but has no size or otherwise
+ // can't draw.
+ if (tiler_->num_tiles_x() == 0 || tiler_->num_tiles_y() == 0)
+ return 0;
+
+ // Any other number of tiles other than 0 or 1 is incorrect for masks.
DCHECK_EQ(tiler_->num_tiles_x(), 1);
DCHECK_EQ(tiler_->num_tiles_y(), 1);
@@ -152,9 +158,11 @@ void TiledLayerImpl::AppendQuads(QuadSink* quad_sink,
DCHECK(!visible_content_rect().IsEmpty());
gfx::Rect content_rect = visible_content_rect();
- SharedQuadState* shared_quad_state =
- quad_sink->UseSharedQuadState(CreateSharedQuadState());
- AppendDebugBorderQuad(quad_sink, shared_quad_state, append_quads_data);
+ SharedQuadState* shared_quad_state = quad_sink->CreateSharedQuadState();
+ PopulateSharedQuadState(shared_quad_state);
+
+ AppendDebugBorderQuad(
+ quad_sink, content_bounds(), shared_quad_state, append_quads_data);
int left, top, right, bottom;
tiler_->ContentRectToTileIndices(content_rect, &left, &top, &right, &bottom);
@@ -164,6 +172,7 @@ void TiledLayerImpl::AppendQuads(QuadSink* quad_sink,
for (int i = left; i <= right; ++i) {
DrawableTile* tile = TileAt(i, j);
gfx::Rect tile_rect = tiler_->tile_bounds(i, j);
+ gfx::Rect visible_tile_rect = tile_rect;
SkColor border_color;
float border_width;
@@ -176,10 +185,12 @@ void TiledLayerImpl::AppendQuads(QuadSink* quad_sink,
}
scoped_ptr<DebugBorderDrawQuad> debug_border_quad =
DebugBorderDrawQuad::Create();
- debug_border_quad->SetNew(
- shared_quad_state, tile_rect, border_color, border_width);
- quad_sink->Append(debug_border_quad.PassAs<DrawQuad>(),
- append_quads_data);
+ debug_border_quad->SetNew(shared_quad_state,
+ tile_rect,
+ visible_tile_rect,
+ border_color,
+ border_width);
+ quad_sink->Append(debug_border_quad.PassAs<DrawQuad>());
}
}
}
@@ -198,6 +209,11 @@ void TiledLayerImpl::AppendQuads(QuadSink* quad_sink,
if (tile_rect.IsEmpty())
continue;
+ gfx::Rect visible_tile_rect =
+ quad_sink->UnoccludedContentRect(tile_rect, draw_transform());
+ if (visible_tile_rect.IsEmpty())
+ continue;
+
if (!tile || !tile->resource_id()) {
SkColor checker_color;
if (ShowDebugBorders()) {
@@ -211,11 +227,9 @@ void TiledLayerImpl::AppendQuads(QuadSink* quad_sink,
scoped_ptr<CheckerboardDrawQuad> checkerboard_quad =
CheckerboardDrawQuad::Create();
checkerboard_quad->SetNew(
- shared_quad_state, tile_rect, checker_color);
- if (quad_sink->Append(checkerboard_quad.PassAs<DrawQuad>(),
- append_quads_data))
- append_quads_data->num_missing_tiles++;
-
+ shared_quad_state, tile_rect, visible_tile_rect, checker_color);
+ quad_sink->Append(checkerboard_quad.PassAs<DrawQuad>());
+ append_quads_data->num_missing_tiles++;
continue;
}
@@ -238,11 +252,12 @@ void TiledLayerImpl::AppendQuads(QuadSink* quad_sink,
quad->SetNew(shared_quad_state,
tile_rect,
tile_opaque_rect,
+ visible_tile_rect,
tile->resource_id(),
tex_coord_rect,
texture_size,
tile->contents_swizzled());
- quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
+ quad_sink->Append(quad.PassAs<DrawQuad>());
}
}
}
@@ -263,7 +278,7 @@ void TiledLayerImpl::PushTileProperties(
int i,
int j,
ResourceProvider::ResourceId resource_id,
- gfx::Rect opaque_rect,
+ const gfx::Rect& opaque_rect,
bool contents_swizzled) {
DrawableTile* tile = TileAt(i, j);
if (!tile)
@@ -290,7 +305,7 @@ Region TiledLayerImpl::VisibleContentOpaqueRegion() const {
return tiler_->OpaqueRegionInContentRect(visible_content_rect());
}
-void TiledLayerImpl::DidLoseOutputSurface() {
+void TiledLayerImpl::ReleaseResources() {
tiler_->reset();
}
diff --git a/chromium/cc/layers/tiled_layer_impl.h b/chromium/cc/layers/tiled_layer_impl.h
index 939842b9027..f4ed1e87e82 100644
--- a/chromium/cc/layers/tiled_layer_impl.h
+++ b/chromium/cc/layers/tiled_layer_impl.h
@@ -38,12 +38,12 @@ class CC_EXPORT TiledLayerImpl : public LayerImpl {
void PushTileProperties(int i,
int j,
ResourceProvider::ResourceId resource,
- gfx::Rect opaque_rect,
+ const gfx::Rect& opaque_rect,
bool contents_swizzled);
void PushInvalidTile(int i, int j);
virtual Region VisibleContentOpaqueRegion() const OVERRIDE;
- virtual void DidLoseOutputSurface() OVERRIDE;
+ virtual void ReleaseResources() OVERRIDE;
const LayerTilingData* TilingForTesting() const { return tiler_.get(); }
diff --git a/chromium/cc/layers/tiled_layer_impl_unittest.cc b/chromium/cc/layers/tiled_layer_impl_unittest.cc
index 801cbf4dc27..7fa7d0f7b51 100644
--- a/chromium/cc/layers/tiled_layer_impl_unittest.cc
+++ b/chromium/cc/layers/tiled_layer_impl_unittest.cc
@@ -20,17 +20,17 @@ namespace {
class TiledLayerImplTest : public testing::Test {
public:
- TiledLayerImplTest() : host_impl_(&proxy_) {}
+ TiledLayerImplTest() : host_impl_(&proxy_, &shared_bitmap_manager_) {}
scoped_ptr<TiledLayerImpl> CreateLayerNoTiles(
- gfx::Size tile_size,
- gfx::Size layer_size,
+ const gfx::Size& tile_size,
+ const gfx::Size& layer_size,
LayerTilingData::BorderTexelOption border_texels) {
scoped_ptr<TiledLayerImpl> layer =
TiledLayerImpl::Create(host_impl_.active_tree(), 1);
scoped_ptr<LayerTilingData> tiler =
LayerTilingData::Create(tile_size, border_texels);
- tiler->SetBounds(layer_size);
+ tiler->SetTilingRect(gfx::Rect(layer_size));
layer->SetTilingData(*tiler);
layer->set_skips_draw(false);
layer->draw_properties().visible_content_rect =
@@ -46,14 +46,12 @@ class TiledLayerImplTest : public testing::Test {
// Create a default tiled layer with textures for all tiles and a default
// visibility of the entire layer size.
scoped_ptr<TiledLayerImpl> CreateLayer(
- gfx::Size tile_size,
- gfx::Size layer_size,
+ const gfx::Size& tile_size,
+ const gfx::Size& layer_size,
LayerTilingData::BorderTexelOption border_texels) {
scoped_ptr<TiledLayerImpl> layer =
CreateLayerNoTiles(tile_size, layer_size, border_texels);
- layer->SetDrawsContent(true);
-
ResourceProvider::ResourceId resource_id = 1;
for (int i = 0; i < layer->TilingForTesting()->num_tiles_x(); ++i) {
for (int j = 0; j < layer->TilingForTesting()->num_tiles_y(); ++j) {
@@ -67,24 +65,25 @@ class TiledLayerImplTest : public testing::Test {
return layer.Pass();
}
- void GetQuads(QuadList* quads,
- SharedQuadStateList* shared_states,
- gfx::Size tile_size,
- gfx::Size layer_size,
+ void GetQuads(RenderPass* render_pass,
+ const gfx::Size& tile_size,
+ const gfx::Size& layer_size,
LayerTilingData::BorderTexelOption border_texel_option,
- gfx::Rect visible_content_rect) {
+ const gfx::Rect& visible_content_rect) {
scoped_ptr<TiledLayerImpl> layer =
CreateLayer(tile_size, layer_size, border_texel_option);
layer->draw_properties().visible_content_rect = visible_content_rect;
layer->SetBounds(layer_size);
- MockQuadCuller quad_culler(quads, shared_states);
+ MockOcclusionTracker<LayerImpl> occlusion_tracker;
+ MockQuadCuller quad_culler(render_pass, &occlusion_tracker);
AppendQuadsData data;
layer->AppendQuads(&quad_culler, &data);
}
protected:
FakeImplProxy proxy_;
+ TestSharedBitmapManager shared_bitmap_manager_;
FakeLayerTreeHostImpl host_impl_;
};
@@ -99,7 +98,10 @@ TEST_F(TiledLayerImplTest, EmptyQuadList) {
{
scoped_ptr<TiledLayerImpl> layer =
CreateLayer(tile_size, layer_size, LayerTilingData::NO_BORDER_TEXELS);
- MockQuadCuller quad_culler;
+ MockOcclusionTracker<LayerImpl> occlusion_tracker;
+ scoped_ptr<RenderPass> render_pass = RenderPass::Create();
+ MockQuadCuller quad_culler(render_pass.get(), &occlusion_tracker);
+
AppendQuadsData data;
EXPECT_TRUE(layer->WillDraw(DRAW_MODE_HARDWARE, NULL));
layer->AppendQuads(&quad_culler, &data);
@@ -114,7 +116,10 @@ TEST_F(TiledLayerImplTest, EmptyQuadList) {
CreateLayer(tile_size, layer_size, LayerTilingData::NO_BORDER_TEXELS);
layer->draw_properties().visible_content_rect = gfx::Rect();
- MockQuadCuller quad_culler;
+ MockOcclusionTracker<LayerImpl> occlusion_tracker;
+ scoped_ptr<RenderPass> render_pass = RenderPass::Create();
+ MockQuadCuller quad_culler(render_pass.get(), &occlusion_tracker);
+
EXPECT_FALSE(layer->WillDraw(DRAW_MODE_HARDWARE, NULL));
}
@@ -126,7 +131,10 @@ TEST_F(TiledLayerImplTest, EmptyQuadList) {
gfx::Rect outside_bounds(-100, -100, 50, 50);
layer->draw_properties().visible_content_rect = outside_bounds;
- MockQuadCuller quad_culler;
+ MockOcclusionTracker<LayerImpl> occlusion_tracker;
+ scoped_ptr<RenderPass> render_pass = RenderPass::Create();
+ MockQuadCuller quad_culler(render_pass.get(), &occlusion_tracker);
+
AppendQuadsData data;
EXPECT_TRUE(layer->WillDraw(DRAW_MODE_HARDWARE, NULL));
layer->AppendQuads(&quad_culler, &data);
@@ -140,7 +148,10 @@ TEST_F(TiledLayerImplTest, EmptyQuadList) {
CreateLayer(tile_size, layer_size, LayerTilingData::NO_BORDER_TEXELS);
layer->set_skips_draw(true);
- MockQuadCuller quad_culler;
+ MockOcclusionTracker<LayerImpl> occlusion_tracker;
+ scoped_ptr<RenderPass> render_pass = RenderPass::Create();
+ MockQuadCuller quad_culler(render_pass.get(), &occlusion_tracker);
+
AppendQuadsData data;
layer->AppendQuads(&quad_culler, &data);
EXPECT_EQ(quad_culler.quad_list().size(), 0u);
@@ -159,7 +170,10 @@ TEST_F(TiledLayerImplTest, Checkerboarding) {
// No checkerboarding
{
- MockQuadCuller quad_culler;
+ MockOcclusionTracker<LayerImpl> occlusion_tracker;
+ scoped_ptr<RenderPass> render_pass = RenderPass::Create();
+ MockQuadCuller quad_culler(render_pass.get(), &occlusion_tracker);
+
AppendQuadsData data;
layer->AppendQuads(&quad_culler, &data);
EXPECT_EQ(quad_culler.quad_list().size(), 4u);
@@ -175,7 +189,10 @@ TEST_F(TiledLayerImplTest, Checkerboarding) {
// All checkerboarding
{
- MockQuadCuller quad_culler;
+ MockOcclusionTracker<LayerImpl> occlusion_tracker;
+ scoped_ptr<RenderPass> render_pass = RenderPass::Create();
+ MockQuadCuller quad_culler(render_pass.get(), &occlusion_tracker);
+
AppendQuadsData data;
layer->AppendQuads(&quad_culler, &data);
EXPECT_LT(0u, data.num_missing_tiles);
@@ -199,15 +216,14 @@ class TiledLayerImplBorderTest : public TiledLayerImplTest {
void CoverageVisibleRectOnTileBoundaries(
LayerTilingData::BorderTexelOption borders) {
gfx::Size layer_size(1000, 1000);
- QuadList quads;
- SharedQuadStateList shared_states;
- GetQuads(&quads,
- &shared_states,
+ scoped_ptr<RenderPass> render_pass = RenderPass::Create();
+ GetQuads(render_pass.get(),
gfx::Size(100, 100),
layer_size,
borders,
gfx::Rect(layer_size));
- LayerTestCommon::VerifyQuadsExactlyCoverRect(quads, gfx::Rect(layer_size));
+ LayerTestCommon::VerifyQuadsExactlyCoverRect(render_pass->quad_list,
+ gfx::Rect(layer_size));
}
void CoverageVisibleRectIntersectsTiles(
@@ -218,30 +234,28 @@ class TiledLayerImplBorderTest : public TiledLayerImplTest {
gfx::Rect visible_content_rect = gfx::BoundingRect(top_left, bottom_right);
gfx::Size layer_size(250, 250);
- QuadList quads;
- SharedQuadStateList shared_states;
- GetQuads(&quads,
- &shared_states,
+ scoped_ptr<RenderPass> render_pass = RenderPass::Create();
+ GetQuads(render_pass.get(),
gfx::Size(50, 50),
gfx::Size(250, 250),
LayerTilingData::NO_BORDER_TEXELS,
visible_content_rect);
- LayerTestCommon::VerifyQuadsExactlyCoverRect(quads, visible_content_rect);
+ LayerTestCommon::VerifyQuadsExactlyCoverRect(render_pass->quad_list,
+ visible_content_rect);
}
void CoverageVisibleRectIntersectsBounds(
LayerTilingData::BorderTexelOption borders) {
gfx::Size layer_size(220, 210);
gfx::Rect visible_content_rect(layer_size);
- QuadList quads;
- SharedQuadStateList shared_states;
- GetQuads(&quads,
- &shared_states,
+ scoped_ptr<RenderPass> render_pass = RenderPass::Create();
+ GetQuads(render_pass.get(),
gfx::Size(100, 100),
layer_size,
LayerTilingData::NO_BORDER_TEXELS,
visible_content_rect);
- LayerTestCommon::VerifyQuadsExactlyCoverRect(quads, visible_content_rect);
+ LayerTestCommon::VerifyQuadsExactlyCoverRect(render_pass->quad_list,
+ visible_content_rect);
}
};
WITH_AND_WITHOUT_BORDER_TEST(CoverageVisibleRectOnTileBoundaries);
@@ -253,17 +267,16 @@ WITH_AND_WITHOUT_BORDER_TEST(CoverageVisibleRectIntersectsBounds);
TEST_F(TiledLayerImplTest, TextureInfoForLayerNoBorders) {
gfx::Size tile_size(50, 50);
gfx::Size layer_size(250, 250);
- QuadList quads;
- SharedQuadStateList shared_states;
- GetQuads(&quads,
- &shared_states,
+ scoped_ptr<RenderPass> render_pass = RenderPass::Create();
+ GetQuads(render_pass.get(),
tile_size,
layer_size,
LayerTilingData::NO_BORDER_TEXELS,
gfx::Rect(layer_size));
- for (size_t i = 0; i < quads.size(); ++i) {
- const TileDrawQuad* quad = TileDrawQuad::MaterialCast(quads[i]);
+ for (size_t i = 0; i < render_pass->quad_list.size(); ++i) {
+ const TileDrawQuad* quad =
+ TileDrawQuad::MaterialCast(render_pass->quad_list[i]);
EXPECT_NE(0u, quad->resource_id) << LayerTestCommon::quad_string << i;
EXPECT_EQ(gfx::RectF(gfx::PointF(), tile_size), quad->tex_coord_rect)
@@ -304,5 +317,78 @@ TEST_F(TiledLayerImplTest, GPUMemoryUsage) {
EXPECT_EQ(layer->GPUMemoryUsageInBytes(), 0u);
}
+TEST_F(TiledLayerImplTest, EmptyMask) {
+ gfx::Size tile_size(20, 20);
+ gfx::Size layer_size(0, 0);
+ scoped_ptr<TiledLayerImpl> layer =
+ CreateLayer(tile_size, layer_size, LayerTilingData::NO_BORDER_TEXELS);
+
+ EXPECT_EQ(0u, layer->ContentsResourceId());
+ EXPECT_EQ(0, layer->TilingForTesting()->num_tiles_x());
+ EXPECT_EQ(0, layer->TilingForTesting()->num_tiles_y());
+}
+
+TEST_F(TiledLayerImplTest, Occlusion) {
+ gfx::Size tile_size(100, 100);
+ gfx::Size layer_bounds(1000, 1000);
+ gfx::Size viewport_size(1000, 1000);
+
+ LayerTestCommon::LayerImplTest impl;
+
+ TiledLayerImpl* tiled_layer = impl.AddChildToRoot<TiledLayerImpl>();
+ tiled_layer->SetBounds(layer_bounds);
+ tiled_layer->SetContentBounds(layer_bounds);
+ tiled_layer->SetDrawsContent(true);
+ tiled_layer->set_skips_draw(false);
+
+ scoped_ptr<LayerTilingData> tiler =
+ LayerTilingData::Create(tile_size, LayerTilingData::NO_BORDER_TEXELS);
+ tiler->SetTilingRect(gfx::Rect(layer_bounds));
+ tiled_layer->SetTilingData(*tiler);
+
+ ResourceProvider::ResourceId resource_id = 1;
+ for (int i = 0; i < tiled_layer->TilingForTesting()->num_tiles_x(); ++i) {
+ for (int j = 0; j < tiled_layer->TilingForTesting()->num_tiles_y(); ++j)
+ tiled_layer->PushTileProperties(i, j, resource_id++, gfx::Rect(), false);
+ }
+
+ impl.CalcDrawProps(viewport_size);
+
+ {
+ SCOPED_TRACE("No occlusion");
+ gfx::Rect occluded;
+ impl.AppendQuadsWithOcclusion(tiled_layer, occluded);
+
+ LayerTestCommon::VerifyQuadsExactlyCoverRect(impl.quad_list(),
+ gfx::Rect(layer_bounds));
+ EXPECT_EQ(100u, impl.quad_list().size());
+ }
+
+ {
+ SCOPED_TRACE("Full occlusion");
+ gfx::Rect occluded(tiled_layer->visible_content_rect());
+ impl.AppendQuadsWithOcclusion(tiled_layer, occluded);
+
+ LayerTestCommon::VerifyQuadsExactlyCoverRect(impl.quad_list(), gfx::Rect());
+ EXPECT_EQ(impl.quad_list().size(), 0u);
+ }
+
+ {
+ SCOPED_TRACE("Partial occlusion");
+ gfx::Rect occluded(150, 0, 200, 1000);
+ impl.AppendQuadsWithOcclusion(tiled_layer, occluded);
+
+ size_t partially_occluded_count = 0;
+ LayerTestCommon::VerifyQuadsCoverRectWithOcclusion(
+ impl.quad_list(),
+ gfx::Rect(layer_bounds),
+ occluded,
+ &partially_occluded_count);
+ // The layer outputs one quad, which is partially occluded.
+ EXPECT_EQ(100u - 10u, impl.quad_list().size());
+ EXPECT_EQ(10u + 10u, partially_occluded_count);
+ }
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/layers/tiled_layer_unittest.cc b/chromium/cc/layers/tiled_layer_unittest.cc
index 42ef29cc93e..bd15f2f1f54 100644
--- a/chromium/cc/layers/tiled_layer_unittest.cc
+++ b/chromium/cc/layers/tiled_layer_unittest.cc
@@ -7,7 +7,7 @@
#include <limits>
#include <vector>
-#include "cc/debug/overdraw_metrics.h"
+#include "base/run_loop.h"
#include "cc/resources/bitmap_content_layer_updater.h"
#include "cc/resources/layer_painter.h"
#include "cc/resources/prioritized_resource_manager.h"
@@ -20,7 +20,9 @@
#include "cc/test/fake_proxy.h"
#include "cc/test/fake_rendering_stats_instrumentation.h"
#include "cc/test/geometry_test_utils.h"
+#include "cc/test/test_shared_bitmap_manager.h"
#include "cc/test/tiled_layer_test_common.h"
+#include "cc/trees/occlusion_tracker.h"
#include "cc/trees/single_thread_proxy.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/rect_conversions.h"
@@ -29,9 +31,9 @@
namespace cc {
namespace {
-class TestOcclusionTracker : public OcclusionTracker {
+class TestOcclusionTracker : public OcclusionTracker<Layer> {
public:
- TestOcclusionTracker() : OcclusionTracker(gfx::Rect(0, 0, 1000, 1000), true) {
+ TestOcclusionTracker() : OcclusionTracker(gfx::Rect(0, 0, 1000, 1000)) {
stack_.push_back(StackObject());
}
@@ -44,6 +46,50 @@ class TestOcclusionTracker : public OcclusionTracker {
}
};
+class SynchronousOutputSurfaceLayerTreeHost : public LayerTreeHost {
+ public:
+ static scoped_ptr<SynchronousOutputSurfaceLayerTreeHost> Create(
+ LayerTreeHostClient* client,
+ SharedBitmapManager* manager,
+ const LayerTreeSettings& settings,
+ scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner) {
+ return make_scoped_ptr(new SynchronousOutputSurfaceLayerTreeHost(
+ client, manager, settings, impl_task_runner));
+ }
+
+ virtual ~SynchronousOutputSurfaceLayerTreeHost() {}
+
+ bool EnsureOutputSurfaceCreated() {
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ run_loop_.QuitClosure(),
+ base::TimeDelta::FromSeconds(5));
+ run_loop_.Run();
+ return output_surface_created_;
+ }
+
+ virtual void OnCreateAndInitializeOutputSurfaceAttempted(
+ bool success) OVERRIDE {
+ LayerTreeHost::OnCreateAndInitializeOutputSurfaceAttempted(success);
+ output_surface_created_ = success;
+ run_loop_.Quit();
+ }
+
+ private:
+ SynchronousOutputSurfaceLayerTreeHost(
+ LayerTreeHostClient* client,
+ SharedBitmapManager* manager,
+ const LayerTreeSettings& settings,
+ scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner)
+ : LayerTreeHost(client, manager, settings),
+ output_surface_created_(false) {
+ LayerTreeHost::InitializeThreaded(impl_task_runner);
+ }
+
+ bool output_surface_created_;
+ base::RunLoop run_loop_;
+};
+
class TiledLayerTest : public testing::Test {
public:
TiledLayerTest()
@@ -59,24 +105,27 @@ class TiledLayerTest : public testing::Test {
virtual void SetUp() {
impl_thread_.Start();
- layer_tree_host_ = LayerTreeHost::CreateThreaded(
+ shared_bitmap_manager_.reset(new TestSharedBitmapManager());
+ layer_tree_host_ = SynchronousOutputSurfaceLayerTreeHost::Create(
&fake_layer_tree_host_client_,
- NULL,
+ shared_bitmap_manager_.get(),
settings_,
impl_thread_.message_loop_proxy());
proxy_ = layer_tree_host_->proxy();
resource_manager_ = PrioritizedResourceManager::Create(proxy_);
layer_tree_host_->SetLayerTreeHostClientReady();
- layer_tree_host_->InitializeOutputSurfaceIfNeeded();
+ CHECK(layer_tree_host_->EnsureOutputSurfaceCreated());
layer_tree_host_->SetRootLayer(Layer::Create());
CHECK(output_surface_->BindToClient(&output_surface_client_));
DebugScopedSetImplThreadAndMainThreadBlocked
impl_thread_and_main_thread_blocked(proxy_);
- resource_provider_ =
- ResourceProvider::Create(output_surface_.get(), NULL, 0, false, 1);
- host_impl_ = make_scoped_ptr(new FakeLayerTreeHostImpl(proxy_));
+ resource_provider_ = ResourceProvider::Create(
+ output_surface_.get(), shared_bitmap_manager_.get(), 0, false, 1,
+ false);
+ host_impl_ = make_scoped_ptr(
+ new FakeLayerTreeHostImpl(proxy_, shared_bitmap_manager_.get()));
}
virtual ~TiledLayerTest() {
@@ -194,12 +243,13 @@ class TiledLayerTest : public testing::Test {
LayerTreeSettings settings_;
FakeOutputSurfaceClient output_surface_client_;
scoped_ptr<OutputSurface> output_surface_;
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager_;
scoped_ptr<ResourceProvider> resource_provider_;
scoped_ptr<ResourceUpdateQueue> queue_;
PriorityCalculator priority_calculator_;
base::Thread impl_thread_;
FakeLayerTreeHostClient fake_layer_tree_host_client_;
- scoped_ptr<LayerTreeHost> layer_tree_host_;
+ scoped_ptr<SynchronousOutputSurfaceLayerTreeHost> layer_tree_host_;
scoped_ptr<FakeLayerTreeHostImpl> host_impl_;
scoped_ptr<PrioritizedResourceManager> resource_manager_;
TestOcclusionTracker* occlusion_;
@@ -253,11 +303,6 @@ TEST_F(TiledLayerTest, PushOccludedDirtyTiles) {
CalcDrawProps(&render_surface_layer_list);
UpdateAndPush(layer, layer_impl);
- EXPECT_NEAR(occluded.overdraw_metrics()->pixels_uploaded_opaque(), 0, 1);
- EXPECT_NEAR(
- occluded.overdraw_metrics()->pixels_uploaded_translucent(), 20000, 1);
- EXPECT_EQ(0, occluded.overdraw_metrics()->tiles_culled_for_upload());
-
// We should have both tiles on the impl side.
EXPECT_TRUE(layer_impl->HasResourceIdForTileAt(0, 0));
EXPECT_TRUE(layer_impl->HasResourceIdForTileAt(0, 1));
@@ -273,12 +318,6 @@ TEST_F(TiledLayerTest, PushOccludedDirtyTiles) {
CalcDrawProps(&render_surface_layer_list);
UpdateAndPush(layer, layer_impl);
- EXPECT_NEAR(occluded.overdraw_metrics()->pixels_uploaded_opaque(), 0, 1);
- EXPECT_NEAR(occluded.overdraw_metrics()->pixels_uploaded_translucent(),
- 20000 + 2500,
- 1);
- EXPECT_EQ(0, occluded.overdraw_metrics()->tiles_culled_for_upload());
-
// We should still have both tiles, as part of the top tile is still
// unoccluded.
EXPECT_TRUE(layer_impl->HasResourceIdForTileAt(0, 0));
@@ -525,10 +564,7 @@ TEST_F(TiledLayerTest, PushIdlePaintedOccludedTiles) {
layer->draw_properties().visible_content_rect = gfx::Rect(0, 0, 100, 100);
UpdateAndPush(layer, layer_impl);
- // We should have the prepainted tile on the impl side, but culled it during
- // paint.
EXPECT_TRUE(layer_impl->HasResourceIdForTileAt(0, 0));
- EXPECT_EQ(1, occluded.overdraw_metrics()->tiles_culled_for_upload());
}
TEST_F(TiledLayerTest, PushTilesMarkedDirtyDuringPaint) {
@@ -1180,11 +1216,6 @@ TEST_F(TiledLayerTest, TilesPaintedWithOcclusion) {
layer->Update(queue_.get(), &occluded);
EXPECT_EQ(36 - 3, layer->fake_layer_updater()->update_count());
- EXPECT_NEAR(occluded.overdraw_metrics()->pixels_uploaded_opaque(), 0, 1);
- EXPECT_NEAR(
- occluded.overdraw_metrics()->pixels_uploaded_translucent(), 330000, 1);
- EXPECT_EQ(3, occluded.overdraw_metrics()->tiles_culled_for_upload());
-
layer->fake_layer_updater()->ClearUpdateCount();
layer->SetTexturePriorities(priority_calculator_);
resource_manager_->PrioritizeTextures();
@@ -1195,12 +1226,6 @@ TEST_F(TiledLayerTest, TilesPaintedWithOcclusion) {
layer->Update(queue_.get(), &occluded);
EXPECT_EQ(36 - 2, layer->fake_layer_updater()->update_count());
- EXPECT_NEAR(occluded.overdraw_metrics()->pixels_uploaded_opaque(), 0, 1);
- EXPECT_NEAR(occluded.overdraw_metrics()->pixels_uploaded_translucent(),
- 330000 + 340000,
- 1);
- EXPECT_EQ(3 + 2, occluded.overdraw_metrics()->tiles_culled_for_upload());
-
layer->fake_layer_updater()->ClearUpdateCount();
layer->SetTexturePriorities(priority_calculator_);
resource_manager_->PrioritizeTextures();
@@ -1210,12 +1235,6 @@ TEST_F(TiledLayerTest, TilesPaintedWithOcclusion) {
layer->SavePaintProperties();
layer->Update(queue_.get(), &occluded);
EXPECT_EQ(36, layer->fake_layer_updater()->update_count());
-
- EXPECT_NEAR(occluded.overdraw_metrics()->pixels_uploaded_opaque(), 0, 1);
- EXPECT_NEAR(occluded.overdraw_metrics()->pixels_uploaded_translucent(),
- 330000 + 340000 + 360000,
- 1);
- EXPECT_EQ(3 + 2, occluded.overdraw_metrics()->tiles_culled_for_upload());
}
TEST_F(TiledLayerTest, TilesPaintedWithOcclusionAndVisiblityConstraints) {
@@ -1246,11 +1265,6 @@ TEST_F(TiledLayerTest, TilesPaintedWithOcclusionAndVisiblityConstraints) {
layer->Update(queue_.get(), &occluded);
EXPECT_EQ(24 - 3, layer->fake_layer_updater()->update_count());
- EXPECT_NEAR(occluded.overdraw_metrics()->pixels_uploaded_opaque(), 0, 1);
- EXPECT_NEAR(
- occluded.overdraw_metrics()->pixels_uploaded_translucent(), 210000, 1);
- EXPECT_EQ(3, occluded.overdraw_metrics()->tiles_culled_for_upload());
-
layer->fake_layer_updater()->ClearUpdateCount();
// Now the visible region stops at the edge of the occlusion so the partly
@@ -1265,12 +1279,6 @@ TEST_F(TiledLayerTest, TilesPaintedWithOcclusionAndVisiblityConstraints) {
layer->Update(queue_.get(), &occluded);
EXPECT_EQ(24 - 6, layer->fake_layer_updater()->update_count());
- EXPECT_NEAR(occluded.overdraw_metrics()->pixels_uploaded_opaque(), 0, 1);
- EXPECT_NEAR(occluded.overdraw_metrics()->pixels_uploaded_translucent(),
- 210000 + 180000,
- 1);
- EXPECT_EQ(3 + 6, occluded.overdraw_metrics()->tiles_culled_for_upload());
-
layer->fake_layer_updater()->ClearUpdateCount();
// Now the visible region is even smaller than the occlusion, it should have
@@ -1284,12 +1292,6 @@ TEST_F(TiledLayerTest, TilesPaintedWithOcclusionAndVisiblityConstraints) {
layer->SavePaintProperties();
layer->Update(queue_.get(), &occluded);
EXPECT_EQ(24 - 6, layer->fake_layer_updater()->update_count());
-
- EXPECT_NEAR(occluded.overdraw_metrics()->pixels_uploaded_opaque(), 0, 1);
- EXPECT_NEAR(occluded.overdraw_metrics()->pixels_uploaded_translucent(),
- 210000 + 180000 + 180000,
- 1);
- EXPECT_EQ(3 + 6 + 6, occluded.overdraw_metrics()->tiles_culled_for_upload());
}
TEST_F(TiledLayerTest, TilesNotPaintedWithoutInvalidation) {
@@ -1316,12 +1318,7 @@ TEST_F(TiledLayerTest, TilesNotPaintedWithoutInvalidation) {
layer->SavePaintProperties();
layer->Update(queue_.get(), &occluded);
EXPECT_EQ(36 - 3, layer->fake_layer_updater()->update_count());
- { UpdateTextures(); }
-
- EXPECT_NEAR(occluded.overdraw_metrics()->pixels_uploaded_opaque(), 0, 1);
- EXPECT_NEAR(
- occluded.overdraw_metrics()->pixels_uploaded_translucent(), 330000, 1);
- EXPECT_EQ(3, occluded.overdraw_metrics()->tiles_culled_for_upload());
+ UpdateTextures();
layer->fake_layer_updater()->ClearUpdateCount();
layer->SetTexturePriorities(priority_calculator_);
@@ -1332,11 +1329,6 @@ TEST_F(TiledLayerTest, TilesNotPaintedWithoutInvalidation) {
// now.
layer->Update(queue_.get(), &occluded);
EXPECT_EQ(3, layer->fake_layer_updater()->update_count());
-
- EXPECT_NEAR(occluded.overdraw_metrics()->pixels_uploaded_opaque(), 0, 1);
- EXPECT_NEAR(
- occluded.overdraw_metrics()->pixels_uploaded_translucent(), 330000, 1);
- EXPECT_EQ(6, occluded.overdraw_metrics()->tiles_culled_for_upload());
}
TEST_F(TiledLayerTest, TilesPaintedWithOcclusionAndTransforms) {
@@ -1371,11 +1363,6 @@ TEST_F(TiledLayerTest, TilesPaintedWithOcclusionAndTransforms) {
layer->SavePaintProperties();
layer->Update(queue_.get(), &occluded);
EXPECT_EQ(36 - 3, layer->fake_layer_updater()->update_count());
-
- EXPECT_NEAR(occluded.overdraw_metrics()->pixels_uploaded_opaque(), 0, 1);
- EXPECT_NEAR(
- occluded.overdraw_metrics()->pixels_uploaded_translucent(), 330000, 1);
- EXPECT_EQ(3, occluded.overdraw_metrics()->tiles_culled_for_upload());
}
TEST_F(TiledLayerTest, TilesPaintedWithOcclusionAndScaling) {
@@ -1398,7 +1385,6 @@ TEST_F(TiledLayerTest, TilesPaintedWithOcclusionAndScaling) {
// This makes sure the painting works when the content space is scaled to
// a different layer space.
layer_tree_host_->SetViewportSize(gfx::Size(600, 600));
- layer->SetAnchorPoint(gfx::PointF());
layer->SetBounds(gfx::Size(300, 300));
scale_layer->AddChild(layer);
CalcDrawProps(&render_surface_layer_list);
@@ -1421,12 +1407,6 @@ TEST_F(TiledLayerTest, TilesPaintedWithOcclusionAndScaling) {
int visible_tiles1 = 6 * 6;
EXPECT_EQ(visible_tiles1, layer->fake_layer_updater()->update_count());
- EXPECT_NEAR(occluded.overdraw_metrics()->pixels_uploaded_opaque(), 0, 1);
- EXPECT_NEAR(occluded.overdraw_metrics()->pixels_uploaded_translucent(),
- visible_tiles1 * 100 * 100,
- 1);
- EXPECT_EQ(0, occluded.overdraw_metrics()->tiles_culled_for_upload());
-
layer->fake_layer_updater()->ClearUpdateCount();
// The occlusion of 300x100 will be cover 3 tiles as tiles are 100x100 still.
@@ -1443,13 +1423,6 @@ TEST_F(TiledLayerTest, TilesPaintedWithOcclusionAndScaling) {
int visible_tiles2 = 6 * 6 - 3;
EXPECT_EQ(visible_tiles2, layer->fake_layer_updater()->update_count());
- EXPECT_NEAR(occluded.overdraw_metrics()->pixels_uploaded_opaque(), 0, 1);
- EXPECT_NEAR(occluded.overdraw_metrics()->pixels_uploaded_translucent(),
- visible_tiles2 * 100 * 100 +
- visible_tiles1 * 100 * 100,
- 1);
- EXPECT_EQ(3, occluded.overdraw_metrics()->tiles_culled_for_upload());
-
layer->fake_layer_updater()->ClearUpdateCount();
// This makes sure content scaling and transforms work together.
@@ -1475,14 +1448,6 @@ TEST_F(TiledLayerTest, TilesPaintedWithOcclusionAndScaling) {
layer->Update(queue_.get(), &occluded);
int visible_tiles3 = 6 * 6 - 6;
EXPECT_EQ(visible_tiles3, layer->fake_layer_updater()->update_count());
-
- EXPECT_NEAR(occluded.overdraw_metrics()->pixels_uploaded_opaque(), 0, 1);
- EXPECT_NEAR(occluded.overdraw_metrics()->pixels_uploaded_translucent(),
- visible_tiles3 * 100 * 100 +
- visible_tiles2 * 100 * 100 +
- visible_tiles1 * 100 * 100,
- 1);
- EXPECT_EQ(6 + 3, occluded.overdraw_metrics()->tiles_culled_for_upload());
}
TEST_F(TiledLayerTest, VisibleContentOpaqueRegion) {
@@ -1520,12 +1485,6 @@ TEST_F(TiledLayerTest, VisibleContentOpaqueRegion) {
opaque_contents = layer->VisibleContentOpaqueRegion();
EXPECT_TRUE(opaque_contents.IsEmpty());
- EXPECT_NEAR(occluded.overdraw_metrics()->pixels_painted(), 20000, 1);
- EXPECT_NEAR(occluded.overdraw_metrics()->pixels_uploaded_opaque(), 0, 1);
- EXPECT_NEAR(
- occluded.overdraw_metrics()->pixels_uploaded_translucent(), 20000, 1);
- EXPECT_EQ(0, occluded.overdraw_metrics()->tiles_culled_for_upload());
-
// VisibleContentOpaqueRegion should match the visible part of what is painted
// opaque.
opaque_paint_rect = gfx::Rect(10, 10, 90, 190);
@@ -1540,13 +1499,6 @@ TEST_F(TiledLayerTest, VisibleContentOpaqueRegion) {
EXPECT_EQ(gfx::IntersectRects(opaque_paint_rect, visible_bounds).ToString(),
opaque_contents.ToString());
- EXPECT_NEAR(occluded.overdraw_metrics()->pixels_painted(), 20000 * 2, 1);
- EXPECT_NEAR(occluded.overdraw_metrics()->pixels_uploaded_opaque(), 17100, 1);
- EXPECT_NEAR(occluded.overdraw_metrics()->pixels_uploaded_translucent(),
- 20000 + 20000 - 17100,
- 1);
- EXPECT_EQ(0, occluded.overdraw_metrics()->tiles_culled_for_upload());
-
// If we paint again without invalidating, the same stuff should be opaque.
layer->fake_layer_updater()->SetOpaquePaintRect(gfx::Rect());
layer->SetTexturePriorities(priority_calculator_);
@@ -1558,13 +1510,6 @@ TEST_F(TiledLayerTest, VisibleContentOpaqueRegion) {
EXPECT_EQ(gfx::IntersectRects(opaque_paint_rect, visible_bounds).ToString(),
opaque_contents.ToString());
- EXPECT_NEAR(occluded.overdraw_metrics()->pixels_painted(), 20000 * 2, 1);
- EXPECT_NEAR(occluded.overdraw_metrics()->pixels_uploaded_opaque(), 17100, 1);
- EXPECT_NEAR(occluded.overdraw_metrics()->pixels_uploaded_translucent(),
- 20000 + 20000 - 17100,
- 1);
- EXPECT_EQ(0, occluded.overdraw_metrics()->tiles_culled_for_upload());
-
// If we repaint a non-opaque part of the tile, then it shouldn't lose its
// opaque-ness. And other tiles should not be affected.
layer->fake_layer_updater()->SetOpaquePaintRect(gfx::Rect());
@@ -1578,13 +1523,6 @@ TEST_F(TiledLayerTest, VisibleContentOpaqueRegion) {
EXPECT_EQ(gfx::IntersectRects(opaque_paint_rect, visible_bounds).ToString(),
opaque_contents.ToString());
- EXPECT_NEAR(occluded.overdraw_metrics()->pixels_painted(), 20000 * 2 + 1, 1);
- EXPECT_NEAR(occluded.overdraw_metrics()->pixels_uploaded_opaque(), 17100, 1);
- EXPECT_NEAR(occluded.overdraw_metrics()->pixels_uploaded_translucent(),
- 20000 + 20000 - 17100 + 1,
- 1);
- EXPECT_EQ(0, occluded.overdraw_metrics()->tiles_culled_for_upload());
-
// If we repaint an opaque part of the tile, then it should lose its
// opaque-ness. But other tiles should still not be affected.
layer->fake_layer_updater()->SetOpaquePaintRect(gfx::Rect());
@@ -1598,77 +1536,6 @@ TEST_F(TiledLayerTest, VisibleContentOpaqueRegion) {
EXPECT_EQ(gfx::IntersectRects(gfx::Rect(10, 100, 90, 100),
visible_bounds).ToString(),
opaque_contents.ToString());
-
- EXPECT_NEAR(
- occluded.overdraw_metrics()->pixels_painted(), 20000 * 2 + 1 + 1, 1);
- EXPECT_NEAR(occluded.overdraw_metrics()->pixels_uploaded_opaque(), 17100, 1);
- EXPECT_NEAR(occluded.overdraw_metrics()->pixels_uploaded_translucent(),
- 20000 + 20000 - 17100 + 1 + 1,
- 1);
- EXPECT_EQ(0, occluded.overdraw_metrics()->tiles_culled_for_upload());
-}
-
-TEST_F(TiledLayerTest, PixelsPaintedMetrics) {
- scoped_refptr<FakeTiledLayer> layer =
- make_scoped_refptr(new FakeTiledLayer(resource_manager_.get()));
- RenderSurfaceLayerList render_surface_layer_list;
- TestOcclusionTracker occluded;
- occlusion_ = &occluded;
- layer_tree_host_->SetViewportSize(gfx::Size(1000, 1000));
-
- layer_tree_host_->root_layer()->AddChild(layer);
-
- // The tile size is 100x100, so this invalidates and then paints two tiles in
- // various ways.
-
- gfx::Rect opaque_paint_rect;
- Region opaque_contents;
-
- gfx::Rect content_bounds = gfx::Rect(0, 0, 100, 300);
- layer->SetBounds(content_bounds.size());
- CalcDrawProps(&render_surface_layer_list);
-
- // Invalidates and paints the whole layer.
- layer->fake_layer_updater()->SetOpaquePaintRect(gfx::Rect());
- layer->InvalidateContentRect(content_bounds);
- layer->SetTexturePriorities(priority_calculator_);
- resource_manager_->PrioritizeTextures();
- layer->SavePaintProperties();
- layer->Update(queue_.get(), &occluded);
- UpdateTextures();
- opaque_contents = layer->VisibleContentOpaqueRegion();
- EXPECT_TRUE(opaque_contents.IsEmpty());
-
- EXPECT_NEAR(occluded.overdraw_metrics()->pixels_painted(), 30000, 1);
- EXPECT_NEAR(occluded.overdraw_metrics()->pixels_uploaded_opaque(), 0, 1);
- EXPECT_NEAR(
- occluded.overdraw_metrics()->pixels_uploaded_translucent(), 30000, 1);
- EXPECT_EQ(0, occluded.overdraw_metrics()->tiles_culled_for_upload());
-
- // Invalidates an area on the top and bottom tile, which will cause us to
- // paint the tile in the middle, even though it is not dirty and will not be
- // uploaded.
- layer->fake_layer_updater()->SetOpaquePaintRect(gfx::Rect());
- layer->InvalidateContentRect(gfx::Rect(0, 0, 1, 1));
- layer->InvalidateContentRect(gfx::Rect(50, 200, 10, 10));
- layer->SetTexturePriorities(priority_calculator_);
- resource_manager_->PrioritizeTextures();
- layer->SavePaintProperties();
- layer->Update(queue_.get(), &occluded);
- UpdateTextures();
- opaque_contents = layer->VisibleContentOpaqueRegion();
- EXPECT_TRUE(opaque_contents.IsEmpty());
-
- // The middle tile was painted even though not invalidated.
- EXPECT_NEAR(
- occluded.overdraw_metrics()->pixels_painted(), 30000 + 60 * 210, 1);
- // The pixels uploaded will not include the non-invalidated tile in the
- // middle.
- EXPECT_NEAR(occluded.overdraw_metrics()->pixels_uploaded_opaque(), 0, 1);
- EXPECT_NEAR(occluded.overdraw_metrics()->pixels_uploaded_translucent(),
- 30000 + 1 + 100,
- 1);
- EXPECT_EQ(0, occluded.overdraw_metrics()->tiles_culled_for_upload());
}
TEST_F(TiledLayerTest, DontAllocateContentsWhenTargetSurfaceCantBeAllocated) {
@@ -1686,25 +1553,21 @@ TEST_F(TiledLayerTest, DontAllocateContentsWhenTargetSurfaceCantBeAllocated) {
new FakeTiledLayer(layer_tree_host_->contents_texture_manager()));
root->SetBounds(root_rect.size());
- root->SetAnchorPoint(gfx::PointF());
root->draw_properties().drawable_content_rect = root_rect;
root->draw_properties().visible_content_rect = root_rect;
root->AddChild(surface);
surface->SetForceRenderSurface(true);
- surface->SetAnchorPoint(gfx::PointF());
surface->SetOpacity(0.5);
surface->AddChild(child);
surface->AddChild(child2);
child->SetBounds(child_rect.size());
- child->SetAnchorPoint(gfx::PointF());
child->SetPosition(child_rect.origin());
child->draw_properties().visible_content_rect = child_rect;
child->draw_properties().drawable_content_rect = root_rect;
child2->SetBounds(child2_rect.size());
- child2->SetAnchorPoint(gfx::PointF());
child2->SetPosition(child2_rect.origin());
child2->draw_properties().visible_content_rect = child2_rect;
child2->draw_properties().drawable_content_rect = root_rect;
@@ -1843,7 +1706,7 @@ class TrackingLayerPainter : public LayerPainter {
}
virtual void Paint(SkCanvas* canvas,
- gfx::Rect content_rect,
+ const gfx::Rect& content_rect,
gfx::RectF* opaque) OVERRIDE {
painted_rect_ = content_rect;
}
diff --git a/chromium/cc/layers/ui_resource_layer.cc b/chromium/cc/layers/ui_resource_layer.cc
index 09b8d9af4cc..b26ebaa6cce 100644
--- a/chromium/cc/layers/ui_resource_layer.cc
+++ b/chromium/cc/layers/ui_resource_layer.cc
@@ -72,7 +72,8 @@ scoped_ptr<LayerImpl> UIResourceLayer::CreateLayerImpl(
return UIResourceLayerImpl::Create(tree_impl, id()).PassAs<LayerImpl>();
}
-void UIResourceLayer::SetUV(gfx::PointF top_left, gfx::PointF bottom_right) {
+void UIResourceLayer::SetUV(const gfx::PointF& top_left,
+ const gfx::PointF& bottom_right) {
if (uv_top_left_ == top_left && uv_bottom_right_ == bottom_right)
return;
uv_top_left_ = top_left;
diff --git a/chromium/cc/layers/ui_resource_layer.h b/chromium/cc/layers/ui_resource_layer.h
index 69721a30faa..d99c073a6db 100644
--- a/chromium/cc/layers/ui_resource_layer.h
+++ b/chromium/cc/layers/ui_resource_layer.h
@@ -32,7 +32,7 @@ class CC_EXPORT UIResourceLayer : public Layer {
void SetUIResourceId(UIResourceId resource_id);
// Sets a UV transform to be used at draw time. Defaults to (0, 0) and (1, 1).
- void SetUV(gfx::PointF top_left, gfx::PointF bottom_right);
+ void SetUV(const gfx::PointF& top_left, const gfx::PointF& bottom_right);
// Sets an opacity value per vertex. It will be multiplied by the layer
// opacity value.
diff --git a/chromium/cc/layers/ui_resource_layer_impl.cc b/chromium/cc/layers/ui_resource_layer_impl.cc
index 2c9a28681ce..d2ec1e4f47e 100644
--- a/chromium/cc/layers/ui_resource_layer_impl.cc
+++ b/chromium/cc/layers/ui_resource_layer_impl.cc
@@ -49,7 +49,7 @@ void UIResourceLayerImpl::SetUIResourceId(UIResourceId uid) {
NoteLayerPropertyChanged();
}
-void UIResourceLayerImpl::SetImageBounds(gfx::Size image_bounds) {
+void UIResourceLayerImpl::SetImageBounds(const gfx::Size& image_bounds) {
// This check imposes an ordering on the call sequence. An UIResource must
// exist before SetImageBounds can be called.
DCHECK(ui_resource_id_);
@@ -62,8 +62,8 @@ void UIResourceLayerImpl::SetImageBounds(gfx::Size image_bounds) {
NoteLayerPropertyChanged();
}
-void UIResourceLayerImpl::SetUV(gfx::PointF top_left,
- gfx::PointF bottom_right) {
+void UIResourceLayerImpl::SetUV(const gfx::PointF& top_left,
+ const gfx::PointF& bottom_right) {
if (uv_top_left_ == top_left && uv_bottom_right_ == bottom_right)
return;
uv_top_left_ = top_left;
@@ -93,9 +93,11 @@ bool UIResourceLayerImpl::WillDraw(DrawMode draw_mode,
void UIResourceLayerImpl::AppendQuads(QuadSink* quad_sink,
AppendQuadsData* append_quads_data) {
- SharedQuadState* shared_quad_state =
- quad_sink->UseSharedQuadState(CreateSharedQuadState());
- AppendDebugBorderQuad(quad_sink, shared_quad_state, append_quads_data);
+ SharedQuadState* shared_quad_state = quad_sink->CreateSharedQuadState();
+ PopulateSharedQuadState(shared_quad_state);
+
+ AppendDebugBorderQuad(
+ quad_sink, content_bounds(), shared_quad_state, append_quads_data);
if (!ui_resource_id_)
return;
@@ -111,17 +113,21 @@ void UIResourceLayerImpl::AppendQuads(QuadSink* quad_sink,
DCHECK(!bounds().IsEmpty());
- gfx::Rect quad_rect(bounds());
-
bool opaque = layer_tree_impl()->IsUIResourceOpaque(ui_resource_id_) ||
contents_opaque();
+
+ gfx::Rect quad_rect(bounds());
gfx::Rect opaque_rect(opaque ? quad_rect : gfx::Rect());
- scoped_ptr<TextureDrawQuad> quad;
+ gfx::Rect visible_quad_rect = quad_sink->UnoccludedContentRect(
+ quad_rect, draw_properties().target_space_transform);
+ if (visible_quad_rect.IsEmpty())
+ return;
- quad = TextureDrawQuad::Create();
+ scoped_ptr<TextureDrawQuad> quad = TextureDrawQuad::Create();
quad->SetNew(shared_quad_state,
quad_rect,
opaque_rect,
+ visible_quad_rect,
resource,
premultiplied_alpha,
uv_top_left_,
@@ -129,7 +135,7 @@ void UIResourceLayerImpl::AppendQuads(QuadSink* quad_sink,
SK_ColorTRANSPARENT,
vertex_opacity_,
flipped);
- quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
+ quad_sink->Append(quad.PassAs<DrawQuad>());
}
const char* UIResourceLayerImpl::LayerTypeAsString() const {
diff --git a/chromium/cc/layers/ui_resource_layer_impl.h b/chromium/cc/layers/ui_resource_layer_impl.h
index 7f20050e99b..c61df47a232 100644
--- a/chromium/cc/layers/ui_resource_layer_impl.h
+++ b/chromium/cc/layers/ui_resource_layer_impl.h
@@ -30,10 +30,10 @@ class CC_EXPORT UIResourceLayerImpl : public LayerImpl {
void SetUIResourceId(UIResourceId uid);
- void SetImageBounds(gfx::Size image_bounds);
+ void SetImageBounds(const gfx::Size& image_bounds);
// Sets a UV transform to be used at draw time. Defaults to (0, 0) and (1, 1).
- void SetUV(gfx::PointF top_left, gfx::PointF bottom_right);
+ void SetUV(const gfx::PointF& top_left, const gfx::PointF& bottom_right);
// Sets an opacity value per vertex. It will be multiplied by the layer
// opacity value.
diff --git a/chromium/cc/layers/ui_resource_layer_impl_unittest.cc b/chromium/cc/layers/ui_resource_layer_impl_unittest.cc
index 4a2a1164182..cd0d7bf02f7 100644
--- a/chromium/cc/layers/ui_resource_layer_impl_unittest.cc
+++ b/chromium/cc/layers/ui_resource_layer_impl_unittest.cc
@@ -11,6 +11,7 @@
#include "cc/test/fake_ui_resource_layer_tree_host_impl.h"
#include "cc/test/layer_test_common.h"
#include "cc/test/mock_quad_culler.h"
+#include "cc/test/test_shared_bitmap_manager.h"
#include "cc/trees/single_thread_proxy.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -21,8 +22,8 @@ namespace {
scoped_ptr<UIResourceLayerImpl> GenerateUIResourceLayer(
FakeUIResourceLayerTreeHostImpl* host_impl,
- gfx::Size bitmap_size,
- gfx::Size layer_size,
+ const gfx::Size& bitmap_size,
+ const gfx::Size& layer_size,
bool opaque,
UIResourceId uid) {
gfx::Rect visible_content_rect(layer_size);
@@ -34,15 +35,7 @@ scoped_ptr<UIResourceLayerImpl> GenerateUIResourceLayer(
layer->CreateRenderSurface();
layer->draw_properties().render_target = layer.get();
- SkBitmap skbitmap;
- skbitmap.setConfig(SkBitmap::kARGB_8888_Config,
- bitmap_size.width(),
- bitmap_size.height(),
- 0,
- opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
- skbitmap.allocPixels();
- skbitmap.setImmutable();
- UIResourceBitmap bitmap(skbitmap);
+ UIResourceBitmap bitmap(bitmap_size, opaque);
host_impl->CreateUIResource(uid, bitmap);
layer->SetUIResourceId(uid);
@@ -52,7 +45,10 @@ scoped_ptr<UIResourceLayerImpl> GenerateUIResourceLayer(
void QuadSizeTest(scoped_ptr<UIResourceLayerImpl> layer,
size_t expected_quad_size) {
- MockQuadCuller quad_culler;
+ MockOcclusionTracker<LayerImpl> occlusion_tracker;
+ scoped_ptr<RenderPass> render_pass = RenderPass::Create();
+ MockQuadCuller quad_culler(render_pass.get(), &occlusion_tracker);
+
AppendQuadsData data;
layer->AppendQuads(&quad_culler, &data);
@@ -63,7 +59,8 @@ void QuadSizeTest(scoped_ptr<UIResourceLayerImpl> layer,
TEST(UIResourceLayerImplTest, VerifyDrawQuads) {
FakeImplProxy proxy;
- FakeUIResourceLayerTreeHostImpl host_impl(&proxy);
+ TestSharedBitmapManager shared_bitmap_manager;
+ FakeUIResourceLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
// Make sure we're appending quads when there are valid values.
gfx::Size bitmap_size(100, 100);
gfx::Size layer_size(100, 100);;
@@ -89,8 +86,11 @@ TEST(UIResourceLayerImplTest, VerifyDrawQuads) {
}
void OpaqueBoundsTest(scoped_ptr<UIResourceLayerImpl> layer,
- gfx::Rect expected_opaque_bounds) {
- MockQuadCuller quad_culler;
+ const gfx::Rect& expected_opaque_bounds) {
+ MockOcclusionTracker<LayerImpl> occlusion_tracker;
+ scoped_ptr<RenderPass> render_pass = RenderPass::Create();
+ MockQuadCuller quad_culler(render_pass.get(), &occlusion_tracker);
+
AppendQuadsData data;
layer->AppendQuads(&quad_culler, &data);
@@ -103,7 +103,8 @@ void OpaqueBoundsTest(scoped_ptr<UIResourceLayerImpl> layer,
TEST(UIResourceLayerImplTest, VerifySetOpaqueOnSkBitmap) {
FakeImplProxy proxy;
- FakeUIResourceLayerTreeHostImpl host_impl(&proxy);
+ TestSharedBitmapManager shared_bitmap_manager;
+ FakeUIResourceLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
gfx::Size bitmap_size(100, 100);
gfx::Size layer_size(100, 100);;
@@ -129,7 +130,8 @@ TEST(UIResourceLayerImplTest, VerifySetOpaqueOnSkBitmap) {
TEST(UIResourceLayerImplTest, VerifySetOpaqueOnLayer) {
FakeImplProxy proxy;
- FakeUIResourceLayerTreeHostImpl host_impl(&proxy);
+ TestSharedBitmapManager shared_bitmap_manager;
+ FakeUIResourceLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
gfx::Size bitmap_size(100, 100);
gfx::Size layer_size(100, 100);
@@ -148,5 +150,63 @@ TEST(UIResourceLayerImplTest, VerifySetOpaqueOnLayer) {
OpaqueBoundsTest(layer.Pass(), expected_opaque_bounds);
}
+TEST(UIResourceLayerImplTest, Occlusion) {
+ gfx::Size layer_size(1000, 1000);
+ gfx::Size viewport_size(1000, 1000);
+
+ LayerTestCommon::LayerImplTest impl;
+
+ SkBitmap sk_bitmap;
+ sk_bitmap.allocN32Pixels(10, 10);
+ sk_bitmap.setImmutable();
+ UIResourceId uid = 5;
+ UIResourceBitmap bitmap(sk_bitmap);
+ impl.host_impl()->CreateUIResource(uid, bitmap);
+
+ UIResourceLayerImpl* ui_resource_layer_impl =
+ impl.AddChildToRoot<UIResourceLayerImpl>();
+ ui_resource_layer_impl->SetBounds(layer_size);
+ ui_resource_layer_impl->SetContentBounds(layer_size);
+ ui_resource_layer_impl->SetDrawsContent(true);
+ ui_resource_layer_impl->SetUIResourceId(uid);
+
+ impl.CalcDrawProps(viewport_size);
+
+ {
+ SCOPED_TRACE("No occlusion");
+ gfx::Rect occluded;
+ impl.AppendQuadsWithOcclusion(ui_resource_layer_impl, occluded);
+
+ LayerTestCommon::VerifyQuadsExactlyCoverRect(impl.quad_list(),
+ gfx::Rect(layer_size));
+ EXPECT_EQ(1u, impl.quad_list().size());
+ }
+
+ {
+ SCOPED_TRACE("Full occlusion");
+ gfx::Rect occluded(ui_resource_layer_impl->visible_content_rect());
+ impl.AppendQuadsWithOcclusion(ui_resource_layer_impl, occluded);
+
+ LayerTestCommon::VerifyQuadsExactlyCoverRect(impl.quad_list(), gfx::Rect());
+ EXPECT_EQ(impl.quad_list().size(), 0u);
+ }
+
+ {
+ SCOPED_TRACE("Partial occlusion");
+ gfx::Rect occluded(200, 0, 800, 1000);
+ impl.AppendQuadsWithOcclusion(ui_resource_layer_impl, occluded);
+
+ size_t partially_occluded_count = 0;
+ LayerTestCommon::VerifyQuadsCoverRectWithOcclusion(
+ impl.quad_list(),
+ gfx::Rect(layer_size),
+ occluded,
+ &partially_occluded_count);
+ // The layer outputs one quad, which is partially occluded.
+ EXPECT_EQ(1u, impl.quad_list().size());
+ EXPECT_EQ(1u, partially_occluded_count);
+ }
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/layers/ui_resource_layer_unittest.cc b/chromium/cc/layers/ui_resource_layer_unittest.cc
index 48dbdf58f71..25cc2c74332 100644
--- a/chromium/cc/layers/ui_resource_layer_unittest.cc
+++ b/chromium/cc/layers/ui_resource_layer_unittest.cc
@@ -4,12 +4,10 @@
#include "cc/layers/ui_resource_layer.h"
-#include "cc/debug/overdraw_metrics.h"
#include "cc/resources/prioritized_resource_manager.h"
#include "cc/resources/resource_provider.h"
#include "cc/resources/resource_update_queue.h"
#include "cc/resources/scoped_ui_resource.h"
-#include "cc/scheduler/texture_uploader.h"
#include "cc/test/fake_layer_tree_host.h"
#include "cc/test/fake_layer_tree_host_client.h"
#include "cc/test/fake_output_surface.h"
@@ -58,18 +56,16 @@ TEST_F(UIResourceLayerTest, SetBitmap) {
Mock::VerifyAndClearExpectations(layer_tree_host_.get());
EXPECT_EQ(test_layer->layer_tree_host(), layer_tree_host_.get());
- layer_tree_host_->InitializeOutputSurfaceIfNeeded();
-
ResourceUpdateQueue queue;
- OcclusionTracker occlusion_tracker(gfx::Rect(), false);
+ gfx::Rect screen_space_clip_rect;
+ OcclusionTracker<Layer> occlusion_tracker(screen_space_clip_rect);
test_layer->SavePaintProperties();
test_layer->Update(&queue, &occlusion_tracker);
EXPECT_FALSE(test_layer->DrawsContent());
SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, 10, 10);
- bitmap.allocPixels();
+ bitmap.allocN32Pixels(10, 10);
bitmap.setImmutable();
test_layer->SetBitmap(bitmap);
@@ -88,22 +84,17 @@ TEST_F(UIResourceLayerTest, SetUIResourceId) {
Mock::VerifyAndClearExpectations(layer_tree_host_.get());
EXPECT_EQ(test_layer->layer_tree_host(), layer_tree_host_.get());
- layer_tree_host_->InitializeOutputSurfaceIfNeeded();
-
ResourceUpdateQueue queue;
- OcclusionTracker occlusion_tracker(gfx::Rect(), false);
+ gfx::Rect screen_space_clip_rect;
+ OcclusionTracker<Layer> occlusion_tracker(screen_space_clip_rect);
test_layer->SavePaintProperties();
test_layer->Update(&queue, &occlusion_tracker);
EXPECT_FALSE(test_layer->DrawsContent());
- SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, 10, 10);
- bitmap.allocPixels();
- bitmap.setImmutable();
-
+ bool is_opaque = false;
scoped_ptr<ScopedUIResource> resource = ScopedUIResource::Create(
- layer_tree_host_.get(), UIResourceBitmap(bitmap));
+ layer_tree_host_.get(), UIResourceBitmap(gfx::Size(10, 10), is_opaque));
test_layer->SetUIResourceId(resource->id());
test_layer->Update(&queue, &occlusion_tracker);
diff --git a/chromium/cc/layers/video_frame_provider_client_impl.cc b/chromium/cc/layers/video_frame_provider_client_impl.cc
index 732bbbb1d0a..cf78413f679 100644
--- a/chromium/cc/layers/video_frame_provider_client_impl.cc
+++ b/chromium/cc/layers/video_frame_provider_client_impl.cc
@@ -4,6 +4,7 @@
#include "cc/layers/video_frame_provider_client_impl.h"
+#include "base/debug/trace_event.h"
#include "cc/base/math_util.h"
#include "cc/layers/video_layer_impl.h"
#include "media/base/video_frame.h"
@@ -22,7 +23,7 @@ VideoFrameProviderClientImpl::~VideoFrameProviderClientImpl() {}
VideoFrameProviderClientImpl::VideoFrameProviderClientImpl(
VideoFrameProvider* provider)
- : provider_(provider) {
+ : active_video_layer_(NULL), provider_(provider) {
// This only happens during a commit on the compositor thread while the main
// thread is blocked. That makes this a thread-safe call to set the video
// frame provider client that does not require a lock. The same is true of
@@ -73,6 +74,10 @@ void VideoFrameProviderClientImpl::StopUsingProvider() {
}
void VideoFrameProviderClientImpl::DidReceiveFrame() {
+ TRACE_EVENT1("cc",
+ "VideoFrameProviderClientImpl::DidReceiveFrame",
+ "active_video_layer",
+ !!active_video_layer_);
if (active_video_layer_)
active_video_layer_->SetNeedsRedraw();
}
diff --git a/chromium/cc/layers/video_frame_provider_client_impl.h b/chromium/cc/layers/video_frame_provider_client_impl.h
index 2bcb4462b73..e676d0b81d2 100644
--- a/chromium/cc/layers/video_frame_provider_client_impl.h
+++ b/chromium/cc/layers/video_frame_provider_client_impl.h
@@ -22,6 +22,7 @@ class VideoFrameProviderClientImpl
static scoped_refptr<VideoFrameProviderClientImpl> Create(
VideoFrameProvider* provider);
+ VideoLayerImpl* active_video_layer() { return active_video_layer_; }
void set_active_video_layer(VideoLayerImpl* video_layer) {
active_video_layer_ = video_layer;
}
diff --git a/chromium/cc/layers/video_layer.cc b/chromium/cc/layers/video_layer.cc
index 8d728e0a8e0..4ddfdae69a6 100644
--- a/chromium/cc/layers/video_layer.cc
+++ b/chromium/cc/layers/video_layer.cc
@@ -23,7 +23,7 @@ scoped_ptr<LayerImpl> VideoLayer::CreateLayerImpl(LayerTreeImpl* tree_impl) {
}
bool VideoLayer::Update(ResourceUpdateQueue* queue,
- const OcclusionTracker* occlusion) {
+ const OcclusionTracker<Layer>* occlusion) {
bool updated = Layer::Update(queue, occlusion);
// Video layer doesn't update any resources from the main thread side,
diff --git a/chromium/cc/layers/video_layer.h b/chromium/cc/layers/video_layer.h
index 4d14f80dd4c..dd2c4e149ff 100644
--- a/chromium/cc/layers/video_layer.h
+++ b/chromium/cc/layers/video_layer.h
@@ -25,7 +25,8 @@ class CC_EXPORT VideoLayer : public Layer {
OVERRIDE;
virtual bool Update(ResourceUpdateQueue* queue,
- const OcclusionTracker* occlusion) OVERRIDE;
+ const OcclusionTracker<Layer>* occlusion) OVERRIDE;
+
private:
explicit VideoLayer(VideoFrameProvider* provider);
virtual ~VideoLayer();
diff --git a/chromium/cc/layers/video_layer_impl.cc b/chromium/cc/layers/video_layer_impl.cc
index 314fed624ca..4abf85b9630 100644
--- a/chromium/cc/layers/video_layer_impl.cc
+++ b/chromium/cc/layers/video_layer_impl.cc
@@ -128,20 +128,31 @@ void VideoLayerImpl::AppendQuads(QuadSink* quad_sink,
AppendQuadsData* append_quads_data) {
DCHECK(frame_.get());
- SharedQuadState* shared_quad_state =
- quad_sink->UseSharedQuadState(CreateSharedQuadState());
- AppendDebugBorderQuad(quad_sink, shared_quad_state, append_quads_data);
+ SharedQuadState* shared_quad_state = quad_sink->CreateSharedQuadState();
+ PopulateSharedQuadState(shared_quad_state);
+
+ AppendDebugBorderQuad(
+ quad_sink, content_bounds(), shared_quad_state, append_quads_data);
gfx::Rect quad_rect(content_bounds());
gfx::Rect opaque_rect(contents_opaque() ? quad_rect : gfx::Rect());
gfx::Rect visible_rect = frame_->visible_rect();
gfx::Size coded_size = frame_->coded_size();
+ gfx::Rect visible_quad_rect = quad_sink->UnoccludedContentRect(
+ quad_rect, draw_properties().target_space_transform);
+ if (visible_quad_rect.IsEmpty())
+ return;
+
// Pixels for macroblocked formats.
- float tex_width_scale =
+ const float tex_width_scale =
static_cast<float>(visible_rect.width()) / coded_size.width();
- float tex_height_scale =
+ const float tex_height_scale =
static_cast<float>(visible_rect.height()) / coded_size.height();
+ const float tex_x_offset =
+ static_cast<float>(visible_rect.x()) / coded_size.width();
+ const float tex_y_offset =
+ static_cast<float>(visible_rect.y()) / coded_size.height();
switch (frame_resource_type_) {
// TODO(danakj): Remove this, hide it in the hardware path.
@@ -159,6 +170,7 @@ void VideoLayerImpl::AppendQuads(QuadSink* quad_sink,
texture_quad->SetNew(shared_quad_state,
quad_rect,
opaque_rect,
+ visible_quad_rect,
software_resources_[0],
premultiplied_alpha,
uv_top_left,
@@ -166,25 +178,32 @@ void VideoLayerImpl::AppendQuads(QuadSink* quad_sink,
SK_ColorTRANSPARENT,
opacity,
flipped);
- quad_sink->Append(texture_quad.PassAs<DrawQuad>(), append_quads_data);
+ quad_sink->Append(texture_quad.PassAs<DrawQuad>());
break;
}
case VideoFrameExternalResources::YUV_RESOURCE: {
DCHECK_GE(frame_resources_.size(), 3u);
if (frame_resources_.size() < 3u)
break;
- gfx::SizeF tex_scale(tex_width_scale, tex_height_scale);
+ YUVVideoDrawQuad::ColorSpace color_space =
+ frame_->format() == media::VideoFrame::YV12J
+ ? YUVVideoDrawQuad::REC_601_JPEG
+ : YUVVideoDrawQuad::REC_601;
+ gfx::RectF tex_coord_rect(
+ tex_x_offset, tex_y_offset, tex_width_scale, tex_height_scale);
scoped_ptr<YUVVideoDrawQuad> yuv_video_quad = YUVVideoDrawQuad::Create();
- yuv_video_quad->SetNew(shared_quad_state,
- quad_rect,
- opaque_rect,
- tex_scale,
- frame_resources_[0],
- frame_resources_[1],
- frame_resources_[2],
- frame_resources_.size() > 3 ?
- frame_resources_[3] : 0);
- quad_sink->Append(yuv_video_quad.PassAs<DrawQuad>(), append_quads_data);
+ yuv_video_quad->SetNew(
+ shared_quad_state,
+ quad_rect,
+ opaque_rect,
+ visible_quad_rect,
+ tex_coord_rect,
+ frame_resources_[0],
+ frame_resources_[1],
+ frame_resources_[2],
+ frame_resources_.size() > 3 ? frame_resources_[3] : 0,
+ color_space);
+ quad_sink->Append(yuv_video_quad.PassAs<DrawQuad>());
break;
}
case VideoFrameExternalResources::RGB_RESOURCE: {
@@ -200,6 +219,7 @@ void VideoLayerImpl::AppendQuads(QuadSink* quad_sink,
texture_quad->SetNew(shared_quad_state,
quad_rect,
opaque_rect,
+ visible_quad_rect,
frame_resources_[0],
premultiplied_alpha,
uv_top_left,
@@ -207,7 +227,7 @@ void VideoLayerImpl::AppendQuads(QuadSink* quad_sink,
SK_ColorTRANSPARENT,
opacity,
flipped);
- quad_sink->Append(texture_quad.PassAs<DrawQuad>(), append_quads_data);
+ quad_sink->Append(texture_quad.PassAs<DrawQuad>());
break;
}
case VideoFrameExternalResources::STREAM_TEXTURE_RESOURCE: {
@@ -222,27 +242,26 @@ void VideoLayerImpl::AppendQuads(QuadSink* quad_sink,
shared_quad_state,
quad_rect,
opaque_rect,
+ visible_quad_rect,
frame_resources_[0],
scale * provider_client_impl_->stream_texture_matrix());
- quad_sink->Append(stream_video_quad.PassAs<DrawQuad>(),
- append_quads_data);
+ quad_sink->Append(stream_video_quad.PassAs<DrawQuad>());
break;
}
case VideoFrameExternalResources::IO_SURFACE: {
DCHECK_EQ(frame_resources_.size(), 1u);
if (frame_resources_.size() < 1u)
break;
- gfx::Size visible_size(visible_rect.width(), visible_rect.height());
scoped_ptr<IOSurfaceDrawQuad> io_surface_quad =
IOSurfaceDrawQuad::Create();
io_surface_quad->SetNew(shared_quad_state,
quad_rect,
opaque_rect,
- visible_size,
+ visible_quad_rect,
+ visible_rect.size(),
frame_resources_[0],
IOSurfaceDrawQuad::UNFLIPPED);
- quad_sink->Append(io_surface_quad.PassAs<DrawQuad>(),
- append_quads_data);
+ quad_sink->Append(io_surface_quad.PassAs<DrawQuad>());
break;
}
#if defined(VIDEO_HOLE)
@@ -259,11 +278,15 @@ void VideoLayerImpl::AppendQuads(QuadSink* quad_sink,
// Create a solid color quad with transparent black and force no
// blending / no anti-aliasing.
- solid_color_draw_quad->SetAll(
- shared_quad_state, quad_rect, quad_rect, quad_rect, false,
- SK_ColorTRANSPARENT, true);
- quad_sink->Append(solid_color_draw_quad.PassAs<DrawQuad>(),
- append_quads_data);
+ gfx::Rect opaque_rect = quad_rect;
+ solid_color_draw_quad->SetAll(shared_quad_state,
+ quad_rect,
+ opaque_rect,
+ visible_quad_rect,
+ false,
+ SK_ColorTRANSPARENT,
+ true);
+ quad_sink->Append(solid_color_draw_quad.PassAs<DrawQuad>());
break;
}
#endif // defined(VIDEO_HOLE)
@@ -297,12 +320,12 @@ void VideoLayerImpl::DidDraw(ResourceProvider* resource_provider) {
provider_client_impl_->ReleaseLock();
}
-void VideoLayerImpl::DidLoseOutputSurface() {
+void VideoLayerImpl::ReleaseResources() {
updater_.reset();
}
void VideoLayerImpl::SetNeedsRedraw() {
- set_update_rect(gfx::UnionRects(update_rect(), gfx::RectF(bounds())));
+ SetUpdateRect(gfx::UnionRects(update_rect(), gfx::RectF(bounds())));
layer_tree_impl()->SetNeedsRedraw();
}
diff --git a/chromium/cc/layers/video_layer_impl.h b/chromium/cc/layers/video_layer_impl.h
index b4df1417bf1..f8df7cbd2f3 100644
--- a/chromium/cc/layers/video_layer_impl.h
+++ b/chromium/cc/layers/video_layer_impl.h
@@ -37,7 +37,7 @@ class CC_EXPORT VideoLayerImpl : public LayerImpl {
AppendQuadsData* append_quads_data) OVERRIDE;
virtual void DidDraw(ResourceProvider* resource_provider) OVERRIDE;
virtual void DidBecomeActive() OVERRIDE;
- virtual void DidLoseOutputSurface() OVERRIDE;
+ virtual void ReleaseResources() OVERRIDE;
void SetNeedsRedraw();
diff --git a/chromium/cc/layers/video_layer_impl_unittest.cc b/chromium/cc/layers/video_layer_impl_unittest.cc
new file mode 100644
index 00000000000..7a17eefd094
--- /dev/null
+++ b/chromium/cc/layers/video_layer_impl_unittest.cc
@@ -0,0 +1,97 @@
+// 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/layers/video_layer_impl.h"
+
+#include "cc/layers/video_frame_provider_client_impl.h"
+#include "cc/output/context_provider.h"
+#include "cc/output/output_surface.h"
+#include "cc/test/fake_video_frame_provider.h"
+#include "cc/test/layer_test_common.h"
+#include "cc/trees/single_thread_proxy.h"
+#include "media/base/video_frame.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+namespace {
+
+TEST(VideoLayerImplTest, Occlusion) {
+ gfx::Size layer_size(1000, 1000);
+ gfx::Size viewport_size(1000, 1000);
+
+ LayerTestCommon::LayerImplTest impl;
+ DebugScopedSetImplThreadAndMainThreadBlocked thread(impl.proxy());
+
+ scoped_refptr<media::VideoFrame> video_frame =
+ media::VideoFrame::CreateFrame(media::VideoFrame::YV12,
+ gfx::Size(10, 10),
+ gfx::Rect(10, 10),
+ gfx::Size(10, 10),
+ base::TimeDelta());
+ FakeVideoFrameProvider provider;
+ provider.set_frame(video_frame);
+
+ VideoLayerImpl* video_layer_impl =
+ impl.AddChildToRoot<VideoLayerImpl>(&provider);
+ video_layer_impl->SetBounds(layer_size);
+ video_layer_impl->SetContentBounds(layer_size);
+ video_layer_impl->SetDrawsContent(true);
+
+ impl.CalcDrawProps(viewport_size);
+
+ {
+ SCOPED_TRACE("No occlusion");
+ gfx::Rect occluded;
+ impl.AppendQuadsWithOcclusion(video_layer_impl, occluded);
+
+ LayerTestCommon::VerifyQuadsExactlyCoverRect(impl.quad_list(),
+ gfx::Rect(layer_size));
+ EXPECT_EQ(1u, impl.quad_list().size());
+ }
+
+ {
+ SCOPED_TRACE("Full occlusion");
+ gfx::Rect occluded(video_layer_impl->visible_content_rect());
+ impl.AppendQuadsWithOcclusion(video_layer_impl, occluded);
+
+ LayerTestCommon::VerifyQuadsExactlyCoverRect(impl.quad_list(), gfx::Rect());
+ EXPECT_EQ(impl.quad_list().size(), 0u);
+ }
+
+ {
+ SCOPED_TRACE("Partial occlusion");
+ gfx::Rect occluded(200, 0, 800, 1000);
+ impl.AppendQuadsWithOcclusion(video_layer_impl, occluded);
+
+ size_t partially_occluded_count = 0;
+ LayerTestCommon::VerifyQuadsCoverRectWithOcclusion(
+ impl.quad_list(),
+ gfx::Rect(layer_size),
+ occluded,
+ &partially_occluded_count);
+ // The layer outputs one quad, which is partially occluded.
+ EXPECT_EQ(1u, impl.quad_list().size());
+ EXPECT_EQ(1u, partially_occluded_count);
+ }
+}
+
+TEST(VideoLayerImplTest, DidBecomeActiveShouldSetActiveVideoLayer) {
+ LayerTestCommon::LayerImplTest impl;
+ DebugScopedSetImplThreadAndMainThreadBlocked thread(impl.proxy());
+
+ FakeVideoFrameProvider provider;
+ VideoLayerImpl* video_layer_impl =
+ impl.AddChildToRoot<VideoLayerImpl>(&provider);
+
+ VideoFrameProviderClientImpl* client =
+ static_cast<VideoFrameProviderClientImpl*>(provider.client());
+ ASSERT_TRUE(client);
+ EXPECT_FALSE(client->active_video_layer());
+
+ video_layer_impl->DidBecomeActive();
+ EXPECT_EQ(video_layer_impl, client->active_video_layer());
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/output/begin_frame_args.cc b/chromium/cc/output/begin_frame_args.cc
index 92901afb1f3..065cadd3726 100644
--- a/chromium/cc/output/begin_frame_args.cc
+++ b/chromium/cc/output/begin_frame_args.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/json/json_writer.h"
#include "cc/output/begin_frame_args.h"
#include "ui/gfx/frame_time.h"
@@ -27,26 +28,22 @@ BeginFrameArgs BeginFrameArgs::Create(base::TimeTicks frame_time,
return BeginFrameArgs(frame_time, deadline, interval);
}
-BeginFrameArgs BeginFrameArgs::CreateForSynchronousCompositor() {
- // For WebView/SynchronousCompositor, we always want to draw immediately,
- // so we set the deadline to 0 and guess that the interval is 16 milliseconds.
- return BeginFrameArgs(gfx::FrameTime::Now(),
- base::TimeTicks(),
- DefaultInterval());
-}
-
-BeginFrameArgs BeginFrameArgs::CreateForTesting() {
- base::TimeTicks now = gfx::FrameTime::Now();
- return BeginFrameArgs(now,
- now + (DefaultInterval() / 2),
- DefaultInterval());
+scoped_ptr<base::Value> BeginFrameArgs::AsValue() const {
+ scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue);
+ state->SetString("type", "BeginFrameArgs");
+ state->SetDouble("frame_time_us", frame_time.ToInternalValue());
+ state->SetDouble("deadline_us", deadline.ToInternalValue());
+ state->SetDouble("interval_us", interval.InMicroseconds());
+ return state.PassAs<base::Value>();
}
-BeginFrameArgs BeginFrameArgs::CreateExpiredForTesting() {
- base::TimeTicks now = gfx::FrameTime::Now();
- return BeginFrameArgs(now,
- now - DefaultInterval(),
- DefaultInterval());
+BeginFrameArgs BeginFrameArgs::CreateForSynchronousCompositor(
+ base::TimeTicks now) {
+ // For WebView/SynchronousCompositor, we always want to draw immediately,
+ // so we set the deadline to 0 and guess that the interval is 16 milliseconds.
+ if (now.is_null())
+ now = gfx::FrameTime::Now();
+ return BeginFrameArgs(now, base::TimeTicks(), DefaultInterval());
}
// This is a hard-coded deadline adjustment that assumes 60Hz, to be used in
@@ -55,8 +52,8 @@ BeginFrameArgs BeginFrameArgs::CreateExpiredForTesting() {
// produce output, the Renderer Impl thread the middle 1/3 of a frame to produce
// ouput, and the Renderer Main thread the first 1/3 of a frame to produce
// output.
-base::TimeDelta BeginFrameArgs::DefaultDeadlineAdjustment() {
- return base::TimeDelta::FromMicroseconds(-16666 / 3);
+base::TimeDelta BeginFrameArgs::DefaultEstimatedParentDrawTime() {
+ return base::TimeDelta::FromMicroseconds(16666 / 3);
}
base::TimeDelta BeginFrameArgs::DefaultInterval() {
diff --git a/chromium/cc/output/begin_frame_args.h b/chromium/cc/output/begin_frame_args.h
index 025a4075c25..91ad182ce0b 100644
--- a/chromium/cc/output/begin_frame_args.h
+++ b/chromium/cc/output/begin_frame_args.h
@@ -6,6 +6,7 @@
#define CC_OUTPUT_BEGIN_FRAME_ARGS_H_
#include "base/time/time.h"
+#include "base/values.h"
#include "cc/base/cc_export.h"
namespace cc {
@@ -19,13 +20,12 @@ struct CC_EXPORT BeginFrameArgs {
static BeginFrameArgs Create(base::TimeTicks frame_time,
base::TimeTicks deadline,
base::TimeDelta interval);
- static BeginFrameArgs CreateForSynchronousCompositor();
- static BeginFrameArgs CreateForTesting();
- static BeginFrameArgs CreateExpiredForTesting();
+ static BeginFrameArgs CreateForSynchronousCompositor(
+ base::TimeTicks now = base::TimeTicks());
// This is the default delta that will be used to adjust the deadline when
// proper draw-time estimations are not yet available.
- static base::TimeDelta DefaultDeadlineAdjustment();
+ static base::TimeDelta DefaultEstimatedParentDrawTime();
// This is the default interval to use to avoid sprinkling the code with
// magic numbers.
@@ -39,6 +39,8 @@ struct CC_EXPORT BeginFrameArgs {
bool IsValid() const { return interval >= base::TimeDelta(); }
+ scoped_ptr<base::Value> AsValue() const;
+
base::TimeTicks frame_time;
base::TimeTicks deadline;
base::TimeDelta interval;
diff --git a/chromium/cc/output/begin_frame_args_unittest.cc b/chromium/cc/output/begin_frame_args_unittest.cc
new file mode 100644
index 00000000000..e0c8b3efd34
--- /dev/null
+++ b/chromium/cc/output/begin_frame_args_unittest.cc
@@ -0,0 +1,77 @@
+// 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 <string>
+
+#include "cc/output/begin_frame_args.h"
+#include "cc/test/begin_frame_args_test.h"
+#include "testing/gtest/include/gtest/gtest-spi.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/frame_time.h"
+
+namespace cc {
+namespace {
+
+TEST(BeginFrameArgsTest, Helpers) {
+ // Quick create methods work
+ BeginFrameArgs args0 = CreateBeginFrameArgsForTesting();
+ EXPECT_TRUE(args0.IsValid()) << args0;
+
+ BeginFrameArgs args1 = CreateBeginFrameArgsForTesting(0, 0, -1);
+ EXPECT_FALSE(args1.IsValid()) << args1;
+
+ BeginFrameArgs args2 = CreateBeginFrameArgsForTesting(1, 2, 3);
+ EXPECT_TRUE(args2.IsValid()) << args2;
+ EXPECT_EQ(1, args2.frame_time.ToInternalValue());
+ EXPECT_EQ(2, args2.deadline.ToInternalValue());
+ EXPECT_EQ(3, args2.interval.ToInternalValue());
+
+ BeginFrameArgs args3 = CreateExpiredBeginFrameArgsForTesting();
+ EXPECT_TRUE(args3.IsValid()) << args3;
+ EXPECT_GT(gfx::FrameTime::Now(), args3.deadline);
+
+ // operator==
+ EXPECT_EQ(CreateBeginFrameArgsForTesting(4, 5, 6),
+ CreateBeginFrameArgsForTesting(4, 5, 6));
+
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(CreateBeginFrameArgsForTesting(4, 5, 6),
+ CreateBeginFrameArgsForTesting(7, 8, 9)),
+ "");
+
+ // operator<<
+ std::stringstream out1;
+ out1 << args1;
+ EXPECT_EQ("BeginFrameArgs(0, 0, -1us)", out1.str());
+ std::stringstream out2;
+ out2 << args2;
+ EXPECT_EQ("BeginFrameArgs(1, 2, 3us)", out2.str());
+
+ // PrintTo
+ EXPECT_EQ(std::string("BeginFrameArgs(0, 0, -1us)"),
+ ::testing::PrintToString(args1));
+ EXPECT_EQ(std::string("BeginFrameArgs(1, 2, 3us)"),
+ ::testing::PrintToString(args2));
+}
+
+TEST(BeginFrameArgsTest, Create) {
+ // BeginFrames are not valid by default
+ BeginFrameArgs args1;
+ EXPECT_FALSE(args1.IsValid()) << args1;
+
+ BeginFrameArgs args2 =
+ BeginFrameArgs::Create(base::TimeTicks::FromInternalValue(1),
+ base::TimeTicks::FromInternalValue(2),
+ base::TimeDelta::FromInternalValue(3));
+ EXPECT_TRUE(args2.IsValid()) << args2;
+ EXPECT_EQ(1, args2.frame_time.ToInternalValue()) << args2;
+ EXPECT_EQ(2, args2.deadline.ToInternalValue()) << args2;
+ EXPECT_EQ(3, args2.interval.ToInternalValue()) << args2;
+
+ base::TimeTicks now = base::TimeTicks::FromInternalValue(1);
+ EXPECT_EQ(CreateBeginFrameArgsForTesting(1, 0, 16666),
+ BeginFrameArgs::CreateForSynchronousCompositor(now));
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/output/compositor_frame_metadata.h b/chromium/cc/output/compositor_frame_metadata.h
index c084151643b..54c3ce61a0f 100644
--- a/chromium/cc/output/compositor_frame_metadata.h
+++ b/chromium/cc/output/compositor_frame_metadata.h
@@ -5,6 +5,8 @@
#ifndef CC_OUTPUT_COMPOSITOR_FRAME_METADATA_H_
#define CC_OUTPUT_COMPOSITOR_FRAME_METADATA_H_
+#include <vector>
+
#include "cc/base/cc_export.h"
#include "ui/events/latency_info.h"
#include "ui/gfx/size_f.h"
@@ -38,7 +40,7 @@ class CC_EXPORT CompositorFrameMetadata {
gfx::Vector2dF location_bar_content_translation;
float overdraw_bottom_height;
- ui::LatencyInfo latency_info;
+ std::vector<ui::LatencyInfo> latency_info;
};
} // namespace cc
diff --git a/chromium/cc/output/context_provider.cc b/chromium/cc/output/context_provider.cc
index 11b4bc5d889..23a8e2c8fd3 100644
--- a/chromium/cc/output/context_provider.cc
+++ b/chromium/cc/output/context_provider.cc
@@ -9,32 +9,6 @@
namespace cc {
ContextProvider::Capabilities::Capabilities()
- : egl_image_external(false),
- fast_npot_mo8_textures(false),
- iosurface(false),
- map_image(false),
- post_sub_buffer(false),
- texture_format_bgra8888(false),
- texture_format_etc1(false),
- texture_rectangle(false),
- texture_storage(false),
- texture_usage(false),
- discard_framebuffer(false),
- max_transfer_buffer_usage_bytes(std::numeric_limits<size_t>::max()) {}
-
-ContextProvider::Capabilities::Capabilities(
- const gpu::Capabilities& gpu_capabilities)
- : egl_image_external(gpu_capabilities.egl_image_external),
- fast_npot_mo8_textures(gpu_capabilities.fast_npot_mo8_textures),
- iosurface(gpu_capabilities.iosurface),
- map_image(gpu_capabilities.map_image),
- post_sub_buffer(gpu_capabilities.post_sub_buffer),
- texture_format_bgra8888(gpu_capabilities.texture_format_bgra8888),
- texture_format_etc1(gpu_capabilities.texture_format_etc1),
- texture_rectangle(gpu_capabilities.texture_rectangle),
- texture_storage(gpu_capabilities.texture_storage),
- texture_usage(gpu_capabilities.texture_usage),
- discard_framebuffer(gpu_capabilities.discard_framebuffer),
- max_transfer_buffer_usage_bytes(std::numeric_limits<size_t>::max()) {}
+ : max_transfer_buffer_usage_bytes(std::numeric_limits<size_t>::max()) {}
} // namespace cc
diff --git a/chromium/cc/output/context_provider.h b/chromium/cc/output/context_provider.h
index 0b6d48232c6..7362e8b55aa 100644
--- a/chromium/cc/output/context_provider.h
+++ b/chromium/cc/output/context_provider.h
@@ -12,7 +12,6 @@
class GrContext;
-namespace blink { class WebGraphicsContext3D; }
namespace gpu {
class ContextSupport;
namespace gles2 { class GLES2Interface; }
@@ -29,32 +28,17 @@ class ContextProvider : public base::RefCountedThreadSafe<ContextProvider> {
// from the same thread.
virtual bool BindToCurrentThread() = 0;
- virtual blink::WebGraphicsContext3D* Context3d() = 0;
virtual gpu::gles2::GLES2Interface* ContextGL() = 0;
virtual gpu::ContextSupport* ContextSupport() = 0;
virtual class GrContext* GrContext() = 0;
- virtual void MakeGrContextCurrent() = 0;
struct Capabilities {
- bool egl_image_external : 1;
- bool fast_npot_mo8_textures : 1;
- bool iosurface : 1;
- bool map_image : 1;
- bool post_sub_buffer : 1;
- bool texture_format_bgra8888 : 1;
- bool texture_format_etc1 : 1;
- bool texture_rectangle : 1;
- bool texture_storage : 1;
- bool texture_usage : 1;
- bool discard_framebuffer : 1;
+ gpu::Capabilities gpu;
size_t max_transfer_buffer_usage_bytes;
CC_EXPORT Capabilities();
-
- // TODO(boliu): Compose a gpu::Capabilities instead and remove this
- // constructor.
- explicit CC_EXPORT Capabilities(const gpu::Capabilities& gpu_capabilities);
};
+
// Returns the capabilities of the currently bound 3d context.
virtual Capabilities ContextCapabilities() = 0;
@@ -66,6 +50,9 @@ class ContextProvider : public base::RefCountedThreadSafe<ContextProvider> {
// one.
virtual void VerifyContexts() = 0;
+ // Delete all cached gpu resources.
+ virtual void DeleteCachedResources() = 0;
+
// A method to be called from the main thread that should return true if
// the context inside the provider is no longer valid.
virtual bool DestroyedOnMainThread() = 0;
diff --git a/chromium/cc/output/copy_output_request.cc b/chromium/cc/output/copy_output_request.cc
index 50173d5853d..97b95e10e0f 100644
--- a/chromium/cc/output/copy_output_request.cc
+++ b/chromium/cc/output/copy_output_request.cc
@@ -6,9 +6,9 @@
#include "base/bind.h"
#include "base/callback_helpers.h"
+#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "cc/output/copy_output_result.h"
-#include "cc/resources/single_release_callback.h"
#include "cc/resources/texture_mailbox.h"
#include "third_party/skia/include/core/SkBitmap.h"
@@ -35,7 +35,10 @@ CopyOutputRequest::CopyOutputRequest(
: force_bitmap_result_(force_bitmap_result),
has_area_(false),
has_texture_mailbox_(false),
- result_callback_(result_callback) {}
+ result_callback_(result_callback) {
+ DCHECK(!result_callback_.is_null());
+ TRACE_EVENT_ASYNC_BEGIN0("cc", "CopyOutputRequest", this);
+}
CopyOutputRequest::~CopyOutputRequest() {
if (!result_callback_.is_null())
@@ -43,7 +46,9 @@ CopyOutputRequest::~CopyOutputRequest() {
}
void CopyOutputRequest::SendResult(scoped_ptr<CopyOutputResult> result) {
+ bool success = !result->IsEmpty();
base::ResetAndReturn(&result_callback_).Run(result.Pass());
+ TRACE_EVENT_ASYNC_END1("cc", "CopyOutputRequest", this, "success", success);
}
void CopyOutputRequest::SendEmptyResult() {
@@ -55,7 +60,7 @@ void CopyOutputRequest::SendBitmapResult(scoped_ptr<SkBitmap> bitmap) {
}
void CopyOutputRequest::SendTextureResult(
- gfx::Size size,
+ const gfx::Size& size,
const TextureMailbox& texture_mailbox,
scoped_ptr<SingleReleaseCallback> release_callback) {
DCHECK(texture_mailbox.IsTexture());
diff --git a/chromium/cc/output/copy_output_request.h b/chromium/cc/output/copy_output_request.h
index 4b74b419fca..60a5f11204d 100644
--- a/chromium/cc/output/copy_output_request.h
+++ b/chromium/cc/output/copy_output_request.h
@@ -8,6 +8,7 @@
#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
#include "cc/base/cc_export.h"
+#include "cc/resources/single_release_callback.h"
#include "cc/resources/texture_mailbox.h"
#include "ui/gfx/rect.h"
@@ -15,7 +16,6 @@ class SkBitmap;
namespace cc {
class CopyOutputResult;
-class SingleReleaseCallback;
class CC_EXPORT CopyOutputRequest {
public:
@@ -46,7 +46,7 @@ class CC_EXPORT CopyOutputRequest {
// By default copy requests copy the entire layer's subtree output. If an
// area is given, then the intersection of this rect (in layer space) with
// the layer's subtree output will be returned.
- void set_area(gfx::Rect area) {
+ void set_area(const gfx::Rect& area) {
has_area_ = true;
area_ = area;
}
@@ -62,7 +62,7 @@ class CC_EXPORT CopyOutputRequest {
void SendEmptyResult();
void SendBitmapResult(scoped_ptr<SkBitmap> bitmap);
- void SendTextureResult(gfx::Size size,
+ void SendTextureResult(const gfx::Size& size,
const TextureMailbox& texture_mailbox,
scoped_ptr<SingleReleaseCallback> release_callback);
diff --git a/chromium/cc/output/copy_output_result.cc b/chromium/cc/output/copy_output_result.cc
index 1831fba3be1..8dee046ce84 100644
--- a/chromium/cc/output/copy_output_result.cc
+++ b/chromium/cc/output/copy_output_result.cc
@@ -5,7 +5,6 @@
#include "cc/output/copy_output_result.h"
#include "base/logging.h"
-#include "cc/resources/single_release_callback.h"
#include "cc/resources/texture_mailbox.h"
#include "third_party/skia/include/core/SkBitmap.h"
@@ -20,7 +19,7 @@ CopyOutputResult::CopyOutputResult(scoped_ptr<SkBitmap> bitmap)
}
CopyOutputResult::CopyOutputResult(
- gfx::Size size,
+ const gfx::Size& size,
const TextureMailbox& texture_mailbox,
scoped_ptr<SingleReleaseCallback> release_callback)
: size_(size),
diff --git a/chromium/cc/output/copy_output_result.h b/chromium/cc/output/copy_output_result.h
index c2f011d20fc..8529e3f1522 100644
--- a/chromium/cc/output/copy_output_result.h
+++ b/chromium/cc/output/copy_output_result.h
@@ -7,13 +7,13 @@
#include "base/memory/scoped_ptr.h"
#include "cc/base/cc_export.h"
+#include "cc/resources/single_release_callback.h"
#include "cc/resources/texture_mailbox.h"
#include "ui/gfx/size.h"
class SkBitmap;
namespace cc {
-class SingleReleaseCallback;
class TextureMailbox;
class CC_EXPORT CopyOutputResult {
@@ -26,7 +26,7 @@ class CC_EXPORT CopyOutputResult {
return make_scoped_ptr(new CopyOutputResult(bitmap.Pass()));
}
static scoped_ptr<CopyOutputResult> CreateTextureResult(
- gfx::Size size,
+ const gfx::Size& size,
const TextureMailbox& texture_mailbox,
scoped_ptr<SingleReleaseCallback> release_callback) {
return make_scoped_ptr(
@@ -47,7 +47,7 @@ class CC_EXPORT CopyOutputResult {
private:
CopyOutputResult();
explicit CopyOutputResult(scoped_ptr<SkBitmap> bitmap);
- explicit CopyOutputResult(gfx::Size size,
+ explicit CopyOutputResult(const gfx::Size& size,
const TextureMailbox& texture_mailbox,
scoped_ptr<SingleReleaseCallback> release_callback);
diff --git a/chromium/cc/output/delegated_frame_data.cc b/chromium/cc/output/delegated_frame_data.cc
index 516a3ec5a5f..94ff51d79da 100644
--- a/chromium/cc/output/delegated_frame_data.cc
+++ b/chromium/cc/output/delegated_frame_data.cc
@@ -6,7 +6,8 @@
namespace cc {
-DelegatedFrameData::DelegatedFrameData() {}
+DelegatedFrameData::DelegatedFrameData() : device_scale_factor(1.0f) {
+}
DelegatedFrameData::~DelegatedFrameData() {}
diff --git a/chromium/cc/output/delegated_frame_data.h b/chromium/cc/output/delegated_frame_data.h
index f7b89bce843..644f180f55a 100644
--- a/chromium/cc/output/delegated_frame_data.h
+++ b/chromium/cc/output/delegated_frame_data.h
@@ -18,6 +18,9 @@ class CC_EXPORT DelegatedFrameData {
DelegatedFrameData();
~DelegatedFrameData();
+ // The device scale factor used when generating this frame.
+ float device_scale_factor;
+
TransferableResourceArray resource_list;
ScopedPtrVector<RenderPass> render_pass_list;
diff --git a/chromium/cc/output/delegating_renderer.cc b/chromium/cc/output/delegating_renderer.cc
index c76f250754a..75c3b6364a5 100644
--- a/chromium/cc/output/delegating_renderer.cc
+++ b/chromium/cc/output/delegating_renderer.cc
@@ -23,11 +23,10 @@
#include "cc/quads/yuv_video_draw_quad.h"
#include "cc/resources/resource_provider.h"
#include "gpu/command_buffer/client/context_support.h"
+#include "gpu/command_buffer/client/gles2_interface.h"
#include "gpu/command_buffer/common/gpu_memory_allocation.h"
-#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
#include "third_party/khronos/GLES2/gl2ext.h"
-using blink::WebGraphicsContext3D;
namespace cc {
@@ -36,11 +35,8 @@ scoped_ptr<DelegatingRenderer> DelegatingRenderer::Create(
const LayerTreeSettings* settings,
OutputSurface* output_surface,
ResourceProvider* resource_provider) {
- scoped_ptr<DelegatingRenderer> renderer(new DelegatingRenderer(
+ return make_scoped_ptr(new DelegatingRenderer(
client, settings, output_surface, resource_provider));
- if (!renderer->Initialize())
- return scoped_ptr<DelegatingRenderer>();
- return renderer.Pass();
}
DelegatingRenderer::DelegatingRenderer(RendererClient* client,
@@ -49,43 +45,36 @@ DelegatingRenderer::DelegatingRenderer(RendererClient* client,
ResourceProvider* resource_provider)
: Renderer(client, settings),
output_surface_(output_surface),
- resource_provider_(resource_provider),
- visible_(true) {
+ resource_provider_(resource_provider) {
DCHECK(resource_provider_);
-}
-bool DelegatingRenderer::Initialize() {
capabilities_.using_partial_swap = false;
capabilities_.max_texture_size = resource_provider_->max_texture_size();
capabilities_.best_texture_format = resource_provider_->best_texture_format();
capabilities_.allow_partial_texture_updates = false;
- capabilities_.using_offscreen_context3d = false;
if (!output_surface_->context_provider()) {
capabilities_.using_shared_memory_resources = true;
- capabilities_.using_map_image = settings_->use_map_image;
- return true;
- }
+ capabilities_.using_map_image = true;
+ } else {
+ const ContextProvider::Capabilities& caps =
+ output_surface_->context_provider()->ContextCapabilities();
- const ContextProvider::Capabilities& caps =
- output_surface_->context_provider()->ContextCapabilities();
+ DCHECK(!caps.gpu.iosurface || caps.gpu.texture_rectangle);
- DCHECK(!caps.iosurface || caps.texture_rectangle);
+ capabilities_.using_egl_image = caps.gpu.egl_image_external;
+ capabilities_.using_map_image = caps.gpu.map_image;
- capabilities_.using_egl_image = caps.egl_image_external;
- capabilities_.using_map_image = settings_->use_map_image && caps.map_image;
-
- return true;
+ capabilities_.allow_rasterize_on_demand = false;
+ }
}
DelegatingRenderer::~DelegatingRenderer() {}
-const RendererCapabilities& DelegatingRenderer::Capabilities() const {
+const RendererCapabilitiesImpl& DelegatingRenderer::Capabilities() const {
return capabilities_;
}
-bool DelegatingRenderer::CanReadPixels() const { return false; }
-
static ResourceProvider::ResourceId AppendToArray(
ResourceProvider::ResourceIdArray* array,
ResourceProvider::ResourceId id) {
@@ -94,11 +83,9 @@ static ResourceProvider::ResourceId AppendToArray(
}
void DelegatingRenderer::DrawFrame(RenderPassList* render_passes_in_draw_order,
- ContextProvider* offscreen_context_provider,
float device_scale_factor,
- gfx::Rect device_viewport_rect,
- gfx::Rect device_clip_rect,
- bool allow_partial_swap,
+ const gfx::Rect& device_viewport_rect,
+ const gfx::Rect& device_clip_rect,
bool disable_picture_quad_image_filtering) {
TRACE_EVENT0("cc", "DelegatingRenderer::DrawFrame");
@@ -106,6 +93,7 @@ void DelegatingRenderer::DrawFrame(RenderPassList* render_passes_in_draw_order,
delegated_frame_data_ = make_scoped_ptr(new DelegatedFrameData);
DelegatedFrameData& out_data = *delegated_frame_data_;
+ out_data.device_scale_factor = device_scale_factor;
// Move the render passes and resources into the |out_frame|.
out_data.render_pass_list.swap(*render_passes_in_draw_order);
@@ -122,17 +110,13 @@ void DelegatingRenderer::DrawFrame(RenderPassList* render_passes_in_draw_order,
}
void DelegatingRenderer::SwapBuffers(const CompositorFrameMetadata& metadata) {
- TRACE_EVENT0("cc", "DelegatingRenderer::SwapBuffers");
+ TRACE_EVENT0("cc,benchmark", "DelegatingRenderer::SwapBuffers");
CompositorFrame compositor_frame;
compositor_frame.metadata = metadata;
compositor_frame.delegated_frame_data = delegated_frame_data_.Pass();
output_surface_->SwapBuffers(&compositor_frame);
}
-void DelegatingRenderer::GetFramebufferPixels(void* pixels, gfx::Rect rect) {
- NOTREACHED();
-}
-
void DelegatingRenderer::ReceiveSwapBuffersAck(
const CompositorFrameAck& ack) {
resource_provider_->ReceiveReturnsFromParent(ack.resources);
@@ -145,41 +129,21 @@ bool DelegatingRenderer::IsContextLost() {
return context_provider->IsContextLost();
}
-void DelegatingRenderer::SetVisible(bool visible) {
- if (visible == visible_)
- return;
-
- visible_ = visible;
+void DelegatingRenderer::DidChangeVisibility() {
ContextProvider* context_provider = output_surface_->context_provider();
- if (!visible_) {
+ if (!visible()) {
TRACE_EVENT0("cc", "DelegatingRenderer::SetVisible dropping resources");
resource_provider_->ReleaseCachedData();
- if (context_provider)
- context_provider->Context3d()->flush();
+ if (context_provider) {
+ context_provider->DeleteCachedResources();
+ context_provider->ContextGL()->Flush();
+ }
}
// We loop visibility to the GPU process, since that's what manages memory.
// That will allow it to feed us with memory allocations that we can act
// upon.
- DCHECK(context_provider);
- context_provider->ContextSupport()->SetSurfaceVisible(visible);
-}
-
-void DelegatingRenderer::SendManagedMemoryStats(size_t bytes_visible,
- size_t bytes_visible_and_nearby,
- size_t bytes_allocated) {
- ContextProvider* context_provider = output_surface_->context_provider();
- if (!context_provider) {
- // TODO(piman): software path.
- NOTIMPLEMENTED();
- return;
- }
- gpu::ManagedMemoryStats stats;
- stats.bytes_required = bytes_visible;
- stats.bytes_nice_to_have = bytes_visible_and_nearby;
- stats.bytes_allocated = bytes_allocated;
- stats.backbuffer_requested = false;
-
- context_provider->ContextSupport()->SendManagedMemoryStats(stats);
+ if (context_provider)
+ context_provider->ContextSupport()->SetSurfaceVisible(visible());
}
} // namespace cc
diff --git a/chromium/cc/output/delegating_renderer.h b/chromium/cc/output/delegating_renderer.h
index c18bfa7d7ac..10d95ce61a8 100644
--- a/chromium/cc/output/delegating_renderer.h
+++ b/chromium/cc/output/delegating_renderer.h
@@ -24,16 +24,12 @@ class CC_EXPORT DelegatingRenderer : public Renderer {
ResourceProvider* resource_provider);
virtual ~DelegatingRenderer();
- virtual const RendererCapabilities& Capabilities() const OVERRIDE;
-
- virtual bool CanReadPixels() const OVERRIDE;
+ virtual const RendererCapabilitiesImpl& Capabilities() const OVERRIDE;
virtual void DrawFrame(RenderPassList* render_passes_in_draw_order,
- ContextProvider* offscreen_context_provider,
float device_scale_factor,
- gfx::Rect device_viewport_rect,
- gfx::Rect device_clip_rect,
- bool allow_partial_swap,
+ const gfx::Rect& device_viewport_rect,
+ const gfx::Rect& device_clip_rect,
bool disable_picture_quad_image_filtering) OVERRIDE;
virtual void Finish() OVERRIDE {}
@@ -41,28 +37,20 @@ class CC_EXPORT DelegatingRenderer : public Renderer {
virtual void SwapBuffers(const CompositorFrameMetadata& metadata) OVERRIDE;
virtual void ReceiveSwapBuffersAck(const CompositorFrameAck&) OVERRIDE;
- virtual void GetFramebufferPixels(void* pixels, gfx::Rect rect) OVERRIDE;
-
virtual bool IsContextLost() OVERRIDE;
- virtual void SetVisible(bool visible) OVERRIDE;
-
- virtual void SendManagedMemoryStats(size_t bytes_visible,
- size_t bytes_visible_and_nearby,
- size_t bytes_allocated) OVERRIDE;
-
private:
DelegatingRenderer(RendererClient* client,
const LayerTreeSettings* settings,
OutputSurface* output_surface,
ResourceProvider* resource_provider);
- bool Initialize();
+
+ virtual void DidChangeVisibility() OVERRIDE;
OutputSurface* output_surface_;
ResourceProvider* resource_provider_;
- RendererCapabilities capabilities_;
+ RendererCapabilitiesImpl capabilities_;
scoped_ptr<DelegatedFrameData> delegated_frame_data_;
- bool visible_;
DISALLOW_COPY_AND_ASSIGN(DelegatingRenderer);
};
diff --git a/chromium/cc/output/delegating_renderer_unittest.cc b/chromium/cc/output/delegating_renderer_unittest.cc
index ffa7e4f6e31..ac026cacc0c 100644
--- a/chromium/cc/output/delegating_renderer_unittest.cc
+++ b/chromium/cc/output/delegating_renderer_unittest.cc
@@ -39,10 +39,10 @@ class DelegatingRendererTestDraw : public DelegatingRendererTest {
virtual void AfterTest() OVERRIDE {}
- virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
- LayerTreeHostImpl::FrameData* frame,
- bool result)
- OVERRIDE {
+ virtual DrawResult PrepareToDrawOnThread(
+ LayerTreeHostImpl* host_impl,
+ LayerTreeHostImpl::FrameData* frame,
+ DrawResult draw_result) OVERRIDE {
EXPECT_EQ(0u, output_surface_->num_sent_frames());
const CompositorFrame& last_frame = output_surface_->last_sent_frame();
@@ -50,7 +50,7 @@ class DelegatingRendererTestDraw : public DelegatingRendererTest {
EXPECT_FALSE(last_frame.gl_frame_data);
EXPECT_EQ(0.f, last_frame.metadata.min_page_scale_factor);
EXPECT_EQ(0.f, last_frame.metadata.max_page_scale_factor);
- return true;
+ return DRAW_SUCCESS;
}
virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
@@ -89,10 +89,9 @@ class DelegatingRendererTestResources : public DelegatingRendererTest {
virtual void AfterTest() OVERRIDE {}
- virtual bool PrepareToDrawOnThread(
- LayerTreeHostImpl* host_impl,
- LayerTreeHostImpl::FrameData* frame,
- bool result) OVERRIDE {
+ virtual DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
+ LayerTreeHostImpl::FrameData* frame,
+ DrawResult draw_result) OVERRIDE {
frame->render_passes.clear();
frame->render_passes_by_id.clear();
@@ -111,7 +110,7 @@ class DelegatingRendererTestResources : public DelegatingRendererTest {
gfx::Transform());
pass->AppendOneOfEveryQuadType(
host_impl->resource_provider(), child_pass->id);
- return true;
+ return draw_result;
}
virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
diff --git a/chromium/cc/output/direct_renderer.cc b/chromium/cc/output/direct_renderer.cc
index 84788c5d13d..ccde85b6e5e 100644
--- a/chromium/cc/output/direct_renderer.cc
+++ b/chromium/cc/output/direct_renderer.cc
@@ -14,6 +14,7 @@
#include "cc/base/math_util.h"
#include "cc/output/copy_output_request.h"
#include "cc/quads/draw_quad.h"
+#include "cc/resources/raster_worker_pool.h"
#include "ui/gfx/rect_conversions.h"
#include "ui/gfx/transform.h"
@@ -57,10 +58,8 @@ static gfx::Transform window_matrix(int x, int y, int width, int height) {
namespace cc {
DirectRenderer::DrawingFrame::DrawingFrame()
- : root_render_pass(NULL),
- current_render_pass(NULL),
- current_texture(NULL),
- offscreen_context_provider(NULL) {}
+ : root_render_pass(NULL), current_render_pass(NULL), current_texture(NULL) {
+}
DirectRenderer::DrawingFrame::~DrawingFrame() {}
@@ -81,9 +80,9 @@ void DirectRenderer::QuadRectTransform(gfx::Transform* quad_rect_transform,
}
void DirectRenderer::InitializeViewport(DrawingFrame* frame,
- gfx::Rect draw_rect,
- gfx::Rect viewport_rect,
- gfx::Size surface_size) {
+ const gfx::Rect& draw_rect,
+ const gfx::Rect& viewport_rect,
+ const gfx::Size& surface_size) {
bool flip_y = FlippedFramebuffer();
DCHECK_GE(viewport_rect.x(), 0);
@@ -117,8 +116,8 @@ void DirectRenderer::InitializeViewport(DrawingFrame* frame,
}
gfx::Rect DirectRenderer::MoveFromDrawToWindowSpace(
- const gfx::RectF& draw_rect) const {
- gfx::Rect window_rect = gfx::ToEnclosingRect(draw_rect);
+ const gfx::Rect& draw_rect) const {
+ gfx::Rect window_rect = draw_rect;
window_rect -= current_draw_rect_.OffsetFromOrigin();
window_rect += current_viewport_rect_.OffsetFromOrigin();
if (FlippedFramebuffer())
@@ -132,14 +131,16 @@ DirectRenderer::DirectRenderer(RendererClient* client,
ResourceProvider* resource_provider)
: Renderer(client, settings),
output_surface_(output_surface),
- resource_provider_(resource_provider) {}
+ resource_provider_(resource_provider),
+ overlay_processor_(
+ new OverlayProcessor(output_surface, resource_provider)) {
+ overlay_processor_->Initialize();
+}
DirectRenderer::~DirectRenderer() {}
-bool DirectRenderer::CanReadPixels() const { return true; }
-
void DirectRenderer::SetEnlargePassTextureAmountForTesting(
- gfx::Vector2d amount) {
+ const gfx::Vector2d& amount) {
enlarge_pass_texture_amount_ = amount;
}
@@ -193,11 +194,9 @@ void DirectRenderer::DecideRenderPassAllocationsForFrame(
}
void DirectRenderer::DrawFrame(RenderPassList* render_passes_in_draw_order,
- ContextProvider* offscreen_context_provider,
float device_scale_factor,
- gfx::Rect device_viewport_rect,
- gfx::Rect device_clip_rect,
- bool allow_partial_swap,
+ const gfx::Rect& device_viewport_rect,
+ const gfx::Rect& device_clip_rect,
bool disable_picture_quad_image_filtering) {
TRACE_EVENT0("cc", "DirectRenderer::DrawFrame");
UMA_HISTOGRAM_COUNTS("Renderer4.renderPassCount",
@@ -208,17 +207,18 @@ void DirectRenderer::DrawFrame(RenderPassList* render_passes_in_draw_order,
DrawingFrame frame;
frame.root_render_pass = root_render_pass;
- frame.root_damage_rect =
- Capabilities().using_partial_swap && allow_partial_swap
- ? root_render_pass->damage_rect
- : root_render_pass->output_rect;
+ frame.root_damage_rect = Capabilities().using_partial_swap
+ ? root_render_pass->damage_rect
+ : root_render_pass->output_rect;
frame.root_damage_rect.Intersect(gfx::Rect(device_viewport_rect.size()));
frame.device_viewport_rect = device_viewport_rect;
frame.device_clip_rect = device_clip_rect;
- frame.offscreen_context_provider = offscreen_context_provider;
frame.disable_picture_quad_image_filtering =
disable_picture_quad_image_filtering;
+ overlay_processor_->ProcessForOverlays(render_passes_in_draw_order,
+ &frame.overlay_list);
+
EnsureBackbuffer();
// Only reshape when we know we are going to draw. Otherwise, the reshape
@@ -229,7 +229,7 @@ void DirectRenderer::DrawFrame(RenderPassList* render_passes_in_draw_order,
BeginDrawingFrame(&frame);
for (size_t i = 0; i < render_passes_in_draw_order->size(); ++i) {
RenderPass* pass = render_passes_in_draw_order->at(i);
- DrawRenderPass(&frame, pass, allow_partial_swap);
+ DrawRenderPass(&frame, pass);
for (ScopedPtrVector<CopyOutputRequest>::iterator it =
pass->copy_requests.begin();
@@ -248,20 +248,21 @@ void DirectRenderer::DrawFrame(RenderPassList* render_passes_in_draw_order,
render_passes_in_draw_order->clear();
}
-gfx::RectF DirectRenderer::ComputeScissorRectForRenderPass(
+gfx::Rect DirectRenderer::ComputeScissorRectForRenderPass(
const DrawingFrame* frame) {
- gfx::RectF render_pass_scissor = frame->current_render_pass->output_rect;
+ gfx::Rect render_pass_scissor = frame->current_render_pass->output_rect;
- if (frame->root_damage_rect == frame->root_render_pass->output_rect)
+ if (frame->root_damage_rect == frame->root_render_pass->output_rect ||
+ !frame->current_render_pass->copy_requests.empty())
return render_pass_scissor;
gfx::Transform inverse_transform(gfx::Transform::kSkipInitialization);
if (frame->current_render_pass->transform_to_root_target.GetInverse(
&inverse_transform)) {
// Only intersect inverse-projected damage if the transform is invertible.
- gfx::RectF damage_rect_in_render_pass_space =
- MathUtil::ProjectClippedRect(inverse_transform,
- frame->root_damage_rect);
+ gfx::Rect damage_rect_in_render_pass_space =
+ MathUtil::ProjectEnclosingClippedRect(inverse_transform,
+ frame->root_damage_rect);
render_pass_scissor.Intersect(damage_rect_in_render_pass_space);
}
@@ -301,9 +302,9 @@ void DirectRenderer::SetScissorStateForQuad(const DrawingFrame* frame,
void DirectRenderer::SetScissorStateForQuadWithRenderPassScissor(
const DrawingFrame* frame,
const DrawQuad& quad,
- const gfx::RectF& render_pass_scissor,
+ const gfx::Rect& render_pass_scissor,
bool* should_skip_quad) {
- gfx::RectF quad_scissor_rect = render_pass_scissor;
+ gfx::Rect quad_scissor_rect = render_pass_scissor;
if (quad.isClipped())
quad_scissor_rect.Intersect(quad.clipRect());
@@ -317,8 +318,9 @@ void DirectRenderer::SetScissorStateForQuadWithRenderPassScissor(
SetScissorTestRectInDrawSpace(frame, quad_scissor_rect);
}
-void DirectRenderer::SetScissorTestRectInDrawSpace(const DrawingFrame* frame,
- gfx::RectF draw_space_rect) {
+void DirectRenderer::SetScissorTestRectInDrawSpace(
+ const DrawingFrame* frame,
+ const gfx::Rect& draw_space_rect) {
gfx::Rect window_space_rect = MoveFromDrawToWindowSpace(draw_space_rect);
if (NeedDeviceClip(frame))
window_space_rect.Intersect(DeviceClipRectInWindowSpace(frame));
@@ -328,15 +330,13 @@ void DirectRenderer::SetScissorTestRectInDrawSpace(const DrawingFrame* frame,
void DirectRenderer::FinishDrawingQuadList() {}
void DirectRenderer::DrawRenderPass(DrawingFrame* frame,
- const RenderPass* render_pass,
- bool allow_partial_swap) {
+ const RenderPass* render_pass) {
TRACE_EVENT0("cc", "DirectRenderer::DrawRenderPass");
if (!UseRenderPass(frame, render_pass))
return;
- bool using_scissor_as_optimization =
- Capabilities().using_partial_swap && allow_partial_swap;
- gfx::RectF render_pass_scissor;
+ bool using_scissor_as_optimization = Capabilities().using_partial_swap;
+ gfx::Rect render_pass_scissor;
bool draw_rect_covers_full_surface = true;
if (frame->current_render_pass == frame->root_render_pass &&
!frame->device_viewport_rect.Contains(
diff --git a/chromium/cc/output/direct_renderer.h b/chromium/cc/output/direct_renderer.h
index 5c4dc7e23f4..1a84a87f59c 100644
--- a/chromium/cc/output/direct_renderer.h
+++ b/chromium/cc/output/direct_renderer.h
@@ -9,9 +9,11 @@
#include "base/callback.h"
#include "base/containers/scoped_ptr_hash_map.h"
#include "cc/base/cc_export.h"
+#include "cc/output/overlay_processor.h"
#include "cc/output/renderer.h"
#include "cc/resources/resource_provider.h"
#include "cc/resources/scoped_resource.h"
+#include "cc/resources/task_graph_runner.h"
namespace cc {
@@ -24,19 +26,14 @@ class CC_EXPORT DirectRenderer : public Renderer {
public:
virtual ~DirectRenderer();
- ResourceProvider* resource_provider() const { return resource_provider_; }
-
- virtual bool CanReadPixels() const OVERRIDE;
virtual void DecideRenderPassAllocationsForFrame(
const RenderPassList& render_passes_in_draw_order) OVERRIDE;
virtual bool HasAllocatedResourcesForTesting(RenderPass::Id id) const
OVERRIDE;
virtual void DrawFrame(RenderPassList* render_passes_in_draw_order,
- ContextProvider* offscreen_context_provider,
float device_scale_factor,
- gfx::Rect device_viewport_rect,
- gfx::Rect device_clip_rect,
- bool allow_partial_swap,
+ const gfx::Rect& device_viewport_rect,
+ const gfx::Rect& device_clip_rect,
bool disable_picture_quad_image_filtering) OVERRIDE;
struct CC_EXPORT DrawingFrame {
@@ -47,19 +44,19 @@ class CC_EXPORT DirectRenderer : public Renderer {
const RenderPass* current_render_pass;
const ScopedResource* current_texture;
- gfx::RectF root_damage_rect;
+ gfx::Rect root_damage_rect;
gfx::Rect device_viewport_rect;
gfx::Rect device_clip_rect;
gfx::Transform projection_matrix;
gfx::Transform window_matrix;
- ContextProvider* offscreen_context_provider;
-
bool disable_picture_quad_image_filtering;
+
+ OverlayCandidateList overlay_list;
};
- void SetEnlargePassTextureAmountForTesting(gfx::Vector2d amount);
+ void SetEnlargePassTextureAmountForTesting(const gfx::Vector2d& amount);
protected:
DirectRenderer(RendererClient* client,
@@ -72,36 +69,34 @@ class CC_EXPORT DirectRenderer : public Renderer {
const gfx::Transform& quad_transform,
const gfx::RectF& quad_rect);
void InitializeViewport(DrawingFrame* frame,
- gfx::Rect draw_rect,
- gfx::Rect viewport_rect,
- gfx::Size surface_size);
- gfx::Rect MoveFromDrawToWindowSpace(const gfx::RectF& draw_rect) const;
+ const gfx::Rect& draw_rect,
+ const gfx::Rect& viewport_rect,
+ const gfx::Size& surface_size);
+ gfx::Rect MoveFromDrawToWindowSpace(const gfx::Rect& draw_rect) const;
bool NeedDeviceClip(const DrawingFrame* frame) const;
gfx::Rect DeviceClipRectInWindowSpace(const DrawingFrame* frame) const;
- static gfx::RectF ComputeScissorRectForRenderPass(const DrawingFrame* frame);
+ static gfx::Rect ComputeScissorRectForRenderPass(const DrawingFrame* frame);
void SetScissorStateForQuad(const DrawingFrame* frame, const DrawQuad& quad);
void SetScissorStateForQuadWithRenderPassScissor(
const DrawingFrame* frame,
const DrawQuad& quad,
- const gfx::RectF& render_pass_scissor,
+ const gfx::Rect& render_pass_scissor,
bool* should_skip_quad);
void SetScissorTestRectInDrawSpace(const DrawingFrame* frame,
- gfx::RectF draw_space_rect);
+ const gfx::Rect& draw_space_rect);
static gfx::Size RenderPassTextureSize(const RenderPass* render_pass);
- void DrawRenderPass(DrawingFrame* frame,
- const RenderPass* render_pass,
- bool allow_partial_swap);
+ void DrawRenderPass(DrawingFrame* frame, const RenderPass* render_pass);
bool UseRenderPass(DrawingFrame* frame, const RenderPass* render_pass);
virtual void BindFramebufferToOutputSurface(DrawingFrame* frame) = 0;
virtual bool BindFramebufferToTexture(DrawingFrame* frame,
const ScopedResource* resource,
- gfx::Rect target_rect) = 0;
- virtual void SetDrawViewport(gfx::Rect window_space_viewport) = 0;
- virtual void SetScissorTestRect(gfx::Rect scissor_rect) = 0;
+ const gfx::Rect& target_rect) = 0;
+ virtual void SetDrawViewport(const gfx::Rect& window_space_viewport) = 0;
+ virtual void SetScissorTestRect(const gfx::Rect& scissor_rect) = 0;
virtual void DiscardPixels(bool has_external_stencil_test,
bool draw_rect_covers_full_surface) = 0;
virtual void ClearFramebuffer(DrawingFrame* frame,
@@ -123,6 +118,7 @@ class CC_EXPORT DirectRenderer : public Renderer {
base::ScopedPtrHashMap<RenderPass::Id, ScopedResource> render_pass_textures_;
OutputSurface* output_surface_;
ResourceProvider* resource_provider_;
+ scoped_ptr<OverlayProcessor> overlay_processor_;
// For use in coordinate conversion, this stores the output rect, viewport
// rect (= unflipped version of glViewport rect), and the size of target
diff --git a/chromium/cc/output/filter_operation.cc b/chromium/cc/output/filter_operation.cc
index 50f111fc2d6..7682853b2e2 100644
--- a/chromium/cc/output/filter_operation.cc
+++ b/chromium/cc/output/filter_operation.cc
@@ -24,12 +24,18 @@ bool FilterOperation::operator==(const FilterOperation& other) const {
}
if (type_ == REFERENCE)
return image_filter_.get() == other.image_filter_.get();
+ if (type_ == ALPHA_THRESHOLD) {
+ return region_ == other.region_ &&
+ amount_ == other.amount_ &&
+ outer_threshold_ == other.outer_threshold_;
+ }
return amount_ == other.amount_;
}
FilterOperation::FilterOperation(FilterType type, float amount)
: type_(type),
amount_(amount),
+ outer_threshold_(0),
drop_shadow_offset_(0, 0),
drop_shadow_color_(0),
zoom_inset_(0) {
@@ -40,11 +46,12 @@ FilterOperation::FilterOperation(FilterType type, float amount)
}
FilterOperation::FilterOperation(FilterType type,
- gfx::Point offset,
+ const gfx::Point& offset,
float stdDeviation,
SkColor color)
: type_(type),
amount_(stdDeviation),
+ outer_threshold_(0),
drop_shadow_offset_(offset),
drop_shadow_color_(color),
zoom_inset_(0) {
@@ -55,6 +62,7 @@ FilterOperation::FilterOperation(FilterType type,
FilterOperation::FilterOperation(FilterType type, SkScalar matrix[20])
: type_(type),
amount_(0),
+ outer_threshold_(0),
drop_shadow_offset_(0, 0),
drop_shadow_color_(0),
zoom_inset_(0) {
@@ -65,6 +73,7 @@ FilterOperation::FilterOperation(FilterType type, SkScalar matrix[20])
FilterOperation::FilterOperation(FilterType type, float amount, int inset)
: type_(type),
amount_(amount),
+ outer_threshold_(0),
drop_shadow_offset_(0, 0),
drop_shadow_color_(0),
zoom_inset_(inset) {
@@ -77,6 +86,7 @@ FilterOperation::FilterOperation(
const skia::RefPtr<SkImageFilter>& image_filter)
: type_(type),
amount_(0),
+ outer_threshold_(0),
drop_shadow_offset_(0, 0),
drop_shadow_color_(0),
image_filter_(image_filter),
@@ -85,13 +95,30 @@ FilterOperation::FilterOperation(
memset(matrix_, 0, sizeof(matrix_));
}
+FilterOperation::FilterOperation(FilterType type,
+ const SkRegion& region,
+ float inner_threshold,
+ float outer_threshold)
+ : type_(type),
+ amount_(inner_threshold),
+ outer_threshold_(outer_threshold),
+ drop_shadow_offset_(0, 0),
+ drop_shadow_color_(0),
+ zoom_inset_(0),
+ region_(region) {
+ DCHECK_EQ(type_, ALPHA_THRESHOLD);
+ memset(matrix_, 0, sizeof(matrix_));
+}
+
FilterOperation::FilterOperation(const FilterOperation& other)
: type_(other.type_),
amount_(other.amount_),
+ outer_threshold_(other.outer_threshold_),
drop_shadow_offset_(other.drop_shadow_offset_),
drop_shadow_color_(other.drop_shadow_color_),
image_filter_(other.image_filter_),
- zoom_inset_(other.zoom_inset_) {
+ zoom_inset_(other.zoom_inset_),
+ region_(other.region_) {
memcpy(matrix_, other.matrix_, sizeof(matrix_));
}
@@ -134,6 +161,8 @@ static FilterOperation CreateNoOpFilter(FilterOperation::FilterType type) {
case FilterOperation::REFERENCE:
return FilterOperation::CreateReferenceFilter(
skia::RefPtr<SkImageFilter>());
+ case FilterOperation::ALPHA_THRESHOLD:
+ return FilterOperation::CreateAlphaThresholdFilter(SkRegion(), 1.f, 0.f);
}
NOTREACHED();
return FilterOperation::CreateEmptyFilter();
@@ -146,6 +175,7 @@ static float ClampAmountForFilterType(float amount,
case FilterOperation::SEPIA:
case FilterOperation::INVERT:
case FilterOperation::OPACITY:
+ case FilterOperation::ALPHA_THRESHOLD:
return MathUtil::ClampToRange(amount, 0.f, 1.f);
case FilterOperation::SATURATE:
case FilterOperation::BRIGHTNESS:
@@ -213,13 +243,20 @@ FilterOperation FilterOperation::Blend(const FilterOperation* from,
std::max(gfx::Tween::LinearIntValueBetween(
from_op.zoom_inset(), to_op.zoom_inset(), progress),
0));
+ } else if (to_op.type() == FilterOperation::ALPHA_THRESHOLD) {
+ blended_filter.set_outer_threshold(ClampAmountForFilterType(
+ gfx::Tween::FloatValueBetween(progress,
+ from_op.outer_threshold(),
+ to_op.outer_threshold()),
+ to_op.type()));
+ blended_filter.set_region(to_op.region());
}
return blended_filter;
}
scoped_ptr<base::Value> FilterOperation::AsValue() const {
- scoped_ptr<base::DictionaryValue> value(new DictionaryValue);
+ scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue);
value->SetInteger("type", type_);
switch (type_) {
case FilterOperation::GRAYSCALE:
@@ -240,7 +277,7 @@ scoped_ptr<base::Value> FilterOperation::AsValue() const {
value->SetInteger("color", drop_shadow_color_);
break;
case FilterOperation::COLOR_MATRIX: {
- scoped_ptr<ListValue> matrix(new ListValue);
+ scoped_ptr<base::ListValue> matrix(new base::ListValue);
for (size_t i = 0; i < arraysize(matrix_); ++i)
matrix->AppendDouble(matrix_[i]);
value->Set("matrix", matrix.release());
@@ -262,6 +299,19 @@ scoped_ptr<base::Value> FilterOperation::AsValue() const {
value->SetBoolean("can_filter_image_gpu", can_filter_image_gpu);
break;
}
+ case FilterOperation::ALPHA_THRESHOLD: {
+ value->SetDouble("inner_threshold", amount_);
+ value->SetDouble("outer_threshold", outer_threshold_);
+ scoped_ptr<base::ListValue> region_value(new base::ListValue());
+ for (SkRegion::Iterator it(region_); !it.done(); it.next()) {
+ region_value->AppendInteger(it.rect().x());
+ region_value->AppendInteger(it.rect().y());
+ region_value->AppendInteger(it.rect().width());
+ region_value->AppendInteger(it.rect().height());
+ }
+ value->Set("region", region_value.release());
+ }
+ break;
}
return value.PassAs<base::Value>();
}
diff --git a/chromium/cc/output/filter_operation.h b/chromium/cc/output/filter_operation.h
index f5c6a8264fa..626d2e7f06b 100644
--- a/chromium/cc/output/filter_operation.h
+++ b/chromium/cc/output/filter_operation.h
@@ -11,6 +11,7 @@
#include "skia/ext/refptr.h"
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkImageFilter.h"
+#include "third_party/skia/include/core/SkRegion.h"
#include "third_party/skia/include/core/SkScalar.h"
#include "ui/gfx/point.h"
@@ -37,6 +38,8 @@ class CC_EXPORT FilterOperation {
ZOOM,
REFERENCE,
SATURATING_BRIGHTNESS, // Not used in CSS/SVG.
+ ALPHA_THRESHOLD, // Not used in CSS/SVG.
+ FILTER_TYPE_LAST = ALPHA_THRESHOLD
};
FilterOperation(const FilterOperation& other);
@@ -51,6 +54,11 @@ class CC_EXPORT FilterOperation {
return amount_;
}
+ float outer_threshold() const {
+ DCHECK_EQ(type_, ALPHA_THRESHOLD);
+ return outer_threshold_;
+ }
+
gfx::Point drop_shadow_offset() const {
DCHECK_EQ(type_, DROP_SHADOW);
return drop_shadow_offset_;
@@ -76,6 +84,11 @@ class CC_EXPORT FilterOperation {
return zoom_inset_;
}
+ const SkRegion& region() const {
+ DCHECK_EQ(type_, ALPHA_THRESHOLD);
+ return region_;
+ }
+
static FilterOperation CreateGrayscaleFilter(float amount) {
return FilterOperation(GRAYSCALE, amount);
}
@@ -112,7 +125,7 @@ class CC_EXPORT FilterOperation {
return FilterOperation(BLUR, amount);
}
- static FilterOperation CreateDropShadowFilter(gfx::Point offset,
+ static FilterOperation CreateDropShadowFilter(const gfx::Point& offset,
float std_deviation,
SkColor color) {
return FilterOperation(DROP_SHADOW, offset, std_deviation, color);
@@ -135,6 +148,13 @@ class CC_EXPORT FilterOperation {
return FilterOperation(SATURATING_BRIGHTNESS, amount);
}
+ static FilterOperation CreateAlphaThresholdFilter(const SkRegion& region,
+ float inner_threshold,
+ float outer_threshold) {
+ return FilterOperation(ALPHA_THRESHOLD, region,
+ inner_threshold, outer_threshold);
+ }
+
bool operator==(const FilterOperation& other) const;
bool operator!=(const FilterOperation& other) const {
@@ -154,7 +174,12 @@ class CC_EXPORT FilterOperation {
amount_ = amount;
}
- void set_drop_shadow_offset(gfx::Point offset) {
+ void set_outer_threshold(float outer_threshold) {
+ DCHECK_EQ(type_, ALPHA_THRESHOLD);
+ outer_threshold_ = outer_threshold;
+ }
+
+ void set_drop_shadow_offset(const gfx::Point& offset) {
DCHECK_EQ(type_, DROP_SHADOW);
drop_shadow_offset_ = offset;
}
@@ -180,6 +205,11 @@ class CC_EXPORT FilterOperation {
zoom_inset_ = inset;
}
+ void set_region(const SkRegion& region) {
+ DCHECK_EQ(type_, ALPHA_THRESHOLD);
+ region_ = region;
+ }
+
// Given two filters of the same type, returns a filter operation created by
// linearly interpolating a |progress| fraction from |from| to |to|. If either
// |from| or |to| (but not both) is null, it is treated as a no-op filter of
@@ -196,7 +226,7 @@ class CC_EXPORT FilterOperation {
FilterOperation(FilterType type, float amount);
FilterOperation(FilterType type,
- gfx::Point offset,
+ const gfx::Point& offset,
float stdDeviation,
SkColor color);
@@ -207,13 +237,20 @@ class CC_EXPORT FilterOperation {
FilterOperation(FilterType type,
const skia::RefPtr<SkImageFilter>& image_filter);
+ FilterOperation(FilterType type,
+ const SkRegion& region,
+ float inner_threshold,
+ float outer_threshold);
+
FilterType type_;
float amount_;
+ float outer_threshold_;
gfx::Point drop_shadow_offset_;
SkColor drop_shadow_color_;
skia::RefPtr<SkImageFilter> image_filter_;
SkScalar matrix_[20];
int zoom_inset_;
+ SkRegion region_;
};
} // namespace cc
diff --git a/chromium/cc/output/filter_operations.cc b/chromium/cc/output/filter_operations.cc
index 21d222e94bf..443d7ecae6e 100644
--- a/chromium/cc/output/filter_operations.cc
+++ b/chromium/cc/output/filter_operations.cc
@@ -102,6 +102,7 @@ bool FilterOperations::HasFilterThatMovesPixels() const {
case FilterOperation::BRIGHTNESS:
case FilterOperation::CONTRAST:
case FilterOperation::SATURATING_BRIGHTNESS:
+ case FilterOperation::ALPHA_THRESHOLD:
break;
}
}
@@ -119,6 +120,7 @@ bool FilterOperations::HasFilterThatAffectsOpacity() const {
case FilterOperation::DROP_SHADOW:
case FilterOperation::ZOOM:
case FilterOperation::REFERENCE:
+ case FilterOperation::ALPHA_THRESHOLD:
return true;
case FilterOperation::COLOR_MATRIX: {
const SkScalar* matrix = op.matrix();
@@ -195,7 +197,7 @@ FilterOperations FilterOperations::Blend(const FilterOperations& from,
}
scoped_ptr<base::Value> FilterOperations::AsValue() const {
- scoped_ptr<base::ListValue> value(new ListValue);
+ scoped_ptr<base::ListValue> value(new base::ListValue);
for (size_t i = 0; i < operations_.size(); ++i)
value->Append(operations_[i].AsValue().release());
return value.PassAs<base::Value>();
diff --git a/chromium/cc/output/filter_operations_unittest.cc b/chromium/cc/output/filter_operations_unittest.cc
index 329601fd726..e97379cbd2a 100644
--- a/chromium/cc/output/filter_operations_unittest.cc
+++ b/chromium/cc/output/filter_operations_unittest.cc
@@ -505,10 +505,10 @@ TEST(FilterOperationsTest, BlendSaturatingBrightnessWithNull) {
}
TEST(FilterOperationsTest, BlendReferenceFilters) {
- skia::RefPtr<SkImageFilter> from_filter = skia::AdoptRef(
- new SkBlurImageFilter(1.f, 1.f));
- skia::RefPtr<SkImageFilter> to_filter = skia::AdoptRef(
- new SkBlurImageFilter(2.f, 2.f));
+ skia::RefPtr<SkImageFilter> from_filter =
+ skia::AdoptRef(SkBlurImageFilter::Create(1.f, 1.f));
+ skia::RefPtr<SkImageFilter> to_filter =
+ skia::AdoptRef(SkBlurImageFilter::Create(2.f, 2.f));
FilterOperation from = FilterOperation::CreateReferenceFilter(from_filter);
FilterOperation to = FilterOperation::CreateReferenceFilter(to_filter);
@@ -526,8 +526,8 @@ TEST(FilterOperationsTest, BlendReferenceFilters) {
}
TEST(FilterOperationsTest, BlendReferenceWithNull) {
- skia::RefPtr<SkImageFilter> image_filter = skia::AdoptRef(
- new SkBlurImageFilter(1.f, 1.f));
+ skia::RefPtr<SkImageFilter> image_filter =
+ skia::AdoptRef(SkBlurImageFilter::Create(1.f, 1.f));
FilterOperation filter = FilterOperation::CreateReferenceFilter(image_filter);
FilterOperation null_filter =
FilterOperation::CreateReferenceFilter(skia::RefPtr<SkImageFilter>());
diff --git a/chromium/cc/output/gl_renderer.cc b/chromium/cc/output/gl_renderer.cc
index 04db7b0609b..b58a4d19e0c 100644
--- a/chromium/cc/output/gl_renderer.cc
+++ b/chromium/cc/output/gl_renderer.cc
@@ -31,6 +31,7 @@
#include "cc/quads/stream_video_draw_quad.h"
#include "cc/quads/texture_draw_quad.h"
#include "cc/resources/layer_quad.h"
+#include "cc/resources/raster_worker_pool.h"
#include "cc/resources/scoped_resource.h"
#include "cc/resources/texture_mailbox_deleter.h"
#include "cc/trees/damage_tracker.h"
@@ -40,7 +41,6 @@
#include "gpu/command_buffer/client/context_support.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "gpu/command_buffer/common/gpu_memory_allocation.h"
-#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "third_party/khronos/GLES2/gl2ext.h"
#include "third_party/skia/include/core/SkBitmap.h"
@@ -55,29 +55,75 @@
#include "ui/gfx/quad_f.h"
#include "ui/gfx/rect_conversions.h"
-using blink::WebGraphicsContext3D;
using gpu::gles2::GLES2Interface;
namespace cc {
-
namespace {
-// TODO(epenner): This should probably be moved to output surface.
-//
-// This implements a simple fence based on client side swaps.
-// This is to isolate the ResourceProvider from 'frames' which
-// it shouldn't need to care about, while still allowing us to
-// enforce good texture recycling behavior strictly throughout
-// the compositor (don't recycle a texture while it's in use).
-class SimpleSwapFence : public ResourceProvider::Fence {
+class FallbackFence : public ResourceProvider::Fence {
public:
- SimpleSwapFence() : has_passed_(false) {}
- virtual bool HasPassed() OVERRIDE { return has_passed_; }
- void SetHasPassed() { has_passed_ = true; }
+ explicit FallbackFence(gpu::gles2::GLES2Interface* gl)
+ : gl_(gl), has_passed_(false) {}
+
+ // Overridden from ResourceProvider::Fence:
+ virtual bool HasPassed() OVERRIDE {
+ if (!has_passed_) {
+ has_passed_ = true;
+ Synchronize();
+ }
+ return true;
+ }
private:
- virtual ~SimpleSwapFence() {}
+ virtual ~FallbackFence() {}
+
+ void Synchronize() {
+ TRACE_EVENT0("cc", "FallbackFence::Synchronize");
+ gl_->Finish();
+ }
+
+ gpu::gles2::GLES2Interface* gl_;
bool has_passed_;
+
+ DISALLOW_COPY_AND_ASSIGN(FallbackFence);
+};
+
+class OnDemandRasterTaskImpl : public Task {
+ public:
+ OnDemandRasterTaskImpl(PicturePileImpl* picture_pile,
+ SkBitmap* bitmap,
+ gfx::Rect content_rect,
+ float contents_scale)
+ : picture_pile_(picture_pile),
+ bitmap_(bitmap),
+ content_rect_(content_rect),
+ contents_scale_(contents_scale) {
+ DCHECK(picture_pile_);
+ DCHECK(bitmap_);
+ }
+
+ // Overridden from Task:
+ virtual void RunOnWorkerThread() OVERRIDE {
+ TRACE_EVENT0("cc", "OnDemandRasterTaskImpl::RunOnWorkerThread");
+ SkCanvas canvas(*bitmap_);
+
+ PicturePileImpl* picture_pile = picture_pile_->GetCloneForDrawingOnThread(
+ RasterWorkerPool::GetPictureCloneIndexForCurrentThread());
+ DCHECK(picture_pile);
+
+ picture_pile->RasterToBitmap(&canvas, content_rect_, contents_scale_, NULL);
+ }
+
+ protected:
+ virtual ~OnDemandRasterTaskImpl() {}
+
+ private:
+ PicturePileImpl* picture_pile_;
+ SkBitmap* bitmap_;
+ const gfx::Rect content_rect_;
+ const float contents_scale_;
+
+ DISALLOW_COPY_AND_ASSIGN(OnDemandRasterTaskImpl);
};
bool NeedsIOSurfaceReadbackWorkaround() {
@@ -129,8 +175,46 @@ SamplerType SamplerTypeFromTextureTarget(GLenum target) {
// determine when anti-aliasing is unnecessary.
const float kAntiAliasingEpsilon = 1.0f / 1024.0f;
+// Block or crash if the number of pending sync queries reach this high as
+// something is seriously wrong on the service side if this happens.
+const size_t kMaxPendingSyncQueries = 16;
+
} // anonymous namespace
+class GLRenderer::ScopedUseGrContext {
+ public:
+ static scoped_ptr<ScopedUseGrContext> Create(GLRenderer* renderer,
+ DrawingFrame* frame) {
+ if (!renderer->output_surface_->context_provider()->GrContext())
+ return scoped_ptr<ScopedUseGrContext>();
+ return make_scoped_ptr(new ScopedUseGrContext(renderer, frame));
+ }
+
+ ~ScopedUseGrContext() { PassControlToGLRenderer(); }
+
+ GrContext* context() const {
+ return renderer_->output_surface_->context_provider()->GrContext();
+ }
+
+ private:
+ ScopedUseGrContext(GLRenderer* renderer, DrawingFrame* frame)
+ : renderer_(renderer), frame_(frame) {
+ PassControlToSkia();
+ }
+
+ void PassControlToSkia() { context()->resetContext(); }
+
+ void PassControlToGLRenderer() {
+ renderer_->RestoreGLState();
+ renderer_->RestoreFramebuffer(frame_);
+ }
+
+ GLRenderer* renderer_;
+ DrawingFrame* frame_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedUseGrContext);
+};
+
struct GLRenderer::PendingAsyncReadPixels {
PendingAsyncReadPixels() : buffer(0) {}
@@ -142,6 +226,63 @@ struct GLRenderer::PendingAsyncReadPixels {
DISALLOW_COPY_AND_ASSIGN(PendingAsyncReadPixels);
};
+class GLRenderer::SyncQuery {
+ public:
+ explicit SyncQuery(gpu::gles2::GLES2Interface* gl)
+ : gl_(gl), query_id_(0u), weak_ptr_factory_(this) {
+ gl_->GenQueriesEXT(1, &query_id_);
+ }
+ virtual ~SyncQuery() { gl_->DeleteQueriesEXT(1, &query_id_); }
+
+ scoped_refptr<ResourceProvider::Fence> Begin() {
+ DCHECK(!weak_ptr_factory_.HasWeakPtrs() || !IsPending());
+ // Invalidate weak pointer held by old fence.
+ weak_ptr_factory_.InvalidateWeakPtrs();
+ gl_->BeginQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM, query_id_);
+ return make_scoped_refptr<ResourceProvider::Fence>(
+ new Fence(weak_ptr_factory_.GetWeakPtr()));
+ }
+
+ void End() { gl_->EndQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM); }
+
+ bool IsPending() {
+ unsigned available = 1;
+ gl_->GetQueryObjectuivEXT(
+ query_id_, GL_QUERY_RESULT_AVAILABLE_EXT, &available);
+ return !available;
+ }
+
+ void Wait() {
+ unsigned result = 0;
+ gl_->GetQueryObjectuivEXT(query_id_, GL_QUERY_RESULT_EXT, &result);
+ }
+
+ private:
+ class Fence : public ResourceProvider::Fence {
+ public:
+ explicit Fence(base::WeakPtr<GLRenderer::SyncQuery> query)
+ : query_(query) {}
+
+ // Overridden from ResourceProvider::Fence:
+ virtual bool HasPassed() OVERRIDE {
+ return !query_ || !query_->IsPending();
+ }
+
+ private:
+ virtual ~Fence() {}
+
+ base::WeakPtr<SyncQuery> query_;
+
+ DISALLOW_COPY_AND_ASSIGN(Fence);
+ };
+
+ gpu::gles2::GLES2Interface* gl_;
+ unsigned query_id_;
+ base::WeakPtrFactory<SyncQuery> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(SyncQuery);
+};
+
scoped_ptr<GLRenderer> GLRenderer::Create(
RendererClient* client,
const LayerTreeSettings* settings,
@@ -165,32 +306,31 @@ GLRenderer::GLRenderer(RendererClient* client,
int highp_threshold_min)
: DirectRenderer(client, settings, output_surface, resource_provider),
offscreen_framebuffer_id_(0),
- shared_geometry_quad_(gfx::RectF(-0.5f, -0.5f, 1.0f, 1.0f)),
- context_(output_surface->context_provider()->Context3d()),
+ shared_geometry_quad_(QuadVertexRect()),
gl_(output_surface->context_provider()->ContextGL()),
context_support_(output_surface->context_provider()->ContextSupport()),
texture_mailbox_deleter_(texture_mailbox_deleter),
is_backbuffer_discarded_(false),
- visible_(true),
is_scissor_enabled_(false),
scissor_rect_needs_reset_(true),
stencil_shadow_(false),
blend_shadow_(false),
highp_threshold_min_(highp_threshold_min),
highp_threshold_cache_(0),
+ use_sync_query_(false),
on_demand_tile_raster_resource_id_(0) {
- DCHECK(context_);
+ DCHECK(gl_);
DCHECK(context_support_);
ContextProvider::Capabilities context_caps =
output_surface_->context_provider()->ContextCapabilities();
capabilities_.using_partial_swap =
- settings_->partial_swap_enabled && context_caps.post_sub_buffer;
+ settings_->partial_swap_enabled && context_caps.gpu.post_sub_buffer;
- DCHECK(!context_caps.iosurface || context_caps.texture_rectangle);
+ DCHECK(!context_caps.gpu.iosurface || context_caps.gpu.texture_rectangle);
- capabilities_.using_egl_image = context_caps.egl_image_external;
+ capabilities_.using_egl_image = context_caps.gpu.egl_image_external;
capabilities_.max_texture_size = resource_provider_->max_texture_size();
capabilities_.best_texture_format = resource_provider_->best_texture_format();
@@ -200,14 +340,16 @@ GLRenderer::GLRenderer(RendererClient* client,
// Check for texture fast paths. Currently we always use MO8 textures,
// so we only need to avoid POT textures if we have an NPOT fast-path.
- capabilities_.avoid_pow2_textures = context_caps.fast_npot_mo8_textures;
+ capabilities_.avoid_pow2_textures = context_caps.gpu.fast_npot_mo8_textures;
- capabilities_.using_offscreen_context3d = true;
+ capabilities_.using_map_image = context_caps.gpu.map_image;
- capabilities_.using_map_image =
- settings_->use_map_image && context_caps.map_image;
+ capabilities_.using_discard_framebuffer =
+ context_caps.gpu.discard_framebuffer;
- capabilities_.using_discard_framebuffer = context_caps.discard_framebuffer;
+ capabilities_.allow_rasterize_on_demand = true;
+
+ use_sync_query_ = context_caps.gpu.sync_query;
InitializeSharedObjects();
}
@@ -219,15 +361,15 @@ GLRenderer::~GLRenderer() {
pending_async_read_pixels_.pop_back();
}
+ in_use_overlay_resources_.clear();
+
CleanupSharedObjects();
}
-const RendererCapabilities& GLRenderer::Capabilities() const {
+const RendererCapabilitiesImpl& GLRenderer::Capabilities() const {
return capabilities_;
}
-WebGraphicsContext3D* GLRenderer::Context() { return context_; }
-
void GLRenderer::DebugGLCall(GLES2Interface* gl,
const char* command,
const char* file,
@@ -239,25 +381,10 @@ void GLRenderer::DebugGLCall(GLES2Interface* gl,
<< static_cast<int>(error) << "\n";
}
-void GLRenderer::SetVisible(bool visible) {
- if (visible_ == visible)
- return;
- visible_ = visible;
-
+void GLRenderer::DidChangeVisibility() {
EnforceMemoryPolicy();
- context_support_->SetSurfaceVisible(visible);
-}
-
-void GLRenderer::SendManagedMemoryStats(size_t bytes_visible,
- size_t bytes_visible_and_nearby,
- size_t bytes_allocated) {
- gpu::ManagedMemoryStats stats;
- stats.bytes_required = bytes_visible;
- stats.bytes_nice_to_have = bytes_visible_and_nearby;
- stats.bytes_allocated = bytes_allocated;
- stats.backbuffer_requested = !is_backbuffer_discarded_;
- context_support_->SendManagedMemoryStats(stats);
+ context_support_->SetSurfaceVisible(visible());
}
void GLRenderer::ReleaseRenderPassTextures() { render_pass_textures_.clear(); }
@@ -310,6 +437,34 @@ void GLRenderer::BeginDrawingFrame(DrawingFrame* frame) {
TRACE_EVENT0("cc", "GLRenderer::BeginDrawingFrame");
+ scoped_refptr<ResourceProvider::Fence> read_lock_fence;
+ if (use_sync_query_) {
+ // Block until oldest sync query has passed if the number of pending queries
+ // ever reach kMaxPendingSyncQueries.
+ if (pending_sync_queries_.size() >= kMaxPendingSyncQueries) {
+ LOG(ERROR) << "Reached limit of pending sync queries.";
+
+ pending_sync_queries_.front()->Wait();
+ DCHECK(!pending_sync_queries_.front()->IsPending());
+ }
+
+ while (!pending_sync_queries_.empty()) {
+ if (pending_sync_queries_.front()->IsPending())
+ break;
+
+ available_sync_queries_.push_back(pending_sync_queries_.take_front());
+ }
+
+ current_sync_query_ = available_sync_queries_.empty()
+ ? make_scoped_ptr(new SyncQuery(gl_))
+ : available_sync_queries_.take_front();
+
+ read_lock_fence = current_sync_query_->Begin();
+ } else {
+ read_lock_fence = make_scoped_refptr(new FallbackFence(gl_));
+ }
+ resource_provider_->SetReadLockFence(read_lock_fence.get());
+
// TODO(enne): Do we need to reinitialize all of this state per frame?
ReinitializeGLState();
}
@@ -350,6 +505,11 @@ void GLRenderer::DoDrawQuad(DrawingFrame* frame, const DrawQuad* quad) {
case DrawQuad::STREAM_VIDEO_CONTENT:
DrawStreamVideoQuad(frame, StreamVideoDrawQuad::MaterialCast(quad));
break;
+ case DrawQuad::SURFACE_CONTENT:
+ // Surface content should be fully resolved to other quad types before
+ // reaching a direct renderer.
+ NOTREACHED();
+ break;
case DrawQuad::TEXTURE_CONTENT:
EnqueueTextureQuad(frame, TextureDrawQuad::MaterialCast(quad));
break;
@@ -417,10 +577,8 @@ void GLRenderer::DrawDebugBorderQuad(const DrawingFrame* frame,
// Use the full quad_rect for debug quads to not move the edges based on
// partial swaps.
gfx::Rect layer_rect = quad->rect;
- gfx::Transform render_matrix = quad->quadTransform();
- render_matrix.Translate(0.5f * layer_rect.width() + layer_rect.x(),
- 0.5f * layer_rect.height() + layer_rect.y());
- render_matrix.Scale(layer_rect.width(), layer_rect.height());
+ gfx::Transform render_matrix;
+ QuadRectTransform(&render_matrix, quad->quadTransform(), layer_rect);
GLRenderer::ToGLMatrix(&gl_matrix[0],
frame->projection_matrix * render_matrix);
GLC(gl_,
@@ -444,27 +602,20 @@ void GLRenderer::DrawDebugBorderQuad(const DrawingFrame* frame,
GLC(gl_, gl_->DrawElements(GL_LINE_LOOP, 4, GL_UNSIGNED_SHORT, 0));
}
-static SkBitmap ApplyImageFilter(GLRenderer* renderer,
- ContextProvider* offscreen_contexts,
- gfx::Point origin,
- SkImageFilter* filter,
- ScopedResource* source_texture_resource) {
+static SkBitmap ApplyImageFilter(
+ scoped_ptr<GLRenderer::ScopedUseGrContext> use_gr_context,
+ ResourceProvider* resource_provider,
+ const gfx::Point& origin,
+ SkImageFilter* filter,
+ ScopedResource* source_texture_resource) {
if (!filter)
return SkBitmap();
- if (!offscreen_contexts || !offscreen_contexts->GrContext())
+ if (!use_gr_context)
return SkBitmap();
- ResourceProvider::ScopedWriteLockGL lock(renderer->resource_provider(),
- source_texture_resource->id());
-
- // Flush the compositor context to ensure that textures there are available
- // in the shared context. Do this after locking/creating the compositor
- // texture.
- renderer->resource_provider()->Flush();
-
- // Make sure skia uses the correct GL context.
- offscreen_contexts->MakeGrContextCurrent();
+ ResourceProvider::ScopedReadLockGL lock(resource_provider,
+ source_texture_resource->id());
// Wrap the source texture in a Ganesh platform texture.
GrBackendTextureDesc backend_texture_description;
@@ -475,7 +626,7 @@ static SkBitmap ApplyImageFilter(GLRenderer* renderer,
backend_texture_description.fTextureHandle = lock.texture_id();
backend_texture_description.fOrigin = kBottomLeft_GrSurfaceOrigin;
skia::RefPtr<GrTexture> texture =
- skia::AdoptRef(offscreen_contexts->GrContext()->wrapBackendTexture(
+ skia::AdoptRef(use_gr_context->context()->wrapBackendTexture(
backend_texture_description));
SkImageInfo info = {
@@ -486,7 +637,7 @@ static SkBitmap ApplyImageFilter(GLRenderer* renderer,
};
// Place the platform texture inside an SkBitmap.
SkBitmap source;
- source.setConfig(info);
+ source.setInfo(info);
skia::RefPtr<SkGrPixelRef> pixel_ref =
skia::AdoptRef(new SkGrPixelRef(info, texture.get()));
source.setPixelRef(pixel_ref.get());
@@ -500,13 +651,21 @@ static SkBitmap ApplyImageFilter(GLRenderer* renderer,
desc.fConfig = kSkia8888_GrPixelConfig;
desc.fOrigin = kBottomLeft_GrSurfaceOrigin;
GrAutoScratchTexture scratch_texture(
- offscreen_contexts->GrContext(), desc, GrContext::kExact_ScratchTexMatch);
+ use_gr_context->context(), desc, GrContext::kExact_ScratchTexMatch);
skia::RefPtr<GrTexture> backing_store =
skia::AdoptRef(scratch_texture.detach());
+ if (backing_store.get() == NULL) {
+ TRACE_EVENT_INSTANT0("cc",
+ "ApplyImageFilter scratch texture allocation failed",
+ TRACE_EVENT_SCOPE_THREAD);
+ return SkBitmap();
+ }
// Create a device and canvas using that backing store.
- SkGpuDevice device(offscreen_contexts->GrContext(), backing_store.get());
- SkCanvas canvas(&device);
+ skia::RefPtr<SkGpuDevice> device =
+ skia::AdoptRef(SkGpuDevice::Create(backing_store->asRenderTarget()));
+ DCHECK(device.get());
+ SkCanvas canvas(device.get());
// Draw the source bitmap through the filter to the canvas.
SkPaint paint;
@@ -519,25 +678,22 @@ static SkBitmap ApplyImageFilter(GLRenderer* renderer,
canvas.translate(SkIntToScalar(-origin.x()), SkIntToScalar(-origin.y()));
canvas.drawSprite(source, 0, 0, &paint);
- // Flush skia context so that all the rendered stuff appears on the
- // texture.
- offscreen_contexts->GrContext()->flush();
-
- // Flush the GL context so rendering results from this context are
- // visible in the compositor's context.
- offscreen_contexts->Context3d()->flush();
+ // Flush the GrContext to ensure all buffered GL calls are drawn to the
+ // backing store before we access and return it, and have cc begin using the
+ // GL context again.
+ use_gr_context->context()->flush();
- return device.accessBitmap(false);
+ return device->accessBitmap(false);
}
static SkBitmap ApplyBlendModeWithBackdrop(
- GLRenderer* renderer,
- ContextProvider* offscreen_contexts,
+ scoped_ptr<GLRenderer::ScopedUseGrContext> use_gr_context,
+ ResourceProvider* resource_provider,
SkBitmap source_bitmap_with_filters,
ScopedResource* source_texture_resource,
ScopedResource* background_texture_resource,
SkXfermode::Mode blend_mode) {
- if (!offscreen_contexts || !offscreen_contexts->GrContext())
+ if (!use_gr_context)
return source_bitmap_with_filters;
DCHECK(background_texture_resource);
@@ -559,20 +715,12 @@ static SkBitmap ApplyBlendModeWithBackdrop(
source_texture_with_filters_id = texture->getTextureHandle();
} else {
lock.reset(new ResourceProvider::ScopedReadLockGL(
- renderer->resource_provider(), source_texture_resource->id()));
+ resource_provider, source_texture_resource->id()));
source_texture_with_filters_id = lock->texture_id();
}
ResourceProvider::ScopedReadLockGL lock_background(
- renderer->resource_provider(), background_texture_resource->id());
-
- // Flush the compositor context to ensure that textures there are available
- // in the shared context. Do this after locking/creating the compositor
- // texture.
- renderer->resource_provider()->Flush();
-
- // Make sure skia uses the correct GL context.
- offscreen_contexts->MakeGrContextCurrent();
+ resource_provider, background_texture_resource->id());
// Wrap the source texture in a Ganesh platform texture.
GrBackendTextureDesc backend_texture_description;
@@ -583,14 +731,14 @@ static SkBitmap ApplyBlendModeWithBackdrop(
backend_texture_description.fHeight = source_size.height();
backend_texture_description.fTextureHandle = source_texture_with_filters_id;
skia::RefPtr<GrTexture> source_texture =
- skia::AdoptRef(offscreen_contexts->GrContext()->wrapBackendTexture(
+ skia::AdoptRef(use_gr_context->context()->wrapBackendTexture(
backend_texture_description));
backend_texture_description.fWidth = background_size.width();
backend_texture_description.fHeight = background_size.height();
backend_texture_description.fTextureHandle = lock_background.texture_id();
skia::RefPtr<GrTexture> background_texture =
- skia::AdoptRef(offscreen_contexts->GrContext()->wrapBackendTexture(
+ skia::AdoptRef(use_gr_context->context()->wrapBackendTexture(
backend_texture_description));
SkImageInfo source_info = {
@@ -601,7 +749,7 @@ static SkBitmap ApplyBlendModeWithBackdrop(
};
// Place the platform texture inside an SkBitmap.
SkBitmap source;
- source.setConfig(source_info);
+ source.setInfo(source_info);
skia::RefPtr<SkGrPixelRef> source_pixel_ref =
skia::AdoptRef(new SkGrPixelRef(source_info, source_texture.get()));
source.setPixelRef(source_pixel_ref.get());
@@ -614,7 +762,7 @@ static SkBitmap ApplyBlendModeWithBackdrop(
};
SkBitmap background;
- background.setConfig(background_info);
+ background.setInfo(background_info);
skia::RefPtr<SkGrPixelRef> background_pixel_ref =
skia::AdoptRef(new SkGrPixelRef(
background_info, background_texture.get()));
@@ -629,13 +777,22 @@ static SkBitmap ApplyBlendModeWithBackdrop(
desc.fConfig = kSkia8888_GrPixelConfig;
desc.fOrigin = kBottomLeft_GrSurfaceOrigin;
GrAutoScratchTexture scratch_texture(
- offscreen_contexts->GrContext(), desc, GrContext::kExact_ScratchTexMatch);
+ use_gr_context->context(), desc, GrContext::kExact_ScratchTexMatch);
skia::RefPtr<GrTexture> backing_store =
skia::AdoptRef(scratch_texture.detach());
+ if (backing_store.get() == NULL) {
+ TRACE_EVENT_INSTANT0(
+ "cc",
+ "ApplyBlendModeWithBackdrop scratch texture allocation failed",
+ TRACE_EVENT_SCOPE_THREAD);
+ return source_bitmap_with_filters;
+ }
// Create a device and canvas using that backing store.
- SkGpuDevice device(offscreen_contexts->GrContext(), backing_store.get());
- SkCanvas canvas(&device);
+ skia::RefPtr<SkGpuDevice> device =
+ skia::AdoptRef(SkGpuDevice::Create(backing_store->asRenderTarget()));
+ DCHECK(device.get());
+ SkCanvas canvas(device.get());
// Draw the source bitmap through the filter to the canvas.
canvas.clear(SK_ColorTRANSPARENT);
@@ -644,15 +801,12 @@ static SkBitmap ApplyBlendModeWithBackdrop(
paint.setXfermodeMode(blend_mode);
canvas.drawSprite(source, 0, 0, &paint);
- // Flush skia context so that all the rendered stuff appears on the
- // texture.
- offscreen_contexts->GrContext()->flush();
-
- // Flush the GL context so rendering results from this context are
- // visible in the compositor's context.
- offscreen_contexts->Context3d()->flush();
+ // Flush the GrContext to ensure all buffered GL calls are drawn to the
+ // backing store before we access and return it, and have cc begin using the
+ // GL context again.
+ use_gr_context->context()->flush();
- return device.accessBitmap(false);
+ return device->accessBitmap(false);
}
scoped_ptr<ScopedResource> GLRenderer::GetBackgroundWithFilters(
@@ -728,8 +882,8 @@ scoped_ptr<ScopedResource> GLRenderer::GetBackgroundWithFilters(
SkBitmap filtered_device_background;
if (apply_background_filters) {
filtered_device_background =
- ApplyImageFilter(this,
- frame->offscreen_context_provider,
+ ApplyImageFilter(ScopedUseGrContext::Create(this, frame),
+ resource_provider_,
quad->rect.origin(),
filter.get(),
device_background_texture.get());
@@ -761,11 +915,8 @@ scoped_ptr<ScopedResource> GLRenderer::GetBackgroundWithFilters(
// Copy the readback pixels from device to the background texture for the
// surface.
gfx::Transform device_to_framebuffer_transform;
- device_to_framebuffer_transform.Translate(
- quad->rect.width() * 0.5f + quad->rect.x(),
- quad->rect.height() * 0.5f + quad->rect.y());
- device_to_framebuffer_transform.Scale(quad->rect.width(),
- quad->rect.height());
+ QuadRectTransform(
+ &device_to_framebuffer_transform, gfx::Transform(), quad->rect);
device_to_framebuffer_transform.PreconcatTransform(
contents_device_transform_inverse);
@@ -843,8 +994,6 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
SkBitmap filter_bitmap;
SkScalar color_matrix[20];
bool use_color_matrix = false;
- // TODO(ajuma): Always use RenderSurfaceFilters::BuildImageFilter, not just
- // when we have a reference filter.
if (!quad->filters.IsEmpty()) {
skia::RefPtr<SkImageFilter> filter = RenderSurfaceFilters::BuildImageFilter(
quad->filters, contents_texture->size());
@@ -862,11 +1011,12 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
// in the compositor.
use_color_matrix = true;
} else {
- filter_bitmap = ApplyImageFilter(this,
- frame->offscreen_context_provider,
- quad->rect.origin(),
- filter.get(),
- contents_texture);
+ filter_bitmap =
+ ApplyImageFilter(ScopedUseGrContext::Create(this, frame),
+ resource_provider_,
+ quad->rect.origin(),
+ filter.get(),
+ contents_texture);
}
}
}
@@ -874,8 +1024,8 @@ void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
if (quad->shared_quad_state->blend_mode != SkXfermode::kSrcOver_Mode &&
background_texture) {
filter_bitmap =
- ApplyBlendModeWithBackdrop(this,
- frame->offscreen_context_provider,
+ ApplyBlendModeWithBackdrop(ScopedUseGrContext::Create(this, frame),
+ resource_provider_,
filter_bitmap,
contents_texture,
background_texture.get(),
@@ -1595,8 +1745,9 @@ void GLRenderer::DrawYUVVideoQuad(const DrawingFrame* frame,
DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), a_plane_lock->target());
}
- int tex_scale_location = -1;
int matrix_location = -1;
+ int tex_scale_location = -1;
+ int tex_offset_location = -1;
int y_texture_location = -1;
int u_texture_location = -1;
int v_texture_location = -1;
@@ -1608,8 +1759,9 @@ void GLRenderer::DrawYUVVideoQuad(const DrawingFrame* frame,
const VideoYUVAProgram* program = GetVideoYUVAProgram(tex_coord_precision);
DCHECK(program && (program->initialized() || IsContextLost()));
SetUseProgram(program->program());
- tex_scale_location = program->vertex_shader().tex_scale_location();
matrix_location = program->vertex_shader().matrix_location();
+ tex_scale_location = program->vertex_shader().tex_scale_location();
+ tex_offset_location = program->vertex_shader().tex_offset_location();
y_texture_location = program->fragment_shader().y_texture_location();
u_texture_location = program->fragment_shader().u_texture_location();
v_texture_location = program->fragment_shader().v_texture_location();
@@ -1621,8 +1773,9 @@ void GLRenderer::DrawYUVVideoQuad(const DrawingFrame* frame,
const VideoYUVProgram* program = GetVideoYUVProgram(tex_coord_precision);
DCHECK(program && (program->initialized() || IsContextLost()));
SetUseProgram(program->program());
- tex_scale_location = program->vertex_shader().tex_scale_location();
matrix_location = program->vertex_shader().matrix_location();
+ tex_scale_location = program->vertex_shader().tex_scale_location();
+ tex_offset_location = program->vertex_shader().tex_offset_location();
y_texture_location = program->fragment_shader().y_texture_location();
u_texture_location = program->fragment_shader().u_texture_location();
v_texture_location = program->fragment_shader().v_texture_location();
@@ -1633,8 +1786,12 @@ void GLRenderer::DrawYUVVideoQuad(const DrawingFrame* frame,
GLC(gl_,
gl_->Uniform2f(tex_scale_location,
- quad->tex_scale.width(),
- quad->tex_scale.height()));
+ quad->tex_coord_rect.width(),
+ quad->tex_coord_rect.height()));
+ GLC(gl_,
+ gl_->Uniform2f(tex_offset_location,
+ quad->tex_coord_rect.x(),
+ quad->tex_coord_rect.y()));
GLC(gl_, gl_->Uniform1i(y_texture_location, 1));
GLC(gl_, gl_->Uniform1i(u_texture_location, 2));
GLC(gl_, gl_->Uniform1i(v_texture_location, 3));
@@ -1644,9 +1801,12 @@ void GLRenderer::DrawYUVVideoQuad(const DrawingFrame* frame,
// These values are magic numbers that are used in the transformation from YUV
// to RGB color values. They are taken from the following webpage:
// http://www.fourcc.org/fccyvrgb.php
- float yuv_to_rgb[9] = {1.164f, 1.164f, 1.164f, 0.0f, -.391f,
- 2.018f, 1.596f, -.813f, 0.0f, };
- GLC(gl_, gl_->UniformMatrix3fv(yuv_matrix_location, 1, 0, yuv_to_rgb));
+ float yuv_to_rgb_rec601[9] = {
+ 1.164f, 1.164f, 1.164f, 0.0f, -.391f, 2.018f, 1.596f, -.813f, 0.0f,
+ };
+ float yuv_to_rgb_rec601_jpeg[9] = {
+ 1.f, 1.f, 1.f, 0.0f, -.34414f, 1.772f, 1.402f, -.71414f, 0.0f,
+ };
// These values map to 16, 128, and 128 respectively, and are computed
// as a fraction over 256 (e.g. 16 / 256 = 0.0625).
@@ -1654,7 +1814,30 @@ void GLRenderer::DrawYUVVideoQuad(const DrawingFrame* frame,
// Y - 16 : Gives 16 values of head and footroom for overshooting
// U - 128 : Turns unsigned U into signed U [-128,127]
// V - 128 : Turns unsigned V into signed V [-128,127]
- float yuv_adjust[3] = {-0.0625f, -0.5f, -0.5f, };
+ float yuv_adjust_rec601[3] = {
+ -0.0625f, -0.5f, -0.5f,
+ };
+
+ // Same as above, but without the head and footroom.
+ float yuv_adjust_rec601_jpeg[3] = {
+ 0.0f, -0.5f, -0.5f,
+ };
+
+ float* yuv_to_rgb = NULL;
+ float* yuv_adjust = NULL;
+
+ switch (quad->color_space) {
+ case YUVVideoDrawQuad::REC_601:
+ yuv_to_rgb = yuv_to_rgb_rec601;
+ yuv_adjust = yuv_adjust_rec601;
+ break;
+ case YUVVideoDrawQuad::REC_601_JPEG:
+ yuv_to_rgb = yuv_to_rgb_rec601_jpeg;
+ yuv_adjust = yuv_adjust_rec601_jpeg;
+ break;
+ }
+
+ GLC(gl_, gl_->UniformMatrix3fv(yuv_matrix_location, 1, 0, yuv_to_rgb));
GLC(gl_, gl_->Uniform3fv(yuv_adj_location, 1, yuv_adjust));
SetShaderOpacity(quad->opacity(), alpha_location);
@@ -1703,10 +1886,8 @@ void GLRenderer::DrawPictureQuad(const DrawingFrame* frame,
const PictureDrawQuad* quad) {
if (on_demand_tile_raster_bitmap_.width() != quad->texture_size.width() ||
on_demand_tile_raster_bitmap_.height() != quad->texture_size.height()) {
- on_demand_tile_raster_bitmap_.setConfig(SkBitmap::kARGB_8888_Config,
- quad->texture_size.width(),
- quad->texture_size.height());
- on_demand_tile_raster_bitmap_.allocPixels();
+ on_demand_tile_raster_bitmap_.allocN32Pixels(quad->texture_size.width(),
+ quad->texture_size.height());
if (on_demand_tile_raster_resource_id_)
resource_provider_->DeleteResource(on_demand_tile_raster_resource_id_);
@@ -1720,18 +1901,20 @@ void GLRenderer::DrawPictureQuad(const DrawingFrame* frame,
quad->texture_format);
}
- SkBitmapDevice device(on_demand_tile_raster_bitmap_);
- SkCanvas canvas(&device);
-
- quad->picture_pile->RasterToBitmap(
- &canvas, quad->content_rect, quad->contents_scale, NULL);
+ // Create and run on-demand raster task for tile.
+ scoped_refptr<Task> on_demand_raster_task(
+ new OnDemandRasterTaskImpl(quad->picture_pile,
+ &on_demand_tile_raster_bitmap_,
+ quad->content_rect,
+ quad->contents_scale));
+ client_->RunOnDemandRasterTask(on_demand_raster_task.get());
uint8_t* bitmap_pixels = NULL;
SkBitmap on_demand_tile_raster_bitmap_dest;
- SkBitmap::Config config = SkBitmapConfig(quad->texture_format);
- if (on_demand_tile_raster_bitmap_.getConfig() != config) {
+ SkColorType colorType = ResourceFormatToSkColorType(quad->texture_format);
+ if (on_demand_tile_raster_bitmap_.colorType() != colorType) {
on_demand_tile_raster_bitmap_.copyTo(&on_demand_tile_raster_bitmap_dest,
- config);
+ colorType);
// TODO(kaanb): The GL pipeline assumes a 4-byte alignment for the
// bitmap data. This check will be removed once crbug.com/293728 is fixed.
CHECK_EQ(0u, on_demand_tile_raster_bitmap_dest.rowBytes() % 4);
@@ -1799,11 +1982,9 @@ void GLRenderer::FlushTextureQuadCache() {
DCHECK_EQ(GL_TEXTURE0, ResourceProvider::GetActiveTextureUnit(gl_));
GLC(gl_, gl_->BindTexture(GL_TEXTURE_2D, locked_quad.texture_id()));
- COMPILE_ASSERT(sizeof(Float4) == 4 * sizeof(float), // NOLINT(runtime/sizeof)
+ COMPILE_ASSERT(sizeof(Float4) == 4 * sizeof(float), struct_is_densely_packed);
+ COMPILE_ASSERT(sizeof(Float16) == 16 * sizeof(float),
struct_is_densely_packed);
- COMPILE_ASSERT(
- sizeof(Float16) == 16 * sizeof(float), // NOLINT(runtime/sizeof)
- struct_is_densely_packed);
// Upload the tranforms for both points and uvs.
GLC(gl_,
@@ -1957,11 +2138,19 @@ void GLRenderer::DrawIOSurfaceQuad(const DrawingFrame* frame,
}
void GLRenderer::FinishDrawingFrame(DrawingFrame* frame) {
+ if (use_sync_query_) {
+ DCHECK(current_sync_query_);
+ current_sync_query_->End();
+ pending_sync_queries_.push_back(current_sync_query_.Pass());
+ }
+
current_framebuffer_lock_.reset();
swap_buffer_rect_.Union(gfx::ToEnclosingRect(frame->root_damage_rect));
GLC(gl_, gl_->Disable(GL_BLEND));
blend_shadow_ = false;
+
+ ScheduleOverlays(frame);
}
void GLRenderer::FinishDrawingQuadList() { FlushTextureQuadCache(); }
@@ -2064,7 +2253,7 @@ void GLRenderer::DrawQuadGeometry(const DrawingFrame* frame,
void GLRenderer::CopyTextureToFramebuffer(const DrawingFrame* frame,
int texture_id,
- gfx::Rect rect,
+ const gfx::Rect& rect,
const gfx::Transform& draw_matrix,
bool flip_vertically) {
TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired(
@@ -2106,7 +2295,7 @@ void GLRenderer::Finish() {
void GLRenderer::SwapBuffers(const CompositorFrameMetadata& metadata) {
DCHECK(!is_backbuffer_discarded_);
- TRACE_EVENT0("cc", "GLRenderer::SwapBuffers");
+ TRACE_EVENT0("cc,benchmark", "GLRenderer::SwapBuffers");
// We're done! Time to swapbuffers!
gfx::Size surface_size = output_surface_->SurfaceSize();
@@ -2133,23 +2322,21 @@ void GLRenderer::SwapBuffers(const CompositorFrameMetadata& metadata) {
}
output_surface_->SwapBuffers(&compositor_frame);
- swap_buffer_rect_ = gfx::Rect();
+ // Release previously used overlay resources and hold onto the pending ones
+ // until the next swap buffers.
+ in_use_overlay_resources_.clear();
+ in_use_overlay_resources_.swap(pending_overlay_resources_);
- // We don't have real fences, so we mark read fences as passed
- // assuming a double-buffered GPU pipeline. A texture can be
- // written to after one full frame has past since it was last read.
- if (last_swap_fence_.get())
- static_cast<SimpleSwapFence*>(last_swap_fence_.get())->SetHasPassed();
- last_swap_fence_ = resource_provider_->GetReadLockFence();
- resource_provider_->SetReadLockFence(new SimpleSwapFence());
+ swap_buffer_rect_ = gfx::Rect();
}
void GLRenderer::EnforceMemoryPolicy() {
- if (!visible_) {
+ if (!visible()) {
TRACE_EVENT0("cc", "GLRenderer::EnforceMemoryPolicy dropping resources");
ReleaseRenderPassTextures();
DiscardBackbuffer();
resource_provider_->ReleaseCachedData();
+ output_surface_->context_provider()->DeleteCachedResources();
GLC(gl_, gl_->Flush());
}
}
@@ -2174,26 +2361,8 @@ void GLRenderer::EnsureBackbuffer() {
is_backbuffer_discarded_ = false;
}
-void GLRenderer::GetFramebufferPixels(void* pixels, gfx::Rect rect) {
- if (!pixels || rect.IsEmpty())
- return;
-
- // This function assumes that it is reading the root frame buffer.
- DCHECK(!current_framebuffer_lock_);
-
- scoped_ptr<PendingAsyncReadPixels> pending_read(new PendingAsyncReadPixels);
- pending_async_read_pixels_.insert(pending_async_read_pixels_.begin(),
- pending_read.Pass());
-
- // This is a syncronous call since the callback is null.
- gfx::Rect window_rect = MoveFromDrawToWindowSpace(rect);
- DoGetFramebufferPixels(static_cast<uint8*>(pixels),
- window_rect,
- AsyncGetFramebufferPixelsCleanupCallback());
-}
-
void GLRenderer::GetFramebufferPixelsAsync(
- gfx::Rect rect,
+ const gfx::Rect& rect,
scoped_ptr<CopyOutputRequest> request) {
DCHECK(!request->IsEmpty());
if (request->IsEmpty())
@@ -2202,6 +2371,10 @@ void GLRenderer::GetFramebufferPixelsAsync(
return;
gfx::Rect window_rect = MoveFromDrawToWindowSpace(rect);
+ DCHECK_GE(window_rect.x(), 0);
+ DCHECK_GE(window_rect.y(), 0);
+ DCHECK_LE(window_rect.right(), current_surface_size_.width());
+ DCHECK_LE(window_rect.bottom(), current_surface_size_.height());
if (!request->force_bitmap_result()) {
bool own_mailbox = !request->has_texture_mailbox();
@@ -2212,13 +2385,8 @@ void GLRenderer::GetFramebufferPixelsAsync(
gpu::Mailbox mailbox;
if (own_mailbox) {
GLC(gl_, gl_->GenMailboxCHROMIUM(mailbox.name));
- if (mailbox.IsZero()) {
- gl_->DeleteTextures(1, &texture_id);
- request->SendEmptyResult();
- return;
- }
} else {
- mailbox = request->texture_mailbox().name();
+ mailbox = request->texture_mailbox().mailbox();
DCHECK_EQ(static_cast<unsigned>(GL_TEXTURE_2D),
request->texture_mailbox().target());
DCHECK(!mailbox.IsZero());
@@ -2264,42 +2432,11 @@ void GLRenderer::GetFramebufferPixelsAsync(
DCHECK(request->force_bitmap_result());
- scoped_ptr<SkBitmap> bitmap(new SkBitmap);
- bitmap->setConfig(
- SkBitmap::kARGB_8888_Config, window_rect.width(), window_rect.height());
- bitmap->allocPixels();
-
- scoped_ptr<SkAutoLockPixels> lock(new SkAutoLockPixels(*bitmap));
-
- // Save a pointer to the pixels, the bitmap is owned by the cleanup_callback.
- uint8* pixels = static_cast<uint8*>(bitmap->getPixels());
-
- AsyncGetFramebufferPixelsCleanupCallback cleanup_callback =
- base::Bind(&GLRenderer::PassOnSkBitmap,
- base::Unretained(this),
- base::Passed(&bitmap),
- base::Passed(&lock));
-
scoped_ptr<PendingAsyncReadPixels> pending_read(new PendingAsyncReadPixels);
pending_read->copy_request = request.Pass();
pending_async_read_pixels_.insert(pending_async_read_pixels_.begin(),
pending_read.Pass());
- // This is an asyncronous call since the callback is not null.
- DoGetFramebufferPixels(pixels, window_rect, cleanup_callback);
-}
-
-void GLRenderer::DoGetFramebufferPixels(
- uint8* dest_pixels,
- gfx::Rect window_rect,
- const AsyncGetFramebufferPixelsCleanupCallback& cleanup_callback) {
- DCHECK_GE(window_rect.x(), 0);
- DCHECK_GE(window_rect.y(), 0);
- DCHECK_LE(window_rect.right(), current_surface_size_.width());
- DCHECK_LE(window_rect.bottom(), current_surface_size_.height());
-
- bool is_async = !cleanup_callback.is_null();
-
bool do_workaround = NeedsIOSurfaceReadbackWorkaround();
unsigned temporary_texture = 0;
@@ -2350,10 +2487,8 @@ void GLRenderer::DoGetFramebufferPixels(
GL_STREAM_READ));
GLuint query = 0;
- if (is_async) {
- gl_->GenQueriesEXT(1, &query);
- GLC(gl_, gl_->BeginQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM, query));
- }
+ gl_->GenQueriesEXT(1, &query);
+ GLC(gl_, gl_->BeginQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM, query));
GLC(gl_,
gl_->ReadPixels(window_rect.x(),
@@ -2376,35 +2511,28 @@ void GLRenderer::DoGetFramebufferPixels(
base::Closure finished_callback = base::Bind(&GLRenderer::FinishedReadback,
base::Unretained(this),
- cleanup_callback,
buffer,
query,
- dest_pixels,
window_rect.size());
// Save the finished_callback so it can be cancelled.
pending_async_read_pixels_.front()->finished_read_pixels_callback.Reset(
finished_callback);
+ base::Closure cancelable_callback =
+ pending_async_read_pixels_.front()->
+ finished_read_pixels_callback.callback();
// Save the buffer to verify the callbacks happen in the expected order.
pending_async_read_pixels_.front()->buffer = buffer;
- if (is_async) {
- GLC(gl_, gl_->EndQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM));
- context_support_->SignalQuery(query, finished_callback);
- } else {
- resource_provider_->Finish();
- finished_callback.Run();
- }
+ GLC(gl_, gl_->EndQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM));
+ context_support_->SignalQuery(query, cancelable_callback);
EnforceMemoryPolicy();
}
-void GLRenderer::FinishedReadback(
- const AsyncGetFramebufferPixelsCleanupCallback& cleanup_callback,
- unsigned source_buffer,
- unsigned query,
- uint8* dest_pixels,
- gfx::Size size) {
+void GLRenderer::FinishedReadback(unsigned source_buffer,
+ unsigned query,
+ const gfx::Size& size) {
DCHECK(!pending_async_read_pixels_.empty());
if (query != 0) {
@@ -2416,6 +2544,7 @@ void GLRenderer::FinishedReadback(
DCHECK_EQ(source_buffer, current_read->buffer);
uint8* src_pixels = NULL;
+ scoped_ptr<SkBitmap> bitmap;
if (source_buffer != 0) {
GLC(gl_,
@@ -2424,6 +2553,11 @@ void GLRenderer::FinishedReadback(
GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, GL_READ_ONLY));
if (src_pixels) {
+ bitmap.reset(new SkBitmap);
+ bitmap->allocN32Pixels(size.width(), size.height());
+ scoped_ptr<SkAutoLockPixels> lock(new SkAutoLockPixels(*bitmap));
+ uint8* dest_pixels = static_cast<uint8*>(bitmap->getPixels());
+
size_t row_bytes = size.width() * 4;
int num_rows = size.height();
size_t total_bytes = num_rows * row_bytes;
@@ -2450,28 +2584,14 @@ void GLRenderer::FinishedReadback(
GLC(gl_, gl_->DeleteBuffers(1, &source_buffer));
}
- // TODO(danakj): This can go away when synchronous readback is no more and its
- // contents can just move here.
- if (!cleanup_callback.is_null())
- cleanup_callback.Run(current_read->copy_request.Pass(), src_pixels != NULL);
-
+ if (bitmap)
+ current_read->copy_request->SendBitmapResult(bitmap.Pass());
pending_async_read_pixels_.pop_back();
}
-void GLRenderer::PassOnSkBitmap(scoped_ptr<SkBitmap> bitmap,
- scoped_ptr<SkAutoLockPixels> lock,
- scoped_ptr<CopyOutputRequest> request,
- bool success) {
- DCHECK(request->force_bitmap_result());
-
- lock.reset();
- if (success)
- request->SendBitmapResult(bitmap.Pass());
-}
-
void GLRenderer::GetFramebufferTexture(unsigned texture_id,
ResourceFormat texture_format,
- gfx::Rect window_rect) {
+ const gfx::Rect& window_rect) {
DCHECK(texture_id);
DCHECK_GE(window_rect.x(), 0);
DCHECK_GE(window_rect.y(), 0);
@@ -2493,7 +2613,7 @@ void GLRenderer::GetFramebufferTexture(unsigned texture_id,
bool GLRenderer::UseScopedTexture(DrawingFrame* frame,
const ScopedResource* texture,
- gfx::Rect viewport_rect) {
+ const gfx::Rect& viewport_rect) {
DCHECK(texture->id());
frame->current_render_pass = NULL;
frame->current_texture = texture;
@@ -2515,7 +2635,7 @@ void GLRenderer::BindFramebufferToOutputSurface(DrawingFrame* frame) {
bool GLRenderer::BindFramebufferToTexture(DrawingFrame* frame,
const ScopedResource* texture,
- gfx::Rect target_rect) {
+ const gfx::Rect& target_rect) {
DCHECK(texture->id());
current_framebuffer_lock_.reset();
@@ -2539,7 +2659,7 @@ bool GLRenderer::BindFramebufferToTexture(DrawingFrame* frame,
return true;
}
-void GLRenderer::SetScissorTestRect(gfx::Rect scissor_rect) {
+void GLRenderer::SetScissorTestRect(const gfx::Rect& scissor_rect) {
EnsureScissorTestEnabled();
// Don't unnecessarily ask the context to change the scissor, because it
@@ -2558,7 +2678,7 @@ void GLRenderer::SetScissorTestRect(gfx::Rect scissor_rect) {
scissor_rect_needs_reset_ = false;
}
-void GLRenderer::SetDrawViewport(gfx::Rect window_space_viewport) {
+void GLRenderer::SetDrawViewport(const gfx::Rect& window_space_viewport) {
viewport_ = window_space_viewport;
GLC(gl_,
gl_->Viewport(window_space_viewport.x(),
@@ -2987,28 +3107,83 @@ void GLRenderer::CleanupSharedObjects() {
}
void GLRenderer::ReinitializeGLState() {
- // Bind the common vertex attributes used for drawing all the layers.
+ is_scissor_enabled_ = false;
+ scissor_rect_needs_reset_ = true;
+ stencil_shadow_ = false;
+ blend_shadow_ = true;
+ program_shadow_ = 0;
+
+ RestoreGLState();
+}
+
+void GLRenderer::RestoreGLState() {
+ // This restores the current GLRenderer state to the GL context.
+
shared_geometry_->PrepareForDraw();
GLC(gl_, gl_->Disable(GL_DEPTH_TEST));
GLC(gl_, gl_->Disable(GL_CULL_FACE));
GLC(gl_, gl_->ColorMask(true, true, true, true));
- GLC(gl_, gl_->Disable(GL_STENCIL_TEST));
- stencil_shadow_ = false;
- GLC(gl_, gl_->Enable(GL_BLEND));
- blend_shadow_ = true;
GLC(gl_, gl_->BlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
GLC(gl_, gl_->ActiveTexture(GL_TEXTURE0));
- program_shadow_ = 0;
- // Make sure scissoring starts as disabled.
- is_scissor_enabled_ = false;
- GLC(gl_, gl_->Disable(GL_SCISSOR_TEST));
- scissor_rect_needs_reset_ = true;
+ if (program_shadow_)
+ gl_->UseProgram(program_shadow_);
+
+ if (stencil_shadow_)
+ GLC(gl_, gl_->Enable(GL_STENCIL_TEST));
+ else
+ GLC(gl_, gl_->Disable(GL_STENCIL_TEST));
+
+ if (blend_shadow_)
+ GLC(gl_, gl_->Enable(GL_BLEND));
+ else
+ GLC(gl_, gl_->Disable(GL_BLEND));
+
+ if (is_scissor_enabled_) {
+ GLC(gl_, gl_->Enable(GL_SCISSOR_TEST));
+ GLC(gl_,
+ gl_->Scissor(scissor_rect_.x(),
+ scissor_rect_.y(),
+ scissor_rect_.width(),
+ scissor_rect_.height()));
+ } else {
+ GLC(gl_, gl_->Disable(GL_SCISSOR_TEST));
+ }
+}
+
+void GLRenderer::RestoreFramebuffer(DrawingFrame* frame) {
+ UseRenderPass(frame, frame->current_render_pass);
}
bool GLRenderer::IsContextLost() {
return output_surface_->context_provider()->IsContextLost();
}
+void GLRenderer::ScheduleOverlays(DrawingFrame* frame) {
+ if (!frame->overlay_list.size())
+ return;
+
+ ResourceProvider::ResourceIdArray resources;
+ OverlayCandidateList& overlays = frame->overlay_list;
+ OverlayCandidateList::iterator it;
+ for (it = overlays.begin(); it != overlays.end(); ++it) {
+ const OverlayCandidate& overlay = *it;
+ // Skip primary plane.
+ if (overlay.plane_z_order == 0)
+ continue;
+
+ pending_overlay_resources_.push_back(
+ make_scoped_ptr(new ResourceProvider::ScopedReadLockGL(
+ resource_provider_, overlay.resource_id)));
+
+ context_support_->ScheduleOverlayPlane(
+ overlay.plane_z_order,
+ overlay.transform,
+ pending_overlay_resources_.back()->texture_id(),
+ overlay.display_rect,
+ overlay.uv_rect);
+ }
+}
+
} // namespace cc
diff --git a/chromium/cc/output/gl_renderer.h b/chromium/cc/output/gl_renderer.h
index cf672f0afa4..b798d55b27f 100644
--- a/chromium/cc/output/gl_renderer.h
+++ b/chromium/cc/output/gl_renderer.h
@@ -7,6 +7,7 @@
#include "base/cancelable_callback.h"
#include "cc/base/cc_export.h"
+#include "cc/base/scoped_ptr_deque.h"
#include "cc/base/scoped_ptr_vector.h"
#include "cc/output/direct_renderer.h"
#include "cc/output/gl_renderer_draw_cache.h"
@@ -23,8 +24,6 @@
class SkBitmap;
-namespace blink { class WebGraphicsContext3D; }
-
namespace gpu {
namespace gles2 {
class GLES2Interface;
@@ -46,6 +45,8 @@ class ScopedEnsureFramebufferAllocation;
// Class that handles drawing of composited render layers using GL.
class CC_EXPORT GLRenderer : public DirectRenderer {
public:
+ class ScopedUseGrContext;
+
static scoped_ptr<GLRenderer> Create(
RendererClient* client,
const LayerTreeSettings* settings,
@@ -56,9 +57,7 @@ class CC_EXPORT GLRenderer : public DirectRenderer {
virtual ~GLRenderer();
- virtual const RendererCapabilities& Capabilities() const OVERRIDE;
-
- blink::WebGraphicsContext3D* Context();
+ virtual const RendererCapabilitiesImpl& Capabilities() const OVERRIDE;
// Waits for rendering to finish.
virtual void Finish() OVERRIDE;
@@ -66,16 +65,8 @@ class CC_EXPORT GLRenderer : public DirectRenderer {
virtual void DoNoOp() OVERRIDE;
virtual void SwapBuffers(const CompositorFrameMetadata& metadata) OVERRIDE;
- virtual void GetFramebufferPixels(void* pixels, gfx::Rect rect) OVERRIDE;
-
virtual bool IsContextLost() OVERRIDE;
- virtual void SetVisible(bool visible) OVERRIDE;
-
- virtual void SendManagedMemoryStats(size_t bytes_visible,
- size_t bytes_visible_and_nearby,
- size_t bytes_allocated) OVERRIDE;
-
static void DebugGLCall(gpu::gles2::GLES2Interface* gl,
const char* command,
const char* file,
@@ -89,19 +80,20 @@ class CC_EXPORT GLRenderer : public DirectRenderer {
TextureMailboxDeleter* texture_mailbox_deleter,
int highp_threshold_min);
+ virtual void DidChangeVisibility() OVERRIDE;
+
bool IsBackbufferDiscarded() const { return is_backbuffer_discarded_; }
- void InitializeGrContext();
const gfx::QuadF& SharedGeometryQuad() const { return shared_geometry_quad_; }
const GeometryBinding* SharedGeometry() const {
return shared_geometry_.get();
}
- void GetFramebufferPixelsAsync(gfx::Rect rect,
+ void GetFramebufferPixelsAsync(const gfx::Rect& rect,
scoped_ptr<CopyOutputRequest> request);
void GetFramebufferTexture(unsigned texture_id,
ResourceFormat texture_format,
- gfx::Rect device_rect);
+ const gfx::Rect& device_rect);
void ReleaseRenderPassTextures();
void SetStencilEnabled(bool enabled);
@@ -112,9 +104,9 @@ class CC_EXPORT GLRenderer : public DirectRenderer {
virtual void BindFramebufferToOutputSurface(DrawingFrame* frame) OVERRIDE;
virtual bool BindFramebufferToTexture(DrawingFrame* frame,
const ScopedResource* resource,
- gfx::Rect target_rect) OVERRIDE;
- virtual void SetDrawViewport(gfx::Rect window_space_viewport) OVERRIDE;
- virtual void SetScissorTestRect(gfx::Rect scissor_rect) OVERRIDE;
+ const gfx::Rect& target_rect) OVERRIDE;
+ virtual void SetDrawViewport(const gfx::Rect& window_space_viewport) OVERRIDE;
+ virtual void SetScissorTestRect(const gfx::Rect& scissor_rect) OVERRIDE;
virtual void DiscardPixels(bool has_external_stencil_test,
bool draw_rect_covers_full_surface) OVERRIDE;
virtual void ClearFramebuffer(DrawingFrame* frame,
@@ -186,13 +178,13 @@ class CC_EXPORT GLRenderer : public DirectRenderer {
void CopyTextureToFramebuffer(const DrawingFrame* frame,
int texture_id,
- gfx::Rect rect,
+ const gfx::Rect& rect,
const gfx::Transform& draw_matrix,
bool flip_vertically);
bool UseScopedTexture(DrawingFrame* frame,
const ScopedResource* resource,
- gfx::Rect viewport_rect);
+ const gfx::Rect& viewport_rect);
bool MakeContextCurrent();
@@ -202,28 +194,26 @@ class CC_EXPORT GLRenderer : public DirectRenderer {
typedef base::Callback<void(scoped_ptr<CopyOutputRequest> copy_request,
bool success)>
AsyncGetFramebufferPixelsCleanupCallback;
- void DoGetFramebufferPixels(
- uint8* pixels,
- gfx::Rect window_rect,
- const AsyncGetFramebufferPixelsCleanupCallback& cleanup_callback);
- void FinishedReadback(
- const AsyncGetFramebufferPixelsCleanupCallback& cleanup_callback,
- unsigned source_buffer,
- unsigned query,
- uint8_t* dest_pixels,
- gfx::Size size);
- void PassOnSkBitmap(scoped_ptr<SkBitmap> bitmap,
- scoped_ptr<SkAutoLockPixels> lock,
- scoped_ptr<CopyOutputRequest> request,
- bool success);
+ void FinishedReadback(unsigned source_buffer,
+ unsigned query,
+ const gfx::Size& size);
void ReinitializeGLState();
+ void RestoreGLState();
+ void RestoreFramebuffer(DrawingFrame* frame);
virtual void DiscardBackbuffer() OVERRIDE;
virtual void EnsureBackbuffer() OVERRIDE;
void EnforceMemoryPolicy();
- RendererCapabilities capabilities_;
+ void ScheduleOverlays(DrawingFrame* frame);
+
+ typedef ScopedPtrVector<ResourceProvider::ScopedReadLockGL>
+ OverlayResourceLockList;
+ OverlayResourceLockList pending_overlay_resources_;
+ OverlayResourceLockList in_use_overlay_resources_;
+
+ RendererCapabilitiesImpl capabilities_;
unsigned offscreen_framebuffer_id_;
@@ -289,10 +279,10 @@ class CC_EXPORT GLRenderer : public DirectRenderer {
// Video shaders.
typedef ProgramBinding<VertexShaderVideoTransform, FragmentShaderRGBATex>
VideoStreamTextureProgram;
- typedef ProgramBinding<VertexShaderPosTexYUVStretch, FragmentShaderYUVVideo>
- VideoYUVProgram;
- typedef ProgramBinding<VertexShaderPosTexYUVStretch, FragmentShaderYUVAVideo>
- VideoYUVAProgram;
+ typedef ProgramBinding<VertexShaderPosTexYUVStretchOffset,
+ FragmentShaderYUVVideo> VideoYUVProgram;
+ typedef ProgramBinding<VertexShaderPosTexYUVStretchOffset,
+ FragmentShaderYUVAVideo> VideoYUVAProgram;
// Special purpose / effects shaders.
typedef ProgramBinding<VertexShaderPos, FragmentShaderColor>
@@ -399,7 +389,6 @@ class CC_EXPORT GLRenderer : public DirectRenderer {
SolidColorProgram solid_color_program_;
SolidColorProgramAA solid_color_program_aa_;
- blink::WebGraphicsContext3D* context_;
gpu::gles2::GLES2Interface* gl_;
gpu::ContextSupport* context_support_;
@@ -413,7 +402,6 @@ class CC_EXPORT GLRenderer : public DirectRenderer {
gfx::Rect viewport_;
bool is_backbuffer_discarded_;
bool is_using_bind_uniform_;
- bool visible_;
bool is_scissor_enabled_;
bool scissor_rect_needs_reset_;
bool stencil_shadow_;
@@ -428,7 +416,11 @@ class CC_EXPORT GLRenderer : public DirectRenderer {
scoped_ptr<ResourceProvider::ScopedWriteLockGL> current_framebuffer_lock_;
- scoped_refptr<ResourceProvider::Fence> last_swap_fence_;
+ class SyncQuery;
+ ScopedPtrDeque<SyncQuery> pending_sync_queries_;
+ ScopedPtrDeque<SyncQuery> available_sync_queries_;
+ scoped_ptr<SyncQuery> current_sync_query_;
+ bool use_sync_query_;
SkBitmap on_demand_tile_raster_bitmap_;
ResourceProvider::ResourceId on_demand_tile_raster_resource_id_;
diff --git a/chromium/cc/output/gl_renderer_unittest.cc b/chromium/cc/output/gl_renderer_unittest.cc
index f165e153bf0..445695cbcb1 100644
--- a/chromium/cc/output/gl_renderer_unittest.cc
+++ b/chromium/cc/output/gl_renderer_unittest.cc
@@ -14,10 +14,12 @@
#include "cc/test/fake_layer_tree_host_impl.h"
#include "cc/test/fake_output_surface.h"
#include "cc/test/fake_output_surface_client.h"
+#include "cc/test/fake_renderer_client.h"
#include "cc/test/mock_quad_culler.h"
#include "cc/test/pixel_test.h"
#include "cc/test/render_pass_test_common.h"
#include "cc/test/render_pass_test_utils.h"
+#include "cc/test/test_shared_bitmap_manager.h"
#include "cc/test/test_web_graphics_context_3d.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "gpu/command_buffer/client/context_support.h"
@@ -40,18 +42,6 @@ using testing::InSequence;
using testing::Mock;
using testing::Return;
using testing::StrictMock;
-using blink::WebGLId;
-using blink::WebString;
-using blink::WGC3Dbitfield;
-using blink::WGC3Dboolean;
-using blink::WGC3Dchar;
-using blink::WGC3Denum;
-using blink::WGC3Dfloat;
-using blink::WGC3Dint;
-using blink::WGC3Dintptr;
-using blink::WGC3Dsizei;
-using blink::WGC3Dsizeiptr;
-using blink::WGC3Duint;
namespace cc {
@@ -135,24 +125,6 @@ namespace {
TEST_F(GLRendererShaderPixelTest, AllShadersCompile) { TestShaders(); }
#endif
-class FakeRendererClient : public RendererClient {
- public:
- FakeRendererClient() : set_full_root_layer_damage_count_(0) {}
-
- // RendererClient methods.
- virtual void SetFullRootLayerDamage() OVERRIDE {
- set_full_root_layer_damage_count_++;
- }
-
- // Methods added for test.
- int set_full_root_layer_damage_count() const {
- return set_full_root_layer_damage_count_;
- }
-
- private:
- int set_full_root_layer_damage_count_;
-};
-
class FakeRendererGL : public GLRenderer {
public:
FakeRendererGL(RendererClient* client,
@@ -179,12 +151,15 @@ class FakeRendererGL : public GLRenderer {
class GLRendererWithDefaultHarnessTest : public GLRendererTest {
protected:
GLRendererWithDefaultHarnessTest() {
- output_surface_ = FakeOutputSurface::Create3d(
- TestWebGraphicsContext3D::Create()).Pass();
+ output_surface_ =
+ FakeOutputSurface::Create3d(TestWebGraphicsContext3D::Create()).Pass();
CHECK(output_surface_->BindToClient(&output_surface_client_));
- resource_provider_ = ResourceProvider::Create(
- output_surface_.get(), NULL, 0, false, 1).Pass();
+ shared_bitmap_manager_.reset(new TestSharedBitmapManager());
+ resource_provider_ =
+ ResourceProvider::Create(
+ output_surface_.get(), shared_bitmap_manager_.get(), 0, false, 1,
+ false).Pass();
renderer_ = make_scoped_ptr(new FakeRendererGL(&renderer_client_,
&settings_,
output_surface_.get(),
@@ -197,6 +172,7 @@ class GLRendererWithDefaultHarnessTest : public GLRendererTest {
FakeOutputSurfaceClient output_surface_client_;
scoped_ptr<FakeOutputSurface> output_surface_;
FakeRendererClient renderer_client_;
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager_;
scoped_ptr<ResourceProvider> resource_provider_;
scoped_ptr<FakeRendererGL> renderer_;
};
@@ -212,8 +188,11 @@ class GLRendererShaderTest : public GLRendererTest {
output_surface_ = FakeOutputSurface::Create3d().Pass();
CHECK(output_surface_->BindToClient(&output_surface_client_));
- resource_provider_ = ResourceProvider::Create(
- output_surface_.get(), NULL, 0, false, 1).Pass();
+ shared_bitmap_manager_.reset(new TestSharedBitmapManager());
+ resource_provider_ =
+ ResourceProvider::Create(
+ output_surface_.get(), shared_bitmap_manager_.get(), 0, false, 1,
+ false).Pass();
renderer_.reset(new FakeRendererGL(&renderer_client_,
&settings_,
output_surface_.get(),
@@ -285,6 +264,7 @@ class GLRendererShaderTest : public GLRendererTest {
FakeOutputSurfaceClient output_surface_client_;
scoped_ptr<FakeOutputSurface> output_surface_;
FakeRendererClient renderer_client_;
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager_;
scoped_ptr<ResourceProvider> resource_provider_;
scoped_ptr<FakeRendererGL> renderer_;
};
@@ -343,11 +323,9 @@ TEST_F(GLRendererWithDefaultHarnessTest,
renderer_->SetVisible(true);
renderer_->DrawFrame(&render_passes_in_draw_order_,
- NULL,
1.f,
viewport_rect,
viewport_rect,
- true,
false);
EXPECT_FALSE(renderer_->IsBackbufferDiscarded());
@@ -355,33 +333,6 @@ TEST_F(GLRendererWithDefaultHarnessTest,
EXPECT_EQ(1u, output_surface_->num_sent_frames());
}
-TEST_F(GLRendererWithDefaultHarnessTest,
- FramebufferDiscardedAfterReadbackWhenNotVisible) {
- gfx::Rect viewport_rect(1, 1);
- renderer_->SetVisible(false);
- EXPECT_TRUE(renderer_->IsBackbufferDiscarded());
- EXPECT_EQ(1, renderer_client_.set_full_root_layer_damage_count());
-
- AddRenderPass(&render_passes_in_draw_order_,
- RenderPass::Id(1, 0),
- viewport_rect,
- gfx::Transform());
-
- char pixels[4];
- renderer_->DrawFrame(&render_passes_in_draw_order_,
- NULL,
- 1.f,
- viewport_rect,
- viewport_rect,
- true,
- false);
- EXPECT_FALSE(renderer_->IsBackbufferDiscarded());
-
- renderer_->GetFramebufferPixels(pixels, gfx::Rect(0, 0, 1, 1));
- EXPECT_TRUE(renderer_->IsBackbufferDiscarded());
- EXPECT_EQ(2, renderer_client_.set_full_root_layer_damage_count());
-}
-
TEST_F(GLRendererWithDefaultHarnessTest, ExternalStencil) {
gfx::Rect viewport_rect(1, 1);
EXPECT_FALSE(renderer_->stencil_enabled());
@@ -395,11 +346,9 @@ TEST_F(GLRendererWithDefaultHarnessTest, ExternalStencil) {
root_pass->has_transparent_background = false;
renderer_->DrawFrame(&render_passes_in_draw_order_,
- NULL,
1.f,
viewport_rect,
viewport_rect,
- true,
false);
EXPECT_TRUE(renderer_->stencil_enabled());
}
@@ -408,52 +357,38 @@ class ForbidSynchronousCallContext : public TestWebGraphicsContext3D {
public:
ForbidSynchronousCallContext() {}
- virtual bool getActiveAttrib(WebGLId program,
- WGC3Duint index,
- ActiveInfo& info) {
- ADD_FAILURE();
- return false;
- }
- virtual bool getActiveUniform(WebGLId program,
- WGC3Duint index,
- ActiveInfo& info) {
- ADD_FAILURE();
- return false;
- }
- virtual void getAttachedShaders(WebGLId program,
- WGC3Dsizei max_count,
- WGC3Dsizei* count,
- WebGLId* shaders) {
+ virtual void getAttachedShaders(GLuint program,
+ GLsizei max_count,
+ GLsizei* count,
+ GLuint* shaders) OVERRIDE {
ADD_FAILURE();
}
- virtual WGC3Dint getAttribLocation(WebGLId program, const WGC3Dchar* name) {
+ virtual GLint getAttribLocation(GLuint program, const GLchar* name) OVERRIDE {
ADD_FAILURE();
return 0;
}
- virtual void getBooleanv(WGC3Denum pname, WGC3Dboolean* value) {
+ virtual void getBooleanv(GLenum pname, GLboolean* value) OVERRIDE {
ADD_FAILURE();
}
- virtual void getBufferParameteriv(WGC3Denum target,
- WGC3Denum pname,
- WGC3Dint* value) {
+ virtual void getBufferParameteriv(GLenum target,
+ GLenum pname,
+ GLint* value) OVERRIDE {
ADD_FAILURE();
}
- virtual Attributes getContextAttributes() {
+ virtual GLenum getError() OVERRIDE {
ADD_FAILURE();
- return attributes_;
+ return GL_NO_ERROR;
}
- virtual WGC3Denum getError() {
+ virtual void getFloatv(GLenum pname, GLfloat* value) OVERRIDE {
ADD_FAILURE();
- return 0;
}
- virtual void getFloatv(WGC3Denum pname, WGC3Dfloat* value) { ADD_FAILURE(); }
- virtual void getFramebufferAttachmentParameteriv(WGC3Denum target,
- WGC3Denum attachment,
- WGC3Denum pname,
- WGC3Dint* value) {
+ virtual void getFramebufferAttachmentParameteriv(GLenum target,
+ GLenum attachment,
+ GLenum pname,
+ GLint* value) OVERRIDE {
ADD_FAILURE();
}
- virtual void getIntegerv(WGC3Denum pname, WGC3Dint* value) {
+ virtual void getIntegerv(GLenum pname, GLint* value) OVERRIDE {
if (pname == GL_MAX_TEXTURE_SIZE) {
// MAX_TEXTURE_SIZE is cached client side, so it's OK to query.
*value = 1024;
@@ -464,7 +399,9 @@ class ForbidSynchronousCallContext : public TestWebGraphicsContext3D {
// We allow querying the shader compilation and program link status in debug
// mode, but not release.
- virtual void getProgramiv(WebGLId program, WGC3Denum pname, WGC3Dint* value) {
+ virtual void getProgramiv(GLuint program,
+ GLenum pname,
+ GLint* value) OVERRIDE {
#ifndef NDEBUG
*value = 1;
#else
@@ -472,7 +409,7 @@ class ForbidSynchronousCallContext : public TestWebGraphicsContext3D {
#endif
}
- virtual void getShaderiv(WebGLId shader, WGC3Denum pname, WGC3Dint* value) {
+ virtual void getShaderiv(GLuint shader, GLenum pname, GLint* value) OVERRIDE {
#ifndef NDEBUG
*value = 1;
#else
@@ -480,84 +417,69 @@ class ForbidSynchronousCallContext : public TestWebGraphicsContext3D {
#endif
}
- virtual WebString getString(WGC3Denum name) {
- ADD_FAILURE() << name;
- return WebString();
- }
-
- virtual WebString getProgramInfoLog(WebGLId program) {
- ADD_FAILURE();
- return WebString();
- }
- virtual void getRenderbufferParameteriv(WGC3Denum target,
- WGC3Denum pname,
- WGC3Dint* value) {
+ virtual void getRenderbufferParameteriv(GLenum target,
+ GLenum pname,
+ GLint* value) OVERRIDE {
ADD_FAILURE();
}
- virtual WebString getShaderInfoLog(WebGLId shader) {
+ virtual void getShaderPrecisionFormat(GLenum shadertype,
+ GLenum precisiontype,
+ GLint* range,
+ GLint* precision) OVERRIDE {
ADD_FAILURE();
- return WebString();
}
- virtual void getShaderPrecisionFormat(WGC3Denum shadertype,
- WGC3Denum precisiontype,
- WGC3Dint* range,
- WGC3Dint* precision) {
+ virtual void getTexParameterfv(GLenum target,
+ GLenum pname,
+ GLfloat* value) OVERRIDE {
ADD_FAILURE();
}
- virtual WebString getShaderSource(WebGLId shader) {
+ virtual void getTexParameteriv(GLenum target,
+ GLenum pname,
+ GLint* value) OVERRIDE {
ADD_FAILURE();
- return WebString();
}
- virtual void getTexParameterfv(WGC3Denum target,
- WGC3Denum pname,
- WGC3Dfloat* value) {
+ virtual void getUniformfv(GLuint program,
+ GLint location,
+ GLfloat* value) OVERRIDE {
ADD_FAILURE();
}
- virtual void getTexParameteriv(WGC3Denum target,
- WGC3Denum pname,
- WGC3Dint* value) {
+ virtual void getUniformiv(GLuint program,
+ GLint location,
+ GLint* value) OVERRIDE {
ADD_FAILURE();
}
- virtual void getUniformfv(WebGLId program,
- WGC3Dint location,
- WGC3Dfloat* value) {
- ADD_FAILURE();
- }
- virtual void getUniformiv(WebGLId program,
- WGC3Dint location,
- WGC3Dint* value) {
- ADD_FAILURE();
- }
- virtual WGC3Dint getUniformLocation(WebGLId program, const WGC3Dchar* name) {
+ virtual GLint getUniformLocation(GLuint program,
+ const GLchar* name) OVERRIDE {
ADD_FAILURE();
return 0;
}
- virtual void getVertexAttribfv(WGC3Duint index,
- WGC3Denum pname,
- WGC3Dfloat* value) {
+ virtual void getVertexAttribfv(GLuint index,
+ GLenum pname,
+ GLfloat* value) OVERRIDE {
ADD_FAILURE();
}
- virtual void getVertexAttribiv(WGC3Duint index,
- WGC3Denum pname,
- WGC3Dint* value) {
+ virtual void getVertexAttribiv(GLuint index,
+ GLenum pname,
+ GLint* value) OVERRIDE {
ADD_FAILURE();
}
- virtual WGC3Dsizeiptr getVertexAttribOffset(WGC3Duint index,
- WGC3Denum pname) {
+ virtual GLsizeiptr getVertexAttribOffset(GLuint index,
+ GLenum pname) OVERRIDE {
ADD_FAILURE();
return 0;
}
};
-
TEST_F(GLRendererTest, InitializationDoesNotMakeSynchronousCalls) {
FakeOutputSurfaceClient output_surface_client;
scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
scoped_ptr<TestWebGraphicsContext3D>(new ForbidSynchronousCallContext)));
CHECK(output_surface->BindToClient(&output_surface_client));
- scoped_ptr<ResourceProvider> resource_provider(
- ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1));
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
+ scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
+ output_surface.get(), shared_bitmap_manager.get(), 0, false, 1, false));
LayerTreeSettings settings;
FakeRendererClient renderer_client;
@@ -571,16 +493,14 @@ class LoseContextOnFirstGetContext : public TestWebGraphicsContext3D {
public:
LoseContextOnFirstGetContext() {}
- virtual void getProgramiv(WebGLId program,
- WGC3Denum pname,
- WGC3Dint* value) OVERRIDE {
+ virtual void getProgramiv(GLuint program,
+ GLenum pname,
+ GLint* value) OVERRIDE {
context_lost_ = true;
*value = 0;
}
- virtual void getShaderiv(WebGLId shader,
- WGC3Denum pname,
- WGC3Dint* value) OVERRIDE {
+ virtual void getShaderiv(GLuint shader, GLenum pname, GLint* value) OVERRIDE {
context_lost_ = true;
*value = 0;
}
@@ -592,8 +512,10 @@ TEST_F(GLRendererTest, InitializationWithQuicklyLostContextDoesNotAssert) {
scoped_ptr<TestWebGraphicsContext3D>(new LoseContextOnFirstGetContext)));
CHECK(output_surface->BindToClient(&output_surface_client));
- scoped_ptr<ResourceProvider> resource_provider(
- ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1));
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
+ scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
+ output_surface.get(), shared_bitmap_manager.get(), 0, false, 1, false));
LayerTreeSettings settings;
FakeRendererClient renderer_client;
@@ -605,13 +527,13 @@ TEST_F(GLRendererTest, InitializationWithQuicklyLostContextDoesNotAssert) {
class ClearCountingContext : public TestWebGraphicsContext3D {
public:
- ClearCountingContext() { test_capabilities_.discard_framebuffer = true; }
+ ClearCountingContext() { test_capabilities_.gpu.discard_framebuffer = true; }
MOCK_METHOD3(discardFramebufferEXT,
- void(WGC3Denum target,
- WGC3Dsizei numAttachments,
- const WGC3Denum* attachments));
- MOCK_METHOD1(clear, void(WGC3Dbitfield mask));
+ void(GLenum target,
+ GLsizei numAttachments,
+ const GLenum* attachments));
+ MOCK_METHOD1(clear, void(GLbitfield mask));
};
TEST_F(GLRendererTest, OpaqueBackground) {
@@ -623,8 +545,10 @@ TEST_F(GLRendererTest, OpaqueBackground) {
context_owned.PassAs<TestWebGraphicsContext3D>()));
CHECK(output_surface->BindToClient(&output_surface_client));
- scoped_ptr<ResourceProvider> resource_provider(
- ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1));
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
+ scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
+ output_surface.get(), shared_bitmap_manager.get(), 0, false, 1, false));
LayerTreeSettings settings;
FakeRendererClient renderer_client;
@@ -651,11 +575,9 @@ TEST_F(GLRendererTest, OpaqueBackground) {
EXPECT_CALL(*context, clear(_)).Times(1);
#endif
renderer.DrawFrame(&render_passes_in_draw_order_,
- NULL,
1.f,
viewport_rect,
viewport_rect,
- true,
false);
Mock::VerifyAndClearExpectations(context);
}
@@ -669,8 +591,10 @@ TEST_F(GLRendererTest, TransparentBackground) {
context_owned.PassAs<TestWebGraphicsContext3D>()));
CHECK(output_surface->BindToClient(&output_surface_client));
- scoped_ptr<ResourceProvider> resource_provider(
- ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1));
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
+ scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
+ output_surface.get(), shared_bitmap_manager.get(), 0, false, 1, false));
LayerTreeSettings settings;
FakeRendererClient renderer_client;
@@ -689,11 +613,9 @@ TEST_F(GLRendererTest, TransparentBackground) {
EXPECT_CALL(*context, discardFramebufferEXT(GL_FRAMEBUFFER, 1, _)).Times(1);
EXPECT_CALL(*context, clear(_)).Times(1);
renderer.DrawFrame(&render_passes_in_draw_order_,
- NULL,
1.f,
viewport_rect,
viewport_rect,
- true,
false);
Mock::VerifyAndClearExpectations(context);
@@ -708,8 +630,10 @@ TEST_F(GLRendererTest, OffscreenOutputSurface) {
context_owned.PassAs<TestWebGraphicsContext3D>()));
CHECK(output_surface->BindToClient(&output_surface_client));
- scoped_ptr<ResourceProvider> resource_provider(
- ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1));
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
+ scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
+ output_surface.get(), shared_bitmap_manager.get(), 0, false, 1, false));
LayerTreeSettings settings;
FakeRendererClient renderer_client;
@@ -729,11 +653,9 @@ TEST_F(GLRendererTest, OffscreenOutputSurface) {
.Times(1);
EXPECT_CALL(*context, clear(_)).Times(AnyNumber());
renderer.DrawFrame(&render_passes_in_draw_order_,
- NULL,
1.f,
viewport_rect,
viewport_rect,
- true,
false);
Mock::VerifyAndClearExpectations(context);
}
@@ -744,20 +666,18 @@ class VisibilityChangeIsLastCallTrackingContext
VisibilityChangeIsLastCallTrackingContext()
: last_call_was_set_visibility_(false) {}
- // WebGraphicsContext3D methods.
- virtual void flush() {
+ // TestWebGraphicsContext3D methods.
+ virtual void flush() OVERRIDE { last_call_was_set_visibility_ = false; }
+ virtual void deleteTexture(GLuint) OVERRIDE {
last_call_was_set_visibility_ = false;
}
- virtual void deleteTexture(WebGLId) {
+ virtual void deleteFramebuffer(GLuint) OVERRIDE {
last_call_was_set_visibility_ = false;
}
- virtual void deleteFramebuffer(WebGLId) {
+ virtual void deleteQueryEXT(GLuint) OVERRIDE {
last_call_was_set_visibility_ = false;
}
- virtual void deleteQueryEXT(WebGLId) {
- last_call_was_set_visibility_ = false;
- }
- virtual void deleteRenderbuffer(WebGLId) {
+ virtual void deleteRenderbuffer(GLuint) OVERRIDE {
last_call_was_set_visibility_ = false;
}
@@ -787,12 +707,14 @@ TEST_F(GLRendererTest, VisibilityChangeIsLastCall) {
base::Unretained(context)));
FakeOutputSurfaceClient output_surface_client;
- scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
- provider));
+ scoped_ptr<OutputSurface> output_surface(
+ FakeOutputSurface::Create3d(provider));
CHECK(output_surface->BindToClient(&output_surface_client));
- scoped_ptr<ResourceProvider> resource_provider(
- ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1));
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
+ scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
+ output_surface.get(), shared_bitmap_manager.get(), 0, false, 1, false));
LayerTreeSettings settings;
FakeRendererClient renderer_client;
@@ -814,11 +736,9 @@ TEST_F(GLRendererTest, VisibilityChangeIsLastCall) {
// the stack.
renderer.SetVisible(true);
renderer.DrawFrame(&render_passes_in_draw_order_,
- NULL,
1.f,
viewport_rect,
viewport_rect,
- true,
false);
renderer.SetVisible(false);
EXPECT_TRUE(context->last_call_was_set_visibility());
@@ -827,26 +747,22 @@ TEST_F(GLRendererTest, VisibilityChangeIsLastCall) {
class TextureStateTrackingContext : public TestWebGraphicsContext3D {
public:
TextureStateTrackingContext() : active_texture_(GL_INVALID_ENUM) {
- test_capabilities_.egl_image_external = true;
+ test_capabilities_.gpu.egl_image_external = true;
}
- MOCK_METHOD3(texParameteri,
- void(WGC3Denum target, WGC3Denum pname, WGC3Dint param));
+ MOCK_METHOD3(texParameteri, void(GLenum target, GLenum pname, GLint param));
MOCK_METHOD4(drawElements,
- void(WGC3Denum mode,
- WGC3Dsizei count,
- WGC3Denum type,
- WGC3Dintptr offset));
+ void(GLenum mode, GLsizei count, GLenum type, GLintptr offset));
- virtual void activeTexture(WGC3Denum texture) {
+ virtual void activeTexture(GLenum texture) {
EXPECT_NE(texture, active_texture_);
active_texture_ = texture;
}
- WGC3Denum active_texture() const { return active_texture_; }
+ GLenum active_texture() const { return active_texture_; }
private:
- WGC3Denum active_texture_;
+ GLenum active_texture_;
};
TEST_F(GLRendererTest, ActiveTextureState) {
@@ -859,8 +775,10 @@ TEST_F(GLRendererTest, ActiveTextureState) {
context_owned.PassAs<TestWebGraphicsContext3D>()));
CHECK(output_surface->BindToClient(&output_surface_client));
- scoped_ptr<ResourceProvider> resource_provider(
- ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1));
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
+ scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
+ output_surface.get(), shared_bitmap_manager.get(), 0, false, 1, false));
LayerTreeSettings settings;
FakeRendererClient renderer_client;
@@ -912,23 +830,18 @@ TEST_F(GLRendererTest, ActiveTextureState) {
gfx::Rect viewport_rect(100, 100);
renderer.DrawFrame(&render_passes_in_draw_order_,
- NULL,
1.f,
viewport_rect,
viewport_rect,
- true,
false);
Mock::VerifyAndClearExpectations(context);
}
class NoClearRootRenderPassMockContext : public TestWebGraphicsContext3D {
public:
- MOCK_METHOD1(clear, void(WGC3Dbitfield mask));
+ MOCK_METHOD1(clear, void(GLbitfield mask));
MOCK_METHOD4(drawElements,
- void(WGC3Denum mode,
- WGC3Dsizei count,
- WGC3Denum type,
- WGC3Dintptr offset));
+ void(GLenum mode, GLsizei count, GLenum type, GLintptr offset));
};
TEST_F(GLRendererTest, ShouldClearRootRenderPass) {
@@ -941,8 +854,10 @@ TEST_F(GLRendererTest, ShouldClearRootRenderPass) {
mock_context_owned.PassAs<TestWebGraphicsContext3D>()));
CHECK(output_surface->BindToClient(&output_surface_client));
- scoped_ptr<ResourceProvider> resource_provider(
- ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1));
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
+ scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
+ output_surface.get(), shared_bitmap_manager.get(), 0, false, 1, false));
LayerTreeSettings settings;
settings.should_clear_root_render_pass = false;
@@ -992,11 +907,9 @@ TEST_F(GLRendererTest, ShouldClearRootRenderPass) {
renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
renderer.DrawFrame(&render_passes_in_draw_order_,
- NULL,
1.f,
viewport_rect,
viewport_rect,
- true,
false);
// In multiple render passes all but the root pass should clear the
@@ -1008,14 +921,14 @@ class ScissorTestOnClearCheckingContext : public TestWebGraphicsContext3D {
public:
ScissorTestOnClearCheckingContext() : scissor_enabled_(false) {}
- virtual void clear(WGC3Dbitfield) { EXPECT_FALSE(scissor_enabled_); }
+ virtual void clear(GLbitfield) OVERRIDE { EXPECT_FALSE(scissor_enabled_); }
- virtual void enable(WGC3Denum cap) {
+ virtual void enable(GLenum cap) OVERRIDE {
if (cap == GL_SCISSOR_TEST)
scissor_enabled_ = true;
}
- virtual void disable(WGC3Denum cap) {
+ virtual void disable(GLenum cap) OVERRIDE {
if (cap == GL_SCISSOR_TEST)
scissor_enabled_ = false;
}
@@ -1033,8 +946,10 @@ TEST_F(GLRendererTest, ScissorTestWhenClearing) {
context_owned.PassAs<TestWebGraphicsContext3D>()));
CHECK(output_surface->BindToClient(&output_surface_client));
- scoped_ptr<ResourceProvider> resource_provider(
- ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1));
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
+ scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
+ output_surface.get(), shared_bitmap_manager.get(), 0, false, 1, false));
LayerTreeSettings settings;
FakeRendererClient renderer_client;
@@ -1075,11 +990,9 @@ TEST_F(GLRendererTest, ScissorTestWhenClearing) {
renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
renderer.DrawFrame(&render_passes_in_draw_order_,
- NULL,
1.f,
viewport_rect,
viewport_rect,
- true,
false);
}
@@ -1090,9 +1003,9 @@ class DiscardCheckingContext : public TestWebGraphicsContext3D {
set_have_discard_framebuffer(true);
}
- virtual void discardFramebufferEXT(WGC3Denum target,
- WGC3Dsizei numAttachments,
- const WGC3Denum* attachments) {
+ virtual void discardFramebufferEXT(GLenum target,
+ GLsizei numAttachments,
+ const GLenum* attachments) OVERRIDE {
++discarded_;
}
@@ -1111,8 +1024,8 @@ class NonReshapableOutputSurface : public FakeOutputSurface {
false) {
surface_size_ = gfx::Size(500, 500);
}
- virtual void Reshape(gfx::Size size, float scale_factor) OVERRIDE {}
- void set_fixed_size(gfx::Size size) { surface_size_ = size; }
+ virtual void Reshape(const gfx::Size& size, float scale_factor) OVERRIDE {}
+ void set_fixed_size(const gfx::Size& size) { surface_size_ = size; }
};
TEST_F(GLRendererTest, NoDiscardOnPartialUpdates) {
@@ -1126,8 +1039,10 @@ TEST_F(GLRendererTest, NoDiscardOnPartialUpdates) {
CHECK(output_surface->BindToClient(&output_surface_client));
output_surface->set_fixed_size(gfx::Size(100, 100));
- scoped_ptr<ResourceProvider> resource_provider(
- ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1));
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
+ scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
+ output_surface.get(), shared_bitmap_manager.get(), 0, false, 1, false));
LayerTreeSettings settings;
settings.partial_swap_enabled = true;
@@ -1149,15 +1064,13 @@ TEST_F(GLRendererTest, NoDiscardOnPartialUpdates) {
viewport_rect,
gfx::Transform());
AddQuad(root_pass, viewport_rect, SK_ColorGREEN);
- root_pass->damage_rect = gfx::RectF(2.f, 2.f, 3.f, 3.f);
+ root_pass->damage_rect = gfx::Rect(2, 2, 3, 3);
renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
renderer.DrawFrame(&render_passes_in_draw_order_,
- NULL,
1.f,
viewport_rect,
clip_rect,
- true,
false);
EXPECT_EQ(0, context->discarded());
context->reset();
@@ -1170,36 +1083,13 @@ TEST_F(GLRendererTest, NoDiscardOnPartialUpdates) {
viewport_rect,
gfx::Transform());
AddQuad(root_pass, viewport_rect, SK_ColorGREEN);
- root_pass->damage_rect = gfx::RectF(root_pass->output_rect);
-
- renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
- renderer.DrawFrame(&render_passes_in_draw_order_,
- NULL,
- 1.f,
- viewport_rect,
- clip_rect,
- true,
- false);
- EXPECT_EQ(1, context->discarded());
- context->reset();
- }
- {
- // Partial frame, disallow partial swap, should discard.
- RenderPass::Id root_pass_id(1, 0);
- TestRenderPass* root_pass = AddRenderPass(&render_passes_in_draw_order_,
- root_pass_id,
- viewport_rect,
- gfx::Transform());
- AddQuad(root_pass, viewport_rect, SK_ColorGREEN);
- root_pass->damage_rect = gfx::RectF(2.f, 2.f, 3.f, 3.f);
+ root_pass->damage_rect = root_pass->output_rect;
renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
renderer.DrawFrame(&render_passes_in_draw_order_,
- NULL,
1.f,
viewport_rect,
clip_rect,
- false,
false);
EXPECT_EQ(1, context->discarded());
context->reset();
@@ -1213,16 +1103,14 @@ TEST_F(GLRendererTest, NoDiscardOnPartialUpdates) {
viewport_rect,
gfx::Transform());
AddQuad(root_pass, viewport_rect, SK_ColorGREEN);
- root_pass->damage_rect = gfx::RectF(root_pass->output_rect);
+ root_pass->damage_rect = root_pass->output_rect;
root_pass->has_transparent_background = false;
renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
renderer.DrawFrame(&render_passes_in_draw_order_,
- NULL,
1.f,
viewport_rect,
clip_rect,
- true,
false);
EXPECT_EQ(0, context->discarded());
context->reset();
@@ -1237,15 +1125,13 @@ TEST_F(GLRendererTest, NoDiscardOnPartialUpdates) {
viewport_rect,
gfx::Transform());
AddQuad(root_pass, viewport_rect, SK_ColorGREEN);
- root_pass->damage_rect = gfx::RectF(root_pass->output_rect);
+ root_pass->damage_rect = root_pass->output_rect;
renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
renderer.DrawFrame(&render_passes_in_draw_order_,
- NULL,
1.f,
viewport_rect,
clip_rect,
- true,
false);
EXPECT_EQ(0, context->discarded());
context->reset();
@@ -1259,15 +1145,13 @@ TEST_F(GLRendererTest, NoDiscardOnPartialUpdates) {
viewport_rect,
gfx::Transform());
AddQuad(root_pass, viewport_rect, SK_ColorGREEN);
- root_pass->damage_rect = gfx::RectF(root_pass->output_rect);
+ root_pass->damage_rect = root_pass->output_rect;
renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
renderer.DrawFrame(&render_passes_in_draw_order_,
- NULL,
1.f,
viewport_rect,
clip_rect,
- true,
false);
EXPECT_EQ(0, context->discarded());
context->reset();
@@ -1282,15 +1166,13 @@ TEST_F(GLRendererTest, NoDiscardOnPartialUpdates) {
viewport_rect,
gfx::Transform());
AddQuad(root_pass, viewport_rect, SK_ColorGREEN);
- root_pass->damage_rect = gfx::RectF(root_pass->output_rect);
+ root_pass->damage_rect = root_pass->output_rect;
renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
renderer.DrawFrame(&render_passes_in_draw_order_,
- NULL,
1.f,
viewport_rect,
clip_rect,
- true,
false);
EXPECT_EQ(0, context->discarded());
context->reset();
@@ -1306,7 +1188,8 @@ class FlippedScissorAndViewportContext : public TestWebGraphicsContext3D {
EXPECT_TRUE(did_call_scissor_);
}
- virtual void viewport(GLint x, GLint y, GLsizei width, GLsizei height) {
+ virtual void viewport(GLint x, GLint y, GLsizei width, GLsizei height)
+ OVERRIDE {
EXPECT_EQ(10, x);
EXPECT_EQ(390, y);
EXPECT_EQ(100, width);
@@ -1314,7 +1197,8 @@ class FlippedScissorAndViewportContext : public TestWebGraphicsContext3D {
did_call_viewport_ = true;
}
- virtual void scissor(GLint x, GLint y, GLsizei width, GLsizei height) {
+ virtual void scissor(GLint x, GLint y, GLsizei width, GLsizei height)
+ OVERRIDE {
EXPECT_EQ(30, x);
EXPECT_EQ(450, y);
EXPECT_EQ(20, width);
@@ -1340,8 +1224,10 @@ TEST_F(GLRendererTest, ScissorAndViewportWithinNonreshapableSurface) {
context_owned.PassAs<TestWebGraphicsContext3D>()));
CHECK(output_surface->BindToClient(&output_surface_client));
- scoped_ptr<ResourceProvider> resource_provider(
- ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1));
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
+ scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
+ output_surface.get(), shared_bitmap_manager.get(), 0, false, 1, false));
LayerTreeSettings settings;
FakeRendererClient renderer_client;
@@ -1364,11 +1250,9 @@ TEST_F(GLRendererTest, ScissorAndViewportWithinNonreshapableSurface) {
renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
renderer.DrawFrame(&render_passes_in_draw_order_,
- NULL,
1.f,
device_viewport_rect,
device_viewport_rect,
- true,
false);
}
@@ -1406,7 +1290,7 @@ TEST_F(GLRendererShaderTest, DrawRenderPassQuadShaderPermutations) {
matrix[15] = matrix[16] = matrix[17] = matrix[19] = 0;
matrix[18] = 1;
skia::RefPtr<SkColorFilter> color_filter(
- skia::AdoptRef(new SkColorMatrixFilter(matrix)));
+ skia::AdoptRef(SkColorMatrixFilter::Create(matrix)));
skia::RefPtr<SkImageFilter> filter = skia::AdoptRef(
SkColorFilterImageFilter::Create(color_filter.get(), NULL));
FilterOperations filters;
@@ -1431,11 +1315,9 @@ TEST_F(GLRendererShaderTest, DrawRenderPassQuadShaderPermutations) {
renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
renderer_->DrawFrame(&render_passes_in_draw_order_,
- NULL,
1.f,
viewport_rect,
viewport_rect,
- true,
false);
TestRenderPassProgram(TexCoordPrecisionMedium);
@@ -1456,11 +1338,9 @@ TEST_F(GLRendererShaderTest, DrawRenderPassQuadShaderPermutations) {
renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
renderer_->DrawFrame(&render_passes_in_draw_order_,
- NULL,
1.f,
viewport_rect,
viewport_rect,
- true,
false);
TestRenderPassColorMatrixProgram(TexCoordPrecisionMedium);
@@ -1482,11 +1362,9 @@ TEST_F(GLRendererShaderTest, DrawRenderPassQuadShaderPermutations) {
renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
renderer_->DrawFrame(&render_passes_in_draw_order_,
- NULL,
1.f,
viewport_rect,
viewport_rect,
- true,
false);
TestRenderPassMaskProgram(TexCoordPrecisionMedium);
@@ -1507,11 +1385,9 @@ TEST_F(GLRendererShaderTest, DrawRenderPassQuadShaderPermutations) {
renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
renderer_->DrawFrame(&render_passes_in_draw_order_,
- NULL,
1.f,
viewport_rect,
viewport_rect,
- true,
false);
TestRenderPassMaskColorMatrixProgram(TexCoordPrecisionMedium);
@@ -1533,11 +1409,9 @@ TEST_F(GLRendererShaderTest, DrawRenderPassQuadShaderPermutations) {
renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
renderer_->DrawFrame(&render_passes_in_draw_order_,
- NULL,
1.f,
viewport_rect,
viewport_rect,
- true,
false);
TestRenderPassProgramAA(TexCoordPrecisionMedium);
@@ -1558,11 +1432,9 @@ TEST_F(GLRendererShaderTest, DrawRenderPassQuadShaderPermutations) {
renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
renderer_->DrawFrame(&render_passes_in_draw_order_,
- NULL,
1.f,
viewport_rect,
viewport_rect,
- true,
false);
TestRenderPassColorMatrixProgramAA(TexCoordPrecisionMedium);
@@ -1584,11 +1456,9 @@ TEST_F(GLRendererShaderTest, DrawRenderPassQuadShaderPermutations) {
renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
renderer_->DrawFrame(&render_passes_in_draw_order_,
- NULL,
1.f,
viewport_rect,
viewport_rect,
- true,
false);
TestRenderPassMaskProgramAA(TexCoordPrecisionMedium);
@@ -1609,11 +1479,9 @@ TEST_F(GLRendererShaderTest, DrawRenderPassQuadShaderPermutations) {
renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
renderer_->DrawFrame(&render_passes_in_draw_order_,
- NULL,
1.f,
viewport_rect,
viewport_rect,
- true,
false);
TestRenderPassMaskColorMatrixProgramAA(TexCoordPrecisionMedium);
}
@@ -1655,11 +1523,9 @@ TEST_F(GLRendererShaderTest, DrawRenderPassQuadSkipsAAForClippingTransform) {
renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
renderer_->DrawFrame(&render_passes_in_draw_order_,
- NULL,
1.f,
viewport_rect,
viewport_rect,
- true,
false);
// If use_aa incorrectly ignores clipping, it will use the
@@ -1687,11 +1553,9 @@ TEST_F(GLRendererShaderTest, DrawSolidColorShader) {
renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
renderer_->DrawFrame(&render_passes_in_draw_order_,
- NULL,
1.f,
viewport_rect,
viewport_rect,
- true,
false);
TestSolidColorProgramAA();
@@ -1699,22 +1563,17 @@ TEST_F(GLRendererShaderTest, DrawSolidColorShader) {
class OutputSurfaceMockContext : public TestWebGraphicsContext3D {
public:
- OutputSurfaceMockContext() {
- test_capabilities_.post_sub_buffer = true;
- }
+ OutputSurfaceMockContext() { test_capabilities_.gpu.post_sub_buffer = true; }
// Specifically override methods even if they are unused (used in conjunction
// with StrictMock). We need to make sure that GLRenderer does not issue
- // framebuffer-related GL calls directly. Instead these are supposed to go
+ // framebuffer-related GLuint calls directly. Instead these are supposed to go
// through the OutputSurface abstraction.
- MOCK_METHOD2(bindFramebuffer, void(WGC3Denum target, WebGLId framebuffer));
+ MOCK_METHOD2(bindFramebuffer, void(GLenum target, GLuint framebuffer));
MOCK_METHOD3(reshapeWithScaleFactor,
void(int width, int height, float scale_factor));
MOCK_METHOD4(drawElements,
- void(WGC3Denum mode,
- WGC3Dsizei count,
- WGC3Denum type,
- WGC3Dintptr offset));
+ void(GLenum mode, GLsizei count, GLenum type, GLintptr offset));
};
class MockOutputSurface : public OutputSurface {
@@ -1729,7 +1588,7 @@ class MockOutputSurface : public OutputSurface {
MOCK_METHOD0(EnsureBackbuffer, void());
MOCK_METHOD0(DiscardBackbuffer, void());
- MOCK_METHOD2(Reshape, void(gfx::Size size, float scale_factor));
+ MOCK_METHOD2(Reshape, void(const gfx::Size& size, float scale_factor));
MOCK_METHOD0(BindFramebuffer, void());
MOCK_METHOD1(SwapBuffers, void(CompositorFrame* frame));
};
@@ -1740,8 +1599,11 @@ class MockOutputSurfaceTest : public GLRendererTest {
FakeOutputSurfaceClient output_surface_client_;
CHECK(output_surface_.BindToClient(&output_surface_client_));
+ shared_bitmap_manager_.reset(new TestSharedBitmapManager());
resource_provider_ =
- ResourceProvider::Create(&output_surface_, NULL, 0, false, 1).Pass();
+ ResourceProvider::Create(
+ &output_surface_, shared_bitmap_manager_.get(), 0, false, 1, false)
+ .Pass();
renderer_.reset(new FakeRendererGL(&renderer_client_,
&settings_,
@@ -1751,7 +1613,8 @@ class MockOutputSurfaceTest : public GLRendererTest {
void SwapBuffers() { renderer_->SwapBuffers(CompositorFrameMetadata()); }
- void DrawFrame(float device_scale_factor, gfx::Rect device_viewport_rect) {
+ void DrawFrame(float device_scale_factor,
+ const gfx::Rect& device_viewport_rect) {
RenderPass::Id render_pass_id(1, 0);
TestRenderPass* render_pass = AddRenderPass(&render_passes_in_draw_order_,
render_pass_id,
@@ -1772,22 +1635,22 @@ class MockOutputSurfaceTest : public GLRendererTest {
renderer_->DecideRenderPassAllocationsForFrame(
render_passes_in_draw_order_);
renderer_->DrawFrame(&render_passes_in_draw_order_,
- NULL,
device_scale_factor,
device_viewport_rect,
device_viewport_rect,
- true,
false);
}
OutputSurfaceMockContext* Context() {
return static_cast<OutputSurfaceMockContext*>(
- output_surface_.context_provider()->Context3d());
+ static_cast<TestContextProvider*>(
+ output_surface_.context_provider().get())->TestContext3d());
}
LayerTreeSettings settings_;
FakeOutputSurfaceClient output_surface_client_;
StrictMock<MockOutputSurface> output_surface_;
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager_;
scoped_ptr<ResourceProvider> resource_provider_;
FakeRendererClient renderer_client_;
scoped_ptr<FakeRendererGL> renderer_;
@@ -1842,15 +1705,15 @@ class GLRendererTestSyncPoint : public GLRendererPixelTest {
TEST_F(GLRendererTestSyncPoint, SignalSyncPointOnLostContext) {
int sync_point_callback_count = 0;
int other_callback_count = 0;
- blink::WebGraphicsContext3D* context3d =
- output_surface_->context_provider()->Context3d();
+ gpu::gles2::GLES2Interface* gl =
+ output_surface_->context_provider()->ContextGL();
gpu::ContextSupport* context_support =
output_surface_->context_provider()->ContextSupport();
- uint32 sync_point = context3d->insertSyncPoint();
+ uint32 sync_point = gl->InsertSyncPointCHROMIUM();
- context3d->loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
- GL_INNOCENT_CONTEXT_RESET_ARB);
+ gl->LoseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
+ GL_INNOCENT_CONTEXT_RESET_ARB);
context_support->SignalSyncPoint(
sync_point, base::Bind(&SyncPointCallback, &sync_point_callback_count));
@@ -1858,7 +1721,7 @@ TEST_F(GLRendererTestSyncPoint, SignalSyncPointOnLostContext) {
EXPECT_EQ(0, other_callback_count);
// Make the sync point happen.
- context3d->finish();
+ gl->Finish();
// Post a task after the sync point.
base::MessageLoop::current()->PostTask(
FROM_HERE, base::Bind(&OtherCallback, &other_callback_count));
@@ -1874,12 +1737,12 @@ TEST_F(GLRendererTestSyncPoint, SignalSyncPoint) {
int sync_point_callback_count = 0;
int other_callback_count = 0;
- blink::WebGraphicsContext3D* context3d =
- output_surface_->context_provider()->Context3d();
+ gpu::gles2::GLES2Interface* gl =
+ output_surface_->context_provider()->ContextGL();
gpu::ContextSupport* context_support =
output_surface_->context_provider()->ContextSupport();
- uint32 sync_point = context3d->insertSyncPoint();
+ uint32 sync_point = gl->InsertSyncPointCHROMIUM();
context_support->SignalSyncPoint(
sync_point, base::Bind(&SyncPointCallback, &sync_point_callback_count));
@@ -1887,7 +1750,7 @@ TEST_F(GLRendererTestSyncPoint, SignalSyncPoint) {
EXPECT_EQ(0, other_callback_count);
// Make the sync point happen.
- context3d->finish();
+ gl->Finish();
// Post a task after the sync point.
base::MessageLoop::current()->PostTask(
FROM_HERE, base::Bind(&OtherCallback, &other_callback_count));
diff --git a/chromium/cc/output/output_surface.cc b/chromium/cc/output/output_surface.cc
index 5bad7ec89b7..46096d2e309 100644
--- a/chromium/cc/output/output_surface.cc
+++ b/chromium/cc/output/output_surface.cc
@@ -24,7 +24,6 @@
#include "gpu/GLES2/gl2extchromium.h"
#include "gpu/command_buffer/client/context_support.h"
#include "gpu/command_buffer/client/gles2_interface.h"
-#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "third_party/khronos/GLES2/gl2ext.h"
#include "ui/gfx/frame_time.h"
@@ -45,194 +44,57 @@ const double kGpuLatencyEstimationPercentile = 100.0;
namespace cc {
OutputSurface::OutputSurface(scoped_refptr<ContextProvider> context_provider)
- : context_provider_(context_provider),
+ : client_(NULL),
+ context_provider_(context_provider),
device_scale_factor_(-1),
- max_frames_pending_(0),
- pending_swap_buffers_(0),
- needs_begin_impl_frame_(false),
- client_ready_for_begin_impl_frame_(true),
- client_(NULL),
- check_for_retroactive_begin_impl_frame_pending_(false),
external_stencil_test_enabled_(false),
weak_ptr_factory_(this),
- gpu_latency_history_(kGpuLatencyHistorySize) {}
+ gpu_latency_history_(kGpuLatencyHistorySize) {
+}
OutputSurface::OutputSurface(scoped_ptr<SoftwareOutputDevice> software_device)
- : software_device_(software_device.Pass()),
+ : client_(NULL),
+ software_device_(software_device.Pass()),
device_scale_factor_(-1),
- max_frames_pending_(0),
- pending_swap_buffers_(0),
- needs_begin_impl_frame_(false),
- client_ready_for_begin_impl_frame_(true),
- client_(NULL),
- check_for_retroactive_begin_impl_frame_pending_(false),
external_stencil_test_enabled_(false),
weak_ptr_factory_(this),
- gpu_latency_history_(kGpuLatencyHistorySize) {}
+ gpu_latency_history_(kGpuLatencyHistorySize) {
+}
OutputSurface::OutputSurface(scoped_refptr<ContextProvider> context_provider,
scoped_ptr<SoftwareOutputDevice> software_device)
- : context_provider_(context_provider),
+ : client_(NULL),
+ context_provider_(context_provider),
software_device_(software_device.Pass()),
device_scale_factor_(-1),
- max_frames_pending_(0),
- pending_swap_buffers_(0),
- needs_begin_impl_frame_(false),
- client_ready_for_begin_impl_frame_(true),
- client_(NULL),
- check_for_retroactive_begin_impl_frame_pending_(false),
external_stencil_test_enabled_(false),
weak_ptr_factory_(this),
- gpu_latency_history_(kGpuLatencyHistorySize) {}
-
-void OutputSurface::InitializeBeginImplFrameEmulation(
- base::SingleThreadTaskRunner* task_runner,
- bool throttle_frame_production,
- base::TimeDelta interval) {
- if (throttle_frame_production) {
- scoped_refptr<DelayBasedTimeSource> time_source;
- if (gfx::FrameTime::TimestampsAreHighRes())
- time_source = DelayBasedTimeSourceHighRes::Create(interval, task_runner);
- else
- time_source = DelayBasedTimeSource::Create(interval, task_runner);
- frame_rate_controller_.reset(new FrameRateController(time_source));
- } else {
- frame_rate_controller_.reset(new FrameRateController(task_runner));
- }
-
- frame_rate_controller_->SetClient(this);
- frame_rate_controller_->SetMaxSwapsPending(max_frames_pending_);
- frame_rate_controller_->SetDeadlineAdjustment(
- capabilities_.adjust_deadline_for_parent ?
- BeginFrameArgs::DefaultDeadlineAdjustment() : base::TimeDelta());
-
- // The new frame rate controller will consume the swap acks of the old
- // frame rate controller, so we set that expectation up here.
- for (int i = 0; i < pending_swap_buffers_; i++)
- frame_rate_controller_->DidSwapBuffers();
-}
-
-void OutputSurface::SetMaxFramesPending(int max_frames_pending) {
- if (frame_rate_controller_)
- frame_rate_controller_->SetMaxSwapsPending(max_frames_pending);
- max_frames_pending_ = max_frames_pending;
-}
-
-void OutputSurface::OnVSyncParametersChanged(base::TimeTicks timebase,
- base::TimeDelta interval) {
- TRACE_EVENT2("cc", "OutputSurface::OnVSyncParametersChanged",
- "timebase", (timebase - base::TimeTicks()).InSecondsF(),
- "interval", interval.InSecondsF());
- if (frame_rate_controller_)
- frame_rate_controller_->SetTimebaseAndInterval(timebase, interval);
+ gpu_latency_history_(kGpuLatencyHistorySize) {
}
-void OutputSurface::FrameRateControllerTick(bool throttled,
- const BeginFrameArgs& args) {
- DCHECK(frame_rate_controller_);
- if (throttled)
- skipped_begin_impl_frame_args_ = args;
- else
- BeginImplFrame(args);
+void OutputSurface::CommitVSyncParameters(base::TimeTicks timebase,
+ base::TimeDelta interval) {
+ TRACE_EVENT2("cc",
+ "OutputSurface::CommitVSyncParameters",
+ "timebase",
+ (timebase - base::TimeTicks()).InSecondsF(),
+ "interval",
+ interval.InSecondsF());
+ client_->CommitVSyncParameters(timebase, interval);
}
// Forwarded to OutputSurfaceClient
-void OutputSurface::SetNeedsRedrawRect(gfx::Rect damage_rect) {
+void OutputSurface::SetNeedsRedrawRect(const gfx::Rect& damage_rect) {
TRACE_EVENT0("cc", "OutputSurface::SetNeedsRedrawRect");
client_->SetNeedsRedrawRect(damage_rect);
}
-void OutputSurface::SetNeedsBeginImplFrame(bool enable) {
- TRACE_EVENT1("cc", "OutputSurface::SetNeedsBeginImplFrame", "enable", enable);
- needs_begin_impl_frame_ = enable;
- client_ready_for_begin_impl_frame_ = true;
- if (frame_rate_controller_) {
- BeginFrameArgs skipped = frame_rate_controller_->SetActive(enable);
- if (skipped.IsValid())
- skipped_begin_impl_frame_args_ = skipped;
- }
- if (needs_begin_impl_frame_)
- PostCheckForRetroactiveBeginImplFrame();
-}
-
-void OutputSurface::BeginImplFrame(const BeginFrameArgs& args) {
- TRACE_EVENT2("cc", "OutputSurface::BeginImplFrame",
- "client_ready_for_begin_impl_frame_",
- client_ready_for_begin_impl_frame_,
- "pending_swap_buffers_", pending_swap_buffers_);
- if (!needs_begin_impl_frame_ || !client_ready_for_begin_impl_frame_ ||
- (pending_swap_buffers_ >= max_frames_pending_ &&
- max_frames_pending_ > 0)) {
- skipped_begin_impl_frame_args_ = args;
- } else {
- client_ready_for_begin_impl_frame_ = false;
- client_->BeginImplFrame(args);
- // args might be an alias for skipped_begin_impl_frame_args_.
- // Do not reset it before calling BeginImplFrame!
- skipped_begin_impl_frame_args_ = BeginFrameArgs();
- }
-}
-
-base::TimeTicks OutputSurface::RetroactiveBeginImplFrameDeadline() {
- // TODO(brianderson): Remove the alternative deadline once we have better
- // deadline estimations.
- base::TimeTicks alternative_deadline =
- skipped_begin_impl_frame_args_.frame_time +
- BeginFrameArgs::DefaultRetroactiveBeginFramePeriod();
- return std::max(skipped_begin_impl_frame_args_.deadline,
- alternative_deadline);
-}
-
-void OutputSurface::PostCheckForRetroactiveBeginImplFrame() {
- if (!skipped_begin_impl_frame_args_.IsValid() ||
- check_for_retroactive_begin_impl_frame_pending_)
- return;
-
- base::MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(&OutputSurface::CheckForRetroactiveBeginImplFrame,
- weak_ptr_factory_.GetWeakPtr()));
- check_for_retroactive_begin_impl_frame_pending_ = true;
-}
-
-void OutputSurface::CheckForRetroactiveBeginImplFrame() {
- TRACE_EVENT0("cc", "OutputSurface::CheckForRetroactiveBeginImplFrame");
- check_for_retroactive_begin_impl_frame_pending_ = false;
- if (gfx::FrameTime::Now() < RetroactiveBeginImplFrameDeadline())
- BeginImplFrame(skipped_begin_impl_frame_args_);
-}
-
-void OutputSurface::DidSwapBuffers() {
- pending_swap_buffers_++;
- TRACE_EVENT1("cc", "OutputSurface::DidSwapBuffers",
- "pending_swap_buffers_", pending_swap_buffers_);
- client_->DidSwapBuffers();
- if (frame_rate_controller_)
- frame_rate_controller_->DidSwapBuffers();
- PostCheckForRetroactiveBeginImplFrame();
-}
-
-void OutputSurface::OnSwapBuffersComplete() {
- pending_swap_buffers_--;
- TRACE_EVENT1("cc", "OutputSurface::OnSwapBuffersComplete",
- "pending_swap_buffers_", pending_swap_buffers_);
- client_->OnSwapBuffersComplete();
- if (frame_rate_controller_)
- frame_rate_controller_->DidSwapBuffersComplete();
- PostCheckForRetroactiveBeginImplFrame();
-}
-
void OutputSurface::ReclaimResources(const CompositorFrameAck* ack) {
client_->ReclaimResources(ack);
}
void OutputSurface::DidLoseOutputSurface() {
TRACE_EVENT0("cc", "OutputSurface::DidLoseOutputSurface");
- client_ready_for_begin_impl_frame_ = true;
- pending_swap_buffers_ = 0;
- skipped_begin_impl_frame_args_ = BeginFrameArgs();
- if (frame_rate_controller_)
- frame_rate_controller_->SetActive(false);
pending_gpu_latency_query_ids_.clear();
available_gpu_latency_query_ids_.clear();
client_->DidLoseOutputSurface();
@@ -243,16 +105,14 @@ void OutputSurface::SetExternalStencilTest(bool enabled) {
}
void OutputSurface::SetExternalDrawConstraints(const gfx::Transform& transform,
- gfx::Rect viewport,
- gfx::Rect clip,
+ const gfx::Rect& viewport,
+ const gfx::Rect& clip,
bool valid_for_tile_management) {
client_->SetExternalDrawConstraints(
transform, viewport, clip, valid_for_tile_management);
}
OutputSurface::~OutputSurface() {
- if (frame_rate_controller_)
- frame_rate_controller_->SetActive(false);
ResetContext3d();
}
@@ -280,8 +140,7 @@ bool OutputSurface::BindToClient(OutputSurfaceClient* client) {
}
bool OutputSurface::InitializeAndSetContext3d(
- scoped_refptr<ContextProvider> context_provider,
- scoped_refptr<ContextProvider> offscreen_context_provider) {
+ scoped_refptr<ContextProvider> context_provider) {
DCHECK(!context_provider_);
DCHECK(context_provider);
DCHECK(client_);
@@ -290,8 +149,8 @@ bool OutputSurface::InitializeAndSetContext3d(
if (context_provider->BindToCurrentThread()) {
context_provider_ = context_provider;
SetUpContext3d();
- if (client_->DeferredInitialize(offscreen_context_provider))
- success = true;
+ client_->DeferredInitialize();
+ success = true;
}
if (!success)
@@ -304,7 +163,7 @@ void OutputSurface::ReleaseGL() {
DCHECK(client_);
DCHECK(context_provider_);
client_->ReleaseGL();
- ResetContext3d();
+ DCHECK(!context_provider_);
}
void OutputSurface::SetUpContext3d() {
@@ -322,17 +181,23 @@ void OutputSurface::SetUpContext3d() {
base::Unretained(this)));
}
+void OutputSurface::ReleaseContextProvider() {
+ DCHECK(client_);
+ DCHECK(context_provider_);
+ ResetContext3d();
+}
+
void OutputSurface::ResetContext3d() {
if (context_provider_.get()) {
while (!pending_gpu_latency_query_ids_.empty()) {
unsigned query_id = pending_gpu_latency_query_ids_.front();
pending_gpu_latency_query_ids_.pop_front();
- context_provider_->Context3d()->deleteQueryEXT(query_id);
+ context_provider_->ContextGL()->DeleteQueriesEXT(1, &query_id);
}
while (!available_gpu_latency_query_ids_.empty()) {
unsigned query_id = available_gpu_latency_query_ids_.front();
available_gpu_latency_query_ids_.pop_front();
- context_provider_->Context3d()->deleteQueryEXT(query_id);
+ context_provider_->ContextGL()->DeleteQueriesEXT(1, &query_id);
}
context_provider_->SetLostContextCallback(
ContextProvider::LostContextCallback());
@@ -356,18 +221,18 @@ void OutputSurface::DiscardBackbuffer() {
software_device_->DiscardBackbuffer();
}
-void OutputSurface::Reshape(gfx::Size size, float scale_factor) {
+void OutputSurface::Reshape(const gfx::Size& size, float scale_factor) {
if (size == surface_size_ && scale_factor == device_scale_factor_)
return;
surface_size_ = size;
device_scale_factor_ = scale_factor;
if (context_provider_) {
- context_provider_->Context3d()->reshapeWithScaleFactor(
+ context_provider_->ContextGL()->ResizeCHROMIUM(
size.width(), size.height(), scale_factor);
}
if (software_device_)
- software_device_->Resize(size);
+ software_device_->Resize(size, scale_factor);
}
gfx::Size OutputSurface::SurfaceSize() const {
@@ -376,13 +241,13 @@ gfx::Size OutputSurface::SurfaceSize() const {
void OutputSurface::BindFramebuffer() {
DCHECK(context_provider_);
- context_provider_->Context3d()->bindFramebuffer(GL_FRAMEBUFFER, 0);
+ context_provider_->ContextGL()->BindFramebuffer(GL_FRAMEBUFFER, 0);
}
void OutputSurface::SwapBuffers(CompositorFrame* frame) {
if (frame->software_frame_data) {
PostSwapBuffersComplete();
- DidSwapBuffers();
+ client_->DidSwapBuffers();
return;
}
@@ -398,7 +263,7 @@ void OutputSurface::SwapBuffers(CompositorFrame* frame) {
frame->gl_frame_data->sub_buffer_rect);
}
- DidSwapBuffers();
+ client_->DidSwapBuffers();
}
base::TimeDelta OutputSurface::GpuLatencyEstimate() {
@@ -409,8 +274,8 @@ base::TimeDelta OutputSurface::GpuLatencyEstimate() {
}
void OutputSurface::UpdateAndMeasureGpuLatency() {
- return; // http://crbug.com/306690 tracks re-enabling latency queries.
-
+ // http://crbug.com/306690 tracks re-enabling latency queries.
+#if 0
// We only care about GPU latency for surfaces that do not have a parent
// compositor, since surfaces that do have a parent compositor can use
// mailboxes or delegated rendering to send frames to their parent without
@@ -421,13 +286,13 @@ void OutputSurface::UpdateAndMeasureGpuLatency() {
while (pending_gpu_latency_query_ids_.size()) {
unsigned query_id = pending_gpu_latency_query_ids_.front();
unsigned query_complete = 1;
- context_provider_->Context3d()->getQueryObjectuivEXT(
+ context_provider_->ContextGL()->GetQueryObjectuivEXT(
query_id, GL_QUERY_RESULT_AVAILABLE_EXT, &query_complete);
if (!query_complete)
break;
unsigned value = 0;
- context_provider_->Context3d()->getQueryObjectuivEXT(
+ context_provider_->ContextGL()->GetQueryObjectuivEXT(
query_id, GL_QUERY_RESULT_EXT, &value);
pending_gpu_latency_query_ids_.pop_front();
available_gpu_latency_query_ids_.push_back(query_id);
@@ -464,13 +329,14 @@ void OutputSurface::UpdateAndMeasureGpuLatency() {
gpu_latency_query_id = available_gpu_latency_query_ids_.front();
available_gpu_latency_query_ids_.pop_front();
} else {
- gpu_latency_query_id = context_provider_->Context3d()->createQueryEXT();
+ context_provider_->ContextGL()->GenQueriesEXT(1, &gpu_latency_query_id);
}
- context_provider_->Context3d()->beginQueryEXT(GL_LATENCY_QUERY_CHROMIUM,
+ context_provider_->ContextGL()->BeginQueryEXT(GL_LATENCY_QUERY_CHROMIUM,
gpu_latency_query_id);
- context_provider_->Context3d()->endQueryEXT(GL_LATENCY_QUERY_CHROMIUM);
+ context_provider_->ContextGL()->EndQueryEXT(GL_LATENCY_QUERY_CHROMIUM);
pending_gpu_latency_query_ids_.push_back(gpu_latency_query_id);
+#endif
}
void OutputSurface::PostSwapBuffersComplete() {
@@ -480,6 +346,12 @@ void OutputSurface::PostSwapBuffersComplete() {
weak_ptr_factory_.GetWeakPtr()));
}
+// We don't post tasks bound to the client directly since they might run
+// after the OutputSurface has been destroyed.
+void OutputSurface::OnSwapBuffersComplete() {
+ client_->DidSwapBuffersComplete();
+}
+
void OutputSurface::SetMemoryPolicy(const ManagedMemoryPolicy& policy) {
TRACE_EVENT1("cc", "OutputSurface::SetMemoryPolicy",
"bytes_limit_when_visible", policy.bytes_limit_when_visible);
diff --git a/chromium/cc/output/output_surface.h b/chromium/cc/output/output_surface.h
index 0d7d4e7fb96..98a48304b8b 100644
--- a/chromium/cc/output/output_surface.h
+++ b/chromium/cc/output/output_surface.h
@@ -12,10 +12,11 @@
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "cc/base/cc_export.h"
+#include "cc/base/rolling_time_delta_history.h"
+#include "cc/output/begin_frame_args.h"
#include "cc/output/context_provider.h"
+#include "cc/output/overlay_candidate_validator.h"
#include "cc/output/software_output_device.h"
-#include "cc/scheduler/frame_rate_controller.h"
-#include "cc/scheduler/rolling_time_delta_history.h"
namespace base { class SingleThreadTaskRunner; }
@@ -41,7 +42,7 @@ class OutputSurfaceClient;
// From here on, it will only be used on the compositor thread.
// 3. If the 3D context is lost, then the compositor will delete the output
// surface (on the compositor thread) and go back to step 1.
-class CC_EXPORT OutputSurface : public FrameRateControllerClient {
+class CC_EXPORT OutputSurface {
public:
enum {
DEFAULT_MAX_FRAMES_PENDING = 2
@@ -68,7 +69,7 @@ class CC_EXPORT OutputSurface : public FrameRateControllerClient {
int max_frames_pending;
bool deferred_gl_initialization;
bool draw_and_swap_full_viewport_every_frame;
- // This doesn't handle the <webview> case, but once BeginImplFrame is
+ // This doesn't handle the <webview> case, but once BeginFrame is
// supported natively, we shouldn't need adjust_deadline_for_parent.
bool adjust_deadline_for_parent;
// Whether this output surface renders to the default OpenGL zero
@@ -104,17 +105,18 @@ class CC_EXPORT OutputSurface : public FrameRateControllerClient {
// thread.
virtual bool BindToClient(OutputSurfaceClient* client);
- void InitializeBeginImplFrameEmulation(
- base::SingleThreadTaskRunner* task_runner,
- bool throttle_frame_production,
- base::TimeDelta interval);
+ // This is called by the compositor on the compositor thread inside ReleaseGL
+ // in order to release the ContextProvider. Only used with
+ // deferred_gl_initialization capability.
+ void ReleaseContextProvider();
- void SetMaxFramesPending(int max_frames_pending);
+ // Enable or disable vsync.
+ void SetThrottleFrameProduction(bool enable);
virtual void EnsureBackbuffer();
virtual void DiscardBackbuffer();
- virtual void Reshape(gfx::Size size, float scale_factor);
+ virtual void Reshape(const gfx::Size& size, float scale_factor);
virtual gfx::Size SurfaceSize() const;
virtual void BindFramebuffer();
@@ -123,15 +125,16 @@ class CC_EXPORT OutputSurface : public FrameRateControllerClient {
// passed in (though it will not take ownership of the CompositorFrame
// itself).
virtual void SwapBuffers(CompositorFrame* frame);
+ virtual void OnSwapBuffersComplete();
// Notifies frame-rate smoothness preference. If true, all non-critical
// processing should be stopped, or lowered in priority.
virtual void UpdateSmoothnessTakesPriority(bool prefer_smoothness) {}
- // Requests a BeginImplFrame notification from the output surface. The
+ // Requests a BeginFrame notification from the output surface. The
// notification will be delivered by calling
- // OutputSurfaceClient::BeginImplFrame until the callback is disabled.
- virtual void SetNeedsBeginImplFrame(bool enable);
+ // OutputSurfaceClient::BeginFrame until the callback is disabled.
+ virtual void SetNeedsBeginFrame(bool enable) {}
bool HasClient() { return !!client_; }
@@ -139,14 +142,18 @@ class CC_EXPORT OutputSurface : public FrameRateControllerClient {
// device is present, returns 0.
base::TimeDelta GpuLatencyEstimate();
+ // Get the class capable of informing cc of hardware overlay capability.
+ OverlayCandidateValidator* overlay_candidate_validator() const {
+ return overlay_candidate_validator_.get();
+ }
+
protected:
+ OutputSurfaceClient* client_;
+
// Synchronously initialize context3d and enter hardware mode.
// This can only supported in threaded compositing mode.
- // |offscreen_context_provider| should match what is returned by
- // LayerTreeClient::OffscreenContextProvider().
bool InitializeAndSetContext3d(
- scoped_refptr<ContextProvider> context_provider,
- scoped_refptr<ContextProvider> offscreen_context_provider);
+ scoped_refptr<ContextProvider> context_provider);
void ReleaseGL();
void PostSwapBuffersComplete();
@@ -154,56 +161,28 @@ class CC_EXPORT OutputSurface : public FrameRateControllerClient {
struct OutputSurface::Capabilities capabilities_;
scoped_refptr<ContextProvider> context_provider_;
scoped_ptr<SoftwareOutputDevice> software_device_;
+ scoped_ptr<OverlayCandidateValidator> overlay_candidate_validator_;
gfx::Size surface_size_;
float device_scale_factor_;
- // The FrameRateController is deprecated.
- // Platforms should move to native BeginImplFrames instead.
- void OnVSyncParametersChanged(base::TimeTicks timebase,
- base::TimeDelta interval);
- virtual void FrameRateControllerTick(bool throttled,
- const BeginFrameArgs& args) OVERRIDE;
- scoped_ptr<FrameRateController> frame_rate_controller_;
- int max_frames_pending_;
- int pending_swap_buffers_;
- bool needs_begin_impl_frame_;
- bool client_ready_for_begin_impl_frame_;
-
- // This stores a BeginImplFrame that we couldn't process immediately,
- // but might process retroactively in the near future.
- BeginFrameArgs skipped_begin_impl_frame_args_;
-
- // Forwarded to OutputSurfaceClient but threaded through OutputSurface
- // first so OutputSurface has a chance to update the FrameRateController
- void SetNeedsRedrawRect(gfx::Rect damage_rect);
- void BeginImplFrame(const BeginFrameArgs& args);
- void DidSwapBuffers();
- void OnSwapBuffersComplete();
+ void CommitVSyncParameters(base::TimeTicks timebase,
+ base::TimeDelta interval);
+
+ void SetNeedsRedrawRect(const gfx::Rect& damage_rect);
void ReclaimResources(const CompositorFrameAck* ack);
void DidLoseOutputSurface();
void SetExternalStencilTest(bool enabled);
void SetExternalDrawConstraints(const gfx::Transform& transform,
- gfx::Rect viewport,
- gfx::Rect clip,
+ const gfx::Rect& viewport,
+ const gfx::Rect& clip,
bool valid_for_tile_management);
- // virtual for testing.
- virtual base::TimeTicks RetroactiveBeginImplFrameDeadline();
- virtual void PostCheckForRetroactiveBeginImplFrame();
- void CheckForRetroactiveBeginImplFrame();
-
private:
- OutputSurfaceClient* client_;
-
void SetUpContext3d();
void ResetContext3d();
void SetMemoryPolicy(const ManagedMemoryPolicy& policy);
void UpdateAndMeasureGpuLatency();
- // check_for_retroactive_begin_impl_frame_pending_ is used to avoid posting
- // redundant checks for a retroactive BeginImplFrame.
- bool check_for_retroactive_begin_impl_frame_pending_;
-
bool external_stencil_test_enabled_;
base::WeakPtrFactory<OutputSurface> weak_ptr_factory_;
diff --git a/chromium/cc/output/output_surface_client.h b/chromium/cc/output/output_surface_client.h
index d82f30df499..9742a6f9734 100644
--- a/chromium/cc/output/output_surface_client.h
+++ b/chromium/cc/output/output_surface_client.h
@@ -27,18 +27,20 @@ class CC_EXPORT OutputSurfaceClient {
// Called to synchronously re-initialize using the Context3D. Upon returning
// the compositor should be able to draw using GL what was previously
// committed.
- virtual bool DeferredInitialize(
- scoped_refptr<ContextProvider> offscreen_context_provider) = 0;
+ virtual void DeferredInitialize() = 0;
+ // Must call OutputSurface::ReleaseContextProvider inside this call.
virtual void ReleaseGL() = 0;
- virtual void SetNeedsRedrawRect(gfx::Rect damage_rect) = 0;
- virtual void BeginImplFrame(const BeginFrameArgs& args) = 0;
+ virtual void CommitVSyncParameters(base::TimeTicks timebase,
+ base::TimeDelta interval) = 0;
+ virtual void SetNeedsRedrawRect(const gfx::Rect& damage_rect) = 0;
+ virtual void BeginFrame(const BeginFrameArgs& args) = 0;
virtual void DidSwapBuffers() = 0;
- virtual void OnSwapBuffersComplete() = 0;
+ virtual void DidSwapBuffersComplete() = 0;
virtual void ReclaimResources(const CompositorFrameAck* ack) = 0;
virtual void DidLoseOutputSurface() = 0;
virtual void SetExternalDrawConstraints(const gfx::Transform& transform,
- gfx::Rect viewport,
- gfx::Rect clip,
+ const gfx::Rect& viewport,
+ const gfx::Rect& clip,
bool valid_for_tile_management) = 0;
virtual void SetMemoryPolicy(const ManagedMemoryPolicy& policy) = 0;
// If set, |callback| will be called subsequent to each new tree activation,
diff --git a/chromium/cc/output/output_surface_unittest.cc b/chromium/cc/output/output_surface_unittest.cc
index 551ec595593..76a2a72ee28 100644
--- a/chromium/cc/output/output_surface_unittest.cc
+++ b/chromium/cc/output/output_surface_unittest.cc
@@ -8,6 +8,7 @@
#include "cc/output/managed_memory_policy.h"
#include "cc/output/output_surface_client.h"
#include "cc/output/software_output_device.h"
+#include "cc/test/begin_frame_args_test.h"
#include "cc/test/fake_output_surface.h"
#include "cc/test/fake_output_surface_client.h"
#include "cc/test/scheduler_test_common.h"
@@ -23,80 +24,36 @@ namespace {
class TestOutputSurface : public OutputSurface {
public:
explicit TestOutputSurface(scoped_refptr<ContextProvider> context_provider)
- : OutputSurface(context_provider),
- retroactive_begin_impl_frame_deadline_enabled_(false),
- override_retroactive_period_(false) {}
+ : OutputSurface(context_provider) {}
explicit TestOutputSurface(scoped_ptr<SoftwareOutputDevice> software_device)
- : OutputSurface(software_device.Pass()),
- retroactive_begin_impl_frame_deadline_enabled_(false),
- override_retroactive_period_(false) {}
+ : OutputSurface(software_device.Pass()) {}
TestOutputSurface(scoped_refptr<ContextProvider> context_provider,
scoped_ptr<SoftwareOutputDevice> software_device)
- : OutputSurface(context_provider, software_device.Pass()),
- retroactive_begin_impl_frame_deadline_enabled_(false),
- override_retroactive_period_(false) {}
+ : OutputSurface(context_provider, software_device.Pass()) {}
bool InitializeNewContext3d(
scoped_refptr<ContextProvider> new_context_provider) {
- return InitializeAndSetContext3d(new_context_provider,
- scoped_refptr<ContextProvider>());
+ return InitializeAndSetContext3d(new_context_provider);
}
using OutputSurface::ReleaseGL;
- void OnVSyncParametersChangedForTesting(base::TimeTicks timebase,
- base::TimeDelta interval) {
- OnVSyncParametersChanged(timebase, interval);
+ void CommitVSyncParametersForTesting(base::TimeTicks timebase,
+ base::TimeDelta interval) {
+ CommitVSyncParameters(timebase, interval);
}
- void BeginImplFrameForTesting() {
- OutputSurface::BeginImplFrame(BeginFrameArgs::CreateExpiredForTesting());
+ void BeginFrameForTesting() {
+ client_->BeginFrame(CreateExpiredBeginFrameArgsForTesting());
}
- void DidSwapBuffersForTesting() {
- DidSwapBuffers();
- }
-
- int pending_swap_buffers() {
- return pending_swap_buffers_;
- }
+ void DidSwapBuffersForTesting() { client_->DidSwapBuffers(); }
- void OnSwapBuffersCompleteForTesting() {
- OnSwapBuffersComplete();
- }
-
- void EnableRetroactiveBeginImplFrameDeadline(
- bool enable,
- bool override_retroactive_period,
- base::TimeDelta period_override) {
- retroactive_begin_impl_frame_deadline_enabled_ = enable;
- override_retroactive_period_ = override_retroactive_period;
- retroactive_period_override_ = period_override;
- }
+ void OnSwapBuffersCompleteForTesting() { client_->DidSwapBuffersComplete(); }
protected:
- virtual void PostCheckForRetroactiveBeginImplFrame() OVERRIDE {
- // For testing purposes, we check immediately rather than posting a task.
- CheckForRetroactiveBeginImplFrame();
- }
-
- virtual base::TimeTicks RetroactiveBeginImplFrameDeadline() OVERRIDE {
- if (retroactive_begin_impl_frame_deadline_enabled_) {
- if (override_retroactive_period_) {
- return skipped_begin_impl_frame_args_.frame_time +
- retroactive_period_override_;
- } else {
- return OutputSurface::RetroactiveBeginImplFrameDeadline();
- }
- }
- return base::TimeTicks();
- }
-
- bool retroactive_begin_impl_frame_deadline_enabled_;
- bool override_retroactive_period_;
- base::TimeDelta retroactive_period_override_;
};
class TestSoftwareOutputDevice : public SoftwareOutputDevice {
@@ -132,7 +89,8 @@ void TestSoftwareOutputDevice::EnsureBackbuffer() {
}
TEST(OutputSurfaceTest, ClientPointerIndicatesBindToClientSuccess) {
- TestOutputSurface output_surface(TestContextProvider::Create());
+ scoped_refptr<TestContextProvider> provider = TestContextProvider::Create();
+ TestOutputSurface output_surface(provider);
EXPECT_FALSE(output_surface.HasClient());
FakeOutputSurfaceClient client;
@@ -142,8 +100,9 @@ TEST(OutputSurfaceTest, ClientPointerIndicatesBindToClientSuccess) {
// Verify DidLoseOutputSurface callback is hooked up correctly.
EXPECT_FALSE(client.did_lose_output_surface_called());
- output_surface.context_provider()->Context3d()->loseContextCHROMIUM(
+ output_surface.context_provider()->ContextGL()->LoseContextCHROMIUM(
GL_GUILTY_CONTEXT_RESET_ARB, GL_INNOCENT_CONTEXT_RESET_ARB);
+ output_surface.context_provider()->ContextGL()->Flush();
EXPECT_TRUE(client.did_lose_output_surface_called());
}
@@ -167,7 +126,8 @@ class OutputSurfaceTestInitializeNewContext3d : public ::testing::Test {
OutputSurfaceTestInitializeNewContext3d()
: context_provider_(TestContextProvider::Create()),
output_surface_(
- scoped_ptr<SoftwareOutputDevice>(new SoftwareOutputDevice)) {}
+ scoped_ptr<SoftwareOutputDevice>(new SoftwareOutputDevice)),
+ client_(&output_surface_) {}
protected:
void BindOutputSurface() {
@@ -197,8 +157,9 @@ TEST_F(OutputSurfaceTestInitializeNewContext3d, Success) {
EXPECT_EQ(context_provider_, output_surface_.context_provider());
EXPECT_FALSE(client_.did_lose_output_surface_called());
- context_provider_->Context3d()->loseContextCHROMIUM(
+ context_provider_->ContextGL()->LoseContextCHROMIUM(
GL_GUILTY_CONTEXT_RESET_ARB, GL_INNOCENT_CONTEXT_RESET_ARB);
+ context_provider_->ContextGL()->Flush();
EXPECT_TRUE(client_.did_lose_output_surface_called());
output_surface_.ReleaseGL();
@@ -212,209 +173,6 @@ TEST_F(OutputSurfaceTestInitializeNewContext3d, Context3dMakeCurrentFails) {
InitializeNewContextExpectFail();
}
-TEST_F(OutputSurfaceTestInitializeNewContext3d, ClientDeferredInitializeFails) {
- BindOutputSurface();
- client_.set_deferred_initialize_result(false);
- InitializeNewContextExpectFail();
-}
-
-TEST(OutputSurfaceTest, BeginImplFrameEmulation) {
- TestOutputSurface output_surface(TestContextProvider::Create());
- EXPECT_FALSE(output_surface.HasClient());
-
- FakeOutputSurfaceClient client;
- EXPECT_TRUE(output_surface.BindToClient(&client));
- EXPECT_TRUE(output_surface.HasClient());
- EXPECT_FALSE(client.deferred_initialize_called());
-
- // Initialize BeginImplFrame emulation
- scoped_refptr<base::TestSimpleTaskRunner> task_runner =
- new base::TestSimpleTaskRunner;
- bool throttle_frame_production = true;
- const base::TimeDelta display_refresh_interval =
- BeginFrameArgs::DefaultInterval();
-
- output_surface.InitializeBeginImplFrameEmulation(
- task_runner.get(),
- throttle_frame_production,
- display_refresh_interval);
-
- output_surface.SetMaxFramesPending(2);
- output_surface.EnableRetroactiveBeginImplFrameDeadline(
- false, false, base::TimeDelta());
-
- // We should start off with 0 BeginImplFrames
- EXPECT_EQ(client.begin_impl_frame_count(), 0);
- EXPECT_EQ(output_surface.pending_swap_buffers(), 0);
-
- // We should not have a pending task until a BeginImplFrame has been
- // requested.
- EXPECT_FALSE(task_runner->HasPendingTask());
- output_surface.SetNeedsBeginImplFrame(true);
- EXPECT_TRUE(task_runner->HasPendingTask());
-
- // BeginImplFrame should be called on the first tick.
- task_runner->RunPendingTasks();
- EXPECT_EQ(client.begin_impl_frame_count(), 1);
- EXPECT_EQ(output_surface.pending_swap_buffers(), 0);
-
- // BeginImplFrame should not be called when there is a pending BeginImplFrame.
- task_runner->RunPendingTasks();
- EXPECT_EQ(client.begin_impl_frame_count(), 1);
- EXPECT_EQ(output_surface.pending_swap_buffers(), 0);
-
- // SetNeedsBeginImplFrame should clear the pending BeginImplFrame after
- // a SwapBuffers.
- output_surface.DidSwapBuffersForTesting();
- output_surface.SetNeedsBeginImplFrame(true);
- EXPECT_EQ(client.begin_impl_frame_count(), 1);
- EXPECT_EQ(output_surface.pending_swap_buffers(), 1);
- task_runner->RunPendingTasks();
- EXPECT_EQ(client.begin_impl_frame_count(), 2);
- EXPECT_EQ(output_surface.pending_swap_buffers(), 1);
-
- // BeginImplFrame should be throttled by pending swap buffers.
- output_surface.DidSwapBuffersForTesting();
- output_surface.SetNeedsBeginImplFrame(true);
- EXPECT_EQ(client.begin_impl_frame_count(), 2);
- EXPECT_EQ(output_surface.pending_swap_buffers(), 2);
- task_runner->RunPendingTasks();
- EXPECT_EQ(client.begin_impl_frame_count(), 2);
- EXPECT_EQ(output_surface.pending_swap_buffers(), 2);
-
- // SwapAck should decrement pending swap buffers and unblock BeginImplFrame
- // again.
- output_surface.OnSwapBuffersCompleteForTesting();
- EXPECT_EQ(client.begin_impl_frame_count(), 2);
- EXPECT_EQ(output_surface.pending_swap_buffers(), 1);
- task_runner->RunPendingTasks();
- EXPECT_EQ(client.begin_impl_frame_count(), 3);
- EXPECT_EQ(output_surface.pending_swap_buffers(), 1);
-
- // Calling SetNeedsBeginImplFrame again indicates a swap did not occur but
- // the client still wants another BeginImplFrame.
- output_surface.SetNeedsBeginImplFrame(true);
- task_runner->RunPendingTasks();
- EXPECT_EQ(client.begin_impl_frame_count(), 4);
- EXPECT_EQ(output_surface.pending_swap_buffers(), 1);
-
- // Disabling SetNeedsBeginImplFrame should prevent further BeginImplFrames.
- output_surface.SetNeedsBeginImplFrame(false);
- task_runner->RunPendingTasks();
- EXPECT_FALSE(task_runner->HasPendingTask());
- EXPECT_EQ(client.begin_impl_frame_count(), 4);
- EXPECT_EQ(output_surface.pending_swap_buffers(), 1);
-}
-
-TEST(OutputSurfaceTest, OptimisticAndRetroactiveBeginImplFrames) {
- TestOutputSurface output_surface(TestContextProvider::Create());
- EXPECT_FALSE(output_surface.HasClient());
-
- FakeOutputSurfaceClient client;
- EXPECT_TRUE(output_surface.BindToClient(&client));
- EXPECT_TRUE(output_surface.HasClient());
- EXPECT_FALSE(client.deferred_initialize_called());
-
- output_surface.SetMaxFramesPending(2);
- output_surface.EnableRetroactiveBeginImplFrameDeadline(
- true, false, base::TimeDelta());
-
- // Optimistically injected BeginImplFrames should be throttled if
- // SetNeedsBeginImplFrame is false...
- output_surface.SetNeedsBeginImplFrame(false);
- output_surface.BeginImplFrameForTesting();
- EXPECT_EQ(client.begin_impl_frame_count(), 0);
- // ...and retroactively triggered by a SetNeedsBeginImplFrame.
- output_surface.SetNeedsBeginImplFrame(true);
- EXPECT_EQ(client.begin_impl_frame_count(), 1);
-
- // Optimistically injected BeginImplFrames should be throttled by pending
- // BeginImplFrames...
- output_surface.BeginImplFrameForTesting();
- EXPECT_EQ(client.begin_impl_frame_count(), 1);
- // ...and retroactively triggered by a SetNeedsBeginImplFrame.
- output_surface.SetNeedsBeginImplFrame(true);
- EXPECT_EQ(client.begin_impl_frame_count(), 2);
- // ...or retroactively triggered by a Swap.
- output_surface.BeginImplFrameForTesting();
- EXPECT_EQ(client.begin_impl_frame_count(), 2);
- output_surface.DidSwapBuffersForTesting();
- output_surface.SetNeedsBeginImplFrame(true);
- EXPECT_EQ(client.begin_impl_frame_count(), 3);
- EXPECT_EQ(output_surface.pending_swap_buffers(), 1);
-
- // Optimistically injected BeginImplFrames should be by throttled by pending
- // swap buffers...
- output_surface.DidSwapBuffersForTesting();
- output_surface.SetNeedsBeginImplFrame(true);
- EXPECT_EQ(client.begin_impl_frame_count(), 3);
- EXPECT_EQ(output_surface.pending_swap_buffers(), 2);
- output_surface.BeginImplFrameForTesting();
- EXPECT_EQ(client.begin_impl_frame_count(), 3);
- // ...and retroactively triggered by OnSwapBuffersComplete
- output_surface.OnSwapBuffersCompleteForTesting();
- EXPECT_EQ(client.begin_impl_frame_count(), 4);
-}
-
-TEST(OutputSurfaceTest,
- RetroactiveBeginImplFrameDoesNotDoubleTickWhenEmulating) {
- scoped_refptr<TestContextProvider> context_provider =
- TestContextProvider::Create();
-
- TestOutputSurface output_surface(context_provider);
- EXPECT_FALSE(output_surface.HasClient());
-
- FakeOutputSurfaceClient client;
- EXPECT_TRUE(output_surface.BindToClient(&client));
- EXPECT_TRUE(output_surface.HasClient());
- EXPECT_FALSE(client.deferred_initialize_called());
-
- base::TimeDelta big_interval = base::TimeDelta::FromSeconds(10);
-
- // Initialize BeginImplFrame emulation
- scoped_refptr<base::TestSimpleTaskRunner> task_runner =
- new base::TestSimpleTaskRunner;
- bool throttle_frame_production = true;
- const base::TimeDelta display_refresh_interval = big_interval;
-
- output_surface.InitializeBeginImplFrameEmulation(
- task_runner.get(),
- throttle_frame_production,
- display_refresh_interval);
-
- // We need to subtract an epsilon from Now() because some platforms have
- // a slow clock.
- output_surface.OnVSyncParametersChangedForTesting(
- gfx::FrameTime::Now() - base::TimeDelta::FromSeconds(1), big_interval);
-
- output_surface.SetMaxFramesPending(2);
- output_surface.EnableRetroactiveBeginImplFrameDeadline(
- true, true, big_interval);
-
- // We should start off with 0 BeginImplFrames
- EXPECT_EQ(client.begin_impl_frame_count(), 0);
- EXPECT_EQ(output_surface.pending_swap_buffers(), 0);
-
- // The first SetNeedsBeginImplFrame(true) should start a retroactive
- // BeginImplFrame.
- EXPECT_FALSE(task_runner->HasPendingTask());
- output_surface.SetNeedsBeginImplFrame(true);
- EXPECT_TRUE(task_runner->HasPendingTask());
- EXPECT_GT(task_runner->NextPendingTaskDelay(), big_interval / 2);
- EXPECT_EQ(client.begin_impl_frame_count(), 1);
-
- output_surface.SetNeedsBeginImplFrame(false);
- EXPECT_TRUE(task_runner->HasPendingTask());
- EXPECT_EQ(client.begin_impl_frame_count(), 1);
-
- // The second SetNeedBeginImplFrame(true) should not retroactively start a
- // BeginImplFrame if the timestamp would be the same as the previous
- // BeginImplFrame.
- output_surface.SetNeedsBeginImplFrame(true);
- EXPECT_TRUE(task_runner->HasPendingTask());
- EXPECT_EQ(client.begin_impl_frame_count(), 1);
-}
-
TEST(OutputSurfaceTest, MemoryAllocation) {
scoped_refptr<TestContextProvider> context_provider =
TestContextProvider::Create();
diff --git a/chromium/cc/output/overlay_candidate.cc b/chromium/cc/output/overlay_candidate.cc
new file mode 100644
index 00000000000..63632fc11b4
--- /dev/null
+++ b/chromium/cc/output/overlay_candidate.cc
@@ -0,0 +1,42 @@
+// 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/output/overlay_candidate.h"
+
+#include "ui/gfx/rect_conversions.h"
+
+namespace cc {
+
+OverlayCandidate::OverlayCandidate()
+ : transform(gfx::OVERLAY_TRANSFORM_NONE),
+ format(RGBA_8888),
+ uv_rect(0.f, 0.f, 1.f, 1.f),
+ resource_id(0),
+ plane_z_order(0),
+ overlay_handled(false) {}
+
+OverlayCandidate::~OverlayCandidate() {}
+
+// static
+gfx::OverlayTransform OverlayCandidate::GetOverlayTransform(
+ const gfx::Transform& quad_transform,
+ bool flipped) {
+ if (!quad_transform.IsIdentityOrTranslation())
+ return gfx::OVERLAY_TRANSFORM_INVALID;
+
+ return flipped ? gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL
+ : gfx::OVERLAY_TRANSFORM_NONE;
+}
+
+// static
+gfx::Rect OverlayCandidate::GetOverlayRect(const gfx::Transform& quad_transform,
+ const gfx::Rect& rect) {
+ DCHECK(quad_transform.IsIdentityOrTranslation());
+
+ gfx::RectF float_rect(rect);
+ quad_transform.TransformRect(&float_rect);
+ return gfx::ToNearestRect(float_rect);
+}
+
+} // namespace cc
diff --git a/chromium/cc/output/overlay_candidate.h b/chromium/cc/output/overlay_candidate.h
new file mode 100644
index 00000000000..9961bfdc83d
--- /dev/null
+++ b/chromium/cc/output/overlay_candidate.h
@@ -0,0 +1,53 @@
+// 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_OUTPUT_OVERLAY_CANDIDATE_H_
+#define CC_OUTPUT_OVERLAY_CANDIDATE_H_
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "cc/base/cc_export.h"
+#include "cc/resources/resource_format.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/overlay_transform.h"
+#include "ui/gfx/transform.h"
+
+namespace cc {
+
+class CC_EXPORT OverlayCandidate {
+ public:
+ static gfx::OverlayTransform GetOverlayTransform(
+ const gfx::Transform& quad_transform,
+ bool flipped);
+ static gfx::Rect GetOverlayRect(const gfx::Transform& quad_transform,
+ const gfx::Rect& rect);
+
+ OverlayCandidate();
+ ~OverlayCandidate();
+
+ // Transformation to apply to layer during composition.
+ gfx::OverlayTransform transform;
+ // Format of the buffer to composite.
+ ResourceFormat format;
+ // Rect on the display to position the overlay to.
+ gfx::Rect display_rect;
+ // Crop within the buffer to be placed inside |display_rect|.
+ gfx::RectF uv_rect;
+ // Texture resource to present in an overlay.
+ unsigned resource_id;
+ // Stacking order of the overlay plane relative to the main surface,
+ // which is 0. Signed to allow for "underlays".
+ int plane_z_order;
+
+ // To be modified by the implementer if this candidate can go into
+ // an overlay.
+ bool overlay_handled;
+};
+
+typedef std::vector<OverlayCandidate> OverlayCandidateList;
+
+} // namespace cc
+
+#endif // CC_OUTPUT_OVERLAY_CANDIDATE_H_
diff --git a/chromium/cc/output/overlay_candidate_validator.h b/chromium/cc/output/overlay_candidate_validator.h
new file mode 100644
index 00000000000..fb528da3fcc
--- /dev/null
+++ b/chromium/cc/output/overlay_candidate_validator.h
@@ -0,0 +1,33 @@
+// 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_OUTPUT_OVERLAY_CANDIDATE_VALIDATOR_H_
+#define CC_OUTPUT_OVERLAY_CANDIDATE_VALIDATOR_H_
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "cc/base/cc_export.h"
+#include "cc/output/overlay_candidate.h"
+#include "cc/resources/resource_format.h"
+#include "ui/gfx/geometry/rect.h"
+
+namespace cc {
+
+// This class that can be used to answer questions about possible overlay
+// configurations for a particular output device.
+class CC_EXPORT OverlayCandidateValidator {
+ public:
+ // A list of possible overlay candidates is presented to this function.
+ // The expected result is that those candidates that can be in a separate
+ // plane are marked with |overlay_handled| set to true, otherwise they are
+ // to be traditionally composited.
+ virtual void CheckOverlaySupport(OverlayCandidateList* surfaces) = 0;
+
+ virtual ~OverlayCandidateValidator() {}
+};
+
+} // namespace cc
+
+#endif // CC_OUTPUT_OVERLAY_CANDIDATE_VALIDATOR_H_
diff --git a/chromium/cc/output/overlay_processor.cc b/chromium/cc/output/overlay_processor.cc
new file mode 100644
index 00000000000..c13a6cfded1
--- /dev/null
+++ b/chromium/cc/output/overlay_processor.cc
@@ -0,0 +1,45 @@
+// 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/output/overlay_processor.h"
+
+#include "cc/output/output_surface.h"
+#include "cc/output/overlay_strategy_single_on_top.h"
+#include "cc/quads/draw_quad.h"
+#include "cc/quads/texture_draw_quad.h"
+#include "ui/gfx/rect_conversions.h"
+#include "ui/gfx/transform.h"
+
+namespace cc {
+
+OverlayProcessor::OverlayProcessor(OutputSurface* surface,
+ ResourceProvider* resource_provider)
+ : surface_(surface), resource_provider_(resource_provider) {}
+
+void OverlayProcessor::Initialize() {
+ DCHECK(surface_);
+ if (!resource_provider_)
+ return;
+
+ OverlayCandidateValidator* candidates =
+ surface_->overlay_candidate_validator();
+ if (candidates) {
+ strategies_.push_back(scoped_ptr<Strategy>(
+ new OverlayStrategySingleOnTop(candidates, resource_provider_)));
+ }
+}
+
+OverlayProcessor::~OverlayProcessor() {}
+
+void OverlayProcessor::ProcessForOverlays(
+ RenderPassList* render_passes_in_draw_order,
+ OverlayCandidateList* candidate_list) {
+ for (StrategyList::iterator it = strategies_.begin(); it != strategies_.end();
+ ++it) {
+ if ((*it)->Attempt(render_passes_in_draw_order, candidate_list))
+ return;
+ }
+}
+
+} // namespace cc
diff --git a/chromium/cc/output/overlay_processor.h b/chromium/cc/output/overlay_processor.h
new file mode 100644
index 00000000000..e50972e711d
--- /dev/null
+++ b/chromium/cc/output/overlay_processor.h
@@ -0,0 +1,51 @@
+// 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_OUTPUT_OVERLAY_PROCESSOR_H_
+#define CC_OUTPUT_OVERLAY_PROCESSOR_H_
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "cc/base/cc_export.h"
+#include "cc/output/overlay_candidate.h"
+#include "cc/quads/render_pass.h"
+
+namespace cc {
+class OutputSurface;
+class ResourceProvider;
+
+class CC_EXPORT OverlayProcessor {
+ public:
+ class CC_EXPORT Strategy {
+ public:
+ virtual ~Strategy() {}
+ // Returns false if the strategy cannot be made to work with the
+ // current set of render passes. Returns true if the strategy was successful
+ // and adds any additional passes necessary to represent overlays to
+ // |render_passes_in_draw_order|.
+ virtual bool Attempt(RenderPassList* render_passes_in_draw_order,
+ OverlayCandidateList* candidates) = 0;
+ };
+ typedef ScopedPtrVector<Strategy> StrategyList;
+
+ OverlayProcessor(OutputSurface* surface, ResourceProvider* resource_provider);
+ virtual ~OverlayProcessor();
+ // Virtual to allow testing different strategies.
+ virtual void Initialize();
+
+ void ProcessForOverlays(RenderPassList* render_passes_in_draw_order,
+ OverlayCandidateList* candidate_list);
+
+ protected:
+ StrategyList strategies_;
+ OutputSurface* surface_;
+ ResourceProvider* resource_provider_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(OverlayProcessor);
+};
+
+} // namespace cc
+
+#endif // CC_OUTPUT_OVERLAY_PROCESSOR_H_
diff --git a/chromium/cc/output/overlay_strategy_single_on_top.cc b/chromium/cc/output/overlay_strategy_single_on_top.cc
new file mode 100644
index 00000000000..405a191c08a
--- /dev/null
+++ b/chromium/cc/output/overlay_strategy_single_on_top.cc
@@ -0,0 +1,81 @@
+// 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/output/overlay_strategy_single_on_top.h"
+
+#include "cc/output/output_surface.h"
+#include "cc/quads/draw_quad.h"
+#include "cc/quads/texture_draw_quad.h"
+#include "ui/gfx/rect_conversions.h"
+#include "ui/gfx/transform.h"
+
+namespace cc {
+
+OverlayStrategySingleOnTop::OverlayStrategySingleOnTop(
+ OverlayCandidateValidator* capability_checker,
+ ResourceProvider* resource_provider)
+ : capability_checker_(capability_checker),
+ resource_provider_(resource_provider) {}
+
+bool OverlayStrategySingleOnTop::Attempt(
+ RenderPassList* render_passes_in_draw_order,
+ OverlayCandidateList* candidate_list) {
+ // Only attempt to handle very simple case for now.
+ if (!capability_checker_)
+ return false;
+
+ RenderPass* root_render_pass = render_passes_in_draw_order->back();
+ DCHECK(root_render_pass);
+
+ QuadList& quad_list = root_render_pass->quad_list;
+ const DrawQuad* candidate_quad = quad_list.front();
+ if (candidate_quad->material != DrawQuad::TEXTURE_CONTENT)
+ return false;
+
+ const TextureDrawQuad& quad = *TextureDrawQuad::MaterialCast(candidate_quad);
+ if (!resource_provider_->AllowOverlay(quad.resource_id))
+ return false;
+
+ // Simple quads only.
+ gfx::OverlayTransform overlay_transform =
+ OverlayCandidate::GetOverlayTransform(quad.quadTransform(), quad.flipped);
+ if (overlay_transform == gfx::OVERLAY_TRANSFORM_INVALID ||
+ !quad.quadTransform().IsIdentityOrTranslation() || quad.needs_blending ||
+ quad.shared_quad_state->opacity != 1.f ||
+ quad.shared_quad_state->blend_mode != SkXfermode::kSrcOver_Mode ||
+ quad.premultiplied_alpha || quad.background_color != SK_ColorTRANSPARENT)
+ return false;
+
+ // Add our primary surface.
+ OverlayCandidateList candidates;
+ OverlayCandidate main_image;
+ main_image.display_rect = root_render_pass->output_rect;
+ main_image.format = RGBA_8888;
+ candidates.push_back(main_image);
+
+ // Add the overlay.
+ OverlayCandidate candidate;
+ candidate.transform = overlay_transform;
+ candidate.display_rect =
+ OverlayCandidate::GetOverlayRect(quad.quadTransform(), quad.rect);
+ candidate.uv_rect = BoundingRect(quad.uv_top_left, quad.uv_bottom_right);
+ candidate.format = RGBA_8888;
+ candidate.resource_id = quad.resource_id;
+ candidate.plane_z_order = 1;
+ candidates.push_back(candidate);
+
+ // Check for support.
+ capability_checker_->CheckOverlaySupport(&candidates);
+
+ // If the candidate can be handled by an overlay, create a pass for it.
+ if (candidates[1].overlay_handled) {
+ scoped_ptr<DrawQuad> overlay_quad = quad_list.take(quad_list.begin());
+ quad_list.erase(quad_list.begin());
+ candidate_list->swap(candidates);
+ return true;
+ }
+ return false;
+}
+
+} // namespace cc
diff --git a/chromium/cc/output/overlay_strategy_single_on_top.h b/chromium/cc/output/overlay_strategy_single_on_top.h
new file mode 100644
index 00000000000..d984d3dacb3
--- /dev/null
+++ b/chromium/cc/output/overlay_strategy_single_on_top.h
@@ -0,0 +1,33 @@
+// 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_OUTPUT_OVERLAY_STRATEGY_SINGLE_ON_TOP_H_
+#define CC_OUTPUT_OVERLAY_STRATEGY_SINGLE_ON_TOP_H_
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "cc/base/cc_export.h"
+#include "cc/output/overlay_candidate.h"
+#include "cc/output/overlay_processor.h"
+#include "cc/quads/render_pass.h"
+
+namespace cc {
+class OverlayCandidateValidator;
+
+class CC_EXPORT OverlayStrategySingleOnTop : public OverlayProcessor::Strategy {
+ public:
+ OverlayStrategySingleOnTop(OverlayCandidateValidator* capability_checker,
+ ResourceProvider* resource_provider);
+ virtual bool Attempt(RenderPassList* render_passes_in_draw_order,
+ OverlayCandidateList* candidate_list) OVERRIDE;
+
+ private:
+ OverlayCandidateValidator* capability_checker_;
+ ResourceProvider* resource_provider_;
+ DISALLOW_COPY_AND_ASSIGN(OverlayStrategySingleOnTop);
+};
+
+} // namespace cc
+
+#endif // CC_OUTPUT_OVERLAY_STRATEGY_SINGLE_ON_TOP_H_
diff --git a/chromium/cc/output/overlay_unittest.cc b/chromium/cc/output/overlay_unittest.cc
new file mode 100644
index 00000000000..932ad7a2bcd
--- /dev/null
+++ b/chromium/cc/output/overlay_unittest.cc
@@ -0,0 +1,727 @@
+// 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/base/scoped_ptr_vector.h"
+#include "cc/output/gl_renderer.h"
+#include "cc/output/output_surface.h"
+#include "cc/output/output_surface_client.h"
+#include "cc/output/overlay_candidate_validator.h"
+#include "cc/output/overlay_processor.h"
+#include "cc/output/overlay_strategy_single_on_top.h"
+#include "cc/quads/checkerboard_draw_quad.h"
+#include "cc/quads/render_pass.h"
+#include "cc/quads/texture_draw_quad.h"
+#include "cc/resources/resource_provider.h"
+#include "cc/resources/texture_mailbox.h"
+#include "cc/test/fake_output_surface_client.h"
+#include "cc/test/geometry_test_utils.h"
+#include "cc/test/test_context_provider.h"
+#include "cc/test/test_shared_bitmap_manager.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::Mock;
+
+namespace cc {
+namespace {
+
+const gfx::Rect kOverlayRect(0, 0, 128, 128);
+const gfx::PointF kUVTopLeft(0.1f, 0.2f);
+const gfx::PointF kUVBottomRight(1.0f, 1.0f);
+
+void MailboxReleased(unsigned sync_point, bool lost_resource) {}
+
+class SingleOverlayValidator : public OverlayCandidateValidator {
+ public:
+ virtual void CheckOverlaySupport(OverlayCandidateList* surfaces) OVERRIDE;
+};
+
+void SingleOverlayValidator::CheckOverlaySupport(
+ OverlayCandidateList* surfaces) {
+ ASSERT_EQ(2U, surfaces->size());
+
+ OverlayCandidate& candidate = surfaces->back();
+ EXPECT_EQ(kOverlayRect.ToString(), candidate.display_rect.ToString());
+ EXPECT_EQ(BoundingRect(kUVTopLeft, kUVBottomRight).ToString(),
+ candidate.uv_rect.ToString());
+ candidate.overlay_handled = true;
+}
+
+class SingleOverlayProcessor : public OverlayProcessor {
+ public:
+ SingleOverlayProcessor(OutputSurface* surface,
+ ResourceProvider* resource_provider);
+ // Virtual to allow testing different strategies.
+ virtual void Initialize() OVERRIDE;
+};
+
+SingleOverlayProcessor::SingleOverlayProcessor(
+ OutputSurface* surface,
+ ResourceProvider* resource_provider)
+ : OverlayProcessor(surface, resource_provider) {
+ EXPECT_EQ(surface, surface_);
+ EXPECT_EQ(resource_provider, resource_provider_);
+}
+
+void SingleOverlayProcessor::Initialize() {
+ OverlayCandidateValidator* candidates =
+ surface_->overlay_candidate_validator();
+ ASSERT_TRUE(candidates != NULL);
+ strategies_.push_back(scoped_ptr<Strategy>(
+ new OverlayStrategySingleOnTop(candidates, resource_provider_)));
+}
+
+class DefaultOverlayProcessor : public OverlayProcessor {
+ public:
+ DefaultOverlayProcessor(OutputSurface* surface,
+ ResourceProvider* resource_provider);
+ size_t GetStrategyCount();
+};
+
+DefaultOverlayProcessor::DefaultOverlayProcessor(
+ OutputSurface* surface,
+ ResourceProvider* resource_provider)
+ : OverlayProcessor(surface, resource_provider) {}
+
+size_t DefaultOverlayProcessor::GetStrategyCount() {
+ return strategies_.size();
+}
+
+class OverlayOutputSurface : public OutputSurface {
+ public:
+ explicit OverlayOutputSurface(scoped_refptr<ContextProvider> context_provider)
+ : OutputSurface(context_provider) {}
+
+ void InitWithSingleOverlayValidator() {
+ overlay_candidate_validator_.reset(new SingleOverlayValidator);
+ }
+};
+
+scoped_ptr<RenderPass> CreateRenderPass() {
+ RenderPass::Id id(1, 0);
+ gfx::Rect output_rect(0, 0, 256, 256);
+ bool has_transparent_background = true;
+
+ scoped_ptr<RenderPass> pass = RenderPass::Create();
+ pass->SetAll(id,
+ output_rect,
+ output_rect,
+ gfx::Transform(),
+ has_transparent_background);
+
+ SharedQuadState* shared_state = pass->CreateAndAppendSharedQuadState();
+ shared_state->opacity = 1.f;
+ return pass.Pass();
+}
+
+ResourceProvider::ResourceId CreateResource(
+ ResourceProvider* resource_provider) {
+ unsigned sync_point = 0;
+ TextureMailbox mailbox =
+ TextureMailbox(gpu::Mailbox::Generate(), GL_TEXTURE_2D, sync_point);
+ mailbox.set_allow_overlay(true);
+ scoped_ptr<SingleReleaseCallback> release_callback =
+ SingleReleaseCallback::Create(base::Bind(&MailboxReleased));
+
+ return resource_provider->CreateResourceFromTextureMailbox(
+ mailbox, release_callback.Pass());
+}
+
+scoped_ptr<TextureDrawQuad> CreateCandidateQuad(
+ ResourceProvider* resource_provider,
+ const SharedQuadState* shared_quad_state) {
+ ResourceProvider::ResourceId resource_id = CreateResource(resource_provider);
+ bool premultiplied_alpha = false;
+ bool flipped = false;
+ float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+
+ scoped_ptr<TextureDrawQuad> overlay_quad = TextureDrawQuad::Create();
+ overlay_quad->SetNew(shared_quad_state,
+ kOverlayRect,
+ kOverlayRect,
+ kOverlayRect,
+ resource_id,
+ premultiplied_alpha,
+ kUVTopLeft,
+ kUVBottomRight,
+ SK_ColorTRANSPARENT,
+ vertex_opacity,
+ flipped);
+
+ return overlay_quad.Pass();
+}
+
+scoped_ptr<DrawQuad> CreateCheckeredQuad(
+ ResourceProvider* resource_provider,
+ const SharedQuadState* shared_quad_state) {
+ scoped_ptr<CheckerboardDrawQuad> checkerboard_quad =
+ CheckerboardDrawQuad::Create();
+ checkerboard_quad->SetNew(
+ shared_quad_state, kOverlayRect, kOverlayRect, SkColor());
+ return checkerboard_quad.PassAs<DrawQuad>();
+}
+
+static void CompareRenderPassLists(const RenderPassList& expected_list,
+ const RenderPassList& actual_list) {
+ EXPECT_EQ(expected_list.size(), actual_list.size());
+ for (size_t i = 0; i < actual_list.size(); ++i) {
+ RenderPass* expected = expected_list[i];
+ RenderPass* actual = actual_list[i];
+
+ EXPECT_EQ(expected->id, actual->id);
+ EXPECT_RECT_EQ(expected->output_rect, actual->output_rect);
+ EXPECT_EQ(expected->transform_to_root_target,
+ actual->transform_to_root_target);
+ EXPECT_RECT_EQ(expected->damage_rect, actual->damage_rect);
+ EXPECT_EQ(expected->has_transparent_background,
+ actual->has_transparent_background);
+
+ EXPECT_EQ(expected->shared_quad_state_list.size(),
+ actual->shared_quad_state_list.size());
+ EXPECT_EQ(expected->quad_list.size(), actual->quad_list.size());
+
+ for (size_t i = 0; i < expected->quad_list.size(); ++i) {
+ EXPECT_EQ(expected->quad_list[i]->rect.ToString(),
+ actual->quad_list[i]->rect.ToString());
+ EXPECT_EQ(
+ expected->quad_list[i]->shared_quad_state->content_bounds.ToString(),
+ actual->quad_list[i]->shared_quad_state->content_bounds.ToString());
+ }
+ }
+}
+
+TEST(OverlayTest, NoOverlaysByDefault) {
+ scoped_refptr<TestContextProvider> provider = TestContextProvider::Create();
+ OverlayOutputSurface output_surface(provider);
+ EXPECT_EQ(NULL, output_surface.overlay_candidate_validator());
+
+ output_surface.InitWithSingleOverlayValidator();
+ EXPECT_TRUE(output_surface.overlay_candidate_validator() != NULL);
+}
+
+TEST(OverlayTest, OverlaysProcessorHasStrategy) {
+ scoped_refptr<TestContextProvider> provider = TestContextProvider::Create();
+ OverlayOutputSurface output_surface(provider);
+ FakeOutputSurfaceClient client;
+ EXPECT_TRUE(output_surface.BindToClient(&client));
+ output_surface.InitWithSingleOverlayValidator();
+ EXPECT_TRUE(output_surface.overlay_candidate_validator() != NULL);
+
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
+ scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
+ &output_surface, shared_bitmap_manager.get(), 0, false, 1, false));
+
+ scoped_ptr<DefaultOverlayProcessor> overlay_processor(
+ new DefaultOverlayProcessor(&output_surface, resource_provider.get()));
+ overlay_processor->Initialize();
+ EXPECT_GE(1U, overlay_processor->GetStrategyCount());
+}
+
+class SingleOverlayOnTopTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ provider_ = TestContextProvider::Create();
+ output_surface_.reset(new OverlayOutputSurface(provider_));
+ EXPECT_TRUE(output_surface_->BindToClient(&client_));
+ output_surface_->InitWithSingleOverlayValidator();
+ EXPECT_TRUE(output_surface_->overlay_candidate_validator() != NULL);
+
+ shared_bitmap_manager_.reset(new TestSharedBitmapManager());
+ resource_provider_ = ResourceProvider::Create(
+ output_surface_.get(), shared_bitmap_manager_.get(), 0, false, 1,
+ false);
+
+ overlay_processor_.reset(new SingleOverlayProcessor(
+ output_surface_.get(), resource_provider_.get()));
+ overlay_processor_->Initialize();
+ }
+
+ scoped_refptr<TestContextProvider> provider_;
+ scoped_ptr<OverlayOutputSurface> output_surface_;
+ FakeOutputSurfaceClient client_;
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager_;
+ scoped_ptr<ResourceProvider> resource_provider_;
+ scoped_ptr<SingleOverlayProcessor> overlay_processor_;
+};
+
+TEST_F(SingleOverlayOnTopTest, SuccessfullOverlay) {
+ scoped_ptr<RenderPass> pass = CreateRenderPass();
+ scoped_ptr<TextureDrawQuad> original_quad = CreateCandidateQuad(
+ resource_provider_.get(), pass->shared_quad_state_list.back());
+
+ pass->quad_list.push_back(
+ original_quad->Copy(pass->shared_quad_state_list.back()));
+ // Add something behind it.
+ pass->quad_list.push_back(CreateCheckeredQuad(
+ resource_provider_.get(), pass->shared_quad_state_list.back()));
+ pass->quad_list.push_back(CreateCheckeredQuad(
+ resource_provider_.get(), pass->shared_quad_state_list.back()));
+
+ RenderPassList pass_list;
+ pass_list.push_back(pass.Pass());
+
+ // Check for potential candidates.
+ OverlayCandidateList candidate_list;
+ overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list);
+
+ ASSERT_EQ(1U, pass_list.size());
+ ASSERT_EQ(2U, candidate_list.size());
+
+ RenderPass* main_pass = pass_list.back();
+ // Check that the quad is gone.
+ EXPECT_EQ(2U, main_pass->quad_list.size());
+ const QuadList& quad_list = main_pass->quad_list;
+ for (QuadList::ConstBackToFrontIterator it = quad_list.BackToFrontBegin();
+ it != quad_list.BackToFrontEnd();
+ ++it) {
+ EXPECT_NE(DrawQuad::TEXTURE_CONTENT, (*it)->material);
+ }
+
+ // Check that the right resource id got extracted.
+ EXPECT_EQ(original_quad->resource_id, candidate_list.back().resource_id);
+}
+
+TEST_F(SingleOverlayOnTopTest, NoCandidates) {
+ scoped_ptr<RenderPass> pass = CreateRenderPass();
+ pass->quad_list.push_back(CreateCheckeredQuad(
+ resource_provider_.get(), pass->shared_quad_state_list.back()));
+ pass->quad_list.push_back(CreateCheckeredQuad(
+ resource_provider_.get(), pass->shared_quad_state_list.back()));
+
+ RenderPassList pass_list;
+ pass_list.push_back(pass.Pass());
+
+ RenderPassList original_pass_list;
+ RenderPass::CopyAll(pass_list, &original_pass_list);
+
+ OverlayCandidateList candidate_list;
+ overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list);
+ EXPECT_EQ(0U, candidate_list.size());
+ // There should be nothing new here.
+ CompareRenderPassLists(pass_list, original_pass_list);
+}
+
+TEST_F(SingleOverlayOnTopTest, OccludedCandidates) {
+ scoped_ptr<RenderPass> pass = CreateRenderPass();
+ pass->quad_list.push_back(CreateCheckeredQuad(
+ resource_provider_.get(), pass->shared_quad_state_list.back()));
+ pass->quad_list.push_back(CreateCheckeredQuad(
+ resource_provider_.get(), pass->shared_quad_state_list.back()));
+
+ pass->quad_list.push_back(
+ CreateCandidateQuad(resource_provider_.get(),
+ pass->shared_quad_state_list.back())
+ .PassAs<DrawQuad>());
+
+ RenderPassList pass_list;
+ pass_list.push_back(pass.Pass());
+
+ RenderPassList original_pass_list;
+ RenderPass::CopyAll(pass_list, &original_pass_list);
+
+ OverlayCandidateList candidate_list;
+ overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list);
+ EXPECT_EQ(0U, candidate_list.size());
+ // There should be nothing new here.
+ CompareRenderPassLists(pass_list, original_pass_list);
+}
+
+// Test with multiple render passes.
+TEST_F(SingleOverlayOnTopTest, MultipleRenderPasses) {
+ RenderPassList pass_list;
+ pass_list.push_back(CreateRenderPass());
+
+ scoped_ptr<RenderPass> pass = CreateRenderPass();
+ scoped_ptr<TextureDrawQuad> original_quad = CreateCandidateQuad(
+ resource_provider_.get(), pass->shared_quad_state_list.back());
+
+ pass->quad_list.push_back(
+ original_quad->Copy(pass->shared_quad_state_list.back()));
+ // Add something behind it.
+ pass->quad_list.push_back(CreateCheckeredQuad(
+ resource_provider_.get(), pass->shared_quad_state_list.back()));
+ pass->quad_list.push_back(CreateCheckeredQuad(
+ resource_provider_.get(), pass->shared_quad_state_list.back()));
+
+ pass_list.push_back(pass.Pass());
+
+ RenderPassList original_pass_list;
+ RenderPass::CopyAll(pass_list, &original_pass_list);
+
+ // Check for potential candidates.
+ OverlayCandidateList candidate_list;
+ overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list);
+ EXPECT_EQ(2U, candidate_list.size());
+
+ // This should be the same.
+ ASSERT_EQ(2U, pass_list.size());
+}
+
+TEST_F(SingleOverlayOnTopTest, RejectPremultipliedAlpha) {
+ scoped_ptr<RenderPass> pass = CreateRenderPass();
+ scoped_ptr<TextureDrawQuad> quad = CreateCandidateQuad(
+ resource_provider_.get(), pass->shared_quad_state_list.back());
+ quad->premultiplied_alpha = true;
+
+ pass->quad_list.push_back(quad.PassAs<DrawQuad>());
+ RenderPassList pass_list;
+ pass_list.push_back(pass.Pass());
+ OverlayCandidateList candidate_list;
+ overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list);
+ EXPECT_EQ(1U, pass_list.size());
+ EXPECT_EQ(0U, candidate_list.size());
+}
+
+TEST_F(SingleOverlayOnTopTest, RejectBlending) {
+ scoped_ptr<RenderPass> pass = CreateRenderPass();
+ scoped_ptr<TextureDrawQuad> quad = CreateCandidateQuad(
+ resource_provider_.get(), pass->shared_quad_state_list.back());
+ quad->needs_blending = true;
+
+ pass->quad_list.push_back(quad.PassAs<DrawQuad>());
+ RenderPassList pass_list;
+ pass_list.push_back(pass.Pass());
+ OverlayCandidateList candidate_list;
+ overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list);
+ ASSERT_EQ(1U, pass_list.size());
+ EXPECT_EQ(0U, candidate_list.size());
+}
+
+TEST_F(SingleOverlayOnTopTest, RejectBackgroundColor) {
+ scoped_ptr<RenderPass> pass = CreateRenderPass();
+ scoped_ptr<TextureDrawQuad> quad = CreateCandidateQuad(
+ resource_provider_.get(), pass->shared_quad_state_list.back());
+ quad->background_color = SK_ColorBLACK;
+
+ pass->quad_list.push_back(quad.PassAs<DrawQuad>());
+ RenderPassList pass_list;
+ pass_list.push_back(pass.Pass());
+ OverlayCandidateList candidate_list;
+ overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list);
+ ASSERT_EQ(1U, pass_list.size());
+ EXPECT_EQ(0U, candidate_list.size());
+}
+
+TEST_F(SingleOverlayOnTopTest, RejectBlendMode) {
+ scoped_ptr<RenderPass> pass = CreateRenderPass();
+ scoped_ptr<TextureDrawQuad> quad = CreateCandidateQuad(
+ resource_provider_.get(), pass->shared_quad_state_list.back());
+ pass->shared_quad_state_list.back()->blend_mode = SkXfermode::kScreen_Mode;
+
+ pass->quad_list.push_back(quad.PassAs<DrawQuad>());
+ RenderPassList pass_list;
+ pass_list.push_back(pass.Pass());
+ OverlayCandidateList candidate_list;
+ overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list);
+ ASSERT_EQ(1U, pass_list.size());
+ EXPECT_EQ(0U, candidate_list.size());
+}
+
+TEST_F(SingleOverlayOnTopTest, RejectOpacity) {
+ scoped_ptr<RenderPass> pass = CreateRenderPass();
+ scoped_ptr<TextureDrawQuad> quad = CreateCandidateQuad(
+ resource_provider_.get(), pass->shared_quad_state_list.back());
+ pass->shared_quad_state_list.back()->opacity = 0.5f;
+
+ pass->quad_list.push_back(quad.PassAs<DrawQuad>());
+ RenderPassList pass_list;
+ pass_list.push_back(pass.Pass());
+ OverlayCandidateList candidate_list;
+ overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list);
+ ASSERT_EQ(1U, pass_list.size());
+ EXPECT_EQ(0U, candidate_list.size());
+}
+
+TEST_F(SingleOverlayOnTopTest, RejectTransform) {
+ scoped_ptr<RenderPass> pass = CreateRenderPass();
+ scoped_ptr<TextureDrawQuad> quad = CreateCandidateQuad(
+ resource_provider_.get(), pass->shared_quad_state_list.back());
+ pass->shared_quad_state_list.back()->content_to_target_transform.Scale(2.f,
+ 2.f);
+
+ pass->quad_list.push_back(quad.PassAs<DrawQuad>());
+ RenderPassList pass_list;
+ pass_list.push_back(pass.Pass());
+ OverlayCandidateList candidate_list;
+ overlay_processor_->ProcessForOverlays(&pass_list, &candidate_list);
+ ASSERT_EQ(1U, pass_list.size());
+ EXPECT_EQ(0U, candidate_list.size());
+}
+
+class OverlayInfoRendererGL : public GLRenderer {
+ public:
+ OverlayInfoRendererGL(RendererClient* client,
+ const LayerTreeSettings* settings,
+ OutputSurface* output_surface,
+ ResourceProvider* resource_provider)
+ : GLRenderer(client,
+ settings,
+ output_surface,
+ resource_provider,
+ NULL,
+ 0),
+ expect_overlays_(false) {}
+
+ MOCK_METHOD2(DoDrawQuad, void(DrawingFrame* frame, const DrawQuad* quad));
+
+ virtual void FinishDrawingFrame(DrawingFrame* frame) OVERRIDE {
+ GLRenderer::FinishDrawingFrame(frame);
+
+ if (!expect_overlays_) {
+ EXPECT_EQ(0U, frame->overlay_list.size());
+ return;
+ }
+
+ ASSERT_EQ(2U, frame->overlay_list.size());
+ EXPECT_NE(0U, frame->overlay_list.back().resource_id);
+ }
+
+ void set_expect_overlays(bool expect_overlays) {
+ expect_overlays_ = expect_overlays;
+ }
+
+ private:
+ bool expect_overlays_;
+};
+
+class FakeRendererClient : public RendererClient {
+ public:
+ // RendererClient methods.
+ virtual void SetFullRootLayerDamage() OVERRIDE {}
+ virtual void RunOnDemandRasterTask(Task* on_demand_raster_task) OVERRIDE {}
+};
+
+class MockOverlayScheduler {
+ public:
+ MOCK_METHOD5(Schedule,
+ void(int plane_z_order,
+ gfx::OverlayTransform plane_transform,
+ unsigned overlay_texture_id,
+ const gfx::Rect& display_bounds,
+ const gfx::RectF& uv_rect));
+};
+
+class GLRendererWithOverlaysTest : public testing::Test {
+ protected:
+ GLRendererWithOverlaysTest() {
+ provider_ = TestContextProvider::Create();
+ output_surface_.reset(new OverlayOutputSurface(provider_));
+ CHECK(output_surface_->BindToClient(&output_surface_client_));
+ resource_provider_ =
+ ResourceProvider::Create(output_surface_.get(), NULL, 0, false, 1,
+ false);
+
+ provider_->support()->SetScheduleOverlayPlaneCallback(base::Bind(
+ &MockOverlayScheduler::Schedule, base::Unretained(&scheduler_)));
+ }
+
+ void Init(bool use_validator) {
+ if (use_validator)
+ output_surface_->InitWithSingleOverlayValidator();
+
+ renderer_ =
+ make_scoped_ptr(new OverlayInfoRendererGL(&renderer_client_,
+ &settings_,
+ output_surface_.get(),
+ resource_provider_.get()));
+ }
+
+ void SwapBuffers() { renderer_->SwapBuffers(CompositorFrameMetadata()); }
+
+ LayerTreeSettings settings_;
+ FakeOutputSurfaceClient output_surface_client_;
+ scoped_ptr<OverlayOutputSurface> output_surface_;
+ FakeRendererClient renderer_client_;
+ scoped_ptr<ResourceProvider> resource_provider_;
+ scoped_ptr<OverlayInfoRendererGL> renderer_;
+ scoped_refptr<TestContextProvider> provider_;
+ MockOverlayScheduler scheduler_;
+};
+
+TEST_F(GLRendererWithOverlaysTest, OverlayQuadNotDrawn) {
+ bool use_validator = true;
+ Init(use_validator);
+ renderer_->set_expect_overlays(true);
+ gfx::Rect viewport_rect(16, 16);
+
+ scoped_ptr<RenderPass> pass = CreateRenderPass();
+
+ pass->quad_list.push_back(
+ CreateCandidateQuad(resource_provider_.get(),
+ pass->shared_quad_state_list.back())
+ .PassAs<DrawQuad>());
+
+ pass->quad_list.push_back(CreateCheckeredQuad(
+ resource_provider_.get(), pass->shared_quad_state_list.back()));
+ pass->quad_list.push_back(CreateCheckeredQuad(
+ resource_provider_.get(), pass->shared_quad_state_list.back()));
+
+ RenderPassList pass_list;
+ pass_list.push_back(pass.Pass());
+
+ // Candidate pass was taken out and extra skipped pass added,
+ // so only draw 2 quads.
+ EXPECT_CALL(*renderer_, DoDrawQuad(_, _)).Times(2);
+ EXPECT_CALL(scheduler_,
+ Schedule(1,
+ gfx::OVERLAY_TRANSFORM_NONE,
+ _,
+ kOverlayRect,
+ BoundingRect(kUVTopLeft, kUVBottomRight))).Times(1);
+ renderer_->DrawFrame(&pass_list, 1.f, viewport_rect, viewport_rect, false);
+
+ SwapBuffers();
+
+ Mock::VerifyAndClearExpectations(renderer_.get());
+ Mock::VerifyAndClearExpectations(&scheduler_);
+}
+
+TEST_F(GLRendererWithOverlaysTest, OccludedQuadDrawn) {
+ bool use_validator = true;
+ Init(use_validator);
+ renderer_->set_expect_overlays(false);
+ gfx::Rect viewport_rect(16, 16);
+
+ scoped_ptr<RenderPass> pass = CreateRenderPass();
+
+ pass->quad_list.push_back(CreateCheckeredQuad(
+ resource_provider_.get(), pass->shared_quad_state_list.back()));
+ pass->quad_list.push_back(CreateCheckeredQuad(
+ resource_provider_.get(), pass->shared_quad_state_list.back()));
+
+ pass->quad_list.push_back(
+ CreateCandidateQuad(resource_provider_.get(),
+ pass->shared_quad_state_list.back())
+ .PassAs<DrawQuad>());
+
+ RenderPassList pass_list;
+ pass_list.push_back(pass.Pass());
+
+ // 3 quads in the pass, all should draw.
+ EXPECT_CALL(*renderer_, DoDrawQuad(_, _)).Times(3);
+ EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(0);
+ renderer_->DrawFrame(&pass_list, 1.f, viewport_rect, viewport_rect, false);
+
+ SwapBuffers();
+
+ Mock::VerifyAndClearExpectations(renderer_.get());
+ Mock::VerifyAndClearExpectations(&scheduler_);
+}
+
+TEST_F(GLRendererWithOverlaysTest, NoValidatorNoOverlay) {
+ bool use_validator = false;
+ Init(use_validator);
+ renderer_->set_expect_overlays(false);
+ gfx::Rect viewport_rect(16, 16);
+
+ scoped_ptr<RenderPass> pass = CreateRenderPass();
+
+ pass->quad_list.push_back(
+ CreateCandidateQuad(resource_provider_.get(),
+ pass->shared_quad_state_list.back())
+ .PassAs<DrawQuad>());
+
+ pass->quad_list.push_back(CreateCheckeredQuad(
+ resource_provider_.get(), pass->shared_quad_state_list.back()));
+ pass->quad_list.push_back(CreateCheckeredQuad(
+ resource_provider_.get(), pass->shared_quad_state_list.back()));
+
+ RenderPassList pass_list;
+ pass_list.push_back(pass.Pass());
+
+ // Should see no overlays.
+ EXPECT_CALL(*renderer_, DoDrawQuad(_, _)).Times(3);
+ EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(0);
+ renderer_->DrawFrame(&pass_list, 1.f, viewport_rect, viewport_rect, false);
+
+ SwapBuffers();
+
+ Mock::VerifyAndClearExpectations(renderer_.get());
+ Mock::VerifyAndClearExpectations(&scheduler_);
+}
+
+TEST_F(GLRendererWithOverlaysTest, ResourcesExportedAndReturned) {
+ bool use_validator = true;
+ Init(use_validator);
+ renderer_->set_expect_overlays(true);
+
+ ResourceProvider::ResourceId resource1 =
+ CreateResource(resource_provider_.get());
+ ResourceProvider::ResourceId resource2 =
+ CreateResource(resource_provider_.get());
+
+ DirectRenderer::DrawingFrame frame1;
+ frame1.overlay_list.resize(2);
+ OverlayCandidate& overlay1 = frame1.overlay_list.back();
+ overlay1.resource_id = resource1;
+ overlay1.plane_z_order = 1;
+
+ DirectRenderer::DrawingFrame frame2;
+ frame2.overlay_list.resize(2);
+ OverlayCandidate& overlay2 = frame2.overlay_list.back();
+ overlay2.resource_id = resource2;
+ overlay2.plane_z_order = 1;
+
+ EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(1);
+ renderer_->FinishDrawingFrame(&frame1);
+ EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1));
+ EXPECT_FALSE(resource_provider_->InUseByConsumer(resource2));
+ SwapBuffers();
+ Mock::VerifyAndClearExpectations(&scheduler_);
+
+ EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(1);
+ renderer_->FinishDrawingFrame(&frame2);
+ EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1));
+ EXPECT_TRUE(resource_provider_->InUseByConsumer(resource2));
+ SwapBuffers();
+ EXPECT_FALSE(resource_provider_->InUseByConsumer(resource1));
+ Mock::VerifyAndClearExpectations(&scheduler_);
+
+ EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(1);
+ renderer_->FinishDrawingFrame(&frame1);
+ EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1));
+ EXPECT_TRUE(resource_provider_->InUseByConsumer(resource2));
+ SwapBuffers();
+ EXPECT_FALSE(resource_provider_->InUseByConsumer(resource2));
+ Mock::VerifyAndClearExpectations(&scheduler_);
+
+ // No overlays, release the resource.
+ EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(0);
+ DirectRenderer::DrawingFrame frame3;
+ renderer_->set_expect_overlays(false);
+ renderer_->FinishDrawingFrame(&frame3);
+ EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1));
+ EXPECT_FALSE(resource_provider_->InUseByConsumer(resource2));
+ SwapBuffers();
+ EXPECT_FALSE(resource_provider_->InUseByConsumer(resource1));
+ Mock::VerifyAndClearExpectations(&scheduler_);
+
+ // Use the same buffer twice.
+ renderer_->set_expect_overlays(true);
+ EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(1);
+ renderer_->FinishDrawingFrame(&frame1);
+ EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1));
+ SwapBuffers();
+ Mock::VerifyAndClearExpectations(&scheduler_);
+
+ EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(1);
+ renderer_->FinishDrawingFrame(&frame1);
+ EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1));
+ SwapBuffers();
+ EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1));
+ Mock::VerifyAndClearExpectations(&scheduler_);
+
+ EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(0);
+ renderer_->set_expect_overlays(false);
+ renderer_->FinishDrawingFrame(&frame3);
+ EXPECT_TRUE(resource_provider_->InUseByConsumer(resource1));
+ SwapBuffers();
+ EXPECT_FALSE(resource_provider_->InUseByConsumer(resource1));
+ Mock::VerifyAndClearExpectations(&scheduler_);
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/output/render_surface_filters.cc b/chromium/cc/output/render_surface_filters.cc
index e10ea885e7f..34e056dad52 100644
--- a/chromium/cc/output/render_surface_filters.cc
+++ b/chromium/cc/output/render_surface_filters.cc
@@ -13,12 +13,14 @@
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkFlattenableBuffers.h"
#include "third_party/skia/include/core/SkImageFilter.h"
+#include "third_party/skia/include/effects/SkAlphaThresholdFilter.h"
#include "third_party/skia/include/effects/SkBlurImageFilter.h"
#include "third_party/skia/include/effects/SkColorFilterImageFilter.h"
#include "third_party/skia/include/effects/SkColorMatrixFilter.h"
#include "third_party/skia/include/effects/SkComposeImageFilter.h"
#include "third_party/skia/include/effects/SkDropShadowImageFilter.h"
#include "third_party/skia/include/effects/SkMagnifierImageFilter.h"
+#include "third_party/skia/include/effects/SkRectShaderImageFilter.h"
#include "third_party/skia/include/gpu/SkGpuDevice.h"
#include "third_party/skia/include/gpu/SkGrPixelRef.h"
#include "ui/gfx/size_f.h"
@@ -151,7 +153,7 @@ skia::RefPtr<SkImageFilter> CreateMatrixImageFilter(
const SkScalar matrix[20],
const skia::RefPtr<SkImageFilter>& input) {
skia::RefPtr<SkColorFilter> color_filter =
- skia::AdoptRef(new SkColorMatrixFilter(matrix));
+ skia::AdoptRef(SkColorMatrixFilter::Create(matrix));
return skia::AdoptRef(
SkColorFilterImageFilter::Create(color_filter.get(), input.get()));
}
@@ -160,7 +162,7 @@ skia::RefPtr<SkImageFilter> CreateMatrixImageFilter(
skia::RefPtr<SkImageFilter> RenderSurfaceFilters::BuildImageFilter(
const FilterOperations& filters,
- gfx::SizeF size) {
+ const gfx::SizeF& size) {
skia::RefPtr<SkImageFilter> image_filter;
SkScalar matrix[20];
for (size_t i = 0; i < filters.size(); ++i) {
@@ -199,11 +201,11 @@ skia::RefPtr<SkImageFilter> RenderSurfaceFilters::BuildImageFilter(
image_filter = CreateMatrixImageFilter(matrix, image_filter);
break;
case FilterOperation::BLUR:
- image_filter = skia::AdoptRef(new SkBlurImageFilter(
+ image_filter = skia::AdoptRef(SkBlurImageFilter::Create(
op.amount(), op.amount(), image_filter.get()));
break;
case FilterOperation::DROP_SHADOW:
- image_filter = skia::AdoptRef(new SkDropShadowImageFilter(
+ image_filter = skia::AdoptRef(SkDropShadowImageFilter::Create(
SkIntToScalar(op.drop_shadow_offset().x()),
SkIntToScalar(op.drop_shadow_offset().y()),
SkIntToScalar(op.amount()),
@@ -214,8 +216,8 @@ skia::RefPtr<SkImageFilter> RenderSurfaceFilters::BuildImageFilter(
image_filter = CreateMatrixImageFilter(op.matrix(), image_filter);
break;
case FilterOperation::ZOOM: {
- skia::RefPtr<SkImageFilter> zoom_filter = skia::AdoptRef(
- new SkMagnifierImageFilter(
+ skia::RefPtr<SkImageFilter> zoom_filter =
+ skia::AdoptRef(SkMagnifierImageFilter::Create(
SkRect::MakeXYWH(
(size.width() - (size.width() / op.amount())) / 2.f,
(size.height() - (size.height() / op.amount())) / 2.f,
@@ -226,7 +228,7 @@ skia::RefPtr<SkImageFilter> RenderSurfaceFilters::BuildImageFilter(
// TODO(ajuma): When there's a 1-input version of
// SkMagnifierImageFilter, use that to handle the input filter
// instead of using an SkComposeImageFilter.
- image_filter = skia::AdoptRef(new SkComposeImageFilter(
+ image_filter = skia::AdoptRef(SkComposeImageFilter::Create(
zoom_filter.get(), image_filter.get()));
} else {
image_filter = zoom_filter;
@@ -253,13 +255,25 @@ skia::RefPtr<SkImageFilter> RenderSurfaceFilters::BuildImageFilter(
!op.image_filter()->getInput(0)) {
image_filter = CreateMatrixImageFilter(matrix, image_filter);
} else if (image_filter) {
- image_filter = skia::AdoptRef(new SkComposeImageFilter(
+ image_filter = skia::AdoptRef(SkComposeImageFilter::Create(
op.image_filter().get(), image_filter.get()));
} else {
image_filter = op.image_filter();
}
break;
}
+ case FilterOperation::ALPHA_THRESHOLD: {
+ skia::RefPtr<SkImageFilter> alpha_filter = skia::AdoptRef(
+ SkAlphaThresholdFilter::Create(
+ op.region(), op.amount(), op.outer_threshold()));
+ if (image_filter.get()) {
+ image_filter = skia::AdoptRef(SkComposeImageFilter::Create(
+ alpha_filter.get(), image_filter.get()));
+ } else {
+ image_filter = alpha_filter;
+ }
+ break;
+ }
}
}
return image_filter;
diff --git a/chromium/cc/output/render_surface_filters.h b/chromium/cc/output/render_surface_filters.h
index 09d0f732a03..42b6e451501 100644
--- a/chromium/cc/output/render_surface_filters.h
+++ b/chromium/cc/output/render_surface_filters.h
@@ -26,13 +26,13 @@ class CC_EXPORT RenderSurfaceFilters {
public:
static SkBitmap Apply(const FilterOperations& filters,
unsigned texture_id,
- gfx::SizeF size,
+ const gfx::SizeF& size,
GrContext* gr_context);
static FilterOperations Optimize(const FilterOperations& filters);
static skia::RefPtr<SkImageFilter> BuildImageFilter(
const FilterOperations& filters,
- gfx::SizeF size);
+ const gfx::SizeF& size);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(RenderSurfaceFilters);
diff --git a/chromium/cc/output/renderer.cc b/chromium/cc/output/renderer.cc
index 2fe0ef75b5f..e17714911ed 100644
--- a/chromium/cc/output/renderer.cc
+++ b/chromium/cc/output/renderer.cc
@@ -14,4 +14,33 @@ bool Renderer::IsContextLost() {
return false;
}
+void Renderer::SetVisible(bool visible) {
+ if (visible_ == visible)
+ return;
+
+ visible_ = visible;
+ DidChangeVisibility();
+}
+
+RendererCapabilitiesImpl::RendererCapabilitiesImpl()
+ : best_texture_format(RGBA_8888),
+ allow_partial_texture_updates(false),
+ max_texture_size(0),
+ using_shared_memory_resources(false),
+ using_partial_swap(false),
+ using_egl_image(false),
+ avoid_pow2_textures(false),
+ using_map_image(false),
+ using_discard_framebuffer(false),
+ allow_rasterize_on_demand(false) {}
+
+RendererCapabilitiesImpl::~RendererCapabilitiesImpl() {}
+
+RendererCapabilities RendererCapabilitiesImpl::MainThreadCapabilities() const {
+ return RendererCapabilities(best_texture_format,
+ allow_partial_texture_updates,
+ max_texture_size,
+ using_shared_memory_resources);
+}
+
} // namespace cc
diff --git a/chromium/cc/output/renderer.h b/chromium/cc/output/renderer.h
index 147b535fd72..d95a7479188 100644
--- a/chromium/cc/output/renderer.h
+++ b/chromium/cc/output/renderer.h
@@ -15,19 +15,40 @@ namespace cc {
class CompositorFrameAck;
class CompositorFrameMetadata;
class ScopedResource;
+class Task;
+
+struct RendererCapabilitiesImpl {
+ RendererCapabilitiesImpl();
+ ~RendererCapabilitiesImpl();
+
+ // Capabilities copied to main thread.
+ ResourceFormat best_texture_format;
+ bool allow_partial_texture_updates;
+ int max_texture_size;
+ bool using_shared_memory_resources;
+
+ // Capabilities used on compositor thread only.
+ bool using_partial_swap;
+ bool using_egl_image;
+ bool avoid_pow2_textures;
+ bool using_map_image;
+ bool using_discard_framebuffer;
+ bool allow_rasterize_on_demand;
+
+ RendererCapabilities MainThreadCapabilities() const;
+};
class CC_EXPORT RendererClient {
public:
virtual void SetFullRootLayerDamage() = 0;
+ virtual void RunOnDemandRasterTask(Task* on_demand_raster_task) = 0;
};
class CC_EXPORT Renderer {
public:
virtual ~Renderer() {}
- virtual const RendererCapabilities& Capabilities() const = 0;
-
- virtual bool CanReadPixels() const = 0;
+ virtual const RendererCapabilitiesImpl& Capabilities() const = 0;
virtual void DecideRenderPassAllocationsForFrame(
const RenderPassList& render_passes_in_draw_order) {}
@@ -39,11 +60,9 @@ class CC_EXPORT Renderer {
// The |device_viewport_rect| and |device_clip_rect| are in non-y-flipped
// window space.
virtual void DrawFrame(RenderPassList* render_passes_in_draw_order,
- ContextProvider* offscreen_context_provider,
float device_scale_factor,
- gfx::Rect device_viewport_rect,
- gfx::Rect device_clip_rect,
- bool allow_partial_swap,
+ const gfx::Rect& device_viewport_rect,
+ const gfx::Rect& device_clip_rect,
bool disable_picture_quad_image_filtering) = 0;
// Waits for rendering to finish.
@@ -55,22 +74,20 @@ class CC_EXPORT Renderer {
virtual void SwapBuffers(const CompositorFrameMetadata& metadata) = 0;
virtual void ReceiveSwapBuffersAck(const CompositorFrameAck& ack) {}
- virtual void GetFramebufferPixels(void* pixels, gfx::Rect rect) = 0;
-
virtual bool IsContextLost();
- virtual void SetVisible(bool visible) = 0;
-
- virtual void SendManagedMemoryStats(size_t bytes_visible,
- size_t bytes_visible_and_nearby,
- size_t bytes_allocated) = 0;
+ bool visible() const { return visible_; }
+ void SetVisible(bool visible);
protected:
explicit Renderer(RendererClient* client, const LayerTreeSettings* settings)
- : client_(client), settings_(settings) {}
+ : client_(client), settings_(settings), visible_(true) {}
+
+ virtual void DidChangeVisibility() = 0;
RendererClient* client_;
const LayerTreeSettings* settings_;
+ bool visible_;
private:
DISALLOW_COPY_AND_ASSIGN(Renderer);
diff --git a/chromium/cc/output/renderer_pixeltest.cc b/chromium/cc/output/renderer_pixeltest.cc
index 24c6126755e..2377043d45a 100644
--- a/chromium/cc/output/renderer_pixeltest.cc
+++ b/chromium/cc/output/renderer_pixeltest.cc
@@ -8,25 +8,30 @@
#include "cc/quads/draw_quad.h"
#include "cc/quads/picture_draw_quad.h"
#include "cc/quads/texture_draw_quad.h"
+#include "cc/resources/video_resource_updater.h"
#include "cc/test/fake_picture_pile_impl.h"
#include "cc/test/pixel_test.h"
#include "gpu/GLES2/gl2extchromium.h"
-#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
+#include "gpu/command_buffer/client/gles2_interface.h"
+#include "media/base/video_frame.h"
+#include "third_party/skia/include/core/SkBitmapDevice.h"
#include "third_party/skia/include/core/SkImageFilter.h"
#include "third_party/skia/include/core/SkMatrix.h"
#include "third_party/skia/include/effects/SkColorFilterImageFilter.h"
#include "third_party/skia/include/effects/SkColorMatrixFilter.h"
#include "ui/gfx/rect_conversions.h"
+using gpu::gles2::GLES2Interface;
+
namespace cc {
namespace {
#if !defined(OS_ANDROID)
scoped_ptr<RenderPass> CreateTestRootRenderPass(RenderPass::Id id,
- gfx::Rect rect) {
+ const gfx::Rect& rect) {
scoped_ptr<RenderPass> pass = RenderPass::Create();
const gfx::Rect output_rect = rect;
- const gfx::RectF damage_rect = rect;
+ const gfx::Rect damage_rect = rect;
const gfx::Transform transform_to_root_target;
pass->SetNew(id, output_rect, damage_rect, transform_to_root_target);
return pass.Pass();
@@ -34,59 +39,69 @@ scoped_ptr<RenderPass> CreateTestRootRenderPass(RenderPass::Id id,
scoped_ptr<RenderPass> CreateTestRenderPass(
RenderPass::Id id,
- gfx::Rect rect,
+ const gfx::Rect& rect,
const gfx::Transform& transform_to_root_target) {
scoped_ptr<RenderPass> pass = RenderPass::Create();
const gfx::Rect output_rect = rect;
- const gfx::RectF damage_rect = rect;
+ const gfx::Rect damage_rect = rect;
pass->SetNew(id, output_rect, damage_rect, transform_to_root_target);
return pass.Pass();
}
-scoped_ptr<SharedQuadState> CreateTestSharedQuadState(
- gfx::Transform content_to_target_transform, gfx::Rect rect) {
+SharedQuadState* CreateTestSharedQuadState(
+ RenderPass* render_pass,
+ gfx::Transform content_to_target_transform,
+ const gfx::Rect& rect) {
const gfx::Size content_bounds = rect.size();
const gfx::Rect visible_content_rect = rect;
const gfx::Rect clip_rect = rect;
const bool is_clipped = false;
const float opacity = 1.0f;
const SkXfermode::Mode blend_mode = SkXfermode::kSrcOver_Mode;
- scoped_ptr<SharedQuadState> shared_state = SharedQuadState::Create();
+ int sorting_context_id = 0;
+ SharedQuadState* shared_state = render_pass->CreateAndAppendSharedQuadState();
shared_state->SetAll(content_to_target_transform,
content_bounds,
visible_content_rect,
clip_rect,
is_clipped,
opacity,
- blend_mode);
- return shared_state.Pass();
+ blend_mode,
+ sorting_context_id);
+ return shared_state;
}
-scoped_ptr<SharedQuadState> CreateTestSharedQuadStateClipped(
+SharedQuadState* CreateTestSharedQuadStateClipped(
+ RenderPass* render_pass,
gfx::Transform content_to_target_transform,
- gfx::Rect rect,
- gfx::Rect clip_rect) {
+ const gfx::Rect& rect,
+ const gfx::Rect& clip_rect) {
const gfx::Size content_bounds = rect.size();
const gfx::Rect visible_content_rect = clip_rect;
const bool is_clipped = true;
const float opacity = 1.0f;
const SkXfermode::Mode blend_mode = SkXfermode::kSrcOver_Mode;
- scoped_ptr<SharedQuadState> shared_state = SharedQuadState::Create();
+ int sorting_context_id = 0;
+ SharedQuadState* shared_state = render_pass->CreateAndAppendSharedQuadState();
shared_state->SetAll(content_to_target_transform,
content_bounds,
visible_content_rect,
clip_rect,
is_clipped,
opacity,
- blend_mode);
- return shared_state.Pass();
+ blend_mode,
+ sorting_context_id);
+ return shared_state;
}
scoped_ptr<DrawQuad> CreateTestRenderPassDrawQuad(
- SharedQuadState* shared_state, gfx::Rect rect, RenderPass::Id pass_id) {
+ SharedQuadState* shared_state,
+ const gfx::Rect& rect,
+ RenderPass::Id pass_id) {
scoped_ptr<RenderPassDrawQuad> quad = RenderPassDrawQuad::Create();
quad->SetNew(shared_state,
rect,
+ rect,
pass_id,
false, // is_replica
0, // mask_resource_id
@@ -99,7 +114,7 @@ scoped_ptr<DrawQuad> CreateTestRenderPassDrawQuad(
}
scoped_ptr<TextureDrawQuad> CreateTestTextureDrawQuad(
- gfx::Rect rect,
+ const gfx::Rect& rect,
SkColor texel_color,
SkColor background_color,
bool premultiplied_alpha,
@@ -131,6 +146,7 @@ scoped_ptr<TextureDrawQuad> CreateTestTextureDrawQuad(
quad->SetNew(shared_state,
rect,
gfx::Rect(),
+ rect,
resource,
premultiplied_alpha,
gfx::PointF(0.0f, 0.0f), // uv_top_left
@@ -196,11 +212,11 @@ TYPED_TEST(RendererPixelTest, SimpleGreenRect) {
RenderPass::Id id(1, 1);
scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect);
- scoped_ptr<SharedQuadState> shared_state =
- CreateTestSharedQuadState(gfx::Transform(), rect);
+ SharedQuadState* shared_state =
+ CreateTestSharedQuadState(pass.get(), gfx::Transform(), rect);
scoped_ptr<SolidColorDrawQuad> color_quad = SolidColorDrawQuad::Create();
- color_quad->SetNew(shared_state.get(), rect, SK_ColorGREEN, false);
+ color_quad->SetNew(shared_state, rect, rect, SK_ColorGREEN, false);
pass->quad_list.push_back(color_quad.PassAs<DrawQuad>());
@@ -209,7 +225,6 @@ TYPED_TEST(RendererPixelTest, SimpleGreenRect) {
EXPECT_TRUE(this->RunPixelTest(
&pass_list,
- PixelTest::NoOffscreenContext,
base::FilePath(FILE_PATH_LITERAL("green.png")),
ExactPixelComparator(true)));
}
@@ -222,24 +237,22 @@ TYPED_TEST(RendererPixelTest, SimpleGreenRect_NonRootRenderPass) {
scoped_ptr<RenderPass> child_pass =
CreateTestRenderPass(child_id, small_rect, gfx::Transform());
- scoped_ptr<SharedQuadState> child_shared_state =
- CreateTestSharedQuadState(gfx::Transform(), small_rect);
+ SharedQuadState* child_shared_state =
+ CreateTestSharedQuadState(child_pass.get(), gfx::Transform(), small_rect);
scoped_ptr<SolidColorDrawQuad> color_quad = SolidColorDrawQuad::Create();
- color_quad->SetNew(child_shared_state.get(), rect, SK_ColorGREEN, false);
+ color_quad->SetNew(child_shared_state, rect, rect, SK_ColorGREEN, false);
child_pass->quad_list.push_back(color_quad.PassAs<DrawQuad>());
RenderPass::Id root_id(1, 1);
scoped_ptr<RenderPass> root_pass =
CreateTestRenderPass(root_id, rect, gfx::Transform());
- scoped_ptr<SharedQuadState> root_shared_state =
- CreateTestSharedQuadState(gfx::Transform(), rect);
+ SharedQuadState* root_shared_state =
+ CreateTestSharedQuadState(root_pass.get(), gfx::Transform(), rect);
scoped_ptr<DrawQuad> render_pass_quad =
- CreateTestRenderPassDrawQuad(root_shared_state.get(),
- small_rect,
- child_id);
+ CreateTestRenderPassDrawQuad(root_shared_state, small_rect, child_id);
root_pass->quad_list.push_back(render_pass_quad.PassAs<DrawQuad>());
RenderPass* child_pass_ptr = child_pass.get();
@@ -251,7 +264,6 @@ TYPED_TEST(RendererPixelTest, SimpleGreenRect_NonRootRenderPass) {
EXPECT_TRUE(this->RunPixelTestWithReadbackTarget(
&pass_list,
child_pass_ptr,
- PixelTest::NoOffscreenContext,
base::FilePath(FILE_PATH_LITERAL("green_small.png")),
ExactPixelComparator(true)));
}
@@ -262,20 +274,20 @@ TYPED_TEST(RendererPixelTest, PremultipliedTextureWithoutBackground) {
RenderPass::Id id(1, 1);
scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect);
- scoped_ptr<SharedQuadState> shared_state =
- CreateTestSharedQuadState(gfx::Transform(), rect);
+ SharedQuadState* shared_state =
+ CreateTestSharedQuadState(pass.get(), gfx::Transform(), rect);
- scoped_ptr<TextureDrawQuad> texture_quad = CreateTestTextureDrawQuad(
- gfx::Rect(this->device_viewport_size_),
- SkColorSetARGB(128, 0, 255, 0), // Texel color.
- SK_ColorTRANSPARENT, // Background color.
- true, // Premultiplied alpha.
- shared_state.get(),
- this->resource_provider_.get());
+ scoped_ptr<TextureDrawQuad> texture_quad =
+ CreateTestTextureDrawQuad(gfx::Rect(this->device_viewport_size_),
+ SkColorSetARGB(128, 0, 255, 0), // Texel color.
+ SK_ColorTRANSPARENT, // Background color.
+ true, // Premultiplied alpha.
+ shared_state,
+ this->resource_provider_.get());
pass->quad_list.push_back(texture_quad.PassAs<DrawQuad>());
scoped_ptr<SolidColorDrawQuad> color_quad = SolidColorDrawQuad::Create();
- color_quad->SetNew(shared_state.get(), rect, SK_ColorWHITE, false);
+ color_quad->SetNew(shared_state, rect, rect, SK_ColorWHITE, false);
pass->quad_list.push_back(color_quad.PassAs<DrawQuad>());
RenderPassList pass_list;
@@ -283,7 +295,6 @@ TYPED_TEST(RendererPixelTest, PremultipliedTextureWithoutBackground) {
EXPECT_TRUE(this->RunPixelTest(
&pass_list,
- PixelTest::NoOffscreenContext,
base::FilePath(FILE_PATH_LITERAL("green_alpha.png")),
FuzzyPixelOffByOneComparator(true)));
}
@@ -294,23 +305,23 @@ TYPED_TEST(RendererPixelTest, PremultipliedTextureWithBackground) {
RenderPass::Id id(1, 1);
scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect);
- scoped_ptr<SharedQuadState> texture_quad_state =
- CreateTestSharedQuadState(gfx::Transform(), rect);
+ SharedQuadState* texture_quad_state =
+ CreateTestSharedQuadState(pass.get(), gfx::Transform(), rect);
texture_quad_state->opacity = 0.8f;
scoped_ptr<TextureDrawQuad> texture_quad = CreateTestTextureDrawQuad(
gfx::Rect(this->device_viewport_size_),
SkColorSetARGB(204, 120, 255, 120), // Texel color.
- SK_ColorGREEN, // Background color.
- true, // Premultiplied alpha.
- texture_quad_state.get(),
+ SK_ColorGREEN, // Background color.
+ true, // Premultiplied alpha.
+ texture_quad_state,
this->resource_provider_.get());
pass->quad_list.push_back(texture_quad.PassAs<DrawQuad>());
- scoped_ptr<SharedQuadState> color_quad_state =
- CreateTestSharedQuadState(gfx::Transform(), rect);
+ SharedQuadState* color_quad_state =
+ CreateTestSharedQuadState(pass.get(), gfx::Transform(), rect);
scoped_ptr<SolidColorDrawQuad> color_quad = SolidColorDrawQuad::Create();
- color_quad->SetNew(color_quad_state.get(), rect, SK_ColorWHITE, false);
+ color_quad->SetNew(color_quad_state, rect, rect, SK_ColorWHITE, false);
pass->quad_list.push_back(color_quad.PassAs<DrawQuad>());
RenderPassList pass_list;
@@ -318,7 +329,6 @@ TYPED_TEST(RendererPixelTest, PremultipliedTextureWithBackground) {
EXPECT_TRUE(this->RunPixelTest(
&pass_list,
- PixelTest::NoOffscreenContext,
base::FilePath(FILE_PATH_LITERAL("green_alpha.png")),
FuzzyPixelOffByOneComparator(true)));
}
@@ -330,20 +340,20 @@ TEST_F(GLRendererPixelTest, NonPremultipliedTextureWithoutBackground) {
RenderPass::Id id(1, 1);
scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect);
- scoped_ptr<SharedQuadState> shared_state =
- CreateTestSharedQuadState(gfx::Transform(), rect);
+ SharedQuadState* shared_state =
+ CreateTestSharedQuadState(pass.get(), gfx::Transform(), rect);
- scoped_ptr<TextureDrawQuad> texture_quad = CreateTestTextureDrawQuad(
- gfx::Rect(this->device_viewport_size_),
- SkColorSetARGB(128, 0, 255, 0), // Texel color.
- SK_ColorTRANSPARENT, // Background color.
- false, // Premultiplied alpha.
- shared_state.get(),
- this->resource_provider_.get());
+ scoped_ptr<TextureDrawQuad> texture_quad =
+ CreateTestTextureDrawQuad(gfx::Rect(this->device_viewport_size_),
+ SkColorSetARGB(128, 0, 255, 0), // Texel color.
+ SK_ColorTRANSPARENT, // Background color.
+ false, // Premultiplied alpha.
+ shared_state,
+ this->resource_provider_.get());
pass->quad_list.push_back(texture_quad.PassAs<DrawQuad>());
scoped_ptr<SolidColorDrawQuad> color_quad = SolidColorDrawQuad::Create();
- color_quad->SetNew(shared_state.get(), rect, SK_ColorWHITE, false);
+ color_quad->SetNew(shared_state, rect, rect, SK_ColorWHITE, false);
pass->quad_list.push_back(color_quad.PassAs<DrawQuad>());
RenderPassList pass_list;
@@ -351,7 +361,6 @@ TEST_F(GLRendererPixelTest, NonPremultipliedTextureWithoutBackground) {
EXPECT_TRUE(this->RunPixelTest(
&pass_list,
- PixelTest::NoOffscreenContext,
base::FilePath(FILE_PATH_LITERAL("green_alpha.png")),
FuzzyPixelOffByOneComparator(true)));
}
@@ -363,23 +372,23 @@ TEST_F(GLRendererPixelTest, NonPremultipliedTextureWithBackground) {
RenderPass::Id id(1, 1);
scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect);
- scoped_ptr<SharedQuadState> texture_quad_state =
- CreateTestSharedQuadState(gfx::Transform(), rect);
+ SharedQuadState* texture_quad_state =
+ CreateTestSharedQuadState(pass.get(), gfx::Transform(), rect);
texture_quad_state->opacity = 0.8f;
scoped_ptr<TextureDrawQuad> texture_quad = CreateTestTextureDrawQuad(
gfx::Rect(this->device_viewport_size_),
SkColorSetARGB(204, 120, 255, 120), // Texel color.
- SK_ColorGREEN, // Background color.
- false, // Premultiplied alpha.
- texture_quad_state.get(),
+ SK_ColorGREEN, // Background color.
+ false, // Premultiplied alpha.
+ texture_quad_state,
this->resource_provider_.get());
pass->quad_list.push_back(texture_quad.PassAs<DrawQuad>());
- scoped_ptr<SharedQuadState> color_quad_state =
- CreateTestSharedQuadState(gfx::Transform(), rect);
+ SharedQuadState* color_quad_state =
+ CreateTestSharedQuadState(pass.get(), gfx::Transform(), rect);
scoped_ptr<SolidColorDrawQuad> color_quad = SolidColorDrawQuad::Create();
- color_quad->SetNew(color_quad_state.get(), rect, SK_ColorWHITE, false);
+ color_quad->SetNew(color_quad_state, rect, rect, SK_ColorWHITE, false);
pass->quad_list.push_back(color_quad.PassAs<DrawQuad>());
RenderPassList pass_list;
@@ -387,79 +396,158 @@ TEST_F(GLRendererPixelTest, NonPremultipliedTextureWithBackground) {
EXPECT_TRUE(this->RunPixelTest(
&pass_list,
- PixelTest::NoOffscreenContext,
base::FilePath(FILE_PATH_LITERAL("green_alpha.png")),
FuzzyPixelOffByOneComparator(true)));
}
class VideoGLRendererPixelTest : public GLRendererPixelTest {
protected:
- scoped_ptr<YUVVideoDrawQuad> CreateTestYUVVideoDrawQuad(
- SharedQuadState* shared_state, bool with_alpha, bool is_transparent) {
- gfx::Rect rect(this->device_viewport_size_);
- gfx::Rect opaque_rect(0, 0, 0, 0);
+ scoped_ptr<YUVVideoDrawQuad> CreateTestYUVVideoDrawQuad_Striped(
+ SharedQuadState* shared_state,
+ media::VideoFrame::Format format,
+ bool is_transparent,
+ const gfx::RectF& tex_coord_rect) {
+ const gfx::Rect rect(this->device_viewport_size_);
+
+ scoped_refptr<media::VideoFrame> video_frame =
+ media::VideoFrame::CreateFrame(
+ format, rect.size(), rect, rect.size(), base::TimeDelta());
+
+ // YUV values representing a striped pattern, for validating texture
+ // coordinates for sampling.
+ uint8_t y_value = 0;
+ uint8_t u_value = 0;
+ uint8_t v_value = 0;
+ for (int i = 0; i < video_frame->rows(media::VideoFrame::kYPlane); ++i) {
+ uint8_t* y_row = video_frame->data(media::VideoFrame::kYPlane) +
+ video_frame->stride(media::VideoFrame::kYPlane) * i;
+ for (int j = 0; j < video_frame->row_bytes(media::VideoFrame::kYPlane);
+ ++j) {
+ y_row[j] = (y_value += 1);
+ }
+ }
+ for (int i = 0; i < video_frame->rows(media::VideoFrame::kUPlane); ++i) {
+ uint8_t* u_row = video_frame->data(media::VideoFrame::kUPlane) +
+ video_frame->stride(media::VideoFrame::kUPlane) * i;
+ uint8_t* v_row = video_frame->data(media::VideoFrame::kVPlane) +
+ video_frame->stride(media::VideoFrame::kVPlane) * i;
+ for (int j = 0; j < video_frame->row_bytes(media::VideoFrame::kUPlane);
+ ++j) {
+ u_row[j] = (u_value += 3);
+ v_row[j] = (v_value += 5);
+ }
+ }
+ return CreateTestYUVVideoDrawQuad_FromVideoFrame(
+ shared_state, video_frame, is_transparent, tex_coord_rect);
+ }
+
+ scoped_ptr<YUVVideoDrawQuad> CreateTestYUVVideoDrawQuad_Solid(
+ SharedQuadState* shared_state,
+ media::VideoFrame::Format format,
+ bool is_transparent,
+ const gfx::RectF& tex_coord_rect,
+ uint8 y,
+ uint8 u,
+ uint8 v) {
+ const gfx::Rect rect(this->device_viewport_size_);
+
+ scoped_refptr<media::VideoFrame> video_frame =
+ media::VideoFrame::CreateFrame(
+ format, rect.size(), rect, rect.size(), base::TimeDelta());
+
+ // YUV values of a solid, constant, color. Useful for testing that color
+ // space/color range are being handled properly.
+ memset(video_frame->data(media::VideoFrame::kYPlane),
+ y,
+ video_frame->stride(media::VideoFrame::kYPlane) *
+ video_frame->rows(media::VideoFrame::kYPlane));
+ memset(video_frame->data(media::VideoFrame::kUPlane),
+ u,
+ video_frame->stride(media::VideoFrame::kUPlane) *
+ video_frame->rows(media::VideoFrame::kUPlane));
+ memset(video_frame->data(media::VideoFrame::kVPlane),
+ v,
+ video_frame->stride(media::VideoFrame::kVPlane) *
+ video_frame->rows(media::VideoFrame::kVPlane));
+
+ return CreateTestYUVVideoDrawQuad_FromVideoFrame(
+ shared_state, video_frame, is_transparent, tex_coord_rect);
+ }
+
+ scoped_ptr<YUVVideoDrawQuad> CreateTestYUVVideoDrawQuad_FromVideoFrame(
+ SharedQuadState* shared_state,
+ scoped_refptr<media::VideoFrame> video_frame,
+ bool is_transparent,
+ const gfx::RectF& tex_coord_rect) {
+ const bool with_alpha = (video_frame->format() == media::VideoFrame::YV12A);
+ const YUVVideoDrawQuad::ColorSpace color_space =
+ (video_frame->format() == media::VideoFrame::YV12J
+ ? YUVVideoDrawQuad::REC_601_JPEG
+ : YUVVideoDrawQuad::REC_601);
+ const gfx::Rect rect(this->device_viewport_size_);
+ const gfx::Rect opaque_rect(0, 0, 0, 0);
+
+ if (with_alpha)
+ memset(video_frame->data(media::VideoFrame::kAPlane),
+ is_transparent ? 0 : 128,
+ video_frame->stride(media::VideoFrame::kAPlane) *
+ video_frame->rows(media::VideoFrame::kAPlane));
+
+ VideoFrameExternalResources resources =
+ video_resource_updater_->CreateExternalResourcesFromVideoFrame(
+ video_frame);
+
+ EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type);
+ EXPECT_EQ(media::VideoFrame::NumPlanes(video_frame->format()),
+ resources.mailboxes.size());
+ EXPECT_EQ(media::VideoFrame::NumPlanes(video_frame->format()),
+ resources.release_callbacks.size());
ResourceProvider::ResourceId y_resource =
- resource_provider_->CreateResource(
- this->device_viewport_size_,
- GL_CLAMP_TO_EDGE,
- ResourceProvider::TextureUsageAny,
- LUMINANCE_8);
+ resource_provider_->CreateResourceFromTextureMailbox(
+ resources.mailboxes[media::VideoFrame::kYPlane],
+ SingleReleaseCallback::Create(
+ resources.release_callbacks[media::VideoFrame::kYPlane]));
ResourceProvider::ResourceId u_resource =
- resource_provider_->CreateResource(
- this->device_viewport_size_,
- GL_CLAMP_TO_EDGE,
- ResourceProvider::TextureUsageAny,
- LUMINANCE_8);
+ resource_provider_->CreateResourceFromTextureMailbox(
+ resources.mailboxes[media::VideoFrame::kUPlane],
+ SingleReleaseCallback::Create(
+ resources.release_callbacks[media::VideoFrame::kUPlane]));
ResourceProvider::ResourceId v_resource =
- resource_provider_->CreateResource(
- this->device_viewport_size_,
- GL_CLAMP_TO_EDGE,
- ResourceProvider::TextureUsageAny,
- LUMINANCE_8);
+ resource_provider_->CreateResourceFromTextureMailbox(
+ resources.mailboxes[media::VideoFrame::kVPlane],
+ SingleReleaseCallback::Create(
+ resources.release_callbacks[media::VideoFrame::kVPlane]));
ResourceProvider::ResourceId a_resource = 0;
if (with_alpha) {
- a_resource = resource_provider_->CreateResource(
- this->device_viewport_size_,
- GL_CLAMP_TO_EDGE,
- ResourceProvider::TextureUsageAny,
- LUMINANCE_8);
- }
-
- int w = this->device_viewport_size_.width();
- int h = this->device_viewport_size_.height();
- const int y_plane_size = w * h;
- gfx::Rect uv_rect((w + 1) / 2, (h + 1) / 2);
- const int uv_plane_size = uv_rect.size().GetArea();
- scoped_ptr<uint8_t[]> y_plane(new uint8_t[y_plane_size]);
- scoped_ptr<uint8_t[]> u_plane(new uint8_t[uv_plane_size]);
- scoped_ptr<uint8_t[]> v_plane(new uint8_t[uv_plane_size]);
- scoped_ptr<uint8_t[]> a_plane;
- if (with_alpha)
- a_plane.reset(new uint8_t[y_plane_size]);
- // YUV values representing Green.
- memset(y_plane.get(), 149, y_plane_size);
- memset(u_plane.get(), 43, uv_plane_size);
- memset(v_plane.get(), 21, uv_plane_size);
- if (with_alpha)
- memset(a_plane.get(), is_transparent ? 0 : 128, y_plane_size);
-
- resource_provider_->SetPixels(y_resource, y_plane.get(), rect, rect,
- gfx::Vector2d());
- resource_provider_->SetPixels(u_resource, u_plane.get(), uv_rect, uv_rect,
- gfx::Vector2d());
- resource_provider_->SetPixels(v_resource, v_plane.get(), uv_rect, uv_rect,
- gfx::Vector2d());
- if (with_alpha) {
- resource_provider_->SetPixels(a_resource, a_plane.get(), rect, rect,
- gfx::Vector2d());
+ a_resource = resource_provider_->CreateResourceFromTextureMailbox(
+ resources.mailboxes[media::VideoFrame::kAPlane],
+ SingleReleaseCallback::Create(
+ resources.release_callbacks[media::VideoFrame::kAPlane]));
}
scoped_ptr<YUVVideoDrawQuad> yuv_quad = YUVVideoDrawQuad::Create();
- yuv_quad->SetNew(shared_state, rect, opaque_rect, gfx::Size(),
- y_resource, u_resource, v_resource, a_resource);
+ yuv_quad->SetNew(shared_state,
+ rect,
+ opaque_rect,
+ rect,
+ tex_coord_rect,
+ y_resource,
+ u_resource,
+ v_resource,
+ a_resource,
+ color_space);
return yuv_quad.Pass();
}
+
+ virtual void SetUp() OVERRIDE {
+ GLRendererPixelTest::SetUp();
+ video_resource_updater_.reset(new VideoResourceUpdater(
+ output_surface_->context_provider().get(), resource_provider_.get()));
+ }
+
+ private:
+ scoped_ptr<VideoResourceUpdater> video_resource_updater_;
};
TEST_F(VideoGLRendererPixelTest, SimpleYUVRect) {
@@ -468,11 +556,41 @@ TEST_F(VideoGLRendererPixelTest, SimpleYUVRect) {
RenderPass::Id id(1, 1);
scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect);
- scoped_ptr<SharedQuadState> shared_state =
- CreateTestSharedQuadState(gfx::Transform(), rect);
+ SharedQuadState* shared_state =
+ CreateTestSharedQuadState(pass.get(), gfx::Transform(), rect);
scoped_ptr<YUVVideoDrawQuad> yuv_quad =
- CreateTestYUVVideoDrawQuad(shared_state.get(), false, false);
+ CreateTestYUVVideoDrawQuad_Striped(shared_state,
+ media::VideoFrame::YV12,
+ false,
+ gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f));
+
+ pass->quad_list.push_back(yuv_quad.PassAs<DrawQuad>());
+
+ RenderPassList pass_list;
+ pass_list.push_back(pass.Pass());
+
+ EXPECT_TRUE(
+ this->RunPixelTest(&pass_list,
+ base::FilePath(FILE_PATH_LITERAL("yuv_stripes.png")),
+ FuzzyPixelOffByOneComparator(true)));
+}
+
+TEST_F(VideoGLRendererPixelTest, OffsetYUVRect) {
+ gfx::Rect rect(this->device_viewport_size_);
+
+ RenderPass::Id id(1, 1);
+ scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect);
+
+ SharedQuadState* shared_state =
+ CreateTestSharedQuadState(pass.get(), gfx::Transform(), rect);
+
+ // Intentionally sets frame format to I420 for testing coverage.
+ scoped_ptr<YUVVideoDrawQuad> yuv_quad = CreateTestYUVVideoDrawQuad_Striped(
+ shared_state,
+ media::VideoFrame::I420,
+ false,
+ gfx::RectF(0.125f, 0.25f, 0.75f, 0.5f));
pass->quad_list.push_back(yuv_quad.PassAs<DrawQuad>());
@@ -481,9 +599,98 @@ TEST_F(VideoGLRendererPixelTest, SimpleYUVRect) {
EXPECT_TRUE(this->RunPixelTest(
&pass_list,
- PixelTest::NoOffscreenContext,
- base::FilePath(FILE_PATH_LITERAL("green.png")),
- ExactPixelComparator(true)));
+ base::FilePath(FILE_PATH_LITERAL("yuv_stripes_offset.png")),
+ FuzzyPixelOffByOneComparator(true)));
+}
+
+TEST_F(VideoGLRendererPixelTest, SimpleYUVRectBlack) {
+ gfx::Rect rect(this->device_viewport_size_);
+
+ RenderPass::Id id(1, 1);
+ scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect);
+
+ SharedQuadState* shared_state =
+ CreateTestSharedQuadState(pass.get(), gfx::Transform(), rect);
+
+ // In MPEG color range YUV values of (15,128,128) should produce black.
+ scoped_ptr<YUVVideoDrawQuad> yuv_quad =
+ CreateTestYUVVideoDrawQuad_Solid(shared_state,
+ media::VideoFrame::YV12,
+ false,
+ gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f),
+ 15,
+ 128,
+ 128);
+
+ pass->quad_list.push_back(yuv_quad.PassAs<DrawQuad>());
+
+ RenderPassList pass_list;
+ pass_list.push_back(pass.Pass());
+
+ // If we didn't get black out of the YUV values above, then we probably have a
+ // color range issue.
+ EXPECT_TRUE(this->RunPixelTest(&pass_list,
+ base::FilePath(FILE_PATH_LITERAL("black.png")),
+ FuzzyPixelOffByOneComparator(true)));
+}
+
+TEST_F(VideoGLRendererPixelTest, SimpleYUVJRect) {
+ gfx::Rect rect(this->device_viewport_size_);
+
+ RenderPass::Id id(1, 1);
+ scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect);
+
+ SharedQuadState* shared_state =
+ CreateTestSharedQuadState(pass.get(), gfx::Transform(), rect);
+
+ // YUV of (149,43,21) should be green (0,255,0) in RGB.
+ scoped_ptr<YUVVideoDrawQuad> yuv_quad =
+ CreateTestYUVVideoDrawQuad_Solid(shared_state,
+ media::VideoFrame::YV12J,
+ false,
+ gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f),
+ 149,
+ 43,
+ 21);
+
+ pass->quad_list.push_back(yuv_quad.PassAs<DrawQuad>());
+
+ RenderPassList pass_list;
+ pass_list.push_back(pass.Pass());
+
+ EXPECT_TRUE(this->RunPixelTest(&pass_list,
+ base::FilePath(FILE_PATH_LITERAL("green.png")),
+ FuzzyPixelOffByOneComparator(true)));
+}
+
+TEST_F(VideoGLRendererPixelTest, SimpleYUVJRectGrey) {
+ gfx::Rect rect(this->device_viewport_size_);
+
+ RenderPass::Id id(1, 1);
+ scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect);
+
+ SharedQuadState* shared_state =
+ CreateTestSharedQuadState(pass.get(), gfx::Transform(), rect);
+
+ // Dark grey in JPEG color range (in MPEG, this is black).
+ scoped_ptr<YUVVideoDrawQuad> yuv_quad =
+ CreateTestYUVVideoDrawQuad_Solid(shared_state,
+ media::VideoFrame::YV12J,
+ false,
+ gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f),
+ 15,
+ 128,
+ 128);
+
+ pass->quad_list.push_back(yuv_quad.PassAs<DrawQuad>());
+
+ RenderPassList pass_list;
+ pass_list.push_back(pass.Pass());
+
+ EXPECT_TRUE(
+ this->RunPixelTest(&pass_list,
+ base::FilePath(FILE_PATH_LITERAL("dark_grey.png")),
+ FuzzyPixelOffByOneComparator(true)));
}
TEST_F(VideoGLRendererPixelTest, SimpleYUVARect) {
@@ -492,16 +699,19 @@ TEST_F(VideoGLRendererPixelTest, SimpleYUVARect) {
RenderPass::Id id(1, 1);
scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect);
- scoped_ptr<SharedQuadState> shared_state =
- CreateTestSharedQuadState(gfx::Transform(), rect);
+ SharedQuadState* shared_state =
+ CreateTestSharedQuadState(pass.get(), gfx::Transform(), rect);
scoped_ptr<YUVVideoDrawQuad> yuv_quad =
- CreateTestYUVVideoDrawQuad(shared_state.get(), true, false);
+ CreateTestYUVVideoDrawQuad_Striped(shared_state,
+ media::VideoFrame::YV12A,
+ false,
+ gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f));
pass->quad_list.push_back(yuv_quad.PassAs<DrawQuad>());
scoped_ptr<SolidColorDrawQuad> color_quad = SolidColorDrawQuad::Create();
- color_quad->SetNew(shared_state.get(), rect, SK_ColorWHITE, false);
+ color_quad->SetNew(shared_state, rect, rect, SK_ColorWHITE, false);
pass->quad_list.push_back(color_quad.PassAs<DrawQuad>());
@@ -510,9 +720,8 @@ TEST_F(VideoGLRendererPixelTest, SimpleYUVARect) {
EXPECT_TRUE(this->RunPixelTest(
&pass_list,
- PixelTest::NoOffscreenContext,
- base::FilePath(FILE_PATH_LITERAL("green_alpha.png")),
- ExactPixelComparator(true)));
+ base::FilePath(FILE_PATH_LITERAL("yuv_stripes_alpha.png")),
+ FuzzyPixelOffByOneComparator(true)));
}
TEST_F(VideoGLRendererPixelTest, FullyTransparentYUVARect) {
@@ -521,16 +730,19 @@ TEST_F(VideoGLRendererPixelTest, FullyTransparentYUVARect) {
RenderPass::Id id(1, 1);
scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect);
- scoped_ptr<SharedQuadState> shared_state =
- CreateTestSharedQuadState(gfx::Transform(), rect);
+ SharedQuadState* shared_state =
+ CreateTestSharedQuadState(pass.get(), gfx::Transform(), rect);
scoped_ptr<YUVVideoDrawQuad> yuv_quad =
- CreateTestYUVVideoDrawQuad(shared_state.get(), true, true);
+ CreateTestYUVVideoDrawQuad_Striped(shared_state,
+ media::VideoFrame::YV12A,
+ true,
+ gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f));
pass->quad_list.push_back(yuv_quad.PassAs<DrawQuad>());
scoped_ptr<SolidColorDrawQuad> color_quad = SolidColorDrawQuad::Create();
- color_quad->SetNew(shared_state.get(), rect, SK_ColorBLACK, false);
+ color_quad->SetNew(shared_state, rect, rect, SK_ColorBLACK, false);
pass->quad_list.push_back(color_quad.PassAs<DrawQuad>());
@@ -539,7 +751,6 @@ TEST_F(VideoGLRendererPixelTest, FullyTransparentYUVARect) {
EXPECT_TRUE(this->RunPixelTest(
&pass_list,
- PixelTest::NoOffscreenContext,
base::FilePath(FILE_PATH_LITERAL("black.png")),
ExactPixelComparator(true)));
}
@@ -558,42 +769,36 @@ TYPED_TEST(RendererPixelTest, FastPassColorFilterAlpha) {
CreateTestRenderPass(child_pass_id, pass_rect, transform_to_root);
gfx::Transform content_to_target_transform;
- scoped_ptr<SharedQuadState> shared_state =
- CreateTestSharedQuadState(content_to_target_transform, viewport_rect);
+ SharedQuadState* shared_state = CreateTestSharedQuadState(
+ child_pass.get(), content_to_target_transform, viewport_rect);
shared_state->opacity = 0.5f;
+ gfx::Rect blue_rect(0,
+ 0,
+ this->device_viewport_size_.width(),
+ this->device_viewport_size_.height() / 2);
scoped_ptr<SolidColorDrawQuad> blue = SolidColorDrawQuad::Create();
- blue->SetNew(shared_state.get(),
- gfx::Rect(0,
- 0,
- this->device_viewport_size_.width(),
- this->device_viewport_size_.height() / 2),
- SK_ColorBLUE,
- false);
+ blue->SetNew(shared_state, blue_rect, blue_rect, SK_ColorBLUE, false);
+ gfx::Rect yellow_rect(0,
+ this->device_viewport_size_.height() / 2,
+ this->device_viewport_size_.width(),
+ this->device_viewport_size_.height() / 2);
scoped_ptr<SolidColorDrawQuad> yellow = SolidColorDrawQuad::Create();
- yellow->SetNew(shared_state.get(),
- gfx::Rect(0,
- this->device_viewport_size_.height() / 2,
- this->device_viewport_size_.width(),
- this->device_viewport_size_.height() / 2),
- SK_ColorYELLOW,
- false);
+ yellow->SetNew(shared_state, yellow_rect, yellow_rect, SK_ColorYELLOW, false);
- scoped_ptr<SharedQuadState> blank_state =
- CreateTestSharedQuadState(content_to_target_transform, viewport_rect);
+ SharedQuadState* blank_state = CreateTestSharedQuadState(
+ child_pass.get(), content_to_target_transform, viewport_rect);
scoped_ptr<SolidColorDrawQuad> white = SolidColorDrawQuad::Create();
- white->SetNew(blank_state.get(),
- viewport_rect,
- SK_ColorWHITE,
- false);
+ white->SetNew(
+ blank_state, viewport_rect, viewport_rect, SK_ColorWHITE, false);
child_pass->quad_list.push_back(blue.PassAs<DrawQuad>());
child_pass->quad_list.push_back(yellow.PassAs<DrawQuad>());
child_pass->quad_list.push_back(white.PassAs<DrawQuad>());
- scoped_ptr<SharedQuadState> pass_shared_state =
- CreateTestSharedQuadState(gfx::Transform(), pass_rect);
+ SharedQuadState* pass_shared_state =
+ CreateTestSharedQuadState(root_pass.get(), gfx::Transform(), pass_rect);
SkScalar matrix[20];
float amount = 0.5f;
@@ -611,8 +816,8 @@ TYPED_TEST(RendererPixelTest, FastPassColorFilterAlpha) {
matrix[13] = matrix[14] = 0;
matrix[15] = matrix[16] = matrix[17] = matrix[19] = 0;
matrix[18] = 1;
- skia::RefPtr<SkColorFilter> colorFilter(skia::AdoptRef(
- new SkColorMatrixFilter(matrix)));
+ skia::RefPtr<SkColorFilter> colorFilter(
+ skia::AdoptRef(SkColorMatrixFilter::Create(matrix)));
skia::RefPtr<SkImageFilter> filter =
skia::AdoptRef(SkColorFilterImageFilter::Create(colorFilter.get(), NULL));
FilterOperations filters;
@@ -620,7 +825,8 @@ TYPED_TEST(RendererPixelTest, FastPassColorFilterAlpha) {
scoped_ptr<RenderPassDrawQuad> render_pass_quad =
RenderPassDrawQuad::Create();
- render_pass_quad->SetNew(pass_shared_state.get(),
+ render_pass_quad->SetNew(pass_shared_state,
+ pass_rect,
pass_rect,
child_pass_id,
false,
@@ -640,7 +846,6 @@ TYPED_TEST(RendererPixelTest, FastPassColorFilterAlpha) {
// renderer so use a fuzzy comparator.
EXPECT_TRUE(this->RunPixelTest(
&pass_list,
- PixelTest::NoOffscreenContext,
base::FilePath(FILE_PATH_LITERAL("blue_yellow_alpha.png")),
FuzzyForSoftwareOnlyPixelComparator<TypeParam>(false)));
}
@@ -659,49 +864,44 @@ TYPED_TEST(RendererPixelTest, FastPassSaturateFilter) {
CreateTestRenderPass(child_pass_id, pass_rect, transform_to_root);
gfx::Transform content_to_target_transform;
- scoped_ptr<SharedQuadState> shared_state =
- CreateTestSharedQuadState(content_to_target_transform, viewport_rect);
+ SharedQuadState* shared_state = CreateTestSharedQuadState(
+ child_pass.get(), content_to_target_transform, viewport_rect);
shared_state->opacity = 0.5f;
+ gfx::Rect blue_rect(0,
+ 0,
+ this->device_viewport_size_.width(),
+ this->device_viewport_size_.height() / 2);
scoped_ptr<SolidColorDrawQuad> blue = SolidColorDrawQuad::Create();
- blue->SetNew(shared_state.get(),
- gfx::Rect(0,
- 0,
- this->device_viewport_size_.width(),
- this->device_viewport_size_.height() / 2),
- SK_ColorBLUE,
- false);
+ blue->SetNew(shared_state, blue_rect, blue_rect, SK_ColorBLUE, false);
+ gfx::Rect yellow_rect(0,
+ this->device_viewport_size_.height() / 2,
+ this->device_viewport_size_.width(),
+ this->device_viewport_size_.height() / 2);
scoped_ptr<SolidColorDrawQuad> yellow = SolidColorDrawQuad::Create();
- yellow->SetNew(shared_state.get(),
- gfx::Rect(0,
- this->device_viewport_size_.height() / 2,
- this->device_viewport_size_.width(),
- this->device_viewport_size_.height() / 2),
- SK_ColorYELLOW,
- false);
+ yellow->SetNew(shared_state, yellow_rect, yellow_rect, SK_ColorYELLOW, false);
- scoped_ptr<SharedQuadState> blank_state =
- CreateTestSharedQuadState(content_to_target_transform, viewport_rect);
+ SharedQuadState* blank_state = CreateTestSharedQuadState(
+ child_pass.get(), content_to_target_transform, viewport_rect);
scoped_ptr<SolidColorDrawQuad> white = SolidColorDrawQuad::Create();
- white->SetNew(blank_state.get(),
- viewport_rect,
- SK_ColorWHITE,
- false);
+ white->SetNew(
+ blank_state, viewport_rect, viewport_rect, SK_ColorWHITE, false);
child_pass->quad_list.push_back(blue.PassAs<DrawQuad>());
child_pass->quad_list.push_back(yellow.PassAs<DrawQuad>());
child_pass->quad_list.push_back(white.PassAs<DrawQuad>());
- scoped_ptr<SharedQuadState> pass_shared_state =
- CreateTestSharedQuadState(gfx::Transform(), pass_rect);
+ SharedQuadState* pass_shared_state =
+ CreateTestSharedQuadState(root_pass.get(), gfx::Transform(), pass_rect);
FilterOperations filters;
filters.Append(FilterOperation::CreateSaturateFilter(0.5f));
scoped_ptr<RenderPassDrawQuad> render_pass_quad =
RenderPassDrawQuad::Create();
- render_pass_quad->SetNew(pass_shared_state.get(),
+ render_pass_quad->SetNew(pass_shared_state,
+ pass_rect,
pass_rect,
child_pass_id,
false,
@@ -719,7 +919,6 @@ TYPED_TEST(RendererPixelTest, FastPassSaturateFilter) {
EXPECT_TRUE(this->RunPixelTest(
&pass_list,
- PixelTest::NoOffscreenContext,
base::FilePath(FILE_PATH_LITERAL("blue_yellow_alpha.png")),
ExactPixelComparator(true)));
}
@@ -738,42 +937,36 @@ TYPED_TEST(RendererPixelTest, FastPassFilterChain) {
CreateTestRenderPass(child_pass_id, pass_rect, transform_to_root);
gfx::Transform content_to_target_transform;
- scoped_ptr<SharedQuadState> shared_state =
- CreateTestSharedQuadState(content_to_target_transform, viewport_rect);
+ SharedQuadState* shared_state = CreateTestSharedQuadState(
+ child_pass.get(), content_to_target_transform, viewport_rect);
shared_state->opacity = 0.5f;
+ gfx::Rect blue_rect(0,
+ 0,
+ this->device_viewport_size_.width(),
+ this->device_viewport_size_.height() / 2);
scoped_ptr<SolidColorDrawQuad> blue = SolidColorDrawQuad::Create();
- blue->SetNew(shared_state.get(),
- gfx::Rect(0,
- 0,
- this->device_viewport_size_.width(),
- this->device_viewport_size_.height() / 2),
- SK_ColorBLUE,
- false);
+ blue->SetNew(shared_state, blue_rect, blue_rect, SK_ColorBLUE, false);
+ gfx::Rect yellow_rect(0,
+ this->device_viewport_size_.height() / 2,
+ this->device_viewport_size_.width(),
+ this->device_viewport_size_.height() / 2);
scoped_ptr<SolidColorDrawQuad> yellow = SolidColorDrawQuad::Create();
- yellow->SetNew(shared_state.get(),
- gfx::Rect(0,
- this->device_viewport_size_.height() / 2,
- this->device_viewport_size_.width(),
- this->device_viewport_size_.height() / 2),
- SK_ColorYELLOW,
- false);
+ yellow->SetNew(shared_state, yellow_rect, yellow_rect, SK_ColorYELLOW, false);
- scoped_ptr<SharedQuadState> blank_state =
- CreateTestSharedQuadState(content_to_target_transform, viewport_rect);
+ SharedQuadState* blank_state = CreateTestSharedQuadState(
+ child_pass.get(), content_to_target_transform, viewport_rect);
scoped_ptr<SolidColorDrawQuad> white = SolidColorDrawQuad::Create();
- white->SetNew(blank_state.get(),
- viewport_rect,
- SK_ColorWHITE,
- false);
+ white->SetNew(
+ blank_state, viewport_rect, viewport_rect, SK_ColorWHITE, false);
child_pass->quad_list.push_back(blue.PassAs<DrawQuad>());
child_pass->quad_list.push_back(yellow.PassAs<DrawQuad>());
child_pass->quad_list.push_back(white.PassAs<DrawQuad>());
- scoped_ptr<SharedQuadState> pass_shared_state =
- CreateTestSharedQuadState(gfx::Transform(), pass_rect);
+ SharedQuadState* pass_shared_state =
+ CreateTestSharedQuadState(root_pass.get(), gfx::Transform(), pass_rect);
FilterOperations filters;
filters.Append(FilterOperation::CreateGrayscaleFilter(1.f));
@@ -781,7 +974,8 @@ TYPED_TEST(RendererPixelTest, FastPassFilterChain) {
scoped_ptr<RenderPassDrawQuad> render_pass_quad =
RenderPassDrawQuad::Create();
- render_pass_quad->SetNew(pass_shared_state.get(),
+ render_pass_quad->SetNew(pass_shared_state,
+ pass_rect,
pass_rect,
child_pass_id,
false,
@@ -799,7 +993,6 @@ TYPED_TEST(RendererPixelTest, FastPassFilterChain) {
EXPECT_TRUE(this->RunPixelTest(
&pass_list,
- PixelTest::NoOffscreenContext,
base::FilePath(FILE_PATH_LITERAL("blue_yellow_filter_chain.png")),
ExactPixelComparator(true)));
}
@@ -818,42 +1011,36 @@ TYPED_TEST(RendererPixelTest, FastPassColorFilterAlphaTranslation) {
CreateTestRenderPass(child_pass_id, pass_rect, transform_to_root);
gfx::Transform content_to_target_transform;
- scoped_ptr<SharedQuadState> shared_state =
- CreateTestSharedQuadState(content_to_target_transform, viewport_rect);
+ SharedQuadState* shared_state = CreateTestSharedQuadState(
+ child_pass.get(), content_to_target_transform, viewport_rect);
shared_state->opacity = 0.5f;
+ gfx::Rect blue_rect(0,
+ 0,
+ this->device_viewport_size_.width(),
+ this->device_viewport_size_.height() / 2);
scoped_ptr<SolidColorDrawQuad> blue = SolidColorDrawQuad::Create();
- blue->SetNew(shared_state.get(),
- gfx::Rect(0,
- 0,
- this->device_viewport_size_.width(),
- this->device_viewport_size_.height() / 2),
- SK_ColorBLUE,
- false);
+ blue->SetNew(shared_state, blue_rect, blue_rect, SK_ColorBLUE, false);
+ gfx::Rect yellow_rect(0,
+ this->device_viewport_size_.height() / 2,
+ this->device_viewport_size_.width(),
+ this->device_viewport_size_.height() / 2);
scoped_ptr<SolidColorDrawQuad> yellow = SolidColorDrawQuad::Create();
- yellow->SetNew(shared_state.get(),
- gfx::Rect(0,
- this->device_viewport_size_.height() / 2,
- this->device_viewport_size_.width(),
- this->device_viewport_size_.height() / 2),
- SK_ColorYELLOW,
- false);
+ yellow->SetNew(shared_state, yellow_rect, yellow_rect, SK_ColorYELLOW, false);
- scoped_ptr<SharedQuadState> blank_state =
- CreateTestSharedQuadState(content_to_target_transform, viewport_rect);
+ SharedQuadState* blank_state = CreateTestSharedQuadState(
+ child_pass.get(), content_to_target_transform, viewport_rect);
scoped_ptr<SolidColorDrawQuad> white = SolidColorDrawQuad::Create();
- white->SetNew(blank_state.get(),
- viewport_rect,
- SK_ColorWHITE,
- false);
+ white->SetNew(
+ blank_state, viewport_rect, viewport_rect, SK_ColorWHITE, false);
child_pass->quad_list.push_back(blue.PassAs<DrawQuad>());
child_pass->quad_list.push_back(yellow.PassAs<DrawQuad>());
child_pass->quad_list.push_back(white.PassAs<DrawQuad>());
- scoped_ptr<SharedQuadState> pass_shared_state =
- CreateTestSharedQuadState(gfx::Transform(), pass_rect);
+ SharedQuadState* pass_shared_state =
+ CreateTestSharedQuadState(root_pass.get(), gfx::Transform(), pass_rect);
SkScalar matrix[20];
float amount = 0.5f;
@@ -874,8 +1061,8 @@ TYPED_TEST(RendererPixelTest, FastPassColorFilterAlphaTranslation) {
matrix[14] = 1.5f;
matrix[15] = matrix[16] = matrix[17] = matrix[19] = 0;
matrix[18] = 1;
- skia::RefPtr<SkColorFilter> colorFilter(skia::AdoptRef(
- new SkColorMatrixFilter(matrix)));
+ skia::RefPtr<SkColorFilter> colorFilter(
+ skia::AdoptRef(SkColorMatrixFilter::Create(matrix)));
skia::RefPtr<SkImageFilter> filter =
skia::AdoptRef(SkColorFilterImageFilter::Create(colorFilter.get(), NULL));
FilterOperations filters;
@@ -883,7 +1070,8 @@ TYPED_TEST(RendererPixelTest, FastPassColorFilterAlphaTranslation) {
scoped_ptr<RenderPassDrawQuad> render_pass_quad =
RenderPassDrawQuad::Create();
- render_pass_quad->SetNew(pass_shared_state.get(),
+ render_pass_quad->SetNew(pass_shared_state,
+ pass_rect,
pass_rect,
child_pass_id,
false,
@@ -903,7 +1091,6 @@ TYPED_TEST(RendererPixelTest, FastPassColorFilterAlphaTranslation) {
// renderer so use a fuzzy comparator.
EXPECT_TRUE(this->RunPixelTest(
&pass_list,
- PixelTest::NoOffscreenContext,
base::FilePath(FILE_PATH_LITERAL("blue_yellow_alpha_translate.png")),
FuzzyForSoftwareOnlyPixelComparator<TypeParam>(false)));
}
@@ -922,35 +1109,29 @@ TYPED_TEST(RendererPixelTest, EnlargedRenderPassTexture) {
CreateTestRenderPass(child_pass_id, pass_rect, transform_to_root);
gfx::Transform content_to_target_transform;
- scoped_ptr<SharedQuadState> shared_state =
- CreateTestSharedQuadState(content_to_target_transform, viewport_rect);
+ SharedQuadState* shared_state = CreateTestSharedQuadState(
+ child_pass.get(), content_to_target_transform, viewport_rect);
+ gfx::Rect blue_rect(0,
+ 0,
+ this->device_viewport_size_.width(),
+ this->device_viewport_size_.height() / 2);
scoped_ptr<SolidColorDrawQuad> blue = SolidColorDrawQuad::Create();
- blue->SetNew(shared_state.get(),
- gfx::Rect(0,
- 0,
- this->device_viewport_size_.width(),
- this->device_viewport_size_.height() / 2),
- SK_ColorBLUE,
- false);
+ blue->SetNew(shared_state, blue_rect, blue_rect, SK_ColorBLUE, false);
+ gfx::Rect yellow_rect(0,
+ this->device_viewport_size_.height() / 2,
+ this->device_viewport_size_.width(),
+ this->device_viewport_size_.height() / 2);
scoped_ptr<SolidColorDrawQuad> yellow = SolidColorDrawQuad::Create();
- yellow->SetNew(shared_state.get(),
- gfx::Rect(0,
- this->device_viewport_size_.height() / 2,
- this->device_viewport_size_.width(),
- this->device_viewport_size_.height() / 2),
- SK_ColorYELLOW,
- false);
+ yellow->SetNew(shared_state, yellow_rect, yellow_rect, SK_ColorYELLOW, false);
child_pass->quad_list.push_back(blue.PassAs<DrawQuad>());
child_pass->quad_list.push_back(yellow.PassAs<DrawQuad>());
- scoped_ptr<SharedQuadState> pass_shared_state =
- CreateTestSharedQuadState(gfx::Transform(), pass_rect);
- root_pass->quad_list.push_back(
- CreateTestRenderPassDrawQuad(pass_shared_state.get(),
- pass_rect,
- child_pass_id));
+ SharedQuadState* pass_shared_state =
+ CreateTestSharedQuadState(root_pass.get(), gfx::Transform(), pass_rect);
+ root_pass->quad_list.push_back(CreateTestRenderPassDrawQuad(
+ pass_shared_state, pass_rect, child_pass_id));
RenderPassList pass_list;
pass_list.push_back(child_pass.Pass());
@@ -960,7 +1141,6 @@ TYPED_TEST(RendererPixelTest, EnlargedRenderPassTexture) {
EXPECT_TRUE(this->RunPixelTest(
&pass_list,
- PixelTest::NoOffscreenContext,
base::FilePath(FILE_PATH_LITERAL("blue_yellow.png")),
ExactPixelComparator(true)));
}
@@ -979,25 +1159,21 @@ TYPED_TEST(RendererPixelTest, EnlargedRenderPassTextureWithAntiAliasing) {
CreateTestRenderPass(child_pass_id, pass_rect, transform_to_root);
gfx::Transform content_to_target_transform;
- scoped_ptr<SharedQuadState> shared_state =
- CreateTestSharedQuadState(content_to_target_transform, viewport_rect);
+ SharedQuadState* shared_state = CreateTestSharedQuadState(
+ child_pass.get(), content_to_target_transform, viewport_rect);
+ gfx::Rect blue_rect(0,
+ 0,
+ this->device_viewport_size_.width(),
+ this->device_viewport_size_.height() / 2);
scoped_ptr<SolidColorDrawQuad> blue = SolidColorDrawQuad::Create();
- blue->SetNew(shared_state.get(),
- gfx::Rect(0,
- 0,
- this->device_viewport_size_.width(),
- this->device_viewport_size_.height() / 2),
- SK_ColorBLUE,
- false);
+ blue->SetNew(shared_state, blue_rect, blue_rect, SK_ColorBLUE, false);
+ gfx::Rect yellow_rect(0,
+ this->device_viewport_size_.height() / 2,
+ this->device_viewport_size_.width(),
+ this->device_viewport_size_.height() / 2);
scoped_ptr<SolidColorDrawQuad> yellow = SolidColorDrawQuad::Create();
- yellow->SetNew(shared_state.get(),
- gfx::Rect(0,
- this->device_viewport_size_.height() / 2,
- this->device_viewport_size_.width(),
- this->device_viewport_size_.height() / 2),
- SK_ColorYELLOW,
- false);
+ yellow->SetNew(shared_state, yellow_rect, yellow_rect, SK_ColorYELLOW, false);
child_pass->quad_list.push_back(blue.PassAs<DrawQuad>());
child_pass->quad_list.push_back(yellow.PassAs<DrawQuad>());
@@ -1005,17 +1181,16 @@ TYPED_TEST(RendererPixelTest, EnlargedRenderPassTextureWithAntiAliasing) {
gfx::Transform aa_transform;
aa_transform.Translate(0.5, 0.0);
- scoped_ptr<SharedQuadState> pass_shared_state =
- CreateTestSharedQuadState(aa_transform, pass_rect);
- root_pass->quad_list.push_back(
- CreateTestRenderPassDrawQuad(pass_shared_state.get(),
- pass_rect,
- child_pass_id));
+ SharedQuadState* pass_shared_state =
+ CreateTestSharedQuadState(root_pass.get(), aa_transform, pass_rect);
+ root_pass->quad_list.push_back(CreateTestRenderPassDrawQuad(
+ pass_shared_state, pass_rect, child_pass_id));
- scoped_ptr<SharedQuadState> root_shared_state =
- CreateTestSharedQuadState(gfx::Transform(), viewport_rect);
+ SharedQuadState* root_shared_state = CreateTestSharedQuadState(
+ root_pass.get(), gfx::Transform(), viewport_rect);
scoped_ptr<SolidColorDrawQuad> background = SolidColorDrawQuad::Create();
- background->SetNew(root_shared_state.get(),
+ background->SetNew(root_shared_state,
+ gfx::Rect(this->device_viewport_size_),
gfx::Rect(this->device_viewport_size_),
SK_ColorWHITE,
false);
@@ -1029,7 +1204,6 @@ TYPED_TEST(RendererPixelTest, EnlargedRenderPassTextureWithAntiAliasing) {
EXPECT_TRUE(this->RunPixelTest(
&pass_list,
- PixelTest::NoOffscreenContext,
base::FilePath(FILE_PATH_LITERAL("blue_yellow_anti_aliasing.png")),
FuzzyPixelOffByOneComparator(true)));
}
@@ -1042,39 +1216,38 @@ TYPED_TEST(RendererPixelTest, RenderPassAndMaskWithPartialQuad) {
RenderPass::Id root_pass_id(1, 1);
scoped_ptr<RenderPass> root_pass =
CreateTestRootRenderPass(root_pass_id, viewport_rect);
- scoped_ptr<SharedQuadState> root_pass_shared_state =
- CreateTestSharedQuadState(gfx::Transform(), viewport_rect);
+ SharedQuadState* root_pass_shared_state = CreateTestSharedQuadState(
+ root_pass.get(), gfx::Transform(), viewport_rect);
RenderPass::Id child_pass_id(2, 2);
gfx::Transform transform_to_root;
scoped_ptr<RenderPass> child_pass =
CreateTestRenderPass(child_pass_id, viewport_rect, transform_to_root);
- scoped_ptr<SharedQuadState> child_pass_shared_state =
- CreateTestSharedQuadState(gfx::Transform(), viewport_rect);
+ SharedQuadState* child_pass_shared_state = CreateTestSharedQuadState(
+ child_pass.get(), gfx::Transform(), viewport_rect);
// The child render pass is just a green box.
static const SkColor kCSSGreen = 0xff008000;
scoped_ptr<SolidColorDrawQuad> green = SolidColorDrawQuad::Create();
- green->SetNew(child_pass_shared_state.get(), viewport_rect, kCSSGreen, false);
+ green->SetNew(
+ child_pass_shared_state, viewport_rect, viewport_rect, kCSSGreen, false);
child_pass->quad_list.push_back(green.PassAs<DrawQuad>());
// Make a mask.
gfx::Rect mask_rect = viewport_rect;
SkBitmap bitmap;
- bitmap.setConfig(
- SkBitmap::kARGB_8888_Config, mask_rect.width(), mask_rect.height());
- bitmap.allocPixels();
- SkBitmapDevice bitmap_device(bitmap);
- skia::RefPtr<SkCanvas> canvas = skia::AdoptRef(new SkCanvas(&bitmap_device));
+ bitmap.allocPixels(
+ SkImageInfo::MakeN32Premul(mask_rect.width(), mask_rect.height()));
+ SkCanvas canvas(bitmap);
SkPaint paint;
paint.setStyle(SkPaint::kStroke_Style);
paint.setStrokeWidth(SkIntToScalar(4));
paint.setColor(SK_ColorWHITE);
- canvas->clear(SK_ColorTRANSPARENT);
+ canvas.clear(SK_ColorTRANSPARENT);
gfx::Rect rect = mask_rect;
while (!rect.IsEmpty()) {
rect.Inset(6, 6, 4, 4);
- canvas->drawRect(
+ canvas.drawRect(
SkRect::MakeXYWH(rect.x(), rect.y(), rect.width(), rect.height()),
paint);
rect.Inset(6, 6, 4, 4);
@@ -1107,7 +1280,8 @@ TYPED_TEST(RendererPixelTest, RenderPassAndMaskWithPartialQuad) {
// Set up a mask on the RenderPassDrawQuad.
scoped_ptr<RenderPassDrawQuad> mask_quad = RenderPassDrawQuad::Create();
- mask_quad->SetNew(root_pass_shared_state.get(),
+ mask_quad->SetNew(root_pass_shared_state,
+ sub_rect,
sub_rect,
child_pass_id,
false, // is_replica
@@ -1120,8 +1294,11 @@ TYPED_TEST(RendererPixelTest, RenderPassAndMaskWithPartialQuad) {
// White background behind the masked render pass.
scoped_ptr<SolidColorDrawQuad> white = SolidColorDrawQuad::Create();
- white->SetNew(
- root_pass_shared_state.get(), viewport_rect, SK_ColorWHITE, false);
+ white->SetNew(root_pass_shared_state,
+ viewport_rect,
+ viewport_rect,
+ SK_ColorWHITE,
+ false);
root_pass->quad_list.push_back(white.PassAs<DrawQuad>());
RenderPassList pass_list;
@@ -1130,7 +1307,6 @@ TYPED_TEST(RendererPixelTest, RenderPassAndMaskWithPartialQuad) {
EXPECT_TRUE(this->RunPixelTest(
&pass_list,
- PixelTest::NoOffscreenContext,
base::FilePath(FILE_PATH_LITERAL("image_mask_of_layer.png")),
ExactPixelComparator(true)));
}
@@ -1158,87 +1334,87 @@ class RendererPixelTestWithBackgroundFilter
// A non-visible quad in the filtering render pass.
{
- scoped_ptr<SharedQuadState> shared_state =
- CreateTestSharedQuadState(identity_content_to_target_transform,
+ SharedQuadState* shared_state =
+ CreateTestSharedQuadState(filter_pass.get(),
+ identity_content_to_target_transform,
filter_pass_content_rect_);
scoped_ptr<SolidColorDrawQuad> color_quad = SolidColorDrawQuad::Create();
- color_quad->SetNew(shared_state.get(),
+ color_quad->SetNew(shared_state,
+ filter_pass_content_rect_,
filter_pass_content_rect_,
SK_ColorTRANSPARENT,
false);
filter_pass->quad_list.push_back(color_quad.PassAs<DrawQuad>());
- filter_pass->shared_quad_state_list.push_back(shared_state.Pass());
}
{
- scoped_ptr<SharedQuadState> shared_state =
- CreateTestSharedQuadState(filter_pass_to_target_transform_,
+ SharedQuadState* shared_state =
+ CreateTestSharedQuadState(filter_pass.get(),
+ filter_pass_to_target_transform_,
filter_pass_content_rect_);
scoped_ptr<RenderPassDrawQuad> filter_pass_quad =
RenderPassDrawQuad::Create();
filter_pass_quad->SetNew(
- shared_state.get(),
+ shared_state,
+ filter_pass_content_rect_,
filter_pass_content_rect_,
filter_pass_id,
- false, // is_replica
- 0, // mask_resource_id
+ false, // is_replica
+ 0, // mask_resource_id
filter_pass_content_rect_, // contents_changed_since_last_frame
- gfx::RectF(), // mask_uv_rect
- FilterOperations(), // filters
+ gfx::RectF(), // mask_uv_rect
+ FilterOperations(), // filters
this->background_filters_);
root_pass->quad_list.push_back(filter_pass_quad.PassAs<DrawQuad>());
- root_pass->shared_quad_state_list.push_back(shared_state.Pass());
}
const int kColumnWidth = device_viewport_rect.width() / 3;
gfx::Rect left_rect = gfx::Rect(0, 0, kColumnWidth, 20);
for (int i = 0; left_rect.y() < device_viewport_rect.height(); ++i) {
- scoped_ptr<SharedQuadState> shared_state =
- CreateTestSharedQuadState(identity_content_to_target_transform,
- left_rect);
+ SharedQuadState* shared_state = CreateTestSharedQuadState(
+ root_pass.get(), identity_content_to_target_transform, left_rect);
scoped_ptr<SolidColorDrawQuad> color_quad = SolidColorDrawQuad::Create();
- color_quad->SetNew(shared_state.get(), left_rect, SK_ColorGREEN, false);
+ color_quad->SetNew(
+ shared_state, left_rect, left_rect, SK_ColorGREEN, false);
root_pass->quad_list.push_back(color_quad.PassAs<DrawQuad>());
- root_pass->shared_quad_state_list.push_back(shared_state.Pass());
left_rect += gfx::Vector2d(0, left_rect.height() + 1);
}
gfx::Rect middle_rect = gfx::Rect(kColumnWidth+1, 0, kColumnWidth, 20);
for (int i = 0; middle_rect.y() < device_viewport_rect.height(); ++i) {
- scoped_ptr<SharedQuadState> shared_state =
- CreateTestSharedQuadState(identity_content_to_target_transform,
- middle_rect);
+ SharedQuadState* shared_state = CreateTestSharedQuadState(
+ root_pass.get(), identity_content_to_target_transform, middle_rect);
scoped_ptr<SolidColorDrawQuad> color_quad = SolidColorDrawQuad::Create();
- color_quad->SetNew(shared_state.get(), middle_rect, SK_ColorRED, false);
+ color_quad->SetNew(
+ shared_state, middle_rect, middle_rect, SK_ColorRED, false);
root_pass->quad_list.push_back(color_quad.PassAs<DrawQuad>());
- root_pass->shared_quad_state_list.push_back(shared_state.Pass());
middle_rect += gfx::Vector2d(0, middle_rect.height() + 1);
}
gfx::Rect right_rect = gfx::Rect((kColumnWidth+1)*2, 0, kColumnWidth, 20);
for (int i = 0; right_rect.y() < device_viewport_rect.height(); ++i) {
- scoped_ptr<SharedQuadState> shared_state =
- CreateTestSharedQuadState(identity_content_to_target_transform,
- right_rect);
+ SharedQuadState* shared_state = CreateTestSharedQuadState(
+ root_pass.get(), identity_content_to_target_transform, right_rect);
scoped_ptr<SolidColorDrawQuad> color_quad = SolidColorDrawQuad::Create();
- color_quad->SetNew(shared_state.get(), right_rect, SK_ColorBLUE, false);
+ color_quad->SetNew(
+ shared_state, right_rect, right_rect, SK_ColorBLUE, false);
root_pass->quad_list.push_back(color_quad.PassAs<DrawQuad>());
- root_pass->shared_quad_state_list.push_back(shared_state.Pass());
right_rect += gfx::Vector2d(0, right_rect.height() + 1);
}
- scoped_ptr<SharedQuadState> shared_state =
- CreateTestSharedQuadState(identity_content_to_target_transform,
+ SharedQuadState* shared_state =
+ CreateTestSharedQuadState(root_pass.get(),
+ identity_content_to_target_transform,
device_viewport_rect);
scoped_ptr<SolidColorDrawQuad> background_quad =
SolidColorDrawQuad::Create();
- background_quad->SetNew(shared_state.get(),
+ background_quad->SetNew(shared_state,
+ device_viewport_rect,
device_viewport_rect,
SK_ColorWHITE,
false);
root_pass->quad_list.push_back(background_quad.PassAs<DrawQuad>());
- root_pass->shared_quad_state_list.push_back(shared_state.Pass());
pass_list_.push_back(filter_pass.Pass());
pass_list_.push_back(root_pass.Pass());
@@ -1269,7 +1445,6 @@ TEST_F(GLRendererPixelTestWithBackgroundFilter, InvertFilter) {
this->SetUpRenderPassList();
EXPECT_TRUE(this->RunPixelTest(
&this->pass_list_,
- PixelTest::WithOffscreenContext,
base::FilePath(FILE_PATH_LITERAL("background_filter.png")),
ExactPixelComparator(true)));
}
@@ -1277,35 +1452,32 @@ TEST_F(GLRendererPixelTestWithBackgroundFilter, InvertFilter) {
class ExternalStencilPixelTest : public GLRendererPixelTest {
protected:
void ClearBackgroundToGreen() {
- blink::WebGraphicsContext3D* context3d =
- output_surface_->context_provider()->Context3d();
+ GLES2Interface* gl = output_surface_->context_provider()->ContextGL();
output_surface_->EnsureBackbuffer();
output_surface_->Reshape(device_viewport_size_, 1);
- context3d->clearColor(0.f, 1.f, 0.f, 1.f);
- context3d->clear(GL_COLOR_BUFFER_BIT);
+ gl->ClearColor(0.f, 1.f, 0.f, 1.f);
+ gl->Clear(GL_COLOR_BUFFER_BIT);
}
void PopulateStencilBuffer() {
// Set two quadrants of the stencil buffer to 1.
- blink::WebGraphicsContext3D* context3d =
- output_surface_->context_provider()->Context3d();
- ASSERT_TRUE(context3d->getContextAttributes().stencil);
+ GLES2Interface* gl = output_surface_->context_provider()->ContextGL();
output_surface_->EnsureBackbuffer();
output_surface_->Reshape(device_viewport_size_, 1);
- context3d->clearStencil(0);
- context3d->clear(GL_STENCIL_BUFFER_BIT);
- context3d->enable(GL_SCISSOR_TEST);
- context3d->clearStencil(1);
- context3d->scissor(0,
- 0,
- device_viewport_size_.width() / 2,
- device_viewport_size_.height() / 2);
- context3d->clear(GL_STENCIL_BUFFER_BIT);
- context3d->scissor(device_viewport_size_.width() / 2,
- device_viewport_size_.height() / 2,
- device_viewport_size_.width(),
- device_viewport_size_.height());
- context3d->clear(GL_STENCIL_BUFFER_BIT);
+ gl->ClearStencil(0);
+ gl->Clear(GL_STENCIL_BUFFER_BIT);
+ gl->Enable(GL_SCISSOR_TEST);
+ gl->ClearStencil(1);
+ gl->Scissor(0,
+ 0,
+ device_viewport_size_.width() / 2,
+ device_viewport_size_.height() / 2);
+ gl->Clear(GL_STENCIL_BUFFER_BIT);
+ gl->Scissor(device_viewport_size_.width() / 2,
+ device_viewport_size_.height() / 2,
+ device_viewport_size_.width(),
+ device_viewport_size_.height());
+ gl->Clear(GL_STENCIL_BUFFER_BIT);
}
};
@@ -1319,10 +1491,10 @@ TEST_F(ExternalStencilPixelTest, StencilTestEnabled) {
gfx::Rect rect(this->device_viewport_size_);
RenderPass::Id id(1, 1);
scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect);
- scoped_ptr<SharedQuadState> blue_shared_state =
- CreateTestSharedQuadState(gfx::Transform(), rect);
+ SharedQuadState* blue_shared_state =
+ CreateTestSharedQuadState(pass.get(), gfx::Transform(), rect);
scoped_ptr<SolidColorDrawQuad> blue = SolidColorDrawQuad::Create();
- blue->SetNew(blue_shared_state.get(), rect, SK_ColorBLUE, false);
+ blue->SetNew(blue_shared_state, rect, rect, SK_ColorBLUE, false);
pass->quad_list.push_back(blue.PassAs<DrawQuad>());
pass->has_transparent_background = false;
RenderPassList pass_list;
@@ -1330,7 +1502,6 @@ TEST_F(ExternalStencilPixelTest, StencilTestEnabled) {
EXPECT_TRUE(this->RunPixelTest(
&pass_list,
- PixelTest::NoOffscreenContext,
base::FilePath(FILE_PATH_LITERAL("four_blue_green_checkers.png")),
ExactPixelComparator(true)));
}
@@ -1343,17 +1514,16 @@ TEST_F(ExternalStencilPixelTest, StencilTestDisabled) {
gfx::Rect rect(this->device_viewport_size_);
RenderPass::Id id(1, 1);
scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect);
- scoped_ptr<SharedQuadState> green_shared_state =
- CreateTestSharedQuadState(gfx::Transform(), rect);
+ SharedQuadState* green_shared_state =
+ CreateTestSharedQuadState(pass.get(), gfx::Transform(), rect);
scoped_ptr<SolidColorDrawQuad> green = SolidColorDrawQuad::Create();
- green->SetNew(green_shared_state.get(), rect, SK_ColorGREEN, false);
+ green->SetNew(green_shared_state, rect, rect, SK_ColorGREEN, false);
pass->quad_list.push_back(green.PassAs<DrawQuad>());
RenderPassList pass_list;
pass_list.push_back(pass.Pass());
EXPECT_TRUE(this->RunPixelTest(
&pass_list,
- PixelTest::NoOffscreenContext,
base::FilePath(FILE_PATH_LITERAL("green.png")),
ExactPixelComparator(true)));
}
@@ -1378,32 +1548,27 @@ TEST_F(ExternalStencilPixelTest, RenderSurfacesIgnoreStencil) {
CreateTestRenderPass(child_pass_id, pass_rect, transform_to_root);
gfx::Transform content_to_target_transform;
- scoped_ptr<SharedQuadState> shared_state =
- CreateTestSharedQuadState(content_to_target_transform, viewport_rect);
+ SharedQuadState* shared_state = CreateTestSharedQuadState(
+ child_pass.get(), content_to_target_transform, viewport_rect);
+ gfx::Rect blue_rect(0,
+ 0,
+ this->device_viewport_size_.width(),
+ this->device_viewport_size_.height());
scoped_ptr<SolidColorDrawQuad> blue = SolidColorDrawQuad::Create();
- blue->SetNew(shared_state.get(),
- gfx::Rect(0,
- 0,
- this->device_viewport_size_.width(),
- this->device_viewport_size_.height()),
- SK_ColorBLUE,
- false);
+ blue->SetNew(shared_state, blue_rect, blue_rect, SK_ColorBLUE, false);
child_pass->quad_list.push_back(blue.PassAs<DrawQuad>());
- scoped_ptr<SharedQuadState> pass_shared_state =
- CreateTestSharedQuadState(gfx::Transform(), pass_rect);
- root_pass->quad_list.push_back(
- CreateTestRenderPassDrawQuad(pass_shared_state.get(),
- pass_rect,
- child_pass_id));
+ SharedQuadState* pass_shared_state =
+ CreateTestSharedQuadState(root_pass.get(), gfx::Transform(), pass_rect);
+ root_pass->quad_list.push_back(CreateTestRenderPassDrawQuad(
+ pass_shared_state, pass_rect, child_pass_id));
RenderPassList pass_list;
pass_list.push_back(child_pass.Pass());
pass_list.push_back(root_pass.Pass());
EXPECT_TRUE(this->RunPixelTest(
&pass_list,
- PixelTest::NoOffscreenContext,
base::FilePath(FILE_PATH_LITERAL("four_blue_green_checkers.png")),
ExactPixelComparator(true)));
}
@@ -1418,17 +1583,16 @@ TEST_F(ExternalStencilPixelTest, DeviceClip) {
gfx::Rect rect(this->device_viewport_size_);
RenderPass::Id id(1, 1);
scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect);
- scoped_ptr<SharedQuadState> blue_shared_state =
- CreateTestSharedQuadState(gfx::Transform(), rect);
+ SharedQuadState* blue_shared_state =
+ CreateTestSharedQuadState(pass.get(), gfx::Transform(), rect);
scoped_ptr<SolidColorDrawQuad> blue = SolidColorDrawQuad::Create();
- blue->SetNew(blue_shared_state.get(), rect, SK_ColorBLUE, false);
+ blue->SetNew(blue_shared_state, rect, rect, SK_ColorBLUE, false);
pass->quad_list.push_back(blue.PassAs<DrawQuad>());
RenderPassList pass_list;
pass_list.push_back(pass.Pass());
EXPECT_TRUE(this->RunPixelTest(
&pass_list,
- PixelTest::NoOffscreenContext,
base::FilePath(FILE_PATH_LITERAL("green_with_blue_corner.png")),
ExactPixelComparator(true)));
}
@@ -1442,30 +1606,30 @@ TEST_F(GLRendererPixelTest, AntiAliasing) {
gfx::Transform red_content_to_target_transform;
red_content_to_target_transform.Rotate(10);
- scoped_ptr<SharedQuadState> red_shared_state =
- CreateTestSharedQuadState(red_content_to_target_transform, rect);
+ SharedQuadState* red_shared_state = CreateTestSharedQuadState(
+ pass.get(), red_content_to_target_transform, rect);
scoped_ptr<SolidColorDrawQuad> red = SolidColorDrawQuad::Create();
- red->SetNew(red_shared_state.get(), rect, SK_ColorRED, false);
+ red->SetNew(red_shared_state, rect, rect, SK_ColorRED, false);
pass->quad_list.push_back(red.PassAs<DrawQuad>());
gfx::Transform yellow_content_to_target_transform;
yellow_content_to_target_transform.Rotate(5);
- scoped_ptr<SharedQuadState> yellow_shared_state =
- CreateTestSharedQuadState(yellow_content_to_target_transform, rect);
+ SharedQuadState* yellow_shared_state = CreateTestSharedQuadState(
+ pass.get(), yellow_content_to_target_transform, rect);
scoped_ptr<SolidColorDrawQuad> yellow = SolidColorDrawQuad::Create();
- yellow->SetNew(yellow_shared_state.get(), rect, SK_ColorYELLOW, false);
+ yellow->SetNew(yellow_shared_state, rect, rect, SK_ColorYELLOW, false);
pass->quad_list.push_back(yellow.PassAs<DrawQuad>());
gfx::Transform blue_content_to_target_transform;
- scoped_ptr<SharedQuadState> blue_shared_state =
- CreateTestSharedQuadState(blue_content_to_target_transform, rect);
+ SharedQuadState* blue_shared_state = CreateTestSharedQuadState(
+ pass.get(), blue_content_to_target_transform, rect);
scoped_ptr<SolidColorDrawQuad> blue = SolidColorDrawQuad::Create();
- blue->SetNew(blue_shared_state.get(), rect, SK_ColorBLUE, false);
+ blue->SetNew(blue_shared_state, rect, rect, SK_ColorBLUE, false);
pass->quad_list.push_back(blue.PassAs<DrawQuad>());
@@ -1474,7 +1638,6 @@ TEST_F(GLRendererPixelTest, AntiAliasing) {
EXPECT_TRUE(this->RunPixelTest(
&pass_list,
- PixelTest::NoOffscreenContext,
base::FilePath(FILE_PATH_LITERAL("anti_aliasing.png")),
FuzzyPixelOffByOneComparator(true)));
}
@@ -1494,31 +1657,31 @@ TEST_F(GLRendererPixelTest, AxisAligned) {
red_content_to_target_transform.Scale(
0.5f + 1.0f / (rect.width() * 2.0f),
0.5f + 1.0f / (rect.height() * 2.0f));
- scoped_ptr<SharedQuadState> red_shared_state =
- CreateTestSharedQuadState(red_content_to_target_transform, rect);
+ SharedQuadState* red_shared_state = CreateTestSharedQuadState(
+ pass.get(), red_content_to_target_transform, rect);
scoped_ptr<SolidColorDrawQuad> red = SolidColorDrawQuad::Create();
- red->SetNew(red_shared_state.get(), rect, SK_ColorRED, false);
+ red->SetNew(red_shared_state, rect, rect, SK_ColorRED, false);
pass->quad_list.push_back(red.PassAs<DrawQuad>());
gfx::Transform yellow_content_to_target_transform;
yellow_content_to_target_transform.Translate(25.5f, 25.5f);
yellow_content_to_target_transform.Scale(0.5f, 0.5f);
- scoped_ptr<SharedQuadState> yellow_shared_state =
- CreateTestSharedQuadState(yellow_content_to_target_transform, rect);
+ SharedQuadState* yellow_shared_state = CreateTestSharedQuadState(
+ pass.get(), yellow_content_to_target_transform, rect);
scoped_ptr<SolidColorDrawQuad> yellow = SolidColorDrawQuad::Create();
- yellow->SetNew(yellow_shared_state.get(), rect, SK_ColorYELLOW, false);
+ yellow->SetNew(yellow_shared_state, rect, rect, SK_ColorYELLOW, false);
pass->quad_list.push_back(yellow.PassAs<DrawQuad>());
gfx::Transform blue_content_to_target_transform;
- scoped_ptr<SharedQuadState> blue_shared_state =
- CreateTestSharedQuadState(blue_content_to_target_transform, rect);
+ SharedQuadState* blue_shared_state = CreateTestSharedQuadState(
+ pass.get(), blue_content_to_target_transform, rect);
scoped_ptr<SolidColorDrawQuad> blue = SolidColorDrawQuad::Create();
- blue->SetNew(blue_shared_state.get(), rect, SK_ColorBLUE, false);
+ blue->SetNew(blue_shared_state, rect, rect, SK_ColorBLUE, false);
pass->quad_list.push_back(blue.PassAs<DrawQuad>());
@@ -1527,7 +1690,6 @@ TEST_F(GLRendererPixelTest, AxisAligned) {
EXPECT_TRUE(this->RunPixelTest(
&pass_list,
- PixelTest::NoOffscreenContext,
base::FilePath(FILE_PATH_LITERAL("axis_aligned.png")),
ExactPixelComparator(true)));
}
@@ -1547,20 +1709,20 @@ TEST_F(GLRendererPixelTest, ForceAntiAliasingOff) {
hole_content_to_target_transform.Scale(
0.5f + 1.0f / (rect.width() * 2.0f),
0.5f + 1.0f / (rect.height() * 2.0f));
- scoped_ptr<SharedQuadState> hole_shared_state =
- CreateTestSharedQuadState(hole_content_to_target_transform, rect);
+ SharedQuadState* hole_shared_state = CreateTestSharedQuadState(
+ pass.get(), hole_content_to_target_transform, rect);
scoped_ptr<SolidColorDrawQuad> hole = SolidColorDrawQuad::Create();
- hole->SetAll(hole_shared_state.get(), rect, rect, rect, false,
- SK_ColorTRANSPARENT, true);
+ hole->SetAll(
+ hole_shared_state, rect, rect, rect, false, SK_ColorTRANSPARENT, true);
pass->quad_list.push_back(hole.PassAs<DrawQuad>());
gfx::Transform green_content_to_target_transform;
- scoped_ptr<SharedQuadState> green_shared_state =
- CreateTestSharedQuadState(green_content_to_target_transform, rect);
+ SharedQuadState* green_shared_state = CreateTestSharedQuadState(
+ pass.get(), green_content_to_target_transform, rect);
scoped_ptr<SolidColorDrawQuad> green = SolidColorDrawQuad::Create();
- green->SetNew(green_shared_state.get(), rect, SK_ColorGREEN, false);
+ green->SetNew(green_shared_state, rect, rect, SK_ColorGREEN, false);
pass->quad_list.push_back(green.PassAs<DrawQuad>());
@@ -1569,7 +1731,6 @@ TEST_F(GLRendererPixelTest, ForceAntiAliasingOff) {
EXPECT_TRUE(this->RunPixelTest(
&pass_list,
- PixelTest::NoOffscreenContext,
base::FilePath(FILE_PATH_LITERAL("force_anti_aliasing_off.png")),
ExactPixelComparator(false)));
}
@@ -1586,23 +1747,24 @@ TEST_F(GLRendererPixelTest, AntiAliasingPerspective) {
0.0f, 0.3528f, 5.9737f, 9.5f,
0.0f, -0.2250f, -0.9744f, 0.0f,
0.0f, 0.0225f, 0.0974f, 1.0f);
- scoped_ptr<SharedQuadState> red_shared_state =
- CreateTestSharedQuadState(red_content_to_target_transform, red_rect);
+ SharedQuadState* red_shared_state = CreateTestSharedQuadState(
+ pass.get(), red_content_to_target_transform, red_rect);
scoped_ptr<SolidColorDrawQuad> red = SolidColorDrawQuad::Create();
- red->SetNew(red_shared_state.get(), red_rect, SK_ColorRED, false);
+ red->SetNew(red_shared_state, red_rect, red_rect, SK_ColorRED, false);
pass->quad_list.push_back(red.PassAs<DrawQuad>());
gfx::Rect green_rect(19, 7, 180, 10);
- scoped_ptr<SharedQuadState> green_shared_state =
- CreateTestSharedQuadState(gfx::Transform(), green_rect);
+ SharedQuadState* green_shared_state =
+ CreateTestSharedQuadState(pass.get(), gfx::Transform(), green_rect);
scoped_ptr<SolidColorDrawQuad> green = SolidColorDrawQuad::Create();
- green->SetNew(green_shared_state.get(), green_rect, SK_ColorGREEN, false);
+ green->SetNew(
+ green_shared_state, green_rect, green_rect, SK_ColorGREEN, false);
pass->quad_list.push_back(green.PassAs<DrawQuad>());
- scoped_ptr<SharedQuadState> blue_shared_state =
- CreateTestSharedQuadState(gfx::Transform(), rect);
+ SharedQuadState* blue_shared_state =
+ CreateTestSharedQuadState(pass.get(), gfx::Transform(), rect);
scoped_ptr<SolidColorDrawQuad> blue = SolidColorDrawQuad::Create();
- blue->SetNew(blue_shared_state.get(), rect, SK_ColorBLUE, false);
+ blue->SetNew(blue_shared_state, rect, rect, SK_ColorBLUE, false);
pass->quad_list.push_back(blue.PassAs<DrawQuad>());
RenderPassList pass_list;
@@ -1610,7 +1772,6 @@ TEST_F(GLRendererPixelTest, AntiAliasingPerspective) {
EXPECT_TRUE(this->RunPixelTest(
&pass_list,
- PixelTest::NoOffscreenContext,
base::FilePath(FILE_PATH_LITERAL("anti_aliasing_perspective.png")),
FuzzyPixelOffByOneComparator(true)));
}
@@ -1645,22 +1806,24 @@ TYPED_TEST(RendererPixelTest, PictureDrawQuadIdentityScale) {
blue_content_to_target_transform.Translate(offset.x(), offset.y());
gfx::RectF blue_scissor_rect = blue_clip_rect;
blue_content_to_target_transform.TransformRect(&blue_scissor_rect);
- scoped_ptr<SharedQuadState> blue_shared_state =
- CreateTestSharedQuadStateClipped(blue_content_to_target_transform,
+ SharedQuadState* blue_shared_state =
+ CreateTestSharedQuadStateClipped(pass.get(),
+ blue_content_to_target_transform,
blue_rect,
gfx::ToEnclosingRect(blue_scissor_rect));
scoped_ptr<PictureDrawQuad> blue_quad = PictureDrawQuad::Create();
- blue_quad->SetNew(blue_shared_state.get(),
+ blue_quad->SetNew(blue_shared_state,
viewport, // Intentionally bigger than clip.
gfx::Rect(),
viewport,
+ gfx::RectF(viewport),
viewport.size(),
texture_format,
viewport,
1.f,
- blue_pile);
+ PicturePileImpl::CreateFromOther(blue_pile));
pass->quad_list.push_back(blue_quad.PassAs<DrawQuad>());
// One viewport-filling green quad.
@@ -1672,19 +1835,20 @@ TYPED_TEST(RendererPixelTest, PictureDrawQuadIdentityScale) {
green_pile->RerecordPile();
gfx::Transform green_content_to_target_transform;
- scoped_ptr<SharedQuadState> green_shared_state =
- CreateTestSharedQuadState(green_content_to_target_transform, viewport);
+ SharedQuadState* green_shared_state = CreateTestSharedQuadState(
+ pass.get(), green_content_to_target_transform, viewport);
scoped_ptr<PictureDrawQuad> green_quad = PictureDrawQuad::Create();
- green_quad->SetNew(green_shared_state.get(),
+ green_quad->SetNew(green_shared_state,
viewport,
gfx::Rect(),
+ viewport,
gfx::RectF(0.f, 0.f, 1.f, 1.f),
viewport.size(),
texture_format,
viewport,
1.f,
- green_pile);
+ PicturePileImpl::CreateFromOther(green_pile));
pass->quad_list.push_back(green_quad.PassAs<DrawQuad>());
RenderPassList pass_list;
@@ -1692,7 +1856,6 @@ TYPED_TEST(RendererPixelTest, PictureDrawQuadIdentityScale) {
EXPECT_TRUE(this->RunPixelTest(
&pass_list,
- PixelTest::NoOffscreenContext,
base::FilePath(FILE_PATH_LITERAL("green_with_blue_corner.png")),
ExactPixelComparator(true)));
}
@@ -1717,20 +1880,21 @@ TYPED_TEST(RendererPixelTest, PictureDrawQuadOpacity) {
green_pile->RerecordPile();
gfx::Transform green_content_to_target_transform;
- scoped_ptr<SharedQuadState> green_shared_state =
- CreateTestSharedQuadState(green_content_to_target_transform, viewport);
+ SharedQuadState* green_shared_state = CreateTestSharedQuadState(
+ pass.get(), green_content_to_target_transform, viewport);
green_shared_state->opacity = 0.5f;
scoped_ptr<PictureDrawQuad> green_quad = PictureDrawQuad::Create();
- green_quad->SetNew(green_shared_state.get(),
+ green_quad->SetNew(green_shared_state,
viewport,
gfx::Rect(),
+ viewport,
gfx::RectF(0, 0, 1, 1),
viewport.size(),
texture_format,
viewport,
1.f,
- green_pile);
+ PicturePileImpl::CreateFromOther(green_pile));
pass->quad_list.push_back(green_quad.PassAs<DrawQuad>());
// One viewport-filling white quad.
@@ -1742,19 +1906,20 @@ TYPED_TEST(RendererPixelTest, PictureDrawQuadOpacity) {
white_pile->RerecordPile();
gfx::Transform white_content_to_target_transform;
- scoped_ptr<SharedQuadState> white_shared_state =
- CreateTestSharedQuadState(white_content_to_target_transform, viewport);
+ SharedQuadState* white_shared_state = CreateTestSharedQuadState(
+ pass.get(), white_content_to_target_transform, viewport);
scoped_ptr<PictureDrawQuad> white_quad = PictureDrawQuad::Create();
- white_quad->SetNew(white_shared_state.get(),
+ white_quad->SetNew(white_shared_state,
viewport,
gfx::Rect(),
+ viewport,
gfx::RectF(0, 0, 1, 1),
viewport.size(),
texture_format,
viewport,
1.f,
- white_pile);
+ PicturePileImpl::CreateFromOther(white_pile));
pass->quad_list.push_back(white_quad.PassAs<DrawQuad>());
RenderPassList pass_list;
@@ -1762,7 +1927,6 @@ TYPED_TEST(RendererPixelTest, PictureDrawQuadOpacity) {
EXPECT_TRUE(this->RunPixelTest(
&pass_list,
- PixelTest::NoOffscreenContext,
base::FilePath(FILE_PATH_LITERAL("green_alpha.png")),
FuzzyPixelOffByOneComparator(true)));
}
@@ -1799,8 +1963,7 @@ TYPED_TEST(RendererPixelTest, PictureDrawQuadDisableImageFiltering) {
CreateTestRenderPass(id, viewport, transform_to_root);
SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, 2, 2);
- bitmap.allocPixels();
+ bitmap.allocN32Pixels(2, 2);
{
SkAutoLockPixels lock(bitmap);
SkCanvas canvas(bitmap);
@@ -1818,19 +1981,20 @@ TYPED_TEST(RendererPixelTest, PictureDrawQuadDisableImageFiltering) {
pile->RerecordPile();
gfx::Transform content_to_target_transform;
- scoped_ptr<SharedQuadState> shared_state =
- CreateTestSharedQuadState(content_to_target_transform, viewport);
+ SharedQuadState* shared_state = CreateTestSharedQuadState(
+ pass.get(), content_to_target_transform, viewport);
scoped_ptr<PictureDrawQuad> quad = PictureDrawQuad::Create();
- quad->SetNew(shared_state.get(),
- viewport,
- gfx::Rect(),
- gfx::RectF(0, 0, 2, 2),
- viewport.size(),
- texture_format,
- viewport,
- 1.f,
- pile);
+ quad->SetNew(shared_state,
+ viewport,
+ gfx::Rect(),
+ viewport,
+ gfx::RectF(0, 0, 2, 2),
+ viewport.size(),
+ texture_format,
+ viewport,
+ 1.f,
+ PicturePileImpl::CreateFromOther(pile));
pass->quad_list.push_back(quad.PassAs<DrawQuad>());
RenderPassList pass_list;
@@ -1840,7 +2004,6 @@ TYPED_TEST(RendererPixelTest, PictureDrawQuadDisableImageFiltering) {
EXPECT_TRUE(this->RunPixelTest(
&pass_list,
- PixelTest::NoOffscreenContext,
base::FilePath(FILE_PATH_LITERAL("four_blue_green_checkers.png")),
ExactPixelComparator(true)));
}
@@ -1874,31 +2037,34 @@ TYPED_TEST(RendererPixelTest, PictureDrawQuadNonIdentityScale) {
green_pile->add_draw_rect_with_paint(green_rect2, green_paint);
green_pile->RerecordPile();
- scoped_ptr<SharedQuadState> top_right_green_shared_quad_state =
- CreateTestSharedQuadState(green_content_to_target_transform, viewport);
+ SharedQuadState* top_right_green_shared_quad_state =
+ CreateTestSharedQuadState(
+ pass.get(), green_content_to_target_transform, viewport);
scoped_ptr<PictureDrawQuad> green_quad1 = PictureDrawQuad::Create();
- green_quad1->SetNew(top_right_green_shared_quad_state.get(),
+ green_quad1->SetNew(top_right_green_shared_quad_state,
green_rect1,
gfx::Rect(),
+ green_rect1,
gfx::RectF(green_rect1.size()),
green_rect1.size(),
texture_format,
green_rect1,
1.f,
- green_pile);
+ PicturePileImpl::CreateFromOther(green_pile));
pass->quad_list.push_back(green_quad1.PassAs<DrawQuad>());
scoped_ptr<PictureDrawQuad> green_quad2 = PictureDrawQuad::Create();
- green_quad2->SetNew(top_right_green_shared_quad_state.get(),
+ green_quad2->SetNew(top_right_green_shared_quad_state,
green_rect2,
gfx::Rect(),
+ green_rect2,
gfx::RectF(green_rect2.size()),
green_rect2.size(),
texture_format,
green_rect2,
1.f,
- green_pile);
+ PicturePileImpl::CreateFromOther(green_pile));
pass->quad_list.push_back(green_quad2.PassAs<DrawQuad>());
// Add a green clipped checkerboard in the bottom right to help test
@@ -1906,13 +2072,18 @@ TYPED_TEST(RendererPixelTest, PictureDrawQuadNonIdentityScale) {
gfx::Rect bottom_right_rect(
gfx::Point(viewport.width() / 2, viewport.height() / 2),
gfx::Size(viewport.width() / 2, viewport.height() / 2));
- scoped_ptr<SharedQuadState> bottom_right_green_shared_state =
- CreateTestSharedQuadStateClipped(
- green_content_to_target_transform, viewport, bottom_right_rect);
+ SharedQuadState* bottom_right_green_shared_state =
+ CreateTestSharedQuadStateClipped(pass.get(),
+ green_content_to_target_transform,
+ viewport,
+ bottom_right_rect);
scoped_ptr<SolidColorDrawQuad> bottom_right_color_quad =
SolidColorDrawQuad::Create();
- bottom_right_color_quad->SetNew(
- bottom_right_green_shared_state.get(), viewport, SK_ColorGREEN, false);
+ bottom_right_color_quad->SetNew(bottom_right_green_shared_state,
+ viewport,
+ viewport,
+ SK_ColorGREEN,
+ false);
pass->quad_list.push_back(bottom_right_color_quad.PassAs<DrawQuad>());
// Add two blue checkerboards taking up the bottom left and top right,
@@ -1957,30 +2128,33 @@ TYPED_TEST(RendererPixelTest, PictureDrawQuadNonIdentityScale) {
gfx::Transform content_to_target_transform;
content_to_target_transform.Scale(10.0, 10.0);
gfx::Rect quad_content_rect(gfx::Size(20, 20));
- scoped_ptr<SharedQuadState> blue_shared_state =
- CreateTestSharedQuadState(content_to_target_transform, quad_content_rect);
+ SharedQuadState* blue_shared_state = CreateTestSharedQuadState(
+ pass.get(), content_to_target_transform, quad_content_rect);
scoped_ptr<PictureDrawQuad> blue_quad = PictureDrawQuad::Create();
- blue_quad->SetNew(blue_shared_state.get(),
+ blue_quad->SetNew(blue_shared_state,
quad_content_rect,
gfx::Rect(),
quad_content_rect,
+ gfx::RectF(quad_content_rect),
content_union_rect.size(),
texture_format,
content_union_rect,
contents_scale,
- pile);
+ PicturePileImpl::CreateFromOther(pile));
pass->quad_list.push_back(blue_quad.PassAs<DrawQuad>());
// Fill left half of viewport with green.
gfx::Transform half_green_content_to_target_transform;
gfx::Rect half_green_rect(gfx::Size(viewport.width() / 2, viewport.height()));
- scoped_ptr<SharedQuadState> half_green_shared_state =
- CreateTestSharedQuadState(half_green_content_to_target_transform,
- half_green_rect);
+ SharedQuadState* half_green_shared_state = CreateTestSharedQuadState(
+ pass.get(), half_green_content_to_target_transform, half_green_rect);
scoped_ptr<SolidColorDrawQuad> half_color_quad = SolidColorDrawQuad::Create();
- half_color_quad->SetNew(
- half_green_shared_state.get(), half_green_rect, SK_ColorGREEN, false);
+ half_color_quad->SetNew(half_green_shared_state,
+ half_green_rect,
+ half_green_rect,
+ SK_ColorGREEN,
+ false);
pass->quad_list.push_back(half_color_quad.PassAs<DrawQuad>());
RenderPassList pass_list;
@@ -1988,7 +2162,6 @@ TYPED_TEST(RendererPixelTest, PictureDrawQuadNonIdentityScale) {
EXPECT_TRUE(this->RunPixelTest(
&pass_list,
- PixelTest::NoOffscreenContext,
base::FilePath(FILE_PATH_LITERAL("four_blue_green_checkers.png")),
ExactPixelComparator(true)));
}
@@ -1999,8 +2172,8 @@ TYPED_TEST(RendererPixelTest, WrapModeRepeat) {
RenderPass::Id id(1, 1);
scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect);
- scoped_ptr<SharedQuadState> shared_state =
- CreateTestSharedQuadState(gfx::Transform(), rect);
+ SharedQuadState* shared_state =
+ CreateTestSharedQuadState(pass.get(), gfx::Transform(), rect);
gfx::Rect texture_rect(4, 4);
SkPMColor colors[4] = {
@@ -2031,13 +2204,14 @@ TYPED_TEST(RendererPixelTest, WrapModeRepeat) {
float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f};
scoped_ptr<TextureDrawQuad> texture_quad = TextureDrawQuad::Create();
texture_quad->SetNew(
- shared_state.get(),
+ shared_state,
gfx::Rect(this->device_viewport_size_),
gfx::Rect(),
+ gfx::Rect(this->device_viewport_size_),
resource,
- true, // premultiplied_alpha
+ true, // premultiplied_alpha
gfx::PointF(0.0f, 0.0f), // uv_top_left
- gfx::PointF( // uv_bottom_right
+ gfx::PointF( // uv_bottom_right
this->device_viewport_size_.width() / texture_rect.width(),
this->device_viewport_size_.height() / texture_rect.height()),
SK_ColorWHITE,
@@ -2050,7 +2224,6 @@ TYPED_TEST(RendererPixelTest, WrapModeRepeat) {
EXPECT_TRUE(this->RunPixelTest(
&pass_list,
- PixelTest::NoOffscreenContext,
base::FilePath(FILE_PATH_LITERAL("wrap_mode_repeat.png")),
FuzzyPixelOffByOneComparator(true)));
}
diff --git a/chromium/cc/output/renderer_unittest.cc b/chromium/cc/output/renderer_unittest.cc
new file mode 100644
index 00000000000..f103baabbc5
--- /dev/null
+++ b/chromium/cc/output/renderer_unittest.cc
@@ -0,0 +1,94 @@
+// 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/output/delegating_renderer.h"
+#include "cc/output/gl_renderer.h"
+#include "cc/output/output_surface.h"
+#include "cc/test/fake_output_surface_client.h"
+#include "cc/test/fake_renderer_client.h"
+#include "cc/test/test_context_provider.h"
+#include "cc/test/test_web_graphics_context_3d.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+namespace {
+
+class MockContextProvider : public TestContextProvider {
+ public:
+ explicit MockContextProvider(scoped_ptr<TestWebGraphicsContext3D> context)
+ : TestContextProvider(context.Pass()) {}
+ MOCK_METHOD0(DeleteCachedResources, void());
+
+ protected:
+ ~MockContextProvider() {}
+};
+
+template <class T>
+scoped_ptr<Renderer> CreateRenderer(RendererClient* client,
+ const LayerTreeSettings* settings,
+ OutputSurface* output_surface,
+ ResourceProvider* resource_provider);
+
+template <>
+scoped_ptr<Renderer> CreateRenderer<DelegatingRenderer>(
+ RendererClient* client,
+ const LayerTreeSettings* settings,
+ OutputSurface* output_surface,
+ ResourceProvider* resource_provider) {
+ return DelegatingRenderer::Create(
+ client, settings, output_surface, resource_provider)
+ .PassAs<Renderer>();
+}
+
+template <>
+scoped_ptr<Renderer> CreateRenderer<GLRenderer>(
+ RendererClient* client,
+ const LayerTreeSettings* settings,
+ OutputSurface* output_surface,
+ ResourceProvider* resource_provider) {
+ return GLRenderer::Create(
+ client, settings, output_surface, resource_provider, NULL, 0)
+ .PassAs<Renderer>();
+}
+
+template <typename T>
+class RendererTest : public ::testing::Test {
+ protected:
+ virtual void SetUp() {
+ context_provider_ =
+ new MockContextProvider(TestWebGraphicsContext3D::Create());
+ output_surface_.reset(new OutputSurface(context_provider_));
+ output_surface_->BindToClient(&output_surface_client_);
+ resource_provider_ =
+ ResourceProvider::Create(output_surface_.get(), NULL, 0, false, 1,
+ false);
+ renderer_ = CreateRenderer<T>(&renderer_client_,
+ &tree_settings_,
+ output_surface_.get(),
+ resource_provider_.get());
+ }
+
+ FakeRendererClient renderer_client_;
+ LayerTreeSettings tree_settings_;
+ FakeOutputSurfaceClient output_surface_client_;
+ scoped_refptr<MockContextProvider> context_provider_;
+ scoped_ptr<OutputSurface> output_surface_;
+ scoped_ptr<ResourceProvider> resource_provider_;
+ scoped_ptr<Renderer> renderer_;
+};
+
+typedef ::testing::Types<DelegatingRenderer, GLRenderer> RendererTypes;
+TYPED_TEST_CASE(RendererTest, RendererTypes);
+
+TYPED_TEST(RendererTest, ContextPurgedWhenRendererBecomesInvisible) {
+ EXPECT_CALL(*(this->context_provider_), DeleteCachedResources()).Times(1);
+
+ EXPECT_TRUE(this->renderer_->visible());
+ this->renderer_->SetVisible(false);
+ EXPECT_FALSE(this->renderer_->visible());
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/output/shader.cc b/chromium/cc/output/shader.cc
index b752f46134d..96b745ce944 100644
--- a/chromium/cc/output/shader.cc
+++ b/chromium/cc/output/shader.cc
@@ -135,9 +135,9 @@ static std::string SetFragmentSamplerType(
} // namespace
TexCoordPrecision TexCoordPrecisionRequired(GLES2Interface* context,
- int *highp_threshold_cache,
+ int* highp_threshold_cache,
int highp_threshold_min,
- gfx::Point max_coordinate) {
+ const gfx::Point& max_coordinate) {
return TexCoordPrecisionRequired(context,
highp_threshold_cache, highp_threshold_min,
max_coordinate.x(), max_coordinate.y());
@@ -146,7 +146,7 @@ TexCoordPrecision TexCoordPrecisionRequired(GLES2Interface* context,
TexCoordPrecision TexCoordPrecisionRequired(GLES2Interface* context,
int *highp_threshold_cache,
int highp_threshold_min,
- gfx::Size max_size) {
+ const gfx::Size& max_size) {
return TexCoordPrecisionRequired(context,
highp_threshold_cache, highp_threshold_min,
max_size.width(), max_size.height());
@@ -185,16 +185,16 @@ std::string VertexShaderPosTex::GetShaderString() const {
); // NOLINT(whitespace/parens)
}
-VertexShaderPosTexYUVStretch::VertexShaderPosTexYUVStretch()
- : matrix_location_(-1),
- tex_scale_location_(-1) {}
+VertexShaderPosTexYUVStretchOffset::VertexShaderPosTexYUVStretchOffset()
+ : matrix_location_(-1), tex_scale_location_(-1), tex_offset_location_(-1) {}
-void VertexShaderPosTexYUVStretch::Init(GLES2Interface* context,
- unsigned program,
- int* base_uniform_index) {
+void VertexShaderPosTexYUVStretchOffset::Init(GLES2Interface* context,
+ unsigned program,
+ int* base_uniform_index) {
static const char* uniforms[] = {
"matrix",
"texScale",
+ "texOffset",
};
int locations[arraysize(uniforms)];
@@ -206,9 +206,10 @@ void VertexShaderPosTexYUVStretch::Init(GLES2Interface* context,
base_uniform_index);
matrix_location_ = locations[0];
tex_scale_location_ = locations[1];
+ tex_offset_location_ = locations[2];
}
-std::string VertexShaderPosTexYUVStretch::GetShaderString() const {
+std::string VertexShaderPosTexYUVStretchOffset::GetShaderString() const {
return VERTEX_SHADER(
precision mediump float;
attribute vec4 a_position;
@@ -216,9 +217,10 @@ std::string VertexShaderPosTexYUVStretch::GetShaderString() const {
uniform mat4 matrix;
varying TexCoordPrecision vec2 v_texCoord;
uniform TexCoordPrecision vec2 texScale;
+ uniform TexCoordPrecision vec2 texOffset;
void main() {
gl_Position = matrix * a_position;
- v_texCoord = a_texCoord * texScale;
+ v_texCoord = a_texCoord * texScale + texOffset;
}
); // NOLINT(whitespace/parens)
}
diff --git a/chromium/cc/output/shader.h b/chromium/cc/output/shader.h
index 9473ce8da38..83c41ee85ff 100644
--- a/chromium/cc/output/shader.h
+++ b/chromium/cc/output/shader.h
@@ -43,17 +43,17 @@ enum SamplerType {
// the caching multi-thread/context safe in an easy low-overhead manner.
// The caller must make sure to clear highp_threshold_cache to 0, so it can be
// reinitialized, if a new or different context is used.
-CC_EXPORT TexCoordPrecision TexCoordPrecisionRequired(
- gpu::gles2::GLES2Interface* context,
- int *highp_threshold_cache,
- int highp_threshold_min,
- gfx::Point max_coordinate);
+CC_EXPORT TexCoordPrecision
+ TexCoordPrecisionRequired(gpu::gles2::GLES2Interface* context,
+ int* highp_threshold_cache,
+ int highp_threshold_min,
+ const gfx::Point& max_coordinate);
CC_EXPORT TexCoordPrecision TexCoordPrecisionRequired(
gpu::gles2::GLES2Interface* context,
int *highp_threshold_cache,
int highp_threshold_min,
- gfx::Size max_size);
+ const gfx::Size& max_size);
class VertexShaderPosTex {
public:
@@ -72,9 +72,9 @@ class VertexShaderPosTex {
DISALLOW_COPY_AND_ASSIGN(VertexShaderPosTex);
};
-class VertexShaderPosTexYUVStretch {
+class VertexShaderPosTexYUVStretchOffset {
public:
- VertexShaderPosTexYUVStretch();
+ VertexShaderPosTexYUVStretchOffset();
void Init(gpu::gles2::GLES2Interface* context,
unsigned program,
@@ -83,12 +83,14 @@ class VertexShaderPosTexYUVStretch {
int matrix_location() const { return matrix_location_; }
int tex_scale_location() const { return tex_scale_location_; }
+ int tex_offset_location() const { return tex_offset_location_; }
private:
int matrix_location_;
int tex_scale_location_;
+ int tex_offset_location_;
- DISALLOW_COPY_AND_ASSIGN(VertexShaderPosTexYUVStretch);
+ DISALLOW_COPY_AND_ASSIGN(VertexShaderPosTexYUVStretchOffset);
};
class VertexShaderPos {
diff --git a/chromium/cc/output/software_frame_data.cc b/chromium/cc/output/software_frame_data.cc
index 0b430325092..7fc380e7b64 100644
--- a/chromium/cc/output/software_frame_data.cc
+++ b/chromium/cc/output/software_frame_data.cc
@@ -6,9 +6,7 @@
namespace cc {
-SoftwareFrameData::SoftwareFrameData()
- : id(0),
- handle(base::SharedMemory::NULLHandle()) {}
+SoftwareFrameData::SoftwareFrameData() : id(0) {}
SoftwareFrameData::~SoftwareFrameData() {}
diff --git a/chromium/cc/output/software_frame_data.h b/chromium/cc/output/software_frame_data.h
index b7fb44a4e81..0a9c345f033 100644
--- a/chromium/cc/output/software_frame_data.h
+++ b/chromium/cc/output/software_frame_data.h
@@ -5,8 +5,8 @@
#ifndef CC_OUTPUT_SOFTWARE_FRAME_DATA_H_
#define CC_OUTPUT_SOFTWARE_FRAME_DATA_H_
-#include "base/memory/shared_memory.h"
#include "cc/base/cc_export.h"
+#include "cc/resources/shared_bitmap.h"
#include "ui/gfx/rect.h"
namespace cc {
@@ -19,7 +19,7 @@ class CC_EXPORT SoftwareFrameData {
unsigned id;
gfx::Size size;
gfx::Rect damage_rect;
- base::SharedMemoryHandle handle;
+ SharedBitmapId bitmap_id;
};
} // namespace cc
diff --git a/chromium/cc/output/software_output_device.cc b/chromium/cc/output/software_output_device.cc
index 17ef63f6d57..9e13cf312a3 100644
--- a/chromium/cc/output/software_output_device.cc
+++ b/chromium/cc/output/software_output_device.cc
@@ -6,29 +6,33 @@
#include "base/logging.h"
#include "cc/output/software_frame_data.h"
-#include "third_party/skia/include/core/SkBitmapDevice.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "ui/gfx/skia_util.h"
#include "ui/gfx/vsync_provider.h"
namespace cc {
-SoftwareOutputDevice::SoftwareOutputDevice() {}
+SoftwareOutputDevice::SoftwareOutputDevice() : scale_factor_(1.f) {
+}
SoftwareOutputDevice::~SoftwareOutputDevice() {}
-void SoftwareOutputDevice::Resize(gfx::Size viewport_size) {
- if (viewport_size_ == viewport_size)
+void SoftwareOutputDevice::Resize(const gfx::Size& viewport_pixel_size,
+ float scale_factor) {
+ scale_factor_ = scale_factor;
+
+ if (viewport_pixel_size_ == viewport_pixel_size)
return;
- viewport_size_ = viewport_size;
- device_ = skia::AdoptRef(new SkBitmapDevice(SkBitmap::kARGB_8888_Config,
- viewport_size.width(), viewport_size.height(), true));
- canvas_ = skia::AdoptRef(new SkCanvas(device_.get()));
+ SkImageInfo info = SkImageInfo::MakeN32(viewport_pixel_size.width(),
+ viewport_pixel_size.height(),
+ kOpaque_SkAlphaType);
+ viewport_pixel_size_ = viewport_pixel_size;
+ canvas_ = skia::AdoptRef(SkCanvas::NewRaster(info));
}
-SkCanvas* SoftwareOutputDevice::BeginPaint(gfx::Rect damage_rect) {
- DCHECK(device_);
+SkCanvas* SoftwareOutputDevice::BeginPaint(const gfx::Rect& damage_rect) {
+ DCHECK(canvas_);
damage_rect_ = damage_rect;
return canvas_.get();
}
@@ -36,20 +40,18 @@ SkCanvas* SoftwareOutputDevice::BeginPaint(gfx::Rect damage_rect) {
void SoftwareOutputDevice::EndPaint(SoftwareFrameData* frame_data) {
DCHECK(frame_data);
frame_data->id = 0;
- frame_data->size = viewport_size_;
+ frame_data->size = viewport_pixel_size_;
frame_data->damage_rect = damage_rect_;
- frame_data->handle = base::SharedMemory::NULLHandle();
}
-void SoftwareOutputDevice::CopyToBitmap(
- gfx::Rect rect, SkBitmap* output) {
- DCHECK(device_);
- const SkBitmap& bitmap = device_->accessBitmap(false);
- bitmap.extractSubset(output, gfx::RectToSkIRect(rect));
+void SoftwareOutputDevice::CopyToPixels(const gfx::Rect& rect, void* pixels) {
+ DCHECK(canvas_);
+ SkImageInfo info = SkImageInfo::MakeN32Premul(rect.width(), rect.height());
+ canvas_->readPixels(info, pixels, info.minRowBytes(), rect.x(), rect.y());
}
-void SoftwareOutputDevice::Scroll(
- gfx::Vector2d delta, gfx::Rect clip_rect) {
+void SoftwareOutputDevice::Scroll(const gfx::Vector2d& delta,
+ const gfx::Rect& clip_rect) {
NOTIMPLEMENTED();
}
diff --git a/chromium/cc/output/software_output_device.h b/chromium/cc/output/software_output_device.h
index 4ecf1fedd8e..e8de5b90570 100644
--- a/chromium/cc/output/software_output_device.h
+++ b/chromium/cc/output/software_output_device.h
@@ -36,13 +36,13 @@ class CC_EXPORT SoftwareOutputDevice {
// Discards any pre-existing backing buffers and allocates memory for a
// software device of |size|. This must be called before the
// |SoftwareOutputDevice| can be used in other ways.
- virtual void Resize(gfx::Size size);
+ virtual void Resize(const gfx::Size& pixel_size, float scale_factor);
// Called on BeginDrawingFrame. The compositor will draw into the returned
// SkCanvas. The |SoftwareOutputDevice| implementation needs to provide a
// valid SkCanvas of at least size |damage_rect|. This class retains ownership
// of the SkCanvas.
- virtual SkCanvas* BeginPaint(gfx::Rect damage_rect);
+ virtual SkCanvas* BeginPaint(const gfx::Rect& damage_rect);
// Called on FinishDrawingFrame. The compositor will no longer mutate the the
// SkCanvas instance returned by |BeginPaint| and should discard any reference
@@ -50,13 +50,12 @@ class CC_EXPORT SoftwareOutputDevice {
virtual void EndPaint(SoftwareFrameData* frame_data);
// Copies pixels inside |rect| from the current software framebuffer to
- // |output|. Fails if there is no current softwareframebuffer.
- virtual void CopyToBitmap(gfx::Rect rect, SkBitmap* output);
+ // |pixels|. Fails if there is no current softwareframebuffer.
+ virtual void CopyToPixels(const gfx::Rect& rect, void* pixels);
// Blit the pixel content of the SoftwareOutputDevice by |delta| with the
// write clipped to |clip_rect|.
- virtual void Scroll(gfx::Vector2d delta,
- gfx::Rect clip_rect);
+ virtual void Scroll(const gfx::Vector2d& delta, const gfx::Rect& clip_rect);
// Discard the backing buffer in the surface provided by this instance.
virtual void DiscardBackbuffer() {}
@@ -75,9 +74,9 @@ class CC_EXPORT SoftwareOutputDevice {
virtual gfx::VSyncProvider* GetVSyncProvider();
protected:
- gfx::Size viewport_size_;
+ gfx::Size viewport_pixel_size_;
+ float scale_factor_;
gfx::Rect damage_rect_;
- skia::RefPtr<SkBaseDevice> device_;
skia::RefPtr<SkCanvas> canvas_;
scoped_ptr<gfx::VSyncProvider> vsync_provider_;
diff --git a/chromium/cc/output/software_renderer.cc b/chromium/cc/output/software_renderer.cc
index 421e541da7d..61b3253353f 100644
--- a/chromium/cc/output/software_renderer.cc
+++ b/chromium/cc/output/software_renderer.cc
@@ -20,7 +20,9 @@
#include "cc/quads/solid_color_draw_quad.h"
#include "cc/quads/texture_draw_quad.h"
#include "cc/quads/tile_draw_quad.h"
+#include "cc/resources/raster_worker_pool.h"
#include "skia/ext/opacity_draw_filter.h"
+#include "third_party/skia/include/core/SkBitmapDevice.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkImageFilter.h"
@@ -35,8 +37,45 @@ namespace cc {
namespace {
+class OnDemandRasterTaskImpl : public Task {
+ public:
+ OnDemandRasterTaskImpl(PicturePileImpl* picture_pile,
+ SkCanvas* canvas,
+ gfx::Rect content_rect,
+ float contents_scale)
+ : picture_pile_(picture_pile),
+ canvas_(canvas),
+ content_rect_(content_rect),
+ contents_scale_(contents_scale) {
+ DCHECK(picture_pile_);
+ DCHECK(canvas_);
+ }
+
+ // Overridden from Task:
+ virtual void RunOnWorkerThread() OVERRIDE {
+ TRACE_EVENT0("cc", "OnDemandRasterTaskImpl::RunOnWorkerThread");
+
+ PicturePileImpl* picture_pile = picture_pile_->GetCloneForDrawingOnThread(
+ RasterWorkerPool::GetPictureCloneIndexForCurrentThread());
+ DCHECK(picture_pile);
+
+ picture_pile->RasterDirect(canvas_, content_rect_, contents_scale_, NULL);
+ }
+
+ protected:
+ virtual ~OnDemandRasterTaskImpl() {}
+
+ private:
+ PicturePileImpl* picture_pile_;
+ SkCanvas* canvas_;
+ const gfx::Rect content_rect_;
+ const float contents_scale_;
+
+ DISALLOW_COPY_AND_ASSIGN(OnDemandRasterTaskImpl);
+};
+
static inline bool IsScalarNearlyInteger(SkScalar scalar) {
- return SkScalarNearlyZero(scalar - SkScalarRound(scalar));
+ return SkScalarNearlyZero(scalar - SkScalarRoundToScalar(scalar));
}
bool IsScaleAndIntegerTranslate(const SkMatrix& matrix) {
@@ -76,7 +115,6 @@ SoftwareRenderer::SoftwareRenderer(RendererClient* client,
OutputSurface* output_surface,
ResourceProvider* resource_provider)
: DirectRenderer(client, settings, output_surface, resource_provider),
- visible_(true),
is_scissor_enabled_(false),
is_backbuffer_discarded_(false),
output_device_(output_surface->software_device()),
@@ -90,13 +128,15 @@ SoftwareRenderer::SoftwareRenderer(RendererClient* client,
capabilities_.allow_partial_texture_updates = true;
capabilities_.using_partial_swap = true;
- capabilities_.using_map_image = settings_->use_map_image;
+ capabilities_.using_map_image = true;
capabilities_.using_shared_memory_resources = true;
+
+ capabilities_.allow_rasterize_on_demand = true;
}
SoftwareRenderer::~SoftwareRenderer() {}
-const RendererCapabilities& SoftwareRenderer::Capabilities() const {
+const RendererCapabilitiesImpl& SoftwareRenderer::Capabilities() const {
return capabilities_;
}
@@ -117,6 +157,7 @@ void SoftwareRenderer::FinishDrawingFrame(DrawingFrame* frame) {
}
void SoftwareRenderer::SwapBuffers(const CompositorFrameMetadata& metadata) {
+ TRACE_EVENT0("cc,benchmark", "SoftwareRenderer::SwapBuffers");
CompositorFrame compositor_frame;
compositor_frame.metadata = metadata;
compositor_frame.software_frame_data = current_frame_data_.Pass();
@@ -142,8 +183,8 @@ void SoftwareRenderer::EnsureScissorTestDisabled() {
// clipRect on the current SkCanvas. This is done by setting clipRect to
// the viewport's dimensions.
is_scissor_enabled_ = false;
- SkBaseDevice* device = current_canvas_->getDevice();
- SetClipRect(gfx::Rect(device->width(), device->height()));
+ SkISize size = current_canvas_->getDeviceSize();
+ SetClipRect(gfx::Rect(size.width(), size.height()));
}
void SoftwareRenderer::Finish() {}
@@ -157,7 +198,7 @@ void SoftwareRenderer::BindFramebufferToOutputSurface(DrawingFrame* frame) {
bool SoftwareRenderer::BindFramebufferToTexture(
DrawingFrame* frame,
const ScopedResource* texture,
- gfx::Rect target_rect) {
+ const gfx::Rect& target_rect) {
current_framebuffer_lock_.reset();
current_framebuffer_lock_ = make_scoped_ptr(
new ResourceProvider::ScopedWriteLockSoftware(
@@ -170,13 +211,13 @@ bool SoftwareRenderer::BindFramebufferToTexture(
return true;
}
-void SoftwareRenderer::SetScissorTestRect(gfx::Rect scissor_rect) {
+void SoftwareRenderer::SetScissorTestRect(const gfx::Rect& scissor_rect) {
is_scissor_enabled_ = true;
scissor_rect_ = scissor_rect;
SetClipRect(scissor_rect);
}
-void SoftwareRenderer::SetClipRect(gfx::Rect rect) {
+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();
@@ -209,7 +250,8 @@ void SoftwareRenderer::ClearFramebuffer(DrawingFrame* frame,
}
}
-void SoftwareRenderer::SetDrawViewport(gfx::Rect window_space_viewport) {}
+void SoftwareRenderer::SetDrawViewport(
+ const gfx::Rect& window_space_viewport) {}
bool SoftwareRenderer::IsSoftwareResource(
ResourceProvider::ResourceId resource_id) const {
@@ -248,7 +290,7 @@ void SoftwareRenderer::DoDrawQuad(DrawingFrame* frame, const DrawQuad* quad) {
quad->IsRightEdge();
if (settings_->allow_antialiasing && all_four_edges_are_exterior)
current_paint_.setAntiAlias(true);
- current_paint_.setFilterBitmap(true);
+ current_paint_.setFilterLevel(SkPaint::kLow_FilterLevel);
}
if (quad->ShouldDrawWithBlending()) {
@@ -280,6 +322,11 @@ void SoftwareRenderer::DoDrawQuad(DrawingFrame* frame, const DrawQuad* quad) {
case DrawQuad::TILED_CONTENT:
DrawTileQuad(frame, TileDrawQuad::MaterialCast(quad));
break;
+ case DrawQuad::SURFACE_CONTENT:
+ // Surface content should be fully resolved to other quad types before
+ // reaching a direct renderer.
+ NOTREACHED();
+ break;
case DrawQuad::INVALID:
case DrawQuad::IO_SURFACE_CONTENT:
case DrawQuad::YUV_VIDEO_CONTENT:
@@ -341,8 +388,14 @@ void SoftwareRenderer::DrawPictureQuad(const DrawingFrame* frame,
TRACE_EVENT0("cc",
"SoftwareRenderer::DrawPictureQuad");
- quad->picture_pile->RasterDirect(
- current_canvas_, quad->content_rect, quad->contents_scale, NULL);
+
+ // Create and run on-demand raster task for tile.
+ scoped_refptr<Task> on_demand_raster_task(
+ new OnDemandRasterTaskImpl(quad->picture_pile,
+ current_canvas_,
+ quad->content_rect,
+ quad->contents_scale));
+ client_->RunOnDemandRasterTask(on_demand_raster_task.get());
current_canvas_->setDrawFilter(NULL);
}
@@ -367,6 +420,8 @@ void SoftwareRenderer::DrawTextureQuad(const DrawingFrame* frame,
// TODO(skaslev): Add support for non-premultiplied alpha.
ResourceProvider::ScopedReadLockSoftware lock(resource_provider_,
quad->resource_id);
+ if (!lock.valid())
+ return;
const SkBitmap* bitmap = lock.sk_bitmap();
gfx::RectF uv_rect = gfx::ScaleRect(gfx::BoundingRect(quad->uv_top_left,
quad->uv_bottom_right),
@@ -399,8 +454,7 @@ void SoftwareRenderer::DrawTextureQuad(const DrawingFrame* frame,
SkMatrix matrix;
matrix.setRectToRect(sk_uv_rect, quad_rect, SkMatrix::kFill_ScaleToFit);
skia::RefPtr<SkShader> shader = skia::AdoptRef(
- SkShader::CreateBitmapShader(*bitmap, tile_mode, tile_mode));
- shader->setLocalMatrix(matrix);
+ SkShader::CreateBitmapShader(*bitmap, tile_mode, tile_mode, &matrix));
SkPaint paint;
paint.setStyle(SkPaint::kFill_Style);
paint.setShader(shader.get());
@@ -423,6 +477,8 @@ void SoftwareRenderer::DrawTileQuad(const DrawingFrame* frame,
ResourceProvider::ScopedReadLockSoftware lock(resource_provider_,
quad->resource_id);
+ if (!lock.valid())
+ return;
DCHECK_EQ(GL_CLAMP_TO_EDGE, lock.wrap_mode());
gfx::RectF visible_tex_coord_rect = MathUtil::ScaleRectProportional(
@@ -431,7 +487,7 @@ void SoftwareRenderer::DrawTileQuad(const DrawingFrame* frame,
QuadVertexRect(), quad->rect, quad->visible_rect);
SkRect uv_rect = gfx::RectFToSkRect(visible_tex_coord_rect);
- current_paint_.setFilterBitmap(true);
+ current_paint_.setFilterLevel(SkPaint::kLow_FilterLevel);
current_canvas_->drawBitmapRectToRect(
*lock.sk_bitmap(),
&uv_rect,
@@ -449,6 +505,8 @@ void SoftwareRenderer::DrawRenderPassQuad(const DrawingFrame* frame,
DCHECK(IsSoftwareResource(content_texture->id()));
ResourceProvider::ScopedReadLockSoftware lock(resource_provider_,
content_texture->id());
+ if (!lock.valid())
+ return;
SkShader::TileMode content_tile_mode = WrapModeToTileMode(lock.wrap_mode());
SkRect dest_rect = gfx::RectFToSkRect(QuadVertexRect());
@@ -472,38 +530,35 @@ void SoftwareRenderer::DrawRenderPassQuad(const DrawingFrame* frame,
// TODO(ajuma): Apply the filter in the same pass as the content where
// possible (e.g. when there's no origin offset). See crbug.com/308201.
if (filter) {
- bool is_opaque = false;
- skia::RefPtr<SkBaseDevice> device =
- skia::AdoptRef(new SkBitmapDevice(SkBitmap::kARGB_8888_Config,
- content_texture->size().width(),
- content_texture->size().height(),
- is_opaque));
- SkCanvas canvas(device.get());
- SkPaint paint;
- paint.setImageFilter(filter.get());
- canvas.clear(SK_ColorTRANSPARENT);
- canvas.translate(SkIntToScalar(-quad->rect.origin().x()),
- SkIntToScalar(-quad->rect.origin().y()));
- canvas.drawSprite(*content, 0, 0, &paint);
- bool will_change_pixels = false;
- filter_bitmap = device->accessBitmap(will_change_pixels);
+ SkImageInfo info = SkImageInfo::MakeN32Premul(
+ content_texture->size().width(), content_texture->size().height());
+ if (filter_bitmap.allocPixels(info)) {
+ SkCanvas canvas(filter_bitmap);
+ SkPaint paint;
+ paint.setImageFilter(filter.get());
+ canvas.clear(SK_ColorTRANSPARENT);
+ canvas.translate(SkIntToScalar(-quad->rect.origin().x()),
+ SkIntToScalar(-quad->rect.origin().y()));
+ canvas.drawSprite(*content, 0, 0, &paint);
+ }
}
}
skia::RefPtr<SkShader> shader;
if (filter_bitmap.isNull()) {
shader = skia::AdoptRef(SkShader::CreateBitmapShader(
- *content, content_tile_mode, content_tile_mode));
+ *content, content_tile_mode, content_tile_mode, &content_mat));
} else {
shader = skia::AdoptRef(SkShader::CreateBitmapShader(
- filter_bitmap, content_tile_mode, content_tile_mode));
+ filter_bitmap, content_tile_mode, content_tile_mode, &content_mat));
}
- shader->setLocalMatrix(content_mat);
current_paint_.setShader(shader.get());
if (quad->mask_resource_id) {
ResourceProvider::ScopedReadLockSoftware mask_lock(resource_provider_,
quad->mask_resource_id);
+ if (!lock.valid())
+ return;
SkShader::TileMode mask_tile_mode = WrapModeToTileMode(
mask_lock.wrap_mode());
@@ -518,16 +573,18 @@ void SoftwareRenderer::DrawRenderPassQuad(const DrawingFrame* frame,
SkMatrix mask_mat;
mask_mat.setRectToRect(mask_rect, dest_rect, SkMatrix::kFill_ScaleToFit);
- skia::RefPtr<SkShader> mask_shader = skia::AdoptRef(
- SkShader::CreateBitmapShader(*mask, mask_tile_mode, mask_tile_mode));
- mask_shader->setLocalMatrix(mask_mat);
+ skia::RefPtr<SkShader> mask_shader =
+ skia::AdoptRef(SkShader::CreateBitmapShader(
+ *mask, mask_tile_mode, mask_tile_mode, &mask_mat));
SkPaint mask_paint;
mask_paint.setShader(mask_shader.get());
+ SkLayerRasterizer::Builder builder;
+ builder.addLayer(mask_paint);
+
skia::RefPtr<SkLayerRasterizer> mask_rasterizer =
- skia::AdoptRef(new SkLayerRasterizer);
- mask_rasterizer->addLayer(mask_paint);
+ skia::AdoptRef(builder.detachRasterizer());
current_paint_.setRasterizer(mask_rasterizer.get());
current_canvas_->drawRect(dest_visible_rect, current_paint_);
@@ -587,22 +644,8 @@ void SoftwareRenderer::EnsureBackbuffer() {
is_backbuffer_discarded_ = false;
}
-void SoftwareRenderer::GetFramebufferPixels(void* pixels, gfx::Rect rect) {
- TRACE_EVENT0("cc", "SoftwareRenderer::GetFramebufferPixels");
- SkBitmap subset_bitmap;
- rect += current_viewport_rect_.OffsetFromOrigin();
- output_device_->CopyToBitmap(rect, &subset_bitmap);
- subset_bitmap.copyPixelsTo(pixels,
- 4 * rect.width() * rect.height(),
- 4 * rect.width());
-}
-
-void SoftwareRenderer::SetVisible(bool visible) {
- if (visible_ == visible)
- return;
- visible_ = visible;
-
- if (visible_)
+void SoftwareRenderer::DidChangeVisibility() {
+ if (visible())
EnsureBackbuffer();
else
DiscardBackbuffer();
diff --git a/chromium/cc/output/software_renderer.h b/chromium/cc/output/software_renderer.h
index 18fb2a3fc33..5c9fef0ba57 100644
--- a/chromium/cc/output/software_renderer.h
+++ b/chromium/cc/output/software_renderer.h
@@ -34,15 +34,9 @@ class CC_EXPORT SoftwareRenderer : public DirectRenderer {
ResourceProvider* resource_provider);
virtual ~SoftwareRenderer();
- virtual const RendererCapabilities& Capabilities() const OVERRIDE;
+ virtual const RendererCapabilitiesImpl& Capabilities() const OVERRIDE;
virtual void Finish() OVERRIDE;
virtual void SwapBuffers(const CompositorFrameMetadata& metadata) OVERRIDE;
- virtual void GetFramebufferPixels(void* pixels, gfx::Rect rect) OVERRIDE;
- virtual void SetVisible(bool visible) OVERRIDE;
- virtual void SendManagedMemoryStats(
- size_t bytes_visible,
- size_t bytes_visible_and_nearby,
- size_t bytes_allocated) OVERRIDE {}
virtual void ReceiveSwapBuffersAck(
const CompositorFrameAck& ack) OVERRIDE;
virtual void DiscardBackbuffer() OVERRIDE;
@@ -53,9 +47,9 @@ class CC_EXPORT SoftwareRenderer : public DirectRenderer {
virtual bool BindFramebufferToTexture(
DrawingFrame* frame,
const ScopedResource* texture,
- gfx::Rect target_rect) OVERRIDE;
- virtual void SetDrawViewport(gfx::Rect window_space_viewport) OVERRIDE;
- virtual void SetScissorTestRect(gfx::Rect scissor_rect) OVERRIDE;
+ const gfx::Rect& target_rect) OVERRIDE;
+ virtual void SetDrawViewport(const gfx::Rect& window_space_viewport) OVERRIDE;
+ virtual void SetScissorTestRect(const gfx::Rect& scissor_rect) OVERRIDE;
virtual void DiscardPixels(bool has_external_stencil_test,
bool draw_rect_covers_full_surface) OVERRIDE;
virtual void ClearFramebuffer(DrawingFrame* frame,
@@ -75,9 +69,11 @@ class CC_EXPORT SoftwareRenderer : public DirectRenderer {
OutputSurface* output_surface,
ResourceProvider* resource_provider);
+ virtual void DidChangeVisibility() OVERRIDE;
+
private:
void ClearCanvas(SkColor color);
- void SetClipRect(gfx::Rect rect);
+ void SetClipRect(const gfx::Rect& rect);
bool IsSoftwareResource(ResourceProvider::ResourceId resource_id) const;
void DrawCheckerboardQuad(const DrawingFrame* frame,
@@ -97,8 +93,7 @@ class CC_EXPORT SoftwareRenderer : public DirectRenderer {
void DrawUnsupportedQuad(const DrawingFrame* frame,
const DrawQuad* quad);
- RendererCapabilities capabilities_;
- bool visible_;
+ RendererCapabilitiesImpl capabilities_;
bool is_scissor_enabled_;
bool is_backbuffer_discarded_;
gfx::Rect scissor_rect_;
diff --git a/chromium/cc/output/software_renderer_unittest.cc b/chromium/cc/output/software_renderer_unittest.cc
index fc1c7070cb4..536b2ef168b 100644
--- a/chromium/cc/output/software_renderer_unittest.cc
+++ b/chromium/cc/output/software_renderer_unittest.cc
@@ -4,8 +4,11 @@
#include "cc/output/software_renderer.h"
+#include "base/run_loop.h"
#include "cc/layers/quad_sink.h"
#include "cc/output/compositor_frame_metadata.h"
+#include "cc/output/copy_output_request.h"
+#include "cc/output/copy_output_result.h"
#include "cc/output/software_output_device.h"
#include "cc/quads/render_pass.h"
#include "cc/quads/render_pass_draw_quad.h"
@@ -17,10 +20,10 @@
#include "cc/test/geometry_test_utils.h"
#include "cc/test/render_pass_test_common.h"
#include "cc/test/render_pass_test_utils.h"
+#include "cc/test/test_shared_bitmap_manager.h"
#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/core/SkDevice.h"
namespace cc {
namespace {
@@ -33,8 +36,10 @@ class SoftwareRendererTest : public testing::Test, public RendererClient {
software_output_device.Pass());
CHECK(output_surface_->BindToClient(&output_surface_client_));
- resource_provider_ =
- ResourceProvider::Create(output_surface_.get(), NULL, 0, false, 1);
+ shared_bitmap_manager_.reset(new TestSharedBitmapManager());
+ resource_provider_ = ResourceProvider::Create(
+ output_surface_.get(), shared_bitmap_manager_.get(), 0, false, 1,
+ false);
renderer_ = SoftwareRenderer::Create(
this, &settings_, output_surface_.get(), resource_provider());
}
@@ -47,11 +52,42 @@ class SoftwareRendererTest : public testing::Test, public RendererClient {
// RendererClient implementation.
virtual void SetFullRootLayerDamage() OVERRIDE {}
+ virtual void RunOnDemandRasterTask(Task* on_demand_raster_task) OVERRIDE {}
+
+ scoped_ptr<SkBitmap> DrawAndCopyOutput(RenderPassList* list,
+ float device_scale_factor,
+ gfx::Rect device_viewport_rect) {
+ scoped_ptr<SkBitmap> bitmap_result;
+ base::RunLoop loop;
+
+ list->back()->copy_requests.push_back(
+ CopyOutputRequest::CreateBitmapRequest(
+ base::Bind(&SoftwareRendererTest::SaveBitmapResult,
+ base::Unretained(&bitmap_result),
+ loop.QuitClosure())));
+
+ renderer()->DrawFrame(list,
+ device_scale_factor,
+ device_viewport_rect,
+ device_viewport_rect,
+ false);
+ loop.Run();
+ return bitmap_result.Pass();
+ }
+
+ static void SaveBitmapResult(scoped_ptr<SkBitmap>* bitmap_result,
+ const base::Closure& quit_closure,
+ scoped_ptr<CopyOutputResult> result) {
+ DCHECK(result->HasBitmap());
+ *bitmap_result = result->TakeBitmap();
+ quit_closure.Run();
+ }
protected:
LayerTreeSettings settings_;
FakeOutputSurfaceClient output_surface_client_;
scoped_ptr<FakeOutputSurface> output_surface_;
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager_;
scoped_ptr<ResourceProvider> resource_provider_;
scoped_ptr<SoftwareRenderer> renderer_;
};
@@ -65,23 +101,26 @@ TEST_F(SoftwareRendererTest, SolidColorQuad) {
InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice));
- scoped_ptr<SharedQuadState> shared_quad_state = SharedQuadState::Create();
+ RenderPass::Id root_render_pass_id = RenderPass::Id(1, 1);
+ scoped_ptr<TestRenderPass> root_render_pass = TestRenderPass::Create();
+ root_render_pass->SetNew(
+ root_render_pass_id, outer_rect, outer_rect, gfx::Transform());
+ SharedQuadState* shared_quad_state =
+ root_render_pass->CreateAndAppendSharedQuadState();
shared_quad_state->SetAll(gfx::Transform(),
outer_size,
outer_rect,
outer_rect,
false,
1.0,
- SkXfermode::kSrcOver_Mode);
- RenderPass::Id root_render_pass_id = RenderPass::Id(1, 1);
- scoped_ptr<TestRenderPass> root_render_pass = TestRenderPass::Create();
- root_render_pass->SetNew(
- root_render_pass_id, outer_rect, outer_rect, gfx::Transform());
+ SkXfermode::kSrcOver_Mode,
+ 0);
scoped_ptr<SolidColorDrawQuad> outer_quad = SolidColorDrawQuad::Create();
outer_quad->SetNew(
- shared_quad_state.get(), outer_rect, SK_ColorYELLOW, false);
+ shared_quad_state, outer_rect, outer_rect, SK_ColorYELLOW, false);
scoped_ptr<SolidColorDrawQuad> inner_quad = SolidColorDrawQuad::Create();
- inner_quad->SetNew(shared_quad_state.get(), inner_rect, SK_ColorCYAN, false);
+ inner_quad->SetNew(
+ shared_quad_state, inner_rect, inner_rect, SK_ColorCYAN, false);
inner_quad->visible_rect = visible_rect;
root_render_pass->AppendQuad(inner_quad.PassAs<DrawQuad>());
root_render_pass->AppendQuad(outer_quad.PassAs<DrawQuad>());
@@ -91,27 +130,18 @@ TEST_F(SoftwareRendererTest, SolidColorQuad) {
float device_scale_factor = 1.f;
gfx::Rect device_viewport_rect(outer_size);
- renderer()->DrawFrame(&list,
- NULL,
- device_scale_factor,
- device_viewport_rect,
- device_viewport_rect,
- true,
- false);
-
- SkBitmap output;
- output.setConfig(
- SkBitmap::kARGB_8888_Config, outer_rect.width(), outer_rect.height());
- output.allocPixels();
- renderer()->GetFramebufferPixels(output.getPixels(), outer_rect);
-
- EXPECT_EQ(SK_ColorYELLOW, output.getColor(0, 0));
+ scoped_ptr<SkBitmap> output =
+ DrawAndCopyOutput(&list, device_scale_factor, device_viewport_rect);
+ EXPECT_EQ(outer_rect.width(), output->info().fWidth);
+ EXPECT_EQ(outer_rect.width(), output->info().fHeight);
+
+ EXPECT_EQ(SK_ColorYELLOW, output->getColor(0, 0));
EXPECT_EQ(SK_ColorYELLOW,
- output.getColor(outer_size.width() - 1, outer_size.height() - 1));
- EXPECT_EQ(SK_ColorYELLOW, output.getColor(1, 1));
- EXPECT_EQ(SK_ColorCYAN, output.getColor(1, 2));
+ output->getColor(outer_size.width() - 1, outer_size.height() - 1));
+ EXPECT_EQ(SK_ColorYELLOW, output->getColor(1, 1));
+ EXPECT_EQ(SK_ColorCYAN, output->getColor(1, 2));
EXPECT_EQ(SK_ColorCYAN,
- output.getColor(inner_size.width() - 1, inner_size.height() - 1));
+ output->getColor(inner_size.width() - 1, inner_size.height() - 1));
}
TEST_F(SoftwareRendererTest, TileQuad) {
@@ -158,20 +188,23 @@ TEST_F(SoftwareRendererTest, TileQuad) {
gfx::Rect root_rect = outer_rect;
- scoped_ptr<SharedQuadState> shared_quad_state = SharedQuadState::Create();
+ RenderPass::Id root_render_pass_id = RenderPass::Id(1, 1);
+ scoped_ptr<TestRenderPass> root_render_pass = TestRenderPass::Create();
+ root_render_pass->SetNew(
+ root_render_pass_id, root_rect, root_rect, gfx::Transform());
+ SharedQuadState* shared_quad_state =
+ root_render_pass->CreateAndAppendSharedQuadState();
shared_quad_state->SetAll(gfx::Transform(),
outer_size,
outer_rect,
outer_rect,
false,
1.0,
- SkXfermode::kSrcOver_Mode);
- RenderPass::Id root_render_pass_id = RenderPass::Id(1, 1);
- scoped_ptr<TestRenderPass> root_render_pass = TestRenderPass::Create();
- root_render_pass->SetNew(
- root_render_pass_id, root_rect, root_rect, gfx::Transform());
+ SkXfermode::kSrcOver_Mode,
+ 0);
scoped_ptr<TileDrawQuad> outer_quad = TileDrawQuad::Create();
- outer_quad->SetNew(shared_quad_state.get(),
+ outer_quad->SetNew(shared_quad_state,
+ outer_rect,
outer_rect,
outer_rect,
resource_yellow,
@@ -179,7 +212,8 @@ TEST_F(SoftwareRendererTest, TileQuad) {
outer_size,
false);
scoped_ptr<TileDrawQuad> inner_quad = TileDrawQuad::Create();
- inner_quad->SetNew(shared_quad_state.get(),
+ inner_quad->SetNew(shared_quad_state,
+ inner_rect,
inner_rect,
inner_rect,
resource_cyan,
@@ -194,26 +228,17 @@ TEST_F(SoftwareRendererTest, TileQuad) {
float device_scale_factor = 1.f;
gfx::Rect device_viewport_rect(outer_size);
- renderer()->DrawFrame(&list,
- NULL,
- device_scale_factor,
- device_viewport_rect,
- device_viewport_rect,
- true,
- false);
-
- SkBitmap output;
- output.setConfig(
- SkBitmap::kARGB_8888_Config, outer_size.width(), outer_size.height());
- output.allocPixels();
- renderer()->GetFramebufferPixels(output.getPixels(), outer_rect);
+ scoped_ptr<SkBitmap> output =
+ DrawAndCopyOutput(&list, device_scale_factor, device_viewport_rect);
+ EXPECT_EQ(outer_rect.width(), output->info().fWidth);
+ EXPECT_EQ(outer_rect.width(), output->info().fHeight);
- EXPECT_EQ(SK_ColorYELLOW, output.getColor(0, 0));
+ EXPECT_EQ(SK_ColorYELLOW, output->getColor(0, 0));
EXPECT_EQ(SK_ColorYELLOW,
- output.getColor(outer_size.width() - 1, outer_size.height() - 1));
- EXPECT_EQ(SK_ColorCYAN, output.getColor(1, 1));
+ output->getColor(outer_size.width() - 1, outer_size.height() - 1));
+ EXPECT_EQ(SK_ColorCYAN, output->getColor(1, 1));
EXPECT_EQ(SK_ColorCYAN,
- output.getColor(inner_size.width() - 1, inner_size.height() - 1));
+ output->getColor(inner_size.width() - 1, inner_size.height() - 1));
}
TEST_F(SoftwareRendererTest, TileQuadVisibleRect) {
@@ -247,20 +272,23 @@ TEST_F(SoftwareRendererTest, TileQuadVisibleRect) {
gfx::Rect root_rect(tile_size);
- scoped_ptr<SharedQuadState> shared_quad_state = SharedQuadState::Create();
+ RenderPass::Id root_render_pass_id = RenderPass::Id(1, 1);
+ scoped_ptr<TestRenderPass> root_render_pass = TestRenderPass::Create();
+ root_render_pass->SetNew(
+ root_render_pass_id, root_rect, root_rect, gfx::Transform());
+ SharedQuadState* shared_quad_state =
+ root_render_pass->CreateAndAppendSharedQuadState();
shared_quad_state->SetAll(gfx::Transform(),
tile_size,
tile_rect,
tile_rect,
false,
1.0,
- SkXfermode::kSrcOver_Mode);
- RenderPass::Id root_render_pass_id = RenderPass::Id(1, 1);
- scoped_ptr<TestRenderPass> root_render_pass = TestRenderPass::Create();
- root_render_pass->SetNew(
- root_render_pass_id, root_rect, root_rect, gfx::Transform());
+ SkXfermode::kSrcOver_Mode,
+ 0);
scoped_ptr<TileDrawQuad> quad = TileDrawQuad::Create();
- quad->SetNew(shared_quad_state.get(),
+ quad->SetNew(shared_quad_state,
+ tile_rect,
tile_rect,
tile_rect,
resource_cyan,
@@ -275,74 +303,57 @@ TEST_F(SoftwareRendererTest, TileQuadVisibleRect) {
float device_scale_factor = 1.f;
gfx::Rect device_viewport_rect(tile_size);
- renderer()->DrawFrame(&list,
- NULL,
- device_scale_factor,
- device_viewport_rect,
- device_viewport_rect,
- true,
- false);
-
- SkBitmap output;
- output.setConfig(
- SkBitmap::kARGB_8888_Config, tile_size.width(), tile_size.height());
- output.allocPixels();
- renderer()->GetFramebufferPixels(output.getPixels(), tile_rect);
+ scoped_ptr<SkBitmap> output =
+ DrawAndCopyOutput(&list, device_scale_factor, device_viewport_rect);
+ EXPECT_EQ(tile_rect.width(), output->info().fWidth);
+ EXPECT_EQ(tile_rect.width(), output->info().fHeight);
// Check portion of tile not in visible rect isn't drawn.
const unsigned int kTransparent = SK_ColorTRANSPARENT;
- EXPECT_EQ(kTransparent, output.getColor(0, 0));
+ EXPECT_EQ(kTransparent, output->getColor(0, 0));
EXPECT_EQ(kTransparent,
- output.getColor(tile_rect.width() - 1, tile_rect.height() - 1));
+ output->getColor(tile_rect.width() - 1, tile_rect.height() - 1));
EXPECT_EQ(kTransparent,
- output.getColor(visible_rect.x() - 1, visible_rect.y() - 1));
+ output->getColor(visible_rect.x() - 1, visible_rect.y() - 1));
EXPECT_EQ(kTransparent,
- output.getColor(visible_rect.right(), visible_rect.bottom()));
+ output->getColor(visible_rect.right(), visible_rect.bottom()));
// Ensure visible part is drawn correctly.
- EXPECT_EQ(SK_ColorCYAN, output.getColor(visible_rect.x(), visible_rect.y()));
+ EXPECT_EQ(SK_ColorCYAN, output->getColor(visible_rect.x(), visible_rect.y()));
EXPECT_EQ(
SK_ColorCYAN,
- output.getColor(visible_rect.right() - 2, visible_rect.bottom() - 2));
+ output->getColor(visible_rect.right() - 2, visible_rect.bottom() - 2));
// Ensure last visible line is correct.
EXPECT_EQ(
SK_ColorYELLOW,
- output.getColor(visible_rect.right() - 1, visible_rect.bottom() - 1));
+ output->getColor(visible_rect.right() - 1, visible_rect.bottom() - 1));
}
TEST_F(SoftwareRendererTest, ShouldClearRootRenderPass) {
float device_scale_factor = 1.f;
- gfx::Rect viewport_rect(0, 0, 100, 100);
+ gfx::Rect device_viewport_rect(0, 0, 100, 100);
settings_.should_clear_root_render_pass = false;
InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice));
RenderPassList list;
- SkBitmap output;
- output.setConfig(SkBitmap::kARGB_8888_Config,
- viewport_rect.width(),
- viewport_rect.height());
- output.allocPixels();
-
// Draw a fullscreen green quad in a first frame.
RenderPass::Id root_clear_pass_id(1, 0);
TestRenderPass* root_clear_pass = AddRenderPass(
- &list, root_clear_pass_id, viewport_rect, gfx::Transform());
- AddQuad(root_clear_pass, viewport_rect, SK_ColorGREEN);
+ &list, root_clear_pass_id, device_viewport_rect, gfx::Transform());
+ AddQuad(root_clear_pass, device_viewport_rect, SK_ColorGREEN);
renderer()->DecideRenderPassAllocationsForFrame(list);
- renderer()->DrawFrame(&list,
- NULL,
- device_scale_factor,
- viewport_rect,
- viewport_rect,
- true,
- false);
- renderer()->GetFramebufferPixels(output.getPixels(), viewport_rect);
-
- EXPECT_EQ(SK_ColorGREEN, output.getColor(0, 0));
+
+ scoped_ptr<SkBitmap> output =
+ DrawAndCopyOutput(&list, device_scale_factor, device_viewport_rect);
+ EXPECT_EQ(device_viewport_rect.width(), output->info().fWidth);
+ EXPECT_EQ(device_viewport_rect.width(), output->info().fHeight);
+
+ EXPECT_EQ(SK_ColorGREEN, output->getColor(0, 0));
EXPECT_EQ(SK_ColorGREEN,
- output.getColor(viewport_rect.width() - 1, viewport_rect.height() - 1));
+ output->getColor(device_viewport_rect.width() - 1,
+ device_viewport_rect.height() - 1));
list.clear();
@@ -352,43 +363,35 @@ TEST_F(SoftwareRendererTest, ShouldClearRootRenderPass) {
RenderPass::Id root_smaller_pass_id(2, 0);
TestRenderPass* root_smaller_pass = AddRenderPass(
- &list, root_smaller_pass_id, viewport_rect, gfx::Transform());
+ &list, root_smaller_pass_id, device_viewport_rect, gfx::Transform());
AddQuad(root_smaller_pass, smaller_rect, SK_ColorMAGENTA);
renderer()->DecideRenderPassAllocationsForFrame(list);
- renderer()->DrawFrame(&list,
- NULL,
- device_scale_factor,
- viewport_rect,
- viewport_rect,
- true,
- false);
- renderer()->GetFramebufferPixels(output.getPixels(), viewport_rect);
+
+ output = DrawAndCopyOutput(&list, device_scale_factor, device_viewport_rect);
+ EXPECT_EQ(device_viewport_rect.width(), output->info().fWidth);
+ EXPECT_EQ(device_viewport_rect.width(), output->info().fHeight);
// If we didn't clear, the borders should still be green.
- EXPECT_EQ(SK_ColorGREEN, output.getColor(0, 0));
+ EXPECT_EQ(SK_ColorGREEN, output->getColor(0, 0));
EXPECT_EQ(SK_ColorGREEN,
- output.getColor(viewport_rect.width() - 1, viewport_rect.height() - 1));
+ output->getColor(device_viewport_rect.width() - 1,
+ device_viewport_rect.height() - 1));
EXPECT_EQ(SK_ColorMAGENTA,
- output.getColor(smaller_rect.x(), smaller_rect.y()));
- EXPECT_EQ(SK_ColorMAGENTA,
- output.getColor(smaller_rect.right() - 1, smaller_rect.bottom() - 1));
+ output->getColor(smaller_rect.x(), smaller_rect.y()));
+ EXPECT_EQ(
+ SK_ColorMAGENTA,
+ output->getColor(smaller_rect.right() - 1, smaller_rect.bottom() - 1));
}
TEST_F(SoftwareRendererTest, RenderPassVisibleRect) {
float device_scale_factor = 1.f;
- gfx::Rect viewport_rect(0, 0, 100, 100);
+ gfx::Rect device_viewport_rect(0, 0, 100, 100);
InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice));
RenderPassList list;
- SkBitmap output;
- output.setConfig(SkBitmap::kARGB_8888_Config,
- viewport_rect.width(),
- viewport_rect.height());
- output.allocPixels();
-
// Pass drawn as inner quad is magenta.
gfx::Rect smaller_rect(20, 20, 60, 60);
RenderPass::Id smaller_pass_id(2, 1);
@@ -398,42 +401,40 @@ TEST_F(SoftwareRendererTest, RenderPassVisibleRect) {
// Root pass is green.
RenderPass::Id root_clear_pass_id(1, 0);
- TestRenderPass* root_clear_pass =
- AddRenderPass(&list, root_clear_pass_id, viewport_rect, gfx::Transform());
+ TestRenderPass* root_clear_pass = AddRenderPass(
+ &list, root_clear_pass_id, device_viewport_rect, gfx::Transform());
AddRenderPassQuad(root_clear_pass, smaller_pass);
- AddQuad(root_clear_pass, viewport_rect, SK_ColorGREEN);
+ AddQuad(root_clear_pass, device_viewport_rect, SK_ColorGREEN);
// Interior pass quad has smaller visible rect.
gfx::Rect interior_visible_rect(30, 30, 40, 40);
root_clear_pass->quad_list[0]->visible_rect = interior_visible_rect;
renderer()->DecideRenderPassAllocationsForFrame(list);
- renderer()->DrawFrame(&list,
- NULL,
- device_scale_factor,
- viewport_rect,
- viewport_rect,
- true,
- false);
- renderer()->GetFramebufferPixels(output.getPixels(), viewport_rect);
-
- EXPECT_EQ(SK_ColorGREEN, output.getColor(0, 0));
- EXPECT_EQ(
- SK_ColorGREEN,
- output.getColor(viewport_rect.width() - 1, viewport_rect.height() - 1));
+
+ scoped_ptr<SkBitmap> output =
+ DrawAndCopyOutput(&list, device_scale_factor, device_viewport_rect);
+ EXPECT_EQ(device_viewport_rect.width(), output->info().fWidth);
+ EXPECT_EQ(device_viewport_rect.width(), output->info().fHeight);
+
+ EXPECT_EQ(SK_ColorGREEN, output->getColor(0, 0));
+ EXPECT_EQ(SK_ColorGREEN,
+ output->getColor(device_viewport_rect.width() - 1,
+ device_viewport_rect.height() - 1));
// Part outside visible rect should remain green.
- EXPECT_EQ(SK_ColorGREEN, output.getColor(smaller_rect.x(), smaller_rect.y()));
+ EXPECT_EQ(SK_ColorGREEN,
+ output->getColor(smaller_rect.x(), smaller_rect.y()));
EXPECT_EQ(
SK_ColorGREEN,
- output.getColor(smaller_rect.right() - 1, smaller_rect.bottom() - 1));
+ output->getColor(smaller_rect.right() - 1, smaller_rect.bottom() - 1));
EXPECT_EQ(
SK_ColorMAGENTA,
- output.getColor(interior_visible_rect.x(), interior_visible_rect.y()));
+ output->getColor(interior_visible_rect.x(), interior_visible_rect.y()));
EXPECT_EQ(SK_ColorMAGENTA,
- output.getColor(interior_visible_rect.right() - 1,
- interior_visible_rect.bottom() - 1));
+ output->getColor(interior_visible_rect.right() - 1,
+ interior_visible_rect.bottom() - 1));
}
} // namespace
diff --git a/chromium/cc/quads/checkerboard_draw_quad.cc b/chromium/cc/quads/checkerboard_draw_quad.cc
index 5e17d885f48..921a553b2c2 100644
--- a/chromium/cc/quads/checkerboard_draw_quad.cc
+++ b/chromium/cc/quads/checkerboard_draw_quad.cc
@@ -16,10 +16,10 @@ scoped_ptr<CheckerboardDrawQuad> CheckerboardDrawQuad::Create() {
}
void CheckerboardDrawQuad::SetNew(const SharedQuadState* shared_quad_state,
- gfx::Rect rect,
+ const gfx::Rect& rect,
+ const gfx::Rect& visible_rect,
SkColor color) {
gfx::Rect opaque_rect = SkColorGetA(color) == 255 ? rect : gfx::Rect();
- gfx::Rect visible_rect = rect;
bool needs_blending = false;
DrawQuad::SetAll(shared_quad_state, DrawQuad::CHECKERBOARD, rect, opaque_rect,
visible_rect, needs_blending);
@@ -27,9 +27,9 @@ void CheckerboardDrawQuad::SetNew(const SharedQuadState* shared_quad_state,
}
void CheckerboardDrawQuad::SetAll(const SharedQuadState* shared_quad_state,
- gfx::Rect rect,
- gfx::Rect opaque_rect,
- gfx::Rect visible_rect,
+ const gfx::Rect& rect,
+ const gfx::Rect& opaque_rect,
+ const gfx::Rect& visible_rect,
bool needs_blending,
SkColor color) {
DrawQuad::SetAll(shared_quad_state, DrawQuad::CHECKERBOARD, rect, opaque_rect,
diff --git a/chromium/cc/quads/checkerboard_draw_quad.h b/chromium/cc/quads/checkerboard_draw_quad.h
index 4f7452eb0a6..d59e53f912e 100644
--- a/chromium/cc/quads/checkerboard_draw_quad.h
+++ b/chromium/cc/quads/checkerboard_draw_quad.h
@@ -17,13 +17,14 @@ class CC_EXPORT CheckerboardDrawQuad : public DrawQuad {
static scoped_ptr<CheckerboardDrawQuad> Create();
void SetNew(const SharedQuadState* shared_quad_state,
- gfx::Rect rect,
+ const gfx::Rect& rect,
+ const gfx::Rect& visible_rect,
SkColor color);
void SetAll(const SharedQuadState* shared_quad_state,
- gfx::Rect rect,
- gfx::Rect opaque_rect,
- gfx::Rect visible_rect,
+ const gfx::Rect& rect,
+ const gfx::Rect& opaque_rect,
+ const gfx::Rect& visible_rect,
bool needs_blending,
SkColor color);
diff --git a/chromium/cc/quads/content_draw_quad_base.cc b/chromium/cc/quads/content_draw_quad_base.cc
index 947af0b2d94..18d3d10c34a 100644
--- a/chromium/cc/quads/content_draw_quad_base.cc
+++ b/chromium/cc/quads/content_draw_quad_base.cc
@@ -19,12 +19,12 @@ ContentDrawQuadBase::~ContentDrawQuadBase() {
void ContentDrawQuadBase::SetNew(const SharedQuadState* shared_quad_state,
DrawQuad::Material material,
- gfx::Rect rect,
- gfx::Rect opaque_rect,
+ const gfx::Rect& rect,
+ const gfx::Rect& opaque_rect,
+ const gfx::Rect& visible_rect,
const gfx::RectF& tex_coord_rect,
- gfx::Size texture_size,
+ const gfx::Size& texture_size,
bool swizzle_contents) {
- gfx::Rect visible_rect = rect;
bool needs_blending = false;
DrawQuad::SetAll(shared_quad_state, material, rect, opaque_rect,
visible_rect, needs_blending);
@@ -35,12 +35,12 @@ void ContentDrawQuadBase::SetNew(const SharedQuadState* shared_quad_state,
void ContentDrawQuadBase::SetAll(const SharedQuadState* shared_quad_state,
DrawQuad::Material material,
- gfx::Rect rect,
- gfx::Rect opaque_rect,
- gfx::Rect visible_rect,
+ const gfx::Rect& rect,
+ const gfx::Rect& opaque_rect,
+ const gfx::Rect& visible_rect,
bool needs_blending,
const gfx::RectF& tex_coord_rect,
- gfx::Size texture_size,
+ const gfx::Size& texture_size,
bool swizzle_contents) {
DrawQuad::SetAll(shared_quad_state, material, rect, opaque_rect,
visible_rect, needs_blending);
diff --git a/chromium/cc/quads/content_draw_quad_base.h b/chromium/cc/quads/content_draw_quad_base.h
index cbf18ca2b15..a286e100861 100644
--- a/chromium/cc/quads/content_draw_quad_base.h
+++ b/chromium/cc/quads/content_draw_quad_base.h
@@ -18,20 +18,21 @@ class CC_EXPORT ContentDrawQuadBase : public DrawQuad {
public:
void SetNew(const SharedQuadState* shared_quad_state,
DrawQuad::Material material,
- gfx::Rect rect,
- gfx::Rect opaque_rect,
+ const gfx::Rect& rect,
+ const gfx::Rect& opaque_rect,
+ const gfx::Rect& visible_rect,
const gfx::RectF& tex_coord_rect,
- gfx::Size texture_size,
+ const gfx::Size& texture_size,
bool swizzle_contents);
void SetAll(const SharedQuadState* shared_quad_state,
DrawQuad::Material material,
- gfx::Rect rect,
- gfx::Rect opaque_rect,
- gfx::Rect visible_rect,
+ const gfx::Rect& rect,
+ const gfx::Rect& opaque_rect,
+ const gfx::Rect& visible_rect,
bool needs_blending,
const gfx::RectF& tex_coord_rect,
- gfx::Size texture_size,
+ const gfx::Size& texture_size,
bool swizzle_contents);
gfx::RectF tex_coord_rect;
diff --git a/chromium/cc/quads/debug_border_draw_quad.cc b/chromium/cc/quads/debug_border_draw_quad.cc
index 89ee8e01281..9c575aada19 100644
--- a/chromium/cc/quads/debug_border_draw_quad.cc
+++ b/chromium/cc/quads/debug_border_draw_quad.cc
@@ -19,11 +19,11 @@ scoped_ptr<DebugBorderDrawQuad> DebugBorderDrawQuad::Create() {
}
void DebugBorderDrawQuad::SetNew(const SharedQuadState* shared_quad_state,
- gfx::Rect rect,
+ const gfx::Rect& rect,
+ const gfx::Rect& visible_rect,
SkColor color,
int width) {
gfx::Rect opaque_rect;
- gfx::Rect visible_rect = rect;
bool needs_blending = SkColorGetA(color) < 255;
DrawQuad::SetAll(shared_quad_state, DrawQuad::DEBUG_BORDER, rect, opaque_rect,
visible_rect, needs_blending);
@@ -32,9 +32,9 @@ void DebugBorderDrawQuad::SetNew(const SharedQuadState* shared_quad_state,
}
void DebugBorderDrawQuad::SetAll(const SharedQuadState* shared_quad_state,
- gfx::Rect rect,
- gfx::Rect opaque_rect,
- gfx::Rect visible_rect,
+ const gfx::Rect& rect,
+ const gfx::Rect& opaque_rect,
+ const gfx::Rect& visible_rect,
bool needs_blending,
SkColor color,
int width) {
diff --git a/chromium/cc/quads/debug_border_draw_quad.h b/chromium/cc/quads/debug_border_draw_quad.h
index 5b369514b50..2bfccc4b9bc 100644
--- a/chromium/cc/quads/debug_border_draw_quad.h
+++ b/chromium/cc/quads/debug_border_draw_quad.h
@@ -17,14 +17,15 @@ class CC_EXPORT DebugBorderDrawQuad : public DrawQuad {
static scoped_ptr<DebugBorderDrawQuad> Create();
void SetNew(const SharedQuadState* shared_quad_state,
- gfx::Rect rect,
+ const gfx::Rect& rect,
+ const gfx::Rect& visible_rect,
SkColor color,
int width);
void SetAll(const SharedQuadState* shared_quad_state,
- gfx::Rect rect,
- gfx::Rect opaque_rect,
- gfx::Rect visible_rect,
+ const gfx::Rect& rect,
+ const gfx::Rect& opaque_rect,
+ const gfx::Rect& visible_rect,
bool needs_blending,
SkColor color,
int width);
diff --git a/chromium/cc/quads/draw_quad.cc b/chromium/cc/quads/draw_quad.cc
index f3cd8189545..e2d6059a611 100644
--- a/chromium/cc/quads/draw_quad.cc
+++ b/chromium/cc/quads/draw_quad.cc
@@ -15,6 +15,7 @@
#include "cc/quads/render_pass_draw_quad.h"
#include "cc/quads/solid_color_draw_quad.h"
#include "cc/quads/stream_video_draw_quad.h"
+#include "cc/quads/surface_draw_quad.h"
#include "cc/quads/texture_draw_quad.h"
#include "cc/quads/tile_draw_quad.h"
#include "cc/quads/yuv_video_draw_quad.h"
@@ -36,9 +37,9 @@ DrawQuad::DrawQuad()
void DrawQuad::SetAll(const SharedQuadState* shared_quad_state,
Material material,
- gfx::Rect rect,
- gfx::Rect opaque_rect,
- gfx::Rect visible_rect,
+ const gfx::Rect& rect,
+ const gfx::Rect& opaque_rect,
+ const gfx::Rect& visible_rect,
bool needs_blending) {
DCHECK(rect.Contains(visible_rect)) << "rect: " << rect.ToString()
<< " visible_rect: "
@@ -89,6 +90,9 @@ scoped_ptr<DrawQuad> DrawQuad::Copy(
case STREAM_VIDEO_CONTENT:
copy_quad.reset(TypedCopy<StreamVideoDrawQuad>(this));
break;
+ case SURFACE_CONTENT:
+ copy_quad.reset(TypedCopy<SurfaceDrawQuad>(this));
+ break;
case YUV_VIDEO_CONTENT:
copy_quad.reset(TypedCopy<YUVVideoDrawQuad>(this));
break;
diff --git a/chromium/cc/quads/draw_quad.h b/chromium/cc/quads/draw_quad.h
index c3696d6f301..1803eb31013 100644
--- a/chromium/cc/quads/draw_quad.h
+++ b/chromium/cc/quads/draw_quad.h
@@ -37,11 +37,13 @@ class CC_EXPORT DrawQuad {
IO_SURFACE_CONTENT,
PICTURE_CONTENT,
RENDER_PASS,
- TEXTURE_CONTENT,
SOLID_COLOR,
+ STREAM_VIDEO_CONTENT,
+ SURFACE_CONTENT,
+ TEXTURE_CONTENT,
TILED_CONTENT,
YUV_VIDEO_CONTENT,
- STREAM_VIDEO_CONTENT,
+ MATERIAL_LAST = YUV_VIDEO_CONTENT
};
virtual ~DrawQuad();
@@ -131,9 +133,9 @@ class CC_EXPORT DrawQuad {
void SetAll(const SharedQuadState* shared_quad_state,
Material material,
- gfx::Rect rect,
- gfx::Rect opaque_rect,
- gfx::Rect visible_rect,
+ const gfx::Rect& rect,
+ const gfx::Rect& opaque_rect,
+ const gfx::Rect& visible_rect,
bool needs_blending);
virtual void ExtendValue(base::DictionaryValue* value) const = 0;
};
diff --git a/chromium/cc/quads/draw_quad_unittest.cc b/chromium/cc/quads/draw_quad_unittest.cc
index 876c0461b37..f0f77190ffb 100644
--- a/chromium/cc/quads/draw_quad_unittest.cc
+++ b/chromium/cc/quads/draw_quad_unittest.cc
@@ -17,6 +17,7 @@
#include "cc/quads/render_pass_draw_quad.h"
#include "cc/quads/solid_color_draw_quad.h"
#include "cc/quads/stream_video_draw_quad.h"
+#include "cc/quads/surface_draw_quad.h"
#include "cc/quads/texture_draw_quad.h"
#include "cc/quads/tile_draw_quad.h"
#include "cc/quads/yuv_video_draw_quad.h"
@@ -37,17 +38,20 @@ TEST(DrawQuadTest, CopySharedQuadState) {
bool is_clipped = true;
float opacity = 0.25f;
SkXfermode::Mode blend_mode = SkXfermode::kMultiply_Mode;
+ int sorting_context_id = 65536;
- scoped_ptr<SharedQuadState> state(SharedQuadState::Create());
+ scoped_ptr<SharedQuadState> state(new SharedQuadState);
state->SetAll(quad_transform,
content_bounds,
visible_content_rect,
clip_rect,
is_clipped,
opacity,
- blend_mode);
+ blend_mode,
+ sorting_context_id);
- scoped_ptr<SharedQuadState> copy(state->Copy());
+ scoped_ptr<SharedQuadState> copy(new SharedQuadState);
+ copy->CopyFrom(state.get());
EXPECT_EQ(quad_transform, copy->content_to_target_transform);
EXPECT_RECT_EQ(visible_content_rect, copy->visible_content_rect);
EXPECT_EQ(opacity, copy->opacity);
@@ -63,16 +67,18 @@ scoped_ptr<SharedQuadState> CreateSharedQuadState() {
gfx::Rect clip_rect(19, 21, 23, 25);
bool is_clipped = false;
float opacity = 1.f;
+ int sorting_context_id = 65536;
SkXfermode::Mode blend_mode = SkXfermode::kSrcOver_Mode;
- scoped_ptr<SharedQuadState> state(SharedQuadState::Create());
+ scoped_ptr<SharedQuadState> state(new SharedQuadState);
state->SetAll(quad_transform,
content_bounds,
visible_content_rect,
clip_rect,
is_clipped,
opacity,
- blend_mode);
+ blend_mode,
+ sorting_context_id);
return state.Pass();
}
@@ -87,9 +93,10 @@ void CompareDrawQuad(DrawQuad* quad,
EXPECT_EQ(copy_shared_state, copy->shared_quad_state);
}
-#define CREATE_SHARED_STATE() \
- scoped_ptr<SharedQuadState> shared_state(CreateSharedQuadState()); \
- scoped_ptr<SharedQuadState> copy_shared_state(shared_state->Copy()); \
+#define CREATE_SHARED_STATE() \
+ scoped_ptr<SharedQuadState> shared_state(CreateSharedQuadState()); \
+ scoped_ptr<SharedQuadState> copy_shared_state(new SharedQuadState); \
+ copy_shared_state->CopyFrom(shared_state.get());
#define QUAD_DATA \
gfx::Rect quad_rect(30, 40, 50, 60); \
@@ -328,11 +335,13 @@ void CompareDrawQuad(DrawQuad* quad,
SETUP_AND_COPY_QUAD_ALL(Type, quad_all);
TEST(DrawQuadTest, CopyCheckerboardDrawQuad) {
+ gfx::Rect visible_rect(40, 50, 30, 20);
SkColor color = 0xfabb0011;
CREATE_SHARED_STATE();
- CREATE_QUAD_1_NEW(CheckerboardDrawQuad, color);
+ CREATE_QUAD_2_NEW(CheckerboardDrawQuad, visible_rect, color);
EXPECT_EQ(DrawQuad::CHECKERBOARD, copy_quad->material);
+ EXPECT_RECT_EQ(visible_rect, copy_quad->visible_rect);
EXPECT_EQ(color, copy_quad->color);
CREATE_QUAD_1_ALL(CheckerboardDrawQuad, color);
@@ -341,12 +350,14 @@ TEST(DrawQuadTest, CopyCheckerboardDrawQuad) {
}
TEST(DrawQuadTest, CopyDebugBorderDrawQuad) {
+ gfx::Rect visible_rect(40, 50, 30, 20);
SkColor color = 0xfabb0011;
int width = 99;
CREATE_SHARED_STATE();
- CREATE_QUAD_2_NEW(DebugBorderDrawQuad, color, width);
+ CREATE_QUAD_3_NEW(DebugBorderDrawQuad, visible_rect, color, width);
EXPECT_EQ(DrawQuad::DEBUG_BORDER, copy_quad->material);
+ EXPECT_RECT_EQ(visible_rect, copy_quad->visible_rect);
EXPECT_EQ(color, copy_quad->color);
EXPECT_EQ(width, copy_quad->width);
@@ -358,14 +369,20 @@ TEST(DrawQuadTest, CopyDebugBorderDrawQuad) {
TEST(DrawQuadTest, CopyIOSurfaceDrawQuad) {
gfx::Rect opaque_rect(33, 47, 10, 12);
+ gfx::Rect visible_rect(40, 50, 30, 20);
gfx::Size size(58, 95);
ResourceProvider::ResourceId resource_id = 72;
IOSurfaceDrawQuad::Orientation orientation = IOSurfaceDrawQuad::UNFLIPPED;
CREATE_SHARED_STATE();
- CREATE_QUAD_4_NEW(
- IOSurfaceDrawQuad, opaque_rect, size, resource_id, orientation);
+ CREATE_QUAD_5_NEW(IOSurfaceDrawQuad,
+ opaque_rect,
+ visible_rect,
+ size,
+ resource_id,
+ orientation);
EXPECT_EQ(DrawQuad::IO_SURFACE_CONTENT, copy_quad->material);
+ EXPECT_RECT_EQ(visible_rect, copy_quad->visible_rect);
EXPECT_RECT_EQ(opaque_rect, copy_quad->opaque_rect);
EXPECT_EQ(size, copy_quad->io_surface_size);
EXPECT_EQ(resource_id, copy_quad->io_surface_resource_id);
@@ -379,6 +396,7 @@ TEST(DrawQuadTest, CopyIOSurfaceDrawQuad) {
}
TEST(DrawQuadTest, CopyRenderPassDrawQuad) {
+ gfx::Rect visible_rect(40, 50, 30, 20);
RenderPass::Id render_pass_id(22, 64);
bool is_replica = true;
ResourceProvider::ResourceId mask_resource_id = 78;
@@ -393,7 +411,8 @@ TEST(DrawQuadTest, CopyRenderPassDrawQuad) {
RenderPass::Id copied_render_pass_id(235, 11);
CREATE_SHARED_STATE();
- CREATE_QUAD_7_NEW_1(RenderPassDrawQuad,
+ CREATE_QUAD_8_NEW_1(RenderPassDrawQuad,
+ visible_rect,
render_pass_id,
is_replica,
mask_resource_id,
@@ -403,6 +422,7 @@ TEST(DrawQuadTest, CopyRenderPassDrawQuad) {
background_filters,
copied_render_pass_id);
EXPECT_EQ(DrawQuad::RENDER_PASS, copy_quad->material);
+ EXPECT_RECT_EQ(visible_rect, copy_quad->visible_rect);
EXPECT_EQ(copied_render_pass_id, copy_quad->render_pass_id);
EXPECT_EQ(is_replica, copy_quad->is_replica);
EXPECT_EQ(mask_resource_id, copy_quad->mask_resource_id);
@@ -433,12 +453,15 @@ TEST(DrawQuadTest, CopyRenderPassDrawQuad) {
}
TEST(DrawQuadTest, CopySolidColorDrawQuad) {
+ gfx::Rect visible_rect(40, 50, 30, 20);
SkColor color = 0x49494949;
bool force_anti_aliasing_off = false;
CREATE_SHARED_STATE();
- CREATE_QUAD_2_NEW(SolidColorDrawQuad, color, force_anti_aliasing_off);
+ CREATE_QUAD_3_NEW(
+ SolidColorDrawQuad, visible_rect, color, force_anti_aliasing_off);
EXPECT_EQ(DrawQuad::SOLID_COLOR, copy_quad->material);
+ EXPECT_RECT_EQ(visible_rect, copy_quad->visible_rect);
EXPECT_EQ(color, copy_quad->color);
EXPECT_EQ(force_anti_aliasing_off, copy_quad->force_anti_aliasing_off);
@@ -450,12 +473,15 @@ TEST(DrawQuadTest, CopySolidColorDrawQuad) {
TEST(DrawQuadTest, CopyStreamVideoDrawQuad) {
gfx::Rect opaque_rect(33, 47, 10, 12);
+ gfx::Rect visible_rect(40, 50, 30, 20);
ResourceProvider::ResourceId resource_id = 64;
gfx::Transform matrix = gfx::Transform(0.5, 0.25, 1, 0.75, 0, 1);
CREATE_SHARED_STATE();
- CREATE_QUAD_3_NEW(StreamVideoDrawQuad, opaque_rect, resource_id, matrix);
+ CREATE_QUAD_4_NEW(
+ StreamVideoDrawQuad, opaque_rect, visible_rect, resource_id, matrix);
EXPECT_EQ(DrawQuad::STREAM_VIDEO_CONTENT, copy_quad->material);
+ EXPECT_RECT_EQ(visible_rect, copy_quad->visible_rect);
EXPECT_RECT_EQ(opaque_rect, copy_quad->opaque_rect);
EXPECT_EQ(resource_id, copy_quad->resource_id);
EXPECT_EQ(matrix, copy_quad->matrix);
@@ -466,8 +492,25 @@ TEST(DrawQuadTest, CopyStreamVideoDrawQuad) {
EXPECT_EQ(matrix, copy_quad->matrix);
}
+TEST(DrawQuadTest, CopySurfaceDrawQuad) {
+ gfx::Rect visible_rect(40, 50, 30, 20);
+ SurfaceId surface_id(1234);
+ CREATE_SHARED_STATE();
+
+ CREATE_QUAD_2_NEW(SurfaceDrawQuad, visible_rect, surface_id);
+ EXPECT_EQ(DrawQuad::SURFACE_CONTENT, copy_quad->material);
+ EXPECT_RECT_EQ(visible_rect, copy_quad->visible_rect);
+ EXPECT_EQ(surface_id, copy_quad->surface_id);
+
+ CREATE_QUAD_1_ALL(SurfaceDrawQuad, surface_id);
+ EXPECT_EQ(DrawQuad::SURFACE_CONTENT, copy_quad->material);
+ EXPECT_EQ(surface_id, copy_quad->surface_id);
+}
+
+
TEST(DrawQuadTest, CopyTextureDrawQuad) {
gfx::Rect opaque_rect(33, 47, 10, 12);
+ gfx::Rect visible_rect(40, 50, 30, 20);
unsigned resource_id = 82;
bool premultiplied_alpha = true;
gfx::PointF uv_top_left(0.5f, 224.f);
@@ -476,8 +519,9 @@ TEST(DrawQuadTest, CopyTextureDrawQuad) {
bool flipped = true;
CREATE_SHARED_STATE();
- CREATE_QUAD_8_NEW(TextureDrawQuad,
+ CREATE_QUAD_9_NEW(TextureDrawQuad,
opaque_rect,
+ visible_rect,
resource_id,
premultiplied_alpha,
uv_top_left,
@@ -486,6 +530,7 @@ TEST(DrawQuadTest, CopyTextureDrawQuad) {
vertex_opacity,
flipped);
EXPECT_EQ(DrawQuad::TEXTURE_CONTENT, copy_quad->material);
+ EXPECT_RECT_EQ(visible_rect, copy_quad->visible_rect);
EXPECT_RECT_EQ(opaque_rect, copy_quad->opaque_rect);
EXPECT_EQ(resource_id, copy_quad->resource_id);
EXPECT_EQ(premultiplied_alpha, copy_quad->premultiplied_alpha);
@@ -513,20 +558,23 @@ TEST(DrawQuadTest, CopyTextureDrawQuad) {
TEST(DrawQuadTest, CopyTileDrawQuad) {
gfx::Rect opaque_rect(33, 44, 22, 33);
+ gfx::Rect visible_rect(40, 50, 30, 20);
unsigned resource_id = 104;
gfx::RectF tex_coord_rect(31.f, 12.f, 54.f, 20.f);
gfx::Size texture_size(85, 32);
bool swizzle_contents = true;
CREATE_SHARED_STATE();
- CREATE_QUAD_5_NEW(TileDrawQuad,
+ CREATE_QUAD_6_NEW(TileDrawQuad,
opaque_rect,
+ visible_rect,
resource_id,
tex_coord_rect,
texture_size,
swizzle_contents);
EXPECT_EQ(DrawQuad::TILED_CONTENT, copy_quad->material);
EXPECT_RECT_EQ(opaque_rect, copy_quad->opaque_rect);
+ EXPECT_RECT_EQ(visible_rect, copy_quad->visible_rect);
EXPECT_EQ(resource_id, copy_quad->resource_id);
EXPECT_EQ(tex_coord_rect, copy_quad->tex_coord_rect);
EXPECT_EQ(texture_size, copy_quad->texture_size);
@@ -546,44 +594,53 @@ TEST(DrawQuadTest, CopyTileDrawQuad) {
TEST(DrawQuadTest, CopyYUVVideoDrawQuad) {
gfx::Rect opaque_rect(33, 47, 10, 12);
- gfx::SizeF tex_scale(0.75f, 0.5f);
+ gfx::Rect visible_rect(40, 50, 30, 20);
+ gfx::RectF tex_coord_rect(0.0f, 0.0f, 0.75f, 0.5f);
ResourceProvider::ResourceId y_plane_resource_id = 45;
ResourceProvider::ResourceId u_plane_resource_id = 532;
ResourceProvider::ResourceId v_plane_resource_id = 4;
ResourceProvider::ResourceId a_plane_resource_id = 63;
+ YUVVideoDrawQuad::ColorSpace color_space = YUVVideoDrawQuad::REC_601_JPEG;
CREATE_SHARED_STATE();
- CREATE_QUAD_6_NEW(YUVVideoDrawQuad,
+ CREATE_QUAD_8_NEW(YUVVideoDrawQuad,
opaque_rect,
- tex_scale,
+ visible_rect,
+ tex_coord_rect,
y_plane_resource_id,
u_plane_resource_id,
v_plane_resource_id,
- a_plane_resource_id);
+ a_plane_resource_id,
+ color_space);
EXPECT_EQ(DrawQuad::YUV_VIDEO_CONTENT, copy_quad->material);
EXPECT_RECT_EQ(opaque_rect, copy_quad->opaque_rect);
- EXPECT_EQ(tex_scale, copy_quad->tex_scale);
+ EXPECT_RECT_EQ(visible_rect, copy_quad->visible_rect);
+ EXPECT_EQ(tex_coord_rect, copy_quad->tex_coord_rect);
EXPECT_EQ(y_plane_resource_id, copy_quad->y_plane_resource_id);
EXPECT_EQ(u_plane_resource_id, copy_quad->u_plane_resource_id);
EXPECT_EQ(v_plane_resource_id, copy_quad->v_plane_resource_id);
EXPECT_EQ(a_plane_resource_id, copy_quad->a_plane_resource_id);
+ EXPECT_EQ(color_space, copy_quad->color_space);
- CREATE_QUAD_5_ALL(YUVVideoDrawQuad,
- tex_scale,
+ CREATE_QUAD_6_ALL(YUVVideoDrawQuad,
+ tex_coord_rect,
y_plane_resource_id,
u_plane_resource_id,
v_plane_resource_id,
- a_plane_resource_id);
+ a_plane_resource_id,
+ color_space);
EXPECT_EQ(DrawQuad::YUV_VIDEO_CONTENT, copy_quad->material);
- EXPECT_EQ(tex_scale, copy_quad->tex_scale);
+ EXPECT_EQ(tex_coord_rect, copy_quad->tex_coord_rect);
EXPECT_EQ(y_plane_resource_id, copy_quad->y_plane_resource_id);
EXPECT_EQ(u_plane_resource_id, copy_quad->u_plane_resource_id);
EXPECT_EQ(v_plane_resource_id, copy_quad->v_plane_resource_id);
EXPECT_EQ(a_plane_resource_id, copy_quad->a_plane_resource_id);
+ EXPECT_EQ(color_space, copy_quad->color_space);
}
TEST(DrawQuadTest, CopyPictureDrawQuad) {
gfx::Rect opaque_rect(33, 44, 22, 33);
+ gfx::Rect visible_rect(40, 50, 30, 20);
gfx::RectF tex_coord_rect(31.f, 12.f, 54.f, 20.f);
gfx::Size texture_size(85, 32);
ResourceFormat texture_format = RGBA_8888;
@@ -592,8 +649,9 @@ TEST(DrawQuadTest, CopyPictureDrawQuad) {
scoped_refptr<PicturePileImpl> picture_pile = PicturePileImpl::Create();
CREATE_SHARED_STATE();
- CREATE_QUAD_7_NEW(PictureDrawQuad,
+ CREATE_QUAD_8_NEW(PictureDrawQuad,
opaque_rect,
+ visible_rect,
tex_coord_rect,
texture_size,
texture_format,
@@ -602,6 +660,7 @@ TEST(DrawQuadTest, CopyPictureDrawQuad) {
picture_pile);
EXPECT_EQ(DrawQuad::PICTURE_CONTENT, copy_quad->material);
EXPECT_RECT_EQ(opaque_rect, copy_quad->opaque_rect);
+ EXPECT_RECT_EQ(visible_rect, copy_quad->visible_rect);
EXPECT_EQ(tex_coord_rect, copy_quad->tex_coord_rect);
EXPECT_EQ(texture_size, copy_quad->texture_size);
EXPECT_EQ(texture_format, copy_quad->texture_format);
@@ -645,37 +704,45 @@ class DrawQuadIteratorTest : public testing::Test {
};
TEST_F(DrawQuadIteratorTest, CheckerboardDrawQuad) {
+ gfx::Rect visible_rect(40, 50, 30, 20);
SkColor color = 0xfabb0011;
CREATE_SHARED_STATE();
- CREATE_QUAD_1_NEW(CheckerboardDrawQuad, color);
+ CREATE_QUAD_2_NEW(CheckerboardDrawQuad, visible_rect, color);
EXPECT_EQ(0, IterateAndCount(quad_new.get()));
}
TEST_F(DrawQuadIteratorTest, DebugBorderDrawQuad) {
+ gfx::Rect visible_rect(40, 50, 30, 20);
SkColor color = 0xfabb0011;
int width = 99;
CREATE_SHARED_STATE();
- CREATE_QUAD_2_NEW(DebugBorderDrawQuad, color, width);
+ CREATE_QUAD_3_NEW(DebugBorderDrawQuad, visible_rect, color, width);
EXPECT_EQ(0, IterateAndCount(quad_new.get()));
}
TEST_F(DrawQuadIteratorTest, IOSurfaceDrawQuad) {
gfx::Rect opaque_rect(33, 47, 10, 12);
+ gfx::Rect visible_rect(40, 50, 30, 20);
gfx::Size size(58, 95);
ResourceProvider::ResourceId resource_id = 72;
IOSurfaceDrawQuad::Orientation orientation = IOSurfaceDrawQuad::UNFLIPPED;
CREATE_SHARED_STATE();
- CREATE_QUAD_4_NEW(
- IOSurfaceDrawQuad, opaque_rect, size, resource_id, orientation);
+ CREATE_QUAD_5_NEW(IOSurfaceDrawQuad,
+ opaque_rect,
+ visible_rect,
+ size,
+ resource_id,
+ orientation);
EXPECT_EQ(resource_id, quad_new->io_surface_resource_id);
EXPECT_EQ(1, IterateAndCount(quad_new.get()));
EXPECT_EQ(resource_id + 1, quad_new->io_surface_resource_id);
}
TEST_F(DrawQuadIteratorTest, RenderPassDrawQuad) {
+ gfx::Rect visible_rect(40, 50, 30, 20);
RenderPass::Id render_pass_id(22, 64);
bool is_replica = true;
ResourceProvider::ResourceId mask_resource_id = 78;
@@ -690,7 +757,8 @@ TEST_F(DrawQuadIteratorTest, RenderPassDrawQuad) {
RenderPass::Id copied_render_pass_id(235, 11);
CREATE_SHARED_STATE();
- CREATE_QUAD_7_NEW_1(RenderPassDrawQuad,
+ CREATE_QUAD_8_NEW_1(RenderPassDrawQuad,
+ visible_rect,
render_pass_id,
is_replica,
mask_resource_id,
@@ -708,28 +776,42 @@ TEST_F(DrawQuadIteratorTest, RenderPassDrawQuad) {
}
TEST_F(DrawQuadIteratorTest, SolidColorDrawQuad) {
+ gfx::Rect visible_rect(40, 50, 30, 20);
SkColor color = 0x49494949;
bool force_anti_aliasing_off = false;
CREATE_SHARED_STATE();
- CREATE_QUAD_2_NEW(SolidColorDrawQuad, color, force_anti_aliasing_off);
+ CREATE_QUAD_3_NEW(
+ SolidColorDrawQuad, visible_rect, color, force_anti_aliasing_off);
EXPECT_EQ(0, IterateAndCount(quad_new.get()));
}
TEST_F(DrawQuadIteratorTest, StreamVideoDrawQuad) {
gfx::Rect opaque_rect(33, 47, 10, 12);
+ gfx::Rect visible_rect(40, 50, 30, 20);
ResourceProvider::ResourceId resource_id = 64;
gfx::Transform matrix = gfx::Transform(0.5, 0.25, 1, 0.75, 0, 1);
CREATE_SHARED_STATE();
- CREATE_QUAD_3_NEW(StreamVideoDrawQuad, opaque_rect, resource_id, matrix);
+ CREATE_QUAD_4_NEW(
+ StreamVideoDrawQuad, opaque_rect, visible_rect, resource_id, matrix);
EXPECT_EQ(resource_id, quad_new->resource_id);
EXPECT_EQ(1, IterateAndCount(quad_new.get()));
EXPECT_EQ(resource_id + 1, quad_new->resource_id);
}
+TEST_F(DrawQuadIteratorTest, SurfaceDrawQuad) {
+ gfx::Rect visible_rect(40, 50, 30, 20);
+ SurfaceId surface_id(4321);
+
+ CREATE_SHARED_STATE();
+ CREATE_QUAD_2_NEW(SurfaceDrawQuad, visible_rect, surface_id);
+ EXPECT_EQ(0, IterateAndCount(quad_new.get()));
+}
+
TEST_F(DrawQuadIteratorTest, TextureDrawQuad) {
gfx::Rect opaque_rect(33, 47, 10, 12);
+ gfx::Rect visible_rect(40, 50, 30, 20);
unsigned resource_id = 82;
bool premultiplied_alpha = true;
gfx::PointF uv_top_left(0.5f, 224.f);
@@ -738,8 +820,9 @@ TEST_F(DrawQuadIteratorTest, TextureDrawQuad) {
bool flipped = true;
CREATE_SHARED_STATE();
- CREATE_QUAD_8_NEW(TextureDrawQuad,
+ CREATE_QUAD_9_NEW(TextureDrawQuad,
opaque_rect,
+ visible_rect,
resource_id,
premultiplied_alpha,
uv_top_left,
@@ -754,14 +837,16 @@ TEST_F(DrawQuadIteratorTest, TextureDrawQuad) {
TEST_F(DrawQuadIteratorTest, TileDrawQuad) {
gfx::Rect opaque_rect(33, 44, 22, 33);
+ gfx::Rect visible_rect(40, 50, 30, 20);
unsigned resource_id = 104;
gfx::RectF tex_coord_rect(31.f, 12.f, 54.f, 20.f);
gfx::Size texture_size(85, 32);
bool swizzle_contents = true;
CREATE_SHARED_STATE();
- CREATE_QUAD_5_NEW(TileDrawQuad,
+ CREATE_QUAD_6_NEW(TileDrawQuad,
opaque_rect,
+ visible_rect,
resource_id,
tex_coord_rect,
texture_size,
@@ -773,25 +858,30 @@ TEST_F(DrawQuadIteratorTest, TileDrawQuad) {
TEST_F(DrawQuadIteratorTest, YUVVideoDrawQuad) {
gfx::Rect opaque_rect(33, 47, 10, 12);
- gfx::SizeF tex_scale(0.75f, 0.5f);
+ gfx::Rect visible_rect(40, 50, 30, 20);
+ gfx::RectF tex_coord_rect(0.0f, 0.0f, 0.75f, 0.5f);
ResourceProvider::ResourceId y_plane_resource_id = 45;
ResourceProvider::ResourceId u_plane_resource_id = 532;
ResourceProvider::ResourceId v_plane_resource_id = 4;
ResourceProvider::ResourceId a_plane_resource_id = 63;
+ YUVVideoDrawQuad::ColorSpace color_space = YUVVideoDrawQuad::REC_601_JPEG;
CREATE_SHARED_STATE();
- CREATE_QUAD_6_NEW(YUVVideoDrawQuad,
+ CREATE_QUAD_8_NEW(YUVVideoDrawQuad,
opaque_rect,
- tex_scale,
+ visible_rect,
+ tex_coord_rect,
y_plane_resource_id,
u_plane_resource_id,
v_plane_resource_id,
- a_plane_resource_id);
+ a_plane_resource_id,
+ color_space);
EXPECT_EQ(DrawQuad::YUV_VIDEO_CONTENT, copy_quad->material);
EXPECT_EQ(y_plane_resource_id, quad_new->y_plane_resource_id);
EXPECT_EQ(u_plane_resource_id, quad_new->u_plane_resource_id);
EXPECT_EQ(v_plane_resource_id, quad_new->v_plane_resource_id);
EXPECT_EQ(a_plane_resource_id, quad_new->a_plane_resource_id);
+ EXPECT_EQ(color_space, quad_new->color_space);
EXPECT_EQ(4, IterateAndCount(quad_new.get()));
EXPECT_EQ(y_plane_resource_id + 1, quad_new->y_plane_resource_id);
EXPECT_EQ(u_plane_resource_id + 1, quad_new->u_plane_resource_id);
@@ -802,6 +892,7 @@ TEST_F(DrawQuadIteratorTest, YUVVideoDrawQuad) {
// Disabled until picture draw quad is supported for ubercomp: crbug.com/231715
TEST_F(DrawQuadIteratorTest, DISABLED_PictureDrawQuad) {
gfx::Rect opaque_rect(33, 44, 22, 33);
+ gfx::Rect visible_rect(40, 50, 30, 20);
gfx::RectF tex_coord_rect(31.f, 12.f, 54.f, 20.f);
gfx::Size texture_size(85, 32);
ResourceFormat texture_format = RGBA_8888;
@@ -810,8 +901,9 @@ TEST_F(DrawQuadIteratorTest, DISABLED_PictureDrawQuad) {
scoped_refptr<PicturePileImpl> picture_pile = PicturePileImpl::Create();
CREATE_SHARED_STATE();
- CREATE_QUAD_7_NEW(PictureDrawQuad,
+ CREATE_QUAD_8_NEW(PictureDrawQuad,
opaque_rect,
+ visible_rect,
tex_coord_rect,
texture_size,
texture_format,
diff --git a/chromium/cc/quads/io_surface_draw_quad.cc b/chromium/cc/quads/io_surface_draw_quad.cc
index 2c986dd3a23..a7a8f691ca2 100644
--- a/chromium/cc/quads/io_surface_draw_quad.cc
+++ b/chromium/cc/quads/io_surface_draw_quad.cc
@@ -20,12 +20,12 @@ scoped_ptr<IOSurfaceDrawQuad> IOSurfaceDrawQuad::Create() {
}
void IOSurfaceDrawQuad::SetNew(const SharedQuadState* shared_quad_state,
- gfx::Rect rect,
- gfx::Rect opaque_rect,
- gfx::Size io_surface_size,
+ const gfx::Rect& rect,
+ const gfx::Rect& opaque_rect,
+ const gfx::Rect& visible_rect,
+ const gfx::Size& io_surface_size,
unsigned io_surface_resource_id,
Orientation orientation) {
- gfx::Rect visible_rect = rect;
bool needs_blending = false;
DrawQuad::SetAll(shared_quad_state, DrawQuad::IO_SURFACE_CONTENT, rect,
opaque_rect, visible_rect, needs_blending);
@@ -35,11 +35,11 @@ void IOSurfaceDrawQuad::SetNew(const SharedQuadState* shared_quad_state,
}
void IOSurfaceDrawQuad::SetAll(const SharedQuadState* shared_quad_state,
- gfx::Rect rect,
- gfx::Rect opaque_rect,
- gfx::Rect visible_rect,
+ const gfx::Rect& rect,
+ const gfx::Rect& opaque_rect,
+ const gfx::Rect& visible_rect,
bool needs_blending,
- gfx::Size io_surface_size,
+ const gfx::Size& io_surface_size,
unsigned io_surface_resource_id,
Orientation orientation) {
DrawQuad::SetAll(shared_quad_state, DrawQuad::IO_SURFACE_CONTENT, rect,
diff --git a/chromium/cc/quads/io_surface_draw_quad.h b/chromium/cc/quads/io_surface_draw_quad.h
index fc8b5019402..a23e54c40f8 100644
--- a/chromium/cc/quads/io_surface_draw_quad.h
+++ b/chromium/cc/quads/io_surface_draw_quad.h
@@ -16,24 +16,26 @@ class CC_EXPORT IOSurfaceDrawQuad : public DrawQuad {
public:
enum Orientation {
FLIPPED,
- UNFLIPPED
+ UNFLIPPED,
+ ORIENTATION_LAST = UNFLIPPED
};
static scoped_ptr<IOSurfaceDrawQuad> Create();
void SetNew(const SharedQuadState* shared_quad_state,
- gfx::Rect rect,
- gfx::Rect opaque_rect,
- gfx::Size io_surface_size,
+ const gfx::Rect& rect,
+ const gfx::Rect& opaque_rect,
+ const gfx::Rect& visible_rect,
+ const gfx::Size& io_surface_size,
unsigned io_surface_resource_id,
Orientation orientation);
void SetAll(const SharedQuadState* shared_quad_state,
- gfx::Rect rect,
- gfx::Rect opaque_rect,
- gfx::Rect visible_rect,
+ const gfx::Rect& rect,
+ const gfx::Rect& opaque_rect,
+ const gfx::Rect& visible_rect,
bool needs_blending,
- gfx::Size io_surface_size,
+ const gfx::Size& io_surface_size,
unsigned io_surface_resource_id,
Orientation orientation);
diff --git a/chromium/cc/quads/picture_draw_quad.cc b/chromium/cc/quads/picture_draw_quad.cc
index bdb12e64d7a..37bb07e907b 100644
--- a/chromium/cc/quads/picture_draw_quad.cc
+++ b/chromium/cc/quads/picture_draw_quad.cc
@@ -21,22 +21,24 @@ scoped_ptr<PictureDrawQuad> PictureDrawQuad::Create() {
}
void PictureDrawQuad::SetNew(const SharedQuadState* shared_quad_state,
- gfx::Rect rect,
- gfx::Rect opaque_rect,
+ const gfx::Rect& rect,
+ const gfx::Rect& opaque_rect,
+ const gfx::Rect& visible_rect,
const gfx::RectF& tex_coord_rect,
- gfx::Size texture_size,
+ const gfx::Size& texture_size,
ResourceFormat texture_format,
- gfx::Rect content_rect,
+ const gfx::Rect& content_rect,
float contents_scale,
scoped_refptr<PicturePileImpl> picture_pile) {
- ContentDrawQuadBase::SetNew(shared_quad_state,
- DrawQuad::PICTURE_CONTENT,
- rect,
- opaque_rect,
- tex_coord_rect,
- texture_size,
- !PlatformColor::SameComponentOrder(
- texture_format));
+ ContentDrawQuadBase::SetNew(
+ shared_quad_state,
+ DrawQuad::PICTURE_CONTENT,
+ rect,
+ opaque_rect,
+ visible_rect,
+ tex_coord_rect,
+ texture_size,
+ !PlatformColor::SameComponentOrder(texture_format));
this->content_rect = content_rect;
this->contents_scale = contents_scale;
this->picture_pile = picture_pile;
@@ -44,14 +46,14 @@ void PictureDrawQuad::SetNew(const SharedQuadState* shared_quad_state,
}
void PictureDrawQuad::SetAll(const SharedQuadState* shared_quad_state,
- gfx::Rect rect,
- gfx::Rect opaque_rect,
- gfx::Rect visible_rect,
+ const gfx::Rect& rect,
+ const gfx::Rect& opaque_rect,
+ const gfx::Rect& visible_rect,
bool needs_blending,
const gfx::RectF& tex_coord_rect,
- gfx::Size texture_size,
+ const gfx::Size& texture_size,
ResourceFormat texture_format,
- gfx::Rect content_rect,
+ const gfx::Rect& content_rect,
float contents_scale,
scoped_refptr<PicturePileImpl> picture_pile) {
ContentDrawQuadBase::SetAll(shared_quad_state,
diff --git a/chromium/cc/quads/picture_draw_quad.h b/chromium/cc/quads/picture_draw_quad.h
index 9bea70b4609..ea1735fa7fd 100644
--- a/chromium/cc/quads/picture_draw_quad.h
+++ b/chromium/cc/quads/picture_draw_quad.h
@@ -23,24 +23,25 @@ class CC_EXPORT PictureDrawQuad : public ContentDrawQuadBase {
virtual ~PictureDrawQuad();
void SetNew(const SharedQuadState* shared_quad_state,
- gfx::Rect rect,
- gfx::Rect opaque_rect,
+ const gfx::Rect& rect,
+ const gfx::Rect& opaque_rect,
+ const gfx::Rect& visible_rect,
const gfx::RectF& tex_coord_rect,
- gfx::Size texture_size,
+ const gfx::Size& texture_size,
ResourceFormat texture_format,
- gfx::Rect content_rect,
+ const gfx::Rect& content_rect,
float contents_scale,
scoped_refptr<PicturePileImpl> picture_pile);
void SetAll(const SharedQuadState* shared_quad_state,
- gfx::Rect rect,
- gfx::Rect opaque_rect,
- gfx::Rect visible_rect,
+ const gfx::Rect& rect,
+ const gfx::Rect& opaque_rect,
+ const gfx::Rect& visible_rect,
bool needs_blending,
const gfx::RectF& tex_coord_rect,
- gfx::Size texture_size,
+ const gfx::Size& texture_size,
ResourceFormat texture_format,
- gfx::Rect content_rect,
+ const gfx::Rect& content_rect,
float contents_scale,
scoped_refptr<PicturePileImpl> picture_pile);
diff --git a/chromium/cc/quads/render_pass.cc b/chromium/cc/quads/render_pass.cc
index 53cb83703a3..afcc6e816fb 100644
--- a/chromium/cc/quads/render_pass.cc
+++ b/chromium/cc/quads/render_pass.cc
@@ -20,7 +20,7 @@ const size_t kDefaultNumQuadsToReserve = 128;
namespace cc {
void* RenderPass::Id::AsTracingId() const {
- COMPILE_ASSERT(sizeof(size_t) <= sizeof(void*), // NOLINT(runtime/sizeof)
+ COMPILE_ASSERT(sizeof(size_t) <= sizeof(void*), // NOLINT
size_t_bigger_than_pointer);
return reinterpret_cast<void*>(base::HashPair(layer_id, index));
}
@@ -33,16 +33,13 @@ scoped_ptr<RenderPass> RenderPass::Create(size_t num_layers) {
return make_scoped_ptr(new RenderPass(num_layers));
}
-RenderPass::RenderPass()
- : id(Id(-1, -1)),
- has_transparent_background(true) {
+RenderPass::RenderPass() : id(Id(-1, -1)), has_transparent_background(true) {
shared_quad_state_list.reserve(kDefaultNumSharedQuadStatesToReserve);
quad_list.reserve(kDefaultNumQuadsToReserve);
}
RenderPass::RenderPass(size_t num_layers)
- : id(Id(-1, -1)),
- has_transparent_background(true) {
+ : id(Id(-1, -1)), has_transparent_background(true) {
// Each layer usually produces one shared quad state, so the number of layers
// is a good hint for what to reserve here.
shared_quad_state_list.reserve(num_layers);
@@ -82,8 +79,9 @@ void RenderPass::CopyAll(const ScopedPtrVector<RenderPass>& in,
source->transform_to_root_target,
source->has_transparent_background);
for (size_t i = 0; i < source->shared_quad_state_list.size(); ++i) {
- copy_pass->shared_quad_state_list.push_back(
- source->shared_quad_state_list[i]->Copy());
+ SharedQuadState* copy_shared_quad_state =
+ copy_pass->CreateAndAppendSharedQuadState();
+ copy_shared_quad_state->CopyFrom(source->shared_quad_state_list[i]);
}
for (size_t i = 0, sqs_i = 0; i < source->quad_list.size(); ++i) {
while (source->quad_list[i]->shared_quad_state !=
@@ -112,11 +110,14 @@ void RenderPass::CopyAll(const ScopedPtrVector<RenderPass>& in,
}
void RenderPass::SetNew(Id id,
- gfx::Rect output_rect,
- gfx::RectF damage_rect,
+ const gfx::Rect& output_rect,
+ const gfx::Rect& damage_rect,
const gfx::Transform& transform_to_root_target) {
DCHECK_GT(id.layer_id, 0);
DCHECK_GE(id.index, 0);
+ DCHECK(damage_rect.IsEmpty() || output_rect.Contains(damage_rect))
+ << "damage_rect: " << damage_rect.ToString()
+ << " output_rect: " << output_rect.ToString();
this->id = id;
this->output_rect = output_rect;
@@ -128,8 +129,8 @@ void RenderPass::SetNew(Id id,
}
void RenderPass::SetAll(Id id,
- gfx::Rect output_rect,
- gfx::RectF damage_rect,
+ const gfx::Rect& output_rect,
+ const gfx::Rect& damage_rect,
const gfx::Transform& transform_to_root_target,
bool has_transparent_background) {
DCHECK_GT(id.layer_id, 0);
@@ -168,4 +169,13 @@ scoped_ptr<base::Value> RenderPass::AsValue() const {
return value.PassAs<base::Value>();
}
+SharedQuadState* RenderPass::CreateAndAppendSharedQuadState() {
+ shared_quad_state_list.push_back(make_scoped_ptr(new SharedQuadState));
+ return shared_quad_state_list.back();
+}
+
+void RenderPass::AppendDrawQuad(scoped_ptr<DrawQuad> draw_quad) {
+ quad_list.push_back(draw_quad.Pass());
+}
+
} // namespace cc
diff --git a/chromium/cc/quads/render_pass.h b/chromium/cc/quads/render_pass.h
index 407381fb172..778a71438fa 100644
--- a/chromium/cc/quads/render_pass.h
+++ b/chromium/cc/quads/render_pass.h
@@ -76,24 +76,27 @@ class CC_EXPORT RenderPass {
ScopedPtrVector<RenderPass>* out);
void SetNew(Id id,
- gfx::Rect output_rect,
- gfx::RectF damage_rect,
+ const gfx::Rect& output_rect,
+ const gfx::Rect& damage_rect,
const gfx::Transform& transform_to_root_target);
void SetAll(Id id,
- gfx::Rect output_rect,
- gfx::RectF damage_rect,
+ const gfx::Rect& output_rect,
+ const gfx::Rect& damage_rect,
const gfx::Transform& transform_to_root_target,
bool has_transparent_background);
scoped_ptr<base::Value> AsValue() const;
+ SharedQuadState* CreateAndAppendSharedQuadState();
+ void AppendDrawQuad(scoped_ptr<DrawQuad> draw_quad);
+
// Uniquely identifies the render pass in the compositor's current frame.
Id id;
// These are in the space of the render pass' physical pixels.
gfx::Rect output_rect;
- gfx::RectF damage_rect;
+ gfx::Rect damage_rect;
// Transforms from the origin of the |output_rect| to the origin of the root
// render pass' |output_rect|.
diff --git a/chromium/cc/quads/render_pass_draw_quad.cc b/chromium/cc/quads/render_pass_draw_quad.cc
index af8cd8c492c..81b0da285e5 100644
--- a/chromium/cc/quads/render_pass_draw_quad.cc
+++ b/chromium/cc/quads/render_pass_draw_quad.cc
@@ -36,19 +36,19 @@ scoped_ptr<RenderPassDrawQuad> RenderPassDrawQuad::Copy(
void RenderPassDrawQuad::SetNew(
const SharedQuadState* shared_quad_state,
- gfx::Rect rect,
+ const gfx::Rect& rect,
+ const gfx::Rect& visible_rect,
RenderPass::Id render_pass_id,
bool is_replica,
ResourceProvider::ResourceId mask_resource_id,
- gfx::Rect contents_changed_since_last_frame,
- gfx::RectF mask_uv_rect,
+ const gfx::Rect& contents_changed_since_last_frame,
+ const gfx::RectF& mask_uv_rect,
const FilterOperations& filters,
const FilterOperations& background_filters) {
DCHECK_GT(render_pass_id.layer_id, 0);
DCHECK_GE(render_pass_id.index, 0);
gfx::Rect opaque_rect;
- gfx::Rect visible_rect = rect;
bool needs_blending = false;
SetAll(shared_quad_state, rect, opaque_rect, visible_rect, needs_blending,
render_pass_id, is_replica, mask_resource_id,
@@ -58,15 +58,15 @@ void RenderPassDrawQuad::SetNew(
void RenderPassDrawQuad::SetAll(
const SharedQuadState* shared_quad_state,
- gfx::Rect rect,
- gfx::Rect opaque_rect,
- gfx::Rect visible_rect,
+ const gfx::Rect& rect,
+ const gfx::Rect& opaque_rect,
+ const gfx::Rect& visible_rect,
bool needs_blending,
RenderPass::Id render_pass_id,
bool is_replica,
ResourceProvider::ResourceId mask_resource_id,
- gfx::Rect contents_changed_since_last_frame,
- gfx::RectF mask_uv_rect,
+ const gfx::Rect& contents_changed_since_last_frame,
+ const gfx::RectF& mask_uv_rect,
const FilterOperations& filters,
const FilterOperations& background_filters) {
DCHECK_GT(render_pass_id.layer_id, 0);
diff --git a/chromium/cc/quads/render_pass_draw_quad.h b/chromium/cc/quads/render_pass_draw_quad.h
index 8546c45621c..1f6217ddc8c 100644
--- a/chromium/cc/quads/render_pass_draw_quad.h
+++ b/chromium/cc/quads/render_pass_draw_quad.h
@@ -21,25 +21,26 @@ class CC_EXPORT RenderPassDrawQuad : public DrawQuad {
virtual ~RenderPassDrawQuad();
void SetNew(const SharedQuadState* shared_quad_state,
- gfx::Rect rect,
+ const gfx::Rect& rect,
+ const gfx::Rect& visible_rect,
RenderPass::Id render_pass_id,
bool is_replica,
ResourceProvider::ResourceId mask_resource_id,
- gfx::Rect contents_changed_since_last_frame,
- gfx::RectF mask_uv_rect,
+ const gfx::Rect& contents_changed_since_last_frame,
+ const gfx::RectF& mask_uv_rect,
const FilterOperations& filters,
const FilterOperations& background_filters);
void SetAll(const SharedQuadState* shared_quad_state,
- gfx::Rect rect,
- gfx::Rect opaque_rect,
- gfx::Rect visible_rect,
+ const gfx::Rect& rect,
+ const gfx::Rect& opaque_rect,
+ const gfx::Rect& visible_rect,
bool needs_blending,
RenderPass::Id render_pass_id,
bool is_replica,
ResourceProvider::ResourceId mask_resource_id,
- gfx::Rect contents_changed_since_last_frame,
- gfx::RectF mask_uv_rect,
+ const gfx::Rect& contents_changed_since_last_frame,
+ const gfx::RectF& mask_uv_rect,
const FilterOperations& filters,
const FilterOperations& background_filters);
diff --git a/chromium/cc/quads/render_pass_unittest.cc b/chromium/cc/quads/render_pass_unittest.cc
index e70a33dd685..59af62d2ed1 100644
--- a/chromium/cc/quads/render_pass_unittest.cc
+++ b/chromium/cc/quads/render_pass_unittest.cc
@@ -28,7 +28,7 @@ struct RenderPassSize {
SharedQuadStateList shared_quad_state_list;
gfx::Transform transform_to_root_target;
gfx::Rect output_rect;
- gfx::RectF damage_rect;
+ gfx::Rect damage_rect;
bool has_transparent_background;
ScopedPtrVector<CopyOutputRequest> copy_callbacks;
};
@@ -79,20 +79,20 @@ TEST(RenderPassTest, CopyShouldBeIdenticalExceptIdAndQuads) {
pass->copy_requests.push_back(CopyOutputRequest::CreateEmptyRequest());
// Stick a quad in the pass, this should not get copied.
- scoped_ptr<SharedQuadState> shared_state = SharedQuadState::Create();
+ SharedQuadState* shared_state = pass->CreateAndAppendSharedQuadState();
shared_state->SetAll(gfx::Transform(),
gfx::Size(),
gfx::Rect(),
gfx::Rect(),
false,
1,
- SkXfermode::kSrcOver_Mode);
- pass->AppendSharedQuadState(shared_state.Pass());
+ SkXfermode::kSrcOver_Mode,
+ 0);
scoped_ptr<CheckerboardDrawQuad> checkerboard_quad =
CheckerboardDrawQuad::Create();
checkerboard_quad->SetNew(
- pass->shared_quad_state_list.back(), gfx::Rect(), SkColor());
+ pass->shared_quad_state_list.back(), gfx::Rect(), gfx::Rect(), SkColor());
pass->quad_list.push_back(checkerboard_quad.PassAs<DrawQuad>());
RenderPass::Id new_id(63, 4);
@@ -130,49 +130,57 @@ TEST(RenderPassTest, CopyAllShouldBeIdentical) {
has_transparent_background);
// Two quads using one shared state.
- scoped_ptr<SharedQuadState> shared_state1 = SharedQuadState::Create();
+ SharedQuadState* shared_state1 = pass->CreateAndAppendSharedQuadState();
shared_state1->SetAll(gfx::Transform(),
gfx::Size(1, 1),
gfx::Rect(),
gfx::Rect(),
false,
1,
- SkXfermode::kSrcOver_Mode);
- pass->AppendSharedQuadState(shared_state1.Pass());
+ SkXfermode::kSrcOver_Mode,
+ 0);
scoped_ptr<CheckerboardDrawQuad> checkerboard_quad1 =
CheckerboardDrawQuad::Create();
- checkerboard_quad1->SetNew(
- pass->shared_quad_state_list.back(), gfx::Rect(1, 1, 1, 1), SkColor());
+ checkerboard_quad1->SetNew(pass->shared_quad_state_list.back(),
+ gfx::Rect(1, 1, 1, 1),
+ gfx::Rect(1, 1, 1, 1),
+ SkColor());
pass->quad_list.push_back(checkerboard_quad1.PassAs<DrawQuad>());
scoped_ptr<CheckerboardDrawQuad> checkerboard_quad2 =
CheckerboardDrawQuad::Create();
- checkerboard_quad2->SetNew(
- pass->shared_quad_state_list.back(), gfx::Rect(2, 2, 2, 2), SkColor());
+ checkerboard_quad2->SetNew(pass->shared_quad_state_list.back(),
+ gfx::Rect(2, 2, 2, 2),
+ gfx::Rect(2, 2, 2, 2),
+ SkColor());
pass->quad_list.push_back(checkerboard_quad2.PassAs<DrawQuad>());
// And two quads using another shared state.
- scoped_ptr<SharedQuadState> shared_state2 = SharedQuadState::Create();
+ SharedQuadState* shared_state2 = pass->CreateAndAppendSharedQuadState();
shared_state2->SetAll(gfx::Transform(),
gfx::Size(2, 2),
gfx::Rect(),
gfx::Rect(),
false,
1,
- SkXfermode::kSrcOver_Mode);
- pass->AppendSharedQuadState(shared_state2.Pass());
+ SkXfermode::kSrcOver_Mode,
+ 0);
scoped_ptr<CheckerboardDrawQuad> checkerboard_quad3 =
CheckerboardDrawQuad::Create();
- checkerboard_quad3->SetNew(
- pass->shared_quad_state_list.back(), gfx::Rect(3, 3, 3, 3), SkColor());
+ checkerboard_quad3->SetNew(pass->shared_quad_state_list.back(),
+ gfx::Rect(3, 3, 3, 3),
+ gfx::Rect(3, 3, 3, 3),
+ SkColor());
pass->quad_list.push_back(checkerboard_quad3.PassAs<DrawQuad>());
scoped_ptr<CheckerboardDrawQuad> checkerboard_quad4 =
CheckerboardDrawQuad::Create();
- checkerboard_quad4->SetNew(
- pass->shared_quad_state_list.back(), gfx::Rect(4, 4, 4, 4), SkColor());
+ checkerboard_quad4->SetNew(pass->shared_quad_state_list.back(),
+ gfx::Rect(4, 4, 4, 4),
+ gfx::Rect(4, 4, 4, 4),
+ SkColor());
pass->quad_list.push_back(checkerboard_quad4.PassAs<DrawQuad>());
// A second render pass with a quad.
@@ -190,26 +198,30 @@ TEST(RenderPassTest, CopyAllShouldBeIdentical) {
contrib_transform_to_root,
contrib_has_transparent_background);
- scoped_ptr<SharedQuadState> contrib_shared_state = SharedQuadState::Create();
+ SharedQuadState* contrib_shared_state =
+ contrib->CreateAndAppendSharedQuadState();
contrib_shared_state->SetAll(gfx::Transform(),
gfx::Size(2, 2),
gfx::Rect(),
gfx::Rect(),
false,
1,
- SkXfermode::kSrcOver_Mode);
- contrib->AppendSharedQuadState(contrib_shared_state.Pass());
+ SkXfermode::kSrcOver_Mode,
+ 0);
scoped_ptr<CheckerboardDrawQuad> contrib_quad =
CheckerboardDrawQuad::Create();
- contrib_quad->SetNew(
- contrib->shared_quad_state_list.back(), gfx::Rect(3, 3, 3, 3), SkColor());
+ contrib_quad->SetNew(contrib->shared_quad_state_list.back(),
+ gfx::Rect(3, 3, 3, 3),
+ gfx::Rect(3, 3, 3, 3),
+ SkColor());
contrib->quad_list.push_back(contrib_quad.PassAs<DrawQuad>());
// And a RenderPassDrawQuad for the contributing pass.
scoped_ptr<RenderPassDrawQuad> pass_quad = RenderPassDrawQuad::Create();
pass_quad->SetNew(pass->shared_quad_state_list.back(),
contrib_output_rect,
+ contrib_output_rect,
contrib_id,
false, // is_replica
0, // mask_resource_id
@@ -247,59 +259,63 @@ TEST(RenderPassTest, CopyAllWithCulledQuads) {
has_transparent_background);
// A shared state with a quad.
- scoped_ptr<SharedQuadState> shared_state1 = SharedQuadState::Create();
+ SharedQuadState* shared_state1 = pass->CreateAndAppendSharedQuadState();
shared_state1->SetAll(gfx::Transform(),
gfx::Size(1, 1),
gfx::Rect(),
gfx::Rect(),
false,
1,
- SkXfermode::kSrcOver_Mode);
- pass->AppendSharedQuadState(shared_state1.Pass());
+ SkXfermode::kSrcOver_Mode,
+ 0);
scoped_ptr<CheckerboardDrawQuad> checkerboard_quad1 =
CheckerboardDrawQuad::Create();
- checkerboard_quad1->SetNew(
- pass->shared_quad_state_list.back(), gfx::Rect(1, 1, 1, 1), SkColor());
+ checkerboard_quad1->SetNew(pass->shared_quad_state_list.back(),
+ gfx::Rect(1, 1, 1, 1),
+ gfx::Rect(1, 1, 1, 1),
+ SkColor());
pass->quad_list.push_back(checkerboard_quad1.PassAs<DrawQuad>());
// A shared state with no quads, they were culled.
- scoped_ptr<SharedQuadState> shared_state2 = SharedQuadState::Create();
+ SharedQuadState* shared_state2 = pass->CreateAndAppendSharedQuadState();
shared_state2->SetAll(gfx::Transform(),
gfx::Size(2, 2),
gfx::Rect(),
gfx::Rect(),
false,
1,
- SkXfermode::kSrcOver_Mode);
- pass->AppendSharedQuadState(shared_state2.Pass());
+ SkXfermode::kSrcOver_Mode,
+ 0);
// A second shared state with no quads.
- scoped_ptr<SharedQuadState> shared_state3 = SharedQuadState::Create();
+ SharedQuadState* shared_state3 = pass->CreateAndAppendSharedQuadState();
shared_state3->SetAll(gfx::Transform(),
gfx::Size(2, 2),
gfx::Rect(),
gfx::Rect(),
false,
1,
- SkXfermode::kSrcOver_Mode);
- pass->AppendSharedQuadState(shared_state3.Pass());
+ SkXfermode::kSrcOver_Mode,
+ 0);
// A last shared state with a quad again.
- scoped_ptr<SharedQuadState> shared_state4 = SharedQuadState::Create();
+ SharedQuadState* shared_state4 = pass->CreateAndAppendSharedQuadState();
shared_state4->SetAll(gfx::Transform(),
gfx::Size(2, 2),
gfx::Rect(),
gfx::Rect(),
false,
1,
- SkXfermode::kSrcOver_Mode);
- pass->AppendSharedQuadState(shared_state4.Pass());
+ SkXfermode::kSrcOver_Mode,
+ 0);
scoped_ptr<CheckerboardDrawQuad> checkerboard_quad2 =
CheckerboardDrawQuad::Create();
- checkerboard_quad2->SetNew(
- pass->shared_quad_state_list.back(), gfx::Rect(3, 3, 3, 3), SkColor());
+ checkerboard_quad2->SetNew(pass->shared_quad_state_list.back(),
+ gfx::Rect(3, 3, 3, 3),
+ gfx::Rect(3, 3, 3, 3),
+ SkColor());
pass->quad_list.push_back(checkerboard_quad2.PassAs<DrawQuad>());
pass_list.push_back(pass.PassAs<RenderPass>());
diff --git a/chromium/cc/quads/shared_quad_state.cc b/chromium/cc/quads/shared_quad_state.cc
index 56584577917..57959e3cdd9 100644
--- a/chromium/cc/quads/shared_quad_state.cc
+++ b/chromium/cc/quads/shared_quad_state.cc
@@ -11,7 +11,11 @@
namespace cc {
SharedQuadState::SharedQuadState()
- : is_clipped(false), opacity(0.f), blend_mode(SkXfermode::kSrcOver_Mode) {}
+ : is_clipped(false),
+ opacity(0.f),
+ blend_mode(SkXfermode::kSrcOver_Mode),
+ sorting_context_id(0) {
+}
SharedQuadState::~SharedQuadState() {
TRACE_EVENT_OBJECT_DELETED_WITH_ID(
@@ -19,21 +23,18 @@ SharedQuadState::~SharedQuadState() {
"cc::SharedQuadState", this);
}
-scoped_ptr<SharedQuadState> SharedQuadState::Create() {
- return make_scoped_ptr(new SharedQuadState);
-}
-
-scoped_ptr<SharedQuadState> SharedQuadState::Copy() const {
- return make_scoped_ptr(new SharedQuadState(*this));
+void SharedQuadState::CopyFrom(const SharedQuadState* other) {
+ *this = *other;
}
void SharedQuadState::SetAll(const gfx::Transform& content_to_target_transform,
- gfx::Size content_bounds,
- gfx::Rect visible_content_rect,
- gfx::Rect clip_rect,
+ const gfx::Size& content_bounds,
+ const gfx::Rect& visible_content_rect,
+ const gfx::Rect& clip_rect,
bool is_clipped,
float opacity,
- SkXfermode::Mode blend_mode) {
+ SkXfermode::Mode blend_mode,
+ int sorting_context_id) {
this->content_to_target_transform = content_to_target_transform;
this->content_bounds = content_bounds;
this->visible_content_rect = visible_content_rect;
@@ -41,6 +42,7 @@ void SharedQuadState::SetAll(const gfx::Transform& content_to_target_transform,
this->is_clipped = is_clipped;
this->opacity = opacity;
this->blend_mode = blend_mode;
+ this->sorting_context_id = sorting_context_id;
}
scoped_ptr<base::Value> SharedQuadState::AsValue() const {
diff --git a/chromium/cc/quads/shared_quad_state.h b/chromium/cc/quads/shared_quad_state.h
index b70d4a11fb9..30a1e25b3d3 100644
--- a/chromium/cc/quads/shared_quad_state.h
+++ b/chromium/cc/quads/shared_quad_state.h
@@ -17,20 +17,26 @@ class Value;
namespace cc {
+// SharedQuadState holds a set of properties that are common across multiple
+// DrawQuads. It's purely an optimization - the properties behave in exactly the
+// same way as if they were replicated on each DrawQuad. A given SharedQuadState
+// can only be shared by DrawQuads that are adjacent in their RenderPass'
+// QuadList.
class CC_EXPORT SharedQuadState {
public:
- static scoped_ptr<SharedQuadState> Create();
+ SharedQuadState();
~SharedQuadState();
- scoped_ptr<SharedQuadState> Copy() const;
+ void CopyFrom(const SharedQuadState* other);
void SetAll(const gfx::Transform& content_to_target_transform,
- gfx::Size content_bounds,
- gfx::Rect visible_content_rect,
- gfx::Rect clip_rect,
+ const gfx::Size& content_bounds,
+ const gfx::Rect& visible_content_rect,
+ const gfx::Rect& clip_rect,
bool is_clipped,
float opacity,
- SkXfermode::Mode blend_mode);
+ SkXfermode::Mode blend_mode,
+ int sorting_context_id);
scoped_ptr<base::Value> AsValue() const;
// Transforms from quad's original content space to its target content space.
@@ -44,9 +50,7 @@ class CC_EXPORT SharedQuadState {
bool is_clipped;
float opacity;
SkXfermode::Mode blend_mode;
-
- private:
- SharedQuadState();
+ int sorting_context_id;
};
} // namespace cc
diff --git a/chromium/cc/quads/solid_color_draw_quad.cc b/chromium/cc/quads/solid_color_draw_quad.cc
index ae3b9142209..7c0b554dcc8 100644
--- a/chromium/cc/quads/solid_color_draw_quad.cc
+++ b/chromium/cc/quads/solid_color_draw_quad.cc
@@ -17,11 +17,11 @@ scoped_ptr<SolidColorDrawQuad> SolidColorDrawQuad::Create() {
}
void SolidColorDrawQuad::SetNew(const SharedQuadState* shared_quad_state,
- gfx::Rect rect,
+ const gfx::Rect& rect,
+ const gfx::Rect& visible_rect,
SkColor color,
bool force_anti_aliasing_off) {
gfx::Rect opaque_rect = SkColorGetA(color) == 255 ? rect : gfx::Rect();
- gfx::Rect visible_rect = rect;
bool needs_blending = false;
DrawQuad::SetAll(shared_quad_state, DrawQuad::SOLID_COLOR, rect, opaque_rect,
visible_rect, needs_blending);
@@ -30,9 +30,9 @@ void SolidColorDrawQuad::SetNew(const SharedQuadState* shared_quad_state,
}
void SolidColorDrawQuad::SetAll(const SharedQuadState* shared_quad_state,
- gfx::Rect rect,
- gfx::Rect opaque_rect,
- gfx::Rect visible_rect,
+ const gfx::Rect& rect,
+ const gfx::Rect& opaque_rect,
+ const gfx::Rect& visible_rect,
bool needs_blending,
SkColor color,
bool force_anti_aliasing_off) {
diff --git a/chromium/cc/quads/solid_color_draw_quad.h b/chromium/cc/quads/solid_color_draw_quad.h
index 2c41243409e..4b8b9a3ae1b 100644
--- a/chromium/cc/quads/solid_color_draw_quad.h
+++ b/chromium/cc/quads/solid_color_draw_quad.h
@@ -17,14 +17,15 @@ class CC_EXPORT SolidColorDrawQuad : public DrawQuad {
static scoped_ptr<SolidColorDrawQuad> Create();
void SetNew(const SharedQuadState* shared_quad_state,
- gfx::Rect rect,
+ const gfx::Rect& rect,
+ const gfx::Rect& visible_rect,
SkColor color,
bool force_anti_aliasing_off);
void SetAll(const SharedQuadState* shared_quad_state,
- gfx::Rect rect,
- gfx::Rect opaque_rect,
- gfx::Rect visible_rect,
+ const gfx::Rect& rect,
+ const gfx::Rect& opaque_rect,
+ const gfx::Rect& visible_rect,
bool needs_blending,
SkColor color,
bool force_anti_aliasing_off);
diff --git a/chromium/cc/quads/stream_video_draw_quad.cc b/chromium/cc/quads/stream_video_draw_quad.cc
index c239256ac51..a9a75bcf130 100644
--- a/chromium/cc/quads/stream_video_draw_quad.cc
+++ b/chromium/cc/quads/stream_video_draw_quad.cc
@@ -17,11 +17,11 @@ scoped_ptr<StreamVideoDrawQuad> StreamVideoDrawQuad::Create() {
}
void StreamVideoDrawQuad::SetNew(const SharedQuadState* shared_quad_state,
- gfx::Rect rect,
- gfx::Rect opaque_rect,
+ const gfx::Rect& rect,
+ const gfx::Rect& opaque_rect,
+ const gfx::Rect& visible_rect,
unsigned resource_id,
const gfx::Transform& matrix) {
- gfx::Rect visible_rect = rect;
bool needs_blending = false;
DrawQuad::SetAll(shared_quad_state, DrawQuad::STREAM_VIDEO_CONTENT, rect,
opaque_rect, visible_rect, needs_blending);
@@ -30,9 +30,9 @@ void StreamVideoDrawQuad::SetNew(const SharedQuadState* shared_quad_state,
}
void StreamVideoDrawQuad::SetAll(const SharedQuadState* shared_quad_state,
- gfx::Rect rect,
- gfx::Rect opaque_rect,
- gfx::Rect visible_rect,
+ const gfx::Rect& rect,
+ const gfx::Rect& opaque_rect,
+ const gfx::Rect& visible_rect,
bool needs_blending,
unsigned resource_id,
const gfx::Transform& matrix) {
diff --git a/chromium/cc/quads/stream_video_draw_quad.h b/chromium/cc/quads/stream_video_draw_quad.h
index e610f4333ce..bc85325cc83 100644
--- a/chromium/cc/quads/stream_video_draw_quad.h
+++ b/chromium/cc/quads/stream_video_draw_quad.h
@@ -17,15 +17,16 @@ class CC_EXPORT StreamVideoDrawQuad : public DrawQuad {
static scoped_ptr<StreamVideoDrawQuad> Create();
void SetNew(const SharedQuadState* shared_quad_state,
- gfx::Rect rect,
- gfx::Rect opaque_rect,
+ const gfx::Rect& rect,
+ const gfx::Rect& opaque_rect,
+ const gfx::Rect& visible_rect,
unsigned resource_id,
const gfx::Transform& matrix);
void SetAll(const SharedQuadState* shared_quad_state,
- gfx::Rect rect,
- gfx::Rect opaque_rect,
- gfx::Rect visible_rect,
+ const gfx::Rect& rect,
+ const gfx::Rect& opaque_rect,
+ const gfx::Rect& visible_rect,
bool needs_blending,
unsigned resource_id,
const gfx::Transform& matrix);
diff --git a/chromium/cc/quads/surface_draw_quad.cc b/chromium/cc/quads/surface_draw_quad.cc
new file mode 100644
index 00000000000..8591261c2de
--- /dev/null
+++ b/chromium/cc/quads/surface_draw_quad.cc
@@ -0,0 +1,54 @@
+// 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/quads/surface_draw_quad.h"
+
+#include "base/logging.h"
+#include "base/values.h"
+
+namespace cc {
+
+SurfaceDrawQuad::SurfaceDrawQuad() {
+}
+
+scoped_ptr<SurfaceDrawQuad> SurfaceDrawQuad::Create() {
+ return make_scoped_ptr(new SurfaceDrawQuad);
+}
+
+void SurfaceDrawQuad::SetNew(const SharedQuadState* shared_quad_state,
+ const gfx::Rect& rect,
+ const gfx::Rect& visible_rect,
+ SurfaceId surface_id) {
+ gfx::Rect opaque_rect;
+ bool needs_blending = false;
+ DrawQuad::SetAll(shared_quad_state, DrawQuad::SURFACE_CONTENT, rect,
+ opaque_rect, visible_rect, needs_blending);
+ this->surface_id = surface_id;
+}
+
+void SurfaceDrawQuad::SetAll(const SharedQuadState* shared_quad_state,
+ const gfx::Rect& rect,
+ const gfx::Rect& opaque_rect,
+ const gfx::Rect& visible_rect,
+ bool needs_blending,
+ SurfaceId surface_id) {
+ DrawQuad::SetAll(shared_quad_state, DrawQuad::SURFACE_CONTENT, rect,
+ opaque_rect, visible_rect, needs_blending);
+ this->surface_id = surface_id;
+}
+
+void SurfaceDrawQuad::IterateResources(
+ const ResourceIteratorCallback& callback) {}
+
+const SurfaceDrawQuad* SurfaceDrawQuad::MaterialCast(const DrawQuad* quad) {
+ DCHECK_EQ(quad->material, DrawQuad::SURFACE_CONTENT);
+ return static_cast<const SurfaceDrawQuad*>(quad);
+}
+
+void SurfaceDrawQuad::ExtendValue(base::DictionaryValue* value) const {
+ value->SetInteger("surface_id", surface_id.id);
+}
+
+
+} // namespace cc
diff --git a/chromium/cc/quads/surface_draw_quad.h b/chromium/cc/quads/surface_draw_quad.h
new file mode 100644
index 00000000000..e182ea3c286
--- /dev/null
+++ b/chromium/cc/quads/surface_draw_quad.h
@@ -0,0 +1,45 @@
+// 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_QUADS_SURFACE_DRAW_QUAD_H_
+#define CC_QUADS_SURFACE_DRAW_QUAD_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "cc/base/cc_export.h"
+#include "cc/quads/draw_quad.h"
+#include "cc/surfaces/surface_id.h"
+
+namespace cc {
+
+class CC_EXPORT SurfaceDrawQuad : public DrawQuad {
+ public:
+ static scoped_ptr<SurfaceDrawQuad> Create();
+
+ void SetNew(const SharedQuadState* shared_quad_state,
+ const gfx::Rect& rect,
+ const gfx::Rect& visible_rect,
+ SurfaceId surface_id);
+
+ void SetAll(const SharedQuadState* shared_quad_state,
+ const gfx::Rect& rect,
+ const gfx::Rect& opaque_rect,
+ const gfx::Rect& visible_rect,
+ bool needs_blending,
+ SurfaceId surface_id);
+
+ SurfaceId surface_id;
+
+ virtual void IterateResources(const ResourceIteratorCallback& callback)
+ OVERRIDE;
+
+ static const SurfaceDrawQuad* MaterialCast(const DrawQuad* quad);
+
+ private:
+ SurfaceDrawQuad();
+ virtual void ExtendValue(base::DictionaryValue* value) const OVERRIDE;
+};
+
+} // namespace cc
+
+#endif // CC_QUADS_SURFACE_DRAW_QUAD_H_
diff --git a/chromium/cc/quads/texture_draw_quad.cc b/chromium/cc/quads/texture_draw_quad.cc
index 191dcc43e7f..fd57feb1ec8 100644
--- a/chromium/cc/quads/texture_draw_quad.cc
+++ b/chromium/cc/quads/texture_draw_quad.cc
@@ -27,14 +27,16 @@ scoped_ptr<TextureDrawQuad> TextureDrawQuad::Create() {
}
void TextureDrawQuad::SetNew(const SharedQuadState* shared_quad_state,
- gfx::Rect rect, gfx::Rect opaque_rect,
- unsigned resource_id, bool premultiplied_alpha,
- gfx::PointF uv_top_left,
- gfx::PointF uv_bottom_right,
+ const gfx::Rect& rect,
+ const gfx::Rect& opaque_rect,
+ const gfx::Rect& visible_rect,
+ unsigned resource_id,
+ bool premultiplied_alpha,
+ const gfx::PointF& uv_top_left,
+ const gfx::PointF& uv_bottom_right,
SkColor background_color,
const float vertex_opacity[4],
bool flipped) {
- gfx::Rect visible_rect = rect;
bool needs_blending = vertex_opacity[0] != 1.0f || vertex_opacity[1] != 1.0f
|| vertex_opacity[2] != 1.0f || vertex_opacity[3] != 1.0f;
DrawQuad::SetAll(shared_quad_state, DrawQuad::TEXTURE_CONTENT, rect,
@@ -52,11 +54,12 @@ void TextureDrawQuad::SetNew(const SharedQuadState* shared_quad_state,
}
void TextureDrawQuad::SetAll(const SharedQuadState* shared_quad_state,
- gfx::Rect rect, gfx::Rect opaque_rect,
- gfx::Rect visible_rect, bool needs_blending,
+ const gfx::Rect& rect,
+ const gfx::Rect& opaque_rect,
+ const gfx::Rect& visible_rect, bool needs_blending,
unsigned resource_id, bool premultiplied_alpha,
- gfx::PointF uv_top_left,
- gfx::PointF uv_bottom_right,
+ const gfx::PointF& uv_top_left,
+ const gfx::PointF& uv_bottom_right,
SkColor background_color,
const float vertex_opacity[4],
bool flipped) {
@@ -90,7 +93,7 @@ void TextureDrawQuad::ExtendValue(base::DictionaryValue* value) const {
value->Set("uv_top_left", MathUtil::AsValue(uv_top_left).release());
value->Set("uv_bottom_right", MathUtil::AsValue(uv_bottom_right).release());
value->SetInteger("background_color", background_color);
- scoped_ptr<ListValue> vertex_opacity_value(new ListValue);
+ scoped_ptr<base::ListValue> vertex_opacity_value(new base::ListValue);
for (size_t i = 0; i < 4; ++i)
vertex_opacity_value->AppendDouble(vertex_opacity[i]);
value->Set("vertex_opacity", vertex_opacity_value.release());
diff --git a/chromium/cc/quads/texture_draw_quad.h b/chromium/cc/quads/texture_draw_quad.h
index 4aa4d7a1642..7fba63493b3 100644
--- a/chromium/cc/quads/texture_draw_quad.h
+++ b/chromium/cc/quads/texture_draw_quad.h
@@ -17,25 +17,26 @@ class CC_EXPORT TextureDrawQuad : public DrawQuad {
static scoped_ptr<TextureDrawQuad> Create();
void SetNew(const SharedQuadState* shared_quad_state,
- gfx::Rect rect,
- gfx::Rect opaque_rect,
+ const gfx::Rect& rect,
+ const gfx::Rect& opaque_rect,
+ const gfx::Rect& visible_rect,
unsigned resource_id,
bool premultiplied_alpha,
- gfx::PointF uv_top_left,
- gfx::PointF uv_bottom_right,
+ const gfx::PointF& uv_top_left,
+ const gfx::PointF& uv_bottom_right,
SkColor background_color,
const float vertex_opacity[4],
bool flipped);
void SetAll(const SharedQuadState* shared_quad_state,
- gfx::Rect rect,
- gfx::Rect opaque_rect,
- gfx::Rect visible_rect,
+ const gfx::Rect& rect,
+ const gfx::Rect& opaque_rect,
+ const gfx::Rect& visible_rect,
bool needs_blending,
unsigned resource_id,
bool premultiplied_alpha,
- gfx::PointF uv_top_left,
- gfx::PointF uv_bottom_right,
+ const gfx::PointF& uv_top_left,
+ const gfx::PointF& uv_bottom_right,
SkColor background_color,
const float vertex_opacity[4],
bool flipped);
diff --git a/chromium/cc/quads/tile_draw_quad.cc b/chromium/cc/quads/tile_draw_quad.cc
index 3ff98095e9f..6e286077ffb 100644
--- a/chromium/cc/quads/tile_draw_quad.cc
+++ b/chromium/cc/quads/tile_draw_quad.cc
@@ -22,26 +22,32 @@ scoped_ptr<TileDrawQuad> TileDrawQuad::Create() {
}
void TileDrawQuad::SetNew(const SharedQuadState* shared_quad_state,
- gfx::Rect rect,
- gfx::Rect opaque_rect,
+ const gfx::Rect& rect,
+ const gfx::Rect& opaque_rect,
+ const gfx::Rect& visible_rect,
unsigned resource_id,
const gfx::RectF& tex_coord_rect,
- gfx::Size texture_size,
+ const gfx::Size& texture_size,
bool swizzle_contents) {
- ContentDrawQuadBase::SetNew(shared_quad_state, DrawQuad::TILED_CONTENT, rect,
- opaque_rect, tex_coord_rect, texture_size,
+ ContentDrawQuadBase::SetNew(shared_quad_state,
+ DrawQuad::TILED_CONTENT,
+ rect,
+ opaque_rect,
+ visible_rect,
+ tex_coord_rect,
+ texture_size,
swizzle_contents);
this->resource_id = resource_id;
}
void TileDrawQuad::SetAll(const SharedQuadState* shared_quad_state,
- gfx::Rect rect,
- gfx::Rect opaque_rect,
- gfx::Rect visible_rect,
+ const gfx::Rect& rect,
+ const gfx::Rect& opaque_rect,
+ const gfx::Rect& visible_rect,
bool needs_blending,
unsigned resource_id,
const gfx::RectF& tex_coord_rect,
- gfx::Size texture_size,
+ const gfx::Size& texture_size,
bool swizzle_contents) {
ContentDrawQuadBase::SetAll(shared_quad_state, DrawQuad::TILED_CONTENT, rect,
opaque_rect, visible_rect, needs_blending,
diff --git a/chromium/cc/quads/tile_draw_quad.h b/chromium/cc/quads/tile_draw_quad.h
index 6da1e54a952..71911ead67e 100644
--- a/chromium/cc/quads/tile_draw_quad.h
+++ b/chromium/cc/quads/tile_draw_quad.h
@@ -15,21 +15,22 @@ class CC_EXPORT TileDrawQuad : public ContentDrawQuadBase {
virtual ~TileDrawQuad();
void SetNew(const SharedQuadState* shared_quad_state,
- gfx::Rect rect,
- gfx::Rect opaque_rect,
+ const gfx::Rect& rect,
+ const gfx::Rect& opaque_rect,
+ const gfx::Rect& visible_rect,
unsigned resource_id,
const gfx::RectF& tex_coord_rect,
- gfx::Size texture_size,
+ const gfx::Size& texture_size,
bool swizzle_contents);
void SetAll(const SharedQuadState* shared_quad_state,
- gfx::Rect rect,
- gfx::Rect opaque_rect,
- gfx::Rect visible_rect,
+ const gfx::Rect& rect,
+ const gfx::Rect& opaque_rect,
+ const gfx::Rect& visible_rect,
bool needs_blending,
unsigned resource_id,
const gfx::RectF& tex_coord_rect,
- gfx::Size texture_size,
+ const gfx::Size& texture_size,
bool swizzle_contents);
unsigned resource_id;
diff --git a/chromium/cc/quads/yuv_video_draw_quad.cc b/chromium/cc/quads/yuv_video_draw_quad.cc
index ecdc78fdcb3..bb8ec739060 100644
--- a/chromium/cc/quads/yuv_video_draw_quad.cc
+++ b/chromium/cc/quads/yuv_video_draw_quad.cc
@@ -22,41 +22,45 @@ scoped_ptr<YUVVideoDrawQuad> YUVVideoDrawQuad::Create() {
}
void YUVVideoDrawQuad::SetNew(const SharedQuadState* shared_quad_state,
- gfx::Rect rect,
- gfx::Rect opaque_rect,
- gfx::SizeF tex_scale,
+ const gfx::Rect& rect,
+ const gfx::Rect& opaque_rect,
+ const gfx::Rect& visible_rect,
+ const gfx::RectF& tex_coord_rect,
unsigned y_plane_resource_id,
unsigned u_plane_resource_id,
unsigned v_plane_resource_id,
- unsigned a_plane_resource_id) {
- gfx::Rect visible_rect = rect;
+ unsigned a_plane_resource_id,
+ ColorSpace color_space) {
bool needs_blending = false;
DrawQuad::SetAll(shared_quad_state, DrawQuad::YUV_VIDEO_CONTENT, rect,
opaque_rect, visible_rect, needs_blending);
- this->tex_scale = tex_scale;
+ this->tex_coord_rect = tex_coord_rect;
this->y_plane_resource_id = y_plane_resource_id;
this->u_plane_resource_id = u_plane_resource_id;
this->v_plane_resource_id = v_plane_resource_id;
this->a_plane_resource_id = a_plane_resource_id;
+ this->color_space = color_space;
}
void YUVVideoDrawQuad::SetAll(const SharedQuadState* shared_quad_state,
- gfx::Rect rect,
- gfx::Rect opaque_rect,
- gfx::Rect visible_rect,
+ const gfx::Rect& rect,
+ const gfx::Rect& opaque_rect,
+ const gfx::Rect& visible_rect,
bool needs_blending,
- gfx::SizeF tex_scale,
+ const gfx::RectF& tex_coord_rect,
unsigned y_plane_resource_id,
unsigned u_plane_resource_id,
unsigned v_plane_resource_id,
- unsigned a_plane_resource_id) {
+ unsigned a_plane_resource_id,
+ ColorSpace color_space) {
DrawQuad::SetAll(shared_quad_state, DrawQuad::YUV_VIDEO_CONTENT, rect,
opaque_rect, visible_rect, needs_blending);
- this->tex_scale = tex_scale;
+ this->tex_coord_rect = tex_coord_rect;
this->y_plane_resource_id = y_plane_resource_id;
this->u_plane_resource_id = u_plane_resource_id;
this->v_plane_resource_id = v_plane_resource_id;
this->a_plane_resource_id = a_plane_resource_id;
+ this->color_space = color_space;
}
void YUVVideoDrawQuad::IterateResources(
@@ -75,7 +79,7 @@ const YUVVideoDrawQuad* YUVVideoDrawQuad::MaterialCast(
}
void YUVVideoDrawQuad::ExtendValue(base::DictionaryValue* value) const {
- value->Set("tex_scale", MathUtil::AsValue(tex_scale).release());
+ value->Set("tex_coord_rect", MathUtil::AsValue(tex_coord_rect).release());
value->SetInteger("y_plane_resource_id", y_plane_resource_id);
value->SetInteger("u_plane_resource_id", u_plane_resource_id);
value->SetInteger("v_plane_resource_id", v_plane_resource_id);
diff --git a/chromium/cc/quads/yuv_video_draw_quad.h b/chromium/cc/quads/yuv_video_draw_quad.h
index aa750fa8ba9..c95681ffa56 100644
--- a/chromium/cc/quads/yuv_video_draw_quad.h
+++ b/chromium/cc/quads/yuv_video_draw_quad.h
@@ -15,35 +15,45 @@ namespace cc {
class CC_EXPORT YUVVideoDrawQuad : public DrawQuad {
public:
+ enum ColorSpace {
+ REC_601, // SDTV standard with restricted "studio swing" color range.
+ REC_601_JPEG, // Full color range [0, 255] variant of the above.
+ COLOR_SPACE_LAST = REC_601_JPEG
+ };
+
virtual ~YUVVideoDrawQuad();
static scoped_ptr<YUVVideoDrawQuad> Create();
void SetNew(const SharedQuadState* shared_quad_state,
- gfx::Rect rect,
- gfx::Rect opaque_rect,
- gfx::SizeF tex_scale,
+ const gfx::Rect& rect,
+ const gfx::Rect& opaque_rect,
+ const gfx::Rect& visible_rect,
+ const gfx::RectF& tex_coord_rect,
unsigned y_plane_resource_id,
unsigned u_plane_resource_id,
unsigned v_plane_resource_id,
- unsigned a_plane_resource_id);
+ unsigned a_plane_resource_id,
+ ColorSpace color_space);
void SetAll(const SharedQuadState* shared_quad_state,
- gfx::Rect rect,
- gfx::Rect opaque_rect,
- gfx::Rect visible_rect,
+ const gfx::Rect& rect,
+ const gfx::Rect& opaque_rect,
+ const gfx::Rect& visible_rect,
bool needs_blending,
- gfx::SizeF tex_scale,
+ const gfx::RectF& tex_coord_rect,
unsigned y_plane_resource_id,
unsigned u_plane_resource_id,
unsigned v_plane_resource_id,
- unsigned a_plane_resource_id);
+ unsigned a_plane_resource_id,
+ ColorSpace color_space);
- gfx::SizeF tex_scale;
+ gfx::RectF tex_coord_rect;
unsigned y_plane_resource_id;
unsigned u_plane_resource_id;
unsigned v_plane_resource_id;
unsigned a_plane_resource_id;
+ ColorSpace color_space;
virtual void IterateResources(const ResourceIteratorCallback& callback)
OVERRIDE;
diff --git a/chromium/cc/resources/bitmap_content_layer_updater.cc b/chromium/cc/resources/bitmap_content_layer_updater.cc
index fd0fbdaf597..fff62cf0aca 100644
--- a/chromium/cc/resources/bitmap_content_layer_updater.cc
+++ b/chromium/cc/resources/bitmap_content_layer_updater.cc
@@ -21,10 +21,11 @@ BitmapContentLayerUpdater::Resource::Resource(
BitmapContentLayerUpdater::Resource::~Resource() {}
-void BitmapContentLayerUpdater::Resource::Update(ResourceUpdateQueue* queue,
- gfx::Rect source_rect,
- gfx::Vector2d dest_offset,
- bool partial_update) {
+void BitmapContentLayerUpdater::Resource::Update(
+ ResourceUpdateQueue* queue,
+ const gfx::Rect& source_rect,
+ const gfx::Vector2d& dest_offset,
+ bool partial_update) {
updater_->UpdateTexture(
queue, texture(), source_rect, dest_offset, partial_update);
}
@@ -54,8 +55,8 @@ scoped_ptr<LayerUpdater::Resource> BitmapContentLayerUpdater::CreateResource(
}
void BitmapContentLayerUpdater::PrepareToUpdate(
- gfx::Rect content_rect,
- gfx::Size tile_size,
+ const gfx::Rect& content_rect,
+ const gfx::Size& tile_size,
float contents_width_scale,
float contents_height_scale,
gfx::Rect* resulting_opaque_rect) {
@@ -63,18 +64,19 @@ void BitmapContentLayerUpdater::PrepareToUpdate(
devtools_instrumentation::ScopedLayerTask paint_setup(
devtools_instrumentation::kPaintSetup, layer_id_);
canvas_size_ = content_rect.size();
- bitmap_backing_.setConfig(
- SkBitmap::kARGB_8888_Config,
- canvas_size_.width(), canvas_size_.height(),
- 0, layer_is_opaque_ ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
- bitmap_backing_.allocPixels();
+ bool alloc = bitmap_backing_.allocN32Pixels(
+ canvas_size_.width(), canvas_size_.height(), layer_is_opaque_);
+ // TODO(danak): Remove when skia does the check for us: crbug.com/360384
+ CHECK(alloc);
canvas_ = skia::AdoptRef(new SkCanvas(bitmap_backing_));
+ DCHECK_EQ(content_rect.width(), canvas_->getBaseLayerSize().width());
+ DCHECK_EQ(content_rect.height(), canvas_->getBaseLayerSize().height());
}
base::TimeTicks start_time =
rendering_stats_instrumentation_->StartRecording();
PaintContents(canvas_.get(),
- content_rect.origin(),
+ content_rect,
contents_width_scale,
contents_height_scale,
resulting_opaque_rect);
@@ -87,16 +89,15 @@ void BitmapContentLayerUpdater::PrepareToUpdate(
void BitmapContentLayerUpdater::UpdateTexture(ResourceUpdateQueue* queue,
PrioritizedResource* texture,
- gfx::Rect source_rect,
- gfx::Vector2d dest_offset,
+ const gfx::Rect& source_rect,
+ const gfx::Vector2d& dest_offset,
bool partial_update) {
CHECK(canvas_);
- ResourceUpdate upload =
- ResourceUpdate::CreateFromCanvas(texture,
- canvas_,
- content_rect(),
- source_rect,
- dest_offset);
+ ResourceUpdate upload = ResourceUpdate::Create(texture,
+ &bitmap_backing_,
+ content_rect(),
+ source_rect,
+ dest_offset);
if (partial_update)
queue->AppendPartialUpload(upload);
else
diff --git a/chromium/cc/resources/bitmap_content_layer_updater.h b/chromium/cc/resources/bitmap_content_layer_updater.h
index ecc0c153b7f..781fc0baa73 100644
--- a/chromium/cc/resources/bitmap_content_layer_updater.h
+++ b/chromium/cc/resources/bitmap_content_layer_updater.h
@@ -18,8 +18,9 @@ class LayerPainter;
class RenderingStatsInstrumenation;
// This class rasterizes the content_rect into a skia bitmap canvas. It then
-// updates textures by copying from the canvas into the texture, using
-// MapSubImage if possible.
+// creates a ResourceUpdate with this bitmap canvas and inserts the
+// ResourceBundle to the provided ResourceUpdateQueue. Actual texture uploading
+// is done by ResourceUpdateController.
class CC_EXPORT BitmapContentLayerUpdater : public ContentLayerUpdater {
public:
class Resource : public LayerUpdater::Resource {
@@ -29,8 +30,8 @@ class CC_EXPORT BitmapContentLayerUpdater : public ContentLayerUpdater {
virtual ~Resource();
virtual void Update(ResourceUpdateQueue* queue,
- gfx::Rect source_rect,
- gfx::Vector2d dest_offset,
+ const gfx::Rect& source_rect,
+ const gfx::Vector2d& dest_offset,
bool partial_update) OVERRIDE;
private:
@@ -46,15 +47,15 @@ class CC_EXPORT BitmapContentLayerUpdater : public ContentLayerUpdater {
virtual scoped_ptr<LayerUpdater::Resource> CreateResource(
PrioritizedResourceManager* manager) OVERRIDE;
- virtual void PrepareToUpdate(gfx::Rect content_rect,
- gfx::Size tile_size,
+ virtual void PrepareToUpdate(const gfx::Rect& content_rect,
+ const gfx::Size& tile_size,
float contents_width_scale,
float contents_height_scale,
gfx::Rect* resulting_opaque_rect) OVERRIDE;
void UpdateTexture(ResourceUpdateQueue* queue,
PrioritizedResource* resource,
- gfx::Rect source_rect,
- gfx::Vector2d dest_offset,
+ const gfx::Rect& source_rect,
+ const gfx::Vector2d& dest_offset,
bool partial_update);
virtual void SetOpaque(bool opaque) OVERRIDE;
virtual void ReduceMemoryUsage() OVERRIDE;
@@ -69,7 +70,6 @@ class CC_EXPORT BitmapContentLayerUpdater : public ContentLayerUpdater {
SkBitmap bitmap_backing_;
skia::RefPtr<SkCanvas> canvas_;
gfx::Size canvas_size_;
- bool opaque_;
private:
DISALLOW_COPY_AND_ASSIGN(BitmapContentLayerUpdater);
diff --git a/chromium/cc/resources/bitmap_skpicture_content_layer_updater.cc b/chromium/cc/resources/bitmap_skpicture_content_layer_updater.cc
index cc839a60eee..21fdbbb72bc 100644
--- a/chromium/cc/resources/bitmap_skpicture_content_layer_updater.cc
+++ b/chromium/cc/resources/bitmap_skpicture_content_layer_updater.cc
@@ -9,7 +9,6 @@
#include "cc/resources/layer_painter.h"
#include "cc/resources/prioritized_resource.h"
#include "cc/resources/resource_update_queue.h"
-#include "third_party/skia/include/core/SkBitmapDevice.h"
#include "third_party/skia/include/core/SkCanvas.h"
namespace cc {
@@ -21,15 +20,14 @@ BitmapSkPictureContentLayerUpdater::Resource::Resource(
void BitmapSkPictureContentLayerUpdater::Resource::Update(
ResourceUpdateQueue* queue,
- gfx::Rect source_rect,
- gfx::Vector2d dest_offset,
+ const gfx::Rect& source_rect,
+ const gfx::Vector2d& dest_offset,
bool partial_update) {
- bitmap_.setConfig(
- SkBitmap::kARGB_8888_Config, source_rect.width(), source_rect.height(), 0,
- updater_->layer_is_opaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
- bitmap_.allocPixels();
- SkBitmapDevice device(bitmap_);
- SkCanvas canvas(&device);
+ SkAlphaType at =
+ updater_->layer_is_opaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
+ bitmap_.allocPixels(SkImageInfo::Make(
+ source_rect.width(), source_rect.height(), kPMColor_SkColorType, at));
+ SkCanvas canvas(bitmap_);
updater_->PaintContentsRect(&canvas, source_rect);
ResourceUpdate upload = ResourceUpdate::Create(
@@ -70,7 +68,9 @@ BitmapSkPictureContentLayerUpdater::CreateResource(
void BitmapSkPictureContentLayerUpdater::PaintContentsRect(
SkCanvas* canvas,
- gfx::Rect source_rect) {
+ const gfx::Rect& source_rect) {
+ if (!canvas)
+ return;
// Translate the origin of content_rect to that of source_rect.
canvas->translate(content_rect().x() - source_rect.x(),
content_rect().y() - source_rect.y());
diff --git a/chromium/cc/resources/bitmap_skpicture_content_layer_updater.h b/chromium/cc/resources/bitmap_skpicture_content_layer_updater.h
index e03f56d853d..e20e3c35c5e 100644
--- a/chromium/cc/resources/bitmap_skpicture_content_layer_updater.h
+++ b/chromium/cc/resources/bitmap_skpicture_content_layer_updater.h
@@ -21,8 +21,8 @@ class BitmapSkPictureContentLayerUpdater : public SkPictureContentLayerUpdater {
scoped_ptr<PrioritizedResource> texture);
virtual void Update(ResourceUpdateQueue* queue,
- gfx::Rect source_rect,
- gfx::Vector2d dest_offset,
+ const gfx::Rect& source_rect,
+ const gfx::Vector2d& dest_offset,
bool partial_update) OVERRIDE;
private:
@@ -40,7 +40,7 @@ class BitmapSkPictureContentLayerUpdater : public SkPictureContentLayerUpdater {
virtual scoped_ptr<LayerUpdater::Resource> CreateResource(
PrioritizedResourceManager* manager) OVERRIDE;
void PaintContentsRect(SkCanvas* canvas,
- gfx::Rect source_rect);
+ const gfx::Rect& source_rect);
private:
BitmapSkPictureContentLayerUpdater(
diff --git a/chromium/cc/resources/caching_bitmap_content_layer_updater.cc b/chromium/cc/resources/caching_bitmap_content_layer_updater.cc
deleted file mode 100644
index f6edb40ccdf..00000000000
--- a/chromium/cc/resources/caching_bitmap_content_layer_updater.cc
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/resources/caching_bitmap_content_layer_updater.h"
-
-#include "base/logging.h"
-#include "cc/resources/layer_painter.h"
-#include "skia/ext/platform_canvas.h"
-
-namespace cc {
-
-scoped_refptr<CachingBitmapContentLayerUpdater>
-CachingBitmapContentLayerUpdater::Create(
- scoped_ptr<LayerPainter> painter,
- RenderingStatsInstrumentation* stats_instrumentation,
- int layer_id) {
- return make_scoped_refptr(
- new CachingBitmapContentLayerUpdater(painter.Pass(),
- stats_instrumentation,
- layer_id));
-}
-
-CachingBitmapContentLayerUpdater::CachingBitmapContentLayerUpdater(
- scoped_ptr<LayerPainter> painter,
- RenderingStatsInstrumentation* stats_instrumentation,
- int layer_id)
- : BitmapContentLayerUpdater(painter.Pass(),
- stats_instrumentation,
- layer_id),
- pixels_did_change_(false) {}
-
-CachingBitmapContentLayerUpdater::~CachingBitmapContentLayerUpdater() {}
-
-void CachingBitmapContentLayerUpdater::PrepareToUpdate(
- gfx::Rect content_rect,
- gfx::Size tile_size,
- float contents_width_scale,
- float contents_height_scale,
- gfx::Rect* resulting_opaque_rect) {
- BitmapContentLayerUpdater::PrepareToUpdate(content_rect,
- tile_size,
- contents_width_scale,
- contents_height_scale,
- resulting_opaque_rect);
-
- const SkBitmap& new_bitmap = canvas_->getDevice()->accessBitmap(false);
- SkAutoLockPixels lock(new_bitmap);
- DCHECK_GT(new_bitmap.bytesPerPixel(), 0);
- pixels_did_change_ = new_bitmap.config() != cached_bitmap_.config() ||
- new_bitmap.height() != cached_bitmap_.height() ||
- new_bitmap.width() != cached_bitmap_.width() ||
- memcmp(new_bitmap.getPixels(),
- cached_bitmap_.getPixels(),
- new_bitmap.getSafeSize());
-
- if (pixels_did_change_)
- new_bitmap.deepCopyTo(&cached_bitmap_, new_bitmap.config());
-}
-
-} // namespace cc
diff --git a/chromium/cc/resources/caching_bitmap_content_layer_updater.h b/chromium/cc/resources/caching_bitmap_content_layer_updater.h
deleted file mode 100644
index 8e9889025c4..00000000000
--- a/chromium/cc/resources/caching_bitmap_content_layer_updater.h
+++ /dev/null
@@ -1,46 +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_RESOURCES_CACHING_BITMAP_CONTENT_LAYER_UPDATER_H_
-#define CC_RESOURCES_CACHING_BITMAP_CONTENT_LAYER_UPDATER_H_
-
-#include "base/compiler_specific.h"
-#include "cc/resources/bitmap_content_layer_updater.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-
-namespace cc {
-
-class CachingBitmapContentLayerUpdater : public BitmapContentLayerUpdater {
- public:
- static scoped_refptr<CachingBitmapContentLayerUpdater> Create(
- scoped_ptr<LayerPainter>,
- RenderingStatsInstrumentation* stats_instrumentation,
- int layer_id);
-
- virtual void PrepareToUpdate(gfx::Rect content_rect,
- gfx::Size tile_size,
- float contents_width_scale,
- float contents_height_scale,
- gfx::Rect* resulting_opaque_rect) OVERRIDE;
-
- bool pixels_did_change() const {
- return pixels_did_change_;
- }
-
- private:
- CachingBitmapContentLayerUpdater(
- scoped_ptr<LayerPainter> painter,
- RenderingStatsInstrumentation* stats_instrumentation,
- int layer_id);
- virtual ~CachingBitmapContentLayerUpdater();
-
- bool pixels_did_change_;
- SkBitmap cached_bitmap_;
-
- DISALLOW_COPY_AND_ASSIGN(CachingBitmapContentLayerUpdater);
-};
-
-} // namespace cc
-
-#endif // CC_RESOURCES_CACHING_BITMAP_CONTENT_LAYER_UPDATER_H_
diff --git a/chromium/cc/resources/content_layer_updater.cc b/chromium/cc/resources/content_layer_updater.cc
index bc6c635dbd0..249a6e92cd8 100644
--- a/chromium/cc/resources/content_layer_updater.cc
+++ b/chromium/cc/resources/content_layer_updater.cc
@@ -9,7 +9,6 @@
#include "cc/debug/rendering_stats_instrumentation.h"
#include "cc/resources/layer_painter.h"
#include "third_party/skia/include/core/SkCanvas.h"
-#include "third_party/skia/include/core/SkDevice.h"
#include "third_party/skia/include/core/SkPaint.h"
#include "third_party/skia/include/core/SkRect.h"
#include "third_party/skia/include/core/SkScalar.h"
@@ -24,8 +23,9 @@ ContentLayerUpdater::ContentLayerUpdater(
int layer_id)
: rendering_stats_instrumentation_(stats_instrumentation),
layer_id_(layer_id),
- painter_(painter.Pass()),
- layer_is_opaque_(false) {}
+ layer_is_opaque_(false),
+ layer_fills_bounds_completely_(false),
+ painter_(painter.Pass()) {}
ContentLayerUpdater::~ContentLayerUpdater() {}
@@ -35,20 +35,22 @@ void ContentLayerUpdater::set_rendering_stats_instrumentation(
}
void ContentLayerUpdater::PaintContents(SkCanvas* canvas,
- gfx::Point origin,
+ const gfx::Rect& content_rect,
float contents_width_scale,
float contents_height_scale,
gfx::Rect* resulting_opaque_rect) {
TRACE_EVENT0("cc", "ContentLayerUpdater::PaintContents");
+ if (!canvas)
+ return;
canvas->save();
- canvas->translate(SkFloatToScalar(-origin.x()),
- SkFloatToScalar(-origin.y()));
+ canvas->translate(SkFloatToScalar(-content_rect.x()),
+ SkFloatToScalar(-content_rect.y()));
- SkBaseDevice* device = canvas->getDevice();
- gfx::Rect content_rect(origin, gfx::Size(device->width(), device->height()));
+ // The |canvas| backing should be sized to hold the |content_rect|.
+ DCHECK_EQ(content_rect.width(), canvas->getBaseLayerSize().width());
+ DCHECK_EQ(content_rect.height(), canvas->getBaseLayerSize().height());
gfx::Rect layer_rect = content_rect;
-
if (contents_width_scale != 1.f || contents_height_scale != 1.f) {
canvas->scale(SkFloatToScalar(contents_width_scale),
SkFloatToScalar(contents_height_scale));
@@ -62,9 +64,9 @@ void ContentLayerUpdater::PaintContents(SkCanvas* canvas,
canvas->clipRect(layer_sk_rect);
- // If the layer has opaque contents then there is no need to
- // clear the canvas before painting.
- if (!layer_is_opaque_) {
+ // If the layer has opaque contents or will fill the bounds completely there
+ // is no need to clear the canvas before painting.
+ if (!layer_is_opaque_ && !layer_fills_bounds_completely_) {
TRACE_EVENT0("cc", "Clear");
canvas->drawColor(SK_ColorTRANSPARENT, SkXfermode::kSrc_Mode);
}
@@ -84,4 +86,8 @@ void ContentLayerUpdater::SetOpaque(bool opaque) {
layer_is_opaque_ = opaque;
}
+void ContentLayerUpdater::SetFillsBoundsCompletely(bool fills_bounds) {
+ layer_fills_bounds_completely_ = fills_bounds;
+}
+
} // namespace cc
diff --git a/chromium/cc/resources/content_layer_updater.h b/chromium/cc/resources/content_layer_updater.h
index 6959526ef1c..7dfcb6a794f 100644
--- a/chromium/cc/resources/content_layer_updater.h
+++ b/chromium/cc/resources/content_layer_updater.h
@@ -22,7 +22,8 @@ class RenderingStatsInstrumentation;
class CC_EXPORT ContentLayerUpdater : public LayerUpdater {
public:
void set_rendering_stats_instrumentation(RenderingStatsInstrumentation* rsi);
- virtual void SetOpaque(bool) OVERRIDE;
+ virtual void SetOpaque(bool opaque) OVERRIDE;
+ virtual void SetFillsBoundsCompletely(bool fills_bounds) OVERRIDE;
protected:
ContentLayerUpdater(scoped_ptr<LayerPainter> painter,
@@ -31,25 +32,29 @@ class CC_EXPORT ContentLayerUpdater : public LayerUpdater {
virtual ~ContentLayerUpdater();
void PaintContents(SkCanvas* canvas,
- gfx::Point origin,
+ const gfx::Rect& content_rect,
float contents_width_scale,
float contents_height_scale,
gfx::Rect* resulting_opaque_rect);
gfx::Rect content_rect() const { return content_rect_; }
bool layer_is_opaque() const { return layer_is_opaque_; }
+ bool layer_fills_bounds_completely() const {
+ return layer_fills_bounds_completely_;
+ }
RenderingStatsInstrumentation* rendering_stats_instrumentation_;
int layer_id_;
+ // True when it is known that all output pixels will be opaque.
+ bool layer_is_opaque_;
+ // True when it is known that all output pixels will be filled.
+ bool layer_fills_bounds_completely_;
+
private:
gfx::Rect content_rect_;
scoped_ptr<LayerPainter> painter_;
- protected:
- // True when it is known that all output pixels will be opaque.
- bool layer_is_opaque_;
-
DISALLOW_COPY_AND_ASSIGN(ContentLayerUpdater);
};
diff --git a/chromium/cc/resources/direct_raster_worker_pool.cc b/chromium/cc/resources/direct_raster_worker_pool.cc
new file mode 100644
index 00000000000..4bd0c55c739
--- /dev/null
+++ b/chromium/cc/resources/direct_raster_worker_pool.cc
@@ -0,0 +1,215 @@
+// 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/resources/direct_raster_worker_pool.h"
+
+#include "base/debug/trace_event.h"
+#include "cc/output/context_provider.h"
+#include "cc/resources/resource.h"
+#include "cc/resources/resource_provider.h"
+#include "gpu/command_buffer/client/gles2_interface.h"
+#include "third_party/skia/include/gpu/GrContext.h"
+
+namespace cc {
+
+// static
+scoped_ptr<RasterWorkerPool> DirectRasterWorkerPool::Create(
+ base::SequencedTaskRunner* task_runner,
+ ResourceProvider* resource_provider,
+ ContextProvider* context_provider) {
+ return make_scoped_ptr<RasterWorkerPool>(new DirectRasterWorkerPool(
+ task_runner, resource_provider, context_provider));
+}
+
+DirectRasterWorkerPool::DirectRasterWorkerPool(
+ base::SequencedTaskRunner* task_runner,
+ ResourceProvider* resource_provider,
+ ContextProvider* context_provider)
+ : task_runner_(task_runner),
+ task_graph_runner_(new TaskGraphRunner),
+ namespace_token_(task_graph_runner_->GetNamespaceToken()),
+ resource_provider_(resource_provider),
+ context_provider_(context_provider),
+ run_tasks_on_origin_thread_pending_(false),
+ raster_tasks_pending_(false),
+ raster_tasks_required_for_activation_pending_(false),
+ raster_finished_weak_ptr_factory_(this),
+ weak_ptr_factory_(this) {}
+
+DirectRasterWorkerPool::~DirectRasterWorkerPool() {
+ DCHECK_EQ(0u, completed_tasks_.size());
+}
+
+Rasterizer* DirectRasterWorkerPool::AsRasterizer() { return this; }
+
+void DirectRasterWorkerPool::SetClient(RasterizerClient* client) {
+ client_ = client;
+}
+
+void DirectRasterWorkerPool::Shutdown() {
+ TRACE_EVENT0("cc", "DirectRasterWorkerPool::Shutdown");
+
+ TaskGraph empty;
+ task_graph_runner_->ScheduleTasks(namespace_token_, &empty);
+ task_graph_runner_->WaitForTasksToFinishRunning(namespace_token_);
+}
+
+void DirectRasterWorkerPool::ScheduleTasks(RasterTaskQueue* queue) {
+ TRACE_EVENT0("cc", "DirectRasterWorkerPool::ScheduleTasks");
+
+ DCHECK_EQ(queue->required_for_activation_count,
+ static_cast<size_t>(
+ std::count_if(queue->items.begin(),
+ queue->items.end(),
+ RasterTaskQueue::Item::IsRequiredForActivation)));
+
+ raster_tasks_pending_ = true;
+ raster_tasks_required_for_activation_pending_ = true;
+
+ unsigned priority = kRasterTaskPriorityBase;
+
+ graph_.Reset();
+
+ // Cancel existing OnRasterFinished callbacks.
+ raster_finished_weak_ptr_factory_.InvalidateWeakPtrs();
+
+ scoped_refptr<RasterizerTask>
+ new_raster_required_for_activation_finished_task(
+ CreateRasterRequiredForActivationFinishedTask(
+ queue->required_for_activation_count,
+ task_runner_.get(),
+ base::Bind(&DirectRasterWorkerPool::
+ OnRasterRequiredForActivationFinished,
+ raster_finished_weak_ptr_factory_.GetWeakPtr())));
+ scoped_refptr<RasterizerTask> new_raster_finished_task(
+ CreateRasterFinishedTask(
+ task_runner_.get(),
+ base::Bind(&DirectRasterWorkerPool::OnRasterFinished,
+ raster_finished_weak_ptr_factory_.GetWeakPtr())));
+
+ for (RasterTaskQueue::Item::Vector::const_iterator it = queue->items.begin();
+ it != queue->items.end();
+ ++it) {
+ const RasterTaskQueue::Item& item = *it;
+ RasterTask* task = item.task;
+ DCHECK(!task->HasCompleted());
+
+ if (item.required_for_activation) {
+ graph_.edges.push_back(TaskGraph::Edge(
+ task, new_raster_required_for_activation_finished_task.get()));
+ }
+
+ InsertNodesForRasterTask(&graph_, task, task->dependencies(), priority++);
+
+ graph_.edges.push_back(
+ TaskGraph::Edge(task, new_raster_finished_task.get()));
+ }
+
+ InsertNodeForTask(&graph_,
+ new_raster_required_for_activation_finished_task.get(),
+ kRasterRequiredForActivationFinishedTaskPriority,
+ queue->required_for_activation_count);
+ InsertNodeForTask(&graph_,
+ new_raster_finished_task.get(),
+ kRasterFinishedTaskPriority,
+ queue->items.size());
+
+ ScheduleTasksOnOriginThread(this, &graph_);
+ task_graph_runner_->ScheduleTasks(namespace_token_, &graph_);
+
+ ScheduleRunTasksOnOriginThread();
+
+ raster_finished_task_ = new_raster_finished_task;
+ raster_required_for_activation_finished_task_ =
+ new_raster_required_for_activation_finished_task;
+}
+
+void DirectRasterWorkerPool::CheckForCompletedTasks() {
+ TRACE_EVENT0("cc", "DirectRasterWorkerPool::CheckForCompletedTasks");
+
+ task_graph_runner_->CollectCompletedTasks(namespace_token_,
+ &completed_tasks_);
+ for (Task::Vector::const_iterator it = completed_tasks_.begin();
+ it != completed_tasks_.end();
+ ++it) {
+ RasterizerTask* task = static_cast<RasterizerTask*>(it->get());
+
+ task->WillComplete();
+ task->CompleteOnOriginThread(this);
+ task->DidComplete();
+
+ task->RunReplyOnOriginThread();
+ }
+ completed_tasks_.clear();
+}
+
+SkCanvas* DirectRasterWorkerPool::AcquireCanvasForRaster(RasterTask* task) {
+ return resource_provider_->MapDirectRasterBuffer(task->resource()->id());
+}
+
+void DirectRasterWorkerPool::ReleaseCanvasForRaster(RasterTask* task) {
+ resource_provider_->UnmapDirectRasterBuffer(task->resource()->id());
+}
+
+void DirectRasterWorkerPool::OnRasterFinished() {
+ TRACE_EVENT0("cc", "DirectRasterWorkerPool::OnRasterFinished");
+
+ DCHECK(raster_tasks_pending_);
+ raster_tasks_pending_ = false;
+ client_->DidFinishRunningTasks();
+}
+
+void DirectRasterWorkerPool::OnRasterRequiredForActivationFinished() {
+ TRACE_EVENT0("cc",
+ "DirectRasterWorkerPool::OnRasterRequiredForActivationFinished");
+
+ DCHECK(raster_tasks_required_for_activation_pending_);
+ raster_tasks_required_for_activation_pending_ = false;
+ client_->DidFinishRunningTasksRequiredForActivation();
+}
+
+void DirectRasterWorkerPool::ScheduleRunTasksOnOriginThread() {
+ if (run_tasks_on_origin_thread_pending_)
+ return;
+
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&DirectRasterWorkerPool::RunTasksOnOriginThread,
+ weak_ptr_factory_.GetWeakPtr()));
+ run_tasks_on_origin_thread_pending_ = true;
+}
+
+void DirectRasterWorkerPool::RunTasksOnOriginThread() {
+ TRACE_EVENT0("cc", "DirectRasterWorkerPool::RunTasksOnOriginThread");
+
+ DCHECK(run_tasks_on_origin_thread_pending_);
+ run_tasks_on_origin_thread_pending_ = false;
+
+ if (context_provider_) {
+ DCHECK(context_provider_->ContextGL());
+ // TODO(alokp): Use a trace macro to push/pop markers.
+ // Using push/pop functions directly incurs cost to evaluate function
+ // arguments even when tracing is disabled.
+ context_provider_->ContextGL()->PushGroupMarkerEXT(
+ 0, "DirectRasterWorkerPool::RunTasksOnOriginThread");
+
+ GrContext* gr_context = context_provider_->GrContext();
+ // TODO(alokp): Implement TestContextProvider::GrContext().
+ if (gr_context)
+ gr_context->resetContext();
+ }
+
+ task_graph_runner_->RunUntilIdle();
+
+ if (context_provider_) {
+ GrContext* gr_context = context_provider_->GrContext();
+ // TODO(alokp): Implement TestContextProvider::GrContext().
+ if (gr_context)
+ gr_context->flush();
+
+ context_provider_->ContextGL()->PopGroupMarkerEXT();
+ }
+}
+
+} // namespace cc
diff --git a/chromium/cc/resources/direct_raster_worker_pool.h b/chromium/cc/resources/direct_raster_worker_pool.h
new file mode 100644
index 00000000000..8194b4f2d6c
--- /dev/null
+++ b/chromium/cc/resources/direct_raster_worker_pool.h
@@ -0,0 +1,81 @@
+// 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_RESOURCES_DIRECT_RASTER_WORKER_POOL_H_
+#define CC_RESOURCES_DIRECT_RASTER_WORKER_POOL_H_
+
+#include "base/memory/weak_ptr.h"
+#include "cc/resources/raster_worker_pool.h"
+#include "cc/resources/rasterizer.h"
+
+namespace cc {
+class ContextProvider;
+class ResourceProvider;
+
+class CC_EXPORT DirectRasterWorkerPool : public RasterWorkerPool,
+ public Rasterizer,
+ public RasterizerTaskClient {
+ public:
+ virtual ~DirectRasterWorkerPool();
+
+ static scoped_ptr<RasterWorkerPool> Create(
+ base::SequencedTaskRunner* task_runner,
+ ResourceProvider* resource_provider,
+ ContextProvider* context_provider);
+
+ // Overridden from RasterWorkerPool:
+ virtual Rasterizer* AsRasterizer() OVERRIDE;
+
+ // Overridden from Rasterizer:
+ virtual void SetClient(RasterizerClient* client) OVERRIDE;
+ virtual void Shutdown() OVERRIDE;
+ virtual void ScheduleTasks(RasterTaskQueue* queue) OVERRIDE;
+ virtual void CheckForCompletedTasks() OVERRIDE;
+
+ // Overridden from RasterizerTaskClient:
+ virtual SkCanvas* AcquireCanvasForRaster(RasterTask* task) OVERRIDE;
+ virtual void ReleaseCanvasForRaster(RasterTask* task) OVERRIDE;
+
+ private:
+ DirectRasterWorkerPool(base::SequencedTaskRunner* task_runner,
+ ResourceProvider* resource_provider,
+ ContextProvider* context_provider);
+
+ void OnRasterFinished();
+ void OnRasterRequiredForActivationFinished();
+ void ScheduleRunTasksOnOriginThread();
+ void RunTasksOnOriginThread();
+ void RunTaskOnOriginThread(RasterizerTask* task);
+
+ scoped_refptr<base::SequencedTaskRunner> task_runner_;
+ scoped_ptr<TaskGraphRunner> task_graph_runner_;
+ const NamespaceToken namespace_token_;
+ RasterizerClient* client_;
+ ResourceProvider* resource_provider_;
+ ContextProvider* context_provider_;
+
+ bool run_tasks_on_origin_thread_pending_;
+
+ bool raster_tasks_pending_;
+ bool raster_tasks_required_for_activation_pending_;
+
+ base::WeakPtrFactory<DirectRasterWorkerPool>
+ raster_finished_weak_ptr_factory_;
+
+ scoped_refptr<RasterizerTask> raster_finished_task_;
+ scoped_refptr<RasterizerTask> raster_required_for_activation_finished_task_;
+
+ // Task graph used when scheduling tasks and vector used to gather
+ // completed tasks.
+ TaskGraph graph_;
+ Task::Vector completed_tasks_;
+
+ base::WeakPtrFactory<DirectRasterWorkerPool> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(DirectRasterWorkerPool);
+};
+
+} // namespace cc
+
+#endif // CC_RESOURCES_DIRECT_RASTER_WORKER_POOL_H_
diff --git a/chromium/cc/resources/etc1_pixel_ref.cc b/chromium/cc/resources/etc1_pixel_ref.cc
deleted file mode 100644
index 7176562317b..00000000000
--- a/chromium/cc/resources/etc1_pixel_ref.cc
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/resources/etc1_pixel_ref.h"
-
-#include "base/memory/scoped_ptr.h"
-#include "third_party/skia/include/core/SkPixelRef.h"
-
-namespace cc {
-
-#ifdef SK_SUPPORT_LEGACY_PIXELREF_CONSTRUCTOR
-// Takes ownership of pixels.
-ETC1PixelRef::ETC1PixelRef(scoped_ptr<uint8_t[]> pixels)
- : pixels_(pixels.Pass()) {
- setImmutable();
-}
-#endif
-
-// Takes ownership of pixels.
-ETC1PixelRef::ETC1PixelRef(const SkImageInfo& info,
- scoped_ptr<uint8_t[]> pixels)
- : SkPixelRef(info), pixels_(pixels.Pass()) {
- setImmutable();
-}
-
-ETC1PixelRef::~ETC1PixelRef() {}
-
-void* ETC1PixelRef::onLockPixels(SkColorTable** color_table) {
- *color_table = NULL;
- return static_cast<void*>(pixels_.get());
-}
-
-void ETC1PixelRef::onUnlockPixels() {}
-
-SkFlattenable::Factory ETC1PixelRef::getFactory() const { return NULL; }
-
-} // namespace cc
diff --git a/chromium/cc/resources/etc1_pixel_ref.h b/chromium/cc/resources/etc1_pixel_ref.h
deleted file mode 100644
index 166e185f533..00000000000
--- a/chromium/cc/resources/etc1_pixel_ref.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CC_RESOURCES_ETC1_PIXEL_REF_H_
-#define CC_RESOURCES_ETC1_PIXEL_REF_H_
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/memory/scoped_ptr.h"
-#include "cc/base/cc_export.h"
-#include "third_party/skia/include/core/SkPixelRef.h"
-
-namespace cc {
-
-class CC_EXPORT ETC1PixelRef : public SkPixelRef {
- public:
-#ifdef SK_SUPPORT_LEGACY_PIXELREF_CONSTRUCTOR
- // DEPRECATED -- will remove once blink updates to pass info
- // TODO(reed)
- explicit ETC1PixelRef(scoped_ptr<uint8_t[]> pixels);
-#endif
-
- // Takes ownership of pixels.
- ETC1PixelRef(const SkImageInfo& info, scoped_ptr<uint8_t[]> pixels);
- virtual ~ETC1PixelRef();
-
- // SK_DECLARE_UNFLATTENABLE_OBJECT
- virtual Factory getFactory() const OVERRIDE;
-
- protected:
- // Implementation of SkPixelRef.
- virtual void* onLockPixels(SkColorTable** color_table) OVERRIDE;
- virtual void onUnlockPixels() OVERRIDE;
-
- private:
- scoped_ptr<uint8_t[]> pixels_;
-
- DISALLOW_COPY_AND_ASSIGN(ETC1PixelRef);
-};
-
-} // namespace cc
-
-#endif // CC_RESOURCES_ETC1_PIXEL_REF_H_
diff --git a/chromium/cc/resources/image_copy_raster_worker_pool.cc b/chromium/cc/resources/image_copy_raster_worker_pool.cc
new file mode 100644
index 00000000000..0d4f7441e52
--- /dev/null
+++ b/chromium/cc/resources/image_copy_raster_worker_pool.cc
@@ -0,0 +1,260 @@
+// 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/resources/image_copy_raster_worker_pool.h"
+
+#include <algorithm>
+
+#include "base/debug/trace_event.h"
+#include "cc/debug/traced_value.h"
+#include "cc/resources/resource_pool.h"
+#include "cc/resources/scoped_resource.h"
+
+namespace cc {
+
+// static
+scoped_ptr<RasterWorkerPool> ImageCopyRasterWorkerPool::Create(
+ base::SequencedTaskRunner* task_runner,
+ TaskGraphRunner* task_graph_runner,
+ ResourceProvider* resource_provider,
+ ResourcePool* resource_pool) {
+ return make_scoped_ptr<RasterWorkerPool>(new ImageCopyRasterWorkerPool(
+ task_runner, task_graph_runner, resource_provider, resource_pool));
+}
+
+ImageCopyRasterWorkerPool::ImageCopyRasterWorkerPool(
+ base::SequencedTaskRunner* task_runner,
+ TaskGraphRunner* task_graph_runner,
+ ResourceProvider* resource_provider,
+ ResourcePool* resource_pool)
+ : task_runner_(task_runner),
+ task_graph_runner_(task_graph_runner),
+ namespace_token_(task_graph_runner->GetNamespaceToken()),
+ resource_provider_(resource_provider),
+ resource_pool_(resource_pool),
+ has_performed_copy_since_last_flush_(false),
+ raster_tasks_pending_(false),
+ raster_tasks_required_for_activation_pending_(false),
+ raster_finished_weak_ptr_factory_(this) {}
+
+ImageCopyRasterWorkerPool::~ImageCopyRasterWorkerPool() {
+ DCHECK_EQ(0u, raster_task_states_.size());
+}
+
+Rasterizer* ImageCopyRasterWorkerPool::AsRasterizer() { return this; }
+
+void ImageCopyRasterWorkerPool::SetClient(RasterizerClient* client) {
+ client_ = client;
+}
+
+void ImageCopyRasterWorkerPool::Shutdown() {
+ TRACE_EVENT0("cc", "ImageCopyRasterWorkerPool::Shutdown");
+
+ TaskGraph empty;
+ task_graph_runner_->ScheduleTasks(namespace_token_, &empty);
+ task_graph_runner_->WaitForTasksToFinishRunning(namespace_token_);
+}
+
+void ImageCopyRasterWorkerPool::ScheduleTasks(RasterTaskQueue* queue) {
+ TRACE_EVENT0("cc", "ImageCopyRasterWorkerPool::ScheduleTasks");
+
+ DCHECK_EQ(queue->required_for_activation_count,
+ static_cast<size_t>(
+ std::count_if(queue->items.begin(),
+ queue->items.end(),
+ RasterTaskQueue::Item::IsRequiredForActivation)));
+
+ if (!raster_tasks_pending_)
+ TRACE_EVENT_ASYNC_BEGIN0("cc", "ScheduledTasks", this);
+
+ raster_tasks_pending_ = true;
+ raster_tasks_required_for_activation_pending_ = true;
+
+ unsigned priority = kRasterTaskPriorityBase;
+
+ graph_.Reset();
+
+ // Cancel existing OnRasterFinished callbacks.
+ raster_finished_weak_ptr_factory_.InvalidateWeakPtrs();
+
+ scoped_refptr<RasterizerTask>
+ new_raster_required_for_activation_finished_task(
+ CreateRasterRequiredForActivationFinishedTask(
+ queue->required_for_activation_count,
+ task_runner_.get(),
+ base::Bind(&ImageCopyRasterWorkerPool::
+ OnRasterRequiredForActivationFinished,
+ raster_finished_weak_ptr_factory_.GetWeakPtr())));
+ scoped_refptr<RasterizerTask> new_raster_finished_task(
+ CreateRasterFinishedTask(
+ task_runner_.get(),
+ base::Bind(&ImageCopyRasterWorkerPool::OnRasterFinished,
+ raster_finished_weak_ptr_factory_.GetWeakPtr())));
+
+ resource_pool_->CheckBusyResources();
+
+ for (RasterTaskQueue::Item::Vector::const_iterator it = queue->items.begin();
+ it != queue->items.end();
+ ++it) {
+ const RasterTaskQueue::Item& item = *it;
+ RasterTask* task = item.task;
+ DCHECK(!task->HasCompleted());
+
+ if (item.required_for_activation) {
+ graph_.edges.push_back(TaskGraph::Edge(
+ task, new_raster_required_for_activation_finished_task.get()));
+ }
+
+ InsertNodesForRasterTask(&graph_, task, task->dependencies(), priority++);
+
+ graph_.edges.push_back(
+ TaskGraph::Edge(task, new_raster_finished_task.get()));
+ }
+
+ InsertNodeForTask(&graph_,
+ new_raster_required_for_activation_finished_task.get(),
+ kRasterRequiredForActivationFinishedTaskPriority,
+ queue->required_for_activation_count);
+ InsertNodeForTask(&graph_,
+ new_raster_finished_task.get(),
+ kRasterFinishedTaskPriority,
+ queue->items.size());
+
+ ScheduleTasksOnOriginThread(this, &graph_);
+ task_graph_runner_->ScheduleTasks(namespace_token_, &graph_);
+
+ raster_finished_task_ = new_raster_finished_task;
+ raster_required_for_activation_finished_task_ =
+ new_raster_required_for_activation_finished_task;
+
+ resource_pool_->ReduceResourceUsage();
+
+ TRACE_EVENT_ASYNC_STEP_INTO1(
+ "cc",
+ "ScheduledTasks",
+ this,
+ "rasterizing",
+ "state",
+ TracedValue::FromValue(StateAsValue().release()));
+}
+
+void ImageCopyRasterWorkerPool::CheckForCompletedTasks() {
+ TRACE_EVENT0("cc", "ImageCopyRasterWorkerPool::CheckForCompletedTasks");
+
+ task_graph_runner_->CollectCompletedTasks(namespace_token_,
+ &completed_tasks_);
+ for (Task::Vector::const_iterator it = completed_tasks_.begin();
+ it != completed_tasks_.end();
+ ++it) {
+ RasterizerTask* task = static_cast<RasterizerTask*>(it->get());
+
+ task->WillComplete();
+ task->CompleteOnOriginThread(this);
+ task->DidComplete();
+
+ task->RunReplyOnOriginThread();
+ }
+ completed_tasks_.clear();
+
+ FlushCopies();
+}
+
+SkCanvas* ImageCopyRasterWorkerPool::AcquireCanvasForRaster(RasterTask* task) {
+ DCHECK_EQ(task->resource()->format(), resource_pool_->resource_format());
+ scoped_ptr<ScopedResource> resource(
+ resource_pool_->AcquireResource(task->resource()->size()));
+ SkCanvas* canvas = resource_provider_->MapImageRasterBuffer(resource->id());
+ DCHECK(std::find_if(raster_task_states_.begin(),
+ raster_task_states_.end(),
+ RasterTaskState::TaskComparator(task)) ==
+ raster_task_states_.end());
+ raster_task_states_.push_back(RasterTaskState(task, resource.release()));
+ return canvas;
+}
+
+void ImageCopyRasterWorkerPool::ReleaseCanvasForRaster(RasterTask* task) {
+ RasterTaskState::Vector::iterator it =
+ std::find_if(raster_task_states_.begin(),
+ raster_task_states_.end(),
+ RasterTaskState::TaskComparator(task));
+ DCHECK(it != raster_task_states_.end());
+ scoped_ptr<ScopedResource> resource(it->resource);
+ std::swap(*it, raster_task_states_.back());
+ raster_task_states_.pop_back();
+
+ bool content_has_changed =
+ resource_provider_->UnmapImageRasterBuffer(resource->id());
+
+ // |content_has_changed| can be false as result of task being canceled or
+ // task implementation deciding not to modify bitmap (ie. analysis of raster
+ // commands detected content as a solid color).
+ if (content_has_changed) {
+ resource_provider_->CopyResource(resource->id(), task->resource()->id());
+ has_performed_copy_since_last_flush_ = true;
+ }
+
+ resource_pool_->ReleaseResource(resource.Pass());
+}
+
+void ImageCopyRasterWorkerPool::OnRasterFinished() {
+ TRACE_EVENT0("cc", "ImageCopyRasterWorkerPool::OnRasterFinished");
+
+ DCHECK(raster_tasks_pending_);
+ raster_tasks_pending_ = false;
+ TRACE_EVENT_ASYNC_END0("cc", "ScheduledTasks", this);
+ client_->DidFinishRunningTasks();
+}
+
+void ImageCopyRasterWorkerPool::OnRasterRequiredForActivationFinished() {
+ TRACE_EVENT0(
+ "cc", "ImageCopyRasterWorkerPool::OnRasterRequiredForActivationFinished");
+
+ DCHECK(raster_tasks_required_for_activation_pending_);
+ raster_tasks_required_for_activation_pending_ = false;
+ TRACE_EVENT_ASYNC_STEP_INTO1(
+ "cc",
+ "ScheduledTasks",
+ this,
+ "rasterizing",
+ "state",
+ TracedValue::FromValue(StateAsValue().release()));
+ client_->DidFinishRunningTasksRequiredForActivation();
+}
+
+void ImageCopyRasterWorkerPool::FlushCopies() {
+ if (!has_performed_copy_since_last_flush_)
+ return;
+
+ resource_provider_->ShallowFlushIfSupported();
+ has_performed_copy_since_last_flush_ = false;
+}
+
+scoped_ptr<base::Value> ImageCopyRasterWorkerPool::StateAsValue() const {
+ scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue);
+
+ state->SetInteger("pending_count", raster_task_states_.size());
+ state->SetBoolean("tasks_required_for_activation_pending",
+ raster_tasks_required_for_activation_pending_);
+ state->Set("staging_state", StagingStateAsValue().release());
+
+ return state.PassAs<base::Value>();
+}
+scoped_ptr<base::Value> ImageCopyRasterWorkerPool::StagingStateAsValue() const {
+ scoped_ptr<base::DictionaryValue> staging_state(new base::DictionaryValue);
+
+ staging_state->SetInteger("staging_resource_count",
+ resource_pool_->total_resource_count());
+ staging_state->SetInteger("bytes_used_for_staging_resources",
+ resource_pool_->total_memory_usage_bytes());
+ staging_state->SetInteger("pending_copy_count",
+ resource_pool_->total_resource_count() -
+ resource_pool_->acquired_resource_count());
+ staging_state->SetInteger("bytes_pending_copy",
+ resource_pool_->total_memory_usage_bytes() -
+ resource_pool_->acquired_memory_usage_bytes());
+
+ return staging_state.PassAs<base::Value>();
+}
+
+} // namespace cc
diff --git a/chromium/cc/resources/image_copy_raster_worker_pool.h b/chromium/cc/resources/image_copy_raster_worker_pool.h
new file mode 100644
index 00000000000..cb243daca38
--- /dev/null
+++ b/chromium/cc/resources/image_copy_raster_worker_pool.h
@@ -0,0 +1,110 @@
+// 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_RESOURCES_IMAGE_COPY_RASTER_WORKER_POOL_H_
+#define CC_RESOURCES_IMAGE_COPY_RASTER_WORKER_POOL_H_
+
+#include <vector>
+
+#include "base/memory/weak_ptr.h"
+#include "base/values.h"
+#include "cc/resources/raster_worker_pool.h"
+#include "cc/resources/rasterizer.h"
+
+namespace cc {
+class ResourcePool;
+class ResourceProvider;
+class ScopedResource;
+
+class CC_EXPORT ImageCopyRasterWorkerPool : public RasterWorkerPool,
+ public Rasterizer,
+ public RasterizerTaskClient {
+ public:
+ virtual ~ImageCopyRasterWorkerPool();
+
+ static scoped_ptr<RasterWorkerPool> Create(
+ base::SequencedTaskRunner* task_runner,
+ TaskGraphRunner* task_graph_runner,
+ ResourceProvider* resource_provider,
+ ResourcePool* resource_pool);
+
+ // Overridden from RasterWorkerPool:
+ virtual Rasterizer* AsRasterizer() OVERRIDE;
+
+ // Overridden from Rasterizer:
+ virtual void SetClient(RasterizerClient* client) OVERRIDE;
+ virtual void Shutdown() OVERRIDE;
+ virtual void ScheduleTasks(RasterTaskQueue* queue) OVERRIDE;
+ virtual void CheckForCompletedTasks() OVERRIDE;
+
+ // Overridden from RasterizerTaskClient:
+ virtual SkCanvas* AcquireCanvasForRaster(RasterTask* task) OVERRIDE;
+ virtual void ReleaseCanvasForRaster(RasterTask* task) OVERRIDE;
+
+ protected:
+ ImageCopyRasterWorkerPool(base::SequencedTaskRunner* task_runner,
+ TaskGraphRunner* task_graph_runner,
+ ResourceProvider* resource_provider,
+ ResourcePool* resource_pool);
+
+ private:
+ struct RasterTaskState {
+ class TaskComparator {
+ public:
+ explicit TaskComparator(const RasterTask* task) : task_(task) {}
+
+ bool operator()(const RasterTaskState& state) const {
+ return state.task == task_;
+ }
+
+ private:
+ const RasterTask* task_;
+ };
+
+ typedef std::vector<RasterTaskState> Vector;
+
+ RasterTaskState(const RasterTask* task, ScopedResource* resource)
+ : task(task), resource(resource) {}
+
+ const RasterTask* task;
+ ScopedResource* resource;
+ };
+
+ void OnRasterFinished();
+ void OnRasterRequiredForActivationFinished();
+ void FlushCopies();
+ scoped_ptr<base::Value> StateAsValue() const;
+ scoped_ptr<base::Value> StagingStateAsValue() const;
+
+ scoped_refptr<base::SequencedTaskRunner> task_runner_;
+ TaskGraphRunner* task_graph_runner_;
+ const NamespaceToken namespace_token_;
+ RasterizerClient* client_;
+ ResourceProvider* resource_provider_;
+ ResourcePool* resource_pool_;
+
+ RasterTaskState::Vector raster_task_states_;
+
+ bool has_performed_copy_since_last_flush_;
+
+ bool raster_tasks_pending_;
+ bool raster_tasks_required_for_activation_pending_;
+
+ base::WeakPtrFactory<ImageCopyRasterWorkerPool>
+ raster_finished_weak_ptr_factory_;
+
+ scoped_refptr<RasterizerTask> raster_finished_task_;
+ scoped_refptr<RasterizerTask> raster_required_for_activation_finished_task_;
+
+ // Task graph used when scheduling tasks and vector used to gather
+ // completed tasks.
+ TaskGraph graph_;
+ Task::Vector completed_tasks_;
+
+ DISALLOW_COPY_AND_ASSIGN(ImageCopyRasterWorkerPool);
+};
+
+} // namespace cc
+
+#endif // CC_RESOURCES_IMAGE_COPY_RASTER_WORKER_POOL_H_
diff --git a/chromium/cc/resources/image_layer_updater.cc b/chromium/cc/resources/image_layer_updater.cc
index 470f518b424..d5d62ed5e97 100644
--- a/chromium/cc/resources/image_layer_updater.cc
+++ b/chromium/cc/resources/image_layer_updater.cc
@@ -15,8 +15,8 @@ ImageLayerUpdater::Resource::Resource(ImageLayerUpdater* updater,
ImageLayerUpdater::Resource::~Resource() {}
void ImageLayerUpdater::Resource::Update(ResourceUpdateQueue* queue,
- gfx::Rect source_rect,
- gfx::Vector2d dest_offset,
+ const gfx::Rect& source_rect,
+ const gfx::Vector2d& dest_offset,
bool partial_update) {
updater_->UpdateTexture(
queue, texture(), source_rect, dest_offset, partial_update);
@@ -35,8 +35,8 @@ scoped_ptr<LayerUpdater::Resource> ImageLayerUpdater::CreateResource(
void ImageLayerUpdater::UpdateTexture(ResourceUpdateQueue* queue,
PrioritizedResource* texture,
- gfx::Rect source_rect,
- gfx::Vector2d dest_offset,
+ const gfx::Rect& source_rect,
+ const gfx::Vector2d& dest_offset,
bool partial_update) {
// Source rect should never go outside the image pixels, even if this
// is requested because the texture extends outside the image.
diff --git a/chromium/cc/resources/image_layer_updater.h b/chromium/cc/resources/image_layer_updater.h
index 44e541d77be..b2235b18031 100644
--- a/chromium/cc/resources/image_layer_updater.h
+++ b/chromium/cc/resources/image_layer_updater.h
@@ -22,8 +22,8 @@ class CC_EXPORT ImageLayerUpdater : public LayerUpdater {
virtual ~Resource();
virtual void Update(ResourceUpdateQueue* queue,
- gfx::Rect source_rect,
- gfx::Vector2d dest_offset,
+ const gfx::Rect& source_rect,
+ const gfx::Vector2d& dest_offset,
bool partial_update) OVERRIDE;
private:
@@ -39,8 +39,8 @@ class CC_EXPORT ImageLayerUpdater : public LayerUpdater {
void UpdateTexture(ResourceUpdateQueue* queue,
PrioritizedResource* texture,
- gfx::Rect source_rect,
- gfx::Vector2d dest_offset,
+ const gfx::Rect& source_rect,
+ const gfx::Vector2d& dest_offset,
bool partial_update);
void SetBitmap(const SkBitmap& bitmap);
diff --git a/chromium/cc/resources/image_raster_worker_pool.cc b/chromium/cc/resources/image_raster_worker_pool.cc
index 90572ab417d..007c1ed83f3 100644
--- a/chromium/cc/resources/image_raster_worker_pool.cc
+++ b/chromium/cc/resources/image_raster_worker_pool.cc
@@ -5,75 +5,56 @@
#include "cc/resources/image_raster_worker_pool.h"
#include "base/debug/trace_event.h"
-#include "base/values.h"
#include "cc/debug/traced_value.h"
#include "cc/resources/resource.h"
-#include "third_party/skia/include/core/SkBitmapDevice.h"
namespace cc {
-namespace {
-
-class ImageWorkerPoolTaskImpl : public internal::WorkerPoolTask {
- public:
- typedef base::Callback<void(bool was_canceled)> Reply;
-
- ImageWorkerPoolTaskImpl(internal::RasterWorkerPoolTask* task,
- uint8_t* buffer,
- int stride,
- const Reply& reply)
- : task_(task),
- buffer_(buffer),
- stride_(stride),
- reply_(reply) {
- }
-
- // Overridden from internal::WorkerPoolTask:
- virtual void RunOnWorkerThread(unsigned thread_index) OVERRIDE {
- TRACE_EVENT0("cc", "ImageWorkerPoolTaskImpl::RunOnWorkerThread");
- if (!buffer_)
- return;
-
- task_->RunOnWorkerThread(thread_index,
- buffer_,
- task_->resource()->size(),
- stride_);
- }
- virtual void CompleteOnOriginThread() OVERRIDE {
- reply_.Run(!HasFinishedRunning());
- }
-
- private:
- virtual ~ImageWorkerPoolTaskImpl() {}
+// static
+scoped_ptr<RasterWorkerPool> ImageRasterWorkerPool::Create(
+ base::SequencedTaskRunner* task_runner,
+ TaskGraphRunner* task_graph_runner,
+ ResourceProvider* resource_provider) {
+ return make_scoped_ptr<RasterWorkerPool>(new ImageRasterWorkerPool(
+ task_runner, task_graph_runner, resource_provider));
+}
- scoped_refptr<internal::RasterWorkerPoolTask> task_;
- uint8_t* buffer_;
- int stride_;
- const Reply reply_;
+ImageRasterWorkerPool::ImageRasterWorkerPool(
+ base::SequencedTaskRunner* task_runner,
+ TaskGraphRunner* task_graph_runner,
+ ResourceProvider* resource_provider)
+ : task_runner_(task_runner),
+ task_graph_runner_(task_graph_runner),
+ namespace_token_(task_graph_runner->GetNamespaceToken()),
+ resource_provider_(resource_provider),
+ raster_tasks_pending_(false),
+ raster_tasks_required_for_activation_pending_(false),
+ raster_finished_weak_ptr_factory_(this) {}
- DISALLOW_COPY_AND_ASSIGN(ImageWorkerPoolTaskImpl);
-};
+ImageRasterWorkerPool::~ImageRasterWorkerPool() {}
-} // namespace
+Rasterizer* ImageRasterWorkerPool::AsRasterizer() { return this; }
-ImageRasterWorkerPool::ImageRasterWorkerPool(
- ResourceProvider* resource_provider,
- size_t num_threads,
- GLenum texture_target)
- : RasterWorkerPool(resource_provider, num_threads),
- texture_target_(texture_target),
- raster_tasks_pending_(false),
- raster_tasks_required_for_activation_pending_(false) {
+void ImageRasterWorkerPool::SetClient(RasterizerClient* client) {
+ client_ = client;
}
-ImageRasterWorkerPool::~ImageRasterWorkerPool() {
- DCHECK_EQ(0u, image_tasks_.size());
+void ImageRasterWorkerPool::Shutdown() {
+ TRACE_EVENT0("cc", "ImageRasterWorkerPool::Shutdown");
+
+ TaskGraph empty;
+ task_graph_runner_->ScheduleTasks(namespace_token_, &empty);
+ task_graph_runner_->WaitForTasksToFinishRunning(namespace_token_);
}
-void ImageRasterWorkerPool::ScheduleTasks(RasterTask::Queue* queue) {
+void ImageRasterWorkerPool::ScheduleTasks(RasterTaskQueue* queue) {
TRACE_EVENT0("cc", "ImageRasterWorkerPool::ScheduleTasks");
- RasterWorkerPool::SetRasterTasks(queue);
+ DCHECK_EQ(queue->required_for_activation_count,
+ static_cast<size_t>(
+ std::count_if(queue->items.begin(),
+ queue->items.end(),
+ RasterTaskQueue::Item::IsRequiredForActivation)));
if (!raster_tasks_pending_)
TRACE_EVENT_ASYNC_BEGIN0("cc", "ScheduledTasks", this);
@@ -81,123 +62,125 @@ void ImageRasterWorkerPool::ScheduleTasks(RasterTask::Queue* queue) {
raster_tasks_pending_ = true;
raster_tasks_required_for_activation_pending_ = true;
- unsigned priority = 0u;
- TaskGraph graph;
+ unsigned priority = kRasterTaskPriorityBase;
- scoped_refptr<internal::WorkerPoolTask>
+ graph_.Reset();
+
+ // Cancel existing OnRasterFinished callbacks.
+ raster_finished_weak_ptr_factory_.InvalidateWeakPtrs();
+
+ scoped_refptr<RasterizerTask>
new_raster_required_for_activation_finished_task(
- CreateRasterRequiredForActivationFinishedTask());
- internal::GraphNode* raster_required_for_activation_finished_node =
- CreateGraphNodeForTask(
- new_raster_required_for_activation_finished_task.get(),
- priority++,
- &graph);
-
- scoped_refptr<internal::WorkerPoolTask> new_raster_finished_task(
- CreateRasterFinishedTask());
- internal::GraphNode* raster_finished_node =
- CreateGraphNodeForTask(new_raster_finished_task.get(),
- priority++,
- &graph);
-
- for (RasterTaskVector::const_iterator it = raster_tasks().begin();
- it != raster_tasks().end(); ++it) {
- internal::RasterWorkerPoolTask* task = it->get();
+ CreateRasterRequiredForActivationFinishedTask(
+ queue->required_for_activation_count,
+ task_runner_.get(),
+ base::Bind(
+ &ImageRasterWorkerPool::OnRasterRequiredForActivationFinished,
+ raster_finished_weak_ptr_factory_.GetWeakPtr())));
+ scoped_refptr<RasterizerTask> new_raster_finished_task(
+ CreateRasterFinishedTask(
+ task_runner_.get(),
+ base::Bind(&ImageRasterWorkerPool::OnRasterFinished,
+ raster_finished_weak_ptr_factory_.GetWeakPtr())));
+
+ for (RasterTaskQueue::Item::Vector::const_iterator it = queue->items.begin();
+ it != queue->items.end();
+ ++it) {
+ const RasterTaskQueue::Item& item = *it;
+ RasterTask* task = item.task;
DCHECK(!task->HasCompleted());
- DCHECK(!task->WasCanceled());
-
- TaskMap::iterator image_it = image_tasks_.find(task);
- if (image_it != image_tasks_.end()) {
- internal::WorkerPoolTask* image_task = image_it->second.get();
- CreateGraphNodeForImageTask(
- image_task,
- task->dependencies(),
- priority++,
- IsRasterTaskRequiredForActivation(task),
- raster_required_for_activation_finished_node,
- raster_finished_node,
- &graph);
- continue;
+
+ if (item.required_for_activation) {
+ graph_.edges.push_back(TaskGraph::Edge(
+ task, new_raster_required_for_activation_finished_task.get()));
}
- // Acquire image for resource.
- resource_provider()->AcquireImage(task->resource()->id());
-
- // Map image for raster.
- uint8* buffer = resource_provider()->MapImage(task->resource()->id());
- int stride = resource_provider()->GetImageStride(task->resource()->id());
-
- scoped_refptr<internal::WorkerPoolTask> new_image_task(
- new ImageWorkerPoolTaskImpl(
- task,
- buffer,
- stride,
- base::Bind(&ImageRasterWorkerPool::OnRasterTaskCompleted,
- base::Unretained(this),
- make_scoped_refptr(task))));
- image_tasks_[task] = new_image_task;
- CreateGraphNodeForImageTask(
- new_image_task.get(),
- task->dependencies(),
- priority++,
- IsRasterTaskRequiredForActivation(task),
- raster_required_for_activation_finished_node,
- raster_finished_node,
- &graph);
+ InsertNodesForRasterTask(&graph_, task, task->dependencies(), priority++);
+
+ graph_.edges.push_back(
+ TaskGraph::Edge(task, new_raster_finished_task.get()));
}
- SetTaskGraph(&graph);
+ InsertNodeForTask(&graph_,
+ new_raster_required_for_activation_finished_task.get(),
+ kRasterRequiredForActivationFinishedTaskPriority,
+ queue->required_for_activation_count);
+ InsertNodeForTask(&graph_,
+ new_raster_finished_task.get(),
+ kRasterFinishedTaskPriority,
+ queue->items.size());
+
+ ScheduleTasksOnOriginThread(this, &graph_);
+ task_graph_runner_->ScheduleTasks(namespace_token_, &graph_);
- set_raster_finished_task(new_raster_finished_task);
- set_raster_required_for_activation_finished_task(
- new_raster_required_for_activation_finished_task);
+ raster_finished_task_ = new_raster_finished_task;
+ raster_required_for_activation_finished_task_ =
+ new_raster_required_for_activation_finished_task;
TRACE_EVENT_ASYNC_STEP_INTO1(
- "cc", "ScheduledTasks", this, "rasterizing",
- "state", TracedValue::FromValue(StateAsValue().release()));
+ "cc",
+ "ScheduledTasks",
+ this,
+ "rasterizing",
+ "state",
+ TracedValue::FromValue(StateAsValue().release()));
}
-GLenum ImageRasterWorkerPool::GetResourceTarget() const {
- return texture_target_;
+void ImageRasterWorkerPool::CheckForCompletedTasks() {
+ TRACE_EVENT0("cc", "ImageRasterWorkerPool::CheckForCompletedTasks");
+
+ task_graph_runner_->CollectCompletedTasks(namespace_token_,
+ &completed_tasks_);
+ for (Task::Vector::const_iterator it = completed_tasks_.begin();
+ it != completed_tasks_.end();
+ ++it) {
+ RasterizerTask* task = static_cast<RasterizerTask*>(it->get());
+
+ task->WillComplete();
+ task->CompleteOnOriginThread(this);
+ task->DidComplete();
+
+ task->RunReplyOnOriginThread();
+ }
+ completed_tasks_.clear();
+}
+
+SkCanvas* ImageRasterWorkerPool::AcquireCanvasForRaster(RasterTask* task) {
+ return resource_provider_->MapImageRasterBuffer(task->resource()->id());
}
-ResourceFormat ImageRasterWorkerPool::GetResourceFormat() const {
- return resource_provider()->best_texture_format();
+void ImageRasterWorkerPool::ReleaseCanvasForRaster(RasterTask* task) {
+ resource_provider_->UnmapImageRasterBuffer(task->resource()->id());
+
+ // Map/UnmapImageRasterBuffer provides direct access to the memory used by the
+ // GPU. Read lock fences are required to ensure that we're not trying to map a
+ // resource that is currently in-use by the GPU.
+ resource_provider_->EnableReadLockFences(task->resource()->id(), true);
}
-void ImageRasterWorkerPool::OnRasterTasksFinished() {
+void ImageRasterWorkerPool::OnRasterFinished() {
+ TRACE_EVENT0("cc", "ImageRasterWorkerPool::OnRasterFinished");
+
DCHECK(raster_tasks_pending_);
raster_tasks_pending_ = false;
TRACE_EVENT_ASYNC_END0("cc", "ScheduledTasks", this);
- client()->DidFinishRunningTasks();
+ client_->DidFinishRunningTasks();
}
-void ImageRasterWorkerPool::OnRasterTasksRequiredForActivationFinished() {
+void ImageRasterWorkerPool::OnRasterRequiredForActivationFinished() {
+ TRACE_EVENT0("cc",
+ "ImageRasterWorkerPool::OnRasterRequiredForActivationFinished");
+
DCHECK(raster_tasks_required_for_activation_pending_);
raster_tasks_required_for_activation_pending_ = false;
TRACE_EVENT_ASYNC_STEP_INTO1(
- "cc", "ScheduledTasks", this, "rasterizing",
- "state", TracedValue::FromValue(StateAsValue().release()));
- client()->DidFinishRunningTasksRequiredForActivation();
-}
-
-void ImageRasterWorkerPool::OnRasterTaskCompleted(
- scoped_refptr<internal::RasterWorkerPoolTask> task,
- bool was_canceled) {
- TRACE_EVENT1("cc", "ImageRasterWorkerPool::OnRasterTaskCompleted",
- "was_canceled", was_canceled);
-
- DCHECK(image_tasks_.find(task.get()) != image_tasks_.end());
-
- // Balanced with MapImage() call in ScheduleTasks().
- resource_provider()->UnmapImage(task->resource()->id());
-
- task->DidRun(was_canceled);
- task->WillComplete();
- task->CompleteOnOriginThread();
- task->DidComplete();
-
- image_tasks_.erase(task.get());
+ "cc",
+ "ScheduledTasks",
+ this,
+ "rasterizing",
+ "state",
+ TracedValue::FromValue(StateAsValue().release()));
+ client_->DidFinishRunningTasksRequiredForActivation();
}
scoped_ptr<base::Value> ImageRasterWorkerPool::StateAsValue() const {
@@ -205,31 +188,7 @@ scoped_ptr<base::Value> ImageRasterWorkerPool::StateAsValue() const {
state->SetBoolean("tasks_required_for_activation_pending",
raster_tasks_required_for_activation_pending_);
- state->Set("scheduled_state", ScheduledStateAsValue().release());
return state.PassAs<base::Value>();
}
-// static
-void ImageRasterWorkerPool::CreateGraphNodeForImageTask(
- internal::WorkerPoolTask* image_task,
- const TaskVector& decode_tasks,
- unsigned priority,
- bool is_required_for_activation,
- internal::GraphNode* raster_required_for_activation_finished_node,
- internal::GraphNode* raster_finished_node,
- TaskGraph* graph) {
- internal::GraphNode* image_node = CreateGraphNodeForRasterTask(image_task,
- decode_tasks,
- priority,
- graph);
-
- if (is_required_for_activation) {
- raster_required_for_activation_finished_node->add_dependency();
- image_node->add_dependent(raster_required_for_activation_finished_node);
- }
-
- raster_finished_node->add_dependency();
- image_node->add_dependent(raster_finished_node);
-}
-
} // namespace cc
diff --git a/chromium/cc/resources/image_raster_worker_pool.h b/chromium/cc/resources/image_raster_worker_pool.h
index 38fe04238e1..2e11a220f41 100644
--- a/chromium/cc/resources/image_raster_worker_pool.h
+++ b/chromium/cc/resources/image_raster_worker_pool.h
@@ -5,57 +5,67 @@
#ifndef CC_RESOURCES_IMAGE_RASTER_WORKER_POOL_H_
#define CC_RESOURCES_IMAGE_RASTER_WORKER_POOL_H_
+#include "base/memory/weak_ptr.h"
+#include "base/values.h"
#include "cc/resources/raster_worker_pool.h"
+#include "cc/resources/rasterizer.h"
namespace cc {
+class ResourceProvider;
-class CC_EXPORT ImageRasterWorkerPool : public RasterWorkerPool {
+class CC_EXPORT ImageRasterWorkerPool : public RasterWorkerPool,
+ public Rasterizer,
+ public RasterizerTaskClient {
public:
virtual ~ImageRasterWorkerPool();
static scoped_ptr<RasterWorkerPool> Create(
- ResourceProvider* resource_provider,
- size_t num_threads,
- GLenum texture_target) {
- return make_scoped_ptr<RasterWorkerPool>(
- new ImageRasterWorkerPool(resource_provider,
- num_threads,
- texture_target));
- }
+ base::SequencedTaskRunner* task_runner,
+ TaskGraphRunner* task_graph_runner,
+ ResourceProvider* resource_provider);
// Overridden from RasterWorkerPool:
- virtual void ScheduleTasks(RasterTask::Queue* queue) OVERRIDE;
- virtual GLenum GetResourceTarget() const OVERRIDE;
- virtual ResourceFormat GetResourceFormat() const OVERRIDE;
- virtual void OnRasterTasksFinished() OVERRIDE;
- virtual void OnRasterTasksRequiredForActivationFinished() OVERRIDE;
+ virtual Rasterizer* AsRasterizer() OVERRIDE;
- private:
- ImageRasterWorkerPool(ResourceProvider* resource_provider,
- size_t num_threads,
- GLenum texture_target);
-
- void OnRasterTaskCompleted(
- scoped_refptr<internal::RasterWorkerPoolTask> task, bool was_canceled);
+ // Overridden from Rasterizer:
+ virtual void SetClient(RasterizerClient* client) OVERRIDE;
+ virtual void Shutdown() OVERRIDE;
+ virtual void ScheduleTasks(RasterTaskQueue* queue) OVERRIDE;
+ virtual void CheckForCompletedTasks() OVERRIDE;
- scoped_ptr<base::Value> StateAsValue() const;
+ // Overridden from RasterizerTaskClient:
+ virtual SkCanvas* AcquireCanvasForRaster(RasterTask* task) OVERRIDE;
+ virtual void ReleaseCanvasForRaster(RasterTask* task) OVERRIDE;
- static void CreateGraphNodeForImageTask(
- internal::WorkerPoolTask* image_task,
- const TaskVector& decode_tasks,
- unsigned priority,
- bool is_required_for_activation,
- internal::GraphNode* raster_required_for_activation_finished_node,
- internal::GraphNode* raster_finished_node,
- TaskGraph* graph);
+ protected:
+ ImageRasterWorkerPool(base::SequencedTaskRunner* task_runner,
+ TaskGraphRunner* task_graph_runner,
+ ResourceProvider* resource_provider);
- const GLenum texture_target_;
+ private:
+ void OnRasterFinished();
+ void OnRasterRequiredForActivationFinished();
+ scoped_ptr<base::Value> StateAsValue() const;
- TaskMap image_tasks_;
+ scoped_refptr<base::SequencedTaskRunner> task_runner_;
+ TaskGraphRunner* task_graph_runner_;
+ const NamespaceToken namespace_token_;
+ RasterizerClient* client_;
+ ResourceProvider* resource_provider_;
bool raster_tasks_pending_;
bool raster_tasks_required_for_activation_pending_;
+ base::WeakPtrFactory<ImageRasterWorkerPool> raster_finished_weak_ptr_factory_;
+
+ scoped_refptr<RasterizerTask> raster_finished_task_;
+ scoped_refptr<RasterizerTask> raster_required_for_activation_finished_task_;
+
+ // Task graph used when scheduling tasks and vector used to gather
+ // completed tasks.
+ TaskGraph graph_;
+ Task::Vector completed_tasks_;
+
DISALLOW_COPY_AND_ASSIGN(ImageRasterWorkerPool);
};
diff --git a/chromium/cc/resources/layer_painter.h b/chromium/cc/resources/layer_painter.h
index 89a14243df3..4cb2527c42f 100644
--- a/chromium/cc/resources/layer_painter.h
+++ b/chromium/cc/resources/layer_painter.h
@@ -20,7 +20,7 @@ class CC_EXPORT LayerPainter {
public:
virtual ~LayerPainter() {}
virtual void Paint(SkCanvas* canvas,
- gfx::Rect content_rect,
+ const gfx::Rect& content_rect,
gfx::RectF* opaque) = 0;
};
diff --git a/chromium/cc/resources/layer_quad.cc b/chromium/cc/resources/layer_quad.cc
index 3e1955d05d8..fdd68662e35 100644
--- a/chromium/cc/resources/layer_quad.cc
+++ b/chromium/cc/resources/layer_quad.cc
@@ -9,7 +9,7 @@
namespace cc {
-LayerQuad::Edge::Edge(gfx::PointF p, gfx::PointF q) {
+LayerQuad::Edge::Edge(const gfx::PointF& p, const gfx::PointF& q) {
DCHECK(p != q);
gfx::Vector2dF tangent(p.y() - q.y(), q.x() - p.x());
diff --git a/chromium/cc/resources/layer_quad.h b/chromium/cc/resources/layer_quad.h
index 8098c209650..1d711931b20 100644
--- a/chromium/cc/resources/layer_quad.h
+++ b/chromium/cc/resources/layer_quad.h
@@ -23,7 +23,7 @@ class CC_EXPORT LayerQuad {
class Edge {
public:
Edge() : x_(0), y_(0), z_(0) {}
- Edge(gfx::PointF p, gfx::PointF q);
+ Edge(const gfx::PointF& p, const gfx::PointF& q);
float x() const { return x_; }
float y() const { return y_; }
diff --git a/chromium/cc/resources/layer_tiling_data.cc b/chromium/cc/resources/layer_tiling_data.cc
index 6b332341b8f..b8d80bc3760 100644
--- a/chromium/cc/resources/layer_tiling_data.cc
+++ b/chromium/cc/resources/layer_tiling_data.cc
@@ -10,19 +10,20 @@
namespace cc {
-scoped_ptr<LayerTilingData> LayerTilingData::Create(gfx::Size tile_size,
+scoped_ptr<LayerTilingData> LayerTilingData::Create(const gfx::Size& tile_size,
BorderTexelOption border) {
return make_scoped_ptr(new LayerTilingData(tile_size, border));
}
-LayerTilingData::LayerTilingData(gfx::Size tile_size, BorderTexelOption border)
- : tiling_data_(tile_size, gfx::Size(), border == HAS_BORDER_TEXELS) {
+LayerTilingData::LayerTilingData(const gfx::Size& tile_size,
+ BorderTexelOption border)
+ : tiling_data_(tile_size, gfx::Rect(), border == HAS_BORDER_TEXELS) {
SetTileSize(tile_size);
}
LayerTilingData::~LayerTilingData() {}
-void LayerTilingData::SetTileSize(gfx::Size size) {
+void LayerTilingData::SetTileSize(const gfx::Size& size) {
if (tile_size() == size)
return;
@@ -66,7 +67,7 @@ LayerTilingData::Tile* LayerTilingData::TileAt(int i, int j) const {
return tiles_.get(std::make_pair(i, j));
}
-void LayerTilingData::ContentRectToTileIndices(gfx::Rect content_rect,
+void LayerTilingData::ContentRectToTileIndices(const gfx::Rect& content_rect,
int* left,
int* top,
int* right,
@@ -90,7 +91,7 @@ gfx::Rect LayerTilingData::TileRect(const Tile* tile) const {
}
Region LayerTilingData::OpaqueRegionInContentRect(
- gfx::Rect content_rect) const {
+ const gfx::Rect& content_rect) const {
if (content_rect.IsEmpty())
return Region();
@@ -111,9 +112,9 @@ Region LayerTilingData::OpaqueRegionInContentRect(
return opaque_region;
}
-void LayerTilingData::SetBounds(gfx::Size size) {
- tiling_data_.SetTotalSize(size);
- if (size.IsEmpty()) {
+void LayerTilingData::SetTilingRect(const gfx::Rect& tiling_rect) {
+ tiling_data_.SetTilingRect(tiling_rect);
+ if (tiling_rect.IsEmpty()) {
tiles_.clear();
return;
}
@@ -121,8 +122,7 @@ void LayerTilingData::SetBounds(gfx::Size size) {
// Any tiles completely outside our new bounds are invalid and should be
// dropped.
int left, top, right, bottom;
- ContentRectToTileIndices(
- gfx::Rect(size), &left, &top, &right, &bottom);
+ ContentRectToTileIndices(tiling_rect, &left, &top, &right, &bottom);
std::vector<TileMapKey> invalid_tile_keys;
for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) {
if (it->first.first > right || it->first.second > bottom)
diff --git a/chromium/cc/resources/layer_tiling_data.h b/chromium/cc/resources/layer_tiling_data.h
index c5c9a745871..b145e38ffab 100644
--- a/chromium/cc/resources/layer_tiling_data.h
+++ b/chromium/cc/resources/layer_tiling_data.h
@@ -27,7 +27,7 @@ class CC_EXPORT LayerTilingData {
~LayerTilingData();
- static scoped_ptr<LayerTilingData> Create(gfx::Size tile_size,
+ static scoped_ptr<LayerTilingData> Create(const gfx::Size& tile_size,
BorderTexelOption option);
bool has_empty_bounds() const { return tiling_data_.has_empty_bounds(); }
@@ -41,7 +41,7 @@ class CC_EXPORT LayerTilingData {
}
// Change the tile size. This may invalidate all the existing tiles.
- void SetTileSize(gfx::Size size);
+ void SetTileSize(const gfx::Size& size);
gfx::Size tile_size() const;
// Change the border texel setting. This may invalidate all existing tiles.
void SetBorderTexelOption(BorderTexelOption option);
@@ -64,7 +64,9 @@ class CC_EXPORT LayerTilingData {
}
gfx::Rect opaque_rect() const { return opaque_rect_; }
- void set_opaque_rect(gfx::Rect opaque_rect) { opaque_rect_ = opaque_rect; }
+ void set_opaque_rect(const gfx::Rect& opaque_rect) {
+ opaque_rect_ = opaque_rect;
+ }
private:
int i_;
int j_;
@@ -79,22 +81,22 @@ class CC_EXPORT LayerTilingData {
Tile* TileAt(int i, int j) const;
const TileMap& tiles() const { return tiles_; }
- void SetBounds(gfx::Size size);
- gfx::Size bounds() const { return tiling_data_.total_size(); }
+ void SetTilingRect(const gfx::Rect& tiling_rect);
+ gfx::Rect tiling_rect() const { return tiling_data_.tiling_rect(); }
- void ContentRectToTileIndices(gfx::Rect rect,
+ void ContentRectToTileIndices(const gfx::Rect& rect,
int* left,
int* top,
int* right,
int* bottom) const;
gfx::Rect TileRect(const Tile* tile) const;
- Region OpaqueRegionInContentRect(gfx::Rect rect) const;
+ Region OpaqueRegionInContentRect(const gfx::Rect& rect) const;
void reset() { tiles_.clear(); }
protected:
- LayerTilingData(gfx::Size tile_size, BorderTexelOption option);
+ LayerTilingData(const gfx::Size& tile_size, BorderTexelOption option);
TileMap tiles_;
TilingData tiling_data_;
diff --git a/chromium/cc/resources/layer_updater.h b/chromium/cc/resources/layer_updater.h
index 5d8eb89ad4e..47f44106e40 100644
--- a/chromium/cc/resources/layer_updater.h
+++ b/chromium/cc/resources/layer_updater.h
@@ -29,9 +29,10 @@ class CC_EXPORT LayerUpdater : public base::RefCounted<LayerUpdater> {
// TODO(reveman): partial_update should be a property of this class
// instead of an argument passed to Update().
virtual void Update(ResourceUpdateQueue* queue,
- gfx::Rect source_rect,
- gfx::Vector2d dest_offset,
+ const gfx::Rect& source_rect,
+ const gfx::Vector2d& dest_offset,
bool partial_update) = 0;
+
protected:
explicit Resource(scoped_ptr<PrioritizedResource> texture);
@@ -48,8 +49,8 @@ class CC_EXPORT LayerUpdater : public base::RefCounted<LayerUpdater> {
// The |resulting_opaque_rect| gives back a region of the layer that was
// painted opaque. If the layer is marked opaque in the updater, then this
// region should be ignored in preference for the entire layer's area.
- virtual void PrepareToUpdate(gfx::Rect content_rect,
- gfx::Size tile_size,
+ virtual void PrepareToUpdate(const gfx::Rect& content_rect,
+ const gfx::Size& tile_size,
float contents_width_scale,
float contents_height_scale,
gfx::Rect* resulting_opaque_rect) {}
@@ -58,6 +59,9 @@ class CC_EXPORT LayerUpdater : public base::RefCounted<LayerUpdater> {
// Set true by the layer when it is known that the entire output is going to
// be opaque.
virtual void SetOpaque(bool opaque) {}
+ // Set true by the layer when it is known that the entire output bounds will
+ // be rasterized.
+ virtual void SetFillsBoundsCompletely(bool fills_bounds) {}
protected:
virtual ~LayerUpdater() {}
diff --git a/chromium/cc/resources/managed_tile_state.cc b/chromium/cc/resources/managed_tile_state.cc
index b453bd6d95f..037432764bd 100644
--- a/chromium/cc/resources/managed_tile_state.cc
+++ b/chromium/cc/resources/managed_tile_state.cc
@@ -14,35 +14,34 @@ scoped_ptr<base::Value> ManagedTileBinAsValue(ManagedTileBin bin) {
switch (bin) {
case NOW_AND_READY_TO_DRAW_BIN:
return scoped_ptr<base::Value>(
- base::Value::CreateStringValue("NOW_AND_READY_TO_DRAW_BIN"));
+ new base::StringValue("NOW_AND_READY_TO_DRAW_BIN"));
case NOW_BIN:
- return scoped_ptr<base::Value>(
- base::Value::CreateStringValue("NOW_BIN"));
+ return scoped_ptr<base::Value>(new base::StringValue("NOW_BIN"));
case SOON_BIN:
return scoped_ptr<base::Value>(
- base::Value::CreateStringValue("SOON_BIN"));
+ new base::StringValue("SOON_BIN"));
case EVENTUALLY_AND_ACTIVE_BIN:
return scoped_ptr<base::Value>(
- base::Value::CreateStringValue("EVENTUALLY_AND_ACTIVE_BIN"));
+ new base::StringValue("EVENTUALLY_AND_ACTIVE_BIN"));
case EVENTUALLY_BIN:
return scoped_ptr<base::Value>(
- base::Value::CreateStringValue("EVENTUALLY_BIN"));
+ new base::StringValue("EVENTUALLY_BIN"));
case AT_LAST_AND_ACTIVE_BIN:
return scoped_ptr<base::Value>(
- base::Value::CreateStringValue("AT_LAST_AND_ACTIVE_BIN"));
+ new base::StringValue("AT_LAST_AND_ACTIVE_BIN"));
case AT_LAST_BIN:
return scoped_ptr<base::Value>(
- base::Value::CreateStringValue("AT_LAST_BIN"));
+ new base::StringValue("AT_LAST_BIN"));
case NEVER_BIN:
return scoped_ptr<base::Value>(
- base::Value::CreateStringValue("NEVER_BIN"));
+ new base::StringValue("NEVER_BIN"));
case NUM_BINS:
NOTREACHED();
return scoped_ptr<base::Value>(
- base::Value::CreateStringValue("Invalid Bin (NUM_BINS)"));
+ new base::StringValue("Invalid Bin (NUM_BINS)"));
}
return scoped_ptr<base::Value>(
- base::Value::CreateStringValue("Invalid Bin (UNKNOWN)"));
+ new base::StringValue("Invalid Bin (UNKNOWN)"));
}
ManagedTileState::ManagedTileState()
@@ -50,20 +49,15 @@ ManagedTileState::ManagedTileState()
bin(NEVER_BIN),
resolution(NON_IDEAL_RESOLUTION),
required_for_activation(false),
- time_to_needed_in_seconds(std::numeric_limits<float>::infinity()),
- distance_to_visible_in_pixels(std::numeric_limits<float>::infinity()),
+ priority_bin(TilePriority::EVENTUALLY),
+ distance_to_visible(std::numeric_limits<float>::infinity()),
visible_and_ready_to_draw(false),
- scheduled_priority(0) {
-}
+ scheduled_priority(0) {}
-ManagedTileState::TileVersion::TileVersion()
- : mode_(RESOURCE_MODE),
- has_text_(false) {
+ManagedTileState::TileVersion::TileVersion() : mode_(RESOURCE_MODE) {
}
-ManagedTileState::TileVersion::~TileVersion() {
- DCHECK(!resource_);
-}
+ManagedTileState::TileVersion::~TileVersion() { DCHECK(!resource_); }
bool ManagedTileState::TileVersion::IsReadyToDraw() const {
switch (mode_) {
@@ -83,15 +77,14 @@ size_t ManagedTileState::TileVersion::GPUMemoryUsageInBytes() const {
return resource_->bytes();
}
-ManagedTileState::~ManagedTileState() {
-}
+ManagedTileState::~ManagedTileState() {}
scoped_ptr<base::Value> ManagedTileState::AsValue() const {
bool has_resource = false;
bool has_active_task = false;
for (int mode = 0; mode < NUM_RASTER_MODES; ++mode) {
has_resource |= (tile_versions[mode].resource_.get() != 0);
- has_active_task |= !tile_versions[mode].raster_task_.is_null();
+ has_active_task |= (tile_versions[mode].raster_task_.get() != 0);
}
bool is_using_gpu_memory = has_resource || has_active_task;
@@ -101,10 +94,9 @@ scoped_ptr<base::Value> ManagedTileState::AsValue() const {
state->SetBoolean("is_using_gpu_memory", is_using_gpu_memory);
state->Set("bin", ManagedTileBinAsValue(bin).release());
state->Set("resolution", TileResolutionAsValue(resolution).release());
- state->Set("time_to_needed_in_seconds",
- MathUtil::AsValueSafely(time_to_needed_in_seconds).release());
- state->Set("distance_to_visible_in_pixels",
- MathUtil::AsValueSafely(distance_to_visible_in_pixels).release());
+ state->Set("priority_bin", TilePriorityBinAsValue(priority_bin).release());
+ state->Set("distance_to_visible",
+ MathUtil::AsValueSafely(distance_to_visible).release());
state->SetBoolean("required_for_activation", required_for_activation);
state->SetBoolean(
"is_solid_color",
diff --git a/chromium/cc/resources/managed_tile_state.h b/chromium/cc/resources/managed_tile_state.h
index dc6f6d62cb6..7224dd64b41 100644
--- a/chromium/cc/resources/managed_tile_state.h
+++ b/chromium/cc/resources/managed_tile_state.h
@@ -7,10 +7,12 @@
#include "base/memory/scoped_ptr.h"
#include "cc/resources/platform_color.h"
-#include "cc/resources/raster_worker_pool.h"
+#include "cc/resources/raster_mode.h"
+#include "cc/resources/rasterizer.h"
#include "cc/resources/resource_pool.h"
#include "cc/resources/resource_provider.h"
#include "cc/resources/scoped_resource.h"
+#include "cc/resources/tile_priority.h"
namespace cc {
@@ -30,90 +32,73 @@ enum ManagedTileBin {
// NOTE: Be sure to update ManagedTileBinAsValue and kBinPolicyMap when adding
// or reordering fields.
};
-scoped_ptr<base::Value> ManagedTileBinAsValue(
- ManagedTileBin bin);
+scoped_ptr<base::Value> ManagedTileBinAsValue(ManagedTileBin bin);
// This is state that is specific to a tile that is
// managed by the TileManager.
class CC_EXPORT ManagedTileState {
public:
class CC_EXPORT TileVersion {
- public:
- enum Mode {
- RESOURCE_MODE,
- SOLID_COLOR_MODE,
- PICTURE_PILE_MODE
- };
-
- TileVersion();
- ~TileVersion();
-
- Mode mode() const {
- return mode_;
- }
-
- bool IsReadyToDraw() const;
-
- ResourceProvider::ResourceId get_resource_id() const {
- DCHECK(mode_ == RESOURCE_MODE);
- DCHECK(resource_);
-
- return resource_->id();
- }
-
- SkColor get_solid_color() const {
- DCHECK(mode_ == SOLID_COLOR_MODE);
-
- return solid_color_;
- }
-
- bool contents_swizzled() const {
- DCHECK(resource_);
- return !PlatformColor::SameComponentOrder(resource_->format());
- }
-
- bool requires_resource() const {
- return mode_ == RESOURCE_MODE ||
- mode_ == PICTURE_PILE_MODE;
- }
-
- size_t GPUMemoryUsageInBytes() const;
-
- void SetSolidColorForTesting(SkColor color) {
- set_solid_color(color);
- }
- void SetHasTextForTesting(bool has_text) {
- has_text_ = has_text;
- }
-
- private:
- friend class TileManager;
- friend class PrioritizedTileSet;
- friend class Tile;
- friend class ManagedTileState;
-
- void set_use_resource() {
- mode_ = RESOURCE_MODE;
- }
-
- void set_solid_color(const SkColor& color) {
- mode_ = SOLID_COLOR_MODE;
- solid_color_ = color;
- }
-
- void set_has_text(bool has_text) {
- has_text_ = has_text;
- }
-
- void set_rasterize_on_demand() {
- mode_ = PICTURE_PILE_MODE;
- }
-
- Mode mode_;
- SkColor solid_color_;
- bool has_text_;
- scoped_ptr<ScopedResource> resource_;
- RasterWorkerPool::RasterTask raster_task_;
+ public:
+ enum Mode { RESOURCE_MODE, SOLID_COLOR_MODE, PICTURE_PILE_MODE };
+
+ TileVersion();
+ ~TileVersion();
+
+ Mode mode() const { return mode_; }
+
+ bool IsReadyToDraw() const;
+
+ ResourceProvider::ResourceId get_resource_id() const {
+ DCHECK(mode_ == RESOURCE_MODE);
+ DCHECK(resource_);
+
+ return resource_->id();
+ }
+
+ SkColor get_solid_color() const {
+ DCHECK(mode_ == SOLID_COLOR_MODE);
+
+ return solid_color_;
+ }
+
+ bool contents_swizzled() const {
+ DCHECK(resource_);
+ return !PlatformColor::SameComponentOrder(resource_->format());
+ }
+
+ bool requires_resource() const {
+ return mode_ == RESOURCE_MODE || mode_ == PICTURE_PILE_MODE;
+ }
+
+ inline bool has_resource() const { return !!resource_; }
+
+ size_t GPUMemoryUsageInBytes() const;
+
+ void SetSolidColorForTesting(SkColor color) { set_solid_color(color); }
+ void SetResourceForTesting(scoped_ptr<ScopedResource> resource) {
+ resource_ = resource.Pass();
+ }
+
+ private:
+ friend class TileManager;
+ friend class PrioritizedTileSet;
+ friend class Tile;
+ friend class ManagedTileState;
+
+ void set_use_resource() { mode_ = RESOURCE_MODE; }
+
+ void set_solid_color(const SkColor& color) {
+ mode_ = SOLID_COLOR_MODE;
+ solid_color_ = color;
+ }
+
+ void set_rasterize_on_demand() { mode_ = PICTURE_PILE_MODE; }
+
+ Mode mode_;
+ SkColor solid_color_;
+ scoped_ptr<ScopedResource> resource_;
+ scoped_refptr<RasterTask> raster_task_;
};
ManagedTileState();
@@ -129,8 +114,8 @@ class CC_EXPORT ManagedTileState {
TileResolution resolution;
bool required_for_activation;
- float time_to_needed_in_seconds;
- float distance_to_visible_in_pixels;
+ TilePriority::PriorityBin priority_bin;
+ float distance_to_visible;
bool visible_and_ready_to_draw;
// Priority for this state from the last time we assigned memory.
diff --git a/chromium/cc/resources/picture.cc b/chromium/cc/resources/picture.cc
index 8c3be9c3bca..a19fd33f3a0 100644
--- a/chromium/cc/resources/picture.cc
+++ b/chromium/cc/resources/picture.cc
@@ -16,12 +16,14 @@
#include "cc/debug/traced_picture.h"
#include "cc/debug/traced_value.h"
#include "cc/layers/content_layer_client.h"
-#include "skia/ext/lazy_pixel_ref_utils.h"
+#include "skia/ext/pixel_ref_utils.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkData.h"
#include "third_party/skia/include/core/SkDrawFilter.h"
#include "third_party/skia/include/core/SkPaint.h"
+#include "third_party/skia/include/core/SkPictureRecorder.h"
#include "third_party/skia/include/core/SkStream.h"
+#include "third_party/skia/include/utils/SkNullCanvas.h"
#include "third_party/skia/include/utils/SkPictureUtils.h"
#include "ui/gfx/codec/jpeg_codec.h"
#include "ui/gfx/codec/png_codec.h"
@@ -81,11 +83,24 @@ bool DecodeBitmap(const void* buffer, size_t size, SkBitmap* bm) {
} // namespace
-scoped_refptr<Picture> Picture::Create(gfx::Rect layer_rect) {
- return make_scoped_refptr(new Picture(layer_rect));
+scoped_refptr<Picture> Picture::Create(
+ const gfx::Rect& layer_rect,
+ ContentLayerClient* client,
+ const SkTileGridFactory::TileGridInfo& tile_grid_info,
+ bool gather_pixel_refs,
+ int num_raster_threads,
+ RecordingMode recording_mode) {
+ scoped_refptr<Picture> picture = make_scoped_refptr(new Picture(layer_rect));
+
+ picture->Record(client, tile_grid_info, recording_mode);
+ if (gather_pixel_refs)
+ picture->GatherPixelRefs(tile_grid_info);
+ picture->CloneForDrawing(num_raster_threads);
+
+ return picture;
}
-Picture::Picture(gfx::Rect layer_rect)
+Picture::Picture(const gfx::Rect& layer_rect)
: layer_rect_(layer_rect),
cell_size_(layer_rect.size()) {
// Instead of recording a trace event for object creation here, we wait for
@@ -152,8 +167,8 @@ scoped_refptr<Picture> Picture::CreateFromValue(const base::Value* raw_value) {
}
Picture::Picture(SkPicture* picture,
- gfx::Rect layer_rect,
- gfx::Rect opaque_rect) :
+ const gfx::Rect& layer_rect,
+ const gfx::Rect& opaque_rect) :
layer_rect_(layer_rect),
opaque_rect_(opaque_rect),
picture_(skia::AdoptRef(picture)),
@@ -161,8 +176,8 @@ Picture::Picture(SkPicture* picture,
}
Picture::Picture(const skia::RefPtr<SkPicture>& picture,
- gfx::Rect layer_rect,
- gfx::Rect opaque_rect,
+ const gfx::Rect& layer_rect,
+ const gfx::Rect& opaque_rect,
const PixelRefMap& pixel_refs) :
layer_rect_(layer_rect),
opaque_rect_(opaque_rect),
@@ -176,48 +191,111 @@ Picture::~Picture() {
TRACE_DISABLED_BY_DEFAULT("cc.debug"), "cc::Picture", this);
}
-scoped_refptr<Picture> Picture::GetCloneForDrawingOnThread(
- unsigned thread_index) const {
+Picture* Picture::GetCloneForDrawingOnThread(unsigned thread_index) {
+ // We don't need clones to draw from multiple threads with SkRecord.
+ if (playback_) {
+ return this;
+ }
+
// SkPicture is not thread-safe to rasterize with, this returns a clone
// to rasterize with on a specific thread.
- CHECK_GT(clones_.size(), thread_index);
- return clones_[thread_index];
+ CHECK_GE(clones_.size(), thread_index);
+ return thread_index == clones_.size() ? this : clones_[thread_index].get();
+}
+
+bool Picture::IsSuitableForGpuRasterization() const {
+ DCHECK(picture_);
+
+ // TODO(alokp): SkPicture::suitableForGpuRasterization needs a GrContext.
+ // Ideally this GrContext should be the same as that for rasterizing this
+ // picture. But we are on the main thread while the rasterization context
+ // may be on the compositor or raster thread.
+ // SkPicture::suitableForGpuRasterization is not implemented yet.
+ // Pass a NULL context for now and discuss with skia folks if the context
+ // is really needed.
+ return picture_->suitableForGpuRasterization(NULL);
}
void Picture::CloneForDrawing(int num_threads) {
TRACE_EVENT1("cc", "Picture::CloneForDrawing", "num_threads", num_threads);
+ // We don't need clones to draw from multiple threads with SkRecord.
+ if (playback_) {
+ return;
+ }
+
DCHECK(picture_);
- scoped_ptr<SkPicture[]> clones(new SkPicture[num_threads]);
- picture_->clone(&clones[0], num_threads);
-
- clones_.clear();
- for (int i = 0; i < num_threads; i++) {
- scoped_refptr<Picture> clone = make_scoped_refptr(
- new Picture(skia::AdoptRef(new SkPicture(clones[i])),
- layer_rect_,
- opaque_rect_,
- pixel_refs_));
- clones_.push_back(clone);
-
- clone->EmitTraceSnapshotAlias(this);
+ DCHECK(clones_.empty());
+
+ // We can re-use this picture for one raster worker thread.
+ raster_thread_checker_.DetachFromThread();
+
+ if (num_threads > 1) {
+ scoped_ptr<SkPicture[]> clones(new SkPicture[num_threads - 1]);
+ picture_->clone(&clones[0], num_threads - 1);
+
+ for (int i = 0; i < num_threads - 1; i++) {
+ scoped_refptr<Picture> clone = make_scoped_refptr(
+ new Picture(skia::AdoptRef(new SkPicture(clones[i])),
+ layer_rect_,
+ opaque_rect_,
+ pixel_refs_));
+ clones_.push_back(clone);
+
+ clone->EmitTraceSnapshotAlias(this);
+ clone->raster_thread_checker_.DetachFromThread();
+ }
}
}
void Picture::Record(ContentLayerClient* painter,
- const SkTileGridPicture::TileGridInfo& tile_grid_info) {
- TRACE_EVENT1("cc", "Picture::Record",
- "data", AsTraceableRecordData());
-
+ const SkTileGridFactory::TileGridInfo& tile_grid_info,
+ RecordingMode recording_mode) {
+ TRACE_EVENT2("cc",
+ "Picture::Record",
+ "data",
+ AsTraceableRecordData(),
+ "recording_mode",
+ recording_mode);
+
+ DCHECK(!picture_);
DCHECK(!tile_grid_info.fTileInterval.isEmpty());
- picture_ = skia::AdoptRef(new SkTileGridPicture(
- layer_rect_.width(), layer_rect_.height(), tile_grid_info));
- SkCanvas* canvas = picture_->beginRecording(
- layer_rect_.width(),
- layer_rect_.height(),
- SkPicture::kUsePathBoundsForClip_RecordingFlag |
- SkPicture::kOptimizeForClippedPlayback_RecordingFlag);
+ SkTileGridFactory factory(tile_grid_info);
+ SkPictureRecorder recorder;
+
+ scoped_ptr<EXPERIMENTAL::SkRecording> recording;
+
+ skia::RefPtr<SkCanvas> canvas;
+ canvas = skia::SharePtr(recorder.beginRecording(
+ layer_rect_.width(), layer_rect_.height(), &factory));
+
+ ContentLayerClient::GraphicsContextStatus graphics_context_status =
+ ContentLayerClient::GRAPHICS_CONTEXT_ENABLED;
+
+ switch (recording_mode) {
+ case RECORD_NORMALLY:
+ // Already setup for normal recording.
+ break;
+ case RECORD_WITH_SK_NULL_CANVAS:
+ canvas = skia::AdoptRef(SkCreateNullCanvas());
+ break;
+ case RECORD_WITH_PAINTING_DISABLED:
+ // We pass a disable flag through the paint calls when perfromance
+ // testing (the only time this case should ever arise) when we want to
+ // prevent the Blink GraphicsContext object from consuming any compute
+ // time.
+ canvas = skia::AdoptRef(SkCreateNullCanvas());
+ graphics_context_status = ContentLayerClient::GRAPHICS_CONTEXT_DISABLED;
+ break;
+ case RECORD_WITH_SKRECORD:
+ recording.reset(new EXPERIMENTAL::SkRecording(layer_rect_.width(),
+ layer_rect_.height()));
+ canvas = skia::SharePtr(recording->canvas());
+ break;
+ default:
+ NOTREACHED();
+ }
canvas->save();
canvas->translate(SkFloatToScalar(-layer_rect_.x()),
@@ -230,11 +308,19 @@ void Picture::Record(ContentLayerClient* painter,
canvas->clipRect(layer_skrect);
gfx::RectF opaque_layer_rect;
-
- painter->PaintContents(canvas, layer_rect_, &opaque_layer_rect);
+ painter->PaintContents(
+ canvas.get(), layer_rect_, &opaque_layer_rect, graphics_context_status);
canvas->restore();
- picture_->endRecording();
+ picture_ = skia::AdoptRef(recorder.endRecording());
+ DCHECK(picture_);
+
+ if (recording) {
+ // SkRecording requires it's the only one holding onto canvas before we
+ // may call releasePlayback(). (This helps enforce thread-safety.)
+ canvas.clear();
+ playback_.reset(recording->releasePlayback());
+ }
opaque_rect_ = gfx::ToEnclosedRect(opaque_layer_rect);
@@ -242,12 +328,13 @@ void Picture::Record(ContentLayerClient* painter,
}
void Picture::GatherPixelRefs(
- const SkTileGridPicture::TileGridInfo& tile_grid_info) {
+ const SkTileGridFactory::TileGridInfo& tile_grid_info) {
TRACE_EVENT2("cc", "Picture::GatherPixelRefs",
"width", layer_rect_.width(),
"height", layer_rect_.height());
DCHECK(picture_);
+ DCHECK(pixel_refs_.empty());
if (!WillPlayBackBitmaps())
return;
cell_size_ = gfx::Size(
@@ -263,9 +350,9 @@ void Picture::GatherPixelRefs(
int max_x = 0;
int max_y = 0;
- skia::LazyPixelRefList pixel_refs;
- skia::LazyPixelRefUtils::GatherPixelRefs(picture_.get(), &pixel_refs);
- for (skia::LazyPixelRefList::const_iterator it = pixel_refs.begin();
+ skia::DiscardablePixelRefList pixel_refs;
+ skia::PixelRefUtils::GatherDiscardablePixelRefs(picture_.get(), &pixel_refs);
+ for (skia::DiscardablePixelRefList::const_iterator it = pixel_refs.begin();
it != pixel_refs.end();
++it) {
gfx::Point min(
@@ -282,7 +369,7 @@ void Picture::GatherPixelRefs(
for (int y = min.y(); y <= max.y(); y += cell_size_.height()) {
for (int x = min.x(); x <= max.x(); x += cell_size_.width()) {
PixelRefMapKey key(x, y);
- pixel_refs_[key].push_back(it->lazy_pixel_ref);
+ pixel_refs_[key].push_back(it->pixel_ref);
}
}
@@ -301,6 +388,8 @@ int Picture::Raster(
SkDrawPictureCallback* callback,
const Region& negated_content_region,
float contents_scale) {
+ if (!playback_)
+ DCHECK(raster_thread_checker_.CalledOnValidThread());
TRACE_EVENT_BEGIN1(
"cc",
"Picture::Raster",
@@ -316,7 +405,11 @@ int Picture::Raster(
canvas->scale(contents_scale, contents_scale);
canvas->translate(layer_rect_.x(), layer_rect_.y());
- picture_->draw(canvas, callback);
+ if (playback_) {
+ playback_->draw(canvas);
+ } else {
+ picture_->draw(canvas, callback);
+ }
SkIRect bounds;
canvas->getClipDeviceBounds(&bounds);
canvas->restore();
@@ -327,10 +420,16 @@ int Picture::Raster(
}
void Picture::Replay(SkCanvas* canvas) {
+ if (!playback_)
+ DCHECK(raster_thread_checker_.CalledOnValidThread());
TRACE_EVENT_BEGIN0("cc", "Picture::Replay");
DCHECK(picture_);
- picture_->draw(canvas);
+ if (playback_) {
+ playback_->draw(canvas);
+ } else {
+ picture_->draw(canvas);
+ }
SkIRect bounds;
canvas->getClipDeviceBounds(&bounds);
TRACE_EVENT_END1("cc", "Picture::Replay",
@@ -340,8 +439,20 @@ void Picture::Replay(SkCanvas* canvas) {
scoped_ptr<base::Value> Picture::AsValue() const {
SkDynamicMemoryWStream stream;
- // Serialize the picture.
- picture_->serialize(&stream, &EncodeBitmap);
+ if (playback_) {
+ // SkPlayback can't serialize itself, so re-record into an SkPicture.
+ SkPictureRecorder recorder;
+ skia::RefPtr<SkCanvas> canvas(skia::SharePtr(recorder.beginRecording(
+ layer_rect_.width(),
+ layer_rect_.height(),
+ NULL))); // Default (no) bounding-box hierarchy is fastest.
+ playback_->draw(canvas.get());
+ skia::RefPtr<SkPicture> picture(skia::AdoptRef(recorder.endRecording()));
+ picture->serialize(&stream, &EncodeBitmap);
+ } else {
+ // Serialize the picture.
+ picture_->serialize(&stream, &EncodeBitmap);
+ }
// Encode the picture as base64.
scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue());
@@ -358,14 +469,19 @@ scoped_ptr<base::Value> Picture::AsValue() const {
return res.PassAs<base::Value>();
}
-void Picture::EmitTraceSnapshot() {
- TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
- "cc::Picture", this, TracedPicture::AsTraceablePicture(this));
+void Picture::EmitTraceSnapshot() const {
+ TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
+ TRACE_DISABLED_BY_DEFAULT("cc.debug") "," TRACE_DISABLED_BY_DEFAULT(
+ "devtools.timeline.picture"),
+ "cc::Picture",
+ this,
+ TracedPicture::AsTraceablePicture(this));
}
-void Picture::EmitTraceSnapshotAlias(Picture* original) {
+void Picture::EmitTraceSnapshotAlias(Picture* original) const {
TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
- TRACE_DISABLED_BY_DEFAULT("cc.debug"),
+ TRACE_DISABLED_BY_DEFAULT("cc.debug") "," TRACE_DISABLED_BY_DEFAULT(
+ "devtools.timeline.picture"),
"cc::Picture",
this,
TracedPicture::AsTraceablePictureAlias(original));
@@ -385,7 +501,7 @@ Picture::PixelRefIterator::PixelRefIterator()
}
Picture::PixelRefIterator::PixelRefIterator(
- gfx::Rect query_rect,
+ const gfx::Rect& rect,
const Picture* picture)
: picture_(picture),
current_pixel_refs_(empty_pixel_refs_.Pointer()),
@@ -394,6 +510,7 @@ Picture::PixelRefIterator::PixelRefIterator(
gfx::Size cell_size = picture->cell_size_;
DCHECK(!cell_size.IsEmpty());
+ gfx::Rect query_rect(rect);
// Early out if the query rect doesn't intersect this picture.
if (!query_rect.Intersects(layer_rect)) {
min_point_ = gfx::Point(0, 0);
@@ -482,8 +599,7 @@ scoped_refptr<base::debug::ConvertableToTraceFormat>
Picture::AsTraceableRecordData() const {
scoped_ptr<base::DictionaryValue> record_data(new base::DictionaryValue());
record_data->Set("picture_id", TracedValue::CreateIDRef(this).release());
- record_data->SetInteger("width", layer_rect_.width());
- record_data->SetInteger("height", layer_rect_.height());
+ record_data->Set("layer_rect", MathUtil::AsValue(layer_rect_).release());
return TracedValue::FromValue(record_data.release());
}
diff --git a/chromium/cc/resources/picture.h b/chromium/cc/resources/picture.h
index 085fb6a4531..78833d17e91 100644
--- a/chromium/cc/resources/picture.h
+++ b/chromium/cc/resources/picture.h
@@ -16,14 +16,17 @@
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
+#include "base/threading/thread_checker.h"
#include "cc/base/cc_export.h"
#include "cc/base/region.h"
-#include "skia/ext/lazy_pixel_ref.h"
#include "skia/ext/refptr.h"
-#include "third_party/skia/include/core/SkPixelRef.h"
-#include "third_party/skia/include/core/SkTileGridPicture.h"
+#include "third_party/skia/include/core/SkBBHFactory.h"
+#include "third_party/skia/include/core/SkPicture.h"
+#include "third_party/skia/include/record/SkRecording.h"
#include "ui/gfx/rect.h"
+class SkPixelRef;
+
namespace base {
class Value;
}
@@ -40,10 +43,24 @@ class CC_EXPORT Picture
: public base::RefCountedThreadSafe<Picture> {
public:
typedef std::pair<int, int> PixelRefMapKey;
- typedef std::vector<skia::LazyPixelRef*> PixelRefs;
+ typedef std::vector<SkPixelRef*> PixelRefs;
typedef base::hash_map<PixelRefMapKey, PixelRefs> PixelRefMap;
- static scoped_refptr<Picture> Create(gfx::Rect layer_rect);
+ enum RecordingMode {
+ RECORD_NORMALLY,
+ RECORD_WITH_SK_NULL_CANVAS,
+ RECORD_WITH_PAINTING_DISABLED,
+ RECORD_WITH_SKRECORD,
+ RECORDING_MODE_COUNT, // Must be the last entry.
+ };
+
+ static scoped_refptr<Picture> Create(
+ const gfx::Rect& layer_rect,
+ ContentLayerClient* client,
+ const SkTileGridFactory::TileGridInfo& tile_grid_info,
+ bool gather_pixels_refs,
+ int num_raster_threads,
+ RecordingMode recording_mode);
static scoped_refptr<Picture> CreateFromValue(const base::Value* value);
static scoped_refptr<Picture> CreateFromSkpValue(const base::Value* value);
@@ -51,25 +68,17 @@ class CC_EXPORT Picture
gfx::Rect OpaqueRect() const { return opaque_rect_; }
// Get thread-safe clone for rasterizing with on a specific thread.
- scoped_refptr<Picture> GetCloneForDrawingOnThread(
- unsigned thread_index) const;
-
- // Make thread-safe clones for rasterizing with.
- void CloneForDrawing(int num_threads);
-
- // Record a paint operation. To be able to safely use this SkPicture for
- // playback on a different thread this can only be called once.
- void Record(ContentLayerClient* client,
- const SkTileGridPicture::TileGridInfo& tile_grid_info);
-
- // Gather pixel refs from recording.
- void GatherPixelRefs(const SkTileGridPicture::TileGridInfo& tile_grid_info);
+ Picture* GetCloneForDrawingOnThread(unsigned thread_index);
// Has Record() been called yet?
bool HasRecording() const { return picture_.get() != NULL; }
- // Apply this scale and raster the negated region into the canvas. See comment
- // in PicturePileImpl::RasterCommon for explanation on negated content region.
+ bool IsSuitableForGpuRasterization() const;
+
+ // Apply this scale and raster the negated region into the canvas.
+ // |negated_content_region| specifies the region to be clipped out of the
+ // raster operation, i.e., the parts of the canvas which will not get drawn
+ // to.
int Raster(SkCanvas* canvas,
SkDrawPictureCallback* callback,
const Region& negated_content_region,
@@ -81,18 +90,21 @@ class CC_EXPORT Picture
scoped_ptr<base::Value> AsValue() const;
+ // This iterator imprecisely returns the set of pixel refs that are needed to
+ // raster this layer rect from this picture. Internally, pixel refs are
+ // clumped into tile grid buckets, so there may be false positives.
class CC_EXPORT PixelRefIterator {
public:
PixelRefIterator();
- PixelRefIterator(gfx::Rect layer_rect, const Picture* picture);
+ PixelRefIterator(const gfx::Rect& layer_rect, const Picture* picture);
~PixelRefIterator();
- skia::LazyPixelRef* operator->() const {
+ SkPixelRef* operator->() const {
DCHECK_LT(current_index_, current_pixel_refs_->size());
return (*current_pixel_refs_)[current_index_];
}
- skia::LazyPixelRef* operator*() const {
+ SkPixelRef* operator*() const {
DCHECK_LT(current_index_, current_pixel_refs_->size());
return (*current_pixel_refs_)[current_index_];
}
@@ -114,28 +126,41 @@ class CC_EXPORT Picture
int current_y_;
};
- void EmitTraceSnapshot();
- void EmitTraceSnapshotAlias(Picture* original);
+ void EmitTraceSnapshot() const;
+ void EmitTraceSnapshotAlias(Picture* original) const;
bool WillPlayBackBitmaps() const { return picture_->willPlayBackBitmaps(); }
private:
- explicit Picture(gfx::Rect layer_rect);
+ explicit Picture(const gfx::Rect& layer_rect);
// This constructor assumes SkPicture is already ref'd and transfers
// ownership to this picture.
Picture(const skia::RefPtr<SkPicture>&,
- gfx::Rect layer_rect,
- gfx::Rect opaque_rect,
+ const gfx::Rect& layer_rect,
+ const gfx::Rect& opaque_rect,
const PixelRefMap& pixel_refs);
// This constructor will call AdoptRef on the SkPicture.
Picture(SkPicture*,
- gfx::Rect layer_rect,
- gfx::Rect opaque_rect);
+ const gfx::Rect& layer_rect,
+ const gfx::Rect& opaque_rect);
~Picture();
+ // Make thread-safe clones for rasterizing with.
+ void CloneForDrawing(int num_threads);
+
+ // Record a paint operation. To be able to safely use this SkPicture for
+ // playback on a different thread this can only be called once.
+ void Record(ContentLayerClient* client,
+ const SkTileGridFactory::TileGridInfo& tile_grid_info,
+ RecordingMode recording_mode);
+
+ // Gather pixel refs from recording.
+ void GatherPixelRefs(const SkTileGridFactory::TileGridInfo& tile_grid_info);
+
gfx::Rect layer_rect_;
gfx::Rect opaque_rect_;
skia::RefPtr<SkPicture> picture_;
+ scoped_ptr<const EXPERIMENTAL::SkPlayback> playback_;
typedef std::vector<scoped_refptr<Picture> > PictureVector;
PictureVector clones_;
@@ -150,6 +175,8 @@ class CC_EXPORT Picture
scoped_refptr<base::debug::ConvertableToTraceFormat>
AsTraceableRecordData() const;
+ base::ThreadChecker raster_thread_checker_;
+
friend class base::RefCountedThreadSafe<Picture>;
friend class PixelRefIterator;
DISALLOW_COPY_AND_ASSIGN(Picture);
diff --git a/chromium/cc/resources/picture_layer_tiling.cc b/chromium/cc/resources/picture_layer_tiling.cc
index 1aa3567e0a3..5a419516e63 100644
--- a/chromium/cc/resources/picture_layer_tiling.cc
+++ b/chromium/cc/resources/picture_layer_tiling.cc
@@ -10,16 +10,45 @@
#include "base/debug/trace_event.h"
#include "cc/base/math_util.h"
+#include "cc/resources/tile.h"
+#include "cc/resources/tile_priority.h"
#include "ui/gfx/point_conversions.h"
#include "ui/gfx/rect_conversions.h"
#include "ui/gfx/safe_integer_conversions.h"
#include "ui/gfx/size_conversions.h"
namespace cc {
+namespace {
+
+const float kSoonBorderDistanceInScreenPixels = 312.f;
+
+class TileEvictionOrder {
+ public:
+ explicit TileEvictionOrder(TreePriority tree_priority)
+ : tree_priority_(tree_priority) {}
+ ~TileEvictionOrder() {}
+
+ bool operator()(const Tile* a, const Tile* b) {
+ const TilePriority& a_priority =
+ a->priority_for_tree_priority(tree_priority_);
+ const TilePriority& b_priority =
+ b->priority_for_tree_priority(tree_priority_);
+
+ if (a_priority.priority_bin == b_priority.priority_bin &&
+ a->required_for_activation() != b->required_for_activation()) {
+ return b->required_for_activation();
+ }
+ return b_priority.IsHigherPriorityThan(a_priority);
+ }
+
+ private:
+ TreePriority tree_priority_;
+};
+} // namespace
scoped_ptr<PictureLayerTiling> PictureLayerTiling::Create(
float contents_scale,
- gfx::Size layer_bounds,
+ const gfx::Size& layer_bounds,
PictureLayerTilingClient* client) {
return make_scoped_ptr(new PictureLayerTiling(contents_scale,
layer_bounds,
@@ -27,14 +56,16 @@ scoped_ptr<PictureLayerTiling> PictureLayerTiling::Create(
}
PictureLayerTiling::PictureLayerTiling(float contents_scale,
- gfx::Size layer_bounds,
+ const gfx::Size& layer_bounds,
PictureLayerTilingClient* client)
: contents_scale_(contents_scale),
layer_bounds_(layer_bounds),
resolution_(NON_IDEAL_RESOLUTION),
client_(client),
- tiling_data_(gfx::Size(), gfx::Size(), true),
- last_impl_frame_time_in_seconds_(0.0) {
+ tiling_data_(gfx::Size(), gfx::Rect(), true),
+ last_impl_frame_time_in_seconds_(0.0),
+ eviction_tiles_cache_valid_(false),
+ eviction_cache_tree_priority_(SAME_PRIORITY_FOR_BOTH_TREES) {
gfx::Size content_bounds =
gfx::ToCeiledSize(gfx::ScaleSize(layer_bounds, contents_scale));
gfx::Size tile_size = client_->CalculateTileSize(content_bounds);
@@ -45,7 +76,7 @@ PictureLayerTiling::PictureLayerTiling(float contents_scale,
" Layer bounds: " << layer_bounds.ToString() <<
" Contents scale: " << contents_scale;
- tiling_data_.SetTotalSize(content_bounds);
+ tiling_data_.SetTilingRect(gfx::Rect(content_bounds));
tiling_data_.SetMaxTextureSize(tile_size);
}
@@ -56,24 +87,13 @@ void PictureLayerTiling::SetClient(PictureLayerTilingClient* client) {
client_ = client;
}
-gfx::Rect PictureLayerTiling::ContentRect() const {
- return gfx::Rect(tiling_data_.total_size());
-}
-
-gfx::SizeF PictureLayerTiling::ContentSizeF() const {
- return gfx::ScaleSize(layer_bounds_, contents_scale_);
+gfx::Rect PictureLayerTiling::TilingRect() const {
+ return tiling_data_.tiling_rect();
}
-Tile* PictureLayerTiling::TileAt(int i, int j) const {
- TileMap::const_iterator iter = tiles_.find(TileMapKey(i, j));
- if (iter == tiles_.end())
- return NULL;
- return iter->second.get();
-}
-
-void PictureLayerTiling::CreateTile(int i,
- int j,
- const PictureLayerTiling* twin_tiling) {
+Tile* PictureLayerTiling::CreateTile(int i,
+ int j,
+ const PictureLayerTiling* twin_tiling) {
TileMapKey key(i, j);
DCHECK(tiles_.find(key) == tiles_.end());
@@ -90,7 +110,7 @@ void PictureLayerTiling::CreateTile(int i,
gfx::ScaleToEnclosingRect(paint_rect, 1.0f / contents_scale_);
if (!client_->GetInvalidation()->Intersects(rect)) {
tiles_[key] = candidate_tile;
- return;
+ return candidate_tile;
}
}
}
@@ -99,23 +119,15 @@ void PictureLayerTiling::CreateTile(int i,
scoped_refptr<Tile> tile = client_->CreateTile(this, tile_rect);
if (tile.get())
tiles_[key] = tile;
-}
-
-Region PictureLayerTiling::OpaqueRegionInContentRect(
- gfx::Rect content_rect) const {
- Region opaque_region;
- // TODO(enne): implement me
- return opaque_region;
-}
-
-void PictureLayerTiling::SetCanUseLCDText(bool can_use_lcd_text) {
- for (TileMap::iterator it = tiles_.begin(); it != tiles_.end(); ++it)
- it->second->set_can_use_lcd_text(can_use_lcd_text);
+ return tile.get();
}
void PictureLayerTiling::CreateMissingTilesInLiveTilesRect() {
const PictureLayerTiling* twin_tiling = client_->GetTwinTiling(this);
- for (TilingData::Iterator iter(&tiling_data_, live_tiles_rect_); iter;
+ bool include_borders = true;
+ for (TilingData::Iterator iter(
+ &tiling_data_, live_tiles_rect_, include_borders);
+ iter;
++iter) {
TileMapKey key = iter.index();
TileMap::iterator find = tiles_.find(key);
@@ -125,7 +137,7 @@ void PictureLayerTiling::CreateMissingTilesInLiveTilesRect() {
}
}
-void PictureLayerTiling::SetLayerBounds(gfx::Size layer_bounds) {
+void PictureLayerTiling::SetLayerBounds(const gfx::Size& layer_bounds) {
if (layer_bounds_ == layer_bounds)
return;
@@ -133,13 +145,12 @@ void PictureLayerTiling::SetLayerBounds(gfx::Size layer_bounds) {
gfx::Size old_layer_bounds = layer_bounds_;
layer_bounds_ = layer_bounds;
- gfx::Size old_content_bounds = tiling_data_.total_size();
gfx::Size content_bounds =
gfx::ToCeiledSize(gfx::ScaleSize(layer_bounds_, contents_scale_));
gfx::Size tile_size = client_->CalculateTileSize(content_bounds);
if (tile_size != tiling_data_.max_texture_size()) {
- tiling_data_.SetTotalSize(content_bounds);
+ tiling_data_.SetTilingRect(gfx::Rect(content_bounds));
tiling_data_.SetMaxTextureSize(tile_size);
Reset();
return;
@@ -149,7 +160,7 @@ void PictureLayerTiling::SetLayerBounds(gfx::Size layer_bounds) {
gfx::Rect bounded_live_tiles_rect(live_tiles_rect_);
bounded_live_tiles_rect.Intersect(gfx::Rect(content_bounds));
SetLiveTilesRect(bounded_live_tiles_rect);
- tiling_data_.SetTotalSize(content_bounds);
+ tiling_data_.SetTilingRect(gfx::Rect(content_bounds));
// Create tiles for newly exposed areas.
Region layer_region((gfx::Rect(layer_bounds_)));
@@ -157,28 +168,48 @@ void PictureLayerTiling::SetLayerBounds(gfx::Size layer_bounds) {
Invalidate(layer_region);
}
+void PictureLayerTiling::RemoveTilesInRegion(const Region& layer_region) {
+ DoInvalidate(layer_region, false /* recreate_tiles */);
+}
+
void PictureLayerTiling::Invalidate(const Region& layer_region) {
+ DoInvalidate(layer_region, true /* recreate_tiles */);
+}
+
+void PictureLayerTiling::DoInvalidate(const Region& layer_region,
+ bool recreate_tiles) {
std::vector<TileMapKey> new_tile_keys;
+ gfx::Rect expanded_live_tiles_rect(
+ tiling_data_.ExpandRectToTileBoundsWithBorders(live_tiles_rect_));
for (Region::Iterator iter(layer_region); iter.has_rect(); iter.next()) {
gfx::Rect layer_rect = iter.rect();
gfx::Rect content_rect =
gfx::ScaleToEnclosingRect(layer_rect, contents_scale_);
- content_rect.Intersect(live_tiles_rect_);
+ // Avoid needless work by not bothering to invalidate where there aren't
+ // tiles.
+ content_rect.Intersect(expanded_live_tiles_rect);
if (content_rect.IsEmpty())
continue;
- for (TilingData::Iterator iter(&tiling_data_, content_rect); iter; ++iter) {
+ bool include_borders = true;
+ for (TilingData::Iterator iter(
+ &tiling_data_, content_rect, include_borders);
+ iter;
+ ++iter) {
TileMapKey key(iter.index());
TileMap::iterator find = tiles_.find(key);
if (find == tiles_.end())
continue;
tiles_.erase(find);
- new_tile_keys.push_back(key);
+ if (recreate_tiles)
+ new_tile_keys.push_back(key);
}
}
- const PictureLayerTiling* twin_tiling = client_->GetTwinTiling(this);
- for (size_t i = 0; i < new_tile_keys.size(); ++i)
- CreateTile(new_tile_keys[i].first, new_tile_keys[i].second, twin_tiling);
+ if (recreate_tiles) {
+ const PictureLayerTiling* twin_tiling = client_->GetTwinTiling(this);
+ for (size_t i = 0; i < new_tile_keys.size(); ++i)
+ CreateTile(new_tile_keys[i].first, new_tile_keys[i].second, twin_tiling);
+ }
}
PictureLayerTiling::CoverageIterator::CoverageIterator()
@@ -195,7 +226,7 @@ PictureLayerTiling::CoverageIterator::CoverageIterator()
PictureLayerTiling::CoverageIterator::CoverageIterator(
const PictureLayerTiling* tiling,
float dest_scale,
- gfx::Rect dest_rect)
+ const gfx::Rect& dest_rect)
: tiling_(tiling),
dest_rect_(dest_rect),
dest_to_content_scale_(0),
@@ -211,11 +242,6 @@ PictureLayerTiling::CoverageIterator::CoverageIterator(
return;
dest_to_content_scale_ = tiling_->contents_scale_ / dest_scale;
- // This is the maximum size that the dest rect can be, given the content size.
- gfx::Size dest_content_size = gfx::ToCeiledSize(gfx::ScaleSize(
- tiling_->ContentRect().size(),
- 1 / dest_to_content_scale_,
- 1 / dest_to_content_scale_));
gfx::Rect content_rect =
gfx::ScaleToEnclosingRect(dest_rect_,
@@ -223,7 +249,7 @@ PictureLayerTiling::CoverageIterator::CoverageIterator(
dest_to_content_scale_);
// IndexFromSrcCoord clamps to valid tile ranges, so it's necessary to
// check for non-intersection first.
- content_rect.Intersect(gfx::Rect(tiling_->tiling_data_.total_size()));
+ content_rect.Intersect(tiling_->TilingRect());
if (content_rect.IsEmpty())
return;
@@ -324,8 +350,10 @@ gfx::RectF PictureLayerTiling::CoverageIterator::texture_rect() const {
gfx::RectF texture_rect(current_geometry_rect_);
texture_rect.Scale(dest_to_content_scale_,
dest_to_content_scale_);
+ texture_rect.Intersect(tiling_->TilingRect());
+ if (texture_rect.IsEmpty())
+ return texture_rect;
texture_rect.Offset(-tex_origin.OffsetFromOrigin());
- texture_rect.Intersect(tiling_->ContentRect());
return texture_rect;
}
@@ -339,229 +367,186 @@ void PictureLayerTiling::Reset() {
tiles_.clear();
}
+gfx::Rect PictureLayerTiling::ComputeSkewport(
+ double current_frame_time_in_seconds,
+ const gfx::Rect& visible_rect_in_content_space) const {
+ gfx::Rect skewport = visible_rect_in_content_space;
+ if (last_impl_frame_time_in_seconds_ == 0.0)
+ return skewport;
+
+ double time_delta =
+ current_frame_time_in_seconds - last_impl_frame_time_in_seconds_;
+ if (time_delta == 0.0)
+ return skewport;
+
+ float skewport_target_time_in_seconds =
+ client_->GetSkewportTargetTimeInSeconds();
+ double extrapolation_multiplier =
+ skewport_target_time_in_seconds / time_delta;
+
+ int old_x = last_visible_rect_in_content_space_.x();
+ int old_y = last_visible_rect_in_content_space_.y();
+ int old_right = last_visible_rect_in_content_space_.right();
+ int old_bottom = last_visible_rect_in_content_space_.bottom();
+
+ int new_x = visible_rect_in_content_space.x();
+ int new_y = visible_rect_in_content_space.y();
+ int new_right = visible_rect_in_content_space.right();
+ int new_bottom = visible_rect_in_content_space.bottom();
+
+ int skewport_limit = client_->GetSkewportExtrapolationLimitInContentPixels();
+
+ // Compute the maximum skewport based on |skewport_limit|.
+ gfx::Rect max_skewport = skewport;
+ max_skewport.Inset(
+ -skewport_limit, -skewport_limit, -skewport_limit, -skewport_limit);
+
+ // Inset the skewport by the needed adjustment.
+ skewport.Inset(extrapolation_multiplier * (new_x - old_x),
+ extrapolation_multiplier * (new_y - old_y),
+ extrapolation_multiplier * (old_right - new_right),
+ extrapolation_multiplier * (old_bottom - new_bottom));
+
+ // Clip the skewport to |max_skewport|.
+ skewport.Intersect(max_skewport);
+
+ // Finally, ensure that visible rect is contained in the skewport.
+ skewport.Union(visible_rect_in_content_space);
+ return skewport;
+}
+
void PictureLayerTiling::UpdateTilePriorities(
WhichTree tree,
- gfx::Size device_viewport,
- gfx::Rect viewport_in_layer_space,
- gfx::Rect visible_layer_rect,
- gfx::Size last_layer_bounds,
- gfx::Size current_layer_bounds,
- float last_layer_contents_scale,
- float current_layer_contents_scale,
- const gfx::Transform& last_screen_transform,
- const gfx::Transform& current_screen_transform,
- double current_frame_time_in_seconds,
- size_t max_tiles_for_interest_area) {
+ const gfx::Rect& visible_layer_rect,
+ float layer_contents_scale,
+ double current_frame_time_in_seconds) {
if (!NeedsUpdateForFrameAtTime(current_frame_time_in_seconds)) {
// This should never be zero for the purposes of has_ever_been_updated().
DCHECK_NE(current_frame_time_in_seconds, 0.0);
return;
}
- if (ContentRect().IsEmpty()) {
+
+ gfx::Rect visible_rect_in_content_space =
+ gfx::ScaleToEnclosingRect(visible_layer_rect, contents_scale_);
+
+ if (TilingRect().IsEmpty()) {
last_impl_frame_time_in_seconds_ = current_frame_time_in_seconds;
+ last_visible_rect_in_content_space_ = visible_rect_in_content_space;
return;
}
- gfx::Rect viewport_in_content_space =
- gfx::ScaleToEnclosingRect(viewport_in_layer_space, contents_scale_);
- gfx::Rect visible_content_rect =
- gfx::ScaleToEnclosingRect(visible_layer_rect, contents_scale_);
+ size_t max_tiles_for_interest_area = client_->GetMaxTilesForInterestArea();
gfx::Size tile_size = tiling_data_.max_texture_size();
- int64 interest_rect_area =
+ int64 eventually_rect_area =
max_tiles_for_interest_area * tile_size.width() * tile_size.height();
- gfx::Rect starting_rect = visible_content_rect.IsEmpty()
- ? viewport_in_content_space
- : visible_content_rect;
- gfx::Rect interest_rect = ExpandRectEquallyToAreaBoundedBy(
- starting_rect,
- interest_rect_area,
- ContentRect(),
- &expansion_cache_);
- DCHECK(interest_rect.IsEmpty() ||
- ContentRect().Contains(interest_rect));
-
- SetLiveTilesRect(interest_rect);
-
- double time_delta = 0;
- if (last_impl_frame_time_in_seconds_ != 0.0 &&
- last_layer_bounds == current_layer_bounds) {
- time_delta =
- current_frame_time_in_seconds - last_impl_frame_time_in_seconds_;
+ gfx::Rect skewport = ComputeSkewport(current_frame_time_in_seconds,
+ visible_rect_in_content_space);
+ DCHECK(skewport.Contains(visible_rect_in_content_space));
+
+ gfx::Rect eventually_rect =
+ ExpandRectEquallyToAreaBoundedBy(visible_rect_in_content_space,
+ eventually_rect_area,
+ TilingRect(),
+ &expansion_cache_);
+
+ DCHECK(eventually_rect.IsEmpty() || TilingRect().Contains(eventually_rect));
+
+ SetLiveTilesRect(eventually_rect);
+
+ last_impl_frame_time_in_seconds_ = current_frame_time_in_seconds;
+ last_visible_rect_in_content_space_ = visible_rect_in_content_space;
+
+ current_visible_rect_in_content_space_ = visible_rect_in_content_space;
+ current_skewport_ = skewport;
+ current_eventually_rect_ = eventually_rect;
+ eviction_tiles_cache_valid_ = false;
+
+ TilePriority now_priority(resolution_, TilePriority::NOW, 0);
+ float content_to_screen_scale =
+ 1.0f / (contents_scale_ * layer_contents_scale);
+
+ // Assign now priority to all visible tiles.
+ bool include_borders = true;
+ for (TilingData::Iterator iter(
+ &tiling_data_, visible_rect_in_content_space, include_borders);
+ iter;
+ ++iter) {
+ TileMap::iterator find = tiles_.find(iter.index());
+ if (find == tiles_.end())
+ continue;
+ Tile* tile = find->second.get();
+
+ tile->SetPriority(tree, now_priority);
}
- gfx::RectF view_rect(device_viewport);
- float current_scale = current_layer_contents_scale / contents_scale_;
- float last_scale = last_layer_contents_scale / contents_scale_;
-
- // Fast path tile priority calculation when both transforms are translations.
- if (last_screen_transform.IsApproximatelyIdentityOrTranslation(
- std::numeric_limits<float>::epsilon()) &&
- current_screen_transform.IsApproximatelyIdentityOrTranslation(
- std::numeric_limits<float>::epsilon())) {
- gfx::Vector2dF current_offset(
- current_screen_transform.matrix().get(0, 3),
- current_screen_transform.matrix().get(1, 3));
- gfx::Vector2dF last_offset(
- last_screen_transform.matrix().get(0, 3),
- last_screen_transform.matrix().get(1, 3));
-
- for (TilingData::Iterator iter(&tiling_data_, interest_rect);
- iter; ++iter) {
- TileMap::iterator find = tiles_.find(iter.index());
- if (find == tiles_.end())
- continue;
- Tile* tile = find->second.get();
-
- gfx::Rect tile_bounds =
- tiling_data_.TileBounds(iter.index_x(), iter.index_y());
- gfx::RectF current_screen_rect = gfx::ScaleRect(
- tile_bounds,
- current_scale,
- current_scale) + current_offset;
- gfx::RectF last_screen_rect = gfx::ScaleRect(
- tile_bounds,
- last_scale,
- last_scale) + last_offset;
-
- float distance_to_visible_in_pixels =
- current_screen_rect.ManhattanInternalDistance(view_rect);
-
- float time_to_visible_in_seconds =
- TilePriority::TimeForBoundsToIntersect(
- last_screen_rect, current_screen_rect, time_delta, view_rect);
- TilePriority priority(
- resolution_,
- time_to_visible_in_seconds,
- distance_to_visible_in_pixels);
- tile->SetPriority(tree, priority);
- }
- } else if (!last_screen_transform.HasPerspective() &&
- !current_screen_transform.HasPerspective()) {
- // Secondary fast path that can be applied for any affine transforms.
-
- // Initialize the necessary geometry in screen space, so that we can
- // iterate over tiles in screen space without needing a costly transform
- // mapping for each tile.
-
- // Apply screen space transform to the local origin point (0, 0); only the
- // translation component is needed and can be initialized directly.
- gfx::Point current_screen_space_origin(
- current_screen_transform.matrix().get(0, 3),
- current_screen_transform.matrix().get(1, 3));
-
- gfx::Point last_screen_space_origin(
- last_screen_transform.matrix().get(0, 3),
- last_screen_transform.matrix().get(1, 3));
-
- float current_tile_width = tiling_data_.TileSizeX(0) * current_scale;
- float last_tile_width = tiling_data_.TileSizeX(0) * last_scale;
- float current_tile_height = tiling_data_.TileSizeY(0) * current_scale;
- float last_tile_height = tiling_data_.TileSizeY(0) * last_scale;
-
- // Apply screen space transform to local basis vectors (tile_width, 0) and
- // (0, tile_height); the math simplifies and can be initialized directly.
- gfx::Vector2dF current_horizontal(
- current_screen_transform.matrix().get(0, 0) * current_tile_width,
- current_screen_transform.matrix().get(1, 0) * current_tile_width);
- gfx::Vector2dF current_vertical(
- current_screen_transform.matrix().get(0, 1) * current_tile_height,
- current_screen_transform.matrix().get(1, 1) * current_tile_height);
-
- gfx::Vector2dF last_horizontal(
- last_screen_transform.matrix().get(0, 0) * last_tile_width,
- last_screen_transform.matrix().get(1, 0) * last_tile_width);
- gfx::Vector2dF last_vertical(
- last_screen_transform.matrix().get(0, 1) * last_tile_height,
- last_screen_transform.matrix().get(1, 1) * last_tile_height);
-
- for (TilingData::Iterator iter(&tiling_data_, interest_rect);
- iter; ++iter) {
- TileMap::iterator find = tiles_.find(iter.index());
- if (find == tiles_.end())
- continue;
+ // Assign soon priority to skewport tiles.
+ for (TilingData::DifferenceIterator iter(
+ &tiling_data_, skewport, visible_rect_in_content_space);
+ iter;
+ ++iter) {
+ TileMap::iterator find = tiles_.find(iter.index());
+ if (find == tiles_.end())
+ continue;
+ Tile* tile = find->second.get();
- Tile* tile = find->second.get();
-
- int i = iter.index_x();
- int j = iter.index_y();
- gfx::PointF current_tile_origin = current_screen_space_origin +
- ScaleVector2d(current_horizontal, i) +
- ScaleVector2d(current_vertical, j);
- gfx::PointF last_tile_origin = last_screen_space_origin +
- ScaleVector2d(last_horizontal, i) +
- ScaleVector2d(last_vertical, j);
-
- gfx::RectF current_screen_rect = gfx::QuadF(
- current_tile_origin,
- current_tile_origin + current_horizontal,
- current_tile_origin + current_horizontal + current_vertical,
- current_tile_origin + current_vertical).BoundingBox();
-
- gfx::RectF last_screen_rect = gfx::QuadF(
- last_tile_origin,
- last_tile_origin + last_horizontal,
- last_tile_origin + last_horizontal + last_vertical,
- last_tile_origin + last_vertical).BoundingBox();
-
- float distance_to_visible_in_pixels =
- current_screen_rect.ManhattanInternalDistance(view_rect);
-
- float time_to_visible_in_seconds =
- TilePriority::TimeForBoundsToIntersect(
- last_screen_rect, current_screen_rect, time_delta, view_rect);
- TilePriority priority(
- resolution_,
- time_to_visible_in_seconds,
- distance_to_visible_in_pixels);
- tile->SetPriority(tree, priority);
- }
- } else {
- for (TilingData::Iterator iter(&tiling_data_, interest_rect);
- iter; ++iter) {
- TileMap::iterator find = tiles_.find(iter.index());
- if (find == tiles_.end())
- continue;
- Tile* tile = find->second.get();
-
- gfx::Rect tile_bounds =
- tiling_data_.TileBounds(iter.index_x(), iter.index_y());
- gfx::RectF current_layer_content_rect = gfx::ScaleRect(
- tile_bounds,
- current_scale,
- current_scale);
- gfx::RectF current_screen_rect = MathUtil::MapClippedRect(
- current_screen_transform, current_layer_content_rect);
- gfx::RectF last_layer_content_rect = gfx::ScaleRect(
- tile_bounds,
- last_scale,
- last_scale);
- gfx::RectF last_screen_rect = MathUtil::MapClippedRect(
- last_screen_transform, last_layer_content_rect);
-
- float distance_to_visible_in_pixels =
- current_screen_rect.ManhattanInternalDistance(view_rect);
-
- float time_to_visible_in_seconds =
- TilePriority::TimeForBoundsToIntersect(
- last_screen_rect, current_screen_rect, time_delta, view_rect);
-
- TilePriority priority(
- resolution_,
- time_to_visible_in_seconds,
- distance_to_visible_in_pixels);
- tile->SetPriority(tree, priority);
- }
+ gfx::Rect tile_bounds =
+ tiling_data_.TileBounds(iter.index_x(), iter.index_y());
+
+ float distance_to_visible =
+ visible_rect_in_content_space.ManhattanInternalDistance(tile_bounds) *
+ content_to_screen_scale;
+
+ TilePriority priority(resolution_, TilePriority::SOON, distance_to_visible);
+ tile->SetPriority(tree, priority);
}
- last_impl_frame_time_in_seconds_ = current_frame_time_in_seconds;
+ // Assign eventually priority to interest rect tiles.
+ for (TilingData::DifferenceIterator iter(
+ &tiling_data_, eventually_rect, skewport);
+ iter;
+ ++iter) {
+ TileMap::iterator find = tiles_.find(iter.index());
+ if (find == tiles_.end())
+ continue;
+ Tile* tile = find->second.get();
+
+ gfx::Rect tile_bounds =
+ tiling_data_.TileBounds(iter.index_x(), iter.index_y());
+
+ float distance_to_visible =
+ visible_rect_in_content_space.ManhattanInternalDistance(tile_bounds) *
+ content_to_screen_scale;
+ TilePriority priority(
+ resolution_, TilePriority::EVENTUALLY, distance_to_visible);
+ tile->SetPriority(tree, priority);
+ }
+
+ // Upgrade the priority on border tiles to be SOON.
+ current_soon_border_rect_ = visible_rect_in_content_space;
+ float border = kSoonBorderDistanceInScreenPixels / content_to_screen_scale;
+ current_soon_border_rect_.Inset(-border, -border, -border, -border);
+ for (TilingData::DifferenceIterator iter(
+ &tiling_data_, current_soon_border_rect_, skewport);
+ iter;
+ ++iter) {
+ TileMap::iterator find = tiles_.find(iter.index());
+ if (find == tiles_.end())
+ continue;
+ Tile* tile = find->second.get();
+
+ TilePriority priority(resolution_,
+ TilePriority::SOON,
+ tile->priority(tree).distance_to_visible);
+ tile->SetPriority(tree, priority);
+ }
}
void PictureLayerTiling::SetLiveTilesRect(
- gfx::Rect new_live_tiles_rect) {
+ const gfx::Rect& new_live_tiles_rect) {
DCHECK(new_live_tiles_rect.IsEmpty() ||
- ContentRect().Contains(new_live_tiles_rect));
+ TilingRect().Contains(new_live_tiles_rect));
if (live_tiles_rect_ == new_live_tiles_rect)
return;
@@ -629,8 +614,7 @@ scoped_ptr<base::Value> PictureLayerTiling::AsValue() const {
scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue());
state->SetInteger("num_tiles", tiles_.size());
state->SetDouble("content_scale", contents_scale_);
- state->Set("content_bounds",
- MathUtil::AsValue(ContentRect().size()).release());
+ state->Set("tiling_rect", MathUtil::AsValue(TilingRect()).release());
return state.PassAs<base::Value>();
}
@@ -676,9 +660,9 @@ int ComputeExpansionDelta(int num_x_edges, int num_y_edges,
} // namespace
gfx::Rect PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy(
- gfx::Rect starting_rect,
+ const gfx::Rect& starting_rect,
int64 target_area,
- gfx::Rect bounding_rect,
+ const gfx::Rect& bounding_rect,
RectExpansionCache* cache) {
if (starting_rect.IsEmpty())
return starting_rect;
@@ -792,4 +776,188 @@ gfx::Rect PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy(
return result;
}
+void PictureLayerTiling::UpdateEvictionCacheIfNeeded(
+ TreePriority tree_priority) {
+ if (eviction_tiles_cache_valid_ &&
+ eviction_cache_tree_priority_ == tree_priority)
+ return;
+
+ eviction_tiles_cache_.clear();
+ eviction_tiles_cache_.reserve(tiles_.size());
+ for (TileMap::iterator it = tiles_.begin(); it != tiles_.end(); ++it) {
+ // TODO(vmpstr): This should update the priority if UpdateTilePriorities
+ // changes not to do this.
+ eviction_tiles_cache_.push_back(it->second);
+ }
+
+ std::sort(eviction_tiles_cache_.begin(),
+ eviction_tiles_cache_.end(),
+ TileEvictionOrder(tree_priority));
+ eviction_tiles_cache_valid_ = true;
+ eviction_cache_tree_priority_ = tree_priority;
+}
+
+PictureLayerTiling::TilingRasterTileIterator::TilingRasterTileIterator()
+ : tiling_(NULL), current_tile_(NULL) {}
+
+PictureLayerTiling::TilingRasterTileIterator::TilingRasterTileIterator(
+ PictureLayerTiling* tiling,
+ WhichTree tree)
+ : tiling_(tiling),
+ type_(TilePriority::NOW),
+ visible_rect_in_content_space_(
+ tiling_->current_visible_rect_in_content_space_),
+ skewport_in_content_space_(tiling_->current_skewport_),
+ eventually_rect_in_content_space_(tiling_->current_eventually_rect_),
+ soon_border_rect_in_content_space_(tiling_->current_soon_border_rect_),
+ tree_(tree),
+ current_tile_(NULL),
+ visible_iterator_(&tiling->tiling_data_,
+ visible_rect_in_content_space_,
+ true /* include_borders */),
+ spiral_iterator_(&tiling->tiling_data_,
+ skewport_in_content_space_,
+ visible_rect_in_content_space_,
+ visible_rect_in_content_space_),
+ skewport_processed_(false) {
+ if (!visible_iterator_) {
+ AdvancePhase();
+ return;
+ }
+
+ current_tile_ =
+ tiling_->TileAt(visible_iterator_.index_x(), visible_iterator_.index_y());
+ if (!current_tile_ || !TileNeedsRaster(current_tile_))
+ ++(*this);
+}
+
+PictureLayerTiling::TilingRasterTileIterator::~TilingRasterTileIterator() {}
+
+void PictureLayerTiling::TilingRasterTileIterator::AdvancePhase() {
+ DCHECK_LT(type_, TilePriority::EVENTUALLY);
+
+ do {
+ type_ = static_cast<TilePriority::PriorityBin>(type_ + 1);
+ if (type_ == TilePriority::EVENTUALLY) {
+ spiral_iterator_ = TilingData::SpiralDifferenceIterator(
+ &tiling_->tiling_data_,
+ eventually_rect_in_content_space_,
+ skewport_in_content_space_,
+ visible_rect_in_content_space_);
+ }
+
+ while (spiral_iterator_) {
+ current_tile_ = tiling_->TileAt(spiral_iterator_.index_x(),
+ spiral_iterator_.index_y());
+ if (current_tile_ && TileNeedsRaster(current_tile_))
+ break;
+ ++spiral_iterator_;
+ }
+
+ if (!spiral_iterator_ && type_ == TilePriority::EVENTUALLY) {
+ current_tile_ = NULL;
+ break;
+ }
+ } while (!spiral_iterator_);
+}
+
+PictureLayerTiling::TilingRasterTileIterator&
+PictureLayerTiling::TilingRasterTileIterator::
+operator++() {
+ current_tile_ = NULL;
+ while (!current_tile_ || !TileNeedsRaster(current_tile_)) {
+ std::pair<int, int> next_index;
+ switch (type_) {
+ case TilePriority::NOW:
+ ++visible_iterator_;
+ if (!visible_iterator_) {
+ AdvancePhase();
+ return *this;
+ }
+ next_index = visible_iterator_.index();
+ break;
+ case TilePriority::SOON:
+ ++spiral_iterator_;
+ if (!spiral_iterator_) {
+ if (skewport_processed_) {
+ AdvancePhase();
+ return *this;
+ }
+ skewport_processed_ = true;
+ spiral_iterator_ = TilingData::SpiralDifferenceIterator(
+ &tiling_->tiling_data_,
+ soon_border_rect_in_content_space_,
+ skewport_in_content_space_,
+ visible_rect_in_content_space_);
+ if (!spiral_iterator_) {
+ AdvancePhase();
+ return *this;
+ }
+ }
+ next_index = spiral_iterator_.index();
+ break;
+ case TilePriority::EVENTUALLY:
+ ++spiral_iterator_;
+ if (!spiral_iterator_) {
+ current_tile_ = NULL;
+ return *this;
+ }
+ next_index = spiral_iterator_.index();
+ break;
+ }
+ current_tile_ = tiling_->TileAt(next_index.first, next_index.second);
+ }
+ return *this;
+}
+
+PictureLayerTiling::TilingEvictionTileIterator::TilingEvictionTileIterator()
+ : is_valid_(false), tiling_(NULL) {}
+
+PictureLayerTiling::TilingEvictionTileIterator::TilingEvictionTileIterator(
+ PictureLayerTiling* tiling,
+ TreePriority tree_priority)
+ : is_valid_(false), tiling_(tiling), tree_priority_(tree_priority) {}
+
+PictureLayerTiling::TilingEvictionTileIterator::~TilingEvictionTileIterator() {}
+
+PictureLayerTiling::TilingEvictionTileIterator::operator bool() {
+ if (!IsValid())
+ Initialize();
+
+ return IsValid() && tile_iterator_ != tiling_->eviction_tiles_cache_.end();
+}
+
+Tile* PictureLayerTiling::TilingEvictionTileIterator::operator*() {
+ if (!IsValid())
+ Initialize();
+
+ DCHECK(*this);
+ return *tile_iterator_;
+}
+
+PictureLayerTiling::TilingEvictionTileIterator&
+PictureLayerTiling::TilingEvictionTileIterator::
+operator++() {
+ DCHECK(*this);
+ do {
+ ++tile_iterator_;
+ } while (tile_iterator_ != tiling_->eviction_tiles_cache_.end() &&
+ (!(*tile_iterator_)->HasResources()));
+
+ return *this;
+}
+
+void PictureLayerTiling::TilingEvictionTileIterator::Initialize() {
+ if (!tiling_)
+ return;
+
+ tiling_->UpdateEvictionCacheIfNeeded(tree_priority_);
+ tile_iterator_ = tiling_->eviction_tiles_cache_.begin();
+ is_valid_ = true;
+ if (tile_iterator_ != tiling_->eviction_tiles_cache_.end() &&
+ !(*tile_iterator_)->HasResources()) {
+ ++(*this);
+ }
+}
+
} // namespace cc
diff --git a/chromium/cc/resources/picture_layer_tiling.h b/chromium/cc/resources/picture_layer_tiling.h
index dae62723711..fc7505c99ad 100644
--- a/chromium/cc/resources/picture_layer_tiling.h
+++ b/chromium/cc/resources/picture_layer_tiling.h
@@ -28,13 +28,16 @@ class CC_EXPORT PictureLayerTilingClient {
// tiling) This might return null if the client cannot create such a tile.
virtual scoped_refptr<Tile> CreateTile(
PictureLayerTiling* tiling,
- gfx::Rect content_rect) = 0;
+ const gfx::Rect& content_rect) = 0;
virtual void UpdatePile(Tile* tile) = 0;
virtual gfx::Size CalculateTileSize(
- gfx::Size content_bounds) const = 0;
+ const gfx::Size& content_bounds) const = 0;
virtual const Region* GetInvalidation() = 0;
virtual const PictureLayerTiling* GetTwinTiling(
const PictureLayerTiling* tiling) const = 0;
+ virtual size_t GetMaxTilesForInterestArea() const = 0;
+ virtual float GetSkewportTargetTimeInSeconds() const = 0;
+ virtual int GetSkewportExtrapolationLimitInContentPixels() const = 0;
protected:
virtual ~PictureLayerTilingClient() {}
@@ -42,32 +45,106 @@ class CC_EXPORT PictureLayerTilingClient {
class CC_EXPORT PictureLayerTiling {
public:
+ class CC_EXPORT TilingRasterTileIterator {
+ public:
+ TilingRasterTileIterator();
+ TilingRasterTileIterator(PictureLayerTiling* tiling, WhichTree tree);
+ ~TilingRasterTileIterator();
+
+ operator bool() const { return !!current_tile_; }
+ Tile* operator*() { return current_tile_; }
+ TilePriority::PriorityBin get_type() const { return type_; }
+
+ TilingRasterTileIterator& operator++();
+
+ gfx::Rect TileBounds() const {
+ DCHECK(*this);
+ if (type_ == TilePriority::NOW) {
+ return tiling_->tiling_data_.TileBounds(visible_iterator_.index_x(),
+ visible_iterator_.index_y());
+ }
+ return tiling_->tiling_data_.TileBounds(spiral_iterator_.index_x(),
+ spiral_iterator_.index_y());
+ }
+
+ private:
+ void AdvancePhase();
+ bool TileNeedsRaster(Tile* tile) const {
+ RasterMode mode = tile->DetermineRasterModeForTree(tree_);
+ return tile->NeedsRasterForMode(mode);
+ }
+
+ PictureLayerTiling* tiling_;
+
+ TilePriority::PriorityBin type_;
+ gfx::Rect visible_rect_in_content_space_;
+ gfx::Rect skewport_in_content_space_;
+ gfx::Rect eventually_rect_in_content_space_;
+ gfx::Rect soon_border_rect_in_content_space_;
+ WhichTree tree_;
+
+ Tile* current_tile_;
+ TilingData::Iterator visible_iterator_;
+ TilingData::SpiralDifferenceIterator spiral_iterator_;
+ bool skewport_processed_;
+ };
+
+ class CC_EXPORT TilingEvictionTileIterator {
+ public:
+ TilingEvictionTileIterator();
+ TilingEvictionTileIterator(PictureLayerTiling* tiling,
+ TreePriority tree_priority);
+ ~TilingEvictionTileIterator();
+
+ operator bool();
+ Tile* operator*();
+ TilingEvictionTileIterator& operator++();
+ TilePriority::PriorityBin get_type() {
+ DCHECK(*this);
+ const TilePriority& priority =
+ (*tile_iterator_)->priority_for_tree_priority(tree_priority_);
+ return priority.priority_bin;
+ }
+
+ private:
+ void Initialize();
+ bool IsValid() const { return is_valid_; }
+
+ bool is_valid_;
+ PictureLayerTiling* tiling_;
+ TreePriority tree_priority_;
+ std::vector<Tile*>::iterator tile_iterator_;
+ };
+
~PictureLayerTiling();
// Create a tiling with no tiles. CreateTiles must be called to add some.
static scoped_ptr<PictureLayerTiling> Create(
float contents_scale,
- gfx::Size layer_bounds,
+ const gfx::Size& layer_bounds,
PictureLayerTilingClient* client);
gfx::Size layer_bounds() const { return layer_bounds_; }
- void SetLayerBounds(gfx::Size layer_bounds);
+ void SetLayerBounds(const gfx::Size& layer_bounds);
void Invalidate(const Region& layer_region);
+ void RemoveTilesInRegion(const Region& layer_region);
void CreateMissingTilesInLiveTilesRect();
- void SetCanUseLCDText(bool can_use_lcd_text);
-
void SetClient(PictureLayerTilingClient* client);
void set_resolution(TileResolution resolution) { resolution_ = resolution; }
TileResolution resolution() const { return resolution_; }
- gfx::Rect ContentRect() const;
- gfx::SizeF ContentSizeF() const;
+ gfx::Rect TilingRect() const;
gfx::Rect live_tiles_rect() const { return live_tiles_rect_; }
gfx::Size tile_size() const { return tiling_data_.max_texture_size(); }
float contents_scale() const { return contents_scale_; }
+ Tile* TileAt(int i, int j) const {
+ TileMap::const_iterator iter = tiles_.find(TileMapKey(i, j));
+ return (iter == tiles_.end()) ? NULL : iter->second.get();
+ }
+
void CreateAllTilesForTesting() {
- SetLiveTilesRect(gfx::Rect(tiling_data_.total_size()));
+ SetLiveTilesRect(tiling_data_.tiling_rect());
}
std::vector<Tile*> AllTilesForTesting() const {
@@ -78,8 +155,6 @@ class CC_EXPORT PictureLayerTiling {
return all_tiles;
}
- Tile* TileAt(int i, int j) const;
-
// Iterate over all tiles to fill content_rect. Even if tiles are invalid
// (i.e. no valid resource) this tiling should still iterate over them.
// The union of all geometry_rect calls for each element iterated over should
@@ -89,7 +164,7 @@ class CC_EXPORT PictureLayerTiling {
CoverageIterator();
CoverageIterator(const PictureLayerTiling* tiling,
float dest_scale,
- gfx::Rect rect);
+ const gfx::Rect& rect);
~CoverageIterator();
// Visible rect (no borders), always in the space of content_rect,
@@ -129,23 +204,12 @@ class CC_EXPORT PictureLayerTiling {
friend class PictureLayerTiling;
};
- Region OpaqueRegionInContentRect(gfx::Rect content_rect) const;
-
void Reset();
- void UpdateTilePriorities(
- WhichTree tree,
- gfx::Size device_viewport,
- gfx::Rect viewport_in_layer_space,
- gfx::Rect visible_layer_rect,
- gfx::Size last_layer_bounds,
- gfx::Size current_layer_bounds,
- float last_layer_contents_scale,
- float current_layer_contents_scale,
- const gfx::Transform& last_screen_transform,
- const gfx::Transform& current_screen_transform,
- double current_frame_time_in_seconds,
- size_t max_tiles_for_interest_area);
+ void UpdateTilePriorities(WhichTree tree,
+ const gfx::Rect& visible_layer_rect,
+ float layer_contents_scale,
+ double current_frame_time_in_seconds);
// Copies the src_tree priority into the dst_tree priority for all tiles.
// The src_tree priority is reset to the lowest priority possible. This
@@ -179,9 +243,9 @@ class CC_EXPORT PictureLayerTiling {
static
gfx::Rect ExpandRectEquallyToAreaBoundedBy(
- gfx::Rect starting_rect,
+ const gfx::Rect& starting_rect,
int64 target_area,
- gfx::Rect bounding_rect,
+ const gfx::Rect& bounding_rect,
RectExpansionCache* cache);
bool has_ever_been_updated() const {
@@ -189,14 +253,29 @@ class CC_EXPORT PictureLayerTiling {
}
protected:
+ friend class CoverageIterator;
+ friend class TilingRasterTileIterator;
+ friend class TilingEvictionTileIterator;
+
typedef std::pair<int, int> TileMapKey;
typedef base::hash_map<TileMapKey, scoped_refptr<Tile> > TileMap;
PictureLayerTiling(float contents_scale,
- gfx::Size layer_bounds,
+ const gfx::Size& layer_bounds,
PictureLayerTilingClient* client);
- void SetLiveTilesRect(gfx::Rect live_tiles_rect);
- void CreateTile(int i, int j, const PictureLayerTiling* twin_tiling);
+ void SetLiveTilesRect(const gfx::Rect& live_tiles_rect);
+ Tile* CreateTile(int i, int j, const PictureLayerTiling* twin_tiling);
+
+ // Computes a skewport. The calculation extrapolates the last visible
+ // rect and the current visible rect to expand the skewport to where it
+ // would be in |skewport_target_time| seconds. Note that the skewport
+ // is guaranteed to contain the current visible rect.
+ gfx::Rect ComputeSkewport(double current_frame_time_in_seconds,
+ const gfx::Rect& visible_rect_in_content_space)
+ const;
+
+ void UpdateEvictionCacheIfNeeded(TreePriority tree_priority);
+ void DoInvalidate(const Region& layer_region, bool recreate_tiles);
// Given properties.
float contents_scale_;
@@ -211,8 +290,16 @@ class CC_EXPORT PictureLayerTiling {
// State saved for computing velocities based upon finite differences.
double last_impl_frame_time_in_seconds_;
+ gfx::Rect last_visible_rect_in_content_space_;
- friend class CoverageIterator;
+ gfx::Rect current_visible_rect_in_content_space_;
+ gfx::Rect current_skewport_;
+ gfx::Rect current_eventually_rect_;
+ gfx::Rect current_soon_border_rect_;
+
+ std::vector<Tile*> eviction_tiles_cache_;
+ bool eviction_tiles_cache_valid_;
+ TreePriority eviction_cache_tree_priority_;
private:
DISALLOW_ASSIGN(PictureLayerTiling);
diff --git a/chromium/cc/resources/picture_layer_tiling_perftest.cc b/chromium/cc/resources/picture_layer_tiling_perftest.cc
index 7a9b8dff4b4..1e698b9e0ec 100644
--- a/chromium/cc/resources/picture_layer_tiling_perftest.cc
+++ b/chromium/cc/resources/picture_layer_tiling_perftest.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "cc/debug/lap_timer.h"
#include "cc/resources/picture_layer_tiling.h"
#include "cc/test/fake_picture_layer_tiling_client.h"
@@ -18,10 +19,14 @@ static const int kTimeCheckInterval = 10;
class PictureLayerTilingPerfTest : public testing::Test {
public:
- PictureLayerTilingPerfTest() : num_runs_(0) {}
+ PictureLayerTilingPerfTest()
+ : timer_(kWarmupRuns,
+ base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
+ kTimeCheckInterval) {}
virtual void SetUp() OVERRIDE {
picture_layer_tiling_client_.SetTileSize(gfx::Size(256, 256));
+ picture_layer_tiling_client_.set_max_tiles_for_interest_area(250);
picture_layer_tiling_ = PictureLayerTiling::Create(
1, gfx::Size(256 * 50, 256 * 50), &picture_layer_tiling_client_);
picture_layer_tiling_->CreateAllTilesForTesting();
@@ -31,70 +36,38 @@ class PictureLayerTilingPerfTest : public testing::Test {
picture_layer_tiling_.reset(NULL);
}
- void EndTest() {
- elapsed_ = base::TimeTicks::HighResNow() - start_time_;
- }
-
- bool DidRun() {
- ++num_runs_;
- if (num_runs_ == kWarmupRuns)
- start_time_ = base::TimeTicks::HighResNow();
-
- if (!start_time_.is_null() && (num_runs_ % kTimeCheckInterval) == 0) {
- base::TimeDelta elapsed = base::TimeTicks::HighResNow() - start_time_;
- if (elapsed >= base::TimeDelta::FromMilliseconds(kTimeLimitMillis)) {
- elapsed_ = elapsed;
- return false;
- }
- }
- return true;
- }
-
void RunInvalidateTest(const std::string& test_name, const Region& region) {
- start_time_ = base::TimeTicks();
- num_runs_ = 0;
+ timer_.Reset();
do {
picture_layer_tiling_->Invalidate(region);
- } while (DidRun());
+ timer_.NextLap();
+ } while (!timer_.HasTimeLimitExpired());
- perf_test::PrintResult("invalidation", "", test_name,
- num_runs_ / elapsed_.InSecondsF(), "runs/s", true);
+ perf_test::PrintResult(
+ "invalidation", "", test_name, timer_.LapsPerSecond(), "runs/s", true);
}
- void RunUpdateTilePrioritiesStationaryTest(
- const std::string& test_name,
- const gfx::Transform& transform) {
- start_time_ = base::TimeTicks();
- num_runs_ = 0;
+ void RunUpdateTilePrioritiesStationaryTest(const std::string& test_name,
+ const gfx::Transform& transform) {
+ gfx::Rect viewport_rect(0, 0, 1024, 768);
- gfx::Size layer_bounds(50 * 256, 50 * 256);
+ timer_.Reset();
do {
picture_layer_tiling_->UpdateTilePriorities(
- ACTIVE_TREE,
- layer_bounds,
- gfx::Rect(layer_bounds),
- gfx::Rect(layer_bounds),
- layer_bounds,
- layer_bounds,
- 1.f,
- 1.f,
- transform,
- transform,
- num_runs_ + 1,
- 250);
- } while (DidRun());
-
- perf_test::PrintResult("update_tile_priorities_stationary", "", test_name,
- num_runs_ / elapsed_.InSecondsF(), "runs/s", true);
+ ACTIVE_TREE, viewport_rect, 1.f, timer_.NumLaps() + 1);
+ timer_.NextLap();
+ } while (!timer_.HasTimeLimitExpired());
+
+ perf_test::PrintResult("update_tile_priorities_stationary",
+ "",
+ test_name,
+ timer_.LapsPerSecond(),
+ "runs/s",
+ true);
}
- void RunUpdateTilePrioritiesScrollingTest(
- const std::string& test_name,
- const gfx::Transform& transform) {
- start_time_ = base::TimeTicks();
- num_runs_ = 0;
-
- gfx::Size layer_bounds(50 * 256, 50 * 256);
+ void RunUpdateTilePrioritiesScrollingTest(const std::string& test_name,
+ const gfx::Transform& transform) {
gfx::Size viewport_size(1024, 768);
gfx::Rect viewport_rect(viewport_size);
int xoffsets[] = {10, 0, -10, 0};
@@ -102,44 +75,66 @@ class PictureLayerTilingPerfTest : public testing::Test {
int offsetIndex = 0;
int offsetCount = 0;
const int maxOffsetCount = 1000;
+
+ timer_.Reset();
do {
picture_layer_tiling_->UpdateTilePriorities(
- ACTIVE_TREE,
- viewport_size,
- viewport_rect,
- gfx::Rect(layer_bounds),
- layer_bounds,
- layer_bounds,
- 1.f,
- 1.f,
- transform,
- transform,
- num_runs_ + 1,
- 250);
-
- viewport_rect = gfx::Rect(
- viewport_rect.x() + xoffsets[offsetIndex],
- viewport_rect.y() + yoffsets[offsetIndex],
- viewport_rect.width(),
- viewport_rect.height());
+ ACTIVE_TREE, viewport_rect, 1.f, timer_.NumLaps() + 1);
+
+ viewport_rect = gfx::Rect(viewport_rect.x() + xoffsets[offsetIndex],
+ viewport_rect.y() + yoffsets[offsetIndex],
+ viewport_rect.width(),
+ viewport_rect.height());
if (++offsetCount > maxOffsetCount) {
offsetCount = 0;
offsetIndex = (offsetIndex + 1) % 4;
}
- } while (DidRun());
+ timer_.NextLap();
+ } while (!timer_.HasTimeLimitExpired());
+
+ perf_test::PrintResult("update_tile_priorities_scrolling",
+ "",
+ test_name,
+ timer_.LapsPerSecond(),
+ "runs/s",
+ true);
+ }
- perf_test::PrintResult("update_tile_priorities_scrolling", "", test_name,
- num_runs_ / elapsed_.InSecondsF(), "runs/s", true);
+ void RunTilingRasterTileIteratorTest(const std::string& test_name,
+ int num_tiles,
+ const gfx::Rect& viewport) {
+ gfx::Size bounds(10000, 10000);
+ picture_layer_tiling_ =
+ PictureLayerTiling::Create(1, bounds, &picture_layer_tiling_client_);
+ picture_layer_tiling_->UpdateTilePriorities(
+ ACTIVE_TREE, viewport, 1.0f, 1.0);
+
+ timer_.Reset();
+ do {
+ int count = num_tiles;
+ for (PictureLayerTiling::TilingRasterTileIterator it(
+ picture_layer_tiling_.get(), ACTIVE_TREE);
+ it && count;
+ ++it) {
+ --count;
+ }
+ timer_.NextLap();
+ } while (!timer_.HasTimeLimitExpired());
+
+ perf_test::PrintResult("tiling_raster_tile_iterator",
+ "",
+ test_name,
+ timer_.LapsPerSecond(),
+ "runs/s",
+ true);
}
private:
FakePictureLayerTilingClient picture_layer_tiling_client_;
scoped_ptr<PictureLayerTiling> picture_layer_tiling_;
- base::TimeTicks start_time_;
- base::TimeDelta elapsed_;
- int num_runs_;
+ LapTimer timer_;
};
TEST_F(PictureLayerTilingPerfTest, Invalidate) {
@@ -160,6 +155,7 @@ TEST_F(PictureLayerTilingPerfTest, DISABLED_UpdateTilePriorities) {
TEST_F(PictureLayerTilingPerfTest, UpdateTilePriorities) {
#endif // defined(OS_ANDROID)
gfx::Transform transform;
+
RunUpdateTilePrioritiesStationaryTest("no_transform", transform);
RunUpdateTilePrioritiesScrollingTest("no_transform", transform);
@@ -172,6 +168,13 @@ TEST_F(PictureLayerTilingPerfTest, UpdateTilePriorities) {
RunUpdateTilePrioritiesScrollingTest("perspective", transform);
}
+TEST_F(PictureLayerTilingPerfTest, TilingRasterTileIterator) {
+ RunTilingRasterTileIteratorTest("32_100x100", 32, gfx::Rect(0, 0, 100, 100));
+ RunTilingRasterTileIteratorTest("32_500x500", 32, gfx::Rect(0, 0, 500, 500));
+ RunTilingRasterTileIteratorTest("64_100x100", 64, gfx::Rect(0, 0, 100, 100));
+ RunTilingRasterTileIteratorTest("64_500x500", 64, gfx::Rect(0, 0, 500, 500));
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/resources/picture_layer_tiling_set.cc b/chromium/cc/resources/picture_layer_tiling_set.cc
index 5ad26506fd7..fe55d76ef13 100644
--- a/chromium/cc/resources/picture_layer_tiling_set.cc
+++ b/chromium/cc/resources/picture_layer_tiling_set.cc
@@ -22,7 +22,7 @@ class LargestToSmallestScaleFunctor {
PictureLayerTilingSet::PictureLayerTilingSet(
PictureLayerTilingClient* client,
- gfx::Size layer_bounds)
+ const gfx::Size& layer_bounds)
: client_(client),
layer_bounds_(layer_bounds) {
}
@@ -36,15 +36,14 @@ void PictureLayerTilingSet::SetClient(PictureLayerTilingClient* client) {
tilings_[i]->SetClient(client_);
}
-void PictureLayerTilingSet::SyncTilings(
- const PictureLayerTilingSet& other,
- gfx::Size new_layer_bounds,
- const Region& layer_invalidation,
- float minimum_contents_scale) {
+bool PictureLayerTilingSet::SyncTilings(const PictureLayerTilingSet& other,
+ const gfx::Size& new_layer_bounds,
+ const Region& layer_invalidation,
+ float minimum_contents_scale) {
if (new_layer_bounds.IsEmpty()) {
RemoveAllTilings();
layer_bounds_ = new_layer_bounds;
- return;
+ return false;
}
tilings_.reserve(other.tilings_.size());
@@ -60,6 +59,8 @@ void PictureLayerTilingSet::SyncTilings(
--i;
}
+ bool have_high_res_tiling = false;
+
// Add any missing tilings from |other| that meet the minimum.
for (size_t i = 0; i < other.tilings_.size(); ++i) {
float contents_scale = other.tilings_[i]->contents_scale();
@@ -75,9 +76,11 @@ void PictureLayerTilingSet::SyncTilings(
this_tiling->UpdateTilesToCurrentPile();
this_tiling->CreateMissingTilesInLiveTilesRect();
+ if (this_tiling->resolution() == HIGH_RESOLUTION)
+ have_high_res_tiling = true;
DCHECK(this_tiling->tile_size() ==
- client_->CalculateTileSize(this_tiling->ContentRect().size()));
+ client_->CalculateTileSize(this_tiling->TilingRect().size()));
continue;
}
scoped_ptr<PictureLayerTiling> new_tiling = PictureLayerTiling::Create(
@@ -85,16 +88,19 @@ void PictureLayerTilingSet::SyncTilings(
new_layer_bounds,
client_);
new_tiling->set_resolution(other.tilings_[i]->resolution());
+ if (new_tiling->resolution() == HIGH_RESOLUTION)
+ have_high_res_tiling = true;
tilings_.push_back(new_tiling.Pass());
}
tilings_.sort(LargestToSmallestScaleFunctor());
layer_bounds_ = new_layer_bounds;
+ return have_high_res_tiling;
}
-void PictureLayerTilingSet::SetCanUseLCDText(bool can_use_lcd_text) {
+void PictureLayerTilingSet::RemoveTilesInRegion(const Region& region) {
for (size_t i = 0; i < tilings_.size(); ++i)
- tilings_[i]->SetCanUseLCDText(can_use_lcd_text);
+ tilings_[i]->RemoveTilesInRegion(region);
}
PictureLayerTiling* PictureLayerTilingSet::AddTiling(float contents_scale) {
@@ -147,7 +153,7 @@ void PictureLayerTilingSet::RemoveAllTiles() {
PictureLayerTilingSet::CoverageIterator::CoverageIterator(
const PictureLayerTilingSet* set,
float contents_scale,
- gfx::Rect content_rect,
+ const gfx::Rect& content_rect,
float ideal_contents_scale)
: set_(set),
contents_scale_(contents_scale),
@@ -301,43 +307,6 @@ PictureLayerTilingSet::CoverageIterator::operator bool() const {
region_iter_.has_rect();
}
-void PictureLayerTilingSet::UpdateTilePriorities(
- WhichTree tree,
- gfx::Size device_viewport,
- gfx::Rect viewport_in_content_space,
- gfx::Rect visible_content_rect,
- gfx::Size last_layer_bounds,
- gfx::Size current_layer_bounds,
- float last_layer_contents_scale,
- float current_layer_contents_scale,
- const gfx::Transform& last_screen_transform,
- const gfx::Transform& current_screen_transform,
- double current_frame_time_in_seconds,
- size_t max_tiles_for_interest_area) {
- gfx::Rect viewport_in_layer_space = gfx::ScaleToEnclosingRect(
- viewport_in_content_space,
- 1.f / current_layer_contents_scale);
- gfx::Rect visible_layer_rect = gfx::ScaleToEnclosingRect(
- visible_content_rect,
- 1.f / current_layer_contents_scale);
-
- for (size_t i = 0; i < tilings_.size(); ++i) {
- tilings_[i]->UpdateTilePriorities(
- tree,
- device_viewport,
- viewport_in_layer_space,
- visible_layer_rect,
- last_layer_bounds,
- current_layer_bounds,
- last_layer_contents_scale,
- current_layer_contents_scale,
- last_screen_transform,
- current_screen_transform,
- current_frame_time_in_seconds,
- max_tiles_for_interest_area);
- }
-}
-
void PictureLayerTilingSet::DidBecomeActive() {
for (size_t i = 0; i < tilings_.size(); ++i)
tilings_[i]->DidBecomeActive();
diff --git a/chromium/cc/resources/picture_layer_tiling_set.h b/chromium/cc/resources/picture_layer_tiling_set.h
index 29e6bf453f5..67b267c2803 100644
--- a/chromium/cc/resources/picture_layer_tiling_set.h
+++ b/chromium/cc/resources/picture_layer_tiling_set.h
@@ -15,7 +15,7 @@ namespace cc {
class CC_EXPORT PictureLayerTilingSet {
public:
PictureLayerTilingSet(PictureLayerTilingClient* client,
- gfx::Size layer_bounds);
+ const gfx::Size& layer_bounds);
~PictureLayerTilingSet();
void SetClient(PictureLayerTilingClient* client);
@@ -25,15 +25,15 @@ class CC_EXPORT PictureLayerTilingSet {
// Delete any tilings that don't meet |minimum_contents_scale|. Recreate
// any tiles that intersect |layer_invalidation|. Update the size of all
// tilings to |new_layer_bounds|.
- void SyncTilings(
- const PictureLayerTilingSet& other,
- gfx::Size new_layer_bounds,
- const Region& layer_invalidation,
- float minimum_contents_scale);
+ // Returns true if we had at least one high res tiling synced.
+ bool SyncTilings(const PictureLayerTilingSet& other,
+ const gfx::Size& new_layer_bounds,
+ const Region& layer_invalidation,
+ float minimum_contents_scale);
- gfx::Size layer_bounds() const { return layer_bounds_; }
+ void RemoveTilesInRegion(const Region& region);
- void SetCanUseLCDText(bool can_use_lcd_text);
+ gfx::Size layer_bounds() const { return layer_bounds_; }
PictureLayerTiling* AddTiling(float contents_scale);
size_t num_tilings() const { return tilings_.size(); }
@@ -54,20 +54,6 @@ class CC_EXPORT PictureLayerTilingSet {
// Remove all tiles; keep all tilings.
void RemoveAllTiles();
- void UpdateTilePriorities(
- WhichTree tree,
- gfx::Size device_viewport,
- gfx::Rect viewport_in_content_space,
- gfx::Rect visible_content_rect,
- gfx::Size last_layer_bounds,
- gfx::Size current_layer_bounds,
- float last_layer_contents_scale,
- float current_layer_contents_scale,
- const gfx::Transform& last_screen_transform,
- const gfx::Transform& current_screen_transform,
- double current_frame_time_in_seconds,
- size_t max_tiles_for_interest_area);
-
void DidBecomeActive();
void DidBecomeRecycled();
@@ -80,7 +66,7 @@ class CC_EXPORT PictureLayerTilingSet {
public:
CoverageIterator(const PictureLayerTilingSet* set,
float contents_scale,
- gfx::Rect content_rect,
+ const gfx::Rect& content_rect,
float ideal_contents_scale);
~CoverageIterator();
diff --git a/chromium/cc/resources/picture_layer_tiling_set_unittest.cc b/chromium/cc/resources/picture_layer_tiling_set_unittest.cc
index 96129c64fe5..259301b8444 100644
--- a/chromium/cc/resources/picture_layer_tiling_set_unittest.cc
+++ b/chromium/cc/resources/picture_layer_tiling_set_unittest.cc
@@ -13,6 +13,7 @@
#include "cc/test/fake_output_surface_client.h"
#include "cc/test/fake_picture_layer_tiling_client.h"
#include "cc/test/fake_tile_manager_client.h"
+#include "cc/test/test_shared_bitmap_manager.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/size_conversions.h"
@@ -65,8 +66,10 @@ class PictureLayerTilingSetTestWithResources : public testing::Test {
FakeOutputSurface::Create3d();
CHECK(output_surface->BindToClient(&output_surface_client));
- scoped_ptr<ResourceProvider> resource_provider =
- ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1);
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
+ scoped_ptr<ResourceProvider> resource_provider = ResourceProvider::Create(
+ output_surface.get(), shared_bitmap_manager.get(), 0, false, 1, false);
FakePictureLayerTilingClient client(resource_provider.get());
client.SetTileSize(gfx::Size(256, 256));
@@ -78,8 +81,7 @@ class PictureLayerTilingSetTestWithResources : public testing::Test {
PictureLayerTiling* tiling = set.AddTiling(scale);
tiling->CreateAllTilesForTesting();
std::vector<Tile*> tiles = tiling->AllTilesForTesting();
- client.tile_manager()->InitializeTilesWithResourcesForTesting(
- tiles, resource_provider.get());
+ client.tile_manager()->InitializeTilesWithResourcesForTesting(tiles);
}
float max_contents_scale = scale;
@@ -157,7 +159,7 @@ class PictureLayerTilingSetSyncTest : public testing::Test {
}
// Sync from source to target.
- void SyncTilings(gfx::Size new_bounds,
+ void SyncTilings(const gfx::Size& new_bounds,
const Region& invalidation,
float minimum_scale) {
for (size_t i = 0; i < source_->num_tilings(); ++i)
@@ -168,19 +170,19 @@ class PictureLayerTilingSetSyncTest : public testing::Test {
target_->SyncTilings(
*source_.get(), new_bounds, invalidation, minimum_scale);
}
- void SyncTilings(gfx::Size new_bounds) {
+ void SyncTilings(const gfx::Size& new_bounds) {
Region invalidation;
SyncTilings(new_bounds, invalidation, 0.f);
}
- void SyncTilings(gfx::Size new_bounds, const Region& invalidation) {
+ void SyncTilings(const gfx::Size& new_bounds, const Region& invalidation) {
SyncTilings(new_bounds, invalidation, 0.f);
}
- void SyncTilings(gfx::Size new_bounds, float minimum_scale) {
+ void SyncTilings(const gfx::Size& new_bounds, float minimum_scale) {
Region invalidation;
SyncTilings(new_bounds, invalidation, minimum_scale);
}
- void VerifyTargetEqualsSource(gfx::Size new_bounds) const {
+ void VerifyTargetEqualsSource(const gfx::Size& new_bounds) const {
ASSERT_FALSE(new_bounds.IsEmpty());
EXPECT_EQ(target_->num_tilings(), source_->num_tilings());
EXPECT_EQ(target_->layer_bounds().ToString(), new_bounds.ToString());
@@ -217,10 +219,10 @@ class PictureLayerTilingSetSyncTest : public testing::Test {
void ValidateTiling(const PictureLayerTiling* tiling,
const PicturePileImpl* pile) const {
- if (tiling->ContentRect().IsEmpty())
+ if (tiling->TilingRect().IsEmpty())
EXPECT_TRUE(tiling->live_tiles_rect().IsEmpty());
else if (!tiling->live_tiles_rect().IsEmpty())
- EXPECT_TRUE(tiling->ContentRect().Contains(tiling->live_tiles_rect()));
+ EXPECT_TRUE(tiling->TilingRect().Contains(tiling->live_tiles_rect()));
std::vector<Tile*> tiles = tiling->AllTilesForTesting();
for (size_t i = 0; i < tiles.size(); ++i) {
diff --git a/chromium/cc/resources/picture_layer_tiling_unittest.cc b/chromium/cc/resources/picture_layer_tiling_unittest.cc
index 6adc6116454..bfdd6fce8a5 100644
--- a/chromium/cc/resources/picture_layer_tiling_unittest.cc
+++ b/chromium/cc/resources/picture_layer_tiling_unittest.cc
@@ -5,10 +5,15 @@
#include "cc/resources/picture_layer_tiling.h"
#include <limits>
+#include <set>
#include "cc/base/math_util.h"
#include "cc/resources/picture_layer_tiling_set.h"
+#include "cc/test/fake_output_surface.h"
+#include "cc/test/fake_output_surface_client.h"
#include "cc/test/fake_picture_layer_tiling_client.h"
+#include "cc/test/test_context_provider.h"
+#include "cc/test/test_shared_bitmap_manager.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/rect_conversions.h"
#include "ui/gfx/size_conversions.h"
@@ -18,7 +23,7 @@ namespace {
static gfx::Rect ViewportInLayerSpace(
const gfx::Transform& transform,
- gfx::Size device_viewport) {
+ const gfx::Size& device_viewport) {
gfx::Transform inverse;
if (!transform.GetInverse(&inverse))
@@ -26,10 +31,22 @@ static gfx::Rect ViewportInLayerSpace(
gfx::RectF viewport_in_layer_space = MathUtil::ProjectClippedRect(
inverse, gfx::RectF(gfx::Point(0, 0), device_viewport));
-
return ToEnclosingRect(viewport_in_layer_space);
}
+static void UpdateAllTilePriorities(PictureLayerTilingSet* set,
+ WhichTree tree,
+ const gfx::Rect& visible_layer_rect,
+ float layer_contents_scale,
+ double current_frame_time_in_seconds) {
+ for (size_t i = 0; i < set->num_tilings(); ++i) {
+ set->tiling_at(i)->UpdateTilePriorities(tree,
+ visible_layer_rect,
+ layer_contents_scale,
+ current_frame_time_in_seconds);
+ }
+}
+
class TestablePictureLayerTiling : public PictureLayerTiling {
public:
using PictureLayerTiling::SetLiveTilesRect;
@@ -37,7 +54,7 @@ class TestablePictureLayerTiling : public PictureLayerTiling {
static scoped_ptr<TestablePictureLayerTiling> Create(
float contents_scale,
- gfx::Size layer_bounds,
+ const gfx::Size& layer_bounds,
PictureLayerTilingClient* client) {
return make_scoped_ptr(new TestablePictureLayerTiling(
contents_scale,
@@ -45,9 +62,11 @@ class TestablePictureLayerTiling : public PictureLayerTiling {
client));
}
+ using PictureLayerTiling::ComputeSkewport;
+
protected:
TestablePictureLayerTiling(float contents_scale,
- gfx::Size layer_bounds,
+ const gfx::Size& layer_bounds,
PictureLayerTilingClient* client)
: PictureLayerTiling(contents_scale, layer_bounds, client) { }
};
@@ -57,16 +76,16 @@ class PictureLayerTilingIteratorTest : public testing::Test {
PictureLayerTilingIteratorTest() {}
virtual ~PictureLayerTilingIteratorTest() {}
- void Initialize(gfx::Size tile_size,
+ void Initialize(const gfx::Size& tile_size,
float contents_scale,
- gfx::Size layer_bounds) {
+ const gfx::Size& layer_bounds) {
client_.SetTileSize(tile_size);
tiling_ = TestablePictureLayerTiling::Create(contents_scale,
layer_bounds,
&client_);
}
- void SetLiveRectAndVerifyTiles(gfx::Rect live_tiles_rect) {
+ void SetLiveRectAndVerifyTiles(const gfx::Rect& live_tiles_rect) {
tiling_->SetLiveTilesRect(live_tiles_rect);
std::vector<Tile*> tiles = tiling_->AllTilesForTesting();
@@ -79,8 +98,8 @@ class PictureLayerTilingIteratorTest : public testing::Test {
void VerifyTilesExactlyCoverRect(
float rect_scale,
- gfx::Rect request_rect,
- gfx::Rect expect_rect) {
+ const gfx::Rect& request_rect,
+ const gfx::Rect& expect_rect) {
EXPECT_TRUE(request_rect.Contains(expect_rect));
// Iterators are not valid if this ratio is too large (i.e. the
@@ -115,14 +134,15 @@ class PictureLayerTilingIteratorTest : public testing::Test {
EXPECT_TRUE(remaining.IsEmpty());
}
- void VerifyTilesExactlyCoverRect(float rect_scale, gfx::Rect rect) {
+ void VerifyTilesExactlyCoverRect(float rect_scale, const gfx::Rect& rect) {
VerifyTilesExactlyCoverRect(rect_scale, rect, rect);
}
void VerifyTiles(
float rect_scale,
- gfx::Rect rect,
- base::Callback<void(Tile* tile, gfx::Rect geometry_rect)> callback) {
+ const gfx::Rect& rect,
+ base::Callback<void(Tile* tile,
+ const gfx::Rect& geometry_rect)> callback) {
VerifyTiles(tiling_.get(),
rect_scale,
rect,
@@ -132,8 +152,9 @@ class PictureLayerTilingIteratorTest : public testing::Test {
void VerifyTiles(
PictureLayerTiling* tiling,
float rect_scale,
- gfx::Rect rect,
- base::Callback<void(Tile* tile, gfx::Rect geometry_rect)> callback) {
+ const gfx::Rect& rect,
+ base::Callback<void(Tile* tile,
+ const gfx::Rect& geometry_rect)> callback) {
Region remaining = rect;
for (PictureLayerTiling::CoverageIterator iter(tiling, rect_scale, rect);
iter;
@@ -144,14 +165,19 @@ class PictureLayerTilingIteratorTest : public testing::Test {
EXPECT_TRUE(remaining.IsEmpty());
}
- void VerifyTilesCoverNonContainedRect(float rect_scale, gfx::Rect dest_rect) {
+ void VerifyTilesCoverNonContainedRect(float rect_scale,
+ const gfx::Rect& dest_rect) {
float dest_to_contents_scale = tiling_->contents_scale() / rect_scale;
gfx::Rect clamped_rect = gfx::ScaleToEnclosingRect(
- tiling_->ContentRect(), 1.f / dest_to_contents_scale);
+ tiling_->TilingRect(), 1.f / dest_to_contents_scale);
clamped_rect.Intersect(dest_rect);
VerifyTilesExactlyCoverRect(rect_scale, dest_rect, clamped_rect);
}
+ void set_max_tiles_for_interest_area(size_t area) {
+ client_.set_max_tiles_for_interest_area(area);
+ }
+
protected:
FakePictureLayerTilingClient client_;
scoped_ptr<TestablePictureLayerTiling> tiling_;
@@ -160,6 +186,23 @@ class PictureLayerTilingIteratorTest : public testing::Test {
DISALLOW_COPY_AND_ASSIGN(PictureLayerTilingIteratorTest);
};
+TEST_F(PictureLayerTilingIteratorTest, ResizeDeletesTiles) {
+ // Verifies that a resize deletes tiles that used to be on the edge.
+ gfx::Size tile_size(100, 100);
+ gfx::Size original_layer_size(10, 10);
+ Initialize(tile_size, 1.f, original_layer_size);
+ SetLiveRectAndVerifyTiles(gfx::Rect(original_layer_size));
+
+ // Tiling only has one tile, since its total size is less than one.
+ EXPECT_TRUE(tiling_->TileAt(0, 0));
+
+ // Stop creating tiles so that any invalidations are left as holes.
+ client_.set_allow_create_tile(false);
+
+ tiling_->SetLayerBounds(gfx::Size(200, 200));
+ EXPECT_FALSE(tiling_->TileAt(0, 0));
+}
+
TEST_F(PictureLayerTilingIteratorTest, LiveTilesExactlyCoverLiveTileRect) {
Initialize(gfx::Size(100, 100), 1, gfx::Size(1099, 801));
SetLiveRectAndVerifyTiles(gfx::Rect(100, 100));
@@ -261,6 +304,293 @@ TEST_F(PictureLayerTilingIteratorTest, NonContainedDestRect) {
VerifyTilesCoverNonContainedRect(0.5f, gfx::Rect(-1000, 100, 2000, 100));
}
+TEST(PictureLayerTilingTest, SkewportLimits) {
+ FakePictureLayerTilingClient client;
+ client.set_skewport_extrapolation_limit_in_content_pixels(75);
+ scoped_ptr<TestablePictureLayerTiling> tiling;
+
+ gfx::Rect viewport(0, 0, 100, 100);
+ gfx::Size layer_bounds(200, 200);
+
+ client.SetTileSize(gfx::Size(100, 100));
+ tiling = TestablePictureLayerTiling::Create(1.0f, layer_bounds, &client);
+
+ tiling->UpdateTilePriorities(ACTIVE_TREE, viewport, 1.f, 1.0);
+
+ // Move viewport down 50 pixels in 0.5 seconds.
+ gfx::Rect down_skewport =
+ tiling->ComputeSkewport(1.5, gfx::Rect(0, 50, 100, 100));
+
+ EXPECT_EQ(0, down_skewport.x());
+ EXPECT_EQ(50, down_skewport.y());
+ EXPECT_EQ(100, down_skewport.width());
+ EXPECT_EQ(175, down_skewport.height());
+ EXPECT_TRUE(down_skewport.Contains(gfx::Rect(0, 50, 100, 100)));
+
+ // Move viewport down 50 and right 10 pixels.
+ gfx::Rect down_right_skewport =
+ tiling->ComputeSkewport(1.5, gfx::Rect(10, 50, 100, 100));
+
+ EXPECT_EQ(10, down_right_skewport.x());
+ EXPECT_EQ(50, down_right_skewport.y());
+ EXPECT_EQ(120, down_right_skewport.width());
+ EXPECT_EQ(175, down_right_skewport.height());
+ EXPECT_TRUE(down_right_skewport.Contains(gfx::Rect(10, 50, 100, 100)));
+
+ // Move viewport left.
+ gfx::Rect left_skewport =
+ tiling->ComputeSkewport(1.5, gfx::Rect(-50, 0, 100, 100));
+
+ EXPECT_EQ(-125, left_skewport.x());
+ EXPECT_EQ(0, left_skewport.y());
+ EXPECT_EQ(175, left_skewport.width());
+ EXPECT_EQ(100, left_skewport.height());
+ EXPECT_TRUE(left_skewport.Contains(gfx::Rect(-50, 0, 100, 100)));
+
+ // Expand viewport.
+ gfx::Rect expand_skewport =
+ tiling->ComputeSkewport(1.5, gfx::Rect(-50, -50, 200, 200));
+
+ // x and y moved by -75 (-50 - 75 = -125).
+ // right side and bottom side moved by 75 [(350 - 125) - (200 - 50) = 75].
+ EXPECT_EQ(-125, expand_skewport.x());
+ EXPECT_EQ(-125, expand_skewport.y());
+ EXPECT_EQ(350, expand_skewport.width());
+ EXPECT_EQ(350, expand_skewport.height());
+ EXPECT_TRUE(expand_skewport.Contains(gfx::Rect(-50, -50, 200, 200)));
+
+ // Expand the viewport past the limit.
+ gfx::Rect big_expand_skewport =
+ tiling->ComputeSkewport(1.5, gfx::Rect(-500, -500, 1500, 1500));
+
+ EXPECT_EQ(-575, big_expand_skewport.x());
+ EXPECT_EQ(-575, big_expand_skewport.y());
+ EXPECT_EQ(1650, big_expand_skewport.width());
+ EXPECT_EQ(1650, big_expand_skewport.height());
+ EXPECT_TRUE(big_expand_skewport.Contains(gfx::Rect(-500, -500, 1500, 1500)));
+}
+
+TEST(PictureLayerTilingTest, ComputeSkewport) {
+ FakePictureLayerTilingClient client;
+ scoped_ptr<TestablePictureLayerTiling> tiling;
+
+ gfx::Rect viewport(0, 0, 100, 100);
+ gfx::Size layer_bounds(200, 200);
+
+ client.SetTileSize(gfx::Size(100, 100));
+ tiling = TestablePictureLayerTiling::Create(1.0f, layer_bounds, &client);
+
+ tiling->UpdateTilePriorities(ACTIVE_TREE, viewport, 1.f, 1.0);
+
+ // Move viewport down 50 pixels in 0.5 seconds.
+ gfx::Rect down_skewport =
+ tiling->ComputeSkewport(1.5, gfx::Rect(0, 50, 100, 100));
+
+ EXPECT_EQ(0, down_skewport.x());
+ EXPECT_EQ(50, down_skewport.y());
+ EXPECT_EQ(100, down_skewport.width());
+ EXPECT_EQ(200, down_skewport.height());
+
+ // Shrink viewport.
+ gfx::Rect shrink_skewport =
+ tiling->ComputeSkewport(1.5, gfx::Rect(25, 25, 50, 50));
+
+ EXPECT_EQ(25, shrink_skewport.x());
+ EXPECT_EQ(25, shrink_skewport.y());
+ EXPECT_EQ(50, shrink_skewport.width());
+ EXPECT_EQ(50, shrink_skewport.height());
+
+ // Move viewport down 50 and right 10 pixels.
+ gfx::Rect down_right_skewport =
+ tiling->ComputeSkewport(1.5, gfx::Rect(10, 50, 100, 100));
+
+ EXPECT_EQ(10, down_right_skewport.x());
+ EXPECT_EQ(50, down_right_skewport.y());
+ EXPECT_EQ(120, down_right_skewport.width());
+ EXPECT_EQ(200, down_right_skewport.height());
+
+ // Move viewport left.
+ gfx::Rect left_skewport =
+ tiling->ComputeSkewport(1.5, gfx::Rect(-20, 0, 100, 100));
+
+ EXPECT_EQ(-60, left_skewport.x());
+ EXPECT_EQ(0, left_skewport.y());
+ EXPECT_EQ(140, left_skewport.width());
+ EXPECT_EQ(100, left_skewport.height());
+
+ // Expand viewport in 0.2 seconds.
+ gfx::Rect expanded_skewport =
+ tiling->ComputeSkewport(1.2, gfx::Rect(-5, -5, 110, 110));
+
+ EXPECT_EQ(-30, expanded_skewport.x());
+ EXPECT_EQ(-30, expanded_skewport.y());
+ EXPECT_EQ(160, expanded_skewport.width());
+ EXPECT_EQ(160, expanded_skewport.height());
+}
+
+TEST(PictureLayerTilingTest, ViewportDistanceWithScale) {
+ FakePictureLayerTilingClient client;
+ scoped_ptr<TestablePictureLayerTiling> tiling;
+
+ gfx::Rect viewport(0, 0, 100, 100);
+ gfx::Size layer_bounds(1500, 1500);
+
+ client.SetTileSize(gfx::Size(10, 10));
+
+ // Tiling at 0.25 scale: this should create 47x47 tiles of size 10x10.
+ // The reason is that each tile has a one pixel border, so tile at (1, 2)
+ // for instance begins at (8, 16) pixels. So tile at (46, 46) will begin at
+ // (368, 368) and extend to the end of 1500 * 0.25 = 375 edge of the
+ // tiling.
+ tiling = TestablePictureLayerTiling::Create(0.25f, layer_bounds, &client);
+ gfx::Rect viewport_in_content_space =
+ gfx::ToEnclosedRect(gfx::ScaleRect(viewport, 0.25f));
+
+ tiling->UpdateTilePriorities(ACTIVE_TREE, viewport, 1.f, 1.0);
+
+ gfx::Rect soon_rect = viewport;
+ soon_rect.Inset(-312.f, -312.f, -312.f, -312.f);
+ gfx::Rect soon_rect_in_content_space =
+ gfx::ToEnclosedRect(gfx::ScaleRect(soon_rect, 0.25f));
+
+ // Sanity checks.
+ for (int i = 0; i < 47; ++i) {
+ for (int j = 0; j < 47; ++j) {
+ EXPECT_TRUE(tiling->TileAt(i, j)) << "i: " << i << " j: " << j;
+ }
+ }
+ for (int i = 0; i < 47; ++i) {
+ EXPECT_FALSE(tiling->TileAt(i, 47)) << "i: " << i;
+ EXPECT_FALSE(tiling->TileAt(47, i)) << "i: " << i;
+ }
+
+ // No movement in the viewport implies that tiles will either be NOW
+ // or EVENTUALLY, with the exception of tiles that are between 0 and 312
+ // pixels away from the viewport, which will be in the SOON bin.
+ bool have_now = false;
+ bool have_eventually = false;
+ bool have_soon = false;
+ for (int i = 0; i < 47; ++i) {
+ for (int j = 0; j < 47; ++j) {
+ Tile* tile = tiling->TileAt(i, j);
+ TilePriority priority = tile->priority(ACTIVE_TREE);
+
+ if (viewport_in_content_space.Intersects(tile->content_rect())) {
+ EXPECT_EQ(TilePriority::NOW, priority.priority_bin);
+ EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible);
+ have_now = true;
+ } else if (soon_rect_in_content_space.Intersects(tile->content_rect())) {
+ EXPECT_EQ(TilePriority::SOON, priority.priority_bin);
+ have_soon = true;
+ } else {
+ EXPECT_EQ(TilePriority::EVENTUALLY, priority.priority_bin);
+ EXPECT_GT(priority.distance_to_visible, 0.f);
+ have_eventually = true;
+ }
+ }
+ }
+
+ EXPECT_TRUE(have_now);
+ EXPECT_TRUE(have_soon);
+ EXPECT_TRUE(have_eventually);
+
+ // Spot check some distances.
+ // Tile at 5, 1 should begin at 41x9 in content space (without borders),
+ // so the distance to a viewport that ends at 25x25 in content space
+ // should be 17 (41 - 25 + 1). In layer space, then that should be
+ // 17 / 0.25 = 68 pixels.
+
+ // We can verify that the content rect (with borders) is one pixel off
+ // 41,9 8x8 on all sides.
+ EXPECT_EQ(tiling->TileAt(5, 1)->content_rect().ToString(), "40,8 10x10");
+
+ TilePriority priority = tiling->TileAt(5, 1)->priority(ACTIVE_TREE);
+ EXPECT_FLOAT_EQ(68.f, priority.distance_to_visible);
+
+ priority = tiling->TileAt(2, 5)->priority(ACTIVE_TREE);
+ EXPECT_FLOAT_EQ(68.f, priority.distance_to_visible);
+
+ priority = tiling->TileAt(3, 4)->priority(ACTIVE_TREE);
+ EXPECT_FLOAT_EQ(40.f, priority.distance_to_visible);
+
+ // Move the viewport down 40 pixels.
+ viewport = gfx::Rect(0, 40, 100, 100);
+ viewport_in_content_space =
+ gfx::ToEnclosedRect(gfx::ScaleRect(viewport, 0.25f));
+ gfx::Rect skewport = tiling->ComputeSkewport(2.0, viewport_in_content_space);
+
+ soon_rect = viewport;
+ soon_rect.Inset(-312.f, -312.f, -312.f, -312.f);
+ soon_rect_in_content_space =
+ gfx::ToEnclosedRect(gfx::ScaleRect(soon_rect, 0.25f));
+
+ EXPECT_EQ(0, skewport.x());
+ EXPECT_EQ(10, skewport.y());
+ EXPECT_EQ(25, skewport.width());
+ EXPECT_EQ(35, skewport.height());
+
+ tiling->UpdateTilePriorities(ACTIVE_TREE, viewport, 1.f, 2.0);
+
+ have_now = false;
+ have_eventually = false;
+ have_soon = false;
+
+ // Viewport moved, so we expect to find some NOW tiles, some SOON tiles and
+ // some EVENTUALLY tiles.
+ for (int i = 0; i < 47; ++i) {
+ for (int j = 0; j < 47; ++j) {
+ Tile* tile = tiling->TileAt(i, j);
+ TilePriority priority = tile->priority(ACTIVE_TREE);
+
+ if (viewport_in_content_space.Intersects(tile->content_rect())) {
+ EXPECT_EQ(TilePriority::NOW, priority.priority_bin) << "i: " << i
+ << " j: " << j;
+ EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible) << "i: " << i
+ << " j: " << j;
+ have_now = true;
+ } else if (skewport.Intersects(tile->content_rect()) ||
+ soon_rect_in_content_space.Intersects(tile->content_rect())) {
+ EXPECT_EQ(TilePriority::SOON, priority.priority_bin) << "i: " << i
+ << " j: " << j;
+ EXPECT_GT(priority.distance_to_visible, 0.f) << "i: " << i
+ << " j: " << j;
+ have_soon = true;
+ } else {
+ EXPECT_EQ(TilePriority::EVENTUALLY, priority.priority_bin)
+ << "i: " << i << " j: " << j;
+ EXPECT_GT(priority.distance_to_visible, 0.f) << "i: " << i
+ << " j: " << j;
+ have_eventually = true;
+ }
+ }
+ }
+
+ EXPECT_TRUE(have_now);
+ EXPECT_TRUE(have_soon);
+ EXPECT_TRUE(have_eventually);
+
+ priority = tiling->TileAt(5, 1)->priority(ACTIVE_TREE);
+ EXPECT_FLOAT_EQ(68.f, priority.distance_to_visible);
+
+ priority = tiling->TileAt(2, 5)->priority(ACTIVE_TREE);
+ EXPECT_FLOAT_EQ(28.f, priority.distance_to_visible);
+
+ priority = tiling->TileAt(3, 4)->priority(ACTIVE_TREE);
+ EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible);
+
+ // Change the underlying layer scale.
+ tiling->UpdateTilePriorities(ACTIVE_TREE, viewport, 2.0f, 3.0);
+
+ priority = tiling->TileAt(5, 1)->priority(ACTIVE_TREE);
+ EXPECT_FLOAT_EQ(34.f, priority.distance_to_visible);
+
+ priority = tiling->TileAt(2, 5)->priority(ACTIVE_TREE);
+ EXPECT_FLOAT_EQ(14.f, priority.distance_to_visible);
+
+ priority = tiling->TileAt(3, 4)->priority(ACTIVE_TREE);
+ EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible);
+}
+
TEST(PictureLayerTilingTest, ExpandRectEqual) {
gfx::Rect in(40, 50, 100, 200);
gfx::Rect bounds(-1000, -1000, 10000, 10000);
@@ -479,10 +809,243 @@ TEST(PictureLayerTilingTest, EmptyStartingRect) {
EXPECT_TRUE(out.IsEmpty());
}
-static void TileExists(bool exists, Tile* tile, gfx::Rect geometry_rect) {
+TEST(PictureLayerTilingTest, TilingRasterTileIteratorStaticViewport) {
+ FakePictureLayerTilingClient client;
+ scoped_ptr<TestablePictureLayerTiling> tiling;
+
+ gfx::Rect viewport(50, 50, 100, 100);
+ gfx::Size layer_bounds(800, 800);
+
+ gfx::Rect soon_rect = viewport;
+ soon_rect.Inset(-312.f, -312.f, -312.f, -312.f);
+
+ client.SetTileSize(gfx::Size(30, 30));
+
+ tiling = TestablePictureLayerTiling::Create(1.0f, layer_bounds, &client);
+ tiling->UpdateTilePriorities(ACTIVE_TREE, viewport, 1.0f, 1.0);
+
+ PictureLayerTiling::TilingRasterTileIterator empty_iterator;
+ EXPECT_FALSE(empty_iterator);
+
+ std::vector<Tile*> all_tiles = tiling->AllTilesForTesting();
+
+ // Sanity check.
+ EXPECT_EQ(841u, all_tiles.size());
+
+ // The explanation of each iteration is as follows:
+ // 1. First iteration tests that we can get all of the tiles correctly.
+ // 2. Second iteration ensures that we can get all of the tiles again (first
+ // iteration didn't change any tiles), as well set all tiles to be ready to
+ // draw.
+ // 3. Third iteration ensures that no tiles are returned, since they were all
+ // marked as ready to draw.
+ for (int i = 0; i < 3; ++i) {
+ PictureLayerTiling::TilingRasterTileIterator it(tiling.get(), ACTIVE_TREE);
+
+ // There are 3 bins in TilePriority.
+ bool have_tiles[3] = {};
+
+ // On the third iteration, we should get no tiles since everything was
+ // marked as ready to draw.
+ if (i == 2) {
+ EXPECT_FALSE(it);
+ continue;
+ }
+
+ EXPECT_TRUE(it);
+ std::set<Tile*> unique_tiles;
+ unique_tiles.insert(*it);
+ Tile* last_tile = *it;
+ have_tiles[last_tile->priority(ACTIVE_TREE).priority_bin] = true;
+
+ // On the second iteration, mark everything as ready to draw (solid color).
+ if (i == 1) {
+ ManagedTileState::TileVersion& tile_version =
+ last_tile->GetTileVersionForTesting(
+ last_tile->DetermineRasterModeForTree(ACTIVE_TREE));
+ tile_version.SetSolidColorForTesting(SK_ColorRED);
+ }
+ ++it;
+ int eventually_bin_order_correct_count = 0;
+ int eventually_bin_order_incorrect_count = 0;
+ while (it) {
+ Tile* new_tile = *it;
+ ++it;
+ unique_tiles.insert(new_tile);
+
+ TilePriority last_priority = last_tile->priority(ACTIVE_TREE);
+ TilePriority new_priority = new_tile->priority(ACTIVE_TREE);
+ EXPECT_LE(last_priority.priority_bin, new_priority.priority_bin);
+ if (last_priority.priority_bin == new_priority.priority_bin) {
+ if (last_priority.priority_bin == TilePriority::EVENTUALLY) {
+ bool order_correct = last_priority.distance_to_visible <=
+ new_priority.distance_to_visible;
+ eventually_bin_order_correct_count += order_correct;
+ eventually_bin_order_incorrect_count += !order_correct;
+ } else if (!soon_rect.Intersects(new_tile->content_rect()) &&
+ !soon_rect.Intersects(last_tile->content_rect())) {
+ EXPECT_LE(last_priority.distance_to_visible,
+ new_priority.distance_to_visible);
+ EXPECT_EQ(TilePriority::NOW, new_priority.priority_bin);
+ } else if (new_priority.distance_to_visible > 0.f) {
+ EXPECT_EQ(TilePriority::SOON, new_priority.priority_bin);
+ }
+ }
+ have_tiles[new_priority.priority_bin] = true;
+
+ last_tile = new_tile;
+
+ // On the second iteration, mark everything as ready to draw (solid
+ // color).
+ if (i == 1) {
+ ManagedTileState::TileVersion& tile_version =
+ last_tile->GetTileVersionForTesting(
+ last_tile->DetermineRasterModeForTree(ACTIVE_TREE));
+ tile_version.SetSolidColorForTesting(SK_ColorRED);
+ }
+ }
+
+ EXPECT_GT(eventually_bin_order_correct_count,
+ eventually_bin_order_incorrect_count);
+
+ // We should have now and eventually tiles, as well as soon tiles from
+ // the border region.
+ EXPECT_TRUE(have_tiles[TilePriority::NOW]);
+ EXPECT_TRUE(have_tiles[TilePriority::SOON]);
+ EXPECT_TRUE(have_tiles[TilePriority::EVENTUALLY]);
+
+ EXPECT_EQ(unique_tiles.size(), all_tiles.size());
+ }
+}
+
+TEST(PictureLayerTilingTest, TilingRasterTileIteratorMovingViewport) {
+ FakePictureLayerTilingClient client;
+ scoped_ptr<TestablePictureLayerTiling> tiling;
+
+ gfx::Rect viewport(50, 0, 100, 100);
+ gfx::Rect moved_viewport(50, 0, 100, 500);
+ gfx::Size layer_bounds(1000, 1000);
+
+ client.SetTileSize(gfx::Size(30, 30));
+
+ tiling = TestablePictureLayerTiling::Create(1.f, layer_bounds, &client);
+ tiling->UpdateTilePriorities(ACTIVE_TREE, viewport, 1.0f, 1.0);
+ tiling->UpdateTilePriorities(ACTIVE_TREE, moved_viewport, 1.0f, 2.0);
+
+ gfx::Rect soon_rect = moved_viewport;
+ soon_rect.Inset(-312.f, -312.f, -312.f, -312.f);
+
+ // There are 3 bins in TilePriority.
+ bool have_tiles[3] = {};
+ Tile* last_tile = NULL;
+ int eventually_bin_order_correct_count = 0;
+ int eventually_bin_order_incorrect_count = 0;
+ for (PictureLayerTiling::TilingRasterTileIterator it(tiling.get(),
+ ACTIVE_TREE);
+ it;
+ ++it) {
+ if (!last_tile)
+ last_tile = *it;
+
+ Tile* new_tile = *it;
+
+ TilePriority last_priority = last_tile->priority(ACTIVE_TREE);
+ TilePriority new_priority = new_tile->priority(ACTIVE_TREE);
+
+ have_tiles[new_priority.priority_bin] = true;
+
+ EXPECT_LE(last_priority.priority_bin, new_priority.priority_bin);
+ if (last_priority.priority_bin == new_priority.priority_bin) {
+ if (last_priority.priority_bin == TilePriority::EVENTUALLY) {
+ bool order_correct = last_priority.distance_to_visible <=
+ new_priority.distance_to_visible;
+ eventually_bin_order_correct_count += order_correct;
+ eventually_bin_order_incorrect_count += !order_correct;
+ } else if (!soon_rect.Intersects(new_tile->content_rect()) &&
+ !soon_rect.Intersects(last_tile->content_rect())) {
+ EXPECT_LE(last_priority.distance_to_visible,
+ new_priority.distance_to_visible);
+ } else if (new_priority.distance_to_visible > 0.f) {
+ EXPECT_EQ(TilePriority::SOON, new_priority.priority_bin);
+ }
+ }
+ last_tile = new_tile;
+ }
+
+ EXPECT_GT(eventually_bin_order_correct_count,
+ eventually_bin_order_incorrect_count);
+
+ EXPECT_TRUE(have_tiles[TilePriority::NOW]);
+ EXPECT_TRUE(have_tiles[TilePriority::SOON]);
+ EXPECT_TRUE(have_tiles[TilePriority::EVENTUALLY]);
+}
+
+static void TileExists(bool exists, Tile* tile,
+ const gfx::Rect& geometry_rect) {
EXPECT_EQ(exists, tile != NULL) << geometry_rect.ToString();
}
+TEST(PictureLayerTilingTest, TilingEvictionTileIteratorStaticViewport) {
+ FakeOutputSurfaceClient output_surface_client;
+ scoped_ptr<FakeOutputSurface> output_surface = FakeOutputSurface::Create3d();
+ CHECK(output_surface->BindToClient(&output_surface_client));
+ TestSharedBitmapManager shared_bitmap_manager;
+ scoped_ptr<ResourceProvider> resource_provider = ResourceProvider::Create(
+ output_surface.get(), &shared_bitmap_manager, 0, false, 1, false);
+
+ FakePictureLayerTilingClient client(resource_provider.get());
+ scoped_ptr<TestablePictureLayerTiling> tiling;
+
+ gfx::Rect viewport(50, 50, 100, 100);
+ gfx::Size layer_bounds(200, 200);
+
+ client.SetTileSize(gfx::Size(30, 30));
+
+ tiling = TestablePictureLayerTiling::Create(1.0f, layer_bounds, &client);
+ tiling->UpdateTilePriorities(ACTIVE_TREE, viewport, 1.0f, 1.0);
+
+ PictureLayerTiling::TilingRasterTileIterator empty_iterator;
+ EXPECT_FALSE(empty_iterator);
+
+ std::vector<Tile*> all_tiles = tiling->AllTilesForTesting();
+
+ PictureLayerTiling::TilingEvictionTileIterator it(tiling.get(),
+ SMOOTHNESS_TAKES_PRIORITY);
+
+ // Tiles don't have resources to evict.
+ EXPECT_FALSE(it);
+
+ // Sanity check.
+ EXPECT_EQ(64u, all_tiles.size());
+
+ client.tile_manager()->InitializeTilesWithResourcesForTesting(all_tiles);
+
+ std::set<Tile*> all_tiles_set(all_tiles.begin(), all_tiles.end());
+
+ it = PictureLayerTiling::TilingEvictionTileIterator(
+ tiling.get(), SMOOTHNESS_TAKES_PRIORITY);
+ EXPECT_TRUE(it);
+
+ std::set<Tile*> eviction_tiles;
+ Tile* last_tile = *it;
+ for (; it; ++it) {
+ Tile* tile = *it;
+ EXPECT_TRUE(tile);
+ EXPECT_LE(tile->priority(ACTIVE_TREE).priority_bin,
+ last_tile->priority(ACTIVE_TREE).priority_bin);
+ if (tile->priority(ACTIVE_TREE).priority_bin ==
+ last_tile->priority(ACTIVE_TREE).priority_bin) {
+ EXPECT_LE(tile->priority(ACTIVE_TREE).distance_to_visible,
+ last_tile->priority(ACTIVE_TREE).distance_to_visible);
+ }
+ last_tile = tile;
+ eviction_tiles.insert(tile);
+ }
+
+ EXPECT_GT(all_tiles_set.size(), 0u);
+ EXPECT_EQ(all_tiles_set, eviction_tiles);
+}
+
TEST_F(PictureLayerTilingIteratorTest, TilesExist) {
gfx::Size layer_bounds(1099, 801);
Initialize(gfx::Size(100, 100), 1.f, layer_bounds);
@@ -491,33 +1054,16 @@ TEST_F(PictureLayerTilingIteratorTest, TilesExist) {
tiling_->UpdateTilePriorities(
ACTIVE_TREE,
- layer_bounds, // device viewport
- gfx::Rect(layer_bounds), // viewport in layer space
gfx::Rect(layer_bounds), // visible content rect
- layer_bounds, // last layer bounds
- layer_bounds, // current layer bounds
- 1.f, // last contents scale
- 1.f, // current contents scale
- gfx::Transform(), // last screen transform
- gfx::Transform(), // current screen transform
- 1.0, // current frame time
- 10000); // max tiles in tile manager
+ 1.f, // current contents scale
+ 1.0); // current frame time
VerifyTiles(1.f, gfx::Rect(layer_bounds), base::Bind(&TileExists, true));
// Make the viewport rect empty. All tiles are killed and become zombies.
- tiling_->UpdateTilePriorities(
- ACTIVE_TREE,
- layer_bounds, // device viewport
- gfx::Rect(), // viewport in layer space
- gfx::Rect(), // visible content rect
- layer_bounds, // last layer bounds
- layer_bounds, // current layer bounds
- 1.f, // last contents scale
- 1.f, // current contents scale
- gfx::Transform(), // last screen transform
- gfx::Transform(), // current screen transform
- 2.0, // current frame time
- 10000); // max tiles in tile manager
+ tiling_->UpdateTilePriorities(ACTIVE_TREE,
+ gfx::Rect(), // visible content rect
+ 1.f, // current contents scale
+ 2.0); // current frame time
VerifyTiles(1.f, gfx::Rect(layer_bounds), base::Bind(&TileExists, false));
}
@@ -531,33 +1077,16 @@ TEST_F(PictureLayerTilingIteratorTest, TilesExistGiantViewport) {
tiling_->UpdateTilePriorities(
ACTIVE_TREE,
- layer_bounds, // device viewport
- giant_rect, // viewport in layer space
gfx::Rect(layer_bounds), // visible content rect
- layer_bounds, // last layer bounds
- layer_bounds, // current layer bounds
- 1.f, // last contents scale
- 1.f, // current contents scale
- gfx::Transform(), // last screen transform
- gfx::Transform(), // current screen transform
- 1.0, // current frame time
- 10000); // max tiles in tile manager
+ 1.f, // current contents scale
+ 1.0); // current frame time
VerifyTiles(1.f, gfx::Rect(layer_bounds), base::Bind(&TileExists, true));
// If the visible content rect is empty, it should still have live tiles.
- tiling_->UpdateTilePriorities(
- ACTIVE_TREE,
- layer_bounds, // device viewport
- giant_rect, // viewport in layer space
- gfx::Rect(), // visible content rect
- layer_bounds, // last layer bounds
- layer_bounds, // current layer bounds
- 1.f, // last contents scale
- 1.f, // current contents scale
- gfx::Transform(), // last screen transform
- gfx::Transform(), // current screen transform
- 2.0, // current frame time
- 10000); // max tiles in tile manager
+ tiling_->UpdateTilePriorities(ACTIVE_TREE,
+ giant_rect, // visible content rect
+ 1.f, // current contents scale
+ 2.0); // current frame time
VerifyTiles(1.f, gfx::Rect(layer_bounds), base::Bind(&TileExists, true));
}
@@ -572,26 +1101,17 @@ TEST_F(PictureLayerTilingIteratorTest, TilesExistOutsideViewport) {
gfx::Rect viewport_rect(1100, 0, 1000, 1000);
EXPECT_FALSE(viewport_rect.Intersects(gfx::Rect(layer_bounds)));
- tiling_->UpdateTilePriorities(
- ACTIVE_TREE,
- layer_bounds, // device viewport
- viewport_rect, // viewport in layer space
- gfx::Rect(), // visible content rect
- layer_bounds, // last layer bounds
- layer_bounds, // current layer bounds
- 1.f, // last contents scale
- 1.f, // current contents scale
- gfx::Transform(), // last screen transform
- gfx::Transform(), // current screen transform
- 1.0, // current frame time
- 10000); // max tiles in tile manager
+ tiling_->UpdateTilePriorities(ACTIVE_TREE,
+ viewport_rect, // visible content rect
+ 1.f, // current contents scale
+ 1.0); // current frame time
VerifyTiles(1.f, gfx::Rect(layer_bounds), base::Bind(&TileExists, true));
}
-static void TilesIntersectingRectExist(gfx::Rect rect,
+static void TilesIntersectingRectExist(const gfx::Rect& rect,
bool intersect_exists,
Tile* tile,
- gfx::Rect geometry_rect) {
+ const gfx::Rect& geometry_rect) {
bool intersects = rect.Intersects(geometry_rect);
bool expected_exists = intersect_exists ? intersects : !intersects;
EXPECT_EQ(expected_exists, tile != NULL)
@@ -608,19 +1128,11 @@ TEST_F(PictureLayerTilingIteratorTest,
gfx::Rect visible_rect(8000, 8000, 50, 50);
- tiling_->UpdateTilePriorities(
- ACTIVE_TREE,
- layer_bounds, // device viewport
- gfx::Rect(layer_bounds), // viewport in layer space
- visible_rect, // visible content rect
- layer_bounds, // last layer bounds
- layer_bounds, // current layer bounds
- 1.f, // last contents scale
- 1.f, // current contents scale
- gfx::Transform(), // last screen transform
- gfx::Transform(), // current screen transform
- 1.0, // current frame time
- 1); // max tiles in tile manager
+ set_max_tiles_for_interest_area(1);
+ tiling_->UpdateTilePriorities(ACTIVE_TREE,
+ visible_rect, // visible content rect
+ 1.f, // current contents scale
+ 1.0); // current frame time
VerifyTiles(1.f,
gfx::Rect(layer_bounds),
base::Bind(&TilesIntersectingRectExist, visible_rect, true));
@@ -628,7 +1140,7 @@ TEST_F(PictureLayerTilingIteratorTest,
static void CountExistingTiles(int *count,
Tile* tile,
- gfx::Rect geometry_rect) {
+ const gfx::Rect& geometry_rect) {
if (tile != NULL)
++(*count);
}
@@ -640,19 +1152,12 @@ TEST_F(PictureLayerTilingIteratorTest,
VerifyTilesExactlyCoverRect(1.f, gfx::Rect(layer_bounds));
VerifyTiles(1.f, gfx::Rect(layer_bounds), base::Bind(&TileExists, false));
+ set_max_tiles_for_interest_area(1);
tiling_->UpdateTilePriorities(
ACTIVE_TREE,
- layer_bounds, // device viewport
- gfx::Rect(layer_bounds), // viewport in layer space
gfx::Rect(layer_bounds), // visible content rect
- layer_bounds, // last layer bounds
- layer_bounds, // current layer bounds
- 1.f, // last contents scale
- 1.f, // current contents scale
- gfx::Transform(), // last screen transform
- gfx::Transform(), // current screen transform
- 1.0, // current frame time
- 1); // max tiles in tile manager
+ 1.f, // current contents scale
+ 1.0); // current frame time
int num_tiles = 0;
VerifyTiles(1.f,
@@ -679,19 +1184,11 @@ TEST_F(PictureLayerTilingIteratorTest, AddTilingsToMatchScale) {
gfx::Rect(layer_bounds),
base::Bind(&TileExists, false));
- active_set.UpdateTilePriorities(
- PENDING_TREE,
- layer_bounds, // device viewport
- gfx::Rect(layer_bounds), // viewport in layer space
- gfx::Rect(layer_bounds), // visible content rect
- layer_bounds, // last layer bounds
- layer_bounds, // current layer bounds
- 1.f, // last contents scale
- 1.f, // current contents scale
- gfx::Transform(), // last screen transform
- gfx::Transform(), // current screen transform
- 1.0, // current frame time
- 10000); // max tiles in tile manager
+ UpdateAllTilePriorities(&active_set,
+ PENDING_TREE,
+ gfx::Rect(layer_bounds), // visible content rect
+ 1.f, // current contents scale
+ 1.0); // current frame time
// The active tiling has tiles now.
VerifyTiles(active_set.tiling_at(0),
@@ -712,19 +1209,11 @@ TEST_F(PictureLayerTilingIteratorTest, AddTilingsToMatchScale) {
// UpdateTilePriorities on the pending tiling at the same frame time. The
// pending tiling should get tiles.
- pending_set.UpdateTilePriorities(
- PENDING_TREE,
- layer_bounds, // device viewport
- gfx::Rect(layer_bounds), // viewport in layer space
- gfx::Rect(layer_bounds), // visible content rect
- layer_bounds, // last layer bounds
- layer_bounds, // current layer bounds
- 1.f, // last contents scale
- 1.f, // current contents scale
- gfx::Transform(), // last screen transform
- gfx::Transform(), // current screen transform
- 1.0, // current frame time
- 10000); // max tiles in tile manager
+ UpdateAllTilePriorities(&pending_set,
+ PENDING_TREE,
+ gfx::Rect(layer_bounds), // visible content rect
+ 1.f, // current contents scale
+ 1.0); // current frame time
VerifyTiles(pending_set.tiling_at(0),
1.f,
@@ -740,15 +1229,11 @@ TEST(UpdateTilePrioritiesTest, VisibleTiles) {
scoped_ptr<TestablePictureLayerTiling> tiling;
gfx::Size device_viewport(800, 600);
- gfx::Rect visible_layer_rect(0, 0, 200, 200);
gfx::Size last_layer_bounds(200, 200);
gfx::Size current_layer_bounds(200, 200);
- float last_layer_contents_scale = 1.f;
float current_layer_contents_scale = 1.f;
- gfx::Transform last_screen_transform;
gfx::Transform current_screen_transform;
double current_frame_time_in_seconds = 1.0;
- size_t max_tiles_for_interest_area = 10000;
gfx::Rect viewport_in_layer_space = ViewportInLayerSpace(
current_screen_transform, device_viewport);
@@ -758,19 +1243,10 @@ TEST(UpdateTilePrioritiesTest, VisibleTiles) {
current_layer_bounds,
&client);
- tiling->UpdateTilePriorities(
- ACTIVE_TREE,
- device_viewport,
- viewport_in_layer_space,
- visible_layer_rect,
- last_layer_bounds,
- current_layer_bounds,
- last_layer_contents_scale,
- current_layer_contents_scale,
- last_screen_transform,
- current_screen_transform,
- current_frame_time_in_seconds,
- max_tiles_for_interest_area);
+ tiling->UpdateTilePriorities(ACTIVE_TREE,
+ viewport_in_layer_space,
+ current_layer_contents_scale,
+ current_frame_time_in_seconds);
ASSERT_TRUE(tiling->TileAt(0, 0));
ASSERT_TRUE(tiling->TileAt(0, 1));
@@ -778,20 +1254,20 @@ TEST(UpdateTilePrioritiesTest, VisibleTiles) {
ASSERT_TRUE(tiling->TileAt(1, 1));
TilePriority priority = tiling->TileAt(0, 0)->priority(ACTIVE_TREE);
- EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible_in_pixels);
- EXPECT_FLOAT_EQ(0.f, priority.time_to_visible_in_seconds);
+ EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible);
+ EXPECT_FLOAT_EQ(TilePriority::NOW, priority.priority_bin);
priority = tiling->TileAt(0, 1)->priority(ACTIVE_TREE);
- EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible_in_pixels);
- EXPECT_FLOAT_EQ(0.f, priority.time_to_visible_in_seconds);
+ EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible);
+ EXPECT_FLOAT_EQ(TilePriority::NOW, priority.priority_bin);
priority = tiling->TileAt(1, 0)->priority(ACTIVE_TREE);
- EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible_in_pixels);
- EXPECT_FLOAT_EQ(0.f, priority.time_to_visible_in_seconds);
+ EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible);
+ EXPECT_FLOAT_EQ(TilePriority::NOW, priority.priority_bin);
priority = tiling->TileAt(1, 1)->priority(ACTIVE_TREE);
- EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible_in_pixels);
- EXPECT_FLOAT_EQ(0.f, priority.time_to_visible_in_seconds);
+ EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible);
+ EXPECT_FLOAT_EQ(TilePriority::NOW, priority.priority_bin);
}
TEST(UpdateTilePrioritiesTest, OffscreenTiles) {
@@ -802,15 +1278,12 @@ TEST(UpdateTilePrioritiesTest, OffscreenTiles) {
scoped_ptr<TestablePictureLayerTiling> tiling;
gfx::Size device_viewport(800, 600);
- gfx::Rect visible_layer_rect(0, 0, 0, 0); // offscreen; nothing is visible.
gfx::Size last_layer_bounds(200, 200);
gfx::Size current_layer_bounds(200, 200);
- float last_layer_contents_scale = 1.f;
float current_layer_contents_scale = 1.f;
gfx::Transform last_screen_transform;
gfx::Transform current_screen_transform;
double current_frame_time_in_seconds = 1.0;
- size_t max_tiles_for_interest_area = 10000;
current_screen_transform.Translate(850, 0);
last_screen_transform = current_screen_transform;
@@ -823,19 +1296,10 @@ TEST(UpdateTilePrioritiesTest, OffscreenTiles) {
current_layer_bounds,
&client);
- tiling->UpdateTilePriorities(
- ACTIVE_TREE,
- device_viewport,
- viewport_in_layer_space,
- visible_layer_rect,
- last_layer_bounds,
- current_layer_bounds,
- last_layer_contents_scale,
- current_layer_contents_scale,
- last_screen_transform,
- current_screen_transform,
- current_frame_time_in_seconds,
- max_tiles_for_interest_area);
+ tiling->UpdateTilePriorities(ACTIVE_TREE,
+ viewport_in_layer_space,
+ current_layer_contents_scale,
+ current_frame_time_in_seconds);
ASSERT_TRUE(tiling->TileAt(0, 0));
ASSERT_TRUE(tiling->TileAt(0, 1));
@@ -843,36 +1307,30 @@ TEST(UpdateTilePrioritiesTest, OffscreenTiles) {
ASSERT_TRUE(tiling->TileAt(1, 1));
TilePriority priority = tiling->TileAt(0, 0)->priority(ACTIVE_TREE);
- EXPECT_GT(priority.distance_to_visible_in_pixels, 0.f);
- EXPECT_FLOAT_EQ(std::numeric_limits<float>::infinity(),
- priority.time_to_visible_in_seconds);
+ EXPECT_GT(priority.distance_to_visible, 0.f);
+ EXPECT_NE(TilePriority::NOW, priority.priority_bin);
priority = tiling->TileAt(0, 1)->priority(ACTIVE_TREE);
- EXPECT_GT(priority.distance_to_visible_in_pixels, 0.f);
- EXPECT_FLOAT_EQ(std::numeric_limits<float>::infinity(),
- priority.time_to_visible_in_seconds);
+ EXPECT_GT(priority.distance_to_visible, 0.f);
+ EXPECT_NE(TilePriority::NOW, priority.priority_bin);
priority = tiling->TileAt(1, 0)->priority(ACTIVE_TREE);
- EXPECT_GT(priority.distance_to_visible_in_pixels, 0.f);
- EXPECT_FLOAT_EQ(std::numeric_limits<float>::infinity(),
- priority.time_to_visible_in_seconds);
+ EXPECT_GT(priority.distance_to_visible, 0.f);
+ EXPECT_NE(TilePriority::NOW, priority.priority_bin);
priority = tiling->TileAt(1, 1)->priority(ACTIVE_TREE);
- EXPECT_GT(priority.distance_to_visible_in_pixels, 0.f);
- EXPECT_FLOAT_EQ(std::numeric_limits<float>::infinity(),
- priority.time_to_visible_in_seconds);
+ EXPECT_GT(priority.distance_to_visible, 0.f);
+ EXPECT_NE(TilePriority::NOW, priority.priority_bin);
// Furthermore, in this scenario tiles on the right hand side should have a
// larger distance to visible.
TilePriority left = tiling->TileAt(0, 0)->priority(ACTIVE_TREE);
TilePriority right = tiling->TileAt(1, 0)->priority(ACTIVE_TREE);
- EXPECT_GT(right.distance_to_visible_in_pixels,
- left.distance_to_visible_in_pixels);
+ EXPECT_GT(right.distance_to_visible, left.distance_to_visible);
left = tiling->TileAt(0, 1)->priority(ACTIVE_TREE);
right = tiling->TileAt(1, 1)->priority(ACTIVE_TREE);
- EXPECT_GT(right.distance_to_visible_in_pixels,
- left.distance_to_visible_in_pixels);
+ EXPECT_GT(right.distance_to_visible, left.distance_to_visible);
}
TEST(UpdateTilePrioritiesTest, PartiallyOffscreenLayer) {
@@ -883,15 +1341,12 @@ TEST(UpdateTilePrioritiesTest, PartiallyOffscreenLayer) {
scoped_ptr<TestablePictureLayerTiling> tiling;
gfx::Size device_viewport(800, 600);
- gfx::Rect visible_layer_rect(0, 0, 100, 100); // only top quarter.
gfx::Size last_layer_bounds(200, 200);
gfx::Size current_layer_bounds(200, 200);
- float last_layer_contents_scale = 1.f;
float current_layer_contents_scale = 1.f;
gfx::Transform last_screen_transform;
gfx::Transform current_screen_transform;
double current_frame_time_in_seconds = 1.0;
- size_t max_tiles_for_interest_area = 10000;
current_screen_transform.Translate(705, 505);
last_screen_transform = current_screen_transform;
@@ -904,19 +1359,10 @@ TEST(UpdateTilePrioritiesTest, PartiallyOffscreenLayer) {
current_layer_bounds,
&client);
- tiling->UpdateTilePriorities(
- ACTIVE_TREE,
- device_viewport,
- viewport_in_layer_space,
- visible_layer_rect,
- last_layer_bounds,
- current_layer_bounds,
- last_layer_contents_scale,
- current_layer_contents_scale,
- last_screen_transform,
- current_screen_transform,
- current_frame_time_in_seconds,
- max_tiles_for_interest_area);
+ tiling->UpdateTilePriorities(ACTIVE_TREE,
+ viewport_in_layer_space,
+ current_layer_contents_scale,
+ current_frame_time_in_seconds);
ASSERT_TRUE(tiling->TileAt(0, 0));
ASSERT_TRUE(tiling->TileAt(0, 1));
@@ -924,23 +1370,20 @@ TEST(UpdateTilePrioritiesTest, PartiallyOffscreenLayer) {
ASSERT_TRUE(tiling->TileAt(1, 1));
TilePriority priority = tiling->TileAt(0, 0)->priority(ACTIVE_TREE);
- EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible_in_pixels);
- EXPECT_FLOAT_EQ(0.f, priority.time_to_visible_in_seconds);
+ EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible);
+ EXPECT_FLOAT_EQ(TilePriority::NOW, priority.priority_bin);
priority = tiling->TileAt(0, 1)->priority(ACTIVE_TREE);
- EXPECT_GT(priority.distance_to_visible_in_pixels, 0.f);
- EXPECT_FLOAT_EQ(std::numeric_limits<float>::infinity(),
- priority.time_to_visible_in_seconds);
+ EXPECT_GT(priority.distance_to_visible, 0.f);
+ EXPECT_NE(TilePriority::NOW, priority.priority_bin);
priority = tiling->TileAt(1, 0)->priority(ACTIVE_TREE);
- EXPECT_GT(priority.distance_to_visible_in_pixels, 0.f);
- EXPECT_FLOAT_EQ(std::numeric_limits<float>::infinity(),
- priority.time_to_visible_in_seconds);
+ EXPECT_GT(priority.distance_to_visible, 0.f);
+ EXPECT_NE(TilePriority::NOW, priority.priority_bin);
priority = tiling->TileAt(1, 1)->priority(ACTIVE_TREE);
- EXPECT_GT(priority.distance_to_visible_in_pixels, 0.f);
- EXPECT_FLOAT_EQ(std::numeric_limits<float>::infinity(),
- priority.time_to_visible_in_seconds);
+ EXPECT_GT(priority.distance_to_visible, 0.f);
+ EXPECT_NE(TilePriority::NOW, priority.priority_bin);
}
TEST(UpdateTilePrioritiesTest, PartiallyOffscreenRotatedLayer) {
@@ -952,19 +1395,16 @@ TEST(UpdateTilePrioritiesTest, PartiallyOffscreenRotatedLayer) {
scoped_ptr<TestablePictureLayerTiling> tiling;
gfx::Size device_viewport(800, 600);
- gfx::Rect visible_layer_rect(0, 0, 100, 100); // only top-left quarter.
gfx::Size last_layer_bounds(200, 200);
gfx::Size current_layer_bounds(200, 200);
- float last_layer_contents_scale = 1.f;
float current_layer_contents_scale = 1.f;
gfx::Transform last_screen_transform;
gfx::Transform current_screen_transform;
double current_frame_time_in_seconds = 1.0;
- size_t max_tiles_for_interest_area = 10000;
// A diagonally rotated layer that is partially off the bottom of the screen.
// In this configuration, only the top-left tile would be visible.
- current_screen_transform.Translate(400, 550);
+ current_screen_transform.Translate(600, 750);
current_screen_transform.RotateAboutZAxis(45);
last_screen_transform = current_screen_transform;
@@ -976,19 +1416,10 @@ TEST(UpdateTilePrioritiesTest, PartiallyOffscreenRotatedLayer) {
current_layer_bounds,
&client);
- tiling->UpdateTilePriorities(
- ACTIVE_TREE,
- device_viewport,
- viewport_in_layer_space,
- visible_layer_rect,
- last_layer_bounds,
- current_layer_bounds,
- last_layer_contents_scale,
- current_layer_contents_scale,
- last_screen_transform,
- current_screen_transform,
- current_frame_time_in_seconds,
- max_tiles_for_interest_area);
+ tiling->UpdateTilePriorities(ACTIVE_TREE,
+ viewport_in_layer_space,
+ current_layer_contents_scale,
+ current_frame_time_in_seconds);
ASSERT_TRUE(tiling->TileAt(0, 0));
ASSERT_TRUE(tiling->TileAt(0, 1));
@@ -996,39 +1427,29 @@ TEST(UpdateTilePrioritiesTest, PartiallyOffscreenRotatedLayer) {
ASSERT_TRUE(tiling->TileAt(1, 1));
TilePriority priority = tiling->TileAt(0, 0)->priority(ACTIVE_TREE);
- EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible_in_pixels);
- EXPECT_FLOAT_EQ(0.f, priority.time_to_visible_in_seconds);
+ EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible);
+ EXPECT_EQ(TilePriority::NOW, priority.priority_bin);
priority = tiling->TileAt(0, 1)->priority(ACTIVE_TREE);
- EXPECT_GT(priority.distance_to_visible_in_pixels, 0.f);
- EXPECT_FLOAT_EQ(std::numeric_limits<float>::infinity(),
- priority.time_to_visible_in_seconds);
+ EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible);
+ EXPECT_EQ(TilePriority::NOW, priority.priority_bin);
priority = tiling->TileAt(1, 0)->priority(ACTIVE_TREE);
- EXPECT_GT(priority.distance_to_visible_in_pixels, 0.f);
- EXPECT_FLOAT_EQ(std::numeric_limits<float>::infinity(),
- priority.time_to_visible_in_seconds);
+ EXPECT_GT(priority.distance_to_visible, 0.f);
+ EXPECT_NE(TilePriority::NOW, priority.priority_bin);
priority = tiling->TileAt(1, 1)->priority(ACTIVE_TREE);
- EXPECT_GT(priority.distance_to_visible_in_pixels, 0.f);
- EXPECT_FLOAT_EQ(std::numeric_limits<float>::infinity(),
- priority.time_to_visible_in_seconds);
+ EXPECT_GT(priority.distance_to_visible, 0.f);
+ EXPECT_NE(TilePriority::NOW, priority.priority_bin);
// Furthermore, in this scenario the bottom-right tile should have the larger
// distance to visible.
TilePriority top_left = tiling->TileAt(0, 0)->priority(ACTIVE_TREE);
TilePriority top_right = tiling->TileAt(1, 0)->priority(ACTIVE_TREE);
- TilePriority bottom_left = tiling->TileAt(0, 1)->priority(ACTIVE_TREE);
TilePriority bottom_right = tiling->TileAt(1, 1)->priority(ACTIVE_TREE);
- EXPECT_GT(top_right.distance_to_visible_in_pixels,
- top_left.distance_to_visible_in_pixels);
- EXPECT_GT(bottom_left.distance_to_visible_in_pixels,
- top_left.distance_to_visible_in_pixels);
-
- EXPECT_GT(bottom_right.distance_to_visible_in_pixels,
- bottom_left.distance_to_visible_in_pixels);
- EXPECT_GT(bottom_right.distance_to_visible_in_pixels,
- top_right.distance_to_visible_in_pixels);
+ EXPECT_GT(top_right.distance_to_visible, top_left.distance_to_visible);
+
+ EXPECT_EQ(bottom_right.distance_to_visible, top_right.distance_to_visible);
}
TEST(UpdateTilePrioritiesTest, PerspectiveLayer) {
@@ -1042,12 +1463,10 @@ TEST(UpdateTilePrioritiesTest, PerspectiveLayer) {
gfx::Rect visible_layer_rect(0, 0, 0, 0); // offscreen.
gfx::Size last_layer_bounds(200, 200);
gfx::Size current_layer_bounds(200, 200);
- float last_layer_contents_scale = 1.f;
float current_layer_contents_scale = 1.f;
gfx::Transform last_screen_transform;
gfx::Transform current_screen_transform;
double current_frame_time_in_seconds = 1.0;
- size_t max_tiles_for_interest_area = 10000;
// A 3d perspective layer rotated about its Y axis, translated to almost
// fully offscreen. The left side will appear closer (i.e. larger in 2d) than
@@ -1078,19 +1497,10 @@ TEST(UpdateTilePrioritiesTest, PerspectiveLayer) {
current_layer_bounds,
&client);
- tiling->UpdateTilePriorities(
- ACTIVE_TREE,
- device_viewport,
- viewport_in_layer_space,
- visible_layer_rect,
- last_layer_bounds,
- current_layer_bounds,
- last_layer_contents_scale,
- current_layer_contents_scale,
- last_screen_transform,
- current_screen_transform,
- current_frame_time_in_seconds,
- max_tiles_for_interest_area);
+ tiling->UpdateTilePriorities(ACTIVE_TREE,
+ viewport_in_layer_space,
+ current_layer_contents_scale,
+ current_frame_time_in_seconds);
ASSERT_TRUE(tiling->TileAt(0, 0));
ASSERT_TRUE(tiling->TileAt(0, 1));
@@ -1100,24 +1510,20 @@ TEST(UpdateTilePrioritiesTest, PerspectiveLayer) {
// All tiles will have a positive distance_to_visible
// and an infinite time_to_visible.
TilePriority priority = tiling->TileAt(0, 0)->priority(ACTIVE_TREE);
- EXPECT_GT(priority.distance_to_visible_in_pixels, 0.f);
- EXPECT_FLOAT_EQ(std::numeric_limits<float>::infinity(),
- priority.time_to_visible_in_seconds);
+ EXPECT_FLOAT_EQ(priority.distance_to_visible, 0.f);
+ EXPECT_EQ(TilePriority::NOW, priority.priority_bin);
priority = tiling->TileAt(0, 1)->priority(ACTIVE_TREE);
- EXPECT_GT(priority.distance_to_visible_in_pixels, 0.f);
- EXPECT_FLOAT_EQ(std::numeric_limits<float>::infinity(),
- priority.time_to_visible_in_seconds);
+ EXPECT_GT(priority.distance_to_visible, 0.f);
+ EXPECT_NE(TilePriority::NOW, priority.priority_bin);
priority = tiling->TileAt(1, 0)->priority(ACTIVE_TREE);
- EXPECT_GT(priority.distance_to_visible_in_pixels, 0.f);
- EXPECT_FLOAT_EQ(std::numeric_limits<float>::infinity(),
- priority.time_to_visible_in_seconds);
+ EXPECT_FLOAT_EQ(priority.distance_to_visible, 0.f);
+ EXPECT_EQ(TilePriority::NOW, priority.priority_bin);
priority = tiling->TileAt(1, 1)->priority(ACTIVE_TREE);
- EXPECT_GT(priority.distance_to_visible_in_pixels, 0.f);
- EXPECT_FLOAT_EQ(std::numeric_limits<float>::infinity(),
- priority.time_to_visible_in_seconds);
+ EXPECT_GT(priority.distance_to_visible, 0.f);
+ EXPECT_NE(TilePriority::NOW, priority.priority_bin);
// Furthermore, in this scenario the top-left distance_to_visible
// will be smallest, followed by top-right. The bottom layers
@@ -1126,14 +1532,10 @@ TEST(UpdateTilePrioritiesTest, PerspectiveLayer) {
TilePriority top_right = tiling->TileAt(1, 0)->priority(ACTIVE_TREE);
TilePriority bottom_left = tiling->TileAt(0, 1)->priority(ACTIVE_TREE);
TilePriority bottom_right = tiling->TileAt(1, 1)->priority(ACTIVE_TREE);
- EXPECT_GT(top_right.distance_to_visible_in_pixels,
- top_left.distance_to_visible_in_pixels);
- EXPECT_GT(bottom_right.distance_to_visible_in_pixels,
- top_right.distance_to_visible_in_pixels);
+ EXPECT_GT(bottom_right.distance_to_visible, top_right.distance_to_visible);
- EXPECT_GT(bottom_left.distance_to_visible_in_pixels,
- top_left.distance_to_visible_in_pixels);
+ EXPECT_GT(bottom_left.distance_to_visible, top_left.distance_to_visible);
}
TEST(UpdateTilePrioritiesTest, PerspectiveLayerClippedByW) {
@@ -1144,15 +1546,12 @@ TEST(UpdateTilePrioritiesTest, PerspectiveLayerClippedByW) {
scoped_ptr<TestablePictureLayerTiling> tiling;
gfx::Size device_viewport(800, 600);
- gfx::Rect visible_layer_rect(0, 0, 0, 0); // offscreen.
gfx::Size last_layer_bounds(200, 200);
gfx::Size current_layer_bounds(200, 200);
- float last_layer_contents_scale = 1.f;
float current_layer_contents_scale = 1.f;
gfx::Transform last_screen_transform;
gfx::Transform current_screen_transform;
double current_frame_time_in_seconds = 1.0;
- size_t max_tiles_for_interest_area = 10000;
// A 3d perspective layer rotated about its Y axis, translated to almost
// fully offscreen. The left side will appear closer (i.e. larger in 2d) than
@@ -1189,19 +1588,10 @@ TEST(UpdateTilePrioritiesTest, PerspectiveLayerClippedByW) {
current_layer_bounds,
&client);
- tiling->UpdateTilePriorities(
- ACTIVE_TREE,
- device_viewport,
- viewport_in_layer_space,
- visible_layer_rect,
- last_layer_bounds,
- current_layer_bounds,
- last_layer_contents_scale,
- current_layer_contents_scale,
- last_screen_transform,
- current_screen_transform,
- current_frame_time_in_seconds,
- max_tiles_for_interest_area);
+ tiling->UpdateTilePriorities(ACTIVE_TREE,
+ viewport_in_layer_space,
+ current_layer_contents_scale,
+ current_frame_time_in_seconds);
ASSERT_TRUE(tiling->TileAt(0, 0));
ASSERT_TRUE(tiling->TileAt(0, 1));
@@ -1211,24 +1601,22 @@ TEST(UpdateTilePrioritiesTest, PerspectiveLayerClippedByW) {
// Left-side tiles will be clipped by the transform, so we have to assume
// they are visible just in case.
TilePriority priority = tiling->TileAt(0, 0)->priority(ACTIVE_TREE);
- EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible_in_pixels);
- EXPECT_FLOAT_EQ(0.f, priority.time_to_visible_in_seconds);
+ EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible);
+ EXPECT_FLOAT_EQ(TilePriority::NOW, priority.priority_bin);
priority = tiling->TileAt(0, 1)->priority(ACTIVE_TREE);
- EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible_in_pixels);
- EXPECT_FLOAT_EQ(0.f, priority.time_to_visible_in_seconds);
+ EXPECT_GT(priority.distance_to_visible, 0.f);
+ EXPECT_NE(TilePriority::NOW, priority.priority_bin);
// Right-side tiles will have a positive distance_to_visible
// and an infinite time_to_visible.
priority = tiling->TileAt(1, 0)->priority(ACTIVE_TREE);
- EXPECT_GT(priority.distance_to_visible_in_pixels, 0.f);
- EXPECT_FLOAT_EQ(std::numeric_limits<float>::infinity(),
- priority.time_to_visible_in_seconds);
+ EXPECT_FLOAT_EQ(priority.distance_to_visible, 0.f);
+ EXPECT_EQ(TilePriority::NOW, priority.priority_bin);
priority = tiling->TileAt(1, 1)->priority(ACTIVE_TREE);
- EXPECT_GT(priority.distance_to_visible_in_pixels, 0.f);
- EXPECT_FLOAT_EQ(std::numeric_limits<float>::infinity(),
- priority.time_to_visible_in_seconds);
+ EXPECT_GT(priority.distance_to_visible, 0.f);
+ EXPECT_NE(TilePriority::NOW, priority.priority_bin);
}
TEST(UpdateTilePrioritiesTest, BasicMotion) {
@@ -1248,7 +1636,6 @@ TEST(UpdateTilePrioritiesTest, BasicMotion) {
gfx::Transform current_screen_transform;
double last_frame_time_in_seconds = 1.0;
double current_frame_time_in_seconds = 2.0;
- size_t max_tiles_for_interest_area = 10000;
// Offscreen layer is coming closer to viewport at 1000 pixels per second.
current_screen_transform.Translate(1800, 0);
@@ -1263,34 +1650,16 @@ TEST(UpdateTilePrioritiesTest, BasicMotion) {
&client);
// previous ("last") frame
- tiling->UpdateTilePriorities(
- ACTIVE_TREE,
- device_viewport,
- viewport_in_layer_space,
- visible_layer_rect,
- last_layer_bounds,
- last_layer_bounds,
- last_layer_contents_scale,
- last_layer_contents_scale,
- last_screen_transform,
- last_screen_transform,
- last_frame_time_in_seconds,
- max_tiles_for_interest_area);
+ tiling->UpdateTilePriorities(ACTIVE_TREE,
+ viewport_in_layer_space,
+ last_layer_contents_scale,
+ last_frame_time_in_seconds);
// current frame
- tiling->UpdateTilePriorities(
- ACTIVE_TREE,
- device_viewport,
- viewport_in_layer_space,
- visible_layer_rect,
- last_layer_bounds,
- current_layer_bounds,
- last_layer_contents_scale,
- current_layer_contents_scale,
- last_screen_transform,
- current_screen_transform,
- current_frame_time_in_seconds,
- max_tiles_for_interest_area);
+ tiling->UpdateTilePriorities(ACTIVE_TREE,
+ viewport_in_layer_space,
+ current_layer_contents_scale,
+ current_frame_time_in_seconds);
ASSERT_TRUE(tiling->TileAt(0, 0));
ASSERT_TRUE(tiling->TileAt(0, 1));
@@ -1298,26 +1667,22 @@ TEST(UpdateTilePrioritiesTest, BasicMotion) {
ASSERT_TRUE(tiling->TileAt(1, 1));
TilePriority priority = tiling->TileAt(0, 0)->priority(ACTIVE_TREE);
- EXPECT_GT(priority.distance_to_visible_in_pixels, 0.f);
- EXPECT_FLOAT_EQ(1.f,
- priority.time_to_visible_in_seconds);
+ EXPECT_GT(priority.distance_to_visible, 0.f);
+ EXPECT_NE(TilePriority::NOW, priority.priority_bin);
priority = tiling->TileAt(0, 1)->priority(ACTIVE_TREE);
- EXPECT_GT(priority.distance_to_visible_in_pixels, 0.f);
- EXPECT_FLOAT_EQ(1.f,
- priority.time_to_visible_in_seconds);
+ EXPECT_GT(priority.distance_to_visible, 0.f);
+ EXPECT_NE(TilePriority::NOW, priority.priority_bin);
// time_to_visible for the right hand side layers needs an extra 0.099
// seconds because this tile is 99 pixels further away.
priority = tiling->TileAt(1, 0)->priority(ACTIVE_TREE);
- EXPECT_GT(priority.distance_to_visible_in_pixels, 0.f);
- EXPECT_FLOAT_EQ(1.099f,
- priority.time_to_visible_in_seconds);
+ EXPECT_GT(priority.distance_to_visible, 0.f);
+ EXPECT_NE(TilePriority::NOW, priority.priority_bin);
priority = tiling->TileAt(1, 1)->priority(ACTIVE_TREE);
- EXPECT_GT(priority.distance_to_visible_in_pixels, 0.f);
- EXPECT_FLOAT_EQ(1.099f,
- priority.time_to_visible_in_seconds);
+ EXPECT_GT(priority.distance_to_visible, 0.f);
+ EXPECT_NE(TilePriority::NOW, priority.priority_bin);
}
TEST(UpdateTilePrioritiesTest, RotationMotion) {
@@ -1338,7 +1703,6 @@ TEST(UpdateTilePrioritiesTest, RotationMotion) {
gfx::Transform current_screen_transform;
double last_frame_time_in_seconds = 1.0;
double current_frame_time_in_seconds = 2.0;
- size_t max_tiles_for_interest_area = 10000;
// Rotation motion is set up specifically so that:
// - rotation occurs about the center of the layer
@@ -1361,34 +1725,16 @@ TEST(UpdateTilePrioritiesTest, RotationMotion) {
&client);
// previous ("last") frame
- tiling->UpdateTilePriorities(
- ACTIVE_TREE,
- device_viewport,
- viewport_in_layer_space,
- visible_layer_rect,
- last_layer_bounds,
- last_layer_bounds,
- last_layer_contents_scale,
- last_layer_contents_scale,
- last_screen_transform,
- last_screen_transform,
- last_frame_time_in_seconds,
- max_tiles_for_interest_area);
+ tiling->UpdateTilePriorities(ACTIVE_TREE,
+ viewport_in_layer_space,
+ last_layer_contents_scale,
+ last_frame_time_in_seconds);
// current frame
- tiling->UpdateTilePriorities(
- ACTIVE_TREE,
- device_viewport,
- viewport_in_layer_space,
- visible_layer_rect,
- last_layer_bounds,
- current_layer_bounds,
- last_layer_contents_scale,
- current_layer_contents_scale,
- last_screen_transform,
- current_screen_transform,
- current_frame_time_in_seconds,
- max_tiles_for_interest_area);
+ tiling->UpdateTilePriorities(ACTIVE_TREE,
+ viewport_in_layer_space,
+ current_layer_contents_scale,
+ current_frame_time_in_seconds);
ASSERT_TRUE(tiling->TileAt(0, 0));
ASSERT_TRUE(tiling->TileAt(0, 1));
@@ -1396,17 +1742,16 @@ TEST(UpdateTilePrioritiesTest, RotationMotion) {
ASSERT_TRUE(tiling->TileAt(1, 1));
TilePriority priority = tiling->TileAt(0, 0)->priority(ACTIVE_TREE);
- EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible_in_pixels);
- EXPECT_FLOAT_EQ(0.f, priority.time_to_visible_in_seconds);
+ EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible);
+ EXPECT_EQ(TilePriority::NOW, priority.priority_bin);
priority = tiling->TileAt(0, 1)->priority(ACTIVE_TREE);
- EXPECT_GT(priority.distance_to_visible_in_pixels, 0.f);
- EXPECT_GT(priority.time_to_visible_in_seconds, 0.f);
+ EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible);
+ EXPECT_EQ(TilePriority::NOW, priority.priority_bin);
priority = tiling->TileAt(1, 0)->priority(ACTIVE_TREE);
- EXPECT_GT(priority.distance_to_visible_in_pixels, 0.f);
- EXPECT_FLOAT_EQ(std::numeric_limits<float>::infinity(),
- priority.time_to_visible_in_seconds);
+ EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible);
+ EXPECT_EQ(TilePriority::NOW, priority.priority_bin);
}
} // namespace
diff --git a/chromium/cc/resources/picture_pile.cc b/chromium/cc/resources/picture_pile.cc
index 68d75d7aea1..6341e88b368 100644
--- a/chromium/cc/resources/picture_pile.cc
+++ b/chromium/cc/resources/picture_pile.cc
@@ -11,6 +11,7 @@
#include "cc/base/region.h"
#include "cc/debug/rendering_stats_instrumentation.h"
#include "cc/resources/picture_pile_impl.h"
+#include "cc/resources/raster_worker_pool.h"
#include "cc/resources/tile_priority.h"
namespace {
@@ -140,22 +141,24 @@ float ClusterTiles(const std::vector<gfx::Rect>& invalid_tiles,
namespace cc {
-PicturePile::PicturePile() {
-}
+PicturePile::PicturePile() : is_suitable_for_gpu_rasterization_(true) {}
PicturePile::~PicturePile() {
}
-bool PicturePile::Update(
+bool PicturePile::UpdateAndExpandInvalidation(
ContentLayerClient* painter,
+ Region* invalidation,
SkColor background_color,
bool contents_opaque,
- const Region& invalidation,
- gfx::Rect visible_layer_rect,
+ bool contents_fill_bounds_completely,
+ const gfx::Rect& visible_layer_rect,
int frame_number,
+ Picture::RecordingMode recording_mode,
RenderingStatsInstrumentation* stats_instrumentation) {
background_color_ = background_color;
contents_opaque_ = contents_opaque;
+ contents_fill_bounds_completely_ = contents_fill_bounds_completely;
gfx::Rect interest_rect = visible_layer_rect;
interest_rect.Inset(
@@ -163,14 +166,23 @@ bool PicturePile::Update(
-kPixelDistanceToRecord,
-kPixelDistanceToRecord,
-kPixelDistanceToRecord);
+ recorded_viewport_ = interest_rect;
+ recorded_viewport_.Intersect(tiling_rect());
+
+ gfx::Rect interest_rect_over_tiles =
+ tiling_.ExpandRectToTileBounds(interest_rect);
+
+ Region invalidation_expanded_to_full_tiles;
bool invalidated = false;
- for (Region::Iterator i(invalidation); i.has_rect(); i.next()) {
- gfx::Rect invalidation = i.rect();
+ for (Region::Iterator i(*invalidation); i.has_rect(); i.next()) {
+ gfx::Rect invalid_rect = i.rect();
// Split this inflated invalidation across tile boundaries and apply it
// to all tiles that it touches.
- for (TilingData::Iterator iter(&tiling_, invalidation);
- iter; ++iter) {
+ bool include_borders = true;
+ for (TilingData::Iterator iter(&tiling_, invalid_rect, include_borders);
+ iter;
+ ++iter) {
const PictureMapKey& key = iter.index();
PictureMap::iterator picture_it = picture_map_.find(key);
@@ -180,14 +192,28 @@ bool PicturePile::Update(
// Inform the grid cell that it has been invalidated in this frame.
invalidated = picture_it->second.Invalidate(frame_number) || invalidated;
}
+
+ // Expand invalidation that is outside tiles that intersect the interest
+ // rect. These tiles are no longer valid and should be considerered fully
+ // invalid, so we can know to not keep around raster tiles that intersect
+ // with these recording tiles.
+ gfx::Rect invalid_rect_outside_interest_rect_tiles = invalid_rect;
+ // TODO(danakj): We should have a Rect-subtract-Rect-to-2-rects operator
+ // instead of using Rect::Subtract which gives you the bounding box of the
+ // subtraction.
+ invalid_rect_outside_interest_rect_tiles.Subtract(interest_rect_over_tiles);
+ invalidation_expanded_to_full_tiles.Union(tiling_.ExpandRectToTileBounds(
+ invalid_rect_outside_interest_rect_tiles));
}
+ invalidation->Union(invalidation_expanded_to_full_tiles);
+
// Make a list of all invalid tiles; we will attempt to
// cluster these into multiple invalidation regions.
std::vector<gfx::Rect> invalid_tiles;
-
- for (TilingData::Iterator it(&tiling_, interest_rect);
- it; ++it) {
+ bool include_borders = true;
+ for (TilingData::Iterator it(&tiling_, interest_rect, include_borders); it;
+ ++it) {
const PictureMapKey& key = it.index();
PictureInfo& info = picture_map_[key];
@@ -198,17 +224,27 @@ bool PicturePile::Update(
if (info.NeedsRecording(frame_number, distance_to_visible)) {
gfx::Rect tile = tiling_.TileBounds(key.first, key.second);
invalid_tiles.push_back(tile);
+ } else if (!info.GetPicture()) {
+ if (recorded_viewport_.Intersects(rect)) {
+ // Recorded viewport is just an optimization for a fully recorded
+ // interest rect. In this case, a tile in that rect has declined
+ // to be recorded (probably due to frequent invalidations).
+ // TODO(enne): Shrink the recorded_viewport_ rather than clearing.
+ recorded_viewport_ = gfx::Rect();
+ }
+
+ // If a tile in the interest rect is not recorded, the entire tile needs
+ // to be considered invalid, so that we know not to keep around raster
+ // tiles that intersect this recording tile.
+ invalidation->Union(tiling_.TileBounds(it.index_x(), it.index_y()));
}
}
std::vector<gfx::Rect> record_rects;
ClusterTiles(invalid_tiles, &record_rects);
- if (record_rects.empty()) {
- if (invalidated)
- UpdateRecordedRegion();
+ if (record_rects.empty())
return invalidated;
- }
for (std::vector<gfx::Rect>::iterator it = record_rects.begin();
it != record_rects.end();
@@ -217,14 +253,33 @@ bool PicturePile::Update(
record_rect = PadRect(record_rect);
int repeat_count = std::max(1, slow_down_raster_scale_factor_for_debug_);
- scoped_refptr<Picture> picture = Picture::Create(record_rect);
+ scoped_refptr<Picture> picture;
+ int num_raster_threads = RasterWorkerPool::GetNumRasterThreads();
+
+ // Note: Currently, gathering of pixel refs when using a single
+ // raster thread doesn't provide any benefit. This might change
+ // in the future but we avoid it for now to reduce the cost of
+ // Picture::Create.
+ bool gather_pixel_refs = num_raster_threads > 1;
{
- base::TimeDelta best_duration = base::TimeDelta::FromInternalValue(
- std::numeric_limits<int64>::max());
+ base::TimeDelta best_duration = base::TimeDelta::Max();
for (int i = 0; i < repeat_count; i++) {
base::TimeTicks start_time = stats_instrumentation->StartRecording();
- picture->Record(painter, tile_grid_info_);
+ picture = Picture::Create(record_rect,
+ painter,
+ tile_grid_info_,
+ gather_pixel_refs,
+ num_raster_threads,
+ recording_mode);
+ // Note the '&&' with previous is-suitable state.
+ // This means that once a picture-pile becomes unsuitable for gpu
+ // rasterization due to some content, it will continue to be unsuitable
+ // even if that content is replaced by gpu-friendly content.
+ // This is an optimization to avoid iterating though all pictures in
+ // the pile after each invalidation.
+ is_suitable_for_gpu_rasterization_ &=
+ picture->IsSuitableForGpuRasterization();
base::TimeDelta duration =
stats_instrumentation->EndRecording(start_time);
best_duration = std::min(duration, best_duration);
@@ -232,23 +287,26 @@ bool PicturePile::Update(
int recorded_pixel_count =
picture->LayerRect().width() * picture->LayerRect().height();
stats_instrumentation->AddRecord(best_duration, recorded_pixel_count);
- if (num_raster_threads_ > 1)
- picture->GatherPixelRefs(tile_grid_info_);
- picture->CloneForDrawing(num_raster_threads_);
}
- for (TilingData::Iterator it(&tiling_, record_rect);
- it; ++it) {
+ bool found_tile_for_recorded_picture = false;
+
+ bool include_borders = true;
+ for (TilingData::Iterator it(&tiling_, record_rect, include_borders); it;
+ ++it) {
const PictureMapKey& key = it.index();
gfx::Rect tile = PaddedRect(key);
if (record_rect.Contains(tile)) {
PictureInfo& info = picture_map_[key];
info.SetPicture(picture);
+ found_tile_for_recorded_picture = true;
}
}
+ DCHECK(found_tile_for_recorded_picture);
}
- UpdateRecordedRegion();
+ has_any_recordings_ = true;
+ DCHECK(CanRasterSlowTileCheck(recorded_viewport_));
return true;
}
diff --git a/chromium/cc/resources/picture_pile.h b/chromium/cc/resources/picture_pile.h
index 7860e7f831f..86ef32f2182 100644
--- a/chromium/cc/resources/picture_pile.h
+++ b/chromium/cc/resources/picture_pile.h
@@ -18,21 +18,21 @@ class CC_EXPORT PicturePile : public PicturePileBase {
PicturePile();
// Re-record parts of the picture that are invalid.
- // Invalidations are in layer space.
+ // Invalidations are in layer space, and will be expanded to cover everything
+ // that was either recorded/changed or that has no recording, leaving out only
+ // pieces that we had a recording for and it was not changed.
// Return true iff the pile was modified.
- bool Update(
+ bool UpdateAndExpandInvalidation(
ContentLayerClient* painter,
+ Region* invalidation,
SkColor background_color,
bool contents_opaque,
- const Region& invalidation,
- gfx::Rect visible_layer_rect,
+ bool contents_fill_bounds_completely,
+ const gfx::Rect& visible_layer_rect,
int frame_number,
+ Picture::RecordingMode recording_mode,
RenderingStatsInstrumentation* stats_instrumentation);
- void set_num_raster_threads(int num_raster_threads) {
- num_raster_threads_ = num_raster_threads;
- }
-
void set_slow_down_raster_scale_factor(int factor) {
slow_down_raster_scale_factor_for_debug_ = factor;
}
@@ -41,12 +41,21 @@ class CC_EXPORT PicturePile : public PicturePileBase {
show_debug_picture_borders_ = show;
}
+ bool is_suitable_for_gpu_rasterization() const {
+ return is_suitable_for_gpu_rasterization_;
+ }
+ void SetUnsuitableForGpuRasterizationForTesting() {
+ is_suitable_for_gpu_rasterization_ = false;
+ }
+
protected:
virtual ~PicturePile();
private:
friend class PicturePileImpl;
+ bool is_suitable_for_gpu_rasterization_;
+
DISALLOW_COPY_AND_ASSIGN(PicturePile);
};
diff --git a/chromium/cc/resources/picture_pile_base.cc b/chromium/cc/resources/picture_pile_base.cc
index 7d60dcafc6b..8f8bf534874 100644
--- a/chromium/cc/resources/picture_pile_base.cc
+++ b/chromium/cc/resources/picture_pile_base.cc
@@ -43,9 +43,10 @@ PicturePileBase::PicturePileBase()
background_color_(SkColorSetARGBInline(0, 0, 0, 0)),
slow_down_raster_scale_factor_for_debug_(0),
contents_opaque_(false),
+ contents_fill_bounds_completely_(false),
show_debug_picture_borders_(false),
clear_canvas_with_debug_color_(kDefaultClearCanvasSetting),
- num_raster_threads_(0) {
+ has_any_recordings_(false) {
tiling_.SetMaxTextureSize(gfx::Size(kBasePictureSize, kBasePictureSize));
tile_grid_info_.fTileInterval.setEmpty();
tile_grid_info_.fMargin.setEmpty();
@@ -55,31 +56,32 @@ PicturePileBase::PicturePileBase()
PicturePileBase::PicturePileBase(const PicturePileBase* other)
: picture_map_(other->picture_map_),
tiling_(other->tiling_),
- recorded_region_(other->recorded_region_),
+ recorded_viewport_(other->recorded_viewport_),
min_contents_scale_(other->min_contents_scale_),
tile_grid_info_(other->tile_grid_info_),
background_color_(other->background_color_),
slow_down_raster_scale_factor_for_debug_(
other->slow_down_raster_scale_factor_for_debug_),
contents_opaque_(other->contents_opaque_),
+ contents_fill_bounds_completely_(other->contents_fill_bounds_completely_),
show_debug_picture_borders_(other->show_debug_picture_borders_),
clear_canvas_with_debug_color_(other->clear_canvas_with_debug_color_),
- num_raster_threads_(other->num_raster_threads_) {
-}
+ has_any_recordings_(other->has_any_recordings_) {}
-PicturePileBase::PicturePileBase(
- const PicturePileBase* other, unsigned thread_index)
+PicturePileBase::PicturePileBase(const PicturePileBase* other,
+ unsigned thread_index)
: tiling_(other->tiling_),
- recorded_region_(other->recorded_region_),
+ recorded_viewport_(other->recorded_viewport_),
min_contents_scale_(other->min_contents_scale_),
tile_grid_info_(other->tile_grid_info_),
background_color_(other->background_color_),
slow_down_raster_scale_factor_for_debug_(
other->slow_down_raster_scale_factor_for_debug_),
contents_opaque_(other->contents_opaque_),
+ contents_fill_bounds_completely_(other->contents_fill_bounds_completely_),
show_debug_picture_borders_(other->show_debug_picture_borders_),
clear_canvas_with_debug_color_(other->clear_canvas_with_debug_color_),
- num_raster_threads_(other->num_raster_threads_) {
+ has_any_recordings_(other->has_any_recordings_) {
for (PictureMap::const_iterator it = other->picture_map_.begin();
it != other->picture_map_.end();
++it) {
@@ -90,25 +92,37 @@ PicturePileBase::PicturePileBase(
PicturePileBase::~PicturePileBase() {
}
-void PicturePileBase::Resize(gfx::Size new_size) {
- if (size() == new_size)
+void PicturePileBase::SetTilingRect(const gfx::Rect& new_tiling_rect) {
+ if (tiling_rect() == new_tiling_rect)
return;
- gfx::Size old_size = size();
- tiling_.SetTotalSize(new_size);
+ gfx::Rect old_tiling_rect = tiling_rect();
+ tiling_.SetTilingRect(new_tiling_rect);
+
+ has_any_recordings_ = false;
+
+ // Don't waste time in Resize figuring out what these hints should be.
+ recorded_viewport_ = gfx::Rect();
+
+ if (new_tiling_rect.origin() != old_tiling_rect.origin()) {
+ picture_map_.clear();
+ return;
+ }
- // Find all tiles that contain any pixels outside the new size.
+ // Find all tiles that contain any pixels outside the new rect.
std::vector<PictureMapKey> to_erase;
int min_toss_x = tiling_.FirstBorderTileXIndexFromSrcCoord(
- std::min(old_size.width(), new_size.width()));
+ std::min(old_tiling_rect.right(), new_tiling_rect.right()));
int min_toss_y = tiling_.FirstBorderTileYIndexFromSrcCoord(
- std::min(old_size.height(), new_size.height()));
+ std::min(old_tiling_rect.bottom(), new_tiling_rect.bottom()));
for (PictureMap::const_iterator it = picture_map_.begin();
it != picture_map_.end();
++it) {
const PictureMapKey& key = it->first;
- if (key.first < min_toss_x && key.second < min_toss_y)
+ if (key.first < min_toss_x && key.second < min_toss_y) {
+ has_any_recordings_ |= !!it->second.GetPicture();
continue;
+ }
to_erase.push_back(key);
}
@@ -139,8 +153,8 @@ void PicturePileBase::SetMinContentsScale(float min_contents_scale) {
// static
void PicturePileBase::ComputeTileGridInfo(
- gfx::Size tile_grid_size,
- SkTileGridPicture::TileGridInfo* info) {
+ const gfx::Size& tile_grid_size,
+ SkTileGridFactory::TileGridInfo* info) {
DCHECK(info);
info->fTileInterval.set(tile_grid_size.width() - 2 * kTileGridBorderPixels,
tile_grid_size.height() - 2 * kTileGridBorderPixels);
@@ -153,7 +167,7 @@ void PicturePileBase::ComputeTileGridInfo(
info->fOffset.set(-kTileGridBorderPixels, -kTileGridBorderPixels);
}
-void PicturePileBase::SetTileGridSize(gfx::Size tile_grid_size) {
+void PicturePileBase::SetTileGridSize(const gfx::Size& tile_grid_size) {
ComputeTileGridInfo(tile_grid_size, &tile_grid_info_);
}
@@ -167,18 +181,7 @@ void PicturePileBase::SetBufferPixels(int new_buffer_pixels) {
void PicturePileBase::Clear() {
picture_map_.clear();
-}
-
-void PicturePileBase::UpdateRecordedRegion() {
- recorded_region_.Clear();
- for (PictureMap::const_iterator it = picture_map_.begin();
- it != picture_map_.end();
- ++it) {
- if (it->second.GetPicture()) {
- const PictureMapKey& key = it->first;
- recorded_region_.Union(tile_bounds(key.first, key.second));
- }
- }
+ recorded_viewport_ = gfx::Rect();
}
bool PicturePileBase::HasRecordingAt(int x, int y) {
@@ -188,13 +191,37 @@ bool PicturePileBase::HasRecordingAt(int x, int y) {
return !!found->second.GetPicture();
}
-bool PicturePileBase::CanRaster(float contents_scale, gfx::Rect content_rect) {
- if (tiling_.total_size().IsEmpty())
+bool PicturePileBase::CanRaster(float contents_scale,
+ const gfx::Rect& content_rect) {
+ if (tiling_.tiling_rect().IsEmpty())
return false;
gfx::Rect layer_rect = gfx::ScaleToEnclosingRect(
content_rect, 1.f / contents_scale);
- layer_rect.Intersect(gfx::Rect(tiling_.total_size()));
- return recorded_region_.Contains(layer_rect);
+ layer_rect.Intersect(tiling_.tiling_rect());
+
+ // Common case inside of viewport to avoid the slower map lookups.
+ if (recorded_viewport_.Contains(layer_rect)) {
+ // Sanity check that there are no false positives in recorded_viewport_.
+ DCHECK(CanRasterSlowTileCheck(layer_rect));
+ return true;
+ }
+
+ return CanRasterSlowTileCheck(layer_rect);
+}
+
+bool PicturePileBase::CanRasterSlowTileCheck(
+ const gfx::Rect& layer_rect) const {
+ bool include_borders = false;
+ for (TilingData::Iterator tile_iter(&tiling_, layer_rect, include_borders);
+ tile_iter;
+ ++tile_iter) {
+ PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index());
+ if (map_iter == picture_map_.end())
+ return false;
+ if (!map_iter->second.GetPicture())
+ return false;
+ }
+ return true;
}
gfx::Rect PicturePileBase::PaddedRect(const PictureMapKey& key) {
@@ -202,7 +229,7 @@ gfx::Rect PicturePileBase::PaddedRect(const PictureMapKey& key) {
return PadRect(tile);
}
-gfx::Rect PicturePileBase::PadRect(gfx::Rect rect) {
+gfx::Rect PicturePileBase::PadRect(const gfx::Rect& rect) {
gfx::Rect padded_rect = rect;
padded_rect.Inset(
-buffer_pixels(), -buffer_pixels(), -buffer_pixels(), -buffer_pixels());
@@ -211,10 +238,12 @@ gfx::Rect PicturePileBase::PadRect(gfx::Rect rect) {
scoped_ptr<base::Value> PicturePileBase::AsValue() const {
scoped_ptr<base::ListValue> pictures(new base::ListValue());
- gfx::Rect layer_rect(tiling_.total_size());
+ gfx::Rect tiling_rect(tiling_.tiling_rect());
std::set<void*> appended_pictures;
- for (TilingData::Iterator tile_iter(&tiling_, layer_rect);
- tile_iter; ++tile_iter) {
+ bool include_borders = true;
+ for (TilingData::Iterator tile_iter(&tiling_, tiling_rect, include_borders);
+ tile_iter;
+ ++tile_iter) {
PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index());
if (map_iter == picture_map_.end())
continue;
diff --git a/chromium/cc/resources/picture_pile_base.h b/chromium/cc/resources/picture_pile_base.h
index 274c865ad3f..9f8acffd294 100644
--- a/chromium/cc/resources/picture_pile_base.h
+++ b/chromium/cc/resources/picture_pile_base.h
@@ -29,23 +29,28 @@ class CC_EXPORT PicturePileBase : public base::RefCounted<PicturePileBase> {
explicit PicturePileBase(const PicturePileBase* other);
PicturePileBase(const PicturePileBase* other, unsigned thread_index);
- void Resize(gfx::Size size);
- gfx::Size size() const { return tiling_.total_size(); }
+ void SetTilingRect(const gfx::Rect& tiling_rect);
+ gfx::Rect tiling_rect() const { return tiling_.tiling_rect(); }
void SetMinContentsScale(float min_contents_scale);
- void UpdateRecordedRegion();
- const Region& recorded_region() const { return recorded_region_; }
+ // If non-empty, all pictures tiles inside this rect are recorded. There may
+ // be recordings outside this rect, but everything inside the rect is
+ // recorded.
+ gfx::Rect recorded_viewport() const { return recorded_viewport_; }
int num_tiles_x() const { return tiling_.num_tiles_x(); }
int num_tiles_y() const { return tiling_.num_tiles_y(); }
gfx::Rect tile_bounds(int x, int y) const { return tiling_.TileBounds(x, y); }
bool HasRecordingAt(int x, int y);
- bool CanRaster(float contents_scale, gfx::Rect content_rect);
+ bool CanRaster(float contents_scale, const gfx::Rect& content_rect);
- static void ComputeTileGridInfo(gfx::Size tile_grid_size,
- SkTileGridPicture::TileGridInfo* info);
+ // If this pile contains any valid recordings. May have false positives.
+ bool HasRecordings() const { return has_any_recordings_; }
- void SetTileGridSize(gfx::Size tile_grid_size);
+ static void ComputeTileGridInfo(const gfx::Size& tile_grid_size,
+ SkTileGridFactory::TileGridInfo* info);
+
+ void SetTileGridSize(const gfx::Size& tile_grid_size);
TilingData& tiling() { return tiling_; }
scoped_ptr<base::Value> AsValue() const;
@@ -84,30 +89,32 @@ class CC_EXPORT PicturePileBase : public base::RefCounted<PicturePileBase> {
virtual ~PicturePileBase();
- void SetRecordedRegionForTesting(const Region& recorded_region) {
- recorded_region_ = recorded_region;
- }
-
- int num_raster_threads() { return num_raster_threads_; }
int buffer_pixels() const { return tiling_.border_texels(); }
void Clear();
gfx::Rect PaddedRect(const PictureMapKey& key);
- gfx::Rect PadRect(gfx::Rect rect);
+ gfx::Rect PadRect(const gfx::Rect& rect);
+
+ // An internal CanRaster check that goes to the picture_map rather than
+ // using the recorded_viewport hint.
+ bool CanRasterSlowTileCheck(const gfx::Rect& layer_rect) const;
// A picture pile is a tiled set of pictures. The picture map is a map of tile
// indices to picture infos.
PictureMap picture_map_;
TilingData tiling_;
- Region recorded_region_;
+ gfx::Rect recorded_viewport_;
float min_contents_scale_;
- SkTileGridPicture::TileGridInfo tile_grid_info_;
+ SkTileGridFactory::TileGridInfo tile_grid_info_;
SkColor background_color_;
int slow_down_raster_scale_factor_for_debug_;
bool contents_opaque_;
+ bool contents_fill_bounds_completely_;
bool show_debug_picture_borders_;
bool clear_canvas_with_debug_color_;
- int num_raster_threads_;
+ // A hint about whether there are any recordings. This may be a false
+ // positive.
+ bool has_any_recordings_;
private:
void SetBufferPixels(int buffer_pixels);
diff --git a/chromium/cc/resources/picture_pile_impl.cc b/chromium/cc/resources/picture_pile_impl.cc
index b6f4d77156f..90713b4fc7e 100644
--- a/chromium/cc/resources/picture_pile_impl.cc
+++ b/chromium/cc/resources/picture_pile_impl.cc
@@ -9,8 +9,10 @@
#include "cc/base/region.h"
#include "cc/debug/debug_colors.h"
#include "cc/resources/picture_pile_impl.h"
+#include "cc/resources/raster_worker_pool.h"
#include "skia/ext/analysis_canvas.h"
#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkPictureRecorder.h"
#include "third_party/skia/include/core/SkSize.h"
#include "ui/gfx/rect_conversions.h"
#include "ui/gfx/size_conversions.h"
@@ -50,7 +52,8 @@ PicturePileImpl::PicturePileImpl()
PicturePileImpl::PicturePileImpl(const PicturePileBase* other)
: PicturePileBase(other),
- clones_for_drawing_(ClonesForDrawing(this, num_raster_threads())) {
+ clones_for_drawing_(ClonesForDrawing(
+ this, RasterWorkerPool::GetNumRasterThreads())) {
}
PicturePileImpl::PicturePileImpl(
@@ -70,7 +73,7 @@ PicturePileImpl* PicturePileImpl::GetCloneForDrawingOnThread(
void PicturePileImpl::RasterDirect(
SkCanvas* canvas,
- gfx::Rect canvas_rect,
+ const gfx::Rect& canvas_rect,
float contents_scale,
RenderingStatsInstrumentation* rendering_stats_instrumentation) {
RasterCommon(canvas,
@@ -83,7 +86,7 @@ void PicturePileImpl::RasterDirect(
void PicturePileImpl::RasterForAnalysis(
skia::AnalysisCanvas* canvas,
- gfx::Rect canvas_rect,
+ const gfx::Rect& canvas_rect,
float contents_scale,
RenderingStatsInstrumentation* stats_instrumentation) {
RasterCommon(
@@ -92,49 +95,64 @@ void PicturePileImpl::RasterForAnalysis(
void PicturePileImpl::RasterToBitmap(
SkCanvas* canvas,
- gfx::Rect canvas_rect,
+ const gfx::Rect& canvas_rect,
float contents_scale,
RenderingStatsInstrumentation* rendering_stats_instrumentation) {
+ canvas->discard();
if (clear_canvas_with_debug_color_) {
- // Any non-painted areas will be left in this color.
+ // Any non-painted areas in the content bounds will be left in this color.
canvas->clear(DebugColors::NonPaintedFillColor());
}
// If this picture has opaque contents, it is guaranteeing that it will
// draw an opaque rect the size of the layer. If it is not, then we must
// clear this canvas ourselves.
- if (!contents_opaque_) {
- // Clearing is about ~4x faster than drawing a rect even if the content
- // isn't covering a majority of the canvas.
- canvas->clear(SK_ColorTRANSPARENT);
- } else {
- // Even if it is opaque, on any rasterizations that touch the edge of the
+ if (contents_opaque_ || contents_fill_bounds_completely_) {
+ // Even if completely covered, for rasterizations that touch the edge of the
// layer, we also need to raster the background color underneath the last
// texel (since the recording won't cover it) and outside the last texel
// (due to linear filtering when using this texture).
- gfx::SizeF total_content_size = gfx::ScaleSize(tiling_.total_size(),
- contents_scale);
- gfx::Rect content_rect(gfx::ToCeiledSize(total_content_size));
+ gfx::Rect content_tiling_rect = gfx::ToEnclosingRect(
+ gfx::ScaleRect(tiling_.tiling_rect(), contents_scale));
// The final texel of content may only be partially covered by a
// rasterization; this rect represents the content rect that is fully
// covered by content.
- gfx::Rect deflated_content_rect = content_rect;
- deflated_content_rect.Inset(0, 0, 1, 1);
- if (!deflated_content_rect.Contains(canvas_rect)) {
+ gfx::Rect deflated_content_tiling_rect = content_tiling_rect;
+ deflated_content_tiling_rect.Inset(0, 0, 1, 1);
+ if (!deflated_content_tiling_rect.Contains(canvas_rect)) {
+ if (clear_canvas_with_debug_color_) {
+ // Any non-painted areas outside of the content bounds are left in
+ // this color. If this is seen then it means that cc neglected to
+ // rerasterize a tile that used to intersect with the content rect
+ // after the content bounds grew.
+ canvas->save();
+ canvas->translate(-canvas_rect.x(), -canvas_rect.y());
+ canvas->clipRect(gfx::RectToSkRect(content_tiling_rect),
+ SkRegion::kDifference_Op);
+ canvas->drawColor(DebugColors::MissingResizeInvalidations(),
+ SkXfermode::kSrc_Mode);
+ canvas->restore();
+ }
+
// Drawing at most 2 x 2 x (canvas width + canvas height) texels is 2-3X
// faster than clearing, so special case this.
canvas->save();
canvas->translate(-canvas_rect.x(), -canvas_rect.y());
- gfx::Rect inflated_content_rect = content_rect;
- inflated_content_rect.Inset(0, 0, -1, -1);
- canvas->clipRect(gfx::RectToSkRect(inflated_content_rect),
+ gfx::Rect inflated_content_tiling_rect = content_tiling_rect;
+ inflated_content_tiling_rect.Inset(0, 0, -1, -1);
+ canvas->clipRect(gfx::RectToSkRect(inflated_content_tiling_rect),
SkRegion::kReplace_Op);
- canvas->clipRect(gfx::RectToSkRect(deflated_content_rect),
+ canvas->clipRect(gfx::RectToSkRect(deflated_content_tiling_rect),
SkRegion::kDifference_Op);
canvas->drawColor(background_color_, SkXfermode::kSrc_Mode);
canvas->restore();
}
+ } else {
+ TRACE_EVENT_INSTANT0("cc", "SkCanvas::clear", TRACE_EVENT_SCOPE_THREAD);
+ // Clearing is about ~4x faster than drawing a rect even if the content
+ // isn't covering a majority of the canvas.
+ canvas->clear(SK_ColorTRANSPARENT);
}
RasterCommon(canvas,
@@ -145,8 +163,8 @@ void PicturePileImpl::RasterToBitmap(
false);
}
-void PicturePileImpl::CoalesceRasters(gfx::Rect canvas_rect,
- gfx::Rect content_rect,
+void PicturePileImpl::CoalesceRasters(const gfx::Rect& canvas_rect,
+ const gfx::Rect& content_rect,
float contents_scale,
PictureRegionMap* results) {
DCHECK(results);
@@ -154,6 +172,13 @@ void PicturePileImpl::CoalesceRasters(gfx::Rect canvas_rect,
gfx::Rect layer_rect = gfx::ScaleToEnclosingRect(
content_rect, 1.f / contents_scale);
+ // Make sure pictures don't overlap by keeping track of previous right/bottom.
+ int min_content_left = -1;
+ int min_content_top = -1;
+ int last_row_index = -1;
+ int last_col_index = -1;
+ gfx::Rect last_content_rect;
+
// Coalesce rasters of the same picture into different rects:
// - Compute the clip of each of the pile chunks,
// - Subtract it from the canvas rect to get difference region
@@ -168,8 +193,10 @@ void PicturePileImpl::CoalesceRasters(gfx::Rect canvas_rect,
// that and subtract chunk rects to get the region that we need to subtract
// from the canvas. Then, we can use clipRect with difference op to subtract
// each rect in the region.
- for (TilingData::Iterator tile_iter(&tiling_, layer_rect);
- tile_iter; ++tile_iter) {
+ bool include_borders = true;
+ for (TilingData::Iterator tile_iter(&tiling_, layer_rect, include_borders);
+ tile_iter;
+ ++tile_iter) {
PictureMap::iterator map_iter = picture_map_.find(tile_iter.index());
if (map_iter == picture_map_.end())
continue;
@@ -191,41 +218,66 @@ void PicturePileImpl::CoalesceRasters(gfx::Rect canvas_rect,
<< "Contents scale: " << contents_scale;
content_clip.Intersect(canvas_rect);
+ // Make sure iterator goes top->bottom.
+ DCHECK_GE(tile_iter.index_y(), last_row_index);
+ if (tile_iter.index_y() > last_row_index) {
+ // First tile in a new row.
+ min_content_left = content_clip.x();
+ min_content_top = last_content_rect.bottom();
+ } else {
+ // Make sure iterator goes left->right.
+ DCHECK_GT(tile_iter.index_x(), last_col_index);
+ min_content_left = last_content_rect.right();
+ min_content_top = last_content_rect.y();
+ }
+
+ last_col_index = tile_iter.index_x();
+ last_row_index = tile_iter.index_y();
+
+ // Only inset if the content_clip is less than then previous min.
+ int inset_left = std::max(0, min_content_left - content_clip.x());
+ int inset_top = std::max(0, min_content_top - content_clip.y());
+ content_clip.Inset(inset_left, inset_top, 0, 0);
+
PictureRegionMap::iterator it = results->find(picture);
+ Region* clip_region;
if (it == results->end()) {
- Region& region = (*results)[picture];
- region = content_rect;
- region.Subtract(content_clip);
- continue;
+ // The clip for a set of coalesced pictures starts out clipping the entire
+ // canvas. Each picture added to the set must subtract its own bounds
+ // from the clip region, poking a hole so that the picture is unclipped.
+ clip_region = &(*results)[picture];
+ *clip_region = canvas_rect;
+ } else {
+ clip_region = &it->second;
}
- Region& region = it->second;
- region.Subtract(content_clip);
+ DCHECK(clip_region->Contains(content_clip))
+ << "Content clips should not overlap.";
+ clip_region->Subtract(content_clip);
+ last_content_rect = content_clip;
}
}
void PicturePileImpl::RasterCommon(
SkCanvas* canvas,
SkDrawPictureCallback* callback,
- gfx::Rect canvas_rect,
+ const gfx::Rect& canvas_rect,
float contents_scale,
RenderingStatsInstrumentation* rendering_stats_instrumentation,
bool is_analysis) {
DCHECK(contents_scale >= min_contents_scale_);
canvas->translate(-canvas_rect.x(), -canvas_rect.y());
- gfx::SizeF total_content_size = gfx::ScaleSize(tiling_.total_size(),
- contents_scale);
- gfx::Rect total_content_rect(gfx::ToCeiledSize(total_content_size));
- gfx::Rect content_rect = total_content_rect;
- content_rect.Intersect(canvas_rect);
+ gfx::Rect content_tiling_rect = gfx::ToEnclosingRect(
+ gfx::ScaleRect(tiling_.tiling_rect(), contents_scale));
+ content_tiling_rect.Intersect(canvas_rect);
- canvas->clipRect(gfx::RectToSkRect(content_rect),
+ canvas->clipRect(gfx::RectToSkRect(content_tiling_rect),
SkRegion::kIntersect_Op);
PictureRegionMap picture_region_map;
CoalesceRasters(
- canvas_rect, content_rect, contents_scale, &picture_region_map);
+ canvas_rect, content_tiling_rect, contents_scale, &picture_region_map);
#ifndef NDEBUG
Region total_clip;
@@ -240,13 +292,14 @@ void PicturePileImpl::RasterCommon(
Region negated_clip_region = it->second;
#ifndef NDEBUG
- Region positive_clip = content_rect;
+ Region positive_clip = content_tiling_rect;
positive_clip.Subtract(negated_clip_region);
+ // Make sure we never rasterize the same region twice.
+ DCHECK(!total_clip.Intersects(positive_clip));
total_clip.Union(positive_clip);
#endif // NDEBUG
- base::TimeDelta best_duration =
- base::TimeDelta::FromInternalValue(std::numeric_limits<int64>::max());
+ base::TimeDelta best_duration = base::TimeDelta::Max();
int repeat_count = std::max(1, slow_down_raster_scale_factor_for_debug_);
int rasterized_pixel_count = 0;
@@ -292,31 +345,26 @@ void PicturePileImpl::RasterCommon(
skia::RefPtr<SkPicture> PicturePileImpl::GetFlattenedPicture() {
TRACE_EVENT0("cc", "PicturePileImpl::GetFlattenedPicture");
- gfx::Rect layer_rect(tiling_.total_size());
- skia::RefPtr<SkPicture> picture = skia::AdoptRef(new SkPicture);
- if (layer_rect.IsEmpty())
- return picture;
-
- SkCanvas* canvas = picture->beginRecording(
- layer_rect.width(),
- layer_rect.height(),
- SkPicture::kUsePathBoundsForClip_RecordingFlag);
-
- RasterToBitmap(canvas, layer_rect, 1.0, NULL);
- picture->endRecording();
+ gfx::Rect tiling_rect(tiling_.tiling_rect());
+ SkPictureRecorder recorder;
+ SkCanvas* canvas =
+ recorder.beginRecording(tiling_rect.width(), tiling_rect.height());
+ if (!tiling_rect.IsEmpty())
+ RasterToBitmap(canvas, tiling_rect, 1.0, NULL);
+ skia::RefPtr<SkPicture> picture = skia::AdoptRef(recorder.endRecording());
return picture;
}
void PicturePileImpl::AnalyzeInRect(
- gfx::Rect content_rect,
+ const gfx::Rect& content_rect,
float contents_scale,
PicturePileImpl::Analysis* analysis) {
AnalyzeInRect(content_rect, contents_scale, analysis, NULL);
}
void PicturePileImpl::AnalyzeInRect(
- gfx::Rect content_rect,
+ const gfx::Rect& content_rect,
float contents_scale,
PicturePileImpl::Analysis* analysis,
RenderingStatsInstrumentation* stats_instrumentation) {
@@ -326,37 +374,35 @@ void PicturePileImpl::AnalyzeInRect(
gfx::Rect layer_rect = gfx::ScaleToEnclosingRect(
content_rect, 1.0f / contents_scale);
- layer_rect.Intersect(gfx::Rect(tiling_.total_size()));
+ layer_rect.Intersect(tiling_.tiling_rect());
- SkBitmap empty_bitmap;
- empty_bitmap.setConfig(SkBitmap::kNo_Config,
- layer_rect.width(),
- layer_rect.height());
- skia::AnalysisDevice device(empty_bitmap);
- skia::AnalysisCanvas canvas(&device);
+ skia::AnalysisCanvas canvas(layer_rect.width(), layer_rect.height());
RasterForAnalysis(&canvas, layer_rect, 1.0f, stats_instrumentation);
analysis->is_solid_color = canvas.GetColorIfSolid(&analysis->solid_color);
- analysis->has_text = canvas.HasText();
}
-PicturePileImpl::Analysis::Analysis()
- : is_solid_color(false),
- has_text(false) {
+// Since there are situations when we can skip analysis, the variables have to
+// be set to their safest values. That is, we have to assume that the tile is
+// not solid color. As well, we have to assume that the tile has text so we
+// don't early out incorrectly.
+PicturePileImpl::Analysis::Analysis() : is_solid_color(false) {
}
PicturePileImpl::Analysis::~Analysis() {
}
PicturePileImpl::PixelRefIterator::PixelRefIterator(
- gfx::Rect content_rect,
+ const gfx::Rect& content_rect,
float contents_scale,
const PicturePileImpl* picture_pile)
: picture_pile_(picture_pile),
- layer_rect_(gfx::ScaleToEnclosingRect(
- content_rect, 1.f / contents_scale)),
- tile_iterator_(&picture_pile_->tiling_, layer_rect_) {
+ layer_rect_(
+ gfx::ScaleToEnclosingRect(content_rect, 1.f / contents_scale)),
+ tile_iterator_(&picture_pile_->tiling_,
+ layer_rect_,
+ false /* include_borders */) {
// Early out if there isn't a single tile.
if (!tile_iterator_)
return;
@@ -398,7 +444,6 @@ void PicturePileImpl::PixelRefIterator::AdvanceToTilePictureWithPixelRefs() {
}
void PicturePileImpl::DidBeginTracing() {
- gfx::Rect layer_rect(tiling_.total_size());
std::set<void*> processed_pictures;
for (PictureMap::iterator it = picture_map_.begin();
it != picture_map_.end();
diff --git a/chromium/cc/resources/picture_pile_impl.h b/chromium/cc/resources/picture_pile_impl.h
index 180dba258ee..ba193811075 100644
--- a/chromium/cc/resources/picture_pile_impl.h
+++ b/chromium/cc/resources/picture_pile_impl.h
@@ -39,16 +39,17 @@ class CC_EXPORT PicturePileImpl : public PicturePileBase {
// measured value over all runs.
void RasterDirect(
SkCanvas* canvas,
- gfx::Rect canvas_rect,
+ const gfx::Rect& canvas_rect,
float contents_scale,
RenderingStatsInstrumentation* rendering_stats_instrumentation);
// Similar to the above RasterDirect method, but this is a convenience method
// for when it is known that the raster is going to an intermediate bitmap
// that itself will then be blended and thus that a canvas clear is required.
+ // Note that this function may write outside the canvas_rect.
void RasterToBitmap(
SkCanvas* canvas,
- gfx::Rect canvas_rect,
+ const gfx::Rect& canvas_rect,
float contents_scale,
RenderingStatsInstrumentation* stats_instrumentation);
@@ -56,7 +57,7 @@ class CC_EXPORT PicturePileImpl : public PicturePileBase {
// SkDrawPictureCallback, which allows us to early out from analysis.
void RasterForAnalysis(
skia::AnalysisCanvas* canvas,
- gfx::Rect canvas_rect,
+ const gfx::Rect& canvas_rect,
float contents_scale,
RenderingStatsInstrumentation* stats_instrumentation);
@@ -67,28 +68,27 @@ class CC_EXPORT PicturePileImpl : public PicturePileBase {
~Analysis();
bool is_solid_color;
- bool has_text;
SkColor solid_color;
};
- void AnalyzeInRect(gfx::Rect content_rect,
+ void AnalyzeInRect(const gfx::Rect& content_rect,
float contents_scale,
Analysis* analysis);
- void AnalyzeInRect(gfx::Rect content_rect,
+ void AnalyzeInRect(const gfx::Rect& content_rect,
float contents_scale,
Analysis* analysis,
RenderingStatsInstrumentation* stats_instrumentation);
class CC_EXPORT PixelRefIterator {
public:
- PixelRefIterator(gfx::Rect content_rect,
+ PixelRefIterator(const gfx::Rect& content_rect,
float contents_scale,
const PicturePileImpl* picture_pile);
~PixelRefIterator();
- skia::LazyPixelRef* operator->() const { return *pixel_ref_iterator_; }
- skia::LazyPixelRef* operator*() const { return *pixel_ref_iterator_; }
+ SkPixelRef* operator->() const { return *pixel_ref_iterator_; }
+ SkPixelRef* operator*() const { return *pixel_ref_iterator_; }
PixelRefIterator& operator++();
operator bool() const { return pixel_ref_iterator_; }
@@ -129,15 +129,15 @@ class CC_EXPORT PicturePileImpl : public PicturePileBase {
private:
typedef std::map<Picture*, Region> PictureRegionMap;
- void CoalesceRasters(gfx::Rect canvas_rect,
- gfx::Rect content_rect,
+ void CoalesceRasters(const gfx::Rect& canvas_rect,
+ const gfx::Rect& content_rect,
float contents_scale,
PictureRegionMap* result);
void RasterCommon(
SkCanvas* canvas,
SkDrawPictureCallback* callback,
- gfx::Rect canvas_rect,
+ const gfx::Rect& canvas_rect,
float contents_scale,
RenderingStatsInstrumentation* rendering_stats_instrumentation,
bool is_analysis);
diff --git a/chromium/cc/resources/picture_pile_impl_perftest.cc b/chromium/cc/resources/picture_pile_impl_perftest.cc
new file mode 100644
index 00000000000..7ced0eaa1be
--- /dev/null
+++ b/chromium/cc/resources/picture_pile_impl_perftest.cc
@@ -0,0 +1,89 @@
+// 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/resources/picture_pile_impl.h"
+
+#include "cc/debug/lap_timer.h"
+#include "cc/test/fake_picture_pile_impl.h"
+#include "cc/test/fake_rendering_stats_instrumentation.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/perf/perf_test.h"
+
+namespace cc {
+namespace {
+
+const int kTimeLimitMillis = 2000;
+const int kWarmupRuns = 5;
+const int kTimeCheckInterval = 10;
+
+const int kTileSize = 100;
+const int kLayerSize = 1000;
+
+class PicturePileImplPerfTest : public testing::Test {
+ public:
+ PicturePileImplPerfTest()
+ : timer_(kWarmupRuns,
+ base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
+ kTimeCheckInterval) {}
+
+ void RunAnalyzeTest(const std::string& test_name, float contents_scale) {
+ scoped_refptr<PicturePileImpl> pile = FakePicturePileImpl::CreateFilledPile(
+ gfx::Size(kTileSize, kTileSize), gfx::Size(kLayerSize, kLayerSize));
+ // Content rect that will align with top-left tile at scale 1.0.
+ gfx::Rect content_rect(0, 0, kTileSize, kTileSize);
+
+ PicturePileImpl::Analysis analysis;
+ timer_.Reset();
+ do {
+ pile->AnalyzeInRect(content_rect, contents_scale, &analysis);
+ timer_.NextLap();
+ } while (!timer_.HasTimeLimitExpired());
+
+ perf_test::PrintResult(
+ "analyze", "", test_name, timer_.LapsPerSecond(), "runs/s", true);
+ }
+
+ void RunRasterTest(const std::string& test_name, float contents_scale) {
+ scoped_refptr<PicturePileImpl> pile = FakePicturePileImpl::CreateFilledPile(
+ gfx::Size(kTileSize, kTileSize), gfx::Size(kLayerSize, kLayerSize));
+ // Content rect that will align with top-left tile at scale 1.0.
+ gfx::Rect content_rect(0, 0, kTileSize, kTileSize);
+
+ SkBitmap bitmap;
+ bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1, 1);
+ bitmap.allocPixels();
+ SkCanvas canvas(bitmap);
+
+ FakeRenderingStatsInstrumentation rendering_stats_instrumentation;
+ timer_.Reset();
+ do {
+ pile->RasterToBitmap(&canvas,
+ content_rect,
+ contents_scale,
+ &rendering_stats_instrumentation);
+ timer_.NextLap();
+ } while (!timer_.HasTimeLimitExpired());
+
+ perf_test::PrintResult(
+ "raster", "", test_name, timer_.LapsPerSecond(), "runs/s", true);
+ }
+
+ private:
+ LapTimer timer_;
+};
+
+TEST_F(PicturePileImplPerfTest, Analyze) {
+ RunAnalyzeTest("1", 1.0f);
+ RunAnalyzeTest("4", 0.5f);
+ RunAnalyzeTest("100", 0.1f);
+}
+
+TEST_F(PicturePileImplPerfTest, Raster) {
+ RunRasterTest("1", 1.0f);
+ RunRasterTest("4", 0.5f);
+ RunRasterTest("100", 0.1f);
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/resources/picture_pile_impl_unittest.cc b/chromium/cc/resources/picture_pile_impl_unittest.cc
index e5691e39301..40d1615a943 100644
--- a/chromium/cc/resources/picture_pile_impl_unittest.cc
+++ b/chromium/cc/resources/picture_pile_impl_unittest.cc
@@ -6,7 +6,6 @@
#include "cc/test/fake_picture_pile_impl.h"
#include "cc/test/fake_rendering_stats_instrumentation.h"
#include "cc/test/skia_common.h"
-#include "skia/ext/lazy_pixel_ref.h"
#include "skia/ext/refptr.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkPixelRef.h"
@@ -206,7 +205,7 @@ TEST(PicturePileImplTest, PixelRefIteratorEmpty) {
}
}
-TEST(PicturePileImplTest, PixelRefIteratorNoLazyRefs) {
+TEST(PicturePileImplTest, PixelRefIteratorNoDiscardableRefs) {
gfx::Size tile_size(128, 128);
gfx::Size layer_bounds(256, 256);
@@ -216,16 +215,16 @@ TEST(PicturePileImplTest, PixelRefIteratorNoLazyRefs) {
SkPaint simple_paint;
simple_paint.setColor(SkColorSetARGB(255, 12, 23, 34));
- SkBitmap non_lazy_bitmap;
- CreateBitmap(gfx::Size(128, 128), "notlazy", &non_lazy_bitmap);
+ SkBitmap non_discardable_bitmap;
+ CreateBitmap(gfx::Size(128, 128), "notdiscardable", &non_discardable_bitmap);
pile->add_draw_rect_with_paint(gfx::Rect(0, 0, 256, 256), simple_paint);
pile->add_draw_rect_with_paint(gfx::Rect(128, 128, 512, 512), simple_paint);
pile->add_draw_rect_with_paint(gfx::Rect(512, 0, 256, 256), simple_paint);
pile->add_draw_rect_with_paint(gfx::Rect(0, 512, 256, 256), simple_paint);
- pile->add_draw_bitmap(non_lazy_bitmap, gfx::Point(128, 0));
- pile->add_draw_bitmap(non_lazy_bitmap, gfx::Point(0, 128));
- pile->add_draw_bitmap(non_lazy_bitmap, gfx::Point(150, 150));
+ pile->add_draw_bitmap(non_discardable_bitmap, gfx::Point(128, 0));
+ pile->add_draw_bitmap(non_discardable_bitmap, gfx::Point(0, 128));
+ pile->add_draw_bitmap(non_discardable_bitmap, gfx::Point(150, 150));
pile->RerecordPile();
@@ -279,27 +278,27 @@ TEST(PicturePileImplTest, PixelRefIteratorNoLazyRefs) {
}
}
-TEST(PicturePileImplTest, PixelRefIteratorLazyRefs) {
+TEST(PicturePileImplTest, PixelRefIteratorDiscardableRefs) {
gfx::Size tile_size(128, 128);
gfx::Size layer_bounds(256, 256);
scoped_refptr<FakePicturePileImpl> pile =
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
- SkBitmap lazy_bitmap[2][2];
- CreateBitmap(gfx::Size(32, 32), "lazy", &lazy_bitmap[0][0]);
- CreateBitmap(gfx::Size(32, 32), "lazy", &lazy_bitmap[1][0]);
- CreateBitmap(gfx::Size(32, 32), "lazy", &lazy_bitmap[1][1]);
+ SkBitmap discardable_bitmap[2][2];
+ CreateBitmap(gfx::Size(32, 32), "discardable", &discardable_bitmap[0][0]);
+ CreateBitmap(gfx::Size(32, 32), "discardable", &discardable_bitmap[1][0]);
+ CreateBitmap(gfx::Size(32, 32), "discardable", &discardable_bitmap[1][1]);
- // Lazy pixel refs are found in the following cells:
+ // Discardable pixel refs are found in the following cells:
// |---|---|
// | x | |
// |---|---|
// | x | x |
// |---|---|
- pile->add_draw_bitmap(lazy_bitmap[0][0], gfx::Point(0, 0));
- pile->add_draw_bitmap(lazy_bitmap[1][0], gfx::Point(0, 130));
- pile->add_draw_bitmap(lazy_bitmap[1][1], gfx::Point(140, 140));
+ pile->add_draw_bitmap(discardable_bitmap[0][0], gfx::Point(0, 0));
+ pile->add_draw_bitmap(discardable_bitmap[1][0], gfx::Point(0, 130));
+ pile->add_draw_bitmap(discardable_bitmap[1][1], gfx::Point(140, 140));
pile->RerecordPile();
@@ -308,21 +307,21 @@ TEST(PicturePileImplTest, PixelRefIteratorLazyRefs) {
PicturePileImpl::PixelRefIterator iterator(
gfx::Rect(0, 0, 128, 128), 1.0, pile.get());
EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[0][0].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[0][0].pixelRef());
EXPECT_FALSE(++iterator);
}
{
PicturePileImpl::PixelRefIterator iterator(
gfx::Rect(0, 0, 256, 256), 2.0, pile.get());
EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[0][0].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[0][0].pixelRef());
EXPECT_FALSE(++iterator);
}
{
PicturePileImpl::PixelRefIterator iterator(
gfx::Rect(0, 0, 64, 64), 0.5, pile.get());
EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[0][0].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[0][0].pixelRef());
EXPECT_FALSE(++iterator);
}
// Shifted tile sized iterators. These should find only one pixel ref.
@@ -330,24 +329,24 @@ TEST(PicturePileImplTest, PixelRefIteratorLazyRefs) {
PicturePileImpl::PixelRefIterator iterator(
gfx::Rect(140, 140, 128, 128), 1.0, pile.get());
EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[1][1].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[1][1].pixelRef());
EXPECT_FALSE(++iterator);
}
{
PicturePileImpl::PixelRefIterator iterator(
gfx::Rect(280, 280, 256, 256), 2.0, pile.get());
EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[1][1].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[1][1].pixelRef());
EXPECT_FALSE(++iterator);
}
{
PicturePileImpl::PixelRefIterator iterator(
gfx::Rect(70, 70, 64, 64), 0.5, pile.get());
EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[1][1].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[1][1].pixelRef());
EXPECT_FALSE(++iterator);
}
- // Ensure there's no lazy pixel refs in the empty cell
+ // Ensure there's no discardable pixel refs in the empty cell
{
PicturePileImpl::PixelRefIterator iterator(
gfx::Rect(140, 0, 128, 128), 1.0, pile.get());
@@ -358,58 +357,58 @@ TEST(PicturePileImplTest, PixelRefIteratorLazyRefs) {
PicturePileImpl::PixelRefIterator iterator(
gfx::Rect(0, 0, 256, 256), 1.0, pile.get());
EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[0][0].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[0][0].pixelRef());
EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[1][0].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[1][0].pixelRef());
EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[1][1].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[1][1].pixelRef());
EXPECT_FALSE(++iterator);
}
{
PicturePileImpl::PixelRefIterator iterator(
gfx::Rect(0, 0, 512, 512), 2.0, pile.get());
EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[0][0].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[0][0].pixelRef());
EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[1][0].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[1][0].pixelRef());
EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[1][1].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[1][1].pixelRef());
EXPECT_FALSE(++iterator);
}
{
PicturePileImpl::PixelRefIterator iterator(
gfx::Rect(0, 0, 128, 128), 0.5, pile.get());
EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[0][0].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[0][0].pixelRef());
EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[1][0].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[1][0].pixelRef());
EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[1][1].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[1][1].pixelRef());
EXPECT_FALSE(++iterator);
}
}
-TEST(PicturePileImplTest, PixelRefIteratorLazyRefsOneTile) {
+TEST(PicturePileImplTest, PixelRefIteratorDiscardableRefsOneTile) {
gfx::Size tile_size(256, 256);
gfx::Size layer_bounds(512, 512);
scoped_refptr<FakePicturePileImpl> pile =
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
- SkBitmap lazy_bitmap[2][2];
- CreateBitmap(gfx::Size(32, 32), "lazy", &lazy_bitmap[0][0]);
- CreateBitmap(gfx::Size(32, 32), "lazy", &lazy_bitmap[0][1]);
- CreateBitmap(gfx::Size(32, 32), "lazy", &lazy_bitmap[1][1]);
+ SkBitmap discardable_bitmap[2][2];
+ CreateBitmap(gfx::Size(32, 32), "discardable", &discardable_bitmap[0][0]);
+ CreateBitmap(gfx::Size(32, 32), "discardable", &discardable_bitmap[0][1]);
+ CreateBitmap(gfx::Size(32, 32), "discardable", &discardable_bitmap[1][1]);
- // Lazy pixel refs are found in the following cells:
+ // Discardable pixel refs are found in the following cells:
// |---|---|
// | x | x |
// |---|---|
// | | x |
// |---|---|
- pile->add_draw_bitmap(lazy_bitmap[0][0], gfx::Point(0, 0));
- pile->add_draw_bitmap(lazy_bitmap[0][1], gfx::Point(260, 0));
- pile->add_draw_bitmap(lazy_bitmap[1][1], gfx::Point(260, 260));
+ pile->add_draw_bitmap(discardable_bitmap[0][0], gfx::Point(0, 0));
+ pile->add_draw_bitmap(discardable_bitmap[0][1], gfx::Point(260, 0));
+ pile->add_draw_bitmap(discardable_bitmap[1][1], gfx::Point(260, 260));
pile->RerecordPile();
@@ -418,21 +417,21 @@ TEST(PicturePileImplTest, PixelRefIteratorLazyRefsOneTile) {
PicturePileImpl::PixelRefIterator iterator(
gfx::Rect(0, 0, 256, 256), 1.0, pile.get());
EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[0][0].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[0][0].pixelRef());
EXPECT_FALSE(++iterator);
}
{
PicturePileImpl::PixelRefIterator iterator(
gfx::Rect(0, 0, 512, 512), 2.0, pile.get());
EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[0][0].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[0][0].pixelRef());
EXPECT_FALSE(++iterator);
}
{
PicturePileImpl::PixelRefIterator iterator(
gfx::Rect(0, 0, 128, 128), 0.5, pile.get());
EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[0][0].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[0][0].pixelRef());
EXPECT_FALSE(++iterator);
}
// Shifted tile sized iterators. These should find only one pixel ref.
@@ -440,24 +439,24 @@ TEST(PicturePileImplTest, PixelRefIteratorLazyRefsOneTile) {
PicturePileImpl::PixelRefIterator iterator(
gfx::Rect(260, 260, 256, 256), 1.0, pile.get());
EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[1][1].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[1][1].pixelRef());
EXPECT_FALSE(++iterator);
}
{
PicturePileImpl::PixelRefIterator iterator(
gfx::Rect(520, 520, 512, 512), 2.0, pile.get());
EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[1][1].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[1][1].pixelRef());
EXPECT_FALSE(++iterator);
}
{
PicturePileImpl::PixelRefIterator iterator(
gfx::Rect(130, 130, 128, 128), 0.5, pile.get());
EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[1][1].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[1][1].pixelRef());
EXPECT_FALSE(++iterator);
}
- // Ensure there's no lazy pixel refs in the empty cell
+ // Ensure there's no discardable pixel refs in the empty cell
{
PicturePileImpl::PixelRefIterator iterator(
gfx::Rect(0, 256, 256, 256), 1.0, pile.get());
@@ -468,33 +467,33 @@ TEST(PicturePileImplTest, PixelRefIteratorLazyRefsOneTile) {
PicturePileImpl::PixelRefIterator iterator(
gfx::Rect(0, 0, 512, 512), 1.0, pile.get());
EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[0][0].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[0][0].pixelRef());
EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[0][1].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[0][1].pixelRef());
EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[1][1].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[1][1].pixelRef());
EXPECT_FALSE(++iterator);
}
{
PicturePileImpl::PixelRefIterator iterator(
gfx::Rect(0, 0, 1024, 1024), 2.0, pile.get());
EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[0][0].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[0][0].pixelRef());
EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[0][1].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[0][1].pixelRef());
EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[1][1].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[1][1].pixelRef());
EXPECT_FALSE(++iterator);
}
{
PicturePileImpl::PixelRefIterator iterator(
gfx::Rect(0, 0, 256, 256), 0.5, pile.get());
EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[0][0].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[0][0].pixelRef());
EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[0][1].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[0][1].pixelRef());
EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[1][1].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[1][1].pixelRef());
EXPECT_FALSE(++iterator);
}
@@ -502,50 +501,50 @@ TEST(PicturePileImplTest, PixelRefIteratorLazyRefsOneTile) {
PicturePileImpl::PixelRefIterator iterator(
gfx::Rect(0, 0, 512, 512), 1.0, pile.get());
EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[0][0].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[0][0].pixelRef());
EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[0][1].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[0][1].pixelRef());
// copy now points to the same spot as iterator,
// but both can be incremented independently.
PicturePileImpl::PixelRefIterator copy = iterator;
EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[1][1].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[1][1].pixelRef());
EXPECT_FALSE(++iterator);
EXPECT_TRUE(copy);
- EXPECT_TRUE(*copy == lazy_bitmap[0][1].pixelRef());
+ EXPECT_TRUE(*copy == discardable_bitmap[0][1].pixelRef());
EXPECT_TRUE(++copy);
- EXPECT_TRUE(*copy == lazy_bitmap[1][1].pixelRef());
+ EXPECT_TRUE(*copy == discardable_bitmap[1][1].pixelRef());
EXPECT_FALSE(++copy);
}
-TEST(PicturePileImplTest, PixelRefIteratorLazyRefsBaseNonLazy) {
+TEST(PicturePileImplTest, PixelRefIteratorDiscardableRefsBaseNonDiscardable) {
gfx::Size tile_size(256, 256);
gfx::Size layer_bounds(512, 512);
scoped_refptr<FakePicturePileImpl> pile =
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
- SkBitmap non_lazy_bitmap;
- CreateBitmap(gfx::Size(512, 512), "notlazy", &non_lazy_bitmap);
+ SkBitmap non_discardable_bitmap;
+ CreateBitmap(gfx::Size(512, 512), "notdiscardable", &non_discardable_bitmap);
- SkBitmap lazy_bitmap[2][2];
- CreateBitmap(gfx::Size(128, 128), "lazy", &lazy_bitmap[0][0]);
- CreateBitmap(gfx::Size(128, 128), "lazy", &lazy_bitmap[0][1]);
- CreateBitmap(gfx::Size(128, 128), "lazy", &lazy_bitmap[1][1]);
+ SkBitmap discardable_bitmap[2][2];
+ CreateBitmap(gfx::Size(128, 128), "discardable", &discardable_bitmap[0][0]);
+ CreateBitmap(gfx::Size(128, 128), "discardable", &discardable_bitmap[0][1]);
+ CreateBitmap(gfx::Size(128, 128), "discardable", &discardable_bitmap[1][1]);
- // One large non-lazy bitmap covers the whole grid.
- // Lazy pixel refs are found in the following cells:
+ // One large non-discardable bitmap covers the whole grid.
+ // Discardable pixel refs are found in the following cells:
// |---|---|
// | x | x |
// |---|---|
// | | x |
// |---|---|
- pile->add_draw_bitmap(non_lazy_bitmap, gfx::Point(0, 0));
- pile->add_draw_bitmap(lazy_bitmap[0][0], gfx::Point(0, 0));
- pile->add_draw_bitmap(lazy_bitmap[0][1], gfx::Point(260, 0));
- pile->add_draw_bitmap(lazy_bitmap[1][1], gfx::Point(260, 260));
+ pile->add_draw_bitmap(non_discardable_bitmap, gfx::Point(0, 0));
+ pile->add_draw_bitmap(discardable_bitmap[0][0], gfx::Point(0, 0));
+ pile->add_draw_bitmap(discardable_bitmap[0][1], gfx::Point(260, 0));
+ pile->add_draw_bitmap(discardable_bitmap[1][1], gfx::Point(260, 260));
pile->RerecordPile();
@@ -554,21 +553,21 @@ TEST(PicturePileImplTest, PixelRefIteratorLazyRefsBaseNonLazy) {
PicturePileImpl::PixelRefIterator iterator(
gfx::Rect(0, 0, 256, 256), 1.0, pile.get());
EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[0][0].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[0][0].pixelRef());
EXPECT_FALSE(++iterator);
}
{
PicturePileImpl::PixelRefIterator iterator(
gfx::Rect(0, 0, 512, 512), 2.0, pile.get());
EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[0][0].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[0][0].pixelRef());
EXPECT_FALSE(++iterator);
}
{
PicturePileImpl::PixelRefIterator iterator(
gfx::Rect(0, 0, 128, 128), 0.5, pile.get());
EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[0][0].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[0][0].pixelRef());
EXPECT_FALSE(++iterator);
}
// Shifted tile sized iterators. These should find only one pixel ref.
@@ -576,24 +575,24 @@ TEST(PicturePileImplTest, PixelRefIteratorLazyRefsBaseNonLazy) {
PicturePileImpl::PixelRefIterator iterator(
gfx::Rect(260, 260, 256, 256), 1.0, pile.get());
EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[1][1].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[1][1].pixelRef());
EXPECT_FALSE(++iterator);
}
{
PicturePileImpl::PixelRefIterator iterator(
gfx::Rect(520, 520, 512, 512), 2.0, pile.get());
EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[1][1].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[1][1].pixelRef());
EXPECT_FALSE(++iterator);
}
{
PicturePileImpl::PixelRefIterator iterator(
gfx::Rect(130, 130, 128, 128), 0.5, pile.get());
EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[1][1].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[1][1].pixelRef());
EXPECT_FALSE(++iterator);
}
- // Ensure there's no lazy pixel refs in the empty cell
+ // Ensure there's no discardable pixel refs in the empty cell
{
PicturePileImpl::PixelRefIterator iterator(
gfx::Rect(0, 256, 256, 256), 1.0, pile.get());
@@ -604,42 +603,48 @@ TEST(PicturePileImplTest, PixelRefIteratorLazyRefsBaseNonLazy) {
PicturePileImpl::PixelRefIterator iterator(
gfx::Rect(0, 0, 512, 512), 1.0, pile.get());
EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[0][0].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[0][0].pixelRef());
EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[0][1].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[0][1].pixelRef());
EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[1][1].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[1][1].pixelRef());
EXPECT_FALSE(++iterator);
}
{
PicturePileImpl::PixelRefIterator iterator(
gfx::Rect(0, 0, 1024, 1024), 2.0, pile.get());
EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[0][0].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[0][0].pixelRef());
EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[0][1].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[0][1].pixelRef());
EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[1][1].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[1][1].pixelRef());
EXPECT_FALSE(++iterator);
}
{
PicturePileImpl::PixelRefIterator iterator(
gfx::Rect(0, 0, 256, 256), 0.5, pile.get());
EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[0][0].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[0][0].pixelRef());
EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[0][1].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[0][1].pixelRef());
EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[1][1].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[1][1].pixelRef());
EXPECT_FALSE(++iterator);
}
}
-TEST(PicturePileImpl, RasterContentsOpaque) {
+class FullContentsTest : public ::testing::TestWithParam<bool> {};
+
+TEST_P(FullContentsTest, RasterFullContents) {
gfx::Size tile_size(1000, 1000);
gfx::Size layer_bounds(3, 5);
float contents_scale = 1.5f;
float raster_divisions = 2.f;
+ // Param in this case is whether the content is fully opaque
+ // or just filled completely. For this test they should behave the same.
+ bool contents_opaque = GetParam();
+ bool fills_content = !GetParam();
scoped_refptr<FakePicturePileImpl> pile =
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
@@ -651,7 +656,8 @@ TEST(PicturePileImpl, RasterContentsOpaque) {
pile->SetMinContentsScale(contents_scale);
pile->set_background_color(SK_ColorBLACK);
- pile->set_contents_opaque(true);
+ pile->set_contents_opaque(contents_opaque);
+ pile->set_contents_fill_bounds_completely(fills_content);
pile->set_clear_canvas_with_debug_color(false);
pile->RerecordPile();
@@ -675,10 +681,7 @@ TEST(PicturePileImpl, RasterContentsOpaque) {
canvas_rect.Inset(0, 0, -1, -1);
SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config,
- canvas_rect.width(),
- canvas_rect.height());
- bitmap.allocPixels();
+ bitmap.allocN32Pixels(canvas_rect.width(), canvas_rect.height());
SkCanvas canvas(bitmap);
canvas.clear(SK_ColorTRANSPARENT);
@@ -707,6 +710,10 @@ TEST(PicturePileImpl, RasterContentsOpaque) {
}
}
+INSTANTIATE_TEST_CASE_P(PicturePileImpl,
+ FullContentsTest,
+ ::testing::Values(false, true));
+
TEST(PicturePileImpl, RasterContentsTransparent) {
gfx::Size tile_size(1000, 1000);
gfx::Size layer_bounds(5, 3);
@@ -727,10 +734,7 @@ TEST(PicturePileImpl, RasterContentsTransparent) {
canvas_rect.Inset(0, 0, -1, -1);
SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config,
- canvas_rect.width(),
- canvas_rect.height());
- bitmap.allocPixels();
+ bitmap.allocN32Pixels(canvas_rect.width(), canvas_rect.height());
SkCanvas canvas(bitmap);
FakeRenderingStatsInstrumentation rendering_stats_instrumentation;
@@ -744,5 +748,148 @@ TEST(PicturePileImpl, RasterContentsTransparent) {
}
}
+class OverlapTest : public ::testing::TestWithParam<float> {
+ public:
+ static float MinContentsScale() { return 1.f / 4.f; }
+};
+
+TEST_P(OverlapTest, NoOverlap) {
+ gfx::Size tile_size(10, 10);
+ gfx::Size layer_bounds(30, 30);
+ gfx::Size bigger_than_layer_bounds(300, 300);
+ float contents_scale = GetParam();
+ // Pick an opaque color to not have to deal with premultiplication off-by-one.
+ SkColor test_color = SkColorSetARGB(255, 45, 56, 67);
+
+ scoped_refptr<FakePicturePileImpl> pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+ pile->set_background_color(SK_ColorTRANSPARENT);
+ pile->set_contents_opaque(false);
+ pile->SetMinContentsScale(MinContentsScale());
+ pile->set_clear_canvas_with_debug_color(true);
+ SkPaint color_paint;
+ color_paint.setColor(test_color);
+ // Additive paint, so that if two paints overlap, the color will change.
+ color_paint.setXfermodeMode(SkXfermode::kPlus_Mode);
+ // Paint outside the layer to make sure that blending works.
+ pile->add_draw_rect_with_paint(gfx::RectF(bigger_than_layer_bounds),
+ color_paint);
+ pile->RerecordPile();
+
+ gfx::Size content_bounds(
+ gfx::ToCeiledSize(gfx::ScaleSize(layer_bounds, contents_scale)));
+
+ SkBitmap bitmap;
+ bitmap.setConfig(SkBitmap::kARGB_8888_Config,
+ content_bounds.width(),
+ content_bounds.height());
+ bitmap.allocPixels();
+ SkCanvas canvas(bitmap);
+
+ FakeRenderingStatsInstrumentation rendering_stats_instrumentation;
+ pile->RasterToBitmap(&canvas,
+ gfx::Rect(content_bounds),
+ contents_scale,
+ &rendering_stats_instrumentation);
+
+ for (int y = 0; y < bitmap.height(); y++) {
+ for (int x = 0; x < bitmap.width(); x++) {
+ SkColor color = bitmap.getColor(x, y);
+ EXPECT_EQ(SkColorGetR(test_color), SkColorGetR(color)) << "x: " << x
+ << ", y: " << y;
+ EXPECT_EQ(SkColorGetG(test_color), SkColorGetG(color)) << "x: " << x
+ << ", y: " << y;
+ EXPECT_EQ(SkColorGetB(test_color), SkColorGetB(color)) << "x: " << x
+ << ", y: " << y;
+ EXPECT_EQ(SkColorGetA(test_color), SkColorGetA(color)) << "x: " << x
+ << ", y: " << y;
+ if (test_color != color)
+ break;
+ }
+ }
+}
+
+INSTANTIATE_TEST_CASE_P(PicturePileImpl,
+ OverlapTest,
+ ::testing::Values(1.f, 0.873f, 1.f / 4.f, 4.f));
+
+TEST(PicturePileImplTest, PixelRefIteratorBorders) {
+ // 3 tile width / 1 tile height pile
+ gfx::Size tile_size(128, 128);
+ gfx::Size layer_bounds(320, 128);
+
+ // Fake picture pile impl uses a tile grid the size of the tile. So,
+ // any iteration that intersects with a tile will return all pixel refs
+ // inside of it.
+ scoped_refptr<FakePicturePileImpl> pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+ pile->SetMinContentsScale(0.5f);
+
+ // Bitmaps 0-2 are exactly on tiles 0-2, so that they overlap the borders
+ // of adjacent tiles.
+ gfx::Rect bitmap_rects[] = {pile->tiling().TileBounds(0, 0),
+ pile->tiling().TileBounds(1, 0),
+ pile->tiling().TileBounds(2, 0), };
+ SkBitmap discardable_bitmap[arraysize(bitmap_rects)];
+
+ for (size_t i = 0; i < arraysize(bitmap_rects); ++i) {
+ CreateBitmap(bitmap_rects[i].size(), "discardable", &discardable_bitmap[i]);
+ pile->add_draw_bitmap(discardable_bitmap[i], bitmap_rects[i].origin());
+ }
+
+ // Sanity check that bitmaps 0-2 intersect the borders of their adjacent
+ // tiles, but not the actual tiles.
+ EXPECT_TRUE(
+ bitmap_rects[0].Intersects(pile->tiling().TileBoundsWithBorder(1, 0)));
+ EXPECT_FALSE(bitmap_rects[0].Intersects(pile->tiling().TileBounds(1, 0)));
+ EXPECT_TRUE(
+ bitmap_rects[1].Intersects(pile->tiling().TileBoundsWithBorder(0, 0)));
+ EXPECT_FALSE(bitmap_rects[1].Intersects(pile->tiling().TileBounds(0, 0)));
+ EXPECT_TRUE(
+ bitmap_rects[1].Intersects(pile->tiling().TileBoundsWithBorder(2, 0)));
+ EXPECT_FALSE(bitmap_rects[1].Intersects(pile->tiling().TileBounds(2, 0)));
+ EXPECT_TRUE(
+ bitmap_rects[2].Intersects(pile->tiling().TileBoundsWithBorder(1, 0)));
+ EXPECT_FALSE(bitmap_rects[2].Intersects(pile->tiling().TileBounds(1, 0)));
+
+ pile->RerecordPile();
+
+ // Tile-sized iterators.
+ {
+ // Because tile 0's borders extend onto tile 1, it will include both
+ // bitmap 0 and 1. However, it should *not* include bitmap 2.
+ PicturePileImpl::PixelRefIterator iterator(
+ pile->tiling().TileBounds(0, 0), 1.f, pile.get());
+ EXPECT_TRUE(iterator);
+ EXPECT_TRUE(*iterator == discardable_bitmap[0].pixelRef());
+ EXPECT_TRUE(++iterator);
+ EXPECT_TRUE(*iterator == discardable_bitmap[1].pixelRef());
+ EXPECT_FALSE(++iterator);
+ }
+ {
+ // Tile 1 + borders hits all bitmaps.
+ PicturePileImpl::PixelRefIterator iterator(
+ pile->tiling().TileBounds(1, 0), 1.f, pile.get());
+ EXPECT_TRUE(iterator);
+ EXPECT_TRUE(*iterator == discardable_bitmap[0].pixelRef());
+ EXPECT_TRUE(++iterator);
+ EXPECT_TRUE(*iterator == discardable_bitmap[1].pixelRef());
+ EXPECT_TRUE(++iterator);
+ EXPECT_TRUE(*iterator == discardable_bitmap[2].pixelRef());
+ EXPECT_FALSE(++iterator);
+ }
+ {
+ // Tile 2 should not include bitmap 0, which is only on tile 0 and the
+ // borders of tile 1.
+ PicturePileImpl::PixelRefIterator iterator(
+ pile->tiling().TileBounds(2, 0), 1.f, pile.get());
+ EXPECT_TRUE(iterator);
+ EXPECT_TRUE(*iterator == discardable_bitmap[1].pixelRef());
+ EXPECT_TRUE(++iterator);
+ EXPECT_TRUE(*iterator == discardable_bitmap[2].pixelRef());
+ EXPECT_FALSE(++iterator);
+ }
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/resources/picture_pile_unittest.cc b/chromium/cc/resources/picture_pile_unittest.cc
index 91ec355424e..681166ea877 100644
--- a/chromium/cc/resources/picture_pile_unittest.cc
+++ b/chromium/cc/resources/picture_pile_unittest.cc
@@ -18,8 +18,15 @@ namespace {
class TestPicturePile : public PicturePile {
public:
using PicturePile::buffer_pixels;
+ using PicturePile::CanRasterSlowTileCheck;
+ using PicturePile::Clear;
PictureMap& picture_map() { return picture_map_; }
+ const gfx::Rect& recorded_viewport() const { return recorded_viewport_; }
+
+ bool CanRasterLayerRect(const gfx::Rect& layer_rect) {
+ return CanRaster(1.f, layer_rect);
+ }
typedef PicturePile::PictureInfo PictureInfo;
typedef PicturePile::PictureMapKey PictureMapKey;
@@ -29,48 +36,68 @@ class TestPicturePile : public PicturePile {
virtual ~TestPicturePile() {}
};
-TEST(PicturePileTest, SmallInvalidateInflated) {
- FakeContentLayerClient client;
- FakeRenderingStatsInstrumentation stats_instrumentation;
- scoped_refptr<TestPicturePile> pile = new TestPicturePile;
- SkColor background_color = SK_ColorBLUE;
-
- float min_scale = 0.125;
- gfx::Size base_picture_size = pile->tiling().max_texture_size();
-
- gfx::Size layer_size = base_picture_size;
- pile->Resize(layer_size);
- pile->SetTileGridSize(gfx::Size(1000, 1000));
- pile->SetMinContentsScale(min_scale);
-
- // Update the whole layer.
- pile->Update(&client,
- background_color,
- false,
- gfx::Rect(layer_size),
- gfx::Rect(layer_size),
- 1,
- &stats_instrumentation);
+class PicturePileTest : public testing::Test {
+ public:
+ PicturePileTest()
+ : pile_(new TestPicturePile()),
+ background_color_(SK_ColorBLUE),
+ min_scale_(0.125),
+ frame_number_(0),
+ contents_opaque_(false) {
+ pile_->SetTilingRect(gfx::Rect(pile_->tiling().max_texture_size()));
+ pile_->SetTileGridSize(gfx::Size(1000, 1000));
+ pile_->SetMinContentsScale(min_scale_);
+ }
+
+ gfx::Rect tiling_rect() const { return pile_->tiling_rect(); }
+
+ bool UpdateAndExpandInvalidation(Region* invalidation,
+ const gfx::Rect& visible_layer_rect) {
+ frame_number_++;
+ return pile_->UpdateAndExpandInvalidation(&client_,
+ invalidation,
+ background_color_,
+ contents_opaque_,
+ false,
+ visible_layer_rect,
+ frame_number_,
+ Picture::RECORD_NORMALLY,
+ &stats_instrumentation_);
+ }
+
+ bool UpdateWholePile() {
+ Region invalidation = tiling_rect();
+ bool result = UpdateAndExpandInvalidation(&invalidation, tiling_rect());
+ EXPECT_EQ(tiling_rect().ToString(), invalidation.ToString());
+ return result;
+ }
+
+ FakeContentLayerClient client_;
+ FakeRenderingStatsInstrumentation stats_instrumentation_;
+ scoped_refptr<TestPicturePile> pile_;
+ SkColor background_color_;
+ float min_scale_;
+ int frame_number_;
+ bool contents_opaque_;
+};
+
+TEST_F(PicturePileTest, SmallInvalidateInflated) {
+ UpdateWholePile();
// Invalidate something inside a tile.
- gfx::Rect invalidate_rect(50, 50, 1, 1);
- pile->Update(&client,
- background_color,
- false,
- invalidate_rect,
- gfx::Rect(layer_size),
- 2,
- &stats_instrumentation);
-
- EXPECT_EQ(1, pile->tiling().num_tiles_x());
- EXPECT_EQ(1, pile->tiling().num_tiles_y());
+ Region invalidate_rect(gfx::Rect(50, 50, 1, 1));
+ UpdateAndExpandInvalidation(&invalidate_rect, tiling_rect());
+ EXPECT_EQ(gfx::Rect(50, 50, 1, 1).ToString(), invalidate_rect.ToString());
+
+ EXPECT_EQ(1, pile_->tiling().num_tiles_x());
+ EXPECT_EQ(1, pile_->tiling().num_tiles_y());
TestPicturePile::PictureInfo& picture_info =
- pile->picture_map().find(TestPicturePile::PictureMapKey(0, 0))->second;
+ pile_->picture_map().find(TestPicturePile::PictureMapKey(0, 0))->second;
// We should have a picture.
EXPECT_TRUE(!!picture_info.GetPicture());
gfx::Rect picture_rect = gfx::ScaleToEnclosedRect(
- picture_info.GetPicture()->LayerRect(), min_scale);
+ picture_info.GetPicture()->LayerRect(), min_scale_);
// The the picture should be large enough that scaling it never makes a rect
// smaller than 1 px wide or tall.
@@ -78,117 +105,67 @@ TEST(PicturePileTest, SmallInvalidateInflated) {
picture_rect.ToString();
}
-TEST(PicturePileTest, LargeInvalidateInflated) {
- FakeContentLayerClient client;
- FakeRenderingStatsInstrumentation stats_instrumentation;
- scoped_refptr<TestPicturePile> pile = new TestPicturePile;
- SkColor background_color = SK_ColorBLUE;
-
- float min_scale = 0.125;
- gfx::Size base_picture_size = pile->tiling().max_texture_size();
-
- gfx::Size layer_size = base_picture_size;
- pile->Resize(layer_size);
- pile->SetTileGridSize(gfx::Size(1000, 1000));
- pile->SetMinContentsScale(min_scale);
-
- // Update the whole layer.
- pile->Update(&client,
- background_color,
- false,
- gfx::Rect(layer_size),
- gfx::Rect(layer_size),
- 1,
- &stats_instrumentation);
+TEST_F(PicturePileTest, LargeInvalidateInflated) {
+ UpdateWholePile();
// Invalidate something inside a tile.
- gfx::Rect invalidate_rect(50, 50, 100, 100);
- pile->Update(&client,
- background_color,
- false,
- invalidate_rect,
- gfx::Rect(layer_size),
- 2,
- &stats_instrumentation);
-
- EXPECT_EQ(1, pile->tiling().num_tiles_x());
- EXPECT_EQ(1, pile->tiling().num_tiles_y());
+ Region invalidate_rect(gfx::Rect(50, 50, 100, 100));
+ UpdateAndExpandInvalidation(&invalidate_rect, tiling_rect());
+ EXPECT_EQ(gfx::Rect(50, 50, 100, 100).ToString(), invalidate_rect.ToString());
+
+ EXPECT_EQ(1, pile_->tiling().num_tiles_x());
+ EXPECT_EQ(1, pile_->tiling().num_tiles_y());
TestPicturePile::PictureInfo& picture_info =
- pile->picture_map().find(TestPicturePile::PictureMapKey(0, 0))->second;
+ pile_->picture_map().find(TestPicturePile::PictureMapKey(0, 0))->second;
EXPECT_TRUE(!!picture_info.GetPicture());
- int expected_inflation = pile->buffer_pixels();
+ int expected_inflation = pile_->buffer_pixels();
Picture* base_picture = picture_info.GetPicture();
- gfx::Rect base_picture_rect(layer_size);
+ gfx::Rect base_picture_rect = pile_->tiling_rect();
base_picture_rect.Inset(-expected_inflation, -expected_inflation);
EXPECT_EQ(base_picture_rect.ToString(),
base_picture->LayerRect().ToString());
}
-TEST(PicturePileTest, InvalidateOnTileBoundaryInflated) {
- FakeContentLayerClient client;
- FakeRenderingStatsInstrumentation stats_instrumentation;
- scoped_refptr<TestPicturePile> pile = new TestPicturePile;
- SkColor background_color = SK_ColorBLUE;
-
- float min_scale = 0.125;
- gfx::Size base_picture_size = pile->tiling().max_texture_size();
-
- gfx::Size layer_size =
- gfx::ToFlooredSize(gfx::ScaleSize(base_picture_size, 2.f));
- pile->Resize(layer_size);
- pile->SetTileGridSize(gfx::Size(1000, 1000));
- pile->SetMinContentsScale(min_scale);
+TEST_F(PicturePileTest, InvalidateOnTileBoundaryInflated) {
+ gfx::Rect new_tiling_rect =
+ gfx::ToEnclosedRect(gfx::ScaleRect(pile_->tiling_rect(), 2.f));
+ pile_->SetTilingRect(new_tiling_rect);
// Due to border pixels, we should have 3 tiles.
- EXPECT_EQ(3, pile->tiling().num_tiles_x());
- EXPECT_EQ(3, pile->tiling().num_tiles_y());
+ EXPECT_EQ(3, pile_->tiling().num_tiles_x());
+ EXPECT_EQ(3, pile_->tiling().num_tiles_y());
// We should have 1/.125 - 1 = 7 border pixels.
- EXPECT_EQ(7, pile->buffer_pixels());
- EXPECT_EQ(7, pile->tiling().border_texels());
+ EXPECT_EQ(7, pile_->buffer_pixels());
+ EXPECT_EQ(7, pile_->tiling().border_texels());
// Update the whole layer to create initial pictures.
- pile->Update(&client,
- background_color,
- false,
- gfx::Rect(layer_size),
- gfx::Rect(layer_size),
- 0,
- &stats_instrumentation);
+ UpdateWholePile();
// Invalidate everything again to have a non zero invalidation
// frequency.
- pile->Update(&client,
- background_color,
- false,
- gfx::Rect(layer_size),
- gfx::Rect(layer_size),
- 1,
- &stats_instrumentation);
+ UpdateWholePile();
// Invalidate something just over a tile boundary by a single pixel.
// This will invalidate the tile (1, 1), as well as 1 row of pixels in (1, 0).
- gfx::Rect invalidate_rect(
- pile->tiling().TileBoundsWithBorder(0, 0).right(),
- pile->tiling().TileBoundsWithBorder(0, 0).bottom() - 1,
- 50,
- 50);
- pile->Update(&client,
- background_color,
- false,
- invalidate_rect,
- gfx::Rect(layer_size),
- 2,
- &stats_instrumentation);
-
- for (int i = 0; i < pile->tiling().num_tiles_x(); ++i) {
- for (int j = 0; j < pile->tiling().num_tiles_y(); ++j) {
+ Region invalidate_rect(
+ gfx::Rect(pile_->tiling().TileBoundsWithBorder(0, 0).right(),
+ pile_->tiling().TileBoundsWithBorder(0, 0).bottom() - 1,
+ 50,
+ 50));
+ Region expected_invalidation = invalidate_rect;
+ UpdateAndExpandInvalidation(&invalidate_rect, tiling_rect());
+ EXPECT_EQ(expected_invalidation.ToString(), invalidate_rect.ToString());
+
+ for (int i = 0; i < pile_->tiling().num_tiles_x(); ++i) {
+ for (int j = 0; j < pile_->tiling().num_tiles_y(); ++j) {
TestPicturePile::PictureInfo& picture_info =
- pile->picture_map().find(
- TestPicturePile::PictureMapKey(i, j))->second;
+ pile_->picture_map()
+ .find(TestPicturePile::PictureMapKey(i, j))
+ ->second;
// Expect (1, 1) and (1, 0) to be invalidated once more
// than the rest of the tiles.
@@ -205,60 +182,42 @@ TEST(PicturePileTest, InvalidateOnTileBoundaryInflated) {
}
}
-TEST(PicturePileTest, StopRecordingOffscreenInvalidations) {
- FakeContentLayerClient client;
- FakeRenderingStatsInstrumentation stats_instrumentation;
- scoped_refptr<TestPicturePile> pile = new TestPicturePile;
- SkColor background_color = SK_ColorBLUE;
+TEST_F(PicturePileTest, StopRecordingOffscreenInvalidations) {
+ gfx::Rect new_tiling_rect =
+ gfx::ToEnclosedRect(gfx::ScaleRect(pile_->tiling_rect(), 4.f));
+ pile_->SetTilingRect(new_tiling_rect);
- float min_scale = 0.125;
- gfx::Size base_picture_size = pile->tiling().max_texture_size();
+ gfx::Rect viewport(
+ tiling_rect().x(), tiling_rect().y(), tiling_rect().width(), 1);
- gfx::Size layer_size =
- gfx::ToFlooredSize(gfx::ScaleSize(base_picture_size, 4.f));
- pile->Resize(layer_size);
- pile->SetTileGridSize(gfx::Size(1000, 1000));
- pile->SetMinContentsScale(min_scale);
-
- gfx::Rect viewport(0, 0, layer_size.width(), 1);
-
- // Update the whole layer until the invalidation frequency is high.
- int frame;
- for (frame = 0; frame < 33; ++frame) {
- pile->Update(&client,
- background_color,
- false,
- gfx::Rect(layer_size),
- viewport,
- frame,
- &stats_instrumentation);
+ // Update the whole pile until the invalidation frequency is high.
+ for (int frame = 0; frame < 33; ++frame) {
+ UpdateWholePile();
}
// Make sure we have a high invalidation frequency.
- for (int i = 0; i < pile->tiling().num_tiles_x(); ++i) {
- for (int j = 0; j < pile->tiling().num_tiles_y(); ++j) {
+ for (int i = 0; i < pile_->tiling().num_tiles_x(); ++i) {
+ for (int j = 0; j < pile_->tiling().num_tiles_y(); ++j) {
TestPicturePile::PictureInfo& picture_info =
- pile->picture_map().find(
- TestPicturePile::PictureMapKey(i, j))->second;
+ pile_->picture_map()
+ .find(TestPicturePile::PictureMapKey(i, j))
+ ->second;
EXPECT_FLOAT_EQ(1.0f, picture_info.GetInvalidationFrequencyForTesting())
<< "i " << i << " j " << j;
}
}
- // Update once more with a small viewport 0,0 layer_width by 1
- pile->Update(&client,
- background_color,
- false,
- gfx::Rect(layer_size),
- viewport,
- frame,
- &stats_instrumentation);
-
- for (int i = 0; i < pile->tiling().num_tiles_x(); ++i) {
- for (int j = 0; j < pile->tiling().num_tiles_y(); ++j) {
+ // Update once more with a small viewport.
+ Region invalidation = tiling_rect();
+ UpdateAndExpandInvalidation(&invalidation, viewport);
+ EXPECT_EQ(tiling_rect().ToString(), invalidation.ToString());
+
+ for (int i = 0; i < pile_->tiling().num_tiles_x(); ++i) {
+ for (int j = 0; j < pile_->tiling().num_tiles_y(); ++j) {
TestPicturePile::PictureInfo& picture_info =
- pile->picture_map().find(
- TestPicturePile::PictureMapKey(i, j))->second;
+ pile_->picture_map()
+ .find(TestPicturePile::PictureMapKey(i, j))
+ ->second;
EXPECT_FLOAT_EQ(1.0f, picture_info.GetInvalidationFrequencyForTesting());
// If the y far enough away we expect to find no picture (no re-recording
@@ -270,28 +229,32 @@ TEST(PicturePileTest, StopRecordingOffscreenInvalidations) {
}
}
+ // Update a partial tile that doesn't get recorded. We should expand the
+ // invalidation to the entire tiles that overlap it.
+ Region small_invalidation =
+ gfx::Rect(pile_->tiling().TileBounds(3, 4).x(),
+ pile_->tiling().TileBounds(3, 4).y() + 10,
+ 1,
+ 1);
+ UpdateAndExpandInvalidation(&small_invalidation, viewport);
+ EXPECT_TRUE(small_invalidation.Contains(gfx::UnionRects(
+ pile_->tiling().TileBounds(2, 4), pile_->tiling().TileBounds(3, 4))))
+ << small_invalidation.ToString();
+
// Now update with no invalidation and full viewport
- pile->Update(&client,
- background_color,
- false,
- gfx::Rect(),
- gfx::Rect(layer_size),
- frame+1,
- &stats_instrumentation);
-
- for (int i = 0; i < pile->tiling().num_tiles_x(); ++i) {
- for (int j = 0; j < pile->tiling().num_tiles_y(); ++j) {
+ Region empty_invalidation;
+ UpdateAndExpandInvalidation(&empty_invalidation, tiling_rect());
+ EXPECT_EQ(Region().ToString(), empty_invalidation.ToString());
+
+ for (int i = 0; i < pile_->tiling().num_tiles_x(); ++i) {
+ for (int j = 0; j < pile_->tiling().num_tiles_y(); ++j) {
TestPicturePile::PictureInfo& picture_info =
- pile->picture_map().find(
- TestPicturePile::PictureMapKey(i, j))->second;
+ pile_->picture_map()
+ .find(TestPicturePile::PictureMapKey(i, j))
+ ->second;
// Expect the invalidation frequency to be less than 1, since we just
// updated with no invalidations.
- float expected_frequency =
- 1.0f -
- 1.0f / TestPicturePile::PictureInfo::INVALIDATION_FRAMES_TRACKED;
-
- EXPECT_FLOAT_EQ(expected_frequency,
- picture_info.GetInvalidationFrequencyForTesting());
+ EXPECT_LT(picture_info.GetInvalidationFrequencyForTesting(), 1.f);
// We expect that there are pictures everywhere now.
EXPECT_TRUE(picture_info.GetPicture()) << "i " << i << " j " << j;
@@ -299,5 +262,124 @@ TEST(PicturePileTest, StopRecordingOffscreenInvalidations) {
}
}
+TEST_F(PicturePileTest, ClearingInvalidatesRecordedRect) {
+ UpdateWholePile();
+
+ gfx::Rect rect(0, 0, 5, 5);
+ EXPECT_TRUE(pile_->CanRasterLayerRect(rect));
+ EXPECT_TRUE(pile_->CanRasterSlowTileCheck(rect));
+
+ pile_->Clear();
+
+ // Make sure both the cache-aware check (using recorded region) and the normal
+ // check are both false after clearing.
+ EXPECT_FALSE(pile_->CanRasterLayerRect(rect));
+ EXPECT_FALSE(pile_->CanRasterSlowTileCheck(rect));
+}
+
+TEST_F(PicturePileTest, FrequentInvalidationCanRaster) {
+ // This test makes sure that if part of the page is frequently invalidated
+ // and doesn't get re-recorded, then CanRaster is not true for any
+ // tiles touching it, but is true for adjacent tiles, even if it
+ // overlaps on borders (edge case).
+ gfx::Rect new_tiling_rect =
+ gfx::ToEnclosedRect(gfx::ScaleRect(pile_->tiling_rect(), 4.f));
+ pile_->SetTilingRect(new_tiling_rect);
+
+ gfx::Rect tile01_borders = pile_->tiling().TileBoundsWithBorder(0, 1);
+ gfx::Rect tile02_borders = pile_->tiling().TileBoundsWithBorder(0, 2);
+ gfx::Rect tile01_noborders = pile_->tiling().TileBounds(0, 1);
+ gfx::Rect tile02_noborders = pile_->tiling().TileBounds(0, 2);
+
+ // Sanity check these two tiles are overlapping with borders, since this is
+ // what the test is trying to repro.
+ EXPECT_TRUE(tile01_borders.Intersects(tile02_borders));
+ EXPECT_FALSE(tile01_noborders.Intersects(tile02_noborders));
+ UpdateWholePile();
+ EXPECT_TRUE(pile_->CanRasterLayerRect(tile01_noborders));
+ EXPECT_TRUE(pile_->CanRasterSlowTileCheck(tile01_noborders));
+ EXPECT_TRUE(pile_->CanRasterLayerRect(tile02_noborders));
+ EXPECT_TRUE(pile_->CanRasterSlowTileCheck(tile02_noborders));
+ // Sanity check that an initial paint goes down the fast path of having
+ // a valid recorded viewport.
+ EXPECT_TRUE(!pile_->recorded_viewport().IsEmpty());
+
+ // Update the whole layer until the invalidation frequency is high.
+ for (int frame = 0; frame < 33; ++frame) {
+ UpdateWholePile();
+ }
+
+ // Update once more with a small viewport.
+ gfx::Rect viewport(0, 0, tiling_rect().width(), 1);
+ Region invalidation(tiling_rect());
+ UpdateAndExpandInvalidation(&invalidation, viewport);
+ EXPECT_EQ(tiling_rect().ToString(), invalidation.ToString());
+
+ // Sanity check some pictures exist and others don't.
+ EXPECT_TRUE(pile_->picture_map()
+ .find(TestPicturePile::PictureMapKey(0, 1))
+ ->second.GetPicture());
+ EXPECT_FALSE(pile_->picture_map()
+ .find(TestPicturePile::PictureMapKey(0, 2))
+ ->second.GetPicture());
+
+ EXPECT_TRUE(pile_->CanRasterLayerRect(tile01_noborders));
+ EXPECT_TRUE(pile_->CanRasterSlowTileCheck(tile01_noborders));
+ EXPECT_FALSE(pile_->CanRasterLayerRect(tile02_noborders));
+ EXPECT_FALSE(pile_->CanRasterSlowTileCheck(tile02_noborders));
+}
+
+TEST_F(PicturePileTest, NoInvalidationValidViewport) {
+ // This test validates that the recorded_viewport cache of full tiles
+ // is still valid for some use cases. If it's not, it's a performance
+ // issue because CanRaster checks will go down the slow path.
+ UpdateWholePile();
+ EXPECT_TRUE(!pile_->recorded_viewport().IsEmpty());
+
+ // No invalidation, same viewport.
+ Region invalidation;
+ UpdateAndExpandInvalidation(&invalidation, tiling_rect());
+ EXPECT_TRUE(!pile_->recorded_viewport().IsEmpty());
+ EXPECT_EQ(Region().ToString(), invalidation.ToString());
+
+ // Partial invalidation, same viewport.
+ invalidation = gfx::Rect(0, 0, 1, 1);
+ UpdateAndExpandInvalidation(&invalidation, tiling_rect());
+ EXPECT_TRUE(!pile_->recorded_viewport().IsEmpty());
+ EXPECT_EQ(gfx::Rect(0, 0, 1, 1).ToString(), invalidation.ToString());
+
+ // No invalidation, changing viewport.
+ invalidation = Region();
+ UpdateAndExpandInvalidation(&invalidation, gfx::Rect(5, 5, 5, 5));
+ EXPECT_TRUE(!pile_->recorded_viewport().IsEmpty());
+ EXPECT_EQ(Region().ToString(), invalidation.ToString());
+}
+
+TEST_F(PicturePileTest, InvalidationOutsideRecordingRect) {
+ gfx::Rect huge_layer_rect(10000000, 20000000);
+ gfx::Rect viewport(300000, 400000, 5000, 6000);
+
+ pile_->SetTilingRect(huge_layer_rect);
+
+ // Invalidation inside the recording rect does not need to be expanded.
+ Region invalidation = viewport;
+ UpdateAndExpandInvalidation(&invalidation, viewport);
+ EXPECT_EQ(viewport.ToString(), invalidation.ToString());
+
+ // Invalidation outside the recording rect should expand to the tiles it
+ // covers.
+ gfx::Rect recorded_over_tiles =
+ pile_->tiling().ExpandRectToTileBounds(pile_->recorded_viewport());
+ gfx::Rect invalidation_outside(
+ recorded_over_tiles.right(), recorded_over_tiles.y(), 30, 30);
+ invalidation = invalidation_outside;
+ UpdateAndExpandInvalidation(&invalidation, viewport);
+ gfx::Rect expanded_recorded_viewport =
+ pile_->tiling().ExpandRectToTileBounds(pile_->recorded_viewport());
+ Region expected_invalidation =
+ pile_->tiling().ExpandRectToTileBounds(invalidation_outside);
+ EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/resources/picture_unittest.cc b/chromium/cc/resources/picture_unittest.cc
index f279a99b281..1367c5fd89a 100644
--- a/chromium/cc/resources/picture_unittest.cc
+++ b/chromium/cc/resources/picture_unittest.cc
@@ -10,11 +10,10 @@
#include "cc/test/fake_content_layer_client.h"
#include "cc/test/skia_common.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkBBHFactory.h"
#include "third_party/skia/include/core/SkCanvas.h"
-#include "third_party/skia/include/core/SkDevice.h"
#include "third_party/skia/include/core/SkGraphics.h"
#include "third_party/skia/include/core/SkPixelRef.h"
-#include "third_party/skia/include/core/SkTileGridPicture.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/skia_util.h"
@@ -26,7 +25,7 @@ TEST(PictureTest, AsBase64String) {
gfx::Rect layer_rect(100, 100);
- SkTileGridPicture::TileGridInfo tile_grid_info;
+ SkTileGridFactory::TileGridInfo tile_grid_info;
tile_grid_info.fTileInterval = SkISize::Make(100, 100);
tile_grid_info.fMargin.setEmpty();
tile_grid_info.fOffset.setZero();
@@ -44,73 +43,88 @@ TEST(PictureTest, AsBase64String) {
tmp.reset(new base::StringValue("abc!@#$%"));
scoped_refptr<Picture> invalid_picture =
Picture::CreateFromValue(tmp.get());
- EXPECT_TRUE(!invalid_picture.get());
+ EXPECT_FALSE(invalid_picture.get());
+
+ Picture::RecordingMode kRecordingModes[] = {Picture::RECORD_NORMALLY,
+ Picture::RECORD_WITH_SKRECORD};
// Single full-size rect picture.
content_layer_client.add_draw_rect(layer_rect, red_paint);
- scoped_refptr<Picture> one_rect_picture = Picture::Create(layer_rect);
- one_rect_picture->Record(&content_layer_client,
- tile_grid_info);
- scoped_ptr<base::Value> serialized_one_rect(
- one_rect_picture->AsValue());
- // Reconstruct the picture.
- scoped_refptr<Picture> one_rect_picture_check =
- Picture::CreateFromValue(serialized_one_rect.get());
- EXPECT_TRUE(!!one_rect_picture_check.get());
-
- // Check for equivalence.
- unsigned char one_rect_buffer[4 * 100 * 100] = {0};
- DrawPicture(one_rect_buffer, layer_rect, one_rect_picture);
- unsigned char one_rect_buffer_check[4 * 100 * 100] = {0};
- DrawPicture(one_rect_buffer_check, layer_rect, one_rect_picture_check);
-
- EXPECT_EQ(one_rect_picture->LayerRect(),
- one_rect_picture_check->LayerRect());
- EXPECT_EQ(one_rect_picture->OpaqueRect(),
- one_rect_picture_check->OpaqueRect());
- EXPECT_TRUE(
- memcmp(one_rect_buffer, one_rect_buffer_check, 4 * 100 * 100) == 0);
+ for (size_t i = 0; i < arraysize(kRecordingModes); ++i) {
+ scoped_refptr<Picture> one_rect_picture =
+ Picture::Create(layer_rect,
+ &content_layer_client,
+ tile_grid_info,
+ false,
+ 0,
+ kRecordingModes[i]);
+ scoped_ptr<base::Value> serialized_one_rect(one_rect_picture->AsValue());
+
+ // Reconstruct the picture.
+ scoped_refptr<Picture> one_rect_picture_check =
+ Picture::CreateFromValue(serialized_one_rect.get());
+ EXPECT_TRUE(!!one_rect_picture_check.get());
+
+ // Check for equivalence.
+ unsigned char one_rect_buffer[4 * 100 * 100] = {0};
+ DrawPicture(one_rect_buffer, layer_rect, one_rect_picture);
+ unsigned char one_rect_buffer_check[4 * 100 * 100] = {0};
+ DrawPicture(one_rect_buffer_check, layer_rect, one_rect_picture_check);
+
+ EXPECT_EQ(one_rect_picture->LayerRect(),
+ one_rect_picture_check->LayerRect());
+ EXPECT_EQ(one_rect_picture->OpaqueRect(),
+ one_rect_picture_check->OpaqueRect());
+ EXPECT_TRUE(memcmp(one_rect_buffer, one_rect_buffer_check, 4 * 100 * 100) ==
+ 0);
+ }
// Two rect picture.
content_layer_client.add_draw_rect(gfx::Rect(25, 25, 50, 50), green_paint);
- scoped_refptr<Picture> two_rect_picture = Picture::Create(layer_rect);
- two_rect_picture->Record(&content_layer_client,
- tile_grid_info);
- scoped_ptr<base::Value> serialized_two_rect(
- two_rect_picture->AsValue());
-
- // Reconstruct the picture.
- scoped_refptr<Picture> two_rect_picture_check =
- Picture::CreateFromValue(serialized_two_rect.get());
- EXPECT_TRUE(!!two_rect_picture_check.get());
-
- // Check for equivalence.
- unsigned char two_rect_buffer[4 * 100 * 100] = {0};
- DrawPicture(two_rect_buffer, layer_rect, two_rect_picture);
- unsigned char two_rect_buffer_check[4 * 100 * 100] = {0};
- DrawPicture(two_rect_buffer_check, layer_rect, two_rect_picture_check);
-
- EXPECT_EQ(two_rect_picture->LayerRect(),
- two_rect_picture_check->LayerRect());
- EXPECT_EQ(two_rect_picture->OpaqueRect(),
- two_rect_picture_check->OpaqueRect());
- EXPECT_TRUE(
- memcmp(two_rect_buffer, two_rect_buffer_check, 4 * 100 * 100) == 0);
+ for (size_t i = 0; i < arraysize(kRecordingModes); ++i) {
+ scoped_refptr<Picture> two_rect_picture =
+ Picture::Create(layer_rect,
+ &content_layer_client,
+ tile_grid_info,
+ false,
+ 0,
+ Picture::RECORD_NORMALLY);
+
+ scoped_ptr<base::Value> serialized_two_rect(two_rect_picture->AsValue());
+
+ // Reconstruct the picture.
+ scoped_refptr<Picture> two_rect_picture_check =
+ Picture::CreateFromValue(serialized_two_rect.get());
+ EXPECT_TRUE(!!two_rect_picture_check.get());
+
+ // Check for equivalence.
+ unsigned char two_rect_buffer[4 * 100 * 100] = {0};
+ DrawPicture(two_rect_buffer, layer_rect, two_rect_picture);
+ unsigned char two_rect_buffer_check[4 * 100 * 100] = {0};
+ DrawPicture(two_rect_buffer_check, layer_rect, two_rect_picture_check);
+
+ EXPECT_EQ(two_rect_picture->LayerRect(),
+ two_rect_picture_check->LayerRect());
+ EXPECT_EQ(two_rect_picture->OpaqueRect(),
+ two_rect_picture_check->OpaqueRect());
+ EXPECT_TRUE(memcmp(two_rect_buffer, two_rect_buffer_check, 4 * 100 * 100) ==
+ 0);
+ }
}
TEST(PictureTest, PixelRefIterator) {
gfx::Rect layer_rect(2048, 2048);
- SkTileGridPicture::TileGridInfo tile_grid_info;
+ SkTileGridFactory::TileGridInfo tile_grid_info;
tile_grid_info.fTileInterval = SkISize::Make(512, 512);
tile_grid_info.fMargin.setEmpty();
tile_grid_info.fOffset.setZero();
FakeContentLayerClient content_layer_client;
- // Lazy pixel refs are found in the following grids:
+ // Discardable pixel refs are found in the following grids:
// |---|---|---|---|
// | | x | | x |
// |---|---|---|---|
@@ -120,23 +134,26 @@ TEST(PictureTest, PixelRefIterator) {
// |---|---|---|---|
// | x | | x | |
// |---|---|---|---|
- SkBitmap lazy_bitmap[4][4];
+ SkBitmap discardable_bitmap[4][4];
for (int y = 0; y < 4; ++y) {
for (int x = 0; x < 4; ++x) {
if ((x + y) & 1) {
- CreateBitmap(gfx::Size(500, 500), "lazy", &lazy_bitmap[y][x]);
+ CreateBitmap(
+ gfx::Size(500, 500), "discardable", &discardable_bitmap[y][x]);
SkPaint paint;
content_layer_client.add_draw_bitmap(
- lazy_bitmap[y][x],
+ discardable_bitmap[y][x],
gfx::Point(x * 512 + 6, y * 512 + 6), paint);
}
}
}
- scoped_refptr<Picture> picture = Picture::Create(layer_rect);
- picture->Record(&content_layer_client,
- tile_grid_info);
- picture->GatherPixelRefs(tile_grid_info);
+ scoped_refptr<Picture> picture = Picture::Create(layer_rect,
+ &content_layer_client,
+ tile_grid_info,
+ true,
+ 0,
+ Picture::RECORD_NORMALLY);
// Default iterator does not have any pixel refs
{
@@ -149,7 +166,8 @@ TEST(PictureTest, PixelRefIterator) {
picture.get());
if ((x + y) & 1) {
EXPECT_TRUE(iterator) << x << " " << y;
- EXPECT_TRUE(*iterator == lazy_bitmap[y][x].pixelRef()) << x << " " << y;
+ EXPECT_TRUE(*iterator == discardable_bitmap[y][x].pixelRef()) << x <<
+ " " << y;
EXPECT_FALSE(++iterator) << x << " " << y;
} else {
EXPECT_FALSE(iterator) << x << " " << y;
@@ -161,13 +179,13 @@ TEST(PictureTest, PixelRefIterator) {
Picture::PixelRefIterator iterator(gfx::Rect(512, 512, 2048, 2048),
picture.get());
EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[1][2].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[1][2].pixelRef());
EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[2][1].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[2][1].pixelRef());
EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[2][3].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[2][3].pixelRef());
EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[3][2].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[3][2].pixelRef());
EXPECT_FALSE(++iterator);
}
@@ -175,39 +193,39 @@ TEST(PictureTest, PixelRefIterator) {
Picture::PixelRefIterator iterator(gfx::Rect(512, 512, 2048, 2048),
picture.get());
EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[1][2].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[1][2].pixelRef());
EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[2][1].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[2][1].pixelRef());
// copy now points to the same spot as iterator,
// but both can be incremented independently.
Picture::PixelRefIterator copy = iterator;
EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[2][3].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[2][3].pixelRef());
EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[3][2].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[3][2].pixelRef());
EXPECT_FALSE(++iterator);
EXPECT_TRUE(copy);
- EXPECT_TRUE(*copy == lazy_bitmap[2][1].pixelRef());
+ EXPECT_TRUE(*copy == discardable_bitmap[2][1].pixelRef());
EXPECT_TRUE(++copy);
- EXPECT_TRUE(*copy == lazy_bitmap[2][3].pixelRef());
+ EXPECT_TRUE(*copy == discardable_bitmap[2][3].pixelRef());
EXPECT_TRUE(++copy);
- EXPECT_TRUE(*copy == lazy_bitmap[3][2].pixelRef());
+ EXPECT_TRUE(*copy == discardable_bitmap[3][2].pixelRef());
EXPECT_FALSE(++copy);
}
TEST(PictureTest, PixelRefIteratorNonZeroLayer) {
gfx::Rect layer_rect(1024, 0, 2048, 2048);
- SkTileGridPicture::TileGridInfo tile_grid_info;
+ SkTileGridFactory::TileGridInfo tile_grid_info;
tile_grid_info.fTileInterval = SkISize::Make(512, 512);
tile_grid_info.fMargin.setEmpty();
tile_grid_info.fOffset.setZero();
FakeContentLayerClient content_layer_client;
- // Lazy pixel refs are found in the following grids:
+ // Discardable pixel refs are found in the following grids:
// |---|---|---|---|
// | | x | | x |
// |---|---|---|---|
@@ -217,23 +235,26 @@ TEST(PictureTest, PixelRefIteratorNonZeroLayer) {
// |---|---|---|---|
// | x | | x | |
// |---|---|---|---|
- SkBitmap lazy_bitmap[4][4];
+ SkBitmap discardable_bitmap[4][4];
for (int y = 0; y < 4; ++y) {
for (int x = 0; x < 4; ++x) {
if ((x + y) & 1) {
- CreateBitmap(gfx::Size(500, 500), "lazy", &lazy_bitmap[y][x]);
+ CreateBitmap(
+ gfx::Size(500, 500), "discardable", &discardable_bitmap[y][x]);
SkPaint paint;
content_layer_client.add_draw_bitmap(
- lazy_bitmap[y][x],
+ discardable_bitmap[y][x],
gfx::Point(1024 + x * 512 + 6, y * 512 + 6), paint);
}
}
}
- scoped_refptr<Picture> picture = Picture::Create(layer_rect);
- picture->Record(&content_layer_client,
- tile_grid_info);
- picture->GatherPixelRefs(tile_grid_info);
+ scoped_refptr<Picture> picture = Picture::Create(layer_rect,
+ &content_layer_client,
+ tile_grid_info,
+ true,
+ 0,
+ Picture::RECORD_NORMALLY);
// Default iterator does not have any pixel refs
{
@@ -246,7 +267,7 @@ TEST(PictureTest, PixelRefIteratorNonZeroLayer) {
gfx::Rect(1024 + x * 512, y * 512, 500, 500), picture.get());
if ((x + y) & 1) {
EXPECT_TRUE(iterator) << x << " " << y;
- EXPECT_TRUE(*iterator == lazy_bitmap[y][x].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[y][x].pixelRef());
EXPECT_FALSE(++iterator) << x << " " << y;
} else {
EXPECT_FALSE(iterator) << x << " " << y;
@@ -258,13 +279,13 @@ TEST(PictureTest, PixelRefIteratorNonZeroLayer) {
Picture::PixelRefIterator iterator(gfx::Rect(1024 + 512, 512, 2048, 2048),
picture.get());
EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[1][2].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[1][2].pixelRef());
EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[2][1].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[2][1].pixelRef());
EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[2][3].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[2][3].pixelRef());
EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[3][2].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[3][2].pixelRef());
EXPECT_FALSE(++iterator);
}
@@ -273,25 +294,25 @@ TEST(PictureTest, PixelRefIteratorNonZeroLayer) {
Picture::PixelRefIterator iterator(gfx::Rect(1024 + 512, 512, 2048, 2048),
picture.get());
EXPECT_TRUE(iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[1][2].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[1][2].pixelRef());
EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[2][1].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[2][1].pixelRef());
// copy now points to the same spot as iterator,
// but both can be incremented independently.
Picture::PixelRefIterator copy = iterator;
EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[2][3].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[2][3].pixelRef());
EXPECT_TRUE(++iterator);
- EXPECT_TRUE(*iterator == lazy_bitmap[3][2].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[3][2].pixelRef());
EXPECT_FALSE(++iterator);
EXPECT_TRUE(copy);
- EXPECT_TRUE(*copy == lazy_bitmap[2][1].pixelRef());
+ EXPECT_TRUE(*copy == discardable_bitmap[2][1].pixelRef());
EXPECT_TRUE(++copy);
- EXPECT_TRUE(*copy == lazy_bitmap[2][3].pixelRef());
+ EXPECT_TRUE(*copy == discardable_bitmap[2][3].pixelRef());
EXPECT_TRUE(++copy);
- EXPECT_TRUE(*copy == lazy_bitmap[3][2].pixelRef());
+ EXPECT_TRUE(*copy == discardable_bitmap[3][2].pixelRef());
EXPECT_FALSE(++copy);
}
@@ -321,14 +342,14 @@ TEST(PictureTest, PixelRefIteratorNonZeroLayer) {
TEST(PictureTest, PixelRefIteratorOnePixelQuery) {
gfx::Rect layer_rect(2048, 2048);
- SkTileGridPicture::TileGridInfo tile_grid_info;
+ SkTileGridFactory::TileGridInfo tile_grid_info;
tile_grid_info.fTileInterval = SkISize::Make(512, 512);
tile_grid_info.fMargin.setEmpty();
tile_grid_info.fOffset.setZero();
FakeContentLayerClient content_layer_client;
- // Lazy pixel refs are found in the following grids:
+ // Discardable pixel refs are found in the following grids:
// |---|---|---|---|
// | | x | | x |
// |---|---|---|---|
@@ -338,23 +359,26 @@ TEST(PictureTest, PixelRefIteratorOnePixelQuery) {
// |---|---|---|---|
// | x | | x | |
// |---|---|---|---|
- SkBitmap lazy_bitmap[4][4];
+ SkBitmap discardable_bitmap[4][4];
for (int y = 0; y < 4; ++y) {
for (int x = 0; x < 4; ++x) {
if ((x + y) & 1) {
- CreateBitmap(gfx::Size(500, 500), "lazy", &lazy_bitmap[y][x]);
+ CreateBitmap(
+ gfx::Size(500, 500), "discardable", &discardable_bitmap[y][x]);
SkPaint paint;
content_layer_client.add_draw_bitmap(
- lazy_bitmap[y][x],
+ discardable_bitmap[y][x],
gfx::Point(x * 512 + 6, y * 512 + 6), paint);
}
}
}
- scoped_refptr<Picture> picture = Picture::Create(layer_rect);
- picture->Record(&content_layer_client,
- tile_grid_info);
- picture->GatherPixelRefs(tile_grid_info);
+ scoped_refptr<Picture> picture = Picture::Create(layer_rect,
+ &content_layer_client,
+ tile_grid_info,
+ true,
+ 0,
+ Picture::RECORD_NORMALLY);
for (int y = 0; y < 4; ++y) {
for (int x = 0; x < 4; ++x) {
@@ -362,7 +386,7 @@ TEST(PictureTest, PixelRefIteratorOnePixelQuery) {
gfx::Rect(x * 512, y * 512 + 256, 1, 1), picture.get());
if ((x + y) & 1) {
EXPECT_TRUE(iterator) << x << " " << y;
- EXPECT_TRUE(*iterator == lazy_bitmap[y][x].pixelRef());
+ EXPECT_TRUE(*iterator == discardable_bitmap[y][x].pixelRef());
EXPECT_FALSE(++iterator) << x << " " << y;
} else {
EXPECT_FALSE(iterator) << x << " " << y;
@@ -376,7 +400,7 @@ TEST(PictureTest, CreateFromSkpValue) {
gfx::Rect layer_rect(100, 200);
- SkTileGridPicture::TileGridInfo tile_grid_info;
+ SkTileGridFactory::TileGridInfo tile_grid_info;
tile_grid_info.fTileInterval = SkISize::Make(100, 200);
tile_grid_info.fMargin.setEmpty();
tile_grid_info.fOffset.setZero();
@@ -398,9 +422,13 @@ TEST(PictureTest, CreateFromSkpValue) {
// Single full-size rect picture.
content_layer_client.add_draw_rect(layer_rect, red_paint);
- scoped_refptr<Picture> one_rect_picture = Picture::Create(layer_rect);
- one_rect_picture->Record(&content_layer_client,
- tile_grid_info);
+ scoped_refptr<Picture> one_rect_picture =
+ Picture::Create(layer_rect,
+ &content_layer_client,
+ tile_grid_info,
+ false,
+ 0,
+ Picture::RECORD_NORMALLY);
scoped_ptr<base::Value> serialized_one_rect(
one_rect_picture->AsValue());
@@ -421,5 +449,64 @@ TEST(PictureTest, CreateFromSkpValue) {
EXPECT_EQ(100, one_rect_picture_check->OpaqueRect().width());
EXPECT_EQ(200, one_rect_picture_check->OpaqueRect().height());
}
+
+TEST(PictureTest, RecordingModes) {
+ SkGraphics::Init();
+
+ gfx::Rect layer_rect(100, 200);
+
+ SkTileGridFactory::TileGridInfo tile_grid_info;
+ tile_grid_info.fTileInterval = SkISize::Make(100, 200);
+ tile_grid_info.fMargin.setEmpty();
+ tile_grid_info.fOffset.setZero();
+
+ FakeContentLayerClient content_layer_client;
+ EXPECT_EQ(NULL, content_layer_client.last_canvas());
+
+ scoped_refptr<Picture> picture = Picture::Create(layer_rect,
+ &content_layer_client,
+ tile_grid_info,
+ false,
+ 0,
+ Picture::RECORD_NORMALLY);
+ EXPECT_TRUE(content_layer_client.last_canvas() != NULL);
+ EXPECT_EQ(ContentLayerClient::GRAPHICS_CONTEXT_ENABLED,
+ content_layer_client.last_context_status());
+ EXPECT_TRUE(picture);
+
+ picture = Picture::Create(layer_rect,
+ &content_layer_client,
+ tile_grid_info,
+ false,
+ 0,
+ Picture::RECORD_WITH_SK_NULL_CANVAS);
+ EXPECT_TRUE(content_layer_client.last_canvas() != NULL);
+ EXPECT_EQ(ContentLayerClient::GRAPHICS_CONTEXT_ENABLED,
+ content_layer_client.last_context_status());
+ EXPECT_TRUE(picture);
+
+ picture = Picture::Create(layer_rect,
+ &content_layer_client,
+ tile_grid_info,
+ false,
+ 0,
+ Picture::RECORD_WITH_PAINTING_DISABLED);
+ EXPECT_TRUE(content_layer_client.last_canvas() != NULL);
+ EXPECT_EQ(ContentLayerClient::GRAPHICS_CONTEXT_DISABLED,
+ content_layer_client.last_context_status());
+ EXPECT_TRUE(picture);
+
+ picture = Picture::Create(layer_rect,
+ &content_layer_client,
+ tile_grid_info,
+ false,
+ 0,
+ Picture::RECORD_WITH_SKRECORD);
+ EXPECT_TRUE(content_layer_client.last_canvas() != NULL);
+ EXPECT_TRUE(picture);
+
+ EXPECT_EQ(4, Picture::RECORDING_MODE_COUNT);
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/resources/pixel_buffer_raster_worker_pool.cc b/chromium/cc/resources/pixel_buffer_raster_worker_pool.cc
index 011e5147e06..1df2362a5ae 100644
--- a/chromium/cc/resources/pixel_buffer_raster_worker_pool.cc
+++ b/chromium/cc/resources/pixel_buffer_raster_worker_pool.cc
@@ -4,140 +4,117 @@
#include "cc/resources/pixel_buffer_raster_worker_pool.h"
+#include <algorithm>
+
#include "base/containers/stack_container.h"
#include "base/debug/trace_event.h"
-#include "base/values.h"
#include "cc/debug/traced_value.h"
#include "cc/resources/resource.h"
-#include "third_party/skia/include/core/SkBitmapDevice.h"
-
-#if defined(OS_ANDROID)
-#include "base/android/sys_utils.h"
-#endif
namespace cc {
-
namespace {
-class PixelBufferWorkerPoolTaskImpl : public internal::WorkerPoolTask {
- public:
- typedef base::Callback<void(bool was_canceled, bool needs_upload)> Reply;
-
- PixelBufferWorkerPoolTaskImpl(internal::RasterWorkerPoolTask* task,
- uint8_t* buffer,
- const Reply& reply)
- : task_(task),
- buffer_(buffer),
- reply_(reply),
- needs_upload_(false) {
- }
-
- // Overridden from internal::WorkerPoolTask:
- virtual void RunOnWorkerThread(unsigned thread_index) OVERRIDE {
- // |buffer_| can be NULL in lost context situations.
- if (!buffer_) {
- // |needs_upload_| still needs to be true as task has not
- // been canceled.
- needs_upload_ = true;
- return;
- }
- needs_upload_ = task_->RunOnWorkerThread(thread_index,
- buffer_,
- task_->resource()->size(),
- 0);
- }
- virtual void CompleteOnOriginThread() OVERRIDE {
- // |needs_upload_| must be be false if task didn't run.
- DCHECK(HasFinishedRunning() || !needs_upload_);
- reply_.Run(!HasFinishedRunning(), needs_upload_);
- }
-
- private:
- virtual ~PixelBufferWorkerPoolTaskImpl() {}
-
- scoped_refptr<internal::RasterWorkerPoolTask> task_;
- uint8_t* buffer_;
- const Reply reply_;
- bool needs_upload_;
-
- DISALLOW_COPY_AND_ASSIGN(PixelBufferWorkerPoolTaskImpl);
-};
-
const int kCheckForCompletedRasterTasksDelayMs = 6;
const size_t kMaxScheduledRasterTasks = 48;
-typedef base::StackVector<internal::GraphNode*,
- kMaxScheduledRasterTasks> NodeVector;
+typedef base::StackVector<RasterTask*, kMaxScheduledRasterTasks>
+ RasterTaskVector;
-void AddDependenciesToGraphNode(
- internal::GraphNode* node,
- const NodeVector::ContainerType& dependencies) {
- for (NodeVector::ContainerType::const_iterator it = dependencies.begin();
- it != dependencies.end(); ++it) {
- internal::GraphNode* dependency = *it;
-
- node->add_dependency();
- dependency->add_dependent(node);
- }
-}
+} // namespace
-// Only used as std::find_if predicate for DCHECKs.
-bool WasCanceled(const internal::RasterWorkerPoolTask* task) {
- return task->WasCanceled();
+// static
+scoped_ptr<RasterWorkerPool> PixelBufferRasterWorkerPool::Create(
+ base::SequencedTaskRunner* task_runner,
+ TaskGraphRunner* task_graph_runner,
+ ResourceProvider* resource_provider,
+ size_t max_transfer_buffer_usage_bytes) {
+ return make_scoped_ptr<RasterWorkerPool>(
+ new PixelBufferRasterWorkerPool(task_runner,
+ task_graph_runner,
+ resource_provider,
+ max_transfer_buffer_usage_bytes));
}
-} // namespace
-
PixelBufferRasterWorkerPool::PixelBufferRasterWorkerPool(
+ base::SequencedTaskRunner* task_runner,
+ TaskGraphRunner* task_graph_runner,
ResourceProvider* resource_provider,
- size_t num_threads,
size_t max_transfer_buffer_usage_bytes)
- : RasterWorkerPool(resource_provider, num_threads),
+ : task_runner_(task_runner),
+ task_graph_runner_(task_graph_runner),
+ namespace_token_(task_graph_runner->GetNamespaceToken()),
+ resource_provider_(resource_provider),
shutdown_(false),
- scheduled_raster_task_count_(0),
- bytes_pending_upload_(0),
+ scheduled_raster_task_count_(0u),
+ raster_tasks_required_for_activation_count_(0u),
+ bytes_pending_upload_(0u),
max_bytes_pending_upload_(max_transfer_buffer_usage_bytes),
has_performed_uploads_since_last_flush_(false),
- check_for_completed_raster_tasks_pending_(false),
should_notify_client_if_no_tasks_are_pending_(false),
should_notify_client_if_no_tasks_required_for_activation_are_pending_(
- false) {
+ false),
+ raster_finished_task_pending_(false),
+ raster_required_for_activation_finished_task_pending_(false),
+ check_for_completed_raster_task_notifier_(
+ task_runner,
+ base::Bind(&PixelBufferRasterWorkerPool::CheckForCompletedRasterTasks,
+ base::Unretained(this)),
+ base::TimeDelta::FromMilliseconds(
+ kCheckForCompletedRasterTasksDelayMs)),
+ raster_finished_weak_ptr_factory_(this) {
}
PixelBufferRasterWorkerPool::~PixelBufferRasterWorkerPool() {
- DCHECK(shutdown_);
- DCHECK(!check_for_completed_raster_tasks_pending_);
- DCHECK_EQ(0u, pixel_buffer_tasks_.size());
- DCHECK_EQ(0u, tasks_with_pending_upload_.size());
- DCHECK_EQ(0u, completed_tasks_.size());
+ DCHECK_EQ(0u, raster_task_states_.size());
+ DCHECK_EQ(0u, raster_tasks_with_pending_upload_.size());
+ DCHECK_EQ(0u, completed_raster_tasks_.size());
+ DCHECK_EQ(0u, completed_image_decode_tasks_.size());
+ DCHECK_EQ(0u, raster_tasks_required_for_activation_count_);
+}
+
+Rasterizer* PixelBufferRasterWorkerPool::AsRasterizer() { return this; }
+
+void PixelBufferRasterWorkerPool::SetClient(RasterizerClient* client) {
+ client_ = client;
}
void PixelBufferRasterWorkerPool::Shutdown() {
+ TRACE_EVENT0("cc", "PixelBufferRasterWorkerPool::Shutdown");
+
shutdown_ = true;
- RasterWorkerPool::Shutdown();
- RasterWorkerPool::CheckForCompletedTasks();
+
+ TaskGraph empty;
+ task_graph_runner_->ScheduleTasks(namespace_token_, &empty);
+ task_graph_runner_->WaitForTasksToFinishRunning(namespace_token_);
+
+ CheckForCompletedRasterizerTasks();
CheckForCompletedUploads();
- check_for_completed_raster_tasks_callback_.Cancel();
- check_for_completed_raster_tasks_pending_ = false;
- for (TaskMap::iterator it = pixel_buffer_tasks_.begin();
- it != pixel_buffer_tasks_.end(); ++it) {
- internal::RasterWorkerPoolTask* task = it->first;
- internal::WorkerPoolTask* pixel_buffer_task = it->second.get();
-
- // All inactive tasks needs to be canceled.
- if (!pixel_buffer_task && !task->HasFinishedRunning()) {
- task->DidRun(true);
- completed_tasks_.push_back(task);
+
+ check_for_completed_raster_task_notifier_.Cancel();
+
+ for (RasterTaskState::Vector::iterator it = raster_task_states_.begin();
+ it != raster_task_states_.end();
+ ++it) {
+ RasterTaskState& state = *it;
+
+ // All unscheduled tasks need to be canceled.
+ if (state.type == RasterTaskState::UNSCHEDULED) {
+ completed_raster_tasks_.push_back(state.task);
+ state.type = RasterTaskState::COMPLETED;
}
}
- DCHECK_EQ(completed_tasks_.size(), pixel_buffer_tasks_.size());
+ DCHECK_EQ(completed_raster_tasks_.size(), raster_task_states_.size());
}
-void PixelBufferRasterWorkerPool::ScheduleTasks(RasterTask::Queue* queue) {
+void PixelBufferRasterWorkerPool::ScheduleTasks(RasterTaskQueue* queue) {
TRACE_EVENT0("cc", "PixelBufferRasterWorkerPool::ScheduleTasks");
- RasterWorkerPool::SetRasterTasks(queue);
+ DCHECK_EQ(queue->required_for_activation_count,
+ static_cast<size_t>(
+ std::count_if(queue->items.begin(),
+ queue->items.end(),
+ RasterTaskQueue::Item::IsRequiredForActivation)));
if (!should_notify_client_if_no_tasks_are_pending_)
TRACE_EVENT_ASYNC_BEGIN0("cc", "ScheduledTasks", this);
@@ -145,116 +122,170 @@ void PixelBufferRasterWorkerPool::ScheduleTasks(RasterTask::Queue* queue) {
should_notify_client_if_no_tasks_are_pending_ = true;
should_notify_client_if_no_tasks_required_for_activation_are_pending_ = true;
- tasks_required_for_activation_.clear();
+ raster_tasks_required_for_activation_count_ = 0u;
- // Build new pixel buffer task set.
- TaskMap new_pixel_buffer_tasks;
- for (RasterTaskVector::const_iterator it = raster_tasks().begin();
- it != raster_tasks().end(); ++it) {
- internal::RasterWorkerPoolTask* task = it->get();
- DCHECK(new_pixel_buffer_tasks.find(task) == new_pixel_buffer_tasks.end());
- DCHECK(!task->HasCompleted());
- DCHECK(!task->WasCanceled());
+ // Update raster task state and remove items from old queue.
+ for (RasterTaskQueue::Item::Vector::const_iterator it = queue->items.begin();
+ it != queue->items.end();
+ ++it) {
+ const RasterTaskQueue::Item& item = *it;
+ RasterTask* task = item.task;
+
+ // Remove any old items that are associated with this task. The result is
+ // that the old queue is left with all items not present in this queue,
+ // which we use below to determine what tasks need to be canceled.
+ RasterTaskQueue::Item::Vector::iterator old_it =
+ std::find_if(raster_tasks_.items.begin(),
+ raster_tasks_.items.end(),
+ RasterTaskQueue::Item::TaskComparator(task));
+ if (old_it != raster_tasks_.items.end()) {
+ std::swap(*old_it, raster_tasks_.items.back());
+ raster_tasks_.items.pop_back();
+ }
- new_pixel_buffer_tasks[task] = pixel_buffer_tasks_[task];
- pixel_buffer_tasks_.erase(task);
+ RasterTaskState::Vector::iterator state_it =
+ std::find_if(raster_task_states_.begin(),
+ raster_task_states_.end(),
+ RasterTaskState::TaskComparator(task));
+ if (state_it != raster_task_states_.end()) {
+ RasterTaskState& state = *state_it;
+
+ state.required_for_activation = item.required_for_activation;
+ // |raster_tasks_required_for_activation_count| accounts for all tasks
+ // that need to complete before we can send a "ready to activate" signal.
+ // Tasks that have already completed should not be part of this count.
+ if (state.type != RasterTaskState::COMPLETED) {
+ raster_tasks_required_for_activation_count_ +=
+ item.required_for_activation;
+ }
+ continue;
+ }
- if (IsRasterTaskRequiredForActivation(task))
- tasks_required_for_activation_.insert(task);
+ DCHECK(!task->HasBeenScheduled());
+ raster_task_states_.push_back(
+ RasterTaskState(task, item.required_for_activation));
+ raster_tasks_required_for_activation_count_ += item.required_for_activation;
}
- // Transfer remaining pixel buffer tasks to |new_pixel_buffer_tasks|
- // and cancel all remaining inactive tasks.
- for (TaskMap::iterator it = pixel_buffer_tasks_.begin();
- it != pixel_buffer_tasks_.end(); ++it) {
- internal::RasterWorkerPoolTask* task = it->first;
- internal::WorkerPoolTask* pixel_buffer_task = it->second.get();
-
- // Move task to |new_pixel_buffer_tasks|
- new_pixel_buffer_tasks[task] = pixel_buffer_task;
-
- // Inactive task can be canceled.
- if (!pixel_buffer_task && !task->HasFinishedRunning()) {
- task->DidRun(true);
- DCHECK(std::find(completed_tasks_.begin(),
- completed_tasks_.end(),
- task) == completed_tasks_.end());
- completed_tasks_.push_back(task);
- } else if (IsRasterTaskRequiredForActivation(task)) {
- tasks_required_for_activation_.insert(task);
+ // Determine what tasks in old queue need to be canceled.
+ for (RasterTaskQueue::Item::Vector::const_iterator it =
+ raster_tasks_.items.begin();
+ it != raster_tasks_.items.end();
+ ++it) {
+ const RasterTaskQueue::Item& item = *it;
+ RasterTask* task = item.task;
+
+ RasterTaskState::Vector::iterator state_it =
+ std::find_if(raster_task_states_.begin(),
+ raster_task_states_.end(),
+ RasterTaskState::TaskComparator(task));
+ // We've already processed completion if we can't find a RasterTaskState for
+ // this task.
+ if (state_it == raster_task_states_.end())
+ continue;
+
+ RasterTaskState& state = *state_it;
+
+ // Unscheduled task can be canceled.
+ if (state.type == RasterTaskState::UNSCHEDULED) {
+ DCHECK(!task->HasBeenScheduled());
+ DCHECK(std::find(completed_raster_tasks_.begin(),
+ completed_raster_tasks_.end(),
+ task) == completed_raster_tasks_.end());
+ completed_raster_tasks_.push_back(task);
+ state.type = RasterTaskState::COMPLETED;
}
- }
- // |tasks_required_for_activation_| contains all tasks that need to
- // complete before we can send a "ready to activate" signal. Tasks
- // that have already completed should not be part of this set.
- for (TaskDeque::const_iterator it = completed_tasks_.begin();
- it != completed_tasks_.end() && !tasks_required_for_activation_.empty();
- ++it) {
- tasks_required_for_activation_.erase(*it);
+ // No longer required for activation.
+ state.required_for_activation = false;
}
- pixel_buffer_tasks_.swap(new_pixel_buffer_tasks);
+ raster_tasks_.Swap(queue);
// Check for completed tasks when ScheduleTasks() is called as
// priorities might have changed and this maximizes the number
// of top priority tasks that are scheduled.
- RasterWorkerPool::CheckForCompletedTasks();
+ CheckForCompletedRasterizerTasks();
CheckForCompletedUploads();
FlushUploads();
// Schedule new tasks.
ScheduleMoreTasks();
- // Cancel any pending check for completed raster tasks and schedule
- // another check.
- check_for_completed_raster_tasks_callback_.Cancel();
- check_for_completed_raster_tasks_pending_ = false;
- ScheduleCheckForCompletedRasterTasks();
+ // Reschedule check for completed raster tasks.
+ check_for_completed_raster_task_notifier_.Schedule();
TRACE_EVENT_ASYNC_STEP_INTO1(
- "cc", "ScheduledTasks", this, StateName(),
- "state", TracedValue::FromValue(StateAsValue().release()));
-}
-
-GLenum PixelBufferRasterWorkerPool::GetResourceTarget() const {
- return GL_TEXTURE_2D;
-}
-
-ResourceFormat PixelBufferRasterWorkerPool::GetResourceFormat() const {
- return resource_provider()->memory_efficient_texture_format();
+ "cc",
+ "ScheduledTasks",
+ this,
+ StateName(),
+ "state",
+ TracedValue::FromValue(StateAsValue().release()));
}
void PixelBufferRasterWorkerPool::CheckForCompletedTasks() {
TRACE_EVENT0("cc", "PixelBufferRasterWorkerPool::CheckForCompletedTasks");
- RasterWorkerPool::CheckForCompletedTasks();
+ CheckForCompletedRasterizerTasks();
CheckForCompletedUploads();
FlushUploads();
- TaskDeque completed_tasks;
- completed_tasks_.swap(completed_tasks);
-
- while (!completed_tasks.empty()) {
- internal::RasterWorkerPoolTask* task = completed_tasks.front().get();
- DCHECK(pixel_buffer_tasks_.find(task) != pixel_buffer_tasks_.end());
+ for (RasterizerTask::Vector::const_iterator it =
+ completed_image_decode_tasks_.begin();
+ it != completed_image_decode_tasks_.end();
+ ++it) {
+ RasterizerTask* task = it->get();
+ task->RunReplyOnOriginThread();
+ }
+ completed_image_decode_tasks_.clear();
- pixel_buffer_tasks_.erase(task);
+ for (RasterTask::Vector::const_iterator it = completed_raster_tasks_.begin();
+ it != completed_raster_tasks_.end();
+ ++it) {
+ RasterTask* task = it->get();
+ RasterTaskState::Vector::iterator state_it =
+ std::find_if(raster_task_states_.begin(),
+ raster_task_states_.end(),
+ RasterTaskState::TaskComparator(task));
+ DCHECK(state_it != raster_task_states_.end());
+ DCHECK_EQ(RasterTaskState::COMPLETED, state_it->type);
+
+ std::swap(*state_it, raster_task_states_.back());
+ raster_task_states_.pop_back();
+
+ task->RunReplyOnOriginThread();
+ }
+ completed_raster_tasks_.clear();
+}
- task->WillComplete();
- task->CompleteOnOriginThread();
- task->DidComplete();
+SkCanvas* PixelBufferRasterWorkerPool::AcquireCanvasForRaster(
+ RasterTask* task) {
+ DCHECK(std::find_if(raster_task_states_.begin(),
+ raster_task_states_.end(),
+ RasterTaskState::TaskComparator(task)) !=
+ raster_task_states_.end());
+ resource_provider_->AcquirePixelRasterBuffer(task->resource()->id());
+ return resource_provider_->MapPixelRasterBuffer(task->resource()->id());
+}
- completed_tasks.pop_front();
- }
+void PixelBufferRasterWorkerPool::ReleaseCanvasForRaster(RasterTask* task) {
+ DCHECK(std::find_if(raster_task_states_.begin(),
+ raster_task_states_.end(),
+ RasterTaskState::TaskComparator(task)) !=
+ raster_task_states_.end());
+ resource_provider_->ReleasePixelRasterBuffer(task->resource()->id());
}
-void PixelBufferRasterWorkerPool::OnRasterTasksFinished() {
+void PixelBufferRasterWorkerPool::OnRasterFinished() {
+ TRACE_EVENT0("cc", "PixelBufferRasterWorkerPool::OnRasterFinished");
+
// |should_notify_client_if_no_tasks_are_pending_| can be set to false as
// a result of a scheduled CheckForCompletedRasterTasks() call. No need to
// perform another check in that case as we've already notified the client.
if (!should_notify_client_if_no_tasks_are_pending_)
return;
+ raster_finished_task_pending_ = false;
// Call CheckForCompletedRasterTasks() when we've finished running all
// raster tasks needed since last time ScheduleTasks() was called.
@@ -263,11 +294,16 @@ void PixelBufferRasterWorkerPool::OnRasterTasksFinished() {
CheckForCompletedRasterTasks();
}
-void PixelBufferRasterWorkerPool::OnRasterTasksRequiredForActivationFinished() {
+void PixelBufferRasterWorkerPool::OnRasterRequiredForActivationFinished() {
+ TRACE_EVENT0(
+ "cc",
+ "PixelBufferRasterWorkerPool::OnRasterRequiredForActivationFinished");
+
// Analogous to OnRasterTasksFinished(), there's no need to call
// CheckForCompletedRasterTasks() if the client has already been notified.
if (!should_notify_client_if_no_tasks_required_for_activation_are_pending_)
return;
+ raster_required_for_activation_finished_task_pending_ = false;
// This reduces latency between the time when all tasks required for
// activation have finished running and the time when the client is
@@ -279,43 +315,55 @@ void PixelBufferRasterWorkerPool::FlushUploads() {
if (!has_performed_uploads_since_last_flush_)
return;
- resource_provider()->ShallowFlushIfSupported();
+ resource_provider_->ShallowFlushIfSupported();
has_performed_uploads_since_last_flush_ = false;
}
void PixelBufferRasterWorkerPool::CheckForCompletedUploads() {
- TaskDeque tasks_with_completed_uploads;
+ RasterTask::Vector tasks_with_completed_uploads;
// First check if any have completed.
- while (!tasks_with_pending_upload_.empty()) {
- internal::RasterWorkerPoolTask* task =
- tasks_with_pending_upload_.front().get();
+ while (!raster_tasks_with_pending_upload_.empty()) {
+ RasterTask* task = raster_tasks_with_pending_upload_.front().get();
+ DCHECK(std::find_if(raster_task_states_.begin(),
+ raster_task_states_.end(),
+ RasterTaskState::TaskComparator(task)) !=
+ raster_task_states_.end());
+ DCHECK_EQ(RasterTaskState::UPLOADING,
+ std::find_if(raster_task_states_.begin(),
+ raster_task_states_.end(),
+ RasterTaskState::TaskComparator(task))->type);
// Uploads complete in the order they are issued.
- if (!resource_provider()->DidSetPixelsComplete(task->resource()->id()))
+ if (!resource_provider_->DidSetPixelsComplete(task->resource()->id()))
break;
tasks_with_completed_uploads.push_back(task);
- tasks_with_pending_upload_.pop_front();
+ raster_tasks_with_pending_upload_.pop_front();
}
- DCHECK(client());
+ DCHECK(client_);
bool should_force_some_uploads_to_complete =
- shutdown_ || client()->ShouldForceTasksRequiredForActivationToComplete();
+ shutdown_ || client_->ShouldForceTasksRequiredForActivationToComplete();
if (should_force_some_uploads_to_complete) {
- TaskDeque tasks_with_uploads_to_force;
- TaskDeque::iterator it = tasks_with_pending_upload_.begin();
- while (it != tasks_with_pending_upload_.end()) {
- internal::RasterWorkerPoolTask* task = it->get();
- DCHECK(pixel_buffer_tasks_.find(task) != pixel_buffer_tasks_.end());
+ RasterTask::Vector tasks_with_uploads_to_force;
+ RasterTaskDeque::iterator it = raster_tasks_with_pending_upload_.begin();
+ while (it != raster_tasks_with_pending_upload_.end()) {
+ RasterTask* task = it->get();
+ RasterTaskState::Vector::const_iterator state_it =
+ std::find_if(raster_task_states_.begin(),
+ raster_task_states_.end(),
+ RasterTaskState::TaskComparator(task));
+ DCHECK(state_it != raster_task_states_.end());
+ const RasterTaskState& state = *state_it;
// Force all uploads required for activation to complete.
// During shutdown, force all pending uploads to complete.
- if (shutdown_ || IsRasterTaskRequiredForActivation(task)) {
+ if (shutdown_ || state.required_for_activation) {
tasks_with_uploads_to_force.push_back(task);
tasks_with_completed_uploads.push_back(task);
- it = tasks_with_pending_upload_.erase(it);
+ it = raster_tasks_with_pending_upload_.erase(it);
continue;
}
@@ -324,72 +372,76 @@ void PixelBufferRasterWorkerPool::CheckForCompletedUploads() {
// Force uploads in reverse order. Since forcing can cause a wait on
// all previous uploads, we would rather wait only once downstream.
- for (TaskDeque::reverse_iterator it = tasks_with_uploads_to_force.rbegin();
+ for (RasterTask::Vector::reverse_iterator it =
+ tasks_with_uploads_to_force.rbegin();
it != tasks_with_uploads_to_force.rend();
++it) {
- resource_provider()->ForceSetPixelsToComplete((*it)->resource()->id());
+ RasterTask* task = it->get();
+
+ resource_provider_->ForceSetPixelsToComplete(task->resource()->id());
has_performed_uploads_since_last_flush_ = true;
}
}
// Release shared memory and move tasks with completed uploads
- // to |completed_tasks_|.
- while (!tasks_with_completed_uploads.empty()) {
- internal::RasterWorkerPoolTask* task =
- tasks_with_completed_uploads.front().get();
-
- // It's now safe to release the pixel buffer and the shared memory.
- resource_provider()->ReleasePixelBuffer(task->resource()->id());
+ // to |completed_raster_tasks_|.
+ for (RasterTask::Vector::const_iterator it =
+ tasks_with_completed_uploads.begin();
+ it != tasks_with_completed_uploads.end();
+ ++it) {
+ RasterTask* task = it->get();
+ RasterTaskState::Vector::iterator state_it =
+ std::find_if(raster_task_states_.begin(),
+ raster_task_states_.end(),
+ RasterTaskState::TaskComparator(task));
+ DCHECK(state_it != raster_task_states_.end());
+ RasterTaskState& state = *state_it;
bytes_pending_upload_ -= task->resource()->bytes();
- task->DidRun(false);
-
- DCHECK(std::find(completed_tasks_.begin(),
- completed_tasks_.end(),
- task) == completed_tasks_.end());
- completed_tasks_.push_back(task);
-
- tasks_required_for_activation_.erase(task);
+ task->WillComplete();
+ task->CompleteOnOriginThread(this);
+ task->DidComplete();
- tasks_with_completed_uploads.pop_front();
+ // Async set pixels commands are not necessarily processed in-sequence with
+ // drawing commands. Read lock fences are required to ensure that async
+ // commands don't access the resource while used for drawing.
+ resource_provider_->EnableReadLockFences(task->resource()->id(), true);
+
+ DCHECK(std::find(completed_raster_tasks_.begin(),
+ completed_raster_tasks_.end(),
+ task) == completed_raster_tasks_.end());
+ completed_raster_tasks_.push_back(task);
+ state.type = RasterTaskState::COMPLETED;
+ DCHECK_LE(static_cast<size_t>(state.required_for_activation),
+ raster_tasks_required_for_activation_count_);
+ raster_tasks_required_for_activation_count_ -=
+ state.required_for_activation;
}
}
-void PixelBufferRasterWorkerPool::ScheduleCheckForCompletedRasterTasks() {
- if (check_for_completed_raster_tasks_pending_)
- return;
-
- check_for_completed_raster_tasks_callback_.Reset(
- base::Bind(&PixelBufferRasterWorkerPool::CheckForCompletedRasterTasks,
- base::Unretained(this)));
- base::MessageLoopProxy::current()->PostDelayedTask(
- FROM_HERE,
- check_for_completed_raster_tasks_callback_.callback(),
- base::TimeDelta::FromMilliseconds(kCheckForCompletedRasterTasksDelayMs));
- check_for_completed_raster_tasks_pending_ = true;
-}
-
void PixelBufferRasterWorkerPool::CheckForCompletedRasterTasks() {
- TRACE_EVENT0(
- "cc", "PixelBufferRasterWorkerPool::CheckForCompletedRasterTasks");
+ TRACE_EVENT0("cc",
+ "PixelBufferRasterWorkerPool::CheckForCompletedRasterTasks");
- DCHECK(should_notify_client_if_no_tasks_are_pending_);
+ // Since this function can be called directly, cancel any pending checks.
+ check_for_completed_raster_task_notifier_.Cancel();
- check_for_completed_raster_tasks_callback_.Cancel();
- check_for_completed_raster_tasks_pending_ = false;
+ DCHECK(should_notify_client_if_no_tasks_are_pending_);
- RasterWorkerPool::CheckForCompletedTasks();
+ CheckForCompletedRasterizerTasks();
CheckForCompletedUploads();
FlushUploads();
// Determine what client notifications to generate.
bool will_notify_client_that_no_tasks_required_for_activation_are_pending =
(should_notify_client_if_no_tasks_required_for_activation_are_pending_ &&
+ !raster_required_for_activation_finished_task_pending_ &&
!HasPendingTasksRequiredForActivation());
bool will_notify_client_that_no_tasks_are_pending =
(should_notify_client_if_no_tasks_are_pending_ &&
- !HasPendingTasks());
+ !raster_required_for_activation_finished_task_pending_ &&
+ !raster_finished_task_pending_ && !HasPendingTasks());
// Adjust the need to generate notifications before scheduling more tasks.
should_notify_client_if_no_tasks_required_for_activation_are_pending_ &=
@@ -402,240 +454,195 @@ void PixelBufferRasterWorkerPool::CheckForCompletedRasterTasks() {
ScheduleMoreTasks();
TRACE_EVENT_ASYNC_STEP_INTO1(
- "cc", "ScheduledTasks", this, StateName(),
- "state", TracedValue::FromValue(StateAsValue().release()));
+ "cc",
+ "ScheduledTasks",
+ this,
+ StateName(),
+ "state",
+ TracedValue::FromValue(StateAsValue().release()));
// Schedule another check for completed raster tasks while there are
// pending raster tasks or pending uploads.
if (HasPendingTasks())
- ScheduleCheckForCompletedRasterTasks();
+ check_for_completed_raster_task_notifier_.Schedule();
// Generate client notifications.
if (will_notify_client_that_no_tasks_required_for_activation_are_pending) {
- DCHECK(std::find_if(raster_tasks_required_for_activation().begin(),
- raster_tasks_required_for_activation().end(),
- WasCanceled) ==
- raster_tasks_required_for_activation().end());
- client()->DidFinishRunningTasksRequiredForActivation();
+ DCHECK(!HasPendingTasksRequiredForActivation());
+ client_->DidFinishRunningTasksRequiredForActivation();
}
if (will_notify_client_that_no_tasks_are_pending) {
TRACE_EVENT_ASYNC_END0("cc", "ScheduledTasks", this);
DCHECK(!HasPendingTasksRequiredForActivation());
- client()->DidFinishRunningTasks();
+ client_->DidFinishRunningTasks();
}
}
void PixelBufferRasterWorkerPool::ScheduleMoreTasks() {
TRACE_EVENT0("cc", "PixelBufferRasterWorkerPool::ScheduleMoreTasks");
- enum RasterTaskType {
- PREPAINT_TYPE = 0,
- REQUIRED_FOR_ACTIVATION_TYPE = 1,
- NUM_TYPES = 2
- };
- NodeVector tasks[NUM_TYPES];
- unsigned priority = 2u; // 0-1 reserved for RasterFinished tasks.
- TaskGraph graph;
+ RasterTaskVector tasks;
+ RasterTaskVector tasks_required_for_activation;
- size_t bytes_pending_upload = bytes_pending_upload_;
+ unsigned priority = kRasterTaskPriorityBase;
+
+ graph_.Reset();
- for (RasterTaskVector::const_iterator it = raster_tasks().begin();
- it != raster_tasks().end(); ++it) {
- internal::RasterWorkerPoolTask* task = it->get();
+ size_t bytes_pending_upload = bytes_pending_upload_;
+ bool did_throttle_raster_tasks = false;
+ bool did_throttle_raster_tasks_required_for_activation = false;
- // |pixel_buffer_tasks_| contains all tasks that have not yet completed.
- TaskMap::iterator pixel_buffer_it = pixel_buffer_tasks_.find(task);
- if (pixel_buffer_it == pixel_buffer_tasks_.end())
+ for (RasterTaskQueue::Item::Vector::const_iterator it =
+ raster_tasks_.items.begin();
+ it != raster_tasks_.items.end();
+ ++it) {
+ const RasterTaskQueue::Item& item = *it;
+ RasterTask* task = item.task;
+
+ // |raster_task_states_| contains the state of all tasks that we have not
+ // yet run reply callbacks for.
+ RasterTaskState::Vector::iterator state_it =
+ std::find_if(raster_task_states_.begin(),
+ raster_task_states_.end(),
+ RasterTaskState::TaskComparator(task));
+ if (state_it == raster_task_states_.end())
continue;
- // HasFinishedRunning() will return true when set pixels has completed.
- if (task->HasFinishedRunning()) {
- DCHECK(std::find(completed_tasks_.begin(),
- completed_tasks_.end(),
- task) != completed_tasks_.end());
+ RasterTaskState& state = *state_it;
+
+ // Skip task if completed.
+ if (state.type == RasterTaskState::COMPLETED) {
+ DCHECK(std::find(completed_raster_tasks_.begin(),
+ completed_raster_tasks_.end(),
+ task) != completed_raster_tasks_.end());
continue;
}
// All raster tasks need to be throttled by bytes of pending uploads.
size_t new_bytes_pending_upload = bytes_pending_upload;
new_bytes_pending_upload += task->resource()->bytes();
- if (new_bytes_pending_upload > max_bytes_pending_upload_)
- break;
-
- internal::WorkerPoolTask* pixel_buffer_task = pixel_buffer_it->second.get();
+ if (new_bytes_pending_upload > max_bytes_pending_upload_) {
+ did_throttle_raster_tasks = true;
+ if (item.required_for_activation)
+ did_throttle_raster_tasks_required_for_activation = true;
+ continue;
+ }
// If raster has finished, just update |bytes_pending_upload|.
- if (pixel_buffer_task && pixel_buffer_task->HasCompleted()) {
+ if (state.type == RasterTaskState::UPLOADING) {
+ DCHECK(!task->HasCompleted());
bytes_pending_upload = new_bytes_pending_upload;
continue;
}
// Throttle raster tasks based on kMaxScheduledRasterTasks.
- size_t scheduled_raster_task_count =
- tasks[PREPAINT_TYPE].container().size() +
- tasks[REQUIRED_FOR_ACTIVATION_TYPE].container().size();
- if (scheduled_raster_task_count >= kMaxScheduledRasterTasks)
- break;
+ if (tasks.container().size() >= kMaxScheduledRasterTasks) {
+ did_throttle_raster_tasks = true;
+ if (item.required_for_activation)
+ did_throttle_raster_tasks_required_for_activation = true;
+ continue;
+ }
// Update |bytes_pending_upload| now that task has cleared all
// throttling limits.
bytes_pending_upload = new_bytes_pending_upload;
- RasterTaskType type = IsRasterTaskRequiredForActivation(task) ?
- REQUIRED_FOR_ACTIVATION_TYPE :
- PREPAINT_TYPE;
-
- // Use existing pixel buffer task if available.
- if (pixel_buffer_task) {
- tasks[type].container().push_back(
- CreateGraphNodeForRasterTask(pixel_buffer_task,
- task->dependencies(),
- priority++,
- &graph));
- continue;
- }
+ DCHECK(state.type == RasterTaskState::UNSCHEDULED ||
+ state.type == RasterTaskState::SCHEDULED);
+ state.type = RasterTaskState::SCHEDULED;
+
+ InsertNodesForRasterTask(&graph_, task, task->dependencies(), priority++);
- // Request a pixel buffer. This will reserve shared memory.
- resource_provider()->AcquirePixelBuffer(task->resource()->id());
-
- // MapPixelBuffer() returns NULL if context was lost at the time
- // AcquirePixelBuffer() was called. For simplicity we still post
- // a raster task that is essentially a noop in these situations.
- uint8* buffer = resource_provider()->MapPixelBuffer(
- task->resource()->id());
-
- scoped_refptr<internal::WorkerPoolTask> new_pixel_buffer_task(
- new PixelBufferWorkerPoolTaskImpl(
- task,
- buffer,
- base::Bind(&PixelBufferRasterWorkerPool::OnRasterTaskCompleted,
- base::Unretained(this),
- make_scoped_refptr(task))));
- pixel_buffer_tasks_[task] = new_pixel_buffer_task;
- tasks[type].container().push_back(
- CreateGraphNodeForRasterTask(new_pixel_buffer_task.get(),
- task->dependencies(),
- priority++,
- &graph));
+ tasks.container().push_back(task);
+ if (item.required_for_activation)
+ tasks_required_for_activation.container().push_back(task);
}
- scoped_refptr<internal::WorkerPoolTask>
+ // Cancel existing OnRasterFinished callbacks.
+ raster_finished_weak_ptr_factory_.InvalidateWeakPtrs();
+
+ scoped_refptr<RasterizerTask>
new_raster_required_for_activation_finished_task;
size_t scheduled_raster_task_required_for_activation_count =
- tasks[REQUIRED_FOR_ACTIVATION_TYPE].container().size();
+ tasks_required_for_activation.container().size();
DCHECK_LE(scheduled_raster_task_required_for_activation_count,
- tasks_required_for_activation_.size());
+ raster_tasks_required_for_activation_count_);
// Schedule OnRasterTasksRequiredForActivationFinished call only when
// notification is pending and throttling is not preventing all pending
// tasks required for activation from being scheduled.
- if (scheduled_raster_task_required_for_activation_count ==
- tasks_required_for_activation_.size() &&
+ if (!did_throttle_raster_tasks_required_for_activation &&
should_notify_client_if_no_tasks_required_for_activation_are_pending_) {
new_raster_required_for_activation_finished_task =
- CreateRasterRequiredForActivationFinishedTask();
- internal::GraphNode* raster_required_for_activation_finished_node =
- CreateGraphNodeForTask(
- new_raster_required_for_activation_finished_task.get(),
- 0u, // Priority 0
- &graph);
- AddDependenciesToGraphNode(
- raster_required_for_activation_finished_node,
- tasks[REQUIRED_FOR_ACTIVATION_TYPE].container());
+ CreateRasterRequiredForActivationFinishedTask(
+ raster_tasks_.required_for_activation_count,
+ task_runner_.get(),
+ base::Bind(&PixelBufferRasterWorkerPool::
+ OnRasterRequiredForActivationFinished,
+ raster_finished_weak_ptr_factory_.GetWeakPtr()));
+ raster_required_for_activation_finished_task_pending_ = true;
+ InsertNodeForTask(&graph_,
+ new_raster_required_for_activation_finished_task.get(),
+ kRasterRequiredForActivationFinishedTaskPriority,
+ scheduled_raster_task_required_for_activation_count);
+ for (RasterTaskVector::ContainerType::const_iterator it =
+ tasks_required_for_activation.container().begin();
+ it != tasks_required_for_activation.container().end();
+ ++it) {
+ graph_.edges.push_back(TaskGraph::Edge(
+ *it, new_raster_required_for_activation_finished_task.get()));
+ }
}
- scoped_refptr<internal::WorkerPoolTask> new_raster_finished_task;
+ scoped_refptr<RasterizerTask> new_raster_finished_task;
- size_t scheduled_raster_task_count =
- tasks[PREPAINT_TYPE].container().size() +
- tasks[REQUIRED_FOR_ACTIVATION_TYPE].container().size();
+ size_t scheduled_raster_task_count = tasks.container().size();
DCHECK_LE(scheduled_raster_task_count, PendingRasterTaskCount());
// Schedule OnRasterTasksFinished call only when notification is pending
// and throttling is not preventing all pending tasks from being scheduled.
- if (scheduled_raster_task_count == PendingRasterTaskCount() &&
+ if (!did_throttle_raster_tasks &&
should_notify_client_if_no_tasks_are_pending_) {
- new_raster_finished_task = CreateRasterFinishedTask();
- internal::GraphNode* raster_finished_node =
- CreateGraphNodeForTask(new_raster_finished_task.get(),
- 1u, // Priority 1
- &graph);
- for (unsigned type = 0; type < NUM_TYPES; ++type) {
- AddDependenciesToGraphNode(
- raster_finished_node,
- tasks[type].container());
+ new_raster_finished_task = CreateRasterFinishedTask(
+ task_runner_.get(),
+ base::Bind(&PixelBufferRasterWorkerPool::OnRasterFinished,
+ raster_finished_weak_ptr_factory_.GetWeakPtr()));
+ raster_finished_task_pending_ = true;
+ InsertNodeForTask(&graph_,
+ new_raster_finished_task.get(),
+ kRasterFinishedTaskPriority,
+ scheduled_raster_task_count);
+ for (RasterTaskVector::ContainerType::const_iterator it =
+ tasks.container().begin();
+ it != tasks.container().end();
+ ++it) {
+ graph_.edges.push_back(
+ TaskGraph::Edge(*it, new_raster_finished_task.get()));
}
}
- SetTaskGraph(&graph);
+ ScheduleTasksOnOriginThread(this, &graph_);
+ task_graph_runner_->ScheduleTasks(namespace_token_, &graph_);
scheduled_raster_task_count_ = scheduled_raster_task_count;
- set_raster_finished_task(new_raster_finished_task);
- set_raster_required_for_activation_finished_task(
- new_raster_required_for_activation_finished_task);
-}
-
-void PixelBufferRasterWorkerPool::OnRasterTaskCompleted(
- scoped_refptr<internal::RasterWorkerPoolTask> task,
- bool was_canceled,
- bool needs_upload) {
- TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("cc"),
- "PixelBufferRasterWorkerPool::OnRasterTaskCompleted",
- "was_canceled", was_canceled,
- "needs_upload", needs_upload);
-
- DCHECK(pixel_buffer_tasks_.find(task.get()) != pixel_buffer_tasks_.end());
-
- // Balanced with MapPixelBuffer() call in ScheduleMoreTasks().
- resource_provider()->UnmapPixelBuffer(task->resource()->id());
-
- if (!needs_upload) {
- resource_provider()->ReleasePixelBuffer(task->resource()->id());
-
- if (was_canceled) {
- // When priorites change, a raster task can be canceled as a result of
- // no longer being of high enough priority to fit in our throttled
- // raster task budget. The task has not yet completed in this case.
- RasterTaskVector::const_iterator it = std::find(raster_tasks().begin(),
- raster_tasks().end(),
- task);
- if (it != raster_tasks().end()) {
- pixel_buffer_tasks_[task.get()] = NULL;
- return;
- }
- }
-
- task->DidRun(was_canceled);
- DCHECK(std::find(completed_tasks_.begin(),
- completed_tasks_.end(),
- task) == completed_tasks_.end());
- completed_tasks_.push_back(task);
- tasks_required_for_activation_.erase(task);
- return;
- }
-
- DCHECK(!was_canceled);
-
- resource_provider()->BeginSetPixels(task->resource()->id());
- has_performed_uploads_since_last_flush_ = true;
-
- bytes_pending_upload_ += task->resource()->bytes();
- tasks_with_pending_upload_.push_back(task);
+ raster_finished_task_ = new_raster_finished_task;
+ raster_required_for_activation_finished_task_ =
+ new_raster_required_for_activation_finished_task;
}
unsigned PixelBufferRasterWorkerPool::PendingRasterTaskCount() const {
unsigned num_completed_raster_tasks =
- tasks_with_pending_upload_.size() + completed_tasks_.size();
- DCHECK_GE(pixel_buffer_tasks_.size(), num_completed_raster_tasks);
- return pixel_buffer_tasks_.size() - num_completed_raster_tasks;
+ raster_tasks_with_pending_upload_.size() + completed_raster_tasks_.size();
+ DCHECK_GE(raster_task_states_.size(), num_completed_raster_tasks);
+ return raster_task_states_.size() - num_completed_raster_tasks;
}
bool PixelBufferRasterWorkerPool::HasPendingTasks() const {
- return PendingRasterTaskCount() || !tasks_with_pending_upload_.empty();
+ return PendingRasterTaskCount() || !raster_tasks_with_pending_upload_.empty();
}
bool PixelBufferRasterWorkerPool::HasPendingTasksRequiredForActivation() const {
- return !tasks_required_for_activation_.empty();
+ return !!raster_tasks_required_for_activation_count_;
}
const char* PixelBufferRasterWorkerPool::StateName() const {
@@ -643,21 +650,101 @@ const char* PixelBufferRasterWorkerPool::StateName() const {
return "rasterizing";
if (PendingRasterTaskCount())
return "throttled";
- if (!tasks_with_pending_upload_.empty())
+ if (!raster_tasks_with_pending_upload_.empty())
return "waiting_for_uploads";
return "finishing";
}
+void PixelBufferRasterWorkerPool::CheckForCompletedRasterizerTasks() {
+ TRACE_EVENT0("cc",
+ "PixelBufferRasterWorkerPool::CheckForCompletedRasterizerTasks");
+
+ task_graph_runner_->CollectCompletedTasks(namespace_token_,
+ &completed_tasks_);
+ for (Task::Vector::const_iterator it = completed_tasks_.begin();
+ it != completed_tasks_.end();
+ ++it) {
+ RasterizerTask* task = static_cast<RasterizerTask*>(it->get());
+
+ RasterTask* raster_task = task->AsRasterTask();
+ if (!raster_task) {
+ task->WillComplete();
+ task->CompleteOnOriginThread(this);
+ task->DidComplete();
+
+ completed_image_decode_tasks_.push_back(task);
+ continue;
+ }
+
+ RasterTaskState::Vector::iterator state_it =
+ std::find_if(raster_task_states_.begin(),
+ raster_task_states_.end(),
+ RasterTaskState::TaskComparator(raster_task));
+ DCHECK(state_it != raster_task_states_.end());
+
+ RasterTaskState& state = *state_it;
+ DCHECK_EQ(RasterTaskState::SCHEDULED, state.type);
+
+ // Balanced with MapPixelRasterBuffer() call in AcquireCanvasForRaster().
+ bool content_has_changed = resource_provider_->UnmapPixelRasterBuffer(
+ raster_task->resource()->id());
+
+ // |content_has_changed| can be false as result of task being canceled or
+ // task implementation deciding not to modify bitmap (ie. analysis of raster
+ // commands detected content as a solid color).
+ if (!content_has_changed) {
+ raster_task->WillComplete();
+ raster_task->CompleteOnOriginThread(this);
+ raster_task->DidComplete();
+
+ if (!raster_task->HasFinishedRunning()) {
+ // When priorites change, a raster task can be canceled as a result of
+ // no longer being of high enough priority to fit in our throttled
+ // raster task budget. The task has not yet completed in this case.
+ RasterTaskQueue::Item::Vector::const_iterator item_it =
+ std::find_if(raster_tasks_.items.begin(),
+ raster_tasks_.items.end(),
+ RasterTaskQueue::Item::TaskComparator(raster_task));
+ if (item_it != raster_tasks_.items.end()) {
+ state.type = RasterTaskState::UNSCHEDULED;
+ continue;
+ }
+ }
+
+ DCHECK(std::find(completed_raster_tasks_.begin(),
+ completed_raster_tasks_.end(),
+ raster_task) == completed_raster_tasks_.end());
+ completed_raster_tasks_.push_back(raster_task);
+ state.type = RasterTaskState::COMPLETED;
+ DCHECK_LE(static_cast<size_t>(state.required_for_activation),
+ raster_tasks_required_for_activation_count_);
+ raster_tasks_required_for_activation_count_ -=
+ state.required_for_activation;
+ continue;
+ }
+
+ DCHECK(raster_task->HasFinishedRunning());
+
+ resource_provider_->BeginSetPixels(raster_task->resource()->id());
+ has_performed_uploads_since_last_flush_ = true;
+
+ bytes_pending_upload_ += raster_task->resource()->bytes();
+ raster_tasks_with_pending_upload_.push_back(raster_task);
+ state.type = RasterTaskState::UPLOADING;
+ }
+ completed_tasks_.clear();
+}
+
scoped_ptr<base::Value> PixelBufferRasterWorkerPool::StateAsValue() const {
scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue);
- state->SetInteger("completed_count", completed_tasks_.size());
- state->SetInteger("pending_count", pixel_buffer_tasks_.size());
- state->SetInteger("pending_upload_count", tasks_with_pending_upload_.size());
- state->SetInteger("required_for_activation_count",
- tasks_required_for_activation_.size());
- state->Set("scheduled_state", ScheduledStateAsValue().release());
+ state->SetInteger("completed_count", completed_raster_tasks_.size());
+ state->SetInteger("pending_count", raster_task_states_.size());
+ state->SetInteger("pending_upload_count",
+ raster_tasks_with_pending_upload_.size());
+ state->SetInteger("pending_required_for_activation_count",
+ raster_tasks_required_for_activation_count_);
state->Set("throttle_state", ThrottleStateAsValue().release());
return state.PassAs<base::Value>();
}
diff --git a/chromium/cc/resources/pixel_buffer_raster_worker_pool.h b/chromium/cc/resources/pixel_buffer_raster_worker_pool.h
index 88be2c02a7f..a2f15fd6f51 100644
--- a/chromium/cc/resources/pixel_buffer_raster_worker_pool.h
+++ b/chromium/cc/resources/pixel_buffer_raster_worker_pool.h
@@ -6,83 +6,127 @@
#define CC_RESOURCES_PIXEL_BUFFER_RASTER_WORKER_POOL_H_
#include <deque>
-#include <set>
#include <vector>
-#include "base/containers/hash_tables.h"
+#include "base/memory/weak_ptr.h"
+#include "base/values.h"
+#include "cc/base/delayed_unique_notifier.h"
#include "cc/resources/raster_worker_pool.h"
+#include "cc/resources/rasterizer.h"
namespace cc {
+class ResourceProvider;
-class CC_EXPORT PixelBufferRasterWorkerPool : public RasterWorkerPool {
+class CC_EXPORT PixelBufferRasterWorkerPool : public RasterWorkerPool,
+ public Rasterizer,
+ public RasterizerTaskClient {
public:
virtual ~PixelBufferRasterWorkerPool();
static scoped_ptr<RasterWorkerPool> Create(
+ base::SequencedTaskRunner* task_runner,
+ TaskGraphRunner* task_graph_runner,
ResourceProvider* resource_provider,
- size_t num_threads,
- size_t max_transfer_buffer_usage_bytes) {
- return make_scoped_ptr<RasterWorkerPool>(
- new PixelBufferRasterWorkerPool(resource_provider,
- num_threads,
- max_transfer_buffer_usage_bytes));
- }
-
- // Overridden from WorkerPool:
+ size_t max_transfer_buffer_usage_bytes);
+
+ // Overridden from RasterWorkerPool:
+ virtual Rasterizer* AsRasterizer() OVERRIDE;
+
+ // Overridden from Rasterizer:
+ virtual void SetClient(RasterizerClient* client) OVERRIDE;
virtual void Shutdown() OVERRIDE;
+ virtual void ScheduleTasks(RasterTaskQueue* queue) OVERRIDE;
virtual void CheckForCompletedTasks() OVERRIDE;
- // Overridden from RasterWorkerPool:
- virtual void ScheduleTasks(RasterTask::Queue* queue) OVERRIDE;
- virtual GLenum GetResourceTarget() const OVERRIDE;
- virtual ResourceFormat GetResourceFormat() const OVERRIDE;
- virtual void OnRasterTasksFinished() OVERRIDE;
- virtual void OnRasterTasksRequiredForActivationFinished() OVERRIDE;
+ // Overridden from RasterizerTaskClient:
+ virtual SkCanvas* AcquireCanvasForRaster(RasterTask* task) OVERRIDE;
+ virtual void ReleaseCanvasForRaster(RasterTask* task) OVERRIDE;
private:
- PixelBufferRasterWorkerPool(ResourceProvider* resource_provider,
- size_t num_threads,
+ struct RasterTaskState {
+ class TaskComparator {
+ public:
+ explicit TaskComparator(const RasterTask* task) : task_(task) {}
+
+ bool operator()(const RasterTaskState& state) const {
+ return state.task == task_;
+ }
+
+ private:
+ const RasterTask* task_;
+ };
+
+ typedef std::vector<RasterTaskState> Vector;
+
+ RasterTaskState(RasterTask* task, bool required_for_activation)
+ : type(UNSCHEDULED),
+ task(task),
+ required_for_activation(required_for_activation) {}
+
+ enum { UNSCHEDULED, SCHEDULED, UPLOADING, COMPLETED } type;
+ RasterTask* task;
+ bool required_for_activation;
+ };
+
+ typedef std::deque<scoped_refptr<RasterTask> > RasterTaskDeque;
+
+ PixelBufferRasterWorkerPool(base::SequencedTaskRunner* task_runner,
+ TaskGraphRunner* task_graph_runner,
+ ResourceProvider* resource_provider,
size_t max_transfer_buffer_usage_bytes);
+ void OnRasterFinished();
+ void OnRasterRequiredForActivationFinished();
void FlushUploads();
void CheckForCompletedUploads();
- void ScheduleCheckForCompletedRasterTasks();
void CheckForCompletedRasterTasks();
void ScheduleMoreTasks();
- void OnRasterTaskCompleted(
- scoped_refptr<internal::RasterWorkerPoolTask> task,
- bool was_canceled,
- bool needs_upload);
- void DidCompleteRasterTask(internal::RasterWorkerPoolTask* task);
unsigned PendingRasterTaskCount() const;
bool HasPendingTasks() const;
bool HasPendingTasksRequiredForActivation() const;
+ void CheckForCompletedRasterizerTasks();
const char* StateName() const;
scoped_ptr<base::Value> StateAsValue() const;
scoped_ptr<base::Value> ThrottleStateAsValue() const;
- bool shutdown_;
+ scoped_refptr<base::SequencedTaskRunner> task_runner_;
+ TaskGraphRunner* task_graph_runner_;
+ const NamespaceToken namespace_token_;
+ RasterizerClient* client_;
+ ResourceProvider* resource_provider_;
- TaskMap pixel_buffer_tasks_;
-
- typedef std::deque<scoped_refptr<internal::RasterWorkerPoolTask> > TaskDeque;
- TaskDeque tasks_with_pending_upload_;
- TaskDeque completed_tasks_;
+ bool shutdown_;
- typedef base::hash_set<internal::RasterWorkerPoolTask*> TaskSet;
- TaskSet tasks_required_for_activation_;
+ RasterTaskQueue raster_tasks_;
+ RasterTaskState::Vector raster_task_states_;
+ RasterTaskDeque raster_tasks_with_pending_upload_;
+ RasterTask::Vector completed_raster_tasks_;
+ RasterizerTask::Vector completed_image_decode_tasks_;
size_t scheduled_raster_task_count_;
+ size_t raster_tasks_required_for_activation_count_;
size_t bytes_pending_upload_;
size_t max_bytes_pending_upload_;
bool has_performed_uploads_since_last_flush_;
- base::CancelableClosure check_for_completed_raster_tasks_callback_;
- bool check_for_completed_raster_tasks_pending_;
bool should_notify_client_if_no_tasks_are_pending_;
bool should_notify_client_if_no_tasks_required_for_activation_are_pending_;
- ResourceFormat format_;
+ bool raster_finished_task_pending_;
+ bool raster_required_for_activation_finished_task_pending_;
+
+ DelayedUniqueNotifier check_for_completed_raster_task_notifier_;
+
+ base::WeakPtrFactory<PixelBufferRasterWorkerPool>
+ raster_finished_weak_ptr_factory_;
+
+ scoped_refptr<RasterizerTask> raster_finished_task_;
+ scoped_refptr<RasterizerTask> raster_required_for_activation_finished_task_;
+
+ // Task graph used when scheduling tasks and vector used to gather
+ // completed tasks.
+ TaskGraph graph_;
+ Task::Vector completed_tasks_;
DISALLOW_COPY_AND_ASSIGN(PixelBufferRasterWorkerPool);
};
diff --git a/chromium/cc/resources/prioritized_resource.cc b/chromium/cc/resources/prioritized_resource.cc
index f62ee40b0cb..462f7f1bb0c 100644
--- a/chromium/cc/resources/prioritized_resource.cc
+++ b/chromium/cc/resources/prioritized_resource.cc
@@ -14,7 +14,7 @@
namespace cc {
PrioritizedResource::PrioritizedResource(PrioritizedResourceManager* manager,
- gfx::Size size,
+ const gfx::Size& size,
ResourceFormat format)
: size_(size),
format_(format),
@@ -45,7 +45,8 @@ void PrioritizedResource::SetTextureManager(
manager->RegisterTexture(this);
}
-void PrioritizedResource::SetDimensions(gfx::Size size, ResourceFormat format) {
+void PrioritizedResource::SetDimensions(const gfx::Size& size,
+ ResourceFormat format) {
if (format_ != format || size_ != size) {
is_above_priority_cutoff_ = false;
format_ = format;
@@ -76,9 +77,9 @@ void PrioritizedResource::AcquireBackingTexture(
void PrioritizedResource::SetPixels(ResourceProvider* resource_provider,
const uint8_t* image,
- gfx::Rect image_rect,
- gfx::Rect source_rect,
- gfx::Vector2d dest_offset) {
+ const gfx::Rect& image_rect,
+ const gfx::Rect& source_rect,
+ const gfx::Vector2d& dest_offset) {
DCHECK(is_above_priority_cutoff_);
if (is_above_priority_cutoff_)
AcquireBackingTexture(resource_provider);
@@ -117,7 +118,7 @@ void PrioritizedResource::SetToSelfManagedMemoryPlaceholder(size_t bytes) {
PrioritizedResource::Backing::Backing(unsigned id,
ResourceProvider* resource_provider,
- gfx::Size size,
+ const gfx::Size& size,
ResourceFormat format)
: Resource(id, size, format),
owner_(NULL),
@@ -125,12 +126,13 @@ PrioritizedResource::Backing::Backing(unsigned id,
was_above_priority_cutoff_at_last_priority_update_(false),
in_drawing_impl_tree_(false),
in_parent_compositor_(false),
-#ifdef NDEBUG
- resource_has_been_deleted_(false) {}
+#if !DCHECK_IS_ON
+ resource_has_been_deleted_(false) {
#else
resource_has_been_deleted_(false),
- resource_provider_(resource_provider) {}
+ resource_provider_(resource_provider) {
#endif
+}
PrioritizedResource::Backing::~Backing() {
DCHECK(!owner_);
@@ -141,7 +143,7 @@ void PrioritizedResource::Backing::DeleteResource(
ResourceProvider* resource_provider) {
DCHECK(!proxy() || proxy()->IsImplThread());
DCHECK(!resource_has_been_deleted_);
-#ifndef NDEBUG
+#if DCHECK_IS_ON
DCHECK(resource_provider == resource_provider_);
#endif
diff --git a/chromium/cc/resources/prioritized_resource.h b/chromium/cc/resources/prioritized_resource.h
index ee90024fd5c..7920f811042 100644
--- a/chromium/cc/resources/prioritized_resource.h
+++ b/chromium/cc/resources/prioritized_resource.h
@@ -25,7 +25,7 @@ class CC_EXPORT PrioritizedResource {
public:
static scoped_ptr<PrioritizedResource> Create(
PrioritizedResourceManager* manager,
- gfx::Size size,
+ const gfx::Size& size,
ResourceFormat format) {
return make_scoped_ptr(new PrioritizedResource(manager, size, format));
}
@@ -40,7 +40,7 @@ class CC_EXPORT PrioritizedResource {
// Setting these to the same value is a no-op.
void SetTextureManager(PrioritizedResourceManager* manager);
PrioritizedResourceManager* resource_manager() { return manager_; }
- void SetDimensions(gfx::Size size, ResourceFormat format);
+ void SetDimensions(const gfx::Size& size, ResourceFormat format);
ResourceFormat format() const { return format_; }
gfx::Size size() const { return size_; }
size_t bytes() const { return bytes_; }
@@ -79,9 +79,9 @@ class CC_EXPORT PrioritizedResource {
// the backing if needed.
void SetPixels(ResourceProvider* resource_provider,
const uint8_t* image,
- gfx::Rect image_rect,
- gfx::Rect source_rect,
- gfx::Vector2d dest_offset);
+ const gfx::Rect& image_rect,
+ const gfx::Rect& source_rect,
+ const gfx::Vector2d& dest_offset);
ResourceProvider::ResourceId resource_id() const {
return backing_ ? backing_->id() : 0;
@@ -107,7 +107,7 @@ class CC_EXPORT PrioritizedResource {
public:
Backing(unsigned id,
ResourceProvider* resource_provider,
- gfx::Size size,
+ const gfx::Size& size,
ResourceFormat format);
~Backing();
void UpdatePriority();
@@ -143,14 +143,14 @@ class CC_EXPORT PrioritizedResource {
bool resource_has_been_deleted_;
-#ifndef NDEBUG
+#if DCHECK_IS_ON
ResourceProvider* resource_provider_;
#endif
DISALLOW_COPY_AND_ASSIGN(Backing);
};
PrioritizedResource(PrioritizedResourceManager* resource_manager,
- gfx::Size size,
+ const gfx::Size& size,
ResourceFormat format);
bool is_above_priority_cutoff() { return is_above_priority_cutoff_; }
diff --git a/chromium/cc/resources/prioritized_resource_manager.cc b/chromium/cc/resources/prioritized_resource_manager.cc
index da8f0555124..81af9fbf6dc 100644
--- a/chromium/cc/resources/prioritized_resource_manager.cc
+++ b/chromium/cc/resources/prioritized_resource_manager.cc
@@ -445,7 +445,7 @@ void PrioritizedResourceManager::ReturnBackingTexture(
}
PrioritizedResource::Backing* PrioritizedResourceManager::CreateBacking(
- gfx::Size size,
+ const gfx::Size& size,
ResourceFormat format,
ResourceProvider* resource_provider) {
DCHECK(proxy_->IsImplThread() && proxy_->IsMainThreadBlocked());
@@ -482,7 +482,7 @@ void PrioritizedResourceManager::EvictFirstBackingResource(
}
void PrioritizedResourceManager::AssertInvariants() {
-#ifndef NDEBUG
+#if DCHECK_IS_ON
DCHECK(proxy_->IsImplThread() && proxy_->IsMainThreadBlocked());
// If we hit any of these asserts, there is a bug in this class. To see
@@ -541,7 +541,7 @@ void PrioritizedResourceManager::AssertInvariants() {
DCHECK(backing->CanBeRecycledIfNotInExternalUse());
previous_backing = backing;
}
-#endif
+#endif // DCHECK_IS_ON
}
const Proxy* PrioritizedResourceManager::ProxyForDebug() const {
diff --git a/chromium/cc/resources/prioritized_resource_manager.h b/chromium/cc/resources/prioritized_resource_manager.h
index 9b558a45b8f..092b1d720fd 100644
--- a/chromium/cc/resources/prioritized_resource_manager.h
+++ b/chromium/cc/resources/prioritized_resource_manager.h
@@ -40,7 +40,7 @@ class CC_EXPORT PrioritizedResourceManager {
return make_scoped_ptr(new PrioritizedResourceManager(proxy));
}
scoped_ptr<PrioritizedResource> CreateTexture(
- gfx::Size size, ResourceFormat format) {
+ const gfx::Size& size, ResourceFormat format) {
return make_scoped_ptr(new PrioritizedResource(this, size, format));
}
~PrioritizedResourceManager();
@@ -189,7 +189,7 @@ class CC_EXPORT PrioritizedResourceManager {
UnlinkPolicy unlink_policy,
ResourceProvider* resource_provider);
PrioritizedResource::Backing* CreateBacking(
- gfx::Size size,
+ const gfx::Size& size,
ResourceFormat format,
ResourceProvider* resource_provider);
void EvictFirstBackingResource(ResourceProvider* resource_provider);
diff --git a/chromium/cc/resources/prioritized_resource_unittest.cc b/chromium/cc/resources/prioritized_resource_unittest.cc
index 7619dcc75e3..14eb317461c 100644
--- a/chromium/cc/resources/prioritized_resource_unittest.cc
+++ b/chromium/cc/resources/prioritized_resource_unittest.cc
@@ -12,6 +12,7 @@
#include "cc/test/fake_output_surface.h"
#include "cc/test/fake_output_surface_client.h"
#include "cc/test/fake_proxy.h"
+#include "cc/test/test_shared_bitmap_manager.h"
#include "cc/test/tiled_layer_test_common.h"
#include "cc/trees/single_thread_proxy.h" // For DebugScopedSetImplThread
#include "testing/gtest/include/gtest/gtest.h"
@@ -26,8 +27,10 @@ class PrioritizedResourceTest : public testing::Test {
output_surface_(FakeOutputSurface::Create3d()) {
DebugScopedSetImplThread impl_thread(&proxy_);
CHECK(output_surface_->BindToClient(&output_surface_client_));
- resource_provider_ =
- ResourceProvider::Create(output_surface_.get(), NULL, 0, false, 1);
+ shared_bitmap_manager_.reset(new TestSharedBitmapManager());
+ resource_provider_ = ResourceProvider::Create(
+ output_surface_.get(), shared_bitmap_manager_.get(), 0, false, 1,
+ false);
}
virtual ~PrioritizedResourceTest() {
@@ -78,11 +81,9 @@ class PrioritizedResourceTest : public testing::Test {
void ResourceManagerAssertInvariants(
PrioritizedResourceManager* resource_manager) {
-#ifndef NDEBUG
DebugScopedSetImplThreadAndMainThreadBlocked
impl_thread_and_main_thread_blocked(&proxy_);
resource_manager->AssertInvariants();
-#endif
}
bool TextureBackingIsAbovePriorityCutoff(PrioritizedResource* texture) {
@@ -111,6 +112,7 @@ class PrioritizedResourceTest : public testing::Test {
const ResourceFormat texture_format_;
FakeOutputSurfaceClient output_surface_client_;
scoped_ptr<OutputSurface> output_surface_;
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager_;
scoped_ptr<ResourceProvider> resource_provider_;
};
diff --git a/chromium/cc/resources/prioritized_tile_set.cc b/chromium/cc/resources/prioritized_tile_set.cc
index 6c5c4729d7e..b7b3b5a741e 100644
--- a/chromium/cc/resources/prioritized_tile_set.cc
+++ b/chromium/cc/resources/prioritized_tile_set.cc
@@ -18,20 +18,17 @@ class BinComparator {
const ManagedTileState& ams = a->managed_state();
const ManagedTileState& bms = b->managed_state();
+ if (ams.priority_bin != bms.priority_bin)
+ return ams.priority_bin < bms.priority_bin;
+
if (ams.required_for_activation != bms.required_for_activation)
return ams.required_for_activation;
if (ams.resolution != bms.resolution)
return ams.resolution < bms.resolution;
- if (ams.time_to_needed_in_seconds != bms.time_to_needed_in_seconds)
- return ams.time_to_needed_in_seconds < bms.time_to_needed_in_seconds;
-
- if (ams.distance_to_visible_in_pixels !=
- bms.distance_to_visible_in_pixels) {
- return ams.distance_to_visible_in_pixels <
- bms.distance_to_visible_in_pixels;
- }
+ if (ams.distance_to_visible != bms.distance_to_visible)
+ return ams.distance_to_visible < bms.distance_to_visible;
gfx::Rect a_rect = a->content_rect();
gfx::Rect b_rect = b->content_rect();
diff --git a/chromium/cc/resources/prioritized_tile_set_unittest.cc b/chromium/cc/resources/prioritized_tile_set_unittest.cc
index b51eb0063fb..f0a01d25900 100644
--- a/chromium/cc/resources/prioritized_tile_set_unittest.cc
+++ b/chromium/cc/resources/prioritized_tile_set_unittest.cc
@@ -13,6 +13,7 @@
#include "cc/test/fake_picture_pile_impl.h"
#include "cc/test/fake_tile_manager.h"
#include "cc/test/fake_tile_manager_client.h"
+#include "cc/test/test_shared_bitmap_manager.h"
#include "cc/test/test_tile_priorities.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -25,20 +26,17 @@ class BinComparator {
const ManagedTileState& ams = a->managed_state();
const ManagedTileState& bms = b->managed_state();
+ if (ams.priority_bin != bms.priority_bin)
+ return ams.priority_bin < bms.priority_bin;
+
if (ams.required_for_activation != bms.required_for_activation)
return ams.required_for_activation;
if (ams.resolution != bms.resolution)
return ams.resolution < bms.resolution;
- if (ams.time_to_needed_in_seconds != bms.time_to_needed_in_seconds)
- return ams.time_to_needed_in_seconds < bms.time_to_needed_in_seconds;
-
- if (ams.distance_to_visible_in_pixels !=
- bms.distance_to_visible_in_pixels) {
- return ams.distance_to_visible_in_pixels <
- bms.distance_to_visible_in_pixels;
- }
+ if (ams.distance_to_visible != bms.distance_to_visible)
+ return ams.distance_to_visible < bms.distance_to_visible;
gfx::Rect a_rect = a->content_rect();
gfx::Rect b_rect = b->content_rect();
@@ -56,15 +54,17 @@ class PrioritizedTileSetTest : public testing::Test {
output_surface_ = FakeOutputSurface::Create3d().Pass();
CHECK(output_surface_->BindToClient(&output_surface_client_));
+ shared_bitmap_manager_.reset(new TestSharedBitmapManager());
resource_provider_ =
- ResourceProvider::Create(output_surface_.get(),
- NULL,
- 0,
- false,
- 1).Pass();
+ ResourceProvider::Create(
+ output_surface_.get(), shared_bitmap_manager_.get(), 0, false, 1,
+ false)
+ .Pass();
+ resource_pool_ = ResourcePool::Create(
+ resource_provider_.get(), GL_TEXTURE_2D, RGBA_8888);
tile_manager_.reset(
- new FakeTileManager(&tile_manager_client_, resource_provider_.get()));
- picture_pile_ = FakePicturePileImpl::CreatePile();
+ new FakeTileManager(&tile_manager_client_, resource_pool_.get()));
+ picture_pile_ = FakePicturePileImpl::CreateInfiniteFilledPile();
}
scoped_refptr<Tile> CreateTile() {
@@ -75,14 +75,16 @@ class PrioritizedTileSetTest : public testing::Test {
1.0,
0,
0,
- Tile::USE_LCD_TEXT);
+ 0);
}
private:
LayerTreeSettings settings_;
FakeOutputSurfaceClient output_surface_client_;
scoped_ptr<FakeOutputSurface> output_surface_;
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager_;
scoped_ptr<ResourceProvider> resource_provider_;
+ scoped_ptr<ResourcePool> resource_pool_;
FakeTileManagerClient tile_manager_client_;
scoped_ptr<FakeTileManager> tile_manager_;
scoped_refptr<FakePicturePileImpl> picture_pile_;
diff --git a/chromium/cc/resources/priority_calculator.cc b/chromium/cc/resources/priority_calculator.cc
index fe5741c30e9..2a0cd189da1 100644
--- a/chromium/cc/resources/priority_calculator.cc
+++ b/chromium/cc/resources/priority_calculator.cc
@@ -69,8 +69,8 @@ int PriorityCalculator::LingeringPriority(int previous_priority) {
}
// static
-int PriorityCalculator::PriorityFromDistance(gfx::Rect visible_rect,
- gfx::Rect texture_rect,
+int PriorityCalculator::PriorityFromDistance(const gfx::Rect& visible_rect,
+ const gfx::Rect& texture_rect,
bool draws_to_root_surface) {
int distance = visible_rect.ManhattanInternalDistance(texture_rect);
if (!distance)
diff --git a/chromium/cc/resources/priority_calculator.h b/chromium/cc/resources/priority_calculator.h
index 877896176b8..502bd2734f8 100644
--- a/chromium/cc/resources/priority_calculator.h
+++ b/chromium/cc/resources/priority_calculator.h
@@ -20,8 +20,8 @@ class CC_EXPORT PriorityCalculator {
static int VisiblePriority(bool draws_to_root_surface);
static int RenderSurfacePriority();
static int LingeringPriority(int previous_priority);
- static int PriorityFromDistance(gfx::Rect visible_rect,
- gfx::Rect texture_rect,
+ static int PriorityFromDistance(const gfx::Rect& visible_rect,
+ const gfx::Rect& texture_rect,
bool draws_to_root_surface);
static int SmallAnimatedLayerMinPriority();
diff --git a/chromium/cc/resources/raster_mode.cc b/chromium/cc/resources/raster_mode.cc
index 47d6344c97d..5da8ee76e9b 100644
--- a/chromium/cc/resources/raster_mode.cc
+++ b/chromium/cc/resources/raster_mode.cc
@@ -12,19 +12,16 @@ namespace cc {
scoped_ptr<base::Value> RasterModeAsValue(RasterMode raster_mode) {
switch (raster_mode) {
- case HIGH_QUALITY_NO_LCD_RASTER_MODE:
- return scoped_ptr<base::Value>(
- base::Value::CreateStringValue("HIGH_QUALITY_NO_LCD_RASTER_MODE"));
case HIGH_QUALITY_RASTER_MODE:
return scoped_ptr<base::Value>(
- base::Value::CreateStringValue("HIGH_QUALITY_RASTER_MODE"));
+ new base::StringValue("HIGH_QUALITY_RASTER_MODE"));
case LOW_QUALITY_RASTER_MODE:
return scoped_ptr<base::Value>(
- base::Value::CreateStringValue("LOW_QUALITY_RASTER_MODE"));
+ new base::StringValue("LOW_QUALITY_RASTER_MODE"));
default:
NOTREACHED() << "Unrecognized RasterMode value " << raster_mode;
return scoped_ptr<base::Value>(
- base::Value::CreateStringValue("<unknown RasterMode value>"));
+ new base::StringValue("<unknown RasterMode value>"));
}
}
diff --git a/chromium/cc/resources/raster_mode.h b/chromium/cc/resources/raster_mode.h
index 9868059e0b7..0a2b4c9b076 100644
--- a/chromium/cc/resources/raster_mode.h
+++ b/chromium/cc/resources/raster_mode.h
@@ -13,15 +13,12 @@ class Value;
namespace cc {
-// Low quality implies no lcd test;
-// high quality implies lcd text.
// Note that the order of these matters, from "better" to "worse" in terms of
// quality.
enum RasterMode {
- HIGH_QUALITY_NO_LCD_RASTER_MODE = 0,
- HIGH_QUALITY_RASTER_MODE = 1,
- LOW_QUALITY_RASTER_MODE = 2,
- NUM_RASTER_MODES = 3
+ HIGH_QUALITY_RASTER_MODE = 0,
+ LOW_QUALITY_RASTER_MODE = 1,
+ NUM_RASTER_MODES = 2
};
scoped_ptr<base::Value> RasterModeAsValue(RasterMode mode);
diff --git a/chromium/cc/resources/raster_worker_pool.cc b/chromium/cc/resources/raster_worker_pool.cc
index 06fd18e62e0..d01bdc80cf4 100644
--- a/chromium/cc/resources/raster_worker_pool.cc
+++ b/chromium/cc/resources/raster_worker_pool.cc
@@ -4,593 +4,287 @@
#include "cc/resources/raster_worker_pool.h"
-#include "base/json/json_writer.h"
-#include "base/metrics/histogram.h"
-#include "base/values.h"
-#include "cc/debug/devtools_instrumentation.h"
-#include "cc/debug/traced_value.h"
-#include "cc/resources/picture_pile_impl.h"
-#include "skia/ext/lazy_pixel_ref.h"
-#include "skia/ext/paint_simplifier.h"
-#include "third_party/skia/include/core/SkBitmap.h"
+#include <algorithm>
-namespace cc {
+#include "base/atomic_sequence_num.h"
+#include "base/debug/trace_event_synthetic_delay.h"
+#include "base/lazy_instance.h"
+#include "base/strings/stringprintf.h"
+#include "base/threading/simple_thread.h"
+#include "base/threading/thread_local.h"
+#include "cc/base/scoped_ptr_deque.h"
+namespace cc {
namespace {
-// Subclass of Allocator that takes a suitably allocated pointer and uses
-// it as the pixel memory for the bitmap.
-class IdentityAllocator : public SkBitmap::Allocator {
- public:
- explicit IdentityAllocator(void* buffer) : buffer_(buffer) {}
- virtual bool allocPixelRef(SkBitmap* dst, SkColorTable*) OVERRIDE {
- dst->setPixels(buffer_);
- return true;
- }
- private:
- void* buffer_;
-};
-
-// Flag to indicate whether we should try and detect that
-// a tile is of solid color.
-const bool kUseColorEstimator = true;
-
-class DisableLCDTextFilter : public SkDrawFilter {
- public:
- // SkDrawFilter interface.
- virtual bool filter(SkPaint* paint, SkDrawFilter::Type type) OVERRIDE {
- if (type != SkDrawFilter::kText_Type)
- return true;
-
- paint->setLCDRenderText(false);
- return true;
- }
+// Synthetic delay for raster tasks that are required for activation. Global to
+// avoid static initializer on critical path.
+struct RasterRequiredForActivationSyntheticDelayInitializer {
+ RasterRequiredForActivationSyntheticDelayInitializer()
+ : delay(base::debug::TraceEventSyntheticDelay::Lookup(
+ "cc.RasterRequiredForActivation")) {}
+ base::debug::TraceEventSyntheticDelay* delay;
};
+static base::LazyInstance<RasterRequiredForActivationSyntheticDelayInitializer>
+ g_raster_required_for_activation_delay = LAZY_INSTANCE_INITIALIZER;
-class RasterWorkerPoolTaskImpl : public internal::RasterWorkerPoolTask {
+class RasterTaskGraphRunner : public TaskGraphRunner,
+ public base::DelegateSimpleThread::Delegate {
public:
- RasterWorkerPoolTaskImpl(const Resource* resource,
- PicturePileImpl* picture_pile,
- gfx::Rect content_rect,
- float contents_scale,
- RasterMode raster_mode,
- TileResolution tile_resolution,
- int layer_id,
- const void* tile_id,
- int source_frame_number,
- RenderingStatsInstrumentation* rendering_stats,
- const RasterWorkerPool::RasterTask::Reply& reply,
- TaskVector* dependencies)
- : internal::RasterWorkerPoolTask(resource, dependencies),
- picture_pile_(picture_pile),
- content_rect_(content_rect),
- contents_scale_(contents_scale),
- raster_mode_(raster_mode),
- tile_resolution_(tile_resolution),
- layer_id_(layer_id),
- tile_id_(tile_id),
- source_frame_number_(source_frame_number),
- rendering_stats_(rendering_stats),
- reply_(reply) {}
-
- void RunAnalysisOnThread(unsigned thread_index) {
- TRACE_EVENT1("cc",
- "RasterWorkerPoolTaskImpl::RunAnalysisOnThread",
- "data",
- TracedValue::FromValue(DataAsValue().release()));
-
- DCHECK(picture_pile_.get());
- DCHECK(rendering_stats_);
-
- PicturePileImpl* picture_clone =
- picture_pile_->GetCloneForDrawingOnThread(thread_index);
-
- DCHECK(picture_clone);
-
- picture_clone->AnalyzeInRect(
- content_rect_, contents_scale_, &analysis_, rendering_stats_);
-
- // Record the solid color prediction.
- UMA_HISTOGRAM_BOOLEAN("Renderer4.SolidColorTilesAnalyzed",
- analysis_.is_solid_color);
-
- // Clear the flag if we're not using the estimator.
- analysis_.is_solid_color &= kUseColorEstimator;
- }
-
- bool RunRasterOnThread(unsigned thread_index,
- void* buffer,
- gfx::Size size,
- int stride) {
- TRACE_EVENT2(
- "cc", "RasterWorkerPoolTaskImpl::RunRasterOnThread",
- "data",
- TracedValue::FromValue(DataAsValue().release()),
- "raster_mode",
- TracedValue::FromValue(RasterModeAsValue(raster_mode_).release()));
-
- devtools_instrumentation::ScopedLayerTask raster_task(
- devtools_instrumentation::kRasterTask, layer_id_);
-
- DCHECK(picture_pile_.get());
- DCHECK(buffer);
-
- if (analysis_.is_solid_color)
- return false;
-
- PicturePileImpl* picture_clone =
- picture_pile_->GetCloneForDrawingOnThread(thread_index);
-
- SkBitmap bitmap;
- switch (resource()->format()) {
- case RGBA_4444:
- // Use the default stride if we will eventually convert this
- // bitmap to 4444.
- bitmap.setConfig(SkBitmap::kARGB_8888_Config,
- size.width(),
- size.height());
- bitmap.allocPixels();
- break;
- case RGBA_8888:
- case BGRA_8888:
- bitmap.setConfig(SkBitmap::kARGB_8888_Config,
- size.width(),
- size.height(),
- stride);
- bitmap.setPixels(buffer);
- break;
- case LUMINANCE_8:
- case RGB_565:
- case ETC1:
- NOTREACHED();
- break;
- }
-
- SkBitmapDevice device(bitmap);
- SkCanvas canvas(&device);
- skia::RefPtr<SkDrawFilter> draw_filter;
- switch (raster_mode_) {
- case LOW_QUALITY_RASTER_MODE:
- draw_filter = skia::AdoptRef(new skia::PaintSimplifier);
- break;
- case HIGH_QUALITY_NO_LCD_RASTER_MODE:
- draw_filter = skia::AdoptRef(new DisableLCDTextFilter);
- break;
- case HIGH_QUALITY_RASTER_MODE:
- break;
- case NUM_RASTER_MODES:
- default:
- NOTREACHED();
- }
-
- canvas.setDrawFilter(draw_filter.get());
-
- base::TimeDelta prev_rasterize_time =
- rendering_stats_->impl_thread_rendering_stats().rasterize_time;
-
- // Only record rasterization time for highres tiles, because
- // lowres tiles are not required for activation and therefore
- // introduce noise in the measurement (sometimes they get rasterized
- // before we draw and sometimes they aren't)
- if (tile_resolution_ == HIGH_RESOLUTION) {
- picture_clone->RasterToBitmap(
- &canvas, content_rect_, contents_scale_, rendering_stats_);
- } else {
- picture_clone->RasterToBitmap(
- &canvas, content_rect_, contents_scale_, NULL);
- }
-
- if (rendering_stats_->record_rendering_stats()) {
- base::TimeDelta current_rasterize_time =
- rendering_stats_->impl_thread_rendering_stats().rasterize_time;
- HISTOGRAM_CUSTOM_COUNTS(
- "Renderer4.PictureRasterTimeUS",
- (current_rasterize_time - prev_rasterize_time).InMicroseconds(),
- 0,
- 100000,
- 100);
+ RasterTaskGraphRunner() {
+ size_t num_threads = RasterWorkerPool::GetNumRasterThreads();
+ while (workers_.size() < num_threads) {
+ scoped_ptr<base::DelegateSimpleThread> worker =
+ make_scoped_ptr(new base::DelegateSimpleThread(
+ this,
+ base::StringPrintf("CompositorRasterWorker%u",
+ static_cast<unsigned>(workers_.size() + 1))
+ .c_str()));
+ worker->Start();
+#if defined(OS_ANDROID) || defined(OS_LINUX)
+ worker->SetThreadPriority(base::kThreadPriority_Background);
+#endif
+ workers_.push_back(worker.Pass());
}
+ }
- ChangeBitmapConfigIfNeeded(bitmap, buffer);
+ virtual ~RasterTaskGraphRunner() { NOTREACHED(); }
- return true;
+ size_t GetPictureCloneIndexForCurrentThread() {
+ // Use index 0 if called on non-raster thread.
+ ThreadLocalState* thread_local_state = current_tls_.Get();
+ return thread_local_state ? current_tls_.Get()->picture_clone_index : 0;
}
- // Overridden from internal::RasterWorkerPoolTask:
- virtual bool RunOnWorkerThread(unsigned thread_index,
- void* buffer,
- gfx::Size size,
- int stride)
- OVERRIDE {
- RunAnalysisOnThread(thread_index);
- return RunRasterOnThread(thread_index, buffer, size, stride);
- }
- virtual void CompleteOnOriginThread() OVERRIDE {
- reply_.Run(analysis_, !HasFinishedRunning() || WasCanceled());
+ private:
+ struct ThreadLocalState {
+ explicit ThreadLocalState(size_t picture_clone_index)
+ : picture_clone_index(picture_clone_index) {}
+
+ size_t picture_clone_index;
+ };
+
+ // Overridden from base::DelegateSimpleThread::Delegate:
+ virtual void Run() OVERRIDE {
+ // Use picture clone index 0..num_threads.
+ int picture_clone_index = picture_clone_index_sequence_.GetNext();
+ DCHECK_LE(0, picture_clone_index);
+ DCHECK_GT(RasterWorkerPool::GetNumRasterThreads(), picture_clone_index);
+ current_tls_.Set(new ThreadLocalState(picture_clone_index));
+
+ TaskGraphRunner::Run();
}
- protected:
- virtual ~RasterWorkerPoolTaskImpl() {}
+ ScopedPtrDeque<base::DelegateSimpleThread> workers_;
+ base::AtomicSequenceNumber picture_clone_index_sequence_;
+ base::ThreadLocalPointer<ThreadLocalState> current_tls_;
+};
- private:
- scoped_ptr<base::Value> DataAsValue() const {
- scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue());
- res->Set("tile_id", TracedValue::CreateIDRef(tile_id_).release());
- res->Set("resolution", TileResolutionAsValue(tile_resolution_).release());
- res->SetInteger("source_frame_number", source_frame_number_);
- res->SetInteger("layer_id", layer_id_);
- return res.PassAs<base::Value>();
- }
+base::LazyInstance<RasterTaskGraphRunner>::Leaky g_task_graph_runner =
+ LAZY_INSTANCE_INITIALIZER;
- void ChangeBitmapConfigIfNeeded(const SkBitmap& bitmap,
- void* buffer) {
- TRACE_EVENT0("cc", "RasterWorkerPoolTaskImpl::ChangeBitmapConfigIfNeeded");
- SkBitmap::Config config = SkBitmapConfig(resource()->format());
- if (bitmap.getConfig() != config) {
- SkBitmap bitmap_dest;
- IdentityAllocator allocator(buffer);
- bitmap.copyTo(&bitmap_dest, config, &allocator);
- // TODO(kaanb): The GL pipeline assumes a 4-byte alignment for the
- // bitmap data. This check will be removed once crbug.com/293728 is fixed.
- CHECK_EQ(0u, bitmap_dest.rowBytes() % 4);
- }
- }
+const int kDefaultNumRasterThreads = 1;
- PicturePileImpl::Analysis analysis_;
- scoped_refptr<PicturePileImpl> picture_pile_;
- gfx::Rect content_rect_;
- float contents_scale_;
- RasterMode raster_mode_;
- TileResolution tile_resolution_;
- int layer_id_;
- const void* tile_id_;
- int source_frame_number_;
- RenderingStatsInstrumentation* rendering_stats_;
- const RasterWorkerPool::RasterTask::Reply reply_;
-
- DISALLOW_COPY_AND_ASSIGN(RasterWorkerPoolTaskImpl);
-};
+int g_num_raster_threads = 0;
-class ImageDecodeWorkerPoolTaskImpl : public internal::WorkerPoolTask {
+class RasterFinishedTaskImpl : public RasterizerTask {
public:
- ImageDecodeWorkerPoolTaskImpl(skia::LazyPixelRef* pixel_ref,
- int layer_id,
- RenderingStatsInstrumentation* rendering_stats,
- const RasterWorkerPool::Task::Reply& reply)
- : pixel_ref_(skia::SharePtr(pixel_ref)),
- layer_id_(layer_id),
- rendering_stats_(rendering_stats),
- reply_(reply) {}
-
- // Overridden from internal::WorkerPoolTask:
- virtual void RunOnWorkerThread(unsigned thread_index) OVERRIDE {
- TRACE_EVENT0("cc", "ImageDecodeWorkerPoolTaskImpl::RunOnWorkerThread");
- devtools_instrumentation::ScopedImageDecodeTask image_decode_task(
- pixel_ref_.get());
- pixel_ref_->Decode();
- }
- virtual void CompleteOnOriginThread() OVERRIDE {
- reply_.Run(!HasFinishedRunning());
+ explicit RasterFinishedTaskImpl(
+ base::SequencedTaskRunner* task_runner,
+ const base::Closure& on_raster_finished_callback)
+ : task_runner_(task_runner),
+ on_raster_finished_callback_(on_raster_finished_callback) {}
+
+ // Overridden from Task:
+ virtual void RunOnWorkerThread() OVERRIDE {
+ TRACE_EVENT0("cc", "RasterFinishedTaskImpl::RunOnWorkerThread");
+ RasterFinished();
}
+ // Overridden from RasterizerTask:
+ virtual void ScheduleOnOriginThread(RasterizerTaskClient* client) OVERRIDE {}
+ virtual void CompleteOnOriginThread(RasterizerTaskClient* client) OVERRIDE {}
+ virtual void RunReplyOnOriginThread() OVERRIDE {}
+
protected:
- virtual ~ImageDecodeWorkerPoolTaskImpl() {}
+ virtual ~RasterFinishedTaskImpl() {}
+
+ void RasterFinished() {
+ task_runner_->PostTask(FROM_HERE, on_raster_finished_callback_);
+ }
private:
- skia::RefPtr<skia::LazyPixelRef> pixel_ref_;
- int layer_id_;
- RenderingStatsInstrumentation* rendering_stats_;
- const RasterWorkerPool::Task::Reply reply_;
+ scoped_refptr<base::SequencedTaskRunner> task_runner_;
+ const base::Closure on_raster_finished_callback_;
- DISALLOW_COPY_AND_ASSIGN(ImageDecodeWorkerPoolTaskImpl);
+ DISALLOW_COPY_AND_ASSIGN(RasterFinishedTaskImpl);
};
-class RasterFinishedWorkerPoolTaskImpl : public internal::WorkerPoolTask {
+class RasterRequiredForActivationFinishedTaskImpl
+ : public RasterFinishedTaskImpl {
public:
- typedef base::Callback<void(const internal::WorkerPoolTask* source)>
- Callback;
-
- RasterFinishedWorkerPoolTaskImpl(
- const Callback& on_raster_finished_callback)
- : origin_loop_(base::MessageLoopProxy::current().get()),
- on_raster_finished_callback_(on_raster_finished_callback) {
+ RasterRequiredForActivationFinishedTaskImpl(
+ base::SequencedTaskRunner* task_runner,
+ const base::Closure& on_raster_finished_callback,
+ size_t tasks_required_for_activation_count)
+ : RasterFinishedTaskImpl(task_runner, on_raster_finished_callback),
+ tasks_required_for_activation_count_(
+ tasks_required_for_activation_count) {
+ if (tasks_required_for_activation_count_) {
+ g_raster_required_for_activation_delay.Get().delay->BeginParallel(
+ &activation_delay_end_time_);
+ }
}
- // Overridden from internal::WorkerPoolTask:
- virtual void RunOnWorkerThread(unsigned thread_index) OVERRIDE {
- TRACE_EVENT0("cc", "RasterFinishedWorkerPoolTaskImpl::RunOnWorkerThread");
- origin_loop_->PostTask(
- FROM_HERE,
- base::Bind(&RasterFinishedWorkerPoolTaskImpl::RunOnOriginThread,
- this));
+ // Overridden from Task:
+ virtual void RunOnWorkerThread() OVERRIDE {
+ TRACE_EVENT0(
+ "cc", "RasterRequiredForActivationFinishedTaskImpl::RunOnWorkerThread");
+
+ if (tasks_required_for_activation_count_) {
+ g_raster_required_for_activation_delay.Get().delay->EndParallel(
+ activation_delay_end_time_);
+ }
+ RasterFinished();
}
- virtual void CompleteOnOriginThread() OVERRIDE {}
private:
- virtual ~RasterFinishedWorkerPoolTaskImpl() {}
+ virtual ~RasterRequiredForActivationFinishedTaskImpl() {}
- void RunOnOriginThread() const {
- on_raster_finished_callback_.Run(this);
- }
+ base::TimeTicks activation_delay_end_time_;
+ const size_t tasks_required_for_activation_count_;
- scoped_refptr<base::MessageLoopProxy> origin_loop_;
- const Callback on_raster_finished_callback_;
-
- DISALLOW_COPY_AND_ASSIGN(RasterFinishedWorkerPoolTaskImpl);
+ DISALLOW_COPY_AND_ASSIGN(RasterRequiredForActivationFinishedTaskImpl);
};
-const char* kWorkerThreadNamePrefix = "CompositorRaster";
-
} // namespace
-namespace internal {
-
-RasterWorkerPoolTask::RasterWorkerPoolTask(
- const Resource* resource, TaskVector* dependencies)
- : did_run_(false),
- did_complete_(false),
- was_canceled_(false),
- resource_(resource) {
- dependencies_.swap(*dependencies);
-}
-
-RasterWorkerPoolTask::~RasterWorkerPoolTask() {
-}
-
-void RasterWorkerPoolTask::DidRun(bool was_canceled) {
- DCHECK(!did_run_);
- did_run_ = true;
- was_canceled_ = was_canceled;
-}
-
-bool RasterWorkerPoolTask::HasFinishedRunning() const {
- return did_run_;
-}
-
-bool RasterWorkerPoolTask::WasCanceled() const {
- return was_canceled_;
-}
-
-void RasterWorkerPoolTask::WillComplete() {
- DCHECK(!did_complete_);
-}
-
-void RasterWorkerPoolTask::DidComplete() {
- DCHECK(!did_complete_);
- did_complete_ = true;
-}
-
-bool RasterWorkerPoolTask::HasCompleted() const {
- return did_complete_;
-}
-
-} // namespace internal
-
-RasterWorkerPool::Task::Set::Set() {
-}
-
-RasterWorkerPool::Task::Set::~Set() {
-}
-
-void RasterWorkerPool::Task::Set::Insert(const Task& task) {
- DCHECK(!task.is_null());
- tasks_.push_back(task.internal_);
-}
+// This allows an external rasterize on-demand system to run raster tasks
+// with highest priority using the same task graph runner instance.
+unsigned RasterWorkerPool::kOnDemandRasterTaskPriority = 0u;
+// This allows a micro benchmark system to run tasks with highest priority,
+// since it should finish as quickly as possible.
+unsigned RasterWorkerPool::kBenchmarkRasterTaskPriority = 0u;
+// Task priorities that make sure raster finished tasks run before any
+// remaining raster tasks.
+unsigned RasterWorkerPool::kRasterFinishedTaskPriority = 2u;
+unsigned RasterWorkerPool::kRasterRequiredForActivationFinishedTaskPriority =
+ 1u;
+unsigned RasterWorkerPool::kRasterTaskPriorityBase = 3u;
-RasterWorkerPool::Task::Task() {
-}
+RasterWorkerPool::RasterWorkerPool() {}
-RasterWorkerPool::Task::Task(internal::WorkerPoolTask* internal)
- : internal_(internal) {
-}
+RasterWorkerPool::~RasterWorkerPool() {}
-RasterWorkerPool::Task::~Task() {
-}
-
-void RasterWorkerPool::Task::Reset() {
- internal_ = NULL;
-}
-
-RasterWorkerPool::RasterTask::Queue::Queue() {
-}
-
-RasterWorkerPool::RasterTask::Queue::~Queue() {
-}
-
-void RasterWorkerPool::RasterTask::Queue::Append(
- const RasterTask& task, bool required_for_activation) {
- DCHECK(!task.is_null());
- tasks_.push_back(task.internal_);
- if (required_for_activation)
- tasks_required_for_activation_.insert(task.internal_.get());
-}
-
-RasterWorkerPool::RasterTask::RasterTask() {
-}
+// static
+void RasterWorkerPool::SetNumRasterThreads(int num_threads) {
+ DCHECK_LT(0, num_threads);
+ DCHECK_EQ(0, g_num_raster_threads);
-RasterWorkerPool::RasterTask::RasterTask(
- internal::RasterWorkerPoolTask* internal)
- : internal_(internal) {
+ g_num_raster_threads = num_threads;
}
-void RasterWorkerPool::RasterTask::Reset() {
- internal_ = NULL;
-}
+// static
+int RasterWorkerPool::GetNumRasterThreads() {
+ if (!g_num_raster_threads)
+ g_num_raster_threads = kDefaultNumRasterThreads;
-RasterWorkerPool::RasterTask::~RasterTask() {
+ return g_num_raster_threads;
}
// static
-RasterWorkerPool::RasterTask RasterWorkerPool::CreateRasterTask(
- const Resource* resource,
- PicturePileImpl* picture_pile,
- gfx::Rect content_rect,
- float contents_scale,
- RasterMode raster_mode,
- TileResolution tile_resolution,
- int layer_id,
- const void* tile_id,
- int source_frame_number,
- RenderingStatsInstrumentation* rendering_stats,
- const RasterTask::Reply& reply,
- Task::Set* dependencies) {
- return RasterTask(
- new RasterWorkerPoolTaskImpl(resource,
- picture_pile,
- content_rect,
- contents_scale,
- raster_mode,
- tile_resolution,
- layer_id,
- tile_id,
- source_frame_number,
- rendering_stats,
- reply,
- &dependencies->tasks_));
+TaskGraphRunner* RasterWorkerPool::GetTaskGraphRunner() {
+ return g_task_graph_runner.Pointer();
}
// static
-RasterWorkerPool::Task RasterWorkerPool::CreateImageDecodeTask(
- skia::LazyPixelRef* pixel_ref,
- int layer_id,
- RenderingStatsInstrumentation* stats_instrumentation,
- const Task::Reply& reply) {
- return Task(new ImageDecodeWorkerPoolTaskImpl(pixel_ref,
- layer_id,
- stats_instrumentation,
- reply));
-}
-
-RasterWorkerPool::RasterWorkerPool(ResourceProvider* resource_provider,
- size_t num_threads)
- : WorkerPool(num_threads, kWorkerThreadNamePrefix),
- client_(NULL),
- resource_provider_(resource_provider),
- weak_ptr_factory_(this) {
+size_t RasterWorkerPool::GetPictureCloneIndexForCurrentThread() {
+ return g_task_graph_runner.Pointer()->GetPictureCloneIndexForCurrentThread();
}
-RasterWorkerPool::~RasterWorkerPool() {
-}
-
-void RasterWorkerPool::SetClient(RasterWorkerPoolClient* client) {
- client_ = client;
-}
-
-void RasterWorkerPool::Shutdown() {
- raster_tasks_.clear();
- TaskGraph empty;
- SetTaskGraph(&empty);
- WorkerPool::Shutdown();
- weak_ptr_factory_.InvalidateWeakPtrs();
-}
-
-void RasterWorkerPool::SetRasterTasks(RasterTask::Queue* queue) {
- raster_tasks_.swap(queue->tasks_);
- raster_tasks_required_for_activation_.swap(
- queue->tasks_required_for_activation_);
-}
-
-bool RasterWorkerPool::IsRasterTaskRequiredForActivation(
- internal::RasterWorkerPoolTask* task) const {
- return
- raster_tasks_required_for_activation_.find(task) !=
- raster_tasks_required_for_activation_.end();
-}
-
-scoped_refptr<internal::WorkerPoolTask>
- RasterWorkerPool::CreateRasterFinishedTask() {
- return make_scoped_refptr(
- new RasterFinishedWorkerPoolTaskImpl(
- base::Bind(&RasterWorkerPool::OnRasterFinished,
- weak_ptr_factory_.GetWeakPtr())));
-}
-
-scoped_refptr<internal::WorkerPoolTask>
- RasterWorkerPool::CreateRasterRequiredForActivationFinishedTask() {
+// static
+scoped_refptr<RasterizerTask> RasterWorkerPool::CreateRasterFinishedTask(
+ base::SequencedTaskRunner* task_runner,
+ const base::Closure& on_raster_finished_callback) {
return make_scoped_refptr(
- new RasterFinishedWorkerPoolTaskImpl(
- base::Bind(&RasterWorkerPool::OnRasterRequiredForActivationFinished,
- weak_ptr_factory_.GetWeakPtr())));
+ new RasterFinishedTaskImpl(task_runner, on_raster_finished_callback));
}
-void RasterWorkerPool::OnRasterFinished(
- const internal::WorkerPoolTask* source) {
- TRACE_EVENT0("cc", "RasterWorkerPool::OnRasterFinished");
-
- // Early out if current |raster_finished_task_| is not the source.
- if (source != raster_finished_task_.get())
- return;
-
- OnRasterTasksFinished();
-}
-
-void RasterWorkerPool::OnRasterRequiredForActivationFinished(
- const internal::WorkerPoolTask* source) {
- TRACE_EVENT0("cc", "RasterWorkerPool::OnRasterRequiredForActivationFinished");
-
- // Early out if current |raster_required_for_activation_finished_task_|
- // is not the source.
- if (source != raster_required_for_activation_finished_task_.get())
- return;
-
- OnRasterTasksRequiredForActivationFinished();
+// static
+scoped_refptr<RasterizerTask>
+RasterWorkerPool::CreateRasterRequiredForActivationFinishedTask(
+ size_t tasks_required_for_activation_count,
+ base::SequencedTaskRunner* task_runner,
+ const base::Closure& on_raster_finished_callback) {
+ return make_scoped_refptr(new RasterRequiredForActivationFinishedTaskImpl(
+ task_runner,
+ on_raster_finished_callback,
+ tasks_required_for_activation_count));
}
-scoped_ptr<base::Value> RasterWorkerPool::ScheduledStateAsValue() const {
- scoped_ptr<base::DictionaryValue> scheduled_state(new base::DictionaryValue);
- scheduled_state->SetInteger("task_count", raster_tasks_.size());
- scheduled_state->SetInteger("task_required_for_activation_count",
- raster_tasks_required_for_activation_.size());
- return scheduled_state.PassAs<base::Value>();
+// static
+void RasterWorkerPool::ScheduleTasksOnOriginThread(RasterizerTaskClient* client,
+ TaskGraph* graph) {
+ TRACE_EVENT0("cc", "Rasterizer::ScheduleTasksOnOriginThread");
+
+ for (TaskGraph::Node::Vector::iterator it = graph->nodes.begin();
+ it != graph->nodes.end();
+ ++it) {
+ TaskGraph::Node& node = *it;
+ RasterizerTask* task = static_cast<RasterizerTask*>(node.task);
+
+ if (!task->HasBeenScheduled()) {
+ task->WillSchedule();
+ task->ScheduleOnOriginThread(client);
+ task->DidSchedule();
+ }
+ }
}
// static
-internal::GraphNode* RasterWorkerPool::CreateGraphNodeForTask(
- internal::WorkerPoolTask* task,
- unsigned priority,
- TaskGraph* graph) {
- internal::GraphNode* node = new internal::GraphNode(task, priority);
- DCHECK(graph->find(task) == graph->end());
- graph->set(task, make_scoped_ptr(node));
- return node;
+void RasterWorkerPool::InsertNodeForTask(TaskGraph* graph,
+ RasterizerTask* task,
+ unsigned priority,
+ size_t dependencies) {
+ DCHECK(std::find_if(graph->nodes.begin(),
+ graph->nodes.end(),
+ TaskGraph::Node::TaskComparator(task)) ==
+ graph->nodes.end());
+ graph->nodes.push_back(TaskGraph::Node(task, priority, dependencies));
}
// static
-internal::GraphNode* RasterWorkerPool::CreateGraphNodeForRasterTask(
- internal::WorkerPoolTask* raster_task,
- const TaskVector& decode_tasks,
- unsigned priority,
- TaskGraph* graph) {
- DCHECK(!raster_task->HasCompleted());
-
- internal::GraphNode* raster_node = CreateGraphNodeForTask(
- raster_task, priority, graph);
+void RasterWorkerPool::InsertNodesForRasterTask(
+ TaskGraph* graph,
+ RasterTask* raster_task,
+ const ImageDecodeTask::Vector& decode_tasks,
+ unsigned priority) {
+ size_t dependencies = 0u;
// Insert image decode tasks.
- for (TaskVector::const_iterator it = decode_tasks.begin();
- it != decode_tasks.end(); ++it) {
- internal::WorkerPoolTask* decode_task = it->get();
+ for (ImageDecodeTask::Vector::const_iterator it = decode_tasks.begin();
+ it != decode_tasks.end();
+ ++it) {
+ ImageDecodeTask* decode_task = it->get();
// Skip if already decoded.
if (decode_task->HasCompleted())
continue;
- raster_node->add_dependency();
+ dependencies++;
- // Check if decode task already exists in graph.
- GraphNodeMap::iterator decode_it = graph->find(decode_task);
- if (decode_it != graph->end()) {
- internal::GraphNode* decode_node = decode_it->second;
- decode_node->add_dependent(raster_node);
- continue;
- }
+ // Add decode task if it doesn't already exists in graph.
+ TaskGraph::Node::Vector::iterator decode_it =
+ std::find_if(graph->nodes.begin(),
+ graph->nodes.end(),
+ TaskGraph::Node::TaskComparator(decode_task));
+ if (decode_it == graph->nodes.end())
+ InsertNodeForTask(graph, decode_task, priority, 0u);
- internal::GraphNode* decode_node = CreateGraphNodeForTask(
- decode_task, priority, graph);
- decode_node->add_dependent(raster_node);
+ graph->edges.push_back(TaskGraph::Edge(decode_task, raster_task));
}
- return raster_node;
+ InsertNodeForTask(graph, raster_task, priority, dependencies);
}
} // namespace cc
diff --git a/chromium/cc/resources/raster_worker_pool.h b/chromium/cc/resources/raster_worker_pool.h
index fac2fd845ce..2c543a0d0c4 100644
--- a/chromium/cc/resources/raster_worker_pool.h
+++ b/chromium/cc/resources/raster_worker_pool.h
@@ -5,276 +5,77 @@
#ifndef CC_RESOURCES_RASTER_WORKER_POOL_H_
#define CC_RESOURCES_RASTER_WORKER_POOL_H_
-#include <vector>
+#include "cc/resources/rasterizer.h"
-#include "base/containers/hash_tables.h"
-#include "cc/debug/rendering_stats_instrumentation.h"
-#include "cc/resources/picture_pile_impl.h"
-#include "cc/resources/raster_mode.h"
-#include "cc/resources/resource.h"
-#include "cc/resources/resource_provider.h"
-#include "cc/resources/tile_priority.h"
-#include "cc/resources/worker_pool.h"
-#include "third_party/khronos/GLES2/gl2.h"
-
-namespace skia {
-class LazyPixelRef;
+namespace base {
+class SequencedTaskRunner;
}
namespace cc {
-namespace internal {
-
-class CC_EXPORT RasterWorkerPoolTask
- : public base::RefCounted<RasterWorkerPoolTask> {
- public:
- typedef std::vector<scoped_refptr<WorkerPoolTask> > TaskVector;
-
- // Returns true if |buffer| was written to. False indicate that
- // the content of |buffer| is undefined and the resource doesn't
- // need to be initialized.
- virtual bool RunOnWorkerThread(unsigned thread_index,
- void* buffer,
- gfx::Size size,
- int stride) = 0;
- virtual void CompleteOnOriginThread() = 0;
-
- void DidRun(bool was_canceled);
- bool HasFinishedRunning() const;
- bool WasCanceled() const;
- void WillComplete();
- void DidComplete();
- bool HasCompleted() const;
-
- const Resource* resource() const { return resource_; }
- const TaskVector& dependencies() const { return dependencies_; }
-
- protected:
- friend class base::RefCounted<RasterWorkerPoolTask>;
-
- RasterWorkerPoolTask(const Resource* resource, TaskVector* dependencies);
- virtual ~RasterWorkerPoolTask();
-
- private:
- bool did_run_;
- bool did_complete_;
- bool was_canceled_;
- const Resource* resource_;
- TaskVector dependencies_;
-};
-
-} // namespace internal
-} // namespace cc
-
-#if defined(COMPILER_GCC)
-namespace BASE_HASH_NAMESPACE {
-template <> struct hash<cc::internal::RasterWorkerPoolTask*> {
- size_t operator()(cc::internal::RasterWorkerPoolTask* ptr) const {
- return hash<size_t>()(reinterpret_cast<size_t>(ptr));
- }
-};
-} // namespace BASE_HASH_NAMESPACE
-#endif // COMPILER
-
-namespace cc {
-
-class CC_EXPORT RasterWorkerPoolClient {
- public:
- virtual bool ShouldForceTasksRequiredForActivationToComplete() const = 0;
- virtual void DidFinishRunningTasks() = 0;
- virtual void DidFinishRunningTasksRequiredForActivation() = 0;
-
- protected:
- virtual ~RasterWorkerPoolClient() {}
-};
-// A worker thread pool that runs raster tasks.
-class CC_EXPORT RasterWorkerPool : public WorkerPool {
+class CC_EXPORT RasterWorkerPool {
public:
- class CC_EXPORT Task {
- public:
- typedef base::Callback<void(bool was_canceled)> Reply;
-
- class CC_EXPORT Set {
- public:
- Set();
- ~Set();
-
- void Insert(const Task& task);
-
- private:
- friend class RasterWorkerPool;
- friend class RasterWorkerPoolTest;
-
- typedef internal::RasterWorkerPoolTask::TaskVector TaskVector;
- TaskVector tasks_;
- };
-
- Task();
- ~Task();
-
- // Returns true if Task is null (doesn't refer to anything).
- bool is_null() const { return !internal_.get(); }
-
- // Returns the Task into an uninitialized state.
- void Reset();
-
- protected:
- friend class RasterWorkerPool;
- friend class RasterWorkerPoolTest;
-
- explicit Task(internal::WorkerPoolTask* internal);
-
- scoped_refptr<internal::WorkerPoolTask> internal_;
- };
-
- class CC_EXPORT RasterTask {
- public:
- typedef base::Callback<void(const PicturePileImpl::Analysis& analysis,
- bool was_canceled)> Reply;
-
- class CC_EXPORT Queue {
- public:
- Queue();
- ~Queue();
-
- void Append(const RasterTask& task, bool required_for_activation);
-
- private:
- friend class RasterWorkerPool;
-
- typedef std::vector<scoped_refptr<internal::RasterWorkerPoolTask> >
- TaskVector;
- TaskVector tasks_;
- typedef base::hash_set<internal::RasterWorkerPoolTask*> TaskSet;
- TaskSet tasks_required_for_activation_;
- };
-
- RasterTask();
- ~RasterTask();
-
- // Returns true if Task is null (doesn't refer to anything).
- bool is_null() const { return !internal_.get(); }
-
- // Returns the Task into an uninitialized state.
- void Reset();
-
- protected:
- friend class RasterWorkerPool;
- friend class RasterWorkerPoolTest;
-
- explicit RasterTask(internal::RasterWorkerPoolTask* internal);
-
- scoped_refptr<internal::RasterWorkerPoolTask> internal_;
- };
+ static unsigned kOnDemandRasterTaskPriority;
+ static unsigned kBenchmarkRasterTaskPriority;
+ static unsigned kRasterFinishedTaskPriority;
+ static unsigned kRasterRequiredForActivationFinishedTaskPriority;
+ static unsigned kRasterTaskPriorityBase;
+ RasterWorkerPool();
virtual ~RasterWorkerPool();
- void SetClient(RasterWorkerPoolClient* client);
-
- // Tells the worker pool to shutdown after canceling all previously
- // scheduled tasks. Reply callbacks are still guaranteed to run.
- virtual void Shutdown() OVERRIDE;
-
- // Schedule running of raster tasks in |queue| and all dependencies.
- // Previously scheduled tasks that are no longer needed to run
- // raster tasks in |queue| will be canceled unless already running.
- // Once scheduled, reply callbacks are guaranteed to run for all tasks
- // even if they later get canceled by another call to ScheduleTasks().
- virtual void ScheduleTasks(RasterTask::Queue* queue) = 0;
-
- // Returns the target that needs to be used for raster task resources.
- virtual GLenum GetResourceTarget() const = 0;
-
- // Returns the format that needs to be used for raster task resources.
- virtual ResourceFormat GetResourceFormat() const = 0;
-
- // TODO(vmpstr): Figure out an elegant way to not pass this many parameters.
- static RasterTask CreateRasterTask(
- const Resource* resource,
- PicturePileImpl* picture_pile,
- gfx::Rect content_rect,
- float contents_scale,
- RasterMode raster_mode,
- TileResolution tile_resolution,
- int layer_id,
- const void* tile_id,
- int source_frame_number,
- RenderingStatsInstrumentation* rendering_stats,
- const RasterTask::Reply& reply,
- Task::Set* dependencies);
-
- static Task CreateImageDecodeTask(
- skia::LazyPixelRef* pixel_ref,
- int layer_id,
- RenderingStatsInstrumentation* stats_instrumentation,
- const Task::Reply& reply);
-
- protected:
- typedef std::vector<scoped_refptr<internal::WorkerPoolTask> > TaskVector;
- typedef std::vector<scoped_refptr<internal::RasterWorkerPoolTask> >
- RasterTaskVector;
- typedef base::hash_set<internal::RasterWorkerPoolTask*> RasterTaskSet;
- typedef internal::RasterWorkerPoolTask* TaskMapKey;
- typedef base::hash_map<TaskMapKey,
- scoped_refptr<internal::WorkerPoolTask> > TaskMap;
-
- RasterWorkerPool(ResourceProvider* resource_provider, size_t num_threads);
-
- virtual void OnRasterTasksFinished() = 0;
- virtual void OnRasterTasksRequiredForActivationFinished() = 0;
-
- void SetRasterTasks(RasterTask::Queue* queue);
- bool IsRasterTaskRequiredForActivation(
- internal::RasterWorkerPoolTask* task) const;
-
- RasterWorkerPoolClient* client() const { return client_; }
- ResourceProvider* resource_provider() const { return resource_provider_; }
- const RasterTaskVector& raster_tasks() const { return raster_tasks_; }
- const RasterTaskSet& raster_tasks_required_for_activation() const {
- return raster_tasks_required_for_activation_;
- }
- void set_raster_finished_task(
- scoped_refptr<internal::WorkerPoolTask> raster_finished_task) {
- raster_finished_task_ = raster_finished_task;
- }
- void set_raster_required_for_activation_finished_task(
- scoped_refptr<internal::WorkerPoolTask>
- raster_required_for_activation_finished_task) {
- raster_required_for_activation_finished_task_ =
- raster_required_for_activation_finished_task;
- }
-
- scoped_refptr<internal::WorkerPoolTask> CreateRasterFinishedTask();
- scoped_refptr<internal::WorkerPoolTask>
- CreateRasterRequiredForActivationFinishedTask();
-
- scoped_ptr<base::Value> ScheduledStateAsValue() const;
-
- static internal::GraphNode* CreateGraphNodeForTask(
- internal::WorkerPoolTask* task,
- unsigned priority,
- TaskGraph* graph);
-
- static internal::GraphNode* CreateGraphNodeForRasterTask(
- internal::WorkerPoolTask* raster_task,
- const TaskVector& decode_tasks,
- unsigned priority,
- TaskGraph* graph);
-
- private:
- void OnRasterFinished(const internal::WorkerPoolTask* source);
- void OnRasterRequiredForActivationFinished(
- const internal::WorkerPoolTask* source);
-
- RasterWorkerPoolClient* client_;
- ResourceProvider* resource_provider_;
- RasterTask::Queue::TaskVector raster_tasks_;
- RasterTask::Queue::TaskSet raster_tasks_required_for_activation_;
-
- scoped_refptr<internal::WorkerPoolTask> raster_finished_task_;
- scoped_refptr<internal::WorkerPoolTask>
- raster_required_for_activation_finished_task_;
- base::WeakPtrFactory<RasterWorkerPool> weak_ptr_factory_;
+ // Set the number of threads to use for the global TaskGraphRunner instance.
+ // This can only be called once and must be called prior to
+ // GetNumRasterThreads().
+ static void SetNumRasterThreads(int num_threads);
+
+ // Returns the number of threads used for the global TaskGraphRunner instance.
+ static int GetNumRasterThreads();
+
+ // Returns a pointer to the global TaskGraphRunner instance.
+ static TaskGraphRunner* GetTaskGraphRunner();
+
+ // Returns a unique clone index for the current thread. Guaranteed to be a
+ // value between 0 and GetNumRasterThreads() - 1.
+ static size_t GetPictureCloneIndexForCurrentThread();
+
+ // Utility function that can be used to create a "raster finished" task that
+ // posts |callback| to |task_runner| when run.
+ static scoped_refptr<RasterizerTask> CreateRasterFinishedTask(
+ base::SequencedTaskRunner* task_runner,
+ const base::Closure& callback);
+
+ // Utility function that can be used to create a "raster required for
+ // activation finished" task that posts |callback| to |task_runner| when run.
+ static scoped_refptr<RasterizerTask>
+ CreateRasterRequiredForActivationFinishedTask(
+ size_t tasks_required_for_activation_count,
+ base::SequencedTaskRunner* task_runner,
+ const base::Closure& callback);
+
+ // Utility function that can be used to call ::ScheduleOnOriginThread() for
+ // each task in |graph|.
+ static void ScheduleTasksOnOriginThread(RasterizerTaskClient* client,
+ TaskGraph* graph);
+
+ // Utility function that can be used to build a task graph. Inserts a node
+ // that represents |task| in |graph|. See TaskGraph definition for valid
+ // |priority| values.
+ static void InsertNodeForTask(TaskGraph* graph,
+ RasterizerTask* task,
+ unsigned priority,
+ size_t dependencies);
+
+ // Utility function that can be used to build a task graph. Inserts nodes that
+ // represent |task| and all its image decode dependencies in |graph|.
+ static void InsertNodesForRasterTask(
+ TaskGraph* graph,
+ RasterTask* task,
+ const ImageDecodeTask::Vector& decode_tasks,
+ unsigned priority);
+
+ // Type-checking downcast routine.
+ virtual Rasterizer* AsRasterizer() = 0;
};
} // namespace cc
diff --git a/chromium/cc/resources/raster_worker_pool_perftest.cc b/chromium/cc/resources/raster_worker_pool_perftest.cc
index 8b9c8e0b5f5..a0b63efaf61 100644
--- a/chromium/cc/resources/raster_worker_pool_perftest.cc
+++ b/chromium/cc/resources/raster_worker_pool_perftest.cc
@@ -5,220 +5,462 @@
#include "cc/resources/raster_worker_pool.h"
#include "base/time/time.h"
-#include "cc/test/lap_timer.h"
+#include "cc/debug/lap_timer.h"
+#include "cc/output/context_provider.h"
+#include "cc/resources/direct_raster_worker_pool.h"
+#include "cc/resources/image_copy_raster_worker_pool.h"
+#include "cc/resources/image_raster_worker_pool.h"
+#include "cc/resources/pixel_buffer_raster_worker_pool.h"
+#include "cc/resources/rasterizer.h"
+#include "cc/resources/resource_pool.h"
+#include "cc/resources/resource_provider.h"
+#include "cc/resources/scoped_resource.h"
+#include "cc/test/fake_output_surface.h"
+#include "cc/test/fake_output_surface_client.h"
+#include "cc/test/test_context_support.h"
+#include "cc/test/test_shared_bitmap_manager.h"
+#include "cc/test/test_web_graphics_context_3d.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/perf/perf_test.h"
+#include "third_party/khronos/GLES2/gl2.h"
namespace cc {
-
namespace {
+class PerfGLES2Interface : public gpu::gles2::GLES2InterfaceStub {
+ // Overridden from gpu::gles2::GLES2Interface:
+ virtual GLuint CreateImageCHROMIUM(GLsizei width,
+ GLsizei height,
+ GLenum internalformat,
+ GLenum usage) OVERRIDE {
+ return 1u;
+ }
+ virtual void GenBuffers(GLsizei n, GLuint* buffers) OVERRIDE {
+ for (GLsizei i = 0; i < n; ++i)
+ buffers[i] = 1u;
+ }
+ virtual void GenTextures(GLsizei n, GLuint* textures) OVERRIDE {
+ for (GLsizei i = 0; i < n; ++i)
+ textures[i] = 1u;
+ }
+ virtual void GetIntegerv(GLenum pname, GLint* params) OVERRIDE {
+ if (pname == GL_MAX_TEXTURE_SIZE)
+ *params = INT_MAX;
+ }
+};
+
+class PerfContextProvider : public ContextProvider {
+ public:
+ PerfContextProvider() : context_gl_(new PerfGLES2Interface) {}
+
+ virtual bool BindToCurrentThread() OVERRIDE { return true; }
+ virtual Capabilities ContextCapabilities() OVERRIDE { return Capabilities(); }
+ virtual gpu::gles2::GLES2Interface* ContextGL() OVERRIDE {
+ return context_gl_.get();
+ }
+ virtual gpu::ContextSupport* ContextSupport() OVERRIDE { return &support_; }
+ virtual class GrContext* GrContext() OVERRIDE { return NULL; }
+ virtual bool IsContextLost() OVERRIDE { return false; }
+ virtual void VerifyContexts() OVERRIDE {}
+ virtual void DeleteCachedResources() OVERRIDE {}
+ virtual bool DestroyedOnMainThread() OVERRIDE { return false; }
+ virtual void SetLostContextCallback(const LostContextCallback& cb) OVERRIDE {}
+ virtual void SetMemoryPolicyChangedCallback(
+ const MemoryPolicyChangedCallback& cb) OVERRIDE {}
+
+ private:
+ virtual ~PerfContextProvider() {}
+
+ scoped_ptr<PerfGLES2Interface> context_gl_;
+ TestContextSupport support_;
+};
+
+enum RasterWorkerPoolType {
+ RASTER_WORKER_POOL_TYPE_PIXEL_BUFFER,
+ RASTER_WORKER_POOL_TYPE_IMAGE,
+ RASTER_WORKER_POOL_TYPE_IMAGE_COPY,
+ RASTER_WORKER_POOL_TYPE_DIRECT
+};
+
static const int kTimeLimitMillis = 2000;
static const int kWarmupRuns = 5;
static const int kTimeCheckInterval = 10;
-class PerfWorkerPoolTaskImpl : public internal::WorkerPoolTask {
+class PerfImageDecodeTaskImpl : public ImageDecodeTask {
public:
- // Overridden from internal::WorkerPoolTask:
- virtual void RunOnWorkerThread(unsigned thread_index) OVERRIDE {}
- virtual void CompleteOnOriginThread() OVERRIDE {}
+ PerfImageDecodeTaskImpl() {}
+
+ // Overridden from Task:
+ virtual void RunOnWorkerThread() OVERRIDE {}
+
+ // Overridden from RasterizerTask:
+ virtual void ScheduleOnOriginThread(RasterizerTaskClient* client) OVERRIDE {}
+ virtual void CompleteOnOriginThread(RasterizerTaskClient* client) OVERRIDE {}
+ virtual void RunReplyOnOriginThread() OVERRIDE { Reset(); }
+
+ void Reset() {
+ did_run_ = false;
+ did_complete_ = false;
+ }
+
+ protected:
+ virtual ~PerfImageDecodeTaskImpl() {}
private:
- virtual ~PerfWorkerPoolTaskImpl() {}
+ DISALLOW_COPY_AND_ASSIGN(PerfImageDecodeTaskImpl);
};
-class PerfRasterWorkerPool : public RasterWorkerPool {
+class PerfRasterTaskImpl : public RasterTask {
public:
- PerfRasterWorkerPool() : RasterWorkerPool(NULL, 1) {}
- virtual ~PerfRasterWorkerPool() {}
+ PerfRasterTaskImpl(scoped_ptr<ScopedResource> resource,
+ ImageDecodeTask::Vector* dependencies)
+ : RasterTask(resource.get(), dependencies), resource_(resource.Pass()) {}
- static scoped_ptr<PerfRasterWorkerPool> Create() {
- return make_scoped_ptr(new PerfRasterWorkerPool);
- }
+ // Overridden from Task:
+ virtual void RunOnWorkerThread() OVERRIDE {}
- // Overridden from RasterWorkerPool:
- virtual void ScheduleTasks(RasterTask::Queue* queue) OVERRIDE {
- NOTREACHED();
+ // Overridden from RasterizerTask:
+ virtual void ScheduleOnOriginThread(RasterizerTaskClient* client) OVERRIDE {
+ client->AcquireCanvasForRaster(this);
}
- virtual GLenum GetResourceTarget() const OVERRIDE {
- NOTREACHED();
- return GL_TEXTURE_2D;
+ virtual void CompleteOnOriginThread(RasterizerTaskClient* client) OVERRIDE {
+ client->ReleaseCanvasForRaster(this);
}
- virtual ResourceFormat GetResourceFormat() const OVERRIDE {
- NOTREACHED();
- return RGBA_8888;
+ virtual void RunReplyOnOriginThread() OVERRIDE { Reset(); }
+
+ void Reset() {
+ did_run_ = false;
+ did_complete_ = false;
}
- virtual void OnRasterTasksFinished() OVERRIDE {
- NOTREACHED();
+
+ protected:
+ virtual ~PerfRasterTaskImpl() {}
+
+ private:
+ scoped_ptr<ScopedResource> resource_;
+
+ DISALLOW_COPY_AND_ASSIGN(PerfRasterTaskImpl);
+};
+
+class RasterWorkerPoolPerfTestBase {
+ public:
+ typedef std::vector<scoped_refptr<RasterTask> > RasterTaskVector;
+
+ RasterWorkerPoolPerfTestBase()
+ : context_provider_(make_scoped_refptr(new PerfContextProvider)),
+ task_graph_runner_(new TaskGraphRunner),
+ timer_(kWarmupRuns,
+ base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
+ kTimeCheckInterval) {
+ output_surface_ = FakeOutputSurface::Create3d(context_provider_).Pass();
+ CHECK(output_surface_->BindToClient(&output_surface_client_));
+
+ shared_bitmap_manager_.reset(new TestSharedBitmapManager());
+ resource_provider_ =
+ ResourceProvider::Create(
+ output_surface_.get(), shared_bitmap_manager_.get(), 0, false, 1,
+ false).Pass();
+ staging_resource_pool_ = ResourcePool::Create(
+ resource_provider_.get(), GL_TEXTURE_2D, RGBA_8888);
}
- virtual void OnRasterTasksRequiredForActivationFinished() OVERRIDE {
- NOTREACHED();
+
+ void CreateImageDecodeTasks(unsigned num_image_decode_tasks,
+ ImageDecodeTask::Vector* image_decode_tasks) {
+ for (unsigned i = 0; i < num_image_decode_tasks; ++i)
+ image_decode_tasks->push_back(new PerfImageDecodeTaskImpl);
}
- void SetRasterTasks(RasterTask::Queue* queue) {
- RasterWorkerPool::SetRasterTasks(queue);
+ void CreateRasterTasks(unsigned num_raster_tasks,
+ const ImageDecodeTask::Vector& image_decode_tasks,
+ RasterTaskVector* raster_tasks) {
+ const gfx::Size size(1, 1);
- TaskMap perf_tasks;
- for (RasterTaskVector::const_iterator it = raster_tasks().begin();
- it != raster_tasks().end(); ++it) {
- internal::RasterWorkerPoolTask* task = it->get();
+ for (unsigned i = 0; i < num_raster_tasks; ++i) {
+ scoped_ptr<ScopedResource> resource(
+ ScopedResource::Create(resource_provider_.get()));
+ resource->Allocate(size, ResourceProvider::TextureUsageAny, RGBA_8888);
- scoped_refptr<internal::WorkerPoolTask> new_perf_task(
- new PerfWorkerPoolTaskImpl);
- perf_tasks[task] = new_perf_task;
+ ImageDecodeTask::Vector dependencies = image_decode_tasks;
+ raster_tasks->push_back(
+ new PerfRasterTaskImpl(resource.Pass(), &dependencies));
}
+ }
- perf_tasks_.swap(perf_tasks);
- }
-
- void BuildTaskGraph() {
- unsigned priority = 0;
- TaskGraph graph;
-
- scoped_refptr<internal::WorkerPoolTask>
- raster_required_for_activation_finished_task(
- CreateRasterRequiredForActivationFinishedTask());
- internal::GraphNode* raster_required_for_activation_finished_node =
- CreateGraphNodeForTask(
- raster_required_for_activation_finished_task.get(),
- priority++,
- &graph);
-
- scoped_refptr<internal::WorkerPoolTask> raster_finished_task(
- CreateRasterFinishedTask());
- internal::GraphNode* raster_finished_node =
- CreateGraphNodeForTask(raster_finished_task.get(),
- priority++,
- &graph);
-
- for (RasterTaskVector::const_iterator it = raster_tasks().begin();
- it != raster_tasks().end(); ++it) {
- internal::RasterWorkerPoolTask* task = it->get();
-
- TaskMap::iterator perf_it = perf_tasks_.find(task);
- DCHECK(perf_it != perf_tasks_.end());
- if (perf_it != perf_tasks_.end()) {
- internal::WorkerPoolTask* perf_task = perf_it->second.get();
-
- internal::GraphNode* perf_node =
- CreateGraphNodeForRasterTask(perf_task,
- task->dependencies(),
- priority++,
- &graph);
-
- if (IsRasterTaskRequiredForActivation(task)) {
- raster_required_for_activation_finished_node->add_dependency();
- perf_node->add_dependent(
- raster_required_for_activation_finished_node);
- }
-
- raster_finished_node->add_dependency();
- perf_node->add_dependent(raster_finished_node);
- }
+ void BuildRasterTaskQueue(RasterTaskQueue* queue,
+ const RasterTaskVector& raster_tasks) {
+ for (size_t i = 0u; i < raster_tasks.size(); ++i) {
+ bool required_for_activation = (i % 2) == 0;
+ queue->items.push_back(RasterTaskQueue::Item(raster_tasks[i].get(),
+ required_for_activation));
+ queue->required_for_activation_count += required_for_activation;
}
}
- private:
- TaskMap perf_tasks_;
-
- DISALLOW_COPY_AND_ASSIGN(PerfRasterWorkerPool);
+ protected:
+ scoped_refptr<ContextProvider> context_provider_;
+ FakeOutputSurfaceClient output_surface_client_;
+ scoped_ptr<FakeOutputSurface> output_surface_;
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager_;
+ scoped_ptr<ResourceProvider> resource_provider_;
+ scoped_ptr<ResourcePool> staging_resource_pool_;
+ scoped_ptr<TaskGraphRunner> task_graph_runner_;
+ LapTimer timer_;
};
-class RasterWorkerPoolPerfTest : public testing::Test {
+class RasterWorkerPoolPerfTest
+ : public RasterWorkerPoolPerfTestBase,
+ public testing::TestWithParam<RasterWorkerPoolType>,
+ public RasterizerClient {
public:
- RasterWorkerPoolPerfTest()
- : timer_(kWarmupRuns,
- base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
- kTimeCheckInterval) {}
+ RasterWorkerPoolPerfTest() {
+ switch (GetParam()) {
+ case RASTER_WORKER_POOL_TYPE_PIXEL_BUFFER:
+ raster_worker_pool_ = PixelBufferRasterWorkerPool::Create(
+ base::MessageLoopProxy::current().get(),
+ task_graph_runner_.get(),
+ resource_provider_.get(),
+ std::numeric_limits<size_t>::max());
+ break;
+ case RASTER_WORKER_POOL_TYPE_IMAGE:
+ raster_worker_pool_ = ImageRasterWorkerPool::Create(
+ base::MessageLoopProxy::current().get(),
+ task_graph_runner_.get(),
+ resource_provider_.get());
+ break;
+ case RASTER_WORKER_POOL_TYPE_IMAGE_COPY:
+ raster_worker_pool_ = ImageCopyRasterWorkerPool::Create(
+ base::MessageLoopProxy::current().get(),
+ task_graph_runner_.get(),
+ resource_provider_.get(),
+ staging_resource_pool_.get());
+ break;
+ case RASTER_WORKER_POOL_TYPE_DIRECT:
+ raster_worker_pool_ = DirectRasterWorkerPool::Create(
+ base::MessageLoopProxy::current().get(),
+ resource_provider_.get(),
+ context_provider_.get());
+ break;
+ }
- // Overridden from testing::Test:
- virtual void SetUp() OVERRIDE {
- raster_worker_pool_ = PerfRasterWorkerPool::Create();
+ DCHECK(raster_worker_pool_);
+ raster_worker_pool_->AsRasterizer()->SetClient(this);
}
+
+ // Overridden from testing::Test:
virtual void TearDown() OVERRIDE {
- raster_worker_pool_->Shutdown();
- }
-
- void CreateTasks(RasterWorkerPool::RasterTask::Queue* tasks,
- unsigned num_raster_tasks,
- unsigned num_image_decode_tasks) {
- typedef std::vector<RasterWorkerPool::Task> TaskVector;
- TaskVector image_decode_tasks;
-
- for (unsigned i = 0; i < num_image_decode_tasks; ++i) {
- image_decode_tasks.push_back(
- RasterWorkerPool::CreateImageDecodeTask(
- NULL,
- 0,
- NULL,
- base::Bind(
- &RasterWorkerPoolPerfTest::OnImageDecodeTaskCompleted)));
- }
+ raster_worker_pool_->AsRasterizer()->Shutdown();
+ raster_worker_pool_->AsRasterizer()->CheckForCompletedTasks();
+ }
- for (unsigned i = 0; i < num_raster_tasks; ++i) {
- RasterWorkerPool::Task::Set decode_tasks;
- for (TaskVector::iterator it = image_decode_tasks.begin();
- it != image_decode_tasks.end(); ++it)
- decode_tasks.Insert(*it);
-
- tasks->Append(
- RasterWorkerPool::CreateRasterTask(
- NULL,
- NULL,
- gfx::Rect(),
- 1.0,
- HIGH_QUALITY_RASTER_MODE,
- TileResolution(),
- 1,
- NULL,
- 1,
- NULL,
- base::Bind(&RasterWorkerPoolPerfTest::OnRasterTaskCompleted),
- &decode_tasks),
- false);
+ // Overriden from RasterizerClient:
+ virtual bool ShouldForceTasksRequiredForActivationToComplete() const
+ OVERRIDE {
+ return false;
+ }
+ virtual void DidFinishRunningTasks() OVERRIDE {
+ raster_worker_pool_->AsRasterizer()->CheckForCompletedTasks();
+ base::MessageLoop::current()->Quit();
+ }
+ virtual void DidFinishRunningTasksRequiredForActivation() OVERRIDE {}
+
+ void RunMessageLoopUntilAllTasksHaveCompleted() {
+ task_graph_runner_->RunUntilIdle();
+ base::MessageLoop::current()->Run();
+ }
+
+ void RunScheduleTasksTest(const std::string& test_name,
+ unsigned num_raster_tasks,
+ unsigned num_image_decode_tasks) {
+ ImageDecodeTask::Vector image_decode_tasks;
+ RasterTaskVector raster_tasks;
+ CreateImageDecodeTasks(num_image_decode_tasks, &image_decode_tasks);
+ CreateRasterTasks(num_raster_tasks, image_decode_tasks, &raster_tasks);
+
+ // Avoid unnecessary heap allocations by reusing the same queue.
+ RasterTaskQueue queue;
+
+ timer_.Reset();
+ do {
+ queue.Reset();
+ BuildRasterTaskQueue(&queue, raster_tasks);
+ raster_worker_pool_->AsRasterizer()->ScheduleTasks(&queue);
+ raster_worker_pool_->AsRasterizer()->CheckForCompletedTasks();
+ timer_.NextLap();
+ } while (!timer_.HasTimeLimitExpired());
+
+ RasterTaskQueue empty;
+ raster_worker_pool_->AsRasterizer()->ScheduleTasks(&empty);
+ RunMessageLoopUntilAllTasksHaveCompleted();
+
+ perf_test::PrintResult("schedule_tasks",
+ TestModifierString(),
+ test_name,
+ timer_.LapsPerSecond(),
+ "runs/s",
+ true);
+ }
+
+ void RunScheduleAlternateTasksTest(const std::string& test_name,
+ unsigned num_raster_tasks,
+ unsigned num_image_decode_tasks) {
+ const size_t kNumVersions = 2;
+ ImageDecodeTask::Vector image_decode_tasks[kNumVersions];
+ RasterTaskVector raster_tasks[kNumVersions];
+ for (size_t i = 0; i < kNumVersions; ++i) {
+ CreateImageDecodeTasks(num_image_decode_tasks, &image_decode_tasks[i]);
+ CreateRasterTasks(
+ num_raster_tasks, image_decode_tasks[i], &raster_tasks[i]);
}
+
+ // Avoid unnecessary heap allocations by reusing the same queue.
+ RasterTaskQueue queue;
+
+ size_t count = 0;
+ timer_.Reset();
+ do {
+ queue.Reset();
+ BuildRasterTaskQueue(&queue, raster_tasks[count % kNumVersions]);
+ raster_worker_pool_->AsRasterizer()->ScheduleTasks(&queue);
+ raster_worker_pool_->AsRasterizer()->CheckForCompletedTasks();
+ ++count;
+ timer_.NextLap();
+ } while (!timer_.HasTimeLimitExpired());
+
+ RasterTaskQueue empty;
+ raster_worker_pool_->AsRasterizer()->ScheduleTasks(&empty);
+ RunMessageLoopUntilAllTasksHaveCompleted();
+
+ perf_test::PrintResult("schedule_alternate_tasks",
+ TestModifierString(),
+ test_name,
+ timer_.LapsPerSecond(),
+ "runs/s",
+ true);
}
- void RunBuildTaskGraphTest(const std::string& test_name,
- unsigned num_raster_tasks,
- unsigned num_image_decode_tasks) {
+ void RunScheduleAndExecuteTasksTest(const std::string& test_name,
+ unsigned num_raster_tasks,
+ unsigned num_image_decode_tasks) {
+ ImageDecodeTask::Vector image_decode_tasks;
+ RasterTaskVector raster_tasks;
+ CreateImageDecodeTasks(num_image_decode_tasks, &image_decode_tasks);
+ CreateRasterTasks(num_raster_tasks, image_decode_tasks, &raster_tasks);
+
+ // Avoid unnecessary heap allocations by reusing the same queue.
+ RasterTaskQueue queue;
+
timer_.Reset();
- RasterWorkerPool::RasterTask::Queue tasks;
- CreateTasks(&tasks, num_raster_tasks, num_image_decode_tasks);
- raster_worker_pool_->SetRasterTasks(&tasks);
do {
- raster_worker_pool_->BuildTaskGraph();
+ queue.Reset();
+ BuildRasterTaskQueue(&queue, raster_tasks);
+ raster_worker_pool_->AsRasterizer()->ScheduleTasks(&queue);
+ RunMessageLoopUntilAllTasksHaveCompleted();
timer_.NextLap();
} while (!timer_.HasTimeLimitExpired());
- perf_test::PrintResult("build_task_graph", "", test_name,
- timer_.LapsPerSecond(), "runs/s", true);
+ RasterTaskQueue empty;
+ raster_worker_pool_->AsRasterizer()->ScheduleTasks(&empty);
+ RunMessageLoopUntilAllTasksHaveCompleted();
+
+ perf_test::PrintResult("schedule_and_execute_tasks",
+ TestModifierString(),
+ test_name,
+ timer_.LapsPerSecond(),
+ "runs/s",
+ true);
}
- protected:
- static void OnRasterTaskCompleted(const PicturePileImpl::Analysis& analysis,
- bool was_canceled) {}
- static void OnImageDecodeTaskCompleted(bool was_canceled) {}
+ private:
+ std::string TestModifierString() const {
+ switch (GetParam()) {
+ case RASTER_WORKER_POOL_TYPE_PIXEL_BUFFER:
+ return std::string("_pixel_raster_worker_pool");
+ case RASTER_WORKER_POOL_TYPE_IMAGE:
+ return std::string("_image_raster_worker_pool");
+ case RASTER_WORKER_POOL_TYPE_IMAGE_COPY:
+ return std::string("_image_copy_raster_worker_pool");
+ case RASTER_WORKER_POOL_TYPE_DIRECT:
+ return std::string("_direct_raster_worker_pool");
+ }
+ NOTREACHED();
+ return std::string();
+ }
- scoped_ptr<PerfRasterWorkerPool> raster_worker_pool_;
- LapTimer timer_;
+ scoped_ptr<RasterWorkerPool> raster_worker_pool_;
};
-TEST_F(RasterWorkerPoolPerfTest, BuildTaskGraph) {
- RunBuildTaskGraphTest("10_0", 10, 0);
- RunBuildTaskGraphTest("100_0", 100, 0);
- RunBuildTaskGraphTest("1000_0", 1000, 0);
- RunBuildTaskGraphTest("10_1", 10, 1);
- RunBuildTaskGraphTest("100_1", 100, 1);
- RunBuildTaskGraphTest("1000_1", 1000, 1);
- RunBuildTaskGraphTest("10_4", 10, 4);
- RunBuildTaskGraphTest("100_4", 100, 4);
- RunBuildTaskGraphTest("1000_4", 1000, 4);
- RunBuildTaskGraphTest("10_16", 10, 16);
- RunBuildTaskGraphTest("100_16", 100, 16);
- RunBuildTaskGraphTest("1000_16", 1000, 16);
+TEST_P(RasterWorkerPoolPerfTest, ScheduleTasks) {
+ RunScheduleTasksTest("1_0", 1, 0);
+ RunScheduleTasksTest("32_0", 32, 0);
+ RunScheduleTasksTest("1_1", 1, 1);
+ RunScheduleTasksTest("32_1", 32, 1);
+ RunScheduleTasksTest("1_4", 1, 4);
+ RunScheduleTasksTest("32_4", 32, 4);
}
-} // namespace
+TEST_P(RasterWorkerPoolPerfTest, ScheduleAlternateTasks) {
+ RunScheduleAlternateTasksTest("1_0", 1, 0);
+ RunScheduleAlternateTasksTest("32_0", 32, 0);
+ RunScheduleAlternateTasksTest("1_1", 1, 1);
+ RunScheduleAlternateTasksTest("32_1", 32, 1);
+ RunScheduleAlternateTasksTest("1_4", 1, 4);
+ RunScheduleAlternateTasksTest("32_4", 32, 4);
+}
+
+TEST_P(RasterWorkerPoolPerfTest, ScheduleAndExecuteTasks) {
+ RunScheduleAndExecuteTasksTest("1_0", 1, 0);
+ RunScheduleAndExecuteTasksTest("32_0", 32, 0);
+ RunScheduleAndExecuteTasksTest("1_1", 1, 1);
+ RunScheduleAndExecuteTasksTest("32_1", 32, 1);
+ RunScheduleAndExecuteTasksTest("1_4", 1, 4);
+ RunScheduleAndExecuteTasksTest("32_4", 32, 4);
+}
+
+INSTANTIATE_TEST_CASE_P(RasterWorkerPoolPerfTests,
+ RasterWorkerPoolPerfTest,
+ ::testing::Values(RASTER_WORKER_POOL_TYPE_PIXEL_BUFFER,
+ RASTER_WORKER_POOL_TYPE_IMAGE,
+ RASTER_WORKER_POOL_TYPE_IMAGE_COPY,
+ RASTER_WORKER_POOL_TYPE_DIRECT));
+
+class RasterWorkerPoolCommonPerfTest : public RasterWorkerPoolPerfTestBase,
+ public testing::Test {
+ public:
+ void RunBuildRasterTaskQueueTest(const std::string& test_name,
+ unsigned num_raster_tasks,
+ unsigned num_image_decode_tasks) {
+ ImageDecodeTask::Vector image_decode_tasks;
+ RasterTaskVector raster_tasks;
+ CreateImageDecodeTasks(num_image_decode_tasks, &image_decode_tasks);
+ CreateRasterTasks(num_raster_tasks, image_decode_tasks, &raster_tasks);
+
+ // Avoid unnecessary heap allocations by reusing the same queue.
+ RasterTaskQueue queue;
+
+ timer_.Reset();
+ do {
+ queue.Reset();
+ BuildRasterTaskQueue(&queue, raster_tasks);
+ timer_.NextLap();
+ } while (!timer_.HasTimeLimitExpired());
+ perf_test::PrintResult("build_raster_task_queue",
+ "",
+ test_name,
+ timer_.LapsPerSecond(),
+ "runs/s",
+ true);
+ }
+};
+
+TEST_F(RasterWorkerPoolCommonPerfTest, BuildRasterTaskQueue) {
+ RunBuildRasterTaskQueueTest("1_0", 1, 0);
+ RunBuildRasterTaskQueueTest("32_0", 32, 0);
+ RunBuildRasterTaskQueueTest("1_1", 1, 1);
+ RunBuildRasterTaskQueueTest("32_1", 32, 1);
+ RunBuildRasterTaskQueueTest("1_4", 1, 4);
+ RunBuildRasterTaskQueueTest("32_4", 32, 4);
+}
+
+} // namespace
} // namespace cc
diff --git a/chromium/cc/resources/raster_worker_pool_unittest.cc b/chromium/cc/resources/raster_worker_pool_unittest.cc
index 716edf6c526..7a5f324e39f 100644
--- a/chromium/cc/resources/raster_worker_pool_unittest.cc
+++ b/chromium/cc/resources/raster_worker_pool_unittest.cc
@@ -7,79 +7,159 @@
#include <limits>
#include <vector>
+#include "base/cancelable_callback.h"
+#include "cc/resources/direct_raster_worker_pool.h"
+#include "cc/resources/image_copy_raster_worker_pool.h"
#include "cc/resources/image_raster_worker_pool.h"
#include "cc/resources/picture_pile.h"
#include "cc/resources/picture_pile_impl.h"
#include "cc/resources/pixel_buffer_raster_worker_pool.h"
+#include "cc/resources/rasterizer.h"
+#include "cc/resources/resource_pool.h"
#include "cc/resources/resource_provider.h"
#include "cc/resources/scoped_resource.h"
#include "cc/test/fake_output_surface.h"
#include "cc/test/fake_output_surface_client.h"
+#include "cc/test/test_shared_bitmap_manager.h"
#include "cc/test/test_web_graphics_context_3d.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace cc {
+namespace {
+
+enum RasterWorkerPoolType {
+ RASTER_WORKER_POOL_TYPE_PIXEL_BUFFER,
+ RASTER_WORKER_POOL_TYPE_IMAGE,
+ RASTER_WORKER_POOL_TYPE_IMAGE_COPY,
+ RASTER_WORKER_POOL_TYPE_DIRECT
+};
-class TestRasterWorkerPoolTaskImpl : public internal::RasterWorkerPoolTask {
+class TestRasterTaskImpl : public RasterTask {
public:
- typedef base::Callback<void(const PicturePileImpl::Analysis& analysis,
- bool was_canceled,
- bool did_raster)> Reply;
-
- TestRasterWorkerPoolTaskImpl(
- const Resource* resource,
- const Reply& reply,
- TaskVector* dependencies)
- : internal::RasterWorkerPoolTask(resource, dependencies),
- reply_(reply),
- did_raster_(false) {}
-
- // Overridden from internal::WorkerPoolTask:
- virtual bool RunOnWorkerThread(unsigned thread_index,
- void* buffer,
- gfx::Size size,
- int stride) OVERRIDE {
- did_raster_ = true;
- return true;
+ typedef base::Callback<
+ void(const PicturePileImpl::Analysis& analysis, bool was_canceled)> Reply;
+
+ TestRasterTaskImpl(const Resource* resource,
+ const Reply& reply,
+ ImageDecodeTask::Vector* dependencies)
+ : RasterTask(resource, dependencies), reply_(reply) {}
+
+ // Overridden from Task:
+ virtual void RunOnWorkerThread() OVERRIDE {}
+
+ // Overridden from RasterizerTask:
+ virtual void ScheduleOnOriginThread(RasterizerTaskClient* client) OVERRIDE {
+ client->AcquireCanvasForRaster(this);
+ }
+ virtual void CompleteOnOriginThread(RasterizerTaskClient* client) OVERRIDE {
+ client->ReleaseCanvasForRaster(this);
}
- virtual void CompleteOnOriginThread() OVERRIDE {
- reply_.Run(PicturePileImpl::Analysis(), !HasFinishedRunning(), did_raster_);
+ virtual void RunReplyOnOriginThread() OVERRIDE {
+ reply_.Run(PicturePileImpl::Analysis(), !HasFinishedRunning());
}
protected:
- virtual ~TestRasterWorkerPoolTaskImpl() {}
+ virtual ~TestRasterTaskImpl() {}
private:
const Reply reply_;
- bool did_raster_;
- DISALLOW_COPY_AND_ASSIGN(TestRasterWorkerPoolTaskImpl);
+ DISALLOW_COPY_AND_ASSIGN(TestRasterTaskImpl);
+};
+
+class BlockingTestRasterTaskImpl : public TestRasterTaskImpl {
+ public:
+ BlockingTestRasterTaskImpl(const Resource* resource,
+ const Reply& reply,
+ base::Lock* lock,
+ ImageDecodeTask::Vector* dependencies)
+ : TestRasterTaskImpl(resource, reply, dependencies), lock_(lock) {}
+
+ // Overridden from Task:
+ virtual void RunOnWorkerThread() OVERRIDE {
+ base::AutoLock lock(*lock_);
+ TestRasterTaskImpl::RunOnWorkerThread();
+ }
+
+ // Overridden from RasterizerTask:
+ virtual void RunReplyOnOriginThread() OVERRIDE {}
+
+ protected:
+ virtual ~BlockingTestRasterTaskImpl() {}
+
+ private:
+ base::Lock* lock_;
+
+ DISALLOW_COPY_AND_ASSIGN(BlockingTestRasterTaskImpl);
};
-class RasterWorkerPoolTest : public testing::Test,
- public RasterWorkerPoolClient {
+class RasterWorkerPoolTest
+ : public testing::TestWithParam<RasterWorkerPoolType>,
+ public RasterizerClient {
public:
+ struct RasterTaskResult {
+ unsigned id;
+ bool canceled;
+ };
+
+ typedef std::vector<scoped_refptr<RasterTask> > RasterTaskVector;
+
RasterWorkerPoolTest()
: context_provider_(TestContextProvider::Create()),
- check_interval_milliseconds_(1),
timeout_seconds_(5),
timed_out_(false) {
output_surface_ = FakeOutputSurface::Create3d(context_provider_).Pass();
CHECK(output_surface_->BindToClient(&output_surface_client_));
- resource_provider_ = ResourceProvider::Create(
- output_surface_.get(), NULL, 0, false, 1).Pass();
+ shared_bitmap_manager_.reset(new TestSharedBitmapManager());
+ resource_provider_ =
+ ResourceProvider::Create(
+ output_surface_.get(), shared_bitmap_manager_.get(), 0, false, 1,
+ false).Pass();
+ staging_resource_pool_ = ResourcePool::Create(
+ resource_provider_.get(), GL_TEXTURE_2D, RGBA_8888);
+
+ switch (GetParam()) {
+ case RASTER_WORKER_POOL_TYPE_PIXEL_BUFFER:
+ raster_worker_pool_ = PixelBufferRasterWorkerPool::Create(
+ base::MessageLoopProxy::current().get(),
+ RasterWorkerPool::GetTaskGraphRunner(),
+ resource_provider_.get(),
+ std::numeric_limits<size_t>::max());
+ break;
+ case RASTER_WORKER_POOL_TYPE_IMAGE:
+ raster_worker_pool_ = ImageRasterWorkerPool::Create(
+ base::MessageLoopProxy::current().get(),
+ RasterWorkerPool::GetTaskGraphRunner(),
+ resource_provider_.get());
+ break;
+ case RASTER_WORKER_POOL_TYPE_IMAGE_COPY:
+ raster_worker_pool_ = ImageCopyRasterWorkerPool::Create(
+ base::MessageLoopProxy::current().get(),
+ RasterWorkerPool::GetTaskGraphRunner(),
+ resource_provider_.get(),
+ staging_resource_pool_.get());
+ break;
+ case RASTER_WORKER_POOL_TYPE_DIRECT:
+ raster_worker_pool_ = DirectRasterWorkerPool::Create(
+ base::MessageLoopProxy::current().get(),
+ resource_provider_.get(),
+ context_provider_.get());
+ break;
+ }
+
+ DCHECK(raster_worker_pool_);
+ raster_worker_pool_->AsRasterizer()->SetClient(this);
}
virtual ~RasterWorkerPoolTest() {
+ staging_resource_pool_.reset();
resource_provider_.reset();
}
// Overridden from testing::Test:
virtual void TearDown() OVERRIDE {
- if (!raster_worker_pool_)
- return;
- raster_worker_pool_->Shutdown();
- raster_worker_pool_->CheckForCompletedTasks();
+ raster_worker_pool_->AsRasterizer()->Shutdown();
+ raster_worker_pool_->AsRasterizer()->CheckForCompletedTasks();
}
// Overriden from RasterWorkerPoolClient:
@@ -87,41 +167,16 @@ class RasterWorkerPoolTest : public testing::Test,
OVERRIDE {
return false;
}
- virtual void DidFinishRunningTasks() OVERRIDE {}
- virtual void DidFinishRunningTasksRequiredForActivation() OVERRIDE {}
-
- virtual void BeginTest() = 0;
- virtual void AfterTest() = 0;
-
- ResourceProvider* resource_provider() const {
- return resource_provider_.get();
- }
-
- RasterWorkerPool* worker_pool() {
- return raster_worker_pool_.get();
+ virtual void DidFinishRunningTasks() OVERRIDE {
+ raster_worker_pool_->AsRasterizer()->CheckForCompletedTasks();
+ base::MessageLoop::current()->Quit();
}
+ virtual void DidFinishRunningTasksRequiredForActivation() OVERRIDE {}
- void RunTest(bool use_map_image) {
- if (use_map_image) {
- raster_worker_pool_ = ImageRasterWorkerPool::Create(
- resource_provider(), 1, GL_TEXTURE_2D);
- } else {
- raster_worker_pool_ =
- PixelBufferRasterWorkerPool::Create(
- resource_provider(),
- 1,
- std::numeric_limits<size_t>::max());
- }
-
- raster_worker_pool_->SetClient(this);
-
- BeginTest();
-
- ScheduleCheckForCompletedTasks();
-
+ void RunMessageLoopUntilAllTasksHaveCompleted() {
if (timeout_seconds_) {
- timeout_.Reset(base::Bind(&RasterWorkerPoolTest::OnTimeout,
- base::Unretained(this)));
+ timeout_.Reset(
+ base::Bind(&RasterWorkerPoolTest::OnTimeout, base::Unretained(this)));
base::MessageLoopProxy::current()->PostDelayedTask(
FROM_HERE,
timeout_.callback(),
@@ -130,69 +185,72 @@ class RasterWorkerPoolTest : public testing::Test,
base::MessageLoop::current()->Run();
- check_.Cancel();
timeout_.Cancel();
- if (timed_out_) {
- FAIL() << "Test timed out";
- return;
- }
- AfterTest();
- }
-
- void EndTest() {
- base::MessageLoop::current()->Quit();
+ ASSERT_FALSE(timed_out_) << "Test timed out";
}
void ScheduleTasks() {
- RasterWorkerPool::RasterTask::Queue tasks;
+ RasterTaskQueue queue;
- for (std::vector<RasterWorkerPool::RasterTask>::iterator it =
- tasks_.begin();
- it != tasks_.end(); ++it)
- tasks.Append(*it, false);
+ for (RasterTaskVector::const_iterator it = tasks_.begin();
+ it != tasks_.end();
+ ++it)
+ queue.items.push_back(RasterTaskQueue::Item(*it, false));
- worker_pool()->ScheduleTasks(&tasks);
+ raster_worker_pool_->AsRasterizer()->ScheduleTasks(&queue);
}
void AppendTask(unsigned id) {
const gfx::Size size(1, 1);
scoped_ptr<ScopedResource> resource(
- ScopedResource::Create(resource_provider()));
+ ScopedResource::Create(resource_provider_.get()));
resource->Allocate(size, ResourceProvider::TextureUsageAny, RGBA_8888);
const Resource* const_resource = resource.get();
- RasterWorkerPool::Task::Set empty;
- tasks_.push_back(
- RasterWorkerPool::RasterTask(new TestRasterWorkerPoolTaskImpl(
- const_resource,
- base::Bind(&RasterWorkerPoolTest::OnTaskCompleted,
- base::Unretained(this),
- base::Passed(&resource),
- id),
- &empty.tasks_)));
+ ImageDecodeTask::Vector empty;
+ tasks_.push_back(new TestRasterTaskImpl(
+ const_resource,
+ base::Bind(&RasterWorkerPoolTest::OnTaskCompleted,
+ base::Unretained(this),
+ base::Passed(&resource),
+ id),
+ &empty));
}
- virtual void OnTaskCompleted(scoped_ptr<ScopedResource> resource,
- unsigned id,
- const PicturePileImpl::Analysis& analysis,
- bool was_canceled,
- bool did_raster) {}
+ void AppendBlockingTask(unsigned id, base::Lock* lock) {
+ const gfx::Size size(1, 1);
- private:
- void ScheduleCheckForCompletedTasks() {
- check_.Reset(base::Bind(&RasterWorkerPoolTest::OnCheckForCompletedTasks,
- base::Unretained(this)));
- base::MessageLoopProxy::current()->PostDelayedTask(
- FROM_HERE,
- check_.callback(),
- base::TimeDelta::FromMilliseconds(check_interval_milliseconds_));
+ scoped_ptr<ScopedResource> resource(
+ ScopedResource::Create(resource_provider_.get()));
+ resource->Allocate(size, ResourceProvider::TextureUsageAny, RGBA_8888);
+ const Resource* const_resource = resource.get();
+
+ ImageDecodeTask::Vector empty;
+ tasks_.push_back(new BlockingTestRasterTaskImpl(
+ const_resource,
+ base::Bind(&RasterWorkerPoolTest::OnTaskCompleted,
+ base::Unretained(this),
+ base::Passed(&resource),
+ id),
+ lock,
+ &empty));
+ }
+
+ const std::vector<RasterTaskResult>& completed_tasks() const {
+ return completed_tasks_;
}
- void OnCheckForCompletedTasks() {
- raster_worker_pool_->CheckForCompletedTasks();
- ScheduleCheckForCompletedTasks();
+ private:
+ void OnTaskCompleted(scoped_ptr<ScopedResource> resource,
+ unsigned id,
+ const PicturePileImpl::Analysis& analysis,
+ bool was_canceled) {
+ RasterTaskResult result;
+ result.id = id;
+ result.canceled = was_canceled;
+ completed_tasks_.push_back(result);
}
void OnTimeout() {
@@ -204,89 +262,72 @@ class RasterWorkerPoolTest : public testing::Test,
scoped_refptr<TestContextProvider> context_provider_;
FakeOutputSurfaceClient output_surface_client_;
scoped_ptr<FakeOutputSurface> output_surface_;
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager_;
scoped_ptr<ResourceProvider> resource_provider_;
+ scoped_ptr<ResourcePool> staging_resource_pool_;
scoped_ptr<RasterWorkerPool> raster_worker_pool_;
- base::CancelableClosure check_;
- int check_interval_milliseconds_;
base::CancelableClosure timeout_;
int timeout_seconds_;
bool timed_out_;
- std::vector<RasterWorkerPool::RasterTask> tasks_;
+ RasterTaskVector tasks_;
+ std::vector<RasterTaskResult> completed_tasks_;
};
-namespace {
-
-#define PIXEL_BUFFER_TEST_F(TEST_FIXTURE_NAME) \
- TEST_F(TEST_FIXTURE_NAME, RunPixelBuffer) { \
- RunTest(false); \
- }
-
-#define IMAGE_TEST_F(TEST_FIXTURE_NAME) \
- TEST_F(TEST_FIXTURE_NAME, RunImage) { \
- RunTest(true); \
- }
-
-#define PIXEL_BUFFER_AND_IMAGE_TEST_F(TEST_FIXTURE_NAME) \
- PIXEL_BUFFER_TEST_F(TEST_FIXTURE_NAME); \
- IMAGE_TEST_F(TEST_FIXTURE_NAME)
-
-class BasicRasterWorkerPoolTest : public RasterWorkerPoolTest {
- public:
- virtual void OnTaskCompleted(scoped_ptr<ScopedResource> resource,
- unsigned id,
- const PicturePileImpl::Analysis& analysis,
- bool was_canceled,
- bool did_raster) OVERRIDE {
- EXPECT_TRUE(did_raster);
- on_task_completed_ids_.push_back(id);
- if (on_task_completed_ids_.size() == 2)
- EndTest();
- }
-
- // Overridden from RasterWorkerPoolTest:
- virtual void BeginTest() OVERRIDE {
- AppendTask(0u);
- AppendTask(1u);
- ScheduleTasks();
- }
- virtual void AfterTest() OVERRIDE {
- EXPECT_EQ(2u, on_task_completed_ids_.size());
- tasks_.clear();
- }
-
- std::vector<unsigned> on_task_completed_ids_;
-};
-
-PIXEL_BUFFER_AND_IMAGE_TEST_F(BasicRasterWorkerPoolTest);
-
-class RasterWorkerPoolTestFailedMapResource : public RasterWorkerPoolTest {
- public:
- virtual void OnTaskCompleted(scoped_ptr<ScopedResource> resource,
- unsigned id,
- const PicturePileImpl::Analysis& analysis,
- bool was_canceled,
- bool did_raster) OVERRIDE {
- EXPECT_FALSE(did_raster);
- EndTest();
- }
-
- // Overridden from RasterWorkerPoolTest:
- virtual void BeginTest() OVERRIDE {
- TestWebGraphicsContext3D* context3d = context_provider_->TestContext3d();
- context3d->set_times_map_image_chromium_succeeds(0);
- context3d->set_times_map_buffer_chromium_succeeds(0);
- AppendTask(0u);
- ScheduleTasks();
- }
-
- virtual void AfterTest() OVERRIDE {
- ASSERT_EQ(1u, tasks_.size());
- tasks_.clear();
- }
-};
-
-PIXEL_BUFFER_AND_IMAGE_TEST_F(RasterWorkerPoolTestFailedMapResource);
+TEST_P(RasterWorkerPoolTest, Basic) {
+ AppendTask(0u);
+ AppendTask(1u);
+ ScheduleTasks();
+
+ RunMessageLoopUntilAllTasksHaveCompleted();
+
+ ASSERT_EQ(2u, completed_tasks().size());
+ EXPECT_FALSE(completed_tasks()[0].canceled);
+ EXPECT_FALSE(completed_tasks()[1].canceled);
+}
+
+TEST_P(RasterWorkerPoolTest, FailedMapResource) {
+ TestWebGraphicsContext3D* context3d = context_provider_->TestContext3d();
+ context3d->set_times_map_image_chromium_succeeds(0);
+ context3d->set_times_map_buffer_chromium_succeeds(0);
+ AppendTask(0u);
+ ScheduleTasks();
+
+ RunMessageLoopUntilAllTasksHaveCompleted();
+
+ ASSERT_EQ(1u, completed_tasks().size());
+ EXPECT_FALSE(completed_tasks()[0].canceled);
+}
+
+// This test checks that replacing a pending raster task with another does
+// not prevent the DidFinishRunningTasks notification from being sent.
+TEST_P(RasterWorkerPoolTest, FalseThrottling) {
+ base::Lock lock;
+
+ // Schedule a task that is prevented from completing with a lock.
+ lock.Acquire();
+ AppendBlockingTask(0u, &lock);
+ ScheduleTasks();
+
+ // Schedule another task to replace the still-pending task. Because the old
+ // task is not a throttled task in the new task set, it should not prevent
+ // DidFinishRunningTasks from getting signaled.
+ RasterTaskVector tasks;
+ tasks.swap(tasks_);
+ AppendTask(1u);
+ ScheduleTasks();
+
+ // Unblock the first task to allow the second task to complete.
+ lock.Release();
+
+ RunMessageLoopUntilAllTasksHaveCompleted();
+}
+
+INSTANTIATE_TEST_CASE_P(RasterWorkerPoolTests,
+ RasterWorkerPoolTest,
+ ::testing::Values(RASTER_WORKER_POOL_TYPE_PIXEL_BUFFER,
+ RASTER_WORKER_POOL_TYPE_IMAGE,
+ RASTER_WORKER_POOL_TYPE_IMAGE_COPY,
+ RASTER_WORKER_POOL_TYPE_DIRECT));
} // namespace
-
} // namespace cc
diff --git a/chromium/cc/resources/rasterizer.cc b/chromium/cc/resources/rasterizer.cc
new file mode 100644
index 00000000000..df7e27ecebc
--- /dev/null
+++ b/chromium/cc/resources/rasterizer.cc
@@ -0,0 +1,79 @@
+// 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/resources/rasterizer.h"
+
+#include <algorithm>
+
+namespace cc {
+
+RasterizerTask::RasterizerTask() : did_schedule_(false), did_complete_(false) {}
+
+RasterizerTask::~RasterizerTask() {
+ // Debugging CHECKs to help track down a use-after-free.
+ CHECK(!did_schedule_);
+ CHECK(!did_run_ || did_complete_);
+}
+
+ImageDecodeTask* RasterizerTask::AsImageDecodeTask() { return NULL; }
+
+RasterTask* RasterizerTask::AsRasterTask() { return NULL; }
+
+void RasterizerTask::WillSchedule() { DCHECK(!did_schedule_); }
+
+void RasterizerTask::DidSchedule() {
+ did_schedule_ = true;
+ did_complete_ = false;
+}
+
+bool RasterizerTask::HasBeenScheduled() const { return did_schedule_; }
+
+void RasterizerTask::WillComplete() { DCHECK(!did_complete_); }
+
+void RasterizerTask::DidComplete() {
+ DCHECK(did_schedule_);
+ DCHECK(!did_complete_);
+ did_schedule_ = false;
+ did_complete_ = true;
+}
+
+bool RasterizerTask::HasCompleted() const { return did_complete_; }
+
+ImageDecodeTask::ImageDecodeTask() {}
+
+ImageDecodeTask::~ImageDecodeTask() {}
+
+ImageDecodeTask* ImageDecodeTask::AsImageDecodeTask() { return this; }
+
+RasterTask::RasterTask(const Resource* resource,
+ ImageDecodeTask::Vector* dependencies)
+ : resource_(resource) {
+ dependencies_.swap(*dependencies);
+}
+
+RasterTask::~RasterTask() {}
+
+RasterTask* RasterTask::AsRasterTask() { return this; }
+
+RasterTaskQueue::Item::Item(RasterTask* task, bool required_for_activation)
+ : task(task), required_for_activation(required_for_activation) {}
+
+RasterTaskQueue::Item::~Item() {}
+
+RasterTaskQueue::RasterTaskQueue() : required_for_activation_count(0u) {}
+
+RasterTaskQueue::~RasterTaskQueue() {}
+
+void RasterTaskQueue::Swap(RasterTaskQueue* other) {
+ items.swap(other->items);
+ std::swap(required_for_activation_count,
+ other->required_for_activation_count);
+}
+
+void RasterTaskQueue::Reset() {
+ required_for_activation_count = 0u;
+ items.clear();
+}
+
+} // namespace cc
diff --git a/chromium/cc/resources/rasterizer.h b/chromium/cc/resources/rasterizer.h
new file mode 100644
index 00000000000..17cc94ed6fa
--- /dev/null
+++ b/chromium/cc/resources/rasterizer.h
@@ -0,0 +1,165 @@
+// 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_RESOURCES_RASTERIZER_H_
+#define CC_RESOURCES_RASTERIZER_H_
+
+#include <vector>
+
+#include "base/callback.h"
+#include "cc/resources/resource_format.h"
+#include "cc/resources/task_graph_runner.h"
+
+class SkCanvas;
+
+namespace cc {
+class ImageDecodeTask;
+class RasterTask;
+class Resource;
+
+class CC_EXPORT RasterizerTaskClient {
+ public:
+ virtual SkCanvas* AcquireCanvasForRaster(RasterTask* task) = 0;
+ virtual void ReleaseCanvasForRaster(RasterTask* task) = 0;
+
+ protected:
+ virtual ~RasterizerTaskClient() {}
+};
+
+class CC_EXPORT RasterizerTask : public Task {
+ public:
+ typedef std::vector<scoped_refptr<RasterizerTask> > Vector;
+
+ virtual void ScheduleOnOriginThread(RasterizerTaskClient* client) = 0;
+ virtual void CompleteOnOriginThread(RasterizerTaskClient* client) = 0;
+ virtual void RunReplyOnOriginThread() = 0;
+
+ // Type-checking downcast routines.
+ virtual ImageDecodeTask* AsImageDecodeTask();
+ virtual RasterTask* AsRasterTask();
+
+ void WillSchedule();
+ void DidSchedule();
+ bool HasBeenScheduled() const;
+
+ void WillComplete();
+ void DidComplete();
+ bool HasCompleted() const;
+
+ protected:
+ RasterizerTask();
+ virtual ~RasterizerTask();
+
+ bool did_schedule_;
+ bool did_complete_;
+};
+
+class CC_EXPORT ImageDecodeTask : public RasterizerTask {
+ public:
+ typedef std::vector<scoped_refptr<ImageDecodeTask> > Vector;
+
+ // Overridden from RasterizerTask:
+ virtual ImageDecodeTask* AsImageDecodeTask() OVERRIDE;
+
+ protected:
+ ImageDecodeTask();
+ virtual ~ImageDecodeTask();
+};
+
+class CC_EXPORT RasterTask : public RasterizerTask {
+ public:
+ typedef std::vector<scoped_refptr<RasterTask> > Vector;
+
+ // Overridden from RasterizerTask:
+ virtual RasterTask* AsRasterTask() OVERRIDE;
+
+ const Resource* resource() const { return resource_; }
+ const ImageDecodeTask::Vector& dependencies() const { return dependencies_; }
+
+ protected:
+ RasterTask(const Resource* resource, ImageDecodeTask::Vector* dependencies);
+ virtual ~RasterTask();
+
+ private:
+ const Resource* resource_;
+ ImageDecodeTask::Vector dependencies_;
+};
+
+class CC_EXPORT RasterizerClient {
+ public:
+ virtual bool ShouldForceTasksRequiredForActivationToComplete() const = 0;
+ virtual void DidFinishRunningTasks() = 0;
+ virtual void DidFinishRunningTasksRequiredForActivation() = 0;
+
+ protected:
+ virtual ~RasterizerClient() {}
+};
+
+struct CC_EXPORT RasterTaskQueue {
+ struct CC_EXPORT Item {
+ class TaskComparator {
+ public:
+ explicit TaskComparator(const RasterTask* task) : task_(task) {}
+
+ bool operator()(const Item& item) const { return item.task == task_; }
+
+ private:
+ const RasterTask* task_;
+ };
+
+ typedef std::vector<Item> Vector;
+
+ Item(RasterTask* task, bool required_for_activation);
+ ~Item();
+
+ static bool IsRequiredForActivation(const Item& item) {
+ return item.required_for_activation;
+ }
+
+ RasterTask* task;
+ bool required_for_activation;
+ };
+
+ RasterTaskQueue();
+ ~RasterTaskQueue();
+
+ void Swap(RasterTaskQueue* other);
+ void Reset();
+
+ Item::Vector items;
+ size_t required_for_activation_count;
+};
+
+// This interface can be used to schedule and run raster tasks. The client will
+// be notified asynchronously when the set of tasks marked as "required for
+// activation" have finished running and when all scheduled tasks have finished
+// running. The client can call CheckForCompletedTasks() at any time to dispatch
+// pending completion callbacks for all tasks that have finished running.
+class CC_EXPORT Rasterizer {
+ public:
+ // Set the client instance to be notified when finished running tasks.
+ virtual void SetClient(RasterizerClient* client) = 0;
+
+ // Tells the worker pool to shutdown after canceling all previously scheduled
+ // tasks. Reply callbacks are still guaranteed to run when
+ // CheckForCompletedTasks() is called.
+ virtual void Shutdown() = 0;
+
+ // Schedule running of raster tasks in |queue| and all dependencies.
+ // Previously scheduled tasks that are not in |queue| will be canceled unless
+ // already running. Once scheduled, reply callbacks are guaranteed to run for
+ // all tasks even if they later get canceled by another call to
+ // ScheduleTasks().
+ virtual void ScheduleTasks(RasterTaskQueue* queue) = 0;
+
+ // Check for completed tasks and dispatch reply callbacks.
+ virtual void CheckForCompletedTasks() = 0;
+
+ protected:
+ virtual ~Rasterizer() {}
+};
+
+} // namespace cc
+
+#endif // CC_RESOURCES_RASTERIZER_H_
diff --git a/chromium/cc/resources/release_callback.h b/chromium/cc/resources/release_callback.h
index 9433f7f6eb9..b471381fbf2 100644
--- a/chromium/cc/resources/release_callback.h
+++ b/chromium/cc/resources/release_callback.h
@@ -9,8 +9,7 @@
namespace cc {
-typedef base::Callback<void(unsigned sync_point, bool is_lost)>
- ReleaseCallback;
+typedef base::Callback<void(uint32 sync_point, bool is_lost)> ReleaseCallback;
} // namespace cc
diff --git a/chromium/cc/resources/resource.h b/chromium/cc/resources/resource.h
index e9dd393a6a4..24cb88a9f84 100644
--- a/chromium/cc/resources/resource.h
+++ b/chromium/cc/resources/resource.h
@@ -15,7 +15,7 @@ namespace cc {
class CC_EXPORT Resource {
public:
Resource() : id_(0) {}
- Resource(unsigned id, gfx::Size size, ResourceFormat format)
+ Resource(unsigned id, const gfx::Size& size, ResourceFormat format)
: id_(id),
size_(size),
format_(format) {}
@@ -25,14 +25,15 @@ class CC_EXPORT Resource {
ResourceFormat format() const { return format_; }
size_t bytes() const;
- inline static size_t MemorySizeBytes(gfx::Size size, ResourceFormat format) {
+ inline static size_t MemorySizeBytes(const gfx::Size& size,
+ ResourceFormat format) {
DCHECK_EQ(0u, (BitsPerPixel(format) * size.width() * size.height()) % 8);
return (BitsPerPixel(format) * size.width() * size.height()) / 8;
}
protected:
void set_id(ResourceProvider::ResourceId id) { id_ = id; }
- void set_dimensions(gfx::Size size, ResourceFormat format) {
+ void set_dimensions(const gfx::Size& size, ResourceFormat format) {
size_ = size;
format_ = format;
}
diff --git a/chromium/cc/resources/resource_format.cc b/chromium/cc/resources/resource_format.cc
index 35617174cb5..273085604a4 100644
--- a/chromium/cc/resources/resource_format.cc
+++ b/chromium/cc/resources/resource_format.cc
@@ -6,13 +6,13 @@
namespace cc {
-SkBitmap::Config SkBitmapConfig(ResourceFormat format) {
+SkColorType ResourceFormatToSkColorType(ResourceFormat format) {
switch (format) {
case RGBA_4444:
- return SkBitmap::kARGB_4444_Config;
+ return kARGB_4444_SkColorType;
case RGBA_8888:
case BGRA_8888:
- return SkBitmap::kARGB_8888_Config;
+ return kPMColor_SkColorType;
case ETC1:
case LUMINANCE_8:
case RGB_565:
@@ -20,7 +20,7 @@ SkBitmap::Config SkBitmapConfig(ResourceFormat format) {
break;
}
NOTREACHED();
- return SkBitmap::kARGB_8888_Config;
+ return kPMColor_SkColorType;
}
} // namespace cc
diff --git a/chromium/cc/resources/resource_format.h b/chromium/cc/resources/resource_format.h
index 54061394ff7..816c2857913 100644
--- a/chromium/cc/resources/resource_format.h
+++ b/chromium/cc/resources/resource_format.h
@@ -21,7 +21,7 @@ enum ResourceFormat {
RESOURCE_FORMAT_MAX = ETC1,
};
-SkBitmap::Config SkBitmapConfig(ResourceFormat format);
+SkColorType ResourceFormatToSkColorType(ResourceFormat format);
} // namespace cc
diff --git a/chromium/cc/resources/resource_pool.cc b/chromium/cc/resources/resource_pool.cc
index 6abfd7c4a3d..31b9b272013 100644
--- a/chromium/cc/resources/resource_pool.cc
+++ b/chromium/cc/resources/resource_pool.cc
@@ -20,8 +20,7 @@ ResourcePool::ResourcePool(ResourceProvider* resource_provider,
max_resource_count_(0),
memory_usage_bytes_(0),
unused_memory_usage_bytes_(0),
- resource_count_(0) {
-}
+ resource_count_(0) {}
ResourcePool::~ResourcePool() {
while (!busy_resources_.empty()) {
@@ -36,9 +35,11 @@ ResourcePool::~ResourcePool() {
DCHECK_EQ(0u, resource_count_);
}
-scoped_ptr<ScopedResource> ResourcePool::AcquireResource(gfx::Size size) {
+scoped_ptr<ScopedResource> ResourcePool::AcquireResource(
+ const gfx::Size& size) {
for (ResourceList::iterator it = unused_resources_.begin();
- it != unused_resources_.end(); ++it) {
+ it != unused_resources_.end();
+ ++it) {
ScopedResource* resource = *it;
DCHECK(resource_provider_->CanLockForWrite(resource->id()));
@@ -50,16 +51,10 @@ scoped_ptr<ScopedResource> ResourcePool::AcquireResource(gfx::Size size) {
return make_scoped_ptr(resource);
}
- // Create new resource.
scoped_ptr<ScopedResource> resource =
ScopedResource::Create(resource_provider_);
resource->AllocateManaged(size, target_, format_);
- // Extend all read locks on all resources until the resource is
- // finished being used, such that we know when resources are
- // truly safe to recycle.
- resource_provider_->EnableReadLockFences(resource->id(), true);
-
memory_usage_bytes_ += resource->bytes();
++resource_count_;
return resource.Pass();
@@ -69,10 +64,9 @@ void ResourcePool::ReleaseResource(scoped_ptr<ScopedResource> resource) {
busy_resources_.push_back(resource.release());
}
-void ResourcePool::SetResourceUsageLimits(
- size_t max_memory_usage_bytes,
- size_t max_unused_memory_usage_bytes,
- size_t max_resource_count) {
+void ResourcePool::SetResourceUsageLimits(size_t max_memory_usage_bytes,
+ size_t max_unused_memory_usage_bytes,
+ size_t max_resource_count) {
max_memory_usage_bytes_ = max_memory_usage_bytes;
max_unused_memory_usage_bytes_ = max_unused_memory_usage_bytes;
max_resource_count_ = max_resource_count;
diff --git a/chromium/cc/resources/resource_pool.h b/chromium/cc/resources/resource_pool.h
index 3c6b23f642a..5f481e986a1 100644
--- a/chromium/cc/resources/resource_pool.h
+++ b/chromium/cc/resources/resource_pool.h
@@ -21,14 +21,12 @@ class CC_EXPORT ResourcePool {
static scoped_ptr<ResourcePool> Create(ResourceProvider* resource_provider,
GLenum target,
ResourceFormat format) {
- return make_scoped_ptr(new ResourcePool(resource_provider,
- target,
- format));
+ return make_scoped_ptr(new ResourcePool(resource_provider, target, format));
}
virtual ~ResourcePool();
- scoped_ptr<ScopedResource> AcquireResource(gfx::Size size);
+ scoped_ptr<ScopedResource> AcquireResource(const gfx::Size& size);
void ReleaseResource(scoped_ptr<ScopedResource>);
void SetResourceUsageLimits(size_t max_memory_usage_bytes,
@@ -38,16 +36,17 @@ class CC_EXPORT ResourcePool {
void ReduceResourceUsage();
void CheckBusyResources();
- size_t total_memory_usage_bytes() const {
- return memory_usage_bytes_;
- }
+ size_t total_memory_usage_bytes() const { return memory_usage_bytes_; }
size_t acquired_memory_usage_bytes() const {
return memory_usage_bytes_ - unused_memory_usage_bytes_;
}
+ size_t total_resource_count() const { return resource_count_; }
size_t acquired_resource_count() const {
return resource_count_ - unused_resources_.size();
}
+ ResourceFormat resource_format() const { return format_; }
+
protected:
ResourcePool(ResourceProvider* resource_provider,
GLenum target,
diff --git a/chromium/cc/resources/resource_provider.cc b/chromium/cc/resources/resource_provider.cc
index 1331ca2f1cf..e3c21ff7c6b 100644
--- a/chromium/cc/resources/resource_provider.cc
+++ b/chromium/cc/resources/resource_provider.cc
@@ -17,12 +17,15 @@
#include "cc/resources/platform_color.h"
#include "cc/resources/returned_resource.h"
#include "cc/resources/shared_bitmap_manager.h"
+#include "cc/resources/texture_uploader.h"
#include "cc/resources/transferable_resource.h"
-#include "cc/scheduler/texture_uploader.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "third_party/khronos/GLES2/gl2ext.h"
+#include "third_party/skia/include/core/SkSurface.h"
+#include "third_party/skia/include/gpu/GrContext.h"
+#include "third_party/skia/include/gpu/SkGpuDevice.h"
#include "ui/gfx/frame_time.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/vector2d.h"
@@ -91,6 +94,42 @@ bool IsFormatSupportedForStorage(ResourceFormat format) {
return false;
}
+GrPixelConfig ToGrPixelConfig(ResourceFormat format) {
+ switch (format) {
+ case RGBA_8888:
+ return kRGBA_8888_GrPixelConfig;
+ case BGRA_8888:
+ return kBGRA_8888_GrPixelConfig;
+ case RGBA_4444:
+ return kRGBA_4444_GrPixelConfig;
+ default:
+ break;
+ }
+ DCHECK(false) << "Unsupported resource format.";
+ return kSkia8888_GrPixelConfig;
+}
+
+class IdentityAllocator : public SkBitmap::Allocator {
+ public:
+ explicit IdentityAllocator(void* buffer) : buffer_(buffer) {}
+ virtual bool allocPixelRef(SkBitmap* dst, SkColorTable*) OVERRIDE {
+ dst->setPixels(buffer_);
+ return true;
+ }
+
+ private:
+ void* buffer_;
+};
+
+void CopyBitmap(const SkBitmap& src, uint8_t* dst, SkColorType dst_colorType) {
+ SkBitmap dst_bitmap;
+ IdentityAllocator allocator(dst);
+ src.copyTo(&dst_bitmap, dst_colorType, &allocator);
+ // TODO(kaanb): The GL pipeline assumes a 4-byte alignment for the
+ // bitmap data. This check will be removed once crbug.com/293728 is fixed.
+ CHECK_EQ(0u, dst_bitmap.rowBytes() % 4);
+}
+
class ScopedSetActiveTexture {
public:
ScopedSetActiveTexture(GLES2Interface* gl, GLenum unit)
@@ -159,6 +198,30 @@ class BufferIdAllocator : public IdAllocator {
DISALLOW_COPY_AND_ASSIGN(BufferIdAllocator);
};
+// Generic fence implementation for query objects. Fence has passed when query
+// result is available.
+class QueryFence : public ResourceProvider::Fence {
+ public:
+ QueryFence(gpu::gles2::GLES2Interface* gl, unsigned query_id)
+ : gl_(gl), query_id_(query_id) {}
+
+ // Overridden from ResourceProvider::Fence:
+ virtual bool HasPassed() OVERRIDE {
+ unsigned available = 1;
+ gl_->GetQueryObjectuivEXT(
+ query_id_, GL_QUERY_RESULT_AVAILABLE_EXT, &available);
+ return !!available;
+ }
+
+ private:
+ virtual ~QueryFence() {}
+
+ gpu::gles2::GLES2Interface* gl_;
+ unsigned query_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(QueryFence);
+};
+
} // namespace
ResourceProvider::Resource::Resource()
@@ -166,38 +229,41 @@ ResourceProvider::Resource::Resource()
gl_id(0),
gl_pixel_buffer_id(0),
gl_upload_query_id(0),
+ gl_read_lock_query_id(0),
pixels(NULL),
- pixel_buffer(NULL),
lock_for_read_count(0),
imported_count(0),
exported_count(0),
+ dirty_image(false),
locked_for_write(false),
- external(false),
+ lost(false),
marked_for_deletion(false),
pending_set_pixels(false),
set_pixels_completion_forced(false),
allocated(false),
enable_read_lock_fences(false),
+ has_shared_bitmap_id(false),
+ allow_overlay(false),
read_lock_fence(NULL),
size(),
+ origin(Internal),
target(0),
original_filter(0),
filter(0),
image_id(0),
bound_image_id(0),
- dirty_image(false),
texture_pool(0),
wrap_mode(0),
- lost(false),
hint(TextureUsageAny),
- type(static_cast<ResourceType>(0)),
+ type(InvalidType),
format(RGBA_8888),
shared_bitmap(NULL) {}
ResourceProvider::Resource::~Resource() {}
ResourceProvider::Resource::Resource(GLuint texture_id,
- gfx::Size size,
+ const gfx::Size& size,
+ Origin origin,
GLenum target,
GLenum filter,
GLenum texture_pool,
@@ -208,73 +274,319 @@ ResourceProvider::Resource::Resource(GLuint texture_id,
gl_id(texture_id),
gl_pixel_buffer_id(0),
gl_upload_query_id(0),
+ gl_read_lock_query_id(0),
pixels(NULL),
- pixel_buffer(NULL),
lock_for_read_count(0),
imported_count(0),
exported_count(0),
+ dirty_image(false),
locked_for_write(false),
- external(false),
+ lost(false),
marked_for_deletion(false),
pending_set_pixels(false),
set_pixels_completion_forced(false),
allocated(false),
enable_read_lock_fences(false),
+ has_shared_bitmap_id(false),
+ allow_overlay(false),
read_lock_fence(NULL),
size(size),
+ origin(origin),
target(target),
original_filter(filter),
filter(filter),
image_id(0),
bound_image_id(0),
- dirty_image(false),
texture_pool(texture_pool),
wrap_mode(wrap_mode),
- lost(false),
hint(hint),
type(GLTexture),
format(format),
shared_bitmap(NULL) {
DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT);
+ DCHECK_EQ(origin == Internal, !!texture_pool);
}
ResourceProvider::Resource::Resource(uint8_t* pixels,
SharedBitmap* bitmap,
- gfx::Size size,
+ const gfx::Size& size,
+ Origin origin,
GLenum filter,
GLint wrap_mode)
: child_id(0),
gl_id(0),
gl_pixel_buffer_id(0),
gl_upload_query_id(0),
+ gl_read_lock_query_id(0),
pixels(pixels),
- pixel_buffer(NULL),
lock_for_read_count(0),
imported_count(0),
exported_count(0),
+ dirty_image(false),
locked_for_write(false),
- external(false),
+ lost(false),
marked_for_deletion(false),
pending_set_pixels(false),
set_pixels_completion_forced(false),
allocated(false),
enable_read_lock_fences(false),
+ has_shared_bitmap_id(!!bitmap),
+ allow_overlay(false),
read_lock_fence(NULL),
size(size),
+ origin(origin),
target(0),
original_filter(filter),
filter(filter),
image_id(0),
bound_image_id(0),
- dirty_image(false),
texture_pool(0),
wrap_mode(wrap_mode),
- lost(false),
hint(TextureUsageAny),
type(Bitmap),
format(RGBA_8888),
shared_bitmap(bitmap) {
DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT);
+ DCHECK(origin == Delegated || pixels);
+ if (bitmap)
+ shared_bitmap_id = bitmap->id();
+}
+
+ResourceProvider::Resource::Resource(const SharedBitmapId& bitmap_id,
+ const gfx::Size& size,
+ Origin origin,
+ GLenum filter,
+ GLint wrap_mode)
+ : child_id(0),
+ gl_id(0),
+ gl_pixel_buffer_id(0),
+ gl_upload_query_id(0),
+ gl_read_lock_query_id(0),
+ pixels(NULL),
+ lock_for_read_count(0),
+ imported_count(0),
+ exported_count(0),
+ dirty_image(false),
+ locked_for_write(false),
+ lost(false),
+ marked_for_deletion(false),
+ pending_set_pixels(false),
+ set_pixels_completion_forced(false),
+ allocated(false),
+ enable_read_lock_fences(false),
+ has_shared_bitmap_id(true),
+ allow_overlay(false),
+ read_lock_fence(NULL),
+ size(size),
+ origin(origin),
+ target(0),
+ original_filter(filter),
+ filter(filter),
+ image_id(0),
+ bound_image_id(0),
+ texture_pool(0),
+ wrap_mode(wrap_mode),
+ hint(TextureUsageAny),
+ type(Bitmap),
+ format(RGBA_8888),
+ shared_bitmap_id(bitmap_id),
+ shared_bitmap(NULL) {
+ DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT);
+}
+
+ResourceProvider::RasterBuffer::RasterBuffer(
+ const Resource* resource,
+ ResourceProvider* resource_provider)
+ : resource_(resource),
+ resource_provider_(resource_provider),
+ locked_canvas_(NULL),
+ canvas_save_count_(0) {
+ DCHECK(resource_);
+ DCHECK(resource_provider_);
+}
+
+ResourceProvider::RasterBuffer::~RasterBuffer() {}
+
+SkCanvas* ResourceProvider::RasterBuffer::LockForWrite() {
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
+ "ResourceProvider::RasterBuffer::LockForWrite");
+
+ DCHECK(!locked_canvas_);
+
+ locked_canvas_ = DoLockForWrite();
+ canvas_save_count_ = locked_canvas_ ? locked_canvas_->save() : 0;
+ return locked_canvas_;
+}
+
+bool ResourceProvider::RasterBuffer::UnlockForWrite() {
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
+ "ResourceProvider::RasterBuffer::UnlockForWrite");
+
+ if (locked_canvas_) {
+ locked_canvas_->restoreToCount(canvas_save_count_);
+ locked_canvas_ = NULL;
+ }
+ return DoUnlockForWrite();
+}
+
+ResourceProvider::DirectRasterBuffer::DirectRasterBuffer(
+ const Resource* resource,
+ ResourceProvider* resource_provider,
+ bool use_distance_field_text )
+ : RasterBuffer(resource, resource_provider),
+ surface_generation_id_(0u),
+ use_distance_field_text_(use_distance_field_text) {}
+
+ResourceProvider::DirectRasterBuffer::~DirectRasterBuffer() {}
+
+SkCanvas* ResourceProvider::DirectRasterBuffer::DoLockForWrite() {
+ if (!surface_)
+ surface_ = CreateSurface();
+ surface_generation_id_ = surface_ ? surface_->generationID() : 0u;
+ return surface_ ? surface_->getCanvas() : NULL;
+}
+
+bool ResourceProvider::DirectRasterBuffer::DoUnlockForWrite() {
+ // generationID returns a non-zero, unique value corresponding to the content
+ // of surface. Hence, a change since DoLockForWrite was called means the
+ // surface has changed.
+ return surface_ ? surface_generation_id_ != surface_->generationID() : false;
+}
+
+skia::RefPtr<SkSurface> ResourceProvider::DirectRasterBuffer::CreateSurface() {
+ skia::RefPtr<SkSurface> surface;
+ switch (resource()->type) {
+ case GLTexture: {
+ DCHECK(resource()->gl_id);
+ class GrContext* gr_context = resource_provider()->GrContext();
+ if (gr_context) {
+ GrBackendTextureDesc desc;
+ desc.fFlags = kRenderTarget_GrBackendTextureFlag;
+ desc.fWidth = resource()->size.width();
+ desc.fHeight = resource()->size.height();
+ desc.fConfig = ToGrPixelConfig(resource()->format);
+ desc.fOrigin = kTopLeft_GrSurfaceOrigin;
+ desc.fTextureHandle = resource()->gl_id;
+ skia::RefPtr<GrTexture> gr_texture =
+ skia::AdoptRef(gr_context->wrapBackendTexture(desc));
+ SkSurface::TextRenderMode text_render_mode =
+ use_distance_field_text_ ? SkSurface::kDistanceField_TextRenderMode
+ : SkSurface::kStandard_TextRenderMode;
+ surface = skia::AdoptRef(SkSurface::NewRenderTargetDirect(
+ gr_texture->asRenderTarget(), text_render_mode));
+ }
+ break;
+ }
+ case Bitmap: {
+ DCHECK(resource()->pixels);
+ DCHECK_EQ(RGBA_8888, resource()->format);
+ SkImageInfo image_info = SkImageInfo::MakeN32Premul(
+ resource()->size.width(), resource()->size.height());
+ surface = skia::AdoptRef(SkSurface::NewRasterDirect(
+ image_info, resource()->pixels, image_info.minRowBytes()));
+ break;
+ }
+ default:
+ NOTREACHED();
+ }
+ return surface;
+}
+
+ResourceProvider::BitmapRasterBuffer::BitmapRasterBuffer(
+ const Resource* resource,
+ ResourceProvider* resource_provider)
+ : RasterBuffer(resource, resource_provider),
+ mapped_buffer_(NULL),
+ raster_bitmap_generation_id_(0u) {}
+
+ResourceProvider::BitmapRasterBuffer::~BitmapRasterBuffer() {}
+
+SkCanvas* ResourceProvider::BitmapRasterBuffer::DoLockForWrite() {
+ DCHECK(!mapped_buffer_);
+ DCHECK(!raster_canvas_);
+
+ int stride = 0;
+ mapped_buffer_ = MapBuffer(&stride);
+ if (!mapped_buffer_)
+ return NULL;
+
+ switch (resource()->format) {
+ case RGBA_4444:
+ // Use the default stride if we will eventually convert this
+ // bitmap to 4444.
+ raster_bitmap_.allocN32Pixels(resource()->size.width(),
+ resource()->size.height());
+ break;
+ case RGBA_8888:
+ case BGRA_8888: {
+ SkImageInfo info = SkImageInfo::MakeN32Premul(resource()->size.width(),
+ resource()->size.height());
+ if (0 == stride)
+ stride = info.minRowBytes();
+ raster_bitmap_.installPixels(info, mapped_buffer_, stride);
+ break;
+ }
+ case LUMINANCE_8:
+ case RGB_565:
+ case ETC1:
+ NOTREACHED();
+ break;
+ }
+ raster_canvas_ = skia::AdoptRef(new SkCanvas(raster_bitmap_));
+ raster_bitmap_generation_id_ = raster_bitmap_.getGenerationID();
+ return raster_canvas_.get();
+}
+
+bool ResourceProvider::BitmapRasterBuffer::DoUnlockForWrite() {
+ raster_canvas_.clear();
+
+ // getGenerationID returns a non-zero, unique value corresponding to the
+ // pixels in bitmap. Hence, a change since DoLockForWrite was called means the
+ // bitmap has changed.
+ bool raster_bitmap_changed =
+ raster_bitmap_generation_id_ != raster_bitmap_.getGenerationID();
+
+ if (raster_bitmap_changed) {
+ SkColorType buffer_colorType =
+ ResourceFormatToSkColorType(resource()->format);
+ if (mapped_buffer_ && (buffer_colorType != raster_bitmap_.colorType()))
+ CopyBitmap(raster_bitmap_, mapped_buffer_, buffer_colorType);
+ }
+ raster_bitmap_.reset();
+
+ UnmapBuffer();
+ mapped_buffer_ = NULL;
+ return raster_bitmap_changed;
+}
+
+ResourceProvider::ImageRasterBuffer::ImageRasterBuffer(
+ const Resource* resource,
+ ResourceProvider* resource_provider)
+ : BitmapRasterBuffer(resource, resource_provider) {}
+
+ResourceProvider::ImageRasterBuffer::~ImageRasterBuffer() {}
+
+uint8_t* ResourceProvider::ImageRasterBuffer::MapBuffer(int* stride) {
+ return resource_provider()->MapImage(resource(), stride);
+}
+
+void ResourceProvider::ImageRasterBuffer::UnmapBuffer() {
+ resource_provider()->UnmapImage(resource());
+}
+
+ResourceProvider::PixelRasterBuffer::PixelRasterBuffer(
+ const Resource* resource,
+ ResourceProvider* resource_provider)
+ : BitmapRasterBuffer(resource, resource_provider) {}
+
+ResourceProvider::PixelRasterBuffer::~PixelRasterBuffer() {}
+
+uint8_t* ResourceProvider::PixelRasterBuffer::MapBuffer(int* stride) {
+ return resource_provider()->MapPixelBuffer(resource(), stride);
+}
+
+void ResourceProvider::PixelRasterBuffer::UnmapBuffer() {
+ resource_provider()->UnmapPixelBuffer(resource());
}
ResourceProvider::Child::Child() : marked_for_deletion(false) {}
@@ -286,24 +598,20 @@ scoped_ptr<ResourceProvider> ResourceProvider::Create(
SharedBitmapManager* shared_bitmap_manager,
int highp_threshold_min,
bool use_rgba_4444_texture_format,
- size_t id_allocation_chunk_size) {
+ size_t id_allocation_chunk_size,
+ bool use_distance_field_text) {
scoped_ptr<ResourceProvider> resource_provider(
new ResourceProvider(output_surface,
shared_bitmap_manager,
highp_threshold_min,
use_rgba_4444_texture_format,
- id_allocation_chunk_size));
+ id_allocation_chunk_size,
+ use_distance_field_text));
- bool success = false;
- if (resource_provider->ContextGL()) {
- success = resource_provider->InitializeGL();
- } else {
+ if (resource_provider->ContextGL())
+ resource_provider->InitializeGL();
+ else
resource_provider->InitializeSoftware();
- success = true;
- }
-
- if (!success)
- return scoped_ptr<ResourceProvider>();
DCHECK_NE(InvalidType, resource_provider->default_resource_type());
return resource_provider.Pass();
@@ -329,8 +637,13 @@ bool ResourceProvider::IsLost(ResourceId id) {
return resource->lost;
}
+bool ResourceProvider::AllowOverlay(ResourceId id) {
+ Resource* resource = GetResource(id);
+ return resource->allow_overlay;
+}
+
ResourceProvider::ResourceId ResourceProvider::CreateResource(
- gfx::Size size,
+ const gfx::Size& size,
GLint wrap_mode,
TextureUsageHint hint,
ResourceFormat format) {
@@ -355,7 +668,7 @@ ResourceProvider::ResourceId ResourceProvider::CreateResource(
}
ResourceProvider::ResourceId ResourceProvider::CreateManagedResource(
- gfx::Size size,
+ const gfx::Size& size,
GLenum target,
GLint wrap_mode,
TextureUsageHint hint,
@@ -381,7 +694,7 @@ ResourceProvider::ResourceId ResourceProvider::CreateManagedResource(
}
ResourceProvider::ResourceId ResourceProvider::CreateGLTexture(
- gfx::Size size,
+ const gfx::Size& size,
GLenum target,
GLenum texture_pool,
GLint wrap_mode,
@@ -392,15 +705,22 @@ ResourceProvider::ResourceId ResourceProvider::CreateGLTexture(
DCHECK(thread_checker_.CalledOnValidThread());
ResourceId id = next_id_++;
- Resource resource(
- 0, size, target, GL_LINEAR, texture_pool, wrap_mode, hint, format);
+ Resource resource(0,
+ size,
+ Resource::Internal,
+ target,
+ GL_LINEAR,
+ texture_pool,
+ wrap_mode,
+ hint,
+ format);
resource.allocated = false;
resources_[id] = resource;
return id;
}
ResourceProvider::ResourceId ResourceProvider::CreateBitmap(
- gfx::Size size, GLint wrap_mode) {
+ const gfx::Size& size, GLint wrap_mode) {
DCHECK(thread_checker_.CalledOnValidThread());
scoped_ptr<SharedBitmap> bitmap;
@@ -408,45 +728,43 @@ ResourceProvider::ResourceId ResourceProvider::CreateBitmap(
bitmap = shared_bitmap_manager_->AllocateSharedBitmap(size);
uint8_t* pixels;
- if (bitmap)
+ if (bitmap) {
pixels = bitmap->pixels();
- else
- pixels = new uint8_t[4 * size.GetArea()];
+ } else {
+ size_t bytes = SharedBitmap::CheckedSizeInBytes(size);
+ pixels = new uint8_t[bytes];
+ }
+ DCHECK(pixels);
ResourceId id = next_id_++;
Resource resource(
- pixels, bitmap.release(), size, GL_LINEAR, wrap_mode);
+ pixels, bitmap.release(), size, Resource::Internal, GL_LINEAR, wrap_mode);
resource.allocated = true;
resources_[id] = resource;
return id;
}
-ResourceProvider::ResourceId
-ResourceProvider::CreateResourceFromExternalTexture(
- GLuint texture_target,
- GLuint texture_id) {
+ResourceProvider::ResourceId ResourceProvider::CreateResourceFromIOSurface(
+ const gfx::Size& size,
+ unsigned io_surface_id) {
DCHECK(thread_checker_.CalledOnValidThread());
- GLES2Interface* gl = ContextGL();
- DCHECK(gl);
- GLC(gl, gl->BindTexture(texture_target, texture_id));
- GLC(gl, gl->TexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
- GLC(gl, gl->TexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
- GLC(gl,
- gl->TexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
- GLC(gl,
- gl->TexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
-
ResourceId id = next_id_++;
- Resource resource(texture_id,
+ Resource resource(0,
gfx::Size(),
- texture_target,
+ Resource::Internal,
+ GL_TEXTURE_RECTANGLE_ARB,
GL_LINEAR,
- 0,
+ GL_TEXTURE_POOL_UNMANAGED_CHROMIUM,
GL_CLAMP_TO_EDGE,
TextureUsageAny,
RGBA_8888);
- resource.external = true;
+ LazyCreate(&resource);
+ GLES2Interface* gl = ContextGL();
+ DCHECK(gl);
+ gl->BindTexture(GL_TEXTURE_RECTANGLE_ARB, resource.gl_id);
+ gl->TexImageIOSurface2DCHROMIUM(
+ GL_TEXTURE_RECTANGLE_ARB, size.width(), size.height(), io_surface_id, 0);
resource.allocated = true;
resources_[id] = resource;
return id;
@@ -463,6 +781,7 @@ ResourceProvider::ResourceId ResourceProvider::CreateResourceFromTextureMailbox(
if (mailbox.IsTexture()) {
resource = Resource(0,
gfx::Size(),
+ Resource::External,
mailbox.target(),
GL_LINEAR,
0,
@@ -474,6 +793,7 @@ ResourceProvider::ResourceId ResourceProvider::CreateResourceFromTextureMailbox(
base::SharedMemory* shared_memory = mailbox.shared_memory();
DCHECK(shared_memory->memory());
uint8_t* pixels = reinterpret_cast<uint8_t*>(shared_memory->memory());
+ DCHECK(pixels);
scoped_ptr<SharedBitmap> shared_bitmap;
if (shared_bitmap_manager_) {
shared_bitmap =
@@ -482,15 +802,16 @@ ResourceProvider::ResourceId ResourceProvider::CreateResourceFromTextureMailbox(
resource = Resource(pixels,
shared_bitmap.release(),
mailbox.shared_memory_size(),
+ Resource::External,
GL_LINEAR,
GL_CLAMP_TO_EDGE);
}
- resource.external = true;
resource.allocated = true;
resource.mailbox = mailbox;
resource.release_callback =
base::Bind(&SingleReleaseCallback::Run,
base::Owned(release_callback.release()));
+ resource.allow_overlay = mailbox.allow_overlay();
return id;
}
@@ -499,12 +820,11 @@ void ResourceProvider::DeleteResource(ResourceId id) {
ResourceMap::iterator it = resources_.find(id);
CHECK(it != resources_.end());
Resource* resource = &it->second;
- DCHECK(!resource->lock_for_read_count);
DCHECK(!resource->marked_for_deletion);
DCHECK_EQ(resource->imported_count, 0);
DCHECK(resource->pending_set_pixels || !resource->locked_for_write);
- if (resource->exported_count > 0) {
+ if (resource->exported_count > 0 || resource->lock_for_read_count > 0) {
resource->marked_for_deletion = true;
return;
} else {
@@ -522,37 +842,48 @@ void ResourceProvider::DeleteResourceInternal(ResourceMap::iterator it,
if (style == ForShutdown && resource->exported_count > 0)
lost_resource = true;
+ resource->direct_raster_buffer.reset();
+ resource->image_raster_buffer.reset();
+ resource->pixel_raster_buffer.reset();
+
if (resource->image_id) {
+ DCHECK(resource->origin == Resource::Internal);
GLES2Interface* gl = ContextGL();
DCHECK(gl);
GLC(gl, gl->DestroyImageCHROMIUM(resource->image_id));
}
-
- if (resource->gl_id && !resource->external) {
+ if (resource->gl_upload_query_id) {
+ DCHECK(resource->origin == Resource::Internal);
GLES2Interface* gl = ContextGL();
DCHECK(gl);
- GLC(gl, gl->DeleteTextures(1, &resource->gl_id));
+ GLC(gl, gl->DeleteQueriesEXT(1, &resource->gl_upload_query_id));
}
- if (resource->gl_upload_query_id) {
+ if (resource->gl_read_lock_query_id) {
+ DCHECK(resource->origin == Resource::Internal);
GLES2Interface* gl = ContextGL();
DCHECK(gl);
- GLC(gl, gl->DeleteQueriesEXT(1, &resource->gl_upload_query_id));
+ GLC(gl, gl->DeleteQueriesEXT(1, &resource->gl_read_lock_query_id));
}
if (resource->gl_pixel_buffer_id) {
+ DCHECK(resource->origin == Resource::Internal);
GLES2Interface* gl = ContextGL();
DCHECK(gl);
GLC(gl, gl->DeleteBuffers(1, &resource->gl_pixel_buffer_id));
}
- if (resource->mailbox.IsValid() && resource->external) {
+ if (resource->origin == Resource::External) {
+ DCHECK(resource->mailbox.IsValid());
GLuint sync_point = resource->mailbox.sync_point();
- if (resource->mailbox.IsTexture()) {
+ if (resource->type == GLTexture) {
+ DCHECK(resource->mailbox.IsTexture());
lost_resource |= lost_output_surface_;
GLES2Interface* gl = ContextGL();
DCHECK(gl);
- if (resource->gl_id)
+ if (resource->gl_id) {
GLC(gl, gl->DeleteTextures(1, &resource->gl_id));
- if (!lost_resource && resource->gl_id)
- sync_point = gl->InsertSyncPointCHROMIUM();
+ resource->gl_id = 0;
+ if (!lost_resource)
+ sync_point = gl->InsertSyncPointCHROMIUM();
+ }
} else {
DCHECK(resource->mailbox.IsSharedMemory());
base::SharedMemory* shared_memory = resource->mailbox.shared_memory();
@@ -565,15 +896,22 @@ void ResourceProvider::DeleteResourceInternal(ResourceMap::iterator it,
}
resource->release_callback.Run(sync_point, lost_resource);
}
+ if (resource->gl_id) {
+ GLES2Interface* gl = ContextGL();
+ DCHECK(gl);
+ GLC(gl, gl->DeleteTextures(1, &resource->gl_id));
+ resource->gl_id = 0;
+ }
if (resource->shared_bitmap) {
+ DCHECK(resource->origin != Resource::External);
+ DCHECK_EQ(Bitmap, resource->type);
delete resource->shared_bitmap;
resource->pixels = NULL;
}
- if (resource->pixels)
+ if (resource->pixels) {
+ DCHECK(resource->origin == Resource::Internal);
delete[] resource->pixels;
- if (resource->pixel_buffer)
- delete[] resource->pixel_buffer;
-
+ }
resources_.erase(it);
}
@@ -584,18 +922,19 @@ ResourceProvider::ResourceType ResourceProvider::GetResourceType(
void ResourceProvider::SetPixels(ResourceId id,
const uint8_t* image,
- gfx::Rect image_rect,
- gfx::Rect source_rect,
- gfx::Vector2d dest_offset) {
+ const gfx::Rect& image_rect,
+ const gfx::Rect& source_rect,
+ const gfx::Vector2d& dest_offset) {
Resource* resource = GetResource(id);
DCHECK(!resource->locked_for_write);
DCHECK(!resource->lock_for_read_count);
- DCHECK(!resource->external);
+ DCHECK(resource->origin == Resource::Internal);
DCHECK_EQ(resource->exported_count, 0);
DCHECK(ReadLockFenceHasPassed(resource));
LazyAllocate(resource);
- if (resource->gl_id) {
+ if (resource->type == GLTexture) {
+ DCHECK(resource->gl_id);
DCHECK(!resource->pending_set_pixels);
DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D));
GLES2Interface* gl = ContextGL();
@@ -608,26 +947,24 @@ void ResourceProvider::SetPixels(ResourceId id,
dest_offset,
resource->format,
resource->size);
- }
-
- if (resource->pixels) {
+ } else {
+ DCHECK_EQ(Bitmap, resource->type);
DCHECK(resource->allocated);
DCHECK_EQ(RGBA_8888, resource->format);
- SkBitmap src_full;
- src_full.setConfig(
- SkBitmap::kARGB_8888_Config, image_rect.width(), image_rect.height());
- src_full.setPixels(const_cast<uint8_t*>(image));
- SkBitmap src_subset;
- SkIRect sk_source_rect = SkIRect::MakeXYWH(source_rect.x(),
- source_rect.y(),
- source_rect.width(),
- source_rect.height());
- sk_source_rect.offset(-image_rect.x(), -image_rect.y());
- src_full.extractSubset(&src_subset, sk_source_rect);
+ DCHECK(source_rect.x() >= image_rect.x());
+ DCHECK(source_rect.y() >= image_rect.y());
+ DCHECK(source_rect.right() <= image_rect.right());
+ DCHECK(source_rect.bottom() <= image_rect.bottom());
+ SkImageInfo source_info =
+ SkImageInfo::MakeN32Premul(source_rect.width(), source_rect.height());
+ size_t image_row_bytes = image_rect.width() * 4;
+ gfx::Vector2d source_offset = source_rect.origin() - image_rect.origin();
+ image += source_offset.y() * image_row_bytes + source_offset.x() * 4;
ScopedWriteLockSoftware lock(this, id);
SkCanvas* dest = lock.sk_canvas();
- dest->writePixels(src_subset, dest_offset.x(), dest_offset.y());
+ dest->writePixels(
+ source_info, image, image_row_bytes, dest_offset.x(), dest_offset.y());
}
}
@@ -733,19 +1070,30 @@ const ResourceProvider::Resource* ResourceProvider::LockForRead(ResourceId id) {
LazyCreate(resource);
- if (resource->external) {
- if (!resource->gl_id && resource->mailbox.IsTexture()) {
- GLES2Interface* gl = ContextGL();
- DCHECK(gl);
- if (resource->mailbox.sync_point()) {
- GLC(gl, gl->WaitSyncPointCHROMIUM(resource->mailbox.sync_point()));
- resource->mailbox.ResetSyncPoint();
- }
- resource->gl_id = texture_id_allocator_->NextId();
- GLC(gl, gl->BindTexture(resource->target, resource->gl_id));
- GLC(gl,
- gl->ConsumeTextureCHROMIUM(resource->target,
- resource->mailbox.data()));
+ if (resource->type == GLTexture && !resource->gl_id) {
+ DCHECK(resource->origin != Resource::Internal);
+ DCHECK(resource->mailbox.IsTexture());
+ GLES2Interface* gl = ContextGL();
+ DCHECK(gl);
+ if (resource->mailbox.sync_point()) {
+ GLC(gl, gl->WaitSyncPointCHROMIUM(resource->mailbox.sync_point()));
+ resource->mailbox.set_sync_point(0);
+ }
+ resource->gl_id = texture_id_allocator_->NextId();
+ GLC(gl, gl->BindTexture(resource->target, resource->gl_id));
+ GLC(gl,
+ gl->ConsumeTextureCHROMIUM(resource->mailbox.target(),
+ resource->mailbox.name()));
+ }
+
+ if (!resource->pixels && resource->has_shared_bitmap_id &&
+ shared_bitmap_manager_) {
+ scoped_ptr<SharedBitmap> bitmap =
+ shared_bitmap_manager_->GetSharedBitmapFromId(
+ resource->size, resource->shared_bitmap_id);
+ if (bitmap) {
+ resource->shared_bitmap = bitmap.release();
+ resource->pixels = resource->shared_bitmap->pixels();
}
}
@@ -757,10 +1105,25 @@ const ResourceProvider::Resource* ResourceProvider::LockForRead(ResourceId id) {
}
void ResourceProvider::UnlockForRead(ResourceId id) {
- Resource* resource = GetResource(id);
+ DCHECK(thread_checker_.CalledOnValidThread());
+ ResourceMap::iterator it = resources_.find(id);
+ CHECK(it != resources_.end());
+
+ Resource* resource = &it->second;
DCHECK_GT(resource->lock_for_read_count, 0);
DCHECK_EQ(resource->exported_count, 0);
resource->lock_for_read_count--;
+ if (resource->marked_for_deletion && !resource->lock_for_read_count) {
+ if (!resource->child_id) {
+ // The resource belongs to this ResourceProvider, so it can be destroyed.
+ DeleteResourceInternal(it, Normal);
+ } else {
+ ChildMap::iterator child_it = children_.find(resource->child_id);
+ ResourceIdArray unused;
+ unused.push_back(id);
+ DeleteAndReturnUnusedResourcesToChild(child_it, Normal, unused);
+ }
+ }
}
const ResourceProvider::Resource* ResourceProvider::LockForWrite(
@@ -769,7 +1132,7 @@ const ResourceProvider::Resource* ResourceProvider::LockForWrite(
DCHECK(!resource->locked_for_write);
DCHECK(!resource->lock_for_read_count);
DCHECK_EQ(resource->exported_count, 0);
- DCHECK(!resource->external);
+ DCHECK(resource->origin == Resource::Internal);
DCHECK(!resource->lost);
DCHECK(ReadLockFenceHasPassed(resource));
LazyAllocate(resource);
@@ -781,15 +1144,15 @@ const ResourceProvider::Resource* ResourceProvider::LockForWrite(
bool ResourceProvider::CanLockForWrite(ResourceId id) {
Resource* resource = GetResource(id);
return !resource->locked_for_write && !resource->lock_for_read_count &&
- !resource->exported_count && !resource->external && !resource->lost &&
- ReadLockFenceHasPassed(resource);
+ !resource->exported_count && resource->origin == Resource::Internal &&
+ !resource->lost && ReadLockFenceHasPassed(resource);
}
void ResourceProvider::UnlockForWrite(ResourceId id) {
Resource* resource = GetResource(id);
DCHECK(resource->locked_for_write);
DCHECK_EQ(resource->exported_count, 0);
- DCHECK(!resource->external);
+ DCHECK(resource->origin == Resource::Internal);
resource->locked_for_write = false;
}
@@ -843,12 +1206,10 @@ ResourceProvider::ScopedWriteLockGL::~ScopedWriteLockGL() {
void ResourceProvider::PopulateSkBitmapWithResource(
SkBitmap* sk_bitmap, const Resource* resource) {
- DCHECK(resource->pixels);
DCHECK_EQ(RGBA_8888, resource->format);
- sk_bitmap->setConfig(SkBitmap::kARGB_8888_Config,
- resource->size.width(),
- resource->size.height());
- sk_bitmap->setPixels(resource->pixels);
+ SkImageInfo info = SkImageInfo::MakeN32Premul(resource->size.width(),
+ resource->size.height());
+ sk_bitmap->installPixels(info, resource->pixels, info.minRowBytes());
}
ResourceProvider::ScopedReadLockSoftware::ScopedReadLockSoftware(
@@ -872,6 +1233,7 @@ ResourceProvider::ScopedWriteLockSoftware::ScopedWriteLockSoftware(
resource_id_(resource_id) {
ResourceProvider::PopulateSkBitmapWithResource(
&sk_bitmap_, resource_provider->LockForWrite(resource_id));
+ DCHECK(valid());
sk_canvas_.reset(new SkCanvas(sk_bitmap_));
}
@@ -883,7 +1245,8 @@ ResourceProvider::ResourceProvider(OutputSurface* output_surface,
SharedBitmapManager* shared_bitmap_manager,
int highp_threshold_min,
bool use_rgba_4444_texture_format,
- size_t id_allocation_chunk_size)
+ size_t id_allocation_chunk_size,
+ bool use_distance_field_text)
: output_surface_(output_surface),
shared_bitmap_manager_(shared_bitmap_manager),
lost_output_surface_(false),
@@ -897,7 +1260,9 @@ ResourceProvider::ResourceProvider(OutputSurface* output_surface,
max_texture_size_(0),
best_texture_format_(RGBA_8888),
use_rgba_4444_texture_format_(use_rgba_4444_texture_format),
- id_allocation_chunk_size_(id_allocation_chunk_size) {
+ id_allocation_chunk_size_(id_allocation_chunk_size),
+ use_sync_query_(false),
+ use_distance_field_text_(use_distance_field_text) {
DCHECK(output_surface_->HasClient());
DCHECK(id_allocation_chunk_size_);
}
@@ -914,7 +1279,7 @@ void ResourceProvider::InitializeSoftware() {
best_texture_format_ = RGBA_8888;
}
-bool ResourceProvider::InitializeGL() {
+void ResourceProvider::InitializeGL() {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(!texture_uploader_);
DCHECK_NE(GLTexture, default_resource_type_);
@@ -926,10 +1291,11 @@ bool ResourceProvider::InitializeGL() {
const ContextProvider::Capabilities& caps =
output_surface_->context_provider()->ContextCapabilities();
- bool use_bgra = caps.texture_format_bgra8888;
- use_texture_storage_ext_ = caps.texture_storage;
- use_texture_usage_hint_ = caps.texture_usage;
- use_compressed_texture_etc1_ = caps.texture_format_etc1;
+ bool use_bgra = caps.gpu.texture_format_bgra8888;
+ use_texture_storage_ext_ = caps.gpu.texture_storage;
+ use_texture_usage_hint_ = caps.gpu.texture_usage;
+ use_compressed_texture_etc1_ = caps.gpu.texture_format_etc1;
+ use_sync_query_ = caps.gpu.sync_query;
GLES2Interface* gl = ContextGL();
DCHECK(gl);
@@ -943,8 +1309,6 @@ bool ResourceProvider::InitializeGL() {
new TextureIdAllocator(gl, id_allocation_chunk_size_));
buffer_id_allocator_.reset(
new BufferIdAllocator(gl, id_allocation_chunk_size_));
-
- return true;
}
void ResourceProvider::CleanUpGLIfNeeded() {
@@ -957,6 +1321,15 @@ void ResourceProvider::CleanUpGLIfNeeded() {
}
DCHECK(gl);
+#if DCHECK_IS_ON
+ // Check that all GL resources has been deleted.
+ for (ResourceMap::const_iterator itr = resources_.begin();
+ itr != resources_.end();
+ ++itr) {
+ DCHECK_NE(GLTexture, itr->second.type);
+ }
+#endif // DCHECK_IS_ON
+
texture_uploader_.reset();
texture_id_allocator_.reset();
buffer_id_allocator_.reset();
@@ -1022,7 +1395,7 @@ void ResourceProvider::PrepareSendToParent(const ResourceIdArray& resources,
++it) {
TransferableResource resource;
TransferResource(gl, *it, &resource);
- if (!resource.sync_point && !resource.is_software)
+ if (!resource.mailbox_holder.sync_point && !resource.is_software)
need_sync_point = true;
++resources_.find(*it)->second.exported_count;
list->push_back(resource);
@@ -1032,8 +1405,8 @@ void ResourceProvider::PrepareSendToParent(const ResourceIdArray& resources,
for (TransferableResourceArray::iterator it = list->begin();
it != list->end();
++it) {
- if (!it->sync_point)
- it->sync_point = sync_point;
+ if (!it->mailbox_holder.sync_point)
+ it->mailbox_holder.sync_point = sync_point;
}
}
}
@@ -1050,21 +1423,14 @@ void ResourceProvider::ReceiveFromChild(
ResourceIdMap::iterator resource_in_map_it =
child_info.child_to_parent_map.find(it->id);
if (resource_in_map_it != child_info.child_to_parent_map.end()) {
- resources_[resource_in_map_it->second].imported_count++;
+ Resource& resource = resources_[resource_in_map_it->second];
+ resource.marked_for_deletion = false;
+ resource.imported_count++;
continue;
}
- scoped_ptr<SharedBitmap> bitmap;
- uint8_t* pixels = NULL;
- if (it->is_software) {
- if (shared_bitmap_manager_)
- bitmap = shared_bitmap_manager_->GetSharedBitmapFromId(it->size,
- it->mailbox);
- if (bitmap)
- pixels = bitmap->pixels();
- }
-
- if ((!it->is_software && !gl) || (it->is_software && !pixels)) {
+ if ((!it->is_software && !gl) ||
+ (it->is_software && !shared_bitmap_manager_)) {
TRACE_EVENT0("cc", "ResourceProvider::ReceiveFromChild dropping invalid");
ReturnedResourceArray to_return;
to_return.push_back(it->ToReturnedResource());
@@ -1075,30 +1441,24 @@ void ResourceProvider::ReceiveFromChild(
ResourceId local_id = next_id_++;
Resource& resource = resources_[local_id];
if (it->is_software) {
- resource = Resource(
- pixels, bitmap.release(), it->size, GL_LINEAR, GL_CLAMP_TO_EDGE);
+ resource = Resource(it->mailbox_holder.mailbox,
+ it->size,
+ Resource::Delegated,
+ GL_LINEAR,
+ it->is_repeated ? GL_REPEAT : GL_CLAMP_TO_EDGE);
} else {
- GLuint texture_id;
- // NOTE: If the parent is a browser and the child a renderer, the parent
- // is not supposed to have its context wait, because that could induce
- // deadlocks and/or security issues. The caller is responsible for
- // waiting asynchronously, and resetting sync_point before calling this.
- // However if the parent is a renderer (e.g. browser tag), it may be ok
- // (and is simpler) to wait.
- if (it->sync_point)
- GLC(gl, gl->WaitSyncPointCHROMIUM(it->sync_point));
- texture_id = texture_id_allocator_->NextId();
- GLC(gl, gl->BindTexture(it->target, texture_id));
- GLC(gl, gl->ConsumeTextureCHROMIUM(it->target, it->mailbox.name));
- resource = Resource(texture_id,
+ resource = Resource(0,
it->size,
- it->target,
+ Resource::Delegated,
+ it->mailbox_holder.texture_target,
it->filter,
0,
- GL_CLAMP_TO_EDGE,
+ it->is_repeated ? GL_REPEAT : GL_CLAMP_TO_EDGE,
TextureUsageAny,
it->format);
- resource.mailbox.SetName(it->mailbox);
+ resource.mailbox = TextureMailbox(it->mailbox_holder.mailbox,
+ it->mailbox_holder.texture_target,
+ it->mailbox_holder.sync_point);
}
resource.child_id = child;
// Don't allocate a texture for a child.
@@ -1126,6 +1486,7 @@ void ResourceProvider::DeclareUsedResourcesFromChild(
DCHECK(it != child_info.child_to_parent_map.end());
ResourceId local_id = it->second;
+ DCHECK(!resources_[local_id].marked_for_deletion);
child_info.in_use_resources.insert(local_id);
}
@@ -1195,12 +1556,20 @@ void ResourceProvider::ReceiveReturnsFromParent(
if (resource->exported_count)
continue;
- if (resource->gl_id) {
- if (returned.sync_point)
+ // Need to wait for the current read lock fence to pass before we can
+ // recycle this resource.
+ if (resource->enable_read_lock_fences)
+ resource->read_lock_fence = current_read_lock_fence_;
+
+ if (returned.sync_point) {
+ DCHECK(!resource->has_shared_bitmap_id);
+ if (resource->origin == Resource::Internal) {
+ DCHECK(resource->gl_id);
GLC(gl, gl->WaitSyncPointCHROMIUM(returned.sync_point));
- } else if (!resource->shared_bitmap) {
- resource->mailbox =
- TextureMailbox(resource->mailbox.name(), returned.sync_point);
+ } else {
+ DCHECK(!resource->gl_id);
+ resource->mailbox.set_sync_point(returned.sync_point);
+ }
}
if (!resource->marked_for_deletion)
@@ -1212,6 +1581,7 @@ void ResourceProvider::ReceiveReturnsFromParent(
continue;
}
+ DCHECK(resource->origin == Resource::Delegated);
// Delete the resource and return it to the child it came from one.
if (resource->child_id != child_id) {
if (child_id) {
@@ -1243,34 +1613,52 @@ void ResourceProvider::TransferResource(GLES2Interface* gl,
Resource* source = GetResource(id);
DCHECK(!source->locked_for_write);
DCHECK(!source->lock_for_read_count);
- DCHECK(!source->external || (source->external && source->mailbox.IsValid()));
+ DCHECK(source->origin != Resource::External || source->mailbox.IsValid());
DCHECK(source->allocated);
- DCHECK_EQ(source->wrap_mode, GL_CLAMP_TO_EDGE);
resource->id = id;
resource->format = source->format;
- resource->target = source->target;
+ resource->mailbox_holder.texture_target = source->target;
resource->filter = source->filter;
resource->size = source->size;
+ resource->is_repeated = (source->wrap_mode == GL_REPEAT);
- if (source->shared_bitmap) {
- resource->mailbox = source->shared_bitmap->id();
+ if (source->type == Bitmap) {
+ resource->mailbox_holder.mailbox = source->shared_bitmap_id;
resource->is_software = true;
} else if (!source->mailbox.IsValid()) {
+ LazyCreate(source);
+ DCHECK(source->gl_id);
+ DCHECK(source->origin == Resource::Internal);
+ GLC(gl,
+ gl->BindTexture(resource->mailbox_holder.texture_target,
+ source->gl_id));
+ if (source->image_id) {
+ DCHECK(source->dirty_image);
+ BindImageForSampling(source);
+ }
// This is a resource allocated by the compositor, we need to produce it.
// Don't set a sync point, the caller will do it.
- DCHECK(source->gl_id);
- GLC(gl, gl->BindTexture(resource->target, source->gl_id));
- GLC(gl, gl->GenMailboxCHROMIUM(resource->mailbox.name));
+ GLC(gl, gl->GenMailboxCHROMIUM(resource->mailbox_holder.mailbox.name));
GLC(gl,
- gl->ProduceTextureCHROMIUM(resource->target, resource->mailbox.name));
- source->mailbox.SetName(resource->mailbox);
+ gl->ProduceTextureCHROMIUM(resource->mailbox_holder.texture_target,
+ resource->mailbox_holder.mailbox.name));
+ source->mailbox = TextureMailbox(resource->mailbox_holder);
} else {
DCHECK(source->mailbox.IsTexture());
+ if (source->image_id && source->dirty_image) {
+ DCHECK(source->gl_id);
+ DCHECK(source->origin == Resource::Internal);
+ GLC(gl,
+ gl->BindTexture(resource->mailbox_holder.texture_target,
+ source->gl_id));
+ BindImageForSampling(source);
+ }
// This is either an external resource, or a compositor resource that we
// already exported. Make sure to forward the sync point that we were given.
- resource->mailbox = source->mailbox.name();
- resource->sync_point = source->mailbox.sync_point();
- source->mailbox.ResetSyncPoint();
+ resource->mailbox_holder.mailbox = source->mailbox.mailbox();
+ resource->mailbox_holder.texture_target = source->mailbox.target();
+ resource->mailbox_holder.sync_point = source->mailbox.sync_point();
+ source->mailbox.set_sync_point(0);
}
}
@@ -1297,7 +1685,6 @@ void ResourceProvider::DeleteAndReturnUnusedResourcesToChild(
Resource& resource = it->second;
DCHECK(!resource.locked_for_write);
- DCHECK(!resource.lock_for_read_count);
DCHECK_EQ(0u, child_info->in_use_resources.count(local_id));
DCHECK(child_info->parent_to_child_map.count(local_id));
@@ -1305,10 +1692,11 @@ void ResourceProvider::DeleteAndReturnUnusedResourcesToChild(
DCHECK(child_info->child_to_parent_map.count(child_id));
bool is_lost =
- resource.lost || (!resource.shared_bitmap && lost_output_surface_);
- if (resource.exported_count > 0) {
+ resource.lost || (resource.type == GLTexture && lost_output_surface_);
+ if (resource.exported_count > 0 || resource.lock_for_read_count > 0) {
if (style != ForShutdown) {
- // Defer this until we receive the resource back from the parent.
+ // Defer this until we receive the resource back from the parent or
+ // the read lock is released.
resource.marked_for_deletion = true;
continue;
}
@@ -1335,7 +1723,7 @@ void ResourceProvider::DeleteAndReturnUnusedResourcesToChild(
ReturnedResource returned;
returned.id = child_id;
returned.sync_point = resource.mailbox.sync_point();
- if (!returned.sync_point && !resource.shared_bitmap)
+ if (!returned.sync_point && resource.type == GLTexture)
need_sync_point = true;
returned.count = resource.imported_count;
returned.lost = is_lost;
@@ -1365,40 +1753,93 @@ void ResourceProvider::DeleteAndReturnUnusedResourcesToChild(
}
}
-void ResourceProvider::AcquirePixelBuffer(ResourceId id) {
+SkCanvas* ResourceProvider::MapDirectRasterBuffer(ResourceId id) {
+ // Resource needs to be locked for write since DirectRasterBuffer writes
+ // directly to it.
+ LockForWrite(id);
Resource* resource = GetResource(id);
- DCHECK(!resource->external);
- DCHECK_EQ(resource->exported_count, 0);
- DCHECK(!resource->image_id);
- DCHECK_NE(ETC1, resource->format);
-
- if (resource->type == GLTexture) {
- GLES2Interface* gl = ContextGL();
- DCHECK(gl);
- if (!resource->gl_pixel_buffer_id)
- resource->gl_pixel_buffer_id = buffer_id_allocator_->NextId();
- gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
- resource->gl_pixel_buffer_id);
- unsigned bytes_per_pixel = BitsPerPixel(resource->format) / 8;
- gl->BufferData(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
- resource->size.height() *
- RoundUp(bytes_per_pixel * resource->size.width(), 4u),
- NULL,
- GL_DYNAMIC_DRAW);
- gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
+ if (!resource->direct_raster_buffer.get()) {
+ resource->direct_raster_buffer.reset(
+ new DirectRasterBuffer(resource, this, use_distance_field_text_));
}
+ return resource->direct_raster_buffer->LockForWrite();
+}
- if (resource->pixels) {
- if (resource->pixel_buffer)
- return;
+void ResourceProvider::UnmapDirectRasterBuffer(ResourceId id) {
+ Resource* resource = GetResource(id);
+ DCHECK(resource->direct_raster_buffer.get());
+ resource->direct_raster_buffer->UnlockForWrite();
+ UnlockForWrite(id);
+}
- resource->pixel_buffer = new uint8_t[4 * resource->size.GetArea()];
- }
+SkCanvas* ResourceProvider::MapImageRasterBuffer(ResourceId id) {
+ Resource* resource = GetResource(id);
+ AcquireImage(resource);
+ if (!resource->image_raster_buffer.get())
+ resource->image_raster_buffer.reset(new ImageRasterBuffer(resource, this));
+ return resource->image_raster_buffer->LockForWrite();
+}
+
+bool ResourceProvider::UnmapImageRasterBuffer(ResourceId id) {
+ Resource* resource = GetResource(id);
+ resource->dirty_image = true;
+ return resource->image_raster_buffer->UnlockForWrite();
}
-void ResourceProvider::ReleasePixelBuffer(ResourceId id) {
+void ResourceProvider::AcquirePixelRasterBuffer(ResourceId id) {
Resource* resource = GetResource(id);
- DCHECK(!resource->external);
+ AcquirePixelBuffer(resource);
+ resource->pixel_raster_buffer.reset(new PixelRasterBuffer(resource, this));
+}
+
+void ResourceProvider::ReleasePixelRasterBuffer(ResourceId id) {
+ Resource* resource = GetResource(id);
+ resource->pixel_raster_buffer.reset();
+ ReleasePixelBuffer(resource);
+}
+
+SkCanvas* ResourceProvider::MapPixelRasterBuffer(ResourceId id) {
+ Resource* resource = GetResource(id);
+ DCHECK(resource->pixel_raster_buffer.get());
+ return resource->pixel_raster_buffer->LockForWrite();
+}
+
+bool ResourceProvider::UnmapPixelRasterBuffer(ResourceId id) {
+ Resource* resource = GetResource(id);
+ DCHECK(resource->pixel_raster_buffer.get());
+ return resource->pixel_raster_buffer->UnlockForWrite();
+}
+
+void ResourceProvider::AcquirePixelBuffer(Resource* resource) {
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
+ "ResourceProvider::AcquirePixelBuffer");
+
+ DCHECK(resource->origin == Resource::Internal);
+ DCHECK_EQ(resource->exported_count, 0);
+ DCHECK(!resource->image_id);
+ DCHECK_NE(ETC1, resource->format);
+
+ DCHECK_EQ(GLTexture, resource->type);
+ GLES2Interface* gl = ContextGL();
+ DCHECK(gl);
+ if (!resource->gl_pixel_buffer_id)
+ resource->gl_pixel_buffer_id = buffer_id_allocator_->NextId();
+ gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
+ resource->gl_pixel_buffer_id);
+ unsigned bytes_per_pixel = BitsPerPixel(resource->format) / 8;
+ gl->BufferData(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
+ resource->size.height() *
+ RoundUp(bytes_per_pixel * resource->size.width(), 4u),
+ NULL,
+ GL_DYNAMIC_DRAW);
+ gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
+}
+
+void ResourceProvider::ReleasePixelBuffer(Resource* resource) {
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
+ "ResourceProvider::ReleasePixelBuffer");
+
+ DCHECK(resource->origin == Resource::Internal);
DCHECK_EQ(resource->exported_count, 0);
DCHECK(!resource->image_id);
@@ -1411,70 +1852,61 @@ void ResourceProvider::ReleasePixelBuffer(ResourceId id) {
if (resource->pending_set_pixels) {
DCHECK(resource->set_pixels_completion_forced);
resource->pending_set_pixels = false;
- UnlockForWrite(id);
- }
-
- if (resource->type == GLTexture) {
- if (!resource->gl_pixel_buffer_id)
- return;
- GLES2Interface* gl = ContextGL();
- DCHECK(gl);
- gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
- resource->gl_pixel_buffer_id);
- gl->BufferData(
- GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0, NULL, GL_DYNAMIC_DRAW);
- gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
+ resource->locked_for_write = false;
}
- if (resource->pixels) {
- if (!resource->pixel_buffer)
- return;
- delete[] resource->pixel_buffer;
- resource->pixel_buffer = NULL;
- }
+ DCHECK_EQ(GLTexture, resource->type);
+ if (!resource->gl_pixel_buffer_id)
+ return;
+ GLES2Interface* gl = ContextGL();
+ DCHECK(gl);
+ gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
+ resource->gl_pixel_buffer_id);
+ gl->BufferData(
+ GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0, NULL, GL_DYNAMIC_DRAW);
+ gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
}
-uint8_t* ResourceProvider::MapPixelBuffer(ResourceId id) {
- Resource* resource = GetResource(id);
- DCHECK(!resource->external);
+uint8_t* ResourceProvider::MapPixelBuffer(const Resource* resource,
+ int* stride) {
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
+ "ResourceProvider::MapPixelBuffer");
+
+ DCHECK(resource->origin == Resource::Internal);
DCHECK_EQ(resource->exported_count, 0);
DCHECK(!resource->image_id);
- if (resource->type == GLTexture) {
- GLES2Interface* gl = ContextGL();
- DCHECK(gl);
- DCHECK(resource->gl_pixel_buffer_id);
- gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
- resource->gl_pixel_buffer_id);
- uint8_t* image = static_cast<uint8_t*>(gl->MapBufferCHROMIUM(
- GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, GL_WRITE_ONLY));
- gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
- // Buffer is required to be 4-byte aligned.
- CHECK(!(reinterpret_cast<intptr_t>(image) & 3));
- return image;
- }
-
- if (resource->pixels)
- return resource->pixel_buffer;
-
- return NULL;
-}
-
-void ResourceProvider::UnmapPixelBuffer(ResourceId id) {
- Resource* resource = GetResource(id);
- DCHECK(!resource->external);
+ *stride = 0;
+ DCHECK_EQ(GLTexture, resource->type);
+ GLES2Interface* gl = ContextGL();
+ DCHECK(gl);
+ DCHECK(resource->gl_pixel_buffer_id);
+ gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
+ resource->gl_pixel_buffer_id);
+ uint8_t* image = static_cast<uint8_t*>(gl->MapBufferCHROMIUM(
+ GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, GL_WRITE_ONLY));
+ gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
+ // Buffer is required to be 4-byte aligned.
+ CHECK(!(reinterpret_cast<intptr_t>(image) & 3));
+ return image;
+}
+
+void ResourceProvider::UnmapPixelBuffer(const Resource* resource) {
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
+ "ResourceProvider::UnmapPixelBuffer");
+
+ DCHECK(resource->origin == Resource::Internal);
DCHECK_EQ(resource->exported_count, 0);
DCHECK(!resource->image_id);
- if (resource->type == GLTexture) {
- GLES2Interface* gl = ContextGL();
- DCHECK(gl);
- DCHECK(resource->gl_pixel_buffer_id);
- gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
- resource->gl_pixel_buffer_id);
- gl->UnmapBufferCHROMIUM(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM);
- gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
- }
+ DCHECK_EQ(GLTexture, resource->type);
+ GLES2Interface* gl = ContextGL();
+ DCHECK(gl);
+ DCHECK(resource->gl_pixel_buffer_id);
+ gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
+ resource->gl_pixel_buffer_id);
+ gl->UnmapBufferCHROMIUM(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM);
+ gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
}
GLenum ResourceProvider::BindForSampling(
@@ -1498,23 +1930,21 @@ GLenum ResourceProvider::BindForSampling(
resource->filter = filter;
}
- if (resource->image_id && resource->dirty_image) {
- // Release image currently bound to texture.
- if (resource->bound_image_id)
- gl->ReleaseTexImage2DCHROMIUM(target, resource->bound_image_id);
- gl->BindTexImage2DCHROMIUM(target, resource->image_id);
- resource->bound_image_id = resource->image_id;
- resource->dirty_image = false;
- }
+ if (resource->image_id && resource->dirty_image)
+ BindImageForSampling(resource);
return target;
}
void ResourceProvider::BeginSetPixels(ResourceId id) {
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
+ "ResourceProvider::BeginSetPixels");
+
Resource* resource = GetResource(id);
DCHECK(!resource->pending_set_pixels);
LazyCreate(resource);
+ DCHECK(resource->origin == Resource::Internal);
DCHECK(resource->gl_id || resource->allocated);
DCHECK(ReadLockFenceHasPassed(resource));
DCHECK(!resource->image_id);
@@ -1523,58 +1953,51 @@ void ResourceProvider::BeginSetPixels(ResourceId id) {
resource->allocated = true;
LockForWrite(id);
- if (resource->gl_id) {
- GLES2Interface* gl = ContextGL();
- DCHECK(gl);
- DCHECK(resource->gl_pixel_buffer_id);
- DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D));
- gl->BindTexture(GL_TEXTURE_2D, resource->gl_id);
- gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
- resource->gl_pixel_buffer_id);
- if (!resource->gl_upload_query_id)
- gl->GenQueriesEXT(1, &resource->gl_upload_query_id);
- gl->BeginQueryEXT(GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM,
- resource->gl_upload_query_id);
- if (allocate) {
- gl->AsyncTexImage2DCHROMIUM(GL_TEXTURE_2D,
- 0, /* level */
- GLInternalFormat(resource->format),
- resource->size.width(),
- resource->size.height(),
- 0, /* border */
- GLDataFormat(resource->format),
- GLDataType(resource->format),
- NULL);
- } else {
- gl->AsyncTexSubImage2DCHROMIUM(GL_TEXTURE_2D,
- 0, /* level */
- 0, /* x */
- 0, /* y */
- resource->size.width(),
- resource->size.height(),
- GLDataFormat(resource->format),
- GLDataType(resource->format),
- NULL);
- }
- gl->EndQueryEXT(GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM);
- gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
- }
-
- if (resource->pixels) {
- DCHECK(!resource->mailbox.IsValid());
- DCHECK(resource->pixel_buffer);
- DCHECK_EQ(RGBA_8888, resource->format);
-
- std::swap(resource->pixels, resource->pixel_buffer);
- delete[] resource->pixel_buffer;
- resource->pixel_buffer = NULL;
+ DCHECK_EQ(GLTexture, resource->type);
+ DCHECK(resource->gl_id);
+ GLES2Interface* gl = ContextGL();
+ DCHECK(gl);
+ DCHECK(resource->gl_pixel_buffer_id);
+ DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D));
+ gl->BindTexture(GL_TEXTURE_2D, resource->gl_id);
+ gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
+ resource->gl_pixel_buffer_id);
+ if (!resource->gl_upload_query_id)
+ gl->GenQueriesEXT(1, &resource->gl_upload_query_id);
+ gl->BeginQueryEXT(GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM,
+ resource->gl_upload_query_id);
+ if (allocate) {
+ gl->AsyncTexImage2DCHROMIUM(GL_TEXTURE_2D,
+ 0, /* level */
+ GLInternalFormat(resource->format),
+ resource->size.width(),
+ resource->size.height(),
+ 0, /* border */
+ GLDataFormat(resource->format),
+ GLDataType(resource->format),
+ NULL);
+ } else {
+ gl->AsyncTexSubImage2DCHROMIUM(GL_TEXTURE_2D,
+ 0, /* level */
+ 0, /* x */
+ 0, /* y */
+ resource->size.width(),
+ resource->size.height(),
+ GLDataFormat(resource->format),
+ GLDataType(resource->format),
+ NULL);
}
+ gl->EndQueryEXT(GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM);
+ gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
resource->pending_set_pixels = true;
resource->set_pixels_completion_forced = false;
}
void ResourceProvider::ForceSetPixelsToComplete(ResourceId id) {
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
+ "ResourceProvider::ForceSetPixelsToComplete");
+
Resource* resource = GetResource(id);
DCHECK(resource->locked_for_write);
DCHECK(resource->pending_set_pixels);
@@ -1591,6 +2014,9 @@ void ResourceProvider::ForceSetPixelsToComplete(ResourceId id) {
}
bool ResourceProvider::DidSetPixelsComplete(ResourceId id) {
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
+ "ResourceProvider::DidSetPixelsComplete");
+
Resource* resource = GetResource(id);
DCHECK(resource->locked_for_write);
DCHECK(resource->pending_set_pixels);
@@ -1622,13 +2048,15 @@ GLenum ResourceProvider::TargetForTesting(ResourceId id) {
}
void ResourceProvider::LazyCreate(Resource* resource) {
- if (resource->type != GLTexture || resource->gl_id != 0)
+ if (resource->type != GLTexture || resource->origin != Resource::Internal)
return;
- // Early out for resources that don't require texture creation.
- if (resource->texture_pool == 0)
+ if (resource->gl_id)
return;
+ DCHECK(resource->texture_pool);
+ DCHECK(resource->origin == Resource::Internal);
+ DCHECK(!resource->mailbox.IsValid());
resource->gl_id = texture_id_allocator_->NextId();
GLES2Interface* gl = ContextGL();
@@ -1697,15 +2125,27 @@ void ResourceProvider::LazyAllocate(Resource* resource) {
}
}
+void ResourceProvider::BindImageForSampling(Resource* resource) {
+ GLES2Interface* gl = ContextGL();
+ DCHECK(resource->gl_id);
+ DCHECK(resource->image_id);
+
+ // Release image currently bound to texture.
+ if (resource->bound_image_id)
+ gl->ReleaseTexImage2DCHROMIUM(resource->target, resource->bound_image_id);
+ gl->BindTexImage2DCHROMIUM(resource->target, resource->image_id);
+ resource->bound_image_id = resource->image_id;
+ resource->dirty_image = false;
+}
+
void ResourceProvider::EnableReadLockFences(ResourceProvider::ResourceId id,
bool enable) {
Resource* resource = GetResource(id);
resource->enable_read_lock_fences = enable;
}
-void ResourceProvider::AcquireImage(ResourceId id) {
- Resource* resource = GetResource(id);
- DCHECK(!resource->external);
+void ResourceProvider::AcquireImage(Resource* resource) {
+ DCHECK(resource->origin == Resource::Internal);
DCHECK_EQ(resource->exported_count, 0);
if (resource->type != GLTexture)
@@ -1720,13 +2160,13 @@ void ResourceProvider::AcquireImage(ResourceId id) {
resource->image_id =
gl->CreateImageCHROMIUM(resource->size.width(),
resource->size.height(),
- TextureToStorageFormat(resource->format));
+ TextureToStorageFormat(resource->format),
+ GL_IMAGE_MAP_CHROMIUM);
DCHECK(resource->image_id);
}
-void ResourceProvider::ReleaseImage(ResourceId id) {
- Resource* resource = GetResource(id);
- DCHECK(!resource->external);
+void ResourceProvider::ReleaseImage(Resource* resource) {
+ DCHECK(resource->origin == Resource::Internal);
DCHECK_EQ(resource->exported_count, 0);
if (!resource->image_id)
@@ -1741,63 +2181,92 @@ void ResourceProvider::ReleaseImage(ResourceId id) {
resource->allocated = false;
}
-uint8_t* ResourceProvider::MapImage(ResourceId id) {
- Resource* resource = GetResource(id);
+uint8_t* ResourceProvider::MapImage(const Resource* resource, int* stride) {
DCHECK(ReadLockFenceHasPassed(resource));
- DCHECK(!resource->external);
+ DCHECK(resource->origin == Resource::Internal);
DCHECK_EQ(resource->exported_count, 0);
- if (resource->image_id) {
+ if (resource->type == GLTexture) {
+ DCHECK(resource->image_id);
GLES2Interface* gl = ContextGL();
DCHECK(gl);
- return static_cast<uint8_t*>(
- gl->MapImageCHROMIUM(resource->image_id, GL_READ_WRITE));
+ // MapImageCHROMIUM should be called prior to GetImageParameterivCHROMIUM.
+ uint8_t* pixels =
+ static_cast<uint8_t*>(gl->MapImageCHROMIUM(resource->image_id));
+ gl->GetImageParameterivCHROMIUM(
+ resource->image_id, GL_IMAGE_ROWBYTES_CHROMIUM, stride);
+ return pixels;
}
-
- if (resource->pixels)
- return resource->pixels;
-
- return NULL;
+ DCHECK_EQ(Bitmap, resource->type);
+ *stride = 0;
+ return resource->pixels;
}
-void ResourceProvider::UnmapImage(ResourceId id) {
- Resource* resource = GetResource(id);
- DCHECK(!resource->external);
+void ResourceProvider::UnmapImage(const Resource* resource) {
+ DCHECK(resource->origin == Resource::Internal);
DCHECK_EQ(resource->exported_count, 0);
if (resource->image_id) {
GLES2Interface* gl = ContextGL();
DCHECK(gl);
gl->UnmapImageCHROMIUM(resource->image_id);
- resource->dirty_image = true;
}
}
-int ResourceProvider::GetImageStride(ResourceId id) {
- Resource* resource = GetResource(id);
- DCHECK(!resource->external);
- DCHECK_EQ(resource->exported_count, 0);
+void ResourceProvider::CopyResource(ResourceId source_id, ResourceId dest_id) {
+ TRACE_EVENT0("cc", "ResourceProvider::CopyResource");
- int stride = 0;
+ Resource* source_resource = GetResource(source_id);
+ DCHECK(!source_resource->lock_for_read_count);
+ DCHECK(source_resource->origin == Resource::Internal);
+ DCHECK_EQ(source_resource->exported_count, 0);
+ DCHECK(source_resource->allocated);
+ LazyCreate(source_resource);
- if (resource->image_id) {
- GLES2Interface* gl = ContextGL();
- DCHECK(gl);
- gl->GetImageParameterivCHROMIUM(
- resource->image_id, GL_IMAGE_ROWBYTES_CHROMIUM, &stride);
- }
+ Resource* dest_resource = GetResource(dest_id);
+ DCHECK(!dest_resource->locked_for_write);
+ DCHECK(!dest_resource->lock_for_read_count);
+ DCHECK(dest_resource->origin == Resource::Internal);
+ DCHECK_EQ(dest_resource->exported_count, 0);
+ LazyCreate(dest_resource);
- return stride;
-}
+ DCHECK_EQ(source_resource->type, dest_resource->type);
+ DCHECK_EQ(source_resource->format, dest_resource->format);
+ DCHECK(source_resource->size == dest_resource->size);
-base::SharedMemory* ResourceProvider::GetSharedMemory(ResourceId id) {
- Resource* resource = GetResource(id);
- DCHECK(!resource->external);
- DCHECK_EQ(resource->exported_count, 0);
+ if (source_resource->type == GLTexture) {
+ GLES2Interface* gl = ContextGL();
+ DCHECK(gl);
+ if (source_resource->image_id && source_resource->dirty_image) {
+ gl->BindTexture(source_resource->target, source_resource->gl_id);
+ BindImageForSampling(source_resource);
+ }
+ DCHECK(use_sync_query_) << "CHROMIUM_sync_query extension missing";
+ if (!source_resource->gl_read_lock_query_id)
+ gl->GenQueriesEXT(1, &source_resource->gl_read_lock_query_id);
+ gl->BeginQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM,
+ source_resource->gl_read_lock_query_id);
+ DCHECK(!dest_resource->image_id);
+ dest_resource->allocated = true;
+ gl->CopyTextureCHROMIUM(dest_resource->target,
+ source_resource->gl_id,
+ dest_resource->gl_id,
+ 0,
+ GLInternalFormat(dest_resource->format),
+ GLDataType(dest_resource->format));
+ // End query and create a read lock fence that will prevent access to
+ // source resource until CopyTextureCHROMIUM command has completed.
+ gl->EndQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM);
+ source_resource->read_lock_fence = make_scoped_refptr(
+ new QueryFence(gl, source_resource->gl_read_lock_query_id));
+ } else {
+ DCHECK_EQ(Bitmap, source_resource->type);
+ DCHECK_EQ(RGBA_8888, source_resource->format);
+ LazyAllocate(dest_resource);
- if (!resource->shared_bitmap)
- return NULL;
- return resource->shared_bitmap->memory();
+ size_t bytes = SharedBitmap::CheckedSizeInBytes(source_resource->size);
+ memcpy(dest_resource->pixels, source_resource->pixels, bytes);
+ }
}
GLint ResourceProvider::GetActiveTextureUnit(GLES2Interface* gl) {
@@ -1811,4 +2280,9 @@ GLES2Interface* ResourceProvider::ContextGL() const {
return context_provider ? context_provider->ContextGL() : NULL;
}
+class GrContext* ResourceProvider::GrContext() const {
+ ContextProvider* context_provider = output_surface_->context_provider();
+ return context_provider ? context_provider->GrContext() : NULL;
+}
+
} // namespace cc
diff --git a/chromium/cc/resources/resource_provider.h b/chromium/cc/resources/resource_provider.h
index 6e5c61a2bfa..1d991e2b144 100644
--- a/chromium/cc/resources/resource_provider.h
+++ b/chromium/cc/resources/resource_provider.h
@@ -14,6 +14,7 @@
#include "base/basictypes.h"
#include "base/callback.h"
#include "base/containers/hash_tables.h"
+#include "base/memory/linked_ptr.h"
#include "base/memory/scoped_ptr.h"
#include "base/threading/thread_checker.h"
#include "cc/base/cc_export.h"
@@ -22,6 +23,7 @@
#include "cc/resources/release_callback.h"
#include "cc/resources/resource_format.h"
#include "cc/resources/return_callback.h"
+#include "cc/resources/shared_bitmap.h"
#include "cc/resources/single_release_callback.h"
#include "cc/resources/texture_mailbox.h"
#include "cc/resources/transferable_resource.h"
@@ -31,6 +33,8 @@
#include "third_party/skia/include/core/SkCanvas.h"
#include "ui/gfx/size.h"
+class GrContext;
+
namespace gpu {
namespace gles {
class GLES2Interface;
@@ -71,11 +75,12 @@ class CC_EXPORT ResourceProvider {
SharedBitmapManager* shared_bitmap_manager,
int highp_threshold_min,
bool use_rgba_4444_texture_format,
- size_t id_allocation_chunk_size);
+ size_t id_allocation_chunk_size,
+ bool use_distance_field_text);
virtual ~ResourceProvider();
void InitializeSoftware();
- bool InitializeGL();
+ void InitializeGL();
void DidLoseOutputSurface() { lost_output_surface_ = true; }
@@ -84,12 +89,14 @@ class CC_EXPORT ResourceProvider {
return use_rgba_4444_texture_format_ ? RGBA_4444 : best_texture_format_;
}
ResourceFormat best_texture_format() const { return best_texture_format_; }
+ bool use_sync_query() const { return use_sync_query_; }
size_t num_resources() const { return resources_.size(); }
// Checks whether a resource is in use by a consumer.
bool InUseByConsumer(ResourceId id);
bool IsLost(ResourceId id);
+ bool AllowOverlay(ResourceId id);
// Producer interface.
@@ -97,32 +104,31 @@ class CC_EXPORT ResourceProvider {
ResourceType GetResourceType(ResourceId id);
// Creates a resource of the default resource type.
- ResourceId CreateResource(gfx::Size size,
+ ResourceId CreateResource(const gfx::Size& size,
GLint wrap_mode,
TextureUsageHint hint,
ResourceFormat format);
// Creates a resource which is tagged as being managed for GPU memory
// accounting purposes.
- ResourceId CreateManagedResource(gfx::Size size,
+ ResourceId CreateManagedResource(const gfx::Size& size,
GLenum target,
GLint wrap_mode,
TextureUsageHint hint,
ResourceFormat format);
// You can also explicitly create a specific resource type.
- ResourceId CreateGLTexture(gfx::Size size,
+ ResourceId CreateGLTexture(const gfx::Size& size,
GLenum target,
GLenum texture_pool,
GLint wrap_mode,
TextureUsageHint hint,
ResourceFormat format);
- ResourceId CreateBitmap(gfx::Size size, GLint wrap_mode);
- // Wraps an external texture into a GL resource.
- ResourceId CreateResourceFromExternalTexture(
- unsigned texture_target,
- unsigned texture_id);
+ ResourceId CreateBitmap(const gfx::Size& size, GLint wrap_mode);
+ // Wraps an IOSurface into a GL resource.
+ ResourceId CreateResourceFromIOSurface(const gfx::Size& size,
+ unsigned io_surface_id);
// Wraps an external texture mailbox into a GL resource.
ResourceId CreateResourceFromTextureMailbox(
@@ -135,9 +141,9 @@ class CC_EXPORT ResourceProvider {
// the resource).
void SetPixels(ResourceId id,
const uint8_t* image,
- gfx::Rect image_rect,
- gfx::Rect source_rect,
- gfx::Vector2d dest_offset);
+ const gfx::Rect& image_rect,
+ const gfx::Rect& source_rect,
+ const gfx::Vector2d& dest_offset);
// Check upload status.
size_t NumBlockingUploads();
@@ -265,9 +271,14 @@ class CC_EXPORT ResourceProvider {
ResourceProvider::ResourceId resource_id);
~ScopedReadLockSoftware();
- const SkBitmap* sk_bitmap() const { return &sk_bitmap_; }
+ const SkBitmap* sk_bitmap() const {
+ DCHECK(valid());
+ return &sk_bitmap_;
+ }
GLint wrap_mode() const { return wrap_mode_; }
+ bool valid() const { return !!sk_bitmap_.getPixels(); }
+
private:
ResourceProvider* resource_provider_;
ResourceProvider::ResourceId resource_id_;
@@ -284,6 +295,7 @@ class CC_EXPORT ResourceProvider {
~ScopedWriteLockSoftware();
SkCanvas* sk_canvas() { return sk_canvas_.get(); }
+ bool valid() const { return !!sk_bitmap_.getPixels(); }
private:
ResourceProvider* resource_provider_;
@@ -307,35 +319,36 @@ class CC_EXPORT ResourceProvider {
DISALLOW_COPY_AND_ASSIGN(Fence);
};
- // Acquire pixel buffer for resource. The pixel buffer can be used to
- // set resource pixels without performing unnecessary copying.
- void AcquirePixelBuffer(ResourceId id);
- void ReleasePixelBuffer(ResourceId id);
-
- // Map/unmap the acquired pixel buffer.
- uint8_t* MapPixelBuffer(ResourceId id);
- void UnmapPixelBuffer(ResourceId id);
+ // Returns a canvas for direct rasterization.
+ // Call Unmap before the resource can be read or used for compositing.
+ // It is used for direct gpu rasterization.
+ SkCanvas* MapDirectRasterBuffer(ResourceId id);
+ void UnmapDirectRasterBuffer(ResourceId id);
+
+ // Returns a canvas backed by an image buffer. UnmapImageRasterBuffer
+ // returns true if canvas was written to while mapped.
+ // Rasterizing to the canvas writes the content into the image buffer,
+ // which is internally bound to the underlying resource when read.
+ // Call Unmap before the resource can be read or used for compositing.
+ // It is used by ImageRasterWorkerPool.
+ SkCanvas* MapImageRasterBuffer(ResourceId id);
+ bool UnmapImageRasterBuffer(ResourceId id);
+
+ // Returns a canvas backed by pixel buffer. UnmapPixelRasterBuffer
+ // returns true if canvas was written to while mapped.
+ // The pixel buffer needs to be uploaded to the underlying resource
+ // using BeginSetPixels before the resouce can be used for compositing.
+ // It is used by PixelRasterWorkerPool.
+ void AcquirePixelRasterBuffer(ResourceId id);
+ void ReleasePixelRasterBuffer(ResourceId id);
+ SkCanvas* MapPixelRasterBuffer(ResourceId id);
+ bool UnmapPixelRasterBuffer(ResourceId id);
// Asynchronously update pixels from acquired pixel buffer.
void BeginSetPixels(ResourceId id);
void ForceSetPixelsToComplete(ResourceId id);
bool DidSetPixelsComplete(ResourceId id);
- // Acquire and release an image. The image allows direct
- // manipulation of texture memory.
- void AcquireImage(ResourceId id);
- void ReleaseImage(ResourceId id);
-
- // Maps the acquired image so that its pixels could be modified.
- // Unmap is called when all pixels are set.
- uint8_t* MapImage(ResourceId id);
- void UnmapImage(ResourceId id);
-
- // Returns the stride for the image.
- int GetImageStride(ResourceId id);
-
- base::SharedMemory* GetSharedMemory(ResourceId id);
-
// For tests only! This prevents detecting uninitialized reads.
// Use SetPixels or LockForWrite to allocate implicitly.
void AllocateForTesting(ResourceId id);
@@ -348,10 +361,7 @@ class CC_EXPORT ResourceProvider {
// Sets the current read fence. If a resource is locked for read
// and has read fences enabled, the resource will not allow writes
// until this fence has passed.
- void SetReadLockFence(scoped_refptr<Fence> fence) {
- current_read_lock_fence_ = fence;
- }
- Fence* GetReadLockFence() { return current_read_lock_fence_.get(); }
+ void SetReadLockFence(Fence* fence) { current_read_lock_fence_ = fence; }
// Enable read lock fences for a specific resource.
void EnableReadLockFences(ResourceProvider::ResourceId id, bool enable);
@@ -359,14 +369,24 @@ class CC_EXPORT ResourceProvider {
// Indicates if we can currently lock this resource for write.
bool CanLockForWrite(ResourceId id);
+ // Copy pixels from source to destination.
+ void CopyResource(ResourceId source_id, ResourceId dest_id);
+
static GLint GetActiveTextureUnit(gpu::gles2::GLES2Interface* gl);
private:
+ class DirectRasterBuffer;
+ class ImageRasterBuffer;
+ class PixelRasterBuffer;
+
struct Resource {
+ enum Origin { Internal, External, Delegated };
+
Resource();
~Resource();
Resource(unsigned texture_id,
- gfx::Size size,
+ const gfx::Size& size,
+ Origin origin,
GLenum target,
GLenum filter,
GLenum texture_pool,
@@ -375,7 +395,13 @@ class CC_EXPORT ResourceProvider {
ResourceFormat format);
Resource(uint8_t* pixels,
SharedBitmap* bitmap,
- gfx::Size size,
+ const gfx::Size& size,
+ Origin origin,
+ GLenum filter,
+ GLint wrap_mode);
+ Resource(const SharedBitmapId& bitmap_id,
+ const gfx::Size& size,
+ Origin origin,
GLenum filter,
GLint wrap_mode);
@@ -385,39 +411,138 @@ class CC_EXPORT ResourceProvider {
unsigned gl_pixel_buffer_id;
// Query used to determine when asynchronous set pixels complete.
unsigned gl_upload_query_id;
+ // Query used to determine when read lock fence has passed.
+ unsigned gl_read_lock_query_id;
TextureMailbox mailbox;
ReleaseCallback release_callback;
uint8_t* pixels;
- uint8_t* pixel_buffer;
int lock_for_read_count;
int imported_count;
int exported_count;
- bool locked_for_write;
- bool external;
- bool marked_for_deletion;
- bool pending_set_pixels;
- bool set_pixels_completion_forced;
- bool allocated;
- bool enable_read_lock_fences;
+ bool dirty_image : 1;
+ bool locked_for_write : 1;
+ bool lost : 1;
+ bool marked_for_deletion : 1;
+ bool pending_set_pixels : 1;
+ bool set_pixels_completion_forced : 1;
+ bool allocated : 1;
+ bool enable_read_lock_fences : 1;
+ bool has_shared_bitmap_id : 1;
+ bool allow_overlay : 1;
scoped_refptr<Fence> read_lock_fence;
gfx::Size size;
+ Origin origin;
GLenum target;
// TODO(skyostil): Use a separate sampler object for filter state.
GLenum original_filter;
GLenum filter;
unsigned image_id;
unsigned bound_image_id;
- bool dirty_image;
GLenum texture_pool;
GLint wrap_mode;
- bool lost;
TextureUsageHint hint;
ResourceType type;
ResourceFormat format;
+ SharedBitmapId shared_bitmap_id;
SharedBitmap* shared_bitmap;
+ linked_ptr<DirectRasterBuffer> direct_raster_buffer;
+ linked_ptr<ImageRasterBuffer> image_raster_buffer;
+ linked_ptr<PixelRasterBuffer> pixel_raster_buffer;
};
typedef base::hash_map<ResourceId, Resource> ResourceMap;
+ class RasterBuffer {
+ public:
+ virtual ~RasterBuffer();
+
+ SkCanvas* LockForWrite();
+ // Returns true if canvas was written to while locked.
+ bool UnlockForWrite();
+
+ protected:
+ RasterBuffer(const Resource* resource, ResourceProvider* resource_provider);
+ const Resource* resource() const { return resource_; }
+ ResourceProvider* resource_provider() const { return resource_provider_; }
+
+ virtual SkCanvas* DoLockForWrite() = 0;
+ virtual bool DoUnlockForWrite() = 0;
+
+ private:
+ const Resource* resource_;
+ ResourceProvider* resource_provider_;
+ SkCanvas* locked_canvas_;
+ int canvas_save_count_;
+ };
+
+ class DirectRasterBuffer : public RasterBuffer {
+ public:
+ DirectRasterBuffer(const Resource* resource,
+ ResourceProvider* resource_provider,
+ bool use_distance_field_text);
+ virtual ~DirectRasterBuffer();
+
+ protected:
+ virtual SkCanvas* DoLockForWrite() OVERRIDE;
+ virtual bool DoUnlockForWrite() OVERRIDE;
+ skia::RefPtr<SkSurface> CreateSurface();
+
+ private:
+ skia::RefPtr<SkSurface> surface_;
+ uint32_t surface_generation_id_;
+ const bool use_distance_field_text_;
+
+ DISALLOW_COPY_AND_ASSIGN(DirectRasterBuffer);
+ };
+
+ class BitmapRasterBuffer : public RasterBuffer {
+ public:
+ virtual ~BitmapRasterBuffer();
+
+ protected:
+ BitmapRasterBuffer(const Resource* resource,
+ ResourceProvider* resource_provider);
+
+ virtual SkCanvas* DoLockForWrite() OVERRIDE;
+ virtual bool DoUnlockForWrite() OVERRIDE;
+
+ virtual uint8_t* MapBuffer(int* stride) = 0;
+ virtual void UnmapBuffer() = 0;
+
+ private:
+ uint8_t* mapped_buffer_;
+ SkBitmap raster_bitmap_;
+ uint32_t raster_bitmap_generation_id_;
+ skia::RefPtr<SkCanvas> raster_canvas_;
+ };
+
+ class ImageRasterBuffer : public BitmapRasterBuffer {
+ public:
+ ImageRasterBuffer(const Resource* resource,
+ ResourceProvider* resource_provider);
+ virtual ~ImageRasterBuffer();
+
+ protected:
+ virtual uint8_t* MapBuffer(int* stride) OVERRIDE;
+ virtual void UnmapBuffer() OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ImageRasterBuffer);
+ };
+
+ class PixelRasterBuffer : public BitmapRasterBuffer {
+ public:
+ PixelRasterBuffer(const Resource* resource,
+ ResourceProvider* resource_provider);
+ virtual ~PixelRasterBuffer();
+
+ protected:
+ virtual uint8_t* MapBuffer(int* stride) OVERRIDE;
+ virtual void UnmapBuffer() OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(PixelRasterBuffer);
+ };
+
static bool CompareResourceMapIteratorsByChildId(
const std::pair<ReturnedResource, ResourceMap::iterator>& a,
const std::pair<ReturnedResource, ResourceMap::iterator>& b);
@@ -434,7 +559,7 @@ class CC_EXPORT ResourceProvider {
};
typedef base::hash_map<int, Child> ChildMap;
- bool ReadLockFenceHasPassed(Resource* resource) {
+ bool ReadLockFenceHasPassed(const Resource* resource) {
return !resource->read_lock_fence.get() ||
resource->read_lock_fence->HasPassed();
}
@@ -443,7 +568,8 @@ class CC_EXPORT ResourceProvider {
SharedBitmapManager* shared_bitmap_manager,
int highp_threshold_min,
bool use_rgba_4444_texture_format,
- size_t id_allocation_chunk_size);
+ size_t id_allocation_chunk_size,
+ bool use_distance_field_text);
void CleanUpGLIfNeeded();
@@ -470,6 +596,26 @@ class CC_EXPORT ResourceProvider {
void LazyCreate(Resource* resource);
void LazyAllocate(Resource* resource);
+ // TODO(alokp): Move the implementation to PixelRasterBuffer.
+ // Acquire pixel buffer for resource. The pixel buffer can be used to
+ // set resource pixels without performing unnecessary copying.
+ void AcquirePixelBuffer(Resource* resource);
+ void ReleasePixelBuffer(Resource* resource);
+ // Map/unmap the acquired pixel buffer.
+ uint8_t* MapPixelBuffer(const Resource* resource, int* stride);
+ void UnmapPixelBuffer(const Resource* resource);
+
+ // TODO(alokp): Move the implementation to ImageRasterBuffer.
+ // Acquire and release an image. The image allows direct
+ // manipulation of texture memory.
+ void AcquireImage(Resource* resource);
+ void ReleaseImage(Resource* resource);
+ // Maps the acquired image so that its pixels could be modified.
+ // Unmap is called when all pixels are set.
+ uint8_t* MapImage(const Resource* resource, int* stride);
+ void UnmapImage(const Resource* resource);
+
+ void BindImageForSampling(Resource* resource);
// Binds the given GL resource to a texture target for sampling using the
// specified filter for both minification and magnification. Returns the
// texture target used. The resource must be locked for reading.
@@ -479,6 +625,7 @@ class CC_EXPORT ResourceProvider {
// Returns NULL if the output_surface_ does not have a ContextProvider.
gpu::gles2::GLES2Interface* ContextGL() const;
+ class GrContext* GrContext() const;
OutputSurface* output_surface_;
SharedBitmapManager* shared_bitmap_manager_;
@@ -506,6 +653,10 @@ class CC_EXPORT ResourceProvider {
scoped_ptr<IdAllocator> texture_id_allocator_;
scoped_ptr<IdAllocator> buffer_id_allocator_;
+ bool use_sync_query_;
+
+ bool use_distance_field_text_;
+
DISALLOW_COPY_AND_ASSIGN(ResourceProvider);
};
diff --git a/chromium/cc/resources/resource_provider_unittest.cc b/chromium/cc/resources/resource_provider_unittest.cc
index e40c9a7e6fe..4bf9ec0565e 100644
--- a/chromium/cc/resources/resource_provider_unittest.cc
+++ b/chromium/cc/resources/resource_provider_unittest.cc
@@ -6,6 +6,7 @@
#include <algorithm>
#include <map>
+#include <set>
#include "base/bind.h"
#include "base/containers/hash_tables.h"
@@ -18,6 +19,7 @@
#include "cc/resources/single_release_callback.h"
#include "cc/test/fake_output_surface.h"
#include "cc/test/fake_output_surface_client.h"
+#include "cc/test/test_shared_bitmap_manager.h"
#include "cc/test/test_texture.h"
#include "cc/test/test_web_graphics_context_3d.h"
#include "gpu/GLES2/gl2extchromium.h"
@@ -37,15 +39,15 @@ using testing::_;
namespace cc {
namespace {
-static void EmptyReleaseCallback(unsigned sync_point, bool lost_resource) {}
+static void EmptyReleaseCallback(uint32 sync_point, bool lost_resource) {}
static void SharedMemoryReleaseCallback(scoped_ptr<base::SharedMemory> memory,
- unsigned sync_point,
+ uint32 sync_point,
bool lost_resource) {}
-static void ReleaseTextureMailbox(unsigned* release_sync_point,
+static void ReleaseTextureMailbox(uint32* release_sync_point,
bool* release_lost_resource,
- unsigned sync_point,
+ uint32 sync_point,
bool lost_resource) {
*release_sync_point = sync_point;
*release_lost_resource = lost_resource;
@@ -54,9 +56,9 @@ static void ReleaseTextureMailbox(unsigned* release_sync_point,
static void ReleaseSharedMemoryCallback(
scoped_ptr<base::SharedMemory> shared_memory,
bool* release_called,
- unsigned* release_sync_point,
+ uint32* release_sync_point,
bool* lost_resource_result,
- unsigned sync_point,
+ uint32 sync_point,
bool lost_resource) {
*release_called = true;
*release_sync_point = sync_point;
@@ -64,7 +66,7 @@ static void ReleaseSharedMemoryCallback(
}
static scoped_ptr<base::SharedMemory> CreateAndFillSharedMemory(
- gfx::Size size,
+ const gfx::Size& size,
uint32_t value) {
scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory);
CHECK(shared_memory->CreateAndMapAnonymous(4 * size.GetArea()));
@@ -78,8 +80,8 @@ class TextureStateTrackingContext : public TestWebGraphicsContext3D {
public:
MOCK_METHOD2(bindTexture, void(GLenum target, GLuint texture));
MOCK_METHOD3(texParameteri, void(GLenum target, GLenum pname, GLint param));
- MOCK_METHOD1(waitSyncPoint, void(unsigned sync_point));
- MOCK_METHOD0(insertSyncPoint, unsigned(void));
+ MOCK_METHOD1(waitSyncPoint, void(GLuint sync_point));
+ MOCK_METHOD0(insertSyncPoint, GLuint(void));
MOCK_METHOD2(produceTextureCHROMIUM,
void(GLenum target, const GLbyte* mailbox));
MOCK_METHOD2(consumeTextureCHROMIUM,
@@ -102,16 +104,16 @@ class ContextSharedData {
return make_scoped_ptr(new ContextSharedData());
}
- unsigned InsertSyncPoint() { return next_sync_point_++; }
+ uint32 InsertSyncPoint() { return next_sync_point_++; }
void GenMailbox(GLbyte* mailbox) {
- memset(mailbox, 0, sizeof(GLbyte[64]));
+ memset(mailbox, 0, GL_MAILBOX_SIZE_CHROMIUM);
memcpy(mailbox, &next_mailbox_, sizeof(next_mailbox_));
++next_mailbox_;
}
void ProduceTexture(const GLbyte* mailbox_name,
- unsigned sync_point,
+ uint32 sync_point,
scoped_refptr<TestTexture> texture) {
unsigned mailbox = 0;
memcpy(&mailbox, mailbox_name, sizeof(mailbox));
@@ -122,7 +124,7 @@ class ContextSharedData {
}
scoped_refptr<TestTexture> ConsumeTexture(const GLbyte* mailbox_name,
- unsigned sync_point) {
+ uint32 sync_point) {
unsigned mailbox = 0;
memcpy(&mailbox, mailbox_name, sizeof(mailbox));
DCHECK(mailbox && mailbox < next_mailbox_);
@@ -140,11 +142,11 @@ class ContextSharedData {
private:
ContextSharedData() : next_sync_point_(1), next_mailbox_(1) {}
- unsigned next_sync_point_;
+ uint32 next_sync_point_;
unsigned next_mailbox_;
typedef base::hash_map<unsigned, scoped_refptr<TestTexture> > TextureMap;
TextureMap textures_;
- base::hash_map<unsigned, unsigned> sync_point_for_mailbox_;
+ base::hash_map<unsigned, uint32> sync_point_for_mailbox_;
};
class ResourceProviderContext : public TestWebGraphicsContext3D {
@@ -154,8 +156,8 @@ class ResourceProviderContext : public TestWebGraphicsContext3D {
return make_scoped_ptr(new ResourceProviderContext(shared_data));
}
- virtual unsigned insertSyncPoint() OVERRIDE {
- unsigned sync_point = shared_data_->InsertSyncPoint();
+ virtual GLuint insertSyncPoint() OVERRIDE {
+ uint32 sync_point = shared_data_->InsertSyncPoint();
// Commit the produceTextureCHROMIUM calls at this point, so that
// they're associated with the sync point.
for (PendingProduceTextureList::iterator it =
@@ -169,10 +171,12 @@ class ResourceProviderContext : public TestWebGraphicsContext3D {
return sync_point;
}
- virtual void waitSyncPoint(unsigned sync_point) OVERRIDE {
+ virtual void waitSyncPoint(GLuint sync_point) OVERRIDE {
last_waited_sync_point_ = std::max(sync_point, last_waited_sync_point_);
}
+ unsigned last_waited_sync_point() const { return last_waited_sync_point_; }
+
virtual void texStorage2DEXT(GLenum target,
GLint levels,
GLuint internalformat,
@@ -262,7 +266,9 @@ class ResourceProviderContext : public TestWebGraphicsContext3D {
namespace_->textures.Replace(BoundTextureId(target), texture);
}
- void GetPixels(gfx::Size size, ResourceFormat format, uint8_t* pixels) {
+ void GetPixels(const gfx::Size& size,
+ ResourceFormat format,
+ uint8_t* pixels) {
CheckTextureIsBound(GL_TEXTURE_2D);
base::AutoLock lock_for_texture_access(namespace_->lock);
scoped_refptr<TestTexture> texture = BoundTexture(GL_TEXTURE_2D);
@@ -277,7 +283,7 @@ class ResourceProviderContext : public TestWebGraphicsContext3D {
last_waited_sync_point_(0) {}
private:
- void AllocateTexture(gfx::Size size, GLenum format) {
+ void AllocateTexture(const gfx::Size& size, GLenum format) {
CheckTextureIsBound(GL_TEXTURE_2D);
ResourceFormat texture_format = RGBA_8888;
switch (format) {
@@ -318,68 +324,19 @@ class ResourceProviderContext : public TestWebGraphicsContext3D {
}
struct PendingProduceTexture {
- GLbyte mailbox[64];
+ GLbyte mailbox[GL_MAILBOX_SIZE_CHROMIUM];
scoped_refptr<TestTexture> texture;
};
typedef ScopedPtrDeque<PendingProduceTexture> PendingProduceTextureList;
ContextSharedData* shared_data_;
- unsigned last_waited_sync_point_;
+ GLuint last_waited_sync_point_;
PendingProduceTextureList pending_produce_textures_;
};
-void FreeSharedBitmap(SharedBitmap* shared_bitmap) {
- delete shared_bitmap->memory();
-}
-
-void IgnoreSharedBitmap(SharedBitmap* shared_bitmap) {}
-
-class TestSharedBitmapManager : public SharedBitmapManager {
- public:
- TestSharedBitmapManager() : count_(0) {}
- virtual ~TestSharedBitmapManager() {}
-
- virtual scoped_ptr<SharedBitmap> AllocateSharedBitmap(gfx::Size size)
- OVERRIDE {
- scoped_ptr<base::SharedMemory> memory(new base::SharedMemory);
- memory->CreateAndMapAnonymous(size.GetArea() * 4);
- int8 name[64] = { 0 };
- name[0] = count_++;
- SharedBitmapId id;
- id.SetName(name);
- bitmap_map_[id] = memory.get();
- return scoped_ptr<SharedBitmap>(
- new SharedBitmap(memory.release(), id, base::Bind(&FreeSharedBitmap)));
- }
-
- virtual scoped_ptr<SharedBitmap> GetSharedBitmapFromId(
- gfx::Size,
- const SharedBitmapId& id) OVERRIDE {
- if (bitmap_map_.find(id) == bitmap_map_.end())
- return scoped_ptr<SharedBitmap>();
- return scoped_ptr<SharedBitmap>(
- new SharedBitmap(bitmap_map_[id], id, base::Bind(&IgnoreSharedBitmap)));
- }
-
- virtual scoped_ptr<SharedBitmap> GetBitmapForSharedMemory(
- base::SharedMemory* memory) OVERRIDE {
- int8 name[64] = { 0 };
- name[0] = count_++;
- SharedBitmapId id;
- id.SetName(name);
- bitmap_map_[id] = memory;
- return scoped_ptr<SharedBitmap>(
- new SharedBitmap(memory, id, base::Bind(&IgnoreSharedBitmap)));
- }
-
- private:
- int count_;
- std::map<SharedBitmapId, base::SharedMemory*> bitmap_map_;
-};
-
void GetResourcePixels(ResourceProvider* resource_provider,
ResourceProviderContext* context,
ResourceProvider::ResourceId id,
- gfx::Size size,
+ const gfx::Size& size,
ResourceFormat format,
uint8_t* pixels) {
switch (resource_provider->default_resource_type()) {
@@ -446,13 +403,15 @@ class ResourceProviderTest
shared_bitmap_manager_.reset(new TestSharedBitmapManager());
resource_provider_ = ResourceProvider::Create(
- output_surface_.get(), shared_bitmap_manager_.get(), 0, false, 1);
+ output_surface_.get(), shared_bitmap_manager_.get(), 0, false, 1,
+ false);
child_resource_provider_ = ResourceProvider::Create(
child_output_surface_.get(),
shared_bitmap_manager_.get(),
0,
false,
- 1);
+ 1,
+ false);
}
static void CollectResources(ReturnedResourceArray* array,
@@ -473,10 +432,10 @@ class ResourceProviderTest
ResourceProviderContext* context() { return context3d_; }
- ResourceProvider::ResourceId CreateChildMailbox(unsigned* release_sync_point,
+ ResourceProvider::ResourceId CreateChildMailbox(uint32* release_sync_point,
bool* lost_resource,
bool* release_called,
- unsigned* sync_point) {
+ uint32* sync_point) {
if (GetParam() == ResourceProvider::GLTexture) {
unsigned texture = child_context_->createTexture();
gpu::Mailbox gpu_mailbox;
@@ -494,7 +453,8 @@ class ResourceProviderTest
release_sync_point,
lost_resource));
return child_resource_provider_->CreateResourceFromTextureMailbox(
- TextureMailbox(gpu_mailbox, *sync_point), callback.Pass());
+ TextureMailbox(gpu_mailbox, GL_TEXTURE_2D, *sync_point),
+ callback.Pass());
} else {
gfx::Size size(64, 64);
scoped_ptr<base::SharedMemory> shared_memory(
@@ -647,6 +607,11 @@ TEST_P(ResourceProviderTest, TransferGLResources) {
uint8_t data2[4] = { 5, 5, 5, 5 };
child_resource_provider_->SetPixels(id2, data2, rect, rect, gfx::Vector2d());
+ ResourceProvider::ResourceId id3 = child_resource_provider_->CreateResource(
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
+ child_resource_provider_->MapImageRasterBuffer(id3);
+ child_resource_provider_->UnmapImageRasterBuffer(id3);
+
GLuint external_texture_id = child_context_->createExternalTexture();
child_context_->bindTexture(GL_TEXTURE_EXTERNAL_OES, external_texture_id);
@@ -654,8 +619,8 @@ TEST_P(ResourceProviderTest, TransferGLResources) {
child_context_->genMailboxCHROMIUM(external_mailbox.name);
child_context_->produceTextureCHROMIUM(GL_TEXTURE_EXTERNAL_OES,
external_mailbox.name);
- const unsigned external_sync_point = child_context_->insertSyncPoint();
- ResourceProvider::ResourceId id3 =
+ const GLuint external_sync_point = child_context_->insertSyncPoint();
+ ResourceProvider::ResourceId id4 =
child_resource_provider_->CreateResourceFromTextureMailbox(
TextureMailbox(
external_mailbox, GL_TEXTURE_EXTERNAL_OES, external_sync_point),
@@ -670,36 +635,59 @@ TEST_P(ResourceProviderTest, TransferGLResources) {
resource_ids_to_transfer.push_back(id1);
resource_ids_to_transfer.push_back(id2);
resource_ids_to_transfer.push_back(id3);
+ resource_ids_to_transfer.push_back(id4);
TransferableResourceArray list;
child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
&list);
- ASSERT_EQ(3u, list.size());
- EXPECT_NE(0u, list[0].sync_point);
- EXPECT_NE(0u, list[1].sync_point);
- EXPECT_EQ(external_sync_point, list[2].sync_point);
- EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D), list[0].target);
- EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D), list[1].target);
- EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_EXTERNAL_OES), list[2].target);
+ ASSERT_EQ(4u, list.size());
+ EXPECT_NE(0u, list[0].mailbox_holder.sync_point);
+ EXPECT_NE(0u, list[1].mailbox_holder.sync_point);
+ EXPECT_EQ(list[0].mailbox_holder.sync_point,
+ list[1].mailbox_holder.sync_point);
+ EXPECT_NE(0u, list[2].mailbox_holder.sync_point);
+ EXPECT_EQ(list[0].mailbox_holder.sync_point,
+ list[2].mailbox_holder.sync_point);
+ EXPECT_EQ(external_sync_point, list[3].mailbox_holder.sync_point);
+ EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D),
+ list[0].mailbox_holder.texture_target);
+ EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D),
+ list[1].mailbox_holder.texture_target);
+ EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D),
+ list[2].mailbox_holder.texture_target);
+ EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_EXTERNAL_OES),
+ list[3].mailbox_holder.texture_target);
EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id2));
EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id3));
+ EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id4));
resource_provider_->ReceiveFromChild(child_id, list);
+ EXPECT_NE(list[0].mailbox_holder.sync_point,
+ context3d_->last_waited_sync_point());
+ {
+ ResourceProvider::ScopedReadLockGL lock(resource_provider_.get(),
+ list[0].id);
+ }
+ EXPECT_EQ(list[0].mailbox_holder.sync_point,
+ context3d_->last_waited_sync_point());
resource_provider_->DeclareUsedResourcesFromChild(child_id,
resource_ids_to_transfer);
}
- EXPECT_EQ(3u, resource_provider_->num_resources());
+ EXPECT_EQ(4u, resource_provider_->num_resources());
ResourceProvider::ResourceIdMap resource_map =
resource_provider_->GetChildToParentMap(child_id);
ResourceProvider::ResourceId mapped_id1 = resource_map[id1];
ResourceProvider::ResourceId mapped_id2 = resource_map[id2];
ResourceProvider::ResourceId mapped_id3 = resource_map[id3];
+ ResourceProvider::ResourceId mapped_id4 = resource_map[id4];
EXPECT_NE(0u, mapped_id1);
EXPECT_NE(0u, mapped_id2);
EXPECT_NE(0u, mapped_id3);
+ EXPECT_NE(0u, mapped_id4);
EXPECT_FALSE(resource_provider_->InUseByConsumer(id1));
EXPECT_FALSE(resource_provider_->InUseByConsumer(id2));
EXPECT_FALSE(resource_provider_->InUseByConsumer(id3));
+ EXPECT_FALSE(resource_provider_->InUseByConsumer(id4));
uint8_t result[4] = { 0 };
GetResourcePixels(
@@ -715,18 +703,29 @@ TEST_P(ResourceProviderTest, TransferGLResources) {
// parent works.
ResourceProvider::ResourceIdArray resource_ids_to_transfer;
resource_ids_to_transfer.push_back(id1);
+ resource_ids_to_transfer.push_back(id2);
+ resource_ids_to_transfer.push_back(id3);
TransferableResourceArray list;
child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
&list);
- EXPECT_EQ(1u, list.size());
+ EXPECT_EQ(3u, list.size());
EXPECT_EQ(id1, list[0].id);
- EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D), list[0].target);
+ EXPECT_EQ(id2, list[1].id);
+ EXPECT_EQ(id3, list[2].id);
+ EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D),
+ list[0].mailbox_holder.texture_target);
+ EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D),
+ list[1].mailbox_holder.texture_target);
+ EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D),
+ list[2].mailbox_holder.texture_target);
ReturnedResourceArray returned;
TransferableResource::ReturnResources(list, &returned);
child_resource_provider_->ReceiveReturnsFromParent(returned);
- // id1 was exported twice, we returned it only once, it should still be
- // in-use.
+ // ids were exported twice, we returned them only once, they should still
+ // be in-use.
EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
+ EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id2));
+ EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id3));
}
{
EXPECT_EQ(0u, returned_to_child.size());
@@ -736,19 +735,22 @@ TEST_P(ResourceProviderTest, TransferGLResources) {
ResourceProvider::ResourceIdArray no_resources;
resource_provider_->DeclareUsedResourcesFromChild(child_id, no_resources);
- ASSERT_EQ(3u, returned_to_child.size());
+ ASSERT_EQ(4u, returned_to_child.size());
EXPECT_NE(0u, returned_to_child[0].sync_point);
EXPECT_NE(0u, returned_to_child[1].sync_point);
EXPECT_NE(0u, returned_to_child[2].sync_point);
+ EXPECT_NE(0u, returned_to_child[3].sync_point);
EXPECT_FALSE(returned_to_child[0].lost);
EXPECT_FALSE(returned_to_child[1].lost);
EXPECT_FALSE(returned_to_child[2].lost);
+ EXPECT_FALSE(returned_to_child[3].lost);
child_resource_provider_->ReceiveReturnsFromParent(returned_to_child);
returned_to_child.clear();
}
EXPECT_FALSE(child_resource_provider_->InUseByConsumer(id1));
EXPECT_FALSE(child_resource_provider_->InUseByConsumer(id2));
EXPECT_FALSE(child_resource_provider_->InUseByConsumer(id3));
+ EXPECT_FALSE(child_resource_provider_->InUseByConsumer(id4));
{
ResourceProvider::ScopedReadLockGL lock(child_resource_provider_.get(),
@@ -767,27 +769,42 @@ TEST_P(ResourceProviderTest, TransferGLResources) {
EXPECT_EQ(0, memcmp(data2, result, pixel_size));
}
{
+ ResourceProvider::ScopedReadLockGL lock(child_resource_provider_.get(),
+ id3);
+ ASSERT_NE(0U, lock.texture_id());
+ child_context_->bindTexture(GL_TEXTURE_2D, lock.texture_id());
+ }
+ {
// Transfer resources to the parent again.
ResourceProvider::ResourceIdArray resource_ids_to_transfer;
resource_ids_to_transfer.push_back(id1);
resource_ids_to_transfer.push_back(id2);
resource_ids_to_transfer.push_back(id3);
+ resource_ids_to_transfer.push_back(id4);
TransferableResourceArray list;
child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
&list);
- ASSERT_EQ(3u, list.size());
+ ASSERT_EQ(4u, list.size());
EXPECT_EQ(id1, list[0].id);
EXPECT_EQ(id2, list[1].id);
EXPECT_EQ(id3, list[2].id);
- EXPECT_NE(0u, list[0].sync_point);
- EXPECT_NE(0u, list[1].sync_point);
- EXPECT_NE(0u, list[2].sync_point);
- EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D), list[0].target);
- EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D), list[1].target);
- EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_EXTERNAL_OES), list[2].target);
+ EXPECT_EQ(id4, list[3].id);
+ EXPECT_NE(0u, list[0].mailbox_holder.sync_point);
+ EXPECT_NE(0u, list[1].mailbox_holder.sync_point);
+ EXPECT_NE(0u, list[2].mailbox_holder.sync_point);
+ EXPECT_NE(0u, list[3].mailbox_holder.sync_point);
+ EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D),
+ list[0].mailbox_holder.texture_target);
+ EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D),
+ list[1].mailbox_holder.texture_target);
+ EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D),
+ list[2].mailbox_holder.texture_target);
+ EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_EXTERNAL_OES),
+ list[3].mailbox_holder.texture_target);
EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id2));
EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id3));
+ EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id4));
resource_provider_->ReceiveFromChild(child_id, list);
resource_provider_->DeclareUsedResourcesFromChild(child_id,
resource_ids_to_transfer);
@@ -795,17 +812,69 @@ TEST_P(ResourceProviderTest, TransferGLResources) {
EXPECT_EQ(0u, returned_to_child.size());
- EXPECT_EQ(3u, resource_provider_->num_resources());
+ EXPECT_EQ(4u, resource_provider_->num_resources());
resource_provider_->DestroyChild(child_id);
EXPECT_EQ(0u, resource_provider_->num_resources());
- ASSERT_EQ(3u, returned_to_child.size());
+ ASSERT_EQ(4u, returned_to_child.size());
EXPECT_NE(0u, returned_to_child[0].sync_point);
EXPECT_NE(0u, returned_to_child[1].sync_point);
EXPECT_NE(0u, returned_to_child[2].sync_point);
+ EXPECT_NE(0u, returned_to_child[3].sync_point);
EXPECT_FALSE(returned_to_child[0].lost);
EXPECT_FALSE(returned_to_child[1].lost);
EXPECT_FALSE(returned_to_child[2].lost);
+ EXPECT_FALSE(returned_to_child[3].lost);
+}
+
+TEST_P(ResourceProviderTest, ReadLockCountStopsReturnToChildOrDelete) {
+ if (GetParam() != ResourceProvider::GLTexture)
+ return;
+ gfx::Size size(1, 1);
+ ResourceFormat format = RGBA_8888;
+
+ ResourceProvider::ResourceId id1 = child_resource_provider_->CreateResource(
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
+ uint8_t data1[4] = {1, 2, 3, 4};
+ gfx::Rect rect(size);
+ child_resource_provider_->SetPixels(id1, data1, rect, rect, gfx::Vector2d());
+
+ ReturnedResourceArray returned_to_child;
+ int child_id =
+ resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
+ {
+ // Transfer some resources to the parent.
+ ResourceProvider::ResourceIdArray resource_ids_to_transfer;
+ resource_ids_to_transfer.push_back(id1);
+ TransferableResourceArray list;
+ child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
+ &list);
+ ASSERT_EQ(1u, list.size());
+ EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
+
+ resource_provider_->ReceiveFromChild(child_id, list);
+
+ ResourceProvider::ScopedReadLockGL lock(resource_provider_.get(),
+ list[0].id);
+
+ resource_provider_->DeclareUsedResourcesFromChild(
+ child_id, ResourceProvider::ResourceIdArray());
+ EXPECT_EQ(0u, returned_to_child.size());
+ }
+
+ EXPECT_EQ(1u, returned_to_child.size());
+ child_resource_provider_->ReceiveReturnsFromParent(returned_to_child);
+
+ {
+ ResourceProvider::ScopedReadLockGL lock(child_resource_provider_.get(),
+ id1);
+ child_resource_provider_->DeleteResource(id1);
+ EXPECT_EQ(1u, child_resource_provider_->num_resources());
+ EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
+ }
+
+ EXPECT_EQ(0u, child_resource_provider_->num_resources());
+ resource_provider_->DestroyChild(child_id);
}
TEST_P(ResourceProviderTest, TransferSoftwareResources) {
@@ -828,10 +897,18 @@ TEST_P(ResourceProviderTest, TransferSoftwareResources) {
uint8_t data2[4] = { 5, 5, 5, 5 };
child_resource_provider_->SetPixels(id2, data2, rect, rect, gfx::Vector2d());
+ ResourceProvider::ResourceId id3 = child_resource_provider_->CreateResource(
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
+ uint8_t data3[4] = { 6, 7, 8, 9 };
+ SkImageInfo info = SkImageInfo::MakeN32Premul(size.width(), size.height());
+ SkCanvas* raster_canvas = child_resource_provider_->MapImageRasterBuffer(id3);
+ raster_canvas->writePixels(info, data3, info.minRowBytes(), 0, 0);
+ child_resource_provider_->UnmapImageRasterBuffer(id3);
+
scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory());
shared_memory->CreateAndMapAnonymous(1);
base::SharedMemory* shared_memory_ptr = shared_memory.get();
- ResourceProvider::ResourceId id3 =
+ ResourceProvider::ResourceId id4 =
child_resource_provider_->CreateResourceFromTextureMailbox(
TextureMailbox(shared_memory_ptr, gfx::Size(1, 1)),
SingleReleaseCallback::Create(base::Bind(
@@ -846,33 +923,39 @@ TEST_P(ResourceProviderTest, TransferSoftwareResources) {
resource_ids_to_transfer.push_back(id1);
resource_ids_to_transfer.push_back(id2);
resource_ids_to_transfer.push_back(id3);
+ resource_ids_to_transfer.push_back(id4);
TransferableResourceArray list;
child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
&list);
- ASSERT_EQ(3u, list.size());
- EXPECT_EQ(0u, list[0].sync_point);
- EXPECT_EQ(0u, list[1].sync_point);
- EXPECT_EQ(0u, list[2].sync_point);
+ ASSERT_EQ(4u, list.size());
+ EXPECT_EQ(0u, list[0].mailbox_holder.sync_point);
+ EXPECT_EQ(0u, list[1].mailbox_holder.sync_point);
+ EXPECT_EQ(0u, list[2].mailbox_holder.sync_point);
+ EXPECT_EQ(0u, list[3].mailbox_holder.sync_point);
EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id2));
EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id3));
+ EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id4));
resource_provider_->ReceiveFromChild(child_id, list);
resource_provider_->DeclareUsedResourcesFromChild(child_id,
resource_ids_to_transfer);
}
- EXPECT_EQ(3u, resource_provider_->num_resources());
+ EXPECT_EQ(4u, resource_provider_->num_resources());
ResourceProvider::ResourceIdMap resource_map =
resource_provider_->GetChildToParentMap(child_id);
ResourceProvider::ResourceId mapped_id1 = resource_map[id1];
ResourceProvider::ResourceId mapped_id2 = resource_map[id2];
ResourceProvider::ResourceId mapped_id3 = resource_map[id3];
+ ResourceProvider::ResourceId mapped_id4 = resource_map[id4];
EXPECT_NE(0u, mapped_id1);
EXPECT_NE(0u, mapped_id2);
EXPECT_NE(0u, mapped_id3);
+ EXPECT_NE(0u, mapped_id4);
EXPECT_FALSE(resource_provider_->InUseByConsumer(id1));
EXPECT_FALSE(resource_provider_->InUseByConsumer(id2));
EXPECT_FALSE(resource_provider_->InUseByConsumer(id3));
+ EXPECT_FALSE(resource_provider_->InUseByConsumer(id4));
uint8_t result[4] = { 0 };
GetResourcePixels(
@@ -883,22 +966,32 @@ TEST_P(ResourceProviderTest, TransferSoftwareResources) {
resource_provider_.get(), context(), mapped_id2, size, format, result);
EXPECT_EQ(0, memcmp(data2, result, pixel_size));
+ GetResourcePixels(
+ resource_provider_.get(), context(), mapped_id3, size, format, result);
+ EXPECT_EQ(0, memcmp(data3, result, pixel_size));
+
{
// Check that transfering again the same resource from the child to the
// parent works.
ResourceProvider::ResourceIdArray resource_ids_to_transfer;
resource_ids_to_transfer.push_back(id1);
+ resource_ids_to_transfer.push_back(id2);
+ resource_ids_to_transfer.push_back(id3);
TransferableResourceArray list;
child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
&list);
- EXPECT_EQ(1u, list.size());
+ EXPECT_EQ(3u, list.size());
EXPECT_EQ(id1, list[0].id);
+ EXPECT_EQ(id2, list[1].id);
+ EXPECT_EQ(id3, list[2].id);
ReturnedResourceArray returned;
TransferableResource::ReturnResources(list, &returned);
child_resource_provider_->ReceiveReturnsFromParent(returned);
- // id1 was exported twice, we returned it only once, it should still be
- // in-use.
+ // ids were exported twice, we returned them only once, they should still
+ // be in-use.
EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
+ EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id2));
+ EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id3));
}
{
EXPECT_EQ(0u, returned_to_child.size());
@@ -908,22 +1001,31 @@ TEST_P(ResourceProviderTest, TransferSoftwareResources) {
ResourceProvider::ResourceIdArray no_resources;
resource_provider_->DeclareUsedResourcesFromChild(child_id, no_resources);
- ASSERT_EQ(3u, returned_to_child.size());
+ ASSERT_EQ(4u, returned_to_child.size());
EXPECT_EQ(0u, returned_to_child[0].sync_point);
EXPECT_EQ(0u, returned_to_child[1].sync_point);
EXPECT_EQ(0u, returned_to_child[2].sync_point);
- EXPECT_EQ(id1, returned_to_child[0].id);
- EXPECT_EQ(id2, returned_to_child[1].id);
- EXPECT_EQ(id3, returned_to_child[2].id);
+ EXPECT_EQ(0u, returned_to_child[3].sync_point);
+ std::set<ResourceProvider::ResourceId> expected_ids;
+ expected_ids.insert(id1);
+ expected_ids.insert(id2);
+ expected_ids.insert(id3);
+ expected_ids.insert(id4);
+ std::set<ResourceProvider::ResourceId> returned_ids;
+ for (unsigned i = 0; i < 4; i++)
+ returned_ids.insert(returned_to_child[i].id);
+ EXPECT_EQ(expected_ids, returned_ids);
EXPECT_FALSE(returned_to_child[0].lost);
EXPECT_FALSE(returned_to_child[1].lost);
EXPECT_FALSE(returned_to_child[2].lost);
+ EXPECT_FALSE(returned_to_child[3].lost);
child_resource_provider_->ReceiveReturnsFromParent(returned_to_child);
returned_to_child.clear();
}
EXPECT_FALSE(child_resource_provider_->InUseByConsumer(id1));
EXPECT_FALSE(child_resource_provider_->InUseByConsumer(id2));
EXPECT_FALSE(child_resource_provider_->InUseByConsumer(id3));
+ EXPECT_FALSE(child_resource_provider_->InUseByConsumer(id4));
{
ResourceProvider::ScopedReadLockSoftware lock(
@@ -942,21 +1044,32 @@ TEST_P(ResourceProviderTest, TransferSoftwareResources) {
EXPECT_EQ(0, memcmp(data2, sk_bitmap->getPixels(), pixel_size));
}
{
+ ResourceProvider::ScopedReadLockSoftware lock(
+ child_resource_provider_.get(), id3);
+ const SkBitmap* sk_bitmap = lock.sk_bitmap();
+ EXPECT_EQ(sk_bitmap->width(), size.width());
+ EXPECT_EQ(sk_bitmap->height(), size.height());
+ EXPECT_EQ(0, memcmp(data3, sk_bitmap->getPixels(), pixel_size));
+ }
+ {
// Transfer resources to the parent again.
ResourceProvider::ResourceIdArray resource_ids_to_transfer;
resource_ids_to_transfer.push_back(id1);
resource_ids_to_transfer.push_back(id2);
resource_ids_to_transfer.push_back(id3);
+ resource_ids_to_transfer.push_back(id4);
TransferableResourceArray list;
child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
&list);
- ASSERT_EQ(3u, list.size());
+ ASSERT_EQ(4u, list.size());
EXPECT_EQ(id1, list[0].id);
EXPECT_EQ(id2, list[1].id);
EXPECT_EQ(id3, list[2].id);
+ EXPECT_EQ(id4, list[3].id);
EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id2));
EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id3));
+ EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id4));
resource_provider_->ReceiveFromChild(child_id, list);
resource_provider_->DeclareUsedResourcesFromChild(child_id,
resource_ids_to_transfer);
@@ -964,78 +1077,28 @@ TEST_P(ResourceProviderTest, TransferSoftwareResources) {
EXPECT_EQ(0u, returned_to_child.size());
- EXPECT_EQ(3u, resource_provider_->num_resources());
+ EXPECT_EQ(4u, resource_provider_->num_resources());
resource_provider_->DestroyChild(child_id);
EXPECT_EQ(0u, resource_provider_->num_resources());
- ASSERT_EQ(3u, returned_to_child.size());
+ ASSERT_EQ(4u, returned_to_child.size());
EXPECT_EQ(0u, returned_to_child[0].sync_point);
EXPECT_EQ(0u, returned_to_child[1].sync_point);
EXPECT_EQ(0u, returned_to_child[2].sync_point);
- EXPECT_EQ(id1, returned_to_child[0].id);
- EXPECT_EQ(id2, returned_to_child[1].id);
- EXPECT_EQ(id3, returned_to_child[2].id);
+ EXPECT_EQ(0u, returned_to_child[3].sync_point);
+ std::set<ResourceProvider::ResourceId> expected_ids;
+ expected_ids.insert(id1);
+ expected_ids.insert(id2);
+ expected_ids.insert(id3);
+ expected_ids.insert(id4);
+ std::set<ResourceProvider::ResourceId> returned_ids;
+ for (unsigned i = 0; i < 4; i++)
+ returned_ids.insert(returned_to_child[i].id);
+ EXPECT_EQ(expected_ids, returned_ids);
EXPECT_FALSE(returned_to_child[0].lost);
EXPECT_FALSE(returned_to_child[1].lost);
EXPECT_FALSE(returned_to_child[2].lost);
-}
-
-TEST_P(ResourceProviderTest, TransferSoftwareToNonUber) {
- // TODO(jbauman): Remove test when shared bitmap manager available
- // everywhere.
- if (GetParam() != ResourceProvider::Bitmap)
- return;
-
- scoped_ptr<FakeOutputSurface> parent_output_surface =
- FakeOutputSurface::CreateSoftware(
- make_scoped_ptr(new SoftwareOutputDevice));
- FakeOutputSurfaceClient parent_output_surface_client;
- CHECK(parent_output_surface->BindToClient(&parent_output_surface_client));
-
- scoped_ptr<ResourceProvider> parent_resource_provider(
- ResourceProvider::Create(parent_output_surface.get(),
- NULL,
- 0,
- false,
- 1));
-
- gfx::Size size(1, 1);
- ResourceFormat format = RGBA_8888;
- size_t pixel_size = TextureSizeBytes(size, format);
- ASSERT_EQ(4U, pixel_size);
-
- ResourceProvider::ResourceId id1 = resource_provider_->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
- uint8_t data1[4] = { 1, 2, 3, 4 };
- gfx::Rect rect(size);
- resource_provider_->SetPixels(id1, data1, rect, rect, gfx::Vector2d());
-
- ReturnedResourceArray returned_to_child;
- int child_id = parent_resource_provider->CreateChild(
- GetReturnCallback(&returned_to_child));
- {
- ResourceProvider::ResourceIdArray resource_ids_to_transfer;
- resource_ids_to_transfer.push_back(id1);
- TransferableResourceArray list;
- resource_provider_->PrepareSendToParent(resource_ids_to_transfer, &list);
- ASSERT_EQ(1u, list.size());
- EXPECT_TRUE(resource_provider_->InUseByConsumer(id1));
- parent_resource_provider->ReceiveFromChild(child_id, list);
- }
-
- EXPECT_EQ(0u, parent_resource_provider->num_resources());
- ASSERT_EQ(1u, returned_to_child.size());
- EXPECT_EQ(returned_to_child[0].id, id1);
- ResourceProvider::ResourceIdMap resource_map =
- parent_resource_provider->GetChildToParentMap(child_id);
- ResourceProvider::ResourceId mapped_id1 = resource_map[id1];
- EXPECT_EQ(0u, mapped_id1);
-
- parent_resource_provider->DestroyChild(child_id);
- EXPECT_EQ(0u, parent_resource_provider->num_resources());
-
- ASSERT_EQ(1u, returned_to_child.size());
- EXPECT_FALSE(returned_to_child[0].lost);
+ EXPECT_FALSE(returned_to_child[3].lost);
}
TEST_P(ResourceProviderTest, TransferGLToSoftware) {
@@ -1050,12 +1113,9 @@ TEST_P(ResourceProviderTest, TransferGLToSoftware) {
child_context_owned.PassAs<TestWebGraphicsContext3D>()));
CHECK(child_output_surface->BindToClient(&child_output_surface_client));
- scoped_ptr<ResourceProvider> child_resource_provider(
- ResourceProvider::Create(child_output_surface.get(),
- NULL,
- 0,
- false,
- 1));
+ scoped_ptr<ResourceProvider> child_resource_provider(ResourceProvider::Create(
+ child_output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1,
+ false));
gfx::Size size(1, 1);
ResourceFormat format = RGBA_8888;
@@ -1078,8 +1138,9 @@ TEST_P(ResourceProviderTest, TransferGLToSoftware) {
child_resource_provider->PrepareSendToParent(resource_ids_to_transfer,
&list);
ASSERT_EQ(1u, list.size());
- EXPECT_NE(0u, list[0].sync_point);
- EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D), list[0].target);
+ EXPECT_NE(0u, list[0].mailbox_holder.sync_point);
+ EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D),
+ list[0].mailbox_holder.texture_target);
EXPECT_TRUE(child_resource_provider->InUseByConsumer(id1));
resource_provider_->ReceiveFromChild(child_id, list);
}
@@ -1125,18 +1186,23 @@ TEST_P(ResourceProviderTest, TransferInvalidSoftware) {
&list);
ASSERT_EQ(1u, list.size());
// Make invalid.
- list[0].mailbox.name[1] = 5;
+ list[0].mailbox_holder.mailbox.name[1] = 5;
EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
resource_provider_->ReceiveFromChild(child_id, list);
}
- EXPECT_EQ(0u, resource_provider_->num_resources());
- ASSERT_EQ(1u, returned_to_child.size());
- EXPECT_EQ(returned_to_child[0].id, id1);
+ EXPECT_EQ(1u, resource_provider_->num_resources());
+ EXPECT_EQ(0u, returned_to_child.size());
+
ResourceProvider::ResourceIdMap resource_map =
resource_provider_->GetChildToParentMap(child_id);
ResourceProvider::ResourceId mapped_id1 = resource_map[id1];
- EXPECT_EQ(0u, mapped_id1);
+ EXPECT_NE(0u, mapped_id1);
+ {
+ ResourceProvider::ScopedReadLockSoftware lock(resource_provider_.get(),
+ mapped_id1);
+ EXPECT_FALSE(lock.valid());
+ }
resource_provider_->DestroyChild(child_id);
EXPECT_EQ(0u, resource_provider_->num_resources());
@@ -1175,8 +1241,8 @@ TEST_P(ResourceProviderTest, DeleteExportedResources) {
&list);
ASSERT_EQ(2u, list.size());
if (GetParam() == ResourceProvider::GLTexture) {
- EXPECT_NE(0u, list[0].sync_point);
- EXPECT_NE(0u, list[1].sync_point);
+ EXPECT_NE(0u, list[0].mailbox_holder.sync_point);
+ EXPECT_NE(0u, list[1].mailbox_holder.sync_point);
}
EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id2));
@@ -1205,8 +1271,8 @@ TEST_P(ResourceProviderTest, DeleteExportedResources) {
ASSERT_EQ(2u, list.size());
if (GetParam() == ResourceProvider::GLTexture) {
- EXPECT_NE(0u, list[0].sync_point);
- EXPECT_NE(0u, list[1].sync_point);
+ EXPECT_NE(0u, list[0].mailbox_holder.sync_point);
+ EXPECT_NE(0u, list[1].mailbox_holder.sync_point);
}
EXPECT_TRUE(resource_provider_->InUseByConsumer(id1));
EXPECT_TRUE(resource_provider_->InUseByConsumer(id2));
@@ -1269,8 +1335,8 @@ TEST_P(ResourceProviderTest, DestroyChildWithExportedResources) {
&list);
ASSERT_EQ(2u, list.size());
if (GetParam() == ResourceProvider::GLTexture) {
- EXPECT_NE(0u, list[0].sync_point);
- EXPECT_NE(0u, list[1].sync_point);
+ EXPECT_NE(0u, list[0].mailbox_holder.sync_point);
+ EXPECT_NE(0u, list[1].mailbox_holder.sync_point);
}
EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id2));
@@ -1299,8 +1365,8 @@ TEST_P(ResourceProviderTest, DestroyChildWithExportedResources) {
ASSERT_EQ(2u, list.size());
if (GetParam() == ResourceProvider::GLTexture) {
- EXPECT_NE(0u, list[0].sync_point);
- EXPECT_NE(0u, list[1].sync_point);
+ EXPECT_NE(0u, list[0].mailbox_holder.sync_point);
+ EXPECT_NE(0u, list[1].mailbox_holder.sync_point);
}
EXPECT_TRUE(resource_provider_->InUseByConsumer(id1));
EXPECT_TRUE(resource_provider_->InUseByConsumer(id2));
@@ -1374,7 +1440,7 @@ TEST_P(ResourceProviderTest, DeleteTransferredResources) {
&list);
ASSERT_EQ(1u, list.size());
if (GetParam() == ResourceProvider::GLTexture)
- EXPECT_NE(0u, list[0].sync_point);
+ EXPECT_NE(0u, list[0].mailbox_holder.sync_point);
EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id));
resource_provider_->ReceiveFromChild(child_id, list);
resource_provider_->DeclareUsedResourcesFromChild(child_id,
@@ -1400,6 +1466,116 @@ TEST_P(ResourceProviderTest, DeleteTransferredResources) {
EXPECT_EQ(0u, child_resource_provider_->num_resources());
}
+TEST_P(ResourceProviderTest, UnuseTransferredResources) {
+ gfx::Size size(1, 1);
+ ResourceFormat format = RGBA_8888;
+ size_t pixel_size = TextureSizeBytes(size, format);
+ ASSERT_EQ(4U, pixel_size);
+
+ ResourceProvider::ResourceId id = child_resource_provider_->CreateResource(
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
+ uint8_t data[4] = {1, 2, 3, 4};
+ gfx::Rect rect(size);
+ child_resource_provider_->SetPixels(id, data, rect, rect, gfx::Vector2d());
+
+ ReturnedResourceArray returned_to_child;
+ int child_id =
+ resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
+ const ResourceProvider::ResourceIdMap& map =
+ resource_provider_->GetChildToParentMap(child_id);
+ {
+ // Transfer some resource to the parent.
+ ResourceProvider::ResourceIdArray resource_ids_to_transfer;
+ resource_ids_to_transfer.push_back(id);
+ TransferableResourceArray list;
+ child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
+ &list);
+ EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id));
+ resource_provider_->ReceiveFromChild(child_id, list);
+ resource_provider_->DeclareUsedResourcesFromChild(child_id,
+ resource_ids_to_transfer);
+ }
+ TransferableResourceArray sent_to_top_level;
+ {
+ // Parent transfers to top-level.
+ ASSERT_TRUE(map.find(id) != map.end());
+ ResourceProvider::ResourceId parent_id = map.find(id)->second;
+ ResourceProvider::ResourceIdArray resource_ids_to_transfer;
+ resource_ids_to_transfer.push_back(parent_id);
+ resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
+ &sent_to_top_level);
+ EXPECT_TRUE(resource_provider_->InUseByConsumer(parent_id));
+ }
+ {
+ // Stop using resource.
+ ResourceProvider::ResourceIdArray empty;
+ resource_provider_->DeclareUsedResourcesFromChild(child_id, empty);
+ // Resource is not yet returned to the child, since it's in use by the
+ // top-level.
+ EXPECT_TRUE(returned_to_child.empty());
+ }
+ {
+ // Send the resource to the parent again.
+ ResourceProvider::ResourceIdArray resource_ids_to_transfer;
+ resource_ids_to_transfer.push_back(id);
+ TransferableResourceArray list;
+ child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
+ &list);
+ EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id));
+ resource_provider_->ReceiveFromChild(child_id, list);
+ resource_provider_->DeclareUsedResourcesFromChild(child_id,
+ resource_ids_to_transfer);
+ }
+ {
+ // Receive returns back from top-level.
+ ReturnedResourceArray returned;
+ TransferableResource::ReturnResources(sent_to_top_level, &returned);
+ resource_provider_->ReceiveReturnsFromParent(returned);
+ // Resource is still not yet returned to the child, since it's declared used
+ // in the parent.
+ EXPECT_TRUE(returned_to_child.empty());
+ ASSERT_TRUE(map.find(id) != map.end());
+ ResourceProvider::ResourceId parent_id = map.find(id)->second;
+ EXPECT_FALSE(resource_provider_->InUseByConsumer(parent_id));
+ }
+ {
+ sent_to_top_level.clear();
+ // Parent transfers again to top-level.
+ ASSERT_TRUE(map.find(id) != map.end());
+ ResourceProvider::ResourceId parent_id = map.find(id)->second;
+ ResourceProvider::ResourceIdArray resource_ids_to_transfer;
+ resource_ids_to_transfer.push_back(parent_id);
+ resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
+ &sent_to_top_level);
+ EXPECT_TRUE(resource_provider_->InUseByConsumer(parent_id));
+ }
+ {
+ // Receive returns back from top-level.
+ ReturnedResourceArray returned;
+ TransferableResource::ReturnResources(sent_to_top_level, &returned);
+ resource_provider_->ReceiveReturnsFromParent(returned);
+ // Resource is still not yet returned to the child, since it's still
+ // declared used in the parent.
+ EXPECT_TRUE(returned_to_child.empty());
+ ASSERT_TRUE(map.find(id) != map.end());
+ ResourceProvider::ResourceId parent_id = map.find(id)->second;
+ EXPECT_FALSE(resource_provider_->InUseByConsumer(parent_id));
+ }
+ {
+ // Stop using resource.
+ ResourceProvider::ResourceIdArray empty;
+ resource_provider_->DeclareUsedResourcesFromChild(child_id, empty);
+ // Resource should have been returned to the child, since it's no longer in
+ // use by the top-level.
+ ASSERT_EQ(1u, returned_to_child.size());
+ EXPECT_EQ(id, returned_to_child[0].id);
+ EXPECT_EQ(2, returned_to_child[0].count);
+ child_resource_provider_->ReceiveReturnsFromParent(returned_to_child);
+ returned_to_child.clear();
+ EXPECT_FALSE(child_resource_provider_->InUseByConsumer(id));
+ }
+}
+
class ResourceProviderTestTextureFilters : public ResourceProviderTest {
public:
static void RunTest(GLenum child_filter, GLenum parent_filter) {
@@ -1411,13 +1587,16 @@ class ResourceProviderTestTextureFilters : public ResourceProviderTest {
scoped_ptr<OutputSurface> child_output_surface(FakeOutputSurface::Create3d(
child_context_owned.PassAs<TestWebGraphicsContext3D>()));
CHECK(child_output_surface->BindToClient(&child_output_surface_client));
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
scoped_ptr<ResourceProvider> child_resource_provider(
ResourceProvider::Create(child_output_surface.get(),
- NULL,
+ shared_bitmap_manager.get(),
0,
false,
- 1));
+ 1,
+ false));
scoped_ptr<TextureStateTrackingContext> parent_context_owned(
new TextureStateTrackingContext);
@@ -1430,10 +1609,11 @@ class ResourceProviderTestTextureFilters : public ResourceProviderTest {
scoped_ptr<ResourceProvider> parent_resource_provider(
ResourceProvider::Create(parent_output_surface.get(),
- NULL,
+ shared_bitmap_manager.get(),
0,
false,
- 1));
+ 1,
+ false));
gfx::Size size(1, 1);
ResourceFormat format = RGBA_8888;
@@ -1510,6 +1690,10 @@ class ResourceProviderTestTextureFilters : public ResourceProviderTest {
bindTexture(GL_TEXTURE_2D, parent_texture_id));
EXPECT_CALL(*parent_context, consumeTextureCHROMIUM(GL_TEXTURE_2D, _));
parent_resource_provider->ReceiveFromChild(child_id, list);
+ {
+ ResourceProvider::ScopedReadLockGL lock(parent_resource_provider.get(),
+ list[0].id);
+ }
Mock::VerifyAndClearExpectations(parent_context);
parent_resource_provider->DeclareUsedResourcesFromChild(
@@ -1588,18 +1772,18 @@ TEST_P(ResourceProviderTest, TransferMailboxResources) {
gpu::Mailbox mailbox;
context()->genMailboxCHROMIUM(mailbox.name);
context()->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
- unsigned sync_point = context()->insertSyncPoint();
+ uint32 sync_point = context()->insertSyncPoint();
// All the logic below assumes that the sync points are all positive.
EXPECT_LT(0u, sync_point);
- unsigned release_sync_point = 0;
+ uint32 release_sync_point = 0;
bool lost_resource = false;
ReleaseCallback callback =
base::Bind(ReleaseTextureMailbox, &release_sync_point, &lost_resource);
ResourceProvider::ResourceId resource =
resource_provider_->CreateResourceFromTextureMailbox(
- TextureMailbox(mailbox, sync_point),
+ TextureMailbox(mailbox, GL_TEXTURE_2D, sync_point),
SingleReleaseCallback::Create(callback));
EXPECT_EQ(1u, context()->NumTextures());
EXPECT_EQ(0u, release_sync_point);
@@ -1610,12 +1794,14 @@ TEST_P(ResourceProviderTest, TransferMailboxResources) {
TransferableResourceArray list;
resource_provider_->PrepareSendToParent(resource_ids_to_transfer, &list);
ASSERT_EQ(1u, list.size());
- EXPECT_LE(sync_point, list[0].sync_point);
+ EXPECT_LE(sync_point, list[0].mailbox_holder.sync_point);
EXPECT_EQ(0,
- memcmp(mailbox.name, list[0].mailbox.name, sizeof(mailbox.name)));
+ memcmp(mailbox.name,
+ list[0].mailbox_holder.mailbox.name,
+ sizeof(mailbox.name)));
EXPECT_EQ(0u, release_sync_point);
- context()->waitSyncPoint(list[0].sync_point);
+ context()->waitSyncPoint(list[0].mailbox_holder.sync_point);
unsigned other_texture = context()->createTexture();
context()->bindTexture(GL_TEXTURE_2D, other_texture);
context()->consumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
@@ -1625,8 +1811,8 @@ TEST_P(ResourceProviderTest, TransferMailboxResources) {
EXPECT_EQ(0, memcmp(data, test_data, sizeof(data)));
context()->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
context()->deleteTexture(other_texture);
- list[0].sync_point = context()->insertSyncPoint();
- EXPECT_LT(0u, list[0].sync_point);
+ list[0].mailbox_holder.sync_point = context()->insertSyncPoint();
+ EXPECT_LT(0u, list[0].mailbox_holder.sync_point);
// Receive the resource, then delete it, expect the sync points to be
// consistent.
@@ -1637,7 +1823,7 @@ TEST_P(ResourceProviderTest, TransferMailboxResources) {
EXPECT_EQ(0u, release_sync_point);
resource_provider_->DeleteResource(resource);
- EXPECT_LE(list[0].sync_point, release_sync_point);
+ EXPECT_LE(list[0].mailbox_holder.sync_point, release_sync_point);
EXPECT_FALSE(lost_resource);
}
@@ -1647,7 +1833,7 @@ TEST_P(ResourceProviderTest, TransferMailboxResources) {
EXPECT_LT(0u, sync_point);
release_sync_point = 0;
resource = resource_provider_->CreateResourceFromTextureMailbox(
- TextureMailbox(mailbox, sync_point),
+ TextureMailbox(mailbox, GL_TEXTURE_2D, sync_point),
SingleReleaseCallback::Create(callback));
EXPECT_EQ(1u, context()->NumTextures());
EXPECT_EQ(0u, release_sync_point);
@@ -1658,12 +1844,14 @@ TEST_P(ResourceProviderTest, TransferMailboxResources) {
TransferableResourceArray list;
resource_provider_->PrepareSendToParent(resource_ids_to_transfer, &list);
ASSERT_EQ(1u, list.size());
- EXPECT_LE(sync_point, list[0].sync_point);
+ EXPECT_LE(sync_point, list[0].mailbox_holder.sync_point);
EXPECT_EQ(0,
- memcmp(mailbox.name, list[0].mailbox.name, sizeof(mailbox.name)));
+ memcmp(mailbox.name,
+ list[0].mailbox_holder.mailbox.name,
+ sizeof(mailbox.name)));
EXPECT_EQ(0u, release_sync_point);
- context()->waitSyncPoint(list[0].sync_point);
+ context()->waitSyncPoint(list[0].mailbox_holder.sync_point);
unsigned other_texture = context()->createTexture();
context()->bindTexture(GL_TEXTURE_2D, other_texture);
context()->consumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
@@ -1673,8 +1861,8 @@ TEST_P(ResourceProviderTest, TransferMailboxResources) {
EXPECT_EQ(0, memcmp(data, test_data, sizeof(data)));
context()->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
context()->deleteTexture(other_texture);
- list[0].sync_point = context()->insertSyncPoint();
- EXPECT_LT(0u, list[0].sync_point);
+ list[0].mailbox_holder.sync_point = context()->insertSyncPoint();
+ EXPECT_LT(0u, list[0].mailbox_holder.sync_point);
// Delete the resource, which shouldn't do anything.
resource_provider_->DeleteResource(resource);
@@ -1686,7 +1874,7 @@ TEST_P(ResourceProviderTest, TransferMailboxResources) {
ReturnedResourceArray returned;
TransferableResource::ReturnResources(list, &returned);
resource_provider_->ReceiveReturnsFromParent(returned);
- EXPECT_LE(list[0].sync_point, release_sync_point);
+ EXPECT_LE(list[0].mailbox_holder.sync_point, release_sync_point);
EXPECT_FALSE(lost_resource);
}
@@ -1826,10 +2014,10 @@ TEST_P(ResourceProviderTest, LostResourceInGrandParent) {
}
TEST_P(ResourceProviderTest, LostMailboxInParent) {
- unsigned release_sync_point = 0;
+ uint32 release_sync_point = 0;
bool lost_resource = false;
bool release_called = false;
- unsigned sync_point = 0;
+ uint32 sync_point = 0;
ResourceProvider::ResourceId resource = CreateChildMailbox(
&release_sync_point, &lost_resource, &release_called, &sync_point);
@@ -1876,10 +2064,10 @@ TEST_P(ResourceProviderTest, LostMailboxInParent) {
}
TEST_P(ResourceProviderTest, LostMailboxInGrandParent) {
- unsigned release_sync_point = 0;
+ uint32 release_sync_point = 0;
bool lost_resource = false;
bool release_called = false;
- unsigned sync_point = 0;
+ uint32 sync_point = 0;
ResourceProvider::ResourceId resource = CreateChildMailbox(
&release_sync_point, &lost_resource, &release_called, &sync_point);
@@ -1944,10 +2132,10 @@ TEST_P(ResourceProviderTest, LostMailboxInGrandParent) {
}
TEST_P(ResourceProviderTest, Shutdown) {
- unsigned release_sync_point = 0;
+ uint32 release_sync_point = 0;
bool lost_resource = false;
bool release_called = false;
- unsigned sync_point = 0;
+ uint32 sync_point = 0;
CreateChildMailbox(
&release_sync_point, &lost_resource, &release_called, &sync_point);
@@ -1964,10 +2152,10 @@ TEST_P(ResourceProviderTest, Shutdown) {
}
TEST_P(ResourceProviderTest, ShutdownWithExportedResource) {
- unsigned release_sync_point = 0;
+ uint32 release_sync_point = 0;
bool lost_resource = false;
bool release_called = false;
- unsigned sync_point = 0;
+ uint32 sync_point = 0;
ResourceProvider::ResourceId resource = CreateChildMailbox(
&release_sync_point, &lost_resource, &release_called, &sync_point);
@@ -1997,17 +2185,16 @@ TEST_P(ResourceProviderTest, LostContext) {
gpu::Mailbox mailbox;
context()->genMailboxCHROMIUM(mailbox.name);
context()->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
- unsigned sync_point = context()->insertSyncPoint();
+ uint32 sync_point = context()->insertSyncPoint();
EXPECT_LT(0u, sync_point);
- unsigned release_sync_point = 0;
+ uint32 release_sync_point = 0;
bool lost_resource = false;
scoped_ptr<SingleReleaseCallback> callback = SingleReleaseCallback::Create(
base::Bind(ReleaseTextureMailbox, &release_sync_point, &lost_resource));
resource_provider_->CreateResourceFromTextureMailbox(
- TextureMailbox(mailbox, sync_point),
- callback.Pass());
+ TextureMailbox(mailbox, GL_TEXTURE_2D, sync_point), callback.Pass());
EXPECT_EQ(0u, release_sync_point);
EXPECT_FALSE(lost_resource);
@@ -2033,8 +2220,8 @@ TEST_P(ResourceProviderTest, ScopedSampler) {
context_owned.PassAs<TestWebGraphicsContext3D>()));
CHECK(output_surface->BindToClient(&output_surface_client));
- scoped_ptr<ResourceProvider> resource_provider(
- ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1));
+ scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
+ output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false));
gfx::Size size(1, 1);
ResourceFormat format = RGBA_8888;
@@ -2114,8 +2301,8 @@ TEST_P(ResourceProviderTest, ManagedResource) {
context_owned.PassAs<TestWebGraphicsContext3D>()));
CHECK(output_surface->BindToClient(&output_surface_client));
- scoped_ptr<ResourceProvider> resource_provider(
- ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1));
+ scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
+ output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false));
gfx::Size size(1, 1);
ResourceFormat format = RGBA_8888;
@@ -2163,8 +2350,8 @@ TEST_P(ResourceProviderTest, TextureWrapMode) {
context_owned.PassAs<TestWebGraphicsContext3D>()));
CHECK(output_surface->BindToClient(&output_surface_client));
- scoped_ptr<ResourceProvider> resource_provider(
- ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1));
+ scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
+ output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false));
gfx::Size size(1, 1);
ResourceFormat format = RGBA_8888;
@@ -2217,8 +2404,8 @@ TEST_P(ResourceProviderTest, TextureMailbox_SharedMemory) {
new SoftwareOutputDevice)));
CHECK(output_surface->BindToClient(&output_surface_client));
- scoped_ptr<ResourceProvider> resource_provider(
- ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1));
+ scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
+ output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false));
scoped_ptr<SingleReleaseCallback> callback = SingleReleaseCallback::Create(
base::Bind(&EmptyReleaseCallback));
@@ -2252,11 +2439,11 @@ TEST_P(ResourceProviderTest, TextureMailbox_GLTexture2D) {
context_owned.PassAs<TestWebGraphicsContext3D>()));
CHECK(output_surface->BindToClient(&output_surface_client));
- scoped_ptr<ResourceProvider> resource_provider(
- ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1));
+ scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
+ output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false));
unsigned texture_id = 1;
- unsigned sync_point = 30;
+ uint32 sync_point = 30;
unsigned target = GL_TEXTURE_2D;
EXPECT_CALL(*context, bindTexture(_, _)).Times(0);
@@ -2270,7 +2457,7 @@ TEST_P(ResourceProviderTest, TextureMailbox_GLTexture2D) {
scoped_ptr<SingleReleaseCallback> callback = SingleReleaseCallback::Create(
base::Bind(&EmptyReleaseCallback));
- TextureMailbox mailbox(gpu_mailbox, sync_point);
+ TextureMailbox mailbox(gpu_mailbox, target, sync_point);
ResourceProvider::ResourceId id =
resource_provider->CreateResourceFromTextureMailbox(
@@ -2316,11 +2503,11 @@ TEST_P(ResourceProviderTest, TextureMailbox_GLTextureExternalOES) {
context_owned.PassAs<TestWebGraphicsContext3D>()));
CHECK(output_surface->BindToClient(&output_surface_client));
- scoped_ptr<ResourceProvider> resource_provider(
- ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1));
+ scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
+ output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false));
unsigned texture_id = 1;
- unsigned sync_point = 30;
+ uint32 sync_point = 30;
unsigned target = GL_TEXTURE_EXTERNAL_OES;
EXPECT_CALL(*context, bindTexture(_, _)).Times(0);
@@ -2427,9 +2614,9 @@ class AllocationTrackingContext3D : public TestWebGraphicsContext3D {
GLsizei image_size,
const void* data));
MOCK_METHOD1(waitAsyncTexImage2DCHROMIUM, void(GLenum));
- MOCK_METHOD3(createImageCHROMIUM, GLuint(GLsizei, GLsizei, GLenum));
+ MOCK_METHOD4(createImageCHROMIUM, GLuint(GLsizei, GLsizei, GLenum, GLenum));
MOCK_METHOD1(destroyImageCHROMIUM, void(GLuint));
- MOCK_METHOD2(mapImageCHROMIUM, void*(GLuint, GLenum));
+ MOCK_METHOD1(mapImageCHROMIUM, void*(GLuint));
MOCK_METHOD3(getImageParameterivCHROMIUM, void(GLuint, GLenum, GLint*));
MOCK_METHOD1(unmapImageCHROMIUM, void(GLuint));
MOCK_METHOD2(bindTexImage2DCHROMIUM, void(GLenum, GLint));
@@ -2454,8 +2641,8 @@ TEST_P(ResourceProviderTest, TextureAllocation) {
context_owned.PassAs<TestWebGraphicsContext3D>()));
CHECK(output_surface->BindToClient(&output_surface_client));
- scoped_ptr<ResourceProvider> resource_provider(
- ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1));
+ scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
+ output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false));
gfx::Size size(2, 2);
gfx::Vector2d offset(0, 0);
@@ -2496,7 +2683,7 @@ TEST_P(ResourceProviderTest, TextureAllocation) {
// Same for async version.
id = resource_provider->CreateResource(
size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
- resource_provider->AcquirePixelBuffer(id);
+ resource_provider->AcquirePixelRasterBuffer(id);
EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id));
EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(2);
@@ -2505,7 +2692,7 @@ TEST_P(ResourceProviderTest, TextureAllocation) {
resource_provider->BeginSetPixels(id);
ASSERT_TRUE(resource_provider->DidSetPixelsComplete(id));
- resource_provider->ReleasePixelBuffer(id);
+ resource_provider->ReleasePixelRasterBuffer(id);
EXPECT_CALL(*context, RetireTextureId(texture_id)).Times(1);
resource_provider->DeleteResource(id);
@@ -2527,8 +2714,8 @@ TEST_P(ResourceProviderTest, TextureAllocationStorageUsageAny) {
context_owned.PassAs<TestWebGraphicsContext3D>()));
CHECK(output_surface->BindToClient(&output_surface_client));
- scoped_ptr<ResourceProvider> resource_provider(
- ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1));
+ scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
+ output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false));
gfx::Size size(2, 2);
ResourceFormat format = RGBA_8888;
@@ -2564,8 +2751,8 @@ TEST_P(ResourceProviderTest, TextureAllocationStorageUsageFramebuffer) {
context_owned.PassAs<TestWebGraphicsContext3D>()));
CHECK(output_surface->BindToClient(&output_surface_client));
- scoped_ptr<ResourceProvider> resource_provider(
- ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1));
+ scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
+ output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false));
gfx::Size size(2, 2);
ResourceFormat format = RGBA_8888;
@@ -2607,12 +2794,12 @@ TEST_P(ResourceProviderTest, PixelBuffer_GLTexture) {
ResourceProvider::ResourceId id = 0;
int texture_id = 123;
- scoped_ptr<ResourceProvider> resource_provider(
- ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1));
+ scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
+ output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false));
id = resource_provider->CreateResource(
size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
- resource_provider->AcquirePixelBuffer(id);
+ resource_provider->AcquirePixelRasterBuffer(id);
EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id));
EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(2);
@@ -2622,7 +2809,7 @@ TEST_P(ResourceProviderTest, PixelBuffer_GLTexture) {
EXPECT_TRUE(resource_provider->DidSetPixelsComplete(id));
- resource_provider->ReleasePixelBuffer(id);
+ resource_provider->ReleasePixelRasterBuffer(id);
EXPECT_CALL(*context, RetireTextureId(texture_id)).Times(1);
resource_provider->DeleteResource(id);
@@ -2630,48 +2817,6 @@ TEST_P(ResourceProviderTest, PixelBuffer_GLTexture) {
Mock::VerifyAndClearExpectations(context);
}
-TEST_P(ResourceProviderTest, PixelBuffer_Bitmap) {
- if (GetParam() != ResourceProvider::Bitmap)
- return;
- FakeOutputSurfaceClient output_surface_client;
- scoped_ptr<OutputSurface> output_surface(
- FakeOutputSurface::CreateSoftware(make_scoped_ptr(
- new SoftwareOutputDevice)));
- CHECK(output_surface->BindToClient(&output_surface_client));
-
- gfx::Size size(1, 1);
- ResourceFormat format = RGBA_8888;
- ResourceProvider::ResourceId id = 0;
- const uint32_t kBadBeef = 0xbadbeef;
-
- scoped_ptr<ResourceProvider> resource_provider(
- ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1));
-
- id = resource_provider->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
- resource_provider->AcquirePixelBuffer(id);
-
- void* data = resource_provider->MapPixelBuffer(id);
- ASSERT_TRUE(!!data);
- memcpy(data, &kBadBeef, sizeof(kBadBeef));
- resource_provider->UnmapPixelBuffer(id);
-
- resource_provider->BeginSetPixels(id);
- EXPECT_TRUE(resource_provider->DidSetPixelsComplete(id));
-
- resource_provider->ReleasePixelBuffer(id);
-
- {
- ResourceProvider::ScopedReadLockSoftware lock(resource_provider.get(), id);
- const SkBitmap* sk_bitmap = lock.sk_bitmap();
- EXPECT_EQ(sk_bitmap->width(), size.width());
- EXPECT_EQ(sk_bitmap->height(), size.height());
- EXPECT_EQ(*sk_bitmap->getAddr32(0, 0), kBadBeef);
- }
-
- resource_provider->DeleteResource(id);
-}
-
TEST_P(ResourceProviderTest, ForcingAsyncUploadToComplete) {
// Only for GL textures.
if (GetParam() != ResourceProvider::GLTexture)
@@ -2690,12 +2835,12 @@ TEST_P(ResourceProviderTest, ForcingAsyncUploadToComplete) {
ResourceProvider::ResourceId id = 0;
int texture_id = 123;
- scoped_ptr<ResourceProvider> resource_provider(
- ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1));
+ scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
+ output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false));
id = resource_provider->CreateResource(
size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
- resource_provider->AcquirePixelBuffer(id);
+ resource_provider->AcquirePixelRasterBuffer(id);
EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id));
EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(2);
@@ -2708,7 +2853,7 @@ TEST_P(ResourceProviderTest, ForcingAsyncUploadToComplete) {
EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, 0)).Times(1);
resource_provider->ForceSetPixelsToComplete(id);
- resource_provider->ReleasePixelBuffer(id);
+ resource_provider->ReleasePixelRasterBuffer(id);
EXPECT_CALL(*context, RetireTextureId(texture_id)).Times(1);
resource_provider->DeleteResource(id);
@@ -2731,8 +2876,8 @@ TEST_P(ResourceProviderTest, PixelBufferLostContext) {
ResourceProvider::ResourceId id = 0;
int texture_id = 123;
- scoped_ptr<ResourceProvider> resource_provider(
- ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1));
+ scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
+ output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false));
EXPECT_CALL(*context, NextTextureId()).WillRepeatedly(Return(texture_id));
@@ -2740,11 +2885,12 @@ TEST_P(ResourceProviderTest, PixelBufferLostContext) {
size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
context->loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
GL_INNOCENT_CONTEXT_RESET_ARB);
- resource_provider->AcquirePixelBuffer(id);
- uint8_t* buffer = resource_provider->MapPixelBuffer(id);
- EXPECT_TRUE(buffer == NULL);
- resource_provider->UnmapPixelBuffer(id);
- resource_provider->ReleasePixelBuffer(id);
+
+ resource_provider->AcquirePixelRasterBuffer(id);
+ SkCanvas* raster_canvas = resource_provider->MapPixelRasterBuffer(id);
+ EXPECT_TRUE(raster_canvas == NULL);
+ resource_provider->UnmapPixelRasterBuffer(id);
+ resource_provider->ReleasePixelRasterBuffer(id);
Mock::VerifyAndClearExpectations(context);
}
@@ -2769,35 +2915,33 @@ TEST_P(ResourceProviderTest, Image_GLTexture) {
const unsigned kTextureId = 123u;
const unsigned kImageId = 234u;
- scoped_ptr<ResourceProvider> resource_provider(
- ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1));
+ scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
+ output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false));
id = resource_provider->CreateResource(
size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
- EXPECT_CALL(*context, createImageCHROMIUM(kWidth, kHeight, GL_RGBA8_OES))
- .WillOnce(Return(kImageId))
- .RetiresOnSaturation();
- resource_provider->AcquireImage(id);
+ const int kStride = 4;
void* dummy_mapped_buffer_address = NULL;
- EXPECT_CALL(*context, mapImageCHROMIUM(kImageId, GL_READ_WRITE))
- .WillOnce(Return(dummy_mapped_buffer_address))
+ EXPECT_CALL(
+ *context,
+ createImageCHROMIUM(kWidth, kHeight, GL_RGBA8_OES, GL_IMAGE_MAP_CHROMIUM))
+ .WillOnce(Return(kImageId))
.RetiresOnSaturation();
- resource_provider->MapImage(id);
-
- const int kStride = 4;
EXPECT_CALL(*context, getImageParameterivCHROMIUM(kImageId,
GL_IMAGE_ROWBYTES_CHROMIUM,
_))
.WillOnce(SetArgPointee<2>(kStride))
.RetiresOnSaturation();
- int stride = resource_provider->GetImageStride(id);
- EXPECT_EQ(kStride, stride);
+ EXPECT_CALL(*context, mapImageCHROMIUM(kImageId))
+ .WillOnce(Return(dummy_mapped_buffer_address))
+ .RetiresOnSaturation();
+ resource_provider->MapImageRasterBuffer(id);
EXPECT_CALL(*context, unmapImageCHROMIUM(kImageId))
.Times(1)
.RetiresOnSaturation();
- resource_provider->UnmapImage(id);
+ resource_provider->UnmapImageRasterBuffer(id);
EXPECT_CALL(*context, NextTextureId())
.WillOnce(Return(kTextureId))
@@ -2814,15 +2958,20 @@ TEST_P(ResourceProviderTest, Image_GLTexture) {
EXPECT_EQ(kTextureId, lock_gl.texture_id());
}
- EXPECT_CALL(*context, mapImageCHROMIUM(kImageId, GL_READ_WRITE))
+ EXPECT_CALL(
+ *context,
+ getImageParameterivCHROMIUM(kImageId, GL_IMAGE_ROWBYTES_CHROMIUM, _))
+ .WillOnce(SetArgPointee<2>(kStride))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*context, mapImageCHROMIUM(kImageId))
.WillOnce(Return(dummy_mapped_buffer_address))
.RetiresOnSaturation();
- resource_provider->MapImage(id);
+ resource_provider->MapImageRasterBuffer(id);
EXPECT_CALL(*context, unmapImageCHROMIUM(kImageId))
.Times(1)
.RetiresOnSaturation();
- resource_provider->UnmapImage(id);
+ resource_provider->UnmapImageRasterBuffer(id);
EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, kTextureId)).Times(1)
.RetiresOnSaturation();
@@ -2844,7 +2993,6 @@ TEST_P(ResourceProviderTest, Image_GLTexture) {
EXPECT_CALL(*context, destroyImageCHROMIUM(kImageId))
.Times(1)
.RetiresOnSaturation();
- resource_provider->ReleaseImage(id);
}
TEST_P(ResourceProviderTest, Image_Bitmap) {
@@ -2861,21 +3009,19 @@ TEST_P(ResourceProviderTest, Image_Bitmap) {
ResourceProvider::ResourceId id = 0;
const uint32_t kBadBeef = 0xbadbeef;
- scoped_ptr<ResourceProvider> resource_provider(
- ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1));
+ scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
+ output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false));
id = resource_provider->CreateResource(
size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
- resource_provider->AcquireImage(id);
- const int kStride = 0;
- int stride = resource_provider->GetImageStride(id);
- EXPECT_EQ(kStride, stride);
-
- void* data = resource_provider->MapImage(id);
- ASSERT_TRUE(!!data);
- memcpy(data, &kBadBeef, sizeof(kBadBeef));
- resource_provider->UnmapImage(id);
+ SkBitmap bitmap;
+ bitmap.allocN32Pixels(size.width(), size.height());
+ *(bitmap.getAddr32(0, 0)) = kBadBeef;
+ SkCanvas* canvas = resource_provider->MapImageRasterBuffer(id);
+ ASSERT_TRUE(!!canvas);
+ canvas->writePixels(bitmap, 0, 0);
+ resource_provider->UnmapImageRasterBuffer(id);
{
ResourceProvider::ScopedReadLockSoftware lock(resource_provider.get(), id);
@@ -2885,10 +3031,142 @@ TEST_P(ResourceProviderTest, Image_Bitmap) {
EXPECT_EQ(*sk_bitmap->getAddr32(0, 0), kBadBeef);
}
- resource_provider->ReleaseImage(id);
resource_provider->DeleteResource(id);
}
+TEST_P(ResourceProviderTest, CopyResource_GLTexture) {
+ if (GetParam() != ResourceProvider::GLTexture)
+ return;
+ scoped_ptr<AllocationTrackingContext3D> context_owned(
+ new StrictMock<AllocationTrackingContext3D>);
+ AllocationTrackingContext3D* context = context_owned.get();
+ context_owned->set_support_sync_query(true);
+
+ FakeOutputSurfaceClient output_surface_client;
+ scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
+ context_owned.PassAs<TestWebGraphicsContext3D>()));
+ ASSERT_TRUE(output_surface->BindToClient(&output_surface_client));
+
+ const int kWidth = 2;
+ const int kHeight = 2;
+ gfx::Size size(kWidth, kHeight);
+ ResourceFormat format = RGBA_8888;
+ ResourceProvider::ResourceId source_id = 0;
+ ResourceProvider::ResourceId dest_id = 0;
+ const unsigned kSourceTextureId = 123u;
+ const unsigned kDestTextureId = 321u;
+ const unsigned kImageId = 234u;
+
+ scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
+ output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false));
+
+ source_id = resource_provider->CreateResource(
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
+
+ const int kStride = 4;
+ void* dummy_mapped_buffer_address = NULL;
+ EXPECT_CALL(
+ *context,
+ createImageCHROMIUM(kWidth, kHeight, GL_RGBA8_OES, GL_IMAGE_MAP_CHROMIUM))
+ .WillOnce(Return(kImageId))
+ .RetiresOnSaturation();
+ EXPECT_CALL(
+ *context,
+ getImageParameterivCHROMIUM(kImageId, GL_IMAGE_ROWBYTES_CHROMIUM, _))
+ .WillOnce(SetArgPointee<2>(kStride))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*context, mapImageCHROMIUM(kImageId))
+ .WillOnce(Return(dummy_mapped_buffer_address))
+ .RetiresOnSaturation();
+ resource_provider->MapImageRasterBuffer(source_id);
+ Mock::VerifyAndClearExpectations(context);
+
+ EXPECT_CALL(*context, unmapImageCHROMIUM(kImageId))
+ .Times(1)
+ .RetiresOnSaturation();
+ resource_provider->UnmapImageRasterBuffer(source_id);
+ Mock::VerifyAndClearExpectations(context);
+
+ dest_id = resource_provider->CreateResource(
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
+
+ EXPECT_CALL(*context, NextTextureId())
+ .WillOnce(Return(kDestTextureId))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, kDestTextureId))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*context, NextTextureId())
+ .WillOnce(Return(kSourceTextureId))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, kSourceTextureId))
+ .Times(2)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*context, bindTexImage2DCHROMIUM(GL_TEXTURE_2D, kImageId))
+ .Times(1)
+ .RetiresOnSaturation();
+ resource_provider->CopyResource(source_id, dest_id);
+ Mock::VerifyAndClearExpectations(context);
+
+ EXPECT_CALL(*context, destroyImageCHROMIUM(kImageId))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*context, RetireTextureId(kSourceTextureId))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*context, RetireTextureId(kDestTextureId))
+ .Times(1)
+ .RetiresOnSaturation();
+ resource_provider->DeleteResource(source_id);
+ resource_provider->DeleteResource(dest_id);
+}
+
+TEST_P(ResourceProviderTest, CopyResource_Bitmap) {
+ if (GetParam() != ResourceProvider::Bitmap)
+ return;
+ FakeOutputSurfaceClient output_surface_client;
+ scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::CreateSoftware(
+ make_scoped_ptr(new SoftwareOutputDevice)));
+ CHECK(output_surface->BindToClient(&output_surface_client));
+
+ gfx::Size size(1, 1);
+ ResourceFormat format = RGBA_8888;
+ ResourceProvider::ResourceId source_id = 0;
+ ResourceProvider::ResourceId dest_id = 0;
+ const uint32_t kBadBeef = 0xbadbeef;
+
+ scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
+ output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false));
+
+ source_id = resource_provider->CreateResource(
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
+
+ SkBitmap bitmap;
+ bitmap.allocN32Pixels(size.width(), size.height());
+ *(bitmap.getAddr32(0, 0)) = kBadBeef;
+ SkCanvas* canvas = resource_provider->MapImageRasterBuffer(source_id);
+ ASSERT_TRUE(!!canvas);
+ canvas->writePixels(bitmap, 0, 0);
+ resource_provider->UnmapImageRasterBuffer(source_id);
+
+ dest_id = resource_provider->CreateResource(
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
+
+ resource_provider->CopyResource(source_id, dest_id);
+
+ {
+ ResourceProvider::ScopedReadLockSoftware lock(resource_provider.get(),
+ dest_id);
+ const SkBitmap* sk_bitmap = lock.sk_bitmap();
+ EXPECT_EQ(sk_bitmap->width(), size.width());
+ EXPECT_EQ(sk_bitmap->height(), size.height());
+ EXPECT_EQ(*sk_bitmap->getAddr32(0, 0), kBadBeef);
+ }
+
+ resource_provider->DeleteResource(source_id);
+ resource_provider->DeleteResource(dest_id);
+}
+
void InitializeGLAndCheck(ContextSharedData* shared_data,
ResourceProvider* resource_provider,
FakeOutputSurface* output_surface) {
@@ -2899,21 +3177,25 @@ void InitializeGLAndCheck(ContextSharedData* shared_data,
scoped_refptr<TestContextProvider> context_provider =
TestContextProvider::Create(
context_owned.PassAs<TestWebGraphicsContext3D>());
- output_surface->InitializeAndSetContext3d(context_provider, NULL);
- EXPECT_TRUE(resource_provider->InitializeGL());
+ output_surface->InitializeAndSetContext3d(context_provider);
+ resource_provider->InitializeGL();
CheckCreateResource(ResourceProvider::GLTexture, resource_provider, context);
}
TEST(ResourceProviderTest, BasicInitializeGLSoftware) {
scoped_ptr<ContextSharedData> shared_data = ContextSharedData::Create();
- FakeOutputSurfaceClient client;
+ bool delegated_rendering = false;
scoped_ptr<FakeOutputSurface> output_surface(
FakeOutputSurface::CreateDeferredGL(
- scoped_ptr<SoftwareOutputDevice>(new SoftwareOutputDevice)));
+ scoped_ptr<SoftwareOutputDevice>(new SoftwareOutputDevice),
+ delegated_rendering));
+ FakeOutputSurfaceClient client(output_surface.get());
EXPECT_TRUE(output_surface->BindToClient(&client));
- scoped_ptr<ResourceProvider> resource_provider(
- ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1));
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
+ scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
+ output_surface.get(), shared_bitmap_manager.get(), 0, false, 1, false));
CheckCreateResource(ResourceProvider::Bitmap, resource_provider.get(), NULL);
@@ -2950,7 +3232,8 @@ TEST_P(ResourceProviderTest, CompressedTextureETC1Allocate) {
shared_bitmap_manager_.get(),
0,
false,
- 1));
+ 1,
+ false));
int texture_id = 123;
ResourceProvider::ResourceId id = resource_provider->CreateResource(
@@ -2984,7 +3267,8 @@ TEST_P(ResourceProviderTest, CompressedTextureETC1SetPixels) {
shared_bitmap_manager_.get(),
0,
false,
- 1));
+ 1,
+ false));
int texture_id = 123;
uint8_t pixels[8];
@@ -3030,6 +3314,8 @@ TEST(ResourceProviderTest, TextureAllocationChunkSize) {
scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
context_owned.PassAs<TestWebGraphicsContext3D>()));
CHECK(output_surface->BindToClient(&output_surface_client));
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
gfx::Size size(1, 1);
ResourceFormat format = RGBA_8888;
@@ -3038,10 +3324,11 @@ TEST(ResourceProviderTest, TextureAllocationChunkSize) {
size_t kTextureAllocationChunkSize = 1;
scoped_ptr<ResourceProvider> resource_provider(
ResourceProvider::Create(output_surface.get(),
- NULL,
+ shared_bitmap_manager.get(),
0,
false,
- kTextureAllocationChunkSize));
+ kTextureAllocationChunkSize,
+ false));
ResourceProvider::ResourceId id = resource_provider->CreateResource(
size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
@@ -3056,10 +3343,11 @@ TEST(ResourceProviderTest, TextureAllocationChunkSize) {
size_t kTextureAllocationChunkSize = 8;
scoped_ptr<ResourceProvider> resource_provider(
ResourceProvider::Create(output_surface.get(),
- NULL,
+ shared_bitmap_manager.get(),
0,
false,
- kTextureAllocationChunkSize));
+ kTextureAllocationChunkSize,
+ false));
ResourceProvider::ResourceId id = resource_provider->CreateResource(
size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
diff --git a/chromium/cc/resources/resource_update.cc b/chromium/cc/resources/resource_update.cc
index 5760ddf4a0d..2fe8fe5eebe 100644
--- a/chromium/cc/resources/resource_update.cc
+++ b/chromium/cc/resources/resource_update.cc
@@ -5,37 +5,18 @@
#include "cc/resources/resource_update.h"
#include "base/logging.h"
-#include "third_party/skia/include/core/SkCanvas.h"
-#include "third_party/skia/include/core/SkDevice.h"
namespace cc {
-ResourceUpdate ResourceUpdate::Create(PrioritizedResource* texture,
+ResourceUpdate ResourceUpdate::Create(PrioritizedResource* resource,
const SkBitmap* bitmap,
- gfx::Rect content_rect,
- gfx::Rect source_rect,
- gfx::Vector2d dest_offset) {
- CHECK(content_rect.Contains(source_rect));
- ResourceUpdate update;
- update.texture = texture;
- update.bitmap = bitmap;
- update.content_rect = content_rect;
- update.source_rect = source_rect;
- update.dest_offset = dest_offset;
- return update;
-}
-
-ResourceUpdate ResourceUpdate::CreateFromCanvas(
- PrioritizedResource* resource,
- const skia::RefPtr<SkCanvas>& canvas,
- gfx::Rect content_rect,
- gfx::Rect source_rect,
- gfx::Vector2d dest_offset) {
+ const gfx::Rect& content_rect,
+ const gfx::Rect& source_rect,
+ const gfx::Vector2d& dest_offset) {
CHECK(content_rect.Contains(source_rect));
ResourceUpdate update;
update.texture = resource;
- update.canvas = canvas;
- update.bitmap = &canvas->getDevice()->accessBitmap(false);
+ update.bitmap = bitmap;
update.content_rect = content_rect;
update.source_rect = source_rect;
update.dest_offset = dest_offset;
diff --git a/chromium/cc/resources/resource_update.h b/chromium/cc/resources/resource_update.h
index 47bef7da189..1eddf83c094 100644
--- a/chromium/cc/resources/resource_update.h
+++ b/chromium/cc/resources/resource_update.h
@@ -5,14 +5,11 @@
#ifndef CC_RESOURCES_RESOURCE_UPDATE_H_
#define CC_RESOURCES_RESOURCE_UPDATE_H_
-#include "base/memory/ref_counted.h"
#include "cc/base/cc_export.h"
-#include "skia/ext/refptr.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/vector2d.h"
class SkBitmap;
-class SkCanvas;
namespace cc {
@@ -21,21 +18,15 @@ class PrioritizedResource;
struct CC_EXPORT ResourceUpdate {
static ResourceUpdate Create(PrioritizedResource* resource,
const SkBitmap* bitmap,
- gfx::Rect content_rect,
- gfx::Rect source_rect,
- gfx::Vector2d dest_offset);
- static ResourceUpdate CreateFromCanvas(PrioritizedResource* resource,
- const skia::RefPtr<SkCanvas>& canvas,
- gfx::Rect content_rect,
- gfx::Rect source_rect,
- gfx::Vector2d dest_offset);
+ const gfx::Rect& content_rect,
+ const gfx::Rect& source_rect,
+ const gfx::Vector2d& dest_offset);
ResourceUpdate();
virtual ~ResourceUpdate();
PrioritizedResource* texture;
const SkBitmap* bitmap;
- skia::RefPtr<SkCanvas> canvas;
gfx::Rect content_rect;
gfx::Rect source_rect;
gfx::Vector2d dest_offset;
diff --git a/chromium/cc/resources/resource_update_controller.cc b/chromium/cc/resources/resource_update_controller.cc
index 868133596be..bd6d21df612 100644
--- a/chromium/cc/resources/resource_update_controller.cc
+++ b/chromium/cc/resources/resource_update_controller.cc
@@ -47,6 +47,7 @@ ResourceUpdateController::ResourceUpdateController(
first_update_attempt_(true),
task_runner_(task_runner),
task_posted_(false),
+ ready_to_finalize_(false),
weak_factory_(this) {}
ResourceUpdateController::~ResourceUpdateController() {}
@@ -55,8 +56,8 @@ void ResourceUpdateController::PerformMoreUpdates(
base::TimeTicks time_limit) {
time_limit_ = time_limit;
- // Update already in progress.
- if (task_posted_)
+ // Update already in progress or we are already done.
+ if (task_posted_ || ready_to_finalize_)
return;
// Call UpdateMoreTexturesNow() directly unless it's the first update
@@ -105,8 +106,10 @@ void ResourceUpdateController::Finalize() {
void ResourceUpdateController::OnTimerFired() {
task_posted_ = false;
- if (!UpdateMoreTexturesIfEnoughTimeRemaining())
+ if (!UpdateMoreTexturesIfEnoughTimeRemaining()) {
+ ready_to_finalize_ = true;
client_->ReadyToFinalizeTextureUpdates();
+ }
}
base::TimeTicks ResourceUpdateController::UpdateMoreTexturesCompletionTime() {
diff --git a/chromium/cc/resources/resource_update_controller.h b/chromium/cc/resources/resource_update_controller.h
index 4425f377f71..994ae2f2df9 100644
--- a/chromium/cc/resources/resource_update_controller.h
+++ b/chromium/cc/resources/resource_update_controller.h
@@ -78,6 +78,7 @@ class CC_EXPORT ResourceUpdateController {
bool first_update_attempt_;
base::SingleThreadTaskRunner* task_runner_;
bool task_posted_;
+ bool ready_to_finalize_;
base::WeakPtrFactory<ResourceUpdateController> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(ResourceUpdateController);
diff --git a/chromium/cc/resources/resource_update_controller_unittest.cc b/chromium/cc/resources/resource_update_controller_unittest.cc
index 8979925caea..0fb899d1461 100644
--- a/chromium/cc/resources/resource_update_controller_unittest.cc
+++ b/chromium/cc/resources/resource_update_controller_unittest.cc
@@ -10,6 +10,7 @@
#include "cc/test/fake_output_surface_client.h"
#include "cc/test/fake_proxy.h"
#include "cc/test/scheduler_test_common.h"
+#include "cc/test/test_shared_bitmap_manager.h"
#include "cc/test/test_web_graphics_context_3d.h"
#include "cc/test/tiled_layer_test_common.h"
#include "cc/trees/single_thread_proxy.h" // For DebugScopedSetImplThread
@@ -42,9 +43,9 @@ class WebGraphicsContext3DForUploadTest : public TestWebGraphicsContext3D {
GLenum format,
GLenum type,
const void* pixels) OVERRIDE;
- virtual GrGLInterface* createGrGLInterface() OVERRIDE { return NULL; }
- virtual void getQueryObjectuivEXT(GLuint id, GLenum pname, GLuint* value);
+ virtual void getQueryObjectuivEXT(GLuint id, GLenum pname, GLuint* value)
+ OVERRIDE;
private:
ResourceUpdateControllerTest* test_;
@@ -107,8 +108,7 @@ class ResourceUpdateControllerTest : public Test {
protected:
virtual void SetUp() {
- bitmap_.setConfig(SkBitmap::kARGB_8888_Config, 300, 150);
- bitmap_.allocPixels();
+ bitmap_.allocN32Pixels(300, 150);
for (int i = 0; i < 4; i++) {
textures_[i] = PrioritizedResource::Create(resource_manager_.get(),
@@ -124,8 +124,10 @@ class ResourceUpdateControllerTest : public Test {
new WebGraphicsContext3DForUploadTest(this)));
CHECK(output_surface_->BindToClient(&output_surface_client_));
- resource_provider_ =
- ResourceProvider::Create(output_surface_.get(), NULL, 0, false, 1);
+ shared_bitmap_manager_.reset(new TestSharedBitmapManager());
+ resource_provider_ = ResourceProvider::Create(
+ output_surface_.get(), shared_bitmap_manager_.get(), 0, false, 1,
+ false);
}
void AppendFullUploadsOfIndexedTextureToUpdateQueue(int count,
@@ -182,6 +184,7 @@ class ResourceUpdateControllerTest : public Test {
FakeProxy proxy_;
FakeOutputSurfaceClient output_surface_client_;
scoped_ptr<OutputSurface> output_surface_;
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager_;
scoped_ptr<ResourceProvider> resource_provider_;
scoped_ptr<ResourceUpdateQueue> queue_;
scoped_ptr<PrioritizedResource> textures_[4];
@@ -455,15 +458,16 @@ TEST_F(ResourceUpdateControllerTest, NoMoreUpdates) {
EXPECT_TRUE(client.ReadyToFinalizeCalled());
EXPECT_EQ(2, num_total_uploads_);
+ client.Reset();
controller->SetUpdateTextureTime(base::TimeDelta::FromMilliseconds(100));
controller->SetUpdateMoreTexturesSize(1);
// Enough time for updates but no more updates left.
controller->PerformMoreUpdates(controller->Now() +
base::TimeDelta::FromMilliseconds(310));
- // 0-delay task used to call ReadyToFinalizeTextureUpdates().
- RunPendingTask(task_runner.get(), controller.get());
+
+ // ReadyToFinalizeTextureUpdates should only be called once.
EXPECT_FALSE(task_runner->HasPendingTask());
- EXPECT_TRUE(client.ReadyToFinalizeCalled());
+ EXPECT_FALSE(client.ReadyToFinalizeCalled());
EXPECT_EQ(2, num_total_uploads_);
}
diff --git a/chromium/cc/resources/scoped_resource.cc b/chromium/cc/resources/scoped_resource.cc
index 99f93c9bc85..68ae59fc0ba 100644
--- a/chromium/cc/resources/scoped_resource.cc
+++ b/chromium/cc/resources/scoped_resource.cc
@@ -15,7 +15,7 @@ ScopedResource::~ScopedResource() {
Free();
}
-void ScopedResource::Allocate(gfx::Size size,
+void ScopedResource::Allocate(const gfx::Size& size,
ResourceProvider::TextureUsageHint hint,
ResourceFormat format) {
DCHECK(!id());
@@ -25,12 +25,12 @@ void ScopedResource::Allocate(gfx::Size size,
set_id(resource_provider_->CreateResource(
size, GL_CLAMP_TO_EDGE, hint, format));
-#ifndef NDEBUG
+#if DCHECK_IS_ON
allocate_thread_id_ = base::PlatformThread::CurrentId();
#endif
}
-void ScopedResource::AllocateManaged(gfx::Size size,
+void ScopedResource::AllocateManaged(const gfx::Size& size,
GLenum target,
ResourceFormat format) {
DCHECK(!id());
@@ -44,14 +44,14 @@ void ScopedResource::AllocateManaged(gfx::Size size,
ResourceProvider::TextureUsageAny,
format));
-#ifndef NDEBUG
+#if DCHECK_IS_ON
allocate_thread_id_ = base::PlatformThread::CurrentId();
#endif
}
void ScopedResource::Free() {
if (id()) {
-#ifndef NDEBUG
+#if DCHECK_IS_ON
DCHECK(allocate_thread_id_ == base::PlatformThread::CurrentId());
#endif
resource_provider_->DeleteResource(id());
diff --git a/chromium/cc/resources/scoped_resource.h b/chromium/cc/resources/scoped_resource.h
index 63f2cd48c47..9f58395a94c 100644
--- a/chromium/cc/resources/scoped_resource.h
+++ b/chromium/cc/resources/scoped_resource.h
@@ -11,7 +11,7 @@
#include "cc/base/cc_export.h"
#include "cc/resources/resource.h"
-#ifndef NDEBUG
+#if DCHECK_IS_ON
#include "base/threading/platform_thread.h"
#endif
@@ -25,10 +25,12 @@ class CC_EXPORT ScopedResource : public Resource {
}
virtual ~ScopedResource();
- void Allocate(gfx::Size size,
+ void Allocate(const gfx::Size& size,
ResourceProvider::TextureUsageHint hint,
ResourceFormat format);
- void AllocateManaged(gfx::Size size, GLenum target, ResourceFormat format);
+ void AllocateManaged(const gfx::Size& size,
+ GLenum target,
+ ResourceFormat format);
void Free();
void Leak();
@@ -38,7 +40,7 @@ class CC_EXPORT ScopedResource : public Resource {
private:
ResourceProvider* resource_provider_;
-#ifndef NDEBUG
+#if DCHECK_IS_ON
base::PlatformThreadId allocate_thread_id_;
#endif
diff --git a/chromium/cc/resources/scoped_resource_unittest.cc b/chromium/cc/resources/scoped_resource_unittest.cc
index 93ad3208b83..50422213736 100644
--- a/chromium/cc/resources/scoped_resource_unittest.cc
+++ b/chromium/cc/resources/scoped_resource_unittest.cc
@@ -7,6 +7,7 @@
#include "cc/output/renderer.h"
#include "cc/test/fake_output_surface.h"
#include "cc/test/fake_output_surface_client.h"
+#include "cc/test/test_shared_bitmap_manager.h"
#include "cc/test/tiled_layer_test_common.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -18,8 +19,10 @@ TEST(ScopedResourceTest, NewScopedResource) {
scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d());
CHECK(output_surface->BindToClient(&output_surface_client));
- scoped_ptr<ResourceProvider> resource_provider(
- ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1));
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
+ scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
+ output_surface.get(), shared_bitmap_manager.get(), 0, false, 1, false));
scoped_ptr<ScopedResource> texture =
ScopedResource::Create(resource_provider.get());
@@ -36,8 +39,10 @@ TEST(ScopedResourceTest, CreateScopedResource) {
scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d());
CHECK(output_surface->BindToClient(&output_surface_client));
- scoped_ptr<ResourceProvider> resource_provider(
- ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1));
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
+ scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
+ output_surface.get(), shared_bitmap_manager.get(), 0, false, 1, false));
scoped_ptr<ScopedResource> texture =
ScopedResource::Create(resource_provider.get());
texture->Allocate(gfx::Size(30, 30),
@@ -58,8 +63,10 @@ TEST(ScopedResourceTest, ScopedResourceIsDeleted) {
scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d());
CHECK(output_surface->BindToClient(&output_surface_client));
- scoped_ptr<ResourceProvider> resource_provider(
- ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1));
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
+ scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
+ output_surface.get(), shared_bitmap_manager.get(), 0, false, 1, false));
{
scoped_ptr<ScopedResource> texture =
ScopedResource::Create(resource_provider.get());
@@ -92,8 +99,10 @@ TEST(ScopedResourceTest, LeakScopedResource) {
scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d());
CHECK(output_surface->BindToClient(&output_surface_client));
- scoped_ptr<ResourceProvider> resource_provider(
- ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1));
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
+ scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
+ output_surface.get(), shared_bitmap_manager.get(), 0, false, 1, false));
{
scoped_ptr<ScopedResource> texture =
ScopedResource::Create(resource_provider.get());
diff --git a/chromium/cc/resources/shared_bitmap.cc b/chromium/cc/resources/shared_bitmap.cc
index 3a6fc3589e3..31cf245151c 100644
--- a/chromium/cc/resources/shared_bitmap.cc
+++ b/chromium/cc/resources/shared_bitmap.cc
@@ -4,14 +4,78 @@
#include "cc/resources/shared_bitmap.h"
+#include "base/logging.h"
+#include "base/numerics/safe_math.h"
+#include "base/rand_util.h"
+
namespace cc {
SharedBitmap::SharedBitmap(
base::SharedMemory* memory,
const SharedBitmapId& id,
- const base::Callback<void(SharedBitmap*)>& free_callback)
- : memory_(memory), id_(id), free_callback_(free_callback) {}
+ const base::Callback<void(SharedBitmap* bitmap)>& free_callback)
+ : memory_(memory),
+ pixels_(static_cast<uint8*>(memory_->memory())),
+ id_(id),
+ free_callback_(free_callback) {
+}
+
+SharedBitmap::SharedBitmap(
+ uint8* pixels,
+ const SharedBitmapId& id,
+ const base::Callback<void(SharedBitmap* bitmap)>& free_callback)
+ : memory_(NULL), pixels_(pixels), id_(id), free_callback_(free_callback) {
+}
SharedBitmap::~SharedBitmap() { free_callback_.Run(this); }
+// static
+bool SharedBitmap::SizeInBytes(const gfx::Size& size, size_t* size_in_bytes) {
+ if (size.IsEmpty())
+ return false;
+ base::CheckedNumeric<size_t> s = 4;
+ s *= size.width();
+ s *= size.height();
+ if (!s.IsValid())
+ return false;
+ *size_in_bytes = s.ValueOrDie();
+ return true;
+}
+
+// static
+size_t SharedBitmap::CheckedSizeInBytes(const gfx::Size& size) {
+ CHECK(!size.IsEmpty());
+ base::CheckedNumeric<size_t> s = 4;
+ s *= size.width();
+ s *= size.height();
+ return s.ValueOrDie();
+}
+
+// static
+size_t SharedBitmap::UncheckedSizeInBytes(const gfx::Size& size) {
+ DCHECK(VerifySizeInBytes(size));
+ size_t s = 4;
+ s *= size.width();
+ s *= size.height();
+ return s;
+}
+
+// static
+bool SharedBitmap::VerifySizeInBytes(const gfx::Size& size) {
+ if (size.IsEmpty())
+ return false;
+ base::CheckedNumeric<size_t> s = 4;
+ s *= size.width();
+ s *= size.height();
+ return s.IsValid();
+}
+
+// static
+SharedBitmapId SharedBitmap::GenerateId() {
+ SharedBitmapId id;
+ // Needs cryptographically-secure random numbers.
+ base::RandBytes(id.name, sizeof(id.name));
+ return id;
+}
+
} // namespace cc
diff --git a/chromium/cc/resources/shared_bitmap.h b/chromium/cc/resources/shared_bitmap.h
index 9575068411a..a90e47a084c 100644
--- a/chromium/cc/resources/shared_bitmap.h
+++ b/chromium/cc/resources/shared_bitmap.h
@@ -10,6 +10,7 @@
#include "base/memory/shared_memory.h"
#include "cc/base/cc_export.h"
#include "gpu/command_buffer/common/mailbox.h"
+#include "ui/gfx/size.h"
namespace base { class SharedMemory; }
@@ -20,7 +21,11 @@ class CC_EXPORT SharedBitmap {
public:
SharedBitmap(base::SharedMemory* memory,
const SharedBitmapId& id,
- const base::Callback<void(SharedBitmap*)>& free_callback);
+ const base::Callback<void(SharedBitmap* bitmap)>& free_callback);
+
+ SharedBitmap(uint8* pixels,
+ const SharedBitmapId& id,
+ const base::Callback<void(SharedBitmap* bitmap)>& free_callback);
~SharedBitmap();
@@ -32,16 +37,30 @@ class CC_EXPORT SharedBitmap {
return id_ < right.id_;
}
- uint8* pixels() { return static_cast<uint8*>(memory_->memory()); }
+ uint8* pixels() { return pixels_; }
base::SharedMemory* memory() { return memory_; }
SharedBitmapId id() { return id_; }
+ // Returns true if the size is valid and false otherwise.
+ static bool SizeInBytes(const gfx::Size& size, size_t* size_in_bytes);
+ // Dies with a CRASH() if the size can not be represented as a positive number
+ // of bytes.
+ static size_t CheckedSizeInBytes(const gfx::Size& size);
+ // Returns the size in bytes but may overflow or return 0. Only do this for
+ // sizes that have already been checked.
+ static size_t UncheckedSizeInBytes(const gfx::Size& size);
+ // Returns true if the size is valid and false otherwise.
+ static bool VerifySizeInBytes(const gfx::Size& size);
+
+ static SharedBitmapId GenerateId();
+
private:
base::SharedMemory* memory_;
+ uint8* pixels_;
SharedBitmapId id_;
- base::Callback<void(SharedBitmap*)> free_callback_;
+ base::Callback<void(SharedBitmap* bitmap)> free_callback_;
DISALLOW_COPY_AND_ASSIGN(SharedBitmap);
};
diff --git a/chromium/cc/resources/shared_bitmap_manager.h b/chromium/cc/resources/shared_bitmap_manager.h
index 53dd156470c..e6e49aff523 100644
--- a/chromium/cc/resources/shared_bitmap_manager.h
+++ b/chromium/cc/resources/shared_bitmap_manager.h
@@ -15,10 +15,11 @@ namespace cc {
class CC_EXPORT SharedBitmapManager {
public:
SharedBitmapManager() {}
+ virtual ~SharedBitmapManager() {}
- virtual scoped_ptr<SharedBitmap> AllocateSharedBitmap(gfx::Size) = 0;
+ virtual scoped_ptr<SharedBitmap> AllocateSharedBitmap(const gfx::Size&) = 0;
virtual scoped_ptr<SharedBitmap> GetSharedBitmapFromId(
- gfx::Size,
+ const gfx::Size&,
const SharedBitmapId&) = 0;
virtual scoped_ptr<SharedBitmap> GetBitmapForSharedMemory(
base::SharedMemory*) = 0;
diff --git a/chromium/cc/resources/single_release_callback.cc b/chromium/cc/resources/single_release_callback.cc
index 9c6b9de5f07..4565963a59f 100644
--- a/chromium/cc/resources/single_release_callback.cc
+++ b/chromium/cc/resources/single_release_callback.cc
@@ -20,7 +20,7 @@ SingleReleaseCallback::~SingleReleaseCallback() {
<< "SingleReleaseCallback was never run.";
}
-void SingleReleaseCallback::Run(unsigned sync_point, bool is_lost) {
+void SingleReleaseCallback::Run(uint32 sync_point, bool is_lost) {
DCHECK(!has_been_run_) << "SingleReleaseCallback was run more than once.";
has_been_run_ = true;
callback_.Run(sync_point, is_lost);
diff --git a/chromium/cc/resources/single_release_callback.h b/chromium/cc/resources/single_release_callback.h
index fe1a3ba92b4..6f64df629e7 100644
--- a/chromium/cc/resources/single_release_callback.h
+++ b/chromium/cc/resources/single_release_callback.h
@@ -19,7 +19,7 @@ class CC_EXPORT SingleReleaseCallback {
~SingleReleaseCallback();
- void Run(unsigned sync_point, bool is_lost);
+ void Run(uint32 sync_point, bool is_lost);
private:
explicit SingleReleaseCallback(const ReleaseCallback& callback);
diff --git a/chromium/cc/resources/skpicture_content_layer_updater.cc b/chromium/cc/resources/skpicture_content_layer_updater.cc
index 79769bc847c..eb12385f460 100644
--- a/chromium/cc/resources/skpicture_content_layer_updater.cc
+++ b/chromium/cc/resources/skpicture_content_layer_updater.cc
@@ -10,6 +10,7 @@
#include "cc/resources/prioritized_resource.h"
#include "cc/resources/resource_update_queue.h"
#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkPictureRecorder.h"
namespace cc {
@@ -22,17 +23,20 @@ SkPictureContentLayerUpdater::SkPictureContentLayerUpdater(
SkPictureContentLayerUpdater::~SkPictureContentLayerUpdater() {}
void SkPictureContentLayerUpdater::PrepareToUpdate(
- gfx::Rect content_rect,
- gfx::Size,
+ const gfx::Rect& content_rect,
+ const gfx::Size&,
float contents_width_scale,
float contents_height_scale,
gfx::Rect* resulting_opaque_rect) {
- SkCanvas* canvas =
- picture_.beginRecording(content_rect.width(), content_rect.height());
+ SkPictureRecorder recorder;
+ SkCanvas* canvas = recorder.beginRecording(
+ content_rect.width(), content_rect.height(), NULL, 0);
+ DCHECK_EQ(content_rect.width(), canvas->getBaseLayerSize().width());
+ DCHECK_EQ(content_rect.height(), canvas->getBaseLayerSize().height());
base::TimeTicks start_time =
rendering_stats_instrumentation_->StartRecording();
PaintContents(canvas,
- content_rect.origin(),
+ content_rect,
contents_width_scale,
contents_height_scale,
resulting_opaque_rect);
@@ -40,12 +44,13 @@ void SkPictureContentLayerUpdater::PrepareToUpdate(
rendering_stats_instrumentation_->EndRecording(start_time);
rendering_stats_instrumentation_->AddRecord(
duration, content_rect.width() * content_rect.height());
- picture_.endRecording();
+ picture_ = skia::AdoptRef(recorder.endRecording());
}
void SkPictureContentLayerUpdater::DrawPicture(SkCanvas* canvas) {
TRACE_EVENT0("cc", "SkPictureContentLayerUpdater::DrawPicture");
- canvas->drawPicture(picture_);
+ if (picture_)
+ canvas->drawPicture(picture_.get());
}
} // namespace cc
diff --git a/chromium/cc/resources/skpicture_content_layer_updater.h b/chromium/cc/resources/skpicture_content_layer_updater.h
index 511d8ee9bfd..a567976a2d8 100644
--- a/chromium/cc/resources/skpicture_content_layer_updater.h
+++ b/chromium/cc/resources/skpicture_content_layer_updater.h
@@ -6,6 +6,7 @@
#define CC_RESOURCES_SKPICTURE_CONTENT_LAYER_UPDATER_H_
#include "cc/resources/content_layer_updater.h"
+#include "skia/ext/refptr.h"
#include "third_party/skia/include/core/SkPicture.h"
class SkCanvas;
@@ -14,11 +15,8 @@ namespace cc {
class LayerPainter;
-// This class records the content_rect into an SkPicture. Subclasses, provide
-// different implementations of tile updating based on this recorded picture.
-// The BitmapSkPictureContentLayerUpdater and
-// FrameBufferSkPictureContentLayerUpdater are two examples of such
-// implementations.
+// This class records the content_rect into an SkPicture. Subclass provides
+// SkCanvas to DrawPicture() for tile updating based on this recorded picture.
class SkPictureContentLayerUpdater : public ContentLayerUpdater {
protected:
SkPictureContentLayerUpdater(
@@ -27,16 +25,15 @@ class SkPictureContentLayerUpdater : public ContentLayerUpdater {
int layer_id);
virtual ~SkPictureContentLayerUpdater();
- virtual void PrepareToUpdate(gfx::Rect content_rect,
- gfx::Size tile_size,
+ virtual void PrepareToUpdate(const gfx::Rect& content_rect,
+ const gfx::Size& tile_size,
float contents_width_scale,
float contents_height_scale,
gfx::Rect* resulting_opaque_rect) OVERRIDE;
void DrawPicture(SkCanvas* canvas);
private:
- // Recording canvas.
- SkPicture picture_;
+ skia::RefPtr<SkPicture> picture_;
DISALLOW_COPY_AND_ASSIGN(SkPictureContentLayerUpdater);
};
diff --git a/chromium/cc/resources/task_graph_runner.cc b/chromium/cc/resources/task_graph_runner.cc
new file mode 100644
index 00000000000..913c06d9b28
--- /dev/null
+++ b/chromium/cc/resources/task_graph_runner.cc
@@ -0,0 +1,477 @@
+// 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/resources/task_graph_runner.h"
+
+#include <algorithm>
+
+#include "base/debug/trace_event.h"
+#include "base/strings/stringprintf.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace cc {
+namespace {
+
+// Helper class for iterating over all dependents of a task.
+class DependentIterator {
+ public:
+ DependentIterator(TaskGraph* graph, const Task* task)
+ : graph_(graph), task_(task), current_index_(-1), current_node_(NULL) {
+ ++(*this);
+ }
+
+ TaskGraph::Node& operator->() const {
+ DCHECK_LT(current_index_, graph_->edges.size());
+ DCHECK_EQ(graph_->edges[current_index_].task, task_);
+ DCHECK(current_node_);
+ return *current_node_;
+ }
+
+ TaskGraph::Node& operator*() const {
+ DCHECK_LT(current_index_, graph_->edges.size());
+ DCHECK_EQ(graph_->edges[current_index_].task, task_);
+ DCHECK(current_node_);
+ return *current_node_;
+ }
+
+ // Note: Performance can be improved by keeping edges sorted.
+ DependentIterator& operator++() {
+ // Find next dependency edge for |task_|.
+ do {
+ ++current_index_;
+ if (current_index_ == graph_->edges.size())
+ return *this;
+ } while (graph_->edges[current_index_].task != task_);
+
+ // Now find the node for the dependent of this edge.
+ TaskGraph::Node::Vector::iterator it =
+ std::find_if(graph_->nodes.begin(),
+ graph_->nodes.end(),
+ TaskGraph::Node::TaskComparator(
+ graph_->edges[current_index_].dependent));
+ DCHECK(it != graph_->nodes.end());
+ current_node_ = &(*it);
+
+ return *this;
+ }
+
+ operator bool() const { return current_index_ < graph_->edges.size(); }
+
+ private:
+ TaskGraph* graph_;
+ const Task* task_;
+ size_t current_index_;
+ TaskGraph::Node* current_node_;
+};
+
+class DependencyMismatchComparator {
+ public:
+ explicit DependencyMismatchComparator(const TaskGraph* graph)
+ : graph_(graph) {}
+
+ bool operator()(const TaskGraph::Node& node) const {
+ return static_cast<size_t>(std::count_if(graph_->edges.begin(),
+ graph_->edges.end(),
+ DependentComparator(node.task))) !=
+ node.dependencies;
+ }
+
+ private:
+ class DependentComparator {
+ public:
+ explicit DependentComparator(const Task* dependent)
+ : dependent_(dependent) {}
+
+ bool operator()(const TaskGraph::Edge& edge) const {
+ return edge.dependent == dependent_;
+ }
+
+ private:
+ const Task* dependent_;
+ };
+
+ const TaskGraph* graph_;
+};
+
+} // namespace
+
+Task::Task() : will_run_(false), did_run_(false) {
+}
+
+Task::~Task() {
+ DCHECK(!will_run_);
+}
+
+void Task::WillRun() {
+ DCHECK(!will_run_);
+ DCHECK(!did_run_);
+ will_run_ = true;
+}
+
+void Task::DidRun() {
+ DCHECK(will_run_);
+ will_run_ = false;
+ did_run_ = true;
+}
+
+bool Task::HasFinishedRunning() const { return did_run_; }
+
+TaskGraph::TaskGraph() {}
+
+TaskGraph::~TaskGraph() {}
+
+void TaskGraph::Swap(TaskGraph* other) {
+ nodes.swap(other->nodes);
+ edges.swap(other->edges);
+}
+
+void TaskGraph::Reset() {
+ nodes.clear();
+ edges.clear();
+}
+
+TaskGraphRunner::TaskNamespace::TaskNamespace() {}
+
+TaskGraphRunner::TaskNamespace::~TaskNamespace() {}
+
+TaskGraphRunner::TaskGraphRunner()
+ : lock_(),
+ has_ready_to_run_tasks_cv_(&lock_),
+ has_namespaces_with_finished_running_tasks_cv_(&lock_),
+ next_namespace_id_(1),
+ shutdown_(false) {}
+
+TaskGraphRunner::~TaskGraphRunner() {
+ {
+ base::AutoLock lock(lock_);
+
+ DCHECK_EQ(0u, ready_to_run_namespaces_.size());
+ DCHECK_EQ(0u, namespaces_.size());
+ }
+}
+
+NamespaceToken TaskGraphRunner::GetNamespaceToken() {
+ base::AutoLock lock(lock_);
+
+ NamespaceToken token(next_namespace_id_++);
+ DCHECK(namespaces_.find(token.id_) == namespaces_.end());
+ return token;
+}
+
+void TaskGraphRunner::ScheduleTasks(NamespaceToken token, TaskGraph* graph) {
+ TRACE_EVENT2("cc",
+ "TaskGraphRunner::ScheduleTasks",
+ "num_nodes",
+ graph->nodes.size(),
+ "num_edges",
+ graph->edges.size());
+
+ DCHECK(token.IsValid());
+ DCHECK(std::find_if(graph->nodes.begin(),
+ graph->nodes.end(),
+ DependencyMismatchComparator(graph)) ==
+ graph->nodes.end());
+
+ {
+ base::AutoLock lock(lock_);
+
+ DCHECK(!shutdown_);
+
+ TaskNamespace& task_namespace = namespaces_[token.id_];
+
+ // First adjust number of dependencies to reflect completed tasks.
+ for (Task::Vector::iterator it = task_namespace.completed_tasks.begin();
+ it != task_namespace.completed_tasks.end();
+ ++it) {
+ for (DependentIterator node_it(graph, it->get()); node_it; ++node_it) {
+ TaskGraph::Node& node = *node_it;
+ DCHECK_LT(0u, node.dependencies);
+ node.dependencies--;
+ }
+ }
+
+ // Build new "ready to run" queue and remove nodes from old graph.
+ task_namespace.ready_to_run_tasks.clear();
+ for (TaskGraph::Node::Vector::iterator it = graph->nodes.begin();
+ it != graph->nodes.end();
+ ++it) {
+ TaskGraph::Node& node = *it;
+
+ // Remove any old nodes that are associated with this task. The result is
+ // that the old graph is left with all nodes not present in this graph,
+ // which we use below to determine what tasks need to be canceled.
+ TaskGraph::Node::Vector::iterator old_it =
+ std::find_if(task_namespace.graph.nodes.begin(),
+ task_namespace.graph.nodes.end(),
+ TaskGraph::Node::TaskComparator(node.task));
+ if (old_it != task_namespace.graph.nodes.end()) {
+ std::swap(*old_it, task_namespace.graph.nodes.back());
+ task_namespace.graph.nodes.pop_back();
+ }
+
+ // Task is not ready to run if dependencies are not yet satisfied.
+ if (node.dependencies)
+ continue;
+
+ // Skip if already finished running task.
+ if (node.task->HasFinishedRunning())
+ continue;
+
+ // Skip if already running.
+ if (std::find(task_namespace.running_tasks.begin(),
+ task_namespace.running_tasks.end(),
+ node.task) != task_namespace.running_tasks.end())
+ continue;
+
+ task_namespace.ready_to_run_tasks.push_back(
+ PrioritizedTask(node.task, node.priority));
+ }
+
+ // Rearrange the elements in |ready_to_run_tasks| in such a way that they
+ // form a heap.
+ std::make_heap(task_namespace.ready_to_run_tasks.begin(),
+ task_namespace.ready_to_run_tasks.end(),
+ CompareTaskPriority);
+
+ // Swap task graph.
+ task_namespace.graph.Swap(graph);
+
+ // Determine what tasks in old graph need to be canceled.
+ for (TaskGraph::Node::Vector::iterator it = graph->nodes.begin();
+ it != graph->nodes.end();
+ ++it) {
+ TaskGraph::Node& node = *it;
+
+ // Skip if already finished running task.
+ if (node.task->HasFinishedRunning())
+ continue;
+
+ // Skip if already running.
+ if (std::find(task_namespace.running_tasks.begin(),
+ task_namespace.running_tasks.end(),
+ node.task) != task_namespace.running_tasks.end())
+ continue;
+
+ DCHECK(std::find(task_namespace.completed_tasks.begin(),
+ task_namespace.completed_tasks.end(),
+ node.task) == task_namespace.completed_tasks.end());
+ task_namespace.completed_tasks.push_back(node.task);
+ }
+
+ // Build new "ready to run" task namespaces queue.
+ ready_to_run_namespaces_.clear();
+ for (TaskNamespaceMap::iterator it = namespaces_.begin();
+ it != namespaces_.end();
+ ++it) {
+ if (!it->second.ready_to_run_tasks.empty())
+ ready_to_run_namespaces_.push_back(&it->second);
+ }
+
+ // Rearrange the task namespaces in |ready_to_run_namespaces_| in such a way
+ // that they form a heap.
+ std::make_heap(ready_to_run_namespaces_.begin(),
+ ready_to_run_namespaces_.end(),
+ CompareTaskNamespacePriority);
+
+ // If there is more work available, wake up worker thread.
+ if (!ready_to_run_namespaces_.empty())
+ has_ready_to_run_tasks_cv_.Signal();
+ }
+}
+
+void TaskGraphRunner::WaitForTasksToFinishRunning(NamespaceToken token) {
+ TRACE_EVENT0("cc", "TaskGraphRunner::WaitForTasksToFinishRunning");
+
+ DCHECK(token.IsValid());
+
+ {
+ base::AutoLock lock(lock_);
+
+ TaskNamespaceMap::const_iterator it = namespaces_.find(token.id_);
+ if (it == namespaces_.end())
+ return;
+
+ const TaskNamespace& task_namespace = it->second;
+
+ while (!HasFinishedRunningTasksInNamespace(&task_namespace))
+ has_namespaces_with_finished_running_tasks_cv_.Wait();
+
+ // There may be other namespaces that have finished running tasks, so wake
+ // up another origin thread.
+ has_namespaces_with_finished_running_tasks_cv_.Signal();
+ }
+}
+
+void TaskGraphRunner::CollectCompletedTasks(NamespaceToken token,
+ Task::Vector* completed_tasks) {
+ TRACE_EVENT0("cc", "TaskGraphRunner::CollectCompletedTasks");
+
+ DCHECK(token.IsValid());
+
+ {
+ base::AutoLock lock(lock_);
+
+ TaskNamespaceMap::iterator it = namespaces_.find(token.id_);
+ if (it == namespaces_.end())
+ return;
+
+ TaskNamespace& task_namespace = it->second;
+
+ DCHECK_EQ(0u, completed_tasks->size());
+ completed_tasks->swap(task_namespace.completed_tasks);
+ if (!HasFinishedRunningTasksInNamespace(&task_namespace))
+ return;
+
+ // Remove namespace if finished running tasks.
+ DCHECK_EQ(0u, task_namespace.completed_tasks.size());
+ DCHECK_EQ(0u, task_namespace.ready_to_run_tasks.size());
+ DCHECK_EQ(0u, task_namespace.running_tasks.size());
+ namespaces_.erase(it);
+ }
+}
+
+void TaskGraphRunner::Shutdown() {
+ base::AutoLock lock(lock_);
+
+ DCHECK_EQ(0u, ready_to_run_namespaces_.size());
+ DCHECK_EQ(0u, namespaces_.size());
+
+ DCHECK(!shutdown_);
+ shutdown_ = true;
+
+ // Wake up a worker so it knows it should exit. This will cause all workers
+ // to exit as each will wake up another worker before exiting.
+ has_ready_to_run_tasks_cv_.Signal();
+}
+
+void TaskGraphRunner::Run() {
+ base::AutoLock lock(lock_);
+
+ while (true) {
+ if (ready_to_run_namespaces_.empty()) {
+ // Exit when shutdown is set and no more tasks are pending.
+ if (shutdown_)
+ break;
+
+ // Wait for more tasks.
+ has_ready_to_run_tasks_cv_.Wait();
+ continue;
+ }
+
+ RunTaskWithLockAcquired();
+ }
+
+ // We noticed we should exit. Wake up the next worker so it knows it should
+ // exit as well (because the Shutdown() code only signals once).
+ has_ready_to_run_tasks_cv_.Signal();
+}
+
+void TaskGraphRunner::RunUntilIdle() {
+ base::AutoLock lock(lock_);
+
+ while (!ready_to_run_namespaces_.empty())
+ RunTaskWithLockAcquired();
+}
+
+void TaskGraphRunner::RunTaskWithLockAcquired() {
+ TRACE_EVENT0("toplevel", "TaskGraphRunner::RunTask");
+
+ lock_.AssertAcquired();
+ DCHECK(!ready_to_run_namespaces_.empty());
+
+ // Take top priority TaskNamespace from |ready_to_run_namespaces_|.
+ std::pop_heap(ready_to_run_namespaces_.begin(),
+ ready_to_run_namespaces_.end(),
+ CompareTaskNamespacePriority);
+ TaskNamespace* task_namespace = ready_to_run_namespaces_.back();
+ ready_to_run_namespaces_.pop_back();
+ DCHECK(!task_namespace->ready_to_run_tasks.empty());
+
+ // Take top priority task from |ready_to_run_tasks|.
+ std::pop_heap(task_namespace->ready_to_run_tasks.begin(),
+ task_namespace->ready_to_run_tasks.end(),
+ CompareTaskPriority);
+ scoped_refptr<Task> task(task_namespace->ready_to_run_tasks.back().task);
+ task_namespace->ready_to_run_tasks.pop_back();
+
+ // Add task namespace back to |ready_to_run_namespaces_| if not empty after
+ // taking top priority task.
+ if (!task_namespace->ready_to_run_tasks.empty()) {
+ ready_to_run_namespaces_.push_back(task_namespace);
+ std::push_heap(ready_to_run_namespaces_.begin(),
+ ready_to_run_namespaces_.end(),
+ CompareTaskNamespacePriority);
+ }
+
+ // Add task to |running_tasks|.
+ task_namespace->running_tasks.push_back(task.get());
+
+ // There may be more work available, so wake up another worker thread.
+ has_ready_to_run_tasks_cv_.Signal();
+
+ // Call WillRun() before releasing |lock_| and running task.
+ task->WillRun();
+
+ {
+ base::AutoUnlock unlock(lock_);
+
+ task->RunOnWorkerThread();
+ }
+
+ // This will mark task as finished running.
+ task->DidRun();
+
+ // Remove task from |running_tasks|.
+ TaskVector::iterator it = std::find(task_namespace->running_tasks.begin(),
+ task_namespace->running_tasks.end(),
+ task.get());
+ DCHECK(it != task_namespace->running_tasks.end());
+ std::swap(*it, task_namespace->running_tasks.back());
+ task_namespace->running_tasks.pop_back();
+
+ // Now iterate over all dependents to decrement dependencies and check if they
+ // are ready to run.
+ bool ready_to_run_namespaces_has_heap_properties = true;
+ for (DependentIterator it(&task_namespace->graph, task.get()); it; ++it) {
+ TaskGraph::Node& dependent_node = *it;
+
+ DCHECK_LT(0u, dependent_node.dependencies);
+ dependent_node.dependencies--;
+ // Task is ready if it has no dependencies. Add it to |ready_to_run_tasks_|.
+ if (!dependent_node.dependencies) {
+ bool was_empty = task_namespace->ready_to_run_tasks.empty();
+ task_namespace->ready_to_run_tasks.push_back(
+ PrioritizedTask(dependent_node.task, dependent_node.priority));
+ std::push_heap(task_namespace->ready_to_run_tasks.begin(),
+ task_namespace->ready_to_run_tasks.end(),
+ CompareTaskPriority);
+ // Task namespace is ready if it has at least one ready to run task. Add
+ // it to |ready_to_run_namespaces_| if it just become ready.
+ if (was_empty) {
+ DCHECK(std::find(ready_to_run_namespaces_.begin(),
+ ready_to_run_namespaces_.end(),
+ task_namespace) == ready_to_run_namespaces_.end());
+ ready_to_run_namespaces_.push_back(task_namespace);
+ }
+ ready_to_run_namespaces_has_heap_properties = false;
+ }
+ }
+
+ // Rearrange the task namespaces in |ready_to_run_namespaces_| in such a way
+ // that they yet again form a heap.
+ if (!ready_to_run_namespaces_has_heap_properties) {
+ std::make_heap(ready_to_run_namespaces_.begin(),
+ ready_to_run_namespaces_.end(),
+ CompareTaskNamespacePriority);
+ }
+
+ // Finally add task to |completed_tasks_|.
+ task_namespace->completed_tasks.push_back(task);
+
+ // If namespace has finished running all tasks, wake up origin thread.
+ if (HasFinishedRunningTasksInNamespace(task_namespace))
+ has_namespaces_with_finished_running_tasks_cv_.Signal();
+}
+
+} // namespace cc
diff --git a/chromium/cc/resources/task_graph_runner.h b/chromium/cc/resources/task_graph_runner.h
new file mode 100644
index 00000000000..0ed714097ad
--- /dev/null
+++ b/chromium/cc/resources/task_graph_runner.h
@@ -0,0 +1,232 @@
+// 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_RESOURCES_TASK_GRAPH_RUNNER_H_
+#define CC_RESOURCES_TASK_GRAPH_RUNNER_H_
+
+#include <map>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/synchronization/condition_variable.h"
+#include "cc/base/cc_export.h"
+
+namespace cc {
+
+class CC_EXPORT Task : public base::RefCountedThreadSafe<Task> {
+ public:
+ typedef std::vector<scoped_refptr<Task> > Vector;
+
+ virtual void RunOnWorkerThread() = 0;
+
+ void WillRun();
+ void DidRun();
+ bool HasFinishedRunning() const;
+
+ protected:
+ friend class base::RefCountedThreadSafe<Task>;
+
+ Task();
+ virtual ~Task();
+
+ bool will_run_;
+ bool did_run_;
+};
+
+// Dependencies are represented as edges in a task graph. Each graph node is
+// assigned a priority and a run count that matches the number of dependencies.
+// Priority range from 0 (most favorable scheduling) to UINT_MAX (least
+// favorable).
+struct CC_EXPORT TaskGraph {
+ struct Node {
+ class TaskComparator {
+ public:
+ explicit TaskComparator(const Task* task) : task_(task) {}
+
+ bool operator()(const Node& node) const { return node.task == task_; }
+
+ private:
+ const Task* task_;
+ };
+
+ typedef std::vector<Node> Vector;
+
+ Node(Task* task, unsigned priority, size_t dependencies)
+ : task(task), priority(priority), dependencies(dependencies) {}
+
+ Task* task;
+ unsigned priority;
+ size_t dependencies;
+ };
+
+ struct Edge {
+ typedef std::vector<Edge> Vector;
+
+ Edge(const Task* task, Task* dependent)
+ : task(task), dependent(dependent) {}
+
+ const Task* task;
+ Task* dependent;
+ };
+
+ TaskGraph();
+ ~TaskGraph();
+
+ void Swap(TaskGraph* other);
+ void Reset();
+
+ Node::Vector nodes;
+ Edge::Vector edges;
+};
+
+class TaskGraphRunner;
+
+// Opaque identifier that defines a namespace of tasks.
+class CC_EXPORT NamespaceToken {
+ public:
+ NamespaceToken() : id_(0) {}
+ ~NamespaceToken() {}
+
+ bool IsValid() const { return id_ != 0; }
+
+ private:
+ friend class TaskGraphRunner;
+
+ explicit NamespaceToken(int id) : id_(id) {}
+
+ int id_;
+};
+
+// A TaskGraphRunner is used to process tasks with dependencies. There can
+// be any number of TaskGraphRunner instances per thread. Tasks can be scheduled
+// from any thread and they can be run on any thread.
+class CC_EXPORT TaskGraphRunner {
+ public:
+ TaskGraphRunner();
+ virtual ~TaskGraphRunner();
+
+ // Returns a unique token that can be used to pass a task graph to
+ // ScheduleTasks(). Valid tokens are always nonzero.
+ NamespaceToken GetNamespaceToken();
+
+ // Schedule running of tasks in |graph|. Tasks previously scheduled but no
+ // longer needed will be canceled unless already running. Canceled tasks are
+ // moved to |completed_tasks| without being run. The result is that once
+ // scheduled, a task is guaranteed to end up in the |completed_tasks| queue
+ // even if it later gets canceled by another call to ScheduleTasks().
+ void ScheduleTasks(NamespaceToken token, TaskGraph* graph);
+
+ // Wait for all scheduled tasks to finish running.
+ void WaitForTasksToFinishRunning(NamespaceToken token);
+
+ // Collect all completed tasks in |completed_tasks|.
+ void CollectCompletedTasks(NamespaceToken token,
+ Task::Vector* completed_tasks);
+
+ // Run tasks until Shutdown() is called.
+ void Run();
+
+ // Process all pending tasks, but don't wait/sleep. Return as soon as all
+ // tasks that can be run are taken care of.
+ void RunUntilIdle();
+
+ // Signals the Run method to return when it becomes idle. It will continue to
+ // process tasks and future tasks as long as they are scheduled.
+ // Warning: if the TaskGraphRunner remains busy, it may never quit.
+ void Shutdown();
+
+ private:
+ struct PrioritizedTask {
+ typedef std::vector<PrioritizedTask> Vector;
+
+ PrioritizedTask(Task* task, unsigned priority)
+ : task(task), priority(priority) {}
+
+ Task* task;
+ unsigned priority;
+ };
+
+ typedef std::vector<const Task*> TaskVector;
+
+ struct TaskNamespace {
+ typedef std::vector<TaskNamespace*> Vector;
+
+ TaskNamespace();
+ ~TaskNamespace();
+
+ // Current task graph.
+ TaskGraph graph;
+
+ // Ordered set of tasks that are ready to run.
+ PrioritizedTask::Vector ready_to_run_tasks;
+
+ // Completed tasks not yet collected by origin thread.
+ Task::Vector completed_tasks;
+
+ // This set contains all currently running tasks.
+ TaskVector running_tasks;
+ };
+
+ typedef std::map<int, TaskNamespace> TaskNamespaceMap;
+
+ static bool CompareTaskPriority(const PrioritizedTask& a,
+ const PrioritizedTask& b) {
+ // In this system, numerically lower priority is run first.
+ return a.priority > b.priority;
+ }
+
+ static bool CompareTaskNamespacePriority(const TaskNamespace* a,
+ const TaskNamespace* b) {
+ DCHECK(!a->ready_to_run_tasks.empty());
+ DCHECK(!b->ready_to_run_tasks.empty());
+
+ // Compare based on task priority of the ready_to_run_tasks heap .front()
+ // will hold the max element of the heap, except after pop_heap, when max
+ // element is moved to .back().
+ return CompareTaskPriority(a->ready_to_run_tasks.front(),
+ b->ready_to_run_tasks.front());
+ }
+
+ static bool HasFinishedRunningTasksInNamespace(
+ const TaskNamespace* task_namespace) {
+ return task_namespace->running_tasks.empty() &&
+ task_namespace->ready_to_run_tasks.empty();
+ }
+
+ // Run next task. Caller must acquire |lock_| prior to calling this function
+ // and make sure at least one task is ready to run.
+ void RunTaskWithLockAcquired();
+
+ // This lock protects all members of this class. Do not read or modify
+ // anything without holding this lock. Do not block while holding this lock.
+ mutable base::Lock lock_;
+
+ // Condition variable that is waited on by Run() until new tasks are ready to
+ // run or shutdown starts.
+ base::ConditionVariable has_ready_to_run_tasks_cv_;
+
+ // Condition variable that is waited on by origin threads until a namespace
+ // has finished running all associated tasks.
+ base::ConditionVariable has_namespaces_with_finished_running_tasks_cv_;
+
+ // Provides a unique id to each NamespaceToken.
+ int next_namespace_id_;
+
+ // This set contains all namespaces with pending, running or completed tasks
+ // not yet collected.
+ TaskNamespaceMap namespaces_;
+
+ // Ordered set of task namespaces that have ready to run tasks.
+ TaskNamespace::Vector ready_to_run_namespaces_;
+
+ // Set during shutdown. Tells Run() to return when no more tasks are pending.
+ bool shutdown_;
+
+ DISALLOW_COPY_AND_ASSIGN(TaskGraphRunner);
+};
+
+} // namespace cc
+
+#endif // CC_RESOURCES_TASK_GRAPH_RUNNER_H_
diff --git a/chromium/cc/resources/task_graph_runner_perftest.cc b/chromium/cc/resources/task_graph_runner_perftest.cc
new file mode 100644
index 00000000000..bfa4ebe8ac3
--- /dev/null
+++ b/chromium/cc/resources/task_graph_runner_perftest.cc
@@ -0,0 +1,318 @@
+// 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/resources/task_graph_runner.h"
+
+#include <vector>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
+#include "cc/base/completion_event.h"
+#include "cc/debug/lap_timer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/perf/perf_test.h"
+
+namespace cc {
+namespace {
+
+static const int kTimeLimitMillis = 2000;
+static const int kWarmupRuns = 5;
+static const int kTimeCheckInterval = 10;
+
+class PerfTaskImpl : public Task {
+ public:
+ typedef std::vector<scoped_refptr<PerfTaskImpl> > Vector;
+
+ PerfTaskImpl() {}
+
+ // Overridden from Task:
+ virtual void RunOnWorkerThread() OVERRIDE {}
+
+ void Reset() { did_run_ = false; }
+
+ private:
+ virtual ~PerfTaskImpl() {}
+
+ DISALLOW_COPY_AND_ASSIGN(PerfTaskImpl);
+};
+
+class TaskGraphRunnerPerfTest : public testing::Test {
+ public:
+ TaskGraphRunnerPerfTest()
+ : timer_(kWarmupRuns,
+ base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
+ kTimeCheckInterval) {}
+
+ // Overridden from testing::Test:
+ virtual void SetUp() OVERRIDE {
+ task_graph_runner_ = make_scoped_ptr(new TaskGraphRunner);
+ namespace_token_ = task_graph_runner_->GetNamespaceToken();
+ }
+ virtual void TearDown() OVERRIDE { task_graph_runner_.reset(); }
+
+ void AfterTest(const std::string& test_name) {
+ // Format matches chrome/test/perf/perf_test.h:PrintResult
+ printf(
+ "*RESULT %s: %.2f runs/s\n", test_name.c_str(), timer_.LapsPerSecond());
+ }
+
+ void RunBuildTaskGraphTest(const std::string& test_name,
+ int num_top_level_tasks,
+ int num_tasks,
+ int num_leaf_tasks) {
+ PerfTaskImpl::Vector top_level_tasks;
+ PerfTaskImpl::Vector tasks;
+ PerfTaskImpl::Vector leaf_tasks;
+ CreateTasks(num_top_level_tasks, &top_level_tasks);
+ CreateTasks(num_tasks, &tasks);
+ CreateTasks(num_leaf_tasks, &leaf_tasks);
+
+ // Avoid unnecessary heap allocations by reusing the same graph.
+ TaskGraph graph;
+
+ timer_.Reset();
+ do {
+ graph.Reset();
+ BuildTaskGraph(top_level_tasks, tasks, leaf_tasks, &graph);
+ timer_.NextLap();
+ } while (!timer_.HasTimeLimitExpired());
+
+ perf_test::PrintResult("build_task_graph",
+ TestModifierString(),
+ test_name,
+ timer_.LapsPerSecond(),
+ "runs/s",
+ true);
+ }
+
+ void RunScheduleTasksTest(const std::string& test_name,
+ int num_top_level_tasks,
+ int num_tasks,
+ int num_leaf_tasks) {
+ PerfTaskImpl::Vector top_level_tasks;
+ PerfTaskImpl::Vector tasks;
+ PerfTaskImpl::Vector leaf_tasks;
+ CreateTasks(num_top_level_tasks, &top_level_tasks);
+ CreateTasks(num_tasks, &tasks);
+ CreateTasks(num_leaf_tasks, &leaf_tasks);
+
+ // Avoid unnecessary heap allocations by reusing the same graph and
+ // completed tasks vector.
+ TaskGraph graph;
+ Task::Vector completed_tasks;
+
+ timer_.Reset();
+ do {
+ graph.Reset();
+ BuildTaskGraph(top_level_tasks, tasks, leaf_tasks, &graph);
+ task_graph_runner_->ScheduleTasks(namespace_token_, &graph);
+ // Shouldn't be any tasks to collect as we reschedule the same set
+ // of tasks.
+ DCHECK_EQ(0u, CollectCompletedTasks(&completed_tasks));
+ timer_.NextLap();
+ } while (!timer_.HasTimeLimitExpired());
+
+ TaskGraph empty;
+ task_graph_runner_->ScheduleTasks(namespace_token_, &empty);
+ CollectCompletedTasks(&completed_tasks);
+
+ perf_test::PrintResult("schedule_tasks",
+ TestModifierString(),
+ test_name,
+ timer_.LapsPerSecond(),
+ "runs/s",
+ true);
+ }
+
+ void RunScheduleAlternateTasksTest(const std::string& test_name,
+ int num_top_level_tasks,
+ int num_tasks,
+ int num_leaf_tasks) {
+ const size_t kNumVersions = 2;
+ PerfTaskImpl::Vector top_level_tasks[kNumVersions];
+ PerfTaskImpl::Vector tasks[kNumVersions];
+ PerfTaskImpl::Vector leaf_tasks[kNumVersions];
+ for (size_t i = 0; i < kNumVersions; ++i) {
+ CreateTasks(num_top_level_tasks, &top_level_tasks[i]);
+ CreateTasks(num_tasks, &tasks[i]);
+ CreateTasks(num_leaf_tasks, &leaf_tasks[i]);
+ }
+
+ // Avoid unnecessary heap allocations by reusing the same graph and
+ // completed tasks vector.
+ TaskGraph graph;
+ Task::Vector completed_tasks;
+
+ size_t count = 0;
+ timer_.Reset();
+ do {
+ graph.Reset();
+ BuildTaskGraph(top_level_tasks[count % kNumVersions],
+ tasks[count % kNumVersions],
+ leaf_tasks[count % kNumVersions],
+ &graph);
+ task_graph_runner_->ScheduleTasks(namespace_token_, &graph);
+ CollectCompletedTasks(&completed_tasks);
+ completed_tasks.clear();
+ ++count;
+ timer_.NextLap();
+ } while (!timer_.HasTimeLimitExpired());
+
+ TaskGraph empty;
+ task_graph_runner_->ScheduleTasks(namespace_token_, &empty);
+ CollectCompletedTasks(&completed_tasks);
+
+ perf_test::PrintResult("schedule_alternate_tasks",
+ TestModifierString(),
+ test_name,
+ timer_.LapsPerSecond(),
+ "runs/s",
+ true);
+ }
+
+ void RunScheduleAndExecuteTasksTest(const std::string& test_name,
+ int num_top_level_tasks,
+ int num_tasks,
+ int num_leaf_tasks) {
+ PerfTaskImpl::Vector top_level_tasks;
+ PerfTaskImpl::Vector tasks;
+ PerfTaskImpl::Vector leaf_tasks;
+ CreateTasks(num_top_level_tasks, &top_level_tasks);
+ CreateTasks(num_tasks, &tasks);
+ CreateTasks(num_leaf_tasks, &leaf_tasks);
+
+ // Avoid unnecessary heap allocations by reusing the same graph and
+ // completed tasks vector.
+ TaskGraph graph;
+ Task::Vector completed_tasks;
+
+ timer_.Reset();
+ do {
+ graph.Reset();
+ BuildTaskGraph(top_level_tasks, tasks, leaf_tasks, &graph);
+ task_graph_runner_->ScheduleTasks(namespace_token_, &graph);
+ task_graph_runner_->RunUntilIdle();
+ CollectCompletedTasks(&completed_tasks);
+ completed_tasks.clear();
+ ResetTasks(&top_level_tasks);
+ ResetTasks(&tasks);
+ ResetTasks(&leaf_tasks);
+ timer_.NextLap();
+ } while (!timer_.HasTimeLimitExpired());
+
+ perf_test::PrintResult("execute_tasks",
+ TestModifierString(),
+ test_name,
+ timer_.LapsPerSecond(),
+ "runs/s",
+ true);
+ }
+
+ private:
+ static std::string TestModifierString() {
+ return std::string("_task_graph_runner");
+ }
+
+ void CreateTasks(int num_tasks, PerfTaskImpl::Vector* tasks) {
+ for (int i = 0; i < num_tasks; ++i)
+ tasks->push_back(make_scoped_refptr(new PerfTaskImpl));
+ }
+
+ void ResetTasks(PerfTaskImpl::Vector* tasks) {
+ for (PerfTaskImpl::Vector::iterator it = tasks->begin(); it != tasks->end();
+ ++it) {
+ PerfTaskImpl* task = it->get();
+ task->Reset();
+ }
+ }
+
+ void BuildTaskGraph(const PerfTaskImpl::Vector& top_level_tasks,
+ const PerfTaskImpl::Vector& tasks,
+ const PerfTaskImpl::Vector& leaf_tasks,
+ TaskGraph* graph) {
+ DCHECK(graph->nodes.empty());
+ DCHECK(graph->edges.empty());
+
+ for (PerfTaskImpl::Vector::const_iterator it = leaf_tasks.begin();
+ it != leaf_tasks.end();
+ ++it) {
+ graph->nodes.push_back(TaskGraph::Node(it->get(), 0u, 0u));
+ }
+
+ for (PerfTaskImpl::Vector::const_iterator it = tasks.begin();
+ it != tasks.end();
+ ++it) {
+ graph->nodes.push_back(TaskGraph::Node(it->get(), 0u, leaf_tasks.size()));
+
+ for (PerfTaskImpl::Vector::const_iterator leaf_it = leaf_tasks.begin();
+ leaf_it != leaf_tasks.end();
+ ++leaf_it) {
+ graph->edges.push_back(TaskGraph::Edge(leaf_it->get(), it->get()));
+ }
+
+ for (PerfTaskImpl::Vector::const_iterator top_level_it =
+ top_level_tasks.begin();
+ top_level_it != top_level_tasks.end();
+ ++top_level_it) {
+ graph->edges.push_back(TaskGraph::Edge(it->get(), top_level_it->get()));
+ }
+ }
+
+ for (PerfTaskImpl::Vector::const_iterator it = top_level_tasks.begin();
+ it != top_level_tasks.end();
+ ++it) {
+ graph->nodes.push_back(TaskGraph::Node(it->get(), 0u, tasks.size()));
+ }
+ }
+
+ size_t CollectCompletedTasks(Task::Vector* completed_tasks) {
+ DCHECK(completed_tasks->empty());
+ task_graph_runner_->CollectCompletedTasks(namespace_token_,
+ completed_tasks);
+ return completed_tasks->size();
+ }
+
+ scoped_ptr<TaskGraphRunner> task_graph_runner_;
+ NamespaceToken namespace_token_;
+ LapTimer timer_;
+};
+
+TEST_F(TaskGraphRunnerPerfTest, BuildTaskGraph) {
+ RunBuildTaskGraphTest("0_1_0", 0, 1, 0);
+ RunBuildTaskGraphTest("0_32_0", 0, 32, 0);
+ RunBuildTaskGraphTest("2_1_0", 2, 1, 0);
+ RunBuildTaskGraphTest("2_32_0", 2, 32, 0);
+ RunBuildTaskGraphTest("2_1_1", 2, 1, 1);
+ RunBuildTaskGraphTest("2_32_1", 2, 32, 1);
+}
+
+TEST_F(TaskGraphRunnerPerfTest, ScheduleTasks) {
+ RunScheduleTasksTest("0_1_0", 0, 1, 0);
+ RunScheduleTasksTest("0_32_0", 0, 32, 0);
+ RunScheduleTasksTest("2_1_0", 2, 1, 0);
+ RunScheduleTasksTest("2_32_0", 2, 32, 0);
+ RunScheduleTasksTest("2_1_1", 2, 1, 1);
+ RunScheduleTasksTest("2_32_1", 2, 32, 1);
+}
+
+TEST_F(TaskGraphRunnerPerfTest, ScheduleAlternateTasks) {
+ RunScheduleAlternateTasksTest("0_1_0", 0, 1, 0);
+ RunScheduleAlternateTasksTest("0_32_0", 0, 32, 0);
+ RunScheduleAlternateTasksTest("2_1_0", 2, 1, 0);
+ RunScheduleAlternateTasksTest("2_32_0", 2, 32, 0);
+ RunScheduleAlternateTasksTest("2_1_1", 2, 1, 1);
+ RunScheduleAlternateTasksTest("2_32_1", 2, 32, 1);
+}
+
+TEST_F(TaskGraphRunnerPerfTest, ScheduleAndExecuteTasks) {
+ RunScheduleAndExecuteTasksTest("0_1_0", 0, 1, 0);
+ RunScheduleAndExecuteTasksTest("0_32_0", 0, 32, 0);
+ RunScheduleAndExecuteTasksTest("2_1_0", 2, 1, 0);
+ RunScheduleAndExecuteTasksTest("2_32_0", 2, 32, 0);
+ RunScheduleAndExecuteTasksTest("2_1_1", 2, 1, 1);
+ RunScheduleAndExecuteTasksTest("2_32_1", 2, 32, 1);
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/resources/task_graph_runner_unittest.cc b/chromium/cc/resources/task_graph_runner_unittest.cc
new file mode 100644
index 00000000000..1a6256c5835
--- /dev/null
+++ b/chromium/cc/resources/task_graph_runner_unittest.cc
@@ -0,0 +1,331 @@
+// 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/resources/task_graph_runner.h"
+
+#include <vector>
+
+#include "base/bind.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/simple_thread.h"
+#include "cc/base/scoped_ptr_deque.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+namespace {
+
+const int kNamespaceCount = 3;
+
+class TaskGraphRunnerTestBase {
+ public:
+ struct TaskInfo {
+ TaskInfo(int namespace_index,
+ unsigned id,
+ unsigned dependent_id,
+ unsigned dependent_count,
+ unsigned priority)
+ : namespace_index(namespace_index),
+ id(id),
+ dependent_id(dependent_id),
+ dependent_count(dependent_count),
+ priority(priority) {}
+
+ int namespace_index;
+ unsigned id;
+ unsigned dependent_id;
+ unsigned dependent_count;
+ unsigned priority;
+ };
+
+ TaskGraphRunnerTestBase() : task_graph_runner_(new TaskGraphRunner) {}
+
+ void ResetIds(int namespace_index) {
+ run_task_ids_[namespace_index].clear();
+ on_task_completed_ids_[namespace_index].clear();
+ }
+
+ void RunAllTasks(int namespace_index) {
+ task_graph_runner_->WaitForTasksToFinishRunning(
+ namespace_token_[namespace_index]);
+
+ Task::Vector completed_tasks;
+ task_graph_runner_->CollectCompletedTasks(namespace_token_[namespace_index],
+ &completed_tasks);
+ for (Task::Vector::const_iterator it = completed_tasks.begin();
+ it != completed_tasks.end();
+ ++it) {
+ FakeTaskImpl* task = static_cast<FakeTaskImpl*>(it->get());
+ task->CompleteOnOriginThread();
+ }
+ }
+
+ void RunTaskOnWorkerThread(int namespace_index, unsigned id) {
+ base::AutoLock lock(run_task_ids_lock_);
+ run_task_ids_[namespace_index].push_back(id);
+ }
+
+ void OnTaskCompleted(int namespace_index, unsigned id) {
+ on_task_completed_ids_[namespace_index].push_back(id);
+ }
+
+ const std::vector<unsigned>& run_task_ids(int namespace_index) {
+ return run_task_ids_[namespace_index];
+ }
+
+ const std::vector<unsigned>& on_task_completed_ids(int namespace_index) {
+ return on_task_completed_ids_[namespace_index];
+ }
+
+ void ScheduleTasks(int namespace_index, const std::vector<TaskInfo>& tasks) {
+ Task::Vector new_tasks;
+ Task::Vector new_dependents;
+ TaskGraph new_graph;
+
+ for (std::vector<TaskInfo>::const_iterator it = tasks.begin();
+ it != tasks.end();
+ ++it) {
+ scoped_refptr<FakeTaskImpl> new_task(
+ new FakeTaskImpl(this, it->namespace_index, it->id));
+ new_graph.nodes.push_back(
+ TaskGraph::Node(new_task.get(), it->priority, 0u));
+ for (unsigned i = 0; i < it->dependent_count; ++i) {
+ scoped_refptr<FakeDependentTaskImpl> new_dependent_task(
+ new FakeDependentTaskImpl(
+ this, it->namespace_index, it->dependent_id));
+ new_graph.nodes.push_back(
+ TaskGraph::Node(new_dependent_task.get(), it->priority, 1u));
+ new_graph.edges.push_back(
+ TaskGraph::Edge(new_task.get(), new_dependent_task.get()));
+
+ new_dependents.push_back(new_dependent_task.get());
+ }
+
+ new_tasks.push_back(new_task.get());
+ }
+
+ task_graph_runner_->ScheduleTasks(namespace_token_[namespace_index],
+ &new_graph);
+
+ dependents_[namespace_index].swap(new_dependents);
+ tasks_[namespace_index].swap(new_tasks);
+ }
+
+ protected:
+ class FakeTaskImpl : public Task {
+ public:
+ FakeTaskImpl(TaskGraphRunnerTestBase* test, int namespace_index, int id)
+ : test_(test), namespace_index_(namespace_index), id_(id) {}
+
+ // Overridden from Task:
+ virtual void RunOnWorkerThread() OVERRIDE {
+ test_->RunTaskOnWorkerThread(namespace_index_, id_);
+ }
+
+ virtual void CompleteOnOriginThread() {
+ test_->OnTaskCompleted(namespace_index_, id_);
+ }
+
+ protected:
+ virtual ~FakeTaskImpl() {}
+
+ private:
+ TaskGraphRunnerTestBase* test_;
+ int namespace_index_;
+ int id_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakeTaskImpl);
+ };
+
+ class FakeDependentTaskImpl : public FakeTaskImpl {
+ public:
+ FakeDependentTaskImpl(TaskGraphRunnerTestBase* test,
+ int namespace_index,
+ int id)
+ : FakeTaskImpl(test, namespace_index, id) {}
+
+ // Overridden from FakeTaskImpl:
+ virtual void CompleteOnOriginThread() OVERRIDE {}
+
+ private:
+ virtual ~FakeDependentTaskImpl() {}
+
+ DISALLOW_COPY_AND_ASSIGN(FakeDependentTaskImpl);
+ };
+
+ scoped_ptr<TaskGraphRunner> task_graph_runner_;
+ NamespaceToken namespace_token_[kNamespaceCount];
+ Task::Vector tasks_[kNamespaceCount];
+ Task::Vector dependents_[kNamespaceCount];
+ std::vector<unsigned> run_task_ids_[kNamespaceCount];
+ base::Lock run_task_ids_lock_;
+ std::vector<unsigned> on_task_completed_ids_[kNamespaceCount];
+};
+
+class TaskGraphRunnerTest : public TaskGraphRunnerTestBase,
+ public testing::TestWithParam<int>,
+ public base::DelegateSimpleThread::Delegate {
+ public:
+ // Overridden from testing::Test:
+ virtual void SetUp() OVERRIDE {
+ const size_t num_threads = GetParam();
+ while (workers_.size() < num_threads) {
+ scoped_ptr<base::DelegateSimpleThread> worker =
+ make_scoped_ptr(new base::DelegateSimpleThread(this, "TestWorker"));
+ worker->Start();
+ workers_.push_back(worker.Pass());
+ }
+
+ for (int i = 0; i < kNamespaceCount; ++i)
+ namespace_token_[i] = task_graph_runner_->GetNamespaceToken();
+ }
+ virtual void TearDown() OVERRIDE {
+ task_graph_runner_->Shutdown();
+ while (workers_.size()) {
+ scoped_ptr<base::DelegateSimpleThread> worker = workers_.take_front();
+ worker->Join();
+ }
+ }
+
+ private:
+ // Overridden from base::DelegateSimpleThread::Delegate:
+ virtual void Run() OVERRIDE { task_graph_runner_->Run(); }
+
+ ScopedPtrDeque<base::DelegateSimpleThread> workers_;
+};
+
+TEST_P(TaskGraphRunnerTest, Basic) {
+ for (int i = 0; i < kNamespaceCount; ++i) {
+ EXPECT_EQ(0u, run_task_ids(i).size());
+ EXPECT_EQ(0u, on_task_completed_ids(i).size());
+
+ ScheduleTasks(i, std::vector<TaskInfo>(1, TaskInfo(i, 0u, 0u, 0u, 0u)));
+ }
+
+ for (int i = 0; i < kNamespaceCount; ++i) {
+ RunAllTasks(i);
+
+ EXPECT_EQ(1u, run_task_ids(i).size());
+ EXPECT_EQ(1u, on_task_completed_ids(i).size());
+ }
+
+ for (int i = 0; i < kNamespaceCount; ++i)
+ ScheduleTasks(i, std::vector<TaskInfo>(1, TaskInfo(i, 0u, 0u, 1u, 0u)));
+
+ for (int i = 0; i < kNamespaceCount; ++i) {
+ RunAllTasks(i);
+
+ EXPECT_EQ(3u, run_task_ids(i).size());
+ EXPECT_EQ(2u, on_task_completed_ids(i).size());
+ }
+
+ for (int i = 0; i < kNamespaceCount; ++i)
+ ScheduleTasks(i, std::vector<TaskInfo>(1, TaskInfo(i, 0u, 0u, 2u, 0u)));
+
+ for (int i = 0; i < kNamespaceCount; ++i) {
+ RunAllTasks(i);
+
+ EXPECT_EQ(6u, run_task_ids(i).size());
+ EXPECT_EQ(3u, on_task_completed_ids(i).size());
+ }
+}
+
+TEST_P(TaskGraphRunnerTest, Dependencies) {
+ for (int i = 0; i < kNamespaceCount; ++i) {
+ ScheduleTasks(i,
+ std::vector<TaskInfo>(1,
+ TaskInfo(i,
+ 0u,
+ 1u,
+ 1u, // 1 dependent
+ 0u)));
+ }
+
+ for (int i = 0; i < kNamespaceCount; ++i) {
+ RunAllTasks(i);
+
+ // Check if task ran before dependent.
+ ASSERT_EQ(2u, run_task_ids(i).size());
+ EXPECT_EQ(0u, run_task_ids(i)[0]);
+ EXPECT_EQ(1u, run_task_ids(i)[1]);
+ ASSERT_EQ(1u, on_task_completed_ids(i).size());
+ EXPECT_EQ(0u, on_task_completed_ids(i)[0]);
+ }
+
+ for (int i = 0; i < kNamespaceCount; ++i) {
+ ScheduleTasks(i,
+ std::vector<TaskInfo>(1,
+ TaskInfo(i,
+ 2u,
+ 3u,
+ 2u, // 2 dependents
+ 0u)));
+ }
+
+ for (int i = 0; i < kNamespaceCount; ++i) {
+ RunAllTasks(i);
+
+ // Task should only run once.
+ ASSERT_EQ(5u, run_task_ids(i).size());
+ EXPECT_EQ(2u, run_task_ids(i)[2]);
+ EXPECT_EQ(3u, run_task_ids(i)[3]);
+ EXPECT_EQ(3u, run_task_ids(i)[4]);
+ ASSERT_EQ(2u, on_task_completed_ids(i).size());
+ EXPECT_EQ(2u, on_task_completed_ids(i)[1]);
+ }
+}
+
+INSTANTIATE_TEST_CASE_P(TaskGraphRunnerTests,
+ TaskGraphRunnerTest,
+ ::testing::Range(1, 5));
+
+class TaskGraphRunnerSingleThreadTest
+ : public TaskGraphRunnerTestBase,
+ public testing::Test,
+ public base::DelegateSimpleThread::Delegate {
+ public:
+ // Overridden from testing::Test:
+ virtual void SetUp() OVERRIDE {
+ worker_.reset(new base::DelegateSimpleThread(this, "TestWorker"));
+ worker_->Start();
+
+ for (int i = 0; i < kNamespaceCount; ++i)
+ namespace_token_[i] = task_graph_runner_->GetNamespaceToken();
+ }
+ virtual void TearDown() OVERRIDE {
+ task_graph_runner_->Shutdown();
+ worker_->Join();
+ }
+
+ private:
+ // Overridden from base::DelegateSimpleThread::Delegate:
+ virtual void Run() OVERRIDE { task_graph_runner_->Run(); }
+
+ scoped_ptr<base::DelegateSimpleThread> worker_;
+};
+
+TEST_F(TaskGraphRunnerSingleThreadTest, Priority) {
+ for (int i = 0; i < kNamespaceCount; ++i) {
+ TaskInfo tasks[] = {TaskInfo(i, 0u, 2u, 1u, 1u), // Priority 1
+ TaskInfo(i, 1u, 3u, 1u, 0u) // Priority 0
+ };
+ ScheduleTasks(i, std::vector<TaskInfo>(tasks, tasks + arraysize(tasks)));
+ }
+
+ for (int i = 0; i < kNamespaceCount; ++i) {
+ RunAllTasks(i);
+
+ // Check if tasks ran in order of priority.
+ ASSERT_EQ(4u, run_task_ids(i).size());
+ EXPECT_EQ(1u, run_task_ids(i)[0]);
+ EXPECT_EQ(3u, run_task_ids(i)[1]);
+ EXPECT_EQ(0u, run_task_ids(i)[2]);
+ EXPECT_EQ(2u, run_task_ids(i)[3]);
+ ASSERT_EQ(2u, on_task_completed_ids(i).size());
+ EXPECT_EQ(1u, on_task_completed_ids(i)[0]);
+ EXPECT_EQ(0u, on_task_completed_ids(i)[1]);
+ }
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/resources/texture_mailbox.cc b/chromium/cc/resources/texture_mailbox.cc
index 149d56c8d1a..90ce6be79c7 100644
--- a/chromium/cc/resources/texture_mailbox.cc
+++ b/chromium/cc/resources/texture_mailbox.cc
@@ -5,84 +5,55 @@
#include "cc/resources/texture_mailbox.h"
#include "base/logging.h"
+#include "cc/resources/shared_bitmap.h"
#include "third_party/khronos/GLES2/gl2.h"
namespace cc {
-TextureMailbox::TextureMailbox()
- : target_(GL_TEXTURE_2D),
- sync_point_(0),
- shared_memory_(NULL) {
-}
-
-TextureMailbox::TextureMailbox(const std::string& mailbox_name)
- : target_(GL_TEXTURE_2D),
- sync_point_(0),
- shared_memory_(NULL) {
- if (!mailbox_name.empty()) {
- CHECK(mailbox_name.size() == sizeof(name_.name));
- name_.SetName(reinterpret_cast<const int8*>(mailbox_name.data()));
- }
-}
+TextureMailbox::TextureMailbox() : shared_memory_(NULL) {}
-TextureMailbox::TextureMailbox(const gpu::Mailbox& mailbox_name)
- : target_(GL_TEXTURE_2D),
- sync_point_(0),
- shared_memory_(NULL) {
- name_.SetName(mailbox_name.name);
-}
-
-TextureMailbox::TextureMailbox(const gpu::Mailbox& mailbox_name,
- unsigned sync_point)
- : target_(GL_TEXTURE_2D),
- sync_point_(sync_point),
- shared_memory_(NULL) {
- name_.SetName(mailbox_name.name);
-}
+TextureMailbox::TextureMailbox(const gpu::MailboxHolder& mailbox_holder)
+ : mailbox_holder_(mailbox_holder),
+ shared_memory_(NULL),
+ allow_overlay_(false) {}
-TextureMailbox::TextureMailbox(const gpu::Mailbox& mailbox_name,
- unsigned texture_target,
- unsigned sync_point)
- : target_(texture_target),
- sync_point_(sync_point),
- shared_memory_(NULL) {
- name_.SetName(mailbox_name.name);
-}
+TextureMailbox::TextureMailbox(const gpu::Mailbox& mailbox,
+ uint32 target,
+ uint32 sync_point)
+ : mailbox_holder_(mailbox, target, sync_point),
+ shared_memory_(NULL),
+ allow_overlay_(false) {}
TextureMailbox::TextureMailbox(base::SharedMemory* shared_memory,
- gfx::Size size)
- : target_(GL_TEXTURE_2D),
- sync_point_(0),
- shared_memory_(shared_memory),
- shared_memory_size_(size) {}
+ const gfx::Size& size)
+ : shared_memory_(shared_memory),
+ shared_memory_size_(size),
+ allow_overlay_(false) {
+ // If an embedder of cc gives an invalid TextureMailbox, we should crash
+ // here to identify the offender.
+ CHECK(SharedBitmap::VerifySizeInBytes(shared_memory_size_));
+}
TextureMailbox::~TextureMailbox() {}
bool TextureMailbox::Equals(const TextureMailbox& other) const {
- if (other.IsTexture())
- return ContainsMailbox(other.name());
- else if (other.IsSharedMemory())
- return ContainsHandle(other.shared_memory_->handle());
+ if (other.IsTexture()) {
+ return IsTexture() && !memcmp(mailbox_holder_.mailbox.name,
+ other.mailbox_holder_.mailbox.name,
+ sizeof(mailbox_holder_.mailbox.name));
+ } else if (other.IsSharedMemory()) {
+ return IsSharedMemory() &&
+ shared_memory_->handle() == other.shared_memory_->handle();
+ }
DCHECK(!other.IsValid());
return !IsValid();
}
-bool TextureMailbox::ContainsMailbox(const gpu::Mailbox& other) const {
- return IsTexture() && !memcmp(data(), other.name, sizeof(name_.name));
-}
-
-bool TextureMailbox::ContainsHandle(base::SharedMemoryHandle handle) const {
- return shared_memory_ && shared_memory_->handle() == handle;
-}
-
-void TextureMailbox::SetName(const gpu::Mailbox& name) {
- DCHECK(shared_memory_ == NULL);
- name_ = name;
-}
-
-size_t TextureMailbox::shared_memory_size_in_bytes() const {
- return 4 * shared_memory_size_.GetArea();
+size_t TextureMailbox::SharedMemorySizeInBytes() const {
+ // UncheckedSizeInBytes is okay because we VerifySizeInBytes in the
+ // constructor and the field is immutable.
+ return SharedBitmap::UncheckedSizeInBytes(shared_memory_size_);
}
} // namespace cc
diff --git a/chromium/cc/resources/texture_mailbox.h b/chromium/cc/resources/texture_mailbox.h
index a9b021b2390..4626dd36698 100644
--- a/chromium/cc/resources/texture_mailbox.h
+++ b/chromium/cc/resources/texture_mailbox.h
@@ -10,7 +10,7 @@
#include "base/callback.h"
#include "base/memory/shared_memory.h"
#include "cc/base/cc_export.h"
-#include "gpu/command_buffer/common/mailbox.h"
+#include "gpu/command_buffer/common/mailbox_holder.h"
#include "ui/gfx/size.h"
namespace cc {
@@ -20,46 +20,38 @@ namespace cc {
class CC_EXPORT TextureMailbox {
public:
TextureMailbox();
- explicit TextureMailbox(const std::string& mailbox_name);
- explicit TextureMailbox(const gpu::Mailbox& mailbox_name);
- TextureMailbox(const gpu::Mailbox& mailbox_name,
- unsigned sync_point);
- TextureMailbox(const gpu::Mailbox& mailbox_name,
- unsigned texture_target,
- unsigned sync_point);
- TextureMailbox(base::SharedMemory* shared_memory,
- gfx::Size size);
+ explicit TextureMailbox(const gpu::MailboxHolder& mailbox_holder);
+ TextureMailbox(const gpu::Mailbox& mailbox, uint32 target, uint32 sync_point);
+ TextureMailbox(base::SharedMemory* shared_memory, const gfx::Size& size);
~TextureMailbox();
bool IsValid() const { return IsTexture() || IsSharedMemory(); }
- bool IsTexture() const { return !name_.IsZero(); }
+ bool IsTexture() const { return !mailbox_holder_.mailbox.IsZero(); }
bool IsSharedMemory() const { return shared_memory_ != NULL; }
bool Equals(const TextureMailbox&) const;
- bool ContainsMailbox(const gpu::Mailbox&) const;
- bool ContainsHandle(base::SharedMemoryHandle handle) const;
- const int8* data() const { return name_.name; }
- const gpu::Mailbox& name() const { return name_; }
- void ResetSyncPoint() { sync_point_ = 0; }
- unsigned target() const { return target_; }
- unsigned sync_point() const { return sync_point_; }
+ const gpu::Mailbox& mailbox() const { return mailbox_holder_.mailbox; }
+ const int8* name() const { return mailbox().name; }
+ uint32 target() const { return mailbox_holder_.texture_target; }
+ uint32 sync_point() const { return mailbox_holder_.sync_point; }
+ void set_sync_point(int32 sync_point) {
+ mailbox_holder_.sync_point = sync_point;
+ }
+
+ bool allow_overlay() const { return allow_overlay_; }
+ void set_allow_overlay(bool allow_overlay) { allow_overlay_ = allow_overlay; }
base::SharedMemory* shared_memory() const { return shared_memory_; }
gfx::Size shared_memory_size() const { return shared_memory_size_; }
- size_t shared_memory_size_in_bytes() const;
-
- // TODO(danakj): ReleaseCallback should be separate from this class, and stop
- // storing a TextureMailbox in ResourceProvider. Then we can remove this.
- void SetName(const gpu::Mailbox& name);
+ size_t SharedMemorySizeInBytes() const;
private:
- gpu::Mailbox name_;
- unsigned target_;
- unsigned sync_point_;
+ gpu::MailboxHolder mailbox_holder_;
base::SharedMemory* shared_memory_;
gfx::Size shared_memory_size_;
+ bool allow_overlay_;
};
} // namespace cc
diff --git a/chromium/cc/resources/texture_mailbox_deleter.cc b/chromium/cc/resources/texture_mailbox_deleter.cc
index cf7b3b6107f..ab863684e81 100644
--- a/chromium/cc/resources/texture_mailbox_deleter.cc
+++ b/chromium/cc/resources/texture_mailbox_deleter.cc
@@ -7,7 +7,7 @@
#include "base/bind.h"
#include "base/location.h"
#include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
#include "cc/output/context_provider.h"
#include "cc/resources/single_release_callback.h"
#include "gpu/command_buffer/client/gles2_interface.h"
@@ -17,7 +17,7 @@ namespace cc {
static void DeleteTextureOnImplThread(
const scoped_refptr<ContextProvider>& context_provider,
unsigned texture_id,
- unsigned sync_point,
+ uint32 sync_point,
bool is_lost) {
if (sync_point)
context_provider->ContextGL()->WaitSyncPointCHROMIUM(sync_point);
@@ -34,7 +34,9 @@ static void PostTaskFromMainToImplThread(
FROM_HERE, base::Bind(run_impl_callback, sync_point, is_lost));
}
-TextureMailboxDeleter::TextureMailboxDeleter() : weak_ptr_factory_(this) {}
+TextureMailboxDeleter::TextureMailboxDeleter(
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner)
+ : impl_task_runner_(task_runner), weak_ptr_factory_(this) {}
TextureMailboxDeleter::~TextureMailboxDeleter() {
for (size_t i = 0; i < impl_callbacks_.size(); ++i)
@@ -65,9 +67,7 @@ scoped_ptr<SingleReleaseCallback> TextureMailboxDeleter::GetReleaseCallback(
// thread.
scoped_ptr<SingleReleaseCallback> main_callback =
SingleReleaseCallback::Create(base::Bind(
- &PostTaskFromMainToImplThread,
- base::MessageLoopProxy::current(),
- run_impl_callback));
+ &PostTaskFromMainToImplThread, impl_task_runner_, run_impl_callback));
return main_callback.Pass();
}
diff --git a/chromium/cc/resources/texture_mailbox_deleter.h b/chromium/cc/resources/texture_mailbox_deleter.h
index 9b6d771c0f5..ca0bc0032ca 100644
--- a/chromium/cc/resources/texture_mailbox_deleter.h
+++ b/chromium/cc/resources/texture_mailbox_deleter.h
@@ -9,13 +9,18 @@
#include "cc/base/cc_export.h"
#include "cc/base/scoped_ptr_vector.h"
+namespace base {
+class SingleThreadTaskRunner;
+}
+
namespace cc {
class ContextProvider;
class SingleReleaseCallback;
class CC_EXPORT TextureMailboxDeleter {
public:
- TextureMailboxDeleter();
+ explicit TextureMailboxDeleter(
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
~TextureMailboxDeleter();
// Returns a Callback that can be used as the ReleaseCallback for a
@@ -32,11 +37,11 @@ class CC_EXPORT TextureMailboxDeleter {
private:
// Runs the |impl_callback| to delete the texture and removes the callback
// from the |impl_callbacks_| list.
- void RunDeleteTextureOnImplThread(
- SingleReleaseCallback* impl_callback,
- unsigned sync_point,
- bool is_lost);
+ void RunDeleteTextureOnImplThread(SingleReleaseCallback* impl_callback,
+ uint32 sync_point,
+ bool is_lost);
+ scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner_;
ScopedPtrVector<SingleReleaseCallback> impl_callbacks_;
base::WeakPtrFactory<TextureMailboxDeleter> weak_ptr_factory_;
};
diff --git a/chromium/cc/resources/texture_mailbox_deleter_unittest.cc b/chromium/cc/resources/texture_mailbox_deleter_unittest.cc
index d08da84af90..0d04c9917f0 100644
--- a/chromium/cc/resources/texture_mailbox_deleter_unittest.cc
+++ b/chromium/cc/resources/texture_mailbox_deleter_unittest.cc
@@ -4,6 +4,7 @@
#include "cc/resources/texture_mailbox_deleter.h"
+#include "base/message_loop/message_loop_proxy.h"
#include "cc/resources/single_release_callback.h"
#include "cc/test/test_context_provider.h"
#include "cc/test/test_web_graphics_context_3d.h"
@@ -13,13 +14,15 @@ namespace cc {
namespace {
TEST(TextureMailboxDeleterTest, Destroy) {
- scoped_ptr<TextureMailboxDeleter> deleter(new TextureMailboxDeleter);
+ scoped_ptr<TextureMailboxDeleter> deleter(
+ new TextureMailboxDeleter(base::MessageLoopProxy::current()));
scoped_refptr<TestContextProvider> context_provider =
TestContextProvider::Create();
context_provider->BindToCurrentThread();
- unsigned texture_id = context_provider->Context3d()->createTexture();
+ GLuint texture_id = 0u;
+ context_provider->ContextGL()->GenTextures(1, &texture_id);
EXPECT_TRUE(context_provider->HasOneRef());
EXPECT_EQ(1u, context_provider->TestContext3d()->NumTextures());
diff --git a/chromium/cc/scheduler/texture_uploader.cc b/chromium/cc/resources/texture_uploader.cc
index 6758f11de2d..eb4e6c097a4 100644
--- a/chromium/cc/scheduler/texture_uploader.cc
+++ b/chromium/cc/resources/texture_uploader.cc
@@ -1,8 +1,8 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
+// 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/scheduler/texture_uploader.h"
+#include "cc/resources/texture_uploader.h"
#include <algorithm>
#include <vector>
@@ -129,11 +129,11 @@ void TextureUploader::EndQuery() {
}
void TextureUploader::Upload(const uint8* image,
- gfx::Rect image_rect,
- gfx::Rect source_rect,
+ const gfx::Rect& image_rect,
+ const gfx::Rect& source_rect,
gfx::Vector2d dest_offset,
ResourceFormat format,
- gfx::Size size) {
+ const gfx::Size& size) {
CHECK(image_rect.Contains(source_rect));
bool is_full_upload = dest_offset.IsZero() && source_rect.size() == size;
@@ -173,8 +173,8 @@ void TextureUploader::ReleaseCachedQueries() {
}
void TextureUploader::UploadWithTexSubImage(const uint8* image,
- gfx::Rect image_rect,
- gfx::Rect source_rect,
+ const gfx::Rect& image_rect,
+ const gfx::Rect& source_rect,
gfx::Vector2d dest_offset,
ResourceFormat format) {
TRACE_EVENT0("cc", "TextureUploader::UploadWithTexSubImage");
@@ -227,8 +227,8 @@ void TextureUploader::UploadWithTexSubImage(const uint8* image,
}
void TextureUploader::UploadWithMapTexSubImage(const uint8* image,
- gfx::Rect image_rect,
- gfx::Rect source_rect,
+ const gfx::Rect& image_rect,
+ const gfx::Rect& source_rect,
gfx::Vector2d dest_offset,
ResourceFormat format) {
TRACE_EVENT0("cc", "TextureUploader::UploadWithMapTexSubImage");
@@ -287,7 +287,7 @@ void TextureUploader::UploadWithMapTexSubImage(const uint8* image,
}
void TextureUploader::UploadWithTexImageETC1(const uint8* image,
- gfx::Size size) {
+ const gfx::Size& size) {
TRACE_EVENT0("cc", "TextureUploader::UploadWithTexImageETC1");
DCHECK_EQ(0, size.width() % 4);
DCHECK_EQ(0, size.height() % 4);
diff --git a/chromium/cc/scheduler/texture_uploader.h b/chromium/cc/resources/texture_uploader.h
index 815282e2c4b..72c46e7ffb5 100644
--- a/chromium/cc/scheduler/texture_uploader.h
+++ b/chromium/cc/resources/texture_uploader.h
@@ -1,9 +1,9 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
+// 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_SCHEDULER_TEXTURE_UPLOADER_H_
-#define CC_SCHEDULER_TEXTURE_UPLOADER_H_
+#ifndef CC_RESOURCES_TEXTURE_UPLOADER_H_
+#define CC_RESOURCES_TEXTURE_UPLOADER_H_
#include <set>
@@ -43,11 +43,11 @@ class CC_EXPORT TextureUploader {
// image be a buffer for content_rect. This function will copy the region
// corresponding to source_rect to dest_offset in this sub-image.
void Upload(const uint8* image,
- gfx::Rect content_rect,
- gfx::Rect source_rect,
+ const gfx::Rect& content_rect,
+ const gfx::Rect& source_rect,
gfx::Vector2d dest_offset,
ResourceFormat format,
- gfx::Size size);
+ const gfx::Size& size);
void Flush();
void ReleaseCachedQueries();
@@ -66,12 +66,8 @@ class CC_EXPORT TextureUploader {
bool IsPending();
unsigned Value();
size_t TexturesUploaded();
- void mark_as_non_blocking() {
- is_non_blocking_ = true;
- }
- bool is_non_blocking() const {
- return is_non_blocking_;
- }
+ void mark_as_non_blocking() { is_non_blocking_ = true; }
+ bool is_non_blocking() const { return is_non_blocking_; }
private:
explicit Query(gpu::gles2::GLES2Interface* gl);
@@ -92,16 +88,16 @@ class CC_EXPORT TextureUploader {
void ProcessQueries();
void UploadWithTexSubImage(const uint8* image,
- gfx::Rect image_rect,
- gfx::Rect source_rect,
+ const gfx::Rect& image_rect,
+ const gfx::Rect& source_rect,
gfx::Vector2d dest_offset,
ResourceFormat format);
void UploadWithMapTexSubImage(const uint8* image,
- gfx::Rect image_rect,
- gfx::Rect source_rect,
+ const gfx::Rect& image_rect,
+ const gfx::Rect& source_rect,
gfx::Vector2d dest_offset,
ResourceFormat format);
- void UploadWithTexImageETC1(const uint8* image, gfx::Size size);
+ void UploadWithTexImageETC1(const uint8* image, const gfx::Size& size);
gpu::gles2::GLES2Interface* gl_;
ScopedPtrDeque<Query> pending_queries_;
@@ -119,4 +115,4 @@ class CC_EXPORT TextureUploader {
} // namespace cc
-#endif // CC_SCHEDULER_TEXTURE_UPLOADER_H_
+#endif // CC_RESOURCES_TEXTURE_UPLOADER_H_
diff --git a/chromium/cc/scheduler/texture_uploader_unittest.cc b/chromium/cc/resources/texture_uploader_unittest.cc
index 792216cf081..8390b28ceef 100644
--- a/chromium/cc/scheduler/texture_uploader_unittest.cc
+++ b/chromium/cc/resources/texture_uploader_unittest.cc
@@ -1,8 +1,8 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
+// 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/scheduler/texture_uploader.h"
+#include "cc/resources/texture_uploader.h"
#include "cc/base/util.h"
#include "cc/resources/prioritized_resource.h"
@@ -145,14 +145,10 @@ class TextureUploadTestContext : public gpu::gles2::GLES2InterfaceStub {
void UploadTexture(TextureUploader* uploader,
ResourceFormat format,
- gfx::Size size,
+ const gfx::Size& size,
const uint8* data) {
- uploader->Upload(data,
- gfx::Rect(size),
- gfx::Rect(size),
- gfx::Vector2d(),
- format,
- size);
+ uploader->Upload(
+ data, gfx::Rect(size), gfx::Rect(size), gfx::Vector2d(), format, size);
}
TEST(TextureUploaderTest, NumBlockingUploads) {
diff --git a/chromium/cc/resources/tile.cc b/chromium/cc/resources/tile.cc
index 209780679cb..d59dc029ccc 100644
--- a/chromium/cc/resources/tile.cc
+++ b/chromium/cc/resources/tile.cc
@@ -4,6 +4,8 @@
#include "cc/resources/tile.h"
+#include <algorithm>
+
#include "cc/base/math_util.h"
#include "cc/debug/traced_value.h"
#include "cc/resources/tile_manager.h"
@@ -15,23 +17,23 @@ Tile::Id Tile::s_next_id_ = 0;
Tile::Tile(TileManager* tile_manager,
PicturePileImpl* picture_pile,
- gfx::Size tile_size,
- gfx::Rect content_rect,
- gfx::Rect opaque_rect,
+ const gfx::Size& tile_size,
+ const gfx::Rect& content_rect,
+ const gfx::Rect& opaque_rect,
float contents_scale,
int layer_id,
int source_frame_number,
int flags)
- : RefCountedManaged<Tile>(tile_manager),
- tile_manager_(tile_manager),
- tile_size_(tile_size),
- content_rect_(content_rect),
- contents_scale_(contents_scale),
- opaque_rect_(opaque_rect),
- layer_id_(layer_id),
- source_frame_number_(source_frame_number),
- flags_(flags),
- id_(s_next_id_++) {
+ : RefCountedManaged<Tile>(tile_manager),
+ tile_manager_(tile_manager),
+ tile_size_(tile_size),
+ content_rect_(content_rect),
+ contents_scale_(contents_scale),
+ opaque_rect_(opaque_rect),
+ layer_id_(layer_id),
+ source_frame_number_(source_frame_number),
+ flags_(flags),
+ id_(s_next_id_++) {
set_picture_pile(picture_pile);
}
@@ -69,8 +71,7 @@ scoped_ptr<base::Value> Tile::AsValue() const {
res->Set("active_priority", priority_[ACTIVE_TREE].AsValue().release());
res->Set("pending_priority", priority_[PENDING_TREE].AsValue().release());
res->Set("managed_state", managed_state_.AsValue().release());
- res->SetBoolean("can_use_lcd_text", can_use_lcd_text());
- res->SetBoolean("use_gpu_rasterization", use_gpu_rasterization());
+ res->SetBoolean("use_picture_analysis", use_picture_analysis());
return res.PassAs<base::Value>();
}
@@ -81,4 +82,21 @@ size_t Tile::GPUMemoryUsageInBytes() const {
return total_size;
}
+RasterMode Tile::DetermineRasterModeForTree(WhichTree tree) const {
+ return DetermineRasterModeForResolution(priority(tree).resolution);
+}
+
+RasterMode Tile::DetermineOverallRasterMode() const {
+ return DetermineRasterModeForResolution(managed_state_.resolution);
+}
+
+RasterMode Tile::DetermineRasterModeForResolution(
+ TileResolution resolution) const {
+ RasterMode current_mode = managed_state_.raster_mode;
+ RasterMode raster_mode = resolution == LOW_RESOLUTION
+ ? LOW_QUALITY_RASTER_MODE
+ : HIGH_QUALITY_RASTER_MODE;
+ return std::min(raster_mode, current_mode);
+}
+
} // namespace cc
diff --git a/chromium/cc/resources/tile.h b/chromium/cc/resources/tile.h
index e7c96360fe5..69ef56fde8c 100644
--- a/chromium/cc/resources/tile.h
+++ b/chromium/cc/resources/tile.h
@@ -10,6 +10,7 @@
#include "base/memory/scoped_vector.h"
#include "cc/base/ref_counted_managed.h"
#include "cc/resources/managed_tile_state.h"
+#include "cc/resources/picture_pile_impl.h"
#include "cc/resources/raster_mode.h"
#include "cc/resources/tile_priority.h"
#include "ui/gfx/rect.h"
@@ -17,14 +18,9 @@
namespace cc {
-class PicturePileImpl;
-
class CC_EXPORT Tile : public RefCountedManaged<Tile> {
public:
- enum TileRasterFlags {
- USE_LCD_TEXT = 1 << 0,
- USE_GPU_RASTERIZATION = 1 << 1
- };
+ enum TileRasterFlags { USE_PICTURE_ANALYSIS = 1 << 0 };
typedef uint64 Id;
@@ -44,6 +40,19 @@ class CC_EXPORT Tile : public RefCountedManaged<Tile> {
return priority_[tree];
}
+ TilePriority priority_for_tree_priority(TreePriority tree_priority) const {
+ switch (tree_priority) {
+ case SMOOTHNESS_TAKES_PRIORITY:
+ return priority_[ACTIVE_TREE];
+ case NEW_CONTENT_TAKES_PRIORITY:
+ return priority_[PENDING_TREE];
+ case SAME_PRIORITY_FOR_BOTH_TREES:
+ return combined_priority();
+ }
+ NOTREACHED();
+ return TilePriority();
+ }
+
TilePriority combined_priority() const {
return TilePriority(priority_[ACTIVE_TREE],
priority_[PENDING_TREE]);
@@ -57,26 +66,20 @@ class CC_EXPORT Tile : public RefCountedManaged<Tile> {
return priority_[PENDING_TREE].required_for_activation;
}
- void set_can_use_lcd_text(bool can_use_lcd_text) {
- if (can_use_lcd_text)
- flags_ |= USE_LCD_TEXT;
- else
- flags_ &= ~USE_LCD_TEXT;
+ bool use_picture_analysis() const {
+ return !!(flags_ & USE_PICTURE_ANALYSIS);
}
- bool can_use_lcd_text() const {
- return !!(flags_ & USE_LCD_TEXT);
+ bool NeedsRasterForMode(RasterMode mode) const {
+ return !managed_state_.tile_versions[mode].IsReadyToDraw();
}
- void set_use_gpu_rasterization(bool use_gpu_rasterization) {
- if (use_gpu_rasterization)
- flags_ |= USE_GPU_RASTERIZATION;
- else
- flags_ &= ~USE_GPU_RASTERIZATION;
- }
-
- bool use_gpu_rasterization() const {
- return !!(flags_ & USE_GPU_RASTERIZATION);
+ bool HasResources() const {
+ for (int mode = 0; mode < NUM_RASTER_MODES; ++mode) {
+ if (managed_state_.tile_versions[mode].has_resource())
+ return true;
+ }
+ return false;
}
scoped_ptr<base::Value> AsValue() const;
@@ -98,10 +101,6 @@ class CC_EXPORT Tile : public RefCountedManaged<Tile> {
}
gfx::Rect opaque_rect() const { return opaque_rect_; }
- bool has_text(RasterMode mode) const {
- return managed_state_.tile_versions[mode].has_text_;
- }
-
float contents_scale() const { return contents_scale_; }
gfx::Rect content_rect() const { return content_rect_; }
@@ -116,6 +115,12 @@ class CC_EXPORT Tile : public RefCountedManaged<Tile> {
size_t GPUMemoryUsageInBytes() const;
+ gfx::Size size() const { return tile_size_.size(); }
+
+ RasterMode DetermineRasterModeForTree(WhichTree tree) const;
+ RasterMode DetermineOverallRasterMode() const;
+
+ // Functionality used in tests.
RasterMode GetRasterModeForTesting() const {
return managed_state().raster_mode;
}
@@ -123,8 +128,6 @@ class CC_EXPORT Tile : public RefCountedManaged<Tile> {
return managed_state_.tile_versions[mode];
}
- gfx::Size size() const { return tile_size_.size(); }
-
private:
friend class TileManager;
friend class PrioritizedTileSet;
@@ -135,9 +138,9 @@ class CC_EXPORT Tile : public RefCountedManaged<Tile> {
// Methods called by by tile manager.
Tile(TileManager* tile_manager,
PicturePileImpl* picture_pile,
- gfx::Size tile_size,
- gfx::Rect content_rect,
- gfx::Rect opaque_rect,
+ const gfx::Size& tile_size,
+ const gfx::Rect& content_rect,
+ const gfx::Rect& opaque_rect,
float contents_scale,
int layer_id,
int source_frame_number,
@@ -146,6 +149,7 @@ class CC_EXPORT Tile : public RefCountedManaged<Tile> {
ManagedTileState& managed_state() { return managed_state_; }
const ManagedTileState& managed_state() const { return managed_state_; }
+ RasterMode DetermineRasterModeForResolution(TileResolution resolution) const;
TileManager* tile_manager_;
scoped_refptr<PicturePileImpl> picture_pile_;
diff --git a/chromium/cc/resources/tile_manager.cc b/chromium/cc/resources/tile_manager.cc
index 2fbb6d18913..d508f6a0a17 100644
--- a/chromium/cc/resources/tile_manager.cc
+++ b/chromium/cc/resources/tile_manager.cc
@@ -12,148 +12,329 @@
#include "base/json/json_writer.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
+#include "cc/debug/devtools_instrumentation.h"
+#include "cc/debug/frame_viewer_instrumentation.h"
#include "cc/debug/traced_value.h"
-#include "cc/resources/image_raster_worker_pool.h"
-#include "cc/resources/pixel_buffer_raster_worker_pool.h"
+#include "cc/layers/picture_layer_impl.h"
+#include "cc/resources/raster_worker_pool.h"
#include "cc/resources/tile.h"
-#include "third_party/skia/include/core/SkCanvas.h"
+#include "skia/ext/paint_simplifier.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "third_party/skia/include/core/SkPixelRef.h"
#include "ui/gfx/rect_conversions.h"
namespace cc {
-
namespace {
-// Memory limit policy works by mapping some bin states to the NEVER bin.
-const ManagedTileBin kBinPolicyMap[NUM_TILE_MEMORY_LIMIT_POLICIES][NUM_BINS] = {
- { // [ALLOW_NOTHING]
- NEVER_BIN, // [NOW_AND_READY_TO_DRAW_BIN]
- NEVER_BIN, // [NOW_BIN]
- NEVER_BIN, // [SOON_BIN]
- NEVER_BIN, // [EVENTUALLY_AND_ACTIVE_BIN]
- NEVER_BIN, // [EVENTUALLY_BIN]
- NEVER_BIN, // [AT_LAST_AND_ACTIVE_BIN]
- NEVER_BIN, // [AT_LAST_BIN]
- NEVER_BIN
- }, { // [ALLOW_ABSOLUTE_MINIMUM]
- NOW_AND_READY_TO_DRAW_BIN,
- NOW_BIN,
- NEVER_BIN, // [SOON_BIN]
- NEVER_BIN, // [EVENTUALLY_AND_ACTIVE_BIN]
- NEVER_BIN, // [EVENTUALLY_BIN]
- NEVER_BIN, // [AT_LAST_AND_ACTIVE_BIN]
- NEVER_BIN, // [AT_LAST_BIN]
- NEVER_BIN
- }, { // [ALLOW_PREPAINT_ONLY]
- NOW_AND_READY_TO_DRAW_BIN,
- NOW_BIN,
- SOON_BIN,
- NEVER_BIN, // [EVENTUALLY_AND_ACTIVE_BIN]
- NEVER_BIN, // [EVENTUALLY_BIN]
- NEVER_BIN, // [AT_LAST_AND_ACTIVE_BIN]
- NEVER_BIN, // [AT_LAST_BIN]
- NEVER_BIN
- }, { // [ALLOW_ANYTHING]
- NOW_AND_READY_TO_DRAW_BIN,
- NOW_BIN,
- SOON_BIN,
- EVENTUALLY_AND_ACTIVE_BIN,
- EVENTUALLY_BIN,
- AT_LAST_AND_ACTIVE_BIN,
- AT_LAST_BIN,
- NEVER_BIN
+// Flag to indicate whether we should try and detect that
+// a tile is of solid color.
+const bool kUseColorEstimator = true;
+
+class RasterTaskImpl : public RasterTask {
+ public:
+ RasterTaskImpl(
+ const Resource* resource,
+ PicturePileImpl* picture_pile,
+ const gfx::Rect& content_rect,
+ float contents_scale,
+ RasterMode raster_mode,
+ TileResolution tile_resolution,
+ int layer_id,
+ const void* tile_id,
+ int source_frame_number,
+ bool analyze_picture,
+ RenderingStatsInstrumentation* rendering_stats,
+ const base::Callback<void(const PicturePileImpl::Analysis&, bool)>& reply,
+ ImageDecodeTask::Vector* dependencies)
+ : RasterTask(resource, dependencies),
+ picture_pile_(picture_pile),
+ content_rect_(content_rect),
+ contents_scale_(contents_scale),
+ raster_mode_(raster_mode),
+ tile_resolution_(tile_resolution),
+ layer_id_(layer_id),
+ tile_id_(tile_id),
+ source_frame_number_(source_frame_number),
+ analyze_picture_(analyze_picture),
+ rendering_stats_(rendering_stats),
+ reply_(reply),
+ canvas_(NULL) {}
+
+ // Overridden from Task:
+ virtual void RunOnWorkerThread() OVERRIDE {
+ TRACE_EVENT0("cc", "RasterizerTaskImpl::RunOnWorkerThread");
+
+ DCHECK(picture_pile_);
+ if (canvas_) {
+ AnalyzeAndRaster(picture_pile_->GetCloneForDrawingOnThread(
+ RasterWorkerPool::GetPictureCloneIndexForCurrentThread()));
+ }
+ }
+
+ // Overridden from RasterizerTask:
+ virtual void ScheduleOnOriginThread(RasterizerTaskClient* client) OVERRIDE {
+ DCHECK(!canvas_);
+ canvas_ = client->AcquireCanvasForRaster(this);
+ }
+ virtual void CompleteOnOriginThread(RasterizerTaskClient* client) OVERRIDE {
+ canvas_ = NULL;
+ client->ReleaseCanvasForRaster(this);
+ }
+ virtual void RunReplyOnOriginThread() OVERRIDE {
+ DCHECK(!canvas_);
+ reply_.Run(analysis_, !HasFinishedRunning());
+ }
+
+ protected:
+ virtual ~RasterTaskImpl() { DCHECK(!canvas_); }
+
+ private:
+ void AnalyzeAndRaster(PicturePileImpl* picture_pile) {
+ DCHECK(picture_pile);
+ DCHECK(canvas_);
+
+ if (analyze_picture_) {
+ Analyze(picture_pile);
+ if (analysis_.is_solid_color)
+ return;
+ }
+
+ Raster(picture_pile);
+ }
+
+ void Analyze(PicturePileImpl* picture_pile) {
+ frame_viewer_instrumentation::ScopedAnalyzeTask analyze_task(
+ tile_id_, tile_resolution_, source_frame_number_, layer_id_);
+
+ DCHECK(picture_pile);
+
+ picture_pile->AnalyzeInRect(
+ content_rect_, contents_scale_, &analysis_, rendering_stats_);
+
+ // Record the solid color prediction.
+ UMA_HISTOGRAM_BOOLEAN("Renderer4.SolidColorTilesAnalyzed",
+ analysis_.is_solid_color);
+
+ // Clear the flag if we're not using the estimator.
+ analysis_.is_solid_color &= kUseColorEstimator;
+ }
+
+ void Raster(PicturePileImpl* picture_pile) {
+ frame_viewer_instrumentation::ScopedRasterTask raster_task(
+ tile_id_,
+ tile_resolution_,
+ source_frame_number_,
+ layer_id_,
+ raster_mode_);
+ devtools_instrumentation::ScopedLayerTask layer_task(
+ devtools_instrumentation::kRasterTask, layer_id_);
+
+ skia::RefPtr<SkDrawFilter> draw_filter;
+ switch (raster_mode_) {
+ case LOW_QUALITY_RASTER_MODE:
+ draw_filter = skia::AdoptRef(new skia::PaintSimplifier);
+ break;
+ case HIGH_QUALITY_RASTER_MODE:
+ break;
+ case NUM_RASTER_MODES:
+ default:
+ NOTREACHED();
+ }
+ canvas_->setDrawFilter(draw_filter.get());
+
+ base::TimeDelta prev_rasterize_time =
+ rendering_stats_->impl_thread_rendering_stats().rasterize_time;
+
+ // Only record rasterization time for highres tiles, because
+ // lowres tiles are not required for activation and therefore
+ // introduce noise in the measurement (sometimes they get rasterized
+ // before we draw and sometimes they aren't)
+ RenderingStatsInstrumentation* stats =
+ tile_resolution_ == HIGH_RESOLUTION ? rendering_stats_ : NULL;
+ DCHECK(picture_pile);
+ picture_pile->RasterToBitmap(
+ canvas_, content_rect_, contents_scale_, stats);
+
+ if (rendering_stats_->record_rendering_stats()) {
+ base::TimeDelta current_rasterize_time =
+ rendering_stats_->impl_thread_rendering_stats().rasterize_time;
+ HISTOGRAM_CUSTOM_COUNTS(
+ "Renderer4.PictureRasterTimeUS",
+ (current_rasterize_time - prev_rasterize_time).InMicroseconds(),
+ 0,
+ 100000,
+ 100);
+ }
}
+
+ PicturePileImpl::Analysis analysis_;
+ scoped_refptr<PicturePileImpl> picture_pile_;
+ gfx::Rect content_rect_;
+ float contents_scale_;
+ RasterMode raster_mode_;
+ TileResolution tile_resolution_;
+ int layer_id_;
+ const void* tile_id_;
+ int source_frame_number_;
+ bool analyze_picture_;
+ RenderingStatsInstrumentation* rendering_stats_;
+ const base::Callback<void(const PicturePileImpl::Analysis&, bool)> reply_;
+ SkCanvas* canvas_;
+
+ DISALLOW_COPY_AND_ASSIGN(RasterTaskImpl);
};
-// Ready to draw works by mapping NOW_BIN to NOW_AND_READY_TO_DRAW_BIN.
-const ManagedTileBin kBinReadyToDrawMap[2][NUM_BINS] = {
- { // Not ready
- NOW_AND_READY_TO_DRAW_BIN,
- NOW_BIN,
- SOON_BIN,
- EVENTUALLY_AND_ACTIVE_BIN,
- EVENTUALLY_BIN,
- AT_LAST_AND_ACTIVE_BIN,
- AT_LAST_BIN,
- NEVER_BIN
- }, { // Ready
- NOW_AND_READY_TO_DRAW_BIN,
- NOW_AND_READY_TO_DRAW_BIN, // [NOW_BIN]
- SOON_BIN,
- EVENTUALLY_AND_ACTIVE_BIN,
- EVENTUALLY_BIN,
- AT_LAST_AND_ACTIVE_BIN,
- AT_LAST_BIN,
- NEVER_BIN
+class ImageDecodeTaskImpl : public ImageDecodeTask {
+ public:
+ ImageDecodeTaskImpl(SkPixelRef* pixel_ref,
+ int layer_id,
+ RenderingStatsInstrumentation* rendering_stats,
+ const base::Callback<void(bool was_canceled)>& reply)
+ : pixel_ref_(skia::SharePtr(pixel_ref)),
+ layer_id_(layer_id),
+ rendering_stats_(rendering_stats),
+ reply_(reply) {}
+
+ // Overridden from Task:
+ virtual void RunOnWorkerThread() OVERRIDE {
+ TRACE_EVENT0("cc", "ImageDecodeTaskImpl::RunOnWorkerThread");
+
+ devtools_instrumentation::ScopedImageDecodeTask image_decode_task(
+ pixel_ref_.get());
+ // This will cause the image referred to by pixel ref to be decoded.
+ pixel_ref_->lockPixels();
+ pixel_ref_->unlockPixels();
}
+
+ // Overridden from RasterizerTask:
+ virtual void ScheduleOnOriginThread(RasterizerTaskClient* client) OVERRIDE {}
+ virtual void CompleteOnOriginThread(RasterizerTaskClient* client) OVERRIDE {}
+ virtual void RunReplyOnOriginThread() OVERRIDE {
+ reply_.Run(!HasFinishedRunning());
+ }
+
+ protected:
+ virtual ~ImageDecodeTaskImpl() {}
+
+ private:
+ skia::RefPtr<SkPixelRef> pixel_ref_;
+ int layer_id_;
+ RenderingStatsInstrumentation* rendering_stats_;
+ const base::Callback<void(bool was_canceled)> reply_;
+
+ DISALLOW_COPY_AND_ASSIGN(ImageDecodeTaskImpl);
};
+const size_t kScheduledRasterTasksLimit = 32u;
+
+// Memory limit policy works by mapping some bin states to the NEVER bin.
+const ManagedTileBin kBinPolicyMap[NUM_TILE_MEMORY_LIMIT_POLICIES][NUM_BINS] = {
+ // [ALLOW_NOTHING]
+ {NEVER_BIN, // [NOW_AND_READY_TO_DRAW_BIN]
+ NEVER_BIN, // [NOW_BIN]
+ NEVER_BIN, // [SOON_BIN]
+ NEVER_BIN, // [EVENTUALLY_AND_ACTIVE_BIN]
+ NEVER_BIN, // [EVENTUALLY_BIN]
+ NEVER_BIN, // [AT_LAST_AND_ACTIVE_BIN]
+ NEVER_BIN, // [AT_LAST_BIN]
+ NEVER_BIN // [NEVER_BIN]
+ },
+ // [ALLOW_ABSOLUTE_MINIMUM]
+ {NOW_AND_READY_TO_DRAW_BIN, // [NOW_AND_READY_TO_DRAW_BIN]
+ NOW_BIN, // [NOW_BIN]
+ NEVER_BIN, // [SOON_BIN]
+ NEVER_BIN, // [EVENTUALLY_AND_ACTIVE_BIN]
+ NEVER_BIN, // [EVENTUALLY_BIN]
+ NEVER_BIN, // [AT_LAST_AND_ACTIVE_BIN]
+ NEVER_BIN, // [AT_LAST_BIN]
+ NEVER_BIN // [NEVER_BIN]
+ },
+ // [ALLOW_PREPAINT_ONLY]
+ {NOW_AND_READY_TO_DRAW_BIN, // [NOW_AND_READY_TO_DRAW_BIN]
+ NOW_BIN, // [NOW_BIN]
+ SOON_BIN, // [SOON_BIN]
+ NEVER_BIN, // [EVENTUALLY_AND_ACTIVE_BIN]
+ NEVER_BIN, // [EVENTUALLY_BIN]
+ NEVER_BIN, // [AT_LAST_AND_ACTIVE_BIN]
+ NEVER_BIN, // [AT_LAST_BIN]
+ NEVER_BIN // [NEVER_BIN]
+ },
+ // [ALLOW_ANYTHING]
+ {NOW_AND_READY_TO_DRAW_BIN, // [NOW_AND_READY_TO_DRAW_BIN]
+ NOW_BIN, // [NOW_BIN]
+ SOON_BIN, // [SOON_BIN]
+ EVENTUALLY_AND_ACTIVE_BIN, // [EVENTUALLY_AND_ACTIVE_BIN]
+ EVENTUALLY_BIN, // [EVENTUALLY_BIN]
+ AT_LAST_AND_ACTIVE_BIN, // [AT_LAST_AND_ACTIVE_BIN]
+ AT_LAST_BIN, // [AT_LAST_BIN]
+ NEVER_BIN // [NEVER_BIN]
+ }};
+
+// Ready to draw works by mapping NOW_BIN to NOW_AND_READY_TO_DRAW_BIN.
+const ManagedTileBin kBinReadyToDrawMap[2][NUM_BINS] = {
+ // Not ready
+ {NOW_AND_READY_TO_DRAW_BIN, // [NOW_AND_READY_TO_DRAW_BIN]
+ NOW_BIN, // [NOW_BIN]
+ SOON_BIN, // [SOON_BIN]
+ EVENTUALLY_AND_ACTIVE_BIN, // [EVENTUALLY_AND_ACTIVE_BIN]
+ EVENTUALLY_BIN, // [EVENTUALLY_BIN]
+ AT_LAST_AND_ACTIVE_BIN, // [AT_LAST_AND_ACTIVE_BIN]
+ AT_LAST_BIN, // [AT_LAST_BIN]
+ NEVER_BIN // [NEVER_BIN]
+ },
+ // Ready
+ {NOW_AND_READY_TO_DRAW_BIN, // [NOW_AND_READY_TO_DRAW_BIN]
+ NOW_AND_READY_TO_DRAW_BIN, // [NOW_BIN]
+ SOON_BIN, // [SOON_BIN]
+ EVENTUALLY_AND_ACTIVE_BIN, // [EVENTUALLY_AND_ACTIVE_BIN]
+ EVENTUALLY_BIN, // [EVENTUALLY_BIN]
+ AT_LAST_AND_ACTIVE_BIN, // [AT_LAST_AND_ACTIVE_BIN]
+ AT_LAST_BIN, // [AT_LAST_BIN]
+ NEVER_BIN // [NEVER_BIN]
+ }};
+
// Active works by mapping some bin stats to equivalent _ACTIVE_BIN state.
const ManagedTileBin kBinIsActiveMap[2][NUM_BINS] = {
- { // Inactive
- NOW_AND_READY_TO_DRAW_BIN,
- NOW_BIN,
- SOON_BIN,
- EVENTUALLY_AND_ACTIVE_BIN,
- EVENTUALLY_BIN,
- AT_LAST_AND_ACTIVE_BIN,
- AT_LAST_BIN,
- NEVER_BIN
- }, { // Active
- NOW_AND_READY_TO_DRAW_BIN,
- NOW_BIN,
- SOON_BIN,
- EVENTUALLY_AND_ACTIVE_BIN,
- EVENTUALLY_AND_ACTIVE_BIN, // [EVENTUALLY_BIN]
- AT_LAST_AND_ACTIVE_BIN,
- AT_LAST_AND_ACTIVE_BIN, // [AT_LAST_BIN]
- NEVER_BIN
- }
-};
+ // Inactive
+ {NOW_AND_READY_TO_DRAW_BIN, // [NOW_AND_READY_TO_DRAW_BIN]
+ NOW_BIN, // [NOW_BIN]
+ SOON_BIN, // [SOON_BIN]
+ EVENTUALLY_AND_ACTIVE_BIN, // [EVENTUALLY_AND_ACTIVE_BIN]
+ EVENTUALLY_BIN, // [EVENTUALLY_BIN]
+ AT_LAST_AND_ACTIVE_BIN, // [AT_LAST_AND_ACTIVE_BIN]
+ AT_LAST_BIN, // [AT_LAST_BIN]
+ NEVER_BIN // [NEVER_BIN]
+ },
+ // Active
+ {NOW_AND_READY_TO_DRAW_BIN, // [NOW_AND_READY_TO_DRAW_BIN]
+ NOW_BIN, // [NOW_BIN]
+ SOON_BIN, // [SOON_BIN]
+ EVENTUALLY_AND_ACTIVE_BIN, // [EVENTUALLY_AND_ACTIVE_BIN]
+ EVENTUALLY_AND_ACTIVE_BIN, // [EVENTUALLY_BIN]
+ AT_LAST_AND_ACTIVE_BIN, // [AT_LAST_AND_ACTIVE_BIN]
+ AT_LAST_AND_ACTIVE_BIN, // [AT_LAST_BIN]
+ NEVER_BIN // [NEVER_BIN]
+ }};
// Determine bin based on three categories of tiles: things we need now,
// things we need soon, and eventually.
inline ManagedTileBin BinFromTilePriority(const TilePriority& prio) {
- // The amount of time/pixels for which we want to have prepainting coverage.
- // Note: All very arbitrary constants: metric-based tuning is welcome!
- const float kPrepaintingWindowTimeSeconds = 1.0f;
- const float kBackflingGuardDistancePixels = 314.0f;
- // Note: The max distances here assume that SOON_BIN will never help overcome
- // raster being too slow (only caching in advance will do that), so we just
- // need enough padding to handle some latency and per-tile variability.
- const float kMaxPrepaintingDistancePixelsHighRes = 2000.0f;
- const float kMaxPrepaintingDistancePixelsLowRes = 4000.0f;
-
- if (prio.distance_to_visible_in_pixels ==
- std::numeric_limits<float>::infinity())
- return NEVER_BIN;
-
- if (prio.time_to_visible_in_seconds == 0)
+ if (prio.priority_bin == TilePriority::NOW)
return NOW_BIN;
- if (prio.resolution == NON_IDEAL_RESOLUTION)
- return EVENTUALLY_BIN;
-
- float max_prepainting_distance_pixels =
- (prio.resolution == HIGH_RESOLUTION)
- ? kMaxPrepaintingDistancePixelsHighRes
- : kMaxPrepaintingDistancePixelsLowRes;
-
- // Soon bin if we are within backfling-guard, or under both the time window
- // and the max distance window.
- if (prio.distance_to_visible_in_pixels < kBackflingGuardDistancePixels ||
- (prio.time_to_visible_in_seconds < kPrepaintingWindowTimeSeconds &&
- prio.distance_to_visible_in_pixels <= max_prepainting_distance_pixels))
+ if (prio.priority_bin == TilePriority::SOON)
return SOON_BIN;
+ if (prio.distance_to_visible == std::numeric_limits<float>::infinity())
+ return NEVER_BIN;
+
return EVENTUALLY_BIN;
}
} // namespace
RasterTaskCompletionStats::RasterTaskCompletionStats()
- : completed_count(0u),
- canceled_count(0u) {
-}
+ : completed_count(0u), canceled_count(0u) {}
scoped_ptr<base::Value> RasterTaskCompletionStatsAsValue(
const RasterTaskCompletionStats& stats) {
@@ -166,56 +347,41 @@ scoped_ptr<base::Value> RasterTaskCompletionStatsAsValue(
// static
scoped_ptr<TileManager> TileManager::Create(
TileManagerClient* client,
- ResourceProvider* resource_provider,
- size_t num_raster_threads,
- RenderingStatsInstrumentation* rendering_stats_instrumentation,
- bool use_map_image,
- size_t max_transfer_buffer_usage_bytes,
- size_t max_raster_usage_bytes,
- GLenum map_image_texture_target) {
- return make_scoped_ptr(
- new TileManager(client,
- resource_provider,
- use_map_image ?
- ImageRasterWorkerPool::Create(
- resource_provider,
- num_raster_threads,
- map_image_texture_target) :
- PixelBufferRasterWorkerPool::Create(
- resource_provider,
- num_raster_threads,
- max_transfer_buffer_usage_bytes),
- num_raster_threads,
- max_raster_usage_bytes,
- rendering_stats_instrumentation));
+ base::SequencedTaskRunner* task_runner,
+ ResourcePool* resource_pool,
+ Rasterizer* rasterizer,
+ RenderingStatsInstrumentation* rendering_stats_instrumentation) {
+ return make_scoped_ptr(new TileManager(client,
+ task_runner,
+ resource_pool,
+ rasterizer,
+ rendering_stats_instrumentation));
}
TileManager::TileManager(
TileManagerClient* client,
- ResourceProvider* resource_provider,
- scoped_ptr<RasterWorkerPool> raster_worker_pool,
- size_t num_raster_threads,
- size_t max_raster_usage_bytes,
+ base::SequencedTaskRunner* task_runner,
+ ResourcePool* resource_pool,
+ Rasterizer* rasterizer,
RenderingStatsInstrumentation* rendering_stats_instrumentation)
: client_(client),
- resource_pool_(ResourcePool::Create(
- resource_provider,
- raster_worker_pool->GetResourceTarget(),
- raster_worker_pool->GetResourceFormat())),
- raster_worker_pool_(raster_worker_pool.Pass()),
+ task_runner_(task_runner),
+ resource_pool_(resource_pool),
+ rasterizer_(rasterizer),
prioritized_tiles_dirty_(false),
all_tiles_that_need_to_be_rasterized_have_memory_(true),
all_tiles_required_for_activation_have_memory_(true),
- memory_required_bytes_(0),
- memory_nice_to_have_bytes_(0),
bytes_releasable_(0),
resources_releasable_(0),
- max_raster_usage_bytes_(max_raster_usage_bytes),
ever_exceeded_memory_budget_(false),
rendering_stats_instrumentation_(rendering_stats_instrumentation),
did_initialize_visible_tile_(false),
- did_check_for_completed_tasks_since_last_schedule_tasks_(true) {
- raster_worker_pool_->SetClient(this);
+ did_check_for_completed_tasks_since_last_schedule_tasks_(true),
+ ready_to_activate_check_notifier_(
+ task_runner_,
+ base::Bind(&TileManager::CheckIfReadyToActivate,
+ base::Unretained(this))) {
+ rasterizer_->SetClient(this);
}
TileManager::~TileManager() {
@@ -226,13 +392,14 @@ TileManager::~TileManager() {
CleanUpReleasedTiles();
DCHECK_EQ(0u, tiles_.size());
- RasterWorkerPool::RasterTask::Queue empty;
- raster_worker_pool_->ScheduleTasks(&empty);
+ RasterTaskQueue empty;
+ rasterizer_->ScheduleTasks(&empty);
+ orphan_raster_tasks_.clear();
// This should finish all pending tasks and release any uninitialized
// resources.
- raster_worker_pool_->Shutdown();
- raster_worker_pool_->CheckForCompletedTasks();
+ rasterizer_->Shutdown();
+ rasterizer_->CheckForCompletedTasks();
DCHECK_EQ(0u, bytes_releasable_);
DCHECK_EQ(0u, resources_releasable_);
@@ -256,8 +423,12 @@ void TileManager::CleanUpReleasedTiles() {
it != released_tiles_.end();
++it) {
Tile* tile = *it;
+ ManagedTileState& mts = tile->managed_state();
- FreeResourcesForTile(tile);
+ for (int mode = 0; mode < NUM_RASTER_MODES; ++mode) {
+ FreeResourceForTile(tile, static_cast<RasterMode>(mode));
+ orphan_raster_tasks_.push_back(mts.tile_versions[mode].raster_task_);
+ }
DCHECK(tiles_.find(tile->id()) != tiles_.end());
tiles_.erase(tile->id());
@@ -290,12 +461,16 @@ void TileManager::UpdatePrioritizedTileSetIfNeeded() {
void TileManager::DidFinishRunningTasks() {
TRACE_EVENT0("cc", "TileManager::DidFinishRunningTasks");
+ bool memory_usage_above_limit = resource_pool_->total_memory_usage_bytes() >
+ global_state_.soft_memory_limit_in_bytes;
+
// When OOM, keep re-assigning memory until we reach a steady state
// where top-priority tiles are initialized.
- if (all_tiles_that_need_to_be_rasterized_have_memory_)
+ if (all_tiles_that_need_to_be_rasterized_have_memory_ &&
+ !memory_usage_above_limit)
return;
- raster_worker_pool_->CheckForCompletedTasks();
+ rasterizer_->CheckForCompletedTasks();
did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
TileVector tiles_that_need_to_be_rasterized;
@@ -309,6 +484,8 @@ void TileManager::DidFinishRunningTasks() {
return;
}
+ resource_pool_->ReduceResourceUsage();
+
// We don't reserve memory for required-for-activation tiles during
// accelerated gestures, so we just postpone activation when we don't
// have these tiles, and activate after the accelerated gesture.
@@ -328,11 +505,14 @@ void TileManager::DidFinishRunningTasks() {
// If we can't raster on demand, give up early (and don't activate).
if (!allow_rasterize_on_demand)
return;
+
tile_version.set_rasterize_on_demand();
+ client_->NotifyTileStateChanged(tile);
}
}
- client_->NotifyReadyToActivate();
+ DCHECK(IsReadyToActivate());
+ ready_to_activate_check_notifier_.Schedule();
}
void TileManager::DidFinishRunningTasksRequiredForActivation() {
@@ -344,16 +524,12 @@ void TileManager::DidFinishRunningTasksRequiredForActivation() {
if (!all_tiles_required_for_activation_have_memory_)
return;
- client_->NotifyReadyToActivate();
+ ready_to_activate_check_notifier_.Schedule();
}
void TileManager::GetTilesWithAssignedBins(PrioritizedTileSet* tiles) {
TRACE_EVENT0("cc", "TileManager::GetTilesWithAssignedBins");
- // Compute new stats to be return by GetMemoryStats().
- memory_required_bytes_ = 0;
- memory_nice_to_have_bytes_ = 0;
-
const TileMemoryLimitPolicy memory_policy = global_state_.memory_limit_policy;
const TreePriority tree_priority = global_state_.tree_priority;
@@ -365,9 +541,8 @@ void TileManager::GetTilesWithAssignedBins(PrioritizedTileSet* tiles) {
const ManagedTileState::TileVersion& tile_version =
tile->GetTileVersionForDrawing();
bool tile_is_ready_to_draw = tile_version.IsReadyToDraw();
- bool tile_is_active =
- tile_is_ready_to_draw ||
- !mts.tile_versions[mts.raster_mode].raster_task_.is_null();
+ bool tile_is_active = tile_is_ready_to_draw ||
+ mts.tile_versions[mts.raster_mode].raster_task_;
// Get the active priority and bin.
TilePriority active_priority = tile->priority(ACTIVE_TREE);
@@ -377,19 +552,12 @@ void TileManager::GetTilesWithAssignedBins(PrioritizedTileSet* tiles) {
TilePriority pending_priority = tile->priority(PENDING_TREE);
ManagedTileBin pending_bin = BinFromTilePriority(pending_priority);
- bool pending_is_low_res =
- pending_priority.resolution == LOW_RESOLUTION;
+ bool pending_is_low_res = pending_priority.resolution == LOW_RESOLUTION;
bool pending_is_non_ideal =
pending_priority.resolution == NON_IDEAL_RESOLUTION;
bool active_is_non_ideal =
active_priority.resolution == NON_IDEAL_RESOLUTION;
- // Adjust pending bin state for low res tiles. This prevents
- // pending tree low-res tiles from being initialized before
- // high-res tiles.
- if (pending_is_low_res)
- pending_bin = std::max(pending_bin, EVENTUALLY_BIN);
-
// Adjust bin state based on if ready to draw.
active_bin = kBinReadyToDrawMap[tile_is_ready_to_draw][active_bin];
pending_bin = kBinReadyToDrawMap[tile_is_ready_to_draw][pending_bin];
@@ -405,79 +573,66 @@ void TileManager::GetTilesWithAssignedBins(PrioritizedTileSet* tiles) {
if (!tile_is_ready_to_draw && pending_is_non_ideal)
pending_bin = NEVER_BIN;
- // Compute combined bin.
- ManagedTileBin combined_bin = std::min(active_bin, pending_bin);
-
ManagedTileBin tree_bin[NUM_TREES];
tree_bin[ACTIVE_TREE] = kBinPolicyMap[memory_policy][active_bin];
tree_bin[PENDING_TREE] = kBinPolicyMap[memory_policy][pending_bin];
- // The bin that the tile would have if the GPU memory manager had
- // a maximally permissive policy, send to the GPU memory manager
- // to determine policy.
- ManagedTileBin gpu_memmgr_stats_bin = NEVER_BIN;
- TilePriority tile_priority;
+ // Adjust pending bin state for low res tiles. This prevents pending tree
+ // low-res tiles from being initialized before high-res tiles.
+ if (pending_is_low_res)
+ tree_bin[PENDING_TREE] = std::max(tree_bin[PENDING_TREE], EVENTUALLY_BIN);
+ TilePriority tile_priority;
switch (tree_priority) {
case SAME_PRIORITY_FOR_BOTH_TREES:
- mts.bin = kBinPolicyMap[memory_policy][combined_bin];
- gpu_memmgr_stats_bin = combined_bin;
+ mts.bin = std::min(tree_bin[ACTIVE_TREE], tree_bin[PENDING_TREE]);
tile_priority = tile->combined_priority();
break;
case SMOOTHNESS_TAKES_PRIORITY:
mts.bin = tree_bin[ACTIVE_TREE];
- gpu_memmgr_stats_bin = active_bin;
tile_priority = active_priority;
break;
case NEW_CONTENT_TAKES_PRIORITY:
mts.bin = tree_bin[PENDING_TREE];
- gpu_memmgr_stats_bin = pending_bin;
tile_priority = pending_priority;
break;
}
- if (!tile_is_ready_to_draw || tile_version.requires_resource()) {
- if ((gpu_memmgr_stats_bin == NOW_BIN) ||
- (gpu_memmgr_stats_bin == NOW_AND_READY_TO_DRAW_BIN))
- memory_required_bytes_ += BytesConsumedIfAllocated(tile);
- if (gpu_memmgr_stats_bin != NEVER_BIN)
- memory_nice_to_have_bytes_ += BytesConsumedIfAllocated(tile);
- }
-
// Bump up the priority if we determined it's NEVER_BIN on one tree,
// but is still required on the other tree.
- bool is_in_never_bin_on_both_trees =
- tree_bin[ACTIVE_TREE] == NEVER_BIN &&
- tree_bin[PENDING_TREE] == NEVER_BIN;
+ bool is_in_never_bin_on_both_trees = tree_bin[ACTIVE_TREE] == NEVER_BIN &&
+ tree_bin[PENDING_TREE] == NEVER_BIN;
if (mts.bin == NEVER_BIN && !is_in_never_bin_on_both_trees)
mts.bin = tile_is_active ? AT_LAST_AND_ACTIVE_BIN : AT_LAST_BIN;
mts.resolution = tile_priority.resolution;
- mts.time_to_needed_in_seconds = tile_priority.time_to_visible_in_seconds;
- mts.distance_to_visible_in_pixels =
- tile_priority.distance_to_visible_in_pixels;
+ mts.priority_bin = tile_priority.priority_bin;
+ mts.distance_to_visible = tile_priority.distance_to_visible;
mts.required_for_activation = tile_priority.required_for_activation;
mts.visible_and_ready_to_draw =
tree_bin[ACTIVE_TREE] == NOW_AND_READY_TO_DRAW_BIN;
- if (mts.bin == NEVER_BIN) {
- FreeResourcesForTile(tile);
+ // Tiles that are required for activation shouldn't be in NEVER_BIN unless
+ // smoothness takes priority or memory policy allows nothing to be
+ // initialized.
+ DCHECK(!mts.required_for_activation || mts.bin != NEVER_BIN ||
+ tree_priority == SMOOTHNESS_TAKES_PRIORITY ||
+ memory_policy == ALLOW_NOTHING);
+
+ // If the tile is in NEVER_BIN and it does not have an active task, then we
+ // can release the resources early. If it does have the task however, we
+ // should keep it in the prioritized tile set to ensure that AssignGpuMemory
+ // can visit it.
+ if (mts.bin == NEVER_BIN &&
+ !mts.tile_versions[mts.raster_mode].raster_task_) {
+ FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile);
continue;
}
- // Note that if the tile is visible_and_ready_to_draw, then we always want
- // the priority to be NOW_AND_READY_TO_DRAW_BIN, even if HIGH_PRIORITY_BIN
- // is something different. The reason for this is that if we're prioritizing
- // the pending tree, we still want visible tiles to take the highest
- // priority.
- ManagedTileBin priority_bin = mts.visible_and_ready_to_draw
- ? NOW_AND_READY_TO_DRAW_BIN
- : mts.bin;
-
// Insert the tile into a priority set.
- tiles->InsertTile(tile, priority_bin);
+ tiles->InsertTile(tile, mts.bin);
}
}
@@ -488,16 +643,12 @@ void TileManager::ManageTiles(const GlobalStateThatImpactsTilePriority& state) {
if (state != global_state_) {
global_state_ = state;
prioritized_tiles_dirty_ = true;
- resource_pool_->SetResourceUsageLimits(
- global_state_.memory_limit_in_bytes,
- global_state_.unused_memory_limit_in_bytes,
- global_state_.num_resources_limit);
}
// We need to call CheckForCompletedTasks() once in-between each call
// to ScheduleTasks() to prevent canceled tasks from being scheduled.
if (!did_check_for_completed_tasks_since_last_schedule_tasks_) {
- raster_worker_pool_->CheckForCompletedTasks();
+ rasterizer_->CheckForCompletedTasks();
did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
}
@@ -510,26 +661,32 @@ void TileManager::ManageTiles(const GlobalStateThatImpactsTilePriority& state) {
// Finally, schedule rasterizer tasks.
ScheduleTasks(tiles_that_need_to_be_rasterized);
- TRACE_EVENT_INSTANT1(
- "cc", "DidManage", TRACE_EVENT_SCOPE_THREAD,
- "state", TracedValue::FromValue(BasicStateAsValue().release()));
+ TRACE_EVENT_INSTANT1("cc",
+ "DidManage",
+ TRACE_EVENT_SCOPE_THREAD,
+ "state",
+ TracedValue::FromValue(BasicStateAsValue().release()));
- TRACE_COUNTER_ID1("cc", "unused_memory_bytes", this,
+ TRACE_COUNTER_ID1("cc",
+ "unused_memory_bytes",
+ this,
resource_pool_->total_memory_usage_bytes() -
- resource_pool_->acquired_memory_usage_bytes());
+ resource_pool_->acquired_memory_usage_bytes());
}
bool TileManager::UpdateVisibleTiles() {
TRACE_EVENT0("cc", "TileManager::UpdateVisibleTiles");
- raster_worker_pool_->CheckForCompletedTasks();
+ rasterizer_->CheckForCompletedTasks();
did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
TRACE_EVENT_INSTANT1(
- "cc", "DidUpdateVisibleTiles", TRACE_EVENT_SCOPE_THREAD,
- "stats", TracedValue::FromValue(
- RasterTaskCompletionStatsAsValue(
- update_visible_tiles_stats_).release()));
+ "cc",
+ "DidUpdateVisibleTiles",
+ TRACE_EVENT_SCOPE_THREAD,
+ "stats",
+ TracedValue::FromValue(RasterTaskCompletionStatsAsValue(
+ update_visible_tiles_stats_).release()));
update_visible_tiles_stats_ = RasterTaskCompletionStats();
bool did_initialize_visible_tile = did_initialize_visible_tile_;
@@ -537,72 +694,19 @@ bool TileManager::UpdateVisibleTiles() {
return did_initialize_visible_tile;
}
-void TileManager::GetMemoryStats(
- size_t* memory_required_bytes,
- size_t* memory_nice_to_have_bytes,
- size_t* memory_allocated_bytes,
- size_t* memory_used_bytes) const {
- *memory_required_bytes = memory_required_bytes_;
- *memory_nice_to_have_bytes = memory_nice_to_have_bytes_;
- *memory_allocated_bytes = resource_pool_->total_memory_usage_bytes();
- *memory_used_bytes = resource_pool_->acquired_memory_usage_bytes();
-}
-
scoped_ptr<base::Value> TileManager::BasicStateAsValue() const {
scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue());
state->SetInteger("tile_count", tiles_.size());
state->Set("global_state", global_state_.AsValue().release());
- state->Set("memory_requirements", GetMemoryRequirementsAsValue().release());
return state.PassAs<base::Value>();
}
scoped_ptr<base::Value> TileManager::AllTilesAsValue() const {
scoped_ptr<base::ListValue> state(new base::ListValue());
- for (TileMap::const_iterator it = tiles_.begin();
- it != tiles_.end();
- it++) {
+ for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it)
state->Append(it->second->AsValue().release());
- }
- return state.PassAs<base::Value>();
-}
-
-scoped_ptr<base::Value> TileManager::GetMemoryRequirementsAsValue() const {
- scoped_ptr<base::DictionaryValue> requirements(
- new base::DictionaryValue());
- size_t memory_required_bytes;
- size_t memory_nice_to_have_bytes;
- size_t memory_allocated_bytes;
- size_t memory_used_bytes;
- GetMemoryStats(&memory_required_bytes,
- &memory_nice_to_have_bytes,
- &memory_allocated_bytes,
- &memory_used_bytes);
- requirements->SetInteger("memory_required_bytes", memory_required_bytes);
- requirements->SetInteger("memory_nice_to_have_bytes",
- memory_nice_to_have_bytes);
- requirements->SetInteger("memory_allocated_bytes", memory_allocated_bytes);
- requirements->SetInteger("memory_used_bytes", memory_used_bytes);
- return requirements.PassAs<base::Value>();
-}
-
-RasterMode TileManager::DetermineRasterMode(const Tile* tile) const {
- DCHECK(tile);
- DCHECK(tile->picture_pile());
-
- const ManagedTileState& mts = tile->managed_state();
- RasterMode current_mode = mts.raster_mode;
-
- RasterMode raster_mode = HIGH_QUALITY_RASTER_MODE;
- if (tile->managed_state().resolution == LOW_RESOLUTION)
- raster_mode = LOW_QUALITY_RASTER_MODE;
- else if (tile->can_use_lcd_text())
- raster_mode = HIGH_QUALITY_RASTER_MODE;
- else if (mts.tile_versions[current_mode].has_text_ ||
- !mts.tile_versions[current_mode].IsReadyToDraw())
- raster_mode = HIGH_QUALITY_NO_LCD_RASTER_MODE;
-
- return std::min(raster_mode, current_mode);
+ return state.PassAs<base::Value>();
}
void TileManager::AssignGpuMemoryToTiles(
@@ -623,42 +727,40 @@ void TileManager::AssignGpuMemoryToTiles(
all_tiles_required_for_activation_have_memory_ = true;
// Cast to prevent overflow.
- int64 bytes_available =
+ int64 soft_bytes_available =
static_cast<int64>(bytes_releasable_) +
- static_cast<int64>(global_state_.memory_limit_in_bytes) -
+ static_cast<int64>(global_state_.soft_memory_limit_in_bytes) -
static_cast<int64>(resource_pool_->acquired_memory_usage_bytes());
- int resources_available =
- resources_releasable_ +
- global_state_.num_resources_limit -
- resource_pool_->acquired_resource_count();
-
- size_t bytes_allocatable =
- std::max(static_cast<int64>(0), bytes_available);
+ int64 hard_bytes_available =
+ static_cast<int64>(bytes_releasable_) +
+ static_cast<int64>(global_state_.hard_memory_limit_in_bytes) -
+ static_cast<int64>(resource_pool_->acquired_memory_usage_bytes());
+ int resources_available = resources_releasable_ +
+ global_state_.num_resources_limit -
+ resource_pool_->acquired_resource_count();
+ size_t soft_bytes_allocatable =
+ std::max(static_cast<int64>(0), soft_bytes_available);
+ size_t hard_bytes_allocatable =
+ std::max(static_cast<int64>(0), hard_bytes_available);
size_t resources_allocatable = std::max(0, resources_available);
size_t bytes_that_exceeded_memory_budget = 0;
- size_t bytes_left = bytes_allocatable;
- size_t resources_left = resources_allocatable;
- bool oomed = false;
+ size_t soft_bytes_left = soft_bytes_allocatable;
+ size_t hard_bytes_left = hard_bytes_allocatable;
- // Memory we assign to raster tasks now will be deducted from our memory
- // in future iterations if priorities change. By assigning at most half
- // the raster limit, we will always have another 50% left even if priorities
- // change completely (assuming we check for completed/cancelled rasters
- // between each call to this function).
- size_t max_raster_bytes = max_raster_usage_bytes_ / 2;
- size_t raster_bytes = 0;
+ size_t resources_left = resources_allocatable;
+ bool oomed_soft = false;
+ bool oomed_hard = false;
+ bool have_hit_soft_memory = false; // Soft memory comes after hard.
unsigned schedule_priority = 1u;
- for (PrioritizedTileSet::Iterator it(tiles, true);
- it;
- ++it) {
+ for (PrioritizedTileSet::Iterator it(tiles, true); it; ++it) {
Tile* tile = *it;
ManagedTileState& mts = tile->managed_state();
mts.scheduled_priority = schedule_priority++;
- mts.raster_mode = DetermineRasterMode(tile);
+ mts.raster_mode = tile->DetermineOverallRasterMode();
ManagedTileState::TileVersion& tile_version =
mts.tile_versions[mts.raster_mode];
@@ -669,12 +771,20 @@ void TileManager::AssignGpuMemoryToTiles(
// If the tile is not needed, free it up.
if (mts.bin == NEVER_BIN) {
- FreeResourcesForTile(tile);
+ FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile);
continue;
}
- size_t bytes_if_allocated = BytesConsumedIfAllocated(tile);
- size_t raster_bytes_if_rastered = raster_bytes + bytes_if_allocated;
+ const bool tile_uses_hard_limit = mts.bin <= NOW_BIN;
+ const size_t bytes_if_allocated = BytesConsumedIfAllocated(tile);
+ const size_t tile_bytes_left =
+ (tile_uses_hard_limit) ? hard_bytes_left : soft_bytes_left;
+
+ // Hard-limit is reserved for tiles that would cause a calamity
+ // if they were to go away, so by definition they are the highest
+ // priority memory, and must be at the front of the list.
+ DCHECK(!(have_hit_soft_memory && tile_uses_hard_limit));
+ have_hit_soft_memory |= !tile_uses_hard_limit;
size_t tile_bytes = 0;
size_t tile_resources = 0;
@@ -690,17 +800,21 @@ void TileManager::AssignGpuMemoryToTiles(
// Allow lower priority tiles with initialized resources to keep
// their memory by only assigning memory to new raster tasks if
// they can be scheduled.
- if (raster_bytes_if_rastered <= max_raster_bytes) {
+ bool reached_scheduled_raster_tasks_limit =
+ tiles_that_need_to_be_rasterized->size() >= kScheduledRasterTasksLimit;
+ if (!reached_scheduled_raster_tasks_limit) {
// If we don't have the required version, and it's not in flight
// then we'll have to pay to create a new task.
- if (!tile_version.resource_ && tile_version.raster_task_.is_null()) {
+ if (!tile_version.resource_ && !tile_version.raster_task_) {
tile_bytes += bytes_if_allocated;
tile_resources++;
}
}
// Tile is OOM.
- if (tile_bytes > bytes_left || tile_resources > resources_left) {
+ if (tile_bytes > tile_bytes_left || tile_resources > resources_left) {
+ bool was_ready_to_draw = tile->IsReadyToDraw();
+
FreeResourcesForTile(tile);
// This tile was already on screen and now its resources have been
@@ -709,12 +823,19 @@ void TileManager::AssignGpuMemoryToTiles(
if (mts.visible_and_ready_to_draw)
tile_version.set_rasterize_on_demand();
- oomed = true;
- bytes_that_exceeded_memory_budget += tile_bytes;
+ if (was_ready_to_draw)
+ client_->NotifyTileStateChanged(tile);
+
+ oomed_soft = true;
+ if (tile_uses_hard_limit) {
+ oomed_hard = true;
+ bytes_that_exceeded_memory_budget += tile_bytes;
+ }
} else {
- bytes_left -= tile_bytes;
resources_left -= tile_resources;
-
+ hard_bytes_left -= tile_bytes;
+ soft_bytes_left =
+ (soft_bytes_left > tile_bytes) ? soft_bytes_left - tile_bytes : 0;
if (tile_version.resource_)
continue;
}
@@ -729,7 +850,10 @@ void TileManager::AssignGpuMemoryToTiles(
// 1. Tile size should not impact raster priority.
// 2. Tiles with existing raster task could otherwise incorrectly
// be added as they are not affected by |bytes_allocatable|.
- if (oomed || raster_bytes_if_rastered > max_raster_bytes) {
+ bool can_schedule_tile =
+ !oomed_soft && !reached_scheduled_raster_tasks_limit;
+
+ if (!can_schedule_tile) {
all_tiles_that_need_to_be_rasterized_have_memory_ = false;
if (tile->required_for_activation())
all_tiles_required_for_activation_have_memory_ = false;
@@ -737,31 +861,33 @@ void TileManager::AssignGpuMemoryToTiles(
continue;
}
- raster_bytes = raster_bytes_if_rastered;
tiles_that_need_to_be_rasterized->push_back(tile);
}
- ever_exceeded_memory_budget_ |= bytes_that_exceeded_memory_budget > 0;
+ // OOM reporting uses hard-limit, soft-OOM is normal depending on limit.
+ ever_exceeded_memory_budget_ |= oomed_hard;
if (ever_exceeded_memory_budget_) {
- TRACE_COUNTER_ID2("cc", "over_memory_budget", this,
- "budget", global_state_.memory_limit_in_bytes,
- "over", bytes_that_exceeded_memory_budget);
+ TRACE_COUNTER_ID2("cc",
+ "over_memory_budget",
+ this,
+ "budget",
+ global_state_.hard_memory_limit_in_bytes,
+ "over",
+ bytes_that_exceeded_memory_budget);
}
memory_stats_from_last_assign_.total_budget_in_bytes =
- global_state_.memory_limit_in_bytes;
+ global_state_.hard_memory_limit_in_bytes;
memory_stats_from_last_assign_.bytes_allocated =
- bytes_allocatable - bytes_left;
+ hard_bytes_allocatable - hard_bytes_left;
memory_stats_from_last_assign_.bytes_unreleasable =
- bytes_allocatable - bytes_releasable_;
- memory_stats_from_last_assign_.bytes_over =
- bytes_that_exceeded_memory_budget;
+ resource_pool_->acquired_memory_usage_bytes() - bytes_releasable_;
+ memory_stats_from_last_assign_.bytes_over = bytes_that_exceeded_memory_budget;
}
void TileManager::FreeResourceForTile(Tile* tile, RasterMode mode) {
ManagedTileState& mts = tile->managed_state();
if (mts.tile_versions[mode].resource_) {
- resource_pool_->ReleaseResource(
- mts.tile_versions[mode].resource_.Pass());
+ resource_pool_->ReleaseResource(mts.tile_versions[mode].resource_.Pass());
DCHECK_GE(bytes_releasable_, BytesConsumedIfAllocated(tile));
DCHECK_GE(resources_releasable_, 1u);
@@ -780,7 +906,7 @@ void TileManager::FreeResourcesForTile(Tile* tile) {
void TileManager::FreeUnusedResourcesForTile(Tile* tile) {
DCHECK(tile->IsReadyToDraw());
ManagedTileState& mts = tile->managed_state();
- RasterMode used_mode = HIGH_QUALITY_NO_LCD_RASTER_MODE;
+ RasterMode used_mode = LOW_QUALITY_RASTER_MODE;
for (int mode = 0; mode < NUM_RASTER_MODES; ++mode) {
if (mts.tile_versions[mode].IsReadyToDraw()) {
used_mode = static_cast<RasterMode>(mode);
@@ -794,14 +920,25 @@ void TileManager::FreeUnusedResourcesForTile(Tile* tile) {
}
}
+void TileManager::FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(
+ Tile* tile) {
+ bool was_ready_to_draw = tile->IsReadyToDraw();
+ FreeResourcesForTile(tile);
+ if (was_ready_to_draw)
+ client_->NotifyTileStateChanged(tile);
+}
+
void TileManager::ScheduleTasks(
const TileVector& tiles_that_need_to_be_rasterized) {
- TRACE_EVENT1("cc", "TileManager::ScheduleTasks",
- "count", tiles_that_need_to_be_rasterized.size());
- RasterWorkerPool::RasterTask::Queue tasks;
+ TRACE_EVENT1("cc",
+ "TileManager::ScheduleTasks",
+ "count",
+ tiles_that_need_to_be_rasterized.size());
DCHECK(did_check_for_completed_tasks_since_last_schedule_tasks_);
+ raster_queue_.Reset();
+
// Build a new task queue containing all task currently needed. Tasks
// are added in order of priority, highest priority task first.
for (TileVector::const_iterator it = tiles_that_need_to_be_rasterized.begin();
@@ -815,37 +952,46 @@ void TileManager::ScheduleTasks(
DCHECK(tile_version.requires_resource());
DCHECK(!tile_version.resource_);
- if (tile_version.raster_task_.is_null())
+ if (!tile_version.raster_task_)
tile_version.raster_task_ = CreateRasterTask(tile);
- tasks.Append(tile_version.raster_task_, tile->required_for_activation());
+ raster_queue_.items.push_back(RasterTaskQueue::Item(
+ tile_version.raster_task_.get(), tile->required_for_activation()));
+ raster_queue_.required_for_activation_count +=
+ tile->required_for_activation();
}
// We must reduce the amount of unused resoruces before calling
// ScheduleTasks to prevent usage from rising above limits.
resource_pool_->ReduceResourceUsage();
- // Schedule running of |tasks|. This replaces any previously
+ // Schedule running of |raster_tasks_|. This replaces any previously
// scheduled tasks and effectively cancels all tasks not present
- // in |tasks|.
- raster_worker_pool_->ScheduleTasks(&tasks);
+ // in |raster_tasks_|.
+ rasterizer_->ScheduleTasks(&raster_queue_);
+
+ // It's now safe to clean up orphan tasks as raster worker pool is not
+ // allowed to keep around unreferenced raster tasks after ScheduleTasks() has
+ // been called.
+ orphan_raster_tasks_.clear();
did_check_for_completed_tasks_since_last_schedule_tasks_ = false;
}
-RasterWorkerPool::Task TileManager::CreateImageDecodeTask(
- Tile* tile, skia::LazyPixelRef* pixel_ref) {
- return RasterWorkerPool::CreateImageDecodeTask(
+scoped_refptr<ImageDecodeTask> TileManager::CreateImageDecodeTask(
+ Tile* tile,
+ SkPixelRef* pixel_ref) {
+ return make_scoped_refptr(new ImageDecodeTaskImpl(
pixel_ref,
tile->layer_id(),
rendering_stats_instrumentation_,
base::Bind(&TileManager::OnImageDecodeTaskCompleted,
base::Unretained(this),
tile->layer_id(),
- base::Unretained(pixel_ref)));
+ base::Unretained(pixel_ref))));
}
-RasterWorkerPool::RasterTask TileManager::CreateRasterTask(Tile* tile) {
+scoped_refptr<RasterTask> TileManager::CreateRasterTask(Tile* tile) {
ManagedTileState& mts = tile->managed_state();
scoped_ptr<ScopedResource> resource =
@@ -853,60 +999,58 @@ RasterWorkerPool::RasterTask TileManager::CreateRasterTask(Tile* tile) {
const ScopedResource* const_resource = resource.get();
// Create and queue all image decode tasks that this tile depends on.
- RasterWorkerPool::Task::Set decode_tasks;
+ ImageDecodeTask::Vector decode_tasks;
PixelRefTaskMap& existing_pixel_refs = image_decode_tasks_[tile->layer_id()];
- for (PicturePileImpl::PixelRefIterator iter(tile->content_rect(),
- tile->contents_scale(),
- tile->picture_pile());
- iter; ++iter) {
- skia::LazyPixelRef* pixel_ref = *iter;
+ for (PicturePileImpl::PixelRefIterator iter(
+ tile->content_rect(), tile->contents_scale(), tile->picture_pile());
+ iter;
+ ++iter) {
+ SkPixelRef* pixel_ref = *iter;
uint32_t id = pixel_ref->getGenerationID();
// Append existing image decode task if available.
PixelRefTaskMap::iterator decode_task_it = existing_pixel_refs.find(id);
if (decode_task_it != existing_pixel_refs.end()) {
- decode_tasks.Insert(decode_task_it->second);
+ decode_tasks.push_back(decode_task_it->second);
continue;
}
// Create and append new image decode task for this pixel ref.
- RasterWorkerPool::Task decode_task = CreateImageDecodeTask(
- tile, pixel_ref);
- decode_tasks.Insert(decode_task);
+ scoped_refptr<ImageDecodeTask> decode_task =
+ CreateImageDecodeTask(tile, pixel_ref);
+ decode_tasks.push_back(decode_task);
existing_pixel_refs[id] = decode_task;
}
- return RasterWorkerPool::CreateRasterTask(
- const_resource,
- tile->picture_pile(),
- tile->content_rect(),
- tile->contents_scale(),
- mts.raster_mode,
- mts.resolution,
- tile->layer_id(),
- static_cast<const void *>(tile),
- tile->source_frame_number(),
- rendering_stats_instrumentation_,
- base::Bind(&TileManager::OnRasterTaskCompleted,
- base::Unretained(this),
- tile->id(),
- base::Passed(&resource),
- mts.raster_mode),
- &decode_tasks);
+ return make_scoped_refptr(
+ new RasterTaskImpl(const_resource,
+ tile->picture_pile(),
+ tile->content_rect(),
+ tile->contents_scale(),
+ mts.raster_mode,
+ mts.resolution,
+ tile->layer_id(),
+ static_cast<const void*>(tile),
+ tile->source_frame_number(),
+ tile->use_picture_analysis(),
+ rendering_stats_instrumentation_,
+ base::Bind(&TileManager::OnRasterTaskCompleted,
+ base::Unretained(this),
+ tile->id(),
+ base::Passed(&resource),
+ mts.raster_mode),
+ &decode_tasks));
}
-void TileManager::OnImageDecodeTaskCompleted(
- int layer_id,
- skia::LazyPixelRef* pixel_ref,
- bool was_canceled) {
+void TileManager::OnImageDecodeTaskCompleted(int layer_id,
+ SkPixelRef* pixel_ref,
+ bool was_canceled) {
// If the task was canceled, we need to clean it up
// from |image_decode_tasks_|.
if (!was_canceled)
return;
- LayerPixelRefTaskMap::iterator layer_it =
- image_decode_tasks_.find(layer_id);
-
+ LayerPixelRefTaskMap::iterator layer_it = image_decode_tasks_.find(layer_id);
if (layer_it == image_decode_tasks_.end())
return;
@@ -933,10 +1077,10 @@ void TileManager::OnRasterTaskCompleted(
Tile* tile = it->second;
ManagedTileState& mts = tile->managed_state();
- ManagedTileState::TileVersion& tile_version =
- mts.tile_versions[raster_mode];
- DCHECK(!tile_version.raster_task_.is_null());
- tile_version.raster_task_.Reset();
+ ManagedTileState::TileVersion& tile_version = mts.tile_versions[raster_mode];
+ DCHECK(tile_version.raster_task_);
+ orphan_raster_tasks_.push_back(tile_version.raster_task_);
+ tile_version.raster_task_ = NULL;
if (was_canceled) {
++update_visible_tiles_stats_.canceled_count;
@@ -946,7 +1090,6 @@ void TileManager::OnRasterTaskCompleted(
++update_visible_tiles_stats_.completed_count;
- tile_version.set_has_text(analysis.has_text);
if (analysis.is_solid_color) {
tile_version.set_solid_color(analysis.solid_color);
resource_pool_->ReleaseResource(resource.Pass());
@@ -959,14 +1102,16 @@ void TileManager::OnRasterTaskCompleted(
}
FreeUnusedResourcesForTile(tile);
- if (tile->priority(ACTIVE_TREE).distance_to_visible_in_pixels == 0)
+ if (tile->priority(ACTIVE_TREE).distance_to_visible == 0.f)
did_initialize_visible_tile_ = true;
+
+ client_->NotifyTileStateChanged(tile);
}
scoped_refptr<Tile> TileManager::CreateTile(PicturePileImpl* picture_pile,
- gfx::Size tile_size,
- gfx::Rect content_rect,
- gfx::Rect opaque_rect,
+ const gfx::Size& tile_size,
+ const gfx::Rect& content_rect,
+ const gfx::Rect& opaque_rect,
float contents_scale,
int layer_id,
int source_frame_number,
@@ -988,4 +1133,453 @@ scoped_refptr<Tile> TileManager::CreateTile(PicturePileImpl* picture_pile,
return tile;
}
+void TileManager::GetPairedPictureLayers(
+ std::vector<PairedPictureLayer>* paired_layers) const {
+ const std::vector<PictureLayerImpl*>& layers = client_->GetPictureLayers();
+
+ paired_layers->clear();
+ // Reserve a maximum possible paired layers.
+ paired_layers->reserve(layers.size());
+
+ for (std::vector<PictureLayerImpl*>::const_iterator it = layers.begin();
+ it != layers.end();
+ ++it) {
+ PictureLayerImpl* layer = *it;
+
+ // TODO(vmpstr): Iterators and should handle this instead. crbug.com/381704
+ if (!layer->HasValidTilePriorities())
+ continue;
+
+ PictureLayerImpl* twin_layer = layer->GetTwinLayer();
+
+ // Ignore the twin layer when tile priorities are invalid.
+ // TODO(vmpstr): Iterators should handle this instead. crbug.com/381704
+ if (twin_layer && !twin_layer->HasValidTilePriorities())
+ twin_layer = NULL;
+
+ PairedPictureLayer paired_layer;
+ WhichTree tree = layer->GetTree();
+
+ // If the current tree is ACTIVE_TREE, then always generate a paired_layer.
+ // If current tree is PENDING_TREE, then only generate a paired_layer if
+ // there is no twin layer.
+ if (tree == ACTIVE_TREE) {
+ DCHECK(!twin_layer || twin_layer->GetTree() == PENDING_TREE);
+ paired_layer.active_layer = layer;
+ paired_layer.pending_layer = twin_layer;
+ paired_layers->push_back(paired_layer);
+ } else if (!twin_layer) {
+ paired_layer.active_layer = NULL;
+ paired_layer.pending_layer = layer;
+ paired_layers->push_back(paired_layer);
+ }
+ }
+}
+
+TileManager::PairedPictureLayer::PairedPictureLayer()
+ : active_layer(NULL), pending_layer(NULL) {}
+
+TileManager::PairedPictureLayer::~PairedPictureLayer() {}
+
+TileManager::RasterTileIterator::RasterTileIterator(TileManager* tile_manager,
+ TreePriority tree_priority)
+ : tree_priority_(tree_priority), comparator_(tree_priority) {
+ std::vector<TileManager::PairedPictureLayer> paired_layers;
+ tile_manager->GetPairedPictureLayers(&paired_layers);
+ bool prioritize_low_res = tree_priority_ == SMOOTHNESS_TAKES_PRIORITY;
+
+ paired_iterators_.reserve(paired_layers.size());
+ iterator_heap_.reserve(paired_layers.size());
+ for (std::vector<TileManager::PairedPictureLayer>::iterator it =
+ paired_layers.begin();
+ it != paired_layers.end();
+ ++it) {
+ PairedPictureLayerIterator paired_iterator;
+ if (it->active_layer) {
+ paired_iterator.active_iterator =
+ PictureLayerImpl::LayerRasterTileIterator(it->active_layer,
+ prioritize_low_res);
+ }
+
+ if (it->pending_layer) {
+ paired_iterator.pending_iterator =
+ PictureLayerImpl::LayerRasterTileIterator(it->pending_layer,
+ prioritize_low_res);
+ }
+
+ if (paired_iterator.PeekTile(tree_priority_) != NULL) {
+ paired_iterators_.push_back(paired_iterator);
+ iterator_heap_.push_back(&paired_iterators_.back());
+ }
+ }
+
+ std::make_heap(iterator_heap_.begin(), iterator_heap_.end(), comparator_);
+}
+
+TileManager::RasterTileIterator::~RasterTileIterator() {}
+
+TileManager::RasterTileIterator& TileManager::RasterTileIterator::operator++() {
+ DCHECK(*this);
+
+ std::pop_heap(iterator_heap_.begin(), iterator_heap_.end(), comparator_);
+ PairedPictureLayerIterator* paired_iterator = iterator_heap_.back();
+ iterator_heap_.pop_back();
+
+ paired_iterator->PopTile(tree_priority_);
+ if (paired_iterator->PeekTile(tree_priority_) != NULL) {
+ iterator_heap_.push_back(paired_iterator);
+ std::push_heap(iterator_heap_.begin(), iterator_heap_.end(), comparator_);
+ }
+ return *this;
+}
+
+TileManager::RasterTileIterator::operator bool() const {
+ return !iterator_heap_.empty();
+}
+
+Tile* TileManager::RasterTileIterator::operator*() {
+ DCHECK(*this);
+ return iterator_heap_.front()->PeekTile(tree_priority_);
+}
+
+TileManager::RasterTileIterator::PairedPictureLayerIterator::
+ PairedPictureLayerIterator() {}
+
+TileManager::RasterTileIterator::PairedPictureLayerIterator::
+ ~PairedPictureLayerIterator() {}
+
+Tile* TileManager::RasterTileIterator::PairedPictureLayerIterator::PeekTile(
+ TreePriority tree_priority) {
+ PictureLayerImpl::LayerRasterTileIterator* next_iterator =
+ NextTileIterator(tree_priority).first;
+ if (!next_iterator)
+ return NULL;
+
+ DCHECK(*next_iterator);
+ DCHECK(std::find(returned_shared_tiles.begin(),
+ returned_shared_tiles.end(),
+ **next_iterator) == returned_shared_tiles.end());
+ return **next_iterator;
+}
+
+void TileManager::RasterTileIterator::PairedPictureLayerIterator::PopTile(
+ TreePriority tree_priority) {
+ PictureLayerImpl::LayerRasterTileIterator* next_iterator =
+ NextTileIterator(tree_priority).first;
+ DCHECK(next_iterator);
+ DCHECK(*next_iterator);
+ returned_shared_tiles.push_back(**next_iterator);
+ ++(*next_iterator);
+
+ next_iterator = NextTileIterator(tree_priority).first;
+ while (next_iterator &&
+ std::find(returned_shared_tiles.begin(),
+ returned_shared_tiles.end(),
+ **next_iterator) != returned_shared_tiles.end()) {
+ ++(*next_iterator);
+ next_iterator = NextTileIterator(tree_priority).first;
+ }
+}
+
+std::pair<PictureLayerImpl::LayerRasterTileIterator*, WhichTree>
+TileManager::RasterTileIterator::PairedPictureLayerIterator::NextTileIterator(
+ TreePriority tree_priority) {
+ // If both iterators are out of tiles, return NULL.
+ if (!active_iterator && !pending_iterator) {
+ return std::pair<PictureLayerImpl::LayerRasterTileIterator*, WhichTree>(
+ NULL, ACTIVE_TREE);
+ }
+
+ // If we only have one iterator with tiles, return it.
+ if (!active_iterator)
+ return std::make_pair(&pending_iterator, PENDING_TREE);
+ if (!pending_iterator)
+ return std::make_pair(&active_iterator, ACTIVE_TREE);
+
+ // Now both iterators have tiles, so we have to decide based on tree priority.
+ switch (tree_priority) {
+ case SMOOTHNESS_TAKES_PRIORITY:
+ return std::make_pair(&active_iterator, ACTIVE_TREE);
+ case NEW_CONTENT_TAKES_PRIORITY:
+ return std::make_pair(&pending_iterator, ACTIVE_TREE);
+ case SAME_PRIORITY_FOR_BOTH_TREES: {
+ Tile* active_tile = *active_iterator;
+ Tile* pending_tile = *pending_iterator;
+ if (active_tile == pending_tile)
+ return std::make_pair(&active_iterator, ACTIVE_TREE);
+
+ const TilePriority& active_priority = active_tile->priority(ACTIVE_TREE);
+ const TilePriority& pending_priority =
+ pending_tile->priority(PENDING_TREE);
+
+ if (active_priority.IsHigherPriorityThan(pending_priority))
+ return std::make_pair(&active_iterator, ACTIVE_TREE);
+ return std::make_pair(&pending_iterator, PENDING_TREE);
+ }
+ }
+
+ NOTREACHED();
+ // Keep the compiler happy.
+ return std::pair<PictureLayerImpl::LayerRasterTileIterator*, WhichTree>(
+ NULL, ACTIVE_TREE);
+}
+
+TileManager::RasterTileIterator::RasterOrderComparator::RasterOrderComparator(
+ TreePriority tree_priority)
+ : tree_priority_(tree_priority) {}
+
+bool TileManager::RasterTileIterator::RasterOrderComparator::operator()(
+ PairedPictureLayerIterator* a,
+ PairedPictureLayerIterator* b) const {
+ std::pair<PictureLayerImpl::LayerRasterTileIterator*, WhichTree> a_pair =
+ a->NextTileIterator(tree_priority_);
+ DCHECK(a_pair.first);
+ DCHECK(*a_pair.first);
+
+ std::pair<PictureLayerImpl::LayerRasterTileIterator*, WhichTree> b_pair =
+ b->NextTileIterator(tree_priority_);
+ DCHECK(b_pair.first);
+ DCHECK(*b_pair.first);
+
+ Tile* a_tile = **a_pair.first;
+ Tile* b_tile = **b_pair.first;
+
+ const TilePriority& a_priority =
+ a_tile->priority_for_tree_priority(tree_priority_);
+ const TilePriority& b_priority =
+ b_tile->priority_for_tree_priority(tree_priority_);
+ bool prioritize_low_res = tree_priority_ == SMOOTHNESS_TAKES_PRIORITY;
+
+ // Now we have to return true iff b is higher priority than a.
+
+ // If the bin is the same but the resolution is not, then the order will be
+ // determined by whether we prioritize low res or not.
+ // TODO(vmpstr): Remove this when TilePriority is no longer a member of Tile
+ // class but instead produced by the iterators.
+ if (b_priority.priority_bin == a_priority.priority_bin &&
+ b_priority.resolution != a_priority.resolution) {
+ // Non ideal resolution should be sorted lower than other resolutions.
+ if (a_priority.resolution == NON_IDEAL_RESOLUTION)
+ return true;
+
+ if (b_priority.resolution == NON_IDEAL_RESOLUTION)
+ return false;
+
+ if (prioritize_low_res)
+ return b_priority.resolution == LOW_RESOLUTION;
+
+ return b_priority.resolution == HIGH_RESOLUTION;
+ }
+
+ return b_priority.IsHigherPriorityThan(a_priority);
+}
+
+TileManager::EvictionTileIterator::EvictionTileIterator()
+ : comparator_(SAME_PRIORITY_FOR_BOTH_TREES) {}
+
+TileManager::EvictionTileIterator::EvictionTileIterator(
+ TileManager* tile_manager,
+ TreePriority tree_priority)
+ : tree_priority_(tree_priority), comparator_(tree_priority) {
+ std::vector<TileManager::PairedPictureLayer> paired_layers;
+
+ tile_manager->GetPairedPictureLayers(&paired_layers);
+
+ paired_iterators_.reserve(paired_layers.size());
+ iterator_heap_.reserve(paired_layers.size());
+ for (std::vector<TileManager::PairedPictureLayer>::iterator it =
+ paired_layers.begin();
+ it != paired_layers.end();
+ ++it) {
+ PairedPictureLayerIterator paired_iterator;
+ if (it->active_layer) {
+ paired_iterator.active_iterator =
+ PictureLayerImpl::LayerEvictionTileIterator(it->active_layer,
+ tree_priority_);
+ }
+
+ if (it->pending_layer) {
+ paired_iterator.pending_iterator =
+ PictureLayerImpl::LayerEvictionTileIterator(it->pending_layer,
+ tree_priority_);
+ }
+
+ if (paired_iterator.PeekTile(tree_priority_) != NULL) {
+ paired_iterators_.push_back(paired_iterator);
+ iterator_heap_.push_back(&paired_iterators_.back());
+ }
+ }
+
+ std::make_heap(iterator_heap_.begin(), iterator_heap_.end(), comparator_);
+}
+
+TileManager::EvictionTileIterator::~EvictionTileIterator() {}
+
+TileManager::EvictionTileIterator& TileManager::EvictionTileIterator::
+operator++() {
+ std::pop_heap(iterator_heap_.begin(), iterator_heap_.end(), comparator_);
+ PairedPictureLayerIterator* paired_iterator = iterator_heap_.back();
+ iterator_heap_.pop_back();
+
+ paired_iterator->PopTile(tree_priority_);
+ if (paired_iterator->PeekTile(tree_priority_) != NULL) {
+ iterator_heap_.push_back(paired_iterator);
+ std::push_heap(iterator_heap_.begin(), iterator_heap_.end(), comparator_);
+ }
+ return *this;
+}
+
+TileManager::EvictionTileIterator::operator bool() const {
+ return !iterator_heap_.empty();
+}
+
+Tile* TileManager::EvictionTileIterator::operator*() {
+ DCHECK(*this);
+ return iterator_heap_.front()->PeekTile(tree_priority_);
+}
+
+TileManager::EvictionTileIterator::PairedPictureLayerIterator::
+ PairedPictureLayerIterator() {}
+
+TileManager::EvictionTileIterator::PairedPictureLayerIterator::
+ ~PairedPictureLayerIterator() {}
+
+Tile* TileManager::EvictionTileIterator::PairedPictureLayerIterator::PeekTile(
+ TreePriority tree_priority) {
+ PictureLayerImpl::LayerEvictionTileIterator* next_iterator =
+ NextTileIterator(tree_priority);
+ if (!next_iterator)
+ return NULL;
+
+ DCHECK(*next_iterator);
+ DCHECK(std::find(returned_shared_tiles.begin(),
+ returned_shared_tiles.end(),
+ **next_iterator) == returned_shared_tiles.end());
+ return **next_iterator;
+}
+
+void TileManager::EvictionTileIterator::PairedPictureLayerIterator::PopTile(
+ TreePriority tree_priority) {
+ PictureLayerImpl::LayerEvictionTileIterator* next_iterator =
+ NextTileIterator(tree_priority);
+ DCHECK(next_iterator);
+ DCHECK(*next_iterator);
+ returned_shared_tiles.push_back(**next_iterator);
+ ++(*next_iterator);
+
+ next_iterator = NextTileIterator(tree_priority);
+ while (next_iterator &&
+ std::find(returned_shared_tiles.begin(),
+ returned_shared_tiles.end(),
+ **next_iterator) != returned_shared_tiles.end()) {
+ ++(*next_iterator);
+ next_iterator = NextTileIterator(tree_priority);
+ }
+}
+
+PictureLayerImpl::LayerEvictionTileIterator*
+TileManager::EvictionTileIterator::PairedPictureLayerIterator::NextTileIterator(
+ TreePriority tree_priority) {
+ // If both iterators are out of tiles, return NULL.
+ if (!active_iterator && !pending_iterator)
+ return NULL;
+
+ // If we only have one iterator with tiles, return it.
+ if (!active_iterator)
+ return &pending_iterator;
+ if (!pending_iterator)
+ return &active_iterator;
+
+ Tile* active_tile = *active_iterator;
+ Tile* pending_tile = *pending_iterator;
+ if (active_tile == pending_tile)
+ return &active_iterator;
+
+ const TilePriority& active_priority =
+ active_tile->priority_for_tree_priority(tree_priority);
+ const TilePriority& pending_priority =
+ pending_tile->priority_for_tree_priority(tree_priority);
+
+ if (pending_priority.IsHigherPriorityThan(active_priority))
+ return &active_iterator;
+ return &pending_iterator;
+}
+
+TileManager::EvictionTileIterator::EvictionOrderComparator::
+ EvictionOrderComparator(TreePriority tree_priority)
+ : tree_priority_(tree_priority) {}
+
+bool TileManager::EvictionTileIterator::EvictionOrderComparator::operator()(
+ PairedPictureLayerIterator* a,
+ PairedPictureLayerIterator* b) const {
+ PictureLayerImpl::LayerEvictionTileIterator* a_iterator =
+ a->NextTileIterator(tree_priority_);
+ DCHECK(a_iterator);
+ DCHECK(*a_iterator);
+
+ PictureLayerImpl::LayerEvictionTileIterator* b_iterator =
+ b->NextTileIterator(tree_priority_);
+ DCHECK(b_iterator);
+ DCHECK(*b_iterator);
+
+ Tile* a_tile = **a_iterator;
+ Tile* b_tile = **b_iterator;
+
+ const TilePriority& a_priority =
+ a_tile->priority_for_tree_priority(tree_priority_);
+ const TilePriority& b_priority =
+ b_tile->priority_for_tree_priority(tree_priority_);
+ bool prioritize_low_res = tree_priority_ == SMOOTHNESS_TAKES_PRIORITY;
+
+ // Now we have to return true iff b is lower priority than a.
+
+ // If the bin is the same but the resolution is not, then the order will be
+ // determined by whether we prioritize low res or not.
+ // TODO(vmpstr): Remove this when TilePriority is no longer a member of Tile
+ // class but instead produced by the iterators.
+ if (b_priority.priority_bin == a_priority.priority_bin &&
+ b_priority.resolution != a_priority.resolution) {
+ // Non ideal resolution should be sorted higher than other resolutions.
+ if (a_priority.resolution == NON_IDEAL_RESOLUTION)
+ return false;
+
+ if (b_priority.resolution == NON_IDEAL_RESOLUTION)
+ return true;
+
+ if (prioritize_low_res)
+ return a_priority.resolution == LOW_RESOLUTION;
+
+ return a_priority.resolution == HIGH_RESOLUTION;
+ }
+ return a_priority.IsHigherPriorityThan(b_priority);
+}
+
+void TileManager::SetRasterizerForTesting(Rasterizer* rasterizer) {
+ rasterizer_ = rasterizer;
+ rasterizer_->SetClient(this);
+}
+
+bool TileManager::IsReadyToActivate() const {
+ const std::vector<PictureLayerImpl*>& layers = client_->GetPictureLayers();
+
+ for (std::vector<PictureLayerImpl*>::const_iterator it = layers.begin();
+ it != layers.end();
+ ++it) {
+ if (!(*it)->AllTilesRequiredForActivationAreReadyToDraw())
+ return false;
+ }
+
+ return true;
+}
+
+void TileManager::CheckIfReadyToActivate() {
+ TRACE_EVENT0("cc", "TileManager::CheckIfReadyToActivate");
+
+ rasterizer_->CheckForCompletedTasks();
+ did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
+
+ if (IsReadyToActivate())
+ client_->NotifyReadyToActivate();
+}
+
} // namespace cc
diff --git a/chromium/cc/resources/tile_manager.h b/chromium/cc/resources/tile_manager.h
index 78beb1b15fb..5ad80910f8e 100644
--- a/chromium/cc/resources/tile_manager.h
+++ b/chromium/cc/resources/tile_manager.h
@@ -5,20 +5,24 @@
#ifndef CC_RESOURCES_TILE_MANAGER_H_
#define CC_RESOURCES_TILE_MANAGER_H_
+#include <deque>
#include <queue>
#include <set>
+#include <utility>
#include <vector>
#include "base/containers/hash_tables.h"
#include "base/memory/scoped_ptr.h"
#include "base/values.h"
#include "cc/base/ref_counted_managed.h"
+#include "cc/base/unique_notifier.h"
#include "cc/debug/rendering_stats_instrumentation.h"
+#include "cc/layers/picture_layer_impl.h"
#include "cc/resources/managed_tile_state.h"
#include "cc/resources/memory_history.h"
#include "cc/resources/picture_pile_impl.h"
#include "cc/resources/prioritized_tile_set.h"
-#include "cc/resources/raster_worker_pool.h"
+#include "cc/resources/rasterizer.h"
#include "cc/resources/resource_pool.h"
#include "cc/resources/tile.h"
@@ -27,8 +31,19 @@ class ResourceProvider;
class CC_EXPORT TileManagerClient {
public:
+ // Returns the set of layers that the tile manager should consider for raster.
+ virtual const std::vector<PictureLayerImpl*>& GetPictureLayers() = 0;
+
+ // Called when all tiles marked as required for activation are ready to draw.
virtual void NotifyReadyToActivate() = 0;
+ // Called when the visible representation of a tile might have changed. Some
+ // examples are:
+ // - Tile version initialized.
+ // - Tile resources freed.
+ // - Tile marked for on-demand raster.
+ virtual void NotifyTileStateChanged(const Tile* tile) = 0;
+
protected:
virtual ~TileManagerClient() {}
};
@@ -46,18 +61,114 @@ scoped_ptr<base::Value> RasterTaskCompletionStatsAsValue(
// should no longer have any memory assigned to them. Tile objects are "owned"
// by layers; they automatically register with the manager when they are
// created, and unregister from the manager when they are deleted.
-class CC_EXPORT TileManager : public RasterWorkerPoolClient,
+class CC_EXPORT TileManager : public RasterizerClient,
public RefCountedManager<Tile> {
public:
+ struct CC_EXPORT PairedPictureLayer {
+ PairedPictureLayer();
+ ~PairedPictureLayer();
+
+ PictureLayerImpl* active_layer;
+ PictureLayerImpl* pending_layer;
+ };
+
+ class CC_EXPORT RasterTileIterator {
+ public:
+ RasterTileIterator(TileManager* tile_manager, TreePriority tree_priority);
+ ~RasterTileIterator();
+
+ RasterTileIterator& operator++();
+ operator bool() const;
+ Tile* operator*();
+
+ private:
+ struct PairedPictureLayerIterator {
+ PairedPictureLayerIterator();
+ ~PairedPictureLayerIterator();
+
+ Tile* PeekTile(TreePriority tree_priority);
+ void PopTile(TreePriority tree_priority);
+
+ std::pair<PictureLayerImpl::LayerRasterTileIterator*, WhichTree>
+ NextTileIterator(TreePriority tree_priority);
+
+ PictureLayerImpl::LayerRasterTileIterator active_iterator;
+ PictureLayerImpl::LayerRasterTileIterator pending_iterator;
+
+ std::vector<Tile*> returned_shared_tiles;
+ };
+
+ class RasterOrderComparator {
+ public:
+ explicit RasterOrderComparator(TreePriority tree_priority);
+
+ bool operator()(PairedPictureLayerIterator* a,
+ PairedPictureLayerIterator* b) const;
+
+ private:
+ TreePriority tree_priority_;
+ };
+
+ std::vector<PairedPictureLayerIterator> paired_iterators_;
+ std::vector<PairedPictureLayerIterator*> iterator_heap_;
+ TreePriority tree_priority_;
+ RasterOrderComparator comparator_;
+
+ DISALLOW_COPY_AND_ASSIGN(RasterTileIterator);
+ };
+
+ struct CC_EXPORT EvictionTileIterator {
+ public:
+ EvictionTileIterator();
+ EvictionTileIterator(TileManager* tile_manager, TreePriority tree_priority);
+ ~EvictionTileIterator();
+
+ EvictionTileIterator& operator++();
+ operator bool() const;
+ Tile* operator*();
+
+ private:
+ struct PairedPictureLayerIterator {
+ PairedPictureLayerIterator();
+ ~PairedPictureLayerIterator();
+
+ Tile* PeekTile(TreePriority tree_priority);
+ void PopTile(TreePriority tree_priority);
+
+ PictureLayerImpl::LayerEvictionTileIterator* NextTileIterator(
+ TreePriority tree_priority);
+
+ PictureLayerImpl::LayerEvictionTileIterator active_iterator;
+ PictureLayerImpl::LayerEvictionTileIterator pending_iterator;
+
+ std::vector<Tile*> returned_shared_tiles;
+ };
+
+ class EvictionOrderComparator {
+ public:
+ explicit EvictionOrderComparator(TreePriority tree_priority);
+
+ bool operator()(PairedPictureLayerIterator* a,
+ PairedPictureLayerIterator* b) const;
+
+ private:
+ TreePriority tree_priority_;
+ };
+
+ std::vector<PairedPictureLayerIterator> paired_iterators_;
+ std::vector<PairedPictureLayerIterator*> iterator_heap_;
+ TreePriority tree_priority_;
+ EvictionOrderComparator comparator_;
+
+ DISALLOW_COPY_AND_ASSIGN(EvictionTileIterator);
+ };
+
static scoped_ptr<TileManager> Create(
TileManagerClient* client,
- ResourceProvider* resource_provider,
- size_t num_raster_threads,
- RenderingStatsInstrumentation* rendering_stats_instrumentation,
- bool use_map_image,
- size_t max_transfer_buffer_usage_bytes,
- size_t max_raster_usage_bytes,
- GLenum map_image_texture_target);
+ base::SequencedTaskRunner* task_runner,
+ ResourcePool* resource_pool,
+ Rasterizer* rasterizer,
+ RenderingStatsInstrumentation* rendering_stats_instrumentation);
virtual ~TileManager();
void ManageTiles(const GlobalStateThatImpactsTilePriority& state);
@@ -66,9 +177,9 @@ class CC_EXPORT TileManager : public RasterWorkerPoolClient,
bool UpdateVisibleTiles();
scoped_refptr<Tile> CreateTile(PicturePileImpl* picture_pile,
- gfx::Size tile_size,
- gfx::Rect content_rect,
- gfx::Rect opaque_rect,
+ const gfx::Size& tile_size,
+ const gfx::Rect& content_rect,
+ const gfx::Rect& opaque_rect,
float contents_scale,
int layer_id,
int source_frame_number,
@@ -76,52 +187,53 @@ class CC_EXPORT TileManager : public RasterWorkerPoolClient,
scoped_ptr<base::Value> BasicStateAsValue() const;
scoped_ptr<base::Value> AllTilesAsValue() const;
- void GetMemoryStats(size_t* memory_required_bytes,
- size_t* memory_nice_to_have_bytes,
- size_t* memory_allocated_bytes,
- size_t* memory_used_bytes) const;
-
const MemoryHistory::Entry& memory_stats_from_last_assign() const {
return memory_stats_from_last_assign_;
}
- void InitializeTilesWithResourcesForTesting(
- const std::vector<Tile*>& tiles,
- ResourceProvider* resource_provider) {
+ void GetPairedPictureLayers(std::vector<PairedPictureLayer>* layers) const;
+
+ void InitializeTilesWithResourcesForTesting(const std::vector<Tile*>& tiles) {
for (size_t i = 0; i < tiles.size(); ++i) {
ManagedTileState& mts = tiles[i]->managed_state();
ManagedTileState::TileVersion& tile_version =
- mts.tile_versions[HIGH_QUALITY_NO_LCD_RASTER_MODE];
+ mts.tile_versions[HIGH_QUALITY_RASTER_MODE];
- tile_version.resource_ = resource_pool_->AcquireResource(
- gfx::Size(1, 1));
+ tile_version.resource_ = resource_pool_->AcquireResource(gfx::Size(1, 1));
bytes_releasable_ += BytesConsumedIfAllocated(tiles[i]);
++resources_releasable_;
}
}
- RasterWorkerPool* RasterWorkerPoolForTesting() {
- return raster_worker_pool_.get();
+
+ void ReleaseTileResourcesForTesting(const std::vector<Tile*>& tiles) {
+ for (size_t i = 0; i < tiles.size(); ++i) {
+ Tile* tile = tiles[i];
+ for (int mode = 0; mode < NUM_RASTER_MODES; ++mode) {
+ FreeResourceForTile(tile, static_cast<RasterMode>(mode));
+ }
+ }
}
void SetGlobalStateForTesting(
const GlobalStateThatImpactsTilePriority& state) {
+ // Soft limit is used for resource pool such that
+ // memory returns to soft limit after going over.
if (state != global_state_) {
global_state_ = state;
prioritized_tiles_dirty_ = true;
- resource_pool_->SetResourceUsageLimits(
- global_state_.memory_limit_in_bytes,
- global_state_.unused_memory_limit_in_bytes,
- global_state_.num_resources_limit);
}
}
+ void SetRasterizerForTesting(Rasterizer* rasterizer);
+
+ void CleanUpReleasedTilesForTesting() { CleanUpReleasedTiles(); }
+
protected:
TileManager(TileManagerClient* client,
- ResourceProvider* resource_provider,
- scoped_ptr<RasterWorkerPool> raster_worker_pool,
- size_t num_raster_threads,
- size_t max_raster_usage_bytes,
+ base::SequencedTaskRunner* task_runner,
+ ResourcePool* resource_pool,
+ Rasterizer* rasterizer,
RenderingStatsInstrumentation* rendering_stats_instrumentation);
// Methods called by Tile
@@ -133,9 +245,8 @@ class CC_EXPORT TileManager : public RasterWorkerPoolClient,
// Overriden from RefCountedManager<Tile>:
virtual void Release(Tile* tile) OVERRIDE;
- // Overriden from RasterWorkerPoolClient:
- virtual bool ShouldForceTasksRequiredForActivationToComplete() const
- OVERRIDE;
+ // Overriden from RasterizerClient:
+ virtual bool ShouldForceTasksRequiredForActivationToComplete() const OVERRIDE;
virtual void DidFinishRunningTasks() OVERRIDE;
virtual void DidFinishRunningTasksRequiredForActivation() OVERRIDE;
@@ -146,16 +257,14 @@ class CC_EXPORT TileManager : public RasterWorkerPoolClient,
virtual void ScheduleTasks(
const TileVector& tiles_that_need_to_be_rasterized);
- void AssignGpuMemoryToTiles(
- PrioritizedTileSet* tiles,
- TileVector* tiles_that_need_to_be_rasterized);
+ void AssignGpuMemoryToTiles(PrioritizedTileSet* tiles,
+ TileVector* tiles_that_need_to_be_rasterized);
void GetTilesWithAssignedBins(PrioritizedTileSet* tiles);
private:
- void OnImageDecodeTaskCompleted(
- int layer_id,
- skia::LazyPixelRef* pixel_ref,
- bool was_canceled);
+ void OnImageDecodeTaskCompleted(int layer_id,
+ SkPixelRef* pixel_ref,
+ bool was_canceled);
void OnRasterTaskCompleted(Tile::Id tile,
scoped_ptr<ScopedResource> resource,
RasterMode raster_mode,
@@ -164,22 +273,25 @@ class CC_EXPORT TileManager : public RasterWorkerPoolClient,
inline size_t BytesConsumedIfAllocated(const Tile* tile) const {
return Resource::MemorySizeBytes(tile->size(),
- raster_worker_pool_->GetResourceFormat());
+ resource_pool_->resource_format());
}
- RasterMode DetermineRasterMode(const Tile* tile) const;
void FreeResourceForTile(Tile* tile, RasterMode mode);
void FreeResourcesForTile(Tile* tile);
void FreeUnusedResourcesForTile(Tile* tile);
- RasterWorkerPool::Task CreateImageDecodeTask(
- Tile* tile, skia::LazyPixelRef* pixel_ref);
- RasterWorkerPool::RasterTask CreateRasterTask(Tile* tile);
- scoped_ptr<base::Value> GetMemoryRequirementsAsValue() const;
+ void FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(Tile* tile);
+ scoped_refptr<ImageDecodeTask> CreateImageDecodeTask(Tile* tile,
+ SkPixelRef* pixel_ref);
+ scoped_refptr<RasterTask> CreateRasterTask(Tile* tile);
void UpdatePrioritizedTileSetIfNeeded();
+ bool IsReadyToActivate() const;
+ void CheckIfReadyToActivate();
+
TileManagerClient* client_;
- scoped_ptr<ResourcePool> resource_pool_;
- scoped_ptr<RasterWorkerPool> raster_worker_pool_;
+ scoped_refptr<base::SequencedTaskRunner> task_runner_;
+ ResourcePool* resource_pool_;
+ Rasterizer* rasterizer_;
GlobalStateThatImpactsTilePriority global_state_;
typedef base::hash_map<Tile::Id, Tile*> TileMap;
@@ -191,12 +303,8 @@ class CC_EXPORT TileManager : public RasterWorkerPoolClient,
bool all_tiles_that_need_to_be_rasterized_have_memory_;
bool all_tiles_required_for_activation_have_memory_;
- size_t memory_required_bytes_;
- size_t memory_nice_to_have_bytes_;
-
size_t bytes_releasable_;
size_t resources_releasable_;
- size_t max_raster_usage_bytes_;
bool ever_exceeded_memory_budget_;
MemoryHistory::Entry memory_stats_from_last_assign_;
@@ -206,7 +314,8 @@ class CC_EXPORT TileManager : public RasterWorkerPoolClient,
bool did_initialize_visible_tile_;
bool did_check_for_completed_tasks_since_last_schedule_tasks_;
- typedef base::hash_map<uint32_t, RasterWorkerPool::Task> PixelRefTaskMap;
+ typedef base::hash_map<uint32_t, scoped_refptr<ImageDecodeTask> >
+ PixelRefTaskMap;
typedef base::hash_map<int, PixelRefTaskMap> LayerPixelRefTaskMap;
LayerPixelRefTaskMap image_decode_tasks_;
@@ -217,6 +326,15 @@ class CC_EXPORT TileManager : public RasterWorkerPoolClient,
std::vector<Tile*> released_tiles_;
+ ResourceFormat resource_format_;
+
+ // Queue used when scheduling raster tasks.
+ RasterTaskQueue raster_queue_;
+
+ std::vector<scoped_refptr<RasterTask> > orphan_raster_tasks_;
+
+ UniqueNotifier ready_to_activate_check_notifier_;
+
DISALLOW_COPY_AND_ASSIGN(TileManager);
};
diff --git a/chromium/cc/resources/tile_manager_perftest.cc b/chromium/cc/resources/tile_manager_perftest.cc
index 9a651a2afa4..cc54fbb633c 100644
--- a/chromium/cc/resources/tile_manager_perftest.cc
+++ b/chromium/cc/resources/tile_manager_perftest.cc
@@ -3,15 +3,21 @@
// found in the LICENSE file.
#include "base/time/time.h"
+#include "cc/debug/lap_timer.h"
#include "cc/resources/tile.h"
#include "cc/resources/tile_priority.h"
+#include "cc/test/fake_impl_proxy.h"
+#include "cc/test/fake_layer_tree_host_impl.h"
#include "cc/test/fake_output_surface.h"
#include "cc/test/fake_output_surface_client.h"
+#include "cc/test/fake_picture_layer_impl.h"
#include "cc/test/fake_picture_pile_impl.h"
#include "cc/test/fake_tile_manager.h"
#include "cc/test/fake_tile_manager_client.h"
-#include "cc/test/lap_timer.h"
+#include "cc/test/impl_side_painting_settings.h"
+#include "cc/test/test_shared_bitmap_manager.h"
#include "cc/test/test_tile_priorities.h"
+#include "cc/trees/layer_tree_impl.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/perf/perf_test.h"
@@ -24,166 +30,308 @@ static const int kTimeLimitMillis = 2000;
static const int kWarmupRuns = 5;
static const int kTimeCheckInterval = 10;
-class TileManagerPerfTest : public testing::Test {
+class FakeRasterizerImpl : public Rasterizer, public RasterizerTaskClient {
public:
- typedef std::vector<std::pair<scoped_refptr<Tile>, ManagedTileBin> >
- TileBinVector;
+ // Overridden from Rasterizer:
+ virtual void SetClient(RasterizerClient* client) OVERRIDE {}
+ virtual void Shutdown() OVERRIDE {}
+ virtual void ScheduleTasks(RasterTaskQueue* queue) OVERRIDE {
+ for (RasterTaskQueue::Item::Vector::const_iterator it =
+ queue->items.begin();
+ it != queue->items.end();
+ ++it) {
+ RasterTask* task = it->task;
+
+ task->WillSchedule();
+ task->ScheduleOnOriginThread(this);
+ task->DidSchedule();
+
+ completed_tasks_.push_back(task);
+ }
+ }
+ virtual void CheckForCompletedTasks() OVERRIDE {
+ for (RasterTask::Vector::iterator it = completed_tasks_.begin();
+ it != completed_tasks_.end();
+ ++it) {
+ RasterTask* task = it->get();
+
+ task->WillComplete();
+ task->CompleteOnOriginThread(this);
+ task->DidComplete();
+
+ task->RunReplyOnOriginThread();
+ }
+ completed_tasks_.clear();
+ }
+
+ // Overridden from RasterizerTaskClient:
+ virtual SkCanvas* AcquireCanvasForRaster(RasterTask* task) OVERRIDE {
+ return NULL;
+ }
+ virtual void ReleaseCanvasForRaster(RasterTask* task) OVERRIDE {}
+ private:
+ RasterTask::Vector completed_tasks_;
+};
+base::LazyInstance<FakeRasterizerImpl> g_fake_rasterizer =
+ LAZY_INSTANCE_INITIALIZER;
+
+class TileManagerPerfTest : public testing::Test {
+ public:
TileManagerPerfTest()
- : timer_(kWarmupRuns,
+ : memory_limit_policy_(ALLOW_ANYTHING),
+ max_tiles_(10000),
+ id_(7),
+ proxy_(base::MessageLoopProxy::current()),
+ host_impl_(ImplSidePaintingSettings(10000),
+ &proxy_,
+ &shared_bitmap_manager_),
+ timer_(kWarmupRuns,
base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
kTimeCheckInterval) {}
- // Overridden from testing::Test:
+ void SetTreePriority(TreePriority tree_priority) {
+ GlobalStateThatImpactsTilePriority state;
+ gfx::Size tile_size(256, 256);
+
+ state.soft_memory_limit_in_bytes = 100 * 1000 * 1000;
+ state.num_resources_limit = max_tiles_;
+ state.hard_memory_limit_in_bytes = state.soft_memory_limit_in_bytes * 2;
+ state.memory_limit_policy = memory_limit_policy_;
+ state.tree_priority = tree_priority;
+
+ global_state_ = state;
+ host_impl_.resource_pool()->SetResourceUsageLimits(
+ state.soft_memory_limit_in_bytes, 0, state.num_resources_limit);
+ host_impl_.tile_manager()->SetGlobalStateForTesting(state);
+ }
+
virtual void SetUp() OVERRIDE {
- output_surface_ = FakeOutputSurface::Create3d();
- CHECK(output_surface_->BindToClient(&output_surface_client_));
+ picture_pile_ = FakePicturePileImpl::CreateInfiniteFilledPile();
+ InitializeRenderer();
+ SetTreePriority(SAME_PRIORITY_FOR_BOTH_TREES);
+ }
- resource_provider_ =
- ResourceProvider::Create(output_surface_.get(), NULL, 0, false, 1);
- size_t raster_task_limit_bytes = 32 * 1024 * 1024; // 16-64MB in practice.
- tile_manager_ = make_scoped_ptr(
- new FakeTileManager(&tile_manager_client_,
- resource_provider_.get(),
- raster_task_limit_bytes));
- picture_pile_ = FakePicturePileImpl::CreatePile();
+ virtual void InitializeRenderer() {
+ host_impl_.InitializeRenderer(
+ FakeOutputSurface::Create3d().PassAs<OutputSurface>());
+ tile_manager()->SetRasterizerForTesting(g_fake_rasterizer.Pointer());
}
- GlobalStateThatImpactsTilePriority GlobalStateForTest() {
- GlobalStateThatImpactsTilePriority state;
- gfx::Size tile_size = settings_.default_tile_size;
- state.memory_limit_in_bytes =
- 10000u * 4u *
- static_cast<size_t>(tile_size.width() * tile_size.height());
- state.num_resources_limit = 10000;
- state.memory_limit_policy = ALLOW_ANYTHING;
- state.tree_priority = SMOOTHNESS_TAKES_PRIORITY;
- return state;
+ void SetupDefaultTrees(const gfx::Size& layer_bounds) {
+ gfx::Size tile_size(100, 100);
+
+ scoped_refptr<FakePicturePileImpl> pending_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+ scoped_refptr<FakePicturePileImpl> active_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+
+ SetupTrees(pending_pile, active_pile);
}
- virtual void TearDown() OVERRIDE {
- tile_manager_.reset(NULL);
- picture_pile_ = NULL;
- }
-
- TilePriority GetTilePriorityFromBin(ManagedTileBin bin) {
- switch (bin) {
- case NOW_AND_READY_TO_DRAW_BIN:
- case NOW_BIN:
- return TilePriorityForNowBin();
- case SOON_BIN:
- return TilePriorityForSoonBin();
- case EVENTUALLY_AND_ACTIVE_BIN:
- case EVENTUALLY_BIN:
- return TilePriorityForEventualBin();
- case AT_LAST_BIN:
- case AT_LAST_AND_ACTIVE_BIN:
- case NEVER_BIN:
- return TilePriority();
- default:
- NOTREACHED();
- return TilePriority();
- }
+ void ActivateTree() {
+ host_impl_.ActivatePendingTree();
+ CHECK(!host_impl_.pending_tree());
+ pending_root_layer_ = NULL;
+ active_root_layer_ = static_cast<FakePictureLayerImpl*>(
+ host_impl_.active_tree()->LayerById(id_));
}
- ManagedTileBin GetNextBin(ManagedTileBin bin) {
- switch (bin) {
- case NOW_AND_READY_TO_DRAW_BIN:
- case NOW_BIN:
- return SOON_BIN;
- case SOON_BIN:
- return EVENTUALLY_BIN;
- case EVENTUALLY_AND_ACTIVE_BIN:
- case EVENTUALLY_BIN:
- return NEVER_BIN;
- case AT_LAST_BIN:
- case AT_LAST_AND_ACTIVE_BIN:
- case NEVER_BIN:
- return NOW_BIN;
- default:
- NOTREACHED();
- return NEVER_BIN;
- }
+ void SetupDefaultTreesWithFixedTileSize(const gfx::Size& layer_bounds,
+ const gfx::Size& tile_size) {
+ SetupDefaultTrees(layer_bounds);
+ pending_root_layer_->set_fixed_tile_size(tile_size);
+ active_root_layer_->set_fixed_tile_size(tile_size);
+ }
+
+ void SetupTrees(scoped_refptr<PicturePileImpl> pending_pile,
+ scoped_refptr<PicturePileImpl> active_pile) {
+ SetupPendingTree(active_pile);
+ ActivateTree();
+ SetupPendingTree(pending_pile);
+ }
+
+ void SetupPendingTree(scoped_refptr<PicturePileImpl> pile) {
+ host_impl_.CreatePendingTree();
+ LayerTreeImpl* pending_tree = host_impl_.pending_tree();
+ // Clear recycled tree.
+ pending_tree->DetachLayerTree();
+
+ scoped_ptr<FakePictureLayerImpl> pending_layer =
+ FakePictureLayerImpl::CreateWithPile(pending_tree, id_, pile);
+ pending_layer->SetDrawsContent(true);
+ pending_tree->SetRootLayer(pending_layer.PassAs<LayerImpl>());
+
+ pending_root_layer_ = static_cast<FakePictureLayerImpl*>(
+ host_impl_.pending_tree()->LayerById(id_));
+ pending_root_layer_->DoPostCommitInitializationIfNeeded();
}
- void CreateBinTiles(int count, ManagedTileBin bin, TileBinVector* tiles) {
- for (int i = 0; i < count; ++i) {
- scoped_refptr<Tile> tile =
- tile_manager_->CreateTile(picture_pile_.get(),
- settings_.default_tile_size,
- gfx::Rect(),
- gfx::Rect(),
- 1.0,
- 0,
- 0,
- Tile::USE_LCD_TEXT);
- tile->SetPriority(ACTIVE_TREE, GetTilePriorityFromBin(bin));
- tile->SetPriority(PENDING_TREE, GetTilePriorityFromBin(bin));
- tiles->push_back(std::make_pair(tile, bin));
+ void CreateHighLowResAndSetAllTilesVisible() {
+ // Active layer must get updated first so pending layer can share from it.
+ active_root_layer_->CreateDefaultTilingsAndTiles();
+ active_root_layer_->SetAllTilesVisible();
+ pending_root_layer_->CreateDefaultTilingsAndTiles();
+ pending_root_layer_->SetAllTilesVisible();
+ }
+
+ void RunRasterIteratorTest(const std::string& test_name,
+ unsigned tile_count) {
+ timer_.Reset();
+ do {
+ int count = tile_count;
+ for (TileManager::RasterTileIterator it(tile_manager(),
+ SAME_PRIORITY_FOR_BOTH_TREES);
+ it && count;
+ ++it) {
+ --count;
+ }
+ ASSERT_EQ(0, count);
+ timer_.NextLap();
+ } while (!timer_.HasTimeLimitExpired());
+
+ perf_test::PrintResult("tile_manager_raster_tile_iterator",
+ "",
+ test_name,
+ timer_.LapsPerSecond(),
+ "runs/s",
+ true);
+ }
+
+ std::vector<LayerImpl*> CreateLayers(int layer_count,
+ int tiles_per_layer_count) {
+ // Compute the width/height required for high res to get
+ // tiles_per_layer_count tiles.
+ float width = std::sqrt(static_cast<float>(tiles_per_layer_count));
+ float height = tiles_per_layer_count / width;
+
+ // Adjust the width and height to account for the fact that tiles
+ // are bigger than 1x1. Also, account for the fact that that we
+ // will be creating one high res and one low res tiling. That is,
+ // width and height should be smaller by sqrt(1 + low_res_scale).
+ // This gives us _approximately_ correct counts.
+ width *= settings_.default_tile_size.width() /
+ std::sqrt(1 + settings_.low_res_contents_scale_factor);
+ height *= settings_.default_tile_size.height() /
+ std::sqrt(1 + settings_.low_res_contents_scale_factor);
+
+ // Ensure that we start with blank trees and no tiles.
+ host_impl_.ResetTreesForTesting();
+ tile_manager()->CleanUpReleasedTilesForTesting();
+
+ gfx::Size layer_bounds(width, height);
+ gfx::Size viewport(width / 5, height / 5);
+ host_impl_.SetViewportSize(viewport);
+ SetupDefaultTreesWithFixedTileSize(layer_bounds,
+ settings_.default_tile_size);
+
+ active_root_layer_->CreateDefaultTilingsAndTiles();
+ pending_root_layer_->CreateDefaultTilingsAndTiles();
+
+ std::vector<LayerImpl*> layers;
+
+ // Pending layer counts as one layer.
+ layers.push_back(pending_root_layer_);
+ int next_id = id_ + 1;
+
+ // Create the rest of the layers as children of the root layer.
+ while (static_cast<int>(layers.size()) < layer_count) {
+ scoped_ptr<FakePictureLayerImpl> layer =
+ FakePictureLayerImpl::CreateWithPile(
+ host_impl_.pending_tree(), next_id, picture_pile_);
+ layer->SetBounds(layer_bounds);
+ layers.push_back(layer.get());
+ pending_root_layer_->AddChild(layer.PassAs<LayerImpl>());
+
+ FakePictureLayerImpl* fake_layer =
+ static_cast<FakePictureLayerImpl*>(layers.back());
+
+ fake_layer->SetDrawsContent(true);
+ fake_layer->DoPostCommitInitializationIfNeeded();
+ fake_layer->CreateDefaultTilingsAndTiles();
+ ++next_id;
}
+
+ return layers;
}
- void CreateTiles(int count, TileBinVector* tiles) {
- // Roughly an equal amount of all bins.
- int count_per_bin = count / NUM_BINS;
- CreateBinTiles(count_per_bin, NOW_BIN, tiles);
- CreateBinTiles(count_per_bin, SOON_BIN, tiles);
- CreateBinTiles(count_per_bin, EVENTUALLY_BIN, tiles);
- CreateBinTiles(count - 3 * count_per_bin, NEVER_BIN, tiles);
+ GlobalStateThatImpactsTilePriority GlobalStateForTest() {
+ GlobalStateThatImpactsTilePriority state;
+ gfx::Size tile_size = settings_.default_tile_size;
+ state.soft_memory_limit_in_bytes =
+ 10000u * 4u *
+ static_cast<size_t>(tile_size.width() * tile_size.height());
+ state.hard_memory_limit_in_bytes = state.soft_memory_limit_in_bytes;
+ state.num_resources_limit = 10000;
+ state.memory_limit_policy = ALLOW_ANYTHING;
+ state.tree_priority = SMOOTHNESS_TAKES_PRIORITY;
+ return state;
}
void RunManageTilesTest(const std::string& test_name,
- unsigned tile_count,
- int priority_change_percent) {
- DCHECK_GE(tile_count, 100u);
- DCHECK_GE(priority_change_percent, 0);
- DCHECK_LE(priority_change_percent, 100);
- TileBinVector tiles;
- CreateTiles(tile_count, &tiles);
+ int layer_count,
+ int approximate_tile_count_per_layer) {
+ std::vector<LayerImpl*> layers =
+ CreateLayers(layer_count, approximate_tile_count_per_layer);
timer_.Reset();
do {
- if (priority_change_percent > 0) {
- for (unsigned i = 0;
- i < tile_count;
- i += 100 / priority_change_percent) {
- Tile* tile = tiles[i].first.get();
- ManagedTileBin bin = GetNextBin(tiles[i].second);
- tile->SetPriority(ACTIVE_TREE, GetTilePriorityFromBin(bin));
- tile->SetPriority(PENDING_TREE, GetTilePriorityFromBin(bin));
- tiles[i].second = bin;
- }
- }
+ host_impl_.UpdateCurrentFrameTime();
+ for (unsigned i = 0; i < layers.size(); ++i)
+ layers[i]->UpdateTiles();
- tile_manager_->ManageTiles(GlobalStateForTest());
- tile_manager_->CheckForCompletedTasks();
+ GlobalStateThatImpactsTilePriority global_state(GlobalStateForTest());
+ tile_manager()->ManageTiles(global_state);
+ tile_manager()->UpdateVisibleTiles();
timer_.NextLap();
+ host_impl_.ResetCurrentFrameTimeForNextFrame();
} while (!timer_.HasTimeLimitExpired());
- perf_test::PrintResult("manage_tiles", "", test_name,
- timer_.LapsPerSecond(), "runs/s", true);
+ perf_test::PrintResult(
+ "manage_tiles", "", test_name, timer_.LapsPerSecond(), "runs/s", true);
}
- private:
- FakeTileManagerClient tile_manager_client_;
- LayerTreeSettings settings_;
- scoped_ptr<FakeTileManager> tile_manager_;
- scoped_refptr<FakePicturePileImpl> picture_pile_;
- FakeOutputSurfaceClient output_surface_client_;
- scoped_ptr<FakeOutputSurface> output_surface_;
- scoped_ptr<ResourceProvider> resource_provider_;
+ TileManager* tile_manager() { return host_impl_.tile_manager(); }
+
+ protected:
+ GlobalStateThatImpactsTilePriority global_state_;
+
+ TestSharedBitmapManager shared_bitmap_manager_;
+ TileMemoryLimitPolicy memory_limit_policy_;
+ int max_tiles_;
+ int id_;
+ FakeImplProxy proxy_;
+ FakeLayerTreeHostImpl host_impl_;
+ FakePictureLayerImpl* pending_root_layer_;
+ FakePictureLayerImpl* active_root_layer_;
LapTimer timer_;
+ scoped_refptr<FakePicturePileImpl> picture_pile_;
+ LayerTreeSettings settings_;
};
TEST_F(TileManagerPerfTest, ManageTiles) {
- RunManageTilesTest("100_0", 100, 0);
- RunManageTilesTest("1000_0", 1000, 0);
- RunManageTilesTest("10000_0", 10000, 0);
- RunManageTilesTest("100_10", 100, 10);
- RunManageTilesTest("1000_10", 1000, 10);
- RunManageTilesTest("10000_10", 10000, 10);
+ RunManageTilesTest("1_100", 1, 100);
+ RunManageTilesTest("1_500", 1, 500);
+ RunManageTilesTest("1_1000", 1, 1000);
+ RunManageTilesTest("5_100", 5, 100);
+ RunManageTilesTest("5_500", 5, 500);
+ RunManageTilesTest("5_1000", 5, 1000);
+ RunManageTilesTest("10_100", 10, 100);
+ RunManageTilesTest("10_500", 10, 500);
+ RunManageTilesTest("10_1000", 10, 1000);
RunManageTilesTest("100_100", 100, 100);
- RunManageTilesTest("1000_100", 1000, 100);
- RunManageTilesTest("10000_100", 10000, 100);
+ RunManageTilesTest("100_500", 100, 500);
+ RunManageTilesTest("100_1000", 100, 1000);
+}
+
+TEST_F(TileManagerPerfTest, RasterTileIterator) {
+ SetupDefaultTrees(gfx::Size(10000, 10000));
+ active_root_layer_->CreateDefaultTilingsAndTiles();
+ pending_root_layer_->CreateDefaultTilingsAndTiles();
+
+ RunRasterIteratorTest("2_16", 16);
+ RunRasterIteratorTest("2_32", 32);
+ RunRasterIteratorTest("2_64", 64);
+ RunRasterIteratorTest("2_128", 128);
}
} // namespace
diff --git a/chromium/cc/resources/tile_manager_unittest.cc b/chromium/cc/resources/tile_manager_unittest.cc
index 8339bd07b0a..f894c4f9c98 100644
--- a/chromium/cc/resources/tile_manager_unittest.cc
+++ b/chromium/cc/resources/tile_manager_unittest.cc
@@ -4,66 +4,75 @@
#include "cc/resources/tile.h"
#include "cc/resources/tile_priority.h"
+#include "cc/test/fake_impl_proxy.h"
+#include "cc/test/fake_layer_tree_host_impl.h"
#include "cc/test/fake_output_surface.h"
#include "cc/test/fake_output_surface_client.h"
+#include "cc/test/fake_picture_layer_impl.h"
#include "cc/test/fake_picture_pile_impl.h"
#include "cc/test/fake_tile_manager.h"
-#include "cc/test/fake_tile_manager_client.h"
+#include "cc/test/impl_side_painting_settings.h"
+#include "cc/test/test_shared_bitmap_manager.h"
#include "cc/test/test_tile_priorities.h"
+#include "cc/trees/layer_tree_impl.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace cc {
namespace {
-class TileManagerTest : public testing::TestWithParam<bool> {
+class TileManagerTest : public testing::TestWithParam<bool>,
+ public TileManagerClient {
public:
typedef std::vector<scoped_refptr<Tile> > TileVector;
+ TileManagerTest()
+ : memory_limit_policy_(ALLOW_ANYTHING),
+ max_tiles_(0),
+ ready_to_activate_(false) {}
+
void Initialize(int max_tiles,
TileMemoryLimitPolicy memory_limit_policy,
TreePriority tree_priority) {
output_surface_ = FakeOutputSurface::Create3d();
CHECK(output_surface_->BindToClient(&output_surface_client_));
- resource_provider_ =
- ResourceProvider::Create(output_surface_.get(), NULL, 0, false, 1);
- tile_manager_ = make_scoped_ptr(
- new FakeTileManager(&tile_manager_client_, resource_provider_.get()));
+ shared_bitmap_manager_.reset(new TestSharedBitmapManager());
+ resource_provider_ = ResourceProvider::Create(
+ output_surface_.get(), shared_bitmap_manager_.get(), 0, false, 1,
+ false);
+ resource_pool_ = ResourcePool::Create(
+ resource_provider_.get(), GL_TEXTURE_2D, RGBA_8888);
+ tile_manager_ =
+ make_scoped_ptr(new FakeTileManager(this, resource_pool_.get()));
memory_limit_policy_ = memory_limit_policy;
- max_memory_tiles_ = max_tiles;
+ max_tiles_ = max_tiles;
+ picture_pile_ = FakePicturePileImpl::CreateInfiniteFilledPile();
+
+ SetTreePriority(tree_priority);
+ }
+
+ void SetTreePriority(TreePriority tree_priority) {
GlobalStateThatImpactsTilePriority state;
gfx::Size tile_size = settings_.default_tile_size;
- // The parametrization specifies whether the max tile limit should
- // be applied to RAM or to tile limit.
- if (GetParam()) {
- state.memory_limit_in_bytes =
- max_tiles * 4 * tile_size.width() * tile_size.height();
+ if (UsingMemoryLimit()) {
+ state.soft_memory_limit_in_bytes =
+ max_tiles_ * 4 * tile_size.width() * tile_size.height();
state.num_resources_limit = 100;
} else {
- state.memory_limit_in_bytes = 100 * 1000 * 1000;
- state.num_resources_limit = max_tiles;
+ state.soft_memory_limit_in_bytes = 100 * 1000 * 1000;
+ state.num_resources_limit = max_tiles_;
}
- state.unused_memory_limit_in_bytes = state.memory_limit_in_bytes;
- state.memory_limit_policy = memory_limit_policy;
+ state.hard_memory_limit_in_bytes = state.soft_memory_limit_in_bytes * 2;
+ state.memory_limit_policy = memory_limit_policy_;
state.tree_priority = tree_priority;
global_state_ = state;
+ resource_pool_->SetResourceUsageLimits(state.soft_memory_limit_in_bytes,
+ state.soft_memory_limit_in_bytes,
+ state.num_resources_limit);
tile_manager_->SetGlobalStateForTesting(state);
- picture_pile_ = FakePicturePileImpl::CreatePile();
- }
-
- void SetTreePriority(TreePriority tree_priority) {
- GlobalStateThatImpactsTilePriority state;
- gfx::Size tile_size = settings_.default_tile_size;
- state.memory_limit_in_bytes =
- max_memory_tiles_ * 4 * tile_size.width() * tile_size.height();
- state.unused_memory_limit_in_bytes = state.memory_limit_in_bytes;
- state.memory_limit_policy = memory_limit_policy_;
- state.num_resources_limit = 100;
- state.tree_priority = tree_priority;
- global_state_ = state;
}
virtual void TearDown() OVERRIDE {
@@ -73,10 +82,17 @@ class TileManagerTest : public testing::TestWithParam<bool> {
testing::Test::TearDown();
}
+ // TileManagerClient implementation.
+ virtual const std::vector<PictureLayerImpl*>& GetPictureLayers() OVERRIDE {
+ return picture_layers_;
+ }
+ virtual void NotifyReadyToActivate() OVERRIDE { ready_to_activate_ = true; }
+ virtual void NotifyTileStateChanged(const Tile* tile) OVERRIDE {}
+
TileVector CreateTilesWithSize(int count,
TilePriority active_priority,
TilePriority pending_priority,
- gfx::Size tile_size) {
+ const gfx::Size& tile_size) {
TileVector tiles;
for (int i = 0; i < count; ++i) {
scoped_refptr<Tile> tile = tile_manager_->CreateTile(picture_pile_.get(),
@@ -86,7 +102,7 @@ class TileManagerTest : public testing::TestWithParam<bool> {
1.0,
0,
0,
- Tile::USE_LCD_TEXT);
+ 0);
tile->SetPriority(ACTIVE_TREE, active_priority);
tile->SetPriority(PENDING_TREE, pending_priority);
tiles.push_back(tile);
@@ -97,20 +113,15 @@ class TileManagerTest : public testing::TestWithParam<bool> {
TileVector CreateTiles(int count,
TilePriority active_priority,
TilePriority pending_priority) {
- return CreateTilesWithSize(count,
- active_priority,
- pending_priority,
- settings_.default_tile_size);
+ return CreateTilesWithSize(
+ count, active_priority, pending_priority, settings_.default_tile_size);
}
- FakeTileManager* tile_manager() {
- return tile_manager_.get();
- }
+ FakeTileManager* tile_manager() { return tile_manager_.get(); }
int AssignedMemoryCount(const TileVector& tiles) {
int has_memory_count = 0;
- for (TileVector::const_iterator it = tiles.begin();
- it != tiles.end();
+ for (TileVector::const_iterator it = tiles.begin(); it != tiles.end();
++it) {
if (tile_manager_->HasBeenAssignedMemory(*it))
++has_memory_count;
@@ -118,30 +129,29 @@ class TileManagerTest : public testing::TestWithParam<bool> {
return has_memory_count;
}
- int TilesWithLCDCount(const TileVector& tiles) {
- int has_lcd_count = 0;
- for (TileVector::const_iterator it = tiles.begin();
- it != tiles.end();
- ++it) {
- if ((*it)->GetRasterModeForTesting() == HIGH_QUALITY_RASTER_MODE)
- ++has_lcd_count;
- }
- return has_lcd_count;
- }
+ bool ready_to_activate() const { return ready_to_activate_; }
+
+ // The parametrization specifies whether the max tile limit should
+ // be applied to memory or resources.
+ bool UsingResourceLimit() { return !GetParam(); }
+ bool UsingMemoryLimit() { return GetParam(); }
protected:
GlobalStateThatImpactsTilePriority global_state_;
private:
- FakeTileManagerClient tile_manager_client_;
LayerTreeSettings settings_;
scoped_ptr<FakeTileManager> tile_manager_;
scoped_refptr<FakePicturePileImpl> picture_pile_;
FakeOutputSurfaceClient output_surface_client_;
scoped_ptr<FakeOutputSurface> output_surface_;
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager_;
scoped_ptr<ResourceProvider> resource_provider_;
+ scoped_ptr<ResourcePool> resource_pool_;
TileMemoryLimitPolicy memory_limit_policy_;
- int max_memory_tiles_;
+ int max_tiles_;
+ bool ready_to_activate_;
+ std::vector<PictureLayerImpl*> picture_layers_;
};
TEST_P(TileManagerTest, EnoughMemoryAllowAnything) {
@@ -152,8 +162,8 @@ TEST_P(TileManagerTest, EnoughMemoryAllowAnything) {
CreateTiles(3, TilePriorityForNowBin(), TilePriority());
TileVector pending_now =
CreateTiles(3, TilePriority(), TilePriorityForNowBin());
- TileVector active_pending_soon = CreateTiles(
- 3, TilePriorityForSoonBin(), TilePriorityForSoonBin());
+ TileVector active_pending_soon =
+ CreateTiles(3, TilePriorityForSoonBin(), TilePriorityForSoonBin());
TileVector never_bin = CreateTiles(1, TilePriority(), TilePriority());
tile_manager()->AssignMemoryToTiles(global_state_);
@@ -173,8 +183,8 @@ TEST_P(TileManagerTest, EnoughMemoryAllowPrepaintOnly) {
CreateTiles(3, TilePriorityForNowBin(), TilePriority());
TileVector pending_now =
CreateTiles(3, TilePriority(), TilePriorityForNowBin());
- TileVector active_pending_soon = CreateTiles(
- 3, TilePriorityForSoonBin(), TilePriorityForSoonBin());
+ TileVector active_pending_soon =
+ CreateTiles(3, TilePriorityForSoonBin(), TilePriorityForSoonBin());
TileVector never_bin = CreateTiles(1, TilePriority(), TilePriority());
tile_manager()->AssignMemoryToTiles(global_state_);
@@ -185,6 +195,19 @@ TEST_P(TileManagerTest, EnoughMemoryAllowPrepaintOnly) {
EXPECT_EQ(0, AssignedMemoryCount(never_bin));
}
+TEST_P(TileManagerTest, EnoughMemoryPendingLowResAllowAbsoluteMinimum) {
+ // A few low-res tiles required for activation, with enough memory for all
+ // tiles.
+
+ Initialize(5, ALLOW_ABSOLUTE_MINIMUM, SAME_PRIORITY_FOR_BOTH_TREES);
+ TileVector pending_low_res =
+ CreateTiles(5, TilePriority(), TilePriorityLowRes());
+
+ tile_manager()->AssignMemoryToTiles(global_state_);
+
+ EXPECT_EQ(5, AssignedMemoryCount(pending_low_res));
+}
+
TEST_P(TileManagerTest, EnoughMemoryAllowAbsoluteMinimum) {
// A few tiles of each type of priority, with enough memory for all tiles,
// with the exception of never and soon bins.
@@ -194,8 +217,8 @@ TEST_P(TileManagerTest, EnoughMemoryAllowAbsoluteMinimum) {
CreateTiles(3, TilePriorityForNowBin(), TilePriority());
TileVector pending_now =
CreateTiles(3, TilePriority(), TilePriorityForNowBin());
- TileVector active_pending_soon = CreateTiles(
- 3, TilePriorityForSoonBin(), TilePriorityForSoonBin());
+ TileVector active_pending_soon =
+ CreateTiles(3, TilePriorityForSoonBin(), TilePriorityForSoonBin());
TileVector never_bin = CreateTiles(1, TilePriority(), TilePriority());
tile_manager()->AssignMemoryToTiles(global_state_);
@@ -215,8 +238,8 @@ TEST_P(TileManagerTest, EnoughMemoryAllowNothing) {
CreateTiles(3, TilePriorityForNowBin(), TilePriority());
TileVector pending_now =
CreateTiles(3, TilePriority(), TilePriorityForNowBin());
- TileVector active_pending_soon = CreateTiles(
- 3, TilePriorityForSoonBin(), TilePriorityForSoonBin());
+ TileVector active_pending_soon =
+ CreateTiles(3, TilePriorityForSoonBin(), TilePriorityForSoonBin());
TileVector never_bin = CreateTiles(1, TilePriority(), TilePriority());
tile_manager()->AssignMemoryToTiles(global_state_);
@@ -231,14 +254,14 @@ TEST_P(TileManagerTest, PartialOOMMemoryToPending) {
// 5 tiles on active tree eventually bin, 5 tiles on pending tree that are
// required for activation, but only enough memory for 8 tiles. The result
// is all pending tree tiles get memory, and 3 of the active tree tiles
- // get memory.
+ // get memory. None of these tiles is needed to avoid calimity (flickering or
+ // raster-on-demand) so the soft memory limit is used.
Initialize(8, ALLOW_ANYTHING, SMOOTHNESS_TAKES_PRIORITY);
TileVector active_tree_tiles =
CreateTiles(5, TilePriorityForEventualBin(), TilePriority());
TileVector pending_tree_tiles =
CreateTiles(5, TilePriority(), TilePriorityRequiredForActivation());
-
tile_manager()->AssignMemoryToTiles(global_state_);
EXPECT_EQ(5, AssignedMemoryCount(active_tree_tiles));
@@ -255,6 +278,8 @@ TEST_P(TileManagerTest, PartialOOMMemoryToActive) {
// 5 tiles on active tree eventually bin, 5 tiles on pending tree now bin,
// but only enough memory for 8 tiles. The result is all active tree tiles
// get memory, and 3 of the pending tree tiles get memory.
+ // The pending tiles are not needed to avoid calimity (flickering or
+ // raster-on-demand) and the active tiles fit, so the soft limit is used.
Initialize(8, ALLOW_ANYTHING, SMOOTHNESS_TAKES_PRIORITY);
TileVector active_tree_tiles =
@@ -269,16 +294,16 @@ TEST_P(TileManagerTest, PartialOOMMemoryToActive) {
}
TEST_P(TileManagerTest, TotalOOMMemoryToPending) {
- // 5 tiles on active tree eventually bin, 5 tiles on pending tree that are
- // required for activation, but only enough memory for 4 tiles. The result
+ // 10 tiles on active tree eventually bin, 10 tiles on pending tree that are
+ // required for activation, but only enough tiles for 4 tiles. The result
// is 4 pending tree tiles get memory, and none of the active tree tiles
// get memory.
Initialize(4, ALLOW_ANYTHING, SMOOTHNESS_TAKES_PRIORITY);
TileVector active_tree_tiles =
- CreateTiles(5, TilePriorityForEventualBin(), TilePriority());
+ CreateTiles(10, TilePriorityForEventualBin(), TilePriority());
TileVector pending_tree_tiles =
- CreateTiles(5, TilePriority(), TilePriorityRequiredForActivation());
+ CreateTiles(10, TilePriority(), TilePriorityRequiredForActivation());
tile_manager()->AssignMemoryToTiles(global_state_);
@@ -288,21 +313,28 @@ TEST_P(TileManagerTest, TotalOOMMemoryToPending) {
SetTreePriority(SAME_PRIORITY_FOR_BOTH_TREES);
tile_manager()->AssignMemoryToTiles(global_state_);
- EXPECT_EQ(0, AssignedMemoryCount(active_tree_tiles));
- EXPECT_EQ(4, AssignedMemoryCount(pending_tree_tiles));
+ if (UsingResourceLimit()) {
+ EXPECT_EQ(0, AssignedMemoryCount(active_tree_tiles));
+ EXPECT_EQ(4, AssignedMemoryCount(pending_tree_tiles));
+ } else {
+ // Pending tiles are now required to avoid calimity (flickering or
+ // raster-on-demand). Hard-limit is used and double the tiles fit.
+ EXPECT_EQ(0, AssignedMemoryCount(active_tree_tiles));
+ EXPECT_EQ(8, AssignedMemoryCount(pending_tree_tiles));
+ }
}
TEST_P(TileManagerTest, TotalOOMActiveSoonMemoryToPending) {
- // 5 tiles on active tree soon bin, 5 tiles on pending tree that are
- // required for activation, but only enough memory for 4 tiles. The result
+ // 10 tiles on active tree soon bin, 10 tiles on pending tree that are
+ // required for activation, but only enough tiles for 4 tiles. The result
// is 4 pending tree tiles get memory, and none of the active tree tiles
// get memory.
Initialize(4, ALLOW_ANYTHING, SMOOTHNESS_TAKES_PRIORITY);
TileVector active_tree_tiles =
- CreateTiles(5, TilePriorityForSoonBin(), TilePriority());
+ CreateTiles(10, TilePriorityForSoonBin(), TilePriority());
TileVector pending_tree_tiles =
- CreateTiles(5, TilePriority(), TilePriorityRequiredForActivation());
+ CreateTiles(10, TilePriority(), TilePriorityRequiredForActivation());
tile_manager()->AssignMemoryToTiles(global_state_);
@@ -312,219 +344,568 @@ TEST_P(TileManagerTest, TotalOOMActiveSoonMemoryToPending) {
SetTreePriority(SAME_PRIORITY_FOR_BOTH_TREES);
tile_manager()->AssignMemoryToTiles(global_state_);
- EXPECT_EQ(0, AssignedMemoryCount(active_tree_tiles));
- EXPECT_EQ(4, AssignedMemoryCount(pending_tree_tiles));
+ if (UsingResourceLimit()) {
+ EXPECT_EQ(0, AssignedMemoryCount(active_tree_tiles));
+ EXPECT_EQ(4, AssignedMemoryCount(pending_tree_tiles));
+ } else {
+ // Pending tiles are now required to avoid calimity (flickering or
+ // raster-on-demand). Hard-limit is used and double the tiles fit.
+ EXPECT_EQ(0, AssignedMemoryCount(active_tree_tiles));
+ EXPECT_EQ(8, AssignedMemoryCount(pending_tree_tiles));
+ }
}
TEST_P(TileManagerTest, TotalOOMMemoryToActive) {
- // 5 tiles on active tree eventually bin, 5 tiles on pending tree now bin,
- // but only enough memory for 4 tiles. The result is 5 active tree tiles
+ // 10 tiles on active tree eventually bin, 10 tiles on pending tree now bin,
+ // but only enough memory for 4 tiles. The result is 4 active tree tiles
// get memory, and none of the pending tree tiles get memory.
Initialize(4, ALLOW_ANYTHING, SMOOTHNESS_TAKES_PRIORITY);
TileVector active_tree_tiles =
- CreateTiles(5, TilePriorityForNowBin(), TilePriority());
+ CreateTiles(10, TilePriorityForNowBin(), TilePriority());
TileVector pending_tree_tiles =
- CreateTiles(5, TilePriority(), TilePriorityForNowBin());
+ CreateTiles(10, TilePriority(), TilePriorityForNowBin());
tile_manager()->AssignMemoryToTiles(global_state_);
- EXPECT_EQ(4, AssignedMemoryCount(active_tree_tiles));
- EXPECT_EQ(0, AssignedMemoryCount(pending_tree_tiles));
+ if (UsingResourceLimit()) {
+ EXPECT_EQ(4, AssignedMemoryCount(active_tree_tiles));
+ EXPECT_EQ(0, AssignedMemoryCount(pending_tree_tiles));
+ } else {
+ // Active tiles are required to avoid calimity (flickering or
+ // raster-on-demand). Hard-limit is used and double the tiles fit.
+ EXPECT_EQ(8, AssignedMemoryCount(active_tree_tiles));
+ EXPECT_EQ(0, AssignedMemoryCount(pending_tree_tiles));
+ }
}
+TEST_P(TileManagerTest, TotalOOMMemoryToNewContent) {
+ // 10 tiles on active tree now bin, 10 tiles on pending tree now bin,
+ // but only enough memory for 8 tiles. Any tile missing would cause
+ // a calamity (flickering or raster-on-demand). Depending on mode,
+ // we should use varying amounts of the higher hard memory limit.
+ if (UsingResourceLimit())
+ return;
-
-TEST_P(TileManagerTest, RasterAsLCD) {
- Initialize(20, ALLOW_ANYTHING, SMOOTHNESS_TAKES_PRIORITY);
+ Initialize(8, ALLOW_ANYTHING, SMOOTHNESS_TAKES_PRIORITY);
TileVector active_tree_tiles =
- CreateTiles(5, TilePriorityForNowBin(), TilePriority());
+ CreateTiles(10, TilePriorityForNowBin(), TilePriority());
TileVector pending_tree_tiles =
- CreateTiles(5, TilePriority(), TilePriorityForNowBin());
+ CreateTiles(10, TilePriority(), TilePriorityForNowBin());
+ // Active tiles are required to avoid calimity. The hard-limit is used and all
+ // active-tiles fit. No pending tiles are needed to avoid calamity so only 10
+ // tiles total are used.
tile_manager()->AssignMemoryToTiles(global_state_);
+ EXPECT_EQ(10, AssignedMemoryCount(active_tree_tiles));
+ EXPECT_EQ(0, AssignedMemoryCount(pending_tree_tiles));
- EXPECT_EQ(5, TilesWithLCDCount(active_tree_tiles));
- EXPECT_EQ(5, TilesWithLCDCount(pending_tree_tiles));
+ // Even the hard-limit won't save us now. All tiles are required to avoid
+ // a clamity but we only have 16. The tiles will be distribted randomly
+ // given they are identical, in practice depending on their screen location.
+ SetTreePriority(SAME_PRIORITY_FOR_BOTH_TREES);
+ tile_manager()->AssignMemoryToTiles(global_state_);
+ EXPECT_EQ(16,
+ AssignedMemoryCount(active_tree_tiles) +
+ AssignedMemoryCount(pending_tree_tiles));
+
+ // The pending tree is now more important. Active tiles will take higher
+ // priority if they are ready-to-draw in practice. Importantly though,
+ // pending tiles also utilize the hard-limit.
+ SetTreePriority(NEW_CONTENT_TAKES_PRIORITY);
+ tile_manager()->AssignMemoryToTiles(global_state_);
+ EXPECT_EQ(0, AssignedMemoryCount(active_tree_tiles));
+ EXPECT_EQ(10, AssignedMemoryCount(pending_tree_tiles));
}
-TEST_P(TileManagerTest, RasterAsNoLCD) {
- Initialize(20, ALLOW_ANYTHING, SMOOTHNESS_TAKES_PRIORITY);
- TileVector active_tree_tiles =
- CreateTiles(5, TilePriorityForNowBin(), TilePriority());
- TileVector pending_tree_tiles =
- CreateTiles(5, TilePriority(), TilePriorityForNowBin());
+// If true, the max tile limit should be applied as bytes; if false,
+// as num_resources_limit.
+INSTANTIATE_TEST_CASE_P(TileManagerTests,
+ TileManagerTest,
+ ::testing::Values(true, false));
- for (TileVector::iterator it = active_tree_tiles.begin();
- it != active_tree_tiles.end();
- ++it) {
- (*it)->set_can_use_lcd_text(false);
+class TileManagerTileIteratorTest : public testing::Test {
+ public:
+ TileManagerTileIteratorTest()
+ : memory_limit_policy_(ALLOW_ANYTHING),
+ max_tiles_(10000),
+ ready_to_activate_(false),
+ id_(7),
+ proxy_(base::MessageLoopProxy::current()),
+ host_impl_(ImplSidePaintingSettings(),
+ &proxy_,
+ &shared_bitmap_manager_) {}
+
+ void SetTreePriority(TreePriority tree_priority) {
+ GlobalStateThatImpactsTilePriority state;
+ gfx::Size tile_size(256, 256);
+
+ state.soft_memory_limit_in_bytes = 100 * 1000 * 1000;
+ state.num_resources_limit = max_tiles_;
+ state.hard_memory_limit_in_bytes = state.soft_memory_limit_in_bytes * 2;
+ state.memory_limit_policy = memory_limit_policy_;
+ state.tree_priority = tree_priority;
+
+ global_state_ = state;
+ host_impl_.resource_pool()->SetResourceUsageLimits(
+ state.soft_memory_limit_in_bytes,
+ state.soft_memory_limit_in_bytes,
+ state.num_resources_limit);
+ host_impl_.tile_manager()->SetGlobalStateForTesting(state);
}
- for (TileVector::iterator it = pending_tree_tiles.begin();
- it != pending_tree_tiles.end();
- ++it) {
- (*it)->set_can_use_lcd_text(false);
+
+ virtual void SetUp() OVERRIDE {
+ InitializeRenderer();
+ SetTreePriority(SAME_PRIORITY_FOR_BOTH_TREES);
}
- tile_manager()->AssignMemoryToTiles(global_state_);
+ virtual void InitializeRenderer() {
+ host_impl_.InitializeRenderer(
+ FakeOutputSurface::Create3d().PassAs<OutputSurface>());
+ }
- EXPECT_EQ(0, TilesWithLCDCount(active_tree_tiles));
- EXPECT_EQ(0, TilesWithLCDCount(pending_tree_tiles));
-}
+ void SetupDefaultTrees(const gfx::Size& layer_bounds) {
+ gfx::Size tile_size(100, 100);
-TEST_P(TileManagerTest, ReRasterAsNoLCD) {
- Initialize(20, ALLOW_ANYTHING, SMOOTHNESS_TAKES_PRIORITY);
- TileVector active_tree_tiles =
- CreateTiles(5, TilePriorityForNowBin(), TilePriority());
- TileVector pending_tree_tiles =
- CreateTiles(5, TilePriority(), TilePriorityForNowBin());
+ scoped_refptr<FakePicturePileImpl> pending_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+ scoped_refptr<FakePicturePileImpl> active_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
- tile_manager()->AssignMemoryToTiles(global_state_);
+ SetupTrees(pending_pile, active_pile);
+ }
- EXPECT_EQ(5, TilesWithLCDCount(active_tree_tiles));
- EXPECT_EQ(5, TilesWithLCDCount(pending_tree_tiles));
+ void ActivateTree() {
+ host_impl_.ActivatePendingTree();
+ CHECK(!host_impl_.pending_tree());
+ pending_layer_ = NULL;
+ active_layer_ = static_cast<FakePictureLayerImpl*>(
+ host_impl_.active_tree()->LayerById(id_));
+ }
- for (TileVector::iterator it = active_tree_tiles.begin();
- it != active_tree_tiles.end();
- ++it) {
- (*it)->set_can_use_lcd_text(false);
+ void SetupDefaultTreesWithFixedTileSize(const gfx::Size& layer_bounds,
+ const gfx::Size& tile_size) {
+ SetupDefaultTrees(layer_bounds);
+ pending_layer_->set_fixed_tile_size(tile_size);
+ active_layer_->set_fixed_tile_size(tile_size);
}
- for (TileVector::iterator it = pending_tree_tiles.begin();
- it != pending_tree_tiles.end();
- ++it) {
- (*it)->set_can_use_lcd_text(false);
+
+ void SetupTrees(scoped_refptr<PicturePileImpl> pending_pile,
+ scoped_refptr<PicturePileImpl> active_pile) {
+ SetupPendingTree(active_pile);
+ ActivateTree();
+ SetupPendingTree(pending_pile);
}
- tile_manager()->AssignMemoryToTiles(global_state_);
+ void SetupPendingTree(scoped_refptr<PicturePileImpl> pile) {
+ host_impl_.CreatePendingTree();
+ LayerTreeImpl* pending_tree = host_impl_.pending_tree();
+ // Clear recycled tree.
+ pending_tree->DetachLayerTree();
- EXPECT_EQ(0, TilesWithLCDCount(active_tree_tiles));
- EXPECT_EQ(0, TilesWithLCDCount(pending_tree_tiles));
-}
+ scoped_ptr<FakePictureLayerImpl> pending_layer =
+ FakePictureLayerImpl::CreateWithPile(pending_tree, id_, pile);
+ pending_layer->SetDrawsContent(true);
+ pending_tree->SetRootLayer(pending_layer.PassAs<LayerImpl>());
-TEST_P(TileManagerTest, NoTextDontReRasterAsNoLCD) {
- Initialize(20, ALLOW_ANYTHING, SMOOTHNESS_TAKES_PRIORITY);
- TileVector active_tree_tiles =
- CreateTiles(5, TilePriorityForNowBin(), TilePriority());
- TileVector pending_tree_tiles =
- CreateTiles(5, TilePriority(), TilePriorityForNowBin());
+ pending_layer_ = static_cast<FakePictureLayerImpl*>(
+ host_impl_.pending_tree()->LayerById(id_));
+ pending_layer_->DoPostCommitInitializationIfNeeded();
+ }
- tile_manager()->AssignMemoryToTiles(global_state_);
+ void CreateHighLowResAndSetAllTilesVisible() {
+ // Active layer must get updated first so pending layer can share from it.
+ active_layer_->CreateDefaultTilingsAndTiles();
+ active_layer_->SetAllTilesVisible();
+ pending_layer_->CreateDefaultTilingsAndTiles();
+ pending_layer_->SetAllTilesVisible();
+ }
- EXPECT_EQ(5, TilesWithLCDCount(active_tree_tiles));
- EXPECT_EQ(5, TilesWithLCDCount(pending_tree_tiles));
+ TileManager* tile_manager() { return host_impl_.tile_manager(); }
- for (TileVector::iterator it = active_tree_tiles.begin();
- it != active_tree_tiles.end();
- ++it) {
- ManagedTileState::TileVersion& tile_version =
- (*it)->GetTileVersionForTesting(HIGH_QUALITY_RASTER_MODE);
- tile_version.SetSolidColorForTesting(SkColorSetARGB(0, 0, 0, 0));
- (*it)->set_can_use_lcd_text(false);
- EXPECT_TRUE((*it)->IsReadyToDraw());
+ protected:
+ GlobalStateThatImpactsTilePriority global_state_;
+
+ TestSharedBitmapManager shared_bitmap_manager_;
+ TileMemoryLimitPolicy memory_limit_policy_;
+ int max_tiles_;
+ bool ready_to_activate_;
+ int id_;
+ FakeImplProxy proxy_;
+ FakeLayerTreeHostImpl host_impl_;
+ FakePictureLayerImpl* pending_layer_;
+ FakePictureLayerImpl* active_layer_;
+};
+
+TEST_F(TileManagerTileIteratorTest, PairedPictureLayers) {
+ host_impl_.CreatePendingTree();
+ host_impl_.ActivatePendingTree();
+ host_impl_.CreatePendingTree();
+
+ LayerTreeImpl* active_tree = host_impl_.active_tree();
+ LayerTreeImpl* pending_tree = host_impl_.pending_tree();
+ EXPECT_NE(active_tree, pending_tree);
+
+ scoped_ptr<FakePictureLayerImpl> active_layer =
+ FakePictureLayerImpl::Create(active_tree, 10);
+ scoped_ptr<FakePictureLayerImpl> pending_layer =
+ FakePictureLayerImpl::Create(pending_tree, 10);
+
+ TileManager* tile_manager = TileManagerTileIteratorTest::tile_manager();
+ EXPECT_TRUE(tile_manager);
+
+ std::vector<TileManager::PairedPictureLayer> paired_layers;
+ tile_manager->GetPairedPictureLayers(&paired_layers);
+
+ EXPECT_EQ(2u, paired_layers.size());
+ if (paired_layers[0].active_layer) {
+ EXPECT_EQ(active_layer.get(), paired_layers[0].active_layer);
+ EXPECT_EQ(NULL, paired_layers[0].pending_layer);
+ } else {
+ EXPECT_EQ(pending_layer.get(), paired_layers[0].pending_layer);
+ EXPECT_EQ(NULL, paired_layers[0].active_layer);
}
- for (TileVector::iterator it = pending_tree_tiles.begin();
- it != pending_tree_tiles.end();
- ++it) {
- ManagedTileState::TileVersion& tile_version =
- (*it)->GetTileVersionForTesting(HIGH_QUALITY_RASTER_MODE);
- tile_version.SetSolidColorForTesting(SkColorSetARGB(0, 0, 0, 0));
- (*it)->set_can_use_lcd_text(false);
- EXPECT_TRUE((*it)->IsReadyToDraw());
+
+ if (paired_layers[1].active_layer) {
+ EXPECT_EQ(active_layer.get(), paired_layers[1].active_layer);
+ EXPECT_EQ(NULL, paired_layers[1].pending_layer);
+ } else {
+ EXPECT_EQ(pending_layer.get(), paired_layers[1].pending_layer);
+ EXPECT_EQ(NULL, paired_layers[1].active_layer);
}
- tile_manager()->AssignMemoryToTiles(global_state_);
+ active_layer->set_twin_layer(pending_layer.get());
+ pending_layer->set_twin_layer(active_layer.get());
- EXPECT_EQ(5, TilesWithLCDCount(active_tree_tiles));
- EXPECT_EQ(5, TilesWithLCDCount(pending_tree_tiles));
+ tile_manager->GetPairedPictureLayers(&paired_layers);
+ EXPECT_EQ(1u, paired_layers.size());
+
+ EXPECT_EQ(active_layer.get(), paired_layers[0].active_layer);
+ EXPECT_EQ(pending_layer.get(), paired_layers[0].pending_layer);
}
-TEST_P(TileManagerTest, TextReRasterAsNoLCD) {
- Initialize(20, ALLOW_ANYTHING, SMOOTHNESS_TAKES_PRIORITY);
- TileVector active_tree_tiles =
- CreateTiles(5, TilePriorityForNowBin(), TilePriority());
- TileVector pending_tree_tiles =
- CreateTiles(5, TilePriority(), TilePriorityForNowBin());
+TEST_F(TileManagerTileIteratorTest, RasterTileIterator) {
+ SetupDefaultTrees(gfx::Size(1000, 1000));
+ TileManager* tile_manager = TileManagerTileIteratorTest::tile_manager();
+ EXPECT_TRUE(tile_manager);
- tile_manager()->AssignMemoryToTiles(global_state_);
+ active_layer_->CreateDefaultTilingsAndTiles();
+ pending_layer_->CreateDefaultTilingsAndTiles();
- EXPECT_EQ(5, TilesWithLCDCount(active_tree_tiles));
- EXPECT_EQ(5, TilesWithLCDCount(pending_tree_tiles));
+ std::vector<TileManager::PairedPictureLayer> paired_layers;
+ tile_manager->GetPairedPictureLayers(&paired_layers);
+ EXPECT_EQ(1u, paired_layers.size());
- for (TileVector::iterator it = active_tree_tiles.begin();
- it != active_tree_tiles.end();
- ++it) {
- ManagedTileState::TileVersion& tile_version =
- (*it)->GetTileVersionForTesting(HIGH_QUALITY_RASTER_MODE);
- tile_version.SetSolidColorForTesting(SkColorSetARGB(0, 0, 0, 0));
- tile_version.SetHasTextForTesting(true);
- (*it)->set_can_use_lcd_text(false);
+ TileManager::RasterTileIterator it(tile_manager,
+ SAME_PRIORITY_FOR_BOTH_TREES);
+ EXPECT_TRUE(it);
- EXPECT_TRUE((*it)->IsReadyToDraw());
+ size_t tile_count = 0;
+ std::set<Tile*> all_tiles;
+ for (; it; ++it) {
+ EXPECT_TRUE(*it);
+ all_tiles.insert(*it);
+ ++tile_count;
}
- for (TileVector::iterator it = pending_tree_tiles.begin();
- it != pending_tree_tiles.end();
+
+ EXPECT_EQ(tile_count, all_tiles.size());
+ EXPECT_EQ(17u, tile_count);
+
+ // Sanity check, all tiles should be visible.
+ std::set<Tile*> smoothness_tiles;
+ for (TileManager::RasterTileIterator it(tile_manager,
+ SMOOTHNESS_TAKES_PRIORITY);
+ it;
++it) {
- ManagedTileState::TileVersion& tile_version =
- (*it)->GetTileVersionForTesting(HIGH_QUALITY_RASTER_MODE);
- tile_version.SetSolidColorForTesting(
- SkColorSetARGB(0, 0, 0, 0));
- tile_version.SetHasTextForTesting(true);
- (*it)->set_can_use_lcd_text(false);
-
- EXPECT_TRUE((*it)->IsReadyToDraw());
+ Tile* tile = *it;
+ EXPECT_TRUE(tile);
+ EXPECT_EQ(TilePriority::NOW, tile->priority(ACTIVE_TREE).priority_bin);
+ EXPECT_EQ(TilePriority::NOW, tile->priority(PENDING_TREE).priority_bin);
+ smoothness_tiles.insert(tile);
}
+ EXPECT_EQ(all_tiles, smoothness_tiles);
+
+ Region invalidation(gfx::Rect(0, 0, 500, 500));
+
+ // Invalidate the pending tree.
+ pending_layer_->set_invalidation(invalidation);
+ pending_layer_->HighResTiling()->Invalidate(invalidation);
+ pending_layer_->LowResTiling()->Invalidate(invalidation);
+
+ active_layer_->ResetAllTilesPriorities();
+ pending_layer_->ResetAllTilesPriorities();
+
+ // Renew all of the tile priorities.
+ gfx::Rect viewport(50, 50, 100, 100);
+ pending_layer_->HighResTiling()->UpdateTilePriorities(
+ PENDING_TREE, viewport, 1.0f, 1.0);
+ pending_layer_->LowResTiling()->UpdateTilePriorities(
+ PENDING_TREE, viewport, 1.0f, 1.0);
+ active_layer_->HighResTiling()->UpdateTilePriorities(
+ ACTIVE_TREE, viewport, 1.0f, 1.0);
+ active_layer_->LowResTiling()->UpdateTilePriorities(
+ ACTIVE_TREE, viewport, 1.0f, 1.0);
+
+ // Populate all tiles directly from the tilings.
+ all_tiles.clear();
+ std::vector<Tile*> pending_high_res_tiles =
+ pending_layer_->HighResTiling()->AllTilesForTesting();
+ for (size_t i = 0; i < pending_high_res_tiles.size(); ++i)
+ all_tiles.insert(pending_high_res_tiles[i]);
+
+ std::vector<Tile*> pending_low_res_tiles =
+ pending_layer_->LowResTiling()->AllTilesForTesting();
+ for (size_t i = 0; i < pending_low_res_tiles.size(); ++i)
+ all_tiles.insert(pending_low_res_tiles[i]);
+
+ std::vector<Tile*> active_high_res_tiles =
+ active_layer_->HighResTiling()->AllTilesForTesting();
+ for (size_t i = 0; i < active_high_res_tiles.size(); ++i)
+ all_tiles.insert(active_high_res_tiles[i]);
+
+ std::vector<Tile*> active_low_res_tiles =
+ active_layer_->LowResTiling()->AllTilesForTesting();
+ for (size_t i = 0; i < active_low_res_tiles.size(); ++i)
+ all_tiles.insert(active_low_res_tiles[i]);
+
+ Tile* last_tile = NULL;
+ smoothness_tiles.clear();
+ tile_count = 0;
+ size_t increasing_distance_tiles = 0u;
+ // Here we expect to get increasing ACTIVE_TREE priority_bin.
+ for (TileManager::RasterTileIterator it(tile_manager,
+ SMOOTHNESS_TAKES_PRIORITY);
+ it;
+ ++it) {
+ Tile* tile = *it;
+ EXPECT_TRUE(tile);
+
+ if (!last_tile)
+ last_tile = tile;
+
+ EXPECT_LE(last_tile->priority(ACTIVE_TREE).priority_bin,
+ tile->priority(ACTIVE_TREE).priority_bin);
+ if (last_tile->priority(ACTIVE_TREE).priority_bin ==
+ tile->priority(ACTIVE_TREE).priority_bin) {
+ increasing_distance_tiles +=
+ last_tile->priority(ACTIVE_TREE).distance_to_visible <=
+ tile->priority(ACTIVE_TREE).distance_to_visible;
+ }
- tile_manager()->AssignMemoryToTiles(global_state_);
+ if (tile->priority(ACTIVE_TREE).priority_bin == TilePriority::NOW &&
+ last_tile->priority(ACTIVE_TREE).resolution !=
+ tile->priority(ACTIVE_TREE).resolution) {
+ // Low resolution should come first.
+ EXPECT_EQ(LOW_RESOLUTION, last_tile->priority(ACTIVE_TREE).resolution);
+ }
- EXPECT_EQ(0, TilesWithLCDCount(active_tree_tiles));
- EXPECT_EQ(0, TilesWithLCDCount(pending_tree_tiles));
-}
+ last_tile = tile;
+ ++tile_count;
+ smoothness_tiles.insert(tile);
+ }
-TEST_P(TileManagerTest, RespectMemoryLimit) {
- Initialize(5, ALLOW_ANYTHING, SMOOTHNESS_TAKES_PRIORITY);
- TileVector large_tiles = CreateTiles(
- 5, TilePriorityForNowBin(), TilePriority());
+ EXPECT_EQ(tile_count, smoothness_tiles.size());
+ EXPECT_EQ(all_tiles, smoothness_tiles);
+ // Since we don't guarantee increasing distance due to spiral iterator, we
+ // should check that we're _mostly_ right.
+ EXPECT_GT(increasing_distance_tiles, 3 * tile_count / 4);
+
+ std::set<Tile*> new_content_tiles;
+ last_tile = NULL;
+ increasing_distance_tiles = 0u;
+ // Here we expect to get increasing PENDING_TREE priority_bin.
+ for (TileManager::RasterTileIterator it(tile_manager,
+ NEW_CONTENT_TAKES_PRIORITY);
+ it;
+ ++it) {
+ Tile* tile = *it;
+ EXPECT_TRUE(tile);
+
+ if (!last_tile)
+ last_tile = tile;
+
+ EXPECT_LE(last_tile->priority(PENDING_TREE).priority_bin,
+ tile->priority(PENDING_TREE).priority_bin);
+ if (last_tile->priority(PENDING_TREE).priority_bin ==
+ tile->priority(PENDING_TREE).priority_bin) {
+ increasing_distance_tiles +=
+ last_tile->priority(PENDING_TREE).distance_to_visible <=
+ tile->priority(PENDING_TREE).distance_to_visible;
+ }
- size_t memory_required_bytes;
- size_t memory_nice_to_have_bytes;
- size_t memory_allocated_bytes;
- size_t memory_used_bytes;
+ if (tile->priority(PENDING_TREE).priority_bin == TilePriority::NOW &&
+ last_tile->priority(PENDING_TREE).resolution !=
+ tile->priority(PENDING_TREE).resolution) {
+ // High resolution should come first.
+ EXPECT_EQ(HIGH_RESOLUTION, last_tile->priority(PENDING_TREE).resolution);
+ }
- tile_manager()->AssignMemoryToTiles(global_state_);
- tile_manager()->GetMemoryStats(&memory_required_bytes,
- &memory_nice_to_have_bytes,
- &memory_allocated_bytes,
- &memory_used_bytes);
- // Allocated bytes should never be more than the memory limit.
- EXPECT_LE(memory_allocated_bytes, global_state_.memory_limit_in_bytes);
-
- // Finish raster of large tiles.
- tile_manager()->UpdateVisibleTiles();
-
- // Remove all large tiles. This will leave the memory currently
- // used by these tiles as unused when AssignMemoryToTiles() is called.
- large_tiles.clear();
-
- // Create a new set of tiles using a different size. These tiles
- // can use the memory currently assigned to the lerge tiles but
- // they can't use the same resources as the size doesn't match.
- TileVector small_tiles = CreateTilesWithSize(
- 5, TilePriorityForNowBin(), TilePriority(), gfx::Size(128, 128));
+ last_tile = tile;
+ new_content_tiles.insert(tile);
+ }
- tile_manager()->AssignMemoryToTiles(global_state_);
- tile_manager()->GetMemoryStats(&memory_required_bytes,
- &memory_nice_to_have_bytes,
- &memory_allocated_bytes,
- &memory_used_bytes);
- // Allocated bytes should never be more than the memory limit.
- EXPECT_LE(memory_allocated_bytes, global_state_.memory_limit_in_bytes);
+ EXPECT_EQ(tile_count, new_content_tiles.size());
+ EXPECT_EQ(all_tiles, new_content_tiles);
+ // Since we don't guarantee increasing distance due to spiral iterator, we
+ // should check that we're _mostly_ right.
+ EXPECT_GT(increasing_distance_tiles, 3 * tile_count / 4);
}
-// If true, the max tile limit should be applied as bytes; if false,
-// as num_resources_limit.
-INSTANTIATE_TEST_CASE_P(TileManagerTests,
- TileManagerTest,
- ::testing::Values(true, false));
+TEST_F(TileManagerTileIteratorTest, EvictionTileIterator) {
+ SetupDefaultTrees(gfx::Size(1000, 1000));
+ TileManager* tile_manager = TileManagerTileIteratorTest::tile_manager();
+ EXPECT_TRUE(tile_manager);
+
+ active_layer_->CreateDefaultTilingsAndTiles();
+ pending_layer_->CreateDefaultTilingsAndTiles();
+
+ std::vector<TileManager::PairedPictureLayer> paired_layers;
+ tile_manager->GetPairedPictureLayers(&paired_layers);
+ EXPECT_EQ(1u, paired_layers.size());
+
+ TileManager::EvictionTileIterator empty_it(tile_manager,
+ SAME_PRIORITY_FOR_BOTH_TREES);
+ EXPECT_FALSE(empty_it);
+ std::set<Tile*> all_tiles;
+ size_t tile_count = 0;
+
+ for (TileManager::RasterTileIterator raster_it(tile_manager,
+ SAME_PRIORITY_FOR_BOTH_TREES);
+ raster_it;
+ ++raster_it) {
+ ++tile_count;
+ EXPECT_TRUE(*raster_it);
+ all_tiles.insert(*raster_it);
+ }
+
+ EXPECT_EQ(tile_count, all_tiles.size());
+ EXPECT_EQ(17u, tile_count);
+
+ tile_manager->InitializeTilesWithResourcesForTesting(
+ std::vector<Tile*>(all_tiles.begin(), all_tiles.end()));
+
+ TileManager::EvictionTileIterator it(tile_manager, SMOOTHNESS_TAKES_PRIORITY);
+ EXPECT_TRUE(it);
+
+ // Sanity check, all tiles should be visible.
+ std::set<Tile*> smoothness_tiles;
+ for (; it; ++it) {
+ Tile* tile = *it;
+ EXPECT_TRUE(tile);
+ EXPECT_EQ(TilePriority::NOW, tile->priority(ACTIVE_TREE).priority_bin);
+ EXPECT_EQ(TilePriority::NOW, tile->priority(PENDING_TREE).priority_bin);
+ EXPECT_TRUE(tile->HasResources());
+ smoothness_tiles.insert(tile);
+ }
+ EXPECT_EQ(all_tiles, smoothness_tiles);
+
+ tile_manager->ReleaseTileResourcesForTesting(
+ std::vector<Tile*>(all_tiles.begin(), all_tiles.end()));
+
+ Region invalidation(gfx::Rect(0, 0, 500, 500));
+
+ // Invalidate the pending tree.
+ pending_layer_->set_invalidation(invalidation);
+ pending_layer_->HighResTiling()->Invalidate(invalidation);
+ pending_layer_->LowResTiling()->Invalidate(invalidation);
+
+ active_layer_->ResetAllTilesPriorities();
+ pending_layer_->ResetAllTilesPriorities();
+
+ // Renew all of the tile priorities.
+ gfx::Rect viewport(50, 50, 100, 100);
+ pending_layer_->HighResTiling()->UpdateTilePriorities(
+ PENDING_TREE, viewport, 1.0f, 1.0);
+ pending_layer_->LowResTiling()->UpdateTilePriorities(
+ PENDING_TREE, viewport, 1.0f, 1.0);
+ active_layer_->HighResTiling()->UpdateTilePriorities(
+ ACTIVE_TREE, viewport, 1.0f, 1.0);
+ active_layer_->LowResTiling()->UpdateTilePriorities(
+ ACTIVE_TREE, viewport, 1.0f, 1.0);
+
+ // Populate all tiles directly from the tilings.
+ all_tiles.clear();
+ std::vector<Tile*> pending_high_res_tiles =
+ pending_layer_->HighResTiling()->AllTilesForTesting();
+ for (size_t i = 0; i < pending_high_res_tiles.size(); ++i)
+ all_tiles.insert(pending_high_res_tiles[i]);
+
+ std::vector<Tile*> pending_low_res_tiles =
+ pending_layer_->LowResTiling()->AllTilesForTesting();
+ for (size_t i = 0; i < pending_low_res_tiles.size(); ++i)
+ all_tiles.insert(pending_low_res_tiles[i]);
+
+ std::vector<Tile*> active_high_res_tiles =
+ active_layer_->HighResTiling()->AllTilesForTesting();
+ for (size_t i = 0; i < active_high_res_tiles.size(); ++i)
+ all_tiles.insert(active_high_res_tiles[i]);
+
+ std::vector<Tile*> active_low_res_tiles =
+ active_layer_->LowResTiling()->AllTilesForTesting();
+ for (size_t i = 0; i < active_low_res_tiles.size(); ++i)
+ all_tiles.insert(active_low_res_tiles[i]);
+
+ tile_manager->InitializeTilesWithResourcesForTesting(
+ std::vector<Tile*>(all_tiles.begin(), all_tiles.end()));
+
+ Tile* last_tile = NULL;
+ smoothness_tiles.clear();
+ tile_count = 0;
+ // Here we expect to get increasing ACTIVE_TREE priority_bin.
+ for (TileManager::EvictionTileIterator it(tile_manager,
+ SMOOTHNESS_TAKES_PRIORITY);
+ it;
+ ++it) {
+ Tile* tile = *it;
+ EXPECT_TRUE(tile);
+ EXPECT_TRUE(tile->HasResources());
+
+ if (!last_tile)
+ last_tile = tile;
+
+ EXPECT_GE(last_tile->priority(ACTIVE_TREE).priority_bin,
+ tile->priority(ACTIVE_TREE).priority_bin);
+ if (last_tile->priority(ACTIVE_TREE).priority_bin ==
+ tile->priority(ACTIVE_TREE).priority_bin) {
+ EXPECT_GE(last_tile->priority(ACTIVE_TREE).distance_to_visible,
+ tile->priority(ACTIVE_TREE).distance_to_visible);
+ }
+ last_tile = tile;
+ ++tile_count;
+ smoothness_tiles.insert(tile);
+ }
+
+ EXPECT_EQ(tile_count, smoothness_tiles.size());
+ EXPECT_EQ(all_tiles, smoothness_tiles);
+
+ std::set<Tile*> new_content_tiles;
+ last_tile = NULL;
+ // Here we expect to get increasing PENDING_TREE priority_bin.
+ for (TileManager::EvictionTileIterator it(tile_manager,
+ NEW_CONTENT_TAKES_PRIORITY);
+ it;
+ ++it) {
+ Tile* tile = *it;
+ EXPECT_TRUE(tile);
+
+ if (!last_tile)
+ last_tile = tile;
+
+ EXPECT_GE(last_tile->priority(PENDING_TREE).priority_bin,
+ tile->priority(PENDING_TREE).priority_bin);
+ if (last_tile->priority(PENDING_TREE).priority_bin ==
+ tile->priority(PENDING_TREE).priority_bin) {
+ EXPECT_GE(last_tile->priority(PENDING_TREE).distance_to_visible,
+ tile->priority(PENDING_TREE).distance_to_visible);
+ }
+
+ last_tile = tile;
+ new_content_tiles.insert(tile);
+ }
+
+ EXPECT_EQ(tile_count, new_content_tiles.size());
+ EXPECT_EQ(all_tiles, new_content_tiles);
+}
} // namespace
} // namespace cc
diff --git a/chromium/cc/resources/tile_priority.cc b/chromium/cc/resources/tile_priority.cc
index 9cf4634f7d5..3bf29680766 100644
--- a/chromium/cc/resources/tile_priority.cc
+++ b/chromium/cc/resources/tile_priority.cc
@@ -7,62 +7,17 @@
#include "base/values.h"
#include "cc/base/math_util.h"
-namespace {
-
-// TODO(qinmin): modify ui/range/Range.h to support template so that we
-// don't need to define this.
-struct Range {
- Range(float start, float end) : start_(start), end_(end) {}
- bool IsEmpty();
- float start_;
- float end_;
-};
-
-bool Range::IsEmpty() {
- return start_ >= end_;
-}
-
-inline void IntersectNegativeHalfplane(Range* out,
- float previous,
- float current,
- float target,
- float time_delta) {
- float time_per_dist = time_delta / (current - previous);
- float t = (target - current) * time_per_dist;
- if (time_per_dist > 0.0f)
- out->start_ = std::max(out->start_, t);
- else
- out->end_ = std::min(out->end_, t);
-}
-
-inline void IntersectPositiveHalfplane(Range* out,
- float previous,
- float current,
- float target,
- float time_delta) {
- float time_per_dist = time_delta / (current - previous);
- float t = (target - current) * time_per_dist;
- if (time_per_dist < 0.0f)
- out->start_ = std::max(out->start_, t);
- else
- out->end_ = std::min(out->end_, t);
-}
-
-} // namespace
-
namespace cc {
scoped_ptr<base::Value> WhichTreeAsValue(WhichTree tree) {
switch (tree) {
case ACTIVE_TREE:
- return scoped_ptr<base::Value>(base::Value::CreateStringValue(
- "ACTIVE_TREE"));
+ return scoped_ptr<base::Value>(new base::StringValue("ACTIVE_TREE"));
case PENDING_TREE:
- return scoped_ptr<base::Value>(base::Value::CreateStringValue(
- "PENDING_TREE"));
+ return scoped_ptr<base::Value>(new base::StringValue("PENDING_TREE"));
default:
DCHECK(false) << "Unrecognized WhichTree value " << tree;
- return scoped_ptr<base::Value>(base::Value::CreateStringValue(
+ return scoped_ptr<base::Value>(new base::StringValue(
"<unknown WhichTree value>"));
}
}
@@ -71,87 +26,59 @@ scoped_ptr<base::Value> TileResolutionAsValue(
TileResolution resolution) {
switch (resolution) {
case LOW_RESOLUTION:
- return scoped_ptr<base::Value>(base::Value::CreateStringValue(
- "LOW_RESOLUTION"));
+ return scoped_ptr<base::Value>(new base::StringValue("LOW_RESOLUTION"));
case HIGH_RESOLUTION:
- return scoped_ptr<base::Value>(base::Value::CreateStringValue(
- "HIGH_RESOLUTION"));
+ return scoped_ptr<base::Value>(new base::StringValue("HIGH_RESOLUTION"));
case NON_IDEAL_RESOLUTION:
- return scoped_ptr<base::Value>(base::Value::CreateStringValue(
+ return scoped_ptr<base::Value>(new base::StringValue(
"NON_IDEAL_RESOLUTION"));
}
DCHECK(false) << "Unrecognized TileResolution value " << resolution;
- return scoped_ptr<base::Value>(base::Value::CreateStringValue(
+ return scoped_ptr<base::Value>(new base::StringValue(
"<unknown TileResolution value>"));
}
+scoped_ptr<base::Value> TilePriorityBinAsValue(TilePriority::PriorityBin bin) {
+ switch (bin) {
+ case TilePriority::NOW:
+ return scoped_ptr<base::Value>(base::Value::CreateStringValue("NOW"));
+ case TilePriority::SOON:
+ return scoped_ptr<base::Value>(base::Value::CreateStringValue("SOON"));
+ case TilePriority::EVENTUALLY:
+ return scoped_ptr<base::Value>(
+ base::Value::CreateStringValue("EVENTUALLY"));
+ }
+ DCHECK(false) << "Unrecognized TilePriority::PriorityBin value " << bin;
+ return scoped_ptr<base::Value>(base::Value::CreateStringValue(
+ "<unknown TilePriority::PriorityBin value>"));
+}
+
scoped_ptr<base::Value> TilePriority::AsValue() const {
scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue());
state->Set("resolution", TileResolutionAsValue(resolution).release());
- state->Set("time_to_visible_in_seconds",
- MathUtil::AsValueSafely(time_to_visible_in_seconds).release());
- state->Set("distance_to_visible_in_pixels",
- MathUtil::AsValueSafely(distance_to_visible_in_pixels).release());
+ state->Set("priority_bin", TilePriorityBinAsValue(priority_bin).release());
+ state->Set("distance_to_visible",
+ MathUtil::AsValueSafely(distance_to_visible).release());
return state.PassAs<base::Value>();
}
-float TilePriority::TimeForBoundsToIntersect(const gfx::RectF& previous_bounds,
- const gfx::RectF& current_bounds,
- float time_delta,
- const gfx::RectF& target_bounds) {
- // Perform an intersection test explicitly between current and target.
- if (current_bounds.x() < target_bounds.right() &&
- current_bounds.y() < target_bounds.bottom() &&
- target_bounds.x() < current_bounds.right() &&
- target_bounds.y() < current_bounds.bottom())
- return 0.0f;
-
- const float kMaxTimeToVisibleInSeconds =
- std::numeric_limits<float>::infinity();
-
- if (time_delta == 0.0f)
- return kMaxTimeToVisibleInSeconds;
-
- // As we are trying to solve the case of both scaling and scrolling, using
- // a single coordinate with velocity is not enough. The logic here is to
- // calculate the velocity for each edge. Then we calculate the time range that
- // each edge will stay on the same side of the target bounds. If there is an
- // overlap between these time ranges, the bounds must have intersect with
- // each other during that period of time.
- Range range(0.0f, kMaxTimeToVisibleInSeconds);
- IntersectPositiveHalfplane(
- &range, previous_bounds.x(), current_bounds.x(),
- target_bounds.right(), time_delta);
- IntersectNegativeHalfplane(
- &range, previous_bounds.right(), current_bounds.right(),
- target_bounds.x(), time_delta);
- IntersectPositiveHalfplane(
- &range, previous_bounds.y(), current_bounds.y(),
- target_bounds.bottom(), time_delta);
- IntersectNegativeHalfplane(
- &range, previous_bounds.bottom(), current_bounds.bottom(),
- target_bounds.y(), time_delta);
- return range.IsEmpty() ? kMaxTimeToVisibleInSeconds : range.start_;
-}
-
scoped_ptr<base::Value> TileMemoryLimitPolicyAsValue(
TileMemoryLimitPolicy policy) {
switch (policy) {
case ALLOW_NOTHING:
- return scoped_ptr<base::Value>(base::Value::CreateStringValue(
- "ALLOW_NOTHING"));
+ return scoped_ptr<base::Value>(new base::StringValue("ALLOW_NOTHING"));
case ALLOW_ABSOLUTE_MINIMUM:
- return scoped_ptr<base::Value>(base::Value::CreateStringValue(
+ return scoped_ptr<base::Value>(new base::StringValue(
"ALLOW_ABSOLUTE_MINIMUM"));
case ALLOW_PREPAINT_ONLY:
- return scoped_ptr<base::Value>(base::Value::CreateStringValue(
+ return scoped_ptr<base::Value>(new base::StringValue(
"ALLOW_PREPAINT_ONLY"));
case ALLOW_ANYTHING:
- return scoped_ptr<base::Value>(base::Value::CreateStringValue(
+ return scoped_ptr<base::Value>(new base::StringValue(
"ALLOW_ANYTHING"));
default:
DCHECK(false) << "Unrecognized policy value";
- return scoped_ptr<base::Value>(base::Value::CreateStringValue(
+ return scoped_ptr<base::Value>(new base::StringValue(
"<unknown>"));
}
}
@@ -159,17 +86,17 @@ scoped_ptr<base::Value> TileMemoryLimitPolicyAsValue(
scoped_ptr<base::Value> TreePriorityAsValue(TreePriority prio) {
switch (prio) {
case SAME_PRIORITY_FOR_BOTH_TREES:
- return scoped_ptr<base::Value>(base::Value::CreateStringValue(
+ return scoped_ptr<base::Value>(new base::StringValue(
"SAME_PRIORITY_FOR_BOTH_TREES"));
case SMOOTHNESS_TAKES_PRIORITY:
- return scoped_ptr<base::Value>(base::Value::CreateStringValue(
+ return scoped_ptr<base::Value>(new base::StringValue(
"SMOOTHNESS_TAKES_PRIORITY"));
case NEW_CONTENT_TAKES_PRIORITY:
- return scoped_ptr<base::Value>(base::Value::CreateStringValue(
+ return scoped_ptr<base::Value>(new base::StringValue(
"NEW_CONTENT_TAKES_PRIORITY"));
}
DCHECK(false) << "Unrecognized priority value " << prio;
- return scoped_ptr<base::Value>(base::Value::CreateStringValue(
+ return scoped_ptr<base::Value>(new base::StringValue(
"<unknown>"));
}
@@ -177,9 +104,8 @@ scoped_ptr<base::Value> GlobalStateThatImpactsTilePriority::AsValue() const {
scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue());
state->Set("memory_limit_policy",
TileMemoryLimitPolicyAsValue(memory_limit_policy).release());
- state->SetInteger("memory_limit_in_bytes", memory_limit_in_bytes);
- state->SetInteger("unused_memory_limit_in_bytes",
- unused_memory_limit_in_bytes);
+ state->SetInteger("soft_memory_limit_in_bytes", soft_memory_limit_in_bytes);
+ state->SetInteger("hard_memory_limit_in_bytes", hard_memory_limit_in_bytes);
state->SetInteger("num_resources_limit", num_resources_limit);
state->Set("tree_priority", TreePriorityAsValue(tree_priority).release());
return state.PassAs<base::Value>();
diff --git a/chromium/cc/resources/tile_priority.h b/chromium/cc/resources/tile_priority.h
index 0052e40ddce..f8ac9c6c7b0 100644
--- a/chromium/cc/resources/tile_priority.h
+++ b/chromium/cc/resources/tile_priority.h
@@ -41,19 +41,21 @@ scoped_ptr<base::Value> TileResolutionAsValue(
TileResolution resolution);
struct CC_EXPORT TilePriority {
+ enum PriorityBin { NOW, SOON, EVENTUALLY };
+
TilePriority()
: resolution(NON_IDEAL_RESOLUTION),
required_for_activation(false),
- time_to_visible_in_seconds(std::numeric_limits<float>::infinity()),
- distance_to_visible_in_pixels(std::numeric_limits<float>::infinity()) {}
+ priority_bin(EVENTUALLY),
+ distance_to_visible(std::numeric_limits<float>::infinity()) {}
TilePriority(TileResolution resolution,
- float time_to_visible_in_seconds,
- float distance_to_visible_in_pixels)
+ PriorityBin bin,
+ float distance_to_visible)
: resolution(resolution),
required_for_activation(false),
- time_to_visible_in_seconds(time_to_visible_in_seconds),
- distance_to_visible_in_pixels(distance_to_visible_in_pixels) {}
+ priority_bin(bin),
+ distance_to_visible(distance_to_visible) {}
TilePriority(const TilePriority& active, const TilePriority& pending) {
if (active.resolution == HIGH_RESOLUTION ||
@@ -68,41 +70,46 @@ struct CC_EXPORT TilePriority {
required_for_activation =
active.required_for_activation || pending.required_for_activation;
- time_to_visible_in_seconds =
- std::min(active.time_to_visible_in_seconds,
- pending.time_to_visible_in_seconds);
- distance_to_visible_in_pixels =
- std::min(active.distance_to_visible_in_pixels,
- pending.distance_to_visible_in_pixels);
+ if (active.priority_bin < pending.priority_bin) {
+ priority_bin = active.priority_bin;
+ distance_to_visible = active.distance_to_visible;
+ } else if (active.priority_bin > pending.priority_bin) {
+ priority_bin = pending.priority_bin;
+ distance_to_visible = pending.distance_to_visible;
+ } else {
+ priority_bin = active.priority_bin;
+ distance_to_visible =
+ std::min(active.distance_to_visible, pending.distance_to_visible);
+ }
}
scoped_ptr<base::Value> AsValue() const;
- // Calculate the time for the |current_bounds| to intersect with the
- // |target_bounds| given its previous location and time delta.
- // This function should work for both scaling and scrolling case.
- static float TimeForBoundsToIntersect(const gfx::RectF& previous_bounds,
- const gfx::RectF& current_bounds,
- float time_delta,
- const gfx::RectF& target_bounds);
-
bool operator ==(const TilePriority& other) const {
return resolution == other.resolution &&
- time_to_visible_in_seconds == other.time_to_visible_in_seconds &&
- distance_to_visible_in_pixels == other.distance_to_visible_in_pixels &&
- required_for_activation == other.required_for_activation;
+ priority_bin == other.priority_bin &&
+ distance_to_visible == other.distance_to_visible &&
+ required_for_activation == other.required_for_activation;
}
bool operator !=(const TilePriority& other) const {
return !(*this == other);
}
+ bool IsHigherPriorityThan(const TilePriority& other) const {
+ return priority_bin < other.priority_bin ||
+ (priority_bin == other.priority_bin &&
+ distance_to_visible < other.distance_to_visible);
+ }
+
TileResolution resolution;
bool required_for_activation;
- float time_to_visible_in_seconds;
- float distance_to_visible_in_pixels;
+ PriorityBin priority_bin;
+ float distance_to_visible;
};
+scoped_ptr<base::Value> TilePriorityBinAsValue(TilePriority::PriorityBin bin);
+
enum TileMemoryLimitPolicy {
// Nothing.
ALLOW_NOTHING = 0,
@@ -137,25 +144,25 @@ class GlobalStateThatImpactsTilePriority {
public:
GlobalStateThatImpactsTilePriority()
: memory_limit_policy(ALLOW_NOTHING),
- memory_limit_in_bytes(0),
- unused_memory_limit_in_bytes(0),
+ soft_memory_limit_in_bytes(0),
+ hard_memory_limit_in_bytes(0),
num_resources_limit(0),
tree_priority(SAME_PRIORITY_FOR_BOTH_TREES) {}
TileMemoryLimitPolicy memory_limit_policy;
- size_t memory_limit_in_bytes;
- size_t unused_memory_limit_in_bytes;
+ size_t soft_memory_limit_in_bytes;
+ size_t hard_memory_limit_in_bytes;
size_t num_resources_limit;
TreePriority tree_priority;
bool operator==(const GlobalStateThatImpactsTilePriority& other) const {
- return memory_limit_policy == other.memory_limit_policy
- && memory_limit_in_bytes == other.memory_limit_in_bytes
- && unused_memory_limit_in_bytes == other.unused_memory_limit_in_bytes
- && num_resources_limit == other.num_resources_limit
- && tree_priority == other.tree_priority;
+ return memory_limit_policy == other.memory_limit_policy &&
+ soft_memory_limit_in_bytes == other.soft_memory_limit_in_bytes &&
+ hard_memory_limit_in_bytes == other.hard_memory_limit_in_bytes &&
+ num_resources_limit == other.num_resources_limit &&
+ tree_priority == other.tree_priority;
}
bool operator!=(const GlobalStateThatImpactsTilePriority& other) const {
return !(*this == other);
diff --git a/chromium/cc/resources/tile_priority_unittest.cc b/chromium/cc/resources/tile_priority_unittest.cc
index 0f4c6717aff..e134bc97642 100644
--- a/chromium/cc/resources/tile_priority_unittest.cc
+++ b/chromium/cc/resources/tile_priority_unittest.cc
@@ -1,53 +1,45 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
+// 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/resources/tile_priority.h"
-
#include "testing/gtest/include/gtest/gtest.h"
namespace cc {
-namespace {
-
-TEST(TilePriorityTest, TimeForBoundsToIntersectWithScroll) {
- const float inf = std::numeric_limits<float>::infinity();
- gfx::Rect target(0, 0, 800, 600);
- gfx::Rect current(100, 100, 100, 100);
- EXPECT_EQ(0, TilePriority::TimeForBoundsToIntersect(
- gfx::Rect(-200, 0, 100, 100), current, 1, target));
- EXPECT_EQ(0, TilePriority::TimeForBoundsToIntersect(
- gfx::Rect(-100, 0, 100, 100), current, 1, target));
- EXPECT_EQ(0, TilePriority::TimeForBoundsToIntersect(
- gfx::Rect(400, 400, 100, 100), current, 1, target));
-
- current = gfx::Rect(-300, -300, 100, 100);
- EXPECT_EQ(inf, TilePriority::TimeForBoundsToIntersect(
- gfx::Rect(0, 0, 100, 100), current, 1, target));
- EXPECT_EQ(inf, TilePriority::TimeForBoundsToIntersect(
- gfx::Rect(-200, -200, 100, 100), current, 1, target));
- EXPECT_EQ(2, TilePriority::TimeForBoundsToIntersect(
- gfx::Rect(-400, -400, 100, 100), current, 1, target));
-}
-
-TEST(TilePriorityTest, TimeForBoundsToIntersectWithScale) {
- const float inf = std::numeric_limits<float>::infinity();
- gfx::Rect target(0, 0, 800, 600);
- gfx::Rect current(100, 100, 100, 100);
- EXPECT_EQ(0, TilePriority::TimeForBoundsToIntersect(
- gfx::Rect(-200, 0, 200, 200), current, 1, target));
- EXPECT_EQ(0, TilePriority::TimeForBoundsToIntersect(
- gfx::Rect(-100, 0, 50, 50), current, 1, target));
- EXPECT_EQ(0, TilePriority::TimeForBoundsToIntersect(
- gfx::Rect(400, 400, 400, 400), current, 1, target));
- current = gfx::Rect(-300, -300, 100, 100);
- EXPECT_EQ(inf, TilePriority::TimeForBoundsToIntersect(
- gfx::Rect(-400, -400, 300, 300), current, 1, target));
- EXPECT_EQ(8, TilePriority::TimeForBoundsToIntersect(
- gfx::Rect(-275, -275, 50, 50), current, 1, target));
- EXPECT_EQ(1, TilePriority::TimeForBoundsToIntersect(
- gfx::Rect(-450, -450, 50, 50), current, 1, target));
+TEST(TilePriorityTest, IsHigherPriorityThan) {
+ TilePriority now(HIGH_RESOLUTION, TilePriority::NOW, 0);
+ TilePriority close_soon(HIGH_RESOLUTION, TilePriority::SOON, 1);
+ TilePriority far_soon(HIGH_RESOLUTION, TilePriority::SOON, 500);
+ TilePriority close_eventually(HIGH_RESOLUTION, TilePriority::EVENTUALLY, 2);
+ TilePriority far_eventually(HIGH_RESOLUTION, TilePriority::EVENTUALLY, 1000);
+ TilePriority non_ideal_now(NON_IDEAL_RESOLUTION, TilePriority::NOW, 0);
+
+ EXPECT_FALSE(now.IsHigherPriorityThan(now));
+ EXPECT_FALSE(now.IsHigherPriorityThan(non_ideal_now));
+
+ EXPECT_TRUE(now.IsHigherPriorityThan(close_soon));
+ EXPECT_TRUE(now.IsHigherPriorityThan(far_soon));
+ EXPECT_TRUE(now.IsHigherPriorityThan(close_eventually));
+ EXPECT_TRUE(now.IsHigherPriorityThan(far_eventually));
+ EXPECT_TRUE(close_soon.IsHigherPriorityThan(far_soon));
+ EXPECT_TRUE(close_soon.IsHigherPriorityThan(close_eventually));
+ EXPECT_TRUE(close_soon.IsHigherPriorityThan(far_eventually));
+ EXPECT_TRUE(far_soon.IsHigherPriorityThan(close_eventually));
+ EXPECT_TRUE(far_soon.IsHigherPriorityThan(far_eventually));
+ EXPECT_TRUE(close_eventually.IsHigherPriorityThan(far_eventually));
+
+ EXPECT_FALSE(far_eventually.IsHigherPriorityThan(close_eventually));
+ EXPECT_FALSE(far_eventually.IsHigherPriorityThan(far_soon));
+ EXPECT_FALSE(far_eventually.IsHigherPriorityThan(close_soon));
+ EXPECT_FALSE(far_eventually.IsHigherPriorityThan(now));
+ EXPECT_FALSE(far_eventually.IsHigherPriorityThan(non_ideal_now));
+ EXPECT_FALSE(close_eventually.IsHigherPriorityThan(far_soon));
+ EXPECT_FALSE(close_eventually.IsHigherPriorityThan(close_soon));
+ EXPECT_FALSE(close_eventually.IsHigherPriorityThan(now));
+ EXPECT_FALSE(far_soon.IsHigherPriorityThan(close_soon));
+ EXPECT_FALSE(far_soon.IsHigherPriorityThan(now));
+ EXPECT_FALSE(close_soon.IsHigherPriorityThan(now));
}
-} // namespace
} // namespace cc
diff --git a/chromium/cc/resources/transferable_resource.cc b/chromium/cc/resources/transferable_resource.cc
index 62f1bdb1641..30fa3169abd 100644
--- a/chromium/cc/resources/transferable_resource.cc
+++ b/chromium/cc/resources/transferable_resource.cc
@@ -10,11 +10,11 @@ namespace cc {
TransferableResource::TransferableResource()
: id(0),
- sync_point(0),
format(RGBA_8888),
- target(0),
filter(0),
- is_software(false) {}
+ is_repeated(false),
+ is_software(false) {
+}
TransferableResource::~TransferableResource() {
}
@@ -22,7 +22,7 @@ TransferableResource::~TransferableResource() {
ReturnedResource TransferableResource::ToReturnedResource() const {
ReturnedResource returned;
returned.id = id;
- returned.sync_point = sync_point;
+ returned.sync_point = mailbox_holder.sync_point;
returned.count = 1;
return returned;
}
diff --git a/chromium/cc/resources/transferable_resource.h b/chromium/cc/resources/transferable_resource.h
index 5c93d1c042f..11651f2722d 100644
--- a/chromium/cc/resources/transferable_resource.h
+++ b/chromium/cc/resources/transferable_resource.h
@@ -10,7 +10,7 @@
#include "base/basictypes.h"
#include "cc/base/cc_export.h"
#include "cc/resources/resource_format.h"
-#include "gpu/command_buffer/common/mailbox.h"
+#include "gpu/command_buffer/common/mailbox_holder.h"
#include "ui/gfx/size.h"
namespace cc {
@@ -29,12 +29,11 @@ struct CC_EXPORT TransferableResource {
ReturnedResourceArray* output);
unsigned id;
- unsigned sync_point;
ResourceFormat format;
- uint32 target;
uint32 filter;
gfx::Size size;
- gpu::Mailbox mailbox;
+ gpu::MailboxHolder mailbox_holder;
+ bool is_repeated;
bool is_software;
};
diff --git a/chromium/cc/resources/ui_resource_bitmap.cc b/chromium/cc/resources/ui_resource_bitmap.cc
index b813d973537..58df9d96272 100644
--- a/chromium/cc/resources/ui_resource_bitmap.cc
+++ b/chromium/cc/resources/ui_resource_bitmap.cc
@@ -6,15 +6,15 @@
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
-#include "cc/resources/etc1_pixel_ref.h"
#include "third_party/skia/include/core/SkBitmap.h"
+#include "third_party/skia/include/core/SkMallocPixelRef.h"
#include "third_party/skia/include/core/SkPixelRef.h"
namespace cc {
void UIResourceBitmap::Create(const skia::RefPtr<SkPixelRef>& pixel_ref,
- UIResourceFormat format,
- gfx::Size size) {
+ const gfx::Size& size,
+ UIResourceFormat format) {
DCHECK(size.width());
DCHECK(size.height());
DCHECK(pixel_ref);
@@ -29,22 +29,32 @@ void UIResourceBitmap::Create(const skia::RefPtr<SkPixelRef>& pixel_ref,
}
UIResourceBitmap::UIResourceBitmap(const SkBitmap& skbitmap) {
- DCHECK_EQ(skbitmap.config(), SkBitmap::kARGB_8888_Config);
+ DCHECK_EQ(skbitmap.colorType(), kPMColor_SkColorType);
DCHECK_EQ(skbitmap.width(), skbitmap.rowBytesAsPixels());
DCHECK(skbitmap.isImmutable());
skia::RefPtr<SkPixelRef> pixel_ref = skia::SharePtr(skbitmap.pixelRef());
- Create(pixel_ref,
- UIResourceBitmap::RGBA8,
- gfx::Size(skbitmap.width(), skbitmap.height()));
+ const SkImageInfo& info = pixel_ref->info();
+ Create(
+ pixel_ref, gfx::Size(info.fWidth, info.fHeight), UIResourceBitmap::RGBA8);
SetOpaque(skbitmap.isOpaque());
}
-UIResourceBitmap::UIResourceBitmap(
- const skia::RefPtr<ETC1PixelRef>& etc1_pixel_ref,
- gfx::Size size) {
- Create(etc1_pixel_ref, ETC1, size);
+UIResourceBitmap::UIResourceBitmap(const gfx::Size& size, bool is_opaque) {
+ SkAlphaType alphaType = is_opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
+ SkImageInfo info =
+ SkImageInfo::MakeN32(size.width(), size.height(), alphaType);
+ skia::RefPtr<SkPixelRef> pixel_ref = skia::AdoptRef(
+ SkMallocPixelRef::NewAllocate(info, info.minRowBytes(), NULL));
+ pixel_ref->setImmutable();
+ Create(pixel_ref, size, UIResourceBitmap::RGBA8);
+ SetOpaque(is_opaque);
+}
+
+UIResourceBitmap::UIResourceBitmap(const skia::RefPtr<SkPixelRef>& pixel_ref,
+ const gfx::Size& size) {
+ Create(pixel_ref, size, UIResourceBitmap::ETC1);
}
UIResourceBitmap::~UIResourceBitmap() {}
diff --git a/chromium/cc/resources/ui_resource_bitmap.h b/chromium/cc/resources/ui_resource_bitmap.h
index ea54f613b10..b8863d8e994 100644
--- a/chromium/cc/resources/ui_resource_bitmap.h
+++ b/chromium/cc/resources/ui_resource_bitmap.h
@@ -44,17 +44,17 @@ class CC_EXPORT UIResourceBitmap {
// User must ensure that |skbitmap| is immutable. The SkBitmap Format should
// be 32-bit RGBA.
explicit UIResourceBitmap(const SkBitmap& skbitmap);
-
- UIResourceBitmap(const skia::RefPtr<ETC1PixelRef>& etc1_pixel_ref,
- gfx::Size size);
-
+ UIResourceBitmap(const gfx::Size& size, bool is_opaque);
+ UIResourceBitmap(const skia::RefPtr<SkPixelRef>& pixel_ref,
+ const gfx::Size& size);
~UIResourceBitmap();
private:
friend class AutoLockUIResourceBitmap;
+
void Create(const skia::RefPtr<SkPixelRef>& pixel_ref,
- UIResourceFormat format,
- gfx::Size size);
+ const gfx::Size& size,
+ UIResourceFormat format);
skia::RefPtr<SkPixelRef> pixel_ref_;
UIResourceFormat format_;
diff --git a/chromium/cc/resources/video_resource_updater.cc b/chromium/cc/resources/video_resource_updater.cc
index 4abeab149d3..1d93aebe3cc 100644
--- a/chromium/cc/resources/video_resource_updater.cc
+++ b/chromium/cc/resources/video_resource_updater.cc
@@ -58,18 +58,14 @@ VideoFrameExternalResources VideoResourceUpdater::
bool VideoResourceUpdater::VerifyFrame(
const scoped_refptr<media::VideoFrame>& video_frame) {
- // If these fail, we'll have to add logic that handles offset bitmap/texture
- // UVs. For now, just expect (0, 0) offset, since all our decoders so far
- // don't offset.
- DCHECK_EQ(video_frame->visible_rect().x(), 0);
- DCHECK_EQ(video_frame->visible_rect().y(), 0);
-
switch (video_frame->format()) {
// Acceptable inputs.
case media::VideoFrame::YV12:
+ case media::VideoFrame::I420:
case media::VideoFrame::YV12A:
case media::VideoFrame::YV16:
case media::VideoFrame::YV12J:
+ case media::VideoFrame::YV24:
case media::VideoFrame::NATIVE_TEXTURE:
#if defined(VIDEO_HOLE)
case media::VideoFrame::HOLE:
@@ -78,8 +74,7 @@ bool VideoResourceUpdater::VerifyFrame(
// Unacceptable inputs. ¯\(°_o)/¯
case media::VideoFrame::UNKNOWN:
- case media::VideoFrame::HISTOGRAM_MAX:
- case media::VideoFrame::I420:
+ case media::VideoFrame::NV12:
break;
}
return false;
@@ -88,36 +83,16 @@ bool VideoResourceUpdater::VerifyFrame(
// For frames that we receive in software format, determine the dimensions of
// each plane in the frame.
static gfx::Size SoftwarePlaneDimension(
- media::VideoFrame::Format input_frame_format,
- gfx::Size coded_size,
+ const scoped_refptr<media::VideoFrame>& input_frame,
ResourceFormat output_resource_format,
- int plane_index) {
+ size_t plane_index) {
if (output_resource_format == kYUVResourceFormat) {
- if (plane_index == media::VideoFrame::kYPlane ||
- plane_index == media::VideoFrame::kAPlane)
- return coded_size;
-
- switch (input_frame_format) {
- case media::VideoFrame::YV12:
- case media::VideoFrame::YV12A:
- case media::VideoFrame::YV12J:
- return gfx::ToFlooredSize(gfx::ScaleSize(coded_size, 0.5f, 0.5f));
- case media::VideoFrame::YV16:
- return gfx::ToFlooredSize(gfx::ScaleSize(coded_size, 0.5f, 1.f));
-
- case media::VideoFrame::UNKNOWN:
- case media::VideoFrame::I420:
- case media::VideoFrame::NATIVE_TEXTURE:
- case media::VideoFrame::HISTOGRAM_MAX:
-#if defined(VIDEO_HOLE)
- case media::VideoFrame::HOLE:
-#endif // defined(VIDEO_HOLE)
- NOTREACHED();
- }
+ return media::VideoFrame::PlaneSize(
+ input_frame->format(), plane_index, input_frame->coded_size());
}
DCHECK_EQ(output_resource_format, kRGBResourceFormat);
- return coded_size;
+ return input_frame->coded_size();
}
VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes(
@@ -134,20 +109,23 @@ VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes(
// Only YUV software video frames are supported.
DCHECK(input_frame_format == media::VideoFrame::YV12 ||
+ input_frame_format == media::VideoFrame::I420 ||
input_frame_format == media::VideoFrame::YV12A ||
input_frame_format == media::VideoFrame::YV12J ||
- input_frame_format == media::VideoFrame::YV16);
+ input_frame_format == media::VideoFrame::YV16 ||
+ input_frame_format == media::VideoFrame::YV24);
if (input_frame_format != media::VideoFrame::YV12 &&
+ input_frame_format != media::VideoFrame::I420 &&
input_frame_format != media::VideoFrame::YV12A &&
input_frame_format != media::VideoFrame::YV12J &&
- input_frame_format != media::VideoFrame::YV16)
+ input_frame_format != media::VideoFrame::YV16 &&
+ input_frame_format != media::VideoFrame::YV24)
return VideoFrameExternalResources();
bool software_compositor = context_provider_ == NULL;
ResourceFormat output_resource_format = kYUVResourceFormat;
- size_t output_plane_count =
- (input_frame_format == media::VideoFrame::YV12A) ? 4 : 3;
+ size_t output_plane_count = media::VideoFrame::NumPlanes(input_frame_format);
// TODO(skaslev): If we're in software compositing mode, we do the YUV -> RGB
// conversion here. That involves an extra copy of each frame to a bitmap.
@@ -159,17 +137,12 @@ VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes(
}
int max_resource_size = resource_provider_->max_texture_size();
- gfx::Size coded_frame_size = video_frame->coded_size();
-
std::vector<PlaneResource> plane_resources;
bool allocation_success = true;
for (size_t i = 0; i < output_plane_count; ++i) {
gfx::Size output_plane_resource_size =
- SoftwarePlaneDimension(input_frame_format,
- coded_frame_size,
- output_resource_format,
- i);
+ SoftwarePlaneDimension(video_frame, output_resource_format, i);
if (output_plane_resource_size.IsEmpty() ||
output_plane_resource_size.width() > max_resource_size ||
output_plane_resource_size.height() > max_resource_size) {
@@ -182,8 +155,13 @@ VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes(
// Try recycle a previously-allocated resource.
for (size_t i = 0; i < recycled_resources_.size(); ++i) {
- if (recycled_resources_[i].resource_format == output_resource_format &&
- recycled_resources_[i].resource_size == output_plane_resource_size) {
+ bool resource_matches =
+ recycled_resources_[i].resource_format == output_resource_format &&
+ recycled_resources_[i].resource_size == output_plane_resource_size;
+ bool not_in_use =
+ !software_compositor || !resource_provider_->InUseByConsumer(
+ recycled_resources_[i].resource_id);
+ if (resource_matches && not_in_use) {
resource_id = recycled_resources_[i].resource_id;
mailbox = recycled_resources_[i].mailbox;
recycled_resources_.erase(recycled_resources_.begin() + i);
@@ -208,16 +186,11 @@ VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes(
gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
GLC(gl, gl->GenMailboxCHROMIUM(mailbox.name));
- if (mailbox.IsZero()) {
- resource_provider_->DeleteResource(resource_id);
- resource_id = 0;
- } else {
- ResourceProvider::ScopedWriteLockGL lock(
- resource_provider_, resource_id);
- GLC(gl, gl->BindTexture(GL_TEXTURE_2D, lock.texture_id()));
- GLC(gl, gl->ProduceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name));
- GLC(gl, gl->BindTexture(GL_TEXTURE_2D, 0));
- }
+ ResourceProvider::ScopedWriteLockGL lock(resource_provider_,
+ resource_id);
+ GLC(gl, gl->BindTexture(GL_TEXTURE_2D, lock.texture_id()));
+ GLC(gl, gl->ProduceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name));
+ GLC(gl, gl->BindTexture(GL_TEXTURE_2D, 0));
}
if (resource_id)
@@ -267,23 +240,11 @@ VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes(
plane_resources[0].resource_format,
gpu::Mailbox()
};
- base::SharedMemory* shared_memory =
- resource_provider_->GetSharedMemory(plane_resources[0].resource_id);
- if (shared_memory) {
- external_resources.mailboxes.push_back(
- TextureMailbox(shared_memory, plane_resources[0].resource_size));
- external_resources.release_callbacks
- .push_back(base::Bind(&RecycleResource, AsWeakPtr(), recycle_data));
- external_resources.type = VideoFrameExternalResources::RGB_RESOURCE;
- } else {
- // TODO(jbauman): Remove this path once shared memory is available
- // everywhere.
- external_resources.software_resources
- .push_back(plane_resources[0].resource_id);
- external_resources.software_release_callback =
- base::Bind(&RecycleResource, AsWeakPtr(), recycle_data);
- external_resources.type = VideoFrameExternalResources::SOFTWARE_RESOURCE;
- }
+ external_resources.software_resources.push_back(
+ plane_resources[0].resource_id);
+ external_resources.software_release_callback =
+ base::Bind(&RecycleResource, AsWeakPtr(), recycle_data);
+ external_resources.type = VideoFrameExternalResources::SOFTWARE_RESOURCE;
return external_resources;
}
@@ -313,7 +274,7 @@ VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes(
};
external_resources.mailboxes.push_back(
- TextureMailbox(plane_resources[i].mailbox));
+ TextureMailbox(plane_resources[i].mailbox, GL_TEXTURE_2D, 0));
external_resources.release_callbacks.push_back(
base::Bind(&RecycleResource, AsWeakPtr(), recycle_data));
}
@@ -323,9 +284,9 @@ VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes(
}
static void ReturnTexture(const scoped_refptr<media::VideoFrame>& frame,
- unsigned sync_point,
+ uint32 sync_point,
bool lost_resource) {
- frame->texture_mailbox()->Resync(sync_point);
+ frame->AppendReleaseSyncPoint(sync_point);
}
VideoFrameExternalResources VideoResourceUpdater::CreateForHardwarePlanes(
@@ -339,8 +300,9 @@ VideoFrameExternalResources VideoResourceUpdater::CreateForHardwarePlanes(
if (!context_provider_)
return VideoFrameExternalResources();
+ const gpu::MailboxHolder* mailbox_holder = video_frame->mailbox_holder();
VideoFrameExternalResources external_resources;
- switch (video_frame->texture_target()) {
+ switch (mailbox_holder->texture_target) {
case GL_TEXTURE_2D:
external_resources.type = VideoFrameExternalResources::RGB_RESOURCE;
break;
@@ -356,13 +318,10 @@ VideoFrameExternalResources VideoResourceUpdater::CreateForHardwarePlanes(
return VideoFrameExternalResources();
}
- media::VideoFrame::MailboxHolder* mailbox_holder =
- video_frame->texture_mailbox();
-
external_resources.mailboxes.push_back(
- TextureMailbox(mailbox_holder->mailbox(),
- video_frame->texture_target(),
- mailbox_holder->sync_point()));
+ TextureMailbox(mailbox_holder->mailbox,
+ mailbox_holder->texture_target,
+ mailbox_holder->sync_point));
external_resources.release_callbacks.push_back(
base::Bind(&ReturnTexture, video_frame));
return external_resources;
@@ -372,7 +331,7 @@ VideoFrameExternalResources VideoResourceUpdater::CreateForHardwarePlanes(
void VideoResourceUpdater::RecycleResource(
base::WeakPtr<VideoResourceUpdater> updater,
RecycleResourceData data,
- unsigned sync_point,
+ uint32 sync_point,
bool lost_resource) {
if (!updater.get()) {
// Resource was already deleted.
diff --git a/chromium/cc/resources/video_resource_updater.h b/chromium/cc/resources/video_resource_updater.h
index 2a27739cef7..eaaa8c10d69 100644
--- a/chromium/cc/resources/video_resource_updater.h
+++ b/chromium/cc/resources/video_resource_updater.h
@@ -80,7 +80,7 @@ class CC_EXPORT VideoResourceUpdater
gpu::Mailbox mailbox;
PlaneResource(unsigned resource_id,
- gfx::Size resource_size,
+ const gfx::Size& resource_size,
ResourceFormat resource_format,
gpu::Mailbox mailbox)
: resource_id(resource_id),
@@ -104,7 +104,7 @@ class CC_EXPORT VideoResourceUpdater
};
static void RecycleResource(base::WeakPtr<VideoResourceUpdater> updater,
RecycleResourceData data,
- unsigned sync_point,
+ uint32 sync_point,
bool lost_resource);
ContextProvider* context_provider_;
diff --git a/chromium/cc/resources/video_resource_updater_unittest.cc b/chromium/cc/resources/video_resource_updater_unittest.cc
index dcb72e349d3..05bcf221b4a 100644
--- a/chromium/cc/resources/video_resource_updater_unittest.cc
+++ b/chromium/cc/resources/video_resource_updater_unittest.cc
@@ -8,6 +8,7 @@
#include "cc/resources/resource_provider.h"
#include "cc/test/fake_output_surface.h"
#include "cc/test/fake_output_surface_client.h"
+#include "cc/test/test_shared_bitmap_manager.h"
#include "cc/test/test_web_graphics_context_3d.h"
#include "media/base/video_frame.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -25,8 +26,10 @@ class VideoResourceUpdaterTest : public testing::Test {
output_surface3d_ =
FakeOutputSurface::Create3d(context3d.Pass());
CHECK(output_surface3d_->BindToClient(&client_));
- resource_provider3d_ =
- ResourceProvider::Create(output_surface3d_.get(), NULL, 0, false, 1);
+ shared_bitmap_manager_.reset(new TestSharedBitmapManager());
+ resource_provider3d_ = ResourceProvider::Create(
+ output_surface3d_.get(), shared_bitmap_manager_.get(), 0, false, 1,
+ false);
}
scoped_refptr<media::VideoFrame> CreateTestYUVVideoFrame() {
@@ -54,6 +57,7 @@ class VideoResourceUpdaterTest : public testing::Test {
TestWebGraphicsContext3D* context3d_;
FakeOutputSurfaceClient client_;
scoped_ptr<FakeOutputSurface> output_surface3d_;
+ scoped_ptr<TestSharedBitmapManager> shared_bitmap_manager_;
scoped_ptr<ResourceProvider> resource_provider3d_;
};
@@ -67,18 +71,5 @@ TEST_F(VideoResourceUpdaterTest, SoftwareFrame) {
EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type);
}
-TEST_F(VideoResourceUpdaterTest, LostContextForSoftwareFrame) {
- VideoResourceUpdater updater(output_surface3d_->context_provider().get(),
- resource_provider3d_.get());
- scoped_refptr<media::VideoFrame> video_frame = CreateTestYUVVideoFrame();
-
- // Fail while creating the mailbox for the second YUV plane.
- context3d_->set_times_gen_mailbox_succeeds(1);
-
- VideoFrameExternalResources resources =
- updater.CreateExternalResourcesFromVideoFrame(video_frame);
- EXPECT_EQ(VideoFrameExternalResources::NONE, resources.type);
-}
-
} // namespace
} // namespace cc
diff --git a/chromium/cc/resources/worker_pool.cc b/chromium/cc/resources/worker_pool.cc
deleted file mode 100644
index dca0c704f09..00000000000
--- a/chromium/cc/resources/worker_pool.cc
+++ /dev/null
@@ -1,433 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/resources/worker_pool.h"
-
-#include <algorithm>
-#include <queue>
-
-#include "base/bind.h"
-#include "base/containers/hash_tables.h"
-#include "base/debug/trace_event.h"
-#include "base/strings/stringprintf.h"
-#include "base/synchronization/condition_variable.h"
-#include "base/threading/simple_thread.h"
-#include "base/threading/thread_restrictions.h"
-#include "cc/base/scoped_ptr_deque.h"
-
-namespace cc {
-
-namespace internal {
-
-WorkerPoolTask::WorkerPoolTask()
- : did_schedule_(false),
- did_run_(false),
- did_complete_(false) {
-}
-
-WorkerPoolTask::~WorkerPoolTask() {
- DCHECK_EQ(did_schedule_, did_complete_);
- DCHECK(!did_run_ || did_schedule_);
- DCHECK(!did_run_ || did_complete_);
-}
-
-void WorkerPoolTask::DidSchedule() {
- DCHECK(!did_complete_);
- did_schedule_ = true;
-}
-
-void WorkerPoolTask::WillRun() {
- DCHECK(did_schedule_);
- DCHECK(!did_complete_);
- DCHECK(!did_run_);
-}
-
-void WorkerPoolTask::DidRun() {
- did_run_ = true;
-}
-
-void WorkerPoolTask::WillComplete() {
- DCHECK(!did_complete_);
-}
-
-void WorkerPoolTask::DidComplete() {
- DCHECK(did_schedule_);
- DCHECK(!did_complete_);
- did_complete_ = true;
-}
-
-bool WorkerPoolTask::HasFinishedRunning() const {
- return did_run_;
-}
-
-bool WorkerPoolTask::HasCompleted() const {
- return did_complete_;
-}
-
-GraphNode::GraphNode(internal::WorkerPoolTask* task, unsigned priority)
- : task_(task),
- priority_(priority),
- num_dependencies_(0) {
-}
-
-GraphNode::~GraphNode() {
-}
-
-} // namespace internal
-
-// Internal to the worker pool. Any data or logic that needs to be
-// shared between threads lives in this class. All members are guarded
-// by |lock_|.
-class WorkerPool::Inner : public base::DelegateSimpleThread::Delegate {
- public:
- Inner(size_t num_threads, const std::string& thread_name_prefix);
- virtual ~Inner();
-
- void Shutdown();
-
- // Schedule running of tasks in |graph|. Tasks previously scheduled but
- // no longer needed will be canceled unless already running. Canceled
- // tasks are moved to |completed_tasks_| without being run. The result
- // is that once scheduled, a task is guaranteed to end up in the
- // |completed_tasks_| queue even if they later get canceled by another
- // call to SetTaskGraph().
- void SetTaskGraph(TaskGraph* graph);
-
- // Collect all completed tasks in |completed_tasks|.
- void CollectCompletedTasks(TaskVector* completed_tasks);
-
- private:
- class PriorityComparator {
- public:
- bool operator()(const internal::GraphNode* a,
- const internal::GraphNode* b) {
- // In this system, numerically lower priority is run first.
- if (a->priority() != b->priority())
- return a->priority() > b->priority();
-
- // Run task with most dependents first when priority is the same.
- return a->dependents().size() < b->dependents().size();
- }
- };
-
- // Overridden from base::DelegateSimpleThread:
- virtual void Run() OVERRIDE;
-
- // This lock protects all members of this class except
- // |worker_pool_on_origin_thread_|. Do not read or modify anything
- // without holding this lock. Do not block while holding this lock.
- mutable base::Lock lock_;
-
- // Condition variable that is waited on by worker threads until new
- // tasks are ready to run or shutdown starts.
- base::ConditionVariable has_ready_to_run_tasks_cv_;
-
- // Provides each running thread loop with a unique index. First thread
- // loop index is 0.
- unsigned next_thread_index_;
-
- // Set during shutdown. Tells workers to exit when no more tasks
- // are pending.
- bool shutdown_;
-
- // This set contains all pending tasks.
- GraphNodeMap pending_tasks_;
-
- // Ordered set of tasks that are ready to run.
- typedef std::priority_queue<internal::GraphNode*,
- std::vector<internal::GraphNode*>,
- PriorityComparator> TaskQueue;
- TaskQueue ready_to_run_tasks_;
-
- // This set contains all currently running tasks.
- GraphNodeMap running_tasks_;
-
- // Completed tasks not yet collected by origin thread.
- TaskVector completed_tasks_;
-
- ScopedPtrDeque<base::DelegateSimpleThread> workers_;
-
- DISALLOW_COPY_AND_ASSIGN(Inner);
-};
-
-WorkerPool::Inner::Inner(
- size_t num_threads, const std::string& thread_name_prefix)
- : lock_(),
- has_ready_to_run_tasks_cv_(&lock_),
- next_thread_index_(0),
- shutdown_(false) {
- base::AutoLock lock(lock_);
-
- while (workers_.size() < num_threads) {
- scoped_ptr<base::DelegateSimpleThread> worker = make_scoped_ptr(
- new base::DelegateSimpleThread(
- this,
- thread_name_prefix +
- base::StringPrintf(
- "Worker%u",
- static_cast<unsigned>(workers_.size() + 1)).c_str()));
- worker->Start();
-#if defined(OS_ANDROID) || defined(OS_LINUX)
- worker->SetThreadPriority(base::kThreadPriority_Background);
-#endif
- workers_.push_back(worker.Pass());
- }
-}
-
-WorkerPool::Inner::~Inner() {
- base::AutoLock lock(lock_);
-
- DCHECK(shutdown_);
-
- DCHECK_EQ(0u, pending_tasks_.size());
- DCHECK_EQ(0u, ready_to_run_tasks_.size());
- DCHECK_EQ(0u, running_tasks_.size());
- DCHECK_EQ(0u, completed_tasks_.size());
-}
-
-void WorkerPool::Inner::Shutdown() {
- {
- base::AutoLock lock(lock_);
-
- DCHECK(!shutdown_);
- shutdown_ = true;
-
- // Wake up a worker so it knows it should exit. This will cause all workers
- // to exit as each will wake up another worker before exiting.
- has_ready_to_run_tasks_cv_.Signal();
- }
-
- while (workers_.size()) {
- scoped_ptr<base::DelegateSimpleThread> worker = workers_.take_front();
- // http://crbug.com/240453 - Join() is considered IO and will block this
- // thread. See also http://crbug.com/239423 for further ideas.
- base::ThreadRestrictions::ScopedAllowIO allow_io;
- worker->Join();
- }
-}
-
-void WorkerPool::Inner::SetTaskGraph(TaskGraph* graph) {
- // It is OK to call SetTaskGraph() after shutdown if |graph| is empty.
- DCHECK(graph->empty() || !shutdown_);
-
- GraphNodeMap new_pending_tasks;
- GraphNodeMap new_running_tasks;
- TaskQueue new_ready_to_run_tasks;
-
- new_pending_tasks.swap(*graph);
-
- {
- base::AutoLock lock(lock_);
-
- // First remove all completed tasks from |new_pending_tasks| and
- // adjust number of dependencies.
- for (TaskVector::iterator it = completed_tasks_.begin();
- it != completed_tasks_.end(); ++it) {
- internal::WorkerPoolTask* task = it->get();
-
- scoped_ptr<internal::GraphNode> node = new_pending_tasks.take_and_erase(
- task);
- if (node) {
- for (internal::GraphNode::Vector::const_iterator it =
- node->dependents().begin();
- it != node->dependents().end(); ++it) {
- internal::GraphNode* dependent_node = *it;
- dependent_node->remove_dependency();
- }
- }
- }
-
- // Build new running task set.
- for (GraphNodeMap::iterator it = running_tasks_.begin();
- it != running_tasks_.end(); ++it) {
- internal::WorkerPoolTask* task = it->first;
- // Transfer scheduled task value from |new_pending_tasks| to
- // |new_running_tasks| if currently running. Value must be set to
- // NULL if |new_pending_tasks| doesn't contain task. This does
- // the right in both cases.
- new_running_tasks.set(task, new_pending_tasks.take_and_erase(task));
- }
-
- // Build new "ready to run" tasks queue.
- // TODO(reveman): Create this queue when building the task graph instead.
- for (GraphNodeMap::iterator it = new_pending_tasks.begin();
- it != new_pending_tasks.end(); ++it) {
- internal::WorkerPoolTask* task = it->first;
- DCHECK(task);
- internal::GraphNode* node = it->second;
-
- // Completed tasks should not exist in |new_pending_tasks|.
- DCHECK(!task->HasFinishedRunning());
-
- // Call DidSchedule() to indicate that this task has been scheduled.
- // Note: This is only for debugging purposes.
- task->DidSchedule();
-
- if (!node->num_dependencies())
- new_ready_to_run_tasks.push(node);
-
- // Erase the task from old pending tasks.
- pending_tasks_.erase(task);
- }
-
- completed_tasks_.reserve(completed_tasks_.size() + pending_tasks_.size());
-
- // The items left in |pending_tasks_| need to be canceled.
- for (GraphNodeMap::const_iterator it = pending_tasks_.begin();
- it != pending_tasks_.end();
- ++it) {
- completed_tasks_.push_back(it->first);
- }
-
- // Swap task sets.
- // Note: old tasks are intentionally destroyed after releasing |lock_|.
- pending_tasks_.swap(new_pending_tasks);
- running_tasks_.swap(new_running_tasks);
- std::swap(ready_to_run_tasks_, new_ready_to_run_tasks);
-
- // If |ready_to_run_tasks_| is empty, it means we either have
- // running tasks, or we have no pending tasks.
- DCHECK(!ready_to_run_tasks_.empty() ||
- (pending_tasks_.empty() || !running_tasks_.empty()));
-
- // If there is more work available, wake up worker thread.
- if (!ready_to_run_tasks_.empty())
- has_ready_to_run_tasks_cv_.Signal();
- }
-}
-
-void WorkerPool::Inner::CollectCompletedTasks(TaskVector* completed_tasks) {
- base::AutoLock lock(lock_);
-
- DCHECK_EQ(0u, completed_tasks->size());
- completed_tasks->swap(completed_tasks_);
-}
-
-void WorkerPool::Inner::Run() {
- base::AutoLock lock(lock_);
-
- // Get a unique thread index.
- int thread_index = next_thread_index_++;
-
- while (true) {
- if (ready_to_run_tasks_.empty()) {
- // Exit when shutdown is set and no more tasks are pending.
- if (shutdown_ && pending_tasks_.empty())
- break;
-
- // Wait for more tasks.
- has_ready_to_run_tasks_cv_.Wait();
- continue;
- }
-
- // Take top priority task from |ready_to_run_tasks_|.
- scoped_refptr<internal::WorkerPoolTask> task(
- ready_to_run_tasks_.top()->task());
- ready_to_run_tasks_.pop();
-
- // Move task from |pending_tasks_| to |running_tasks_|.
- DCHECK(pending_tasks_.contains(task.get()));
- DCHECK(!running_tasks_.contains(task.get()));
- running_tasks_.set(task.get(), pending_tasks_.take_and_erase(task.get()));
-
- // There may be more work available, so wake up another worker thread.
- has_ready_to_run_tasks_cv_.Signal();
-
- // Call WillRun() before releasing |lock_| and running task.
- task->WillRun();
-
- {
- base::AutoUnlock unlock(lock_);
-
- task->RunOnWorkerThread(thread_index);
- }
-
- // This will mark task as finished running.
- task->DidRun();
-
- // Now iterate over all dependents to remove dependency and check
- // if they are ready to run.
- scoped_ptr<internal::GraphNode> node = running_tasks_.take_and_erase(
- task.get());
- if (node) {
- for (internal::GraphNode::Vector::const_iterator it =
- node->dependents().begin();
- it != node->dependents().end(); ++it) {
- internal::GraphNode* dependent_node = *it;
-
- dependent_node->remove_dependency();
- // Task is ready if it has no dependencies. Add it to
- // |ready_to_run_tasks_|.
- if (!dependent_node->num_dependencies())
- ready_to_run_tasks_.push(dependent_node);
- }
- }
-
- // Finally add task to |completed_tasks_|.
- completed_tasks_.push_back(task);
- }
-
- // We noticed we should exit. Wake up the next worker so it knows it should
- // exit as well (because the Shutdown() code only signals once).
- has_ready_to_run_tasks_cv_.Signal();
-}
-
-WorkerPool::WorkerPool(size_t num_threads,
- const std::string& thread_name_prefix)
- : in_dispatch_completion_callbacks_(false),
- inner_(make_scoped_ptr(new Inner(num_threads, thread_name_prefix))) {
-}
-
-WorkerPool::~WorkerPool() {
-}
-
-void WorkerPool::Shutdown() {
- TRACE_EVENT0("cc", "WorkerPool::Shutdown");
-
- DCHECK(!in_dispatch_completion_callbacks_);
-
- inner_->Shutdown();
-}
-
-void WorkerPool::CheckForCompletedTasks() {
- TRACE_EVENT0("cc", "WorkerPool::CheckForCompletedTasks");
-
- DCHECK(!in_dispatch_completion_callbacks_);
-
- TaskVector completed_tasks;
- inner_->CollectCompletedTasks(&completed_tasks);
- ProcessCompletedTasks(completed_tasks);
-}
-
-void WorkerPool::ProcessCompletedTasks(
- const TaskVector& completed_tasks) {
- TRACE_EVENT1("cc", "WorkerPool::ProcessCompletedTasks",
- "completed_task_count", completed_tasks.size());
-
- // Worker pool instance is not reentrant while processing completed tasks.
- in_dispatch_completion_callbacks_ = true;
-
- for (TaskVector::const_iterator it = completed_tasks.begin();
- it != completed_tasks.end();
- ++it) {
- internal::WorkerPoolTask* task = it->get();
-
- task->WillComplete();
- task->CompleteOnOriginThread();
- task->DidComplete();
- }
-
- in_dispatch_completion_callbacks_ = false;
-}
-
-void WorkerPool::SetTaskGraph(TaskGraph* graph) {
- TRACE_EVENT1("cc", "WorkerPool::SetTaskGraph",
- "num_tasks", graph->size());
-
- DCHECK(!in_dispatch_completion_callbacks_);
-
- inner_->SetTaskGraph(graph);
-}
-
-} // namespace cc
diff --git a/chromium/cc/resources/worker_pool.h b/chromium/cc/resources/worker_pool.h
deleted file mode 100644
index cc8c39f3642..00000000000
--- a/chromium/cc/resources/worker_pool.h
+++ /dev/null
@@ -1,143 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CC_RESOURCES_WORKER_POOL_H_
-#define CC_RESOURCES_WORKER_POOL_H_
-
-#include <deque>
-#include <string>
-#include <vector>
-
-#include "base/cancelable_callback.h"
-#include "base/containers/scoped_ptr_hash_map.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "cc/base/cc_export.h"
-
-namespace cc {
-namespace internal {
-
-class CC_EXPORT WorkerPoolTask
- : public base::RefCountedThreadSafe<WorkerPoolTask> {
- public:
- virtual void RunOnWorkerThread(unsigned thread_index) = 0;
- virtual void CompleteOnOriginThread() = 0;
-
- void DidSchedule();
- void WillRun();
- void DidRun();
- void WillComplete();
- void DidComplete();
-
- bool HasFinishedRunning() const;
- bool HasCompleted() const;
-
- protected:
- friend class base::RefCountedThreadSafe<WorkerPoolTask>;
-
- WorkerPoolTask();
- virtual ~WorkerPoolTask();
-
- private:
- bool did_schedule_;
- bool did_run_;
- bool did_complete_;
-};
-
-class CC_EXPORT GraphNode {
- public:
- typedef std::vector<GraphNode*> Vector;
-
- GraphNode(internal::WorkerPoolTask* task, unsigned priority);
- ~GraphNode();
-
- WorkerPoolTask* task() { return task_; }
-
- void add_dependent(GraphNode* dependent) {
- DCHECK(dependent);
- dependents_.push_back(dependent);
- }
- const Vector& dependents() const { return dependents_; }
-
- unsigned priority() const { return priority_; }
-
- unsigned num_dependencies() const { return num_dependencies_; }
- void add_dependency() { ++num_dependencies_; }
- void remove_dependency() {
- DCHECK(num_dependencies_);
- --num_dependencies_;
- }
-
- private:
- WorkerPoolTask* task_;
- Vector dependents_;
- unsigned priority_;
- unsigned num_dependencies_;
-
- DISALLOW_COPY_AND_ASSIGN(GraphNode);
-};
-
-} // namespace internal
-} // namespace cc
-
-#if defined(COMPILER_GCC)
-namespace BASE_HASH_NAMESPACE {
-template <> struct hash<cc::internal::WorkerPoolTask*> {
- size_t operator()(cc::internal::WorkerPoolTask* ptr) const {
- return hash<size_t>()(reinterpret_cast<size_t>(ptr));
- }
-};
-} // namespace BASE_HASH_NAMESPACE
-#endif // COMPILER
-
-namespace cc {
-
-// A worker thread pool that runs tasks provided by task graph and
-// guarantees completion of all pending tasks at shutdown.
-class CC_EXPORT WorkerPool {
- public:
- virtual ~WorkerPool();
-
- // Tells the worker pool to shutdown and returns once all pending tasks have
- // completed.
- virtual void Shutdown();
-
- // Force a check for completed tasks.
- virtual void CheckForCompletedTasks();
-
- protected:
- // A task graph contains a unique set of tasks with edges between
- // dependencies pointing in the direction of the dependents. Each task
- // need to be assigned a unique priority and a run count that matches
- // the number of dependencies.
- typedef base::ScopedPtrHashMap<internal::WorkerPoolTask*, internal::GraphNode>
- GraphNodeMap;
- typedef GraphNodeMap TaskGraph;
-
- WorkerPool(size_t num_threads, const std::string& thread_name_prefix);
-
- // Schedule running of tasks in |graph|. Any previously scheduled tasks
- // that are not already running will be canceled. Canceled tasks don't run
- // but completion of them is still processed.
- void SetTaskGraph(TaskGraph* graph);
-
- private:
- class Inner;
- friend class Inner;
-
- typedef std::vector<scoped_refptr<internal::WorkerPoolTask> > TaskVector;
-
- void ProcessCompletedTasks(const TaskVector& completed_tasks);
-
- bool in_dispatch_completion_callbacks_;
-
- // Hide the gory details of the worker pool in |inner_|.
- const scoped_ptr<Inner> inner_;
-};
-
-} // namespace cc
-
-#endif // CC_RESOURCES_WORKER_POOL_H_
diff --git a/chromium/cc/resources/worker_pool_perftest.cc b/chromium/cc/resources/worker_pool_perftest.cc
deleted file mode 100644
index 06a2b9806df..00000000000
--- a/chromium/cc/resources/worker_pool_perftest.cc
+++ /dev/null
@@ -1,235 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/resources/worker_pool.h"
-
-#include "base/time/time.h"
-#include "cc/base/completion_event.h"
-#include "cc/test/lap_timer.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/perf/perf_test.h"
-
-namespace cc {
-
-namespace {
-
-static const int kTimeLimitMillis = 2000;
-static const int kWarmupRuns = 5;
-static const int kTimeCheckInterval = 10;
-
-class PerfWorkerPoolTaskImpl : public internal::WorkerPoolTask {
- public:
- // Overridden from internal::WorkerPoolTask:
- virtual void RunOnWorkerThread(unsigned thread_index) OVERRIDE {}
- virtual void CompleteOnOriginThread() OVERRIDE {}
-
- private:
- virtual ~PerfWorkerPoolTaskImpl() {}
-};
-
-class PerfControlWorkerPoolTaskImpl : public internal::WorkerPoolTask {
- public:
- PerfControlWorkerPoolTaskImpl() : did_start_(new CompletionEvent),
- can_finish_(new CompletionEvent) {}
-
- // Overridden from internal::WorkerPoolTask:
- virtual void RunOnWorkerThread(unsigned thread_index) OVERRIDE {
- did_start_->Signal();
- can_finish_->Wait();
- }
- virtual void CompleteOnOriginThread() OVERRIDE {}
-
- void WaitForTaskToStartRunning() {
- did_start_->Wait();
- }
-
- void AllowTaskToFinish() {
- can_finish_->Signal();
- }
-
- private:
- virtual ~PerfControlWorkerPoolTaskImpl() {}
-
- scoped_ptr<CompletionEvent> did_start_;
- scoped_ptr<CompletionEvent> can_finish_;
-
- DISALLOW_COPY_AND_ASSIGN(PerfControlWorkerPoolTaskImpl);
-};
-
-class PerfWorkerPool : public WorkerPool {
- public:
- PerfWorkerPool() : WorkerPool(1, "test") {}
- virtual ~PerfWorkerPool() {}
-
- static scoped_ptr<PerfWorkerPool> Create() {
- return make_scoped_ptr(new PerfWorkerPool);
- }
-
- void ScheduleTasks(internal::WorkerPoolTask* root_task,
- internal::WorkerPoolTask* leaf_task,
- unsigned max_depth,
- unsigned num_children_per_node) {
- TaskVector tasks;
- TaskGraph graph;
-
- scoped_ptr<internal::GraphNode> root_node;
- if (root_task)
- root_node = make_scoped_ptr(new internal::GraphNode(root_task, 0u));
-
- scoped_ptr<internal::GraphNode> leaf_node;
- if (leaf_task)
- leaf_node = make_scoped_ptr(new internal::GraphNode(leaf_task, 0u));
-
- if (max_depth) {
- BuildTaskGraph(&tasks,
- &graph,
- root_node.get(),
- leaf_node.get(),
- 0,
- max_depth,
- num_children_per_node);
- }
-
- if (leaf_node)
- graph.set(leaf_task, leaf_node.Pass());
-
- if (root_node)
- graph.set(root_task, root_node.Pass());
-
- SetTaskGraph(&graph);
-
- tasks_.swap(tasks);
- }
-
- private:
- typedef std::vector<scoped_refptr<internal::WorkerPoolTask> > TaskVector;
-
- void BuildTaskGraph(TaskVector* tasks,
- TaskGraph* graph,
- internal::GraphNode* dependent_node,
- internal::GraphNode* leaf_node,
- unsigned current_depth,
- unsigned max_depth,
- unsigned num_children_per_node) {
- scoped_refptr<PerfWorkerPoolTaskImpl> task(new PerfWorkerPoolTaskImpl);
- scoped_ptr<internal::GraphNode> node(
- new internal::GraphNode(task.get(), 0u));
-
- if (current_depth < max_depth) {
- for (unsigned i = 0; i < num_children_per_node; ++i) {
- BuildTaskGraph(tasks,
- graph,
- node.get(),
- leaf_node,
- current_depth + 1,
- max_depth,
- num_children_per_node);
- }
- } else if (leaf_node) {
- leaf_node->add_dependent(node.get());
- node->add_dependency();
- }
-
- if (dependent_node) {
- node->add_dependent(dependent_node);
- dependent_node->add_dependency();
- }
- graph->set(task.get(), node.Pass());
- tasks->push_back(task.get());
- }
-
- TaskVector tasks_;
-
- DISALLOW_COPY_AND_ASSIGN(PerfWorkerPool);
-};
-
-class WorkerPoolPerfTest : public testing::Test {
- public:
- WorkerPoolPerfTest()
- : timer_(kWarmupRuns,
- base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
- kTimeCheckInterval) {}
-
- // Overridden from testing::Test:
- virtual void SetUp() OVERRIDE {
- worker_pool_ = PerfWorkerPool::Create();
- }
- virtual void TearDown() OVERRIDE {
- worker_pool_->Shutdown();
- worker_pool_->CheckForCompletedTasks();
- }
-
- void AfterTest(const std::string& test_name) {
- // Format matches chrome/test/perf/perf_test.h:PrintResult
- printf(
- "*RESULT %s: %.2f runs/s\n", test_name.c_str(), timer_.LapsPerSecond());
- }
-
- void RunScheduleTasksTest(const std::string& test_name,
- unsigned max_depth,
- unsigned num_children_per_node) {
- timer_.Reset();
- do {
- scoped_refptr<PerfControlWorkerPoolTaskImpl> leaf_task(
- new PerfControlWorkerPoolTaskImpl);
- worker_pool_->ScheduleTasks(
- NULL, leaf_task.get(), max_depth, num_children_per_node);
- leaf_task->WaitForTaskToStartRunning();
- worker_pool_->ScheduleTasks(NULL, NULL, 0, 0);
- worker_pool_->CheckForCompletedTasks();
- leaf_task->AllowTaskToFinish();
- timer_.NextLap();
- } while (!timer_.HasTimeLimitExpired());
-
- perf_test::PrintResult("schedule_tasks", "", test_name,
- timer_.LapsPerSecond(), "runs/s", true);
- }
-
- void RunExecuteTasksTest(const std::string& test_name,
- unsigned max_depth,
- unsigned num_children_per_node) {
- timer_.Reset();
- do {
- scoped_refptr<PerfControlWorkerPoolTaskImpl> root_task(
- new PerfControlWorkerPoolTaskImpl);
- worker_pool_->ScheduleTasks(
- root_task.get(), NULL, max_depth, num_children_per_node);
- root_task->WaitForTaskToStartRunning();
- root_task->AllowTaskToFinish();
- worker_pool_->CheckForCompletedTasks();
- timer_.NextLap();
- } while (!timer_.HasTimeLimitExpired());
-
- perf_test::PrintResult("execute_tasks", "", test_name,
- timer_.LapsPerSecond(), "runs/s", true);
- }
-
- protected:
- scoped_ptr<PerfWorkerPool> worker_pool_;
- LapTimer timer_;
-};
-
-TEST_F(WorkerPoolPerfTest, ScheduleTasks) {
- RunScheduleTasksTest("1_10", 1, 10);
- RunScheduleTasksTest("1_1000", 1, 1000);
- RunScheduleTasksTest("2_10", 2, 10);
- RunScheduleTasksTest("5_5", 5, 5);
- RunScheduleTasksTest("10_2", 10, 2);
- RunScheduleTasksTest("1000_1", 1000, 1);
- RunScheduleTasksTest("10_1", 10, 1);
-}
-
-TEST_F(WorkerPoolPerfTest, ExecuteTasks) {
- RunExecuteTasksTest("1_10", 1, 10);
- RunExecuteTasksTest("1_1000", 1, 1000);
- RunExecuteTasksTest("2_10", 2, 10);
- RunExecuteTasksTest("5_5", 5, 5);
- RunExecuteTasksTest("10_2", 10, 2);
- RunExecuteTasksTest("1000_1", 1000, 1);
- RunExecuteTasksTest("10_1", 10, 1);
-}
-
-} // namespace
-
-} // namespace cc
diff --git a/chromium/cc/resources/worker_pool_unittest.cc b/chromium/cc/resources/worker_pool_unittest.cc
deleted file mode 100644
index f7c5a951df6..00000000000
--- a/chromium/cc/resources/worker_pool_unittest.cc
+++ /dev/null
@@ -1,394 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/resources/worker_pool.h"
-
-#include <vector>
-
-#include "cc/base/completion_event.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace cc {
-
-namespace {
-
-class FakeWorkerPoolTaskImpl : public internal::WorkerPoolTask {
- public:
- FakeWorkerPoolTaskImpl(const base::Closure& callback,
- const base::Closure& reply)
- : callback_(callback),
- reply_(reply) {
- }
-
- // Overridden from internal::WorkerPoolTask:
- virtual void RunOnWorkerThread(unsigned thread_index) OVERRIDE {
- if (!callback_.is_null())
- callback_.Run();
- }
- virtual void CompleteOnOriginThread() OVERRIDE {
- if (!reply_.is_null())
- reply_.Run();
- }
-
- private:
- virtual ~FakeWorkerPoolTaskImpl() {}
-
- const base::Closure callback_;
- const base::Closure reply_;
-
- DISALLOW_COPY_AND_ASSIGN(FakeWorkerPoolTaskImpl);
-};
-
-class FakeWorkerPool : public WorkerPool {
- public:
- struct Task {
- Task(const base::Closure& callback,
- const base::Closure& reply,
- const base::Closure& dependent,
- unsigned dependent_count,
- unsigned priority) : callback(callback),
- reply(reply),
- dependent(dependent),
- dependent_count(dependent_count),
- priority(priority) {
- }
-
- base::Closure callback;
- base::Closure reply;
- base::Closure dependent;
- unsigned dependent_count;
- unsigned priority;
- };
- FakeWorkerPool() : WorkerPool(1, "test") {}
- virtual ~FakeWorkerPool() {}
-
- static scoped_ptr<FakeWorkerPool> Create() {
- return make_scoped_ptr(new FakeWorkerPool);
- }
-
- void ScheduleTasks(const std::vector<Task>& tasks) {
- TaskVector new_tasks;
- TaskVector new_dependents;
- TaskGraph new_graph;
-
- scoped_refptr<FakeWorkerPoolTaskImpl> new_completion_task(
- new FakeWorkerPoolTaskImpl(
- base::Bind(&FakeWorkerPool::OnTasksCompleted,
- base::Unretained(this)),
- base::Closure()));
- scoped_ptr<internal::GraphNode> completion_node(
- new internal::GraphNode(new_completion_task.get(), 0u));
-
- for (std::vector<Task>::const_iterator it = tasks.begin();
- it != tasks.end(); ++it) {
- scoped_refptr<FakeWorkerPoolTaskImpl> new_task(
- new FakeWorkerPoolTaskImpl(it->callback, it->reply));
- scoped_ptr<internal::GraphNode> node(
- new internal::GraphNode(new_task.get(), it->priority));
-
- DCHECK(it->dependent_count);
- for (unsigned i = 0; i < it->dependent_count; ++i) {
- scoped_refptr<FakeWorkerPoolTaskImpl> new_dependent_task(
- new FakeWorkerPoolTaskImpl(it->dependent, base::Closure()));
- scoped_ptr<internal::GraphNode> dependent_node(
- new internal::GraphNode(new_dependent_task.get(), it->priority));
- dependent_node->add_dependent(completion_node.get());
- completion_node->add_dependency();
- node->add_dependent(dependent_node.get());
- dependent_node->add_dependency();
- new_graph.set(new_dependent_task.get(), dependent_node.Pass());
- new_dependents.push_back(new_dependent_task.get());
- }
-
- new_graph.set(new_task.get(), node.Pass());
- new_tasks.push_back(new_task.get());
- }
-
- new_graph.set(new_completion_task.get(), completion_node.Pass());
-
- scheduled_tasks_completion_.reset(new CompletionEvent);
-
- SetTaskGraph(&new_graph);
-
- dependents_.swap(new_dependents);
- completion_task_.swap(new_completion_task);
- tasks_.swap(new_tasks);
- }
-
- void WaitForTasksToComplete() {
- DCHECK(scheduled_tasks_completion_);
- scheduled_tasks_completion_->Wait();
- }
-
- private:
- typedef std::vector<scoped_refptr<internal::WorkerPoolTask> > TaskVector;
-
- void OnTasksCompleted() {
- DCHECK(scheduled_tasks_completion_);
- scheduled_tasks_completion_->Signal();
- }
-
- TaskVector tasks_;
- TaskVector dependents_;
- scoped_refptr<FakeWorkerPoolTaskImpl> completion_task_;
- scoped_ptr<CompletionEvent> scheduled_tasks_completion_;
-
- DISALLOW_COPY_AND_ASSIGN(FakeWorkerPool);
-};
-
-class WorkerPoolTest : public testing::Test {
- public:
- WorkerPoolTest() {}
- virtual ~WorkerPoolTest() {}
-
- // Overridden from testing::Test:
- virtual void SetUp() OVERRIDE {
- worker_pool_ = FakeWorkerPool::Create();
- }
- virtual void TearDown() OVERRIDE {
- worker_pool_->Shutdown();
- worker_pool_->CheckForCompletedTasks();
- }
-
- void ResetIds() {
- run_task_ids_.clear();
- on_task_completed_ids_.clear();
- }
-
- void RunAllTasks() {
- worker_pool_->WaitForTasksToComplete();
- worker_pool_->CheckForCompletedTasks();
- }
-
- FakeWorkerPool* worker_pool() {
- return worker_pool_.get();
- }
-
- void RunTask(unsigned id) {
- run_task_ids_.push_back(id);
- }
-
- void OnTaskCompleted(unsigned id) {
- on_task_completed_ids_.push_back(id);
- }
-
- const std::vector<unsigned>& run_task_ids() {
- return run_task_ids_;
- }
-
- const std::vector<unsigned>& on_task_completed_ids() {
- return on_task_completed_ids_;
- }
-
- private:
- scoped_ptr<FakeWorkerPool> worker_pool_;
- std::vector<unsigned> run_task_ids_;
- std::vector<unsigned> on_task_completed_ids_;
-};
-
-TEST_F(WorkerPoolTest, Basic) {
- EXPECT_EQ(0u, run_task_ids().size());
- EXPECT_EQ(0u, on_task_completed_ids().size());
-
- worker_pool()->ScheduleTasks(
- std::vector<FakeWorkerPool::Task>(
- 1,
- FakeWorkerPool::Task(base::Bind(&WorkerPoolTest::RunTask,
- base::Unretained(this),
- 0u),
- base::Bind(&WorkerPoolTest::OnTaskCompleted,
- base::Unretained(this),
- 0u),
- base::Closure(),
- 1u,
- 0u)));
- RunAllTasks();
-
- EXPECT_EQ(1u, run_task_ids().size());
- EXPECT_EQ(1u, on_task_completed_ids().size());
-
- worker_pool()->ScheduleTasks(
- std::vector<FakeWorkerPool::Task>(
- 1,
- FakeWorkerPool::Task(base::Bind(&WorkerPoolTest::RunTask,
- base::Unretained(this),
- 0u),
- base::Bind(&WorkerPoolTest::OnTaskCompleted,
- base::Unretained(this),
- 0u),
- base::Bind(&WorkerPoolTest::RunTask,
- base::Unretained(this),
- 0u),
- 1u,
- 0u)));
- RunAllTasks();
-
- EXPECT_EQ(3u, run_task_ids().size());
- EXPECT_EQ(2u, on_task_completed_ids().size());
-
- worker_pool()->ScheduleTasks(
- std::vector<FakeWorkerPool::Task>(
- 1, FakeWorkerPool::Task(base::Bind(&WorkerPoolTest::RunTask,
- base::Unretained(this),
- 0u),
- base::Bind(&WorkerPoolTest::OnTaskCompleted,
- base::Unretained(this),
- 0u),
- base::Bind(&WorkerPoolTest::RunTask,
- base::Unretained(this),
- 0u),
- 2u,
- 0u)));
- RunAllTasks();
-
- EXPECT_EQ(6u, run_task_ids().size());
- EXPECT_EQ(3u, on_task_completed_ids().size());
-}
-
-TEST_F(WorkerPoolTest, Dependencies) {
- worker_pool()->ScheduleTasks(
- std::vector<FakeWorkerPool::Task>(
- 1, FakeWorkerPool::Task(base::Bind(&WorkerPoolTest::RunTask,
- base::Unretained(this),
- 0u),
- base::Bind(&WorkerPoolTest::OnTaskCompleted,
- base::Unretained(this),
- 0u),
- base::Bind(&WorkerPoolTest::RunTask,
- base::Unretained(this),
- 1u),
- 1u,
- 0u)));
- RunAllTasks();
-
- // Check if task ran before dependent.
- ASSERT_EQ(2u, run_task_ids().size());
- EXPECT_EQ(0u, run_task_ids()[0]);
- EXPECT_EQ(1u, run_task_ids()[1]);
- ASSERT_EQ(1u, on_task_completed_ids().size());
- EXPECT_EQ(0u, on_task_completed_ids()[0]);
-
- worker_pool()->ScheduleTasks(
- std::vector<FakeWorkerPool::Task>(
- 1, FakeWorkerPool::Task(base::Bind(&WorkerPoolTest::RunTask,
- base::Unretained(this),
- 2u),
- base::Bind(&WorkerPoolTest::OnTaskCompleted,
- base::Unretained(this),
- 2u),
- base::Bind(&WorkerPoolTest::RunTask,
- base::Unretained(this),
- 3u),
- 2u,
- 0u)));
- RunAllTasks();
-
- // Task should only run once.
- ASSERT_EQ(5u, run_task_ids().size());
- EXPECT_EQ(2u, run_task_ids()[2]);
- EXPECT_EQ(3u, run_task_ids()[3]);
- EXPECT_EQ(3u, run_task_ids()[4]);
- ASSERT_EQ(2u, on_task_completed_ids().size());
- EXPECT_EQ(2u, on_task_completed_ids()[1]);
-}
-
-TEST_F(WorkerPoolTest, Priority) {
- {
- FakeWorkerPool::Task tasks[] = {
- FakeWorkerPool::Task(base::Bind(&WorkerPoolTest::RunTask,
- base::Unretained(this),
- 0u),
- base::Bind(&WorkerPoolTest::OnTaskCompleted,
- base::Unretained(this),
- 0u),
- base::Bind(&WorkerPoolTest::RunTask,
- base::Unretained(this),
- 2u),
- 1u,
- 1u), // Priority 1
- FakeWorkerPool::Task(base::Bind(&WorkerPoolTest::RunTask,
- base::Unretained(this),
- 1u),
- base::Bind(&WorkerPoolTest::OnTaskCompleted,
- base::Unretained(this),
- 1u),
- base::Bind(&WorkerPoolTest::RunTask,
- base::Unretained(this),
- 3u),
- 1u,
- 0u) // Priority 0
- };
- worker_pool()->ScheduleTasks(
- std::vector<FakeWorkerPool::Task>(tasks, tasks + arraysize(tasks)));
- }
- RunAllTasks();
-
- // Check if tasks ran in order of priority.
- ASSERT_EQ(4u, run_task_ids().size());
- EXPECT_EQ(1u, run_task_ids()[0]);
- EXPECT_EQ(3u, run_task_ids()[1]);
- EXPECT_EQ(0u, run_task_ids()[2]);
- EXPECT_EQ(2u, run_task_ids()[3]);
- ASSERT_EQ(2u, on_task_completed_ids().size());
- EXPECT_EQ(1u, on_task_completed_ids()[0]);
- EXPECT_EQ(0u, on_task_completed_ids()[1]);
-
- ResetIds();
- {
- std::vector<FakeWorkerPool::Task> tasks;
- tasks.push_back(
- FakeWorkerPool::Task(base::Bind(&WorkerPoolTest::RunTask,
- base::Unretained(this),
- 0u),
- base::Bind(&WorkerPoolTest::OnTaskCompleted,
- base::Unretained(this),
- 0u),
- base::Bind(&WorkerPoolTest::RunTask,
- base::Unretained(this),
- 3u),
- 1u, // 1 dependent
- 1u)); // Priority 1
- tasks.push_back(
- FakeWorkerPool::Task(base::Bind(&WorkerPoolTest::RunTask,
- base::Unretained(this),
- 1u),
- base::Bind(&WorkerPoolTest::OnTaskCompleted,
- base::Unretained(this),
- 1u),
- base::Bind(&WorkerPoolTest::RunTask,
- base::Unretained(this),
- 4u),
- 2u, // 2 dependents
- 1u)); // Priority 1
- tasks.push_back(
- FakeWorkerPool::Task(base::Bind(&WorkerPoolTest::RunTask,
- base::Unretained(this),
- 2u),
- base::Bind(&WorkerPoolTest::OnTaskCompleted,
- base::Unretained(this),
- 2u),
- base::Bind(&WorkerPoolTest::RunTask,
- base::Unretained(this),
- 5u),
- 1u, // 1 dependent
- 0u)); // Priority 0
- worker_pool()->ScheduleTasks(tasks);
- }
- RunAllTasks();
-
- // Check if tasks ran in order of priority and that task with more
- // dependents ran first when priority is the same.
- ASSERT_LE(3u, run_task_ids().size());
- EXPECT_EQ(2u, run_task_ids()[0]);
- EXPECT_EQ(5u, run_task_ids()[1]);
- EXPECT_EQ(1u, run_task_ids()[2]);
- ASSERT_EQ(3u, on_task_completed_ids().size());
- EXPECT_EQ(2u, on_task_completed_ids()[0]);
- EXPECT_EQ(1u, on_task_completed_ids()[1]);
- EXPECT_EQ(0u, on_task_completed_ids()[2]);
-}
-
-} // namespace
-
-} // namespace cc
diff --git a/chromium/cc/scheduler/delay_based_time_source.cc b/chromium/cc/scheduler/delay_based_time_source.cc
index 00515b72f76..2be3d3d472a 100644
--- a/chromium/cc/scheduler/delay_based_time_source.cc
+++ b/chromium/cc/scheduler/delay_based_time_source.cc
@@ -6,6 +6,7 @@
#include <algorithm>
#include <cmath>
+#include <string>
#include "base/bind.h"
#include "base/debug/trace_event.h"
@@ -43,8 +44,10 @@ scoped_refptr<DelayBasedTimeSourceHighRes> DelayBasedTimeSourceHighRes::Create(
}
DelayBasedTimeSourceHighRes::DelayBasedTimeSourceHighRes(
- base::TimeDelta interval, base::SingleThreadTaskRunner* task_runner)
- : DelayBasedTimeSource(interval, task_runner) {}
+ base::TimeDelta interval,
+ base::SingleThreadTaskRunner* task_runner)
+ : DelayBasedTimeSource(interval, task_runner) {
+}
DelayBasedTimeSourceHighRes::~DelayBasedTimeSourceHighRes() {}
@@ -61,14 +64,17 @@ scoped_refptr<DelayBasedTimeSource> DelayBasedTimeSource::Create(
}
DelayBasedTimeSource::DelayBasedTimeSource(
- base::TimeDelta interval, base::SingleThreadTaskRunner* task_runner)
+ base::TimeDelta interval,
+ base::SingleThreadTaskRunner* task_runner)
: client_(NULL),
last_tick_time_(base::TimeTicks() - interval),
current_parameters_(interval, base::TimeTicks()),
next_parameters_(interval, base::TimeTicks()),
active_(false),
task_runner_(task_runner),
- weak_factory_(this) {}
+ weak_factory_(this) {
+ DCHECK_GT(interval.ToInternalValue(), 0);
+}
DelayBasedTimeSource::~DelayBasedTimeSource() {}
@@ -100,9 +106,11 @@ base::TimeTicks DelayBasedTimeSource::SetActive(bool active) {
bool DelayBasedTimeSource::Active() const { return active_; }
-base::TimeTicks DelayBasedTimeSource::LastTickTime() { return last_tick_time_; }
+base::TimeTicks DelayBasedTimeSource::LastTickTime() const {
+ return last_tick_time_;
+}
-base::TimeTicks DelayBasedTimeSource::NextTickTime() {
+base::TimeTicks DelayBasedTimeSource::NextTickTime() const {
return Active() ? current_parameters_.tick_target : base::TimeTicks();
}
@@ -124,6 +132,7 @@ void DelayBasedTimeSource::SetClient(TimeSourceClient* client) {
void DelayBasedTimeSource::SetTimebaseAndInterval(base::TimeTicks timebase,
base::TimeDelta interval) {
+ DCHECK_GT(interval.ToInternalValue(), 0);
next_parameters_.interval = interval;
next_parameters_.tick_target = timebase;
@@ -272,4 +281,39 @@ void DelayBasedTimeSource::PostNextTickTask(base::TimeTicks now) {
current_parameters_ = next_parameters_;
}
+std::string DelayBasedTimeSource::TypeString() const {
+ return "DelayBasedTimeSource";
+}
+
+std::string DelayBasedTimeSourceHighRes::TypeString() const {
+ return "DelayBasedTimeSourceHighRes";
+}
+
+scoped_ptr<base::Value> DelayBasedTimeSource::AsValue() const {
+ scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue);
+ state->SetString("type", TypeString());
+ state->SetDouble("last_tick_time_us", LastTickTime().ToInternalValue());
+ state->SetDouble("next_tick_time_us", NextTickTime().ToInternalValue());
+
+ scoped_ptr<base::DictionaryValue> state_current_parameters(
+ new base::DictionaryValue);
+ state_current_parameters->SetDouble(
+ "interval_us", current_parameters_.interval.InMicroseconds());
+ state_current_parameters->SetDouble(
+ "tick_target_us", current_parameters_.tick_target.ToInternalValue());
+ state->Set("current_parameters", state_current_parameters.release());
+
+ scoped_ptr<base::DictionaryValue> state_next_parameters(
+ new base::DictionaryValue);
+ state_next_parameters->SetDouble("interval_us",
+ next_parameters_.interval.InMicroseconds());
+ state_next_parameters->SetDouble(
+ "tick_target_us", next_parameters_.tick_target.ToInternalValue());
+ state->Set("next_parameters", state_next_parameters.release());
+
+ state->SetBoolean("active", active_);
+
+ return state.PassAs<base::Value>();
+}
+
} // namespace cc
diff --git a/chromium/cc/scheduler/delay_based_time_source.h b/chromium/cc/scheduler/delay_based_time_source.h
index ddb89da3566..18c8002f292 100644
--- a/chromium/cc/scheduler/delay_based_time_source.h
+++ b/chromium/cc/scheduler/delay_based_time_source.h
@@ -5,44 +5,59 @@
#ifndef CC_SCHEDULER_DELAY_BASED_TIME_SOURCE_H_
#define CC_SCHEDULER_DELAY_BASED_TIME_SOURCE_H_
+#include <string>
+
#include "base/memory/weak_ptr.h"
+#include "base/values.h"
#include "cc/base/cc_export.h"
-#include "cc/scheduler/time_source.h"
namespace base { class SingleThreadTaskRunner; }
namespace cc {
+class CC_EXPORT TimeSourceClient {
+ public:
+ virtual void OnTimerTick() = 0;
+
+ protected:
+ virtual ~TimeSourceClient() {}
+};
+
// This timer implements a time source that achieves the specified interval
// in face of millisecond-precision delayed callbacks and random queueing
// delays. DelayBasedTimeSource uses base::TimeTicks::Now as its timebase.
-class CC_EXPORT DelayBasedTimeSource : public TimeSource {
+class CC_EXPORT DelayBasedTimeSource
+ : public base::RefCounted<DelayBasedTimeSource> {
public:
static scoped_refptr<DelayBasedTimeSource> Create(
base::TimeDelta interval, base::SingleThreadTaskRunner* task_runner);
- virtual void SetClient(TimeSourceClient* client) OVERRIDE;
+ virtual void SetClient(TimeSourceClient* client);
// TimeSource implementation
virtual void SetTimebaseAndInterval(base::TimeTicks timebase,
- base::TimeDelta interval) OVERRIDE;
+ base::TimeDelta interval);
- virtual base::TimeTicks SetActive(bool active) OVERRIDE;
- virtual bool Active() const OVERRIDE;
+ virtual base::TimeTicks SetActive(bool active);
+ virtual bool Active() const;
- // Get the last and next tick times. nextTimeTime() returns null when
+ // Get the last and next tick times. NextTickTime() returns null when
// inactive.
- virtual base::TimeTicks LastTickTime() OVERRIDE;
- virtual base::TimeTicks NextTickTime() OVERRIDE;
+ virtual base::TimeTicks LastTickTime() const;
+ virtual base::TimeTicks NextTickTime() const;
// Virtual for testing.
virtual base::TimeTicks Now() const;
+ virtual scoped_ptr<base::Value> AsValue() const;
+
protected:
DelayBasedTimeSource(base::TimeDelta interval,
base::SingleThreadTaskRunner* task_runner);
virtual ~DelayBasedTimeSource();
+ virtual std::string TypeString() const;
+
base::TimeTicks NextTickTarget(base::TimeTicks now);
void PostNextTickTask(base::TimeTicks now);
void OnTimerFired();
@@ -70,6 +85,7 @@ class CC_EXPORT DelayBasedTimeSource : public TimeSource {
base::WeakPtrFactory<DelayBasedTimeSource> weak_factory_;
private:
+ friend class base::RefCounted<DelayBasedTimeSource>;
DISALLOW_COPY_AND_ASSIGN(DelayBasedTimeSource);
};
@@ -86,6 +102,8 @@ class DelayBasedTimeSourceHighRes : public DelayBasedTimeSource {
base::SingleThreadTaskRunner* task_runner);
virtual ~DelayBasedTimeSourceHighRes();
+ virtual std::string TypeString() const OVERRIDE;
+
private:
DISALLOW_COPY_AND_ASSIGN(DelayBasedTimeSourceHighRes);
};
diff --git a/chromium/cc/scheduler/delay_based_time_source_unittest.cc b/chromium/cc/scheduler/delay_based_time_source_unittest.cc
index 42652e21868..0af8b02f4b9 100644
--- a/chromium/cc/scheduler/delay_based_time_source_unittest.cc
+++ b/chromium/cc/scheduler/delay_based_time_source_unittest.cc
@@ -35,7 +35,7 @@ TEST(DelayBasedTimeSourceTest, TaskPostedAndTickCalled) {
EXPECT_TRUE(client.TickCalled());
}
-TEST(DelayBasedTimeSource, TickNotCalledWithTaskPosted) {
+TEST(DelayBasedTimeSourceTest, TickNotCalledWithTaskPosted) {
scoped_refptr<base::TestSimpleTaskRunner> task_runner =
new base::TestSimpleTaskRunner;
FakeTimeSourceClient client;
@@ -49,7 +49,7 @@ TEST(DelayBasedTimeSource, TickNotCalledWithTaskPosted) {
EXPECT_FALSE(client.TickCalled());
}
-TEST(DelayBasedTimeSource, StartTwiceEnqueuesOneTask) {
+TEST(DelayBasedTimeSourceTest, StartTwiceEnqueuesOneTask) {
scoped_refptr<base::TestSimpleTaskRunner> task_runner =
new base::TestSimpleTaskRunner;
FakeTimeSourceClient client;
@@ -63,7 +63,7 @@ TEST(DelayBasedTimeSource, StartTwiceEnqueuesOneTask) {
EXPECT_FALSE(task_runner->HasPendingTask());
}
-TEST(DelayBasedTimeSource, StartWhenRunningDoesntTick) {
+TEST(DelayBasedTimeSourceTest, StartWhenRunningDoesntTick) {
scoped_refptr<base::TestSimpleTaskRunner> task_runner =
new base::TestSimpleTaskRunner;
FakeTimeSourceClient client;
@@ -80,7 +80,7 @@ TEST(DelayBasedTimeSource, StartWhenRunningDoesntTick) {
// At 60Hz, when the tick returns at exactly the requested next time, make sure
// a 16ms next delay is posted.
-TEST(DelayBasedTimeSource, NextDelaySaneWhenExactlyOnRequestedTime) {
+TEST(DelayBasedTimeSourceTest, NextDelaySaneWhenExactlyOnRequestedTime) {
scoped_refptr<base::TestSimpleTaskRunner> task_runner =
new base::TestSimpleTaskRunner;
FakeTimeSourceClient client;
@@ -101,7 +101,7 @@ TEST(DelayBasedTimeSource, NextDelaySaneWhenExactlyOnRequestedTime) {
// At 60Hz, when the tick returns at slightly after the requested next time,
// make sure a 16ms next delay is posted.
-TEST(DelayBasedTimeSource, NextDelaySaneWhenSlightlyAfterRequestedTime) {
+TEST(DelayBasedTimeSourceTest, NextDelaySaneWhenSlightlyAfterRequestedTime) {
scoped_refptr<base::TestSimpleTaskRunner> task_runner =
new base::TestSimpleTaskRunner;
FakeTimeSourceClient client;
@@ -123,7 +123,8 @@ TEST(DelayBasedTimeSource, NextDelaySaneWhenSlightlyAfterRequestedTime) {
// At 60Hz, when the tick returns at exactly 2*interval after the requested next
// time, make sure a 0ms next delay is posted.
-TEST(DelayBasedTimeSource, NextDelaySaneWhenExactlyTwiceAfterRequestedTime) {
+TEST(DelayBasedTimeSourceTest,
+ NextDelaySaneWhenExactlyTwiceAfterRequestedTime) {
scoped_refptr<base::TestSimpleTaskRunner> task_runner =
new base::TestSimpleTaskRunner;
FakeTimeSourceClient client;
@@ -144,7 +145,8 @@ TEST(DelayBasedTimeSource, NextDelaySaneWhenExactlyTwiceAfterRequestedTime) {
// At 60Hz, when the tick returns at 2*interval and a bit after the requested
// next time, make sure a 16ms next delay is posted.
-TEST(DelayBasedTimeSource, NextDelaySaneWhenSlightlyAfterTwiceRequestedTime) {
+TEST(DelayBasedTimeSourceTest,
+ NextDelaySaneWhenSlightlyAfterTwiceRequestedTime) {
scoped_refptr<base::TestSimpleTaskRunner> task_runner =
new base::TestSimpleTaskRunner;
FakeTimeSourceClient client;
@@ -166,7 +168,7 @@ TEST(DelayBasedTimeSource, NextDelaySaneWhenSlightlyAfterTwiceRequestedTime) {
// At 60Hz, when the tick returns halfway to the next frame time, make sure
// a correct next delay value is posted.
-TEST(DelayBasedTimeSource, NextDelaySaneWhenHalfAfterRequestedTime) {
+TEST(DelayBasedTimeSourceTest, NextDelaySaneWhenHalfAfterRequestedTime) {
scoped_refptr<base::TestSimpleTaskRunner> task_runner =
new base::TestSimpleTaskRunner;
FakeTimeSourceClient client;
@@ -188,7 +190,7 @@ TEST(DelayBasedTimeSource, NextDelaySaneWhenHalfAfterRequestedTime) {
// If the timebase and interval are updated with a jittery source, we want to
// make sure we do not double tick.
-TEST(DelayBasedTimeSource, SaneHandlingOfJitteryTimebase) {
+TEST(DelayBasedTimeSourceTest, SaneHandlingOfJitteryTimebase) {
scoped_refptr<base::TestSimpleTaskRunner> task_runner =
new base::TestSimpleTaskRunner;
FakeTimeSourceClient client;
@@ -219,7 +221,7 @@ TEST(DelayBasedTimeSource, SaneHandlingOfJitteryTimebase) {
EXPECT_EQ(15, task_runner->NextPendingTaskDelay().InMilliseconds());
}
-TEST(DelayBasedTimeSource, HandlesSignificantTimebaseChangesImmediately) {
+TEST(DelayBasedTimeSourceTest, HandlesSignificantTimebaseChangesImmediately) {
scoped_refptr<base::TestSimpleTaskRunner> task_runner =
new base::TestSimpleTaskRunner;
FakeTimeSourceClient client;
@@ -263,7 +265,7 @@ TEST(DelayBasedTimeSource, HandlesSignificantTimebaseChangesImmediately) {
EXPECT_EQ(16 - 7, task_runner->NextPendingTaskDelay().InMilliseconds());
}
-TEST(DelayBasedTimeSource, HanldlesSignificantIntervalChangesImmediately) {
+TEST(DelayBasedTimeSourceTest, HanldlesSignificantIntervalChangesImmediately) {
scoped_refptr<base::TestSimpleTaskRunner> task_runner =
new base::TestSimpleTaskRunner;
FakeTimeSourceClient client;
@@ -305,7 +307,7 @@ TEST(DelayBasedTimeSource, HanldlesSignificantIntervalChangesImmediately) {
EXPECT_EQ(16, task_runner->NextPendingTaskDelay().InMilliseconds());
}
-TEST(DelayBasedTimeSource, JitteryRuntimeWithFutureTimebases) {
+TEST(DelayBasedTimeSourceTest, JitteryRuntimeWithFutureTimebases) {
scoped_refptr<base::TestSimpleTaskRunner> task_runner =
new base::TestSimpleTaskRunner;
FakeTimeSourceClient client;
@@ -441,7 +443,7 @@ TEST(DelayBasedTimeSourceTest, AchievesTargetRateWithNoNoise) {
EXPECT_NEAR(1.0 / 60.0, average_interval, 0.1);
}
-TEST(DelayBasedTimeSource, TestDeactivateWhilePending) {
+TEST(DelayBasedTimeSourceTest, TestDeactivateWhilePending) {
scoped_refptr<base::TestSimpleTaskRunner> task_runner =
new base::TestSimpleTaskRunner;
FakeTimeSourceClient client;
@@ -456,7 +458,7 @@ TEST(DelayBasedTimeSource, TestDeactivateWhilePending) {
task_runner->RunPendingTasks();
}
-TEST(DelayBasedTimeSource, TestDeactivateAndReactivateBeforeNextTickTime) {
+TEST(DelayBasedTimeSourceTest, TestDeactivateAndReactivateBeforeNextTickTime) {
scoped_refptr<base::TestSimpleTaskRunner> task_runner =
new base::TestSimpleTaskRunner;
FakeTimeSourceClient client;
@@ -481,7 +483,7 @@ TEST(DelayBasedTimeSource, TestDeactivateAndReactivateBeforeNextTickTime) {
EXPECT_EQ(12, task_runner->NextPendingTaskDelay().InMilliseconds());
}
-TEST(DelayBasedTimeSource, TestDeactivateAndReactivateAfterNextTickTime) {
+TEST(DelayBasedTimeSourceTest, TestDeactivateAndReactivateAfterNextTickTime) {
scoped_refptr<base::TestSimpleTaskRunner> task_runner =
new base::TestSimpleTaskRunner;
FakeTimeSourceClient client;
@@ -506,7 +508,7 @@ TEST(DelayBasedTimeSource, TestDeactivateAndReactivateAfterNextTickTime) {
EXPECT_EQ(13, task_runner->NextPendingTaskDelay().InMilliseconds());
}
-TEST(DelayBasedTimeSource, TestOverflow) {
+TEST(DelayBasedTimeSourceTest, TestOverflow) {
// int(big_now / interval) < 0, so this causes a crash if the number of
// intervals elapsed is attempted to be stored in an int.
base::TimeDelta interval = base::TimeDelta::FromInternalValue(4000);
@@ -523,5 +525,21 @@ TEST(DelayBasedTimeSource, TestOverflow) {
EXPECT_EQ(0, task_runner->NextPendingTaskDelay().InMilliseconds());
}
+TEST(DelayBasedTimeSourceTest, TestReturnValueWhenTimerIsDeActivated) {
+ scoped_refptr<base::TestSimpleTaskRunner> task_runner =
+ new base::TestSimpleTaskRunner;
+ FakeTimeSourceClient client;
+ scoped_refptr<FakeDelayBasedTimeSource> timer =
+ FakeDelayBasedTimeSource::Create(Interval(), task_runner.get());
+ timer->SetClient(&client);
+
+ timer->SetActive(true);
+ task_runner->RunPendingTasks();
+
+ // SetActive should return empty TimeTicks when the timer is deactivated.
+ base::TimeTicks missed_tick_time = timer->SetActive(false);
+ EXPECT_TRUE(missed_tick_time.is_null());
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/scheduler/draw_result.h b/chromium/cc/scheduler/draw_result.h
new file mode 100644
index 00000000000..0809a413e06
--- /dev/null
+++ b/chromium/cc/scheduler/draw_result.h
@@ -0,0 +1,21 @@
+// 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_SCHEDULER_DRAW_RESULT_H_
+#define CC_SCHEDULER_DRAW_RESULT_H_
+
+namespace cc {
+
+enum DrawResult {
+ INVALID_RESULT,
+ DRAW_SUCCESS,
+ DRAW_ABORTED_CHECKERBOARD_ANIMATIONS,
+ DRAW_ABORTED_MISSING_HIGH_RES_CONTENT,
+ DRAW_ABORTED_CONTEXT_LOST,
+ DRAW_ABORTED_CANT_DRAW,
+};
+
+} // namespace cc
+
+#endif // CC_SCHEDULER_DRAW_RESULT_H_
diff --git a/chromium/cc/scheduler/frame_rate_controller.cc b/chromium/cc/scheduler/frame_rate_controller.cc
deleted file mode 100644
index 243ef6b6291..00000000000
--- a/chromium/cc/scheduler/frame_rate_controller.cc
+++ /dev/null
@@ -1,178 +0,0 @@
-// Copyright 2011 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/scheduler/frame_rate_controller.h"
-
-#include "base/bind.h"
-#include "base/debug/trace_event.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/single_thread_task_runner.h"
-#include "cc/scheduler/delay_based_time_source.h"
-#include "cc/scheduler/time_source.h"
-#include "ui/gfx/frame_time.h"
-
-namespace cc {
-
-class FrameRateControllerTimeSourceAdapter : public TimeSourceClient {
- public:
- static scoped_ptr<FrameRateControllerTimeSourceAdapter> Create(
- FrameRateController* frame_rate_controller) {
- return make_scoped_ptr(
- new FrameRateControllerTimeSourceAdapter(frame_rate_controller));
- }
- virtual ~FrameRateControllerTimeSourceAdapter() {}
-
- virtual void OnTimerTick() OVERRIDE {
- frame_rate_controller_->OnTimerTick();
- }
-
- private:
- explicit FrameRateControllerTimeSourceAdapter(
- FrameRateController* frame_rate_controller)
- : frame_rate_controller_(frame_rate_controller) {}
-
- FrameRateController* frame_rate_controller_;
-};
-
-FrameRateController::FrameRateController(scoped_refptr<TimeSource> timer)
- : client_(NULL),
- num_frames_pending_(0),
- max_swaps_pending_(0),
- interval_(BeginFrameArgs::DefaultInterval()),
- time_source_(timer),
- active_(false),
- is_time_source_throttling_(true),
- manual_tick_pending_(false),
- task_runner_(NULL),
- weak_factory_(this) {
- time_source_client_adapter_ =
- FrameRateControllerTimeSourceAdapter::Create(this);
- time_source_->SetClient(time_source_client_adapter_.get());
-}
-
-FrameRateController::FrameRateController(
- base::SingleThreadTaskRunner* task_runner)
- : client_(NULL),
- num_frames_pending_(0),
- max_swaps_pending_(0),
- interval_(BeginFrameArgs::DefaultInterval()),
- active_(false),
- is_time_source_throttling_(false),
- manual_tick_pending_(false),
- task_runner_(task_runner),
- weak_factory_(this) {}
-
-FrameRateController::~FrameRateController() {
- if (is_time_source_throttling_)
- time_source_->SetActive(false);
-}
-
-BeginFrameArgs FrameRateController::SetActive(bool active) {
- if (active_ == active)
- return BeginFrameArgs();
- TRACE_EVENT1("cc", "FrameRateController::SetActive", "active", active);
- active_ = active;
-
- if (is_time_source_throttling_) {
- base::TimeTicks missed_tick_time = time_source_->SetActive(active);
- if (!missed_tick_time.is_null()) {
- base::TimeTicks deadline = NextTickTime();
- return BeginFrameArgs::Create(
- missed_tick_time, deadline + deadline_adjustment_, interval_);
- }
- } else {
- if (active) {
- PostManualTick();
- } else {
- weak_factory_.InvalidateWeakPtrs();
- manual_tick_pending_ = false;
- }
- }
-
- return BeginFrameArgs();
-}
-
-void FrameRateController::SetMaxSwapsPending(int max_swaps_pending) {
- DCHECK_GE(max_swaps_pending, 0);
- max_swaps_pending_ = max_swaps_pending;
-}
-
-void FrameRateController::SetTimebaseAndInterval(base::TimeTicks timebase,
- base::TimeDelta interval) {
- interval_ = interval;
- if (is_time_source_throttling_)
- time_source_->SetTimebaseAndInterval(timebase, interval);
-}
-
-void FrameRateController::SetDeadlineAdjustment(base::TimeDelta delta) {
- deadline_adjustment_ = delta;
-}
-
-void FrameRateController::OnTimerTick() {
- TRACE_EVENT0("cc", "FrameRateController::OnTimerTick");
- DCHECK(active_);
-
- // Check if we have too many frames in flight.
- bool throttled =
- max_swaps_pending_ && num_frames_pending_ >= max_swaps_pending_;
- TRACE_COUNTER_ID1("cc", "ThrottledCompositor", task_runner_, throttled);
-
- if (client_) {
- // TODO(brianderson): Use an adaptive parent compositor deadline.
- base::TimeTicks frame_time = LastTickTime();
- base::TimeTicks deadline = NextTickTime();
- BeginFrameArgs args = BeginFrameArgs::Create(
- frame_time, deadline + deadline_adjustment_, interval_);
- client_->FrameRateControllerTick(throttled, args);
- }
-
- if (!is_time_source_throttling_ && !throttled)
- PostManualTick();
-}
-
-void FrameRateController::PostManualTick() {
- if (active_ && !manual_tick_pending_) {
- manual_tick_pending_ = true;
- task_runner_->PostTask(FROM_HERE,
- base::Bind(&FrameRateController::ManualTick,
- weak_factory_.GetWeakPtr()));
- }
-}
-
-void FrameRateController::ManualTick() {
- manual_tick_pending_ = false;
- OnTimerTick();
-}
-
-void FrameRateController::DidSwapBuffers() {
- num_frames_pending_++;
-}
-
-void FrameRateController::DidSwapBuffersComplete() {
- DCHECK_GT(num_frames_pending_, 0);
- num_frames_pending_--;
- if (!is_time_source_throttling_)
- PostManualTick();
-}
-
-void FrameRateController::DidAbortAllPendingFrames() {
- num_frames_pending_ = 0;
-}
-
-base::TimeTicks FrameRateController::NextTickTime() {
- if (is_time_source_throttling_)
- return time_source_->NextTickTime();
-
- return base::TimeTicks();
-}
-
-base::TimeTicks FrameRateController::LastTickTime() {
- if (is_time_source_throttling_)
- return time_source_->LastTickTime();
-
- return gfx::FrameTime::Now();
-}
-
-} // namespace cc
diff --git a/chromium/cc/scheduler/frame_rate_controller.h b/chromium/cc/scheduler/frame_rate_controller.h
deleted file mode 100644
index 6d86d974966..00000000000
--- a/chromium/cc/scheduler/frame_rate_controller.h
+++ /dev/null
@@ -1,101 +0,0 @@
-// Copyright 2011 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_SCHEDULER_FRAME_RATE_CONTROLLER_H_
-#define CC_SCHEDULER_FRAME_RATE_CONTROLLER_H_
-
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/weak_ptr.h"
-#include "base/time/time.h"
-#include "cc/base/cc_export.h"
-#include "cc/output/begin_frame_args.h"
-
-namespace base { class SingleThreadTaskRunner; }
-
-namespace cc {
-
-class TimeSource;
-class FrameRateController;
-
-class CC_EXPORT FrameRateControllerClient {
- protected:
- virtual ~FrameRateControllerClient() {}
-
- public:
- // Throttled is true when we have a maximum number of frames pending.
- virtual void FrameRateControllerTick(bool throttled,
- const BeginFrameArgs& args) = 0;
-};
-
-class FrameRateControllerTimeSourceAdapter;
-
-// The FrameRateController is used in cases where we self-tick (i.e. BeginFrame
-// is not sent by a parent compositor.
-class CC_EXPORT FrameRateController {
- public:
- explicit FrameRateController(scoped_refptr<TimeSource> timer);
- // Alternate form of FrameRateController with unthrottled frame-rate.
- explicit FrameRateController(base::SingleThreadTaskRunner* task_runner);
- virtual ~FrameRateController();
-
- void SetClient(FrameRateControllerClient* client) { client_ = client; }
-
- // Returns a valid BeginFrame on activation to potentially be used
- // retroactively.
- BeginFrameArgs SetActive(bool active);
-
- bool IsActive() { return active_; }
-
- // Use the following methods to adjust target frame rate.
- //
- // Multiple frames can be in-progress, but for every DidSwapBuffers, a
- // DidFinishFrame should be posted.
- //
- // If the rendering pipeline crashes, call DidAbortAllPendingFrames.
- void DidSwapBuffers();
- void DidSwapBuffersComplete();
- void DidAbortAllPendingFrames();
- void SetMaxSwapsPending(int max_swaps_pending); // 0 for unlimited.
- int MaxSwapsPending() const { return max_swaps_pending_; }
- int NumSwapsPendingForTesting() const { return num_frames_pending_; }
-
- void SetTimebaseAndInterval(base::TimeTicks timebase,
- base::TimeDelta interval);
- void SetDeadlineAdjustment(base::TimeDelta delta);
-
- protected:
- friend class FrameRateControllerTimeSourceAdapter;
- void OnTimerTick();
-
- void PostManualTick();
- void ManualTick();
-
- // This returns null for unthrottled frame-rate.
- base::TimeTicks NextTickTime();
- // This returns now for unthrottled frame-rate.
- base::TimeTicks LastTickTime();
-
- FrameRateControllerClient* client_;
- int num_frames_pending_;
- int max_swaps_pending_;
- base::TimeDelta interval_;
- base::TimeDelta deadline_adjustment_;
- scoped_refptr<TimeSource> time_source_;
- scoped_ptr<FrameRateControllerTimeSourceAdapter> time_source_client_adapter_;
- bool active_;
-
- // Members for unthrottled frame-rate.
- bool is_time_source_throttling_;
- bool manual_tick_pending_;
- base::SingleThreadTaskRunner* task_runner_;
- base::WeakPtrFactory<FrameRateController> weak_factory_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(FrameRateController);
-};
-
-} // namespace cc
-
-#endif // CC_SCHEDULER_FRAME_RATE_CONTROLLER_H_
diff --git a/chromium/cc/scheduler/frame_rate_controller_unittest.cc b/chromium/cc/scheduler/frame_rate_controller_unittest.cc
deleted file mode 100644
index e7d75802eb3..00000000000
--- a/chromium/cc/scheduler/frame_rate_controller_unittest.cc
+++ /dev/null
@@ -1,211 +0,0 @@
-// Copyright 2011 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/scheduler/frame_rate_controller.h"
-
-#include "base/test/test_simple_task_runner.h"
-#include "cc/test/scheduler_test_common.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace cc {
-namespace {
-
-class FakeFrameRateControllerClient : public FrameRateControllerClient {
- public:
- FakeFrameRateControllerClient() { Reset(); }
-
- void Reset() { frame_count_ = 0; }
- bool BeganFrame() const { return frame_count_ > 0; }
- int frame_count() const { return frame_count_; }
-
- virtual void FrameRateControllerTick(
- bool throttled, const BeginFrameArgs& args) OVERRIDE {
- frame_count_ += throttled ? 0 : 1;
- }
-
- protected:
- int frame_count_;
-};
-
-TEST(FrameRateControllerTest, TestFrameThrottling_ImmediateAck) {
- scoped_refptr<base::TestSimpleTaskRunner> task_runner =
- new base::TestSimpleTaskRunner;
- FakeFrameRateControllerClient client;
- base::TimeDelta interval = base::TimeDelta::FromMicroseconds(
- base::Time::kMicrosecondsPerSecond / 60);
- scoped_refptr<FakeDelayBasedTimeSource> time_source =
- FakeDelayBasedTimeSource::Create(interval, task_runner.get());
- FrameRateController controller(time_source);
-
- controller.SetClient(&client);
- controller.SetActive(true);
-
- base::TimeTicks elapsed; // Muck around with time a bit
-
- // Trigger one frame, make sure the BeginFrame callback is called
- elapsed += task_runner->NextPendingTaskDelay();
- time_source->SetNow(elapsed);
- task_runner->RunPendingTasks();
- EXPECT_TRUE(client.BeganFrame());
- client.Reset();
-
- // Tell the controller we drew
- controller.DidSwapBuffers();
-
- // Tell the controller the frame ended 5ms later
- time_source->SetNow(time_source->Now() +
- base::TimeDelta::FromMilliseconds(5));
- controller.DidSwapBuffersComplete();
-
- // Trigger another frame, make sure BeginFrame runs again
- elapsed += task_runner->NextPendingTaskDelay();
- // Sanity check that previous code didn't move time backward.
- EXPECT_GE(elapsed, time_source->Now());
- time_source->SetNow(elapsed);
- task_runner->RunPendingTasks();
- EXPECT_TRUE(client.BeganFrame());
-}
-
-TEST(FrameRateControllerTest, TestFrameThrottling_TwoFramesInFlight) {
- scoped_refptr<base::TestSimpleTaskRunner> task_runner =
- new base::TestSimpleTaskRunner;
- FakeFrameRateControllerClient client;
- base::TimeDelta interval = base::TimeDelta::FromMicroseconds(
- base::Time::kMicrosecondsPerSecond / 60);
- scoped_refptr<FakeDelayBasedTimeSource> time_source =
- FakeDelayBasedTimeSource::Create(interval, task_runner.get());
- FrameRateController controller(time_source);
-
- controller.SetClient(&client);
- controller.SetActive(true);
- controller.SetMaxSwapsPending(2);
-
- base::TimeTicks elapsed; // Muck around with time a bit
-
- // Trigger one frame, make sure the BeginFrame callback is called
- elapsed += task_runner->NextPendingTaskDelay();
- time_source->SetNow(elapsed);
- task_runner->RunPendingTasks();
- EXPECT_TRUE(client.BeganFrame());
- client.Reset();
-
- // Tell the controller we drew
- controller.DidSwapBuffers();
-
- // Trigger another frame, make sure BeginFrame callback runs again
- elapsed += task_runner->NextPendingTaskDelay();
- // Sanity check that previous code didn't move time backward.
- EXPECT_GE(elapsed, time_source->Now());
- time_source->SetNow(elapsed);
- task_runner->RunPendingTasks();
- EXPECT_TRUE(client.BeganFrame());
- client.Reset();
-
- // Tell the controller we drew, again.
- controller.DidSwapBuffers();
-
- // Trigger another frame. Since two frames are pending, we should not draw.
- elapsed += task_runner->NextPendingTaskDelay();
- // Sanity check that previous code didn't move time backward.
- EXPECT_GE(elapsed, time_source->Now());
- time_source->SetNow(elapsed);
- task_runner->RunPendingTasks();
- EXPECT_FALSE(client.BeganFrame());
-
- // Tell the controller the first frame ended 5ms later
- time_source->SetNow(time_source->Now() +
- base::TimeDelta::FromMilliseconds(5));
- controller.DidSwapBuffersComplete();
-
- // Tick should not have been called
- EXPECT_FALSE(client.BeganFrame());
-
- // Trigger yet another frame. Since one frames is pending, another
- // BeginFrame callback should run.
- elapsed += task_runner->NextPendingTaskDelay();
- // Sanity check that previous code didn't move time backward.
- EXPECT_GE(elapsed, time_source->Now());
- time_source->SetNow(elapsed);
- task_runner->RunPendingTasks();
- EXPECT_TRUE(client.BeganFrame());
-}
-
-TEST(FrameRateControllerTest, TestFrameThrottling_Unthrottled) {
- scoped_refptr<base::TestSimpleTaskRunner> task_runner =
- new base::TestSimpleTaskRunner;
- FakeFrameRateControllerClient client;
- FrameRateController controller(task_runner.get());
-
- controller.SetClient(&client);
- controller.SetMaxSwapsPending(2);
-
- // SetActive triggers 1st frame, make sure the BeginFrame callback
- // is called
- controller.SetActive(true);
- task_runner->RunPendingTasks();
- EXPECT_TRUE(client.BeganFrame());
- client.Reset();
-
- // Even if we don't call DidSwapBuffers, FrameRateController should
- // still attempt to tick multiple times until it does result in
- // a DidSwapBuffers.
- task_runner->RunPendingTasks();
- EXPECT_TRUE(client.BeganFrame());
- client.Reset();
-
- task_runner->RunPendingTasks();
- EXPECT_TRUE(client.BeganFrame());
- client.Reset();
-
- // DidSwapBuffers triggers 2nd frame, make sure the BeginFrame callback is
- // called
- controller.DidSwapBuffers();
- task_runner->RunPendingTasks();
- EXPECT_TRUE(client.BeganFrame());
- client.Reset();
-
- // DidSwapBuffers triggers 3rd frame (> max_frames_pending),
- // make sure the BeginFrame callback is NOT called
- controller.DidSwapBuffers();
- task_runner->RunPendingTasks();
- EXPECT_FALSE(client.BeganFrame());
- client.Reset();
-
- // Make sure there is no pending task since we can't do anything until we
- // receive a DidSwapBuffersComplete anyway.
- EXPECT_FALSE(task_runner->HasPendingTask());
-
- // DidSwapBuffersComplete triggers a frame, make sure the BeginFrame
- // callback is called
- controller.DidSwapBuffersComplete();
- task_runner->RunPendingTasks();
- EXPECT_TRUE(client.BeganFrame());
-}
-
-TEST(FrameRateControllerTest, TestFrameThrottling_NoDoubleTicking) {
- scoped_refptr<base::TestSimpleTaskRunner> task_runner =
- new base::TestSimpleTaskRunner;
- FakeFrameRateControllerClient client;
- FrameRateController controller(task_runner.get());
- controller.SetClient(&client);
-
- // SetActive triggers 1st frame and queues another tick task since the time
- // source isn't throttling.
- controller.SetActive(true);
- task_runner->RunPendingTasks();
- EXPECT_TRUE(client.BeganFrame());
- client.Reset();
- EXPECT_TRUE(task_runner->HasPendingTask());
-
- // Simulate a frame swap. This shouldn't queue a second tick task.
- controller.DidSwapBuffers();
- controller.DidSwapBuffersComplete();
-
- // The client should only be ticked once.
- task_runner->RunPendingTasks();
- EXPECT_EQ(1, client.frame_count());
-}
-
-} // namespace
-} // namespace cc
diff --git a/chromium/cc/scheduler/scheduler.cc b/chromium/cc/scheduler/scheduler.cc
index d31f042e761..4a682cdb441 100644
--- a/chromium/cc/scheduler/scheduler.cc
+++ b/chromium/cc/scheduler/scheduler.cc
@@ -8,28 +8,141 @@
#include "base/auto_reset.h"
#include "base/debug/trace_event.h"
#include "base/logging.h"
+#include "base/single_thread_task_runner.h"
#include "cc/debug/devtools_instrumentation.h"
#include "cc/debug/traced_value.h"
+#include "cc/scheduler/delay_based_time_source.h"
#include "ui/gfx/frame_time.h"
namespace cc {
-Scheduler::Scheduler(SchedulerClient* client,
- const SchedulerSettings& scheduler_settings,
- int layer_tree_host_id)
+Scheduler::SyntheticBeginFrameSource::SyntheticBeginFrameSource(
+ Scheduler* scheduler,
+ base::SingleThreadTaskRunner* task_runner)
+ : scheduler_(scheduler) {
+ if (gfx::FrameTime::TimestampsAreHighRes()) {
+ time_source_ = DelayBasedTimeSourceHighRes::Create(
+ scheduler_->VSyncInterval(), task_runner);
+ } else {
+ time_source_ = DelayBasedTimeSource::Create(scheduler_->VSyncInterval(),
+ task_runner);
+ }
+ time_source_->SetClient(this);
+}
+
+Scheduler::SyntheticBeginFrameSource::~SyntheticBeginFrameSource() {
+}
+
+void Scheduler::SyntheticBeginFrameSource::CommitVSyncParameters(
+ base::TimeTicks timebase,
+ base::TimeDelta interval) {
+ time_source_->SetTimebaseAndInterval(timebase, interval);
+}
+
+void Scheduler::SyntheticBeginFrameSource::SetNeedsBeginFrame(
+ bool needs_begin_frame,
+ std::deque<BeginFrameArgs>* begin_retro_frame_args) {
+ DCHECK(begin_retro_frame_args);
+ base::TimeTicks missed_tick_time =
+ time_source_->SetActive(needs_begin_frame);
+ if (!missed_tick_time.is_null()) {
+ begin_retro_frame_args->push_back(
+ CreateSyntheticBeginFrameArgs(missed_tick_time));
+ }
+}
+
+bool Scheduler::SyntheticBeginFrameSource::IsActive() const {
+ return time_source_->Active();
+}
+
+void Scheduler::SyntheticBeginFrameSource::OnTimerTick() {
+ BeginFrameArgs begin_frame_args(
+ CreateSyntheticBeginFrameArgs(time_source_->LastTickTime()));
+ scheduler_->BeginFrame(begin_frame_args);
+}
+
+scoped_ptr<base::Value> Scheduler::SyntheticBeginFrameSource::AsValue() const {
+ return time_source_->AsValue();
+}
+
+BeginFrameArgs
+Scheduler::SyntheticBeginFrameSource::CreateSyntheticBeginFrameArgs(
+ base::TimeTicks frame_time) {
+ base::TimeTicks deadline = time_source_->NextTickTime();
+ return BeginFrameArgs::Create(
+ frame_time, deadline, scheduler_->VSyncInterval());
+}
+
+Scheduler::Scheduler(
+ SchedulerClient* client,
+ const SchedulerSettings& scheduler_settings,
+ int layer_tree_host_id,
+ const scoped_refptr<base::SingleThreadTaskRunner>& impl_task_runner)
: settings_(scheduler_settings),
client_(client),
layer_tree_host_id_(layer_tree_host_id),
- last_set_needs_begin_impl_frame_(false),
+ impl_task_runner_(impl_task_runner),
+ vsync_interval_(BeginFrameArgs::DefaultInterval()),
+ last_set_needs_begin_frame_(false),
+ begin_unthrottled_frame_posted_(false),
+ begin_retro_frame_posted_(false),
state_machine_(scheduler_settings),
inside_process_scheduled_actions_(false),
inside_action_(SchedulerStateMachine::ACTION_NONE),
weak_factory_(this) {
+ TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"),
+ "Scheduler::Scheduler",
+ "settings",
+ ToTrace(settings_));
DCHECK(client_);
- DCHECK(!state_machine_.BeginImplFrameNeeded());
+ DCHECK(!state_machine_.BeginFrameNeeded());
+ if (settings_.main_frame_before_activation_enabled) {
+ DCHECK(settings_.main_frame_before_draw_enabled);
+ }
+
+ begin_retro_frame_closure_ =
+ base::Bind(&Scheduler::BeginRetroFrame, weak_factory_.GetWeakPtr());
+ begin_unthrottled_frame_closure_ =
+ base::Bind(&Scheduler::BeginUnthrottledFrame, weak_factory_.GetWeakPtr());
+ begin_impl_frame_deadline_closure_ = base::Bind(
+ &Scheduler::OnBeginImplFrameDeadline, weak_factory_.GetWeakPtr());
+ poll_for_draw_triggers_closure_ = base::Bind(
+ &Scheduler::PollForAnticipatedDrawTriggers, weak_factory_.GetWeakPtr());
+ advance_commit_state_closure_ = base::Bind(
+ &Scheduler::PollToAdvanceCommitState, weak_factory_.GetWeakPtr());
+
+ if (!settings_.begin_frame_scheduling_enabled) {
+ SetupSyntheticBeginFrames();
+ }
+}
+
+Scheduler::~Scheduler() {
+ if (synthetic_begin_frame_source_) {
+ synthetic_begin_frame_source_->SetNeedsBeginFrame(false,
+ &begin_retro_frame_args_);
+ }
+}
+
+void Scheduler::SetupSyntheticBeginFrames() {
+ DCHECK(!synthetic_begin_frame_source_);
+ synthetic_begin_frame_source_.reset(
+ new SyntheticBeginFrameSource(this, impl_task_runner_.get()));
}
-Scheduler::~Scheduler() {}
+void Scheduler::CommitVSyncParameters(base::TimeTicks timebase,
+ base::TimeDelta interval) {
+ // TODO(brianderson): We should not be receiving 0 intervals.
+ if (interval == base::TimeDelta())
+ interval = BeginFrameArgs::DefaultInterval();
+ vsync_interval_ = interval;
+ if (!settings_.begin_frame_scheduling_enabled)
+ synthetic_begin_frame_source_->CommitVSyncParameters(timebase, interval);
+}
+
+void Scheduler::SetEstimatedParentDrawTime(base::TimeDelta draw_time) {
+ DCHECK_GE(draw_time.ToInternalValue(), 0);
+ estimated_parent_draw_time_ = draw_time;
+}
void Scheduler::SetCanStart() {
state_machine_.SetCanStart();
@@ -51,23 +164,18 @@ void Scheduler::NotifyReadyToActivate() {
ProcessScheduledActions();
}
-void Scheduler::ActivatePendingTree() {
- client_->ScheduledActionActivatePendingTree();
-}
-
void Scheduler::SetNeedsCommit() {
state_machine_.SetNeedsCommit();
ProcessScheduledActions();
}
-void Scheduler::SetNeedsForcedCommitForReadback() {
- state_machine_.SetNeedsCommit();
- state_machine_.SetNeedsForcedCommitForReadback();
+void Scheduler::SetNeedsRedraw() {
+ state_machine_.SetNeedsRedraw();
ProcessScheduledActions();
}
-void Scheduler::SetNeedsRedraw() {
- state_machine_.SetNeedsRedraw();
+void Scheduler::SetNeedsAnimate() {
+ state_machine_.SetNeedsAnimate();
ProcessScheduledActions();
}
@@ -77,24 +185,38 @@ void Scheduler::SetNeedsManageTiles() {
ProcessScheduledActions();
}
+void Scheduler::SetMaxSwapsPending(int max) {
+ state_machine_.SetMaxSwapsPending(max);
+}
+
+void Scheduler::DidSwapBuffers() {
+ state_machine_.DidSwapBuffers();
+
+ // There is no need to call ProcessScheduledActions here because
+ // swapping should not trigger any new actions.
+ if (!inside_process_scheduled_actions_) {
+ DCHECK_EQ(state_machine_.NextAction(), SchedulerStateMachine::ACTION_NONE);
+ }
+}
+
void Scheduler::SetSwapUsedIncompleteTile(bool used_incomplete_tile) {
state_machine_.SetSwapUsedIncompleteTile(used_incomplete_tile);
ProcessScheduledActions();
}
-void Scheduler::SetSmoothnessTakesPriority(bool smoothness_takes_priority) {
- state_machine_.SetSmoothnessTakesPriority(smoothness_takes_priority);
+void Scheduler::DidSwapBuffersComplete() {
+ state_machine_.DidSwapBuffersComplete();
ProcessScheduledActions();
}
-void Scheduler::SetMainThreadNeedsLayerTextures() {
- state_machine_.SetMainThreadNeedsLayerTextures();
+void Scheduler::SetSmoothnessTakesPriority(bool smoothness_takes_priority) {
+ state_machine_.SetSmoothnessTakesPriority(smoothness_takes_priority);
ProcessScheduledActions();
}
-void Scheduler::FinishCommit() {
- TRACE_EVENT0("cc", "Scheduler::FinishCommit");
- state_machine_.FinishCommit();
+void Scheduler::NotifyReadyToCommit() {
+ TRACE_EVENT0("cc", "Scheduler::NotifyReadyToCommit");
+ state_machine_.NotifyReadyToCommit();
ProcessScheduledActions();
}
@@ -110,144 +232,311 @@ void Scheduler::DidManageTiles() {
void Scheduler::DidLoseOutputSurface() {
TRACE_EVENT0("cc", "Scheduler::DidLoseOutputSurface");
- last_set_needs_begin_impl_frame_ = false;
- begin_impl_frame_deadline_closure_.Cancel();
state_machine_.DidLoseOutputSurface();
+ last_set_needs_begin_frame_ = false;
+ if (!settings_.begin_frame_scheduling_enabled) {
+ synthetic_begin_frame_source_->SetNeedsBeginFrame(false,
+ &begin_retro_frame_args_);
+ }
+ begin_retro_frame_args_.clear();
ProcessScheduledActions();
}
void Scheduler::DidCreateAndInitializeOutputSurface() {
TRACE_EVENT0("cc", "Scheduler::DidCreateAndInitializeOutputSurface");
- DCHECK(!last_set_needs_begin_impl_frame_);
- DCHECK(begin_impl_frame_deadline_closure_.IsCancelled());
+ DCHECK(!last_set_needs_begin_frame_);
+ DCHECK(begin_impl_frame_deadline_task_.IsCancelled());
state_machine_.DidCreateAndInitializeOutputSurface();
ProcessScheduledActions();
}
-base::TimeTicks Scheduler::AnticipatedDrawTime() {
- TRACE_EVENT0("cc", "Scheduler::AnticipatedDrawTime");
+void Scheduler::NotifyBeginMainFrameStarted() {
+ TRACE_EVENT0("cc", "Scheduler::NotifyBeginMainFrameStarted");
+ state_machine_.NotifyBeginMainFrameStarted();
+}
- if (!last_set_needs_begin_impl_frame_ ||
- last_begin_impl_frame_args_.interval <= base::TimeDelta())
+base::TimeTicks Scheduler::AnticipatedDrawTime() const {
+ if (!last_set_needs_begin_frame_ ||
+ begin_impl_frame_args_.interval <= base::TimeDelta())
return base::TimeTicks();
base::TimeTicks now = gfx::FrameTime::Now();
- base::TimeTicks timebase = std::max(last_begin_impl_frame_args_.frame_time,
- last_begin_impl_frame_args_.deadline);
- int64 intervals =
- 1 + ((now - timebase) / last_begin_impl_frame_args_.interval);
- return timebase + (last_begin_impl_frame_args_.interval * intervals);
+ base::TimeTicks timebase = std::max(begin_impl_frame_args_.frame_time,
+ begin_impl_frame_args_.deadline);
+ int64 intervals = 1 + ((now - timebase) / begin_impl_frame_args_.interval);
+ return timebase + (begin_impl_frame_args_.interval * intervals);
}
base::TimeTicks Scheduler::LastBeginImplFrameTime() {
- return last_begin_impl_frame_args_.frame_time;
+ return begin_impl_frame_args_.frame_time;
}
-void Scheduler::SetupNextBeginImplFrameIfNeeded() {
- bool needs_begin_impl_frame =
- state_machine_.BeginImplFrameNeeded();
+void Scheduler::SetupNextBeginFrameIfNeeded() {
+ bool needs_begin_frame = state_machine_.BeginFrameNeeded();
+ if (settings_.throttle_frame_production) {
+ SetupNextBeginFrameWhenVSyncThrottlingEnabled(needs_begin_frame);
+ } else {
+ SetupNextBeginFrameWhenVSyncThrottlingDisabled(needs_begin_frame);
+ }
+ SetupPollingMechanisms(needs_begin_frame);
+}
+
+// When we are throttling frame production, we request BeginFrames
+// from the OutputSurface.
+void Scheduler::SetupNextBeginFrameWhenVSyncThrottlingEnabled(
+ bool needs_begin_frame) {
bool at_end_of_deadline =
state_machine_.begin_impl_frame_state() ==
SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE;
- bool should_call_set_needs_begin_impl_frame =
- // Always request the BeginImplFrame immediately if it wasn't needed
- // before.
- (needs_begin_impl_frame && !last_set_needs_begin_impl_frame_) ||
- // We always need to explicitly request our next BeginImplFrame.
- at_end_of_deadline;
+ bool should_call_set_needs_begin_frame =
+ // Always request the BeginFrame immediately if it wasn't needed before.
+ (needs_begin_frame && !last_set_needs_begin_frame_) ||
+ // Only stop requesting BeginFrames after a deadline.
+ (!needs_begin_frame && last_set_needs_begin_frame_ && at_end_of_deadline);
+
+ if (should_call_set_needs_begin_frame) {
+ if (settings_.begin_frame_scheduling_enabled) {
+ client_->SetNeedsBeginFrame(needs_begin_frame);
+ } else {
+ synthetic_begin_frame_source_->SetNeedsBeginFrame(
+ needs_begin_frame, &begin_retro_frame_args_);
+ }
+ last_set_needs_begin_frame_ = needs_begin_frame;
+ }
+
+ PostBeginRetroFrameIfNeeded();
+}
- if (should_call_set_needs_begin_impl_frame) {
- client_->SetNeedsBeginImplFrame(needs_begin_impl_frame);
- last_set_needs_begin_impl_frame_ = needs_begin_impl_frame;
+// When we aren't throttling frame production, we initiate a BeginFrame
+// as soon as one is needed.
+void Scheduler::SetupNextBeginFrameWhenVSyncThrottlingDisabled(
+ bool needs_begin_frame) {
+ last_set_needs_begin_frame_ = needs_begin_frame;
+
+ if (!needs_begin_frame || begin_unthrottled_frame_posted_)
+ return;
+
+ if (state_machine_.begin_impl_frame_state() !=
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE &&
+ state_machine_.begin_impl_frame_state() !=
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE) {
+ return;
}
+ begin_unthrottled_frame_posted_ = true;
+ impl_task_runner_->PostTask(FROM_HERE, begin_unthrottled_frame_closure_);
+}
+
+// BeginUnthrottledFrame is used when we aren't throttling frame production.
+// This will usually be because VSync is disabled.
+void Scheduler::BeginUnthrottledFrame() {
+ DCHECK(!settings_.throttle_frame_production);
+ DCHECK(begin_retro_frame_args_.empty());
+
+ base::TimeTicks now = gfx::FrameTime::Now();
+ base::TimeTicks deadline = now + vsync_interval_;
+
+ BeginFrameArgs begin_frame_args =
+ BeginFrameArgs::Create(now, deadline, vsync_interval_);
+ BeginImplFrame(begin_frame_args);
+
+ begin_unthrottled_frame_posted_ = false;
+}
+
+// We may need to poll when we can't rely on BeginFrame to advance certain
+// state or to avoid deadlock.
+void Scheduler::SetupPollingMechanisms(bool needs_begin_frame) {
bool needs_advance_commit_state_timer = false;
// Setup PollForAnticipatedDrawTriggers if we need to monitor state but
- // aren't expecting any more BeginImplFrames. This should only be needed by
- // the synchronous compositor when BeginImplFrameNeeded is false.
+ // aren't expecting any more BeginFrames. This should only be needed by
+ // the synchronous compositor when BeginFrameNeeded is false.
if (state_machine_.ShouldPollForAnticipatedDrawTriggers()) {
- DCHECK(!state_machine_.SupportsProactiveBeginImplFrame());
- DCHECK(!needs_begin_impl_frame);
- if (poll_for_draw_triggers_closure_.IsCancelled()) {
- poll_for_draw_triggers_closure_.Reset(
- base::Bind(&Scheduler::PollForAnticipatedDrawTriggers,
- weak_factory_.GetWeakPtr()));
- base::MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- poll_for_draw_triggers_closure_.callback(),
- last_begin_impl_frame_args_.interval);
+ DCHECK(!state_machine_.SupportsProactiveBeginFrame());
+ DCHECK(!needs_begin_frame);
+ if (poll_for_draw_triggers_task_.IsCancelled()) {
+ poll_for_draw_triggers_task_.Reset(poll_for_draw_triggers_closure_);
+ base::TimeDelta delay = begin_impl_frame_args_.IsValid()
+ ? begin_impl_frame_args_.interval
+ : BeginFrameArgs::DefaultInterval();
+ impl_task_runner_->PostDelayedTask(
+ FROM_HERE, poll_for_draw_triggers_task_.callback(), delay);
}
} else {
- poll_for_draw_triggers_closure_.Cancel();
+ poll_for_draw_triggers_task_.Cancel();
// At this point we'd prefer to advance through the commit flow by
// drawing a frame, however it's possible that the frame rate controller
- // will not give us a BeginImplFrame until the commit completes. See
+ // will not give us a BeginFrame until the commit completes. See
// crbug.com/317430 for an example of a swap ack being held on commit. Thus
// we set a repeating timer to poll on ProcessScheduledActions until we
- // successfully reach BeginImplFrame.
- if (state_machine_.IsCommitStateWaiting())
+ // successfully reach BeginFrame. Synchronous compositor does not use
+ // frame rate controller or have the circular wait in the bug.
+ if (IsBeginMainFrameSentOrStarted() &&
+ !settings_.using_synchronous_renderer_compositor) {
needs_advance_commit_state_timer = true;
+ }
}
- if (needs_advance_commit_state_timer !=
- advance_commit_state_timer_.IsRunning()) {
- if (needs_advance_commit_state_timer &&
- last_begin_impl_frame_args_.IsValid()) {
- // Since we'd rather get a BeginImplFrame by the normally mechanism, we set
- // the interval to twice the interval from the previous frame.
- advance_commit_state_timer_.Start(
- FROM_HERE,
- last_begin_impl_frame_args_.interval * 2,
- base::Bind(&Scheduler::ProcessScheduledActions,
- base::Unretained(this)));
- } else {
- advance_commit_state_timer_.Stop();
+
+ if (needs_advance_commit_state_timer) {
+ if (advance_commit_state_task_.IsCancelled() &&
+ begin_impl_frame_args_.IsValid()) {
+ // Since we'd rather get a BeginImplFrame by the normal mechanism, we
+ // set the interval to twice the interval from the previous frame.
+ advance_commit_state_task_.Reset(advance_commit_state_closure_);
+ impl_task_runner_->PostDelayedTask(FROM_HERE,
+ advance_commit_state_task_.callback(),
+ begin_impl_frame_args_.interval * 2);
}
+ } else {
+ advance_commit_state_task_.Cancel();
+ }
+}
+
+// BeginFrame is the mechanism that tells us that now is a good time to start
+// making a frame. Usually this means that user input for the frame is complete.
+// If the scheduler is busy, we queue the BeginFrame to be handled later as
+// a BeginRetroFrame.
+void Scheduler::BeginFrame(const BeginFrameArgs& args) {
+ TRACE_EVENT1("cc", "Scheduler::BeginFrame", "args", ToTrace(args));
+ DCHECK(settings_.throttle_frame_production);
+
+ BeginFrameArgs adjusted_args(args);
+ adjusted_args.deadline -= EstimatedParentDrawTime();
+
+ bool should_defer_begin_frame;
+ if (settings_.using_synchronous_renderer_compositor) {
+ should_defer_begin_frame = false;
+ } else {
+ should_defer_begin_frame =
+ !begin_retro_frame_args_.empty() || begin_retro_frame_posted_ ||
+ !last_set_needs_begin_frame_ ||
+ (state_machine_.begin_impl_frame_state() !=
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
+ }
+
+ if (should_defer_begin_frame) {
+ begin_retro_frame_args_.push_back(adjusted_args);
+ TRACE_EVENT_INSTANT0(
+ "cc", "Scheduler::BeginFrame deferred", TRACE_EVENT_SCOPE_THREAD);
+ return;
+ }
+
+ BeginImplFrame(adjusted_args);
+}
+
+// BeginRetroFrame is called for BeginFrames that we've deferred because
+// the scheduler was in the middle of processing a previous BeginFrame.
+void Scheduler::BeginRetroFrame() {
+ TRACE_EVENT0("cc", "Scheduler::BeginRetroFrame");
+ DCHECK(!settings_.using_synchronous_renderer_compositor);
+ DCHECK(begin_retro_frame_posted_);
+ begin_retro_frame_posted_ = false;
+
+ // If there aren't any retroactive BeginFrames, then we've lost the
+ // OutputSurface and should abort.
+ if (begin_retro_frame_args_.empty())
+ return;
+
+ // Discard expired BeginRetroFrames
+ // Today, we should always end up with at most one un-expired BeginRetroFrame
+ // because deadlines will not be greater than the next frame time. We don't
+ // DCHECK though because some systems don't always have monotonic timestamps.
+ // TODO(brianderson): In the future, long deadlines could result in us not
+ // draining the queue if we don't catch up. If we consistently can't catch
+ // up, our fallback should be to lower our frame rate.
+ base::TimeTicks now = gfx::FrameTime::Now();
+ base::TimeDelta draw_duration_estimate = client_->DrawDurationEstimate();
+ while (!begin_retro_frame_args_.empty() &&
+ now > AdjustedBeginImplFrameDeadline(begin_retro_frame_args_.front(),
+ draw_duration_estimate)) {
+ TRACE_EVENT1("cc",
+ "Scheduler::BeginRetroFrame discarding",
+ "frame_time",
+ begin_retro_frame_args_.front().frame_time);
+ begin_retro_frame_args_.pop_front();
}
+
+ if (begin_retro_frame_args_.empty()) {
+ DCHECK(settings_.throttle_frame_production);
+ TRACE_EVENT_INSTANT0("cc",
+ "Scheduler::BeginRetroFrames all expired",
+ TRACE_EVENT_SCOPE_THREAD);
+ } else {
+ BeginImplFrame(begin_retro_frame_args_.front());
+ begin_retro_frame_args_.pop_front();
+ }
+}
+
+// There could be a race between the posted BeginRetroFrame and a new
+// BeginFrame arriving via the normal mechanism. Scheduler::BeginFrame
+// will check if there is a pending BeginRetroFrame to ensure we handle
+// BeginFrames in FIFO order.
+void Scheduler::PostBeginRetroFrameIfNeeded() {
+ if (!last_set_needs_begin_frame_)
+ return;
+
+ if (begin_retro_frame_args_.empty() || begin_retro_frame_posted_)
+ return;
+
+ // begin_retro_frame_args_ should always be empty for the
+ // synchronous compositor.
+ DCHECK(!settings_.using_synchronous_renderer_compositor);
+
+ if (state_machine_.begin_impl_frame_state() !=
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE)
+ return;
+
+ begin_retro_frame_posted_ = true;
+ impl_task_runner_->PostTask(FROM_HERE, begin_retro_frame_closure_);
}
+// BeginImplFrame starts a compositor frame that will wait up until a deadline
+// for a BeginMainFrame+activation to complete before it times out and draws
+// any asynchronous animation and scroll/pinch updates.
void Scheduler::BeginImplFrame(const BeginFrameArgs& args) {
- TRACE_EVENT0("cc", "Scheduler::BeginImplFrame");
+ TRACE_EVENT1("cc", "Scheduler::BeginImplFrame", "args", ToTrace(args));
DCHECK(state_machine_.begin_impl_frame_state() ==
SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
DCHECK(state_machine_.HasInitializedOutputSurface());
- last_begin_impl_frame_args_ = args;
- last_begin_impl_frame_args_.deadline -= client_->DrawDurationEstimate();
- state_machine_.OnBeginImplFrame(last_begin_impl_frame_args_);
-
- if (settings_.switch_to_low_latency_if_possible) {
- state_machine_.SetSkipBeginMainFrameToReduceLatency(
- state_machine_.MainThreadIsInHighLatencyMode() &&
- CanCommitAndActivateBeforeDeadline());
+
+ advance_commit_state_task_.Cancel();
+
+ base::TimeDelta draw_duration_estimate = client_->DrawDurationEstimate();
+ begin_impl_frame_args_ = args;
+ begin_impl_frame_args_.deadline -= draw_duration_estimate;
+
+ if (!state_machine_.smoothness_takes_priority() &&
+ state_machine_.MainThreadIsInHighLatencyMode() &&
+ CanCommitAndActivateBeforeDeadline()) {
+ state_machine_.SetSkipNextBeginMainFrameToReduceLatency();
}
- ProcessScheduledActions();
+ client_->WillBeginImplFrame(begin_impl_frame_args_);
+ state_machine_.OnBeginImplFrame(begin_impl_frame_args_);
+ devtools_instrumentation::DidBeginFrame(layer_tree_host_id_);
- if (!state_machine_.HasInitializedOutputSurface())
- return;
+ ProcessScheduledActions();
state_machine_.OnBeginImplFrameDeadlinePending();
- devtools_instrumentation::didBeginFrame(layer_tree_host_id_);
+ ScheduleBeginImplFrameDeadline(
+ AdjustedBeginImplFrameDeadline(args, draw_duration_estimate));
+}
+
+base::TimeTicks Scheduler::AdjustedBeginImplFrameDeadline(
+ const BeginFrameArgs& args,
+ base::TimeDelta draw_duration_estimate) const {
if (settings_.using_synchronous_renderer_compositor) {
- // The synchronous renderer compositor has to make its GL calls
- // within this call to BeginImplFrame.
- // TODO(brianderson): Have the OutputSurface initiate the deadline tasks
- // so the sychronous renderer compositor can take advantage of splitting
- // up the BeginImplFrame and deadline as well.
- OnBeginImplFrameDeadline();
- } else if (!settings_.deadline_scheduling_enabled) {
- // We emulate the old non-deadline scheduler here by posting the
- // deadline task without any delay.
- PostBeginImplFrameDeadline(base::TimeTicks());
+ // The synchronous compositor needs to draw right away.
+ return base::TimeTicks();
} else if (state_machine_.ShouldTriggerBeginImplFrameDeadlineEarly()) {
// We are ready to draw a new active tree immediately.
- PostBeginImplFrameDeadline(base::TimeTicks());
+ return base::TimeTicks();
} else if (state_machine_.needs_redraw()) {
// We have an animation or fast input path on the impl thread that wants
// to draw, so don't wait too long for a new active tree.
- PostBeginImplFrameDeadline(last_begin_impl_frame_args_.deadline);
+ return args.deadline - draw_duration_estimate;
} else {
// The impl thread doesn't have anything it wants to draw and we are just
// waiting for a new active tree, so post the deadline for the next
@@ -256,60 +545,71 @@ void Scheduler::BeginImplFrame(const BeginFrameArgs& args) {
// BeginImplFrame.
// TODO(brianderson): Handle long deadlines (that are past the next frame's
// frame time) properly instead of using this hack.
- PostBeginImplFrameDeadline(last_begin_impl_frame_args_.frame_time +
- last_begin_impl_frame_args_.interval);
+ return args.frame_time + args.interval;
}
}
-void Scheduler::PostBeginImplFrameDeadline(base::TimeTicks deadline) {
- begin_impl_frame_deadline_closure_.Cancel();
- begin_impl_frame_deadline_closure_.Reset(
- base::Bind(&Scheduler::OnBeginImplFrameDeadline,
- weak_factory_.GetWeakPtr()));
- client_->PostBeginImplFrameDeadline(
- begin_impl_frame_deadline_closure_.callback(), deadline);
+void Scheduler::ScheduleBeginImplFrameDeadline(base::TimeTicks deadline) {
+ if (settings_.using_synchronous_renderer_compositor) {
+ // The synchronous renderer compositor has to make its GL calls
+ // within this call.
+ // TODO(brianderson): Have the OutputSurface initiate the deadline tasks
+ // so the sychronous renderer compositor can take advantage of splitting
+ // up the BeginImplFrame and deadline as well.
+ OnBeginImplFrameDeadline();
+ return;
+ }
+ begin_impl_frame_deadline_task_.Cancel();
+ begin_impl_frame_deadline_task_.Reset(begin_impl_frame_deadline_closure_);
+
+ base::TimeDelta delta = deadline - gfx::FrameTime::Now();
+ if (delta <= base::TimeDelta())
+ delta = base::TimeDelta();
+ impl_task_runner_->PostDelayedTask(
+ FROM_HERE, begin_impl_frame_deadline_task_.callback(), delta);
}
void Scheduler::OnBeginImplFrameDeadline() {
TRACE_EVENT0("cc", "Scheduler::OnBeginImplFrameDeadline");
- DCHECK(state_machine_.HasInitializedOutputSurface());
- begin_impl_frame_deadline_closure_.Cancel();
+ begin_impl_frame_deadline_task_.Cancel();
+
+ // We split the deadline actions up into two phases so the state machine
+ // has a chance to trigger actions that should occur durring and after
+ // the deadline separately. For example:
+ // * Sending the BeginMainFrame will not occur after the deadline in
+ // order to wait for more user-input before starting the next commit.
+ // * Creating a new OuputSurface will not occur during the deadline in
+ // order to allow the state machine to "settle" first.
state_machine_.OnBeginImplFrameDeadline();
ProcessScheduledActions();
-
- if (state_machine_.HasInitializedOutputSurface()) {
- // We only transition out of BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE when all
- // actions that occur back-to-back in response to entering
- // BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE have completed. This is important
- // because sending the BeginMainFrame will not occur if we transition to
- // BEGIN_IMPL_FRAME_STATE_IDLE too early.
- state_machine_.OnBeginImplFrameIdle();
- }
+ state_machine_.OnBeginImplFrameIdle();
+ ProcessScheduledActions();
client_->DidBeginImplFrameDeadline();
}
void Scheduler::PollForAnticipatedDrawTriggers() {
TRACE_EVENT0("cc", "Scheduler::PollForAnticipatedDrawTriggers");
- poll_for_draw_triggers_closure_.Cancel();
+ poll_for_draw_triggers_task_.Cancel();
state_machine_.DidEnterPollForAnticipatedDrawTriggers();
ProcessScheduledActions();
state_machine_.DidLeavePollForAnticipatedDrawTriggers();
}
-void Scheduler::DrawAndSwapIfPossible() {
- DrawSwapReadbackResult result =
- client_->ScheduledActionDrawAndSwapIfPossible();
- state_machine_.DidDrawIfPossibleCompleted(result.did_draw);
+void Scheduler::PollToAdvanceCommitState() {
+ TRACE_EVENT0("cc", "Scheduler::PollToAdvanceCommitState");
+ advance_commit_state_task_.Cancel();
+ ProcessScheduledActions();
}
-void Scheduler::DrawAndSwapForced() {
- client_->ScheduledActionDrawAndSwapForced();
+bool Scheduler::IsBeginMainFrameSent() const {
+ return state_machine_.commit_state() ==
+ SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT;
}
-void Scheduler::DrawAndReadback() {
- DrawSwapReadbackResult result = client_->ScheduledActionDrawAndReadback();
- DCHECK(!result.did_swap);
+void Scheduler::DrawAndSwapIfPossible() {
+ DrawResult result = client_->ScheduledActionDrawAndSwapIfPossible();
+ state_machine_.DidDrawIfPossibleCompleted(result);
}
void Scheduler::ProcessScheduledActions() {
@@ -322,18 +622,20 @@ void Scheduler::ProcessScheduledActions() {
SchedulerStateMachine::Action action;
do {
- state_machine_.CheckInvariants();
action = state_machine_.NextAction();
TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"),
"SchedulerStateMachine",
"state",
- TracedValue::FromValue(state_machine_.AsValue().release()));
+ ToTrace(this));
state_machine_.UpdateState(action);
base::AutoReset<SchedulerStateMachine::Action>
mark_inside_action(&inside_action_, action);
switch (action) {
case SchedulerStateMachine::ACTION_NONE:
break;
+ case SchedulerStateMachine::ACTION_ANIMATE:
+ client_->ScheduledActionAnimate();
+ break;
case SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME:
client_->ScheduledActionSendBeginMainFrame();
break;
@@ -344,53 +646,111 @@ void Scheduler::ProcessScheduledActions() {
client_->ScheduledActionUpdateVisibleTiles();
break;
case SchedulerStateMachine::ACTION_ACTIVATE_PENDING_TREE:
- ActivatePendingTree();
+ client_->ScheduledActionActivatePendingTree();
break;
case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE:
DrawAndSwapIfPossible();
break;
case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED:
- DrawAndSwapForced();
+ client_->ScheduledActionDrawAndSwapForced();
break;
case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT:
// No action is actually performed, but this allows the state machine to
// advance out of its waiting to draw state without actually drawing.
break;
- case SchedulerStateMachine::ACTION_DRAW_AND_READBACK:
- DrawAndReadback();
- break;
case SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION:
client_->ScheduledActionBeginOutputSurfaceCreation();
break;
- case SchedulerStateMachine::ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD:
- client_->ScheduledActionAcquireLayerTexturesForMainThread();
- break;
case SchedulerStateMachine::ACTION_MANAGE_TILES:
client_->ScheduledActionManageTiles();
break;
}
} while (action != SchedulerStateMachine::ACTION_NONE);
- SetupNextBeginImplFrameIfNeeded();
+ SetupNextBeginFrameIfNeeded();
client_->DidAnticipatedDrawTimeChange(AnticipatedDrawTime());
- if (state_machine_.ShouldTriggerBeginImplFrameDeadlineEarly())
- PostBeginImplFrameDeadline(base::TimeTicks());
+ if (state_machine_.ShouldTriggerBeginImplFrameDeadlineEarly()) {
+ DCHECK(!settings_.using_synchronous_renderer_compositor);
+ ScheduleBeginImplFrameDeadline(base::TimeTicks());
+ }
}
bool Scheduler::WillDrawIfNeeded() const {
return !state_machine_.PendingDrawsShouldBeAborted();
}
+scoped_ptr<base::Value> Scheduler::AsValue() const {
+ scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue);
+ state->Set("state_machine", state_machine_.AsValue().release());
+ if (synthetic_begin_frame_source_)
+ state->Set("synthetic_begin_frame_source_",
+ synthetic_begin_frame_source_->AsValue().release());
+
+ scoped_ptr<base::DictionaryValue> scheduler_state(new base::DictionaryValue);
+ scheduler_state->SetDouble(
+ "time_until_anticipated_draw_time_ms",
+ (AnticipatedDrawTime() - base::TimeTicks::Now()).InMillisecondsF());
+ scheduler_state->SetDouble("vsync_interval_ms",
+ vsync_interval_.InMillisecondsF());
+ scheduler_state->SetDouble("estimated_parent_draw_time_ms",
+ estimated_parent_draw_time_.InMillisecondsF());
+ scheduler_state->SetBoolean("last_set_needs_begin_frame_",
+ last_set_needs_begin_frame_);
+ scheduler_state->SetBoolean("begin_unthrottled_frame_posted_",
+ begin_unthrottled_frame_posted_);
+ scheduler_state->SetBoolean("begin_retro_frame_posted_",
+ begin_retro_frame_posted_);
+ scheduler_state->SetInteger("begin_retro_frame_args_",
+ begin_retro_frame_args_.size());
+ scheduler_state->SetBoolean("begin_impl_frame_deadline_task_",
+ !begin_impl_frame_deadline_task_.IsCancelled());
+ scheduler_state->SetBoolean("poll_for_draw_triggers_task_",
+ !poll_for_draw_triggers_task_.IsCancelled());
+ scheduler_state->SetBoolean("advance_commit_state_task_",
+ !advance_commit_state_task_.IsCancelled());
+ scheduler_state->Set("begin_impl_frame_args",
+ begin_impl_frame_args_.AsValue().release());
+
+ state->Set("scheduler_state", scheduler_state.release());
+
+ scoped_ptr<base::DictionaryValue> client_state(new base::DictionaryValue);
+ client_state->SetDouble("draw_duration_estimate_ms",
+ client_->DrawDurationEstimate().InMillisecondsF());
+ client_state->SetDouble(
+ "begin_main_frame_to_commit_duration_estimate_ms",
+ client_->BeginMainFrameToCommitDurationEstimate().InMillisecondsF());
+ client_state->SetDouble(
+ "commit_to_activate_duration_estimate_ms",
+ client_->CommitToActivateDurationEstimate().InMillisecondsF());
+ state->Set("client_state", client_state.release());
+ return state.PassAs<base::Value>();
+}
+
bool Scheduler::CanCommitAndActivateBeforeDeadline() const {
// Check if the main thread computation and commit can be finished before the
// impl thread's deadline.
base::TimeTicks estimated_draw_time =
- last_begin_impl_frame_args_.frame_time +
+ begin_impl_frame_args_.frame_time +
client_->BeginMainFrameToCommitDurationEstimate() +
client_->CommitToActivateDurationEstimate();
- return estimated_draw_time < last_begin_impl_frame_args_.deadline;
+ TRACE_EVENT2(
+ TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"),
+ "CanCommitAndActivateBeforeDeadline",
+ "time_left_after_drawing_ms",
+ (begin_impl_frame_args_.deadline - estimated_draw_time).InMillisecondsF(),
+ "state",
+ ToTrace(this));
+
+ return estimated_draw_time < begin_impl_frame_args_.deadline;
+}
+
+bool Scheduler::IsBeginMainFrameSentOrStarted() const {
+ return (state_machine_.commit_state() ==
+ SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT ||
+ state_machine_.commit_state() ==
+ SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED);
}
} // namespace cc
diff --git a/chromium/cc/scheduler/scheduler.h b/chromium/cc/scheduler/scheduler.h
index 92097829390..3de06acbdc4 100644
--- a/chromium/cc/scheduler/scheduler.h
+++ b/chromium/cc/scheduler/scheduler.h
@@ -5,6 +5,7 @@
#ifndef CC_SCHEDULER_SCHEDULER_H_
#define CC_SCHEDULER_SCHEDULER_H_
+#include <deque>
#include <string>
#include "base/basictypes.h"
@@ -13,43 +14,34 @@
#include "base/time/time.h"
#include "cc/base/cc_export.h"
#include "cc/output/begin_frame_args.h"
+#include "cc/scheduler/delay_based_time_source.h"
+#include "cc/scheduler/draw_result.h"
#include "cc/scheduler/scheduler_settings.h"
#include "cc/scheduler/scheduler_state_machine.h"
-#include "cc/trees/layer_tree_host.h"
-namespace cc {
-
-class Thread;
+namespace base {
+class SingleThreadTaskRunner;
+}
-struct DrawSwapReadbackResult {
- DrawSwapReadbackResult()
- : did_draw(false), did_swap(false), did_readback(false) {}
- DrawSwapReadbackResult(bool did_draw, bool did_swap, bool did_readback)
- : did_draw(did_draw), did_swap(did_swap), did_readback(did_readback) {}
- bool did_draw;
- bool did_swap;
- bool did_readback;
-};
+namespace cc {
class SchedulerClient {
public:
- virtual void SetNeedsBeginImplFrame(bool enable) = 0;
+ virtual void SetNeedsBeginFrame(bool enable) = 0;
+ virtual void WillBeginImplFrame(const BeginFrameArgs& args) = 0;
virtual void ScheduledActionSendBeginMainFrame() = 0;
- virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapIfPossible() = 0;
- virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapForced() = 0;
- virtual DrawSwapReadbackResult ScheduledActionDrawAndReadback() = 0;
+ virtual DrawResult ScheduledActionDrawAndSwapIfPossible() = 0;
+ virtual DrawResult ScheduledActionDrawAndSwapForced() = 0;
+ virtual void ScheduledActionAnimate() = 0;
virtual void ScheduledActionCommit() = 0;
virtual void ScheduledActionUpdateVisibleTiles() = 0;
virtual void ScheduledActionActivatePendingTree() = 0;
virtual void ScheduledActionBeginOutputSurfaceCreation() = 0;
- virtual void ScheduledActionAcquireLayerTexturesForMainThread() = 0;
virtual void ScheduledActionManageTiles() = 0;
virtual void DidAnticipatedDrawTimeChange(base::TimeTicks time) = 0;
virtual base::TimeDelta DrawDurationEstimate() = 0;
virtual base::TimeDelta BeginMainFrameToCommitDurationEstimate() = 0;
virtual base::TimeDelta CommitToActivateDurationEstimate() = 0;
- virtual void PostBeginImplFrameDeadline(const base::Closure& closure,
- base::TimeTicks deadline) = 0;
virtual void DidBeginImplFrameDeadline() = 0;
protected:
@@ -61,13 +53,20 @@ class CC_EXPORT Scheduler {
static scoped_ptr<Scheduler> Create(
SchedulerClient* client,
const SchedulerSettings& scheduler_settings,
- int layer_tree_host_id) {
- return make_scoped_ptr(
- new Scheduler(client, scheduler_settings, layer_tree_host_id));
+ int layer_tree_host_id,
+ const scoped_refptr<base::SingleThreadTaskRunner>& impl_task_runner) {
+ return make_scoped_ptr(new Scheduler(
+ client, scheduler_settings, layer_tree_host_id, impl_task_runner));
}
virtual ~Scheduler();
+ const SchedulerSettings& settings() const { return settings_; }
+
+ void CommitVSyncParameters(base::TimeTicks timebase,
+ base::TimeDelta interval);
+ void SetEstimatedParentDrawTime(base::TimeDelta draw_time);
+
void SetCanStart();
void SetVisible(bool visible);
@@ -76,29 +75,25 @@ class CC_EXPORT Scheduler {
void SetNeedsCommit();
- // Like SetNeedsCommit(), but ensures a commit will definitely happen even if
- // we are not visible. Will eventually result in a forced draw internally.
- void SetNeedsForcedCommitForReadback();
-
void SetNeedsRedraw();
- void SetNeedsManageTiles();
+ void SetNeedsAnimate();
- void SetMainThreadNeedsLayerTextures();
+ void SetNeedsManageTiles();
+ void SetMaxSwapsPending(int max);
+ void DidSwapBuffers();
void SetSwapUsedIncompleteTile(bool used_incomplete_tile);
+ void DidSwapBuffersComplete();
void SetSmoothnessTakesPriority(bool smoothness_takes_priority);
- void FinishCommit();
+ void NotifyReadyToCommit();
void BeginMainFrameAborted(bool did_handle);
void DidManageTiles();
void DidLoseOutputSurface();
void DidCreateAndInitializeOutputSurface();
- bool HasInitializedOutputSurface() const {
- return state_machine_.HasInitializedOutputSurface();
- }
bool CommitPending() const { return state_machine_.CommitPending(); }
bool RedrawPending() const { return state_machine_.RedrawPending(); }
@@ -108,55 +103,126 @@ class CC_EXPORT Scheduler {
bool MainThreadIsInHighLatencyMode() const {
return state_machine_.MainThreadIsInHighLatencyMode();
}
+ bool BeginImplFrameDeadlinePending() const {
+ return !begin_impl_frame_deadline_task_.IsCancelled();
+ }
bool WillDrawIfNeeded() const;
- base::TimeTicks AnticipatedDrawTime();
+ base::TimeTicks AnticipatedDrawTime() const;
+
+ void NotifyBeginMainFrameStarted();
base::TimeTicks LastBeginImplFrameTime();
+ base::TimeDelta VSyncInterval() { return vsync_interval_; }
+ base::TimeDelta EstimatedParentDrawTime() {
+ return estimated_parent_draw_time_;
+ }
+
+ void BeginFrame(const BeginFrameArgs& args);
+ void PostBeginRetroFrame();
+ void BeginRetroFrame();
+ void BeginUnthrottledFrame();
void BeginImplFrame(const BeginFrameArgs& args);
void OnBeginImplFrameDeadline();
void PollForAnticipatedDrawTriggers();
+ void PollToAdvanceCommitState();
- scoped_ptr<base::Value> StateAsValue() {
- return state_machine_.AsValue().Pass();
- }
+ scoped_ptr<base::Value> AsValue() const;
bool IsInsideAction(SchedulerStateMachine::Action action) {
return inside_action_ == action;
}
- private:
- Scheduler(SchedulerClient* client,
- const SchedulerSettings& scheduler_settings,
- int layer_tree_host_id);
+ bool IsBeginMainFrameSent() const;
+ void SetContinuousPainting(bool continuous_painting) {
+ state_machine_.SetContinuousPainting(continuous_painting);
+ }
- void PostBeginImplFrameDeadline(base::TimeTicks deadline);
- void SetupNextBeginImplFrameIfNeeded();
- void ActivatePendingTree();
- void DrawAndSwapIfPossible();
- void DrawAndSwapForced();
- void DrawAndReadback();
- void ProcessScheduledActions();
+ protected:
+ class CC_EXPORT SyntheticBeginFrameSource : public TimeSourceClient {
+ public:
+ SyntheticBeginFrameSource(Scheduler* scheduler,
+ base::SingleThreadTaskRunner* task_runner);
+ virtual ~SyntheticBeginFrameSource();
- bool CanCommitAndActivateBeforeDeadline() const;
- void AdvanceCommitStateIfPossible();
+ // Updates the phase and frequency of the timer.
+ void CommitVSyncParameters(base::TimeTicks timebase,
+ base::TimeDelta interval);
+
+ // Activates future BeginFrames and, if activating, pushes the most
+ // recently missed BeginFrame to the back of a retroactive queue.
+ void SetNeedsBeginFrame(bool needs_begin_frame,
+ std::deque<BeginFrameArgs>* begin_retro_frame_args);
+
+ bool IsActive() const;
+
+ // TimeSourceClient implementation of OnTimerTick triggers a BeginFrame.
+ virtual void OnTimerTick() OVERRIDE;
+
+ scoped_ptr<base::Value> AsValue() const;
+
+ private:
+ BeginFrameArgs CreateSyntheticBeginFrameArgs(base::TimeTicks frame_time);
+
+ Scheduler* scheduler_;
+ scoped_refptr<DelayBasedTimeSource> time_source_;
+ };
+
+ Scheduler(
+ SchedulerClient* client,
+ const SchedulerSettings& scheduler_settings,
+ int layer_tree_host_id,
+ const scoped_refptr<base::SingleThreadTaskRunner>& impl_task_runner);
const SchedulerSettings settings_;
SchedulerClient* client_;
int layer_tree_host_id_;
+ scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner_;
- bool last_set_needs_begin_impl_frame_;
- BeginFrameArgs last_begin_impl_frame_args_;
- base::CancelableClosure begin_impl_frame_deadline_closure_;
- base::CancelableClosure poll_for_draw_triggers_closure_;
- base::RepeatingTimer<Scheduler> advance_commit_state_timer_;
+ base::TimeDelta vsync_interval_;
+ base::TimeDelta estimated_parent_draw_time_;
+
+ bool last_set_needs_begin_frame_;
+ bool begin_unthrottled_frame_posted_;
+ bool begin_retro_frame_posted_;
+ std::deque<BeginFrameArgs> begin_retro_frame_args_;
+ BeginFrameArgs begin_impl_frame_args_;
+
+ scoped_ptr<SyntheticBeginFrameSource> synthetic_begin_frame_source_;
+
+ base::Closure begin_retro_frame_closure_;
+ base::Closure begin_unthrottled_frame_closure_;
+
+ base::Closure begin_impl_frame_deadline_closure_;
+ base::Closure poll_for_draw_triggers_closure_;
+ base::Closure advance_commit_state_closure_;
+ base::CancelableClosure begin_impl_frame_deadline_task_;
+ base::CancelableClosure poll_for_draw_triggers_task_;
+ base::CancelableClosure advance_commit_state_task_;
SchedulerStateMachine state_machine_;
bool inside_process_scheduled_actions_;
SchedulerStateMachine::Action inside_action_;
+ private:
+ base::TimeTicks AdjustedBeginImplFrameDeadline(
+ const BeginFrameArgs& args,
+ base::TimeDelta draw_duration_estimate) const;
+ void ScheduleBeginImplFrameDeadline(base::TimeTicks deadline);
+ void SetupNextBeginFrameIfNeeded();
+ void PostBeginRetroFrameIfNeeded();
+ void SetupNextBeginFrameWhenVSyncThrottlingEnabled(bool needs_begin_frame);
+ void SetupNextBeginFrameWhenVSyncThrottlingDisabled(bool needs_begin_frame);
+ void SetupPollingMechanisms(bool needs_begin_frame);
+ void DrawAndSwapIfPossible();
+ void ProcessScheduledActions();
+ bool CanCommitAndActivateBeforeDeadline() const;
+ void AdvanceCommitStateIfPossible();
+ bool IsBeginMainFrameSentOrStarted() const;
+ void SetupSyntheticBeginFrames();
+
base::WeakPtrFactory<Scheduler> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(Scheduler);
diff --git a/chromium/cc/scheduler/scheduler_settings.cc b/chromium/cc/scheduler/scheduler_settings.cc
index ad925d4d135..f1bf60e7865 100644
--- a/chromium/cc/scheduler/scheduler_settings.cc
+++ b/chromium/cc/scheduler/scheduler_settings.cc
@@ -4,17 +4,55 @@
#include "cc/scheduler/scheduler_settings.h"
+#include "cc/trees/layer_tree_settings.h"
+
namespace cc {
SchedulerSettings::SchedulerSettings()
- : deadline_scheduling_enabled(true),
+ : begin_frame_scheduling_enabled(true),
+ main_frame_before_draw_enabled(true),
+ main_frame_before_activation_enabled(false),
impl_side_painting(false),
timeout_and_draw_when_animation_checkerboards(true),
maximum_number_of_failed_draws_before_draw_is_forced_(3),
using_synchronous_renderer_compositor(false),
- throttle_frame_production(true),
- switch_to_low_latency_if_possible(false) {}
+ throttle_frame_production(true) {
+}
+
+SchedulerSettings::SchedulerSettings(const LayerTreeSettings& settings)
+ : begin_frame_scheduling_enabled(settings.begin_frame_scheduling_enabled),
+ main_frame_before_draw_enabled(settings.main_frame_before_draw_enabled),
+ main_frame_before_activation_enabled(
+ settings.main_frame_before_activation_enabled),
+ impl_side_painting(settings.impl_side_painting),
+ timeout_and_draw_when_animation_checkerboards(
+ settings.timeout_and_draw_when_animation_checkerboards),
+ maximum_number_of_failed_draws_before_draw_is_forced_(
+ settings.maximum_number_of_failed_draws_before_draw_is_forced_),
+ using_synchronous_renderer_compositor(
+ settings.using_synchronous_renderer_compositor),
+ throttle_frame_production(settings.throttle_frame_production) {
+}
SchedulerSettings::~SchedulerSettings() {}
+scoped_ptr<base::Value> SchedulerSettings::AsValue() const {
+ scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue);
+ state->SetBoolean("begin_frame_scheduling_enabled",
+ begin_frame_scheduling_enabled);
+ state->SetBoolean("main_frame_before_draw_enabled",
+ main_frame_before_draw_enabled);
+ state->SetBoolean("main_frame_before_activation_enabled",
+ main_frame_before_activation_enabled);
+ state->SetBoolean("impl_side_painting", impl_side_painting);
+ state->SetBoolean("timeout_and_draw_when_animation_checkerboards",
+ timeout_and_draw_when_animation_checkerboards);
+ state->SetInteger("maximum_number_of_failed_draws_before_draw_is_forced_",
+ maximum_number_of_failed_draws_before_draw_is_forced_);
+ state->SetBoolean("using_synchronous_renderer_compositor",
+ using_synchronous_renderer_compositor);
+ state->SetBoolean("throttle_frame_production", throttle_frame_production);
+ return state.PassAs<base::Value>();
+}
+
} // namespace cc
diff --git a/chromium/cc/scheduler/scheduler_settings.h b/chromium/cc/scheduler/scheduler_settings.h
index b35cb7e6af6..c282cf6a124 100644
--- a/chromium/cc/scheduler/scheduler_settings.h
+++ b/chromium/cc/scheduler/scheduler_settings.h
@@ -5,22 +5,29 @@
#ifndef CC_SCHEDULER_SCHEDULER_SETTINGS_H_
#define CC_SCHEDULER_SCHEDULER_SETTINGS_H_
+#include "base/memory/scoped_ptr.h"
+#include "base/values.h"
#include "cc/base/cc_export.h"
namespace cc {
+class LayerTreeSettings;
class CC_EXPORT SchedulerSettings {
public:
SchedulerSettings();
+ explicit SchedulerSettings(const LayerTreeSettings& settings);
~SchedulerSettings();
- bool deadline_scheduling_enabled;
+ bool begin_frame_scheduling_enabled;
+ bool main_frame_before_draw_enabled;
+ bool main_frame_before_activation_enabled;
bool impl_side_painting;
bool timeout_and_draw_when_animation_checkerboards;
int maximum_number_of_failed_draws_before_draw_is_forced_;
bool using_synchronous_renderer_compositor;
bool throttle_frame_production;
- bool switch_to_low_latency_if_possible;
+
+ scoped_ptr<base::Value> AsValue() const;
};
} // namespace cc
diff --git a/chromium/cc/scheduler/scheduler_state_machine.cc b/chromium/cc/scheduler/scheduler_state_machine.cc
index 7d8fcd721a3..dea25b40871 100644
--- a/chromium/cc/scheduler/scheduler_state_machine.cc
+++ b/chromium/cc/scheduler/scheduler_state_machine.cc
@@ -18,21 +18,23 @@ SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings)
output_surface_state_(OUTPUT_SURFACE_LOST),
begin_impl_frame_state_(BEGIN_IMPL_FRAME_STATE_IDLE),
commit_state_(COMMIT_STATE_IDLE),
- texture_state_(LAYER_TEXTURE_STATE_UNLOCKED),
forced_redraw_state_(FORCED_REDRAW_STATE_IDLE),
- readback_state_(READBACK_STATE_IDLE),
commit_count_(0),
current_frame_number_(0),
+ last_frame_number_animate_performed_(-1),
last_frame_number_swap_performed_(-1),
+ last_frame_number_swap_requested_(-1),
last_frame_number_begin_main_frame_sent_(-1),
last_frame_number_update_visible_tiles_was_called_(-1),
- last_frame_number_manage_tiles_called_(-1),
- consecutive_failed_draws_(0),
+ manage_tiles_funnel_(0),
+ consecutive_checkerboard_animations_(0),
+ max_pending_swaps_(1),
+ pending_swaps_(0),
needs_redraw_(false),
+ needs_animate_(false),
needs_manage_tiles_(false),
swap_used_incomplete_tile_(false),
needs_commit_(false),
- main_thread_needs_layer_textures_(false),
inside_poll_for_anticipated_draw_triggers_(false),
visible_(false),
can_start_(false),
@@ -40,10 +42,12 @@ SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings)
has_pending_tree_(false),
pending_tree_is_ready_for_activation_(false),
active_tree_needs_first_draw_(false),
- draw_if_possible_failed_(false),
did_create_and_initialize_first_output_surface_(false),
smoothness_takes_priority_(false),
- skip_begin_main_frame_to_reduce_latency_(false) {}
+ skip_next_begin_main_frame_to_reduce_latency_(false),
+ skip_begin_main_frame_to_reduce_latency_(false),
+ continuous_painting_(false) {
+}
const char* SchedulerStateMachine::OutputSurfaceStateToString(
OutputSurfaceState state) {
@@ -83,10 +87,14 @@ const char* SchedulerStateMachine::CommitStateToString(CommitState state) {
switch (state) {
case COMMIT_STATE_IDLE:
return "COMMIT_STATE_IDLE";
- case COMMIT_STATE_FRAME_IN_PROGRESS:
- return "COMMIT_STATE_FRAME_IN_PROGRESS";
+ case COMMIT_STATE_BEGIN_MAIN_FRAME_SENT:
+ return "COMMIT_STATE_BEGIN_MAIN_FRAME_SENT";
+ case COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED:
+ return "COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED";
case COMMIT_STATE_READY_TO_COMMIT:
return "COMMIT_STATE_READY_TO_COMMIT";
+ case COMMIT_STATE_WAITING_FOR_ACTIVATION:
+ return "COMMIT_STATE_WAITING_FOR_ACTIVATION";
case COMMIT_STATE_WAITING_FOR_FIRST_DRAW:
return "COMMIT_STATE_WAITING_FOR_FIRST_DRAW";
}
@@ -94,41 +102,6 @@ const char* SchedulerStateMachine::CommitStateToString(CommitState state) {
return "???";
}
-const char* SchedulerStateMachine::TextureStateToString(TextureState state) {
- switch (state) {
- case LAYER_TEXTURE_STATE_UNLOCKED:
- return "LAYER_TEXTURE_STATE_UNLOCKED";
- case LAYER_TEXTURE_STATE_ACQUIRED_BY_MAIN_THREAD:
- return "LAYER_TEXTURE_STATE_ACQUIRED_BY_MAIN_THREAD";
- case LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD:
- return "LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD";
- }
- NOTREACHED();
- return "???";
-}
-
-const char* SchedulerStateMachine::SynchronousReadbackStateToString(
- SynchronousReadbackState state) {
- switch (state) {
- case READBACK_STATE_IDLE:
- return "READBACK_STATE_IDLE";
- case READBACK_STATE_NEEDS_BEGIN_MAIN_FRAME:
- return "READBACK_STATE_NEEDS_BEGIN_MAIN_FRAME";
- case READBACK_STATE_WAITING_FOR_COMMIT:
- return "READBACK_STATE_WAITING_FOR_COMMIT";
- case READBACK_STATE_WAITING_FOR_ACTIVATION:
- return "READBACK_STATE_WAITING_FOR_ACTIVATION";
- case READBACK_STATE_WAITING_FOR_DRAW_AND_READBACK:
- return "READBACK_STATE_WAITING_FOR_DRAW_AND_READBACK";
- case READBACK_STATE_WAITING_FOR_REPLACEMENT_COMMIT:
- return "READBACK_STATE_WAITING_FOR_REPLACEMENT_COMMIT";
- case READBACK_STATE_WAITING_FOR_REPLACEMENT_ACTIVATION:
- return "READBACK_STATE_WAITING_FOR_REPLACEMENT_ACTIVATION";
- }
- NOTREACHED();
- return "???";
-}
-
const char* SchedulerStateMachine::ForcedRedrawOnTimeoutStateToString(
ForcedRedrawOnTimeoutState state) {
switch (state) {
@@ -149,6 +122,8 @@ const char* SchedulerStateMachine::ActionToString(Action action) {
switch (action) {
case ACTION_NONE:
return "ACTION_NONE";
+ case ACTION_ANIMATE:
+ return "ACTION_ANIMATE";
case ACTION_SEND_BEGIN_MAIN_FRAME:
return "ACTION_SEND_BEGIN_MAIN_FRAME";
case ACTION_COMMIT:
@@ -163,12 +138,8 @@ const char* SchedulerStateMachine::ActionToString(Action action) {
return "ACTION_DRAW_AND_SWAP_FORCED";
case ACTION_DRAW_AND_SWAP_ABORT:
return "ACTION_DRAW_AND_SWAP_ABORT";
- case ACTION_DRAW_AND_READBACK:
- return "ACTION_DRAW_AND_READBACK";
case ACTION_BEGIN_OUTPUT_SURFACE_CREATION:
return "ACTION_BEGIN_OUTPUT_SURFACE_CREATION";
- case ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD:
- return "ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD";
case ACTION_MANAGE_TILES:
return "ACTION_MANAGE_TILES";
}
@@ -184,45 +155,37 @@ scoped_ptr<base::Value> SchedulerStateMachine::AsValue() const {
major_state->SetString("begin_impl_frame_state",
BeginImplFrameStateToString(begin_impl_frame_state_));
major_state->SetString("commit_state", CommitStateToString(commit_state_));
- major_state->SetString("texture_state_",
- TextureStateToString(texture_state_));
major_state->SetString("output_surface_state_",
OutputSurfaceStateToString(output_surface_state_));
major_state->SetString(
"forced_redraw_state",
ForcedRedrawOnTimeoutStateToString(forced_redraw_state_));
- major_state->SetString("readback_state",
- SynchronousReadbackStateToString(readback_state_));
state->Set("major_state", major_state.release());
scoped_ptr<base::DictionaryValue> timestamps_state(new base::DictionaryValue);
base::TimeTicks now = gfx::FrameTime::Now();
timestamps_state->SetDouble(
- "0_interval",
- last_begin_impl_frame_args_.interval.InMicroseconds() / 1000.0L);
+ "0_interval", begin_impl_frame_args_.interval.InMicroseconds() / 1000.0L);
timestamps_state->SetDouble(
"1_now_to_deadline",
- (last_begin_impl_frame_args_.deadline - now).InMicroseconds() / 1000.0L);
+ (begin_impl_frame_args_.deadline - now).InMicroseconds() / 1000.0L);
timestamps_state->SetDouble(
"2_frame_time_to_now",
- (now - last_begin_impl_frame_args_.frame_time).InMicroseconds() /
- 1000.0L);
+ (now - begin_impl_frame_args_.frame_time).InMicroseconds() / 1000.0L);
timestamps_state->SetDouble(
"3_frame_time_to_deadline",
- (last_begin_impl_frame_args_.deadline -
- last_begin_impl_frame_args_.frame_time).InMicroseconds() /
+ (begin_impl_frame_args_.deadline - begin_impl_frame_args_.frame_time)
+ .InMicroseconds() /
1000.0L);
timestamps_state->SetDouble(
"4_now", (now - base::TimeTicks()).InMicroseconds() / 1000.0L);
timestamps_state->SetDouble(
"5_frame_time",
- (last_begin_impl_frame_args_.frame_time - base::TimeTicks())
- .InMicroseconds() /
+ (begin_impl_frame_args_.frame_time - base::TimeTicks()).InMicroseconds() /
1000.0L);
timestamps_state->SetDouble(
"6_deadline",
- (last_begin_impl_frame_args_.deadline - base::TimeTicks())
- .InMicroseconds() /
+ (begin_impl_frame_args_.deadline - base::TimeTicks()).InMicroseconds() /
1000.0L);
state->Set("major_timestamps_in_ms", timestamps_state.release());
@@ -230,8 +193,12 @@ scoped_ptr<base::Value> SchedulerStateMachine::AsValue() const {
minor_state->SetInteger("commit_count", commit_count_);
minor_state->SetInteger("current_frame_number", current_frame_number_);
+ minor_state->SetInteger("last_frame_number_animate_performed",
+ last_frame_number_animate_performed_);
minor_state->SetInteger("last_frame_number_swap_performed",
last_frame_number_swap_performed_);
+ minor_state->SetInteger("last_frame_number_swap_requested",
+ last_frame_number_swap_requested_);
minor_state->SetInteger(
"last_frame_number_begin_main_frame_sent",
last_frame_number_begin_main_frame_sent_);
@@ -239,15 +206,17 @@ scoped_ptr<base::Value> SchedulerStateMachine::AsValue() const {
"last_frame_number_update_visible_tiles_was_called",
last_frame_number_update_visible_tiles_was_called_);
- minor_state->SetInteger("consecutive_failed_draws",
- consecutive_failed_draws_);
+ minor_state->SetInteger("manage_tiles_funnel", manage_tiles_funnel_);
+ minor_state->SetInteger("consecutive_checkerboard_animations",
+ consecutive_checkerboard_animations_);
+ minor_state->SetInteger("max_pending_swaps_", max_pending_swaps_);
+ minor_state->SetInteger("pending_swaps_", pending_swaps_);
minor_state->SetBoolean("needs_redraw", needs_redraw_);
+ minor_state->SetBoolean("needs_animate_", needs_animate_);
minor_state->SetBoolean("needs_manage_tiles", needs_manage_tiles_);
minor_state->SetBoolean("swap_used_incomplete_tile",
swap_used_incomplete_tile_);
minor_state->SetBoolean("needs_commit", needs_commit_);
- minor_state->SetBoolean("main_thread_needs_layer_textures",
- main_thread_needs_layer_textures_);
minor_state->SetBoolean("visible", visible_);
minor_state->SetBoolean("can_start", can_start_);
minor_state->SetBoolean("can_draw", can_draw_);
@@ -256,7 +225,6 @@ scoped_ptr<base::Value> SchedulerStateMachine::AsValue() const {
pending_tree_is_ready_for_activation_);
minor_state->SetBoolean("active_tree_needs_first_draw",
active_tree_needs_first_draw_);
- minor_state->SetBoolean("draw_if_possible_failed", draw_if_possible_failed_);
minor_state->SetBoolean("did_create_and_initialize_first_output_surface",
did_create_and_initialize_first_output_surface_);
minor_state->SetBoolean("smoothness_takes_priority",
@@ -265,11 +233,26 @@ scoped_ptr<base::Value> SchedulerStateMachine::AsValue() const {
MainThreadIsInHighLatencyMode());
minor_state->SetBoolean("skip_begin_main_frame_to_reduce_latency",
skip_begin_main_frame_to_reduce_latency_);
+ minor_state->SetBoolean("skip_next_begin_main_frame_to_reduce_latency",
+ skip_next_begin_main_frame_to_reduce_latency_);
+ minor_state->SetBoolean("continuous_painting", continuous_painting_);
state->Set("minor_state", minor_state.release());
return state.PassAs<base::Value>();
}
+void SchedulerStateMachine::AdvanceCurrentFrameNumber() {
+ current_frame_number_++;
+
+ // "Drain" the ManageTiles funnel.
+ if (manage_tiles_funnel_ > 0)
+ manage_tiles_funnel_--;
+
+ skip_begin_main_frame_to_reduce_latency_ =
+ skip_next_begin_main_frame_to_reduce_latency_;
+ skip_next_begin_main_frame_to_reduce_latency_ = false;
+}
+
bool SchedulerStateMachine::HasSentBeginMainFrameThisFrame() const {
return current_frame_number_ ==
last_frame_number_begin_main_frame_sent_;
@@ -284,6 +267,10 @@ bool SchedulerStateMachine::HasSwappedThisFrame() const {
return current_frame_number_ == last_frame_number_swap_performed_;
}
+bool SchedulerStateMachine::HasRequestedSwapThisFrame() const {
+ return current_frame_number_ == last_frame_number_swap_requested_;
+}
+
bool SchedulerStateMachine::PendingDrawsShouldBeAborted() const {
// These are all the cases where we normally cannot or do not want to draw
// but, if needs_redraw_ is true and we do not draw to make forward progress,
@@ -308,11 +295,6 @@ bool SchedulerStateMachine::PendingActivationsShouldBeForced() const {
// These are all the cases where, if we do not force activations to make
// forward progress, we might deadlock with the main thread.
- // The impl thread cannot lock layer textures unless the pending
- // tree can be activated to unblock the commit.
- if (texture_state_ == LAYER_TEXTURE_STATE_ACQUIRED_BY_MAIN_THREAD)
- return true;
-
// There is no output surface to trigger our activations.
if (output_surface_state_ == OUTPUT_SURFACE_LOST)
return true;
@@ -330,11 +312,15 @@ bool SchedulerStateMachine::ShouldBeginOutputSurfaceCreation() const {
if (commit_state_ != COMMIT_STATE_IDLE)
return false;
+ // Make sure the BeginImplFrame from any previous OutputSurfaces
+ // are complete before creating the new OutputSurface.
+ if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_IDLE)
+ return false;
+
// We want to clear the pipline of any pending draws and activations
// before starting output surface initialization. This allows us to avoid
// weird corner cases where we abort draws or force activation while we
- // are initializing the output surface and can potentially have a pending
- // readback.
+ // are initializing the output surface.
if (active_tree_needs_first_draw_ || has_pending_tree_)
return false;
@@ -344,18 +330,6 @@ bool SchedulerStateMachine::ShouldBeginOutputSurfaceCreation() const {
}
bool SchedulerStateMachine::ShouldDraw() const {
- // After a readback, make sure not to draw again until we've replaced the
- // readback commit with a real one.
- if (readback_state_ == READBACK_STATE_WAITING_FOR_REPLACEMENT_COMMIT ||
- readback_state_ == READBACK_STATE_WAITING_FOR_REPLACEMENT_ACTIVATION)
- return false;
-
- // Draw immediately for readbacks to unblock the main thread quickly.
- if (readback_state_ == READBACK_STATE_WAITING_FOR_DRAW_AND_READBACK) {
- DCHECK_EQ(commit_state_, COMMIT_STATE_WAITING_FOR_FIRST_DRAW);
- return true;
- }
-
// If we need to abort draws, we should do so ASAP since the draw could
// be blocking other important actions (like output surface initialization),
// from occuring. If we are waiting for the first draw, then perfom the
@@ -364,8 +338,12 @@ bool SchedulerStateMachine::ShouldDraw() const {
if (PendingDrawsShouldBeAborted())
return active_tree_needs_first_draw_;
- // After this line, we only want to swap once per frame.
- if (HasSwappedThisFrame())
+ // After this line, we only want to send a swap request once per frame.
+ if (HasRequestedSwapThisFrame())
+ return false;
+
+ // Do not queue too many swaps.
+ if (pending_swaps_ >= max_pending_swaps_)
return false;
// Except for the cases above, do not draw outside of the BeginImplFrame
@@ -374,23 +352,12 @@ bool SchedulerStateMachine::ShouldDraw() const {
return false;
// Only handle forced redraws due to timeouts on the regular deadline.
- if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW) {
- DCHECK_EQ(commit_state_, COMMIT_STATE_WAITING_FOR_FIRST_DRAW);
+ if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)
return true;
- }
return needs_redraw_;
}
-bool SchedulerStateMachine::ShouldAcquireLayerTexturesForMainThread() const {
- if (!main_thread_needs_layer_textures_)
- return false;
- if (texture_state_ == LAYER_TEXTURE_STATE_UNLOCKED)
- return true;
- DCHECK_EQ(texture_state_, LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD);
- return false;
-}
-
bool SchedulerStateMachine::ShouldActivatePendingTree() const {
// There is nothing to activate.
if (!has_pending_tree_)
@@ -416,6 +383,10 @@ bool SchedulerStateMachine::ShouldUpdateVisibleTiles() const {
if (HasUpdatedVisibleTilesThisFrame())
return false;
+ // We don't want to update visible tiles right after drawing.
+ if (HasRequestedSwapThisFrame())
+ return false;
+
// There's no reason to check for tiles if we don't have an output surface.
if (!HasInitializedOutputSurface())
return false;
@@ -434,6 +405,20 @@ bool SchedulerStateMachine::ShouldUpdateVisibleTiles() const {
return false;
}
+bool SchedulerStateMachine::ShouldAnimate() const {
+ if (!can_draw_)
+ return false;
+
+ if (last_frame_number_animate_performed_ == current_frame_number_)
+ return false;
+
+ if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING &&
+ begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE)
+ return false;
+
+ return needs_redraw_ || needs_animate_;
+}
+
bool SchedulerStateMachine::ShouldSendBeginMainFrame() const {
if (!needs_commit_)
return false;
@@ -442,19 +427,14 @@ bool SchedulerStateMachine::ShouldSendBeginMainFrame() const {
if (commit_state_ != COMMIT_STATE_IDLE)
return false;
- // We can't accept a commit if we have a pending tree.
- if (has_pending_tree_)
+ // Don't send BeginMainFrame early if we are prioritizing the active tree
+ // because of smoothness_takes_priority.
+ if (smoothness_takes_priority_ &&
+ (has_pending_tree_ || active_tree_needs_first_draw_)) {
return false;
+ }
- // We want to handle readback commits immediately to unblock the main thread.
- // Note: This BeginMainFrame will correspond to the replacement commit that
- // comes after the readback commit itself, so we only send the BeginMainFrame
- // if a commit isn't already pending behind the readback.
- if (readback_state_ == READBACK_STATE_NEEDS_BEGIN_MAIN_FRAME)
- return !CommitPending();
-
- // We do not need commits if we are not visible, unless there's a
- // request for a readback.
+ // We do not need commits if we are not visible.
if (!visible_)
return false;
@@ -462,20 +442,13 @@ bool SchedulerStateMachine::ShouldSendBeginMainFrame() const {
if (output_surface_state_ == OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT)
return true;
- // With deadline scheduling enabled, we should not send BeginMainFrame while
- // we are in BEGIN_IMPL_FRAME_STATE_IDLE, since we might have new user input
- // coming in soon.
- // However, if we are not expecting a BeginImplFrame to take us out of idle,
- // we should not early out here to avoid blocking commits forever.
- // This only works well when deadline scheduling is enabled because there is
- // an interval over which to accept the commit and draw. Without deadline
- // scheduling, delaying the commit could prevent us from having something
- // to draw on the next BeginImplFrame.
+ // We should not send BeginMainFrame while we are in
+ // BEGIN_IMPL_FRAME_STATE_IDLE since we might have new
+ // user input arriving soon.
// TODO(brianderson): Allow sending BeginMainFrame while idle when the main
// thread isn't consuming user input.
- if (settings_.deadline_scheduling_enabled &&
- begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_IDLE &&
- BeginImplFrameNeeded())
+ if (begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_IDLE &&
+ BeginFrameNeeded())
return false;
// We need a new commit for the forced redraw. This honors the
@@ -491,6 +464,14 @@ bool SchedulerStateMachine::ShouldSendBeginMainFrame() const {
if (!HasInitializedOutputSurface())
return false;
+ // SwapAck throttle the BeginMainFrames unless we just swapped.
+ // TODO(brianderson): Remove this restriction to improve throughput.
+ bool just_swapped_in_deadline =
+ begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE &&
+ HasSwappedThisFrame();
+ if (pending_swaps_ >= max_pending_swaps_ && !just_swapped_in_deadline)
+ return false;
+
if (skip_begin_main_frame_to_reduce_latency_)
return false;
@@ -498,18 +479,27 @@ bool SchedulerStateMachine::ShouldSendBeginMainFrame() const {
}
bool SchedulerStateMachine::ShouldCommit() const {
- return commit_state_ == COMMIT_STATE_READY_TO_COMMIT;
-}
+ if (commit_state_ != COMMIT_STATE_READY_TO_COMMIT)
+ return false;
-bool SchedulerStateMachine::IsCommitStateWaiting() const {
- return commit_state_ == COMMIT_STATE_FRAME_IN_PROGRESS;
+ // We must not finish the commit until the pending tree is free.
+ if (has_pending_tree_) {
+ DCHECK(settings_.main_frame_before_activation_enabled);
+ return false;
+ }
+
+ // Prioritize drawing the previous commit before finishing the next commit.
+ if (active_tree_needs_first_draw_)
+ return false;
+
+ return true;
}
bool SchedulerStateMachine::ShouldManageTiles() const {
// ManageTiles only really needs to be called immediately after commit
- // and then periodically after that. Limiting to once per frame prevents
- // post-commit and post-draw ManageTiles on the same frame.
- if (last_frame_number_manage_tiles_called_ == current_frame_number_)
+ // and then periodically after that. Use a funnel to make sure we average
+ // one ManageTiles per BeginImplFrame in the long run.
+ if (manage_tiles_funnel_ > 0)
return false;
// Limiting to once per-frame is not enough, since we only want to
@@ -522,18 +512,16 @@ bool SchedulerStateMachine::ShouldManageTiles() const {
}
SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const {
- if (ShouldAcquireLayerTexturesForMainThread())
- return ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD;
if (ShouldUpdateVisibleTiles())
return ACTION_UPDATE_VISIBLE_TILES;
if (ShouldActivatePendingTree())
return ACTION_ACTIVATE_PENDING_TREE;
if (ShouldCommit())
return ACTION_COMMIT;
+ if (ShouldAnimate())
+ return ACTION_ANIMATE;
if (ShouldDraw()) {
- if (readback_state_ == READBACK_STATE_WAITING_FOR_DRAW_AND_READBACK)
- return ACTION_DRAW_AND_READBACK;
- else if (PendingDrawsShouldBeAborted())
+ if (PendingDrawsShouldBeAborted())
return ACTION_DRAW_AND_SWAP_ABORT;
else if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)
return ACTION_DRAW_AND_SWAP_FORCED;
@@ -549,13 +537,6 @@ SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const {
return ACTION_NONE;
}
-void SchedulerStateMachine::CheckInvariants() {
- // We should never try to perform a draw for readback and forced draw due to
- // timeout simultaneously.
- DCHECK(!(forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW &&
- readback_state_ == READBACK_STATE_WAITING_FOR_DRAW_AND_READBACK));
-}
-
void SchedulerStateMachine::UpdateState(Action action) {
switch (action) {
case ACTION_NONE:
@@ -570,14 +551,22 @@ void SchedulerStateMachine::UpdateState(Action action) {
UpdateStateOnActivation();
return;
+ case ACTION_ANIMATE:
+ last_frame_number_animate_performed_ = current_frame_number_;
+ needs_animate_ = false;
+ // TODO(skyostil): Instead of assuming this, require the client to tell
+ // us.
+ SetNeedsRedraw();
+ return;
+
case ACTION_SEND_BEGIN_MAIN_FRAME:
- DCHECK(!has_pending_tree_);
- DCHECK(visible_ ||
- readback_state_ == READBACK_STATE_NEEDS_BEGIN_MAIN_FRAME);
- commit_state_ = COMMIT_STATE_FRAME_IN_PROGRESS;
+ DCHECK(!has_pending_tree_ ||
+ settings_.main_frame_before_activation_enabled);
+ DCHECK(!active_tree_needs_first_draw_ ||
+ settings_.main_frame_before_draw_enabled);
+ DCHECK(visible_);
+ commit_state_ = COMMIT_STATE_BEGIN_MAIN_FRAME_SENT;
needs_commit_ = false;
- if (readback_state_ == READBACK_STATE_NEEDS_BEGIN_MAIN_FRAME)
- readback_state_ = READBACK_STATE_WAITING_FOR_COMMIT;
last_frame_number_begin_main_frame_sent_ =
current_frame_number_;
return;
@@ -590,15 +579,14 @@ void SchedulerStateMachine::UpdateState(Action action) {
case ACTION_DRAW_AND_SWAP_FORCED:
case ACTION_DRAW_AND_SWAP_IF_POSSIBLE: {
- bool did_swap = true;
- UpdateStateOnDraw(did_swap);
+ bool did_request_swap = true;
+ UpdateStateOnDraw(did_request_swap);
return;
}
- case ACTION_DRAW_AND_SWAP_ABORT:
- case ACTION_DRAW_AND_READBACK: {
- bool did_swap = false;
- UpdateStateOnDraw(did_swap);
+ case ACTION_DRAW_AND_SWAP_ABORT: {
+ bool did_request_swap = false;
+ UpdateStateOnDraw(did_request_swap);
return;
}
@@ -614,11 +602,6 @@ void SchedulerStateMachine::UpdateState(Action action) {
DCHECK(!active_tree_needs_first_draw_);
return;
- case ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD:
- texture_state_ = LAYER_TEXTURE_STATE_ACQUIRED_BY_MAIN_THREAD;
- main_thread_needs_layer_textures_ = false;
- return;
-
case ACTION_MANAGE_TILES:
UpdateStateOnManageTiles();
return;
@@ -628,68 +611,42 @@ void SchedulerStateMachine::UpdateState(Action action) {
void SchedulerStateMachine::UpdateStateOnCommit(bool commit_was_aborted) {
commit_count_++;
+ if (commit_was_aborted || settings_.main_frame_before_activation_enabled) {
+ commit_state_ = COMMIT_STATE_IDLE;
+ } else if (settings_.main_frame_before_draw_enabled) {
+ commit_state_ = settings_.impl_side_painting
+ ? COMMIT_STATE_WAITING_FOR_ACTIVATION
+ : COMMIT_STATE_IDLE;
+ } else {
+ commit_state_ = COMMIT_STATE_WAITING_FOR_FIRST_DRAW;
+ }
+
// If we are impl-side-painting but the commit was aborted, then we behave
// mostly as if we are not impl-side-painting since there is no pending tree.
has_pending_tree_ = settings_.impl_side_painting && !commit_was_aborted;
- // Update state related to readbacks.
- if (readback_state_ == READBACK_STATE_WAITING_FOR_COMMIT) {
- // Update the state if this is the readback commit.
- readback_state_ = has_pending_tree_
- ? READBACK_STATE_WAITING_FOR_ACTIVATION
- : READBACK_STATE_WAITING_FOR_DRAW_AND_READBACK;
- } else if (readback_state_ == READBACK_STATE_WAITING_FOR_REPLACEMENT_COMMIT) {
- // Update the state if this is the commit replacing the readback commit.
- readback_state_ = has_pending_tree_
- ? READBACK_STATE_WAITING_FOR_REPLACEMENT_ACTIVATION
- : READBACK_STATE_IDLE;
- } else {
- DCHECK(readback_state_ == READBACK_STATE_IDLE);
+ // Update state related to forced draws.
+ if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_COMMIT) {
+ forced_redraw_state_ = has_pending_tree_
+ ? FORCED_REDRAW_STATE_WAITING_FOR_ACTIVATION
+ : FORCED_REDRAW_STATE_WAITING_FOR_DRAW;
}
- // Readbacks can interrupt output surface initialization and forced draws,
- // so we do not want to advance those states if we are in the middle of a
- // readback. Note: It is possible for the readback's replacement commit to
- // be the output surface's first commit and/or the forced redraw's commit.
- if (readback_state_ == READBACK_STATE_IDLE ||
- readback_state_ == READBACK_STATE_WAITING_FOR_REPLACEMENT_ACTIVATION) {
- // Update state related to forced draws.
- if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_COMMIT) {
- forced_redraw_state_ = has_pending_tree_
- ? FORCED_REDRAW_STATE_WAITING_FOR_ACTIVATION
- : FORCED_REDRAW_STATE_WAITING_FOR_DRAW;
- }
-
- // Update the output surface state.
- DCHECK_NE(output_surface_state_,
- OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION);
- if (output_surface_state_ == OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT) {
- if (has_pending_tree_) {
- output_surface_state_ = OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION;
- } else {
- output_surface_state_ = OUTPUT_SURFACE_ACTIVE;
- needs_redraw_ = true;
- }
+ // Update the output surface state.
+ DCHECK_NE(output_surface_state_, OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION);
+ if (output_surface_state_ == OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT) {
+ if (has_pending_tree_) {
+ output_surface_state_ = OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION;
+ } else {
+ output_surface_state_ = OUTPUT_SURFACE_ACTIVE;
+ needs_redraw_ = true;
}
}
- // Update the commit state. We expect and wait for a draw if the commit
- // was not aborted or if we are in a readback or forced draw.
- if (!commit_was_aborted) {
- DCHECK(commit_state_ == COMMIT_STATE_READY_TO_COMMIT);
- commit_state_ = COMMIT_STATE_WAITING_FOR_FIRST_DRAW;
- } else if (readback_state_ != READBACK_STATE_IDLE ||
- forced_redraw_state_ != FORCED_REDRAW_STATE_IDLE) {
- commit_state_ = COMMIT_STATE_WAITING_FOR_FIRST_DRAW;
- } else {
- commit_state_ = COMMIT_STATE_IDLE;
- }
-
// Update state if we have a new active tree to draw, or if the active tree
- // was unchanged but we need to do a readback or forced draw.
+ // was unchanged but we need to do a forced draw.
if (!has_pending_tree_ &&
(!commit_was_aborted ||
- readback_state_ == READBACK_STATE_WAITING_FOR_DRAW_AND_READBACK ||
forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)) {
needs_redraw_ = true;
active_tree_needs_first_draw_ = true;
@@ -698,125 +655,88 @@ void SchedulerStateMachine::UpdateStateOnCommit(bool commit_was_aborted) {
// This post-commit work is common to both completed and aborted commits.
pending_tree_is_ready_for_activation_ = false;
- if (draw_if_possible_failed_)
- last_frame_number_swap_performed_ = -1;
-
- // If we are planing to draw with the new commit, lock the layer textures for
- // use on the impl thread. Otherwise, leave them unlocked.
- if (has_pending_tree_ || needs_redraw_)
- texture_state_ = LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD;
- else
- texture_state_ = LAYER_TEXTURE_STATE_UNLOCKED;
+ if (continuous_painting_)
+ needs_commit_ = true;
}
void SchedulerStateMachine::UpdateStateOnActivation() {
- // Update output surface state.
+ if (commit_state_ == COMMIT_STATE_WAITING_FOR_ACTIVATION)
+ commit_state_ = COMMIT_STATE_IDLE;
+
if (output_surface_state_ == OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION)
output_surface_state_ = OUTPUT_SURFACE_ACTIVE;
- // Update readback state
if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_ACTIVATION)
forced_redraw_state_ = FORCED_REDRAW_STATE_WAITING_FOR_DRAW;
- // Update forced redraw state
- if (readback_state_ == READBACK_STATE_WAITING_FOR_ACTIVATION)
- readback_state_ = READBACK_STATE_WAITING_FOR_DRAW_AND_READBACK;
- else if (readback_state_ == READBACK_STATE_WAITING_FOR_REPLACEMENT_ACTIVATION)
- readback_state_ = READBACK_STATE_IDLE;
-
has_pending_tree_ = false;
pending_tree_is_ready_for_activation_ = false;
active_tree_needs_first_draw_ = true;
needs_redraw_ = true;
}
-void SchedulerStateMachine::UpdateStateOnDraw(bool did_swap) {
- DCHECK(readback_state_ != READBACK_STATE_WAITING_FOR_REPLACEMENT_COMMIT &&
- readback_state_ != READBACK_STATE_WAITING_FOR_REPLACEMENT_ACTIVATION)
- << *AsValue();
-
- if (readback_state_ == READBACK_STATE_WAITING_FOR_DRAW_AND_READBACK) {
- // The draw correspons to a readback commit.
- DCHECK_EQ(commit_state_, COMMIT_STATE_WAITING_FOR_FIRST_DRAW);
- // We are blocking commits from the main thread until after this draw, so
- // we should not have a pending tree.
- DCHECK(!has_pending_tree_);
- // We transition to COMMIT_STATE_FRAME_IN_PROGRESS because there is a
- // pending BeginMainFrame behind the readback request.
- commit_state_ = COMMIT_STATE_FRAME_IN_PROGRESS;
- readback_state_ = READBACK_STATE_WAITING_FOR_REPLACEMENT_COMMIT;
- } else if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW) {
- DCHECK_EQ(commit_state_, COMMIT_STATE_WAITING_FOR_FIRST_DRAW);
- commit_state_ = COMMIT_STATE_IDLE;
+void SchedulerStateMachine::UpdateStateOnDraw(bool did_request_swap) {
+ if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)
forced_redraw_state_ = FORCED_REDRAW_STATE_IDLE;
- } else if (commit_state_ == COMMIT_STATE_WAITING_FOR_FIRST_DRAW &&
- !has_pending_tree_) {
+
+ if (!has_pending_tree_ &&
+ commit_state_ == COMMIT_STATE_WAITING_FOR_FIRST_DRAW) {
commit_state_ = COMMIT_STATE_IDLE;
}
- if (texture_state_ == LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD)
- texture_state_ = LAYER_TEXTURE_STATE_UNLOCKED;
-
needs_redraw_ = false;
- draw_if_possible_failed_ = false;
active_tree_needs_first_draw_ = false;
- if (did_swap)
- last_frame_number_swap_performed_ = current_frame_number_;
+ if (did_request_swap)
+ last_frame_number_swap_requested_ = current_frame_number_;
}
void SchedulerStateMachine::UpdateStateOnManageTiles() {
needs_manage_tiles_ = false;
}
-void SchedulerStateMachine::SetMainThreadNeedsLayerTextures() {
- DCHECK(!main_thread_needs_layer_textures_);
- DCHECK_NE(texture_state_, LAYER_TEXTURE_STATE_ACQUIRED_BY_MAIN_THREAD);
- main_thread_needs_layer_textures_ = true;
-}
-
-void SchedulerStateMachine::SetSkipBeginMainFrameToReduceLatency(bool skip) {
- skip_begin_main_frame_to_reduce_latency_ = skip;
+void SchedulerStateMachine::SetSkipNextBeginMainFrameToReduceLatency() {
+ skip_next_begin_main_frame_to_reduce_latency_ = true;
}
-bool SchedulerStateMachine::BeginImplFrameNeeded() const {
- // Proactive BeginImplFrames are bad for the synchronous compositor because we
- // have to draw when we get the BeginImplFrame and could end up drawing many
+bool SchedulerStateMachine::BeginFrameNeeded() const {
+ // Proactive BeginFrames are bad for the synchronous compositor because we
+ // have to draw when we get the BeginFrame and could end up drawing many
// duplicate frames if our new frame isn't ready in time.
// To poll for state with the synchronous compositor without having to draw,
// we rely on ShouldPollForAnticipatedDrawTriggers instead.
- if (!SupportsProactiveBeginImplFrame())
- return BeginImplFrameNeededToDraw();
+ if (!SupportsProactiveBeginFrame())
+ return BeginFrameNeededToAnimateOrDraw();
- return BeginImplFrameNeededToDraw() ||
- ProactiveBeginImplFrameWanted();
+ return BeginFrameNeededToAnimateOrDraw() || ProactiveBeginFrameWanted();
}
bool SchedulerStateMachine::ShouldPollForAnticipatedDrawTriggers() const {
// ShouldPollForAnticipatedDrawTriggers is what we use in place of
- // ProactiveBeginImplFrameWanted when we are using the synchronous
+ // ProactiveBeginFrameWanted when we are using the synchronous
// compositor.
- if (!SupportsProactiveBeginImplFrame()) {
- return !BeginImplFrameNeededToDraw() &&
- ProactiveBeginImplFrameWanted();
+ if (!SupportsProactiveBeginFrame()) {
+ return !BeginFrameNeededToAnimateOrDraw() && ProactiveBeginFrameWanted();
}
// Non synchronous compositors should rely on
- // ProactiveBeginImplFrameWanted to poll for state instead.
+ // ProactiveBeginFrameWanted to poll for state instead.
return false;
}
-bool SchedulerStateMachine::SupportsProactiveBeginImplFrame() const {
- // Both the synchronous compositor and disabled vsync settings
- // make it undesirable to proactively request BeginImplFrames.
- // If this is true, the scheduler should poll.
- return !settings_.using_synchronous_renderer_compositor &&
- settings_.throttle_frame_production;
+// Note: If SupportsProactiveBeginFrame is false, the scheduler should poll
+// for changes in it's draw state so it can request a BeginFrame when it's
+// actually ready.
+bool SchedulerStateMachine::SupportsProactiveBeginFrame() const {
+ // It is undesirable to proactively request BeginFrames if we are
+ // using a synchronous compositor because we *must* draw for every
+ // BeginFrame, which could cause duplicate draws.
+ return !settings_.using_synchronous_renderer_compositor;
}
// These are the cases where we definitely (or almost definitely) have a
-// new frame to draw and can draw.
-bool SchedulerStateMachine::BeginImplFrameNeededToDraw() const {
+// new frame to animate and/or draw and can draw.
+bool SchedulerStateMachine::BeginFrameNeededToAnimateOrDraw() const {
// The output surface is the provider of BeginImplFrames, so we are not going
// to get them even if we ask for them.
if (!HasInitializedOutputSurface())
@@ -841,14 +761,17 @@ bool SchedulerStateMachine::BeginImplFrameNeededToDraw() const {
if (swap_used_incomplete_tile_)
return true;
+ if (needs_animate_)
+ return true;
+
return needs_redraw_;
}
// These are cases where we are very likely to draw soon, but might not
// actually have a new frame to draw when we receive the next BeginImplFrame.
// Proactively requesting the BeginImplFrame helps hide the round trip latency
-// of the SetNeedsBeginImplFrame request that has to go to the Browser.
-bool SchedulerStateMachine::ProactiveBeginImplFrameWanted() const {
+// of the SetNeedsBeginFrame request that has to go to the Browser.
+bool SchedulerStateMachine::ProactiveBeginFrameWanted() const {
// The output surface is the provider of BeginImplFrames,
// so we are not going to get them even if we ask for them.
if (!HasInitializedOutputSurface())
@@ -873,20 +796,20 @@ bool SchedulerStateMachine::ProactiveBeginImplFrameWanted() const {
if (needs_manage_tiles_)
return true;
- // If we just swapped, it's likely that we are going to produce another
- // frame soon. This helps avoid negative glitches in our
- // SetNeedsBeginImplFrame requests, which may propagate to the BeginImplFrame
+ // If we just sent a swap request, it's likely that we are going to produce
+ // another frame soon. This helps avoid negative glitches in our
+ // SetNeedsBeginFrame requests, which may propagate to the BeginImplFrame
// provider and get sampled at an inopportune time, delaying the next
// BeginImplFrame.
- if (last_frame_number_swap_performed_ == current_frame_number_)
+ if (HasRequestedSwapThisFrame())
return true;
return false;
}
void SchedulerStateMachine::OnBeginImplFrame(const BeginFrameArgs& args) {
- current_frame_number_++;
- last_begin_impl_frame_args_ = args;
+ AdvanceCurrentFrameNumber();
+ begin_impl_frame_args_ = args;
DCHECK_EQ(begin_impl_frame_state_, BEGIN_IMPL_FRAME_STATE_IDLE) << *AsValue();
begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING;
}
@@ -913,12 +836,16 @@ void SchedulerStateMachine::OnBeginImplFrameIdle() {
bool SchedulerStateMachine::ShouldTriggerBeginImplFrameDeadlineEarly() const {
// TODO(brianderson): This should take into account multiple commit sources.
- // If we are in the middle of the readback, we won't swap, so there is
- // no reason to trigger the deadline early.
- if (readback_state_ != READBACK_STATE_IDLE)
+ if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME)
return false;
- if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME)
+ // If we've lost the output surface, end the current BeginImplFrame ASAP
+ // so we can start creating the next output surface.
+ if (output_surface_state_ == OUTPUT_SURFACE_LOST)
+ return true;
+
+ // SwapAck throttle the deadline since we wont draw and swap anyway.
+ if (pending_swaps_ >= max_pending_swaps_)
return false;
if (active_tree_needs_first_draw_)
@@ -943,9 +870,14 @@ bool SchedulerStateMachine::ShouldTriggerBeginImplFrameDeadlineEarly() const {
}
bool SchedulerStateMachine::MainThreadIsInHighLatencyMode() const {
+ // If a commit is pending before the previous commit has been drawn, we
+ // are definitely in a high latency mode.
+ if (CommitPending() && (active_tree_needs_first_draw_ || has_pending_tree_))
+ return true;
+
// If we just sent a BeginMainFrame and haven't hit the deadline yet, the main
// thread is in a low latency mode.
- if (last_frame_number_begin_main_frame_sent_ == current_frame_number_ &&
+ if (HasSentBeginMainFrameThisFrame() &&
(begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING ||
begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME))
return false;
@@ -953,8 +885,7 @@ bool SchedulerStateMachine::MainThreadIsInHighLatencyMode() const {
// If there's a commit in progress it must either be from the previous frame
// or it started after the impl thread's deadline. In either case the main
// thread is in high latency mode.
- if (commit_state_ == COMMIT_STATE_FRAME_IN_PROGRESS ||
- commit_state_ == COMMIT_STATE_READY_TO_COMMIT)
+ if (CommitPending())
return true;
// Similarly, if there's a pending tree the main thread is in high latency
@@ -968,11 +899,10 @@ bool SchedulerStateMachine::MainThreadIsInHighLatencyMode() const {
if (begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE) {
// Even if there's a new active tree to draw at the deadline or we've just
- // drawn it, it may have been triggered by a previous BeginImplFrame, in
+ // swapped it, it may have been triggered by a previous BeginImplFrame, in
// which case the main thread is in a high latency mode.
- return (active_tree_needs_first_draw_ ||
- last_frame_number_swap_performed_ == current_frame_number_) &&
- last_frame_number_begin_main_frame_sent_ != current_frame_number_;
+ return (active_tree_needs_first_draw_ || HasSwappedThisFrame()) &&
+ !HasSentBeginMainFrameThisFrame();
}
// If the active tree needs its first draw in any other state, we know the
@@ -981,7 +911,7 @@ bool SchedulerStateMachine::MainThreadIsInHighLatencyMode() const {
}
void SchedulerStateMachine::DidEnterPollForAnticipatedDrawTriggers() {
- current_frame_number_++;
+ AdvanceCurrentFrameNumber();
inside_poll_for_anticipated_draw_triggers_ = true;
}
@@ -995,6 +925,10 @@ void SchedulerStateMachine::SetCanDraw(bool can_draw) { can_draw_ = can_draw; }
void SchedulerStateMachine::SetNeedsRedraw() { needs_redraw_ = true; }
+void SchedulerStateMachine::SetNeedsAnimate() {
+ needs_animate_ = true;
+}
+
void SchedulerStateMachine::SetNeedsManageTiles() {
if (!needs_manage_tiles_) {
TRACE_EVENT0("cc",
@@ -1003,77 +937,88 @@ void SchedulerStateMachine::SetNeedsManageTiles() {
}
}
+void SchedulerStateMachine::SetMaxSwapsPending(int max) {
+ max_pending_swaps_ = max;
+}
+
+void SchedulerStateMachine::DidSwapBuffers() {
+ pending_swaps_++;
+ DCHECK_LE(pending_swaps_, max_pending_swaps_);
+
+ last_frame_number_swap_performed_ = current_frame_number_;
+}
+
void SchedulerStateMachine::SetSwapUsedIncompleteTile(
bool used_incomplete_tile) {
swap_used_incomplete_tile_ = used_incomplete_tile;
}
+void SchedulerStateMachine::DidSwapBuffersComplete() {
+ DCHECK_GT(pending_swaps_, 0);
+ pending_swaps_--;
+}
+
void SchedulerStateMachine::SetSmoothnessTakesPriority(
bool smoothness_takes_priority) {
smoothness_takes_priority_ = smoothness_takes_priority;
}
-void SchedulerStateMachine::DidDrawIfPossibleCompleted(bool success) {
- draw_if_possible_failed_ = !success;
- if (draw_if_possible_failed_) {
- needs_redraw_ = true;
-
- // If we're already in the middle of a redraw, we don't need to
- // restart it.
- if (forced_redraw_state_ != FORCED_REDRAW_STATE_IDLE)
- return;
-
- needs_commit_ = true;
- consecutive_failed_draws_++;
- if (settings_.timeout_and_draw_when_animation_checkerboards &&
- consecutive_failed_draws_ >=
- settings_.maximum_number_of_failed_draws_before_draw_is_forced_) {
- consecutive_failed_draws_ = 0;
- // We need to force a draw, but it doesn't make sense to do this until
- // we've committed and have new textures.
- forced_redraw_state_ = FORCED_REDRAW_STATE_WAITING_FOR_COMMIT;
- }
- } else {
- consecutive_failed_draws_ = 0;
- forced_redraw_state_ = FORCED_REDRAW_STATE_IDLE;
+void SchedulerStateMachine::DidDrawIfPossibleCompleted(DrawResult result) {
+ switch (result) {
+ case INVALID_RESULT:
+ NOTREACHED() << "Uninitialized DrawResult.";
+ break;
+ case DRAW_ABORTED_CANT_DRAW:
+ case DRAW_ABORTED_CONTEXT_LOST:
+ NOTREACHED() << "Invalid return value from DrawAndSwapIfPossible:"
+ << result;
+ break;
+ case DRAW_SUCCESS:
+ consecutive_checkerboard_animations_ = 0;
+ forced_redraw_state_ = FORCED_REDRAW_STATE_IDLE;
+ break;
+ case DRAW_ABORTED_CHECKERBOARD_ANIMATIONS:
+ needs_redraw_ = true;
+
+ // If we're already in the middle of a redraw, we don't need to
+ // restart it.
+ if (forced_redraw_state_ != FORCED_REDRAW_STATE_IDLE)
+ return;
+
+ needs_commit_ = true;
+ consecutive_checkerboard_animations_++;
+ if (settings_.timeout_and_draw_when_animation_checkerboards &&
+ consecutive_checkerboard_animations_ >=
+ settings_.maximum_number_of_failed_draws_before_draw_is_forced_) {
+ consecutive_checkerboard_animations_ = 0;
+ // We need to force a draw, but it doesn't make sense to do this until
+ // we've committed and have new textures.
+ forced_redraw_state_ = FORCED_REDRAW_STATE_WAITING_FOR_COMMIT;
+ }
+ break;
+ case DRAW_ABORTED_MISSING_HIGH_RES_CONTENT:
+ // It's not clear whether this missing content is because of missing
+ // pictures (which requires a commit) or because of memory pressure
+ // removing textures (which might not). To be safe, request a commit
+ // anyway.
+ needs_commit_ = true;
+ break;
}
}
void SchedulerStateMachine::SetNeedsCommit() { needs_commit_ = true; }
-void SchedulerStateMachine::SetNeedsForcedCommitForReadback() {
- // If this is called in READBACK_STATE_IDLE, this is a "first" readback
- // request.
- // If this is called in READBACK_STATE_WAITING_FOR_REPLACEMENT_COMMIT, this
- // is a back-to-back readback request that started before the replacement
- // commit had a chance to land.
- DCHECK(readback_state_ == READBACK_STATE_IDLE ||
- readback_state_ == READBACK_STATE_WAITING_FOR_REPLACEMENT_COMMIT);
-
- // If there is already a commit in progress when we get the readback request
- // (we are in COMMIT_STATE_FRAME_IN_PROGRESS), then we don't need to send a
- // BeginMainFrame for the replacement commit, since there's already a
- // BeginMainFrame behind the readback request. In that case, we can skip
- // READBACK_STATE_NEEDS_BEGIN_MAIN_FRAME and go directly to
- // READBACK_STATE_WAITING_FOR_COMMIT
- if (commit_state_ == COMMIT_STATE_FRAME_IN_PROGRESS)
- readback_state_ = READBACK_STATE_WAITING_FOR_COMMIT;
- else
- readback_state_ = READBACK_STATE_NEEDS_BEGIN_MAIN_FRAME;
-}
-
-void SchedulerStateMachine::FinishCommit() {
- DCHECK(commit_state_ == COMMIT_STATE_FRAME_IN_PROGRESS) << *AsValue();
+void SchedulerStateMachine::NotifyReadyToCommit() {
+ DCHECK(commit_state_ == COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED) << *AsValue();
commit_state_ = COMMIT_STATE_READY_TO_COMMIT;
}
void SchedulerStateMachine::BeginMainFrameAborted(bool did_handle) {
- DCHECK_EQ(commit_state_, COMMIT_STATE_FRAME_IN_PROGRESS);
+ DCHECK_EQ(commit_state_, COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
if (did_handle) {
bool commit_was_aborted = true;
UpdateStateOnCommit(commit_was_aborted);
} else {
- DCHECK_NE(readback_state_, READBACK_STATE_WAITING_FOR_COMMIT);
commit_state_ = COMMIT_STATE_IDLE;
SetNeedsCommit();
}
@@ -1081,7 +1026,8 @@ void SchedulerStateMachine::BeginMainFrameAborted(bool did_handle) {
void SchedulerStateMachine::DidManageTiles() {
needs_manage_tiles_ = false;
- last_frame_number_manage_tiles_called_ = current_frame_number_;
+ // "Fill" the ManageTiles funnel.
+ manage_tiles_funnel_++;
}
void SchedulerStateMachine::DidLoseOutputSurface() {
@@ -1090,7 +1036,6 @@ void SchedulerStateMachine::DidLoseOutputSurface() {
return;
output_surface_state_ = OUTPUT_SURFACE_LOST;
needs_redraw_ = false;
- begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_IDLE;
}
void SchedulerStateMachine::NotifyReadyToActivate() {
@@ -1108,6 +1053,12 @@ void SchedulerStateMachine::DidCreateAndInitializeOutputSurface() {
needs_commit_ = true;
}
did_create_and_initialize_first_output_surface_ = true;
+ pending_swaps_ = 0;
+}
+
+void SchedulerStateMachine::NotifyBeginMainFrameStarted() {
+ DCHECK_EQ(commit_state_, COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
+ commit_state_ = COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED;
}
bool SchedulerStateMachine::HasInitializedOutputSurface() const {
diff --git a/chromium/cc/scheduler/scheduler_state_machine.h b/chromium/cc/scheduler/scheduler_state_machine.h
index 2e61224fb28..a2a8b59e6c6 100644
--- a/chromium/cc/scheduler/scheduler_state_machine.h
+++ b/chromium/cc/scheduler/scheduler_state_machine.h
@@ -12,6 +12,7 @@
#include "base/time/time.h"
#include "cc/base/cc_export.h"
#include "cc/output/begin_frame_args.h"
+#include "cc/scheduler/draw_result.h"
#include "cc/scheduler/scheduler_settings.h"
namespace base {
@@ -59,31 +60,14 @@ class CC_EXPORT SchedulerStateMachine {
enum CommitState {
COMMIT_STATE_IDLE,
- COMMIT_STATE_FRAME_IN_PROGRESS,
+ COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
+ COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED,
COMMIT_STATE_READY_TO_COMMIT,
+ COMMIT_STATE_WAITING_FOR_ACTIVATION,
COMMIT_STATE_WAITING_FOR_FIRST_DRAW,
};
static const char* CommitStateToString(CommitState state);
- enum TextureState {
- LAYER_TEXTURE_STATE_UNLOCKED,
- LAYER_TEXTURE_STATE_ACQUIRED_BY_MAIN_THREAD,
- LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD,
- };
- static const char* TextureStateToString(TextureState state);
-
- enum SynchronousReadbackState {
- READBACK_STATE_IDLE,
- READBACK_STATE_NEEDS_BEGIN_MAIN_FRAME,
- READBACK_STATE_WAITING_FOR_COMMIT,
- READBACK_STATE_WAITING_FOR_ACTIVATION,
- READBACK_STATE_WAITING_FOR_DRAW_AND_READBACK,
- READBACK_STATE_WAITING_FOR_REPLACEMENT_COMMIT,
- READBACK_STATE_WAITING_FOR_REPLACEMENT_ACTIVATION,
- };
- static const char* SynchronousReadbackStateToString(
- SynchronousReadbackState state);
-
enum ForcedRedrawOnTimeoutState {
FORCED_REDRAW_STATE_IDLE,
FORCED_REDRAW_STATE_WAITING_FOR_COMMIT,
@@ -94,15 +78,18 @@ class CC_EXPORT SchedulerStateMachine {
ForcedRedrawOnTimeoutState state);
bool CommitPending() const {
- return commit_state_ == COMMIT_STATE_FRAME_IN_PROGRESS ||
+ return commit_state_ == COMMIT_STATE_BEGIN_MAIN_FRAME_SENT ||
+ commit_state_ == COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED ||
commit_state_ == COMMIT_STATE_READY_TO_COMMIT;
}
+ CommitState commit_state() const { return commit_state_; }
bool RedrawPending() const { return needs_redraw_; }
bool ManageTilesPending() const { return needs_manage_tiles_; }
enum Action {
ACTION_NONE,
+ ACTION_ANIMATE,
ACTION_SEND_BEGIN_MAIN_FRAME,
ACTION_COMMIT,
ACTION_UPDATE_VISIBLE_TILES,
@@ -110,9 +97,7 @@ class CC_EXPORT SchedulerStateMachine {
ACTION_DRAW_AND_SWAP_IF_POSSIBLE,
ACTION_DRAW_AND_SWAP_FORCED,
ACTION_DRAW_AND_SWAP_ABORT,
- ACTION_DRAW_AND_READBACK,
ACTION_BEGIN_OUTPUT_SURFACE_CREATION,
- ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD,
ACTION_MANAGE_TILES,
};
static const char* ActionToString(Action action);
@@ -122,11 +107,9 @@ class CC_EXPORT SchedulerStateMachine {
Action NextAction() const;
void UpdateState(Action action);
- void CheckInvariants();
-
// Indicates whether the impl thread needs a BeginImplFrame callback in order
// to make progress.
- bool BeginImplFrameNeeded() const;
+ bool BeginFrameNeeded() const;
// Indicates that we need to independently poll for new state and actions
// because we can't expect a BeginImplFrame. This is mostly used to avoid
@@ -167,63 +150,71 @@ class CC_EXPORT SchedulerStateMachine {
void SetNeedsRedraw();
bool needs_redraw() const { return needs_redraw_; }
+ void SetNeedsAnimate();
+ bool needs_animate() const { return needs_animate_; }
+
// Indicates that manage-tiles is required. This guarantees another
// ManageTiles will occur shortly (even if no redraw is required).
void SetNeedsManageTiles();
+ // Sets how many swaps can be pending to the OutputSurface.
+ void SetMaxSwapsPending(int max);
+
+ // If the scheduler attempted to draw and swap, this provides feedback
+ // regarding whether or not the swap actually occured. We might skip the
+ // swap when there is not damage, for example.
+ void DidSwapBuffers();
+
// Indicates whether a redraw is required because we are currently rendering
// with a low resolution or checkerboarded tile.
void SetSwapUsedIncompleteTile(bool used_incomplete_tile);
+ // Notification from the OutputSurface that a swap has been consumed.
+ void DidSwapBuffersComplete();
+
// Indicates whether to prioritize animation smoothness over new content
// activation.
void SetSmoothnessTakesPriority(bool smoothness_takes_priority);
+ bool smoothness_takes_priority() const { return smoothness_takes_priority_; }
// Indicates whether ACTION_DRAW_AND_SWAP_IF_POSSIBLE drew to the screen.
- void DidDrawIfPossibleCompleted(bool success);
+ void DidDrawIfPossibleCompleted(DrawResult result);
// Indicates that a new commit flow needs to be performed, either to pull
// updates from the main thread to the impl, or to push deltas from the impl
// thread to main.
void SetNeedsCommit();
- // As SetNeedsCommit(), but ensures the BeginMainFrame will be sent even
- // if we are not visible. After this call we expect to go through
- // the forced commit flow and then return to waiting for a non-forced
- // BeginMainFrame to finish.
- void SetNeedsForcedCommitForReadback();
-
// Call this only in response to receiving an ACTION_SEND_BEGIN_MAIN_FRAME
// from NextAction.
// Indicates that all painting is complete.
- void FinishCommit();
+ void NotifyReadyToCommit();
// Call this only in response to receiving an ACTION_SEND_BEGIN_MAIN_FRAME
// from NextAction if the client rejects the BeginMainFrame message.
// If did_handle is false, then another commit will be retried soon.
void BeginMainFrameAborted(bool did_handle);
- // Request exclusive access to the textures that back single buffered
- // layers on behalf of the main thread. Upon acquisition,
- // ACTION_DRAW_AND_SWAP_IF_POSSIBLE will not draw until the main thread
- // releases the
- // textures to the impl thread by committing the layers.
- void SetMainThreadNeedsLayerTextures();
-
// Set that we can create the first OutputSurface and start the scheduler.
void SetCanStart() { can_start_ = true; }
- void SetSkipBeginMainFrameToReduceLatency(bool skip);
+ void SetSkipNextBeginMainFrameToReduceLatency();
// Indicates whether drawing would, at this time, make sense.
// CanDraw can be used to suppress flashes or checkerboarding
// when such behavior would be undesirable.
void SetCanDraw(bool can);
+ // Indicates that scheduled BeginMainFrame is started.
+ void NotifyBeginMainFrameStarted();
+
// Indicates that the pending tree is ready for activation.
void NotifyReadyToActivate();
bool has_pending_tree() const { return has_pending_tree_; }
+ bool active_tree_needs_first_draw() const {
+ return active_tree_needs_first_draw_;
+ }
void DidManageTiles();
void DidLoseOutputSurface();
@@ -233,35 +224,38 @@ class CC_EXPORT SchedulerStateMachine {
// True if we need to abort draws to make forward progress.
bool PendingDrawsShouldBeAborted() const;
- bool SupportsProactiveBeginImplFrame() const;
+ bool SupportsProactiveBeginFrame() const;
- bool IsCommitStateWaiting() const;
+ void SetContinuousPainting(bool continuous_painting) {
+ continuous_painting_ = continuous_painting;
+ }
protected:
- bool BeginImplFrameNeededToDraw() const;
- bool ProactiveBeginImplFrameWanted() const;
+ bool BeginFrameNeededToAnimateOrDraw() const;
+ bool ProactiveBeginFrameWanted() const;
// True if we need to force activations to make forward progress.
bool PendingActivationsShouldBeForced() const;
+ bool ShouldAnimate() const;
bool ShouldBeginOutputSurfaceCreation() const;
bool ShouldDrawForced() const;
bool ShouldDraw() const;
bool ShouldActivatePendingTree() const;
- bool ShouldAcquireLayerTexturesForMainThread() const;
bool ShouldUpdateVisibleTiles() const;
bool ShouldSendBeginMainFrame() const;
bool ShouldCommit() const;
bool ShouldManageTiles() const;
+ void AdvanceCurrentFrameNumber();
bool HasSentBeginMainFrameThisFrame() const;
- bool HasScheduledManageTilesThisFrame() const;
bool HasUpdatedVisibleTilesThisFrame() const;
+ bool HasRequestedSwapThisFrame() const;
bool HasSwappedThisFrame() const;
void UpdateStateOnCommit(bool commit_was_aborted);
void UpdateStateOnActivation();
- void UpdateStateOnDraw(bool did_swap);
+ void UpdateStateOnDraw(bool did_request_swap);
void UpdateStateOnManageTiles();
const SchedulerSettings settings_;
@@ -269,25 +263,31 @@ class CC_EXPORT SchedulerStateMachine {
OutputSurfaceState output_surface_state_;
BeginImplFrameState begin_impl_frame_state_;
CommitState commit_state_;
- TextureState texture_state_;
ForcedRedrawOnTimeoutState forced_redraw_state_;
- SynchronousReadbackState readback_state_;
- BeginFrameArgs last_begin_impl_frame_args_;
+ BeginFrameArgs begin_impl_frame_args_;
int commit_count_;
int current_frame_number_;
+ int last_frame_number_animate_performed_;
int last_frame_number_swap_performed_;
+ int last_frame_number_swap_requested_;
int last_frame_number_begin_main_frame_sent_;
int last_frame_number_update_visible_tiles_was_called_;
- int last_frame_number_manage_tiles_called_;
- int consecutive_failed_draws_;
+ // manage_tiles_funnel_ is "filled" each time ManageTiles is called
+ // and "drained" on each BeginImplFrame. If the funnel gets too full,
+ // we start throttling ACTION_MANAGE_TILES such that we average one
+ // ManageTile per BeginImplFrame.
+ int manage_tiles_funnel_;
+ int consecutive_checkerboard_animations_;
+ int max_pending_swaps_;
+ int pending_swaps_;
bool needs_redraw_;
+ bool needs_animate_;
bool needs_manage_tiles_;
bool swap_used_incomplete_tile_;
bool needs_commit_;
- bool main_thread_needs_layer_textures_;
bool inside_poll_for_anticipated_draw_triggers_;
bool visible_;
bool can_start_;
@@ -295,10 +295,11 @@ class CC_EXPORT SchedulerStateMachine {
bool has_pending_tree_;
bool pending_tree_is_ready_for_activation_;
bool active_tree_needs_first_draw_;
- bool draw_if_possible_failed_;
bool did_create_and_initialize_first_output_surface_;
bool smoothness_takes_priority_;
+ bool skip_next_begin_main_frame_to_reduce_latency_;
bool skip_begin_main_frame_to_reduce_latency_;
+ bool continuous_painting_;
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 67925a059b3..b5834241d8c 100644
--- a/chromium/cc/scheduler/scheduler_state_machine_unittest.cc
+++ b/chromium/cc/scheduler/scheduler_state_machine_unittest.cc
@@ -5,17 +5,13 @@
#include "cc/scheduler/scheduler_state_machine.h"
#include "cc/scheduler/scheduler.h"
+#include "cc/test/begin_frame_args_test.h"
#include "testing/gtest/include/gtest/gtest.h"
#define EXPECT_ACTION_UPDATE_STATE(action) \
EXPECT_EQ(action, state.NextAction()) << *state.AsValue(); \
if (action == SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE || \
action == SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED) { \
- if (SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_FIRST_DRAW == \
- state.CommitState() && \
- SchedulerStateMachine::OUTPUT_SURFACE_ACTIVE != \
- state.output_surface_state()) \
- return; \
EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE, \
state.begin_impl_frame_state()) \
<< *state.AsValue(); \
@@ -42,9 +38,11 @@ const SchedulerStateMachine::BeginImplFrameState all_begin_impl_frame_states[] =
const SchedulerStateMachine::CommitState all_commit_states[] = {
SchedulerStateMachine::COMMIT_STATE_IDLE,
- SchedulerStateMachine::COMMIT_STATE_FRAME_IN_PROGRESS,
+ SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
+ SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED,
SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT,
- SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_FIRST_DRAW, };
+ SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_ACTIVATION,
+ SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_FIRST_DRAW};
// Exposes the protected state fields of the SchedulerStateMachine for testing
class StateMachine : public SchedulerStateMachine {
@@ -82,21 +80,12 @@ class StateMachine : public SchedulerStateMachine {
void SetNeedsForcedRedrawForTimeout(bool b) {
forced_redraw_state_ = FORCED_REDRAW_STATE_WAITING_FOR_COMMIT;
- commit_state_ = COMMIT_STATE_WAITING_FOR_FIRST_DRAW;
+ active_tree_needs_first_draw_ = true;
}
bool NeedsForcedRedrawForTimeout() const {
return forced_redraw_state_ != FORCED_REDRAW_STATE_IDLE;
}
- void SetNeedsForcedRedrawForReadback() {
- readback_state_ = READBACK_STATE_WAITING_FOR_DRAW_AND_READBACK;
- commit_state_ = COMMIT_STATE_WAITING_FOR_FIRST_DRAW;
- }
-
- bool NeedsForcedRedrawForReadback() const {
- return readback_state_ != READBACK_STATE_IDLE;
- }
-
void SetActiveTreeNeedsFirstDraw(bool needs_first_draw) {
active_tree_needs_first_draw_ = needs_first_draw;
}
@@ -107,6 +96,10 @@ class StateMachine : public SchedulerStateMachine {
bool PendingActivationsShouldBeForced() const {
return SchedulerStateMachine::PendingActivationsShouldBeForced();
}
+
+ void SetHasPendingTree(bool has_pending_tree) {
+ has_pending_tree_ = has_pending_tree;
+ }
};
TEST(SchedulerStateMachineTest, TestNextActionBeginsMainFrameIfNeeded) {
@@ -123,11 +116,11 @@ TEST(SchedulerStateMachineTest, TestNextActionBeginsMainFrameIfNeeded) {
state.SetNeedsRedraw(false);
state.SetVisible(true);
- EXPECT_FALSE(state.BeginImplFrameNeeded());
+ EXPECT_FALSE(state.BeginFrameNeeded());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- EXPECT_FALSE(state.BeginImplFrameNeeded());
- state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting());
+ EXPECT_FALSE(state.BeginFrameNeeded());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
@@ -139,12 +132,13 @@ TEST(SchedulerStateMachineTest, TestNextActionBeginsMainFrameIfNeeded) {
state.SetCommitState(SchedulerStateMachine::COMMIT_STATE_IDLE);
state.SetNeedsRedraw(false);
state.SetVisible(true);
+ state.SetNeedsCommit();
- EXPECT_FALSE(state.BeginImplFrameNeeded());
+ EXPECT_FALSE(state.BeginFrameNeeded());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- EXPECT_FALSE(state.BeginImplFrameNeeded());
- state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting());
+ EXPECT_FALSE(state.BeginFrameNeeded());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
}
@@ -154,9 +148,17 @@ TEST(SchedulerStateMachineTest, TestNextActionBeginsMainFrameIfNeeded) {
StateMachine state(default_scheduler_settings);
state.SetCommitState(SchedulerStateMachine::COMMIT_STATE_IDLE);
state.SetCanStart();
+ state.UpdateState(state.NextAction());
+ state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
state.SetNeedsRedraw(false);
state.SetVisible(true);
- EXPECT_FALSE(state.BeginImplFrameNeeded());
+ state.SetNeedsCommit();
+
+ EXPECT_TRUE(state.BeginFrameNeeded());
+
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
}
// Begin the frame, make sure needs_commit and commit_state update correctly.
@@ -167,14 +169,163 @@ TEST(SchedulerStateMachineTest, TestNextActionBeginsMainFrameIfNeeded) {
state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
state.SetVisible(true);
state.UpdateState(SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_FRAME_IN_PROGRESS,
+ EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
state.CommitState());
EXPECT_FALSE(state.NeedsCommit());
}
}
+// Explicitly test main_frame_before_draw_enabled = false
+TEST(SchedulerStateMachineTest, MainFrameBeforeDrawDisabled) {
+ SchedulerSettings scheduler_settings;
+ scheduler_settings.impl_side_painting = true;
+ scheduler_settings.main_frame_before_draw_enabled = false;
+ StateMachine state(scheduler_settings);
+ state.SetCommitState(SchedulerStateMachine::COMMIT_STATE_IDLE);
+ state.SetCanStart();
+ state.UpdateState(state.NextAction());
+ state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
+ state.SetNeedsRedraw(false);
+ state.SetVisible(true);
+ state.SetCanDraw(true);
+ state.SetNeedsCommit();
+
+ EXPECT_TRUE(state.BeginFrameNeeded());
+
+ // Commit to the pending tree.
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ state.NotifyBeginMainFrameStarted();
+ state.NotifyReadyToCommit();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ EXPECT_EQ(state.CommitState(),
+ SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_FIRST_DRAW);
+
+ state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ EXPECT_EQ(state.CommitState(),
+ SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_FIRST_DRAW);
+
+ // Verify that the next commit doesn't start until the previous
+ // commit has been drawn.
+ state.SetNeedsCommit();
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
+ // Make sure that a draw of the active tree doesn't spuriously advance
+ // the commit state and unblock the next commit.
+ state.SetNeedsRedraw(true);
+ state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ EXPECT_EQ(state.CommitState(),
+ SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_FIRST_DRAW);
+ EXPECT_TRUE(state.has_pending_tree());
+
+ // Verify NotifyReadyToActivate unblocks activation, draw, and
+ // commit in that order.
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+
+ state.NotifyReadyToActivate();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_ACTIVATE_PENDING_TREE);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ EXPECT_EQ(state.CommitState(),
+ SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_FIRST_DRAW);
+
+ EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineEarly());
+ state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
+ state.DidSwapBuffers();
+ state.DidSwapBuffersComplete();
+ EXPECT_EQ(state.CommitState(), SchedulerStateMachine::COMMIT_STATE_IDLE);
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ EXPECT_EQ(state.CommitState(),
+ SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
+
+ state.NotifyBeginMainFrameStarted();
+ state.NotifyReadyToCommit();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ EXPECT_EQ(state.CommitState(),
+ SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_FIRST_DRAW);
+}
+
+// Explicitly test main_frame_before_activation_enabled = true
+TEST(SchedulerStateMachineTest, MainFrameBeforeActivationEnabled) {
+ SchedulerSettings scheduler_settings;
+ scheduler_settings.impl_side_painting = true;
+ scheduler_settings.main_frame_before_activation_enabled = true;
+ StateMachine state(scheduler_settings);
+ state.SetCommitState(SchedulerStateMachine::COMMIT_STATE_IDLE);
+ state.SetCanStart();
+ state.UpdateState(state.NextAction());
+ state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
+ state.SetNeedsRedraw(false);
+ state.SetVisible(true);
+ state.SetCanDraw(true);
+ state.SetNeedsCommit();
+
+ EXPECT_TRUE(state.BeginFrameNeeded());
+
+ // Commit to the pending tree.
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
+ state.NotifyBeginMainFrameStarted();
+ state.NotifyReadyToCommit();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ EXPECT_EQ(state.CommitState(), SchedulerStateMachine::COMMIT_STATE_IDLE);
+
+ state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
+ // Verify that the next commit starts while there is still a pending tree.
+ state.SetNeedsCommit();
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
+ // Verify the pending commit doesn't overwrite the pending
+ // tree until the pending tree has been activated.
+ state.NotifyBeginMainFrameStarted();
+ state.NotifyReadyToCommit();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
+ // Verify NotifyReadyToActivate unblocks activation, draw, and
+ // commit in that order.
+ state.NotifyReadyToActivate();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_ACTIVATE_PENDING_TREE);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
+ EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineEarly());
+ state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
+ state.DidSwapBuffers();
+ state.DidSwapBuffersComplete();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ EXPECT_EQ(state.CommitState(), SchedulerStateMachine::COMMIT_STATE_IDLE);
+}
+
TEST(SchedulerStateMachineTest,
- TestFailedDrawSetsNeedsCommitAndDoesNotDrawAgain) {
+ TestFailedDrawForAnimationCheckerboardSetsNeedsCommitAndDoesNotDrawAgain) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
state.SetCanStart();
@@ -184,28 +335,65 @@ TEST(SchedulerStateMachineTest,
state.SetCanDraw(true);
state.SetNeedsRedraw(true);
EXPECT_TRUE(state.RedrawPending());
- EXPECT_TRUE(state.BeginImplFrameNeeded());
- state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting());
+ EXPECT_TRUE(state.BeginFrameNeeded());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
// We're drawing now.
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
+ state.DidSwapBuffers();
+ state.DidSwapBuffersComplete();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
EXPECT_FALSE(state.RedrawPending());
EXPECT_FALSE(state.CommitPending());
// Failing the draw makes us require a commit.
- state.DidDrawIfPossibleCompleted(false);
- state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting());
+ state.DidDrawIfPossibleCompleted(DRAW_ABORTED_CHECKERBOARD_ANIMATIONS);
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_TRUE(state.RedrawPending());
EXPECT_TRUE(state.CommitPending());
}
+TEST(SchedulerStateMachineTest, TestFailedDrawForMissingHighResNeedsCommit) {
+ SchedulerSettings default_scheduler_settings;
+ StateMachine state(default_scheduler_settings);
+ state.SetCanStart();
+ state.UpdateState(state.NextAction());
+ state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
+ state.SetVisible(true);
+ state.SetCanDraw(true);
+ state.SetNeedsRedraw(true);
+ EXPECT_TRUE(state.RedrawPending());
+ EXPECT_TRUE(state.BeginFrameNeeded());
+
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
+ state.DidSwapBuffers();
+ state.DidSwapBuffersComplete();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ EXPECT_FALSE(state.RedrawPending());
+ EXPECT_FALSE(state.CommitPending());
+
+ // Missing high res content requires a commit (but not a redraw)
+ state.DidDrawIfPossibleCompleted(DRAW_ABORTED_MISSING_HIGH_RES_CONTENT);
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
+ EXPECT_FALSE(state.RedrawPending());
+ EXPECT_TRUE(state.CommitPending());
+}
+
TEST(SchedulerStateMachineTest,
TestsetNeedsRedrawDuringFailedDrawDoesNotRemoveNeedsRedraw) {
SchedulerSettings default_scheduler_settings;
@@ -218,14 +406,17 @@ TEST(SchedulerStateMachineTest,
state.SetCanDraw(true);
state.SetNeedsRedraw(true);
EXPECT_TRUE(state.RedrawPending());
- EXPECT_TRUE(state.BeginImplFrameNeeded());
- state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting());
+ EXPECT_TRUE(state.BeginFrameNeeded());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
// We're drawing now.
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
+ state.DidSwapBuffers();
+ state.DidSwapBuffersComplete();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
EXPECT_FALSE(state.RedrawPending());
EXPECT_FALSE(state.CommitPending());
@@ -235,19 +426,21 @@ TEST(SchedulerStateMachineTest,
state.SetNeedsRedraw(true);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- // Failing the draw makes us require a commit.
- state.DidDrawIfPossibleCompleted(false);
- state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting());
+ // Failing the draw for animation checkerboards makes us require a commit.
+ state.DidDrawIfPossibleCompleted(DRAW_ABORTED_CHECKERBOARD_ANIMATIONS);
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_TRUE(state.RedrawPending());
}
-void TestFailedDrawsWillEventuallyForceADrawAfterTheNextCommit(
- bool deadline_scheduling_enabled) {
+void TestFailedDrawsEventuallyForceDrawAfterNextCommit(
+ bool main_frame_before_draw_enabled) {
SchedulerSettings scheduler_settings;
+ scheduler_settings.main_frame_before_draw_enabled =
+ main_frame_before_draw_enabled;
scheduler_settings.maximum_number_of_failed_draws_before_draw_is_forced_ = 1;
- scheduler_settings.deadline_scheduling_enabled = deadline_scheduling_enabled;
StateMachine state(scheduler_settings);
state.SetCanStart();
state.UpdateState(state.NextAction());
@@ -257,69 +450,70 @@ void TestFailedDrawsWillEventuallyForceADrawAfterTheNextCommit(
// Start a commit.
state.SetNeedsCommit();
- if (!deadline_scheduling_enabled) {
- EXPECT_ACTION_UPDATE_STATE(
- SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
- }
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting());
- if (deadline_scheduling_enabled) {
- EXPECT_ACTION_UPDATE_STATE(
- SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
- }
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
EXPECT_TRUE(state.CommitPending());
// Then initiate a draw.
state.SetNeedsRedraw(true);
state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
// Fail the draw.
- state.DidDrawIfPossibleCompleted(false);
+ state.DidDrawIfPossibleCompleted(DRAW_ABORTED_CHECKERBOARD_ANIMATIONS);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- EXPECT_TRUE(state.BeginImplFrameNeeded());
+ EXPECT_TRUE(state.BeginFrameNeeded());
EXPECT_TRUE(state.RedrawPending());
// But the commit is ongoing.
EXPECT_TRUE(state.CommitPending());
// Finish the commit. Note, we should not yet be forcing a draw, but should
// continue the commit as usual.
- state.FinishCommit();
+ state.NotifyBeginMainFrameStarted();
+ state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
EXPECT_TRUE(state.RedrawPending());
// The redraw should be forced at the end of the next BeginImplFrame.
- state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
+ if (main_frame_before_draw_enabled) {
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
+ }
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED);
+ state.DidSwapBuffers();
+ state.DidSwapBuffersComplete();
}
TEST(SchedulerStateMachineTest,
- TestFailedDrawsWillEventuallyForceADrawAfterTheNextCommit) {
- bool deadline_scheduling_enabled = false;
- TestFailedDrawsWillEventuallyForceADrawAfterTheNextCommit(
- deadline_scheduling_enabled);
+ TestFailedDrawsEventuallyForceDrawAfterNextCommit) {
+ bool main_frame_before_draw_enabled = false;
+ TestFailedDrawsEventuallyForceDrawAfterNextCommit(
+ main_frame_before_draw_enabled);
}
TEST(SchedulerStateMachineTest,
- TestFailedDrawsWillEventuallyForceADrawAfterTheNextCommit_Deadline) {
- bool deadline_scheduling_enabled = true;
- TestFailedDrawsWillEventuallyForceADrawAfterTheNextCommit(
- deadline_scheduling_enabled);
+ TestFailedDrawsEventuallyForceDrawAfterNextCommit_CommitBeforeDraw) {
+ bool main_frame_before_draw_enabled = true;
+ TestFailedDrawsEventuallyForceDrawAfterNextCommit(
+ main_frame_before_draw_enabled);
}
-void TestFailedDrawsDoNotRestartForcedDraw(
- bool deadline_scheduling_enabled) {
+TEST(SchedulerStateMachineTest, TestFailedDrawsDoNotRestartForcedDraw) {
SchedulerSettings scheduler_settings;
- int drawLimit = 1;
+ int draw_limit = 1;
scheduler_settings.maximum_number_of_failed_draws_before_draw_is_forced_ =
- drawLimit;
- scheduler_settings.deadline_scheduling_enabled = deadline_scheduling_enabled;
+ draw_limit;
scheduler_settings.impl_side_painting = true;
StateMachine state(scheduler_settings);
state.SetCanStart();
@@ -330,39 +524,34 @@ void TestFailedDrawsDoNotRestartForcedDraw(
// Start a commit.
state.SetNeedsCommit();
- if (!deadline_scheduling_enabled) {
- EXPECT_ACTION_UPDATE_STATE(
- SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
- }
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting());
- if (deadline_scheduling_enabled) {
- EXPECT_ACTION_UPDATE_STATE(
- SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
- }
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
EXPECT_TRUE(state.CommitPending());
// Then initiate a draw.
state.SetNeedsRedraw(true);
state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
// Fail the draw enough times to force a redraw,
// then once more for good measure.
- for (int i = 0; i < drawLimit; ++i)
- state.DidDrawIfPossibleCompleted(false);
- state.DidDrawIfPossibleCompleted(false);
+ for (int i = 0; i < draw_limit + 1; ++i)
+ state.DidDrawIfPossibleCompleted(DRAW_ABORTED_CHECKERBOARD_ANIMATIONS);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- EXPECT_TRUE(state.BeginImplFrameNeeded());
+ EXPECT_TRUE(state.BeginFrameNeeded());
EXPECT_TRUE(state.RedrawPending());
// But the commit is ongoing.
EXPECT_TRUE(state.CommitPending());
EXPECT_TRUE(state.ForcedRedrawState() ==
SchedulerStateMachine::FORCED_REDRAW_STATE_WAITING_FOR_COMMIT);
- state.FinishCommit();
+ state.NotifyBeginMainFrameStarted();
+ state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
EXPECT_TRUE(state.RedrawPending());
@@ -374,28 +563,13 @@ void TestFailedDrawsDoNotRestartForcedDraw(
// After failing additional draws, we should still be in a forced
// redraw, but not back in WAITING_FOR_COMMIT.
- for (int i = 0; i < drawLimit; ++i)
- state.DidDrawIfPossibleCompleted(false);
- state.DidDrawIfPossibleCompleted(false);
+ for (int i = 0; i < draw_limit + 1; ++i)
+ state.DidDrawIfPossibleCompleted(DRAW_ABORTED_CHECKERBOARD_ANIMATIONS);
EXPECT_TRUE(state.RedrawPending());
EXPECT_TRUE(state.ForcedRedrawState() ==
SchedulerStateMachine::FORCED_REDRAW_STATE_WAITING_FOR_ACTIVATION);
}
-TEST(SchedulerStateMachineTest,
- TestFailedDrawsDoNotRestartForcedDraw) {
- bool deadline_scheduling_enabled = false;
- TestFailedDrawsDoNotRestartForcedDraw(
- deadline_scheduling_enabled);
-}
-
-TEST(SchedulerStateMachineTest,
- TestFailedDrawsDoNotRestartForcedDraw_Deadline) {
- bool deadline_scheduling_enabled = true;
- TestFailedDrawsDoNotRestartForcedDraw(
- deadline_scheduling_enabled);
-}
-
TEST(SchedulerStateMachineTest, TestFailedDrawIsRetriedInNextBeginImplFrame) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
@@ -407,24 +581,26 @@ TEST(SchedulerStateMachineTest, TestFailedDrawIsRetriedInNextBeginImplFrame) {
// Start a draw.
state.SetNeedsRedraw(true);
- EXPECT_TRUE(state.BeginImplFrameNeeded());
- state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting());
+ EXPECT_TRUE(state.BeginFrameNeeded());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
EXPECT_TRUE(state.RedrawPending());
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
- // Fail the draw
- state.DidDrawIfPossibleCompleted(false);
+ // Failing the draw for animation checkerboards makes us require a commit.
+ state.DidDrawIfPossibleCompleted(DRAW_ABORTED_CHECKERBOARD_ANIMATIONS);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
EXPECT_TRUE(state.RedrawPending());
// We should not be trying to draw again now, but we have a commit pending.
- EXPECT_TRUE(state.BeginImplFrameNeeded());
- state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting());
+ EXPECT_TRUE(state.BeginFrameNeeded());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// We should try to draw again at the end of the next BeginImplFrame on
@@ -432,6 +608,8 @@ TEST(SchedulerStateMachineTest, TestFailedDrawIsRetriedInNextBeginImplFrame) {
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
+ state.DidSwapBuffers();
+ state.DidSwapBuffersComplete();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
}
@@ -446,14 +624,17 @@ TEST(SchedulerStateMachineTest, TestDoestDrawTwiceInSameFrame) {
state.SetNeedsRedraw(true);
// Draw the first frame.
- EXPECT_TRUE(state.BeginImplFrameNeeded());
- state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting());
+ EXPECT_TRUE(state.BeginFrameNeeded());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
- state.DidDrawIfPossibleCompleted(true);
+ state.DidSwapBuffers();
+ state.DidDrawIfPossibleCompleted(DRAW_SUCCESS);
+ state.DidSwapBuffersComplete();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// Before the next BeginImplFrame, set needs redraw again.
@@ -462,19 +643,22 @@ TEST(SchedulerStateMachineTest, TestDoestDrawTwiceInSameFrame) {
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// Move to another frame. This should now draw.
- EXPECT_TRUE(state.BeginImplFrameNeeded());
- state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting());
+ EXPECT_TRUE(state.BeginFrameNeeded());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
- state.DidDrawIfPossibleCompleted(true);
+ state.DidSwapBuffers();
+ state.DidDrawIfPossibleCompleted(DRAW_SUCCESS);
+ state.DidSwapBuffersComplete();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// We just swapped, so we should proactively request another BeginImplFrame.
- EXPECT_TRUE(state.BeginImplFrameNeeded());
+ EXPECT_TRUE(state.BeginFrameNeeded());
}
TEST(SchedulerStateMachineTest, TestNextActionDrawsOnBeginImplFrame) {
@@ -512,60 +696,38 @@ TEST(SchedulerStateMachineTest, TestNextActionDrawsOnBeginImplFrame) {
}
}
- // When in BeginImplFrame deadline we should always draw for SetNeedsRedraw or
- // SetNeedsForcedRedrawForReadback have been called... except if we're
- // ready to commit, in which case we expect a commit first.
+ // When in BeginImplFrame deadline we should always draw for SetNeedsRedraw
+ // except if we're ready to commit, in which case we expect a commit first.
for (size_t i = 0; i < num_commit_states; ++i) {
- for (size_t j = 0; j < 2; ++j) {
- bool request_readback = j;
+ StateMachine state(default_scheduler_settings);
+ state.SetCanStart();
+ state.UpdateState(state.NextAction());
+ state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
+ state.SetCanDraw(true);
+ state.SetCommitState(all_commit_states[i]);
+ state.SetBeginImplFrameState(
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE);
- // Skip invalid states
- if (request_readback &&
- (SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_FIRST_DRAW !=
- all_commit_states[i]))
- continue;
+ state.SetNeedsRedraw(true);
+ state.SetVisible(true);
- StateMachine state(default_scheduler_settings);
- state.SetCanStart();
+ SchedulerStateMachine::Action expected_action;
+ if (all_commit_states[i] ==
+ SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT) {
+ expected_action = SchedulerStateMachine::ACTION_COMMIT;
+ } else {
+ expected_action = SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE;
+ EXPECT_EQ(state.NextAction(), SchedulerStateMachine::ACTION_ANIMATE)
+ << *state.AsValue();
state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetCanDraw(true);
- state.SetCommitState(all_commit_states[i]);
- state.SetBeginImplFrameState(
- SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE);
- if (request_readback) {
- state.SetNeedsForcedRedrawForReadback();
- } else {
- state.SetNeedsRedraw(true);
- state.SetVisible(true);
- }
+ }
- SchedulerStateMachine::Action expected_action;
- if (all_commit_states[i] ==
- SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT) {
- expected_action = SchedulerStateMachine::ACTION_COMMIT;
- } else if (request_readback) {
- if (all_commit_states[i] ==
- SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_FIRST_DRAW)
- expected_action = SchedulerStateMachine::ACTION_DRAW_AND_READBACK;
- else
- expected_action = SchedulerStateMachine::ACTION_NONE;
- } else {
- expected_action =
- SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE;
- }
+ // Case 1: needs_commit=false.
+ EXPECT_EQ(state.NextAction(), expected_action) << *state.AsValue();
- // Case 1: needs_commit=false.
- EXPECT_NE(state.BeginImplFrameNeeded(), request_readback)
- << *state.AsValue();
- EXPECT_EQ(expected_action, state.NextAction()) << *state.AsValue();
-
- // Case 2: needs_commit=true.
- state.SetNeedsCommit();
- EXPECT_NE(state.BeginImplFrameNeeded(), request_readback)
- << *state.AsValue();
- EXPECT_EQ(expected_action, state.NextAction()) << *state.AsValue();
- }
+ // Case 2: needs_commit=true.
+ state.SetNeedsCommit();
+ EXPECT_EQ(state.NextAction(), expected_action) << *state.AsValue();
}
}
@@ -618,7 +780,7 @@ TEST(SchedulerStateMachineTest, TestCanRedraw_StopsDraw) {
state.SetVisible(false);
state.SetNeedsRedraw(true);
if (j == 1)
- state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
state.SetCanDraw(false);
EXPECT_NE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE,
@@ -635,28 +797,29 @@ TEST(SchedulerStateMachineTest,
state.UpdateState(state.NextAction());
state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetCommitState(
- SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_FIRST_DRAW);
state.SetActiveTreeNeedsFirstDraw(true);
state.SetNeedsCommit();
state.SetNeedsRedraw(true);
state.SetVisible(true);
state.SetCanDraw(false);
- state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- state.FinishCommit();
+ state.NotifyBeginMainFrameStarted();
+ state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
}
-TEST(SchedulerStateMachineTest, TestsetNeedsCommitIsNotLost) {
- SchedulerSettings default_scheduler_settings;
- StateMachine state(default_scheduler_settings);
+void TestSetNeedsCommitIsNotLost(bool main_frame_before_draw_enabled) {
+ SchedulerSettings scheduler_settings;
+ scheduler_settings.main_frame_before_draw_enabled =
+ main_frame_before_draw_enabled;
+ StateMachine state(scheduler_settings);
state.SetCanStart();
state.UpdateState(state.NextAction());
state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
@@ -664,13 +827,13 @@ TEST(SchedulerStateMachineTest, TestsetNeedsCommitIsNotLost) {
state.SetVisible(true);
state.SetCanDraw(true);
- EXPECT_TRUE(state.BeginImplFrameNeeded());
+ EXPECT_TRUE(state.BeginFrameNeeded());
// Begin the frame.
- state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_FRAME_IN_PROGRESS,
+ EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
state.CommitState());
// Now, while the frame is in progress, set another commit.
@@ -678,7 +841,8 @@ TEST(SchedulerStateMachineTest, TestsetNeedsCommitIsNotLost) {
EXPECT_TRUE(state.NeedsCommit());
// Let the frame finish.
- state.FinishCommit();
+ state.NotifyBeginMainFrameStarted();
+ state.NotifyReadyToCommit();
EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT,
state.CommitState());
@@ -702,27 +866,46 @@ TEST(SchedulerStateMachineTest, TestsetNeedsCommitIsNotLost) {
state.begin_impl_frame_state());
EXPECT_EQ(SchedulerStateMachine::ACTION_COMMIT, state.NextAction());
- state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING,
state.begin_impl_frame_state());
EXPECT_EQ(SchedulerStateMachine::ACTION_COMMIT, state.NextAction());
- // Commit and make sure we draw on next BeginImplFrame
+ // Finish the commit, then make sure we start the next commit immediately
+ // and draw on the next BeginImplFrame.
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
+ if (main_frame_before_draw_enabled) {
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
+ }
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
state.OnBeginImplFrameDeadline();
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_FIRST_DRAW,
- state.CommitState());
- EXPECT_ACTION_UPDATE_STATE(
- SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
- state.DidDrawIfPossibleCompleted(true);
- // Verify that another commit will start immediately after draw.
+ EXPECT_TRUE(state.active_tree_needs_first_draw());
EXPECT_ACTION_UPDATE_STATE(
- SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
+ SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
+ state.DidSwapBuffers();
+ state.DidDrawIfPossibleCompleted(DRAW_SUCCESS);
+ state.DidSwapBuffersComplete();
+ if (!main_frame_before_draw_enabled) {
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
+ }
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
}
+TEST(SchedulerStateMachineTest, TestSetNeedsCommitIsNotLost) {
+ bool main_frame_before_draw_enabled = false;
+ TestSetNeedsCommitIsNotLost(main_frame_before_draw_enabled);
+}
+
+TEST(SchedulerStateMachineTest, TestSetNeedsCommitIsNotLost_CommitBeforeDraw) {
+ bool main_frame_before_draw_enabled = true;
+ TestSetNeedsCommitIsNotLost(main_frame_before_draw_enabled);
+}
+
TEST(SchedulerStateMachineTest, TestFullCycle) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
@@ -736,23 +919,23 @@ TEST(SchedulerStateMachineTest, TestFullCycle) {
state.SetNeedsCommit();
// Begin the frame.
- state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_FRAME_IN_PROGRESS,
+ EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
state.CommitState());
EXPECT_FALSE(state.NeedsCommit());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// Tell the scheduler the frame finished.
- state.FinishCommit();
+ state.NotifyBeginMainFrameStarted();
+ state.NotifyReadyToCommit();
EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT,
state.CommitState());
// Commit.
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_FIRST_DRAW,
- state.CommitState());
+ EXPECT_TRUE(state.active_tree_needs_first_draw());
EXPECT_TRUE(state.needs_redraw());
// Expect to do nothing until BeginImplFrame deadline
@@ -760,9 +943,12 @@ TEST(SchedulerStateMachineTest, TestFullCycle) {
// At BeginImplFrame deadline, draw.
state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
- state.DidDrawIfPossibleCompleted(true);
+ state.DidSwapBuffers();
+ state.DidDrawIfPossibleCompleted(DRAW_SUCCESS);
+ state.DidSwapBuffersComplete();
// Should be synchronized, no draw needed, no action needed.
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -783,10 +969,10 @@ TEST(SchedulerStateMachineTest, TestFullCycleWithCommitRequestInbetween) {
state.SetNeedsCommit();
// Begin the frame.
- state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_FRAME_IN_PROGRESS,
+ EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
state.CommitState());
EXPECT_FALSE(state.NeedsCommit());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -796,14 +982,14 @@ TEST(SchedulerStateMachineTest, TestFullCycleWithCommitRequestInbetween) {
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// Tell the scheduler the frame finished.
- state.FinishCommit();
+ state.NotifyBeginMainFrameStarted();
+ state.NotifyReadyToCommit();
EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT,
state.CommitState());
// First commit.
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_FIRST_DRAW,
- state.CommitState());
+ EXPECT_TRUE(state.active_tree_needs_first_draw());
EXPECT_TRUE(state.needs_redraw());
// Expect to do nothing until BeginImplFrame deadline.
@@ -811,9 +997,12 @@ TEST(SchedulerStateMachineTest, TestFullCycleWithCommitRequestInbetween) {
// At BeginImplFrame deadline, draw.
state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
- state.DidDrawIfPossibleCompleted(true);
+ state.DidSwapBuffers();
+ state.DidDrawIfPossibleCompleted(DRAW_SUCCESS);
+ state.DidSwapBuffersComplete();
// Should be synchronized, no draw needed, no action needed.
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -821,7 +1010,7 @@ TEST(SchedulerStateMachineTest, TestFullCycleWithCommitRequestInbetween) {
EXPECT_FALSE(state.needs_redraw());
// Next BeginImplFrame should initiate second commit.
- state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
}
@@ -849,10 +1038,10 @@ TEST(SchedulerStateMachineTest, TestGoesInvisibleBeforeFinishCommit) {
state.SetNeedsCommit();
// Begin the frame while visible.
- state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_FRAME_IN_PROGRESS,
+ EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
state.CommitState());
EXPECT_FALSE(state.NeedsCommit());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -879,12 +1068,12 @@ TEST(SchedulerStateMachineTest, TestGoesInvisibleBeforeFinishCommit) {
EXPECT_TRUE(state.NeedsCommit());
// Start a new frame.
- state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
// We should be starting the commit now.
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_FRAME_IN_PROGRESS,
+ EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
state.CommitState());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
}
@@ -903,7 +1092,7 @@ TEST(SchedulerStateMachineTest, AbortBeginMainFrameAndCancelCommit) {
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_FRAME_IN_PROGRESS,
+ EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
state.CommitState());
EXPECT_FALSE(state.NeedsCommit());
EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
@@ -918,11 +1107,14 @@ TEST(SchedulerStateMachineTest, AbortBeginMainFrameAndCancelCommit) {
// Start a new frame; draw because this is the first frame since output
// surface init'd.
- state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
+ state.DidSwapBuffers();
+ state.DidSwapBuffersComplete();
// Verify another commit doesn't start on another frame either.
EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
@@ -936,6 +1128,152 @@ TEST(SchedulerStateMachineTest, AbortBeginMainFrameAndCancelCommit) {
state.NextAction());
}
+TEST(SchedulerStateMachineTest,
+ AbortBeginMainFrameAndCancelCommitWhenInvisible) {
+ SchedulerSettings default_scheduler_settings;
+ StateMachine state(default_scheduler_settings);
+ state.SetCanStart();
+ state.UpdateState(state.NextAction());
+ state.DidCreateAndInitializeOutputSurface();
+ state.SetVisible(true);
+ state.SetCanDraw(true);
+
+ // Get into a begin frame / commit state.
+ state.SetNeedsCommit();
+
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
+ EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
+ state.CommitState());
+ EXPECT_FALSE(state.NeedsCommit());
+ EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+
+ // Become invisible and abort BeginMainFrame.
+ state.SetVisible(false);
+ state.BeginMainFrameAborted(true);
+
+ // Verify that another commit doesn't start on the same frame.
+ EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
+ EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+ EXPECT_FALSE(state.NeedsCommit());
+
+ // Become visible and start a new frame.
+ state.SetVisible(true);
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
+ // Draw because this is the first frame since output surface init'd.
+ state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
+ state.DidSwapBuffers();
+ state.DidSwapBuffersComplete();
+
+ // Verify another commit doesn't start on another frame either.
+ EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
+ EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+ EXPECT_FALSE(state.NeedsCommit());
+
+ // Verify another commit can start if requested, though.
+ state.SetNeedsCommit();
+ EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
+ EXPECT_EQ(SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME,
+ state.NextAction());
+}
+
+TEST(SchedulerStateMachineTest,
+ AbortBeginMainFrameAndRequestCommitWhenInvisible) {
+ SchedulerSettings default_scheduler_settings;
+ StateMachine state(default_scheduler_settings);
+ state.SetCanStart();
+ state.UpdateState(state.NextAction());
+ state.DidCreateAndInitializeOutputSurface();
+ state.SetVisible(true);
+ state.SetCanDraw(true);
+
+ // Get into a begin frame / commit state.
+ state.SetNeedsCommit();
+
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
+ EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
+ state.CommitState());
+ EXPECT_FALSE(state.NeedsCommit());
+ EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+
+ // Become invisible and abort BeginMainFrame.
+ state.SetVisible(false);
+ state.BeginMainFrameAborted(true);
+
+ // Verify that another commit doesn't start on the same frame.
+ EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
+ EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+ EXPECT_FALSE(state.NeedsCommit());
+
+ // Asking for a commit while not visible won't make it happen.
+ state.SetNeedsCommit();
+ EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
+ EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+ EXPECT_TRUE(state.NeedsCommit());
+
+ // Become visible but nothing happens until the next frame.
+ state.SetVisible(true);
+ EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
+ EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+ EXPECT_TRUE(state.NeedsCommit());
+
+ // We should get that commit when we begin the next frame.
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
+}
+
+TEST(SchedulerStateMachineTest,
+ AbortBeginMainFrameAndRequestCommitAndBeginImplFrameWhenInvisible) {
+ SchedulerSettings default_scheduler_settings;
+ StateMachine state(default_scheduler_settings);
+ state.SetCanStart();
+ state.UpdateState(state.NextAction());
+ state.DidCreateAndInitializeOutputSurface();
+ state.SetVisible(true);
+ state.SetCanDraw(true);
+
+ // Get into a begin frame / commit state.
+ state.SetNeedsCommit();
+
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
+ EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
+ state.CommitState());
+ EXPECT_FALSE(state.NeedsCommit());
+ EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+
+ // Become invisible and abort BeginMainFrame.
+ state.SetVisible(false);
+ state.BeginMainFrameAborted(true);
+
+ // Asking for a commit while not visible won't make it happen.
+ state.SetNeedsCommit();
+ EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
+ EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+ EXPECT_TRUE(state.NeedsCommit());
+
+ // Begin a frame when not visible, the scheduler animates but does not commit.
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
+ EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+ EXPECT_TRUE(state.NeedsCommit());
+
+ // Become visible and the requested commit happens immediately.
+ state.SetVisible(true);
+ EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
+}
+
TEST(SchedulerStateMachineTest, TestFirstContextCreation) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
@@ -949,14 +1287,14 @@ TEST(SchedulerStateMachineTest, TestFirstContextCreation) {
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// Check that the first init does not SetNeedsCommit.
- state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// Check that a needs commit initiates a BeginMainFrame.
state.SetNeedsCommit();
- state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
}
@@ -986,7 +1324,7 @@ TEST(SchedulerStateMachineTest, TestContextLostWhenCompletelyIdle) {
state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
// When the context is recreated, we should begin a commit.
- state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
}
@@ -1010,14 +1348,14 @@ TEST(SchedulerStateMachineTest,
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// Once context recreation begins, nothing should happen.
- state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// While context is recreating, commits shouldn't begin.
state.SetNeedsCommit();
- state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -1030,9 +1368,11 @@ TEST(SchedulerStateMachineTest,
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_FRAME_IN_PROGRESS,
+ EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT,
state.CommitState());
- state.FinishCommit();
+
+ state.NotifyBeginMainFrameStarted();
+ state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// Finishing the first commit after initializing an output surface should
@@ -1041,7 +1381,8 @@ TEST(SchedulerStateMachineTest,
// Once the context is recreated, whether we draw should be based on
// SetCanDraw.
- state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
EXPECT_EQ(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE,
@@ -1054,9 +1395,8 @@ TEST(SchedulerStateMachineTest,
state.NextAction());
}
-void TestContextLostWhileCommitInProgress(bool deadline_scheduling_enabled) {
+TEST(SchedulerStateMachineTest, TestContextLostWhileCommitInProgress) {
SchedulerSettings scheduler_settings;
- scheduler_settings.deadline_scheduling_enabled = deadline_scheduling_enabled;
StateMachine state(scheduler_settings);
state.SetCanStart();
state.UpdateState(state.NextAction());
@@ -1066,22 +1406,19 @@ void TestContextLostWhileCommitInProgress(bool deadline_scheduling_enabled) {
// Get a commit in flight.
state.SetNeedsCommit();
- if (!deadline_scheduling_enabled) {
- EXPECT_ACTION_UPDATE_STATE(
- SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
- }
// Set damage and expect a draw.
state.SetNeedsRedraw(true);
- state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting());
- if (deadline_scheduling_enabled) {
- EXPECT_ACTION_UPDATE_STATE(
- SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
- }
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
+ state.DidSwapBuffers();
+ state.DidSwapBuffersComplete();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// Cause a lost context while the BeginMainFrame is in flight.
@@ -1092,55 +1429,40 @@ void TestContextLostWhileCommitInProgress(bool deadline_scheduling_enabled) {
EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
// Finish the frame, and commit.
- state.FinishCommit();
+ state.NotifyBeginMainFrameStarted();
+ state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
// We will abort the draw when the output surface is lost if we are
// waiting for the first draw to unblock the main thread.
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_FIRST_DRAW,
- state.CommitState());
+ EXPECT_TRUE(state.active_tree_needs_first_draw());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT);
- // Expect to be told to begin context recreation, independent of
- // BeginImplFrame state.
+ // Expect to begin context recreation only in BEGIN_IMPL_FRAME_STATE_IDLE
EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE,
state.begin_impl_frame_state());
EXPECT_EQ(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION,
state.NextAction());
- state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING,
state.begin_impl_frame_state());
- EXPECT_EQ(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION,
- state.NextAction());
+ EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
state.OnBeginImplFrameDeadlinePending();
EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME,
state.begin_impl_frame_state());
- EXPECT_EQ(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION,
- state.NextAction());
+ EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
state.OnBeginImplFrameDeadline();
EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE,
state.begin_impl_frame_state());
- EXPECT_EQ(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION,
- state.NextAction());
-}
-
-TEST(SchedulerStateMachineTest, TestContextLostWhileCommitInProgress) {
- bool deadline_scheduling_enabled = false;
- TestContextLostWhileCommitInProgress(deadline_scheduling_enabled);
-}
-
-TEST(SchedulerStateMachineTest, TestContextLostWhileCommitInProgress_Deadline) {
- bool deadline_scheduling_enabled = true;
- TestContextLostWhileCommitInProgress(deadline_scheduling_enabled);
+ EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
}
-void TestContextLostWhileCommitInProgressAndAnotherCommitRequested(
- bool deadline_scheduling_enabled) {
+TEST(SchedulerStateMachineTest,
+ TestContextLostWhileCommitInProgressAndAnotherCommitRequested) {
SchedulerSettings scheduler_settings;
- scheduler_settings.deadline_scheduling_enabled = deadline_scheduling_enabled;
StateMachine state(scheduler_settings);
state.SetCanStart();
state.UpdateState(state.NextAction());
@@ -1150,23 +1472,20 @@ void TestContextLostWhileCommitInProgressAndAnotherCommitRequested(
// Get a commit in flight.
state.SetNeedsCommit();
- if (!deadline_scheduling_enabled) {
- EXPECT_ACTION_UPDATE_STATE(
- SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
- }
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// Set damage and expect a draw.
state.SetNeedsRedraw(true);
- state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting());
- if (deadline_scheduling_enabled) {
- EXPECT_ACTION_UPDATE_STATE(
- SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
- }
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
+ state.DidSwapBuffers();
+ state.DidSwapBuffersComplete();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// Cause a lost context while the BeginMainFrame is in flight.
@@ -1178,116 +1497,55 @@ void TestContextLostWhileCommitInProgressAndAnotherCommitRequested(
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// Finish the frame, and commit.
- state.FinishCommit();
+ state.NotifyBeginMainFrameStarted();
+ state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_FIRST_DRAW,
- state.CommitState());
+ EXPECT_TRUE(state.active_tree_needs_first_draw());
// Because the output surface is missing, we expect the draw to abort.
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT);
- // Expect to be told to begin context recreation, independent of
- // BeginImplFrame state
+ // Expect to begin context recreation only in BEGIN_IMPL_FRAME_STATE_IDLE
EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE,
state.begin_impl_frame_state());
EXPECT_EQ(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION,
state.NextAction());
- state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING,
state.begin_impl_frame_state());
- EXPECT_EQ(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION,
- state.NextAction());
+ EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
state.OnBeginImplFrameDeadlinePending();
EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME,
state.begin_impl_frame_state());
- EXPECT_EQ(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION,
- state.NextAction());
+ EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
state.OnBeginImplFrameDeadline();
EXPECT_EQ(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE,
state.begin_impl_frame_state());
- EXPECT_EQ(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION,
- state.NextAction());
+ EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
- // After we get a new output surface, the commit flow should start.
+ state.OnBeginImplFrameIdle();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION);
+
+ // After we get a new output surface, the commit flow should start.
state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.OnBeginImplFrameIdle();
- state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- state.FinishCommit();
+ state.NotifyBeginMainFrameStarted();
+ state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
- EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
-}
-
-TEST(SchedulerStateMachineTest,
- TestContextLostWhileCommitInProgressAndAnotherCommitRequested) {
- bool deadline_scheduling_enabled = false;
- TestContextLostWhileCommitInProgressAndAnotherCommitRequested(
- deadline_scheduling_enabled);
-}
-
-TEST(SchedulerStateMachineTest,
- TestContextLostWhileCommitInProgressAndAnotherCommitRequested_Deadline) {
- bool deadline_scheduling_enabled = true;
- TestContextLostWhileCommitInProgressAndAnotherCommitRequested(
- deadline_scheduling_enabled);
-}
-
-TEST(SchedulerStateMachineTest, TestFinishAllRenderingWhileContextLost) {
- SchedulerSettings default_scheduler_settings;
- StateMachine state(default_scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
-
- // Cause a lost context lost.
- state.DidLoseOutputSurface();
-
- // Ask a forced redraw for readback and verify it ocurrs.
- state.SetCommitState(
- SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_FIRST_DRAW);
- state.SetNeedsForcedRedrawForReadback();
- state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting());
- EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_AND_READBACK);
- EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
-
- // Forced redraws for readbacks need to be followed by a new commit
- // to replace the readback commit.
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_FRAME_IN_PROGRESS,
- state.CommitState());
- state.FinishCommit();
- EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
-
- // We don't yet have an output surface, so we the draw and swap should abort.
- EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT);
-
- // Expect to be told to begin context recreation, independent of
- // BeginImplFrame state
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
- EXPECT_EQ(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION,
- state.NextAction());
-
- state.OnBeginImplFrameDeadline();
- EXPECT_EQ(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION,
- state.NextAction());
-
- // Ask a readback and verify it occurs.
- state.SetCommitState(
- SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_FIRST_DRAW);
- state.SetNeedsForcedRedrawForReadback();
- EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_AND_READBACK);
+ state.DidSwapBuffers();
+ state.DidSwapBuffersComplete();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
}
@@ -1310,83 +1568,69 @@ TEST(SchedulerStateMachineTest, DontDrawBeforeCommitAfterLostOutputSurface) {
state.DidCreateAndInitializeOutputSurface();
EXPECT_FALSE(state.RedrawPending());
- state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
EXPECT_EQ(SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME,
state.NextAction());
}
TEST(SchedulerStateMachineTest,
- TestSendBeginMainFrameWhenInvisibleAndForceCommit) {
- SchedulerSettings default_scheduler_settings;
- StateMachine state(default_scheduler_settings);
+ TestPendingActivationsShouldBeForcedAfterLostOutputSurface) {
+ SchedulerSettings settings;
+ settings.impl_side_painting = true;
+ StateMachine state(settings);
state.SetCanStart();
state.UpdateState(state.NextAction());
state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(false);
- state.SetNeedsCommit();
- state.SetNeedsForcedCommitForReadback();
- EXPECT_EQ(SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME,
- state.NextAction());
-}
-
-TEST(SchedulerStateMachineTest,
- TestSendBeginMainFrameWhenCanStartFalseAndForceCommit) {
- SchedulerSettings default_scheduler_settings;
- StateMachine state(default_scheduler_settings);
state.SetVisible(true);
state.SetCanDraw(true);
- state.SetNeedsCommit();
- state.SetNeedsForcedCommitForReadback();
- EXPECT_EQ(SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME,
- state.NextAction());
+
+ state.SetCommitState(
+ SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
+
+ // Cause a lost context.
+ state.DidLoseOutputSurface();
+
+ state.NotifyBeginMainFrameStarted();
+ state.NotifyReadyToCommit();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
+
+ EXPECT_TRUE(state.PendingActivationsShouldBeForced());
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_ACTIVATE_PENDING_TREE);
+
+ EXPECT_TRUE(state.PendingDrawsShouldBeAborted());
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT);
}
-TEST(SchedulerStateMachineTest, TestFinishCommitWhenCommitInProgress) {
+TEST(SchedulerStateMachineTest, TestNoBeginMainFrameWhenInvisible) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
state.SetCanStart();
state.UpdateState(state.NextAction());
state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
state.SetVisible(false);
- state.SetCommitState(SchedulerStateMachine::COMMIT_STATE_FRAME_IN_PROGRESS);
state.SetNeedsCommit();
-
- state.FinishCommit();
- EXPECT_EQ(SchedulerStateMachine::ACTION_COMMIT, state.NextAction());
- state.UpdateState(state.NextAction());
-
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_FIRST_DRAW,
- state.CommitState());
- EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT);
+ EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
}
-TEST(SchedulerStateMachineTest, TestFinishCommitWhenForcedCommitInProgress) {
+TEST(SchedulerStateMachineTest, TestFinishCommitWhenCommitInProgress) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
state.SetCanStart();
state.UpdateState(state.NextAction());
state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
state.SetVisible(false);
- state.SetCommitState(SchedulerStateMachine::COMMIT_STATE_FRAME_IN_PROGRESS);
+ state.SetCommitState(
+ SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
state.SetNeedsCommit();
- state.SetNeedsForcedCommitForReadback();
- // The commit for readback interupts the normal commit.
- state.FinishCommit();
- EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
-
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_FIRST_DRAW,
- state.CommitState());
- EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_AND_READBACK);
-
- // When the readback interrupts the normal commit, we should not get
- // another BeginMainFrame when the readback completes.
- EXPECT_NE(SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME,
- state.NextAction());
+ state.NotifyBeginMainFrameStarted();
+ state.NotifyReadyToCommit();
+ EXPECT_EQ(SchedulerStateMachine::ACTION_COMMIT, state.NextAction());
+ state.UpdateState(state.NextAction());
- // The normal commit can then proceed.
- state.FinishCommit();
- EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
+ EXPECT_TRUE(state.active_tree_needs_first_draw());
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT);
}
TEST(SchedulerStateMachineTest, TestInitialActionsWhenContextLost) {
@@ -1415,295 +1659,202 @@ TEST(SchedulerStateMachineTest, TestInitialActionsWhenContextLost) {
state.SetVisible(false);
EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction())
<< *state.AsValue();
-
- // If there is a forced commit, however, we could be blocking a readback
- // on the main thread, so we need to unblock it before we can get our
- // output surface, even if we are not visible.
- state.SetNeedsForcedCommitForReadback();
- EXPECT_EQ(
- SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME, state.NextAction())
- << *state.AsValue();
}
-TEST(SchedulerStateMachineTest, TestImmediateFinishCommit) {
+TEST(SchedulerStateMachineTest, ReportIfNotDrawing) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
state.SetCanStart();
state.UpdateState(state.NextAction());
state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(true);
- // Schedule a readback, commit it, draw it.
- state.SetNeedsCommit();
- state.SetNeedsForcedCommitForReadback();
- EXPECT_ACTION_UPDATE_STATE(
- SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
- state.FinishCommit();
-
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT,
- state.CommitState());
- EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
+ state.SetCanDraw(true);
+ state.SetVisible(true);
+ EXPECT_FALSE(state.PendingDrawsShouldBeAborted());
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_FIRST_DRAW,
- state.CommitState());
+ state.SetCanDraw(false);
+ state.SetVisible(true);
+ EXPECT_TRUE(state.PendingDrawsShouldBeAborted());
- EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_AND_READBACK);
- state.DidDrawIfPossibleCompleted(true);
+ state.SetCanDraw(true);
+ state.SetVisible(false);
+ EXPECT_TRUE(state.PendingDrawsShouldBeAborted());
- EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ state.SetCanDraw(false);
+ state.SetVisible(false);
+ EXPECT_TRUE(state.PendingDrawsShouldBeAborted());
- // Should be waiting for the normal BeginMainFrame.
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_FRAME_IN_PROGRESS,
- state.CommitState());
+ state.SetCanDraw(true);
+ state.SetVisible(true);
+ EXPECT_FALSE(state.PendingDrawsShouldBeAborted());
}
-void TestImmediateFinishCommitDuringCommit(bool deadline_scheduling_enabled) {
- SchedulerSettings scheduler_settings;
- scheduler_settings.deadline_scheduling_enabled = deadline_scheduling_enabled;
- StateMachine state(scheduler_settings);
+TEST(SchedulerStateMachineTest, TestTriggerDeadlineEarlyAfterAbortedCommit) {
+ SchedulerSettings settings;
+ settings.impl_side_painting = true;
+ StateMachine state(settings);
state.SetCanStart();
state.UpdateState(state.NextAction());
state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
state.SetVisible(true);
state.SetCanDraw(true);
- // Start a normal commit.
+ // This test mirrors what happens during the first frame of a scroll gesture.
+ // First we get the input event and a BeginFrame.
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+
+ // As a response the compositor requests a redraw and a commit to tell the
+ // main thread about the new scroll offset.
+ state.SetNeedsRedraw(true);
state.SetNeedsCommit();
- if (!deadline_scheduling_enabled) {
- EXPECT_ACTION_UPDATE_STATE(
- SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
- }
- EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- // Schedule a readback, commit it, draw it.
- state.SetNeedsForcedCommitForReadback();
- if (deadline_scheduling_enabled) {
- EXPECT_ACTION_UPDATE_STATE(
- SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
- }
+ // We should start the commit normally.
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- state.FinishCommit();
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT,
- state.CommitState());
- EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
-
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_FIRST_DRAW,
- state.CommitState());
- EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_AND_READBACK);
- state.DidDrawIfPossibleCompleted(true);
- EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ // Since only the scroll offset changed, the main thread will abort the
+ // commit.
+ state.BeginMainFrameAborted(true);
- // Should be waiting for the normal BeginMainFrame.
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_FRAME_IN_PROGRESS,
- state.CommitState())
- << *state.AsValue();
+ // Since the commit was aborted, we should draw right away instead of waiting
+ // for the deadline.
+ EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineEarly());
}
-TEST(SchedulerStateMachineTest, TestImmediateFinishCommitDuringCommit) {
- bool deadline_scheduling_enabled = false;
- TestImmediateFinishCommitDuringCommit(deadline_scheduling_enabled);
-}
+void FinishPreviousCommitAndDrawWithoutExitingDeadline(
+ StateMachine* state_ptr) {
+ // Gross, but allows us to use macros below.
+ StateMachine& state = *state_ptr;
-TEST(SchedulerStateMachineTest,
- TestImmediateFinishCommitDuringCommit_Deadline) {
- bool deadline_scheduling_enabled = true;
- TestImmediateFinishCommitDuringCommit(deadline_scheduling_enabled);
+ state.NotifyBeginMainFrameStarted();
+ state.NotifyReadyToCommit();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ state.NotifyReadyToActivate();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_ACTIVATE_PENDING_TREE);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
+ EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineEarly());
+ state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
+ state.DidSwapBuffers();
}
-void ImmediateBeginMainFrameAbortedWhileInvisible(
- bool deadline_scheduling_enabled) {
- SchedulerSettings scheduler_settings;
- scheduler_settings.deadline_scheduling_enabled = deadline_scheduling_enabled;
- StateMachine state(scheduler_settings);
+TEST(SchedulerStateMachineTest, TestSmoothnessTakesPriority) {
+ SchedulerSettings settings;
+ settings.impl_side_painting = true;
+ StateMachine state(settings);
state.SetCanStart();
state.UpdateState(state.NextAction());
state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
state.SetVisible(true);
state.SetCanDraw(true);
+ // This test ensures that impl-draws are prioritized over main thread updates
+ // in prefer smoothness mode.
+ state.SetNeedsRedraw(true);
state.SetNeedsCommit();
- if (!deadline_scheduling_enabled) {
- EXPECT_ACTION_UPDATE_STATE(
- SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
- }
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- state.SetNeedsCommit();
- state.SetNeedsForcedCommitForReadback();
- if (deadline_scheduling_enabled) {
- EXPECT_ACTION_UPDATE_STATE(
- SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
- }
- state.FinishCommit();
-
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT,
- state.CommitState());
- EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
-
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_FIRST_DRAW,
- state.CommitState());
+ // Verify the deadline is not triggered early until we enter
+ // prefer smoothness mode.
+ EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineEarly());
+ state.SetSmoothnessTakesPriority(true);
+ EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineEarly());
- EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_AND_READBACK);
- state.DidDrawIfPossibleCompleted(true);
+ // Trigger the deadline.
+ state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
+ state.DidSwapBuffers();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ state.DidSwapBuffersComplete();
- // Should be waiting for BeginMainFrame.
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_FRAME_IN_PROGRESS,
- state.CommitState())
- << *state.AsValue();
-
- // Become invisible and abort BeginMainFrame.
- state.SetVisible(false);
- state.BeginMainFrameAborted(false);
-
- // Should be back in the idle state, but needing a commit.
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_IDLE, state.CommitState());
- EXPECT_TRUE(state.NeedsCommit());
-}
-
-TEST(SchedulerStateMachineTest,
- ImmediateBeginMainFrameAbortedWhileInvisible) {
- bool deadline_scheduling_enabled = false;
- ImmediateBeginMainFrameAbortedWhileInvisible(
- deadline_scheduling_enabled);
-}
-
-TEST(SchedulerStateMachineTest,
- ImmediateBeginMainFrameAbortedWhileInvisible_Deadline) {
- bool deadline_scheduling_enabled = true;
- ImmediateBeginMainFrameAbortedWhileInvisible(
- deadline_scheduling_enabled);
-}
-
-TEST(SchedulerStateMachineTest, ImmediateFinishCommitWhileCantDraw) {
- SchedulerSettings default_scheduler_settings;
- StateMachine state(default_scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.SetVisible(true);
- state.SetCanDraw(false);
-
+ // Request a new commit and finish the previous one.
state.SetNeedsCommit();
- state.UpdateState(state.NextAction());
-
- state.SetNeedsCommit();
- state.SetNeedsForcedCommitForReadback();
- state.UpdateState(state.NextAction());
- state.FinishCommit();
-
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_READY_TO_COMMIT,
- state.CommitState());
- EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
+ FinishPreviousCommitAndDrawWithoutExitingDeadline(&state);
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ state.DidSwapBuffersComplete();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- EXPECT_EQ(SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_FIRST_DRAW,
- state.CommitState());
+ // Finish the previous commit and draw it.
+ FinishPreviousCommitAndDrawWithoutExitingDeadline(&state);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_AND_READBACK);
- state.DidDrawIfPossibleCompleted(true);
+ // Verify we do not send another BeginMainFrame if was are swap throttled
+ // and did not just swap.
+ state.SetNeedsCommit();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineEarly());
+ state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
}
-TEST(SchedulerStateMachineTest, ReportIfNotDrawing) {
+TEST(SchedulerStateMachineTest, TestTriggerDeadlineEarlyOnLostOutputSurface) {
SchedulerSettings default_scheduler_settings;
StateMachine state(default_scheduler_settings);
state.SetCanStart();
state.UpdateState(state.NextAction());
state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
-
- state.SetCanDraw(true);
state.SetVisible(true);
- EXPECT_FALSE(state.PendingDrawsShouldBeAborted());
-
- state.SetCanDraw(false);
- state.SetVisible(true);
- EXPECT_TRUE(state.PendingDrawsShouldBeAborted());
-
- state.SetCanDraw(true);
- state.SetVisible(false);
- EXPECT_TRUE(state.PendingDrawsShouldBeAborted());
-
- state.SetCanDraw(false);
- state.SetVisible(false);
- EXPECT_TRUE(state.PendingDrawsShouldBeAborted());
-
- state.SetCanDraw(true);
- state.SetVisible(true);
- EXPECT_FALSE(state.PendingDrawsShouldBeAborted());
-}
-
-TEST(SchedulerStateMachineTest, ReportIfNotDrawingFromAcquiredTextures) {
- SchedulerSettings default_scheduler_settings;
- StateMachine state(default_scheduler_settings);
- state.SetCanStart();
- state.UpdateState(state.NextAction());
- state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
state.SetCanDraw(true);
- state.SetVisible(true);
- EXPECT_FALSE(state.PendingDrawsShouldBeAborted());
-
- state.SetMainThreadNeedsLayerTextures();
- EXPECT_ACTION_UPDATE_STATE(
- SchedulerStateMachine::ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD);
- EXPECT_TRUE(state.PendingDrawsShouldBeAborted());
- EXPECT_TRUE(state.PendingActivationsShouldBeForced());
state.SetNeedsCommit();
- state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting());
+
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
- EXPECT_TRUE(state.PendingDrawsShouldBeAborted());
- EXPECT_TRUE(state.PendingActivationsShouldBeForced());
-
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
-
- state.FinishCommit();
- EXPECT_TRUE(state.PendingDrawsShouldBeAborted());
-
- EXPECT_EQ(SchedulerStateMachine::ACTION_COMMIT, state.NextAction());
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineEarly());
- state.UpdateState(state.NextAction());
- EXPECT_FALSE(state.PendingDrawsShouldBeAborted());
+ state.DidLoseOutputSurface();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ // The deadline should be triggered immediately when output surface is lost.
+ EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineEarly());
}
-TEST(SchedulerStateMachineTest, AcquireTexturesWithAbort) {
- SchedulerSettings default_scheduler_settings;
- StateMachine state(default_scheduler_settings);
+TEST(SchedulerStateMachineTest, TestSetNeedsAnimate) {
+ SchedulerSettings settings;
+ settings.impl_side_painting = true;
+ StateMachine state(settings);
state.SetCanStart();
state.UpdateState(state.NextAction());
- state.DidCreateAndInitializeOutputSurface();
- state.SetCanDraw(true);
+ state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
state.SetVisible(true);
+ state.SetCanDraw(true);
- state.SetMainThreadNeedsLayerTextures();
- EXPECT_EQ(
- SchedulerStateMachine::ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD,
- state.NextAction());
- state.UpdateState(state.NextAction());
- EXPECT_TRUE(state.PendingDrawsShouldBeAborted());
-
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
-
- state.SetNeedsCommit();
- EXPECT_EQ(SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME,
- state.NextAction());
- state.UpdateState(state.NextAction());
- EXPECT_TRUE(state.PendingDrawsShouldBeAborted());
-
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
+ // Test requesting an animation that, when run, causes us to draw.
+ state.SetNeedsAnimate();
+ EXPECT_TRUE(state.BeginFrameNeeded());
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- state.BeginMainFrameAborted(true);
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
- EXPECT_EQ(SchedulerStateMachine::ACTION_NONE, state.NextAction());
- EXPECT_FALSE(state.PendingDrawsShouldBeAborted());
+ state.OnBeginImplFrameDeadlinePending();
+ state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
}
-TEST(SchedulerStateMachineTest,
- TestTriggerDeadlineEarlyAfterAbortedCommit) {
+TEST(SchedulerStateMachineTest, TestAnimateBeforeCommit) {
SchedulerSettings settings;
- settings.deadline_scheduling_enabled = true;
settings.impl_side_painting = true;
StateMachine state(settings);
state.SetCanStart();
@@ -1712,32 +1863,26 @@ TEST(SchedulerStateMachineTest,
state.SetVisible(true);
state.SetCanDraw(true);
- // This test mirrors what happens during the first frame of a scroll gesture.
- // First we get the input event and a BeginFrame.
- state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting());
-
- // As a response the compositor requests a redraw and a commit to tell the
- // main thread about the new scroll offset.
- state.SetNeedsRedraw(true);
+ // Check that animations are updated before we start a commit.
+ state.SetNeedsAnimate();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.SetNeedsCommit();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+ EXPECT_TRUE(state.BeginFrameNeeded());
- // We should start the commit normally.
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
- EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
-
- // Since only the scroll offset changed, the main thread will abort the
- // commit.
- state.BeginMainFrameAborted(true);
- // Since the commit was aborted, we should draw right away instead of waiting
- // for the deadline.
- EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineEarly());
+ state.OnBeginImplFrameDeadlinePending();
+ state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
}
-TEST(SchedulerStateMachineTest, TestTriggerDeadlineEarlyForSmoothness) {
+TEST(SchedulerStateMachineTest, TestSetNeedsAnimateAfterAnimate) {
SchedulerSettings settings;
- settings.deadline_scheduling_enabled = true;
settings.impl_side_painting = true;
StateMachine state(settings);
state.SetCanStart();
@@ -1746,19 +1891,21 @@ TEST(SchedulerStateMachineTest, TestTriggerDeadlineEarlyForSmoothness) {
state.SetVisible(true);
state.SetCanDraw(true);
- // This test ensures that impl-draws are prioritized over main thread updates
- // in prefer smoothness mode.
- state.OnBeginImplFrame(BeginFrameArgs::CreateForTesting());
+ // Test requesting an animation after we have already animated during this
+ // frame.
state.SetNeedsRedraw(true);
- state.SetNeedsCommit();
- EXPECT_ACTION_UPDATE_STATE(
- SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
+ EXPECT_TRUE(state.BeginFrameNeeded());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- // The deadline is not triggered early until we enter prefer smoothness mode.
- EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineEarly());
- state.SetSmoothnessTakesPriority(true);
- EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineEarly());
+ state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
+
+ state.SetNeedsAnimate();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
+ state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE);
}
} // namespace
diff --git a/chromium/cc/scheduler/scheduler_unittest.cc b/chromium/cc/scheduler/scheduler_unittest.cc
index 6f5eb2c2dcd..7d5a163dacc 100644
--- a/chromium/cc/scheduler/scheduler_unittest.cc
+++ b/chromium/cc/scheduler/scheduler_unittest.cc
@@ -11,43 +11,78 @@
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/time/time.h"
+#include "cc/test/begin_frame_args_test.h"
+#include "cc/test/ordered_simple_task_runner.h"
#include "cc/test/scheduler_test_common.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#define EXPECT_ACTION(action, client, action_index, expected_num_actions) \
- EXPECT_EQ(expected_num_actions, client.num_actions_()); \
- ASSERT_LT(action_index, client.num_actions_()); \
do { \
- EXPECT_STREQ(action, client.Action(action_index)); \
+ EXPECT_EQ(expected_num_actions, client.num_actions_()); \
+ if (action_index >= 0) { \
+ ASSERT_LT(action_index, client.num_actions_()) << scheduler; \
+ EXPECT_STREQ(action, client.Action(action_index)); \
+ } \
for (int i = expected_num_actions; i < client.num_actions_(); ++i) \
- ADD_FAILURE() << "Unexpected action: " << client.Action(i) << \
- " with state:\n" << client.StateForAction(action_index); \
+ ADD_FAILURE() << "Unexpected action: " << client.Action(i) \
+ << " with state:\n" << client.StateForAction(i); \
} while (false)
+#define EXPECT_NO_ACTION(client) EXPECT_ACTION("", client, -1, 0)
+
#define EXPECT_SINGLE_ACTION(action, client) \
EXPECT_ACTION(action, client, 0, 1)
namespace cc {
namespace {
-void InitializeOutputSurfaceAndFirstCommit(Scheduler* scheduler) {
- scheduler->DidCreateAndInitializeOutputSurface();
- scheduler->SetNeedsCommit();
- scheduler->FinishCommit();
- // Go through the motions to draw the commit.
- scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
- scheduler->OnBeginImplFrameDeadline();
- // We need another BeginImplFrame so Scheduler calls
- // SetNeedsBeginImplFrame(false).
- scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
- scheduler->OnBeginImplFrameDeadline();
-}
+class FakeSchedulerClient;
+
+void InitializeOutputSurfaceAndFirstCommit(Scheduler* scheduler,
+ FakeSchedulerClient* client);
+
+class TestScheduler : public Scheduler {
+ public:
+ static scoped_ptr<TestScheduler> Create(
+ SchedulerClient* client,
+ const SchedulerSettings& scheduler_settings,
+ int layer_tree_host_id,
+ const scoped_refptr<base::SingleThreadTaskRunner>& impl_task_runner) {
+ return make_scoped_ptr(new TestScheduler(
+ client, scheduler_settings, layer_tree_host_id, impl_task_runner));
+ }
+
+ virtual ~TestScheduler() {}
+
+ bool IsBeginRetroFrameArgsEmpty() const {
+ return begin_retro_frame_args_.empty();
+ }
+
+ bool IsSyntheticBeginFrameSourceActive() const {
+ return synthetic_begin_frame_source_->IsActive();
+ }
+
+ private:
+ TestScheduler(
+ SchedulerClient* client,
+ const SchedulerSettings& scheduler_settings,
+ int layer_tree_host_id,
+ const scoped_refptr<base::SingleThreadTaskRunner> & impl_task_runner)
+ : Scheduler(client,
+ scheduler_settings,
+ layer_tree_host_id,
+ impl_task_runner) {
+ }
+};
class FakeSchedulerClient : public SchedulerClient {
public:
FakeSchedulerClient()
- : needs_begin_impl_frame_(false) {
+ : needs_begin_frame_(false),
+ automatic_swap_ack_(true),
+ swap_contains_incomplete_tile_(false),
+ redraw_will_happen_if_update_visible_tiles_happens_(false) {
Reset();
}
@@ -60,8 +95,9 @@ class FakeSchedulerClient : public SchedulerClient {
log_anticipated_draw_time_change_ = false;
}
- Scheduler* CreateScheduler(const SchedulerSettings& settings) {
- scheduler_ = Scheduler::Create(this, settings, 0);
+ TestScheduler* CreateScheduler(const SchedulerSettings& settings) {
+ task_runner_ = new OrderedSimpleTaskRunner;
+ scheduler_ = TestScheduler::Create(this, settings, 0, task_runner_);
return scheduler_.get();
}
@@ -70,11 +106,16 @@ class FakeSchedulerClient : public SchedulerClient {
void set_log_anticipated_draw_time_change(bool log) {
log_anticipated_draw_time_change_ = log;
}
- bool needs_begin_impl_frame() { return needs_begin_impl_frame_; }
+ bool needs_begin_frame() { return needs_begin_frame_; }
int num_draws() const { return num_draws_; }
int num_actions_() const { return static_cast<int>(actions_.size()); }
const char* Action(int i) const { return actions_[i]; }
base::Value& StateForAction(int i) const { return *states_[i]; }
+ base::TimeTicks posted_begin_impl_frame_deadline() const {
+ return posted_begin_impl_frame_deadline_;
+ }
+
+ OrderedSimpleTaskRunner& task_runner() { return *task_runner_; }
int ActionIndex(const char* action) const {
for (size_t i = 0; i < actions_.size(); i++)
@@ -83,6 +124,10 @@ class FakeSchedulerClient : public SchedulerClient {
return -1;
}
+ void SetSwapContainsIncompleteTile(bool contain) {
+ swap_contains_incomplete_tile_ = contain;
+ }
+
bool HasAction(const char* action) const {
return ActionIndex(action) >= 0;
}
@@ -93,67 +138,78 @@ class FakeSchedulerClient : public SchedulerClient {
void SetSwapWillHappenIfDrawHappens(bool swap_will_happen_if_draw_happens) {
swap_will_happen_if_draw_happens_ = swap_will_happen_if_draw_happens;
}
-
+ void SetAutomaticSwapAck(bool automatic_swap_ack) {
+ automatic_swap_ack_ = automatic_swap_ack;
+ }
+ void SetRedrawWillHappenIfUpdateVisibleTilesHappens(bool redraw) {
+ redraw_will_happen_if_update_visible_tiles_happens_ = redraw;
+ }
// SchedulerClient implementation.
- virtual void SetNeedsBeginImplFrame(bool enable) OVERRIDE {
- actions_.push_back("SetNeedsBeginImplFrame");
- states_.push_back(scheduler_->StateAsValue().release());
- needs_begin_impl_frame_ = enable;
+ virtual void SetNeedsBeginFrame(bool enable) OVERRIDE {
+ actions_.push_back("SetNeedsBeginFrame");
+ states_.push_back(scheduler_->AsValue().release());
+ needs_begin_frame_ = enable;
+ }
+ virtual void WillBeginImplFrame(const BeginFrameArgs& args) OVERRIDE {
+ actions_.push_back("WillBeginImplFrame");
+ states_.push_back(scheduler_->AsValue().release());
}
virtual void ScheduledActionSendBeginMainFrame() OVERRIDE {
actions_.push_back("ScheduledActionSendBeginMainFrame");
- states_.push_back(scheduler_->StateAsValue().release());
+ states_.push_back(scheduler_->AsValue().release());
}
- virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapIfPossible()
- OVERRIDE {
+ virtual void ScheduledActionAnimate() OVERRIDE {
+ actions_.push_back("ScheduledActionAnimate");
+ states_.push_back(scheduler_->AsValue().release());
+ }
+ virtual DrawResult ScheduledActionDrawAndSwapIfPossible() OVERRIDE {
actions_.push_back("ScheduledActionDrawAndSwapIfPossible");
- states_.push_back(scheduler_->StateAsValue().release());
+ states_.push_back(scheduler_->AsValue().release());
num_draws_++;
- bool did_readback = false;
- return DrawSwapReadbackResult(
- draw_will_happen_,
- draw_will_happen_ && swap_will_happen_if_draw_happens_,
- did_readback);
+ DrawResult result =
+ draw_will_happen_ ? DRAW_SUCCESS : DRAW_ABORTED_CHECKERBOARD_ANIMATIONS;
+ bool swap_will_happen =
+ draw_will_happen_ && swap_will_happen_if_draw_happens_;
+ if (swap_will_happen) {
+ scheduler_->DidSwapBuffers();
+ if (swap_contains_incomplete_tile_) {
+ scheduler_->SetSwapUsedIncompleteTile(true);
+ swap_contains_incomplete_tile_ = false;
+ } else {
+ scheduler_->SetSwapUsedIncompleteTile(false);
+ }
+
+ if (automatic_swap_ack_)
+ scheduler_->DidSwapBuffersComplete();
+ }
+ return result;
}
- virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapForced() OVERRIDE {
+ virtual DrawResult ScheduledActionDrawAndSwapForced() OVERRIDE {
actions_.push_back("ScheduledActionDrawAndSwapForced");
- states_.push_back(scheduler_->StateAsValue().release());
- bool did_draw = true;
- bool did_swap = swap_will_happen_if_draw_happens_;
- bool did_readback = false;
- return DrawSwapReadbackResult(did_draw, did_swap, did_readback);
- }
- virtual DrawSwapReadbackResult ScheduledActionDrawAndReadback() OVERRIDE {
- actions_.push_back("ScheduledActionDrawAndReadback");
- states_.push_back(scheduler_->StateAsValue().release());
- bool did_draw = true;
- bool did_swap = false;
- bool did_readback = true;
- return DrawSwapReadbackResult(did_draw, did_swap, did_readback);
+ states_.push_back(scheduler_->AsValue().release());
+ return DRAW_SUCCESS;
}
virtual void ScheduledActionCommit() OVERRIDE {
actions_.push_back("ScheduledActionCommit");
- states_.push_back(scheduler_->StateAsValue().release());
+ states_.push_back(scheduler_->AsValue().release());
}
virtual void ScheduledActionUpdateVisibleTiles() OVERRIDE {
actions_.push_back("ScheduledActionUpdateVisibleTiles");
- states_.push_back(scheduler_->StateAsValue().release());
+ states_.push_back(scheduler_->AsValue().release());
+ if (redraw_will_happen_if_update_visible_tiles_happens_)
+ scheduler_->SetNeedsRedraw();
}
virtual void ScheduledActionActivatePendingTree() OVERRIDE {
actions_.push_back("ScheduledActionActivatePendingTree");
- states_.push_back(scheduler_->StateAsValue().release());
+ states_.push_back(scheduler_->AsValue().release());
}
virtual void ScheduledActionBeginOutputSurfaceCreation() OVERRIDE {
actions_.push_back("ScheduledActionBeginOutputSurfaceCreation");
- states_.push_back(scheduler_->StateAsValue().release());
- }
- virtual void ScheduledActionAcquireLayerTexturesForMainThread() OVERRIDE {
- actions_.push_back("ScheduledActionAcquireLayerTexturesForMainThread");
- states_.push_back(scheduler_->StateAsValue().release());
+ states_.push_back(scheduler_->AsValue().release());
}
virtual void ScheduledActionManageTiles() OVERRIDE {
actions_.push_back("ScheduledActionManageTiles");
- states_.push_back(scheduler_->StateAsValue().release());
+ states_.push_back(scheduler_->AsValue().release());
}
virtual void DidAnticipatedDrawTimeChange(base::TimeTicks) OVERRIDE {
if (log_anticipated_draw_time_change_)
@@ -169,29 +225,64 @@ class FakeSchedulerClient : public SchedulerClient {
return base::TimeDelta();
}
- virtual void PostBeginImplFrameDeadline(const base::Closure& closure,
- base::TimeTicks deadline) OVERRIDE {
- actions_.push_back("PostBeginImplFrameDeadlineTask");
- states_.push_back(scheduler_->StateAsValue().release());
- }
-
virtual void DidBeginImplFrameDeadline() OVERRIDE {}
protected:
- bool needs_begin_impl_frame_;
+ bool needs_begin_frame_;
bool draw_will_happen_;
bool swap_will_happen_if_draw_happens_;
+ bool automatic_swap_ack_;
int num_draws_;
bool log_anticipated_draw_time_change_;
+ bool swap_contains_incomplete_tile_;
+ bool redraw_will_happen_if_update_visible_tiles_happens_;
+ base::TimeTicks posted_begin_impl_frame_deadline_;
std::vector<const char*> actions_;
ScopedVector<base::Value> states_;
- scoped_ptr<Scheduler> scheduler_;
+ scoped_ptr<TestScheduler> scheduler_;
+ scoped_refptr<OrderedSimpleTaskRunner> task_runner_;
};
+void InitializeOutputSurfaceAndFirstCommit(Scheduler* scheduler,
+ FakeSchedulerClient* client) {
+ bool client_initiates_begin_frame =
+ scheduler->settings().begin_frame_scheduling_enabled &&
+ scheduler->settings().throttle_frame_production;
+
+ scheduler->DidCreateAndInitializeOutputSurface();
+ scheduler->SetNeedsCommit();
+ scheduler->NotifyBeginMainFrameStarted();
+ scheduler->NotifyReadyToCommit();
+ if (scheduler->settings().impl_side_painting)
+ scheduler->NotifyReadyToActivate();
+ // Go through the motions to draw the commit.
+ if (client_initiates_begin_frame)
+ scheduler->BeginFrame(CreateBeginFrameArgsForTesting());
+ else
+ client->task_runner().RunPendingTasks(); // Run posted BeginFrame.
+
+ // Run the posted deadline task.
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+ client->task_runner().RunPendingTasks();
+ EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+
+ // We need another BeginImplFrame so Scheduler calls
+ // SetNeedsBeginFrame(false).
+ if (client_initiates_begin_frame)
+ scheduler->BeginFrame(CreateBeginFrameArgsForTesting());
+ else
+ client->task_runner().RunPendingTasks(); // Run posted BeginFrame.
+
+ // Run the posted deadline task.
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+ client->task_runner().RunPendingTasks();
+ EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+}
+
TEST(SchedulerTest, InitializeOutputSurfaceDoesNotBeginImplFrame) {
FakeSchedulerClient client;
SchedulerSettings default_scheduler_settings;
- Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+ TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
@@ -199,127 +290,99 @@ TEST(SchedulerTest, InitializeOutputSurfaceDoesNotBeginImplFrame) {
EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
client.Reset();
scheduler->DidCreateAndInitializeOutputSurface();
- EXPECT_EQ(0, client.num_actions_());
+ EXPECT_NO_ACTION(client);
}
-void RequestCommit(bool deadline_scheduling_enabled) {
+TEST(SchedulerTest, RequestCommit) {
FakeSchedulerClient client;
SchedulerSettings scheduler_settings;
- scheduler_settings.deadline_scheduling_enabled = deadline_scheduling_enabled;
- Scheduler* scheduler = client.CreateScheduler(scheduler_settings);
+ TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
- InitializeOutputSurfaceAndFirstCommit(scheduler);
+ InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
// SetNeedsCommit should begin the frame on the next BeginImplFrame.
client.Reset();
scheduler->SetNeedsCommit();
- EXPECT_TRUE(client.needs_begin_impl_frame());
- if (deadline_scheduling_enabled) {
- EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
- } else {
- EXPECT_EQ(client.num_actions_(), 2);
- EXPECT_TRUE(client.HasAction("ScheduledActionSendBeginMainFrame"));
- EXPECT_TRUE(client.HasAction("SetNeedsBeginImplFrame"));
- }
+ EXPECT_TRUE(client.needs_begin_frame());
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
client.Reset();
- scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
- if (deadline_scheduling_enabled) {
- EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2);
- EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2);
- } else {
- EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
- }
- EXPECT_TRUE(client.needs_begin_impl_frame());
+ scheduler->BeginFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client.needs_begin_frame());
client.Reset();
- // If we don't swap on the deadline, we need to request another
- // BeginImplFrame.
- scheduler->OnBeginImplFrameDeadline();
- EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
- EXPECT_TRUE(client.needs_begin_impl_frame());
+ // If we don't swap on the deadline, we wait for the next BeginFrame.
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_NO_ACTION(client);
+ EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client.needs_begin_frame());
client.Reset();
- // FinishCommit should commit
- scheduler->FinishCommit();
+ // NotifyReadyToCommit should trigger the commit.
+ scheduler->NotifyBeginMainFrameStarted();
+ scheduler->NotifyReadyToCommit();
EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
- EXPECT_TRUE(client.needs_begin_impl_frame());
+ EXPECT_TRUE(client.needs_begin_frame());
client.Reset();
// BeginImplFrame should prepare the draw.
- scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
- EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
- EXPECT_TRUE(client.needs_begin_impl_frame());
+ scheduler->BeginFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client.needs_begin_frame());
client.Reset();
// BeginImplFrame deadline should draw.
- scheduler->OnBeginImplFrameDeadline();
- EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2);
- EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2);
- EXPECT_TRUE(client.needs_begin_impl_frame());
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 1);
+ EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client.needs_begin_frame());
client.Reset();
- // The following BeginImplFrame deadline should SetNeedsBeginImplFrame(false)
+ // The following BeginImplFrame deadline should SetNeedsBeginFrame(false)
// to avoid excessive toggles.
- scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
- EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
+ scheduler->BeginFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_SINGLE_ACTION("WillBeginImplFrame", client);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
client.Reset();
- scheduler->OnBeginImplFrameDeadline();
- EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
- EXPECT_FALSE(client.needs_begin_impl_frame());
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
+ EXPECT_FALSE(client.needs_begin_frame());
client.Reset();
}
-TEST(SchedulerTest, RequestCommit) {
- bool deadline_scheduling_enabled = false;
- RequestCommit(deadline_scheduling_enabled);
-}
-
-TEST(SchedulerTest, RequestCommit_Deadline) {
- bool deadline_scheduling_enabled = true;
- RequestCommit(deadline_scheduling_enabled);
-}
-
-void RequestCommitAfterBeginMainFrameSent(
- bool deadline_scheduling_enabled) {
+TEST(SchedulerTest, RequestCommitAfterBeginMainFrameSent) {
FakeSchedulerClient client;
SchedulerSettings scheduler_settings;
- scheduler_settings.deadline_scheduling_enabled = deadline_scheduling_enabled;
- Scheduler* scheduler = client.CreateScheduler(scheduler_settings);
+ TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
- InitializeOutputSurfaceAndFirstCommit(scheduler);
+ InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
client.Reset();
// SetNeedsCommit should begin the frame.
scheduler->SetNeedsCommit();
- if (deadline_scheduling_enabled) {
- EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
- } else {
- EXPECT_EQ(client.num_actions_(), 2);
- EXPECT_TRUE(client.HasAction("SetNeedsBeginImplFrame"));
- EXPECT_TRUE(client.HasAction("ScheduledActionSendBeginMainFrame"));
- }
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
client.Reset();
- scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
- if (deadline_scheduling_enabled) {
- EXPECT_EQ(client.num_actions_(), 2);
- EXPECT_TRUE(client.HasAction("ScheduledActionSendBeginMainFrame"));
- EXPECT_TRUE(client.HasAction("PostBeginImplFrameDeadlineTask"));
- } else {
- EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
- }
+ scheduler->BeginFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_TRUE(client.needs_begin_impl_frame());
+ EXPECT_TRUE(client.needs_begin_frame());
client.Reset();
// Now SetNeedsCommit again. Calling here means we need a second commit.
@@ -328,358 +391,54 @@ void RequestCommitAfterBeginMainFrameSent(
client.Reset();
// Finish the first commit.
- scheduler->FinishCommit();
- EXPECT_ACTION("ScheduledActionCommit", client, 0, 2);
- EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2);
- client.Reset();
- scheduler->OnBeginImplFrameDeadline();
- if (deadline_scheduling_enabled) {
- EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2);
- EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2);
- } else {
- EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 3);
- EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 3);
- EXPECT_ACTION("SetNeedsBeginImplFrame", client, 2, 3);
- }
+ scheduler->NotifyBeginMainFrameStarted();
+ scheduler->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+ client.Reset();
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
+ EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
// Because we just swapped, the Scheduler should also request the next
// BeginImplFrame from the OutputSurface.
- EXPECT_TRUE(client.needs_begin_impl_frame());
+ EXPECT_TRUE(client.needs_begin_frame());
client.Reset();
-
// Since another commit is needed, the next BeginImplFrame should initiate
// the second commit.
- scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
- if (deadline_scheduling_enabled) {
- EXPECT_EQ(client.num_actions_(), 2);
- EXPECT_TRUE(client.HasAction("ScheduledActionSendBeginMainFrame"));
- EXPECT_TRUE(client.HasAction("PostBeginImplFrameDeadlineTask"));
- } else {
- EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
- }
+ scheduler->BeginFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
client.Reset();
// Finishing the commit before the deadline should post a new deadline task
// to trigger the deadline early.
- scheduler->FinishCommit();
- EXPECT_ACTION("ScheduledActionCommit", client, 0, 2);
- EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2);
+ scheduler->NotifyBeginMainFrameStarted();
+ scheduler->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
client.Reset();
- scheduler->OnBeginImplFrameDeadline();
- EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2);
- EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2);
- EXPECT_TRUE(client.needs_begin_impl_frame());
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
+ EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client.needs_begin_frame());
client.Reset();
// On the next BeginImplFrame, verify we go back to a quiescent state and
// no longer request BeginImplFrames.
- scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
- scheduler->OnBeginImplFrameDeadline();
- EXPECT_FALSE(client.needs_begin_impl_frame());
- client.Reset();
-}
-
-TEST(SchedulerTest, RequestCommitAfterBeginMainFrameSent) {
- bool deadline_scheduling_enabled = false;
- RequestCommitAfterBeginMainFrameSent(deadline_scheduling_enabled);
-}
-
-TEST(SchedulerTest, RequestCommitAfterBeginMainFrameSent_Deadline) {
- bool deadline_scheduling_enabled = true;
- RequestCommitAfterBeginMainFrameSent(deadline_scheduling_enabled);
-}
-
-void TextureAcquisitionCausesCommitInsteadOfDraw(
- bool deadline_scheduling_enabled) {
- FakeSchedulerClient client;
- SchedulerSettings scheduler_settings;
- scheduler_settings.deadline_scheduling_enabled = deadline_scheduling_enabled;
- Scheduler* scheduler = client.CreateScheduler(scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
- EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
-
- InitializeOutputSurfaceAndFirstCommit(scheduler);
- client.Reset();
- scheduler->SetNeedsRedraw();
- EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
- EXPECT_TRUE(client.needs_begin_impl_frame());
-
- client.Reset();
- scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
- EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
- client.Reset();
- scheduler->OnBeginImplFrameDeadline();
- EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2);
- EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2);
- EXPECT_FALSE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_impl_frame());
-
- client.Reset();
- scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
- EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
- client.Reset();
- scheduler->OnBeginImplFrameDeadline();
- EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
- EXPECT_FALSE(scheduler->RedrawPending());
- EXPECT_FALSE(client.needs_begin_impl_frame());
-
- client.Reset();
- scheduler->SetMainThreadNeedsLayerTextures();
- EXPECT_SINGLE_ACTION("ScheduledActionAcquireLayerTexturesForMainThread",
- client);
-
- // We should request a BeginImplFrame in anticipation of a draw.
- client.Reset();
- scheduler->SetNeedsRedraw();
- EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
- EXPECT_TRUE(client.needs_begin_impl_frame());
-
- // No draw happens since the textures are acquired by the main thread.
- client.Reset();
- scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
- EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
+ scheduler->BeginFrame(CreateBeginFrameArgsForTesting());
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_FALSE(client.needs_begin_frame());
client.Reset();
- scheduler->OnBeginImplFrameDeadline();
- EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
- EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_impl_frame());
-
- client.Reset();
- scheduler->SetNeedsCommit();
- if (deadline_scheduling_enabled) {
- EXPECT_EQ(0, client.num_actions_());
- } else {
- EXPECT_SINGLE_ACTION("ScheduledActionSendBeginMainFrame", client);
- }
-
- client.Reset();
- scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
- if (deadline_scheduling_enabled) {
- EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2);
- EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2);
- } else {
- EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
- }
-
- // Commit will release the texture.
- client.Reset();
- scheduler->FinishCommit();
- EXPECT_ACTION("ScheduledActionCommit", client, 0, 2);
- EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2);
- EXPECT_TRUE(scheduler->RedrawPending());
-
- // Now we can draw again after the commit happens.
- client.Reset();
- scheduler->OnBeginImplFrameDeadline();
- EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2);
- EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2);
- EXPECT_FALSE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_impl_frame());
-
- // Make sure we stop requesting BeginImplFrames if we don't swap.
- client.Reset();
- scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
- EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
- client.Reset();
- scheduler->OnBeginImplFrameDeadline();
- EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
- EXPECT_FALSE(client.needs_begin_impl_frame());
-}
-
-TEST(SchedulerTest, TextureAcquisitionCausesCommitInsteadOfDraw) {
- bool deadline_scheduling_enabled = false;
- TextureAcquisitionCausesCommitInsteadOfDraw(deadline_scheduling_enabled);
-}
-
-TEST(SchedulerTest, TextureAcquisitionCausesCommitInsteadOfDraw_Deadline) {
- bool deadline_scheduling_enabled = true;
- TextureAcquisitionCausesCommitInsteadOfDraw(deadline_scheduling_enabled);
-}
-
-void TextureAcquisitionCollision(bool deadline_scheduling_enabled) {
- FakeSchedulerClient client;
- SchedulerSettings scheduler_settings;
- scheduler_settings.deadline_scheduling_enabled = deadline_scheduling_enabled;
- Scheduler* scheduler = client.CreateScheduler(scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
-
- EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
- InitializeOutputSurfaceAndFirstCommit(scheduler);
-
- client.Reset();
- scheduler->SetNeedsCommit();
-if (deadline_scheduling_enabled) {
- EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
- } else {
- EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2);
- EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2);
- }
-
- client.Reset();
- scheduler->SetMainThreadNeedsLayerTextures();
- EXPECT_SINGLE_ACTION(
- "ScheduledActionAcquireLayerTexturesForMainThread", client);
-
- client.Reset();
- scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
- if (deadline_scheduling_enabled) {
- EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2);
- EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2);
- } else {
- EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
- }
-
- client.Reset();
- scheduler->OnBeginImplFrameDeadline();
- EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
-
- // Although the compositor cannot draw because textures are locked by main
- // thread, we continue requesting SetNeedsBeginImplFrame in anticipation of
- // the unlock.
- EXPECT_TRUE(client.needs_begin_impl_frame());
-
- // Trigger the commit
- scheduler->FinishCommit();
- EXPECT_TRUE(client.needs_begin_impl_frame());
-
- // Between commit and draw, texture acquisition for main thread delayed,
- // and main thread blocks.
- client.Reset();
- scheduler->SetMainThreadNeedsLayerTextures();
- EXPECT_EQ(0, client.num_actions_());
-
- // No implicit commit is expected.
- client.Reset();
- scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
- EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
-
- client.Reset();
- scheduler->OnBeginImplFrameDeadline();
- EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 3);
- EXPECT_ACTION(
- "ScheduledActionAcquireLayerTexturesForMainThread", client, 1, 3);
- EXPECT_ACTION("SetNeedsBeginImplFrame", client, 2, 3);
- EXPECT_TRUE(client.needs_begin_impl_frame());
-
- // The compositor should not draw because textures are locked by main
- // thread.
- client.Reset();
- scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
- EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
- client.Reset();
- scheduler->OnBeginImplFrameDeadline();
- EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
- EXPECT_FALSE(client.needs_begin_impl_frame());
-
- // The impl thread need an explicit commit from the main thread to lock
- // the textures.
- client.Reset();
- scheduler->SetNeedsCommit();
- if (deadline_scheduling_enabled) {
- EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);
- } else {
- EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2);
- EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2);
- }
- EXPECT_TRUE(client.needs_begin_impl_frame());
-
- client.Reset();
- scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
- if (deadline_scheduling_enabled) {
- EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2);
- EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2);
- } else {
- EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
- }
- client.Reset();
-
- // Trigger the commit, which will trigger the deadline task early.
- scheduler->FinishCommit();
- EXPECT_ACTION("ScheduledActionCommit", client, 0, 2);
- EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2);
- EXPECT_TRUE(client.needs_begin_impl_frame());
- client.Reset();
-
- // Verify we draw on the next BeginImplFrame deadline
- scheduler->OnBeginImplFrameDeadline();
- EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 2);
- EXPECT_ACTION("SetNeedsBeginImplFrame", client, 1, 2);
- EXPECT_TRUE(client.needs_begin_impl_frame());
- client.Reset();
-}
-
-TEST(SchedulerTest, TextureAcquisitionCollision) {
- bool deadline_scheduling_enabled = false;
- TextureAcquisitionCollision(deadline_scheduling_enabled);
-}
-
-TEST(SchedulerTest, TextureAcquisitionCollision_Deadline) {
- bool deadline_scheduling_enabled = true;
- TextureAcquisitionCollision(deadline_scheduling_enabled);
-}
-
-void VisibilitySwitchWithTextureAcquisition(bool deadline_scheduling_enabled) {
- FakeSchedulerClient client;
- SchedulerSettings scheduler_settings;
- scheduler_settings.deadline_scheduling_enabled = deadline_scheduling_enabled;
- Scheduler* scheduler = client.CreateScheduler(scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
-
- EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
- client.Reset();
- scheduler->DidCreateAndInitializeOutputSurface();
-
- scheduler->SetNeedsCommit();
- if (deadline_scheduling_enabled) {
- scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
- scheduler->OnBeginImplFrameDeadline();
- }
- scheduler->FinishCommit();
- scheduler->SetMainThreadNeedsLayerTextures();
- scheduler->SetNeedsCommit();
- client.Reset();
- // Verify that pending texture acquisition fires when visibility
- // is lost in order to avoid a deadlock.
- scheduler->SetVisible(false);
- EXPECT_SINGLE_ACTION("ScheduledActionAcquireLayerTexturesForMainThread",
- client);
-
- client.Reset();
- scheduler->SetVisible(true);
- EXPECT_EQ(0, client.num_actions_());
- EXPECT_TRUE(client.needs_begin_impl_frame());
-
- // Regaining visibility with textures acquired by main thread while
- // compositor is waiting for first draw should result in a request
- // for a new frame in order to escape a deadlock.
- client.Reset();
- scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
- EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 2);
- EXPECT_ACTION("PostBeginImplFrameDeadlineTask", client, 1, 2);
-}
-
-TEST(SchedulerTest, VisibilitySwitchWithTextureAcquisition) {
- bool deadline_scheduling_enabled = false;
- VisibilitySwitchWithTextureAcquisition(deadline_scheduling_enabled);
-}
-
-TEST(SchedulerTest, VisibilitySwitchWithTextureAcquisition_Deadline) {
- bool deadline_scheduling_enabled = true;
- VisibilitySwitchWithTextureAcquisition(deadline_scheduling_enabled);
}
class SchedulerClientThatsetNeedsDrawInsideDraw : public FakeSchedulerClient {
public:
virtual void ScheduledActionSendBeginMainFrame() OVERRIDE {}
- virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapIfPossible()
+ virtual DrawResult ScheduledActionDrawAndSwapIfPossible()
OVERRIDE {
// Only SetNeedsRedraw the first time this is called
if (!num_draws_)
@@ -687,12 +446,9 @@ class SchedulerClientThatsetNeedsDrawInsideDraw : public FakeSchedulerClient {
return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible();
}
- virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapForced() OVERRIDE {
+ virtual DrawResult ScheduledActionDrawAndSwapForced() OVERRIDE {
NOTREACHED();
- bool did_draw = true;
- bool did_swap = true;
- bool did_readback = false;
- return DrawSwapReadbackResult(did_draw, did_swap, did_readback);
+ return DRAW_SUCCESS;
}
virtual void ScheduledActionCommit() OVERRIDE {}
@@ -707,84 +463,84 @@ class SchedulerClientThatsetNeedsDrawInsideDraw : public FakeSchedulerClient {
TEST(SchedulerTest, RequestRedrawInsideDraw) {
SchedulerClientThatsetNeedsDrawInsideDraw client;
SchedulerSettings default_scheduler_settings;
- Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+ TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
- InitializeOutputSurfaceAndFirstCommit(scheduler);
+ InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
client.Reset();
scheduler->SetNeedsRedraw();
EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_impl_frame());
+ EXPECT_TRUE(client.needs_begin_frame());
EXPECT_EQ(0, client.num_draws());
- scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
- scheduler->OnBeginImplFrameDeadline();
+ scheduler->BeginFrame(CreateBeginFrameArgsForTesting());
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(1, client.num_draws());
EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_impl_frame());
+ EXPECT_TRUE(client.needs_begin_frame());
- scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
- scheduler->OnBeginImplFrameDeadline();
+ scheduler->BeginFrame(CreateBeginFrameArgsForTesting());
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(2, client.num_draws());
EXPECT_FALSE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_impl_frame());
+ EXPECT_TRUE(client.needs_begin_frame());
// We stop requesting BeginImplFrames after a BeginImplFrame where we don't
// swap.
- scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
- scheduler->OnBeginImplFrameDeadline();
+ scheduler->BeginFrame(CreateBeginFrameArgsForTesting());
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(2, client.num_draws());
EXPECT_FALSE(scheduler->RedrawPending());
- EXPECT_FALSE(client.needs_begin_impl_frame());
+ EXPECT_FALSE(client.needs_begin_frame());
}
// Test that requesting redraw inside a failed draw doesn't lose the request.
TEST(SchedulerTest, RequestRedrawInsideFailedDraw) {
SchedulerClientThatsetNeedsDrawInsideDraw client;
SchedulerSettings default_scheduler_settings;
- Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+ TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
- InitializeOutputSurfaceAndFirstCommit(scheduler);
+ InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
client.Reset();
client.SetDrawWillHappen(false);
scheduler->SetNeedsRedraw();
EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_impl_frame());
+ EXPECT_TRUE(client.needs_begin_frame());
EXPECT_EQ(0, client.num_draws());
// Fail the draw.
- scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
- scheduler->OnBeginImplFrameDeadline();
+ scheduler->BeginFrame(CreateBeginFrameArgsForTesting());
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(1, client.num_draws());
// We have a commit pending and the draw failed, and we didn't lose the redraw
// request.
EXPECT_TRUE(scheduler->CommitPending());
EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_impl_frame());
+ EXPECT_TRUE(client.needs_begin_frame());
// Fail the draw again.
- scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
- scheduler->OnBeginImplFrameDeadline();
+ scheduler->BeginFrame(CreateBeginFrameArgsForTesting());
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(2, client.num_draws());
EXPECT_TRUE(scheduler->CommitPending());
EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_impl_frame());
+ EXPECT_TRUE(client.needs_begin_frame());
// Draw successfully.
client.SetDrawWillHappen(true);
- scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
- scheduler->OnBeginImplFrameDeadline();
+ scheduler->BeginFrame(CreateBeginFrameArgsForTesting());
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(3, client.num_draws());
EXPECT_TRUE(scheduler->CommitPending());
EXPECT_FALSE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_impl_frame());
+ EXPECT_TRUE(client.needs_begin_frame());
}
class SchedulerClientThatSetNeedsCommitInsideDraw : public FakeSchedulerClient {
@@ -793,7 +549,7 @@ class SchedulerClientThatSetNeedsCommitInsideDraw : public FakeSchedulerClient {
: set_needs_commit_on_next_draw_(false) {}
virtual void ScheduledActionSendBeginMainFrame() OVERRIDE {}
- virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapIfPossible()
+ virtual DrawResult ScheduledActionDrawAndSwapIfPossible()
OVERRIDE {
// Only SetNeedsCommit the first time this is called
if (set_needs_commit_on_next_draw_) {
@@ -803,12 +559,9 @@ class SchedulerClientThatSetNeedsCommitInsideDraw : public FakeSchedulerClient {
return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible();
}
- virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapForced() OVERRIDE {
+ virtual DrawResult ScheduledActionDrawAndSwapForced() OVERRIDE {
NOTREACHED();
- bool did_draw = true;
- bool did_swap = false;
- bool did_readback = false;
- return DrawSwapReadbackResult(did_draw, did_swap, did_readback);
+ return DRAW_SUCCESS;
}
virtual void ScheduledActionCommit() OVERRIDE {}
@@ -826,172 +579,131 @@ class SchedulerClientThatSetNeedsCommitInsideDraw : public FakeSchedulerClient {
TEST(SchedulerTest, RequestCommitInsideDraw) {
SchedulerClientThatSetNeedsCommitInsideDraw client;
SchedulerSettings default_scheduler_settings;
- Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+ TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
- InitializeOutputSurfaceAndFirstCommit(scheduler);
+ InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
client.Reset();
- EXPECT_FALSE(client.needs_begin_impl_frame());
+ EXPECT_FALSE(client.needs_begin_frame());
scheduler->SetNeedsRedraw();
EXPECT_TRUE(scheduler->RedrawPending());
EXPECT_EQ(0, client.num_draws());
- EXPECT_TRUE(client.needs_begin_impl_frame());
+ EXPECT_TRUE(client.needs_begin_frame());
client.SetNeedsCommitOnNextDraw();
- scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
+ scheduler->BeginFrame(CreateBeginFrameArgsForTesting());
client.SetNeedsCommitOnNextDraw();
- scheduler->OnBeginImplFrameDeadline();
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(1, client.num_draws());
EXPECT_TRUE(scheduler->CommitPending());
- EXPECT_TRUE(client.needs_begin_impl_frame());
- scheduler->FinishCommit();
+ EXPECT_TRUE(client.needs_begin_frame());
+ scheduler->NotifyBeginMainFrameStarted();
+ scheduler->NotifyReadyToCommit();
- scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
- scheduler->OnBeginImplFrameDeadline();
+ scheduler->BeginFrame(CreateBeginFrameArgsForTesting());
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(2, client.num_draws());
EXPECT_FALSE(scheduler->RedrawPending());
EXPECT_FALSE(scheduler->CommitPending());
- EXPECT_TRUE(client.needs_begin_impl_frame());
+ EXPECT_TRUE(client.needs_begin_frame());
// We stop requesting BeginImplFrames after a BeginImplFrame where we don't
// swap.
- scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
- scheduler->OnBeginImplFrameDeadline();
+ scheduler->BeginFrame(CreateBeginFrameArgsForTesting());
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(2, client.num_draws());
EXPECT_FALSE(scheduler->RedrawPending());
EXPECT_FALSE(scheduler->CommitPending());
- EXPECT_FALSE(client.needs_begin_impl_frame());
+ EXPECT_FALSE(client.needs_begin_frame());
}
// Tests that when a draw fails then the pending commit should not be dropped.
TEST(SchedulerTest, RequestCommitInsideFailedDraw) {
SchedulerClientThatsetNeedsDrawInsideDraw client;
SchedulerSettings default_scheduler_settings;
- Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+ TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
- InitializeOutputSurfaceAndFirstCommit(scheduler);
+ InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
client.Reset();
client.SetDrawWillHappen(false);
scheduler->SetNeedsRedraw();
EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_impl_frame());
+ EXPECT_TRUE(client.needs_begin_frame());
EXPECT_EQ(0, client.num_draws());
// Fail the draw.
- scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
- scheduler->OnBeginImplFrameDeadline();
+ scheduler->BeginFrame(CreateBeginFrameArgsForTesting());
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(1, client.num_draws());
// We have a commit pending and the draw failed, and we didn't lose the commit
// request.
EXPECT_TRUE(scheduler->CommitPending());
EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_impl_frame());
+ EXPECT_TRUE(client.needs_begin_frame());
// Fail the draw again.
- scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
- scheduler->OnBeginImplFrameDeadline();
+ scheduler->BeginFrame(CreateBeginFrameArgsForTesting());
+
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(2, client.num_draws());
EXPECT_TRUE(scheduler->CommitPending());
EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_impl_frame());
+ EXPECT_TRUE(client.needs_begin_frame());
// Draw successfully.
client.SetDrawWillHappen(true);
- scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
- scheduler->OnBeginImplFrameDeadline();
+ scheduler->BeginFrame(CreateBeginFrameArgsForTesting());
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(3, client.num_draws());
EXPECT_TRUE(scheduler->CommitPending());
EXPECT_FALSE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_impl_frame());
+ EXPECT_TRUE(client.needs_begin_frame());
}
TEST(SchedulerTest, NoSwapWhenDrawFails) {
SchedulerClientThatSetNeedsCommitInsideDraw client;
SchedulerSettings default_scheduler_settings;
- Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+ TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
- InitializeOutputSurfaceAndFirstCommit(scheduler);
+ InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
client.Reset();
scheduler->SetNeedsRedraw();
EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_impl_frame());
+ EXPECT_TRUE(client.needs_begin_frame());
EXPECT_EQ(0, client.num_draws());
// Draw successfully, this starts a new frame.
client.SetNeedsCommitOnNextDraw();
- scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
- scheduler->OnBeginImplFrameDeadline();
+ scheduler->BeginFrame(CreateBeginFrameArgsForTesting());
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(1, client.num_draws());
scheduler->SetNeedsRedraw();
EXPECT_TRUE(scheduler->RedrawPending());
- EXPECT_TRUE(client.needs_begin_impl_frame());
+ EXPECT_TRUE(client.needs_begin_frame());
// Fail to draw, this should not start a frame.
client.SetDrawWillHappen(false);
client.SetNeedsCommitOnNextDraw();
- scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
- scheduler->OnBeginImplFrameDeadline();
+ scheduler->BeginFrame(CreateBeginFrameArgsForTesting());
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(2, client.num_draws());
}
-TEST(SchedulerTest, NoSwapWhenSwapFailsDuringForcedCommit) {
- FakeSchedulerClient client;
- SchedulerSettings default_scheduler_settings;
- Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
-
- // Tell the client that it will fail to swap.
- client.SetDrawWillHappen(true);
- client.SetSwapWillHappenIfDrawHappens(false);
-
- // Get the compositor to do a ScheduledActionDrawAndReadback.
- scheduler->SetCanDraw(true);
- scheduler->SetNeedsRedraw();
- scheduler->SetNeedsForcedCommitForReadback();
- scheduler->FinishCommit();
- EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndReadback"));
-}
-
-TEST(SchedulerTest, BackToBackReadbackAllowed) {
- // Some clients call readbacks twice in a row before the replacement
- // commit comes in. Make sure it is allowed.
- FakeSchedulerClient client;
- SchedulerSettings default_scheduler_settings;
- Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
-
- // Get the compositor to do 2 ScheduledActionDrawAndReadbacks before
- // the replacement commit comes in.
- scheduler->SetCanDraw(true);
- scheduler->SetNeedsRedraw();
- scheduler->SetNeedsForcedCommitForReadback();
- scheduler->FinishCommit();
- EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndReadback"));
-
- client.Reset();
- scheduler->SetNeedsForcedCommitForReadback();
- scheduler->FinishCommit();
- EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndReadback"));
-
- // The replacement commit comes in after 2 readbacks.
- client.Reset();
- scheduler->FinishCommit();
-}
-
-
class SchedulerClientNeedsManageTilesInDraw : public FakeSchedulerClient {
public:
- virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapIfPossible()
+ virtual DrawResult ScheduledActionDrawAndSwapIfPossible()
OVERRIDE {
scheduler_->SetNeedsManageTiles();
return FakeSchedulerClient::ScheduledActionDrawAndSwapIfPossible();
@@ -1002,11 +714,11 @@ class SchedulerClientNeedsManageTilesInDraw : public FakeSchedulerClient {
TEST(SchedulerTest, ManageTiles) {
SchedulerClientNeedsManageTilesInDraw client;
SchedulerSettings default_scheduler_settings;
- Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+ TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
- InitializeOutputSurfaceAndFirstCommit(scheduler);
+ InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
// Request both draw and manage tiles. ManageTiles shouldn't
// be trigged until BeginImplFrame.
@@ -1015,7 +727,7 @@ TEST(SchedulerTest, ManageTiles) {
scheduler->SetNeedsRedraw();
EXPECT_TRUE(scheduler->RedrawPending());
EXPECT_TRUE(scheduler->ManageTilesPending());
- EXPECT_TRUE(client.needs_begin_impl_frame());
+ EXPECT_TRUE(client.needs_begin_frame());
EXPECT_EQ(0, client.num_draws());
EXPECT_FALSE(client.HasAction("ScheduledActionManageTiles"));
EXPECT_FALSE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
@@ -1023,12 +735,14 @@ TEST(SchedulerTest, ManageTiles) {
// We have no immediate actions to perform, so the BeginImplFrame should post
// the deadline task.
client.Reset();
- scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
- EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
+ scheduler->BeginFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
// On the deadline, he actions should have occured in the right order.
client.Reset();
- scheduler->OnBeginImplFrameDeadline();
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(1, client.num_draws());
EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles"));
@@ -1036,26 +750,29 @@ TEST(SchedulerTest, ManageTiles) {
client.ActionIndex("ScheduledActionManageTiles"));
EXPECT_FALSE(scheduler->RedrawPending());
EXPECT_FALSE(scheduler->ManageTilesPending());
+ EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
// Request a draw. We don't need a ManageTiles yet.
client.Reset();
scheduler->SetNeedsRedraw();
EXPECT_TRUE(scheduler->RedrawPending());
EXPECT_FALSE(scheduler->ManageTilesPending());
- EXPECT_TRUE(client.needs_begin_impl_frame());
+ EXPECT_TRUE(client.needs_begin_frame());
EXPECT_EQ(0, client.num_draws());
// We have no immediate actions to perform, so the BeginImplFrame should post
// the deadline task.
client.Reset();
- scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
- EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
+ scheduler->BeginFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
// Draw. The draw will trigger SetNeedsManageTiles, and
// then the ManageTiles action will be triggered after the Draw.
// Afterwards, neither a draw nor ManageTiles are pending.
client.Reset();
- scheduler->OnBeginImplFrameDeadline();
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(1, client.num_draws());
EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles"));
@@ -1063,75 +780,86 @@ TEST(SchedulerTest, ManageTiles) {
client.ActionIndex("ScheduledActionManageTiles"));
EXPECT_FALSE(scheduler->RedrawPending());
EXPECT_FALSE(scheduler->ManageTilesPending());
+ EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
// We need a BeginImplFrame where we don't swap to go idle.
client.Reset();
- scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
- EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
+ scheduler->BeginFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_SINGLE_ACTION("WillBeginImplFrame", client);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
client.Reset();
- scheduler->OnBeginImplFrameDeadline();
- EXPECT_SINGLE_ACTION("SetNeedsBeginImplFrame", client);;
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
+ EXPECT_FALSE(client.needs_begin_frame());
+ EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
EXPECT_EQ(0, client.num_draws());
// Now trigger a ManageTiles outside of a draw. We will then need
// a begin-frame for the ManageTiles, but we don't need a draw.
client.Reset();
- EXPECT_FALSE(client.needs_begin_impl_frame());
+ EXPECT_FALSE(client.needs_begin_frame());
scheduler->SetNeedsManageTiles();
- EXPECT_TRUE(client.needs_begin_impl_frame());
+ EXPECT_TRUE(client.needs_begin_frame());
EXPECT_TRUE(scheduler->ManageTilesPending());
EXPECT_FALSE(scheduler->RedrawPending());
// BeginImplFrame. There will be no draw, only ManageTiles.
client.Reset();
- scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
- EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
+ scheduler->BeginFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_SINGLE_ACTION("WillBeginImplFrame", client);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
client.Reset();
- scheduler->OnBeginImplFrameDeadline();
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(0, client.num_draws());
EXPECT_FALSE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles"));
+ EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
}
// Test that ManageTiles only happens once per frame. If an external caller
-// initiates it, then the state machine should not on that frame.
+// initiates it, then the state machine should not ManageTiles on that frame.
TEST(SchedulerTest, ManageTilesOncePerFrame) {
FakeSchedulerClient client;
SchedulerSettings default_scheduler_settings;
- Scheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+ TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
- InitializeOutputSurfaceAndFirstCommit(scheduler);
+ InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
// If DidManageTiles during a frame, then ManageTiles should not occur again.
scheduler->SetNeedsManageTiles();
scheduler->SetNeedsRedraw();
client.Reset();
- scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
- EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
+ scheduler->BeginFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
EXPECT_TRUE(scheduler->ManageTilesPending());
- scheduler->DidManageTiles();
+ scheduler->DidManageTiles(); // An explicit ManageTiles.
EXPECT_FALSE(scheduler->ManageTilesPending());
client.Reset();
- scheduler->OnBeginImplFrameDeadline();
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(1, client.num_draws());
EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
EXPECT_FALSE(client.HasAction("ScheduledActionManageTiles"));
EXPECT_FALSE(scheduler->RedrawPending());
EXPECT_FALSE(scheduler->ManageTilesPending());
+ EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
// Next frame without DidManageTiles should ManageTiles with draw.
scheduler->SetNeedsManageTiles();
scheduler->SetNeedsRedraw();
client.Reset();
- scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
- EXPECT_SINGLE_ACTION("PostBeginImplFrameDeadlineTask", client);
+ scheduler->BeginFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
client.Reset();
- scheduler->OnBeginImplFrameDeadline();
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(1, client.num_draws());
EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles"));
@@ -1139,6 +867,153 @@ TEST(SchedulerTest, ManageTilesOncePerFrame) {
client.ActionIndex("ScheduledActionManageTiles"));
EXPECT_FALSE(scheduler->RedrawPending());
EXPECT_FALSE(scheduler->ManageTilesPending());
+ EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+ scheduler->DidManageTiles(); // Corresponds to ScheduledActionManageTiles
+
+ // If we get another DidManageTiles within the same frame, we should
+ // not ManageTiles on the next frame.
+ scheduler->DidManageTiles(); // An explicit ManageTiles.
+ scheduler->SetNeedsManageTiles();
+ scheduler->SetNeedsRedraw();
+ client.Reset();
+ scheduler->BeginFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+
+ EXPECT_TRUE(scheduler->ManageTilesPending());
+
+ client.Reset();
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(1, client.num_draws());
+ EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
+ EXPECT_FALSE(client.HasAction("ScheduledActionManageTiles"));
+ EXPECT_FALSE(scheduler->RedrawPending());
+ EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+
+ // If we get another DidManageTiles, we should not ManageTiles on the next
+ // frame. This verifies we don't alternate calling ManageTiles once and twice.
+ EXPECT_TRUE(scheduler->ManageTilesPending());
+ scheduler->DidManageTiles(); // An explicit ManageTiles.
+ EXPECT_FALSE(scheduler->ManageTilesPending());
+ scheduler->SetNeedsManageTiles();
+ scheduler->SetNeedsRedraw();
+ client.Reset();
+ scheduler->BeginFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+
+ EXPECT_TRUE(scheduler->ManageTilesPending());
+
+ client.Reset();
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(1, client.num_draws());
+ EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
+ EXPECT_FALSE(client.HasAction("ScheduledActionManageTiles"));
+ EXPECT_FALSE(scheduler->RedrawPending());
+ EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+
+ // Next frame without DidManageTiles should ManageTiles with draw.
+ scheduler->SetNeedsManageTiles();
+ scheduler->SetNeedsRedraw();
+ client.Reset();
+ scheduler->BeginFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+
+ client.Reset();
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_EQ(1, client.num_draws());
+ EXPECT_TRUE(client.HasAction("ScheduledActionDrawAndSwapIfPossible"));
+ EXPECT_TRUE(client.HasAction("ScheduledActionManageTiles"));
+ EXPECT_LT(client.ActionIndex("ScheduledActionDrawAndSwapIfPossible"),
+ client.ActionIndex("ScheduledActionManageTiles"));
+ EXPECT_FALSE(scheduler->RedrawPending());
+ EXPECT_FALSE(scheduler->ManageTilesPending());
+ EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+ scheduler->DidManageTiles(); // Corresponds to ScheduledActionManageTiles
+}
+
+TEST(SchedulerTest, ShouldUpdateVisibleTiles) {
+ FakeSchedulerClient client;
+ SchedulerSettings scheduler_settings;
+ scheduler_settings.impl_side_painting = true;
+ TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
+ scheduler->SetCanStart();
+ scheduler->SetVisible(true);
+ scheduler->SetCanDraw(true);
+ InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+
+ client.SetRedrawWillHappenIfUpdateVisibleTilesHappens(true);
+
+ // SetNeedsCommit should begin the frame.
+ client.Reset();
+ scheduler->SetNeedsCommit();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
+
+ client.Reset();
+ scheduler->BeginFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+
+ client.Reset();
+ scheduler->NotifyBeginMainFrameStarted();
+ scheduler->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
+
+ client.Reset();
+ scheduler->NotifyReadyToActivate();
+ EXPECT_SINGLE_ACTION("ScheduledActionActivatePendingTree", client);
+
+ client.Reset();
+ client.SetSwapContainsIncompleteTile(true);
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
+ EXPECT_FALSE(scheduler->RedrawPending());
+
+ client.Reset();
+ scheduler->BeginFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_SINGLE_ACTION("WillBeginImplFrame", client);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+
+ client.Reset();
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_ACTION("ScheduledActionUpdateVisibleTiles", client, 0, 3);
+ EXPECT_ACTION("ScheduledActionAnimate", client, 1, 3);
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 2, 3);
+
+ client.Reset();
+ scheduler->BeginFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_SINGLE_ACTION("WillBeginImplFrame", client);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+
+ // No more UpdateVisibleTiles().
+ client.Reset();
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
+ EXPECT_FALSE(client.needs_begin_frame());
+}
+
+TEST(SchedulerTest, TriggerBeginFrameDeadlineEarly) {
+ SchedulerClientNeedsManageTilesInDraw client;
+ SchedulerSettings default_scheduler_settings;
+ TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+ scheduler->SetCanStart();
+ scheduler->SetVisible(true);
+ scheduler->SetCanDraw(true);
+ InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+
+ client.Reset();
+ scheduler->SetNeedsRedraw();
+ scheduler->BeginFrame(CreateBeginFrameArgsForTesting());
+
+ // The deadline should be zero since there is no work other than drawing
+ // pending.
+ EXPECT_EQ(base::TimeTicks(), client.posted_begin_impl_frame_deadline());
}
class SchedulerClientWithFixedEstimates : public FakeSchedulerClient {
@@ -1170,6 +1045,7 @@ class SchedulerClientWithFixedEstimates : public FakeSchedulerClient {
void MainFrameInHighLatencyMode(int64 begin_main_frame_to_commit_estimate_in_ms,
int64 commit_to_activate_estimate_in_ms,
+ bool smoothness_takes_priority,
bool should_send_begin_main_frame) {
// Set up client with specified estimates (draw duration is set to 1).
SchedulerClientWithFixedEstimates client(
@@ -1177,33 +1053,33 @@ void MainFrameInHighLatencyMode(int64 begin_main_frame_to_commit_estimate_in_ms,
base::TimeDelta::FromMilliseconds(
begin_main_frame_to_commit_estimate_in_ms),
base::TimeDelta::FromMilliseconds(commit_to_activate_estimate_in_ms));
- SchedulerSettings scheduler_settings;
- scheduler_settings.deadline_scheduling_enabled = true;
- scheduler_settings.switch_to_low_latency_if_possible = true;
- Scheduler* scheduler = client.CreateScheduler(scheduler_settings);
+ SchedulerSettings default_scheduler_settings;
+ TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
- InitializeOutputSurfaceAndFirstCommit(scheduler);
+ scheduler->SetSmoothnessTakesPriority(smoothness_takes_priority);
+ InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
// Impl thread hits deadline before commit finishes.
client.Reset();
scheduler->SetNeedsCommit();
EXPECT_FALSE(scheduler->MainThreadIsInHighLatencyMode());
- scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
+ scheduler->BeginFrame(CreateBeginFrameArgsForTesting());
EXPECT_FALSE(scheduler->MainThreadIsInHighLatencyMode());
- scheduler->OnBeginImplFrameDeadline();
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_TRUE(scheduler->MainThreadIsInHighLatencyMode());
- scheduler->FinishCommit();
+ scheduler->NotifyBeginMainFrameStarted();
+ scheduler->NotifyReadyToCommit();
EXPECT_TRUE(scheduler->MainThreadIsInHighLatencyMode());
EXPECT_TRUE(client.HasAction("ScheduledActionSendBeginMainFrame"));
client.Reset();
scheduler->SetNeedsCommit();
EXPECT_TRUE(scheduler->MainThreadIsInHighLatencyMode());
- scheduler->BeginImplFrame(BeginFrameArgs::CreateForTesting());
+ scheduler->BeginFrame(CreateBeginFrameArgsForTesting());
EXPECT_TRUE(scheduler->MainThreadIsInHighLatencyMode());
- scheduler->OnBeginImplFrameDeadline();
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_EQ(scheduler->MainThreadIsInHighLatencyMode(),
should_send_begin_main_frame);
EXPECT_EQ(client.HasAction("ScheduledActionSendBeginMainFrame"),
@@ -1214,36 +1090,38 @@ TEST(SchedulerTest,
SkipMainFrameIfHighLatencyAndCanCommitAndActivateBeforeDeadline) {
// Set up client so that estimates indicate that we can commit and activate
// before the deadline (~8ms by default).
- MainFrameInHighLatencyMode(1, 1, false);
+ MainFrameInHighLatencyMode(1, 1, false, false);
}
TEST(SchedulerTest, NotSkipMainFrameIfHighLatencyAndCanCommitTooLong) {
// Set up client so that estimates indicate that the commit cannot finish
// before the deadline (~8ms by default).
- MainFrameInHighLatencyMode(10, 1, true);
+ MainFrameInHighLatencyMode(10, 1, false, true);
}
TEST(SchedulerTest, NotSkipMainFrameIfHighLatencyAndCanActivateTooLong) {
// Set up client so that estimates indicate that the activate cannot finish
// before the deadline (~8ms by default).
- MainFrameInHighLatencyMode(1, 10, true);
+ MainFrameInHighLatencyMode(1, 10, false, true);
}
-void SpinForMillis(int millis) {
- base::RunLoop run_loop;
- base::MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- run_loop.QuitClosure(),
- base::TimeDelta::FromMilliseconds(millis));
- run_loop.Run();
+TEST(SchedulerTest, NotSkipMainFrameInPreferSmoothnessMode) {
+ // Set up client so that estimates indicate that we can commit and activate
+ // before the deadline (~8ms by default), but also enable smoothness takes
+ // priority mode.
+ MainFrameInHighLatencyMode(1, 1, true, true);
}
TEST(SchedulerTest, PollForCommitCompletion) {
- FakeSchedulerClient client;
+ // Since we are simulating a long commit, set up a client with draw duration
+ // estimates that prevent skipping main frames to get to low latency mode.
+ SchedulerClientWithFixedEstimates client(
+ base::TimeDelta::FromMilliseconds(1),
+ base::TimeDelta::FromMilliseconds(32),
+ base::TimeDelta::FromMilliseconds(32));
client.set_log_anticipated_draw_time_change(true);
- SchedulerSettings settings = SchedulerSettings();
- settings.throttle_frame_production = false;
- Scheduler* scheduler = client.CreateScheduler(settings);
+ SchedulerSettings default_scheduler_settings;
+ TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
scheduler->SetCanDraw(true);
scheduler->SetCanStart();
@@ -1252,34 +1130,789 @@ TEST(SchedulerTest, PollForCommitCompletion) {
scheduler->SetNeedsCommit();
EXPECT_TRUE(scheduler->CommitPending());
- scheduler->FinishCommit();
+ scheduler->NotifyBeginMainFrameStarted();
+ scheduler->NotifyReadyToCommit();
scheduler->SetNeedsRedraw();
- BeginFrameArgs impl_frame_args = BeginFrameArgs::CreateForTesting();
- const int interval = 1;
- impl_frame_args.interval = base::TimeDelta::FromMilliseconds(interval);
- scheduler->BeginImplFrame(impl_frame_args);
- scheduler->OnBeginImplFrameDeadline();
-
- // At this point, we've drawn a frame. Start another commit, but hold off on
- // the FinishCommit for now.
+
+ BeginFrameArgs frame_args = CreateBeginFrameArgsForTesting();
+ frame_args.interval = base::TimeDelta::FromMilliseconds(1000);
+ scheduler->BeginFrame(frame_args);
+
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+
+ scheduler->DidSwapBuffers();
+ scheduler->DidSwapBuffersComplete();
+
+ // At this point, we've drawn a frame. Start another commit, but hold off on
+ // the NotifyReadyToCommit for now.
EXPECT_FALSE(scheduler->CommitPending());
scheduler->SetNeedsCommit();
+ scheduler->BeginFrame(frame_args);
EXPECT_TRUE(scheduler->CommitPending());
+ // Draw and swap the frame, but don't ack the swap to simulate the Browser
+ // blocking on the renderer.
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+ scheduler->DidSwapBuffers();
+
// Spin the event loop a few times and make sure we get more
// DidAnticipateDrawTimeChange calls every time.
int actions_so_far = client.num_actions_();
// Does three iterations to make sure that the timer is properly repeating.
for (int i = 0; i < 3; ++i) {
- // Wait for 2x the frame interval to match
- // Scheduler::advance_commit_state_timer_'s rate.
- SpinForMillis(interval * 2);
+ EXPECT_EQ((frame_args.interval * 2).InMicroseconds(),
+ client.task_runner().NextPendingTaskDelay().InMicroseconds())
+ << *scheduler->AsValue();
+ client.task_runner().RunPendingTasks();
EXPECT_GT(client.num_actions_(), actions_so_far);
EXPECT_STREQ(client.Action(client.num_actions_() - 1),
"DidAnticipatedDrawTimeChange");
actions_so_far = client.num_actions_();
}
+
+ // Do the same thing after BeginMainFrame starts but still before activation.
+ scheduler->NotifyBeginMainFrameStarted();
+ for (int i = 0; i < 3; ++i) {
+ EXPECT_EQ((frame_args.interval * 2).InMicroseconds(),
+ client.task_runner().NextPendingTaskDelay().InMicroseconds())
+ << *scheduler->AsValue();
+ client.task_runner().RunPendingTasks();
+ EXPECT_GT(client.num_actions_(), actions_so_far);
+ EXPECT_STREQ(client.Action(client.num_actions_() - 1),
+ "DidAnticipatedDrawTimeChange");
+ actions_so_far = client.num_actions_();
+ }
+}
+
+TEST(SchedulerTest, BeginRetroFrame) {
+ FakeSchedulerClient client;
+ SchedulerSettings scheduler_settings;
+ TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
+ scheduler->SetCanStart();
+ scheduler->SetVisible(true);
+ scheduler->SetCanDraw(true);
+ InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+
+ // SetNeedsCommit should begin the frame on the next BeginImplFrame.
+ client.Reset();
+ scheduler->SetNeedsCommit();
+ EXPECT_TRUE(client.needs_begin_frame());
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
+ client.Reset();
+
+ // Create a BeginFrame with a long deadline to avoid race conditions.
+ // This is the first BeginFrame, which will be handled immediately.
+ BeginFrameArgs args = CreateBeginFrameArgsForTesting();
+ args.deadline += base::TimeDelta::FromHours(1);
+ scheduler->BeginFrame(args);
+ EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client.needs_begin_frame());
+ client.Reset();
+
+ // Queue BeginFrames while we are still handling the previous BeginFrame.
+ args.frame_time += base::TimeDelta::FromSeconds(1);
+ scheduler->BeginFrame(args);
+ args.frame_time += base::TimeDelta::FromSeconds(1);
+ scheduler->BeginFrame(args);
+
+ // If we don't swap on the deadline, we wait for the next BeginImplFrame.
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_NO_ACTION(client);
+ EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client.needs_begin_frame());
+ client.Reset();
+
+ // NotifyReadyToCommit should trigger the commit.
+ scheduler->NotifyBeginMainFrameStarted();
+ scheduler->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
+ EXPECT_TRUE(client.needs_begin_frame());
+ client.Reset();
+
+ // BeginImplFrame should prepare the draw.
+ client.task_runner().RunPendingTasks(); // Run posted BeginRetroFrame.
+ EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client.needs_begin_frame());
+ client.Reset();
+
+ // BeginImplFrame deadline should draw.
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 1);
+ EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client.needs_begin_frame());
+ client.Reset();
+
+ // The following BeginImplFrame deadline should SetNeedsBeginFrame(false)
+ // to avoid excessive toggles.
+ client.task_runner().RunPendingTasks(); // Run posted BeginRetroFrame.
+ EXPECT_SINGLE_ACTION("WillBeginImplFrame", client);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+ client.Reset();
+
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
+ EXPECT_FALSE(client.needs_begin_frame());
+ client.Reset();
+}
+
+TEST(SchedulerTest, BeginRetroFrame_SwapThrottled) {
+ FakeSchedulerClient client;
+ SchedulerSettings scheduler_settings;
+ TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
+ scheduler->SetCanStart();
+ scheduler->SetVisible(true);
+ scheduler->SetCanDraw(true);
+ InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+
+ // To test swap ack throttling, this test disables automatic swap acks.
+ scheduler->SetMaxSwapsPending(1);
+ client.SetAutomaticSwapAck(false);
+
+ // SetNeedsCommit should begin the frame on the next BeginImplFrame.
+ client.Reset();
+ scheduler->SetNeedsCommit();
+ EXPECT_TRUE(client.needs_begin_frame());
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
+ client.Reset();
+
+ // Create a BeginFrame with a long deadline to avoid race conditions.
+ // This is the first BeginFrame, which will be handled immediately.
+ BeginFrameArgs args = CreateBeginFrameArgsForTesting();
+ args.deadline += base::TimeDelta::FromHours(1);
+ scheduler->BeginFrame(args);
+ EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client.needs_begin_frame());
+ client.Reset();
+
+ // Queue BeginFrame while we are still handling the previous BeginFrame.
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+ args.frame_time += base::TimeDelta::FromSeconds(1);
+ scheduler->BeginFrame(args);
+ EXPECT_NO_ACTION(client);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+ client.Reset();
+
+ // NotifyReadyToCommit should trigger the pending commit and draw.
+ scheduler->NotifyBeginMainFrameStarted();
+ scheduler->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
+ EXPECT_TRUE(client.needs_begin_frame());
+ client.Reset();
+
+ // Swapping will put us into a swap throttled state.
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
+ EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client.needs_begin_frame());
+ client.Reset();
+
+ // While swap throttled, BeginRetroFrames should trigger BeginImplFrames
+ // but not a BeginMainFrame or draw.
+ scheduler->SetNeedsCommit();
+ client.task_runner().RunPendingTasks(); // Run posted BeginRetroFrame.
+ EXPECT_ACTION("WillBeginImplFrame", client, 0, 1);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client.needs_begin_frame());
+ client.Reset();
+
+ // Queue BeginFrame while we are still handling the previous BeginFrame.
+ args.frame_time += base::TimeDelta::FromSeconds(1);
+ scheduler->BeginFrame(args);
+ EXPECT_NO_ACTION(client);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client.needs_begin_frame());
+ client.Reset();
+
+ // Take us out of a swap throttled state.
+ scheduler->DidSwapBuffersComplete();
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 1);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client.needs_begin_frame());
+ client.Reset();
+
+ // BeginImplFrame deadline should draw.
+ scheduler->SetNeedsRedraw();
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
+ EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client.needs_begin_frame());
+ client.Reset();
+}
+
+void BeginFramesNotFromClient(bool begin_frame_scheduling_enabled,
+ bool throttle_frame_production) {
+ FakeSchedulerClient client;
+ SchedulerSettings scheduler_settings;
+ scheduler_settings.begin_frame_scheduling_enabled =
+ begin_frame_scheduling_enabled;
+ scheduler_settings.throttle_frame_production = throttle_frame_production;
+ TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
+ scheduler->SetCanStart();
+ scheduler->SetVisible(true);
+ scheduler->SetCanDraw(true);
+ InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+
+ // SetNeedsCommit should begin the frame on the next BeginImplFrame
+ // without calling SetNeedsBeginFrame.
+ client.Reset();
+ scheduler->SetNeedsCommit();
+ EXPECT_FALSE(client.needs_begin_frame());
+ EXPECT_NO_ACTION(client);
+ client.Reset();
+
+ // When the client-driven BeginFrame are disabled, the scheduler posts it's
+ // own BeginFrame tasks.
+ client.task_runner().RunPendingTasks(); // Run posted BeginFrame.
+ EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_FALSE(client.needs_begin_frame());
+ client.Reset();
+
+ // If we don't swap on the deadline, we wait for the next BeginFrame.
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_NO_ACTION(client);
+ EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_FALSE(client.needs_begin_frame());
+ client.Reset();
+
+ // NotifyReadyToCommit should trigger the commit.
+ scheduler->NotifyBeginMainFrameStarted();
+ scheduler->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
+ EXPECT_FALSE(client.needs_begin_frame());
+ client.Reset();
+
+ // BeginImplFrame should prepare the draw.
+ client.task_runner().RunPendingTasks(); // Run posted BeginFrame.
+ EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_FALSE(client.needs_begin_frame());
+ client.Reset();
+
+ // BeginImplFrame deadline should draw.
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 1);
+ EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_FALSE(client.needs_begin_frame());
+ client.Reset();
+
+ // The following BeginImplFrame deadline should SetNeedsBeginFrame(false)
+ // to avoid excessive toggles.
+ client.task_runner().RunPendingTasks(); // Run posted BeginFrame.
+ EXPECT_SINGLE_ACTION("WillBeginImplFrame", client);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+ client.Reset();
+
+ // Make sure SetNeedsBeginFrame isn't called on the client
+ // when the BeginFrame is no longer needed.
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_NO_ACTION(client);
+ EXPECT_FALSE(client.needs_begin_frame());
+ client.Reset();
+}
+
+TEST(SchedulerTest, SyntheticBeginFrames) {
+ bool begin_frame_scheduling_enabled = false;
+ bool throttle_frame_production = true;
+ BeginFramesNotFromClient(begin_frame_scheduling_enabled,
+ throttle_frame_production);
+}
+
+TEST(SchedulerTest, VSyncThrottlingDisabled) {
+ bool begin_frame_scheduling_enabled = true;
+ bool throttle_frame_production = false;
+ BeginFramesNotFromClient(begin_frame_scheduling_enabled,
+ throttle_frame_production);
+}
+
+TEST(SchedulerTest, SyntheticBeginFrames_And_VSyncThrottlingDisabled) {
+ bool begin_frame_scheduling_enabled = false;
+ bool throttle_frame_production = false;
+ BeginFramesNotFromClient(begin_frame_scheduling_enabled,
+ throttle_frame_production);
+}
+
+void BeginFramesNotFromClient_SwapThrottled(bool begin_frame_scheduling_enabled,
+ bool throttle_frame_production) {
+ FakeSchedulerClient client;
+ SchedulerSettings scheduler_settings;
+ scheduler_settings.begin_frame_scheduling_enabled =
+ begin_frame_scheduling_enabled;
+ scheduler_settings.throttle_frame_production = throttle_frame_production;
+ TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
+ scheduler->SetCanStart();
+ scheduler->SetVisible(true);
+ scheduler->SetCanDraw(true);
+ InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+
+ // To test swap ack throttling, this test disables automatic swap acks.
+ scheduler->SetMaxSwapsPending(1);
+ client.SetAutomaticSwapAck(false);
+
+ // SetNeedsCommit should begin the frame on the next BeginImplFrame.
+ client.Reset();
+ scheduler->SetNeedsCommit();
+ EXPECT_FALSE(client.needs_begin_frame());
+ EXPECT_NO_ACTION(client);
+ client.Reset();
+
+ // Trigger the first BeginImplFrame and BeginMainFrame
+ client.task_runner().RunPendingTasks(); // Run posted BeginFrame.
+ EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_FALSE(client.needs_begin_frame());
+ client.Reset();
+
+ // NotifyReadyToCommit should trigger the pending commit and draw.
+ scheduler->NotifyBeginMainFrameStarted();
+ scheduler->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
+ EXPECT_FALSE(client.needs_begin_frame());
+ client.Reset();
+
+ // Swapping will put us into a swap throttled state.
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
+ EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_FALSE(client.needs_begin_frame());
+ client.Reset();
+
+ // While swap throttled, BeginFrames should trigger BeginImplFrames,
+ // but not a BeginMainFrame or draw.
+ scheduler->SetNeedsCommit();
+ client.task_runner().RunPendingTasks(); // Run posted BeginFrame.
+ EXPECT_ACTION("WillBeginImplFrame", client, 0, 1);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_FALSE(client.needs_begin_frame());
+ client.Reset();
+
+ // Take us out of a swap throttled state.
+ scheduler->DidSwapBuffersComplete();
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 1);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_FALSE(client.needs_begin_frame());
+ client.Reset();
+
+ // BeginImplFrame deadline should draw.
+ scheduler->SetNeedsRedraw();
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
+ EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_FALSE(client.needs_begin_frame());
+ client.Reset();
+}
+
+TEST(SchedulerTest, SyntheticBeginFrames_SwapThrottled) {
+ bool begin_frame_scheduling_enabled = false;
+ bool throttle_frame_production = true;
+ BeginFramesNotFromClient_SwapThrottled(begin_frame_scheduling_enabled,
+ throttle_frame_production);
+}
+
+TEST(SchedulerTest, VSyncThrottlingDisabled_SwapThrottled) {
+ bool begin_frame_scheduling_enabled = true;
+ bool throttle_frame_production = false;
+ BeginFramesNotFromClient_SwapThrottled(begin_frame_scheduling_enabled,
+ throttle_frame_production);
+}
+
+TEST(SchedulerTest,
+ SyntheticBeginFrames_And_VSyncThrottlingDisabled_SwapThrottled) {
+ bool begin_frame_scheduling_enabled = false;
+ bool throttle_frame_production = false;
+ BeginFramesNotFromClient_SwapThrottled(begin_frame_scheduling_enabled,
+ throttle_frame_production);
+}
+
+TEST(SchedulerTest, DidLoseOutputSurfaceAfterOutputSurfaceIsInitialized) {
+ FakeSchedulerClient client;
+ SchedulerSettings scheduler_settings;
+ TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
+ scheduler->SetCanStart();
+ scheduler->SetVisible(true);
+ scheduler->SetCanDraw(true);
+
+ EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
+ client.Reset();
+ scheduler->DidCreateAndInitializeOutputSurface();
+ EXPECT_NO_ACTION(client);
+
+ scheduler->DidLoseOutputSurface();
+ EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
+}
+
+TEST(SchedulerTest, DidLoseOutputSurfaceAfterBeginFrameStarted) {
+ FakeSchedulerClient client;
+ SchedulerSettings scheduler_settings;
+ TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
+ scheduler->SetCanStart();
+ scheduler->SetVisible(true);
+ scheduler->SetCanDraw(true);
+
+ EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
+ InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+ // SetNeedsCommit should begin the frame.
+ client.Reset();
+ scheduler->SetNeedsCommit();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
+
+ client.Reset();
+ scheduler->BeginFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+
+ client.Reset();
+ scheduler->DidLoseOutputSurface();
+ // Do nothing when impl frame is in deadine pending state.
+ EXPECT_NO_ACTION(client);
+
+ client.Reset();
+ scheduler->NotifyBeginMainFrameStarted();
+ scheduler->NotifyReadyToCommit();
+ EXPECT_ACTION("ScheduledActionCommit", client, 0, 1);
+
+ client.Reset();
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
+}
+
+void DidLoseOutputSurfaceAfterBeginFrameStartedWithHighLatency(
+ bool impl_side_painting) {
+ FakeSchedulerClient client;
+ SchedulerSettings scheduler_settings;
+ scheduler_settings.impl_side_painting = impl_side_painting;
+ TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
+ scheduler->SetCanStart();
+ scheduler->SetVisible(true);
+ scheduler->SetCanDraw(true);
+
+ EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
+ InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+
+ // SetNeedsCommit should begin the frame.
+ client.Reset();
+ scheduler->SetNeedsCommit();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
+
+ client.Reset();
+ scheduler->BeginFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+
+ client.Reset();
+ scheduler->DidLoseOutputSurface();
+ // Do nothing when impl frame is in deadine pending state.
+ EXPECT_NO_ACTION(client);
+
+ client.Reset();
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
+ // OnBeginImplFrameDeadline didn't schedule any actions because main frame is
+ // not yet completed.
+ EXPECT_NO_ACTION(client);
+
+ // BeginImplFrame is not started.
+ scheduler->BeginFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_NO_ACTION(client);
+ EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+
+ client.Reset();
+ scheduler->NotifyBeginMainFrameStarted();
+ scheduler->NotifyReadyToCommit();
+ if (impl_side_painting) {
+ EXPECT_ACTION("ScheduledActionCommit", client, 0, 3);
+ EXPECT_ACTION("ScheduledActionActivatePendingTree", client, 1, 3);
+ EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client, 2, 3);
+ } else {
+ EXPECT_ACTION("ScheduledActionCommit", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client, 1, 2);
+ }
+}
+
+TEST(SchedulerTest, DidLoseOutputSurfaceAfterBeginFrameStartedWithHighLatency) {
+ bool impl_side_painting = false;
+ DidLoseOutputSurfaceAfterBeginFrameStartedWithHighLatency(impl_side_painting);
+}
+
+TEST(SchedulerTest,
+ DidLoseOutputSurfaceAfterBeginFrameStartedWithHighLatencyWithImplPaint) {
+ bool impl_side_painting = true;
+ DidLoseOutputSurfaceAfterBeginFrameStartedWithHighLatency(impl_side_painting);
+}
+
+void DidLoseOutputSurfaceAfterReadyToCommit(bool impl_side_painting) {
+ FakeSchedulerClient client;
+ SchedulerSettings scheduler_settings;
+ scheduler_settings.impl_side_painting = impl_side_painting;
+ TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
+ scheduler->SetCanStart();
+ scheduler->SetVisible(true);
+ scheduler->SetCanDraw(true);
+
+ EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
+ InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+
+ // SetNeedsCommit should begin the frame.
+ client.Reset();
+ scheduler->SetNeedsCommit();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
+
+ client.Reset();
+ scheduler->BeginFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+
+ client.Reset();
+ scheduler->NotifyBeginMainFrameStarted();
+ scheduler->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
+
+ client.Reset();
+ scheduler->DidLoseOutputSurface();
+ if (impl_side_painting) {
+ // Pending tree should be forced to activate.
+ EXPECT_SINGLE_ACTION("ScheduledActionActivatePendingTree", client);
+ } else {
+ // Do nothing when impl frame is in deadine pending state.
+ EXPECT_NO_ACTION(client);
+ }
+
+ client.Reset();
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
+}
+
+TEST(SchedulerTest, DidLoseOutputSurfaceAfterReadyToCommit) {
+ DidLoseOutputSurfaceAfterReadyToCommit(false);
+}
+
+TEST(SchedulerTest, DidLoseOutputSurfaceAfterReadyToCommitWithImplPainting) {
+ DidLoseOutputSurfaceAfterReadyToCommit(true);
+}
+
+TEST(SchedulerTest, DidLoseOutputSurfaceAfterSetNeedsManageTiles) {
+ FakeSchedulerClient client;
+ SchedulerSettings scheduler_settings;
+ TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
+ scheduler->SetCanStart();
+ scheduler->SetVisible(true);
+ scheduler->SetCanDraw(true);
+ InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+
+ client.Reset();
+ scheduler->SetNeedsManageTiles();
+ scheduler->SetNeedsRedraw();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
+ EXPECT_TRUE(client.needs_begin_frame());
+
+ client.Reset();
+ scheduler->BeginFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+
+ client.Reset();
+ scheduler->DidLoseOutputSurface();
+ EXPECT_NO_ACTION(client);
+
+ client.Reset();
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_ACTION("ScheduledActionManageTiles", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client, 1, 2);
+}
+
+TEST(SchedulerTest, DidLoseOutputSurfaceAfterBeginRetroFramePosted) {
+ FakeSchedulerClient client;
+ SchedulerSettings scheduler_settings;
+ TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
+ scheduler->SetCanStart();
+ scheduler->SetVisible(true);
+ scheduler->SetCanDraw(true);
+ InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+
+ // SetNeedsCommit should begin the frame on the next BeginImplFrame.
+ client.Reset();
+ scheduler->SetNeedsCommit();
+ EXPECT_TRUE(client.needs_begin_frame());
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
+
+ // Create a BeginFrame with a long deadline to avoid race conditions.
+ // This is the first BeginFrame, which will be handled immediately.
+ client.Reset();
+ BeginFrameArgs args = CreateBeginFrameArgsForTesting();
+ args.deadline += base::TimeDelta::FromHours(1);
+ scheduler->BeginFrame(args);
+ EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client.needs_begin_frame());
+
+ // Queue BeginFrames while we are still handling the previous BeginFrame.
+ args.frame_time += base::TimeDelta::FromSeconds(1);
+ scheduler->BeginFrame(args);
+ args.frame_time += base::TimeDelta::FromSeconds(1);
+ scheduler->BeginFrame(args);
+
+ // If we don't swap on the deadline, we wait for the next BeginImplFrame.
+ client.Reset();
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_NO_ACTION(client);
+ EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client.needs_begin_frame());
+
+ // NotifyReadyToCommit should trigger the commit.
+ client.Reset();
+ scheduler->NotifyBeginMainFrameStarted();
+ scheduler->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
+ EXPECT_TRUE(client.needs_begin_frame());
+
+ client.Reset();
+ EXPECT_FALSE(scheduler->IsBeginRetroFrameArgsEmpty());
+ scheduler->DidLoseOutputSurface();
+ EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
+ EXPECT_TRUE(client.needs_begin_frame());
+ EXPECT_TRUE(scheduler->IsBeginRetroFrameArgsEmpty());
+
+ // Posted BeginRetroFrame is aborted.
+ client.Reset();
+ client.task_runner().RunPendingTasks();
+ EXPECT_NO_ACTION(client);
+}
+
+TEST(SchedulerTest, DidLoseOutputSurfaceDuringBeginRetroFrameRunning) {
+ FakeSchedulerClient client;
+ SchedulerSettings scheduler_settings;
+ TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
+ scheduler->SetCanStart();
+ scheduler->SetVisible(true);
+ scheduler->SetCanDraw(true);
+ InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+
+ // SetNeedsCommit should begin the frame on the next BeginImplFrame.
+ client.Reset();
+ scheduler->SetNeedsCommit();
+ EXPECT_TRUE(client.needs_begin_frame());
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrame", client);
+
+ // Create a BeginFrame with a long deadline to avoid race conditions.
+ // This is the first BeginFrame, which will be handled immediately.
+ client.Reset();
+ BeginFrameArgs args = CreateBeginFrameArgsForTesting();
+ args.deadline += base::TimeDelta::FromHours(1);
+ scheduler->BeginFrame(args);
+ EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client.needs_begin_frame());
+
+ // Queue BeginFrames while we are still handling the previous BeginFrame.
+ args.frame_time += base::TimeDelta::FromSeconds(1);
+ scheduler->BeginFrame(args);
+ args.frame_time += base::TimeDelta::FromSeconds(1);
+ scheduler->BeginFrame(args);
+
+ // If we don't swap on the deadline, we wait for the next BeginImplFrame.
+ client.Reset();
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_NO_ACTION(client);
+ EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client.needs_begin_frame());
+
+ // NotifyReadyToCommit should trigger the commit.
+ client.Reset();
+ scheduler->NotifyBeginMainFrameStarted();
+ scheduler->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
+ EXPECT_TRUE(client.needs_begin_frame());
+
+ // BeginImplFrame should prepare the draw.
+ client.Reset();
+ client.task_runner().RunPendingTasks(); // Run posted BeginRetroFrame.
+ EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client.needs_begin_frame());
+
+ client.Reset();
+ EXPECT_FALSE(scheduler->IsBeginRetroFrameArgsEmpty());
+ scheduler->DidLoseOutputSurface();
+ EXPECT_NO_ACTION(client);
+ EXPECT_TRUE(scheduler->IsBeginRetroFrameArgsEmpty());
+
+ // BeginImplFrame deadline should abort drawing.
+ client.Reset();
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
+ EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(client.needs_begin_frame());
+
+ // No more BeginRetroFrame because BeginRetroFrame queue is cleared.
+ client.Reset();
+ client.task_runner().RunPendingTasks();
+ EXPECT_NO_ACTION(client);
+}
+
+TEST(SchedulerTest,
+ StopBeginFrameAfterDidLoseOutputSurfaceWithSyntheticBeginFrameSource) {
+ FakeSchedulerClient client;
+ SchedulerSettings scheduler_settings;
+ scheduler_settings.begin_frame_scheduling_enabled = false;
+ TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
+ scheduler->SetCanStart();
+ scheduler->SetVisible(true);
+ scheduler->SetCanDraw(true);
+ InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+
+ // SetNeedsCommit should begin the frame on the next BeginImplFrame.
+ client.Reset();
+ EXPECT_FALSE(scheduler->IsSyntheticBeginFrameSourceActive());
+ scheduler->SetNeedsCommit();
+ EXPECT_TRUE(scheduler->IsSyntheticBeginFrameSourceActive());
+
+ client.Reset();
+ client.task_runner().RunPendingTasks(); // Run posted Tick.
+ EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
+ EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
+ EXPECT_TRUE(scheduler->IsSyntheticBeginFrameSourceActive());
+
+ // NotifyReadyToCommit should trigger the commit.
+ client.Reset();
+ scheduler->NotifyBeginMainFrameStarted();
+ scheduler->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
+ EXPECT_TRUE(scheduler->IsSyntheticBeginFrameSourceActive());
+
+ client.Reset();
+ scheduler->DidLoseOutputSurface();
+ EXPECT_EQ(0, client.num_actions_());
+ EXPECT_FALSE(scheduler->IsSyntheticBeginFrameSourceActive());
+
+ client.Reset();
+ client.task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client);
+ EXPECT_FALSE(scheduler->IsSyntheticBeginFrameSourceActive());
}
} // namespace
diff --git a/chromium/cc/scheduler/time_source.h b/chromium/cc/scheduler/time_source.h
deleted file mode 100644
index e45ffbb95aa..00000000000
--- a/chromium/cc/scheduler/time_source.h
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2011 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_SCHEDULER_TIME_SOURCE_H_
-#define CC_SCHEDULER_TIME_SOURCE_H_
-
-#include "base/memory/ref_counted.h"
-#include "base/time/time.h"
-#include "cc/base/cc_export.h"
-
-namespace cc {
-
-class TimeSourceClient {
- public:
- virtual void OnTimerTick() = 0;
-
- protected:
- virtual ~TimeSourceClient() {}
-};
-
-// An generic interface for getting a reliably-ticking timesource of
-// a specified rate.
-//
-// Be sure to call SetActive(false) before releasing your reference to the
-// timer, or it will keep on ticking!
-class CC_EXPORT TimeSource : public base::RefCounted<TimeSource> {
- public:
- virtual void SetClient(TimeSourceClient* client) = 0;
-
- // If transitioning from not active to active, SetActive will return the
- // timestamp of the most recenly missed tick that did not have OnTimerTick
- // called.
- virtual base::TimeTicks SetActive(bool active) = 0;
-
- virtual bool Active() const = 0;
- virtual void SetTimebaseAndInterval(base::TimeTicks timebase,
- base::TimeDelta interval) = 0;
- virtual base::TimeTicks LastTickTime() = 0;
- virtual base::TimeTicks NextTickTime() = 0;
-
- protected:
- virtual ~TimeSource() {}
-
- private:
- friend class base::RefCounted<TimeSource>;
-};
-
-} // namespace cc
-
-#endif // CC_SCHEDULER_TIME_SOURCE_H_
diff --git a/chromium/cc/surfaces/OWNERS b/chromium/cc/surfaces/OWNERS
new file mode 100644
index 00000000000..023e5fc459f
--- /dev/null
+++ b/chromium/cc/surfaces/OWNERS
@@ -0,0 +1 @@
+jamesr@chromium.org
diff --git a/chromium/cc/surfaces/display.cc b/chromium/cc/surfaces/display.cc
new file mode 100644
index 00000000000..a39695f5732
--- /dev/null
+++ b/chromium/cc/surfaces/display.cc
@@ -0,0 +1,163 @@
+// 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/display.h"
+
+#include "base/message_loop/message_loop.h"
+#include "cc/output/compositor_frame.h"
+#include "cc/output/direct_renderer.h"
+#include "cc/output/gl_renderer.h"
+#include "cc/output/software_renderer.h"
+#include "cc/surfaces/display_client.h"
+#include "cc/surfaces/surface.h"
+
+namespace cc {
+
+static ResourceProvider::ResourceId ResourceRemapHelper(
+ bool* invalid_frame,
+ const ResourceProvider::ResourceIdMap& child_to_parent_map,
+ ResourceProvider::ResourceIdArray* resources_in_frame,
+ ResourceProvider::ResourceId id) {
+ ResourceProvider::ResourceIdMap::const_iterator it =
+ child_to_parent_map.find(id);
+ if (it == child_to_parent_map.end()) {
+ *invalid_frame = true;
+ return 0;
+ }
+
+ DCHECK_EQ(it->first, id);
+ ResourceProvider::ResourceId remapped_id = it->second;
+ resources_in_frame->push_back(id);
+ return remapped_id;
+}
+
+Display::Display(DisplayClient* client,
+ SurfaceManager* manager,
+ SharedBitmapManager* bitmap_manager)
+ : client_(client),
+ manager_(manager),
+ aggregator_(manager),
+ bitmap_manager_(bitmap_manager) {
+}
+
+Display::~Display() {
+}
+
+void Display::Resize(const gfx::Size& size) {
+ current_surface_.reset(new Surface(manager_, this, size));
+}
+
+void Display::InitializeOutputSurface() {
+ if (output_surface_)
+ return;
+ scoped_ptr<OutputSurface> output_surface = client_->CreateOutputSurface();
+ if (!output_surface->BindToClient(this))
+ return;
+
+ int highp_threshold_min = 0;
+ bool use_rgba_4444_texture_format = false;
+ size_t id_allocation_chunk_size = 1;
+ bool use_distance_field_text = false;
+ scoped_ptr<ResourceProvider> resource_provider =
+ ResourceProvider::Create(output_surface.get(),
+ bitmap_manager_,
+ highp_threshold_min,
+ use_rgba_4444_texture_format,
+ id_allocation_chunk_size,
+ use_distance_field_text);
+ if (!resource_provider)
+ return;
+
+ if (output_surface->context_provider()) {
+ TextureMailboxDeleter* texture_mailbox_deleter = NULL;
+ scoped_ptr<GLRenderer> renderer =
+ GLRenderer::Create(this,
+ &settings_,
+ output_surface.get(),
+ resource_provider.get(),
+ texture_mailbox_deleter,
+ highp_threshold_min);
+ if (!renderer)
+ return;
+ renderer_ = renderer.Pass();
+ } else {
+ scoped_ptr<SoftwareRenderer> renderer = SoftwareRenderer::Create(
+ this, &settings_, output_surface.get(), resource_provider.get());
+ if (!renderer)
+ return;
+ renderer_ = renderer.Pass();
+ }
+
+ output_surface_ = output_surface.Pass();
+ resource_provider_ = resource_provider.Pass();
+ child_id_ = resource_provider_->CreateChild(
+ base::Bind(&Display::ReturnResources, base::Unretained(this)));
+}
+
+bool Display::Draw() {
+ if (!current_surface_)
+ return false;
+
+ InitializeOutputSurface();
+ if (!output_surface_)
+ return false;
+
+ // TODO(jamesr): Use the surface aggregator instead.
+ scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
+ CompositorFrame* current_frame = current_surface_->GetEligibleFrame();
+ frame_data->resource_list =
+ current_frame->delegated_frame_data->resource_list;
+ RenderPass::CopyAll(current_frame->delegated_frame_data->render_pass_list,
+ &frame_data->render_pass_list);
+
+ if (frame_data->render_pass_list.empty())
+ return false;
+
+ const ResourceProvider::ResourceIdMap& resource_map =
+ resource_provider_->GetChildToParentMap(child_id_);
+ resource_provider_->ReceiveFromChild(child_id_, frame_data->resource_list);
+
+ bool invalid_frame = false;
+ ResourceProvider::ResourceIdArray resources_in_frame;
+ DrawQuad::ResourceIteratorCallback remap_resources_to_parent_callback =
+ base::Bind(&ResourceRemapHelper,
+ &invalid_frame,
+ resource_map,
+ &resources_in_frame);
+ for (size_t i = 0; i < frame_data->render_pass_list.size(); ++i) {
+ RenderPass* pass = frame_data->render_pass_list[i];
+ for (size_t j = 0; j < pass->quad_list.size(); ++j) {
+ DrawQuad* quad = pass->quad_list[j];
+ quad->IterateResources(remap_resources_to_parent_callback);
+ }
+ }
+
+ if (invalid_frame)
+ return false;
+ resource_provider_->DeclareUsedResourcesFromChild(child_id_,
+ resources_in_frame);
+
+ float device_scale_factor = 1.0f;
+ gfx::Rect device_viewport_rect = gfx::Rect(current_surface_->size());
+ gfx::Rect device_clip_rect = device_viewport_rect;
+ bool disable_picture_quad_image_filtering = false;
+
+ renderer_->DrawFrame(&frame_data->render_pass_list,
+ device_scale_factor,
+ device_viewport_rect,
+ device_clip_rect,
+ disable_picture_quad_image_filtering);
+ CompositorFrameMetadata metadata;
+ renderer_->SwapBuffers(metadata);
+ return true;
+}
+
+SurfaceId Display::CurrentSurfaceId() {
+ return current_surface_ ? current_surface_->surface_id() : SurfaceId();
+}
+
+void Display::ReturnResources(const ReturnedResourceArray& resources) {
+}
+
+} // namespace cc
diff --git a/chromium/cc/surfaces/display.h b/chromium/cc/surfaces/display.h
new file mode 100644
index 00000000000..191b28db009
--- /dev/null
+++ b/chromium/cc/surfaces/display.h
@@ -0,0 +1,91 @@
+// 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_DISPLAY_H_
+#define CC_SURFACES_DISPLAY_H_
+
+#include "base/memory/scoped_ptr.h"
+
+#include "cc/output/output_surface_client.h"
+#include "cc/output/renderer.h"
+#include "cc/surfaces/surface_aggregator.h"
+#include "cc/surfaces/surface_client.h"
+#include "cc/surfaces/surface_id.h"
+#include "cc/surfaces/surfaces_export.h"
+
+namespace gfx {
+class Size;
+}
+
+namespace cc {
+
+class DirectRenderer;
+class DisplayClient;
+class OutputSurface;
+class ResourceProvider;
+class SharedBitmapManager;
+class Surface;
+class SurfaceManager;
+
+class CC_SURFACES_EXPORT Display : public SurfaceClient,
+ public OutputSurfaceClient,
+ public RendererClient {
+ public:
+ Display(DisplayClient* client,
+ SurfaceManager* manager,
+ SharedBitmapManager* bitmap_manager);
+ virtual ~Display();
+
+ void Resize(const gfx::Size& new_size);
+ bool Draw();
+
+ SurfaceId CurrentSurfaceId();
+
+ // OutputSurfaceClient implementation.
+ virtual void DeferredInitialize() OVERRIDE {}
+ virtual void ReleaseGL() OVERRIDE {}
+ virtual void CommitVSyncParameters(base::TimeTicks timebase,
+ base::TimeDelta interval) OVERRIDE {}
+ virtual void SetNeedsRedrawRect(const gfx::Rect& damage_rect) OVERRIDE {}
+ virtual void BeginFrame(const BeginFrameArgs& args) OVERRIDE {}
+ virtual void DidSwapBuffers() OVERRIDE {}
+ virtual void DidSwapBuffersComplete() OVERRIDE {}
+ virtual void ReclaimResources(const CompositorFrameAck* ack) OVERRIDE {}
+ virtual void DidLoseOutputSurface() OVERRIDE {}
+ virtual void SetExternalDrawConstraints(
+ const gfx::Transform& transform,
+ const gfx::Rect& viewport,
+ const gfx::Rect& clip,
+ bool valid_for_tile_management) OVERRIDE {}
+ virtual void SetMemoryPolicy(const ManagedMemoryPolicy& policy) OVERRIDE {}
+ virtual void SetTreeActivationCallback(
+ const base::Closure& callback) OVERRIDE {}
+
+ // RendererClient implementation.
+ virtual void SetFullRootLayerDamage() OVERRIDE {}
+ virtual void RunOnDemandRasterTask(Task* on_demand_raster_task) OVERRIDE {}
+
+ // SurfaceClient implementation.
+ virtual void ReturnResources(const ReturnedResourceArray& resources) OVERRIDE;
+
+ private:
+ void InitializeOutputSurface();
+
+ DisplayClient* client_;
+ SurfaceManager* manager_;
+ SurfaceAggregator aggregator_;
+ SharedBitmapManager* bitmap_manager_;
+ LayerTreeSettings settings_;
+ scoped_ptr<Surface> current_surface_;
+ scoped_ptr<OutputSurface> output_surface_;
+ scoped_ptr<ResourceProvider> resource_provider_;
+ scoped_ptr<DirectRenderer> renderer_;
+ int child_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(Display);
+};
+
+} // namespace cc
+
+#endif // CC_SURFACES_DISPLAY_H_
diff --git a/chromium/cc/surfaces/display_client.h b/chromium/cc/surfaces/display_client.h
new file mode 100644
index 00000000000..e5f0b31a10c
--- /dev/null
+++ b/chromium/cc/surfaces/display_client.h
@@ -0,0 +1,23 @@
+// 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_DISPLAY_CLIENT_H_
+#define CC_SURFACES_DISPLAY_CLIENT_H_
+
+#include "base/memory/scoped_ptr.h"
+
+namespace cc {
+
+class OutputSurface;
+
+class DisplayClient {
+ public:
+ virtual scoped_ptr<OutputSurface> CreateOutputSurface() = 0;
+
+ protected:
+ virtual ~DisplayClient() {}
+};
+}
+
+#endif // CC_SURFACES_DISPLAY_CLIENT_H_
diff --git a/chromium/cc/surfaces/surface.cc b/chromium/cc/surfaces/surface.cc
new file mode 100644
index 00000000000..ed5a0f6dd8b
--- /dev/null
+++ b/chromium/cc/surfaces/surface.cc
@@ -0,0 +1,92 @@
+// 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.h"
+
+#include "cc/output/compositor_frame.h"
+#include "cc/surfaces/surface_manager.h"
+
+namespace cc {
+
+Surface::Surface(SurfaceManager* manager,
+ SurfaceClient* client,
+ const gfx::Size& size)
+ : manager_(manager),
+ client_(client),
+ size_(size) {
+ surface_id_ = manager_->RegisterAndAllocateIdForSurface(this);
+}
+
+Surface::~Surface() {
+ manager_->DeregisterSurface(surface_id_);
+}
+
+void Surface::QueueFrame(scoped_ptr<CompositorFrame> frame) {
+ scoped_ptr<CompositorFrame> previous_frame = current_frame_.Pass();
+ current_frame_ = frame.Pass();
+ ReceiveResourcesFromClient(
+ current_frame_->delegated_frame_data->resource_list);
+ if (previous_frame) {
+ ReturnedResourceArray previous_resources;
+ TransferableResource::ReturnResources(
+ previous_frame->delegated_frame_data->resource_list,
+ &previous_resources);
+ UnrefResources(previous_resources);
+ }
+}
+
+CompositorFrame* Surface::GetEligibleFrame() { return current_frame_.get(); }
+
+void Surface::ReturnUnusedResourcesToClient() {
+ client_->ReturnResources(resources_available_to_return_);
+ resources_available_to_return_.clear();
+}
+
+void Surface::RefCurrentFrameResources() {
+ if (!current_frame_)
+ return;
+ const TransferableResourceArray& current_frame_resources =
+ current_frame_->delegated_frame_data->resource_list;
+ for (size_t i = 0; i < current_frame_resources.size(); ++i) {
+ const TransferableResource& resource = current_frame_resources[i];
+ ResourceIdCountMap::iterator it =
+ resource_id_use_count_map_.find(resource.id);
+ DCHECK(it != resource_id_use_count_map_.end());
+ it->second.refs_holding_resource_alive++;
+ }
+}
+
+Surface::ResourceRefs::ResourceRefs()
+ : refs_received_from_child(0), refs_holding_resource_alive(0) {
+}
+
+void Surface::ReceiveResourcesFromClient(
+ const TransferableResourceArray& resources) {
+ for (TransferableResourceArray::const_iterator it = resources.begin();
+ it != resources.end();
+ ++it) {
+ ResourceRefs& ref = resource_id_use_count_map_[it->id];
+ ref.refs_holding_resource_alive++;
+ ref.refs_received_from_child++;
+ }
+}
+
+void Surface::UnrefResources(const ReturnedResourceArray& resources) {
+ for (ReturnedResourceArray::const_iterator it = resources.begin();
+ it != resources.end();
+ ++it) {
+ ResourceProvider::ResourceId id = it->id;
+ ResourceIdCountMap::iterator count_it = resource_id_use_count_map_.find(id);
+ DCHECK(count_it != resource_id_use_count_map_.end());
+ count_it->second.refs_holding_resource_alive -= it->count;
+ if (count_it->second.refs_holding_resource_alive == 0) {
+ resources_available_to_return_.push_back(*it);
+ resources_available_to_return_.back().count =
+ count_it->second.refs_received_from_child;
+ resource_id_use_count_map_.erase(count_it);
+ }
+ }
+}
+
+} // namespace cc
diff --git a/chromium/cc/surfaces/surface.h b/chromium/cc/surfaces/surface.h
new file mode 100644
index 00000000000..007f33d10a2
--- /dev/null
+++ b/chromium/cc/surfaces/surface.h
@@ -0,0 +1,75 @@
+// 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_H_
+#define CC_SURFACES_SURFACE_H_
+
+#include "base/containers/hash_tables.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "cc/resources/resource_provider.h"
+#include "cc/resources/return_callback.h"
+#include "cc/surfaces/surface_client.h"
+#include "cc/surfaces/surface_id.h"
+#include "cc/surfaces/surfaces_export.h"
+#include "ui/gfx/size.h"
+
+namespace cc {
+class CompositorFrame;
+class SurfaceManager;
+
+class CC_SURFACES_EXPORT Surface {
+ public:
+ Surface(SurfaceManager* manager,
+ SurfaceClient* client,
+ const gfx::Size& size);
+ ~Surface();
+
+ const gfx::Size& size() const { return size_; }
+ SurfaceId surface_id() const { return surface_id_; }
+
+ void QueueFrame(scoped_ptr<CompositorFrame> frame);
+ // Returns the most recent frame that is eligible to be rendered.
+ CompositorFrame* GetEligibleFrame();
+
+ // Takes a reference to all of the current frame's resources for an external
+ // consumer (e.g. a ResourceProvider). The caller to this should call
+ // UnrefResources() when they are done with the resources.
+ void RefCurrentFrameResources();
+ void UnrefResources(const ReturnedResourceArray& resources);
+
+ // Returns all resources that are currently not in use to the client.
+ void ReturnUnusedResourcesToClient();
+
+ private:
+ void ReceiveResourcesFromClient(const TransferableResourceArray& resources);
+
+ SurfaceManager* manager_;
+ SurfaceClient* client_;
+ gfx::Size size_;
+ SurfaceId surface_id_;
+ // TODO(jamesr): Support multiple frames in flight.
+ scoped_ptr<CompositorFrame> current_frame_;
+
+ struct ResourceRefs {
+ ResourceRefs();
+
+ int refs_received_from_child;
+ int refs_holding_resource_alive;
+ };
+ // Keeps track of the number of users currently in flight for each resource
+ // ID we've received from the client. When this counter hits zero for a
+ // particular resource, that ID is available to return to the client.
+ typedef base::hash_map<ResourceProvider::ResourceId, ResourceRefs>
+ ResourceIdCountMap;
+ ResourceIdCountMap resource_id_use_count_map_;
+
+ ReturnedResourceArray resources_available_to_return_;
+
+ DISALLOW_COPY_AND_ASSIGN(Surface);
+};
+
+} // namespace cc
+
+#endif // CC_SURFACES_SURFACE_H_
diff --git a/chromium/cc/surfaces/surface_aggregator.cc b/chromium/cc/surfaces/surface_aggregator.cc
new file mode 100644
index 00000000000..72300c0a5db
--- /dev/null
+++ b/chromium/cc/surfaces/surface_aggregator.cc
@@ -0,0 +1,250 @@
+// 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_aggregator.h"
+
+#include "base/containers/hash_tables.h"
+#include "base/logging.h"
+#include "cc/output/compositor_frame.h"
+#include "cc/output/delegated_frame_data.h"
+#include "cc/quads/draw_quad.h"
+#include "cc/quads/render_pass_draw_quad.h"
+#include "cc/quads/shared_quad_state.h"
+#include "cc/quads/surface_draw_quad.h"
+#include "cc/surfaces/surface.h"
+#include "cc/surfaces/surface_manager.h"
+
+namespace cc {
+
+SurfaceAggregator::SurfaceAggregator(SurfaceManager* manager)
+ : manager_(manager) {
+ DCHECK(manager_);
+}
+
+SurfaceAggregator::~SurfaceAggregator() {}
+
+DelegatedFrameData* SurfaceAggregator::GetReferencedDataForSurfaceId(
+ SurfaceId surface_id) {
+ Surface* referenced_surface = manager_->GetSurfaceForId(surface_id);
+ if (!referenced_surface)
+ return NULL; // Invalid surface id, skip this quad.
+ CompositorFrame* referenced_frame = referenced_surface->GetEligibleFrame();
+ if (!referenced_frame)
+ return NULL;
+ return referenced_frame->delegated_frame_data.get();
+}
+
+class SurfaceAggregator::RenderPassIdAllocator {
+ public:
+ explicit RenderPassIdAllocator(int surface_id)
+ : surface_id_(surface_id), next_index_(1) {}
+ ~RenderPassIdAllocator() {}
+
+ void AddKnownPass(RenderPass::Id id) {
+ if (id_to_index_map_.find(id) != id_to_index_map_.end())
+ return;
+ id_to_index_map_[id] = next_index_++;
+ }
+
+ RenderPass::Id Remap(RenderPass::Id id) {
+ DCHECK(id_to_index_map_.find(id) != id_to_index_map_.end());
+ return RenderPass::Id(surface_id_, id_to_index_map_[id]);
+ }
+
+ private:
+ base::hash_map<RenderPass::Id, int> id_to_index_map_;
+ int surface_id_;
+ int next_index_;
+
+ DISALLOW_COPY_AND_ASSIGN(RenderPassIdAllocator);
+};
+
+RenderPass::Id SurfaceAggregator::RemapPassId(
+ RenderPass::Id surface_local_pass_id,
+ int surface_id) {
+ RenderPassIdAllocator* allocator = render_pass_allocator_map_.get(surface_id);
+ if (!allocator) {
+ allocator = new RenderPassIdAllocator(surface_id);
+ render_pass_allocator_map_.set(surface_id, make_scoped_ptr(allocator));
+ }
+ allocator->AddKnownPass(surface_local_pass_id);
+ return allocator->Remap(surface_local_pass_id);
+}
+
+void SurfaceAggregator::HandleSurfaceQuad(const SurfaceDrawQuad* surface_quad,
+ RenderPass* dest_pass) {
+ SurfaceId surface_id = surface_quad->surface_id;
+ // If this surface's id is already in our referenced set then it creates
+ // a cycle in the graph and should be dropped.
+ if (referenced_surfaces_.count(surface_id.id))
+ return;
+ DelegatedFrameData* referenced_data =
+ GetReferencedDataForSurfaceId(surface_id);
+ if (!referenced_data)
+ return;
+ std::set<int>::iterator it = referenced_surfaces_.insert(surface_id.id).first;
+
+ const RenderPassList& referenced_passes = referenced_data->render_pass_list;
+ for (size_t j = 0; j + 1 < referenced_passes.size(); ++j) {
+ const RenderPass& source = *referenced_passes[j];
+
+ scoped_ptr<RenderPass> copy_pass(RenderPass::Create());
+
+ RenderPass::Id remapped_pass_id = RemapPassId(source.id, surface_id.id);
+
+ copy_pass->SetAll(remapped_pass_id,
+ source.output_rect,
+ source.damage_rect,
+ source.transform_to_root_target,
+ source.has_transparent_background);
+
+ // Contributing passes aggregated in to the pass list need to take the
+ // transform of the surface quad into account to update their transform to
+ // the root surface.
+ // TODO(jamesr): Make sure this is sufficient for surfaces nested several
+ // levels deep and add tests.
+ copy_pass->transform_to_root_target.ConcatTransform(
+ surface_quad->quadTransform());
+
+ CopyQuadsToPass(source.quad_list,
+ source.shared_quad_state_list,
+ gfx::Transform(),
+ copy_pass.get(),
+ surface_id.id);
+
+ dest_pass_list_->push_back(copy_pass.Pass());
+ }
+
+ // TODO(jamesr): Clean up last pass special casing.
+ const RenderPass& last_pass = *referenced_data->render_pass_list.back();
+ const QuadList& quads = last_pass.quad_list;
+
+ // TODO(jamesr): Make sure clipping is enforced.
+ CopyQuadsToPass(quads,
+ last_pass.shared_quad_state_list,
+ surface_quad->quadTransform(),
+ dest_pass,
+ surface_id.id);
+
+ referenced_surfaces_.erase(it);
+}
+
+void SurfaceAggregator::CopySharedQuadState(
+ const SharedQuadState* source_sqs,
+ const gfx::Transform& content_to_target_transform,
+ RenderPass* dest_render_pass) {
+ SharedQuadState* copy_shared_quad_state =
+ dest_render_pass->CreateAndAppendSharedQuadState();
+ copy_shared_quad_state->CopyFrom(source_sqs);
+ // content_to_target_transform contains any transformation that may exist
+ // between the context that these quads are being copied from (i.e. the
+ // surface's draw transform when aggregated from within a surface) to the
+ // target space of the pass. This will be identity except when copying the
+ // root draw pass from a surface into a pass when the surface draw quad's
+ // transform is not identity.
+ copy_shared_quad_state->content_to_target_transform.ConcatTransform(
+ content_to_target_transform);
+}
+
+void SurfaceAggregator::CopyQuadsToPass(
+ const QuadList& source_quad_list,
+ const SharedQuadStateList& source_shared_quad_state_list,
+ const gfx::Transform& content_to_target_transform,
+ RenderPass* dest_pass,
+ int surface_id) {
+ const SharedQuadState* last_copied_source_shared_quad_state = NULL;
+
+ for (size_t i = 0, sqs_i = 0; i < source_quad_list.size(); ++i) {
+ DrawQuad* quad = source_quad_list[i];
+ while (quad->shared_quad_state != source_shared_quad_state_list[sqs_i]) {
+ ++sqs_i;
+ DCHECK_LT(sqs_i, source_shared_quad_state_list.size());
+ }
+ DCHECK_EQ(quad->shared_quad_state, source_shared_quad_state_list[sqs_i]);
+
+ if (quad->material == DrawQuad::SURFACE_CONTENT) {
+ const SurfaceDrawQuad* surface_quad = SurfaceDrawQuad::MaterialCast(quad);
+ HandleSurfaceQuad(surface_quad, dest_pass);
+ } else {
+ if (quad->shared_quad_state != last_copied_source_shared_quad_state) {
+ CopySharedQuadState(
+ quad->shared_quad_state, content_to_target_transform, dest_pass);
+ last_copied_source_shared_quad_state = quad->shared_quad_state;
+ }
+ if (quad->material == DrawQuad::RENDER_PASS) {
+ const RenderPassDrawQuad* pass_quad =
+ RenderPassDrawQuad::MaterialCast(quad);
+ RenderPass::Id original_pass_id = pass_quad->render_pass_id;
+ RenderPass::Id remapped_pass_id =
+ RemapPassId(original_pass_id, surface_id);
+
+ dest_pass->quad_list.push_back(
+ pass_quad->Copy(dest_pass->shared_quad_state_list.back(),
+ remapped_pass_id).PassAs<DrawQuad>());
+ } else {
+ dest_pass->quad_list.push_back(
+ quad->Copy(dest_pass->shared_quad_state_list.back()));
+ }
+ }
+ }
+}
+
+void SurfaceAggregator::CopyPasses(const RenderPassList& source_pass_list,
+ int surface_id) {
+ for (size_t i = 0; i < source_pass_list.size(); ++i) {
+ const RenderPass& source = *source_pass_list[i];
+
+ scoped_ptr<RenderPass> copy_pass(RenderPass::Create());
+
+ RenderPass::Id remapped_pass_id = RemapPassId(source.id, surface_id);
+
+ copy_pass->SetAll(remapped_pass_id,
+ source.output_rect,
+ source.damage_rect,
+ source.transform_to_root_target,
+ source.has_transparent_background);
+
+ CopyQuadsToPass(source.quad_list,
+ source.shared_quad_state_list,
+ gfx::Transform(),
+ copy_pass.get(),
+ surface_id);
+
+ dest_pass_list_->push_back(copy_pass.Pass());
+ }
+}
+
+scoped_ptr<CompositorFrame> SurfaceAggregator::Aggregate(SurfaceId surface_id) {
+ Surface* surface = manager_->GetSurfaceForId(surface_id);
+ if (!surface)
+ return scoped_ptr<CompositorFrame>();
+ CompositorFrame* root_surface_frame = surface->GetEligibleFrame();
+ if (!root_surface_frame)
+ return scoped_ptr<CompositorFrame>();
+
+ scoped_ptr<CompositorFrame> frame(new CompositorFrame);
+ frame->delegated_frame_data = make_scoped_ptr(new DelegatedFrameData);
+
+ DCHECK(root_surface_frame->delegated_frame_data);
+
+ const RenderPassList& source_pass_list =
+ root_surface_frame->delegated_frame_data->render_pass_list;
+
+ std::set<int>::iterator it = referenced_surfaces_.insert(surface_id.id).first;
+
+ dest_pass_list_ = &frame->delegated_frame_data->render_pass_list;
+ CopyPasses(source_pass_list, surface_id.id);
+
+ referenced_surfaces_.erase(it);
+ DCHECK(referenced_surfaces_.empty());
+
+ dest_pass_list_ = NULL;
+
+ // TODO(jamesr): Aggregate all resource references into the returned frame's
+ // resource list.
+
+ return frame.Pass();
+}
+
+} // namespace cc
diff --git a/chromium/cc/surfaces/surface_aggregator.h b/chromium/cc/surfaces/surface_aggregator.h
new file mode 100644
index 00000000000..fe52050503f
--- /dev/null
+++ b/chromium/cc/surfaces/surface_aggregator.h
@@ -0,0 +1,70 @@
+// 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_AGGREGATOR_H_
+#define CC_SURFACES_SURFACE_AGGREGATOR_H_
+
+#include <set>
+
+#include "base/containers/scoped_ptr_hash_map.h"
+#include "base/memory/scoped_ptr.h"
+#include "cc/quads/render_pass.h"
+#include "cc/surfaces/surface_id.h"
+#include "cc/surfaces/surfaces_export.h"
+
+namespace cc {
+
+class CompositorFrame;
+class DelegatedFrameData;
+class SurfaceDrawQuad;
+class SurfaceManager;
+
+class CC_SURFACES_EXPORT SurfaceAggregator {
+ public:
+ explicit SurfaceAggregator(SurfaceManager* manager);
+ ~SurfaceAggregator();
+
+ scoped_ptr<CompositorFrame> Aggregate(SurfaceId surface_id);
+
+ private:
+ DelegatedFrameData* GetReferencedDataForSurfaceId(SurfaceId surface_id);
+ RenderPass::Id RemapPassId(RenderPass::Id surface_local_pass_id,
+ int surface_id);
+
+ void HandleSurfaceQuad(const SurfaceDrawQuad* surface_quad,
+ RenderPass* dest_pass);
+ void CopySharedQuadState(const SharedQuadState* source_sqs,
+ const gfx::Transform& content_to_target_transform,
+ RenderPass* dest_render_pass);
+ void CopyQuadsToPass(const QuadList& source_quad_list,
+ const SharedQuadStateList& source_shared_quad_state_list,
+ const gfx::Transform& content_to_target_transform,
+ RenderPass* dest_pass,
+ int surface_id);
+ void CopyPasses(const RenderPassList& source_pass_list, int surface_id);
+
+ SurfaceManager* manager_;
+
+ class RenderPassIdAllocator;
+ typedef base::ScopedPtrHashMap<int, RenderPassIdAllocator>
+ RenderPassIdAllocatorMap;
+ RenderPassIdAllocatorMap render_pass_allocator_map_;
+
+ // 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
+ // function call.
+
+ // This is the set of surfaces referenced in the aggregation so far, used to
+ // detect cycles.
+ std::set<int> referenced_surfaces_;
+
+ // This is the pass list for the aggregated frame.
+ RenderPassList* dest_pass_list_;
+
+ DISALLOW_COPY_AND_ASSIGN(SurfaceAggregator);
+};
+
+} // namespace cc
+
+#endif // CC_SURFACES_SURFACE_AGGREGATOR_H_
diff --git a/chromium/cc/surfaces/surface_aggregator_test_helpers.cc b/chromium/cc/surfaces/surface_aggregator_test_helpers.cc
new file mode 100644
index 00000000000..a653eb1735d
--- /dev/null
+++ b/chromium/cc/surfaces/surface_aggregator_test_helpers.cc
@@ -0,0 +1,172 @@
+// 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_aggregator_test_helpers.h"
+
+#include "base/format_macros.h"
+#include "base/strings/stringprintf.h"
+#include "cc/layers/append_quads_data.h"
+#include "cc/output/compositor_frame.h"
+#include "cc/output/delegated_frame_data.h"
+#include "cc/quads/render_pass_draw_quad.h"
+#include "cc/quads/shared_quad_state.h"
+#include "cc/quads/solid_color_draw_quad.h"
+#include "cc/quads/surface_draw_quad.h"
+#include "cc/surfaces/surface.h"
+#include "cc/test/render_pass_test_common.h"
+#include "cc/test/render_pass_test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkXfermode.h"
+
+namespace cc {
+namespace test {
+
+void AddTestSurfaceQuad(TestRenderPass* pass,
+ const gfx::Size& surface_size,
+ SurfaceId surface_id) {
+ gfx::Transform content_to_target_transform;
+ gfx::Size content_bounds = surface_size;
+ gfx::Rect visible_content_rect = gfx::Rect(surface_size);
+ gfx::Rect clip_rect = gfx::Rect(surface_size);
+ bool is_clipped = false;
+ float opacity = 1.0;
+ SkXfermode::Mode blend_mode = SkXfermode::kSrcOver_Mode;
+
+ SharedQuadState* shared_quad_state = pass->CreateAndAppendSharedQuadState();
+ shared_quad_state->SetAll(content_to_target_transform,
+ content_bounds,
+ visible_content_rect,
+ clip_rect,
+ is_clipped,
+ opacity,
+ blend_mode,
+ 0);
+
+ scoped_ptr<SurfaceDrawQuad> surface_quad = SurfaceDrawQuad::Create();
+ gfx::Rect quad_rect = gfx::Rect(surface_size);
+ surface_quad->SetNew(pass->shared_quad_state_list.back(),
+ gfx::Rect(surface_size),
+ gfx::Rect(surface_size),
+ surface_id);
+ pass->quad_list.push_back(surface_quad.PassAs<DrawQuad>());
+}
+void AddTestRenderPassQuad(TestRenderPass* pass,
+ RenderPass::Id render_pass_id) {
+ gfx::Rect output_rect = gfx::Rect(0, 0, 5, 5);
+ SharedQuadState* shared_state = pass->CreateAndAppendSharedQuadState();
+ shared_state->SetAll(gfx::Transform(),
+ output_rect.size(),
+ output_rect,
+ output_rect,
+ false,
+ 1,
+ SkXfermode::kSrcOver_Mode,
+ 0);
+ scoped_ptr<RenderPassDrawQuad> quad = RenderPassDrawQuad::Create();
+ quad->SetNew(shared_state,
+ output_rect,
+ output_rect,
+ render_pass_id,
+ false,
+ 0,
+ output_rect,
+ gfx::RectF(),
+ FilterOperations(),
+ FilterOperations());
+ pass->AppendDrawQuad(quad.PassAs<DrawQuad>());
+}
+
+void AddQuadInPass(TestRenderPass* pass, Quad desc) {
+ switch (desc.material) {
+ case DrawQuad::SOLID_COLOR:
+ AddQuad(pass, gfx::Rect(0, 0, 5, 5), desc.color);
+ break;
+ case DrawQuad::SURFACE_CONTENT:
+ AddTestSurfaceQuad(pass, gfx::Size(5, 5), desc.surface_id);
+ break;
+ case DrawQuad::RENDER_PASS:
+ AddTestRenderPassQuad(pass, desc.render_pass_id);
+ break;
+ default:
+ NOTREACHED();
+ }
+}
+
+void AddPasses(RenderPassList* pass_list,
+ const gfx::Rect& output_rect,
+ Pass* passes,
+ size_t pass_count) {
+ gfx::Transform root_transform;
+ for (size_t i = 0; i < pass_count; ++i) {
+ Pass pass = passes[i];
+ TestRenderPass* test_pass =
+ AddRenderPass(pass_list, pass.id, output_rect, root_transform);
+ for (size_t j = 0; j < pass.quad_count; ++j) {
+ AddQuadInPass(test_pass, pass.quads[j]);
+ }
+ }
+}
+
+void TestQuadMatchesExpectations(Quad expected_quad, DrawQuad* quad) {
+ switch (expected_quad.material) {
+ case DrawQuad::SOLID_COLOR: {
+ ASSERT_EQ(DrawQuad::SOLID_COLOR, quad->material);
+
+ const SolidColorDrawQuad* solid_color_quad =
+ SolidColorDrawQuad::MaterialCast(quad);
+
+ EXPECT_EQ(expected_quad.color, solid_color_quad->color);
+ break;
+ }
+ default:
+ NOTREACHED();
+ break;
+ }
+}
+
+void TestPassMatchesExpectations(Pass expected_pass, RenderPass* pass) {
+ ASSERT_EQ(expected_pass.quad_count, pass->quad_list.size());
+ for (size_t i = 0u; i < pass->quad_list.size(); ++i) {
+ SCOPED_TRACE(base::StringPrintf("Quad number %" PRIuS, i));
+ TestQuadMatchesExpectations(expected_pass.quads[i], pass->quad_list.at(i));
+ }
+}
+
+void TestPassesMatchExpectations(Pass* expected_passes,
+ size_t expected_pass_count,
+ RenderPassList* passes) {
+ ASSERT_EQ(expected_pass_count, passes->size());
+
+ for (size_t i = 0; i < passes->size(); ++i) {
+ SCOPED_TRACE(base::StringPrintf("Pass number %" PRIuS, i));
+ RenderPass* pass = passes->at(i);
+ TestPassMatchesExpectations(expected_passes[i], pass);
+ }
+}
+
+void SubmitFrame(Pass* passes, size_t pass_count, Surface* surface) {
+ RenderPassList pass_list;
+ AddPasses(&pass_list, gfx::Rect(surface->size()), passes, pass_count);
+
+ scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
+ pass_list.swap(frame_data->render_pass_list);
+
+ scoped_ptr<CompositorFrame> frame(new CompositorFrame);
+ frame->delegated_frame_data = frame_data.Pass();
+
+ surface->QueueFrame(frame.Pass());
+}
+
+void QueuePassAsFrame(scoped_ptr<RenderPass> pass, Surface* surface) {
+ scoped_ptr<DelegatedFrameData> delegated_frame_data(new DelegatedFrameData);
+ delegated_frame_data->render_pass_list.push_back(pass.Pass());
+
+ scoped_ptr<CompositorFrame> child_frame(new CompositorFrame);
+ child_frame->delegated_frame_data = delegated_frame_data.Pass();
+
+ surface->QueueFrame(child_frame.Pass());
+}
+
+} // namespace test
+} // namespace cc
diff --git a/chromium/cc/surfaces/surface_aggregator_test_helpers.h b/chromium/cc/surfaces/surface_aggregator_test_helpers.h
new file mode 100644
index 00000000000..10c56590d79
--- /dev/null
+++ b/chromium/cc/surfaces/surface_aggregator_test_helpers.h
@@ -0,0 +1,95 @@
+// 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_AGGREGATOR_TEST_HELPERS_H_
+#define CC_SURFACES_SURFACE_AGGREGATOR_TEST_HELPERS_H_
+
+#include "cc/quads/draw_quad.h"
+#include "cc/quads/render_pass.h"
+#include "cc/surfaces/surface_id.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/gfx/size.h"
+
+namespace cc {
+
+class Surface;
+class TestRenderPass;
+
+namespace test {
+
+struct Quad {
+ static Quad SolidColorQuad(SkColor color) {
+ Quad quad;
+ quad.material = DrawQuad::SOLID_COLOR;
+ quad.color = color;
+ return quad;
+ }
+
+ static Quad SurfaceQuad(SurfaceId surface_id) {
+ Quad quad;
+ quad.material = DrawQuad::SURFACE_CONTENT;
+ quad.surface_id = surface_id;
+ return quad;
+ }
+
+ static Quad RenderPassQuad(RenderPass::Id id) {
+ Quad quad;
+ quad.material = DrawQuad::RENDER_PASS;
+ quad.render_pass_id = id;
+ return quad;
+ }
+
+ DrawQuad::Material material;
+ // Set when material==DrawQuad::SURFACE_CONTENT.
+ SurfaceId surface_id;
+ // Set when material==DrawQuad::SOLID_COLOR.
+ SkColor color;
+ // Set when material==DrawQuad::RENDER_PASS.
+ RenderPass::Id render_pass_id;
+
+ private:
+ Quad()
+ : material(DrawQuad::INVALID),
+ color(SK_ColorWHITE),
+ render_pass_id(-1, -1) {}
+};
+
+struct Pass {
+ Pass(Quad* quads, size_t quad_count, RenderPass::Id id)
+ : quads(quads), quad_count(quad_count), id(id) {}
+ Pass(Quad* quads, size_t quad_count)
+ : quads(quads), quad_count(quad_count), id(1, 1) {}
+
+ Quad* quads;
+ size_t quad_count;
+ RenderPass::Id id;
+};
+
+void AddSurfaceQuad(TestRenderPass* pass,
+ const gfx::Size& surface_size,
+ int surface_id);
+
+void AddQuadInPass(TestRenderPass* pass, Quad desc);
+
+void AddPasses(RenderPassList* pass_list,
+ const gfx::Rect& output_rect,
+ Pass* passes,
+ size_t pass_count);
+
+void TestQuadMatchesExpectations(Quad expected_quad, DrawQuad* quad);
+
+void TestPassMatchesExpectations(Pass expected_pass, RenderPass* pass);
+
+void TestPassesMatchExpectations(Pass* expected_passes,
+ size_t expected_pass_count,
+ RenderPassList* passes);
+
+void SubmitFrame(Pass* passes, size_t pass_count, Surface* surface);
+
+void QueuePassAsFrame(scoped_ptr<RenderPass> pass, Surface* surface);
+
+} // namespace test
+} // namespace cc
+
+#endif // CC_SURFACES_SURFACE_AGGREGATOR_TEST_HELPERS_H_
diff --git a/chromium/cc/surfaces/surface_aggregator_unittest.cc b/chromium/cc/surfaces/surface_aggregator_unittest.cc
new file mode 100644
index 00000000000..62ba079aad9
--- /dev/null
+++ b/chromium/cc/surfaces/surface_aggregator_unittest.cc
@@ -0,0 +1,708 @@
+// 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/output/compositor_frame.h"
+#include "cc/output/delegated_frame_data.h"
+#include "cc/quads/render_pass.h"
+#include "cc/quads/render_pass_draw_quad.h"
+#include "cc/quads/solid_color_draw_quad.h"
+#include "cc/quads/surface_draw_quad.h"
+#include "cc/surfaces/surface.h"
+#include "cc/surfaces/surface_aggregator.h"
+#include "cc/surfaces/surface_aggregator_test_helpers.h"
+#include "cc/surfaces/surface_manager.h"
+#include "cc/test/render_pass_test_common.h"
+#include "cc/test/render_pass_test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkColor.h"
+
+namespace cc {
+namespace {
+
+SurfaceId InvalidSurfaceId() {
+ static SurfaceId invalid;
+ invalid.id = -1;
+ return invalid;
+}
+
+class SurfaceAggregatorTest : public testing::Test {
+ public:
+ SurfaceAggregatorTest() : aggregator_(&manager_) {}
+
+ protected:
+ SurfaceManager manager_;
+ SurfaceAggregator aggregator_;
+};
+
+TEST_F(SurfaceAggregatorTest, InvalidSurfaceId) {
+ scoped_ptr<CompositorFrame> frame = aggregator_.Aggregate(InvalidSurfaceId());
+ EXPECT_FALSE(frame);
+}
+
+TEST_F(SurfaceAggregatorTest, ValidSurfaceNoFrame) {
+ Surface one(&manager_, NULL, gfx::Size(5, 5));
+ scoped_ptr<CompositorFrame> frame = aggregator_.Aggregate(one.surface_id());
+ EXPECT_FALSE(frame);
+}
+
+class SurfaceAggregatorValidSurfaceTest : public SurfaceAggregatorTest {
+ public:
+ SurfaceAggregatorValidSurfaceTest()
+ : root_surface_(&manager_, NULL, gfx::Size(5, 5)) {}
+
+ void AggregateAndVerify(test::Pass* expected_passes,
+ size_t expected_pass_count) {
+ scoped_ptr<CompositorFrame> aggregated_frame =
+ aggregator_.Aggregate(root_surface_.surface_id());
+
+ ASSERT_TRUE(aggregated_frame);
+ ASSERT_TRUE(aggregated_frame->delegated_frame_data);
+
+ DelegatedFrameData* frame_data =
+ aggregated_frame->delegated_frame_data.get();
+
+ TestPassesMatchExpectations(
+ expected_passes, expected_pass_count, &frame_data->render_pass_list);
+ }
+
+ protected:
+ Surface root_surface_;
+};
+
+// Tests that a very simple frame containing only two solid color quads makes it
+// through the aggregator correctly.
+TEST_F(SurfaceAggregatorValidSurfaceTest, SimpleFrame) {
+ test::Quad quads[] = {test::Quad::SolidColorQuad(SK_ColorRED),
+ test::Quad::SolidColorQuad(SK_ColorBLUE)};
+ test::Pass passes[] = {test::Pass(quads, arraysize(quads))};
+
+ SubmitFrame(passes, arraysize(passes), &root_surface_);
+
+ AggregateAndVerify(passes, arraysize(passes));
+}
+
+TEST_F(SurfaceAggregatorValidSurfaceTest, MultiPassSimpleFrame) {
+ test::Quad quads[][2] = {{test::Quad::SolidColorQuad(SK_ColorWHITE),
+ test::Quad::SolidColorQuad(SK_ColorLTGRAY)},
+ {test::Quad::SolidColorQuad(SK_ColorGRAY),
+ test::Quad::SolidColorQuad(SK_ColorDKGRAY)}};
+ test::Pass passes[] = {test::Pass(quads[0], arraysize(quads[0])),
+ test::Pass(quads[1], arraysize(quads[1]))};
+
+ SubmitFrame(passes, arraysize(passes), &root_surface_);
+
+ AggregateAndVerify(passes, arraysize(passes));
+}
+
+// This tests very simple embedding. root_surface has a frame containing a few
+// solid color quads and a surface quad referencing embedded_surface.
+// embedded_surface has a frame containing only a solid color quad. The solid
+// color quad should be aggregated into the final frame.
+TEST_F(SurfaceAggregatorValidSurfaceTest, SimpleSurfaceReference) {
+ gfx::Size surface_size(5, 5);
+
+ Surface embedded_surface(&manager_, NULL, surface_size);
+
+ test::Quad embedded_quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN)};
+ test::Pass embedded_passes[] = {
+ test::Pass(embedded_quads, arraysize(embedded_quads))};
+
+ SubmitFrame(embedded_passes, arraysize(embedded_passes), &embedded_surface);
+
+ test::Quad root_quads[] = {
+ test::Quad::SolidColorQuad(SK_ColorWHITE),
+ test::Quad::SurfaceQuad(embedded_surface.surface_id()),
+ test::Quad::SolidColorQuad(SK_ColorBLACK)};
+ test::Pass root_passes[] = {test::Pass(root_quads, arraysize(root_quads))};
+
+ SubmitFrame(root_passes, arraysize(root_passes), &root_surface_);
+
+ test::Quad expected_quads[] = {test::Quad::SolidColorQuad(SK_ColorWHITE),
+ test::Quad::SolidColorQuad(SK_ColorGREEN),
+ test::Quad::SolidColorQuad(SK_ColorBLACK)};
+ test::Pass expected_passes[] = {
+ test::Pass(expected_quads, arraysize(expected_quads))};
+ AggregateAndVerify(expected_passes, arraysize(expected_passes));
+}
+
+// This tests referencing a surface that has multiple render passes.
+TEST_F(SurfaceAggregatorValidSurfaceTest, MultiPassSurfaceReference) {
+ gfx::Size surface_size(5, 5);
+
+ Surface embedded_surface(&manager_, NULL, surface_size);
+
+ RenderPass::Id pass_ids[] = {RenderPass::Id(1, 1), RenderPass::Id(1, 2),
+ RenderPass::Id(1, 3)};
+
+ test::Quad embedded_quads[][2] = {
+ {test::Quad::SolidColorQuad(1), test::Quad::SolidColorQuad(2)},
+ {test::Quad::SolidColorQuad(3), test::Quad::RenderPassQuad(pass_ids[0])},
+ {test::Quad::SolidColorQuad(4), test::Quad::RenderPassQuad(pass_ids[1])}};
+ test::Pass embedded_passes[] = {
+ test::Pass(embedded_quads[0], arraysize(embedded_quads[0]), pass_ids[0]),
+ test::Pass(embedded_quads[1], arraysize(embedded_quads[1]), pass_ids[1]),
+ test::Pass(embedded_quads[2], arraysize(embedded_quads[2]), pass_ids[2])};
+
+ SubmitFrame(embedded_passes, arraysize(embedded_passes), &embedded_surface);
+
+ test::Quad root_quads[][2] = {
+ {test::Quad::SolidColorQuad(5), test::Quad::SolidColorQuad(6)},
+ {test::Quad::SurfaceQuad(embedded_surface.surface_id()),
+ test::Quad::RenderPassQuad(pass_ids[0])},
+ {test::Quad::SolidColorQuad(7), test::Quad::RenderPassQuad(pass_ids[1])}};
+ test::Pass root_passes[] = {
+ test::Pass(root_quads[0], arraysize(root_quads[0]), pass_ids[0]),
+ test::Pass(root_quads[1], arraysize(root_quads[1]), pass_ids[1]),
+ test::Pass(root_quads[2], arraysize(root_quads[2]), pass_ids[2])};
+
+ SubmitFrame(root_passes, arraysize(root_passes), &root_surface_);
+
+ scoped_ptr<CompositorFrame> aggregated_frame =
+ aggregator_.Aggregate(root_surface_.surface_id());
+
+ ASSERT_TRUE(aggregated_frame);
+ ASSERT_TRUE(aggregated_frame->delegated_frame_data);
+
+ DelegatedFrameData* frame_data = aggregated_frame->delegated_frame_data.get();
+
+ const RenderPassList& aggregated_pass_list = frame_data->render_pass_list;
+
+ ASSERT_EQ(5u, aggregated_pass_list.size());
+ RenderPass::Id actual_pass_ids[] = {
+ aggregated_pass_list[0]->id, aggregated_pass_list[1]->id,
+ aggregated_pass_list[2]->id, aggregated_pass_list[3]->id,
+ aggregated_pass_list[4]->id};
+ for (size_t i = 0; i < 5; ++i) {
+ for (size_t j = 0; j < i; ++j) {
+ EXPECT_NE(actual_pass_ids[i], actual_pass_ids[j]);
+ }
+ }
+
+ {
+ SCOPED_TRACE("First pass");
+ // The first pass will just be the first pass from the root surfaces quad
+ // with no render pass quads to remap.
+ TestPassMatchesExpectations(root_passes[0], aggregated_pass_list[0]);
+ }
+
+ {
+ SCOPED_TRACE("Second pass");
+ // The next two passes will be from the embedded surface since we have to
+ // draw those passes before they are referenced from the render pass draw
+ // quad embedded into the root surface's second pass.
+ // First, there's the first embedded pass which doesn't reference anything
+ // else.
+ TestPassMatchesExpectations(embedded_passes[0], aggregated_pass_list[1]);
+ }
+
+ {
+ SCOPED_TRACE("Third pass");
+ const QuadList& third_pass_quad_list = aggregated_pass_list[2]->quad_list;
+ ASSERT_EQ(2u, third_pass_quad_list.size());
+ TestQuadMatchesExpectations(embedded_quads[1][0],
+ third_pass_quad_list.at(0u));
+
+ // This render pass pass quad will reference the first pass from the
+ // embedded surface, which is the second pass in the aggregated frame.
+ ASSERT_EQ(DrawQuad::RENDER_PASS, third_pass_quad_list.at(1u)->material);
+ const RenderPassDrawQuad* third_pass_render_pass_draw_quad =
+ RenderPassDrawQuad::MaterialCast(third_pass_quad_list.at(1u));
+ EXPECT_EQ(actual_pass_ids[1],
+ third_pass_render_pass_draw_quad->render_pass_id);
+ }
+
+ {
+ SCOPED_TRACE("Fourth pass");
+ // The fourth pass will have aggregated quads from the root surface's second
+ // pass and the embedded surface's first pass.
+ const QuadList& fourth_pass_quad_list = aggregated_pass_list[3]->quad_list;
+ ASSERT_EQ(3u, fourth_pass_quad_list.size());
+
+ // The first quad will be the yellow quad from the embedded surface's last
+ // pass.
+ TestQuadMatchesExpectations(embedded_quads[2][0],
+ fourth_pass_quad_list.at(0u));
+
+ // The next quad will be a render pass quad referencing the second pass from
+ // the embedded surface, which is the third pass in the aggregated frame.
+ ASSERT_EQ(DrawQuad::RENDER_PASS, fourth_pass_quad_list.at(1u)->material);
+ const RenderPassDrawQuad* fourth_pass_first_render_pass_draw_quad =
+ RenderPassDrawQuad::MaterialCast(fourth_pass_quad_list.at(1u));
+ EXPECT_EQ(actual_pass_ids[2],
+ fourth_pass_first_render_pass_draw_quad->render_pass_id);
+
+ // The last quad will be a render pass quad referencing the first pass from
+ // the root surface, which is the first pass overall.
+ ASSERT_EQ(DrawQuad::RENDER_PASS, fourth_pass_quad_list.at(2u)->material);
+ const RenderPassDrawQuad* fourth_pass_second_render_pass_draw_quad =
+ RenderPassDrawQuad::MaterialCast(fourth_pass_quad_list.at(2u));
+ EXPECT_EQ(actual_pass_ids[0],
+ fourth_pass_second_render_pass_draw_quad->render_pass_id);
+ }
+
+ {
+ SCOPED_TRACE("Fifth pass");
+ const QuadList& fifth_pass_quad_list = aggregated_pass_list[4]->quad_list;
+ ASSERT_EQ(2u, fifth_pass_quad_list.size());
+
+ TestQuadMatchesExpectations(root_quads[2][0], fifth_pass_quad_list.at(0));
+
+ // The last quad in the last pass will reference the second pass from the
+ // root surface, which after aggregating is the fourth pass in the overall
+ // list.
+ ASSERT_EQ(DrawQuad::RENDER_PASS, fifth_pass_quad_list.at(1u)->material);
+ const RenderPassDrawQuad* fifth_pass_render_pass_draw_quad =
+ RenderPassDrawQuad::MaterialCast(fifth_pass_quad_list.at(1u));
+ EXPECT_EQ(actual_pass_ids[3],
+ fifth_pass_render_pass_draw_quad->render_pass_id);
+ }
+}
+
+// Tests an invalid surface reference in a frame. The surface quad should just
+// be dropped.
+TEST_F(SurfaceAggregatorValidSurfaceTest, InvalidSurfaceReference) {
+ test::Quad quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN),
+ test::Quad::SurfaceQuad(InvalidSurfaceId()),
+ test::Quad::SolidColorQuad(SK_ColorBLUE)};
+ test::Pass passes[] = {test::Pass(quads, arraysize(quads))};
+
+ SubmitFrame(passes, arraysize(passes), &root_surface_);
+
+ test::Quad expected_quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN),
+ test::Quad::SolidColorQuad(SK_ColorBLUE)};
+ test::Pass expected_passes[] = {
+ test::Pass(expected_quads, arraysize(expected_quads))};
+ AggregateAndVerify(expected_passes, arraysize(expected_passes));
+}
+
+// Tests a reference to a valid surface with no submitted frame. This quad
+// should also just be dropped.
+TEST_F(SurfaceAggregatorValidSurfaceTest, ValidSurfaceReferenceWithNoFrame) {
+ Surface surface_with_no_frame(&manager_, NULL, gfx::Size(5, 5));
+ test::Quad quads[] = {
+ test::Quad::SolidColorQuad(SK_ColorGREEN),
+ test::Quad::SurfaceQuad(surface_with_no_frame.surface_id()),
+ test::Quad::SolidColorQuad(SK_ColorBLUE)};
+ test::Pass passes[] = {test::Pass(quads, arraysize(quads))};
+
+ SubmitFrame(passes, arraysize(passes), &root_surface_);
+
+ test::Quad expected_quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN),
+ test::Quad::SolidColorQuad(SK_ColorBLUE)};
+ test::Pass expected_passes[] = {
+ test::Pass(expected_quads, arraysize(expected_quads))};
+ AggregateAndVerify(expected_passes, arraysize(expected_passes));
+}
+
+// Tests a surface quad referencing itself, generating a trivial cycle.
+// The quad creating the cycle should be dropped from the final frame.
+TEST_F(SurfaceAggregatorValidSurfaceTest, SimpleCyclicalReference) {
+ test::Quad quads[] = {test::Quad::SurfaceQuad(root_surface_.surface_id()),
+ test::Quad::SolidColorQuad(SK_ColorYELLOW)};
+ test::Pass passes[] = {test::Pass(quads, arraysize(quads))};
+
+ SubmitFrame(passes, arraysize(passes), &root_surface_);
+
+ test::Quad expected_quads[] = {test::Quad::SolidColorQuad(SK_ColorYELLOW)};
+ test::Pass expected_passes[] = {
+ test::Pass(expected_quads, arraysize(expected_quads))};
+ AggregateAndVerify(expected_passes, arraysize(expected_passes));
+}
+
+// Tests a more complex cycle with one intermediate surface.
+TEST_F(SurfaceAggregatorValidSurfaceTest, TwoSurfaceCyclicalReference) {
+ gfx::Size surface_size(5, 5);
+
+ Surface child_surface(&manager_, NULL, surface_size);
+
+ test::Quad parent_quads[] = {
+ test::Quad::SolidColorQuad(SK_ColorBLUE),
+ test::Quad::SurfaceQuad(child_surface.surface_id()),
+ test::Quad::SolidColorQuad(SK_ColorCYAN)};
+ test::Pass parent_passes[] = {
+ test::Pass(parent_quads, arraysize(parent_quads))};
+
+ SubmitFrame(parent_passes, arraysize(parent_passes), &root_surface_);
+
+ test::Quad child_quads[] = {
+ test::Quad::SolidColorQuad(SK_ColorGREEN),
+ test::Quad::SurfaceQuad(root_surface_.surface_id()),
+ test::Quad::SolidColorQuad(SK_ColorMAGENTA)};
+ test::Pass child_passes[] = {test::Pass(child_quads, arraysize(child_quads))};
+
+ SubmitFrame(child_passes, arraysize(child_passes), &child_surface);
+
+ // The child surface's reference to the root_surface_ will be dropped, so
+ // we'll end up with:
+ // SK_ColorBLUE from the parent
+ // SK_ColorGREEN from the child
+ // SK_ColorMAGENTA from the child
+ // SK_ColorCYAN from the parent
+ test::Quad expected_quads[] = {test::Quad::SolidColorQuad(SK_ColorBLUE),
+ test::Quad::SolidColorQuad(SK_ColorGREEN),
+ test::Quad::SolidColorQuad(SK_ColorMAGENTA),
+ test::Quad::SolidColorQuad(SK_ColorCYAN)};
+ test::Pass expected_passes[] = {
+ test::Pass(expected_quads, arraysize(expected_quads))};
+ AggregateAndVerify(expected_passes, arraysize(expected_passes));
+}
+
+// Tests that we map render pass IDs from different surfaces into a unified
+// namespace and update RenderPassDrawQuad's id references to match.
+TEST_F(SurfaceAggregatorValidSurfaceTest, RenderPassIdMapping) {
+ gfx::Size surface_size(5, 5);
+
+ Surface child_surface(&manager_, NULL, surface_size);
+
+ RenderPass::Id child_pass_id[] = {RenderPass::Id(1, 1), RenderPass::Id(1, 2)};
+ test::Quad child_quad[][1] = {{test::Quad::SolidColorQuad(SK_ColorGREEN)},
+ {test::Quad::RenderPassQuad(child_pass_id[0])}};
+ test::Pass surface_passes[] = {
+ test::Pass(child_quad[0], arraysize(child_quad[0]), child_pass_id[0]),
+ test::Pass(child_quad[1], arraysize(child_quad[1]), child_pass_id[1])};
+
+ SubmitFrame(surface_passes, arraysize(surface_passes), &child_surface);
+
+ // Pass IDs from the parent surface may collide with ones from the child.
+ RenderPass::Id parent_pass_id[] = {RenderPass::Id(2, 1),
+ RenderPass::Id(1, 2)};
+ test::Quad parent_quad[][1] = {
+ {test::Quad::SurfaceQuad(child_surface.surface_id())},
+ {test::Quad::RenderPassQuad(parent_pass_id[0])}};
+ test::Pass parent_passes[] = {
+ test::Pass(parent_quad[0], arraysize(parent_quad[0]), parent_pass_id[0]),
+ test::Pass(parent_quad[1], arraysize(parent_quad[1]), parent_pass_id[1])};
+
+ SubmitFrame(parent_passes, arraysize(parent_passes), &root_surface_);
+ scoped_ptr<CompositorFrame> aggregated_frame =
+ aggregator_.Aggregate(root_surface_.surface_id());
+
+ ASSERT_TRUE(aggregated_frame);
+ ASSERT_TRUE(aggregated_frame->delegated_frame_data);
+
+ DelegatedFrameData* frame_data = aggregated_frame->delegated_frame_data.get();
+
+ const RenderPassList& aggregated_pass_list = frame_data->render_pass_list;
+
+ ASSERT_EQ(3u, aggregated_pass_list.size());
+ RenderPass::Id actual_pass_ids[] = {aggregated_pass_list[0]->id,
+ aggregated_pass_list[1]->id,
+ aggregated_pass_list[2]->id};
+ // Make sure the aggregated frame's pass IDs are all unique.
+ for (size_t i = 0; i < 3; ++i) {
+ for (size_t j = 0; j < i; ++j) {
+ EXPECT_NE(actual_pass_ids[j], actual_pass_ids[i]) << "pass ids " << i
+ << " and " << j;
+ }
+ }
+
+ // Make sure the render pass quads reference the remapped pass IDs.
+ DrawQuad* render_pass_quads[] = {aggregated_pass_list[1]->quad_list[0],
+ aggregated_pass_list[2]->quad_list[0]};
+ ASSERT_EQ(render_pass_quads[0]->material, DrawQuad::RENDER_PASS);
+ EXPECT_EQ(
+ actual_pass_ids[0],
+ RenderPassDrawQuad::MaterialCast(render_pass_quads[0])->render_pass_id);
+
+ ASSERT_EQ(render_pass_quads[1]->material, DrawQuad::RENDER_PASS);
+ EXPECT_EQ(
+ actual_pass_ids[1],
+ RenderPassDrawQuad::MaterialCast(render_pass_quads[1])->render_pass_id);
+}
+
+void AddSolidColorQuadWithBlendMode(const gfx::Size& size,
+ RenderPass* pass,
+ const SkXfermode::Mode blend_mode) {
+ const gfx::Transform content_to_target_transform;
+ const gfx::Size content_bounds(size);
+ const gfx::Rect visible_content_rect(size);
+ const gfx::Rect clip_rect(size);
+
+ bool is_clipped = false;
+ float opacity = 1.f;
+
+ bool force_anti_aliasing_off = false;
+ SharedQuadState* sqs = pass->CreateAndAppendSharedQuadState();
+ sqs->SetAll(content_to_target_transform,
+ content_bounds,
+ visible_content_rect,
+ clip_rect,
+ is_clipped,
+ opacity,
+ blend_mode,
+ 0);
+
+ scoped_ptr<SolidColorDrawQuad> color_quad = SolidColorDrawQuad::Create();
+ color_quad->SetNew(pass->shared_quad_state_list.back(),
+ visible_content_rect,
+ visible_content_rect,
+ SK_ColorGREEN,
+ force_anti_aliasing_off);
+ pass->quad_list.push_back(color_quad.PassAs<DrawQuad>());
+}
+
+// This tests that we update shared quad state pointers correctly within
+// aggregated passes. The shared quad state list on the aggregated pass will
+// include the shared quad states from each pass in one list so the quads will
+// end up pointed to shared quad state objects at different offsets. This test
+// uses the blend_mode value stored on the shared quad state to track the shared
+// quad state, but anything saved on the shared quad state would work.
+//
+// This test has 4 surfaces in the following structure:
+// root_surface -> quad with kClear_Mode,
+// [child_one_surface],
+// quad with kDstOver_Mode,
+// [child_two_surface],
+// quad with kDstIn_Mode
+// child_one_surface -> quad with kSrc_Mode,
+// [grandchild_surface],
+// quad with kSrcOver_Mode
+// child_two_surface -> quad with kSrcIn_Mode
+// grandchild_surface -> quad with kDst_Mode
+//
+// Resulting in the following aggregated pass:
+// quad_root_0 - blend_mode kClear_Mode
+// quad_child_one_0 - blend_mode kSrc_Mode
+// quad_grandchild_0 - blend_mode kDst_Mode
+// quad_child_one_1 - blend_mode kSrcOver_Mode
+// quad_root_1 - blend_mode kDstOver_Mode
+// quad_child_two_0 - blend_mode kSrcIn_Mode
+// quad_root_2 - blend_mode kDstIn_Mode
+TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateSharedQuadStateProperties) {
+ gfx::Size surface_size(5, 5);
+
+ const SkXfermode::Mode blend_modes[] = {SkXfermode::kClear_Mode, // 0
+ SkXfermode::kSrc_Mode, // 1
+ SkXfermode::kDst_Mode, // 2
+ SkXfermode::kSrcOver_Mode, // 3
+ SkXfermode::kDstOver_Mode, // 4
+ SkXfermode::kSrcIn_Mode, // 5
+ SkXfermode::kDstIn_Mode, // 6
+ };
+
+ RenderPass::Id pass_id(1, 1);
+ Surface grandchild_surface(&manager_, NULL, surface_size);
+ scoped_ptr<RenderPass> grandchild_pass = RenderPass::Create();
+ gfx::Rect output_rect(surface_size);
+ gfx::Rect damage_rect(surface_size);
+ gfx::Transform transform_to_root_target;
+ grandchild_pass->SetNew(
+ pass_id, output_rect, damage_rect, transform_to_root_target);
+ AddSolidColorQuadWithBlendMode(
+ surface_size, grandchild_pass.get(), blend_modes[2]);
+ test::QueuePassAsFrame(grandchild_pass.Pass(), &grandchild_surface);
+
+ Surface child_one_surface(&manager_, NULL, surface_size);
+
+ scoped_ptr<RenderPass> child_one_pass = RenderPass::Create();
+ child_one_pass->SetNew(
+ pass_id, output_rect, damage_rect, transform_to_root_target);
+ AddSolidColorQuadWithBlendMode(
+ surface_size, child_one_pass.get(), blend_modes[1]);
+ scoped_ptr<SurfaceDrawQuad> grandchild_surface_quad =
+ SurfaceDrawQuad::Create();
+ grandchild_surface_quad->SetNew(child_one_pass->shared_quad_state_list.back(),
+ gfx::Rect(surface_size),
+ gfx::Rect(surface_size),
+ grandchild_surface.surface_id());
+ child_one_pass->quad_list.push_back(
+ grandchild_surface_quad.PassAs<DrawQuad>());
+ AddSolidColorQuadWithBlendMode(
+ surface_size, child_one_pass.get(), blend_modes[3]);
+ test::QueuePassAsFrame(child_one_pass.Pass(), &child_one_surface);
+
+ Surface child_two_surface(&manager_, NULL, surface_size);
+
+ scoped_ptr<RenderPass> child_two_pass = RenderPass::Create();
+ child_two_pass->SetNew(
+ pass_id, output_rect, damage_rect, transform_to_root_target);
+ AddSolidColorQuadWithBlendMode(
+ surface_size, child_two_pass.get(), blend_modes[5]);
+ test::QueuePassAsFrame(child_two_pass.Pass(), &child_two_surface);
+
+ scoped_ptr<RenderPass> root_pass = RenderPass::Create();
+ root_pass->SetNew(
+ pass_id, output_rect, damage_rect, transform_to_root_target);
+
+ AddSolidColorQuadWithBlendMode(surface_size, root_pass.get(), blend_modes[0]);
+ scoped_ptr<SurfaceDrawQuad> child_one_surface_quad =
+ SurfaceDrawQuad::Create();
+ child_one_surface_quad->SetNew(root_pass->shared_quad_state_list.back(),
+ gfx::Rect(surface_size),
+ gfx::Rect(surface_size),
+ child_one_surface.surface_id());
+ root_pass->quad_list.push_back(child_one_surface_quad.PassAs<DrawQuad>());
+ AddSolidColorQuadWithBlendMode(surface_size, root_pass.get(), blend_modes[4]);
+ scoped_ptr<SurfaceDrawQuad> child_two_surface_quad =
+ SurfaceDrawQuad::Create();
+ child_two_surface_quad->SetNew(root_pass->shared_quad_state_list.back(),
+ gfx::Rect(surface_size),
+ gfx::Rect(surface_size),
+ child_two_surface.surface_id());
+ root_pass->quad_list.push_back(child_two_surface_quad.PassAs<DrawQuad>());
+ AddSolidColorQuadWithBlendMode(surface_size, root_pass.get(), blend_modes[6]);
+
+ test::QueuePassAsFrame(root_pass.Pass(), &root_surface_);
+
+ scoped_ptr<CompositorFrame> aggregated_frame =
+ aggregator_.Aggregate(root_surface_.surface_id());
+
+ ASSERT_TRUE(aggregated_frame);
+ ASSERT_TRUE(aggregated_frame->delegated_frame_data);
+
+ DelegatedFrameData* frame_data = aggregated_frame->delegated_frame_data.get();
+
+ const RenderPassList& aggregated_pass_list = frame_data->render_pass_list;
+
+ ASSERT_EQ(1u, aggregated_pass_list.size());
+
+ const QuadList& aggregated_quad_list = aggregated_pass_list[0]->quad_list;
+
+ ASSERT_EQ(7u, aggregated_quad_list.size());
+
+ for (size_t i = 0; i < aggregated_quad_list.size(); ++i) {
+ DrawQuad* quad = aggregated_quad_list[i];
+ EXPECT_EQ(blend_modes[i], quad->shared_quad_state->blend_mode) << i;
+ }
+}
+
+// This tests that when aggregating a frame with multiple render passes that we
+// map the transforms for the root pass but do not modify the transform on child
+// passes.
+//
+// The root surface has one pass with a surface quad transformed by +10 in the y
+// direction.
+//
+// The child surface has two passes. The first pass has a quad with a transform
+// of +5 in the x direction. The second pass has a reference to the first pass'
+// pass id and a transform of +8 in the x direction.
+//
+// After aggregation, the child surface's root pass quad should have both
+// transforms concatenated for a total transform of +8 x, +10 y. The
+// contributing render pass' transform in the aggregate frame should not be
+// affected.
+TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateMultiplePassWithTransform) {
+ gfx::Size surface_size(5, 5);
+
+ Surface child_surface(&manager_, NULL, surface_size);
+ RenderPass::Id child_pass_id[] = {RenderPass::Id(1, 1), RenderPass::Id(1, 2)};
+ test::Quad child_quads[][1] = {
+ {test::Quad::SolidColorQuad(SK_ColorGREEN)},
+ {test::Quad::RenderPassQuad(child_pass_id[0])}};
+ test::Pass child_passes[] = {
+ test::Pass(child_quads[0], arraysize(child_quads[0]), child_pass_id[0]),
+ test::Pass(child_quads[1], arraysize(child_quads[1]), child_pass_id[1])};
+
+ RenderPassList child_pass_list;
+ AddPasses(&child_pass_list,
+ gfx::Rect(surface_size),
+ child_passes,
+ arraysize(child_passes));
+
+ RenderPass* child_nonroot_pass = child_pass_list.at(0u);
+ child_nonroot_pass->transform_to_root_target.Translate(8, 0);
+ SharedQuadState* child_nonroot_pass_sqs =
+ child_nonroot_pass->shared_quad_state_list[0];
+ child_nonroot_pass_sqs->content_to_target_transform.Translate(5, 0);
+
+ RenderPass* child_root_pass = child_pass_list.at(1u);
+ SharedQuadState* child_root_pass_sqs =
+ child_root_pass->shared_quad_state_list[0];
+ child_root_pass_sqs->content_to_target_transform.Translate(8, 0);
+
+ scoped_ptr<DelegatedFrameData> child_frame_data(new DelegatedFrameData);
+ child_pass_list.swap(child_frame_data->render_pass_list);
+
+ scoped_ptr<CompositorFrame> child_frame(new CompositorFrame);
+ child_frame->delegated_frame_data = child_frame_data.Pass();
+
+ child_surface.QueueFrame(child_frame.Pass());
+
+ test::Quad root_quads[] = {
+ test::Quad::SolidColorQuad(1),
+ test::Quad::SurfaceQuad(child_surface.surface_id())};
+ test::Pass root_passes[] = {test::Pass(root_quads, arraysize(root_quads))};
+
+ RenderPassList root_pass_list;
+ AddPasses(&root_pass_list,
+ gfx::Rect(surface_size),
+ root_passes,
+ arraysize(root_passes));
+
+ root_pass_list.at(0)
+ ->shared_quad_state_list[0]
+ ->content_to_target_transform.Translate(0, 7);
+ root_pass_list.at(0)
+ ->shared_quad_state_list[1]
+ ->content_to_target_transform.Translate(0, 10);
+
+ scoped_ptr<DelegatedFrameData> root_frame_data(new DelegatedFrameData);
+ root_pass_list.swap(root_frame_data->render_pass_list);
+
+ scoped_ptr<CompositorFrame> root_frame(new CompositorFrame);
+ root_frame->delegated_frame_data = root_frame_data.Pass();
+
+ root_surface_.QueueFrame(root_frame.Pass());
+
+ scoped_ptr<CompositorFrame> aggregated_frame =
+ aggregator_.Aggregate(root_surface_.surface_id());
+
+ ASSERT_TRUE(aggregated_frame);
+ ASSERT_TRUE(aggregated_frame->delegated_frame_data);
+
+ DelegatedFrameData* frame_data = aggregated_frame->delegated_frame_data.get();
+
+ const RenderPassList& aggregated_pass_list = frame_data->render_pass_list;
+
+ ASSERT_EQ(2u, aggregated_pass_list.size());
+
+ ASSERT_EQ(1u, aggregated_pass_list[0]->shared_quad_state_list.size());
+
+ // The first pass should have one shared quad state for the one solid color
+ // quad.
+ EXPECT_EQ(1u, aggregated_pass_list[0]->shared_quad_state_list.size());
+ // The second (root) pass should have just two shared quad states. We'll
+ // verify the properties through the quads.
+ EXPECT_EQ(2u, aggregated_pass_list[1]->shared_quad_state_list.size());
+
+ SharedQuadState* aggregated_first_pass_sqs =
+ aggregated_pass_list[0]->shared_quad_state_list.front();
+
+ // The first pass's transform should be unaffected by the embedding and still
+ // be a translation by +5 in the x direction.
+ gfx::Transform expected_aggregated_first_pass_sqs_transform;
+ expected_aggregated_first_pass_sqs_transform.Translate(5, 0);
+ EXPECT_EQ(expected_aggregated_first_pass_sqs_transform.ToString(),
+ aggregated_first_pass_sqs->content_to_target_transform.ToString());
+
+ // The first pass's transform to the root target should include the aggregated
+ // transform.
+ gfx::Transform expected_first_pass_transform_to_root_target;
+ expected_first_pass_transform_to_root_target.Translate(8, 10);
+ EXPECT_EQ(expected_first_pass_transform_to_root_target.ToString(),
+ aggregated_pass_list[0]->transform_to_root_target.ToString());
+
+ ASSERT_EQ(2u, aggregated_pass_list[1]->quad_list.size());
+
+ gfx::Transform expected_root_pass_quad_transforms[2];
+ // The first quad in the root pass is the solid color quad from the original
+ // root surface. Its transform should be unaffected by the aggregation and
+ // still be +7 in the y direction.
+ expected_root_pass_quad_transforms[0].Translate(0, 7);
+ // The second quad in the root pass is aggregated from the child surface so
+ // its transform should be the combination of its original translation (0, 10)
+ // and the child surface draw quad's translation (8, 0).
+ expected_root_pass_quad_transforms[1].Translate(8, 10);
+
+ for (size_t i = 0; i < 2; ++i) {
+ DrawQuad* quad = aggregated_pass_list[1]->quad_list.at(i);
+ EXPECT_EQ(expected_root_pass_quad_transforms[i].ToString(),
+ quad->quadTransform().ToString())
+ << i;
+ }
+}
+
+} // namespace
+} // namespace cc
+
diff --git a/chromium/cc/surfaces/surface_client.h b/chromium/cc/surfaces/surface_client.h
new file mode 100644
index 00000000000..88758729b82
--- /dev/null
+++ b/chromium/cc/surfaces/surface_client.h
@@ -0,0 +1,22 @@
+// 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_CLIENT_H_
+#define CC_SURFACES_SURFACE_CLIENT_H_
+
+#include "cc/resources/returned_resource.h"
+#include "cc/surfaces/surfaces_export.h"
+
+namespace cc {
+
+class CC_SURFACES_EXPORT SurfaceClient {
+ public:
+ virtual ~SurfaceClient() {}
+
+ virtual void ReturnResources(const ReturnedResourceArray& resources) = 0;
+};
+
+} // namespace cc
+
+#endif // CC_SURFACES_SURFACE_CLIENT_H_
diff --git a/chromium/cc/surfaces/surface_id.h b/chromium/cc/surfaces/surface_id.h
new file mode 100644
index 00000000000..aa9474d61f5
--- /dev/null
+++ b/chromium/cc/surfaces/surface_id.h
@@ -0,0 +1,29 @@
+// 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_ID_H_
+#define CC_SURFACES_SURFACE_ID_H_
+
+namespace cc {
+
+struct SurfaceId {
+ SurfaceId() : id(0) {}
+ explicit SurfaceId(int id) : id(id) {}
+
+ bool is_null() const { return id == 0; }
+
+ int id;
+};
+
+inline bool operator==(const SurfaceId& a, const SurfaceId& b) {
+ return a.id == b.id;
+}
+
+inline bool operator!=(const SurfaceId& a, const SurfaceId& b) {
+ return !(a == b);
+}
+
+} // namespace cc
+
+#endif // CC_SURFACES_SURFACE_ID_H_
diff --git a/chromium/cc/surfaces/surface_manager.cc b/chromium/cc/surfaces/surface_manager.cc
new file mode 100644
index 00000000000..b41aefc424a
--- /dev/null
+++ b/chromium/cc/surfaces/surface_manager.cc
@@ -0,0 +1,37 @@
+// 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_manager.h"
+
+#include "base/logging.h"
+
+namespace cc {
+
+SurfaceManager::SurfaceManager()
+ : next_surface_id_(1) {
+}
+
+SurfaceManager::~SurfaceManager() {}
+
+SurfaceId SurfaceManager::RegisterAndAllocateIdForSurface(Surface* surface) {
+ DCHECK(surface);
+ int surface_id = next_surface_id_++;
+ surface_map_[surface_id] = surface;
+ return SurfaceId(surface_id);
+}
+
+void SurfaceManager::DeregisterSurface(SurfaceId surface_id) {
+ SurfaceMap::iterator it = surface_map_.find(surface_id.id);
+ DCHECK(it != surface_map_.end());
+ surface_map_.erase(it);
+}
+
+Surface* SurfaceManager::GetSurfaceForId(SurfaceId surface_id) {
+ SurfaceMap::iterator it = surface_map_.find(surface_id.id);
+ if (it == surface_map_.end())
+ return NULL;
+ return it->second;
+}
+
+} // namespace cc
diff --git a/chromium/cc/surfaces/surface_manager.h b/chromium/cc/surfaces/surface_manager.h
new file mode 100644
index 00000000000..b14259d63de
--- /dev/null
+++ b/chromium/cc/surfaces/surface_manager.h
@@ -0,0 +1,39 @@
+// 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_MANAGER_H_
+#define CC_SURFACES_SURFACE_MANAGER_H_
+
+#include "base/containers/hash_tables.h"
+#include "base/macros.h"
+#include "cc/surfaces/surface_id.h"
+#include "cc/surfaces/surfaces_export.h"
+
+namespace cc {
+class CompositorFrame;
+class Surface;
+class SurfaceClient;
+
+class CC_SURFACES_EXPORT SurfaceManager {
+ public:
+ SurfaceManager();
+ ~SurfaceManager();
+
+ SurfaceId RegisterAndAllocateIdForSurface(Surface* surface);
+ void DeregisterSurface(SurfaceId surface_id);
+
+ Surface* GetSurfaceForId(SurfaceId surface_id);
+
+ private:
+ typedef base::hash_map<int, Surface*> SurfaceMap;
+ SurfaceMap surface_map_;
+
+ int next_surface_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(SurfaceManager);
+};
+
+} // namespace cc
+
+#endif // CC_SURFACES_SURFACE_MANAGER_H_
diff --git a/chromium/cc/surfaces/surface_unittest.cc b/chromium/cc/surfaces/surface_unittest.cc
new file mode 100644
index 00000000000..66890c4213d
--- /dev/null
+++ b/chromium/cc/surfaces/surface_unittest.cc
@@ -0,0 +1,411 @@
+// 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/output/compositor_frame.h"
+#include "cc/output/delegated_frame_data.h"
+#include "cc/surfaces/surface.h"
+#include "cc/surfaces/surface_client.h"
+#include "cc/surfaces/surface_manager.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/size.h"
+
+namespace cc {
+namespace {
+
+TEST(SurfaceTest, SurfaceLifetime) {
+ SurfaceManager manager;
+
+ SurfaceId surface_id;
+ {
+ Surface surface(&manager, NULL, gfx::Size(5, 5));
+ surface_id = surface.surface_id();
+ EXPECT_TRUE(!surface_id.is_null());
+ EXPECT_EQ(&surface, manager.GetSurfaceForId(surface_id));
+ }
+
+ EXPECT_EQ(NULL, manager.GetSurfaceForId(surface_id));
+}
+
+class TestSurfaceClient : public SurfaceClient {
+ public:
+ TestSurfaceClient() {}
+ virtual ~TestSurfaceClient() {}
+
+ virtual void ReturnResources(
+ const ReturnedResourceArray& resources) OVERRIDE {
+ returned_resources_ = resources;
+ }
+
+ const ReturnedResourceArray& returned_resources() const {
+ return returned_resources_;
+ }
+
+ void clear_returned_resources() { returned_resources_.clear(); }
+
+ private:
+ ReturnedResourceArray returned_resources_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestSurfaceClient);
+};
+
+void SubmitFrameWithResources(ResourceProvider::ResourceId* resource_ids,
+ size_t num_resource_ids,
+ Surface* surface) {
+ scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
+ 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;
+ frame_data->resource_list.push_back(resource);
+ }
+ scoped_ptr<CompositorFrame> frame(new CompositorFrame);
+ frame->delegated_frame_data = frame_data.Pass();
+ surface->QueueFrame(frame.Pass());
+}
+
+void CheckReturnedResourcesMatchExpected(
+ ResourceProvider::ResourceId* expected_returned_ids,
+ int* expected_returned_counts,
+ size_t expected_resources,
+ const ReturnedResourceArray& actual_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_returned_ids[i], resource.id);
+ EXPECT_EQ(expected_returned_counts[i], resource.count);
+ }
+}
+
+void UnrefResources(ResourceProvider::ResourceId* ids_to_unref,
+ int* counts_to_unref,
+ size_t num_ids_to_unref,
+ Surface* surface) {
+ ReturnedResourceArray unref_array;
+ for (size_t i = 0; i < num_ids_to_unref; ++i) {
+ ReturnedResource resource;
+ resource.id = ids_to_unref[i];
+ resource.count = counts_to_unref[i];
+ unref_array.push_back(resource);
+ }
+ surface->UnrefResources(unref_array);
+}
+
+// Tests submitting a frame with resources followed by one with no resources
+// with no resource provider action in between.
+TEST(SurfaceTest, ResourceLifetimeSimple) {
+ SurfaceManager manager;
+ TestSurfaceClient client;
+ Surface surface(&manager, &client, gfx::Size(5, 5));
+
+ ResourceProvider::ResourceId first_frame_ids[] = {1, 2, 3};
+ SubmitFrameWithResources(
+ first_frame_ids, arraysize(first_frame_ids), &surface);
+
+ // 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.
+ surface.ReturnUnusedResourcesToClient();
+ EXPECT_EQ(0u, client.returned_resources().size());
+ client.clear_returned_resources();
+
+ // The second frame references no resources and thus should make all resources
+ // available to be returned.
+ SubmitFrameWithResources(NULL, 0, &surface);
+
+ surface.ReturnUnusedResourcesToClient();
+ ResourceProvider::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),
+ client.returned_resources());
+}
+
+// Tests submitting a frame with resources followed by one with no resources
+// with the resource provider holding everything alive.
+TEST(SurfaceTest, ResourceLifetimeSimpleWithProviderHoldingAlive) {
+ SurfaceManager manager;
+ TestSurfaceClient client;
+ Surface surface(&manager, &client, gfx::Size(5, 5));
+
+ ResourceProvider::ResourceId first_frame_ids[] = {1, 2, 3};
+ SubmitFrameWithResources(
+ first_frame_ids, arraysize(first_frame_ids), &surface);
+
+ // 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.
+ surface.ReturnUnusedResourcesToClient();
+ EXPECT_EQ(0u, client.returned_resources().size());
+ client.clear_returned_resources();
+
+ // Hold on to everything.
+ surface.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.
+ SubmitFrameWithResources(NULL, 0, &surface);
+
+ surface.ReturnUnusedResourcesToClient();
+ 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), &surface);
+
+ surface.ReturnUnusedResourcesToClient();
+ ResourceProvider::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),
+ client.returned_resources());
+}
+
+// Tests referencing a resource, unref'ing it to zero, then using it again
+// before returning it to the client.
+TEST(SurfaceTest, ResourceReusedBeforeReturn) {
+ SurfaceManager manager;
+ TestSurfaceClient client;
+ Surface surface(&manager, &client, gfx::Size(5, 5));
+
+ ResourceProvider::ResourceId first_frame_ids[] = {7};
+ SubmitFrameWithResources(
+ first_frame_ids, arraysize(first_frame_ids), &surface);
+
+ // This removes all references to resource id 7.
+ SubmitFrameWithResources(NULL, 0, &surface);
+
+ // This references id 7 again.
+ SubmitFrameWithResources(
+ first_frame_ids, arraysize(first_frame_ids), &surface);
+
+ // This removes it again.
+ SubmitFrameWithResources(NULL, 0, &surface);
+
+ // Now it should be returned.
+ surface.ReturnUnusedResourcesToClient();
+
+ // 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(SurfaceTest, ResourceRefMultipleTimes) {
+ SurfaceManager manager;
+ TestSurfaceClient client;
+ Surface surface(&manager, &client, gfx::Size(5, 5));
+
+ ResourceProvider::ResourceId first_frame_ids[] = {3, 4};
+ SubmitFrameWithResources(
+ first_frame_ids, arraysize(first_frame_ids), &surface);
+
+ // Ref resources from the first frame twice.
+ surface.RefCurrentFrameResources();
+ surface.RefCurrentFrameResources();
+
+ ResourceProvider::ResourceId second_frame_ids[] = {4, 5};
+ SubmitFrameWithResources(
+ second_frame_ids, arraysize(second_frame_ids), &surface);
+
+ // Ref resources from the second frame 3 times.
+ surface.RefCurrentFrameResources();
+ surface.RefCurrentFrameResources();
+ surface.RefCurrentFrameResources();
+
+ // Submit a frame with no resources to remove all current frame refs from
+ // submitted resources.
+ SubmitFrameWithResources(NULL, 0, &surface);
+
+ surface.ReturnUnusedResourcesToClient();
+ 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");
+ ResourceProvider::ResourceId ids_to_unref[] = {3, 4, 5};
+ int counts[] = {1, 1, 1};
+ UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref), &surface);
+
+ surface.ReturnUnusedResourcesToClient();
+ EXPECT_EQ(0u, client.returned_resources().size());
+ client.clear_returned_resources();
+
+ UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref), &surface);
+
+ surface.ReturnUnusedResourcesToClient();
+ ResourceProvider::ResourceId expected_returned_ids[] = {3};
+ int expected_returned_counts[] = {1};
+ CheckReturnedResourcesMatchExpected(expected_returned_ids,
+ expected_returned_counts,
+ arraysize(expected_returned_counts),
+ client.returned_resources());
+ }
+
+ // Expected refs remaining:
+ // 4 -> 3
+ // 5 -> 1
+ {
+ SCOPED_TRACE("unref 4 and 5");
+ ResourceProvider::ResourceId ids_to_unref[] = {4, 5};
+ int counts[] = {1, 1};
+ UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref), &surface);
+
+ surface.ReturnUnusedResourcesToClient();
+ ResourceProvider::ResourceId expected_returned_ids[] = {5};
+ int expected_returned_counts[] = {1};
+ CheckReturnedResourcesMatchExpected(expected_returned_ids,
+ expected_returned_counts,
+ arraysize(expected_returned_counts),
+ client.returned_resources());
+ }
+
+ // 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");
+ ResourceProvider::ResourceId ids_to_unref[] = {4};
+ int counts[] = {2};
+ UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref), &surface);
+
+ surface.ReturnUnusedResourcesToClient();
+ ResourceProvider::ResourceId expected_returned_ids[] = {4};
+ int expected_returned_counts[] = {2};
+ CheckReturnedResourcesMatchExpected(expected_returned_ids,
+ expected_returned_counts,
+ arraysize(expected_returned_counts),
+ client.returned_resources());
+ }
+}
+
+TEST(SurfaceTest, ResourceLifetime) {
+ SurfaceManager manager;
+ TestSurfaceClient client;
+ Surface surface(&manager, &client, gfx::Size(5, 5));
+
+ ResourceProvider::ResourceId first_frame_ids[] = {1, 2, 3};
+ SubmitFrameWithResources(
+ first_frame_ids, arraysize(first_frame_ids), &surface);
+
+ // 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.
+ surface.ReturnUnusedResourcesToClient();
+ 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.
+ ResourceProvider::ResourceId second_frame_ids[] = {2, 3, 4};
+ SubmitFrameWithResources(
+ second_frame_ids, arraysize(second_frame_ids), &surface);
+
+ surface.ReturnUnusedResourcesToClient();
+ {
+ SCOPED_TRACE("second frame");
+ ResourceProvider::ResourceId expected_returned_ids[] = {1};
+ int expected_returned_counts[] = {1};
+ CheckReturnedResourcesMatchExpected(expected_returned_ids,
+ expected_returned_counts,
+ arraysize(expected_returned_counts),
+ client.returned_resources());
+ }
+
+ // 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.
+ ResourceProvider::ResourceId third_frame_ids[] = {10, 11, 12, 13};
+ SubmitFrameWithResources(
+ third_frame_ids, arraysize(third_frame_ids), &surface);
+
+ surface.ReturnUnusedResourcesToClient();
+ {
+ SCOPED_TRACE("third frame");
+ ResourceProvider::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),
+ client.returned_resources());
+ }
+
+ // Simulate a ResourceProvider taking a ref on all of the resources.
+ surface.RefCurrentFrameResources();
+
+ ResourceProvider::ResourceId fourth_frame_ids[] = {12, 13};
+ SubmitFrameWithResources(
+ fourth_frame_ids, arraysize(fourth_frame_ids), &surface);
+
+ surface.ReturnUnusedResourcesToClient();
+ EXPECT_EQ(0u, client.returned_resources().size());
+
+ surface.RefCurrentFrameResources();
+
+ // All resources are still being used by the external reference, so none can
+ // be returned to the client.
+ surface.ReturnUnusedResourcesToClient();
+ EXPECT_EQ(0u, client.returned_resources().size());
+
+ // Release resources associated with the first RefCurrentFrameResources() call
+ // first.
+ {
+ ResourceProvider::ResourceId ids_to_unref[] = {10, 11, 12, 13};
+ int counts[] = {1, 1, 1, 1};
+ UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref), &surface);
+ }
+
+ surface.ReturnUnusedResourcesToClient();
+ {
+ SCOPED_TRACE("fourth frame, first unref");
+ ResourceProvider::ResourceId expected_returned_ids[] = {10, 11};
+ int expected_returned_counts[] = {1, 1};
+ CheckReturnedResourcesMatchExpected(expected_returned_ids,
+ expected_returned_counts,
+ arraysize(expected_returned_counts),
+ client.returned_resources());
+ }
+
+ {
+ ResourceProvider::ResourceId ids_to_unref[] = {12, 13};
+ int counts[] = {1, 1};
+ UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref), &surface);
+ }
+
+ // Resources 12 and 13 are still in use by the current frame, so they
+ // shouldn't be available to be returned.
+ surface.ReturnUnusedResourcesToClient();
+ EXPECT_EQ(0u, client.returned_resources().size());
+
+ // If we submit an empty frame, however, they should become available.
+ SubmitFrameWithResources(NULL, 0u, &surface);
+
+ surface.ReturnUnusedResourcesToClient();
+ {
+ SCOPED_TRACE("fourth frame, second unref");
+ ResourceProvider::ResourceId expected_returned_ids[] = {12, 13};
+ int expected_returned_counts[] = {2, 2};
+ CheckReturnedResourcesMatchExpected(expected_returned_ids,
+ expected_returned_counts,
+ arraysize(expected_returned_counts),
+ client.returned_resources());
+ }
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/surfaces/surfaces_export.h b/chromium/cc/surfaces/surfaces_export.h
new file mode 100644
index 00000000000..f84933371cc
--- /dev/null
+++ b/chromium/cc/surfaces/surfaces_export.h
@@ -0,0 +1,29 @@
+// 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_SURFACES_EXPORT_H_
+#define CC_SURFACES_SURFACES_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(CC_SURFACES_IMPLEMENTATION)
+#define CC_SURFACES_EXPORT __declspec(dllexport)
+#else
+#define CC_SURFACES_EXPORT __declspec(dllimport)
+#endif // defined(CC_SURFACES_IMPLEMENTATION)
+
+#else // defined(WIN32)
+#if defined(CC_SURFACES_IMPLEMENTATION)
+#define CC_SURFACES_EXPORT __attribute__((visibility("default")))
+#else
+#define CC_SURFACES_EXPORT
+#endif
+#endif
+
+#else // defined(COMPONENT_BUILD)
+#define CC_SURFACES_EXPORT
+#endif
+
+#endif // CC_SURFACES_SURFACES_EXPORT_H_
diff --git a/chromium/cc/surfaces/surfaces_pixeltest.cc b/chromium/cc/surfaces/surfaces_pixeltest.cc
new file mode 100644
index 00000000000..9afb4c639ad
--- /dev/null
+++ b/chromium/cc/surfaces/surfaces_pixeltest.cc
@@ -0,0 +1,312 @@
+// 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/output/compositor_frame.h"
+#include "cc/quads/render_pass.h"
+#include "cc/quads/solid_color_draw_quad.h"
+#include "cc/quads/surface_draw_quad.h"
+#include "cc/surfaces/surface.h"
+#include "cc/surfaces/surface_aggregator.h"
+#include "cc/surfaces/surface_manager.h"
+#include "cc/test/pixel_comparator.h"
+#include "cc/test/pixel_test.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if !defined(OS_ANDROID)
+
+namespace cc {
+namespace {
+
+class SurfacesPixelTest : public RendererPixelTest<GLRenderer> {
+ protected:
+ SurfaceManager manager_;
+};
+
+SharedQuadState* CreateAndAppendTestSharedQuadState(
+ RenderPass* render_pass,
+ const gfx::Transform& transform,
+ const gfx::Size& size) {
+ const gfx::Size content_bounds = size;
+ const gfx::Rect visible_content_rect = gfx::Rect(size);
+ const gfx::Rect clip_rect = gfx::Rect(size);
+ bool is_clipped = false;
+ float opacity = 1.f;
+ const SkXfermode::Mode blend_mode = SkXfermode::kSrcOver_Mode;
+ SharedQuadState* shared_state = render_pass->CreateAndAppendSharedQuadState();
+ shared_state->SetAll(transform,
+ content_bounds,
+ visible_content_rect,
+ clip_rect,
+ is_clipped,
+ opacity,
+ blend_mode,
+ 0);
+ return shared_state;
+}
+
+// Draws a very simple frame with no surface references.
+TEST_F(SurfacesPixelTest, DrawSimpleFrame) {
+ gfx::Rect rect(device_viewport_size_);
+ RenderPass::Id id(1, 1);
+ scoped_ptr<RenderPass> pass = RenderPass::Create();
+ pass->SetNew(id, rect, rect, gfx::Transform());
+
+ CreateAndAppendTestSharedQuadState(
+ pass.get(), gfx::Transform(), device_viewport_size_);
+
+ scoped_ptr<SolidColorDrawQuad> color_quad = SolidColorDrawQuad::Create();
+ bool force_anti_aliasing_off = false;
+ color_quad->SetNew(pass->shared_quad_state_list.back(),
+ rect,
+ rect,
+ SK_ColorGREEN,
+ force_anti_aliasing_off);
+ pass->quad_list.push_back(color_quad.PassAs<DrawQuad>());
+
+ scoped_ptr<DelegatedFrameData> delegated_frame_data(new DelegatedFrameData);
+ delegated_frame_data->render_pass_list.push_back(pass.Pass());
+
+ scoped_ptr<CompositorFrame> root_frame(new CompositorFrame);
+ root_frame->delegated_frame_data = delegated_frame_data.Pass();
+
+ Surface root_surface(&manager_, NULL, device_viewport_size_);
+ root_surface.QueueFrame(root_frame.Pass());
+
+ SurfaceAggregator aggregator(&manager_);
+ scoped_ptr<CompositorFrame> aggregated_frame =
+ aggregator.Aggregate(root_surface.surface_id());
+
+ bool discard_alpha = false;
+ ExactPixelComparator pixel_comparator(discard_alpha);
+ RenderPassList* pass_list =
+ &aggregated_frame->delegated_frame_data->render_pass_list;
+ EXPECT_TRUE(RunPixelTest(pass_list,
+ base::FilePath(FILE_PATH_LITERAL("green.png")),
+ pixel_comparator));
+}
+
+// Draws a frame with simple surface embedding.
+TEST_F(SurfacesPixelTest, DrawSimpleAggregatedFrame) {
+ gfx::Size child_size(200, 100);
+ Surface child_surface(&manager_, NULL, child_size);
+ Surface root_surface(&manager_, NULL, device_viewport_size_);
+
+ {
+ gfx::Rect rect(device_viewport_size_);
+ RenderPass::Id id(1, 1);
+ scoped_ptr<RenderPass> pass = RenderPass::Create();
+ pass->SetNew(id, rect, rect, gfx::Transform());
+
+ CreateAndAppendTestSharedQuadState(
+ pass.get(), gfx::Transform(), device_viewport_size_);
+
+ scoped_ptr<SurfaceDrawQuad> surface_quad = SurfaceDrawQuad::Create();
+ surface_quad->SetNew(pass->shared_quad_state_list.back(),
+ gfx::Rect(child_size),
+ gfx::Rect(child_size),
+ child_surface.surface_id());
+ pass->quad_list.push_back(surface_quad.PassAs<DrawQuad>());
+
+ scoped_ptr<SolidColorDrawQuad> color_quad = SolidColorDrawQuad::Create();
+ bool force_anti_aliasing_off = false;
+ color_quad->SetNew(pass->shared_quad_state_list.back(),
+ rect,
+ rect,
+ SK_ColorYELLOW,
+ force_anti_aliasing_off);
+ pass->quad_list.push_back(color_quad.PassAs<DrawQuad>());
+
+ scoped_ptr<DelegatedFrameData> delegated_frame_data(new DelegatedFrameData);
+ delegated_frame_data->render_pass_list.push_back(pass.Pass());
+
+ scoped_ptr<CompositorFrame> root_frame(new CompositorFrame);
+ root_frame->delegated_frame_data = delegated_frame_data.Pass();
+
+ root_surface.QueueFrame(root_frame.Pass());
+ }
+
+ {
+ gfx::Rect rect(child_size);
+ RenderPass::Id id(1, 1);
+ scoped_ptr<RenderPass> pass = RenderPass::Create();
+ pass->SetNew(id, rect, rect, gfx::Transform());
+
+ CreateAndAppendTestSharedQuadState(
+ pass.get(), gfx::Transform(), child_size);
+
+ scoped_ptr<SolidColorDrawQuad> color_quad = SolidColorDrawQuad::Create();
+ bool force_anti_aliasing_off = false;
+ color_quad->SetNew(pass->shared_quad_state_list.back(),
+ rect,
+ rect,
+ SK_ColorBLUE,
+ force_anti_aliasing_off);
+ pass->quad_list.push_back(color_quad.PassAs<DrawQuad>());
+
+ scoped_ptr<DelegatedFrameData> delegated_frame_data(new DelegatedFrameData);
+ delegated_frame_data->render_pass_list.push_back(pass.Pass());
+
+ scoped_ptr<CompositorFrame> child_frame(new CompositorFrame);
+ child_frame->delegated_frame_data = delegated_frame_data.Pass();
+
+ child_surface.QueueFrame(child_frame.Pass());
+ }
+
+ SurfaceAggregator aggregator(&manager_);
+ scoped_ptr<CompositorFrame> aggregated_frame =
+ aggregator.Aggregate(root_surface.surface_id());
+
+ bool discard_alpha = false;
+ ExactPixelComparator pixel_comparator(discard_alpha);
+ RenderPassList* pass_list =
+ &aggregated_frame->delegated_frame_data->render_pass_list;
+ EXPECT_TRUE(RunPixelTest(pass_list,
+ base::FilePath(FILE_PATH_LITERAL("blue_yellow.png")),
+ pixel_comparator));
+}
+
+// Tests a surface quad that has a non-identity transform into its pass.
+TEST_F(SurfacesPixelTest, DrawAggregatedFrameWithSurfaceTransforms) {
+ gfx::Size child_size(100, 200);
+ gfx::Size quad_size(100, 100);
+ // Structure:
+ // root (200x200) -> left_child (100x200 @ 0x0,
+ // right_child (100x200 @ 0x100)
+ // left_child -> top_green_quad (100x100 @ 0x0),
+ // bottom_blue_quad (100x100 @ 0x100)
+ // right_child -> top_blue_quad (100x100 @ 0x0),
+ // bottom_green_quad (100x100 @ 0x100)
+ Surface left_child(&manager_, NULL, child_size);
+ Surface right_child(&manager_, NULL, child_size);
+ Surface root_surface(&manager_, NULL, device_viewport_size_);
+
+ {
+ gfx::Rect rect(device_viewport_size_);
+ RenderPass::Id id(1, 1);
+ scoped_ptr<RenderPass> pass = RenderPass::Create();
+ pass->SetNew(id, rect, rect, gfx::Transform());
+
+ gfx::Transform surface_transform;
+ CreateAndAppendTestSharedQuadState(
+ pass.get(), surface_transform, device_viewport_size_);
+
+ scoped_ptr<SurfaceDrawQuad> left_surface_quad = SurfaceDrawQuad::Create();
+ left_surface_quad->SetNew(pass->shared_quad_state_list.back(),
+ gfx::Rect(child_size),
+ gfx::Rect(child_size),
+ left_child.surface_id());
+ pass->quad_list.push_back(left_surface_quad.PassAs<DrawQuad>());
+
+ surface_transform.Translate(100, 0);
+ CreateAndAppendTestSharedQuadState(
+ pass.get(), surface_transform, device_viewport_size_);
+
+ scoped_ptr<SurfaceDrawQuad> right_surface_quad = SurfaceDrawQuad::Create();
+ right_surface_quad->SetNew(pass->shared_quad_state_list.back(),
+ gfx::Rect(child_size),
+ gfx::Rect(child_size),
+ right_child.surface_id());
+ pass->quad_list.push_back(right_surface_quad.PassAs<DrawQuad>());
+
+ scoped_ptr<DelegatedFrameData> delegated_frame_data(new DelegatedFrameData);
+ delegated_frame_data->render_pass_list.push_back(pass.Pass());
+
+ scoped_ptr<CompositorFrame> root_frame(new CompositorFrame);
+ root_frame->delegated_frame_data = delegated_frame_data.Pass();
+
+ root_surface.QueueFrame(root_frame.Pass());
+ }
+
+ {
+ gfx::Rect rect(child_size);
+ RenderPass::Id id(1, 1);
+ scoped_ptr<RenderPass> pass = RenderPass::Create();
+ pass->SetNew(id, rect, rect, gfx::Transform());
+
+ CreateAndAppendTestSharedQuadState(
+ pass.get(), gfx::Transform(), child_size);
+
+ scoped_ptr<SolidColorDrawQuad> top_color_quad =
+ SolidColorDrawQuad::Create();
+ bool force_anti_aliasing_off = false;
+ top_color_quad->SetNew(pass->shared_quad_state_list.back(),
+ gfx::Rect(quad_size),
+ gfx::Rect(quad_size),
+ SK_ColorGREEN,
+ force_anti_aliasing_off);
+ pass->quad_list.push_back(top_color_quad.PassAs<DrawQuad>());
+
+ scoped_ptr<SolidColorDrawQuad> bottom_color_quad =
+ SolidColorDrawQuad::Create();
+ bottom_color_quad->SetNew(pass->shared_quad_state_list.back(),
+ gfx::Rect(0, 100, 100, 100),
+ gfx::Rect(0, 100, 100, 100),
+ SK_ColorBLUE,
+ force_anti_aliasing_off);
+ pass->quad_list.push_back(bottom_color_quad.PassAs<DrawQuad>());
+
+ scoped_ptr<DelegatedFrameData> delegated_frame_data(new DelegatedFrameData);
+ delegated_frame_data->render_pass_list.push_back(pass.Pass());
+
+ scoped_ptr<CompositorFrame> child_frame(new CompositorFrame);
+ child_frame->delegated_frame_data = delegated_frame_data.Pass();
+
+ left_child.QueueFrame(child_frame.Pass());
+ }
+
+ {
+ gfx::Rect rect(child_size);
+ RenderPass::Id id(1, 1);
+ scoped_ptr<RenderPass> pass = RenderPass::Create();
+ pass->SetNew(id, rect, rect, gfx::Transform());
+
+ CreateAndAppendTestSharedQuadState(
+ pass.get(), gfx::Transform(), child_size);
+
+ scoped_ptr<SolidColorDrawQuad> top_color_quad =
+ SolidColorDrawQuad::Create();
+ bool force_anti_aliasing_off = false;
+ top_color_quad->SetNew(pass->shared_quad_state_list.back(),
+ gfx::Rect(quad_size),
+ gfx::Rect(quad_size),
+ SK_ColorBLUE,
+ force_anti_aliasing_off);
+ pass->quad_list.push_back(top_color_quad.PassAs<DrawQuad>());
+
+ scoped_ptr<SolidColorDrawQuad> bottom_color_quad =
+ SolidColorDrawQuad::Create();
+ bottom_color_quad->SetNew(pass->shared_quad_state_list.back(),
+ gfx::Rect(0, 100, 100, 100),
+ gfx::Rect(0, 100, 100, 100),
+ SK_ColorGREEN,
+ force_anti_aliasing_off);
+ pass->quad_list.push_back(bottom_color_quad.PassAs<DrawQuad>());
+
+ scoped_ptr<DelegatedFrameData> delegated_frame_data(new DelegatedFrameData);
+ delegated_frame_data->render_pass_list.push_back(pass.Pass());
+
+ scoped_ptr<CompositorFrame> child_frame(new CompositorFrame);
+ child_frame->delegated_frame_data = delegated_frame_data.Pass();
+
+ right_child.QueueFrame(child_frame.Pass());
+ }
+
+ SurfaceAggregator aggregator(&manager_);
+ scoped_ptr<CompositorFrame> aggregated_frame =
+ aggregator.Aggregate(root_surface.surface_id());
+
+ bool discard_alpha = false;
+ ExactPixelComparator pixel_comparator(discard_alpha);
+ RenderPassList* pass_list =
+ &aggregated_frame->delegated_frame_data->render_pass_list;
+ EXPECT_TRUE(RunPixelTest(
+ pass_list,
+ base::FilePath(FILE_PATH_LITERAL("four_blue_green_checkers.png")),
+ pixel_comparator));
+}
+
+} // namespace
+} // namespace cc
+
+#endif // !defined(OS_ANDROID)
diff --git a/chromium/cc/trees/blocking_task_runner.cc b/chromium/cc/trees/blocking_task_runner.cc
index 576aa9b1bf9..5c33f40d4fc 100644
--- a/chromium/cc/trees/blocking_task_runner.cc
+++ b/chromium/cc/trees/blocking_task_runner.cc
@@ -12,16 +12,13 @@
namespace cc {
-typedef std::pair<base::SingleThreadTaskRunner*,
- scoped_refptr<BlockingTaskRunner> > TaskRunnerPair;
-
struct TaskRunnerPairs {
static TaskRunnerPairs* GetInstance() {
return Singleton<TaskRunnerPairs>::get();
}
base::Lock lock;
- std::vector<TaskRunnerPair> pairs;
+ std::vector<scoped_refptr<BlockingTaskRunner> > runners;
private:
friend struct DefaultSingletonTraits<TaskRunnerPairs>;
@@ -30,43 +27,47 @@ struct TaskRunnerPairs {
// static
scoped_refptr<BlockingTaskRunner> BlockingTaskRunner::current() {
TaskRunnerPairs* task_runners = TaskRunnerPairs::GetInstance();
+ base::PlatformThreadId thread_id = base::PlatformThread::CurrentId();
base::AutoLock lock(task_runners->lock);
- for (size_t i = 0; i < task_runners->pairs.size(); ++i) {
- if (task_runners->pairs[i].first->HasOneRef()) {
- // The SingleThreadTaskRunner is kept alive by its MessageLoop, and we
- // hold a second reference in the TaskRunnerPairs array. If the
- // SingleThreadTaskRunner has one ref, then it is being held alive only
- // by the BlockingTaskRunner and the MessageLoop is gone, so drop the
- // BlockingTaskRunner from the TaskRunnerPairs array along with the
- // SingleThreadTaskRunner.
- task_runners->pairs.erase(task_runners->pairs.begin() + i);
- --i;
+ scoped_refptr<BlockingTaskRunner> current_task_runner;
+
+ for (size_t i = 0; i < task_runners->runners.size(); ++i) {
+ if (task_runners->runners[i]->thread_id_ == thread_id) {
+ current_task_runner = task_runners->runners[i];
+ } else if (task_runners->runners[i]->HasOneRef()) {
+ task_runners->runners.erase(task_runners->runners.begin() + i);
+ i--;
}
}
- scoped_refptr<base::SingleThreadTaskRunner> current =
- base::MessageLoopProxy::current();
- for (size_t i = 0; i < task_runners->pairs.size(); ++i) {
- if (task_runners->pairs[i].first == current.get())
- return task_runners->pairs[i].second.get();
- }
+ if (current_task_runner)
+ return current_task_runner;
- scoped_refptr<BlockingTaskRunner> runner = new BlockingTaskRunner(current);
- task_runners->pairs.push_back(TaskRunnerPair(current, runner));
+ scoped_refptr<BlockingTaskRunner> runner =
+ new BlockingTaskRunner(base::MessageLoopProxy::current());
+ task_runners->runners.push_back(runner);
return runner;
}
BlockingTaskRunner::BlockingTaskRunner(
scoped_refptr<base::SingleThreadTaskRunner> task_runner)
- : task_runner_(task_runner), capture_(0) {}
+ : thread_id_(base::PlatformThread::CurrentId()),
+ task_runner_(task_runner),
+ capture_(0) {
+}
BlockingTaskRunner::~BlockingTaskRunner() {}
+bool BlockingTaskRunner::BelongsToCurrentThread() {
+ return base::PlatformThread::CurrentId() == thread_id_;
+}
+
bool BlockingTaskRunner::PostTask(const tracked_objects::Location& from_here,
const base::Closure& task) {
base::AutoLock lock(lock_);
+ DCHECK(task_runner_.get() || capture_);
if (!capture_)
return task_runner_->PostTask(from_here, task);
captured_tasks_.push_back(task);
diff --git a/chromium/cc/trees/blocking_task_runner.h b/chromium/cc/trees/blocking_task_runner.h
index 28633171c20..8388a881e60 100644
--- a/chromium/cc/trees/blocking_task_runner.h
+++ b/chromium/cc/trees/blocking_task_runner.h
@@ -11,6 +11,7 @@
#include "base/memory/ref_counted.h"
#include "base/single_thread_task_runner.h"
#include "base/synchronization/lock.h"
+#include "base/threading/platform_thread.h"
#include "cc/base/cc_export.h"
namespace cc {
@@ -62,9 +63,7 @@ class CC_EXPORT BlockingTaskRunner
// True if tasks posted to the BlockingTaskRunner will run on the current
// thread.
- bool BelongsToCurrentThread() {
- return task_runner_->BelongsToCurrentThread();
- }
+ bool BelongsToCurrentThread();
// Posts a task using the contained SingleThreadTaskRunner unless |capture_|
// is true. When |capture_| is true, tasks posted will be caught and stored
@@ -82,6 +81,7 @@ class CC_EXPORT BlockingTaskRunner
void SetCapture(bool capture);
+ base::PlatformThreadId thread_id_;
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
base::Lock lock_;
diff --git a/chromium/cc/trees/damage_tracker.cc b/chromium/cc/trees/damage_tracker.cc
index 9895458c99a..866f09d6569 100644
--- a/chromium/cc/trees/damage_tracker.cc
+++ b/chromium/cc/trees/damage_tracker.cc
@@ -13,6 +13,7 @@
#include "cc/output/filter_operations.h"
#include "cc/trees/layer_tree_host_common.h"
#include "cc/trees/layer_tree_impl.h"
+#include "ui/gfx/geometry/rect_conversions.h"
namespace cc {
@@ -25,20 +26,20 @@ DamageTracker::DamageTracker()
DamageTracker::~DamageTracker() {}
-static inline void ExpandRectWithFilters(
- gfx::RectF* rect, const FilterOperations& filters) {
+static inline void ExpandRectWithFilters(gfx::Rect* rect,
+ const FilterOperations& filters) {
int top, right, bottom, left;
filters.GetOutsets(&top, &right, &bottom, &left);
rect->Inset(-left, -top, -right, -bottom);
}
static inline void ExpandDamageRectInsideRectWithFilters(
- gfx::RectF* damage_rect,
- const gfx::RectF& pre_filter_rect,
+ gfx::Rect* damage_rect,
+ const gfx::Rect& pre_filter_rect,
const FilterOperations& filters) {
- gfx::RectF expanded_damage_rect = *damage_rect;
+ gfx::Rect expanded_damage_rect = *damage_rect;
ExpandRectWithFilters(&expanded_damage_rect, filters);
- gfx::RectF filter_rect = pre_filter_rect;
+ gfx::Rect filter_rect = pre_filter_rect;
ExpandRectWithFilters(&filter_rect, filters);
expanded_damage_rect.Intersect(filter_rect);
@@ -49,7 +50,7 @@ void DamageTracker::UpdateDamageTrackingState(
const LayerImplList& layer_list,
int target_surface_layer_id,
bool target_surface_property_changed_only_from_descendant,
- gfx::Rect target_surface_content_rect,
+ const gfx::Rect& target_surface_content_rect,
LayerImpl* target_surface_mask_layer,
const FilterOperations& filters) {
//
@@ -124,13 +125,13 @@ void DamageTracker::UpdateDamageTrackingState(
// 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.
- gfx::RectF damage_from_active_layers =
+ gfx::Rect damage_from_active_layers =
TrackDamageFromActiveLayers(layer_list, target_surface_layer_id);
- gfx::RectF damage_from_surface_mask =
+ gfx::Rect damage_from_surface_mask =
TrackDamageFromSurfaceMask(target_surface_mask_layer);
- gfx::RectF damage_from_leftover_rects = TrackDamageFromLeftoverRects();
+ gfx::Rect damage_from_leftover_rects = TrackDamageFromLeftoverRects();
- gfx::RectF damage_rect_for_this_update;
+ gfx::Rect damage_rect_for_this_update;
if (target_surface_property_changed_only_from_descendant) {
damage_rect_for_this_update = target_surface_content_rect;
@@ -172,10 +173,10 @@ DamageTracker::RectMapData& DamageTracker::RectDataForLayer(
return *it;
}
-gfx::RectF DamageTracker::TrackDamageFromActiveLayers(
+gfx::Rect DamageTracker::TrackDamageFromActiveLayers(
const LayerImplList& layer_list,
int target_surface_layer_id) {
- gfx::RectF damage_rect = gfx::RectF();
+ gfx::Rect damage_rect;
for (size_t layer_index = 0; layer_index < layer_list.size(); ++layer_index) {
// Visit layers in back-to-front order.
@@ -186,7 +187,6 @@ gfx::RectF DamageTracker::TrackDamageFromActiveLayers(
// HUD damage rect visualization.
if (layer == layer->layer_tree_impl()->hud_layer())
continue;
-
if (LayerTreeHostCommon::RenderSurfaceContributesToTarget<LayerImpl>(
layer, target_surface_layer_id))
ExtendDamageForRenderSurface(layer, &damage_rect);
@@ -197,9 +197,9 @@ gfx::RectF DamageTracker::TrackDamageFromActiveLayers(
return damage_rect;
}
-gfx::RectF DamageTracker::TrackDamageFromSurfaceMask(
+gfx::Rect DamageTracker::TrackDamageFromSurfaceMask(
LayerImpl* target_surface_mask_layer) {
- gfx::RectF damage_rect = gfx::RectF();
+ gfx::Rect damage_rect;
if (!target_surface_mask_layer)
return damage_rect;
@@ -209,8 +209,7 @@ gfx::RectF DamageTracker::TrackDamageFromSurfaceMask(
// expected to be a common case.
if (target_surface_mask_layer->LayerPropertyChanged() ||
!target_surface_mask_layer->update_rect().IsEmpty()) {
- damage_rect = gfx::RectF(gfx::PointF(),
- target_surface_mask_layer->bounds());
+ damage_rect = gfx::Rect(target_surface_mask_layer->bounds());
}
return damage_rect;
@@ -220,12 +219,12 @@ void DamageTracker::PrepareRectHistoryForUpdate() {
mailboxId_++;
}
-gfx::RectF DamageTracker::TrackDamageFromLeftoverRects() {
+gfx::Rect DamageTracker::TrackDamageFromLeftoverRects() {
// After computing damage for all active layers, any leftover items in the
// current rect history correspond to layers/surfaces that no longer exist.
// So, these regions are now exposed on the target surface.
- gfx::RectF damage_rect = gfx::RectF();
+ gfx::Rect damage_rect;
SortedRectMap::iterator cur_pos = rect_history_.begin();
SortedRectMap::iterator copy_pos = cur_pos;
@@ -261,7 +260,7 @@ gfx::RectF DamageTracker::TrackDamageFromLeftoverRects() {
}
void DamageTracker::ExtendDamageForLayer(LayerImpl* layer,
- gfx::RectF* target_damage_rect) {
+ gfx::Rect* target_damage_rect) {
// 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.
@@ -282,13 +281,15 @@ void DamageTracker::ExtendDamageForLayer(LayerImpl* layer,
bool layer_is_new = false;
RectMapData& data = RectDataForLayer(layer->id(), &layer_is_new);
- gfx::RectF old_rect_in_target_space = data.rect_;
+ gfx::Rect old_rect_in_target_space = data.rect_;
- gfx::RectF rect_in_target_space = MathUtil::MapClippedRect(
- layer->draw_transform(),
- gfx::RectF(gfx::PointF(), layer->content_bounds()));
+ gfx::Rect rect_in_target_space = MathUtil::MapEnclosingClippedRect(
+ layer->draw_transform(), gfx::Rect(layer->content_bounds()));
data.Update(rect_in_target_space, mailboxId_);
+ gfx::RectF damage_rect =
+ gfx::UnionRects(layer->update_rect(), layer->damage_rect());
+
if (layer_is_new || layer->LayerPropertyChanged()) {
// If a layer is new or has changed, then its entire layer rect affects the
// target surface.
@@ -297,19 +298,19 @@ void DamageTracker::ExtendDamageForLayer(LayerImpl* layer,
// 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_rect->Union(old_rect_in_target_space);
- } else if (!layer->update_rect().IsEmpty()) {
+ } else if (!damage_rect.IsEmpty()) {
// If the layer properties haven't changed, then the the target surface is
- // only affected by the layer's update area, which could be empty.
- gfx::RectF update_content_rect =
- layer->LayerRectToContentRect(layer->update_rect());
- gfx::RectF update_rect_in_target_space =
- MathUtil::MapClippedRect(layer->draw_transform(), update_content_rect);
- target_damage_rect->Union(update_rect_in_target_space);
+ // only affected by the layer's damaged area, which could be empty.
+ gfx::Rect damage_content_rect = layer->LayerRectToContentRect(damage_rect);
+ gfx::Rect damage_rect_in_target_space = MathUtil::MapEnclosingClippedRect(
+ layer->draw_transform(), damage_content_rect);
+ target_damage_rect->Union(damage_rect_in_target_space);
}
}
void DamageTracker::ExtendDamageForRenderSurface(
- LayerImpl* layer, gfx::RectF* target_damage_rect) {
+ LayerImpl* layer,
+ gfx::Rect* target_damage_rect) {
// There are two ways a "descendant surface" can damage regions of the "target
// surface":
// 1. Property change:
@@ -329,14 +330,14 @@ void DamageTracker::ExtendDamageForRenderSurface(
bool surface_is_new = false;
RectMapData& data = RectDataForLayer(layer->id(), &surface_is_new);
- gfx::RectF old_surface_rect = data.rect_;
+ gfx::Rect old_surface_rect = data.rect_;
// The drawableContextRect() already includes the replica if it exists.
- gfx::RectF surface_rect_in_target_space =
- render_surface->DrawableContentRect();
+ gfx::Rect surface_rect_in_target_space =
+ gfx::ToEnclosingRect(render_surface->DrawableContentRect());
data.Update(surface_rect_in_target_space, mailboxId_);
- gfx::RectF damage_rect_in_local_space;
+ gfx::Rect damage_rect_in_local_space;
if (surface_is_new || render_surface->SurfacePropertyChanged()) {
// The entire surface contributes damage.
damage_rect_in_local_space = render_surface->content_rect();
@@ -353,14 +354,14 @@ void DamageTracker::ExtendDamageForRenderSurface(
// its reflection if needed.
if (!damage_rect_in_local_space.IsEmpty()) {
const gfx::Transform& draw_transform = render_surface->draw_transform();
- gfx::RectF damage_rect_in_target_space =
- MathUtil::MapClippedRect(draw_transform, damage_rect_in_local_space);
+ gfx::Rect damage_rect_in_target_space = MathUtil::MapEnclosingClippedRect(
+ draw_transform, damage_rect_in_local_space);
target_damage_rect->Union(damage_rect_in_target_space);
if (layer->replica_layer()) {
const gfx::Transform& replica_draw_transform =
render_surface->replica_draw_transform();
- target_damage_rect->Union(MathUtil::MapClippedRect(
+ target_damage_rect->Union(MathUtil::MapEnclosingClippedRect(
replica_draw_transform, damage_rect_in_local_space));
}
}
@@ -376,9 +377,8 @@ void DamageTracker::ExtendDamageForRenderSurface(
const gfx::Transform& replica_draw_transform =
render_surface->replica_draw_transform();
- gfx::RectF replica_mask_layer_rect = MathUtil::MapClippedRect(
- replica_draw_transform,
- gfx::RectF(gfx::PointF(), replica_mask_layer->bounds()));
+ gfx::Rect replica_mask_layer_rect = MathUtil::MapEnclosingClippedRect(
+ replica_draw_transform, gfx::Rect(replica_mask_layer->bounds()));
data.Update(replica_mask_layer_rect, mailboxId_);
// In the current implementation, a change in the replica mask damages the
diff --git a/chromium/cc/trees/damage_tracker.h b/chromium/cc/trees/damage_tracker.h
index 37a1900f788..37c4c6ec9eb 100644
--- a/chromium/cc/trees/damage_tracker.h
+++ b/chromium/cc/trees/damage_tracker.h
@@ -9,7 +9,7 @@
#include "base/memory/scoped_ptr.h"
#include "cc/base/cc_export.h"
#include "cc/layers/layer_lists.h"
-#include "ui/gfx/rect_f.h"
+#include "ui/gfx/rect.h"
class SkImageFilter;
@@ -31,38 +31,39 @@ class CC_EXPORT DamageTracker {
static scoped_ptr<DamageTracker> Create();
~DamageTracker();
- void DidDrawDamagedArea() { current_damage_rect_ = gfx::RectF(); }
- void AddDamageNextUpdate(gfx::RectF dmg) { current_damage_rect_.Union(dmg); }
+ void DidDrawDamagedArea() { current_damage_rect_ = gfx::Rect(); }
+ void AddDamageNextUpdate(const gfx::Rect& dmg) {
+ current_damage_rect_.Union(dmg);
+ }
void UpdateDamageTrackingState(
const LayerImplList& layer_list,
int target_surface_layer_id,
bool target_surface_property_changed_only_from_descendant,
- gfx::Rect target_surface_content_rect,
+ const gfx::Rect& target_surface_content_rect,
LayerImpl* target_surface_mask_layer,
const FilterOperations& filters);
- gfx::RectF current_damage_rect() { return current_damage_rect_; }
+ gfx::Rect current_damage_rect() { return current_damage_rect_; }
private:
DamageTracker();
- gfx::RectF TrackDamageFromActiveLayers(
- const LayerImplList& layer_list,
- int target_surface_layer_id);
- gfx::RectF TrackDamageFromSurfaceMask(LayerImpl* target_surface_mask_layer);
- gfx::RectF TrackDamageFromLeftoverRects();
+ gfx::Rect TrackDamageFromActiveLayers(const LayerImplList& layer_list,
+ int target_surface_layer_id);
+ gfx::Rect TrackDamageFromSurfaceMask(LayerImpl* target_surface_mask_layer);
+ gfx::Rect TrackDamageFromLeftoverRects();
void PrepareRectHistoryForUpdate();
// These helper functions are used only in TrackDamageFromActiveLayers().
- void ExtendDamageForLayer(LayerImpl* layer, gfx::RectF* target_damage_rect);
+ void ExtendDamageForLayer(LayerImpl* layer, gfx::Rect* target_damage_rect);
void ExtendDamageForRenderSurface(LayerImpl* layer,
- gfx::RectF* target_damage_rect);
+ gfx::Rect* target_damage_rect);
struct RectMapData {
RectMapData() : layer_id_(0), mailboxId_(0) {}
explicit RectMapData(int layer_id) : layer_id_(layer_id), mailboxId_(0) {}
- void Update(const gfx::RectF& rect, unsigned int mailboxId) {
+ void Update(const gfx::Rect& rect, unsigned int mailboxId) {
mailboxId_ = mailboxId;
rect_ = rect;
}
@@ -73,7 +74,7 @@ class CC_EXPORT DamageTracker {
int layer_id_;
unsigned int mailboxId_;
- gfx::RectF rect_;
+ gfx::Rect rect_;
};
typedef std::vector<RectMapData> SortedRectMap;
@@ -82,7 +83,7 @@ class CC_EXPORT DamageTracker {
SortedRectMap rect_history_;
unsigned int mailboxId_;
- gfx::RectF current_damage_rect_;
+ gfx::Rect current_damage_rect_;
DISALLOW_COPY_AND_ASSIGN(DamageTracker);
};
diff --git a/chromium/cc/trees/damage_tracker_unittest.cc b/chromium/cc/trees/damage_tracker_unittest.cc
index 7fb8720b83d..169eea4cd5f 100644
--- a/chromium/cc/trees/damage_tracker_unittest.cc
+++ b/chromium/cc/trees/damage_tracker_unittest.cc
@@ -11,25 +11,27 @@
#include "cc/test/fake_impl_proxy.h"
#include "cc/test/fake_layer_tree_host_impl.h"
#include "cc/test/geometry_test_utils.h"
+#include "cc/test/test_shared_bitmap_manager.h"
#include "cc/trees/layer_tree_host_common.h"
#include "cc/trees/single_thread_proxy.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/effects/SkBlurImageFilter.h"
-#include "ui/gfx/quad_f.h"
+#include "ui/gfx/geometry/quad_f.h"
+#include "ui/gfx/geometry/rect_conversions.h"
namespace cc {
namespace {
void ExecuteCalculateDrawProperties(LayerImpl* root,
- LayerImplList& render_surface_layer_list) {
+ LayerImplList* render_surface_layer_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_TRUE(root->render_surface());
- ASSERT_FALSE(render_surface_layer_list.size());
+ ASSERT_FALSE(render_surface_layer_list->size());
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root, root->bounds(), &render_surface_layer_list);
+ root, root->bounds(), render_surface_layer_list);
LayerTreeHostCommon::CalculateDrawProperties(&inputs);
}
@@ -50,7 +52,7 @@ void EmulateDrawingOneFrame(LayerImpl* root) {
// and surfaces.
LayerImplList render_surface_layer_list;
- ExecuteCalculateDrawProperties(root, render_surface_layer_list);
+ ExecuteCalculateDrawProperties(root, &render_surface_layer_list);
// Iterate back-to-front, so that damage correctly propagates from descendant
// surfaces to ancestors.
@@ -71,7 +73,7 @@ void EmulateDrawingOneFrame(LayerImpl* root) {
class DamageTrackerTest : public testing::Test {
public:
- DamageTrackerTest() : host_impl_(&proxy_) {}
+ DamageTrackerTest() : host_impl_(&proxy_, &shared_bitmap_manager_) {}
scoped_ptr<LayerImpl> CreateTestTreeWithOneSurface() {
scoped_ptr<LayerImpl> root =
@@ -80,7 +82,6 @@ class DamageTrackerTest : public testing::Test {
LayerImpl::Create(host_impl_.active_tree(), 2);
root->SetPosition(gfx::PointF());
- root->SetAnchorPoint(gfx::PointF());
root->SetBounds(gfx::Size(500, 500));
root->SetContentBounds(gfx::Size(500, 500));
root->SetDrawsContent(true);
@@ -88,7 +89,6 @@ class DamageTrackerTest : public testing::Test {
root->render_surface()->SetContentRect(gfx::Rect(0, 0, 500, 500));
child->SetPosition(gfx::PointF(100.f, 100.f));
- child->SetAnchorPoint(gfx::PointF());
child->SetBounds(gfx::Size(30, 30));
child->SetContentBounds(gfx::Size(30, 30));
child->SetDrawsContent(true);
@@ -114,7 +114,6 @@ class DamageTrackerTest : public testing::Test {
LayerImpl::Create(host_impl_.active_tree(), 5);
root->SetPosition(gfx::PointF());
- root->SetAnchorPoint(gfx::PointF());
root->SetBounds(gfx::Size(500, 500));
root->SetContentBounds(gfx::Size(500, 500));
root->SetDrawsContent(true);
@@ -122,7 +121,6 @@ class DamageTrackerTest : public testing::Test {
root->render_surface()->SetContentRect(gfx::Rect(0, 0, 500, 500));
child1->SetPosition(gfx::PointF(100.f, 100.f));
- child1->SetAnchorPoint(gfx::PointF());
child1->SetBounds(gfx::Size(30, 30));
child1->SetContentBounds(gfx::Size(30, 30));
// With a child that draws_content, opacity will cause the layer to create
@@ -134,19 +132,16 @@ class DamageTrackerTest : public testing::Test {
child1->SetForceRenderSurface(true);
child2->SetPosition(gfx::PointF(11.f, 11.f));
- child2->SetAnchorPoint(gfx::PointF());
child2->SetBounds(gfx::Size(18, 18));
child2->SetContentBounds(gfx::Size(18, 18));
child2->SetDrawsContent(true);
grand_child1->SetPosition(gfx::PointF(200.f, 200.f));
- grand_child1->SetAnchorPoint(gfx::PointF());
grand_child1->SetBounds(gfx::Size(6, 8));
grand_child1->SetContentBounds(gfx::Size(6, 8));
grand_child1->SetDrawsContent(true);
grand_child2->SetPosition(gfx::PointF(190.f, 190.f));
- grand_child2->SetAnchorPoint(gfx::PointF());
grand_child2->SetBounds(gfx::Size(6, 8));
grand_child2->SetContentBounds(gfx::Size(6, 8));
grand_child2->SetDrawsContent(true);
@@ -181,6 +176,7 @@ class DamageTrackerTest : public testing::Test {
protected:
FakeImplProxy proxy_;
+ TestSharedBitmapManager shared_bitmap_manager_;
FakeLayerTreeHostImpl host_impl_;
};
@@ -194,10 +190,10 @@ TEST_F(DamageTrackerTest, SanityCheckTestTreeWithOneSurface) {
EXPECT_EQ(1, root->render_surface()->layer_list()[0]->id());
EXPECT_EQ(2, root->render_surface()->layer_list()[1]->id());
- gfx::RectF root_damage_rect =
- root->render_surface()->damage_tracker()->current_damage_rect();
+ gfx::Rect root_damage_rect =
+ root->render_surface()->damage_tracker()->current_damage_rect();
- EXPECT_FLOAT_RECT_EQ(gfx::RectF(0.f, 0.f, 500.f, 500.f), root_damage_rect);
+ EXPECT_EQ(gfx::Rect(500, 500).ToString(), root_damage_rect.ToString());
}
TEST_F(DamageTrackerTest, SanityCheckTestTreeWithTwoSurfaces) {
@@ -208,10 +204,10 @@ TEST_F(DamageTrackerTest, SanityCheckTestTreeWithTwoSurfaces) {
LayerImpl* child1 = root->children()[0];
LayerImpl* child2 = root->children()[1];
- gfx::RectF child_damage_rect =
- child1->render_surface()->damage_tracker()->current_damage_rect();
- gfx::RectF root_damage_rect =
- root->render_surface()->damage_tracker()->current_damage_rect();
+ gfx::Rect child_damage_rect =
+ child1->render_surface()->damage_tracker()->current_damage_rect();
+ gfx::Rect root_damage_rect =
+ root->render_surface()->damage_tracker()->current_damage_rect();
ASSERT_TRUE(child1->render_surface());
EXPECT_FALSE(child2->render_surface());
@@ -220,8 +216,9 @@ TEST_F(DamageTrackerTest, SanityCheckTestTreeWithTwoSurfaces) {
// The render surface for child1 only has a content_rect that encloses
// grand_child1 and grand_child2, because child1 does not draw content.
- EXPECT_FLOAT_RECT_EQ(gfx::RectF(190.f, 190.f, 16.f, 18.f), child_damage_rect);
- EXPECT_FLOAT_RECT_EQ(gfx::RectF(0.f, 0.f, 500.f, 500.f), root_damage_rect);
+ EXPECT_EQ(gfx::Rect(190, 190, 16, 18).ToString(),
+ child_damage_rect.ToString());
+ EXPECT_EQ(gfx::Rect(500, 500).ToString(), root_damage_rect.ToString());
}
TEST_F(DamageTrackerTest, VerifyDamageForUpdateRects) {
@@ -231,35 +228,131 @@ TEST_F(DamageTrackerTest, VerifyDamageForUpdateRects) {
// CASE 1: Setting the update rect should cause the corresponding damage to
// the surface.
ClearDamageForAllSurfaces(root.get());
- child->set_update_rect(gfx::RectF(10.f, 11.f, 12.f, 13.f));
+ child->SetUpdateRect(gfx::RectF(10.f, 11.f, 12.f, 13.f));
EmulateDrawingOneFrame(root.get());
// Damage position on the surface should be: position of update_rect (10, 11)
// relative to the child (100, 100).
- gfx::RectF root_damage_rect =
- root->render_surface()->damage_tracker()->current_damage_rect();
- EXPECT_FLOAT_RECT_EQ(gfx::RectF(110.f, 111.f, 12.f, 13.f), root_damage_rect);
+ gfx::Rect root_damage_rect =
+ root->render_surface()->damage_tracker()->current_damage_rect();
+ EXPECT_EQ(gfx::Rect(110, 111, 12, 13).ToString(),
+ root_damage_rect.ToString());
// CASE 2: The same update rect twice in a row still produces the same
// damage.
ClearDamageForAllSurfaces(root.get());
- child->set_update_rect(gfx::RectF(10.f, 11.f, 12.f, 13.f));
+ child->SetUpdateRect(gfx::RectF(10.f, 11.f, 12.f, 13.f));
EmulateDrawingOneFrame(root.get());
root_damage_rect =
root->render_surface()->damage_tracker()->current_damage_rect();
- EXPECT_FLOAT_RECT_EQ(gfx::RectF(110.f, 111.f, 12.f, 13.f), root_damage_rect);
+ EXPECT_EQ(gfx::Rect(110, 111, 12, 13).ToString(),
+ root_damage_rect.ToString());
// CASE 3: Setting a different update rect should cause damage on the new
// update region, but no additional exposed old region.
ClearDamageForAllSurfaces(root.get());
- child->set_update_rect(gfx::RectF(20.f, 25.f, 1.f, 2.f));
+ child->SetUpdateRect(gfx::RectF(20.f, 25.f, 1.f, 2.f));
EmulateDrawingOneFrame(root.get());
// Damage position on the surface should be: position of update_rect (20, 25)
// relative to the child (100, 100).
root_damage_rect =
root->render_surface()->damage_tracker()->current_damage_rect();
- EXPECT_FLOAT_RECT_EQ(gfx::RectF(120.f, 125.f, 1.f, 2.f), root_damage_rect);
+ EXPECT_EQ(gfx::Rect(120, 125, 1, 2).ToString(), root_damage_rect.ToString());
+}
+
+TEST_F(DamageTrackerTest, VerifyDamageForLayerDamageRects) {
+ scoped_ptr<LayerImpl> root = CreateAndSetUpTestTreeWithOneSurface();
+ LayerImpl* child = root->children()[0];
+
+ // CASE 1: Adding the layer damage rect should cause the corresponding damage
+ // to the surface.
+ ClearDamageForAllSurfaces(root.get());
+ child->AddDamageRect(gfx::RectF(10.f, 11.f, 12.f, 13.f));
+ EmulateDrawingOneFrame(root.get());
+
+ // 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 =
+ root->render_surface()->damage_tracker()->current_damage_rect();
+ EXPECT_EQ(true, root_damage_rect.Contains(gfx::Rect(110, 111, 12, 13)));
+
+ // CASE 2: The same layer damage rect twice in a row still produces the same
+ // damage.
+ ClearDamageForAllSurfaces(root.get());
+ child->AddDamageRect(gfx::RectF(10.f, 11.f, 12.f, 13.f));
+ EmulateDrawingOneFrame(root.get());
+ root_damage_rect =
+ root->render_surface()->damage_tracker()->current_damage_rect();
+ EXPECT_EQ(true, root_damage_rect.Contains(gfx::Rect(110, 111, 12, 13)));
+
+ // CASE 3: Adding a different layer damage rect should cause damage on the
+ // new damaged region, but no additional exposed old region.
+ ClearDamageForAllSurfaces(root.get());
+ child->AddDamageRect(gfx::RectF(20.f, 25.f, 1.f, 2.f));
+ EmulateDrawingOneFrame(root.get());
+
+ // Damage position on the surface should be: position of layer damage_rect
+ // (20, 25) relative to the child (100, 100).
+ root_damage_rect =
+ root->render_surface()->damage_tracker()->current_damage_rect();
+ EXPECT_EQ(true, root_damage_rect.Contains(gfx::Rect(120, 125, 1, 2)));
+
+ // CASE 4: Adding multiple layer damage rects should cause a unified
+ // damage on root damage rect.
+ ClearDamageForAllSurfaces(root.get());
+ child->AddDamageRect(gfx::RectF(20.f, 25.f, 1.f, 2.f));
+ child->AddDamageRect(gfx::RectF(10.f, 15.f, 3.f, 4.f));
+ EmulateDrawingOneFrame(root.get());
+
+ // Damage position on the surface should be: position of layer damage_rect
+ // (20, 25) relative to the child (100, 100).
+ root_damage_rect =
+ root->render_surface()->damage_tracker()->current_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)));
+}
+
+TEST_F(DamageTrackerTest, VerifyDamageForLayerUpdateAndDamageRects) {
+ scoped_ptr<LayerImpl> root = CreateAndSetUpTestTreeWithOneSurface();
+ LayerImpl* child = root->children()[0];
+
+ // CASE 1: Adding the layer damage rect and update rect should cause the
+ // corresponding damage to the surface.
+ ClearDamageForAllSurfaces(root.get());
+ child->AddDamageRect(gfx::RectF(5.f, 6.f, 12.f, 13.f));
+ child->SetUpdateRect(gfx::RectF(15.f, 16.f, 14.f, 10.f));
+ EmulateDrawingOneFrame(root.get());
+
+ // Damage position on the surface should be: position of unified layer
+ // damage_rect and update rect (5, 6)
+ // relative to the child (100, 100).
+ gfx::Rect root_damage_rect =
+ root->render_surface()->damage_tracker()->current_damage_rect();
+ EXPECT_EQ(true, root_damage_rect.Contains(gfx::Rect(105, 106, 24, 20)));
+
+ // CASE 2: The same layer damage rect and update rect twice in a row still
+ // produces the same damage.
+ ClearDamageForAllSurfaces(root.get());
+ child->AddDamageRect(gfx::RectF(10.f, 11.f, 12.f, 13.f));
+ child->SetUpdateRect(gfx::RectF(10.f, 11.f, 14.f, 15.f));
+ EmulateDrawingOneFrame(root.get());
+ root_damage_rect =
+ root->render_surface()->damage_tracker()->current_damage_rect();
+ EXPECT_EQ(true, root_damage_rect.Contains(gfx::Rect(110, 111, 14, 15)));
+
+ // CASE 3: Adding a different layer damage rect and update rect should cause
+ // damage on the new damaged region, but no additional exposed old region.
+ ClearDamageForAllSurfaces(root.get());
+ child->AddDamageRect(gfx::RectF(20.f, 25.f, 2.f, 3.f));
+ child->SetUpdateRect(gfx::RectF(5.f, 10.f, 7.f, 8.f));
+ EmulateDrawingOneFrame(root.get());
+
+ // Damage position on the surface should be: position of unified layer damage
+ // rect and update rect (5, 10) relative to the child (100, 100).
+ root_damage_rect =
+ root->render_surface()->damage_tracker()->current_damage_rect();
+ EXPECT_EQ(true, root_damage_rect.Contains(gfx::Rect(105, 110, 17, 18)));
}
TEST_F(DamageTrackerTest, VerifyDamageForPropertyChanges) {
@@ -269,7 +362,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForPropertyChanges) {
// CASE 1: The layer's property changed flag takes priority over update rect.
//
ClearDamageForAllSurfaces(root.get());
- child->set_update_rect(gfx::RectF(10.f, 11.f, 12.f, 13.f));
+ child->SetUpdateRect(gfx::RectF(10.f, 11.f, 12.f, 13.f));
child->SetOpacity(0.5f);
EmulateDrawingOneFrame(root.get());
@@ -279,10 +372,10 @@ TEST_F(DamageTrackerTest, VerifyDamageForPropertyChanges) {
ASSERT_EQ(2u, root->render_surface()->layer_list().size());
// Damage should be the entire child layer in target_surface space.
- gfx::RectF expected_rect = gfx::RectF(100.f, 100.f, 30.f, 30.f);
- gfx::RectF root_damage_rect =
- root->render_surface()->damage_tracker()->current_damage_rect();
- EXPECT_FLOAT_RECT_EQ(expected_rect, root_damage_rect);
+ gfx::Rect expected_rect = gfx::Rect(100, 100, 30, 30);
+ gfx::Rect root_damage_rect =
+ root->render_surface()->damage_tracker()->current_damage_rect();
+ EXPECT_EQ(expected_rect.ToString(), root_damage_rect.ToString());
// CASE 2: If a layer moves due to property change, it damages both the new
// location and the old (exposed) location. The old location is the
@@ -302,7 +395,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForPropertyChanges) {
EmulateDrawingOneFrame(root.get());
// Expect damage to be the combination of the previous one and the new one.
- expected_rect.Union(gfx::RectF(200, 230, 30, 30));
+ expected_rect.Union(gfx::Rect(200, 230, 30, 30));
root_damage_rect =
root->render_surface()->damage_tracker()->current_damage_rect();
EXPECT_FLOAT_RECT_EQ(expected_rect, root_damage_rect);
@@ -319,15 +412,16 @@ TEST_F(DamageTrackerTest, VerifyDamageForTransformedLayer) {
rotation.Rotate(45.0);
ClearDamageForAllSurfaces(root.get());
- child->SetAnchorPoint(gfx::PointF(0.5f, 0.5f));
+ child->SetTransformOrigin(gfx::Point3F(
+ child->bounds().width() * 0.5f, child->bounds().height() * 0.5f, 0.f));
child->SetPosition(gfx::PointF(85.f, 85.f));
EmulateDrawingOneFrame(root.get());
// Sanity check that the layer actually moved to (85, 85), damaging its old
// location and new location.
- gfx::RectF root_damage_rect =
- root->render_surface()->damage_tracker()->current_damage_rect();
- EXPECT_FLOAT_RECT_EQ(gfx::RectF(85.f, 85.f, 45.f, 45.f), root_damage_rect);
+ gfx::Rect root_damage_rect =
+ root->render_surface()->damage_tracker()->current_damage_rect();
+ EXPECT_EQ(gfx::Rect(85, 85, 45, 45).ToString(), root_damage_rect.ToString());
// With the anchor on the layer's center, now we can test the rotation more
// intuitively, since it applies about the layer's anchor.
@@ -341,11 +435,11 @@ TEST_F(DamageTrackerTest, VerifyDamageForTransformedLayer) {
// region.
float expected_width = 30.f * sqrt(2.f);
float expected_position = 100.f - 0.5f * expected_width;
- gfx::RectF expected_rect(
- expected_position, expected_position, expected_width, expected_width);
+ gfx::Rect expected_rect = gfx::ToEnclosingRect(gfx::RectF(
+ expected_position, expected_position, expected_width, expected_width));
root_damage_rect =
root->render_surface()->damage_tracker()->current_damage_rect();
- EXPECT_FLOAT_RECT_EQ(expected_rect, root_damage_rect);
+ EXPECT_EQ(expected_rect.ToString(), root_damage_rect.ToString());
}
TEST_F(DamageTrackerTest, VerifyDamageForPerspectiveClippedLayer) {
@@ -392,10 +486,9 @@ TEST_F(DamageTrackerTest, VerifyDamageForPerspectiveClippedLayer) {
// The expected damage should cover the entire root surface (500x500), but we
// don't care whether the damage rect was clamped or is larger than the
// surface for this test.
- gfx::RectF root_damage_rect =
- root->render_surface()->damage_tracker()->current_damage_rect();
- gfx::RectF damage_we_care_about =
- gfx::RectF(gfx::PointF(), gfx::SizeF(500.f, 500.f));
+ gfx::Rect root_damage_rect =
+ root->render_surface()->damage_tracker()->current_damage_rect();
+ gfx::Rect damage_we_care_about = gfx::Rect(gfx::Size(500, 500));
EXPECT_TRUE(root_damage_rect.Contains(damage_we_care_about));
}
@@ -417,34 +510,32 @@ TEST_F(DamageTrackerTest, VerifyDamageForBlurredSurface) {
// Setting the update rect should cause the corresponding damage to the
// surface, blurred based on the size of the blur filter.
ClearDamageForAllSurfaces(root.get());
- child->set_update_rect(gfx::RectF(1.f, 2.f, 3.f, 4.f));
+ child->SetUpdateRect(gfx::RectF(1.f, 2.f, 3.f, 4.f));
EmulateDrawingOneFrame(root.get());
// Damage position on the surface should be: position of update_rect (1, 2)
// relative to the child (300, 300), but expanded by the blur outsets.
- gfx::RectF root_damage_rect =
- root->render_surface()->damage_tracker()->current_damage_rect();
- gfx::RectF expected_damage_rect =
- gfx::RectF(301.f, 302.f, 3.f, 4.f);
+ gfx::Rect root_damage_rect =
+ root->render_surface()->damage_tracker()->current_damage_rect();
+ gfx::Rect expected_damage_rect = gfx::Rect(301, 302, 3, 4);
expected_damage_rect.Inset(-outset_left,
-outset_top,
-outset_right,
-outset_bottom);
- EXPECT_FLOAT_RECT_EQ(expected_damage_rect, root_damage_rect);
+ EXPECT_EQ(expected_damage_rect.ToString(), root_damage_rect.ToString());
}
TEST_F(DamageTrackerTest, VerifyDamageForImageFilter) {
scoped_ptr<LayerImpl> root = CreateAndSetUpTestTreeWithOneSurface();
LayerImpl* child = root->children()[0];
- gfx::RectF root_damage_rect, child_damage_rect;
+ gfx::Rect root_damage_rect, child_damage_rect;
// Allow us to set damage on child too.
child->SetDrawsContent(true);
- skia::RefPtr<SkImageFilter> filter =
- skia::AdoptRef(new SkBlurImageFilter(SkIntToScalar(2),
- SkIntToScalar(2)));
+ skia::RefPtr<SkImageFilter> filter = skia::AdoptRef(
+ SkBlurImageFilter::Create(SkIntToScalar(2), SkIntToScalar(2)));
FilterOperations filters;
filters.Append(FilterOperation::CreateReferenceFilter(filter));
@@ -456,20 +547,22 @@ TEST_F(DamageTrackerTest, VerifyDamageForImageFilter) {
root->render_surface()->damage_tracker()->current_damage_rect();
child_damage_rect =
child->render_surface()->damage_tracker()->current_damage_rect();
- EXPECT_FLOAT_RECT_EQ(gfx::RectF(100.f, 100.f, 30.f, 30.f), root_damage_rect);
- EXPECT_FLOAT_RECT_EQ(gfx::RectF(0.f, 0.f, 30.f, 30.f), child_damage_rect);
+ EXPECT_EQ(gfx::Rect(100, 100, 30, 30).ToString(),
+ root_damage_rect.ToString());
+ EXPECT_EQ(gfx::Rect(30, 30).ToString(), child_damage_rect.ToString());
// CASE 1: Setting the update rect should damage the whole surface (for now)
ClearDamageForAllSurfaces(root.get());
- child->set_update_rect(gfx::RectF(0.f, 0.f, 1.f, 1.f));
+ child->SetUpdateRect(gfx::RectF(1.f, 1.f));
EmulateDrawingOneFrame(root.get());
root_damage_rect =
root->render_surface()->damage_tracker()->current_damage_rect();
child_damage_rect =
child->render_surface()->damage_tracker()->current_damage_rect();
- EXPECT_FLOAT_RECT_EQ(gfx::RectF(100.f, 100.f, 30.f, 30.f), root_damage_rect);
- EXPECT_FLOAT_RECT_EQ(gfx::RectF(0.f, 0.f, 30.f, 30.f), child_damage_rect);
+ EXPECT_EQ(gfx::Rect(100, 100, 30, 30).ToString(),
+ root_damage_rect.ToString());
+ EXPECT_EQ(gfx::Rect(30.f, 30.f).ToString(), child_damage_rect.ToString());
}
TEST_F(DamageTrackerTest, VerifyDamageForBackgroundBlurredChild) {
@@ -494,29 +587,28 @@ TEST_F(DamageTrackerTest, VerifyDamageForBackgroundBlurredChild) {
// the surface, blurred based on the size of the child's background
// blur filter.
ClearDamageForAllSurfaces(root.get());
- root->set_update_rect(gfx::RectF(297.f, 297.f, 2.f, 2.f));
+ root->SetUpdateRect(gfx::RectF(297.f, 297.f, 2.f, 2.f));
EmulateDrawingOneFrame(root.get());
- gfx::RectF root_damage_rect =
- root->render_surface()->damage_tracker()->current_damage_rect();
+ gfx::Rect root_damage_rect =
+ root->render_surface()->damage_tracker()->current_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
// update_rect (297, 297), but expanded by the blur outsets.
- gfx::RectF expected_damage_rect =
- gfx::RectF(297.f, 297.f, 2.f, 2.f);
+ gfx::Rect expected_damage_rect = gfx::Rect(297, 297, 2, 2);
expected_damage_rect.Inset(-outset_left,
-outset_top,
-outset_right,
-outset_bottom);
- EXPECT_FLOAT_RECT_EQ(expected_damage_rect, root_damage_rect);
+ EXPECT_EQ(expected_damage_rect.ToString(), root_damage_rect.ToString());
// CASE 2: Setting the update rect should cause the corresponding damage to
// the surface, blurred based on the size of the child's background
// blur filter. Since the damage extends to the right/bottom outside
// of the blurred layer, only the left/top should end up expanded.
ClearDamageForAllSurfaces(root.get());
- root->set_update_rect(gfx::RectF(297.f, 297.f, 30.f, 30.f));
+ root->SetUpdateRect(gfx::RectF(297.f, 297.f, 30.f, 30.f));
EmulateDrawingOneFrame(root.get());
root_damage_rect =
@@ -524,35 +616,33 @@ TEST_F(DamageTrackerTest, VerifyDamageForBackgroundBlurredChild) {
// 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
// update_rect (297, 297), but expanded on the left/top by the blur outsets.
- expected_damage_rect =
- gfx::RectF(297.f, 297.f, 30.f, 30.f);
+ expected_damage_rect = gfx::Rect(297, 297, 30, 30);
expected_damage_rect.Inset(-outset_left,
-outset_top,
0,
0);
- EXPECT_FLOAT_RECT_EQ(expected_damage_rect, root_damage_rect);
+ EXPECT_EQ(expected_damage_rect.ToString(), root_damage_rect.ToString());
// CASE 3: Setting this update rect outside the blurred content_bounds of the
// blurred child1 will not cause it to be expanded.
ClearDamageForAllSurfaces(root.get());
- root->set_update_rect(gfx::RectF(30.f, 30.f, 2.f, 2.f));
+ root->SetUpdateRect(gfx::RectF(30.f, 30.f, 2.f, 2.f));
EmulateDrawingOneFrame(root.get());
root_damage_rect =
root->render_surface()->damage_tracker()->current_damage_rect();
// Damage on the root should be: position of update_rect (30, 30), not
// expanded.
- expected_damage_rect =
- gfx::RectF(30.f, 30.f, 2.f, 2.f);
+ expected_damage_rect = gfx::Rect(30, 30, 2, 2);
- EXPECT_FLOAT_RECT_EQ(expected_damage_rect, root_damage_rect);
+ EXPECT_EQ(expected_damage_rect.ToString(), root_damage_rect.ToString());
// CASE 4: Setting this update rect inside the blurred content_bounds but
// outside the original content_bounds of the blurred child1 will
// cause it to be expanded.
ClearDamageForAllSurfaces(root.get());
- root->set_update_rect(gfx::RectF(99.f, 99.f, 1.f, 1.f));
+ root->SetUpdateRect(gfx::RectF(99.f, 99.f, 1.f, 1.f));
EmulateDrawingOneFrame(root.get());
root_damage_rect =
@@ -560,49 +650,46 @@ TEST_F(DamageTrackerTest, VerifyDamageForBackgroundBlurredChild) {
// Damage on the root should be: position of update_rect (99, 99), expanded by
// the blurring on child1, but since it is 1 pixel outside the layer, the
// expanding should be reduced by 1.
- expected_damage_rect =
- gfx::RectF(99.f, 99.f, 1.f, 1.f);
+ expected_damage_rect = gfx::Rect(99, 99, 1, 1);
expected_damage_rect.Inset(-outset_left + 1,
-outset_top + 1,
-outset_right,
-outset_bottom);
- EXPECT_FLOAT_RECT_EQ(expected_damage_rect, root_damage_rect);
+ EXPECT_EQ(expected_damage_rect.ToString(), root_damage_rect.ToString());
// CASE 5: Setting the update rect on child2, which is above child1, will
// not get blurred by child1, so it does not need to get expanded.
ClearDamageForAllSurfaces(root.get());
- child2->set_update_rect(gfx::RectF(0.f, 0.f, 1.f, 1.f));
+ child2->SetUpdateRect(gfx::RectF(0.f, 0.f, 1.f, 1.f));
EmulateDrawingOneFrame(root.get());
root_damage_rect =
root->render_surface()->damage_tracker()->current_damage_rect();
// Damage on child2 should be: position of update_rect offset by the child's
// position (11, 11), and not expanded by anything.
- expected_damage_rect =
- gfx::RectF(11.f, 11.f, 1.f, 1.f);
+ expected_damage_rect = gfx::Rect(11, 11, 1, 1);
- EXPECT_FLOAT_RECT_EQ(expected_damage_rect, root_damage_rect);
+ EXPECT_EQ(expected_damage_rect.ToString(), root_damage_rect.ToString());
// CASE 6: Setting the update rect on child1 will also blur the damage, so
// that any pixels needed for the blur are redrawn in the current
// frame.
ClearDamageForAllSurfaces(root.get());
- child1->set_update_rect(gfx::RectF(0.f, 0.f, 1.f, 1.f));
+ child1->SetUpdateRect(gfx::RectF(0.f, 0.f, 1.f, 1.f));
EmulateDrawingOneFrame(root.get());
root_damage_rect =
root->render_surface()->damage_tracker()->current_damage_rect();
// Damage on child1 should be: position of update_rect offset by the child's
// position (100, 100), and expanded by the damage.
- expected_damage_rect =
- gfx::RectF(100.f, 100.f, 1.f, 1.f);
+ expected_damage_rect = gfx::Rect(100, 100, 1, 1);
expected_damage_rect.Inset(-outset_left,
-outset_top,
-outset_right,
-outset_bottom);
- EXPECT_FLOAT_RECT_EQ(expected_damage_rect, root_damage_rect);
+ EXPECT_EQ(expected_damage_rect.ToString(), root_damage_rect.ToString());
}
TEST_F(DamageTrackerTest, VerifyDamageForAddingAndRemovingLayer) {
@@ -616,7 +703,6 @@ TEST_F(DamageTrackerTest, VerifyDamageForAddingAndRemovingLayer) {
scoped_ptr<LayerImpl> child2 =
LayerImpl::Create(host_impl_.active_tree(), 3);
child2->SetPosition(gfx::PointF(400.f, 380.f));
- child2->SetAnchorPoint(gfx::PointF());
child2->SetBounds(gfx::Size(6, 8));
child2->SetContentBounds(gfx::Size(6, 8));
child2->SetDrawsContent(true);
@@ -628,9 +714,9 @@ TEST_F(DamageTrackerTest, VerifyDamageForAddingAndRemovingLayer) {
// surfaces are tested elsewhere.
ASSERT_EQ(3u, root->render_surface()->layer_list().size());
- gfx::RectF root_damage_rect =
- root->render_surface()->damage_tracker()->current_damage_rect();
- EXPECT_FLOAT_RECT_EQ(gfx::RectF(400.f, 380.f, 6.f, 8.f), root_damage_rect);
+ gfx::Rect root_damage_rect =
+ root->render_surface()->damage_tracker()->current_damage_rect();
+ EXPECT_EQ(gfx::Rect(400, 380, 6, 8).ToString(), root_damage_rect.ToString());
// CASE 2: If the layer is removed, its entire old layer becomes exposed, not
// just the last update rect.
@@ -651,7 +737,8 @@ TEST_F(DamageTrackerTest, VerifyDamageForAddingAndRemovingLayer) {
root_damage_rect =
root->render_surface()->damage_tracker()->current_damage_rect();
- EXPECT_FLOAT_RECT_EQ(gfx::RectF(100.f, 100.f, 30.f, 30.f), root_damage_rect);
+ EXPECT_EQ(gfx::Rect(100, 100, 30, 30).ToString(),
+ root_damage_rect.ToString());
}
TEST_F(DamageTrackerTest, VerifyDamageForNewUnchangedLayer) {
@@ -665,7 +752,6 @@ TEST_F(DamageTrackerTest, VerifyDamageForNewUnchangedLayer) {
scoped_ptr<LayerImpl> child2 =
LayerImpl::Create(host_impl_.active_tree(), 3);
child2->SetPosition(gfx::PointF(400.f, 380.f));
- child2->SetAnchorPoint(gfx::PointF());
child2->SetBounds(gfx::Size(6, 8));
child2->SetContentBounds(gfx::Size(6, 8));
child2->SetDrawsContent(true);
@@ -683,9 +769,9 @@ TEST_F(DamageTrackerTest, VerifyDamageForNewUnchangedLayer) {
// surfaces are tested elsewhere.
ASSERT_EQ(3u, root->render_surface()->layer_list().size());
- gfx::RectF root_damage_rect =
- root->render_surface()->damage_tracker()->current_damage_rect();
- EXPECT_FLOAT_RECT_EQ(gfx::RectF(400.f, 380.f, 6.f, 8.f), root_damage_rect);
+ gfx::Rect root_damage_rect =
+ root->render_surface()->damage_tracker()->current_damage_rect();
+ EXPECT_EQ(gfx::Rect(400, 380, 6, 8).ToString(), root_damage_rect.ToString());
}
TEST_F(DamageTrackerTest, VerifyDamageForMultipleLayers) {
@@ -699,7 +785,6 @@ TEST_F(DamageTrackerTest, VerifyDamageForMultipleLayers) {
scoped_ptr<LayerImpl> child2 =
LayerImpl::Create(host_impl_.active_tree(), 3);
child2->SetPosition(gfx::PointF(400.f, 380.f));
- child2->SetAnchorPoint(gfx::PointF());
child2->SetBounds(gfx::Size(6, 8));
child2->SetContentBounds(gfx::Size(6, 8));
child2->SetDrawsContent(true);
@@ -709,16 +794,16 @@ TEST_F(DamageTrackerTest, VerifyDamageForMultipleLayers) {
EmulateDrawingOneFrame(root.get());
// Damaging two layers simultaneously should cause combined damage.
- // - child1 update rect in surface space: gfx::RectF(100.f, 100.f, 1.f, 2.f);
- // - child2 update rect in surface space: gfx::RectF(400.f, 380.f, 3.f, 4.f);
+ // - child1 update rect in surface space: gfx::Rect(100, 100, 1, 2);
+ // - child2 update rect in surface space: gfx::Rect(400, 380, 3, 4);
ClearDamageForAllSurfaces(root.get());
- child1->set_update_rect(gfx::RectF(0.f, 0.f, 1.f, 2.f));
- child2->set_update_rect(gfx::RectF(0.f, 0.f, 3.f, 4.f));
+ child1->SetUpdateRect(gfx::RectF(0.f, 0.f, 1.f, 2.f));
+ child2->SetUpdateRect(gfx::RectF(0.f, 0.f, 3.f, 4.f));
EmulateDrawingOneFrame(root.get());
- gfx::RectF root_damage_rect =
- root->render_surface()->damage_tracker()->current_damage_rect();
- EXPECT_FLOAT_RECT_EQ(
- gfx::RectF(100.f, 100.f, 303.f, 284.f), root_damage_rect);
+ gfx::Rect root_damage_rect =
+ root->render_surface()->damage_tracker()->current_damage_rect();
+ EXPECT_EQ(gfx::Rect(100, 100, 303, 284).ToString(),
+ root_damage_rect.ToString());
}
TEST_F(DamageTrackerTest, VerifyDamageForNestedSurfaces) {
@@ -726,8 +811,8 @@ TEST_F(DamageTrackerTest, VerifyDamageForNestedSurfaces) {
LayerImpl* child1 = root->children()[0];
LayerImpl* child2 = root->children()[1];
LayerImpl* grand_child1 = root->children()[0]->children()[0];
- gfx::RectF child_damage_rect;
- gfx::RectF root_damage_rect;
+ gfx::Rect child_damage_rect;
+ gfx::Rect root_damage_rect;
// CASE 1: Damage to a descendant surface should propagate properly to
// ancestor surface.
@@ -738,15 +823,15 @@ TEST_F(DamageTrackerTest, VerifyDamageForNestedSurfaces) {
child1->render_surface()->damage_tracker()->current_damage_rect();
root_damage_rect =
root->render_surface()->damage_tracker()->current_damage_rect();
- EXPECT_FLOAT_RECT_EQ(gfx::RectF(200.f, 200.f, 6.f, 8.f), child_damage_rect);
- EXPECT_FLOAT_RECT_EQ(gfx::RectF(300.f, 300.f, 6.f, 8.f), 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());
// CASE 2: Same as previous case, but with additional damage elsewhere that
// should be properly unioned.
// - child1 surface damage in root surface space:
- // gfx::RectF(300.f, 300.f, 6.f, 8.f);
+ // gfx::Rect(300, 300, 6, 8);
// - child2 damage in root surface space:
- // gfx::RectF(11.f, 11.f, 18.f, 18.f);
+ // gfx::Rect(11, 11, 18, 18);
ClearDamageForAllSurfaces(root.get());
grand_child1->SetOpacity(0.7f);
child2->SetOpacity(0.7f);
@@ -755,8 +840,9 @@ TEST_F(DamageTrackerTest, VerifyDamageForNestedSurfaces) {
child1->render_surface()->damage_tracker()->current_damage_rect();
root_damage_rect =
root->render_surface()->damage_tracker()->current_damage_rect();
- EXPECT_FLOAT_RECT_EQ(gfx::RectF(200.f, 200.f, 6.f, 8.f), child_damage_rect);
- EXPECT_FLOAT_RECT_EQ(gfx::RectF(11.f, 11.f, 295.f, 297.f), 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(),
+ root_damage_rect.ToString());
}
TEST_F(DamageTrackerTest, VerifyDamageForSurfaceChangeFromDescendantLayer) {
@@ -770,8 +856,8 @@ TEST_F(DamageTrackerTest, VerifyDamageForSurfaceChangeFromDescendantLayer) {
scoped_ptr<LayerImpl> root = CreateAndSetUpTestTreeWithTwoSurfaces();
LayerImpl* child1 = root->children()[0];
LayerImpl* grand_child1 = root->children()[0]->children()[0];
- gfx::RectF child_damage_rect;
- gfx::RectF root_damage_rect;
+ gfx::Rect child_damage_rect;
+ gfx::Rect root_damage_rect;
ClearDamageForAllSurfaces(root.get());
grand_child1->SetPosition(gfx::PointF(195.f, 205.f));
@@ -783,12 +869,14 @@ TEST_F(DamageTrackerTest, VerifyDamageForSurfaceChangeFromDescendantLayer) {
// The new surface bounds should be damaged entirely, even though only one of
// the layers changed.
- EXPECT_FLOAT_RECT_EQ(gfx::RectF(190.f, 190.f, 11.f, 23.f), child_damage_rect);
+ EXPECT_EQ(gfx::Rect(190, 190, 11, 23).ToString(),
+ child_damage_rect.ToString());
// Damage to the root surface should be the union of child1's *entire* render
// surface (in target space), and its old exposed area (also in target
// space).
- EXPECT_FLOAT_RECT_EQ(gfx::RectF(290.f, 290.f, 16.f, 23.f), root_damage_rect);
+ EXPECT_EQ(gfx::Rect(290, 290, 16, 23).ToString(),
+ root_damage_rect.ToString());
}
TEST_F(DamageTrackerTest, VerifyDamageForSurfaceChangeFromAncestorLayer) {
@@ -805,8 +893,8 @@ TEST_F(DamageTrackerTest, VerifyDamageForSurfaceChangeFromAncestorLayer) {
scoped_ptr<LayerImpl> root = CreateAndSetUpTestTreeWithTwoSurfaces();
LayerImpl* child1 = root->children()[0];
- gfx::RectF child_damage_rect;
- gfx::RectF root_damage_rect;
+ gfx::Rect child_damage_rect;
+ gfx::Rect root_damage_rect;
ClearDamageForAllSurfaces(root.get());
child1->SetPosition(gfx::PointF(50.f, 50.f));
@@ -817,20 +905,22 @@ TEST_F(DamageTrackerTest, VerifyDamageForSurfaceChangeFromAncestorLayer) {
root->render_surface()->damage_tracker()->current_damage_rect();
// The new surface bounds should be damaged entirely.
- EXPECT_FLOAT_RECT_EQ(gfx::RectF(190.f, 190.f, 16.f, 18.f), child_damage_rect);
+ EXPECT_EQ(gfx::Rect(190, 190, 16, 18).ToString(),
+ child_damage_rect.ToString());
// The entire child1 surface and the old exposed child1 surface should damage
// the root surface.
- // - old child1 surface in target space: gfx::RectF(290.f, 290.f, 16.f, 18.f)
- // - new child1 surface in target space: gfx::RectF(240.f, 240.f, 16.f, 18.f)
- EXPECT_FLOAT_RECT_EQ(gfx::RectF(240.f, 240.f, 66.f, 68.f), root_damage_rect);
+ // - old child1 surface in target space: gfx::Rect(290, 290, 16, 18)
+ // - new child1 surface in target space: gfx::Rect(240, 240, 16, 18)
+ EXPECT_EQ(gfx::Rect(240, 240, 66, 68).ToString(),
+ root_damage_rect.ToString());
}
TEST_F(DamageTrackerTest, VerifyDamageForAddingAndRemovingRenderSurfaces) {
scoped_ptr<LayerImpl> root = CreateAndSetUpTestTreeWithTwoSurfaces();
LayerImpl* child1 = root->children()[0];
- gfx::RectF child_damage_rect;
- gfx::RectF root_damage_rect;
+ gfx::Rect child_damage_rect;
+ gfx::Rect root_damage_rect;
// CASE 1: If a descendant surface disappears, its entire old area becomes
// exposed.
@@ -845,7 +935,8 @@ TEST_F(DamageTrackerTest, VerifyDamageForAddingAndRemovingRenderSurfaces) {
root_damage_rect =
root->render_surface()->damage_tracker()->current_damage_rect();
- EXPECT_FLOAT_RECT_EQ(gfx::RectF(290.f, 290.f, 16.f, 18.f), root_damage_rect);
+ EXPECT_EQ(gfx::Rect(290, 290, 16, 18).ToString(),
+ root_damage_rect.ToString());
// CASE 2: If a descendant surface appears, its entire old area becomes
// exposed.
@@ -873,15 +964,17 @@ TEST_F(DamageTrackerTest, VerifyDamageForAddingAndRemovingRenderSurfaces) {
child1->render_surface()->damage_tracker()->current_damage_rect();
root_damage_rect =
root->render_surface()->damage_tracker()->current_damage_rect();
- EXPECT_FLOAT_RECT_EQ(gfx::RectF(190.f, 190.f, 16.f, 18.f), child_damage_rect);
- EXPECT_FLOAT_RECT_EQ(gfx::RectF(290.f, 290.f, 16.f, 18.f), root_damage_rect);
+ EXPECT_EQ(gfx::Rect(190, 190, 16, 18).ToString(),
+ child_damage_rect.ToString());
+ EXPECT_EQ(gfx::Rect(290, 290, 16, 18).ToString(),
+ root_damage_rect.ToString());
}
TEST_F(DamageTrackerTest, VerifyNoDamageWhenNothingChanged) {
scoped_ptr<LayerImpl> root = CreateAndSetUpTestTreeWithTwoSurfaces();
LayerImpl* child1 = root->children()[0];
- gfx::RectF child_damage_rect;
- gfx::RectF root_damage_rect;
+ gfx::Rect child_damage_rect;
+ gfx::Rect root_damage_rect;
// CASE 1: If nothing changes, the damage rect should be empty.
//
@@ -910,13 +1003,13 @@ TEST_F(DamageTrackerTest, VerifyNoDamageWhenNothingChanged) {
TEST_F(DamageTrackerTest, VerifyNoDamageForUpdateRectThatDoesNotDrawContent) {
scoped_ptr<LayerImpl> root = CreateAndSetUpTestTreeWithTwoSurfaces();
LayerImpl* child1 = root->children()[0];
- gfx::RectF child_damage_rect;
- gfx::RectF root_damage_rect;
+ gfx::Rect child_damage_rect;
+ gfx::Rect root_damage_rect;
// In our specific tree, the update rect of child1 should not cause any
// damage to any surface because it does not actually draw content.
ClearDamageForAllSurfaces(root.get());
- child1->set_update_rect(gfx::RectF(0.f, 0.f, 1.f, 2.f));
+ child1->SetUpdateRect(gfx::RectF(0.f, 0.f, 1.f, 2.f));
EmulateDrawingOneFrame(root.get());
child_damage_rect =
child1->render_surface()->damage_tracker()->current_damage_rect();
@@ -943,7 +1036,6 @@ TEST_F(DamageTrackerTest, VerifyDamageForReplica) {
scoped_ptr<LayerImpl> grand_child3 =
LayerImpl::Create(host_impl_.active_tree(), 6);
grand_child3->SetPosition(gfx::PointF(240.f, 240.f));
- grand_child3->SetAnchorPoint(gfx::PointF());
grand_child3->SetBounds(gfx::Size(10, 10));
grand_child3->SetContentBounds(gfx::Size(10, 10));
grand_child3->SetDrawsContent(true);
@@ -959,7 +1051,6 @@ TEST_F(DamageTrackerTest, VerifyDamageForReplica) {
scoped_ptr<LayerImpl> grand_child1_replica =
LayerImpl::Create(host_impl_.active_tree(), 7);
grand_child1_replica->SetPosition(gfx::PointF());
- grand_child1_replica->SetAnchorPoint(gfx::PointF());
gfx::Transform reflection;
reflection.Scale3d(-1.0, 1.0, 1.0);
grand_child1_replica->SetTransform(reflection);
@@ -967,19 +1058,19 @@ TEST_F(DamageTrackerTest, VerifyDamageForReplica) {
}
EmulateDrawingOneFrame(root.get());
- gfx::RectF grand_child_damage_rect =
- grand_child1->render_surface()->damage_tracker()->
- current_damage_rect();
- gfx::RectF child_damage_rect =
- child1->render_surface()->damage_tracker()->current_damage_rect();
- gfx::RectF root_damage_rect =
- root->render_surface()->damage_tracker()->current_damage_rect();
+ gfx::Rect grand_child_damage_rect =
+ grand_child1->render_surface()->damage_tracker()->current_damage_rect();
+ gfx::Rect child_damage_rect =
+ child1->render_surface()->damage_tracker()->current_damage_rect();
+ gfx::Rect root_damage_rect =
+ root->render_surface()->damage_tracker()->current_damage_rect();
// The grand_child surface damage should not include its own replica. The
// child surface damage should include the normal and replica surfaces.
- EXPECT_FLOAT_RECT_EQ(gfx::RectF(0.f, 0.f, 6.f, 8.f), grand_child_damage_rect);
- EXPECT_FLOAT_RECT_EQ(gfx::RectF(194.f, 200.f, 12.f, 8.f), child_damage_rect);
- EXPECT_FLOAT_RECT_EQ(gfx::RectF(294.f, 300.f, 12.f, 8.f), root_damage_rect);
+ EXPECT_EQ(gfx::Rect(6, 8).ToString(), grand_child_damage_rect.ToString());
+ EXPECT_EQ(gfx::Rect(194, 200, 12, 8).ToString(),
+ child_damage_rect.ToString());
+ EXPECT_EQ(gfx::Rect(294, 300, 12, 8).ToString(), root_damage_rect.ToString());
// CASE 2: moving the descendant surface should cause both the original and
// reflected areas to be damaged on the target.
@@ -1002,11 +1093,13 @@ TEST_F(DamageTrackerTest, VerifyDamageForReplica) {
// The child surface damage should include normal and replica surfaces for
// both old and new locations.
- // - old location in target space: gfx::RectF(194.f, 200.f, 12.f, 8.f)
- // - new location in target space: gfx::RectF(189.f, 205.f, 12.f, 8.f)
- EXPECT_FLOAT_RECT_EQ(gfx::RectF(0.f, 0.f, 6.f, 8.f), grand_child_damage_rect);
- EXPECT_FLOAT_RECT_EQ(gfx::RectF(189.f, 200.f, 17.f, 13.f), child_damage_rect);
- EXPECT_FLOAT_RECT_EQ(gfx::RectF(289.f, 300.f, 17.f, 13.f), root_damage_rect);
+ // - old location in target space: gfx::Rect(194, 200, 12, 8)
+ // - new location in target space: gfx::Rect(189, 205, 12, 8)
+ EXPECT_EQ(gfx::Rect(6, 8).ToString(), grand_child_damage_rect.ToString());
+ EXPECT_EQ(gfx::Rect(189, 200, 17, 13).ToString(),
+ child_damage_rect.ToString());
+ EXPECT_EQ(gfx::Rect(289, 300, 17, 13).ToString(),
+ root_damage_rect.ToString());
// CASE 3: removing the reflection should cause the entire region including
// reflection to damage the target surface.
@@ -1024,8 +1117,9 @@ TEST_F(DamageTrackerTest, VerifyDamageForReplica) {
root_damage_rect =
root->render_surface()->damage_tracker()->current_damage_rect();
- EXPECT_FLOAT_RECT_EQ(gfx::RectF(189.f, 205.f, 12.f, 8.f), child_damage_rect);
- EXPECT_FLOAT_RECT_EQ(gfx::RectF(289.f, 305.f, 12.f, 8.f), root_damage_rect);
+ EXPECT_EQ(gfx::Rect(189, 205, 12, 8).ToString(),
+ child_damage_rect.ToString());
+ EXPECT_EQ(gfx::Rect(289, 305, 12, 8).ToString(), root_damage_rect.ToString());
}
TEST_F(DamageTrackerTest, VerifyDamageForMask) {
@@ -1042,7 +1136,6 @@ TEST_F(DamageTrackerTest, VerifyDamageForMask) {
scoped_ptr<LayerImpl> mask_layer =
LayerImpl::Create(host_impl_.active_tree(), 3);
mask_layer->SetPosition(child->position());
- mask_layer->SetAnchorPoint(gfx::PointF());
mask_layer->SetBounds(child->bounds());
mask_layer->SetContentBounds(child->bounds());
child->SetMaskLayer(mask_layer.Pass());
@@ -1056,7 +1149,6 @@ TEST_F(DamageTrackerTest, VerifyDamageForMask) {
scoped_ptr<LayerImpl> grand_child =
LayerImpl::Create(host_impl_.active_tree(), 4);
grand_child->SetPosition(gfx::PointF(2.f, 2.f));
- grand_child->SetAnchorPoint(gfx::PointF());
grand_child->SetBounds(gfx::Size(2, 2));
grand_child->SetContentBounds(gfx::Size(2, 2));
grand_child->SetDrawsContent(true);
@@ -1070,11 +1162,11 @@ TEST_F(DamageTrackerTest, VerifyDamageForMask) {
// CASE 1: the update_rect on a mask layer should damage the entire target
// surface.
ClearDamageForAllSurfaces(root.get());
- mask_layer->set_update_rect(gfx::RectF(1.f, 2.f, 3.f, 4.f));
+ mask_layer->SetUpdateRect(gfx::RectF(1.f, 2.f, 3.f, 4.f));
EmulateDrawingOneFrame(root.get());
- gfx::RectF child_damage_rect =
- child->render_surface()->damage_tracker()->current_damage_rect();
- EXPECT_FLOAT_RECT_EQ(gfx::RectF(0.f, 0.f, 30.f, 30.f), child_damage_rect);
+ gfx::Rect child_damage_rect =
+ child->render_surface()->damage_tracker()->current_damage_rect();
+ EXPECT_EQ(gfx::Rect(30, 30).ToString(), child_damage_rect.ToString());
// CASE 2: a property change on the mask layer should damage the entire
// target surface.
@@ -1094,7 +1186,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForMask) {
EmulateDrawingOneFrame(root.get());
child_damage_rect =
child->render_surface()->damage_tracker()->current_damage_rect();
- EXPECT_FLOAT_RECT_EQ(gfx::RectF(0.f, 0.f, 30.f, 30.f), child_damage_rect);
+ EXPECT_EQ(gfx::Rect(30, 30).ToString(), child_damage_rect.ToString());
// CASE 3: removing the mask also damages the entire target surface.
//
@@ -1118,7 +1210,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForMask) {
child_damage_rect =
child->render_surface()->damage_tracker()->current_damage_rect();
- EXPECT_FLOAT_RECT_EQ(gfx::RectF(0.f, 0.f, 30.f, 30.f), child_damage_rect);
+ EXPECT_EQ(gfx::Rect(30, 30).ToString(), child_damage_rect.ToString());
}
TEST_F(DamageTrackerTest, VerifyDamageForReplicaMask) {
@@ -1136,7 +1228,6 @@ TEST_F(DamageTrackerTest, VerifyDamageForReplicaMask) {
scoped_ptr<LayerImpl> grand_child1_replica =
LayerImpl::Create(host_impl_.active_tree(), 6);
grand_child1_replica->SetPosition(gfx::PointF());
- grand_child1_replica->SetAnchorPoint(gfx::PointF());
gfx::Transform reflection;
reflection.Scale3d(-1.0, 1.0, 1.0);
grand_child1_replica->SetTransform(reflection);
@@ -1149,7 +1240,6 @@ TEST_F(DamageTrackerTest, VerifyDamageForReplicaMask) {
scoped_ptr<LayerImpl> replica_mask_layer =
LayerImpl::Create(host_impl_.active_tree(), 7);
replica_mask_layer->SetPosition(gfx::PointF());
- replica_mask_layer->SetAnchorPoint(gfx::PointF());
replica_mask_layer->SetBounds(grand_child1->bounds());
replica_mask_layer->SetContentBounds(grand_child1->bounds());
grand_child1_replica->SetMaskLayer(replica_mask_layer.Pass());
@@ -1167,14 +1257,13 @@ TEST_F(DamageTrackerTest, VerifyDamageForReplicaMask) {
replica_mask_layer->SetStackingOrderChanged(true);
EmulateDrawingOneFrame(root.get());
- gfx::RectF grand_child_damage_rect =
- grand_child1->render_surface()->damage_tracker()->
- current_damage_rect();
- gfx::RectF child_damage_rect =
- child1->render_surface()->damage_tracker()->current_damage_rect();
+ gfx::Rect grand_child_damage_rect =
+ grand_child1->render_surface()->damage_tracker()->current_damage_rect();
+ gfx::Rect child_damage_rect =
+ child1->render_surface()->damage_tracker()->current_damage_rect();
EXPECT_TRUE(grand_child_damage_rect.IsEmpty());
- EXPECT_FLOAT_RECT_EQ(gfx::RectF(194.f, 200.f, 6.f, 8.f), child_damage_rect);
+ EXPECT_EQ(gfx::Rect(194, 200, 6, 8).ToString(), child_damage_rect.ToString());
// CASE 2: removing the replica mask damages only the reflected region on the
// target surface.
@@ -1190,10 +1279,10 @@ TEST_F(DamageTrackerTest, VerifyDamageForReplicaMask) {
child1->render_surface()->damage_tracker()->current_damage_rect();
EXPECT_TRUE(grand_child_damage_rect.IsEmpty());
- EXPECT_FLOAT_RECT_EQ(gfx::RectF(194.f, 200.f, 6.f, 8.f), child_damage_rect);
+ EXPECT_EQ(gfx::Rect(194, 200, 6, 8).ToString(), child_damage_rect.ToString());
}
-TEST_F(DamageTrackerTest, VerifyDamageForReplicaMaskWithAnchor) {
+TEST_F(DamageTrackerTest, VerifyDamageForReplicaMaskWithTransformOrigin) {
scoped_ptr<LayerImpl> root = CreateAndSetUpTestTreeWithTwoSurfaces();
LayerImpl* child1 = root->children()[0];
LayerImpl* grand_child1 = child1->children()[0];
@@ -1202,9 +1291,11 @@ TEST_F(DamageTrackerTest, VerifyDamageForReplicaMaskWithAnchor) {
// replica_mask.
ClearDamageForAllSurfaces(root.get());
- // This is not actually the anchor point being tested, but by convention its
+ // This is not actually the transform origin point being tested, but by
+ // convention its
// expected to be the same as the replica's anchor point.
- grand_child1->SetAnchorPoint(gfx::PointF(1.f, 0.f));
+ grand_child1->SetTransformOrigin(
+ gfx::Point3F(grand_child1->bounds().width(), 0.f, 0.f));
{
scoped_ptr<LayerImpl> grand_child1_replica =
@@ -1212,7 +1303,8 @@ TEST_F(DamageTrackerTest, VerifyDamageForReplicaMaskWithAnchor) {
grand_child1_replica->SetPosition(gfx::PointF());
// This is the anchor being tested.
- grand_child1_replica->SetAnchorPoint(gfx::PointF(1.f, 0.f));
+ grand_child1_replica->SetTransformOrigin(
+ gfx::Point3F(grand_child1->bounds().width(), 0.f, 0.f));
gfx::Transform reflection;
reflection.Scale3d(-1.0, 1.0, 1.0);
grand_child1_replica->SetTransform(reflection);
@@ -1225,8 +1317,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForReplicaMaskWithAnchor) {
scoped_ptr<LayerImpl> replica_mask_layer =
LayerImpl::Create(host_impl_.active_tree(), 7);
replica_mask_layer->SetPosition(gfx::PointF());
- // Note: this is not the anchor being tested.
- replica_mask_layer->SetAnchorPoint(gfx::PointF());
+ // Note: this is not the transform origin being tested.
replica_mask_layer->SetBounds(grand_child1->bounds());
replica_mask_layer->SetContentBounds(grand_child1->bounds());
grand_child1_replica->SetMaskLayer(replica_mask_layer.Pass());
@@ -1245,9 +1336,9 @@ TEST_F(DamageTrackerTest, VerifyDamageForReplicaMaskWithAnchor) {
EmulateDrawingOneFrame(root.get());
- gfx::RectF child_damage_rect =
- child1->render_surface()->damage_tracker()->current_damage_rect();
- EXPECT_FLOAT_RECT_EQ(gfx::RectF(206.f, 200.f, 6.f, 8.f), child_damage_rect);
+ gfx::Rect child_damage_rect =
+ child1->render_surface()->damage_tracker()->current_damage_rect();
+ EXPECT_EQ(gfx::Rect(206, 200, 6, 8).ToString(), child_damage_rect.ToString());
}
TEST_F(DamageTrackerTest, DamageWhenAddedExternally) {
@@ -1258,27 +1349,26 @@ TEST_F(DamageTrackerTest, DamageWhenAddedExternally) {
// it is included with any other partial damage.
//
ClearDamageForAllSurfaces(root.get());
- child->set_update_rect(gfx::RectF(10, 11, 12, 13));
+ child->SetUpdateRect(gfx::RectF(10, 11, 12, 13));
root->render_surface()->damage_tracker()->AddDamageNextUpdate(
- gfx::RectF(15, 16, 32, 33));
+ gfx::Rect(15, 16, 32, 33));
EmulateDrawingOneFrame(root.get());
- gfx::RectF root_damage_rect =
+ gfx::Rect root_damage_rect =
root->render_surface()->damage_tracker()->current_damage_rect();
- EXPECT_FLOAT_RECT_EQ(
- gfx::UnionRects(gfx::RectF(15, 16, 32, 33),
- gfx::RectF(100+10, 100+11, 12, 13)),
- root_damage_rect);
+ EXPECT_EQ(gfx::UnionRects(gfx::Rect(15, 16, 32, 33),
+ gfx::Rect(100 + 10, 100 + 11, 12, 13)).ToString(),
+ root_damage_rect.ToString());
// Case 2: An additional sanity check that adding damage works even when
// nothing on the layer tree changed.
//
ClearDamageForAllSurfaces(root.get());
root->render_surface()->damage_tracker()->AddDamageNextUpdate(
- gfx::RectF(30, 31, 14, 15));
+ gfx::Rect(30, 31, 14, 15));
EmulateDrawingOneFrame(root.get());
root_damage_rect =
root->render_surface()->damage_tracker()->current_damage_rect();
- EXPECT_FLOAT_RECT_EQ(gfx::RectF(30, 31, 14, 15), root_damage_rect);
+ EXPECT_EQ(gfx::Rect(30, 31, 14, 15).ToString(), root_damage_rect.ToString());
}
TEST_F(DamageTrackerTest, VerifyDamageForEmptyLayerList) {
@@ -1300,8 +1390,8 @@ TEST_F(DamageTrackerTest, VerifyDamageForEmptyLayerList) {
NULL,
FilterOperations());
- gfx::RectF damage_rect =
- target_surface->damage_tracker()->current_damage_rect();
+ gfx::Rect damage_rect =
+ target_surface->damage_tracker()->current_damage_rect();
EXPECT_TRUE(damage_rect.IsEmpty());
}
@@ -1312,21 +1402,22 @@ TEST_F(DamageTrackerTest, VerifyDamageAccumulatesUntilReset) {
LayerImpl* child = root->children()[0];
ClearDamageForAllSurfaces(root.get());
- child->set_update_rect(gfx::RectF(10.f, 11.f, 1.f, 2.f));
+ child->SetUpdateRect(gfx::Rect(10.f, 11.f, 1.f, 2.f));
EmulateDrawingOneFrame(root.get());
// Sanity check damage after the first frame; this isnt the actual test yet.
- gfx::RectF root_damage_rect =
- root->render_surface()->damage_tracker()->current_damage_rect();
- EXPECT_FLOAT_RECT_EQ(gfx::RectF(110.f, 111.f, 1.f, 2.f), root_damage_rect);
+ gfx::Rect root_damage_rect =
+ root->render_surface()->damage_tracker()->current_damage_rect();
+ EXPECT_EQ(gfx::Rect(110, 111, 1, 2).ToString(), root_damage_rect.ToString());
// New damage, without having cleared the previous damage, should be unioned
// to the previous one.
- child->set_update_rect(gfx::RectF(20.f, 25.f, 1.f, 2.f));
+ child->SetUpdateRect(gfx::RectF(20.f, 25.f, 1.f, 2.f));
EmulateDrawingOneFrame(root.get());
root_damage_rect =
root->render_surface()->damage_tracker()->current_damage_rect();
- EXPECT_FLOAT_RECT_EQ(gfx::RectF(110.f, 111.f, 11.f, 16.f), 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.
@@ -1343,5 +1434,37 @@ TEST_F(DamageTrackerTest, VerifyDamageAccumulatesUntilReset) {
EXPECT_TRUE(root_damage_rect.IsEmpty());
}
+TEST_F(DamageTrackerTest, HugeDamageRect) {
+ // This number is so large that we start losting floating point accuracy.
+ const int kBigNumber = 900000000;
+ // Walk over a range to find floating point inaccuracy boundaries that move
+ // toward the wrong direction.
+ const int kRange = 5000;
+
+ for (int i = 0; i < kRange; ++i) {
+ scoped_ptr<LayerImpl> root = CreateTestTreeWithOneSurface();
+ LayerImpl* child = root->children()[0];
+
+ gfx::Transform transform;
+ transform.Translate(-kBigNumber, -kBigNumber);
+
+ // The child layer covers (0, 0, i, i) of the viewport,
+ // but has a huge negative position.
+ child->SetPosition(gfx::PointF());
+ child->SetBounds(gfx::Size(kBigNumber + i, kBigNumber + i));
+ child->SetContentBounds(gfx::Size(kBigNumber + i, kBigNumber + i));
+ child->SetTransform(transform);
+ EmulateDrawingOneFrame(root.get());
+
+ // 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 =
+ root->render_surface()->damage_tracker()->current_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());
+ }
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/trees/layer_sorter.cc b/chromium/cc/trees/layer_sorter.cc
index 73fe3efcb1e..e171fe01120 100644
--- a/chromium/cc/trees/layer_sorter.cc
+++ b/chromium/cc/trees/layer_sorter.cc
@@ -23,16 +23,17 @@ namespace cc {
// the test scene went away.
const float k_layer_epsilon = 1e-4f;
-inline static float PerpProduct(gfx::Vector2dF u, gfx::Vector2dF v) {
+inline static float PerpProduct(const gfx::Vector2dF& u,
+ const gfx::Vector2dF& v) {
return u.x() * v.y() - u.y() * v.x();
}
// Tests if two edges defined by their endpoints (a,b) and (c,d) intersect.
// Returns true and the point of intersection if they do and false otherwise.
-static bool EdgeEdgeTest(gfx::PointF a,
- gfx::PointF b,
- gfx::PointF c,
- gfx::PointF d,
+static bool EdgeEdgeTest(const gfx::PointF& a,
+ const gfx::PointF& b,
+ const gfx::PointF& c,
+ const gfx::PointF& d,
gfx::PointF* r) {
gfx::Vector2dF u = b - a;
gfx::Vector2dF v = d - c;
@@ -242,7 +243,7 @@ LayerShape::~LayerShape() {}
// to point p which lies on the z = 0 plane. It does it by computing the
// intersection of a line starting from p along the Z axis and the plane
// of the layer.
-float LayerShape::LayerZFromProjectedPoint(gfx::PointF p) const {
+float LayerShape::LayerZFromProjectedPoint(const gfx::PointF& p) const {
gfx::Vector3dF z_axis(0.f, 0.f, 1.f);
gfx::Vector3dF w = gfx::Point3F(p) - transform_origin;
diff --git a/chromium/cc/trees/layer_sorter.h b/chromium/cc/trees/layer_sorter.h
index 361a5c85f75..c5aab7ca780 100644
--- a/chromium/cc/trees/layer_sorter.h
+++ b/chromium/cc/trees/layer_sorter.h
@@ -42,7 +42,7 @@ struct CC_EXPORT LayerShape {
LayerShape(float width, float height, const gfx::Transform& draw_transform);
~LayerShape();
- float LayerZFromProjectedPoint(gfx::PointF p) const;
+ float LayerZFromProjectedPoint(const gfx::PointF& p) const;
gfx::Vector3dF layer_normal;
gfx::Point3F transform_origin;
diff --git a/chromium/cc/trees/layer_sorter_unittest.cc b/chromium/cc/trees/layer_sorter_unittest.cc
index 6669100fccf..ba7765bd6fb 100644
--- a/chromium/cc/trees/layer_sorter_unittest.cc
+++ b/chromium/cc/trees/layer_sorter_unittest.cc
@@ -8,6 +8,7 @@
#include "cc/layers/layer_impl.h"
#include "cc/test/fake_impl_proxy.h"
#include "cc/test/fake_layer_tree_host_impl.h"
+#include "cc/test/test_shared_bitmap_manager.h"
#include "cc/trees/single_thread_proxy.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/transform.h"
@@ -210,7 +211,8 @@ TEST(LayerSorterTest, VerifyExistingOrderingPreservedWhenNoZDiff) {
// - 3 and 4 should be re-sorted so they are in front of 1, 2, and 5.
FakeImplProxy proxy;
- FakeLayerTreeHostImpl host_impl(&proxy);
+ TestSharedBitmapManager shared_bitmap_manager;
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
scoped_ptr<LayerImpl> layer1 = LayerImpl::Create(host_impl.active_tree(), 1);
scoped_ptr<LayerImpl> layer2 = LayerImpl::Create(host_impl.active_tree(), 2);
@@ -275,7 +277,8 @@ TEST(LayerSorterTest, VerifyExistingOrderingPreservedWhenNoZDiff) {
TEST(LayerSorterTest, VerifyConcidentLayerPrecisionLossResultsInDocumentOrder) {
FakeImplProxy proxy;
- FakeLayerTreeHostImpl host_impl(&proxy);
+ TestSharedBitmapManager shared_bitmap_manager;
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
scoped_ptr<LayerImpl> layer1 = LayerImpl::Create(host_impl.active_tree(), 1);
scoped_ptr<LayerImpl> layer2 = LayerImpl::Create(host_impl.active_tree(), 2);
diff --git a/chromium/cc/trees/layer_tree_host.cc b/chromium/cc/trees/layer_tree_host.cc
index 74321976ff3..51b9b4f2e33 100644
--- a/chromium/cc/trees/layer_tree_host.cc
+++ b/chromium/cc/trees/layer_tree_host.cc
@@ -20,7 +20,6 @@
#include "cc/animation/layer_animation_controller.h"
#include "cc/base/math_util.h"
#include "cc/debug/devtools_instrumentation.h"
-#include "cc/debug/overdraw_metrics.h"
#include "cc/debug/rendering_stats_instrumentation.h"
#include "cc/input/top_controls_manager.h"
#include "cc/layers/heads_up_display_layer.h"
@@ -47,17 +46,20 @@ static base::StaticAtomicSequenceNumber s_layer_tree_host_sequence_number;
namespace cc {
+RendererCapabilities::RendererCapabilities(ResourceFormat best_texture_format,
+ bool allow_partial_texture_updates,
+ int max_texture_size,
+ bool using_shared_memory_resources)
+ : best_texture_format(best_texture_format),
+ allow_partial_texture_updates(allow_partial_texture_updates),
+ max_texture_size(max_texture_size),
+ using_shared_memory_resources(using_shared_memory_resources) {}
+
RendererCapabilities::RendererCapabilities()
: best_texture_format(RGBA_8888),
- using_partial_swap(false),
- using_egl_image(false),
allow_partial_texture_updates(false),
- using_offscreen_context3d(false),
max_texture_size(0),
- avoid_pow2_textures(false),
- using_map_image(false),
- using_shared_memory_resources(false),
- using_discard_framebuffer(false) {}
+ using_shared_memory_resources(false) {}
RendererCapabilities::~RendererCapabilities() {}
@@ -69,8 +71,7 @@ scoped_ptr<LayerTreeHost> LayerTreeHost::CreateThreaded(
DCHECK(impl_task_runner);
scoped_ptr<LayerTreeHost> layer_tree_host(
new LayerTreeHost(client, manager, settings));
- if (!layer_tree_host->InitializeThreaded(impl_task_runner))
- return scoped_ptr<LayerTreeHost>();
+ layer_tree_host->InitializeThreaded(impl_task_runner);
return layer_tree_host.Pass();
}
@@ -81,25 +82,20 @@ scoped_ptr<LayerTreeHost> LayerTreeHost::CreateSingleThreaded(
const LayerTreeSettings& settings) {
scoped_ptr<LayerTreeHost> layer_tree_host(
new LayerTreeHost(client, manager, settings));
- if (!layer_tree_host->InitializeSingleThreaded(single_thread_client))
- return scoped_ptr<LayerTreeHost>();
+ layer_tree_host->InitializeSingleThreaded(single_thread_client);
return layer_tree_host.Pass();
}
-
-LayerTreeHost::LayerTreeHost(
- LayerTreeHostClient* client,
- SharedBitmapManager* manager,
- const LayerTreeSettings& settings)
+LayerTreeHost::LayerTreeHost(LayerTreeHostClient* client,
+ SharedBitmapManager* manager,
+ const LayerTreeSettings& settings)
: micro_benchmark_controller_(this),
next_ui_resource_id_(1),
animating_(false),
needs_full_tree_sync_(true),
- needs_filter_context_(false),
client_(client),
source_frame_number_(0),
rendering_stats_instrumentation_(RenderingStatsInstrumentation::Create()),
- output_surface_can_be_initialized_(true),
output_surface_lost_(true),
num_failed_recreate_attempts_(0),
settings_(settings),
@@ -110,7 +106,9 @@ LayerTreeHost::LayerTreeHost(
page_scale_factor_(1.f),
min_page_scale_factor_(1.f),
max_page_scale_factor_(1.f),
- trigger_idle_updates_(true),
+ has_gpu_rasterization_trigger_(false),
+ content_is_suitable_for_gpu_rasterization_(true),
+ gpu_rasterization_histogram_recorded_(false),
background_color_(SK_ColorWHITE),
has_transparent_background_(false),
partial_texture_update_requests_(0),
@@ -125,31 +123,25 @@ LayerTreeHost::LayerTreeHost(
debug_state_.RecordRenderingStats());
}
-bool LayerTreeHost::InitializeThreaded(
+void LayerTreeHost::InitializeThreaded(
scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner) {
- return InitializeProxy(ThreadProxy::Create(this, impl_task_runner));
+ InitializeProxy(ThreadProxy::Create(this, impl_task_runner));
}
-bool LayerTreeHost::InitializeSingleThreaded(
+void LayerTreeHost::InitializeSingleThreaded(
LayerTreeHostSingleThreadClient* single_thread_client) {
- return InitializeProxy(
- SingleThreadProxy::Create(this, single_thread_client));
+ InitializeProxy(SingleThreadProxy::Create(this, single_thread_client));
}
-bool LayerTreeHost::InitializeForTesting(scoped_ptr<Proxy> proxy_for_testing) {
- return InitializeProxy(proxy_for_testing.Pass());
+void LayerTreeHost::InitializeForTesting(scoped_ptr<Proxy> proxy_for_testing) {
+ InitializeProxy(proxy_for_testing.Pass());
}
-bool LayerTreeHost::InitializeProxy(scoped_ptr<Proxy> proxy) {
+void LayerTreeHost::InitializeProxy(scoped_ptr<Proxy> proxy) {
TRACE_EVENT0("cc", "LayerTreeHost::InitializeForReal");
- scoped_ptr<OutputSurface> output_surface(CreateOutputSurface());
- if (!output_surface)
- return false;
-
proxy_ = proxy.Pass();
- proxy_->Start(output_surface.Pass());
- return true;
+ proxy_->Start();
}
LayerTreeHost::~LayerTreeHost() {
@@ -165,6 +157,9 @@ LayerTreeHost::~LayerTreeHost() {
proxy_->Stop();
}
+ // We must clear any pointers into the layer tree prior to destroying it.
+ RegisterViewportLayers(NULL, NULL, NULL);
+
if (root_layer_.get()) {
// The layer tree must be destroyed before the layer tree host. We've
// made a contract with our animation controllers that the registrar
@@ -181,50 +176,38 @@ static void LayerTreeHostOnOutputSurfaceCreatedCallback(Layer* layer) {
layer->OnOutputSurfaceCreated();
}
-LayerTreeHost::CreateResult
-LayerTreeHost::OnCreateAndInitializeOutputSurfaceAttempted(bool success) {
+void LayerTreeHost::OnCreateAndInitializeOutputSurfaceAttempted(bool success) {
+ DCHECK(output_surface_lost_);
TRACE_EVENT1("cc",
"LayerTreeHost::OnCreateAndInitializeOutputSurfaceAttempted",
"success",
success);
- DCHECK(output_surface_lost_);
- if (success) {
- output_surface_lost_ = false;
-
- if (!contents_texture_manager_ && !settings_.impl_side_painting) {
- contents_texture_manager_ =
- PrioritizedResourceManager::Create(proxy_.get());
- surface_memory_placeholder_ =
- contents_texture_manager_->CreateTexture(gfx::Size(), RGBA_8888);
- }
-
- if (root_layer()) {
- LayerTreeHostCommon::CallFunctionForSubtree(
- root_layer(),
- base::Bind(&LayerTreeHostOnOutputSurfaceCreatedCallback));
- }
-
- client_->DidInitializeOutputSurface(true);
- return CreateSucceeded;
+ if (!success) {
+ // Tolerate a certain number of recreation failures to work around races
+ // in the output-surface-lost machinery.
+ ++num_failed_recreate_attempts_;
+ if (num_failed_recreate_attempts_ >= 5)
+ LOG(FATAL) << "Failed to create a fallback OutputSurface.";
+ client_->DidFailToInitializeOutputSurface();
+ return;
}
- // Failure path.
+ output_surface_lost_ = false;
- client_->DidFailToInitializeOutputSurface();
+ if (!contents_texture_manager_ && !settings_.impl_side_painting) {
+ contents_texture_manager_ =
+ PrioritizedResourceManager::Create(proxy_.get());
+ surface_memory_placeholder_ =
+ contents_texture_manager_->CreateTexture(gfx::Size(), RGBA_8888);
+ }
- // Tolerate a certain number of recreation failures to work around races
- // in the output-surface-lost machinery.
- ++num_failed_recreate_attempts_;
- if (num_failed_recreate_attempts_ >= 5) {
- // We have tried too many times to recreate the output surface. Tell the
- // host to fall back to software rendering.
- output_surface_can_be_initialized_ = false;
- client_->DidInitializeOutputSurface(false);
- return CreateFailedAndGaveUp;
+ if (root_layer()) {
+ LayerTreeHostCommon::CallFunctionForSubtree(
+ root_layer(), base::Bind(&LayerTreeHostOnOutputSurfaceCreatedCallback));
}
- return CreateFailedButTryAgain;
+ client_->DidInitializeOutputSurface();
}
void LayerTreeHost::DeleteContentsTexturesOnImplThread(
@@ -234,18 +217,13 @@ void LayerTreeHost::DeleteContentsTexturesOnImplThread(
contents_texture_manager_->ClearAllMemory(resource_provider);
}
-void LayerTreeHost::AcquireLayerTextures() {
- DCHECK(proxy_->IsMainThread());
- proxy_->AcquireLayerTextures();
-}
-
void LayerTreeHost::DidBeginMainFrame() {
client_->DidBeginMainFrame();
}
void LayerTreeHost::UpdateClientAnimations(base::TimeTicks frame_begin_time) {
animating_ = true;
- client_->Animate((frame_begin_time - base::TimeTicks()).InSecondsF());
+ client_->Animate(frame_begin_time);
animating_ = false;
}
@@ -293,28 +271,15 @@ void LayerTreeHost::FinishCommitOnImplThread(LayerTreeHostImpl* host_impl) {
contents_texture_manager_->UpdateBackingsState(
host_impl->resource_provider());
- }
-
- // In impl-side painting, synchronize to the pending tree so that it has
- // time to raster before being displayed. If no pending tree is needed,
- // synchronization can happen directly to the active tree and
- // unlinked contents resources can be reclaimed immediately.
- LayerTreeImpl* sync_tree;
- if (settings_.impl_side_painting) {
- // Commits should not occur while there is already a pending tree.
- DCHECK(!host_impl->pending_tree());
- host_impl->CreatePendingTree();
- sync_tree = host_impl->pending_tree();
- if (next_commit_forces_redraw_)
- sync_tree->ForceRedrawNextActivation();
- } else {
- if (next_commit_forces_redraw_)
- host_impl->SetFullRootLayerDamage();
contents_texture_manager_->ReduceMemory(host_impl->resource_provider());
- sync_tree = host_impl->active_tree();
}
- next_commit_forces_redraw_ = false;
+ LayerTreeImpl* sync_tree = host_impl->sync_tree();
+
+ if (next_commit_forces_redraw_) {
+ sync_tree->ForceRedrawNextActivation();
+ next_commit_forces_redraw_ = false;
+ }
sync_tree->set_source_frame_number(source_frame_number());
@@ -340,12 +305,7 @@ void LayerTreeHost::FinishCommitOnImplThread(LayerTreeHostImpl* host_impl) {
sync_tree->set_background_color(background_color_);
sync_tree->set_has_transparent_background(has_transparent_background_);
- sync_tree->FindRootScrollLayer();
-
- // TODO(wjmaclean) For now, not all LTH clients will register viewports, so
- // only set them when available..
- if (page_scale_layer_) {
- DCHECK(inner_viewport_scroll_layer_);
+ if (page_scale_layer_ && inner_viewport_scroll_layer_) {
sync_tree->SetViewportLayersFromIds(
page_scale_layer_->id(),
inner_viewport_scroll_layer_->id(),
@@ -355,27 +315,19 @@ void LayerTreeHost::FinishCommitOnImplThread(LayerTreeHostImpl* host_impl) {
sync_tree->ClearViewportLayers();
}
- float page_scale_delta, sent_page_scale_delta;
- if (settings_.impl_side_painting) {
- // Update the delta from the active tree, which may have
- // adjusted its delta prior to the pending tree being created.
- // This code is equivalent to that in LayerTreeImpl::SetPageScaleDelta.
- DCHECK_EQ(1.f, sync_tree->sent_page_scale_delta());
- page_scale_delta = host_impl->active_tree()->page_scale_delta();
- sent_page_scale_delta = host_impl->active_tree()->sent_page_scale_delta();
- } else {
- page_scale_delta = sync_tree->page_scale_delta();
- sent_page_scale_delta = sync_tree->sent_page_scale_delta();
- sync_tree->set_sent_page_scale_delta(1.f);
- }
-
- sync_tree->SetPageScaleFactorAndLimits(page_scale_factor_,
- min_page_scale_factor_,
- max_page_scale_factor_);
- sync_tree->SetPageScaleDelta(page_scale_delta / sent_page_scale_delta);
+ float page_scale_delta =
+ sync_tree->page_scale_delta() / sync_tree->sent_page_scale_delta();
+ sync_tree->SetPageScaleValues(page_scale_factor_,
+ min_page_scale_factor_,
+ max_page_scale_factor_,
+ page_scale_delta);
+ sync_tree->set_sent_page_scale_delta(1.f);
sync_tree->PassSwapPromises(&swap_promise_list_);
+ host_impl->SetUseGpuRasterization(UseGpuRasterization());
+ RecordGpuRasterizationHistogram();
+
host_impl->SetViewportSize(device_viewport_size_);
host_impl->SetOverdrawBottomHeight(overdraw_bottom_height_);
host_impl->SetDeviceScaleFactor(device_scale_factor_);
@@ -392,10 +344,6 @@ void LayerTreeHost::FinishCommitOnImplThread(LayerTreeHostImpl* host_impl) {
if (!ui_resource_request_queue_.empty()) {
sync_tree->set_ui_resource_request_queue(ui_resource_request_queue_);
ui_resource_request_queue_.clear();
- // Process any ui resource requests in the queue. For impl-side-painting,
- // the queue is processed in LayerTreeHostImpl::ActivatePendingTree.
- if (!settings_.impl_side_painting)
- sync_tree->ProcessUIResourceRequestQueue();
}
if (overhang_ui_resource_) {
host_impl->SetOverhangUIResource(
@@ -410,16 +358,7 @@ void LayerTreeHost::FinishCommitOnImplThread(LayerTreeHostImpl* host_impl) {
sync_tree->ResetContentsTexturesPurged();
}
- if (!settings_.impl_side_painting) {
- // If we're not in impl-side painting, the tree is immediately
- // considered active.
- sync_tree->DidBecomeActive();
- devtools_instrumentation::didActivateLayerTree(id_, source_frame_number_);
- }
-
micro_benchmark_controller_.ScheduleImplBenchmarks(host_impl);
-
- source_frame_number_++;
}
void LayerTreeHost::WillCommit() {
@@ -440,6 +379,7 @@ void LayerTreeHost::UpdateHudLayer() {
}
void LayerTreeHost::CommitComplete() {
+ source_frame_number_++;
client_->DidCommit();
}
@@ -457,6 +397,7 @@ scoped_ptr<LayerTreeHostImpl> LayerTreeHost::CreateLayerTreeHostImpl(
rendering_stats_instrumentation_.get(),
shared_bitmap_manager_,
id_);
+ host_impl->SetUseGpuRasterization(UseGpuRasterization());
shared_bitmap_manager_ = NULL;
if (settings_.calculate_top_controls_position &&
host_impl->top_controls_manager()) {
@@ -479,14 +420,6 @@ void LayerTreeHost::DidLoseOutputSurface() {
SetNeedsCommit();
}
-bool LayerTreeHost::CompositeAndReadback(void* pixels,
- gfx::Rect rect_in_device_viewport) {
- trigger_idle_updates_ = false;
- bool ret = proxy_->CompositeAndReadback(pixels, rect_in_device_viewport);
- trigger_idle_updates_ = true;
- return ret;
-}
-
void LayerTreeHost::FinishAllRendering() {
proxy_->FinishAllRendering();
}
@@ -510,11 +443,6 @@ void LayerTreeHost::SetNeedsDisplayOnAllLayers() {
}
}
-void LayerTreeHost::CollectRenderingStats(RenderingStats* stats) const {
- CHECK(debug_state_.RecordRenderingStats());
- *stats = rendering_stats_instrumentation_->GetRenderingStats();
-}
-
const RendererCapabilities& LayerTreeHost::GetRendererCapabilities() const {
return proxy_->GetRendererCapabilities();
}
@@ -549,7 +477,7 @@ void LayerTreeHost::SetNeedsRedraw() {
SetNeedsRedrawRect(gfx::Rect(device_viewport_size_));
}
-void LayerTreeHost::SetNeedsRedrawRect(gfx::Rect damage_rect) {
+void LayerTreeHost::SetNeedsRedrawRect(const gfx::Rect& damage_rect) {
proxy_->SetNeedsRedraw(damage_rect);
}
@@ -570,8 +498,8 @@ void LayerTreeHost::SetNextCommitForcesRedraw() {
next_commit_forces_redraw_ = true;
}
-void LayerTreeHost::SetAnimationEvents(scoped_ptr<AnimationEventsVector> events,
- base::Time wall_clock_time) {
+void LayerTreeHost::SetAnimationEvents(
+ scoped_ptr<AnimationEventsVector> events) {
DCHECK(proxy_->IsMainThread());
for (size_t event_index = 0; event_index < events->size(); ++event_index) {
int event_layer_id = (*events)[event_index].layer_id;
@@ -585,13 +513,11 @@ void LayerTreeHost::SetAnimationEvents(scoped_ptr<AnimationEventsVector> events,
if (iter != animation_controllers.end()) {
switch ((*events)[event_index].type) {
case AnimationEvent::Started:
- (*iter).second->NotifyAnimationStarted((*events)[event_index],
- wall_clock_time.ToDoubleT());
+ (*iter).second->NotifyAnimationStarted((*events)[event_index]);
break;
case AnimationEvent::Finished:
- (*iter).second->NotifyAnimationFinished((*events)[event_index],
- wall_clock_time.ToDoubleT());
+ (*iter).second->NotifyAnimationFinished((*events)[event_index]);
break;
case AnimationEvent::Aborted:
@@ -621,6 +547,11 @@ void LayerTreeHost::SetRootLayer(scoped_refptr<Layer> root_layer) {
if (hud_layer_.get())
hud_layer_->RemoveFromParent();
+ // Reset gpu rasterization flag.
+ // This flag is sticky until a new tree comes along.
+ content_is_suitable_for_gpu_rasterization_ = true;
+ gpu_rasterization_histogram_recorded_ = false;
+
SetNeedsFullTreeSync();
}
@@ -637,9 +568,33 @@ void LayerTreeHost::SetDebugState(const LayerTreeDebugState& debug_state) {
debug_state_.RecordRenderingStats());
SetNeedsCommit();
+ proxy_->SetDebugState(debug_state);
}
-void LayerTreeHost::SetViewportSize(gfx::Size device_viewport_size) {
+bool LayerTreeHost::UseGpuRasterization() const {
+ if (settings_.gpu_rasterization_forced) {
+ return true;
+ } else if (settings_.gpu_rasterization_enabled) {
+ return has_gpu_rasterization_trigger_ &&
+ content_is_suitable_for_gpu_rasterization_;
+ } else {
+ return false;
+ }
+}
+
+void LayerTreeHost::SetHasGpuRasterizationTrigger(bool has_trigger) {
+ if (has_trigger == has_gpu_rasterization_trigger_)
+ return;
+
+ has_gpu_rasterization_trigger_ = has_trigger;
+ TRACE_EVENT_INSTANT1("cc",
+ "LayerTreeHost::SetHasGpuRasterizationTrigger",
+ TRACE_EVENT_SCOPE_THREAD,
+ "has_trigger",
+ has_gpu_rasterization_trigger_);
+}
+
+void LayerTreeHost::SetViewportSize(const gfx::Size& device_viewport_size) {
if (device_viewport_size == device_viewport_size_)
return;
@@ -683,7 +638,7 @@ void LayerTreeHost::SetOverhangBitmap(const SkBitmap& bitmap) {
if (bitmap.isImmutable()) {
bitmap_copy = bitmap;
} else {
- bitmap.copyTo(&bitmap_copy, bitmap.config());
+ bitmap.copyTo(&bitmap_copy);
bitmap_copy.setImmutable();
}
@@ -701,7 +656,7 @@ void LayerTreeHost::SetVisible(bool visible) {
proxy_->SetVisible(visible);
}
-void LayerTreeHost::StartPageScaleAnimation(gfx::Vector2d target_offset,
+void LayerTreeHost::StartPageScaleAnimation(const gfx::Vector2d& target_offset,
bool use_anchor,
float scale,
base::TimeDelta duration) {
@@ -719,20 +674,15 @@ void LayerTreeHost::NotifyInputThrottledUntilCommit() {
}
void LayerTreeHost::Composite(base::TimeTicks frame_begin_time) {
- if (!proxy_->HasImplThread())
- static_cast<SingleThreadProxy*>(proxy_.get())->CompositeImmediately(
- frame_begin_time);
- else
- SetNeedsCommit();
-}
-
-bool LayerTreeHost::InitializeOutputSurfaceIfNeeded() {
- if (!output_surface_can_be_initialized_)
- return false;
+ DCHECK(!proxy_->HasImplThread());
+ SingleThreadProxy* proxy = static_cast<SingleThreadProxy*>(proxy_.get());
if (output_surface_lost_)
- proxy_->CreateAndInitializeOutputSurface();
- return !output_surface_lost_;
+ proxy->CreateAndInitializeOutputSurface();
+ if (output_surface_lost_)
+ return;
+
+ proxy->CompositeImmediately(frame_begin_time);
}
bool LayerTreeHost::UpdateLayers(ResourceUpdateQueue* queue) {
@@ -747,7 +697,7 @@ bool LayerTreeHost::UpdateLayers(ResourceUpdateQueue* queue) {
micro_benchmark_controller_.DidUpdateLayers();
- return result;
+ return result || next_commit_forces_redraw_;
}
static Layer* FindFirstScrollableLayer(Layer* layer) {
@@ -766,6 +716,31 @@ static Layer* FindFirstScrollableLayer(Layer* layer) {
return NULL;
}
+void LayerTreeHost::RecordGpuRasterizationHistogram() {
+ // Gpu rasterization is only supported when impl-side painting is enabled.
+ if (gpu_rasterization_histogram_recorded_ || !settings_.impl_side_painting)
+ return;
+
+ // Record how widely gpu rasterization is enabled.
+ // This number takes device/gpu whitelisting/backlisting into account.
+ // Note that we do not consider the forced gpu rasterization mode, which is
+ // mostly used for debugging purposes.
+ UMA_HISTOGRAM_BOOLEAN("Renderer4.GpuRasterizationEnabled",
+ settings_.gpu_rasterization_enabled);
+ if (settings_.gpu_rasterization_enabled) {
+ UMA_HISTOGRAM_BOOLEAN("Renderer4.GpuRasterizationTriggered",
+ has_gpu_rasterization_trigger_);
+ UMA_HISTOGRAM_BOOLEAN("Renderer4.GpuRasterizationSuitableContent",
+ content_is_suitable_for_gpu_rasterization_);
+ // Record how many pages actually get gpu rasterization when enabled.
+ UMA_HISTOGRAM_BOOLEAN("Renderer4.GpuRasterizationUsed",
+ (has_gpu_rasterization_trigger_ &&
+ content_is_suitable_for_gpu_rasterization_));
+ }
+
+ gpu_rasterization_histogram_recorded_ = true;
+}
+
void LayerTreeHost::CalculateLCDTextMetricsCallback(Layer* layer) {
if (!layer->SupportsLCDText())
return;
@@ -803,6 +778,10 @@ bool LayerTreeHost::UpdateLayers(Layer* root_layer,
TRACE_EVENT0("cc", "LayerTreeHost::UpdateLayers::CalcDrawProps");
bool can_render_to_separate_surface = true;
+ // TODO(vmpstr): Passing 0 as the current render surface layer list id means
+ // that we won't be able to detect if a layer is part of |update_list|.
+ // Change this if this information is required.
+ int render_surface_layer_list_id = 0;
LayerTreeHostCommon::CalcDrawPropsMainInputs inputs(
root_layer,
device_viewport_size(),
@@ -814,7 +793,8 @@ bool LayerTreeHost::UpdateLayers(Layer* root_layer,
settings_.can_use_lcd_text,
can_render_to_separate_surface,
settings_.layer_transforms_should_scale_layer_contents,
- &update_list);
+ &update_list,
+ render_surface_layer_list_id);
LayerTreeHostCommon::CalculateDrawProperties(&inputs);
if (total_frames_used_for_lcd_text_metrics_ <=
@@ -848,7 +828,7 @@ bool LayerTreeHost::UpdateLayers(Layer* root_layer,
bool need_more_updates = false;
PaintLayerContents(
update_list, queue, &did_paint_content, &need_more_updates);
- if (trigger_idle_updates_ && need_more_updates) {
+ if (need_more_updates) {
TRACE_EVENT0("cc", "LayerTreeHost::UpdateLayers::posting prepaint task");
prepaint_callback_.Reset(base::Bind(&LayerTreeHost::TriggerPrepaint,
base::Unretained(this)));
@@ -895,12 +875,8 @@ void LayerTreeHost::SetPrioritiesForSurfaces(size_t surface_memory_bytes) {
void LayerTreeHost::SetPrioritiesForLayers(
const RenderSurfaceLayerList& update_list) {
- typedef LayerIterator<Layer,
- RenderSurfaceLayerList,
- RenderSurface,
- LayerIteratorActions::FrontToBack> LayerIteratorType;
-
PriorityCalculator calculator;
+ typedef LayerIterator<Layer> LayerIteratorType;
LayerIteratorType end = LayerIteratorType::End(&update_list);
for (LayerIteratorType it = LayerIteratorType::Begin(&update_list);
it != end;
@@ -917,8 +893,7 @@ void LayerTreeHost::SetPrioritiesForLayers(
}
void LayerTreeHost::PrioritizeTextures(
- const RenderSurfaceLayerList& render_surface_layer_list,
- OverdrawMetrics* metrics) {
+ const RenderSurfaceLayerList& render_surface_layer_list) {
if (!contents_texture_manager_)
return;
@@ -930,11 +905,6 @@ void LayerTreeHost::PrioritizeTextures(
SetPrioritiesForLayers(render_surface_layer_list);
SetPrioritiesForSurfaces(memory_for_render_surfaces_metric);
- metrics->DidUseContentsTextureMemoryBytes(
- contents_texture_manager_->MemoryAboveCutoffBytes());
- metrics->DidUseRenderSurfaceTextureMemoryBytes(
- memory_for_render_surfaces_metric);
-
contents_texture_manager_->PrioritizeTextures();
}
@@ -997,27 +967,18 @@ void LayerTreeHost::PaintLayerContents(
ResourceUpdateQueue* queue,
bool* did_paint_content,
bool* need_more_updates) {
- // Use FrontToBack to allow for testing occlusion and performing culling
- // during the tree walk.
- typedef LayerIterator<Layer,
- RenderSurfaceLayerList,
- RenderSurface,
- LayerIteratorActions::FrontToBack> LayerIteratorType;
-
- bool record_metrics_for_frame =
- settings_.show_overdraw_in_tracing &&
- base::debug::TraceLog::GetInstance() &&
- base::debug::TraceLog::GetInstance()->IsEnabled();
- OcclusionTracker occlusion_tracker(
- root_layer_->render_surface()->content_rect(), record_metrics_for_frame);
+ OcclusionTracker<Layer> occlusion_tracker(
+ root_layer_->render_surface()->content_rect());
occlusion_tracker.set_minimum_tracking_size(
settings_.minimum_occlusion_tracking_size);
- PrioritizeTextures(render_surface_layer_list,
- occlusion_tracker.overdraw_metrics());
+ PrioritizeTextures(render_surface_layer_list);
in_paint_layer_contents_ = true;
+ // Iterates front-to-back to allow for testing occlusion and performing
+ // culling during the tree walk.
+ typedef LayerIterator<Layer> LayerIteratorType;
LayerIteratorType end = LayerIteratorType::End(&render_surface_layer_list);
for (LayerIteratorType it =
LayerIteratorType::Begin(&render_surface_layer_list);
@@ -1028,26 +989,33 @@ void LayerTreeHost::PaintLayerContents(
if (it.represents_target_render_surface()) {
PaintMasksForRenderSurface(
*it, queue, did_paint_content, need_more_updates);
- } else if (it.represents_itself() && it->DrawsContent()) {
+ } else if (it.represents_itself()) {
DCHECK(!it->paint_properties().bounds.IsEmpty());
*did_paint_content |= it->Update(queue, &occlusion_tracker);
*need_more_updates |= it->NeedMoreUpdates();
+ // Note the '&&' with previous is-suitable state.
+ // This means that once the layer-tree becomes unsuitable for gpu
+ // rasterization due to some content, it will continue to be unsuitable
+ // even if that content is replaced by gpu-friendly content.
+ // This is to avoid switching back-and-forth between gpu and sw
+ // rasterization which may be both bad for performance and visually
+ // jarring.
+ content_is_suitable_for_gpu_rasterization_ &=
+ it->IsSuitableForGpuRasterization();
}
occlusion_tracker.LeaveLayer(it);
}
in_paint_layer_contents_ = false;
-
- occlusion_tracker.overdraw_metrics()->RecordMetrics(this);
}
void LayerTreeHost::ApplyScrollAndScale(const ScrollAndScaleSet& info) {
if (!root_layer_.get())
return;
- gfx::Vector2d root_scroll_delta;
- Layer* root_scroll_layer = FindFirstScrollableLayer(root_layer_.get());
+ gfx::Vector2d inner_viewport_scroll_delta;
+ gfx::Vector2d outer_viewport_scroll_delta;
for (size_t i = 0; i < info.scrolls.size(); ++i) {
Layer* layer =
@@ -1055,28 +1023,39 @@ void LayerTreeHost::ApplyScrollAndScale(const ScrollAndScaleSet& info) {
info.scrolls[i].layer_id);
if (!layer)
continue;
- if (layer == root_scroll_layer) {
- root_scroll_delta += info.scrolls[i].scroll_delta;
+ if (layer == outer_viewport_scroll_layer_.get()) {
+ outer_viewport_scroll_delta += info.scrolls[i].scroll_delta;
+ } else if (layer == inner_viewport_scroll_layer_.get()) {
+ inner_viewport_scroll_delta += info.scrolls[i].scroll_delta;
} else {
layer->SetScrollOffsetFromImplSide(layer->scroll_offset() +
info.scrolls[i].scroll_delta);
}
}
- if (!root_scroll_delta.IsZero() || info.page_scale_delta != 1.f) {
+ if (!inner_viewport_scroll_delta.IsZero() ||
+ !outer_viewport_scroll_delta.IsZero() || info.page_scale_delta != 1.f) {
// SetScrollOffsetFromImplSide above could have destroyed the tree,
// so re-get this layer before doing anything to it.
- root_scroll_layer = FindFirstScrollableLayer(root_layer_.get());
// 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 (root_scroll_layer) {
- root_scroll_layer->SetScrollOffsetFromImplSide(
- root_scroll_layer->scroll_offset() + root_scroll_delta);
+ DCHECK(inner_viewport_scroll_layer_); // We should always have this.
+
+ inner_viewport_scroll_layer_->SetScrollOffsetFromImplSide(
+ inner_viewport_scroll_layer_->scroll_offset() +
+ inner_viewport_scroll_delta);
+ if (outer_viewport_scroll_layer_) {
+ outer_viewport_scroll_layer_->SetScrollOffsetFromImplSide(
+ outer_viewport_scroll_layer_->scroll_offset() +
+ outer_viewport_scroll_delta);
}
ApplyPageScaleDeltaFromImplSide(info.page_scale_delta);
- client_->ApplyScrollAndScale(root_scroll_delta, info.page_scale_delta);
+
+ client_->ApplyScrollAndScale(
+ inner_viewport_scroll_delta + outer_viewport_scroll_delta,
+ info.page_scale_delta);
}
}
@@ -1159,15 +1138,13 @@ scoped_ptr<base::Value> LayerTreeHost::AsValue() const {
return state.PassAs<base::Value>();
}
-void LayerTreeHost::AnimateLayers(base::TimeTicks time) {
+void LayerTreeHost::AnimateLayers(base::TimeTicks monotonic_time) {
if (!settings_.accelerated_animation_enabled ||
animation_registrar_->active_animation_controllers().empty())
return;
TRACE_EVENT0("cc", "LayerTreeHost::AnimateLayers");
- double monotonic_time = (time - base::TimeTicks()).InSecondsF();
-
AnimationRegistrar::AnimationControllerMap copy =
animation_registrar_->active_animation_controllers();
for (AnimationRegistrar::AnimationControllerMap::iterator iter = copy.begin();
@@ -1244,7 +1221,7 @@ void LayerTreeHost::RegisterViewportLayers(
outer_viewport_scroll_layer_ = outer_viewport_scroll_layer;
}
-bool LayerTreeHost::ScheduleMicroBenchmark(
+int LayerTreeHost::ScheduleMicroBenchmark(
const std::string& benchmark_name,
scoped_ptr<base::Value> value,
const MicroBenchmark::DoneCallback& callback) {
@@ -1252,6 +1229,11 @@ bool LayerTreeHost::ScheduleMicroBenchmark(
benchmark_name, value.Pass(), callback);
}
+bool LayerTreeHost::SendMessageToMicroBenchmark(int id,
+ scoped_ptr<base::Value> value) {
+ return micro_benchmark_controller_.SendMessage(id, value.Pass());
+}
+
void LayerTreeHost::InsertSwapPromiseMonitor(SwapPromiseMonitor* monitor) {
swap_promise_monitor_.insert(monitor);
}
diff --git a/chromium/cc/trees/layer_tree_host.h b/chromium/cc/trees/layer_tree_host.h
index 8b9c1cf3226..ef6e74fabe0 100644
--- a/chromium/cc/trees/layer_tree_host.h
+++ b/chromium/cc/trees/layer_tree_host.h
@@ -36,7 +36,6 @@
#include "cc/trees/layer_tree_host_client.h"
#include "cc/trees/layer_tree_host_common.h"
#include "cc/trees/layer_tree_settings.h"
-#include "cc/trees/occlusion_tracker.h"
#include "cc/trees/proxy.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/rect.h"
@@ -64,19 +63,19 @@ struct ScrollAndScaleSet;
// Provides information on an Impl's rendering capabilities back to the
// LayerTreeHost.
struct CC_EXPORT RendererCapabilities {
+ RendererCapabilities(ResourceFormat best_texture_format,
+ bool allow_partial_texture_updates,
+ int max_texture_size,
+ bool using_shared_memory_resources);
+
RendererCapabilities();
~RendererCapabilities();
+ // Duplicate any modification to this list to RendererCapabilitiesImpl.
ResourceFormat best_texture_format;
- bool using_partial_swap;
- bool using_egl_image;
bool allow_partial_texture_updates;
- bool using_offscreen_context3d;
int max_texture_size;
- bool avoid_pow2_textures;
- bool using_map_image;
bool using_shared_memory_resources;
- bool using_discard_framebuffer;
};
class CC_EXPORT LayerTreeHost {
@@ -97,11 +96,6 @@ class CC_EXPORT LayerTreeHost {
void SetLayerTreeHostClientReady();
- void set_needs_filter_context() { needs_filter_context_ = true; }
- bool needs_offscreen_context() const {
- return needs_filter_context_;
- }
-
// LayerTreeHost interface to Proxy.
void WillBeginMainFrame() {
client_->WillBeginMainFrame(source_frame_number_);
@@ -120,18 +114,10 @@ class CC_EXPORT LayerTreeHost {
LayerTreeHostImplClient* client);
void DidLoseOutputSurface();
bool output_surface_lost() const { return output_surface_lost_; }
- enum CreateResult {
- CreateSucceeded,
- CreateFailedButTryAgain,
- CreateFailedAndGaveUp,
- };
- CreateResult OnCreateAndInitializeOutputSurfaceAttempted(bool success);
+ virtual void OnCreateAndInitializeOutputSurfaceAttempted(bool success);
void DidCommitAndDrawFrame() { client_->DidCommitAndDrawFrame(); }
void DidCompleteSwapBuffers() { client_->DidCompleteSwapBuffers(); }
void DeleteContentsTexturesOnImplThread(ResourceProvider* resource_provider);
- virtual void AcquireLayerTextures();
- // Returns false if we should abort this frame due to initialization failure.
- bool InitializeOutputSurfaceIfNeeded();
bool UpdateLayers(ResourceUpdateQueue* queue);
LayerTreeHostClient* client() { return client_; }
@@ -143,11 +129,6 @@ class CC_EXPORT LayerTreeHost {
void Composite(base::TimeTicks frame_begin_time);
- // Composites and attempts to read back the result into the provided
- // buffer. If it wasn't possible, e.g. due to context lost, will return
- // false.
- bool CompositeAndReadback(void* pixels, gfx::Rect rect_in_device_viewport);
-
void FinishAllRendering();
void SetDeferCommits(bool defer_commits);
@@ -172,7 +153,7 @@ class CC_EXPORT LayerTreeHost {
virtual void SetNeedsCommit();
virtual void SetNeedsFullTreeSync();
void SetNeedsRedraw();
- void SetNeedsRedrawRect(gfx::Rect damage_rect);
+ void SetNeedsRedrawRect(const gfx::Rect& damage_rect);
bool CommitRequested() const;
bool BeginMainFrameRequested() const;
@@ -180,8 +161,7 @@ class CC_EXPORT LayerTreeHost {
void SetNextCommitForcesRedraw();
- void SetAnimationEvents(scoped_ptr<AnimationEventsVector> events,
- base::Time wall_clock_time);
+ void SetAnimationEvents(scoped_ptr<AnimationEventsVector> events);
void SetRootLayer(scoped_refptr<Layer> root_layer);
Layer* root_layer() { return root_layer_.get(); }
@@ -191,13 +171,25 @@ class CC_EXPORT LayerTreeHost {
scoped_refptr<Layer> page_scale_layer,
scoped_refptr<Layer> inner_viewport_scroll_layer,
scoped_refptr<Layer> outer_viewport_scroll_layer);
+ Layer* inner_viewport_scroll_layer() const {
+ return inner_viewport_scroll_layer_.get();
+ }
+ Layer* outer_viewport_scroll_layer() const {
+ return outer_viewport_scroll_layer_.get();
+ }
const LayerTreeSettings& settings() const { return settings_; }
void SetDebugState(const LayerTreeDebugState& debug_state);
const LayerTreeDebugState& debug_state() const { return debug_state_; }
- void SetViewportSize(gfx::Size device_viewport_size);
+ bool has_gpu_rasterization_trigger() const {
+ return has_gpu_rasterization_trigger_;
+ }
+ void SetHasGpuRasterizationTrigger(bool has_trigger);
+ bool UseGpuRasterization() const;
+
+ void SetViewportSize(const gfx::Size& device_viewport_size);
void SetOverdrawBottomHeight(float overdraw_bottom_height);
gfx::Size device_viewport_size() const { return device_viewport_size_; }
@@ -225,13 +217,12 @@ class CC_EXPORT LayerTreeHost {
void SetVisible(bool visible);
bool visible() const { return visible_; }
- void StartPageScaleAnimation(gfx::Vector2d target_offset,
+ void StartPageScaleAnimation(const gfx::Vector2d& target_offset,
bool use_anchor,
float scale,
base::TimeDelta duration);
void ApplyScrollAndScale(const ScrollAndScaleSet& info);
-
void SetImplTransform(const gfx::Transform& transform);
// Virtual for tests.
@@ -282,9 +273,12 @@ class CC_EXPORT LayerTreeHost {
bool UsingSharedMemoryResources();
int id() const { return id_; }
- bool ScheduleMicroBenchmark(const std::string& benchmark_name,
- scoped_ptr<base::Value> value,
- const MicroBenchmark::DoneCallback& callback);
+ // Returns the id of the benchmark on success, 0 otherwise.
+ int ScheduleMicroBenchmark(const std::string& benchmark_name,
+ scoped_ptr<base::Value> value,
+ const MicroBenchmark::DoneCallback& callback);
+ // Returns true if the message was successfully delivered and handled.
+ bool SendMessageToMicroBenchmark(int id, scoped_ptr<base::Value> value);
// When a SwapPromiseMonitor is created on the main thread, it calls
// InsertSwapPromiseMonitor() to register itself with LayerTreeHost.
@@ -303,11 +297,11 @@ class CC_EXPORT LayerTreeHost {
LayerTreeHost(LayerTreeHostClient* client,
SharedBitmapManager* manager,
const LayerTreeSettings& settings);
- bool InitializeThreaded(
+ void InitializeThreaded(
scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner);
- bool InitializeSingleThreaded(
+ void InitializeSingleThreaded(
LayerTreeHostSingleThreadClient* single_thread_client);
- bool InitializeForTesting(scoped_ptr<Proxy> proxy_for_testing);
+ void InitializeForTesting(scoped_ptr<Proxy> proxy_for_testing);
void SetOutputSurfaceLostForTesting(bool is_lost) {
output_surface_lost_ = is_lost;
}
@@ -315,7 +309,7 @@ class CC_EXPORT LayerTreeHost {
MicroBenchmarkController micro_benchmark_controller_;
private:
- bool InitializeProxy(scoped_ptr<Proxy> proxy);
+ void InitializeProxy(scoped_ptr<Proxy> proxy);
void PaintLayerContents(
const RenderSurfaceLayerList& render_surface_layer_list,
@@ -333,8 +327,7 @@ class CC_EXPORT LayerTreeHost {
void ReduceMemoryUsage();
void PrioritizeTextures(
- const RenderSurfaceLayerList& render_surface_layer_list,
- OverdrawMetrics* metrics);
+ const RenderSurfaceLayerList& render_surface_layer_list);
void SetPrioritiesForSurfaces(size_t surface_memory_bytes);
void SetPrioritiesForLayers(const RenderSurfaceLayerList& update_list);
size_t CalculateMemoryForRenderSurfaces(
@@ -355,13 +348,13 @@ class CC_EXPORT LayerTreeHost {
typedef std::list<UIResourceRequest> UIResourceRequestQueue;
UIResourceRequestQueue ui_resource_request_queue_;
+ void RecordGpuRasterizationHistogram();
void CalculateLCDTextMetricsCallback(Layer* layer);
void NotifySwapPromiseMonitorsOfSetNeedsCommit();
bool animating_;
bool needs_full_tree_sync_;
- bool needs_filter_context_;
base::CancelableClosure prepaint_callback_;
@@ -371,7 +364,6 @@ class CC_EXPORT LayerTreeHost {
int source_frame_number_;
scoped_ptr<RenderingStatsInstrumentation> rendering_stats_instrumentation_;
- bool output_surface_can_be_initialized_;
bool output_surface_lost_;
int num_failed_recreate_attempts_;
@@ -400,6 +392,9 @@ class CC_EXPORT LayerTreeHost {
float max_page_scale_factor_;
gfx::Transform impl_transform_;
bool trigger_idle_updates_;
+ bool has_gpu_rasterization_trigger_;
+ bool content_is_suitable_for_gpu_rasterization_;
+ bool gpu_rasterization_histogram_recorded_;
SkColor background_color_;
bool has_transparent_background_;
diff --git a/chromium/cc/trees/layer_tree_host_client.h b/chromium/cc/trees/layer_tree_host_client.h
index 2e3023a7f79..74dcbc0cff2 100644
--- a/chromium/cc/trees/layer_tree_host_client.h
+++ b/chromium/cc/trees/layer_tree_host_client.h
@@ -7,6 +7,7 @@
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
namespace gfx {
class Vector2d;
@@ -23,24 +24,19 @@ class LayerTreeHostClient {
// Marks finishing compositing-related tasks on the main thread. In threaded
// mode, this corresponds to DidCommit().
virtual void DidBeginMainFrame() = 0;
- virtual void Animate(double frame_begin_time) = 0;
+ virtual void Animate(base::TimeTicks frame_begin_time) = 0;
virtual void Layout() = 0;
- virtual void ApplyScrollAndScale(gfx::Vector2d scroll_delta,
+ virtual void ApplyScrollAndScale(const gfx::Vector2d& scroll_delta,
float page_scale) = 0;
// Creates an OutputSurface. If fallback is true, it should attempt to
// create an OutputSurface that is guaranteed to initialize correctly.
virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback) = 0;
- virtual void DidInitializeOutputSurface(bool success) = 0;
+ virtual void DidInitializeOutputSurface() = 0;
virtual void WillCommit() = 0;
virtual void DidCommit() = 0;
virtual void DidCommitAndDrawFrame() = 0;
virtual void DidCompleteSwapBuffers() = 0;
- // If the client provides an OutputSurface bound to a 3d context for direct
- // rendering, this must return a provider that provides contexts usable from
- // the same thread as the OutputSurface's context.
- virtual scoped_refptr<ContextProvider> OffscreenContextProvider() = 0;
-
// Requests that the client insert a rate limiting token in the shared main
// thread context's command stream that will block if the context gets too far
// ahead of the compositor's command stream. Only needed if the tree contains
diff --git a/chromium/cc/trees/layer_tree_host_common.cc b/chromium/cc/trees/layer_tree_host_common.cc
index 33236cf52e4..3bbbf6340b6 100644
--- a/chromium/cc/trees/layer_tree_host_common.cc
+++ b/chromium/cc/trees/layer_tree_host_common.cc
@@ -16,7 +16,6 @@
#include "cc/layers/render_surface_impl.h"
#include "cc/trees/layer_sorter.h"
#include "cc/trees/layer_tree_impl.h"
-#include "ui/gfx/point_conversions.h"
#include "ui/gfx/rect_conversions.h"
#include "ui/gfx/transform.h"
@@ -64,9 +63,9 @@ static gfx::Vector2dF GetEffectiveTotalScrollOffset(LayerType* layer) {
}
inline gfx::Rect CalculateVisibleRectWithCachedLayerRect(
- gfx::Rect target_surface_rect,
- gfx::Rect layer_bound_rect,
- gfx::Rect layer_rect_in_target_space,
+ const gfx::Rect& target_surface_rect,
+ const gfx::Rect& layer_bound_rect,
+ const gfx::Rect& layer_rect_in_target_space,
const gfx::Transform& transform) {
if (layer_rect_in_target_space.IsEmpty())
return gfx::Rect();
@@ -82,7 +81,7 @@ inline gfx::Rect CalculateVisibleRectWithCachedLayerRect(
minimal_surface_rect.Intersect(layer_rect_in_target_space);
if (minimal_surface_rect.IsEmpty())
- return gfx::Rect();
+ return gfx::Rect();
// Project the corners of the target surface rect into the layer space.
// This bounding rectangle may be larger than it needs to be (being
@@ -97,18 +96,18 @@ inline gfx::Rect CalculateVisibleRectWithCachedLayerRect(
return layer_bound_rect;
}
- gfx::Rect layer_rect = gfx::ToEnclosingRect(MathUtil::ProjectClippedRect(
- surface_to_layer, gfx::RectF(minimal_surface_rect)));
+ gfx::Rect layer_rect = MathUtil::ProjectEnclosingClippedRect(
+ surface_to_layer, minimal_surface_rect);
layer_rect.Intersect(layer_bound_rect);
return layer_rect;
}
gfx::Rect LayerTreeHostCommon::CalculateVisibleRect(
- gfx::Rect target_surface_rect,
- gfx::Rect layer_bound_rect,
+ const gfx::Rect& target_surface_rect,
+ const gfx::Rect& layer_bound_rect,
const gfx::Transform& transform) {
gfx::Rect layer_in_surface_space =
- MathUtil::MapClippedRect(transform, layer_bound_rect);
+ MathUtil::MapEnclosingClippedRect(transform, layer_bound_rect);
return CalculateVisibleRectWithCachedLayerRect(
target_surface_rect, layer_bound_rect, layer_in_surface_space, transform);
}
@@ -154,7 +153,7 @@ enum TranslateRectDirection {
template <typename LayerType>
static gfx::Rect TranslateRectToTargetSpace(const LayerType& ancestor_layer,
const LayerType& descendant_layer,
- gfx::Rect rect,
+ const gfx::Rect& rect,
TranslateRectDirection direction) {
gfx::Vector2dF translation = ComputeChangeOfBasisTranslation<LayerType>(
ancestor_layer, descendant_layer);
@@ -240,7 +239,7 @@ struct AccumulatedSurfaceState {
template <typename LayerType>
void UpdateAccumulatedSurfaceState(
LayerType* layer,
- gfx::Rect drawable_content_rect,
+ const gfx::Rect& drawable_content_rect,
std::vector<AccumulatedSurfaceState<LayerType> >*
accumulated_surface_state) {
if (IsRootLayer(layer))
@@ -328,21 +327,16 @@ template <typename LayerType> static inline bool IsRootLayer(LayerType* layer) {
template <typename LayerType>
static inline bool LayerIsInExisting3DRenderingContext(LayerType* layer) {
- // According to current W3C spec on CSS transforms, a layer is part of an
- // established 3d rendering context if its parent has transform-style of
- // preserves-3d.
- return layer->parent() && layer->parent()->preserves_3d();
+ return layer->Is3dSorted() && layer->parent() &&
+ layer->parent()->Is3dSorted();
}
template <typename LayerType>
static bool IsRootLayerOfNewRenderingContext(LayerType* layer) {
- // According to current W3C spec on CSS transforms (Section 6.1), a layer is
- // the beginning of 3d rendering context if its parent does not have
- // transform-style: preserve-3d, but this layer itself does.
if (layer->parent())
- return !layer->parent()->preserves_3d() && layer->preserves_3d();
+ return !layer->parent()->Is3dSorted() && layer->Is3dSorted();
- return layer->preserves_3d();
+ return layer->Is3dSorted();
}
template <typename LayerType>
@@ -383,8 +377,8 @@ static inline bool LayerClipsSubtree(LayerType* layer) {
template <typename LayerType>
static gfx::Rect CalculateVisibleContentRect(
LayerType* layer,
- gfx::Rect clip_rect_of_target_surface_in_target_space,
- gfx::Rect layer_rect_in_target_space) {
+ const gfx::Rect& clip_rect_of_target_surface_in_target_space,
+ const gfx::Rect& layer_rect_in_target_space) {
DCHECK(layer->render_target());
// Nothing is visible if the layer bounds are empty.
@@ -433,14 +427,14 @@ static inline bool TransformToScreenIsKnown(Layer* layer) {
}
template <typename LayerType>
-static bool LayerShouldBeSkipped(LayerType* layer,
- bool layer_is_visible) {
+static bool LayerShouldBeSkipped(LayerType* layer, bool layer_is_drawn) {
// Layers can be skipped if any of these conditions are met.
- // - is not visible due to it or one of its ancestors being hidden.
+ // - is not drawn due to it or one of its ancestors being hidden (or having
+ // no copy requests).
+ // - does not draw content.
+ // - is transparent.
// - has empty bounds
// - the layer is not double-sided, but its back face is visible.
- // - is transparent
- // - does not draw content and does not participate in hit testing.
//
// Some additional conditions need to be computed at a later point after the
// recursion is finished.
@@ -451,10 +445,10 @@ static bool LayerShouldBeSkipped(LayerType* layer,
// transparent, we would have skipped the entire subtree and never made it
// into this function, so it is safe to omit this check here.
- if (!layer_is_visible)
+ if (!layer_is_drawn)
return true;
- if (layer->bounds().IsEmpty())
+ if (!layer->DrawsContent() || layer->bounds().IsEmpty())
return true;
LayerType* backface_test_layer = layer;
@@ -471,25 +465,35 @@ static bool LayerShouldBeSkipped(LayerType* layer,
IsLayerBackFaceVisible(backface_test_layer))
return true;
- // The layer is visible to events. If it's subject to hit testing, then
- // we can't skip it.
- bool can_accept_input = !layer->touch_event_handler_region().IsEmpty() ||
- layer->have_wheel_event_handlers();
- if (!layer->DrawsContent() && !can_accept_input)
- return true;
-
return false;
}
+template <typename LayerType>
+static bool HasInvertibleOrAnimatedTransform(LayerType* layer) {
+ return layer->transform_is_invertible() || layer->TransformIsAnimating();
+}
+
static inline bool SubtreeShouldBeSkipped(LayerImpl* layer,
- bool layer_is_visible) {
+ bool layer_is_drawn) {
+ // If the layer transform is not invertible, it should not be drawn.
+ // 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 (!HasInvertibleOrAnimatedTransform(layer))
+ return true;
+
// When we need to do a readback/copy of a layer's output, we can not skip
// it or any of its ancestors.
if (layer->draw_properties().layer_or_descendant_has_copy_request)
return false;
- // If the layer is not visible, then skip it and its subtree.
- if (!layer_is_visible)
+ // We cannot skip the the subtree if a descendant has a wheel or touch handler
+ // or the hit testing code will break (it requires fresh transforms, etc).
+ if (layer->draw_properties().layer_or_descendant_has_input_handler)
+ return false;
+
+ // If the layer is not drawn, then skip it and its subtree.
+ if (!layer_is_drawn)
return true;
// If layer is on the pending tree and opacity is being animated then
@@ -501,19 +505,26 @@ static inline bool SubtreeShouldBeSkipped(LayerImpl* layer,
// The opacity of a layer always applies to its children (either implicitly
// via a render surface or explicitly if the parent preserves 3D), so the
// entire subtree can be skipped if this layer is fully transparent.
- // TODO(sad): Don't skip layers used for hit testing crbug.com/295295.
return !layer->opacity();
}
-static inline bool SubtreeShouldBeSkipped(Layer* layer,
- bool layer_is_visible) {
+static inline bool SubtreeShouldBeSkipped(Layer* layer, bool layer_is_drawn) {
+ // If the layer transform is not invertible, it should not be drawn.
+ if (!layer->transform_is_invertible() && !layer->TransformIsAnimating())
+ return true;
+
// When we need to do a readback/copy of a layer's output, we can not skip
// it or any of its ancestors.
if (layer->draw_properties().layer_or_descendant_has_copy_request)
return false;
- // If the layer is not visible, then skip it and its subtree.
- if (!layer_is_visible)
+ // We cannot skip the the subtree if a descendant has a wheel or touch handler
+ // or the hit testing code will break (it requires fresh transforms, etc).
+ if (layer->draw_properties().layer_or_descendant_has_input_handler)
+ return false;
+
+ // If the layer is not drawn, then skip it and its subtree.
+ if (!layer_is_drawn)
return true;
// If the opacity is being animated then the opacity on the main thread is
@@ -522,7 +533,6 @@ static inline bool SubtreeShouldBeSkipped(Layer* layer,
// In particular, it should not cause the subtree to be skipped.
// Similarly, for layers that might animate opacity using an impl-only
// animation, their subtree should also not be skipped.
- // TODO(sad): Don't skip layers used for hit testing crbug.com/295295.
return !layer->opacity() && !layer->OpacityIsAnimating() &&
!layer->OpacityCanAnimateOnImplThread();
}
@@ -575,9 +585,10 @@ static bool SubtreeShouldRenderToSeparateSurface(
int num_descendants_that_draw_content =
layer->draw_properties().num_descendants_that_draw_content;
- // If the layer flattens its subtree (i.e. the layer doesn't preserve-3d), but
- // it is treated as a 3D object by its parent (i.e. parent does preserve-3d).
- if (LayerIsInExisting3DRenderingContext(layer) && !layer->preserves_3d() &&
+ // If the layer flattens its subtree, but it is treated as a 3D object by its
+ // parent (i.e. parent participates in a 3D rendering context).
+ if (LayerIsInExisting3DRenderingContext(layer) &&
+ layer->should_flatten_transform() &&
num_descendants_that_draw_content > 0) {
TRACE_EVENT_INSTANT0(
"cc",
@@ -623,7 +634,7 @@ static bool SubtreeShouldRenderToSeparateSurface(
num_descendants_that_draw_content > 0 &&
(layer->DrawsContent() || num_descendants_that_draw_content > 1);
- if (layer->opacity() != 1.f && !layer->preserves_3d() &&
+ if (layer->opacity() != 1.f && layer->should_flatten_transform() &&
at_least_two_layers_in_subtree_draw_content) {
TRACE_EVENT_INSTANT0(
"cc",
@@ -672,7 +683,7 @@ static bool SubtreeShouldRenderToSeparateSurface(
gfx::Transform ComputeSizeDeltaCompensation(
LayerImpl* layer,
LayerImpl* container,
- gfx::Vector2dF position_offset) {
+ const gfx::Vector2dF& position_offset) {
gfx::Transform result_transform;
// To apply a translate in the container's layer space,
@@ -760,7 +771,7 @@ void ApplyPositionAdjustment(
layer->position_constraint().is_fixed_to_right_edge();
bool fixed_to_bottom_edge =
layer->position_constraint().is_fixed_to_bottom_edge();
- gfx::Vector2dF position_offset = container->fixed_container_size_delta();
+ gfx::Vector2dF position_offset = container->FixedContainerSizeDelta();
position_offset.set_x(fixed_to_right_edge ? position_offset.x() : 0);
position_offset.set_y(fixed_to_bottom_edge ? position_offset.y() : 0);
if (position_offset.IsZero())
@@ -775,7 +786,7 @@ void ApplyPositionAdjustment(
gfx::Transform ComputeScrollCompensationForThisLayer(
LayerImpl* scrolling_layer,
const gfx::Transform& parent_matrix,
- gfx::Vector2dF scroll_delta) {
+ const gfx::Vector2dF& scroll_delta) {
// For every layer that has non-zero scroll_delta, we have to compute a
// transform that can undo the scroll_delta translation. In particular, we
// want this matrix to premultiply a fixed-position layer's parent_matrix, so
@@ -815,7 +826,7 @@ gfx::Transform ComputeScrollCompensationMatrixForChildren(
Layer* current_layer,
const gfx::Transform& current_parent_matrix,
const gfx::Transform& current_scroll_compensation,
- gfx::Vector2dF scroll_delta) {
+ const gfx::Vector2dF& scroll_delta) {
// The main thread (i.e. Layer) does not need to worry about scroll
// compensation. So we can just return an identity matrix here.
return gfx::Transform();
@@ -825,7 +836,7 @@ gfx::Transform ComputeScrollCompensationMatrixForChildren(
LayerImpl* layer,
const gfx::Transform& parent_matrix,
const gfx::Transform& current_scroll_compensation_matrix,
- gfx::Vector2dF scroll_delta) {
+ const gfx::Vector2dF& scroll_delta) {
// "Total scroll compensation" is the transform needed to cancel out all
// scroll_delta translations that occurred since the nearest container layer,
// even if there are render_surfaces in-between.
@@ -908,38 +919,67 @@ gfx::Transform ComputeScrollCompensationMatrixForChildren(
}
template <typename LayerType>
-static inline void CalculateContentsScale(LayerType* layer,
- float contents_scale,
- float device_scale_factor,
- float page_scale_factor,
- bool animating_transform_to_screen) {
+static inline void UpdateLayerScaleDrawProperties(
+ LayerType* layer,
+ float ideal_contents_scale,
+ float maximum_animation_contents_scale,
+ float page_scale_factor,
+ float device_scale_factor) {
+ layer->draw_properties().ideal_contents_scale = ideal_contents_scale;
+ layer->draw_properties().maximum_animation_contents_scale =
+ maximum_animation_contents_scale;
+ layer->draw_properties().page_scale_factor = page_scale_factor;
+ layer->draw_properties().device_scale_factor = device_scale_factor;
+}
+
+static inline void CalculateContentsScale(
+ LayerImpl* layer,
+ float contents_scale,
+ float device_scale_factor,
+ float page_scale_factor,
+ float maximum_animation_contents_scale,
+ bool animating_transform_to_screen) {
+ // LayerImpl has all of its content scales and bounds pushed from the Main
+ // thread during commit and just uses those values as-is.
+}
+
+static inline void CalculateContentsScale(
+ Layer* layer,
+ float contents_scale,
+ float device_scale_factor,
+ float page_scale_factor,
+ float maximum_animation_contents_scale,
+ bool animating_transform_to_screen) {
layer->CalculateContentsScale(contents_scale,
device_scale_factor,
page_scale_factor,
+ maximum_animation_contents_scale,
animating_transform_to_screen,
&layer->draw_properties().contents_scale_x,
&layer->draw_properties().contents_scale_y,
&layer->draw_properties().content_bounds);
- LayerType* mask_layer = layer->mask_layer();
+ Layer* mask_layer = layer->mask_layer();
if (mask_layer) {
mask_layer->CalculateContentsScale(
contents_scale,
device_scale_factor,
page_scale_factor,
+ maximum_animation_contents_scale,
animating_transform_to_screen,
&mask_layer->draw_properties().contents_scale_x,
&mask_layer->draw_properties().contents_scale_y,
&mask_layer->draw_properties().content_bounds);
}
- LayerType* replica_mask_layer =
+ Layer* replica_mask_layer =
layer->replica_layer() ? layer->replica_layer()->mask_layer() : NULL;
if (replica_mask_layer) {
replica_mask_layer->CalculateContentsScale(
contents_scale,
device_scale_factor,
page_scale_factor,
+ maximum_animation_contents_scale,
animating_transform_to_screen,
&replica_mask_layer->draw_properties().contents_scale_x,
&replica_mask_layer->draw_properties().contents_scale_y,
@@ -953,11 +993,13 @@ static inline void UpdateLayerContentsScale(
float ideal_contents_scale,
float device_scale_factor,
float page_scale_factor,
+ float maximum_animation_contents_scale,
bool animating_transform_to_screen) {
CalculateContentsScale(layer,
ideal_contents_scale,
device_scale_factor,
page_scale_factor,
+ maximum_animation_contents_scale,
animating_transform_to_screen);
}
@@ -967,6 +1009,7 @@ static inline void UpdateLayerContentsScale(
float ideal_contents_scale,
float device_scale_factor,
float page_scale_factor,
+ float maximum_animation_contents_scale,
bool animating_transform_to_screen) {
if (can_adjust_raster_scale) {
float ideal_raster_scale =
@@ -994,25 +1037,113 @@ static inline void UpdateLayerContentsScale(
if (!layer->raster_scale_is_unknown())
raster_scale = layer->raster_scale();
+ gfx::Size old_content_bounds = layer->content_bounds();
+ float old_contents_scale_x = layer->contents_scale_x();
+ float old_contents_scale_y = layer->contents_scale_y();
float contents_scale = raster_scale * device_scale_factor * page_scale_factor;
CalculateContentsScale(layer,
contents_scale,
device_scale_factor,
page_scale_factor,
+ maximum_animation_contents_scale,
animating_transform_to_screen);
+
+ if (layer->content_bounds() != old_content_bounds ||
+ layer->contents_scale_x() != old_contents_scale_x ||
+ layer->contents_scale_y() != old_contents_scale_y)
+ layer->SetNeedsPushProperties();
}
-static inline RenderSurface* CreateOrReuseRenderSurface(Layer* layer) {
- // The render surface should always be new on the main thread, as the
- // RenderSurfaceLayerList should be a new empty list when given to
- // CalculateDrawProperties.
- DCHECK(!layer->render_surface());
- layer->CreateRenderSurface();
- return layer->render_surface();
+static inline void CalculateAnimationContentsScale(
+ Layer* layer,
+ bool ancestor_is_animating_scale,
+ float ancestor_maximum_animation_contents_scale,
+ const gfx::Transform& parent_transform,
+ const gfx::Transform& combined_transform,
+ bool* combined_is_animating_scale,
+ float* combined_maximum_animation_contents_scale) {
+ *combined_is_animating_scale = false;
+ *combined_maximum_animation_contents_scale = 0.f;
+}
+
+static inline void CalculateAnimationContentsScale(
+ LayerImpl* layer,
+ bool ancestor_is_animating_scale,
+ float ancestor_maximum_animation_contents_scale,
+ const gfx::Transform& ancestor_transform,
+ const gfx::Transform& combined_transform,
+ bool* combined_is_animating_scale,
+ float* combined_maximum_animation_contents_scale) {
+ if (ancestor_is_animating_scale &&
+ ancestor_maximum_animation_contents_scale == 0.f) {
+ // We've already failed to compute a maximum animated scale at an
+ // ancestor, so we'll continue to fail.
+ *combined_maximum_animation_contents_scale = 0.f;
+ *combined_is_animating_scale = true;
+ return;
+ }
+
+ if (!combined_transform.IsScaleOrTranslation()) {
+ // Computing maximum animated scale in the presence of
+ // non-scale/translation transforms isn't supported.
+ *combined_maximum_animation_contents_scale = 0.f;
+ *combined_is_animating_scale = true;
+ return;
+ }
+
+ // We currently only support computing maximum scale for combinations of
+ // scales and translations. We treat all non-translations as potentially
+ // affecting scale. Animations that include non-translation/scale components
+ // will cause the computation of MaximumScale below to fail.
+ bool layer_is_animating_scale =
+ !layer->layer_animation_controller()->HasOnlyTranslationTransforms();
+
+ if (!layer_is_animating_scale && !ancestor_is_animating_scale) {
+ *combined_maximum_animation_contents_scale = 0.f;
+ *combined_is_animating_scale = false;
+ return;
+ }
+
+ // We don't attempt to accumulate animation scale from multiple nodes,
+ // because of the risk of significant overestimation. For example, one node
+ // may be increasing scale from 1 to 10 at the same time as a descendant is
+ // decreasing scale from 10 to 1. Naively combining these scales would produce
+ // a scale of 100.
+ if (layer_is_animating_scale && ancestor_is_animating_scale) {
+ *combined_maximum_animation_contents_scale = 0.f;
+ *combined_is_animating_scale = true;
+ return;
+ }
+
+ // At this point, we know either the layer or an ancestor, but not both,
+ // is animating scale.
+ *combined_is_animating_scale = true;
+ if (!layer_is_animating_scale) {
+ gfx::Vector2dF layer_transform_scales =
+ MathUtil::ComputeTransform2dScaleComponents(layer->transform(), 0.f);
+ *combined_maximum_animation_contents_scale =
+ ancestor_maximum_animation_contents_scale *
+ std::max(layer_transform_scales.x(), layer_transform_scales.y());
+ return;
+ }
+
+ float layer_maximum_animated_scale = 0.f;
+ if (!layer->layer_animation_controller()->MaximumScale(
+ &layer_maximum_animated_scale)) {
+ *combined_maximum_animation_contents_scale = 0.f;
+ return;
+ }
+ gfx::Vector2dF ancestor_transform_scales =
+ MathUtil::ComputeTransform2dScaleComponents(ancestor_transform, 0.f);
+ *combined_maximum_animation_contents_scale =
+ layer_maximum_animated_scale *
+ std::max(ancestor_transform_scales.x(), ancestor_transform_scales.y());
}
-static inline RenderSurfaceImpl* CreateOrReuseRenderSurface(LayerImpl* layer) {
+template <typename LayerType>
+static inline typename LayerType::RenderSurfaceType* CreateOrReuseRenderSurface(
+ LayerType* layer) {
if (!layer->render_surface()) {
layer->CreateRenderSurface();
return layer->render_surface();
@@ -1022,6 +1153,42 @@ static inline RenderSurfaceImpl* CreateOrReuseRenderSurface(LayerImpl* layer) {
return layer->render_surface();
}
+template <typename LayerTypePtr>
+static inline void MarkLayerWithRenderSurfaceLayerListId(
+ LayerTypePtr layer,
+ int current_render_surface_layer_list_id) {
+ layer->draw_properties().last_drawn_render_surface_layer_list_id =
+ current_render_surface_layer_list_id;
+}
+
+template <typename LayerTypePtr>
+static inline void MarkMasksWithRenderSurfaceLayerListId(
+ LayerTypePtr layer,
+ int current_render_surface_layer_list_id) {
+ if (layer->mask_layer()) {
+ MarkLayerWithRenderSurfaceLayerListId(layer->mask_layer(),
+ current_render_surface_layer_list_id);
+ }
+ if (layer->replica_layer() && layer->replica_layer()->mask_layer()) {
+ MarkLayerWithRenderSurfaceLayerListId(layer->replica_layer()->mask_layer(),
+ current_render_surface_layer_list_id);
+ }
+}
+
+template <typename LayerListType>
+static inline void MarkLayerListWithRenderSurfaceLayerListId(
+ LayerListType* layer_list,
+ int current_render_surface_layer_list_id) {
+ for (typename LayerListType::iterator it = layer_list->begin();
+ it != layer_list->end();
+ ++it) {
+ MarkLayerWithRenderSurfaceLayerListId(*it,
+ current_render_surface_layer_list_id);
+ MarkMasksWithRenderSurfaceLayerListId(*it,
+ current_render_surface_layer_list_id);
+ }
+}
+
template <typename LayerType>
static inline void RemoveSurfaceForEarlyExit(
LayerType* layer_to_remove,
@@ -1034,25 +1201,36 @@ static inline void RemoveSurfaceForEarlyExit(
// things to crash. So here we proactively remove any additional
// layers from the end of the list.
while (render_surface_layer_list->back() != layer_to_remove) {
- render_surface_layer_list->back()->ClearRenderSurface();
+ MarkLayerListWithRenderSurfaceLayerListId(
+ &render_surface_layer_list->back()->render_surface()->layer_list(), 0);
+ MarkLayerWithRenderSurfaceLayerListId(render_surface_layer_list->back(), 0);
+
+ render_surface_layer_list->back()->ClearRenderSurfaceLayerList();
render_surface_layer_list->pop_back();
}
DCHECK_EQ(render_surface_layer_list->back(), layer_to_remove);
+ MarkLayerListWithRenderSurfaceLayerListId(
+ &layer_to_remove->render_surface()->layer_list(), 0);
+ MarkLayerWithRenderSurfaceLayerListId(layer_to_remove, 0);
render_surface_layer_list->pop_back();
- layer_to_remove->ClearRenderSurface();
+ layer_to_remove->ClearRenderSurfaceLayerList();
}
struct PreCalculateMetaInformationRecursiveData {
bool layer_or_descendant_has_copy_request;
+ bool layer_or_descendant_has_input_handler;
int num_unclipped_descendants;
PreCalculateMetaInformationRecursiveData()
: layer_or_descendant_has_copy_request(false),
+ layer_or_descendant_has_input_handler(false),
num_unclipped_descendants(0) {}
void Merge(const PreCalculateMetaInformationRecursiveData& data) {
layer_or_descendant_has_copy_request |=
data.layer_or_descendant_has_copy_request;
+ layer_or_descendant_has_input_handler |=
+ data.layer_or_descendant_has_input_handler;
num_unclipped_descendants +=
data.num_unclipped_descendants;
}
@@ -1067,6 +1245,15 @@ static void PreCalculateMetaInformation(
bool has_delegated_content = layer->HasDelegatedContent();
int num_descendants_that_draw_content = 0;
+ layer->draw_properties().sorted_for_recursion = false;
+ layer->draw_properties().has_child_with_a_scroll_parent = false;
+
+ if (!HasInvertibleOrAnimatedTransform(layer)) {
+ // Layers with singular transforms should not be drawn, the whole subtree
+ // can be skipped.
+ return;
+ }
+
if (has_delegated_content) {
// Layers with delegated content need to be treated as if they have as
// many children as the number of layers they own delegated quads for.
@@ -1075,15 +1262,12 @@ static void PreCalculateMetaInformation(
num_descendants_that_draw_content = 1000;
}
- layer->draw_properties().sorted_for_recursion = false;
- layer->draw_properties().has_child_with_a_scroll_parent = false;
-
if (layer->clip_parent())
recursive_data->num_unclipped_descendants++;
for (size_t i = 0; i < layer->children().size(); ++i) {
LayerType* child_layer =
- LayerTreeHostCommon::get_child_as_raw_ptr(layer->children(), i);
+ LayerTreeHostCommon::get_layer_as_raw_ptr(layer->children(), i);
PreCalculateMetaInformationRecursiveData data_for_child;
PreCalculateMetaInformation(child_layer, &data_for_child);
@@ -1106,12 +1290,18 @@ static void PreCalculateMetaInformation(
if (layer->HasCopyRequest())
recursive_data->layer_or_descendant_has_copy_request = true;
+ if (!layer->touch_event_handler_region().IsEmpty() ||
+ layer->have_wheel_event_handlers())
+ recursive_data->layer_or_descendant_has_input_handler = true;
+
layer->draw_properties().num_descendants_that_draw_content =
num_descendants_that_draw_content;
layer->draw_properties().num_unclipped_descendants =
recursive_data->num_unclipped_descendants;
layer->draw_properties().layer_or_descendant_has_copy_request =
recursive_data->layer_or_descendant_has_copy_request;
+ layer->draw_properties().layer_or_descendant_has_input_handler =
+ recursive_data->layer_or_descendant_has_input_handler;
}
static void RoundTranslationComponents(gfx::Transform* transform) {
@@ -1162,6 +1352,11 @@ struct DataForRecursion {
// passed down the recursion to the children that actually use it.
gfx::Rect clip_rect_of_target_surface_in_target_space;
+ // The maximum amount by which this layer will be scaled during the lifetime
+ // of currently running animations.
+ float maximum_animation_contents_scale;
+
+ bool ancestor_is_animating_scale;
bool ancestor_clips_subtree;
typename LayerType::RenderSurfaceType*
nearest_occlusion_immune_ancestor_surface;
@@ -1230,7 +1425,7 @@ static bool SortChildrenForRecursion(std::vector<LayerType*>* out,
bool order_changed = false;
for (size_t i = 0; i < parent.children().size(); ++i) {
LayerType* current =
- LayerTreeHostCommon::get_child_as_raw_ptr(parent.children(), i);
+ LayerTreeHostCommon::get_layer_as_raw_ptr(parent.children(), i);
if (current->draw_properties().sorted_for_recursion) {
order_changed = true;
@@ -1261,18 +1456,26 @@ static void GetNewRenderSurfacesStartIndexAndCount(LayerType* layer,
*count = layer->draw_properties().num_render_surfaces_added;
}
-template <typename LayerType,
- typename GetIndexAndCountType>
+// We need to extract a list from the the two flavors of RenderSurfaceListType
+// for use in the sorting function below.
+static LayerList* GetLayerListForSorting(RenderSurfaceLayerList* rsll) {
+ return &rsll->AsLayerList();
+}
+
+static LayerImplList* GetLayerListForSorting(LayerImplList* layer_list) {
+ return layer_list;
+}
+
+template <typename LayerType, typename GetIndexAndCountType>
static void SortLayerListContributions(
const LayerType& parent,
- typename LayerType::RenderSurfaceListType* unsorted,
+ typename LayerType::LayerListType* unsorted,
size_t start_index_for_all_contributions,
GetIndexAndCountType get_index_and_count) {
-
typename LayerType::LayerListType buffer;
for (size_t i = 0; i < parent.children().size(); ++i) {
LayerType* child =
- LayerTreeHostCommon::get_child_as_raw_ptr(parent.children(), i);
+ LayerTreeHostCommon::get_layer_as_raw_ptr(parent.children(), i);
size_t start_index = 0;
size_t count = 0;
@@ -1296,9 +1499,9 @@ static void CalculateDrawPropertiesInternal(
const SubtreeGlobals<LayerType>& globals,
const DataForRecursion<LayerType>& data_from_ancestor,
typename LayerType::RenderSurfaceListType* render_surface_layer_list,
- typename LayerType::RenderSurfaceListType* layer_list,
- std::vector<AccumulatedSurfaceState<LayerType> >*
- accumulated_surface_state) {
+ typename LayerType::LayerListType* layer_list,
+ std::vector<AccumulatedSurfaceState<LayerType> >* accumulated_surface_state,
+ int current_render_surface_layer_list_id) {
// This function computes the new matrix transformations recursively for this
// layer and all its descendants. It also computes the appropriate render
// surfaces.
@@ -1336,9 +1539,6 @@ static void CalculateDrawPropertiesInternal(
//
// M[layer] is the layer's matrix (applied at the anchor point)
//
- // M[sublayer] is the layer's sublayer transform (also applied at the
- // layer's anchor point)
- //
// S[layer2content] is the ratio of a layer's content_bounds() to its
// Bounds().
//
@@ -1347,9 +1547,6 @@ static void CalculateDrawPropertiesInternal(
// composite_layer_transform = Tr[origin2anchor] * M[layer] *
// Tr[origin2anchor].inverse()
//
- // composite_sublayer_transform = Tr[origin2anchor] * M[sublayer] *
- // Tr[origin2anchor].inverse()
- //
// 4. When a layer (or render surface) is drawn, it is drawn into a "target
// render surface". Therefore the draw transform does not necessarily
// transform from screen space to local layer space. Instead, the draw
@@ -1382,10 +1579,9 @@ static void CalculateDrawPropertiesInternal(
// The transform hierarchy that is passed on to children (i.e. the child's
// parent_matrix) is:
// M[parent]_for_child = M[parent] * Tr[origin] *
- // composite_layer_transform * composite_sublayer_transform
+ // composite_layer_transform
// = M[parent] * Tr[layer->position() + anchor] *
- // M[layer] * Tr[anchor2origin] *
- // composite_sublayer_transform
+ // M[layer] * Tr[anchor2origin]
//
// and a similar matrix for the full hierarchy with respect to the
// root.
@@ -1435,19 +1631,19 @@ static void CalculateDrawPropertiesInternal(
data_for_children.subtree_can_use_lcd_text =
data_from_ancestor.subtree_can_use_lcd_text;
- // Layers with a copy request are always visible, as well as un-hiding their
- // subtree. Otherise, layers that are marked as hidden will hide themselves
- // and their subtree.
- bool layer_is_visible =
+ // Layers that are marked as hidden will hide themselves and their subtree.
+ // Exception: Layers with copy requests, whether hidden or not, must be drawn
+ // anyway. In this case, we will inform their subtree they are visible to get
+ // the right results.
+ const bool layer_is_visible =
data_from_ancestor.subtree_is_visible_from_ancestor &&
!layer->hide_layer_and_subtree();
- if (layer->HasCopyRequest())
- layer_is_visible = true;
+ const bool layer_is_drawn = layer_is_visible || layer->HasCopyRequest();
// The root layer cannot skip CalcDrawProperties.
- if (!IsRootLayer(layer) && SubtreeShouldBeSkipped(layer, layer_is_visible)) {
+ if (!IsRootLayer(layer) && SubtreeShouldBeSkipped(layer, layer_is_drawn)) {
if (layer->render_surface())
- layer->ClearRenderSurface();
+ layer->ClearRenderSurfaceLayerList();
return;
}
@@ -1499,25 +1695,21 @@ static void CalculateDrawPropertiesInternal(
animating_transform_to_screen |=
layer->parent()->screen_space_transform_is_animating();
}
-
- gfx::Size bounds = layer->bounds();
- gfx::PointF anchor_point = layer->anchor_point();
+ gfx::Point3F transform_origin = layer->transform_origin();
gfx::Vector2dF scroll_offset = GetEffectiveTotalScrollOffset(layer);
gfx::PointF position = layer->position() - scroll_offset;
-
gfx::Transform combined_transform = data_from_ancestor.parent_matrix;
if (!layer->transform().IsIdentity()) {
- // LT = Tr[origin] * Tr[origin2anchor]
- combined_transform.Translate3d(
- position.x() + anchor_point.x() * bounds.width(),
- position.y() + anchor_point.y() * bounds.height(),
- layer->anchor_point_z());
- // LT = Tr[origin] * Tr[origin2anchor] * M[layer]
+ // LT = Tr[origin] * Tr[origin2transformOrigin]
+ combined_transform.Translate3d(position.x() + transform_origin.x(),
+ position.y() + transform_origin.y(),
+ transform_origin.z());
+ // LT = Tr[origin] * Tr[origin2origin] * M[layer]
combined_transform.PreconcatTransform(layer->transform());
- // LT = Tr[origin] * Tr[origin2anchor] * M[layer] * Tr[anchor2origin]
- combined_transform.Translate3d(-anchor_point.x() * bounds.width(),
- -anchor_point.y() * bounds.height(),
- -layer->anchor_point_z());
+ // LT = Tr[origin] * Tr[origin2origin] * M[layer] *
+ // Tr[transformOrigin2origin]
+ combined_transform.Translate3d(
+ -transform_origin.x(), -transform_origin.y(), -transform_origin.z());
} else {
combined_transform.Translate(position.x(), position.y());
}
@@ -1533,14 +1725,39 @@ static void CalculateDrawPropertiesInternal(
gfx::Vector2dF current_translation = combined_transform.To2dTranslation();
// This rounding changes the scroll delta, and so must be included
- // in the scroll compensation matrix.
- effective_scroll_delta -= current_translation - previous_translation;
+ // in the scroll compensation matrix. The scaling converts from physical
+ // coordinates to the scroll delta's CSS coordinates (using the parent
+ // matrix instead of combined transform since scrolling is applied before
+ // the layer's transform). For example, if we have a total scale factor of
+ // 3.0, then 1 physical pixel is only 1/3 of a CSS pixel.
+ gfx::Vector2dF parent_scales = MathUtil::ComputeTransform2dScaleComponents(
+ data_from_ancestor.parent_matrix, 1.f);
+ effective_scroll_delta -=
+ gfx::ScaleVector2d(current_translation - previous_translation,
+ 1.f / parent_scales.x(),
+ 1.f / parent_scales.y());
}
// Apply adjustment from position constraints.
ApplyPositionAdjustment(layer, data_from_ancestor.fixed_container,
data_from_ancestor.scroll_compensation_matrix, &combined_transform);
+ bool combined_is_animating_scale = false;
+ float combined_maximum_animation_contents_scale = 0.f;
+ if (globals.can_adjust_raster_scales) {
+ CalculateAnimationContentsScale(
+ layer,
+ data_from_ancestor.ancestor_is_animating_scale,
+ data_from_ancestor.maximum_animation_contents_scale,
+ data_from_ancestor.parent_matrix,
+ combined_transform,
+ &combined_is_animating_scale,
+ &combined_maximum_animation_contents_scale);
+ }
+ data_for_children.ancestor_is_animating_scale = combined_is_animating_scale;
+ data_for_children.maximum_animation_contents_scale =
+ combined_maximum_animation_contents_scale;
+
// Compute the 2d scale components of the transform hierarchy up to the target
// surface. From there, we can decide on a contents scale for the layer.
float layer_scale_factors = globals.device_scale_factor;
@@ -1561,10 +1778,46 @@ static void CalculateDrawPropertiesInternal(
globals.can_adjust_raster_scales,
ideal_contents_scale,
globals.device_scale_factor,
- data_from_ancestor.in_subtree_of_page_scale_application_layer ?
- globals.page_scale_factor : 1.f,
+ data_from_ancestor.in_subtree_of_page_scale_application_layer
+ ? globals.page_scale_factor
+ : 1.f,
+ combined_maximum_animation_contents_scale,
animating_transform_to_screen);
+ UpdateLayerScaleDrawProperties(
+ layer,
+ ideal_contents_scale,
+ combined_maximum_animation_contents_scale,
+ data_from_ancestor.in_subtree_of_page_scale_application_layer
+ ? globals.page_scale_factor
+ : 1.f,
+ globals.device_scale_factor);
+
+ LayerType* mask_layer = layer->mask_layer();
+ if (mask_layer) {
+ UpdateLayerScaleDrawProperties(
+ mask_layer,
+ ideal_contents_scale,
+ combined_maximum_animation_contents_scale,
+ data_from_ancestor.in_subtree_of_page_scale_application_layer
+ ? globals.page_scale_factor
+ : 1.f,
+ globals.device_scale_factor);
+ }
+
+ LayerType* replica_mask_layer =
+ layer->replica_layer() ? layer->replica_layer()->mask_layer() : NULL;
+ if (replica_mask_layer) {
+ UpdateLayerScaleDrawProperties(
+ replica_mask_layer,
+ ideal_contents_scale,
+ combined_maximum_animation_contents_scale,
+ data_from_ancestor.in_subtree_of_page_scale_application_layer
+ ? globals.page_scale_factor
+ : 1.f,
+ globals.device_scale_factor);
+ }
+
// The draw_transform that gets computed below is effectively the layer's
// draw_transform, unless the layer itself creates a render_surface. In that
// case, the render_surface re-parents the transforms.
@@ -1578,7 +1831,7 @@ static void CalculateDrawPropertiesInternal(
// layer's "screen space" and local content space.
layer_draw_properties.screen_space_transform =
data_from_ancestor.full_hierarchy_matrix;
- if (!layer->preserves_3d())
+ if (layer->should_flatten_transform())
layer_draw_properties.screen_space_transform.FlattenTo2d();
layer_draw_properties.screen_space_transform.PreconcatTransform
(layer_draw_properties.target_space_transform);
@@ -1595,7 +1848,7 @@ static void CalculateDrawPropertiesInternal(
layer_draw_properties.target_space_transform.
IsIdentityOrIntegerTranslation();
- gfx::RectF content_rect(layer->content_bounds());
+ gfx::Rect content_rect(layer->content_bounds());
// full_hierarchy_matrix is the matrix that transforms objects between screen
// space (except projection matrix) and the most recent RenderSurfaceImpl's
@@ -1624,7 +1877,7 @@ static void CalculateDrawPropertiesInternal(
// subtree
if (!layer->double_sided() && TransformToParentIsKnown(layer) &&
IsSurfaceBackFaceVisible(layer, combined_transform)) {
- layer->ClearRenderSurface();
+ layer->ClearRenderSurfaceLayerList();
return;
}
@@ -1667,8 +1920,9 @@ static void CalculateDrawPropertiesInternal(
data_for_children.parent_matrix.Scale(render_surface_sublayer_scale.x(),
render_surface_sublayer_scale.y());
+ // Even if the |layer_is_drawn|, it only contributes to a drawn surface
+ // when the |layer_is_visible|.
layer->render_surface()->set_contributes_to_drawn_surface(
- data_from_ancestor.subtree_is_visible_from_ancestor &&
layer_is_visible);
}
@@ -1743,9 +1997,8 @@ static void CalculateDrawPropertiesInternal(
// here, or DCHECK that the transform is invertible.
}
- gfx::Rect projected_surface_rect = gfx::ToEnclosingRect(
- MathUtil::ProjectClippedRect(inverse_surface_draw_transform,
- ancestor_clip_rect_in_target_space));
+ gfx::Rect projected_surface_rect = MathUtil::ProjectEnclosingClippedRect(
+ inverse_surface_draw_transform, ancestor_clip_rect_in_target_space);
if (layer_draw_properties.num_unclipped_descendants > 0) {
// If we have unclipped descendants, we cannot count on the render
@@ -1828,8 +2081,8 @@ static void CalculateDrawPropertiesInternal(
if (adjust_text_aa)
layer_draw_properties.can_use_lcd_text = layer_can_use_lcd_text;
- gfx::Rect rect_in_target_space = ToEnclosingRect(
- MathUtil::MapClippedRect(layer->draw_transform(), content_rect));
+ gfx::Rect rect_in_target_space =
+ MathUtil::MapEnclosingClippedRect(layer->draw_transform(), content_rect);
if (LayerClipsSubtree(layer)) {
layer_or_ancestor_clips_descendants = true;
@@ -1857,7 +2110,7 @@ static void CalculateDrawPropertiesInternal(
layer_draw_properties.clip_rect = rect_in_target_space;
}
- typename LayerType::RenderSurfaceListType& descendants =
+ typename LayerType::LayerListType& descendants =
(layer->render_surface() ? layer->render_surface()->layer_list()
: *layer_list);
@@ -1865,8 +2118,11 @@ static void CalculateDrawPropertiesInternal(
// and should be included in the sorting process.
size_t sorting_start_index = descendants.size();
- if (!LayerShouldBeSkipped(layer, layer_is_visible))
+ if (!LayerShouldBeSkipped(layer, layer_is_drawn)) {
+ MarkLayerWithRenderSurfaceLayerListId(layer,
+ current_render_surface_layer_list_id);
descendants.push_back(layer);
+ }
// Any layers that are appended after this point may need to be sorted if we
// visit the children out of order.
@@ -1883,21 +2139,9 @@ static void CalculateDrawPropertiesInternal(
}
// Flatten to 2D if the layer doesn't preserve 3D.
- if (!layer->preserves_3d())
+ if (layer->should_flatten_transform())
data_for_children.parent_matrix.FlattenTo2d();
- // Apply the sublayer transform at the anchor point of the layer.
- if (!layer->sublayer_transform().IsIdentity()) {
- data_for_children.parent_matrix.Translate(
- layer->anchor_point().x() * bounds.width(),
- layer->anchor_point().y() * bounds.height());
- data_for_children.parent_matrix.PreconcatTransform(
- layer->sublayer_transform());
- data_for_children.parent_matrix.Translate(
- -layer->anchor_point().x() * bounds.width(),
- -layer->anchor_point().y() * bounds.height());
- }
-
data_for_children.scroll_compensation_matrix =
ComputeScrollCompensationMatrixForChildren(
layer,
@@ -1915,7 +2159,7 @@ static void CalculateDrawPropertiesInternal(
layer_or_ancestor_clips_descendants;
data_for_children.nearest_occlusion_immune_ancestor_surface =
nearest_occlusion_immune_ancestor_surface;
- data_for_children.subtree_is_visible_from_ancestor = layer_is_visible;
+ data_for_children.subtree_is_visible_from_ancestor = layer_is_drawn;
}
std::vector<LayerType*> sorted_children;
@@ -1931,21 +2175,29 @@ static void CalculateDrawPropertiesInternal(
LayerType* child =
layer_draw_properties.has_child_with_a_scroll_parent
? sorted_children[i]
- : LayerTreeHostCommon::get_child_as_raw_ptr(layer->children(), i);
+ : LayerTreeHostCommon::get_layer_as_raw_ptr(layer->children(), i);
child->draw_properties().index_of_first_descendants_addition =
descendants.size();
child->draw_properties().index_of_first_render_surface_layer_list_addition =
render_surface_layer_list->size();
- CalculateDrawPropertiesInternal<LayerType>(child,
- globals,
- data_for_children,
- render_surface_layer_list,
- &descendants,
- accumulated_surface_state);
+ CalculateDrawPropertiesInternal<LayerType>(
+ child,
+ globals,
+ data_for_children,
+ render_surface_layer_list,
+ &descendants,
+ accumulated_surface_state,
+ current_render_surface_layer_list_id);
if (child->render_surface() &&
+ !child->render_surface()->layer_list().empty() &&
!child->render_surface()->content_rect().IsEmpty()) {
+ // This child will contribute its render surface, which means
+ // we need to mark just the mask layer (and replica mask layer)
+ // with the id.
+ MarkMasksWithRenderSurfaceLayerListId(
+ child, current_render_surface_layer_list_id);
descendants.push_back(child);
}
@@ -1962,7 +2214,7 @@ static void CalculateDrawPropertiesInternal(
if (child_order_changed) {
SortLayerListContributions(
*layer,
- render_surface_layer_list,
+ GetLayerListForSorting(render_surface_layer_list),
render_surface_layer_list_child_sorting_start_index,
&GetNewRenderSurfacesStartIndexAndCount<LayerType>);
@@ -2072,14 +2324,14 @@ static void CalculateDrawPropertiesInternal(
render_surface_sublayer_scale.x(), render_surface_sublayer_scale.y());
surface_origin_to_replica_origin_transform.Translate(
layer->replica_layer()->position().x() +
- layer->replica_layer()->anchor_point().x() * bounds.width(),
+ layer->replica_layer()->transform_origin().x(),
layer->replica_layer()->position().y() +
- layer->replica_layer()->anchor_point().y() * bounds.height());
+ layer->replica_layer()->transform_origin().y());
surface_origin_to_replica_origin_transform.PreconcatTransform(
layer->replica_layer()->transform());
surface_origin_to_replica_origin_transform.Translate(
- -layer->replica_layer()->anchor_point().x() * bounds.width(),
- -layer->replica_layer()->anchor_point().y() * bounds.height());
+ -layer->replica_layer()->transform_origin().x(),
+ -layer->replica_layer()->transform_origin().y());
surface_origin_to_replica_origin_transform.Scale(
1.0 / render_surface_sublayer_scale.x(),
1.0 / render_surface_sublayer_scale.y());
@@ -2113,8 +2365,8 @@ static void CalculateDrawPropertiesInternal(
// drawn from back to front. If the preserves-3d property is also set on the
// parent then skip the sorting as the parent will sort all the descendants
// anyway.
- if (globals.layer_sorter && descendants.size() && layer->preserves_3d() &&
- (!layer->parent() || !layer->parent()->preserves_3d())) {
+ if (globals.layer_sorter && descendants.size() && layer->Is3dSorted() &&
+ !LayerIsInExisting3DRenderingContext(layer)) {
SortLayers(descendants.begin() + sorting_start_index,
descendants.end(),
globals.layer_sorter);
@@ -2129,54 +2381,78 @@ static void CalculateDrawPropertiesInternal(
}
}
-void LayerTreeHostCommon::CalculateDrawProperties(
- CalcDrawPropsMainInputs* inputs) {
- DCHECK(inputs->root_layer);
- DCHECK(IsRootLayer(inputs->root_layer));
- DCHECK(inputs->render_surface_layer_list);
+template <typename LayerType, typename RenderSurfaceLayerListType>
+static void ProcessCalcDrawPropsInputs(
+ const LayerTreeHostCommon::CalcDrawPropsInputs<LayerType,
+ RenderSurfaceLayerListType>&
+ inputs,
+ SubtreeGlobals<LayerType>* globals,
+ DataForRecursion<LayerType>* data_for_recursion) {
+ DCHECK(inputs.root_layer);
+ DCHECK(IsRootLayer(inputs.root_layer));
+ DCHECK(inputs.render_surface_layer_list);
+
gfx::Transform identity_matrix;
- gfx::Transform scaled_device_transform = inputs->device_transform;
- scaled_device_transform.Scale(inputs->device_scale_factor,
- inputs->device_scale_factor);
- RenderSurfaceLayerList dummy_layer_list;
// The root layer's render_surface should receive the device viewport as the
// initial clip rect.
- gfx::Rect device_viewport_rect(inputs->device_viewport_size);
+ gfx::Rect device_viewport_rect(inputs.device_viewport_size);
+
+ gfx::Vector2dF device_transform_scale_components =
+ MathUtil::ComputeTransform2dScaleComponents(inputs.device_transform, 1.f);
+ // Not handling the rare case of different x and y device scale.
+ float device_transform_scale =
+ std::max(device_transform_scale_components.x(),
+ device_transform_scale_components.y());
+
+ gfx::Transform scaled_device_transform = inputs.device_transform;
+ scaled_device_transform.Scale(inputs.device_scale_factor,
+ inputs.device_scale_factor);
+
+ globals->layer_sorter = NULL;
+ globals->max_texture_size = inputs.max_texture_size;
+ globals->device_scale_factor =
+ inputs.device_scale_factor * device_transform_scale;
+ globals->page_scale_factor = inputs.page_scale_factor;
+ globals->page_scale_application_layer = inputs.page_scale_application_layer;
+ globals->can_render_to_separate_surface =
+ inputs.can_render_to_separate_surface;
+ globals->can_adjust_raster_scales = inputs.can_adjust_raster_scales;
+
+ data_for_recursion->parent_matrix = scaled_device_transform;
+ data_for_recursion->full_hierarchy_matrix = identity_matrix;
+ data_for_recursion->scroll_compensation_matrix = identity_matrix;
+ data_for_recursion->fixed_container = inputs.root_layer;
+ data_for_recursion->clip_rect_in_target_space = device_viewport_rect;
+ data_for_recursion->clip_rect_of_target_surface_in_target_space =
+ device_viewport_rect;
+ data_for_recursion->maximum_animation_contents_scale = 0.f;
+ data_for_recursion->ancestor_is_animating_scale = false;
+ data_for_recursion->ancestor_clips_subtree = true;
+ data_for_recursion->nearest_occlusion_immune_ancestor_surface = NULL;
+ data_for_recursion->in_subtree_of_page_scale_application_layer = false;
+ data_for_recursion->subtree_can_use_lcd_text = inputs.can_use_lcd_text;
+ data_for_recursion->subtree_is_visible_from_ancestor = true;
+}
+void LayerTreeHostCommon::CalculateDrawProperties(
+ CalcDrawPropsMainInputs* inputs) {
+ LayerList dummy_layer_list;
SubtreeGlobals<Layer> globals;
- globals.layer_sorter = NULL;
- globals.max_texture_size = inputs->max_texture_size;
- globals.device_scale_factor = inputs->device_scale_factor;
- globals.page_scale_factor = inputs->page_scale_factor;
- globals.page_scale_application_layer = inputs->page_scale_application_layer;
- globals.can_render_to_separate_surface =
- inputs->can_render_to_separate_surface;
- globals.can_adjust_raster_scales = inputs->can_adjust_raster_scales;
-
DataForRecursion<Layer> data_for_recursion;
- data_for_recursion.parent_matrix = scaled_device_transform;
- data_for_recursion.full_hierarchy_matrix = identity_matrix;
- data_for_recursion.scroll_compensation_matrix = identity_matrix;
- data_for_recursion.fixed_container = inputs->root_layer;
- data_for_recursion.clip_rect_in_target_space = device_viewport_rect;
- data_for_recursion.clip_rect_of_target_surface_in_target_space =
- device_viewport_rect;
- data_for_recursion.ancestor_clips_subtree = true;
- data_for_recursion.nearest_occlusion_immune_ancestor_surface = NULL;
- data_for_recursion.in_subtree_of_page_scale_application_layer = false;
- data_for_recursion.subtree_can_use_lcd_text = inputs->can_use_lcd_text;
- data_for_recursion.subtree_is_visible_from_ancestor = true;
+ ProcessCalcDrawPropsInputs(*inputs, &globals, &data_for_recursion);
PreCalculateMetaInformationRecursiveData recursive_data;
PreCalculateMetaInformation(inputs->root_layer, &recursive_data);
std::vector<AccumulatedSurfaceState<Layer> > accumulated_surface_state;
- CalculateDrawPropertiesInternal<Layer>(inputs->root_layer,
- globals,
- data_for_recursion,
- inputs->render_surface_layer_list,
- &dummy_layer_list,
- &accumulated_surface_state);
+ CalculateDrawPropertiesInternal<Layer>(
+ inputs->root_layer,
+ globals,
+ data_for_recursion,
+ inputs->render_surface_layer_list,
+ &dummy_layer_list,
+ &accumulated_surface_state,
+ inputs->current_render_surface_layer_list_id);
// The dummy layer list should not have been used.
DCHECK_EQ(0u, dummy_layer_list.size());
@@ -2187,55 +2463,26 @@ void LayerTreeHostCommon::CalculateDrawProperties(
void LayerTreeHostCommon::CalculateDrawProperties(
CalcDrawPropsImplInputs* inputs) {
- DCHECK(inputs->root_layer);
- DCHECK(IsRootLayer(inputs->root_layer));
- DCHECK(inputs->render_surface_layer_list);
-
- gfx::Transform identity_matrix;
- gfx::Transform scaled_device_transform = inputs->device_transform;
- scaled_device_transform.Scale(inputs->device_scale_factor,
- inputs->device_scale_factor);
LayerImplList dummy_layer_list;
- LayerSorter layer_sorter;
-
- // The root layer's render_surface should receive the device viewport as the
- // initial clip rect.
- gfx::Rect device_viewport_rect(inputs->device_viewport_size);
-
SubtreeGlobals<LayerImpl> globals;
- globals.layer_sorter = &layer_sorter;
- globals.max_texture_size = inputs->max_texture_size;
- globals.device_scale_factor = inputs->device_scale_factor;
- globals.page_scale_factor = inputs->page_scale_factor;
- globals.page_scale_application_layer = inputs->page_scale_application_layer;
- globals.can_render_to_separate_surface =
- inputs->can_render_to_separate_surface;
- globals.can_adjust_raster_scales = inputs->can_adjust_raster_scales;
-
DataForRecursion<LayerImpl> data_for_recursion;
- data_for_recursion.parent_matrix = scaled_device_transform;
- data_for_recursion.full_hierarchy_matrix = identity_matrix;
- data_for_recursion.scroll_compensation_matrix = identity_matrix;
- data_for_recursion.fixed_container = inputs->root_layer;
- data_for_recursion.clip_rect_in_target_space = device_viewport_rect;
- data_for_recursion.clip_rect_of_target_surface_in_target_space =
- device_viewport_rect;
- data_for_recursion.ancestor_clips_subtree = true;
- data_for_recursion.nearest_occlusion_immune_ancestor_surface = NULL;
- data_for_recursion.in_subtree_of_page_scale_application_layer = false;
- data_for_recursion.subtree_can_use_lcd_text = inputs->can_use_lcd_text;
- data_for_recursion.subtree_is_visible_from_ancestor = true;
+ ProcessCalcDrawPropsInputs(*inputs, &globals, &data_for_recursion);
+
+ LayerSorter layer_sorter;
+ globals.layer_sorter = &layer_sorter;
PreCalculateMetaInformationRecursiveData recursive_data;
PreCalculateMetaInformation(inputs->root_layer, &recursive_data);
std::vector<AccumulatedSurfaceState<LayerImpl> >
accumulated_surface_state;
- CalculateDrawPropertiesInternal<LayerImpl>(inputs->root_layer,
- globals,
- data_for_recursion,
- inputs->render_surface_layer_list,
- &dummy_layer_list,
- &accumulated_surface_state);
+ CalculateDrawPropertiesInternal<LayerImpl>(
+ inputs->root_layer,
+ globals,
+ data_for_recursion,
+ inputs->render_surface_layer_list,
+ &dummy_layer_list,
+ &accumulated_surface_state,
+ inputs->current_render_surface_layer_list_id);
// The dummy layer list should not have been used.
DCHECK_EQ(0u, dummy_layer_list.size());
@@ -2244,182 +2491,4 @@ void LayerTreeHostCommon::CalculateDrawProperties(
DCHECK(inputs->root_layer->render_surface());
}
-static bool PointHitsRect(
- gfx::PointF screen_space_point,
- const gfx::Transform& local_space_to_screen_space_transform,
- gfx::RectF local_space_rect) {
- // If the transform is not invertible, then assume that this point doesn't hit
- // this rect.
- gfx::Transform inverse_local_space_to_screen_space(
- gfx::Transform::kSkipInitialization);
- if (!local_space_to_screen_space_transform.GetInverse(
- &inverse_local_space_to_screen_space))
- return false;
-
- // Transform the hit test point from screen space to the local space of the
- // given rect.
- bool clipped = false;
- gfx::PointF hit_test_point_in_local_space = MathUtil::ProjectPoint(
- inverse_local_space_to_screen_space, screen_space_point, &clipped);
-
- // If ProjectPoint could not project to a valid value, then we assume that
- // this point doesn't hit this rect.
- if (clipped)
- return false;
-
- return local_space_rect.Contains(hit_test_point_in_local_space);
-}
-
-static bool PointHitsRegion(gfx::PointF screen_space_point,
- const gfx::Transform& screen_space_transform,
- const Region& layer_space_region,
- float layer_content_scale_x,
- float layer_content_scale_y) {
- // If the transform is not invertible, then assume that this point doesn't hit
- // this region.
- gfx::Transform inverse_screen_space_transform(
- gfx::Transform::kSkipInitialization);
- if (!screen_space_transform.GetInverse(&inverse_screen_space_transform))
- return false;
-
- // Transform the hit test point from screen space to the local space of the
- // given region.
- bool clipped = false;
- gfx::PointF hit_test_point_in_content_space = MathUtil::ProjectPoint(
- inverse_screen_space_transform, screen_space_point, &clipped);
- gfx::PointF hit_test_point_in_layer_space =
- gfx::ScalePoint(hit_test_point_in_content_space,
- 1.f / layer_content_scale_x,
- 1.f / layer_content_scale_y);
-
- // If ProjectPoint could not project to a valid value, then we assume that
- // this point doesn't hit this region.
- if (clipped)
- return false;
-
- return layer_space_region.Contains(
- gfx::ToRoundedPoint(hit_test_point_in_layer_space));
-}
-
-static bool PointIsClippedBySurfaceOrClipRect(gfx::PointF screen_space_point,
- LayerImpl* layer) {
- LayerImpl* current_layer = layer;
-
- // Walk up the layer tree and hit-test any render_surfaces and any layer
- // clip rects that are active.
- while (current_layer) {
- if (current_layer->render_surface() &&
- !PointHitsRect(
- screen_space_point,
- current_layer->render_surface()->screen_space_transform(),
- current_layer->render_surface()->content_rect()))
- return true;
-
- // Note that drawable content rects are actually in target surface space, so
- // the transform we have to provide is the target surface's
- // screen_space_transform.
- LayerImpl* render_target = current_layer->render_target();
- if (LayerClipsSubtree(current_layer) &&
- !PointHitsRect(
- screen_space_point,
- render_target->render_surface()->screen_space_transform(),
- current_layer->drawable_content_rect()))
- return true;
-
- current_layer = current_layer->parent();
- }
-
- // If we have finished walking all ancestors without having already exited,
- // then the point is not clipped by any ancestors.
- return false;
-}
-
-LayerImpl* LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- gfx::PointF screen_space_point,
- const LayerImplList& render_surface_layer_list) {
- LayerImpl* found_layer = NULL;
-
- typedef LayerIterator<LayerImpl,
- LayerImplList,
- RenderSurfaceImpl,
- LayerIteratorActions::FrontToBack> LayerIteratorType;
- LayerIteratorType end = LayerIteratorType::End(&render_surface_layer_list);
-
- for (LayerIteratorType
- it = LayerIteratorType::Begin(&render_surface_layer_list);
- it != end;
- ++it) {
- // We don't want to consider render_surfaces for hit testing.
- if (!it.represents_itself())
- continue;
-
- LayerImpl* current_layer = (*it);
-
- gfx::RectF content_rect(current_layer->content_bounds());
- if (!PointHitsRect(screen_space_point,
- current_layer->screen_space_transform(),
- content_rect))
- continue;
-
- // At this point, we think the point does hit the layer, but we need to walk
- // up the parents to ensure that the layer was not clipped in such a way
- // that the hit point actually should not hit the layer.
- if (PointIsClippedBySurfaceOrClipRect(screen_space_point, current_layer))
- continue;
-
- // Skip the HUD layer.
- if (current_layer == current_layer->layer_tree_impl()->hud_layer())
- continue;
-
- found_layer = current_layer;
- break;
- }
-
- // This can potentially return NULL, which means the screen_space_point did
- // not successfully hit test any layers, not even the root layer.
- return found_layer;
-}
-
-LayerImpl* LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
- gfx::PointF screen_space_point,
- const LayerImplList& render_surface_layer_list) {
- // First find out which layer was hit from the saved list of visible layers
- // in the most recent frame.
- LayerImpl* layer_impl = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- screen_space_point,
- render_surface_layer_list);
-
- // Walk up the hierarchy and look for a layer with a touch event handler
- // region that the given point hits.
- // This walk may not be necessary anymore: http://crbug.com/310817
- for (; layer_impl; layer_impl = layer_impl->parent()) {
- if (LayerTreeHostCommon::LayerHasTouchEventHandlersAt(screen_space_point,
- layer_impl))
- break;
- }
- return layer_impl;
-}
-
-bool LayerTreeHostCommon::LayerHasTouchEventHandlersAt(
- gfx::PointF screen_space_point,
- LayerImpl* layer_impl) {
- if (layer_impl->touch_event_handler_region().IsEmpty())
- return false;
-
- if (!PointHitsRegion(screen_space_point,
- layer_impl->screen_space_transform(),
- layer_impl->touch_event_handler_region(),
- layer_impl->contents_scale_x(),
- layer_impl->contents_scale_y()))
- return false;
-
- // At this point, we think the point does hit the touch event handler region
- // on the layer, but we need to walk up the parents to ensure that the layer
- // was not clipped in such a way that the hit point actually should not hit
- // the layer.
- if (PointIsClippedBySurfaceOrClipRect(screen_space_point, layer_impl))
- return false;
-
- return true;
-}
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_host_common.h b/chromium/cc/trees/layer_tree_host_common.h
index 727244864ee..0e139471739 100644
--- a/chromium/cc/trees/layer_tree_host_common.h
+++ b/chromium/cc/trees/layer_tree_host_common.h
@@ -24,15 +24,15 @@ class Layer;
class CC_EXPORT LayerTreeHostCommon {
public:
- static gfx::Rect CalculateVisibleRect(gfx::Rect target_surface_rect,
- gfx::Rect layer_bound_rect,
+ static gfx::Rect CalculateVisibleRect(const gfx::Rect& target_surface_rect,
+ const gfx::Rect& layer_bound_rect,
const gfx::Transform& transform);
template <typename LayerType, typename RenderSurfaceLayerListType>
struct CalcDrawPropsInputs {
public:
CalcDrawPropsInputs(LayerType* root_layer,
- gfx::Size device_viewport_size,
+ const gfx::Size& device_viewport_size,
const gfx::Transform& device_transform,
float device_scale_factor,
float page_scale_factor,
@@ -41,7 +41,8 @@ class CC_EXPORT LayerTreeHostCommon {
bool can_use_lcd_text,
bool can_render_to_separate_surface,
bool can_adjust_raster_scales,
- RenderSurfaceLayerListType* render_surface_layer_list)
+ RenderSurfaceLayerListType* render_surface_layer_list,
+ int current_render_surface_layer_list_id)
: root_layer(root_layer),
device_viewport_size(device_viewport_size),
device_transform(device_transform),
@@ -52,7 +53,9 @@ class CC_EXPORT LayerTreeHostCommon {
can_use_lcd_text(can_use_lcd_text),
can_render_to_separate_surface(can_render_to_separate_surface),
can_adjust_raster_scales(can_adjust_raster_scales),
- render_surface_layer_list(render_surface_layer_list) {}
+ render_surface_layer_list(render_surface_layer_list),
+ current_render_surface_layer_list_id(
+ current_render_surface_layer_list_id) {}
LayerType* root_layer;
gfx::Size device_viewport_size;
@@ -65,6 +68,7 @@ class CC_EXPORT LayerTreeHostCommon {
bool can_render_to_separate_surface;
bool can_adjust_raster_scales;
RenderSurfaceLayerListType* render_surface_layer_list;
+ int current_render_surface_layer_list_id;
};
template <typename LayerType, typename RenderSurfaceLayerListType>
@@ -72,12 +76,12 @@ class CC_EXPORT LayerTreeHostCommon {
: public CalcDrawPropsInputs<LayerType, RenderSurfaceLayerListType> {
CalcDrawPropsInputsForTesting(
LayerType* root_layer,
- gfx::Size device_viewport_size,
+ const gfx::Size& device_viewport_size,
const gfx::Transform& device_transform,
RenderSurfaceLayerListType* render_surface_layer_list);
CalcDrawPropsInputsForTesting(
LayerType* root_layer,
- gfx::Size device_viewport_size,
+ const gfx::Size& device_viewport_size,
RenderSurfaceLayerListType* render_surface_layer_list);
private:
@@ -95,18 +99,6 @@ class CC_EXPORT LayerTreeHostCommon {
CalcDrawPropsImplInputsForTesting;
static void CalculateDrawProperties(CalcDrawPropsImplInputs* inputs);
- // Performs hit testing for a given render_surface_layer_list.
- static LayerImpl* FindLayerThatIsHitByPoint(
- gfx::PointF screen_space_point,
- const LayerImplList& render_surface_layer_list);
-
- static LayerImpl* FindLayerThatIsHitByPointInTouchHandlerRegion(
- gfx::PointF screen_space_point,
- const LayerImplList& render_surface_layer_list);
-
- static bool LayerHasTouchEventHandlersAt(gfx::PointF screen_space_point,
- LayerImpl* layer_impl);
-
template <typename LayerType>
static bool RenderSurfaceContributesToTarget(LayerType*,
int target_surface_layer_id);
@@ -121,16 +113,18 @@ class CC_EXPORT LayerTreeHostCommon {
template <typename LayerType>
static LayerType* FindLayerInSubtree(LayerType* root_layer, int layer_id);
- static Layer* get_child_as_raw_ptr(
- const LayerList& children,
- size_t index) {
- return children[index].get();
+ static Layer* get_layer_as_raw_ptr(const LayerList& layers, size_t index) {
+ return layers[index].get();
+ }
+
+ static LayerImpl* get_layer_as_raw_ptr(const OwnedLayerImplList& layers,
+ size_t index) {
+ return layers[index];
}
- static LayerImpl* get_child_as_raw_ptr(
- const OwnedLayerImplList& children,
- size_t index) {
- return children[index];
+ static LayerImpl* get_layer_as_raw_ptr(const LayerImplList& layers,
+ size_t index) {
+ return layers[index];
}
struct ScrollUpdateInfo {
@@ -180,7 +174,7 @@ LayerType* LayerTreeHostCommon::FindLayerInSubtree(LayerType* root_layer,
for (size_t i = 0; i < root_layer->children().size(); ++i) {
if (LayerType* found = FindLayerInSubtree(
- get_child_as_raw_ptr(root_layer->children(), i), layer_id))
+ get_layer_as_raw_ptr(root_layer->children(), i), layer_id))
return found;
}
return NULL;
@@ -201,7 +195,7 @@ void LayerTreeHostCommon::CallFunctionForSubtree(
}
for (size_t i = 0; i < root_layer->children().size(); ++i) {
- CallFunctionForSubtree(get_child_as_raw_ptr(root_layer->children(), i),
+ CallFunctionForSubtree(get_layer_as_raw_ptr(root_layer->children(), i),
function);
}
}
@@ -211,7 +205,7 @@ LayerTreeHostCommon::CalcDrawPropsInputsForTesting<LayerType,
RenderSurfaceLayerListType>::
CalcDrawPropsInputsForTesting(
LayerType* root_layer,
- gfx::Size device_viewport_size,
+ const gfx::Size& device_viewport_size,
const gfx::Transform& device_transform,
RenderSurfaceLayerListType* render_surface_layer_list)
: CalcDrawPropsInputs<LayerType, RenderSurfaceLayerListType>(
@@ -225,7 +219,8 @@ LayerTreeHostCommon::CalcDrawPropsInputsForTesting<LayerType,
false,
true,
false,
- render_surface_layer_list) {
+ render_surface_layer_list,
+ 0) {
DCHECK(root_layer);
DCHECK(render_surface_layer_list);
}
@@ -235,7 +230,7 @@ LayerTreeHostCommon::CalcDrawPropsInputsForTesting<LayerType,
RenderSurfaceLayerListType>::
CalcDrawPropsInputsForTesting(
LayerType* root_layer,
- gfx::Size device_viewport_size,
+ const gfx::Size& device_viewport_size,
RenderSurfaceLayerListType* render_surface_layer_list)
: CalcDrawPropsInputs<LayerType, RenderSurfaceLayerListType>(
root_layer,
@@ -248,7 +243,8 @@ LayerTreeHostCommon::CalcDrawPropsInputsForTesting<LayerType,
false,
true,
false,
- render_surface_layer_list) {
+ render_surface_layer_list,
+ 0) {
DCHECK(root_layer);
DCHECK(render_surface_layer_list);
}
diff --git a/chromium/cc/trees/layer_tree_host_common_perftest.cc b/chromium/cc/trees/layer_tree_host_common_perftest.cc
index 7b63b2a0c51..02b0770495b 100644
--- a/chromium/cc/trees/layer_tree_host_common_perftest.cc
+++ b/chromium/cc/trees/layer_tree_host_common_perftest.cc
@@ -12,13 +12,14 @@
#include "base/strings/string_piece.h"
#include "base/threading/thread.h"
#include "base/time/time.h"
+#include "cc/debug/lap_timer.h"
#include "cc/layers/layer.h"
#include "cc/test/fake_content_layer_client.h"
#include "cc/test/fake_layer_tree_host_client.h"
-#include "cc/test/lap_timer.h"
#include "cc/test/layer_tree_json_parser.h"
#include "cc/test/layer_tree_test.h"
#include "cc/test/paths.h"
+#include "cc/trees/layer_sorter.h"
#include "cc/trees/layer_tree_impl.h"
#include "testing/perf/perf_test.h"
@@ -97,7 +98,8 @@ class CalcDrawPropsMainTest : public LayerTreeHostCommonPerfTest {
layer_tree_host()
->settings()
.layer_transforms_should_scale_layer_contents,
- &update_list);
+ &update_list,
+ 0);
LayerTreeHostCommon::CalculateDrawProperties(&inputs);
timer_.NextLap();
@@ -124,48 +126,107 @@ class CalcDrawPropsImplTest : public LayerTreeHostCommonPerfTest {
do {
bool can_render_to_separate_surface = true;
int max_texture_size = 8096;
- LayerImplList update_list;
- LayerTreeHostCommon::CalcDrawPropsImplInputs inputs(
- active_tree->root_layer(),
- active_tree->DrawViewportSize(),
- host_impl->DrawTransform(),
- active_tree->device_scale_factor(),
- active_tree->total_page_scale_factor(),
- active_tree->RootContainerLayer(),
- max_texture_size,
- host_impl->settings().can_use_lcd_text,
- can_render_to_separate_surface,
- host_impl->settings().layer_transforms_should_scale_layer_contents,
- &update_list);
- LayerTreeHostCommon::CalculateDrawProperties(&inputs);
+ DoCalcDrawPropertiesImpl(can_render_to_separate_surface,
+ max_texture_size,
+ active_tree,
+ host_impl);
+
+ timer_.NextLap();
+ } while (!timer_.HasTimeLimitExpired());
+
+ EndTest();
+ }
+
+ void DoCalcDrawPropertiesImpl(bool can_render_to_separate_surface,
+ int max_texture_size,
+ LayerTreeImpl* active_tree,
+ LayerTreeHostImpl* host_impl) {
+ LayerImplList update_list;
+ LayerTreeHostCommon::CalcDrawPropsImplInputs inputs(
+ active_tree->root_layer(),
+ active_tree->DrawViewportSize(),
+ host_impl->DrawTransform(),
+ active_tree->device_scale_factor(),
+ active_tree->total_page_scale_factor(),
+ active_tree->InnerViewportContainerLayer(),
+ max_texture_size,
+ host_impl->settings().can_use_lcd_text,
+ can_render_to_separate_surface,
+ host_impl->settings().layer_transforms_should_scale_layer_contents,
+ &update_list,
+ 0);
+ LayerTreeHostCommon::CalculateDrawProperties(&inputs);
+ }
+};
+
+class LayerSorterMainTest : public CalcDrawPropsImplTest {
+ public:
+ void RunSortLayers() { RunTest(false, false, false); }
+
+ virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
+
+ virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
+ 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);
+ // Behaviour of this test is different from that of sorting in practice.
+ // In this case, all layers that exist in any 3D context are put into a list
+ // and are sorted as one big 3D context instead of several smaller ones.
+ BuildLayerImplList(active_tree->root_layer(), &base_list_);
+ timer_.Reset();
+ do {
+ // Here we'll move the layers into a LayerImpl list of their own to be
+ // sorted so we don't have a sorted list for every run after the first
+ LayerImplList test_list = base_list_;
+ layer_sorter_.Sort(test_list.begin(), test_list.end());
timer_.NextLap();
} while (!timer_.HasTimeLimitExpired());
EndTest();
}
+
+ void BuildLayerImplList(LayerImpl* layer, LayerImplList* list) {
+ if (layer->Is3dSorted()) {
+ list->push_back(layer);
+ }
+
+ for (unsigned int i = 0; i < layer->children().size(); i++) {
+ BuildLayerImplList(layer->children()[i], list);
+ }
+ }
+
+ private:
+ LayerImplList base_list_;
+ LayerSorter layer_sorter_;
};
TEST_F(CalcDrawPropsMainTest, TenTen) {
- SetTestName("10_10");
+ SetTestName("10_10_main_thread");
ReadTestFile("10_10_layer_tree");
RunCalcDrawProps();
}
TEST_F(CalcDrawPropsMainTest, HeavyPage) {
- SetTestName("heavy_page");
+ SetTestName("heavy_page_main_thread");
ReadTestFile("heavy_layer_tree");
RunCalcDrawProps();
}
TEST_F(CalcDrawPropsMainTest, TouchRegionLight) {
- SetTestName("touch_region_light");
+ SetTestName("touch_region_light_main_thread");
ReadTestFile("touch_region_light");
RunCalcDrawProps();
}
TEST_F(CalcDrawPropsMainTest, TouchRegionHeavy) {
- SetTestName("touch_region_heavy");
+ SetTestName("touch_region_heavy_main_thread");
ReadTestFile("touch_region_heavy");
RunCalcDrawProps();
}
@@ -194,5 +255,17 @@ TEST_F(CalcDrawPropsImplTest, TouchRegionHeavy) {
RunCalcDrawProps();
}
+TEST_F(LayerSorterMainTest, LayerSorterCubes) {
+ SetTestName("layer_sort_cubes");
+ ReadTestFile("layer_sort_cubes");
+ RunSortLayers();
+}
+
+TEST_F(LayerSorterMainTest, LayerSorterRubik) {
+ SetTestName("layer_sort_rubik");
+ ReadTestFile("layer_sort_rubik");
+ RunSortLayers();
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_host_common_unittest.cc b/chromium/cc/trees/layer_tree_host_common_unittest.cc
index 58d82ceda4a..8dcb6d7ad1e 100644
--- a/chromium/cc/trees/layer_tree_host_common_unittest.cc
+++ b/chromium/cc/trees/layer_tree_host_common_unittest.cc
@@ -7,13 +7,14 @@
#include <set>
#include "cc/animation/layer_animation_controller.h"
+#include "cc/animation/transform_operations.h"
#include "cc/base/math_util.h"
#include "cc/layers/content_layer.h"
#include "cc/layers/content_layer_client.h"
-#include "cc/layers/heads_up_display_layer_impl.h"
#include "cc/layers/layer.h"
#include "cc/layers/layer_client.h"
#include "cc/layers/layer_impl.h"
+#include "cc/layers/layer_iterator.h"
#include "cc/layers/render_surface.h"
#include "cc/layers/render_surface_impl.h"
#include "cc/output/copy_output_request.h"
@@ -23,182 +24,74 @@
#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_tree_host_common_test.h"
#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/proxy.h"
#include "cc/trees/single_thread_proxy.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/quad_f.h"
-#include "ui/gfx/size_conversions.h"
#include "ui/gfx/transform.h"
namespace cc {
namespace {
-class LayerTreeHostCommonTestBase {
- protected:
- template <typename LayerType>
- void SetLayerPropertiesForTestingInternal(
- LayerType* layer,
- const gfx::Transform& transform,
- const gfx::Transform& sublayer_transform,
- gfx::PointF anchor,
- gfx::PointF position,
- gfx::Size bounds,
- bool preserves3d) {
- layer->SetTransform(transform);
- layer->SetSublayerTransform(sublayer_transform);
- layer->SetAnchorPoint(anchor);
- layer->SetPosition(position);
- layer->SetBounds(bounds);
- layer->SetPreserves3d(preserves3d);
- }
-
- void SetLayerPropertiesForTesting(Layer* layer,
- const gfx::Transform& transform,
- const gfx::Transform& sublayer_transform,
- gfx::PointF anchor,
- gfx::PointF position,
- gfx::Size bounds,
- bool preserves3d) {
- SetLayerPropertiesForTestingInternal<Layer>(layer,
- transform,
- sublayer_transform,
- anchor,
- position,
- bounds,
- preserves3d);
- }
-
- void SetLayerPropertiesForTesting(LayerImpl* layer,
- const gfx::Transform& transform,
- const gfx::Transform& sublayer_transform,
- gfx::PointF anchor,
- gfx::PointF position,
- gfx::Size bounds,
- bool preserves3d) {
- SetLayerPropertiesForTestingInternal<LayerImpl>(layer,
- transform,
- sublayer_transform,
- anchor,
- position,
- bounds,
- preserves3d);
- layer->SetContentBounds(bounds);
- }
-
- void ExecuteCalculateDrawProperties(Layer* root_layer,
- float device_scale_factor,
- float page_scale_factor,
- Layer* page_scale_application_layer,
- bool can_use_lcd_text) {
- EXPECT_TRUE(page_scale_application_layer || (page_scale_factor == 1.f));
- gfx::Transform identity_matrix;
- gfx::Size device_viewport_size =
- gfx::Size(root_layer->bounds().width() * device_scale_factor,
- root_layer->bounds().height() * device_scale_factor);
-
- render_surface_layer_list_.reset(new RenderSurfaceLayerList);
-
- // We are probably not testing what is intended if the root_layer bounds are
- // empty.
- DCHECK(!root_layer->bounds().IsEmpty());
- LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs(
- root_layer, device_viewport_size, render_surface_layer_list_.get());
- inputs.device_scale_factor = device_scale_factor;
- inputs.page_scale_factor = page_scale_factor;
- inputs.page_scale_application_layer = page_scale_application_layer;
- inputs.can_use_lcd_text = can_use_lcd_text;
- inputs.can_adjust_raster_scales = true;
- LayerTreeHostCommon::CalculateDrawProperties(&inputs);
- }
-
- void ExecuteCalculateDrawProperties(LayerImpl* root_layer,
- float device_scale_factor,
- float page_scale_factor,
- LayerImpl* page_scale_application_layer,
- bool can_use_lcd_text) {
- gfx::Transform identity_matrix;
- LayerImplList dummy_render_surface_layer_list;
- gfx::Size device_viewport_size =
- gfx::Size(root_layer->bounds().width() * device_scale_factor,
- root_layer->bounds().height() * device_scale_factor);
-
- // 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, &dummy_render_surface_layer_list);
- inputs.device_scale_factor = device_scale_factor;
- inputs.page_scale_factor = page_scale_factor;
- inputs.page_scale_application_layer = page_scale_application_layer;
- inputs.can_use_lcd_text = can_use_lcd_text;
- inputs.can_adjust_raster_scales = true;
- LayerTreeHostCommon::CalculateDrawProperties(&inputs);
- }
-
- template <class LayerType>
- void ExecuteCalculateDrawProperties(LayerType* root_layer) {
- LayerType* page_scale_application_layer = NULL;
- ExecuteCalculateDrawProperties(
- root_layer, 1.f, 1.f, page_scale_application_layer, false);
- }
-
- template <class LayerType>
- void ExecuteCalculateDrawProperties(LayerType* root_layer,
- float device_scale_factor) {
- LayerType* page_scale_application_layer = NULL;
- ExecuteCalculateDrawProperties(root_layer,
- device_scale_factor,
- 1.f,
- page_scale_application_layer,
- false);
- }
-
- template <class LayerType>
- void ExecuteCalculateDrawProperties(LayerType* root_layer,
- float device_scale_factor,
- float page_scale_factor,
- LayerType* page_scale_application_layer) {
- ExecuteCalculateDrawProperties(root_layer,
- device_scale_factor,
- page_scale_factor,
- page_scale_application_layer,
- false);
- }
-
- RenderSurfaceLayerList* render_surface_layer_list() const {
- return render_surface_layer_list_.get();
- }
-
- private:
- scoped_ptr<RenderSurfaceLayerList> render_surface_layer_list_;
-};
-
-class LayerTreeHostCommonTest : public LayerTreeHostCommonTestBase,
- public testing::Test {
-};
-
class LayerWithForcedDrawsContent : public Layer {
public:
- LayerWithForcedDrawsContent() : Layer() {}
+ LayerWithForcedDrawsContent() : Layer(), last_device_scale_factor_(0.f) {}
virtual bool DrawsContent() const OVERRIDE;
+ virtual void CalculateContentsScale(float ideal_contents_scale,
+ float device_scale_factor,
+ float page_scale_factor,
+ float maximum_animation_contents_scale,
+ bool animating_transform_to_screen,
+ float* contents_scale_x,
+ float* contents_scale_y,
+ gfx::Size* content_bounds) OVERRIDE;
+
+ float last_device_scale_factor() const { return last_device_scale_factor_; }
private:
virtual ~LayerWithForcedDrawsContent() {}
+
+ // Parameters from last CalculateContentsScale.
+ float last_device_scale_factor_;
};
bool LayerWithForcedDrawsContent::DrawsContent() const { return true; }
+void LayerWithForcedDrawsContent::CalculateContentsScale(
+ float ideal_contents_scale,
+ float device_scale_factor,
+ float page_scale_factor,
+ float maximum_animation_contents_scale,
+ bool animating_transform_to_screen,
+ float* contents_scale_x,
+ float* contents_scale_y,
+ gfx::Size* content_bounds) {
+ last_device_scale_factor_ = device_scale_factor;
+ Layer::CalculateContentsScale(ideal_contents_scale,
+ device_scale_factor,
+ page_scale_factor,
+ maximum_animation_contents_scale,
+ animating_transform_to_screen,
+ contents_scale_x,
+ contents_scale_y,
+ content_bounds);
+}
+
class MockContentLayerClient : public ContentLayerClient {
public:
MockContentLayerClient() {}
virtual ~MockContentLayerClient() {}
- virtual void PaintContents(SkCanvas* canvas,
- gfx::Rect clip,
- gfx::RectF* opaque) OVERRIDE {}
+ virtual void PaintContents(
+ SkCanvas* canvas,
+ const gfx::Rect& clip,
+ gfx::RectF* opaque,
+ ContentLayerClient::GraphicsContextStatus gc_status) OVERRIDE {}
virtual void DidChangeLayerCanUseLCDText() OVERRIDE {}
+ virtual bool FillsBoundsCompletely() const OVERRIDE { return false; }
};
scoped_refptr<ContentLayer> CreateDrawableContentLayer(
@@ -232,24 +125,24 @@ TEST_F(LayerTreeHostCommonTest, TransformsForNoOpLayer) {
gfx::Transform identity_matrix;
SetLayerPropertiesForTesting(parent.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ true,
false);
SetLayerPropertiesForTesting(child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(),
+ true,
false);
SetLayerPropertiesForTesting(grand_child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(),
+ true,
false);
ExecuteCalculateDrawProperties(parent.get());
@@ -263,6 +156,52 @@ TEST_F(LayerTreeHostCommonTest, TransformsForNoOpLayer) {
grand_child->screen_space_transform());
}
+TEST_F(LayerTreeHostCommonTest, DoNotSkipLayersWithHandlers) {
+ scoped_refptr<Layer> parent = Layer::Create();
+ scoped_refptr<Layer> child = Layer::Create();
+ scoped_refptr<Layer> grand_child = Layer::Create();
+ parent->AddChild(child);
+ child->AddChild(grand_child);
+
+ scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create();
+ host->SetRootLayer(parent);
+
+ gfx::Transform identity_matrix;
+ SetLayerPropertiesForTesting(parent.get(),
+ identity_matrix,
+ gfx::Point3F(),
+ gfx::PointF(),
+ gfx::Size(100, 100),
+ true,
+ false);
+ SetLayerPropertiesForTesting(child.get(),
+ identity_matrix,
+ gfx::Point3F(),
+ gfx::PointF(10, 10),
+ gfx::Size(100, 100),
+ true,
+ false);
+ // This would have previously caused us to skip our subtree, but this would be
+ // wrong; we need up-to-date draw properties to do hit testing on the layers
+ // with handlers.
+ child->SetOpacity(0.f);
+ SetLayerPropertiesForTesting(grand_child.get(),
+ identity_matrix,
+ gfx::Point3F(),
+ gfx::PointF(10, 10),
+ gfx::Size(100, 100),
+ true,
+ false);
+ grand_child->SetTouchEventHandlerRegion(gfx::Rect(0, 0, 100, 100));
+
+ ExecuteCalculateDrawProperties(parent.get());
+
+ // Check that we've computed draw properties for the subtree rooted at
+ // |child|.
+ EXPECT_FALSE(child->draw_transform().IsIdentity());
+ EXPECT_FALSE(grand_child->draw_transform().IsIdentity());
+}
+
TEST_F(LayerTreeHostCommonTest, TransformsForSingleLayer) {
gfx::Transform identity_matrix;
scoped_refptr<Layer> layer = Layer::Create();
@@ -270,44 +209,26 @@ TEST_F(LayerTreeHostCommonTest, TransformsForSingleLayer) {
scoped_refptr<Layer> root = Layer::Create();
SetLayerPropertiesForTesting(root.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(1, 2),
+ true,
false);
root->AddChild(layer);
scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create();
host->SetRootLayer(root);
- // Case 1: setting the sublayer transform should not affect this layer's draw
- // transform or screen-space transform.
- gfx::Transform arbitrary_translation;
- arbitrary_translation.Translate(10.0, 20.0);
- SetLayerPropertiesForTesting(layer.get(),
- identity_matrix,
- arbitrary_translation,
- gfx::PointF(),
- gfx::PointF(),
- gfx::Size(100, 100),
- false);
- ExecuteCalculateDrawProperties(root.get());
- gfx::Transform expected_draw_transform = identity_matrix;
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected_draw_transform,
- layer->draw_transform());
- EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix,
- layer->screen_space_transform());
-
// Case 2: Setting the bounds of the layer should not affect either the draw
// transform or the screenspace transform.
gfx::Transform translation_to_center;
translation_to_center.Translate(5.0, 6.0);
SetLayerPropertiesForTesting(layer.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(10, 12),
+ true,
false);
ExecuteCalculateDrawProperties(root.get());
EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, layer->draw_transform());
@@ -318,10 +239,10 @@ TEST_F(LayerTreeHostCommonTest, TransformsForSingleLayer) {
// no effect on the transforms.
SetLayerPropertiesForTesting(layer.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(0.25f, 0.25f),
+ gfx::Point3F(2.5f, 3.0f, 0.f),
gfx::PointF(),
gfx::Size(10, 12),
+ true,
false);
ExecuteCalculateDrawProperties(root.get());
EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, layer->draw_transform());
@@ -334,10 +255,10 @@ TEST_F(LayerTreeHostCommonTest, TransformsForSingleLayer) {
position_transform.Translate(0.f, 1.2f);
SetLayerPropertiesForTesting(layer.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(0.25f, 0.25f),
+ gfx::Point3F(2.5f, 3.0f, 0.f),
gfx::PointF(0.f, 1.2f),
gfx::Size(10, 12),
+ true,
false);
ExecuteCalculateDrawProperties(root.get());
EXPECT_TRANSFORMATION_MATRIX_EQ(position_transform, layer->draw_transform());
@@ -351,10 +272,10 @@ TEST_F(LayerTreeHostCommonTest, TransformsForSingleLayer) {
layer_transform.Scale3d(2.0, 2.0, 1.0);
SetLayerPropertiesForTesting(layer.get(),
layer_transform,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(10, 12),
+ true,
false);
ExecuteCalculateDrawProperties(root.get());
EXPECT_TRANSFORMATION_MATRIX_EQ(layer_transform, layer->draw_transform());
@@ -368,10 +289,10 @@ TEST_F(LayerTreeHostCommonTest, TransformsForSingleLayer) {
translation_to_anchor * layer_transform * Inverse(translation_to_anchor);
SetLayerPropertiesForTesting(layer.get(),
layer_transform,
- identity_matrix,
- gfx::PointF(0.5f, 0.f),
+ gfx::Point3F(5.0f, 0.f, 0.f),
gfx::PointF(),
gfx::Size(10, 12),
+ true,
false);
ExecuteCalculateDrawProperties(root.get());
EXPECT_TRANSFORMATION_MATRIX_EQ(expected_result, layer->draw_transform());
@@ -385,10 +306,10 @@ TEST_F(LayerTreeHostCommonTest, TransformsForSingleLayer) {
layer_transform * Inverse(translation_to_anchor);
SetLayerPropertiesForTesting(layer.get(),
layer_transform,
- identity_matrix,
- gfx::PointF(0.5f, 0.f),
+ gfx::Point3F(5.0f, 0.f, 0.f),
gfx::PointF(0.f, 1.2f),
gfx::Size(10, 12),
+ true,
false);
ExecuteCalculateDrawProperties(root.get());
EXPECT_TRANSFORMATION_MATRIX_EQ(expected_result, layer->draw_transform());
@@ -406,7 +327,8 @@ TEST_F(LayerTreeHostCommonTest, TransformsAboutScrollOffset) {
const float kDeviceScale = 1.666f;
FakeImplProxy proxy;
- FakeLayerTreeHostImpl host_impl(&proxy);
+ TestSharedBitmapManager shared_bitmap_manager;
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
gfx::Transform identity_matrix;
scoped_ptr<LayerImpl> sublayer_scoped_ptr(
@@ -416,38 +338,47 @@ TEST_F(LayerTreeHostCommonTest, TransformsAboutScrollOffset) {
kPageScale * kDeviceScale);
SetLayerPropertiesForTesting(sublayer,
identity_matrix,
- identity_matrix,
- gfx::Point(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(500, 500),
+ true,
false);
- scoped_ptr<LayerImpl> scroll_layerScopedPtr(
+ scoped_ptr<LayerImpl> scroll_layer_scoped_ptr(
LayerImpl::Create(host_impl.active_tree(), 2));
- LayerImpl* scroll_layer = scroll_layerScopedPtr.get();
+ LayerImpl* scroll_layer = scroll_layer_scoped_ptr.get();
SetLayerPropertiesForTesting(scroll_layer,
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(10, 20),
+ true,
false);
- scroll_layer->SetScrollable(true);
- scroll_layer->SetMaxScrollOffset(kMaxScrollOffset);
- scroll_layer->SetScrollOffset(kScrollOffset);
+ scoped_ptr<LayerImpl> clip_layer_scoped_ptr(
+ LayerImpl::Create(host_impl.active_tree(), 4));
+ LayerImpl* clip_layer = clip_layer_scoped_ptr.get();
+
+ scroll_layer->SetScrollClipLayer(clip_layer->id());
+ clip_layer->SetBounds(
+ gfx::Size(scroll_layer->bounds().width() + kMaxScrollOffset.x(),
+ scroll_layer->bounds().height() + kMaxScrollOffset.y()));
+ scroll_layer->SetScrollClipLayer(clip_layer->id());
scroll_layer->SetScrollDelta(kScrollDelta);
gfx::Transform impl_transform;
scroll_layer->AddChild(sublayer_scoped_ptr.Pass());
+ LayerImpl* scroll_layer_raw_ptr = scroll_layer_scoped_ptr.get();
+ clip_layer->AddChild(scroll_layer_scoped_ptr.Pass());
+ scroll_layer_raw_ptr->SetScrollOffset(kScrollOffset);
scoped_ptr<LayerImpl> root(LayerImpl::Create(host_impl.active_tree(), 3));
SetLayerPropertiesForTesting(root.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(3, 4),
+ true,
false);
- root->AddChild(scroll_layerScopedPtr.Pass());
+ root->AddChild(clip_layer_scoped_ptr.Pass());
ExecuteCalculateDrawProperties(
root.get(), kDeviceScale, kPageScale, scroll_layer->parent());
@@ -467,10 +398,10 @@ TEST_F(LayerTreeHostCommonTest, TransformsAboutScrollOffset) {
arbitrary_translate.Translate(kTranslateX, kTranslateY);
SetLayerPropertiesForTesting(scroll_layer,
arbitrary_translate,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(10, 20),
+ true,
false);
ExecuteCalculateDrawProperties(
root.get(), kDeviceScale, kPageScale, scroll_layer->parent());
@@ -500,33 +431,33 @@ TEST_F(LayerTreeHostCommonTest, TransformsForSimpleHierarchy) {
// One-time setup of root layer
SetLayerPropertiesForTesting(root.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(1, 2),
+ true,
false);
// Case 1: parent's anchor point should not affect child or grand_child.
SetLayerPropertiesForTesting(parent.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(0.25f, 0.25f),
+ gfx::Point3F(2.5f, 3.0f, 0.f),
gfx::PointF(),
gfx::Size(10, 12),
+ true,
false);
SetLayerPropertiesForTesting(child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(16, 18),
+ true,
false);
SetLayerPropertiesForTesting(grand_child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(76, 78),
+ true,
false);
ExecuteCalculateDrawProperties(root.get());
EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, child->draw_transform());
@@ -542,24 +473,24 @@ TEST_F(LayerTreeHostCommonTest, TransformsForSimpleHierarchy) {
parent_position_transform.Translate(0.f, 1.2f);
SetLayerPropertiesForTesting(parent.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(0.25f, 0.25f),
+ gfx::Point3F(2.5f, 3.0f, 0.f),
gfx::PointF(0.f, 1.2f),
gfx::Size(10, 12),
+ true,
false);
SetLayerPropertiesForTesting(child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(16, 18),
+ true,
false);
SetLayerPropertiesForTesting(grand_child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(76, 78),
+ true,
false);
ExecuteCalculateDrawProperties(root.get());
EXPECT_TRANSFORMATION_MATRIX_EQ(parent_position_transform,
@@ -581,103 +512,24 @@ TEST_F(LayerTreeHostCommonTest, TransformsForSimpleHierarchy) {
Inverse(parent_translation_to_anchor);
SetLayerPropertiesForTesting(parent.get(),
parent_layer_transform,
- identity_matrix,
- gfx::PointF(0.25f, 0.25f),
+ gfx::Point3F(2.5f, 3.0f, 0.f),
gfx::PointF(),
gfx::Size(10, 12),
+ true,
false);
SetLayerPropertiesForTesting(child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(16, 18),
+ true,
false);
SetLayerPropertiesForTesting(grand_child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
- gfx::PointF(),
- gfx::Size(76, 78),
- false);
- ExecuteCalculateDrawProperties(root.get());
- EXPECT_TRANSFORMATION_MATRIX_EQ(parent_composite_transform,
- child->draw_transform());
- EXPECT_TRANSFORMATION_MATRIX_EQ(parent_composite_transform,
- child->screen_space_transform());
- EXPECT_TRANSFORMATION_MATRIX_EQ(parent_composite_transform,
- grand_child->draw_transform());
- EXPECT_TRANSFORMATION_MATRIX_EQ(parent_composite_transform,
- grand_child->screen_space_transform());
-
- // Case 4: parent's sublayer matrix affects child and grandchild scaling is
- // used here again so that the correct sequence of transforms is properly
- // tested. Note that preserves3d is false, but the sublayer matrix should
- // retain its 3D properties when given to child. But then, the child also
- // does not preserve3D. When it gives its hierarchy to the grand_child, it
- // should be flattened to 2D.
- gfx::Transform parent_sublayer_matrix;
- parent_sublayer_matrix.Scale3d(10.f, 10.f, 3.3f);
- // Sublayer matrix is applied to the anchor point of the parent layer.
- parent_composite_transform =
- parent_translation_to_anchor * parent_layer_transform *
- Inverse(parent_translation_to_anchor) * parent_translation_to_anchor *
- parent_sublayer_matrix * Inverse(parent_translation_to_anchor);
- gfx::Transform flattened_composite_transform = parent_composite_transform;
- flattened_composite_transform.FlattenTo2d();
- SetLayerPropertiesForTesting(parent.get(),
- parent_layer_transform,
- parent_sublayer_matrix,
- gfx::PointF(0.25f, 0.25f),
- gfx::PointF(),
- gfx::Size(10, 12),
- false);
- SetLayerPropertiesForTesting(child.get(),
- identity_matrix,
- identity_matrix,
- gfx::PointF(),
- gfx::PointF(),
- gfx::Size(16, 18),
- false);
- SetLayerPropertiesForTesting(grand_child.get(),
- identity_matrix,
- identity_matrix,
- gfx::PointF(),
- gfx::PointF(),
- gfx::Size(76, 78),
- false);
- ExecuteCalculateDrawProperties(root.get());
- EXPECT_TRANSFORMATION_MATRIX_EQ(parent_composite_transform,
- child->draw_transform());
- EXPECT_TRANSFORMATION_MATRIX_EQ(parent_composite_transform,
- child->screen_space_transform());
- EXPECT_TRANSFORMATION_MATRIX_EQ(flattened_composite_transform,
- grand_child->draw_transform());
- EXPECT_TRANSFORMATION_MATRIX_EQ(flattened_composite_transform,
- grand_child->screen_space_transform());
-
- // Case 5: same as Case 4, except that child does preserve 3D, so the
- // grand_child should receive the non-flattened composite transform.
- SetLayerPropertiesForTesting(parent.get(),
- parent_layer_transform,
- parent_sublayer_matrix,
- gfx::PointF(0.25f, 0.25f),
- gfx::PointF(),
- gfx::Size(10, 12),
- false);
- SetLayerPropertiesForTesting(child.get(),
- identity_matrix,
- identity_matrix,
- gfx::PointF(),
- gfx::PointF(),
- gfx::Size(16, 18),
- true);
- SetLayerPropertiesForTesting(grand_child.get(),
- identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(76, 78),
+ true,
false);
ExecuteCalculateDrawProperties(root.get());
EXPECT_TRANSFORMATION_MATRIX_EQ(parent_composite_transform,
@@ -707,10 +559,10 @@ TEST_F(LayerTreeHostCommonTest, TransformsForSingleRenderSurface) {
gfx::Transform identity_matrix;
SetLayerPropertiesForTesting(root.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(1, 2),
+ true,
false);
// Child is set up so that a new render surface should be created.
@@ -721,13 +573,10 @@ TEST_F(LayerTreeHostCommonTest, TransformsForSingleRenderSurface) {
parent_layer_transform.Scale3d(1.f, 0.9f, 1.f);
gfx::Transform parent_translation_to_anchor;
parent_translation_to_anchor.Translate(25.0, 30.0);
- gfx::Transform parent_sublayer_matrix;
- parent_sublayer_matrix.Scale3d(0.9f, 1.f, 3.3f);
gfx::Transform parent_composite_transform =
parent_translation_to_anchor * parent_layer_transform *
- Inverse(parent_translation_to_anchor) * parent_translation_to_anchor *
- parent_sublayer_matrix * Inverse(parent_translation_to_anchor);
+ Inverse(parent_translation_to_anchor);
gfx::Vector2dF parent_composite_scale =
MathUtil::ComputeTransform2dScaleComponents(parent_composite_transform,
1.f);
@@ -742,24 +591,24 @@ TEST_F(LayerTreeHostCommonTest, TransformsForSingleRenderSurface) {
SetLayerPropertiesForTesting(parent.get(),
parent_layer_transform,
- parent_sublayer_matrix,
- gfx::PointF(0.25f, 0.25f),
+ gfx::Point3F(25.0f, 30.0f, 0.f),
gfx::PointF(),
gfx::Size(100, 120),
+ true,
false);
SetLayerPropertiesForTesting(child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(16, 18),
+ true,
false);
SetLayerPropertiesForTesting(grand_child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(8, 10),
+ true,
false);
ExecuteCalculateDrawProperties(root.get());
@@ -788,56 +637,6 @@ TEST_F(LayerTreeHostCommonTest, TransformsForSingleRenderSurface) {
child->render_target()->render_surface()->screen_space_transform());
}
-TEST_F(LayerTreeHostCommonTest, SublayerTransformWithAnchorPoint) {
- // crbug.com/157961 - we were always applying the sublayer transform about
- // the center of the layer, rather than the anchor point.
-
- scoped_refptr<Layer> root = Layer::Create();
- scoped_refptr<Layer> parent = Layer::Create();
- scoped_refptr<LayerWithForcedDrawsContent> child =
- make_scoped_refptr(new LayerWithForcedDrawsContent());
- root->AddChild(parent);
- parent->AddChild(child);
-
- scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create();
- host->SetRootLayer(root);
-
- gfx::Transform identity_matrix;
- gfx::Transform parent_sublayer_matrix;
- parent_sublayer_matrix.ApplyPerspectiveDepth(2.0);
- gfx::PointF parent_anchor_point(0.2f, 0.8f);
-
- SetLayerPropertiesForTesting(root.get(),
- identity_matrix,
- identity_matrix,
- gfx::PointF(),
- gfx::PointF(),
- gfx::Size(1, 2),
- false);
- SetLayerPropertiesForTesting(parent.get(),
- identity_matrix,
- parent_sublayer_matrix,
- parent_anchor_point,
- gfx::PointF(),
- gfx::Size(100, 100),
- false);
- SetLayerPropertiesForTesting(child.get(),
- identity_matrix,
- identity_matrix,
- gfx::PointF(),
- gfx::PointF(),
- gfx::Size(10, 10),
- false);
- ExecuteCalculateDrawProperties(root.get());
-
- gfx::Transform expected_child_draw_transform;
- expected_child_draw_transform.Translate(20.0, 80.0);
- expected_child_draw_transform.ApplyPerspectiveDepth(2.0);
- expected_child_draw_transform.Translate(-20.0, -80.0);
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected_child_draw_transform,
- child->draw_transform());
-}
-
TEST_F(LayerTreeHostCommonTest, TransformsForReplica) {
scoped_refptr<Layer> root = Layer::Create();
scoped_refptr<Layer> parent = Layer::Create();
@@ -857,10 +656,10 @@ TEST_F(LayerTreeHostCommonTest, TransformsForReplica) {
gfx::Transform identity_matrix;
SetLayerPropertiesForTesting(root.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(1, 2),
+ true,
false);
// Child is set up so that a new render surface should be created.
@@ -870,12 +669,9 @@ TEST_F(LayerTreeHostCommonTest, TransformsForReplica) {
parent_layer_transform.Scale3d(2.0, 2.0, 1.0);
gfx::Transform parent_translation_to_anchor;
parent_translation_to_anchor.Translate(2.5, 3.0);
- gfx::Transform parent_sublayer_matrix;
- parent_sublayer_matrix.Scale3d(10.f, 10.f, 3.3f);
gfx::Transform parent_composite_transform =
parent_translation_to_anchor * parent_layer_transform *
- Inverse(parent_translation_to_anchor) * parent_translation_to_anchor *
- parent_sublayer_matrix * Inverse(parent_translation_to_anchor);
+ Inverse(parent_translation_to_anchor);
gfx::Transform replica_layer_transform;
replica_layer_transform.Scale3d(3.0, 3.0, 1.0);
gfx::Vector2dF parent_composite_scale =
@@ -893,31 +689,31 @@ TEST_F(LayerTreeHostCommonTest, TransformsForReplica) {
SetLayerPropertiesForTesting(parent.get(),
parent_layer_transform,
- parent_sublayer_matrix,
- gfx::PointF(0.25f, 0.25f),
+ gfx::Point3F(2.5f, 3.0f, 0.f),
gfx::PointF(),
gfx::Size(10, 12),
+ true,
false);
SetLayerPropertiesForTesting(child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(16, 18),
+ true,
false);
SetLayerPropertiesForTesting(grand_child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(-0.5f, -0.5f),
gfx::Size(1, 1),
+ true,
false);
SetLayerPropertiesForTesting(child_replica.get(),
replica_layer_transform,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(),
+ true,
false);
ExecuteCalculateDrawProperties(root.get());
@@ -929,7 +725,8 @@ TEST_F(LayerTreeHostCommonTest, TransformsForReplica) {
replica_composite_transform,
child->render_target()->render_surface()->replica_draw_transform());
EXPECT_TRANSFORMATION_MATRIX_EQ(replica_composite_transform,
- child->render_target()->render_surface()
+ child->render_target()
+ ->render_surface()
->replica_screen_space_transform());
}
@@ -985,40 +782,29 @@ TEST_F(LayerTreeHostCommonTest, TransformsForRenderSurfaceHierarchy) {
gfx::Transform identity_matrix;
SetLayerPropertiesForTesting(root.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(1, 2),
+ true,
false);
// All layers in the tree are initialized with an anchor at .25 and a size of
// (10,10). matrix "A" is the composite layer transform used in all layers,
- // centered about the anchor point. matrix "B" is the sublayer transform used
- // in all layers, centered about the center position of the layer. matrix "R"
- // is the composite replica transform used in all replica layers.
- //
- // x component tests that layer_transform and sublayer_transform are done in
- // the right order (translation and scale are noncommutative). y component
- // has a translation by 1 for every ancestor, which indicates the "depth" of
- // the layer in the hierarchy.
+ // Matrix "R" is the composite replica transform used in all replica layers.
gfx::Transform translation_to_anchor;
translation_to_anchor.Translate(2.5, 0.0);
gfx::Transform layer_transform;
layer_transform.Translate(1.0, 1.0);
- gfx::Transform sublayer_transform;
- sublayer_transform.Scale3d(10.0, 1.0, 1.0);
gfx::Transform replica_layer_transform;
replica_layer_transform.Scale3d(-2.0, 5.0, 1.0);
gfx::Transform A =
translation_to_anchor * layer_transform * Inverse(translation_to_anchor);
- gfx::Transform B = translation_to_anchor * sublayer_transform *
- Inverse(translation_to_anchor);
gfx::Transform R = A * translation_to_anchor * replica_layer_transform *
Inverse(translation_to_anchor);
gfx::Vector2dF surface1_parent_transform_scale =
- MathUtil::ComputeTransform2dScaleComponents(A * B, 1.f);
+ MathUtil::ComputeTransform2dScaleComponents(A, 1.f);
gfx::Transform surface1_sublayer_transform;
surface1_sublayer_transform.Scale(surface1_parent_transform_scale.x(),
surface1_parent_transform_scale.y());
@@ -1030,7 +816,7 @@ TEST_F(LayerTreeHostCommonTest, TransformsForRenderSurfaceHierarchy) {
gfx::Transform S1 = Inverse(surface1_sublayer_transform);
gfx::Vector2dF surface2_parent_transform_scale =
- MathUtil::ComputeTransform2dScaleComponents(SS1 * A * B, 1.f);
+ MathUtil::ComputeTransform2dScaleComponents(SS1 * A, 1.f);
gfx::Transform surface2_sublayer_transform;
surface2_sublayer_transform.Scale(surface2_parent_transform_scale.x(),
surface2_parent_transform_scale.y());
@@ -1043,80 +829,80 @@ TEST_F(LayerTreeHostCommonTest, TransformsForRenderSurfaceHierarchy) {
SetLayerPropertiesForTesting(parent.get(),
layer_transform,
- sublayer_transform,
- gfx::PointF(0.25f, 0.f),
+ gfx::Point3F(2.5f, 0.f, 0.f),
gfx::PointF(),
gfx::Size(10, 10),
+ true,
false);
SetLayerPropertiesForTesting(render_surface1.get(),
layer_transform,
- sublayer_transform,
- gfx::PointF(0.25f, 0.f),
+ gfx::Point3F(2.5f, 0.f, 0.f),
gfx::PointF(),
gfx::Size(10, 10),
+ true,
false);
SetLayerPropertiesForTesting(render_surface2.get(),
layer_transform,
- sublayer_transform,
- gfx::PointF(0.25f, 0.f),
+ gfx::Point3F(2.5f, 0.f, 0.f),
gfx::PointF(),
gfx::Size(10, 10),
+ true,
false);
SetLayerPropertiesForTesting(child_of_root.get(),
layer_transform,
- sublayer_transform,
- gfx::PointF(0.25f, 0.f),
+ gfx::Point3F(2.5f, 0.f, 0.f),
gfx::PointF(),
gfx::Size(10, 10),
+ true,
false);
SetLayerPropertiesForTesting(child_of_rs1.get(),
layer_transform,
- sublayer_transform,
- gfx::PointF(0.25f, 0.f),
+ gfx::Point3F(2.5f, 0.f, 0.f),
gfx::PointF(),
gfx::Size(10, 10),
+ true,
false);
SetLayerPropertiesForTesting(child_of_rs2.get(),
layer_transform,
- sublayer_transform,
- gfx::PointF(0.25f, 0.f),
+ gfx::Point3F(2.5f, 0.f, 0.f),
gfx::PointF(),
gfx::Size(10, 10),
+ true,
false);
SetLayerPropertiesForTesting(grand_child_of_root.get(),
layer_transform,
- sublayer_transform,
- gfx::PointF(0.25f, 0.f),
+ gfx::Point3F(2.5f, 0.f, 0.f),
gfx::PointF(),
gfx::Size(10, 10),
+ true,
false);
SetLayerPropertiesForTesting(grand_child_of_rs1.get(),
layer_transform,
- sublayer_transform,
- gfx::PointF(0.25f, 0.f),
+ gfx::Point3F(2.5f, 0.f, 0.f),
gfx::PointF(),
gfx::Size(10, 10),
+ true,
false);
SetLayerPropertiesForTesting(grand_child_of_rs2.get(),
layer_transform,
- sublayer_transform,
- gfx::PointF(0.25f, 0.f),
+ gfx::Point3F(2.5f, 0.f, 0.f),
gfx::PointF(),
gfx::Size(10, 10),
+ true,
false);
SetLayerPropertiesForTesting(replica_of_rs1.get(),
replica_layer_transform,
- sublayer_transform,
- gfx::PointF(0.25f, 0.f),
+ gfx::Point3F(2.5f, 0.f, 0.f),
gfx::PointF(),
gfx::Size(),
+ true,
false);
SetLayerPropertiesForTesting(replica_of_rs2.get(),
replica_layer_transform,
- sublayer_transform,
- gfx::PointF(0.25f, 0.f),
+ gfx::Point3F(2.5f, 0.f, 0.f),
gfx::PointF(),
gfx::Size(),
+ true,
false);
ExecuteCalculateDrawProperties(root.get());
@@ -1152,68 +938,66 @@ TEST_F(LayerTreeHostCommonTest, TransformsForRenderSurfaceHierarchy) {
// respect to the nearest ancestor render surface but screen space transforms
// are described with respect to the root.
EXPECT_TRANSFORMATION_MATRIX_EQ(A, parent->draw_transform());
- EXPECT_TRANSFORMATION_MATRIX_EQ(A * B * A, child_of_root->draw_transform());
- EXPECT_TRANSFORMATION_MATRIX_EQ(A * B * A * B * A,
+ EXPECT_TRANSFORMATION_MATRIX_EQ(A * A, child_of_root->draw_transform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(A * A * A,
grand_child_of_root->draw_transform());
EXPECT_TRANSFORMATION_MATRIX_EQ(SS1, render_surface1->draw_transform());
- EXPECT_TRANSFORMATION_MATRIX_EQ(SS1 * B * A, child_of_rs1->draw_transform());
- EXPECT_TRANSFORMATION_MATRIX_EQ(SS1 * B * A * B * A,
+ EXPECT_TRANSFORMATION_MATRIX_EQ(SS1 * A, child_of_rs1->draw_transform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(SS1 * A * A,
grand_child_of_rs1->draw_transform());
EXPECT_TRANSFORMATION_MATRIX_EQ(SS2, render_surface2->draw_transform());
- EXPECT_TRANSFORMATION_MATRIX_EQ(SS2 * B * A, child_of_rs2->draw_transform());
- EXPECT_TRANSFORMATION_MATRIX_EQ(SS2 * B * A * B * A,
+ EXPECT_TRANSFORMATION_MATRIX_EQ(SS2 * A, child_of_rs2->draw_transform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(SS2 * A * A,
grand_child_of_rs2->draw_transform());
// Verify layer screen-space transforms
//
EXPECT_TRANSFORMATION_MATRIX_EQ(A, parent->screen_space_transform());
- EXPECT_TRANSFORMATION_MATRIX_EQ(A * B * A,
+ EXPECT_TRANSFORMATION_MATRIX_EQ(A * A,
child_of_root->screen_space_transform());
EXPECT_TRANSFORMATION_MATRIX_EQ(
- A * B * A * B * A, grand_child_of_root->screen_space_transform());
+ A * A * A, grand_child_of_root->screen_space_transform());
- EXPECT_TRANSFORMATION_MATRIX_EQ(A * B * A,
+ EXPECT_TRANSFORMATION_MATRIX_EQ(A * A,
render_surface1->screen_space_transform());
- EXPECT_TRANSFORMATION_MATRIX_EQ(A * B * A * B * A,
+ EXPECT_TRANSFORMATION_MATRIX_EQ(A * A * A,
child_of_rs1->screen_space_transform());
- EXPECT_TRANSFORMATION_MATRIX_EQ(A * B * A * B * A * B * A,
+ EXPECT_TRANSFORMATION_MATRIX_EQ(A * A * A * A,
grand_child_of_rs1->screen_space_transform());
- EXPECT_TRANSFORMATION_MATRIX_EQ(A * B * A * B * A,
+ EXPECT_TRANSFORMATION_MATRIX_EQ(A * A * A,
render_surface2->screen_space_transform());
- EXPECT_TRANSFORMATION_MATRIX_EQ(A * B * A * B * A * B * A,
+ EXPECT_TRANSFORMATION_MATRIX_EQ(A * A * A * A,
child_of_rs2->screen_space_transform());
- EXPECT_TRANSFORMATION_MATRIX_EQ(A * B * A * B * A * B * A * B * A,
+ EXPECT_TRANSFORMATION_MATRIX_EQ(A * A * A * A * A,
grand_child_of_rs2->screen_space_transform());
// Verify render surface transforms.
//
// Draw transform of render surface 1 is described with respect to root.
EXPECT_TRANSFORMATION_MATRIX_EQ(
- A * B * A * S1, render_surface1->render_surface()->draw_transform());
+ A * A * S1, render_surface1->render_surface()->draw_transform());
EXPECT_TRANSFORMATION_MATRIX_EQ(
- A * B * R * S1,
- render_surface1->render_surface()->replica_draw_transform());
+ A * R * S1, render_surface1->render_surface()->replica_draw_transform());
EXPECT_TRANSFORMATION_MATRIX_EQ(
- A * B * A * S1,
- render_surface1->render_surface()->screen_space_transform());
+ A * A * S1, render_surface1->render_surface()->screen_space_transform());
EXPECT_TRANSFORMATION_MATRIX_EQ(
- A * B * R * S1,
+ A * R * S1,
render_surface1->render_surface()->replica_screen_space_transform());
// Draw transform of render surface 2 is described with respect to render
// surface 1.
EXPECT_TRANSFORMATION_MATRIX_EQ(
- SS1 * B * A * S2, render_surface2->render_surface()->draw_transform());
+ SS1 * A * S2, render_surface2->render_surface()->draw_transform());
EXPECT_TRANSFORMATION_MATRIX_EQ(
- SS1 * B * R * S2,
+ SS1 * R * S2,
render_surface2->render_surface()->replica_draw_transform());
EXPECT_TRANSFORMATION_MATRIX_EQ(
- A * B * A * B * A * S2,
+ A * A * A * S2,
render_surface2->render_surface()->screen_space_transform());
EXPECT_TRANSFORMATION_MATRIX_EQ(
- A * B * A * B * R * S2,
+ A * A * R * S2,
render_surface2->render_surface()->replica_screen_space_transform());
// Sanity check. If these fail there is probably a bug in the test itself. It
@@ -1257,24 +1041,24 @@ TEST_F(LayerTreeHostCommonTest, TransformsForFlatteningLayer) {
const gfx::Transform identity_matrix;
SetLayerPropertiesForTesting(root.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ true,
false);
SetLayerPropertiesForTesting(child.get(),
rotation_about_y_axis,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(10, 10),
+ true,
false);
SetLayerPropertiesForTesting(grand_child.get(),
rotation_about_y_axis,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(10, 10),
+ true,
false);
root->AddChild(child);
@@ -1285,9 +1069,9 @@ TEST_F(LayerTreeHostCommonTest, TransformsForFlatteningLayer) {
host->SetRootLayer(root);
// No layers in this test should preserve 3d.
- ASSERT_FALSE(root->preserves_3d());
- ASSERT_FALSE(child->preserves_3d());
- ASSERT_FALSE(grand_child->preserves_3d());
+ ASSERT_TRUE(root->should_flatten_transform());
+ ASSERT_TRUE(child->should_flatten_transform());
+ ASSERT_TRUE(grand_child->should_flatten_transform());
gfx::Transform expected_child_draw_transform = rotation_about_y_axis;
gfx::Transform expected_child_screen_space_transform = rotation_about_y_axis;
@@ -1336,24 +1120,24 @@ TEST_F(LayerTreeHostCommonTest, TransformsForDegenerateIntermediateLayer) {
const gfx::Transform identity_matrix;
SetLayerPropertiesForTesting(root.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ true,
false);
SetLayerPropertiesForTesting(child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(10, 0),
+ true,
false);
SetLayerPropertiesForTesting(grand_child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(10, 10),
+ true,
false);
root->AddChild(child);
@@ -1378,9 +1162,11 @@ TEST_F(LayerTreeHostCommonTest, TransformAboveRootLayer) {
// Transformations applied at the root of the tree should be forwarded
// to child layers instead of applied to the root RenderSurface.
const gfx::Transform identity_matrix;
- scoped_refptr<Layer> root = Layer::Create();
- scoped_refptr<Layer> child = Layer::Create();
- child->SetScrollable(true);
+ scoped_refptr<LayerWithForcedDrawsContent> root =
+ new LayerWithForcedDrawsContent;
+ scoped_refptr<LayerWithForcedDrawsContent> child =
+ new LayerWithForcedDrawsContent;
+ child->SetScrollClipLayerId(root->id());
root->AddChild(child);
scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create();
@@ -1388,17 +1174,17 @@ TEST_F(LayerTreeHostCommonTest, TransformAboveRootLayer) {
SetLayerPropertiesForTesting(root.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(20, 20),
+ true,
false);
SetLayerPropertiesForTesting(child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(20, 20),
+ true,
false);
gfx::Transform translate;
@@ -1412,6 +1198,8 @@ TEST_F(LayerTreeHostCommonTest, TransformAboveRootLayer) {
EXPECT_EQ(translate, root->draw_properties().target_space_transform);
EXPECT_EQ(translate, child->draw_properties().target_space_transform);
EXPECT_EQ(identity_matrix, root->render_surface()->draw_transform());
+ EXPECT_EQ(1.f, root->last_device_scale_factor());
+ EXPECT_EQ(1.f, child->last_device_scale_factor());
}
gfx::Transform scale;
@@ -1425,6 +1213,8 @@ TEST_F(LayerTreeHostCommonTest, TransformAboveRootLayer) {
EXPECT_EQ(scale, root->draw_properties().target_space_transform);
EXPECT_EQ(scale, child->draw_properties().target_space_transform);
EXPECT_EQ(identity_matrix, root->render_surface()->draw_transform());
+ EXPECT_EQ(2.f, root->last_device_scale_factor());
+ EXPECT_EQ(2.f, child->last_device_scale_factor());
}
gfx::Transform rotate;
@@ -1438,6 +1228,8 @@ TEST_F(LayerTreeHostCommonTest, TransformAboveRootLayer) {
EXPECT_EQ(rotate, root->draw_properties().target_space_transform);
EXPECT_EQ(rotate, child->draw_properties().target_space_transform);
EXPECT_EQ(identity_matrix, root->render_surface()->draw_transform());
+ EXPECT_EQ(1.f, root->last_device_scale_factor());
+ EXPECT_EQ(1.f, child->last_device_scale_factor());
}
gfx::Transform composite;
@@ -1472,6 +1264,8 @@ TEST_F(LayerTreeHostCommonTest, TransformAboveRootLayer) {
EXPECT_EQ(device_scaled_translate,
child->draw_properties().target_space_transform);
EXPECT_EQ(identity_matrix, root->render_surface()->draw_transform());
+ EXPECT_EQ(device_scale_factor, root->last_device_scale_factor());
+ EXPECT_EQ(device_scale_factor, child->last_device_scale_factor());
}
// Verify it composes correctly with page scale.
@@ -1491,11 +1285,12 @@ TEST_F(LayerTreeHostCommonTest, TransformAboveRootLayer) {
EXPECT_EQ(page_scaled_translate,
child->draw_properties().target_space_transform);
EXPECT_EQ(identity_matrix, root->render_surface()->draw_transform());
+ EXPECT_EQ(1.f, root->last_device_scale_factor());
+ EXPECT_EQ(1.f, child->last_device_scale_factor());
}
// Verify that it composes correctly with transforms directly on root layer.
root->SetTransform(composite);
- root->SetSublayerTransform(composite);
{
RenderSurfaceLayerList render_surface_layer_list;
@@ -1505,12 +1300,10 @@ TEST_F(LayerTreeHostCommonTest, TransformAboveRootLayer) {
LayerTreeHostCommon::CalculateDrawProperties(&inputs);
gfx::Transform compositeSquared = composite;
compositeSquared.ConcatTransform(composite);
- gfx::Transform compositeCubed = compositeSquared;
- compositeCubed.ConcatTransform(composite);
EXPECT_TRANSFORMATION_MATRIX_EQ(
compositeSquared, root->draw_properties().target_space_transform);
EXPECT_TRANSFORMATION_MATRIX_EQ(
- compositeCubed, child->draw_properties().target_space_transform);
+ compositeSquared, child->draw_properties().target_space_transform);
EXPECT_EQ(identity_matrix, root->render_surface()->draw_transform());
}
}
@@ -1525,28 +1318,27 @@ TEST_F(LayerTreeHostCommonTest,
scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create();
host->SetRootLayer(parent);
-
const gfx::Transform identity_matrix;
SetLayerPropertiesForTesting(parent.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(10, 10),
+ true,
false);
SetLayerPropertiesForTesting(render_surface1.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(10, 10),
+ true,
false);
SetLayerPropertiesForTesting(child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(30.f, 30.f),
gfx::Size(10, 10),
+ true,
false);
parent->AddChild(render_surface1);
@@ -1568,7 +1360,6 @@ TEST_F(LayerTreeHostCommonTest,
// are unexpected at draw time (e.g. we might try to create a content texture
// of size 0).
ASSERT_TRUE(parent->render_surface());
- ASSERT_FALSE(render_surface1->render_surface());
EXPECT_EQ(1U, render_surface_layer_list.size());
}
@@ -1584,17 +1375,17 @@ TEST_F(LayerTreeHostCommonTest, RenderSurfaceListForTransparentChild) {
const gfx::Transform identity_matrix;
SetLayerPropertiesForTesting(render_surface1.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(10, 10),
+ true,
false);
SetLayerPropertiesForTesting(child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(10, 10),
+ true,
false);
parent->AddChild(render_surface1);
@@ -1631,24 +1422,24 @@ TEST_F(LayerTreeHostCommonTest, ForceRenderSurface) {
const gfx::Transform identity_matrix;
SetLayerPropertiesForTesting(parent.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(10, 10),
+ true,
false);
SetLayerPropertiesForTesting(render_surface1.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(10, 10),
+ true,
false);
SetLayerPropertiesForTesting(child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(10, 10),
+ true,
false);
parent->AddChild(render_surface1);
@@ -1725,45 +1516,45 @@ TEST_F(LayerTreeHostCommonTest, ClipRectCullsRenderSurfaces) {
SetLayerPropertiesForTesting(parent.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(500, 500),
+ true,
false);
SetLayerPropertiesForTesting(child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(20, 20),
+ true,
false);
SetLayerPropertiesForTesting(grand_child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(45.f, 45.f),
gfx::Size(10, 10),
+ true,
false);
SetLayerPropertiesForTesting(great_grand_child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(10, 10),
+ true,
false);
SetLayerPropertiesForTesting(leaf_node1.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(500, 500),
+ true,
false);
SetLayerPropertiesForTesting(leaf_node2.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(20, 20),
+ true,
false);
child->SetMasksToBounds(true);
@@ -1817,31 +1608,31 @@ TEST_F(LayerTreeHostCommonTest, ClipRectCullsSurfaceWithoutVisibleContent) {
SetLayerPropertiesForTesting(parent.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ true,
false);
SetLayerPropertiesForTesting(child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(20, 20),
+ true,
false);
SetLayerPropertiesForTesting(grand_child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(200.f, 200.f),
gfx::Size(10, 10),
+ true,
false);
SetLayerPropertiesForTesting(leaf_node.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(10, 10),
+ true,
false);
parent->SetMasksToBounds(true);
@@ -1921,52 +1712,52 @@ TEST_F(LayerTreeHostCommonTest, IsClippedIsSetCorrectly) {
SetLayerPropertiesForTesting(root.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ true,
false);
SetLayerPropertiesForTesting(parent.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ true,
false);
SetLayerPropertiesForTesting(child1.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ true,
false);
SetLayerPropertiesForTesting(child2.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ true,
false);
SetLayerPropertiesForTesting(grand_child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ true,
false);
SetLayerPropertiesForTesting(leaf_node1.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ true,
false);
SetLayerPropertiesForTesting(leaf_node2.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ true,
false);
// Case 1: nothing is clipped except the root render surface.
@@ -2077,45 +1868,45 @@ TEST_F(LayerTreeHostCommonTest, DrawableContentRectForLayers) {
SetLayerPropertiesForTesting(parent.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(500, 500),
+ true,
false);
SetLayerPropertiesForTesting(child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(20, 20),
+ true,
false);
SetLayerPropertiesForTesting(grand_child1.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(5.f, 5.f),
gfx::Size(10, 10),
+ true,
false);
SetLayerPropertiesForTesting(grand_child2.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(15.f, 15.f),
gfx::Size(10, 10),
+ true,
false);
SetLayerPropertiesForTesting(grand_child3.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(15.f, 15.f),
gfx::Size(10, 10),
+ true,
false);
SetLayerPropertiesForTesting(grand_child4.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(45.f, 45.f),
gfx::Size(10, 10),
+ true,
false);
child->SetMasksToBounds(true);
@@ -2185,73 +1976,73 @@ TEST_F(LayerTreeHostCommonTest, ClipRectIsPropagatedCorrectlyToSurfaces) {
SetLayerPropertiesForTesting(parent.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(500, 500),
+ true,
false);
SetLayerPropertiesForTesting(child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(20, 20),
+ true,
false);
SetLayerPropertiesForTesting(grand_child1.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(5.f, 5.f),
gfx::Size(10, 10),
+ true,
false);
SetLayerPropertiesForTesting(grand_child2.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(15.f, 15.f),
gfx::Size(10, 10),
+ true,
false);
SetLayerPropertiesForTesting(grand_child3.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(15.f, 15.f),
gfx::Size(10, 10),
+ true,
false);
SetLayerPropertiesForTesting(grand_child4.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(45.f, 45.f),
gfx::Size(10, 10),
+ true,
false);
SetLayerPropertiesForTesting(leaf_node1.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(10, 10),
+ true,
false);
SetLayerPropertiesForTesting(leaf_node2.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(10, 10),
+ true,
false);
SetLayerPropertiesForTesting(leaf_node3.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(10, 10),
+ true,
false);
SetLayerPropertiesForTesting(leaf_node4.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(10, 10),
+ true,
false);
child->SetMasksToBounds(true);
@@ -2278,9 +2069,6 @@ TEST_F(LayerTreeHostCommonTest, ClipRectIsPropagatedCorrectlyToSurfaces) {
ASSERT_TRUE(grand_child1->render_surface());
ASSERT_TRUE(grand_child2->render_surface());
ASSERT_TRUE(grand_child3->render_surface());
- // Because grand_child4 is entirely clipped, it is expected to not have a
- // render surface.
- EXPECT_FALSE(grand_child4->render_surface());
// Surfaces are clipped by their parent, but un-affected by the owning layer's
// masksToBounds.
@@ -2322,71 +2110,69 @@ TEST_F(LayerTreeHostCommonTest, AnimationsForRenderSurfaceHierarchy) {
gfx::Transform layer_transform;
layer_transform.Translate(1.0, 1.0);
- gfx::Transform sublayer_transform;
- sublayer_transform.Scale3d(10.0, 1.0, 1.0);
SetLayerPropertiesForTesting(parent.get(),
layer_transform,
- sublayer_transform,
- gfx::PointF(0.25f, 0.f),
+ gfx::Point3F(0.25f, 0.f, 0.f),
gfx::PointF(2.5f, 0.f),
gfx::Size(10, 10),
+ true,
false);
SetLayerPropertiesForTesting(render_surface1.get(),
layer_transform,
- sublayer_transform,
- gfx::PointF(0.25f, 0.f),
+ gfx::Point3F(0.25f, 0.f, 0.f),
gfx::PointF(2.5f, 0.f),
gfx::Size(10, 10),
+ true,
false);
SetLayerPropertiesForTesting(render_surface2.get(),
layer_transform,
- sublayer_transform,
- gfx::PointF(0.25f, 0.f),
+ gfx::Point3F(0.25f, 0.f, 0.f),
gfx::PointF(2.5f, 0.f),
gfx::Size(10, 10),
+ true,
false);
SetLayerPropertiesForTesting(child_of_root.get(),
layer_transform,
- sublayer_transform,
- gfx::PointF(0.25f, 0.f),
+ gfx::Point3F(0.25f, 0.f, 0.f),
gfx::PointF(2.5f, 0.f),
gfx::Size(10, 10),
+ true,
false);
SetLayerPropertiesForTesting(child_of_rs1.get(),
layer_transform,
- sublayer_transform,
- gfx::PointF(0.25f, 0.f),
+ gfx::Point3F(0.25f, 0.f, 0.f),
gfx::PointF(2.5f, 0.f),
gfx::Size(10, 10),
+ true,
false);
SetLayerPropertiesForTesting(child_of_rs2.get(),
layer_transform,
- sublayer_transform,
- gfx::PointF(0.25f, 0.f),
+ gfx::Point3F(0.25f, 0.f, 0.f),
gfx::PointF(2.5f, 0.f),
gfx::Size(10, 10),
+ true,
false);
SetLayerPropertiesForTesting(grand_child_of_root.get(),
layer_transform,
- sublayer_transform,
- gfx::PointF(0.25f, 0.f),
+ gfx::Point3F(0.25f, 0.f, 0.f),
gfx::PointF(2.5f, 0.f),
gfx::Size(10, 10),
+ true,
false);
SetLayerPropertiesForTesting(grand_child_of_rs1.get(),
layer_transform,
- sublayer_transform,
- gfx::PointF(0.25f, 0.f),
+ gfx::Point3F(0.25f, 0.f, 0.f),
gfx::PointF(2.5f, 0.f),
gfx::Size(10, 10),
+ true,
false);
SetLayerPropertiesForTesting(grand_child_of_rs2.get(),
layer_transform,
- sublayer_transform,
- gfx::PointF(0.25f, 0.f),
+ gfx::Point3F(0.25f, 0.f, 0.f),
gfx::PointF(2.5f, 0.f),
gfx::Size(10, 10),
+ true,
false);
// Put an animated opacity on the render surface.
@@ -2809,31 +2595,31 @@ TEST_F(LayerTreeHostCommonTest, DrawableAndVisibleContentRectsForSimpleLayers) {
gfx::Transform identity_matrix;
SetLayerPropertiesForTesting(root.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ true,
false);
SetLayerPropertiesForTesting(child1.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(50, 50),
+ true,
false);
SetLayerPropertiesForTesting(child2.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(75.f, 75.f),
gfx::Size(50, 50),
+ true,
false);
SetLayerPropertiesForTesting(child3.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(125.f, 125.f),
gfx::Size(50, 50),
+ true,
false);
ExecuteCalculateDrawProperties(root.get());
@@ -2877,38 +2663,38 @@ TEST_F(LayerTreeHostCommonTest,
gfx::Transform identity_matrix;
SetLayerPropertiesForTesting(root.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ true,
false);
SetLayerPropertiesForTesting(child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ true,
false);
SetLayerPropertiesForTesting(grand_child1.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(5.f, 5.f),
gfx::Size(50, 50),
+ true,
false);
SetLayerPropertiesForTesting(grand_child2.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(75.f, 75.f),
gfx::Size(50, 50),
+ true,
false);
SetLayerPropertiesForTesting(grand_child3.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(125.f, 125.f),
gfx::Size(50, 50),
+ true,
false);
child->SetMasksToBounds(true);
@@ -2958,38 +2744,38 @@ TEST_F(LayerTreeHostCommonTest,
gfx::Transform identity_matrix;
SetLayerPropertiesForTesting(root.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ true,
false);
SetLayerPropertiesForTesting(render_surface1.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(3, 4),
+ true,
false);
SetLayerPropertiesForTesting(child1.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(5.f, 5.f),
gfx::Size(50, 50),
+ true,
false);
SetLayerPropertiesForTesting(child2.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(75.f, 75.f),
gfx::Size(50, 50),
+ true,
false);
SetLayerPropertiesForTesting(child3.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(125.f, 125.f),
gfx::Size(50, 50),
+ true,
false);
render_surface1->SetForceRenderSurface(true);
@@ -3038,17 +2824,17 @@ TEST_F(LayerTreeHostCommonTest,
SetLayerPropertiesForTesting(root.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ true,
false);
SetLayerPropertiesForTesting(child.get(),
uninvertible_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(5.f, 5.f),
gfx::Size(50, 50),
+ true,
false);
ExecuteCalculateDrawProperties(root.get());
@@ -3056,30 +2842,26 @@ TEST_F(LayerTreeHostCommonTest,
EXPECT_TRUE(child->visible_content_rect().IsEmpty());
EXPECT_TRUE(child->drawable_content_rect().IsEmpty());
- // Case 2: a matrix with flattened z, technically uninvertible but still
- // drawable and visible. In this case, we must assume that the entire layer
- // bounds are visible since there is no way to inverse-project the surface
- // bounds to intersect.
+ // Case 2: a matrix with flattened z, uninvertible and not visible according
+ // to the CSS spec.
uninvertible_matrix.MakeIdentity();
uninvertible_matrix.matrix().set(2, 2, 0.0);
ASSERT_FALSE(uninvertible_matrix.IsInvertible());
SetLayerPropertiesForTesting(child.get(),
uninvertible_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(5.f, 5.f),
gfx::Size(50, 50),
+ true,
false);
ExecuteCalculateDrawProperties(root.get());
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 50, 50), child->visible_content_rect());
- EXPECT_RECT_EQ(gfx::Rect(5, 5, 50, 50), child->drawable_content_rect());
+ EXPECT_TRUE(child->visible_content_rect().IsEmpty());
+ EXPECT_TRUE(child->drawable_content_rect().IsEmpty());
- // Case 3: a matrix with flattened z, technically uninvertible but still
- // drawable, but not visible. In this case, we don't need to conservatively
- // assume that the whole layer is visible.
+ // Case 3: a matrix with flattened z, also uninvertible and not visible.
uninvertible_matrix.MakeIdentity();
uninvertible_matrix.Translate(500.0, 0.0);
uninvertible_matrix.matrix().set(2, 2, 0.0);
@@ -3087,16 +2869,91 @@ TEST_F(LayerTreeHostCommonTest,
SetLayerPropertiesForTesting(child.get(),
uninvertible_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(5.f, 5.f),
gfx::Size(50, 50),
+ true,
false);
ExecuteCalculateDrawProperties(root.get());
EXPECT_TRUE(child->visible_content_rect().IsEmpty());
- EXPECT_RECT_EQ(gfx::Rect(505, 5, 50, 50), child->drawable_content_rect());
+ EXPECT_TRUE(child->drawable_content_rect().IsEmpty());
+}
+
+TEST_F(LayerTreeHostCommonTest,
+ SingularTransformDoesNotPreventClearingDrawProperties) {
+ scoped_refptr<Layer> root = Layer::Create();
+ scoped_refptr<LayerWithForcedDrawsContent> child =
+ make_scoped_refptr(new LayerWithForcedDrawsContent());
+ root->AddChild(child);
+
+ scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create();
+ host->SetRootLayer(root);
+
+ gfx::Transform identity_matrix;
+ gfx::Transform uninvertible_matrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
+ ASSERT_FALSE(uninvertible_matrix.IsInvertible());
+
+ SetLayerPropertiesForTesting(root.get(),
+ uninvertible_matrix,
+ gfx::Point3F(),
+ gfx::PointF(),
+ gfx::Size(100, 100),
+ true,
+ false);
+ SetLayerPropertiesForTesting(child.get(),
+ identity_matrix,
+ gfx::Point3F(),
+ gfx::PointF(5.f, 5.f),
+ gfx::Size(50, 50),
+ true,
+ false);
+
+ child->draw_properties().sorted_for_recursion = true;
+
+ TransformOperations start_transform_operations;
+ start_transform_operations.AppendScale(1.f, 0.f, 0.f);
+
+ TransformOperations end_transform_operations;
+ end_transform_operations.AppendScale(1.f, 1.f, 0.f);
+
+ AddAnimatedTransformToLayer(
+ root.get(), 10.0, start_transform_operations, end_transform_operations);
+
+ EXPECT_TRUE(root->TransformIsAnimating());
+
+ ExecuteCalculateDrawProperties(root.get());
+
+ EXPECT_FALSE(child->draw_properties().sorted_for_recursion);
+}
+
+TEST_F(LayerTreeHostCommonTest,
+ SingularNonAnimatingTransformDoesNotPreventClearingDrawProperties) {
+ scoped_refptr<Layer> root = Layer::Create();
+
+ scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create();
+ host->SetRootLayer(root);
+
+ gfx::Transform identity_matrix;
+ gfx::Transform uninvertible_matrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
+ ASSERT_FALSE(uninvertible_matrix.IsInvertible());
+
+ SetLayerPropertiesForTesting(root.get(),
+ uninvertible_matrix,
+ gfx::Point3F(),
+ gfx::PointF(),
+ gfx::Size(100, 100),
+ true,
+ false);
+
+ root->draw_properties().sorted_for_recursion = true;
+
+ EXPECT_FALSE(root->TransformIsAnimating());
+
+ ExecuteCalculateDrawProperties(root.get());
+
+ EXPECT_FALSE(root->draw_properties().sorted_for_recursion);
}
TEST_F(LayerTreeHostCommonTest,
@@ -3120,38 +2977,38 @@ TEST_F(LayerTreeHostCommonTest,
gfx::Transform identity_matrix;
SetLayerPropertiesForTesting(root.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ true,
false);
SetLayerPropertiesForTesting(render_surface1.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(3, 4),
+ true,
false);
SetLayerPropertiesForTesting(child1.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(5.f, 5.f),
gfx::Size(50, 50),
+ true,
false);
SetLayerPropertiesForTesting(child2.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(75.f, 75.f),
gfx::Size(50, 50),
+ true,
false);
SetLayerPropertiesForTesting(child3.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(125.f, 125.f),
gfx::Size(50, 50),
+ true,
false);
root->SetMasksToBounds(true);
@@ -3210,45 +3067,45 @@ TEST_F(LayerTreeHostCommonTest,
gfx::Transform identity_matrix;
SetLayerPropertiesForTesting(root.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ true,
false);
SetLayerPropertiesForTesting(render_surface1.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(3, 4),
+ true,
false);
SetLayerPropertiesForTesting(render_surface2.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(7, 13),
+ true,
false);
SetLayerPropertiesForTesting(child1.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(5.f, 5.f),
gfx::Size(50, 50),
+ true,
false);
SetLayerPropertiesForTesting(child2.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(75.f, 75.f),
gfx::Size(50, 50),
+ true,
false);
SetLayerPropertiesForTesting(child3.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(125.f, 125.f),
gfx::Size(50, 50),
+ true,
false);
root->SetMasksToBounds(true);
@@ -3312,24 +3169,24 @@ TEST_F(LayerTreeHostCommonTest,
child_rotation.Rotate(45.0);
SetLayerPropertiesForTesting(root.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ true,
false);
SetLayerPropertiesForTesting(render_surface1.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(3, 4),
+ true,
false);
SetLayerPropertiesForTesting(child1.get(),
child_rotation,
- identity_matrix,
- gfx::PointF(0.5f, 0.5f),
+ gfx::Point3F(25, 25, 0.f),
gfx::PointF(25.f, 25.f),
gfx::Size(50, 50),
+ true,
false);
render_surface1->SetForceRenderSurface(true);
@@ -3383,24 +3240,25 @@ TEST_F(LayerTreeHostCommonTest,
child_rotation.Rotate(45.0);
SetLayerPropertiesForTesting(root.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(50, 50),
+ true,
false);
SetLayerPropertiesForTesting(render_surface1.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(3, 4),
+ true,
false);
+
SetLayerPropertiesForTesting(child1.get(),
child_rotation,
- identity_matrix,
- gfx::PointF(0.5f, 0.5f),
+ gfx::Point3F(25, 25, 0.f),
gfx::PointF(25.f, 25.f),
gfx::Size(50, 50),
+ true,
false);
root->SetMasksToBounds(true);
@@ -3455,45 +3313,45 @@ TEST_F(LayerTreeHostCommonTest, DrawableAndVisibleContentRectsInHighDPI) {
gfx::Transform identity_matrix;
SetLayerPropertiesForTesting(root.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ true,
false);
SetLayerPropertiesForTesting(render_surface1.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(5.f, 5.f),
gfx::Size(3, 4),
+ true,
false);
SetLayerPropertiesForTesting(render_surface2.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(5.f, 5.f),
gfx::Size(7, 13),
+ true,
false);
SetLayerPropertiesForTesting(child1.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(5.f, 5.f),
gfx::Size(50, 50),
+ true,
false);
SetLayerPropertiesForTesting(child2.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(75.f, 75.f),
gfx::Size(50, 50),
+ true,
false);
SetLayerPropertiesForTesting(child3.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(125.f, 125.f),
gfx::Size(50, 50),
+ true,
false);
float device_scale_factor = 2.f;
@@ -3603,66 +3461,66 @@ TEST_F(LayerTreeHostCommonTest, BackFaceCullingWithoutPreserves3d) {
// back-face culling.
SetLayerPropertiesForTesting(parent.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ true,
false);
SetLayerPropertiesForTesting(front_facing_child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ true,
false);
SetLayerPropertiesForTesting(back_facing_child.get(),
backface_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ true,
false);
SetLayerPropertiesForTesting(front_facing_surface.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ true,
false);
SetLayerPropertiesForTesting(back_facing_surface.get(),
backface_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ true,
false);
SetLayerPropertiesForTesting(front_facing_child_of_front_facing_surface.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ true,
false);
SetLayerPropertiesForTesting(back_facing_child_of_front_facing_surface.get(),
backface_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ true,
false);
SetLayerPropertiesForTesting(front_facing_child_of_back_facing_surface.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ true,
false);
SetLayerPropertiesForTesting(back_facing_child_of_back_facing_surface.get(),
backface_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ true,
false);
RenderSurfaceLayerList render_surface_layer_list;
@@ -3695,13 +3553,22 @@ TEST_F(LayerTreeHostCommonTest, BackFaceCullingWithoutPreserves3d) {
render_surface_layer_list.at(0)->render_surface()->layer_list().size());
EXPECT_EQ(front_facing_child->id(),
render_surface_layer_list.at(0)
- ->render_surface()->layer_list().at(0)->id());
+ ->render_surface()
+ ->layer_list()
+ .at(0)
+ ->id());
EXPECT_EQ(front_facing_surface->id(),
render_surface_layer_list.at(0)
- ->render_surface()->layer_list().at(1)->id());
+ ->render_surface()
+ ->layer_list()
+ .at(1)
+ ->id());
EXPECT_EQ(back_facing_surface->id(),
render_surface_layer_list.at(0)
- ->render_surface()->layer_list().at(2)->id());
+ ->render_surface()
+ ->layer_list()
+ .at(2)
+ ->id());
// Verify front_facing_surface's layer list.
ASSERT_EQ(
@@ -3709,10 +3576,16 @@ TEST_F(LayerTreeHostCommonTest, BackFaceCullingWithoutPreserves3d) {
render_surface_layer_list.at(1)->render_surface()->layer_list().size());
EXPECT_EQ(front_facing_surface->id(),
render_surface_layer_list.at(1)
- ->render_surface()->layer_list().at(0)->id());
+ ->render_surface()
+ ->layer_list()
+ .at(0)
+ ->id());
EXPECT_EQ(front_facing_child_of_front_facing_surface->id(),
render_surface_layer_list.at(1)
- ->render_surface()->layer_list().at(1)->id());
+ ->render_surface()
+ ->layer_list()
+ .at(1)
+ ->id());
// Verify back_facing_surface's layer list; its own layer should be culled
// from the surface list.
@@ -3721,7 +3594,10 @@ TEST_F(LayerTreeHostCommonTest, BackFaceCullingWithoutPreserves3d) {
render_surface_layer_list.at(2)->render_surface()->layer_list().size());
EXPECT_EQ(front_facing_child_of_back_facing_surface->id(),
render_surface_layer_list.at(2)
- ->render_surface()->layer_list().at(0)->id());
+ ->render_surface()
+ ->layer_list()
+ .at(0)
+ ->id());
}
TEST_F(LayerTreeHostCommonTest, BackFaceCullingWithPreserves3d) {
@@ -3795,69 +3671,69 @@ TEST_F(LayerTreeHostCommonTest, BackFaceCullingWithPreserves3d) {
// and (b) the layer's transform style is preserve-3d.
SetLayerPropertiesForTesting(parent.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ true,
false); // parent transform style is flat.
SetLayerPropertiesForTesting(front_facing_child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ true,
false);
SetLayerPropertiesForTesting(back_facing_child.get(),
backface_matrix,
+ gfx::Point3F(),
+ gfx::PointF(),
+ gfx::Size(100, 100),
+ true,
+ false);
+ // surface transform style is preserve-3d.
+ SetLayerPropertiesForTesting(front_facing_surface.get(),
identity_matrix,
+ gfx::Point3F(),
gfx::PointF(),
+ gfx::Size(100, 100),
+ false,
+ true);
+ // surface transform style is preserve-3d.
+ SetLayerPropertiesForTesting(back_facing_surface.get(),
+ backface_matrix,
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
- false);
- SetLayerPropertiesForTesting(
- front_facing_surface.get(),
- identity_matrix,
- identity_matrix,
- gfx::PointF(),
- gfx::PointF(),
- gfx::Size(100, 100),
- true); // surface transform style is preserve-3d.
- SetLayerPropertiesForTesting(
- back_facing_surface.get(),
- backface_matrix,
- identity_matrix,
- gfx::PointF(),
- gfx::PointF(),
- gfx::Size(100, 100),
- true); // surface transform style is preserve-3d.
+ false,
+ true);
SetLayerPropertiesForTesting(front_facing_child_of_front_facing_surface.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
- false);
+ true,
+ true);
SetLayerPropertiesForTesting(back_facing_child_of_front_facing_surface.get(),
backface_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
- false);
+ true,
+ true);
SetLayerPropertiesForTesting(front_facing_child_of_back_facing_surface.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
- false);
+ true,
+ true);
SetLayerPropertiesForTesting(back_facing_child_of_back_facing_surface.get(),
backface_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
- false);
+ true,
+ true);
RenderSurfaceLayerList render_surface_layer_list;
LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs(
@@ -3957,45 +3833,45 @@ TEST_F(LayerTreeHostCommonTest, BackFaceCullingWithAnimatingTransforms) {
SetLayerPropertiesForTesting(parent.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ true,
false);
SetLayerPropertiesForTesting(child.get(),
backface_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ true,
false);
SetLayerPropertiesForTesting(animating_surface.get(),
backface_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ true,
false);
SetLayerPropertiesForTesting(child_of_animating_surface.get(),
backface_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ true,
false);
SetLayerPropertiesForTesting(animating_child.get(),
backface_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ true,
false);
SetLayerPropertiesForTesting(child2.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ true,
false);
RenderSurfaceLayerList render_surface_layer_list;
@@ -4090,40 +3966,43 @@ TEST_F(LayerTreeHostCommonTest,
SetLayerPropertiesForTesting(parent.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
- true); // parent transform style is preserve3d.
+ false,
+ true); // parent transform style is preserve3d.
SetLayerPropertiesForTesting(front_facing_surface.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
- false); // surface transform style is flat.
+ true,
+ true); // surface transform style is flat.
SetLayerPropertiesForTesting(back_facing_surface.get(),
backface_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
- false); // surface transform style is flat.
+ true,
+ true); // surface transform style is flat.
SetLayerPropertiesForTesting(child1.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ true,
false);
SetLayerPropertiesForTesting(child2.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ true,
false);
+ front_facing_surface->Set3dSortingContextId(1);
+ back_facing_surface->Set3dSortingContextId(1);
+
RenderSurfaceLayerList render_surface_layer_list;
LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs(
parent.get(), parent->bounds(), &render_surface_layer_list);
@@ -4163,1952 +4042,6 @@ TEST_F(LayerTreeHostCommonTest,
->render_surface()->layer_list().at(1)->id());
}
-
-TEST_F(LayerTreeHostCommonTest, HitTestingForEmptyLayerList) {
- // Hit testing on an empty render_surface_layer_list should return a null
- // pointer.
- LayerImplList render_surface_layer_list;
-
- gfx::Point test_point(0, 0);
- LayerImpl* result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- test_point = gfx::Point(10, 20);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-}
-
-TEST_F(LayerTreeHostCommonTest, HitTestingForSingleLayer) {
- FakeImplProxy proxy;
- FakeLayerTreeHostImpl host_impl(&proxy);
- scoped_ptr<LayerImpl> root =
- LayerImpl::Create(host_impl.active_tree(), 12345);
-
- gfx::Transform identity_matrix;
- gfx::PointF anchor;
- gfx::PointF position;
- gfx::Size bounds(100, 100);
- SetLayerPropertiesForTesting(root.get(),
- identity_matrix,
- identity_matrix,
- anchor,
- position,
- bounds,
- false);
- root->SetDrawsContent(true);
-
- LayerImplList render_surface_layer_list;
- LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root.get(), root->bounds(), &render_surface_layer_list);
- inputs.can_adjust_raster_scales = true;
- LayerTreeHostCommon::CalculateDrawProperties(&inputs);
-
- // Sanity check the scenario we just created.
- ASSERT_EQ(1u, render_surface_layer_list.size());
- ASSERT_EQ(1u, root->render_surface()->layer_list().size());
-
- // Hit testing for a point outside the layer should return a null pointer.
- gfx::Point test_point(101, 101);
- LayerImpl* result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- test_point = gfx::Point(-1, -1);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- // Hit testing for a point inside should return the root layer.
- test_point = gfx::Point(1, 1);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- ASSERT_TRUE(result_layer);
- EXPECT_EQ(12345, result_layer->id());
-
- test_point = gfx::Point(99, 99);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- ASSERT_TRUE(result_layer);
- EXPECT_EQ(12345, result_layer->id());
-}
-
-TEST_F(LayerTreeHostCommonTest, HitTestingForSingleLayerAndHud) {
- FakeImplProxy proxy;
- FakeLayerTreeHostImpl host_impl(&proxy);
- scoped_ptr<LayerImpl> root =
- LayerImpl::Create(host_impl.active_tree(), 12345);
- scoped_ptr<HeadsUpDisplayLayerImpl> hud =
- HeadsUpDisplayLayerImpl::Create(host_impl.active_tree(), 11111);
-
- gfx::Transform identity_matrix;
- gfx::PointF anchor;
- gfx::PointF position;
- gfx::Size bounds(100, 100);
- SetLayerPropertiesForTesting(root.get(),
- identity_matrix,
- identity_matrix,
- anchor,
- position,
- bounds,
- false);
- root->SetDrawsContent(true);
-
- // Create hud and add it as a child of root.
- gfx::Size hud_bounds(200, 200);
- SetLayerPropertiesForTesting(hud.get(),
- identity_matrix,
- identity_matrix,
- anchor,
- position,
- hud_bounds,
- false);
- hud->SetDrawsContent(true);
-
- host_impl.active_tree()->set_hud_layer(hud.get());
- root->AddChild(hud.PassAs<LayerImpl>());
-
- LayerImplList render_surface_layer_list;
- LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root.get(), hud_bounds, &render_surface_layer_list);
- inputs.can_adjust_raster_scales = true;
- LayerTreeHostCommon::CalculateDrawProperties(&inputs);
-
- // Sanity check the scenario we just created.
- ASSERT_EQ(1u, render_surface_layer_list.size());
- ASSERT_EQ(2u, root->render_surface()->layer_list().size());
-
- // Hit testing for a point inside HUD, but outside root should return null
- gfx::Point test_point(101, 101);
- LayerImpl* result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- test_point = gfx::Point(-1, -1);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- // Hit testing for a point inside should return the root layer, never the HUD
- // layer.
- test_point = gfx::Point(1, 1);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- ASSERT_TRUE(result_layer);
- EXPECT_EQ(12345, result_layer->id());
-
- test_point = gfx::Point(99, 99);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- ASSERT_TRUE(result_layer);
- EXPECT_EQ(12345, result_layer->id());
-}
-
-TEST_F(LayerTreeHostCommonTest, HitTestingForUninvertibleTransform) {
- FakeImplProxy proxy;
- FakeLayerTreeHostImpl host_impl(&proxy);
- scoped_ptr<LayerImpl> root =
- LayerImpl::Create(host_impl.active_tree(), 12345);
-
- gfx::Transform uninvertible_transform;
- uninvertible_transform.matrix().set(0, 0, 0.0);
- uninvertible_transform.matrix().set(1, 1, 0.0);
- uninvertible_transform.matrix().set(2, 2, 0.0);
- uninvertible_transform.matrix().set(3, 3, 0.0);
- ASSERT_FALSE(uninvertible_transform.IsInvertible());
-
- gfx::Transform identity_matrix;
- gfx::PointF anchor;
- gfx::PointF position;
- gfx::Size bounds(100, 100);
- SetLayerPropertiesForTesting(root.get(),
- uninvertible_transform,
- identity_matrix,
- anchor,
- position,
- bounds,
- false);
- root->SetDrawsContent(true);
-
- LayerImplList render_surface_layer_list;
- LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root.get(), root->bounds(), &render_surface_layer_list);
- inputs.can_adjust_raster_scales = true;
- LayerTreeHostCommon::CalculateDrawProperties(&inputs);
-
- // Sanity check the scenario we just created.
- ASSERT_EQ(1u, render_surface_layer_list.size());
- ASSERT_EQ(1u, root->render_surface()->layer_list().size());
- ASSERT_FALSE(root->screen_space_transform().IsInvertible());
-
- // Hit testing any point should not hit the layer. If the invertible matrix is
- // accidentally ignored and treated like an identity, then the hit testing
- // will incorrectly hit the layer when it shouldn't.
- gfx::Point test_point(1, 1);
- LayerImpl* result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- test_point = gfx::Point(10, 10);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- test_point = gfx::Point(10, 30);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- test_point = gfx::Point(50, 50);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- test_point = gfx::Point(67, 48);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- test_point = gfx::Point(99, 99);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- test_point = gfx::Point(-1, -1);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-}
-
-TEST_F(LayerTreeHostCommonTest, HitTestingForSinglePositionedLayer) {
- FakeImplProxy proxy;
- FakeLayerTreeHostImpl host_impl(&proxy);
- scoped_ptr<LayerImpl> root =
- LayerImpl::Create(host_impl.active_tree(), 12345);
-
- gfx::Transform identity_matrix;
- gfx::PointF anchor;
- // this layer is positioned, and hit testing should correctly know where the
- // layer is located.
- gfx::PointF position(50.f, 50.f);
- gfx::Size bounds(100, 100);
- SetLayerPropertiesForTesting(root.get(),
- identity_matrix,
- identity_matrix,
- anchor,
- position,
- bounds,
- false);
- root->SetDrawsContent(true);
-
- LayerImplList render_surface_layer_list;
- LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root.get(), root->bounds(), &render_surface_layer_list);
- inputs.can_adjust_raster_scales = true;
- LayerTreeHostCommon::CalculateDrawProperties(&inputs);
-
- // Sanity check the scenario we just created.
- ASSERT_EQ(1u, render_surface_layer_list.size());
- ASSERT_EQ(1u, root->render_surface()->layer_list().size());
-
- // Hit testing for a point outside the layer should return a null pointer.
- gfx::Point test_point(49, 49);
- LayerImpl* result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- // Even though the layer exists at (101, 101), it should not be visible there
- // since the root render surface would clamp it.
- test_point = gfx::Point(101, 101);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- // Hit testing for a point inside should return the root layer.
- test_point = gfx::Point(51, 51);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- ASSERT_TRUE(result_layer);
- EXPECT_EQ(12345, result_layer->id());
-
- test_point = gfx::Point(99, 99);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- ASSERT_TRUE(result_layer);
- EXPECT_EQ(12345, result_layer->id());
-}
-
-TEST_F(LayerTreeHostCommonTest, HitTestingForSingleRotatedLayer) {
- FakeImplProxy proxy;
- FakeLayerTreeHostImpl host_impl(&proxy);
- scoped_ptr<LayerImpl> root =
- LayerImpl::Create(host_impl.active_tree(), 12345);
-
- gfx::Transform identity_matrix;
- gfx::Transform rotation45_degrees_about_center;
- rotation45_degrees_about_center.Translate(50.0, 50.0);
- rotation45_degrees_about_center.RotateAboutZAxis(45.0);
- rotation45_degrees_about_center.Translate(-50.0, -50.0);
- gfx::PointF anchor;
- gfx::PointF position;
- gfx::Size bounds(100, 100);
- SetLayerPropertiesForTesting(root.get(),
- rotation45_degrees_about_center,
- identity_matrix,
- anchor,
- position,
- bounds,
- false);
- root->SetDrawsContent(true);
-
- LayerImplList render_surface_layer_list;
- LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root.get(), root->bounds(), &render_surface_layer_list);
- inputs.can_adjust_raster_scales = true;
- LayerTreeHostCommon::CalculateDrawProperties(&inputs);
-
- // Sanity check the scenario we just created.
- ASSERT_EQ(1u, render_surface_layer_list.size());
- ASSERT_EQ(1u, root->render_surface()->layer_list().size());
-
- // Hit testing for points outside the layer.
- // These corners would have been inside the un-transformed layer, but they
- // should not hit the correctly transformed layer.
- gfx::Point test_point(99, 99);
- LayerImpl* result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- test_point = gfx::Point(1, 1);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- // Hit testing for a point inside should return the root layer.
- test_point = gfx::Point(1, 50);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- ASSERT_TRUE(result_layer);
- EXPECT_EQ(12345, result_layer->id());
-
- // Hit testing the corners that would overlap the unclipped layer, but are
- // outside the clipped region.
- test_point = gfx::Point(50, -1);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- ASSERT_FALSE(result_layer);
-
- test_point = gfx::Point(-1, 50);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- ASSERT_FALSE(result_layer);
-}
-
-TEST_F(LayerTreeHostCommonTest, HitTestingForSinglePerspectiveLayer) {
- FakeImplProxy proxy;
- FakeLayerTreeHostImpl host_impl(&proxy);
- scoped_ptr<LayerImpl> root =
- LayerImpl::Create(host_impl.active_tree(), 12345);
-
- gfx::Transform identity_matrix;
-
- // 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).
- gfx::Transform perspective_projection_about_center;
- perspective_projection_about_center.Translate(50.0, 50.0);
- perspective_projection_about_center.ApplyPerspectiveDepth(1.0);
- perspective_projection_about_center.Translate(-50.0, -50.0);
- gfx::Transform translation_by_z;
- translation_by_z.Translate3d(0.0, 0.0, -1.0);
-
- gfx::PointF anchor;
- gfx::PointF position;
- gfx::Size bounds(100, 100);
- SetLayerPropertiesForTesting(
- root.get(),
- perspective_projection_about_center * translation_by_z,
- identity_matrix,
- anchor,
- position,
- bounds,
- false);
- root->SetDrawsContent(true);
-
- LayerImplList render_surface_layer_list;
- LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root.get(), root->bounds(), &render_surface_layer_list);
- inputs.can_adjust_raster_scales = true;
- LayerTreeHostCommon::CalculateDrawProperties(&inputs);
-
- // Sanity check the scenario we just created.
- ASSERT_EQ(1u, render_surface_layer_list.size());
- ASSERT_EQ(1u, root->render_surface()->layer_list().size());
-
- // Hit testing for points outside the layer.
- // These corners would have been inside the un-transformed layer, but they
- // should not hit the correctly transformed layer.
- gfx::Point test_point(24, 24);
- LayerImpl* result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- test_point = gfx::Point(76, 76);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- // Hit testing for a point inside should return the root layer.
- test_point = gfx::Point(26, 26);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- ASSERT_TRUE(result_layer);
- EXPECT_EQ(12345, result_layer->id());
-
- test_point = gfx::Point(74, 74);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- ASSERT_TRUE(result_layer);
- EXPECT_EQ(12345, result_layer->id());
-}
-
-TEST_F(LayerTreeHostCommonTest, HitTestingForSingleLayerWithScaledContents) {
- // A layer's visible content rect is actually in the layer's content space.
- // The screen space transform converts from the layer's origin space to screen
- // space. This test makes sure that hit testing works correctly accounts for
- // the contents scale. A contents scale that is not 1 effectively forces a
- // non-identity transform between layer's content space and layer's origin
- // space. The hit testing code must take this into account.
- //
- // To test this, the layer is positioned at (25, 25), and is size (50, 50). If
- // contents scale is ignored, then hit testing will mis-interpret the visible
- // content rect as being larger than the actual bounds of the layer.
- //
- FakeImplProxy proxy;
- FakeLayerTreeHostImpl host_impl(&proxy);
- scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl.active_tree(), 1);
-
- gfx::Transform identity_matrix;
- gfx::PointF anchor;
-
- SetLayerPropertiesForTesting(root.get(),
- identity_matrix,
- identity_matrix,
- anchor,
- gfx::PointF(),
- gfx::Size(100, 100),
- false);
- {
- gfx::PointF position(25.f, 25.f);
- gfx::Size bounds(50, 50);
- scoped_ptr<LayerImpl> test_layer =
- LayerImpl::Create(host_impl.active_tree(), 12345);
- SetLayerPropertiesForTesting(test_layer.get(),
- identity_matrix,
- identity_matrix,
- anchor,
- position,
- bounds,
- false);
-
- // override content bounds and contents scale
- test_layer->SetContentBounds(gfx::Size(100, 100));
- test_layer->SetContentsScale(2, 2);
-
- test_layer->SetDrawsContent(true);
- root->AddChild(test_layer.Pass());
- }
-
- LayerImplList render_surface_layer_list;
- LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root.get(), root->bounds(), &render_surface_layer_list);
- inputs.can_adjust_raster_scales = true;
- LayerTreeHostCommon::CalculateDrawProperties(&inputs);
-
- // Sanity check the scenario we just created.
- // The visible content rect for test_layer is actually 100x100, even though
- // its layout size is 50x50, positioned at 25x25.
- LayerImpl* test_layer = root->children()[0];
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100),
- test_layer->visible_content_rect());
- ASSERT_EQ(1u, render_surface_layer_list.size());
- ASSERT_EQ(1u, root->render_surface()->layer_list().size());
-
- // Hit testing for a point outside the layer should return a null pointer (the
- // root layer does not draw content, so it will not be hit tested either).
- gfx::Point test_point(101, 101);
- LayerImpl* result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- test_point = gfx::Point(24, 24);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- test_point = gfx::Point(76, 76);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- // Hit testing for a point inside should return the test layer.
- test_point = gfx::Point(26, 26);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- ASSERT_TRUE(result_layer);
- EXPECT_EQ(12345, result_layer->id());
-
- test_point = gfx::Point(74, 74);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- ASSERT_TRUE(result_layer);
- EXPECT_EQ(12345, result_layer->id());
-}
-
-TEST_F(LayerTreeHostCommonTest, HitTestingForSimpleClippedLayer) {
- // Test that hit-testing will only work for the visible portion of a layer,
- // and not the entire layer bounds. Here we just test the simple axis-aligned
- // case.
- gfx::Transform identity_matrix;
- gfx::PointF anchor;
-
- FakeImplProxy proxy;
- FakeLayerTreeHostImpl host_impl(&proxy);
- scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl.active_tree(), 1);
- SetLayerPropertiesForTesting(root.get(),
- identity_matrix,
- identity_matrix,
- anchor,
- gfx::PointF(),
- gfx::Size(100, 100),
- false);
- {
- scoped_ptr<LayerImpl> clipping_layer =
- LayerImpl::Create(host_impl.active_tree(), 123);
- // this layer is positioned, and hit testing should correctly know where the
- // layer is located.
- gfx::PointF position(25.f, 25.f);
- gfx::Size bounds(50, 50);
- SetLayerPropertiesForTesting(clipping_layer.get(),
- identity_matrix,
- identity_matrix,
- anchor,
- position,
- bounds,
- false);
- clipping_layer->SetMasksToBounds(true);
-
- scoped_ptr<LayerImpl> child =
- LayerImpl::Create(host_impl.active_tree(), 456);
- position = gfx::PointF(-50.f, -50.f);
- bounds = gfx::Size(300, 300);
- SetLayerPropertiesForTesting(child.get(),
- identity_matrix,
- identity_matrix,
- anchor,
- position,
- bounds,
- false);
- child->SetDrawsContent(true);
- clipping_layer->AddChild(child.Pass());
- root->AddChild(clipping_layer.Pass());
- }
-
- LayerImplList render_surface_layer_list;
- LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root.get(), root->bounds(), &render_surface_layer_list);
- inputs.can_adjust_raster_scales = true;
- LayerTreeHostCommon::CalculateDrawProperties(&inputs);
-
- // Sanity check the scenario we just created.
- ASSERT_EQ(1u, render_surface_layer_list.size());
- ASSERT_EQ(1u, root->render_surface()->layer_list().size());
- ASSERT_EQ(456, root->render_surface()->layer_list().at(0)->id());
-
- // 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
- // layer's bounds.
- gfx::Point test_point(24, 24);
- LayerImpl* result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- // Even though the layer exists at (101, 101), it should not be visible there
- // since the clipping_layer would clamp it.
- test_point = gfx::Point(76, 76);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- // Hit testing for a point inside should return the child layer.
- test_point = gfx::Point(26, 26);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- ASSERT_TRUE(result_layer);
- EXPECT_EQ(456, result_layer->id());
-
- test_point = gfx::Point(74, 74);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- ASSERT_TRUE(result_layer);
- EXPECT_EQ(456, result_layer->id());
-}
-
-TEST_F(LayerTreeHostCommonTest, HitTestingForMultiClippedRotatedLayer) {
- // This test checks whether hit testing correctly avoids hit testing with
- // multiple ancestors that clip in non axis-aligned ways. To pass this test,
- // the hit testing algorithm needs to recognize that multiple parent layers
- // may clip the layer, and should not actually hit those clipped areas.
- //
- // The child and grand_child layers are both initialized to clip the
- // rotated_leaf. The child layer is rotated about the top-left corner, so that
- // the root + child clips combined create a triangle. The rotated_leaf will
- // only be visible where it overlaps this triangle.
- //
- FakeImplProxy proxy;
- FakeLayerTreeHostImpl host_impl(&proxy);
- scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl.active_tree(), 123);
-
- gfx::Transform identity_matrix;
- gfx::PointF anchor;
- gfx::PointF position;
- gfx::Size bounds(100, 100);
- SetLayerPropertiesForTesting(root.get(),
- identity_matrix,
- identity_matrix,
- anchor,
- position,
- bounds,
- false);
- root->SetMasksToBounds(true);
- {
- scoped_ptr<LayerImpl> child =
- LayerImpl::Create(host_impl.active_tree(), 456);
- scoped_ptr<LayerImpl> grand_child =
- LayerImpl::Create(host_impl.active_tree(), 789);
- scoped_ptr<LayerImpl> rotated_leaf =
- LayerImpl::Create(host_impl.active_tree(), 2468);
-
- position = gfx::PointF(10.f, 10.f);
- bounds = gfx::Size(80, 80);
- SetLayerPropertiesForTesting(child.get(),
- identity_matrix,
- identity_matrix,
- anchor,
- position,
- bounds,
- false);
- child->SetMasksToBounds(true);
-
- gfx::Transform rotation45_degrees_about_corner;
- rotation45_degrees_about_corner.RotateAboutZAxis(45.0);
-
- // remember, positioned with respect to its parent which is already at 10,
- // 10
- position = gfx::PointF();
- bounds =
- gfx::Size(200, 200); // to ensure it covers at least sqrt(2) * 100.
- SetLayerPropertiesForTesting(grand_child.get(),
- rotation45_degrees_about_corner,
- identity_matrix,
- anchor,
- position,
- bounds,
- false);
- grand_child->SetMasksToBounds(true);
-
- // Rotates about the center of the layer
- gfx::Transform rotated_leaf_transform;
- rotated_leaf_transform.Translate(
- -10.0, -10.0); // cancel out the grand_parent's position
- rotated_leaf_transform.RotateAboutZAxis(
- -45.0); // cancel out the corner 45-degree rotation of the parent.
- rotated_leaf_transform.Translate(50.0, 50.0);
- rotated_leaf_transform.RotateAboutZAxis(45.0);
- rotated_leaf_transform.Translate(-50.0, -50.0);
- position = gfx::PointF();
- bounds = gfx::Size(100, 100);
- SetLayerPropertiesForTesting(rotated_leaf.get(),
- rotated_leaf_transform,
- identity_matrix,
- anchor,
- position,
- bounds,
- false);
- rotated_leaf->SetDrawsContent(true);
-
- grand_child->AddChild(rotated_leaf.Pass());
- child->AddChild(grand_child.Pass());
- root->AddChild(child.Pass());
- }
-
- LayerImplList render_surface_layer_list;
- LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root.get(), root->bounds(), &render_surface_layer_list);
- inputs.can_adjust_raster_scales = true;
- LayerTreeHostCommon::CalculateDrawProperties(&inputs);
-
- // Sanity check the scenario we just created.
- // The grand_child is expected to create a render surface because it
- // MasksToBounds and is not axis aligned.
- ASSERT_EQ(2u, render_surface_layer_list.size());
- ASSERT_EQ(
- 1u,
- render_surface_layer_list.at(0)->render_surface()->layer_list().size());
- ASSERT_EQ(789,
- render_surface_layer_list.at(0)->render_surface()->layer_list().at(
- 0)->id()); // grand_child's surface.
- ASSERT_EQ(
- 1u,
- render_surface_layer_list.at(1)->render_surface()->layer_list().size());
- ASSERT_EQ(
- 2468,
- render_surface_layer_list[1]->render_surface()->layer_list().at(0)->id());
-
- // (11, 89) is close to the the bottom left corner within the clip, but it is
- // not inside the layer.
- gfx::Point test_point(11, 89);
- LayerImpl* result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- // Closer inwards from the bottom left will overlap the layer.
- test_point = gfx::Point(25, 75);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- ASSERT_TRUE(result_layer);
- EXPECT_EQ(2468, result_layer->id());
-
- // (4, 50) is inside the unclipped layer, but that corner of the layer should
- // be clipped away by the grandparent and should not get hit. If hit testing
- // blindly uses visible content rect without considering how parent may clip
- // the layer, then hit testing would accidentally think that the point
- // successfully hits the layer.
- test_point = gfx::Point(4, 50);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- // (11, 50) is inside the layer and within the clipped area.
- test_point = gfx::Point(11, 50);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- ASSERT_TRUE(result_layer);
- EXPECT_EQ(2468, result_layer->id());
-
- // Around the middle, just to the right and up, would have hit the layer
- // except that that area should be clipped away by the parent.
- test_point = gfx::Point(51, 49);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- // Around the middle, just to the left and down, should successfully hit the
- // layer.
- test_point = gfx::Point(49, 51);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- ASSERT_TRUE(result_layer);
- EXPECT_EQ(2468, result_layer->id());
-}
-
-TEST_F(LayerTreeHostCommonTest, HitTestingForNonClippingIntermediateLayer) {
- // This test checks that hit testing code does not accidentally clip to layer
- // bounds for a layer that actually does not clip.
- gfx::Transform identity_matrix;
- gfx::PointF anchor;
-
- FakeImplProxy proxy;
- FakeLayerTreeHostImpl host_impl(&proxy);
- scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl.active_tree(), 1);
- SetLayerPropertiesForTesting(root.get(),
- identity_matrix,
- identity_matrix,
- anchor,
- gfx::PointF(),
- gfx::Size(100, 100),
- false);
- {
- scoped_ptr<LayerImpl> intermediate_layer =
- LayerImpl::Create(host_impl.active_tree(), 123);
- // this layer is positioned, and hit testing should correctly know where the
- // layer is located.
- gfx::PointF position(10.f, 10.f);
- gfx::Size bounds(50, 50);
- SetLayerPropertiesForTesting(intermediate_layer.get(),
- identity_matrix,
- identity_matrix,
- anchor,
- position,
- bounds,
- false);
- // Sanity check the intermediate layer should not clip.
- ASSERT_FALSE(intermediate_layer->masks_to_bounds());
- ASSERT_FALSE(intermediate_layer->mask_layer());
-
- // The child of the intermediate_layer is translated so that it does not
- // overlap intermediate_layer at all. If child is incorrectly clipped, we
- // would not be able to hit it successfully.
- scoped_ptr<LayerImpl> child =
- LayerImpl::Create(host_impl.active_tree(), 456);
- position = gfx::PointF(60.f, 60.f); // 70, 70 in screen space
- bounds = gfx::Size(20, 20);
- SetLayerPropertiesForTesting(child.get(),
- identity_matrix,
- identity_matrix,
- anchor,
- position,
- bounds,
- false);
- child->SetDrawsContent(true);
- intermediate_layer->AddChild(child.Pass());
- root->AddChild(intermediate_layer.Pass());
- }
-
- LayerImplList render_surface_layer_list;
- LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root.get(), root->bounds(), &render_surface_layer_list);
- inputs.can_adjust_raster_scales = true;
- LayerTreeHostCommon::CalculateDrawProperties(&inputs);
-
- // Sanity check the scenario we just created.
- ASSERT_EQ(1u, render_surface_layer_list.size());
- ASSERT_EQ(1u, root->render_surface()->layer_list().size());
- ASSERT_EQ(456, root->render_surface()->layer_list().at(0)->id());
-
- // Hit testing for a point outside the layer should return a null pointer.
- gfx::Point test_point(69, 69);
- LayerImpl* result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- test_point = gfx::Point(91, 91);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- // Hit testing for a point inside should return the child layer.
- test_point = gfx::Point(71, 71);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- ASSERT_TRUE(result_layer);
- EXPECT_EQ(456, result_layer->id());
-
- test_point = gfx::Point(89, 89);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- ASSERT_TRUE(result_layer);
- EXPECT_EQ(456, result_layer->id());
-}
-
-TEST_F(LayerTreeHostCommonTest, HitTestingForMultipleLayers) {
- FakeImplProxy proxy;
- FakeLayerTreeHostImpl host_impl(&proxy);
- scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl.active_tree(), 1);
-
- gfx::Transform identity_matrix;
- gfx::PointF anchor;
- gfx::PointF position;
- gfx::Size bounds(100, 100);
- SetLayerPropertiesForTesting(root.get(),
- identity_matrix,
- identity_matrix,
- anchor,
- position,
- bounds,
- false);
- root->SetDrawsContent(true);
- {
- // child 1 and child2 are initialized to overlap between x=50 and x=60.
- // grand_child is set to overlap both child1 and child2 between y=50 and
- // y=60. The expected stacking order is: (front) child2, (second)
- // grand_child, (third) child1, and (back) the root layer behind all other
- // layers.
-
- scoped_ptr<LayerImpl> child1 =
- LayerImpl::Create(host_impl.active_tree(), 2);
- scoped_ptr<LayerImpl> child2 =
- LayerImpl::Create(host_impl.active_tree(), 3);
- scoped_ptr<LayerImpl> grand_child1 =
- LayerImpl::Create(host_impl.active_tree(), 4);
-
- position = gfx::PointF(10.f, 10.f);
- bounds = gfx::Size(50, 50);
- SetLayerPropertiesForTesting(child1.get(),
- identity_matrix,
- identity_matrix,
- anchor,
- position,
- bounds,
- false);
- child1->SetDrawsContent(true);
-
- position = gfx::PointF(50.f, 10.f);
- bounds = gfx::Size(50, 50);
- SetLayerPropertiesForTesting(child2.get(),
- identity_matrix,
- identity_matrix,
- anchor,
- position,
- bounds,
- false);
- child2->SetDrawsContent(true);
-
- // Remember that grand_child is positioned with respect to its parent (i.e.
- // child1). In screen space, the intended position is (10, 50), with size
- // 100 x 50.
- position = gfx::PointF(0.f, 40.f);
- bounds = gfx::Size(100, 50);
- SetLayerPropertiesForTesting(grand_child1.get(),
- identity_matrix,
- identity_matrix,
- anchor,
- position,
- bounds,
- false);
- grand_child1->SetDrawsContent(true);
-
- child1->AddChild(grand_child1.Pass());
- root->AddChild(child1.Pass());
- root->AddChild(child2.Pass());
- }
-
- LayerImpl* child1 = root->children()[0];
- LayerImpl* child2 = root->children()[1];
- LayerImpl* grand_child1 = child1->children()[0];
-
- LayerImplList render_surface_layer_list;
- LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root.get(), root->bounds(), &render_surface_layer_list);
- inputs.can_adjust_raster_scales = true;
- LayerTreeHostCommon::CalculateDrawProperties(&inputs);
-
- // Sanity check the scenario we just created.
- ASSERT_TRUE(child1);
- ASSERT_TRUE(child2);
- ASSERT_TRUE(grand_child1);
- ASSERT_EQ(1u, render_surface_layer_list.size());
-
- RenderSurfaceImpl* root_render_surface = root->render_surface();
- 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
-
- // Nothing overlaps the root_layer at (1, 1), so hit testing there should find
- // the root layer.
- gfx::Point test_point = gfx::Point(1, 1);
- LayerImpl* result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- ASSERT_TRUE(result_layer);
- EXPECT_EQ(1, result_layer->id());
-
- // At (15, 15), child1 and root are the only layers. child1 is expected to be
- // on top.
- test_point = gfx::Point(15, 15);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- ASSERT_TRUE(result_layer);
- EXPECT_EQ(2, result_layer->id());
-
- // At (51, 20), child1 and child2 overlap. child2 is expected to be on top.
- test_point = gfx::Point(51, 20);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- ASSERT_TRUE(result_layer);
- EXPECT_EQ(3, result_layer->id());
-
- // At (80, 51), child2 and grand_child1 overlap. child2 is expected to be on
- // top.
- test_point = gfx::Point(80, 51);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- ASSERT_TRUE(result_layer);
- EXPECT_EQ(3, result_layer->id());
-
- // At (51, 51), all layers overlap each other. child2 is expected to be on top
- // of all other layers.
- test_point = gfx::Point(51, 51);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- ASSERT_TRUE(result_layer);
- EXPECT_EQ(3, result_layer->id());
-
- // At (20, 51), child1 and grand_child1 overlap. grand_child1 is expected to
- // be on top.
- test_point = gfx::Point(20, 51);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- ASSERT_TRUE(result_layer);
- EXPECT_EQ(4, result_layer->id());
-}
-
-TEST_F(LayerTreeHostCommonTest, HitTestingForMultipleLayerLists) {
- //
- // The geometry is set up similarly to the previous case, but
- // all layers are forced to be render surfaces now.
- //
- FakeImplProxy proxy;
- FakeLayerTreeHostImpl host_impl(&proxy);
- scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl.active_tree(), 1);
-
- gfx::Transform identity_matrix;
- gfx::PointF anchor;
- gfx::PointF position;
- gfx::Size bounds(100, 100);
- SetLayerPropertiesForTesting(root.get(),
- identity_matrix,
- identity_matrix,
- anchor,
- position,
- bounds,
- false);
- root->SetDrawsContent(true);
- {
- // child 1 and child2 are initialized to overlap between x=50 and x=60.
- // grand_child is set to overlap both child1 and child2 between y=50 and
- // y=60. The expected stacking order is: (front) child2, (second)
- // grand_child, (third) child1, and (back) the root layer behind all other
- // layers.
-
- scoped_ptr<LayerImpl> child1 =
- LayerImpl::Create(host_impl.active_tree(), 2);
- scoped_ptr<LayerImpl> child2 =
- LayerImpl::Create(host_impl.active_tree(), 3);
- scoped_ptr<LayerImpl> grand_child1 =
- LayerImpl::Create(host_impl.active_tree(), 4);
-
- position = gfx::PointF(10.f, 10.f);
- bounds = gfx::Size(50, 50);
- SetLayerPropertiesForTesting(child1.get(),
- identity_matrix,
- identity_matrix,
- anchor,
- position,
- bounds,
- false);
- child1->SetDrawsContent(true);
- child1->SetForceRenderSurface(true);
-
- position = gfx::PointF(50.f, 10.f);
- bounds = gfx::Size(50, 50);
- SetLayerPropertiesForTesting(child2.get(),
- identity_matrix,
- identity_matrix,
- anchor,
- position,
- bounds,
- false);
- child2->SetDrawsContent(true);
- child2->SetForceRenderSurface(true);
-
- // Remember that grand_child is positioned with respect to its parent (i.e.
- // child1). In screen space, the intended position is (10, 50), with size
- // 100 x 50.
- position = gfx::PointF(0.f, 40.f);
- bounds = gfx::Size(100, 50);
- SetLayerPropertiesForTesting(grand_child1.get(),
- identity_matrix,
- identity_matrix,
- anchor,
- position,
- bounds,
- false);
- grand_child1->SetDrawsContent(true);
- grand_child1->SetForceRenderSurface(true);
-
- child1->AddChild(grand_child1.Pass());
- root->AddChild(child1.Pass());
- root->AddChild(child2.Pass());
- }
-
- LayerImpl* child1 = root->children()[0];
- LayerImpl* child2 = root->children()[1];
- LayerImpl* grand_child1 = child1->children()[0];
-
- LayerImplList render_surface_layer_list;
- LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root.get(), root->bounds(), &render_surface_layer_list);
- inputs.can_adjust_raster_scales = true;
- LayerTreeHostCommon::CalculateDrawProperties(&inputs);
-
- // Sanity check the scenario we just created.
- ASSERT_TRUE(child1);
- ASSERT_TRUE(child2);
- ASSERT_TRUE(grand_child1);
- ASSERT_TRUE(child1->render_surface());
- ASSERT_TRUE(child2->render_surface());
- ASSERT_TRUE(grand_child1->render_surface());
- ASSERT_EQ(4u, render_surface_layer_list.size());
- // The root surface has the root layer, and child1's and child2's render
- // surfaces.
- ASSERT_EQ(3u, root->render_surface()->layer_list().size());
- // The child1 surface has the child1 layer and grand_child1's render surface.
- ASSERT_EQ(2u, child1->render_surface()->layer_list().size());
- ASSERT_EQ(1u, child2->render_surface()->layer_list().size());
- ASSERT_EQ(1u, grand_child1->render_surface()->layer_list().size());
- ASSERT_EQ(1, render_surface_layer_list.at(0)->id()); // root layer
- ASSERT_EQ(2, render_surface_layer_list[1]->id()); // child1
- ASSERT_EQ(4, render_surface_layer_list.at(2)->id()); // grand_child1
- ASSERT_EQ(3, render_surface_layer_list[3]->id()); // child2
-
- // Nothing overlaps the root_layer at (1, 1), so hit testing there should find
- // the root layer.
- gfx::Point test_point = gfx::Point(1, 1);
- LayerImpl* result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- ASSERT_TRUE(result_layer);
- EXPECT_EQ(1, result_layer->id());
-
- // At (15, 15), child1 and root are the only layers. child1 is expected to be
- // on top.
- test_point = gfx::Point(15, 15);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- ASSERT_TRUE(result_layer);
- EXPECT_EQ(2, result_layer->id());
-
- // At (51, 20), child1 and child2 overlap. child2 is expected to be on top.
- test_point = gfx::Point(51, 20);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- ASSERT_TRUE(result_layer);
- EXPECT_EQ(3, result_layer->id());
-
- // At (80, 51), child2 and grand_child1 overlap. child2 is expected to be on
- // top.
- test_point = gfx::Point(80, 51);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- ASSERT_TRUE(result_layer);
- EXPECT_EQ(3, result_layer->id());
-
- // At (51, 51), all layers overlap each other. child2 is expected to be on top
- // of all other layers.
- test_point = gfx::Point(51, 51);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- ASSERT_TRUE(result_layer);
- EXPECT_EQ(3, result_layer->id());
-
- // At (20, 51), child1 and grand_child1 overlap. grand_child1 is expected to
- // be on top.
- test_point = gfx::Point(20, 51);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- ASSERT_TRUE(result_layer);
- EXPECT_EQ(4, result_layer->id());
-}
-
-TEST_F(LayerTreeHostCommonTest, HitTestingForEmptyLayers) {
- FakeImplProxy proxy;
- FakeLayerTreeHostImpl host_impl(&proxy);
-
- // Layer 1 - root
- scoped_ptr<LayerImpl> root =
- LayerImpl::Create(host_impl.active_tree(), 1);
- gfx::Transform identity_matrix;
- gfx::PointF anchor;
- gfx::PointF position;
- gfx::Size bounds(100, 100);
- SetLayerPropertiesForTesting(root.get(),
- identity_matrix,
- identity_matrix,
- anchor,
- position,
- bounds,
- false);
- root->SetDrawsContent(true);
-
- {
- // Layer 2 - empty: drawsContent=false
- gfx::PointF position(10.f, 10.f);
- gfx::Size bounds(30, 30);
- scoped_ptr<LayerImpl> empty_layer =
- LayerImpl::Create(host_impl.active_tree(), 2);
- SetLayerPropertiesForTesting(empty_layer.get(),
- identity_matrix,
- identity_matrix,
- anchor,
- position,
- bounds,
- false);
-
- empty_layer->SetDrawsContent(false);
- root->AddChild(empty_layer.Pass());
- }
-
- {
- // Layer 3 - empty, but has touch handler
- gfx::PointF position(10.f, 60.f);
- gfx::Size bounds(30, 30);
- scoped_ptr<LayerImpl> test_layer =
- LayerImpl::Create(host_impl.active_tree(), 3);
- SetLayerPropertiesForTesting(test_layer.get(),
- identity_matrix,
- identity_matrix,
- anchor,
- position,
- bounds,
- false);
-
- test_layer->SetDrawsContent(false);
- Region touch_handler_region(gfx::Rect(10, 10, 10, 10));
- test_layer->SetTouchEventHandlerRegion(touch_handler_region);
- root->AddChild(test_layer.Pass());
- }
-
- {
- // Layer 4 - empty, but has mousewheel handler
- gfx::PointF position(60.f, 60.f);
- gfx::Size bounds(30, 30);
- scoped_ptr<LayerImpl> test_layer =
- LayerImpl::Create(host_impl.active_tree(), 4);
- SetLayerPropertiesForTesting(test_layer.get(),
- identity_matrix,
- identity_matrix,
- anchor,
- position,
- bounds,
- false);
-
- test_layer->SetDrawsContent(false);
- test_layer->SetHaveWheelEventHandlers(true);
- root->AddChild(test_layer.Pass());
- }
-
- LayerImplList render_surface_layer_list;
- LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root.get(), root->bounds(), &render_surface_layer_list);
- inputs.can_adjust_raster_scales = true;
- LayerTreeHostCommon::CalculateDrawProperties(&inputs);
-
- // Verify that the root layer and empty layers with touch/wheel handlers
- // (but not the empty layer without a touch handler) are in the RSSL.
- ASSERT_EQ(1u, render_surface_layer_list.size());
- EXPECT_EQ(1, render_surface_layer_list[0]->id());
- ASSERT_EQ(3u, root->render_surface()->layer_list().size());
- EXPECT_EQ(1, root->render_surface()->layer_list().at(0)->id());
- EXPECT_EQ(3, root->render_surface()->layer_list().at(1)->id());
- EXPECT_EQ(4, root->render_surface()->layer_list().at(2)->id());
-
- // Hit testing for a point inside the empty no-handlers layer should return
- // the root layer.
- gfx::Point test_point = gfx::Point(15, 15);
- LayerImpl* result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- ASSERT_TRUE(result_layer);
- EXPECT_EQ(1, result_layer->id());
-
- // Hit testing for a point inside the touch handler layer should return it.
- test_point = gfx::Point(15, 75);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- ASSERT_TRUE(result_layer);
- EXPECT_EQ(3, result_layer->id());
-
- // Hit testing for a point inside the mousewheel layer should return it.
- test_point = gfx::Point(75, 75);
- result_layer = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- test_point, render_surface_layer_list);
- ASSERT_TRUE(result_layer);
- EXPECT_EQ(4, result_layer->id());
-}
-
-TEST_F(LayerTreeHostCommonTest,
- HitCheckingTouchHandlerRegionsForEmptyLayerList) {
- // Hit checking on an empty render_surface_layer_list should return a null
- // pointer.
- LayerImplList render_surface_layer_list;
-
- gfx::Point test_point(0, 0);
- LayerImpl* result_layer =
- LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- test_point = gfx::Point(10, 20);
- result_layer =
- LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-}
-
-TEST_F(LayerTreeHostCommonTest, HitCheckingTouchHandlerRegionsForSingleLayer) {
- FakeImplProxy proxy;
- FakeLayerTreeHostImpl host_impl(&proxy);
- scoped_ptr<LayerImpl> root =
- LayerImpl::Create(host_impl.active_tree(), 12345);
-
- gfx::Transform identity_matrix;
- Region touch_handler_region(gfx::Rect(10, 10, 50, 50));
- gfx::PointF anchor;
- gfx::PointF position;
- gfx::Size bounds(100, 100);
- SetLayerPropertiesForTesting(root.get(),
- identity_matrix,
- identity_matrix,
- anchor,
- position,
- bounds,
- false);
- root->SetDrawsContent(true);
-
- LayerImplList render_surface_layer_list;
- LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root.get(), root->bounds(), &render_surface_layer_list);
- inputs.can_adjust_raster_scales = true;
- LayerTreeHostCommon::CalculateDrawProperties(&inputs);
-
- // Sanity check the scenario we just created.
- ASSERT_EQ(1u, render_surface_layer_list.size());
- ASSERT_EQ(1u, root->render_surface()->layer_list().size());
-
- // Hit checking for any point should return a null pointer for a layer without
- // any touch event handler regions.
- gfx::Point test_point(11, 11);
- LayerImpl* result_layer =
- LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- root->SetTouchEventHandlerRegion(touch_handler_region);
- // Hit checking for a point outside the layer should return a null pointer.
- test_point = gfx::Point(101, 101);
- result_layer =
- LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- test_point = gfx::Point(-1, -1);
- result_layer =
- LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- // Hit checking for a point inside the layer, but outside the touch handler
- // region should return a null pointer.
- test_point = gfx::Point(1, 1);
- result_layer =
- LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- test_point = gfx::Point(99, 99);
- result_layer =
- LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- // Hit checking for a point inside the touch event handler region should
- // return the root layer.
- test_point = gfx::Point(11, 11);
- result_layer =
- LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
- test_point, render_surface_layer_list);
- ASSERT_TRUE(result_layer);
- EXPECT_EQ(12345, result_layer->id());
-
- test_point = gfx::Point(59, 59);
- result_layer =
- LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
- test_point, render_surface_layer_list);
- ASSERT_TRUE(result_layer);
- EXPECT_EQ(12345, result_layer->id());
-}
-
-TEST_F(LayerTreeHostCommonTest,
- HitCheckingTouchHandlerRegionsForUninvertibleTransform) {
- FakeImplProxy proxy;
- FakeLayerTreeHostImpl host_impl(&proxy);
- scoped_ptr<LayerImpl> root =
- LayerImpl::Create(host_impl.active_tree(), 12345);
-
- gfx::Transform uninvertible_transform;
- uninvertible_transform.matrix().set(0, 0, 0.0);
- uninvertible_transform.matrix().set(1, 1, 0.0);
- uninvertible_transform.matrix().set(2, 2, 0.0);
- uninvertible_transform.matrix().set(3, 3, 0.0);
- ASSERT_FALSE(uninvertible_transform.IsInvertible());
-
- gfx::Transform identity_matrix;
- Region touch_handler_region(gfx::Rect(10, 10, 50, 50));
- gfx::PointF anchor;
- gfx::PointF position;
- gfx::Size bounds(100, 100);
- SetLayerPropertiesForTesting(root.get(),
- uninvertible_transform,
- identity_matrix,
- anchor,
- position,
- bounds,
- false);
- root->SetDrawsContent(true);
- root->SetTouchEventHandlerRegion(touch_handler_region);
-
- LayerImplList render_surface_layer_list;
- LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root.get(), root->bounds(), &render_surface_layer_list);
- inputs.can_adjust_raster_scales = true;
- LayerTreeHostCommon::CalculateDrawProperties(&inputs);
-
- // Sanity check the scenario we just created.
- ASSERT_EQ(1u, render_surface_layer_list.size());
- ASSERT_EQ(1u, root->render_surface()->layer_list().size());
- ASSERT_FALSE(root->screen_space_transform().IsInvertible());
-
- // Hit checking any point should not hit the touch handler region on the
- // layer. If the invertible matrix is accidentally ignored and treated like an
- // identity, then the hit testing will incorrectly hit the layer when it
- // shouldn't.
- gfx::Point test_point(1, 1);
- LayerImpl* result_layer =
- LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- test_point = gfx::Point(10, 10);
- result_layer =
- LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- test_point = gfx::Point(10, 30);
- result_layer =
- LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- test_point = gfx::Point(50, 50);
- result_layer =
- LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- test_point = gfx::Point(67, 48);
- result_layer =
- LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- test_point = gfx::Point(99, 99);
- result_layer =
- LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- test_point = gfx::Point(-1, -1);
- result_layer =
- LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-}
-
-TEST_F(LayerTreeHostCommonTest,
- HitCheckingTouchHandlerRegionsForSinglePositionedLayer) {
- FakeImplProxy proxy;
- FakeLayerTreeHostImpl host_impl(&proxy);
- scoped_ptr<LayerImpl> root =
- LayerImpl::Create(host_impl.active_tree(), 12345);
-
- gfx::Transform identity_matrix;
- Region touch_handler_region(gfx::Rect(10, 10, 50, 50));
- gfx::PointF anchor;
- // this layer is positioned, and hit testing should correctly know where the
- // layer is located.
- gfx::PointF position(50.f, 50.f);
- gfx::Size bounds(100, 100);
- SetLayerPropertiesForTesting(root.get(),
- identity_matrix,
- identity_matrix,
- anchor,
- position,
- bounds,
- false);
- root->SetDrawsContent(true);
- root->SetTouchEventHandlerRegion(touch_handler_region);
-
- LayerImplList render_surface_layer_list;
- LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root.get(), root->bounds(), &render_surface_layer_list);
- inputs.can_adjust_raster_scales = true;
- LayerTreeHostCommon::CalculateDrawProperties(&inputs);
-
- // Sanity check the scenario we just created.
- ASSERT_EQ(1u, render_surface_layer_list.size());
- ASSERT_EQ(1u, root->render_surface()->layer_list().size());
-
- // Hit checking for a point outside the layer should return a null pointer.
- gfx::Point test_point(49, 49);
- LayerImpl* result_layer =
- LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- // Even though the layer has a touch handler region containing (101, 101), it
- // should not be visible there since the root render surface would clamp it.
- test_point = gfx::Point(101, 101);
- result_layer =
- LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- // Hit checking for a point inside the layer, but outside the touch handler
- // region should return a null pointer.
- test_point = gfx::Point(51, 51);
- result_layer =
- LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- // Hit checking for a point inside the touch event handler region should
- // return the root layer.
- test_point = gfx::Point(61, 61);
- result_layer =
- LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
- test_point, render_surface_layer_list);
- ASSERT_TRUE(result_layer);
- EXPECT_EQ(12345, result_layer->id());
-
- test_point = gfx::Point(99, 99);
- result_layer =
- LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
- test_point, render_surface_layer_list);
- ASSERT_TRUE(result_layer);
- EXPECT_EQ(12345, result_layer->id());
-}
-
-TEST_F(LayerTreeHostCommonTest,
- HitCheckingTouchHandlerRegionsForSingleLayerWithScaledContents) {
- // A layer's visible content rect is actually in the layer's content space.
- // The screen space transform converts from the layer's origin space to screen
- // space. This test makes sure that hit testing works correctly accounts for
- // the contents scale. A contents scale that is not 1 effectively forces a
- // non-identity transform between layer's content space and layer's origin
- // space. The hit testing code must take this into account.
- //
- // To test this, the layer is positioned at (25, 25), and is size (50, 50). If
- // contents scale is ignored, then hit checking will mis-interpret the visible
- // content rect as being larger than the actual bounds of the layer.
- //
- FakeImplProxy proxy;
- FakeLayerTreeHostImpl host_impl(&proxy);
- scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl.active_tree(), 1);
-
- gfx::Transform identity_matrix;
- gfx::PointF anchor;
-
- SetLayerPropertiesForTesting(root.get(),
- identity_matrix,
- identity_matrix,
- anchor,
- gfx::PointF(),
- gfx::Size(100, 100),
- false);
- {
- Region touch_handler_region(gfx::Rect(10, 10, 30, 30));
- gfx::PointF position(25.f, 25.f);
- gfx::Size bounds(50, 50);
- scoped_ptr<LayerImpl> test_layer =
- LayerImpl::Create(host_impl.active_tree(), 12345);
- SetLayerPropertiesForTesting(test_layer.get(),
- identity_matrix,
- identity_matrix,
- anchor,
- position,
- bounds,
- false);
-
- // override content bounds and contents scale
- test_layer->SetContentBounds(gfx::Size(100, 100));
- test_layer->SetContentsScale(2, 2);
-
- test_layer->SetDrawsContent(true);
- test_layer->SetTouchEventHandlerRegion(touch_handler_region);
- root->AddChild(test_layer.Pass());
- }
-
- LayerImplList render_surface_layer_list;
- LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root.get(), root->bounds(), &render_surface_layer_list);
- inputs.can_adjust_raster_scales = true;
- LayerTreeHostCommon::CalculateDrawProperties(&inputs);
-
- // Sanity check the scenario we just created.
- // The visible content rect for test_layer is actually 100x100, even though
- // its layout size is 50x50, positioned at 25x25.
- LayerImpl* test_layer = root->children()[0];
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100), test_layer->visible_content_rect());
- ASSERT_EQ(1u, render_surface_layer_list.size());
- ASSERT_EQ(1u, root->render_surface()->layer_list().size());
-
- // Hit checking for a point outside the layer should return a null pointer
- // (the root layer does not draw content, so it will not be tested either).
- gfx::Point test_point(76, 76);
- LayerImpl* result_layer =
- LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- // Hit checking for a point inside the layer, but outside the touch handler
- // region should return a null pointer.
- test_point = gfx::Point(26, 26);
- result_layer =
- LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- test_point = gfx::Point(34, 34);
- result_layer =
- LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- test_point = gfx::Point(65, 65);
- result_layer =
- LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- test_point = gfx::Point(74, 74);
- result_layer =
- LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- // Hit checking for a point inside the touch event handler region should
- // return the root layer.
- test_point = gfx::Point(35, 35);
- result_layer =
- LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
- test_point, render_surface_layer_list);
- ASSERT_TRUE(result_layer);
- EXPECT_EQ(12345, result_layer->id());
-
- test_point = gfx::Point(64, 64);
- result_layer =
- LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
- test_point, render_surface_layer_list);
- ASSERT_TRUE(result_layer);
- EXPECT_EQ(12345, result_layer->id());
-}
-
-TEST_F(LayerTreeHostCommonTest,
- HitCheckingTouchHandlerRegionsForSingleLayerWithDeviceScale) {
- // The layer's device_scale_factor and page_scale_factor should scale the
- // content rect and we should be able to hit the touch handler region by
- // scaling the points accordingly.
- FakeImplProxy proxy;
- FakeLayerTreeHostImpl host_impl(&proxy);
- scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl.active_tree(), 1);
-
- gfx::Transform identity_matrix;
- gfx::PointF anchor;
- // Set the bounds of the root layer big enough to fit the child when scaled.
- SetLayerPropertiesForTesting(root.get(),
- identity_matrix,
- identity_matrix,
- anchor,
- gfx::PointF(),
- gfx::Size(100, 100),
- false);
- {
- Region touch_handler_region(gfx::Rect(10, 10, 30, 30));
- gfx::PointF position(25.f, 25.f);
- gfx::Size bounds(50, 50);
- scoped_ptr<LayerImpl> test_layer =
- LayerImpl::Create(host_impl.active_tree(), 12345);
- SetLayerPropertiesForTesting(test_layer.get(),
- identity_matrix,
- identity_matrix,
- anchor,
- position,
- bounds,
- false);
-
- test_layer->SetDrawsContent(true);
- test_layer->SetTouchEventHandlerRegion(touch_handler_region);
- root->AddChild(test_layer.Pass());
- }
-
- LayerImplList render_surface_layer_list;
- float device_scale_factor = 3.f;
- float page_scale_factor = 5.f;
- gfx::Size scaled_bounds_for_root = gfx::ToCeiledSize(
- gfx::ScaleSize(root->bounds(), device_scale_factor * page_scale_factor));
-
- LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root.get(), scaled_bounds_for_root, &render_surface_layer_list);
- inputs.device_scale_factor = device_scale_factor;
- inputs.page_scale_factor = page_scale_factor;
- inputs.page_scale_application_layer = root.get();
- inputs.can_adjust_raster_scales = true;
- LayerTreeHostCommon::CalculateDrawProperties(&inputs);
-
- // Sanity check the scenario we just created.
- // The visible content rect for test_layer is actually 100x100, even though
- // its layout size is 50x50, positioned at 25x25.
- LayerImpl* test_layer = root->children()[0];
- ASSERT_EQ(1u, render_surface_layer_list.size());
- ASSERT_EQ(1u, root->render_surface()->layer_list().size());
-
- // Check whether the child layer fits into the root after scaled.
- EXPECT_RECT_EQ(gfx::Rect(test_layer->content_bounds()),
- test_layer->visible_content_rect());
-
- // Hit checking for a point outside the layer should return a null pointer
- // (the root layer does not draw content, so it will not be tested either).
- gfx::PointF test_point(76.f, 76.f);
- test_point =
- gfx::ScalePoint(test_point, device_scale_factor * page_scale_factor);
- LayerImpl* result_layer =
- LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- // Hit checking for a point inside the layer, but outside the touch handler
- // region should return a null pointer.
- test_point = gfx::Point(26, 26);
- test_point =
- gfx::ScalePoint(test_point, device_scale_factor * page_scale_factor);
- result_layer =
- LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- test_point = gfx::Point(34, 34);
- test_point =
- gfx::ScalePoint(test_point, device_scale_factor * page_scale_factor);
- result_layer =
- LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- test_point = gfx::Point(65, 65);
- test_point =
- gfx::ScalePoint(test_point, device_scale_factor * page_scale_factor);
- result_layer =
- LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- test_point = gfx::Point(74, 74);
- test_point =
- gfx::ScalePoint(test_point, device_scale_factor * page_scale_factor);
- result_layer =
- LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- // Hit checking for a point inside the touch event handler region should
- // return the root layer.
- test_point = gfx::Point(35, 35);
- test_point =
- gfx::ScalePoint(test_point, device_scale_factor * page_scale_factor);
- result_layer =
- LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
- test_point, render_surface_layer_list);
- ASSERT_TRUE(result_layer);
- EXPECT_EQ(12345, result_layer->id());
-
- test_point = gfx::Point(64, 64);
- test_point =
- gfx::ScalePoint(test_point, device_scale_factor * page_scale_factor);
- result_layer =
- LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
- test_point, render_surface_layer_list);
- ASSERT_TRUE(result_layer);
- EXPECT_EQ(12345, result_layer->id());
-}
-
-TEST_F(LayerTreeHostCommonTest,
- HitCheckingTouchHandlerRegionsForSimpleClippedLayer) {
- // Test that hit-checking will only work for the visible portion of a layer,
- // and not the entire layer bounds. Here we just test the simple axis-aligned
- // case.
- gfx::Transform identity_matrix;
- gfx::PointF anchor;
-
- FakeImplProxy proxy;
- FakeLayerTreeHostImpl host_impl(&proxy);
- scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl.active_tree(), 1);
- SetLayerPropertiesForTesting(root.get(),
- identity_matrix,
- identity_matrix,
- anchor,
- gfx::PointF(),
- gfx::Size(100, 100),
- false);
- {
- scoped_ptr<LayerImpl> clipping_layer =
- LayerImpl::Create(host_impl.active_tree(), 123);
- // this layer is positioned, and hit testing should correctly know where the
- // layer is located.
- gfx::PointF position(25.f, 25.f);
- gfx::Size bounds(50, 50);
- SetLayerPropertiesForTesting(clipping_layer.get(),
- identity_matrix,
- identity_matrix,
- anchor,
- position,
- bounds,
- false);
- clipping_layer->SetMasksToBounds(true);
-
- scoped_ptr<LayerImpl> child =
- LayerImpl::Create(host_impl.active_tree(), 456);
- Region touch_handler_region(gfx::Rect(10, 10, 50, 50));
- position = gfx::PointF(-50.f, -50.f);
- bounds = gfx::Size(300, 300);
- SetLayerPropertiesForTesting(child.get(),
- identity_matrix,
- identity_matrix,
- anchor,
- position,
- bounds,
- false);
- child->SetDrawsContent(true);
- child->SetTouchEventHandlerRegion(touch_handler_region);
- clipping_layer->AddChild(child.Pass());
- root->AddChild(clipping_layer.Pass());
- }
-
- LayerImplList render_surface_layer_list;
- LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root.get(), root->bounds(), &render_surface_layer_list);
- inputs.can_adjust_raster_scales = true;
- LayerTreeHostCommon::CalculateDrawProperties(&inputs);
-
- // Sanity check the scenario we just created.
- ASSERT_EQ(1u, render_surface_layer_list.size());
- ASSERT_EQ(1u, root->render_surface()->layer_list().size());
- ASSERT_EQ(456, root->render_surface()->layer_list().at(0)->id());
-
- // 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
- // layer's bounds.
- gfx::Point test_point(24, 24);
- LayerImpl* result_layer =
- LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- // Hit checking for a point inside the layer, but outside the touch handler
- // region should return a null pointer.
- test_point = gfx::Point(35, 35);
- result_layer =
- LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- test_point = gfx::Point(74, 74);
- result_layer =
- LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- // Hit checking for a point inside the touch event handler region should
- // return the root layer.
- test_point = gfx::Point(25, 25);
- result_layer =
- LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
- test_point, render_surface_layer_list);
- ASSERT_TRUE(result_layer);
- EXPECT_EQ(456, result_layer->id());
-
- test_point = gfx::Point(34, 34);
- result_layer =
- LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
- test_point, render_surface_layer_list);
- ASSERT_TRUE(result_layer);
- EXPECT_EQ(456, result_layer->id());
-}
-
-TEST_F(LayerTreeHostCommonTest,
- HitCheckingTouchHandlerOverlappingRegions) {
- gfx::Transform identity_matrix;
- gfx::PointF anchor;
-
- FakeImplProxy proxy;
- FakeLayerTreeHostImpl host_impl(&proxy);
- scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl.active_tree(), 1);
- SetLayerPropertiesForTesting(root.get(),
- identity_matrix,
- identity_matrix,
- anchor,
- gfx::PointF(),
- gfx::Size(100, 100),
- false);
- {
- scoped_ptr<LayerImpl> touch_layer =
- LayerImpl::Create(host_impl.active_tree(), 123);
- // this layer is positioned, and hit testing should correctly know where the
- // layer is located.
- gfx::PointF position;
- gfx::Size bounds(50, 50);
- SetLayerPropertiesForTesting(touch_layer.get(),
- identity_matrix,
- identity_matrix,
- anchor,
- position,
- bounds,
- false);
- touch_layer->SetDrawsContent(true);
- touch_layer->SetTouchEventHandlerRegion(gfx::Rect(0, 0, 50, 50));
- root->AddChild(touch_layer.Pass());
- }
-
- {
- scoped_ptr<LayerImpl> notouch_layer =
- LayerImpl::Create(host_impl.active_tree(), 1234);
- // this layer is positioned, and hit testing should correctly know where the
- // layer is located.
- gfx::PointF position(0, 25);
- gfx::Size bounds(50, 50);
- SetLayerPropertiesForTesting(notouch_layer.get(),
- identity_matrix,
- identity_matrix,
- anchor,
- position,
- bounds,
- false);
- notouch_layer->SetDrawsContent(true);
- root->AddChild(notouch_layer.Pass());
- }
-
- LayerImplList render_surface_layer_list;
- LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root.get(), root->bounds(), &render_surface_layer_list);
- inputs.can_adjust_raster_scales = true;
- LayerTreeHostCommon::CalculateDrawProperties(&inputs);
-
- // Sanity check the scenario we just created.
- ASSERT_EQ(1u, render_surface_layer_list.size());
- ASSERT_EQ(2u, root->render_surface()->layer_list().size());
- ASSERT_EQ(123, root->render_surface()->layer_list().at(0)->id());
- ASSERT_EQ(1234, root->render_surface()->layer_list().at(1)->id());
-
- gfx::Point test_point(35, 35);
- LayerImpl* result_layer =
- LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-
- test_point = gfx::Point(35, 15);
- result_layer =
- LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
- test_point, render_surface_layer_list);
- ASSERT_TRUE(result_layer);
- EXPECT_EQ(123, result_layer->id());
-
- test_point = gfx::Point(35, 65);
- result_layer =
- LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
- test_point, render_surface_layer_list);
- EXPECT_FALSE(result_layer);
-}
-
class NoScaleContentLayer : public ContentLayer {
public:
static scoped_refptr<NoScaleContentLayer> Create(ContentLayerClient* client) {
@@ -6118,6 +4051,7 @@ class NoScaleContentLayer : public ContentLayer {
virtual void CalculateContentsScale(float ideal_contents_scale,
float device_scale_factor,
float page_scale_factor,
+ float maximum_animation_contents_scale,
bool animating_transform_to_screen,
float* contents_scale_x,
float* contents_scale_y,
@@ -6126,6 +4060,7 @@ class NoScaleContentLayer : public ContentLayer {
Layer::CalculateContentsScale(ideal_contents_scale,
device_scale_factor,
page_scale_factor,
+ maximum_animation_contents_scale,
animating_transform_to_screen,
contents_scale_x,
contents_scale_y,
@@ -6154,39 +4089,39 @@ TEST_F(LayerTreeHostCommonTest, LayerTransformsInHighDPI) {
scoped_refptr<ContentLayer> parent = CreateDrawableContentLayer(&delegate);
SetLayerPropertiesForTesting(parent.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ false,
true);
scoped_refptr<ContentLayer> child = CreateDrawableContentLayer(&delegate);
SetLayerPropertiesForTesting(child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(2.f, 2.f),
gfx::Size(10, 10),
+ false,
true);
scoped_refptr<ContentLayer> child_empty =
CreateDrawableContentLayer(&delegate);
SetLayerPropertiesForTesting(child_empty.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(2.f, 2.f),
gfx::Size(),
+ false,
true);
scoped_refptr<NoScaleContentLayer> child_no_scale =
CreateNoScaleDrawableContentLayer(&delegate);
SetLayerPropertiesForTesting(child_no_scale.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(2.f, 2.f),
gfx::Size(10, 10),
+ false,
true);
parent->AddChild(child);
@@ -6298,30 +4233,30 @@ TEST_F(LayerTreeHostCommonTest, SurfaceLayerTransformsInHighDPI) {
scoped_refptr<ContentLayer> parent = CreateDrawableContentLayer(&delegate);
SetLayerPropertiesForTesting(parent.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ false,
true);
scoped_refptr<ContentLayer> perspective_surface =
CreateDrawableContentLayer(&delegate);
SetLayerPropertiesForTesting(perspective_surface.get(),
perspective_matrix * scale_small_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(2.f, 2.f),
gfx::Size(10, 10),
+ false,
true);
scoped_refptr<ContentLayer> scale_surface =
CreateDrawableContentLayer(&delegate);
SetLayerPropertiesForTesting(scale_surface.get(),
scale_small_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(2.f, 2.f),
gfx::Size(10, 10),
+ false,
true);
perspective_surface->SetForceRenderSurface(true);
@@ -6402,29 +4337,29 @@ TEST_F(LayerTreeHostCommonTest,
scoped_refptr<ContentLayer> parent = CreateDrawableContentLayer(&delegate);
SetLayerPropertiesForTesting(parent.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(133, 133),
+ false,
true);
scoped_refptr<ContentLayer> child = CreateDrawableContentLayer(&delegate);
SetLayerPropertiesForTesting(child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(13, 13),
+ false,
true);
scoped_refptr<NoScaleContentLayer> child_no_scale =
CreateNoScaleDrawableContentLayer(&delegate);
SetLayerPropertiesForTesting(child_no_scale.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(13, 13),
+ false,
true);
parent->AddChild(child);
@@ -6526,40 +4461,40 @@ TEST_F(LayerTreeHostCommonTest, ContentsScale) {
scoped_refptr<ContentLayer> parent = CreateDrawableContentLayer(&delegate);
SetLayerPropertiesForTesting(parent.get(),
parent_scale_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ false,
true);
scoped_refptr<ContentLayer> child_scale =
CreateDrawableContentLayer(&delegate);
SetLayerPropertiesForTesting(child_scale.get(),
child_scale_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(2.f, 2.f),
gfx::Size(10, 10),
+ false,
true);
scoped_refptr<ContentLayer> child_empty =
CreateDrawableContentLayer(&delegate);
SetLayerPropertiesForTesting(child_empty.get(),
child_scale_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(2.f, 2.f),
gfx::Size(),
+ false,
true);
scoped_refptr<NoScaleContentLayer> child_no_scale =
CreateNoScaleDrawableContentLayer(&delegate);
SetLayerPropertiesForTesting(child_no_scale.get(),
child_scale_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(12.f, 12.f),
gfx::Size(10, 10),
+ false,
true);
root->AddChild(parent);
@@ -6710,40 +4645,40 @@ TEST_F(LayerTreeHostCommonTest,
scoped_refptr<ContentLayer> parent = CreateDrawableContentLayer(&delegate);
SetLayerPropertiesForTesting(parent.get(),
parent_scale_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ false,
true);
scoped_refptr<ContentLayer> child_scale =
CreateDrawableContentLayer(&delegate);
SetLayerPropertiesForTesting(child_scale.get(),
child_scale_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(2.f, 2.f),
gfx::Size(10, 10),
+ false,
true);
scoped_refptr<ContentLayer> child_empty =
CreateDrawableContentLayer(&delegate);
SetLayerPropertiesForTesting(child_empty.get(),
child_scale_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(2.f, 2.f),
gfx::Size(),
+ false,
true);
scoped_refptr<NoScaleContentLayer> child_no_scale =
CreateNoScaleDrawableContentLayer(&delegate);
SetLayerPropertiesForTesting(child_no_scale.get(),
child_scale_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(12.f, 12.f),
gfx::Size(10, 10),
+ false,
true);
root->AddChild(parent);
@@ -6814,20 +4749,20 @@ TEST_F(LayerTreeHostCommonTest, SmallContentsScale) {
scoped_refptr<ContentLayer> parent = CreateDrawableContentLayer(&delegate);
SetLayerPropertiesForTesting(parent.get(),
parent_scale_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ false,
true);
scoped_refptr<ContentLayer> child_scale =
CreateDrawableContentLayer(&delegate);
SetLayerPropertiesForTesting(child_scale.get(),
child_scale_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(2.f, 2.f),
gfx::Size(10, 10),
+ false,
true);
root->AddChild(parent);
@@ -6903,70 +4838,70 @@ TEST_F(LayerTreeHostCommonTest, ContentsScaleForSurfaces) {
scoped_refptr<ContentLayer> parent = CreateDrawableContentLayer(&delegate);
SetLayerPropertiesForTesting(parent.get(),
parent_scale_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ false,
true);
scoped_refptr<ContentLayer> surface_scale =
CreateDrawableContentLayer(&delegate);
SetLayerPropertiesForTesting(surface_scale.get(),
child_scale_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(2.f, 2.f),
gfx::Size(10, 10),
+ false,
true);
scoped_refptr<ContentLayer> surface_scale_child_scale =
CreateDrawableContentLayer(&delegate);
SetLayerPropertiesForTesting(surface_scale_child_scale.get(),
child_scale_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(10, 10),
+ false,
true);
scoped_refptr<NoScaleContentLayer> surface_scale_child_no_scale =
CreateNoScaleDrawableContentLayer(&delegate);
SetLayerPropertiesForTesting(surface_scale_child_no_scale.get(),
child_scale_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(10, 10),
+ false,
true);
scoped_refptr<NoScaleContentLayer> surface_no_scale =
CreateNoScaleDrawableContentLayer(&delegate);
SetLayerPropertiesForTesting(surface_no_scale.get(),
child_scale_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(12.f, 12.f),
gfx::Size(10, 10),
+ false,
true);
scoped_refptr<ContentLayer> surface_no_scale_child_scale =
CreateDrawableContentLayer(&delegate);
SetLayerPropertiesForTesting(surface_no_scale_child_scale.get(),
child_scale_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(10, 10),
+ false,
true);
scoped_refptr<NoScaleContentLayer> surface_no_scale_child_no_scale =
CreateNoScaleDrawableContentLayer(&delegate);
SetLayerPropertiesForTesting(surface_no_scale_child_no_scale.get(),
child_scale_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(10, 10),
+ false,
true);
root->AddChild(parent);
@@ -7104,70 +5039,70 @@ TEST_F(LayerTreeHostCommonTest,
scoped_refptr<ContentLayer> parent = CreateDrawableContentLayer(&delegate);
SetLayerPropertiesForTesting(parent.get(),
parent_scale_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ false,
true);
scoped_refptr<ContentLayer> surface_scale =
CreateDrawableContentLayer(&delegate);
SetLayerPropertiesForTesting(surface_scale.get(),
child_scale_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(2.f, 2.f),
gfx::Size(10, 10),
+ false,
true);
scoped_refptr<ContentLayer> surface_scale_child_scale =
CreateDrawableContentLayer(&delegate);
SetLayerPropertiesForTesting(surface_scale_child_scale.get(),
child_scale_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(10, 10),
+ false,
true);
scoped_refptr<NoScaleContentLayer> surface_scale_child_no_scale =
CreateNoScaleDrawableContentLayer(&delegate);
SetLayerPropertiesForTesting(surface_scale_child_no_scale.get(),
child_scale_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(10, 10),
+ false,
true);
scoped_refptr<NoScaleContentLayer> surface_no_scale =
CreateNoScaleDrawableContentLayer(&delegate);
SetLayerPropertiesForTesting(surface_no_scale.get(),
child_scale_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(12.f, 12.f),
gfx::Size(10, 10),
+ false,
true);
scoped_refptr<ContentLayer> surface_no_scale_child_scale =
CreateDrawableContentLayer(&delegate);
SetLayerPropertiesForTesting(surface_no_scale_child_scale.get(),
child_scale_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(10, 10),
+ false,
true);
scoped_refptr<NoScaleContentLayer> surface_no_scale_child_no_scale =
CreateNoScaleDrawableContentLayer(&delegate);
SetLayerPropertiesForTesting(surface_no_scale_child_no_scale.get(),
child_scale_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(10, 10),
+ false,
true);
root->AddChild(parent);
@@ -7306,20 +5241,20 @@ TEST_F(LayerTreeHostCommonTest, ContentsScaleForAnimatingLayer) {
scoped_refptr<ContentLayer> parent = CreateDrawableContentLayer(&delegate);
SetLayerPropertiesForTesting(parent.get(),
parent_scale_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ false,
true);
scoped_refptr<ContentLayer> child_scale =
CreateDrawableContentLayer(&delegate);
SetLayerPropertiesForTesting(child_scale.get(),
child_scale_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(2.f, 2.f),
gfx::Size(10, 10),
+ false,
true);
root->AddChild(parent);
@@ -7364,6 +5299,58 @@ TEST_F(LayerTreeHostCommonTest, ContentsScaleForAnimatingLayer) {
}
}
+TEST_F(LayerTreeHostCommonTest,
+ ChangeInContentBoundsOrScaleTriggersPushProperties) {
+ MockContentLayerClient delegate;
+ scoped_refptr<Layer> root = Layer::Create();
+ scoped_refptr<Layer> child = CreateDrawableContentLayer(&delegate);
+ root->AddChild(child);
+
+ scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create();
+ host->SetRootLayer(root);
+
+ gfx::Transform identity_matrix;
+ SetLayerPropertiesForTesting(root.get(),
+ identity_matrix,
+ gfx::Point3F(),
+ gfx::PointF(),
+ gfx::Size(100, 100),
+ true,
+ false);
+ SetLayerPropertiesForTesting(child.get(),
+ identity_matrix,
+ gfx::Point3F(),
+ gfx::PointF(),
+ gfx::Size(100, 100),
+ true,
+ false);
+
+ root->reset_needs_push_properties_for_testing();
+ child->reset_needs_push_properties_for_testing();
+
+ // This will change both layers' content bounds.
+ ExecuteCalculateDrawProperties(root.get());
+ EXPECT_TRUE(root->needs_push_properties());
+ EXPECT_TRUE(child->needs_push_properties());
+
+ root->reset_needs_push_properties_for_testing();
+ child->reset_needs_push_properties_for_testing();
+
+ // This will change only the child layer's contents scale and content bounds,
+ // since the root layer is not a ContentsScalingLayer.
+ ExecuteCalculateDrawProperties(root.get(), 2.f);
+ EXPECT_FALSE(root->needs_push_properties());
+ EXPECT_TRUE(child->needs_push_properties());
+
+ root->reset_needs_push_properties_for_testing();
+ child->reset_needs_push_properties_for_testing();
+
+ // This will not change either layer's contents scale or content bounds.
+ ExecuteCalculateDrawProperties(root.get(), 2.f);
+ EXPECT_FALSE(root->needs_push_properties());
+ EXPECT_FALSE(child->needs_push_properties());
+}
+
TEST_F(LayerTreeHostCommonTest, RenderSurfaceTransformsInHighDPI) {
MockContentLayerClient delegate;
gfx::Transform identity_matrix;
@@ -7371,19 +5358,19 @@ TEST_F(LayerTreeHostCommonTest, RenderSurfaceTransformsInHighDPI) {
scoped_refptr<ContentLayer> parent = CreateDrawableContentLayer(&delegate);
SetLayerPropertiesForTesting(parent.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(30, 30),
+ false,
true);
scoped_refptr<ContentLayer> child = CreateDrawableContentLayer(&delegate);
SetLayerPropertiesForTesting(child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(2.f, 2.f),
gfx::Size(10, 10),
+ false,
true);
gfx::Transform replica_transform;
@@ -7391,10 +5378,10 @@ TEST_F(LayerTreeHostCommonTest, RenderSurfaceTransformsInHighDPI) {
scoped_refptr<ContentLayer> replica = CreateDrawableContentLayer(&delegate);
SetLayerPropertiesForTesting(replica.get(),
replica_transform,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(2.f, 2.f),
gfx::Size(10, 10),
+ false,
true);
// This layer should end up in the same surface as child, with the same draw
@@ -7403,10 +5390,10 @@ TEST_F(LayerTreeHostCommonTest, RenderSurfaceTransformsInHighDPI) {
CreateDrawableContentLayer(&delegate);
SetLayerPropertiesForTesting(duplicate_child_non_owner.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(10, 10),
+ false,
true);
parent->AddChild(child);
@@ -7506,19 +5493,19 @@ TEST_F(LayerTreeHostCommonTest,
scoped_refptr<ContentLayer> parent = CreateDrawableContentLayer(&delegate);
SetLayerPropertiesForTesting(parent.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(33, 31),
+ false,
true);
scoped_refptr<ContentLayer> child = CreateDrawableContentLayer(&delegate);
SetLayerPropertiesForTesting(child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(13, 11),
+ false,
true);
gfx::Transform replica_transform;
@@ -7526,10 +5513,10 @@ TEST_F(LayerTreeHostCommonTest,
scoped_refptr<ContentLayer> replica = CreateDrawableContentLayer(&delegate);
SetLayerPropertiesForTesting(replica.get(),
replica_transform,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(13, 11),
+ false,
true);
// This layer should end up in the same surface as child, with the same draw
@@ -7538,10 +5525,10 @@ TEST_F(LayerTreeHostCommonTest,
CreateDrawableContentLayer(&delegate);
SetLayerPropertiesForTesting(duplicate_child_non_owner.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(13, 11),
+ false,
true);
parent->AddChild(child);
@@ -7643,24 +5630,24 @@ TEST_F(LayerTreeHostCommonTest, TransparentChildRenderSurfaceCreation) {
const gfx::Transform identity_matrix;
SetLayerPropertiesForTesting(root.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ true,
false);
SetLayerPropertiesForTesting(child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(10, 10),
+ true,
false);
SetLayerPropertiesForTesting(grand_child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(10, 10),
+ true,
false);
root->AddChild(child);
@@ -7677,27 +5664,28 @@ TEST_F(LayerTreeHostCommonTest, TransparentChildRenderSurfaceCreation) {
TEST_F(LayerTreeHostCommonTest, OpacityAnimatingOnPendingTree) {
FakeImplProxy proxy;
- FakeLayerTreeHostImpl host_impl(&proxy);
+ TestSharedBitmapManager shared_bitmap_manager;
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
host_impl.CreatePendingTree();
scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl.pending_tree(), 1);
const gfx::Transform identity_matrix;
SetLayerPropertiesForTesting(root.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(100, 100),
+ true,
false);
root->SetDrawsContent(true);
scoped_ptr<LayerImpl> child = LayerImpl::Create(host_impl.pending_tree(), 2);
SetLayerPropertiesForTesting(child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(50, 50),
+ true,
false);
child->SetDrawsContent(true);
child->SetOpacity(0.0f);
@@ -7737,24 +5725,24 @@ class LCDTextTest
gfx::Transform identity_matrix;
SetLayerPropertiesForTesting(root_.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(1, 1),
+ true,
false);
SetLayerPropertiesForTesting(child_.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(1, 1),
+ true,
false);
SetLayerPropertiesForTesting(grand_child_.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(1, 1),
+ true,
false);
child_->SetForceRenderSurface(std::tr1::get<1>(GetParam()));
@@ -7876,37 +5864,38 @@ INSTANTIATE_TEST_CASE_P(LayerTreeHostCommonTest,
TEST_F(LayerTreeHostCommonTest, SubtreeHidden_SingleLayer) {
FakeImplProxy proxy;
- FakeLayerTreeHostImpl host_impl(&proxy);
+ TestSharedBitmapManager shared_bitmap_manager;
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
host_impl.CreatePendingTree();
const gfx::Transform identity_matrix;
scoped_refptr<Layer> root = Layer::Create();
SetLayerPropertiesForTesting(root.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(50, 50),
+ true,
false);
root->SetIsDrawable(true);
scoped_refptr<Layer> child = Layer::Create();
SetLayerPropertiesForTesting(child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(40, 40),
+ true,
false);
child->SetIsDrawable(true);
scoped_refptr<Layer> grand_child = Layer::Create();
SetLayerPropertiesForTesting(grand_child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(30, 30),
+ true,
false);
grand_child->SetIsDrawable(true);
grand_child->SetHideLayerAndSubtree(true);
@@ -7933,27 +5922,28 @@ TEST_F(LayerTreeHostCommonTest, SubtreeHidden_SingleLayer) {
TEST_F(LayerTreeHostCommonTest, SubtreeHidden_SingleLayerImpl) {
FakeImplProxy proxy;
- FakeLayerTreeHostImpl host_impl(&proxy);
+ TestSharedBitmapManager shared_bitmap_manager;
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
host_impl.CreatePendingTree();
const gfx::Transform identity_matrix;
scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl.pending_tree(), 1);
SetLayerPropertiesForTesting(root.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(50, 50),
+ true,
false);
root->SetDrawsContent(true);
scoped_ptr<LayerImpl> child = LayerImpl::Create(host_impl.pending_tree(), 2);
SetLayerPropertiesForTesting(child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(40, 40),
+ true,
false);
child->SetDrawsContent(true);
@@ -7961,10 +5951,10 @@ TEST_F(LayerTreeHostCommonTest, SubtreeHidden_SingleLayerImpl) {
LayerImpl::Create(host_impl.pending_tree(), 3);
SetLayerPropertiesForTesting(grand_child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(30, 30),
+ true,
false);
grand_child->SetDrawsContent(true);
grand_child->SetHideLayerAndSubtree(true);
@@ -7988,27 +5978,28 @@ TEST_F(LayerTreeHostCommonTest, SubtreeHidden_SingleLayerImpl) {
TEST_F(LayerTreeHostCommonTest, SubtreeHidden_TwoLayers) {
FakeImplProxy proxy;
- FakeLayerTreeHostImpl host_impl(&proxy);
+ TestSharedBitmapManager shared_bitmap_manager;
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
host_impl.CreatePendingTree();
const gfx::Transform identity_matrix;
scoped_refptr<Layer> root = Layer::Create();
SetLayerPropertiesForTesting(root.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(50, 50),
+ true,
false);
root->SetIsDrawable(true);
scoped_refptr<Layer> child = Layer::Create();
SetLayerPropertiesForTesting(child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(40, 40),
+ true,
false);
child->SetIsDrawable(true);
child->SetHideLayerAndSubtree(true);
@@ -8016,10 +6007,10 @@ TEST_F(LayerTreeHostCommonTest, SubtreeHidden_TwoLayers) {
scoped_refptr<Layer> grand_child = Layer::Create();
SetLayerPropertiesForTesting(grand_child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(30, 30),
+ true,
false);
grand_child->SetIsDrawable(true);
@@ -8044,27 +6035,28 @@ TEST_F(LayerTreeHostCommonTest, SubtreeHidden_TwoLayers) {
TEST_F(LayerTreeHostCommonTest, SubtreeHidden_TwoLayersImpl) {
FakeImplProxy proxy;
- FakeLayerTreeHostImpl host_impl(&proxy);
+ TestSharedBitmapManager shared_bitmap_manager;
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
host_impl.CreatePendingTree();
const gfx::Transform identity_matrix;
scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl.pending_tree(), 1);
SetLayerPropertiesForTesting(root.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(50, 50),
+ true,
false);
root->SetDrawsContent(true);
scoped_ptr<LayerImpl> child = LayerImpl::Create(host_impl.pending_tree(), 2);
SetLayerPropertiesForTesting(child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(40, 40),
+ true,
false);
child->SetDrawsContent(true);
child->SetHideLayerAndSubtree(true);
@@ -8073,10 +6065,10 @@ TEST_F(LayerTreeHostCommonTest, SubtreeHidden_TwoLayersImpl) {
LayerImpl::Create(host_impl.pending_tree(), 3);
SetLayerPropertiesForTesting(grand_child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(30, 30),
+ true,
false);
grand_child->SetDrawsContent(true);
@@ -8100,37 +6092,38 @@ void EmptyCopyOutputCallback(scoped_ptr<CopyOutputResult> result) {}
TEST_F(LayerTreeHostCommonTest, SubtreeHiddenWithCopyRequest) {
FakeImplProxy proxy;
- FakeLayerTreeHostImpl host_impl(&proxy);
+ TestSharedBitmapManager shared_bitmap_manager;
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
host_impl.CreatePendingTree();
const gfx::Transform identity_matrix;
scoped_refptr<Layer> root = Layer::Create();
SetLayerPropertiesForTesting(root.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(50, 50),
+ true,
false);
root->SetIsDrawable(true);
scoped_refptr<Layer> copy_grand_parent = Layer::Create();
SetLayerPropertiesForTesting(copy_grand_parent.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(40, 40),
+ true,
false);
copy_grand_parent->SetIsDrawable(true);
scoped_refptr<Layer> copy_parent = Layer::Create();
SetLayerPropertiesForTesting(copy_parent.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(30, 30),
+ true,
false);
copy_parent->SetIsDrawable(true);
copy_parent->SetForceRenderSurface(true);
@@ -8138,40 +6131,40 @@ TEST_F(LayerTreeHostCommonTest, SubtreeHiddenWithCopyRequest) {
scoped_refptr<Layer> copy_layer = Layer::Create();
SetLayerPropertiesForTesting(copy_layer.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(20, 20),
+ true,
false);
copy_layer->SetIsDrawable(true);
scoped_refptr<Layer> copy_child = Layer::Create();
SetLayerPropertiesForTesting(copy_child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(20, 20),
+ true,
false);
copy_child->SetIsDrawable(true);
scoped_refptr<Layer> copy_grand_parent_sibling_before = Layer::Create();
SetLayerPropertiesForTesting(copy_grand_parent_sibling_before.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(40, 40),
+ true,
false);
copy_grand_parent_sibling_before->SetIsDrawable(true);
scoped_refptr<Layer> copy_grand_parent_sibling_after = Layer::Create();
SetLayerPropertiesForTesting(copy_grand_parent_sibling_after.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(40, 40),
+ true,
false);
copy_grand_parent_sibling_after->SetIsDrawable(true);
@@ -8230,7 +6223,7 @@ TEST_F(LayerTreeHostCommonTest, SubtreeHiddenWithCopyRequest) {
EXPECT_EQ(copy_parent->id(),
root->render_surface()->layer_list().at(1)->id());
- // Nothing actually drawns into the copy parent, so only the copy_layer will
+ // 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->render_surface()->layer_list().size());
EXPECT_EQ(copy_layer->id(),
@@ -8246,27 +6239,28 @@ TEST_F(LayerTreeHostCommonTest, SubtreeHiddenWithCopyRequest) {
TEST_F(LayerTreeHostCommonTest, ClippedOutCopyRequest) {
FakeImplProxy proxy;
- FakeLayerTreeHostImpl host_impl(&proxy);
+ TestSharedBitmapManager shared_bitmap_manager;
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
host_impl.CreatePendingTree();
const gfx::Transform identity_matrix;
scoped_refptr<Layer> root = Layer::Create();
SetLayerPropertiesForTesting(root.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(50, 50),
+ true,
false);
root->SetIsDrawable(true);
scoped_refptr<Layer> copy_parent = Layer::Create();
SetLayerPropertiesForTesting(copy_parent.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(),
+ true,
false);
copy_parent->SetIsDrawable(true);
copy_parent->SetMasksToBounds(true);
@@ -8274,20 +6268,20 @@ TEST_F(LayerTreeHostCommonTest, ClippedOutCopyRequest) {
scoped_refptr<Layer> copy_layer = Layer::Create();
SetLayerPropertiesForTesting(copy_layer.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(30, 30),
+ true,
false);
copy_layer->SetIsDrawable(true);
scoped_refptr<Layer> copy_child = Layer::Create();
SetLayerPropertiesForTesting(copy_child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(20, 20),
+ true,
false);
copy_child->SetIsDrawable(true);
@@ -8320,17 +6314,18 @@ TEST_F(LayerTreeHostCommonTest, ClippedOutCopyRequest) {
TEST_F(LayerTreeHostCommonTest, VisibleContentRectInsideSurface) {
FakeImplProxy proxy;
- FakeLayerTreeHostImpl host_impl(&proxy);
+ TestSharedBitmapManager shared_bitmap_manager;
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
host_impl.CreatePendingTree();
const gfx::Transform identity_matrix;
scoped_refptr<Layer> root = Layer::Create();
SetLayerPropertiesForTesting(root.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(50, 50),
+ true,
false);
root->SetIsDrawable(true);
@@ -8338,20 +6333,20 @@ TEST_F(LayerTreeHostCommonTest, VisibleContentRectInsideSurface) {
scoped_refptr<Layer> surface = Layer::Create();
SetLayerPropertiesForTesting(surface.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(-10, -20),
gfx::Size(),
+ true,
false);
surface->SetForceRenderSurface(true);
scoped_refptr<Layer> surface_child = Layer::Create();
SetLayerPropertiesForTesting(surface_child.get(),
identity_matrix,
- identity_matrix,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(50, 50),
+ true,
false);
surface_child->SetIsDrawable(true);
@@ -8411,38 +6406,38 @@ TEST_F(LayerTreeHostCommonTest, TransformedClipParent) {
SetLayerPropertiesForTesting(root.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(50, 50),
+ true,
false);
SetLayerPropertiesForTesting(render_surface.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(10, 10),
+ true,
false);
SetLayerPropertiesForTesting(clip_parent.get(),
scale_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(1.f, 1.f),
gfx::Size(10, 10),
+ true,
false);
SetLayerPropertiesForTesting(intervening.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(1.f, 1.f),
gfx::Size(5, 5),
+ true,
false);
SetLayerPropertiesForTesting(clip_child.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(1.f, 1.f),
gfx::Size(10, 10),
+ true,
false);
scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create();
@@ -8515,45 +6510,45 @@ TEST_F(LayerTreeHostCommonTest, ClipParentWithInterveningRenderSurface) {
gfx::Transform identity_transform;
SetLayerPropertiesForTesting(root.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(50, 50),
+ true,
false);
SetLayerPropertiesForTesting(clip_parent.get(),
translation_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(1.f, 1.f),
gfx::Size(40, 40),
+ true,
false);
SetLayerPropertiesForTesting(render_surface1.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(10, 10),
+ true,
false);
SetLayerPropertiesForTesting(intervening.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(1.f, 1.f),
gfx::Size(5, 5),
+ true,
false);
SetLayerPropertiesForTesting(render_surface2.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(10, 10),
+ true,
false);
SetLayerPropertiesForTesting(clip_child.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(-10.f, -10.f),
gfx::Size(60, 60),
+ true,
false);
scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create();
@@ -8632,8 +6627,7 @@ TEST_F(LayerTreeHostCommonTest, ClipParentScrolledInterveningLayer) {
intervening->SetMasksToBounds(true);
clip_parent->SetMasksToBounds(true);
- intervening->SetScrollable(true);
- intervening->SetMaxScrollOffset(gfx::Vector2d(50, 50));
+ intervening->SetScrollClipLayerId(clip_parent->id());
intervening->SetScrollOffset(gfx::Vector2d(3, 3));
render_surface1->SetForceRenderSurface(true);
@@ -8645,45 +6639,45 @@ TEST_F(LayerTreeHostCommonTest, ClipParentScrolledInterveningLayer) {
gfx::Transform identity_transform;
SetLayerPropertiesForTesting(root.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(50, 50),
+ true,
false);
SetLayerPropertiesForTesting(clip_parent.get(),
translation_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(1.f, 1.f),
gfx::Size(40, 40),
+ true,
false);
SetLayerPropertiesForTesting(render_surface1.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(10, 10),
+ true,
false);
SetLayerPropertiesForTesting(intervening.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(1.f, 1.f),
gfx::Size(5, 5),
+ true,
false);
SetLayerPropertiesForTesting(render_surface2.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(10, 10),
+ true,
false);
SetLayerPropertiesForTesting(clip_child.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(-10.f, -10.f),
gfx::Size(60, 60),
+ true,
false);
scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create();
@@ -8761,38 +6755,38 @@ TEST_F(LayerTreeHostCommonTest, DescendantsOfClipChildren) {
gfx::Transform identity_transform;
SetLayerPropertiesForTesting(root.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(50, 50),
+ true,
false);
SetLayerPropertiesForTesting(clip_parent.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(40, 40),
+ true,
false);
SetLayerPropertiesForTesting(intervening.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(5, 5),
+ true,
false);
SetLayerPropertiesForTesting(clip_child.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(60, 60),
+ true,
false);
SetLayerPropertiesForTesting(child.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(60, 60),
+ true,
false);
scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create();
@@ -8848,45 +6842,45 @@ TEST_F(LayerTreeHostCommonTest,
gfx::Transform identity_transform;
SetLayerPropertiesForTesting(root.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(15, 15),
+ true,
false);
SetLayerPropertiesForTesting(clip_parent.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(10, 10),
+ true,
false);
SetLayerPropertiesForTesting(render_surface1.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(5, 5),
gfx::Size(5, 5),
+ true,
false);
SetLayerPropertiesForTesting(render_surface2.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(5, 5),
+ true,
false);
SetLayerPropertiesForTesting(clip_child.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(-1, 1),
gfx::Size(10, 10),
+ true,
false);
SetLayerPropertiesForTesting(non_clip_child.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(5, 5),
+ true,
false);
render_surface1->SetForceRenderSurface(true);
@@ -8931,7 +6925,8 @@ TEST_F(LayerTreeHostCommonTest,
TEST_F(LayerTreeHostCommonTest, CanRenderToSeparateSurface) {
FakeImplProxy proxy;
- FakeLayerTreeHostImpl host_impl(&proxy);
+ TestSharedBitmapManager shared_bitmap_manager;
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
scoped_ptr<LayerImpl> root =
LayerImpl::Create(host_impl.active_tree(), 12345);
scoped_ptr<LayerImpl> child1 =
@@ -8942,46 +6937,48 @@ TEST_F(LayerTreeHostCommonTest, CanRenderToSeparateSurface) {
LayerImpl::Create(host_impl.active_tree(), 12345678);
gfx::Transform identity_matrix;
- gfx::PointF anchor;
+ gfx::Point3F transform_origin;
gfx::PointF position;
gfx::Size bounds(100, 100);
SetLayerPropertiesForTesting(root.get(),
identity_matrix,
- identity_matrix,
- anchor,
+ transform_origin,
position,
bounds,
+ true,
false);
root->SetDrawsContent(true);
// This layer structure normally forces render surface due to preserves3d
// behavior.
- bool preserves3d = true;
SetLayerPropertiesForTesting(child1.get(),
identity_matrix,
- identity_matrix,
- anchor,
+ transform_origin,
position,
bounds,
- preserves3d);
+ false,
+ true);
child1->SetDrawsContent(true);
SetLayerPropertiesForTesting(child2.get(),
identity_matrix,
- identity_matrix,
- anchor,
+ transform_origin,
position,
bounds,
+ true,
false);
child2->SetDrawsContent(true);
SetLayerPropertiesForTesting(child3.get(),
identity_matrix,
- identity_matrix,
- anchor,
+ transform_origin,
position,
bounds,
+ true,
false);
child3->SetDrawsContent(true);
+ child2->Set3dSortingContextId(1);
+ child3->Set3dSortingContextId(1);
+
child2->AddChild(child3.Pass());
child1->AddChild(child2.Pass());
root->AddChild(child1.Pass());
@@ -9019,27 +7016,28 @@ TEST_F(LayerTreeHostCommonTest, DoNotIncludeBackfaceInvisibleSurfaces) {
gfx::Transform identity_transform;
SetLayerPropertiesForTesting(root.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(50, 50),
+ true,
false);
SetLayerPropertiesForTesting(render_surface.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(30, 30),
- false);
+ false,
+ true);
SetLayerPropertiesForTesting(child.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(20, 20),
+ true,
false);
- root->SetPreserves3d(true);
+ root->SetShouldFlattenTransform(false);
+ root->Set3dSortingContextId(1);
render_surface->SetDoubleSided(false);
render_surface->SetForceRenderSurface(true);
@@ -9100,38 +7098,38 @@ TEST_F(LayerTreeHostCommonTest, ClippedByScrollParent) {
gfx::Transform identity_transform;
SetLayerPropertiesForTesting(root.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(50, 50),
+ true,
false);
SetLayerPropertiesForTesting(scroll_parent_border.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(40, 40),
+ true,
false);
SetLayerPropertiesForTesting(scroll_parent_clip.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(30, 30),
+ true,
false);
SetLayerPropertiesForTesting(scroll_parent.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(50, 50),
+ true,
false);
SetLayerPropertiesForTesting(scroll_child.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(50, 50),
+ true,
false);
scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create();
@@ -9146,6 +7144,70 @@ TEST_F(LayerTreeHostCommonTest, ClippedByScrollParent) {
EXPECT_TRUE(scroll_child->is_clipped());
}
+TEST_F(LayerTreeHostCommonTest, SingularTransformSubtreesDoNotDraw) {
+ scoped_refptr<LayerWithForcedDrawsContent> root =
+ make_scoped_refptr(new LayerWithForcedDrawsContent);
+ scoped_refptr<LayerWithForcedDrawsContent> parent =
+ make_scoped_refptr(new LayerWithForcedDrawsContent);
+ scoped_refptr<LayerWithForcedDrawsContent> child =
+ make_scoped_refptr(new LayerWithForcedDrawsContent);
+
+ root->AddChild(parent);
+ parent->AddChild(child);
+
+ gfx::Transform identity_transform;
+ SetLayerPropertiesForTesting(root.get(),
+ identity_transform,
+ gfx::Point3F(),
+ gfx::PointF(),
+ gfx::Size(50, 50),
+ true,
+ true);
+ root->SetForceRenderSurface(true);
+ SetLayerPropertiesForTesting(parent.get(),
+ identity_transform,
+ gfx::Point3F(),
+ gfx::PointF(),
+ gfx::Size(30, 30),
+ true,
+ true);
+ parent->SetForceRenderSurface(true);
+ SetLayerPropertiesForTesting(child.get(),
+ identity_transform,
+ gfx::Point3F(),
+ gfx::PointF(),
+ gfx::Size(20, 20),
+ true,
+ true);
+ child->SetForceRenderSurface(true);
+
+ scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create();
+ host->SetRootLayer(root);
+
+ ExecuteCalculateDrawProperties(root.get());
+
+ EXPECT_EQ(3u, render_surface_layer_list()->size());
+
+ gfx::Transform singular_transform;
+ singular_transform.Scale3d(
+ SkDoubleToMScalar(1.0), SkDoubleToMScalar(1.0), SkDoubleToMScalar(0.0));
+
+ child->SetTransform(singular_transform);
+
+ ExecuteCalculateDrawProperties(root.get());
+
+ EXPECT_EQ(2u, render_surface_layer_list()->size());
+
+ // Ensure that the entire subtree under a layer with singular transform does
+ // not get rendered.
+ parent->SetTransform(singular_transform);
+ child->SetTransform(identity_transform);
+
+ ExecuteCalculateDrawProperties(root.get());
+
+ EXPECT_EQ(1u, render_surface_layer_list()->size());
+}
+
TEST_F(LayerTreeHostCommonTest, ClippedByOutOfOrderScrollParent) {
// Checks that clipping by a scroll parent that follows you in paint order
// still results in correct clipping.
@@ -9177,38 +7239,38 @@ TEST_F(LayerTreeHostCommonTest, ClippedByOutOfOrderScrollParent) {
gfx::Transform identity_transform;
SetLayerPropertiesForTesting(root.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(50, 50),
+ true,
false);
SetLayerPropertiesForTesting(scroll_parent_border.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(40, 40),
+ true,
false);
SetLayerPropertiesForTesting(scroll_parent_clip.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(30, 30),
+ true,
false);
SetLayerPropertiesForTesting(scroll_parent.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(50, 50),
+ true,
false);
SetLayerPropertiesForTesting(scroll_child.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(50, 50),
+ true,
false);
scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create();
@@ -9269,59 +7331,59 @@ TEST_F(LayerTreeHostCommonTest, ClippedByOutOfOrderScrollGrandparent) {
gfx::Transform identity_transform;
SetLayerPropertiesForTesting(root.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(50, 50),
+ true,
false);
SetLayerPropertiesForTesting(scroll_grandparent_border.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(40, 40),
+ true,
false);
SetLayerPropertiesForTesting(scroll_grandparent_clip.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(20, 20),
+ true,
false);
SetLayerPropertiesForTesting(scroll_grandparent.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(50, 50),
+ true,
false);
SetLayerPropertiesForTesting(scroll_parent_border.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(40, 40),
+ true,
false);
SetLayerPropertiesForTesting(scroll_parent_clip.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(30, 30),
+ true,
false);
SetLayerPropertiesForTesting(scroll_parent.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(50, 50),
+ true,
false);
SetLayerPropertiesForTesting(scroll_child.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(50, 50),
+ true,
false);
scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create();
@@ -9404,73 +7466,73 @@ TEST_F(LayerTreeHostCommonTest, OutOfOrderClippingRequiresRSLLSorting) {
gfx::Transform identity_transform;
SetLayerPropertiesForTesting(root.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(50, 50),
+ true,
false);
SetLayerPropertiesForTesting(scroll_grandparent_border.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(40, 40),
+ true,
false);
SetLayerPropertiesForTesting(scroll_grandparent_clip.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(20, 20),
+ true,
false);
SetLayerPropertiesForTesting(scroll_grandparent.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(50, 50),
+ true,
false);
SetLayerPropertiesForTesting(render_surface1.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(50, 50),
+ true,
false);
SetLayerPropertiesForTesting(scroll_parent_border.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(40, 40),
+ true,
false);
SetLayerPropertiesForTesting(scroll_parent_clip.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(30, 30),
+ true,
false);
SetLayerPropertiesForTesting(scroll_parent.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(50, 50),
+ true,
false);
SetLayerPropertiesForTesting(render_surface2.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(50, 50),
+ true,
false);
SetLayerPropertiesForTesting(scroll_child.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(50, 50),
+ true,
false);
scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create();
@@ -9517,7 +7579,8 @@ TEST_F(LayerTreeHostCommonTest, DoNotClobberSorting) {
// + scroll_parent
//
FakeImplProxy proxy;
- FakeLayerTreeHostImpl host_impl(&proxy);
+ TestSharedBitmapManager shared_bitmap_manager;
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
host_impl.CreatePendingTree();
scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl.active_tree(), 1);
scoped_ptr<LayerImpl> scroll_parent_border =
@@ -9553,55 +7616,56 @@ TEST_F(LayerTreeHostCommonTest, DoNotClobberSorting) {
SetLayerPropertiesForTesting(root.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(50, 50),
+ true,
false);
SetLayerPropertiesForTesting(scroll_parent_border.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(40, 40),
+ true,
false);
SetLayerPropertiesForTesting(scroll_parent_clip.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(30, 30),
+ true,
false);
SetLayerPropertiesForTesting(scroll_parent.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(50, 50),
+ true,
false);
SetLayerPropertiesForTesting(scroll_child.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(50, 50),
+ true,
false);
SetLayerPropertiesForTesting(top_content.get(),
top_transform,
- top_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(50, 50),
- false);
+ false,
+ true);
SetLayerPropertiesForTesting(bottom_content.get(),
bottom_transform,
- bottom_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(50, 50),
- false);
+ false,
+ true);
- scroll_child->SetPreserves3d(true);
+ scroll_child->SetShouldFlattenTransform(false);
+ scroll_child->Set3dSortingContextId(1);
scroll_child->AddChild(top_content.Pass());
scroll_child->AddChild(bottom_content.Pass());
@@ -9642,7 +7706,8 @@ TEST_F(LayerTreeHostCommonTest, ScrollCompensationWithRounding) {
// + fixed
//
FakeImplProxy proxy;
- FakeLayerTreeHostImpl host_impl(&proxy);
+ TestSharedBitmapManager shared_bitmap_manager;
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
host_impl.CreatePendingTree();
scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl.active_tree(), 1);
scoped_ptr<LayerImpl> container =
@@ -9660,7 +7725,7 @@ TEST_F(LayerTreeHostCommonTest, ScrollCompensationWithRounding) {
constraint.set_is_fixed_position(true);
fixed->SetPositionConstraint(constraint);
- scroller->SetScrollable(true);
+ scroller->SetScrollClipLayer(container->id());
gfx::Transform identity_transform;
gfx::Transform container_transform;
@@ -9669,31 +7734,31 @@ TEST_F(LayerTreeHostCommonTest, ScrollCompensationWithRounding) {
SetLayerPropertiesForTesting(root.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(50, 50),
+ true,
false);
SetLayerPropertiesForTesting(container.get(),
container_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(40, 40),
+ true,
false);
SetLayerPropertiesForTesting(scroller.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(30, 30),
+ true,
false);
SetLayerPropertiesForTesting(fixed.get(),
identity_transform,
- identity_transform,
- gfx::PointF(),
+ gfx::Point3F(),
gfx::PointF(),
gfx::Size(50, 50),
+ true,
false);
scroller->AddChild(fixed.Pass());
@@ -9743,6 +7808,794 @@ TEST_F(LayerTreeHostCommonTest, ScrollCompensationWithRounding) {
.screen_space_transform.To2dTranslation(),
container_offset - rounded_scroll_delta);
}
+
+ // Scale is applied earlier in the tree.
+ {
+ gfx::Transform scaled_container_transform = container_transform;
+ scaled_container_transform.Scale3d(3.0, 3.0, 1.0);
+ container_layer->SetTransform(scaled_container_transform);
+
+ gfx::Vector2dF scroll_delta(4.5f, 8.5f);
+ scroll_layer->SetScrollDelta(scroll_delta);
+
+ LayerImplList render_surface_layer_list;
+ LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
+ root.get(), root->bounds(), &render_surface_layer_list);
+ LayerTreeHostCommon::CalculateDrawProperties(&inputs);
+
+ EXPECT_TRANSFORMATION_MATRIX_EQ(
+ container_layer->draw_properties().screen_space_transform,
+ fixed_layer->draw_properties().screen_space_transform);
+ EXPECT_VECTOR_EQ(
+ fixed_layer->draw_properties().screen_space_transform.To2dTranslation(),
+ container_offset);
+
+ container_layer->SetTransform(container_transform);
+ }
+
+ // Scale is applied on the scroll layer itself.
+ {
+ gfx::Transform scale_transform;
+ scale_transform.Scale3d(3.0, 3.0, 1.0);
+ scroll_layer->SetTransform(scale_transform);
+
+ gfx::Vector2dF scroll_delta(4.5f, 8.5f);
+ scroll_layer->SetScrollDelta(scroll_delta);
+
+ LayerImplList render_surface_layer_list;
+ LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
+ root.get(), root->bounds(), &render_surface_layer_list);
+ LayerTreeHostCommon::CalculateDrawProperties(&inputs);
+
+ EXPECT_VECTOR_EQ(
+ fixed_layer->draw_properties().screen_space_transform.To2dTranslation(),
+ container_offset);
+
+ scroll_layer->SetTransform(identity_transform);
+ }
+}
+
+class AnimationScaleFactorTrackingLayerImpl : public LayerImpl {
+ public:
+ static scoped_ptr<AnimationScaleFactorTrackingLayerImpl> Create(
+ LayerTreeImpl* tree_impl,
+ int id) {
+ return make_scoped_ptr(
+ new AnimationScaleFactorTrackingLayerImpl(tree_impl, id));
+ }
+
+ virtual ~AnimationScaleFactorTrackingLayerImpl() {}
+
+ private:
+ explicit AnimationScaleFactorTrackingLayerImpl(LayerTreeImpl* tree_impl,
+ int id)
+ : LayerImpl(tree_impl, id) {
+ SetDrawsContent(true);
+ }
+};
+
+TEST_F(LayerTreeHostCommonTest, MaximumAnimationScaleFactor) {
+ FakeImplProxy proxy;
+ TestSharedBitmapManager shared_bitmap_manager;
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ gfx::Transform identity_matrix;
+ scoped_ptr<AnimationScaleFactorTrackingLayerImpl> grand_parent =
+ AnimationScaleFactorTrackingLayerImpl::Create(host_impl.active_tree(), 1);
+ scoped_ptr<AnimationScaleFactorTrackingLayerImpl> parent =
+ AnimationScaleFactorTrackingLayerImpl::Create(host_impl.active_tree(), 2);
+ scoped_ptr<AnimationScaleFactorTrackingLayerImpl> child =
+ AnimationScaleFactorTrackingLayerImpl::Create(host_impl.active_tree(), 3);
+ scoped_ptr<AnimationScaleFactorTrackingLayerImpl> grand_child =
+ AnimationScaleFactorTrackingLayerImpl::Create(host_impl.active_tree(), 4);
+
+ AnimationScaleFactorTrackingLayerImpl* parent_raw = parent.get();
+ AnimationScaleFactorTrackingLayerImpl* child_raw = child.get();
+ AnimationScaleFactorTrackingLayerImpl* grand_child_raw = grand_child.get();
+
+ child->AddChild(grand_child.PassAs<LayerImpl>());
+ parent->AddChild(child.PassAs<LayerImpl>());
+ grand_parent->AddChild(parent.PassAs<LayerImpl>());
+
+ SetLayerPropertiesForTesting(grand_parent.get(),
+ identity_matrix,
+ gfx::Point3F(),
+ gfx::PointF(),
+ gfx::Size(1, 2),
+ true,
+ false);
+ SetLayerPropertiesForTesting(parent_raw,
+ identity_matrix,
+ gfx::Point3F(),
+ gfx::PointF(),
+ gfx::Size(1, 2),
+ true,
+ false);
+ SetLayerPropertiesForTesting(child_raw,
+ identity_matrix,
+ gfx::Point3F(),
+ gfx::PointF(),
+ gfx::Size(1, 2),
+ true,
+ false);
+ SetLayerPropertiesForTesting(grand_child_raw,
+ identity_matrix,
+ gfx::Point3F(),
+ gfx::PointF(),
+ gfx::Size(1, 2),
+ true,
+ false);
+
+ ExecuteCalculateDrawProperties(grand_parent.get());
+
+ // No layers have animations.
+ EXPECT_EQ(0.f,
+ grand_parent->draw_properties().maximum_animation_contents_scale);
+ EXPECT_EQ(0.f,
+ parent_raw->draw_properties().maximum_animation_contents_scale);
+ EXPECT_EQ(0.f, child_raw->draw_properties().maximum_animation_contents_scale);
+ EXPECT_EQ(
+ 0.f, grand_child_raw->draw_properties().maximum_animation_contents_scale);
+
+ TransformOperations translation;
+ translation.AppendTranslate(1.f, 2.f, 3.f);
+
+ AddAnimatedTransformToLayer(
+ parent_raw, 1.0, TransformOperations(), translation);
+
+ // No layers have scale-affecting animations.
+ EXPECT_EQ(0.f,
+ grand_parent->draw_properties().maximum_animation_contents_scale);
+ EXPECT_EQ(0.f,
+ parent_raw->draw_properties().maximum_animation_contents_scale);
+ EXPECT_EQ(0.f, child_raw->draw_properties().maximum_animation_contents_scale);
+ EXPECT_EQ(
+ 0.f, grand_child_raw->draw_properties().maximum_animation_contents_scale);
+
+ TransformOperations scale;
+ scale.AppendScale(5.f, 4.f, 3.f);
+
+ AddAnimatedTransformToLayer(child_raw, 1.0, TransformOperations(), scale);
+ ExecuteCalculateDrawProperties(grand_parent.get());
+
+ // Only |child| has a scale-affecting animation.
+ EXPECT_EQ(0.f,
+ grand_parent->draw_properties().maximum_animation_contents_scale);
+ EXPECT_EQ(0.f,
+ parent_raw->draw_properties().maximum_animation_contents_scale);
+ EXPECT_EQ(5.f, child_raw->draw_properties().maximum_animation_contents_scale);
+ EXPECT_EQ(
+ 5.f, grand_child_raw->draw_properties().maximum_animation_contents_scale);
+
+ AddAnimatedTransformToLayer(
+ grand_parent.get(), 1.0, TransformOperations(), scale);
+ ExecuteCalculateDrawProperties(grand_parent.get());
+
+ // |grand_parent| and |child| have scale-affecting animations.
+ EXPECT_EQ(5.f,
+ grand_parent->draw_properties().maximum_animation_contents_scale);
+ EXPECT_EQ(5.f,
+ parent_raw->draw_properties().maximum_animation_contents_scale);
+ // We don't support combining animated scales from two nodes; 0.f means
+ // that the maximum scale could not be computed.
+ EXPECT_EQ(0.f, child_raw->draw_properties().maximum_animation_contents_scale);
+ EXPECT_EQ(
+ 0.f, grand_child_raw->draw_properties().maximum_animation_contents_scale);
+
+ AddAnimatedTransformToLayer(parent_raw, 1.0, TransformOperations(), scale);
+ ExecuteCalculateDrawProperties(grand_parent.get());
+
+ // |grand_parent|, |parent|, and |child| have scale-affecting animations.
+ EXPECT_EQ(5.f,
+ grand_parent->draw_properties().maximum_animation_contents_scale);
+ EXPECT_EQ(0.f,
+ parent_raw->draw_properties().maximum_animation_contents_scale);
+ EXPECT_EQ(0.f, child_raw->draw_properties().maximum_animation_contents_scale);
+ EXPECT_EQ(
+ 0.f, grand_child_raw->draw_properties().maximum_animation_contents_scale);
+
+ grand_parent->layer_animation_controller()->AbortAnimations(
+ Animation::Transform);
+ parent_raw->layer_animation_controller()->AbortAnimations(
+ Animation::Transform);
+ child_raw->layer_animation_controller()->AbortAnimations(
+ Animation::Transform);
+
+ TransformOperations perspective;
+ perspective.AppendPerspective(10.f);
+
+ AddAnimatedTransformToLayer(
+ child_raw, 1.0, TransformOperations(), perspective);
+ ExecuteCalculateDrawProperties(grand_parent.get());
+
+ // |child| has a scale-affecting animation but computing the maximum of this
+ // animation is not supported.
+ EXPECT_EQ(0.f,
+ grand_parent->draw_properties().maximum_animation_contents_scale);
+ EXPECT_EQ(0.f,
+ parent_raw->draw_properties().maximum_animation_contents_scale);
+ EXPECT_EQ(0.f, child_raw->draw_properties().maximum_animation_contents_scale);
+ EXPECT_EQ(
+ 0.f, grand_child_raw->draw_properties().maximum_animation_contents_scale);
+
+ child_raw->layer_animation_controller()->AbortAnimations(
+ Animation::Transform);
+
+ gfx::Transform scale_matrix;
+ scale_matrix.Scale(1.f, 2.f);
+ grand_parent->SetTransform(scale_matrix);
+ parent_raw->SetTransform(scale_matrix);
+ AddAnimatedTransformToLayer(parent_raw, 1.0, TransformOperations(), scale);
+ ExecuteCalculateDrawProperties(grand_parent.get());
+
+ // |grand_parent| and |parent| each have scale 2.f. |parent| has a scale
+ // animation with maximum scale 5.f.
+ EXPECT_EQ(0.f,
+ grand_parent->draw_properties().maximum_animation_contents_scale);
+ EXPECT_EQ(10.f,
+ parent_raw->draw_properties().maximum_animation_contents_scale);
+ EXPECT_EQ(10.f,
+ child_raw->draw_properties().maximum_animation_contents_scale);
+ EXPECT_EQ(
+ 10.f,
+ grand_child_raw->draw_properties().maximum_animation_contents_scale);
+
+ gfx::Transform perspective_matrix;
+ perspective_matrix.ApplyPerspectiveDepth(2.f);
+ child_raw->SetTransform(perspective_matrix);
+ ExecuteCalculateDrawProperties(grand_parent.get());
+
+ // |child| has a transform that's neither a translation nor a scale.
+ EXPECT_EQ(0.f,
+ grand_parent->draw_properties().maximum_animation_contents_scale);
+ EXPECT_EQ(10.f,
+ parent_raw->draw_properties().maximum_animation_contents_scale);
+ EXPECT_EQ(0.f, child_raw->draw_properties().maximum_animation_contents_scale);
+ EXPECT_EQ(
+ 0.f, grand_child_raw->draw_properties().maximum_animation_contents_scale);
+
+ parent_raw->SetTransform(perspective_matrix);
+ ExecuteCalculateDrawProperties(grand_parent.get());
+
+ // |parent| and |child| have transforms that are neither translations nor
+ // scales.
+ EXPECT_EQ(0.f,
+ grand_parent->draw_properties().maximum_animation_contents_scale);
+ EXPECT_EQ(0.f,
+ parent_raw->draw_properties().maximum_animation_contents_scale);
+ EXPECT_EQ(0.f, child_raw->draw_properties().maximum_animation_contents_scale);
+ EXPECT_EQ(
+ 0.f, grand_child_raw->draw_properties().maximum_animation_contents_scale);
+
+ parent_raw->SetTransform(identity_matrix);
+ child_raw->SetTransform(identity_matrix);
+ grand_parent->SetTransform(perspective_matrix);
+
+ ExecuteCalculateDrawProperties(grand_parent.get());
+
+ // |grand_parent| has a transform that's neither a translation nor a scale.
+ EXPECT_EQ(0.f,
+ grand_parent->draw_properties().maximum_animation_contents_scale);
+ EXPECT_EQ(0.f,
+ parent_raw->draw_properties().maximum_animation_contents_scale);
+ EXPECT_EQ(0.f, child_raw->draw_properties().maximum_animation_contents_scale);
+ EXPECT_EQ(
+ 0.f, grand_child_raw->draw_properties().maximum_animation_contents_scale);
+}
+
+static int membership_id(LayerImpl* layer) {
+ return layer->draw_properties().last_drawn_render_surface_layer_list_id;
+}
+
+static void GatherDrawnLayers(LayerImplList* rsll,
+ std::set<LayerImpl*>* drawn_layers) {
+ for (LayerIterator<LayerImpl> it = LayerIterator<LayerImpl>::Begin(rsll),
+ end = LayerIterator<LayerImpl>::End(rsll);
+ it != end;
+ ++it) {
+ LayerImpl* layer = *it;
+ if (it.represents_itself())
+ drawn_layers->insert(layer);
+
+ if (!it.represents_contributing_render_surface())
+ continue;
+
+ if (layer->mask_layer())
+ drawn_layers->insert(layer->mask_layer());
+ if (layer->replica_layer() && layer->replica_layer()->mask_layer())
+ drawn_layers->insert(layer->replica_layer()->mask_layer());
+ }
+}
+
+TEST_F(LayerTreeHostCommonTest, RenderSurfaceLayerListMembership) {
+ FakeImplProxy proxy;
+ TestSharedBitmapManager shared_bitmap_manager;
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ gfx::Transform identity_matrix;
+
+ scoped_ptr<LayerImpl> grand_parent =
+ LayerImpl::Create(host_impl.active_tree(), 1);
+ scoped_ptr<LayerImpl> parent = LayerImpl::Create(host_impl.active_tree(), 3);
+ scoped_ptr<LayerImpl> child = LayerImpl::Create(host_impl.active_tree(), 5);
+ scoped_ptr<LayerImpl> grand_child1 =
+ LayerImpl::Create(host_impl.active_tree(), 7);
+ scoped_ptr<LayerImpl> grand_child2 =
+ LayerImpl::Create(host_impl.active_tree(), 9);
+
+ LayerImpl* grand_parent_raw = grand_parent.get();
+ LayerImpl* parent_raw = parent.get();
+ LayerImpl* child_raw = child.get();
+ LayerImpl* grand_child1_raw = grand_child1.get();
+ LayerImpl* grand_child2_raw = grand_child2.get();
+
+ child->AddChild(grand_child1.Pass());
+ child->AddChild(grand_child2.Pass());
+ parent->AddChild(child.Pass());
+ grand_parent->AddChild(parent.Pass());
+
+ SetLayerPropertiesForTesting(grand_parent_raw,
+ identity_matrix,
+ gfx::Point3F(),
+ gfx::PointF(),
+ gfx::Size(1, 2),
+ true,
+ false);
+ SetLayerPropertiesForTesting(parent_raw,
+ identity_matrix,
+ gfx::Point3F(),
+ gfx::PointF(),
+ gfx::Size(1, 2),
+ true,
+ false);
+ SetLayerPropertiesForTesting(child_raw,
+ identity_matrix,
+ gfx::Point3F(),
+ gfx::PointF(),
+ gfx::Size(1, 2),
+ true,
+ false);
+ SetLayerPropertiesForTesting(grand_child1_raw,
+ identity_matrix,
+ gfx::Point3F(),
+ gfx::PointF(),
+ gfx::Size(1, 2),
+ true,
+ false);
+ SetLayerPropertiesForTesting(grand_child2_raw,
+ identity_matrix,
+ gfx::Point3F(),
+ gfx::PointF(),
+ gfx::Size(1, 2),
+ true,
+ false);
+
+ // Start with nothing being drawn.
+ ExecuteCalculateDrawProperties(grand_parent_raw);
+ int member_id = render_surface_layer_list_count();
+
+ EXPECT_NE(member_id, membership_id(grand_parent_raw));
+ EXPECT_NE(member_id, membership_id(parent_raw));
+ EXPECT_NE(member_id, membership_id(child_raw));
+ EXPECT_NE(member_id, membership_id(grand_child1_raw));
+ EXPECT_NE(member_id, membership_id(grand_child2_raw));
+
+ std::set<LayerImpl*> expected;
+ std::set<LayerImpl*> actual;
+ GatherDrawnLayers(render_surface_layer_list_impl(), &actual);
+ EXPECT_EQ(expected, actual);
+
+ // If we force render surface, but none of the layers are in the layer list,
+ // then this layer should not appear in RSLL.
+ grand_child1_raw->SetForceRenderSurface(true);
+
+ ExecuteCalculateDrawProperties(grand_parent_raw);
+ member_id = render_surface_layer_list_count();
+
+ EXPECT_NE(member_id, membership_id(grand_parent_raw));
+ EXPECT_NE(member_id, membership_id(parent_raw));
+ EXPECT_NE(member_id, membership_id(child_raw));
+ EXPECT_NE(member_id, membership_id(grand_child1_raw));
+ EXPECT_NE(member_id, membership_id(grand_child2_raw));
+
+ expected.clear();
+ actual.clear();
+ GatherDrawnLayers(render_surface_layer_list_impl(), &actual);
+ EXPECT_EQ(expected, actual);
+
+ // However, if we say that this layer also draws content, it will appear in
+ // RSLL.
+ grand_child1_raw->SetDrawsContent(true);
+
+ ExecuteCalculateDrawProperties(grand_parent_raw);
+ member_id = render_surface_layer_list_count();
+
+ EXPECT_NE(member_id, membership_id(grand_parent_raw));
+ EXPECT_NE(member_id, membership_id(parent_raw));
+ EXPECT_NE(member_id, membership_id(child_raw));
+ EXPECT_EQ(member_id, membership_id(grand_child1_raw));
+ EXPECT_NE(member_id, membership_id(grand_child2_raw));
+
+ expected.clear();
+ expected.insert(grand_child1_raw);
+
+ actual.clear();
+ GatherDrawnLayers(render_surface_layer_list_impl(), &actual);
+ EXPECT_EQ(expected, actual);
+
+ // Now child is forced to have a render surface, and one if its children draws
+ // content.
+ grand_child1_raw->SetDrawsContent(false);
+ grand_child1_raw->SetForceRenderSurface(false);
+ child_raw->SetForceRenderSurface(true);
+ grand_child2_raw->SetDrawsContent(true);
+
+ ExecuteCalculateDrawProperties(grand_parent_raw);
+ member_id = render_surface_layer_list_count();
+
+ EXPECT_NE(member_id, membership_id(grand_parent_raw));
+ EXPECT_NE(member_id, membership_id(parent_raw));
+ EXPECT_NE(member_id, membership_id(child_raw));
+ EXPECT_NE(member_id, membership_id(grand_child1_raw));
+ EXPECT_EQ(member_id, membership_id(grand_child2_raw));
+
+ expected.clear();
+ expected.insert(grand_child2_raw);
+
+ actual.clear();
+ GatherDrawnLayers(render_surface_layer_list_impl(), &actual);
+ EXPECT_EQ(expected, actual);
+
+ // Add a mask layer to child.
+ child_raw->SetMaskLayer(LayerImpl::Create(host_impl.active_tree(), 6).Pass());
+
+ ExecuteCalculateDrawProperties(grand_parent_raw);
+ member_id = render_surface_layer_list_count();
+
+ EXPECT_NE(member_id, membership_id(grand_parent_raw));
+ EXPECT_NE(member_id, membership_id(parent_raw));
+ EXPECT_NE(member_id, membership_id(child_raw));
+ EXPECT_EQ(member_id, membership_id(child_raw->mask_layer()));
+ EXPECT_NE(member_id, membership_id(grand_child1_raw));
+ EXPECT_EQ(member_id, membership_id(grand_child2_raw));
+
+ expected.clear();
+ expected.insert(grand_child2_raw);
+ expected.insert(child_raw->mask_layer());
+
+ expected.clear();
+ expected.insert(grand_child2_raw);
+ expected.insert(child_raw->mask_layer());
+
+ actual.clear();
+ GatherDrawnLayers(render_surface_layer_list_impl(), &actual);
+ EXPECT_EQ(expected, actual);
+
+ // Add replica mask layer.
+ scoped_ptr<LayerImpl> replica_layer =
+ LayerImpl::Create(host_impl.active_tree(), 20);
+ replica_layer->SetMaskLayer(LayerImpl::Create(host_impl.active_tree(), 21));
+ child_raw->SetReplicaLayer(replica_layer.Pass());
+
+ ExecuteCalculateDrawProperties(grand_parent_raw);
+ member_id = render_surface_layer_list_count();
+
+ EXPECT_NE(member_id, membership_id(grand_parent_raw));
+ EXPECT_NE(member_id, membership_id(parent_raw));
+ EXPECT_NE(member_id, membership_id(child_raw));
+ EXPECT_EQ(member_id, membership_id(child_raw->mask_layer()));
+ EXPECT_EQ(member_id, membership_id(child_raw->replica_layer()->mask_layer()));
+ EXPECT_NE(member_id, membership_id(grand_child1_raw));
+ EXPECT_EQ(member_id, membership_id(grand_child2_raw));
+
+ expected.clear();
+ expected.insert(grand_child2_raw);
+ expected.insert(child_raw->mask_layer());
+ expected.insert(child_raw->replica_layer()->mask_layer());
+
+ actual.clear();
+ GatherDrawnLayers(render_surface_layer_list_impl(), &actual);
+ EXPECT_EQ(expected, actual);
+
+ child_raw->TakeReplicaLayer();
+
+ // With nothing drawing, we should have no layers.
+ grand_child2_raw->SetDrawsContent(false);
+
+ ExecuteCalculateDrawProperties(grand_parent_raw);
+ member_id = render_surface_layer_list_count();
+
+ EXPECT_NE(member_id, membership_id(grand_parent_raw));
+ EXPECT_NE(member_id, membership_id(parent_raw));
+ EXPECT_NE(member_id, membership_id(child_raw));
+ EXPECT_NE(member_id, membership_id(child_raw->mask_layer()));
+ EXPECT_NE(member_id, membership_id(grand_child1_raw));
+ EXPECT_NE(member_id, membership_id(grand_child2_raw));
+
+ expected.clear();
+ actual.clear();
+ GatherDrawnLayers(render_surface_layer_list_impl(), &actual);
+ EXPECT_EQ(expected, actual);
+
+ // Child itself draws means that we should have the child and the mask in the
+ // list.
+ child_raw->SetDrawsContent(true);
+
+ ExecuteCalculateDrawProperties(grand_parent_raw);
+ member_id = render_surface_layer_list_count();
+
+ EXPECT_NE(member_id, membership_id(grand_parent_raw));
+ EXPECT_NE(member_id, membership_id(parent_raw));
+ EXPECT_EQ(member_id, membership_id(child_raw));
+ EXPECT_EQ(member_id, membership_id(child_raw->mask_layer()));
+ EXPECT_NE(member_id, membership_id(grand_child1_raw));
+ EXPECT_NE(member_id, membership_id(grand_child2_raw));
+
+ expected.clear();
+ expected.insert(child_raw);
+ expected.insert(child_raw->mask_layer());
+ actual.clear();
+ GatherDrawnLayers(render_surface_layer_list_impl(), &actual);
+ EXPECT_EQ(expected, actual);
+
+ child_raw->TakeMaskLayer();
+
+ // Now everyone's a member!
+ grand_parent_raw->SetDrawsContent(true);
+ parent_raw->SetDrawsContent(true);
+ child_raw->SetDrawsContent(true);
+ grand_child1_raw->SetDrawsContent(true);
+ grand_child2_raw->SetDrawsContent(true);
+
+ ExecuteCalculateDrawProperties(grand_parent_raw);
+ member_id = render_surface_layer_list_count();
+
+ EXPECT_EQ(member_id, membership_id(grand_parent_raw));
+ EXPECT_EQ(member_id, membership_id(parent_raw));
+ EXPECT_EQ(member_id, membership_id(child_raw));
+ EXPECT_EQ(member_id, membership_id(grand_child1_raw));
+ EXPECT_EQ(member_id, membership_id(grand_child2_raw));
+
+ expected.clear();
+ expected.insert(grand_parent_raw);
+ expected.insert(parent_raw);
+ expected.insert(child_raw);
+ expected.insert(grand_child1_raw);
+ expected.insert(grand_child2_raw);
+
+ actual.clear();
+ GatherDrawnLayers(render_surface_layer_list_impl(), &actual);
+ EXPECT_EQ(expected, actual);
+}
+
+TEST_F(LayerTreeHostCommonTest, DrawPropertyScales) {
+ FakeImplProxy proxy;
+ TestSharedBitmapManager shared_bitmap_manager;
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+
+ scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl.active_tree(), 1);
+ LayerImpl* root_layer = root.get();
+ scoped_ptr<LayerImpl> child1 = LayerImpl::Create(host_impl.active_tree(), 2);
+ LayerImpl* child1_layer = child1.get();
+ scoped_ptr<LayerImpl> child2 = LayerImpl::Create(host_impl.active_tree(), 3);
+ LayerImpl* child2_layer = child2.get();
+
+ root->AddChild(child1.Pass());
+ root->AddChild(child2.Pass());
+
+ gfx::Transform identity_matrix, scale_transform_child1,
+ scale_transform_child2;
+ scale_transform_child1.Scale(2, 3);
+ scale_transform_child2.Scale(4, 5);
+
+ SetLayerPropertiesForTesting(root_layer,
+ identity_matrix,
+ gfx::Point3F(),
+ gfx::PointF(),
+ gfx::Size(1, 1),
+ true,
+ false);
+ SetLayerPropertiesForTesting(child1_layer,
+ scale_transform_child1,
+ gfx::Point3F(),
+ gfx::PointF(),
+ gfx::Size(),
+ true,
+ false);
+
+ child1_layer->SetMaskLayer(
+ LayerImpl::Create(host_impl.active_tree(), 4).Pass());
+
+ scoped_ptr<LayerImpl> replica_layer =
+ LayerImpl::Create(host_impl.active_tree(), 5);
+ replica_layer->SetMaskLayer(LayerImpl::Create(host_impl.active_tree(), 6));
+ child1_layer->SetReplicaLayer(replica_layer.Pass());
+
+ ExecuteCalculateDrawProperties(root_layer);
+
+ TransformOperations scale;
+ scale.AppendScale(5.f, 8.f, 3.f);
+
+ AddAnimatedTransformToLayer(child2_layer, 1.0, TransformOperations(), scale);
+ SetLayerPropertiesForTesting(child2_layer,
+ scale_transform_child2,
+ gfx::Point3F(),
+ gfx::PointF(),
+ gfx::Size(),
+ true,
+ false);
+
+ ExecuteCalculateDrawProperties(root_layer);
+
+ EXPECT_FLOAT_EQ(1.f, root_layer->draw_properties().ideal_contents_scale);
+ EXPECT_FLOAT_EQ(3.f, child1_layer->draw_properties().ideal_contents_scale);
+ EXPECT_FLOAT_EQ(
+ 3.f, child1_layer->mask_layer()->draw_properties().ideal_contents_scale);
+ EXPECT_FLOAT_EQ(3.f,
+ child1_layer->replica_layer()
+ ->mask_layer()
+ ->draw_properties()
+ .ideal_contents_scale);
+ EXPECT_FLOAT_EQ(5.f, child2_layer->draw_properties().ideal_contents_scale);
+
+ EXPECT_FLOAT_EQ(
+ 0.f, root_layer->draw_properties().maximum_animation_contents_scale);
+ EXPECT_FLOAT_EQ(
+ 0.f, child1_layer->draw_properties().maximum_animation_contents_scale);
+ EXPECT_FLOAT_EQ(0.f,
+ child1_layer->mask_layer()
+ ->draw_properties()
+ .maximum_animation_contents_scale);
+ EXPECT_FLOAT_EQ(0.f,
+ child1_layer->replica_layer()
+ ->mask_layer()
+ ->draw_properties()
+ .maximum_animation_contents_scale);
+ EXPECT_FLOAT_EQ(
+ 8.f, child2_layer->draw_properties().maximum_animation_contents_scale);
+
+ EXPECT_FLOAT_EQ(1.f, root_layer->draw_properties().page_scale_factor);
+ EXPECT_FLOAT_EQ(1.f, child1_layer->draw_properties().page_scale_factor);
+ EXPECT_FLOAT_EQ(
+ 1.f, child1_layer->mask_layer()->draw_properties().page_scale_factor);
+ EXPECT_FLOAT_EQ(1.f,
+ child1_layer->replica_layer()
+ ->mask_layer()
+ ->draw_properties()
+ .page_scale_factor);
+ EXPECT_FLOAT_EQ(1.f, child2_layer->draw_properties().page_scale_factor);
+
+ EXPECT_FLOAT_EQ(1.f, root_layer->draw_properties().device_scale_factor);
+ EXPECT_FLOAT_EQ(1.f, child1_layer->draw_properties().device_scale_factor);
+ EXPECT_FLOAT_EQ(
+ 1.f, child1_layer->mask_layer()->draw_properties().device_scale_factor);
+ EXPECT_FLOAT_EQ(1.f,
+ child1_layer->replica_layer()
+ ->mask_layer()
+ ->draw_properties()
+ .device_scale_factor);
+ EXPECT_FLOAT_EQ(1.f, child2_layer->draw_properties().device_scale_factor);
+
+ // Changing page-scale would affect ideal_contents_scale and
+ // maximum_animation_contents_scale.
+
+ float page_scale_factor = 3.f;
+ float device_scale_factor = 1.0f;
+ std::vector<LayerImpl*> render_surface_layer_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);
+
+ inputs.page_scale_factor = page_scale_factor;
+ inputs.can_adjust_raster_scales = true;
+ inputs.page_scale_application_layer = root_layer;
+ LayerTreeHostCommon::CalculateDrawProperties(&inputs);
+
+ EXPECT_FLOAT_EQ(1.f, root_layer->draw_properties().ideal_contents_scale);
+ EXPECT_FLOAT_EQ(9.f, child1_layer->draw_properties().ideal_contents_scale);
+ EXPECT_FLOAT_EQ(
+ 9.f, child1_layer->mask_layer()->draw_properties().ideal_contents_scale);
+ EXPECT_FLOAT_EQ(9.f,
+ child1_layer->replica_layer()
+ ->mask_layer()
+ ->draw_properties()
+ .ideal_contents_scale);
+ EXPECT_FLOAT_EQ(15.f, child2_layer->draw_properties().ideal_contents_scale);
+
+ EXPECT_FLOAT_EQ(
+ 0.f, root_layer->draw_properties().maximum_animation_contents_scale);
+ EXPECT_FLOAT_EQ(
+ 0.f, child1_layer->draw_properties().maximum_animation_contents_scale);
+ EXPECT_FLOAT_EQ(0.f,
+ child1_layer->mask_layer()
+ ->draw_properties()
+ .maximum_animation_contents_scale);
+ EXPECT_FLOAT_EQ(0.f,
+ child1_layer->replica_layer()
+ ->mask_layer()
+ ->draw_properties()
+ .maximum_animation_contents_scale);
+ EXPECT_FLOAT_EQ(
+ 24.f, child2_layer->draw_properties().maximum_animation_contents_scale);
+
+ EXPECT_FLOAT_EQ(1.f, root_layer->draw_properties().page_scale_factor);
+ EXPECT_FLOAT_EQ(3.f, child1_layer->draw_properties().page_scale_factor);
+ EXPECT_FLOAT_EQ(
+ 3.f, child1_layer->mask_layer()->draw_properties().page_scale_factor);
+ EXPECT_FLOAT_EQ(3.f,
+ child1_layer->replica_layer()
+ ->mask_layer()
+ ->draw_properties()
+ .page_scale_factor);
+ EXPECT_FLOAT_EQ(3.f, child2_layer->draw_properties().page_scale_factor);
+
+ EXPECT_FLOAT_EQ(1.f, root_layer->draw_properties().device_scale_factor);
+ EXPECT_FLOAT_EQ(1.f, child1_layer->draw_properties().device_scale_factor);
+ EXPECT_FLOAT_EQ(
+ 1.f, child1_layer->mask_layer()->draw_properties().device_scale_factor);
+ EXPECT_FLOAT_EQ(1.f,
+ child1_layer->replica_layer()
+ ->mask_layer()
+ ->draw_properties()
+ .device_scale_factor);
+ EXPECT_FLOAT_EQ(1.f, child2_layer->draw_properties().device_scale_factor);
+
+ // Changing device-scale would affect ideal_contents_scale and
+ // maximum_animation_contents_scale.
+
+ device_scale_factor = 4.0f;
+ inputs.device_scale_factor = device_scale_factor;
+ inputs.can_adjust_raster_scales = true;
+ LayerTreeHostCommon::CalculateDrawProperties(&inputs);
+
+ EXPECT_FLOAT_EQ(4.f, root_layer->draw_properties().ideal_contents_scale);
+ EXPECT_FLOAT_EQ(36.f, child1_layer->draw_properties().ideal_contents_scale);
+ EXPECT_FLOAT_EQ(
+ 36.f, child1_layer->mask_layer()->draw_properties().ideal_contents_scale);
+ EXPECT_FLOAT_EQ(36.f,
+ child1_layer->replica_layer()
+ ->mask_layer()
+ ->draw_properties()
+ .ideal_contents_scale);
+ EXPECT_FLOAT_EQ(60.f, child2_layer->draw_properties().ideal_contents_scale);
+
+ EXPECT_FLOAT_EQ(
+ 0.f, root_layer->draw_properties().maximum_animation_contents_scale);
+ EXPECT_FLOAT_EQ(
+ 0.f, child1_layer->draw_properties().maximum_animation_contents_scale);
+ EXPECT_FLOAT_EQ(0.f,
+ child1_layer->mask_layer()
+ ->draw_properties()
+ .maximum_animation_contents_scale);
+ EXPECT_FLOAT_EQ(0.f,
+ child1_layer->replica_layer()
+ ->mask_layer()
+ ->draw_properties()
+ .maximum_animation_contents_scale);
+ EXPECT_FLOAT_EQ(
+ 96.f, child2_layer->draw_properties().maximum_animation_contents_scale);
+
+ EXPECT_FLOAT_EQ(1.f, root_layer->draw_properties().page_scale_factor);
+ EXPECT_FLOAT_EQ(3.f, child1_layer->draw_properties().page_scale_factor);
+ EXPECT_FLOAT_EQ(
+ 3.f, child1_layer->mask_layer()->draw_properties().page_scale_factor);
+ EXPECT_FLOAT_EQ(3.f,
+ child1_layer->replica_layer()
+ ->mask_layer()
+ ->draw_properties()
+ .page_scale_factor);
+ EXPECT_FLOAT_EQ(3.f, child2_layer->draw_properties().page_scale_factor);
+
+ EXPECT_FLOAT_EQ(4.f, root_layer->draw_properties().device_scale_factor);
+ EXPECT_FLOAT_EQ(4.f, child1_layer->draw_properties().device_scale_factor);
+ EXPECT_FLOAT_EQ(
+ 4.f, child1_layer->mask_layer()->draw_properties().device_scale_factor);
+ EXPECT_FLOAT_EQ(4.f,
+ child1_layer->replica_layer()
+ ->mask_layer()
+ ->draw_properties()
+ .device_scale_factor);
+ EXPECT_FLOAT_EQ(4.f, child2_layer->draw_properties().device_scale_factor);
}
} // namespace
diff --git a/chromium/cc/trees/layer_tree_host_impl.cc b/chromium/cc/trees/layer_tree_host_impl.cc
index e4d1b735765..e35187e34df 100644
--- a/chromium/cc/trees/layer_tree_host_impl.cc
+++ b/chromium/cc/trees/layer_tree_host_impl.cc
@@ -22,7 +22,6 @@
#include "cc/debug/debug_rect_history.h"
#include "cc/debug/devtools_instrumentation.h"
#include "cc/debug/frame_rate_counter.h"
-#include "cc/debug/overdraw_metrics.h"
#include "cc/debug/paint_time_counter.h"
#include "cc/debug/rendering_stats_instrumentation.h"
#include "cc/debug/traced_value.h"
@@ -33,6 +32,7 @@
#include "cc/layers/layer_impl.h"
#include "cc/layers/layer_iterator.h"
#include "cc/layers/painted_scrollbar_layer_impl.h"
+#include "cc/layers/quad_sink.h"
#include "cc/layers/render_surface_impl.h"
#include "cc/layers/scrollbar_layer_impl_base.h"
#include "cc/output/compositor_frame_metadata.h"
@@ -44,18 +44,23 @@
#include "cc/quads/shared_quad_state.h"
#include "cc/quads/solid_color_draw_quad.h"
#include "cc/quads/texture_draw_quad.h"
+#include "cc/resources/direct_raster_worker_pool.h"
+#include "cc/resources/image_copy_raster_worker_pool.h"
+#include "cc/resources/image_raster_worker_pool.h"
#include "cc/resources/memory_history.h"
#include "cc/resources/picture_layer_tiling.h"
+#include "cc/resources/pixel_buffer_raster_worker_pool.h"
#include "cc/resources/prioritized_resource_manager.h"
+#include "cc/resources/raster_worker_pool.h"
+#include "cc/resources/resource_pool.h"
#include "cc/resources/texture_mailbox_deleter.h"
#include "cc/resources/ui_resource_bitmap.h"
#include "cc/scheduler/delay_based_time_source.h"
-#include "cc/scheduler/texture_uploader.h"
#include "cc/trees/damage_tracker.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/layer_tree_host_common.h"
#include "cc/trees/layer_tree_impl.h"
-#include "cc/trees/quad_culler.h"
+#include "cc/trees/occlusion_tracker.h"
#include "cc/trees/single_thread_proxy.h"
#include "cc/trees/tree_synchronizer.h"
#include "gpu/GLES2/gl2extchromium.h"
@@ -98,26 +103,14 @@ size_t GetMaxTransferBufferUsageBytes(cc::ContextProvider* context_provider) {
kMaxTransferBufferUsageBytes);
}
-size_t GetMaxRasterTasksUsageBytes(cc::ContextProvider* context_provider) {
- // Transfer-buffer/raster-tasks limits are different but related. We make
- // equal here, as this is ideal when using transfer buffers. When not using
- // transfer buffers we should still limit raster to something similar, to
- // preserve caching behavior (and limit memory waste when priorities change).
- return GetMaxTransferBufferUsageBytes(context_provider);
-}
-
-GLenum GetMapImageTextureTarget(cc::ContextProvider* context_provider) {
+unsigned GetMapImageTextureTarget(cc::ContextProvider* context_provider) {
if (!context_provider)
return GL_TEXTURE_2D;
- // TODO(reveman): Determine if GL_TEXTURE_EXTERNAL_OES works well on
- // Android before we enable this. crbug.com/322780
-#if !defined(OS_ANDROID)
- if (context_provider->ContextCapabilities().egl_image_external)
+ if (context_provider->ContextCapabilities().gpu.egl_image_external)
return GL_TEXTURE_EXTERNAL_OES;
- if (context_provider->ContextCapabilities().texture_rectangle)
+ if (context_provider->ContextCapabilities().gpu.texture_rectangle)
return GL_TEXTURE_RECTANGLE_ARB;
-#endif
return GL_TEXTURE_2D;
}
@@ -161,18 +154,17 @@ class LayerTreeHostImplTimeSourceAdapter : public TimeSourceClient {
new DebugScopedSetImplThread(layer_tree_host_impl_->proxy()));
}
- // TODO(enne): This should probably happen post-animate.
+ layer_tree_host_impl_->Animate(
+ layer_tree_host_impl_->CurrentFrameTimeTicks());
+ layer_tree_host_impl_->UpdateBackgroundAnimateTicking(true);
+ bool start_ready_animations = true;
+ layer_tree_host_impl_->UpdateAnimationState(start_ready_animations);
+
if (layer_tree_host_impl_->pending_tree()) {
layer_tree_host_impl_->pending_tree()->UpdateDrawProperties();
layer_tree_host_impl_->ManageTiles();
}
- layer_tree_host_impl_->Animate(
- layer_tree_host_impl_->CurrentFrameTimeTicks(),
- layer_tree_host_impl_->CurrentFrameTime());
- layer_tree_host_impl_->UpdateBackgroundAnimateTicking(true);
- bool start_ready_animations = true;
- layer_tree_host_impl_->UpdateAnimationState(start_ready_animations);
layer_tree_host_impl_->ResetCurrentFrameTimeForNextFrame();
}
@@ -223,11 +215,13 @@ LayerTreeHostImpl::LayerTreeHostImpl(
int id)
: client_(client),
proxy_(proxy),
+ use_gpu_rasterization_(false),
+ on_demand_task_graph_runner_(NULL),
input_handler_client_(NULL),
did_lock_scrolling_layer_(false),
should_bubble_scrolls_(false),
- last_scroll_did_bubble_(false),
wheel_scrolling_(false),
+ scroll_affects_scroll_handler_(false),
scroll_layer_id_when_mouse_over_scrollbar_(0),
tile_priorities_dirty_(false),
root_layer_scroll_offset_delegate_(NULL),
@@ -243,26 +237,26 @@ LayerTreeHostImpl::LayerTreeHostImpl(
paint_time_counter_(PaintTimeCounter::Create()),
memory_history_(MemoryHistory::Create()),
debug_rect_history_(DebugRectHistory::Create()),
- texture_mailbox_deleter_(new TextureMailboxDeleter),
+ texture_mailbox_deleter_(new TextureMailboxDeleter(
+ proxy_->HasImplThread() ? proxy_->ImplThreadTaskRunner()
+ : proxy_->MainThreadTaskRunner())),
max_memory_needed_bytes_(0),
- last_sent_memory_visible_bytes_(0),
- last_sent_memory_visible_and_nearby_bytes_(0),
- last_sent_memory_use_bytes_(0),
zero_budget_(false),
device_scale_factor_(1.f),
overhang_ui_resource_id_(0),
overdraw_bottom_height_(0.f),
device_viewport_valid_for_tile_management_(true),
- external_stencil_test_enabled_(false),
+ begin_impl_frame_interval_(BeginFrameArgs::DefaultInterval()),
animation_registrar_(AnimationRegistrar::Create()),
rendering_stats_instrumentation_(rendering_stats_instrumentation),
micro_benchmark_controller_(this),
need_to_update_visible_tiles_before_draw_(false),
-#ifndef NDEBUG
+#if DCHECK_IS_ON
did_lose_called_(false),
#endif
shared_bitmap_manager_(manager),
- id_(id) {
+ id_(id),
+ transfer_buffer_memory_limit_(0u) {
DCHECK(proxy_->IsImplThread());
DidVisibilityChange(this, visible_);
@@ -281,14 +275,14 @@ LayerTreeHostImpl::LayerTreeHostImpl(
// LTHI always has an active tree.
active_tree_ = LayerTreeImpl::create(this);
TRACE_EVENT_OBJECT_CREATED_WITH_ID(
- TRACE_DISABLED_BY_DEFAULT("cc.debug"), "cc::LayerTreeHostImpl", this);
+ TRACE_DISABLED_BY_DEFAULT("cc.debug"), "cc::LayerTreeHostImpl", id_);
}
LayerTreeHostImpl::~LayerTreeHostImpl() {
DCHECK(proxy_->IsImplThread());
TRACE_EVENT0("cc", "LayerTreeHostImpl::~LayerTreeHostImpl()");
TRACE_EVENT_OBJECT_DELETED_WITH_ID(
- TRACE_DISABLED_BY_DEFAULT("cc.debug"), "cc::LayerTreeHostImpl", this);
+ TRACE_DISABLED_BY_DEFAULT("cc.debug"), "cc::LayerTreeHostImpl", id_);
if (input_handler_client_) {
input_handler_client_->WillShutdown();
@@ -298,9 +292,15 @@ LayerTreeHostImpl::~LayerTreeHostImpl() {
// The layer trees must be destroyed before the layer tree host. We've
// made a contract with our animation controllers that the registrar
// will outlive them, and we must make good.
+ if (recycle_tree_)
+ recycle_tree_->Shutdown();
+ if (pending_tree_)
+ pending_tree_->Shutdown();
+ active_tree_->Shutdown();
recycle_tree_.reset();
pending_tree_.reset();
active_tree_.reset();
+ DestroyTileManager();
}
void LayerTreeHostImpl::BeginMainFrameAborted(bool did_handle) {
@@ -313,7 +313,12 @@ void LayerTreeHostImpl::BeginMainFrameAborted(bool did_handle) {
}
}
-void LayerTreeHostImpl::BeginCommit() {}
+void LayerTreeHostImpl::BeginCommit() {
+ TRACE_EVENT0("cc", "LayerTreeHostImpl::BeginCommit");
+
+ if (settings_.impl_side_painting)
+ CreatePendingTree();
+}
void LayerTreeHostImpl::CommitComplete() {
TRACE_EVENT0("cc", "LayerTreeHostImpl::CommitComplete");
@@ -331,13 +336,18 @@ void LayerTreeHostImpl::CommitComplete() {
else
ManageTiles();
} else {
+ // If we're not in impl-side painting, the tree is immediately considered
+ // active.
+ active_tree_->ProcessUIResourceRequestQueue();
+ active_tree_->DidBecomeActive();
+
+ ActivateAnimations();
+
active_tree_->set_needs_update_draw_properties();
if (time_source_client_adapter_ && time_source_client_adapter_->Active())
DCHECK(active_tree_->root_layer());
}
- client_->SendManagedMemoryStats();
-
micro_benchmark_controller_.DidCompleteCommit();
}
@@ -393,12 +403,11 @@ bool LayerTreeHostImpl::CanDraw() const {
return true;
}
-void LayerTreeHostImpl::Animate(base::TimeTicks monotonic_time,
- base::Time wall_clock_time) {
+void LayerTreeHostImpl::Animate(base::TimeTicks monotonic_time) {
if (input_handler_client_)
input_handler_client_->Animate(monotonic_time);
AnimatePageScale(monotonic_time);
- AnimateLayers(monotonic_time, wall_clock_time);
+ AnimateLayers(monotonic_time);
AnimateScrollbars(monotonic_time);
AnimateTopControls(monotonic_time);
}
@@ -408,34 +417,22 @@ void LayerTreeHostImpl::ManageTiles() {
return;
if (!tile_priorities_dirty_)
return;
- if (!device_viewport_valid_for_tile_management_)
- return;
tile_priorities_dirty_ = false;
tile_manager_->ManageTiles(global_tile_state_);
- size_t memory_required_bytes;
- size_t memory_nice_to_have_bytes;
- size_t memory_allocated_bytes;
- size_t memory_used_bytes;
- tile_manager_->GetMemoryStats(&memory_required_bytes,
- &memory_nice_to_have_bytes,
- &memory_allocated_bytes,
- &memory_used_bytes);
- SendManagedMemoryStats(memory_required_bytes,
- memory_nice_to_have_bytes,
- memory_used_bytes);
-}
-
-void LayerTreeHostImpl::StartPageScaleAnimation(gfx::Vector2d target_offset,
- bool anchor_point,
- float page_scale,
- base::TimeDelta duration) {
- if (!RootScrollLayer())
+ client_->DidManageTiles();
+}
+
+void LayerTreeHostImpl::StartPageScaleAnimation(
+ const gfx::Vector2d& target_offset,
+ bool anchor_point,
+ float page_scale,
+ base::TimeDelta duration) {
+ if (!InnerViewportScrollLayer())
return;
- gfx::Vector2dF scroll_total =
- RootScrollLayer()->scroll_offset() + RootScrollLayer()->ScrollDelta();
+ gfx::Vector2dF scroll_total = active_tree_->TotalScrollOffset();
gfx::SizeF scaled_scrollable_size = active_tree_->ScrollableSize();
gfx::SizeF viewport_size = UnscaledScrollableViewportSize();
@@ -462,28 +459,41 @@ void LayerTreeHostImpl::StartPageScaleAnimation(gfx::Vector2d target_offset,
duration.InSecondsF());
}
- SetNeedsRedraw();
+ SetNeedsAnimate();
client_->SetNeedsCommitOnImplThread();
client_->RenewTreePriority();
}
-void LayerTreeHostImpl::ScheduleAnimation() {
- SetNeedsRedraw();
+bool LayerTreeHostImpl::IsCurrentlyScrollingLayerAt(
+ const gfx::Point& viewport_point,
+ InputHandler::ScrollInputType type) {
+ if (!CurrentlyScrollingLayer())
+ return false;
+
+ gfx::PointF device_viewport_point =
+ gfx::ScalePoint(viewport_point, device_scale_factor_);
+
+ LayerImpl* layer_impl =
+ active_tree_->FindLayerThatIsHitByPoint(device_viewport_point);
+
+ bool scroll_on_main_thread = false;
+ LayerImpl* scrolling_layer_impl = FindScrollLayerForDeviceViewportPoint(
+ device_viewport_point, type, layer_impl, &scroll_on_main_thread, NULL);
+ return CurrentlyScrollingLayer() == scrolling_layer_impl;
}
-bool LayerTreeHostImpl::HaveTouchEventHandlersAt(gfx::Point viewport_point) {
+bool LayerTreeHostImpl::HaveTouchEventHandlersAt(
+ const gfx::Point& viewport_point) {
if (!settings_.touch_hit_testing)
return true;
- if (!EnsureRenderSurfaceLayerList())
- return false;
gfx::PointF device_viewport_point =
gfx::ScalePoint(viewport_point, device_scale_factor_);
LayerImpl* layer_impl =
- LayerTreeHostCommon::FindLayerThatIsHitByPointInTouchHandlerRegion(
- device_viewport_point,
- active_tree_->RenderSurfaceLayerList());
+ active_tree_->FindLayerThatIsHitByPointInTouchHandlerRegion(
+ device_viewport_point);
+
return layer_impl != NULL;
}
@@ -550,22 +560,20 @@ static DrawMode GetDrawMode(OutputSurface* output_surface) {
return DRAW_MODE_HARDWARE;
} else {
DCHECK_EQ(!output_surface->software_device(),
- output_surface->capabilities().delegated_rendering);
+ output_surface->capabilities().delegated_rendering &&
+ !output_surface->capabilities().deferred_gl_initialization)
+ << output_surface->capabilities().delegated_rendering << " "
+ << output_surface->capabilities().deferred_gl_initialization;
return DRAW_MODE_SOFTWARE;
}
}
-static void AppendQuadsForLayer(RenderPass* target_render_pass,
- LayerImpl* layer,
- const OcclusionTrackerImpl& occlusion_tracker,
- AppendQuadsData* append_quads_data) {
- bool for_surface = false;
- QuadCuller quad_culler(&target_render_pass->quad_list,
- &target_render_pass->shared_quad_state_list,
- layer,
- occlusion_tracker,
- layer->ShowDebugBorders(),
- for_surface);
+static void AppendQuadsForLayer(
+ RenderPass* target_render_pass,
+ LayerImpl* layer,
+ const OcclusionTracker<LayerImpl>& occlusion_tracker,
+ AppendQuadsData* append_quads_data) {
+ QuadSink quad_culler(target_render_pass, &occlusion_tracker);
layer->AppendQuads(&quad_culler, append_quads_data);
}
@@ -573,15 +581,9 @@ static void AppendQuadsForRenderSurfaceLayer(
RenderPass* target_render_pass,
LayerImpl* layer,
const RenderPass* contributing_render_pass,
- const OcclusionTrackerImpl& occlusion_tracker,
+ const OcclusionTracker<LayerImpl>& occlusion_tracker,
AppendQuadsData* append_quads_data) {
- bool for_surface = true;
- QuadCuller quad_culler(&target_render_pass->quad_list,
- &target_render_pass->shared_quad_state_list,
- layer,
- occlusion_tracker,
- layer->ShowDebugBorders(),
- for_surface);
+ QuadSink quad_culler(target_render_pass, &occlusion_tracker);
bool is_replica = false;
layer->render_surface()->AppendQuads(&quad_culler,
@@ -601,12 +603,12 @@ static void AppendQuadsForRenderSurfaceLayer(
static void AppendQuadsToFillScreen(
ResourceProvider::ResourceId overhang_resource_id,
- gfx::SizeF overhang_resource_scaled_size,
- gfx::Rect root_scroll_layer_rect,
+ const gfx::SizeF& overhang_resource_scaled_size,
+ const gfx::Rect& root_scroll_layer_rect,
RenderPass* target_render_pass,
LayerImpl* root_layer,
SkColor screen_background_color,
- const OcclusionTrackerImpl& occlusion_tracker) {
+ const OcclusionTracker<LayerImpl>& occlusion_tracker) {
if (!root_layer || !SkColorGetA(screen_background_color))
return;
@@ -624,13 +626,7 @@ static void AppendQuadsToFillScreen(
screen_background_color_region.Intersect(root_scroll_layer_rect);
}
- bool for_surface = false;
- QuadCuller quad_culler(&target_render_pass->quad_list,
- &target_render_pass->shared_quad_state_list,
- root_layer,
- occlusion_tracker,
- root_layer->ShowDebugBorders(),
- for_surface);
+ QuadSink quad_culler(target_render_pass, &occlusion_tracker);
// Manually create the quad state for the gutter quads, as the root layer
// doesn't have any bounds and so can't generate this itself.
@@ -639,68 +635,67 @@ static void AppendQuadsToFillScreen(
gfx::Rect root_target_rect = root_layer->render_surface()->content_rect();
float opacity = 1.f;
- SharedQuadState* shared_quad_state =
- quad_culler.UseSharedQuadState(SharedQuadState::Create());
- shared_quad_state->SetAll(root_layer->draw_transform(),
+ int sorting_context_id = 0;
+ SharedQuadState* shared_quad_state = quad_culler.CreateSharedQuadState();
+ shared_quad_state->SetAll(gfx::Transform(),
root_target_rect.size(),
root_target_rect,
root_target_rect,
false,
opacity,
- SkXfermode::kSrcOver_Mode);
+ SkXfermode::kSrcOver_Mode,
+ sorting_context_id);
- AppendQuadsData append_quads_data;
-
- gfx::Transform transform_to_layer_space(gfx::Transform::kSkipInitialization);
- bool did_invert = root_layer->screen_space_transform().GetInverse(
- &transform_to_layer_space);
- DCHECK(did_invert);
for (Region::Iterator fill_rects(screen_background_color_region);
fill_rects.has_rect();
fill_rects.next()) {
- // The root layer transform is composed of translations and scales only,
- // no perspective, so mapping is sufficient (as opposed to projecting).
- gfx::Rect layer_rect =
- MathUtil::MapClippedRect(transform_to_layer_space, fill_rects.rect());
+ gfx::Rect screen_space_rect = fill_rects.rect();
+ gfx::Rect visible_screen_space_rect = screen_space_rect;
// Skip the quad culler and just append the quads directly to avoid
// occlusion checks.
scoped_ptr<SolidColorDrawQuad> quad = SolidColorDrawQuad::Create();
- quad->SetNew(
- shared_quad_state, layer_rect, screen_background_color, false);
- quad_culler.Append(quad.PassAs<DrawQuad>(), &append_quads_data);
+ quad->SetNew(shared_quad_state,
+ screen_space_rect,
+ visible_screen_space_rect,
+ screen_background_color,
+ false);
+ quad_culler.Append(quad.PassAs<DrawQuad>());
}
for (Region::Iterator fill_rects(overhang_region);
fill_rects.has_rect();
fill_rects.next()) {
DCHECK(overhang_resource_id);
- gfx::Rect layer_rect =
- MathUtil::MapClippedRect(transform_to_layer_space, fill_rects.rect());
+ gfx::Rect screen_space_rect = fill_rects.rect();
+ gfx::Rect opaque_screen_space_rect = screen_space_rect;
+ gfx::Rect visible_screen_space_rect = screen_space_rect;
scoped_ptr<TextureDrawQuad> tex_quad = TextureDrawQuad::Create();
const float vertex_opacity[4] = {1.f, 1.f, 1.f, 1.f};
tex_quad->SetNew(
shared_quad_state,
- layer_rect,
- layer_rect,
+ screen_space_rect,
+ opaque_screen_space_rect,
+ visible_screen_space_rect,
overhang_resource_id,
false,
- gfx::PointF(layer_rect.x() / overhang_resource_scaled_size.width(),
- layer_rect.y() / overhang_resource_scaled_size.height()),
- gfx::PointF(layer_rect.right() /
- overhang_resource_scaled_size.width(),
- layer_rect.bottom() /
- overhang_resource_scaled_size.height()),
+ gfx::PointF(
+ screen_space_rect.x() / overhang_resource_scaled_size.width(),
+ screen_space_rect.y() / overhang_resource_scaled_size.height()),
+ gfx::PointF(
+ screen_space_rect.right() / overhang_resource_scaled_size.width(),
+ screen_space_rect.bottom() /
+ overhang_resource_scaled_size.height()),
screen_background_color,
vertex_opacity,
false);
- quad_culler.Append(tex_quad.PassAs<DrawQuad>(), &append_quads_data);
+ quad_culler.Append(tex_quad.PassAs<DrawQuad>());
}
}
-bool LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) {
+DrawResult LayerTreeHostImpl::CalculateRenderPasses(
+ FrameData* frame) {
DCHECK(frame->render_passes.empty());
-
- if (!CanDraw() || !active_tree_->root_layer())
- return false;
+ DCHECK(CanDraw());
+ DCHECK(active_tree_->root_layer());
TrackDamageForAllSurfaces(active_tree_->root_layer(),
*frame->render_surface_layer_list);
@@ -714,17 +709,18 @@ bool LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) {
root_surface->content_rect());
bool root_surface_has_contributing_layers =
!root_surface->layer_list().empty();
+ bool hud_wants_to_draw_ = active_tree_->hud_layer() &&
+ active_tree_->hud_layer()->IsAnimatingHUDContents();
if (root_surface_has_contributing_layers &&
- root_surface_has_no_visible_damage) {
+ root_surface_has_no_visible_damage &&
+ active_tree_->LayersWithCopyOutputRequest().empty() &&
+ !hud_wants_to_draw_) {
TRACE_EVENT0("cc",
"LayerTreeHostImpl::CalculateRenderPasses::EmptyDamageRect");
frame->has_no_damage = true;
- // A copy request should cause damage, so we should not have any copy
- // requests in this case.
- DCHECK_EQ(0u, active_tree_->LayersWithCopyOutputRequest().size());
DCHECK(!output_surface_->capabilities()
.draw_and_swap_full_viewport_every_frame);
- return true;
+ return DRAW_SUCCESS;
}
TRACE_EVENT1("cc",
@@ -748,13 +744,19 @@ bool LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) {
render_surface_layer->render_surface()->AppendRenderPasses(frame);
}
- bool record_metrics_for_frame =
- settings_.show_overdraw_in_tracing &&
- base::debug::TraceLog::GetInstance() &&
- base::debug::TraceLog::GetInstance()->IsEnabled();
- OcclusionTrackerImpl occlusion_tracker(
- active_tree_->root_layer()->render_surface()->content_rect(),
- record_metrics_for_frame);
+ // When we are displaying the HUD, change the root damage rect to cover the
+ // entire root surface. This will disable partial-swap/scissor optimizations
+ // that would prevent the HUD from updating, since the HUD does not cause
+ // damage itself, to prevent it from messing with damage visualizations. Since
+ // damage visualizations are done off the LayerImpls and RenderSurfaceImpls,
+ // changing the RenderPass does not affect them.
+ if (active_tree_->hud_layer()) {
+ RenderPass* root_pass = frame->render_passes.back();
+ root_pass->damage_rect = root_pass->output_rect;
+ }
+
+ OcclusionTracker<LayerImpl> occlusion_tracker(
+ active_tree_->root_layer()->render_surface()->content_rect());
occlusion_tracker.set_minimum_tracking_size(
settings_.minimum_occlusion_tracking_size);
@@ -767,18 +769,15 @@ bool LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) {
&frame->non_occluding_screen_space_rects);
}
- // Add quads to the Render passes in FrontToBack order to allow for testing
+ // Add quads to the Render passes in front-to-back order to allow for testing
// occlusion and performing culling during the tree walk.
- typedef LayerIterator<LayerImpl,
- LayerImplList,
- RenderSurfaceImpl,
- LayerIteratorActions::FrontToBack> LayerIteratorType;
+ typedef LayerIterator<LayerImpl> LayerIteratorType;
// Typically when we are missing a texture and use a checkerboard quad, we
// still draw the frame. However when the layer being checkerboarded is moving
// due to an impl-animation, we drop the frame to avoid flashing due to the
// texture suddenly appearing in the future.
- bool draw_frame = true;
+ DrawResult draw_result = DRAW_SUCCESS;
// When we have a copy request for a layer, we need to draw no matter
// what, as the layer may disappear after this frame.
bool have_copy_request = false;
@@ -819,14 +818,11 @@ bool LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) {
contributing_render_pass,
occlusion_tracker,
&append_quads_data);
- } else if (it.represents_itself() && it->DrawsContent() &&
+ } else if (it.represents_itself() &&
!it->visible_content_rect().IsEmpty()) {
- bool impl_draw_transform_is_unknown = false;
- bool occluded = occlusion_tracker.Occluded(
- it->render_target(),
- it->visible_content_rect(),
- it->draw_transform(),
- impl_draw_transform_is_unknown);
+ bool occluded = occlusion_tracker.Occluded(it->render_target(),
+ it->visible_content_rect(),
+ it->draw_transform());
if (!occluded && it->WillDraw(draw_mode, resource_provider_.get())) {
DCHECK_EQ(active_tree_, it->layer_tree_impl());
@@ -860,25 +856,33 @@ bool LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) {
++layers_drawn;
}
+ rendering_stats_instrumentation_->AddVisibleContentArea(
+ append_quads_data.visible_content_area);
+ rendering_stats_instrumentation_->AddApproximatedVisibleContentArea(
+ append_quads_data.approximated_visible_content_area);
+
if (append_quads_data.num_missing_tiles) {
bool layer_has_animating_transform =
it->screen_space_transform_is_animating() ||
it->draw_transform_is_animating();
if (layer_has_animating_transform)
- draw_frame = false;
+ draw_result = DRAW_ABORTED_CHECKERBOARD_ANIMATIONS;
}
- if (append_quads_data.had_incomplete_tile)
+ if (append_quads_data.had_incomplete_tile) {
frame->contains_incomplete_tile = true;
+ if (active_tree()->RequiresHighResToDraw())
+ draw_result = DRAW_ABORTED_MISSING_HIGH_RES_CONTENT;
+ }
occlusion_tracker.LeaveLayer(it);
}
if (have_copy_request ||
output_surface_->capabilities().draw_and_swap_full_viewport_every_frame)
- draw_frame = true;
+ draw_result = DRAW_SUCCESS;
-#ifndef NDEBUG
+#if DCHECK_IS_ON
for (size_t i = 0; i < frame->render_passes.size(); ++i) {
for (size_t j = 0; j < frame->render_passes[i]->quad_list.size(); ++j)
DCHECK(frame->render_passes[i]->quad_list[j]->shared_quad_state);
@@ -900,11 +904,6 @@ bool LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) {
occlusion_tracker);
}
- if (draw_frame)
- occlusion_tracker.overdraw_metrics()->RecordMetrics(this);
- else
- DCHECK(!have_copy_request);
-
RemoveRenderPasses(CullRenderPassesWithNoQuads(), frame);
renderer_->DecideRenderPassAllocationsForFrame(frame->render_passes);
@@ -925,7 +924,7 @@ bool LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) {
if (output_surface_->ForcedDrawToSoftwareDevice())
DCHECK_EQ(1u, frame->render_passes.size());
- return draw_frame;
+ return draw_result;
}
void LayerTreeHostImpl::MainThreadHasStoppedFlinging() {
@@ -939,8 +938,7 @@ void LayerTreeHostImpl::UpdateBackgroundAnimateTicking(
if (should_background_tick)
DCHECK(active_tree_->root_layer());
- bool enabled = should_background_tick &&
- !animation_registrar_->active_animation_controllers().empty();
+ bool enabled = should_background_tick && needs_animate_layers();
// Lazily create the time_source adapter so that we can vary the interval for
// testing.
@@ -961,7 +959,7 @@ void LayerTreeHostImpl::DidAnimateScrollOffset() {
client_->RenewTreePriority();
}
-void LayerTreeHostImpl::SetViewportDamage(gfx::Rect damage_rect) {
+void LayerTreeHostImpl::SetViewportDamage(const gfx::Rect& damage_rect) {
viewport_damage_rect_.Union(damage_rect);
}
@@ -1077,8 +1075,7 @@ void LayerTreeHostImpl::RemoveRenderPasses(RenderPassCuller culler,
}
}
-bool LayerTreeHostImpl::PrepareToDraw(FrameData* frame,
- gfx::Rect device_viewport_damage_rect) {
+DrawResult LayerTreeHostImpl::PrepareToDraw(FrameData* frame) {
TRACE_EVENT1("cc",
"LayerTreeHostImpl::PrepareToDraw",
"SourceFrameNumber",
@@ -1090,7 +1087,8 @@ bool LayerTreeHostImpl::PrepareToDraw(FrameData* frame,
}
need_to_update_visible_tiles_before_draw_ = true;
- active_tree_->UpdateDrawProperties();
+ bool ok = active_tree_->UpdateDrawProperties();
+ DCHECK(ok) << "UpdateDrawProperties failed during draw";
frame->render_surface_layer_list = &active_tree_->RenderSurfaceLayerList();
frame->render_passes.clear();
@@ -1100,22 +1098,23 @@ bool LayerTreeHostImpl::PrepareToDraw(FrameData* frame,
frame->has_no_damage = false;
if (active_tree_->root_layer()) {
- device_viewport_damage_rect.Union(viewport_damage_rect_);
+ gfx::Rect device_viewport_damage_rect = viewport_damage_rect_;
viewport_damage_rect_ = gfx::Rect();
active_tree_->root_layer()->render_surface()->damage_tracker()->
AddDamageNextUpdate(device_viewport_damage_rect);
}
- if (!CalculateRenderPasses(frame)) {
+ DrawResult draw_result = CalculateRenderPasses(frame);
+ if (draw_result != DRAW_SUCCESS) {
DCHECK(!output_surface_->capabilities()
.draw_and_swap_full_viewport_every_frame);
- return false;
+ return draw_result;
}
- // If we return true, then we expect DrawLayers() to be called before this
- // function is called again.
- return true;
+ // If we return DRAW_SUCCESS, then we expect DrawLayers() to be called before
+ // this function is called again.
+ return draw_result;
}
void LayerTreeHostImpl::EvictTexturesForTesting() {
@@ -1127,9 +1126,24 @@ void LayerTreeHostImpl::BlockNotifyReadyToActivateForTesting(bool block) {
}
void LayerTreeHostImpl::DidInitializeVisibleTileForTesting() {
+ // Add arbitrary damage, to trigger prepare-to-draws.
+ // Here, setting damage as viewport size, used only for testing.
+ SetFullRootLayerDamage();
DidInitializeVisibleTile();
}
+void LayerTreeHostImpl::ResetTreesForTesting() {
+ if (active_tree_)
+ active_tree_->DetachLayerTree();
+ active_tree_ = LayerTreeImpl::create(this);
+ if (pending_tree_)
+ pending_tree_->DetachLayerTree();
+ pending_tree_.reset();
+ if (recycle_tree_)
+ recycle_tree_->DetachLayerTree();
+ recycle_tree_.reset();
+}
+
void LayerTreeHostImpl::EnforceManagedMemoryPolicy(
const ManagedMemoryPolicy& policy) {
@@ -1146,7 +1160,6 @@ void LayerTreeHostImpl::EnforceManagedMemoryPolicy(
client_->OnCanDrawStateChanged(CanDraw());
client_->RenewTreePriority();
}
- client_->SendManagedMemoryStats();
UpdateTileManagerMemoryPolicy(policy);
}
@@ -1156,14 +1169,16 @@ void LayerTreeHostImpl::UpdateTileManagerMemoryPolicy(
if (!tile_manager_)
return;
- // TODO(reveman): We should avoid keeping around unused resources if
- // possible. crbug.com/224475
- global_tile_state_.memory_limit_in_bytes =
- visible_ ?
- policy.bytes_limit_when_visible : 0;
- global_tile_state_.unused_memory_limit_in_bytes = static_cast<size_t>(
- (static_cast<int64>(global_tile_state_.memory_limit_in_bytes) *
- settings_.max_unused_resource_memory_percentage) / 100);
+ global_tile_state_.hard_memory_limit_in_bytes = 0;
+ global_tile_state_.soft_memory_limit_in_bytes = 0;
+ if (visible_ && policy.bytes_limit_when_visible > 0) {
+ global_tile_state_.hard_memory_limit_in_bytes =
+ policy.bytes_limit_when_visible;
+ global_tile_state_.soft_memory_limit_in_bytes =
+ (static_cast<int64>(global_tile_state_.hard_memory_limit_in_bytes) *
+ settings_.max_memory_for_prepaint_percentage) /
+ 100;
+ }
global_tile_state_.memory_limit_policy =
ManagedMemoryPolicy::PriorityCutoffToTileMemoryLimitPolicy(
visible_ ?
@@ -1171,6 +1186,34 @@ void LayerTreeHostImpl::UpdateTileManagerMemoryPolicy(
gpu::MemoryAllocation::CUTOFF_ALLOW_NOTHING);
global_tile_state_.num_resources_limit = policy.num_resources_limit;
+ // TODO(reveman): We should avoid keeping around unused resources if
+ // possible. crbug.com/224475
+ // Unused limit is calculated from soft-limit, as hard-limit may
+ // be very high and shouldn't typically be exceeded.
+ size_t unused_memory_limit_in_bytes = static_cast<size_t>(
+ (static_cast<int64>(global_tile_state_.soft_memory_limit_in_bytes) *
+ settings_.max_unused_resource_memory_percentage) /
+ 100);
+
+ DCHECK(resource_pool_);
+ resource_pool_->CheckBusyResources();
+ // Soft limit is used for resource pool such that memory returns to soft
+ // limit after going over.
+ resource_pool_->SetResourceUsageLimits(
+ global_tile_state_.soft_memory_limit_in_bytes,
+ unused_memory_limit_in_bytes,
+ global_tile_state_.num_resources_limit);
+
+ // Staging pool resources are used as transfer buffers so we use
+ // |transfer_buffer_memory_limit_| as the memory limit for this resource pool.
+ if (staging_resource_pool_) {
+ staging_resource_pool_->CheckBusyResources();
+ staging_resource_pool_->SetResourceUsageLimits(
+ visible_ ? transfer_buffer_memory_limit_ : 0,
+ transfer_buffer_memory_limit_,
+ std::numeric_limits<size_t>::max());
+ }
+
DidModifyTilePriorities();
}
@@ -1182,17 +1225,36 @@ void LayerTreeHostImpl::DidModifyTilePriorities() {
}
void LayerTreeHostImpl::DidInitializeVisibleTile() {
- // TODO(reveman): Determine tiles that changed and only damage
- // what's necessary.
- SetFullRootLayerDamage();
if (client_ && !client_->IsInsideDraw())
client_->DidInitializeVisibleTileOnImplThread();
}
+const std::vector<PictureLayerImpl*>& LayerTreeHostImpl::GetPictureLayers() {
+ return picture_layers_;
+}
+
void LayerTreeHostImpl::NotifyReadyToActivate() {
client_->NotifyReadyToActivate();
}
+void LayerTreeHostImpl::NotifyTileStateChanged(const Tile* tile) {
+ TRACE_EVENT0("cc", "LayerTreeHostImpl::NotifyTileStateChanged");
+
+ if (active_tree_) {
+ LayerImpl* layer_impl =
+ active_tree_->FindActiveTreeLayerById(tile->layer_id());
+ if (layer_impl)
+ layer_impl->NotifyTileStateChanged(tile);
+ }
+
+ if (pending_tree_) {
+ LayerImpl* layer_impl =
+ pending_tree_->FindPendingTreeLayerById(tile->layer_id());
+ if (layer_impl)
+ layer_impl->NotifyTileStateChanged(tile);
+ }
+}
+
void LayerTreeHostImpl::SetMemoryPolicy(const ManagedMemoryPolicy& policy) {
SetManagedMemoryPolicy(policy, zero_budget_);
}
@@ -1247,32 +1309,36 @@ void LayerTreeHostImpl::SetManagedMemoryPolicy(
void LayerTreeHostImpl::SetExternalDrawConstraints(
const gfx::Transform& transform,
- gfx::Rect viewport,
- gfx::Rect clip,
+ const gfx::Rect& viewport,
+ const gfx::Rect& clip,
bool valid_for_tile_management) {
+ if (external_transform_ != transform || external_viewport_ != viewport) {
+ active_tree_->set_needs_update_draw_properties();
+ }
+
external_transform_ = transform;
external_viewport_ = viewport;
external_clip_ = clip;
device_viewport_valid_for_tile_management_ = valid_for_tile_management;
}
-void LayerTreeHostImpl::SetNeedsRedrawRect(gfx::Rect damage_rect) {
+void LayerTreeHostImpl::SetNeedsRedrawRect(const gfx::Rect& damage_rect) {
if (damage_rect.IsEmpty())
return;
NotifySwapPromiseMonitorsOfSetNeedsRedraw();
client_->SetNeedsRedrawRectOnImplThread(damage_rect);
}
-void LayerTreeHostImpl::BeginImplFrame(const BeginFrameArgs& args) {
- client_->BeginImplFrame(args);
+void LayerTreeHostImpl::BeginFrame(const BeginFrameArgs& args) {
+ client_->BeginFrame(args);
}
void LayerTreeHostImpl::DidSwapBuffers() {
client_->DidSwapBuffersOnImplThread();
}
-void LayerTreeHostImpl::OnSwapBuffersComplete() {
- client_->OnSwapBuffersCompleteOnImplThread();
+void LayerTreeHostImpl::DidSwapBuffersComplete() {
+ client_->DidSwapBuffersCompleteOnImplThread();
}
void LayerTreeHostImpl::ReclaimResources(const CompositorFrameAck* ack) {
@@ -1280,6 +1346,20 @@ void LayerTreeHostImpl::ReclaimResources(const CompositorFrameAck* ack) {
// processing it.
if (renderer_)
renderer_->ReceiveSwapBuffersAck(*ack);
+
+ // In OOM, we now might be able to release more resources that were held
+ // because they were exported.
+ if (tile_manager_) {
+ DCHECK(resource_pool_);
+
+ resource_pool_->CheckBusyResources();
+ resource_pool_->ReduceResourceUsage();
+ }
+ // If we're not visible, we likely released resources, so we want to
+ // aggressively flush here to make sure those DeleteTextures make it to the
+ // GPU process to free up the memory.
+ if (resource_provider_ && !visible_)
+ resource_provider_->ShallowFlushIfSupported();
}
void LayerTreeHostImpl::OnCanDrawStateChangedForTree() {
@@ -1302,10 +1382,10 @@ CompositorFrameMetadata LayerTreeHostImpl::MakeCompositorFrameMetadata() const {
metadata.overdraw_bottom_height = overdraw_bottom_height_;
}
- if (!RootScrollLayer())
+ if (!InnerViewportScrollLayer())
return metadata;
- metadata.root_scroll_offset = RootScrollLayer()->TotalScrollOffset();
+ metadata.root_scroll_offset = active_tree_->TotalScrollOffset();
return metadata;
}
@@ -1320,7 +1400,7 @@ void LayerTreeHostImpl::DrawLayers(FrameData* frame,
DCHECK(CanDraw());
if (frame->has_no_damage) {
- TRACE_EVENT0("cc", "EarlyOut_NoDamage");
+ TRACE_EVENT_INSTANT0("cc", "EarlyOut_NoDamage", TRACE_EVENT_SCOPE_THREAD);
DCHECK(!output_surface_->capabilities()
.draw_and_swap_full_viewport_every_frame);
return;
@@ -1330,7 +1410,6 @@ void LayerTreeHostImpl::DrawLayers(FrameData* frame,
fps_counter_->SaveTimeStamp(frame_begin_time,
!output_surface_->context_provider());
-
bool on_main_thread = false;
rendering_stats_instrumentation_->IncrementFrameCount(
1, on_main_thread);
@@ -1343,6 +1422,7 @@ void LayerTreeHostImpl::DrawLayers(FrameData* frame,
if (debug_state_.ShowHudRects()) {
debug_rect_history_->SaveDebugRectsForCurrentFrame(
active_tree_->root_layer(),
+ active_tree_->hud_layer(),
*frame->render_surface_layer_list,
frame->occluding_screen_space_rects,
frame->non_occluding_screen_space_rects,
@@ -1370,8 +1450,11 @@ void LayerTreeHostImpl::DrawLayers(FrameData* frame,
TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
TRACE_DISABLED_BY_DEFAULT("cc.debug") ","
- TRACE_DISABLED_BY_DEFAULT("cc.debug.quads"), "cc::LayerTreeHostImpl",
- this, TracedValue::FromValue(AsValueWithFrame(frame).release()));
+ TRACE_DISABLED_BY_DEFAULT("cc.debug.quads") ","
+ TRACE_DISABLED_BY_DEFAULT("devtools.timeline.layers"),
+ "cc::LayerTreeHostImpl",
+ id_,
+ TracedValue::FromValue(AsValueWithFrame(frame).release()));
// Because the contents of the HUD depend on everything else in the frame, the
// contents of its texture are updated as the last thing before the frame is
@@ -1383,31 +1466,21 @@ void LayerTreeHostImpl::DrawLayers(FrameData* frame,
}
if (output_surface_->ForcedDrawToSoftwareDevice()) {
- bool allow_partial_swap = false;
bool disable_picture_quad_image_filtering =
IsCurrentlyScrolling() || needs_animate_layers();
scoped_ptr<SoftwareRenderer> temp_software_renderer =
SoftwareRenderer::Create(this, &settings_, output_surface_.get(), NULL);
temp_software_renderer->DrawFrame(&frame->render_passes,
- NULL,
device_scale_factor_,
DeviceViewport(),
DeviceClip(),
- allow_partial_swap,
disable_picture_quad_image_filtering);
} else {
- // We don't track damage on the HUD layer (it interacts with damage tracking
- // visualizations), so disable partial swaps to make the HUD layer display
- // properly.
- bool allow_partial_swap = !debug_state_.ShowHudRects();
-
renderer_->DrawFrame(&frame->render_passes,
- offscreen_context_provider_.get(),
device_scale_factor_,
DeviceViewport(),
DeviceClip(),
- allow_partial_swap,
false);
}
// The render passes should be consumed by the renderer.
@@ -1424,6 +1497,7 @@ void LayerTreeHostImpl::DrawLayers(FrameData* frame,
}
active_tree_->root_layer()->ResetAllChangeTrackingForSubtree();
+ devtools_instrumentation::DidDrawFrame(id_);
BenchmarkInstrumentation::IssueImplThreadRenderingStatsEvent(
rendering_stats_instrumentation_->impl_thread_rendering_stats());
rendering_stats_instrumentation_->AccumulateAndClearImplThreadStats();
@@ -1448,43 +1522,105 @@ bool LayerTreeHostImpl::IsContextLost() {
return renderer_ && renderer_->IsContextLost();
}
-const RendererCapabilities& LayerTreeHostImpl::GetRendererCapabilities() const {
+void LayerTreeHostImpl::SetUseGpuRasterization(bool use_gpu) {
+ if (use_gpu == use_gpu_rasterization_)
+ return;
+
+ use_gpu_rasterization_ = use_gpu;
+ ReleaseTreeResources();
+
+ // Replace existing tile manager with another one that uses appropriate
+ // rasterizer.
+ if (tile_manager_) {
+ DestroyTileManager();
+ CreateAndSetTileManager();
+ }
+
+ // We have released tilings for both active and pending tree.
+ // We would not have any content to draw until the pending tree is activated.
+ // Prevent the active tree from drawing until activation.
+ active_tree_->SetRequiresHighResToDraw();
+}
+
+const RendererCapabilitiesImpl&
+LayerTreeHostImpl::GetRendererCapabilities() const {
return renderer_->Capabilities();
}
bool LayerTreeHostImpl::SwapBuffers(const LayerTreeHostImpl::FrameData& frame) {
+ active_tree()->ResetRequiresHighResToDraw();
if (frame.has_no_damage) {
active_tree()->BreakSwapPromises(SwapPromise::SWAP_FAILS);
return false;
}
CompositorFrameMetadata metadata = MakeCompositorFrameMetadata();
active_tree()->FinishSwapPromises(&metadata);
+ for (size_t i = 0; i < metadata.latency_info.size(); i++) {
+ TRACE_EVENT_FLOW_STEP0(
+ "input",
+ "LatencyInfo.Flow",
+ TRACE_ID_DONT_MANGLE(metadata.latency_info[i].trace_id),
+ "SwapBuffers");
+ }
renderer_->SwapBuffers(metadata);
return true;
}
-void LayerTreeHostImpl::SetNeedsBeginImplFrame(bool enable) {
+void LayerTreeHostImpl::SetNeedsBeginFrame(bool enable) {
if (output_surface_)
- output_surface_->SetNeedsBeginImplFrame(enable);
+ output_surface_->SetNeedsBeginFrame(enable);
+ else
+ DCHECK(!enable);
+}
+
+void LayerTreeHostImpl::WillBeginImplFrame(const BeginFrameArgs& args) {
+ // Sample the frame time now. This time will be used for updating animations
+ // when we draw.
+ UpdateCurrentFrameTime();
+ // Cache the begin impl frame interval
+ begin_impl_frame_interval_ = args.interval;
+}
+
+gfx::SizeF LayerTreeHostImpl::ComputeInnerViewportContainerSize() const {
+ gfx::SizeF dip_size =
+ gfx::ScaleSize(device_viewport_size_, 1.f / device_scale_factor());
+
+ float top_offset =
+ top_controls_manager_ ? top_controls_manager_->content_top_offset() : 0.f;
+
+ return gfx::SizeF(dip_size.width(),
+ dip_size.height() - top_offset - overdraw_bottom_height_);
+}
+
+void LayerTreeHostImpl::UpdateInnerViewportContainerSize() {
+ LayerImpl* container_layer = active_tree_->InnerViewportContainerLayer();
+ if (!container_layer)
+ return;
+
+ // We pass the value returned from UnscaledScrollableViewportSize() here as
+ // it accounts for scrollbar dimensions when
+ // container_layer->masks_to_bounds() is set.
+ container_layer->SetTemporaryImplBounds(UnscaledScrollableViewportSize());
}
gfx::SizeF LayerTreeHostImpl::UnscaledScrollableViewportSize() const {
// Use the root container layer bounds if it clips to them, otherwise, the
// true viewport size should be used.
- LayerImpl* container_layer = active_tree_->RootContainerLayer();
+ LayerImpl* container_layer = active_tree_->InnerViewportContainerLayer();
if (container_layer && container_layer->masks_to_bounds()) {
DCHECK(!top_controls_manager_);
DCHECK_EQ(0, overdraw_bottom_height_);
return container_layer->bounds();
}
- gfx::SizeF dip_size =
- gfx::ScaleSize(device_viewport_size_, 1.f / device_scale_factor());
+ return ComputeInnerViewportContainerSize();
+}
- float top_offset =
- top_controls_manager_ ? top_controls_manager_->content_top_offset() : 0.f;
- return gfx::SizeF(dip_size.width(),
- dip_size.height() - top_offset - overdraw_bottom_height_);
+float LayerTreeHostImpl::VerticalAdjust() const {
+ if (!active_tree_->InnerViewportContainerLayer())
+ return 0;
+
+ return active_tree_->InnerViewportContainerLayer()->BoundsDelta().y();
}
void LayerTreeHostImpl::DidLoseOutputSurface() {
@@ -1495,27 +1631,25 @@ void LayerTreeHostImpl::DidLoseOutputSurface() {
// important) in production. We should adjust the test to not need this.
if (renderer_)
client_->DidLoseOutputSurfaceOnImplThread();
-#ifndef NDEBUG
+#if DCHECK_IS_ON
did_lose_called_ = true;
#endif
}
-void LayerTreeHostImpl::Readback(void* pixels,
- gfx::Rect rect_in_device_viewport) {
- DCHECK(renderer_);
- renderer_->GetFramebufferPixels(pixels, rect_in_device_viewport);
-}
-
bool LayerTreeHostImpl::HaveRootScrollLayer() const {
- return !!RootScrollLayer();
+ return !!InnerViewportScrollLayer();
}
LayerImpl* LayerTreeHostImpl::RootLayer() const {
return active_tree_->root_layer();
}
-LayerImpl* LayerTreeHostImpl::RootScrollLayer() const {
- return active_tree_->RootScrollLayer();
+LayerImpl* LayerTreeHostImpl::InnerViewportScrollLayer() const {
+ return active_tree_->InnerViewportScrollLayer();
+}
+
+LayerImpl* LayerTreeHostImpl::OuterViewportScrollLayer() const {
+ return active_tree_->OuterViewportScrollLayer();
}
LayerImpl* LayerTreeHostImpl::CurrentlyScrollingLayer() const {
@@ -1524,7 +1658,10 @@ LayerImpl* LayerTreeHostImpl::CurrentlyScrollingLayer() const {
bool LayerTreeHostImpl::IsCurrentlyScrolling() const {
return CurrentlyScrollingLayer() ||
- (RootScrollLayer() && RootScrollLayer()->IsExternalFlingActive());
+ (InnerViewportScrollLayer() &&
+ InnerViewportScrollLayer()->IsExternalFlingActive()) ||
+ (OuterViewportScrollLayer() &&
+ OuterViewportScrollLayer()->IsExternalFlingActive());
}
// Content layers can be either directly scrollable or contained in an outer
@@ -1551,6 +1688,13 @@ void LayerTreeHostImpl::CreatePendingTree() {
recycle_tree_.swap(pending_tree_);
else
pending_tree_ = LayerTreeImpl::create(this);
+
+ // Update the delta from the active tree, which may have
+ // adjusted its delta prior to the pending tree being created.
+ DCHECK_EQ(1.f, pending_tree_->sent_page_scale_delta());
+ pending_tree_->SetPageScaleDelta(active_tree_->page_scale_delta() /
+ active_tree_->sent_page_scale_delta());
+
client_->OnCanDrawStateChanged(CanDraw());
TRACE_EVENT_ASYNC_BEGIN0("cc", "PendingTree:waiting", pending_tree_.get());
}
@@ -1594,6 +1738,7 @@ void LayerTreeHostImpl::ActivatePendingTree() {
active_tree_->DidBecomeActive();
active_tree_->SetRootLayerScrollOffsetDelegate(
root_layer_scroll_offset_delegate_);
+ ActivateAnimations();
client_->OnCanDrawStateChanged(CanDraw());
SetNeedsRedraw();
@@ -1607,14 +1752,13 @@ void LayerTreeHostImpl::ActivatePendingTree() {
stats.impl_stats.rasterize_time);
}
+ UpdateInnerViewportContainerSize();
client_->DidActivatePendingTree();
if (!tree_activation_callback_.is_null())
tree_activation_callback_.Run();
if (time_source_client_adapter_ && time_source_client_adapter_->Active())
DCHECK(active_tree_->root_layer());
- devtools_instrumentation::didActivateLayerTree(id_,
- active_tree_->source_frame_number());
}
void LayerTreeHostImpl::SetVisible(bool visible) {
@@ -1626,7 +1770,11 @@ void LayerTreeHostImpl::SetVisible(bool visible) {
DidVisibilityChange(this, visible_);
EnforceManagedMemoryPolicy(ActualManagedMemoryPolicy());
- if (!visible_)
+ // If we just became visible, we have to ensure that we draw high res tiles,
+ // to prevent checkerboard/low res flashes.
+ if (visible_)
+ active_tree()->SetRequiresHighResToDraw();
+ else
EvictAllUIResources();
// Evict tiles immediately if invisible since this tab may never get another
@@ -1640,6 +1788,11 @@ void LayerTreeHostImpl::SetVisible(bool visible) {
renderer_->SetVisible(visible);
}
+void LayerTreeHostImpl::SetNeedsAnimate() {
+ NotifySwapPromiseMonitorsOfSetNeedsRedraw();
+ client_->SetNeedsAnimateOnImplThread();
+}
+
void LayerTreeHostImpl::SetNeedsRedraw() {
NotifySwapPromiseMonitorsOfSetNeedsRedraw();
client_->SetNeedsRedrawOnImplThread();
@@ -1650,6 +1803,9 @@ ManagedMemoryPolicy LayerTreeHostImpl::ActualManagedMemoryPolicy() const {
if (debug_state_.rasterize_only_visible_content) {
actual.priority_cutoff_when_visible =
gpu::MemoryAllocation::CUTOFF_ALLOW_REQUIRED_ONLY;
+ } else if (use_gpu_rasterization()) {
+ actual.priority_cutoff_when_visible =
+ gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE;
}
if (zero_budget_) {
@@ -1669,67 +1825,143 @@ int LayerTreeHostImpl::memory_allocation_priority_cutoff() const {
}
void LayerTreeHostImpl::ReleaseTreeResources() {
- if (active_tree_->root_layer())
- SendReleaseResourcesRecursive(active_tree_->root_layer());
- if (pending_tree_ && pending_tree_->root_layer())
- SendReleaseResourcesRecursive(pending_tree_->root_layer());
- if (recycle_tree_ && recycle_tree_->root_layer())
- SendReleaseResourcesRecursive(recycle_tree_->root_layer());
+ active_tree_->ReleaseResources();
+ if (pending_tree_)
+ pending_tree_->ReleaseResources();
+ if (recycle_tree_)
+ recycle_tree_->ReleaseResources();
EvictAllUIResources();
}
-void LayerTreeHostImpl::CreateAndSetRenderer(
- OutputSurface* output_surface,
- ResourceProvider* resource_provider,
- bool skip_gl_renderer) {
+void LayerTreeHostImpl::CreateAndSetRenderer() {
DCHECK(!renderer_);
- if (output_surface->capabilities().delegated_rendering) {
+ DCHECK(output_surface_);
+ DCHECK(resource_provider_);
+
+ if (output_surface_->capabilities().delegated_rendering) {
renderer_ = DelegatingRenderer::Create(
- this, &settings_, output_surface, resource_provider);
- } else if (output_surface->context_provider() && !skip_gl_renderer) {
+ this, &settings_, output_surface_.get(), resource_provider_.get());
+ } else if (output_surface_->context_provider()) {
renderer_ = GLRenderer::Create(this,
&settings_,
- output_surface,
- resource_provider,
+ output_surface_.get(),
+ resource_provider_.get(),
texture_mailbox_deleter_.get(),
settings_.highp_threshold_min);
- } else if (output_surface->software_device()) {
+ } else if (output_surface_->software_device()) {
renderer_ = SoftwareRenderer::Create(
- this, &settings_, output_surface, resource_provider);
+ this, &settings_, output_surface_.get(), resource_provider_.get());
}
+ DCHECK(renderer_);
- if (renderer_) {
- renderer_->SetVisible(visible_);
- SetFullRootLayerDamage();
+ renderer_->SetVisible(visible_);
+ SetFullRootLayerDamage();
- // See note in LayerTreeImpl::UpdateDrawProperties. Renderer needs to be
- // initialized to get max texture size. Also, after releasing resources,
- // trees need another update to generate new ones.
- active_tree_->set_needs_update_draw_properties();
- if (pending_tree_)
- pending_tree_->set_needs_update_draw_properties();
- }
+ // See note in LayerTreeImpl::UpdateDrawProperties. Renderer needs to be
+ // initialized to get max texture size. Also, after releasing resources,
+ // trees need another update to generate new ones.
+ active_tree_->set_needs_update_draw_properties();
+ if (pending_tree_)
+ pending_tree_->set_needs_update_draw_properties();
+ client_->UpdateRendererCapabilitiesOnImplThread();
}
-void LayerTreeHostImpl::CreateAndSetTileManager(
- ResourceProvider* resource_provider,
- ContextProvider* context_provider,
- bool using_map_image) {
+void LayerTreeHostImpl::CreateAndSetTileManager() {
+ DCHECK(!tile_manager_);
DCHECK(settings_.impl_side_painting);
- DCHECK(resource_provider);
+ DCHECK(output_surface_);
+ DCHECK(resource_provider_);
+ DCHECK(proxy_->ImplThreadTaskRunner());
+
+ ContextProvider* context_provider = output_surface_->context_provider();
+ transfer_buffer_memory_limit_ =
+ GetMaxTransferBufferUsageBytes(context_provider);
+
+ if (use_gpu_rasterization_ && context_provider) {
+ resource_pool_ =
+ ResourcePool::Create(resource_provider_.get(),
+ GL_TEXTURE_2D,
+ resource_provider_->best_texture_format());
+
+ raster_worker_pool_ =
+ DirectRasterWorkerPool::Create(proxy_->ImplThreadTaskRunner(),
+ resource_provider_.get(),
+ context_provider);
+ on_demand_task_graph_runner_ = &synchronous_task_graph_runner_;
+ } else if (UseZeroCopyTextureUpload()) {
+ resource_pool_ =
+ ResourcePool::Create(resource_provider_.get(),
+ GetMapImageTextureTarget(context_provider),
+ resource_provider_->best_texture_format());
+
+ raster_worker_pool_ =
+ ImageRasterWorkerPool::Create(proxy_->ImplThreadTaskRunner(),
+ RasterWorkerPool::GetTaskGraphRunner(),
+ resource_provider_.get());
+ on_demand_task_graph_runner_ = RasterWorkerPool::GetTaskGraphRunner();
+ } else if (UseOneCopyTextureUpload()) {
+ // We need to create a staging resource pool when using copy rasterizer.
+ staging_resource_pool_ =
+ ResourcePool::Create(resource_provider_.get(),
+ GetMapImageTextureTarget(context_provider),
+ resource_provider_->best_texture_format());
+ resource_pool_ =
+ ResourcePool::Create(resource_provider_.get(),
+ GL_TEXTURE_2D,
+ resource_provider_->best_texture_format());
+
+ raster_worker_pool_ = ImageCopyRasterWorkerPool::Create(
+ proxy_->ImplThreadTaskRunner(),
+ RasterWorkerPool::GetTaskGraphRunner(),
+ resource_provider_.get(),
+ staging_resource_pool_.get());
+ on_demand_task_graph_runner_ = RasterWorkerPool::GetTaskGraphRunner();
+ } else {
+ resource_pool_ = ResourcePool::Create(
+ resource_provider_.get(),
+ GL_TEXTURE_2D,
+ resource_provider_->memory_efficient_texture_format());
+
+ raster_worker_pool_ = PixelBufferRasterWorkerPool::Create(
+ proxy_->ImplThreadTaskRunner(),
+ RasterWorkerPool::GetTaskGraphRunner(),
+ resource_provider_.get(),
+ transfer_buffer_memory_limit_);
+ on_demand_task_graph_runner_ = RasterWorkerPool::GetTaskGraphRunner();
+ }
+
tile_manager_ =
TileManager::Create(this,
- resource_provider,
- settings_.num_raster_threads,
- rendering_stats_instrumentation_,
- using_map_image,
- GetMaxTransferBufferUsageBytes(context_provider),
- GetMaxRasterTasksUsageBytes(context_provider),
- GetMapImageTextureTarget(context_provider));
+ proxy_->ImplThreadTaskRunner(),
+ resource_pool_.get(),
+ raster_worker_pool_->AsRasterizer(),
+ rendering_stats_instrumentation_);
UpdateTileManagerMemoryPolicy(ActualManagedMemoryPolicy());
need_to_update_visible_tiles_before_draw_ = false;
+ on_demand_task_namespace_ = on_demand_task_graph_runner_->GetNamespaceToken();
+}
+
+void LayerTreeHostImpl::DestroyTileManager() {
+ tile_manager_.reset();
+ resource_pool_.reset();
+ staging_resource_pool_.reset();
+ raster_worker_pool_.reset();
+}
+
+bool LayerTreeHostImpl::UseZeroCopyTextureUpload() const {
+ // Note: we use zero-copy by default when the renderer is using
+ // shared memory resources.
+ return (settings_.use_zero_copy ||
+ GetRendererCapabilities().using_shared_memory_resources) &&
+ GetRendererCapabilities().using_map_image;
+}
+
+bool LayerTreeHostImpl::UseOneCopyTextureUpload() const {
+ // Sync query support is required by one-copy rasterizer.
+ return settings_.use_one_copy && GetRendererCapabilities().using_map_image &&
+ resource_provider_->use_sync_query();
}
void LayerTreeHostImpl::EnforceZeroBudget(bool zero_budget) {
@@ -1738,7 +1970,8 @@ void LayerTreeHostImpl::EnforceZeroBudget(bool zero_budget) {
bool LayerTreeHostImpl::InitializeRenderer(
scoped_ptr<OutputSurface> output_surface) {
-#ifndef NDEBUG
+ TRACE_EVENT0("cc", "LayerTreeHostImpl::InitializeRenderer");
+#if DCHECK_IS_ON
DCHECK(!renderer_ || did_lose_called_);
#endif
@@ -1749,120 +1982,77 @@ bool LayerTreeHostImpl::InitializeRenderer(
// Note: order is important here.
renderer_.reset();
- tile_manager_.reset();
+ DestroyTileManager();
resource_provider_.reset();
output_surface_.reset();
if (!output_surface->BindToClient(this))
return false;
- scoped_ptr<ResourceProvider> resource_provider =
- ResourceProvider::Create(output_surface.get(),
+ output_surface_ = output_surface.Pass();
+ resource_provider_ =
+ ResourceProvider::Create(output_surface_.get(),
shared_bitmap_manager_,
settings_.highp_threshold_min,
settings_.use_rgba_4444_textures,
- settings_.texture_id_allocation_chunk_size);
- if (!resource_provider)
- return false;
+ settings_.texture_id_allocation_chunk_size,
+ settings_.use_distance_field_text);
- if (output_surface->capabilities().deferred_gl_initialization)
+ if (output_surface_->capabilities().deferred_gl_initialization)
EnforceZeroBudget(true);
- bool skip_gl_renderer = false;
- CreateAndSetRenderer(
- output_surface.get(), resource_provider.get(), skip_gl_renderer);
+ CreateAndSetRenderer();
- if (!renderer_)
- return false;
+ transfer_buffer_memory_limit_ =
+ GetMaxTransferBufferUsageBytes(output_surface_->context_provider());
- if (settings_.impl_side_painting) {
- CreateAndSetTileManager(resource_provider.get(),
- output_surface->context_provider().get(),
- GetRendererCapabilities().using_map_image);
- }
+ if (settings_.impl_side_painting)
+ CreateAndSetTileManager();
- // Setup BeginImplFrameEmulation if it's not supported natively
- if (!settings_.begin_impl_frame_scheduling_enabled) {
- const base::TimeDelta display_refresh_interval =
- base::TimeDelta::FromMicroseconds(
- base::Time::kMicrosecondsPerSecond /
- settings_.refresh_rate);
+ // Initialize vsync parameters to sane values.
+ const base::TimeDelta display_refresh_interval =
+ base::TimeDelta::FromMicroseconds(base::Time::kMicrosecondsPerSecond /
+ settings_.refresh_rate);
+ CommitVSyncParameters(base::TimeTicks(), display_refresh_interval);
- output_surface->InitializeBeginImplFrameEmulation(
- proxy_->ImplThreadTaskRunner(),
- settings_.throttle_frame_production,
- display_refresh_interval);
- }
+ // TODO(brianderson): Don't use a hard-coded parent draw time.
+ base::TimeDelta parent_draw_time =
+ (!settings_.begin_frame_scheduling_enabled &&
+ output_surface_->capabilities().adjust_deadline_for_parent)
+ ? BeginFrameArgs::DefaultEstimatedParentDrawTime()
+ : base::TimeDelta();
+ client_->SetEstimatedParentDrawTime(parent_draw_time);
- int max_frames_pending =
- output_surface->capabilities().max_frames_pending;
+ int max_frames_pending = output_surface_->capabilities().max_frames_pending;
if (max_frames_pending <= 0)
max_frames_pending = OutputSurface::DEFAULT_MAX_FRAMES_PENDING;
- output_surface->SetMaxFramesPending(max_frames_pending);
-
- resource_provider_ = resource_provider.Pass();
- output_surface_ = output_surface.Pass();
-
+ client_->SetMaxSwapsPendingOnImplThread(max_frames_pending);
client_->OnCanDrawStateChanged(CanDraw());
return true;
}
-bool LayerTreeHostImpl::DeferredInitialize(
- scoped_refptr<ContextProvider> offscreen_context_provider) {
+void LayerTreeHostImpl::CommitVSyncParameters(base::TimeTicks timebase,
+ base::TimeDelta interval) {
+ client_->CommitVSyncParameters(timebase, interval);
+}
+
+void LayerTreeHostImpl::DeferredInitialize() {
DCHECK(output_surface_->capabilities().deferred_gl_initialization);
DCHECK(settings_.impl_side_painting);
DCHECK(output_surface_->context_provider());
ReleaseTreeResources();
renderer_.reset();
+ DestroyTileManager();
- bool resource_provider_success = resource_provider_->InitializeGL();
-
- bool success = resource_provider_success;
- if (success) {
- bool skip_gl_renderer = false;
- CreateAndSetRenderer(
- output_surface_.get(), resource_provider_.get(), skip_gl_renderer);
- if (!renderer_)
- success = false;
- }
-
- if (success) {
- if (offscreen_context_provider.get() &&
- !offscreen_context_provider->BindToCurrentThread())
- success = false;
- }
-
- if (success) {
- EnforceZeroBudget(false);
- client_->SetNeedsCommitOnImplThread();
- } else {
- if (offscreen_context_provider.get()) {
- if (offscreen_context_provider->BindToCurrentThread())
- offscreen_context_provider->VerifyContexts();
- offscreen_context_provider = NULL;
- }
-
- client_->DidLoseOutputSurfaceOnImplThread();
+ resource_provider_->InitializeGL();
- if (resource_provider_success) {
- // If this fails the context provider will be dropped from the output
- // surface and destroyed. But the GLRenderer expects the output surface
- // to stick around - and hold onto the context3d - as long as it is alive.
- // TODO(danakj): Remove the need for this code path: crbug.com/276411
- renderer_.reset();
-
- // The resource provider can't stay in GL mode or it tries to clean up GL
- // stuff, but the context provider is going away on the output surface
- // which contradicts being in GL mode.
- // TODO(danakj): Remove the need for this code path: crbug.com/276411
- resource_provider_->InitializeSoftware();
- }
- }
+ CreateAndSetRenderer();
+ EnforceZeroBudget(false);
+ CreateAndSetTileManager();
- SetOffscreenContextProvider(offscreen_context_provider);
- return success;
+ client_->SetNeedsCommitOnImplThread();
}
void LayerTreeHostImpl::ReleaseGL() {
@@ -1872,26 +2062,19 @@ void LayerTreeHostImpl::ReleaseGL() {
ReleaseTreeResources();
renderer_.reset();
- tile_manager_.reset();
- resource_provider_->InitializeSoftware();
+ DestroyTileManager();
- bool skip_gl_renderer = true;
- CreateAndSetRenderer(
- output_surface_.get(), resource_provider_.get(), skip_gl_renderer);
- DCHECK(renderer_);
+ resource_provider_->InitializeSoftware();
+ output_surface_->ReleaseContextProvider();
+ CreateAndSetRenderer();
EnforceZeroBudget(true);
- CreateAndSetTileManager(resource_provider_.get(),
- NULL,
- GetRendererCapabilities().using_map_image);
- DCHECK(tile_manager_);
-
- SetOffscreenContextProvider(NULL);
+ CreateAndSetTileManager();
client_->SetNeedsCommitOnImplThread();
}
-void LayerTreeHostImpl::SetViewportSize(gfx::Size device_viewport_size) {
+void LayerTreeHostImpl::SetViewportSize(const gfx::Size& device_viewport_size) {
if (device_viewport_size == device_viewport_size_)
return;
@@ -1900,10 +2083,10 @@ void LayerTreeHostImpl::SetViewportSize(gfx::Size device_viewport_size) {
device_viewport_size_ = device_viewport_size;
- UpdateMaxScrollOffset();
-
+ UpdateInnerViewportContainerSize();
client_->OnCanDrawStateChanged(CanDraw());
SetFullRootLayerDamage();
+ active_tree_->set_needs_update_draw_properties();
}
void LayerTreeHostImpl::SetOverdrawBottomHeight(float overdraw_bottom_height) {
@@ -1911,13 +2094,13 @@ void LayerTreeHostImpl::SetOverdrawBottomHeight(float overdraw_bottom_height) {
return;
overdraw_bottom_height_ = overdraw_bottom_height;
- UpdateMaxScrollOffset();
+ UpdateInnerViewportContainerSize();
SetFullRootLayerDamage();
}
void LayerTreeHostImpl::SetOverhangUIResource(
UIResourceId overhang_ui_resource_id,
- gfx::Size overhang_ui_resource_size) {
+ const gfx::Size& overhang_ui_resource_size) {
overhang_ui_resource_id_ = overhang_ui_resource_id;
overhang_ui_resource_size_ = overhang_ui_resource_size;
}
@@ -1927,7 +2110,7 @@ void LayerTreeHostImpl::SetDeviceScaleFactor(float device_scale_factor) {
return;
device_scale_factor_ = device_scale_factor;
- UpdateMaxScrollOffset();
+ UpdateInnerViewportContainerSize();
SetFullRootLayerDamage();
}
@@ -1953,21 +2136,14 @@ const gfx::Transform& LayerTreeHostImpl::DrawTransform() const {
return external_transform_;
}
-void LayerTreeHostImpl::UpdateMaxScrollOffset() {
- active_tree_->UpdateMaxScrollOffset();
-}
-
void LayerTreeHostImpl::DidChangeTopControlsPosition() {
+ UpdateInnerViewportContainerSize();
SetNeedsRedraw();
+ SetNeedsAnimate();
active_tree_->set_needs_update_draw_properties();
SetFullRootLayerDamage();
}
-bool LayerTreeHostImpl::EnsureRenderSurfaceLayerList() {
- active_tree_->UpdateDrawProperties();
- return !active_tree_->RenderSurfaceLayerList().empty();
-}
-
void LayerTreeHostImpl::BindToClient(InputHandlerClient* client) {
DCHECK(input_handler_client_ == NULL);
input_handler_client_ = client;
@@ -1980,12 +2156,15 @@ static LayerImpl* NextScrollLayer(LayerImpl* layer) {
}
LayerImpl* LayerTreeHostImpl::FindScrollLayerForDeviceViewportPoint(
- gfx::PointF device_viewport_point, InputHandler::ScrollInputType type,
- LayerImpl* layer_impl, bool* scroll_on_main_thread) const {
+ const gfx::PointF& device_viewport_point,
+ InputHandler::ScrollInputType type,
+ LayerImpl* layer_impl,
+ bool* scroll_on_main_thread,
+ bool* optional_has_ancestor_scroll_handler) const {
DCHECK(scroll_on_main_thread);
// Walk up the hierarchy and look for a scrollable layer.
- LayerImpl* potentially_scrolling_layer_impl = 0;
+ LayerImpl* potentially_scrolling_layer_impl = NULL;
for (; layer_impl; layer_impl = NextScrollLayer(layer_impl)) {
// The content layer can also block attempts to scroll outside the main
// thread.
@@ -2006,24 +2185,39 @@ LayerImpl* LayerTreeHostImpl::FindScrollLayerForDeviceViewportPoint(
return NULL;
}
+ if (optional_has_ancestor_scroll_handler &&
+ scroll_layer_impl->have_scroll_event_handlers())
+ *optional_has_ancestor_scroll_handler = true;
+
if (status == ScrollStarted && !potentially_scrolling_layer_impl)
potentially_scrolling_layer_impl = scroll_layer_impl;
}
- // When hiding top controls is enabled and the controls are hidden or
- // overlaying the content, force scrolls to be enabled on the root layer to
- // allow bringing the top controls back into view.
- if (!potentially_scrolling_layer_impl && top_controls_manager_ &&
- top_controls_manager_->content_top_offset() !=
- settings_.top_controls_height) {
- potentially_scrolling_layer_impl = RootScrollLayer();
- }
+ // Falling back to the root scroll layer ensures generation of root overscroll
+ // notifications while preventing scroll updates from being unintentionally
+ // forwarded to the main thread.
+ if (!potentially_scrolling_layer_impl)
+ potentially_scrolling_layer_impl = OuterViewportScrollLayer()
+ ? OuterViewportScrollLayer()
+ : InnerViewportScrollLayer();
return potentially_scrolling_layer_impl;
}
+// Similar to LayerImpl::HasAncestor, but walks up the scroll parents.
+static bool HasScrollAncestor(LayerImpl* child, LayerImpl* scroll_ancestor) {
+ DCHECK(scroll_ancestor);
+ for (LayerImpl* ancestor = child; ancestor;
+ ancestor = NextScrollLayer(ancestor)) {
+ if (ancestor->scrollable())
+ return ancestor == scroll_ancestor;
+ }
+ return false;
+}
+
InputHandler::ScrollStatus LayerTreeHostImpl::ScrollBegin(
- gfx::Point viewport_point, InputHandler::ScrollInputType type) {
+ const gfx::Point& viewport_point,
+ InputHandler::ScrollInputType type) {
TRACE_EVENT0("cc", "LayerTreeHostImpl::ScrollBegin");
if (top_controls_manager_)
@@ -2032,33 +2226,35 @@ InputHandler::ScrollStatus LayerTreeHostImpl::ScrollBegin(
DCHECK(!CurrentlyScrollingLayer());
ClearCurrentlyScrollingLayer();
- if (!EnsureRenderSurfaceLayerList())
- return ScrollIgnored;
-
gfx::PointF device_viewport_point = gfx::ScalePoint(viewport_point,
device_scale_factor_);
- LayerImpl* layer_impl = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- device_viewport_point,
- active_tree_->RenderSurfaceLayerList());
+ LayerImpl* layer_impl =
+ active_tree_->FindLayerThatIsHitByPoint(device_viewport_point);
+
+ if (layer_impl) {
+ LayerImpl* scroll_layer_impl =
+ active_tree_->FindFirstScrollingLayerThatIsHitByPoint(
+ device_viewport_point);
+ if (scroll_layer_impl && !HasScrollAncestor(layer_impl, scroll_layer_impl))
+ return ScrollUnknown;
+ }
+
bool scroll_on_main_thread = false;
- LayerImpl* potentially_scrolling_layer_impl =
- FindScrollLayerForDeviceViewportPoint(device_viewport_point, type,
- layer_impl, &scroll_on_main_thread);
+ LayerImpl* scrolling_layer_impl =
+ FindScrollLayerForDeviceViewportPoint(device_viewport_point,
+ type,
+ layer_impl,
+ &scroll_on_main_thread,
+ &scroll_affects_scroll_handler_);
if (scroll_on_main_thread) {
UMA_HISTOGRAM_BOOLEAN("TryScroll.SlowScroll", true);
return ScrollOnMainThread;
}
- // If we want to send a DidOverscroll for this scroll it can't be ignored.
- if (!potentially_scrolling_layer_impl && settings_.always_overscroll)
- potentially_scrolling_layer_impl = RootScrollLayer();
-
- if (potentially_scrolling_layer_impl) {
- active_tree_->SetCurrentlyScrollingLayer(
- potentially_scrolling_layer_impl);
+ if (scrolling_layer_impl) {
+ active_tree_->SetCurrentlyScrollingLayer(scrolling_layer_impl);
should_bubble_scrolls_ = (type != NonBubblingGesture);
- last_scroll_did_bubble_ = false;
wheel_scrolling_ = (type == Wheel);
client_->RenewTreePriority();
UMA_HISTOGRAM_BOOLEAN("TryScroll.SlowScroll", false);
@@ -2070,8 +2266,8 @@ InputHandler::ScrollStatus LayerTreeHostImpl::ScrollBegin(
gfx::Vector2dF LayerTreeHostImpl::ScrollLayerWithViewportSpaceDelta(
LayerImpl* layer_impl,
float scale_from_viewport_to_screen_space,
- gfx::PointF viewport_point,
- gfx::Vector2dF viewport_delta) {
+ const gfx::PointF& viewport_point,
+ const gfx::Vector2dF& viewport_delta) {
// Layers with non-invertible screen space transforms should not have passed
// the scroll hit test in the first place.
DCHECK(layer_impl->screen_space_transform().IsInvertible());
@@ -2144,14 +2340,14 @@ gfx::Vector2dF LayerTreeHostImpl::ScrollLayerWithViewportSpaceDelta(
}
static gfx::Vector2dF ScrollLayerWithLocalDelta(LayerImpl* layer_impl,
- gfx::Vector2dF local_delta) {
+ const gfx::Vector2dF& local_delta) {
gfx::Vector2dF previous_delta(layer_impl->ScrollDelta());
layer_impl->ScrollBy(local_delta);
return layer_impl->ScrollDelta() - previous_delta;
}
-bool LayerTreeHostImpl::ScrollBy(gfx::Point viewport_point,
- gfx::Vector2dF scroll_delta) {
+bool LayerTreeHostImpl::ScrollBy(const gfx::Point& viewport_point,
+ const gfx::Vector2dF& scroll_delta) {
TRACE_EVENT0("cc", "LayerTreeHostImpl::ScrollBy");
if (!CurrentlyScrollingLayer())
return false;
@@ -2160,9 +2356,15 @@ bool LayerTreeHostImpl::ScrollBy(gfx::Point viewport_point,
gfx::Vector2dF unused_root_delta;
bool did_scroll_x = false;
bool did_scroll_y = false;
- bool consume_by_top_controls = top_controls_manager_ &&
- (CurrentlyScrollingLayer() == RootScrollLayer() || scroll_delta.y() < 0);
- last_scroll_did_bubble_ = false;
+ bool did_scroll_top_controls = false;
+ // TODO(wjmaclean) Should we guard against CurrentlyScrollingLayer() == 0
+ // here?
+ bool consume_by_top_controls =
+ top_controls_manager_ &&
+ (((CurrentlyScrollingLayer() == InnerViewportScrollLayer() ||
+ CurrentlyScrollingLayer() == OuterViewportScrollLayer()) &&
+ InnerViewportScrollLayer()->MaxScrollOffset().y() > 0) ||
+ scroll_delta.y() < 0);
for (LayerImpl* layer_impl = CurrentlyScrollingLayer();
layer_impl;
@@ -2170,12 +2372,20 @@ bool LayerTreeHostImpl::ScrollBy(gfx::Point viewport_point,
if (!layer_impl->scrollable())
continue;
- if (layer_impl == RootScrollLayer()) {
+ if (layer_impl == InnerViewportScrollLayer()) {
// Only allow bubble scrolling when the scroll is in the direction to make
// the top controls visible.
- if (consume_by_top_controls && layer_impl == RootScrollLayer()) {
- pending_delta = top_controls_manager_->ScrollBy(pending_delta);
- UpdateMaxScrollOffset();
+ gfx::Vector2dF applied_delta;
+ gfx::Vector2dF excess_delta;
+ if (consume_by_top_controls) {
+ excess_delta = top_controls_manager_->ScrollBy(pending_delta);
+ applied_delta = pending_delta - excess_delta;
+ pending_delta = excess_delta;
+ // Force updating of vertical adjust values if needed.
+ if (applied_delta.y() != 0) {
+ did_scroll_top_controls = true;
+ layer_impl->ScrollbarParametersDidChange();
+ }
}
// Track root layer deltas for reporting overscroll.
unused_root_delta = pending_delta;
@@ -2196,27 +2406,36 @@ bool LayerTreeHostImpl::ScrollBy(gfx::Point viewport_point,
applied_delta = ScrollLayerWithLocalDelta(layer_impl, pending_delta);
}
+ const float kEpsilon = 0.1f;
+ if (layer_impl == InnerViewportScrollLayer()) {
+ unused_root_delta.Subtract(applied_delta);
+ if (std::abs(unused_root_delta.x()) < kEpsilon)
+ unused_root_delta.set_x(0.0f);
+ if (std::abs(unused_root_delta.y()) < kEpsilon)
+ unused_root_delta.set_y(0.0f);
+ // Disable overscroll on axes which is impossible to scroll.
+ if (settings_.report_overscroll_only_for_scrollable_axes) {
+ if (std::abs(active_tree_->TotalMaxScrollOffset().x()) <= kEpsilon)
+ unused_root_delta.set_x(0.0f);
+ if (std::abs(active_tree_->TotalMaxScrollOffset().y()) <= kEpsilon)
+ unused_root_delta.set_y(0.0f);
+ }
+ }
+
// If the layer wasn't able to move, try the next one in the hierarchy.
- float move_threshold = 0.1f;
- bool did_move_layer_x = std::abs(applied_delta.x()) > move_threshold;
- bool did_move_layer_y = std::abs(applied_delta.y()) > move_threshold;
+ bool did_move_layer_x = std::abs(applied_delta.x()) > kEpsilon;
+ bool did_move_layer_y = std::abs(applied_delta.y()) > kEpsilon;
did_scroll_x |= did_move_layer_x;
did_scroll_y |= did_move_layer_y;
if (!did_move_layer_x && !did_move_layer_y) {
- if (!did_lock_scrolling_layer_)
+ // Scrolls should always bubble between the outer and inner viewports
+ if (should_bubble_scrolls_ || !did_lock_scrolling_layer_ ||
+ layer_impl == OuterViewportScrollLayer())
continue;
-
- if (should_bubble_scrolls_) {
- last_scroll_did_bubble_ = true;
- continue;
- }
-
- break;
+ else
+ break;
}
- if (layer_impl == RootScrollLayer())
- unused_root_delta.Subtract(applied_delta);
-
did_lock_scrolling_layer_ = true;
if (!should_bubble_scrolls_) {
active_tree_->SetCurrentlyScrollingLayer(layer_impl);
@@ -2242,8 +2461,8 @@ bool LayerTreeHostImpl::ScrollBy(gfx::Point viewport_point,
break;
}
- bool did_scroll = did_scroll_x || did_scroll_y;
- if (did_scroll) {
+ bool did_scroll_content = did_scroll_x || did_scroll_y;
+ if (did_scroll_content) {
client_->SetNeedsCommitOnImplThread();
SetNeedsRedraw();
client_->RenewTreePriority();
@@ -2256,22 +2475,19 @@ bool LayerTreeHostImpl::ScrollBy(gfx::Point viewport_point,
accumulated_root_overscroll_.set_y(0);
accumulated_root_overscroll_ += unused_root_delta;
- bool did_overscroll = !gfx::ToRoundedVector2d(unused_root_delta).IsZero();
+ bool did_overscroll = !unused_root_delta.IsZero();
if (did_overscroll && input_handler_client_) {
- DidOverscrollParams params;
- params.accumulated_overscroll = accumulated_root_overscroll_;
- params.latest_overscroll_delta = unused_root_delta;
- params.current_fling_velocity = current_fling_velocity_;
- input_handler_client_->DidOverscroll(params);
+ input_handler_client_->DidOverscroll(accumulated_root_overscroll_,
+ unused_root_delta);
}
- return did_scroll;
+ return did_scroll_content || did_scroll_top_controls;
}
// This implements scrolling by page as described here:
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms645601(v=vs.85).aspx#_win32_The_Mouse_Wheel
// for events with WHEEL_PAGESCROLL set.
-bool LayerTreeHostImpl::ScrollVerticallyByPage(gfx::Point viewport_point,
+bool LayerTreeHostImpl::ScrollVerticallyByPage(const gfx::Point& viewport_point,
ScrollDirection direction) {
DCHECK(wheel_scrolling_);
@@ -2281,10 +2497,10 @@ bool LayerTreeHostImpl::ScrollVerticallyByPage(gfx::Point viewport_point,
if (!layer_impl->scrollable())
continue;
- if (!layer_impl->vertical_scrollbar_layer())
+ if (!layer_impl->HasScrollbar(VERTICAL))
continue;
- float height = layer_impl->vertical_scrollbar_layer()->bounds().height();
+ float height = layer_impl->clip_height();
// These magical values match WebKit and are designed to scroll nearly the
// entire visible content height but leave a bit of overlap.
@@ -2319,20 +2535,20 @@ void LayerTreeHostImpl::SetRootLayerScrollOffsetDelegate(
void LayerTreeHostImpl::OnRootLayerDelegatedScrollOffsetChanged() {
DCHECK(root_layer_scroll_offset_delegate_ != NULL);
client_->SetNeedsCommitOnImplThread();
+ active_tree_->set_needs_update_draw_properties();
}
void LayerTreeHostImpl::ClearCurrentlyScrollingLayer() {
active_tree_->ClearCurrentlyScrollingLayer();
did_lock_scrolling_layer_ = false;
+ scroll_affects_scroll_handler_ = false;
accumulated_root_overscroll_ = gfx::Vector2dF();
- current_fling_velocity_ = gfx::Vector2dF();
}
void LayerTreeHostImpl::ScrollEnd() {
if (top_controls_manager_)
top_controls_manager_->ScrollEnd();
ClearCurrentlyScrollingLayer();
- StartScrollbarAnimation();
}
InputHandler::ScrollStatus LayerTreeHostImpl::FlingScrollBegin() {
@@ -2340,24 +2556,24 @@ InputHandler::ScrollStatus LayerTreeHostImpl::FlingScrollBegin() {
return ScrollIgnored;
if (settings_.ignore_root_layer_flings &&
- active_tree_->CurrentlyScrollingLayer() ==
- active_tree_->RootScrollLayer()) {
+ (active_tree_->CurrentlyScrollingLayer() == InnerViewportScrollLayer() ||
+ active_tree_->CurrentlyScrollingLayer() == OuterViewportScrollLayer())) {
ClearCurrentlyScrollingLayer();
return ScrollIgnored;
}
- if (!wheel_scrolling_)
- should_bubble_scrolls_ = last_scroll_did_bubble_;
+ if (!wheel_scrolling_) {
+ // Allow the fling to lock to the first layer that moves after the initial
+ // fling |ScrollBy()| event.
+ did_lock_scrolling_layer_ = false;
+ should_bubble_scrolls_ = false;
+ }
return ScrollStarted;
}
-void LayerTreeHostImpl::NotifyCurrentFlingVelocity(gfx::Vector2dF velocity) {
- current_fling_velocity_ = velocity;
-}
-
float LayerTreeHostImpl::DeviceSpaceDistanceToLayer(
- gfx::PointF device_viewport_point,
+ const gfx::PointF& device_viewport_point,
LayerImpl* layer_impl) {
if (!layer_impl)
return std::numeric_limits<float>::max();
@@ -2373,16 +2589,11 @@ float LayerTreeHostImpl::DeviceSpaceDistanceToLayer(
device_viewport_point);
}
-void LayerTreeHostImpl::MouseMoveAt(gfx::Point viewport_point) {
- if (!EnsureRenderSurfaceLayerList())
- return;
-
+void LayerTreeHostImpl::MouseMoveAt(const gfx::Point& viewport_point) {
gfx::PointF device_viewport_point = gfx::ScalePoint(viewport_point,
device_scale_factor_);
-
- LayerImpl* layer_impl = LayerTreeHostCommon::FindLayerThatIsHitByPoint(
- device_viewport_point,
- active_tree_->RenderSurfaceLayerList());
+ LayerImpl* layer_impl =
+ active_tree_->FindLayerThatIsHitByPoint(device_viewport_point);
if (HandleMouseOverScrollbar(layer_impl, device_viewport_point))
return;
@@ -2390,20 +2601,24 @@ void LayerTreeHostImpl::MouseMoveAt(gfx::Point viewport_point) {
LayerImpl* scroll_layer_impl = active_tree_->LayerById(
scroll_layer_id_when_mouse_over_scrollbar_);
+ // The check for a null scroll_layer_impl below was added to see if it will
+ // eliminate the crashes described in http://crbug.com/326635.
+ // TODO(wjmaclean) Add a unit test if this fixes the crashes.
ScrollbarAnimationController* animation_controller =
- scroll_layer_impl->scrollbar_animation_controller();
- if (animation_controller) {
- animation_controller->DidMouseMoveOffScrollbar(
- CurrentPhysicalTimeTicks());
- StartScrollbarAnimation();
- }
+ scroll_layer_impl ? scroll_layer_impl->scrollbar_animation_controller()
+ : NULL;
+ if (animation_controller)
+ animation_controller->DidMouseMoveOffScrollbar();
scroll_layer_id_when_mouse_over_scrollbar_ = 0;
}
bool scroll_on_main_thread = false;
- LayerImpl* scroll_layer_impl = FindScrollLayerForDeviceViewportPoint(
- device_viewport_point, InputHandler::Gesture, layer_impl,
- &scroll_on_main_thread);
+ LayerImpl* scroll_layer_impl =
+ FindScrollLayerForDeviceViewportPoint(device_viewport_point,
+ InputHandler::Gesture,
+ layer_impl,
+ &scroll_on_main_thread,
+ NULL);
if (scroll_on_main_thread || !scroll_layer_impl)
return;
@@ -2412,30 +2627,28 @@ void LayerTreeHostImpl::MouseMoveAt(gfx::Point viewport_point) {
if (!animation_controller)
return;
- float distance_to_scrollbar = std::min(
- DeviceSpaceDistanceToLayer(device_viewport_point,
- scroll_layer_impl->horizontal_scrollbar_layer()),
- DeviceSpaceDistanceToLayer(device_viewport_point,
- scroll_layer_impl->vertical_scrollbar_layer()));
+ // TODO(wjmaclean) Is it ok to choose distance from more than two scrollbars?
+ float distance_to_scrollbar = std::numeric_limits<float>::max();
+ for (LayerImpl::ScrollbarSet::iterator it =
+ scroll_layer_impl->scrollbars()->begin();
+ it != scroll_layer_impl->scrollbars()->end();
+ ++it)
+ distance_to_scrollbar =
+ std::min(distance_to_scrollbar,
+ DeviceSpaceDistanceToLayer(device_viewport_point, *it));
- bool should_animate = animation_controller->DidMouseMoveNear(
- CurrentPhysicalTimeTicks(), distance_to_scrollbar / device_scale_factor_);
- if (should_animate)
- StartScrollbarAnimation();
+ animation_controller->DidMouseMoveNear(distance_to_scrollbar /
+ device_scale_factor_);
}
bool LayerTreeHostImpl::HandleMouseOverScrollbar(LayerImpl* layer_impl,
- gfx::PointF device_viewport_point) {
+ const gfx::PointF& device_viewport_point) {
if (layer_impl && layer_impl->ToScrollbarLayer()) {
int scroll_layer_id = layer_impl->ToScrollbarLayer()->ScrollLayerId();
layer_impl = active_tree_->LayerById(scroll_layer_id);
if (layer_impl && layer_impl->scrollbar_animation_controller()) {
scroll_layer_id_when_mouse_over_scrollbar_ = scroll_layer_id;
- bool should_animate =
- layer_impl->scrollbar_animation_controller()->DidMouseMoveNear(
- CurrentPhysicalTimeTicks(), 0);
- if (should_animate)
- StartScrollbarAnimation();
+ layer_impl->scrollbar_animation_controller()->DidMouseMoveNear(0);
} else {
scroll_layer_id_when_mouse_over_scrollbar_ = 0;
}
@@ -2451,17 +2664,28 @@ void LayerTreeHostImpl::PinchGestureBegin() {
previous_pinch_anchor_ = gfx::Point();
client_->RenewTreePriority();
pinch_gesture_end_should_clear_scrolling_layer_ = !CurrentlyScrollingLayer();
- active_tree_->SetCurrentlyScrollingLayer(RootScrollLayer());
+ if (active_tree_->OuterViewportScrollLayer()) {
+ active_tree_->SetCurrentlyScrollingLayer(
+ active_tree_->OuterViewportScrollLayer());
+ } else {
+ active_tree_->SetCurrentlyScrollingLayer(
+ active_tree_->InnerViewportScrollLayer());
+ }
if (top_controls_manager_)
top_controls_manager_->PinchBegin();
}
void LayerTreeHostImpl::PinchGestureUpdate(float magnify_delta,
- gfx::Point anchor) {
+ const gfx::Point& anchor) {
+ if (!InnerViewportScrollLayer())
+ return;
+
TRACE_EVENT0("cc", "LayerTreeHostImpl::PinchGestureUpdate");
- if (!RootScrollLayer())
- return;
+ // For a moment the scroll offset ends up being outside of the max range. This
+ // confuses the delegate so we switch it off till after we're done processing
+ // the pinch update.
+ active_tree_->SetRootLayerScrollOffsetDelegate(NULL);
// Keep the center-of-pinch anchor specified by (x, y) in a stable
// position over the course of the magnify.
@@ -2477,8 +2701,27 @@ void LayerTreeHostImpl::PinchGestureUpdate(float magnify_delta,
previous_pinch_anchor_ = anchor;
move.Scale(1 / active_tree_->page_scale_factor());
+ // If clamping the inner viewport scroll offset causes a change, it should
+ // be accounted for from the intended move.
+ move -= InnerViewportScrollLayer()->ClampScrollToMaxScrollOffset();
- RootScrollLayer()->ScrollBy(move);
+ // We manually manage the bubbling behaviour here as it is different to that
+ // implemented in LayerTreeHostImpl::ScrollBy(). Specifically:
+ // 1) we want to explicit limit the bubbling to the outer/inner viewports,
+ // 2) we don't want the directional limitations on the unused parts that
+ // ScrollBy() implements, and
+ // 3) pinching should not engage the top controls manager.
+ gfx::Vector2dF unused = OuterViewportScrollLayer()
+ ? OuterViewportScrollLayer()->ScrollBy(move)
+ : move;
+
+ if (!unused.IsZero()) {
+ InnerViewportScrollLayer()->ScrollBy(unused);
+ InnerViewportScrollLayer()->ClampScrollToMaxScrollOffset();
+ }
+
+ active_tree_->SetRootLayerScrollOffsetDelegate(
+ root_layer_scroll_offset_delegate_);
client_->SetNeedsCommitOnImplThread();
SetNeedsRedraw();
@@ -2529,13 +2772,51 @@ void LayerTreeHostImpl::SetFullRootLayerDamage() {
SetViewportDamage(gfx::Rect(DrawViewportSize()));
}
-void LayerTreeHostImpl::AnimatePageScale(base::TimeTicks time) {
- if (!page_scale_animation_ || !RootScrollLayer())
+void LayerTreeHostImpl::RunOnDemandRasterTask(Task* on_demand_raster_task) {
+ DCHECK(on_demand_task_graph_runner_);
+
+ // Construct a task graph that contains this single raster task.
+ TaskGraph graph;
+ graph.nodes.push_back(
+ TaskGraph::Node(on_demand_raster_task,
+ RasterWorkerPool::kOnDemandRasterTaskPriority,
+ 0u));
+
+ // Schedule task and wait for task graph runner to finish running it.
+ on_demand_task_graph_runner_->ScheduleTasks(on_demand_task_namespace_,
+ &graph);
+
+ if (on_demand_task_graph_runner_ == &synchronous_task_graph_runner_)
+ on_demand_task_graph_runner_->RunUntilIdle();
+
+ on_demand_task_graph_runner_->WaitForTasksToFinishRunning(
+ on_demand_task_namespace_);
+
+ // Collect task now that it has finished running.
+ Task::Vector completed_tasks;
+ on_demand_task_graph_runner_->CollectCompletedTasks(on_demand_task_namespace_,
+ &completed_tasks);
+ DCHECK_EQ(1u, completed_tasks.size());
+ DCHECK_EQ(completed_tasks[0], on_demand_raster_task);
+}
+
+void LayerTreeHostImpl::ScrollViewportBy(gfx::Vector2dF scroll_delta) {
+ DCHECK(InnerViewportScrollLayer());
+ LayerImpl* scroll_layer = OuterViewportScrollLayer()
+ ? OuterViewportScrollLayer()
+ : InnerViewportScrollLayer();
+
+ gfx::Vector2dF unused_delta = scroll_layer->ScrollBy(scroll_delta);
+
+ if (!unused_delta.IsZero() && (scroll_layer == OuterViewportScrollLayer()))
+ InnerViewportScrollLayer()->ScrollBy(unused_delta);
+}
+
+void LayerTreeHostImpl::AnimatePageScale(base::TimeTicks monotonic_time) {
+ if (!page_scale_animation_)
return;
- double monotonic_time = (time - base::TimeTicks()).InSecondsF();
- gfx::Vector2dF scroll_total = RootScrollLayer()->scroll_offset() +
- RootScrollLayer()->ScrollDelta();
+ gfx::Vector2dF scroll_total = active_tree_->TotalScrollOffset();
if (!page_scale_animation_->IsAnimationStarted())
page_scale_animation_->StartAnimation(monotonic_time);
@@ -2546,52 +2827,52 @@ void LayerTreeHostImpl::AnimatePageScale(base::TimeTicks time) {
gfx::Vector2dF next_scroll =
page_scale_animation_->ScrollOffsetAtTime(monotonic_time);
- RootScrollLayer()->ScrollBy(next_scroll - scroll_total);
+ ScrollViewportBy(next_scroll - scroll_total);
SetNeedsRedraw();
if (page_scale_animation_->IsAnimationCompleteAtTime(monotonic_time)) {
page_scale_animation_.reset();
client_->SetNeedsCommitOnImplThread();
client_->RenewTreePriority();
+ } else {
+ SetNeedsAnimate();
}
}
void LayerTreeHostImpl::AnimateTopControls(base::TimeTicks time) {
- if (!top_controls_manager_ || !RootScrollLayer())
+ if (!top_controls_manager_ || !top_controls_manager_->animation())
return;
gfx::Vector2dF scroll = top_controls_manager_->Animate(time);
- UpdateMaxScrollOffset();
- if (RootScrollLayer()->TotalScrollOffset().y() == 0.f)
+ if (active_tree_->TotalScrollOffset().y() == 0.f)
return;
- RootScrollLayer()->ScrollBy(gfx::ScaleVector2d(
- scroll, 1.f / active_tree_->total_page_scale_factor()));
+ if (!scroll.IsZero()) {
+ ScrollViewportBy(gfx::ScaleVector2d(
+ scroll, 1.f / active_tree_->total_page_scale_factor()));
+ SetNeedsRedraw();
+ }
+ SetNeedsAnimate();
}
-void LayerTreeHostImpl::AnimateLayers(base::TimeTicks monotonic_time,
- base::Time wall_clock_time) {
+void LayerTreeHostImpl::AnimateLayers(base::TimeTicks monotonic_time) {
if (!settings_.accelerated_animation_enabled ||
- animation_registrar_->active_animation_controllers().empty() ||
+ !needs_animate_layers() ||
!active_tree_->root_layer())
return;
TRACE_EVENT0("cc", "LayerTreeHostImpl::AnimateLayers");
-
- last_animation_time_ = wall_clock_time;
- double monotonic_seconds = (monotonic_time - base::TimeTicks()).InSecondsF();
-
AnimationRegistrar::AnimationControllerMap copy =
animation_registrar_->active_animation_controllers();
for (AnimationRegistrar::AnimationControllerMap::iterator iter = copy.begin();
iter != copy.end();
++iter)
- (*iter).second->Animate(monotonic_seconds);
+ (*iter).second->Animate(monotonic_time);
- SetNeedsRedraw();
+ SetNeedsAnimate();
}
void LayerTreeHostImpl::UpdateAnimationState(bool start_ready_animations) {
if (!settings_.accelerated_animation_enabled ||
- animation_registrar_->active_animation_controllers().empty() ||
+ !needs_animate_layers() ||
!active_tree_->root_layer())
return;
@@ -2606,40 +2887,28 @@ void LayerTreeHostImpl::UpdateAnimationState(bool start_ready_animations) {
(*iter).second->UpdateState(start_ready_animations, events.get());
if (!events->empty()) {
- client_->PostAnimationEventsToMainThreadOnImplThread(events.Pass(),
- last_animation_time_);
+ client_->PostAnimationEventsToMainThreadOnImplThread(events.Pass());
}
-}
-base::TimeDelta LayerTreeHostImpl::LowFrequencyAnimationInterval() const {
- return base::TimeDelta::FromSeconds(1);
+ SetNeedsAnimate();
}
-void LayerTreeHostImpl::SendReleaseResourcesRecursive(LayerImpl* current) {
- DCHECK(current);
- // TODO(boliu): Rename DidLoseOutputSurface to ReleaseResources.
- current->DidLoseOutputSurface();
- if (current->mask_layer())
- SendReleaseResourcesRecursive(current->mask_layer());
- if (current->replica_layer())
- SendReleaseResourcesRecursive(current->replica_layer());
- for (size_t i = 0; i < current->children().size(); ++i)
- SendReleaseResourcesRecursive(current->children()[i]);
-}
-
-void LayerTreeHostImpl::SetOffscreenContextProvider(
- const scoped_refptr<ContextProvider>& offscreen_context_provider) {
- if (!offscreen_context_provider.get()) {
- offscreen_context_provider_ = NULL;
+void LayerTreeHostImpl::ActivateAnimations() {
+ if (!settings_.accelerated_animation_enabled || !needs_animate_layers() ||
+ !active_tree_->root_layer())
return;
- }
- if (!offscreen_context_provider->BindToCurrentThread()) {
- offscreen_context_provider_ = NULL;
- return;
- }
+ TRACE_EVENT0("cc", "LayerTreeHostImpl::ActivateAnimations");
+ AnimationRegistrar::AnimationControllerMap copy =
+ animation_registrar_->active_animation_controllers();
+ for (AnimationRegistrar::AnimationControllerMap::iterator iter = copy.begin();
+ iter != copy.end();
+ ++iter)
+ (*iter).second->ActivateAnimations();
+}
- offscreen_context_provider_ = offscreen_context_provider;
+base::TimeDelta LayerTreeHostImpl::LowFrequencyAnimationInterval() const {
+ return base::TimeDelta::FromSeconds(1);
}
std::string LayerTreeHostImpl::LayerTreeAsJson() const {
@@ -2656,35 +2925,6 @@ int LayerTreeHostImpl::SourceAnimationFrameNumber() const {
return fps_counter_->current_frame_number();
}
-void LayerTreeHostImpl::SendManagedMemoryStats(
- size_t memory_visible_bytes,
- size_t memory_visible_and_nearby_bytes,
- size_t memory_use_bytes) {
- if (!renderer_)
- return;
-
- // Round the numbers being sent up to the next 8MB, to throttle the rate
- // at which we spam the GPU process.
- static const size_t rounding_step = 8 * 1024 * 1024;
- memory_visible_bytes = RoundUp(memory_visible_bytes, rounding_step);
- memory_visible_and_nearby_bytes = RoundUp(memory_visible_and_nearby_bytes,
- rounding_step);
- memory_use_bytes = RoundUp(memory_use_bytes, rounding_step);
- if (last_sent_memory_visible_bytes_ == memory_visible_bytes &&
- last_sent_memory_visible_and_nearby_bytes_ ==
- memory_visible_and_nearby_bytes &&
- last_sent_memory_use_bytes_ == memory_use_bytes) {
- return;
- }
- last_sent_memory_visible_bytes_ = memory_visible_bytes;
- last_sent_memory_visible_and_nearby_bytes_ = memory_visible_and_nearby_bytes;
- last_sent_memory_use_bytes_ = memory_use_bytes;
-
- renderer_->SendManagedMemoryStats(last_sent_memory_visible_bytes_,
- last_sent_memory_visible_and_nearby_bytes_,
- last_sent_memory_use_bytes_);
-}
-
void LayerTreeHostImpl::AnimateScrollbars(base::TimeTicks time) {
AnimateScrollbarsRecursive(active_tree_->root_layer(), time);
}
@@ -2696,39 +2936,25 @@ void LayerTreeHostImpl::AnimateScrollbarsRecursive(LayerImpl* layer,
ScrollbarAnimationController* scrollbar_controller =
layer->scrollbar_animation_controller();
- if (scrollbar_controller && scrollbar_controller->Animate(time)) {
- TRACE_EVENT_INSTANT0(
- "cc", "LayerTreeHostImpl::SetNeedsRedraw due to AnimateScrollbars",
- TRACE_EVENT_SCOPE_THREAD);
- SetNeedsRedraw();
- }
+ if (scrollbar_controller)
+ scrollbar_controller->Animate(time);
for (size_t i = 0; i < layer->children().size(); ++i)
AnimateScrollbarsRecursive(layer->children()[i], time);
}
-void LayerTreeHostImpl::StartScrollbarAnimation() {
- TRACE_EVENT0("cc", "LayerTreeHostImpl::StartScrollbarAnimation");
- StartScrollbarAnimationRecursive(RootLayer(), CurrentPhysicalTimeTicks());
+void LayerTreeHostImpl::PostDelayedScrollbarFade(
+ const base::Closure& start_fade,
+ base::TimeDelta delay) {
+ client_->PostDelayedScrollbarFadeOnImplThread(start_fade, delay);
}
-void LayerTreeHostImpl::StartScrollbarAnimationRecursive(LayerImpl* layer,
- base::TimeTicks time) {
- if (!layer)
- return;
-
- ScrollbarAnimationController* scrollbar_controller =
- layer->scrollbar_animation_controller();
- if (scrollbar_controller && scrollbar_controller->IsAnimating()) {
- base::TimeDelta delay = scrollbar_controller->DelayBeforeStart(time);
- if (delay > base::TimeDelta())
- client_->RequestScrollbarAnimationOnImplThread(delay);
- else if (scrollbar_controller->Animate(time))
- SetNeedsRedraw();
- }
-
- for (size_t i = 0; i < layer->children().size(); ++i)
- StartScrollbarAnimationRecursive(layer->children()[i], time);
+void LayerTreeHostImpl::SetNeedsScrollbarAnimationFrame() {
+ TRACE_EVENT_INSTANT0(
+ "cc",
+ "LayerTreeHostImpl::SetNeedsRedraw due to scrollbar fade",
+ TRACE_EVENT_SCOPE_THREAD);
+ SetNeedsAnimate();
}
void LayerTreeHostImpl::SetTreePriority(TreePriority priority) {
@@ -2741,31 +2967,21 @@ void LayerTreeHostImpl::SetTreePriority(TreePriority priority) {
DidModifyTilePriorities();
}
-void LayerTreeHostImpl::ResetCurrentFrameTimeForNextFrame() {
- current_frame_timeticks_ = base::TimeTicks();
- current_frame_time_ = base::Time();
+void LayerTreeHostImpl::UpdateCurrentFrameTime() {
+ DCHECK(current_frame_timeticks_.is_null());
+ current_frame_timeticks_ = gfx::FrameTime::Now();
}
-void LayerTreeHostImpl::UpdateCurrentFrameTime(base::TimeTicks* ticks,
- base::Time* now) const {
- if (ticks->is_null()) {
- DCHECK(now->is_null());
- *ticks = CurrentPhysicalTimeTicks();
- *now = base::Time::Now();
- }
+void LayerTreeHostImpl::ResetCurrentFrameTimeForNextFrame() {
+ current_frame_timeticks_ = base::TimeTicks();
}
base::TimeTicks LayerTreeHostImpl::CurrentFrameTimeTicks() {
- UpdateCurrentFrameTime(&current_frame_timeticks_, &current_frame_time_);
- return current_frame_timeticks_;
-}
-
-base::Time LayerTreeHostImpl::CurrentFrameTime() {
- UpdateCurrentFrameTime(&current_frame_timeticks_, &current_frame_time_);
- return current_frame_time_;
-}
-
-base::TimeTicks LayerTreeHostImpl::CurrentPhysicalTimeTicks() const {
+ // Try to use the current frame time to keep animations non-jittery. But if
+ // we're not in a frame (because this is during an input event or a delayed
+ // task), fall back to physical time. This should still be monotonic.
+ if (!current_frame_timeticks_.is_null())
+ return current_frame_timeticks_;
return gfx::FrameTime::Now();
}
@@ -2924,4 +3140,17 @@ void LayerTreeHostImpl::NotifySwapPromiseMonitorsOfSetNeedsRedraw() {
(*it)->OnSetNeedsRedrawOnImpl();
}
+void LayerTreeHostImpl::RegisterPictureLayerImpl(PictureLayerImpl* layer) {
+ DCHECK(std::find(picture_layers_.begin(), picture_layers_.end(), layer) ==
+ picture_layers_.end());
+ picture_layers_.push_back(layer);
+}
+
+void LayerTreeHostImpl::UnregisterPictureLayerImpl(PictureLayerImpl* layer) {
+ std::vector<PictureLayerImpl*>::iterator it =
+ std::find(picture_layers_.begin(), picture_layers_.end(), layer);
+ DCHECK(it != picture_layers_.end());
+ picture_layers_.erase(it);
+}
+
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_host_impl.h b/chromium/cc/trees/layer_tree_host_impl.h
index 531384f6fdb..fe9afc219e6 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/time/time.h"
#include "cc/animation/animation_events.h"
#include "cc/animation/animation_registrar.h"
+#include "cc/animation/scrollbar_animation_controller.h"
#include "cc/base/cc_export.h"
#include "cc/debug/micro_benchmark_controller_impl.h"
#include "cc/input/input_handler.h"
@@ -30,6 +31,7 @@
#include "cc/quads/render_pass.h"
#include "cc/resources/resource_provider.h"
#include "cc/resources/tile_manager.h"
+#include "cc/scheduler/draw_result.h"
#include "skia/ext/refptr.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/rect.h"
@@ -43,45 +45,55 @@ class FrameRateCounter;
class LayerImpl;
class LayerTreeHostImplTimeSourceAdapter;
class LayerTreeImpl;
+class MemoryHistory;
class PageScaleAnimation;
class PaintTimeCounter;
-class MemoryHistory;
-class RenderingStatsInstrumentation;
+class PictureLayerImpl;
+class RasterWorkerPool;
class RenderPassDrawQuad;
+class RenderingStatsInstrumentation;
+class ResourcePool;
class ScrollbarLayerImplBase;
class TextureMailboxDeleter;
class TopControlsManager;
class UIResourceBitmap;
class UIResourceRequest;
-struct RendererCapabilities;
+struct RendererCapabilitiesImpl;
// LayerTreeHost->Proxy callback interface.
class LayerTreeHostImplClient {
public:
+ virtual void UpdateRendererCapabilitiesOnImplThread() = 0;
virtual void DidLoseOutputSurfaceOnImplThread() = 0;
+ virtual void CommitVSyncParameters(base::TimeTicks timebase,
+ base::TimeDelta interval) = 0;
+ virtual void SetEstimatedParentDrawTime(base::TimeDelta draw_time) = 0;
+ virtual void SetMaxSwapsPendingOnImplThread(int max) = 0;
virtual void DidSwapBuffersOnImplThread() = 0;
- virtual void OnSwapBuffersCompleteOnImplThread() = 0;
- virtual void BeginImplFrame(const BeginFrameArgs& args) = 0;
+ virtual void DidSwapBuffersCompleteOnImplThread() = 0;
+ virtual void BeginFrame(const BeginFrameArgs& args) = 0;
virtual void OnCanDrawStateChanged(bool can_draw) = 0;
virtual void NotifyReadyToActivate() = 0;
- // Please call these 2 functions through
- // LayerTreeHostImpl's SetNeedsRedraw() and SetNeedsRedrawRect().
+ // Please call these 3 functions through
+ // LayerTreeHostImpl's SetNeedsRedraw(), SetNeedsRedrawRect() and
+ // SetNeedsAnimate().
virtual void SetNeedsRedrawOnImplThread() = 0;
- virtual void SetNeedsRedrawRectOnImplThread(gfx::Rect damage_rect) = 0;
+ virtual void SetNeedsRedrawRectOnImplThread(const gfx::Rect& damage_rect) = 0;
+ virtual void SetNeedsAnimateOnImplThread() = 0;
virtual void DidInitializeVisibleTileOnImplThread() = 0;
virtual void SetNeedsCommitOnImplThread() = 0;
virtual void SetNeedsManageTilesOnImplThread() = 0;
virtual void PostAnimationEventsToMainThreadOnImplThread(
- scoped_ptr<AnimationEventsVector> events,
- base::Time wall_clock_time) = 0;
+ scoped_ptr<AnimationEventsVector> events) = 0;
// Returns true if resources were deleted by this call.
virtual bool ReduceContentsTextureMemoryOnImplThread(
size_t limit_bytes,
int priority_cutoff) = 0;
- virtual void SendManagedMemoryStats() = 0;
virtual bool IsInsideDraw() = 0;
virtual void RenewTreePriority() = 0;
- virtual void RequestScrollbarAnimationOnImplThread(base::TimeDelta delay) = 0;
+ virtual void PostDelayedScrollbarFadeOnImplThread(
+ const base::Closure& start_fade,
+ base::TimeDelta delay) = 0;
virtual void DidActivatePendingTree() = 0;
virtual void DidManageTiles() = 0;
@@ -97,6 +109,7 @@ class CC_EXPORT LayerTreeHostImpl
public TileManagerClient,
public OutputSurfaceClient,
public TopControlsManagerClient,
+ public ScrollbarAnimationControllerClient,
public base::SupportsWeakPtr<LayerTreeHostImpl> {
public:
static scoped_ptr<LayerTreeHostImpl> Create(
@@ -111,29 +124,32 @@ class CC_EXPORT LayerTreeHostImpl
// InputHandler implementation
virtual void BindToClient(InputHandlerClient* client) OVERRIDE;
virtual InputHandler::ScrollStatus ScrollBegin(
- gfx::Point viewport_point,
+ const gfx::Point& viewport_point,
InputHandler::ScrollInputType type) OVERRIDE;
- virtual bool ScrollBy(gfx::Point viewport_point,
- gfx::Vector2dF scroll_delta) OVERRIDE;
- virtual bool ScrollVerticallyByPage(gfx::Point viewport_point,
+ virtual bool ScrollBy(const gfx::Point& viewport_point,
+ const gfx::Vector2dF& scroll_delta) OVERRIDE;
+ virtual bool ScrollVerticallyByPage(const gfx::Point& viewport_point,
ScrollDirection direction) OVERRIDE;
virtual void SetRootLayerScrollOffsetDelegate(
LayerScrollOffsetDelegate* root_layer_scroll_offset_delegate) OVERRIDE;
virtual void OnRootLayerDelegatedScrollOffsetChanged() OVERRIDE;
virtual void ScrollEnd() OVERRIDE;
virtual InputHandler::ScrollStatus FlingScrollBegin() OVERRIDE;
- virtual void NotifyCurrentFlingVelocity(gfx::Vector2dF velocity) OVERRIDE;
- virtual void MouseMoveAt(gfx::Point viewport_point) OVERRIDE;
+ virtual void MouseMoveAt(const gfx::Point& viewport_point) OVERRIDE;
virtual void PinchGestureBegin() OVERRIDE;
virtual void PinchGestureUpdate(float magnify_delta,
- gfx::Point anchor) OVERRIDE;
+ const gfx::Point& anchor) OVERRIDE;
virtual void PinchGestureEnd() OVERRIDE;
- virtual void StartPageScaleAnimation(gfx::Vector2d target_offset,
+ virtual void StartPageScaleAnimation(const gfx::Vector2d& target_offset,
bool anchor_point,
float page_scale,
base::TimeDelta duration) OVERRIDE;
- virtual void ScheduleAnimation() OVERRIDE;
- virtual bool HaveTouchEventHandlersAt(gfx::Point viewport_port) OVERRIDE;
+ virtual void SetNeedsAnimate() OVERRIDE;
+ virtual bool IsCurrentlyScrollingLayerAt(
+ const gfx::Point& viewport_point,
+ InputHandler::ScrollInputType type) OVERRIDE;
+ virtual bool HaveTouchEventHandlersAt(
+ const gfx::Point& viewport_port) OVERRIDE;
virtual scoped_ptr<SwapPromiseMonitor> CreateLatencyInfoSwapPromiseMonitor(
ui::LatencyInfo* latency) OVERRIDE;
@@ -141,8 +157,6 @@ class CC_EXPORT LayerTreeHostImpl
virtual void DidChangeTopControlsPosition() OVERRIDE;
virtual bool HaveRootScrollLayer() const OVERRIDE;
- void StartScrollbarAnimation();
-
struct CC_EXPORT FrameData : public RenderPassSink {
FrameData();
virtual ~FrameData();
@@ -164,22 +178,21 @@ class CC_EXPORT LayerTreeHostImpl
virtual void BeginMainFrameAborted(bool did_handle);
virtual void BeginCommit();
virtual void CommitComplete();
- virtual void Animate(base::TimeTicks monotonic_time,
- base::Time wall_clock_time);
+ virtual void Animate(base::TimeTicks monotonic_time);
virtual void UpdateAnimationState(bool start_ready_animations);
+ void ActivateAnimations();
void MainThreadHasStoppedFlinging();
void UpdateBackgroundAnimateTicking(bool should_background_tick);
void DidAnimateScrollOffset();
- void SetViewportDamage(gfx::Rect damage_rect);
+ void SetViewportDamage(const gfx::Rect& damage_rect);
virtual void ManageTiles();
- // Returns false if problems occured preparing the frame, and we should try
- // to avoid displaying the frame. If PrepareToDraw is called, DidDrawAllLayers
- // must also be called, regardless of whether DrawLayers is called between the
- // two.
- virtual bool PrepareToDraw(FrameData* frame,
- gfx::Rect device_viewport_damage_rect);
+ // Returns DRAW_SUCCESS unless problems occured preparing the frame, and we
+ // should try to avoid displaying the frame. If PrepareToDraw is called,
+ // DidDrawAllLayers must also be called, regardless of whether DrawLayers is
+ // called between the two.
+ virtual DrawResult PrepareToDraw(FrameData* frame);
virtual void DrawLayers(FrameData* frame, base::TimeTicks frame_begin_time);
// Must be called if and only if PrepareToDraw was called.
void DidDrawAllLayers(const FrameData& frame);
@@ -197,6 +210,9 @@ class CC_EXPORT LayerTreeHostImpl
// This allows us to inject DidInitializeVisibleTile events for testing.
void DidInitializeVisibleTileForTesting();
+ // Resets all of the trees to an empty state.
+ void ResetTreesForTesting();
+
bool device_viewport_valid_for_tile_management() const {
return device_viewport_valid_for_tile_management_;
}
@@ -209,27 +225,37 @@ class CC_EXPORT LayerTreeHostImpl
// excludes the URL bar and non-overlay scrollbars and is in DIP (and
// invariant relative to page scale).
gfx::SizeF UnscaledScrollableViewportSize() const;
+ float VerticalAdjust() const;
// RendererClient implementation.
virtual void SetFullRootLayerDamage() OVERRIDE;
+ virtual void RunOnDemandRasterTask(Task* on_demand_raster_task) OVERRIDE;
// TileManagerClient implementation.
+ virtual const std::vector<PictureLayerImpl*>& GetPictureLayers() OVERRIDE;
virtual void NotifyReadyToActivate() OVERRIDE;
+ virtual void NotifyTileStateChanged(const Tile* tile) OVERRIDE;
+
+ // ScrollbarAnimationControllerClient implementation.
+ virtual void PostDelayedScrollbarFade(const base::Closure& start_fade,
+ base::TimeDelta delay) OVERRIDE;
+ virtual void SetNeedsScrollbarAnimationFrame() OVERRIDE;
// OutputSurfaceClient implementation.
- virtual bool DeferredInitialize(
- scoped_refptr<ContextProvider> offscreen_context_provider) OVERRIDE;
+ virtual void DeferredInitialize() OVERRIDE;
virtual void ReleaseGL() OVERRIDE;
- virtual void SetNeedsRedrawRect(gfx::Rect rect) OVERRIDE;
- virtual void BeginImplFrame(const BeginFrameArgs& args) OVERRIDE;
+ virtual void CommitVSyncParameters(base::TimeTicks timebase,
+ base::TimeDelta interval) OVERRIDE;
+ virtual void SetNeedsRedrawRect(const gfx::Rect& rect) OVERRIDE;
+ virtual void BeginFrame(const BeginFrameArgs& args) OVERRIDE;
virtual void SetExternalDrawConstraints(
const gfx::Transform& transform,
- gfx::Rect viewport,
- gfx::Rect clip,
+ const gfx::Rect& viewport,
+ const gfx::Rect& clip,
bool valid_for_tile_management) OVERRIDE;
virtual void DidLoseOutputSurface() OVERRIDE;
virtual void DidSwapBuffers() OVERRIDE;
- virtual void OnSwapBuffersComplete() OVERRIDE;
+ virtual void DidSwapBuffersComplete() OVERRIDE;
virtual void ReclaimResources(const CompositorFrameAck* ack) OVERRIDE;
virtual void SetMemoryPolicy(const ManagedMemoryPolicy& policy) OVERRIDE;
virtual void SetTreeActivationCallback(const base::Closure& callback)
@@ -239,15 +265,10 @@ class CC_EXPORT LayerTreeHostImpl
void OnCanDrawStateChangedForTree();
// Implementation.
+ int id() const { return id_; }
bool CanDraw() const;
OutputSurface* output_surface() const { return output_surface_.get(); }
- void SetOffscreenContextProvider(
- const scoped_refptr<ContextProvider>& offscreen_context_provider);
- ContextProvider* offscreen_context_provider() const {
- return offscreen_context_provider_.get();
- }
-
std::string LayerTreeAsJson() const;
void FinishAllRendering();
@@ -256,32 +277,48 @@ class CC_EXPORT LayerTreeHostImpl
virtual bool InitializeRenderer(scoped_ptr<OutputSurface> output_surface);
bool IsContextLost();
TileManager* tile_manager() { return tile_manager_.get(); }
+ void SetUseGpuRasterization(bool use_gpu);
+ bool use_gpu_rasterization() const { return use_gpu_rasterization_; }
+ bool create_low_res_tiling() const {
+ return settings_.create_low_res_tiling && !use_gpu_rasterization_;
+ }
+ ResourcePool* resource_pool() { return resource_pool_.get(); }
Renderer* renderer() { return renderer_.get(); }
- const RendererCapabilities& GetRendererCapabilities() const;
+ const RendererCapabilitiesImpl& GetRendererCapabilities() const;
virtual bool SwapBuffers(const FrameData& frame);
- void SetNeedsBeginImplFrame(bool enable);
+ void SetNeedsBeginFrame(bool enable);
+ virtual void WillBeginImplFrame(const BeginFrameArgs& args);
void DidModifyTilePriorities();
- void Readback(void* pixels, gfx::Rect rect_in_device_viewport);
-
LayerTreeImpl* active_tree() { return active_tree_.get(); }
const LayerTreeImpl* active_tree() const { return active_tree_.get(); }
LayerTreeImpl* pending_tree() { return pending_tree_.get(); }
const LayerTreeImpl* pending_tree() const { return pending_tree_.get(); }
const LayerTreeImpl* recycle_tree() const { return recycle_tree_.get(); }
+ // Returns the tree LTH synchronizes with.
+ LayerTreeImpl* sync_tree() {
+ // In impl-side painting, synchronize to the pending tree so that it has
+ // time to raster before being displayed.
+ return settings_.impl_side_painting ? pending_tree_.get()
+ : active_tree_.get();
+ }
virtual void CreatePendingTree();
virtual void UpdateVisibleTiles();
virtual void ActivatePendingTree();
// Shortcuts to layers on the active tree.
LayerImpl* RootLayer() const;
- LayerImpl* RootScrollLayer() const;
+ LayerImpl* InnerViewportScrollLayer() const;
+ LayerImpl* OuterViewportScrollLayer() const;
LayerImpl* CurrentlyScrollingLayer() const;
- int scroll_layer_id_when_mouse_over_scrollbar() {
+ int scroll_layer_id_when_mouse_over_scrollbar() const {
return scroll_layer_id_when_mouse_over_scrollbar_;
}
+ bool scroll_affects_scroll_handler() const {
+ return scroll_affects_scroll_handler_;
+ }
bool IsCurrentlyScrolling() const;
@@ -296,13 +333,14 @@ class CC_EXPORT LayerTreeHostImpl
size_t memory_allocation_limit_bytes() const;
int memory_allocation_priority_cutoff() const;
- void SetViewportSize(gfx::Size device_viewport_size);
+ void SetViewportSize(const gfx::Size& device_viewport_size);
+ gfx::Size device_viewport_size() const { return device_viewport_size_; }
void SetOverdrawBottomHeight(float overdraw_bottom_height);
float overdraw_bottom_height() const { return overdraw_bottom_height_; }
void SetOverhangUIResource(UIResourceId overhang_ui_resource_id,
- gfx::Size overhang_ui_resource_size);
+ const gfx::Size& overhang_ui_resource_size);
void SetDeviceScaleFactor(float device_scale_factor);
float device_scale_factor() const { return device_scale_factor_; }
@@ -315,11 +353,6 @@ class CC_EXPORT LayerTreeHostImpl
return !animation_registrar_->active_animation_controllers().empty();
}
- void SendManagedMemoryStats(
- size_t memory_visible_bytes,
- size_t memory_visible_and_nearby_bytes,
- size_t memory_use_bytes);
-
void set_max_memory_needed_bytes(size_t bytes) {
max_memory_needed_bytes_ = bytes;
}
@@ -342,6 +375,9 @@ class CC_EXPORT LayerTreeHostImpl
TopControlsManager* top_controls_manager() {
return top_controls_manager_.get();
}
+ const GlobalStateThatImpactsTilePriority& global_tile_state() {
+ return global_tile_state_;
+ }
Proxy* proxy() const { return proxy_; }
@@ -353,7 +389,7 @@ class CC_EXPORT LayerTreeHostImpl
const LayerTreeDebugState& debug_state() const { return debug_state_; }
class CC_EXPORT CullRenderPassesWithNoQuads {
- public:
+ public:
bool ShouldRemoveRenderPass(const RenderPassDrawQuad& quad,
const FrameData& frame) const;
@@ -372,19 +408,19 @@ class CC_EXPORT LayerTreeHostImpl
gfx::Vector2dF accumulated_root_overscroll() const {
return accumulated_root_overscroll_;
}
- gfx::Vector2dF current_fling_velocity() const {
- return current_fling_velocity_;
- }
bool pinch_gesture_active() const { return pinch_gesture_active_; }
void SetTreePriority(TreePriority priority);
+ void UpdateCurrentFrameTime();
void ResetCurrentFrameTimeForNextFrame();
virtual base::TimeTicks CurrentFrameTimeTicks();
- base::Time CurrentFrameTime();
- virtual base::TimeTicks CurrentPhysicalTimeTicks() const;
+ // Expected time between two begin impl frame calls.
+ base::TimeDelta begin_impl_frame_interval() const {
+ return begin_impl_frame_interval_;
+ }
scoped_ptr<base::Value> AsValue() const { return AsValueWithFrame(NULL); }
scoped_ptr<base::Value> AsValueWithFrame(FrameData* frame) const;
@@ -426,6 +462,9 @@ class CC_EXPORT LayerTreeHostImpl
void InsertSwapPromiseMonitor(SwapPromiseMonitor* monitor);
void RemoveSwapPromiseMonitor(SwapPromiseMonitor* monitor);
+ void RegisterPictureLayerImpl(PictureLayerImpl* layer);
+ void UnregisterPictureLayerImpl(PictureLayerImpl* layer);
+
protected:
LayerTreeHostImpl(
const LayerTreeSettings& settings,
@@ -435,9 +474,11 @@ class CC_EXPORT LayerTreeHostImpl
SharedBitmapManager* manager,
int id);
+ gfx::SizeF ComputeInnerViewportContainerSize() const;
+ void UpdateInnerViewportContainerSize();
+
// Virtual for testing.
- virtual void AnimateLayers(base::TimeTicks monotonic_time,
- base::Time wall_clock_time);
+ virtual void AnimateLayers(base::TimeTicks monotonic_time);
// Virtual for testing.
virtual base::TimeDelta LowFrequencyAnimationInterval() const;
@@ -453,16 +494,16 @@ class CC_EXPORT LayerTreeHostImpl
Proxy* proxy_;
private:
- void CreateAndSetRenderer(
- OutputSurface* output_surface,
- ResourceProvider* resource_provider,
- bool skip_gl_renderer);
- void CreateAndSetTileManager(ResourceProvider* resource_provider,
- ContextProvider* context_provider,
- bool using_map_image);
+ void CreateAndSetRenderer();
+ void CreateAndSetTileManager();
+ void DestroyTileManager();
void ReleaseTreeResources();
void EnforceZeroBudget(bool zero_budget);
+ bool UseZeroCopyTextureUpload() const;
+ bool UseOneCopyTextureUpload() const;
+
+ void ScrollViewportBy(gfx::Vector2dF scroll_delta);
void AnimatePageScale(base::TimeTicks monotonic_time);
void AnimateScrollbars(base::TimeTicks monotonic_time);
void AnimateTopControls(base::TimeTicks monotonic_time);
@@ -470,41 +511,37 @@ class CC_EXPORT LayerTreeHostImpl
gfx::Vector2dF ScrollLayerWithViewportSpaceDelta(
LayerImpl* layer_impl,
float scale_from_viewport_to_screen_space,
- gfx::PointF viewport_point,
- gfx::Vector2dF viewport_delta);
+ const gfx::PointF& viewport_point,
+ const gfx::Vector2dF& viewport_delta);
- void UpdateMaxScrollOffset();
void TrackDamageForAllSurfaces(
LayerImpl* root_draw_layer,
const LayerImplList& render_surface_layer_list);
void UpdateTileManagerMemoryPolicy(const ManagedMemoryPolicy& policy);
- // Returns false if the frame should not be displayed. This function should
- // only be called from PrepareToDraw, as DidDrawAllLayers must be called
- // if this helper function is called.
- bool CalculateRenderPasses(FrameData* frame);
+ // This function should only be called from PrepareToDraw, as DidDrawAllLayers
+ // must be called if this helper function is called. Returns DRAW_SUCCESS if
+ // the frame should be drawn.
+ DrawResult CalculateRenderPasses(FrameData* frame);
- void SendReleaseResourcesRecursive(LayerImpl* current);
- bool EnsureRenderSurfaceLayerList();
void ClearCurrentlyScrollingLayer();
bool HandleMouseOverScrollbar(LayerImpl* layer_impl,
- gfx::PointF device_viewport_point);
+ const gfx::PointF& device_viewport_point);
void AnimateScrollbarsRecursive(LayerImpl* layer,
base::TimeTicks time);
- void UpdateCurrentFrameTime(base::TimeTicks* ticks, base::Time* now) const;
-
LayerImpl* FindScrollLayerForDeviceViewportPoint(
- gfx::PointF device_viewport_point,
+ const gfx::PointF& device_viewport_point,
InputHandler::ScrollInputType type,
LayerImpl* layer_hit_by_point,
- bool* scroll_on_main_thread) const;
- float DeviceSpaceDistanceToLayer(gfx::PointF device_viewport_point,
+ bool* scroll_on_main_thread,
+ bool* optional_has_ancestor_scroll_handler) const;
+ float DeviceSpaceDistanceToLayer(const gfx::PointF& device_viewport_point,
LayerImpl* layer_impl);
- void StartScrollbarAnimationRecursive(LayerImpl* layer, base::TimeTicks time);
+ void StartScrollbarFadeRecursive(LayerImpl* layer);
void SetManagedMemoryPolicy(const ManagedMemoryPolicy& policy,
bool zero_budget);
void EnforceManagedMemoryPolicy(const ManagedMemoryPolicy& policy);
@@ -531,8 +568,16 @@ class CC_EXPORT LayerTreeHostImpl
// free rendering - see OutputSurface::ForcedDrawToSoftwareDevice().
scoped_ptr<ResourceProvider> resource_provider_;
scoped_ptr<TileManager> tile_manager_;
+ bool use_gpu_rasterization_;
+ scoped_ptr<RasterWorkerPool> raster_worker_pool_;
+ scoped_ptr<ResourcePool> resource_pool_;
+ scoped_ptr<ResourcePool> staging_resource_pool_;
scoped_ptr<Renderer> renderer_;
+ TaskGraphRunner synchronous_task_graph_runner_;
+ TaskGraphRunner* on_demand_task_graph_runner_;
+ NamespaceToken on_demand_task_namespace_;
+
GlobalStateThatImpactsTilePriority global_tile_state_;
// Tree currently being drawn.
@@ -549,8 +594,8 @@ class CC_EXPORT LayerTreeHostImpl
InputHandlerClient* input_handler_client_;
bool did_lock_scrolling_layer_;
bool should_bubble_scrolls_;
- bool last_scroll_did_bubble_;
bool wheel_scrolling_;
+ bool scroll_affects_scroll_handler_;
int scroll_layer_id_when_mouse_over_scrollbar_;
bool tile_priorities_dirty_;
@@ -563,16 +608,11 @@ class CC_EXPORT LayerTreeHostImpl
ManagedMemoryPolicy cached_managed_memory_policy_;
gfx::Vector2dF accumulated_root_overscroll_;
- gfx::Vector2dF current_fling_velocity_;
bool pinch_gesture_active_;
bool pinch_gesture_end_should_clear_scrolling_layer_;
gfx::Point previous_pinch_anchor_;
- // This is set by AnimateLayers() and used by UpdateAnimationState()
- // when sending animation events to the main thread.
- base::Time last_animation_time_;
-
scoped_ptr<TopControlsManager> top_controls_manager_;
scoped_ptr<PageScaleAnimation> page_scale_animation_;
@@ -591,9 +631,6 @@ class CC_EXPORT LayerTreeHostImpl
// manager, if there were no limit on memory usage.
size_t max_memory_needed_bytes_;
- size_t last_sent_memory_visible_bytes_;
- size_t last_sent_memory_visible_and_nearby_bytes_;
- size_t last_sent_memory_use_bytes_;
bool zero_budget_;
// Viewport size passed in from the main thread, in physical pixels. This
@@ -621,19 +658,17 @@ class CC_EXPORT LayerTreeHostImpl
// - external_viewport_ is used DrawProperties, tile management and
// glViewport/window projection matrix.
// - external_clip_ specifies a top-level clip rect
- // - external_stencil_test_enabled_ tells CC to respect existing stencil bits
- // (When these are specified, device_viewport_size_ remains used only for
- // scrollable size.)
gfx::Transform external_transform_;
gfx::Rect external_viewport_;
gfx::Rect external_clip_;
bool device_viewport_valid_for_tile_management_;
- bool external_stencil_test_enabled_;
gfx::Rect viewport_damage_rect_;
base::TimeTicks current_frame_timeticks_;
- base::Time current_frame_time_;
+
+ // Expected time between two begin impl frame calls.
+ base::TimeDelta begin_impl_frame_interval_;
scoped_ptr<AnimationRegistrar> animation_registrar_;
@@ -641,7 +676,7 @@ class CC_EXPORT LayerTreeHostImpl
MicroBenchmarkControllerImpl micro_benchmark_controller_;
bool need_to_update_visible_tiles_before_draw_;
-#ifndef NDEBUG
+#if DCHECK_IS_ON
bool did_lose_called_;
#endif
@@ -653,6 +688,10 @@ class CC_EXPORT LayerTreeHostImpl
std::set<SwapPromiseMonitor*> swap_promise_monitor_;
+ size_t transfer_buffer_memory_limit_;
+
+ std::vector<PictureLayerImpl*> picture_layers_;
+
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 4630adc555d..9ada4029bbd 100644
--- a/chromium/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/chromium/cc/trees/layer_tree_host_impl_unittest.cc
@@ -14,6 +14,7 @@
#include "cc/base/latency_info_swap_promise.h"
#include "cc/base/math_util.h"
#include "cc/input/top_controls_manager.h"
+#include "cc/layers/append_quads_data.h"
#include "cc/layers/delegated_renderer_layer_impl.h"
#include "cc/layers/heads_up_display_layer_impl.h"
#include "cc/layers/io_surface_layer_impl.h"
@@ -22,6 +23,7 @@
#include "cc/layers/quad_sink.h"
#include "cc/layers/render_surface_impl.h"
#include "cc/layers/solid_color_layer_impl.h"
+#include "cc/layers/solid_color_scrollbar_layer_impl.h"
#include "cc/layers/texture_layer_impl.h"
#include "cc/layers/tiled_layer_impl.h"
#include "cc/layers/video_layer_impl.h"
@@ -35,7 +37,6 @@
#include "cc/quads/solid_color_draw_quad.h"
#include "cc/quads/texture_draw_quad.h"
#include "cc/quads/tile_draw_quad.h"
-#include "cc/resources/etc1_pixel_ref.h"
#include "cc/resources/layer_tiling_data.h"
#include "cc/test/animation_test_common.h"
#include "cc/test/fake_layer_tree_host_impl.h"
@@ -49,12 +50,14 @@
#include "cc/test/geometry_test_utils.h"
#include "cc/test/layer_test_common.h"
#include "cc/test/render_pass_test_common.h"
+#include "cc/test/test_shared_bitmap_manager.h"
#include "cc/test/test_web_graphics_context_3d.h"
#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/single_thread_proxy.h"
#include "media/base/media.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkMallocPixelRef.h"
#include "ui/gfx/frame_time.h"
#include "ui/gfx/rect_conversions.h"
#include "ui/gfx/size_conversions.h"
@@ -74,13 +77,15 @@ class LayerTreeHostImplTest : public testing::Test,
public LayerTreeHostImplClient {
public:
LayerTreeHostImplTest()
- : proxy_(),
+ : proxy_(base::MessageLoopProxy::current()),
always_impl_thread_(&proxy_),
always_main_thread_blocked_(&proxy_),
+ shared_bitmap_manager_(new TestSharedBitmapManager()),
on_can_draw_state_changed_called_(false),
did_notify_ready_to_activate_(false),
did_request_commit_(false),
did_request_redraw_(false),
+ did_request_animate_(false),
did_request_manage_tiles_(false),
did_upload_visible_tile_(false),
reduce_memory_result_(true),
@@ -94,6 +99,7 @@ class LayerTreeHostImplTest : public testing::Test,
settings.minimum_occlusion_tracking_size = gfx::Size();
settings.impl_side_painting = true;
settings.texture_id_allocation_chunk_size = 1;
+ settings.report_overscroll_only_for_scrollable_axes = true;
return settings;
}
@@ -103,10 +109,15 @@ class LayerTreeHostImplTest : public testing::Test,
virtual void TearDown() OVERRIDE {}
+ virtual void UpdateRendererCapabilitiesOnImplThread() OVERRIDE {}
virtual void DidLoseOutputSurfaceOnImplThread() OVERRIDE {}
+ virtual void CommitVSyncParameters(base::TimeTicks timebase,
+ base::TimeDelta interval) OVERRIDE {}
+ virtual void SetEstimatedParentDrawTime(base::TimeDelta draw_time) OVERRIDE {}
+ virtual void SetMaxSwapsPendingOnImplThread(int max) OVERRIDE {}
virtual void DidSwapBuffersOnImplThread() OVERRIDE {}
- virtual void OnSwapBuffersCompleteOnImplThread() OVERRIDE {}
- virtual void BeginImplFrame(const BeginFrameArgs& args) OVERRIDE {}
+ virtual void DidSwapBuffersCompleteOnImplThread() OVERRIDE {}
+ virtual void BeginFrame(const BeginFrameArgs& args) OVERRIDE {}
virtual void OnCanDrawStateChanged(bool can_draw) OVERRIDE {
on_can_draw_state_changed_called_ = true;
}
@@ -117,9 +128,13 @@ class LayerTreeHostImplTest : public testing::Test,
virtual void SetNeedsRedrawOnImplThread() OVERRIDE {
did_request_redraw_ = true;
}
- virtual void SetNeedsRedrawRectOnImplThread(gfx::Rect damage_rect) OVERRIDE {
+ virtual void SetNeedsRedrawRectOnImplThread(
+ const gfx::Rect& damage_rect) OVERRIDE {
did_request_redraw_ = true;
}
+ virtual void SetNeedsAnimateOnImplThread() OVERRIDE {
+ did_request_animate_ = true;
+ }
virtual void SetNeedsManageTilesOnImplThread() OVERRIDE {
did_request_manage_tiles_ = true;
}
@@ -130,19 +145,21 @@ class LayerTreeHostImplTest : public testing::Test,
did_request_commit_ = true;
}
virtual void PostAnimationEventsToMainThreadOnImplThread(
- scoped_ptr<AnimationEventsVector> events,
- base::Time wall_clock_time) OVERRIDE {}
+ scoped_ptr<AnimationEventsVector> events) OVERRIDE {}
virtual bool ReduceContentsTextureMemoryOnImplThread(
size_t limit_bytes, int priority_cutoff) OVERRIDE {
current_limit_bytes_ = limit_bytes;
current_priority_cutoff_value_ = priority_cutoff;
return reduce_memory_result_;
}
- virtual void SendManagedMemoryStats() OVERRIDE {}
virtual bool IsInsideDraw() OVERRIDE { return false; }
virtual void RenewTreePriority() OVERRIDE {}
- virtual void RequestScrollbarAnimationOnImplThread(base::TimeDelta delay)
- OVERRIDE { requested_scrollbar_animation_delay_ = delay; }
+ virtual void PostDelayedScrollbarFadeOnImplThread(
+ const base::Closure& start_fade,
+ base::TimeDelta delay) OVERRIDE {
+ scrollbar_fade_start_ = start_fade;
+ requested_scrollbar_animation_delay_ = delay;
+ }
virtual void DidActivatePendingTree() OVERRIDE {}
virtual void DidManageTiles() OVERRIDE {}
@@ -152,15 +169,18 @@ class LayerTreeHostImplTest : public testing::Test,
bool CreateHostImpl(const LayerTreeSettings& settings,
scoped_ptr<OutputSurface> output_surface) {
- host_impl_ = LayerTreeHostImpl::Create(
- settings, this, &proxy_, &stats_instrumentation_, NULL, 0);
+ host_impl_ = LayerTreeHostImpl::Create(settings,
+ this,
+ &proxy_,
+ &stats_instrumentation_,
+ shared_bitmap_manager_.get(),
+ 0);
bool init = host_impl_->InitializeRenderer(output_surface.Pass());
host_impl_->SetViewportSize(gfx::Size(10, 10));
return init;
}
void SetupRootLayerImpl(scoped_ptr<LayerImpl> root) {
- root->SetAnchorPoint(gfx::PointF());
root->SetPosition(gfx::PointF());
root->SetBounds(gfx::Size(10, 10));
root->SetContentBounds(gfx::Size(10, 10));
@@ -177,7 +197,7 @@ class LayerTreeHostImplTest : public testing::Test,
static void ExpectContains(const ScrollAndScaleSet& scroll_info,
int id,
- gfx::Vector2d scroll_delta) {
+ const gfx::Vector2d& scroll_delta) {
int times_encountered = 0;
for (size_t i = 0; i < scroll_info.scrolls.size(); ++i) {
@@ -203,25 +223,35 @@ class LayerTreeHostImplTest : public testing::Test,
}
LayerImpl* CreateScrollAndContentsLayers(LayerTreeImpl* layer_tree_impl,
- gfx::Size content_size) {
+ const gfx::Size& content_size) {
+ const int kInnerViewportScrollLayerId = 2;
+ const int kInnerViewportClipLayerId = 4;
+ const int kPageScaleLayerId = 5;
scoped_ptr<LayerImpl> root =
LayerImpl::Create(layer_tree_impl, 1);
root->SetBounds(content_size);
root->SetContentBounds(content_size);
root->SetPosition(gfx::PointF());
- root->SetAnchorPoint(gfx::PointF());
scoped_ptr<LayerImpl> scroll =
- LayerImpl::Create(layer_tree_impl, 2);
+ LayerImpl::Create(layer_tree_impl, kInnerViewportScrollLayerId);
LayerImpl* scroll_layer = scroll.get();
- scroll->SetScrollable(true);
+ scroll->SetIsContainerForFixedPositionLayers(true);
scroll->SetScrollOffset(gfx::Vector2d());
- scroll->SetMaxScrollOffset(gfx::Vector2d(content_size.width(),
- content_size.height()));
+
+ scoped_ptr<LayerImpl> clip =
+ LayerImpl::Create(layer_tree_impl, kInnerViewportClipLayerId);
+ clip->SetBounds(
+ gfx::Size(content_size.width() / 2, content_size.height() / 2));
+
+ scoped_ptr<LayerImpl> page_scale =
+ LayerImpl::Create(layer_tree_impl, kPageScaleLayerId);
+
+ scroll->SetScrollClipLayer(clip->id());
scroll->SetBounds(content_size);
scroll->SetContentBounds(content_size);
scroll->SetPosition(gfx::PointF());
- scroll->SetAnchorPoint(gfx::PointF());
+ scroll->SetIsContainerForFixedPositionLayers(true);
scoped_ptr<LayerImpl> contents =
LayerImpl::Create(layer_tree_impl, 3);
@@ -229,37 +259,45 @@ class LayerTreeHostImplTest : public testing::Test,
contents->SetBounds(content_size);
contents->SetContentBounds(content_size);
contents->SetPosition(gfx::PointF());
- contents->SetAnchorPoint(gfx::PointF());
scroll->AddChild(contents.Pass());
- root->AddChild(scroll.Pass());
+ page_scale->AddChild(scroll.Pass());
+ clip->AddChild(page_scale.Pass());
+ root->AddChild(clip.Pass());
layer_tree_impl->SetRootLayer(root.Pass());
+ layer_tree_impl->SetViewportLayersFromIds(
+ kPageScaleLayerId, kInnerViewportScrollLayerId, Layer::INVALID_ID);
+
return scroll_layer;
}
- LayerImpl* SetupScrollAndContentsLayers(gfx::Size content_size) {
+ LayerImpl* SetupScrollAndContentsLayers(const gfx::Size& content_size) {
LayerImpl* scroll_layer = CreateScrollAndContentsLayers(
host_impl_->active_tree(), content_size);
host_impl_->active_tree()->DidBecomeActive();
return scroll_layer;
}
- scoped_ptr<LayerImpl> CreateScrollableLayer(int id, gfx::Size size) {
+ // TODO(wjmaclean) Add clip-layer pointer to parameters.
+ scoped_ptr<LayerImpl> CreateScrollableLayer(int id,
+ const gfx::Size& size,
+ LayerImpl* clip_layer) {
+ DCHECK(clip_layer);
+ DCHECK(id != clip_layer->id());
scoped_ptr<LayerImpl> layer =
LayerImpl::Create(host_impl_->active_tree(), id);
- layer->SetScrollable(true);
+ layer->SetScrollClipLayer(clip_layer->id());
layer->SetDrawsContent(true);
layer->SetBounds(size);
layer->SetContentBounds(size);
- layer->SetMaxScrollOffset(gfx::Vector2d(size.width() * 2,
- size.height() * 2));
+ clip_layer->SetBounds(gfx::Size(size.width() / 2, size.height() / 2));
return layer.Pass();
}
void DrawFrame() {
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
host_impl_->DidDrawAllLayers(frame);
}
@@ -340,12 +378,12 @@ class LayerTreeHostImplTest : public testing::Test,
protected:
virtual scoped_ptr<OutputSurface> CreateOutputSurface() {
- return CreateFakeOutputSurface();
+ return FakeOutputSurface::Create3d().PassAs<OutputSurface>();
}
void DrawOneFrame() {
LayerTreeHostImpl::FrameData frame_data;
- host_impl_->PrepareToDraw(&frame_data, gfx::Rect());
+ host_impl_->PrepareToDraw(&frame_data);
host_impl_->DidDrawAllLayers(frame_data);
}
@@ -353,15 +391,18 @@ class LayerTreeHostImplTest : public testing::Test,
DebugScopedSetImplThread always_impl_thread_;
DebugScopedSetMainThreadBlocked always_main_thread_blocked_;
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager_;
scoped_ptr<LayerTreeHostImpl> host_impl_;
FakeRenderingStatsInstrumentation stats_instrumentation_;
bool on_can_draw_state_changed_called_;
bool did_notify_ready_to_activate_;
bool did_request_commit_;
bool did_request_redraw_;
+ bool did_request_animate_;
bool did_request_manage_tiles_;
bool did_upload_visible_tile_;
bool reduce_memory_result_;
+ base::Closure scrollbar_fade_start_;
base::TimeDelta requested_scrollbar_animation_delay_;
size_t current_limit_bytes_;
int current_priority_cutoff_value_;
@@ -421,15 +462,20 @@ TEST_F(LayerTreeHostImplTest, ScrollDeltaRepeatedScrolls) {
gfx::Vector2d scroll_offset(20, 30);
gfx::Vector2d scroll_delta(11, -15);
{
+ scoped_ptr<LayerImpl> root_clip =
+ LayerImpl::Create(host_impl_->active_tree(), 2);
scoped_ptr<LayerImpl> root =
LayerImpl::Create(host_impl_->active_tree(), 1);
- root->SetMaxScrollOffset(gfx::Vector2d(100, 100));
- root->SetScrollOffset(scroll_offset);
- root->SetScrollable(true);
- root->ScrollBy(scroll_delta);
- host_impl_->active_tree()->SetRootLayer(root.Pass());
+ root_clip->SetBounds(gfx::Size(10, 10));
+ LayerImpl* root_layer = root.get();
+ root_clip->AddChild(root.Pass());
+ root_layer->SetBounds(gfx::Size(110, 110));
+ root_layer->SetScrollClipLayer(root_clip->id());
+ root_layer->SetScrollOffset(scroll_offset);
+ root_layer->ScrollBy(scroll_delta);
+ host_impl_->active_tree()->SetRootLayer(root_clip.Pass());
}
- LayerImpl* root = host_impl_->active_tree()->root_layer();
+ LayerImpl* root = host_impl_->active_tree()->root_layer()->children()[0];
scoped_ptr<ScrollAndScaleSet> scroll_info;
@@ -457,8 +503,14 @@ TEST_F(LayerTreeHostImplTest, ScrollRootCallsCommitAndRedraw) {
EXPECT_EQ(InputHandler::ScrollStarted,
host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+ EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(),
+ InputHandler::Wheel));
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
+ EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(0, 10),
+ InputHandler::Wheel));
host_impl_->ScrollEnd();
+ EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(),
+ InputHandler::Wheel));
EXPECT_TRUE(did_request_redraw_);
EXPECT_TRUE(did_request_commit_);
}
@@ -485,7 +537,7 @@ TEST_F(LayerTreeHostImplTest, ScrollWithoutRenderer) {
// We should not crash when trying to scroll after the renderer initialization
// fails.
- EXPECT_EQ(InputHandler::ScrollIgnored,
+ EXPECT_EQ(InputHandler::ScrollStarted,
host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
}
@@ -623,21 +675,35 @@ TEST_F(LayerTreeHostImplTest, NonFastScrollableRegionBasic) {
EXPECT_EQ(InputHandler::ScrollOnMainThread,
host_impl_->ScrollBegin(gfx::Point(25, 25),
InputHandler::Wheel));
+ EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(25, 25),
+ InputHandler::Wheel));
EXPECT_EQ(InputHandler::ScrollOnMainThread,
host_impl_->ScrollBegin(gfx::Point(25, 25),
InputHandler::Gesture));
+ EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(25, 25),
+ InputHandler::Gesture));
// All scroll types outside this region should succeed.
EXPECT_EQ(InputHandler::ScrollStarted,
host_impl_->ScrollBegin(gfx::Point(75, 75),
InputHandler::Wheel));
+ EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(75, 75),
+ InputHandler::Gesture));
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
+ EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(25, 25),
+ InputHandler::Gesture));
host_impl_->ScrollEnd();
+ EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(75, 75),
+ InputHandler::Gesture));
EXPECT_EQ(InputHandler::ScrollStarted,
host_impl_->ScrollBegin(gfx::Point(75, 75),
InputHandler::Gesture));
+ EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(75, 75),
+ InputHandler::Gesture));
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
host_impl_->ScrollEnd();
+ EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(75, 75),
+ InputHandler::Gesture));
}
TEST_F(LayerTreeHostImplTest, NonFastScrollableRegionWithOffset) {
@@ -656,6 +722,8 @@ TEST_F(LayerTreeHostImplTest, NonFastScrollableRegionWithOffset) {
EXPECT_EQ(InputHandler::ScrollStarted,
host_impl_->ScrollBegin(gfx::Point(40, 10),
InputHandler::Wheel));
+ EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(40, 10),
+ InputHandler::Wheel));
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 1));
host_impl_->ScrollEnd();
@@ -665,6 +733,32 @@ TEST_F(LayerTreeHostImplTest, NonFastScrollableRegionWithOffset) {
InputHandler::Wheel));
}
+TEST_F(LayerTreeHostImplTest, ScrollHandlerNotPresent) {
+ LayerImpl* scroll_layer = SetupScrollAndContentsLayers(gfx::Size(200, 200));
+ EXPECT_FALSE(scroll_layer->have_scroll_event_handlers());
+ host_impl_->SetViewportSize(gfx::Size(50, 50));
+ DrawFrame();
+
+ EXPECT_FALSE(host_impl_->scroll_affects_scroll_handler());
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture);
+ EXPECT_FALSE(host_impl_->scroll_affects_scroll_handler());
+ host_impl_->ScrollEnd();
+ EXPECT_FALSE(host_impl_->scroll_affects_scroll_handler());
+}
+
+TEST_F(LayerTreeHostImplTest, ScrollHandlerPresent) {
+ LayerImpl* scroll_layer = SetupScrollAndContentsLayers(gfx::Size(200, 200));
+ scroll_layer->SetHaveScrollEventHandlers(true);
+ host_impl_->SetViewportSize(gfx::Size(50, 50));
+ DrawFrame();
+
+ EXPECT_FALSE(host_impl_->scroll_affects_scroll_handler());
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture);
+ EXPECT_TRUE(host_impl_->scroll_affects_scroll_handler());
+ host_impl_->ScrollEnd();
+ EXPECT_FALSE(host_impl_->scroll_affects_scroll_handler());
+}
+
TEST_F(LayerTreeHostImplTest, ScrollByReturnsCorrectValue) {
SetupScrollAndContentsLayers(gfx::Size(200, 200));
host_impl_->SetViewportSize(gfx::Size(100, 100));
@@ -714,19 +808,20 @@ TEST_F(LayerTreeHostImplTest, ScrollVerticallyByPageReturnsCorrectValue) {
EXPECT_FALSE(host_impl_->ScrollVerticallyByPage(
gfx::Point(), SCROLL_BACKWARD));
- scoped_ptr<cc::PaintedScrollbarLayerImpl> vertical_scrollbar(
- cc::PaintedScrollbarLayerImpl::Create(
+ scoped_ptr<PaintedScrollbarLayerImpl> vertical_scrollbar(
+ PaintedScrollbarLayerImpl::Create(
host_impl_->active_tree(),
20,
VERTICAL));
vertical_scrollbar->SetBounds(gfx::Size(15, 1000));
- host_impl_->RootScrollLayer()->SetVerticalScrollbarLayer(
+ host_impl_->InnerViewportScrollLayer()->AddScrollbar(
vertical_scrollbar.get());
// Trying to scroll with a vertical scrollbar will succeed.
EXPECT_TRUE(host_impl_->ScrollVerticallyByPage(
gfx::Point(), SCROLL_FORWARD));
- EXPECT_FLOAT_EQ(875.f, host_impl_->RootScrollLayer()->ScrollDelta().y());
+ EXPECT_FLOAT_EQ(875.f,
+ host_impl_->InnerViewportScrollLayer()->ScrollDelta().y());
EXPECT_TRUE(host_impl_->ScrollVerticallyByPage(
gfx::Point(), SCROLL_BACKWARD));
}
@@ -742,12 +837,9 @@ TEST_F(LayerTreeHostImplTest, DISABLED_ScrollWithUserUnscrollableLayers) {
LayerImpl* overflow = scroll_layer->children()[0];
overflow->SetBounds(overflow_size);
overflow->SetContentBounds(overflow_size);
- overflow->SetScrollable(true);
- overflow->SetMaxScrollOffset(gfx::Vector2d(overflow_size.width(),
- overflow_size.height()));
+ overflow->SetScrollClipLayer(scroll_layer->parent()->id());
overflow->SetScrollOffset(gfx::Vector2d());
overflow->SetPosition(gfx::PointF());
- overflow->SetAnchorPoint(gfx::PointF());
DrawFrame();
gfx::Point scroll_position(10, 10);
@@ -807,40 +899,54 @@ TEST_F(LayerTreeHostImplTest, ImplPinchZoom) {
host_impl_->SetViewportSize(gfx::Size(50, 50));
DrawFrame();
- EXPECT_EQ(scroll_layer, host_impl_->RootScrollLayer());
+ EXPECT_EQ(scroll_layer, host_impl_->InnerViewportScrollLayer());
+ LayerImpl* container_layer = scroll_layer->scroll_clip_layer();
+ EXPECT_EQ(gfx::Size(50, 50), container_layer->bounds());
float min_page_scale = 1.f, max_page_scale = 4.f;
+ float page_scale_factor = 1.f;
// The impl-based pinch zoom should adjust the max scroll position.
{
- host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f,
- min_page_scale,
- max_page_scale);
+ host_impl_->active_tree()->SetPageScaleFactorAndLimits(
+ page_scale_factor, min_page_scale, max_page_scale);
host_impl_->active_tree()->SetPageScaleDelta(1.f);
scroll_layer->SetScrollDelta(gfx::Vector2d());
float page_scale_delta = 2.f;
+ gfx::Vector2dF expected_container_size_delta(
+ container_layer->bounds().width(), container_layer->bounds().height());
+ expected_container_size_delta.Scale((1.f - page_scale_delta) /
+ (page_scale_factor * page_scale_delta));
+
host_impl_->ScrollBegin(gfx::Point(50, 50), InputHandler::Gesture);
+ host_impl_->PinchGestureBegin();
host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(50, 50));
+ // While the gesture is still active, the scroll layer should have a
+ // container size delta = container->bounds() * ((1.f -
+ // page_scale_delta)/())
+ EXPECT_EQ(expected_container_size_delta,
+ scroll_layer->FixedContainerSizeDelta());
host_impl_->PinchGestureEnd();
host_impl_->ScrollEnd();
+ EXPECT_FALSE(did_request_animate_);
EXPECT_TRUE(did_request_redraw_);
EXPECT_TRUE(did_request_commit_);
+ EXPECT_EQ(gfx::Size(50, 50), container_layer->bounds());
scoped_ptr<ScrollAndScaleSet> scroll_info =
host_impl_->ProcessScrollDeltas();
EXPECT_EQ(scroll_info->page_scale_delta, page_scale_delta);
EXPECT_EQ(gfx::Vector2d(75, 75).ToString(),
- scroll_layer->max_scroll_offset().ToString());
+ scroll_layer->MaxScrollOffset().ToString());
}
// Scrolling after a pinch gesture should always be in local space. The
// scroll deltas do not have the page scale factor applied.
{
- host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f,
- min_page_scale,
- max_page_scale);
+ host_impl_->active_tree()->SetPageScaleFactorAndLimits(
+ page_scale_factor, min_page_scale, max_page_scale);
host_impl_->active_tree()->SetPageScaleDelta(1.f);
scroll_layer->SetScrollDelta(gfx::Vector2d());
@@ -866,12 +972,67 @@ TEST_F(LayerTreeHostImplTest, ImplPinchZoom) {
}
}
+TEST_F(LayerTreeHostImplTest, MasksToBoundsDoesntClobberInnerContainerSize) {
+ SetupScrollAndContentsLayers(gfx::Size(100, 100));
+ host_impl_->SetViewportSize(gfx::Size(50, 50));
+ DrawFrame();
+
+ LayerImpl* scroll_layer = host_impl_->InnerViewportScrollLayer();
+ LayerImpl* container_layer = scroll_layer->scroll_clip_layer();
+ DCHECK(scroll_layer);
+
+ float min_page_scale = 1.f;
+ float max_page_scale = 4.f;
+ host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f,
+ min_page_scale,
+ max_page_scale);
+
+ // If the container's masks_to_bounds is false, the viewport size should
+ // overwrite the inner viewport container layer's size.
+ {
+ EXPECT_EQ(gfx::Size(50, 50),
+ container_layer->bounds());
+ container_layer->SetMasksToBounds(false);
+
+ container_layer->SetBounds(gfx::Size(30, 25));
+ EXPECT_EQ(gfx::Size(30, 25),
+ container_layer->bounds());
+
+ // This should cause a reset of the inner viewport container layer's bounds.
+ host_impl_->DidChangeTopControlsPosition();
+
+ EXPECT_EQ(gfx::Size(50, 50),
+ container_layer->bounds());
+ }
+
+ host_impl_->SetViewportSize(gfx::Size(50, 50));
+ container_layer->SetBounds(gfx::Size(50, 50));
+
+ // If the container's masks_to_bounds is true, the viewport size should
+ // *NOT* overwrite the inner viewport container layer's size.
+ {
+ EXPECT_EQ(gfx::Size(50, 50),
+ container_layer->bounds());
+ container_layer->SetMasksToBounds(true);
+
+ container_layer->SetBounds(gfx::Size(30, 25));
+ EXPECT_EQ(gfx::Size(30, 25),
+ container_layer->bounds());
+
+ // This should cause a reset of the inner viewport container layer's bounds.
+ host_impl_->DidChangeTopControlsPosition();
+
+ EXPECT_EQ(gfx::Size(30, 25),
+ container_layer->bounds());
+ }
+}
+
TEST_F(LayerTreeHostImplTest, PinchGesture) {
SetupScrollAndContentsLayers(gfx::Size(100, 100));
host_impl_->SetViewportSize(gfx::Size(50, 50));
DrawFrame();
- LayerImpl* scroll_layer = host_impl_->RootScrollLayer();
+ LayerImpl* scroll_layer = host_impl_->InnerViewportScrollLayer();
DCHECK(scroll_layer);
float min_page_scale = 1.f;
@@ -890,6 +1051,7 @@ TEST_F(LayerTreeHostImplTest, PinchGesture) {
host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(50, 50));
host_impl_->PinchGestureEnd();
host_impl_->ScrollEnd();
+ EXPECT_FALSE(did_request_animate_);
EXPECT_TRUE(did_request_redraw_);
EXPECT_TRUE(did_request_commit_);
@@ -991,7 +1153,6 @@ TEST_F(LayerTreeHostImplTest, PinchGesture) {
4.f);
scroll_layer->SetScrollDelta(gfx::Vector2d());
scroll_layer->SetScrollOffset(gfx::Vector2d(0, 0));
- host_impl_->active_tree()->UpdateMaxScrollOffset();
host_impl_->ScrollBegin(gfx::Point(0, 0), InputHandler::Gesture);
host_impl_->PinchGestureBegin();
@@ -1014,7 +1175,7 @@ TEST_F(LayerTreeHostImplTest, PageScaleAnimation) {
host_impl_->SetViewportSize(gfx::Size(50, 50));
DrawFrame();
- LayerImpl* scroll_layer = host_impl_->RootScrollLayer();
+ LayerImpl* scroll_layer = host_impl_->InnerViewportScrollLayer();
DCHECK(scroll_layer);
float min_page_scale = 0.5f;
@@ -1032,19 +1193,30 @@ TEST_F(LayerTreeHostImplTest, PageScaleAnimation) {
max_page_scale);
scroll_layer->SetScrollOffset(gfx::Vector2d(50, 50));
+ did_request_redraw_ = false;
+ did_request_animate_ = false;
host_impl_->StartPageScaleAnimation(gfx::Vector2d(), false, 2.f, duration);
+ EXPECT_FALSE(did_request_redraw_);
+ EXPECT_TRUE(did_request_animate_);
+
did_request_redraw_ = false;
- host_impl_->Animate(start_time, base::Time());
+ did_request_animate_ = false;
+ host_impl_->Animate(start_time);
EXPECT_TRUE(did_request_redraw_);
+ EXPECT_TRUE(did_request_animate_);
did_request_redraw_ = false;
- host_impl_->Animate(halfway_through_animation, base::Time());
+ did_request_animate_ = false;
+ host_impl_->Animate(halfway_through_animation);
EXPECT_TRUE(did_request_redraw_);
+ EXPECT_TRUE(did_request_animate_);
did_request_redraw_ = false;
+ did_request_animate_ = false;
did_request_commit_ = false;
- host_impl_->Animate(end_time, base::Time());
+ host_impl_->Animate(end_time);
EXPECT_TRUE(did_request_commit_);
+ EXPECT_FALSE(did_request_animate_);
scoped_ptr<ScrollAndScaleSet> scroll_info =
host_impl_->ProcessScrollDeltas();
@@ -1059,16 +1231,25 @@ TEST_F(LayerTreeHostImplTest, PageScaleAnimation) {
max_page_scale);
scroll_layer->SetScrollOffset(gfx::Vector2d(50, 50));
+ did_request_redraw_ = false;
+ did_request_animate_ = false;
host_impl_->StartPageScaleAnimation(
gfx::Vector2d(25, 25), true, min_page_scale, duration);
+ EXPECT_FALSE(did_request_redraw_);
+ EXPECT_TRUE(did_request_animate_);
+
did_request_redraw_ = false;
- host_impl_->Animate(start_time, base::Time());
+ did_request_animate_ = false;
+ host_impl_->Animate(start_time);
EXPECT_TRUE(did_request_redraw_);
+ EXPECT_TRUE(did_request_animate_);
did_request_redraw_ = false;
did_request_commit_ = false;
- host_impl_->Animate(end_time, base::Time());
+ did_request_animate_ = false;
+ host_impl_->Animate(end_time);
EXPECT_TRUE(did_request_redraw_);
+ EXPECT_FALSE(did_request_animate_);
EXPECT_TRUE(did_request_commit_);
scoped_ptr<ScrollAndScaleSet> scroll_info =
@@ -1084,7 +1265,7 @@ TEST_F(LayerTreeHostImplTest, PageScaleAnimationNoOp) {
host_impl_->SetViewportSize(gfx::Size(50, 50));
DrawFrame();
- LayerImpl* scroll_layer = host_impl_->RootScrollLayer();
+ LayerImpl* scroll_layer = host_impl_->InnerViewportScrollLayer();
DCHECK(scroll_layer);
float min_page_scale = 0.5f;
@@ -1103,10 +1284,10 @@ TEST_F(LayerTreeHostImplTest, PageScaleAnimationNoOp) {
scroll_layer->SetScrollOffset(gfx::Vector2d(50, 50));
host_impl_->StartPageScaleAnimation(gfx::Vector2d(), true, 1.f, duration);
- host_impl_->Animate(start_time, base::Time());
- host_impl_->Animate(halfway_through_animation, base::Time());
+ host_impl_->Animate(start_time);
+ host_impl_->Animate(halfway_through_animation);
EXPECT_TRUE(did_request_redraw_);
- host_impl_->Animate(end_time, base::Time());
+ host_impl_->Animate(end_time);
EXPECT_TRUE(did_request_commit_);
scoped_ptr<ScrollAndScaleSet> scroll_info =
@@ -1122,15 +1303,16 @@ class LayerTreeHostImplOverridePhysicalTime : public LayerTreeHostImpl {
const LayerTreeSettings& settings,
LayerTreeHostImplClient* client,
Proxy* proxy,
+ SharedBitmapManager* manager,
RenderingStatsInstrumentation* rendering_stats_instrumentation)
: LayerTreeHostImpl(settings,
client,
proxy,
rendering_stats_instrumentation,
- NULL,
+ manager,
0) {}
- virtual base::TimeTicks CurrentPhysicalTimeTicks() const OVERRIDE {
+ virtual base::TimeTicks CurrentFrameTimeTicks() OVERRIDE {
return fake_current_physical_time_;
}
@@ -1142,117 +1324,170 @@ class LayerTreeHostImplOverridePhysicalTime : public LayerTreeHostImpl {
base::TimeTicks fake_current_physical_time_;
};
+#define SETUP_LAYERS_FOR_SCROLLBAR_ANIMATION_TEST() \
+ gfx::Size viewport_size(10, 10); \
+ gfx::Size content_size(100, 100); \
+ \
+ LayerTreeHostImplOverridePhysicalTime* host_impl_override_time = \
+ new LayerTreeHostImplOverridePhysicalTime(settings, \
+ this, \
+ &proxy_, \
+ shared_bitmap_manager_.get(), \
+ &stats_instrumentation_); \
+ host_impl_ = make_scoped_ptr(host_impl_override_time); \
+ host_impl_->InitializeRenderer(CreateOutputSurface()); \
+ host_impl_->SetViewportSize(viewport_size); \
+ \
+ scoped_ptr<LayerImpl> root = \
+ LayerImpl::Create(host_impl_->active_tree(), 1); \
+ root->SetBounds(viewport_size); \
+ \
+ scoped_ptr<LayerImpl> scroll = \
+ LayerImpl::Create(host_impl_->active_tree(), 2); \
+ scroll->SetScrollClipLayer(root->id()); \
+ scroll->SetScrollOffset(gfx::Vector2d()); \
+ root->SetBounds(viewport_size); \
+ scroll->SetBounds(content_size); \
+ scroll->SetContentBounds(content_size); \
+ scroll->SetIsContainerForFixedPositionLayers(true); \
+ \
+ scoped_ptr<LayerImpl> contents = \
+ LayerImpl::Create(host_impl_->active_tree(), 3); \
+ contents->SetDrawsContent(true); \
+ contents->SetBounds(content_size); \
+ contents->SetContentBounds(content_size); \
+ \
+ scoped_ptr<SolidColorScrollbarLayerImpl> scrollbar = \
+ SolidColorScrollbarLayerImpl::Create( \
+ host_impl_->active_tree(), 4, VERTICAL, 10, 0, false, true); \
+ EXPECT_FLOAT_EQ(0.f, scrollbar->opacity()); \
+ scrollbar->SetScrollLayerById(2); \
+ scrollbar->SetClipLayerById(1); \
+ \
+ scroll->AddChild(contents.Pass()); \
+ root->AddChild(scroll.Pass()); \
+ root->AddChild(scrollbar.PassAs<LayerImpl>()); \
+ \
+ host_impl_->active_tree()->SetRootLayer(root.Pass()); \
+ host_impl_->active_tree()->SetViewportLayersFromIds( \
+ 1, 2, Layer::INVALID_ID); \
+ host_impl_->active_tree()->DidBecomeActive(); \
+ DrawFrame();
+
TEST_F(LayerTreeHostImplTest, ScrollbarLinearFadeScheduling) {
LayerTreeSettings settings;
settings.scrollbar_animator = LayerTreeSettings::LinearFade;
- settings.scrollbar_linear_fade_delay_ms = 20;
- settings.scrollbar_linear_fade_length_ms = 20;
-
- gfx::Size viewport_size(10, 10);
- gfx::Size content_size(100, 100);
-
- LayerTreeHostImplOverridePhysicalTime* host_impl_override_time =
- new LayerTreeHostImplOverridePhysicalTime(
- settings, this, &proxy_, &stats_instrumentation_);
- host_impl_ = make_scoped_ptr(host_impl_override_time);
- host_impl_->InitializeRenderer(CreateOutputSurface());
- host_impl_->SetViewportSize(viewport_size);
-
- scoped_ptr<LayerImpl> root =
- LayerImpl::Create(host_impl_->active_tree(), 1);
- root->SetBounds(viewport_size);
-
- scoped_ptr<LayerImpl> scroll =
- LayerImpl::Create(host_impl_->active_tree(), 2);
- scroll->SetScrollable(true);
- scroll->SetScrollOffset(gfx::Vector2d());
- scroll->SetMaxScrollOffset(gfx::Vector2d(content_size.width(),
- content_size.height()));
- scroll->SetBounds(content_size);
- scroll->SetContentBounds(content_size);
+ settings.scrollbar_fade_delay_ms = 20;
+ settings.scrollbar_fade_duration_ms = 20;
- scoped_ptr<LayerImpl> contents =
- LayerImpl::Create(host_impl_->active_tree(), 3);
- contents->SetDrawsContent(true);
- contents->SetBounds(content_size);
- contents->SetContentBounds(content_size);
-
- scoped_ptr<PaintedScrollbarLayerImpl> scrollbar =
- PaintedScrollbarLayerImpl::Create(host_impl_->active_tree(), 4, VERTICAL);
- scroll->SetVerticalScrollbarLayer(scrollbar.get());
-
- scroll->AddChild(contents.Pass());
- root->AddChild(scroll.Pass());
- root->AddChild(scrollbar.PassAs<LayerImpl>());
-
- host_impl_->active_tree()->SetRootLayer(root.Pass());
- host_impl_->active_tree()->DidBecomeActive();
- DrawFrame();
+ SETUP_LAYERS_FOR_SCROLLBAR_ANIMATION_TEST();
base::TimeTicks fake_now = gfx::FrameTime::Now();
- host_impl_override_time->SetCurrentPhysicalTimeTicksForTest(fake_now);
- // If no scroll happened recently, StartScrollbarAnimation should have no
- // effect.
- host_impl_->StartScrollbarAnimation();
EXPECT_EQ(base::TimeDelta(), requested_scrollbar_animation_delay_);
EXPECT_FALSE(did_request_redraw_);
- // If no scroll happened during a scroll gesture, StartScrollbarAnimation
- // should have no effect.
+ // If no scroll happened during a scroll gesture, it should have no effect.
host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel);
host_impl_->ScrollEnd();
- host_impl_->StartScrollbarAnimation();
EXPECT_EQ(base::TimeDelta(), requested_scrollbar_animation_delay_);
EXPECT_FALSE(did_request_redraw_);
+ EXPECT_TRUE(scrollbar_fade_start_.Equals(base::Closure()));
// After a scroll, a fade animation should be scheduled about 20ms from now.
host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel);
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(5, 0));
host_impl_->ScrollEnd();
did_request_redraw_ = false;
- host_impl_->StartScrollbarAnimation();
+ did_request_animate_ = false;
EXPECT_LT(base::TimeDelta::FromMilliseconds(19),
requested_scrollbar_animation_delay_);
EXPECT_FALSE(did_request_redraw_);
+ EXPECT_FALSE(did_request_animate_);
requested_scrollbar_animation_delay_ = base::TimeDelta();
+ scrollbar_fade_start_.Run();
+ host_impl_->Animate(fake_now);
// After the fade begins, we should start getting redraws instead of a
// scheduled animation.
fake_now += base::TimeDelta::FromMilliseconds(25);
- host_impl_override_time->SetCurrentPhysicalTimeTicksForTest(fake_now);
- host_impl_->StartScrollbarAnimation();
EXPECT_EQ(base::TimeDelta(), requested_scrollbar_animation_delay_);
- EXPECT_TRUE(did_request_redraw_);
+ EXPECT_TRUE(did_request_animate_);
+ did_request_animate_ = false;
+
+ // Setting the scroll offset outside a scroll should also cause the scrollbar
+ // to appear and to schedule a fade.
+ host_impl_->InnerViewportScrollLayer()->SetScrollOffset(gfx::Vector2d(5, 5));
+ EXPECT_LT(base::TimeDelta::FromMilliseconds(19),
+ requested_scrollbar_animation_delay_);
+ EXPECT_FALSE(did_request_redraw_);
+ EXPECT_FALSE(did_request_animate_);
+ requested_scrollbar_animation_delay_ = base::TimeDelta();
+}
+
+TEST_F(LayerTreeHostImplTest, ScrollbarFadePinchZoomScrollbars) {
+ LayerTreeSettings settings;
+ settings.scrollbar_animator = LayerTreeSettings::LinearFade;
+ settings.scrollbar_fade_delay_ms = 20;
+ settings.scrollbar_fade_duration_ms = 20;
+ settings.use_pinch_zoom_scrollbars = true;
+
+ SETUP_LAYERS_FOR_SCROLLBAR_ANIMATION_TEST();
+
+ base::TimeTicks fake_now = gfx::FrameTime::Now();
+
+ host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f, 1.f, 4.f);
+
+ EXPECT_EQ(base::TimeDelta(), requested_scrollbar_animation_delay_);
+ EXPECT_FALSE(did_request_animate_);
+
+ // If no scroll happened during a scroll gesture, it should have no effect.
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel);
+ host_impl_->ScrollEnd();
+ EXPECT_EQ(base::TimeDelta(), requested_scrollbar_animation_delay_);
+ EXPECT_FALSE(did_request_animate_);
+ EXPECT_TRUE(scrollbar_fade_start_.Equals(base::Closure()));
+
+ // After a scroll, no fade animation should be scheduled.
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel);
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(5, 0));
+ host_impl_->ScrollEnd();
did_request_redraw_ = false;
+ EXPECT_EQ(base::TimeDelta(), requested_scrollbar_animation_delay_);
+ EXPECT_FALSE(did_request_animate_);
+ requested_scrollbar_animation_delay_ = base::TimeDelta();
- // If no scroll happened recently, StartScrollbarAnimation should have no
- // effect.
+ // We should not see any draw requests.
fake_now += base::TimeDelta::FromMilliseconds(25);
- host_impl_override_time->SetCurrentPhysicalTimeTicksForTest(fake_now);
- host_impl_->StartScrollbarAnimation();
EXPECT_EQ(base::TimeDelta(), requested_scrollbar_animation_delay_);
- EXPECT_FALSE(did_request_redraw_);
+ EXPECT_FALSE(did_request_animate_);
- // Setting the scroll offset outside a scroll should also cause the scrollbar
- // to appear and to schedule a fade.
- host_impl_->RootScrollLayer()->SetScrollOffset(gfx::Vector2d(5, 5));
- host_impl_->StartScrollbarAnimation();
+ // Make page scale > min so that subsequent scrolls will trigger fades.
+ host_impl_->active_tree()->SetPageScaleDelta(1.1f);
+
+ // After a scroll, a fade animation should be scheduled about 20ms from now.
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel);
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(5, 0));
+ host_impl_->ScrollEnd();
+ did_request_redraw_ = false;
EXPECT_LT(base::TimeDelta::FromMilliseconds(19),
requested_scrollbar_animation_delay_);
- EXPECT_FALSE(did_request_redraw_);
+ EXPECT_FALSE(did_request_animate_);
requested_scrollbar_animation_delay_ = base::TimeDelta();
+ scrollbar_fade_start_.Run();
- // None of the above should have called CurrentFrameTimeTicks, so if we call
- // it now we should get the current time.
- fake_now += base::TimeDelta::FromMilliseconds(10);
- host_impl_override_time->SetCurrentPhysicalTimeTicksForTest(fake_now);
- EXPECT_EQ(fake_now, host_impl_->CurrentFrameTimeTicks());
+ // After the fade begins, we should start getting redraws instead of a
+ // scheduled animation.
+ fake_now += base::TimeDelta::FromMilliseconds(25);
+ host_impl_->Animate(fake_now);
+ EXPECT_TRUE(did_request_animate_);
}
void LayerTreeHostImplTest::SetupMouseMoveAtWithDeviceScale(
float device_scale_factor) {
LayerTreeSettings settings;
+ settings.scrollbar_fade_delay_ms = 500;
+ settings.scrollbar_fade_duration_ms = 300;
settings.scrollbar_animator = LayerTreeSettings::Thinning;
gfx::Size viewport_size(300, 200);
@@ -1270,12 +1505,11 @@ void LayerTreeHostImplTest::SetupMouseMoveAtWithDeviceScale(
scoped_ptr<LayerImpl> scroll =
LayerImpl::Create(host_impl_->active_tree(), 2);
- scroll->SetScrollable(true);
+ scroll->SetScrollClipLayer(root->id());
scroll->SetScrollOffset(gfx::Vector2d());
- scroll->SetMaxScrollOffset(gfx::Vector2d(content_size.width(),
- content_size.height()));
scroll->SetBounds(content_size);
scroll->SetContentBounds(content_size);
+ scroll->SetIsContainerForFixedPositionLayers(true);
scoped_ptr<LayerImpl> contents =
LayerImpl::Create(host_impl_->active_tree(), 3);
@@ -1290,17 +1524,20 @@ void LayerTreeHostImplTest::SetupMouseMoveAtWithDeviceScale(
scrollbar->SetBounds(gfx::Size(15, viewport_size.height()));
scrollbar->SetContentBounds(gfx::Size(15, viewport_size.height()));
scrollbar->SetPosition(gfx::Point(285, 0));
- scroll->SetVerticalScrollbarLayer(scrollbar.get());
+ scrollbar->SetClipLayerById(1);
+ scrollbar->SetScrollLayerById(2);
scroll->AddChild(contents.Pass());
root->AddChild(scroll.Pass());
root->AddChild(scrollbar.PassAs<LayerImpl>());
host_impl_->active_tree()->SetRootLayer(root.Pass());
+ host_impl_->active_tree()->SetViewportLayersFromIds(1, 2, Layer::INVALID_ID);
host_impl_->active_tree()->DidBecomeActive();
DrawFrame();
- LayerImpl* root_scroll = host_impl_->active_tree()->RootScrollLayer();
+ LayerImpl* root_scroll =
+ host_impl_->active_tree()->InnerViewportScrollLayer();
ASSERT_TRUE(root_scroll->scrollbar_animation_controller());
ScrollbarAnimationControllerThinning* scrollbar_animation_controller =
static_cast<ScrollbarAnimationControllerThinning*>(
@@ -1403,7 +1640,7 @@ TEST_F(LayerTreeHostImplTest, CompositorFrameMetadata) {
}
}
-class DidDrawCheckLayer : public TiledLayerImpl {
+class DidDrawCheckLayer : public LayerImpl {
public:
static scoped_ptr<LayerImpl> Create(LayerTreeImpl* tree_impl, int id) {
return scoped_ptr<LayerImpl>(new DidDrawCheckLayer(tree_impl, id));
@@ -1414,18 +1651,18 @@ class DidDrawCheckLayer : public TiledLayerImpl {
will_draw_called_ = true;
if (will_draw_returns_false_)
return false;
- return TiledLayerImpl::WillDraw(draw_mode, provider);
+ return LayerImpl::WillDraw(draw_mode, provider);
}
virtual void AppendQuads(QuadSink* quad_sink,
AppendQuadsData* append_quads_data) OVERRIDE {
append_quads_called_ = true;
- TiledLayerImpl::AppendQuads(quad_sink, append_quads_data);
+ LayerImpl::AppendQuads(quad_sink, append_quads_data);
}
virtual void DidDraw(ResourceProvider* provider) OVERRIDE {
did_draw_called_ = true;
- TiledLayerImpl::DidDraw(provider);
+ LayerImpl::DidDraw(provider);
}
bool will_draw_called() const { return will_draw_called_; }
@@ -1442,23 +1679,15 @@ class DidDrawCheckLayer : public TiledLayerImpl {
protected:
DidDrawCheckLayer(LayerTreeImpl* tree_impl, int id)
- : TiledLayerImpl(tree_impl, id),
+ : LayerImpl(tree_impl, id),
will_draw_returns_false_(false),
will_draw_called_(false),
append_quads_called_(false),
did_draw_called_(false) {
- SetAnchorPoint(gfx::PointF());
SetBounds(gfx::Size(10, 10));
SetContentBounds(gfx::Size(10, 10));
SetDrawsContent(true);
- set_skips_draw(false);
draw_properties().visible_content_rect = gfx::Rect(0, 0, 10, 10);
-
- scoped_ptr<LayerTilingData> tiler =
- LayerTilingData::Create(gfx::Size(100, 100),
- LayerTilingData::HAS_BORDER_TEXELS);
- tiler->SetBounds(content_bounds());
- SetTilingData(*tiler.get());
}
private:
@@ -1482,7 +1711,7 @@ TEST_F(LayerTreeHostImplTest, WillDrawReturningFalseDoesNotCall) {
{
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect(10, 10)));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
host_impl_->DidDrawAllLayers(frame);
@@ -1491,13 +1720,15 @@ TEST_F(LayerTreeHostImplTest, WillDrawReturningFalseDoesNotCall) {
EXPECT_TRUE(layer->did_draw_called());
}
+ host_impl_->SetViewportDamage(gfx::Rect(10, 10));
+
{
LayerTreeHostImpl::FrameData frame;
layer->set_will_draw_returns_false();
layer->ClearDidDrawCheck();
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect(10, 10)));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
host_impl_->DidDrawAllLayers(frame);
@@ -1529,7 +1760,7 @@ TEST_F(LayerTreeHostImplTest, DidDrawNotCalledOnHiddenLayer) {
EXPECT_FALSE(layer->will_draw_called());
EXPECT_FALSE(layer->did_draw_called());
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
host_impl_->DidDrawAllLayers(frame);
@@ -1544,7 +1775,7 @@ TEST_F(LayerTreeHostImplTest, DidDrawNotCalledOnHiddenLayer) {
EXPECT_FALSE(layer->will_draw_called());
EXPECT_FALSE(layer->did_draw_called());
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
host_impl_->DidDrawAllLayers(frame);
@@ -1583,7 +1814,7 @@ TEST_F(LayerTreeHostImplTest, WillDrawNotCalledOnOccludedLayer) {
EXPECT_FALSE(top_layer->will_draw_called());
EXPECT_FALSE(top_layer->did_draw_called());
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
host_impl_->DidDrawAllLayers(frame);
@@ -1608,14 +1839,14 @@ TEST_F(LayerTreeHostImplTest, DidDrawCalledOnAllLayers) {
static_cast<DidDrawCheckLayer*>(layer1->children()[0]);
layer1->SetOpacity(0.3f);
- layer1->SetPreserves3d(false);
+ layer1->SetShouldFlattenTransform(true);
EXPECT_FALSE(root->did_draw_called());
EXPECT_FALSE(layer1->did_draw_called());
EXPECT_FALSE(layer2->did_draw_called());
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
host_impl_->DidDrawAllLayers(frame);
@@ -1632,123 +1863,253 @@ class MissingTextureAnimatingLayer : public DidDrawCheckLayer {
static scoped_ptr<LayerImpl> Create(LayerTreeImpl* tree_impl,
int id,
bool tile_missing,
- bool skips_draw,
+ bool had_incomplete_tile,
bool animating,
ResourceProvider* resource_provider) {
- return scoped_ptr<LayerImpl>(new MissingTextureAnimatingLayer(
- tree_impl,
- id,
- tile_missing,
- skips_draw,
- animating,
- resource_provider));
+ return scoped_ptr<LayerImpl>(
+ new MissingTextureAnimatingLayer(tree_impl,
+ id,
+ tile_missing,
+ had_incomplete_tile,
+ animating,
+ resource_provider));
+ }
+
+ virtual void AppendQuads(QuadSink* quad_sink,
+ AppendQuadsData* append_quads_data) OVERRIDE {
+ LayerImpl::AppendQuads(quad_sink, append_quads_data);
+ if (had_incomplete_tile_)
+ append_quads_data->had_incomplete_tile = true;
+ if (tile_missing_)
+ append_quads_data->num_missing_tiles++;
}
private:
MissingTextureAnimatingLayer(LayerTreeImpl* tree_impl,
int id,
bool tile_missing,
- bool skips_draw,
+ bool had_incomplete_tile,
bool animating,
ResourceProvider* resource_provider)
- : DidDrawCheckLayer(tree_impl, id) {
- scoped_ptr<LayerTilingData> tiling_data =
- LayerTilingData::Create(gfx::Size(10, 10),
- LayerTilingData::NO_BORDER_TEXELS);
- tiling_data->SetBounds(bounds());
- SetTilingData(*tiling_data.get());
- set_skips_draw(skips_draw);
- if (!tile_missing) {
- ResourceProvider::ResourceId resource =
- resource_provider->CreateResource(gfx::Size(1, 1),
- GL_CLAMP_TO_EDGE,
- ResourceProvider::TextureUsageAny,
- RGBA_8888);
- resource_provider->AllocateForTesting(resource);
- PushTileProperties(0, 0, resource, gfx::Rect(), false);
- }
+ : DidDrawCheckLayer(tree_impl, id),
+ tile_missing_(tile_missing),
+ had_incomplete_tile_(had_incomplete_tile) {
if (animating)
AddAnimatedTransformToLayer(this, 10.0, 3, 0);
}
+
+ bool tile_missing_;
+ bool had_incomplete_tile_;
};
-TEST_F(LayerTreeHostImplTest, PrepareToDrawFailsWhenAnimationUsesCheckerboard) {
- // When the texture is not missing, we draw as usual.
+TEST_F(LayerTreeHostImplTest, PrepareToDrawSucceedsOnDefault) {
host_impl_->active_tree()->SetRootLayer(
DidDrawCheckLayer::Create(host_impl_->active_tree(), 1));
DidDrawCheckLayer* root =
static_cast<DidDrawCheckLayer*>(host_impl_->active_tree()->root_layer());
+
+ bool tile_missing = false;
+ bool had_incomplete_tile = false;
+ bool is_animating = false;
root->AddChild(
MissingTextureAnimatingLayer::Create(host_impl_->active_tree(),
2,
- false,
- false,
- true,
+ tile_missing,
+ had_incomplete_tile,
+ is_animating,
host_impl_->resource_provider()));
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
host_impl_->DidDrawAllLayers(frame);
+}
- // When a texture is missing and we're not animating, we draw as usual with
- // checkerboarding.
+TEST_F(LayerTreeHostImplTest, PrepareToDrawSucceedsWithAnimatedLayer) {
+ host_impl_->active_tree()->SetRootLayer(
+ DidDrawCheckLayer::Create(host_impl_->active_tree(), 1));
+ DidDrawCheckLayer* root =
+ static_cast<DidDrawCheckLayer*>(host_impl_->active_tree()->root_layer());
+ bool tile_missing = false;
+ bool had_incomplete_tile = false;
+ bool is_animating = true;
+ root->AddChild(
+ MissingTextureAnimatingLayer::Create(host_impl_->active_tree(),
+ 2,
+ tile_missing,
+ had_incomplete_tile,
+ is_animating,
+ host_impl_->resource_provider()));
+
+ LayerTreeHostImpl::FrameData frame;
+
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
+ host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DidDrawAllLayers(frame);
+}
+
+TEST_F(LayerTreeHostImplTest, PrepareToDrawSucceedsWithMissingTiles) {
host_impl_->active_tree()->SetRootLayer(
DidDrawCheckLayer::Create(host_impl_->active_tree(), 3));
- root =
+ DidDrawCheckLayer* root =
static_cast<DidDrawCheckLayer*>(host_impl_->active_tree()->root_layer());
+
+ bool tile_missing = true;
+ bool had_incomplete_tile = false;
+ bool is_animating = false;
root->AddChild(
MissingTextureAnimatingLayer::Create(host_impl_->active_tree(),
4,
- true,
- false,
- false,
+ tile_missing,
+ had_incomplete_tile,
+ is_animating,
host_impl_->resource_provider()));
+ LayerTreeHostImpl::FrameData frame;
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
+ host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DidDrawAllLayers(frame);
+}
+
+TEST_F(LayerTreeHostImplTest, PrepareToDrawSucceedsWithIncompleteTile) {
+ host_impl_->active_tree()->SetRootLayer(
+ DidDrawCheckLayer::Create(host_impl_->active_tree(), 3));
+ DidDrawCheckLayer* root =
+ static_cast<DidDrawCheckLayer*>(host_impl_->active_tree()->root_layer());
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ bool tile_missing = false;
+ bool had_incomplete_tile = true;
+ bool is_animating = false;
+ root->AddChild(
+ MissingTextureAnimatingLayer::Create(host_impl_->active_tree(),
+ 4,
+ tile_missing,
+ had_incomplete_tile,
+ is_animating,
+ host_impl_->resource_provider()));
+ LayerTreeHostImpl::FrameData frame;
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
host_impl_->DidDrawAllLayers(frame);
+}
- // When a texture is missing and we're animating, we don't want to draw
- // anything.
+TEST_F(LayerTreeHostImplTest,
+ PrepareToDrawFailsWithAnimationAndMissingTilesUsesCheckerboard) {
host_impl_->active_tree()->SetRootLayer(
DidDrawCheckLayer::Create(host_impl_->active_tree(), 5));
- root =
+ DidDrawCheckLayer* root =
static_cast<DidDrawCheckLayer*>(host_impl_->active_tree()->root_layer());
+ bool tile_missing = true;
+ bool had_incomplete_tile = false;
+ bool is_animating = true;
root->AddChild(
MissingTextureAnimatingLayer::Create(host_impl_->active_tree(),
6,
- true,
- false,
- true,
+ tile_missing,
+ had_incomplete_tile,
+ is_animating,
host_impl_->resource_provider()));
+ LayerTreeHostImpl::FrameData frame;
+ EXPECT_EQ(DRAW_ABORTED_CHECKERBOARD_ANIMATIONS,
+ host_impl_->PrepareToDraw(&frame));
+ host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DidDrawAllLayers(frame);
+}
- EXPECT_FALSE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+TEST_F(LayerTreeHostImplTest,
+ PrepareToDrawSucceedsWithAnimationAndIncompleteTiles) {
+ host_impl_->active_tree()->SetRootLayer(
+ DidDrawCheckLayer::Create(host_impl_->active_tree(), 5));
+ DidDrawCheckLayer* root =
+ static_cast<DidDrawCheckLayer*>(host_impl_->active_tree()->root_layer());
+ bool tile_missing = false;
+ bool had_incomplete_tile = true;
+ bool is_animating = true;
+ root->AddChild(
+ MissingTextureAnimatingLayer::Create(host_impl_->active_tree(),
+ 6,
+ tile_missing,
+ had_incomplete_tile,
+ is_animating,
+ host_impl_->resource_provider()));
+ LayerTreeHostImpl::FrameData frame;
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
host_impl_->DidDrawAllLayers(frame);
+}
- // When the layer skips draw and we're animating, we still draw the frame.
+TEST_F(LayerTreeHostImplTest, PrepareToDrawSucceedsWhenHighResRequired) {
host_impl_->active_tree()->SetRootLayer(
DidDrawCheckLayer::Create(host_impl_->active_tree(), 7));
- root =
+ DidDrawCheckLayer* root =
static_cast<DidDrawCheckLayer*>(host_impl_->active_tree()->root_layer());
+ bool tile_missing = false;
+ bool had_incomplete_tile = false;
+ bool is_animating = false;
root->AddChild(
MissingTextureAnimatingLayer::Create(host_impl_->active_tree(),
8,
- false,
- true,
- true,
+ tile_missing,
+ had_incomplete_tile,
+ is_animating,
host_impl_->resource_provider()));
+ host_impl_->active_tree()->SetRequiresHighResToDraw();
+ LayerTreeHostImpl::FrameData frame;
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
+ host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DidDrawAllLayers(frame);
+}
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+TEST_F(LayerTreeHostImplTest,
+ PrepareToDrawFailsWhenHighResRequiredAndIncompleteTiles) {
+ host_impl_->active_tree()->SetRootLayer(
+ DidDrawCheckLayer::Create(host_impl_->active_tree(), 7));
+ DidDrawCheckLayer* root =
+ static_cast<DidDrawCheckLayer*>(host_impl_->active_tree()->root_layer());
+ bool tile_missing = false;
+ bool had_incomplete_tile = true;
+ bool is_animating = false;
+ root->AddChild(
+ MissingTextureAnimatingLayer::Create(host_impl_->active_tree(),
+ 8,
+ tile_missing,
+ had_incomplete_tile,
+ is_animating,
+ host_impl_->resource_provider()));
+ host_impl_->active_tree()->SetRequiresHighResToDraw();
+ LayerTreeHostImpl::FrameData frame;
+ EXPECT_EQ(DRAW_ABORTED_MISSING_HIGH_RES_CONTENT,
+ host_impl_->PrepareToDraw(&frame));
+ host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
+ host_impl_->DidDrawAllLayers(frame);
+}
+
+TEST_F(LayerTreeHostImplTest,
+ PrepareToDrawSucceedsWhenHighResRequiredAndMissingTile) {
+ host_impl_->active_tree()->SetRootLayer(
+ DidDrawCheckLayer::Create(host_impl_->active_tree(), 7));
+ DidDrawCheckLayer* root =
+ static_cast<DidDrawCheckLayer*>(host_impl_->active_tree()->root_layer());
+ bool tile_missing = true;
+ bool had_incomplete_tile = false;
+ bool is_animating = false;
+ root->AddChild(
+ MissingTextureAnimatingLayer::Create(host_impl_->active_tree(),
+ 8,
+ tile_missing,
+ had_incomplete_tile,
+ is_animating,
+ host_impl_->resource_provider()));
+ host_impl_->active_tree()->SetRequiresHighResToDraw();
+ LayerTreeHostImpl::FrameData frame;
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
host_impl_->DidDrawAllLayers(frame);
}
TEST_F(LayerTreeHostImplTest, ScrollRootIgnored) {
scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1);
- root->SetScrollable(false);
+ root->SetScrollClipLayer(Layer::INVALID_ID);
host_impl_->active_tree()->SetRootLayer(root.Pass());
DrawFrame();
@@ -1759,67 +2120,189 @@ TEST_F(LayerTreeHostImplTest, ScrollRootIgnored) {
EXPECT_FALSE(did_request_commit_);
}
-TEST_F(LayerTreeHostImplTest, ScrollNonScrollableRootWithTopControls) {
- LayerTreeSettings settings;
- settings.calculate_top_controls_position = true;
- settings.top_controls_height = 50;
+class LayerTreeHostImplTopControlsTest : public LayerTreeHostImplTest {
+ public:
+ LayerTreeHostImplTopControlsTest()
+ // Make the clip size the same as the layer (content) size so the layer is
+ // non-scrollable.
+ : layer_size_(10, 10),
+ clip_size_(layer_size_) {
+ settings_.calculate_top_controls_position = true;
+ settings_.top_controls_height = 50;
- CreateHostImpl(settings, CreateOutputSurface());
+ viewport_size_ =
+ gfx::Size(clip_size_.width(),
+ clip_size_.height() + settings_.top_controls_height);
+ }
- gfx::Size layer_size(5, 5);
- scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1);
- root->SetScrollable(true);
- root->SetMaxScrollOffset(gfx::Vector2d(layer_size.width(),
- layer_size.height()));
- root->SetBounds(layer_size);
- root->SetContentBounds(layer_size);
- root->SetPosition(gfx::PointF());
- root->SetAnchorPoint(gfx::PointF());
- root->SetDrawsContent(false);
- host_impl_->active_tree()->SetRootLayer(root.Pass());
- host_impl_->active_tree()->FindRootScrollLayer();
+ void SetupTopControlsAndScrollLayer() {
+ CreateHostImpl(settings_, CreateOutputSurface());
+
+ scoped_ptr<LayerImpl> root =
+ LayerImpl::Create(host_impl_->active_tree(), 1);
+ scoped_ptr<LayerImpl> root_clip =
+ LayerImpl::Create(host_impl_->active_tree(), 2);
+ root_clip->SetBounds(clip_size_);
+ root->SetScrollClipLayer(root_clip->id());
+ root->SetBounds(layer_size_);
+ root->SetContentBounds(layer_size_);
+ root->SetPosition(gfx::PointF());
+ root->SetDrawsContent(false);
+ root->SetIsContainerForFixedPositionLayers(true);
+ int inner_viewport_scroll_layer_id = root->id();
+ int page_scale_layer_id = root_clip->id();
+ root_clip->AddChild(root.Pass());
+ host_impl_->active_tree()->SetRootLayer(root_clip.Pass());
+ host_impl_->active_tree()->SetViewportLayersFromIds(
+ page_scale_layer_id, inner_viewport_scroll_layer_id, Layer::INVALID_ID);
+ // Set a viewport size that is large enough to contain both the top controls
+ // and some content.
+ host_impl_->SetViewportSize(viewport_size_);
+ LayerImpl* root_clip_ptr = host_impl_->active_tree()->root_layer();
+ EXPECT_EQ(clip_size_, root_clip_ptr->bounds());
+ }
+
+ protected:
+ gfx::Size layer_size_;
+ gfx::Size clip_size_;
+ gfx::Size viewport_size_;
+
+ LayerTreeSettings settings_;
+}; // class LayerTreeHostImplTopControlsTest
+
+TEST_F(LayerTreeHostImplTopControlsTest, ScrollTopControlsByFractionalAmount) {
+ SetupTopControlsAndScrollLayer();
DrawFrame();
- EXPECT_EQ(InputHandler::ScrollIgnored,
+ EXPECT_EQ(InputHandler::ScrollStarted,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+
+ // Make the test scroll delta a fractional amount, to verify that the
+ // fixed container size delta is (1) non-zero, and (2) fractional, and
+ // (3) matches the movement of the top controls.
+ gfx::Vector2dF top_controls_scroll_delta(0.f, 5.25f);
+ host_impl_->top_controls_manager()->ScrollBegin();
+ host_impl_->top_controls_manager()->ScrollBy(top_controls_scroll_delta);
+ host_impl_->top_controls_manager()->ScrollEnd();
+
+ LayerImpl* inner_viewport_scroll_layer =
+ host_impl_->active_tree()->InnerViewportScrollLayer();
+ DCHECK(inner_viewport_scroll_layer);
+ host_impl_->ScrollEnd();
+ EXPECT_EQ(top_controls_scroll_delta,
+ inner_viewport_scroll_layer->FixedContainerSizeDelta());
+}
+
+TEST_F(LayerTreeHostImplTopControlsTest, ScrollTopControlsWithPageScale) {
+ SetupTopControlsAndScrollLayer();
+ DrawFrame();
+
+ EXPECT_EQ(InputHandler::ScrollStarted,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+
+ float page_scale = 1.5f;
+ host_impl_->active_tree()->SetPageScaleFactorAndLimits(page_scale, 1.f, 2.f);
+
+ gfx::Vector2dF top_controls_scroll_delta(0.f, 5.f);
+ gfx::Vector2dF expected_container_size_delta =
+ ScaleVector2d(top_controls_scroll_delta, 1.f / page_scale);
+ host_impl_->top_controls_manager()->ScrollBegin();
+ host_impl_->top_controls_manager()->ScrollBy(top_controls_scroll_delta);
+ host_impl_->top_controls_manager()->ScrollEnd();
+
+ LayerImpl* inner_viewport_scroll_layer =
+ host_impl_->active_tree()->InnerViewportScrollLayer();
+ DCHECK(inner_viewport_scroll_layer);
+ host_impl_->ScrollEnd();
+
+ // Use a tolerance that requires the container size delta to be within 0.01
+ // pixels.
+ double tolerance = 0.0001;
+ EXPECT_LT(
+ (expected_container_size_delta -
+ inner_viewport_scroll_layer->FixedContainerSizeDelta()).LengthSquared(),
+ tolerance);
+}
+
+TEST_F(LayerTreeHostImplTopControlsTest,
+ ScrollNonScrollableRootWithTopControls) {
+ SetupTopControlsAndScrollLayer();
+ DrawFrame();
+
+ EXPECT_EQ(InputHandler::ScrollStarted,
host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
host_impl_->top_controls_manager()->ScrollBegin();
host_impl_->top_controls_manager()->ScrollBy(gfx::Vector2dF(0.f, 50.f));
host_impl_->top_controls_manager()->ScrollEnd();
- EXPECT_EQ(host_impl_->top_controls_manager()->content_top_offset(), 0.f);
+ EXPECT_EQ(0.f, host_impl_->top_controls_manager()->content_top_offset());
+ // Now that top controls have moved, expect the clip to resize.
+ LayerImpl* root_clip_ptr = host_impl_->active_tree()->root_layer();
+ EXPECT_EQ(viewport_size_, root_clip_ptr->bounds());
+
+ host_impl_->ScrollEnd();
EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(),
- InputHandler::Gesture));
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+
+ float scroll_increment_y = -25.f;
+ host_impl_->top_controls_manager()->ScrollBegin();
+ host_impl_->top_controls_manager()->ScrollBy(
+ gfx::Vector2dF(0.f, scroll_increment_y));
+ EXPECT_EQ(-scroll_increment_y,
+ host_impl_->top_controls_manager()->content_top_offset());
+ // Now that top controls have moved, expect the clip to resize.
+ EXPECT_EQ(gfx::Size(viewport_size_.width(),
+ viewport_size_.height() + scroll_increment_y),
+ root_clip_ptr->bounds());
+
+ host_impl_->top_controls_manager()->ScrollBy(
+ gfx::Vector2dF(0.f, scroll_increment_y));
+ host_impl_->top_controls_manager()->ScrollEnd();
+ EXPECT_EQ(-2 * scroll_increment_y,
+ host_impl_->top_controls_manager()->content_top_offset());
+ // Now that top controls have moved, expect the clip to resize.
+ EXPECT_EQ(clip_size_, root_clip_ptr->bounds());
+
+ host_impl_->ScrollEnd();
+
+ // Verify the layer is once-again non-scrollable.
+ EXPECT_EQ(
+ gfx::Vector2d(),
+ host_impl_->active_tree()->InnerViewportScrollLayer()->MaxScrollOffset());
+
+ EXPECT_EQ(InputHandler::ScrollStarted,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
}
TEST_F(LayerTreeHostImplTest, ScrollNonCompositedRoot) {
// Test the configuration where a non-composited root layer is embedded in a
// scrollable outer layer.
gfx::Size surface_size(10, 10);
+ gfx::Size contents_size(20, 20);
scoped_ptr<LayerImpl> content_layer =
LayerImpl::Create(host_impl_->active_tree(), 1);
content_layer->SetDrawsContent(true);
content_layer->SetPosition(gfx::PointF());
- content_layer->SetAnchorPoint(gfx::PointF());
- content_layer->SetBounds(surface_size);
- content_layer->SetContentBounds(gfx::Size(surface_size.width() * 2,
- surface_size.height() * 2));
+ content_layer->SetBounds(contents_size);
+ content_layer->SetContentBounds(contents_size);
content_layer->SetContentsScale(2.f, 2.f);
+ scoped_ptr<LayerImpl> scroll_clip_layer =
+ LayerImpl::Create(host_impl_->active_tree(), 3);
+ scroll_clip_layer->SetBounds(surface_size);
+
scoped_ptr<LayerImpl> scroll_layer =
LayerImpl::Create(host_impl_->active_tree(), 2);
- scroll_layer->SetScrollable(true);
- scroll_layer->SetMaxScrollOffset(gfx::Vector2d(surface_size.width(),
- surface_size.height()));
- scroll_layer->SetBounds(surface_size);
- scroll_layer->SetContentBounds(surface_size);
+ scroll_layer->SetScrollClipLayer(3);
+ scroll_layer->SetBounds(contents_size);
+ scroll_layer->SetContentBounds(contents_size);
scroll_layer->SetPosition(gfx::PointF());
- scroll_layer->SetAnchorPoint(gfx::PointF());
scroll_layer->AddChild(content_layer.Pass());
+ scroll_clip_layer->AddChild(scroll_layer.Pass());
- host_impl_->active_tree()->SetRootLayer(scroll_layer.Pass());
+ host_impl_->active_tree()->SetRootLayer(scroll_clip_layer.Pass());
host_impl_->SetViewportSize(surface_size);
DrawFrame();
@@ -1834,10 +2317,11 @@ TEST_F(LayerTreeHostImplTest, ScrollNonCompositedRoot) {
TEST_F(LayerTreeHostImplTest, ScrollChildCallsCommitAndRedraw) {
gfx::Size surface_size(10, 10);
+ gfx::Size contents_size(20, 20);
scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1);
root->SetBounds(surface_size);
- root->SetContentBounds(surface_size);
- root->AddChild(CreateScrollableLayer(2, surface_size));
+ root->SetContentBounds(contents_size);
+ root->AddChild(CreateScrollableLayer(2, contents_size, root.get()));
host_impl_->active_tree()->SetRootLayer(root.Pass());
host_impl_->SetViewportSize(surface_size);
DrawFrame();
@@ -1854,7 +2338,7 @@ TEST_F(LayerTreeHostImplTest, ScrollChildCallsCommitAndRedraw) {
TEST_F(LayerTreeHostImplTest, ScrollMissesChild) {
gfx::Size surface_size(10, 10);
scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1);
- root->AddChild(CreateScrollableLayer(2, surface_size));
+ root->AddChild(CreateScrollableLayer(2, surface_size, root.get()));
host_impl_->active_tree()->SetRootLayer(root.Pass());
host_impl_->SetViewportSize(surface_size);
DrawFrame();
@@ -1871,7 +2355,8 @@ TEST_F(LayerTreeHostImplTest, ScrollMissesChild) {
TEST_F(LayerTreeHostImplTest, ScrollMissesBackfacingChild) {
gfx::Size surface_size(10, 10);
scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1);
- scoped_ptr<LayerImpl> child = CreateScrollableLayer(2, surface_size);
+ scoped_ptr<LayerImpl> child =
+ CreateScrollableLayer(2, surface_size, root.get());
host_impl_->SetViewportSize(surface_size);
gfx::Transform matrix;
@@ -1894,14 +2379,21 @@ TEST_F(LayerTreeHostImplTest, ScrollMissesBackfacingChild) {
TEST_F(LayerTreeHostImplTest, ScrollBlockedByContentLayer) {
gfx::Size surface_size(10, 10);
- scoped_ptr<LayerImpl> content_layer = CreateScrollableLayer(1, surface_size);
+ scoped_ptr<LayerImpl> clip_layer =
+ LayerImpl::Create(host_impl_->active_tree(), 3);
+ scoped_ptr<LayerImpl> content_layer =
+ CreateScrollableLayer(1, surface_size, clip_layer.get());
content_layer->SetShouldScrollOnMainThread(true);
- content_layer->SetScrollable(false);
+ content_layer->SetScrollClipLayer(Layer::INVALID_ID);
- scoped_ptr<LayerImpl> scroll_layer = CreateScrollableLayer(2, surface_size);
+ // Note: we can use the same clip layer for both since both calls to
+ // CreateScrollableLayer() use the same surface size.
+ scoped_ptr<LayerImpl> scroll_layer =
+ CreateScrollableLayer(2, surface_size, clip_layer.get());
scroll_layer->AddChild(content_layer.Pass());
+ clip_layer->AddChild(scroll_layer.Pass());
- host_impl_->active_tree()->SetRootLayer(scroll_layer.Pass());
+ host_impl_->active_tree()->SetRootLayer(clip_layer.Pass());
host_impl_->SetViewportSize(surface_size);
DrawFrame();
@@ -1913,21 +2405,33 @@ TEST_F(LayerTreeHostImplTest, ScrollBlockedByContentLayer) {
}
TEST_F(LayerTreeHostImplTest, ScrollRootAndChangePageScaleOnMainThread) {
- gfx::Size surface_size(10, 10);
+ gfx::Size surface_size(20, 20);
+ gfx::Size viewport_size(10, 10);
float page_scale = 2.f;
scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1);
- scoped_ptr<LayerImpl> root_scrolling = CreateScrollableLayer(2, surface_size);
- root->AddChild(root_scrolling.Pass());
+ scoped_ptr<LayerImpl> root_clip =
+ LayerImpl::Create(host_impl_->active_tree(), 2);
+ scoped_ptr<LayerImpl> root_scrolling =
+ CreateScrollableLayer(3, surface_size, root_clip.get());
+ EXPECT_EQ(viewport_size, root_clip->bounds());
+ root_scrolling->SetIsContainerForFixedPositionLayers(true);
+ root_clip->AddChild(root_scrolling.Pass());
+ root->AddChild(root_clip.Pass());
host_impl_->active_tree()->SetRootLayer(root.Pass());
+ // The behaviour in this test assumes the page scale is applied at a layer
+ // above the clip layer.
+ host_impl_->active_tree()->SetViewportLayersFromIds(1, 3, Layer::INVALID_ID);
host_impl_->active_tree()->DidBecomeActive();
- host_impl_->SetViewportSize(surface_size);
+ host_impl_->SetViewportSize(viewport_size);
DrawFrame();
- LayerImpl* root_scroll = host_impl_->active_tree()->RootScrollLayer();
+ LayerImpl* root_scroll =
+ host_impl_->active_tree()->InnerViewportScrollLayer();
+ EXPECT_EQ(viewport_size, root_scroll->scroll_clip_layer()->bounds());
gfx::Vector2d scroll_delta(0, 10);
gfx::Vector2d expected_scroll_delta = scroll_delta;
- gfx::Vector2d expected_max_scroll = root_scroll->max_scroll_offset();
+ gfx::Vector2d expected_max_scroll = root_scroll->MaxScrollOffset();
EXPECT_EQ(InputHandler::ScrollStarted,
host_impl_->ScrollBegin(gfx::Point(5, 5),
InputHandler::Wheel));
@@ -1943,7 +2447,7 @@ TEST_F(LayerTreeHostImplTest, ScrollRootAndChangePageScaleOnMainThread) {
ExpectContains(*scroll_info.get(), root_scroll->id(), expected_scroll_delta);
// The scroll range should also have been updated.
- EXPECT_EQ(expected_max_scroll, root_scroll->max_scroll_offset());
+ EXPECT_EQ(expected_max_scroll, root_scroll->MaxScrollOffset());
// The page scale delta remains constant because the impl thread did not
// scale.
@@ -1951,22 +2455,34 @@ TEST_F(LayerTreeHostImplTest, ScrollRootAndChangePageScaleOnMainThread) {
}
TEST_F(LayerTreeHostImplTest, ScrollRootAndChangePageScaleOnImplThread) {
- gfx::Size surface_size(10, 10);
+ gfx::Size surface_size(20, 20);
+ gfx::Size viewport_size(10, 10);
float page_scale = 2.f;
scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1);
- scoped_ptr<LayerImpl> root_scrolling = CreateScrollableLayer(2, surface_size);
- root->AddChild(root_scrolling.Pass());
+ scoped_ptr<LayerImpl> root_clip =
+ LayerImpl::Create(host_impl_->active_tree(), 2);
+ scoped_ptr<LayerImpl> root_scrolling =
+ CreateScrollableLayer(3, surface_size, root_clip.get());
+ EXPECT_EQ(viewport_size, root_clip->bounds());
+ root_scrolling->SetIsContainerForFixedPositionLayers(true);
+ root_clip->AddChild(root_scrolling.Pass());
+ root->AddChild(root_clip.Pass());
host_impl_->active_tree()->SetRootLayer(root.Pass());
+ // The behaviour in this test assumes the page scale is applied at a layer
+ // above the clip layer.
+ host_impl_->active_tree()->SetViewportLayersFromIds(1, 3, Layer::INVALID_ID);
host_impl_->active_tree()->DidBecomeActive();
- host_impl_->SetViewportSize(surface_size);
+ host_impl_->SetViewportSize(viewport_size);
host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f, 1.f, page_scale);
DrawFrame();
- LayerImpl* root_scroll = host_impl_->active_tree()->RootScrollLayer();
+ LayerImpl* root_scroll =
+ host_impl_->active_tree()->InnerViewportScrollLayer();
+ EXPECT_EQ(viewport_size, root_scroll->scroll_clip_layer()->bounds());
gfx::Vector2d scroll_delta(0, 10);
gfx::Vector2d expected_scroll_delta = scroll_delta;
- gfx::Vector2d expected_max_scroll = root_scroll->max_scroll_offset();
+ gfx::Vector2d expected_max_scroll = root_scroll->MaxScrollOffset();
EXPECT_EQ(InputHandler::ScrollStarted,
host_impl_->ScrollBegin(gfx::Point(5, 5),
InputHandler::Wheel));
@@ -1986,7 +2502,7 @@ TEST_F(LayerTreeHostImplTest, ScrollRootAndChangePageScaleOnImplThread) {
ExpectContains(*scroll_info.get(), root_scroll->id(), expected_scroll_delta);
// The scroll range should also have been updated.
- EXPECT_EQ(expected_max_scroll, root_scroll->max_scroll_offset());
+ EXPECT_EQ(expected_max_scroll, root_scroll->MaxScrollOffset());
// The page scale delta should match the new scale on the impl side.
EXPECT_EQ(page_scale, host_impl_->active_tree()->total_page_scale_factor());
@@ -2007,9 +2523,12 @@ TEST_F(LayerTreeHostImplTest, PageScaleDeltaAppliedToRootScrollLayerOnly) {
LayerImpl* root = host_impl_->active_tree()->root_layer();
LayerImpl* child = scroll->children()[0];
+ scoped_ptr<LayerImpl> scrollable_child_clip =
+ LayerImpl::Create(host_impl_->active_tree(), 6);
scoped_ptr<LayerImpl> scrollable_child =
- CreateScrollableLayer(4, surface_size);
- child->AddChild(scrollable_child.Pass());
+ CreateScrollableLayer(7, surface_size, scrollable_child_clip.get());
+ scrollable_child_clip->AddChild(scrollable_child.Pass());
+ child->AddChild(scrollable_child_clip.Pass());
LayerImpl* grand_child = child->children()[0];
// Set new page scale on impl thread by pinching.
@@ -2032,7 +2551,7 @@ TEST_F(LayerTreeHostImplTest, PageScaleDeltaAppliedToRootScrollLayerOnly) {
// Make sure all the layers are drawn with the page scale delta applied, i.e.,
// the page scale delta on the root layer is applied hierarchically.
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
host_impl_->DidDrawAllLayers(frame);
@@ -2049,27 +2568,31 @@ TEST_F(LayerTreeHostImplTest, PageScaleDeltaAppliedToRootScrollLayerOnly) {
}
TEST_F(LayerTreeHostImplTest, ScrollChildAndChangePageScaleOnMainThread) {
- gfx::Size surface_size(10, 10);
+ gfx::Size surface_size(30, 30);
scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1);
+ root->SetBounds(gfx::Size(5, 5));
scoped_ptr<LayerImpl> root_scrolling =
LayerImpl::Create(host_impl_->active_tree(), 2);
root_scrolling->SetBounds(surface_size);
root_scrolling->SetContentBounds(surface_size);
- root_scrolling->SetScrollable(true);
+ root_scrolling->SetScrollClipLayer(root->id());
+ root_scrolling->SetIsContainerForFixedPositionLayers(true);
+ LayerImpl* root_scrolling_ptr = root_scrolling.get();
root->AddChild(root_scrolling.Pass());
int child_scroll_layer_id = 3;
- scoped_ptr<LayerImpl> child_scrolling =
- CreateScrollableLayer(child_scroll_layer_id, surface_size);
+ scoped_ptr<LayerImpl> child_scrolling = CreateScrollableLayer(
+ child_scroll_layer_id, surface_size, root_scrolling_ptr);
LayerImpl* child = child_scrolling.get();
- root->AddChild(child_scrolling.Pass());
+ root_scrolling_ptr->AddChild(child_scrolling.Pass());
host_impl_->active_tree()->SetRootLayer(root.Pass());
+ host_impl_->active_tree()->SetViewportLayersFromIds(1, 2, Layer::INVALID_ID);
host_impl_->active_tree()->DidBecomeActive();
host_impl_->SetViewportSize(surface_size);
DrawFrame();
gfx::Vector2d scroll_delta(0, 10);
gfx::Vector2d expected_scroll_delta(scroll_delta);
- gfx::Vector2d expected_max_scroll(child->max_scroll_offset());
+ gfx::Vector2d expected_max_scroll(child->MaxScrollOffset());
EXPECT_EQ(InputHandler::ScrollStarted,
host_impl_->ScrollBegin(gfx::Point(5, 5),
InputHandler::Wheel));
@@ -2088,7 +2611,7 @@ TEST_F(LayerTreeHostImplTest, ScrollChildAndChangePageScaleOnMainThread) {
*scroll_info.get(), child_scroll_layer_id, expected_scroll_delta);
// The scroll range should not have changed.
- EXPECT_EQ(child->max_scroll_offset(), expected_max_scroll);
+ EXPECT_EQ(child->MaxScrollOffset(), expected_max_scroll);
// The page scale delta remains constant because the impl thread did not
// scale.
@@ -2100,19 +2623,26 @@ TEST_F(LayerTreeHostImplTest, ScrollChildBeyondLimit) {
// parent layer is scrolled on the axis on which the child was unable to
// scroll.
gfx::Size surface_size(10, 10);
- scoped_ptr<LayerImpl> root = CreateScrollableLayer(1, surface_size);
+ gfx::Size content_size(20, 20);
+ scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1);
+ root->SetBounds(surface_size);
- scoped_ptr<LayerImpl> grand_child = CreateScrollableLayer(3, surface_size);
- grand_child->SetScrollOffset(gfx::Vector2d(0, 5));
+ scoped_ptr<LayerImpl> grand_child =
+ CreateScrollableLayer(3, content_size, root.get());
- scoped_ptr<LayerImpl> child = CreateScrollableLayer(2, surface_size);
- child->SetScrollOffset(gfx::Vector2d(3, 0));
+ scoped_ptr<LayerImpl> child =
+ CreateScrollableLayer(2, content_size, root.get());
+ LayerImpl* grand_child_layer = grand_child.get();
child->AddChild(grand_child.Pass());
+ LayerImpl* child_layer = child.get();
root->AddChild(child.Pass());
host_impl_->active_tree()->SetRootLayer(root.Pass());
host_impl_->active_tree()->DidBecomeActive();
host_impl_->SetViewportSize(surface_size);
+ grand_child_layer->SetScrollOffset(gfx::Vector2d(0, 5));
+ child_layer->SetScrollOffset(gfx::Vector2d(3, 0));
+
DrawFrame();
{
gfx::Vector2d scroll_delta(-8, -7);
@@ -2138,22 +2668,33 @@ TEST_F(LayerTreeHostImplTest, ScrollChildBeyondLimit) {
TEST_F(LayerTreeHostImplTest, ScrollWithoutBubbling) {
// Scroll a child layer beyond its maximum scroll range and make sure the
// the scroll doesn't bubble up to the parent layer.
- gfx::Size surface_size(10, 10);
+ gfx::Size surface_size(20, 20);
+ gfx::Size viewport_size(10, 10);
scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1);
- scoped_ptr<LayerImpl> root_scrolling = CreateScrollableLayer(2, surface_size);
+ scoped_ptr<LayerImpl> root_scrolling =
+ CreateScrollableLayer(2, surface_size, root.get());
+ root_scrolling->SetIsContainerForFixedPositionLayers(true);
- scoped_ptr<LayerImpl> grand_child = CreateScrollableLayer(4, surface_size);
- grand_child->SetScrollOffset(gfx::Vector2d(0, 2));
+ scoped_ptr<LayerImpl> grand_child =
+ CreateScrollableLayer(4, surface_size, root.get());
- scoped_ptr<LayerImpl> child = CreateScrollableLayer(3, surface_size);
- child->SetScrollOffset(gfx::Vector2d(0, 3));
+ scoped_ptr<LayerImpl> child =
+ CreateScrollableLayer(3, surface_size, root.get());
+ LayerImpl* grand_child_layer = grand_child.get();
child->AddChild(grand_child.Pass());
+ LayerImpl* child_layer = child.get();
root_scrolling->AddChild(child.Pass());
root->AddChild(root_scrolling.Pass());
+ EXPECT_EQ(viewport_size, root->bounds());
host_impl_->active_tree()->SetRootLayer(root.Pass());
+ host_impl_->active_tree()->SetViewportLayersFromIds(1, 2, Layer::INVALID_ID);
host_impl_->active_tree()->DidBecomeActive();
- host_impl_->SetViewportSize(surface_size);
+ host_impl_->SetViewportSize(viewport_size);
+
+ grand_child_layer->SetScrollOffset(gfx::Vector2d(0, 2));
+ child_layer->SetScrollOffset(gfx::Vector2d(0, 3));
+
DrawFrame();
{
gfx::Vector2d scroll_delta(0, -10);
@@ -2231,20 +2772,29 @@ TEST_F(LayerTreeHostImplTest, ScrollWithoutBubbling) {
ExpectContains(*scroll_info.get(), grand_child->id(), gfx::Vector2d(0, 4));
}
}
-
TEST_F(LayerTreeHostImplTest, ScrollEventBubbling) {
// When we try to scroll a non-scrollable child layer, the scroll delta
// should be applied to one of its ancestors if possible.
gfx::Size surface_size(10, 10);
gfx::Size content_size(20, 20);
- scoped_ptr<LayerImpl> root = CreateScrollableLayer(1, content_size);
- scoped_ptr<LayerImpl> child = CreateScrollableLayer(2, content_size);
+ scoped_ptr<LayerImpl> root_clip =
+ LayerImpl::Create(host_impl_->active_tree(), 3);
+ scoped_ptr<LayerImpl> root =
+ CreateScrollableLayer(1, 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.
+ scoped_ptr<LayerImpl> child =
+ CreateScrollableLayer(2, content_size, root.get());
+ child->SetIsContainerForFixedPositionLayers(true);
+ root->SetBounds(content_size);
- child->SetScrollable(false);
+ int root_scroll_id = root->id();
root->AddChild(child.Pass());
+ root_clip->AddChild(root.Pass());
host_impl_->SetViewportSize(surface_size);
- host_impl_->active_tree()->SetRootLayer(root.Pass());
+ host_impl_->active_tree()->SetRootLayer(root_clip.Pass());
+ host_impl_->active_tree()->SetViewportLayersFromIds(3, 2, Layer::INVALID_ID);
host_impl_->active_tree()->DidBecomeActive();
DrawFrame();
{
@@ -2258,18 +2808,22 @@ TEST_F(LayerTreeHostImplTest, ScrollEventBubbling) {
scoped_ptr<ScrollAndScaleSet> scroll_info =
host_impl_->ProcessScrollDeltas();
- // Only the root should have scrolled.
+ // Only the root scroll should have scrolled.
ASSERT_EQ(scroll_info->scrolls.size(), 1u);
- ExpectContains(*scroll_info.get(),
- host_impl_->active_tree()->root_layer()->id(),
- scroll_delta);
+ ExpectContains(*scroll_info.get(), root_scroll_id, scroll_delta);
}
}
TEST_F(LayerTreeHostImplTest, ScrollBeforeRedraw) {
gfx::Size surface_size(10, 10);
- host_impl_->active_tree()->SetRootLayer(
- CreateScrollableLayer(1, surface_size));
+ scoped_ptr<LayerImpl> root_clip =
+ LayerImpl::Create(host_impl_->active_tree(), 1);
+ scoped_ptr<LayerImpl> root_scroll =
+ CreateScrollableLayer(2, surface_size, root_clip.get());
+ root_scroll->SetIsContainerForFixedPositionLayers(true);
+ root_clip->AddChild(root_scroll.Pass());
+ host_impl_->active_tree()->SetRootLayer(root_clip.Pass());
+ host_impl_->active_tree()->SetViewportLayersFromIds(1, 2, Layer::INVALID_ID);
host_impl_->active_tree()->DidBecomeActive();
host_impl_->SetViewportSize(surface_size);
@@ -2277,8 +2831,14 @@ TEST_F(LayerTreeHostImplTest, ScrollBeforeRedraw) {
// synchronization.
DrawFrame();
host_impl_->active_tree()->DetachLayerTree();
- host_impl_->active_tree()->SetRootLayer(
- CreateScrollableLayer(2, surface_size));
+ scoped_ptr<LayerImpl> root_clip2 =
+ LayerImpl::Create(host_impl_->active_tree(), 3);
+ scoped_ptr<LayerImpl> root_scroll2 =
+ CreateScrollableLayer(4, surface_size, root_clip2.get());
+ root_scroll2->SetIsContainerForFixedPositionLayers(true);
+ root_clip2->AddChild(root_scroll2.Pass());
+ host_impl_->active_tree()->SetRootLayer(root_clip2.Pass());
+ host_impl_->active_tree()->SetViewportLayersFromIds(3, 4, Layer::INVALID_ID);
host_impl_->active_tree()->DidBecomeActive();
// Scrolling should still work even though we did not draw yet.
@@ -2331,22 +2891,32 @@ TEST_F(LayerTreeHostImplTest, ScrollAxisAlignedRotatedLayer) {
TEST_F(LayerTreeHostImplTest, ScrollNonAxisAlignedRotatedLayer) {
LayerImpl* scroll_layer = SetupScrollAndContentsLayers(gfx::Size(100, 100));
- int child_layer_id = 4;
+ int child_clip_layer_id = 6;
+ int child_layer_id = 7;
float child_layer_angle = -20.f;
// Create a child layer that is rotated to a non-axis-aligned angle.
+ scoped_ptr<LayerImpl> clip_layer =
+ LayerImpl::Create(host_impl_->active_tree(), child_clip_layer_id);
scoped_ptr<LayerImpl> child = CreateScrollableLayer(
- child_layer_id,
- scroll_layer->content_bounds());
+ child_layer_id, scroll_layer->content_bounds(), clip_layer.get());
gfx::Transform rotate_transform;
rotate_transform.Translate(-50.0, -50.0);
rotate_transform.Rotate(child_layer_angle);
rotate_transform.Translate(50.0, 50.0);
- child->SetTransform(rotate_transform);
+ clip_layer->SetTransform(rotate_transform);
// Only allow vertical scrolling.
- child->SetMaxScrollOffset(gfx::Vector2d(0, child->content_bounds().height()));
- scroll_layer->AddChild(child.Pass());
+ clip_layer->SetBounds(
+ gfx::Size(child->bounds().width(), child->bounds().height() / 2));
+ // The rotation depends on the layer's transform origin, and the child layer
+ // is a different size than the clip, so make sure the clip layer's origin
+ // lines up over the child.
+ clip_layer->SetTransformOrigin(gfx::Point3F(
+ clip_layer->bounds().width() * 0.5f, clip_layer->bounds().height(), 0.f));
+ LayerImpl* child_ptr = child.get();
+ clip_layer->AddChild(child.Pass());
+ scroll_layer->AddChild(clip_layer.Pass());
gfx::Size surface_size(50, 50);
host_impl_->SetViewportSize(surface_size);
@@ -2376,8 +2946,7 @@ TEST_F(LayerTreeHostImplTest, ScrollNonAxisAlignedRotatedLayer) {
}
{
// Now reset and scroll the same amount horizontally.
- scroll_layer->children()[1]->SetScrollDelta(
- gfx::Vector2dF());
+ child_ptr->SetScrollDelta(gfx::Vector2dF());
gfx::Vector2d gesture_scroll_delta(10, 0);
EXPECT_EQ(InputHandler::ScrollStarted,
host_impl_->ScrollBegin(gfx::Point(1, 1),
@@ -2452,37 +3021,40 @@ TEST_F(LayerTreeHostImplTest, ScrollScaledLayer) {
class TestScrollOffsetDelegate : public LayerScrollOffsetDelegate {
public:
- TestScrollOffsetDelegate() : page_scale_factor_(0.f) {}
+ TestScrollOffsetDelegate()
+ : page_scale_factor_(0.f),
+ min_page_scale_factor_(-1.f),
+ max_page_scale_factor_(-1.f) {}
virtual ~TestScrollOffsetDelegate() {}
- virtual void SetMaxScrollOffset(gfx::Vector2dF max_scroll_offset) OVERRIDE {
- max_scroll_offset_ = max_scroll_offset;
- }
-
- virtual void SetTotalScrollOffset(gfx::Vector2dF new_value) OVERRIDE {
- last_set_scroll_offset_ = new_value;
- }
-
virtual gfx::Vector2dF GetTotalScrollOffset() OVERRIDE {
return getter_return_value_;
}
virtual bool IsExternalFlingActive() const OVERRIDE { return false; }
- virtual void SetTotalPageScaleFactor(float page_scale_factor) OVERRIDE {
- page_scale_factor_ = page_scale_factor;
- }
-
- virtual void SetScrollableSize(gfx::SizeF scrollable_size) OVERRIDE {
+ virtual void UpdateRootLayerState(const gfx::Vector2dF& total_scroll_offset,
+ const gfx::Vector2dF& max_scroll_offset,
+ const gfx::SizeF& scrollable_size,
+ float page_scale_factor,
+ float min_page_scale_factor,
+ float max_page_scale_factor) OVERRIDE {
+ DCHECK(total_scroll_offset.x() <= max_scroll_offset.x());
+ DCHECK(total_scroll_offset.y() <= max_scroll_offset.y());
+ last_set_scroll_offset_ = total_scroll_offset;
+ max_scroll_offset_ = max_scroll_offset;
scrollable_size_ = scrollable_size;
+ page_scale_factor_ = page_scale_factor;
+ min_page_scale_factor_ = min_page_scale_factor;
+ max_page_scale_factor_ = max_page_scale_factor;
}
gfx::Vector2dF last_set_scroll_offset() {
return last_set_scroll_offset_;
}
- void set_getter_return_value(gfx::Vector2dF value) {
+ void set_getter_return_value(const gfx::Vector2dF& value) {
getter_return_value_ = value;
}
@@ -2498,18 +3070,30 @@ class TestScrollOffsetDelegate : public LayerScrollOffsetDelegate {
return page_scale_factor_;
}
+ float min_page_scale_factor() const {
+ return min_page_scale_factor_;
+ }
+
+ float max_page_scale_factor() const {
+ return max_page_scale_factor_;
+ }
+
private:
gfx::Vector2dF last_set_scroll_offset_;
gfx::Vector2dF getter_return_value_;
gfx::Vector2dF max_scroll_offset_;
gfx::SizeF scrollable_size_;
float page_scale_factor_;
+ float min_page_scale_factor_;
+ float max_page_scale_factor_;
};
TEST_F(LayerTreeHostImplTest, RootLayerScrollOffsetDelegation) {
TestScrollOffsetDelegate scroll_delegate;
host_impl_->SetViewportSize(gfx::Size(10, 20));
LayerImpl* scroll_layer = SetupScrollAndContentsLayers(gfx::Size(100, 100));
+ LayerImpl* clip_layer = scroll_layer->parent()->parent();
+ clip_layer->SetBounds(gfx::Size(10, 20));
// Setting the delegate results in the current scroll offset being set.
gfx::Vector2dF initial_scroll_delta(10.f, 10.f);
@@ -2519,20 +3103,38 @@ TEST_F(LayerTreeHostImplTest, RootLayerScrollOffsetDelegation) {
EXPECT_EQ(initial_scroll_delta.ToString(),
scroll_delegate.last_set_scroll_offset().ToString());
- // Setting the delegate results in the scrollable_size, max_scroll_offset and
- // page_scale being set.
+ // Setting the delegate results in the scrollable_size, max_scroll_offset,
+ // page_scale_factor and {min|max}_page_scale_factor being set.
EXPECT_EQ(gfx::SizeF(100, 100), scroll_delegate.scrollable_size());
EXPECT_EQ(gfx::Vector2dF(90, 80), scroll_delegate.max_scroll_offset());
EXPECT_EQ(1.f, scroll_delegate.page_scale_factor());
+ EXPECT_EQ(0.f, scroll_delegate.min_page_scale_factor());
+ EXPECT_EQ(0.f, scroll_delegate.max_page_scale_factor());
// Updating page scale immediately updates the delegate.
host_impl_->active_tree()->SetPageScaleFactorAndLimits(2.f, 0.5f, 4.f);
EXPECT_EQ(2.f, scroll_delegate.page_scale_factor());
+ EXPECT_EQ(0.5f, scroll_delegate.min_page_scale_factor());
+ EXPECT_EQ(4.f, scroll_delegate.max_page_scale_factor());
host_impl_->active_tree()->SetPageScaleDelta(1.5f);
EXPECT_EQ(3.f, scroll_delegate.page_scale_factor());
+ EXPECT_EQ(0.5f, scroll_delegate.min_page_scale_factor());
+ EXPECT_EQ(4.f, scroll_delegate.max_page_scale_factor());
host_impl_->active_tree()->SetPageScaleDelta(1.f);
host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f, 0.5f, 4.f);
EXPECT_EQ(1.f, scroll_delegate.page_scale_factor());
+ EXPECT_EQ(0.5f, scroll_delegate.min_page_scale_factor());
+ EXPECT_EQ(4.f, scroll_delegate.max_page_scale_factor());
+
+ // The pinch gesture doesn't put the delegate into a state where the scroll
+ // offset is outside of the scroll range. (this is verified by DCHECKs in the
+ // delegate).
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture);
+ host_impl_->PinchGestureBegin();
+ host_impl_->PinchGestureUpdate(2.f, gfx::Point());
+ host_impl_->PinchGestureUpdate(.5f, gfx::Point());
+ host_impl_->PinchGestureEnd();
+ host_impl_->ScrollEnd();
// Scrolling should be relative to the offset as returned by the delegate.
gfx::Vector2dF scroll_delta(0.f, 10.f);
@@ -2552,6 +3154,7 @@ TEST_F(LayerTreeHostImplTest, RootLayerScrollOffsetDelegation) {
EXPECT_EQ(current_offset + scroll_delta,
scroll_delegate.last_set_scroll_offset());
host_impl_->ScrollEnd();
+ scroll_delegate.set_getter_return_value(gfx::Vector2dF());
// Forces a full tree synchronization and ensures that the scroll delegate
// sees the correct size of the new tree.
@@ -2571,25 +3174,58 @@ TEST_F(LayerTreeHostImplTest, RootLayerScrollOffsetDelegation) {
scroll_layer->TotalScrollOffset().ToString());
}
+void CheckLayerScrollDelta(LayerImpl* layer, gfx::Vector2dF scroll_delta) {
+ const gfx::Transform target_space_transform =
+ layer->draw_properties().target_space_transform;
+ EXPECT_TRUE(target_space_transform.IsScaleOrTranslation());
+ gfx::Point translated_point;
+ target_space_transform.TransformPoint(&translated_point);
+ gfx::Point expected_point = gfx::Point() - ToRoundedVector2d(scroll_delta);
+ EXPECT_EQ(expected_point.ToString(), translated_point.ToString());
+}
+
+TEST_F(LayerTreeHostImplTest,
+ ExternalRootLayerScrollOffsetDelegationReflectedInNextDraw) {
+ TestScrollOffsetDelegate scroll_delegate;
+ host_impl_->SetViewportSize(gfx::Size(10, 20));
+ LayerImpl* scroll_layer = SetupScrollAndContentsLayers(gfx::Size(100, 100));
+ LayerImpl* clip_layer = scroll_layer->parent()->parent();
+ clip_layer->SetBounds(gfx::Size(10, 20));
+ host_impl_->SetRootLayerScrollOffsetDelegate(&scroll_delegate);
+
+ // Draw first frame to clear any pending draws and check scroll.
+ DrawFrame();
+ CheckLayerScrollDelta(scroll_layer, gfx::Vector2dF(0.f, 0.f));
+ EXPECT_FALSE(host_impl_->active_tree()->needs_update_draw_properties());
+
+ // Set external scroll delta on delegate and notify LayerTreeHost.
+ gfx::Vector2dF scroll_delta(10.f, 10.f);
+ scroll_delegate.set_getter_return_value(scroll_delta);
+ host_impl_->OnRootLayerDelegatedScrollOffsetChanged();
+
+ // Check scroll delta reflected in layer.
+ DrawFrame();
+ CheckLayerScrollDelta(scroll_layer, scroll_delta);
+
+ host_impl_->SetRootLayerScrollOffsetDelegate(NULL);
+}
+
TEST_F(LayerTreeHostImplTest, OverscrollRoot) {
SetupScrollAndContentsLayers(gfx::Size(100, 100));
host_impl_->SetViewportSize(gfx::Size(50, 50));
host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f, 0.5f, 4.f);
DrawFrame();
EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll());
- EXPECT_EQ(gfx::Vector2dF(), host_impl_->current_fling_velocity());
// In-bounds scrolling does not affect overscroll.
EXPECT_EQ(InputHandler::ScrollStarted,
host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll());
- EXPECT_EQ(gfx::Vector2dF(), host_impl_->current_fling_velocity());
// Overscroll events are reflected immediately.
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 50));
EXPECT_EQ(gfx::Vector2dF(0, 10), host_impl_->accumulated_root_overscroll());
- EXPECT_EQ(gfx::Vector2dF(), host_impl_->current_fling_velocity());
// In-bounds scrolling resets accumulated overscroll for the scrolled axes.
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -50));
@@ -2617,15 +3253,6 @@ TEST_F(LayerTreeHostImplTest, OverscrollRoot) {
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -20));
EXPECT_EQ(gfx::Vector2dF(0, -10), host_impl_->accumulated_root_overscroll());
host_impl_->ScrollEnd();
-
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
- // Fling velocity is reflected immediately.
- host_impl_->NotifyCurrentFlingVelocity(gfx::Vector2dF(10, 0));
- EXPECT_EQ(gfx::Vector2dF(10, 0), host_impl_->current_fling_velocity());
- host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -20));
- EXPECT_EQ(gfx::Vector2dF(0, -20), host_impl_->accumulated_root_overscroll());
- EXPECT_EQ(gfx::Vector2dF(10, 0), host_impl_->current_fling_velocity());
}
@@ -2633,17 +3260,25 @@ TEST_F(LayerTreeHostImplTest, OverscrollChildWithoutBubbling) {
// Scroll child layers beyond their maximum scroll range and make sure root
// overscroll does not accumulate.
gfx::Size surface_size(10, 10);
- scoped_ptr<LayerImpl> root = CreateScrollableLayer(1, surface_size);
+ scoped_ptr<LayerImpl> root_clip =
+ LayerImpl::Create(host_impl_->active_tree(), 4);
+ scoped_ptr<LayerImpl> root =
+ CreateScrollableLayer(1, surface_size, root_clip.get());
- scoped_ptr<LayerImpl> grand_child = CreateScrollableLayer(3, surface_size);
- grand_child->SetScrollOffset(gfx::Vector2d(0, 2));
+ scoped_ptr<LayerImpl> grand_child =
+ CreateScrollableLayer(3, surface_size, root_clip.get());
- scoped_ptr<LayerImpl> child = CreateScrollableLayer(2, surface_size);
- child->SetScrollOffset(gfx::Vector2d(0, 3));
+ scoped_ptr<LayerImpl> child =
+ CreateScrollableLayer(2, surface_size, root_clip.get());
+ LayerImpl* grand_child_layer = grand_child.get();
child->AddChild(grand_child.Pass());
+ LayerImpl* child_layer = child.get();
root->AddChild(child.Pass());
- host_impl_->active_tree()->SetRootLayer(root.Pass());
+ root_clip->AddChild(root.Pass());
+ child_layer->SetScrollOffset(gfx::Vector2d(0, 3));
+ grand_child_layer->SetScrollOffset(gfx::Vector2d(0, 2));
+ host_impl_->active_tree()->SetRootLayer(root_clip.Pass());
host_impl_->active_tree()->DidBecomeActive();
host_impl_->SetViewportSize(surface_size);
DrawFrame();
@@ -2656,35 +3291,29 @@ TEST_F(LayerTreeHostImplTest, OverscrollChildWithoutBubbling) {
EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll());
host_impl_->ScrollEnd();
- LayerImpl* child = host_impl_->active_tree()->root_layer()->children()[0];
- LayerImpl* grand_child = child->children()[0];
-
// The next time we scroll we should only scroll the parent, but overscroll
// should still not reach the root layer.
scroll_delta = gfx::Vector2d(0, -30);
EXPECT_EQ(InputHandler::ScrollStarted,
host_impl_->ScrollBegin(gfx::Point(5, 5),
InputHandler::NonBubblingGesture));
- EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child);
+ EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child_layer);
EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll());
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
- EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), child);
+ EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), child_layer);
EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll());
host_impl_->ScrollEnd();
// After scrolling the parent, another scroll on the opposite direction
- // should scroll the child, resetting the fling velocity.
+ // should scroll the child.
scroll_delta = gfx::Vector2d(0, 70);
- host_impl_->NotifyCurrentFlingVelocity(gfx::Vector2dF(10, 0));
- EXPECT_EQ(gfx::Vector2dF(10, 0), host_impl_->current_fling_velocity());
EXPECT_EQ(InputHandler::ScrollStarted,
host_impl_->ScrollBegin(gfx::Point(5, 5),
InputHandler::NonBubblingGesture));
- EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child);
+ EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child_layer);
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
- EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child);
+ EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child_layer);
EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll());
- EXPECT_EQ(gfx::Vector2dF(), host_impl_->current_fling_velocity());
host_impl_->ScrollEnd();
}
}
@@ -2695,14 +3324,21 @@ TEST_F(LayerTreeHostImplTest, OverscrollChildEventBubbling) {
// be reflected only when it has bubbled up to the root scrolling layer.
gfx::Size surface_size(10, 10);
gfx::Size content_size(20, 20);
- scoped_ptr<LayerImpl> root = CreateScrollableLayer(1, content_size);
- scoped_ptr<LayerImpl> child = CreateScrollableLayer(2, content_size);
+ scoped_ptr<LayerImpl> root_clip =
+ LayerImpl::Create(host_impl_->active_tree(), 3);
+ scoped_ptr<LayerImpl> root =
+ CreateScrollableLayer(1, content_size, root_clip.get());
+ root->SetIsContainerForFixedPositionLayers(true);
+ scoped_ptr<LayerImpl> child =
+ CreateScrollableLayer(2, content_size, root_clip.get());
- child->SetScrollable(false);
+ child->SetScrollClipLayer(Layer::INVALID_ID);
root->AddChild(child.Pass());
+ root_clip->AddChild(root.Pass());
host_impl_->SetViewportSize(surface_size);
- host_impl_->active_tree()->SetRootLayer(root.Pass());
+ host_impl_->active_tree()->SetRootLayer(root_clip.Pass());
+ host_impl_->active_tree()->SetViewportLayersFromIds(3, 1, Layer::INVALID_ID);
host_impl_->active_tree()->DidBecomeActive();
DrawFrame();
{
@@ -2722,22 +3358,118 @@ TEST_F(LayerTreeHostImplTest, OverscrollChildEventBubbling) {
TEST_F(LayerTreeHostImplTest, OverscrollAlways) {
LayerTreeSettings settings;
- settings.always_overscroll = true;
CreateHostImpl(settings, CreateOutputSurface());
- SetupScrollAndContentsLayers(gfx::Size(50, 50));
+ LayerImpl* scroll_layer = SetupScrollAndContentsLayers(gfx::Size(50, 50));
+ LayerImpl* clip_layer = scroll_layer->parent()->parent();
+ clip_layer->SetBounds(gfx::Size(50, 50));
host_impl_->SetViewportSize(gfx::Size(50, 50));
host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f, 0.5f, 4.f);
DrawFrame();
EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll());
- EXPECT_EQ(gfx::Vector2dF(), host_impl_->current_fling_velocity());
// Even though the layer can't scroll the overscroll still happens.
EXPECT_EQ(InputHandler::ScrollStarted,
host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
EXPECT_EQ(gfx::Vector2dF(0, 10), host_impl_->accumulated_root_overscroll());
- EXPECT_EQ(gfx::Vector2dF(), host_impl_->current_fling_velocity());
+}
+
+TEST_F(LayerTreeHostImplTest, NoOverscrollOnFractionalDeviceScale) {
+ gfx::Size surface_size(980, 1439);
+ gfx::Size content_size(980, 1438);
+ float device_scale_factor = 1.5f;
+ scoped_ptr<LayerImpl> root_clip =
+ LayerImpl::Create(host_impl_->active_tree(), 3);
+ scoped_ptr<LayerImpl> root =
+ CreateScrollableLayer(1, content_size, root_clip.get());
+ root->SetIsContainerForFixedPositionLayers(true);
+ scoped_ptr<LayerImpl> child =
+ CreateScrollableLayer(2, content_size, root_clip.get());
+ root->scroll_clip_layer()->SetBounds(gfx::Size(320, 469));
+ host_impl_->active_tree()->SetPageScaleFactorAndLimits(
+ 0.326531f, 0.326531f, 5.f);
+ host_impl_->active_tree()->SetPageScaleDelta(1.f);
+ child->SetScrollClipLayer(Layer::INVALID_ID);
+ root->AddChild(child.Pass());
+ root_clip->AddChild(root.Pass());
+
+ host_impl_->SetViewportSize(surface_size);
+ host_impl_->SetDeviceScaleFactor(device_scale_factor);
+ host_impl_->active_tree()->SetRootLayer(root_clip.Pass());
+ host_impl_->active_tree()->SetViewportLayersFromIds(3, 1, Layer::INVALID_ID);
+ host_impl_->active_tree()->DidBecomeActive();
+ DrawFrame();
+ {
+ // Horizontal & Vertical GlowEffect should not be applied when
+ // content size is less then view port size. For Example Horizontal &
+ // vertical GlowEffect should not be applied in about:blank page.
+ EXPECT_EQ(InputHandler::ScrollStarted,
+ host_impl_->ScrollBegin(gfx::Point(0, 0), InputHandler::Wheel));
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(0, -1));
+ EXPECT_EQ(gfx::Vector2dF().ToString(),
+ host_impl_->accumulated_root_overscroll().ToString());
+
+ host_impl_->ScrollEnd();
+ }
+}
+
+TEST_F(LayerTreeHostImplTest, NoOverscrollWhenNotAtEdge) {
+ gfx::Size surface_size(100, 100);
+ gfx::Size content_size(200, 200);
+ scoped_ptr<LayerImpl> root_clip =
+ LayerImpl::Create(host_impl_->active_tree(), 3);
+ scoped_ptr<LayerImpl> root =
+ CreateScrollableLayer(1, content_size, root_clip.get());
+ root->SetIsContainerForFixedPositionLayers(true);
+ scoped_ptr<LayerImpl> child =
+ CreateScrollableLayer(2, content_size, root_clip.get());
+
+ child->SetScrollClipLayer(Layer::INVALID_ID);
+ root->AddChild(child.Pass());
+ root_clip->AddChild(root.Pass());
+
+ host_impl_->SetViewportSize(surface_size);
+ host_impl_->active_tree()->SetRootLayer(root_clip.Pass());
+ host_impl_->active_tree()->SetViewportLayersFromIds(3, 1, Layer::INVALID_ID);
+ host_impl_->active_tree()->DidBecomeActive();
+ DrawFrame();
+ {
+ // Edge glow effect should be applicable only upon reaching Edges
+ // of the content. unnecessary glow effect calls shouldn't be
+ // called while scrolling up without reaching the edge of the content.
+ EXPECT_EQ(InputHandler::ScrollStarted,
+ host_impl_->ScrollBegin(gfx::Point(0, 0), InputHandler::Wheel));
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(0, 100));
+ EXPECT_EQ(gfx::Vector2dF().ToString(),
+ host_impl_->accumulated_root_overscroll().ToString());
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(0, -2.30f));
+ EXPECT_EQ(gfx::Vector2dF().ToString(),
+ host_impl_->accumulated_root_overscroll().ToString());
+ host_impl_->ScrollEnd();
+ // unusedrootDelta should be subtracted from applied delta so that
+ // unwanted glow effect calls are not called.
+ EXPECT_EQ(InputHandler::ScrollStarted,
+ host_impl_->ScrollBegin(gfx::Point(0, 0),
+ InputHandler::NonBubblingGesture));
+ EXPECT_EQ(InputHandler::ScrollStarted, host_impl_->FlingScrollBegin());
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(0, 20));
+ EXPECT_EQ(gfx::Vector2dF(0.000000f, 17.699997f).ToString(),
+ host_impl_->accumulated_root_overscroll().ToString());
+
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(0.02f, -0.01f));
+ EXPECT_EQ(gfx::Vector2dF(0.000000f, 17.699997f).ToString(),
+ host_impl_->accumulated_root_overscroll().ToString());
+ host_impl_->ScrollEnd();
+ // TestCase to check kEpsilon, which prevents minute values to trigger
+ // gloweffect without reaching edge.
+ EXPECT_EQ(InputHandler::ScrollStarted,
+ host_impl_->ScrollBegin(gfx::Point(0, 0), InputHandler::Wheel));
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(-0.12f, 0.1f));
+ EXPECT_EQ(gfx::Vector2dF().ToString(),
+ host_impl_->accumulated_root_overscroll().ToString());
+ host_impl_->ScrollEnd();
+ }
}
class BlendStateCheckLayer : public LayerImpl {
@@ -2759,13 +3491,16 @@ class BlendStateCheckLayer : public LayerImpl {
opaque_rect = quad_rect_;
else
opaque_rect = opaque_content_rect_;
+ gfx::Rect visible_quad_rect = quad_rect_;
+
+ SharedQuadState* shared_quad_state = quad_sink->CreateSharedQuadState();
+ PopulateSharedQuadState(shared_quad_state);
- SharedQuadState* shared_quad_state =
- quad_sink->UseSharedQuadState(CreateSharedQuadState());
scoped_ptr<TileDrawQuad> test_blending_draw_quad = TileDrawQuad::Create();
test_blending_draw_quad->SetNew(shared_quad_state,
quad_rect_,
opaque_rect,
+ visible_quad_rect,
resource_id_,
gfx::RectF(0.f, 0.f, 1.f, 1.f),
gfx::Size(1, 1),
@@ -2773,8 +3508,7 @@ class BlendStateCheckLayer : public LayerImpl {
test_blending_draw_quad->visible_rect = quad_visible_rect_;
EXPECT_EQ(blend_, test_blending_draw_quad->ShouldDrawWithBlending());
EXPECT_EQ(has_render_surface_, !!render_surface());
- quad_sink->Append(test_blending_draw_quad.PassAs<DrawQuad>(),
- append_quads_data);
+ quad_sink->Append(test_blending_draw_quad.PassAs<DrawQuad>());
}
void SetExpectation(bool blend, bool has_render_surface) {
@@ -2785,9 +3519,11 @@ class BlendStateCheckLayer : public LayerImpl {
bool quads_appended() const { return quads_appended_; }
- void SetQuadRect(gfx::Rect rect) { quad_rect_ = rect; }
- void SetQuadVisibleRect(gfx::Rect rect) { quad_visible_rect_ = rect; }
- void SetOpaqueContentRect(gfx::Rect rect) { opaque_content_rect_ = rect; }
+ void SetQuadRect(const gfx::Rect& rect) { quad_rect_ = rect; }
+ void SetQuadVisibleRect(const gfx::Rect& rect) { quad_visible_rect_ = rect; }
+ void SetOpaqueContentRect(const gfx::Rect& rect) {
+ opaque_content_rect_ = rect;
+ }
private:
BlendStateCheckLayer(LayerTreeImpl* tree_impl,
@@ -2805,7 +3541,6 @@ class BlendStateCheckLayer : public LayerImpl {
ResourceProvider::TextureUsageAny,
RGBA_8888)) {
resource_provider->AllocateForTesting(resource_id_);
- SetAnchorPoint(gfx::PointF());
SetBounds(gfx::Size(10, 10));
SetContentBounds(gfx::Size(10, 10));
SetDrawsContent(true);
@@ -2824,7 +3559,6 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
{
scoped_ptr<LayerImpl> root =
LayerImpl::Create(host_impl_->active_tree(), 1);
- root->SetAnchorPoint(gfx::PointF());
root->SetBounds(gfx::Size(10, 10));
root->SetContentBounds(root->bounds());
root->SetDrawsContent(false);
@@ -2845,8 +3579,8 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
// Opaque layer, drawn without blending.
layer1->SetContentsOpaque(true);
layer1->SetExpectation(false, false);
- layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ layer1->SetUpdateRect(gfx::RectF(layer1->content_bounds()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
EXPECT_TRUE(layer1->quads_appended());
host_impl_->DidDrawAllLayers(frame);
@@ -2854,8 +3588,8 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
// Layer with translucent content and painting, so drawn with blending.
layer1->SetContentsOpaque(false);
layer1->SetExpectation(true, false);
- layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ layer1->SetUpdateRect(gfx::RectF(layer1->content_bounds()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
EXPECT_TRUE(layer1->quads_appended());
host_impl_->DidDrawAllLayers(frame);
@@ -2864,8 +3598,8 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
layer1->SetContentsOpaque(true);
layer1->SetOpacity(0.5f);
layer1->SetExpectation(true, false);
- layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ layer1->SetUpdateRect(gfx::RectF(layer1->content_bounds()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
EXPECT_TRUE(layer1->quads_appended());
host_impl_->DidDrawAllLayers(frame);
@@ -2874,8 +3608,8 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
layer1->SetContentsOpaque(true);
layer1->SetOpacity(0.5f);
layer1->SetExpectation(true, false);
- layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ layer1->SetUpdateRect(gfx::RectF(layer1->content_bounds()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
EXPECT_TRUE(layer1->quads_appended());
host_impl_->DidDrawAllLayers(frame);
@@ -2892,12 +3626,12 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
layer1->SetContentsOpaque(true);
layer1->SetOpacity(1.f);
layer1->SetExpectation(false, false);
- layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
+ layer1->SetUpdateRect(gfx::RectF(layer1->content_bounds()));
layer2->SetContentsOpaque(true);
layer2->SetOpacity(1.f);
layer2->SetExpectation(false, false);
- layer2->set_update_rect(gfx::RectF(layer1->content_bounds()));
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ layer2->SetUpdateRect(gfx::RectF(layer1->content_bounds()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
EXPECT_TRUE(layer1->quads_appended());
EXPECT_TRUE(layer2->quads_appended());
@@ -2907,10 +3641,10 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
// Child layer with opaque content, drawn without blending.
layer1->SetContentsOpaque(false);
layer1->SetExpectation(true, false);
- layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
+ layer1->SetUpdateRect(gfx::RectF(layer1->content_bounds()));
layer2->SetExpectation(false, false);
- layer2->set_update_rect(gfx::RectF(layer1->content_bounds()));
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ layer2->SetUpdateRect(gfx::RectF(layer1->content_bounds()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
EXPECT_TRUE(layer1->quads_appended());
EXPECT_TRUE(layer2->quads_appended());
@@ -2921,10 +3655,10 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
// Child layer with opaque content, drawn without blending.
layer1->SetContentsOpaque(true);
layer1->SetExpectation(false, false);
- layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
+ layer1->SetUpdateRect(gfx::RectF(layer1->content_bounds()));
layer2->SetExpectation(false, false);
- layer2->set_update_rect(gfx::RectF(layer1->content_bounds()));
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ layer2->SetUpdateRect(gfx::RectF(layer1->content_bounds()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
EXPECT_TRUE(layer1->quads_appended());
EXPECT_TRUE(layer2->quads_appended());
@@ -2938,10 +3672,10 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
layer1->SetContentsOpaque(true);
layer1->SetOpacity(0.5f);
layer1->SetExpectation(false, true);
- layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
+ layer1->SetUpdateRect(gfx::RectF(layer1->content_bounds()));
layer2->SetExpectation(false, false);
- layer2->set_update_rect(gfx::RectF(layer1->content_bounds()));
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ layer2->SetUpdateRect(gfx::RectF(layer1->content_bounds()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
EXPECT_TRUE(layer1->quads_appended());
EXPECT_TRUE(layer2->quads_appended());
@@ -2952,12 +3686,12 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
layer1->SetContentsOpaque(true);
layer1->SetOpacity(1.f);
layer1->SetExpectation(false, false);
- layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
+ layer1->SetUpdateRect(gfx::RectF(layer1->content_bounds()));
layer2->SetContentsOpaque(true);
layer2->SetOpacity(0.5f);
layer2->SetExpectation(true, false);
- layer2->set_update_rect(gfx::RectF(layer1->content_bounds()));
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ layer2->SetUpdateRect(gfx::RectF(layer1->content_bounds()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
EXPECT_TRUE(layer1->quads_appended());
EXPECT_TRUE(layer2->quads_appended());
@@ -2967,12 +3701,12 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
layer1->SetContentsOpaque(true);
layer1->SetOpacity(1.f);
layer1->SetExpectation(false, false);
- layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
+ layer1->SetUpdateRect(gfx::RectF(layer1->content_bounds()));
layer2->SetContentsOpaque(false);
layer2->SetOpacity(1.f);
layer2->SetExpectation(true, false);
- layer2->set_update_rect(gfx::RectF(layer1->content_bounds()));
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ layer2->SetUpdateRect(gfx::RectF(layer1->content_bounds()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
EXPECT_TRUE(layer1->quads_appended());
EXPECT_TRUE(layer2->quads_appended());
@@ -2983,12 +3717,12 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
layer1->SetContentsOpaque(true);
layer1->SetOpacity(1.f);
layer1->SetExpectation(false, false);
- layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
+ layer1->SetUpdateRect(gfx::RectF(layer1->content_bounds()));
layer2->SetContentsOpaque(true);
layer2->SetOpacity(1.f);
layer2->SetExpectation(false, false);
- layer2->set_update_rect(gfx::RectF(layer1->content_bounds()));
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ layer2->SetUpdateRect(gfx::RectF(layer1->content_bounds()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
EXPECT_TRUE(layer1->quads_appended());
EXPECT_TRUE(layer2->quads_appended());
@@ -3000,8 +3734,8 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
layer1->SetQuadVisibleRect(gfx::Rect(5, 5, 5, 5));
layer1->SetOpaqueContentRect(gfx::Rect(5, 5, 2, 5));
layer1->SetExpectation(true, false);
- layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ layer1->SetUpdateRect(gfx::RectF(layer1->content_bounds()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
EXPECT_TRUE(layer1->quads_appended());
host_impl_->DidDrawAllLayers(frame);
@@ -3012,8 +3746,8 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
layer1->SetQuadVisibleRect(gfx::Rect(5, 5, 5, 2));
layer1->SetOpaqueContentRect(gfx::Rect(5, 5, 2, 5));
layer1->SetExpectation(true, false);
- layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ layer1->SetUpdateRect(gfx::RectF(layer1->content_bounds()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
EXPECT_TRUE(layer1->quads_appended());
host_impl_->DidDrawAllLayers(frame);
@@ -3024,8 +3758,8 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
layer1->SetQuadVisibleRect(gfx::Rect(7, 5, 3, 5));
layer1->SetOpaqueContentRect(gfx::Rect(5, 5, 2, 5));
layer1->SetExpectation(true, false);
- layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ layer1->SetUpdateRect(gfx::RectF(layer1->content_bounds()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
EXPECT_TRUE(layer1->quads_appended());
host_impl_->DidDrawAllLayers(frame);
@@ -3037,8 +3771,8 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
layer1->SetQuadVisibleRect(gfx::Rect(5, 5, 2, 5));
layer1->SetOpaqueContentRect(gfx::Rect(5, 5, 2, 5));
layer1->SetExpectation(false, false);
- layer1->set_update_rect(gfx::RectF(layer1->content_bounds()));
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ layer1->SetUpdateRect(gfx::RectF(layer1->content_bounds()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
EXPECT_TRUE(layer1->quads_appended());
host_impl_->DidDrawAllLayers(frame);
@@ -3083,7 +3817,7 @@ class LayerTreeHostImplViewportCoveredTest : public LayerTreeHostImplTest {
child_->SetQuadVisibleRect(gfx::Rect(layer_rect.size()));
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
ASSERT_EQ(1u, frame.render_passes.size());
EXPECT_EQ(0u, CountGutterQuads(frame.render_passes[0]->quad_list));
@@ -3104,7 +3838,7 @@ class LayerTreeHostImplViewportCoveredTest : public LayerTreeHostImplTest {
child_->SetQuadVisibleRect(gfx::Rect(layer_rect.size()));
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
ASSERT_EQ(1u, frame.render_passes.size());
EXPECT_EQ(1u, CountGutterQuads(frame.render_passes[0]->quad_list));
@@ -3125,7 +3859,7 @@ class LayerTreeHostImplViewportCoveredTest : public LayerTreeHostImplTest {
child_->SetQuadVisibleRect(gfx::Rect(layer_rect.size()));
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
ASSERT_EQ(1u, frame.render_passes.size());
EXPECT_EQ(4u, CountGutterQuads(frame.render_passes[0]->quad_list));
@@ -3147,7 +3881,7 @@ class LayerTreeHostImplViewportCoveredTest : public LayerTreeHostImplTest {
child_->SetQuadVisibleRect(gfx::Rect(layer_rect.size()));
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
ASSERT_EQ(1u, frame.render_passes.size());
EXPECT_EQ(0u, CountGutterQuads(frame.render_passes[0]->quad_list));
@@ -3164,7 +3898,7 @@ class LayerTreeHostImplViewportCoveredTest : public LayerTreeHostImplTest {
void set_gutter_quad_material(DrawQuad::Material material) {
gutter_quad_material_ = material;
}
- void set_gutter_texture_size(gfx::Size gutter_texture_size) {
+ void set_gutter_texture_size(const gfx::Size& gutter_texture_size) {
gutter_texture_size_ = gutter_texture_size;
}
@@ -3202,7 +3936,7 @@ class LayerTreeHostImplViewportCoveredTest : public LayerTreeHostImplTest {
}
}
- gfx::Size DipSizeToPixelSize(gfx::Size size) {
+ gfx::Size DipSizeToPixelSize(const gfx::Size& size) {
return gfx::ToRoundedSize(
gfx::ScaleSize(size, host_impl_->device_scale_factor()));
}
@@ -3252,13 +3986,9 @@ TEST_F(LayerTreeHostImplViewportCoveredTest, ViewportCoveredOverhangBitmap) {
host_impl_->SetViewportSize(DipSizeToPixelSize(viewport_size_));
SetupActiveTreeLayers();
- SkBitmap skbitmap;
- skbitmap.setConfig(SkBitmap::kARGB_8888_Config, 2, 2);
- skbitmap.allocPixels();
- skbitmap.setImmutable();
-
// Specify an overhang bitmap to use.
- UIResourceBitmap ui_resource_bitmap(skbitmap);
+ bool is_opaque = false;
+ UIResourceBitmap ui_resource_bitmap(gfx::Size(2, 2), is_opaque);
ui_resource_bitmap.SetWrapMode(UIResourceBitmap::REPEAT);
UIResourceId ui_resource_id = 12345;
host_impl_->CreateUIResource(ui_resource_id, ui_resource_bitmap);
@@ -3355,7 +4085,6 @@ TEST_F(LayerTreeHostImplTest, ReshapeNotCalledUntilDraw) {
scoped_ptr<LayerImpl> root =
FakeDrawableLayerImpl::Create(host_impl_->active_tree(), 1);
- root->SetAnchorPoint(gfx::PointF());
root->SetBounds(gfx::Size(10, 10));
root->SetContentBounds(gfx::Size(10, 10));
root->SetDrawsContent(true);
@@ -3366,7 +4095,7 @@ TEST_F(LayerTreeHostImplTest, ReshapeNotCalledUntilDraw) {
LayerTreeHostImpl::FrameData frame;
host_impl_->SetViewportSize(gfx::Size(10, 10));
host_impl_->SetDeviceScaleFactor(1.f);
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
EXPECT_TRUE(provider->TestContext3d()->reshape_called());
EXPECT_EQ(provider->TestContext3d()->width(), 10);
@@ -3376,7 +4105,7 @@ TEST_F(LayerTreeHostImplTest, ReshapeNotCalledUntilDraw) {
provider->TestContext3d()->clear_reshape_called();
host_impl_->SetViewportSize(gfx::Size(20, 30));
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
EXPECT_TRUE(provider->TestContext3d()->reshape_called());
EXPECT_EQ(provider->TestContext3d()->width(), 20);
@@ -3386,7 +4115,7 @@ TEST_F(LayerTreeHostImplTest, ReshapeNotCalledUntilDraw) {
provider->TestContext3d()->clear_reshape_called();
host_impl_->SetDeviceScaleFactor(2.f);
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
EXPECT_TRUE(provider->TestContext3d()->reshape_called());
EXPECT_EQ(provider->TestContext3d()->width(), 20);
@@ -3411,9 +4140,15 @@ TEST_F(LayerTreeHostImplTest, PartialSwapReceivesDamageRect) {
// that we can force partial swap enabled.
LayerTreeSettings settings;
settings.partial_swap_enabled = true;
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
scoped_ptr<LayerTreeHostImpl> layer_tree_host_impl =
- LayerTreeHostImpl::Create(
- settings, this, &proxy_, &stats_instrumentation_, NULL, 0);
+ LayerTreeHostImpl::Create(settings,
+ this,
+ &proxy_,
+ &stats_instrumentation_,
+ shared_bitmap_manager.get(),
+ 0);
layer_tree_host_impl->InitializeRenderer(output_surface.Pass());
layer_tree_host_impl->SetViewportSize(gfx::Size(500, 500));
@@ -3422,11 +4157,9 @@ TEST_F(LayerTreeHostImplTest, PartialSwapReceivesDamageRect) {
scoped_ptr<LayerImpl> child =
FakeDrawableLayerImpl::Create(layer_tree_host_impl->active_tree(), 2);
child->SetPosition(gfx::PointF(12.f, 13.f));
- child->SetAnchorPoint(gfx::PointF());
child->SetBounds(gfx::Size(14, 15));
child->SetContentBounds(gfx::Size(14, 15));
child->SetDrawsContent(true);
- root->SetAnchorPoint(gfx::PointF());
root->SetBounds(gfx::Size(500, 500));
root->SetContentBounds(gfx::Size(500, 500));
root->SetDrawsContent(true);
@@ -3436,7 +4169,7 @@ TEST_F(LayerTreeHostImplTest, PartialSwapReceivesDamageRect) {
LayerTreeHostImpl::FrameData frame;
// First frame, the entire screen should get swapped.
- EXPECT_TRUE(layer_tree_host_impl->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, layer_tree_host_impl->PrepareToDraw(&frame));
layer_tree_host_impl->DrawLayers(&frame, gfx::FrameTime::Now());
layer_tree_host_impl->DidDrawAllLayers(frame);
layer_tree_host_impl->SwapBuffers(frame);
@@ -3449,7 +4182,7 @@ TEST_F(LayerTreeHostImplTest, PartialSwapReceivesDamageRect) {
// expected swap rect: vertically flipped, with origin at bottom left corner.
layer_tree_host_impl->active_tree()->root_layer()->children()[0]->SetPosition(
gfx::PointF());
- EXPECT_TRUE(layer_tree_host_impl->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, layer_tree_host_impl->PrepareToDraw(&frame));
layer_tree_host_impl->DrawLayers(&frame, gfx::FrameTime::Now());
host_impl_->DidDrawAllLayers(frame);
layer_tree_host_impl->SwapBuffers(frame);
@@ -3468,7 +4201,7 @@ TEST_F(LayerTreeHostImplTest, PartialSwapReceivesDamageRect) {
// This will damage everything.
layer_tree_host_impl->active_tree()->root_layer()->SetBackgroundColor(
SK_ColorBLACK);
- EXPECT_TRUE(layer_tree_host_impl->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, layer_tree_host_impl->PrepareToDraw(&frame));
layer_tree_host_impl->DrawLayers(&frame, gfx::FrameTime::Now());
host_impl_->DidDrawAllLayers(frame);
layer_tree_host_impl->SwapBuffers(frame);
@@ -3482,11 +4215,9 @@ TEST_F(LayerTreeHostImplTest, RootLayerDoesntCreateExtraSurface) {
FakeDrawableLayerImpl::Create(host_impl_->active_tree(), 1);
scoped_ptr<LayerImpl> child =
FakeDrawableLayerImpl::Create(host_impl_->active_tree(), 2);
- child->SetAnchorPoint(gfx::PointF());
child->SetBounds(gfx::Size(10, 10));
child->SetContentBounds(gfx::Size(10, 10));
child->SetDrawsContent(true);
- root->SetAnchorPoint(gfx::PointF());
root->SetBounds(gfx::Size(10, 10));
root->SetContentBounds(gfx::Size(10, 10));
root->SetDrawsContent(true);
@@ -3497,7 +4228,7 @@ TEST_F(LayerTreeHostImplTest, RootLayerDoesntCreateExtraSurface) {
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
EXPECT_EQ(1u, frame.render_surface_layer_list->size());
EXPECT_EQ(1u, frame.render_passes.size());
host_impl_->DidDrawAllLayers(frame);
@@ -3511,14 +4242,16 @@ class FakeLayerWithQuads : public LayerImpl {
virtual void AppendQuads(QuadSink* quad_sink,
AppendQuadsData* append_quads_data) OVERRIDE {
- SharedQuadState* shared_quad_state =
- quad_sink->UseSharedQuadState(CreateSharedQuadState());
+ SharedQuadState* shared_quad_state = quad_sink->CreateSharedQuadState();
+ PopulateSharedQuadState(shared_quad_state);
SkColor gray = SkColorSetRGB(100, 100, 100);
gfx::Rect quad_rect(content_bounds());
+ gfx::Rect visible_quad_rect(quad_rect);
scoped_ptr<SolidColorDrawQuad> my_quad = SolidColorDrawQuad::Create();
- my_quad->SetNew(shared_quad_state, quad_rect, gray, false);
- quad_sink->Append(my_quad.PassAs<DrawQuad>(), append_quads_data);
+ my_quad->SetNew(
+ shared_quad_state, quad_rect, visible_quad_rect, gray, false);
+ quad_sink->Append(my_quad.PassAs<DrawQuad>());
}
private:
@@ -3528,27 +4261,26 @@ class FakeLayerWithQuads : public LayerImpl {
class MockContext : public TestWebGraphicsContext3D {
public:
- MOCK_METHOD1(useProgram, void(blink::WebGLId program));
- MOCK_METHOD5(uniform4f, void(blink::WGC3Dint location,
- blink::WGC3Dfloat x,
- blink::WGC3Dfloat y,
- blink::WGC3Dfloat z,
- blink::WGC3Dfloat w));
- MOCK_METHOD4(uniformMatrix4fv, void(blink::WGC3Dint location,
- blink::WGC3Dsizei count,
- blink::WGC3Dboolean transpose,
- const blink::WGC3Dfloat* value));
- MOCK_METHOD4(drawElements, void(blink::WGC3Denum mode,
- blink::WGC3Dsizei count,
- blink::WGC3Denum type,
- blink::WGC3Dintptr offset));
- MOCK_METHOD0(getRequestableExtensionsCHROMIUM, blink::WebString());
- MOCK_METHOD1(enable, void(blink::WGC3Denum cap));
- MOCK_METHOD1(disable, void(blink::WGC3Denum cap));
- MOCK_METHOD4(scissor, void(blink::WGC3Dint x,
- blink::WGC3Dint y,
- blink::WGC3Dsizei width,
- blink::WGC3Dsizei height));
+ MOCK_METHOD1(useProgram, void(GLuint program));
+ MOCK_METHOD5(uniform4f, void(GLint location,
+ GLfloat x,
+ GLfloat y,
+ GLfloat z,
+ GLfloat w));
+ MOCK_METHOD4(uniformMatrix4fv, void(GLint location,
+ GLsizei count,
+ GLboolean transpose,
+ const GLfloat* value));
+ MOCK_METHOD4(drawElements, void(GLenum mode,
+ GLsizei count,
+ GLenum type,
+ GLintptr offset));
+ MOCK_METHOD1(enable, void(GLenum cap));
+ MOCK_METHOD1(disable, void(GLenum cap));
+ MOCK_METHOD4(scissor, void(GLint x,
+ GLint y,
+ GLsizei width,
+ GLsizei height));
};
class MockContextHarness {
@@ -3633,7 +4365,7 @@ TEST_F(LayerTreeHostImplTest, NoPartialSwap) {
harness.MustSetNoScissor();
{
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
host_impl_->DidDrawAllLayers(frame);
}
@@ -3646,7 +4378,7 @@ TEST_F(LayerTreeHostImplTest, NoPartialSwap) {
harness.MustSetScissor(0, 0, 10, 10);
{
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
host_impl_->DidDrawAllLayers(frame);
}
@@ -3670,14 +4402,14 @@ TEST_F(LayerTreeHostImplTest, PartialSwap) {
harness.MustDrawSolidQuad();
{
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
host_impl_->DidDrawAllLayers(frame);
}
Mock::VerifyAndClearExpectations(&mock_context);
// Damage a portion of the frame.
- host_impl_->active_tree()->root_layer()->set_update_rect(
+ host_impl_->active_tree()->root_layer()->SetUpdateRect(
gfx::Rect(0, 0, 2, 3));
// The second frame will be partially-swapped (the y coordinates are flipped).
@@ -3685,7 +4417,7 @@ TEST_F(LayerTreeHostImplTest, PartialSwap) {
harness.MustDrawSolidQuad();
{
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
host_impl_->DidDrawAllLayers(frame);
}
@@ -3696,6 +4428,7 @@ static scoped_ptr<LayerTreeHostImpl> SetupLayersForOpacity(
bool partial_swap,
LayerTreeHostImplClient* client,
Proxy* proxy,
+ SharedBitmapManager* manager,
RenderingStatsInstrumentation* stats_instrumentation) {
scoped_refptr<TestContextProvider> provider(TestContextProvider::Create());
scoped_ptr<OutputSurface> output_surface(
@@ -3706,7 +4439,7 @@ static scoped_ptr<LayerTreeHostImpl> SetupLayersForOpacity(
LayerTreeSettings settings;
settings.partial_swap_enabled = partial_swap;
scoped_ptr<LayerTreeHostImpl> my_host_impl = LayerTreeHostImpl::Create(
- settings, client, proxy, stats_instrumentation, NULL, 0);
+ settings, client, proxy, stats_instrumentation, manager, 0);
my_host_impl->InitializeRenderer(output_surface.Pass());
my_host_impl->SetViewportSize(gfx::Size(100, 100));
@@ -3740,7 +4473,6 @@ static scoped_ptr<LayerTreeHostImpl> SetupLayersForOpacity(
gfx::Rect grand_child_rect(5, 5, 150, 150);
root->CreateRenderSurface();
- root->SetAnchorPoint(gfx::PointF());
root->SetPosition(root_rect.origin());
root->SetBounds(root_rect.size());
root->SetContentBounds(root->bounds());
@@ -3748,7 +4480,6 @@ static scoped_ptr<LayerTreeHostImpl> SetupLayersForOpacity(
root->SetDrawsContent(false);
root->render_surface()->SetContentRect(gfx::Rect(root_rect.size()));
- child->SetAnchorPoint(gfx::PointF());
child->SetPosition(gfx::PointF(child_rect.x(), child_rect.y()));
child->SetOpacity(0.5f);
child->SetBounds(gfx::Size(child_rect.width(), child_rect.height()));
@@ -3757,7 +4488,6 @@ static scoped_ptr<LayerTreeHostImpl> SetupLayersForOpacity(
child->SetDrawsContent(false);
child->SetForceRenderSurface(true);
- grand_child->SetAnchorPoint(gfx::PointF());
grand_child->SetPosition(grand_child_rect.origin());
grand_child->SetBounds(grand_child_rect.size());
grand_child->SetContentBounds(grand_child->bounds());
@@ -3772,11 +4502,17 @@ static scoped_ptr<LayerTreeHostImpl> SetupLayersForOpacity(
}
TEST_F(LayerTreeHostImplTest, ContributingLayerEmptyScissorPartialSwap) {
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
scoped_ptr<LayerTreeHostImpl> my_host_impl =
- SetupLayersForOpacity(true, this, &proxy_, &stats_instrumentation_);
+ SetupLayersForOpacity(true,
+ this,
+ &proxy_,
+ shared_bitmap_manager.get(),
+ &stats_instrumentation_);
{
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, my_host_impl->PrepareToDraw(&frame));
// Verify all quads have been computed
ASSERT_EQ(2U, frame.render_passes.size());
@@ -3793,11 +4529,17 @@ TEST_F(LayerTreeHostImplTest, ContributingLayerEmptyScissorPartialSwap) {
}
TEST_F(LayerTreeHostImplTest, ContributingLayerEmptyScissorNoPartialSwap) {
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
scoped_ptr<LayerTreeHostImpl> my_host_impl =
- SetupLayersForOpacity(false, this, &proxy_, &stats_instrumentation_);
+ SetupLayersForOpacity(false,
+ this,
+ &proxy_,
+ shared_bitmap_manager.get(),
+ &stats_instrumentation_);
{
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(my_host_impl->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, my_host_impl->PrepareToDraw(&frame));
// Verify all quads have been computed
ASSERT_EQ(2U, frame.render_passes.size());
@@ -3824,7 +4566,6 @@ TEST_F(LayerTreeHostImplTest, LayersFreeTextures) {
scoped_ptr<LayerImpl> root_layer =
LayerImpl::Create(host_impl_->active_tree(), 1);
root_layer->SetBounds(gfx::Size(10, 10));
- root_layer->SetAnchorPoint(gfx::PointF());
scoped_refptr<VideoFrame> softwareFrame =
media::VideoFrame::CreateColorFrame(
@@ -3834,7 +4575,6 @@ TEST_F(LayerTreeHostImplTest, LayersFreeTextures) {
scoped_ptr<VideoLayerImpl> video_layer =
VideoLayerImpl::Create(host_impl_->active_tree(), 4, &provider);
video_layer->SetBounds(gfx::Size(10, 10));
- video_layer->SetAnchorPoint(gfx::PointF());
video_layer->SetContentBounds(gfx::Size(10, 10));
video_layer->SetDrawsContent(true);
root_layer->AddChild(video_layer.PassAs<LayerImpl>());
@@ -3842,7 +4582,6 @@ TEST_F(LayerTreeHostImplTest, LayersFreeTextures) {
scoped_ptr<IOSurfaceLayerImpl> io_surface_layer =
IOSurfaceLayerImpl::Create(host_impl_->active_tree(), 5);
io_surface_layer->SetBounds(gfx::Size(10, 10));
- io_surface_layer->SetAnchorPoint(gfx::PointF());
io_surface_layer->SetContentBounds(gfx::Size(10, 10));
io_surface_layer->SetDrawsContent(true);
io_surface_layer->SetIOSurfaceProperties(1, gfx::Size(10, 10));
@@ -3853,7 +4592,7 @@ TEST_F(LayerTreeHostImplTest, LayersFreeTextures) {
EXPECT_EQ(0u, context3d->NumTextures());
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
host_impl_->DidDrawAllLayers(frame);
host_impl_->SwapBuffers(frame);
@@ -3869,11 +4608,11 @@ TEST_F(LayerTreeHostImplTest, LayersFreeTextures) {
class MockDrawQuadsToFillScreenContext : public TestWebGraphicsContext3D {
public:
- MOCK_METHOD1(useProgram, void(blink::WebGLId program));
- MOCK_METHOD4(drawElements, void(blink::WGC3Denum mode,
- blink::WGC3Dsizei count,
- blink::WGC3Denum type,
- blink::WGC3Dintptr offset));
+ MOCK_METHOD1(useProgram, void(GLuint program));
+ MOCK_METHOD4(drawElements, void(GLenum mode,
+ GLsizei count,
+ GLenum type,
+ GLintptr offset));
};
TEST_F(LayerTreeHostImplTest, HasTransparentBackground) {
@@ -3898,7 +4637,7 @@ TEST_F(LayerTreeHostImplTest, HasTransparentBackground) {
EXPECT_CALL(*mock_context, drawElements(_, _, _, _))
.Times(1);
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
host_impl_->DidDrawAllLayers(frame);
Mock::VerifyAndClearExpectations(&mock_context);
@@ -3906,7 +4645,7 @@ TEST_F(LayerTreeHostImplTest, HasTransparentBackground) {
// Verify no quads are drawn when transparent background is set.
host_impl_->active_tree()->set_has_transparent_background(true);
host_impl_->SetFullRootLayerDamage();
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
host_impl_->DidDrawAllLayers(frame);
Mock::VerifyAndClearExpectations(&mock_context);
@@ -3963,7 +4702,7 @@ class LayerTreeHostImplTestWithDelegatingRenderer
bool expect_to_draw = !expected_damage.IsEmpty();
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
if (!expect_to_draw) {
// With no damage, we don't draw, and no quads are created.
@@ -3999,7 +4738,6 @@ class LayerTreeHostImplTestWithDelegatingRenderer
TEST_F(LayerTreeHostImplTestWithDelegatingRenderer, FrameIncludesDamageRect) {
scoped_ptr<SolidColorLayerImpl> root =
SolidColorLayerImpl::Create(host_impl_->active_tree(), 1);
- root->SetAnchorPoint(gfx::PointF());
root->SetPosition(gfx::PointF());
root->SetBounds(gfx::Size(10, 10));
root->SetContentBounds(gfx::Size(10, 10));
@@ -4008,7 +4746,6 @@ TEST_F(LayerTreeHostImplTestWithDelegatingRenderer, FrameIncludesDamageRect) {
// Child layer is in the bottom right corner.
scoped_ptr<SolidColorLayerImpl> child =
SolidColorLayerImpl::Create(host_impl_->active_tree(), 2);
- child->SetAnchorPoint(gfx::PointF(0.f, 0.f));
child->SetPosition(gfx::PointF(9.f, 9.f));
child->SetBounds(gfx::Size(1, 1));
child->SetContentBounds(gfx::Size(1, 1));
@@ -4024,7 +4761,7 @@ TEST_F(LayerTreeHostImplTestWithDelegatingRenderer, FrameIncludesDamageRect) {
// The second frame has damage that doesn't touch the child layer. Its quads
// should still be generated.
gfx::Rect small_damage = gfx::Rect(0, 0, 1, 1);
- host_impl_->active_tree()->root_layer()->set_update_rect(small_damage);
+ host_impl_->active_tree()->root_layer()->SetUpdateRect(small_damage);
DrawFrameAndTestDamage(small_damage);
// The third frame should have no damage, so no quads should be generated.
@@ -4032,6 +4769,14 @@ TEST_F(LayerTreeHostImplTestWithDelegatingRenderer, FrameIncludesDamageRect) {
DrawFrameAndTestDamage(no_damage);
}
+// TODO(reveman): Remove this test and the ability to prevent on demand raster
+// when delegating renderer supports PictureDrawQuads. crbug.com/342121
+TEST_F(LayerTreeHostImplTestWithDelegatingRenderer, PreventRasterizeOnDemand) {
+ LayerTreeSettings settings;
+ CreateHostImpl(settings, CreateOutputSurface());
+ EXPECT_FALSE(host_impl_->GetRendererCapabilities().allow_rasterize_on_demand);
+}
+
class FakeMaskLayerImpl : public LayerImpl {
public:
static scoped_ptr<FakeMaskLayerImpl> Create(LayerTreeImpl* tree_impl,
@@ -4083,13 +4828,11 @@ TEST_F(LayerTreeHostImplTest, MaskLayerWithScaling) {
root->SetBounds(root_size);
root->SetContentBounds(root_size);
root->SetPosition(gfx::PointF());
- root->SetAnchorPoint(gfx::PointF());
gfx::Size scaling_layer_size(50, 50);
scaling_layer->SetBounds(scaling_layer_size);
scaling_layer->SetContentBounds(scaling_layer_size);
scaling_layer->SetPosition(gfx::PointF());
- scaling_layer->SetAnchorPoint(gfx::PointF());
gfx::Transform scale;
scale.Scale(2.f, 2.f);
scaling_layer->SetTransform(scale);
@@ -4097,13 +4840,11 @@ TEST_F(LayerTreeHostImplTest, MaskLayerWithScaling) {
content_layer->SetBounds(scaling_layer_size);
content_layer->SetContentBounds(scaling_layer_size);
content_layer->SetPosition(gfx::PointF());
- content_layer->SetAnchorPoint(gfx::PointF());
content_layer->SetDrawsContent(true);
mask_layer->SetBounds(scaling_layer_size);
mask_layer->SetContentBounds(scaling_layer_size);
mask_layer->SetPosition(gfx::PointF());
- mask_layer->SetAnchorPoint(gfx::PointF());
mask_layer->SetDrawsContent(true);
@@ -4114,7 +4855,7 @@ TEST_F(LayerTreeHostImplTest, MaskLayerWithScaling) {
host_impl_->SetDeviceScaleFactor(device_scale_factor);
{
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
ASSERT_EQ(1u, frame.render_passes.size());
ASSERT_EQ(1u, frame.render_passes[0]->quad_list.size());
@@ -4142,7 +4883,7 @@ TEST_F(LayerTreeHostImplTest, MaskLayerWithScaling) {
host_impl_->active_tree()->set_needs_update_draw_properties();
{
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
ASSERT_EQ(1u, frame.render_passes.size());
ASSERT_EQ(1u, frame.render_passes[0]->quad_list.size());
@@ -4172,7 +4913,7 @@ TEST_F(LayerTreeHostImplTest, MaskLayerWithScaling) {
host_impl_->active_tree()->set_needs_update_draw_properties();
{
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
ASSERT_EQ(1u, frame.render_passes.size());
ASSERT_EQ(1u, frame.render_passes[0]->quad_list.size());
@@ -4213,20 +4954,17 @@ TEST_F(LayerTreeHostImplTest, MaskLayerWithDifferentBounds) {
root->SetBounds(root_size);
root->SetContentBounds(root_size);
root->SetPosition(gfx::PointF());
- root->SetAnchorPoint(gfx::PointF());
gfx::Size layer_size(50, 50);
content_layer->SetBounds(layer_size);
content_layer->SetContentBounds(layer_size);
content_layer->SetPosition(gfx::PointF());
- content_layer->SetAnchorPoint(gfx::PointF());
content_layer->SetDrawsContent(true);
gfx::Size mask_size(100, 100);
mask_layer->SetBounds(mask_size);
mask_layer->SetContentBounds(mask_size);
mask_layer->SetPosition(gfx::PointF());
- mask_layer->SetAnchorPoint(gfx::PointF());
mask_layer->SetDrawsContent(true);
// Check that the mask fills the surface.
@@ -4235,7 +4973,7 @@ TEST_F(LayerTreeHostImplTest, MaskLayerWithDifferentBounds) {
host_impl_->SetDeviceScaleFactor(device_scale_factor);
{
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
ASSERT_EQ(1u, frame.render_passes.size());
ASSERT_EQ(1u, frame.render_passes[0]->quad_list.size());
@@ -4262,7 +5000,7 @@ TEST_F(LayerTreeHostImplTest, MaskLayerWithDifferentBounds) {
host_impl_->active_tree()->set_needs_update_draw_properties();
{
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
ASSERT_EQ(1u, frame.render_passes.size());
ASSERT_EQ(1u, frame.render_passes[0]->quad_list.size());
@@ -4292,7 +5030,7 @@ TEST_F(LayerTreeHostImplTest, MaskLayerWithDifferentBounds) {
host_impl_->active_tree()->set_needs_update_draw_properties();
{
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
ASSERT_EQ(1u, frame.render_passes.size());
ASSERT_EQ(1u, frame.render_passes[0]->quad_list.size());
@@ -4317,7 +5055,7 @@ TEST_F(LayerTreeHostImplTest, MaskLayerWithDifferentBounds) {
host_impl_->active_tree()->set_needs_update_draw_properties();
{
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
ASSERT_EQ(1u, frame.render_passes.size());
ASSERT_EQ(1u, frame.render_passes[0]->quad_list.size());
@@ -4363,20 +5101,17 @@ TEST_F(LayerTreeHostImplTest, ReflectionMaskLayerWithDifferentBounds) {
root->SetBounds(root_size);
root->SetContentBounds(root_size);
root->SetPosition(gfx::PointF());
- root->SetAnchorPoint(gfx::PointF());
gfx::Size layer_size(50, 50);
content_layer->SetBounds(layer_size);
content_layer->SetContentBounds(layer_size);
content_layer->SetPosition(gfx::PointF());
- content_layer->SetAnchorPoint(gfx::PointF());
content_layer->SetDrawsContent(true);
gfx::Size mask_size(100, 100);
mask_layer->SetBounds(mask_size);
mask_layer->SetContentBounds(mask_size);
mask_layer->SetPosition(gfx::PointF());
- mask_layer->SetAnchorPoint(gfx::PointF());
mask_layer->SetDrawsContent(true);
// Check that the mask fills the surface.
@@ -4385,7 +5120,7 @@ TEST_F(LayerTreeHostImplTest, ReflectionMaskLayerWithDifferentBounds) {
host_impl_->SetDeviceScaleFactor(device_scale_factor);
{
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
ASSERT_EQ(1u, frame.render_passes.size());
ASSERT_EQ(2u, frame.render_passes[0]->quad_list.size());
@@ -4413,7 +5148,7 @@ TEST_F(LayerTreeHostImplTest, ReflectionMaskLayerWithDifferentBounds) {
host_impl_->active_tree()->set_needs_update_draw_properties();
{
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
ASSERT_EQ(1u, frame.render_passes.size());
ASSERT_EQ(2u, frame.render_passes[0]->quad_list.size());
@@ -4444,7 +5179,7 @@ TEST_F(LayerTreeHostImplTest, ReflectionMaskLayerWithDifferentBounds) {
host_impl_->active_tree()->set_needs_update_draw_properties();
{
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
ASSERT_EQ(1u, frame.render_passes.size());
ASSERT_EQ(2u, frame.render_passes[0]->quad_list.size());
@@ -4470,7 +5205,7 @@ TEST_F(LayerTreeHostImplTest, ReflectionMaskLayerWithDifferentBounds) {
host_impl_->active_tree()->set_needs_update_draw_properties();
{
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
ASSERT_EQ(1u, frame.render_passes.size());
ASSERT_EQ(2u, frame.render_passes[0]->quad_list.size());
@@ -4522,27 +5257,23 @@ TEST_F(LayerTreeHostImplTest, ReflectionMaskLayerForSurfaceWithUnclippedChild) {
root->SetBounds(root_size);
root->SetContentBounds(root_size);
root->SetPosition(gfx::PointF());
- root->SetAnchorPoint(gfx::PointF());
gfx::Size layer_size(50, 50);
content_layer->SetBounds(layer_size);
content_layer->SetContentBounds(layer_size);
content_layer->SetPosition(gfx::PointF());
- content_layer->SetAnchorPoint(gfx::PointF());
content_layer->SetDrawsContent(true);
gfx::Size child_size(50, 50);
content_child_layer->SetBounds(child_size);
content_child_layer->SetContentBounds(child_size);
content_child_layer->SetPosition(gfx::Point(50, 0));
- content_child_layer->SetAnchorPoint(gfx::PointF());
content_child_layer->SetDrawsContent(true);
gfx::Size mask_size(50, 50);
mask_layer->SetBounds(mask_size);
mask_layer->SetContentBounds(mask_size);
mask_layer->SetPosition(gfx::PointF());
- mask_layer->SetAnchorPoint(gfx::PointF());
mask_layer->SetDrawsContent(true);
float device_scale_factor = 1.f;
@@ -4550,7 +5281,7 @@ TEST_F(LayerTreeHostImplTest, ReflectionMaskLayerForSurfaceWithUnclippedChild) {
host_impl_->SetDeviceScaleFactor(device_scale_factor);
{
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
ASSERT_EQ(1u, frame.render_passes.size());
ASSERT_EQ(2u, frame.render_passes[0]->quad_list.size());
@@ -4584,7 +5315,7 @@ TEST_F(LayerTreeHostImplTest, ReflectionMaskLayerForSurfaceWithUnclippedChild) {
content_child_layer->SetPosition(gfx::Point(-50, 0));
{
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
ASSERT_EQ(1u, frame.render_passes.size());
ASSERT_EQ(2u, frame.render_passes[0]->quad_list.size());
@@ -4648,34 +5379,29 @@ TEST_F(LayerTreeHostImplTest, MaskLayerForSurfaceWithClippedLayer) {
root->SetBounds(root_size);
root->SetContentBounds(root_size);
root->SetPosition(gfx::PointF());
- root->SetAnchorPoint(gfx::PointF());
gfx::Rect clipping_rect(20, 10, 10, 20);
clipping_layer->SetBounds(clipping_rect.size());
clipping_layer->SetContentBounds(clipping_rect.size());
clipping_layer->SetPosition(clipping_rect.origin());
- clipping_layer->SetAnchorPoint(gfx::PointF());
clipping_layer->SetMasksToBounds(true);
gfx::Size layer_size(50, 50);
content_layer->SetBounds(layer_size);
content_layer->SetContentBounds(layer_size);
content_layer->SetPosition(gfx::Point() - clipping_rect.OffsetFromOrigin());
- content_layer->SetAnchorPoint(gfx::PointF());
content_layer->SetDrawsContent(true);
gfx::Size child_size(50, 50);
content_child_layer->SetBounds(child_size);
content_child_layer->SetContentBounds(child_size);
content_child_layer->SetPosition(gfx::Point(50, 0));
- content_child_layer->SetAnchorPoint(gfx::PointF());
content_child_layer->SetDrawsContent(true);
gfx::Size mask_size(100, 100);
mask_layer->SetBounds(mask_size);
mask_layer->SetContentBounds(mask_size);
mask_layer->SetPosition(gfx::PointF());
- mask_layer->SetAnchorPoint(gfx::PointF());
mask_layer->SetDrawsContent(true);
float device_scale_factor = 1.f;
@@ -4683,7 +5409,7 @@ TEST_F(LayerTreeHostImplTest, MaskLayerForSurfaceWithClippedLayer) {
host_impl_->SetDeviceScaleFactor(device_scale_factor);
{
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
ASSERT_EQ(1u, frame.render_passes.size());
ASSERT_EQ(1u, frame.render_passes[0]->quad_list.size());
@@ -4755,8 +5481,7 @@ TEST_F(LayerTreeHostImplTest, FarAwayQuadsDontNeedAA) {
root->SetBounds(root_size);
gfx::Vector2d scroll_offset(100000, 0);
- scrolling_layer->SetScrollable(true);
- scrolling_layer->SetMaxScrollOffset(scroll_offset);
+ scrolling_layer->SetScrollClipLayer(root->id());
scrolling_layer->SetScrollOffset(scroll_offset);
host_impl_->ActivatePendingTree();
@@ -4765,7 +5490,7 @@ TEST_F(LayerTreeHostImplTest, FarAwayQuadsDontNeedAA) {
ASSERT_EQ(1u, host_impl_->active_tree()->RenderSurfaceLayerList().size());
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
ASSERT_EQ(1u, frame.render_passes.size());
ASSERT_LE(1u, frame.render_passes[0]->quad_list.size());
@@ -4788,7 +5513,7 @@ class CompositorFrameMetadataTest : public LayerTreeHostImplTest {
CompositorFrameMetadataTest()
: swap_buffers_complete_(0) {}
- virtual void OnSwapBuffersCompleteOnImplThread() OVERRIDE {
+ virtual void DidSwapBuffersCompleteOnImplThread() OVERRIDE {
swap_buffers_complete_++;
}
@@ -4799,13 +5524,13 @@ TEST_F(CompositorFrameMetadataTest, CompositorFrameAckCountsAsSwapComplete) {
SetupRootLayerImpl(FakeLayerWithQuads::Create(host_impl_->active_tree(), 1));
{
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
host_impl_->DrawLayers(&frame, base::TimeTicks());
host_impl_->DidDrawAllLayers(frame);
}
CompositorFrameAck ack;
host_impl_->ReclaimResources(&ack);
- host_impl_->OnSwapBuffersComplete();
+ host_impl_->DidSwapBuffersComplete();
EXPECT_EQ(swap_buffers_complete_, 1);
}
@@ -4813,7 +5538,7 @@ class CountingSoftwareDevice : public SoftwareOutputDevice {
public:
CountingSoftwareDevice() : frames_began_(0), frames_ended_(0) {}
- virtual SkCanvas* BeginPaint(gfx::Rect damage_rect) OVERRIDE {
+ virtual SkCanvas* BeginPaint(const gfx::Rect& damage_rect) OVERRIDE {
++frames_began_;
return SoftwareOutputDevice::BeginPaint(damage_rect);
}
@@ -4829,8 +5554,11 @@ TEST_F(LayerTreeHostImplTest, ForcedDrawToSoftwareDeviceBasicRender) {
// No main thread evictions in resourceless software mode.
set_reduce_memory_result(false);
CountingSoftwareDevice* software_device = new CountingSoftwareDevice();
- FakeOutputSurface* output_surface = FakeOutputSurface::CreateDeferredGL(
- scoped_ptr<SoftwareOutputDevice>(software_device)).release();
+ bool delegated_rendering = false;
+ FakeOutputSurface* output_surface =
+ FakeOutputSurface::CreateDeferredGL(
+ scoped_ptr<SoftwareOutputDevice>(software_device),
+ delegated_rendering).release();
EXPECT_TRUE(CreateHostImpl(DefaultSettings(),
scoped_ptr<OutputSurface>(output_surface)));
host_impl_->SetViewportSize(gfx::Size(50, 50));
@@ -4856,8 +5584,11 @@ TEST_F(LayerTreeHostImplTest, ForcedDrawToSoftwareDeviceBasicRender) {
TEST_F(LayerTreeHostImplTest,
ForcedDrawToSoftwareDeviceSkipsUnsupportedLayers) {
set_reduce_memory_result(false);
- FakeOutputSurface* output_surface = FakeOutputSurface::CreateDeferredGL(
- scoped_ptr<SoftwareOutputDevice>(new CountingSoftwareDevice())).release();
+ bool delegated_rendering = false;
+ FakeOutputSurface* output_surface =
+ FakeOutputSurface::CreateDeferredGL(
+ scoped_ptr<SoftwareOutputDevice>(new CountingSoftwareDevice()),
+ delegated_rendering).release();
EXPECT_TRUE(CreateHostImpl(DefaultSettings(),
scoped_ptr<OutputSurface>(output_surface)));
@@ -4879,7 +5610,7 @@ TEST_F(LayerTreeHostImplTest,
SetupRootLayerImpl(root_layer.PassAs<LayerImpl>());
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
host_impl_->DidDrawAllLayers(frame);
@@ -4894,9 +5625,11 @@ class LayerTreeHostImplTestDeferredInitialize : public LayerTreeHostImplTest {
set_reduce_memory_result(false);
+ bool delegated_rendering = false;
scoped_ptr<FakeOutputSurface> output_surface(
FakeOutputSurface::CreateDeferredGL(
- scoped_ptr<SoftwareOutputDevice>(new CountingSoftwareDevice())));
+ scoped_ptr<SoftwareOutputDevice>(new CountingSoftwareDevice()),
+ delegated_rendering));
output_surface_ = output_surface.get();
EXPECT_TRUE(CreateHostImpl(DefaultSettings(),
@@ -4907,12 +5640,15 @@ class LayerTreeHostImplTestDeferredInitialize : public LayerTreeHostImplTest {
SetupRootLayerImpl(root_layer.PassAs<LayerImpl>());
onscreen_context_provider_ = TestContextProvider::Create();
- offscreen_context_provider_ = TestContextProvider::Create();
+ }
+
+ virtual void UpdateRendererCapabilitiesOnImplThread() OVERRIDE {
+ did_update_renderer_capabilities_ = true;
}
FakeOutputSurface* output_surface_;
scoped_refptr<TestContextProvider> onscreen_context_provider_;
- scoped_refptr<TestContextProvider> offscreen_context_provider_;
+ bool did_update_renderer_capabilities_;
};
@@ -4921,29 +5657,29 @@ TEST_F(LayerTreeHostImplTestDeferredInitialize, Success) {
DrawFrame();
EXPECT_FALSE(host_impl_->output_surface()->context_provider());
- EXPECT_FALSE(host_impl_->offscreen_context_provider());
// DeferredInitialize and hardware draw.
- EXPECT_TRUE(output_surface_->InitializeAndSetContext3d(
- onscreen_context_provider_, offscreen_context_provider_));
+ did_update_renderer_capabilities_ = false;
+ EXPECT_TRUE(
+ output_surface_->InitializeAndSetContext3d(onscreen_context_provider_));
EXPECT_EQ(onscreen_context_provider_,
host_impl_->output_surface()->context_provider());
- EXPECT_EQ(offscreen_context_provider_,
- host_impl_->offscreen_context_provider());
+ EXPECT_TRUE(did_update_renderer_capabilities_);
// Defer intialized GL draw.
DrawFrame();
// Revert back to software.
+ did_update_renderer_capabilities_ = false;
output_surface_->ReleaseGL();
EXPECT_FALSE(host_impl_->output_surface()->context_provider());
- EXPECT_FALSE(host_impl_->offscreen_context_provider());
+ EXPECT_TRUE(did_update_renderer_capabilities_);
// Software draw again.
DrawFrame();
}
-TEST_F(LayerTreeHostImplTestDeferredInitialize, Fails_OnscreenContext_0) {
+TEST_F(LayerTreeHostImplTestDeferredInitialize, Fails) {
// Software draw.
DrawFrame();
@@ -4952,74 +5688,28 @@ TEST_F(LayerTreeHostImplTestDeferredInitialize, Fails_OnscreenContext_0) {
onscreen_context_provider_->UnboundTestContext3d()->set_context_lost(true);
EXPECT_FALSE(host_impl_->output_surface()->context_provider());
- EXPECT_FALSE(host_impl_->offscreen_context_provider());
// DeferredInitialize fails.
- EXPECT_FALSE(output_surface_->InitializeAndSetContext3d(
- onscreen_context_provider_, offscreen_context_provider_));
+ did_update_renderer_capabilities_ = false;
+ EXPECT_FALSE(
+ output_surface_->InitializeAndSetContext3d(onscreen_context_provider_));
EXPECT_FALSE(host_impl_->output_surface()->context_provider());
- EXPECT_FALSE(host_impl_->offscreen_context_provider());
+ EXPECT_FALSE(did_update_renderer_capabilities_);
// Software draw again.
DrawFrame();
}
-TEST_F(LayerTreeHostImplTestDeferredInitialize, Fails_OnscreenContext_1) {
- // Software draw.
- DrawFrame();
-
- EXPECT_FALSE(host_impl_->output_surface()->context_provider());
- EXPECT_FALSE(host_impl_->offscreen_context_provider());
-
- onscreen_context_provider_->UnboundTestContext3d()->set_context_lost(true);
-
- EXPECT_FALSE(host_impl_->output_surface()->context_provider());
- // DeferredInitialize fails.
- EXPECT_FALSE(output_surface_->InitializeAndSetContext3d(
- onscreen_context_provider_, offscreen_context_provider_));
- EXPECT_FALSE(host_impl_->output_surface()->context_provider());
- EXPECT_FALSE(host_impl_->offscreen_context_provider());
-}
-
-TEST_F(LayerTreeHostImplTestDeferredInitialize, Fails_OnscreenContext_2) {
- // Software draw.
- DrawFrame();
-
- EXPECT_FALSE(host_impl_->output_surface()->context_provider());
- EXPECT_FALSE(host_impl_->offscreen_context_provider());
-
- onscreen_context_provider_->UnboundTestContext3d()->set_context_lost(true);
-
- // DeferredInitialize fails.
- EXPECT_FALSE(output_surface_->InitializeAndSetContext3d(
- onscreen_context_provider_, offscreen_context_provider_));
- EXPECT_FALSE(host_impl_->output_surface()->context_provider());
- EXPECT_FALSE(host_impl_->offscreen_context_provider());
-}
-
-TEST_F(LayerTreeHostImplTestDeferredInitialize, Fails_OffscreenContext) {
- // Software draw.
- DrawFrame();
-
- EXPECT_FALSE(host_impl_->output_surface()->context_provider());
- EXPECT_FALSE(host_impl_->offscreen_context_provider());
-
- // Fail initialization of the offscreen context.
- onscreen_context_provider_->UnboundTestContext3d()->set_context_lost(true);
-
- // DeferredInitialize fails.
- EXPECT_FALSE(output_surface_->InitializeAndSetContext3d(
- onscreen_context_provider_, offscreen_context_provider_));
- EXPECT_FALSE(host_impl_->output_surface()->context_provider());
- EXPECT_FALSE(host_impl_->offscreen_context_provider());
-}
-
// Checks that we have a non-0 default allocation if we pass a context that
// doesn't support memory management extensions.
TEST_F(LayerTreeHostImplTest, DefaultMemoryAllocation) {
LayerTreeSettings settings;
- host_impl_ = LayerTreeHostImpl::Create(
- settings, this, &proxy_, &stats_instrumentation_, NULL, 0);
+ host_impl_ = LayerTreeHostImpl::Create(settings,
+ this,
+ &proxy_,
+ &stats_instrumentation_,
+ shared_bitmap_manager_.get(),
+ 0);
scoped_ptr<OutputSurface> output_surface(
FakeOutputSurface::Create3d(TestWebGraphicsContext3D::Create()));
@@ -5032,9 +5722,16 @@ TEST_F(LayerTreeHostImplTest, MemoryPolicy) {
456, gpu::MemoryAllocation::CUTOFF_ALLOW_EVERYTHING, 1000);
int everything_cutoff_value = ManagedMemoryPolicy::PriorityCutoffToValue(
gpu::MemoryAllocation::CUTOFF_ALLOW_EVERYTHING);
+ int allow_nice_to_have_cutoff_value =
+ ManagedMemoryPolicy::PriorityCutoffToValue(
+ gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE);
int nothing_cutoff_value = ManagedMemoryPolicy::PriorityCutoffToValue(
gpu::MemoryAllocation::CUTOFF_ALLOW_NOTHING);
+ // GPU rasterization should be disabled by default on the tree(s)
+ EXPECT_FALSE(host_impl_->active_tree()->use_gpu_rasterization());
+ EXPECT_TRUE(host_impl_->pending_tree() == NULL);
+
host_impl_->SetVisible(true);
host_impl_->SetMemoryPolicy(policy1);
EXPECT_EQ(policy1.bytes_limit_when_visible, current_limit_bytes_);
@@ -5047,6 +5744,61 @@ TEST_F(LayerTreeHostImplTest, MemoryPolicy) {
host_impl_->SetVisible(true);
EXPECT_EQ(policy1.bytes_limit_when_visible, current_limit_bytes_);
EXPECT_EQ(everything_cutoff_value, current_priority_cutoff_value_);
+
+ // Now enable GPU rasterization and test if we get nice to have cutoff,
+ // when visible.
+ LayerTreeSettings settings;
+ settings.gpu_rasterization_enabled = true;
+ host_impl_ = LayerTreeHostImpl::Create(
+ settings, this, &proxy_, &stats_instrumentation_, NULL, 0);
+ host_impl_->SetUseGpuRasterization(true);
+ host_impl_->SetVisible(true);
+ host_impl_->SetMemoryPolicy(policy1);
+ EXPECT_EQ(policy1.bytes_limit_when_visible, current_limit_bytes_);
+ EXPECT_EQ(allow_nice_to_have_cutoff_value, current_priority_cutoff_value_);
+
+ host_impl_->SetVisible(false);
+ EXPECT_EQ(0u, current_limit_bytes_);
+ EXPECT_EQ(nothing_cutoff_value, current_priority_cutoff_value_);
+}
+
+TEST_F(LayerTreeHostImplTest, RequireHighResWhenVisible) {
+ ASSERT_TRUE(host_impl_->active_tree());
+
+ EXPECT_FALSE(host_impl_->active_tree()->RequiresHighResToDraw());
+ host_impl_->SetVisible(false);
+ EXPECT_FALSE(host_impl_->active_tree()->RequiresHighResToDraw());
+ host_impl_->SetVisible(true);
+ EXPECT_TRUE(host_impl_->active_tree()->RequiresHighResToDraw());
+ host_impl_->SetVisible(false);
+ EXPECT_TRUE(host_impl_->active_tree()->RequiresHighResToDraw());
+
+ host_impl_->CreatePendingTree();
+ host_impl_->ActivatePendingTree();
+
+ EXPECT_FALSE(host_impl_->active_tree()->RequiresHighResToDraw());
+ host_impl_->SetVisible(true);
+ EXPECT_TRUE(host_impl_->active_tree()->RequiresHighResToDraw());
+}
+
+TEST_F(LayerTreeHostImplTest, RequireHighResAfterGpuRasterizationToggles) {
+ ASSERT_TRUE(host_impl_->active_tree());
+ EXPECT_FALSE(host_impl_->use_gpu_rasterization());
+
+ EXPECT_FALSE(host_impl_->active_tree()->RequiresHighResToDraw());
+ host_impl_->SetUseGpuRasterization(false);
+ EXPECT_FALSE(host_impl_->active_tree()->RequiresHighResToDraw());
+ host_impl_->SetUseGpuRasterization(true);
+ EXPECT_TRUE(host_impl_->active_tree()->RequiresHighResToDraw());
+ host_impl_->SetUseGpuRasterization(false);
+ EXPECT_TRUE(host_impl_->active_tree()->RequiresHighResToDraw());
+
+ host_impl_->CreatePendingTree();
+ host_impl_->ActivatePendingTree();
+
+ EXPECT_FALSE(host_impl_->active_tree()->RequiresHighResToDraw());
+ host_impl_->SetUseGpuRasterization(true);
+ EXPECT_TRUE(host_impl_->active_tree()->RequiresHighResToDraw());
}
class LayerTreeHostImplTestManageTiles : public LayerTreeHostImplTest {
@@ -5055,7 +5807,8 @@ class LayerTreeHostImplTestManageTiles : public LayerTreeHostImplTest {
LayerTreeSettings settings;
settings.impl_side_painting = true;
- fake_host_impl_ = new FakeLayerTreeHostImpl(settings, &proxy_);
+ fake_host_impl_ = new FakeLayerTreeHostImpl(
+ settings, &proxy_, shared_bitmap_manager_.get());
host_impl_.reset(fake_host_impl_);
host_impl_->InitializeRenderer(CreateOutputSurface());
host_impl_->SetViewportSize(gfx::Size(10, 10));
@@ -5075,18 +5828,14 @@ TEST_F(LayerTreeHostImplTest, UIResourceManagement) {
scoped_ptr<TestWebGraphicsContext3D> context =
TestWebGraphicsContext3D::Create();
TestWebGraphicsContext3D* context3d = context.get();
- scoped_ptr<OutputSurface> output_surface = CreateFakeOutputSurface();
- CreateHostImpl(DefaultSettings(), output_surface.Pass());
+ scoped_ptr<FakeOutputSurface> output_surface = FakeOutputSurface::Create3d();
+ CreateHostImpl(DefaultSettings(), output_surface.PassAs<OutputSurface>());
EXPECT_EQ(0u, context3d->NumTextures());
- SkBitmap skbitmap;
- skbitmap.setConfig(SkBitmap::kARGB_8888_Config, 1, 1);
- skbitmap.allocPixels();
- skbitmap.setImmutable();
-
UIResourceId ui_resource_id = 1;
- UIResourceBitmap bitmap(skbitmap);
+ bool is_opaque = false;
+ UIResourceBitmap bitmap(gfx::Size(1, 1), is_opaque);
host_impl_->CreateUIResource(ui_resource_id, bitmap);
EXPECT_EQ(1u, context3d->NumTextures());
ResourceProvider::ResourceId id1 =
@@ -5124,16 +5873,21 @@ TEST_F(LayerTreeHostImplTest, CreateETC1UIResource) {
scoped_ptr<TestWebGraphicsContext3D> context =
TestWebGraphicsContext3D::Create();
TestWebGraphicsContext3D* context3d = context.get();
- scoped_ptr<OutputSurface> output_surface = CreateFakeOutputSurface();
- CreateHostImpl(DefaultSettings(), output_surface.Pass());
+ scoped_ptr<FakeOutputSurface> output_surface = FakeOutputSurface::Create3d();
+ CreateHostImpl(DefaultSettings(), output_surface.PassAs<OutputSurface>());
EXPECT_EQ(0u, context3d->NumTextures());
- scoped_ptr<uint8_t[]> pixels(new uint8_t[8]);
- skia::RefPtr<ETC1PixelRef> etc1_pixel_ref =
- skia::AdoptRef(new ETC1PixelRef(pixels.Pass()));
- UIResourceBitmap bitmap(etc1_pixel_ref, gfx::Size(4, 4));
-
+ gfx::Size size(4, 4);
+ // SkImageInfo has no support for ETC1. The |info| below contains the right
+ // total pixel size for the bitmap but not the right height and width. The
+ // correct width/height are passed directly to UIResourceBitmap.
+ SkImageInfo info =
+ SkImageInfo::Make(4, 2, kAlpha_8_SkColorType, kPremul_SkAlphaType);
+ skia::RefPtr<SkPixelRef> pixel_ref =
+ skia::AdoptRef(SkMallocPixelRef::NewAllocate(info, 0, 0));
+ pixel_ref->setImmutable();
+ UIResourceBitmap bitmap(pixel_ref, size);
UIResourceId ui_resource_id = 1;
host_impl_->CreateUIResource(ui_resource_id, bitmap);
EXPECT_EQ(1u, context3d->NumTextures());
@@ -5162,7 +5916,7 @@ TEST_F(LayerTreeHostImplTest, ShutdownReleasesContext) {
host_impl_->active_tree()->root_layer()->PassCopyRequests(&requests);
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
host_impl_->DidDrawAllLayers(frame);
@@ -5184,13 +5938,21 @@ TEST_F(LayerTreeHostImplTest, TouchFlingShouldNotBubble) {
// bubble).
gfx::Size surface_size(10, 10);
gfx::Size content_size(20, 20);
- scoped_ptr<LayerImpl> root = CreateScrollableLayer(1, content_size);
- scoped_ptr<LayerImpl> child = CreateScrollableLayer(2, content_size);
+ scoped_ptr<LayerImpl> root_clip =
+ LayerImpl::Create(host_impl_->active_tree(), 3);
+ scoped_ptr<LayerImpl> root =
+ CreateScrollableLayer(1, content_size, root_clip.get());
+ root->SetIsContainerForFixedPositionLayers(true);
+ scoped_ptr<LayerImpl> child =
+ CreateScrollableLayer(2, content_size, root_clip.get());
root->AddChild(child.Pass());
+ int root_id = root->id();
+ root_clip->AddChild(root.Pass());
host_impl_->SetViewportSize(surface_size);
- host_impl_->active_tree()->SetRootLayer(root.Pass());
+ host_impl_->active_tree()->SetRootLayer(root_clip.Pass());
+ host_impl_->active_tree()->SetViewportLayersFromIds(3, 1, Layer::INVALID_ID);
host_impl_->active_tree()->DidBecomeActive();
DrawFrame();
{
@@ -5212,56 +5974,75 @@ TEST_F(LayerTreeHostImplTest, TouchFlingShouldNotBubble) {
// Only the child should have scrolled.
ASSERT_EQ(1u, scroll_info->scrolls.size());
- ExpectNone(*scroll_info.get(),
- host_impl_->active_tree()->root_layer()->id());
+ ExpectNone(*scroll_info.get(), root_id);
}
}
-TEST_F(LayerTreeHostImplTest, TouchFlingShouldBubbleIfPrecedingScrollBubbled) {
- // When flinging via touch, bubble scrolls if the touch scroll
- // immediately preceding the fling bubbled.
+TEST_F(LayerTreeHostImplTest, TouchFlingShouldLockToFirstScrolledLayer) {
+ // Scroll a child layer beyond its maximum scroll range and make sure the
+ // the scroll doesn't bubble up to the parent layer.
gfx::Size surface_size(10, 10);
- gfx::Size root_content_size(10, 20);
- gfx::Size child_content_size(40, 40);
- scoped_ptr<LayerImpl> root = CreateScrollableLayer(1, root_content_size);
- scoped_ptr<LayerImpl> child = CreateScrollableLayer(2, child_content_size);
+ scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_->active_tree(), 1);
+ scoped_ptr<LayerImpl> root_scrolling =
+ CreateScrollableLayer(2, surface_size, root.get());
- root->AddChild(child.Pass());
+ scoped_ptr<LayerImpl> grand_child =
+ CreateScrollableLayer(4, surface_size, root.get());
+ grand_child->SetScrollOffset(gfx::Vector2d(0, 2));
- host_impl_->SetViewportSize(surface_size);
+ scoped_ptr<LayerImpl> child =
+ CreateScrollableLayer(3, surface_size, root.get());
+ child->SetScrollOffset(gfx::Vector2d(0, 4));
+ child->AddChild(grand_child.Pass());
+
+ root_scrolling->AddChild(child.Pass());
+ root->AddChild(root_scrolling.Pass());
host_impl_->active_tree()->SetRootLayer(root.Pass());
host_impl_->active_tree()->DidBecomeActive();
+ host_impl_->SetViewportSize(surface_size);
DrawFrame();
{
+ scoped_ptr<ScrollAndScaleSet> scroll_info;
+ LayerImpl* child =
+ host_impl_->active_tree()->root_layer()->children()[0]->children()[0];
+ LayerImpl* grand_child = child->children()[0];
+
+ gfx::Vector2d scroll_delta(0, -2);
EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(),
- InputHandler::Gesture));
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), scroll_delta));
- // Touch scroll before starting the fling. The second scroll should bubble.
- EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 100)));
- EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 5)));
+ // The grand child should have scrolled up to its limit.
+ scroll_info = host_impl_->ProcessScrollDeltas();
+ ASSERT_EQ(1u, scroll_info->scrolls.size());
+ ExpectContains(*scroll_info, grand_child->id(), scroll_delta);
+ EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child);
- scoped_ptr<ScrollAndScaleSet> scroll_info =
- host_impl_->ProcessScrollDeltas();
+ // The child should have received the bubbled delta, but the locked
+ // scrolling layer should remain set as the grand child.
+ EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), scroll_delta));
+ scroll_info = host_impl_->ProcessScrollDeltas();
+ ASSERT_EQ(2u, scroll_info->scrolls.size());
+ ExpectContains(*scroll_info, grand_child->id(), scroll_delta);
+ ExpectContains(*scroll_info, child->id(), scroll_delta);
+ EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child);
- // The root should have (partially) scrolled.
- EXPECT_EQ(2u, scroll_info->scrolls.size());
- ExpectContains(*scroll_info.get(),
- host_impl_->active_tree()->root_layer()->id(),
- gfx::Vector2d(0, 5));
+ // The first |ScrollBy| after the fling should re-lock the scrolling
+ // layer to the first layer that scrolled, which is the child.
+ EXPECT_EQ(InputHandler::ScrollStarted, host_impl_->FlingScrollBegin());
+ EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), scroll_delta));
+ EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), child);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->FlingScrollBegin());
+ // The child should have scrolled up to its limit.
+ scroll_info = host_impl_->ProcessScrollDeltas();
+ ASSERT_EQ(2u, scroll_info->scrolls.size());
+ ExpectContains(*scroll_info, grand_child->id(), scroll_delta);
+ ExpectContains(*scroll_info, child->id(), scroll_delta + scroll_delta);
- EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 5)));
+ // As the locked layer is at it's limit, no further scrolling can occur.
+ EXPECT_FALSE(host_impl_->ScrollBy(gfx::Point(), scroll_delta));
+ EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), child);
host_impl_->ScrollEnd();
-
- // The root should have (fully) scrolled from the fling.
- scroll_info = host_impl_->ProcessScrollDeltas();
- EXPECT_EQ(2u, scroll_info->scrolls.size());
- ExpectContains(*scroll_info.get(),
- host_impl_->active_tree()->root_layer()->id(),
- gfx::Vector2d(0, 10));
}
}
@@ -5270,13 +6051,19 @@ TEST_F(LayerTreeHostImplTest, WheelFlingShouldBubble) {
// bubble).
gfx::Size surface_size(10, 10);
gfx::Size content_size(20, 20);
- scoped_ptr<LayerImpl> root = CreateScrollableLayer(1, content_size);
- scoped_ptr<LayerImpl> child = CreateScrollableLayer(2, content_size);
+ scoped_ptr<LayerImpl> root_clip =
+ LayerImpl::Create(host_impl_->active_tree(), 3);
+ scoped_ptr<LayerImpl> root_scroll =
+ CreateScrollableLayer(1, content_size, root_clip.get());
+ int root_scroll_id = root_scroll->id();
+ scoped_ptr<LayerImpl> child =
+ CreateScrollableLayer(2, content_size, root_clip.get());
- root->AddChild(child.Pass());
+ root_scroll->AddChild(child.Pass());
+ root_clip->AddChild(root_scroll.Pass());
host_impl_->SetViewportSize(surface_size);
- host_impl_->active_tree()->SetRootLayer(root.Pass());
+ host_impl_->active_tree()->SetRootLayer(root_clip.Pass());
host_impl_->active_tree()->DidBecomeActive();
DrawFrame();
{
@@ -5297,18 +6084,174 @@ TEST_F(LayerTreeHostImplTest, WheelFlingShouldBubble) {
// The root should have scrolled.
ASSERT_EQ(2u, scroll_info->scrolls.size());
- ExpectContains(*scroll_info.get(),
- host_impl_->active_tree()->root_layer()->id(),
- gfx::Vector2d(0, 10));
+ ExpectContains(*scroll_info.get(), root_scroll_id, gfx::Vector2d(0, 10));
}
}
+TEST_F(LayerTreeHostImplTest, ScrollUnknownNotOnAncestorChain) {
+ // If we ray cast a scroller that is not on the first layer's ancestor chain,
+ // we should return ScrollUnknown.
+ gfx::Size content_size(100, 100);
+ SetupScrollAndContentsLayers(content_size);
+
+ int scroll_layer_id = 2;
+ LayerImpl* scroll_layer =
+ host_impl_->active_tree()->LayerById(scroll_layer_id);
+ scroll_layer->SetDrawsContent(true);
+
+ int page_scale_layer_id = 5;
+ LayerImpl* page_scale_layer =
+ host_impl_->active_tree()->LayerById(page_scale_layer_id);
+
+ int occluder_layer_id = 6;
+ scoped_ptr<LayerImpl> occluder_layer =
+ LayerImpl::Create(host_impl_->active_tree(), occluder_layer_id);
+ occluder_layer->SetDrawsContent(true);
+ occluder_layer->SetBounds(content_size);
+ occluder_layer->SetContentBounds(content_size);
+ occluder_layer->SetPosition(gfx::PointF());
+
+ // The parent of the occluder is *above* the scroller.
+ page_scale_layer->AddChild(occluder_layer.Pass());
+
+ DrawFrame();
+
+ EXPECT_EQ(InputHandler::ScrollUnknown,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+}
+
+TEST_F(LayerTreeHostImplTest, ScrollUnknownScrollAncestorMismatch) {
+ // If we ray cast a scroller this is on the first layer's ancestor chain, but
+ // is not the first scroller we encounter when walking up from the layer, we
+ // should also return ScrollUnknown.
+ gfx::Size content_size(100, 100);
+ SetupScrollAndContentsLayers(content_size);
+
+ int scroll_layer_id = 2;
+ LayerImpl* scroll_layer =
+ host_impl_->active_tree()->LayerById(scroll_layer_id);
+ scroll_layer->SetDrawsContent(true);
+
+ int occluder_layer_id = 6;
+ scoped_ptr<LayerImpl> occluder_layer =
+ LayerImpl::Create(host_impl_->active_tree(), occluder_layer_id);
+ occluder_layer->SetDrawsContent(true);
+ occluder_layer->SetBounds(content_size);
+ occluder_layer->SetContentBounds(content_size);
+ occluder_layer->SetPosition(gfx::PointF(-10.f, -10.f));
+
+ int child_scroll_clip_layer_id = 7;
+ scoped_ptr<LayerImpl> child_scroll_clip =
+ LayerImpl::Create(host_impl_->active_tree(), child_scroll_clip_layer_id);
+
+ int child_scroll_layer_id = 8;
+ scoped_ptr<LayerImpl> child_scroll = CreateScrollableLayer(
+ child_scroll_layer_id, content_size, child_scroll_clip.get());
+
+ child_scroll->SetPosition(gfx::PointF(10.f, 10.f));
+
+ child_scroll->AddChild(occluder_layer.Pass());
+ scroll_layer->AddChild(child_scroll.Pass());
+
+ DrawFrame();
+
+ EXPECT_EQ(InputHandler::ScrollUnknown,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+}
+
+TEST_F(LayerTreeHostImplTest, ScrollInvisibleScroller) {
+ gfx::Size content_size(100, 100);
+ SetupScrollAndContentsLayers(content_size);
+
+ LayerImpl* root = host_impl_->active_tree()->LayerById(1);
+
+ int scroll_layer_id = 2;
+ LayerImpl* scroll_layer =
+ host_impl_->active_tree()->LayerById(scroll_layer_id);
+
+ int child_scroll_layer_id = 7;
+ scoped_ptr<LayerImpl> child_scroll =
+ CreateScrollableLayer(child_scroll_layer_id, content_size, root);
+ child_scroll->SetDrawsContent(false);
+
+ scroll_layer->AddChild(child_scroll.Pass());
+
+ DrawFrame();
+
+ // We should not have scrolled |child_scroll| even though we technically "hit"
+ // it. The reason for this is that if the scrolling the scroll would not move
+ // any layer that is a drawn RSLL member, then we can ignore the hit.
+ //
+ // Why ScrollStarted? In this case, it's because we've bubbled out and started
+ // overscrolling the inner viewport.
+ EXPECT_EQ(InputHandler::ScrollStarted,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+
+ EXPECT_EQ(2, host_impl_->CurrentlyScrollingLayer()->id());
+}
+
+TEST_F(LayerTreeHostImplTest, ScrollInvisibleScrollerWithVisibleScrollChild) {
+ // This test case is very similar to the one above with one key difference:
+ // the invisible scroller has a scroll child that is indeed draw contents.
+ // If we attempt to initiate a gesture scroll off of the visible scroll child
+ // we should still start the scroll child.
+ gfx::Size content_size(100, 100);
+ SetupScrollAndContentsLayers(content_size);
+
+ LayerImpl* root = host_impl_->active_tree()->LayerById(1);
+
+ int scroll_layer_id = 2;
+ LayerImpl* scroll_layer =
+ host_impl_->active_tree()->LayerById(scroll_layer_id);
+
+ int scroll_child_id = 6;
+ scoped_ptr<LayerImpl> scroll_child =
+ LayerImpl::Create(host_impl_->active_tree(), scroll_child_id);
+ scroll_child->SetDrawsContent(true);
+ scroll_child->SetBounds(content_size);
+ scroll_child->SetContentBounds(content_size);
+ // Move the scroll child so it's not hit by our test point.
+ scroll_child->SetPosition(gfx::PointF(10.f, 10.f));
+
+ int invisible_scroll_layer_id = 7;
+ scoped_ptr<LayerImpl> invisible_scroll =
+ CreateScrollableLayer(invisible_scroll_layer_id, content_size, root);
+ invisible_scroll->SetDrawsContent(false);
+
+ int container_id = 8;
+ scoped_ptr<LayerImpl> container =
+ LayerImpl::Create(host_impl_->active_tree(), container_id);
+
+ scoped_ptr<std::set<LayerImpl*> > scroll_children(new std::set<LayerImpl*>());
+ scroll_children->insert(scroll_child.get());
+ invisible_scroll->SetScrollChildren(scroll_children.release());
+
+ scroll_child->SetScrollParent(invisible_scroll.get());
+
+ container->AddChild(invisible_scroll.Pass());
+ container->AddChild(scroll_child.Pass());
+
+ scroll_layer->AddChild(container.Pass());
+
+ DrawFrame();
+
+ // We should not have scrolled |child_scroll| even though we technically "hit"
+ // it. The reason for this is that if the scrolling the scroll would not move
+ // any layer that is a drawn RSLL member, then we can ignore the hit.
+ //
+ // Why ScrollStarted? In this case, it's because we've bubbled out and started
+ // overscrolling the inner viewport.
+ EXPECT_EQ(InputHandler::ScrollStarted,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+
+ EXPECT_EQ(7, host_impl_->CurrentlyScrollingLayer()->id());
+}
+
// Make sure LatencyInfo carried by LatencyInfoSwapPromise are passed
// to CompositorFrameMetadata after SwapBuffers();
TEST_F(LayerTreeHostImplTest, LatencyInfoPassedToCompositorFrameMetadata) {
scoped_ptr<SolidColorLayerImpl> root =
SolidColorLayerImpl::Create(host_impl_->active_tree(), 1);
- root->SetAnchorPoint(gfx::PointF());
root->SetPosition(gfx::PointF());
root->SetBounds(gfx::Size(10, 10));
root->SetContentBounds(gfx::Size(10, 10));
@@ -5319,10 +6262,9 @@ TEST_F(LayerTreeHostImplTest, LatencyInfoPassedToCompositorFrameMetadata) {
FakeOutputSurface* fake_output_surface =
static_cast<FakeOutputSurface*>(host_impl_->output_surface());
- const ui::LatencyInfo& metadata_latency_before =
+ const std::vector<ui::LatencyInfo>& metadata_latency_before =
fake_output_surface->last_sent_frame().metadata.latency_info;
- EXPECT_FALSE(metadata_latency_before.FindLatency(
- ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, 0, NULL));
+ EXPECT_TRUE(metadata_latency_before.empty());
ui::LatencyInfo latency_info;
latency_info.AddLatencyNumber(
@@ -5334,14 +6276,15 @@ TEST_F(LayerTreeHostImplTest, LatencyInfoPassedToCompositorFrameMetadata) {
gfx::Rect full_frame_damage(host_impl_->DrawViewportSize());
LayerTreeHostImpl::FrameData frame;
- EXPECT_TRUE(host_impl_->PrepareToDraw(&frame, gfx::Rect()));
+ EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
host_impl_->DidDrawAllLayers(frame);
EXPECT_TRUE(host_impl_->SwapBuffers(frame));
- const ui::LatencyInfo& metadata_latency_after =
+ const std::vector<ui::LatencyInfo>& metadata_latency_after =
fake_output_surface->last_sent_frame().metadata.latency_info;
- EXPECT_TRUE(metadata_latency_after.FindLatency(
+ EXPECT_EQ(1u, metadata_latency_after.size());
+ EXPECT_TRUE(metadata_latency_after[0].FindLatency(
ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, 0, NULL));
}
@@ -5415,5 +6358,246 @@ TEST_F(LayerTreeHostImplTest, SimpleSwapPromiseMonitor) {
}
}
+class LayerTreeHostImplWithTopControlsTest : public LayerTreeHostImplTest {
+ public:
+ virtual void SetUp() OVERRIDE {
+ LayerTreeSettings settings = DefaultSettings();
+ settings.calculate_top_controls_position = true;
+ settings.top_controls_height = top_controls_height_;
+ CreateHostImpl(settings, CreateOutputSurface());
+ }
+
+ protected:
+ static const int top_controls_height_;
+};
+
+const int LayerTreeHostImplWithTopControlsTest::top_controls_height_ = 50;
+
+TEST_F(LayerTreeHostImplWithTopControlsTest, NoIdleAnimations) {
+ SetupScrollAndContentsLayers(gfx::Size(100, 100))
+ ->SetScrollOffset(gfx::Vector2d(0, 10));
+ host_impl_->Animate(base::TimeTicks());
+ EXPECT_FALSE(did_request_redraw_);
+}
+
+TEST_F(LayerTreeHostImplWithTopControlsTest, TopControlsAnimationScheduling) {
+ SetupScrollAndContentsLayers(gfx::Size(100, 100))
+ ->SetScrollOffset(gfx::Vector2d(0, 10));
+ host_impl_->DidChangeTopControlsPosition();
+ EXPECT_TRUE(did_request_animate_);
+ EXPECT_TRUE(did_request_redraw_);
+}
+
+TEST_F(LayerTreeHostImplWithTopControlsTest, ScrollHandledByTopControls) {
+ LayerImpl* scroll_layer = SetupScrollAndContentsLayers(gfx::Size(100, 200));
+ host_impl_->SetViewportSize(gfx::Size(100, 100));
+ DrawFrame();
+
+ EXPECT_EQ(InputHandler::ScrollStarted,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(0, host_impl_->top_controls_manager()->controls_top_offset());
+ EXPECT_EQ(gfx::Vector2dF().ToString(),
+ scroll_layer->TotalScrollOffset().ToString());
+
+ // Scroll just the top controls and verify that the scroll succeeds.
+ const float residue = 10;
+ float offset = top_controls_height_ - residue;
+ EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)));
+ EXPECT_EQ(-offset, host_impl_->top_controls_manager()->controls_top_offset());
+ EXPECT_EQ(gfx::Vector2dF().ToString(),
+ scroll_layer->TotalScrollOffset().ToString());
+
+ // Scroll across the boundary
+ const float content_scroll = 20;
+ offset = residue + content_scroll;
+ EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)));
+ EXPECT_EQ(-top_controls_height_,
+ host_impl_->top_controls_manager()->controls_top_offset());
+ EXPECT_EQ(gfx::Vector2dF(0, content_scroll).ToString(),
+ scroll_layer->TotalScrollOffset().ToString());
+
+ // Now scroll back to the top of the content
+ offset = -content_scroll;
+ EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)));
+ EXPECT_EQ(-top_controls_height_,
+ host_impl_->top_controls_manager()->controls_top_offset());
+ EXPECT_EQ(gfx::Vector2dF().ToString(),
+ scroll_layer->TotalScrollOffset().ToString());
+
+ // And scroll the top controls completely into view
+ offset = -top_controls_height_;
+ EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)));
+ EXPECT_EQ(0, host_impl_->top_controls_manager()->controls_top_offset());
+ EXPECT_EQ(gfx::Vector2dF().ToString(),
+ scroll_layer->TotalScrollOffset().ToString());
+
+ // And attempt to scroll past the end
+ EXPECT_FALSE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)));
+ EXPECT_EQ(0, host_impl_->top_controls_manager()->controls_top_offset());
+ EXPECT_EQ(gfx::Vector2dF().ToString(),
+ scroll_layer->TotalScrollOffset().ToString());
+
+ host_impl_->ScrollEnd();
+}
+
+class LayerTreeHostImplVirtualViewportTest : public LayerTreeHostImplTest {
+ public:
+ void SetupVirtualViewportLayers(const gfx::Size& content_size,
+ const gfx::Size& outer_viewport,
+ const gfx::Size& inner_viewport) {
+ LayerTreeImpl* layer_tree_impl = host_impl_->active_tree();
+ const int kOuterViewportClipLayerId = 6;
+ const int kOuterViewportScrollLayerId = 7;
+ const int kInnerViewportScrollLayerId = 2;
+ const int kInnerViewportClipLayerId = 4;
+ const int kPageScaleLayerId = 5;
+
+ scoped_ptr<LayerImpl> inner_scroll =
+ LayerImpl::Create(layer_tree_impl, kInnerViewportScrollLayerId);
+ inner_scroll->SetIsContainerForFixedPositionLayers(true);
+ inner_scroll->SetScrollOffset(gfx::Vector2d());
+
+ scoped_ptr<LayerImpl> inner_clip =
+ LayerImpl::Create(layer_tree_impl, kInnerViewportClipLayerId);
+ inner_clip->SetBounds(inner_viewport);
+
+ scoped_ptr<LayerImpl> page_scale =
+ LayerImpl::Create(layer_tree_impl, kPageScaleLayerId);
+
+ inner_scroll->SetScrollClipLayer(inner_clip->id());
+ inner_scroll->SetBounds(outer_viewport);
+ inner_scroll->SetContentBounds(outer_viewport);
+ inner_scroll->SetPosition(gfx::PointF());
+
+ scoped_ptr<LayerImpl> outer_clip =
+ LayerImpl::Create(layer_tree_impl, kOuterViewportClipLayerId);
+ outer_clip->SetBounds(outer_viewport);
+ outer_clip->SetIsContainerForFixedPositionLayers(true);
+
+ scoped_ptr<LayerImpl> outer_scroll =
+ LayerImpl::Create(layer_tree_impl, kOuterViewportScrollLayerId);
+ outer_scroll->SetScrollClipLayer(outer_clip->id());
+ outer_scroll->SetScrollOffset(gfx::Vector2d());
+ outer_scroll->SetBounds(content_size);
+ outer_scroll->SetContentBounds(content_size);
+ outer_scroll->SetPosition(gfx::PointF());
+
+ scoped_ptr<LayerImpl> contents =
+ LayerImpl::Create(layer_tree_impl, 8);
+ contents->SetDrawsContent(true);
+ contents->SetBounds(content_size);
+ contents->SetContentBounds(content_size);
+ contents->SetPosition(gfx::PointF());
+
+ outer_scroll->AddChild(contents.Pass());
+ outer_clip->AddChild(outer_scroll.Pass());
+ inner_scroll->AddChild(outer_clip.Pass());
+ page_scale->AddChild(inner_scroll.Pass());
+ inner_clip->AddChild(page_scale.Pass());
+
+ layer_tree_impl->SetRootLayer(inner_clip.Pass());
+ layer_tree_impl->SetViewportLayersFromIds(kPageScaleLayerId,
+ kInnerViewportScrollLayerId, kOuterViewportScrollLayerId);
+
+ host_impl_->active_tree()->DidBecomeActive();
+ }
+};
+
+TEST_F(LayerTreeHostImplVirtualViewportTest, FlingScrollBubblesToInner) {
+ gfx::Size content_size = gfx::Size(100, 160);
+ gfx::Size outer_viewport = gfx::Size(50, 80);
+ gfx::Size inner_viewport = gfx::Size(25, 40);
+
+ SetupVirtualViewportLayers(content_size, outer_viewport, inner_viewport);
+
+ LayerImpl* outer_scroll = host_impl_->OuterViewportScrollLayer();
+ LayerImpl* inner_scroll = host_impl_->InnerViewportScrollLayer();
+ DrawFrame();
+ {
+ gfx::Vector2dF inner_expected;
+ gfx::Vector2dF outer_expected;
+ EXPECT_VECTOR_EQ(inner_expected, inner_scroll->TotalScrollOffset());
+ EXPECT_VECTOR_EQ(outer_expected, outer_scroll->TotalScrollOffset());
+
+ // Make sure the fling goes to the outer viewport first
+ EXPECT_EQ(InputHandler::ScrollStarted,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::ScrollStarted, host_impl_->FlingScrollBegin());
+
+ gfx::Vector2d scroll_delta(inner_viewport.width(), inner_viewport.height());
+ host_impl_->ScrollBy(gfx::Point(), scroll_delta);
+ outer_expected += gfx::Vector2dF(scroll_delta.x(), scroll_delta.y());
+
+ host_impl_->ScrollEnd();
+
+ EXPECT_VECTOR_EQ(inner_expected, inner_scroll->TotalScrollOffset());
+ EXPECT_VECTOR_EQ(outer_expected, outer_scroll->TotalScrollOffset());
+
+ // Fling past the outer viewport boundry, make sure inner viewport scrolls.
+ EXPECT_EQ(InputHandler::ScrollStarted,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::ScrollStarted, host_impl_->FlingScrollBegin());
+
+ host_impl_->ScrollBy(gfx::Point(), scroll_delta);
+ outer_expected += gfx::Vector2dF(scroll_delta.x(), scroll_delta.y());
+
+ host_impl_->ScrollBy(gfx::Point(), scroll_delta);
+ inner_expected += gfx::Vector2dF(scroll_delta.x(), scroll_delta.y());
+
+ host_impl_->ScrollEnd();
+
+ EXPECT_VECTOR_EQ(inner_expected, inner_scroll->TotalScrollOffset());
+ EXPECT_VECTOR_EQ(outer_expected, outer_scroll->TotalScrollOffset());
+ }
+}
+
+class LayerTreeHostImplWithImplicitLimitsTest : public LayerTreeHostImplTest {
+ public:
+ virtual void SetUp() OVERRIDE {
+ LayerTreeSettings settings = DefaultSettings();
+ settings.max_memory_for_prepaint_percentage = 50;
+ CreateHostImpl(settings, CreateOutputSurface());
+ }
+};
+
+TEST_F(LayerTreeHostImplWithImplicitLimitsTest, ImplicitMemoryLimits) {
+ // Set up a memory policy and percentages which could cause
+ // 32-bit integer overflows.
+ ManagedMemoryPolicy mem_policy(300 * 1024 * 1024); // 300MB
+
+ // Verify implicit limits are calculated correctly with no overflows
+ host_impl_->SetMemoryPolicy(mem_policy);
+ EXPECT_EQ(host_impl_->global_tile_state().hard_memory_limit_in_bytes,
+ 300u * 1024u * 1024u);
+ EXPECT_EQ(host_impl_->global_tile_state().soft_memory_limit_in_bytes,
+ 150u * 1024u * 1024u);
+}
+
+TEST_F(LayerTreeHostImplTest, ExternalTransformReflectedInNextDraw) {
+ const gfx::Size layer_size(100, 100);
+ gfx::Transform external_transform;
+ const gfx::Rect external_viewport(layer_size);
+ const gfx::Rect external_clip(layer_size);
+ const bool valid_for_tile_management = true;
+ LayerImpl* layer = SetupScrollAndContentsLayers(layer_size);
+
+ host_impl_->SetExternalDrawConstraints(external_transform,
+ external_viewport,
+ external_clip,
+ valid_for_tile_management);
+ DrawFrame();
+ EXPECT_TRANSFORMATION_MATRIX_EQ(
+ external_transform, layer->draw_properties().target_space_transform);
+
+ external_transform.Translate(20, 20);
+ host_impl_->SetExternalDrawConstraints(external_transform,
+ external_viewport,
+ external_clip,
+ valid_for_tile_management);
+ DrawFrame();
+ EXPECT_TRANSFORMATION_MATRIX_EQ(
+ external_transform, layer->draw_properties().target_space_transform);
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_host_perftest.cc b/chromium/cc/trees/layer_tree_host_perftest.cc
index 1bfe1c49d9e..70b2a645236 100644
--- a/chromium/cc/trees/layer_tree_host_perftest.cc
+++ b/chromium/cc/trees/layer_tree_host_perftest.cc
@@ -11,13 +11,13 @@
#include "base/path_service.h"
#include "base/strings/string_piece.h"
#include "base/time/time.h"
+#include "cc/debug/lap_timer.h"
#include "cc/layers/content_layer.h"
#include "cc/layers/nine_patch_layer.h"
#include "cc/layers/solid_color_layer.h"
#include "cc/layers/texture_layer.h"
#include "cc/resources/texture_mailbox.h"
#include "cc/test/fake_content_layer_client.h"
-#include "cc/test/lap_timer.h"
#include "cc/test/layer_tree_json_parser.h"
#include "cc/test/layer_tree_test.h"
#include "cc/test/paths.h"
@@ -54,8 +54,10 @@ class LayerTreeHostPerfTest : public LayerTreeTest {
}
virtual void Animate(base::TimeTicks monotonic_time) OVERRIDE {
- if (animation_driven_drawing_ && !TestEnded())
+ if (animation_driven_drawing_ && !TestEnded()) {
layer_tree_host()->SetNeedsAnimate();
+ layer_tree_host()->SetNextCommitForcesRedraw();
+ }
}
virtual void BeginCommitOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
@@ -246,14 +248,16 @@ TEST_F(ScrollingLayerTreePerfTest, LongScrollablePageThreadedImplSide) {
RunTestWithImplSidePainting();
}
-static void EmptyReleaseCallback(unsigned sync_point, bool lost_resource) {}
+static void EmptyReleaseCallback(uint32 sync_point, bool lost_resource) {}
// Simulates main-thread scrolling on each frame.
class BrowserCompositorInvalidateLayerTreePerfTest
: public LayerTreeHostPerfTestJsonReader {
public:
BrowserCompositorInvalidateLayerTreePerfTest()
- : next_sync_point_(1), clean_up_started_(false) {}
+ : LayerTreeHostPerfTestJsonReader(),
+ next_sync_point_(1),
+ clean_up_started_(false) {}
virtual void BuildTree() OVERRIDE {
LayerTreeHostPerfTestJsonReader::BuildTree();
@@ -267,6 +271,8 @@ class BrowserCompositorInvalidateLayerTreePerfTest
}
virtual void WillCommit() OVERRIDE {
+ if (CleanUpStarted())
+ return;
gpu::Mailbox gpu_mailbox;
std::ostringstream name_stream;
name_stream << "name" << next_sync_point_;
@@ -274,7 +280,7 @@ class BrowserCompositorInvalidateLayerTreePerfTest
reinterpret_cast<const int8*>(name_stream.str().c_str()));
scoped_ptr<SingleReleaseCallback> callback = SingleReleaseCallback::Create(
base::Bind(&EmptyReleaseCallback));
- TextureMailbox mailbox(gpu_mailbox, next_sync_point_);
+ TextureMailbox mailbox(gpu_mailbox, GL_TEXTURE_2D, next_sync_point_);
next_sync_point_++;
tab_contents_->SetTextureMailbox(mailbox, callback.Pass());
@@ -286,11 +292,6 @@ class BrowserCompositorInvalidateLayerTreePerfTest
layer_tree_host()->SetNeedsCommit();
}
- virtual void DidCommitAndDrawFrame() OVERRIDE {
- if (CleanUpStarted())
- EndTest();
- }
-
virtual void CleanUpAndEndTest(LayerTreeHostImpl* host_impl) OVERRIDE {
clean_up_started_ = true;
MainThreadTaskRunner()->PostTask(
@@ -303,6 +304,7 @@ class BrowserCompositorInvalidateLayerTreePerfTest
void CleanUpAndEndTestOnMainThread() {
tab_contents_->SetTextureMailbox(TextureMailbox(),
scoped_ptr<SingleReleaseCallback>());
+ EndTest();
}
virtual bool CleanUpStarted() OVERRIDE { return clean_up_started_; }
@@ -314,6 +316,7 @@ class BrowserCompositorInvalidateLayerTreePerfTest
};
TEST_F(BrowserCompositorInvalidateLayerTreePerfTest, DenseBrowserUI) {
+ measure_commit_cost_ = true;
SetTestName("dense_layer_tree");
ReadTestFile("dense_layer_tree");
RunTestWithImplSidePainting();
@@ -328,70 +331,5 @@ TEST_F(LayerTreeHostPerfTestJsonReader, HeavyPageThreadedImplSide) {
RunTestWithImplSidePainting();
}
-class PageScaleImplSidePaintingPerfTest
- : public LayerTreeHostPerfTestJsonReader {
- public:
- PageScaleImplSidePaintingPerfTest()
- : max_scale_(16.f), min_scale_(1.f / max_scale_) {}
-
- virtual void SetupTree() OVERRIDE {
- layer_tree_host()->SetPageScaleFactorAndLimits(1.f, min_scale_, max_scale_);
- }
-
- virtual void ApplyScrollAndScale(gfx::Vector2d scroll_delta,
- float scale_delta) OVERRIDE {
- float page_scale_factor = layer_tree_host()->page_scale_factor();
- page_scale_factor *= scale_delta;
- layer_tree_host()->SetPageScaleFactorAndLimits(
- page_scale_factor, min_scale_, max_scale_);
- }
-
- virtual void AnimateLayers(LayerTreeHostImpl* host_impl,
- base::TimeTicks monotonic_time) OVERRIDE {
- if (!host_impl->pinch_gesture_active()) {
- host_impl->PinchGestureBegin();
- start_time_ = monotonic_time;
- }
- gfx::Point anchor(200, 200);
-
- float seconds = (monotonic_time - start_time_).InSecondsF();
-
- // Every half second, zoom from min scale to max scale.
- float interval = 0.5f;
-
- // Start time in the middle of the interval when zoom = 1.
- seconds += interval / 2.f;
-
- // Stack two ranges together to go up from min to max and down from
- // max to min in the next so as not to have a zoom discrepancy.
- float time_in_two_intervals = fmod(seconds, 2.f * interval) / interval;
-
- // Map everything to go from min to max between 0 and 1.
- float time_in_one_interval =
- time_in_two_intervals > 1.f ? 2.f - time_in_two_intervals
- : time_in_two_intervals;
- // Normalize time to -1..1.
- float normalized = 2.f * time_in_one_interval - 1.f;
- float scale_factor = std::abs(normalized) * (max_scale_ - 1.f) + 1.f;
- float total_scale = normalized < 0.f ? 1.f / scale_factor : scale_factor;
-
- float desired_delta =
- total_scale / host_impl->active_tree()->total_page_scale_factor();
- host_impl->PinchGestureUpdate(desired_delta, anchor);
- }
-
- private:
- float max_scale_;
- float min_scale_;
- base::TimeTicks start_time_;
-};
-
-TEST_F(PageScaleImplSidePaintingPerfTest, HeavyPage) {
- measure_commit_cost_ = true;
- SetTestName("heavy_page_page_scale");
- ReadTestFile("heavy_layer_tree");
- RunTestWithImplSidePainting();
-}
-
} // namespace
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc b/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc
index d2a6507f940..c8c8c7adf3f 100644
--- a/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc
+++ b/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc
@@ -110,12 +110,19 @@ TEST_F(LayerTreeHostFiltersPixelTest, BackgroundFilterBlurOffAxis) {
background->AddChild(green);
background->AddChild(blur);
- background->SetPreserves3d(true);
+ background->SetShouldFlattenTransform(false);
+ background->Set3dSortingContextId(1);
+ green->SetShouldFlattenTransform(false);
+ green->Set3dSortingContextId(1);
gfx::Transform background_transform;
background_transform.ApplyPerspectiveDepth(200.0);
background->SetTransform(background_transform);
- blur->SetPreserves3d(true);
+ blur->SetShouldFlattenTransform(false);
+ blur->Set3dSortingContextId(1);
+ for (size_t i = 0; i < blur->children().size(); ++i)
+ blur->children()[i]->Set3dSortingContextId(1);
+
gfx::Transform blur_transform;
blur_transform.Translate(55.0, 65.0);
blur_transform.RotateAboutXAxis(85.0);
@@ -169,7 +176,7 @@ class ImageFilterClippedPixelTest : public LayerTreeHostFiltersPixelTest {
// This filter does a red-blue swap, so the foreground becomes blue.
matrix[2] = matrix[6] = matrix[10] = matrix[18] = SK_Scalar1;
skia::RefPtr<SkColorFilter> colorFilter(
- skia::AdoptRef(new SkColorMatrixFilter(matrix)));
+ skia::AdoptRef(SkColorMatrixFilter::Create(matrix)));
// We filter only the bottom 200x100 pixels of the foreground.
SkImageFilter::CropRect crop_rect(SkRect::MakeXYWH(0, 100, 200, 100));
skia::RefPtr<SkImageFilter> filter = skia::AdoptRef(
diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_masks.cc b/chromium/cc/trees/layer_tree_host_pixeltest_masks.cc
index 1d4f893d7d0..9b386866ee3 100644
--- a/chromium/cc/trees/layer_tree_host_pixeltest_masks.cc
+++ b/chromium/cc/trees/layer_tree_host_pixeltest_masks.cc
@@ -17,28 +17,34 @@ namespace {
class LayerTreeHostMasksPixelTest : public LayerTreePixelTest {};
-class MaskContentLayerClient : public cc::ContentLayerClient {
+class MaskContentLayerClient : public ContentLayerClient {
public:
MaskContentLayerClient() {}
virtual ~MaskContentLayerClient() {}
virtual void DidChangeLayerCanUseLCDText() OVERRIDE {}
- virtual void PaintContents(SkCanvas* canvas,
- gfx::Rect rect,
- gfx::RectF* opaque_rect) OVERRIDE {
+ virtual bool FillsBoundsCompletely() const OVERRIDE { return false; }
+
+ virtual void PaintContents(
+ SkCanvas* canvas,
+ const gfx::Rect& rect,
+ gfx::RectF* opaque_rect,
+ ContentLayerClient::GraphicsContextStatus gc_status) OVERRIDE {
SkPaint paint;
paint.setStyle(SkPaint::kStroke_Style);
paint.setStrokeWidth(SkIntToScalar(2));
paint.setColor(SK_ColorWHITE);
canvas->clear(SK_ColorTRANSPARENT);
- while (!rect.IsEmpty()) {
- rect.Inset(3, 3, 2, 2);
+ gfx::Rect inset_rect(rect);
+ while (!inset_rect.IsEmpty()) {
+ inset_rect.Inset(3, 3, 2, 2);
canvas->drawRect(
- SkRect::MakeXYWH(rect.x(), rect.y(), rect.width(), rect.height()),
+ SkRect::MakeXYWH(inset_rect.x(), inset_rect.y(),
+ inset_rect.width(), inset_rect.height()),
paint);
- rect.Inset(3, 3, 2, 2);
+ inset_rect.Inset(3, 3, 2, 2);
}
}
};
@@ -74,14 +80,14 @@ TEST_F(LayerTreeHostMasksPixelTest, ImageMaskOfLayer) {
mask->SetBounds(gfx::Size(100, 100));
SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, 400, 400);
- bitmap.allocPixels();
+ bitmap.allocN32Pixels(400, 400);
SkCanvas canvas(bitmap);
canvas.scale(SkIntToScalar(4), SkIntToScalar(4));
MaskContentLayerClient client;
client.PaintContents(&canvas,
gfx::Rect(100, 100),
- NULL);
+ NULL,
+ ContentLayerClient::GRAPHICS_CONTEXT_ENABLED);
mask->SetBitmap(bitmap);
scoped_refptr<SolidColorLayer> green = CreateSolidColorLayerWithBorder(
@@ -101,7 +107,6 @@ TEST_F(LayerTreeHostMasksPixelTest, MaskOfClippedLayer) {
// Clip to the top half of the green layer.
scoped_refptr<Layer> clip = Layer::Create();
- clip->SetAnchorPoint(gfx::PointF(0.f, 0.f));
clip->SetPosition(gfx::Point(0, 0));
clip->SetBounds(gfx::Size(200, 100));
clip->SetMasksToBounds(true);
@@ -143,7 +148,7 @@ TEST_F(LayerTreeHostMasksPixelTest, MaskWithReplica) {
replica_transform.Rotate(-90.0);
scoped_refptr<Layer> replica = Layer::Create();
- replica->SetAnchorPoint(gfx::PointF(0.5f, 0.5f));
+ replica->SetTransformOrigin(gfx::Point3F(50.f, 50.f, 0.f));
replica->SetPosition(gfx::Point(100, 100));
replica->SetTransform(replica_transform);
green->SetReplicaLayer(replica.get());
@@ -167,7 +172,6 @@ TEST_F(LayerTreeHostMasksPixelTest, MaskWithReplicaOfClippedLayer) {
// Clip to the bottom half of the green layer, and the left half of the
// replica.
scoped_refptr<Layer> clip = Layer::Create();
- clip->SetAnchorPoint(gfx::PointF(0.f, 0.f));
clip->SetPosition(gfx::Point(0, 50));
clip->SetBounds(gfx::Size(150, 150));
clip->SetMasksToBounds(true);
@@ -182,7 +186,7 @@ TEST_F(LayerTreeHostMasksPixelTest, MaskWithReplicaOfClippedLayer) {
replica_transform.Rotate(-90.0);
scoped_refptr<Layer> replica = Layer::Create();
- replica->SetAnchorPoint(gfx::PointF(0.5f, 0.5f));
+ replica->SetTransformOrigin(gfx::Point3F(50.f, 50.f, 0.f));
replica->SetPosition(gfx::Point(100, 100));
replica->SetTransform(replica_transform);
green->SetReplicaLayer(replica.get());
@@ -217,7 +221,7 @@ TEST_F(LayerTreeHostMasksPixelTest, MaskOfReplica) {
replica_transform.Translate(100.0, 0.0);
scoped_refptr<Layer> replica = Layer::Create();
- replica->SetAnchorPoint(gfx::PointF(1.f, 1.f));
+ replica->SetTransformOrigin(gfx::Point3F(100.f, 100.f, 0.f));
replica->SetPosition(gfx::Point());
replica->SetTransform(replica_transform);
replica->SetMaskLayer(mask.get());
@@ -241,7 +245,6 @@ TEST_F(LayerTreeHostMasksPixelTest, MaskOfReplicaOfClippedLayer) {
// Clip to the bottom 3/4 of the green layer, and the top 3/4 of the replica.
scoped_refptr<Layer> clip = Layer::Create();
- clip->SetAnchorPoint(gfx::PointF(0.f, 0.f));
clip->SetPosition(gfx::Point(0, 25));
clip->SetBounds(gfx::Size(200, 150));
clip->SetMasksToBounds(true);
@@ -260,7 +263,7 @@ TEST_F(LayerTreeHostMasksPixelTest, MaskOfReplicaOfClippedLayer) {
replica_transform.Translate(100.0, 0.0);
scoped_refptr<Layer> replica = Layer::Create();
- replica->SetAnchorPoint(gfx::PointF(1.f, 1.f));
+ replica->SetTransformOrigin(gfx::Point3F(100.f, 100.f, 0.f));
replica->SetPosition(gfx::Point());
replica->SetTransform(replica_transform);
replica->SetMaskLayer(mask.get());
diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_on_demand_raster.cc b/chromium/cc/trees/layer_tree_host_pixeltest_on_demand_raster.cc
index eaa97492c65..b7eb516004a 100644
--- a/chromium/cc/trees/layer_tree_host_pixeltest_on_demand_raster.cc
+++ b/chromium/cc/trees/layer_tree_host_pixeltest_on_demand_raster.cc
@@ -41,19 +41,21 @@ class LayerTreeHostOnDemandRasterPixelTest : public LayerTreePixelTest {
PictureLayerImpl* picture_layer = static_cast<PictureLayerImpl*>(
host_impl->active_tree()->root_layer()->child_at(0));
- QuadList quads;
- SharedQuadStateList shared_states;
- MockQuadCuller quad_culler(&quads, &shared_states);
+ MockOcclusionTracker<LayerImpl> occlusion_tracker;
+ scoped_ptr<RenderPass> render_pass = RenderPass::Create();
+ MockQuadCuller quad_culler(render_pass.get(), &occlusion_tracker);
AppendQuadsData data;
picture_layer->AppendQuads(&quad_culler, &data);
- for (size_t i = 0; i < quads.size(); ++i)
- EXPECT_EQ(quads[i]->material, DrawQuad::PICTURE_CONTENT);
+ for (size_t i = 0; i < render_pass->quad_list.size(); ++i)
+ EXPECT_EQ(render_pass->quad_list[i]->material, DrawQuad::PICTURE_CONTENT);
// Triggers pixel readback and ends the test.
LayerTreePixelTest::SwapBuffersOnThread(host_impl, result);
}
+
+ void RunOnDemandRasterPixelTest();
};
class BlueYellowLayerClient : public ContentLayerClient {
@@ -63,9 +65,13 @@ class BlueYellowLayerClient : public ContentLayerClient {
virtual void DidChangeLayerCanUseLCDText() OVERRIDE { }
- virtual void PaintContents(SkCanvas* canvas,
- gfx::Rect clip,
- gfx::RectF* opaque) OVERRIDE {
+ virtual bool FillsBoundsCompletely() const OVERRIDE { return false; }
+
+ virtual void PaintContents(
+ SkCanvas* canvas,
+ const gfx::Rect& clip,
+ gfx::RectF* opaque,
+ ContentLayerClient::GraphicsContextStatus gc_status) OVERRIDE {
*opaque = gfx::RectF(layer_rect_.width(), layer_rect_.height());
SkPaint paint;
@@ -87,7 +93,7 @@ class BlueYellowLayerClient : public ContentLayerClient {
gfx::Rect layer_rect_;
};
-TEST_F(LayerTreeHostOnDemandRasterPixelTest, RasterPictureLayer) {
+void LayerTreeHostOnDemandRasterPixelTest::RunOnDemandRasterPixelTest() {
// Use multiple colors in a single layer to prevent bypassing on-demand
// rasterization if a single solid color is detected in picture analysis.
gfx::Rect layer_rect(200, 200);
@@ -95,7 +101,6 @@ TEST_F(LayerTreeHostOnDemandRasterPixelTest, RasterPictureLayer) {
scoped_refptr<PictureLayer> layer = PictureLayer::Create(&client);
layer->SetIsDrawable(true);
- layer->SetAnchorPoint(gfx::PointF());
layer->SetBounds(layer_rect.size());
layer->SetPosition(layer_rect.origin());
@@ -104,6 +109,23 @@ TEST_F(LayerTreeHostOnDemandRasterPixelTest, RasterPictureLayer) {
base::FilePath(FILE_PATH_LITERAL("blue_yellow.png")));
}
+TEST_F(LayerTreeHostOnDemandRasterPixelTest, RasterPictureLayer) {
+ RunOnDemandRasterPixelTest();
+}
+
+class LayerTreeHostOnDemandRasterPixelTestWithGpuRasterizationForced
+ : public LayerTreeHostOnDemandRasterPixelTest {
+ virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
+ LayerTreeHostOnDemandRasterPixelTest::InitializeSettings(settings);
+ settings->gpu_rasterization_forced = true;
+ }
+};
+
+TEST_F(LayerTreeHostOnDemandRasterPixelTestWithGpuRasterizationForced,
+ RasterPictureLayer) {
+ RunOnDemandRasterPixelTest();
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_readback.cc b/chromium/cc/trees/layer_tree_host_pixeltest_readback.cc
index e5bfcd24599..4c808397eba 100644
--- a/chromium/cc/trees/layer_tree_host_pixeltest_readback.cc
+++ b/chromium/cc/trees/layer_tree_host_pixeltest_readback.cc
@@ -20,6 +20,9 @@ namespace {
class LayerTreeHostReadbackPixelTest : public LayerTreePixelTest {
protected:
+ LayerTreeHostReadbackPixelTest()
+ : insert_copy_request_after_frame_count_(0) {}
+
virtual scoped_ptr<CopyOutputRequest> CreateCopyOutputRequest() OVERRIDE {
scoped_ptr<CopyOutputRequest> request;
@@ -47,6 +50,24 @@ class LayerTreeHostReadbackPixelTest : public LayerTreePixelTest {
return request.Pass();
}
+ virtual void BeginTest() OVERRIDE {
+ if (insert_copy_request_after_frame_count_ == 0) {
+ Layer* const target =
+ readback_target_ ? readback_target_ : layer_tree_host()->root_layer();
+ target->RequestCopyOfOutput(CreateCopyOutputRequest().Pass());
+ }
+ PostSetNeedsCommitToMainThread();
+ }
+
+ virtual void DidCommitAndDrawFrame() OVERRIDE {
+ if (insert_copy_request_after_frame_count_ ==
+ layer_tree_host()->source_frame_number()) {
+ Layer* const target =
+ readback_target_ ? readback_target_ : layer_tree_host()->root_layer();
+ target->RequestCopyOfOutput(CreateCopyOutputRequest().Pass());
+ }
+ }
+
void ReadbackResultAsBitmap(scoped_ptr<CopyOutputResult> result) {
EXPECT_TRUE(proxy()->IsMainThread());
EXPECT_TRUE(result->HasBitmap());
@@ -72,8 +93,11 @@ class LayerTreeHostReadbackPixelTest : public LayerTreePixelTest {
}
gfx::Rect copy_subrect_;
+ int insert_copy_request_after_frame_count_;
};
+void IgnoreReadbackResult(scoped_ptr<CopyOutputResult> result) {}
+
TEST_F(LayerTreeHostReadbackPixelTest, ReadbackRootLayer_Software) {
scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(
gfx::Rect(200, 200), SK_ColorWHITE);
@@ -485,6 +509,129 @@ TEST_F(LayerTreeHostReadbackPixelTest,
"green_small_with_blue_corner.png")));
}
+TEST_F(LayerTreeHostReadbackPixelTest, ReadbackHiddenSubtree_Software) {
+ scoped_refptr<SolidColorLayer> background =
+ CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorBLACK);
+
+ scoped_refptr<SolidColorLayer> hidden_target =
+ CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
+ hidden_target->SetHideLayerAndSubtree(true);
+ background->AddChild(hidden_target);
+
+ scoped_refptr<SolidColorLayer> blue =
+ CreateSolidColorLayer(gfx::Rect(150, 150, 50, 50), SK_ColorBLUE);
+ hidden_target->AddChild(blue);
+
+ RunPixelTestWithReadbackTarget(
+ SOFTWARE_WITH_DEFAULT,
+ background,
+ hidden_target.get(),
+ base::FilePath(FILE_PATH_LITERAL("green_with_blue_corner.png")));
+}
+
+TEST_F(LayerTreeHostReadbackPixelTest, ReadbackHiddenSubtree_GL_Bitmap) {
+ scoped_refptr<SolidColorLayer> background =
+ CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorBLACK);
+
+ scoped_refptr<SolidColorLayer> hidden_target =
+ CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
+ hidden_target->SetHideLayerAndSubtree(true);
+ background->AddChild(hidden_target);
+
+ scoped_refptr<SolidColorLayer> blue =
+ CreateSolidColorLayer(gfx::Rect(150, 150, 50, 50), SK_ColorBLUE);
+ hidden_target->AddChild(blue);
+
+ RunPixelTestWithReadbackTarget(
+ GL_WITH_BITMAP,
+ background,
+ hidden_target.get(),
+ base::FilePath(FILE_PATH_LITERAL("green_with_blue_corner.png")));
+}
+
+TEST_F(LayerTreeHostReadbackPixelTest, ReadbackHiddenSubtree_GL) {
+ scoped_refptr<SolidColorLayer> background =
+ CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorBLACK);
+
+ scoped_refptr<SolidColorLayer> hidden_target =
+ CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
+ hidden_target->SetHideLayerAndSubtree(true);
+ background->AddChild(hidden_target);
+
+ scoped_refptr<SolidColorLayer> blue =
+ CreateSolidColorLayer(gfx::Rect(150, 150, 50, 50), SK_ColorBLUE);
+ hidden_target->AddChild(blue);
+
+ RunPixelTestWithReadbackTarget(
+ GL_WITH_DEFAULT,
+ background,
+ hidden_target.get(),
+ base::FilePath(FILE_PATH_LITERAL("green_with_blue_corner.png")));
+}
+
+TEST_F(LayerTreeHostReadbackPixelTest,
+ HiddenSubtreeNotVisibleWhenDrawnForReadback_Software) {
+ scoped_refptr<SolidColorLayer> background =
+ CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorBLACK);
+
+ scoped_refptr<SolidColorLayer> hidden_target =
+ CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
+ hidden_target->SetHideLayerAndSubtree(true);
+ background->AddChild(hidden_target);
+
+ scoped_refptr<SolidColorLayer> blue =
+ CreateSolidColorLayer(gfx::Rect(150, 150, 50, 50), SK_ColorBLUE);
+ hidden_target->AddChild(blue);
+
+ hidden_target->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
+ base::Bind(&IgnoreReadbackResult)));
+ RunPixelTest(SOFTWARE_WITH_DEFAULT,
+ background,
+ base::FilePath(FILE_PATH_LITERAL("black.png")));
+}
+
+TEST_F(LayerTreeHostReadbackPixelTest,
+ HiddenSubtreeNotVisibleWhenDrawnForReadback_GL_Bitmap) {
+ scoped_refptr<SolidColorLayer> background =
+ CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorBLACK);
+
+ scoped_refptr<SolidColorLayer> hidden_target =
+ CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
+ hidden_target->SetHideLayerAndSubtree(true);
+ background->AddChild(hidden_target);
+
+ scoped_refptr<SolidColorLayer> blue =
+ CreateSolidColorLayer(gfx::Rect(150, 150, 50, 50), SK_ColorBLUE);
+ hidden_target->AddChild(blue);
+
+ hidden_target->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
+ base::Bind(&IgnoreReadbackResult)));
+ RunPixelTest(GL_WITH_BITMAP,
+ background,
+ base::FilePath(FILE_PATH_LITERAL("black.png")));
+}
+
+TEST_F(LayerTreeHostReadbackPixelTest,
+ HiddenSubtreeNotVisibleWhenDrawnForReadback_GL) {
+ scoped_refptr<SolidColorLayer> background =
+ CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorBLACK);
+
+ scoped_refptr<SolidColorLayer> hidden_target =
+ CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorGREEN);
+ hidden_target->SetHideLayerAndSubtree(true);
+ background->AddChild(hidden_target);
+
+ scoped_refptr<SolidColorLayer> blue =
+ CreateSolidColorLayer(gfx::Rect(150, 150, 50, 50), SK_ColorBLUE);
+ hidden_target->AddChild(blue);
+
+ hidden_target->RequestCopyOfOutput(CopyOutputRequest::CreateBitmapRequest(
+ base::Bind(&IgnoreReadbackResult)));
+ RunPixelTest(GL_WITH_DEFAULT,
+ background,
+ base::FilePath(FILE_PATH_LITERAL("black.png")));
+}
+
TEST_F(LayerTreeHostReadbackPixelTest, ReadbackSubrect_Software) {
scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(
gfx::Rect(200, 200), SK_ColorWHITE);
@@ -614,6 +761,155 @@ TEST_F(LayerTreeHostReadbackPixelTest, ReadbackNonRootLayerSubrect_GL) {
"green_small_with_blue_corner.png")));
}
+TEST_F(LayerTreeHostReadbackPixelTest, ReadbackWhenNoDamage_Software) {
+ scoped_refptr<SolidColorLayer> background =
+ CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorWHITE);
+
+ scoped_refptr<SolidColorLayer> parent =
+ CreateSolidColorLayer(gfx::Rect(0, 0, 150, 150), SK_ColorRED);
+ background->AddChild(parent);
+
+ scoped_refptr<SolidColorLayer> target =
+ CreateSolidColorLayer(gfx::Rect(0, 0, 100, 100), SK_ColorGREEN);
+ parent->AddChild(target);
+
+ scoped_refptr<SolidColorLayer> blue =
+ CreateSolidColorLayer(gfx::Rect(50, 50, 50, 50), SK_ColorBLUE);
+ target->AddChild(blue);
+
+ insert_copy_request_after_frame_count_ = 1;
+ RunPixelTestWithReadbackTarget(
+ SOFTWARE_WITH_DEFAULT,
+ background,
+ target.get(),
+ base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
+}
+
+TEST_F(LayerTreeHostReadbackPixelTest, ReadbackWhenNoDamage_GL_Bitmap) {
+ scoped_refptr<SolidColorLayer> background =
+ CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorWHITE);
+
+ scoped_refptr<SolidColorLayer> parent =
+ CreateSolidColorLayer(gfx::Rect(0, 0, 150, 150), SK_ColorRED);
+ background->AddChild(parent);
+
+ scoped_refptr<SolidColorLayer> target =
+ CreateSolidColorLayer(gfx::Rect(0, 0, 100, 100), SK_ColorGREEN);
+ parent->AddChild(target);
+
+ scoped_refptr<SolidColorLayer> blue =
+ CreateSolidColorLayer(gfx::Rect(50, 50, 50, 50), SK_ColorBLUE);
+ target->AddChild(blue);
+
+ insert_copy_request_after_frame_count_ = 1;
+ RunPixelTestWithReadbackTarget(
+ GL_WITH_BITMAP,
+ background,
+ target.get(),
+ base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
+}
+
+TEST_F(LayerTreeHostReadbackPixelTest, ReadbackWhenNoDamage_GL) {
+ scoped_refptr<SolidColorLayer> background =
+ CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorWHITE);
+
+ scoped_refptr<SolidColorLayer> parent =
+ CreateSolidColorLayer(gfx::Rect(0, 0, 150, 150), SK_ColorRED);
+ background->AddChild(parent);
+
+ scoped_refptr<SolidColorLayer> target =
+ CreateSolidColorLayer(gfx::Rect(0, 0, 100, 100), SK_ColorGREEN);
+ parent->AddChild(target);
+
+ scoped_refptr<SolidColorLayer> blue =
+ CreateSolidColorLayer(gfx::Rect(50, 50, 50, 50), SK_ColorBLUE);
+ target->AddChild(blue);
+
+ insert_copy_request_after_frame_count_ = 1;
+ RunPixelTestWithReadbackTarget(
+ GL_WITH_DEFAULT,
+ background,
+ target.get(),
+ base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
+}
+
+TEST_F(LayerTreeHostReadbackPixelTest,
+ ReadbackOutsideViewportWhenNoDamage_Software) {
+ scoped_refptr<SolidColorLayer> background =
+ CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorWHITE);
+
+ scoped_refptr<SolidColorLayer> parent =
+ CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorRED);
+ EXPECT_FALSE(parent->masks_to_bounds());
+ background->AddChild(parent);
+
+ scoped_refptr<SolidColorLayer> target =
+ CreateSolidColorLayer(gfx::Rect(250, 250, 100, 100), SK_ColorGREEN);
+ parent->AddChild(target);
+
+ scoped_refptr<SolidColorLayer> blue =
+ CreateSolidColorLayer(gfx::Rect(50, 50, 50, 50), SK_ColorBLUE);
+ target->AddChild(blue);
+
+ insert_copy_request_after_frame_count_ = 1;
+ RunPixelTestWithReadbackTarget(
+ SOFTWARE_WITH_DEFAULT,
+ background,
+ target.get(),
+ base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
+}
+
+TEST_F(LayerTreeHostReadbackPixelTest,
+ ReadbackOutsideViewportWhenNoDamage_GL_Bitmap) {
+ scoped_refptr<SolidColorLayer> background =
+ CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorWHITE);
+
+ scoped_refptr<SolidColorLayer> parent =
+ CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorRED);
+ EXPECT_FALSE(parent->masks_to_bounds());
+ background->AddChild(parent);
+
+ scoped_refptr<SolidColorLayer> target =
+ CreateSolidColorLayer(gfx::Rect(250, 250, 100, 100), SK_ColorGREEN);
+ parent->AddChild(target);
+
+ scoped_refptr<SolidColorLayer> blue =
+ CreateSolidColorLayer(gfx::Rect(50, 50, 50, 50), SK_ColorBLUE);
+ target->AddChild(blue);
+
+ insert_copy_request_after_frame_count_ = 1;
+ RunPixelTestWithReadbackTarget(
+ GL_WITH_BITMAP,
+ background,
+ target.get(),
+ base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
+}
+
+TEST_F(LayerTreeHostReadbackPixelTest, ReadbackOutsideViewportWhenNoDamage_GL) {
+ scoped_refptr<SolidColorLayer> background =
+ CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorWHITE);
+
+ scoped_refptr<SolidColorLayer> parent =
+ CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorRED);
+ EXPECT_FALSE(parent->masks_to_bounds());
+ background->AddChild(parent);
+
+ scoped_refptr<SolidColorLayer> target =
+ CreateSolidColorLayer(gfx::Rect(250, 250, 100, 100), SK_ColorGREEN);
+ parent->AddChild(target);
+
+ scoped_refptr<SolidColorLayer> blue =
+ CreateSolidColorLayer(gfx::Rect(50, 50, 50, 50), SK_ColorBLUE);
+ target->AddChild(blue);
+
+ insert_copy_request_after_frame_count_ = 1;
+ RunPixelTestWithReadbackTarget(
+ GL_WITH_DEFAULT,
+ background,
+ target.get(),
+ base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")));
+}
+
class LayerTreeHostReadbackDeviceScalePixelTest
: public LayerTreeHostReadbackPixelTest {
protected:
@@ -658,18 +954,15 @@ class LayerTreeHostReadbackDeviceScalePixelTest
TEST_F(LayerTreeHostReadbackDeviceScalePixelTest,
ReadbackSubrect_Software) {
scoped_refptr<ContentLayer> background = ContentLayer::Create(&white_client_);
- background->SetAnchorPoint(gfx::PointF());
background->SetBounds(gfx::Size(100, 100));
background->SetIsDrawable(true);
scoped_refptr<ContentLayer> green = ContentLayer::Create(&green_client_);
- green->SetAnchorPoint(gfx::PointF());
green->SetBounds(gfx::Size(100, 100));
green->SetIsDrawable(true);
background->AddChild(green);
scoped_refptr<ContentLayer> blue = ContentLayer::Create(&blue_client_);
- blue->SetAnchorPoint(gfx::PointF());
blue->SetPosition(gfx::Point(50, 50));
blue->SetBounds(gfx::Size(25, 25));
blue->SetIsDrawable(true);
@@ -689,18 +982,15 @@ TEST_F(LayerTreeHostReadbackDeviceScalePixelTest,
TEST_F(LayerTreeHostReadbackDeviceScalePixelTest,
ReadbackSubrect_GL) {
scoped_refptr<ContentLayer> background = ContentLayer::Create(&white_client_);
- background->SetAnchorPoint(gfx::PointF());
background->SetBounds(gfx::Size(100, 100));
background->SetIsDrawable(true);
scoped_refptr<ContentLayer> green = ContentLayer::Create(&green_client_);
- green->SetAnchorPoint(gfx::PointF());
green->SetBounds(gfx::Size(100, 100));
green->SetIsDrawable(true);
background->AddChild(green);
scoped_refptr<ContentLayer> blue = ContentLayer::Create(&blue_client_);
- blue->SetAnchorPoint(gfx::PointF());
blue->SetPosition(gfx::Point(50, 50));
blue->SetBounds(gfx::Size(25, 25));
blue->SetIsDrawable(true);
@@ -720,19 +1010,16 @@ TEST_F(LayerTreeHostReadbackDeviceScalePixelTest,
TEST_F(LayerTreeHostReadbackDeviceScalePixelTest,
ReadbackNonRootLayerSubrect_Software) {
scoped_refptr<ContentLayer> background = ContentLayer::Create(&white_client_);
- background->SetAnchorPoint(gfx::PointF());
background->SetBounds(gfx::Size(100, 100));
background->SetIsDrawable(true);
scoped_refptr<ContentLayer> green = ContentLayer::Create(&green_client_);
- green->SetAnchorPoint(gfx::PointF());
green->SetPosition(gfx::Point(10, 20));
green->SetBounds(gfx::Size(90, 80));
green->SetIsDrawable(true);
background->AddChild(green);
scoped_refptr<ContentLayer> blue = ContentLayer::Create(&blue_client_);
- blue->SetAnchorPoint(gfx::PointF());
blue->SetPosition(gfx::Point(50, 50));
blue->SetBounds(gfx::Size(25, 25));
blue->SetIsDrawable(true);
@@ -753,19 +1040,16 @@ TEST_F(LayerTreeHostReadbackDeviceScalePixelTest,
TEST_F(LayerTreeHostReadbackDeviceScalePixelTest,
ReadbackNonRootLayerSubrect_GL) {
scoped_refptr<ContentLayer> background = ContentLayer::Create(&white_client_);
- background->SetAnchorPoint(gfx::PointF());
background->SetBounds(gfx::Size(100, 100));
background->SetIsDrawable(true);
scoped_refptr<ContentLayer> green = ContentLayer::Create(&green_client_);
- green->SetAnchorPoint(gfx::PointF());
green->SetPosition(gfx::Point(10, 20));
green->SetBounds(gfx::Size(90, 80));
green->SetIsDrawable(true);
background->AddChild(green);
scoped_refptr<ContentLayer> blue = ContentLayer::Create(&blue_client_);
- blue->SetAnchorPoint(gfx::PointF());
blue->SetPosition(gfx::Point(50, 50));
blue->SetBounds(gfx::Size(25, 25));
blue->SetIsDrawable(true);
@@ -783,201 +1067,6 @@ TEST_F(LayerTreeHostReadbackDeviceScalePixelTest,
"green_small_with_blue_corner.png")));
}
-class LayerTreeHostReadbackViaCompositeAndReadbackPixelTest
- : public LayerTreePixelTest {
- protected:
- LayerTreeHostReadbackViaCompositeAndReadbackPixelTest()
- : device_scale_factor_(1.f),
- white_client_(SK_ColorWHITE),
- green_client_(SK_ColorGREEN),
- blue_client_(SK_ColorBLUE) {}
-
- virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
- // Cause the device scale factor to be inherited by contents scales.
- settings->layer_transforms_should_scale_layer_contents = true;
- }
-
- virtual void SetupTree() OVERRIDE {
- layer_tree_host()->SetDeviceScaleFactor(device_scale_factor_);
- LayerTreePixelTest::SetupTree();
- }
-
- virtual void BeginTest() OVERRIDE {
- EXPECT_EQ(device_scale_factor_, layer_tree_host()->device_scale_factor());
- if (TestEnded())
- return;
-
- gfx::Rect device_viewport_copy_rect(
- layer_tree_host()->device_viewport_size());
- if (!device_viewport_copy_subrect_.IsEmpty())
- device_viewport_copy_rect.Intersect(device_viewport_copy_subrect_);
-
- scoped_ptr<SkBitmap> bitmap(new SkBitmap);
- bitmap->setConfig(SkBitmap::kARGB_8888_Config,
- device_viewport_copy_rect.width(),
- device_viewport_copy_rect.height());
- bitmap->allocPixels();
- {
- scoped_ptr<SkAutoLockPixels> lock(new SkAutoLockPixels(*bitmap));
- layer_tree_host()->CompositeAndReadback(bitmap->getPixels(),
- device_viewport_copy_rect);
- }
-
- result_bitmap_ = bitmap.Pass();
- EndTest();
- }
-
- virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
- LayerImpl* root_impl = host_impl->active_tree()->root_layer();
-
- LayerImpl* background_impl = root_impl->children()[0];
- EXPECT_EQ(device_scale_factor_, background_impl->contents_scale_x());
- EXPECT_EQ(device_scale_factor_, background_impl->contents_scale_y());
-
- LayerImpl* green_impl = background_impl->children()[0];
- EXPECT_EQ(device_scale_factor_, green_impl->contents_scale_x());
- EXPECT_EQ(device_scale_factor_, green_impl->contents_scale_y());
-
- LayerImpl* blue_impl = green_impl->children()[0];
- EXPECT_EQ(device_scale_factor_, blue_impl->contents_scale_x());
- EXPECT_EQ(device_scale_factor_, blue_impl->contents_scale_y());
- }
-
- gfx::Rect device_viewport_copy_subrect_;
- float device_scale_factor_;
- SolidColorContentLayerClient white_client_;
- SolidColorContentLayerClient green_client_;
- SolidColorContentLayerClient blue_client_;
-};
-
-TEST_F(LayerTreeHostReadbackViaCompositeAndReadbackPixelTest,
- CompositeAndReadback_Software_1) {
- scoped_refptr<ContentLayer> background = ContentLayer::Create(&white_client_);
- background->SetAnchorPoint(gfx::PointF());
- background->SetBounds(gfx::Size(200, 200));
- background->SetIsDrawable(true);
-
- scoped_refptr<ContentLayer> green = ContentLayer::Create(&green_client_);
- green->SetAnchorPoint(gfx::PointF());
- green->SetBounds(gfx::Size(200, 200));
- green->SetIsDrawable(true);
- background->AddChild(green);
-
- scoped_refptr<ContentLayer> blue = ContentLayer::Create(&blue_client_);
- blue->SetAnchorPoint(gfx::PointF());
- blue->SetPosition(gfx::Point(100, 100));
- blue->SetBounds(gfx::Size(50, 50));
- blue->SetIsDrawable(true);
- green->AddChild(blue);
-
- // Grab the middle of the device viewport.
- device_viewport_copy_subrect_ = gfx::Rect(50, 50, 100, 100);
- device_scale_factor_ = 1.f;
-
- this->impl_side_painting_ = false;
- RunPixelTestWithReadbackTarget(SOFTWARE_WITH_DEFAULT,
- background,
- green.get(),
- base::FilePath(FILE_PATH_LITERAL(
- "green_small_with_blue_corner.png")));
-}
-
-TEST_F(LayerTreeHostReadbackViaCompositeAndReadbackPixelTest,
- CompositeAndReadback_Software_2) {
- scoped_refptr<ContentLayer> background = ContentLayer::Create(&white_client_);
- background->SetAnchorPoint(gfx::PointF());
- background->SetBounds(gfx::Size(100, 100));
- background->SetIsDrawable(true);
-
- scoped_refptr<ContentLayer> green = ContentLayer::Create(&green_client_);
- green->SetAnchorPoint(gfx::PointF());
- green->SetBounds(gfx::Size(100, 100));
- green->SetIsDrawable(true);
- background->AddChild(green);
-
- scoped_refptr<ContentLayer> blue = ContentLayer::Create(&blue_client_);
- blue->SetAnchorPoint(gfx::PointF());
- blue->SetPosition(gfx::Point(50, 50));
- blue->SetBounds(gfx::Size(25, 25));
- blue->SetIsDrawable(true);
- green->AddChild(blue);
-
- // Grab the middle of the device viewport.
- device_viewport_copy_subrect_ = gfx::Rect(50, 50, 100, 100);
- device_scale_factor_ = 2.f;
-
- this->impl_side_painting_ = false;
- RunPixelTestWithReadbackTarget(SOFTWARE_WITH_DEFAULT,
- background,
- green.get(),
- base::FilePath(FILE_PATH_LITERAL(
- "green_small_with_blue_corner.png")));
-}
-
-TEST_F(LayerTreeHostReadbackViaCompositeAndReadbackPixelTest,
- CompositeAndReadback_GL_1) {
- scoped_refptr<ContentLayer> background = ContentLayer::Create(&white_client_);
- background->SetAnchorPoint(gfx::PointF());
- background->SetBounds(gfx::Size(200, 200));
- background->SetIsDrawable(true);
-
- scoped_refptr<ContentLayer> green = ContentLayer::Create(&green_client_);
- green->SetAnchorPoint(gfx::PointF());
- green->SetBounds(gfx::Size(200, 200));
- green->SetIsDrawable(true);
- background->AddChild(green);
-
- scoped_refptr<ContentLayer> blue = ContentLayer::Create(&blue_client_);
- blue->SetAnchorPoint(gfx::PointF());
- blue->SetPosition(gfx::Point(100, 100));
- blue->SetBounds(gfx::Size(50, 50));
- blue->SetIsDrawable(true);
- green->AddChild(blue);
-
- // Grab the middle of the device viewport.
- device_viewport_copy_subrect_ = gfx::Rect(50, 50, 100, 100);
- device_scale_factor_ = 1.f;
-
- this->impl_side_painting_ = false;
- RunPixelTestWithReadbackTarget(GL_WITH_DEFAULT,
- background,
- green.get(),
- base::FilePath(FILE_PATH_LITERAL(
- "green_small_with_blue_corner.png")));
-}
-
-TEST_F(LayerTreeHostReadbackViaCompositeAndReadbackPixelTest,
- CompositeAndReadback_GL_2) {
- scoped_refptr<ContentLayer> background = ContentLayer::Create(&white_client_);
- background->SetAnchorPoint(gfx::PointF());
- background->SetBounds(gfx::Size(100, 100));
- background->SetIsDrawable(true);
-
- scoped_refptr<ContentLayer> green = ContentLayer::Create(&green_client_);
- green->SetAnchorPoint(gfx::PointF());
- green->SetBounds(gfx::Size(100, 100));
- green->SetIsDrawable(true);
- background->AddChild(green);
-
- scoped_refptr<ContentLayer> blue = ContentLayer::Create(&blue_client_);
- blue->SetAnchorPoint(gfx::PointF());
- blue->SetPosition(gfx::Point(50, 50));
- blue->SetBounds(gfx::Size(25, 25));
- blue->SetIsDrawable(true);
- green->AddChild(blue);
-
- // Grab the middle of the device viewport.
- device_viewport_copy_subrect_ = gfx::Rect(50, 50, 100, 100);
- device_scale_factor_ = 2.f;
-
- this->impl_side_painting_ = false;
- RunPixelTestWithReadbackTarget(GL_WITH_DEFAULT,
- background,
- green.get(),
- base::FilePath(FILE_PATH_LITERAL(
- "green_small_with_blue_corner.png")));
-}
-
TEST_F(LayerTreeHostReadbackPixelTest, ReadbackNonRootLayerOutsideViewport) {
scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(
gfx::Rect(200, 200), SK_ColorWHITE);
diff --git a/chromium/cc/trees/layer_tree_host_unittest.cc b/chromium/cc/trees/layer_tree_host_unittest.cc
index 0ac203a9a9e..6b781cb60ef 100644
--- a/chromium/cc/trees/layer_tree_host_unittest.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest.cc
@@ -20,13 +20,15 @@
#include "cc/layers/solid_color_layer.h"
#include "cc/layers/video_layer.h"
#include "cc/output/begin_frame_args.h"
+#include "cc/output/compositor_frame_ack.h"
#include "cc/output/copy_output_request.h"
#include "cc/output/copy_output_result.h"
#include "cc/output/output_surface.h"
+#include "cc/quads/draw_quad.h"
+#include "cc/quads/io_surface_draw_quad.h"
#include "cc/resources/prioritized_resource.h"
#include "cc/resources/prioritized_resource_manager.h"
#include "cc/resources/resource_update_queue.h"
-#include "cc/scheduler/frame_rate_controller.h"
#include "cc/test/fake_content_layer.h"
#include "cc/test/fake_content_layer_client.h"
#include "cc/test/fake_content_layer_impl.h"
@@ -40,7 +42,7 @@
#include "cc/test/fake_video_frame_provider.h"
#include "cc/test/geometry_test_utils.h"
#include "cc/test/layer_tree_test.h"
-#include "cc/test/occlusion_tracker_test_common.h"
+#include "cc/test/test_shared_bitmap_manager.h"
#include "cc/test/test_web_graphics_context_3d.h"
#include "cc/trees/layer_tree_host_impl.h"
#include "cc/trees/layer_tree_impl.h"
@@ -65,8 +67,7 @@ using testing::Mock;
namespace cc {
namespace {
-class LayerTreeHostTest : public LayerTreeTest {
-};
+class LayerTreeHostTest : public LayerTreeTest {};
// Two setNeedsCommits in a row should lead to at least 1 commit and at least 1
// draw with frame 0.
@@ -276,8 +277,7 @@ class LayerTreeHostTestSetNeedsRedrawRect : public LayerTreeHostTest {
: num_draws_(0),
bounds_(50, 50),
invalid_rect_(10, 10, 20, 20),
- root_layer_(ContentLayer::Create(&client_)) {
- }
+ root_layer_(ContentLayer::Create(&client_)) {}
virtual void BeginTest() OVERRIDE {
root_layer_->SetIsDrawable(true);
@@ -287,10 +287,11 @@ class LayerTreeHostTestSetNeedsRedrawRect : public LayerTreeHostTest {
PostSetNeedsCommitToMainThread();
}
- virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
- LayerTreeHostImpl::FrameData* frame_data,
- bool result) OVERRIDE {
- EXPECT_TRUE(result);
+ virtual DrawResult PrepareToDrawOnThread(
+ LayerTreeHostImpl* host_impl,
+ LayerTreeHostImpl::FrameData* frame_data,
+ DrawResult draw_result) OVERRIDE {
+ EXPECT_EQ(DRAW_SUCCESS, draw_result);
gfx::RectF root_damage_rect;
if (!frame_data->render_passes.empty())
@@ -304,7 +305,7 @@ class LayerTreeHostTestSetNeedsRedrawRect : public LayerTreeHostTest {
EXPECT_TRUE(root_damage_rect.Contains(invalid_rect_));
}
- return result;
+ return draw_result;
}
virtual void DrawLayersOnThread(LayerTreeHostImpl* impl) OVERRIDE {
@@ -316,9 +317,7 @@ class LayerTreeHostTestSetNeedsRedrawRect : public LayerTreeHostTest {
num_draws_++;
}
- virtual void AfterTest() OVERRIDE {
- EXPECT_EQ(2, num_draws_);
- }
+ virtual void AfterTest() OVERRIDE { EXPECT_EQ(2, num_draws_); }
private:
int num_draws_;
@@ -348,9 +347,7 @@ class LayerTreeHostTestNoExtraCommitFromInvalidate : public LayerTreeHostTest {
LayerTreeHostTest::SetupTree();
}
- virtual void BeginTest() OVERRIDE {
- PostSetNeedsCommitToMainThread();
- }
+ virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
if (host_impl->active_tree()->source_frame_number() == 1)
@@ -408,9 +405,7 @@ class LayerTreeHostTestNoExtraCommitFromScrollbarInvalidate
LayerTreeHostTest::SetupTree();
}
- virtual void BeginTest() OVERRIDE {
- PostSetNeedsCommitToMainThread();
- }
+ virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
if (host_impl->active_tree()->source_frame_number() == 1)
@@ -445,208 +440,13 @@ class LayerTreeHostTestNoExtraCommitFromScrollbarInvalidate
SINGLE_AND_MULTI_THREAD_TEST_F(
LayerTreeHostTestNoExtraCommitFromScrollbarInvalidate);
-class LayerTreeHostTestCompositeAndReadback : public LayerTreeHostTest {
- public:
- LayerTreeHostTestCompositeAndReadback() : num_commits_(0) {}
-
- virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
-
- virtual void DidCommit() OVERRIDE {
- num_commits_++;
- if (num_commits_ == 1) {
- char pixels[4];
- layer_tree_host()->CompositeAndReadback(&pixels, gfx::Rect(0, 0, 1, 1));
- } else if (num_commits_ == 2) {
- // This is inside the readback. We should get another commit after it.
- } else if (num_commits_ == 3) {
- EndTest();
- } else {
- NOTREACHED();
- }
- }
-
- virtual void AfterTest() OVERRIDE {}
-
- private:
- int num_commits_;
-};
-
-MULTI_THREAD_TEST_F(LayerTreeHostTestCompositeAndReadback);
-
-class LayerTreeHostTestCompositeAndReadbackBeforePreviousCommitDraws
- : public LayerTreeHostTest {
- public:
- LayerTreeHostTestCompositeAndReadbackBeforePreviousCommitDraws()
- : num_commits_(0) {}
-
- virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
-
- virtual void DidCommit() OVERRIDE {
- num_commits_++;
- if (num_commits_ == 1) {
- layer_tree_host()->SetNeedsCommit();
- } else if (num_commits_ == 2) {
- char pixels[4];
- layer_tree_host()->CompositeAndReadback(&pixels, gfx::Rect(0, 0, 1, 1));
- } else if (num_commits_ == 3) {
- // This is inside the readback. We should get another commit after it.
- } else if (num_commits_ == 4) {
- EndTest();
- } else {
- NOTREACHED();
- }
- }
-
- virtual void AfterTest() OVERRIDE {}
-
- private:
- int num_commits_;
-};
-
-MULTI_THREAD_TEST_F(
- LayerTreeHostTestCompositeAndReadbackBeforePreviousCommitDraws);
-
-class LayerTreeHostTestCompositeAndReadbackDuringForcedDraw
- : public LayerTreeHostTest {
- protected:
- static const int kFirstCommitSourceFrameNumber = 0;
- static const int kReadbackSourceFrameNumber = 1;
- static const int kReadbackReplacementAndForcedDrawSourceFrameNumber = 2;
-
- LayerTreeHostTestCompositeAndReadbackDuringForcedDraw()
- : did_post_readback_(false) {}
-
- virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
- // This enables forced draws after a single prepare to draw failure.
- settings->timeout_and_draw_when_animation_checkerboards = true;
- settings->maximum_number_of_failed_draws_before_draw_is_forced_ = 1;
- }
-
- virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
-
- virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
- LayerTreeHostImpl::FrameData* frame_data,
- bool result) OVERRIDE {
- int sfn = host_impl->active_tree()->source_frame_number();
- EXPECT_TRUE(sfn == kFirstCommitSourceFrameNumber ||
- sfn == kReadbackSourceFrameNumber ||
- sfn == kReadbackReplacementAndForcedDrawSourceFrameNumber)
- << sfn;
-
- // Before we react to the failed draw by initiating the forced draw
- // sequence, start a readback on the main thread.
- if (sfn == kFirstCommitSourceFrameNumber && !did_post_readback_) {
- did_post_readback_ = true;
- PostReadbackToMainThread();
- }
-
- // Returning false will result in a forced draw.
- return false;
- }
-
- virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
- // We should only draw for the readback and the forced draw.
- int sfn = host_impl->active_tree()->source_frame_number();
- EXPECT_TRUE(sfn == kReadbackSourceFrameNumber ||
- sfn == kReadbackReplacementAndForcedDrawSourceFrameNumber)
- << sfn;
- }
-
- virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl,
- bool result) OVERRIDE {
- // We should only swap for the forced draw.
- int sfn = host_impl->active_tree()->source_frame_number();
- EXPECT_TRUE(sfn == kReadbackReplacementAndForcedDrawSourceFrameNumber)
- << sfn;
- EndTest();
- }
-
- virtual void AfterTest() OVERRIDE {}
-
- bool did_post_readback_;
-};
-
-MULTI_THREAD_TEST_F(LayerTreeHostTestCompositeAndReadbackDuringForcedDraw);
-
-class LayerTreeHostTestCompositeAndReadbackAfterForcedDraw
- : public LayerTreeHostTest {
- protected:
- static const int kFirstCommitSourceFrameNumber = 0;
- static const int kForcedDrawSourceFrameNumber = 1;
- static const int kReadbackSourceFrameNumber = 2;
- static const int kReadbackReplacementSourceFrameNumber = 3;
-
- virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
- // This enables forced draws after a single prepare to draw failure.
- settings->timeout_and_draw_when_animation_checkerboards = true;
- settings->maximum_number_of_failed_draws_before_draw_is_forced_ = 1;
- }
-
- virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
-
- virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
- LayerTreeHostImpl::FrameData* frame_data,
- bool result) OVERRIDE {
- int sfn = host_impl->active_tree()->source_frame_number();
- EXPECT_TRUE(sfn == kFirstCommitSourceFrameNumber ||
- sfn == kForcedDrawSourceFrameNumber ||
- sfn == kReadbackSourceFrameNumber ||
- sfn == kReadbackReplacementSourceFrameNumber)
- << sfn;
-
- // Returning false will result in a forced draw.
- return false;
- }
-
- virtual void DidCommit() OVERRIDE {
- if (layer_tree_host()->source_frame_number() ==
- kForcedDrawSourceFrameNumber) {
- // Avoid aborting the forced draw commit so source_frame_number
- // increments.
- layer_tree_host()->SetNeedsCommit();
- } else if (layer_tree_host()->source_frame_number() ==
- kReadbackSourceFrameNumber) {
- // Perform a readback immediately after the forced draw's commit.
- char pixels[4];
- layer_tree_host()->CompositeAndReadback(&pixels, gfx::Rect(0, 0, 1, 1));
- }
- }
-
- virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
- // We should only draw for the the forced draw, readback, and
- // replacement commit.
- int sfn = host_impl->active_tree()->source_frame_number();
- EXPECT_TRUE(sfn == kForcedDrawSourceFrameNumber ||
- sfn == kReadbackSourceFrameNumber ||
- sfn == kReadbackReplacementSourceFrameNumber)
- << sfn;
- }
-
- virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl,
- bool result) OVERRIDE {
- // We should only swap for the forced draw and replacement commit.
- int sfn = host_impl->active_tree()->source_frame_number();
- EXPECT_TRUE(sfn == kForcedDrawSourceFrameNumber ||
- sfn == kReadbackReplacementSourceFrameNumber)
- << sfn;
-
- if (sfn == kReadbackReplacementSourceFrameNumber)
- EndTest();
- }
-
- virtual void AfterTest() OVERRIDE {}
-};
-
-MULTI_THREAD_TEST_F(LayerTreeHostTestCompositeAndReadbackAfterForcedDraw);
-
class LayerTreeHostTestSetNextCommitForcesRedraw : public LayerTreeHostTest {
public:
LayerTreeHostTestSetNextCommitForcesRedraw()
: num_draws_(0),
bounds_(50, 50),
invalid_rect_(10, 10, 20, 20),
- root_layer_(ContentLayer::Create(&client_)) {
- }
+ root_layer_(ContentLayer::Create(&client_)) {}
virtual void BeginTest() OVERRIDE {
root_layer_->SetIsDrawable(true);
@@ -661,10 +461,11 @@ class LayerTreeHostTestSetNextCommitForcesRedraw : public LayerTreeHostTest {
host_impl->SetNeedsRedrawRect(invalid_rect_);
}
- virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
- LayerTreeHostImpl::FrameData* frame_data,
- bool result) OVERRIDE {
- EXPECT_TRUE(result);
+ virtual DrawResult PrepareToDrawOnThread(
+ LayerTreeHostImpl* host_impl,
+ LayerTreeHostImpl::FrameData* frame_data,
+ DrawResult draw_result) OVERRIDE {
+ EXPECT_EQ(DRAW_SUCCESS, draw_result);
gfx::RectF root_damage_rect;
if (!frame_data->render_passes.empty())
@@ -688,7 +489,7 @@ class LayerTreeHostTestSetNextCommitForcesRedraw : public LayerTreeHostTest {
NOTREACHED();
}
- return result;
+ return draw_result;
}
virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
@@ -718,9 +519,7 @@ class LayerTreeHostTestSetNextCommitForcesRedraw : public LayerTreeHostTest {
num_draws_++;
}
- virtual void AfterTest() OVERRIDE {
- EXPECT_EQ(5, num_draws_);
- }
+ virtual void AfterTest() OVERRIDE { EXPECT_EQ(5, num_draws_); }
private:
int num_draws_;
@@ -737,8 +536,7 @@ SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestSetNextCommitForcesRedraw);
class LayerTreeHostTestUndrawnLayersDamageLater : public LayerTreeHostTest {
public:
LayerTreeHostTestUndrawnLayersDamageLater()
- : root_layer_(ContentLayer::Create(&client_)) {
- }
+ : root_layer_(ContentLayer::Create(&client_)) {}
virtual void SetupTree() OVERRIDE {
root_layer_->SetIsDrawable(true);
@@ -759,14 +557,13 @@ class LayerTreeHostTestUndrawnLayersDamageLater : public LayerTreeHostTest {
LayerTreeHostTest::SetupTree();
}
- virtual void BeginTest() OVERRIDE {
- PostSetNeedsCommitToMainThread();
- }
+ virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
- virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
- LayerTreeHostImpl::FrameData* frame_data,
- bool result) OVERRIDE {
- EXPECT_TRUE(result);
+ virtual DrawResult PrepareToDrawOnThread(
+ LayerTreeHostImpl* host_impl,
+ LayerTreeHostImpl::FrameData* frame_data,
+ DrawResult draw_result) OVERRIDE {
+ EXPECT_EQ(DRAW_SUCCESS, draw_result);
gfx::RectF root_damage_rect;
if (!frame_data->render_passes.empty())
@@ -777,20 +574,20 @@ class LayerTreeHostTestUndrawnLayersDamageLater : public LayerTreeHostTest {
// and each damage should be the bounding box of it and its child. If this
// was working improperly, the damage might not include its childs bounding
// box.
- switch (layer_tree_host()->source_frame_number()) {
- case 1:
+ switch (host_impl->active_tree()->source_frame_number()) {
+ case 0:
EXPECT_RECT_EQ(gfx::Rect(root_layer_->bounds()), root_damage_rect);
break;
+ case 1:
case 2:
case 3:
- case 4:
EXPECT_RECT_EQ(gfx::Rect(child_layer_->bounds()), root_damage_rect);
break;
default:
NOTREACHED();
}
- return result;
+ return draw_result;
}
virtual void DidCommitAndDrawFrame() OVERRIDE {
@@ -815,7 +612,6 @@ class LayerTreeHostTestUndrawnLayersDamageLater : public LayerTreeHostTest {
}
}
-
virtual void AfterTest() OVERRIDE {}
private:
@@ -827,145 +623,76 @@ class LayerTreeHostTestUndrawnLayersDamageLater : public LayerTreeHostTest {
SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestUndrawnLayersDamageLater);
-// If the layerTreeHost says it can't draw, Then we should not try to draw.
-class LayerTreeHostTestCanDrawBlocksDrawing : public LayerTreeHostTest {
+// Tests that if a layer is not drawn because of some reason in the parent,
+// causing its content bounds to not be computed, then when it is later drawn,
+// its content bounds get pushed.
+class LayerTreeHostTestUndrawnLayersPushContentBoundsLater
+ : public LayerTreeHostTest {
public:
- LayerTreeHostTestCanDrawBlocksDrawing() : num_commits_(0), done_(false) {}
-
- virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
-
- virtual void DrawLayersOnThread(LayerTreeHostImpl* impl) OVERRIDE {
- if (done_)
- return;
- // Only the initial draw should bring us here.
- EXPECT_TRUE(impl->CanDraw());
- EXPECT_EQ(0, impl->active_tree()->source_frame_number());
- }
-
- virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
- if (done_)
- return;
- if (num_commits_ >= 1) {
- // After the first commit, we should not be able to draw.
- EXPECT_FALSE(impl->CanDraw());
- }
- }
-
- virtual void DidCommit() OVERRIDE {
- num_commits_++;
- if (num_commits_ == 1) {
- // Make the viewport empty so the host says it can't draw.
- layer_tree_host()->SetViewportSize(gfx::Size(0, 0));
- } else if (num_commits_ == 2) {
- char pixels[4];
- layer_tree_host()->CompositeAndReadback(&pixels, gfx::Rect(0, 0, 1, 1));
- } else if (num_commits_ == 3) {
- // Let it draw so we go idle and end the test.
- layer_tree_host()->SetViewportSize(gfx::Size(1, 1));
- done_ = true;
- EndTest();
- }
- }
-
- virtual void AfterTest() OVERRIDE {}
+ LayerTreeHostTestUndrawnLayersPushContentBoundsLater()
+ : root_layer_(Layer::Create()) {}
- private:
- int num_commits_;
- bool done_;
-};
-
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestCanDrawBlocksDrawing);
-
-// beginLayerWrite should prevent draws from executing until a commit occurs
-class LayerTreeHostTestWriteLayersRedraw : public LayerTreeHostTest {
- public:
- LayerTreeHostTestWriteLayersRedraw() : num_commits_(0), num_draws_(0) {}
+ virtual void SetupTree() OVERRIDE {
+ root_layer_->SetIsDrawable(true);
+ root_layer_->SetBounds(gfx::Size(20, 20));
+ layer_tree_host()->SetRootLayer(root_layer_);
- virtual void BeginTest() OVERRIDE {
- PostAcquireLayerTextures();
- PostSetNeedsRedrawToMainThread(); // should be inhibited without blocking
- PostSetNeedsCommitToMainThread();
- }
+ parent_layer_ = Layer::Create();
+ parent_layer_->SetBounds(gfx::Size(20, 20));
+ parent_layer_->SetOpacity(0.0f);
+ root_layer_->AddChild(parent_layer_);
- virtual void DrawLayersOnThread(LayerTreeHostImpl* impl) OVERRIDE {
- num_draws_++;
- EXPECT_EQ(num_draws_, num_commits_);
- }
+ child_layer_ = Layer::Create();
+ child_layer_->SetBounds(gfx::Size(15, 15));
+ parent_layer_->AddChild(child_layer_);
- virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
- num_commits_++;
- EndTest();
+ LayerTreeHostTest::SetupTree();
}
- virtual void AfterTest() OVERRIDE { EXPECT_EQ(1, num_commits_); }
-
- private:
- int num_commits_;
- int num_draws_;
-};
-
-MULTI_THREAD_TEST_F(LayerTreeHostTestWriteLayersRedraw);
-
-// Verify that when resuming visibility, Requesting layer write permission
-// will not deadlock the main thread even though there are not yet any
-// scheduled redraws. This behavior is critical for reliably surviving tab
-// switching. There are no failure conditions to this test, it just passes
-// by not timing out.
-class LayerTreeHostTestWriteLayersAfterVisible : public LayerTreeHostTest {
- public:
- LayerTreeHostTestWriteLayersAfterVisible() : num_commits_(0) {}
-
virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
- virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
- num_commits_++;
- if (num_commits_ == 2)
- EndTest();
- else if (num_commits_ < 2) {
- PostSetVisibleToMainThread(false);
- PostSetVisibleToMainThread(true);
- PostAcquireLayerTextures();
- PostSetNeedsCommitToMainThread();
+ virtual void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
+ LayerImpl* root = host_impl->active_tree()->root_layer();
+ LayerImpl* parent = root->children()[0];
+ LayerImpl* child = parent->children()[0];
+
+ switch (host_impl->active_tree()->source_frame_number()) {
+ case 0:
+ EXPECT_EQ(0.f, parent->opacity());
+ EXPECT_EQ(gfx::SizeF(), child->content_bounds());
+ break;
+ case 1:
+ EXPECT_EQ(1.f, parent->opacity());
+ EXPECT_EQ(gfx::SizeF(15.f, 15.f), child->content_bounds());
+ EndTest();
+ break;
+ default:
+ NOTREACHED();
}
}
- virtual void AfterTest() OVERRIDE {}
-
- private:
- int num_commits_;
-};
-
-MULTI_THREAD_TEST_F(LayerTreeHostTestWriteLayersAfterVisible);
-
-// A compositeAndReadback while invisible should force a normal commit without
-// assertion.
-class LayerTreeHostTestCompositeAndReadbackWhileInvisible
- : public LayerTreeHostTest {
- public:
- LayerTreeHostTestCompositeAndReadbackWhileInvisible() : num_commits_(0) {}
-
- virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
-
- virtual void DidCommitAndDrawFrame() OVERRIDE {
- num_commits_++;
- if (num_commits_ == 1) {
- layer_tree_host()->SetVisible(false);
- layer_tree_host()->SetNeedsCommit();
- layer_tree_host()->SetNeedsCommit();
- char pixels[4];
- layer_tree_host()->CompositeAndReadback(&pixels, gfx::Rect(0, 0, 1, 1));
- } else {
- EndTest();
+ virtual void DidCommit() OVERRIDE {
+ switch (layer_tree_host()->source_frame_number()) {
+ case 1:
+ parent_layer_->SetOpacity(1.0f);
+ break;
+ case 2:
+ break;
+ default:
+ NOTREACHED();
}
}
virtual void AfterTest() OVERRIDE {}
private:
- int num_commits_;
+ scoped_refptr<Layer> root_layer_;
+ scoped_refptr<Layer> parent_layer_;
+ scoped_refptr<Layer> child_layer_;
};
-MULTI_THREAD_TEST_F(LayerTreeHostTestCompositeAndReadbackWhileInvisible);
+SINGLE_AND_MULTI_THREAD_TEST_F(
+ LayerTreeHostTestUndrawnLayersPushContentBoundsLater);
class LayerTreeHostTestAbortFrameWhenInvisible : public LayerTreeHostTest {
public:
@@ -1033,7 +760,7 @@ class LayerTreeHostTestFrameTimeUpdatesAfterActivationFails
PostSetNeedsCommitToMainThread();
}
- virtual void BeginCommitOnThread(LayerTreeHostImpl *impl) OVERRIDE {
+ virtual void BeginCommitOnThread(LayerTreeHostImpl* impl) OVERRIDE {
EXPECT_EQ(frame_count_with_pending_tree_, 0);
impl->BlockNotifyReadyToActivateForTesting(true);
}
@@ -1043,15 +770,11 @@ class LayerTreeHostTestFrameTimeUpdatesAfterActivationFails
if (impl->pending_tree())
frame_count_with_pending_tree_++;
- if (frame_count_with_pending_tree_ == 2)
- impl->BlockNotifyReadyToActivateForTesting(false);
- }
-
- virtual void DidBeginImplFrameOnThread(LayerTreeHostImpl* impl,
- const BeginFrameArgs& args) OVERRIDE {
if (frame_count_with_pending_tree_ == 1) {
EXPECT_EQ(first_frame_time_.ToInternalValue(), 0);
first_frame_time_ = impl->CurrentFrameTimeTicks();
+ } else if (frame_count_with_pending_tree_ == 2) {
+ impl->BlockNotifyReadyToActivateForTesting(false);
}
}
@@ -1103,7 +826,8 @@ class LayerTreeHostTestFrameTimeUpdatesAfterDraw : public LayerTreeHostTest {
// Since we might use a low-resolution clock on Windows, we need to
// make sure that the clock has incremented past first_frame_time_.
- while (first_frame_time_ == gfx::FrameTime::Now()) {}
+ while (first_frame_time_ == gfx::FrameTime::Now()) {
+ }
return;
}
@@ -1132,8 +856,7 @@ SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestFrameTimeUpdatesAfterDraw);
// Verifies that StartPageScaleAnimation events propagate correctly
// from LayerTreeHost to LayerTreeHostImpl in the MT compositor.
-class LayerTreeHostTestStartPageScaleAnimation
- : public LayerTreeHostTest {
+class LayerTreeHostTestStartPageScaleAnimation : public LayerTreeHostTest {
public:
LayerTreeHostTestStartPageScaleAnimation() {}
@@ -1149,18 +872,24 @@ class LayerTreeHostTestStartPageScaleAnimation
scroll_layer_ = FakeContentLayer::Create(&client_);
}
- scroll_layer_->SetScrollable(true);
+ Layer* root_layer = layer_tree_host()->root_layer();
+ scroll_layer_->SetScrollClipLayerId(root_layer->id());
+ scroll_layer_->SetIsContainerForFixedPositionLayers(true);
+ scroll_layer_->SetBounds(gfx::Size(2 * root_layer->bounds().width(),
+ 2 * root_layer->bounds().height()));
scroll_layer_->SetScrollOffset(gfx::Vector2d());
layer_tree_host()->root_layer()->AddChild(scroll_layer_);
+ // This test requires the page_scale and inner viewport layers to be
+ // identified.
+ layer_tree_host()->RegisterViewportLayers(
+ root_layer, scroll_layer_.get(), NULL);
layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 0.5f, 2.f);
}
- virtual void BeginTest() OVERRIDE {
- PostSetNeedsCommitToMainThread();
- }
+ virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
- virtual void ApplyScrollAndScale(gfx::Vector2d scroll_delta, float scale)
- OVERRIDE {
+ virtual void ApplyScrollAndScale(const gfx::Vector2d& scroll_delta,
+ float scale) OVERRIDE {
gfx::Vector2d offset = scroll_layer_->scroll_offset();
scroll_layer_->SetScrollOffset(offset + scroll_delta);
layer_tree_host()->SetPageScaleFactorAndLimits(scale, 0.5f, 2.f);
@@ -1236,12 +965,17 @@ class TestOpacityChangeLayerDelegate : public ContentLayerClient {
void SetTestLayer(Layer* test_layer) { test_layer_ = test_layer; }
- virtual void PaintContents(SkCanvas*, gfx::Rect, gfx::RectF*) OVERRIDE {
+ virtual void PaintContents(
+ SkCanvas* canvas,
+ const gfx::Rect& clip,
+ gfx::RectF* opaque,
+ ContentLayerClient::GraphicsContextStatus gc_status) OVERRIDE {
// Set layer opacity to 0.
if (test_layer_)
test_layer_->SetOpacity(0.f);
}
virtual void DidChangeLayerCanUseLCDText() OVERRIDE {}
+ virtual bool FillsBoundsCompletely() const OVERRIDE { return false; }
private:
Layer* test_layer_;
@@ -1258,7 +992,7 @@ class ContentLayerWithUpdateTracking : public ContentLayer {
void ResetPaintContentsCount() { paint_contents_count_ = 0; }
virtual bool Update(ResourceUpdateQueue* queue,
- const OcclusionTracker* occlusion) OVERRIDE {
+ const OcclusionTracker<Layer>* occlusion) OVERRIDE {
bool updated = ContentLayer::Update(queue, occlusion);
paint_contents_count_++;
return updated;
@@ -1267,7 +1001,6 @@ class ContentLayerWithUpdateTracking : public ContentLayer {
private:
explicit ContentLayerWithUpdateTracking(ContentLayerClient* client)
: ContentLayer(client), paint_contents_count_(0) {
- SetAnchorPoint(gfx::PointF(0.f, 0.f));
SetBounds(gfx::Size(10, 10));
SetIsDrawable(true);
}
@@ -1319,6 +1052,7 @@ class NoScaleContentLayer : public ContentLayer {
virtual void CalculateContentsScale(float ideal_contents_scale,
float device_scale_factor,
float page_scale_factor,
+ float maximum_animation_contents_scale,
bool animating_transform_to_screen,
float* contents_scale_x,
float* contents_scale_y,
@@ -1327,6 +1061,7 @@ class NoScaleContentLayer : public ContentLayer {
Layer::CalculateContentsScale(ideal_contents_scale,
device_scale_factor,
page_scale_factor,
+ maximum_animation_contents_scale,
animating_transform_to_screen,
contents_scale_x,
contents_scale_y,
@@ -1355,12 +1090,10 @@ class LayerTreeHostTestDeviceScaleFactorScalesViewportAndLayers
root_layer_->SetIsDrawable(true);
root_layer_->SetBounds(gfx::Size(30, 30));
- root_layer_->SetAnchorPoint(gfx::PointF(0.f, 0.f));
child_layer_->SetIsDrawable(true);
child_layer_->SetPosition(gfx::Point(2, 2));
child_layer_->SetBounds(gfx::Size(10, 10));
- child_layer_->SetAnchorPoint(gfx::PointF(0.f, 0.f));
layer_tree_host()->SetRootLayer(root_layer_);
@@ -1388,7 +1121,7 @@ class LayerTreeHostTestDeviceScaleFactorScalesViewportAndLayers
// Compute all the layer transforms for the frame.
LayerTreeHostImpl::FrameData frame_data;
- impl->PrepareToDraw(&frame_data, gfx::Rect());
+ impl->PrepareToDraw(&frame_data);
impl->DidDrawAllLayers(frame_data);
const LayerImplList& render_surface_layer_list =
@@ -1479,8 +1212,7 @@ class LayerTreeHostTestDirectRendererAtomicCommit : public LayerTreeHostTest {
virtual void DidActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
ASSERT_EQ(0u, layer_tree_host()->settings().max_partial_texture_updates);
- TestWebGraphicsContext3D* context = static_cast<TestWebGraphicsContext3D*>(
- impl->output_surface()->context_provider()->Context3d());
+ TestWebGraphicsContext3D* context = TestContext();
switch (impl->active_tree()->source_frame_number()) {
case 0:
@@ -1493,7 +1225,6 @@ class LayerTreeHostTestDirectRendererAtomicCommit : public LayerTreeHostTest {
EXPECT_TRUE(context->UsedTexture(context->TextureAt(1)));
context->ResetUsedTextures();
- PostSetNeedsCommitToMainThread();
break;
case 1:
// Number of textures should be one for scrollbar layer since it was
@@ -1509,7 +1240,6 @@ class LayerTreeHostTestDirectRendererAtomicCommit : public LayerTreeHostTest {
// New textures should have been used.
EXPECT_TRUE(context->UsedTexture(context->TextureAt(2)));
context->ResetUsedTextures();
- PostSetNeedsCommitToMainThread();
break;
case 2:
EndTest();
@@ -1521,8 +1251,7 @@ class LayerTreeHostTestDirectRendererAtomicCommit : public LayerTreeHostTest {
}
virtual void DrawLayersOnThread(LayerTreeHostImpl* impl) OVERRIDE {
- TestWebGraphicsContext3D* context = static_cast<TestWebGraphicsContext3D*>(
- impl->output_surface()->context_provider()->Context3d());
+ TestWebGraphicsContext3D* context = TestContext();
if (drew_frame_ == impl->active_tree()->source_frame_number()) {
EXPECT_EQ(0u, context->NumUsedTextures()) << "For frame " << drew_frame_;
@@ -1533,6 +1262,9 @@ class LayerTreeHostTestDirectRendererAtomicCommit : public LayerTreeHostTest {
// We draw/ship one texture each frame for each layer.
EXPECT_EQ(2u, context->NumUsedTextures());
context->ResetUsedTextures();
+
+ if (!TestEnded())
+ PostSetNeedsCommitToMainThread();
}
virtual void Layout() OVERRIDE {
@@ -1558,8 +1290,7 @@ class LayerTreeHostTestDelegatingRendererAtomicCommit
virtual void DidActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
ASSERT_EQ(0u, layer_tree_host()->settings().max_partial_texture_updates);
- TestWebGraphicsContext3D* context = static_cast<TestWebGraphicsContext3D*>(
- impl->output_surface()->context_provider()->Context3d());
+ TestWebGraphicsContext3D* context = TestContext();
switch (impl->active_tree()->source_frame_number()) {
case 0:
@@ -1571,7 +1302,6 @@ class LayerTreeHostTestDelegatingRendererAtomicCommit
EXPECT_TRUE(context->UsedTexture(context->TextureAt(0)));
EXPECT_TRUE(context->UsedTexture(context->TextureAt(1)));
context->ResetUsedTextures();
- PostSetNeedsCommitToMainThread();
break;
case 1:
// Number of textures should be doubled as the first context layer
@@ -1590,7 +1320,6 @@ class LayerTreeHostTestDelegatingRendererAtomicCommit
EXPECT_TRUE(context->UsedTexture(context->TextureAt(2)));
EXPECT_TRUE(context->UsedTexture(context->TextureAt(3)));
context->ResetUsedTextures();
- PostSetNeedsCommitToMainThread();
break;
case 2:
EndTest();
@@ -1608,15 +1337,15 @@ MULTI_THREAD_DELEGATING_RENDERER_NOIMPL_TEST_F(
static void SetLayerPropertiesForTesting(Layer* layer,
Layer* parent,
const gfx::Transform& transform,
- gfx::PointF anchor,
- gfx::PointF position,
- gfx::Size bounds,
+ const gfx::Point3F& transform_origin,
+ const gfx::PointF& position,
+ const gfx::Size& bounds,
bool opaque) {
layer->RemoveAllChildren();
if (parent)
parent->AddChild(layer);
layer->SetTransform(transform);
- layer->SetAnchorPoint(anchor);
+ layer->SetTransformOrigin(transform_origin);
layer->SetPosition(position);
layer->SetBounds(bounds);
layer->SetContentsOpaque(opaque);
@@ -1647,9 +1376,7 @@ class LayerTreeHostTestAtomicCommitWithPartialUpdate
LayerTreeHostTest::SetupTree();
}
- virtual void BeginTest() OVERRIDE {
- PostSetNeedsCommitToMainThread();
- }
+ virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
virtual void DidCommitAndDrawFrame() OVERRIDE {
switch (layer_tree_host()->source_frame_number()) {
@@ -1681,8 +1408,7 @@ class LayerTreeHostTestAtomicCommitWithPartialUpdate
virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
ASSERT_EQ(1u, layer_tree_host()->settings().max_partial_texture_updates);
- TestWebGraphicsContext3D* context = static_cast<TestWebGraphicsContext3D*>(
- impl->output_surface()->context_provider()->Context3d());
+ TestWebGraphicsContext3D* context = TestContext();
switch (impl->active_tree()->source_frame_number()) {
case 0:
@@ -1772,16 +1498,15 @@ class LayerTreeHostTestAtomicCommitWithPartialUpdate
virtual void DrawLayersOnThread(LayerTreeHostImpl* impl) OVERRIDE {
EXPECT_LT(impl->active_tree()->source_frame_number(), 5);
- TestWebGraphicsContext3D* context = static_cast<TestWebGraphicsContext3D*>(
- impl->output_surface()->context_provider()->Context3d());
+ TestWebGraphicsContext3D* context = TestContext();
// Number of textures used for drawing should one per layer except for
// frame 3 where the viewport only contains one layer.
if (impl->active_tree()->source_frame_number() == 3) {
EXPECT_EQ(1u, context->NumUsedTextures());
} else {
- EXPECT_EQ(2u, context->NumUsedTextures()) <<
- "For frame " << impl->active_tree()->source_frame_number();
+ EXPECT_EQ(2u, context->NumUsedTextures())
+ << "For frame " << impl->active_tree()->source_frame_number();
}
context->ResetUsedTextures();
@@ -1799,66 +1524,6 @@ class LayerTreeHostTestAtomicCommitWithPartialUpdate
SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(
LayerTreeHostTestAtomicCommitWithPartialUpdate);
-class LayerTreeHostTestFinishAllRendering : public LayerTreeHostTest {
- public:
- LayerTreeHostTestFinishAllRendering() : once_(false), draw_count_(0) {}
-
- virtual void BeginTest() OVERRIDE {
- layer_tree_host()->SetNeedsRedraw();
- PostSetNeedsCommitToMainThread();
- }
-
- virtual void DidCommitAndDrawFrame() OVERRIDE {
- if (once_)
- return;
- once_ = true;
- layer_tree_host()->SetNeedsRedraw();
- layer_tree_host()->AcquireLayerTextures();
- {
- base::AutoLock lock(lock_);
- draw_count_ = 0;
- }
- layer_tree_host()->FinishAllRendering();
- {
- base::AutoLock lock(lock_);
- EXPECT_EQ(0, draw_count_);
- }
- EndTest();
- }
-
- virtual void DrawLayersOnThread(LayerTreeHostImpl* impl) OVERRIDE {
- base::AutoLock lock(lock_);
- ++draw_count_;
- }
-
- virtual void AfterTest() OVERRIDE {}
-
- private:
- bool once_;
- base::Lock lock_;
- int draw_count_;
-};
-
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestFinishAllRendering);
-
-class LayerTreeHostTestCompositeAndReadbackCleanup : public LayerTreeHostTest {
- public:
- virtual void BeginTest() OVERRIDE {
- Layer* root_layer = layer_tree_host()->root_layer();
-
- char pixels[4];
- layer_tree_host()->CompositeAndReadback(static_cast<void*>(&pixels),
- gfx::Rect(0, 0, 1, 1));
- EXPECT_FALSE(root_layer->render_surface());
-
- EndTest();
- }
-
- virtual void AfterTest() OVERRIDE {}
-};
-
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestCompositeAndReadbackCleanup);
-
class LayerTreeHostTestSurfaceNotAllocatedForLayersOutsideMemoryLimit
: public LayerTreeHostTest {
protected:
@@ -1888,24 +1553,28 @@ class LayerTreeHostTestSurfaceNotAllocatedForLayersOutsideMemoryLimit
LayerTreeHostTest::SetupTree();
}
- virtual void BeginTest() OVERRIDE {
- PostSetNeedsCommitToMainThread();
- }
+ virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
Renderer* renderer = host_impl->renderer();
RenderPass::Id surface1_render_pass_id = host_impl->active_tree()
- ->root_layer()->children()[0]->render_surface()->RenderPassId();
- RenderPass::Id surface2_render_pass_id =
- host_impl->active_tree()->root_layer()->children()[0]->children()[0]
- ->render_surface()->RenderPassId();
+ ->root_layer()
+ ->children()[0]
+ ->render_surface()
+ ->RenderPassId();
+ RenderPass::Id surface2_render_pass_id = host_impl->active_tree()
+ ->root_layer()
+ ->children()[0]
+ ->children()[0]
+ ->render_surface()
+ ->RenderPassId();
switch (host_impl->active_tree()->source_frame_number()) {
case 0:
- EXPECT_TRUE(renderer->HasAllocatedResourcesForTesting(
- surface1_render_pass_id));
- EXPECT_TRUE(renderer->HasAllocatedResourcesForTesting(
- surface2_render_pass_id));
+ EXPECT_TRUE(
+ renderer->HasAllocatedResourcesForTesting(surface1_render_pass_id));
+ EXPECT_TRUE(
+ renderer->HasAllocatedResourcesForTesting(surface2_render_pass_id));
// Reduce the memory limit to only fit the root layer and one render
// surface. This prevents any contents drawing into surfaces
@@ -1913,10 +1582,10 @@ class LayerTreeHostTestSurfaceNotAllocatedForLayersOutsideMemoryLimit
host_impl->SetMemoryPolicy(ManagedMemoryPolicy(100 * 100 * 4 * 2));
break;
case 1:
- EXPECT_FALSE(renderer->HasAllocatedResourcesForTesting(
- surface1_render_pass_id));
- EXPECT_FALSE(renderer->HasAllocatedResourcesForTesting(
- surface2_render_pass_id));
+ EXPECT_FALSE(
+ renderer->HasAllocatedResourcesForTesting(surface1_render_pass_id));
+ EXPECT_FALSE(
+ renderer->HasAllocatedResourcesForTesting(surface2_render_pass_id));
EndTest();
break;
@@ -1953,7 +1622,7 @@ class EvictionTestLayer : public Layer {
}
virtual bool Update(ResourceUpdateQueue*,
- const OcclusionTracker*) OVERRIDE;
+ const OcclusionTracker<Layer>*) OVERRIDE;
virtual bool DrawsContent() const OVERRIDE { return true; }
virtual scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl)
@@ -1975,8 +1644,7 @@ class EvictionTestLayer : public Layer {
texture_ = PrioritizedResource::Create(
layer_tree_host()->contents_texture_manager());
texture_->SetDimensions(gfx::Size(10, 10), RGBA_8888);
- bitmap_.setConfig(SkBitmap::kARGB_8888_Config, 10, 10);
- bitmap_.allocPixels();
+ bitmap_.allocN32Pixels(10, 10);
}
scoped_ptr<PrioritizedResource> texture_;
@@ -2014,7 +1682,7 @@ void EvictionTestLayer::SetTexturePriorities(const PriorityCalculator&) {
}
bool EvictionTestLayer::Update(ResourceUpdateQueue* queue,
- const OcclusionTracker*) {
+ const OcclusionTracker<Layer>* occlusion) {
CreateTextureIfNeeded();
if (!texture_)
return false;
@@ -2055,7 +1723,7 @@ class LayerTreeHostTestEvictTextures : public LayerTreeHostTest {
SetLayerPropertiesForTesting(layer_.get(),
0,
identity_matrix,
- gfx::PointF(0.f, 0.f),
+ gfx::Point3F(0.f, 0.f, 0.f),
gfx::PointF(0.f, 0.f),
gfx::Size(10, 20),
true);
@@ -2222,7 +1890,6 @@ class LayerTreeHostTestContinuousInvalidate : public LayerTreeHostTest {
content_layer_ = ContentLayer::Create(&client_);
content_layer_->SetBounds(gfx::Size(10, 10));
content_layer_->SetPosition(gfx::PointF(0.f, 0.f));
- content_layer_->SetAnchorPoint(gfx::PointF(0.f, 0.f));
content_layer_->SetIsDrawable(true);
layer_tree_host()->root_layer()->AddChild(content_layer_);
@@ -2308,7 +1975,7 @@ class LayerTreeHostWithProxy : public LayerTreeHost {
scoped_ptr<FakeProxy> proxy)
: LayerTreeHost(client, NULL, settings) {
proxy->SetLayerTreeHost(this);
- EXPECT_TRUE(InitializeForTesting(proxy.PassAs<Proxy>()));
+ InitializeForTesting(proxy.PassAs<Proxy>());
}
};
@@ -2325,7 +1992,7 @@ TEST(LayerTreeHostTest, LimitPartialUpdates) {
settings.max_partial_texture_updates = 10;
LayerTreeHostWithProxy host(&client, settings, proxy.Pass());
- EXPECT_TRUE(host.InitializeOutputSurfaceIfNeeded());
+ host.OnCreateAndInitializeOutputSurfaceAttempted(true);
EXPECT_EQ(0u, host.MaxPartialTextureUpdates());
}
@@ -2343,7 +2010,7 @@ TEST(LayerTreeHostTest, LimitPartialUpdates) {
settings.max_partial_texture_updates = 10;
LayerTreeHostWithProxy host(&client, settings, proxy.Pass());
- EXPECT_TRUE(host.InitializeOutputSurfaceIfNeeded());
+ host.OnCreateAndInitializeOutputSurfaceAttempted(true);
EXPECT_EQ(5u, host.MaxPartialTextureUpdates());
}
@@ -2361,7 +2028,7 @@ TEST(LayerTreeHostTest, LimitPartialUpdates) {
settings.max_partial_texture_updates = 10;
LayerTreeHostWithProxy host(&client, settings, proxy.Pass());
- EXPECT_TRUE(host.InitializeOutputSurfaceIfNeeded());
+ host.OnCreateAndInitializeOutputSurfaceAttempted(true);
EXPECT_EQ(10u, host.MaxPartialTextureUpdates());
}
@@ -2373,9 +2040,12 @@ TEST(LayerTreeHostTest, PartialUpdatesWithGLRenderer) {
LayerTreeSettings settings;
settings.max_partial_texture_updates = 4;
- scoped_ptr<LayerTreeHost> host =
- LayerTreeHost::CreateSingleThreaded(&client, &client, NULL, settings);
- EXPECT_TRUE(host->InitializeOutputSurfaceIfNeeded());
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
+ scoped_ptr<LayerTreeHost> host = LayerTreeHost::CreateSingleThreaded(
+ &client, &client, shared_bitmap_manager.get(), settings);
+ host->Composite(base::TimeTicks::Now());
+
EXPECT_EQ(4u, host->settings().max_partial_texture_updates);
}
@@ -2385,9 +2055,12 @@ TEST(LayerTreeHostTest, PartialUpdatesWithSoftwareRenderer) {
LayerTreeSettings settings;
settings.max_partial_texture_updates = 4;
- scoped_ptr<LayerTreeHost> host =
- LayerTreeHost::CreateSingleThreaded(&client, &client, NULL, settings);
- EXPECT_TRUE(host->InitializeOutputSurfaceIfNeeded());
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
+ scoped_ptr<LayerTreeHost> host = LayerTreeHost::CreateSingleThreaded(
+ &client, &client, shared_bitmap_manager.get(), settings);
+ host->Composite(base::TimeTicks::Now());
+
EXPECT_EQ(4u, host->settings().max_partial_texture_updates);
}
@@ -2397,9 +2070,12 @@ TEST(LayerTreeHostTest, PartialUpdatesWithDelegatingRendererAndGLContent) {
LayerTreeSettings settings;
settings.max_partial_texture_updates = 4;
- scoped_ptr<LayerTreeHost> host =
- LayerTreeHost::CreateSingleThreaded(&client, &client, NULL, settings);
- EXPECT_TRUE(host->InitializeOutputSurfaceIfNeeded());
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
+ scoped_ptr<LayerTreeHost> host = LayerTreeHost::CreateSingleThreaded(
+ &client, &client, shared_bitmap_manager.get(), settings);
+ host->Composite(base::TimeTicks::Now());
+
EXPECT_EQ(0u, host->MaxPartialTextureUpdates());
}
@@ -2410,9 +2086,12 @@ TEST(LayerTreeHostTest,
LayerTreeSettings settings;
settings.max_partial_texture_updates = 4;
- scoped_ptr<LayerTreeHost> host =
- LayerTreeHost::CreateSingleThreaded(&client, &client, NULL, settings);
- EXPECT_TRUE(host->InitializeOutputSurfaceIfNeeded());
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
+ scoped_ptr<LayerTreeHost> host = LayerTreeHost::CreateSingleThreaded(
+ &client, &client, shared_bitmap_manager.get(), settings);
+ host->Composite(base::TimeTicks::Now());
+
EXPECT_EQ(0u, host->MaxPartialTextureUpdates());
}
@@ -2445,8 +2124,7 @@ class LayerTreeHostTestShutdownWithOnlySomeResourcesEvicted
layer_tree_host()->contents_texture_manager()->MemoryUseBytes());
} else {
EXPECT_EQ(
- 0u,
- layer_tree_host()->contents_texture_manager()->MemoryUseBytes());
+ 0u, layer_tree_host()->contents_texture_manager()->MemoryUseBytes());
}
// Make sure that contents textures are marked as having been
@@ -2512,15 +2190,18 @@ class LayerTreeHostTestLCDNotification : public LayerTreeHostTest {
int paint_count() const { return paint_count_; }
int lcd_notification_count() const { return lcd_notification_count_; }
- virtual void PaintContents(SkCanvas* canvas,
- gfx::Rect clip,
- gfx::RectF* opaque) OVERRIDE {
+ virtual void PaintContents(
+ SkCanvas* canvas,
+ const gfx::Rect& clip,
+ gfx::RectF* opaque,
+ ContentLayerClient::GraphicsContextStatus gc_status) OVERRIDE {
++paint_count_;
}
virtual void DidChangeLayerCanUseLCDText() OVERRIDE {
++lcd_notification_count_;
layer_->SetNeedsDisplay();
}
+ virtual bool FillsBoundsCompletely() const OVERRIDE { return false; }
private:
Layer* layer_;
@@ -2529,7 +2210,11 @@ class LayerTreeHostTestLCDNotification : public LayerTreeHostTest {
};
virtual void SetupTree() OVERRIDE {
- scoped_refptr<ContentLayer> root_layer = ContentLayer::Create(&client_);
+ scoped_refptr<Layer> root_layer;
+ if (layer_tree_host()->settings().impl_side_painting)
+ root_layer = PictureLayer::Create(&client_);
+ else
+ root_layer = ContentLayer::Create(&client_);
root_layer->SetIsDrawable(true);
root_layer->SetBounds(gfx::Size(1, 1));
@@ -2550,7 +2235,7 @@ class LayerTreeHostTestLCDNotification : public LayerTreeHostTest {
virtual void DidCommit() OVERRIDE {
switch (layer_tree_host()->source_frame_number()) {
case 1:
- // The first update consists one LCD notification and one paint.
+ // The first update consists of one LCD notification and one paint.
EXPECT_EQ(1, client_.lcd_notification_count());
EXPECT_EQ(1, client_.paint_count());
// LCD text must have been enabled on the layer.
@@ -2569,7 +2254,7 @@ class LayerTreeHostTestLCDNotification : public LayerTreeHostTest {
// No need to request a commit - setting opacity will do it.
break;
default:
- // Verify that there is not extra commit due to layer invalidation.
+ // Verify that there is no extra commit due to layer invalidation.
EXPECT_EQ(3, layer_tree_host()->source_frame_number());
// LCD notification count should have incremented due to
// change in layer opacity.
@@ -2587,27 +2272,27 @@ class LayerTreeHostTestLCDNotification : public LayerTreeHostTest {
NotificationClient client_;
};
-SINGLE_THREAD_TEST_F(LayerTreeHostTestLCDNotification);
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestLCDNotification);
-// Verify that the BeginImplFrame notification is used to initiate rendering.
-class LayerTreeHostTestBeginImplFrameNotification : public LayerTreeHostTest {
+// Verify that the BeginFrame notification is used to initiate rendering.
+class LayerTreeHostTestBeginFrameNotification : public LayerTreeHostTest {
public:
virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
- settings->begin_impl_frame_scheduling_enabled = true;
+ settings->begin_frame_scheduling_enabled = true;
}
virtual void BeginTest() OVERRIDE {
- // This will trigger a SetNeedsBeginImplFrame which will trigger a
- // BeginImplFrame.
+ // This will trigger a SetNeedsBeginFrame which will trigger a
+ // BeginFrame.
PostSetNeedsCommitToMainThread();
}
- virtual bool PrepareToDrawOnThread(
+ virtual DrawResult PrepareToDrawOnThread(
LayerTreeHostImpl* host_impl,
LayerTreeHostImpl::FrameData* frame,
- bool result) OVERRIDE {
+ DrawResult draw_result) OVERRIDE {
EndTest();
- return true;
+ return DRAW_SUCCESS;
}
virtual void AfterTest() OVERRIDE {}
@@ -2616,24 +2301,24 @@ class LayerTreeHostTestBeginImplFrameNotification : public LayerTreeHostTest {
base::TimeTicks frame_time_;
};
-MULTI_THREAD_TEST_F(LayerTreeHostTestBeginImplFrameNotification);
+MULTI_THREAD_TEST_F(LayerTreeHostTestBeginFrameNotification);
-class LayerTreeHostTestBeginImplFrameNotificationShutdownWhileEnabled
+class LayerTreeHostTestBeginFrameNotificationShutdownWhileEnabled
: public LayerTreeHostTest {
public:
virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
- settings->begin_impl_frame_scheduling_enabled = true;
+ settings->begin_frame_scheduling_enabled = true;
settings->using_synchronous_renderer_compositor = true;
}
virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
- // The BeginImplFrame notification is turned off now but will get enabled
+ // The BeginFrame notification is turned off now but will get enabled
// once we return. End test while it's enabled.
ImplThreadTaskRunner()->PostTask(
FROM_HERE,
- base::Bind(&LayerTreeHostTestBeginImplFrameNotification::EndTest,
+ base::Bind(&LayerTreeHostTestBeginFrameNotification::EndTest,
base::Unretained(this)));
}
@@ -2641,7 +2326,7 @@ class LayerTreeHostTestBeginImplFrameNotificationShutdownWhileEnabled
};
MULTI_THREAD_TEST_F(
- LayerTreeHostTestBeginImplFrameNotificationShutdownWhileEnabled);
+ LayerTreeHostTestBeginFrameNotificationShutdownWhileEnabled);
class LayerTreeHostTestAbortedCommitDoesntStall : public LayerTreeHostTest {
protected:
@@ -2649,7 +2334,7 @@ class LayerTreeHostTestAbortedCommitDoesntStall : public LayerTreeHostTest {
: commit_count_(0), commit_abort_count_(0), commit_complete_count_(0) {}
virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
- settings->begin_impl_frame_scheduling_enabled = true;
+ settings->begin_frame_scheduling_enabled = true;
}
virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
@@ -2664,8 +2349,8 @@ class LayerTreeHostTestAbortedCommitDoesntStall : public LayerTreeHostTest {
}
}
- virtual void BeginMainFrameAbortedOnThread(
- LayerTreeHostImpl *host_impl, bool did_handle) OVERRIDE {
+ virtual void BeginMainFrameAbortedOnThread(LayerTreeHostImpl* host_impl,
+ bool did_handle) OVERRIDE {
commit_abort_count_++;
// Initiate another abortable commit.
host_impl->SetNeedsCommit();
@@ -2729,16 +2414,13 @@ class LayerTreeHostTestUninvertibleTransformDoesNotBlockActivation
layer_tree_host()->root_layer()->AddChild(layer);
}
- virtual void BeginTest() OVERRIDE {
- PostSetNeedsCommitToMainThread();
- }
+ virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
virtual void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
EndTest();
}
- virtual void AfterTest() OVERRIDE {
- }
+ virtual void AfterTest() OVERRIDE {}
FakeContentLayerClient client_;
};
@@ -2755,14 +2437,18 @@ class LayerTreeHostTestChangeLayerPropertiesInPaintContents
void set_layer(Layer* layer) { layer_ = layer; }
- virtual void PaintContents(SkCanvas* canvas,
- gfx::Rect clip,
- gfx::RectF* opaque) OVERRIDE {
+ virtual void PaintContents(
+ SkCanvas* canvas,
+ const gfx::Rect& clip,
+ gfx::RectF* opaque,
+ ContentLayerClient::GraphicsContextStatus gc_status) OVERRIDE {
layer_->SetBounds(gfx::Size(2, 2));
}
virtual void DidChangeLayerCanUseLCDText() OVERRIDE {}
+ virtual bool FillsBoundsCompletely() const OVERRIDE { return false; }
+
private:
Layer* layer_;
};
@@ -2805,44 +2491,48 @@ SINGLE_THREAD_TEST_F(LayerTreeHostTestChangeLayerPropertiesInPaintContents);
class MockIOSurfaceWebGraphicsContext3D : public TestWebGraphicsContext3D {
public:
MockIOSurfaceWebGraphicsContext3D() {
- test_capabilities_.iosurface = true;
- test_capabilities_.texture_rectangle = true;
+ test_capabilities_.gpu.iosurface = true;
+ test_capabilities_.gpu.texture_rectangle = true;
}
- virtual blink::WebGLId createTexture() OVERRIDE {
+ virtual GLuint createTexture() OVERRIDE {
return 1;
}
-
- MOCK_METHOD1(activeTexture, void(blink::WGC3Denum texture));
- MOCK_METHOD2(bindTexture, void(blink::WGC3Denum target,
- blink::WebGLId texture_id));
- MOCK_METHOD3(texParameteri, void(blink::WGC3Denum target,
- blink::WGC3Denum pname,
- blink::WGC3Dint param));
- MOCK_METHOD5(texImageIOSurface2DCHROMIUM, void(blink::WGC3Denum target,
- blink::WGC3Dint width,
- blink::WGC3Dint height,
- blink::WGC3Duint ioSurfaceId,
- blink::WGC3Duint plane));
- MOCK_METHOD4(drawElements, void(blink::WGC3Denum mode,
- blink::WGC3Dsizei count,
- blink::WGC3Denum type,
- blink::WGC3Dintptr offset));
- MOCK_METHOD1(deleteTexture, void(blink::WGC3Denum texture));
+ MOCK_METHOD1(activeTexture, void(GLenum texture));
+ MOCK_METHOD2(bindTexture, void(GLenum target,
+ GLuint texture_id));
+ MOCK_METHOD3(texParameteri, void(GLenum target,
+ GLenum pname,
+ GLint param));
+ MOCK_METHOD5(texImageIOSurface2DCHROMIUM, void(GLenum target,
+ GLint width,
+ GLint height,
+ GLuint ioSurfaceId,
+ GLuint plane));
+ MOCK_METHOD4(drawElements, void(GLenum mode,
+ GLsizei count,
+ GLenum type,
+ GLintptr offset));
+ MOCK_METHOD1(deleteTexture, void(GLenum texture));
+ MOCK_METHOD2(produceTextureCHROMIUM,
+ void(GLenum target, const GLbyte* mailbox));
};
-
class LayerTreeHostTestIOSurfaceDrawing : public LayerTreeHostTest {
protected:
- virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback)
+ virtual scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(bool fallback)
OVERRIDE {
scoped_ptr<MockIOSurfaceWebGraphicsContext3D> mock_context_owned(
new MockIOSurfaceWebGraphicsContext3D);
mock_context_ = mock_context_owned.get();
- scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
- mock_context_owned.PassAs<TestWebGraphicsContext3D>()));
- return output_surface.Pass();
+ if (delegating_renderer()) {
+ return FakeOutputSurface::CreateDelegating3d(
+ mock_context_owned.PassAs<TestWebGraphicsContext3D>());
+ } else {
+ return FakeOutputSurface::Create3d(
+ mock_context_owned.PassAs<TestWebGraphicsContext3D>());
+ }
}
virtual void SetupTree() OVERRIDE {
@@ -2855,73 +2545,91 @@ class LayerTreeHostTestIOSurfaceDrawing : public LayerTreeHostTest {
scoped_refptr<IOSurfaceLayer> io_surface_layer = IOSurfaceLayer::Create();
io_surface_layer->SetBounds(gfx::Size(10, 10));
- io_surface_layer->SetAnchorPoint(gfx::PointF());
io_surface_layer->SetIsDrawable(true);
+ io_surface_layer->SetContentsOpaque(true);
io_surface_layer->SetIOSurfaceProperties(io_surface_id_, io_surface_size_);
layer_tree_host()->root_layer()->AddChild(io_surface_layer);
}
- virtual void BeginTest() OVERRIDE {
- PostSetNeedsCommitToMainThread();
- }
+ virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
virtual void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
+ EXPECT_EQ(0u, host_impl->resource_provider()->num_resources());
// In WillDraw, the IOSurfaceLayer sets up the io surface texture.
- EXPECT_CALL(*mock_context_, activeTexture(_))
- .Times(0);
+ EXPECT_CALL(*mock_context_, activeTexture(_)).Times(0);
EXPECT_CALL(*mock_context_, bindTexture(GL_TEXTURE_RECTANGLE_ARB, 1))
.Times(AtLeast(1));
- EXPECT_CALL(*mock_context_, texParameteri(GL_TEXTURE_RECTANGLE_ARB,
- GL_TEXTURE_MIN_FILTER,
- GL_LINEAR))
- .Times(1);
- EXPECT_CALL(*mock_context_, texParameteri(GL_TEXTURE_RECTANGLE_ARB,
- GL_TEXTURE_MAG_FILTER,
- GL_LINEAR))
+ EXPECT_CALL(*mock_context_,
+ texParameteri(
+ GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR))
.Times(1);
- EXPECT_CALL(*mock_context_, texParameteri(GL_TEXTURE_RECTANGLE_ARB,
- GL_TEXTURE_WRAP_S,
- GL_CLAMP_TO_EDGE))
- .Times(1);
- EXPECT_CALL(*mock_context_, texParameteri(GL_TEXTURE_RECTANGLE_ARB,
- GL_TEXTURE_WRAP_T,
- GL_CLAMP_TO_EDGE))
- .Times(1);
-
- EXPECT_CALL(*mock_context_, texImageIOSurface2DCHROMIUM(
- GL_TEXTURE_RECTANGLE_ARB,
- io_surface_size_.width(),
- io_surface_size_.height(),
- io_surface_id_,
- 0))
+ EXPECT_CALL(*mock_context_,
+ texParameteri(
+ GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR))
.Times(1);
-
- EXPECT_CALL(*mock_context_, bindTexture(_, 0))
- .Times(AnyNumber());
- }
-
- virtual bool PrepareToDrawOnThread(
+ EXPECT_CALL(*mock_context_,
+ texParameteri(GL_TEXTURE_RECTANGLE_ARB,
+ GL_TEXTURE_POOL_CHROMIUM,
+ GL_TEXTURE_POOL_UNMANAGED_CHROMIUM)).Times(1);
+ EXPECT_CALL(*mock_context_,
+ texParameteri(GL_TEXTURE_RECTANGLE_ARB,
+ GL_TEXTURE_WRAP_S,
+ GL_CLAMP_TO_EDGE)).Times(1);
+ EXPECT_CALL(*mock_context_,
+ texParameteri(GL_TEXTURE_RECTANGLE_ARB,
+ GL_TEXTURE_WRAP_T,
+ GL_CLAMP_TO_EDGE)).Times(1);
+
+ EXPECT_CALL(*mock_context_,
+ texImageIOSurface2DCHROMIUM(GL_TEXTURE_RECTANGLE_ARB,
+ io_surface_size_.width(),
+ io_surface_size_.height(),
+ io_surface_id_,
+ 0)).Times(1);
+
+ EXPECT_CALL(*mock_context_, bindTexture(_, 0)).Times(AnyNumber());
+ }
+
+ virtual DrawResult PrepareToDrawOnThread(
LayerTreeHostImpl* host_impl,
LayerTreeHostImpl::FrameData* frame,
- bool result) OVERRIDE {
+ DrawResult draw_result) OVERRIDE {
Mock::VerifyAndClearExpectations(&mock_context_);
+ ResourceProvider* resource_provider = host_impl->resource_provider();
+ EXPECT_EQ(1u, resource_provider->num_resources());
+ CHECK_EQ(1u, frame->render_passes.size());
+ CHECK_LE(1u, frame->render_passes[0]->quad_list.size());
+ const DrawQuad* quad = frame->render_passes[0]->quad_list[0];
+ CHECK_EQ(DrawQuad::IO_SURFACE_CONTENT, quad->material);
+ const IOSurfaceDrawQuad* io_surface_draw_quad =
+ IOSurfaceDrawQuad::MaterialCast(quad);
+ EXPECT_SIZE_EQ(io_surface_size_, io_surface_draw_quad->io_surface_size);
+ EXPECT_NE(0u, io_surface_draw_quad->io_surface_resource_id);
+ EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_RECTANGLE_ARB),
+ resource_provider->TargetForTesting(
+ io_surface_draw_quad->io_surface_resource_id));
- // The io surface layer's texture is drawn.
- EXPECT_CALL(*mock_context_, activeTexture(GL_TEXTURE0))
- .Times(AtLeast(1));
EXPECT_CALL(*mock_context_, bindTexture(GL_TEXTURE_RECTANGLE_ARB, 1))
.Times(1);
- EXPECT_CALL(*mock_context_, drawElements(GL_TRIANGLES, 6, _, _))
- .Times(AtLeast(1));
+ if (delegating_renderer()) {
+ // The io surface layer's resource should be sent to the parent.
+ EXPECT_CALL(*mock_context_,
+ produceTextureCHROMIUM(GL_TEXTURE_RECTANGLE_ARB, _)).Times(1);
+ } else {
+ // The io surface layer's texture is drawn.
+ EXPECT_CALL(*mock_context_, activeTexture(GL_TEXTURE0)).Times(AtLeast(1));
+ EXPECT_CALL(*mock_context_, drawElements(GL_TRIANGLES, 6, _, _))
+ .Times(AtLeast(1));
+ }
- return result;
+ return draw_result;
}
virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
Mock::VerifyAndClearExpectations(&mock_context_);
- EXPECT_CALL(*mock_context_, deleteTexture(1)).Times(1);
+ EXPECT_CALL(*mock_context_, deleteTexture(1)).Times(AtLeast(1));
EndTest();
}
@@ -2932,9 +2640,7 @@ class LayerTreeHostTestIOSurfaceDrawing : public LayerTreeHostTest {
gfx::Size io_surface_size_;
};
-// TODO(danakj): IOSurface layer can not be transported. crbug.com/239335
-SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(
- LayerTreeHostTestIOSurfaceDrawing);
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestIOSurfaceDrawing);
class LayerTreeHostTestNumFramesPending : public LayerTreeHostTest {
public:
@@ -2946,8 +2652,6 @@ class LayerTreeHostTestNumFramesPending : public LayerTreeHostTest {
// Round 1: commit + draw
// Round 2: commit only (no draw/swap)
// Round 3: draw only (no commit)
- // Round 4: composite & readback (2 commits, no draw/swap)
- // Round 5: commit + draw
virtual void DidCommit() OVERRIDE {
int commit = layer_tree_host()->source_frame_number();
@@ -2957,23 +2661,12 @@ class LayerTreeHostTestNumFramesPending : public LayerTreeHostTest {
EXPECT_EQ(1, frame_);
layer_tree_host()->SetNeedsRedraw();
break;
- case 3:
- // CompositeAndReadback in Round 4, first commit.
- EXPECT_EQ(2, frame_);
- break;
- case 4:
- // Round 4 done.
- EXPECT_EQ(2, frame_);
- layer_tree_host()->SetNeedsCommit();
- layer_tree_host()->SetNeedsRedraw();
- break;
}
}
virtual void DidCompleteSwapBuffers() OVERRIDE {
int commit = layer_tree_host()->source_frame_number();
++frame_;
- char pixels[4] = {0};
switch (frame_) {
case 1:
// Round 1 done.
@@ -2983,11 +2676,6 @@ class LayerTreeHostTestNumFramesPending : public LayerTreeHostTest {
case 2:
// Round 3 done.
EXPECT_EQ(2, commit);
- layer_tree_host()->CompositeAndReadback(pixels, gfx::Rect(0, 0, 1, 1));
- break;
- case 3:
- // Round 5 done.
- EXPECT_EQ(5, commit);
EndTest();
break;
}
@@ -2999,11 +2687,12 @@ class LayerTreeHostTestNumFramesPending : public LayerTreeHostTest {
int frame_;
};
-TEST_F(LayerTreeHostTestNumFramesPending, DelegatingRenderer) {
+// Flaky on all platforms: http://crbug.com/327498
+TEST_F(LayerTreeHostTestNumFramesPending, DISABLED_DelegatingRenderer) {
RunTest(true, true, true);
}
-TEST_F(LayerTreeHostTestNumFramesPending, GLRenderer) {
+TEST_F(LayerTreeHostTestNumFramesPending, DISABLED_GLRenderer) {
RunTest(true, false, true);
}
@@ -3030,14 +2719,14 @@ class LayerTreeHostTestDeferredInitialize : public LayerTreeHostTest {
PostSetNeedsCommitToMainThread();
}
- virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback)
+ virtual scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(bool fallback)
OVERRIDE {
scoped_ptr<TestWebGraphicsContext3D> context3d(
TestWebGraphicsContext3D::Create());
return FakeOutputSurface::CreateDeferredGL(
- scoped_ptr<SoftwareOutputDevice>(new SoftwareOutputDevice))
- .PassAs<OutputSurface>();
+ scoped_ptr<SoftwareOutputDevice>(new SoftwareOutputDevice),
+ delegating_renderer());
}
virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
@@ -3067,10 +2756,9 @@ class LayerTreeHostTestDeferredInitialize : public LayerTreeHostTest {
EXPECT_LE(2u, layer_impl->append_quads_count());
ImplThreadTaskRunner()->PostTask(
FROM_HERE,
- base::Bind(
- &LayerTreeHostTestDeferredInitialize::ReleaseGLAndRedraw,
- base::Unretained(this),
- base::Unretained(host_impl)));
+ base::Bind(&LayerTreeHostTestDeferredInitialize::ReleaseGLAndRedraw,
+ base::Unretained(this),
+ base::Unretained(host_impl)));
} else if (did_initialize_gl_ && did_release_gl_) {
EXPECT_LE(3u, layer_impl->append_quads_count());
EndTest();
@@ -3084,8 +2772,8 @@ class LayerTreeHostTestDeferredInitialize : public LayerTreeHostTest {
static_cast<FakeOutputSurface*>(host_impl->output_surface());
scoped_refptr<TestContextProvider> context_provider =
TestContextProvider::Create(); // Not bound to thread.
- EXPECT_TRUE(fake_output_surface->InitializeAndSetContext3d(
- context_provider, NULL));
+ EXPECT_TRUE(
+ fake_output_surface->InitializeAndSetContext3d(context_provider));
did_initialize_gl_ = true;
}
@@ -3097,6 +2785,24 @@ class LayerTreeHostTestDeferredInitialize : public LayerTreeHostTest {
did_release_gl_ = true;
}
+ virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl,
+ bool result) OVERRIDE {
+ ASSERT_TRUE(result);
+ DelegatedFrameData* delegated_frame_data =
+ output_surface()->last_sent_frame().delegated_frame_data.get();
+ if (!delegated_frame_data)
+ return;
+
+ // Return all resources immediately.
+ TransferableResourceArray resources_to_return =
+ output_surface()->resources_held_by_parent();
+
+ CompositorFrameAck ack;
+ for (size_t i = 0; i < resources_to_return.size(); ++i)
+ output_surface()->ReturnResource(resources_to_return[i].id, &ack);
+ host_impl->ReclaimResources(&ack);
+ }
+
virtual void AfterTest() OVERRIDE {
EXPECT_TRUE(did_initialize_gl_);
EXPECT_TRUE(did_release_gl_);
@@ -3115,7 +2821,7 @@ MULTI_THREAD_TEST_F(LayerTreeHostTestDeferredInitialize);
// Test for UI Resource management.
class LayerTreeHostTestUIResource : public LayerTreeHostTest {
public:
- LayerTreeHostTestUIResource() : num_ui_resources_(0), num_commits_(0) {}
+ LayerTreeHostTestUIResource() : num_ui_resources_(0) {}
virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
settings->texture_id_allocation_chunk_size = 1;
@@ -3124,7 +2830,7 @@ class LayerTreeHostTestUIResource : public LayerTreeHostTest {
virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
virtual void DidCommit() OVERRIDE {
- int frame = num_commits_;
+ int frame = layer_tree_host()->source_frame_number();
switch (frame) {
case 1:
CreateResource();
@@ -3156,28 +2862,27 @@ class LayerTreeHostTestUIResource : public LayerTreeHostTest {
}
void PerformTest(LayerTreeHostImpl* impl) {
- TestWebGraphicsContext3D* context = static_cast<TestWebGraphicsContext3D*>(
- impl->output_surface()->context_provider()->Context3d());
+ TestWebGraphicsContext3D* context = TestContext();
- int frame = num_commits_;
+ int frame = impl->active_tree()->source_frame_number();
switch (frame) {
- case 1:
+ case 0:
ASSERT_EQ(0u, context->NumTextures());
break;
- case 2:
+ case 1:
// Created two textures.
ASSERT_EQ(2u, context->NumTextures());
break;
- case 3:
+ case 2:
// One texture left after one deletion.
ASSERT_EQ(1u, context->NumTextures());
break;
- case 4:
+ case 3:
// Resource manager state should not change when delete is called on an
// invalid id.
ASSERT_EQ(1u, context->NumTextures());
break;
- case 5:
+ case 4:
// Creation after deletion: two more creates should total up to
// three textures.
ASSERT_EQ(3u, context->NumTextures());
@@ -3186,7 +2891,6 @@ class LayerTreeHostTestUIResource : public LayerTreeHostTest {
}
virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
- ++num_commits_;
if (!layer_tree_host()->settings().impl_side_painting)
PerformTest(impl);
}
@@ -3212,11 +2916,46 @@ class LayerTreeHostTestUIResource : public LayerTreeHostTest {
scoped_ptr<FakeScopedUIResource> ui_resources_[5];
int num_ui_resources_;
- int num_commits_;
};
MULTI_THREAD_TEST_F(LayerTreeHostTestUIResource);
+class PushPropertiesCountingLayerImpl : public LayerImpl {
+ public:
+ static scoped_ptr<PushPropertiesCountingLayerImpl> Create(
+ LayerTreeImpl* tree_impl, int id) {
+ return make_scoped_ptr(new PushPropertiesCountingLayerImpl(tree_impl, id));
+ }
+
+ virtual ~PushPropertiesCountingLayerImpl() {}
+
+ virtual void PushPropertiesTo(LayerImpl* layer) OVERRIDE {
+ LayerImpl::PushPropertiesTo(layer);
+ push_properties_count_++;
+ // Push state to the active tree because we can only access it from there.
+ static_cast<PushPropertiesCountingLayerImpl*>(
+ layer)->push_properties_count_ = push_properties_count_;
+ }
+
+ virtual scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl)
+ OVERRIDE {
+ return PushPropertiesCountingLayerImpl::Create(tree_impl, id()).
+ PassAs<LayerImpl>();
+ }
+
+ size_t push_properties_count() const { return push_properties_count_; }
+ void reset_push_properties_count() { push_properties_count_ = 0; }
+
+ private:
+ size_t push_properties_count_;
+
+ PushPropertiesCountingLayerImpl(LayerTreeImpl* tree_impl, int id)
+ : LayerImpl(tree_impl, id),
+ push_properties_count_(0) {
+ SetBounds(gfx::Size(1, 1));
+ }
+};
+
class PushPropertiesCountingLayer : public Layer {
public:
static scoped_refptr<PushPropertiesCountingLayer> Create() {
@@ -3230,6 +2969,12 @@ class PushPropertiesCountingLayer : public Layer {
needs_push_properties_ = true;
}
+ virtual scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl)
+ OVERRIDE {
+ return PushPropertiesCountingLayerImpl::Create(tree_impl, id()).
+ PassAs<LayerImpl>();
+ }
+
size_t push_properties_count() const { return push_properties_count_; }
void reset_push_properties_count() { push_properties_count_ = 0; }
@@ -3239,9 +2984,7 @@ class PushPropertiesCountingLayer : public Layer {
private:
PushPropertiesCountingLayer()
- : push_properties_count_(0),
- persist_needs_push_properties_(false) {
- SetAnchorPoint(gfx::PointF());
+ : push_properties_count_(0), persist_needs_push_properties_(false) {
SetBounds(gfx::Size(1, 1));
SetIsDrawable(true);
}
@@ -3443,13 +3186,211 @@ class LayerTreeHostTestLayersPushProperties : public LayerTreeHostTest {
MULTI_THREAD_TEST_F(LayerTreeHostTestLayersPushProperties);
-class LayerTreeHostTestPropertyChangesDuringUpdateArePushed
- : public LayerTreeHostTest {
+class LayerTreeHostTestImplLayersPushProperties
+ : public LayerTreeHostTestLayersPushProperties {
protected:
virtual void BeginTest() OVERRIDE {
- PostSetNeedsCommitToMainThread();
+ expected_push_properties_root_impl_ = 0;
+ expected_push_properties_child_impl_ = 0;
+ expected_push_properties_grandchild_impl_ = 0;
+ expected_push_properties_child2_impl_ = 0;
+ expected_push_properties_grandchild2_impl_ = 0;
+ LayerTreeHostTestLayersPushProperties::BeginTest();
}
+ virtual void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
+ // These commits are in response to the changes made in
+ // LayerTreeHostTestLayersPushProperties::DidCommitAndDrawFrame()
+ switch (num_commits_) {
+ case 0:
+ // Tree hasn't been setup yet don't bother to check anything.
+ return;
+ case 1:
+ // Root gets set up, Everyone is initialized.
+ ++expected_push_properties_root_impl_;
+ ++expected_push_properties_child_impl_;
+ ++expected_push_properties_grandchild_impl_;
+ ++expected_push_properties_child2_impl_;
+ ++expected_push_properties_grandchild2_impl_;
+ break;
+ case 2:
+ // Tree doesn't change but the one leaf that always pushes is pushed.
+ ++expected_push_properties_grandchild2_impl_;
+ break;
+ case 3:
+ // Root is swapped here.
+ // Clear the expected push properties the tree will be rebuilt.
+ expected_push_properties_root_impl_ = 0;
+ expected_push_properties_child_impl_ = 0;
+ expected_push_properties_grandchild_impl_ = 0;
+ expected_push_properties_child2_impl_ = 0;
+ expected_push_properties_grandchild2_impl_ = 0;
+
+ // Make sure the new root is pushed.
+ EXPECT_EQ(1u, static_cast<PushPropertiesCountingLayerImpl*>(
+ host_impl->RootLayer())->push_properties_count());
+ return;
+ case 4:
+ // Root is swapped back all of the layers in the tree get pushed.
+ ++expected_push_properties_root_impl_;
+ ++expected_push_properties_child_impl_;
+ ++expected_push_properties_grandchild_impl_;
+ ++expected_push_properties_child2_impl_;
+ ++expected_push_properties_grandchild2_impl_;
+ break;
+ case 5:
+ // Tree doesn't change but the one leaf that always pushes is pushed.
+ ++expected_push_properties_grandchild2_impl_;
+ break;
+ case 6:
+ // First child is removed. Structure of the tree changes here so swap
+ // some of the values. child_impl becomes child2_impl.
+ expected_push_properties_child_impl_ =
+ expected_push_properties_child2_impl_;
+ expected_push_properties_child2_impl_ = 0;
+ // grandchild_impl becomes grandchild2_impl.
+ expected_push_properties_grandchild_impl_ =
+ expected_push_properties_grandchild2_impl_;
+ expected_push_properties_grandchild2_impl_ = 0;
+
+ // grandchild_impl is now the leaf that always pushes. It is pushed.
+ ++expected_push_properties_grandchild_impl_;
+ break;
+ case 7:
+ // The leaf that always pushes is pushed.
+ ++expected_push_properties_grandchild_impl_;
+
+ // Child is added back. New layers are initialized.
+ ++expected_push_properties_grandchild2_impl_;
+ ++expected_push_properties_child2_impl_;
+ break;
+ case 8:
+ // Leaf is removed.
+ expected_push_properties_grandchild2_impl_ = 0;
+
+ // Always pushing.
+ ++expected_push_properties_grandchild_impl_;
+ break;
+ case 9:
+ // Leaf is added back
+ ++expected_push_properties_grandchild2_impl_;
+
+ // The leaf that always pushes is pushed.
+ ++expected_push_properties_grandchild_impl_;
+ break;
+ case 10:
+ // The leaf that always pushes is pushed.
+ ++expected_push_properties_grandchild_impl_;
+ break;
+ case 11:
+ // The leaf that always pushes is pushed.
+ ++expected_push_properties_grandchild_impl_;
+ break;
+ case 12:
+ // The leaf that always pushes is pushed.
+ ++expected_push_properties_grandchild_impl_;
+
+ // This child position was changed.
+ ++expected_push_properties_child2_impl_;
+ break;
+ case 13:
+ // The position of this child was changed.
+ ++expected_push_properties_child_impl_;
+
+ // The leaf that always pushes is pushed.
+ ++expected_push_properties_grandchild_impl_;
+ break;
+ case 14:
+ // Second child is removed from tree. Don't discard counts because
+ // they are added back before commit.
+
+ // The leaf that always pushes is pushed.
+ ++expected_push_properties_grandchild_impl_;
+
+ // Second child added back.
+ ++expected_push_properties_child2_impl_;
+ ++expected_push_properties_grandchild2_impl_;
+
+ break;
+ case 15:
+ // The position of this child was changed.
+ ++expected_push_properties_grandchild2_impl_;
+
+ // The leaf that always pushes is pushed.
+ ++expected_push_properties_grandchild_impl_;
+ break;
+ case 16:
+ // Second child is invalidated with SetNeedsDisplay
+ ++expected_push_properties_child2_impl_;
+
+ // The leaf that always pushed is pushed.
+ ++expected_push_properties_grandchild_impl_;
+ break;
+ }
+
+ PushPropertiesCountingLayerImpl* root_impl_ = NULL;
+ PushPropertiesCountingLayerImpl* child_impl_ = NULL;
+ PushPropertiesCountingLayerImpl* child2_impl_ = NULL;
+ PushPropertiesCountingLayerImpl* grandchild_impl_ = NULL;
+ PushPropertiesCountingLayerImpl* leaf_always_pushing_layer_impl_ = NULL;
+
+ // Pull the layers that we need from the tree assuming the same structure
+ // as LayerTreeHostTestLayersPushProperties
+ root_impl_ = static_cast<PushPropertiesCountingLayerImpl*>(
+ host_impl->RootLayer());
+
+ if (root_impl_ && root_impl_->children().size() > 0) {
+ child_impl_ = static_cast<PushPropertiesCountingLayerImpl*>(
+ root_impl_->children()[0]);
+
+ if (child_impl_ && child_impl_->children().size() > 0)
+ grandchild_impl_ = static_cast<PushPropertiesCountingLayerImpl*>(
+ child_impl_->children()[0]);
+ }
+
+ if (root_impl_ && root_impl_->children().size() > 1) {
+ child2_impl_ = static_cast<PushPropertiesCountingLayerImpl*>(
+ root_impl_->children()[1]);
+
+ if (child2_impl_ && child2_impl_->children().size() > 0)
+ leaf_always_pushing_layer_impl_ =
+ static_cast<PushPropertiesCountingLayerImpl*>(
+ child2_impl_->children()[0]);
+ }
+
+ if (root_impl_)
+ EXPECT_EQ(expected_push_properties_root_impl_,
+ root_impl_->push_properties_count());
+ if (child_impl_)
+ EXPECT_EQ(expected_push_properties_child_impl_,
+ child_impl_->push_properties_count());
+ if (grandchild_impl_)
+ EXPECT_EQ(expected_push_properties_grandchild_impl_,
+ grandchild_impl_->push_properties_count());
+ if (child2_impl_)
+ EXPECT_EQ(expected_push_properties_child2_impl_,
+ child2_impl_->push_properties_count());
+ if (leaf_always_pushing_layer_impl_)
+ EXPECT_EQ(expected_push_properties_grandchild2_impl_,
+ leaf_always_pushing_layer_impl_->push_properties_count());
+ }
+
+ size_t expected_push_properties_root_impl_;
+ size_t expected_push_properties_child_impl_;
+ size_t expected_push_properties_child2_impl_;
+ size_t expected_push_properties_grandchild_impl_;
+ size_t expected_push_properties_grandchild2_impl_;
+};
+
+TEST_F(LayerTreeHostTestImplLayersPushProperties, DelegatingRenderer) {
+ RunTestWithImplSidePainting();
+}
+
+class LayerTreeHostTestPropertyChangesDuringUpdateArePushed
+ : public LayerTreeHostTest {
+ protected:
+ virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
+
virtual void SetupTree() OVERRIDE {
root_ = Layer::Create();
root_->SetBounds(gfx::Size(1, 1));
@@ -3923,9 +3864,10 @@ class LayerTreeHostTestTreeActivationCallback : public LayerTreeHostTest {
PostSetNeedsCommitToMainThread();
}
- virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
- LayerTreeHostImpl::FrameData* frame_data,
- bool result) OVERRIDE {
+ virtual DrawResult PrepareToDrawOnThread(
+ LayerTreeHostImpl* host_impl,
+ LayerTreeHostImpl::FrameData* frame_data,
+ DrawResult draw_result) OVERRIDE {
++num_commits_;
switch (num_commits_) {
case 1:
@@ -3950,24 +3892,22 @@ class LayerTreeHostTestTreeActivationCallback : public LayerTreeHostTest {
EndTest();
break;
}
- return LayerTreeHostTest::PrepareToDrawOnThread(host_impl, frame_data,
- result);
+ return LayerTreeHostTest::PrepareToDrawOnThread(
+ host_impl, frame_data, draw_result);
}
- virtual void AfterTest() OVERRIDE {
- EXPECT_EQ(3, num_commits_);
- }
+ virtual void AfterTest() OVERRIDE { EXPECT_EQ(3, num_commits_); }
void SetCallback(bool enable) {
- output_surface()->SetTreeActivationCallback(enable ?
- base::Bind(&LayerTreeHostTestTreeActivationCallback::ActivationCallback,
- base::Unretained(this)) :
- base::Closure());
+ output_surface()->SetTreeActivationCallback(
+ enable
+ ? base::Bind(
+ &LayerTreeHostTestTreeActivationCallback::ActivationCallback,
+ base::Unretained(this))
+ : base::Closure());
}
- void ActivationCallback() {
- ++callback_count_;
- }
+ void ActivationCallback() { ++callback_count_; }
int num_commits_;
int callback_count_;
@@ -3996,7 +3936,7 @@ class LayerInvalidateCausesDraw : public LayerTreeHostTest {
virtual void DidCommitAndDrawFrame() OVERRIDE {
// After commit, invalidate the layer. This should cause a commit.
if (layer_tree_host()->source_frame_number() == 1)
- invalidate_layer_->SetNeedsDisplay();
+ invalidate_layer_->SetNeedsDisplay();
}
virtual void DrawLayersOnThread(LayerTreeHostImpl* impl) OVERRIDE {
@@ -4070,19 +4010,16 @@ class LayerTreeHostTestPushHiddenLayer : public LayerTreeHostTest {
protected:
virtual void SetupTree() OVERRIDE {
root_layer_ = Layer::Create();
- root_layer_->SetAnchorPoint(gfx::PointF());
root_layer_->SetPosition(gfx::Point());
root_layer_->SetBounds(gfx::Size(10, 10));
parent_layer_ = SolidColorLayer::Create();
- parent_layer_->SetAnchorPoint(gfx::PointF());
parent_layer_->SetPosition(gfx::Point());
parent_layer_->SetBounds(gfx::Size(10, 10));
parent_layer_->SetIsDrawable(true);
root_layer_->AddChild(parent_layer_);
child_layer_ = SolidColorLayer::Create();
- child_layer_->SetAnchorPoint(gfx::PointF());
child_layer_->SetPosition(gfx::Point());
child_layer_->SetBounds(gfx::Size(10, 10));
child_layer_->SetIsDrawable(true);
@@ -4143,7 +4080,6 @@ class LayerTreeHostTestUpdateLayerInEmptyViewport : public LayerTreeHostTest {
virtual void SetupTree() OVERRIDE {
root_layer_ = FakePictureLayer::Create(&client_);
- root_layer_->SetAnchorPoint(gfx::PointF());
root_layer_->SetBounds(gfx::Size(10, 10));
layer_tree_host()->SetRootLayer(root_layer_);
@@ -4237,16 +4173,17 @@ class LayerTreeHostTestMaxTransferBufferUsageBytes : public LayerTreeHostTest {
protected:
virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
settings->impl_side_painting = true;
- settings->default_tile_size = gfx::Size(128, 128);
}
- virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback)
+ virtual scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(bool fallback)
OVERRIDE {
scoped_refptr<TestContextProvider> context_provider =
TestContextProvider::Create();
context_provider->SetMaxTransferBufferUsageBytes(1024 * 1024);
- return FakeOutputSurface::Create3d(context_provider)
- .PassAs<OutputSurface>();
+ if (delegating_renderer())
+ return FakeOutputSurface::CreateDelegating3d(context_provider);
+ else
+ return FakeOutputSurface::Create3d(context_provider);
}
virtual void SetupTree() OVERRIDE {
@@ -4259,21 +4196,14 @@ class LayerTreeHostTestMaxTransferBufferUsageBytes : public LayerTreeHostTest {
LayerTreeHostTest::SetupTree();
}
- virtual void BeginTest() OVERRIDE {
- PostSetNeedsCommitToMainThread();
- }
+ virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
virtual void DidActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
- TestWebGraphicsContext3D* context = static_cast<TestWebGraphicsContext3D*>(
- impl->output_surface()->context_provider()->Context3d());
+ TestWebGraphicsContext3D* context = TestContext();
// Expect that the transfer buffer memory used is equal to the
// MaxTransferBufferUsageBytes value set in CreateOutputSurface.
- // NOTE: This is now 1/2 due to raster memory limit in TileManager.
- // Only half the limit will be reached unless the task set
- // thrashes to a completly new set of tiles.
- EXPECT_EQ(512 * 1024u,
- context->GetPeakTransferBufferMemoryUsedBytes());
+ EXPECT_EQ(1024 * 1024u, context->max_used_transfer_buffer_usage_bytes());
EndTest();
}
@@ -4294,75 +4224,76 @@ class LayerTreeHostTestMemoryLimits : public LayerTreeHostTest {
virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
+ virtual void WillCommit() OVERRIDE {
+ // Some commits are aborted, so increment number of attempted commits here.
+ num_commits_++;
+ }
+
virtual void DidCommit() OVERRIDE {
- int frame = num_commits_;
- switch (frame) {
- case 0:
+ switch (num_commits_) {
+ case 1:
// Verify default values.
- EXPECT_EQ(
- PrioritizedResourceManager::DefaultMemoryAllocationLimit(),
- layer_tree_host()->contents_texture_manager()->
- MaxMemoryLimitBytes());
- EXPECT_EQ(
- PriorityCalculator::AllowEverythingCutoff(),
- layer_tree_host()->contents_texture_manager()->
- ExternalPriorityCutoff());
+ EXPECT_EQ(PrioritizedResourceManager::DefaultMemoryAllocationLimit(),
+ layer_tree_host()
+ ->contents_texture_manager()
+ ->MaxMemoryLimitBytes());
+ EXPECT_EQ(PriorityCalculator::AllowEverythingCutoff(),
+ layer_tree_host()
+ ->contents_texture_manager()
+ ->ExternalPriorityCutoff());
PostSetNeedsCommitToMainThread();
break;
- case 1:
+ case 2:
// The values should remain the same until the commit after the policy
// is changed.
- EXPECT_EQ(
- PrioritizedResourceManager::DefaultMemoryAllocationLimit(),
- layer_tree_host()->contents_texture_manager()->
- MaxMemoryLimitBytes());
- EXPECT_EQ(
- PriorityCalculator::AllowEverythingCutoff(),
- layer_tree_host()->contents_texture_manager()->
- ExternalPriorityCutoff());
+ EXPECT_EQ(PrioritizedResourceManager::DefaultMemoryAllocationLimit(),
+ layer_tree_host()
+ ->contents_texture_manager()
+ ->MaxMemoryLimitBytes());
+ EXPECT_EQ(PriorityCalculator::AllowEverythingCutoff(),
+ layer_tree_host()
+ ->contents_texture_manager()
+ ->ExternalPriorityCutoff());
break;
- case 2:
+ case 3:
// Verify values were correctly passed.
- EXPECT_EQ(
- 16u*1024u*1024u,
- layer_tree_host()->contents_texture_manager()->
- MaxMemoryLimitBytes());
- EXPECT_EQ(
- PriorityCalculator::AllowVisibleAndNearbyCutoff(),
- layer_tree_host()->contents_texture_manager()->
- ExternalPriorityCutoff());
+ EXPECT_EQ(16u * 1024u * 1024u,
+ layer_tree_host()
+ ->contents_texture_manager()
+ ->MaxMemoryLimitBytes());
+ EXPECT_EQ(PriorityCalculator::AllowVisibleAndNearbyCutoff(),
+ layer_tree_host()
+ ->contents_texture_manager()
+ ->ExternalPriorityCutoff());
EndTest();
break;
- case 3:
+ case 4:
// Make sure no extra commits happen.
NOTREACHED();
break;
}
-
- ++num_commits_;
}
virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
- int frame = num_commits_;
- switch (frame) {
- case 0:
- break;
+ switch (num_commits_) {
case 1:
+ break;
+ case 2:
// This will trigger a commit because the priority cutoff has changed.
impl->SetMemoryPolicy(ManagedMemoryPolicy(
- 16u*1024u*1024u,
+ 16u * 1024u * 1024u,
gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE,
1000));
break;
- case 2:
+ case 3:
// This will not trigger a commit because the priority cutoff has not
// changed, and there is already enough memory for all allocations.
impl->SetMemoryPolicy(ManagedMemoryPolicy(
- 32u*1024u*1024u,
+ 32u * 1024u * 1024u,
gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE,
1000));
break;
- case 3:
+ case 4:
NOTREACHED();
break;
}
@@ -4376,113 +4307,6 @@ class LayerTreeHostTestMemoryLimits : public LayerTreeHostTest {
SINGLE_AND_MULTI_THREAD_NOIMPL_TEST_F(LayerTreeHostTestMemoryLimits);
-class LayerSetsNeedsFilterContext : public Layer {
- public:
- static scoped_refptr<LayerSetsNeedsFilterContext> Create() {
- return make_scoped_refptr(new LayerSetsNeedsFilterContext());
- }
-
- virtual bool Update(ResourceUpdateQueue* queue,
- const OcclusionTracker* occlusion) OVERRIDE {
- bool updated = Layer::Update(queue, occlusion);
- if (needs_context_) {
- layer_tree_host()->set_needs_filter_context();
- return true;
- }
- return updated;
- }
-
- void set_needs_context(bool need) { needs_context_ = need; }
-
- private:
- LayerSetsNeedsFilterContext() : needs_context_(false) {}
- virtual ~LayerSetsNeedsFilterContext() {}
-
- bool needs_context_;
-};
-
-class LayerTreeHostTestOffscreenContext : public LayerTreeHostTest {
- protected:
- virtual void SetupTree() OVERRIDE {
- scoped_refptr<LayerSetsNeedsFilterContext> root =
- LayerSetsNeedsFilterContext::Create();
- root->SetIsDrawable(true);
- root->SetAnchorPoint(gfx::PointF());
- root->SetBounds(gfx::Size(10, 10));
- root->set_needs_context(with_context_);
- layer_tree_host()->SetRootLayer(root);
- LayerTreeHostTest::SetupTree();
- }
-
- virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
-
- virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
- bool expect_context = with_context_;
- if (delegating_renderer())
- expect_context = false;
- EXPECT_EQ(expect_context, !!host_impl->offscreen_context_provider());
- EndTest();
- }
-
- virtual void AfterTest() OVERRIDE {}
-
- bool with_context_;
-};
-
-class LayerTreeHostTestOffscreenContext_NoContext
- : public LayerTreeHostTestOffscreenContext {
- protected:
- LayerTreeHostTestOffscreenContext_NoContext() { with_context_ = false; }
-};
-
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestOffscreenContext_NoContext);
-
-class LayerTreeHostTestOffscreenContext_WithContext
- : public LayerTreeHostTestOffscreenContext {
- protected:
- LayerTreeHostTestOffscreenContext_WithContext() { with_context_ = true; }
-};
-
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestOffscreenContext_WithContext);
-
-class LayerTreeHostTestNoQuadsForEmptyLayer : public LayerTreeHostTest {
- protected:
- virtual void SetupTree() OVERRIDE {
- LayerTreeHostTest::SetupTree();
- root_layer_ = FakeContentLayer::Create(&client_);
- root_layer_->SetBounds(gfx::Size(10, 10));
- root_layer_->SetIsDrawable(false);
- root_layer_->SetHaveWheelEventHandlers(true);
- layer_tree_host()->SetRootLayer(root_layer_);
- LayerTreeHostTest::SetupTree();
- }
-
- virtual void BeginTest() OVERRIDE {
- PostSetNeedsCommitToMainThread();
- }
-
- virtual void DidActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
- FakeContentLayerImpl* layer_impl =
- static_cast<FakeContentLayerImpl*>(impl->RootLayer());
- EXPECT_FALSE(layer_impl->DrawsContent());
- EXPECT_EQ(0u, layer_impl->append_quads_count());
- }
-
- virtual void DidCommit() OVERRIDE {
- // The layer is not drawable, so it should not be updated.
- EXPECT_EQ(0u, root_layer_->update_count());
- EndTest();
- }
- virtual void AfterTest() OVERRIDE {}
-
- private:
- FakeContentLayerClient client_;
- scoped_refptr<FakeContentLayer> root_layer_;
-};
-
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestNoQuadsForEmptyLayer);
-
-
} // namespace
class LayerTreeHostTestSetMemoryPolicyOnLostOutputSurface
@@ -4492,7 +4316,7 @@ class LayerTreeHostTestSetMemoryPolicyOnLostOutputSurface
: first_output_surface_memory_limit_(4321234),
second_output_surface_memory_limit_(1234321) {}
- virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback)
+ virtual scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(bool fallback)
OVERRIDE {
if (!first_context_provider_) {
first_context_provider_ = TestContextProvider::Create();
@@ -4501,19 +4325,21 @@ class LayerTreeHostTestSetMemoryPolicyOnLostOutputSurface
second_context_provider_ = TestContextProvider::Create();
}
- scoped_ptr<FakeOutputSurface> output_surface(
- FakeOutputSurface::Create3d(
- second_context_provider_ ?
- second_context_provider_ :
- first_context_provider_));
- output_surface->SetMemoryPolicyToSetAtBind(make_scoped_ptr(
- new ManagedMemoryPolicy(
- second_context_provider_ ?
- second_output_surface_memory_limit_ :
- first_output_surface_memory_limit_,
+ scoped_refptr<TestContextProvider> provider(second_context_provider_
+ ? second_context_provider_
+ : first_context_provider_);
+ scoped_ptr<FakeOutputSurface> output_surface;
+ if (delegating_renderer())
+ output_surface = FakeOutputSurface::CreateDelegating3d(provider);
+ else
+ output_surface = FakeOutputSurface::Create3d(provider);
+ output_surface->SetMemoryPolicyToSetAtBind(
+ make_scoped_ptr(new ManagedMemoryPolicy(
+ second_context_provider_ ? second_output_surface_memory_limit_
+ : first_output_surface_memory_limit_,
gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE,
ManagedMemoryPolicy::kDefaultNumResourcesLimit)));
- return output_surface.PassAs<OutputSurface>();
+ return output_surface.Pass();
}
virtual void SetupTree() OVERRIDE {
@@ -4523,9 +4349,7 @@ class LayerTreeHostTestSetMemoryPolicyOnLostOutputSurface
LayerTreeHostTest::SetupTree();
}
- virtual void BeginTest() OVERRIDE {
- PostSetNeedsCommitToMainThread();
- }
+ virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
virtual void DidCommitAndDrawFrame() OVERRIDE {
// Lost context sometimes takes two frames to recreate. The third frame
@@ -4538,16 +4362,15 @@ class LayerTreeHostTestSetMemoryPolicyOnLostOutputSurface
}
}
- virtual void SwapBuffersOnThread(LayerTreeHostImpl *impl, bool result)
- OVERRIDE {
+ virtual void SwapBuffersOnThread(LayerTreeHostImpl* impl,
+ bool result) OVERRIDE {
switch (impl->active_tree()->source_frame_number()) {
case 1:
EXPECT_EQ(first_output_surface_memory_limit_,
impl->memory_allocation_limit_bytes());
// Lose the output surface.
first_context_provider_->TestContext3d()->loseContextCHROMIUM(
- GL_GUILTY_CONTEXT_RESET_ARB,
- GL_INNOCENT_CONTEXT_RESET_ARB);
+ GL_GUILTY_CONTEXT_RESET_ARB, GL_INNOCENT_CONTEXT_RESET_ARB);
break;
case 4:
EXPECT_EQ(second_output_surface_memory_limit_,
@@ -4571,11 +4394,11 @@ SINGLE_AND_MULTI_THREAD_TEST_F(
LayerTreeHostTestSetMemoryPolicyOnLostOutputSurface);
struct TestSwapPromiseResult {
- TestSwapPromiseResult() : did_swap_called(false),
- did_not_swap_called(false),
- dtor_called(false),
- reason(SwapPromise::DID_NOT_SWAP_UNKNOWN) {
- }
+ TestSwapPromiseResult()
+ : did_swap_called(false),
+ did_not_swap_called(false),
+ dtor_called(false),
+ reason(SwapPromise::DID_NOT_SWAP_UNKNOWN) {}
bool did_swap_called;
bool did_not_swap_called;
@@ -4586,9 +4409,7 @@ struct TestSwapPromiseResult {
class TestSwapPromise : public SwapPromise {
public:
- explicit TestSwapPromise(TestSwapPromiseResult* result)
- : result_(result) {
- }
+ explicit TestSwapPromise(TestSwapPromiseResult* result) : result_(result) {}
virtual ~TestSwapPromise() {
base::AutoLock lock(result_->lock);
@@ -4615,17 +4436,15 @@ class TestSwapPromise : public SwapPromise {
TestSwapPromiseResult* result_;
};
-class LayerTreeHostTestBreakSwapPromise
- : public LayerTreeHostTest {
+class LayerTreeHostTestBreakSwapPromise : public LayerTreeHostTest {
protected:
LayerTreeHostTestBreakSwapPromise()
- : commit_count_(0), commit_complete_count_(0) {
- }
+ : commit_count_(0), commit_complete_count_(0) {}
virtual void WillBeginMainFrame() OVERRIDE {
ASSERT_LE(commit_count_, 2);
- scoped_ptr<SwapPromise> swap_promise(new TestSwapPromise(
- &swap_promise_result_[commit_count_]));
+ scoped_ptr<SwapPromise> swap_promise(
+ new TestSwapPromise(&swap_promise_result_[commit_count_]));
layer_tree_host()->QueueSwapPromise(swap_promise.Pass());
}
@@ -4690,7 +4509,6 @@ class LayerTreeHostTestBreakSwapPromise
MULTI_THREAD_TEST_F(LayerTreeHostTestBreakSwapPromise);
-
class SimpleSwapPromiseMonitor : public SwapPromiseMonitor {
public:
SimpleSwapPromiseMonitor(LayerTreeHost* layer_tree_host,
@@ -4716,9 +4534,8 @@ class SimpleSwapPromiseMonitor : public SwapPromiseMonitor {
int* set_needs_redraw_count_;
};
-class LayerTreeHostTestSimpleSwapPromiseMonitor
- : public LayerTreeHostTest {
-
+class LayerTreeHostTestSimpleSwapPromiseMonitor : public LayerTreeHostTest {
+ public:
virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
virtual void WillBeginMainFrame() OVERRIDE {
@@ -4772,4 +4589,314 @@ class LayerTreeHostTestSimpleSwapPromiseMonitor
MULTI_THREAD_TEST_F(LayerTreeHostTestSimpleSwapPromiseMonitor);
+class LayerTreeHostTestHighResRequiredAfterEvictingUIResources
+ : public LayerTreeHostTest {
+ protected:
+ virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
+ settings->impl_side_painting = true;
+ }
+
+ virtual void SetupTree() OVERRIDE {
+ LayerTreeHostTest::SetupTree();
+ ui_resource_ = FakeScopedUIResource::Create(layer_tree_host());
+ }
+
+ virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
+
+ virtual void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
+ host_impl->EvictAllUIResources();
+ // Existence of evicted UI resources will trigger NEW_CONTENT_TAKES_PRIORITY
+ // mode. Active tree should require high-res to draw after entering this
+ // mode to ensure that high-res tiles are also required for a pending tree
+ // to be activated.
+ EXPECT_TRUE(host_impl->active_tree()->RequiresHighResToDraw());
+ }
+
+ virtual void DidCommit() OVERRIDE {
+ int frame = layer_tree_host()->source_frame_number();
+ switch (frame) {
+ case 1:
+ PostSetNeedsCommitToMainThread();
+ break;
+ case 2:
+ ui_resource_.reset();
+ EndTest();
+ break;
+ }
+ }
+
+ virtual void AfterTest() OVERRIDE {}
+
+ FakeContentLayerClient client_;
+ scoped_ptr<FakeScopedUIResource> ui_resource_;
+};
+
+// This test is flaky, see http://crbug.com/386199
+//MULTI_THREAD_TEST_F(LayerTreeHostTestHighResRequiredAfterEvictingUIResources);
+
+class LayerTreeHostTestGpuRasterizationDefault : public LayerTreeHostTest {
+ protected:
+ virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
+ settings->impl_side_painting = true;
+
+ EXPECT_FALSE(settings->gpu_rasterization_enabled);
+ EXPECT_FALSE(settings->gpu_rasterization_forced);
+ }
+
+ virtual void SetupTree() OVERRIDE {
+ LayerTreeHostTest::SetupTree();
+
+ scoped_refptr<PictureLayer> layer = PictureLayer::Create(&layer_client_);
+ layer->SetBounds(gfx::Size(10, 10));
+ layer->SetIsDrawable(true);
+ layer_tree_host()->root_layer()->AddChild(layer);
+ }
+
+ virtual void BeginTest() OVERRIDE {
+ Layer* root = layer_tree_host()->root_layer();
+ PictureLayer* layer = static_cast<PictureLayer*>(root->child_at(0));
+ PicturePile* pile = layer->GetPicturePileForTesting();
+
+ // Verify default values.
+ EXPECT_TRUE(root->IsSuitableForGpuRasterization());
+ EXPECT_TRUE(layer->IsSuitableForGpuRasterization());
+ EXPECT_TRUE(pile->is_suitable_for_gpu_rasterization());
+ EXPECT_FALSE(layer_tree_host()->has_gpu_rasterization_trigger());
+ EXPECT_FALSE(layer_tree_host()->UseGpuRasterization());
+
+ // Setting gpu rasterization trigger does not enable gpu rasterization.
+ layer_tree_host()->SetHasGpuRasterizationTrigger(true);
+ EXPECT_TRUE(layer_tree_host()->has_gpu_rasterization_trigger());
+ EXPECT_FALSE(layer_tree_host()->UseGpuRasterization());
+
+ PostSetNeedsCommitToMainThread();
+ }
+
+ virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
+ EXPECT_FALSE(host_impl->pending_tree()->use_gpu_rasterization());
+ EXPECT_FALSE(host_impl->use_gpu_rasterization());
+ }
+
+ virtual void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
+ EXPECT_FALSE(host_impl->active_tree()->use_gpu_rasterization());
+ EXPECT_FALSE(host_impl->use_gpu_rasterization());
+ EndTest();
+ }
+
+ virtual void AfterTest() OVERRIDE {}
+
+ FakeContentLayerClient layer_client_;
+};
+
+MULTI_THREAD_TEST_F(LayerTreeHostTestGpuRasterizationDefault);
+
+class LayerTreeHostTestGpuRasterizationEnabled : public LayerTreeHostTest {
+ protected:
+ virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
+ settings->impl_side_painting = true;
+
+ EXPECT_FALSE(settings->gpu_rasterization_enabled);
+ settings->gpu_rasterization_enabled = true;
+ }
+
+ virtual void SetupTree() OVERRIDE {
+ LayerTreeHostTest::SetupTree();
+
+ scoped_refptr<PictureLayer> layer = PictureLayer::Create(&layer_client_);
+ layer->SetBounds(gfx::Size(10, 10));
+ layer->SetIsDrawable(true);
+ layer_tree_host()->root_layer()->AddChild(layer);
+ }
+
+ virtual void BeginTest() OVERRIDE {
+ Layer* root = layer_tree_host()->root_layer();
+ PictureLayer* layer = static_cast<PictureLayer*>(root->child_at(0));
+ PicturePile* pile = layer->GetPicturePileForTesting();
+
+ // Verify default values.
+ EXPECT_TRUE(root->IsSuitableForGpuRasterization());
+ EXPECT_TRUE(layer->IsSuitableForGpuRasterization());
+ EXPECT_TRUE(pile->is_suitable_for_gpu_rasterization());
+ EXPECT_FALSE(layer_tree_host()->has_gpu_rasterization_trigger());
+ EXPECT_FALSE(layer_tree_host()->UseGpuRasterization());
+
+ // Gpu rasterization trigger is relevant.
+ layer_tree_host()->SetHasGpuRasterizationTrigger(true);
+ EXPECT_TRUE(layer_tree_host()->has_gpu_rasterization_trigger());
+ EXPECT_TRUE(layer_tree_host()->UseGpuRasterization());
+
+ // Content-based veto is relevant as well.
+ pile->SetUnsuitableForGpuRasterizationForTesting();
+ EXPECT_FALSE(pile->is_suitable_for_gpu_rasterization());
+ EXPECT_FALSE(layer->IsSuitableForGpuRasterization());
+ // Veto will take effect when layers are updated.
+ // The results will be verified after commit is completed below.
+ // Since we are manually marking picture pile as unsuitable,
+ // make sure that the layer gets a chance to update.
+ layer->SetNeedsDisplay();
+ PostSetNeedsCommitToMainThread();
+ }
+
+ virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
+ EXPECT_FALSE(host_impl->pending_tree()->use_gpu_rasterization());
+ EXPECT_FALSE(host_impl->use_gpu_rasterization());
+ }
+
+ virtual void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
+ EXPECT_FALSE(host_impl->active_tree()->use_gpu_rasterization());
+ EXPECT_FALSE(host_impl->use_gpu_rasterization());
+ EndTest();
+ }
+
+ virtual void AfterTest() OVERRIDE {}
+
+ FakeContentLayerClient layer_client_;
+};
+
+MULTI_THREAD_TEST_F(LayerTreeHostTestGpuRasterizationEnabled);
+
+class LayerTreeHostTestGpuRasterizationForced : public LayerTreeHostTest {
+ protected:
+ virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
+ settings->impl_side_painting = true;
+
+ EXPECT_FALSE(settings->gpu_rasterization_forced);
+ settings->gpu_rasterization_forced = true;
+ }
+
+ virtual void SetupTree() OVERRIDE {
+ LayerTreeHostTest::SetupTree();
+
+ scoped_refptr<PictureLayer> layer = PictureLayer::Create(&layer_client_);
+ layer->SetBounds(gfx::Size(10, 10));
+ layer->SetIsDrawable(true);
+ layer_tree_host()->root_layer()->AddChild(layer);
+ }
+
+ virtual void BeginTest() OVERRIDE {
+ Layer* root = layer_tree_host()->root_layer();
+ PictureLayer* layer = static_cast<PictureLayer*>(root->child_at(0));
+ PicturePile* pile = layer->GetPicturePileForTesting();
+
+ // Verify default values.
+ EXPECT_TRUE(root->IsSuitableForGpuRasterization());
+ EXPECT_TRUE(layer->IsSuitableForGpuRasterization());
+ EXPECT_TRUE(pile->is_suitable_for_gpu_rasterization());
+ EXPECT_FALSE(layer_tree_host()->has_gpu_rasterization_trigger());
+
+ // With gpu rasterization forced, gpu rasterization trigger is irrelevant.
+ EXPECT_TRUE(layer_tree_host()->UseGpuRasterization());
+ layer_tree_host()->SetHasGpuRasterizationTrigger(true);
+ EXPECT_TRUE(layer_tree_host()->has_gpu_rasterization_trigger());
+ EXPECT_TRUE(layer_tree_host()->UseGpuRasterization());
+
+ // Content-based veto is irrelevant as well.
+ pile->SetUnsuitableForGpuRasterizationForTesting();
+ EXPECT_FALSE(pile->is_suitable_for_gpu_rasterization());
+ EXPECT_FALSE(layer->IsSuitableForGpuRasterization());
+ // Veto will take effect when layers are updated.
+ // The results will be verified after commit is completed below.
+ // Since we are manually marking picture pile as unsuitable,
+ // make sure that the layer gets a chance to update.
+ layer->SetNeedsDisplay();
+ PostSetNeedsCommitToMainThread();
+ }
+
+ virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
+ EXPECT_TRUE(host_impl->pending_tree()->use_gpu_rasterization());
+ EXPECT_TRUE(host_impl->use_gpu_rasterization());
+ }
+
+ virtual void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
+ EXPECT_TRUE(host_impl->active_tree()->use_gpu_rasterization());
+ EXPECT_TRUE(host_impl->use_gpu_rasterization());
+ EndTest();
+ }
+
+ virtual void AfterTest() OVERRIDE {}
+
+ FakeContentLayerClient layer_client_;
+};
+
+MULTI_THREAD_TEST_F(LayerTreeHostTestGpuRasterizationForced);
+
+class LayerTreeHostTestContinuousPainting : public LayerTreeHostTest {
+ public:
+ LayerTreeHostTestContinuousPainting()
+ : num_commits_(0), num_draws_(0), bounds_(20, 20), child_layer_(NULL) {}
+
+ protected:
+ enum { kExpectedNumCommits = 10 };
+
+ virtual void SetupTree() OVERRIDE {
+ scoped_refptr<Layer> root_layer = Layer::Create();
+ root_layer->SetBounds(bounds_);
+
+ if (layer_tree_host()->settings().impl_side_painting) {
+ picture_layer_ = FakePictureLayer::Create(&client_);
+ child_layer_ = picture_layer_.get();
+ } else {
+ content_layer_ = ContentLayerWithUpdateTracking::Create(&client_);
+ child_layer_ = content_layer_.get();
+ }
+ child_layer_->SetBounds(bounds_);
+ child_layer_->SetIsDrawable(true);
+ root_layer->AddChild(child_layer_);
+
+ layer_tree_host()->SetRootLayer(root_layer);
+ layer_tree_host()->SetViewportSize(bounds_);
+ LayerTreeHostTest::SetupTree();
+ }
+
+ virtual void BeginTest() OVERRIDE {
+ // Wait 50x longer than expected.
+ double milliseconds_per_frame =
+ 1000 / layer_tree_host()->settings().refresh_rate;
+ EndTestAfterDelay(50 * kExpectedNumCommits * milliseconds_per_frame);
+ MainThreadTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(
+ &LayerTreeHostTestContinuousPainting::EnableContinuousPainting,
+ base::Unretained(this)));
+ }
+
+ virtual void Animate(base::TimeTicks monotonic_time) OVERRIDE {
+ child_layer_->SetNeedsDisplay();
+ }
+
+ virtual void AfterTest() OVERRIDE {
+ EXPECT_LE(kExpectedNumCommits, num_commits_);
+ EXPECT_LE(kExpectedNumCommits, num_draws_);
+ int update_count = content_layer_ ? content_layer_->PaintContentsCount()
+ : picture_layer_->update_count();
+ EXPECT_LE(kExpectedNumCommits, update_count);
+ }
+
+ virtual void DrawLayersOnThread(LayerTreeHostImpl* impl) OVERRIDE {
+ if (++num_draws_ == kExpectedNumCommits)
+ EndTest();
+ }
+
+ virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
+ ++num_commits_;
+ }
+
+ private:
+ void EnableContinuousPainting() {
+ LayerTreeDebugState debug_state = layer_tree_host()->debug_state();
+ debug_state.continuous_painting = true;
+ layer_tree_host()->SetDebugState(debug_state);
+ }
+
+ int num_commits_;
+ int num_draws_;
+ const gfx::Size bounds_;
+ FakeContentLayerClient client_;
+ scoped_refptr<ContentLayerWithUpdateTracking> content_layer_;
+ scoped_refptr<FakePictureLayer> picture_layer_;
+ Layer* child_layer_;
+};
+
+MULTI_THREAD_TEST_F(LayerTreeHostTestContinuousPainting);
+
} // 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 22c8965a5fd..1542a1417b4 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_animation.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_animation.cc
@@ -149,7 +149,6 @@ class LayerTreeHostAnimationTestAddAnimation
}
virtual void NotifyAnimationStarted(
- double wall_clock_time,
base::TimeTicks monotonic_time,
Animation::TargetProperty target_property) OVERRIDE {
received_animation_started_notification_ = true;
@@ -201,11 +200,11 @@ class LayerTreeHostAnimationTestCheckerboardDoesNotStarveDraws
EndTest();
}
- virtual bool PrepareToDrawOnThread(
+ virtual DrawResult PrepareToDrawOnThread(
LayerTreeHostImpl* host_impl,
LayerTreeHostImpl::FrameData* frame,
- bool result) OVERRIDE {
- return false;
+ DrawResult draw_result) OVERRIDE {
+ return DRAW_ABORTED_CHECKERBOARD_ANIMATIONS;
}
virtual void AfterTest() OVERRIDE { }
@@ -243,7 +242,6 @@ class LayerTreeHostAnimationTestAnimationsGetDeleted
}
virtual void NotifyAnimationFinished(
- double wall_clock_time,
base::TimeTicks monotonic_time,
Animation::TargetProperty target_property) OVERRIDE {
// Animations on the impl-side controller only get deleted during a commit,
@@ -299,6 +297,61 @@ class LayerTreeHostAnimationTestTickAnimationWhileBackgrounded
SINGLE_AND_MULTI_THREAD_TEST_F(
LayerTreeHostAnimationTestTickAnimationWhileBackgrounded);
+// Ensures that animation time remains monotonic when we switch from foreground
+// to background ticking and back, even if we're skipping draws due to
+// checkerboarding when in the foreground.
+class LayerTreeHostAnimationTestAnimationTickTimeIsMonotonic
+ : public LayerTreeHostAnimationTest {
+ public:
+ LayerTreeHostAnimationTestAnimationTickTimeIsMonotonic()
+ : has_background_ticked_(false), num_foreground_animates_(0) {}
+
+ virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
+ // Make sure that drawing many times doesn't cause a checkerboarded
+ // animation to start so we avoid flake in this test.
+ settings->timeout_and_draw_when_animation_checkerboards = false;
+ }
+
+ virtual void BeginTest() OVERRIDE {
+ PostAddLongAnimationToMainThread(layer_tree_host()->root_layer());
+ }
+
+ virtual void AnimateLayers(LayerTreeHostImpl* host_impl,
+ base::TimeTicks monotonic_time) OVERRIDE {
+ EXPECT_GE(monotonic_time, last_tick_time_);
+ last_tick_time_ = monotonic_time;
+ if (host_impl->visible()) {
+ num_foreground_animates_++;
+ if (num_foreground_animates_ > 1 && !has_background_ticked_)
+ PostSetVisibleToMainThread(false);
+ else if (has_background_ticked_)
+ EndTest();
+ } else {
+ has_background_ticked_ = true;
+ PostSetVisibleToMainThread(true);
+ }
+ }
+
+ virtual DrawResult PrepareToDrawOnThread(
+ LayerTreeHostImpl* host_impl,
+ LayerTreeHostImpl::FrameData* frame,
+ DrawResult draw_result) OVERRIDE {
+ if (TestEnded())
+ return draw_result;
+ return DRAW_ABORTED_CHECKERBOARD_ANIMATIONS;
+ }
+
+ virtual void AfterTest() OVERRIDE {}
+
+ private:
+ bool has_background_ticked_;
+ int num_foreground_animates_;
+ base::TimeTicks last_tick_time_;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(
+ LayerTreeHostAnimationTestAnimationTickTimeIsMonotonic);
+
// Ensures that animations do not tick when we are backgrounded and
// and we have an empty active tree.
class LayerTreeHostAnimationTestNoBackgroundTickingWithoutActiveTree
@@ -316,7 +369,6 @@ class LayerTreeHostAnimationTestNoBackgroundTickingWithoutActiveTree
}
virtual void NotifyAnimationFinished(
- double wall_clock_time,
base::TimeTicks monotonic_time,
Animation::TargetProperty target_property) OVERRIDE {
// Replace animated commits with an empty tree.
@@ -509,7 +561,6 @@ class LayerTreeHostAnimationTestSynchronizeAnimationStartTimes
}
virtual void NotifyAnimationStarted(
- double wall_clock_time,
base::TimeTicks monotonic_time,
Animation::TargetProperty target_property) OVERRIDE {
LayerAnimationController* controller =
@@ -517,7 +568,8 @@ class LayerTreeHostAnimationTestSynchronizeAnimationStartTimes
layer_animation_controller();
Animation* animation =
controller->GetAnimation(Animation::Opacity);
- main_start_time_ = animation->start_time();
+ main_start_time_ =
+ (animation->start_time() - base::TimeTicks()).InSecondsF();
controller->RemoveAnimation(animation->id());
if (impl_start_time_ > 0.0)
@@ -535,7 +587,8 @@ class LayerTreeHostAnimationTestSynchronizeAnimationStartTimes
if (!animation)
return;
- impl_start_time_ = animation->start_time();
+ impl_start_time_ =
+ (animation->start_time() - base::TimeTicks()).InSecondsF();
controller->RemoveAnimation(animation->id());
if (main_start_time_ > 0.0)
@@ -567,7 +620,6 @@ class LayerTreeHostAnimationTestAnimationFinishedEvents
}
virtual void NotifyAnimationFinished(
- double wall_clock_time,
base::TimeTicks monotonic_time,
Animation::TargetProperty target_property) OVERRIDE {
LayerAnimationController* controller =
@@ -670,56 +722,6 @@ class LayerTreeHostAnimationTestLayerAddedWithAnimation
SINGLE_AND_MULTI_THREAD_TEST_F(
LayerTreeHostAnimationTestLayerAddedWithAnimation);
-class LayerTreeHostAnimationTestCompositeAndReadbackAnimateCount
- : public LayerTreeHostAnimationTest {
- public:
- LayerTreeHostAnimationTestCompositeAndReadbackAnimateCount()
- : animated_commit_(-1) {
- }
-
- virtual void Animate(base::TimeTicks) OVERRIDE {
- // We shouldn't animate on the CompositeAndReadback-forced commit, but we
- // should for the SetNeedsCommit-triggered commit.
- animated_commit_ = layer_tree_host()->source_frame_number();
- EXPECT_NE(2, animated_commit_);
- }
-
- virtual void BeginTest() OVERRIDE {
- PostSetNeedsCommitToMainThread();
- }
-
- virtual void DidCommit() OVERRIDE {
- switch (layer_tree_host()->source_frame_number()) {
- case 1:
- layer_tree_host()->SetNeedsCommit();
- break;
- case 2: {
- char pixels[4];
- layer_tree_host()->CompositeAndReadback(&pixels, gfx::Rect(0, 0, 1, 1));
- break;
- }
- case 3:
- // This is finishing the readback's commit.
- break;
- case 4:
- // This is finishing the followup commit.
- EndTest();
- break;
- default:
- NOTREACHED();
- }
- }
-
- virtual void AfterTest() OVERRIDE {
- EXPECT_EQ(3, animated_commit_);
- }
-
- private:
- int animated_commit_;
-};
-
-MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestCompositeAndReadbackAnimateCount);
-
class LayerTreeHostAnimationTestContinuousAnimate
: public LayerTreeHostAnimationTest {
public:
@@ -728,6 +730,15 @@ class LayerTreeHostAnimationTestContinuousAnimate
num_draw_layers_(0) {
}
+ virtual void SetupTree() OVERRIDE {
+ LayerTreeHostAnimationTest::SetupTree();
+ // Create a fake content layer so we actually produce new content for every
+ // animation frame.
+ content_ = FakeContentLayer::Create(&client_);
+ content_->set_always_update_resources(true);
+ layer_tree_host()->root_layer()->AddChild(content_);
+ }
+
virtual void BeginTest() OVERRIDE {
PostSetNeedsCommitToMainThread();
}
@@ -761,10 +772,128 @@ class LayerTreeHostAnimationTestContinuousAnimate
private:
int num_commit_complete_;
int num_draw_layers_;
+ FakeContentLayerClient client_;
+ scoped_refptr<FakeContentLayer> content_;
};
MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestContinuousAnimate);
+class LayerTreeHostAnimationTestCancelAnimateCommit
+ : public LayerTreeHostAnimationTest {
+ public:
+ LayerTreeHostAnimationTestCancelAnimateCommit()
+ : num_animate_calls_(0), num_commit_calls_(0), num_draw_calls_(0) {}
+
+ virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
+
+ virtual void Animate(base::TimeTicks) OVERRIDE {
+ num_animate_calls_++;
+ // No-op animate will cancel the commit.
+ if (layer_tree_host()->source_frame_number() == 1) {
+ EndTest();
+ return;
+ }
+ layer_tree_host()->SetNeedsAnimate();
+ }
+
+ virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
+ num_commit_calls_++;
+ if (impl->active_tree()->source_frame_number() > 1)
+ FAIL() << "Commit should have been canceled.";
+ }
+
+ virtual void DrawLayersOnThread(LayerTreeHostImpl* impl) OVERRIDE {
+ num_draw_calls_++;
+ if (impl->active_tree()->source_frame_number() > 1)
+ FAIL() << "Draw should have been canceled.";
+ }
+
+ virtual void AfterTest() OVERRIDE {
+ EXPECT_EQ(2, num_animate_calls_);
+ EXPECT_EQ(1, num_commit_calls_);
+ EXPECT_EQ(1, num_draw_calls_);
+ }
+
+ private:
+ int num_animate_calls_;
+ int num_commit_calls_;
+ int num_draw_calls_;
+ FakeContentLayerClient client_;
+ scoped_refptr<FakeContentLayer> content_;
+};
+
+MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestCancelAnimateCommit);
+
+class LayerTreeHostAnimationTestForceRedraw
+ : public LayerTreeHostAnimationTest {
+ public:
+ LayerTreeHostAnimationTestForceRedraw()
+ : num_animate_(0), num_draw_layers_(0) {}
+
+ virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
+
+ virtual void Animate(base::TimeTicks) OVERRIDE {
+ if (++num_animate_ < 2)
+ layer_tree_host()->SetNeedsAnimate();
+ }
+
+ virtual void Layout() OVERRIDE {
+ layer_tree_host()->SetNextCommitForcesRedraw();
+ }
+
+ virtual void DrawLayersOnThread(LayerTreeHostImpl* impl) OVERRIDE {
+ if (++num_draw_layers_ == 2)
+ EndTest();
+ }
+
+ virtual void AfterTest() OVERRIDE {
+ // The first commit will always draw; make sure the second draw triggered
+ // by the animation was not cancelled.
+ EXPECT_EQ(2, num_draw_layers_);
+ EXPECT_EQ(2, num_animate_);
+ }
+
+ private:
+ int num_animate_;
+ int num_draw_layers_;
+};
+
+MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestForceRedraw);
+
+class LayerTreeHostAnimationTestAnimateAfterSetNeedsCommit
+ : public LayerTreeHostAnimationTest {
+ public:
+ LayerTreeHostAnimationTestAnimateAfterSetNeedsCommit()
+ : num_animate_(0), num_draw_layers_(0) {}
+
+ virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
+
+ virtual void Animate(base::TimeTicks) OVERRIDE {
+ if (++num_animate_ <= 2) {
+ layer_tree_host()->SetNeedsCommit();
+ layer_tree_host()->SetNeedsAnimate();
+ }
+ }
+
+ virtual void DrawLayersOnThread(LayerTreeHostImpl* impl) OVERRIDE {
+ if (++num_draw_layers_ == 2)
+ EndTest();
+ }
+
+ virtual void AfterTest() OVERRIDE {
+ // The first commit will always draw; make sure the second draw triggered
+ // by the SetNeedsCommit was not cancelled.
+ EXPECT_EQ(2, num_draw_layers_);
+ EXPECT_GE(num_animate_, 2);
+ }
+
+ private:
+ int num_animate_;
+ int num_draw_layers_;
+};
+
+MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestAnimateAfterSetNeedsCommit);
+
// Make sure the main thread can still execute animations when CanDraw() is not
// true.
class LayerTreeHostAnimationTestRunAnimationWhenNotCanDraw
@@ -786,14 +915,12 @@ class LayerTreeHostAnimationTestRunAnimationWhenNotCanDraw
}
virtual void NotifyAnimationStarted(
- double wall_clock_time,
base::TimeTicks monotonic_time,
Animation::TargetProperty target_property) OVERRIDE {
started_times_++;
}
virtual void NotifyAnimationFinished(
- double wall_clock_time,
base::TimeTicks monotonic_time,
Animation::TargetProperty target_property) OVERRIDE {
EndTest();
@@ -838,7 +965,6 @@ class LayerTreeHostAnimationTestRunAnimationWhenNotVisible
}
virtual void NotifyAnimationStarted(
- double wall_clock_time,
base::TimeTicks monotonic_time,
Animation::TargetProperty target_property) OVERRIDE {
EXPECT_FALSE(visible_);
@@ -846,7 +972,6 @@ class LayerTreeHostAnimationTestRunAnimationWhenNotVisible
}
virtual void NotifyAnimationFinished(
- double wall_clock_time,
base::TimeTicks monotonic_time,
Animation::TargetProperty target_property) OVERRIDE {
EXPECT_FALSE(visible_);
@@ -888,21 +1013,23 @@ class LayerTreeHostAnimationTestCheckerboardDoesntStartAnimations
prevented_draw_ = 0;
added_animations_ = 0;
started_times_ = 0;
- finished_times_ = 0;
PostSetNeedsCommitToMainThread();
}
- virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
- LayerTreeHostImpl::FrameData* frame_data,
- bool result) OVERRIDE {
+ virtual DrawResult PrepareToDrawOnThread(
+ LayerTreeHostImpl* host_impl,
+ LayerTreeHostImpl::FrameData* frame_data,
+ DrawResult draw_result) OVERRIDE {
if (added_animations_ < 2)
- return result;
+ return draw_result;
if (TestEnded())
- return result;
+ return draw_result;
// Act like there is checkerboard when the second animation wants to draw.
++prevented_draw_;
- return false;
+ if (prevented_draw_ > 2)
+ EndTest();
+ return DRAW_ABORTED_CHECKERBOARD_ANIMATIONS;
}
virtual void DidCommitAndDrawFrame() OVERRIDE {
@@ -921,7 +1048,6 @@ class LayerTreeHostAnimationTestCheckerboardDoesntStartAnimations
}
virtual void NotifyAnimationStarted(
- double wall_clock_time,
base::TimeTicks monotonic_time,
Animation::TargetProperty target_property) OVERRIDE {
if (TestEnded())
@@ -929,31 +1055,17 @@ class LayerTreeHostAnimationTestCheckerboardDoesntStartAnimations
started_times_++;
}
- virtual void NotifyAnimationFinished(
- double wall_clock_time,
- base::TimeTicks monotonic_time,
- Animation::TargetProperty target_property) OVERRIDE {
- // We should be checkerboarding already, but it should still finish the
- // first animation.
- EXPECT_EQ(2, added_animations_);
- finished_times_++;
- EndTest();
- }
-
virtual void AfterTest() OVERRIDE {
// Make sure we tried to draw the second animation but failed.
EXPECT_LT(0, prevented_draw_);
// The first animation should be started, but the second should not because
// of checkerboard.
EXPECT_EQ(1, started_times_);
- // The first animation should still be finished.
- EXPECT_EQ(1, finished_times_);
}
int prevented_draw_;
int added_animations_;
int started_times_;
- int finished_times_;
FakeContentLayerClient client_;
scoped_refptr<FakeContentLayer> content_;
};
@@ -972,7 +1084,7 @@ class LayerTreeHostAnimationTestScrollOffsetChangesArePropagated
LayerTreeHostAnimationTest::SetupTree();
scroll_layer_ = FakeContentLayer::Create(&client_);
- scroll_layer_->SetScrollable(true);
+ scroll_layer_->SetScrollClipLayerId(layer_tree_host()->root_layer()->id());
scroll_layer_->SetBounds(gfx::Size(1000, 1000));
scroll_layer_->SetScrollOffset(gfx::Vector2d(10, 20));
layer_tree_host()->root_layer()->AddChild(scroll_layer_);
@@ -1013,5 +1125,219 @@ class LayerTreeHostAnimationTestScrollOffsetChangesArePropagated
// LayerTreeHost.
MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestScrollOffsetChangesArePropagated);
+// Ensure that animation time is correctly updated when animations are frozen
+// because of checkerboarding.
+class LayerTreeHostAnimationTestFrozenAnimationTickTime
+ : public LayerTreeHostAnimationTest {
+ public:
+ LayerTreeHostAnimationTestFrozenAnimationTickTime()
+ : started_animating_(false), num_commits_(0), num_draw_attempts_(2) {}
+
+ virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
+ // Make sure that drawing many times doesn't cause a checkerboarded
+ // animation to start so we avoid flake in this test.
+ settings->timeout_and_draw_when_animation_checkerboards = false;
+ }
+
+ virtual void BeginTest() OVERRIDE {
+ PostAddAnimationToMainThread(layer_tree_host()->root_layer());
+ }
+
+ virtual void Animate(base::TimeTicks monotonic_time) OVERRIDE {
+ last_main_thread_tick_time_ = monotonic_time;
+ }
+
+ virtual void AnimateLayers(LayerTreeHostImpl* host_impl,
+ base::TimeTicks monotonic_time) OVERRIDE {
+ if (TestEnded())
+ return;
+ if (!started_animating_) {
+ started_animating_ = true;
+ expected_impl_tick_time_ = monotonic_time;
+ } else {
+ EXPECT_EQ(expected_impl_tick_time_, monotonic_time);
+ if (num_commits_ > 2)
+ EndTest();
+ }
+ }
+
+ virtual DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
+ LayerTreeHostImpl::FrameData* frame,
+ DrawResult draw_result) OVERRIDE {
+ if (TestEnded())
+ return draw_result;
+ num_draw_attempts_++;
+ if (num_draw_attempts_ > 2) {
+ num_draw_attempts_ = 0;
+ PostSetNeedsCommitToMainThread();
+ }
+ return DRAW_ABORTED_CHECKERBOARD_ANIMATIONS;
+ }
+
+ virtual void BeginCommitOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
+ if (!started_animating_)
+ return;
+ expected_impl_tick_time_ =
+ std::max(expected_impl_tick_time_, last_main_thread_tick_time_);
+ num_commits_++;
+ }
+
+ virtual void AfterTest() OVERRIDE {}
+
+ private:
+ bool started_animating_;
+ int num_commits_;
+ int num_draw_attempts_;
+ base::TimeTicks last_main_thread_tick_time_;
+ base::TimeTicks expected_impl_tick_time_;
+};
+
+// Only the non-impl-paint multi-threaded compositor freezes animations.
+MULTI_THREAD_NOIMPL_TEST_F(LayerTreeHostAnimationTestFrozenAnimationTickTime);
+
+// When animations are simultaneously added to an existing layer and to a new
+// layer, they should start at the same time, even when there's already a
+// running animation on the existing layer.
+class LayerTreeHostAnimationTestAnimationsAddedToNewAndExistingLayers
+ : public LayerTreeHostAnimationTest {
+ public:
+ LayerTreeHostAnimationTestAnimationsAddedToNewAndExistingLayers()
+ : frame_count_with_pending_tree_(0) {}
+
+ virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
+
+ virtual void DidCommit() OVERRIDE {
+ if (layer_tree_host()->source_frame_number() == 1) {
+ AddAnimatedTransformToLayer(layer_tree_host()->root_layer(), 4, 1, 1);
+ } else if (layer_tree_host()->source_frame_number() == 2) {
+ AddOpacityTransitionToLayer(
+ layer_tree_host()->root_layer(), 1, 0.f, 0.5f, true);
+
+ scoped_refptr<Layer> layer = Layer::Create();
+ layer_tree_host()->root_layer()->AddChild(layer);
+ layer->set_layer_animation_delegate(this);
+ layer->SetBounds(gfx::Size(4, 4));
+ AddOpacityTransitionToLayer(layer, 1, 0.f, 0.5f, true);
+ }
+ }
+
+ virtual void BeginCommitOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
+ host_impl->BlockNotifyReadyToActivateForTesting(true);
+ }
+
+ virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
+ // For the commit that added animations to new and existing layers, keep
+ // blocking activation. We want to verify that even with activation blocked,
+ // the animation on the layer that's already in the active tree won't get a
+ // head start.
+ if (!host_impl->settings().impl_side_painting ||
+ host_impl->pending_tree()->source_frame_number() != 2)
+ host_impl->BlockNotifyReadyToActivateForTesting(false);
+ }
+
+ virtual void WillBeginImplFrameOnThread(LayerTreeHostImpl* host_impl,
+ const BeginFrameArgs& args) OVERRIDE {
+ if (!host_impl->pending_tree() ||
+ host_impl->pending_tree()->source_frame_number() != 2)
+ return;
+
+ frame_count_with_pending_tree_++;
+ if (frame_count_with_pending_tree_ == 2)
+ host_impl->BlockNotifyReadyToActivateForTesting(false);
+ }
+
+ virtual void UpdateAnimationState(LayerTreeHostImpl* host_impl,
+ bool has_unfinished_animation) OVERRIDE {
+ Animation* root_animation = host_impl->active_tree()
+ ->root_layer()
+ ->layer_animation_controller()
+ ->GetAnimation(Animation::Opacity);
+ if (!root_animation || root_animation->run_state() != Animation::Running)
+ return;
+
+ Animation* child_animation = host_impl->active_tree()
+ ->root_layer()
+ ->children()[0]
+ ->layer_animation_controller()
+ ->GetAnimation(Animation::Opacity);
+ EXPECT_EQ(Animation::Running, child_animation->run_state());
+ EXPECT_EQ(root_animation->start_time(), child_animation->start_time());
+ EndTest();
+ }
+
+ virtual void AfterTest() OVERRIDE {}
+
+ private:
+ int frame_count_with_pending_tree_;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(
+ LayerTreeHostAnimationTestAnimationsAddedToNewAndExistingLayers);
+
+class LayerTreeHostAnimationTestAddAnimationAfterAnimating
+ : public LayerTreeHostAnimationTest {
+ public:
+ LayerTreeHostAnimationTestAddAnimationAfterAnimating()
+ : num_swap_buffers_(0) {}
+
+ virtual void SetupTree() OVERRIDE {
+ LayerTreeHostAnimationTest::SetupTree();
+ content_ = Layer::Create();
+ content_->SetBounds(gfx::Size(4, 4));
+ layer_tree_host()->root_layer()->AddChild(content_);
+ }
+
+ virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
+
+ virtual void DidCommit() OVERRIDE {
+ switch (layer_tree_host()->source_frame_number()) {
+ case 1:
+ // First frame: add an animation to the root layer.
+ AddAnimatedTransformToLayer(layer_tree_host()->root_layer(), 0.1, 5, 5);
+ break;
+ case 2:
+ // Second frame: add an animation to the content layer. The root layer
+ // animation has caused us to animate already during this frame.
+ AddOpacityTransitionToLayer(content_.get(), 0.1, 5, 5, false);
+ break;
+ }
+ }
+
+ virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl,
+ bool result) OVERRIDE {
+ // After both animations have started, verify that they have valid
+ // start times.
+ num_swap_buffers_++;
+ AnimationRegistrar::AnimationControllerMap copy =
+ host_impl->animation_registrar()->active_animation_controllers();
+ if (copy.size() == 2u) {
+ EndTest();
+ EXPECT_GE(num_swap_buffers_, 3);
+ for (AnimationRegistrar::AnimationControllerMap::iterator iter =
+ copy.begin();
+ iter != copy.end();
+ ++iter) {
+ int id = ((*iter).second->id());
+ if (id == host_impl->RootLayer()->id()) {
+ Animation* anim = (*iter).second->GetAnimation(Animation::Transform);
+ EXPECT_GT((anim->start_time() - base::TimeTicks()).InSecondsF(), 0);
+ } else if (id == host_impl->RootLayer()->children()[0]->id()) {
+ Animation* anim = (*iter).second->GetAnimation(Animation::Opacity);
+ EXPECT_GT((anim->start_time() - base::TimeTicks()).InSecondsF(), 0);
+ }
+ }
+ }
+ }
+
+ virtual void AfterTest() OVERRIDE {}
+
+ private:
+ scoped_refptr<Layer> content_;
+ int num_swap_buffers_;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(
+ LayerTreeHostAnimationTestAddAnimationAfterAnimating);
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_host_unittest_context.cc b/chromium/cc/trees/layer_tree_host_unittest_context.cc
index 7112436595d..879e5347e31 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_context.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_context.cc
@@ -33,6 +33,7 @@
#include "cc/test/layer_tree_test.h"
#include "cc/test/render_pass_test_common.h"
#include "cc/test/test_context_provider.h"
+#include "cc/test/test_shared_bitmap_manager.h"
#include "cc/test/test_web_graphics_context_3d.h"
#include "cc/trees/layer_tree_host_impl.h"
#include "cc/trees/layer_tree_impl.h"
@@ -41,7 +42,6 @@
#include "media/base/media.h"
using media::VideoFrame;
-using blink::WebGraphicsContext3D;
namespace cc {
namespace {
@@ -56,11 +56,8 @@ class LayerTreeHostContextTest : public LayerTreeTest {
times_to_lose_during_commit_(0),
times_to_lose_during_draw_(0),
times_to_fail_recreate_(0),
- times_to_fail_create_offscreen_(0),
- times_to_fail_recreate_offscreen_(0),
times_to_expect_create_failed_(0),
times_create_failed_(0),
- times_offscreen_created_(0),
committed_at_least_once_(false),
context_should_support_io_surface_(false),
fallback_context_works_(false) {
@@ -77,12 +74,12 @@ class LayerTreeHostContextTest : public LayerTreeTest {
return TestWebGraphicsContext3D::Create();
}
- virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback)
+ virtual scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(bool fallback)
OVERRIDE {
if (times_to_fail_create_) {
--times_to_fail_create_;
ExpectCreateToFail();
- return scoped_ptr<OutputSurface>();
+ return scoped_ptr<FakeOutputSurface>();
}
scoped_ptr<TestWebGraphicsContext3D> context3d = CreateContext3d();
@@ -93,59 +90,27 @@ class LayerTreeHostContextTest : public LayerTreeTest {
context3d_->set_have_extension_egl_image(true);
}
- if (delegating_renderer()) {
- return FakeOutputSurface::CreateDelegating3d(context3d.Pass())
- .PassAs<OutputSurface>();
- }
- return FakeOutputSurface::Create3d(context3d.Pass())
- .PassAs<OutputSurface>();
- }
-
- scoped_ptr<TestWebGraphicsContext3D> CreateOffscreenContext3d() {
- if (!context3d_)
- return scoped_ptr<TestWebGraphicsContext3D>();
-
- ++times_offscreen_created_;
-
- if (times_to_fail_create_offscreen_) {
- --times_to_fail_create_offscreen_;
- ExpectCreateToFail();
- return scoped_ptr<TestWebGraphicsContext3D>();
- }
-
- scoped_ptr<TestWebGraphicsContext3D> offscreen_context3d =
- TestWebGraphicsContext3D::Create().Pass();
- DCHECK(offscreen_context3d);
- context3d_->add_share_group_context(offscreen_context3d.get());
-
- return offscreen_context3d.Pass();
- }
-
- virtual scoped_refptr<ContextProvider> OffscreenContextProvider() OVERRIDE {
- if (!offscreen_contexts_.get() ||
- offscreen_contexts_->DestroyedOnMainThread()) {
- offscreen_contexts_ =
- TestContextProvider::Create(CreateOffscreenContext3d());
- }
- return offscreen_contexts_;
+ if (delegating_renderer())
+ return FakeOutputSurface::CreateDelegating3d(context3d.Pass());
+ else
+ return FakeOutputSurface::Create3d(context3d.Pass());
}
- virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
- LayerTreeHostImpl::FrameData* frame,
- bool result) OVERRIDE {
- EXPECT_TRUE(result);
+ virtual DrawResult PrepareToDrawOnThread(
+ LayerTreeHostImpl* host_impl,
+ LayerTreeHostImpl::FrameData* frame,
+ DrawResult draw_result) OVERRIDE {
+ EXPECT_EQ(DRAW_SUCCESS, draw_result);
if (!times_to_lose_during_draw_)
- return result;
+ return draw_result;
--times_to_lose_during_draw_;
LoseContext();
times_to_fail_create_ = times_to_fail_recreate_;
times_to_fail_recreate_ = 0;
- times_to_fail_create_offscreen_ = times_to_fail_recreate_offscreen_;
- times_to_fail_recreate_offscreen_ = 0;
- return result;
+ return draw_result;
}
virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
@@ -158,8 +123,6 @@ class LayerTreeHostContextTest : public LayerTreeTest {
times_to_fail_create_ = times_to_fail_recreate_;
times_to_fail_recreate_ = 0;
- times_to_fail_create_offscreen_ = times_to_fail_recreate_offscreen_;
- times_to_fail_recreate_offscreen_ = 0;
}
virtual void DidFailToInitializeOutputSurface() OVERRIDE {
@@ -171,9 +134,7 @@ class LayerTreeHostContextTest : public LayerTreeTest {
EXPECT_EQ(times_to_expect_create_failed_, times_create_failed_);
}
- void ExpectCreateToFail() {
- ++times_to_expect_create_failed_;
- }
+ void ExpectCreateToFail() { ++times_to_expect_create_failed_; }
protected:
TestWebGraphicsContext3D* context3d_;
@@ -181,16 +142,11 @@ class LayerTreeHostContextTest : public LayerTreeTest {
int times_to_lose_during_commit_;
int times_to_lose_during_draw_;
int times_to_fail_recreate_;
- int times_to_fail_create_offscreen_;
- int times_to_fail_recreate_offscreen_;
int times_to_expect_create_failed_;
int times_create_failed_;
- int times_offscreen_created_;
bool committed_at_least_once_;
bool context_should_support_io_surface_;
bool fallback_context_works_;
-
- scoped_refptr<TestContextProvider> offscreen_contexts_;
};
class LayerTreeHostContextTestLostContextSucceeds
@@ -204,13 +160,9 @@ class LayerTreeHostContextTestLostContextSucceeds
recovered_context_(true),
first_initialized_(false) {}
- virtual void BeginTest() OVERRIDE {
- PostSetNeedsCommitToMainThread();
- }
-
- virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
- EXPECT_TRUE(succeeded);
+ virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
+ virtual void DidInitializeOutputSurface() OVERRIDE {
if (first_initialized_)
++num_losses_;
else
@@ -219,7 +171,7 @@ class LayerTreeHostContextTestLostContextSucceeds
recovered_context_ = true;
}
- virtual void AfterTest() OVERRIDE { EXPECT_EQ(9u, test_case_); }
+ virtual void AfterTest() OVERRIDE { EXPECT_EQ(7u, test_case_); }
virtual void DidCommitAndDrawFrame() OVERRIDE {
// If the last frame had a context loss, then we'll commit again to
@@ -246,67 +198,47 @@ class LayerTreeHostContextTestLostContextSucceeds
bool NextTestCase() {
static const TestCase kTests[] = {
- // Losing the context and failing to recreate it (or losing it again
- // immediately) a small number of times should succeed.
- { 1, // times_to_lose_during_commit
- 0, // times_to_lose_during_draw
- 0, // times_to_fail_recreate
- 0, // times_to_fail_recreate_offscreen
- false, // fallback_context_works
- },
- { 0, // times_to_lose_during_commit
- 1, // times_to_lose_during_draw
- 0, // times_to_fail_recreate
- 0, // times_to_fail_recreate_offscreen
- false, // fallback_context_works
- },
- { 1, // times_to_lose_during_commit
- 0, // times_to_lose_during_draw
- 3, // times_to_fail_recreate
- 0, // times_to_fail_recreate_offscreen
- false, // fallback_context_works
- },
- { 0, // times_to_lose_during_commit
- 1, // times_to_lose_during_draw
- 3, // times_to_fail_recreate
- 0, // times_to_fail_recreate_offscreen
- false, // fallback_context_works
- },
- { 1, // times_to_lose_during_commit
- 0, // times_to_lose_during_draw
- 0, // times_to_fail_recreate
- 3, // times_to_fail_recreate_offscreen
- false, // fallback_context_works
- },
- { 0, // times_to_lose_during_commit
- 1, // times_to_lose_during_draw
- 0, // times_to_fail_recreate
- 3, // times_to_fail_recreate_offscreen
- false, // fallback_context_works
- },
- // Losing the context and recreating it any number of times should
- // succeed.
- { 10, // times_to_lose_during_commit
- 0, // times_to_lose_during_draw
- 0, // times_to_fail_recreate
- 0, // times_to_fail_recreate_offscreen
- false, // fallback_context_works
- },
- { 0, // times_to_lose_during_commit
- 10, // times_to_lose_during_draw
- 0, // times_to_fail_recreate
- 0, // times_to_fail_recreate_offscreen
- false, // fallback_context_works
- },
- // Losing the context, failing to reinitialize it, and making a fallback
- // context should work.
- { 0, // times_to_lose_during_commit
- 1, // times_to_lose_during_draw
- 0, // times_to_fail_recreate
- 0, // times_to_fail_recreate_offscreen
- true, // fallback_context_works
- },
- };
+ // Losing the context and failing to recreate it (or losing it again
+ // immediately) a small number of times should succeed.
+ {1, // times_to_lose_during_commit
+ 0, // times_to_lose_during_draw
+ 0, // times_to_fail_recreate
+ false, // fallback_context_works
+ },
+ {0, // times_to_lose_during_commit
+ 1, // times_to_lose_during_draw
+ 0, // times_to_fail_recreate
+ false, // fallback_context_works
+ },
+ {1, // times_to_lose_during_commit
+ 0, // times_to_lose_during_draw
+ 3, // times_to_fail_recreate
+ false, // fallback_context_works
+ },
+ {0, // times_to_lose_during_commit
+ 1, // times_to_lose_during_draw
+ 3, // times_to_fail_recreate
+ false, // fallback_context_works
+ },
+ // Losing the context and recreating it any number of times should
+ // succeed.
+ {10, // times_to_lose_during_commit
+ 0, // times_to_lose_during_draw
+ 0, // times_to_fail_recreate
+ false, // fallback_context_works
+ },
+ {0, // times_to_lose_during_commit
+ 10, // times_to_lose_during_draw
+ 0, // times_to_fail_recreate
+ false, // fallback_context_works
+ },
+ // Losing the context, failing to reinitialize it, and making a fallback
+ // context should work.
+ {0, // times_to_lose_during_commit
+ 1, // times_to_lose_during_draw
+ 0, // times_to_fail_recreate
+ true, // fallback_context_works
+ }, };
if (test_case_ >= arraysize(kTests))
return false;
@@ -317,11 +249,8 @@ class LayerTreeHostContextTestLostContextSucceeds
times_to_lose_during_commit_ =
kTests[test_case_].times_to_lose_during_commit;
- times_to_lose_during_draw_ =
- kTests[test_case_].times_to_lose_during_draw;
+ times_to_lose_during_draw_ = kTests[test_case_].times_to_lose_during_draw;
times_to_fail_recreate_ = kTests[test_case_].times_to_fail_recreate;
- times_to_fail_recreate_offscreen_ =
- kTests[test_case_].times_to_fail_recreate_offscreen;
fallback_context_works_ = kTests[test_case_].fallback_context_works;
++test_case_;
return true;
@@ -331,7 +260,6 @@ class LayerTreeHostContextTestLostContextSucceeds
int times_to_lose_during_commit;
int times_to_lose_during_draw;
int times_to_fail_recreate;
- int times_to_fail_recreate_offscreen;
bool fallback_context_works;
};
@@ -345,30 +273,46 @@ class LayerTreeHostContextTestLostContextSucceeds
SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestLostContextSucceeds);
+class LayerTreeHostClientNotReadyDoesNotCreateOutputSurface
+ : public LayerTreeHostContextTest {
+ public:
+ LayerTreeHostClientNotReadyDoesNotCreateOutputSurface()
+ : LayerTreeHostContextTest() {}
+
+ virtual void WillBeginTest() OVERRIDE {
+ // Override and do not signal SetLayerTreeHostClientReady.
+ }
+
+ virtual void BeginTest() OVERRIDE {
+ PostSetNeedsCommitToMainThread();
+ EndTest();
+ }
+
+ virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback)
+ OVERRIDE {
+ EXPECT_TRUE(false);
+ return scoped_ptr<OutputSurface>();
+ }
+
+ virtual void DidInitializeOutputSurface() OVERRIDE { EXPECT_TRUE(false); }
+
+ virtual void AfterTest() OVERRIDE {
+ }
+};
+
+MULTI_THREAD_TEST_F(LayerTreeHostClientNotReadyDoesNotCreateOutputSurface);
+
class LayerTreeHostContextTestLostContextSucceedsWithContent
: public LayerTreeHostContextTestLostContextSucceeds {
public:
- LayerTreeHostContextTestLostContextSucceedsWithContent()
- : LayerTreeHostContextTestLostContextSucceeds() {}
-
virtual void SetupTree() OVERRIDE {
root_ = Layer::Create();
root_->SetBounds(gfx::Size(10, 10));
- root_->SetAnchorPoint(gfx::PointF());
root_->SetIsDrawable(true);
content_ = FakeContentLayer::Create(&client_);
content_->SetBounds(gfx::Size(10, 10));
- content_->SetAnchorPoint(gfx::PointF());
content_->SetIsDrawable(true);
- if (use_surface_) {
- content_->SetForceRenderSurface(true);
- // Filters require us to create an offscreen context.
- FilterOperations filters;
- filters.Append(FilterOperation::CreateGrayscaleFilter(0.5f));
- content_->SetFilters(filters);
- content_->SetBackgroundFilters(filters);
- }
root_->AddChild(content_);
@@ -391,174 +335,89 @@ class LayerTreeHostContextTestLostContextSucceedsWithContent
// TestWebGraphicsContext3D ensures that this resource is created with
// the active context.
EXPECT_TRUE(content_impl->HaveResourceForTileAt(0, 0));
-
- ContextProvider* contexts = host_impl->offscreen_context_provider();
- if (use_surface_) {
- ASSERT_TRUE(contexts);
- EXPECT_TRUE(contexts->Context3d());
- // TODO(danakj): Make a fake GrContext.
- // EXPECT_TRUE(contexts->GrContext());
- } else {
- EXPECT_FALSE(contexts);
- }
- }
-
- virtual void AfterTest() OVERRIDE {
- LayerTreeHostContextTestLostContextSucceeds::AfterTest();
- if (use_surface_) {
- // 1 create to start with +
- // 4 from test cases that lose the offscreen context directly +
- // 2 from test cases that create a fallback +
- // All the test cases that recreate both contexts only once
- // per time it is lost.
- EXPECT_EQ(4 + 1 + 2 + num_losses_, times_offscreen_created_);
- } else {
- EXPECT_EQ(0, times_offscreen_created_);
- }
}
protected:
- bool use_surface_;
FakeContentLayerClient client_;
scoped_refptr<Layer> root_;
scoped_refptr<ContentLayer> content_;
};
-TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent,
- NoSurface_SingleThread_DirectRenderer) {
- use_surface_ = false;
- RunTest(false, false, false);
-}
-
-TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent,
- NoSurface_SingleThread_DelegatingRenderer) {
- use_surface_ = false;
- RunTest(false, true, false);
-}
-
-TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent,
- NoSurface_MultiThread_DirectRenderer_MainThreadPaint) {
- use_surface_ = false;
- RunTest(true, false, false);
-}
-
-TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent,
- NoSurface_MultiThread_DelegatingRenderer_MainThreadPaint) {
- use_surface_ = false;
- RunTest(true, true, false);
-}
-
-// Surfaces don't exist with a delegating renderer.
-TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent,
- WithSurface_SingleThread_DirectRenderer) {
- use_surface_ = true;
- RunTest(false, false, false);
-}
-
-TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent,
- WithSurface_MultiThread_DirectRenderer_MainThreadPaint) {
- use_surface_ = true;
- RunTest(true, false, false);
-}
+// This test uses TiledLayer to check for a working context.
+SINGLE_AND_MULTI_THREAD_NOIMPL_TEST_F(
+ LayerTreeHostContextTestLostContextSucceedsWithContent);
-class LayerTreeHostContextTestOffscreenContextFails
+class LayerTreeHostContextTestCreateOutputSurfaceFails
: public LayerTreeHostContextTest {
public:
- virtual void SetupTree() OVERRIDE {
- root_ = Layer::Create();
- root_->SetBounds(gfx::Size(10, 10));
- root_->SetAnchorPoint(gfx::PointF());
- root_->SetIsDrawable(true);
-
- content_ = FakeContentLayer::Create(&client_);
- content_->SetBounds(gfx::Size(10, 10));
- content_->SetAnchorPoint(gfx::PointF());
- content_->SetIsDrawable(true);
- content_->SetForceRenderSurface(true);
- // Filters require us to create an offscreen context.
- FilterOperations filters;
- filters.Append(FilterOperation::CreateGrayscaleFilter(0.5f));
- content_->SetFilters(filters);
- content_->SetBackgroundFilters(filters);
-
- root_->AddChild(content_);
-
- layer_tree_host()->SetRootLayer(root_);
- LayerTreeHostContextTest::SetupTree();
- }
+ // Run a test that initially fails OutputSurface creation |times_to_fail|
+ // times. If |expect_fallback_attempt| is |true|, an attempt to create a
+ // fallback/software OutputSurface is expected to occur.
+ LayerTreeHostContextTestCreateOutputSurfaceFails(int times_to_fail,
+ bool expect_fallback_attempt)
+ : times_to_fail_(times_to_fail),
+ expect_fallback_attempt_(expect_fallback_attempt),
+ did_attempt_fallback_(false),
+ times_initialized_(0) {}
virtual void BeginTest() OVERRIDE {
- times_to_fail_create_offscreen_ = 1;
+ times_to_fail_create_ = times_to_fail_;
PostSetNeedsCommitToMainThread();
}
- virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
- ContextProvider* contexts = host_impl->offscreen_context_provider();
- EXPECT_FALSE(contexts);
-
- // This did not lead to create failure.
- times_to_expect_create_failed_ = 0;
- EndTest();
- }
-
- virtual void AfterTest() OVERRIDE {}
-
- protected:
- FakeContentLayerClient client_;
- scoped_refptr<Layer> root_;
- scoped_refptr<ContentLayer> content_;
-};
+ virtual scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(bool fallback)
+ OVERRIDE {
+ scoped_ptr<FakeOutputSurface> surface =
+ LayerTreeHostContextTest::CreateFakeOutputSurface(fallback);
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestOffscreenContextFails);
+ if (surface)
+ EXPECT_EQ(times_to_fail_, times_create_failed_);
-class LayerTreeHostContextTestLostContextFails
- : public LayerTreeHostContextTest {
- public:
- LayerTreeHostContextTestLostContextFails()
- : LayerTreeHostContextTest(),
- num_commits_(0),
- first_initialized_(false) {
- times_to_lose_during_commit_ = 1;
+ did_attempt_fallback_ = fallback;
+ return surface.Pass();
}
- virtual void BeginTest() OVERRIDE {
- PostSetNeedsCommitToMainThread();
- }
+ virtual void DidInitializeOutputSurface() OVERRIDE { times_initialized_++; }
- virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
- if (first_initialized_) {
- EXPECT_FALSE(succeeded);
- EndTest();
- } else {
- first_initialized_ = true;
- }
+ virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
+ EndTest();
}
- virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
- LayerTreeHostContextTest::CommitCompleteOnThread(host_impl);
+ virtual void AfterTest() OVERRIDE {
+ EXPECT_EQ(times_to_fail_, times_create_failed_);
+ EXPECT_NE(0, times_initialized_);
+ EXPECT_EQ(expect_fallback_attempt_, did_attempt_fallback_);
+ }
- ++num_commits_;
- if (num_commits_ == 1) {
- // When the context is ok, we should have these things.
- EXPECT_TRUE(host_impl->output_surface());
- EXPECT_TRUE(host_impl->renderer());
- EXPECT_TRUE(host_impl->resource_provider());
- return;
- }
+ private:
+ int times_to_fail_;
+ bool expect_fallback_attempt_;
+ bool did_attempt_fallback_;
+ int times_initialized_;
+};
- // When context recreation fails we shouldn't be left with any of them.
- EXPECT_FALSE(host_impl->output_surface());
- EXPECT_FALSE(host_impl->renderer());
- EXPECT_FALSE(host_impl->resource_provider());
- }
+class LayerTreeHostContextTestCreateOutputSurfaceFailsOnce
+ : public LayerTreeHostContextTestCreateOutputSurfaceFails {
+ public:
+ LayerTreeHostContextTestCreateOutputSurfaceFailsOnce()
+ : LayerTreeHostContextTestCreateOutputSurfaceFails(1, false) {}
+};
- virtual void AfterTest() OVERRIDE {}
+SINGLE_AND_MULTI_THREAD_TEST_F(
+ LayerTreeHostContextTestCreateOutputSurfaceFailsOnce);
- private:
- int num_commits_;
- bool first_initialized_;
+// After 4 failures we expect an attempt to create a fallback/software
+// OutputSurface.
+class LayerTreeHostContextTestCreateOutputSurfaceFailsWithFallback
+ : public LayerTreeHostContextTestCreateOutputSurfaceFails {
+ public:
+ LayerTreeHostContextTestCreateOutputSurfaceFailsWithFallback()
+ : LayerTreeHostContextTestCreateOutputSurfaceFails(4, true) {}
};
+SINGLE_AND_MULTI_THREAD_TEST_F(
+ LayerTreeHostContextTestCreateOutputSurfaceFailsWithFallback);
+
class LayerTreeHostContextTestLostContextAndEvictTextures
: public LayerTreeHostContextTest {
public:
@@ -574,18 +433,15 @@ class LayerTreeHostContextTestLostContextAndEvictTextures
LayerTreeHostContextTest::SetupTree();
}
- virtual void BeginTest() OVERRIDE {
- PostSetNeedsCommitToMainThread();
- }
+ virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
void PostEvictTextures() {
if (HasImplThread()) {
ImplThreadTaskRunner()->PostTask(
FROM_HERE,
- base::Bind(
- &LayerTreeHostContextTestLostContextAndEvictTextures::
- EvictTexturesOnImplThread,
- base::Unretained(this)));
+ base::Bind(&LayerTreeHostContextTestLostContextAndEvictTextures::
+ EvictTexturesOnImplThread,
+ base::Unretained(this)));
} else {
DebugScopedSetImplThread impl(proxy());
EvictTexturesOnImplThread();
@@ -615,10 +471,7 @@ class LayerTreeHostContextTestLostContextAndEvictTextures
impl_host_ = impl;
}
- virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
- EXPECT_TRUE(succeeded);
- EndTest();
- }
+ virtual void DidInitializeOutputSurface() OVERRIDE { EndTest(); }
virtual void AfterTest() OVERRIDE {}
@@ -730,19 +583,13 @@ class LayerTreeHostContextTestLostContextWhileUpdatingResources
LayerTreeHostContextTest::SetupTree();
}
- virtual void BeginTest() OVERRIDE {
- PostSetNeedsCommitToMainThread();
- }
+ virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
EXPECT_EQ(0, times_to_lose_on_end_query_);
EndTest();
}
- virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
- EXPECT_TRUE(succeeded);
- }
-
virtual void AfterTest() OVERRIDE {
EXPECT_EQ(0, times_to_lose_on_end_query_);
}
@@ -757,12 +604,10 @@ class LayerTreeHostContextTestLostContextWhileUpdatingResources
SINGLE_AND_MULTI_THREAD_NOIMPL_TEST_F(
LayerTreeHostContextTestLostContextWhileUpdatingResources);
-class LayerTreeHostContextTestLayersNotified
- : public LayerTreeHostContextTest {
+class LayerTreeHostContextTestLayersNotified : public LayerTreeHostContextTest {
public:
LayerTreeHostContextTestLayersNotified()
- : LayerTreeHostContextTest(),
- num_commits_(0) {}
+ : LayerTreeHostContextTest(), num_commits_(0) {}
virtual void SetupTree() OVERRIDE {
root_ = FakeContentLayer::Create(&client_);
@@ -776,19 +621,17 @@ class LayerTreeHostContextTestLayersNotified
LayerTreeHostContextTest::SetupTree();
}
- virtual void BeginTest() OVERRIDE {
- PostSetNeedsCommitToMainThread();
- }
+ virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
virtual void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
LayerTreeHostContextTest::DidActivateTreeOnThread(host_impl);
FakeContentLayerImpl* root = static_cast<FakeContentLayerImpl*>(
host_impl->active_tree()->root_layer());
- FakeContentLayerImpl* child = static_cast<FakeContentLayerImpl*>(
- root->children()[0]);
- FakeContentLayerImpl* grandchild = static_cast<FakeContentLayerImpl*>(
- child->children()[0]);
+ FakeContentLayerImpl* child =
+ static_cast<FakeContentLayerImpl*>(root->children()[0]);
+ FakeContentLayerImpl* grandchild =
+ static_cast<FakeContentLayerImpl*>(child->children()[0]);
++num_commits_;
switch (num_commits_) {
@@ -827,25 +670,22 @@ SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestLayersNotified);
class LayerTreeHostContextTestDontUseLostResources
: public LayerTreeHostContextTest {
public:
- LayerTreeHostContextTestDontUseLostResources()
- : lost_context_(false) {
+ LayerTreeHostContextTestDontUseLostResources() : lost_context_(false) {
context_should_support_io_surface_ = true;
child_output_surface_ = FakeOutputSurface::Create3d();
child_output_surface_->BindToClient(&output_surface_client_);
- child_resource_provider_ =
- ResourceProvider::Create(child_output_surface_.get(),
- NULL,
- 0,
- false,
- 1);
+ shared_bitmap_manager_.reset(new TestSharedBitmapManager());
+ child_resource_provider_ = ResourceProvider::Create(
+ child_output_surface_.get(), shared_bitmap_manager_.get(), 0, false, 1,
+ false);
}
static void EmptyReleaseCallback(unsigned sync_point, bool lost) {}
virtual void SetupTree() OVERRIDE {
- blink::WebGraphicsContext3D* context3d =
- child_output_surface_->context_provider()->Context3d();
+ gpu::gles2::GLES2Interface* gl =
+ child_output_surface_->context_provider()->ContextGL();
scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
@@ -882,46 +722,40 @@ class LayerTreeHostContextTestDontUseLostResources
resource);
gpu::Mailbox mailbox;
- context3d->genMailboxCHROMIUM(mailbox.name);
- unsigned sync_point = context3d->insertSyncPoint();
+ gl->GenMailboxCHROMIUM(mailbox.name);
+ GLuint sync_point = gl->InsertSyncPointCHROMIUM();
scoped_refptr<Layer> root = Layer::Create();
root->SetBounds(gfx::Size(10, 10));
- root->SetAnchorPoint(gfx::PointF());
root->SetIsDrawable(true);
scoped_refptr<FakeDelegatedRendererLayer> delegated =
FakeDelegatedRendererLayer::Create(delegated_frame_provider_.get());
delegated->SetBounds(gfx::Size(10, 10));
- delegated->SetAnchorPoint(gfx::PointF());
delegated->SetIsDrawable(true);
root->AddChild(delegated);
scoped_refptr<ContentLayer> content = ContentLayer::Create(&client_);
content->SetBounds(gfx::Size(10, 10));
- content->SetAnchorPoint(gfx::PointF());
content->SetIsDrawable(true);
root->AddChild(content);
scoped_refptr<TextureLayer> texture = TextureLayer::CreateForMailbox(NULL);
texture->SetBounds(gfx::Size(10, 10));
- texture->SetAnchorPoint(gfx::PointF());
texture->SetIsDrawable(true);
texture->SetTextureMailbox(
- TextureMailbox(mailbox, sync_point),
- SingleReleaseCallback::Create(base::Bind(
- &LayerTreeHostContextTestDontUseLostResources::
- EmptyReleaseCallback)));
+ TextureMailbox(mailbox, GL_TEXTURE_2D, sync_point),
+ SingleReleaseCallback::Create(
+ base::Bind(&LayerTreeHostContextTestDontUseLostResources::
+ EmptyReleaseCallback)));
root->AddChild(texture);
scoped_refptr<ContentLayer> mask = ContentLayer::Create(&client_);
mask->SetBounds(gfx::Size(10, 10));
- mask->SetAnchorPoint(gfx::PointF());
scoped_refptr<ContentLayer> content_with_mask =
ContentLayer::Create(&client_);
content_with_mask->SetBounds(gfx::Size(10, 10));
- content_with_mask->SetAnchorPoint(gfx::PointF());
content_with_mask->SetIsDrawable(true);
content_with_mask->SetMaskLayer(mask.get());
root->AddChild(content_with_mask);
@@ -929,50 +763,41 @@ class LayerTreeHostContextTestDontUseLostResources
scoped_refptr<VideoLayer> video_color =
VideoLayer::Create(&color_frame_provider_);
video_color->SetBounds(gfx::Size(10, 10));
- video_color->SetAnchorPoint(gfx::PointF());
video_color->SetIsDrawable(true);
root->AddChild(video_color);
scoped_refptr<VideoLayer> video_hw =
VideoLayer::Create(&hw_frame_provider_);
video_hw->SetBounds(gfx::Size(10, 10));
- video_hw->SetAnchorPoint(gfx::PointF());
video_hw->SetIsDrawable(true);
root->AddChild(video_hw);
scoped_refptr<VideoLayer> video_scaled_hw =
VideoLayer::Create(&scaled_hw_frame_provider_);
video_scaled_hw->SetBounds(gfx::Size(10, 10));
- video_scaled_hw->SetAnchorPoint(gfx::PointF());
video_scaled_hw->SetIsDrawable(true);
root->AddChild(video_scaled_hw);
color_video_frame_ = VideoFrame::CreateColorFrame(
gfx::Size(4, 4), 0x80, 0x80, 0x80, base::TimeDelta());
- hw_video_frame_ = VideoFrame::WrapNativeTexture(
- make_scoped_ptr(new VideoFrame::MailboxHolder(
- mailbox,
- sync_point,
- VideoFrame::MailboxHolder::TextureNoLongerNeededCallback())),
- GL_TEXTURE_2D,
- gfx::Size(4, 4),
- gfx::Rect(0, 0, 4, 4),
- gfx::Size(4, 4),
- base::TimeDelta(),
- VideoFrame::ReadPixelsCB(),
- base::Closure());
- scaled_hw_video_frame_ = VideoFrame::WrapNativeTexture(
- make_scoped_ptr(new VideoFrame::MailboxHolder(
- mailbox,
- sync_point,
- VideoFrame::MailboxHolder::TextureNoLongerNeededCallback())),
- GL_TEXTURE_2D,
- gfx::Size(4, 4),
- gfx::Rect(0, 0, 3, 2),
- gfx::Size(4, 4),
- base::TimeDelta(),
- VideoFrame::ReadPixelsCB(),
- base::Closure());
+ hw_video_frame_ =
+ VideoFrame::WrapNativeTexture(make_scoped_ptr(new gpu::MailboxHolder(
+ mailbox, GL_TEXTURE_2D, sync_point)),
+ media::VideoFrame::ReleaseMailboxCB(),
+ gfx::Size(4, 4),
+ gfx::Rect(0, 0, 4, 4),
+ gfx::Size(4, 4),
+ base::TimeDelta(),
+ VideoFrame::ReadPixelsCB());
+ scaled_hw_video_frame_ =
+ VideoFrame::WrapNativeTexture(make_scoped_ptr(new gpu::MailboxHolder(
+ mailbox, GL_TEXTURE_2D, sync_point)),
+ media::VideoFrame::ReleaseMailboxCB(),
+ gfx::Size(4, 4),
+ gfx::Rect(0, 0, 3, 2),
+ gfx::Size(4, 4),
+ base::TimeDelta(),
+ VideoFrame::ReadPixelsCB());
color_frame_provider_.set_frame(color_video_frame_);
hw_frame_provider_.set_frame(hw_video_frame_);
@@ -982,7 +807,6 @@ class LayerTreeHostContextTestDontUseLostResources
// TODO(danakj): IOSurface layer can not be transported. crbug.com/239335
scoped_refptr<IOSurfaceLayer> io_surface = IOSurfaceLayer::Create();
io_surface->SetBounds(gfx::Size(10, 10));
- io_surface->SetAnchorPoint(gfx::PointF());
io_surface->SetIsDrawable(true);
io_surface->SetIOSurfaceProperties(1, gfx::Size(10, 10));
root->AddChild(io_surface);
@@ -997,7 +821,6 @@ class LayerTreeHostContextTestDontUseLostResources
PaintedScrollbarLayer::Create(
scoped_ptr<Scrollbar>(new FakeScrollbar).Pass(), content->id());
scrollbar->SetBounds(gfx::Size(10, 10));
- scrollbar->SetAnchorPoint(gfx::PointF());
scrollbar->SetIsDrawable(true);
root->AddChild(scrollbar);
@@ -1019,30 +842,33 @@ class LayerTreeHostContextTestDontUseLostResources
}
}
- virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
- LayerTreeHostImpl::FrameData* frame,
- bool result) OVERRIDE {
+ virtual DrawResult PrepareToDrawOnThread(
+ LayerTreeHostImpl* host_impl,
+ LayerTreeHostImpl::FrameData* frame,
+ DrawResult draw_result) OVERRIDE {
if (host_impl->active_tree()->source_frame_number() == 2) {
// Lose the context during draw on the second commit. This will cause
// a third commit to recover.
context3d_->set_times_bind_texture_succeeds(0);
}
- return true;
+ return draw_result;
}
- virtual scoped_ptr<OutputSurface> CreateOutputSurface(
- bool fallback) OVERRIDE {
- if (layer_tree_host()) {
+ virtual scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(bool fallback)
+ OVERRIDE {
+ // This will get called twice:
+ // First when we create the initial output surface...
+ if (layer_tree_host()->source_frame_number() > 0) {
+ // ... and then again after we forced the context to be lost.
lost_context_ = true;
- EXPECT_EQ(layer_tree_host()->source_frame_number(), 3);
}
- return LayerTreeHostContextTest::CreateOutputSurface(fallback);
+ return LayerTreeHostContextTest::CreateFakeOutputSurface(fallback);
}
virtual void DidCommitAndDrawFrame() OVERRIDE {
ASSERT_TRUE(layer_tree_host()->hud_layer());
// End the test once we know the 3nd frame drew.
- if (layer_tree_host()->source_frame_number() < 4) {
+ if (layer_tree_host()->source_frame_number() < 5) {
layer_tree_host()->root_layer()->SetNeedsDisplay();
layer_tree_host()->SetNeedsCommit();
} else {
@@ -1050,9 +876,7 @@ class LayerTreeHostContextTestDontUseLostResources
}
}
- virtual void AfterTest() OVERRIDE {
- EXPECT_TRUE(lost_context_);
- }
+ virtual void AfterTest() OVERRIDE { EXPECT_TRUE(lost_context_); }
private:
FakeContentLayerClient client_;
@@ -1060,6 +884,7 @@ class LayerTreeHostContextTestDontUseLostResources
FakeOutputSurfaceClient output_surface_client_;
scoped_ptr<FakeOutputSurface> child_output_surface_;
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager_;
scoped_ptr<ResourceProvider> child_resource_provider_;
scoped_refptr<DelegatedFrameResourceCollection>
@@ -1077,238 +902,6 @@ class LayerTreeHostContextTestDontUseLostResources
SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestDontUseLostResources);
-class LayerTreeHostContextTestCompositeAndReadbackBeforeOutputSurfaceInit
- : public LayerTreeHostContextTest {
- public:
- virtual void BeginTest() OVERRIDE {
- // This must be called immediately after creating LTH, before the first
- // OutputSurface is initialized.
- ASSERT_TRUE(layer_tree_host()->output_surface_lost());
-
- times_output_surface_created_ = 0;
-
- // Post the SetNeedsCommit before the readback to make sure it is run
- // on the main thread before the readback's replacement commit when
- // we have a threaded compositor.
- PostSetNeedsCommitToMainThread();
-
- char pixels[4];
- bool result = layer_tree_host()->CompositeAndReadback(
- &pixels, gfx::Rect(1, 1));
- EXPECT_EQ(!delegating_renderer(), result);
- EXPECT_EQ(1, times_output_surface_created_);
- }
-
- virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
- EXPECT_TRUE(succeeded);
- ++times_output_surface_created_;
- }
-
- virtual void DidCommitAndDrawFrame() OVERRIDE {
- EndTest();
- }
-
- virtual void AfterTest() OVERRIDE {
- // Should not try to create output surface again after successfully
- // created by CompositeAndReadback.
- EXPECT_EQ(1, times_output_surface_created_);
- }
-
- virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
- LayerTreeHostImpl::FrameData* frame_data,
- bool result) OVERRIDE {
- EXPECT_GE(host_impl->active_tree()->source_frame_number(), 0);
- EXPECT_LE(host_impl->active_tree()->source_frame_number(), 1);
- return true;
- }
-
- virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
- // We should only draw for the readback and the replacement commit.
- // The replacement commit will also be the first commit after output
- // surface initialization.
- EXPECT_GE(host_impl->active_tree()->source_frame_number(), 0);
- EXPECT_LE(host_impl->active_tree()->source_frame_number(), 1);
- }
-
- virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl,
- bool result) OVERRIDE {
- // We should only swap for the replacement commit.
- EXPECT_EQ(host_impl->active_tree()->source_frame_number(), 1);
- EndTest();
- }
-
- private:
- int times_output_surface_created_;
-};
-
-SINGLE_AND_MULTI_THREAD_TEST_F(
- LayerTreeHostContextTestCompositeAndReadbackBeforeOutputSurfaceInit);
-
-// This test verifies that losing an output surface during a
-// simultaneous readback and forced redraw works and does not deadlock.
-class LayerTreeHostContextTestLoseOutputSurfaceDuringReadbackAndForcedDraw
- : public LayerTreeHostContextTest {
- protected:
- static const int kFirstOutputSurfaceInitSourceFrameNumber = 0;
- static const int kReadbackSourceFrameNumber = 1;
- static const int kReadbackReplacementSourceFrameNumber = 2;
- static const int kSecondOutputSurfaceInitSourceFrameNumber = 3;
-
- LayerTreeHostContextTestLoseOutputSurfaceDuringReadbackAndForcedDraw()
- : did_react_to_first_commit_(false) {}
-
- virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
- // This enables forced draws after a single prepare to draw failure.
- settings->timeout_and_draw_when_animation_checkerboards = true;
- settings->maximum_number_of_failed_draws_before_draw_is_forced_ = 1;
- }
-
- virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
-
- virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
- LayerTreeHostImpl::FrameData* frame_data,
- bool result) OVERRIDE {
- int sfn = host_impl->active_tree()->source_frame_number();
- EXPECT_TRUE(sfn == kFirstOutputSurfaceInitSourceFrameNumber ||
- sfn == kSecondOutputSurfaceInitSourceFrameNumber ||
- sfn == kReadbackSourceFrameNumber)
- << sfn;
-
- // Before we react to the failed draw by initiating the forced draw
- // sequence, start a readback on the main thread and then lose the context
- // to start output surface initialization all at the same time.
- if (sfn == kFirstOutputSurfaceInitSourceFrameNumber &&
- !did_react_to_first_commit_) {
- did_react_to_first_commit_ = true;
- PostReadbackToMainThread();
- LoseContext();
- }
-
- return false;
- }
-
- virtual void InitializedRendererOnThread(LayerTreeHostImpl* host_impl,
- bool success) OVERRIDE {
- // -1 is for the first output surface initialization.
- int sfn = host_impl->active_tree()->source_frame_number();
- EXPECT_TRUE(sfn == -1 || sfn == kReadbackReplacementSourceFrameNumber)
- << sfn;
- }
-
- virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
- // We should only draw the first commit after output surface initialization
- // and attempt to draw the readback commit (which will fail).
- // All others should abort because the output surface is lost.
- int sfn = host_impl->active_tree()->source_frame_number();
- EXPECT_TRUE(sfn == kSecondOutputSurfaceInitSourceFrameNumber ||
- sfn == kReadbackSourceFrameNumber)
- << sfn;
- }
-
- virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl,
- bool result) OVERRIDE {
- // We should only swap the first commit after the second output surface
- // initialization.
- int sfn = host_impl->active_tree()->source_frame_number();
- EXPECT_TRUE(sfn == kSecondOutputSurfaceInitSourceFrameNumber) << sfn;
- EndTest();
- }
-
- virtual void AfterTest() OVERRIDE {}
-
- int did_react_to_first_commit_;
-};
-
-MULTI_THREAD_TEST_F(
- LayerTreeHostContextTestLoseOutputSurfaceDuringReadbackAndForcedDraw);
-
-// This test verifies that losing an output surface right before a
-// simultaneous readback and forced redraw works and does not deadlock.
-class LayerTreeHostContextTestReadbackWithForcedDrawAndOutputSurfaceInit
- : public LayerTreeHostContextTest {
- protected:
- static const int kFirstOutputSurfaceInitSourceFrameNumber = 0;
- static const int kReadbackSourceFrameNumber = 1;
- static const int kForcedDrawCommitSourceFrameNumber = 2;
- static const int kSecondOutputSurfaceInitSourceFrameNumber = 2;
-
- LayerTreeHostContextTestReadbackWithForcedDrawAndOutputSurfaceInit()
- : did_lose_context_(false) {}
-
- virtual void InitializeSettings(LayerTreeSettings* settings) OVERRIDE {
- // This enables forced draws after a single prepare to draw failure.
- settings->timeout_and_draw_when_animation_checkerboards = true;
- settings->maximum_number_of_failed_draws_before_draw_is_forced_ = 1;
- }
-
- virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
-
- virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
- LayerTreeHostImpl::FrameData* frame_data,
- bool result) OVERRIDE {
- int sfn = host_impl->active_tree()->source_frame_number();
- EXPECT_TRUE(sfn == kFirstOutputSurfaceInitSourceFrameNumber ||
- sfn == kSecondOutputSurfaceInitSourceFrameNumber ||
- sfn == kReadbackSourceFrameNumber)
- << sfn;
-
- // Before we react to the failed draw by initiating the forced draw
- // sequence, start a readback on the main thread and then lose the context
- // to start output surface initialization all at the same time.
- if (sfn == kFirstOutputSurfaceInitSourceFrameNumber && !did_lose_context_) {
- did_lose_context_ = true;
- LoseContext();
- }
-
- // Returning false will result in a forced draw.
- return false;
- }
-
- virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
- EXPECT_TRUE(succeeded);
- if (layer_tree_host()->source_frame_number() > 0) {
- // Perform a readback right after the second output surface
- // initialization.
- char pixels[4];
- layer_tree_host()->CompositeAndReadback(&pixels, gfx::Rect(0, 0, 1, 1));
- }
- }
-
- virtual void InitializedRendererOnThread(LayerTreeHostImpl* host_impl,
- bool success) OVERRIDE {
- // -1 is for the first output surface initialization.
- int sfn = host_impl->active_tree()->source_frame_number();
- EXPECT_TRUE(sfn == -1 || sfn == kFirstOutputSurfaceInitSourceFrameNumber)
- << sfn;
- }
-
- virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
- // We should only draw the first commit after output surface initialization
- // and attempt to draw the readback commit (which will fail).
- // All others should abort because the output surface is lost.
- int sfn = host_impl->active_tree()->source_frame_number();
- EXPECT_TRUE(sfn == kForcedDrawCommitSourceFrameNumber ||
- sfn == kReadbackSourceFrameNumber)
- << sfn;
- }
-
- virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl,
- bool result) OVERRIDE {
- // We should only swap the first commit after the second output surface
- // initialization.
- int sfn = host_impl->active_tree()->source_frame_number();
- EXPECT_TRUE(sfn == kForcedDrawCommitSourceFrameNumber) << sfn;
- EndTest();
- }
-
- virtual void AfterTest() OVERRIDE {}
-
- int did_lose_context_;
-};
-
-MULTI_THREAD_TEST_F(
- LayerTreeHostContextTestReadbackWithForcedDrawAndOutputSurfaceInit);
-
class ImplSidePaintingLayerTreeHostContextTest
: public LayerTreeHostContextTest {
public:
@@ -1323,12 +916,10 @@ class LayerTreeHostContextTestImplSidePainting
virtual void SetupTree() OVERRIDE {
scoped_refptr<Layer> root = Layer::Create();
root->SetBounds(gfx::Size(10, 10));
- root->SetAnchorPoint(gfx::PointF());
root->SetIsDrawable(true);
scoped_refptr<PictureLayer> picture = PictureLayer::Create(&client_);
picture->SetBounds(gfx::Size(10, 10));
- picture->SetAnchorPoint(gfx::PointF());
picture->SetIsDrawable(true);
root->AddChild(picture);
@@ -1343,10 +934,7 @@ class LayerTreeHostContextTestImplSidePainting
virtual void AfterTest() OVERRIDE {}
- virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
- EXPECT_TRUE(succeeded);
- EndTest();
- }
+ virtual void DidInitializeOutputSurface() OVERRIDE { EndTest(); }
private:
FakeContentLayerClient client_;
@@ -1360,8 +948,8 @@ class ScrollbarLayerLostContext : public LayerTreeHostContextTest {
virtual 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->id());
scrollbar_layer_->SetBounds(gfx::Size(10, 100));
layer_tree_host()->root_layer()->AddChild(scrollbar_layer_);
layer_tree_host()->root_layer()->AddChild(scroll_layer);
@@ -1405,43 +993,6 @@ class ScrollbarLayerLostContext : public LayerTreeHostContextTest {
SINGLE_AND_MULTI_THREAD_TEST_F(ScrollbarLayerLostContext);
-// Not reusing LayerTreeTest because it expects creating LTH to always succeed.
-class LayerTreeHostTestCannotCreateIfCannotCreateOutputSurface
- : public testing::Test,
- public FakeLayerTreeHostClient {
- public:
- LayerTreeHostTestCannotCreateIfCannotCreateOutputSurface()
- : FakeLayerTreeHostClient(FakeLayerTreeHostClient::DIRECT_3D) {}
-
- // FakeLayerTreeHostClient implementation.
- virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback)
- OVERRIDE {
- return scoped_ptr<OutputSurface>();
- }
-
- void RunTest(bool threaded,
- bool delegating_renderer,
- bool impl_side_painting) {
- LayerTreeSettings settings;
- settings.impl_side_painting = impl_side_painting;
- if (threaded) {
- scoped_ptr<base::Thread> impl_thread(new base::Thread("LayerTreeTest"));
- ASSERT_TRUE(impl_thread->Start());
- ASSERT_TRUE(impl_thread->message_loop_proxy().get());
- scoped_ptr<LayerTreeHost> layer_tree_host = LayerTreeHost::CreateThreaded(
- this, NULL, settings, impl_thread->message_loop_proxy());
- EXPECT_FALSE(layer_tree_host);
- } else {
- scoped_ptr<LayerTreeHost> layer_tree_host =
- LayerTreeHost::CreateSingleThreaded(this, this, NULL, settings);
- EXPECT_FALSE(layer_tree_host);
- }
- }
-};
-
-SINGLE_AND_MULTI_THREAD_TEST_F(
- LayerTreeHostTestCannotCreateIfCannotCreateOutputSurface);
-
class UIResourceLostTest : public LayerTreeHostContextTest {
public:
UIResourceLostTest() : time_step_(0) {}
@@ -1466,10 +1017,9 @@ class UIResourceLostTest : public LayerTreeHostContextTest {
void PostStepCompleteToMainThread() {
proxy()->MainThreadTaskRunner()->PostTask(
FROM_HERE,
- base::Bind(
- &UIResourceLostTest::StepCompleteOnMainThreadInternal,
- base::Unretained(this),
- time_step_));
+ base::Bind(&UIResourceLostTest::StepCompleteOnMainThreadInternal,
+ base::Unretained(this),
+ time_step_));
}
void PostLoseContextToImplThread() {
@@ -1477,11 +1027,9 @@ class UIResourceLostTest : public LayerTreeHostContextTest {
base::SingleThreadTaskRunner* task_runner =
HasImplThread() ? ImplThreadTaskRunner()
: base::MessageLoopProxy::current();
- task_runner->PostTask(
- FROM_HERE,
- base::Bind(
- &LayerTreeHostContextTest::LoseContext,
- base::Unretained(this)));
+ task_runner->PostTask(FROM_HERE,
+ base::Bind(&LayerTreeHostContextTest::LoseContext,
+ base::Unretained(this)));
}
protected:
@@ -1583,9 +1131,7 @@ SINGLE_AND_MULTI_THREAD_TEST_F(UIResourceLostAfterCommit);
// the resource to not exist in the manager.
class UIResourceLostBeforeCommit : public UIResourceLostTestSimple {
public:
- UIResourceLostBeforeCommit()
- : test_id0_(0),
- test_id1_(0) {}
+ UIResourceLostBeforeCommit() : test_id0_(0), test_id1_(0) {}
virtual void StepCompleteOnMainThread(int step) OVERRIDE {
switch (step) {
@@ -1810,8 +1356,7 @@ class UIResourceLostEviction : public UIResourceLostTestSimple {
virtual void DidSetVisibleOnImplTree(LayerTreeHostImpl* impl,
bool visible) OVERRIDE {
- TestWebGraphicsContext3D* context = static_cast<TestWebGraphicsContext3D*>(
- impl->output_surface()->context_provider()->Context3d());
+ TestWebGraphicsContext3D* context = TestContext();
if (!visible) {
// All resources should have been evicted.
ASSERT_EQ(0u, context->NumTextures());
@@ -1827,8 +1372,7 @@ class UIResourceLostEviction : public UIResourceLostTestSimple {
}
virtual void StepCompleteOnImplThread(LayerTreeHostImpl* impl) OVERRIDE {
- TestWebGraphicsContext3D* context = static_cast<TestWebGraphicsContext3D*>(
- impl->output_surface()->context_provider()->Context3d());
+ TestWebGraphicsContext3D* context = TestContext();
LayerTreeHostContextTest::CommitCompleteOnThread(impl);
switch (time_step_) {
case 1:
@@ -1874,8 +1418,7 @@ class LayerTreeHostContextTestSurfaceCreateCallback
public:
LayerTreeHostContextTestSurfaceCreateCallback()
: LayerTreeHostContextTest(),
- layer_(FakeContentLayer::Create(&client_)),
- num_commits_(0) {}
+ layer_(FakeContentLayer::Create(&client_)) {}
virtual void SetupTree() OVERRIDE {
layer_->SetBounds(gfx::Size(10, 20));
@@ -1883,34 +1426,31 @@ class LayerTreeHostContextTestSurfaceCreateCallback
LayerTreeHostContextTest::SetupTree();
}
- virtual void BeginTest() OVERRIDE {
- PostSetNeedsCommitToMainThread();
- }
+ virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
virtual void DidCommit() OVERRIDE {
- switch (num_commits_) {
- case 0:
- EXPECT_EQ(1u, layer_->output_surface_created_count());
- layer_tree_host()->SetNeedsCommit();
- break;
+ switch (layer_tree_host()->source_frame_number()) {
case 1:
EXPECT_EQ(1u, layer_->output_surface_created_count());
layer_tree_host()->SetNeedsCommit();
break;
case 2:
EXPECT_EQ(1u, layer_->output_surface_created_count());
+ layer_tree_host()->SetNeedsCommit();
break;
case 3:
+ EXPECT_EQ(1u, layer_->output_surface_created_count());
+ break;
+ case 4:
EXPECT_EQ(2u, layer_->output_surface_created_count());
layer_tree_host()->SetNeedsCommit();
break;
}
- ++num_commits_;
}
virtual void CommitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
LayerTreeHostContextTest::CommitCompleteOnThread(impl);
- switch (num_commits_) {
+ switch (LastCommittedSourceFrameNumber(impl)) {
case 0:
break;
case 1:
@@ -1924,19 +1464,73 @@ class LayerTreeHostContextTestSurfaceCreateCallback
}
}
- virtual void DidInitializeOutputSurface(bool succeeded) OVERRIDE {
- EXPECT_TRUE(succeeded);
- }
-
virtual void AfterTest() OVERRIDE {}
protected:
FakeContentLayerClient client_;
scoped_refptr<FakeContentLayer> layer_;
- int num_commits_;
};
SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestSurfaceCreateCallback);
+class LayerTreeHostContextTestLoseAfterSendingBeginMainFrame
+ : public LayerTreeHostContextTest {
+ protected:
+ virtual void BeginTest() OVERRIDE {
+ deferred_ = false;
+ PostSetNeedsCommitToMainThread();
+ }
+
+ virtual void ScheduledActionWillSendBeginMainFrame() OVERRIDE {
+ if (deferred_)
+ return;
+ deferred_ = true;
+
+ // Defer commits before the BeginFrame arrives, causing it to be delayed.
+ MainThreadTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(&LayerTreeHostContextTestLoseAfterSendingBeginMainFrame::
+ DeferCommitsOnMainThread,
+ base::Unretained(this),
+ true));
+ // Meanwhile, lose the context while we are in defer commits.
+ ImplThreadTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(&LayerTreeHostContextTestLoseAfterSendingBeginMainFrame::
+ LoseContextOnImplThread,
+ base::Unretained(this)));
+ }
+
+ void LoseContextOnImplThread() {
+ LoseContext();
+
+ // After losing the context, stop deferring commits.
+ MainThreadTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(&LayerTreeHostContextTestLoseAfterSendingBeginMainFrame::
+ DeferCommitsOnMainThread,
+ base::Unretained(this),
+ false));
+ }
+
+ void DeferCommitsOnMainThread(bool defer_commits) {
+ layer_tree_host()->SetDeferCommits(defer_commits);
+ }
+
+ virtual void WillBeginMainFrame() OVERRIDE {
+ // Don't begin a frame with a lost surface.
+ EXPECT_FALSE(layer_tree_host()->output_surface_lost());
+ }
+
+ virtual void DidCommitAndDrawFrame() OVERRIDE { EndTest(); }
+
+ virtual void AfterTest() OVERRIDE {}
+
+ bool deferred_;
+};
+
+// TODO(danakj): We don't use scheduler with SingleThreadProxy yet.
+MULTI_THREAD_TEST_F(LayerTreeHostContextTestLoseAfterSendingBeginMainFrame);
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc b/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc
index c06f345ef17..12fc63128f0 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc
@@ -103,16 +103,12 @@ class LayerTreeHostCopyRequestTestMultipleRequests
virtual void AfterTest() OVERRIDE { EXPECT_EQ(4u, callbacks_.size()); }
- virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback)
+ virtual scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(bool fallback)
OVERRIDE {
- scoped_ptr<FakeOutputSurface> output_surface;
- if (use_gl_renderer_) {
- output_surface = FakeOutputSurface::Create3d().Pass();
- } else {
- output_surface = FakeOutputSurface::CreateSoftware(
- make_scoped_ptr(new SoftwareOutputDevice)).Pass();
- }
- return output_surface.PassAs<OutputSurface>();
+ if (use_gl_renderer_)
+ return FakeOutputSurface::Create3d();
+ return FakeOutputSurface::CreateSoftware(
+ make_scoped_ptr(new SoftwareOutputDevice));
}
bool use_gl_renderer_;
@@ -538,18 +534,16 @@ SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F(
class LayerTreeHostCopyRequestTestLostOutputSurface
: public LayerTreeHostCopyRequestTest {
protected:
- virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback)
+ virtual scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(bool fallback)
OVERRIDE {
if (!first_context_provider_.get()) {
first_context_provider_ = TestContextProvider::Create();
- return FakeOutputSurface::Create3d(first_context_provider_)
- .PassAs<OutputSurface>();
+ return FakeOutputSurface::Create3d(first_context_provider_);
}
EXPECT_FALSE(second_context_provider_.get());
second_context_provider_ = TestContextProvider::Create();
- return FakeOutputSurface::Create3d(second_context_provider_)
- .PassAs<OutputSurface>();
+ return FakeOutputSurface::Create3d(second_context_provider_);
}
virtual void SetupTree() OVERRIDE {
@@ -670,11 +664,10 @@ SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F(
class LayerTreeHostCopyRequestTestCountTextures
: public LayerTreeHostCopyRequestTest {
protected:
- virtual scoped_ptr<OutputSurface> CreateOutputSurface(bool fallback)
+ virtual scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(bool fallback)
OVERRIDE {
context_provider_ = TestContextProvider::Create();
- return FakeOutputSurface::Create3d(context_provider_)
- .PassAs<OutputSurface>();
+ return FakeOutputSurface::Create3d(context_provider_);
}
virtual void SetupTree() OVERRIDE {
@@ -803,10 +796,12 @@ class LayerTreeHostCopyRequestTestProvideTexture
&LayerTreeHostCopyRequestTestProvideTexture::CopyOutputCallback,
base::Unretained(this)));
+ gpu::gles2::GLES2Interface* gl = external_context_provider_->ContextGL();
gpu::Mailbox mailbox;
- external_context_provider_->Context3d()->genMailboxCHROMIUM(mailbox.name);
- sync_point_ = external_context_provider_->Context3d()->insertSyncPoint();
- request->SetTextureMailbox(TextureMailbox(mailbox, sync_point_));
+ gl->GenMailboxCHROMIUM(mailbox.name);
+ sync_point_ = gl->InsertSyncPointCHROMIUM();
+ request->SetTextureMailbox(
+ TextureMailbox(mailbox, GL_TEXTURE_2D, sync_point_));
EXPECT_TRUE(request->has_texture_mailbox());
copy_layer_->RequestCopyOfOutput(request.Pass());
@@ -904,5 +899,76 @@ class LayerTreeHostCopyRequestTestDestroyBeforeCopy
SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(
LayerTreeHostCopyRequestTestDestroyBeforeCopy);
+class LayerTreeHostCopyRequestTestShutdownBeforeCopy
+ : public LayerTreeHostCopyRequestTest {
+ protected:
+ virtual void SetupTree() OVERRIDE {
+ root_ = FakeContentLayer::Create(&client_);
+ root_->SetBounds(gfx::Size(20, 20));
+
+ copy_layer_ = FakeContentLayer::Create(&client_);
+ copy_layer_->SetBounds(gfx::Size(10, 10));
+ root_->AddChild(copy_layer_);
+
+ layer_tree_host()->SetRootLayer(root_);
+ LayerTreeHostCopyRequestTest::SetupTree();
+ }
+
+ virtual void BeginTest() OVERRIDE {
+ callback_count_ = 0;
+ PostSetNeedsCommitToMainThread();
+ }
+
+ void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) {
+ EXPECT_TRUE(result->IsEmpty());
+ ++callback_count_;
+ }
+
+ virtual void DidActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
+ MainThreadTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(&LayerTreeHostCopyRequestTestShutdownBeforeCopy::DidActivate,
+ base::Unretained(this)));
+ }
+
+ void DidActivate() {
+ switch (layer_tree_host()->source_frame_number()) {
+ case 1: {
+ EXPECT_EQ(0, callback_count_);
+ // Put a copy request on the layer, but then don't allow any
+ // drawing to take place.
+ scoped_ptr<CopyOutputRequest> request =
+ CopyOutputRequest::CreateRequest(
+ base::Bind(&LayerTreeHostCopyRequestTestShutdownBeforeCopy::
+ CopyOutputCallback,
+ base::Unretained(this)));
+ copy_layer_->RequestCopyOfOutput(request.Pass());
+
+ layer_tree_host()->SetViewportSize(gfx::Size());
+ break;
+ }
+ case 2:
+ DestroyLayerTreeHost();
+ // End the test after the copy result has had a chance to get back to
+ // the main thread.
+ MainThreadTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(&LayerTreeHostCopyRequestTestShutdownBeforeCopy::EndTest,
+ base::Unretained(this)));
+ break;
+ }
+ }
+
+ virtual void AfterTest() OVERRIDE { EXPECT_EQ(1, callback_count_); }
+
+ int callback_count_;
+ FakeContentLayerClient client_;
+ scoped_refptr<FakeContentLayer> root_;
+ scoped_refptr<FakeContentLayer> copy_layer_;
+};
+
+SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(
+ LayerTreeHostCopyRequestTestShutdownBeforeCopy);
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_host_unittest_damage.cc b/chromium/cc/trees/layer_tree_host_unittest_damage.cc
index 7f008b46808..eab8ed6b60e 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_damage.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_damage.cc
@@ -48,10 +48,11 @@ class LayerTreeHostDamageTestSetNeedsRedraw
}
}
- virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* impl,
- LayerTreeHostImpl::FrameData* frame_data,
- bool result) OVERRIDE {
- EXPECT_TRUE(result);
+ virtual DrawResult PrepareToDrawOnThread(
+ LayerTreeHostImpl* impl,
+ LayerTreeHostImpl::FrameData* frame_data,
+ DrawResult draw_result) OVERRIDE {
+ EXPECT_EQ(DRAW_SUCCESS, draw_result);
RenderSurfaceImpl* root_surface =
impl->active_tree()->root_layer()->render_surface();
@@ -73,7 +74,7 @@ class LayerTreeHostDamageTestSetNeedsRedraw
}
++draw_count_;
- return result;
+ return draw_result;
}
virtual void AfterTest() OVERRIDE {}
@@ -109,10 +110,11 @@ class LayerTreeHostDamageTestSetViewportSize
}
}
- virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* impl,
- LayerTreeHostImpl::FrameData* frame_data,
- bool result) OVERRIDE {
- EXPECT_TRUE(result);
+ virtual DrawResult PrepareToDrawOnThread(
+ LayerTreeHostImpl* impl,
+ LayerTreeHostImpl::FrameData* frame_data,
+ DrawResult draw_result) OVERRIDE {
+ EXPECT_EQ(DRAW_SUCCESS, draw_result);
RenderSurfaceImpl* root_surface =
impl->active_tree()->root_layer()->render_surface();
@@ -134,7 +136,7 @@ class LayerTreeHostDamageTestSetViewportSize
}
++draw_count_;
- return result;
+ return draw_result;
}
virtual void AfterTest() OVERRIDE {}
@@ -167,10 +169,11 @@ class LayerTreeHostDamageTestNoDamageDoesNotSwap
LayerTreeHostDamageTest::SetupTree();
}
- virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
- LayerTreeHostImpl::FrameData* frame_data,
- bool result) OVERRIDE {
- EXPECT_TRUE(result);
+ virtual DrawResult PrepareToDrawOnThread(
+ LayerTreeHostImpl* host_impl,
+ LayerTreeHostImpl::FrameData* frame_data,
+ DrawResult draw_result) OVERRIDE {
+ EXPECT_EQ(DRAW_SUCCESS, draw_result);
int source_frame = host_impl->active_tree()->source_frame_number();
switch (source_frame) {
@@ -191,7 +194,7 @@ class LayerTreeHostDamageTestNoDamageDoesNotSwap
EndTest();
break;
}
- return result;
+ return draw_result;
}
virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl,
@@ -237,77 +240,6 @@ class LayerTreeHostDamageTestNoDamageDoesNotSwap
SINGLE_AND_MULTI_THREAD_NOIMPL_TEST_F(
LayerTreeHostDamageTestNoDamageDoesNotSwap);
-class LayerTreeHostDamageTestNoDamageReadbackDoesDraw
- : public LayerTreeHostDamageTest {
- virtual void BeginTest() OVERRIDE {
- PostSetNeedsCommitToMainThread();
- }
-
- virtual void SetupTree() OVERRIDE {
- scoped_refptr<FakeContentLayer> root = FakeContentLayer::Create(&client_);
- root->SetBounds(gfx::Size(10, 10));
-
- // Most of the layer isn't visible.
- content_ = FakeContentLayer::Create(&client_);
- content_->SetBounds(gfx::Size(100, 100));
- root->AddChild(content_);
-
- layer_tree_host()->SetRootLayer(root);
- LayerTreeHostDamageTest::SetupTree();
- }
-
- virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
- LayerTreeHostImpl::FrameData* frame_data,
- bool result) OVERRIDE {
- EXPECT_TRUE(result);
-
- int source_frame = host_impl->active_tree()->source_frame_number();
- switch (source_frame) {
- case 0:
- // The first frame draws and clears any damage.
- break;
- case 1: {
- // The second frame is a readback, we should have damage in the readback
- // rect, but not swap.
- RenderSurfaceImpl* root_surface =
- host_impl->active_tree()->root_layer()->render_surface();
- gfx::RectF root_damage =
- root_surface->damage_tracker()->current_damage_rect();
- root_damage.Intersect(root_surface->content_rect());
- EXPECT_TRUE(root_damage.Contains(gfx::Rect(3, 3, 1, 1)));
- break;
- }
- case 2:
- // CompositeAndReadback causes a follow-up commit.
- break;
- case 3:
- NOTREACHED();
- break;
- }
- return result;
- }
-
- virtual void DidCommitAndDrawFrame() OVERRIDE {
- int next_frame = layer_tree_host()->source_frame_number();
- switch (next_frame) {
- case 1: {
- char pixels[4];
- layer_tree_host()->CompositeAndReadback(static_cast<void*>(&pixels),
- gfx::Rect(3, 3, 1, 1));
- EndTest();
- break;
- }
- }
- }
-
- virtual void AfterTest() OVERRIDE {}
-
- FakeContentLayerClient client_;
- scoped_refptr<FakeContentLayer> content_;
-};
-
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostDamageTestNoDamageReadbackDoesDraw);
-
class LayerTreeHostDamageTestForcedFullDamage : public LayerTreeHostDamageTest {
virtual void BeginTest() OVERRIDE {
PostSetNeedsCommitToMainThread();
@@ -326,10 +258,11 @@ class LayerTreeHostDamageTestForcedFullDamage : public LayerTreeHostDamageTest {
LayerTreeHostDamageTest::SetupTree();
}
- virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
- LayerTreeHostImpl::FrameData* frame_data,
- bool result) OVERRIDE {
- EXPECT_TRUE(result);
+ virtual DrawResult PrepareToDrawOnThread(
+ LayerTreeHostImpl* host_impl,
+ LayerTreeHostImpl::FrameData* frame_data,
+ DrawResult draw_result) OVERRIDE {
+ EXPECT_EQ(DRAW_SUCCESS, draw_result);
RenderSurfaceImpl* root_surface =
host_impl->active_tree()->root_layer()->render_surface();
@@ -398,7 +331,7 @@ class LayerTreeHostDamageTestForcedFullDamage : public LayerTreeHostDamageTest {
EndTest();
break;
}
- return result;
+ return draw_result;
}
virtual void DidCommitAndDrawFrame() OVERRIDE {
@@ -428,17 +361,23 @@ class LayerTreeHostScrollbarDamageTest : public LayerTreeHostDamageTest {
root_layer->SetMasksToBounds(true);
layer_tree_host()->SetRootLayer(root_layer);
+ scoped_refptr<Layer> scroll_clip_layer = Layer::Create();
scoped_refptr<Layer> content_layer = FakeContentLayer::Create(&client_);
- content_layer->SetScrollable(true);
+ content_layer->SetScrollClipLayerId(scroll_clip_layer->id());
content_layer->SetScrollOffset(gfx::Vector2d(10, 20));
- content_layer->SetMaxScrollOffset(gfx::Vector2d(30, 50));
content_layer->SetBounds(gfx::Size(100, 200));
- root_layer->AddChild(content_layer);
+ scroll_clip_layer->SetBounds(
+ gfx::Size(content_layer->bounds().width() - 30,
+ content_layer->bounds().height() - 50));
+ scroll_clip_layer->AddChild(content_layer);
+ root_layer->AddChild(scroll_clip_layer);
scoped_refptr<Layer> scrollbar_layer =
FakePaintedScrollbarLayer::Create(false, true, content_layer->id());
scrollbar_layer->SetPosition(gfx::Point(300, 300));
scrollbar_layer->SetBounds(gfx::Size(10, 100));
+ scrollbar_layer->ToScrollbarLayer()->SetClipLayer(scroll_clip_layer->id());
+ scrollbar_layer->ToScrollbarLayer()->SetScrollLayer(content_layer->id());
root_layer->AddChild(scrollbar_layer);
gfx::RectF content_rect(content_layer->position(),
@@ -461,10 +400,11 @@ class LayerTreeHostDamageTestScrollbarDoesDamage
PostSetNeedsCommitToMainThread();
}
- virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
- LayerTreeHostImpl::FrameData* frame_data,
- bool result) OVERRIDE {
- EXPECT_TRUE(result);
+ virtual DrawResult PrepareToDrawOnThread(
+ LayerTreeHostImpl* host_impl,
+ LayerTreeHostImpl::FrameData* frame_data,
+ DrawResult draw_result) OVERRIDE {
+ EXPECT_EQ(DRAW_SUCCESS, draw_result);
RenderSurfaceImpl* root_surface =
host_impl->active_tree()->root_layer()->render_surface();
gfx::RectF root_damage =
@@ -488,7 +428,7 @@ class LayerTreeHostDamageTestScrollbarDoesDamage
EndTest();
break;
}
- return result;
+ return draw_result;
}
virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl,
@@ -496,7 +436,8 @@ class LayerTreeHostDamageTestScrollbarDoesDamage
++did_swaps_;
EXPECT_TRUE(result);
LayerImpl* root = host_impl->active_tree()->root_layer();
- LayerImpl* scroll_layer = root->children()[0];
+ LayerImpl* scroll_clip_layer = root->children()[0];
+ LayerImpl* scroll_layer = scroll_clip_layer->children()[0];
switch (did_swaps_) {
case 1:
// Test that modifying the position of the content layer (not
@@ -510,7 +451,8 @@ class LayerTreeHostDamageTestScrollbarDoesDamage
host_impl->SetNeedsRedraw();
break;
case 3:
- scroll_layer->SetMaxScrollOffset(gfx::Vector2d(60, 100));
+ scroll_layer->SetBounds(gfx::Size(root->bounds().width() + 60,
+ root->bounds().height() + 100));
host_impl->SetNeedsRedraw();
break;
}
@@ -532,10 +474,11 @@ class LayerTreeHostDamageTestScrollbarCommitDoesNoDamage
PostSetNeedsCommitToMainThread();
}
- virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
- LayerTreeHostImpl::FrameData* frame_data,
- bool result) OVERRIDE {
- EXPECT_TRUE(result);
+ virtual DrawResult PrepareToDrawOnThread(
+ LayerTreeHostImpl* host_impl,
+ LayerTreeHostImpl::FrameData* frame_data,
+ DrawResult draw_result) OVERRIDE {
+ EXPECT_EQ(DRAW_SUCCESS, draw_result);
RenderSurfaceImpl* root_surface =
host_impl->active_tree()->root_layer()->render_surface();
gfx::RectF root_damage =
@@ -561,7 +504,7 @@ class LayerTreeHostDamageTestScrollbarCommitDoesNoDamage
NOTREACHED();
break;
}
- return result;
+ return draw_result;
}
virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl,
@@ -569,7 +512,8 @@ class LayerTreeHostDamageTestScrollbarCommitDoesNoDamage
++did_swaps_;
EXPECT_TRUE(result);
LayerImpl* root = host_impl->active_tree()->root_layer();
- LayerImpl* scroll_layer = root->children()[0];
+ LayerImpl* scroll_clip_layer = root->children()[0];
+ LayerImpl* scroll_layer = scroll_clip_layer->children()[0];
switch (did_swaps_) {
case 1:
// Scroll on the thread. This should damage the scrollbar for the
@@ -622,10 +566,11 @@ class LayerTreeHostDamageTestVisibleTilesStillTriggerDraws
update_visible_tile_count_ = 0;
}
- virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
- LayerTreeHostImpl::FrameData* frame_data,
- bool result) OVERRIDE {
- EXPECT_TRUE(result);
+ virtual DrawResult PrepareToDrawOnThread(
+ LayerTreeHostImpl* host_impl,
+ LayerTreeHostImpl::FrameData* frame_data,
+ DrawResult draw_result) OVERRIDE {
+ EXPECT_EQ(DRAW_SUCCESS, draw_result);
prepare_to_draw_count_++;
switch (prepare_to_draw_count_) {
case 1:
@@ -651,7 +596,7 @@ class LayerTreeHostDamageTestVisibleTilesStillTriggerDraws
break;
}
- return result;
+ return draw_result;
}
virtual void UpdateVisibleTilesOnThread(
diff --git a/chromium/cc/trees/layer_tree_host_unittest_delegated.cc b/chromium/cc/trees/layer_tree_host_unittest_delegated.cc
index 195a4acdfa5..37c928b9bd6 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_delegated.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_delegated.cc
@@ -28,7 +28,6 @@
#include "cc/test/layer_tree_test.h"
#include "cc/trees/layer_tree_impl.h"
#include "gpu/GLES2/gl2extchromium.h"
-#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
namespace cc {
namespace {
@@ -75,8 +74,9 @@ bool ResourcesMatch(ReturnedResourceArray actual,
// These tests deal with delegated renderer layers.
class LayerTreeHostDelegatedTest : public LayerTreeTest {
protected:
- scoped_ptr<DelegatedFrameData> CreateFrameData(gfx::Rect root_output_rect,
- gfx::Rect root_damage_rect) {
+ scoped_ptr<DelegatedFrameData> CreateFrameData(
+ const gfx::Rect& root_output_rect,
+ const gfx::Rect& root_damage_rect) {
scoped_ptr<DelegatedFrameData> frame(new DelegatedFrameData);
scoped_ptr<RenderPass> root_pass(RenderPass::Create());
@@ -89,8 +89,8 @@ class LayerTreeHostDelegatedTest : public LayerTreeTest {
}
scoped_ptr<DelegatedFrameData> CreateInvalidFrameData(
- gfx::Rect root_output_rect,
- gfx::Rect root_damage_rect) {
+ const gfx::Rect& root_output_rect,
+ const gfx::Rect& root_damage_rect) {
scoped_ptr<DelegatedFrameData> frame(new DelegatedFrameData);
scoped_ptr<RenderPass> root_pass(RenderPass::Create());
@@ -99,10 +99,12 @@ class LayerTreeHostDelegatedTest : public LayerTreeTest {
root_damage_rect,
gfx::Transform());
- scoped_ptr<SharedQuadState> shared_quad_state = SharedQuadState::Create();
+ SharedQuadState* shared_quad_state =
+ root_pass->CreateAndAppendSharedQuadState();
gfx::Rect rect = root_output_rect;
gfx::Rect opaque_rect = root_output_rect;
+ gfx::Rect visible_rect = root_output_rect;
// An invalid resource id! The resource isn't part of the frame.
unsigned resource_id = 5;
bool premultiplied_alpha = false;
@@ -113,9 +115,10 @@ class LayerTreeHostDelegatedTest : public LayerTreeTest {
bool flipped = false;
scoped_ptr<TextureDrawQuad> invalid_draw_quad = TextureDrawQuad::Create();
- invalid_draw_quad->SetNew(shared_quad_state.get(),
+ invalid_draw_quad->SetNew(shared_quad_state,
rect,
opaque_rect,
+ visible_rect,
resource_id,
premultiplied_alpha,
uv_top_left,
@@ -125,8 +128,6 @@ class LayerTreeHostDelegatedTest : public LayerTreeTest {
flipped);
root_pass->quad_list.push_back(invalid_draw_quad.PassAs<DrawQuad>());
- root_pass->shared_quad_state_list.push_back(shared_quad_state.Pass());
-
frame->render_pass_list.push_back(root_pass.Pass());
return frame.Pass();
}
@@ -135,16 +136,23 @@ class LayerTreeHostDelegatedTest : public LayerTreeTest {
ResourceProvider::ResourceId resource_id) {
TransferableResource resource;
resource.id = resource_id;
- resource.target = GL_TEXTURE_2D;
+ resource.mailbox_holder.texture_target = GL_TEXTURE_2D;
+ GLbyte arbitrary_mailbox[GL_MAILBOX_SIZE_CHROMIUM] = {
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2,
+ 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4};
+ resource.mailbox_holder.mailbox.SetName(arbitrary_mailbox);
frame->resource_list.push_back(resource);
}
void AddTextureQuad(DelegatedFrameData* frame,
ResourceProvider::ResourceId resource_id) {
- scoped_ptr<SharedQuadState> sqs = SharedQuadState::Create();
+ SharedQuadState* sqs =
+ frame->render_pass_list[0]->CreateAndAppendSharedQuadState();
scoped_ptr<TextureDrawQuad> quad = TextureDrawQuad::Create();
float vertex_opacity[4] = { 1.f, 1.f, 1.f, 1.f };
- quad->SetNew(sqs.get(),
+ quad->SetNew(sqs,
+ gfx::Rect(0, 0, 10, 10),
gfx::Rect(0, 0, 10, 10),
gfx::Rect(0, 0, 10, 10),
resource_id,
@@ -154,14 +162,13 @@ class LayerTreeHostDelegatedTest : public LayerTreeTest {
SK_ColorTRANSPARENT,
vertex_opacity,
false);
- frame->render_pass_list[0]->shared_quad_state_list.push_back(sqs.Pass());
frame->render_pass_list[0]->quad_list.push_back(quad.PassAs<DrawQuad>());
}
void AddRenderPass(DelegatedFrameData* frame,
RenderPass::Id id,
- gfx::Rect output_rect,
- gfx::Rect damage_rect,
+ const gfx::Rect& output_rect,
+ const gfx::Rect& damage_rect,
const FilterOperations& filters,
const FilterOperations& background_filters) {
for (size_t i = 0; i < frame->render_pass_list.size(); ++i)
@@ -174,19 +181,20 @@ class LayerTreeHostDelegatedTest : public LayerTreeTest {
gfx::Transform());
frame->render_pass_list.push_back(pass.Pass());
- scoped_ptr<SharedQuadState> sqs = SharedQuadState::Create();
+ SharedQuadState* sqs =
+ frame->render_pass_list[0]->CreateAndAppendSharedQuadState();
scoped_ptr<RenderPassDrawQuad> quad = RenderPassDrawQuad::Create();
- quad->SetNew(sqs.get(),
+ quad->SetNew(sqs,
+ output_rect,
output_rect,
id,
false, // is_replica
- 0, // mask_resource_id
+ 0, // mask_resource_id
damage_rect,
gfx::Rect(0, 0, 1, 1), // mask_uv_rect
filters,
background_filters);
- frame->render_pass_list[0]->shared_quad_state_list.push_back(sqs.Pass());
frame->render_pass_list[0]->quad_list.push_back(quad.PassAs<DrawQuad>());
}
@@ -231,7 +239,6 @@ class LayerTreeHostDelegatedTest : public LayerTreeTest {
for (size_t i = 0; i < resources_to_return.size(); ++i)
output_surface()->ReturnResource(resources_to_return[i], &ack);
host_impl->ReclaimResources(&ack);
- host_impl->OnSwapBuffersComplete();
}
};
@@ -247,8 +254,7 @@ class LayerTreeHostDelegatedTestCaseSingleDelegatedLayer
virtual void SetupTree() OVERRIDE {
root_ = Layer::Create();
- root_->SetAnchorPoint(gfx::PointF());
- root_->SetBounds(gfx::Size(10, 10));
+ root_->SetBounds(gfx::Size(15, 15));
layer_tree_host()->SetRootLayer(root_);
LayerTreeHostDelegatedTest::SetupTree();
@@ -284,7 +290,6 @@ class LayerTreeHostDelegatedTestCaseSingleDelegatedLayer
DelegatedFrameProvider* frame_provider) {
scoped_refptr<DelegatedRendererLayer> delegated =
FakeDelegatedRendererLayer::Create(frame_provider);
- delegated->SetAnchorPoint(gfx::PointF());
delegated->SetBounds(gfx::Size(10, 10));
delegated->SetIsDrawable(true);
@@ -333,8 +338,8 @@ class LayerTreeHostDelegatedTestCreateChildId
FakeDelegatedRendererLayerImpl* delegated_impl =
static_cast<FakeDelegatedRendererLayerImpl*>(root_impl->children()[0]);
- ContextProvider* context_provider =
- host_impl->output_surface()->context_provider();
+ TestContextProvider* context_provider = static_cast<TestContextProvider*>(
+ host_impl->output_surface()->context_provider().get());
++num_activates_;
switch (num_activates_) {
@@ -342,9 +347,10 @@ class LayerTreeHostDelegatedTestCreateChildId
EXPECT_TRUE(delegated_impl->ChildId());
EXPECT_FALSE(did_reset_child_id_);
- context_provider->Context3d()->loseContextCHROMIUM(
+ context_provider->ContextGL()->LoseContextCHROMIUM(
GL_GUILTY_CONTEXT_RESET_ARB,
GL_INNOCENT_CONTEXT_RESET_ARB);
+ context_provider->ContextGL()->Flush();
break;
case 3:
EXPECT_TRUE(delegated_impl->ChildId());
@@ -377,125 +383,86 @@ class LayerTreeHostDelegatedTestCreateChildId
SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostDelegatedTestCreateChildId);
-class LayerTreeHostDelegatedTestOffscreenContext_NoFilters
+// Test that we can gracefully handle invalid frames after the context was lost.
+// For example, we might be trying to use the previous frame in that case and
+// have to make sure we don't crash because our resource accounting goes wrong.
+class LayerTreeHostDelegatedTestInvalidFrameAfterContextLost
: public LayerTreeHostDelegatedTestCaseSingleDelegatedLayer {
- protected:
- virtual void BeginTest() OVERRIDE {
- scoped_ptr<DelegatedFrameData> frame =
- CreateFrameData(gfx::Rect(0, 0, 1, 1),
- gfx::Rect(0, 0, 1, 1));
- SetFrameData(frame.Pass());
+ public:
+ LayerTreeHostDelegatedTestInvalidFrameAfterContextLost()
+ : num_activates_(0), num_output_surfaces_initialized_(0) {}
- PostSetNeedsCommitToMainThread();
+ virtual void DidCommit() OVERRIDE {
+ if (TestEnded())
+ return;
+ scoped_ptr<DelegatedFrameData> frame1 =
+ CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1));
+ AddTextureQuad(frame1.get(), 999);
+ AddTransferableResource(frame1.get(), 999);
+ SetFrameData(frame1.Pass());
}
- virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
- EXPECT_FALSE(host_impl->offscreen_context_provider());
- EndTest();
+ virtual void DidInitializeOutputSurface() OVERRIDE {
+ if (!num_output_surfaces_initialized_++)
+ return;
+
+ scoped_refptr<DelegatedRendererLayer> old_delegated = delegated_;
+ SetFrameData(
+ CreateInvalidFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1)));
+ // Make sure we end up using the same layer, or we won't test the right
+ // thing, which is to make sure we can handle an invalid frame when using
+ // a stale layer from before the context was lost.
+ DCHECK(delegated_.get() == old_delegated.get());
}
-};
-SINGLE_AND_MULTI_THREAD_TEST_F(
- LayerTreeHostDelegatedTestOffscreenContext_NoFilters);
+ virtual void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
+ if (host_impl->active_tree()->source_frame_number() < 1)
+ return;
-class LayerTreeHostDelegatedTestOffscreenContext_Filters
- : public LayerTreeHostDelegatedTestCaseSingleDelegatedLayer {
- protected:
- virtual void BeginTest() OVERRIDE {
- scoped_ptr<DelegatedFrameData> frame =
- CreateFrameData(gfx::Rect(0, 0, 1, 1),
- gfx::Rect(0, 0, 1, 1));
-
- FilterOperations filters;
- filters.Append(FilterOperation::CreateGrayscaleFilter(0.5f));
- AddRenderPass(frame.get(),
- RenderPass::Id(2, 1),
- gfx::Rect(0, 0, 1, 1),
- gfx::Rect(0, 0, 1, 1),
- filters,
- FilterOperations());
- SetFrameData(frame.Pass());
+ TestContextProvider* context_provider = static_cast<TestContextProvider*>(
+ host_impl->output_surface()->context_provider().get());
- PostSetNeedsCommitToMainThread();
+ ++num_activates_;
+ switch (num_activates_) {
+ case 2:
+ context_provider->ContextGL()->LoseContextCHROMIUM(
+ GL_GUILTY_CONTEXT_RESET_ARB,
+ GL_INNOCENT_CONTEXT_RESET_ARB);
+ break;
+ case 3:
+ EndTest();
+ break;
+ }
}
- virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
- bool expect_context = !delegating_renderer();
- EXPECT_EQ(expect_context, !!host_impl->offscreen_context_provider());
- EndTest();
- }
-};
+ virtual void InitializedRendererOnThread(LayerTreeHostImpl* host_impl,
+ bool success) OVERRIDE {
+ EXPECT_TRUE(success);
-SINGLE_AND_MULTI_THREAD_TEST_F(
- LayerTreeHostDelegatedTestOffscreenContext_Filters);
+ if (num_activates_ < 2)
+ return;
-class LayerTreeHostDelegatedTestOffscreenContext_BackgroundFilters
- : public LayerTreeHostDelegatedTestCaseSingleDelegatedLayer {
- protected:
- virtual void BeginTest() OVERRIDE {
- scoped_ptr<DelegatedFrameData> frame =
- CreateFrameData(gfx::Rect(0, 0, 1, 1),
- gfx::Rect(0, 0, 1, 1));
-
- FilterOperations filters;
- filters.Append(FilterOperation::CreateGrayscaleFilter(0.5f));
- AddRenderPass(frame.get(),
- RenderPass::Id(2, 1),
- gfx::Rect(0, 0, 1, 1),
- gfx::Rect(0, 0, 1, 1),
- FilterOperations(),
- filters);
- SetFrameData(frame.Pass());
+ LayerImpl* root_impl = host_impl->active_tree()->root_layer();
+ FakeDelegatedRendererLayerImpl* delegated_impl =
+ static_cast<FakeDelegatedRendererLayerImpl*>(root_impl->children()[0]);
- PostSetNeedsCommitToMainThread();
+ EXPECT_EQ(2, num_activates_);
+ // Resources should have gotten cleared after the context was lost.
+ EXPECT_EQ(0U, delegated_impl->Resources().size());
}
- virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
- bool expect_context = !delegating_renderer();
- EXPECT_EQ(expect_context, !!host_impl->offscreen_context_provider());
- EndTest();
+ virtual void AfterTest() OVERRIDE {
+ LayerTreeHostDelegatedTestCaseSingleDelegatedLayer::AfterTest();
+ EXPECT_EQ(2, num_output_surfaces_initialized_);
}
-};
-
-SINGLE_AND_MULTI_THREAD_TEST_F(
- LayerTreeHostDelegatedTestOffscreenContext_BackgroundFilters);
-class LayerTreeHostDelegatedTestOffscreenContext_Filters_AddedToTree
- : public LayerTreeHostDelegatedTestCaseSingleDelegatedLayer {
protected:
- virtual void BeginTest() OVERRIDE {
- scoped_ptr<DelegatedFrameData> frame_no_filters =
- CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1));
-
- scoped_ptr<DelegatedFrameData> frame_with_filters =
- CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1));
-
- FilterOperations filters;
- filters.Append(FilterOperation::CreateGrayscaleFilter(0.5f));
- AddRenderPass(frame_with_filters.get(),
- RenderPass::Id(2, 1),
- gfx::Rect(0, 0, 1, 1),
- gfx::Rect(0, 0, 1, 1),
- filters,
- FilterOperations());
-
- SetFrameData(frame_no_filters.Pass());
- delegated_->RemoveFromParent();
- SetFrameData(frame_with_filters.Pass());
- layer_tree_host()->root_layer()->AddChild(delegated_);
-
- PostSetNeedsCommitToMainThread();
- }
-
- virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
- bool expect_context = !delegating_renderer();
- EXPECT_EQ(expect_context, !!host_impl->offscreen_context_provider());
- EndTest();
- }
+ int num_activates_;
+ int num_output_surfaces_initialized_;
};
SINGLE_AND_MULTI_THREAD_TEST_F(
- LayerTreeHostDelegatedTestOffscreenContext_Filters_AddedToTree);
+ LayerTreeHostDelegatedTestInvalidFrameAfterContextLost);
class LayerTreeHostDelegatedTestLayerUsesFrameDamage
: public LayerTreeHostDelegatedTestCaseSingleDelegatedLayer {
@@ -519,9 +486,8 @@ class LayerTreeHostDelegatedTestLayerUsesFrameDamage
CreateFrameData(gfx::Rect(0, 0, 20, 20), gfx::Rect(0, 0, 0, 0)));
break;
case 3:
- // Should create a total amount of gfx::Rect(2, 2, 10, 6) damage.
- // The frame size is 20x20 while the layer is 10x10, so this should
- // produce a gfx::Rect(1, 1, 5, 3) damage rect.
+ // Should create a total amount of gfx::Rect(2, 2, 8, 6) damage:
+ // (2, 2, 10, 6) clamped to the root output rect.
SetFrameData(
CreateFrameData(gfx::Rect(0, 0, 20, 20), gfx::Rect(2, 2, 5, 5)));
SetFrameData(
@@ -550,41 +516,35 @@ class LayerTreeHostDelegatedTestLayerUsesFrameDamage
layer_tree_host()->SetNeedsCommit();
break;
case 9:
- // Should damage the full layer.
- delegated_->SetDisplaySize(gfx::Size(10, 10));
- break;
- case 10:
// Should create zero damage.
layer_tree_host()->SetNeedsCommit();
break;
- case 11:
+ case 10:
// Changing the frame size damages the full layer.
SetFrameData(
CreateFrameData(gfx::Rect(0, 0, 5, 5), gfx::Rect(4, 4, 1, 1)));
break;
- case 12:
+ case 11:
// An invalid frame isn't used, so it should not cause damage.
SetFrameData(CreateInvalidFrameData(gfx::Rect(0, 0, 5, 5),
gfx::Rect(4, 4, 1, 1)));
break;
- case 13:
- // Should create gfx::Rect(1, 1, 2, 2) of damage. The frame size is
- // 5x5 and the display size is now set to 10x10, so this should result
- // in a gfx::Rect(2, 2, 4, 4) damage rect.
+ case 12:
+ // Should create gfx::Rect(1, 1, 2, 2) of damage.
SetFrameData(
CreateFrameData(gfx::Rect(0, 0, 5, 5), gfx::Rect(1, 1, 2, 2)));
break;
- case 14:
+ case 13:
// Should create zero damage.
layer_tree_host()->SetNeedsCommit();
break;
- case 15:
+ case 14:
// Moving the layer out of the tree and back in will damage the whole
// impl layer.
delegated_->RemoveFromParent();
layer_tree_host()->root_layer()->AddChild(delegated_);
break;
- case 16:
+ case 15:
// Make a larger frame with lots of damage. Then a frame smaller than
// the first frame's damage. The entire layer should be damaged, but
// nothing more.
@@ -593,7 +553,7 @@ class LayerTreeHostDelegatedTestLayerUsesFrameDamage
SetFrameData(
CreateFrameData(gfx::Rect(0, 0, 5, 5), gfx::Rect(1, 1, 2, 2)));
break;
- case 17:
+ case 16:
// Make a frame with lots of damage. Then replace it with a frame with
// no damage. The entire layer should be damaged, but nothing more.
SetFrameData(
@@ -601,7 +561,7 @@ class LayerTreeHostDelegatedTestLayerUsesFrameDamage
SetFrameData(
CreateFrameData(gfx::Rect(0, 0, 10, 10), gfx::Rect(0, 0, 0, 0)));
break;
- case 18:
+ case 17:
// Make another layer that uses the same frame provider. The new layer
// should be damaged.
delegated_copy_ = CreateDelegatedLayer(frame_provider_);
@@ -611,24 +571,26 @@ class LayerTreeHostDelegatedTestLayerUsesFrameDamage
SetFrameData(
CreateFrameData(gfx::Rect(0, 0, 10, 10), gfx::Rect(4, 0, 1, 1)));
break;
- case 19:
+ case 18:
// Set another new frame, both layers should be damaged in the same
// ways.
SetFrameData(
CreateFrameData(gfx::Rect(0, 0, 10, 10), gfx::Rect(3, 3, 1, 1)));
+ break;
}
first_draw_for_source_frame_ = true;
}
- virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
- LayerTreeHostImpl::FrameData* frame,
- bool result) OVERRIDE {
- EXPECT_TRUE(result);
+ virtual DrawResult PrepareToDrawOnThread(
+ LayerTreeHostImpl* host_impl,
+ LayerTreeHostImpl::FrameData* frame,
+ DrawResult draw_result) OVERRIDE {
+ EXPECT_EQ(DRAW_SUCCESS, draw_result);
if (!first_draw_for_source_frame_)
- return result;
+ return draw_result;
- gfx::RectF damage_rect;
+ gfx::Rect damage_rect;
if (!frame->has_no_damage) {
damage_rect = frame->render_passes.back()->damage_rect;
} else {
@@ -639,90 +601,68 @@ class LayerTreeHostDelegatedTestLayerUsesFrameDamage
switch (host_impl->active_tree()->source_frame_number()) {
case 0:
// First frame is damaged because of viewport resize.
- EXPECT_EQ(gfx::RectF(0.f, 0.f, 10.f, 10.f).ToString(),
- damage_rect.ToString());
+ EXPECT_EQ(gfx::Rect(15, 15).ToString(), damage_rect.ToString());
break;
case 1:
- EXPECT_EQ(gfx::RectF(0.f, 0.f, 10.f, 10.f).ToString(),
- damage_rect.ToString());
+ EXPECT_EQ(gfx::Rect(10, 10).ToString(), damage_rect.ToString());
break;
case 2:
- EXPECT_EQ(gfx::RectF(0.f, 0.f, 10.f, 10.f).ToString(),
- damage_rect.ToString());
+ EXPECT_EQ(gfx::Rect(10, 10).ToString(), damage_rect.ToString());
break;
case 3:
- EXPECT_EQ(gfx::RectF(1.f, 1.f, 5.f, 3.f).ToString(),
- damage_rect.ToString());
+ EXPECT_EQ(gfx::Rect(2, 2, 8, 6).ToString(), damage_rect.ToString());
break;
case 4:
- EXPECT_EQ(gfx::RectF(0.f, 0.f, 0.f, 0.f).ToString(),
- damage_rect.ToString());
+ EXPECT_EQ(gfx::Rect().ToString(), damage_rect.ToString());
break;
case 5:
- EXPECT_EQ(gfx::RectF(0.f, 0.f, 10.f, 10.f).ToString(),
- damage_rect.ToString());
+ EXPECT_EQ(gfx::Rect(10, 10).ToString(), damage_rect.ToString());
break;
case 6:
- EXPECT_EQ(gfx::RectF(0.f, 0.f, 0.f, 0.f).ToString(),
- damage_rect.ToString());
+ EXPECT_EQ(gfx::Rect().ToString(), damage_rect.ToString());
break;
case 7:
- EXPECT_EQ(gfx::RectF(0.f, 0.f, 6.f, 6.f).ToString(),
- damage_rect.ToString());
+ EXPECT_EQ(gfx::Rect(6, 6).ToString(), damage_rect.ToString());
break;
case 8:
- EXPECT_EQ(gfx::RectF(0.f, 0.f, 0.f, 0.f).ToString(),
- damage_rect.ToString());
+ EXPECT_EQ(gfx::Rect().ToString(), damage_rect.ToString());
break;
case 9:
- EXPECT_EQ(gfx::RectF(0.f, 0.f, 6.f, 6.f).ToString(),
- damage_rect.ToString());
+ EXPECT_EQ(gfx::Rect().ToString(), damage_rect.ToString());
break;
case 10:
- EXPECT_EQ(gfx::RectF(0.f, 0.f, 0.f, 0.f).ToString(),
- damage_rect.ToString());
+ EXPECT_EQ(gfx::Rect(10, 10).ToString(), damage_rect.ToString());
break;
case 11:
- EXPECT_EQ(gfx::RectF(0.f, 0.f, 10.f, 10.f).ToString(),
- damage_rect.ToString());
+ EXPECT_EQ(gfx::Rect().ToString(), damage_rect.ToString());
break;
case 12:
- EXPECT_EQ(gfx::RectF(0.f, 0.f, 0.f, 0.f).ToString(),
- damage_rect.ToString());
+ EXPECT_EQ(gfx::Rect(1, 1, 2, 2).ToString(), damage_rect.ToString());
break;
case 13:
- EXPECT_EQ(gfx::RectF(2.f, 2.f, 4.f, 4.f).ToString(),
- damage_rect.ToString());
+ EXPECT_EQ(gfx::Rect().ToString(), damage_rect.ToString());
break;
case 14:
- EXPECT_EQ(gfx::RectF(0.f, 0.f, 0.f, 0.f).ToString(),
- damage_rect.ToString());
+ EXPECT_EQ(gfx::Rect(10, 10).ToString(), damage_rect.ToString());
break;
case 15:
- EXPECT_EQ(gfx::RectF(0.f, 0.f, 10.f, 10.f).ToString(),
- damage_rect.ToString());
+ EXPECT_EQ(gfx::Rect(10, 10).ToString(), damage_rect.ToString());
break;
case 16:
- EXPECT_EQ(gfx::RectF(0.f, 0.f, 10.f, 10.f).ToString(),
- damage_rect.ToString());
+ EXPECT_EQ(gfx::Rect(10, 10).ToString(), damage_rect.ToString());
break;
case 17:
- EXPECT_EQ(gfx::RectF(0.f, 0.f, 10.f, 10.f).ToString(),
+ EXPECT_EQ(gfx::UnionRects(gfx::Rect(5, 0, 10, 10),
+ gfx::Rect(4, 0, 1, 1)).ToString(),
damage_rect.ToString());
break;
case 18:
- EXPECT_EQ(gfx::UnionRects(gfx::RectF(5.f, 0.f, 10.f, 10.f),
- gfx::RectF(4.f, 0.f, 1.f, 1.f)).ToString(),
- damage_rect.ToString());
- break;
- case 19:
- EXPECT_EQ(gfx::RectF(3.f, 3.f, 6.f, 1.f).ToString(),
- damage_rect.ToString());
+ EXPECT_EQ(gfx::Rect(3, 3, 6, 1).ToString(), damage_rect.ToString());
EndTest();
break;
}
- return result;
+ return draw_result;
}
protected:
@@ -1575,7 +1515,6 @@ class LayerTreeHostDelegatedTestResourceSentToParent
CompositorFrameAck ack;
output_surface()->ReturnResource(map.find(999)->second, &ack);
host_impl->ReclaimResources(&ack);
- host_impl->OnSwapBuffersComplete();
}
virtual void UnusedResourcesAreAvailable() OVERRIDE {
@@ -1774,12 +1713,7 @@ SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostDelegatedTestCommitWithoutTake);
class DelegatedFrameIsActivatedDuringCommit
: public LayerTreeHostDelegatedTestCaseSingleDelegatedLayer {
protected:
- DelegatedFrameIsActivatedDuringCommit()
- : wait_thread_("WAIT"),
- wait_event_(false, false),
- returned_resource_count_(0) {
- wait_thread_.Start();
- }
+ DelegatedFrameIsActivatedDuringCommit() : returned_resource_count_(0) {}
virtual void BeginTest() OVERRIDE {
activate_count_ = 0;
@@ -1794,31 +1728,11 @@ class DelegatedFrameIsActivatedDuringCommit
}
virtual void WillActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
- // Slow down activation so the main thread DidCommit() will run if
- // not blocked.
- wait_thread_.message_loop()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&base::WaitableEvent::Signal,
- base::Unretained(&wait_event_)),
- base::TimeDelta::FromMilliseconds(10));
- wait_event_.Wait();
-
- base::AutoLock lock(activate_lock_);
++activate_count_;
}
- virtual void DidActivateTreeOnThread(LayerTreeHostImpl* impl) OVERRIDE {
- // The main thread is awake now, and will run DidCommit() immediately.
- // Run DidActivate() afterwards by posting it now.
- proxy()->MainThreadTaskRunner()->PostTask(
- FROM_HERE,
- base::Bind(&DelegatedFrameIsActivatedDuringCommit::DidActivate,
- base::Unretained(this)));
- }
-
- void DidActivate() {
- base::AutoLock lock(activate_lock_);
- switch (activate_count_) {
+ virtual void DidCommit() OVERRIDE {
+ switch (layer_tree_host()->source_frame_number()) {
case 1: {
// The first frame has been activated. Set a new frame, and
// expect the next commit to finish *after* it is activated.
@@ -1827,8 +1741,6 @@ class DelegatedFrameIsActivatedDuringCommit
AddTextureQuad(frame.get(), 555);
AddTransferableResource(frame.get(), 555);
SetFrameData(frame.Pass());
- // So this commit number should complete after the second activate.
- EXPECT_EQ(1, layer_tree_host()->source_frame_number());
break;
}
case 2:
@@ -1836,28 +1748,26 @@ class DelegatedFrameIsActivatedDuringCommit
// the tree to cause another commit/activation. The commit should
// finish *after* the layer is removed from the active tree.
delegated_->RemoveFromParent();
- // So this commit number should complete after the third activate.
- EXPECT_EQ(2, layer_tree_host()->source_frame_number());
+ break;
+ case 3:
+ // Finish the test by releasing resources on the next frame.
+ scoped_ptr<DelegatedFrameData> frame =
+ CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1));
+ SetFrameData(frame.Pass());
break;
}
}
- virtual void DidCommit() OVERRIDE {
- switch (layer_tree_host()->source_frame_number()) {
+ virtual void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
+ switch (host_impl->active_tree()->source_frame_number()) {
case 2: {
// The activate for the 2nd frame should have happened before now.
- base::AutoLock lock(activate_lock_);
EXPECT_EQ(2, activate_count_);
break;
}
case 3: {
// The activate to remove the layer should have happened before now.
- base::AutoLock lock(activate_lock_);
EXPECT_EQ(3, activate_count_);
-
- scoped_ptr<DelegatedFrameData> frame =
- CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1));
- SetFrameData(frame.Pass());
break;
}
}
@@ -1879,9 +1789,6 @@ class DelegatedFrameIsActivatedDuringCommit
EndTest();
}
- base::Thread wait_thread_;
- base::WaitableEvent wait_event_;
- base::Lock activate_lock_;
int activate_count_;
size_t returned_resource_count_;
};
diff --git a/chromium/cc/trees/layer_tree_host_unittest_no_message_loop.cc b/chromium/cc/trees/layer_tree_host_unittest_no_message_loop.cc
new file mode 100644
index 00000000000..4c6796f3021
--- /dev/null
+++ b/chromium/cc/trees/layer_tree_host_unittest_no_message_loop.cc
@@ -0,0 +1,235 @@
+// 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 "base/message_loop/message_loop_proxy.h"
+#include "base/threading/simple_thread.h"
+#include "cc/layers/delegated_frame_provider.h"
+#include "cc/layers/delegated_frame_resource_collection.h"
+#include "cc/layers/delegated_renderer_layer.h"
+#include "cc/layers/layer.h"
+#include "cc/layers/solid_color_layer.h"
+#include "cc/output/delegated_frame_data.h"
+#include "cc/output/output_surface.h"
+#include "cc/output/output_surface_client.h"
+#include "cc/resources/resource_provider.h"
+#include "cc/test/fake_delegated_renderer_layer.h"
+#include "cc/test/test_context_provider.h"
+#include "cc/trees/layer_tree_host.h"
+#include "cc/trees/layer_tree_host_client.h"
+#include "cc/trees/layer_tree_host_single_thread_client.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/gfx/frame_time.h"
+
+namespace cc {
+namespace {
+
+class NoMessageLoopOutputSurface : public OutputSurface {
+ public:
+ NoMessageLoopOutputSurface() : OutputSurface(TestContextProvider::Create()) {}
+ virtual ~NoMessageLoopOutputSurface() {}
+
+ // OutputSurface overrides.
+ virtual void SwapBuffers(CompositorFrame* frame) OVERRIDE {
+ DCHECK(client_);
+ client_->DidSwapBuffers();
+ client_->DidSwapBuffersComplete();
+ }
+};
+
+class LayerTreeHostNoMessageLoopTest
+ : public testing::Test,
+ public base::DelegateSimpleThread::Delegate,
+ public LayerTreeHostClient,
+ public LayerTreeHostSingleThreadClient {
+ public:
+ LayerTreeHostNoMessageLoopTest()
+ : did_initialize_output_surface_(false),
+ did_commit_(false),
+ did_commit_and_draw_frame_(false),
+ size_(100, 100),
+ no_loop_thread_(this, "LayerTreeHostNoMessageLoopTest") {}
+ virtual ~LayerTreeHostNoMessageLoopTest() {}
+
+ // LayerTreeHostClient overrides.
+ virtual void WillBeginMainFrame(int frame_id) OVERRIDE {}
+ virtual void DidBeginMainFrame() OVERRIDE {}
+ virtual void Animate(base::TimeTicks frame_begin_time) OVERRIDE {}
+ virtual void Layout() OVERRIDE {}
+ virtual void ApplyScrollAndScale(const gfx::Vector2d& scroll_delta,
+ float page_scale) OVERRIDE {}
+ virtual scoped_ptr<OutputSurface> CreateOutputSurface(
+ bool fallback) OVERRIDE {
+ return make_scoped_ptr<OutputSurface>(new NoMessageLoopOutputSurface);
+ }
+ virtual void DidInitializeOutputSurface() OVERRIDE {
+ did_initialize_output_surface_ = true;
+ }
+ virtual void WillCommit() OVERRIDE {}
+ virtual void DidCommit() OVERRIDE { did_commit_ = true; }
+ virtual void DidCommitAndDrawFrame() OVERRIDE {
+ did_commit_and_draw_frame_ = true;
+ }
+ virtual void DidCompleteSwapBuffers() OVERRIDE {}
+
+ // LayerTreeHostSingleThreadClient overrides.
+ virtual void ScheduleComposite() OVERRIDE {}
+ virtual void ScheduleAnimation() OVERRIDE {}
+ virtual void DidPostSwapBuffers() OVERRIDE {}
+ virtual void DidAbortSwapBuffers() OVERRIDE {}
+
+ void RunTest() {
+ no_loop_thread_.Start();
+ no_loop_thread_.Join();
+ }
+
+ // base::DelegateSimpleThread::Delegate override.
+ virtual void Run() OVERRIDE {
+ ASSERT_FALSE(base::MessageLoopProxy::current());
+ RunTestWithoutMessageLoop();
+ EXPECT_FALSE(base::MessageLoopProxy::current());
+ }
+
+ protected:
+ virtual void RunTestWithoutMessageLoop() = 0;
+
+ void SetupLayerTreeHost() {
+ LayerTreeSettings settings;
+ layer_tree_host_ =
+ LayerTreeHost::CreateSingleThreaded(this, this, NULL, settings);
+ layer_tree_host_->SetViewportSize(size_);
+ layer_tree_host_->SetRootLayer(root_layer_);
+ }
+
+ void Composite() {
+ did_commit_ = false;
+ did_commit_and_draw_frame_ = false;
+ layer_tree_host_->Composite(gfx::FrameTime::Now());
+ EXPECT_TRUE(did_initialize_output_surface_);
+ EXPECT_TRUE(did_commit_);
+ EXPECT_TRUE(did_commit_and_draw_frame_);
+ }
+
+ void TearDownLayerTreeHost() {
+ // Explicit teardown to make failures easier to debug.
+ layer_tree_host_.reset();
+ root_layer_ = NULL;
+ }
+
+ // All protected member variables are accessed only on |no_loop_thread_|.
+ scoped_ptr<LayerTreeHost> layer_tree_host_;
+ scoped_refptr<Layer> root_layer_;
+
+ bool did_initialize_output_surface_;
+ bool did_commit_;
+ bool did_commit_and_draw_frame_;
+ gfx::Size size_;
+
+ private:
+ base::DelegateSimpleThread no_loop_thread_;
+};
+
+class LayerTreeHostNoMessageLoopSmokeTest
+ : public LayerTreeHostNoMessageLoopTest {
+ protected:
+ virtual void RunTestWithoutMessageLoop() OVERRIDE {
+ gfx::Size size(100, 100);
+
+ // Set up root layer.
+ {
+ scoped_refptr<SolidColorLayer> solid_color_layer =
+ SolidColorLayer::Create();
+ solid_color_layer->SetBackgroundColor(SK_ColorRED);
+ solid_color_layer->SetBounds(size_);
+ solid_color_layer->SetIsDrawable(true);
+ root_layer_ = solid_color_layer;
+ }
+
+ SetupLayerTreeHost();
+ Composite();
+ TearDownLayerTreeHost();
+ }
+};
+
+TEST_F(LayerTreeHostNoMessageLoopSmokeTest, SmokeTest) {
+ RunTest();
+}
+
+class LayerTreeHostNoMessageLoopDelegatedLayer
+ : public LayerTreeHostNoMessageLoopTest,
+ public DelegatedFrameResourceCollectionClient {
+ protected:
+ virtual void RunTestWithoutMessageLoop() OVERRIDE {
+ resource_collection_ = new DelegatedFrameResourceCollection;
+ frame_provider_ = new DelegatedFrameProvider(
+ resource_collection_.get(), CreateFrameDataWithResource(998));
+
+ root_layer_ = Layer::Create();
+ delegated_layer_ = FakeDelegatedRendererLayer::Create(frame_provider_);
+ delegated_layer_->SetBounds(size_);
+ delegated_layer_->SetIsDrawable(true);
+ root_layer_->AddChild(delegated_layer_);
+
+ SetupLayerTreeHost();
+
+ // Draw first frame.
+ Composite();
+
+ // Prepare and draw second frame.
+ frame_provider_->SetFrameData(CreateFrameDataWithResource(999));
+ Composite();
+
+ // Resource from first frame should be returned.
+ CheckReturnedResource(1u);
+
+ TearDownLayerTreeHost();
+ delegated_layer_ = NULL;
+ frame_provider_ = NULL;
+
+ // Resource from second frame should be returned.
+ CheckReturnedResource(1u);
+ resource_collection_ = NULL;
+ }
+
+ // DelegatedFrameResourceCollectionClient overrides.
+ virtual void UnusedResourcesAreAvailable() OVERRIDE {}
+
+ private:
+ scoped_ptr<DelegatedFrameData> CreateFrameDataWithResource(
+ ResourceProvider::ResourceId resource_id) {
+ scoped_ptr<DelegatedFrameData> frame(new DelegatedFrameData);
+ gfx::Rect frame_rect(size_);
+
+ scoped_ptr<RenderPass> root_pass(RenderPass::Create());
+ root_pass->SetNew(
+ RenderPass::Id(1, 1), frame_rect, frame_rect, gfx::Transform());
+ frame->render_pass_list.push_back(root_pass.Pass());
+
+ TransferableResource resource;
+ resource.id = resource_id;
+ resource.mailbox_holder.texture_target = GL_TEXTURE_2D;
+ resource.mailbox_holder.mailbox = gpu::Mailbox::Generate();
+ frame->resource_list.push_back(resource);
+
+ return frame.Pass();
+ }
+
+ void CheckReturnedResource(size_t expected_num) {
+ ReturnedResourceArray returned_resources;
+ resource_collection_->TakeUnusedResourcesForChildCompositor(
+ &returned_resources);
+ EXPECT_EQ(expected_num, returned_resources.size());
+ }
+
+ scoped_refptr<DelegatedFrameResourceCollection> resource_collection_;
+ scoped_refptr<DelegatedFrameProvider> frame_provider_;
+ scoped_refptr<DelegatedRendererLayer> delegated_layer_;
+};
+
+TEST_F(LayerTreeHostNoMessageLoopDelegatedLayer, SingleDelegatedLayer) {
+ RunTest();
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_host_unittest_occlusion.cc b/chromium/cc/trees/layer_tree_host_unittest_occlusion.cc
index 621d23d360f..cb6a5d32819 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_occlusion.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_occlusion.cc
@@ -8,7 +8,7 @@
#include "cc/output/copy_output_request.h"
#include "cc/output/copy_output_result.h"
#include "cc/test/layer_tree_test.h"
-#include "cc/test/occlusion_tracker_test_common.h"
+#include "cc/test/test_occlusion_tracker.h"
namespace cc {
namespace {
@@ -19,15 +19,14 @@ class TestLayer : public Layer {
return make_scoped_refptr(new TestLayer());
}
- virtual bool Update(
- ResourceUpdateQueue* update_queue,
- const OcclusionTracker* occlusion) OVERRIDE {
+ virtual bool Update(ResourceUpdateQueue* update_queue,
+ const OcclusionTracker<Layer>* occlusion) OVERRIDE {
if (!occlusion)
return false;
// Gain access to internals of the OcclusionTracker.
- const TestOcclusionTracker* test_occlusion =
- static_cast<const TestOcclusionTracker*>(occlusion);
+ const TestOcclusionTracker<Layer>* test_occlusion =
+ static_cast<const TestOcclusionTracker<Layer>*>(occlusion);
occlusion_ = UnionRegions(
test_occlusion->occlusion_from_inside_target(),
test_occlusion->occlusion_from_outside_target());
@@ -86,8 +85,8 @@ class LayerTreeHostOcclusionTest : public LayerTreeTest {
void SetLayerPropertiesForTesting(TestLayer* layer,
TestLayer* parent,
const gfx::Transform& transform,
- gfx::PointF position,
- gfx::Size bounds,
+ const gfx::PointF& position,
+ const gfx::Size& bounds,
bool opaque) const {
layer->RemoveAllChildren();
if (parent)
@@ -96,8 +95,6 @@ class LayerTreeHostOcclusionTest : public LayerTreeTest {
layer->SetPosition(position);
layer->SetBounds(bounds);
layer->SetContentsOpaque(opaque);
-
- layer->SetAnchorPoint(gfx::PointF());
}
protected:
diff --git a/chromium/cc/trees/layer_tree_host_unittest_proxy.cc b/chromium/cc/trees/layer_tree_host_unittest_proxy.cc
new file mode 100644
index 00000000000..4f79311f649
--- /dev/null
+++ b/chromium/cc/trees/layer_tree_host_unittest_proxy.cc
@@ -0,0 +1,135 @@
+// 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 "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "cc/test/layer_tree_test.h"
+#include "cc/trees/thread_proxy.h"
+
+#define THREAD_PROXY_NO_IMPL_TEST_F(TEST_FIXTURE_NAME) \
+ TEST_F(TEST_FIXTURE_NAME, Run_MainThreadPaint) { \
+ Run(true, false); \
+ }
+
+#define THREAD_PROXY_TEST_F(TEST_FIXTURE_NAME) \
+ THREAD_PROXY_NO_IMPL_TEST_F(TEST_FIXTURE_NAME); \
+ TEST_F(TEST_FIXTURE_NAME, Run_ImplSidePaint) { \
+ Run(true, true); \
+ }
+
+// Do common tests for single thread proxy and thread proxy.
+// TODO(simonhong): Add SINGLE_THREAD_PROXY_TEST_F
+#define PROXY_TEST_SCHEDULED_ACTION(TEST_FIXTURE_NAME) \
+ THREAD_PROXY_TEST_F(TEST_FIXTURE_NAME);
+
+namespace cc {
+
+class ProxyTest : public LayerTreeTest {
+ protected:
+ ProxyTest() {}
+ virtual ~ProxyTest() {}
+
+ void Run(bool threaded, bool impl_side_painting) {
+ // We don't need to care about delegating mode.
+ bool delegating_renderer = true;
+
+ RunTest(threaded, delegating_renderer, impl_side_painting);
+ }
+
+ virtual void BeginTest() OVERRIDE {}
+ virtual void AfterTest() OVERRIDE {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ProxyTest);
+};
+
+class ProxyTestScheduledActionsBasic : public ProxyTest {
+ protected:
+ virtual void BeginTest() OVERRIDE {
+ proxy()->SetNeedsCommit();
+ }
+
+ virtual void ScheduledActionBeginOutputSurfaceCreation() OVERRIDE {
+ EXPECT_EQ(0, action_phase_++);
+ }
+
+ virtual void ScheduledActionSendBeginMainFrame() OVERRIDE {
+ EXPECT_EQ(1, action_phase_++);
+ }
+
+ virtual void ScheduledActionCommit() OVERRIDE {
+ EXPECT_EQ(2, action_phase_++);
+ }
+
+ virtual void ScheduledActionDrawAndSwapIfPossible() OVERRIDE {
+ EXPECT_EQ(3, action_phase_++);
+ EndTest();
+ }
+
+ virtual void AfterTest() OVERRIDE {
+ EXPECT_EQ(4, action_phase_);
+ }
+
+ ProxyTestScheduledActionsBasic() : action_phase_(0) {
+ }
+ virtual ~ProxyTestScheduledActionsBasic() {}
+
+ private:
+ int action_phase_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProxyTestScheduledActionsBasic);
+};
+
+PROXY_TEST_SCHEDULED_ACTION(ProxyTestScheduledActionsBasic);
+
+class ThreadProxyTest : public ProxyTest {
+ protected:
+ ThreadProxyTest() {}
+ virtual ~ThreadProxyTest() {}
+
+ const ThreadProxy::MainThreadOnly& ThreadProxyMainOnly() const {
+ DCHECK(proxy());
+ DCHECK(proxy()->HasImplThread());
+ return static_cast<const ThreadProxy*>(proxy())->main();
+ }
+
+ const ThreadProxy::CompositorThreadOnly& ThreadProxyImplOnly() const {
+ DCHECK(proxy());
+ DCHECK(proxy()->HasImplThread());
+ return static_cast<const ThreadProxy*>(proxy())->impl();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ThreadProxyTest);
+};
+
+class ThreadProxyTestSetNeedsCommit : public ThreadProxyTest {
+ protected:
+ ThreadProxyTestSetNeedsCommit() {}
+ virtual ~ThreadProxyTestSetNeedsCommit() {}
+
+ virtual void BeginTest() OVERRIDE {
+ EXPECT_FALSE(ThreadProxyMainOnly().commit_requested);
+ EXPECT_FALSE(ThreadProxyMainOnly().commit_request_sent_to_impl_thread);
+
+ proxy()->SetNeedsCommit();
+
+ EXPECT_TRUE(ThreadProxyMainOnly().commit_requested);
+ EXPECT_TRUE(ThreadProxyMainOnly().commit_request_sent_to_impl_thread);
+ }
+
+ virtual void DidBeginMainFrame() OVERRIDE {
+ EXPECT_FALSE(ThreadProxyMainOnly().commit_requested);
+ EXPECT_FALSE(ThreadProxyMainOnly().commit_request_sent_to_impl_thread);
+
+ EndTest();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ThreadProxyTestSetNeedsCommit);
+};
+
+THREAD_PROXY_TEST_F(ThreadProxyTestSetNeedsCommit);
+
+} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_host_unittest_scroll.cc b/chromium/cc/trees/layer_tree_host_unittest_scroll.cc
index 38711545636..05a58764018 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_scroll.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_scroll.cc
@@ -12,6 +12,7 @@
#include "cc/test/fake_layer_tree_host_client.h"
#include "cc/test/geometry_test_utils.h"
#include "cc/test/layer_tree_test.h"
+#include "cc/test/test_shared_bitmap_manager.h"
#include "cc/trees/layer_tree_impl.h"
#include "ui/gfx/point_conversions.h"
#include "ui/gfx/size_conversions.h"
@@ -31,48 +32,59 @@ class LayerTreeHostScrollTestScrollSimple : public LayerTreeHostScrollTest {
num_scrolls_(0) {}
virtual void BeginTest() OVERRIDE {
- layer_tree_host()->root_layer()->SetScrollable(true);
- layer_tree_host()->root_layer()
- ->SetMaxScrollOffset(gfx::Vector2d(100, 100));
- layer_tree_host()->root_layer()->SetScrollOffset(initial_scroll_);
+ Layer* root_layer = layer_tree_host()->root_layer();
+ scoped_refptr<Layer> scroll_layer = Layer::Create();
+ root_layer->AddChild(scroll_layer);
+ // Create an effective max_scroll_offset of (100, 100).
+ scroll_layer->SetBounds(gfx::Size(root_layer->bounds().width() + 100,
+ root_layer->bounds().height() + 100));
+ scroll_layer->SetIsDrawable(true);
+ scroll_layer->SetIsContainerForFixedPositionLayers(true);
+ scroll_layer->SetScrollClipLayerId(root_layer->id());
+ scroll_layer->SetScrollOffset(initial_scroll_);
+ layer_tree_host()->RegisterViewportLayers(root_layer, scroll_layer, NULL);
PostSetNeedsCommitToMainThread();
}
virtual void Layout() OVERRIDE {
Layer* root = layer_tree_host()->root_layer();
+ Layer* scroll_layer = root->children()[0];
if (!layer_tree_host()->source_frame_number()) {
- EXPECT_VECTOR_EQ(initial_scroll_, root->scroll_offset());
+ EXPECT_VECTOR_EQ(initial_scroll_, scroll_layer->scroll_offset());
} else {
- EXPECT_VECTOR_EQ(initial_scroll_ + scroll_amount_, root->scroll_offset());
+ EXPECT_VECTOR_EQ(initial_scroll_ + scroll_amount_,
+ scroll_layer->scroll_offset());
// Pretend like Javascript updated the scroll position itself.
- root->SetScrollOffset(second_scroll_);
+ scroll_layer->SetScrollOffset(second_scroll_);
}
}
virtual void DrawLayersOnThread(LayerTreeHostImpl* impl) OVERRIDE {
LayerImpl* root = impl->active_tree()->root_layer();
- EXPECT_VECTOR_EQ(gfx::Vector2d(), root->ScrollDelta());
+ LayerImpl* scroll_layer = root->children()[0];
+ EXPECT_VECTOR_EQ(gfx::Vector2d(), scroll_layer->ScrollDelta());
- root->SetScrollable(true);
- root->SetMaxScrollOffset(gfx::Vector2d(100, 100));
- root->ScrollBy(scroll_amount_);
+ scroll_layer->SetScrollClipLayer(root->id());
+ scroll_layer->SetBounds(
+ gfx::Size(root->bounds().width() + 100, root->bounds().height() + 100));
+ scroll_layer->ScrollBy(scroll_amount_);
switch (impl->active_tree()->source_frame_number()) {
case 0:
- EXPECT_VECTOR_EQ(initial_scroll_, root->scroll_offset());
- EXPECT_VECTOR_EQ(scroll_amount_, root->ScrollDelta());
+ EXPECT_VECTOR_EQ(initial_scroll_, scroll_layer->scroll_offset());
+ EXPECT_VECTOR_EQ(scroll_amount_, scroll_layer->ScrollDelta());
PostSetNeedsCommitToMainThread();
break;
case 1:
- EXPECT_VECTOR_EQ(root->scroll_offset(), second_scroll_);
- EXPECT_VECTOR_EQ(root->ScrollDelta(), scroll_amount_);
+ EXPECT_VECTOR_EQ(scroll_layer->scroll_offset(), second_scroll_);
+ EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(), scroll_amount_);
EndTest();
break;
}
}
- virtual void ApplyScrollAndScale(gfx::Vector2d scroll_delta,
+ virtual void ApplyScrollAndScale(const gfx::Vector2d& scroll_delta,
float scale) OVERRIDE {
num_scrolls_++;
}
@@ -95,61 +107,68 @@ class LayerTreeHostScrollTestScrollMultipleRedraw
: initial_scroll_(40, 10), scroll_amount_(-3, 17), num_scrolls_(0) {}
virtual void BeginTest() OVERRIDE {
- layer_tree_host()->root_layer()->SetScrollable(true);
- layer_tree_host()->root_layer()->SetScrollOffset(initial_scroll_);
- layer_tree_host()->root_layer()->SetBounds(gfx::Size(200, 200));
- layer_tree_host()->root_layer()
- ->SetMaxScrollOffset(gfx::Vector2d(100, 100));
+ Layer* root_layer = layer_tree_host()->root_layer();
+ scroll_layer_ = Layer::Create();
+ root_layer->AddChild(scroll_layer_);
+ // Create an effective max_scroll_offset of (100, 100).
+ scroll_layer_->SetBounds(gfx::Size(root_layer->bounds().width() + 100,
+ root_layer->bounds().height() + 100));
+ scroll_layer_->SetIsDrawable(true);
+ scroll_layer_->SetIsContainerForFixedPositionLayers(true);
+ scroll_layer_->SetScrollClipLayerId(root_layer->id());
+ scroll_layer_->SetScrollOffset(initial_scroll_);
+ layer_tree_host()->RegisterViewportLayers(root_layer, scroll_layer_, NULL);
PostSetNeedsCommitToMainThread();
}
virtual void BeginCommitOnThread(LayerTreeHostImpl* impl) OVERRIDE {
- Layer* root = layer_tree_host()->root_layer();
switch (layer_tree_host()->source_frame_number()) {
case 0:
- EXPECT_VECTOR_EQ(root->scroll_offset(), initial_scroll_);
+ EXPECT_VECTOR_EQ(scroll_layer_->scroll_offset(), initial_scroll_);
break;
case 1:
- EXPECT_VECTOR_EQ(root->scroll_offset(),
+ EXPECT_VECTOR_EQ(scroll_layer_->scroll_offset(),
initial_scroll_ + scroll_amount_ + scroll_amount_);
case 2:
- EXPECT_VECTOR_EQ(root->scroll_offset(),
+ EXPECT_VECTOR_EQ(scroll_layer_->scroll_offset(),
initial_scroll_ + scroll_amount_ + scroll_amount_);
break;
}
}
virtual void DrawLayersOnThread(LayerTreeHostImpl* impl) OVERRIDE {
- LayerImpl* root = impl->active_tree()->root_layer();
+ LayerImpl* scroll_layer =
+ impl->active_tree()->LayerById(scroll_layer_->id());
if (impl->active_tree()->source_frame_number() == 0 &&
impl->SourceAnimationFrameNumber() == 1) {
// First draw after first commit.
- EXPECT_VECTOR_EQ(root->ScrollDelta(), gfx::Vector2d());
- root->ScrollBy(scroll_amount_);
- EXPECT_VECTOR_EQ(root->ScrollDelta(), scroll_amount_);
+ EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(), gfx::Vector2d());
+ scroll_layer->ScrollBy(scroll_amount_);
+ EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(), scroll_amount_);
- EXPECT_VECTOR_EQ(root->scroll_offset(), initial_scroll_);
+ EXPECT_VECTOR_EQ(scroll_layer->scroll_offset(), initial_scroll_);
PostSetNeedsRedrawToMainThread();
} else if (impl->active_tree()->source_frame_number() == 0 &&
impl->SourceAnimationFrameNumber() == 2) {
// Second draw after first commit.
- EXPECT_EQ(root->ScrollDelta(), scroll_amount_);
- root->ScrollBy(scroll_amount_);
- EXPECT_VECTOR_EQ(root->ScrollDelta(), scroll_amount_ + scroll_amount_);
+ EXPECT_EQ(scroll_layer->ScrollDelta(), scroll_amount_);
+ scroll_layer->ScrollBy(scroll_amount_);
+ EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(),
+ scroll_amount_ + scroll_amount_);
- EXPECT_VECTOR_EQ(root->scroll_offset(), initial_scroll_);
+ EXPECT_VECTOR_EQ(scroll_layer_->scroll_offset(), initial_scroll_);
PostSetNeedsCommitToMainThread();
} else if (impl->active_tree()->source_frame_number() == 1) {
// Third or later draw after second commit.
EXPECT_GE(impl->SourceAnimationFrameNumber(), 3);
- EXPECT_VECTOR_EQ(root->ScrollDelta(), gfx::Vector2d());
- EXPECT_VECTOR_EQ(root->scroll_offset(),
+ EXPECT_VECTOR_EQ(scroll_layer_->ScrollDelta(), gfx::Vector2d());
+ EXPECT_VECTOR_EQ(scroll_layer_->scroll_offset(),
initial_scroll_ + scroll_amount_ + scroll_amount_);
EndTest();
}
}
- virtual void ApplyScrollAndScale(gfx::Vector2d scroll_delta,
+ virtual void ApplyScrollAndScale(const gfx::Vector2d& scroll_delta,
float scale) OVERRIDE {
num_scrolls_++;
}
@@ -160,6 +179,7 @@ class LayerTreeHostScrollTestScrollMultipleRedraw
gfx::Vector2d initial_scroll_;
gfx::Vector2d scroll_amount_;
int num_scrolls_;
+ scoped_refptr<Layer> scroll_layer_;
};
MULTI_THREAD_TEST_F(LayerTreeHostScrollTestScrollMultipleRedraw);
@@ -183,14 +203,17 @@ class LayerTreeHostScrollTestScrollAbortedCommit
virtual void SetupTree() OVERRIDE {
LayerTreeHostScrollTest::SetupTree();
+ Layer* root_layer = layer_tree_host()->root_layer();
scoped_refptr<Layer> root_scroll_layer = Layer::Create();
- root_scroll_layer->SetScrollable(true);
+ root_scroll_layer->SetScrollClipLayerId(root_layer->id());
root_scroll_layer->SetScrollOffset(initial_scroll_);
root_scroll_layer->SetBounds(gfx::Size(200, 200));
- root_scroll_layer->SetMaxScrollOffset(gfx::Vector2d(100, 100));
root_scroll_layer->SetIsDrawable(true);
- layer_tree_host()->root_layer()->AddChild(root_scroll_layer);
+ root_scroll_layer->SetIsContainerForFixedPositionLayers(true);
+ root_layer->AddChild(root_scroll_layer);
+ layer_tree_host()->RegisterViewportLayers(
+ root_layer, root_scroll_layer, NULL);
layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 0.01f, 100.f);
}
@@ -218,7 +241,8 @@ class LayerTreeHostScrollTestScrollAbortedCommit
case 3:
// This commit will not be aborted because of the scroll change.
EXPECT_EQ(2, num_impl_scrolls_);
- EXPECT_EQ(1, layer_tree_host()->source_frame_number());
+ // The source frame number still increases even with the abort.
+ EXPECT_EQ(2, layer_tree_host()->source_frame_number());
EXPECT_VECTOR_EQ(root_scroll_layer->scroll_offset(),
initial_scroll_ + impl_scroll_ + impl_scroll_);
EXPECT_EQ(impl_scale_ * impl_scale_,
@@ -229,7 +253,7 @@ class LayerTreeHostScrollTestScrollAbortedCommit
case 4:
// This commit will also be aborted.
EXPECT_EQ(3, num_impl_scrolls_);
- EXPECT_EQ(2, layer_tree_host()->source_frame_number());
+ EXPECT_EQ(3, layer_tree_host()->source_frame_number());
EXPECT_VECTOR_EQ(root_scroll_layer->scroll_offset(),
initial_scroll_ + impl_scroll_ + impl_scroll_ +
impl_scroll_ + second_main_scroll_);
@@ -288,7 +312,10 @@ class LayerTreeHostScrollTestScrollAbortedCommit
impl->active_tree()->total_page_scale_factor());
impl->SetNeedsCommit();
- } else if (impl->active_tree()->source_frame_number() == 1 &&
+ } else if (impl->active_tree()->source_frame_number() == 1) {
+ // Commit for source frame 1 is aborted.
+ NOTREACHED();
+ } else if (impl->active_tree()->source_frame_number() == 2 &&
impl->SourceAnimationFrameNumber() == 3) {
// Third draw after the second full commit.
EXPECT_EQ(root_scroll_layer->ScrollDelta(), gfx::Vector2d());
@@ -298,7 +325,7 @@ class LayerTreeHostScrollTestScrollAbortedCommit
EXPECT_VECTOR_EQ(
root_scroll_layer->scroll_offset(),
initial_scroll_ + impl_scroll_ + impl_scroll_ + second_main_scroll_);
- } else if (impl->active_tree()->source_frame_number() == 1 &&
+ } else if (impl->active_tree()->source_frame_number() == 2 &&
impl->SourceAnimationFrameNumber() == 4) {
// Final draw after the second aborted commit.
EXPECT_VECTOR_EQ(root_scroll_layer->ScrollDelta(), gfx::Vector2d());
@@ -306,10 +333,13 @@ class LayerTreeHostScrollTestScrollAbortedCommit
initial_scroll_ + impl_scroll_ + impl_scroll_ +
impl_scroll_ + second_main_scroll_);
EndTest();
+ } else {
+ // Commit for source frame 3 is aborted.
+ NOTREACHED();
}
}
- virtual void ApplyScrollAndScale(gfx::Vector2d scroll_delta,
+ virtual void ApplyScrollAndScale(const gfx::Vector2d& scroll_delta,
float scale) OVERRIDE {
num_impl_scrolls_++;
}
@@ -344,42 +374,57 @@ class LayerTreeHostScrollTestFractionalScroll : public LayerTreeHostScrollTest {
public:
LayerTreeHostScrollTestFractionalScroll() : scroll_amount_(1.75, 0) {}
+ virtual void SetupTree() OVERRIDE {
+ LayerTreeHostScrollTest::SetupTree();
+ Layer* root_layer = layer_tree_host()->root_layer();
+ scoped_refptr<Layer> root_scroll_layer = Layer::Create();
+ root_scroll_layer->SetScrollClipLayerId(root_layer->id());
+ root_scroll_layer->SetBounds(
+ gfx::Size(root_layer->bounds().width() + 100,
+ root_layer->bounds().height() + 100));
+ root_scroll_layer->SetIsDrawable(true);
+ root_scroll_layer->SetIsContainerForFixedPositionLayers(true);
+ root_layer->AddChild(root_scroll_layer);
+
+ layer_tree_host()->RegisterViewportLayers(
+ root_layer, root_scroll_layer, NULL);
+ layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 0.01f, 100.f);
+ }
+
virtual void BeginTest() OVERRIDE {
- layer_tree_host()->root_layer()->SetScrollable(true);
- layer_tree_host()->root_layer()
- ->SetMaxScrollOffset(gfx::Vector2d(100, 100));
PostSetNeedsCommitToMainThread();
}
virtual void DrawLayersOnThread(LayerTreeHostImpl* impl) OVERRIDE {
LayerImpl* root = impl->active_tree()->root_layer();
+ LayerImpl* scroll_layer = root->children()[0];
// Check that a fractional scroll delta is correctly accumulated over
// multiple commits.
switch (impl->active_tree()->source_frame_number()) {
case 0:
- EXPECT_VECTOR_EQ(root->scroll_offset(), gfx::Vector2d(0, 0));
- EXPECT_VECTOR_EQ(root->ScrollDelta(), gfx::Vector2d(0, 0));
+ EXPECT_VECTOR_EQ(scroll_layer->scroll_offset(), gfx::Vector2d(0, 0));
+ EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(), gfx::Vector2d(0, 0));
PostSetNeedsCommitToMainThread();
break;
case 1:
- EXPECT_VECTOR_EQ(root->scroll_offset(),
+ EXPECT_VECTOR_EQ(scroll_layer->scroll_offset(),
gfx::ToFlooredVector2d(scroll_amount_));
- EXPECT_VECTOR_EQ(root->ScrollDelta(),
+ EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(),
gfx::Vector2dF(fmod(scroll_amount_.x(), 1.0f), 0.0f));
PostSetNeedsCommitToMainThread();
break;
case 2:
EXPECT_VECTOR_EQ(
- root->scroll_offset(),
+ scroll_layer->scroll_offset(),
gfx::ToFlooredVector2d(scroll_amount_ + scroll_amount_));
EXPECT_VECTOR_EQ(
- root->ScrollDelta(),
+ scroll_layer->ScrollDelta(),
gfx::Vector2dF(fmod(2.0f * scroll_amount_.x(), 1.0f), 0.0f));
EndTest();
break;
}
- root->ScrollBy(scroll_amount_);
+ scroll_layer->ScrollBy(scroll_amount_);
}
virtual void AfterTest() OVERRIDE {}
@@ -408,11 +453,10 @@ class LayerTreeHostScrollTestCaseWithChild : public LayerTreeHostScrollTest {
root_scroll_layer_->SetBounds(gfx::Size(110, 110));
root_scroll_layer_->SetPosition(gfx::Point());
- root_scroll_layer_->SetAnchorPoint(gfx::PointF());
root_scroll_layer_->SetIsDrawable(true);
- root_scroll_layer_->SetScrollable(true);
- root_scroll_layer_->SetMaxScrollOffset(gfx::Vector2d(100, 100));
+ root_scroll_layer_->SetScrollClipLayerId(root_layer->id());
+ root_scroll_layer_->SetIsContainerForFixedPositionLayers(true);
root_layer->AddChild(root_scroll_layer_);
child_layer_ = ContentLayer::Create(&fake_content_layer_client_);
@@ -430,11 +474,10 @@ class LayerTreeHostScrollTestCaseWithChild : public LayerTreeHostScrollTest {
// Adjust the child layer horizontally so that scrolls will never hit it.
child_layer_->SetPosition(gfx::Point(60, 5));
}
- child_layer_->SetAnchorPoint(gfx::PointF());
child_layer_->SetIsDrawable(true);
- child_layer_->SetScrollable(true);
- child_layer_->SetMaxScrollOffset(gfx::Vector2d(100, 100));
+ child_layer_->SetScrollClipLayerId(root_layer->id());
+ child_layer_->SetBounds(root_scroll_layer_->bounds());
root_scroll_layer_->AddChild(child_layer_);
if (scroll_child_layer_) {
@@ -448,6 +491,8 @@ class LayerTreeHostScrollTestCaseWithChild : public LayerTreeHostScrollTest {
expected_scroll_layer_->SetScrollOffset(initial_offset_);
layer_tree_host()->SetRootLayer(root_layer);
+ layer_tree_host()->RegisterViewportLayers(
+ root_layer, root_scroll_layer_, NULL);
LayerTreeHostScrollTest::SetupTree();
}
@@ -465,7 +510,7 @@ class LayerTreeHostScrollTestCaseWithChild : public LayerTreeHostScrollTest {
final_scroll_offset_ = expected_scroll_layer_->scroll_offset();
}
- virtual void ApplyScrollAndScale(gfx::Vector2d scroll_delta,
+ virtual void ApplyScrollAndScale(const gfx::Vector2d& scroll_delta,
float scale) OVERRIDE {
num_scrolls_++;
}
@@ -724,26 +769,41 @@ class ImplSidePaintingScrollTestSimple : public ImplSidePaintingScrollTest {
impl_thread_scroll2_(-3, 10),
num_scrolls_(0) {}
+ virtual void SetupTree() OVERRIDE {
+ LayerTreeHostScrollTest::SetupTree();
+ Layer* root_layer = layer_tree_host()->root_layer();
+ scoped_refptr<Layer> root_scroll_layer = Layer::Create();
+ root_scroll_layer->SetScrollClipLayerId(root_layer->id());
+ root_scroll_layer->SetScrollOffset(initial_scroll_);
+ root_scroll_layer->SetBounds(
+ gfx::Size(root_layer->bounds().width() + 100,
+ root_layer->bounds().height() + 100));
+ root_scroll_layer->SetIsDrawable(true);
+ root_scroll_layer->SetIsContainerForFixedPositionLayers(true);
+ root_layer->AddChild(root_scroll_layer);
+
+ layer_tree_host()->RegisterViewportLayers(
+ root_layer, root_scroll_layer, NULL);
+ layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 0.01f, 100.f);
+ }
+
virtual void BeginTest() OVERRIDE {
- layer_tree_host()->root_layer()->SetScrollable(true);
- layer_tree_host()->root_layer()
- ->SetMaxScrollOffset(gfx::Vector2d(100, 100));
- layer_tree_host()->root_layer()->SetScrollOffset(initial_scroll_);
PostSetNeedsCommitToMainThread();
}
virtual void Layout() OVERRIDE {
Layer* root = layer_tree_host()->root_layer();
+ Layer* scroll_layer = root->children()[0];
if (!layer_tree_host()->source_frame_number()) {
- EXPECT_VECTOR_EQ(root->scroll_offset(), initial_scroll_);
+ EXPECT_VECTOR_EQ(scroll_layer->scroll_offset(), initial_scroll_);
} else {
- EXPECT_VECTOR_EQ(root->scroll_offset(),
+ EXPECT_VECTOR_EQ(scroll_layer->scroll_offset(),
initial_scroll_ + impl_thread_scroll1_);
// Pretend like Javascript updated the scroll position itself with a
// change of main_thread_scroll.
- root->SetScrollOffset(initial_scroll_ + main_thread_scroll_ +
- impl_thread_scroll1_);
+ scroll_layer->SetScrollOffset(initial_scroll_ + main_thread_scroll_ +
+ impl_thread_scroll1_);
}
}
@@ -758,6 +818,7 @@ class ImplSidePaintingScrollTestSimple : public ImplSidePaintingScrollTest {
ImplSidePaintingScrollTest::DrawLayersOnThread(impl);
LayerImpl* root = impl->active_tree()->root_layer();
+ LayerImpl* scroll_layer = root->children()[0];
LayerImpl* pending_root =
impl->active_tree()->FindPendingTreeLayerById(root->id());
@@ -765,12 +826,12 @@ class ImplSidePaintingScrollTestSimple : public ImplSidePaintingScrollTest {
case 0:
if (!impl->pending_tree()) {
impl->BlockNotifyReadyToActivateForTesting(true);
- EXPECT_VECTOR_EQ(root->ScrollDelta(), gfx::Vector2d());
- root->ScrollBy(impl_thread_scroll1_);
+ EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(), gfx::Vector2d());
+ scroll_layer->ScrollBy(impl_thread_scroll1_);
- EXPECT_VECTOR_EQ(root->scroll_offset(), initial_scroll_);
- EXPECT_VECTOR_EQ(root->ScrollDelta(), impl_thread_scroll1_);
- EXPECT_VECTOR_EQ(root->sent_scroll_delta(), gfx::Vector2d());
+ EXPECT_VECTOR_EQ(scroll_layer->scroll_offset(), initial_scroll_);
+ EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(), impl_thread_scroll1_);
+ EXPECT_VECTOR_EQ(scroll_layer->sent_scroll_delta(), gfx::Vector2d());
PostSetNeedsCommitToMainThread();
// CommitCompleteOnThread will trigger this function again
@@ -780,32 +841,36 @@ class ImplSidePaintingScrollTestSimple : public ImplSidePaintingScrollTest {
ASSERT_TRUE(pending_root);
EXPECT_EQ(impl->pending_tree()->source_frame_number(), 1);
- root->ScrollBy(impl_thread_scroll2_);
- EXPECT_VECTOR_EQ(root->scroll_offset(), initial_scroll_);
- EXPECT_VECTOR_EQ(root->ScrollDelta(),
+ scroll_layer->ScrollBy(impl_thread_scroll2_);
+ EXPECT_VECTOR_EQ(scroll_layer->scroll_offset(), initial_scroll_);
+ EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(),
impl_thread_scroll1_ + impl_thread_scroll2_);
- EXPECT_VECTOR_EQ(root->sent_scroll_delta(), impl_thread_scroll1_);
+ EXPECT_VECTOR_EQ(scroll_layer->sent_scroll_delta(),
+ impl_thread_scroll1_);
+ LayerImpl* pending_scroll_layer = pending_root->children()[0];
EXPECT_VECTOR_EQ(
- pending_root->scroll_offset(),
+ pending_scroll_layer->scroll_offset(),
initial_scroll_ + main_thread_scroll_ + impl_thread_scroll1_);
- EXPECT_VECTOR_EQ(pending_root->ScrollDelta(), impl_thread_scroll2_);
- EXPECT_VECTOR_EQ(pending_root->sent_scroll_delta(), gfx::Vector2d());
+ EXPECT_VECTOR_EQ(pending_scroll_layer->ScrollDelta(),
+ impl_thread_scroll2_);
+ EXPECT_VECTOR_EQ(pending_scroll_layer->sent_scroll_delta(),
+ gfx::Vector2d());
}
break;
case 1:
EXPECT_FALSE(impl->pending_tree());
EXPECT_VECTOR_EQ(
- root->scroll_offset(),
+ scroll_layer->scroll_offset(),
initial_scroll_ + main_thread_scroll_ + impl_thread_scroll1_);
- EXPECT_VECTOR_EQ(root->ScrollDelta(), impl_thread_scroll2_);
- EXPECT_VECTOR_EQ(root->sent_scroll_delta(), gfx::Vector2d());
+ EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(), impl_thread_scroll2_);
+ EXPECT_VECTOR_EQ(scroll_layer->sent_scroll_delta(), gfx::Vector2d());
EndTest();
break;
}
}
- virtual void ApplyScrollAndScale(gfx::Vector2d scroll_delta,
+ virtual void ApplyScrollAndScale(const gfx::Vector2d& scroll_delta,
float scale) OVERRIDE {
num_scrolls_++;
}
@@ -832,25 +897,40 @@ class ImplSidePaintingScrollTestImplOnlyScroll
ImplSidePaintingScrollTestImplOnlyScroll()
: initial_scroll_(20, 10), impl_thread_scroll_(-2, 3) {}
+ virtual void SetupTree() OVERRIDE {
+ LayerTreeHostScrollTest::SetupTree();
+ Layer* root_layer = layer_tree_host()->root_layer();
+ scoped_refptr<Layer> root_scroll_layer = Layer::Create();
+ root_scroll_layer->SetScrollClipLayerId(root_layer->id());
+ root_scroll_layer->SetScrollOffset(initial_scroll_);
+ root_scroll_layer->SetBounds(
+ gfx::Size(root_layer->bounds().width() + 100,
+ root_layer->bounds().height() + 100));
+ root_scroll_layer->SetIsDrawable(true);
+ root_scroll_layer->SetIsContainerForFixedPositionLayers(true);
+ root_layer->AddChild(root_scroll_layer);
+
+ layer_tree_host()->RegisterViewportLayers(
+ root_layer, root_scroll_layer, NULL);
+ layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 0.01f, 100.f);
+ }
+
virtual void BeginTest() OVERRIDE {
- layer_tree_host()->root_layer()->SetScrollable(true);
- layer_tree_host()->root_layer()->SetMaxScrollOffset(
- gfx::Vector2d(100, 100));
- layer_tree_host()->root_layer()->SetScrollOffset(initial_scroll_);
PostSetNeedsCommitToMainThread();
}
virtual void WillCommit() OVERRIDE {
Layer* root = layer_tree_host()->root_layer();
+ Layer* scroll_layer = root->children()[0];
switch (layer_tree_host()->source_frame_number()) {
case 0:
- EXPECT_TRUE(root->needs_push_properties());
+ EXPECT_TRUE(scroll_layer->needs_push_properties());
break;
case 1:
// Even if this layer doesn't need push properties, it should
// still pick up scrolls that happen on the active layer during
// commit.
- EXPECT_FALSE(root->needs_push_properties());
+ EXPECT_FALSE(scroll_layer->needs_push_properties());
break;
}
}
@@ -859,8 +939,10 @@ class ImplSidePaintingScrollTestImplOnlyScroll
// Scroll after the 2nd commit has started.
if (impl->active_tree()->source_frame_number() == 0) {
LayerImpl* active_root = impl->active_tree()->root_layer();
+ LayerImpl* active_scroll_layer = active_root->children()[0];
ASSERT_TRUE(active_root);
- active_root->ScrollBy(impl_thread_scroll_);
+ ASSERT_TRUE(active_scroll_layer);
+ active_scroll_layer->ScrollBy(impl_thread_scroll_);
}
}
@@ -868,33 +950,45 @@ class ImplSidePaintingScrollTestImplOnlyScroll
// We force a second draw here of the first commit before activating
// the second commit.
LayerImpl* active_root = impl->active_tree()->root_layer();
+ LayerImpl* active_scroll_layer =
+ active_root ? active_root->children()[0] : NULL;
LayerImpl* pending_root = impl->pending_tree()->root_layer();
+ LayerImpl* pending_scroll_layer = pending_root->children()[0];
ASSERT_TRUE(pending_root);
+ ASSERT_TRUE(pending_scroll_layer);
switch (impl->pending_tree()->source_frame_number()) {
case 0:
- EXPECT_VECTOR_EQ(pending_root->scroll_offset(), initial_scroll_);
- EXPECT_VECTOR_EQ(pending_root->ScrollDelta(), gfx::Vector2d());
- EXPECT_VECTOR_EQ(pending_root->sent_scroll_delta(), gfx::Vector2d());
+ EXPECT_VECTOR_EQ(pending_scroll_layer->scroll_offset(),
+ initial_scroll_);
+ EXPECT_VECTOR_EQ(pending_scroll_layer->ScrollDelta(), gfx::Vector2d());
+ EXPECT_VECTOR_EQ(pending_scroll_layer->sent_scroll_delta(),
+ gfx::Vector2d());
EXPECT_FALSE(active_root);
break;
case 1:
// Even though the scroll happened during the commit, both layers
// should have the appropriate scroll delta.
- EXPECT_VECTOR_EQ(pending_root->scroll_offset(), initial_scroll_);
- EXPECT_VECTOR_EQ(pending_root->ScrollDelta(), impl_thread_scroll_);
- EXPECT_VECTOR_EQ(pending_root->sent_scroll_delta(), gfx::Vector2d());
+ EXPECT_VECTOR_EQ(pending_scroll_layer->scroll_offset(),
+ initial_scroll_);
+ EXPECT_VECTOR_EQ(pending_scroll_layer->ScrollDelta(),
+ impl_thread_scroll_);
+ EXPECT_VECTOR_EQ(pending_scroll_layer->sent_scroll_delta(),
+ gfx::Vector2d());
ASSERT_TRUE(active_root);
- EXPECT_VECTOR_EQ(active_root->scroll_offset(), initial_scroll_);
- EXPECT_VECTOR_EQ(active_root->ScrollDelta(), impl_thread_scroll_);
- EXPECT_VECTOR_EQ(active_root->sent_scroll_delta(), gfx::Vector2d());
+ EXPECT_VECTOR_EQ(active_scroll_layer->scroll_offset(), initial_scroll_);
+ EXPECT_VECTOR_EQ(active_scroll_layer->ScrollDelta(),
+ impl_thread_scroll_);
+ EXPECT_VECTOR_EQ(active_scroll_layer->sent_scroll_delta(),
+ gfx::Vector2d());
break;
case 2:
// On the next commit, this delta should have been sent and applied.
- EXPECT_VECTOR_EQ(pending_root->scroll_offset(),
+ EXPECT_VECTOR_EQ(pending_scroll_layer->scroll_offset(),
initial_scroll_ + impl_thread_scroll_);
- EXPECT_VECTOR_EQ(pending_root->ScrollDelta(), gfx::Vector2d());
- EXPECT_VECTOR_EQ(pending_root->sent_scroll_delta(), gfx::Vector2d());
+ EXPECT_VECTOR_EQ(pending_scroll_layer->ScrollDelta(), gfx::Vector2d());
+ EXPECT_VECTOR_EQ(pending_scroll_layer->sent_scroll_delta(),
+ gfx::Vector2d());
EndTest();
break;
}
@@ -904,18 +998,19 @@ class ImplSidePaintingScrollTestImplOnlyScroll
ImplSidePaintingScrollTest::DrawLayersOnThread(impl);
LayerImpl* root = impl->active_tree()->root_layer();
+ LayerImpl* scroll_layer = root->children()[0];
switch (impl->active_tree()->source_frame_number()) {
case 0:
- EXPECT_VECTOR_EQ(root->scroll_offset(), initial_scroll_);
- EXPECT_VECTOR_EQ(root->ScrollDelta(), gfx::Vector2d());
- EXPECT_VECTOR_EQ(root->sent_scroll_delta(), gfx::Vector2d());
+ EXPECT_VECTOR_EQ(scroll_layer->scroll_offset(), initial_scroll_);
+ EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(), gfx::Vector2d());
+ EXPECT_VECTOR_EQ(scroll_layer->sent_scroll_delta(), gfx::Vector2d());
PostSetNeedsCommitToMainThread();
break;
case 1:
- EXPECT_VECTOR_EQ(root->scroll_offset(), initial_scroll_);
- EXPECT_VECTOR_EQ(root->ScrollDelta(), impl_thread_scroll_);
- EXPECT_VECTOR_EQ(root->sent_scroll_delta(), gfx::Vector2d());
+ EXPECT_VECTOR_EQ(scroll_layer->scroll_offset(), initial_scroll_);
+ EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(), impl_thread_scroll_);
+ EXPECT_VECTOR_EQ(scroll_layer->sent_scroll_delta(), gfx::Vector2d());
PostSetNeedsCommitToMainThread();
break;
}
@@ -935,23 +1030,37 @@ class LayerTreeHostScrollTestScrollZeroMaxScrollOffset
public:
LayerTreeHostScrollTestScrollZeroMaxScrollOffset() {}
+ virtual void SetupTree() OVERRIDE {
+ LayerTreeTest::SetupTree();
+ scoped_refptr<Layer> scroll_layer = Layer::Create();
+ layer_tree_host()->root_layer()->AddChild(scroll_layer);
+ }
+
virtual void BeginTest() OVERRIDE { PostSetNeedsCommitToMainThread(); }
virtual void DrawLayersOnThread(LayerTreeHostImpl* impl) OVERRIDE {
LayerImpl* root = impl->active_tree()->root_layer();
- root->SetScrollable(true);
+ LayerImpl* scroll_layer = root->children()[0];
+ scroll_layer->SetScrollClipLayer(root->id());
- root->SetMaxScrollOffset(gfx::Vector2d(100, 100));
+ // Set max_scroll_offset = (100, 100).
+ scroll_layer->SetBounds(
+ gfx::Size(root->bounds().width() + 100, root->bounds().height() + 100));
EXPECT_EQ(InputHandler::ScrollStarted,
- root->TryScroll(gfx::PointF(0.0f, 1.0f), InputHandler::Gesture));
+ scroll_layer->TryScroll(gfx::PointF(0.0f, 1.0f),
+ InputHandler::Gesture));
- root->SetMaxScrollOffset(gfx::Vector2d(0, 0));
+ // Set max_scroll_offset = (0, 0).
+ scroll_layer->SetBounds(root->bounds());
EXPECT_EQ(InputHandler::ScrollIgnored,
- root->TryScroll(gfx::PointF(0.0f, 1.0f), InputHandler::Gesture));
+ scroll_layer->TryScroll(gfx::PointF(0.0f, 1.0f),
+ InputHandler::Gesture));
- root->SetMaxScrollOffset(gfx::Vector2d(-100, -100));
+ // Set max_scroll_offset = (-100, -100).
+ scroll_layer->SetBounds(gfx::Size());
EXPECT_EQ(InputHandler::ScrollIgnored,
- root->TryScroll(gfx::PointF(0.0f, 1.0f), InputHandler::Gesture));
+ scroll_layer->TryScroll(gfx::PointF(0.0f, 1.0f),
+ InputHandler::Gesture));
EndTest();
}
@@ -984,7 +1093,9 @@ class ThreadCheckingInputHandlerClient : public InputHandlerClient {
*received_stop_flinging_ = true;
}
- virtual void DidOverscroll(const DidOverscrollParams& params) OVERRIDE {
+ virtual void DidOverscroll(const gfx::Vector2dF& accumulated_overscroll,
+ const gfx::Vector2dF& latest_overscroll_delta)
+ OVERRIDE {
if (!task_runner_->BelongsToCurrentThread())
ADD_FAILURE() << "DidOverscroll called on wrong thread";
}
@@ -1012,8 +1123,13 @@ TEST(LayerTreeHostFlingTest, DidStopFlingingThread) {
FakeLayerTreeHostClient client(FakeLayerTreeHostClient::DIRECT_3D);
ASSERT_TRUE(impl_thread.message_loop_proxy().get());
- scoped_ptr<LayerTreeHost> layer_tree_host = LayerTreeHost::CreateThreaded(
- &client, NULL, settings, impl_thread.message_loop_proxy());
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
+ scoped_ptr<LayerTreeHost> layer_tree_host =
+ LayerTreeHost::CreateThreaded(&client,
+ shared_bitmap_manager.get(),
+ settings,
+ impl_thread.message_loop_proxy());
impl_thread.message_loop_proxy()
->PostTask(FROM_HERE,
@@ -1091,10 +1207,10 @@ class LayerTreeHostScrollTestLayerStructureChange
ContentLayer::Create(&fake_content_layer_client_);
scroll_layer->SetBounds(gfx::Size(110, 110));
scroll_layer->SetPosition(gfx::Point(0, 0));
- scroll_layer->SetAnchorPoint(gfx::PointF());
scroll_layer->SetIsDrawable(true);
- scroll_layer->SetScrollable(true);
- scroll_layer->SetMaxScrollOffset(gfx::Vector2d(100, 100));
+ scroll_layer->SetScrollClipLayerId(parent->id());
+ scroll_layer->SetBounds(gfx::Size(parent->bounds().width() + 100,
+ parent->bounds().height() + 100));
scroll_layer->set_did_scroll_callback(base::Bind(
&FakeLayerScrollClient::DidScroll, base::Unretained(client)));
client->owner_ = this;
diff --git a/chromium/cc/trees/layer_tree_host_unittest_video.cc b/chromium/cc/trees/layer_tree_host_unittest_video.cc
index 5413a602d4b..5484e4c9163 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_video.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_video.cc
@@ -25,14 +25,12 @@ class LayerTreeHostVideoTestSetNeedsDisplay
virtual void SetupTree() OVERRIDE {
scoped_refptr<Layer> root = Layer::Create();
root->SetBounds(gfx::Size(10, 10));
- root->SetAnchorPoint(gfx::PointF());
root->SetIsDrawable(true);
scoped_refptr<VideoLayer> video = VideoLayer::Create(
&video_frame_provider_);
video->SetPosition(gfx::PointF(3.f, 3.f));
video->SetBounds(gfx::Size(4, 4));
- video->SetAnchorPoint(gfx::PointF());
video->SetIsDrawable(true);
root->AddChild(video);
@@ -46,9 +44,9 @@ class LayerTreeHostVideoTestSetNeedsDisplay
PostSetNeedsCommitToMainThread();
}
- virtual bool PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
- LayerTreeHostImpl::FrameData* frame,
- bool result) OVERRIDE {
+ virtual DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
+ LayerTreeHostImpl::FrameData* frame,
+ DrawResult draw_result) OVERRIDE {
LayerImpl* root_layer = host_impl->active_tree()->root_layer();
RenderSurfaceImpl* root_surface = root_layer->render_surface();
gfx::RectF damage_rect =
@@ -68,8 +66,8 @@ class LayerTreeHostVideoTestSetNeedsDisplay
break;
}
- EXPECT_TRUE(result);
- return result;
+ EXPECT_EQ(DRAW_SUCCESS, draw_result);
+ return draw_result;
}
virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
diff --git a/chromium/cc/trees/layer_tree_impl.cc b/chromium/cc/trees/layer_tree_impl.cc
index 9f181cda458..d5ec804eaa9 100644
--- a/chromium/cc/trees/layer_tree_impl.cc
+++ b/chromium/cc/trees/layer_tree_impl.cc
@@ -4,29 +4,72 @@
#include "cc/trees/layer_tree_impl.h"
+#include <limits>
+#include <set>
+
#include "base/debug/trace_event.h"
#include "cc/animation/keyframed_animation_curve.h"
#include "cc/animation/scrollbar_animation_controller.h"
+#include "cc/animation/scrollbar_animation_controller_linear_fade.h"
+#include "cc/animation/scrollbar_animation_controller_thinning.h"
#include "cc/base/math_util.h"
#include "cc/base/util.h"
+#include "cc/debug/devtools_instrumentation.h"
#include "cc/debug/traced_value.h"
#include "cc/layers/heads_up_display_layer_impl.h"
#include "cc/layers/layer.h"
+#include "cc/layers/layer_iterator.h"
#include "cc/layers/render_surface_impl.h"
#include "cc/layers/scrollbar_layer_impl_base.h"
#include "cc/resources/ui_resource_request.h"
#include "cc/trees/layer_tree_host_common.h"
#include "cc/trees/layer_tree_host_impl.h"
+#include "ui/gfx/point_conversions.h"
#include "ui/gfx/size_conversions.h"
#include "ui/gfx/vector2d_conversions.h"
namespace cc {
+// This class exists to split the LayerScrollOffsetDelegate between the
+// InnerViewportScrollLayer and the OuterViewportScrollLayer in a manner
+// that never requires the embedder or LayerImpl to know about.
+class LayerScrollOffsetDelegateProxy : public LayerImpl::ScrollOffsetDelegate {
+ public:
+ LayerScrollOffsetDelegateProxy(LayerImpl* layer,
+ LayerScrollOffsetDelegate* delegate,
+ LayerTreeImpl* layer_tree)
+ : layer_(layer), delegate_(delegate), layer_tree_impl_(layer_tree) {}
+ virtual ~LayerScrollOffsetDelegateProxy() {}
+
+ gfx::Vector2dF last_set_scroll_offset() const {
+ return last_set_scroll_offset_;
+ }
+
+ // LayerScrollOffsetDelegate implementation.
+ virtual void SetTotalScrollOffset(const gfx::Vector2dF& new_offset) OVERRIDE {
+ last_set_scroll_offset_ = new_offset;
+ layer_tree_impl_->UpdateScrollOffsetDelegate();
+ }
+
+ virtual gfx::Vector2dF GetTotalScrollOffset() OVERRIDE {
+ return layer_tree_impl_->GetDelegatedScrollOffset(layer_);
+ }
+
+ virtual bool IsExternalFlingActive() const OVERRIDE {
+ return delegate_->IsExternalFlingActive();
+ }
+
+ private:
+ LayerImpl* layer_;
+ LayerScrollOffsetDelegate* delegate_;
+ LayerTreeImpl* layer_tree_impl_;
+ gfx::Vector2dF last_set_scroll_offset_;
+};
+
LayerTreeImpl::LayerTreeImpl(LayerTreeHostImpl* layer_tree_host_impl)
: layer_tree_host_impl_(layer_tree_host_impl),
source_frame_number_(-1),
hud_layer_(0),
- root_scroll_layer_(NULL),
currently_scrolling_layer_(NULL),
root_layer_scroll_offset_delegate_(NULL),
background_color_(0),
@@ -41,69 +84,99 @@ LayerTreeImpl::LayerTreeImpl(LayerTreeHostImpl* layer_tree_host_impl)
max_page_scale_factor_(0),
scrolling_layer_id_from_previous_tree_(0),
contents_textures_purged_(false),
+ requires_high_res_to_draw_(false),
viewport_size_invalid_(false),
needs_update_draw_properties_(true),
needs_full_tree_sync_(true),
- next_activation_forces_redraw_(false) {
+ next_activation_forces_redraw_(false),
+ render_surface_layer_list_id_(0) {
}
LayerTreeImpl::~LayerTreeImpl() {
// Need to explicitly clear the tree prior to destroying this so that
// the LayerTreeImpl pointer is still valid in the LayerImpl dtor.
- root_layer_.reset();
+ DCHECK(!root_layer_);
+ DCHECK(layers_with_copy_output_request_.empty());
}
-static LayerImpl* FindRootScrollLayerRecursive(LayerImpl* layer) {
- if (!layer)
- return NULL;
-
- if (layer->scrollable())
- return layer;
-
- for (size_t i = 0; i < layer->children().size(); ++i) {
- LayerImpl* found = FindRootScrollLayerRecursive(layer->children()[i]);
- if (found)
- return found;
- }
+void LayerTreeImpl::Shutdown() { root_layer_.reset(); }
- return NULL;
+void LayerTreeImpl::ReleaseResources() {
+ if (root_layer_)
+ ReleaseResourcesRecursive(root_layer_.get());
}
void LayerTreeImpl::SetRootLayer(scoped_ptr<LayerImpl> layer) {
- if (root_scroll_layer_)
- root_scroll_layer_->SetScrollOffsetDelegate(NULL);
+ if (inner_viewport_scroll_layer_)
+ inner_viewport_scroll_layer_->SetScrollOffsetDelegate(NULL);
+ if (outer_viewport_scroll_layer_)
+ outer_viewport_scroll_layer_->SetScrollOffsetDelegate(NULL);
+ inner_viewport_scroll_delegate_proxy_.reset();
+ outer_viewport_scroll_delegate_proxy_.reset();
+
root_layer_ = layer.Pass();
currently_scrolling_layer_ = NULL;
- root_scroll_layer_ = NULL;
+ inner_viewport_scroll_layer_ = NULL;
+ outer_viewport_scroll_layer_ = NULL;
+ page_scale_layer_ = NULL;
layer_tree_host_impl_->OnCanDrawStateChangedForTree();
}
-void LayerTreeImpl::FindRootScrollLayer() {
- root_scroll_layer_ = FindRootScrollLayerRecursive(root_layer_.get());
+LayerImpl* LayerTreeImpl::InnerViewportScrollLayer() const {
+ return inner_viewport_scroll_layer_;
+}
- if (root_scroll_layer_) {
- UpdateMaxScrollOffset();
- root_scroll_layer_->SetScrollOffsetDelegate(
- root_layer_scroll_offset_delegate_);
- }
+LayerImpl* LayerTreeImpl::OuterViewportScrollLayer() const {
+ return outer_viewport_scroll_layer_;
+}
- if (scrolling_layer_id_from_previous_tree_) {
- currently_scrolling_layer_ = LayerTreeHostCommon::FindLayerInSubtree(
- root_layer_.get(),
- scrolling_layer_id_from_previous_tree_);
- }
+gfx::Vector2dF LayerTreeImpl::TotalScrollOffset() const {
+ gfx::Vector2dF offset;
- scrolling_layer_id_from_previous_tree_ = 0;
+ if (inner_viewport_scroll_layer_)
+ offset += inner_viewport_scroll_layer_->TotalScrollOffset();
+
+ if (outer_viewport_scroll_layer_)
+ offset += outer_viewport_scroll_layer_->TotalScrollOffset();
+
+ return offset;
+}
+
+gfx::Vector2dF LayerTreeImpl::TotalMaxScrollOffset() const {
+ gfx::Vector2dF offset;
+
+ if (inner_viewport_scroll_layer_)
+ offset += inner_viewport_scroll_layer_->MaxScrollOffset();
+
+ if (outer_viewport_scroll_layer_)
+ offset += outer_viewport_scroll_layer_->MaxScrollOffset();
+
+ return offset;
+}
+gfx::Vector2dF LayerTreeImpl::TotalScrollDelta() const {
+ DCHECK(inner_viewport_scroll_layer_);
+ gfx::Vector2dF delta = inner_viewport_scroll_layer_->ScrollDelta();
+
+ if (outer_viewport_scroll_layer_)
+ delta += outer_viewport_scroll_layer_->ScrollDelta();
+
+ return delta;
}
scoped_ptr<LayerImpl> LayerTreeImpl::DetachLayerTree() {
// Clear all data structures that have direct references to the layer tree.
scrolling_layer_id_from_previous_tree_ =
currently_scrolling_layer_ ? currently_scrolling_layer_->id() : 0;
- if (root_scroll_layer_)
- root_scroll_layer_->SetScrollOffsetDelegate(NULL);
- root_scroll_layer_ = NULL;
+ if (inner_viewport_scroll_layer_)
+ inner_viewport_scroll_layer_->SetScrollOffsetDelegate(NULL);
+ if (outer_viewport_scroll_layer_)
+ outer_viewport_scroll_layer_->SetScrollOffsetDelegate(NULL);
+ inner_viewport_scroll_delegate_proxy_.reset();
+ outer_viewport_scroll_delegate_proxy_.reset();
+ inner_viewport_scroll_layer_ = NULL;
+ outer_viewport_scroll_layer_ = NULL;
+ page_scale_layer_ = NULL;
currently_scrolling_layer_ = NULL;
render_surface_layer_list_.clear();
@@ -116,24 +189,25 @@ void LayerTreeImpl::PushPropertiesTo(LayerTreeImpl* target_tree) {
DCHECK_EQ(ui_resource_request_queue_.size(), 0u);
if (next_activation_forces_redraw_) {
- layer_tree_host_impl_->SetFullRootLayerDamage();
+ target_tree->ForceRedrawNextActivation();
next_activation_forces_redraw_ = false;
}
target_tree->PassSwapPromises(&swap_promise_list_);
- target_tree->SetPageScaleFactorAndLimits(
- page_scale_factor(), min_page_scale_factor(), max_page_scale_factor());
- target_tree->SetPageScaleDelta(
+ target_tree->SetPageScaleValues(
+ page_scale_factor(), min_page_scale_factor(), max_page_scale_factor(),
target_tree->page_scale_delta() / target_tree->sent_page_scale_delta());
target_tree->set_sent_page_scale_delta(1);
- if (settings().use_pinch_virtual_viewport) {
+ if (page_scale_layer_ && inner_viewport_scroll_layer_) {
target_tree->SetViewportLayersFromIds(
page_scale_layer_->id(),
inner_viewport_scroll_layer_->id(),
outer_viewport_scroll_layer_ ? outer_viewport_scroll_layer_->id()
: Layer::INVALID_ID);
+ } else {
+ target_tree->ClearViewportLayers();
}
// This should match the property synchronization in
// LayerTreeHost::finishCommitOnImplThread().
@@ -146,6 +220,10 @@ void LayerTreeImpl::PushPropertiesTo(LayerTreeImpl* target_tree) {
else
target_tree->ResetContentsTexturesPurged();
+ // Always reset this flag on activation, as we would only have activated
+ // if we were in a good state.
+ target_tree->ResetRequiresHighResToDraw();
+
if (ViewportSizeInvalid())
target_tree->SetViewportSizeInvalid();
else
@@ -159,12 +237,10 @@ void LayerTreeImpl::PushPropertiesTo(LayerTreeImpl* target_tree) {
target_tree->set_hud_layer(NULL);
}
-LayerImpl* LayerTreeImpl::RootScrollLayer() const {
- return root_scroll_layer_;
-}
-
-LayerImpl* LayerTreeImpl::RootContainerLayer() const {
- return root_scroll_layer_ ? root_scroll_layer_->parent() : NULL;
+LayerImpl* LayerTreeImpl::InnerViewportContainerLayer() const {
+ return inner_viewport_scroll_layer_
+ ? inner_viewport_scroll_layer_->scroll_clip_layer()
+ : NULL;
}
LayerImpl* LayerTreeImpl::CurrentlyScrollingLayer() const {
@@ -178,11 +254,11 @@ void LayerTreeImpl::SetCurrentlyScrollingLayer(LayerImpl* layer) {
if (currently_scrolling_layer_ &&
currently_scrolling_layer_->scrollbar_animation_controller())
- currently_scrolling_layer_->scrollbar_animation_controller()->
- DidScrollGestureEnd(CurrentPhysicalTimeTicks());
+ currently_scrolling_layer_->scrollbar_animation_controller()
+ ->DidScrollEnd();
currently_scrolling_layer_ = layer;
if (layer && layer->scrollbar_animation_controller())
- layer->scrollbar_animation_controller()->DidScrollGestureBegin();
+ layer->scrollbar_animation_controller()->DidScrollBegin();
}
void LayerTreeImpl::ClearCurrentlyScrollingLayer() {
@@ -190,79 +266,106 @@ void LayerTreeImpl::ClearCurrentlyScrollingLayer() {
scrolling_layer_id_from_previous_tree_ = 0;
}
+float LayerTreeImpl::VerticalAdjust(const int clip_layer_id) const {
+ LayerImpl* container_layer = InnerViewportContainerLayer();
+ if (!container_layer || clip_layer_id != container_layer->id())
+ return 0.f;
+
+ return layer_tree_host_impl_->VerticalAdjust();
+}
+
+namespace {
+
+void ForceScrollbarParameterUpdateAfterScaleChange(LayerImpl* current_layer) {
+ if (!current_layer)
+ return;
+
+ while (current_layer) {
+ current_layer->ScrollbarParametersDidChange();
+ current_layer = current_layer->parent();
+ }
+}
+
+} // namespace
+
void LayerTreeImpl::SetPageScaleFactorAndLimits(float page_scale_factor,
float min_page_scale_factor, float max_page_scale_factor) {
- if (!page_scale_factor)
- return;
+ SetPageScaleValues(page_scale_factor, min_page_scale_factor,
+ max_page_scale_factor, page_scale_delta_);
+}
+
+void LayerTreeImpl::SetPageScaleDelta(float delta) {
+ SetPageScaleValues(page_scale_factor_, min_page_scale_factor_,
+ max_page_scale_factor_, delta);
+}
+
+void LayerTreeImpl::SetPageScaleValues(float page_scale_factor,
+ float min_page_scale_factor, float max_page_scale_factor,
+ float page_scale_delta) {
+ bool page_scale_changed =
+ min_page_scale_factor != min_page_scale_factor_ ||
+ max_page_scale_factor != max_page_scale_factor_ ||
+ page_scale_factor != page_scale_factor_;
min_page_scale_factor_ = min_page_scale_factor;
max_page_scale_factor_ = max_page_scale_factor;
page_scale_factor_ = page_scale_factor;
- if (root_layer_scroll_offset_delegate_) {
- root_layer_scroll_offset_delegate_->SetTotalPageScaleFactor(
- total_page_scale_factor());
- }
-}
-
-void LayerTreeImpl::SetPageScaleDelta(float delta) {
- // Clamp to the current min/max limits.
- float total = page_scale_factor_ * delta;
+ float total = page_scale_factor_ * page_scale_delta;
if (min_page_scale_factor_ && total < min_page_scale_factor_)
- delta = min_page_scale_factor_ / page_scale_factor_;
+ page_scale_delta = min_page_scale_factor_ / page_scale_factor_;
else if (max_page_scale_factor_ && total > max_page_scale_factor_)
- delta = max_page_scale_factor_ / page_scale_factor_;
+ page_scale_delta = max_page_scale_factor_ / page_scale_factor_;
- if (delta == page_scale_delta_)
+ if (page_scale_delta_ == page_scale_delta && !page_scale_changed)
return;
- page_scale_delta_ = delta;
+ if (page_scale_delta_ != page_scale_delta) {
+ page_scale_delta_ = page_scale_delta;
- if (IsActiveTree()) {
- LayerTreeImpl* pending_tree = layer_tree_host_impl_->pending_tree();
- if (pending_tree) {
- DCHECK_EQ(1, pending_tree->sent_page_scale_delta());
- pending_tree->SetPageScaleDelta(
- page_scale_delta_ / sent_page_scale_delta_);
+ if (IsActiveTree()) {
+ LayerTreeImpl* pending_tree = layer_tree_host_impl_->pending_tree();
+ if (pending_tree) {
+ DCHECK_EQ(1, pending_tree->sent_page_scale_delta());
+ pending_tree->SetPageScaleDelta(
+ page_scale_delta_ / sent_page_scale_delta_);
+ }
}
- }
- UpdateMaxScrollOffset();
- set_needs_update_draw_properties();
+ set_needs_update_draw_properties();
+ }
if (root_layer_scroll_offset_delegate_) {
- root_layer_scroll_offset_delegate_->SetTotalPageScaleFactor(
- total_page_scale_factor());
+ root_layer_scroll_offset_delegate_->UpdateRootLayerState(
+ TotalScrollOffset(),
+ TotalMaxScrollOffset(),
+ ScrollableSize(),
+ total_page_scale_factor(),
+ min_page_scale_factor_,
+ max_page_scale_factor_);
}
+
+ ForceScrollbarParameterUpdateAfterScaleChange(page_scale_layer());
}
gfx::SizeF LayerTreeImpl::ScrollableViewportSize() const {
- return gfx::ScaleSize(layer_tree_host_impl_->UnscaledScrollableViewportSize(),
- 1.0f / total_page_scale_factor());
+ if (outer_viewport_scroll_layer_)
+ return layer_tree_host_impl_->UnscaledScrollableViewportSize();
+ else
+ return gfx::ScaleSize(
+ layer_tree_host_impl_->UnscaledScrollableViewportSize(),
+ 1.0f / total_page_scale_factor());
}
gfx::Rect LayerTreeImpl::RootScrollLayerDeviceViewportBounds() const {
- if (!root_scroll_layer_ || root_scroll_layer_->children().empty())
+ LayerImpl* root_scroll_layer = OuterViewportScrollLayer()
+ ? OuterViewportScrollLayer()
+ : InnerViewportScrollLayer();
+ if (!root_scroll_layer || root_scroll_layer->children().empty())
return gfx::Rect();
- LayerImpl* layer = root_scroll_layer_->children()[0];
- return MathUtil::MapClippedRect(
- layer->screen_space_transform(),
- gfx::Rect(layer->content_bounds()));
-}
-
-void LayerTreeImpl::UpdateMaxScrollOffset() {
- LayerImpl* root_scroll = RootScrollLayer();
- if (!root_scroll || !root_scroll->children().size())
- return;
-
- gfx::Vector2dF max_scroll = gfx::Rect(ScrollableSize()).bottom_right() -
- gfx::RectF(ScrollableViewportSize()).bottom_right();
-
- // The viewport may be larger than the contents in some cases, such as
- // having a vertical scrollbar but no horizontal overflow.
- max_scroll.SetToMax(gfx::Vector2dF());
-
- root_scroll_layer_->SetMaxScrollOffset(gfx::ToFlooredVector2d(max_scroll));
+ LayerImpl* layer = root_scroll_layer->children()[0];
+ return MathUtil::MapEnclosingClippedRect(layer->screen_space_transform(),
+ gfx::Rect(layer->content_bounds()));
}
static void ApplySentScrollDeltasFromAbortedCommitTo(LayerImpl* layer) {
@@ -311,6 +414,20 @@ void LayerTreeImpl::SetViewportLayersFromIds(
LayerById(outer_viewport_scroll_layer_id);
DCHECK(outer_viewport_scroll_layer_ ||
outer_viewport_scroll_layer_id == Layer::INVALID_ID);
+
+ if (!root_layer_scroll_offset_delegate_)
+ return;
+
+ inner_viewport_scroll_delegate_proxy_ = make_scoped_ptr(
+ new LayerScrollOffsetDelegateProxy(inner_viewport_scroll_layer_,
+ root_layer_scroll_offset_delegate_,
+ this));
+
+ if (outer_viewport_scroll_layer_)
+ outer_viewport_scroll_delegate_proxy_ = make_scoped_ptr(
+ new LayerScrollOffsetDelegateProxy(outer_viewport_scroll_layer_,
+ root_layer_scroll_offset_delegate_,
+ this));
}
void LayerTreeImpl::ClearViewportLayers() {
@@ -319,55 +436,19 @@ void LayerTreeImpl::ClearViewportLayers() {
outer_viewport_scroll_layer_ = NULL;
}
-// TODO(wjmaclean) This needs to go away, and be replaced with a single core
-// of login that works for both scrollbar layer types. This is already planned
-// as part of the larger pinch-zoom re-factoring viewport.
-void LayerTreeImpl::UpdateSolidColorScrollbars() {
- LayerImpl* root_scroll = RootScrollLayer();
- DCHECK(root_scroll);
- DCHECK(IsActiveTree());
-
- gfx::RectF scrollable_viewport(
- gfx::PointAtOffsetFromOrigin(root_scroll->TotalScrollOffset()),
- ScrollableViewportSize());
- float vertical_adjust = 0.0f;
- if (RootContainerLayer())
- vertical_adjust =
- layer_tree_host_impl_->UnscaledScrollableViewportSize().height() -
- RootContainerLayer()->bounds().height();
- if (ScrollbarLayerImplBase* horiz =
- root_scroll->horizontal_scrollbar_layer()) {
- horiz->SetVerticalAdjust(vertical_adjust);
- horiz->SetVisibleToTotalLengthRatio(
- scrollable_viewport.width() / ScrollableSize().width());
- }
- if (ScrollbarLayerImplBase* vertical =
- root_scroll->vertical_scrollbar_layer()) {
- vertical->SetVerticalAdjust(vertical_adjust);
- vertical->SetVisibleToTotalLengthRatio(
- scrollable_viewport.height() / ScrollableSize().height());
- }
-}
-
-void LayerTreeImpl::UpdateDrawProperties() {
- if (IsActiveTree() && RootScrollLayer() && RootContainerLayer())
- UpdateRootScrollLayerSizeDelta();
-
- if (IsActiveTree() &&
- RootContainerLayer()
- && !RootContainerLayer()->masks_to_bounds()) {
- UpdateSolidColorScrollbars();
- }
-
- needs_update_draw_properties_ = false;
- render_surface_layer_list_.clear();
+bool LayerTreeImpl::UpdateDrawProperties() {
+ if (!needs_update_draw_properties_)
+ return true;
// For max_texture_size.
if (!layer_tree_host_impl_->renderer())
- return;
+ return false;
if (!root_layer())
- return;
+ return false;
+
+ needs_update_draw_properties_ = false;
+ render_surface_layer_list_.clear();
{
TRACE_EVENT2("cc",
@@ -377,9 +458,11 @@ void LayerTreeImpl::UpdateDrawProperties() {
"SourceFrameNumber",
source_frame_number_);
LayerImpl* page_scale_layer =
- page_scale_layer_ ? page_scale_layer_ : RootContainerLayer();
+ page_scale_layer_ ? page_scale_layer_ : InnerViewportContainerLayer();
bool can_render_to_separate_surface =
!output_surface()->ForcedDrawToSoftwareDevice();
+
+ ++render_surface_layer_list_id_;
LayerTreeHostCommon::CalcDrawPropsImplInputs inputs(
root_layer(),
DrawViewportSize(),
@@ -391,7 +474,8 @@ void LayerTreeImpl::UpdateDrawProperties() {
settings().can_use_lcd_text,
can_render_to_separate_surface,
settings().layer_transforms_should_scale_layer_contents,
- &render_surface_layer_list_);
+ &render_surface_layer_list_,
+ render_surface_layer_list_id_);
LayerTreeHostCommon::CalculateDrawProperties(&inputs);
}
@@ -405,29 +489,29 @@ void LayerTreeImpl::UpdateDrawProperties() {
// LayerIterator is used here instead of CallFunctionForSubtree to only
// UpdateTilePriorities on layers that will be visible (and thus have valid
// draw properties) and not because any ordering is required.
- typedef LayerIterator<LayerImpl,
- LayerImplList,
- RenderSurfaceImpl,
- LayerIteratorActions::FrontToBack> LayerIteratorType;
+ typedef LayerIterator<LayerImpl> LayerIteratorType;
LayerIteratorType end = LayerIteratorType::End(&render_surface_layer_list_);
for (LayerIteratorType it =
LayerIteratorType::Begin(&render_surface_layer_list_);
it != end;
++it) {
- if (!it.represents_itself())
- continue;
LayerImpl* layer = *it;
+ if (it.represents_itself())
+ layer->UpdateTiles();
+
+ if (!it.represents_contributing_render_surface())
+ continue;
- layer->UpdateTilePriorities();
if (layer->mask_layer())
- layer->mask_layer()->UpdateTilePriorities();
+ layer->mask_layer()->UpdateTiles();
if (layer->replica_layer() && layer->replica_layer()->mask_layer())
- layer->replica_layer()->mask_layer()->UpdateTilePriorities();
+ layer->replica_layer()->mask_layer()->UpdateTiles();
}
}
DCHECK(!needs_update_draw_properties_) <<
"CalcDrawProperties should not set_needs_update_draw_properties()";
+ return true;
}
const LayerImplList& LayerTreeImpl::RenderSurfaceLayerList() const {
@@ -437,9 +521,12 @@ const LayerImplList& LayerTreeImpl::RenderSurfaceLayerList() const {
}
gfx::Size LayerTreeImpl::ScrollableSize() const {
- if (!root_scroll_layer_ || root_scroll_layer_->children().empty())
+ LayerImpl* root_scroll_layer = OuterViewportScrollLayer()
+ ? OuterViewportScrollLayer()
+ : InnerViewportScrollLayer();
+ if (!root_scroll_layer || root_scroll_layer->children().empty())
return gfx::Size();
- return root_scroll_layer_->children()[0]->bounds();
+ return root_scroll_layer->children()[0]->bounds();
}
LayerImpl* LayerTreeImpl::LayerById(int id) {
@@ -473,8 +560,19 @@ void LayerTreeImpl::DidBecomeActive() {
if (!root_layer())
return;
+ if (next_activation_forces_redraw_) {
+ layer_tree_host_impl_->SetFullRootLayerDamage();
+ next_activation_forces_redraw_ = false;
+ }
+
+ if (scrolling_layer_id_from_previous_tree_) {
+ currently_scrolling_layer_ = LayerTreeHostCommon::FindLayerInSubtree(
+ root_layer_.get(), scrolling_layer_id_from_previous_tree_);
+ }
+
DidBecomeActiveRecursive(root_layer());
- FindRootScrollLayer();
+ devtools_instrumentation::DidActivateLayerTree(layer_tree_host_impl_->id(),
+ source_frame_number_);
}
bool LayerTreeImpl::ContentsTexturesPurged() const {
@@ -495,6 +593,18 @@ void LayerTreeImpl::ResetContentsTexturesPurged() {
layer_tree_host_impl_->OnCanDrawStateChangedForTree();
}
+void LayerTreeImpl::SetRequiresHighResToDraw() {
+ requires_high_res_to_draw_ = true;
+}
+
+void LayerTreeImpl::ResetRequiresHighResToDraw() {
+ requires_high_res_to_draw_ = false;
+}
+
+bool LayerTreeImpl::RequiresHighResToDraw() const {
+ return requires_high_res_to_draw_;
+}
+
bool LayerTreeImpl::ViewportSizeInvalid() const {
return viewport_size_invalid_;
}
@@ -517,7 +627,7 @@ const LayerTreeSettings& LayerTreeImpl::settings() const {
return layer_tree_host_impl_->settings();
}
-const RendererCapabilities& LayerTreeImpl::GetRendererCapabilities() const {
+const RendererCapabilitiesImpl& LayerTreeImpl::GetRendererCapabilities() const {
return layer_tree_host_impl_->GetRendererCapabilities();
}
@@ -553,6 +663,10 @@ bool LayerTreeImpl::device_viewport_valid_for_tile_management() const {
return layer_tree_host_impl_->device_viewport_valid_for_tile_management();
}
+gfx::Size LayerTreeImpl::device_viewport_size() const {
+ return layer_tree_host_impl_->device_viewport_size();
+}
+
bool LayerTreeImpl::IsActiveTree() const {
return layer_tree_host_impl_->active_tree() == this;
}
@@ -591,12 +705,8 @@ base::TimeTicks LayerTreeImpl::CurrentFrameTimeTicks() const {
return layer_tree_host_impl_->CurrentFrameTimeTicks();
}
-base::Time LayerTreeImpl::CurrentFrameTime() const {
- return layer_tree_host_impl_->CurrentFrameTime();
-}
-
-base::TimeTicks LayerTreeImpl::CurrentPhysicalTimeTicks() const {
- return layer_tree_host_impl_->CurrentPhysicalTimeTicks();
+base::TimeDelta LayerTreeImpl::begin_impl_frame_interval() const {
+ return layer_tree_host_impl_->begin_impl_frame_interval();
}
void LayerTreeImpl::SetNeedsCommit() {
@@ -607,14 +717,44 @@ gfx::Size LayerTreeImpl::DrawViewportSize() const {
return layer_tree_host_impl_->DrawViewportSize();
}
-void LayerTreeImpl::StartScrollbarAnimation() {
- layer_tree_host_impl_->StartScrollbarAnimation();
+scoped_ptr<ScrollbarAnimationController>
+LayerTreeImpl::CreateScrollbarAnimationController(LayerImpl* scrolling_layer) {
+ DCHECK(settings().scrollbar_fade_delay_ms);
+ DCHECK(settings().scrollbar_fade_duration_ms);
+ base::TimeDelta delay =
+ base::TimeDelta::FromMilliseconds(settings().scrollbar_fade_delay_ms);
+ base::TimeDelta duration =
+ base::TimeDelta::FromMilliseconds(settings().scrollbar_fade_duration_ms);
+ switch (settings().scrollbar_animator) {
+ case LayerTreeSettings::LinearFade: {
+ return ScrollbarAnimationControllerLinearFade::Create(
+ scrolling_layer, layer_tree_host_impl_, delay, duration)
+ .PassAs<ScrollbarAnimationController>();
+ }
+ case LayerTreeSettings::Thinning: {
+ return ScrollbarAnimationControllerThinning::Create(
+ scrolling_layer, layer_tree_host_impl_, delay, duration)
+ .PassAs<ScrollbarAnimationController>();
+ }
+ case LayerTreeSettings::NoAnimator:
+ NOTREACHED();
+ break;
+ }
+ return scoped_ptr<ScrollbarAnimationController>();
}
void LayerTreeImpl::DidAnimateScrollOffset() {
layer_tree_host_impl_->DidAnimateScrollOffset();
}
+bool LayerTreeImpl::use_gpu_rasterization() const {
+ return layer_tree_host_impl_->use_gpu_rasterization();
+}
+
+bool LayerTreeImpl::create_low_res_tiling() const {
+ return layer_tree_host_impl_->create_low_res_tiling();
+}
+
void LayerTreeImpl::SetNeedsRedraw() {
layer_tree_host_impl_->SetNeedsRedraw();
}
@@ -643,10 +783,7 @@ scoped_ptr<base::Value> LayerTreeImpl::AsValue() const {
state->Set("root_layer", root_layer_->AsValue().release());
scoped_ptr<base::ListValue> render_surface_layer_list(new base::ListValue());
- typedef LayerIterator<LayerImpl,
- LayerImplList,
- RenderSurfaceImpl,
- LayerIteratorActions::FrontToBack> LayerIteratorType;
+ typedef LayerIterator<LayerImpl> LayerIteratorType;
LayerIteratorType end = LayerIteratorType::End(&render_surface_layer_list_);
for (LayerIteratorType it = LayerIteratorType::Begin(
&render_surface_layer_list_); it != end; ++it) {
@@ -665,37 +802,105 @@ void LayerTreeImpl::SetRootLayerScrollOffsetDelegate(
if (root_layer_scroll_offset_delegate_ == root_layer_scroll_offset_delegate)
return;
- root_layer_scroll_offset_delegate_ = root_layer_scroll_offset_delegate;
-
- if (root_scroll_layer_) {
- root_scroll_layer_->SetScrollOffsetDelegate(
- root_layer_scroll_offset_delegate_);
+ if (!root_layer_scroll_offset_delegate) {
+ // Make sure we remove the proxies from their layers before
+ // releasing them.
+ if (InnerViewportScrollLayer())
+ InnerViewportScrollLayer()->SetScrollOffsetDelegate(NULL);
+ if (OuterViewportScrollLayer())
+ OuterViewportScrollLayer()->SetScrollOffsetDelegate(NULL);
+ inner_viewport_scroll_delegate_proxy_.reset();
+ outer_viewport_scroll_delegate_proxy_.reset();
}
+ root_layer_scroll_offset_delegate_ = root_layer_scroll_offset_delegate;
+
if (root_layer_scroll_offset_delegate_) {
- root_layer_scroll_offset_delegate_->SetScrollableSize(ScrollableSize());
- root_layer_scroll_offset_delegate_->SetTotalPageScaleFactor(
- total_page_scale_factor());
+ root_layer_scroll_offset_delegate_->UpdateRootLayerState(
+ TotalScrollOffset(),
+ TotalMaxScrollOffset(),
+ ScrollableSize(),
+ total_page_scale_factor(),
+ min_page_scale_factor(),
+ max_page_scale_factor());
+
+ if (inner_viewport_scroll_layer_) {
+ inner_viewport_scroll_delegate_proxy_ = make_scoped_ptr(
+ new LayerScrollOffsetDelegateProxy(InnerViewportScrollLayer(),
+ root_layer_scroll_offset_delegate_,
+ this));
+ inner_viewport_scroll_layer_->SetScrollOffsetDelegate(
+ inner_viewport_scroll_delegate_proxy_.get());
+ }
+
+ if (outer_viewport_scroll_layer_) {
+ outer_viewport_scroll_delegate_proxy_ = make_scoped_ptr(
+ new LayerScrollOffsetDelegateProxy(OuterViewportScrollLayer(),
+ root_layer_scroll_offset_delegate_,
+ this));
+ outer_viewport_scroll_layer_->SetScrollOffsetDelegate(
+ outer_viewport_scroll_delegate_proxy_.get());
+ }
}
}
-void LayerTreeImpl::UpdateRootScrollLayerSizeDelta() {
- LayerImpl* root_scroll = RootScrollLayer();
- LayerImpl* root_container = RootContainerLayer();
- DCHECK(root_scroll);
- DCHECK(root_container);
- DCHECK(IsActiveTree());
+void LayerTreeImpl::UpdateScrollOffsetDelegate() {
+ DCHECK(InnerViewportScrollLayer());
+ DCHECK(root_layer_scroll_offset_delegate_);
+
+ gfx::Vector2dF offset =
+ inner_viewport_scroll_delegate_proxy_->last_set_scroll_offset();
+
+ if (OuterViewportScrollLayer())
+ offset += outer_viewport_scroll_delegate_proxy_->last_set_scroll_offset();
+
+ root_layer_scroll_offset_delegate_->UpdateRootLayerState(
+ offset,
+ TotalMaxScrollOffset(),
+ ScrollableSize(),
+ total_page_scale_factor(),
+ min_page_scale_factor(),
+ max_page_scale_factor());
+}
+
+gfx::Vector2dF LayerTreeImpl::GetDelegatedScrollOffset(LayerImpl* layer) {
+ DCHECK(root_layer_scroll_offset_delegate_);
+ DCHECK(InnerViewportScrollLayer());
+ if (layer == InnerViewportScrollLayer() && !OuterViewportScrollLayer())
+ return root_layer_scroll_offset_delegate_->GetTotalScrollOffset();
+
+ // If we get here, we have both inner/outer viewports, and need to distribute
+ // the scroll offset between them.
+ DCHECK(inner_viewport_scroll_delegate_proxy_);
+ DCHECK(outer_viewport_scroll_delegate_proxy_);
+ gfx::Vector2dF inner_viewport_offset =
+ inner_viewport_scroll_delegate_proxy_->last_set_scroll_offset();
+ gfx::Vector2dF outer_viewport_offset =
+ outer_viewport_scroll_delegate_proxy_->last_set_scroll_offset();
+
+ // It may be nothing has changed.
+ gfx::Vector2dF delegate_offset =
+ root_layer_scroll_offset_delegate_->GetTotalScrollOffset();
+ if (inner_viewport_offset + outer_viewport_offset == delegate_offset) {
+ if (layer == InnerViewportScrollLayer())
+ return inner_viewport_offset;
+ else
+ return outer_viewport_offset;
+ }
+
+ gfx::Vector2d max_outer_viewport_scroll_offset =
+ OuterViewportScrollLayer()->MaxScrollOffset();
- gfx::Vector2dF scrollable_viewport_size =
- gfx::RectF(ScrollableViewportSize()).bottom_right() - gfx::PointF();
+ outer_viewport_offset = delegate_offset - inner_viewport_offset;
+ outer_viewport_offset.SetToMin(max_outer_viewport_scroll_offset);
+ outer_viewport_offset.SetToMax(gfx::Vector2d());
- gfx::Vector2dF original_viewport_size =
- gfx::RectF(root_container->bounds()).bottom_right() -
- gfx::PointF();
- original_viewport_size.Scale(1 / page_scale_factor());
+ if (layer == OuterViewportScrollLayer())
+ return outer_viewport_offset;
- root_scroll->SetFixedContainerSizeDelta(
- scrollable_viewport_size - original_viewport_size);
+ inner_viewport_offset = delegate_offset - outer_viewport_offset;
+
+ return inner_viewport_offset;
}
void LayerTreeImpl::QueueSwapPromise(scoped_ptr<SwapPromise> swap_promise) {
@@ -771,9 +976,14 @@ void LayerTreeImpl::AddLayerWithCopyOutputRequest(LayerImpl* layer) {
// they are aborted if not serviced during draw.
DCHECK(IsActiveTree());
- DCHECK(std::find(layers_with_copy_output_request_.begin(),
- layers_with_copy_output_request_.end(),
- layer) == layers_with_copy_output_request_.end());
+ // DCHECK(std::find(layers_with_copy_output_request_.begin(),
+ // layers_with_copy_output_request_.end(),
+ // layer) == layers_with_copy_output_request_.end());
+ // TODO(danakj): Remove this once crash is found crbug.com/309777
+ for (size_t i = 0; i < layers_with_copy_output_request_.size(); ++i) {
+ CHECK(layers_with_copy_output_request_[i] != layer)
+ << i << " of " << layers_with_copy_output_request_.size();
+ }
layers_with_copy_output_request_.push_back(layer);
}
@@ -788,6 +998,12 @@ void LayerTreeImpl::RemoveLayerWithCopyOutputRequest(LayerImpl* layer) {
layer);
DCHECK(it != layers_with_copy_output_request_.end());
layers_with_copy_output_request_.erase(it);
+
+ // TODO(danakj): Remove this once crash is found crbug.com/309777
+ for (size_t i = 0; i < layers_with_copy_output_request_.size(); ++i) {
+ CHECK(layers_with_copy_output_request_[i] != layer)
+ << i << " of " << layers_with_copy_output_request_.size();
+ }
}
const std::vector<LayerImpl*>& LayerTreeImpl::LayersWithCopyOutputRequest()
@@ -799,4 +1015,287 @@ const std::vector<LayerImpl*>& LayerTreeImpl::LayersWithCopyOutputRequest()
return layers_with_copy_output_request_;
}
+void LayerTreeImpl::ReleaseResourcesRecursive(LayerImpl* current) {
+ DCHECK(current);
+ current->ReleaseResources();
+ if (current->mask_layer())
+ ReleaseResourcesRecursive(current->mask_layer());
+ if (current->replica_layer())
+ ReleaseResourcesRecursive(current->replica_layer());
+ for (size_t i = 0; i < current->children().size(); ++i)
+ ReleaseResourcesRecursive(current->children()[i]);
+}
+
+template <typename LayerType>
+static inline bool LayerClipsSubtree(LayerType* layer) {
+ return layer->masks_to_bounds() || layer->mask_layer();
+}
+
+static bool PointHitsRect(
+ const gfx::PointF& screen_space_point,
+ const gfx::Transform& local_space_to_screen_space_transform,
+ const gfx::RectF& local_space_rect,
+ float* distance_to_camera) {
+ // If the transform is not invertible, then assume that this point doesn't hit
+ // this rect.
+ gfx::Transform inverse_local_space_to_screen_space(
+ gfx::Transform::kSkipInitialization);
+ if (!local_space_to_screen_space_transform.GetInverse(
+ &inverse_local_space_to_screen_space))
+ return false;
+
+ // Transform the hit test point from screen space to the local space of the
+ // given rect.
+ bool clipped = false;
+ gfx::Point3F planar_point = MathUtil::ProjectPoint3D(
+ inverse_local_space_to_screen_space, screen_space_point, &clipped);
+ gfx::PointF hit_test_point_in_local_space =
+ gfx::PointF(planar_point.x(), planar_point.y());
+
+ // If ProjectPoint could not project to a valid value, then we assume that
+ // this point doesn't hit this rect.
+ if (clipped)
+ return false;
+
+ if (!local_space_rect.Contains(hit_test_point_in_local_space))
+ return false;
+
+ if (distance_to_camera) {
+ // To compute the distance to the camera, we have to take the planar point
+ // and pull it back to world space and compute the displacement along the
+ // z-axis.
+ gfx::Point3F planar_point_in_screen_space(planar_point);
+ local_space_to_screen_space_transform.TransformPoint(
+ &planar_point_in_screen_space);
+ *distance_to_camera = planar_point_in_screen_space.z();
+ }
+
+ return true;
+}
+
+static bool PointHitsRegion(const gfx::PointF& screen_space_point,
+ const gfx::Transform& screen_space_transform,
+ const Region& layer_space_region,
+ float layer_content_scale_x,
+ float layer_content_scale_y) {
+ // If the transform is not invertible, then assume that this point doesn't hit
+ // this region.
+ gfx::Transform inverse_screen_space_transform(
+ gfx::Transform::kSkipInitialization);
+ if (!screen_space_transform.GetInverse(&inverse_screen_space_transform))
+ return false;
+
+ // Transform the hit test point from screen space to the local space of the
+ // given region.
+ bool clipped = false;
+ gfx::PointF hit_test_point_in_content_space = MathUtil::ProjectPoint(
+ inverse_screen_space_transform, screen_space_point, &clipped);
+ gfx::PointF hit_test_point_in_layer_space =
+ gfx::ScalePoint(hit_test_point_in_content_space,
+ 1.f / layer_content_scale_x,
+ 1.f / layer_content_scale_y);
+
+ // If ProjectPoint could not project to a valid value, then we assume that
+ // this point doesn't hit this region.
+ if (clipped)
+ return false;
+
+ return layer_space_region.Contains(
+ gfx::ToRoundedPoint(hit_test_point_in_layer_space));
+}
+
+static LayerImpl* GetNextClippingLayer(LayerImpl* layer) {
+ if (layer->scroll_parent())
+ return layer->scroll_parent();
+ if (layer->clip_parent())
+ return layer->clip_parent();
+ return layer->parent();
+}
+
+static bool PointIsClippedBySurfaceOrClipRect(
+ const gfx::PointF& screen_space_point,
+ LayerImpl* layer) {
+ // Walk up the layer tree and hit-test any render_surfaces and any layer
+ // clip rects that are active.
+ for (; layer; layer = GetNextClippingLayer(layer)) {
+ if (layer->render_surface() &&
+ !PointHitsRect(screen_space_point,
+ layer->render_surface()->screen_space_transform(),
+ layer->render_surface()->content_rect(),
+ NULL))
+ return true;
+
+ if (LayerClipsSubtree(layer) &&
+ !PointHitsRect(screen_space_point,
+ layer->screen_space_transform(),
+ gfx::Rect(layer->content_bounds()),
+ NULL))
+ return true;
+ }
+
+ // If we have finished walking all ancestors without having already exited,
+ // then the point is not clipped by any ancestors.
+ return false;
+}
+
+static bool PointHitsLayer(LayerImpl* layer,
+ const gfx::PointF& screen_space_point,
+ float* distance_to_intersection) {
+ gfx::RectF content_rect(layer->content_bounds());
+ if (!PointHitsRect(screen_space_point,
+ layer->screen_space_transform(),
+ content_rect,
+ distance_to_intersection))
+ return false;
+
+ // At this point, we think the point does hit the layer, but we need to walk
+ // up the parents to ensure that the layer was not clipped in such a way
+ // that the hit point actually should not hit the layer.
+ if (PointIsClippedBySurfaceOrClipRect(screen_space_point, layer))
+ return false;
+
+ // Skip the HUD layer.
+ if (layer == layer->layer_tree_impl()->hud_layer())
+ return false;
+
+ return true;
+}
+
+struct FindClosestMatchingLayerDataForRecursion {
+ FindClosestMatchingLayerDataForRecursion()
+ : closest_match(NULL),
+ closest_distance(-std::numeric_limits<float>::infinity()) {}
+ LayerImpl* closest_match;
+ // Note that the positive z-axis points towards the camera, so bigger means
+ // closer in this case, counterintuitively.
+ float closest_distance;
+};
+
+template <typename Functor>
+static void FindClosestMatchingLayer(
+ const gfx::PointF& screen_space_point,
+ LayerImpl* layer,
+ const Functor& func,
+ FindClosestMatchingLayerDataForRecursion* data_for_recursion) {
+ for (int i = layer->children().size() - 1; i >= 0; --i) {
+ FindClosestMatchingLayer(
+ screen_space_point, layer->children()[i], func, data_for_recursion);
+ }
+
+ float distance_to_intersection = 0.f;
+ if (func(layer) &&
+ PointHitsLayer(layer, screen_space_point, &distance_to_intersection) &&
+ ((!data_for_recursion->closest_match ||
+ distance_to_intersection > data_for_recursion->closest_distance))) {
+ data_for_recursion->closest_distance = distance_to_intersection;
+ data_for_recursion->closest_match = layer;
+ }
+}
+
+static bool ScrollsAnyDrawnRenderSurfaceLayerListMember(LayerImpl* layer) {
+ if (!layer->scrollable())
+ return false;
+ if (layer->IsDrawnRenderSurfaceLayerListMember())
+ return true;
+ if (!layer->scroll_children())
+ return false;
+ for (std::set<LayerImpl*>::const_iterator it =
+ layer->scroll_children()->begin();
+ it != layer->scroll_children()->end();
+ ++it) {
+ if ((*it)->IsDrawnRenderSurfaceLayerListMember())
+ return true;
+ }
+ return false;
+}
+
+struct FindScrollingLayerFunctor {
+ bool operator()(LayerImpl* layer) const {
+ return ScrollsAnyDrawnRenderSurfaceLayerListMember(layer);
+ }
+};
+
+LayerImpl* LayerTreeImpl::FindFirstScrollingLayerThatIsHitByPoint(
+ const gfx::PointF& screen_space_point) {
+ FindClosestMatchingLayerDataForRecursion data_for_recursion;
+ FindClosestMatchingLayer(screen_space_point,
+ root_layer(),
+ FindScrollingLayerFunctor(),
+ &data_for_recursion);
+ return data_for_recursion.closest_match;
+}
+
+struct HitTestVisibleScrollableOrTouchableFunctor {
+ bool operator()(LayerImpl* layer) const {
+ return layer->IsDrawnRenderSurfaceLayerListMember() ||
+ ScrollsAnyDrawnRenderSurfaceLayerListMember(layer) ||
+ !layer->touch_event_handler_region().IsEmpty() ||
+ layer->have_wheel_event_handlers();
+ }
+};
+
+LayerImpl* LayerTreeImpl::FindLayerThatIsHitByPoint(
+ const gfx::PointF& screen_space_point) {
+ if (!root_layer())
+ return NULL;
+ if (!UpdateDrawProperties())
+ return NULL;
+ FindClosestMatchingLayerDataForRecursion data_for_recursion;
+ FindClosestMatchingLayer(screen_space_point,
+ root_layer(),
+ HitTestVisibleScrollableOrTouchableFunctor(),
+ &data_for_recursion);
+ return data_for_recursion.closest_match;
+}
+
+static bool LayerHasTouchEventHandlersAt(const gfx::PointF& screen_space_point,
+ LayerImpl* layer_impl) {
+ if (layer_impl->touch_event_handler_region().IsEmpty())
+ return false;
+
+ if (!PointHitsRegion(screen_space_point,
+ layer_impl->screen_space_transform(),
+ layer_impl->touch_event_handler_region(),
+ layer_impl->contents_scale_x(),
+ layer_impl->contents_scale_y()))
+ return false;
+
+ // At this point, we think the point does hit the touch event handler region
+ // on the layer, but we need to walk up the parents to ensure that the layer
+ // was not clipped in such a way that the hit point actually should not hit
+ // the layer.
+ if (PointIsClippedBySurfaceOrClipRect(screen_space_point, layer_impl))
+ return false;
+
+ return true;
+}
+
+struct FindTouchEventLayerFunctor {
+ bool operator()(LayerImpl* layer) const {
+ return LayerHasTouchEventHandlersAt(screen_space_point, layer);
+ }
+ const gfx::PointF screen_space_point;
+};
+
+LayerImpl* LayerTreeImpl::FindLayerThatIsHitByPointInTouchHandlerRegion(
+ const gfx::PointF& screen_space_point) {
+ if (!root_layer())
+ return NULL;
+ if (!UpdateDrawProperties())
+ return NULL;
+ FindTouchEventLayerFunctor func = {screen_space_point};
+ FindClosestMatchingLayerDataForRecursion data_for_recursion;
+ FindClosestMatchingLayer(
+ screen_space_point, root_layer(), func, &data_for_recursion);
+ return data_for_recursion.closest_match;
+}
+
+void LayerTreeImpl::RegisterPictureLayerImpl(PictureLayerImpl* layer) {
+ layer_tree_host_impl_->RegisterPictureLayerImpl(layer);
+}
+
+void LayerTreeImpl::UnregisterPictureLayerImpl(PictureLayerImpl* layer) {
+ layer_tree_host_impl_->UnregisterPictureLayerImpl(layer);
+}
+
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_impl.h b/chromium/cc/trees/layer_tree_impl.h
index 2f27460fe04..3b3c6cf5623 100644
--- a/chromium/cc/trees/layer_tree_impl.h
+++ b/chromium/cc/trees/layer_tree_impl.h
@@ -14,6 +14,7 @@
#include "cc/base/scoped_ptr_vector.h"
#include "cc/base/swap_promise.h"
#include "cc/layers/layer_impl.h"
+#include "cc/output/renderer.h"
#include "cc/resources/ui_resource_client.h"
#if defined(COMPILER_GCC)
@@ -33,6 +34,7 @@ class ContextProvider;
class DebugRectHistory;
class FrameRateCounter;
class HeadsUpDisplayLayerImpl;
+class LayerScrollOffsetDelegateProxy;
class LayerTreeDebugState;
class LayerTreeHostImpl;
class LayerTreeImpl;
@@ -40,6 +42,7 @@ class LayerTreeSettings;
class MemoryHistory;
class OutputSurface;
class PaintTimeCounter;
+class PictureLayerImpl;
class Proxy;
class ResourceProvider;
class TileManager;
@@ -56,10 +59,13 @@ class CC_EXPORT LayerTreeImpl {
}
virtual ~LayerTreeImpl();
+ void Shutdown();
+ void ReleaseResources();
+
// Methods called by the layer tree that pass-through or access LTHI.
// ---------------------------------------------------------------------------
const LayerTreeSettings& settings() const;
- const RendererCapabilities& GetRendererCapabilities() const;
+ const RendererCapabilitiesImpl& GetRendererCapabilities() const;
ContextProvider* context_provider() const;
OutputSurface* output_surface() const;
ResourceProvider* resource_provider() const;
@@ -68,6 +74,7 @@ class CC_EXPORT LayerTreeImpl {
PaintTimeCounter* paint_time_counter() const;
MemoryHistory* memory_history() const;
bool device_viewport_valid_for_tile_management() const;
+ gfx::Size device_viewport_size() const;
bool IsActiveTree() const;
bool IsPendingTree() const;
bool IsRecycleTree() const;
@@ -76,12 +83,14 @@ class CC_EXPORT LayerTreeImpl {
int MaxTextureSize() const;
bool PinchGestureActive() const;
base::TimeTicks CurrentFrameTimeTicks() const;
- base::Time CurrentFrameTime() const;
- base::TimeTicks CurrentPhysicalTimeTicks() const;
+ base::TimeDelta begin_impl_frame_interval() const;
void SetNeedsCommit();
gfx::Size DrawViewportSize() const;
- void StartScrollbarAnimation();
+ scoped_ptr<ScrollbarAnimationController> CreateScrollbarAnimationController(
+ LayerImpl* scrolling_layer);
void DidAnimateScrollOffset();
+ bool use_gpu_rasterization() const;
+ bool create_low_res_tiling() const;
// Tree specific methods exposed to layer-impl tree.
// ---------------------------------------------------------------------------
@@ -112,18 +121,24 @@ class CC_EXPORT LayerTreeImpl {
hud_layer_ = layer_impl;
}
- LayerImpl* RootScrollLayer() const;
- LayerImpl* RootContainerLayer() const;
+ LayerImpl* InnerViewportScrollLayer() const;
+ // This function may return NULL, it is the caller's responsibility to check.
+ LayerImpl* OuterViewportScrollLayer() const;
+ gfx::Vector2dF TotalScrollOffset() const;
+ gfx::Vector2dF TotalMaxScrollOffset() const;
+ gfx::Vector2dF TotalScrollDelta() const;
+
+ LayerImpl* InnerViewportContainerLayer() const;
LayerImpl* CurrentlyScrollingLayer() const;
void SetCurrentlyScrollingLayer(LayerImpl* layer);
void ClearCurrentlyScrollingLayer();
+ float VerticalAdjust(const int clip_layer_id) const;
- void FindRootScrollLayer();
- void UpdateMaxScrollOffset();
void SetViewportLayersFromIds(int page_scale_layer_id,
int inner_viewport_scroll_layer_id,
int outer_viewport_scroll_layer_id);
void ClearViewportLayers();
+ LayerImpl* page_scale_layer() { return page_scale_layer_; }
void ApplySentScrollAndScaleDeltasFromAbortedCommit();
void ApplyScrollDeltasSinceBeginMainFrame();
@@ -140,6 +155,9 @@ class CC_EXPORT LayerTreeImpl {
void SetPageScaleFactorAndLimits(float page_scale_factor,
float min_page_scale_factor, float max_page_scale_factor);
void SetPageScaleDelta(float delta);
+ void SetPageScaleValues(float page_scale_factor,
+ float min_page_scale_factor, float max_page_scale_factor,
+ float page_scale_delta);
float total_page_scale_factor() const {
return page_scale_factor_ * page_scale_delta_;
}
@@ -153,8 +171,8 @@ class CC_EXPORT LayerTreeImpl {
float sent_page_scale_delta() const { return sent_page_scale_delta_; }
// Updates draw properties and render surface layer list, as well as tile
- // priorities.
- void UpdateDrawProperties();
+ // priorities. Returns false if it was unable to update.
+ bool UpdateDrawProperties();
void set_needs_update_draw_properties() {
needs_update_draw_properties_ = true;
@@ -195,6 +213,10 @@ class CC_EXPORT LayerTreeImpl {
void SetContentsTexturesPurged();
void ResetContentsTexturesPurged();
+ void SetRequiresHighResToDraw();
+ void ResetRequiresHighResToDraw();
+ bool RequiresHighResToDraw() const;
+
// Set on the active tree when the viewport size recently changed
// and the active tree's size is now out of date.
bool ViewportSizeInvalid() const;
@@ -206,6 +228,8 @@ class CC_EXPORT LayerTreeImpl {
void SetRootLayerScrollOffsetDelegate(
LayerScrollOffsetDelegate* root_layer_scroll_offset_delegate);
+ void UpdateScrollOffsetDelegate();
+ gfx::Vector2dF GetDelegatedScrollOffset(LayerImpl* layer);
// Call this function when you expect there to be a swap buffer.
// See swap_promise.h for how to use SwapPromise.
@@ -227,20 +251,35 @@ class CC_EXPORT LayerTreeImpl {
void RemoveLayerWithCopyOutputRequest(LayerImpl* layer);
const std::vector<LayerImpl*>& LayersWithCopyOutputRequest() const;
- protected:
- explicit LayerTreeImpl(LayerTreeHostImpl* layer_tree_host_impl);
+ int current_render_surface_list_id() const {
+ return render_surface_layer_list_id_;
+ }
- void UpdateSolidColorScrollbars();
+ LayerImpl* FindFirstScrollingLayerThatIsHitByPoint(
+ const gfx::PointF& screen_space_point);
- void UpdateRootScrollLayerSizeDelta();
+ LayerImpl* FindLayerThatIsHitByPoint(const gfx::PointF& screen_space_point);
+
+ LayerImpl* FindLayerThatIsHitByPointInTouchHandlerRegion(
+ const gfx::PointF& screen_space_point);
+
+ void RegisterPictureLayerImpl(PictureLayerImpl* layer);
+ void UnregisterPictureLayerImpl(PictureLayerImpl* layer);
+
+ protected:
+ explicit LayerTreeImpl(LayerTreeHostImpl* layer_tree_host_impl);
+ void ReleaseResourcesRecursive(LayerImpl* current);
LayerTreeHostImpl* layer_tree_host_impl_;
int source_frame_number_;
scoped_ptr<LayerImpl> root_layer_;
HeadsUpDisplayLayerImpl* hud_layer_;
- LayerImpl* root_scroll_layer_;
LayerImpl* currently_scrolling_layer_;
LayerScrollOffsetDelegate* root_layer_scroll_offset_delegate_;
+ scoped_ptr<LayerScrollOffsetDelegateProxy>
+ inner_viewport_scroll_delegate_proxy_;
+ scoped_ptr<LayerScrollOffsetDelegateProxy>
+ outer_viewport_scroll_delegate_proxy_;
SkColor background_color_;
bool has_transparent_background_;
@@ -262,11 +301,11 @@ class CC_EXPORT LayerTreeImpl {
// Persisted state for non-impl-side-painting.
int scrolling_layer_id_from_previous_tree_;
- // List of visible or hit-testable layers for the most recently prepared
- // frame. Used for rendering and input event hit testing.
+ // List of visible layers for the most recently prepared frame.
LayerImplList render_surface_layer_list_;
bool contents_textures_purged_;
+ bool requires_high_res_to_draw_;
bool viewport_size_invalid_;
bool needs_update_draw_properties_;
@@ -280,6 +319,8 @@ class CC_EXPORT LayerTreeImpl {
UIResourceRequestQueue ui_resource_request_queue_;
+ int render_surface_layer_list_id_;
+
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
new file mode 100644
index 00000000000..006fc35997a
--- /dev/null
+++ b/chromium/cc/trees/layer_tree_impl_unittest.cc
@@ -0,0 +1,2074 @@
+// 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/trees/layer_tree_impl.h"
+
+#include "cc/layers/heads_up_display_layer_impl.h"
+#include "cc/layers/layer.h"
+#include "cc/test/fake_impl_proxy.h"
+#include "cc/test/fake_layer_tree_host_impl.h"
+#include "cc/test/fake_output_surface.h"
+#include "cc/test/geometry_test_utils.h"
+#include "cc/test/layer_tree_host_common_test.h"
+#include "cc/test/test_shared_bitmap_manager.h"
+#include "cc/trees/layer_tree_host_impl.h"
+#include "ui/gfx/size_conversions.h"
+
+namespace cc {
+namespace {
+
+class LayerTreeImplTest : public LayerTreeHostCommonTest {
+ public:
+ LayerTreeImplTest() {
+ LayerTreeSettings settings;
+ settings.layer_transforms_should_scale_layer_contents = true;
+ host_impl_.reset(
+ new FakeLayerTreeHostImpl(settings, &proxy_, &shared_bitmap_manager_));
+ EXPECT_TRUE(host_impl_->InitializeRenderer(
+ FakeOutputSurface::Create3d().PassAs<OutputSurface>()));
+ }
+
+ FakeLayerTreeHostImpl& host_impl() { return *host_impl_; }
+
+ LayerImpl* root_layer() { return host_impl_->active_tree()->root_layer(); }
+
+ const LayerImplList& RenderSurfaceLayerList() const {
+ return host_impl_->active_tree()->RenderSurfaceLayerList();
+ }
+
+ private:
+ TestSharedBitmapManager shared_bitmap_manager_;
+ FakeImplProxy proxy_;
+ scoped_ptr<FakeLayerTreeHostImpl> host_impl_;
+};
+
+TEST_F(LayerTreeImplTest, HitTestingForSingleLayer) {
+ scoped_ptr<LayerImpl> root =
+ LayerImpl::Create(host_impl().active_tree(), 12345);
+
+ gfx::Transform identity_matrix;
+ gfx::Point3F transform_origin;
+ gfx::PointF position;
+ gfx::Size bounds(100, 100);
+ SetLayerPropertiesForTesting(root.get(),
+ identity_matrix,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+ root->SetDrawsContent(true);
+
+ host_impl().SetViewportSize(root->bounds());
+ host_impl().active_tree()->SetRootLayer(root.Pass());
+ host_impl().active_tree()->UpdateDrawProperties();
+
+ // Sanity check the scenario we just created.
+ ASSERT_EQ(1u, RenderSurfaceLayerList().size());
+ ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
+
+ // Hit testing for a point outside the layer should return a null pointer.
+ gfx::Point test_point(101, 101);
+ LayerImpl* result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ EXPECT_FALSE(result_layer);
+
+ test_point = gfx::Point(-1, -1);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ EXPECT_FALSE(result_layer);
+
+ // Hit testing for a point inside should return the root layer.
+ test_point = gfx::Point(1, 1);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(12345, result_layer->id());
+
+ test_point = gfx::Point(99, 99);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(12345, result_layer->id());
+}
+
+TEST_F(LayerTreeImplTest, HitTestingForSingleLayerAndHud) {
+ scoped_ptr<LayerImpl> root =
+ LayerImpl::Create(host_impl().active_tree(), 12345);
+ scoped_ptr<HeadsUpDisplayLayerImpl> hud =
+ HeadsUpDisplayLayerImpl::Create(host_impl().active_tree(), 11111);
+
+ gfx::Transform identity_matrix;
+ gfx::Point3F transform_origin;
+ gfx::PointF position;
+ gfx::Size bounds(100, 100);
+ SetLayerPropertiesForTesting(root.get(),
+ identity_matrix,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+ root->SetDrawsContent(true);
+
+ // Create hud and add it as a child of root.
+ gfx::Size hud_bounds(200, 200);
+ SetLayerPropertiesForTesting(hud.get(),
+ identity_matrix,
+ transform_origin,
+ position,
+ hud_bounds,
+ true,
+ false);
+ hud->SetDrawsContent(true);
+
+ host_impl().active_tree()->set_hud_layer(hud.get());
+ root->AddChild(hud.PassAs<LayerImpl>());
+
+ host_impl().SetViewportSize(hud_bounds);
+ host_impl().active_tree()->SetRootLayer(root.Pass());
+ host_impl().active_tree()->UpdateDrawProperties();
+
+ // Sanity check the scenario we just created.
+ ASSERT_EQ(1u, RenderSurfaceLayerList().size());
+ ASSERT_EQ(2u, root_layer()->render_surface()->layer_list().size());
+
+ // Hit testing for a point inside HUD, but outside root should return null
+ gfx::Point test_point(101, 101);
+ LayerImpl* result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ EXPECT_FALSE(result_layer);
+
+ test_point = gfx::Point(-1, -1);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ EXPECT_FALSE(result_layer);
+
+ // Hit testing for a point inside should return the root layer, never the HUD
+ // layer.
+ test_point = gfx::Point(1, 1);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(12345, result_layer->id());
+
+ test_point = gfx::Point(99, 99);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(12345, result_layer->id());
+}
+
+TEST_F(LayerTreeImplTest, HitTestingForUninvertibleTransform) {
+ scoped_ptr<LayerImpl> root =
+ LayerImpl::Create(host_impl().active_tree(), 12345);
+
+ gfx::Transform uninvertible_transform;
+ uninvertible_transform.matrix().set(0, 0, 0.0);
+ uninvertible_transform.matrix().set(1, 1, 0.0);
+ uninvertible_transform.matrix().set(2, 2, 0.0);
+ uninvertible_transform.matrix().set(3, 3, 0.0);
+ ASSERT_FALSE(uninvertible_transform.IsInvertible());
+
+ gfx::Transform identity_matrix;
+ gfx::Point3F transform_origin;
+ gfx::PointF position;
+ gfx::Size bounds(100, 100);
+ SetLayerPropertiesForTesting(root.get(),
+ uninvertible_transform,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+ root->SetDrawsContent(true);
+
+ host_impl().SetViewportSize(root->bounds());
+ host_impl().active_tree()->SetRootLayer(root.Pass());
+ host_impl().active_tree()->UpdateDrawProperties();
+ // Sanity check the scenario we just created.
+ ASSERT_EQ(1u, RenderSurfaceLayerList().size());
+ ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
+ ASSERT_FALSE(root_layer()->screen_space_transform().IsInvertible());
+
+ // Hit testing any point should not hit the layer. If the invertible matrix is
+ // accidentally ignored and treated like an identity, then the hit testing
+ // will incorrectly hit the layer when it shouldn't.
+ gfx::Point test_point(1, 1);
+ LayerImpl* result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ EXPECT_FALSE(result_layer);
+
+ test_point = gfx::Point(10, 10);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ EXPECT_FALSE(result_layer);
+
+ test_point = gfx::Point(10, 30);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ EXPECT_FALSE(result_layer);
+
+ test_point = gfx::Point(50, 50);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ EXPECT_FALSE(result_layer);
+
+ test_point = gfx::Point(67, 48);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ EXPECT_FALSE(result_layer);
+
+ test_point = gfx::Point(99, 99);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ EXPECT_FALSE(result_layer);
+
+ test_point = gfx::Point(-1, -1);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ EXPECT_FALSE(result_layer);
+}
+
+TEST_F(LayerTreeImplTest, HitTestingForSinglePositionedLayer) {
+ scoped_ptr<LayerImpl> root =
+ LayerImpl::Create(host_impl().active_tree(), 12345);
+
+ gfx::Transform identity_matrix;
+ gfx::Point3F transform_origin;
+ // this layer is positioned, and hit testing should correctly know where the
+ // layer is located.
+ gfx::PointF position(50.f, 50.f);
+ gfx::Size bounds(100, 100);
+ SetLayerPropertiesForTesting(root.get(),
+ identity_matrix,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+ root->SetDrawsContent(true);
+
+ host_impl().SetViewportSize(root->bounds());
+ host_impl().active_tree()->SetRootLayer(root.Pass());
+ host_impl().active_tree()->UpdateDrawProperties();
+
+ // Sanity check the scenario we just created.
+ ASSERT_EQ(1u, RenderSurfaceLayerList().size());
+ ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
+
+ // Hit testing for a point outside the layer should return a null pointer.
+ gfx::Point test_point(49, 49);
+ LayerImpl* result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ EXPECT_FALSE(result_layer);
+
+ // Even though the layer exists at (101, 101), it should not be visible there
+ // since the root render surface would clamp it.
+ test_point = gfx::Point(101, 101);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ EXPECT_FALSE(result_layer);
+
+ // Hit testing for a point inside should return the root layer.
+ test_point = gfx::Point(51, 51);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(12345, result_layer->id());
+
+ test_point = gfx::Point(99, 99);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(12345, result_layer->id());
+}
+
+TEST_F(LayerTreeImplTest, HitTestingForSingleRotatedLayer) {
+ scoped_ptr<LayerImpl> root =
+ LayerImpl::Create(host_impl().active_tree(), 12345);
+
+ gfx::Transform identity_matrix;
+ gfx::Transform rotation45_degrees_about_center;
+ rotation45_degrees_about_center.Translate(50.0, 50.0);
+ rotation45_degrees_about_center.RotateAboutZAxis(45.0);
+ rotation45_degrees_about_center.Translate(-50.0, -50.0);
+ gfx::Point3F transform_origin;
+ gfx::PointF position;
+ gfx::Size bounds(100, 100);
+ SetLayerPropertiesForTesting(root.get(),
+ rotation45_degrees_about_center,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+ root->SetDrawsContent(true);
+
+ host_impl().SetViewportSize(root->bounds());
+ host_impl().active_tree()->SetRootLayer(root.Pass());
+ host_impl().active_tree()->UpdateDrawProperties();
+
+ // Sanity check the scenario we just created.
+ ASSERT_EQ(1u, RenderSurfaceLayerList().size());
+ ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
+
+ // Hit testing for points outside the layer.
+ // These corners would have been inside the un-transformed layer, but they
+ // should not hit the correctly transformed layer.
+ gfx::Point test_point(99, 99);
+ LayerImpl* result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ EXPECT_FALSE(result_layer);
+
+ test_point = gfx::Point(1, 1);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ EXPECT_FALSE(result_layer);
+
+ // Hit testing for a point inside should return the root layer.
+ test_point = gfx::Point(1, 50);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(12345, result_layer->id());
+
+ // Hit testing the corners that would overlap the unclipped layer, but are
+ // outside the clipped region.
+ test_point = gfx::Point(50, -1);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ ASSERT_FALSE(result_layer);
+
+ test_point = gfx::Point(-1, 50);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ ASSERT_FALSE(result_layer);
+}
+
+TEST_F(LayerTreeImplTest, HitTestingForSinglePerspectiveLayer) {
+ scoped_ptr<LayerImpl> root =
+ LayerImpl::Create(host_impl().active_tree(), 12345);
+
+ gfx::Transform identity_matrix;
+
+ // 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).
+ gfx::Transform perspective_projection_about_center;
+ perspective_projection_about_center.Translate(50.0, 50.0);
+ perspective_projection_about_center.ApplyPerspectiveDepth(1.0);
+ perspective_projection_about_center.Translate(-50.0, -50.0);
+ gfx::Transform translation_by_z;
+ translation_by_z.Translate3d(0.0, 0.0, -1.0);
+
+ gfx::Point3F transform_origin;
+ gfx::PointF position;
+ gfx::Size bounds(100, 100);
+ SetLayerPropertiesForTesting(
+ root.get(),
+ perspective_projection_about_center * translation_by_z,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+ root->SetDrawsContent(true);
+
+ host_impl().SetViewportSize(root->bounds());
+ host_impl().active_tree()->SetRootLayer(root.Pass());
+ host_impl().active_tree()->UpdateDrawProperties();
+
+ // Sanity check the scenario we just created.
+ ASSERT_EQ(1u, RenderSurfaceLayerList().size());
+ ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
+
+ // Hit testing for points outside the layer.
+ // These corners would have been inside the un-transformed layer, but they
+ // should not hit the correctly transformed layer.
+ gfx::Point test_point(24, 24);
+ LayerImpl* result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ EXPECT_FALSE(result_layer);
+
+ test_point = gfx::Point(76, 76);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ EXPECT_FALSE(result_layer);
+
+ // Hit testing for a point inside should return the root layer.
+ test_point = gfx::Point(26, 26);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(12345, result_layer->id());
+
+ test_point = gfx::Point(74, 74);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(12345, result_layer->id());
+}
+
+TEST_F(LayerTreeImplTest, HitTestingForSingleLayerWithScaledContents) {
+ // A layer's visible content rect is actually in the layer's content space.
+ // The screen space transform converts from the layer's origin space to screen
+ // space. This test makes sure that hit testing works correctly accounts for
+ // the contents scale. A contents scale that is not 1 effectively forces a
+ // non-identity transform between layer's content space and layer's origin
+ // space. The hit testing code must take this into account.
+ //
+ // To test this, the layer is positioned at (25, 25), and is size (50, 50). If
+ // contents scale is ignored, then hit testing will mis-interpret the visible
+ // content rect as being larger than the actual bounds of the layer.
+ //
+ scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl().active_tree(), 1);
+
+ gfx::Transform identity_matrix;
+ gfx::Point3F transform_origin;
+
+ SetLayerPropertiesForTesting(root.get(),
+ identity_matrix,
+ transform_origin,
+ gfx::PointF(),
+ gfx::Size(100, 100),
+ true,
+ false);
+ {
+ gfx::PointF position(25.f, 25.f);
+ gfx::Size bounds(50, 50);
+ scoped_ptr<LayerImpl> test_layer =
+ LayerImpl::Create(host_impl().active_tree(), 12345);
+ SetLayerPropertiesForTesting(test_layer.get(),
+ identity_matrix,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+
+ // override content bounds and contents scale
+ test_layer->SetContentBounds(gfx::Size(100, 100));
+ test_layer->SetContentsScale(2, 2);
+
+ test_layer->SetDrawsContent(true);
+ root->AddChild(test_layer.Pass());
+ }
+
+ host_impl().SetViewportSize(root->bounds());
+ host_impl().active_tree()->SetRootLayer(root.Pass());
+ host_impl().active_tree()->UpdateDrawProperties();
+
+ // Sanity check the scenario we just created.
+ // The visible content rect for test_layer is actually 100x100, even though
+ // its layout size is 50x50, positioned at 25x25.
+ LayerImpl* test_layer =
+ host_impl().active_tree()->root_layer()->children()[0];
+ EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100), test_layer->visible_content_rect());
+ ASSERT_EQ(1u, RenderSurfaceLayerList().size());
+ ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
+
+ // Hit testing for a point outside the layer should return a null pointer (the
+ // root layer does not draw content, so it will not be hit tested either).
+ gfx::Point test_point(101, 101);
+ LayerImpl* result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ EXPECT_FALSE(result_layer);
+
+ test_point = gfx::Point(24, 24);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ EXPECT_FALSE(result_layer);
+
+ test_point = gfx::Point(76, 76);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ EXPECT_FALSE(result_layer);
+
+ // Hit testing for a point inside should return the test layer.
+ test_point = gfx::Point(26, 26);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(12345, result_layer->id());
+
+ test_point = gfx::Point(74, 74);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(12345, result_layer->id());
+}
+
+TEST_F(LayerTreeImplTest, HitTestingForSimpleClippedLayer) {
+ // Test that hit-testing will only work for the visible portion of a layer,
+ // and not the entire layer bounds. Here we just test the simple axis-aligned
+ // case.
+ gfx::Transform identity_matrix;
+ gfx::Point3F transform_origin;
+
+ scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl().active_tree(), 1);
+ SetLayerPropertiesForTesting(root.get(),
+ identity_matrix,
+ transform_origin,
+ gfx::PointF(),
+ gfx::Size(100, 100),
+ true,
+ false);
+ {
+ scoped_ptr<LayerImpl> clipping_layer =
+ LayerImpl::Create(host_impl().active_tree(), 123);
+ // this layer is positioned, and hit testing should correctly know where the
+ // layer is located.
+ gfx::PointF position(25.f, 25.f);
+ gfx::Size bounds(50, 50);
+ SetLayerPropertiesForTesting(clipping_layer.get(),
+ identity_matrix,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+ clipping_layer->SetMasksToBounds(true);
+
+ scoped_ptr<LayerImpl> child =
+ LayerImpl::Create(host_impl().active_tree(), 456);
+ position = gfx::PointF(-50.f, -50.f);
+ bounds = gfx::Size(300, 300);
+ SetLayerPropertiesForTesting(child.get(),
+ identity_matrix,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+ child->SetDrawsContent(true);
+ clipping_layer->AddChild(child.Pass());
+ root->AddChild(clipping_layer.Pass());
+ }
+
+ host_impl().SetViewportSize(root->bounds());
+ host_impl().active_tree()->SetRootLayer(root.Pass());
+ host_impl().active_tree()->UpdateDrawProperties();
+
+ // Sanity check the scenario we just created.
+ ASSERT_EQ(1u, RenderSurfaceLayerList().size());
+ ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
+ ASSERT_EQ(456, root_layer()->render_surface()->layer_list().at(0)->id());
+
+ // 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
+ // layer's bounds.
+ gfx::Point test_point(24, 24);
+ LayerImpl* result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ EXPECT_FALSE(result_layer);
+
+ // Even though the layer exists at (101, 101), it should not be visible there
+ // since the clipping_layer would clamp it.
+ test_point = gfx::Point(76, 76);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ EXPECT_FALSE(result_layer);
+
+ // Hit testing for a point inside should return the child layer.
+ test_point = gfx::Point(26, 26);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(456, result_layer->id());
+
+ test_point = gfx::Point(74, 74);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(456, result_layer->id());
+}
+
+TEST_F(LayerTreeImplTest, HitTestingForMultiClippedRotatedLayer) {
+ // This test checks whether hit testing correctly avoids hit testing with
+ // multiple ancestors that clip in non axis-aligned ways. To pass this test,
+ // the hit testing algorithm needs to recognize that multiple parent layers
+ // may clip the layer, and should not actually hit those clipped areas.
+ //
+ // The child and grand_child layers are both initialized to clip the
+ // rotated_leaf. The child layer is rotated about the top-left corner, so that
+ // the root + child clips combined create a triangle. The rotated_leaf will
+ // only be visible where it overlaps this triangle.
+ //
+ scoped_ptr<LayerImpl> root =
+ LayerImpl::Create(host_impl().active_tree(), 123);
+
+ gfx::Transform identity_matrix;
+ gfx::Point3F transform_origin;
+ gfx::PointF position;
+ gfx::Size bounds(100, 100);
+ SetLayerPropertiesForTesting(root.get(),
+ identity_matrix,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+ root->SetMasksToBounds(true);
+ {
+ scoped_ptr<LayerImpl> child =
+ LayerImpl::Create(host_impl().active_tree(), 456);
+ scoped_ptr<LayerImpl> grand_child =
+ LayerImpl::Create(host_impl().active_tree(), 789);
+ scoped_ptr<LayerImpl> rotated_leaf =
+ LayerImpl::Create(host_impl().active_tree(), 2468);
+
+ position = gfx::PointF(10.f, 10.f);
+ bounds = gfx::Size(80, 80);
+ SetLayerPropertiesForTesting(child.get(),
+ identity_matrix,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+ child->SetMasksToBounds(true);
+
+ gfx::Transform rotation45_degrees_about_corner;
+ rotation45_degrees_about_corner.RotateAboutZAxis(45.0);
+
+ // remember, positioned with respect to its parent which is already at 10,
+ // 10
+ position = gfx::PointF();
+ bounds =
+ gfx::Size(200, 200); // to ensure it covers at least sqrt(2) * 100.
+ SetLayerPropertiesForTesting(grand_child.get(),
+ rotation45_degrees_about_corner,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+ grand_child->SetMasksToBounds(true);
+
+ // Rotates about the center of the layer
+ gfx::Transform rotated_leaf_transform;
+ rotated_leaf_transform.Translate(
+ -10.0, -10.0); // cancel out the grand_parent's position
+ rotated_leaf_transform.RotateAboutZAxis(
+ -45.0); // cancel out the corner 45-degree rotation of the parent.
+ rotated_leaf_transform.Translate(50.0, 50.0);
+ rotated_leaf_transform.RotateAboutZAxis(45.0);
+ rotated_leaf_transform.Translate(-50.0, -50.0);
+ position = gfx::PointF();
+ bounds = gfx::Size(100, 100);
+ SetLayerPropertiesForTesting(rotated_leaf.get(),
+ rotated_leaf_transform,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+ rotated_leaf->SetDrawsContent(true);
+
+ grand_child->AddChild(rotated_leaf.Pass());
+ child->AddChild(grand_child.Pass());
+ root->AddChild(child.Pass());
+ }
+
+ host_impl().SetViewportSize(root->bounds());
+ host_impl().active_tree()->SetRootLayer(root.Pass());
+ host_impl().active_tree()->UpdateDrawProperties();
+
+ // Sanity check the scenario we just created.
+ // The grand_child is expected to create a render surface because it
+ // MasksToBounds and is not axis aligned.
+ ASSERT_EQ(2u, RenderSurfaceLayerList().size());
+ ASSERT_EQ(
+ 1u,
+ RenderSurfaceLayerList().at(0)->render_surface()->layer_list().size());
+ ASSERT_EQ(789,
+ RenderSurfaceLayerList()
+ .at(0)
+ ->render_surface()
+ ->layer_list()
+ .at(0)
+ ->id()); // grand_child's surface.
+ ASSERT_EQ(
+ 1u,
+ RenderSurfaceLayerList().at(1)->render_surface()->layer_list().size());
+ ASSERT_EQ(
+ 2468,
+ RenderSurfaceLayerList()[1]->render_surface()->layer_list().at(0)->id());
+
+ // (11, 89) is close to the the bottom left corner within the clip, but it is
+ // not inside the layer.
+ gfx::Point test_point(11, 89);
+ LayerImpl* result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ EXPECT_FALSE(result_layer);
+
+ // Closer inwards from the bottom left will overlap the layer.
+ test_point = gfx::Point(25, 75);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(2468, result_layer->id());
+
+ // (4, 50) is inside the unclipped layer, but that corner of the layer should
+ // be clipped away by the grandparent and should not get hit. If hit testing
+ // blindly uses visible content rect without considering how parent may clip
+ // the layer, then hit testing would accidentally think that the point
+ // successfully hits the layer.
+ test_point = gfx::Point(4, 50);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ EXPECT_FALSE(result_layer);
+
+ // (11, 50) is inside the layer and within the clipped area.
+ test_point = gfx::Point(11, 50);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(2468, result_layer->id());
+
+ // Around the middle, just to the right and up, would have hit the layer
+ // except that that area should be clipped away by the parent.
+ test_point = gfx::Point(51, 49);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ EXPECT_FALSE(result_layer);
+
+ // Around the middle, just to the left and down, should successfully hit the
+ // layer.
+ test_point = gfx::Point(49, 51);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(2468, result_layer->id());
+}
+
+TEST_F(LayerTreeImplTest, HitTestingForNonClippingIntermediateLayer) {
+ // This test checks that hit testing code does not accidentally clip to layer
+ // bounds for a layer that actually does not clip.
+ gfx::Transform identity_matrix;
+ gfx::Point3F transform_origin;
+
+ scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl().active_tree(), 1);
+ SetLayerPropertiesForTesting(root.get(),
+ identity_matrix,
+ transform_origin,
+ gfx::PointF(),
+ gfx::Size(100, 100),
+ true,
+ false);
+ {
+ scoped_ptr<LayerImpl> intermediate_layer =
+ LayerImpl::Create(host_impl().active_tree(), 123);
+ // this layer is positioned, and hit testing should correctly know where the
+ // layer is located.
+ gfx::PointF position(10.f, 10.f);
+ gfx::Size bounds(50, 50);
+ SetLayerPropertiesForTesting(intermediate_layer.get(),
+ identity_matrix,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+ // Sanity check the intermediate layer should not clip.
+ ASSERT_FALSE(intermediate_layer->masks_to_bounds());
+ ASSERT_FALSE(intermediate_layer->mask_layer());
+
+ // The child of the intermediate_layer is translated so that it does not
+ // overlap intermediate_layer at all. If child is incorrectly clipped, we
+ // would not be able to hit it successfully.
+ scoped_ptr<LayerImpl> child =
+ LayerImpl::Create(host_impl().active_tree(), 456);
+ position = gfx::PointF(60.f, 60.f); // 70, 70 in screen space
+ bounds = gfx::Size(20, 20);
+ SetLayerPropertiesForTesting(child.get(),
+ identity_matrix,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+ child->SetDrawsContent(true);
+ intermediate_layer->AddChild(child.Pass());
+ root->AddChild(intermediate_layer.Pass());
+ }
+
+ host_impl().SetViewportSize(root->bounds());
+ host_impl().active_tree()->SetRootLayer(root.Pass());
+ host_impl().active_tree()->UpdateDrawProperties();
+
+ // Sanity check the scenario we just created.
+ ASSERT_EQ(1u, RenderSurfaceLayerList().size());
+ ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
+ ASSERT_EQ(456, root_layer()->render_surface()->layer_list().at(0)->id());
+
+ // Hit testing for a point outside the layer should return a null pointer.
+ gfx::Point test_point(69, 69);
+ LayerImpl* result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ EXPECT_FALSE(result_layer);
+
+ test_point = gfx::Point(91, 91);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ EXPECT_FALSE(result_layer);
+
+ // Hit testing for a point inside should return the child layer.
+ test_point = gfx::Point(71, 71);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(456, result_layer->id());
+
+ test_point = gfx::Point(89, 89);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(456, result_layer->id());
+}
+
+TEST_F(LayerTreeImplTest, HitTestingForMultipleLayers) {
+ scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl().active_tree(), 1);
+
+ gfx::Transform identity_matrix;
+ gfx::Point3F transform_origin;
+ gfx::PointF position;
+ gfx::Size bounds(100, 100);
+ SetLayerPropertiesForTesting(root.get(),
+ identity_matrix,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+ root->SetDrawsContent(true);
+ {
+ // child 1 and child2 are initialized to overlap between x=50 and x=60.
+ // grand_child is set to overlap both child1 and child2 between y=50 and
+ // y=60. The expected stacking order is: (front) child2, (second)
+ // grand_child, (third) child1, and (back) the root layer behind all other
+ // layers.
+
+ scoped_ptr<LayerImpl> child1 =
+ LayerImpl::Create(host_impl().active_tree(), 2);
+ scoped_ptr<LayerImpl> child2 =
+ LayerImpl::Create(host_impl().active_tree(), 3);
+ scoped_ptr<LayerImpl> grand_child1 =
+ LayerImpl::Create(host_impl().active_tree(), 4);
+
+ position = gfx::PointF(10.f, 10.f);
+ bounds = gfx::Size(50, 50);
+ SetLayerPropertiesForTesting(child1.get(),
+ identity_matrix,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+ child1->SetDrawsContent(true);
+
+ position = gfx::PointF(50.f, 10.f);
+ bounds = gfx::Size(50, 50);
+ SetLayerPropertiesForTesting(child2.get(),
+ identity_matrix,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+ child2->SetDrawsContent(true);
+
+ // Remember that grand_child is positioned with respect to its parent (i.e.
+ // child1). In screen space, the intended position is (10, 50), with size
+ // 100 x 50.
+ position = gfx::PointF(0.f, 40.f);
+ bounds = gfx::Size(100, 50);
+ SetLayerPropertiesForTesting(grand_child1.get(),
+ identity_matrix,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+ grand_child1->SetDrawsContent(true);
+
+ child1->AddChild(grand_child1.Pass());
+ root->AddChild(child1.Pass());
+ root->AddChild(child2.Pass());
+ }
+
+ LayerImpl* child1 = root->children()[0];
+ LayerImpl* child2 = root->children()[1];
+ LayerImpl* grand_child1 = child1->children()[0];
+
+ host_impl().SetViewportSize(root->bounds());
+ host_impl().active_tree()->SetRootLayer(root.Pass());
+ host_impl().active_tree()->UpdateDrawProperties();
+
+ // Sanity check the scenario we just created.
+ ASSERT_TRUE(child1);
+ ASSERT_TRUE(child2);
+ ASSERT_TRUE(grand_child1);
+ ASSERT_EQ(1u, RenderSurfaceLayerList().size());
+
+ RenderSurfaceImpl* root_render_surface = root_layer()->render_surface();
+ 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
+
+ // Nothing overlaps the root_layer at (1, 1), so hit testing there should find
+ // the root layer.
+ gfx::Point test_point = gfx::Point(1, 1);
+ LayerImpl* result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(1, result_layer->id());
+
+ // At (15, 15), child1 and root are the only layers. child1 is expected to be
+ // on top.
+ test_point = gfx::Point(15, 15);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(2, result_layer->id());
+
+ // At (51, 20), child1 and child2 overlap. child2 is expected to be on top.
+ test_point = gfx::Point(51, 20);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(3, result_layer->id());
+
+ // At (80, 51), child2 and grand_child1 overlap. child2 is expected to be on
+ // top.
+ test_point = gfx::Point(80, 51);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(3, result_layer->id());
+
+ // At (51, 51), all layers overlap each other. child2 is expected to be on top
+ // of all other layers.
+ test_point = gfx::Point(51, 51);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(3, result_layer->id());
+
+ // At (20, 51), child1 and grand_child1 overlap. grand_child1 is expected to
+ // be on top.
+ test_point = gfx::Point(20, 51);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(4, result_layer->id());
+}
+
+TEST_F(LayerTreeImplTest, HitTestingForMultipleLayersAtVaryingDepths) {
+ scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl().active_tree(), 1);
+
+ gfx::Transform identity_matrix;
+ gfx::Point3F transform_origin;
+ gfx::PointF position;
+ gfx::Size bounds(100, 100);
+ SetLayerPropertiesForTesting(root.get(),
+ identity_matrix,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+ root->SetDrawsContent(true);
+ root->SetShouldFlattenTransform(false);
+ root->Set3dSortingContextId(1);
+ {
+ // child 1 and child2 are initialized to overlap between x=50 and x=60.
+ // grand_child is set to overlap both child1 and child2 between y=50 and
+ // y=60. The expected stacking order is: (front) child2, (second)
+ // grand_child, (third) child1, and (back) the root layer behind all other
+ // layers.
+
+ scoped_ptr<LayerImpl> child1 =
+ LayerImpl::Create(host_impl().active_tree(), 2);
+ scoped_ptr<LayerImpl> child2 =
+ LayerImpl::Create(host_impl().active_tree(), 3);
+ scoped_ptr<LayerImpl> grand_child1 =
+ LayerImpl::Create(host_impl().active_tree(), 4);
+
+ position = gfx::PointF(10.f, 10.f);
+ bounds = gfx::Size(50, 50);
+ SetLayerPropertiesForTesting(child1.get(),
+ identity_matrix,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+ child1->SetDrawsContent(true);
+ child1->SetShouldFlattenTransform(false);
+ child1->Set3dSortingContextId(1);
+
+ position = gfx::PointF(50.f, 10.f);
+ bounds = gfx::Size(50, 50);
+ gfx::Transform translate_z;
+ translate_z.Translate3d(0, 0, -10.f);
+ SetLayerPropertiesForTesting(child2.get(),
+ translate_z,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+ child2->SetDrawsContent(true);
+ child2->SetShouldFlattenTransform(false);
+ child2->Set3dSortingContextId(1);
+
+ // Remember that grand_child is positioned with respect to its parent (i.e.
+ // child1). In screen space, the intended position is (10, 50), with size
+ // 100 x 50.
+ position = gfx::PointF(0.f, 40.f);
+ bounds = gfx::Size(100, 50);
+ SetLayerPropertiesForTesting(grand_child1.get(),
+ identity_matrix,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+ grand_child1->SetDrawsContent(true);
+ grand_child1->SetShouldFlattenTransform(false);
+
+ child1->AddChild(grand_child1.Pass());
+ root->AddChild(child1.Pass());
+ root->AddChild(child2.Pass());
+ }
+
+ LayerImpl* child1 = root->children()[0];
+ LayerImpl* child2 = root->children()[1];
+ LayerImpl* grand_child1 = child1->children()[0];
+
+ host_impl().SetViewportSize(root->bounds());
+ host_impl().active_tree()->SetRootLayer(root.Pass());
+ host_impl().active_tree()->UpdateDrawProperties();
+
+ // Sanity check the scenario we just created.
+ ASSERT_TRUE(child1);
+ ASSERT_TRUE(child2);
+ ASSERT_TRUE(grand_child1);
+ ASSERT_EQ(1u, RenderSurfaceLayerList().size());
+
+ RenderSurfaceImpl* root_render_surface =
+ host_impl().active_tree()->root_layer()->render_surface();
+ ASSERT_EQ(4u, root_render_surface->layer_list().size());
+ ASSERT_EQ(3, root_render_surface->layer_list().at(0)->id());
+ ASSERT_EQ(1, root_render_surface->layer_list().at(1)->id());
+ ASSERT_EQ(2, root_render_surface->layer_list().at(2)->id());
+ ASSERT_EQ(4, root_render_surface->layer_list().at(3)->id());
+
+ // Nothing overlaps the root_layer at (1, 1), so hit testing there should find
+ // the root layer.
+ gfx::Point test_point = gfx::Point(1, 1);
+ LayerImpl* result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(1, result_layer->id());
+
+ // At (15, 15), child1 and root are the only layers. child1 is expected to be
+ // on top.
+ test_point = gfx::Point(15, 15);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(2, result_layer->id());
+
+ // At (51, 20), child1 and child2 overlap. child2 is expected to be on top.
+ // (because 3 is transformed to the back).
+ test_point = gfx::Point(51, 20);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(2, result_layer->id());
+
+ // 3 Would have been on top if it hadn't been transformed to the background.
+ // Make sure that it isn't hit.
+ test_point = gfx::Point(80, 51);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(4, result_layer->id());
+
+ // 3 Would have been on top if it hadn't been transformed to the background.
+ // Make sure that it isn't hit.
+ test_point = gfx::Point(51, 51);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(4, result_layer->id());
+
+ // At (20, 51), child1 and grand_child1 overlap. grand_child1 is expected to
+ // be on top.
+ test_point = gfx::Point(20, 51);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(4, result_layer->id());
+}
+
+TEST_F(LayerTreeImplTest, HitTestingRespectsClipParents) {
+ scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl().active_tree(), 1);
+ gfx::Transform identity_matrix;
+ gfx::Point3F transform_origin;
+ gfx::PointF position;
+ gfx::Size bounds(100, 100);
+ SetLayerPropertiesForTesting(root.get(),
+ identity_matrix,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+ root->SetDrawsContent(true);
+ {
+ scoped_ptr<LayerImpl> child =
+ LayerImpl::Create(host_impl().active_tree(), 2);
+ scoped_ptr<LayerImpl> grand_child =
+ LayerImpl::Create(host_impl().active_tree(), 4);
+
+ position = gfx::PointF(10.f, 10.f);
+ bounds = gfx::Size(1, 1);
+ SetLayerPropertiesForTesting(child.get(),
+ identity_matrix,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+ child->SetDrawsContent(true);
+ child->SetMasksToBounds(true);
+
+ position = gfx::PointF(0.f, 40.f);
+ bounds = gfx::Size(100, 50);
+ SetLayerPropertiesForTesting(grand_child.get(),
+ identity_matrix,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+ grand_child->SetDrawsContent(true);
+ grand_child->SetForceRenderSurface(true);
+
+ // This should let |grand_child| "escape" |child|'s clip.
+ grand_child->SetClipParent(root.get());
+
+ child->AddChild(grand_child.Pass());
+ root->AddChild(child.Pass());
+ }
+
+ host_impl().SetViewportSize(root->bounds());
+ host_impl().active_tree()->SetRootLayer(root.Pass());
+ host_impl().active_tree()->UpdateDrawProperties();
+
+ gfx::Point test_point = gfx::Point(12, 52);
+ LayerImpl* result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(4, result_layer->id());
+}
+
+TEST_F(LayerTreeImplTest, HitTestingRespectsScrollParents) {
+ scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl().active_tree(), 1);
+ gfx::Transform identity_matrix;
+ gfx::Point3F transform_origin;
+ gfx::PointF position;
+ gfx::Size bounds(100, 100);
+ SetLayerPropertiesForTesting(root.get(),
+ identity_matrix,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+ root->SetDrawsContent(true);
+ {
+ scoped_ptr<LayerImpl> child =
+ LayerImpl::Create(host_impl().active_tree(), 2);
+ scoped_ptr<LayerImpl> scroll_child =
+ LayerImpl::Create(host_impl().active_tree(), 3);
+ scoped_ptr<LayerImpl> grand_child =
+ LayerImpl::Create(host_impl().active_tree(), 4);
+
+ position = gfx::PointF(10.f, 10.f);
+ bounds = gfx::Size(1, 1);
+ SetLayerPropertiesForTesting(child.get(),
+ identity_matrix,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+ child->SetDrawsContent(true);
+ child->SetMasksToBounds(true);
+
+ position = gfx::PointF();
+ bounds = gfx::Size(200, 200);
+ SetLayerPropertiesForTesting(scroll_child.get(),
+ identity_matrix,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+ scroll_child->SetDrawsContent(true);
+
+ // This should cause scroll child and its descendants to be affected by
+ // |child|'s clip.
+ scroll_child->SetScrollParent(child.get());
+
+ SetLayerPropertiesForTesting(grand_child.get(),
+ identity_matrix,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+ grand_child->SetDrawsContent(true);
+ grand_child->SetForceRenderSurface(true);
+
+ scroll_child->AddChild(grand_child.Pass());
+ root->AddChild(scroll_child.Pass());
+ root->AddChild(child.Pass());
+ }
+
+ host_impl().SetViewportSize(root->bounds());
+ host_impl().active_tree()->SetRootLayer(root.Pass());
+ host_impl().active_tree()->UpdateDrawProperties();
+
+ gfx::Point test_point = gfx::Point(12, 52);
+ LayerImpl* result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ // The |test_point| should have been clipped away by |child|, the scroll
+ // parent, so the only thing that should be hit is |root|.
+ ASSERT_TRUE(result_layer);
+ ASSERT_EQ(1, result_layer->id());
+}
+TEST_F(LayerTreeImplTest, HitTestingForMultipleLayerLists) {
+ //
+ // The geometry is set up similarly to the previous case, but
+ // all layers are forced to be render surfaces now.
+ //
+ scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl().active_tree(), 1);
+
+ gfx::Transform identity_matrix;
+ gfx::Point3F transform_origin;
+ gfx::PointF position;
+ gfx::Size bounds(100, 100);
+ SetLayerPropertiesForTesting(root.get(),
+ identity_matrix,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+ root->SetDrawsContent(true);
+ {
+ // child 1 and child2 are initialized to overlap between x=50 and x=60.
+ // grand_child is set to overlap both child1 and child2 between y=50 and
+ // y=60. The expected stacking order is: (front) child2, (second)
+ // grand_child, (third) child1, and (back) the root layer behind all other
+ // layers.
+
+ scoped_ptr<LayerImpl> child1 =
+ LayerImpl::Create(host_impl().active_tree(), 2);
+ scoped_ptr<LayerImpl> child2 =
+ LayerImpl::Create(host_impl().active_tree(), 3);
+ scoped_ptr<LayerImpl> grand_child1 =
+ LayerImpl::Create(host_impl().active_tree(), 4);
+
+ position = gfx::PointF(10.f, 10.f);
+ bounds = gfx::Size(50, 50);
+ SetLayerPropertiesForTesting(child1.get(),
+ identity_matrix,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+ child1->SetDrawsContent(true);
+ child1->SetForceRenderSurface(true);
+
+ position = gfx::PointF(50.f, 10.f);
+ bounds = gfx::Size(50, 50);
+ SetLayerPropertiesForTesting(child2.get(),
+ identity_matrix,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+ child2->SetDrawsContent(true);
+ child2->SetForceRenderSurface(true);
+
+ // Remember that grand_child is positioned with respect to its parent (i.e.
+ // child1). In screen space, the intended position is (10, 50), with size
+ // 100 x 50.
+ position = gfx::PointF(0.f, 40.f);
+ bounds = gfx::Size(100, 50);
+ SetLayerPropertiesForTesting(grand_child1.get(),
+ identity_matrix,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+ grand_child1->SetDrawsContent(true);
+ grand_child1->SetForceRenderSurface(true);
+
+ child1->AddChild(grand_child1.Pass());
+ root->AddChild(child1.Pass());
+ root->AddChild(child2.Pass());
+ }
+
+ LayerImpl* child1 = root->children()[0];
+ LayerImpl* child2 = root->children()[1];
+ LayerImpl* grand_child1 = child1->children()[0];
+
+ host_impl().SetViewportSize(root->bounds());
+ host_impl().active_tree()->SetRootLayer(root.Pass());
+ host_impl().active_tree()->UpdateDrawProperties();
+
+ // Sanity check the scenario we just created.
+ ASSERT_TRUE(child1);
+ ASSERT_TRUE(child2);
+ ASSERT_TRUE(grand_child1);
+ ASSERT_TRUE(child1->render_surface());
+ ASSERT_TRUE(child2->render_surface());
+ ASSERT_TRUE(grand_child1->render_surface());
+ ASSERT_EQ(4u, RenderSurfaceLayerList().size());
+ // The root surface has the root layer, and child1's and child2's render
+ // surfaces.
+ ASSERT_EQ(3u, root_layer()->render_surface()->layer_list().size());
+ // The child1 surface has the child1 layer and grand_child1's render surface.
+ ASSERT_EQ(2u, child1->render_surface()->layer_list().size());
+ ASSERT_EQ(1u, child2->render_surface()->layer_list().size());
+ ASSERT_EQ(1u, grand_child1->render_surface()->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
+
+ // Nothing overlaps the root_layer at (1, 1), so hit testing there should find
+ // the root layer.
+ gfx::Point test_point = gfx::Point(1, 1);
+ LayerImpl* result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(1, result_layer->id());
+
+ // At (15, 15), child1 and root are the only layers. child1 is expected to be
+ // on top.
+ test_point = gfx::Point(15, 15);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(2, result_layer->id());
+
+ // At (51, 20), child1 and child2 overlap. child2 is expected to be on top.
+ test_point = gfx::Point(51, 20);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(3, result_layer->id());
+
+ // At (80, 51), child2 and grand_child1 overlap. child2 is expected to be on
+ // top.
+ test_point = gfx::Point(80, 51);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(3, result_layer->id());
+
+ // At (51, 51), all layers overlap each other. child2 is expected to be on top
+ // of all other layers.
+ test_point = gfx::Point(51, 51);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(3, result_layer->id());
+
+ // At (20, 51), child1 and grand_child1 overlap. grand_child1 is expected to
+ // be on top.
+ test_point = gfx::Point(20, 51);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(4, result_layer->id());
+}
+
+TEST_F(LayerTreeImplTest, HitCheckingTouchHandlerRegionsForSingleLayer) {
+ scoped_ptr<LayerImpl> root =
+ LayerImpl::Create(host_impl().active_tree(), 12345);
+
+ gfx::Transform identity_matrix;
+ Region touch_handler_region(gfx::Rect(10, 10, 50, 50));
+ gfx::Point3F transform_origin;
+ gfx::PointF position;
+ gfx::Size bounds(100, 100);
+ SetLayerPropertiesForTesting(root.get(),
+ identity_matrix,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+ root->SetDrawsContent(true);
+
+ host_impl().SetViewportSize(root->bounds());
+ host_impl().active_tree()->SetRootLayer(root.Pass());
+ host_impl().active_tree()->UpdateDrawProperties();
+
+ // Sanity check the scenario we just created.
+ ASSERT_EQ(1u, RenderSurfaceLayerList().size());
+ ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
+
+ // Hit checking for any point should return a null pointer for a layer without
+ // any touch event handler regions.
+ gfx::Point test_point(11, 11);
+ LayerImpl* result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
+ test_point);
+ EXPECT_FALSE(result_layer);
+
+ host_impl().active_tree()->root_layer()->SetTouchEventHandlerRegion(
+ touch_handler_region);
+ // Hit checking for a point outside the layer should return a null pointer.
+ test_point = gfx::Point(101, 101);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
+ test_point);
+ EXPECT_FALSE(result_layer);
+
+ test_point = gfx::Point(-1, -1);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
+ test_point);
+ EXPECT_FALSE(result_layer);
+
+ // Hit checking for a point inside the layer, but outside the touch handler
+ // region should return a null pointer.
+ test_point = gfx::Point(1, 1);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
+ test_point);
+ EXPECT_FALSE(result_layer);
+
+ test_point = gfx::Point(99, 99);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
+ test_point);
+ EXPECT_FALSE(result_layer);
+
+ // Hit checking for a point inside the touch event handler region should
+ // return the root layer.
+ test_point = gfx::Point(11, 11);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
+ test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(12345, result_layer->id());
+
+ test_point = gfx::Point(59, 59);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
+ test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(12345, result_layer->id());
+}
+
+TEST_F(LayerTreeImplTest,
+ HitCheckingTouchHandlerRegionsForUninvertibleTransform) {
+ scoped_ptr<LayerImpl> root =
+ LayerImpl::Create(host_impl().active_tree(), 12345);
+
+ gfx::Transform uninvertible_transform;
+ uninvertible_transform.matrix().set(0, 0, 0.0);
+ uninvertible_transform.matrix().set(1, 1, 0.0);
+ uninvertible_transform.matrix().set(2, 2, 0.0);
+ uninvertible_transform.matrix().set(3, 3, 0.0);
+ ASSERT_FALSE(uninvertible_transform.IsInvertible());
+
+ gfx::Transform identity_matrix;
+ Region touch_handler_region(gfx::Rect(10, 10, 50, 50));
+ gfx::Point3F transform_origin;
+ gfx::PointF position;
+ gfx::Size bounds(100, 100);
+ SetLayerPropertiesForTesting(root.get(),
+ uninvertible_transform,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+ root->SetDrawsContent(true);
+ root->SetTouchEventHandlerRegion(touch_handler_region);
+
+ host_impl().SetViewportSize(root->bounds());
+ host_impl().active_tree()->SetRootLayer(root.Pass());
+ host_impl().active_tree()->UpdateDrawProperties();
+
+ // Sanity check the scenario we just created.
+ ASSERT_EQ(1u, RenderSurfaceLayerList().size());
+ ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
+ ASSERT_FALSE(root_layer()->screen_space_transform().IsInvertible());
+
+ // Hit checking any point should not hit the touch handler region on the
+ // layer. If the invertible matrix is accidentally ignored and treated like an
+ // identity, then the hit testing will incorrectly hit the layer when it
+ // shouldn't.
+ gfx::Point test_point(1, 1);
+ LayerImpl* result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
+ test_point);
+ EXPECT_FALSE(result_layer);
+
+ test_point = gfx::Point(10, 10);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
+ test_point);
+ EXPECT_FALSE(result_layer);
+
+ test_point = gfx::Point(10, 30);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
+ test_point);
+ EXPECT_FALSE(result_layer);
+
+ test_point = gfx::Point(50, 50);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
+ test_point);
+ EXPECT_FALSE(result_layer);
+
+ test_point = gfx::Point(67, 48);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
+ test_point);
+ EXPECT_FALSE(result_layer);
+
+ test_point = gfx::Point(99, 99);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
+ test_point);
+ EXPECT_FALSE(result_layer);
+
+ test_point = gfx::Point(-1, -1);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
+ test_point);
+ EXPECT_FALSE(result_layer);
+}
+
+TEST_F(LayerTreeImplTest,
+ HitCheckingTouchHandlerRegionsForSinglePositionedLayer) {
+ scoped_ptr<LayerImpl> root =
+ LayerImpl::Create(host_impl().active_tree(), 12345);
+
+ gfx::Transform identity_matrix;
+ Region touch_handler_region(gfx::Rect(10, 10, 50, 50));
+ gfx::Point3F transform_origin;
+ // this layer is positioned, and hit testing should correctly know where the
+ // layer is located.
+ gfx::PointF position(50.f, 50.f);
+ gfx::Size bounds(100, 100);
+ SetLayerPropertiesForTesting(root.get(),
+ identity_matrix,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+ root->SetDrawsContent(true);
+ root->SetTouchEventHandlerRegion(touch_handler_region);
+
+ host_impl().SetViewportSize(root->bounds());
+ host_impl().active_tree()->SetRootLayer(root.Pass());
+ host_impl().active_tree()->UpdateDrawProperties();
+
+ // Sanity check the scenario we just created.
+ ASSERT_EQ(1u, RenderSurfaceLayerList().size());
+ ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
+
+ // Hit checking for a point outside the layer should return a null pointer.
+ gfx::Point test_point(49, 49);
+ LayerImpl* result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
+ test_point);
+ EXPECT_FALSE(result_layer);
+
+ // Even though the layer has a touch handler region containing (101, 101), it
+ // should not be visible there since the root render surface would clamp it.
+ test_point = gfx::Point(101, 101);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
+ test_point);
+ EXPECT_FALSE(result_layer);
+
+ // Hit checking for a point inside the layer, but outside the touch handler
+ // region should return a null pointer.
+ test_point = gfx::Point(51, 51);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
+ test_point);
+ EXPECT_FALSE(result_layer);
+
+ // Hit checking for a point inside the touch event handler region should
+ // return the root layer.
+ test_point = gfx::Point(61, 61);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
+ test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(12345, result_layer->id());
+
+ test_point = gfx::Point(99, 99);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
+ test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(12345, result_layer->id());
+}
+
+TEST_F(LayerTreeImplTest,
+ HitCheckingTouchHandlerRegionsForSingleLayerWithScaledContents) {
+ // A layer's visible content rect is actually in the layer's content space.
+ // The screen space transform converts from the layer's origin space to screen
+ // space. This test makes sure that hit testing works correctly accounts for
+ // the contents scale. A contents scale that is not 1 effectively forces a
+ // non-identity transform between layer's content space and layer's origin
+ // space. The hit testing code must take this into account.
+ //
+ // To test this, the layer is positioned at (25, 25), and is size (50, 50). If
+ // contents scale is ignored, then hit checking will mis-interpret the visible
+ // content rect as being larger than the actual bounds of the layer.
+ //
+ scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl().active_tree(), 1);
+
+ gfx::Transform identity_matrix;
+ gfx::Point3F transform_origin;
+
+ SetLayerPropertiesForTesting(root.get(),
+ identity_matrix,
+ transform_origin,
+ gfx::PointF(),
+ gfx::Size(100, 100),
+ true,
+ false);
+ {
+ Region touch_handler_region(gfx::Rect(10, 10, 30, 30));
+ gfx::PointF position(25.f, 25.f);
+ gfx::Size bounds(50, 50);
+ scoped_ptr<LayerImpl> test_layer =
+ LayerImpl::Create(host_impl().active_tree(), 12345);
+ SetLayerPropertiesForTesting(test_layer.get(),
+ identity_matrix,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+
+ // override content bounds and contents scale
+ test_layer->SetContentBounds(gfx::Size(100, 100));
+ test_layer->SetContentsScale(2, 2);
+
+ test_layer->SetDrawsContent(true);
+ test_layer->SetTouchEventHandlerRegion(touch_handler_region);
+ root->AddChild(test_layer.Pass());
+ }
+
+ host_impl().SetViewportSize(root->bounds());
+ host_impl().active_tree()->SetRootLayer(root.Pass());
+ host_impl().active_tree()->UpdateDrawProperties();
+
+ // Sanity check the scenario we just created.
+ // The visible content rect for test_layer is actually 100x100, even though
+ // its layout size is 50x50, positioned at 25x25.
+ LayerImpl* test_layer =
+ host_impl().active_tree()->root_layer()->children()[0];
+ EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100), test_layer->visible_content_rect());
+ ASSERT_EQ(1u, RenderSurfaceLayerList().size());
+ ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
+
+ // Hit checking for a point outside the layer should return a null pointer
+ // (the root layer does not draw content, so it will not be tested either).
+ gfx::Point test_point(76, 76);
+ LayerImpl* result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
+ test_point);
+ EXPECT_FALSE(result_layer);
+
+ // Hit checking for a point inside the layer, but outside the touch handler
+ // region should return a null pointer.
+ test_point = gfx::Point(26, 26);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
+ test_point);
+ EXPECT_FALSE(result_layer);
+
+ test_point = gfx::Point(34, 34);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
+ test_point);
+ EXPECT_FALSE(result_layer);
+
+ test_point = gfx::Point(65, 65);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
+ test_point);
+ EXPECT_FALSE(result_layer);
+
+ test_point = gfx::Point(74, 74);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
+ test_point);
+ EXPECT_FALSE(result_layer);
+
+ // Hit checking for a point inside the touch event handler region should
+ // return the root layer.
+ test_point = gfx::Point(35, 35);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
+ test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(12345, result_layer->id());
+
+ test_point = gfx::Point(64, 64);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
+ test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(12345, result_layer->id());
+}
+
+TEST_F(LayerTreeImplTest,
+ HitCheckingTouchHandlerRegionsForSingleLayerWithDeviceScale) {
+ // The layer's device_scale_factor and page_scale_factor should scale the
+ // content rect and we should be able to hit the touch handler region by
+ // scaling the points accordingly.
+ scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl().active_tree(), 1);
+
+ gfx::Transform identity_matrix;
+ gfx::Point3F transform_origin;
+ // Set the bounds of the root layer big enough to fit the child when scaled.
+ SetLayerPropertiesForTesting(root.get(),
+ identity_matrix,
+ transform_origin,
+ gfx::PointF(),
+ gfx::Size(100, 100),
+ true,
+ false);
+ {
+ Region touch_handler_region(gfx::Rect(10, 10, 30, 30));
+ gfx::PointF position(25.f, 25.f);
+ gfx::Size bounds(50, 50);
+ scoped_ptr<LayerImpl> test_layer =
+ LayerImpl::Create(host_impl().active_tree(), 12345);
+ SetLayerPropertiesForTesting(test_layer.get(),
+ identity_matrix,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+
+ test_layer->SetDrawsContent(true);
+ test_layer->SetTouchEventHandlerRegion(touch_handler_region);
+ root->AddChild(test_layer.Pass());
+ }
+
+ float device_scale_factor = 3.f;
+ float page_scale_factor = 5.f;
+ gfx::Size scaled_bounds_for_root = gfx::ToCeiledSize(
+ gfx::ScaleSize(root->bounds(), device_scale_factor * page_scale_factor));
+ host_impl().SetViewportSize(scaled_bounds_for_root);
+
+ host_impl().SetDeviceScaleFactor(device_scale_factor);
+ host_impl().active_tree()->SetPageScaleFactorAndLimits(
+ page_scale_factor, page_scale_factor, page_scale_factor);
+ host_impl().active_tree()->SetRootLayer(root.Pass());
+ host_impl().active_tree()->SetViewportLayersFromIds(1, 1, Layer::INVALID_ID);
+ host_impl().active_tree()->UpdateDrawProperties();
+
+ // Sanity check the scenario we just created.
+ // The visible content rect for test_layer is actually 100x100, even though
+ // its layout size is 50x50, positioned at 25x25.
+ LayerImpl* test_layer =
+ host_impl().active_tree()->root_layer()->children()[0];
+ ASSERT_EQ(1u, RenderSurfaceLayerList().size());
+ ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
+
+ // Check whether the child layer fits into the root after scaled.
+ EXPECT_RECT_EQ(gfx::Rect(test_layer->content_bounds()),
+ test_layer->visible_content_rect());
+
+ // Hit checking for a point outside the layer should return a null pointer
+ // (the root layer does not draw content, so it will not be tested either).
+ gfx::PointF test_point(76.f, 76.f);
+ test_point =
+ gfx::ScalePoint(test_point, device_scale_factor * page_scale_factor);
+ LayerImpl* result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
+ test_point);
+ EXPECT_FALSE(result_layer);
+
+ // Hit checking for a point inside the layer, but outside the touch handler
+ // region should return a null pointer.
+ test_point = gfx::Point(26, 26);
+ test_point =
+ gfx::ScalePoint(test_point, device_scale_factor * page_scale_factor);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
+ test_point);
+ EXPECT_FALSE(result_layer);
+
+ test_point = gfx::Point(34, 34);
+ test_point =
+ gfx::ScalePoint(test_point, device_scale_factor * page_scale_factor);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
+ test_point);
+ EXPECT_FALSE(result_layer);
+
+ test_point = gfx::Point(65, 65);
+ test_point =
+ gfx::ScalePoint(test_point, device_scale_factor * page_scale_factor);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
+ test_point);
+ EXPECT_FALSE(result_layer);
+
+ test_point = gfx::Point(74, 74);
+ test_point =
+ gfx::ScalePoint(test_point, device_scale_factor * page_scale_factor);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
+ test_point);
+ EXPECT_FALSE(result_layer);
+
+ // Hit checking for a point inside the touch event handler region should
+ // return the root layer.
+ test_point = gfx::Point(35, 35);
+ test_point =
+ gfx::ScalePoint(test_point, device_scale_factor * page_scale_factor);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
+ test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(12345, result_layer->id());
+
+ test_point = gfx::Point(64, 64);
+ test_point =
+ gfx::ScalePoint(test_point, device_scale_factor * page_scale_factor);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
+ test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(12345, result_layer->id());
+}
+
+TEST_F(LayerTreeImplTest, HitCheckingTouchHandlerRegionsForSimpleClippedLayer) {
+ // Test that hit-checking will only work for the visible portion of a layer,
+ // and not the entire layer bounds. Here we just test the simple axis-aligned
+ // case.
+ gfx::Transform identity_matrix;
+ gfx::Point3F transform_origin;
+
+ scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl().active_tree(), 1);
+ SetLayerPropertiesForTesting(root.get(),
+ identity_matrix,
+ transform_origin,
+ gfx::PointF(),
+ gfx::Size(100, 100),
+ true,
+ false);
+ {
+ scoped_ptr<LayerImpl> clipping_layer =
+ LayerImpl::Create(host_impl().active_tree(), 123);
+ // this layer is positioned, and hit testing should correctly know where the
+ // layer is located.
+ gfx::PointF position(25.f, 25.f);
+ gfx::Size bounds(50, 50);
+ SetLayerPropertiesForTesting(clipping_layer.get(),
+ identity_matrix,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+ clipping_layer->SetMasksToBounds(true);
+
+ scoped_ptr<LayerImpl> child =
+ LayerImpl::Create(host_impl().active_tree(), 456);
+ Region touch_handler_region(gfx::Rect(10, 10, 50, 50));
+ position = gfx::PointF(-50.f, -50.f);
+ bounds = gfx::Size(300, 300);
+ SetLayerPropertiesForTesting(child.get(),
+ identity_matrix,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+ child->SetDrawsContent(true);
+ child->SetTouchEventHandlerRegion(touch_handler_region);
+ clipping_layer->AddChild(child.Pass());
+ root->AddChild(clipping_layer.Pass());
+ }
+
+ host_impl().SetViewportSize(root->bounds());
+ host_impl().active_tree()->SetRootLayer(root.Pass());
+ host_impl().active_tree()->UpdateDrawProperties();
+
+ // Sanity check the scenario we just created.
+ ASSERT_EQ(1u, RenderSurfaceLayerList().size());
+ ASSERT_EQ(1u, root_layer()->render_surface()->layer_list().size());
+ ASSERT_EQ(456, root_layer()->render_surface()->layer_list().at(0)->id());
+
+ // 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
+ // layer's bounds.
+ gfx::Point test_point(24, 24);
+ LayerImpl* result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
+ test_point);
+ EXPECT_FALSE(result_layer);
+
+ // Hit checking for a point inside the layer, but outside the touch handler
+ // region should return a null pointer.
+ test_point = gfx::Point(35, 35);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
+ test_point);
+ EXPECT_FALSE(result_layer);
+
+ test_point = gfx::Point(74, 74);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
+ test_point);
+ EXPECT_FALSE(result_layer);
+
+ // Hit checking for a point inside the touch event handler region should
+ // return the root layer.
+ test_point = gfx::Point(25, 25);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
+ test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(456, result_layer->id());
+
+ test_point = gfx::Point(34, 34);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
+ test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(456, result_layer->id());
+}
+
+TEST_F(LayerTreeImplTest, HitCheckingTouchHandlerOverlappingRegions) {
+ gfx::Transform identity_matrix;
+ gfx::Point3F transform_origin;
+
+ scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl().active_tree(), 1);
+ SetLayerPropertiesForTesting(root.get(),
+ identity_matrix,
+ transform_origin,
+ gfx::PointF(),
+ gfx::Size(100, 100),
+ true,
+ false);
+ {
+ scoped_ptr<LayerImpl> touch_layer =
+ LayerImpl::Create(host_impl().active_tree(), 123);
+ // this layer is positioned, and hit testing should correctly know where the
+ // layer is located.
+ gfx::PointF position;
+ gfx::Size bounds(50, 50);
+ SetLayerPropertiesForTesting(touch_layer.get(),
+ identity_matrix,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+ touch_layer->SetDrawsContent(true);
+ touch_layer->SetTouchEventHandlerRegion(gfx::Rect(0, 0, 50, 50));
+ root->AddChild(touch_layer.Pass());
+ }
+
+ {
+ scoped_ptr<LayerImpl> notouch_layer =
+ LayerImpl::Create(host_impl().active_tree(), 1234);
+ // this layer is positioned, and hit testing should correctly know where the
+ // layer is located.
+ gfx::PointF position(0, 25);
+ gfx::Size bounds(50, 50);
+ SetLayerPropertiesForTesting(notouch_layer.get(),
+ identity_matrix,
+ transform_origin,
+ position,
+ bounds,
+ true,
+ false);
+ notouch_layer->SetDrawsContent(true);
+ root->AddChild(notouch_layer.Pass());
+ }
+
+ host_impl().SetViewportSize(root->bounds());
+ host_impl().active_tree()->SetRootLayer(root.Pass());
+ host_impl().active_tree()->UpdateDrawProperties();
+
+ // Sanity check the scenario we just created.
+ ASSERT_EQ(1u, RenderSurfaceLayerList().size());
+ ASSERT_EQ(2u, root_layer()->render_surface()->layer_list().size());
+ ASSERT_EQ(123, root_layer()->render_surface()->layer_list().at(0)->id());
+ ASSERT_EQ(1234, root_layer()->render_surface()->layer_list().at(1)->id());
+
+ gfx::Point test_point(35, 35);
+ LayerImpl* result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
+ test_point);
+
+ // We should have passed through the no-touch layer and found the layer
+ // behind it.
+ EXPECT_TRUE(result_layer);
+
+ host_impl().active_tree()->LayerById(1234)->SetContentsOpaque(true);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
+ test_point);
+
+ // Even with an opaque layer in the middle, we should still find the layer
+ // with
+ // the touch handler behind it (since we can't assume that opaque layers are
+ // opaque to hit testing).
+ EXPECT_TRUE(result_layer);
+
+ test_point = gfx::Point(35, 15);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
+ test_point);
+ ASSERT_TRUE(result_layer);
+ EXPECT_EQ(123, result_layer->id());
+
+ test_point = gfx::Point(35, 65);
+ result_layer =
+ host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
+ test_point);
+ EXPECT_FALSE(result_layer);
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_settings.cc b/chromium/cc/trees/layer_tree_settings.cc
index b39524cb61b..1465325f5ba 100644
--- a/chromium/cc/trees/layer_tree_settings.cc
+++ b/chromium/cc/trees/layer_tree_settings.cc
@@ -16,23 +16,25 @@ LayerTreeSettings::LayerTreeSettings()
: impl_side_painting(false),
allow_antialiasing(true),
throttle_frame_production(true),
- begin_impl_frame_scheduling_enabled(false),
- deadline_scheduling_enabled(true),
+ begin_frame_scheduling_enabled(false),
+ main_frame_before_draw_enabled(true),
+ main_frame_before_activation_enabled(false),
using_synchronous_renderer_compositor(false),
+ report_overscroll_only_for_scrollable_axes(false),
per_tile_painting_enabled(false),
partial_swap_enabled(false),
accelerated_animation_enabled(true),
- background_color_instead_of_checkerboard(false),
- show_overdraw_in_tracing(false),
can_use_lcd_text(true),
should_clear_root_render_pass(true),
- gpu_rasterization(false),
+ gpu_rasterization_enabled(false),
+ gpu_rasterization_forced(false),
+ recording_mode(RecordNormally),
+ create_low_res_tiling(true),
scrollbar_animator(NoAnimator),
- scrollbar_linear_fade_delay_ms(300),
- scrollbar_linear_fade_length_ms(300),
+ scrollbar_fade_delay_ms(0),
+ scrollbar_fade_duration_ms(0),
solid_color_scrollbar_color(SK_ColorWHITE),
calculate_top_controls_position(false),
- use_memory_management(true),
timeout_and_draw_when_animation_checkerboards(true),
maximum_number_of_failed_draws_before_draw_is_forced_(3),
layer_transforms_should_scale_layer_contents(false),
@@ -43,7 +45,6 @@ LayerTreeSettings::LayerTreeSettings()
top_controls_hide_threshold(0.5f),
refresh_rate(60.0),
max_partial_texture_updates(std::numeric_limits<size_t>::max()),
- num_raster_threads(1),
default_tile_size(gfx::Size(256, 256)),
max_untiled_layer_size(gfx::Size(512, 512)),
minimum_occlusion_tracking_size(gfx::Size(160, 160)),
@@ -51,15 +52,19 @@ LayerTreeSettings::LayerTreeSettings()
use_pinch_virtual_viewport(false),
// At 256x256 tiles, 128 tiles cover an area of 2048x4096 pixels.
max_tiles_for_interest_area(128),
+ skewport_target_time_multiplier(1.0f),
+ skewport_extrapolation_limit_in_content_pixels(2000),
max_unused_resource_memory_percentage(100),
+ max_memory_for_prepaint_percentage(100),
highp_threshold_min(0),
strict_layer_property_change_checking(false),
- use_map_image(false),
+ use_one_copy(false),
+ use_zero_copy(false),
ignore_root_layer_flings(false),
use_rgba_4444_textures(false),
- always_overscroll(false),
touch_hit_testing(true),
- texture_id_allocation_chunk_size(64) {
+ texture_id_allocation_chunk_size(64),
+ record_full_layer(false) {
}
LayerTreeSettings::~LayerTreeSettings() {}
diff --git a/chromium/cc/trees/layer_tree_settings.h b/chromium/cc/trees/layer_tree_settings.h
index 6ba5da464a2..ba39e3ca3ba 100644
--- a/chromium/cc/trees/layer_tree_settings.h
+++ b/chromium/cc/trees/layer_tree_settings.h
@@ -21,17 +21,25 @@ class CC_EXPORT LayerTreeSettings {
bool impl_side_painting;
bool allow_antialiasing;
bool throttle_frame_production;
- bool begin_impl_frame_scheduling_enabled;
- bool deadline_scheduling_enabled;
+ bool begin_frame_scheduling_enabled;
+ bool main_frame_before_draw_enabled;
+ bool main_frame_before_activation_enabled;
bool using_synchronous_renderer_compositor;
+ bool report_overscroll_only_for_scrollable_axes;
bool per_tile_painting_enabled;
bool partial_swap_enabled;
bool accelerated_animation_enabled;
- bool background_color_instead_of_checkerboard;
- bool show_overdraw_in_tracing;
bool can_use_lcd_text;
+ bool use_distance_field_text;
bool should_clear_root_render_pass;
- bool gpu_rasterization;
+ bool gpu_rasterization_enabled;
+ bool gpu_rasterization_forced;
+ enum RecordingMode {
+ RecordNormally,
+ RecordWithSkRecord,
+ };
+ RecordingMode recording_mode;
+ bool create_low_res_tiling;
enum ScrollbarAnimator {
NoAnimator,
@@ -39,11 +47,10 @@ class CC_EXPORT LayerTreeSettings {
Thinning,
};
ScrollbarAnimator scrollbar_animator;
- int scrollbar_linear_fade_delay_ms;
- int scrollbar_linear_fade_length_ms;
+ int scrollbar_fade_delay_ms;
+ int scrollbar_fade_duration_ms;
SkColor solid_color_scrollbar_color;
bool calculate_top_controls_position;
- bool use_memory_management;
bool timeout_and_draw_when_animation_checkerboards;
int maximum_number_of_failed_draws_before_draw_is_forced_;
bool layer_transforms_should_scale_layer_contents;
@@ -54,22 +61,25 @@ class CC_EXPORT LayerTreeSettings {
float top_controls_hide_threshold;
double refresh_rate;
size_t max_partial_texture_updates;
- size_t num_raster_threads;
gfx::Size default_tile_size;
gfx::Size max_untiled_layer_size;
gfx::Size minimum_occlusion_tracking_size;
bool use_pinch_zoom_scrollbars;
bool use_pinch_virtual_viewport;
size_t max_tiles_for_interest_area;
+ float skewport_target_time_multiplier;
+ int skewport_extrapolation_limit_in_content_pixels;
size_t max_unused_resource_memory_percentage;
+ size_t max_memory_for_prepaint_percentage;
int highp_threshold_min;
bool strict_layer_property_change_checking;
- bool use_map_image;
+ bool use_one_copy;
+ bool use_zero_copy;
bool ignore_root_layer_flings;
bool use_rgba_4444_textures;
- bool always_overscroll;
bool touch_hit_testing;
size_t texture_id_allocation_chunk_size;
+ bool record_full_layer;
LayerTreeDebugState initial_debug_state;
};
diff --git a/chromium/cc/trees/occlusion_tracker.cc b/chromium/cc/trees/occlusion_tracker.cc
index 1c6c8a04e4e..f4a414f6de2 100644
--- a/chromium/cc/trees/occlusion_tracker.cc
+++ b/chromium/cc/trees/occlusion_tracker.cc
@@ -7,7 +7,6 @@
#include <algorithm>
#include "cc/base/math_util.h"
-#include "cc/debug/overdraw_metrics.h"
#include "cc/layers/layer.h"
#include "cc/layers/layer_impl.h"
#include "cc/layers/render_surface.h"
@@ -17,19 +16,18 @@
namespace cc {
-template <typename LayerType, typename RenderSurfaceType>
-OcclusionTrackerBase<LayerType, RenderSurfaceType>::OcclusionTrackerBase(
- gfx::Rect screen_space_clip_rect, bool record_metrics_for_frame)
+template <typename LayerType>
+OcclusionTracker<LayerType>::OcclusionTracker(
+ const gfx::Rect& screen_space_clip_rect)
: screen_space_clip_rect_(screen_space_clip_rect),
- overdraw_metrics_(OverdrawMetrics::Create(record_metrics_for_frame)),
occluding_screen_space_rects_(NULL),
non_occluding_screen_space_rects_(NULL) {}
-template <typename LayerType, typename RenderSurfaceType>
-OcclusionTrackerBase<LayerType, RenderSurfaceType>::~OcclusionTrackerBase() {}
+template <typename LayerType>
+OcclusionTracker<LayerType>::~OcclusionTracker() {}
-template <typename LayerType, typename RenderSurfaceType>
-void OcclusionTrackerBase<LayerType, RenderSurfaceType>::EnterLayer(
+template <typename LayerType>
+void OcclusionTracker<LayerType>::EnterLayer(
const LayerIteratorPosition<LayerType>& layer_iterator) {
LayerType* render_target = layer_iterator.target_render_surface_layer;
@@ -39,8 +37,8 @@ void OcclusionTrackerBase<LayerType, RenderSurfaceType>::EnterLayer(
FinishedRenderTarget(render_target);
}
-template <typename LayerType, typename RenderSurfaceType>
-void OcclusionTrackerBase<LayerType, RenderSurfaceType>::LeaveLayer(
+template <typename LayerType>
+void OcclusionTracker<LayerType>::LeaveLayer(
const LayerIteratorPosition<LayerType>& layer_iterator) {
LayerType* render_target = layer_iterator.target_render_surface_layer;
@@ -54,22 +52,24 @@ void OcclusionTrackerBase<LayerType, RenderSurfaceType>::LeaveLayer(
template <typename RenderSurfaceType>
static gfx::Rect ScreenSpaceClipRectInTargetSurface(
- const RenderSurfaceType* target_surface, gfx::Rect screen_space_clip_rect) {
+ const RenderSurfaceType* target_surface,
+ const gfx::Rect& screen_space_clip_rect) {
gfx::Transform inverse_screen_space_transform(
gfx::Transform::kSkipInitialization);
if (!target_surface->screen_space_transform().GetInverse(
&inverse_screen_space_transform))
return target_surface->content_rect();
- return gfx::ToEnclosingRect(MathUtil::ProjectClippedRect(
- inverse_screen_space_transform, screen_space_clip_rect));
+ return MathUtil::ProjectEnclosingClippedRect(inverse_screen_space_transform,
+ screen_space_clip_rect);
}
template <typename RenderSurfaceType>
-static Region TransformSurfaceOpaqueRegion(const Region& region,
- bool have_clip_rect,
- gfx::Rect clip_rect_in_new_target,
- const gfx::Transform& transform) {
+static Region TransformSurfaceOpaqueRegion(
+ const Region& region,
+ bool have_clip_rect,
+ const gfx::Rect& clip_rect_in_new_target,
+ const gfx::Transform& transform) {
if (region.IsEmpty())
return Region();
@@ -131,7 +131,7 @@ static inline bool SurfaceTransformsToScreenKnown(const RenderSurfaceImpl* rs) {
}
static inline bool LayerIsInUnsorted3dRenderingContext(const Layer* layer) {
- return layer->parent() && layer->parent()->preserves_3d();
+ return layer->Is3dSorted();
}
static inline bool LayerIsInUnsorted3dRenderingContext(const LayerImpl* layer) {
return false;
@@ -143,20 +143,21 @@ static inline bool LayerIsHidden(const LayerType* layer) {
(layer->parent() && LayerIsHidden(layer->parent()));
}
-template <typename LayerType, typename RenderSurfaceType>
-void OcclusionTrackerBase<LayerType, RenderSurfaceType>::EnterRenderTarget(
+template <typename LayerType>
+void OcclusionTracker<LayerType>::EnterRenderTarget(
const LayerType* new_target) {
if (!stack_.empty() && stack_.back().target == new_target)
return;
const LayerType* old_target = NULL;
- const RenderSurfaceType* old_occlusion_immune_ancestor = NULL;
+ const typename LayerType::RenderSurfaceType* old_occlusion_immune_ancestor =
+ NULL;
if (!stack_.empty()) {
old_target = stack_.back().target;
old_occlusion_immune_ancestor =
old_target->render_surface()->nearest_occlusion_immune_ancestor();
}
- const RenderSurfaceType* new_occlusion_immune_ancestor =
+ const typename LayerType::RenderSurfaceType* new_occlusion_immune_ancestor =
new_target->render_surface()->nearest_occlusion_immune_ancestor();
stack_.push_back(StackObject(new_target));
@@ -196,26 +197,27 @@ void OcclusionTrackerBase<LayerType, RenderSurfaceType>::EnterRenderTarget(
inverse_new_target_screen_space_transform,
old_target->render_surface()->screen_space_transform());
stack_[last_index].occlusion_from_outside_target =
- TransformSurfaceOpaqueRegion<RenderSurfaceType>(
+ TransformSurfaceOpaqueRegion<typename LayerType::RenderSurfaceType>(
stack_[last_index - 1].occlusion_from_outside_target,
false,
gfx::Rect(),
old_target_to_new_target_transform);
stack_[last_index].occlusion_from_outside_target.Union(
- TransformSurfaceOpaqueRegion<RenderSurfaceType>(
+ TransformSurfaceOpaqueRegion<typename LayerType::RenderSurfaceType>(
stack_[last_index - 1].occlusion_from_inside_target,
false,
gfx::Rect(),
old_target_to_new_target_transform));
}
-template <typename LayerType, typename RenderSurfaceType>
-void OcclusionTrackerBase<LayerType, RenderSurfaceType>::FinishedRenderTarget(
+template <typename LayerType>
+void OcclusionTracker<LayerType>::FinishedRenderTarget(
const LayerType* finished_target) {
// Make sure we know about the target surface.
EnterRenderTarget(finished_target);
- RenderSurfaceType* surface = finished_target->render_surface();
+ typename LayerType::RenderSurfaceType* surface =
+ finished_target->render_surface();
// Readbacks always happen on render targets so we only need to check
// for readbacks here.
@@ -239,15 +241,15 @@ void OcclusionTrackerBase<LayerType, RenderSurfaceType>::FinishedRenderTarget(
template <typename LayerType>
static void ReduceOcclusionBelowSurface(LayerType* contributing_layer,
- gfx::Rect surface_rect,
+ const gfx::Rect& surface_rect,
const gfx::Transform& surface_transform,
LayerType* render_target,
Region* occlusion_from_inside_target) {
if (surface_rect.IsEmpty())
return;
- gfx::Rect affected_area_in_target = gfx::ToEnclosingRect(
- MathUtil::MapClippedRect(surface_transform, gfx::RectF(surface_rect)));
+ gfx::Rect affected_area_in_target =
+ MathUtil::MapEnclosingClippedRect(surface_transform, surface_rect);
if (contributing_layer->render_surface()->is_clipped()) {
affected_area_in_target.Intersect(
contributing_layer->render_surface()->clip_rect());
@@ -292,8 +294,8 @@ static void ReduceOcclusionBelowSurface(LayerType* contributing_layer,
}
}
-template <typename LayerType, typename RenderSurfaceType>
-void OcclusionTrackerBase<LayerType, RenderSurfaceType>::LeaveToRenderTarget(
+template <typename LayerType>
+void OcclusionTracker<LayerType>::LeaveToRenderTarget(
const LayerType* new_target) {
int last_index = stack_.size() - 1;
bool surface_will_be_at_top_after_pop =
@@ -304,17 +306,18 @@ void OcclusionTrackerBase<LayerType, RenderSurfaceType>::LeaveToRenderTarget(
// merged out as well but needs to be transformed to the new target.
const LayerType* old_target = stack_[last_index].target;
- const RenderSurfaceType* old_surface = old_target->render_surface();
+ const typename LayerType::RenderSurfaceType* old_surface =
+ old_target->render_surface();
Region old_occlusion_from_inside_target_in_new_target =
- TransformSurfaceOpaqueRegion<RenderSurfaceType>(
+ TransformSurfaceOpaqueRegion<typename LayerType::RenderSurfaceType>(
stack_[last_index].occlusion_from_inside_target,
old_surface->is_clipped(),
old_surface->clip_rect(),
old_surface->draw_transform());
if (old_target->has_replica() && !old_target->replica_has_mask()) {
old_occlusion_from_inside_target_in_new_target.Union(
- TransformSurfaceOpaqueRegion<RenderSurfaceType>(
+ TransformSurfaceOpaqueRegion<typename LayerType::RenderSurfaceType>(
stack_[last_index].occlusion_from_inside_target,
old_surface->is_clipped(),
old_surface->clip_rect(),
@@ -322,7 +325,7 @@ void OcclusionTrackerBase<LayerType, RenderSurfaceType>::LeaveToRenderTarget(
}
Region old_occlusion_from_outside_target_in_new_target =
- TransformSurfaceOpaqueRegion<RenderSurfaceType>(
+ TransformSurfaceOpaqueRegion<typename LayerType::RenderSurfaceType>(
stack_[last_index].occlusion_from_outside_target,
false,
gfx::Rect(),
@@ -332,10 +335,11 @@ void OcclusionTrackerBase<LayerType, RenderSurfaceType>::LeaveToRenderTarget(
gfx::Rect unoccluded_replica_rect;
if (old_target->background_filters().HasFilterThatMovesPixels()) {
unoccluded_surface_rect = UnoccludedContributingSurfaceContentRect(
- old_target, false, old_surface->content_rect());
+ old_surface->content_rect(), old_surface->draw_transform());
if (old_target->has_replica()) {
unoccluded_replica_rect = UnoccludedContributingSurfaceContentRect(
- old_target, true, old_surface->content_rect());
+ old_surface->content_rect(),
+ old_surface->replica_draw_transform());
}
}
@@ -391,17 +395,14 @@ void OcclusionTrackerBase<LayerType, RenderSurfaceType>::LeaveToRenderTarget(
&stack_.back().occlusion_from_outside_target);
}
-template <typename LayerType, typename RenderSurfaceType>
-void OcclusionTrackerBase<LayerType, RenderSurfaceType>::
- MarkOccludedBehindLayer(const LayerType* layer) {
+template <typename LayerType>
+void OcclusionTracker<LayerType>::MarkOccludedBehindLayer(
+ const LayerType* layer) {
DCHECK(!stack_.empty());
DCHECK_EQ(layer->render_target(), stack_.back().target);
if (stack_.empty())
return;
- if (!layer->DrawsContent())
- return;
-
if (!LayerOpacityKnown(layer) || layer->draw_opacity() < 1)
return;
@@ -494,19 +495,16 @@ void OcclusionTrackerBase<LayerType, RenderSurfaceType>::
}
}
-template <typename LayerType, typename RenderSurfaceType>
-bool OcclusionTrackerBase<LayerType, RenderSurfaceType>::Occluded(
+template <typename LayerType>
+bool OcclusionTracker<LayerType>::Occluded(
const LayerType* render_target,
- gfx::Rect content_rect,
- const gfx::Transform& draw_transform,
- bool impl_draw_transform_is_unknown) const {
+ const gfx::Rect& content_rect,
+ const gfx::Transform& draw_transform) const {
DCHECK(!stack_.empty());
if (stack_.empty())
return false;
if (content_rect.IsEmpty())
return true;
- if (impl_draw_transform_is_unknown)
- return false;
// For tests with no render target.
if (!render_target)
@@ -527,8 +525,8 @@ bool OcclusionTrackerBase<LayerType, RenderSurfaceType>::Occluded(
// Take the ToEnclosingRect at each step, as we want to contain any unoccluded
// partial pixels in the resulting Rect.
- Region unoccluded_region_in_target_surface = gfx::ToEnclosingRect(
- MathUtil::MapClippedRect(draw_transform, gfx::RectF(content_rect)));
+ Region unoccluded_region_in_target_surface =
+ MathUtil::MapEnclosingClippedRect(draw_transform, content_rect);
unoccluded_region_in_target_surface.Subtract(
stack_.back().occlusion_from_inside_target);
gfx::RectF unoccluded_rect_in_target_surface_without_outside_occlusion =
@@ -542,28 +540,14 @@ bool OcclusionTrackerBase<LayerType, RenderSurfaceType>::Occluded(
return unoccluded_rect_in_target_surface.IsEmpty();
}
-template <typename LayerType, typename RenderSurfaceType>
-gfx::Rect OcclusionTrackerBase<LayerType, RenderSurfaceType>::
- UnoccludedContentRect(
- const LayerType* render_target,
- gfx::Rect content_rect,
- const gfx::Transform& draw_transform,
- bool impl_draw_transform_is_unknown) const {
- DCHECK(!stack_.empty());
+template <typename LayerType>
+gfx::Rect OcclusionTracker<LayerType>::UnoccludedContentRect(
+ const gfx::Rect& content_rect,
+ const gfx::Transform& draw_transform) const {
if (stack_.empty())
return content_rect;
if (content_rect.IsEmpty())
return content_rect;
- if (impl_draw_transform_is_unknown)
- return content_rect;
-
- // For tests with no render target.
- if (!render_target)
- return content_rect;
-
- DCHECK_EQ(render_target->render_target(), render_target);
- DCHECK(render_target->render_surface());
- DCHECK_EQ(render_target, stack_.back().target);
if (stack_.back().occlusion_from_inside_target.IsEmpty() &&
stack_.back().occlusion_from_outside_target.IsEmpty()) {
@@ -576,97 +560,66 @@ gfx::Rect OcclusionTrackerBase<LayerType, RenderSurfaceType>::
// Take the ToEnclosingRect at each step, as we want to contain any unoccluded
// partial pixels in the resulting Rect.
- Region unoccluded_region_in_target_surface = gfx::ToEnclosingRect(
- MathUtil::MapClippedRect(draw_transform, gfx::RectF(content_rect)));
+ Region unoccluded_region_in_target_surface =
+ MathUtil::MapEnclosingClippedRect(draw_transform, content_rect);
unoccluded_region_in_target_surface.Subtract(
stack_.back().occlusion_from_inside_target);
unoccluded_region_in_target_surface.Subtract(
stack_.back().occlusion_from_outside_target);
- gfx::RectF unoccluded_rect_in_target_surface =
+ gfx::Rect unoccluded_rect_in_target_surface =
unoccluded_region_in_target_surface.bounds();
- gfx::Rect unoccluded_rect = gfx::ToEnclosingRect(
- MathUtil::ProjectClippedRect(inverse_draw_transform,
- unoccluded_rect_in_target_surface));
+ gfx::Rect unoccluded_rect = MathUtil::ProjectEnclosingClippedRect(
+ inverse_draw_transform, unoccluded_rect_in_target_surface);
unoccluded_rect.Intersect(content_rect);
return unoccluded_rect;
}
-template <typename LayerType, typename RenderSurfaceType>
-gfx::Rect OcclusionTrackerBase<LayerType, RenderSurfaceType>::
- UnoccludedContributingSurfaceContentRect(
- const LayerType* layer,
- bool for_replica,
- gfx::Rect content_rect) const {
- DCHECK(!stack_.empty());
- // The layer is a contributing render_target so it should have a surface.
- DCHECK(layer->render_surface());
- // The layer is a contributing render_target so its target should be itself.
- DCHECK_EQ(layer->render_target(), layer);
- // The layer should not be the root, else what is is contributing to?
- DCHECK(layer->parent());
- // This should be called while the layer is still considered the current
- // target in the occlusion tracker.
- DCHECK_EQ(layer, stack_.back().target);
-
+template <typename LayerType>
+gfx::Rect OcclusionTracker<LayerType>::UnoccludedContributingSurfaceContentRect(
+ const gfx::Rect& content_rect,
+ const gfx::Transform& draw_transform) const {
if (content_rect.IsEmpty())
return content_rect;
- const RenderSurfaceType* surface = layer->render_surface();
- const LayerType* contributing_surface_render_target =
- layer->parent()->render_target();
+ // A contributing surface doesn't get occluded by things inside its own
+ // surface, so only things outside the surface can occlude it. That occlusion
+ // is found just below the top of the stack (if it exists).
+ bool has_occlusion = stack_.size() > 1;
+ if (!has_occlusion)
+ return content_rect;
+
+ const StackObject& second_last = stack_[stack_.size() - 2];
- if (!SurfaceTransformsToTargetKnown(surface))
+ if (second_last.occlusion_from_inside_target.IsEmpty() &&
+ second_last.occlusion_from_outside_target.IsEmpty())
return content_rect;
- gfx::Transform draw_transform =
- for_replica ? surface->replica_draw_transform()
- : surface->draw_transform();
gfx::Transform inverse_draw_transform(gfx::Transform::kSkipInitialization);
if (!draw_transform.GetInverse(&inverse_draw_transform))
return content_rect;
- // A contributing surface doesn't get occluded by things inside its own
- // surface, so only things outside the surface can occlude it. That occlusion
- // is found just below the top of the stack (if it exists).
- bool has_occlusion = stack_.size() > 1;
-
// Take the ToEnclosingRect at each step, as we want to contain any unoccluded
// partial pixels in the resulting Rect.
- Region unoccluded_region_in_target_surface = gfx::ToEnclosingRect(
- MathUtil::MapClippedRect(draw_transform, gfx::RectF(content_rect)));
- // Layers can't clip across surfaces, so count this as internal occlusion.
- if (surface->is_clipped())
- unoccluded_region_in_target_surface.Intersect(surface->clip_rect());
- if (has_occlusion) {
- const StackObject& second_last = stack_[stack_.size() - 2];
- unoccluded_region_in_target_surface.Subtract(
- second_last.occlusion_from_inside_target);
- unoccluded_region_in_target_surface.Subtract(
- second_last.occlusion_from_outside_target);
- }
-
- // Treat other clipping as occlusion from outside the target surface.
- unoccluded_region_in_target_surface.Intersect(
- contributing_surface_render_target->render_surface()->content_rect());
- unoccluded_region_in_target_surface.Intersect(
- ScreenSpaceClipRectInTargetSurface(
- contributing_surface_render_target->render_surface(),
- screen_space_clip_rect_));
+ Region unoccluded_region_in_target_surface =
+ MathUtil::MapEnclosingClippedRect(draw_transform, content_rect);
+ unoccluded_region_in_target_surface.Subtract(
+ second_last.occlusion_from_inside_target);
+ unoccluded_region_in_target_surface.Subtract(
+ second_last.occlusion_from_outside_target);
- gfx::RectF unoccluded_rect_in_target_surface =
+ gfx::Rect unoccluded_rect_in_target_surface =
unoccluded_region_in_target_surface.bounds();
- gfx::Rect unoccluded_rect = gfx::ToEnclosingRect(
- MathUtil::ProjectClippedRect(inverse_draw_transform,
- unoccluded_rect_in_target_surface));
+ gfx::Rect unoccluded_rect = MathUtil::ProjectEnclosingClippedRect(
+ inverse_draw_transform, unoccluded_rect_in_target_surface);
unoccluded_rect.Intersect(content_rect);
return unoccluded_rect;
}
// Instantiate (and export) templates here for the linker.
-template class OcclusionTrackerBase<Layer, RenderSurface>;
-template class OcclusionTrackerBase<LayerImpl, RenderSurfaceImpl>;
+template class OcclusionTracker<Layer>;
+template class OcclusionTracker<LayerImpl>;
} // namespace cc
diff --git a/chromium/cc/trees/occlusion_tracker.h b/chromium/cc/trees/occlusion_tracker.h
index 68418c7e435..78b992cd1c5 100644
--- a/chromium/cc/trees/occlusion_tracker.h
+++ b/chromium/cc/trees/occlusion_tracker.h
@@ -14,7 +14,6 @@
#include "ui/gfx/rect.h"
namespace cc {
-class OverdrawMetrics;
class LayerImpl;
class RenderSurfaceImpl;
class Layer;
@@ -29,12 +28,11 @@ class RenderSurface;
// be queried via surfaceOccluded() and surfaceUnoccludedContentRect(). Finally,
// once finished with the layer, occlusion behind the layer should be marked by
// calling MarkOccludedBehindLayer().
-template <typename LayerType, typename RenderSurfaceType>
-class CC_EXPORT OcclusionTrackerBase {
+template <typename LayerType>
+class CC_EXPORT OcclusionTracker {
public:
- OcclusionTrackerBase(gfx::Rect screen_space_clip_rect,
- bool record_metrics_for_frame);
- ~OcclusionTrackerBase();
+ explicit OcclusionTracker(const gfx::Rect& screen_space_clip_rect);
+ ~OcclusionTracker();
// Called at the beginning of each step in the LayerIterator's front-to-back
// traversal.
@@ -48,32 +46,22 @@ class CC_EXPORT OcclusionTrackerBase {
// |render_target| is the contributing layer's render target, and
// |draw_transform| and |impl_draw_transform_is_unknown| are relative to that.
bool Occluded(const LayerType* render_target,
- gfx::Rect content_rect,
- const gfx::Transform& draw_transform,
- bool impl_draw_transform_is_unknown) const;
+ const gfx::Rect& content_rect,
+ const gfx::Transform& draw_transform) const;
// Gives an unoccluded sub-rect of |content_rect| in the content space of a
// layer. Used when considering occlusion for a layer that paints/draws
// something. |render_target| is the contributing layer's render target, and
// |draw_transform| and |impl_draw_transform_is_unknown| are relative to that.
- gfx::Rect UnoccludedContentRect(
- const LayerType* render_target,
- gfx::Rect content_rect,
- const gfx::Transform& draw_transform,
- bool impl_draw_transform_is_unknown) const;
+ gfx::Rect UnoccludedContentRect(const gfx::Rect& content_rect,
+ const gfx::Transform& draw_transform) const;
// Gives an unoccluded sub-rect of |content_rect| in the content space of the
// render_target owned by the layer. Used when considering occlusion for a
// contributing surface that is rendering into another target.
gfx::Rect UnoccludedContributingSurfaceContentRect(
- const LayerType* layer,
- bool for_replica,
- gfx::Rect content_rect) const;
-
- // Report operations for recording overdraw metrics.
- OverdrawMetrics* overdraw_metrics() const {
- return overdraw_metrics_.get();
- }
+ const gfx::Rect& content_rect,
+ const gfx::Transform& draw_transform) const;
// Gives the region of the screen that is not occluded by something opaque.
Region ComputeVisibleRegionInScreen() const {
@@ -82,7 +70,7 @@ class CC_EXPORT OcclusionTrackerBase {
stack_.back().occlusion_from_inside_target);
}
- void set_minimum_tracking_size(gfx::Size size) {
+ void set_minimum_tracking_size(const gfx::Size& size) {
minimum_tracking_size_ = size;
}
@@ -142,21 +130,18 @@ class CC_EXPORT OcclusionTrackerBase {
void MarkOccludedBehindLayer(const LayerType* layer);
gfx::Rect screen_space_clip_rect_;
- scoped_ptr<class OverdrawMetrics> overdraw_metrics_;
gfx::Size minimum_tracking_size_;
// This is used for visualizing the occlusion tracking process.
std::vector<gfx::Rect>* occluding_screen_space_rects_;
std::vector<gfx::Rect>* non_occluding_screen_space_rects_;
- DISALLOW_COPY_AND_ASSIGN(OcclusionTrackerBase);
+ DISALLOW_COPY_AND_ASSIGN(OcclusionTracker);
};
-typedef OcclusionTrackerBase<Layer, RenderSurface> OcclusionTracker;
-typedef OcclusionTrackerBase<LayerImpl, RenderSurfaceImpl> OcclusionTrackerImpl;
#if !defined(COMPILER_MSVC)
-extern template class OcclusionTrackerBase<Layer, RenderSurface>;
-extern template class OcclusionTrackerBase<LayerImpl, RenderSurfaceImpl>;
+extern template class OcclusionTracker<Layer>;
+extern template class OcclusionTracker<LayerImpl>;
#endif
} // namespace cc
diff --git a/chromium/cc/trees/occlusion_tracker_perftest.cc b/chromium/cc/trees/occlusion_tracker_perftest.cc
new file mode 100644
index 00000000000..d9130746de7
--- /dev/null
+++ b/chromium/cc/trees/occlusion_tracker_perftest.cc
@@ -0,0 +1,206 @@
+// 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/trees/occlusion_tracker.h"
+
+#include "base/time/time.h"
+#include "cc/debug/lap_timer.h"
+#include "cc/layers/layer_iterator.h"
+#include "cc/layers/solid_color_layer_impl.h"
+#include "cc/test/fake_layer_tree_host_impl_client.h"
+#include "cc/test/fake_output_surface.h"
+#include "cc/test/fake_proxy.h"
+#include "cc/test/fake_rendering_stats_instrumentation.h"
+#include "cc/test/test_shared_bitmap_manager.h"
+#include "cc/trees/layer_tree_host_impl.h"
+#include "cc/trees/layer_tree_impl.h"
+#include "cc/trees/single_thread_proxy.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/perf/perf_test.h"
+
+namespace cc {
+namespace {
+
+static const int kTimeLimitMillis = 2000;
+static const int kWarmupRuns = 5;
+static const int kTimeCheckInterval = 10;
+
+class OcclusionTrackerPerfTest : public testing::Test {
+ public:
+ OcclusionTrackerPerfTest()
+ : timer_(kWarmupRuns,
+ base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
+ kTimeCheckInterval),
+ impl_(&proxy_) {}
+ void CreateHost() {
+ LayerTreeSettings settings;
+ shared_bitmap_manager_.reset(new TestSharedBitmapManager());
+ host_impl_ = LayerTreeHostImpl::Create(
+ settings, &client_, &proxy_, &stats_, shared_bitmap_manager_.get(), 1);
+ host_impl_->InitializeRenderer(
+ FakeOutputSurface::Create3d().PassAs<OutputSurface>());
+
+ scoped_ptr<LayerImpl> root_layer = LayerImpl::Create(active_tree(), 1);
+ active_tree()->SetRootLayer(root_layer.Pass());
+ }
+
+ LayerTreeImpl* active_tree() { return host_impl_->active_tree(); }
+
+ void SetTestName(const std::string& name) { test_name_ = name; }
+
+ void PrintResults() {
+ CHECK(!test_name_.empty()) << "Must SetTestName() before AfterTest().";
+ perf_test::PrintResult("occlusion_tracker_time",
+ "",
+ test_name_,
+ 1000 * timer_.MsPerLap(),
+ "us",
+ true);
+ }
+
+ protected:
+ LapTimer timer_;
+ std::string test_name_;
+ FakeLayerTreeHostImplClient client_;
+ FakeProxy proxy_;
+ DebugScopedSetImplThread impl_;
+ FakeRenderingStatsInstrumentation stats_;
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager_;
+ scoped_ptr<LayerTreeHostImpl> host_impl_;
+};
+
+TEST_F(OcclusionTrackerPerfTest, UnoccludedContentRect_FullyOccluded) {
+ SetTestName("unoccluded_content_rect_fully_occluded");
+
+ gfx::Rect viewport_rect(768, 1038);
+ OcclusionTracker<LayerImpl> tracker(viewport_rect);
+
+ CreateHost();
+ host_impl_->SetViewportSize(viewport_rect.size());
+
+ scoped_ptr<SolidColorLayerImpl> opaque_layer =
+ SolidColorLayerImpl::Create(active_tree(), 2);
+ opaque_layer->SetBackgroundColor(SK_ColorRED);
+ opaque_layer->SetContentsOpaque(true);
+ opaque_layer->SetDrawsContent(true);
+ opaque_layer->SetBounds(viewport_rect.size());
+ opaque_layer->SetContentBounds(viewport_rect.size());
+ active_tree()->root_layer()->AddChild(opaque_layer.PassAs<LayerImpl>());
+
+ active_tree()->UpdateDrawProperties();
+ const LayerImplList& rsll = active_tree()->RenderSurfaceLayerList();
+ ASSERT_EQ(1u, rsll.size());
+ EXPECT_EQ(1u, rsll[0]->render_surface()->layer_list().size());
+
+ LayerIterator<LayerImpl> begin = LayerIterator<LayerImpl>::Begin(&rsll);
+ LayerIterator<LayerImpl> end = LayerIterator<LayerImpl>::End(&rsll);
+
+ LayerIteratorPosition<LayerImpl> pos = begin;
+
+ // The opaque_layer adds occlusion over the whole viewport.
+ tracker.EnterLayer(pos);
+ tracker.LeaveLayer(pos);
+
+ gfx::Transform transform_to_target;
+ transform_to_target.Translate(0, 96);
+
+ do {
+ for (int x = 0; x < viewport_rect.width(); x += 256) {
+ for (int y = 0; y < viewport_rect.height(); y += 256) {
+ gfx::Rect query_content_rect(x, y, 256, 256);
+ gfx::Rect unoccluded = tracker.UnoccludedContentRect(
+ query_content_rect, transform_to_target);
+ // Sanity test that we're not hitting early outs.
+ bool expect_empty =
+ query_content_rect.right() <= viewport_rect.width() &&
+ query_content_rect.bottom() + 96 <= viewport_rect.height();
+ CHECK_EQ(expect_empty, unoccluded.IsEmpty())
+ << query_content_rect.ToString();
+ }
+ }
+
+ timer_.NextLap();
+ } while (!timer_.HasTimeLimitExpired());
+
+ ++begin;
+ LayerIteratorPosition<LayerImpl> next = begin;
+ EXPECT_EQ(active_tree()->root_layer(), next.current_layer);
+
+ ++begin;
+ EXPECT_EQ(end, begin);
+
+ PrintResults();
+}
+
+TEST_F(OcclusionTrackerPerfTest, UnoccludedContentRect_10OpaqueLayers) {
+ static const int kNumOpaqueLayers = 10;
+ SetTestName("unoccluded_content_rect_10_opaque_layers");
+
+ gfx::Rect viewport_rect(768, 1038);
+ OcclusionTracker<LayerImpl> tracker(viewport_rect);
+
+ CreateHost();
+ host_impl_->SetViewportSize(viewport_rect.size());
+
+ for (int i = 0; i < kNumOpaqueLayers; ++i) {
+ scoped_ptr<SolidColorLayerImpl> opaque_layer =
+ SolidColorLayerImpl::Create(active_tree(), 2 + i);
+ opaque_layer->SetBackgroundColor(SK_ColorRED);
+ opaque_layer->SetContentsOpaque(true);
+ opaque_layer->SetDrawsContent(true);
+ opaque_layer->SetBounds(
+ gfx::Size(viewport_rect.width() / 2, viewport_rect.height() / 2));
+ opaque_layer->SetContentBounds(
+ gfx::Size(viewport_rect.width() / 2, viewport_rect.height() / 2));
+ opaque_layer->SetPosition(gfx::Point(i, i));
+ active_tree()->root_layer()->AddChild(opaque_layer.PassAs<LayerImpl>());
+ }
+
+ active_tree()->UpdateDrawProperties();
+ const LayerImplList& rsll = active_tree()->RenderSurfaceLayerList();
+ ASSERT_EQ(1u, rsll.size());
+ EXPECT_EQ(static_cast<size_t>(kNumOpaqueLayers),
+ rsll[0]->render_surface()->layer_list().size());
+
+ LayerIterator<LayerImpl> begin = LayerIterator<LayerImpl>::Begin(&rsll);
+ LayerIterator<LayerImpl> end = LayerIterator<LayerImpl>::End(&rsll);
+
+ // The opaque_layers add occlusion.
+ for (int i = 0; i < kNumOpaqueLayers - 1; ++i) {
+ LayerIteratorPosition<LayerImpl> pos = begin;
+ tracker.EnterLayer(pos);
+ tracker.LeaveLayer(pos);
+ ++begin;
+ }
+ LayerIteratorPosition<LayerImpl> pos = begin;
+ tracker.EnterLayer(pos);
+ tracker.LeaveLayer(pos);
+
+ gfx::Transform transform_to_target;
+ transform_to_target.Translate(0, 96);
+
+ do {
+ for (int x = 0; x < viewport_rect.width(); x += 256) {
+ for (int y = 0; y < viewport_rect.height(); y += 256) {
+ gfx::Rect query_content_rect(x, y, 256, 256);
+ gfx::Rect unoccluded = tracker.UnoccludedContentRect(
+ query_content_rect, transform_to_target);
+ }
+ }
+
+ timer_.NextLap();
+ } while (!timer_.HasTimeLimitExpired());
+
+ ++begin;
+ LayerIteratorPosition<LayerImpl> next = begin;
+ EXPECT_EQ(active_tree()->root_layer(), next.current_layer);
+
+ ++begin;
+ EXPECT_EQ(end, begin);
+
+ PrintResults();
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/trees/occlusion_tracker_unittest.cc b/chromium/cc/trees/occlusion_tracker_unittest.cc
index 89afe4f909b..1a6529bc557 100644
--- a/chromium/cc/trees/occlusion_tracker_unittest.cc
+++ b/chromium/cc/trees/occlusion_tracker_unittest.cc
@@ -6,7 +6,6 @@
#include "cc/animation/layer_animation_controller.h"
#include "cc/base/math_util.h"
-#include "cc/debug/overdraw_metrics.h"
#include "cc/layers/layer.h"
#include "cc/layers/layer_impl.h"
#include "cc/output/copy_output_request.h"
@@ -18,7 +17,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/occlusion_tracker_test_common.h"
+#include "cc/test/test_occlusion_tracker.h"
#include "cc/trees/layer_tree_host_common.h"
#include "cc/trees/single_thread_proxy.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -39,7 +38,7 @@ class TestContentLayer : public Layer {
return gfx::IntersectRects(opaque_contents_rect_, visible_content_rect());
return Layer::VisibleContentOpaqueRegion();
}
- void SetOpaqueContentsRect(gfx::Rect opaque_contents_rect) {
+ void SetOpaqueContentsRect(const gfx::Rect& opaque_contents_rect) {
override_opaque_contents_rect_ = true;
opaque_contents_rect_ = opaque_contents_rect;
}
@@ -63,7 +62,7 @@ class TestContentLayerImpl : public LayerImpl {
return gfx::IntersectRects(opaque_contents_rect_, visible_content_rect());
return LayerImpl::VisibleContentOpaqueRegion();
}
- void SetOpaqueContentsRect(gfx::Rect opaque_contents_rect) {
+ void SetOpaqueContentsRect(const gfx::Rect& opaque_contents_rect) {
override_opaque_contents_rect_ = true;
opaque_contents_rect_ = opaque_contents_rect;
}
@@ -73,45 +72,36 @@ class TestContentLayerImpl : public LayerImpl {
gfx::Rect opaque_contents_rect_;
};
-static inline bool LayerImplDrawTransformIsUnknown(const Layer* layer) {
- return layer->draw_transform_is_animating();
-}
-static inline bool LayerImplDrawTransformIsUnknown(const LayerImpl* layer) {
- return false;
-}
-
-template <typename LayerType, typename RenderSurfaceType>
-class TestOcclusionTrackerWithClip
- : public TestOcclusionTrackerBase<LayerType, RenderSurfaceType> {
+template <typename LayerType>
+class TestOcclusionTrackerWithClip : public TestOcclusionTracker<LayerType> {
public:
- TestOcclusionTrackerWithClip(gfx::Rect viewport_rect,
- bool record_metrics_for_frame)
- : TestOcclusionTrackerBase<LayerType, RenderSurfaceType>(
- viewport_rect,
- record_metrics_for_frame) {}
- explicit TestOcclusionTrackerWithClip(gfx::Rect viewport_rect)
- : TestOcclusionTrackerBase<LayerType, RenderSurfaceType>(viewport_rect,
- false) {}
+ explicit TestOcclusionTrackerWithClip(const gfx::Rect& viewport_rect)
+ : TestOcclusionTracker<LayerType>(viewport_rect) {}
bool OccludedLayer(const LayerType* layer,
- gfx::Rect content_rect) const {
+ const gfx::Rect& content_rect) const {
DCHECK(layer->visible_content_rect().Contains(content_rect));
- return this->Occluded(layer->render_target(),
- content_rect,
- layer->draw_transform(),
- LayerImplDrawTransformIsUnknown(layer));
+ return this->Occluded(
+ layer->render_target(), content_rect, layer->draw_transform());
}
// Gives an unoccluded sub-rect of |content_rect| in the content space of the
// layer. Simple wrapper around UnoccludedContentRect.
gfx::Rect UnoccludedLayerContentRect(const LayerType* layer,
- gfx::Rect content_rect) const {
+ const gfx::Rect& content_rect) const {
DCHECK(layer->visible_content_rect().Contains(content_rect));
- return this->UnoccludedContentRect(
- layer->render_target(),
- content_rect,
- layer->draw_transform(),
- LayerImplDrawTransformIsUnknown(layer));
+ return this->UnoccludedContentRect(content_rect, layer->draw_transform());
+ }
+
+ gfx::Rect UnoccludedSurfaceContentRect(const LayerType* layer,
+ bool for_replica,
+ const gfx::Rect& content_rect) const {
+ typename LayerType::RenderSurfaceType* surface = layer->render_surface();
+ gfx::Transform draw_transform = for_replica
+ ? surface->replica_draw_transform()
+ : surface->draw_transform();
+ return this->UnoccludedContributingSurfaceContentRect(content_rect,
+ draw_transform);
}
};
@@ -122,11 +112,8 @@ struct OcclusionTrackerTestMainThreadTypes {
typedef TestContentLayer ContentLayerType;
typedef scoped_refptr<Layer> LayerPtrType;
typedef scoped_refptr<ContentLayerType> ContentLayerPtrType;
- typedef LayerIterator<Layer,
- RenderSurfaceLayerList,
- RenderSurface,
- LayerIteratorActions::FrontToBack> TestLayerIterator;
- typedef OcclusionTracker OcclusionTrackerType;
+ typedef LayerIterator<Layer> TestLayerIterator;
+ typedef OcclusionTracker<Layer> OcclusionTrackerType;
static LayerPtrType CreateLayer(HostType* host) { return Layer::Create(); }
static ContentLayerPtrType CreateContentLayer(HostType* host) {
@@ -155,11 +142,8 @@ struct OcclusionTrackerTestImplThreadTypes {
typedef TestContentLayerImpl ContentLayerType;
typedef scoped_ptr<LayerImpl> LayerPtrType;
typedef scoped_ptr<ContentLayerType> ContentLayerPtrType;
- typedef LayerIterator<LayerImpl,
- LayerImplList,
- RenderSurfaceImpl,
- LayerIteratorActions::FrontToBack> TestLayerIterator;
- typedef OcclusionTrackerImpl OcclusionTrackerType;
+ typedef LayerIterator<LayerImpl> TestLayerIterator;
+ typedef OcclusionTracker<LayerImpl> OcclusionTrackerType;
static LayerPtrType CreateLayer(HostType* host) {
return LayerImpl::Create(host, next_layer_impl_id++);
@@ -200,8 +184,8 @@ template <typename Types> class OcclusionTrackerTest : public testing::Test {
typename Types::HostType* GetHost();
typename Types::ContentLayerType* CreateRoot(const gfx::Transform& transform,
- gfx::PointF position,
- gfx::Size bounds) {
+ const gfx::PointF& position,
+ const gfx::Size& bounds) {
typename Types::ContentLayerPtrType layer(
Types::CreateContentLayer(GetHost()));
typename Types::ContentLayerType* layer_ptr = layer.get();
@@ -217,8 +201,8 @@ template <typename Types> class OcclusionTrackerTest : public testing::Test {
typename Types::LayerType* CreateLayer(typename Types::LayerType* parent,
const gfx::Transform& transform,
- gfx::PointF position,
- gfx::Size bounds) {
+ const gfx::PointF& position,
+ const gfx::Size& bounds) {
typename Types::LayerPtrType layer(Types::CreateLayer(GetHost()));
typename Types::LayerType* layer_ptr = layer.get();
SetProperties(layer_ptr, transform, position, bounds);
@@ -228,8 +212,8 @@ template <typename Types> class OcclusionTrackerTest : public testing::Test {
typename Types::LayerType* CreateSurface(typename Types::LayerType* parent,
const gfx::Transform& transform,
- gfx::PointF position,
- gfx::Size bounds) {
+ const gfx::PointF& position,
+ const gfx::Size& bounds) {
typename Types::LayerType* layer =
CreateLayer(parent, transform, position, bounds);
layer->SetForceRenderSurface(true);
@@ -239,8 +223,8 @@ template <typename Types> class OcclusionTrackerTest : public testing::Test {
typename Types::ContentLayerType* CreateDrawingLayer(
typename Types::LayerType* parent,
const gfx::Transform& transform,
- gfx::PointF position,
- gfx::Size bounds,
+ const gfx::PointF& position,
+ const gfx::Size& bounds,
bool opaque) {
typename Types::ContentLayerPtrType layer(
Types::CreateContentLayer(GetHost()));
@@ -264,8 +248,8 @@ template <typename Types> class OcclusionTrackerTest : public testing::Test {
typename Types::LayerType* CreateReplicaLayer(
typename Types::LayerType* owning_layer,
const gfx::Transform& transform,
- gfx::PointF position,
- gfx::Size bounds) {
+ const gfx::PointF& position,
+ const gfx::Size& bounds) {
typename Types::ContentLayerPtrType layer(
Types::CreateContentLayer(GetHost()));
typename Types::ContentLayerType* layer_ptr = layer.get();
@@ -276,7 +260,7 @@ template <typename Types> class OcclusionTrackerTest : public testing::Test {
typename Types::LayerType* CreateMaskLayer(
typename Types::LayerType* owning_layer,
- gfx::Size bounds) {
+ const gfx::Size& bounds) {
typename Types::ContentLayerPtrType layer(
Types::CreateContentLayer(GetHost()));
typename Types::ContentLayerType* layer_ptr = layer.get();
@@ -288,8 +272,8 @@ template <typename Types> class OcclusionTrackerTest : public testing::Test {
typename Types::ContentLayerType* CreateDrawingSurface(
typename Types::LayerType* parent,
const gfx::Transform& transform,
- gfx::PointF position,
- gfx::Size bounds,
+ const gfx::PointF& position,
+ const gfx::Size& bounds,
bool opaque) {
typename Types::ContentLayerType* layer =
CreateDrawingLayer(parent, transform, position, bounds, opaque);
@@ -343,14 +327,6 @@ template <typename Types> class OcclusionTrackerTest : public testing::Test {
Types::TestLayerIterator::Begin(render_surface_layer_list_.get());
}
- void SetDrawsContent(LayerImpl* layer_impl, bool draws_content) {
- layer_impl->SetDrawsContent(draws_content);
- }
-
- void SetDrawsContent(Layer* layer, bool draws_content) {
- layer->SetIsDrawable(draws_content);
- }
-
void EnterLayer(typename Types::LayerType* layer,
typename Types::OcclusionTrackerType* occlusion) {
ASSERT_EQ(layer, *layer_iterator_);
@@ -413,26 +389,24 @@ template <typename Types> class OcclusionTrackerTest : public testing::Test {
void SetBaseProperties(typename Types::LayerType* layer,
const gfx::Transform& transform,
- gfx::PointF position,
- gfx::Size bounds) {
+ const gfx::PointF& position,
+ const gfx::Size& bounds) {
layer->SetTransform(transform);
- layer->SetSublayerTransform(gfx::Transform());
- layer->SetAnchorPoint(gfx::PointF());
layer->SetPosition(position);
layer->SetBounds(bounds);
}
void SetProperties(Layer* layer,
const gfx::Transform& transform,
- gfx::PointF position,
- gfx::Size bounds) {
+ const gfx::PointF& position,
+ const gfx::Size& bounds) {
SetBaseProperties(layer, transform, position, bounds);
}
void SetProperties(LayerImpl* layer,
const gfx::Transform& transform,
- gfx::PointF position,
- gfx::Size bounds) {
+ const gfx::PointF& position,
+ const gfx::Size& bounds) {
SetBaseProperties(layer, transform, position, bounds);
layer->SetContentBounds(layer->bounds());
@@ -552,9 +526,8 @@ class OcclusionTrackerTestIdentityTransforms
parent->SetMasksToBounds(true);
this->CalcDrawEtc(root);
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
- gfx::Rect(0, 0, 1000, 1000), false);
+ TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
+ gfx::Rect(0, 0, 1000, 1000));
this->VisitLayer(layer, &occlusion);
this->EnterLayer(parent, &occlusion);
@@ -619,8 +592,7 @@ class OcclusionTrackerTestQuadsMismatchLayer
layer1, layer_transform, gfx::PointF(), gfx::Size(50, 50), true);
this->CalcDrawEtc(parent);
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
+ TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
gfx::Rect(0, 0, 1000, 1000));
this->VisitLayer(layer2, &occlusion);
@@ -638,25 +610,14 @@ class OcclusionTrackerTestQuadsMismatchLayer
gfx::Transform quad_transform;
quad_transform.Translate(30.0, 30.0);
- EXPECT_TRUE(occlusion.UnoccludedContentRect(parent,
- gfx::Rect(0, 0, 10, 10),
- quad_transform,
- false).IsEmpty());
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 10, 10),
- occlusion.UnoccludedContentRect(parent,
- gfx::Rect(0, 0, 10, 10),
- quad_transform,
- true));
+ EXPECT_TRUE(occlusion.UnoccludedContentRect(gfx::Rect(0, 0, 10, 10),
+ quad_transform).IsEmpty());
EXPECT_RECT_EQ(gfx::Rect(40, 40, 10, 10),
- occlusion.UnoccludedContentRect(parent,
- gfx::Rect(40, 40, 10, 10),
- quad_transform,
- false));
+ occlusion.UnoccludedContentRect(gfx::Rect(40, 40, 10, 10),
+ quad_transform));
EXPECT_RECT_EQ(gfx::Rect(40, 30, 5, 10),
- occlusion.UnoccludedContentRect(parent,
- gfx::Rect(35, 30, 10, 10),
- quad_transform,
- false));
+ occlusion.UnoccludedContentRect(gfx::Rect(35, 30, 10, 10),
+ quad_transform));
}
};
@@ -686,8 +647,7 @@ class OcclusionTrackerTestRotatedChild : public OcclusionTrackerTest<Types> {
parent->SetMasksToBounds(true);
this->CalcDrawEtc(root);
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
+ TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
gfx::Rect(0, 0, 1000, 1000));
this->VisitLayer(layer, &occlusion);
@@ -757,8 +717,7 @@ class OcclusionTrackerTestTranslatedChild : public OcclusionTrackerTest<Types> {
parent->SetMasksToBounds(true);
this->CalcDrawEtc(root);
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
+ TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
gfx::Rect(0, 0, 1000, 1000));
this->VisitLayer(layer, &occlusion);
@@ -829,8 +788,7 @@ class OcclusionTrackerTestChildInRotatedChild
true);
this->CalcDrawEtc(parent);
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
+ TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
gfx::Rect(0, 0, 1000, 1000));
this->VisitLayer(layer, &occlusion);
@@ -936,8 +894,7 @@ class OcclusionTrackerTestScaledRenderSurface
true);
this->CalcDrawEtc(parent);
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
+ TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
gfx::Rect(0, 0, 1000, 1000));
this->VisitLayer(occluder, &occlusion);
@@ -1001,8 +958,7 @@ class OcclusionTrackerTestVisitTargetTwoTimes
true);
this->CalcDrawEtc(root);
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
+ TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
gfx::Rect(0, 0, 1000, 1000));
this->VisitLayer(child2, &occlusion);
@@ -1168,11 +1124,10 @@ class OcclusionTrackerTestSurfaceRotatedOffAxis
child, layer_transform, gfx::PointF(), gfx::Size(500, 500), true);
this->CalcDrawEtc(root);
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
+ TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
gfx::Rect(0, 0, 1000, 1000));
- gfx::Rect clipped_layer_in_child = MathUtil::MapClippedRect(
+ gfx::Rect clipped_layer_in_child = MathUtil::MapEnclosingClippedRect(
layer_transform, layer->visible_content_rect());
this->VisitLayer(layer, &occlusion);
@@ -1238,8 +1193,7 @@ class OcclusionTrackerTestSurfaceWithTwoOpaqueChildren
true);
this->CalcDrawEtc(root);
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
+ TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
gfx::Rect(0, 0, 1000, 1000));
this->VisitLayer(layer2, &occlusion);
@@ -1358,8 +1312,7 @@ class OcclusionTrackerTestOverlappingSurfaceSiblings
true);
this->CalcDrawEtc(parent);
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
+ TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
gfx::Rect(0, 0, 1000, 1000));
this->VisitLayer(layer2, &occlusion);
@@ -1372,7 +1325,7 @@ class OcclusionTrackerTestOverlappingSurfaceSiblings
// There is nothing above child2's surface in the z-order.
EXPECT_RECT_EQ(gfx::Rect(-10, 420, 70, 80),
- occlusion.UnoccludedContributingSurfaceContentRect(
+ occlusion.UnoccludedSurfaceContentRect(
child2, false, gfx::Rect(-10, 420, 70, 80)));
this->LeaveContributingSurface(child2, &occlusion);
@@ -1386,7 +1339,7 @@ class OcclusionTrackerTestOverlappingSurfaceSiblings
// child2's contents will occlude child1 below it.
EXPECT_RECT_EQ(gfx::Rect(-10, 430, 10, 70),
- occlusion.UnoccludedContributingSurfaceContentRect(
+ occlusion.UnoccludedSurfaceContentRect(
child1, false, gfx::Rect(-10, 430, 80, 70)));
this->LeaveContributingSurface(child1, &occlusion);
@@ -1479,8 +1432,7 @@ class OcclusionTrackerTestOverlappingSurfaceSiblingsWithTwoTransforms
true);
this->CalcDrawEtc(parent);
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
+ TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
gfx::Rect(0, 0, 1000, 1000));
this->VisitLayer(layer2, &occlusion);
@@ -1496,7 +1448,7 @@ class OcclusionTrackerTestOverlappingSurfaceSiblingsWithTwoTransforms
// There is nothing above child2's surface in the z-order.
EXPECT_RECT_EQ(gfx::Rect(-10, 420, 70, 80),
- occlusion.UnoccludedContributingSurfaceContentRect(
+ occlusion.UnoccludedSurfaceContentRect(
child2, false, gfx::Rect(-10, 420, 70, 80)));
this->LeaveContributingSurface(child2, &occlusion);
@@ -1509,15 +1461,12 @@ class OcclusionTrackerTestOverlappingSurfaceSiblingsWithTwoTransforms
occlusion.occlusion_from_inside_target().ToString());
// child2's contents will occlude child1 below it.
- EXPECT_RECT_EQ(gfx::Rect(420, -20, 80, 90),
- occlusion.UnoccludedContributingSurfaceContentRect(
- child1, false, gfx::Rect(420, -20, 80, 90)));
- EXPECT_RECT_EQ(gfx::Rect(490, -10, 10, 80),
- occlusion.UnoccludedContributingSurfaceContentRect(
- child1, false, gfx::Rect(420, -10, 80, 90)));
- EXPECT_RECT_EQ(gfx::Rect(420, -20, 70, 10),
- occlusion.UnoccludedContributingSurfaceContentRect(
- child1, false, gfx::Rect(420, -20, 70, 90)));
+ EXPECT_EQ(gfx::Rect(20, 30, 80, 70).ToString(),
+ occlusion.occlusion_on_contributing_surface_from_inside_target()
+ .ToString());
+ EXPECT_EQ(gfx::Rect().ToString(),
+ occlusion.occlusion_on_contributing_surface_from_outside_target()
+ .ToString());
this->LeaveContributingSurface(child1, &occlusion);
this->EnterLayer(parent, &occlusion);
@@ -1603,8 +1552,7 @@ class OcclusionTrackerTestFilters : public OcclusionTrackerTest<Types> {
this->CalcDrawEtc(parent);
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
+ TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
gfx::Rect(0, 0, 1000, 1000));
// Opacity layer won't contribute to occlusion.
@@ -1675,8 +1623,7 @@ class OcclusionTrackerTestReplicaDoesOcclude
surface, this->identity_matrix, gfx::PointF(50.f, 50.f), gfx::Size());
this->CalcDrawEtc(parent);
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
+ TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
gfx::Rect(0, 0, 1000, 1000));
this->VisitLayer(surface, &occlusion);
@@ -1717,8 +1664,7 @@ class OcclusionTrackerTestReplicaWithClipping
surface, this->identity_matrix, gfx::PointF(50.f, 50.f), gfx::Size());
this->CalcDrawEtc(parent);
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
+ TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
gfx::Rect(0, 0, 1000, 1000));
this->VisitLayer(surface, &occlusion);
@@ -1758,8 +1704,7 @@ class OcclusionTrackerTestReplicaWithMask : public OcclusionTrackerTest<Types> {
this->CreateMaskLayer(replica, gfx::Size(10, 10));
this->CalcDrawEtc(parent);
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
+ TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
gfx::Rect(0, 0, 1000, 1000));
this->VisitLayer(surface, &occlusion);
@@ -1796,8 +1741,7 @@ class OcclusionTrackerTestOpaqueContentsRegionEmpty
false);
this->CalcDrawEtc(parent);
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
+ TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
gfx::Rect(0, 0, 1000, 1000));
this->EnterLayer(layer, &occlusion);
@@ -1833,8 +1777,7 @@ class OcclusionTrackerTestOpaqueContentsRegionNonEmpty
false);
this->CalcDrawEtc(parent);
{
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
+ TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
gfx::Rect(0, 0, 1000, 1000));
layer->SetOpaqueContentsRect(gfx::Rect(0, 0, 100, 100));
@@ -1853,8 +1796,7 @@ class OcclusionTrackerTestOpaqueContentsRegionNonEmpty
occlusion.OccludedLayer(parent, gfx::Rect(200, 200, 100, 100)));
}
{
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
+ TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
gfx::Rect(0, 0, 1000, 1000));
layer->SetOpaqueContentsRect(gfx::Rect(20, 20, 180, 180));
@@ -1873,8 +1815,7 @@ class OcclusionTrackerTestOpaqueContentsRegionNonEmpty
occlusion.OccludedLayer(parent, gfx::Rect(200, 200, 100, 100)));
}
{
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
+ TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
gfx::Rect(0, 0, 1000, 1000));
layer->SetOpaqueContentsRect(gfx::Rect(150, 150, 100, 100));
@@ -1918,8 +1859,7 @@ class OcclusionTrackerTest3dTransform : public OcclusionTrackerTest<Types> {
true);
this->CalcDrawEtc(parent);
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
+ TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
gfx::Rect(0, 0, 1000, 1000));
this->EnterLayer(layer, &occlusion);
@@ -1962,12 +1902,14 @@ class OcclusionTrackerTestUnsorted3dLayers
gfx::PointF(50.f, 50.f),
gfx::Size(100, 100),
true);
- parent->SetPreserves3d(true);
+ parent->SetShouldFlattenTransform(false);
+ parent->Set3dSortingContextId(1);
+ child1->Set3dSortingContextId(1);
+ child2->Set3dSortingContextId(1);
this->CalcDrawEtc(parent);
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
+ TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
gfx::Rect(0, 0, 1000, 1000));
this->VisitLayer(child2, &occlusion);
EXPECT_TRUE(occlusion.occlusion_from_outside_target().IsEmpty());
@@ -2006,12 +1948,14 @@ class OcclusionTrackerTestPerspectiveTransform
gfx::PointF(100.f, 100.f),
gfx::Size(200, 200),
true);
- container->SetPreserves3d(true);
- layer->SetPreserves3d(true);
+ container->SetShouldFlattenTransform(false);
+ container->Set3dSortingContextId(1);
+ layer->Set3dSortingContextId(1);
+ layer->SetShouldFlattenTransform(false);
+
this->CalcDrawEtc(parent);
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
+ TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
gfx::Rect(0, 0, 1000, 1000));
this->EnterLayer(layer, &occlusion);
@@ -2025,7 +1969,6 @@ class OcclusionTrackerTestPerspectiveTransform
// the occlusion tracker on the main thread. So this test should run on the impl
// thread.
IMPL_THREAD_TEST(OcclusionTrackerTestPerspectiveTransform);
-
template <class Types>
class OcclusionTrackerTestPerspectiveTransformBehindCamera
: public OcclusionTrackerTest<Types> {
@@ -2050,12 +1993,13 @@ class OcclusionTrackerTestPerspectiveTransformBehindCamera
parent, this->identity_matrix, gfx::PointF(), gfx::Size(500, 500));
typename Types::ContentLayerType* layer = this->CreateDrawingLayer(
container, transform, gfx::PointF(), gfx::Size(500, 500), true);
- container->SetPreserves3d(true);
- layer->SetPreserves3d(true);
+ container->SetShouldFlattenTransform(false);
+ container->Set3dSortingContextId(1);
+ layer->SetShouldFlattenTransform(false);
+ layer->Set3dSortingContextId(1);
this->CalcDrawEtc(parent);
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
+ TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
gfx::Rect(0, 0, 1000, 1000));
this->EnterLayer(layer, &occlusion);
@@ -2092,12 +2036,13 @@ class OcclusionTrackerTestLayerBehindCameraDoesNotOcclude
this->identity_matrix, gfx::PointF(), gfx::Size(100, 100));
typename Types::ContentLayerType* layer = this->CreateDrawingLayer(
parent, transform, gfx::PointF(), gfx::Size(100, 100), true);
- parent->SetPreserves3d(true);
- layer->SetPreserves3d(true);
+ parent->SetShouldFlattenTransform(false);
+ parent->Set3dSortingContextId(1);
+ layer->SetShouldFlattenTransform(false);
+ layer->Set3dSortingContextId(1);
this->CalcDrawEtc(parent);
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
+ TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
gfx::Rect(0, 0, 1000, 1000));
// The |layer| is entirely behind the camera and should not occlude.
@@ -2132,12 +2077,13 @@ class OcclusionTrackerTestLargePixelsOccludeInsideClipRect
parent->SetMasksToBounds(true);
typename Types::ContentLayerType* layer = this->CreateDrawingLayer(
parent, transform, gfx::PointF(), gfx::Size(100, 100), true);
- parent->SetPreserves3d(true);
- layer->SetPreserves3d(true);
+ parent->SetShouldFlattenTransform(false);
+ parent->Set3dSortingContextId(1);
+ layer->SetShouldFlattenTransform(false);
+ layer->Set3dSortingContextId(1);
this->CalcDrawEtc(parent);
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
+ TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
gfx::Rect(0, 0, 1000, 1000));
// This is very close to the camera, so pixels in its visible_content_rect()
@@ -2221,8 +2167,7 @@ class OcclusionTrackerTestAnimationOpacity1OnMainThread
EXPECT_FALSE(surface->draw_opacity_is_animating());
EXPECT_TRUE(surface->render_surface()->draw_opacity_is_animating());
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
+ TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
gfx::Rect(0, 0, 1000, 1000));
this->VisitLayer(topmost, &occlusion);
@@ -2264,7 +2209,7 @@ class OcclusionTrackerTestAnimationOpacity1OnMainThread
EXPECT_EQ(gfx::Rect().ToString(),
occlusion.occlusion_from_outside_target().ToString());
EXPECT_RECT_EQ(gfx::Rect(0, 0, 250, 300),
- occlusion.UnoccludedContributingSurfaceContentRect(
+ occlusion.UnoccludedSurfaceContentRect(
surface, false, gfx::Rect(0, 0, 300, 300)));
this->LeaveContributingSurface(surface, &occlusion);
@@ -2342,8 +2287,7 @@ class OcclusionTrackerTestAnimationOpacity0OnMainThread
EXPECT_FALSE(surface->draw_opacity_is_animating());
EXPECT_TRUE(surface->render_surface()->draw_opacity_is_animating());
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
+ TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
gfx::Rect(0, 0, 1000, 1000));
this->VisitLayer(topmost, &occlusion);
@@ -2385,7 +2329,7 @@ class OcclusionTrackerTestAnimationOpacity0OnMainThread
EXPECT_EQ(gfx::Rect().ToString(),
occlusion.occlusion_from_outside_target().ToString());
EXPECT_RECT_EQ(gfx::Rect(0, 0, 250, 300),
- occlusion.UnoccludedContributingSurfaceContentRect(
+ occlusion.UnoccludedSurfaceContentRect(
surface, false, gfx::Rect(0, 0, 300, 300)));
this->LeaveContributingSurface(surface, &occlusion);
@@ -2464,8 +2408,7 @@ class OcclusionTrackerTestAnimationTranslateOnMainThread
EXPECT_TRUE(surface_child->draw_transform_is_animating());
EXPECT_TRUE(surface_child->screen_space_transform_is_animating());
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
+ TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
gfx::Rect(0, 0, 1000, 1000));
this->VisitLayer(surface2, &occlusion);
@@ -2476,84 +2419,63 @@ class OcclusionTrackerTestAnimationTranslateOnMainThread
this->LeaveContributingSurface(surface2, &occlusion);
this->EnterLayer(surface_child2, &occlusion);
-
// surface_child2 is moving in screen space but not relative to its target,
// so occlusion should happen in its target space only. It also means that
// things occluding from outside the target (e.g. surface2) cannot occlude
// this layer.
EXPECT_EQ(gfx::Rect().ToString(),
occlusion.occlusion_from_outside_target().ToString());
-
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 300),
- occlusion.UnoccludedLayerContentRect(
- surface_child2, gfx::Rect(0, 0, 100, 300)));
- EXPECT_FALSE(
- occlusion.OccludedLayer(surface_child, gfx::Rect(0, 0, 50, 300)));
+ EXPECT_EQ(gfx::Rect().ToString(),
+ occlusion.occlusion_from_inside_target().ToString());
this->LeaveLayer(surface_child2, &occlusion);
this->EnterLayer(surface_child, &occlusion);
- EXPECT_FALSE(
- occlusion.OccludedLayer(surface_child, gfx::Rect(0, 0, 100, 300)));
+ // surface_child2 added to the occlusion since it is not moving relative
+ // to its target.
EXPECT_EQ(gfx::Rect().ToString(),
occlusion.occlusion_from_outside_target().ToString());
EXPECT_EQ(gfx::Rect(0, 0, 100, 300).ToString(),
occlusion.occlusion_from_inside_target().ToString());
- EXPECT_RECT_EQ(gfx::Rect(100, 0, 200, 300),
- occlusion.UnoccludedLayerContentRect(
- surface, gfx::Rect(0, 0, 300, 300)));
-
- // The surface_child is occluded by the surface_child2, but is moving
- // relative its target, so it can't be occluded.
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 200, 300),
- occlusion.UnoccludedLayerContentRect(
- surface_child, gfx::Rect(0, 0, 200, 300)));
- EXPECT_FALSE(
- occlusion.OccludedLayer(surface_child, gfx::Rect(0, 0, 50, 300)));
this->LeaveLayer(surface_child, &occlusion);
+ // surface_child is moving relative to its target, so it does not add
+ // occlusion.
+ EXPECT_EQ(gfx::Rect().ToString(),
+ occlusion.occlusion_from_outside_target().ToString());
+ EXPECT_EQ(gfx::Rect(0, 0, 100, 300).ToString(),
+ occlusion.occlusion_from_inside_target().ToString());
+
this->EnterLayer(surface, &occlusion);
- // The surface_child is moving in screen space but not relative to its
- // target, so occlusion should happen from within the target only.
EXPECT_EQ(gfx::Rect().ToString(),
occlusion.occlusion_from_outside_target().ToString());
EXPECT_EQ(gfx::Rect(0, 0, 100, 300).ToString(),
occlusion.occlusion_from_inside_target().ToString());
- EXPECT_RECT_EQ(gfx::Rect(100, 0, 200, 300),
- occlusion.UnoccludedLayerContentRect(
- surface, gfx::Rect(0, 0, 300, 300)));
this->LeaveLayer(surface, &occlusion);
// The surface's owning layer is moving in screen space but not relative to
- // its target, so occlusion should happen within the target only.
+ // its target, so it adds to the occlusion.
EXPECT_EQ(gfx::Rect().ToString(),
occlusion.occlusion_from_outside_target().ToString());
EXPECT_EQ(gfx::Rect(0, 0, 300, 300).ToString(),
occlusion.occlusion_from_inside_target().ToString());
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 0, 0),
- occlusion.UnoccludedLayerContentRect(
- surface, gfx::Rect(0, 0, 300, 300)));
this->EnterContributingSurface(surface, &occlusion);
- // The contributing |surface| is animating so it can't be occluded.
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 300, 300),
- occlusion.UnoccludedContributingSurfaceContentRect(
- surface, false, gfx::Rect(0, 0, 300, 300)));
this->LeaveContributingSurface(surface, &occlusion);
-
- this->EnterLayer(layer, &occlusion);
// The |surface| is moving in the screen and in its target, so all occlusion
- // within the surface is lost when leaving it.
- EXPECT_RECT_EQ(gfx::Rect(50, 0, 250, 300),
- occlusion.UnoccludedLayerContentRect(
- parent, gfx::Rect(0, 0, 300, 300)));
- this->LeaveLayer(layer, &occlusion);
+ // within the surface is lost when leaving it. Only the |surface2| occlusion
+ // is left.
+ EXPECT_EQ(gfx::Rect().ToString(),
+ occlusion.occlusion_from_outside_target().ToString());
+ EXPECT_EQ(gfx::Rect(0, 0, 50, 300).ToString(),
+ occlusion.occlusion_from_inside_target().ToString());
- this->EnterLayer(parent, &occlusion);
+ this->VisitLayer(layer, &occlusion);
// The |layer| is animating in the screen and in its target, so no occlusion
// is added.
- EXPECT_RECT_EQ(gfx::Rect(50, 0, 250, 300),
- occlusion.UnoccludedLayerContentRect(
- parent, gfx::Rect(0, 0, 300, 300)));
+ EXPECT_EQ(gfx::Rect().ToString(),
+ occlusion.occlusion_from_outside_target().ToString());
+ EXPECT_EQ(gfx::Rect(0, 0, 50, 300).ToString(),
+ occlusion.occlusion_from_inside_target().ToString());
}
};
@@ -2586,8 +2508,7 @@ class OcclusionTrackerTestSurfaceOcclusionTranslatesToParent
surface2->SetOpaqueContentsRect(gfx::Rect(0, 0, 200, 200));
this->CalcDrawEtc(parent);
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
+ TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
gfx::Rect(0, 0, 1000, 1000));
this->VisitLayer(surface2, &occlusion);
@@ -2635,8 +2556,7 @@ class OcclusionTrackerTestSurfaceOcclusionTranslatesWithClipping
surface->SetOpaqueContentsRect(gfx::Rect(0, 0, 400, 200));
this->CalcDrawEtc(parent);
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
+ TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
gfx::Rect(0, 0, 1000, 1000));
this->VisitLayer(surface, &occlusion);
@@ -2678,8 +2598,7 @@ class OcclusionTrackerTestReplicaOccluded : public OcclusionTrackerTest<Types> {
true);
this->CalcDrawEtc(parent);
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
+ TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
gfx::Rect(0, 0, 1000, 1000));
// |topmost| occludes the replica, but not the surface itself.
@@ -2702,7 +2621,7 @@ class OcclusionTrackerTestReplicaOccluded : public OcclusionTrackerTest<Types> {
// Surface is not occluded so it shouldn't think it is.
EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100),
- occlusion.UnoccludedContributingSurfaceContentRect(
+ occlusion.UnoccludedSurfaceContentRect(
surface, false, gfx::Rect(0, 0, 100, 100)));
}
};
@@ -2736,8 +2655,7 @@ class OcclusionTrackerTestSurfaceWithReplicaUnoccluded
true);
this->CalcDrawEtc(parent);
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
+ TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
gfx::Rect(0, 0, 1000, 1000));
// |topmost| occludes the surface, but not the entire surface's replica.
@@ -2760,10 +2678,10 @@ class OcclusionTrackerTestSurfaceWithReplicaUnoccluded
// Surface is occluded, but only the top 10px of the replica.
EXPECT_RECT_EQ(gfx::Rect(0, 0, 0, 0),
- occlusion.UnoccludedContributingSurfaceContentRect(
+ occlusion.UnoccludedSurfaceContentRect(
surface, false, gfx::Rect(0, 0, 100, 100)));
EXPECT_RECT_EQ(gfx::Rect(0, 10, 100, 90),
- occlusion.UnoccludedContributingSurfaceContentRect(
+ occlusion.UnoccludedSurfaceContentRect(
surface, true, gfx::Rect(0, 0, 100, 100)));
}
};
@@ -2800,8 +2718,7 @@ class OcclusionTrackerTestSurfaceAndReplicaOccludedDifferently
true);
this->CalcDrawEtc(parent);
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
+ TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
gfx::Rect(0, 0, 1000, 1000));
// These occlude the surface and replica differently, so we can test each
@@ -2827,10 +2744,10 @@ class OcclusionTrackerTestSurfaceAndReplicaOccludedDifferently
// Surface and replica are occluded different amounts.
EXPECT_RECT_EQ(gfx::Rect(40, 0, 60, 100),
- occlusion.UnoccludedContributingSurfaceContentRect(
+ occlusion.UnoccludedSurfaceContentRect(
surface, false, gfx::Rect(0, 0, 100, 100)));
EXPECT_RECT_EQ(gfx::Rect(50, 0, 50, 100),
- occlusion.UnoccludedContributingSurfaceContentRect(
+ occlusion.UnoccludedSurfaceContentRect(
surface, true, gfx::Rect(0, 0, 100, 100)));
}
};
@@ -2866,8 +2783,7 @@ class OcclusionTrackerTestSurfaceChildOfSurface
parent, this->identity_matrix, gfx::PointF(), gfx::Size(100, 50), true);
this->CalcDrawEtc(parent);
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
+ TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
gfx::Rect(-100, -100, 1000, 1000));
// |topmost| occludes everything partially so we know occlusion is happening
@@ -2899,7 +2815,7 @@ class OcclusionTrackerTestSurfaceChildOfSurface
// surface. Make sure the unoccluded rect does not get clipped away
// inappropriately.
EXPECT_RECT_EQ(gfx::Rect(0, 40, 100, 10),
- occlusion.UnoccludedContributingSurfaceContentRect(
+ occlusion.UnoccludedSurfaceContentRect(
surface_child, false, gfx::Rect(0, 0, 100, 50)));
this->LeaveContributingSurface(surface_child, &occlusion);
@@ -2915,7 +2831,7 @@ class OcclusionTrackerTestSurfaceChildOfSurface
this->EnterContributingSurface(surface, &occlusion);
// The surface's parent does have a clip rect as it is the root layer.
EXPECT_RECT_EQ(gfx::Rect(0, 50, 100, 50),
- occlusion.UnoccludedContributingSurfaceContentRect(
+ occlusion.UnoccludedSurfaceContentRect(
surface, false, gfx::Rect(0, 0, 100, 100)));
}
};
@@ -2923,144 +2839,6 @@ class OcclusionTrackerTestSurfaceChildOfSurface
ALL_OCCLUSIONTRACKER_TEST(OcclusionTrackerTestSurfaceChildOfSurface);
template <class Types>
-class OcclusionTrackerTestTopmostSurfaceIsClippedToViewport
- : public OcclusionTrackerTest<Types> {
- protected:
- explicit OcclusionTrackerTestTopmostSurfaceIsClippedToViewport(
- bool opaque_layers)
- : OcclusionTrackerTest<Types>(opaque_layers) {}
- void RunMyTest() {
- // This test verifies that the top-most surface is considered occluded
- // outside of its target's clip rect and outside the viewport rect.
-
- typename Types::ContentLayerType* parent = this->CreateRoot(
- this->identity_matrix, gfx::PointF(), gfx::Size(100, 200));
- typename Types::LayerType* surface =
- this->CreateDrawingSurface(parent,
- this->identity_matrix,
- gfx::PointF(),
- gfx::Size(100, 300),
- true);
- this->CalcDrawEtc(parent);
- {
- // Make a viewport rect that is larger than the root layer.
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
- gfx::Rect(0, 0, 1000, 1000));
-
- this->VisitLayer(surface, &occlusion);
-
- // The root layer always has a clip rect. So the parent of |surface| has a
- // clip rect giving the surface itself a clip rect.
- this->EnterContributingSurface(surface, &occlusion);
- // Make sure the parent's clip rect clips the unoccluded region of the
- // child surface.
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 200),
- occlusion.UnoccludedContributingSurfaceContentRect(
- surface, false, gfx::Rect(0, 0, 100, 300)));
- }
- this->ResetLayerIterator();
- {
- // Make a viewport rect that is smaller than the root layer.
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
- gfx::Rect(0, 0, 100, 100));
-
- this->VisitLayer(surface, &occlusion);
-
- // The root layer always has a clip rect. So the parent of |surface| has a
- // clip rect giving the surface itself a clip rect.
- this->EnterContributingSurface(surface, &occlusion);
- // Make sure the viewport rect clips the unoccluded region of the child
- // surface.
- EXPECT_RECT_EQ(gfx::Rect(0, 0, 100, 100),
- occlusion.UnoccludedContributingSurfaceContentRect(
- surface, false, gfx::Rect(0, 0, 100, 300)));
- }
- }
-};
-
-ALL_OCCLUSIONTRACKER_TEST(
- OcclusionTrackerTestTopmostSurfaceIsClippedToViewport);
-
-template <class Types>
-class OcclusionTrackerTestSurfaceChildOfClippingSurface
- : public OcclusionTrackerTest<Types> {
- protected:
- explicit OcclusionTrackerTestSurfaceChildOfClippingSurface(bool opaque_layers)
- : OcclusionTrackerTest<Types>(opaque_layers) {}
- void RunMyTest() {
- // This test verifies that the surface cliprect does not end up empty and
- // clip away the entire unoccluded rect.
-
- typename Types::ContentLayerType* parent = this->CreateRoot(
- this->identity_matrix, gfx::PointF(), gfx::Size(80, 200));
- parent->SetMasksToBounds(true);
- typename Types::LayerType* surface =
- this->CreateDrawingSurface(parent,
- this->identity_matrix,
- gfx::PointF(),
- gfx::Size(100, 100),
- true);
- typename Types::LayerType* surface_child =
- this->CreateDrawingSurface(surface,
- this->identity_matrix,
- gfx::PointF(),
- gfx::Size(100, 100),
- false);
- typename Types::LayerType* topmost = this->CreateDrawingLayer(
- parent, this->identity_matrix, gfx::PointF(), gfx::Size(100, 50), true);
- this->CalcDrawEtc(parent);
-
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
- gfx::Rect(0, 0, 1000, 1000));
-
- // |topmost| occludes everything partially so we know occlusion is happening
- // at all.
- this->VisitLayer(topmost, &occlusion);
-
- EXPECT_EQ(gfx::Rect().ToString(),
- occlusion.occlusion_from_outside_target().ToString());
- EXPECT_EQ(gfx::Rect(0, 0, 80, 50).ToString(),
- occlusion.occlusion_from_inside_target().ToString());
-
- // surface_child is not opaque and does not occlude, so we have a non-empty
- // unoccluded area on surface.
- this->VisitLayer(surface_child, &occlusion);
-
- EXPECT_EQ(gfx::Rect(0, 0, 80, 50).ToString(),
- occlusion.occlusion_from_outside_target().ToString());
- EXPECT_EQ(gfx::Rect(0, 0, 0, 0).ToString(),
- occlusion.occlusion_from_inside_target().ToString());
-
- // The root layer always has a clip rect. So the parent of |surface| has a
- // clip rect. However, the owning layer for |surface| does not mask to
- // bounds, so it doesn't have a clip rect of its own. Thus the parent of
- // |surface_child| exercises different code paths as its parent does not
- // have a clip rect.
-
- this->EnterContributingSurface(surface_child, &occlusion);
- // The surface_child's parent does not have a clip rect as it owns a render
- // surface.
- EXPECT_EQ(
- gfx::Rect(0, 50, 80, 50).ToString(),
- occlusion.UnoccludedContributingSurfaceContentRect(
- surface_child, false, gfx::Rect(0, 0, 100, 100)).ToString());
- this->LeaveContributingSurface(surface_child, &occlusion);
-
- this->VisitLayer(surface, &occlusion);
- this->EnterContributingSurface(surface, &occlusion);
- // The surface's parent does have a clip rect as it is the root layer.
- EXPECT_EQ(gfx::Rect(0, 50, 80, 50).ToString(),
- occlusion.UnoccludedContributingSurfaceContentRect(
- surface, false, gfx::Rect(0, 0, 100, 100)).ToString());
- }
-};
-
-ALL_OCCLUSIONTRACKER_TEST(OcclusionTrackerTestSurfaceChildOfClippingSurface);
-
-template <class Types>
class OcclusionTrackerTestDontOccludePixelsNeededForBackgroundFilter
: public OcclusionTrackerTest<Types> {
protected:
@@ -3116,8 +2894,7 @@ class OcclusionTrackerTestDontOccludePixelsNeededForBackgroundFilter
this->CalcDrawEtc(parent);
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
+ TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
gfx::Rect(0, 0, 1000, 1000));
// These layers occlude pixels directly beside the filtered_surface. Because
@@ -3260,8 +3037,7 @@ class OcclusionTrackerTestTwoBackgroundFiltersReduceOcclusionTwice
this->CalcDrawEtc(root);
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
+ TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
gfx::Rect(0, 0, 1000, 1000));
this->VisitLayer(occluding_layer_above, &occlusion);
@@ -3341,8 +3117,7 @@ class OcclusionTrackerTestDontReduceOcclusionBelowBackgroundFilter
this->CalcDrawEtc(parent);
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
+ TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
gfx::Rect(0, 0, 1000, 1000));
// The surface has a background blur, so it blurs non-opaque pixels below
@@ -3409,8 +3184,7 @@ class OcclusionTrackerTestDontReduceOcclusionIfBackgroundFilterIsOccluded
this->CalcDrawEtc(parent);
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
+ TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
gfx::Rect(0, 0, 1000, 1000));
this->VisitLayer(occluding_layer, &occlusion);
@@ -3511,8 +3285,7 @@ class OcclusionTrackerTestReduceOcclusionWhenBackgroundFilterIsPartiallyOccluded
this->CalcDrawEtc(parent);
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
+ TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
gfx::Rect(0, 0, 1000, 1000));
this->VisitLayer(beside_replica_layer, &occlusion);
@@ -3585,8 +3358,7 @@ class OcclusionTrackerTestMinimumTrackingSize
true);
this->CalcDrawEtc(parent);
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
+ TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
gfx::Rect(0, 0, 1000, 1000));
occlusion.set_minimum_tracking_size(tracking_size);
@@ -3633,8 +3405,7 @@ class OcclusionTrackerTestScaledLayerIsClipped
scale, this->identity_matrix, gfx::PointF(), gfx::Size(500, 500), true);
this->CalcDrawEtc(parent);
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
+ TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
gfx::Rect(0, 0, 1000, 1000));
this->VisitLayer(scaled, &occlusion);
@@ -3673,8 +3444,7 @@ class OcclusionTrackerTestScaledLayerInSurfaceIsClipped
scale, this->identity_matrix, gfx::PointF(), gfx::Size(500, 500), true);
this->CalcDrawEtc(parent);
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
+ TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
gfx::Rect(0, 0, 1000, 1000));
this->VisitLayer(scaled, &occlusion);
@@ -3714,8 +3484,7 @@ class OcclusionTrackerTestCopyRequestDoesOcclude
true);
this->CalcDrawEtc(root);
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
+ TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
gfx::Rect(0, 0, 1000, 1000));
this->VisitLayer(copy_child, &occlusion);
@@ -3763,8 +3532,7 @@ class OcclusionTrackerTestHiddenCopyRequestDoesNotOcclude
this->CalcDrawEtc(root);
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
+ TestOcclusionTrackerWithClip<typename Types::LayerType> occlusion(
gfx::Rect(0, 0, 1000, 1000));
this->VisitLayer(copy_child, &occlusion);
@@ -3786,37 +3554,5 @@ class OcclusionTrackerTestHiddenCopyRequestDoesNotOcclude
ALL_OCCLUSIONTRACKER_TEST(OcclusionTrackerTestHiddenCopyRequestDoesNotOcclude)
-template <class Types>
-class OcclusionTrackerTestEmptyEventLayerDoesNotOcclude
- : public OcclusionTrackerTest<Types> {
- protected:
- explicit OcclusionTrackerTestEmptyEventLayerDoesNotOcclude(
- bool opaque_layers)
- : OcclusionTrackerTest<Types>(opaque_layers) {}
- void RunMyTest() {
- typename Types::ContentLayerType* root = this->CreateRoot(
- this->identity_matrix, gfx::Point(), gfx::Size(400, 400));
- typename Types::ContentLayerType* empty_layer = this->CreateDrawingLayer(
- root, this->identity_matrix, gfx::Point(), gfx::Size(200, 200), true);
- this->SetDrawsContent(empty_layer, false);
- empty_layer->SetTouchEventHandlerRegion(gfx::Rect(10, 10, 10, 10));
-
- this->CalcDrawEtc(root);
-
- TestOcclusionTrackerWithClip<typename Types::LayerType,
- typename Types::RenderSurfaceType> occlusion(
- gfx::Rect(0, 0, 1000, 1000), false);
-
- this->VisitLayer(empty_layer, &occlusion);
-
- EXPECT_EQ(gfx::Rect().ToString(),
- occlusion.occlusion_from_outside_target().ToString());
- EXPECT_EQ(gfx::Rect().ToString(),
- occlusion.occlusion_from_inside_target().ToString());
- }
-};
-
-ALL_OCCLUSIONTRACKER_TEST(OcclusionTrackerTestEmptyEventLayerDoesNotOcclude)
-
} // namespace
} // namespace cc
diff --git a/chromium/cc/trees/proxy.cc b/chromium/cc/trees/proxy.cc
index 9315f31f56a..a8f7b26fb04 100644
--- a/chromium/cc/trees/proxy.cc
+++ b/chromium/cc/trees/proxy.cc
@@ -20,18 +20,22 @@ base::SingleThreadTaskRunner* Proxy::ImplThreadTaskRunner() const {
}
bool Proxy::IsMainThread() const {
-#ifndef NDEBUG
- DCHECK(main_task_runner_.get());
+#if DCHECK_IS_ON
if (impl_thread_is_overridden_)
return false;
- return main_task_runner_->BelongsToCurrentThread();
+
+ bool is_main_thread = base::PlatformThread::CurrentId() == main_thread_id_;
+ if (is_main_thread && main_task_runner_.get()) {
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
+ }
+ return is_main_thread;
#else
return true;
#endif
}
bool Proxy::IsImplThread() const {
-#ifndef NDEBUG
+#if DCHECK_IS_ON
if (impl_thread_is_overridden_)
return true;
if (!impl_task_runner_.get())
@@ -42,42 +46,43 @@ bool Proxy::IsImplThread() const {
#endif
}
-#ifndef NDEBUG
+#if DCHECK_IS_ON
void Proxy::SetCurrentThreadIsImplThread(bool is_impl_thread) {
impl_thread_is_overridden_ = is_impl_thread;
}
#endif
bool Proxy::IsMainThreadBlocked() const {
-#ifndef NDEBUG
+#if DCHECK_IS_ON
return is_main_thread_blocked_;
#else
return true;
#endif
}
-#ifndef NDEBUG
+#if DCHECK_IS_ON
void Proxy::SetMainThreadBlocked(bool is_main_thread_blocked) {
is_main_thread_blocked_ = is_main_thread_blocked;
}
#endif
-Proxy::Proxy(
- scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner)
+Proxy::Proxy(scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner)
: main_task_runner_(base::MessageLoopProxy::current()),
-#ifdef NDEBUG
- impl_task_runner_(impl_task_runner) {}
+#if !DCHECK_IS_ON
+ impl_task_runner_(impl_task_runner) {
#else
impl_task_runner_(impl_task_runner),
+ main_thread_id_(base::PlatformThread::CurrentId()),
impl_thread_is_overridden_(false),
- is_main_thread_blocked_(false) {}
+ is_main_thread_blocked_(false) {
#endif
+}
Proxy::~Proxy() {
DCHECK(IsMainThread());
}
-scoped_ptr<base::Value> Proxy::SchedulerStateAsValueForTesting() {
+scoped_ptr<base::Value> Proxy::SchedulerAsValueForTesting() {
return make_scoped_ptr(base::Value::CreateNullValue());
}
diff --git a/chromium/cc/trees/proxy.h b/chromium/cc/trees/proxy.h
index 69975a6dd7f..4066513773c 100644
--- a/chromium/cc/trees/proxy.h
+++ b/chromium/cc/trees/proxy.h
@@ -11,6 +11,7 @@
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
+#include "base/threading/platform_thread.h"
#include "base/time/time.h"
#include "base/values.h"
#include "cc/base/cc_export.h"
@@ -24,6 +25,7 @@ class Vector2d;
namespace cc {
+class LayerTreeDebugState;
class OutputSurface;
struct RendererCapabilities;
@@ -39,15 +41,13 @@ class CC_EXPORT Proxy {
bool IsMainThread() const;
bool IsImplThread() const;
bool IsMainThreadBlocked() const;
-#ifndef NDEBUG
+#if DCHECK_IS_ON
void SetMainThreadBlocked(bool is_main_thread_blocked);
void SetCurrentThreadIsImplThread(bool is_impl_thread);
#endif
virtual ~Proxy();
- virtual bool CompositeAndReadback(void* pixels, gfx::Rect rect) = 0;
-
virtual void FinishAllRendering() = 0;
virtual bool IsStarted() const = 0;
@@ -58,17 +58,12 @@ class CC_EXPORT Proxy {
virtual void SetVisible(bool visible) = 0;
- // Attempts to recreate the context and renderer synchronously after the
- // output surface is lost. Calls
- // LayerTreeHost::OnCreateAndInitializeOutputSurfaceAttempted with the result.
- virtual void CreateAndInitializeOutputSurface() = 0;
-
virtual const RendererCapabilities& GetRendererCapabilities() const = 0;
virtual void SetNeedsAnimate() = 0;
virtual void SetNeedsUpdateLayers() = 0;
virtual void SetNeedsCommit() = 0;
- virtual void SetNeedsRedraw(gfx::Rect damage_rect) = 0;
+ virtual void SetNeedsRedraw(const gfx::Rect& damage_rect) = 0;
virtual void SetNextCommitWaitsForActivation() = 0;
virtual void NotifyInputThrottledUntilCommit() = 0;
@@ -84,7 +79,7 @@ class CC_EXPORT Proxy {
virtual bool BeginMainFrameRequested() const = 0;
// Must be called before using the proxy.
- virtual void Start(scoped_ptr<OutputSurface> first_output_surface) = 0;
+ virtual void Start() = 0;
virtual void Stop() = 0; // Must be called before deleting the proxy.
// Forces 3D commands on all contexts to wait for all previous SwapBuffers
@@ -94,13 +89,13 @@ class CC_EXPORT Proxy {
// Maximum number of sub-region texture updates supported for each commit.
virtual size_t MaxPartialTextureUpdates() const = 0;
- virtual void AcquireLayerTextures() = 0;
-
virtual scoped_ptr<base::Value> AsValue() const = 0;
+ virtual void SetDebugState(const LayerTreeDebugState& debug_state) = 0;
+
// Testing hooks
virtual bool CommitPendingForTesting() = 0;
- virtual scoped_ptr<base::Value> SchedulerStateAsValueForTesting();
+ virtual scoped_ptr<base::Value> SchedulerAsValueForTesting();
protected:
explicit Proxy(
@@ -112,7 +107,8 @@ class CC_EXPORT Proxy {
private:
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner_;
-#ifndef NDEBUG
+#if DCHECK_IS_ON
+ const base::PlatformThreadId main_thread_id_;
bool impl_thread_is_overridden_;
bool is_main_thread_blocked_;
#endif
@@ -120,7 +116,7 @@ class CC_EXPORT Proxy {
DISALLOW_COPY_AND_ASSIGN(Proxy);
};
-#ifndef NDEBUG
+#if DCHECK_IS_ON
class DebugScopedSetMainThreadBlocked {
public:
explicit DebugScopedSetMainThreadBlocked(Proxy* proxy) : proxy_(proxy) {
diff --git a/chromium/cc/trees/proxy_timing_history.cc b/chromium/cc/trees/proxy_timing_history.cc
new file mode 100644
index 00000000000..e920f285697
--- /dev/null
+++ b/chromium/cc/trees/proxy_timing_history.cc
@@ -0,0 +1,66 @@
+// 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/trees/proxy_timing_history.h"
+
+const size_t kDurationHistorySize = 60;
+const double kCommitAndActivationDurationEstimationPercentile = 50.0;
+const double kDrawDurationEstimationPercentile = 100.0;
+const int kDrawDurationEstimatePaddingInMicroseconds = 0;
+
+namespace cc {
+
+ProxyTimingHistory::ProxyTimingHistory()
+ : draw_duration_history_(kDurationHistorySize),
+ begin_main_frame_to_commit_duration_history_(kDurationHistorySize),
+ commit_to_activate_duration_history_(kDurationHistorySize) {}
+
+ProxyTimingHistory::~ProxyTimingHistory() {}
+
+base::TimeDelta ProxyTimingHistory::DrawDurationEstimate() const {
+ base::TimeDelta historical_estimate =
+ draw_duration_history_.Percentile(kDrawDurationEstimationPercentile);
+ base::TimeDelta padding = base::TimeDelta::FromMicroseconds(
+ kDrawDurationEstimatePaddingInMicroseconds);
+ return historical_estimate + padding;
+}
+
+base::TimeDelta ProxyTimingHistory::BeginMainFrameToCommitDurationEstimate()
+ const {
+ return begin_main_frame_to_commit_duration_history_.Percentile(
+ kCommitAndActivationDurationEstimationPercentile);
+}
+
+base::TimeDelta ProxyTimingHistory::CommitToActivateDurationEstimate() const {
+ return commit_to_activate_duration_history_.Percentile(
+ kCommitAndActivationDurationEstimationPercentile);
+}
+
+void ProxyTimingHistory::DidBeginMainFrame() {
+ begin_main_frame_sent_time_ = base::TimeTicks::HighResNow();
+}
+
+void ProxyTimingHistory::DidCommit() {
+ commit_complete_time_ = base::TimeTicks::HighResNow();
+ begin_main_frame_to_commit_duration_history_.InsertSample(
+ commit_complete_time_ - begin_main_frame_sent_time_);
+}
+
+void ProxyTimingHistory::DidActivatePendingTree() {
+ commit_to_activate_duration_history_.InsertSample(
+ base::TimeTicks::HighResNow() - commit_complete_time_);
+}
+
+void ProxyTimingHistory::DidStartDrawing() {
+ start_draw_time_ = base::TimeTicks::HighResNow();
+}
+
+base::TimeDelta ProxyTimingHistory::DidFinishDrawing() {
+ base::TimeDelta draw_duration =
+ base::TimeTicks::HighResNow() - start_draw_time_;
+ draw_duration_history_.InsertSample(draw_duration);
+ return draw_duration;
+}
+
+} // namespace cc
diff --git a/chromium/cc/trees/proxy_timing_history.h b/chromium/cc/trees/proxy_timing_history.h
new file mode 100644
index 00000000000..01a92d93a03
--- /dev/null
+++ b/chromium/cc/trees/proxy_timing_history.h
@@ -0,0 +1,40 @@
+// 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_TREES_PROXY_TIMING_HISTORY_H_
+#define CC_TREES_PROXY_TIMING_HISTORY_H_
+
+#include "cc/base/rolling_time_delta_history.h"
+
+namespace cc {
+
+class ProxyTimingHistory {
+ public:
+ ProxyTimingHistory();
+ ~ProxyTimingHistory();
+
+ base::TimeDelta DrawDurationEstimate() const;
+ base::TimeDelta BeginMainFrameToCommitDurationEstimate() const;
+ base::TimeDelta CommitToActivateDurationEstimate() const;
+
+ void DidBeginMainFrame();
+ void DidCommit();
+ void DidActivatePendingTree();
+ void DidStartDrawing();
+ // Returns draw duration.
+ base::TimeDelta DidFinishDrawing();
+
+ protected:
+ RollingTimeDeltaHistory draw_duration_history_;
+ RollingTimeDeltaHistory begin_main_frame_to_commit_duration_history_;
+ RollingTimeDeltaHistory commit_to_activate_duration_history_;
+
+ base::TimeTicks begin_main_frame_sent_time_;
+ base::TimeTicks commit_complete_time_;
+ base::TimeTicks start_draw_time_;
+};
+
+} // namespace cc
+
+#endif // CC_TREES_PROXY_TIMING_HISTORY_H_
diff --git a/chromium/cc/trees/quad_culler.cc b/chromium/cc/trees/quad_culler.cc
deleted file mode 100644
index 2fc8aaa6caa..00000000000
--- a/chromium/cc/trees/quad_culler.cc
+++ /dev/null
@@ -1,108 +0,0 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/trees/quad_culler.h"
-
-#include "cc/debug/debug_colors.h"
-#include "cc/debug/overdraw_metrics.h"
-#include "cc/layers/append_quads_data.h"
-#include "cc/layers/layer_impl.h"
-#include "cc/quads/debug_border_draw_quad.h"
-#include "cc/quads/render_pass.h"
-#include "cc/trees/occlusion_tracker.h"
-#include "third_party/skia/include/core/SkColor.h"
-#include "ui/gfx/transform.h"
-
-namespace cc {
-
-QuadCuller::QuadCuller(QuadList* quad_list,
- SharedQuadStateList* shared_quad_state_list,
- const LayerImpl* layer,
- const OcclusionTrackerImpl& occlusion_tracker,
- bool show_culling_with_debug_border_quads,
- bool for_surface)
- : quad_list_(quad_list),
- shared_quad_state_list_(shared_quad_state_list),
- layer_(layer),
- occlusion_tracker_(occlusion_tracker),
- current_shared_quad_state_(NULL),
- show_culling_with_debug_border_quads_(
- show_culling_with_debug_border_quads),
- for_surface_(for_surface) {}
-
-SharedQuadState* QuadCuller::UseSharedQuadState(
- scoped_ptr<SharedQuadState> shared_quad_state) {
- // TODO(danakj): If all quads are culled for the shared_quad_state, we can
- // drop it from the list.
- current_shared_quad_state_ = shared_quad_state.get();
- shared_quad_state_list_->push_back(shared_quad_state.Pass());
- return current_shared_quad_state_;
-}
-
-static inline bool AppendQuadInternal(
- scoped_ptr<DrawQuad> draw_quad,
- gfx::Rect culled_rect,
- QuadList* quad_list,
- const OcclusionTrackerImpl& occlusion_tracker,
- const LayerImpl* layer,
- bool create_debug_border_quads) {
- bool keep_quad = !culled_rect.IsEmpty();
- if (keep_quad)
- draw_quad->visible_rect = culled_rect;
-
- occlusion_tracker.overdraw_metrics()->DidCullForDrawing(
- draw_quad->quadTransform(), draw_quad->rect, culled_rect);
- gfx::Rect opaque_draw_rect =
- draw_quad->opacity() == 1.0f ? draw_quad->opaque_rect : gfx::Rect();
- occlusion_tracker.overdraw_metrics()->
- DidDraw(draw_quad->quadTransform(), culled_rect, opaque_draw_rect);
-
- if (keep_quad) {
- if (create_debug_border_quads && !draw_quad->IsDebugQuad() &&
- draw_quad->visible_rect != draw_quad->rect) {
- SkColor color = DebugColors::CulledTileBorderColor();
- float width = DebugColors::CulledTileBorderWidth(
- layer ? layer->layer_tree_impl() : NULL);
- scoped_ptr<DebugBorderDrawQuad> debug_border_quad =
- DebugBorderDrawQuad::Create();
- debug_border_quad->SetNew(
- draw_quad->shared_quad_state, draw_quad->visible_rect, color, width);
- quad_list->push_back(debug_border_quad.PassAs<DrawQuad>());
- }
-
- // Pass the quad after we're done using it.
- quad_list->push_back(draw_quad.Pass());
- }
- return keep_quad;
-}
-
-bool QuadCuller::Append(scoped_ptr<DrawQuad> draw_quad,
- AppendQuadsData* append_quads_data) {
- DCHECK(draw_quad->shared_quad_state == current_shared_quad_state_);
- DCHECK(!shared_quad_state_list_->empty());
- DCHECK(shared_quad_state_list_->back() == current_shared_quad_state_);
-
- gfx::Rect culled_rect;
- bool impl_draw_transform_is_unknown = false;
-
- if (for_surface_) {
- culled_rect = occlusion_tracker_.UnoccludedContributingSurfaceContentRect(
- layer_, false, draw_quad->visible_rect);
- } else {
- culled_rect = occlusion_tracker_.UnoccludedContentRect(
- layer_->render_target(),
- draw_quad->visible_rect,
- draw_quad->quadTransform(),
- impl_draw_transform_is_unknown);
- }
-
- return AppendQuadInternal(draw_quad.Pass(),
- culled_rect,
- quad_list_,
- occlusion_tracker_,
- layer_,
- show_culling_with_debug_border_quads_);
-}
-
-} // namespace cc
diff --git a/chromium/cc/trees/quad_culler.h b/chromium/cc/trees/quad_culler.h
deleted file mode 100644
index be0095f9f41..00000000000
--- a/chromium/cc/trees/quad_culler.h
+++ /dev/null
@@ -1,49 +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_TREES_QUAD_CULLER_H_
-#define CC_TREES_QUAD_CULLER_H_
-
-#include "cc/base/cc_export.h"
-#include "cc/layers/quad_sink.h"
-#include "cc/quads/render_pass.h"
-
-namespace cc {
-class LayerImpl;
-class RenderSurfaceImpl;
-template <typename LayerType, typename SurfaceType> class OcclusionTrackerBase;
-
-class CC_EXPORT QuadCuller : public QuadSink {
- public:
- QuadCuller(QuadList* quad_list,
- SharedQuadStateList* shared_quad_state_list,
- const LayerImpl* layer,
- const OcclusionTrackerBase<LayerImpl, RenderSurfaceImpl>&
- occlusion_tracker,
- bool show_culling_with_debug_border_quads,
- bool for_surface);
- virtual ~QuadCuller() {}
-
- // QuadSink implementation.
- virtual SharedQuadState* UseSharedQuadState(
- scoped_ptr<SharedQuadState> shared_quad_state) OVERRIDE;
- virtual bool Append(scoped_ptr<DrawQuad> draw_quad,
- AppendQuadsData* append_quads_data) OVERRIDE;
-
- private:
- QuadList* quad_list_;
- SharedQuadStateList* shared_quad_state_list_;
- const LayerImpl* layer_;
- const OcclusionTrackerBase<LayerImpl, RenderSurfaceImpl>& occlusion_tracker_;
-
- SharedQuadState* current_shared_quad_state_;
- bool show_culling_with_debug_border_quads_;
- bool for_surface_;
-
- DISALLOW_COPY_AND_ASSIGN(QuadCuller);
-};
-
-} // namespace cc
-
-#endif // CC_TREES_QUAD_CULLER_H_
diff --git a/chromium/cc/trees/quad_culler_unittest.cc b/chromium/cc/trees/quad_culler_unittest.cc
deleted file mode 100644
index c07a0a79e04..00000000000
--- a/chromium/cc/trees/quad_culler_unittest.cc
+++ /dev/null
@@ -1,919 +0,0 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/trees/quad_culler.h"
-
-#include <vector>
-
-#include "cc/base/math_util.h"
-#include "cc/debug/overdraw_metrics.h"
-#include "cc/layers/append_quads_data.h"
-#include "cc/layers/render_surface_impl.h"
-#include "cc/layers/tiled_layer_impl.h"
-#include "cc/quads/render_pass_draw_quad.h"
-#include "cc/quads/solid_color_draw_quad.h"
-#include "cc/quads/tile_draw_quad.h"
-#include "cc/resources/layer_tiling_data.h"
-#include "cc/test/fake_impl_proxy.h"
-#include "cc/test/fake_layer_tree_host_impl.h"
-#include "cc/test/occlusion_tracker_test_common.h"
-#include "cc/trees/occlusion_tracker.h"
-#include "cc/trees/single_thread_proxy.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/transform.h"
-
-namespace cc {
-namespace {
-
-class TestOcclusionTrackerImpl
- : public TestOcclusionTrackerBase<LayerImpl, RenderSurfaceImpl> {
- public:
- TestOcclusionTrackerImpl(gfx::Rect scissor_rect_in_screen,
- bool record_metrics_for_frame = true)
- : TestOcclusionTrackerBase(scissor_rect_in_screen,
- record_metrics_for_frame) {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(TestOcclusionTrackerImpl);
-};
-
-typedef LayerIterator<LayerImpl,
- LayerImplList,
- RenderSurfaceImpl,
- LayerIteratorActions::FrontToBack> LayerIteratorType;
-
-class QuadCullerTest : public testing::Test {
- public:
- QuadCullerTest()
- : host_impl_(&proxy_),
- layer_id_(1) {}
-
- scoped_ptr<TiledLayerImpl> MakeLayer(TiledLayerImpl* parent,
- const gfx::Transform& draw_transform,
- gfx::Rect layer_rect,
- float opacity,
- bool opaque,
- gfx::Rect layer_opaque_rect,
- LayerImplList& surface_layer_list) {
- scoped_ptr<TiledLayerImpl> layer =
- TiledLayerImpl::Create(host_impl_.active_tree(), layer_id_++);
- scoped_ptr<LayerTilingData> tiler = LayerTilingData::Create(
- gfx::Size(100, 100), LayerTilingData::NO_BORDER_TEXELS);
- tiler->SetBounds(layer_rect.size());
- layer->SetTilingData(*tiler);
- layer->set_skips_draw(false);
- layer->SetDrawsContent(true);
- layer->draw_properties().target_space_transform = draw_transform;
- layer->draw_properties().screen_space_transform = draw_transform;
- layer->draw_properties().visible_content_rect = layer_rect;
- layer->draw_properties().opacity = opacity;
- layer->SetContentsOpaque(opaque);
- layer->SetBounds(layer_rect.size());
- layer->SetContentBounds(layer_rect.size());
-
- ResourceProvider::ResourceId resource_id = 1;
- for (int i = 0; i < tiler->num_tiles_x(); ++i) {
- for (int j = 0; j < tiler->num_tiles_y(); ++j) {
- gfx::Rect tile_opaque_rect =
- opaque
- ? tiler->tile_bounds(i, j)
- : gfx::IntersectRects(tiler->tile_bounds(i, j), layer_opaque_rect);
- layer->PushTileProperties(i, j, resource_id++, tile_opaque_rect, false);
- }
- }
-
- gfx::Rect rect_in_target = MathUtil::MapClippedRect(
- layer->draw_transform(), layer->visible_content_rect());
- if (!parent) {
- layer->CreateRenderSurface();
- layer->render_surface()->SetContentRect(rect_in_target);
- surface_layer_list.push_back(layer.get());
- layer->render_surface()->layer_list().push_back(layer.get());
- } else {
- layer->draw_properties().render_target = parent->render_target();
- parent->render_surface()->layer_list().push_back(layer.get());
- rect_in_target.Union(MathUtil::MapClippedRect(
- parent->draw_transform(), parent->visible_content_rect()));
- parent->render_surface()->SetContentRect(rect_in_target);
- }
- layer->draw_properties().drawable_content_rect = rect_in_target;
-
- return layer.Pass();
- }
-
- void AppendQuads(QuadList* quad_list,
- SharedQuadStateList* shared_state_list,
- TiledLayerImpl* layer,
- LayerIteratorType* it,
- OcclusionTrackerImpl* occlusion_tracker) {
- occlusion_tracker->EnterLayer(*it);
- QuadCuller quad_culler(
- quad_list, shared_state_list, layer, *occlusion_tracker, false, false);
- AppendQuadsData data;
- layer->AppendQuads(&quad_culler, &data);
- occlusion_tracker->LeaveLayer(*it);
- ++it;
- }
-
- protected:
- FakeImplProxy proxy_;
- FakeLayerTreeHostImpl host_impl_;
- int layer_id_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(QuadCullerTest);
-};
-
-#define DECLARE_AND_INITIALIZE_TEST_QUADS() \
- QuadList quad_list; \
- SharedQuadStateList shared_state_list; \
- LayerImplList render_surface_layer_list; \
- gfx::Transform child_transform; \
- gfx::Size root_size = gfx::Size(300, 300); \
- gfx::Rect root_rect = gfx::Rect(root_size); \
- gfx::Size child_size = gfx::Size(200, 200); \
- gfx::Rect child_rect = gfx::Rect(child_size);
-
-TEST_F(QuadCullerTest, NoCulling) {
- DECLARE_AND_INITIALIZE_TEST_QUADS();
-
- scoped_ptr<TiledLayerImpl> root_layer = MakeLayer(NULL,
- gfx::Transform(),
- root_rect,
- 1.f,
- true,
- gfx::Rect(),
- render_surface_layer_list);
- scoped_ptr<TiledLayerImpl> child_layer = MakeLayer(root_layer.get(),
- gfx::Transform(),
- child_rect,
- 1.f,
- false,
- gfx::Rect(),
- render_surface_layer_list);
- TestOcclusionTrackerImpl occlusion_tracker(gfx::Rect(-100, -100, 1000, 1000));
- LayerIteratorType it = LayerIteratorType::Begin(&render_surface_layer_list);
-
- AppendQuads(&quad_list,
- &shared_state_list,
- child_layer.get(),
- &it,
- &occlusion_tracker);
- AppendQuads(&quad_list,
- &shared_state_list,
- root_layer.get(),
- &it,
- &occlusion_tracker);
- EXPECT_EQ(13u, quad_list.size());
- EXPECT_NEAR(
- occlusion_tracker.overdraw_metrics()->pixels_drawn_opaque(), 90000, 1);
- EXPECT_NEAR(occlusion_tracker.overdraw_metrics()->pixels_drawn_translucent(),
- 40000,
- 1);
- EXPECT_NEAR(
- occlusion_tracker.overdraw_metrics()->pixels_culled_for_drawing(), 0, 1);
-}
-
-TEST_F(QuadCullerTest, CullChildLinesUpTopLeft) {
- DECLARE_AND_INITIALIZE_TEST_QUADS();
-
- scoped_ptr<TiledLayerImpl> root_layer = MakeLayer(NULL,
- gfx::Transform(),
- root_rect,
- 1.f,
- true,
- gfx::Rect(),
- render_surface_layer_list);
- scoped_ptr<TiledLayerImpl> child_layer = MakeLayer(root_layer.get(),
- gfx::Transform(),
- child_rect,
- 1.f,
- true,
- gfx::Rect(),
- render_surface_layer_list);
- TestOcclusionTrackerImpl occlusion_tracker(gfx::Rect(-100, -100, 1000, 1000));
- LayerIteratorType it = LayerIteratorType::Begin(&render_surface_layer_list);
-
- AppendQuads(&quad_list,
- &shared_state_list,
- child_layer.get(),
- &it,
- &occlusion_tracker);
- AppendQuads(&quad_list,
- &shared_state_list,
- root_layer.get(),
- &it,
- &occlusion_tracker);
- EXPECT_EQ(9u, quad_list.size());
- EXPECT_NEAR(
- occlusion_tracker.overdraw_metrics()->pixels_drawn_opaque(), 90000, 1);
- EXPECT_NEAR(
- occlusion_tracker.overdraw_metrics()->pixels_drawn_translucent(), 0, 1);
- EXPECT_NEAR(occlusion_tracker.overdraw_metrics()->pixels_culled_for_drawing(),
- 40000,
- 1);
-}
-
-TEST_F(QuadCullerTest, CullWhenChildOpacityNotOne) {
- DECLARE_AND_INITIALIZE_TEST_QUADS();
-
- scoped_ptr<TiledLayerImpl> root_layer = MakeLayer(NULL,
- gfx::Transform(),
- root_rect,
- 1.f,
- true,
- gfx::Rect(),
- render_surface_layer_list);
- scoped_ptr<TiledLayerImpl> child_layer = MakeLayer(root_layer.get(),
- child_transform,
- child_rect,
- 0.9f,
- true,
- gfx::Rect(),
- render_surface_layer_list);
- TestOcclusionTrackerImpl occlusion_tracker(gfx::Rect(-100, -100, 1000, 1000));
- LayerIteratorType it = LayerIteratorType::Begin(&render_surface_layer_list);
-
- AppendQuads(&quad_list,
- &shared_state_list,
- child_layer.get(),
- &it,
- &occlusion_tracker);
- AppendQuads(&quad_list,
- &shared_state_list,
- root_layer.get(),
- &it,
- &occlusion_tracker);
- EXPECT_EQ(13u, quad_list.size());
- EXPECT_NEAR(
- occlusion_tracker.overdraw_metrics()->pixels_drawn_opaque(), 90000, 1);
- EXPECT_NEAR(occlusion_tracker.overdraw_metrics()->pixels_drawn_translucent(),
- 40000,
- 1);
- EXPECT_NEAR(
- occlusion_tracker.overdraw_metrics()->pixels_culled_for_drawing(), 0, 1);
-}
-
-TEST_F(QuadCullerTest, CullWhenChildOpaqueFlagFalse) {
- DECLARE_AND_INITIALIZE_TEST_QUADS();
-
- scoped_ptr<TiledLayerImpl> root_layer = MakeLayer(NULL,
- gfx::Transform(),
- root_rect,
- 1.f,
- true,
- gfx::Rect(),
- render_surface_layer_list);
- scoped_ptr<TiledLayerImpl> child_layer = MakeLayer(root_layer.get(),
- child_transform,
- child_rect,
- 1.f,
- false,
- gfx::Rect(),
- render_surface_layer_list);
- TestOcclusionTrackerImpl occlusion_tracker(gfx::Rect(-100, -100, 1000, 1000));
- LayerIteratorType it = LayerIteratorType::Begin(&render_surface_layer_list);
-
- AppendQuads(&quad_list,
- &shared_state_list,
- child_layer.get(),
- &it,
- &occlusion_tracker);
- AppendQuads(&quad_list,
- &shared_state_list,
- root_layer.get(),
- &it,
- &occlusion_tracker);
- EXPECT_EQ(13u, quad_list.size());
- EXPECT_NEAR(
- occlusion_tracker.overdraw_metrics()->pixels_drawn_opaque(), 90000, 1);
- EXPECT_NEAR(occlusion_tracker.overdraw_metrics()->pixels_drawn_translucent(),
- 40000,
- 1);
- EXPECT_NEAR(
- occlusion_tracker.overdraw_metrics()->pixels_culled_for_drawing(), 0, 1);
-}
-
-TEST_F(QuadCullerTest, CullCenterTileOnly) {
- DECLARE_AND_INITIALIZE_TEST_QUADS();
-
- child_transform.Translate(50, 50);
- scoped_ptr<TiledLayerImpl> root_layer = MakeLayer(NULL,
- gfx::Transform(),
- root_rect,
- 1.f,
- true,
- gfx::Rect(),
- render_surface_layer_list);
- scoped_ptr<TiledLayerImpl> child_layer = MakeLayer(root_layer.get(),
- child_transform,
- child_rect,
- 1.f,
- true,
- gfx::Rect(),
- render_surface_layer_list);
- TestOcclusionTrackerImpl occlusion_tracker(gfx::Rect(-100, -100, 1000, 1000));
- LayerIteratorType it = LayerIteratorType::Begin(&render_surface_layer_list);
-
- AppendQuads(&quad_list,
- &shared_state_list,
- child_layer.get(),
- &it,
- &occlusion_tracker);
- AppendQuads(&quad_list,
- &shared_state_list,
- root_layer.get(),
- &it,
- &occlusion_tracker);
- ASSERT_EQ(quad_list.size(), 12u);
-
- gfx::Rect quad_visible_rect1 = quad_list[5]->visible_rect;
- EXPECT_EQ(50, quad_visible_rect1.height());
-
- gfx::Rect quad_visible_rect3 = quad_list[7]->visible_rect;
- EXPECT_EQ(50, quad_visible_rect3.width());
-
- // Next index is 8, not 9, since centre quad culled.
- gfx::Rect quad_visible_rect4 = quad_list[8]->visible_rect;
- EXPECT_EQ(50, quad_visible_rect4.width());
- EXPECT_EQ(250, quad_visible_rect4.x());
-
- gfx::Rect quad_visible_rect6 = quad_list[10]->visible_rect;
- EXPECT_EQ(50, quad_visible_rect6.height());
- EXPECT_EQ(250, quad_visible_rect6.y());
-
- EXPECT_NEAR(
- occlusion_tracker.overdraw_metrics()->pixels_drawn_opaque(), 100000, 1);
- EXPECT_NEAR(
- occlusion_tracker.overdraw_metrics()->pixels_drawn_translucent(), 0, 1);
- EXPECT_NEAR(occlusion_tracker.overdraw_metrics()->pixels_culled_for_drawing(),
- 30000,
- 1);
-}
-
-TEST_F(QuadCullerTest, CullCenterTileNonIntegralSize1) {
- DECLARE_AND_INITIALIZE_TEST_QUADS();
-
- child_transform.Translate(100, 100);
-
- // Make the root layer's quad have extent (99.1, 99.1) -> (200.9, 200.9) to
- // make sure it doesn't get culled due to transform rounding.
- gfx::Transform root_transform;
- root_transform.Translate(99.1f, 99.1f);
- root_transform.Scale(1.018f, 1.018f);
-
- root_rect = child_rect = gfx::Rect(0, 0, 100, 100);
-
- scoped_ptr<TiledLayerImpl> root_layer = MakeLayer(NULL,
- root_transform,
- root_rect,
- 1.f,
- true,
- gfx::Rect(),
- render_surface_layer_list);
- scoped_ptr<TiledLayerImpl> child_layer = MakeLayer(root_layer.get(),
- child_transform,
- child_rect,
- 1.f,
- true,
- gfx::Rect(),
- render_surface_layer_list);
- TestOcclusionTrackerImpl occlusion_tracker(gfx::Rect(-100, -100, 1000, 1000));
- LayerIteratorType it = LayerIteratorType::Begin(&render_surface_layer_list);
-
- AppendQuads(&quad_list,
- &shared_state_list,
- child_layer.get(),
- &it,
- &occlusion_tracker);
- AppendQuads(&quad_list,
- &shared_state_list,
- root_layer.get(),
- &it,
- &occlusion_tracker);
- EXPECT_EQ(2u, quad_list.size());
-
- EXPECT_NEAR(
- occlusion_tracker.overdraw_metrics()->pixels_drawn_opaque(), 20363, 1);
- EXPECT_NEAR(
- occlusion_tracker.overdraw_metrics()->pixels_drawn_translucent(), 0, 1);
- EXPECT_NEAR(
- occlusion_tracker.overdraw_metrics()->pixels_culled_for_drawing(), 0, 1);
-}
-
-TEST_F(QuadCullerTest, CullCenterTileNonIntegralSize2) {
- DECLARE_AND_INITIALIZE_TEST_QUADS();
-
- // Make the child's quad slightly smaller than, and centred over, the root
- // layer tile. Verify the child does not cause the quad below to be culled
- // due to rounding.
- child_transform.Translate(100.1f, 100.1f);
- child_transform.Scale(0.982f, 0.982f);
-
- gfx::Transform root_transform;
- root_transform.Translate(100, 100);
-
- root_rect = child_rect = gfx::Rect(0, 0, 100, 100);
-
- scoped_ptr<TiledLayerImpl> root_layer = MakeLayer(NULL,
- root_transform,
- root_rect,
- 1.f,
- true,
- gfx::Rect(),
- render_surface_layer_list);
- scoped_ptr<TiledLayerImpl> child_layer = MakeLayer(root_layer.get(),
- child_transform,
- child_rect,
- 1.f,
- true,
- gfx::Rect(),
- render_surface_layer_list);
- TestOcclusionTrackerImpl occlusion_tracker(gfx::Rect(-100, -100, 1000, 1000));
- LayerIteratorType it = LayerIteratorType::Begin(&render_surface_layer_list);
-
- AppendQuads(&quad_list,
- &shared_state_list,
- child_layer.get(),
- &it,
- &occlusion_tracker);
- AppendQuads(&quad_list,
- &shared_state_list,
- root_layer.get(),
- &it,
- &occlusion_tracker);
- EXPECT_EQ(2u, quad_list.size());
-
- EXPECT_NEAR(
- occlusion_tracker.overdraw_metrics()->pixels_drawn_opaque(), 19643, 1);
- EXPECT_NEAR(
- occlusion_tracker.overdraw_metrics()->pixels_drawn_translucent(), 0, 1);
- EXPECT_NEAR(
- occlusion_tracker.overdraw_metrics()->pixels_culled_for_drawing(), 0, 1);
-}
-
-TEST_F(QuadCullerTest, CullChildLinesUpBottomRight) {
- DECLARE_AND_INITIALIZE_TEST_QUADS();
-
- child_transform.Translate(100, 100);
- scoped_ptr<TiledLayerImpl> root_layer = MakeLayer(NULL,
- gfx::Transform(),
- root_rect,
- 1.f,
- true,
- gfx::Rect(),
- render_surface_layer_list);
- scoped_ptr<TiledLayerImpl> child_layer = MakeLayer(root_layer.get(),
- child_transform,
- child_rect,
- 1.f,
- true,
- gfx::Rect(),
- render_surface_layer_list);
- TestOcclusionTrackerImpl occlusion_tracker(gfx::Rect(-100, -100, 1000, 1000));
- LayerIteratorType it = LayerIteratorType::Begin(&render_surface_layer_list);
-
- AppendQuads(&quad_list,
- &shared_state_list,
- child_layer.get(),
- &it,
- &occlusion_tracker);
- AppendQuads(&quad_list,
- &shared_state_list,
- root_layer.get(),
- &it,
- &occlusion_tracker);
- EXPECT_EQ(9u, quad_list.size());
- EXPECT_NEAR(
- occlusion_tracker.overdraw_metrics()->pixels_drawn_opaque(), 90000, 1);
- EXPECT_NEAR(
- occlusion_tracker.overdraw_metrics()->pixels_drawn_translucent(), 0, 1);
- EXPECT_NEAR(occlusion_tracker.overdraw_metrics()->pixels_culled_for_drawing(),
- 40000,
- 1);
-}
-
-TEST_F(QuadCullerTest, CullSubRegion) {
- DECLARE_AND_INITIALIZE_TEST_QUADS();
-
- child_transform.Translate(50, 50);
- scoped_ptr<TiledLayerImpl> root_layer = MakeLayer(NULL,
- gfx::Transform(),
- root_rect,
- 1.f,
- true,
- gfx::Rect(),
- render_surface_layer_list);
- gfx::Rect child_opaque_rect(child_rect.x() + child_rect.width() / 4,
- child_rect.y() + child_rect.height() / 4,
- child_rect.width() / 2,
- child_rect.height() / 2);
- scoped_ptr<TiledLayerImpl> child_layer = MakeLayer(root_layer.get(),
- child_transform,
- child_rect,
- 1.f,
- false,
- child_opaque_rect,
- render_surface_layer_list);
- TestOcclusionTrackerImpl occlusion_tracker(gfx::Rect(-100, -100, 1000, 1000));
- LayerIteratorType it = LayerIteratorType::Begin(&render_surface_layer_list);
-
- AppendQuads(&quad_list,
- &shared_state_list,
- child_layer.get(),
- &it,
- &occlusion_tracker);
- AppendQuads(&quad_list,
- &shared_state_list,
- root_layer.get(),
- &it,
- &occlusion_tracker);
- EXPECT_EQ(12u, quad_list.size());
- EXPECT_NEAR(
- occlusion_tracker.overdraw_metrics()->pixels_drawn_opaque(), 90000, 1);
- EXPECT_NEAR(occlusion_tracker.overdraw_metrics()->pixels_drawn_translucent(),
- 30000,
- 1);
- EXPECT_NEAR(occlusion_tracker.overdraw_metrics()->pixels_culled_for_drawing(),
- 10000,
- 1);
-}
-
-TEST_F(QuadCullerTest, CullSubRegion2) {
- DECLARE_AND_INITIALIZE_TEST_QUADS();
-
- child_transform.Translate(50, 10);
- scoped_ptr<TiledLayerImpl> root_layer = MakeLayer(NULL,
- gfx::Transform(),
- root_rect,
- 1.f,
- true,
- gfx::Rect(),
- render_surface_layer_list);
- gfx::Rect child_opaque_rect(child_rect.x() + child_rect.width() / 4,
- child_rect.y() + child_rect.height() / 4,
- child_rect.width() / 2,
- child_rect.height() * 3 / 4);
- scoped_ptr<TiledLayerImpl> child_layer = MakeLayer(root_layer.get(),
- child_transform,
- child_rect,
- 1.f,
- false,
- child_opaque_rect,
- render_surface_layer_list);
- TestOcclusionTrackerImpl occlusion_tracker(gfx::Rect(-100, -100, 1000, 1000));
- LayerIteratorType it = LayerIteratorType::Begin(&render_surface_layer_list);
-
- AppendQuads(&quad_list,
- &shared_state_list,
- child_layer.get(),
- &it,
- &occlusion_tracker);
- AppendQuads(&quad_list,
- &shared_state_list,
- root_layer.get(),
- &it,
- &occlusion_tracker);
- EXPECT_EQ(12u, quad_list.size());
- EXPECT_NEAR(
- occlusion_tracker.overdraw_metrics()->pixels_drawn_opaque(), 90000, 1);
- EXPECT_NEAR(occlusion_tracker.overdraw_metrics()->pixels_drawn_translucent(),
- 25000,
- 1);
- EXPECT_NEAR(occlusion_tracker.overdraw_metrics()->pixels_culled_for_drawing(),
- 15000,
- 1);
-}
-
-TEST_F(QuadCullerTest, CullSubRegionCheckOvercull) {
- DECLARE_AND_INITIALIZE_TEST_QUADS();
-
- child_transform.Translate(50, 49);
- scoped_ptr<TiledLayerImpl> root_layer = MakeLayer(NULL,
- gfx::Transform(),
- root_rect,
- 1.f,
- true,
- gfx::Rect(),
- render_surface_layer_list);
- gfx::Rect child_opaque_rect(child_rect.x() + child_rect.width() / 4,
- child_rect.y() + child_rect.height() / 4,
- child_rect.width() / 2,
- child_rect.height() / 2);
- scoped_ptr<TiledLayerImpl> child_layer = MakeLayer(root_layer.get(),
- child_transform,
- child_rect,
- 1.f,
- false,
- child_opaque_rect,
- render_surface_layer_list);
- TestOcclusionTrackerImpl occlusion_tracker(gfx::Rect(-100, -100, 1000, 1000));
- LayerIteratorType it = LayerIteratorType::Begin(&render_surface_layer_list);
-
- AppendQuads(&quad_list,
- &shared_state_list,
- child_layer.get(),
- &it,
- &occlusion_tracker);
- AppendQuads(&quad_list,
- &shared_state_list,
- root_layer.get(),
- &it,
- &occlusion_tracker);
- EXPECT_EQ(13u, quad_list.size());
- EXPECT_NEAR(
- occlusion_tracker.overdraw_metrics()->pixels_drawn_opaque(), 90000, 1);
- EXPECT_NEAR(occlusion_tracker.overdraw_metrics()->pixels_drawn_translucent(),
- 30000,
- 1);
- EXPECT_NEAR(occlusion_tracker.overdraw_metrics()->pixels_culled_for_drawing(),
- 10000,
- 1);
-}
-
-TEST_F(QuadCullerTest, NonAxisAlignedQuadsDontOcclude) {
- DECLARE_AND_INITIALIZE_TEST_QUADS();
-
- // Use a small rotation so as to not disturb the geometry significantly.
- child_transform.Rotate(1);
-
- scoped_ptr<TiledLayerImpl> root_layer = MakeLayer(NULL,
- gfx::Transform(),
- root_rect,
- 1.f,
- true,
- gfx::Rect(),
- render_surface_layer_list);
- scoped_ptr<TiledLayerImpl> child_layer = MakeLayer(root_layer.get(),
- child_transform,
- child_rect,
- 1.f,
- true,
- gfx::Rect(),
- render_surface_layer_list);
- TestOcclusionTrackerImpl occlusion_tracker(gfx::Rect(-100, -100, 1000, 1000));
- LayerIteratorType it = LayerIteratorType::Begin(&render_surface_layer_list);
-
- AppendQuads(&quad_list,
- &shared_state_list,
- child_layer.get(),
- &it,
- &occlusion_tracker);
- AppendQuads(&quad_list,
- &shared_state_list,
- root_layer.get(),
- &it,
- &occlusion_tracker);
- EXPECT_EQ(13u, quad_list.size());
- EXPECT_NEAR(
- occlusion_tracker.overdraw_metrics()->pixels_drawn_opaque(), 130000, 1);
- EXPECT_NEAR(
- occlusion_tracker.overdraw_metrics()->pixels_drawn_translucent(), 0, 1);
- EXPECT_NEAR(
- occlusion_tracker.overdraw_metrics()->pixels_culled_for_drawing(), 0, 1);
-}
-
-// This test requires some explanation: here we are rotating the quads to be
-// culled. The 2x2 tile child layer remains in the top-left corner, unrotated,
-// but the 3x3 tile parent layer is rotated by 1 degree. Of the four tiles the
-// child would normally occlude, three will move (slightly) out from under the
-// child layer, and one moves further under the child. Only this last tile
-// should be culled.
-TEST_F(QuadCullerTest, NonAxisAlignedQuadsSafelyCulled) {
- DECLARE_AND_INITIALIZE_TEST_QUADS();
-
- // Use a small rotation so as to not disturb the geometry significantly.
- gfx::Transform parent_transform;
- parent_transform.Rotate(1);
-
- scoped_ptr<TiledLayerImpl> root_layer = MakeLayer(NULL,
- parent_transform,
- root_rect,
- 1.f,
- true,
- gfx::Rect(),
- render_surface_layer_list);
- scoped_ptr<TiledLayerImpl> child_layer = MakeLayer(root_layer.get(),
- gfx::Transform(),
- child_rect,
- 1.f,
- true,
- gfx::Rect(),
- render_surface_layer_list);
- TestOcclusionTrackerImpl occlusion_tracker(gfx::Rect(-100, -100, 1000, 1000));
- LayerIteratorType it = LayerIteratorType::Begin(&render_surface_layer_list);
-
- AppendQuads(&quad_list,
- &shared_state_list,
- child_layer.get(),
- &it,
- &occlusion_tracker);
- AppendQuads(&quad_list,
- &shared_state_list,
- root_layer.get(),
- &it,
- &occlusion_tracker);
- EXPECT_EQ(12u, quad_list.size());
- EXPECT_NEAR(
- occlusion_tracker.overdraw_metrics()->pixels_drawn_opaque(), 100600, 1);
- EXPECT_NEAR(
- occlusion_tracker.overdraw_metrics()->pixels_drawn_translucent(), 0, 1);
- EXPECT_NEAR(occlusion_tracker.overdraw_metrics()->pixels_culled_for_drawing(),
- 29400,
- 1);
-}
-
-TEST_F(QuadCullerTest, WithoutMetrics) {
- DECLARE_AND_INITIALIZE_TEST_QUADS();
- scoped_ptr<TiledLayerImpl> root_layer = MakeLayer(NULL,
- gfx::Transform(),
- root_rect,
- 1.f,
- true,
- gfx::Rect(),
- render_surface_layer_list);
- scoped_ptr<TiledLayerImpl> child_layer = MakeLayer(root_layer.get(),
- gfx::Transform(),
- child_rect,
- 1.f,
- true,
- gfx::Rect(),
- render_surface_layer_list);
- bool record_metrics = false;
- TestOcclusionTrackerImpl occlusion_tracker(gfx::Rect(-100, -100, 1000, 1000),
- record_metrics);
- LayerIteratorType it = LayerIteratorType::Begin(&render_surface_layer_list);
-
- AppendQuads(&quad_list,
- &shared_state_list,
- child_layer.get(),
- &it,
- &occlusion_tracker);
- AppendQuads(&quad_list,
- &shared_state_list,
- root_layer.get(),
- &it,
- &occlusion_tracker);
- EXPECT_EQ(9u, quad_list.size());
- EXPECT_EQ(0.f,
- occlusion_tracker.overdraw_metrics()->pixels_drawn_opaque());
- EXPECT_EQ(0.f,
- occlusion_tracker.overdraw_metrics()->pixels_drawn_translucent());
- EXPECT_EQ(0.f,
- occlusion_tracker.overdraw_metrics()->pixels_culled_for_drawing());
-}
-
-TEST_F(QuadCullerTest, PartialCullingNotDestroyed) {
- DECLARE_AND_INITIALIZE_TEST_QUADS();
-
- scoped_ptr<TiledLayerImpl> dummy_layer = MakeLayer(NULL,
- gfx::Transform(),
- gfx::Rect(),
- 1.f,
- true,
- gfx::Rect(),
- render_surface_layer_list);
-
- TestOcclusionTrackerImpl occlusion_tracker(gfx::Rect(1000, 1000));
- LayerIteratorType it = LayerIteratorType::Begin(&render_surface_layer_list);
-
- QuadCuller culler(&quad_list,
- &shared_state_list,
- dummy_layer.get(),
- occlusion_tracker,
- false,
- false);
-
- SharedQuadState* sqs = culler.UseSharedQuadState(SharedQuadState::Create());
-
- scoped_ptr<SolidColorDrawQuad> color_quad = SolidColorDrawQuad::Create();
- color_quad->SetNew(sqs, gfx::Rect(100, 100), SK_ColorRED, false);
-
- scoped_ptr<RenderPassDrawQuad> pass_quad = RenderPassDrawQuad::Create();
- pass_quad->SetNew(sqs,
- gfx::Rect(100, 100),
- RenderPass::Id(10, 10),
- false,
- 0,
- gfx::Rect(),
- gfx::RectF(),
- FilterOperations(),
- FilterOperations());
-
- scoped_ptr<RenderPassDrawQuad> replica_quad = RenderPassDrawQuad::Create();
- replica_quad->SetNew(sqs,
- gfx::Rect(100, 100),
- RenderPass::Id(10, 10),
- true,
- 0,
- gfx::Rect(),
- gfx::RectF(),
- FilterOperations(),
- FilterOperations());
-
- // Set a visible rect on the quads.
- color_quad->visible_rect = gfx::Rect(20, 30, 10, 11);
- pass_quad->visible_rect = gfx::Rect(50, 60, 13, 14);
- replica_quad->visible_rect = gfx::Rect(30, 40, 15, 16);
-
- // Nothing is occluding.
- occlusion_tracker.EnterLayer(it);
-
- EXPECT_EQ(0u, quad_list.size());
-
- AppendQuadsData data;
- culler.Append(color_quad.PassAs<DrawQuad>(), &data);
- culler.Append(pass_quad.PassAs<DrawQuad>(), &data);
- culler.Append(replica_quad.PassAs<DrawQuad>(), &data);
-
- ASSERT_EQ(3u, quad_list.size());
-
- // The partial culling is preserved.
- EXPECT_EQ(gfx::Rect(20, 30, 10, 11).ToString(),
- quad_list[0]->visible_rect.ToString());
- EXPECT_EQ(gfx::Rect(50, 60, 13, 14).ToString(),
- quad_list[1]->visible_rect.ToString());
- EXPECT_EQ(gfx::Rect(30, 40, 15, 16).ToString(),
- quad_list[2]->visible_rect.ToString());
-}
-
-TEST_F(QuadCullerTest, PartialCullingWithOcclusionNotDestroyed) {
- DECLARE_AND_INITIALIZE_TEST_QUADS();
-
- scoped_ptr<TiledLayerImpl> dummy_layer = MakeLayer(NULL,
- gfx::Transform(),
- gfx::Rect(),
- 1.f,
- true,
- gfx::Rect(),
- render_surface_layer_list);
-
- TestOcclusionTrackerImpl occlusion_tracker(gfx::Rect(1000, 1000));
- LayerIteratorType it = LayerIteratorType::Begin(&render_surface_layer_list);
-
- QuadCuller culler(&quad_list,
- &shared_state_list,
- dummy_layer.get(),
- occlusion_tracker,
- false,
- false);
-
- SharedQuadState* sqs = culler.UseSharedQuadState(SharedQuadState::Create());
-
- scoped_ptr<SolidColorDrawQuad> color_quad = SolidColorDrawQuad::Create();
- color_quad->SetNew(sqs, gfx::Rect(100, 100), SK_ColorRED, false);
-
- scoped_ptr<RenderPassDrawQuad> pass_quad = RenderPassDrawQuad::Create();
- pass_quad->SetNew(sqs,
- gfx::Rect(100, 100),
- RenderPass::Id(10, 10),
- false,
- 0,
- gfx::Rect(),
- gfx::RectF(),
- FilterOperations(),
- FilterOperations());
-
- scoped_ptr<RenderPassDrawQuad> replica_quad = RenderPassDrawQuad::Create();
- replica_quad->SetNew(sqs,
- gfx::Rect(100, 100),
- RenderPass::Id(10, 10),
- true,
- 0,
- gfx::Rect(),
- gfx::RectF(),
- FilterOperations(),
- FilterOperations());
-
- // Set a visible rect on the quads.
- color_quad->visible_rect = gfx::Rect(10, 10, 10, 11);
- pass_quad->visible_rect = gfx::Rect(10, 20, 13, 14);
- replica_quad->visible_rect = gfx::Rect(10, 30, 15, 16);
-
- // Occlude the left part of the visible rects.
- occlusion_tracker.EnterLayer(it);
- occlusion_tracker.set_occlusion_from_outside_target(gfx::Rect(0, 0, 15, 100));
-
- EXPECT_EQ(0u, quad_list.size());
-
- AppendQuadsData data;
- culler.Append(color_quad.PassAs<DrawQuad>(), &data);
- culler.Append(pass_quad.PassAs<DrawQuad>(), &data);
- culler.Append(replica_quad.PassAs<DrawQuad>(), &data);
-
- ASSERT_EQ(3u, quad_list.size());
-
- // The partial culling is preserved, while the left side of the quads is newly
- // occluded.
- EXPECT_EQ(gfx::Rect(15, 10, 5, 11).ToString(),
- quad_list[0]->visible_rect.ToString());
- EXPECT_EQ(gfx::Rect(15, 20, 8, 14).ToString(),
- quad_list[1]->visible_rect.ToString());
- EXPECT_EQ(gfx::Rect(15, 30, 10, 16).ToString(),
- quad_list[2]->visible_rect.ToString());
-}
-
-} // namespace
-} // namespace cc
diff --git a/chromium/cc/trees/single_thread_proxy.cc b/chromium/cc/trees/single_thread_proxy.cc
index f1f8a4f5824..c254311a930 100644
--- a/chromium/cc/trees/single_thread_proxy.cc
+++ b/chromium/cc/trees/single_thread_proxy.cc
@@ -32,7 +32,6 @@ SingleThreadProxy::SingleThreadProxy(LayerTreeHost* layer_tree_host,
: Proxy(NULL),
layer_tree_host_(layer_tree_host),
client_(client),
- created_offscreen_context_provider_(false),
next_frame_is_newly_committed_frame_(false),
inside_draw_(false) {
TRACE_EVENT0("cc", "SingleThreadProxy::SingleThreadProxy");
@@ -44,11 +43,9 @@ SingleThreadProxy::SingleThreadProxy(LayerTreeHost* layer_tree_host,
<< "Threaded compositing must be enabled to use impl-side painting.";
}
-void SingleThreadProxy::Start(scoped_ptr<OutputSurface> first_output_surface) {
- DCHECK(first_output_surface);
+void SingleThreadProxy::Start() {
DebugScopedSetImplThread impl(this);
layer_tree_host_impl_ = layer_tree_host_->CreateLayerTreeHostImpl(this);
- first_output_surface_ = first_output_surface.Pass();
}
SingleThreadProxy::~SingleThreadProxy() {
@@ -58,31 +55,8 @@ SingleThreadProxy::~SingleThreadProxy() {
DCHECK(!layer_tree_host_impl_);
}
-bool SingleThreadProxy::CompositeAndReadback(void* pixels, gfx::Rect rect) {
- TRACE_EVENT0("cc", "SingleThreadProxy::CompositeAndReadback");
- DCHECK(Proxy::IsMainThread());
-
- gfx::Rect device_viewport_damage_rect = rect;
-
- LayerTreeHostImpl::FrameData frame;
- if (!CommitAndComposite(gfx::FrameTime::Now(),
- device_viewport_damage_rect,
- true, // for_readback
- &frame))
- return false;
-
- {
- DebugScopedSetImplThread impl(this);
- layer_tree_host_impl_->Readback(pixels, rect);
-
- if (layer_tree_host_impl_->IsContextLost())
- return false;
- }
-
- return true;
-}
-
void SingleThreadProxy::FinishAllRendering() {
+ TRACE_EVENT0("cc", "SingleThreadProxy::FinishAllRendering");
DCHECK(Proxy::IsMainThread());
{
DebugScopedSetImplThread impl(this);
@@ -96,11 +70,13 @@ bool SingleThreadProxy::IsStarted() const {
}
void SingleThreadProxy::SetLayerTreeHostClientReady() {
+ TRACE_EVENT0("cc", "SingleThreadProxy::SetLayerTreeHostClientReady");
// Scheduling is controlled by the embedder in the single thread case, so
// nothing to do.
}
void SingleThreadProxy::SetVisible(bool visible) {
+ TRACE_EVENT0("cc", "SingleThreadProxy::SetVisible");
DebugScopedSetImplThread impl(this);
layer_tree_host_impl_->SetVisible(visible);
@@ -112,59 +88,25 @@ void SingleThreadProxy::CreateAndInitializeOutputSurface() {
TRACE_EVENT0(
"cc", "SingleThreadProxy::CreateAndInitializeOutputSurface");
DCHECK(Proxy::IsMainThread());
+ DCHECK(layer_tree_host_->output_surface_lost());
- scoped_ptr<OutputSurface> output_surface = first_output_surface_.Pass();
- if (!output_surface)
- output_surface = layer_tree_host_->CreateOutputSurface();
- if (!output_surface) {
- OnOutputSurfaceInitializeAttempted(false);
- return;
- }
+ scoped_ptr<OutputSurface> output_surface =
+ layer_tree_host_->CreateOutputSurface();
- scoped_refptr<ContextProvider> offscreen_context_provider;
- if (created_offscreen_context_provider_) {
- offscreen_context_provider =
- layer_tree_host_->client()->OffscreenContextProvider();
- if (!offscreen_context_provider.get() ||
- !offscreen_context_provider->BindToCurrentThread()) {
- OnOutputSurfaceInitializeAttempted(false);
- return;
- }
- }
+ renderer_capabilities_for_main_thread_ = RendererCapabilities();
- {
+ bool success = !!output_surface;
+ if (success) {
DebugScopedSetMainThreadBlocked main_thread_blocked(this);
DebugScopedSetImplThread impl(this);
layer_tree_host_->DeleteContentsTexturesOnImplThread(
layer_tree_host_impl_->resource_provider());
+ success = layer_tree_host_impl_->InitializeRenderer(output_surface.Pass());
}
- bool initialized;
- {
- DebugScopedSetImplThread impl(this);
-
- DCHECK(output_surface);
- initialized = layer_tree_host_impl_->InitializeRenderer(
- output_surface.Pass());
- if (initialized) {
- renderer_capabilities_for_main_thread_ =
- layer_tree_host_impl_->GetRendererCapabilities();
- } else if (offscreen_context_provider.get()) {
- offscreen_context_provider->VerifyContexts();
- offscreen_context_provider = NULL;
- }
-
- layer_tree_host_impl_->SetOffscreenContextProvider(
- offscreen_context_provider);
- }
-
- OnOutputSurfaceInitializeAttempted(initialized);
-}
+ layer_tree_host_->OnCreateAndInitializeOutputSurfaceAttempted(success);
-void SingleThreadProxy::OnOutputSurfaceInitializeAttempted(bool success) {
- LayerTreeHost::CreateResult result =
- layer_tree_host_->OnCreateAndInitializeOutputSurfaceAttempted(success);
- if (result == LayerTreeHost::CreateFailedButTryAgain) {
+ if (!success) {
// Force another recreation attempt to happen by requesting another commit.
SetNeedsCommit();
}
@@ -177,16 +119,19 @@ const RendererCapabilities& SingleThreadProxy::GetRendererCapabilities() const {
}
void SingleThreadProxy::SetNeedsAnimate() {
+ TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsAnimate");
DCHECK(Proxy::IsMainThread());
client_->ScheduleAnimation();
}
void SingleThreadProxy::SetNeedsUpdateLayers() {
+ TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsUpdateLayers");
DCHECK(Proxy::IsMainThread());
client_->ScheduleComposite();
}
void SingleThreadProxy::DoCommit(scoped_ptr<ResourceUpdateQueue> queue) {
+ TRACE_EVENT0("cc", "SingleThreadProxy::DoCommit");
DCHECK(Proxy::IsMainThread());
// Commit immediately.
{
@@ -221,7 +166,7 @@ void SingleThreadProxy::DoCommit(scoped_ptr<ResourceUpdateQueue> queue) {
layer_tree_host_impl_->CommitComplete();
-#ifndef NDEBUG
+#if DCHECK_IS_ON
// In the single-threaded case, the scale and scroll deltas should never be
// touched on the impl layer tree.
scoped_ptr<ScrollAndScaleSet> scroll_info =
@@ -245,7 +190,8 @@ void SingleThreadProxy::SetNeedsCommit() {
client_->ScheduleComposite();
}
-void SingleThreadProxy::SetNeedsRedraw(gfx::Rect damage_rect) {
+void SingleThreadProxy::SetNeedsRedraw(const gfx::Rect& damage_rect) {
+ TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsRedraw");
SetNeedsRedrawRectOnImplThread(damage_rect);
client_->ScheduleComposite();
}
@@ -274,6 +220,7 @@ void SingleThreadProxy::Stop() {
DebugScopedSetMainThreadBlocked main_thread_blocked(this);
DebugScopedSetImplThread impl(this);
+ BlockingTaskRunner::CapturePostTasks blocked;
layer_tree_host_->DeleteContentsTexturesOnImplThread(
layer_tree_host_impl_->resource_provider());
layer_tree_host_impl_.reset();
@@ -282,6 +229,8 @@ void SingleThreadProxy::Stop() {
}
void SingleThreadProxy::OnCanDrawStateChanged(bool can_draw) {
+ TRACE_EVENT1(
+ "cc", "SingleThreadProxy::OnCanDrawStateChanged", "can_draw", can_draw);
DCHECK(Proxy::IsImplThread());
UpdateBackgroundAnimateTicking();
}
@@ -295,12 +244,17 @@ void SingleThreadProxy::SetNeedsRedrawOnImplThread() {
client_->ScheduleComposite();
}
+void SingleThreadProxy::SetNeedsAnimateOnImplThread() {
+ SetNeedsRedrawOnImplThread();
+}
+
void SingleThreadProxy::SetNeedsManageTilesOnImplThread() {
// Thread-only/Impl-side-painting-only feature.
NOTREACHED();
}
-void SingleThreadProxy::SetNeedsRedrawRectOnImplThread(gfx::Rect damage_rect) {
+void SingleThreadProxy::SetNeedsRedrawRectOnImplThread(
+ const gfx::Rect& damage_rect) {
// TODO(brianderson): Once we move render_widget scheduling into this class,
// we can treat redraw requests more efficiently than CommitAndRedraw
// requests.
@@ -318,11 +272,12 @@ void SingleThreadProxy::SetNeedsCommitOnImplThread() {
}
void SingleThreadProxy::PostAnimationEventsToMainThreadOnImplThread(
- scoped_ptr<AnimationEventsVector> events,
- base::Time wall_clock_time) {
+ scoped_ptr<AnimationEventsVector> events) {
+ TRACE_EVENT0(
+ "cc", "SingleThreadProxy::PostAnimationEventsToMainThreadOnImplThread");
DCHECK(Proxy::IsImplThread());
DebugScopedSetMainThread main(this);
- layer_tree_host_->SetAnimationEvents(events.Pass(), wall_clock_time);
+ layer_tree_host_->SetAnimationEvents(events.Pass());
}
bool SingleThreadProxy::ReduceContentsTextureMemoryOnImplThread(
@@ -342,24 +297,16 @@ bool SingleThreadProxy::ReduceContentsTextureMemoryOnImplThread(
limit_bytes, priority_cutoff, resource_provider);
}
-void SingleThreadProxy::SendManagedMemoryStats() {
- DCHECK(Proxy::IsImplThread());
- if (!layer_tree_host_impl_)
- return;
- PrioritizedResourceManager* contents_texture_manager =
- layer_tree_host_->contents_texture_manager();
- if (!contents_texture_manager)
- return;
+bool SingleThreadProxy::IsInsideDraw() { return inside_draw_; }
- layer_tree_host_impl_->SendManagedMemoryStats(
- contents_texture_manager->MemoryVisibleBytes(),
- contents_texture_manager->MemoryVisibleAndNearbyBytes(),
- contents_texture_manager->MemoryUseBytes());
+void SingleThreadProxy::UpdateRendererCapabilitiesOnImplThread() {
+ DCHECK(IsImplThread());
+ renderer_capabilities_for_main_thread_ =
+ layer_tree_host_impl_->GetRendererCapabilities().MainThreadCapabilities();
}
-bool SingleThreadProxy::IsInsideDraw() { return inside_draw_; }
-
void SingleThreadProxy::DidLoseOutputSurfaceOnImplThread() {
+ TRACE_EVENT0("cc", "SingleThreadProxy::DidLoseOutputSurfaceOnImplThread");
// Cause a commit so we can notice the lost context.
SetNeedsCommitOnImplThread();
client_->DidAbortSwapBuffers();
@@ -369,20 +316,38 @@ void SingleThreadProxy::DidSwapBuffersOnImplThread() {
client_->DidPostSwapBuffers();
}
-void SingleThreadProxy::OnSwapBuffersCompleteOnImplThread() {
+void SingleThreadProxy::DidSwapBuffersCompleteOnImplThread() {
+ TRACE_EVENT0("cc", "SingleThreadProxy::DidSwapBuffersCompleteOnImplThread");
client_->DidCompleteSwapBuffers();
}
// Called by the legacy scheduling path (e.g. where render_widget does the
// scheduling)
void SingleThreadProxy::CompositeImmediately(base::TimeTicks frame_begin_time) {
- gfx::Rect device_viewport_damage_rect;
+ TRACE_EVENT0("cc", "SingleThreadProxy::CompositeImmediately");
+ DCHECK(Proxy::IsMainThread());
+ DCHECK(!layer_tree_host_->output_surface_lost());
+
+ layer_tree_host_->AnimateLayers(frame_begin_time);
+
+ if (PrioritizedResourceManager* contents_texture_manager =
+ layer_tree_host_->contents_texture_manager()) {
+ contents_texture_manager->UnlinkAndClearEvictedBackings();
+ contents_texture_manager->SetMaxMemoryLimitBytes(
+ layer_tree_host_impl_->memory_allocation_limit_bytes());
+ contents_texture_manager->SetExternalPriorityCutoff(
+ layer_tree_host_impl_->memory_allocation_priority_cutoff());
+ }
+
+ scoped_ptr<ResourceUpdateQueue> queue =
+ make_scoped_ptr(new ResourceUpdateQueue);
+ layer_tree_host_->UpdateLayers(queue.get());
+ layer_tree_host_->WillCommit();
+ DoCommit(queue.Pass());
+ layer_tree_host_->DidBeginMainFrame();
LayerTreeHostImpl::FrameData frame;
- if (CommitAndComposite(frame_begin_time,
- device_viewport_damage_rect,
- false, // for_readback
- &frame)) {
+ if (DoComposite(frame_begin_time, &frame)) {
{
DebugScopedSetMainThreadBlocked main_thread_blocked(this);
DebugScopedSetImplThread impl(this);
@@ -426,56 +391,6 @@ void SingleThreadProxy::ForceSerializeOnSwapBuffers() {
}
}
-bool SingleThreadProxy::CommitAndComposite(
- base::TimeTicks frame_begin_time,
- gfx::Rect device_viewport_damage_rect,
- bool for_readback,
- LayerTreeHostImpl::FrameData* frame) {
- DCHECK(Proxy::IsMainThread());
-
- if (!layer_tree_host_->InitializeOutputSurfaceIfNeeded())
- return false;
-
- layer_tree_host_->AnimateLayers(frame_begin_time);
-
- if (PrioritizedResourceManager* contents_texture_manager =
- layer_tree_host_->contents_texture_manager()) {
- contents_texture_manager->UnlinkAndClearEvictedBackings();
- contents_texture_manager->SetMaxMemoryLimitBytes(
- layer_tree_host_impl_->memory_allocation_limit_bytes());
- contents_texture_manager->SetExternalPriorityCutoff(
- layer_tree_host_impl_->memory_allocation_priority_cutoff());
- }
-
- scoped_ptr<ResourceUpdateQueue> queue =
- make_scoped_ptr(new ResourceUpdateQueue);
- layer_tree_host_->UpdateLayers(queue.get());
-
- layer_tree_host_->WillCommit();
-
- scoped_refptr<ContextProvider> offscreen_context_provider;
- if (renderer_capabilities_for_main_thread_.using_offscreen_context3d &&
- layer_tree_host_->needs_offscreen_context()) {
- offscreen_context_provider =
- layer_tree_host_->client()->OffscreenContextProvider();
- if (offscreen_context_provider.get() &&
- !offscreen_context_provider->BindToCurrentThread())
- offscreen_context_provider = NULL;
-
- if (offscreen_context_provider.get())
- created_offscreen_context_provider_ = true;
- }
-
- DoCommit(queue.Pass());
- bool result = DoComposite(offscreen_context_provider,
- frame_begin_time,
- device_viewport_damage_rect,
- for_readback,
- frame);
- layer_tree_host_->DidBeginMainFrame();
- return result;
-}
-
bool SingleThreadProxy::ShouldComposite() const {
DCHECK(Proxy::IsImplThread());
return layer_tree_host_impl_->visible() &&
@@ -489,11 +404,9 @@ void SingleThreadProxy::UpdateBackgroundAnimateTicking() {
}
bool SingleThreadProxy::DoComposite(
- scoped_refptr<ContextProvider> offscreen_context_provider,
base::TimeTicks frame_begin_time,
- gfx::Rect device_viewport_damage_rect,
- bool for_readback,
LayerTreeHostImpl::FrameData* frame) {
+ TRACE_EVENT0("cc", "SingleThreadProxy::DoComposite");
DCHECK(!layer_tree_host_->output_surface_lost());
bool lost_output_surface = false;
@@ -501,27 +414,21 @@ bool SingleThreadProxy::DoComposite(
DebugScopedSetImplThread impl(this);
base::AutoReset<bool> mark_inside(&inside_draw_, true);
- layer_tree_host_impl_->SetOffscreenContextProvider(
- offscreen_context_provider);
-
- bool can_do_readback = layer_tree_host_impl_->renderer()->CanReadPixels();
-
// We guard PrepareToDraw() with CanDraw() because it always returns a valid
// frame, so can only be used when such a frame is possible. Since
// DrawLayers() depends on the result of PrepareToDraw(), it is guarded on
// CanDraw() as well.
- if (!ShouldComposite() || (for_readback && !can_do_readback)) {
+ if (!ShouldComposite()) {
UpdateBackgroundAnimateTicking();
return false;
}
layer_tree_host_impl_->Animate(
- layer_tree_host_impl_->CurrentFrameTimeTicks(),
- layer_tree_host_impl_->CurrentFrameTime());
+ layer_tree_host_impl_->CurrentFrameTimeTicks());
UpdateBackgroundAnimateTicking();
if (!layer_tree_host_impl_->IsContextLost()) {
- layer_tree_host_impl_->PrepareToDraw(frame, device_viewport_damage_rect);
+ layer_tree_host_impl_->PrepareToDraw(frame);
layer_tree_host_impl_->DrawLayers(frame, frame_begin_time);
layer_tree_host_impl_->DidDrawAllLayers(*frame);
}
@@ -534,10 +441,6 @@ bool SingleThreadProxy::DoComposite(
}
if (lost_output_surface) {
- ContextProvider* offscreen_contexts =
- layer_tree_host_impl_->offscreen_context_provider();
- if (offscreen_contexts)
- offscreen_contexts->VerifyContexts();
layer_tree_host_->DidLoseOutputSurface();
return false;
}
diff --git a/chromium/cc/trees/single_thread_proxy.h b/chromium/cc/trees/single_thread_proxy.h
index 463141c1748..7ad48b48bee 100644
--- a/chromium/cc/trees/single_thread_proxy.h
+++ b/chromium/cc/trees/single_thread_proxy.h
@@ -19,7 +19,8 @@ class ContextProvider;
class LayerTreeHost;
class LayerTreeHostSingleThreadClient;
-class SingleThreadProxy : public Proxy, LayerTreeHostImplClient {
+class CC_EXPORT SingleThreadProxy : public Proxy,
+ NON_EXPORTED_BASE(LayerTreeHostImplClient) {
public:
static scoped_ptr<Proxy> Create(
LayerTreeHost* layer_tree_host,
@@ -27,57 +28,64 @@ class SingleThreadProxy : public Proxy, LayerTreeHostImplClient {
virtual ~SingleThreadProxy();
// Proxy implementation
- virtual bool CompositeAndReadback(void* pixels, gfx::Rect rect) OVERRIDE;
virtual void FinishAllRendering() OVERRIDE;
virtual bool IsStarted() const OVERRIDE;
virtual void SetLayerTreeHostClientReady() OVERRIDE;
virtual void SetVisible(bool visible) OVERRIDE;
- virtual void CreateAndInitializeOutputSurface() OVERRIDE;
virtual const RendererCapabilities& GetRendererCapabilities() const OVERRIDE;
virtual void SetNeedsAnimate() OVERRIDE;
virtual void SetNeedsUpdateLayers() OVERRIDE;
virtual void SetNeedsCommit() OVERRIDE;
- virtual void SetNeedsRedraw(gfx::Rect damage_rect) OVERRIDE;
+ virtual void SetNeedsRedraw(const gfx::Rect& damage_rect) OVERRIDE;
virtual void SetNextCommitWaitsForActivation() OVERRIDE;
virtual void NotifyInputThrottledUntilCommit() OVERRIDE {}
virtual void SetDeferCommits(bool defer_commits) OVERRIDE;
virtual bool CommitRequested() const OVERRIDE;
virtual bool BeginMainFrameRequested() const OVERRIDE;
virtual void MainThreadHasStoppedFlinging() OVERRIDE {}
- virtual void Start(scoped_ptr<OutputSurface> first_output_surface) OVERRIDE;
+ virtual void Start() OVERRIDE;
virtual void Stop() OVERRIDE;
virtual size_t MaxPartialTextureUpdates() const OVERRIDE;
- virtual void AcquireLayerTextures() OVERRIDE {}
virtual void ForceSerializeOnSwapBuffers() OVERRIDE;
virtual scoped_ptr<base::Value> AsValue() const OVERRIDE;
virtual bool CommitPendingForTesting() OVERRIDE;
// LayerTreeHostImplClient implementation
+ virtual void UpdateRendererCapabilitiesOnImplThread() OVERRIDE;
virtual void DidLoseOutputSurfaceOnImplThread() OVERRIDE;
+ virtual void CommitVSyncParameters(base::TimeTicks timebase,
+ base::TimeDelta interval) OVERRIDE {}
+ virtual void SetEstimatedParentDrawTime(base::TimeDelta draw_time) OVERRIDE {}
+ virtual void SetMaxSwapsPendingOnImplThread(int max) OVERRIDE {}
virtual void DidSwapBuffersOnImplThread() OVERRIDE;
- virtual void OnSwapBuffersCompleteOnImplThread() OVERRIDE;
- virtual void BeginImplFrame(const BeginFrameArgs& args)
- OVERRIDE {}
+ virtual void DidSwapBuffersCompleteOnImplThread() OVERRIDE;
+ virtual void BeginFrame(const BeginFrameArgs& args) OVERRIDE {}
virtual void OnCanDrawStateChanged(bool can_draw) OVERRIDE;
virtual void NotifyReadyToActivate() OVERRIDE;
virtual void SetNeedsRedrawOnImplThread() OVERRIDE;
- virtual void SetNeedsRedrawRectOnImplThread(gfx::Rect dirty_rect) OVERRIDE;
+ virtual void SetNeedsRedrawRectOnImplThread(
+ const gfx::Rect& dirty_rect) OVERRIDE;
+ virtual void SetNeedsAnimateOnImplThread() OVERRIDE;
virtual void SetNeedsManageTilesOnImplThread() OVERRIDE;
virtual void DidInitializeVisibleTileOnImplThread() OVERRIDE;
virtual void SetNeedsCommitOnImplThread() OVERRIDE;
virtual void PostAnimationEventsToMainThreadOnImplThread(
- scoped_ptr<AnimationEventsVector> events,
- base::Time wall_clock_time) OVERRIDE;
+ scoped_ptr<AnimationEventsVector> events) OVERRIDE;
virtual bool ReduceContentsTextureMemoryOnImplThread(
size_t limit_bytes,
int priority_cutoff) OVERRIDE;
- virtual void SendManagedMemoryStats() OVERRIDE;
virtual bool IsInsideDraw() OVERRIDE;
virtual void RenewTreePriority() OVERRIDE {}
- virtual void RequestScrollbarAnimationOnImplThread(base::TimeDelta delay)
- OVERRIDE {}
+ virtual void PostDelayedScrollbarFadeOnImplThread(
+ const base::Closure& start_fade,
+ base::TimeDelta delay) OVERRIDE {}
virtual void DidActivatePendingTree() OVERRIDE {}
virtual void DidManageTiles() OVERRIDE {}
+ virtual void SetDebugState(const LayerTreeDebugState& debug_state) OVERRIDE {}
+
+ // Attempts to create the context and renderer synchronously. Calls
+ // LayerTreeHost::OnCreateAndInitializeOutputSurfaceAttempted with the result.
+ void CreateAndInitializeOutputSurface();
// Called by the legacy path where RenderWidget does the scheduling.
void CompositeImmediately(base::TimeTicks frame_begin_time);
@@ -86,16 +94,8 @@ class SingleThreadProxy : public Proxy, LayerTreeHostImplClient {
SingleThreadProxy(LayerTreeHost* layer_tree_host,
LayerTreeHostSingleThreadClient* client);
- void OnOutputSurfaceInitializeAttempted(bool success);
- bool CommitAndComposite(base::TimeTicks frame_begin_time,
- gfx::Rect device_viewport_damage_rect,
- bool for_readback,
- LayerTreeHostImpl::FrameData* frame);
void DoCommit(scoped_ptr<ResourceUpdateQueue> queue);
- bool DoComposite(scoped_refptr<ContextProvider> offscreen_context_provider,
- base::TimeTicks frame_begin_time,
- gfx::Rect device_viewport_damage_rect,
- bool for_readback,
+ bool DoComposite(base::TimeTicks frame_begin_time,
LayerTreeHostImpl::FrameData* frame);
void DidSwapFrame();
@@ -105,11 +105,6 @@ class SingleThreadProxy : public Proxy, LayerTreeHostImplClient {
// Accessed on main thread only.
LayerTreeHost* layer_tree_host_;
LayerTreeHostSingleThreadClient* client_;
- bool created_offscreen_context_provider_;
-
- // Holds the first output surface passed from Start. Should not be used for
- // anything else.
- scoped_ptr<OutputSurface> first_output_surface_;
// Used on the Thread, but checked on main thread during
// initialization/shutdown.
@@ -128,13 +123,13 @@ class SingleThreadProxy : public Proxy, LayerTreeHostImplClient {
class DebugScopedSetImplThread {
public:
explicit DebugScopedSetImplThread(Proxy* proxy) : proxy_(proxy) {
-#ifndef NDEBUG
+#if DCHECK_IS_ON
previous_value_ = proxy_->impl_thread_is_overridden_;
proxy_->SetCurrentThreadIsImplThread(true);
#endif
}
~DebugScopedSetImplThread() {
-#ifndef NDEBUG
+#if DCHECK_IS_ON
proxy_->SetCurrentThreadIsImplThread(previous_value_);
#endif
}
@@ -151,13 +146,13 @@ class DebugScopedSetImplThread {
class DebugScopedSetMainThread {
public:
explicit DebugScopedSetMainThread(Proxy* proxy) : proxy_(proxy) {
-#ifndef NDEBUG
+#if DCHECK_IS_ON
previous_value_ = proxy_->impl_thread_is_overridden_;
proxy_->SetCurrentThreadIsImplThread(false);
#endif
}
~DebugScopedSetMainThread() {
-#ifndef NDEBUG
+#if DCHECK_IS_ON
proxy_->SetCurrentThreadIsImplThread(previous_value_);
#endif
}
diff --git a/chromium/cc/trees/thread_proxy.cc b/chromium/cc/trees/thread_proxy.cc
index 2823182d590..e16adb9a550 100644
--- a/chromium/cc/trees/thread_proxy.cc
+++ b/chromium/cc/trees/thread_proxy.cc
@@ -4,21 +4,23 @@
#include "cc/trees/thread_proxy.h"
+#include <algorithm>
#include <string>
#include "base/auto_reset.h"
#include "base/bind.h"
#include "base/debug/trace_event.h"
+#include "base/debug/trace_event_synthetic_delay.h"
#include "base/metrics/histogram.h"
#include "cc/base/swap_promise.h"
#include "cc/debug/benchmark_instrumentation.h"
+#include "cc/debug/devtools_instrumentation.h"
#include "cc/input/input_handler.h"
#include "cc/output/context_provider.h"
#include "cc/output/output_surface.h"
#include "cc/quads/draw_quad.h"
#include "cc/resources/prioritized_resource_manager.h"
#include "cc/scheduler/delay_based_time_source.h"
-#include "cc/scheduler/frame_rate_controller.h"
#include "cc/scheduler/scheduler.h"
#include "cc/trees/blocking_task_runner.h"
#include "cc/trees/layer_tree_host.h"
@@ -30,15 +32,10 @@ namespace {
// Measured in seconds.
const double kSmoothnessTakesPriorityExpirationDelay = 0.25;
-const size_t kDurationHistorySize = 60;
-const double kCommitAndActivationDurationEstimationPercentile = 50.0;
-const double kDrawDurationEstimationPercentile = 100.0;
-const int kDrawDurationEstimatePaddingInMicroseconds = 0;
-
class SwapPromiseChecker {
public:
explicit SwapPromiseChecker(cc::LayerTreeHost* layer_tree_host)
- : layer_tree_host_(layer_tree_host) {}
+ : layer_tree_host_(layer_tree_host) {}
~SwapPromiseChecker() {
layer_tree_host_->BreakSwapPromises(cc::SwapPromise::COMMIT_FAILS);
@@ -52,13 +49,6 @@ class SwapPromiseChecker {
namespace cc {
-struct ThreadProxy::ReadbackRequest {
- CompletionEvent completion;
- bool success;
- void* pixels;
- gfx::Rect rect;
-};
-
struct ThreadProxy::CommitPendingRequest {
CompletionEvent completion;
bool commit_pending;
@@ -72,137 +62,79 @@ struct ThreadProxy::SchedulerStateRequest {
scoped_ptr<Proxy> ThreadProxy::Create(
LayerTreeHost* layer_tree_host,
scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner) {
- return make_scoped_ptr(
- new ThreadProxy(layer_tree_host, impl_task_runner)).PassAs<Proxy>();
+ return make_scoped_ptr(new ThreadProxy(layer_tree_host, impl_task_runner))
+ .PassAs<Proxy>();
}
ThreadProxy::ThreadProxy(
LayerTreeHost* layer_tree_host,
scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner)
: Proxy(impl_task_runner),
- animate_requested_(false),
- commit_requested_(false),
- commit_request_sent_to_impl_thread_(false),
- created_offscreen_context_provider_(false),
- layer_tree_host_unsafe_(layer_tree_host),
- contents_texture_manager_unsafe_(NULL),
- started_(false),
- textures_acquired_(true),
- in_composite_and_readback_(false),
- manage_tiles_pending_(false),
- commit_waits_for_activation_(false),
- inside_commit_(false),
- begin_main_frame_sent_completion_event_on_impl_thread_(NULL),
- readback_request_on_impl_thread_(NULL),
- commit_completion_event_on_impl_thread_(NULL),
- completion_event_for_commit_held_on_tree_activation_(NULL),
- texture_acquisition_completion_event_on_impl_thread_(NULL),
- next_frame_is_newly_committed_frame_on_impl_thread_(false),
- throttle_frame_production_(
- layer_tree_host->settings().throttle_frame_production),
- begin_impl_frame_scheduling_enabled_(
- layer_tree_host->settings().begin_impl_frame_scheduling_enabled),
- using_synchronous_renderer_compositor_(
- layer_tree_host->settings().using_synchronous_renderer_compositor),
- inside_draw_(false),
- can_cancel_commit_(true),
- defer_commits_(false),
- input_throttled_until_commit_(false),
- renew_tree_priority_on_impl_thread_pending_(false),
- draw_duration_history_(kDurationHistorySize),
- begin_main_frame_to_commit_duration_history_(kDurationHistorySize),
- commit_to_activate_duration_history_(kDurationHistorySize),
- weak_factory_on_impl_thread_(this),
- weak_factory_(this),
- layer_tree_host_id_(layer_tree_host->id()) {
+ main_thread_only_vars_unsafe_(this, layer_tree_host->id()),
+ main_thread_or_blocked_vars_unsafe_(layer_tree_host),
+ compositor_thread_vars_unsafe_(this, layer_tree_host->id()) {
TRACE_EVENT0("cc", "ThreadProxy::ThreadProxy");
DCHECK(IsMainThread());
DCHECK(this->layer_tree_host());
}
-ThreadProxy::~ThreadProxy() {
- TRACE_EVENT0("cc", "ThreadProxy::~ThreadProxy");
- DCHECK(IsMainThread());
- DCHECK(!started_);
-}
-
-bool ThreadProxy::CompositeAndReadback(void* pixels, gfx::Rect rect) {
- TRACE_EVENT0("cc", "ThreadProxy::CompositeAndReadback");
- DCHECK(IsMainThread());
- DCHECK(layer_tree_host());
-
- if (defer_commits_) {
- TRACE_EVENT0("cc", "CompositeAndReadback_DeferCommit");
- return false;
- }
-
- if (!layer_tree_host()->InitializeOutputSurfaceIfNeeded()) {
- TRACE_EVENT0("cc", "CompositeAndReadback_EarlyOut_LR_Uninitialized");
- return false;
- }
+ThreadProxy::MainThreadOnly::MainThreadOnly(ThreadProxy* proxy,
+ int layer_tree_host_id)
+ : layer_tree_host_id(layer_tree_host_id),
+ animate_requested(false),
+ commit_requested(false),
+ commit_request_sent_to_impl_thread(false),
+ started(false),
+ manage_tiles_pending(false),
+ can_cancel_commit(true),
+ defer_commits(false),
+ weak_factory(proxy) {}
- // Perform a synchronous commit with an associated readback.
- ReadbackRequest request;
- request.rect = rect;
- request.pixels = pixels;
- {
- DebugScopedSetMainThreadBlocked main_thread_blocked(this);
- CompletionEvent begin_main_frame_sent_completion;
- Proxy::ImplThreadTaskRunner()
- ->PostTask(FROM_HERE,
- base::Bind(&ThreadProxy::ForceCommitForReadbackOnImplThread,
- impl_thread_weak_ptr_,
- &begin_main_frame_sent_completion,
- &request));
- begin_main_frame_sent_completion.Wait();
- }
+ThreadProxy::MainThreadOnly::~MainThreadOnly() {}
- in_composite_and_readback_ = true;
- // This is the forced commit.
- // Note: The Impl thread also queues a separate BeginMainFrame on the
- // main thread, which will be called after this CompositeAndReadback
- // completes, to replace the forced commit.
- BeginMainFrame(scoped_ptr<BeginMainFrameAndCommitState>());
- in_composite_and_readback_ = false;
+ThreadProxy::MainThreadOrBlockedMainThread::MainThreadOrBlockedMainThread(
+ LayerTreeHost* host)
+ : layer_tree_host(host),
+ commit_waits_for_activation(false),
+ main_thread_inside_commit(false) {}
- // Composite and readback requires a second commit to undo any changes
- // that it made.
- can_cancel_commit_ = false;
+ThreadProxy::MainThreadOrBlockedMainThread::~MainThreadOrBlockedMainThread() {}
- request.completion.Wait();
- return request.success;
-}
-
-void ThreadProxy::ForceCommitForReadbackOnImplThread(
- CompletionEvent* begin_main_frame_sent_completion,
- ReadbackRequest* request) {
- TRACE_EVENT0("cc", "ThreadProxy::ForceCommitForReadbackOnImplThread");
- DCHECK(IsImplThread());
- DCHECK(!begin_main_frame_sent_completion_event_on_impl_thread_);
- DCHECK(!readback_request_on_impl_thread_);
-
- if (!layer_tree_host_impl_) {
- begin_main_frame_sent_completion->Signal();
- request->success = false;
- request->completion.Signal();
- return;
- }
-
- readback_request_on_impl_thread_ = request;
-
- scheduler_on_impl_thread_->SetNeedsForcedCommitForReadback();
- if (scheduler_on_impl_thread_->CommitPending()) {
- begin_main_frame_sent_completion->Signal();
- return;
- }
+PrioritizedResourceManager*
+ThreadProxy::MainThreadOrBlockedMainThread::contents_texture_manager() {
+ return layer_tree_host->contents_texture_manager();
+}
+
+ThreadProxy::CompositorThreadOnly::CompositorThreadOnly(ThreadProxy* proxy,
+ int layer_tree_host_id)
+ : layer_tree_host_id(layer_tree_host_id),
+ contents_texture_manager(NULL),
+ commit_completion_event(NULL),
+ completion_event_for_commit_held_on_tree_activation(NULL),
+ next_frame_is_newly_committed_frame(false),
+ inside_draw(false),
+ input_throttled_until_commit(false),
+ animations_frozen_until_next_draw(false),
+ did_commit_after_animating(false),
+ smoothness_priority_expiration_notifier(
+ proxy->ImplThreadTaskRunner(),
+ base::Bind(&ThreadProxy::RenewTreePriority, base::Unretained(proxy)),
+ base::TimeDelta::FromMilliseconds(
+ kSmoothnessTakesPriorityExpirationDelay * 1000)),
+ weak_factory(proxy) {
+}
+
+ThreadProxy::CompositorThreadOnly::~CompositorThreadOnly() {}
- begin_main_frame_sent_completion_event_on_impl_thread_ =
- begin_main_frame_sent_completion;
+ThreadProxy::~ThreadProxy() {
+ TRACE_EVENT0("cc", "ThreadProxy::~ThreadProxy");
+ DCHECK(IsMainThread());
+ DCHECK(!main().started);
}
void ThreadProxy::FinishAllRendering() {
DCHECK(Proxy::IsMainThread());
- DCHECK(!defer_commits_);
+ DCHECK(!main().defer_commits);
// Make sure all GL drawing is finished on the impl thread.
DebugScopedSetMainThreadBlocked main_thread_blocked(this);
@@ -217,7 +149,7 @@ void ThreadProxy::FinishAllRendering() {
bool ThreadProxy::IsStarted() const {
DCHECK(Proxy::IsMainThread());
- return started_;
+ return main().started;
}
void ThreadProxy::SetLayerTreeHostClientReady() {
@@ -230,7 +162,7 @@ void ThreadProxy::SetLayerTreeHostClientReady() {
void ThreadProxy::SetLayerTreeHostClientReadyOnImplThread() {
TRACE_EVENT0("cc", "ThreadProxy::SetLayerTreeHostClientReadyOnImplThread");
- scheduler_on_impl_thread_->SetCanStart();
+ impl().scheduler->SetCanStart();
}
void ThreadProxy::SetVisible(bool visible) {
@@ -250,94 +182,88 @@ void ThreadProxy::SetVisible(bool visible) {
void ThreadProxy::SetVisibleOnImplThread(CompletionEvent* completion,
bool visible) {
TRACE_EVENT0("cc", "ThreadProxy::SetVisibleOnImplThread");
- layer_tree_host_impl_->SetVisible(visible);
- scheduler_on_impl_thread_->SetVisible(visible);
+ impl().layer_tree_host_impl->SetVisible(visible);
+ impl().scheduler->SetVisible(visible);
UpdateBackgroundAnimateTicking();
completion->Signal();
}
void ThreadProxy::UpdateBackgroundAnimateTicking() {
- layer_tree_host_impl_->UpdateBackgroundAnimateTicking(
- !scheduler_on_impl_thread_->WillDrawIfNeeded() &&
- layer_tree_host_impl_->active_tree()->root_layer());
+ bool should_background_tick =
+ !impl().scheduler->WillDrawIfNeeded() &&
+ impl().layer_tree_host_impl->active_tree()->root_layer();
+ impl().layer_tree_host_impl->UpdateBackgroundAnimateTicking(
+ should_background_tick);
+ if (should_background_tick)
+ impl().animations_frozen_until_next_draw = false;
}
-void ThreadProxy::DoCreateAndInitializeOutputSurface() {
- TRACE_EVENT0("cc", "ThreadProxy::DoCreateAndInitializeOutputSurface");
+void ThreadProxy::DidLoseOutputSurface() {
+ TRACE_EVENT0("cc", "ThreadProxy::DidLoseOutputSurface");
DCHECK(IsMainThread());
+ layer_tree_host()->DidLoseOutputSurface();
- scoped_ptr<OutputSurface> output_surface = first_output_surface_.Pass();
- if (!output_surface)
- output_surface = layer_tree_host()->CreateOutputSurface();
+ {
+ DebugScopedSetMainThreadBlocked main_thread_blocked(this);
- RendererCapabilities capabilities;
- bool success = !!output_surface;
- if (!success) {
- OnOutputSurfaceInitializeAttempted(false, capabilities);
- return;
- }
+ // Return lost resources to their owners immediately.
+ BlockingTaskRunner::CapturePostTasks blocked;
- scoped_refptr<ContextProvider> offscreen_context_provider;
- if (created_offscreen_context_provider_) {
- offscreen_context_provider =
- layer_tree_host()->client()->OffscreenContextProvider();
- success = !!offscreen_context_provider.get();
- if (!success) {
- OnOutputSurfaceInitializeAttempted(false, capabilities);
- return;
- }
+ CompletionEvent completion;
+ Proxy::ImplThreadTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(&ThreadProxy::DeleteContentsTexturesOnImplThread,
+ impl_thread_weak_ptr_,
+ &completion));
+ completion.Wait();
}
+}
- success = false;
- {
- // Make a blocking call to InitializeOutputSurfaceOnImplThread. The results
- // of that call are pushed into the success and capabilities local
- // variables.
- CompletionEvent completion;
- DebugScopedSetMainThreadBlocked main_thread_blocked(this);
+void ThreadProxy::CreateAndInitializeOutputSurface() {
+ TRACE_EVENT0("cc", "ThreadProxy::DoCreateAndInitializeOutputSurface");
+ DCHECK(IsMainThread());
+ scoped_ptr<OutputSurface> output_surface =
+ layer_tree_host()->CreateOutputSurface();
+
+ if (output_surface) {
Proxy::ImplThreadTaskRunner()->PostTask(
FROM_HERE,
base::Bind(&ThreadProxy::InitializeOutputSurfaceOnImplThread,
impl_thread_weak_ptr_,
- &completion,
- base::Passed(&output_surface),
- offscreen_context_provider,
- &success,
- &capabilities));
- completion.Wait();
+ base::Passed(&output_surface)));
+ return;
}
- OnOutputSurfaceInitializeAttempted(success, capabilities);
+ DidInitializeOutputSurface(false, RendererCapabilities());
}
-void ThreadProxy::OnOutputSurfaceInitializeAttempted(
+void ThreadProxy::DidInitializeOutputSurface(
bool success,
const RendererCapabilities& capabilities) {
+ TRACE_EVENT0("cc", "ThreadProxy::DidInitializeOutputSurface");
DCHECK(IsMainThread());
- DCHECK(layer_tree_host());
+ main().renderer_capabilities_main_thread_copy = capabilities;
+ layer_tree_host()->OnCreateAndInitializeOutputSurfaceAttempted(success);
- if (success) {
- renderer_capabilities_main_thread_copy_ = capabilities;
+ if (!success) {
+ Proxy::MainThreadTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(&ThreadProxy::CreateAndInitializeOutputSurface,
+ main_thread_weak_ptr_));
}
+}
- LayerTreeHost::CreateResult result =
- layer_tree_host()->OnCreateAndInitializeOutputSurfaceAttempted(success);
- if (result == LayerTreeHost::CreateFailedButTryAgain) {
- if (!output_surface_creation_callback_.callback().is_null()) {
- Proxy::MainThreadTaskRunner()->PostTask(
- FROM_HERE, output_surface_creation_callback_.callback());
- }
- } else {
- output_surface_creation_callback_.Cancel();
- }
+void ThreadProxy::SetRendererCapabilitiesMainThreadCopy(
+ const RendererCapabilities& capabilities) {
+ main().renderer_capabilities_main_thread_copy = capabilities;
}
void ThreadProxy::SendCommitRequestToImplThreadIfNeeded() {
DCHECK(IsMainThread());
- if (commit_request_sent_to_impl_thread_)
+ if (main().commit_request_sent_to_impl_thread)
return;
- commit_request_sent_to_impl_thread_ = true;
+ main().commit_request_sent_to_impl_thread = true;
Proxy::ImplThreadTaskRunner()->PostTask(
FROM_HERE,
base::Bind(&ThreadProxy::SetNeedsCommitOnImplThread,
@@ -347,24 +273,23 @@ void ThreadProxy::SendCommitRequestToImplThreadIfNeeded() {
const RendererCapabilities& ThreadProxy::GetRendererCapabilities() const {
DCHECK(IsMainThread());
DCHECK(!layer_tree_host()->output_surface_lost());
- return renderer_capabilities_main_thread_copy_;
+ return main().renderer_capabilities_main_thread_copy;
}
void ThreadProxy::SetNeedsAnimate() {
DCHECK(IsMainThread());
- if (animate_requested_)
+ if (main().animate_requested)
return;
TRACE_EVENT0("cc", "ThreadProxy::SetNeedsAnimate");
- animate_requested_ = true;
- can_cancel_commit_ = false;
+ main().animate_requested = true;
SendCommitRequestToImplThreadIfNeeded();
}
void ThreadProxy::SetNeedsUpdateLayers() {
DCHECK(IsMainThread());
- if (commit_request_sent_to_impl_thread_)
+ if (main().commit_request_sent_to_impl_thread)
return;
TRACE_EVENT0("cc", "ThreadProxy::SetNeedsUpdateLayers");
@@ -374,143 +299,146 @@ void ThreadProxy::SetNeedsUpdateLayers() {
void ThreadProxy::SetNeedsCommit() {
DCHECK(IsMainThread());
// Unconditionally set here to handle SetNeedsCommit calls during a commit.
- can_cancel_commit_ = false;
+ main().can_cancel_commit = false;
- if (commit_requested_)
+ if (main().commit_requested)
return;
TRACE_EVENT0("cc", "ThreadProxy::SetNeedsCommit");
- commit_requested_ = true;
+ main().commit_requested = true;
SendCommitRequestToImplThreadIfNeeded();
}
-void ThreadProxy::DidLoseOutputSurfaceOnImplThread() {
+void ThreadProxy::UpdateRendererCapabilitiesOnImplThread() {
DCHECK(IsImplThread());
+ Proxy::MainThreadTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(&ThreadProxy::SetRendererCapabilitiesMainThreadCopy,
+ main_thread_weak_ptr_,
+ impl()
+ .layer_tree_host_impl->GetRendererCapabilities()
+ .MainThreadCapabilities()));
+}
+
+void ThreadProxy::DidLoseOutputSurfaceOnImplThread() {
TRACE_EVENT0("cc", "ThreadProxy::DidLoseOutputSurfaceOnImplThread");
+ DCHECK(IsImplThread());
CheckOutputSurfaceStatusOnImplThread();
}
void ThreadProxy::CheckOutputSurfaceStatusOnImplThread() {
- DCHECK(IsImplThread());
TRACE_EVENT0("cc", "ThreadProxy::CheckOutputSurfaceStatusOnImplThread");
- if (!layer_tree_host_impl_->IsContextLost())
+ DCHECK(IsImplThread());
+ if (!impl().layer_tree_host_impl->IsContextLost())
return;
- if (ContextProvider* offscreen_contexts =
- layer_tree_host_impl_->offscreen_context_provider())
- offscreen_contexts->VerifyContexts();
- scheduler_on_impl_thread_->DidLoseOutputSurface();
+ Proxy::MainThreadTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(&ThreadProxy::DidLoseOutputSurface, main_thread_weak_ptr_));
+ impl().scheduler->DidLoseOutputSurface();
+}
+
+void ThreadProxy::CommitVSyncParameters(base::TimeTicks timebase,
+ base::TimeDelta interval) {
+ impl().scheduler->CommitVSyncParameters(timebase, interval);
+}
+
+void ThreadProxy::SetEstimatedParentDrawTime(base::TimeDelta draw_time) {
+ impl().scheduler->SetEstimatedParentDrawTime(draw_time);
+}
+
+void ThreadProxy::SetMaxSwapsPendingOnImplThread(int max) {
+ impl().scheduler->SetMaxSwapsPending(max);
}
-void ThreadProxy::OnSwapBuffersCompleteOnImplThread() {
+void ThreadProxy::DidSwapBuffersOnImplThread() {
+ impl().scheduler->DidSwapBuffers();
+}
+
+void ThreadProxy::DidSwapBuffersCompleteOnImplThread() {
+ TRACE_EVENT0("cc", "ThreadProxy::DidSwapBuffersCompleteOnImplThread");
DCHECK(IsImplThread());
- TRACE_EVENT0("cc", "ThreadProxy::OnSwapBuffersCompleteOnImplThread");
+ impl().scheduler->DidSwapBuffersComplete();
Proxy::MainThreadTaskRunner()->PostTask(
FROM_HERE,
base::Bind(&ThreadProxy::DidCompleteSwapBuffers, main_thread_weak_ptr_));
}
-void ThreadProxy::SetNeedsBeginImplFrame(bool enable) {
- DCHECK(IsImplThread());
- TRACE_EVENT1("cc", "ThreadProxy::SetNeedsBeginImplFrame",
- "enable", enable);
- layer_tree_host_impl_->SetNeedsBeginImplFrame(enable);
+void ThreadProxy::SetNeedsBeginFrame(bool enable) {
+ TRACE_EVENT1("cc", "ThreadProxy::SetNeedsBeginFrame", "enable", enable);
+ impl().layer_tree_host_impl->SetNeedsBeginFrame(enable);
UpdateBackgroundAnimateTicking();
}
-void ThreadProxy::BeginImplFrame(const BeginFrameArgs& args) {
- DCHECK(IsImplThread());
- TRACE_EVENT0("cc", "ThreadProxy::BeginImplFrame");
-
- // Sample the frame time now. This time will be used for updating animations
- // when we draw.
- layer_tree_host_impl_->CurrentFrameTimeTicks();
+void ThreadProxy::BeginFrame(const BeginFrameArgs& args) {
+ impl().scheduler->BeginFrame(args);
+}
- scheduler_on_impl_thread_->BeginImplFrame(args);
+void ThreadProxy::WillBeginImplFrame(const BeginFrameArgs& args) {
+ impl().layer_tree_host_impl->WillBeginImplFrame(args);
}
void ThreadProxy::OnCanDrawStateChanged(bool can_draw) {
- DCHECK(IsImplThread());
TRACE_EVENT1(
"cc", "ThreadProxy::OnCanDrawStateChanged", "can_draw", can_draw);
- scheduler_on_impl_thread_->SetCanDraw(can_draw);
+ DCHECK(IsImplThread());
+ impl().scheduler->SetCanDraw(can_draw);
UpdateBackgroundAnimateTicking();
}
void ThreadProxy::NotifyReadyToActivate() {
TRACE_EVENT0("cc", "ThreadProxy::NotifyReadyToActivate");
- scheduler_on_impl_thread_->NotifyReadyToActivate();
+ impl().scheduler->NotifyReadyToActivate();
}
void ThreadProxy::SetNeedsCommitOnImplThread() {
- DCHECK(IsImplThread());
TRACE_EVENT0("cc", "ThreadProxy::SetNeedsCommitOnImplThread");
- scheduler_on_impl_thread_->SetNeedsCommit();
+ DCHECK(IsImplThread());
+ impl().scheduler->SetNeedsCommit();
}
void ThreadProxy::PostAnimationEventsToMainThreadOnImplThread(
- scoped_ptr<AnimationEventsVector> events,
- base::Time wall_clock_time) {
- DCHECK(IsImplThread());
+ scoped_ptr<AnimationEventsVector> events) {
TRACE_EVENT0("cc",
"ThreadProxy::PostAnimationEventsToMainThreadOnImplThread");
+ DCHECK(IsImplThread());
Proxy::MainThreadTaskRunner()->PostTask(
FROM_HERE,
base::Bind(&ThreadProxy::SetAnimationEvents,
main_thread_weak_ptr_,
- base::Passed(&events),
- wall_clock_time));
+ base::Passed(&events)));
}
bool ThreadProxy::ReduceContentsTextureMemoryOnImplThread(size_t limit_bytes,
int priority_cutoff) {
DCHECK(IsImplThread());
- if (!contents_texture_manager_on_impl_thread())
+ if (!impl().contents_texture_manager)
return false;
- if (!layer_tree_host_impl_->resource_provider())
+ if (!impl().layer_tree_host_impl->resource_provider())
return false;
- bool reduce_result = contents_texture_manager_on_impl_thread()->
- ReduceMemoryOnImplThread(limit_bytes,
- priority_cutoff,
- layer_tree_host_impl_->resource_provider());
+ bool reduce_result =
+ impl().contents_texture_manager->ReduceMemoryOnImplThread(
+ limit_bytes,
+ priority_cutoff,
+ impl().layer_tree_host_impl->resource_provider());
if (!reduce_result)
return false;
// The texture upload queue may reference textures that were just purged,
// clear them from the queue.
- if (current_resource_update_controller_on_impl_thread_) {
- current_resource_update_controller_on_impl_thread_->
- DiscardUploadsToEvictedResources();
+ if (impl().current_resource_update_controller) {
+ impl()
+ .current_resource_update_controller->DiscardUploadsToEvictedResources();
}
return true;
}
-void ThreadProxy::SendManagedMemoryStats() {
- DCHECK(IsImplThread());
- if (!layer_tree_host_impl_)
- return;
- if (!contents_texture_manager_on_impl_thread())
- return;
-
- // If we are using impl-side painting, then SendManagedMemoryStats is called
- // directly after the tile manager's manage function, and doesn't need to
- // interact with main thread's layer tree.
- if (layer_tree_host_impl_->settings().impl_side_painting)
- return;
-
- layer_tree_host_impl_->SendManagedMemoryStats(
- contents_texture_manager_on_impl_thread()->MemoryVisibleBytes(),
- contents_texture_manager_on_impl_thread()->
- MemoryVisibleAndNearbyBytes(),
- contents_texture_manager_on_impl_thread()->MemoryUseBytes());
-}
+bool ThreadProxy::IsInsideDraw() { return impl().inside_draw; }
-bool ThreadProxy::IsInsideDraw() { return inside_draw_; }
-
-void ThreadProxy::SetNeedsRedraw(gfx::Rect damage_rect) {
- DCHECK(IsMainThread());
+void ThreadProxy::SetNeedsRedraw(const gfx::Rect& damage_rect) {
TRACE_EVENT0("cc", "ThreadProxy::SetNeedsRedraw");
+ DCHECK(IsMainThread());
Proxy::ImplThreadTaskRunner()->PostTask(
FROM_HERE,
base::Bind(&ThreadProxy::SetNeedsRedrawRectOnImplThread,
@@ -520,52 +448,58 @@ void ThreadProxy::SetNeedsRedraw(gfx::Rect damage_rect) {
void ThreadProxy::SetNextCommitWaitsForActivation() {
DCHECK(IsMainThread());
- DCHECK(!inside_commit_);
- commit_waits_for_activation_ = true;
+ DCHECK(!blocked_main().main_thread_inside_commit);
+ blocked_main().commit_waits_for_activation = true;
}
void ThreadProxy::SetDeferCommits(bool defer_commits) {
DCHECK(IsMainThread());
- DCHECK_NE(defer_commits_, defer_commits);
- defer_commits_ = defer_commits;
+ DCHECK_NE(main().defer_commits, defer_commits);
+ main().defer_commits = defer_commits;
- if (defer_commits_)
+ if (main().defer_commits)
TRACE_EVENT_ASYNC_BEGIN0("cc", "ThreadProxy::SetDeferCommits", this);
else
TRACE_EVENT_ASYNC_END0("cc", "ThreadProxy::SetDeferCommits", this);
- if (!defer_commits_ && pending_deferred_commit_)
+ if (!main().defer_commits && main().pending_deferred_commit)
Proxy::MainThreadTaskRunner()->PostTask(
FROM_HERE,
base::Bind(&ThreadProxy::BeginMainFrame,
main_thread_weak_ptr_,
- base::Passed(&pending_deferred_commit_)));
+ base::Passed(&main().pending_deferred_commit)));
}
bool ThreadProxy::CommitRequested() const {
DCHECK(IsMainThread());
- return commit_requested_;
+ return main().commit_requested;
}
bool ThreadProxy::BeginMainFrameRequested() const {
DCHECK(IsMainThread());
- return commit_request_sent_to_impl_thread_;
+ return main().commit_request_sent_to_impl_thread;
}
void ThreadProxy::SetNeedsRedrawOnImplThread() {
- DCHECK(IsImplThread());
TRACE_EVENT0("cc", "ThreadProxy::SetNeedsRedrawOnImplThread");
- scheduler_on_impl_thread_->SetNeedsRedraw();
+ DCHECK(IsImplThread());
+ impl().scheduler->SetNeedsRedraw();
+}
+
+void ThreadProxy::SetNeedsAnimateOnImplThread() {
+ TRACE_EVENT0("cc", "ThreadProxy::SetNeedsAnimateOnImplThread");
+ DCHECK(IsImplThread());
+ impl().scheduler->SetNeedsAnimate();
}
void ThreadProxy::SetNeedsManageTilesOnImplThread() {
DCHECK(IsImplThread());
- scheduler_on_impl_thread_->SetNeedsManageTiles();
+ impl().scheduler->SetNeedsManageTiles();
}
-void ThreadProxy::SetNeedsRedrawRectOnImplThread(gfx::Rect damage_rect) {
+void ThreadProxy::SetNeedsRedrawRectOnImplThread(const gfx::Rect& damage_rect) {
DCHECK(IsImplThread());
- layer_tree_host_impl_->SetViewportDamage(damage_rect);
+ impl().layer_tree_host_impl->SetViewportDamage(damage_rect);
SetNeedsRedrawOnImplThread();
}
@@ -573,19 +507,17 @@ void ThreadProxy::SetSwapUsedIncompleteTileOnImplThread(
bool used_incomplete_tile) {
DCHECK(IsImplThread());
if (used_incomplete_tile) {
- TRACE_EVENT_INSTANT0(
- "cc",
- "ThreadProxy::SetSwapUsedIncompleteTileOnImplThread",
- TRACE_EVENT_SCOPE_THREAD);
+ TRACE_EVENT_INSTANT0("cc",
+ "ThreadProxy::SetSwapUsedIncompleteTileOnImplThread",
+ TRACE_EVENT_SCOPE_THREAD);
}
- scheduler_on_impl_thread_->SetSwapUsedIncompleteTile(
- used_incomplete_tile);
+ impl().scheduler->SetSwapUsedIncompleteTile(used_incomplete_tile);
}
void ThreadProxy::DidInitializeVisibleTileOnImplThread() {
- DCHECK(IsImplThread());
TRACE_EVENT0("cc", "ThreadProxy::DidInitializeVisibleTileOnImplThread");
- scheduler_on_impl_thread_->SetNeedsRedraw();
+ DCHECK(IsImplThread());
+ impl().scheduler->SetNeedsRedraw();
}
void ThreadProxy::MainThreadHasStoppedFlinging() {
@@ -598,7 +530,7 @@ void ThreadProxy::MainThreadHasStoppedFlinging() {
void ThreadProxy::MainThreadHasStoppedFlingingOnImplThread() {
DCHECK(IsImplThread());
- layer_tree_host_impl_->MainThreadHasStoppedFlinging();
+ impl().layer_tree_host_impl->MainThreadHasStoppedFlinging();
}
void ThreadProxy::NotifyInputThrottledUntilCommit() {
@@ -610,41 +542,55 @@ void ThreadProxy::NotifyInputThrottledUntilCommit() {
true));
}
-void ThreadProxy::SetInputThrottledUntilCommitOnImplThread(
- bool is_throttled) {
+void ThreadProxy::SetInputThrottledUntilCommitOnImplThread(bool is_throttled) {
DCHECK(IsImplThread());
- if (is_throttled == input_throttled_until_commit_)
+ if (is_throttled == impl().input_throttled_until_commit)
return;
- input_throttled_until_commit_ = is_throttled;
+ impl().input_throttled_until_commit = is_throttled;
RenewTreePriority();
}
LayerTreeHost* ThreadProxy::layer_tree_host() {
- DCHECK(IsMainThread() || IsMainThreadBlocked());
- return layer_tree_host_unsafe_;
+ return blocked_main().layer_tree_host;
}
const LayerTreeHost* ThreadProxy::layer_tree_host() const {
+ return blocked_main().layer_tree_host;
+}
+
+ThreadProxy::MainThreadOnly& ThreadProxy::main() {
+ DCHECK(IsMainThread());
+ return main_thread_only_vars_unsafe_;
+}
+const ThreadProxy::MainThreadOnly& ThreadProxy::main() const {
+ DCHECK(IsMainThread());
+ return main_thread_only_vars_unsafe_;
+}
+
+ThreadProxy::MainThreadOrBlockedMainThread& ThreadProxy::blocked_main() {
DCHECK(IsMainThread() || IsMainThreadBlocked());
- return layer_tree_host_unsafe_;
+ return main_thread_or_blocked_vars_unsafe_;
}
-PrioritizedResourceManager*
-ThreadProxy::contents_texture_manager_on_main_thread() {
+const ThreadProxy::MainThreadOrBlockedMainThread& ThreadProxy::blocked_main()
+ const {
DCHECK(IsMainThread() || IsMainThreadBlocked());
- return layer_tree_host()->contents_texture_manager();
+ return main_thread_or_blocked_vars_unsafe_;
}
-PrioritizedResourceManager*
-ThreadProxy::contents_texture_manager_on_impl_thread() {
+ThreadProxy::CompositorThreadOnly& ThreadProxy::impl() {
DCHECK(IsImplThread());
- return contents_texture_manager_unsafe_;
+ return compositor_thread_vars_unsafe_;
}
-void ThreadProxy::Start(scoped_ptr<OutputSurface> first_output_surface) {
+const ThreadProxy::CompositorThreadOnly& ThreadProxy::impl() const {
+ DCHECK(IsImplThread());
+ return compositor_thread_vars_unsafe_;
+}
+
+void ThreadProxy::Start() {
DCHECK(IsMainThread());
DCHECK(Proxy::HasImplThread());
- DCHECK(first_output_surface);
// Create LayerTreeHostImpl.
DebugScopedSetMainThreadBlocked main_thread_blocked(this);
@@ -656,16 +602,15 @@ void ThreadProxy::Start(scoped_ptr<OutputSurface> first_output_surface) {
&completion));
completion.Wait();
- main_thread_weak_ptr_ = weak_factory_.GetWeakPtr();
- first_output_surface_ = first_output_surface.Pass();
+ main_thread_weak_ptr_ = main().weak_factory.GetWeakPtr();
- started_ = true;
+ main().started = true;
}
void ThreadProxy::Stop() {
TRACE_EVENT0("cc", "ThreadProxy::Stop");
DCHECK(IsMainThread());
- DCHECK(started_);
+ DCHECK(main().started);
// Synchronously finishes pending GL operations and deletes the impl.
// The two steps are done as separate post tasks, so that tasks posted
@@ -694,12 +639,9 @@ void ThreadProxy::Stop() {
completion.Wait();
}
- weak_factory_.InvalidateWeakPtrs();
-
- DCHECK(!layer_tree_host_impl_.get()); // verify that the impl deleted.
- contents_texture_manager_unsafe_ = NULL;
- layer_tree_host_unsafe_ = NULL;
- started_ = false;
+ main().weak_factory.InvalidateWeakPtrs();
+ blocked_main().layer_tree_host = NULL;
+ main().started = false;
}
void ThreadProxy::ForceSerializeOnSwapBuffers() {
@@ -715,15 +657,29 @@ void ThreadProxy::ForceSerializeOnSwapBuffers() {
void ThreadProxy::ForceSerializeOnSwapBuffersOnImplThread(
CompletionEvent* completion) {
- if (layer_tree_host_impl_->renderer())
- layer_tree_host_impl_->renderer()->DoNoOp();
+ if (impl().layer_tree_host_impl->renderer())
+ impl().layer_tree_host_impl->renderer()->DoNoOp();
completion->Signal();
}
+void ThreadProxy::SetDebugState(const LayerTreeDebugState& debug_state) {
+ Proxy::ImplThreadTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(&ThreadProxy::SetDebugStateOnImplThread,
+ impl_thread_weak_ptr_,
+ debug_state));
+}
+
+void ThreadProxy::SetDebugStateOnImplThread(
+ const LayerTreeDebugState& debug_state) {
+ DCHECK(IsImplThread());
+ impl().scheduler->SetContinuousPainting(debug_state.continuous_painting);
+}
+
void ThreadProxy::FinishAllRenderingOnImplThread(CompletionEvent* completion) {
TRACE_EVENT0("cc", "ThreadProxy::FinishAllRenderingOnImplThread");
DCHECK(IsImplThread());
- layer_tree_host_impl_->FinishAllRendering();
+ impl().layer_tree_host_impl->FinishAllRendering();
completion->Signal();
}
@@ -732,44 +688,40 @@ void ThreadProxy::ScheduledActionSendBeginMainFrame() {
scoped_ptr<BeginMainFrameAndCommitState> begin_main_frame_state(
new BeginMainFrameAndCommitState);
begin_main_frame_state->monotonic_frame_begin_time =
- layer_tree_host_impl_->CurrentPhysicalTimeTicks();
+ impl().layer_tree_host_impl->CurrentFrameTimeTicks();
begin_main_frame_state->scroll_info =
- layer_tree_host_impl_->ProcessScrollDeltas();
+ impl().layer_tree_host_impl->ProcessScrollDeltas();
- if (!layer_tree_host_impl_->settings().impl_side_painting) {
- DCHECK_GT(layer_tree_host_impl_->memory_allocation_limit_bytes(), 0u);
+ if (!impl().layer_tree_host_impl->settings().impl_side_painting) {
+ DCHECK_GT(impl().layer_tree_host_impl->memory_allocation_limit_bytes(), 0u);
}
begin_main_frame_state->memory_allocation_limit_bytes =
- layer_tree_host_impl_->memory_allocation_limit_bytes();
+ impl().layer_tree_host_impl->memory_allocation_limit_bytes();
begin_main_frame_state->memory_allocation_priority_cutoff =
- layer_tree_host_impl_->memory_allocation_priority_cutoff();
+ impl().layer_tree_host_impl->memory_allocation_priority_cutoff();
begin_main_frame_state->evicted_ui_resources =
- layer_tree_host_impl_->EvictedUIResourcesExist();
+ impl().layer_tree_host_impl->EvictedUIResourcesExist();
Proxy::MainThreadTaskRunner()->PostTask(
FROM_HERE,
base::Bind(&ThreadProxy::BeginMainFrame,
main_thread_weak_ptr_,
base::Passed(&begin_main_frame_state)));
-
- if (begin_main_frame_sent_completion_event_on_impl_thread_) {
- begin_main_frame_sent_completion_event_on_impl_thread_->Signal();
- begin_main_frame_sent_completion_event_on_impl_thread_ = NULL;
- }
- begin_main_frame_sent_time_ = base::TimeTicks::HighResNow();
+ devtools_instrumentation::DidRequestMainThreadFrame(
+ impl().layer_tree_host_id);
+ impl().timing_history.DidBeginMainFrame();
}
void ThreadProxy::BeginMainFrame(
scoped_ptr<BeginMainFrameAndCommitState> begin_main_frame_state) {
TRACE_EVENT0("cc", "ThreadProxy::BeginMainFrame");
+ TRACE_EVENT_SYNTHETIC_DELAY_BEGIN("cc.BeginMainFrame");
DCHECK(IsMainThread());
- if (!layer_tree_host())
- return;
-
- if (defer_commits_) {
- pending_deferred_commit_ = begin_main_frame_state.Pass();
+ if (main().defer_commits) {
+ main().pending_deferred_commit = begin_main_frame_state.Pass();
layer_tree_host()->DidDeferCommit();
- TRACE_EVENT0("cc", "EarlyOut_DeferCommits");
+ TRACE_EVENT_INSTANT0(
+ "cc", "EarlyOut_DeferCommits", TRACE_EVENT_SCOPE_THREAD);
return;
}
@@ -778,24 +730,12 @@ void ThreadProxy::BeginMainFrame(
// swap promises.
SwapPromiseChecker swap_promise_checker(layer_tree_host());
- // Do not notify the impl thread of commit requests that occur during
- // the apply/animate/layout part of the BeginMainFrameAndCommit process since
- // those commit requests will get painted immediately. Once we have done
- // the paint, commit_requested_ will be set to false to allow new commit
- // requests to be scheduled.
- commit_requested_ = true;
- commit_request_sent_to_impl_thread_ = true;
-
- // On the other hand, the AnimationRequested flag needs to be cleared
- // here so that any animation requests generated by the apply or animate
- // callbacks will trigger another frame.
- animate_requested_ = false;
-
- if (!in_composite_and_readback_ && !layer_tree_host()->visible()) {
- commit_requested_ = false;
- commit_request_sent_to_impl_thread_ = false;
+ main().commit_requested = false;
+ main().commit_request_sent_to_impl_thread = false;
+ main().animate_requested = false;
- TRACE_EVENT0("cc", "EarlyOut_NotVisible");
+ if (!layer_tree_host()->visible()) {
+ TRACE_EVENT_INSTANT0("cc", "EarlyOut_NotVisible", TRACE_EVENT_SCOPE_THREAD);
bool did_handle = false;
Proxy::ImplThreadTaskRunner()->PostTask(
FROM_HERE,
@@ -805,68 +745,88 @@ void ThreadProxy::BeginMainFrame(
return;
}
- if (begin_main_frame_state) {
- layer_tree_host()->ApplyScrollAndScale(
- *begin_main_frame_state->scroll_info);
+ if (layer_tree_host()->output_surface_lost()) {
+ TRACE_EVENT_INSTANT0(
+ "cc", "EarlyOut_OutputSurfaceLost", TRACE_EVENT_SCOPE_THREAD);
+ bool did_handle = false;
+ Proxy::ImplThreadTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(&ThreadProxy::BeginMainFrameAbortedOnImplThread,
+ impl_thread_weak_ptr_,
+ did_handle));
+ return;
}
+ // Do not notify the impl thread of commit requests that occur during
+ // the apply/animate/layout part of the BeginMainFrameAndCommit process since
+ // those commit requests will get painted immediately. Once we have done
+ // the paint, main().commit_requested will be set to false to allow new commit
+ // requests to be scheduled.
+ // On the other hand, the animate_requested flag should remain cleared
+ // here so that any animation requests generated by the apply or animate
+ // callbacks will trigger another frame.
+ main().commit_requested = true;
+ main().commit_request_sent_to_impl_thread = true;
+
+ layer_tree_host()->ApplyScrollAndScale(*begin_main_frame_state->scroll_info);
+
layer_tree_host()->WillBeginMainFrame();
- if (begin_main_frame_state) {
- layer_tree_host()->UpdateClientAnimations(
- begin_main_frame_state->monotonic_frame_begin_time);
- layer_tree_host()->AnimateLayers(
- begin_main_frame_state->monotonic_frame_begin_time);
- }
+ layer_tree_host()->UpdateClientAnimations(
+ begin_main_frame_state->monotonic_frame_begin_time);
+ layer_tree_host()->AnimateLayers(
+ begin_main_frame_state->monotonic_frame_begin_time);
+ blocked_main().last_monotonic_frame_begin_time =
+ begin_main_frame_state->monotonic_frame_begin_time;
// Unlink any backings that the impl thread has evicted, so that we know to
// re-paint them in UpdateLayers.
- if (contents_texture_manager_on_main_thread()) {
- contents_texture_manager_on_main_thread()->
- UnlinkAndClearEvictedBackings();
-
- if (begin_main_frame_state) {
- contents_texture_manager_on_main_thread()->SetMaxMemoryLimitBytes(
- begin_main_frame_state->memory_allocation_limit_bytes);
- contents_texture_manager_on_main_thread()->SetExternalPriorityCutoff(
- begin_main_frame_state->memory_allocation_priority_cutoff);
- }
+ if (blocked_main().contents_texture_manager()) {
+ blocked_main().contents_texture_manager()->UnlinkAndClearEvictedBackings();
+
+ blocked_main().contents_texture_manager()->SetMaxMemoryLimitBytes(
+ begin_main_frame_state->memory_allocation_limit_bytes);
+ blocked_main().contents_texture_manager()->SetExternalPriorityCutoff(
+ begin_main_frame_state->memory_allocation_priority_cutoff);
}
// Recreate all UI resources if there were evicted UI resources when the impl
// thread initiated the commit.
- bool evicted_ui_resources = begin_main_frame_state
- ? begin_main_frame_state->evicted_ui_resources
- : false;
- if (evicted_ui_resources)
- layer_tree_host()->RecreateUIResources();
+ if (begin_main_frame_state->evicted_ui_resources)
+ layer_tree_host()->RecreateUIResources();
layer_tree_host()->Layout();
+ TRACE_EVENT_SYNTHETIC_DELAY_END("cc.BeginMainFrame");
// Clear the commit flag after updating animations and layout here --- objects
// that only layout when painted will trigger another SetNeedsCommit inside
// UpdateLayers.
- commit_requested_ = false;
- commit_request_sent_to_impl_thread_ = false;
+ main().commit_requested = false;
+ main().commit_request_sent_to_impl_thread = false;
bool can_cancel_this_commit =
- can_cancel_commit_ &&
- !in_composite_and_readback_ &&
- !evicted_ui_resources;
- can_cancel_commit_ = true;
+ main().can_cancel_commit && !begin_main_frame_state->evicted_ui_resources;
+ main().can_cancel_commit = true;
scoped_ptr<ResourceUpdateQueue> queue =
make_scoped_ptr(new ResourceUpdateQueue);
bool updated = layer_tree_host()->UpdateLayers(queue.get());
- // Once single buffered layers are committed, they cannot be modified until
- // they are drawn by the impl thread.
- textures_acquired_ = false;
-
layer_tree_host()->WillCommit();
+ // Before calling animate, we set main().animate_requested to false. If it is
+ // true now, it means SetNeedAnimate was called again, but during a state when
+ // main().commit_request_sent_to_impl_thread = true. We need to force that
+ // call to happen again now so that the commit request is sent to the impl
+ // thread.
+ if (main().animate_requested) {
+ // Forces SetNeedsAnimate to consider posting a commit task.
+ main().animate_requested = false;
+ SetNeedsAnimate();
+ }
+
if (!updated && can_cancel_this_commit) {
- TRACE_EVENT0("cc", "EarlyOut_NoUpdates");
+ TRACE_EVENT_INSTANT0("cc", "EarlyOut_NoUpdates", TRACE_EVENT_SCOPE_THREAD);
bool did_handle = true;
Proxy::ImplThreadTaskRunner()->PostTask(
FROM_HERE,
@@ -882,25 +842,6 @@ void ThreadProxy::BeginMainFrame(
return;
}
- // Before calling animate, we set animate_requested_ to false. If it is true
- // now, it means SetNeedAnimate was called again, but during a state when
- // commit_request_sent_to_impl_thread_ = true. We need to force that call to
- // happen again now so that the commit request is sent to the impl thread.
- if (animate_requested_) {
- // Forces SetNeedsAnimate to consider posting a commit task.
- animate_requested_ = false;
- SetNeedsAnimate();
- }
-
- scoped_refptr<ContextProvider> offscreen_context_provider;
- if (renderer_capabilities_main_thread_copy_.using_offscreen_context3d &&
- layer_tree_host()->needs_offscreen_context()) {
- offscreen_context_provider =
- layer_tree_host()->client()->OffscreenContextProvider();
- if (offscreen_context_provider.get())
- created_offscreen_context_provider_ = true;
- }
-
// Notify the impl thread that the main thread is ready to commit. This will
// begin the commit process, which is blocking from the main thread's
// point of view, but asynchronously performed on the impl thread,
@@ -921,8 +862,7 @@ void ThreadProxy::BeginMainFrame(
base::Bind(&ThreadProxy::StartCommitOnImplThread,
impl_thread_weak_ptr_,
&completion,
- queue.release(),
- offscreen_context_provider));
+ queue.release()));
completion.Wait();
RenderingStatsInstrumentation* stats_instrumentation =
@@ -936,42 +876,38 @@ void ThreadProxy::BeginMainFrame(
layer_tree_host()->DidBeginMainFrame();
}
-void ThreadProxy::StartCommitOnImplThread(
- CompletionEvent* completion,
- ResourceUpdateQueue* raw_queue,
- scoped_refptr<ContextProvider> offscreen_context_provider) {
- scoped_ptr<ResourceUpdateQueue> queue(raw_queue);
-
+void ThreadProxy::StartCommitOnImplThread(CompletionEvent* completion,
+ ResourceUpdateQueue* raw_queue) {
TRACE_EVENT0("cc", "ThreadProxy::StartCommitOnImplThread");
- DCHECK(!commit_completion_event_on_impl_thread_);
+ DCHECK(!impl().commit_completion_event);
DCHECK(IsImplThread() && IsMainThreadBlocked());
- DCHECK(scheduler_on_impl_thread_);
- DCHECK(scheduler_on_impl_thread_->CommitPending());
+ DCHECK(impl().scheduler);
+ DCHECK(impl().scheduler->CommitPending());
- if (!layer_tree_host_impl_) {
- TRACE_EVENT0("cc", "EarlyOut_NoLayerTree");
+ if (!impl().layer_tree_host_impl) {
+ TRACE_EVENT_INSTANT0(
+ "cc", "EarlyOut_NoLayerTree", TRACE_EVENT_SCOPE_THREAD);
completion->Signal();
return;
}
- if (offscreen_context_provider.get())
- offscreen_context_provider->BindToCurrentThread();
- layer_tree_host_impl_->SetOffscreenContextProvider(
- offscreen_context_provider);
+ // Ideally, we should inform to impl thread when BeginMainFrame is started.
+ // But, we can avoid a PostTask in here.
+ impl().scheduler->NotifyBeginMainFrameStarted();
+
+ scoped_ptr<ResourceUpdateQueue> queue(raw_queue);
- if (contents_texture_manager_unsafe_) {
- DCHECK_EQ(contents_texture_manager_unsafe_,
- contents_texture_manager_on_main_thread());
+ if (impl().contents_texture_manager) {
+ DCHECK_EQ(impl().contents_texture_manager,
+ blocked_main().contents_texture_manager());
} else {
// Cache this pointer that was created on the main thread side to avoid a
// data race between creating it and using it on the compositor thread.
- contents_texture_manager_unsafe_ =
- contents_texture_manager_on_main_thread();
+ impl().contents_texture_manager = blocked_main().contents_texture_manager();
}
- if (contents_texture_manager_on_main_thread()) {
- if (contents_texture_manager_on_main_thread()->
- LinkedEvictedBackingsExist()) {
+ if (impl().contents_texture_manager) {
+ if (impl().contents_texture_manager->LinkedEvictedBackingsExist()) {
// Clear any uploads we were making to textures linked to evicted
// resources
queue->ClearUploadsToEvictedResources();
@@ -980,132 +916,137 @@ void ThreadProxy::StartCommitOnImplThread(
SetNeedsCommitOnImplThread();
}
- contents_texture_manager_on_main_thread()->
- PushTexturePrioritiesToBackings();
+ impl().contents_texture_manager->PushTexturePrioritiesToBackings();
}
- commit_completion_event_on_impl_thread_ = completion;
- current_resource_update_controller_on_impl_thread_ =
- ResourceUpdateController::Create(
- this,
- Proxy::ImplThreadTaskRunner(),
- queue.Pass(),
- layer_tree_host_impl_->resource_provider());
- current_resource_update_controller_on_impl_thread_->PerformMoreUpdates(
- scheduler_on_impl_thread_->AnticipatedDrawTime());
+ impl().commit_completion_event = completion;
+ impl().current_resource_update_controller = ResourceUpdateController::Create(
+ this,
+ Proxy::ImplThreadTaskRunner(),
+ queue.Pass(),
+ impl().layer_tree_host_impl->resource_provider());
+ impl().current_resource_update_controller->PerformMoreUpdates(
+ impl().scheduler->AnticipatedDrawTime());
}
void ThreadProxy::BeginMainFrameAbortedOnImplThread(bool did_handle) {
TRACE_EVENT0("cc", "ThreadProxy::BeginMainFrameAbortedOnImplThread");
DCHECK(IsImplThread());
- DCHECK(scheduler_on_impl_thread_);
- DCHECK(scheduler_on_impl_thread_->CommitPending());
- DCHECK(!layer_tree_host_impl_->pending_tree());
+ DCHECK(impl().scheduler);
+ DCHECK(impl().scheduler->CommitPending());
+ DCHECK(!impl().layer_tree_host_impl->pending_tree());
if (did_handle)
SetInputThrottledUntilCommitOnImplThread(false);
- layer_tree_host_impl_->BeginMainFrameAborted(did_handle);
- scheduler_on_impl_thread_->BeginMainFrameAborted(did_handle);
+ impl().layer_tree_host_impl->BeginMainFrameAborted(did_handle);
+ impl().scheduler->BeginMainFrameAborted(did_handle);
+}
+
+void ThreadProxy::ScheduledActionAnimate() {
+ TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionAnimate");
+ DCHECK(IsImplThread());
+
+ if (!impl().animations_frozen_until_next_draw) {
+ impl().animation_time =
+ impl().layer_tree_host_impl->CurrentFrameTimeTicks();
+ }
+ impl().layer_tree_host_impl->Animate(impl().animation_time);
+ impl().did_commit_after_animating = false;
}
void ThreadProxy::ScheduledActionCommit() {
TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionCommit");
DCHECK(IsImplThread());
- DCHECK(commit_completion_event_on_impl_thread_);
- DCHECK(current_resource_update_controller_on_impl_thread_);
+ DCHECK(IsMainThreadBlocked());
+ DCHECK(impl().commit_completion_event);
+ DCHECK(impl().current_resource_update_controller);
// Complete all remaining texture updates.
- current_resource_update_controller_on_impl_thread_->Finalize();
- current_resource_update_controller_on_impl_thread_.reset();
-
- inside_commit_ = true;
- layer_tree_host_impl_->BeginCommit();
- layer_tree_host()->BeginCommitOnImplThread(layer_tree_host_impl_.get());
- layer_tree_host()->FinishCommitOnImplThread(layer_tree_host_impl_.get());
- layer_tree_host_impl_->CommitComplete();
- inside_commit_ = false;
+ impl().current_resource_update_controller->Finalize();
+ impl().current_resource_update_controller.reset();
- SetInputThrottledUntilCommitOnImplThread(false);
+ if (impl().animations_frozen_until_next_draw) {
+ impl().animation_time = std::max(
+ impl().animation_time, blocked_main().last_monotonic_frame_begin_time);
+ }
+ impl().did_commit_after_animating = true;
- UpdateBackgroundAnimateTicking();
+ blocked_main().main_thread_inside_commit = true;
+ impl().layer_tree_host_impl->BeginCommit();
+ layer_tree_host()->BeginCommitOnImplThread(impl().layer_tree_host_impl.get());
+ layer_tree_host()->FinishCommitOnImplThread(
+ impl().layer_tree_host_impl.get());
+ blocked_main().main_thread_inside_commit = false;
- next_frame_is_newly_committed_frame_on_impl_thread_ = true;
+ bool hold_commit = layer_tree_host()->settings().impl_side_painting &&
+ blocked_main().commit_waits_for_activation;
+ blocked_main().commit_waits_for_activation = false;
- if (layer_tree_host()->settings().impl_side_painting &&
- commit_waits_for_activation_) {
+ if (hold_commit) {
// For some layer types in impl-side painting, the commit is held until
// the pending tree is activated. It's also possible that the
// pending tree has already activated if there was no work to be done.
TRACE_EVENT_INSTANT0("cc", "HoldCommit", TRACE_EVENT_SCOPE_THREAD);
- completion_event_for_commit_held_on_tree_activation_ =
- commit_completion_event_on_impl_thread_;
- commit_completion_event_on_impl_thread_ = NULL;
+ impl().completion_event_for_commit_held_on_tree_activation =
+ impl().commit_completion_event;
+ impl().commit_completion_event = NULL;
} else {
- commit_completion_event_on_impl_thread_->Signal();
- commit_completion_event_on_impl_thread_ = NULL;
+ impl().commit_completion_event->Signal();
+ impl().commit_completion_event = NULL;
}
- commit_waits_for_activation_ = false;
+ // Delay this step until afer the main thread has been released as it's
+ // often a good bit of work to update the tree and prepare the new frame.
+ impl().layer_tree_host_impl->CommitComplete();
+
+ SetInputThrottledUntilCommitOnImplThread(false);
+
+ UpdateBackgroundAnimateTicking();
- commit_complete_time_ = base::TimeTicks::HighResNow();
- begin_main_frame_to_commit_duration_history_.InsertSample(
- commit_complete_time_ - begin_main_frame_sent_time_);
+ impl().next_frame_is_newly_committed_frame = true;
- // SetVisible kicks off the next scheduler action, so this must be last.
- scheduler_on_impl_thread_->SetVisible(layer_tree_host_impl_->visible());
+ impl().timing_history.DidCommit();
}
void ThreadProxy::ScheduledActionUpdateVisibleTiles() {
- DCHECK(IsImplThread());
TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionUpdateVisibleTiles");
- layer_tree_host_impl_->UpdateVisibleTiles();
+ DCHECK(IsImplThread());
+ impl().layer_tree_host_impl->UpdateVisibleTiles();
}
void ThreadProxy::ScheduledActionActivatePendingTree() {
- DCHECK(IsImplThread());
TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionActivatePendingTree");
- layer_tree_host_impl_->ActivatePendingTree();
+ DCHECK(IsImplThread());
+ impl().layer_tree_host_impl->ActivatePendingTree();
}
void ThreadProxy::ScheduledActionBeginOutputSurfaceCreation() {
- DCHECK(IsImplThread());
TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionBeginOutputSurfaceCreation");
+ DCHECK(IsImplThread());
Proxy::MainThreadTaskRunner()->PostTask(
FROM_HERE,
base::Bind(&ThreadProxy::CreateAndInitializeOutputSurface,
main_thread_weak_ptr_));
}
-DrawSwapReadbackResult ThreadProxy::DrawSwapReadbackInternal(
- bool forced_draw,
- bool swap_requested,
- bool readback_requested) {
- DrawSwapReadbackResult result;
- result.did_draw = false;
- result.did_swap = false;
- result.did_readback = false;
- DCHECK(IsImplThread());
- DCHECK(layer_tree_host_impl_.get());
- if (!layer_tree_host_impl_)
- return result;
+DrawResult ThreadProxy::DrawSwapInternal(bool forced_draw) {
+ TRACE_EVENT_SYNTHETIC_DELAY("cc.DrawAndSwap");
+ DrawResult result;
- DCHECK(layer_tree_host_impl_->renderer());
- if (!layer_tree_host_impl_->renderer())
- return result;
+ DCHECK(IsImplThread());
+ DCHECK(impl().layer_tree_host_impl.get());
- base::TimeTicks start_time = base::TimeTicks::HighResNow();
+ impl().timing_history.DidStartDrawing();
base::TimeDelta draw_duration_estimate = DrawDurationEstimate();
- base::AutoReset<bool> mark_inside(&inside_draw_, true);
+ base::AutoReset<bool> mark_inside(&impl().inside_draw, true);
- // Advance our animations.
- base::TimeTicks monotonic_time =
- layer_tree_host_impl_->CurrentFrameTimeTicks();
- base::Time wall_clock_time = layer_tree_host_impl_->CurrentFrameTime();
+ if (impl().did_commit_after_animating) {
+ impl().layer_tree_host_impl->Animate(impl().animation_time);
+ impl().did_commit_after_animating = false;
+ }
- // TODO(enne): This should probably happen post-animate.
- if (layer_tree_host_impl_->pending_tree())
- layer_tree_host_impl_->pending_tree()->UpdateDrawProperties();
- layer_tree_host_impl_->Animate(monotonic_time, wall_clock_time);
+ if (impl().layer_tree_host_impl->pending_tree())
+ impl().layer_tree_host_impl->pending_tree()->UpdateDrawProperties();
// This method is called on a forced draw, regardless of whether we are able
// to produce a frame, as the calling site on main thread is blocked until its
@@ -1118,72 +1059,63 @@ DrawSwapReadbackResult ThreadProxy::DrawSwapReadbackInternal(
// DrawLayers() depends on the result of PrepareToDraw(), it is guarded on
// CanDraw() as well.
- bool drawing_for_readback =
- readback_requested && !!readback_request_on_impl_thread_;
- bool can_do_readback = layer_tree_host_impl_->renderer()->CanReadPixels();
-
LayerTreeHostImpl::FrameData frame;
bool draw_frame = false;
- if (layer_tree_host_impl_->CanDraw() &&
- (!drawing_for_readback || can_do_readback)) {
- // If it is for a readback, make sure we draw the portion being read back.
- gfx::Rect readback_rect;
- if (drawing_for_readback)
- readback_rect = readback_request_on_impl_thread_->rect;
-
- if (layer_tree_host_impl_->PrepareToDraw(&frame, readback_rect) ||
- forced_draw)
- draw_frame = true;
+ if (impl().layer_tree_host_impl->CanDraw()) {
+ result = impl().layer_tree_host_impl->PrepareToDraw(&frame);
+ draw_frame = forced_draw || result == DRAW_SUCCESS;
+ } else {
+ result = DRAW_ABORTED_CANT_DRAW;
}
if (draw_frame) {
- layer_tree_host_impl_->DrawLayers(
- &frame,
- scheduler_on_impl_thread_->LastBeginImplFrameTime());
- result.did_draw = true;
+ impl().layer_tree_host_impl->DrawLayers(
+ &frame, impl().scheduler->LastBeginImplFrameTime());
+ result = DRAW_SUCCESS;
+ impl().animations_frozen_until_next_draw = false;
+ } else if (result == DRAW_ABORTED_CHECKERBOARD_ANIMATIONS &&
+ !impl().layer_tree_host_impl->settings().impl_side_painting) {
+ // Without impl-side painting, the animated layer that is checkerboarding
+ // will continue to checkerboard until the next commit. If this layer
+ // continues to move during the commit, it may continue to checkerboard
+ // after the commit since the region rasterized during the commit will not
+ // match the region that is currently visible; eventually this
+ // checkerboarding will be displayed when we force a draw. To avoid this,
+ // we freeze animations until we successfully draw.
+ impl().animations_frozen_until_next_draw = true;
+ } else {
+ DCHECK_NE(DRAW_SUCCESS, result);
}
- layer_tree_host_impl_->DidDrawAllLayers(frame);
+ impl().layer_tree_host_impl->DidDrawAllLayers(frame);
bool start_ready_animations = draw_frame;
- layer_tree_host_impl_->UpdateAnimationState(start_ready_animations);
-
- // Check for a pending CompositeAndReadback.
- if (drawing_for_readback) {
- DCHECK(!swap_requested);
- result.did_readback = false;
- if (draw_frame && !layer_tree_host_impl_->IsContextLost()) {
- layer_tree_host_impl_->Readback(readback_request_on_impl_thread_->pixels,
- readback_request_on_impl_thread_->rect);
- result.did_readback = true;
- }
- readback_request_on_impl_thread_->success = result.did_readback;
- readback_request_on_impl_thread_->completion.Signal();
- readback_request_on_impl_thread_ = NULL;
- } else if (draw_frame) {
- DCHECK(swap_requested);
- result.did_swap = layer_tree_host_impl_->SwapBuffers(frame);
+ impl().layer_tree_host_impl->UpdateAnimationState(start_ready_animations);
+
+ if (draw_frame) {
+ bool did_request_swap = impl().layer_tree_host_impl->SwapBuffers(frame);
// We don't know if we have incomplete tiles if we didn't actually swap.
- if (result.did_swap) {
+ if (did_request_swap) {
DCHECK(!frame.has_no_damage);
SetSwapUsedIncompleteTileOnImplThread(frame.contains_incomplete_tile);
}
}
// Tell the main thread that the the newly-commited frame was drawn.
- if (next_frame_is_newly_committed_frame_on_impl_thread_) {
- next_frame_is_newly_committed_frame_on_impl_thread_ = false;
+ if (impl().next_frame_is_newly_committed_frame) {
+ impl().next_frame_is_newly_committed_frame = false;
Proxy::MainThreadTaskRunner()->PostTask(
FROM_HERE,
base::Bind(&ThreadProxy::DidCommitAndDrawFrame, main_thread_weak_ptr_));
}
- if (draw_frame) {
+ if (draw_frame)
CheckOutputSurfaceStatusOnImplThread();
- base::TimeDelta draw_duration = base::TimeTicks::HighResNow() - start_time;
- draw_duration_history_.InsertSample(draw_duration);
+ if (result == DRAW_SUCCESS) {
+ base::TimeDelta draw_duration = impl().timing_history.DidFinishDrawing();
+
base::TimeDelta draw_duration_overestimate;
base::TimeDelta draw_duration_underestimate;
if (draw_duration > draw_duration_estimate)
@@ -1207,258 +1139,146 @@ DrawSwapReadbackResult ThreadProxy::DrawSwapReadbackInternal(
50);
}
+ DCHECK_NE(INVALID_RESULT, result);
return result;
}
-void ThreadProxy::AcquireLayerTextures() {
- // Called when the main thread needs to modify a layer texture that is used
- // directly by the compositor.
- // This method will block until the next compositor draw if there is a
- // previously committed frame that is still undrawn. This is necessary to
- // ensure that the main thread does not monopolize access to the textures.
- DCHECK(IsMainThread());
-
- if (textures_acquired_)
- return;
-
- TRACE_EVENT0("cc", "ThreadProxy::AcquireLayerTextures");
- DebugScopedSetMainThreadBlocked main_thread_blocked(this);
- CompletionEvent completion;
- Proxy::ImplThreadTaskRunner()->PostTask(
- FROM_HERE,
- base::Bind(&ThreadProxy::AcquireLayerTexturesForMainThreadOnImplThread,
- impl_thread_weak_ptr_,
- &completion));
- // Block until it is safe to write to layer textures from the main thread.
- completion.Wait();
-
- textures_acquired_ = true;
- can_cancel_commit_ = false;
-}
-
-void ThreadProxy::AcquireLayerTexturesForMainThreadOnImplThread(
- CompletionEvent* completion) {
- DCHECK(IsImplThread());
- DCHECK(!texture_acquisition_completion_event_on_impl_thread_);
-
- texture_acquisition_completion_event_on_impl_thread_ = completion;
- scheduler_on_impl_thread_->SetMainThreadNeedsLayerTextures();
-}
-
-void ThreadProxy::ScheduledActionAcquireLayerTexturesForMainThread() {
- DCHECK(texture_acquisition_completion_event_on_impl_thread_);
- texture_acquisition_completion_event_on_impl_thread_->Signal();
- texture_acquisition_completion_event_on_impl_thread_ = NULL;
-}
-
void ThreadProxy::ScheduledActionManageTiles() {
TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionManageTiles");
- DCHECK(layer_tree_host_impl_->settings().impl_side_painting);
- layer_tree_host_impl_->ManageTiles();
+ DCHECK(impl().layer_tree_host_impl->settings().impl_side_painting);
+ impl().layer_tree_host_impl->ManageTiles();
}
-DrawSwapReadbackResult ThreadProxy::ScheduledActionDrawAndSwapIfPossible() {
+DrawResult ThreadProxy::ScheduledActionDrawAndSwapIfPossible() {
TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionDrawAndSwap");
+
+ // SchedulerStateMachine::DidDrawIfPossibleCompleted isn't set up to
+ // handle DRAW_ABORTED_CANT_DRAW. Moreover, the scheduler should
+ // never generate this call when it can't draw.
+ DCHECK(impl().layer_tree_host_impl->CanDraw());
+
bool forced_draw = false;
- bool swap_requested = true;
- bool readback_requested = false;
- return DrawSwapReadbackInternal(
- forced_draw, swap_requested, readback_requested);
+ return DrawSwapInternal(forced_draw);
}
-DrawSwapReadbackResult ThreadProxy::ScheduledActionDrawAndSwapForced() {
+DrawResult ThreadProxy::ScheduledActionDrawAndSwapForced() {
TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionDrawAndSwapForced");
bool forced_draw = true;
- bool swap_requested = true;
- bool readback_requested = false;
- return DrawSwapReadbackInternal(
- forced_draw, swap_requested, readback_requested);
-}
-
-DrawSwapReadbackResult ThreadProxy::ScheduledActionDrawAndReadback() {
- TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionDrawAndReadback");
- bool forced_draw = true;
- bool swap_requested = false;
- bool readback_requested = true;
- return DrawSwapReadbackInternal(
- forced_draw, swap_requested, readback_requested);
+ return DrawSwapInternal(forced_draw);
}
void ThreadProxy::DidAnticipatedDrawTimeChange(base::TimeTicks time) {
- if (current_resource_update_controller_on_impl_thread_)
- current_resource_update_controller_on_impl_thread_->PerformMoreUpdates(
- time);
+ if (impl().current_resource_update_controller)
+ impl().current_resource_update_controller->PerformMoreUpdates(time);
}
base::TimeDelta ThreadProxy::DrawDurationEstimate() {
- base::TimeDelta historical_estimate =
- draw_duration_history_.Percentile(kDrawDurationEstimationPercentile);
- base::TimeDelta padding = base::TimeDelta::FromMicroseconds(
- kDrawDurationEstimatePaddingInMicroseconds);
- return historical_estimate + padding;
+ return impl().timing_history.DrawDurationEstimate();
}
base::TimeDelta ThreadProxy::BeginMainFrameToCommitDurationEstimate() {
- return begin_main_frame_to_commit_duration_history_.Percentile(
- kCommitAndActivationDurationEstimationPercentile);
+ return impl().timing_history.BeginMainFrameToCommitDurationEstimate();
}
base::TimeDelta ThreadProxy::CommitToActivateDurationEstimate() {
- return commit_to_activate_duration_history_.Percentile(
- kCommitAndActivationDurationEstimationPercentile);
-}
-
-void ThreadProxy::PostBeginImplFrameDeadline(const base::Closure& closure,
- base::TimeTicks deadline) {
- base::TimeDelta delta = deadline - gfx::FrameTime::Now();
- if (delta <= base::TimeDelta())
- delta = base::TimeDelta();
- Proxy::ImplThreadTaskRunner()->PostDelayedTask(FROM_HERE, closure, delta);
+ return impl().timing_history.CommitToActivateDurationEstimate();
}
void ThreadProxy::DidBeginImplFrameDeadline() {
- layer_tree_host_impl_->ResetCurrentFrameTimeForNextFrame();
+ impl().layer_tree_host_impl->ResetCurrentFrameTimeForNextFrame();
}
void ThreadProxy::ReadyToFinalizeTextureUpdates() {
DCHECK(IsImplThread());
- scheduler_on_impl_thread_->FinishCommit();
+ impl().scheduler->NotifyReadyToCommit();
}
void ThreadProxy::DidCommitAndDrawFrame() {
DCHECK(IsMainThread());
- if (!layer_tree_host())
- return;
layer_tree_host()->DidCommitAndDrawFrame();
}
void ThreadProxy::DidCompleteSwapBuffers() {
DCHECK(IsMainThread());
- if (!layer_tree_host())
- return;
layer_tree_host()->DidCompleteSwapBuffers();
}
-void ThreadProxy::SetAnimationEvents(scoped_ptr<AnimationEventsVector> events,
- base::Time wall_clock_time) {
+void ThreadProxy::SetAnimationEvents(scoped_ptr<AnimationEventsVector> events) {
TRACE_EVENT0("cc", "ThreadProxy::SetAnimationEvents");
DCHECK(IsMainThread());
- if (!layer_tree_host())
- return;
- layer_tree_host()->SetAnimationEvents(events.Pass(), wall_clock_time);
+ layer_tree_host()->SetAnimationEvents(events.Pass());
}
-void ThreadProxy::CreateAndInitializeOutputSurface() {
- TRACE_EVENT0("cc", "ThreadProxy::CreateAndInitializeOutputSurface");
- DCHECK(IsMainThread());
-
- // Check that output surface has not been recreated by CompositeAndReadback
- // after this task is posted but before it is run.
- bool has_initialized_output_surface_on_impl_thread = true;
- {
- CompletionEvent completion;
- Proxy::ImplThreadTaskRunner()->PostTask(
- FROM_HERE,
- base::Bind(&ThreadProxy::HasInitializedOutputSurfaceOnImplThread,
- impl_thread_weak_ptr_,
- &completion,
- &has_initialized_output_surface_on_impl_thread));
- completion.Wait();
- }
- if (has_initialized_output_surface_on_impl_thread)
- return;
-
- layer_tree_host()->DidLoseOutputSurface();
- output_surface_creation_callback_.Reset(base::Bind(
- &ThreadProxy::DoCreateAndInitializeOutputSurface,
- base::Unretained(this)));
- output_surface_creation_callback_.callback().Run();
-}
-
-void ThreadProxy::HasInitializedOutputSurfaceOnImplThread(
- CompletionEvent* completion,
- bool* has_initialized_output_surface) {
+void ThreadProxy::InitializeImplOnImplThread(CompletionEvent* completion) {
+ TRACE_EVENT0("cc", "ThreadProxy::InitializeImplOnImplThread");
DCHECK(IsImplThread());
- *has_initialized_output_surface =
- scheduler_on_impl_thread_->HasInitializedOutputSurface();
+ impl().layer_tree_host_impl =
+ layer_tree_host()->CreateLayerTreeHostImpl(this);
+ SchedulerSettings scheduler_settings(layer_tree_host()->settings());
+ impl().scheduler = Scheduler::Create(this,
+ scheduler_settings,
+ impl().layer_tree_host_id,
+ ImplThreadTaskRunner());
+ impl().scheduler->SetVisible(impl().layer_tree_host_impl->visible());
+
+ impl_thread_weak_ptr_ = impl().weak_factory.GetWeakPtr();
completion->Signal();
}
-void ThreadProxy::InitializeImplOnImplThread(CompletionEvent* completion) {
- TRACE_EVENT0("cc", "ThreadProxy::InitializeImplOnImplThread");
+void ThreadProxy::DeleteContentsTexturesOnImplThread(
+ CompletionEvent* completion) {
+ TRACE_EVENT0("cc", "ThreadProxy::DeleteContentsTexturesOnImplThread");
DCHECK(IsImplThread());
- layer_tree_host_impl_ = layer_tree_host()->CreateLayerTreeHostImpl(this);
- const LayerTreeSettings& settings = layer_tree_host()->settings();
- SchedulerSettings scheduler_settings;
- scheduler_settings.deadline_scheduling_enabled =
- settings.deadline_scheduling_enabled;
- scheduler_settings.impl_side_painting = settings.impl_side_painting;
- scheduler_settings.timeout_and_draw_when_animation_checkerboards =
- settings.timeout_and_draw_when_animation_checkerboards;
- scheduler_settings.maximum_number_of_failed_draws_before_draw_is_forced_ =
- settings.maximum_number_of_failed_draws_before_draw_is_forced_;
- scheduler_settings.using_synchronous_renderer_compositor =
- settings.using_synchronous_renderer_compositor;
- scheduler_settings.throttle_frame_production =
- settings.throttle_frame_production;
- scheduler_on_impl_thread_ = Scheduler::Create(this, scheduler_settings,
- layer_tree_host_id_);
- scheduler_on_impl_thread_->SetVisible(layer_tree_host_impl_->visible());
-
- impl_thread_weak_ptr_ = weak_factory_on_impl_thread_.GetWeakPtr();
+ DCHECK(IsMainThreadBlocked());
+ layer_tree_host()->DeleteContentsTexturesOnImplThread(
+ impl().layer_tree_host_impl->resource_provider());
completion->Signal();
}
void ThreadProxy::InitializeOutputSurfaceOnImplThread(
- CompletionEvent* completion,
- scoped_ptr<OutputSurface> output_surface,
- scoped_refptr<ContextProvider> offscreen_context_provider,
- bool* success,
- RendererCapabilities* capabilities) {
+ scoped_ptr<OutputSurface> output_surface) {
TRACE_EVENT0("cc", "ThreadProxy::InitializeOutputSurfaceOnImplThread");
DCHECK(IsImplThread());
- DCHECK(IsMainThreadBlocked());
- DCHECK(success);
- DCHECK(capabilities);
-
- layer_tree_host()->DeleteContentsTexturesOnImplThread(
- layer_tree_host_impl_->resource_provider());
-
- *success = layer_tree_host_impl_->InitializeRenderer(output_surface.Pass());
- if (*success) {
- *capabilities = layer_tree_host_impl_->GetRendererCapabilities();
- scheduler_on_impl_thread_->DidCreateAndInitializeOutputSurface();
- } else if (offscreen_context_provider.get()) {
- if (offscreen_context_provider->BindToCurrentThread())
- offscreen_context_provider->VerifyContexts();
- offscreen_context_provider = NULL;
+ LayerTreeHostImpl* host_impl = impl().layer_tree_host_impl.get();
+ bool success = host_impl->InitializeRenderer(output_surface.Pass());
+ RendererCapabilities capabilities;
+ if (success) {
+ capabilities =
+ host_impl->GetRendererCapabilities().MainThreadCapabilities();
}
- layer_tree_host_impl_->SetOffscreenContextProvider(
- offscreen_context_provider);
+ Proxy::MainThreadTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(&ThreadProxy::DidInitializeOutputSurface,
+ main_thread_weak_ptr_,
+ success,
+ capabilities));
- completion->Signal();
+ if (success)
+ impl().scheduler->DidCreateAndInitializeOutputSurface();
}
void ThreadProxy::FinishGLOnImplThread(CompletionEvent* completion) {
TRACE_EVENT0("cc", "ThreadProxy::FinishGLOnImplThread");
DCHECK(IsImplThread());
- if (layer_tree_host_impl_->resource_provider())
- layer_tree_host_impl_->resource_provider()->Finish();
+ if (impl().layer_tree_host_impl->resource_provider())
+ impl().layer_tree_host_impl->resource_provider()->Finish();
completion->Signal();
}
void ThreadProxy::LayerTreeHostClosedOnImplThread(CompletionEvent* completion) {
TRACE_EVENT0("cc", "ThreadProxy::LayerTreeHostClosedOnImplThread");
DCHECK(IsImplThread());
+ DCHECK(IsMainThreadBlocked());
layer_tree_host()->DeleteContentsTexturesOnImplThread(
- layer_tree_host_impl_->resource_provider());
- current_resource_update_controller_on_impl_thread_.reset();
- layer_tree_host_impl_->SetNeedsBeginImplFrame(false);
- scheduler_on_impl_thread_.reset();
- layer_tree_host_impl_.reset();
- weak_factory_on_impl_thread_.InvalidateWeakPtrs();
+ impl().layer_tree_host_impl->resource_provider());
+ impl().current_resource_update_controller.reset();
+ impl().layer_tree_host_impl->SetNeedsBeginFrame(false);
+ impl().scheduler.reset();
+ impl().layer_tree_host_impl.reset();
+ impl().weak_factory.InvalidateWeakPtrs();
+ impl().contents_texture_manager = NULL;
completion->Signal();
}
@@ -1494,7 +1314,7 @@ scoped_ptr<base::Value> ThreadProxy::AsValue() const {
void ThreadProxy::AsValueOnImplThread(CompletionEvent* completion,
base::DictionaryValue* state) const {
state->Set("layer_tree_host_impl",
- layer_tree_host_impl_->AsValue().release());
+ impl().layer_tree_host_impl->AsValue().release());
completion->Signal();
}
@@ -1516,23 +1336,23 @@ bool ThreadProxy::CommitPendingForTesting() {
void ThreadProxy::CommitPendingOnImplThreadForTesting(
CommitPendingRequest* request) {
DCHECK(IsImplThread());
- if (layer_tree_host_impl_->output_surface())
- request->commit_pending = scheduler_on_impl_thread_->CommitPending();
+ if (impl().layer_tree_host_impl->output_surface())
+ request->commit_pending = impl().scheduler->CommitPending();
else
request->commit_pending = false;
request->completion.Signal();
}
-scoped_ptr<base::Value> ThreadProxy::SchedulerStateAsValueForTesting() {
+scoped_ptr<base::Value> ThreadProxy::SchedulerAsValueForTesting() {
if (IsImplThread())
- return scheduler_on_impl_thread_->StateAsValue().Pass();
+ return impl().scheduler->AsValue().Pass();
SchedulerStateRequest scheduler_state_request;
{
DebugScopedSetMainThreadBlocked main_thread_blocked(this);
Proxy::ImplThreadTaskRunner()->PostTask(
FROM_HERE,
- base::Bind(&ThreadProxy::SchedulerStateAsValueOnImplThreadForTesting,
+ base::Bind(&ThreadProxy::SchedulerAsValueOnImplThreadForTesting,
impl_thread_weak_ptr_,
&scheduler_state_request));
scheduler_state_request.completion.Wait();
@@ -1540,115 +1360,86 @@ scoped_ptr<base::Value> ThreadProxy::SchedulerStateAsValueForTesting() {
return scheduler_state_request.state.Pass();
}
-void ThreadProxy::SchedulerStateAsValueOnImplThreadForTesting(
+void ThreadProxy::SchedulerAsValueOnImplThreadForTesting(
SchedulerStateRequest* request) {
DCHECK(IsImplThread());
- request->state = scheduler_on_impl_thread_->StateAsValue();
+ request->state = impl().scheduler->AsValue();
request->completion.Signal();
}
void ThreadProxy::RenewTreePriority() {
DCHECK(IsImplThread());
bool smoothness_takes_priority =
- layer_tree_host_impl_->pinch_gesture_active() ||
- layer_tree_host_impl_->IsCurrentlyScrolling() ||
- layer_tree_host_impl_->page_scale_animation_active();
+ impl().layer_tree_host_impl->pinch_gesture_active() ||
+ impl().layer_tree_host_impl->page_scale_animation_active() ||
+ (impl().layer_tree_host_impl->IsCurrentlyScrolling() &&
+ !impl().layer_tree_host_impl->scroll_affects_scroll_handler());
- base::TimeTicks now = layer_tree_host_impl_->CurrentPhysicalTimeTicks();
-
- // Update expiration time if smoothness currently takes priority.
- if (smoothness_takes_priority) {
- smoothness_takes_priority_expiration_time_ =
- now + base::TimeDelta::FromMilliseconds(
- kSmoothnessTakesPriorityExpirationDelay * 1000);
- }
+ // Schedule expiration if smoothness currently takes priority.
+ if (smoothness_takes_priority)
+ impl().smoothness_priority_expiration_notifier.Schedule();
// We use the same priority for both trees by default.
TreePriority priority = SAME_PRIORITY_FOR_BOTH_TREES;
- // Smoothness takes priority if expiration time is in the future.
- if (smoothness_takes_priority_expiration_time_ > now)
+ // Smoothness takes priority if we have an expiration for it scheduled.
+ if (impl().smoothness_priority_expiration_notifier.HasPendingNotification())
priority = SMOOTHNESS_TAKES_PRIORITY;
// New content always takes priority when the active tree has
// evicted resources or there is an invalid viewport size.
- if (layer_tree_host_impl_->active_tree()->ContentsTexturesPurged() ||
- layer_tree_host_impl_->active_tree()->ViewportSizeInvalid() ||
- layer_tree_host_impl_->EvictedUIResourcesExist() ||
- input_throttled_until_commit_)
+ if (impl().layer_tree_host_impl->active_tree()->ContentsTexturesPurged() ||
+ impl().layer_tree_host_impl->active_tree()->ViewportSizeInvalid() ||
+ impl().layer_tree_host_impl->EvictedUIResourcesExist() ||
+ impl().input_throttled_until_commit) {
+ // Once we enter NEW_CONTENTS_TAKES_PRIORITY mode, visible tiles on active
+ // tree might be freed. We need to set RequiresHighResToDraw to ensure that
+ // high res tiles will be required to activate pending tree.
+ impl().layer_tree_host_impl->active_tree()->SetRequiresHighResToDraw();
priority = NEW_CONTENT_TAKES_PRIORITY;
+ }
- layer_tree_host_impl_->SetTreePriority(priority);
- scheduler_on_impl_thread_->SetSmoothnessTakesPriority(
- priority == SMOOTHNESS_TAKES_PRIORITY);
+ impl().layer_tree_host_impl->SetTreePriority(priority);
+ impl().scheduler->SetSmoothnessTakesPriority(priority ==
+ SMOOTHNESS_TAKES_PRIORITY);
// Notify the the client of this compositor via the output surface.
// TODO(epenner): Route this to compositor-thread instead of output-surface
// after GTFO refactor of compositor-thread (http://crbug/170828).
- if (layer_tree_host_impl_->output_surface()) {
- layer_tree_host_impl_->output_surface()->
- UpdateSmoothnessTakesPriority(priority == SMOOTHNESS_TAKES_PRIORITY);
+ if (impl().layer_tree_host_impl->output_surface()) {
+ impl()
+ .layer_tree_host_impl->output_surface()
+ ->UpdateSmoothnessTakesPriority(priority == SMOOTHNESS_TAKES_PRIORITY);
}
-
- base::TimeDelta delay = smoothness_takes_priority_expiration_time_ - now;
-
- // Need to make sure a delayed task is posted when we have smoothness
- // takes priority expiration time in the future.
- if (delay <= base::TimeDelta())
- return;
- if (renew_tree_priority_on_impl_thread_pending_)
- return;
-
- Proxy::ImplThreadTaskRunner()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&ThreadProxy::RenewTreePriorityOnImplThread,
- weak_factory_on_impl_thread_.GetWeakPtr()),
- delay);
-
- renew_tree_priority_on_impl_thread_pending_ = true;
}
-void ThreadProxy::RenewTreePriorityOnImplThread() {
- DCHECK(renew_tree_priority_on_impl_thread_pending_);
- renew_tree_priority_on_impl_thread_pending_ = false;
-
- RenewTreePriority();
-}
-
-void ThreadProxy::RequestScrollbarAnimationOnImplThread(base::TimeDelta delay) {
- Proxy::ImplThreadTaskRunner()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&ThreadProxy::StartScrollbarAnimationOnImplThread,
- impl_thread_weak_ptr_),
- delay);
-}
-
-void ThreadProxy::StartScrollbarAnimationOnImplThread() {
- layer_tree_host_impl_->StartScrollbarAnimation();
+void ThreadProxy::PostDelayedScrollbarFadeOnImplThread(
+ const base::Closure& start_fade,
+ base::TimeDelta delay) {
+ Proxy::ImplThreadTaskRunner()->PostDelayedTask(FROM_HERE, start_fade, delay);
}
void ThreadProxy::DidActivatePendingTree() {
- DCHECK(IsImplThread());
TRACE_EVENT0("cc", "ThreadProxy::DidActivatePendingTreeOnImplThread");
+ DCHECK(IsImplThread());
+ DCHECK(!impl().layer_tree_host_impl->pending_tree());
- if (completion_event_for_commit_held_on_tree_activation_ &&
- !layer_tree_host_impl_->pending_tree()) {
- TRACE_EVENT_INSTANT0("cc", "ReleaseCommitbyActivation",
- TRACE_EVENT_SCOPE_THREAD);
- DCHECK(layer_tree_host_impl_->settings().impl_side_painting);
- completion_event_for_commit_held_on_tree_activation_->Signal();
- completion_event_for_commit_held_on_tree_activation_ = NULL;
+ if (impl().completion_event_for_commit_held_on_tree_activation) {
+ TRACE_EVENT_INSTANT0(
+ "cc", "ReleaseCommitbyActivation", TRACE_EVENT_SCOPE_THREAD);
+ DCHECK(impl().layer_tree_host_impl->settings().impl_side_painting);
+ impl().completion_event_for_commit_held_on_tree_activation->Signal();
+ impl().completion_event_for_commit_held_on_tree_activation = NULL;
}
UpdateBackgroundAnimateTicking();
- commit_to_activate_duration_history_.InsertSample(
- base::TimeTicks::HighResNow() - commit_complete_time_);
+ impl().timing_history.DidActivatePendingTree();
}
void ThreadProxy::DidManageTiles() {
DCHECK(IsImplThread());
- scheduler_on_impl_thread_->DidManageTiles();
+ impl().scheduler->DidManageTiles();
}
} // namespace cc
diff --git a/chromium/cc/trees/thread_proxy.h b/chromium/cc/trees/thread_proxy.h
index cf041edbcfd..8d4348e490d 100644
--- a/chromium/cc/trees/thread_proxy.h
+++ b/chromium/cc/trees/thread_proxy.h
@@ -12,13 +12,16 @@
#include "base/time/time.h"
#include "cc/animation/animation_events.h"
#include "cc/base/completion_event.h"
+#include "cc/base/delayed_unique_notifier.h"
#include "cc/resources/resource_update_controller.h"
-#include "cc/scheduler/rolling_time_delta_history.h"
#include "cc/scheduler/scheduler.h"
#include "cc/trees/layer_tree_host_impl.h"
#include "cc/trees/proxy.h"
+#include "cc/trees/proxy_timing_history.h"
-namespace base { class SingleThreadTaskRunner; }
+namespace base {
+class SingleThreadTaskRunner;
+}
namespace cc {
@@ -29,10 +32,10 @@ class ResourceUpdateQueue;
class Scheduler;
class ScopedThreadProxy;
-class ThreadProxy : public Proxy,
- LayerTreeHostImplClient,
- SchedulerClient,
- ResourceUpdateControllerClient {
+class CC_EXPORT ThreadProxy : public Proxy,
+ NON_EXPORTED_BASE(LayerTreeHostImplClient),
+ NON_EXPORTED_BASE(SchedulerClient),
+ NON_EXPORTED_BASE(ResourceUpdateControllerClient) {
public:
static scoped_ptr<Proxy> Create(
LayerTreeHost* layer_tree_host,
@@ -40,128 +43,216 @@ class ThreadProxy : public Proxy,
virtual ~ThreadProxy();
+ struct BeginMainFrameAndCommitState {
+ BeginMainFrameAndCommitState();
+ ~BeginMainFrameAndCommitState();
+
+ base::TimeTicks monotonic_frame_begin_time;
+ scoped_ptr<ScrollAndScaleSet> scroll_info;
+ size_t memory_allocation_limit_bytes;
+ int memory_allocation_priority_cutoff;
+ bool evicted_ui_resources;
+ };
+
+ struct MainThreadOnly {
+ MainThreadOnly(ThreadProxy* proxy, int layer_tree_host_id);
+ ~MainThreadOnly();
+
+ const int layer_tree_host_id;
+
+ // Set only when SetNeedsAnimate is called.
+ bool animate_requested;
+ // Set only when SetNeedsCommit is called.
+ bool commit_requested;
+ // Set by SetNeedsAnimate, SetNeedsUpdateLayers, and SetNeedsCommit.
+ bool commit_request_sent_to_impl_thread;
+
+ bool started;
+ bool manage_tiles_pending;
+ bool can_cancel_commit;
+ bool defer_commits;
+
+ RendererCapabilities renderer_capabilities_main_thread_copy;
+
+ scoped_ptr<BeginMainFrameAndCommitState> pending_deferred_commit;
+ base::WeakPtrFactory<ThreadProxy> weak_factory;
+ };
+
+ // Accessed on the main thread, or when main thread is blocked.
+ struct MainThreadOrBlockedMainThread {
+ explicit MainThreadOrBlockedMainThread(LayerTreeHost* host);
+ ~MainThreadOrBlockedMainThread();
+
+ PrioritizedResourceManager* contents_texture_manager();
+
+ LayerTreeHost* layer_tree_host;
+ bool commit_waits_for_activation;
+ bool main_thread_inside_commit;
+
+ base::TimeTicks last_monotonic_frame_begin_time;
+ };
+
+ struct ReadbackRequest;
+
+ struct CompositorThreadOnly {
+ CompositorThreadOnly(ThreadProxy* proxy, int layer_tree_host_id);
+ ~CompositorThreadOnly();
+
+ const int layer_tree_host_id;
+
+ // Copy of the main thread side contents texture manager for work
+ // that needs to be done on the compositor thread.
+ PrioritizedResourceManager* contents_texture_manager;
+
+ scoped_ptr<Scheduler> scheduler;
+
+ // Set when the main thread is waiting on a
+ // ScheduledActionSendBeginMainFrame to be issued.
+ CompletionEvent* begin_main_frame_sent_completion_event;
+
+ // Set when the main thread is waiting on a commit to complete.
+ CompletionEvent* commit_completion_event;
+
+ // Set when the main thread is waiting on a pending tree activation.
+ CompletionEvent* completion_event_for_commit_held_on_tree_activation;
+
+ scoped_ptr<ResourceUpdateController> current_resource_update_controller;
+
+ // Set when the next draw should post DidCommitAndDrawFrame to the main
+ // thread.
+ bool next_frame_is_newly_committed_frame;
+
+ bool inside_draw;
+
+ bool input_throttled_until_commit;
+
+ // Set when we freeze animations to avoid checkerboarding.
+ bool animations_frozen_until_next_draw;
+ base::TimeTicks animation_time;
+
+ // Whether a commit has been completed since the last time animations were
+ // ticked. If this happens, we need to animate again.
+ bool did_commit_after_animating;
+
+ DelayedUniqueNotifier smoothness_priority_expiration_notifier;
+
+ ProxyTimingHistory timing_history;
+
+ scoped_ptr<LayerTreeHostImpl> layer_tree_host_impl;
+ base::WeakPtrFactory<ThreadProxy> weak_factory;
+ };
+
+ const MainThreadOnly& main() const;
+ const MainThreadOrBlockedMainThread& blocked_main() const;
+ const CompositorThreadOnly& impl() const;
+
// Proxy implementation
- virtual bool CompositeAndReadback(void* pixels, gfx::Rect rect) OVERRIDE;
virtual void FinishAllRendering() OVERRIDE;
virtual bool IsStarted() const OVERRIDE;
virtual void SetLayerTreeHostClientReady() OVERRIDE;
virtual void SetVisible(bool visible) OVERRIDE;
- virtual void CreateAndInitializeOutputSurface() OVERRIDE;
virtual const RendererCapabilities& GetRendererCapabilities() const OVERRIDE;
virtual void SetNeedsAnimate() OVERRIDE;
virtual void SetNeedsUpdateLayers() OVERRIDE;
virtual void SetNeedsCommit() OVERRIDE;
- virtual void SetNeedsRedraw(gfx::Rect damage_rect) OVERRIDE;
+ virtual void SetNeedsRedraw(const gfx::Rect& damage_rect) OVERRIDE;
virtual void SetNextCommitWaitsForActivation() OVERRIDE;
virtual void NotifyInputThrottledUntilCommit() OVERRIDE;
virtual void SetDeferCommits(bool defer_commits) OVERRIDE;
virtual bool CommitRequested() const OVERRIDE;
virtual bool BeginMainFrameRequested() const OVERRIDE;
virtual void MainThreadHasStoppedFlinging() OVERRIDE;
- virtual void Start(scoped_ptr<OutputSurface> first_output_surface) OVERRIDE;
+ virtual void Start() OVERRIDE;
virtual void Stop() OVERRIDE;
virtual size_t MaxPartialTextureUpdates() const OVERRIDE;
- virtual void AcquireLayerTextures() OVERRIDE;
virtual void ForceSerializeOnSwapBuffers() OVERRIDE;
+ virtual void SetDebugState(const LayerTreeDebugState& debug_state) OVERRIDE;
virtual scoped_ptr<base::Value> AsValue() const OVERRIDE;
virtual bool CommitPendingForTesting() OVERRIDE;
- virtual scoped_ptr<base::Value> SchedulerStateAsValueForTesting() OVERRIDE;
+ virtual scoped_ptr<base::Value> SchedulerAsValueForTesting() OVERRIDE;
// LayerTreeHostImplClient implementation
+ virtual void UpdateRendererCapabilitiesOnImplThread() OVERRIDE;
virtual void DidLoseOutputSurfaceOnImplThread() OVERRIDE;
- virtual void DidSwapBuffersOnImplThread() OVERRIDE {}
- virtual void OnSwapBuffersCompleteOnImplThread() OVERRIDE;
- virtual void BeginImplFrame(const BeginFrameArgs& args) OVERRIDE;
+ virtual void CommitVSyncParameters(base::TimeTicks timebase,
+ base::TimeDelta interval) OVERRIDE;
+ virtual void SetEstimatedParentDrawTime(base::TimeDelta draw_time) OVERRIDE;
+ virtual void BeginFrame(const BeginFrameArgs& args) OVERRIDE;
+ virtual void SetMaxSwapsPendingOnImplThread(int max) OVERRIDE;
+ virtual void DidSwapBuffersOnImplThread() OVERRIDE;
+ virtual void DidSwapBuffersCompleteOnImplThread() OVERRIDE;
virtual void OnCanDrawStateChanged(bool can_draw) OVERRIDE;
virtual void NotifyReadyToActivate() OVERRIDE;
- // Please call these 2 functions through
- // LayerTreeHostImpl's SetNeedsRedraw() and SetNeedsRedrawRect().
+ // Please call these 3 functions through
+ // LayerTreeHostImpl's SetNeedsRedraw(), SetNeedsRedrawRect() and
+ // SetNeedsAnimate().
virtual void SetNeedsRedrawOnImplThread() OVERRIDE;
- virtual void SetNeedsRedrawRectOnImplThread(gfx::Rect dirty_rect) OVERRIDE;
+ virtual void SetNeedsRedrawRectOnImplThread(const gfx::Rect& dirty_rect)
+ OVERRIDE;
+ virtual void SetNeedsAnimateOnImplThread() OVERRIDE;
virtual void SetNeedsManageTilesOnImplThread() OVERRIDE;
virtual void DidInitializeVisibleTileOnImplThread() OVERRIDE;
virtual void SetNeedsCommitOnImplThread() OVERRIDE;
virtual void PostAnimationEventsToMainThreadOnImplThread(
- scoped_ptr<AnimationEventsVector> queue,
- base::Time wall_clock_time) OVERRIDE;
+ scoped_ptr<AnimationEventsVector> queue) OVERRIDE;
virtual bool ReduceContentsTextureMemoryOnImplThread(size_t limit_bytes,
int priority_cutoff)
OVERRIDE;
- virtual void SendManagedMemoryStats() OVERRIDE;
virtual bool IsInsideDraw() OVERRIDE;
virtual void RenewTreePriority() OVERRIDE;
- virtual void RequestScrollbarAnimationOnImplThread(base::TimeDelta delay)
- OVERRIDE;
+ virtual void PostDelayedScrollbarFadeOnImplThread(
+ const base::Closure& start_fade,
+ base::TimeDelta delay) OVERRIDE;
virtual void DidActivatePendingTree() OVERRIDE;
virtual void DidManageTiles() OVERRIDE;
// SchedulerClient implementation
- virtual void SetNeedsBeginImplFrame(bool enable) OVERRIDE;
+ virtual void SetNeedsBeginFrame(bool enable) OVERRIDE;
+ virtual void WillBeginImplFrame(const BeginFrameArgs& args) OVERRIDE;
virtual void ScheduledActionSendBeginMainFrame() OVERRIDE;
- virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapIfPossible()
- OVERRIDE;
- virtual DrawSwapReadbackResult ScheduledActionDrawAndSwapForced() OVERRIDE;
- virtual DrawSwapReadbackResult ScheduledActionDrawAndReadback() OVERRIDE;
+ virtual DrawResult ScheduledActionDrawAndSwapIfPossible() OVERRIDE;
+ virtual DrawResult ScheduledActionDrawAndSwapForced() OVERRIDE;
+ virtual void ScheduledActionAnimate() OVERRIDE;
virtual void ScheduledActionCommit() OVERRIDE;
virtual void ScheduledActionUpdateVisibleTiles() OVERRIDE;
virtual void ScheduledActionActivatePendingTree() OVERRIDE;
virtual void ScheduledActionBeginOutputSurfaceCreation() OVERRIDE;
- virtual void ScheduledActionAcquireLayerTexturesForMainThread() OVERRIDE;
virtual void ScheduledActionManageTiles() OVERRIDE;
virtual void DidAnticipatedDrawTimeChange(base::TimeTicks time) OVERRIDE;
virtual base::TimeDelta DrawDurationEstimate() OVERRIDE;
virtual base::TimeDelta BeginMainFrameToCommitDurationEstimate() OVERRIDE;
virtual base::TimeDelta CommitToActivateDurationEstimate() OVERRIDE;
- virtual void PostBeginImplFrameDeadline(const base::Closure& closure,
- base::TimeTicks deadline) OVERRIDE;
virtual void DidBeginImplFrameDeadline() OVERRIDE;
// ResourceUpdateControllerClient implementation
virtual void ReadyToFinalizeTextureUpdates() OVERRIDE;
- private:
+ protected:
ThreadProxy(LayerTreeHost* layer_tree_host,
scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner);
- struct BeginMainFrameAndCommitState {
- BeginMainFrameAndCommitState();
- ~BeginMainFrameAndCommitState();
-
- base::TimeTicks monotonic_frame_begin_time;
- scoped_ptr<ScrollAndScaleSet> scroll_info;
- size_t memory_allocation_limit_bytes;
- int memory_allocation_priority_cutoff;
- bool evicted_ui_resources;
- };
-
+ private:
// Called on main thread.
+ void SetRendererCapabilitiesMainThreadCopy(
+ const RendererCapabilities& capabilities);
void BeginMainFrame(
scoped_ptr<BeginMainFrameAndCommitState> begin_main_frame_state);
void DidCommitAndDrawFrame();
void DidCompleteSwapBuffers();
- void SetAnimationEvents(scoped_ptr<AnimationEventsVector> queue,
- base::Time wall_clock_time);
- void DoCreateAndInitializeOutputSurface();
- // |capabilities| is set only when |success| is true.
- void OnOutputSurfaceInitializeAttempted(
- bool success,
- const RendererCapabilities& capabilities);
+ void SetAnimationEvents(scoped_ptr<AnimationEventsVector> queue);
+ void DidLoseOutputSurface();
+ void CreateAndInitializeOutputSurface();
+ void DidInitializeOutputSurface(bool success,
+ const RendererCapabilities& capabilities);
void SendCommitRequestToImplThreadIfNeeded();
// Called on impl thread.
- struct ReadbackRequest;
struct CommitPendingRequest;
struct SchedulerStateRequest;
- void ForceCommitForReadbackOnImplThread(
- CompletionEvent* begin_main_frame_sent_completion,
- ReadbackRequest* request);
- void StartCommitOnImplThread(
- CompletionEvent* completion,
- ResourceUpdateQueue* queue,
- scoped_refptr<ContextProvider> offscreen_context_provider);
+ void StartCommitOnImplThread(CompletionEvent* completion,
+ ResourceUpdateQueue* queue);
void BeginMainFrameAbortedOnImplThread(bool did_handle);
- void RequestReadbackOnImplThread(ReadbackRequest* request);
void FinishAllRenderingOnImplThread(CompletionEvent* completion);
void InitializeImplOnImplThread(CompletionEvent* completion);
void SetLayerTreeHostClientReadyOnImplThread();
@@ -170,126 +261,40 @@ class ThreadProxy : public Proxy,
void HasInitializedOutputSurfaceOnImplThread(
CompletionEvent* completion,
bool* has_initialized_output_surface);
+ void DeleteContentsTexturesOnImplThread(CompletionEvent* completion);
void InitializeOutputSurfaceOnImplThread(
- CompletionEvent* completion,
- scoped_ptr<OutputSurface> output_surface,
- scoped_refptr<ContextProvider> offscreen_context_provider,
- bool* success,
- RendererCapabilities* capabilities);
+ scoped_ptr<OutputSurface> output_surface);
void FinishGLOnImplThread(CompletionEvent* completion);
void LayerTreeHostClosedOnImplThread(CompletionEvent* completion);
- void AcquireLayerTexturesForMainThreadOnImplThread(
- CompletionEvent* completion);
- DrawSwapReadbackResult DrawSwapReadbackInternal(bool forced_draw,
- bool swap_requested,
- bool readback_requested);
+ DrawResult DrawSwapInternal(bool forced_draw);
void ForceSerializeOnSwapBuffersOnImplThread(CompletionEvent* completion);
void CheckOutputSurfaceStatusOnImplThread();
void CommitPendingOnImplThreadForTesting(CommitPendingRequest* request);
- void SchedulerStateAsValueOnImplThreadForTesting(
- SchedulerStateRequest* request);
+ void SchedulerAsValueOnImplThreadForTesting(SchedulerStateRequest* request);
void AsValueOnImplThread(CompletionEvent* completion,
base::DictionaryValue* state) const;
- void RenewTreePriorityOnImplThread();
void SetSwapUsedIncompleteTileOnImplThread(bool used_incomplete_tile);
- void StartScrollbarAnimationOnImplThread();
void MainThreadHasStoppedFlingingOnImplThread();
void SetInputThrottledUntilCommitOnImplThread(bool is_throttled);
+ void SetDebugStateOnImplThread(const LayerTreeDebugState& debug_state);
+
LayerTreeHost* layer_tree_host();
const LayerTreeHost* layer_tree_host() const;
- PrioritizedResourceManager* contents_texture_manager_on_main_thread();
- PrioritizedResourceManager* contents_texture_manager_on_impl_thread();
-
- // Accessed on main thread only.
-
- // Set only when SetNeedsAnimate is called.
- bool animate_requested_;
- // Set only when SetNeedsCommit is called.
- bool commit_requested_;
- // Set by SetNeedsAnimate, SetNeedsUpdateLayers, and SetNeedsCommit.
- bool commit_request_sent_to_impl_thread_;
- // Set by BeginMainFrame
- bool created_offscreen_context_provider_;
- base::CancelableClosure output_surface_creation_callback_;
- // Don't use this variable directly, go through layer_tree_host() to ensure it
- // is only used on the main thread or if the main thread is blocked.
- LayerTreeHost* layer_tree_host_unsafe_;
- // Use one of the contents_texture_manager_on functions above instead of using
- // this variable directly.
- PrioritizedResourceManager* contents_texture_manager_unsafe_;
- RendererCapabilities renderer_capabilities_main_thread_copy_;
- bool started_;
- bool textures_acquired_;
- bool in_composite_and_readback_;
- bool manage_tiles_pending_;
- // Weak pointer to use when posting tasks to the impl thread.
- base::WeakPtr<ThreadProxy> impl_thread_weak_ptr_;
- // Holds the first output surface passed from Start. Should not be used for
- // anything else.
- scoped_ptr<OutputSurface> first_output_surface_;
-
- // Accessed on the main thread, or when main thread is blocked.
- bool commit_waits_for_activation_;
- bool inside_commit_;
-
- scoped_ptr<LayerTreeHostImpl> layer_tree_host_impl_;
-
- scoped_ptr<Scheduler> scheduler_on_impl_thread_;
-
- // Set when the main thread is waiting on a
- // ScheduledActionSendBeginMainFrame to be issued.
- CompletionEvent*
- begin_main_frame_sent_completion_event_on_impl_thread_;
-
- // Set when the main thread is waiting on a readback.
- ReadbackRequest* readback_request_on_impl_thread_;
-
- // Set when the main thread is waiting on a commit to complete.
- CompletionEvent* commit_completion_event_on_impl_thread_;
- // Set when the main thread is waiting on a pending tree activation.
- CompletionEvent* completion_event_for_commit_held_on_tree_activation_;
+ // Use accessors instead of this variable directly.
+ MainThreadOnly main_thread_only_vars_unsafe_;
+ MainThreadOnly& main();
- // Set when the main thread is waiting on layers to be drawn.
- CompletionEvent* texture_acquisition_completion_event_on_impl_thread_;
+ // Use accessors instead of this variable directly.
+ MainThreadOrBlockedMainThread main_thread_or_blocked_vars_unsafe_;
+ MainThreadOrBlockedMainThread& blocked_main();
- scoped_ptr<ResourceUpdateController>
- current_resource_update_controller_on_impl_thread_;
-
- // Set when the next draw should post DidCommitAndDrawFrame to the main
- // thread.
- bool next_frame_is_newly_committed_frame_on_impl_thread_;
-
- bool throttle_frame_production_;
- bool begin_impl_frame_scheduling_enabled_;
- bool using_synchronous_renderer_compositor_;
-
- bool inside_draw_;
-
- bool can_cancel_commit_;
-
- bool defer_commits_;
- bool input_throttled_until_commit_;
- scoped_ptr<BeginMainFrameAndCommitState> pending_deferred_commit_;
-
- base::TimeTicks smoothness_takes_priority_expiration_time_;
- bool renew_tree_priority_on_impl_thread_pending_;
-
- RollingTimeDeltaHistory draw_duration_history_;
- RollingTimeDeltaHistory begin_main_frame_to_commit_duration_history_;
- RollingTimeDeltaHistory commit_to_activate_duration_history_;
-
- // Used for computing samples added to
- // begin_main_frame_to_commit_duration_history_ and
- // activation_duration_history_.
- base::TimeTicks begin_main_frame_sent_time_;
- base::TimeTicks commit_complete_time_;
+ // Use accessors instead of this variable directly.
+ CompositorThreadOnly compositor_thread_vars_unsafe_;
+ CompositorThreadOnly& impl();
base::WeakPtr<ThreadProxy> main_thread_weak_ptr_;
- base::WeakPtrFactory<ThreadProxy> weak_factory_on_impl_thread_;
- base::WeakPtrFactory<ThreadProxy> weak_factory_;
-
- const int layer_tree_host_id_;
+ base::WeakPtr<ThreadProxy> impl_thread_weak_ptr_;
DISALLOW_COPY_AND_ASSIGN(ThreadProxy);
};
diff --git a/chromium/cc/trees/tree_synchronizer.cc b/chromium/cc/trees/tree_synchronizer.cc
index 48a9d5bd966..a54bd22efa1 100644
--- a/chromium/cc/trees/tree_synchronizer.cc
+++ b/chromium/cc/trees/tree_synchronizer.cc
@@ -4,6 +4,8 @@
#include "cc/trees/tree_synchronizer.h"
+#include <set>
+
#include "base/containers/hash_tables.h"
#include "base/containers/scoped_ptr_hash_map.h"
#include "base/debug/trace_event.h"
@@ -25,6 +27,13 @@ void CollectExistingLayerImplRecursive(ScopedPtrLayerImplMap* old_layers,
if (!layer_impl)
return;
+ layer_impl->ClearScrollbars();
+ if (ScrollbarLayerImplBase* scrollbar_layer =
+ layer_impl->ToScrollbarLayer()) {
+ scrollbar_layer->ClearClipLayer();
+ scrollbar_layer->ClearScrollLayer();
+ }
+
OwnedLayerImplList& children = layer_impl->children();
for (OwnedLayerImplList::iterator it = children.begin();
it != children.end();
@@ -112,11 +121,6 @@ scoped_ptr<LayerImpl> SynchronizeTreesRecursiveInternal(
layer_impl->SetReplicaLayer(SynchronizeTreesRecursiveInternal(
new_layers, old_layers, layer->replica_layer(), tree_impl));
- // Remove all dangling pointers. The pointers will be setup later in
- // UpdateScrollbarLayerPointersRecursive phase
- layer_impl->SetHorizontalScrollbarLayer(NULL);
- layer_impl->SetVerticalScrollbarLayer(NULL);
-
return layer_impl.Pass();
}
@@ -160,17 +164,9 @@ void UpdateScrollbarLayerPointersRecursiveInternal(
iter != new_layers->end()
? static_cast<ScrollbarLayerImplBase*>(iter->second)
: NULL;
- iter = new_layers->find(scrollbar_layer->ScrollLayerId());
- LayerImpl* scroll_layer_impl =
- iter != new_layers->end() ? iter->second : NULL;
-
DCHECK(scrollbar_layer_impl);
- DCHECK(scroll_layer_impl);
- if (scrollbar_layer->orientation() == HORIZONTAL)
- scroll_layer_impl->SetHorizontalScrollbarLayer(scrollbar_layer_impl);
- else
- scroll_layer_impl->SetVerticalScrollbarLayer(scrollbar_layer_impl);
+ scrollbar_layer->PushScrollClipPropertiesTo(scrollbar_layer_impl);
}
void UpdateScrollbarLayerPointersRecursive(const RawPtrLayerImplMap* new_layers,
@@ -187,17 +183,6 @@ void UpdateScrollbarLayerPointersRecursive(const RawPtrLayerImplMap* new_layers,
}
// static
-void TreeSynchronizer::SetNumDependentsNeedPushProperties(
- Layer* layer, size_t num) {
- layer->num_dependents_need_push_properties_ = num;
-}
-
-// static
-void TreeSynchronizer::SetNumDependentsNeedPushProperties(
- LayerImpl* layer, size_t num) {
-}
-
-// static
template <typename LayerType>
void TreeSynchronizer::PushPropertiesInternal(
LayerType* layer,
@@ -216,6 +201,8 @@ void TreeSynchronizer::PushPropertiesInternal(
if (push_layer)
layer->PushPropertiesTo(layer_impl);
+ else if (layer->ToScrollbarLayer())
+ layer->ToScrollbarLayer()->PushScrollClipPropertiesTo(layer_impl);
size_t num_dependents_need_push_properties = 0;
if (recurse_on_children_and_dependents) {
@@ -240,8 +227,8 @@ void TreeSynchronizer::PushPropertiesInternal(
// every PushProperties tree walk. Here we keep track of those layers, and
// ensure that their ancestors know about them for the next PushProperties
// tree walk.
- SetNumDependentsNeedPushProperties(
- layer, num_dependents_need_push_properties);
+ layer->num_dependents_need_push_properties_ =
+ num_dependents_need_push_properties;
}
bool add_self_to_parent = num_dependents_need_push_properties > 0 ||
@@ -249,11 +236,64 @@ void TreeSynchronizer::PushPropertiesInternal(
*num_dependents_need_push_properties_for_parent += add_self_to_parent ? 1 : 0;
}
+static void CheckScrollAndClipPointersRecursive(Layer* layer,
+ LayerImpl* layer_impl) {
+ DCHECK_EQ(!!layer, !!layer_impl);
+ if (!layer)
+ return;
+
+ DCHECK_EQ(!!layer->scroll_parent(), !!layer_impl->scroll_parent());
+ if (layer->scroll_parent())
+ DCHECK_EQ(layer->scroll_parent()->id(), layer_impl->scroll_parent()->id());
+
+ DCHECK_EQ(!!layer->clip_parent(), !!layer_impl->clip_parent());
+ if (layer->clip_parent())
+ DCHECK_EQ(layer->clip_parent()->id(), layer_impl->clip_parent()->id());
+
+ DCHECK_EQ(!!layer->scroll_children(), !!layer_impl->scroll_children());
+ if (layer->scroll_children()) {
+ for (std::set<Layer*>::iterator it = layer->scroll_children()->begin();
+ it != layer->scroll_children()->end();
+ ++it) {
+ DCHECK_EQ((*it)->scroll_parent(), layer);
+ }
+ for (std::set<LayerImpl*>::iterator it =
+ layer_impl->scroll_children()->begin();
+ it != layer_impl->scroll_children()->end();
+ ++it) {
+ DCHECK_EQ((*it)->scroll_parent(), layer_impl);
+ }
+ }
+
+ DCHECK_EQ(!!layer->clip_children(), !!layer_impl->clip_children());
+ if (layer->clip_children()) {
+ for (std::set<Layer*>::iterator it = layer->clip_children()->begin();
+ it != layer->clip_children()->end();
+ ++it) {
+ DCHECK_EQ((*it)->clip_parent(), layer);
+ }
+ for (std::set<LayerImpl*>::iterator it =
+ layer_impl->clip_children()->begin();
+ it != layer_impl->clip_children()->end();
+ ++it) {
+ DCHECK_EQ((*it)->clip_parent(), layer_impl);
+ }
+ }
+
+ for (size_t i = 0u; i < layer->children().size(); ++i) {
+ CheckScrollAndClipPointersRecursive(layer->child_at(i),
+ layer_impl->child_at(i));
+ }
+}
+
void TreeSynchronizer::PushProperties(Layer* layer,
LayerImpl* layer_impl) {
size_t num_dependents_need_push_properties = 0;
PushPropertiesInternal(
layer, layer_impl, &num_dependents_need_push_properties);
+#if DCHECK_IS_ON
+ CheckScrollAndClipPointersRecursive(layer, layer_impl);
+#endif
}
void TreeSynchronizer::PushProperties(LayerImpl* layer, LayerImpl* layer_impl) {
diff --git a/chromium/cc/trees/tree_synchronizer.h b/chromium/cc/trees/tree_synchronizer.h
index de48cee26f0..e7b2e2bdeda 100644
--- a/chromium/cc/trees/tree_synchronizer.h
+++ b/chromium/cc/trees/tree_synchronizer.h
@@ -38,9 +38,6 @@ class CC_EXPORT TreeSynchronizer {
private:
TreeSynchronizer(); // Not instantiable.
- static void SetNumDependentsNeedPushProperties(Layer* layer, size_t num);
- static void SetNumDependentsNeedPushProperties(LayerImpl* layer, size_t num);
-
template <typename LayerType>
static void PushPropertiesInternal(
LayerType* layer,
diff --git a/chromium/cc/trees/tree_synchronizer_unittest.cc b/chromium/cc/trees/tree_synchronizer_unittest.cc
index 827c3662f79..46895541ab8 100644
--- a/chromium/cc/trees/tree_synchronizer_unittest.cc
+++ b/chromium/cc/trees/tree_synchronizer_unittest.cc
@@ -8,12 +8,15 @@
#include <set>
#include <vector>
+#include "base/format_macros.h"
+#include "base/strings/stringprintf.h"
#include "cc/animation/layer_animation_controller.h"
#include "cc/layers/layer.h"
#include "cc/layers/layer_impl.h"
#include "cc/test/animation_test_common.h"
#include "cc/test/fake_impl_proxy.h"
#include "cc/test/fake_layer_tree_host.h"
+#include "cc/test/test_shared_bitmap_manager.h"
#include "cc/trees/proxy.h"
#include "cc/trees/single_thread_proxy.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -110,12 +113,14 @@ void ExpectTreesAreIdentical(Layer* layer,
ASSERT_EQ(!!layer->mask_layer(), !!layer_impl->mask_layer());
if (layer->mask_layer()) {
+ SCOPED_TRACE("mask_layer");
ExpectTreesAreIdentical(
layer->mask_layer(), layer_impl->mask_layer(), tree_impl);
}
ASSERT_EQ(!!layer->replica_layer(), !!layer_impl->replica_layer());
if (layer->replica_layer()) {
+ SCOPED_TRACE("replica_layer");
ExpectTreesAreIdentical(
layer->replica_layer(), layer_impl->replica_layer(), tree_impl);
}
@@ -176,6 +181,7 @@ void ExpectTreesAreIdentical(Layer* layer,
}
for (size_t i = 0; i < layer_children.size(); ++i) {
+ SCOPED_TRACE(base::StringPrintf("child layer %" PRIuS, i).c_str());
ExpectTreesAreIdentical(
layer_children[i].get(), layer_impl_children[i], tree_impl);
}
@@ -552,8 +558,15 @@ TEST_F(TreeSynchronizerTest, SynchronizeAnimations) {
FakeProxy proxy;
DebugScopedSetImplThread impl(&proxy);
FakeRenderingStatsInstrumentation stats_instrumentation;
- scoped_ptr<LayerTreeHostImpl> host_impl = LayerTreeHostImpl::Create(
- settings, NULL, &proxy, &stats_instrumentation, NULL, 0);
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
+ scoped_ptr<LayerTreeHostImpl> host_impl =
+ LayerTreeHostImpl::Create(settings,
+ NULL,
+ &proxy,
+ &stats_instrumentation,
+ shared_bitmap_manager.get(),
+ 0);
scoped_refptr<Layer> layer_tree_root = Layer::Create();
host_->SetRootLayer(layer_tree_root);
@@ -584,8 +597,15 @@ TEST_F(TreeSynchronizerTest, SynchronizeScrollParent) {
FakeProxy proxy;
DebugScopedSetImplThread impl(&proxy);
FakeRenderingStatsInstrumentation stats_instrumentation;
- scoped_ptr<LayerTreeHostImpl> host_impl = LayerTreeHostImpl::Create(
- settings, NULL, &proxy, &stats_instrumentation, NULL, 0);
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
+ scoped_ptr<LayerTreeHostImpl> host_impl =
+ LayerTreeHostImpl::Create(settings,
+ NULL,
+ &proxy,
+ &stats_instrumentation,
+ shared_bitmap_manager.get(),
+ 0);
scoped_refptr<Layer> layer_tree_root = Layer::Create();
scoped_refptr<Layer> scroll_parent = Layer::Create();
@@ -605,9 +625,12 @@ TEST_F(TreeSynchronizerTest, SynchronizeScrollParent) {
host_impl->active_tree());
TreeSynchronizer::PushProperties(layer_tree_root.get(),
layer_impl_tree_root.get());
- ExpectTreesAreIdentical(layer_tree_root.get(),
- layer_impl_tree_root.get(),
- host_impl->active_tree());
+ {
+ SCOPED_TRACE("case one");
+ ExpectTreesAreIdentical(layer_tree_root.get(),
+ layer_impl_tree_root.get(),
+ host_impl->active_tree());
+ }
// Remove the first scroll child.
layer_tree_root->children()[1]->RemoveFromParent();
@@ -617,9 +640,12 @@ TEST_F(TreeSynchronizerTest, SynchronizeScrollParent) {
host_impl->active_tree());
TreeSynchronizer::PushProperties(layer_tree_root.get(),
layer_impl_tree_root.get());
- ExpectTreesAreIdentical(layer_tree_root.get(),
- layer_impl_tree_root.get(),
- host_impl->active_tree());
+ {
+ SCOPED_TRACE("case two");
+ ExpectTreesAreIdentical(layer_tree_root.get(),
+ layer_impl_tree_root.get(),
+ host_impl->active_tree());
+ }
// Add an additional scroll layer.
scoped_refptr<Layer> additional_scroll_child = Layer::Create();
@@ -631,27 +657,12 @@ TEST_F(TreeSynchronizerTest, SynchronizeScrollParent) {
host_impl->active_tree());
TreeSynchronizer::PushProperties(layer_tree_root.get(),
layer_impl_tree_root.get());
- ExpectTreesAreIdentical(layer_tree_root.get(),
- layer_impl_tree_root.get(),
- host_impl->active_tree());
-
- // Remove the scroll parent.
- scroll_parent->RemoveFromParent();
- scroll_parent = NULL;
- layer_impl_tree_root =
- TreeSynchronizer::SynchronizeTrees(layer_tree_root.get(),
- layer_impl_tree_root.Pass(),
- host_impl->active_tree());
- TreeSynchronizer::PushProperties(layer_tree_root.get(),
- layer_impl_tree_root.get());
- ExpectTreesAreIdentical(layer_tree_root.get(),
- layer_impl_tree_root.get(),
- host_impl->active_tree());
-
- // The scroll children should have been unhooked.
- EXPECT_EQ(2u, layer_tree_root->children().size());
- EXPECT_FALSE(layer_tree_root->children()[0]->scroll_parent());
- EXPECT_FALSE(layer_tree_root->children()[1]->scroll_parent());
+ {
+ SCOPED_TRACE("case three");
+ ExpectTreesAreIdentical(layer_tree_root.get(),
+ layer_impl_tree_root.get(),
+ host_impl->active_tree());
+ }
}
TEST_F(TreeSynchronizerTest, SynchronizeClipParent) {
@@ -659,8 +670,15 @@ TEST_F(TreeSynchronizerTest, SynchronizeClipParent) {
FakeProxy proxy;
DebugScopedSetImplThread impl(&proxy);
FakeRenderingStatsInstrumentation stats_instrumentation;
- scoped_ptr<LayerTreeHostImpl> host_impl = LayerTreeHostImpl::Create(
- settings, NULL, &proxy, &stats_instrumentation, NULL, 0);
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
+ new TestSharedBitmapManager());
+ scoped_ptr<LayerTreeHostImpl> host_impl =
+ LayerTreeHostImpl::Create(settings,
+ NULL,
+ &proxy,
+ &stats_instrumentation,
+ shared_bitmap_manager.get(),
+ 0);
scoped_refptr<Layer> layer_tree_root = Layer::Create();
scoped_refptr<Layer> clip_parent = Layer::Create();