diff options
Diffstat (limited to 'chromium/cc/trees/layer_tree_host_impl_unittest.cc')
-rw-r--r-- | chromium/cc/trees/layer_tree_host_impl_unittest.cc | 2518 |
1 files changed, 1851 insertions, 667 deletions
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 |