Index: ui/views/view_unittest.cc |
diff --git a/ui/views/view_unittest.cc b/ui/views/view_unittest.cc |
index b1bcb6ac817d358e23d22348a9b91bb7d7d65fcf..3685673ecc9834ee048f2dd431856c0b06de79e7 100644 |
--- a/ui/views/view_unittest.cc |
+++ b/ui/views/view_unittest.cc |
@@ -240,7 +240,7 @@ class TestView : public View { |
// Ignores GestureEvent by default. |
virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE; |
- virtual void Paint(gfx::Canvas* canvas) OVERRIDE; |
+ virtual void Paint(gfx::Canvas* canvas, const CullSet& cull_set) OVERRIDE; |
virtual void SchedulePaintInRect(const gfx::Rect& rect) OVERRIDE; |
virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE; |
@@ -670,7 +670,7 @@ TEST_F(ViewTest, ScrollGestureEvent) { |
// Painting |
//////////////////////////////////////////////////////////////////////////////// |
-void TestView::Paint(gfx::Canvas* canvas) { |
+void TestView::Paint(gfx::Canvas* canvas, const CullSet& cull_set) { |
canvas->sk_canvas()->getClipBounds(&last_clip_); |
} |
@@ -3463,6 +3463,246 @@ TEST_F(ViewLayerTest, RecreateLayerMovesNonViewChildren) { |
EXPECT_EQ(v.layer()->children()[1], child.layer()); |
} |
+class BoundsTreeTestView : public View { |
+ public: |
+ BoundsTreeTestView() {} |
+ |
+ virtual void PaintChildren(gfx::Canvas* canvas, |
+ const CullSet& cull_set) OVERRIDE { |
+ // Save out a copy of the cull_set before calling the base implementation. |
+ last_cull_set_.clear(); |
+ if (cull_set.cull_set_) { |
+ for (base::hash_set<intptr_t>::iterator it = cull_set.cull_set_->begin(); |
+ it != cull_set.cull_set_->end(); |
+ ++it) { |
+ last_cull_set_.insert(reinterpret_cast<View*>(*it)); |
+ } |
+ } |
+ View::PaintChildren(canvas, cull_set); |
+ } |
+ |
+ std::set<View*> last_cull_set_; |
+}; |
+ |
+TEST_F(ViewLayerTest, BoundsTreePaintUpdatesCullSet) { |
+ BoundsTreeTestView* test_view = new BoundsTreeTestView; |
+ widget()->SetContentsView(test_view); |
+ |
+ View* v1 = new View(); |
+ v1->SetBoundsRect(gfx::Rect(10, 15, 150, 151)); |
+ test_view->AddChildView(v1); |
+ |
+ View* v2 = new View(); |
+ v2->SetBoundsRect(gfx::Rect(20, 33, 40, 50)); |
+ v1->AddChildView(v2); |
+ |
+ // Schedule a full-view paint to get everyone's rectangles updated. |
+ test_view->SchedulePaintInRect(test_view->bounds()); |
+ GetRootLayer()->GetCompositor()->ScheduleDraw(); |
+ ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); |
+ |
+ // Now we have test_view - v1 - v2. Damage to only test_view should only |
+ // return root_view and test_view. |
+ test_view->SchedulePaintInRect(gfx::Rect(0, 0, 1, 1)); |
+ GetRootLayer()->GetCompositor()->ScheduleDraw(); |
+ ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); |
+ EXPECT_EQ(2U, test_view->last_cull_set_.size()); |
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(widget()->GetRootView())); |
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(test_view)); |
+ |
+ // Damage to v1 only should only return root_view, test_view, and v1. |
+ test_view->SchedulePaintInRect(gfx::Rect(11, 16, 1, 1)); |
+ GetRootLayer()->GetCompositor()->ScheduleDraw(); |
+ ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); |
+ EXPECT_EQ(3U, test_view->last_cull_set_.size()); |
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(widget()->GetRootView())); |
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(test_view)); |
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(v1)); |
+ |
+ // A Damage rect inside v2 should get all 3 views back in the |last_cull_set_| |
+ // on call to TestView::Paint(), along with the widget root view. |
+ test_view->SchedulePaintInRect(gfx::Rect(31, 49, 1, 1)); |
+ GetRootLayer()->GetCompositor()->ScheduleDraw(); |
+ ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); |
+ EXPECT_EQ(4U, test_view->last_cull_set_.size()); |
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(widget()->GetRootView())); |
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(test_view)); |
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(v1)); |
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(v2)); |
+} |
+ |
+TEST_F(ViewLayerTest, BoundsTreeSetBoundsChangesCullSet) { |
+ BoundsTreeTestView* test_view = new BoundsTreeTestView; |
+ widget()->SetContentsView(test_view); |
+ |
+ View* v1 = new View; |
+ v1->SetBoundsRect(gfx::Rect(5, 6, 100, 101)); |
+ test_view->AddChildView(v1); |
+ |
+ View* v2 = new View; |
+ v2->SetBoundsRect(gfx::Rect(20, 33, 40, 50)); |
+ v1->AddChildView(v2); |
+ |
+ // Schedule a full-view paint to get everyone's rectangles updated. |
+ test_view->SchedulePaintInRect(test_view->bounds()); |
+ GetRootLayer()->GetCompositor()->ScheduleDraw(); |
+ ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); |
+ |
+ // Move v1 to a new origin out of the way of our next query. |
+ v1->SetBoundsRect(gfx::Rect(50, 60, 100, 101)); |
+ // The move will force a repaint. |
+ GetRootLayer()->GetCompositor()->ScheduleDraw(); |
+ ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); |
+ |
+ // Schedule a paint with damage rect where v1 used to be. |
+ test_view->SchedulePaintInRect(gfx::Rect(5, 6, 10, 11)); |
+ GetRootLayer()->GetCompositor()->ScheduleDraw(); |
+ ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); |
+ |
+ // Should only have picked up root_view and test_view. |
+ EXPECT_EQ(2U, test_view->last_cull_set_.size()); |
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(widget()->GetRootView())); |
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(test_view)); |
+} |
+ |
+TEST_F(ViewLayerTest, BoundsTreeLayerChangeMakesNewTree) { |
+ BoundsTreeTestView* test_view = new BoundsTreeTestView; |
+ widget()->SetContentsView(test_view); |
+ |
+ View* v1 = new View; |
+ v1->SetBoundsRect(gfx::Rect(5, 10, 15, 20)); |
+ test_view->AddChildView(v1); |
+ |
+ View* v2 = new View; |
+ v2->SetBoundsRect(gfx::Rect(1, 2, 3, 4)); |
+ v1->AddChildView(v2); |
+ |
+ // Schedule a full-view paint to get everyone's rectangles updated. |
+ test_view->SchedulePaintInRect(test_view->bounds()); |
+ GetRootLayer()->GetCompositor()->ScheduleDraw(); |
+ ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); |
+ |
+ // Set v1 to paint to its own layer, it should remove itself from the |
+ // test_view heiarchy and no longer intersect with damage rects in that cull |
+ // set. |
+ v1->SetPaintToLayer(true); |
+ |
+ // Schedule another full-view paint. |
+ test_view->SchedulePaintInRect(test_view->bounds()); |
+ GetRootLayer()->GetCompositor()->ScheduleDraw(); |
+ ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); |
+ // v1 and v2 should no longer be present in the test_view cull_set. |
+ EXPECT_EQ(2U, test_view->last_cull_set_.size()); |
+ EXPECT_EQ(0U, test_view->last_cull_set_.count(v1)); |
+ EXPECT_EQ(0U, test_view->last_cull_set_.count(v2)); |
+ |
+ // Now set v1 back to not painting to a layer. |
+ v1->SetPaintToLayer(false); |
+ // Schedule another full-view paint. |
+ test_view->SchedulePaintInRect(test_view->bounds()); |
+ GetRootLayer()->GetCompositor()->ScheduleDraw(); |
+ ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); |
+ // We should be back to the full cull set including v1 and v2. |
+ EXPECT_EQ(4U, test_view->last_cull_set_.size()); |
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(widget()->GetRootView())); |
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(test_view)); |
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(v1)); |
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(v2)); |
+} |
+ |
+TEST_F(ViewLayerTest, BoundsTreeRemoveChildRemovesBounds) { |
+ BoundsTreeTestView* test_view = new BoundsTreeTestView; |
+ widget()->SetContentsView(test_view); |
+ |
+ View* v1 = new View; |
+ v1->SetBoundsRect(gfx::Rect(5, 10, 15, 20)); |
+ test_view->AddChildView(v1); |
+ |
+ View* v2 = new View; |
+ v2->SetBoundsRect(gfx::Rect(1, 2, 3, 4)); |
+ v1->AddChildView(v2); |
+ |
+ // Schedule a full-view paint to get everyone's rectangles updated. |
+ test_view->SchedulePaintInRect(test_view->bounds()); |
+ GetRootLayer()->GetCompositor()->ScheduleDraw(); |
+ ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); |
+ |
+ // Now remove v1 from the root view. |
+ test_view->RemoveChildView(v1); |
+ |
+ // Schedule another full-view paint. |
+ test_view->SchedulePaintInRect(test_view->bounds()); |
+ GetRootLayer()->GetCompositor()->ScheduleDraw(); |
+ ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); |
+ // v1 and v2 should no longer be present in the test_view cull_set. |
+ EXPECT_EQ(2U, test_view->last_cull_set_.size()); |
+ EXPECT_EQ(0U, test_view->last_cull_set_.count(v1)); |
+ EXPECT_EQ(0U, test_view->last_cull_set_.count(v2)); |
+ |
+ // View v1 and v2 are no longer part of view hierarchy and therefore won't be |
+ // deleted with that hierarchy. |
+ delete v1; |
+} |
+ |
+TEST_F(ViewLayerTest, BoundsTreeMoveViewMovesBounds) { |
+ BoundsTreeTestView* test_view = new BoundsTreeTestView; |
+ widget()->SetContentsView(test_view); |
+ |
+ // Build hierarchy v1 - v2 - v3. |
+ View* v1 = new View; |
+ v1->SetBoundsRect(gfx::Rect(20, 30, 150, 160)); |
+ test_view->AddChildView(v1); |
+ |
+ View* v2 = new View; |
+ v2->SetBoundsRect(gfx::Rect(5, 10, 40, 50)); |
+ v1->AddChildView(v2); |
+ |
+ View* v3 = new View; |
+ v3->SetBoundsRect(gfx::Rect(1, 2, 3, 4)); |
+ v2->AddChildView(v3); |
+ |
+ // Schedule a full-view paint and ensure all views are present in the cull. |
+ test_view->SchedulePaintInRect(test_view->bounds()); |
+ GetRootLayer()->GetCompositor()->ScheduleDraw(); |
+ ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); |
+ EXPECT_EQ(5U, test_view->last_cull_set_.size()); |
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(widget()->GetRootView())); |
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(test_view)); |
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(v1)); |
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(v2)); |
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(v3)); |
+ |
+ // Build an unrelated view hierarchy and move v2 in to it. |
+ scoped_ptr<Widget> test_widget(new Widget); |
+ Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); |
+ params.bounds = gfx::Rect(10, 10, 500, 500); |
+ params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; |
+ test_widget->Init(params); |
+ test_widget->Show(); |
+ BoundsTreeTestView* widget_view = new BoundsTreeTestView; |
+ test_widget->SetContentsView(widget_view); |
+ widget_view->AddChildView(v2); |
+ |
+ // Now schedule full-view paints in both widgets. |
+ test_view->SchedulePaintInRect(test_view->bounds()); |
+ widget_view->SchedulePaintInRect(widget_view->bounds()); |
+ GetRootLayer()->GetCompositor()->ScheduleDraw(); |
+ ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); |
+ |
+ // Only v1 should be present in the first cull set. |
+ EXPECT_EQ(3U, test_view->last_cull_set_.size()); |
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(widget()->GetRootView())); |
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(test_view)); |
+ EXPECT_EQ(1U, test_view->last_cull_set_.count(v1)); |
+ |
+ // We should find v2 and v3 in the widget_view cull_set. |
+ EXPECT_EQ(4U, widget_view->last_cull_set_.size()); |
+ EXPECT_EQ(1U, widget_view->last_cull_set_.count(test_widget->GetRootView())); |
+ EXPECT_EQ(1U, widget_view->last_cull_set_.count(widget_view)); |
+ EXPECT_EQ(1U, widget_view->last_cull_set_.count(v2)); |
+ EXPECT_EQ(1U, widget_view->last_cull_set_.count(v3)); |
+} |
+ |
TEST_F(ViewTest, FocusableAssertions) { |
// View subclasses may change insets based on whether they are focusable, |
// which effects the preferred size. To avoid preferred size changing around |