1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <map> 6 7 #include "base/memory/scoped_ptr.h" 8 #include "base/rand_util.h" 9 #include "base/strings/string_util.h" 10 #include "base/strings/utf_string_conversions.h" 11 #include "grit/ui_strings.h" 12 #include "testing/gmock/include/gmock/gmock.h" 13 #include "ui/base/accelerators/accelerator.h" 14 #include "ui/base/clipboard/clipboard.h" 15 #include "ui/base/events/event.h" 16 #include "ui/base/keycodes/keyboard_codes.h" 17 #include "ui/base/l10n/l10n_util.h" 18 #include "ui/compositor/compositor.h" 19 #include "ui/compositor/layer.h" 20 #include "ui/compositor/layer_animator.h" 21 #include "ui/gfx/canvas.h" 22 #include "ui/gfx/path.h" 23 #include "ui/gfx/transform.h" 24 #include "ui/views/background.h" 25 #include "ui/views/controls/native/native_view_host.h" 26 #include "ui/views/controls/scroll_view.h" 27 #include "ui/views/controls/textfield/textfield.h" 28 #include "ui/views/focus/accelerator_handler.h" 29 #include "ui/views/focus/view_storage.h" 30 #include "ui/views/test/views_test_base.h" 31 #include "ui/views/view.h" 32 #include "ui/views/views_delegate.h" 33 #include "ui/views/widget/native_widget.h" 34 #include "ui/views/widget/root_view.h" 35 #include "ui/views/window/dialog_client_view.h" 36 #include "ui/views/window/dialog_delegate.h" 37 38 #if defined(OS_WIN) 39 #include "ui/views/test/test_views_delegate.h" 40 #endif 41 #if defined(USE_AURA) 42 #include "ui/aura/root_window.h" 43 #include "ui/base/gestures/gesture_recognizer.h" 44 #endif 45 46 using ::testing::_; 47 48 namespace { 49 50 // Returns true if |ancestor| is an ancestor of |layer|. 51 bool LayerIsAncestor(const ui::Layer* ancestor, const ui::Layer* layer) { 52 while (layer && layer != ancestor) 53 layer = layer->parent(); 54 return layer == ancestor; 55 } 56 57 // Convenience functions for walking a View tree. 58 const views::View* FirstView(const views::View* view) { 59 const views::View* v = view; 60 while (v->has_children()) 61 v = v->child_at(0); 62 return v; 63 } 64 65 const views::View* NextView(const views::View* view) { 66 const views::View* v = view; 67 const views::View* parent = v->parent(); 68 if (!parent) 69 return NULL; 70 int next = parent->GetIndexOf(v) + 1; 71 if (next != parent->child_count()) 72 return FirstView(parent->child_at(next)); 73 return parent; 74 } 75 76 // Convenience functions for walking a Layer tree. 77 const ui::Layer* FirstLayer(const ui::Layer* layer) { 78 const ui::Layer* l = layer; 79 while (l->children().size() > 0) 80 l = l->children()[0]; 81 return l; 82 } 83 84 const ui::Layer* NextLayer(const ui::Layer* layer) { 85 const ui::Layer* parent = layer->parent(); 86 if (!parent) 87 return NULL; 88 const std::vector<ui::Layer*> children = parent->children(); 89 size_t index; 90 for (index = 0; index < children.size(); index++) { 91 if (children[index] == layer) 92 break; 93 } 94 size_t next = index + 1; 95 if (next < children.size()) 96 return FirstLayer(children[next]); 97 return parent; 98 } 99 100 // Given the root nodes of a View tree and a Layer tree, makes sure the two 101 // trees are in sync. 102 bool ViewAndLayerTreeAreConsistent(const views::View* view, 103 const ui::Layer* layer) { 104 const views::View* v = FirstView(view); 105 const ui::Layer* l = FirstLayer(layer); 106 while (v && l) { 107 // Find the view with a layer. 108 while (v && !v->layer()) 109 v = NextView(v); 110 EXPECT_TRUE(v); 111 if (!v) 112 return false; 113 114 // Check if the View tree and the Layer tree are in sync. 115 EXPECT_EQ(l, v->layer()); 116 if (v->layer() != l) 117 return false; 118 119 // Check if the visibility states of the View and the Layer are in sync. 120 EXPECT_EQ(l->IsDrawn(), v->IsDrawn()); 121 if (v->IsDrawn() != l->IsDrawn()) { 122 for (const views::View* vv = v; vv; vv = vv->parent()) 123 LOG(ERROR) << "V: " << vv << " " << vv->visible() << " " 124 << vv->IsDrawn() << " " << vv->layer(); 125 for (const ui::Layer* ll = l; ll; ll = ll->parent()) 126 LOG(ERROR) << "L: " << ll << " " << ll->IsDrawn(); 127 return false; 128 } 129 130 // Check if the size of the View and the Layer are in sync. 131 EXPECT_EQ(l->bounds(), v->bounds()); 132 if (v->bounds() != l->bounds()) 133 return false; 134 135 if (v == view || l == layer) 136 return v == view && l == layer; 137 138 v = NextView(v); 139 l = NextLayer(l); 140 } 141 142 return false; 143 } 144 145 // Constructs a View tree with the specified depth. 146 void ConstructTree(views::View* view, int depth) { 147 if (depth == 0) 148 return; 149 int count = base::RandInt(1, 5); 150 for (int i = 0; i < count; i++) { 151 views::View* v = new views::View; 152 view->AddChildView(v); 153 if (base::RandDouble() > 0.5) 154 v->SetPaintToLayer(true); 155 if (base::RandDouble() < 0.2) 156 v->SetVisible(false); 157 158 ConstructTree(v, depth - 1); 159 } 160 } 161 162 void ScrambleTree(views::View* view) { 163 int count = view->child_count(); 164 if (count == 0) 165 return; 166 for (int i = 0; i < count; i++) { 167 ScrambleTree(view->child_at(i)); 168 } 169 170 if (count > 1) { 171 int a = base::RandInt(0, count - 1); 172 int b = base::RandInt(0, count - 1); 173 174 views::View* view_a = view->child_at(a); 175 views::View* view_b = view->child_at(b); 176 view->ReorderChildView(view_a, b); 177 view->ReorderChildView(view_b, a); 178 } 179 180 if (!view->layer() && base::RandDouble() < 0.1) 181 view->SetPaintToLayer(true); 182 183 if (base::RandDouble() < 0.1) 184 view->SetVisible(!view->visible()); 185 } 186 187 // Convenience to make constructing a GestureEvent simpler. 188 class GestureEventForTest : public ui::GestureEvent { 189 public: 190 GestureEventForTest(ui::EventType type, int x, int y, int flags) 191 : GestureEvent(type, x, y, flags, base::TimeDelta(), 192 ui::GestureEventDetails(type, 0.0f, 0.0f), 0) { 193 } 194 195 private: 196 DISALLOW_COPY_AND_ASSIGN(GestureEventForTest); 197 }; 198 199 } // namespace 200 201 namespace views { 202 203 typedef ViewsTestBase ViewTest; 204 205 // A derived class for testing purpose. 206 class TestView : public View { 207 public: 208 TestView() : View(), delete_on_pressed_(false), in_touch_sequence_(false) {} 209 virtual ~TestView() {} 210 211 // Reset all test state 212 void Reset() { 213 did_change_bounds_ = false; 214 last_mouse_event_type_ = 0; 215 location_.SetPoint(0, 0); 216 received_mouse_enter_ = false; 217 received_mouse_exit_ = false; 218 last_touch_event_type_ = 0; 219 last_touch_event_was_handled_ = false; 220 last_gesture_event_type_ = 0; 221 last_gesture_event_was_handled_ = false; 222 last_clip_.setEmpty(); 223 accelerator_count_map_.clear(); 224 } 225 226 virtual void OnBoundsChanged(const gfx::Rect& previous_bounds) OVERRIDE; 227 virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE; 228 virtual bool OnMouseDragged(const ui::MouseEvent& event) OVERRIDE; 229 virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE; 230 virtual void OnMouseEntered(const ui::MouseEvent& event) OVERRIDE; 231 virtual void OnMouseExited(const ui::MouseEvent& event) OVERRIDE; 232 233 virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE; 234 // Ignores GestureEvent by default. 235 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE; 236 237 virtual void Paint(gfx::Canvas* canvas) OVERRIDE; 238 virtual void SchedulePaintInRect(const gfx::Rect& rect) OVERRIDE; 239 virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE; 240 241 // OnBoundsChanged. 242 bool did_change_bounds_; 243 gfx::Rect new_bounds_; 244 245 // MouseEvent. 246 int last_mouse_event_type_; 247 gfx::Point location_; 248 bool received_mouse_enter_; 249 bool received_mouse_exit_; 250 bool delete_on_pressed_; 251 252 // Painting. 253 std::vector<gfx::Rect> scheduled_paint_rects_; 254 255 // GestureEvent 256 int last_gesture_event_type_; 257 bool last_gesture_event_was_handled_; 258 259 // TouchEvent. 260 int last_touch_event_type_; 261 bool last_touch_event_was_handled_; 262 bool in_touch_sequence_; 263 264 // Painting. 265 SkRect last_clip_; 266 267 // Accelerators. 268 std::map<ui::Accelerator, int> accelerator_count_map_; 269 }; 270 271 // A view subclass that ignores all touch events for testing purposes. 272 class TestViewIgnoreTouch : public TestView { 273 public: 274 TestViewIgnoreTouch() : TestView() {} 275 virtual ~TestViewIgnoreTouch() {} 276 277 private: 278 virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE; 279 }; 280 281 // A view subclass that consumes all Gesture events for testing purposes. 282 class TestViewConsumeGesture : public TestView { 283 public: 284 TestViewConsumeGesture() : TestView() {} 285 virtual ~TestViewConsumeGesture() {} 286 287 protected: 288 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE { 289 last_gesture_event_type_ = event->type(); 290 location_.SetPoint(event->x(), event->y()); 291 event->StopPropagation(); 292 } 293 294 private: 295 DISALLOW_COPY_AND_ASSIGN(TestViewConsumeGesture); 296 }; 297 298 // A view subclass that ignores all Gesture events. 299 class TestViewIgnoreGesture: public TestView { 300 public: 301 TestViewIgnoreGesture() : TestView() {} 302 virtual ~TestViewIgnoreGesture() {} 303 304 private: 305 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE { 306 } 307 308 DISALLOW_COPY_AND_ASSIGN(TestViewIgnoreGesture); 309 }; 310 311 // A view subclass that ignores all scroll-gesture events, but consume all other 312 // gesture events. 313 class TestViewIgnoreScrollGestures : public TestViewConsumeGesture { 314 public: 315 TestViewIgnoreScrollGestures() {} 316 virtual ~TestViewIgnoreScrollGestures() {} 317 318 private: 319 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE { 320 if (event->IsScrollGestureEvent()) 321 return; 322 TestViewConsumeGesture::OnGestureEvent(event); 323 } 324 325 DISALLOW_COPY_AND_ASSIGN(TestViewIgnoreScrollGestures); 326 }; 327 328 //////////////////////////////////////////////////////////////////////////////// 329 // OnBoundsChanged 330 //////////////////////////////////////////////////////////////////////////////// 331 332 void TestView::OnBoundsChanged(const gfx::Rect& previous_bounds) { 333 did_change_bounds_ = true; 334 new_bounds_ = bounds(); 335 } 336 337 TEST_F(ViewTest, OnBoundsChanged) { 338 TestView v; 339 340 gfx::Rect prev_rect(0, 0, 200, 200); 341 gfx::Rect new_rect(100, 100, 250, 250); 342 343 v.SetBoundsRect(prev_rect); 344 v.Reset(); 345 v.SetBoundsRect(new_rect); 346 347 EXPECT_TRUE(v.did_change_bounds_); 348 EXPECT_EQ(v.new_bounds_, new_rect); 349 EXPECT_EQ(v.bounds(), new_rect); 350 } 351 352 //////////////////////////////////////////////////////////////////////////////// 353 // MouseEvent 354 //////////////////////////////////////////////////////////////////////////////// 355 356 bool TestView::OnMousePressed(const ui::MouseEvent& event) { 357 last_mouse_event_type_ = event.type(); 358 location_.SetPoint(event.x(), event.y()); 359 if (delete_on_pressed_) 360 delete this; 361 return true; 362 } 363 364 bool TestView::OnMouseDragged(const ui::MouseEvent& event) { 365 last_mouse_event_type_ = event.type(); 366 location_.SetPoint(event.x(), event.y()); 367 return true; 368 } 369 370 void TestView::OnMouseReleased(const ui::MouseEvent& event) { 371 last_mouse_event_type_ = event.type(); 372 location_.SetPoint(event.x(), event.y()); 373 } 374 375 void TestView::OnMouseEntered(const ui::MouseEvent& event) { 376 received_mouse_enter_ = true; 377 } 378 379 void TestView::OnMouseExited(const ui::MouseEvent& event) { 380 received_mouse_exit_ = true; 381 } 382 383 TEST_F(ViewTest, MouseEvent) { 384 TestView* v1 = new TestView(); 385 v1->SetBoundsRect(gfx::Rect(0, 0, 300, 300)); 386 387 TestView* v2 = new TestView(); 388 v2->SetBoundsRect(gfx::Rect(100, 100, 100, 100)); 389 390 scoped_ptr<Widget> widget(new Widget); 391 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 392 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 393 params.bounds = gfx::Rect(50, 50, 650, 650); 394 widget->Init(params); 395 internal::RootView* root = 396 static_cast<internal::RootView*>(widget->GetRootView()); 397 398 root->AddChildView(v1); 399 v1->AddChildView(v2); 400 401 v1->Reset(); 402 v2->Reset(); 403 404 gfx::Point p1(110, 120); 405 ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, p1, p1, 406 ui::EF_LEFT_MOUSE_BUTTON); 407 root->OnMousePressed(pressed); 408 EXPECT_EQ(v2->last_mouse_event_type_, ui::ET_MOUSE_PRESSED); 409 EXPECT_EQ(v2->location_.x(), 10); 410 EXPECT_EQ(v2->location_.y(), 20); 411 // Make sure v1 did not receive the event 412 EXPECT_EQ(v1->last_mouse_event_type_, 0); 413 414 // Drag event out of bounds. Should still go to v2 415 v1->Reset(); 416 v2->Reset(); 417 gfx::Point p2(50, 40); 418 ui::MouseEvent dragged(ui::ET_MOUSE_DRAGGED, p2, p2, 419 ui::EF_LEFT_MOUSE_BUTTON); 420 root->OnMouseDragged(dragged); 421 EXPECT_EQ(v2->last_mouse_event_type_, ui::ET_MOUSE_DRAGGED); 422 EXPECT_EQ(v2->location_.x(), -50); 423 EXPECT_EQ(v2->location_.y(), -60); 424 // Make sure v1 did not receive the event 425 EXPECT_EQ(v1->last_mouse_event_type_, 0); 426 427 // Releasted event out of bounds. Should still go to v2 428 v1->Reset(); 429 v2->Reset(); 430 ui::MouseEvent released(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(), 0); 431 root->OnMouseDragged(released); 432 EXPECT_EQ(v2->last_mouse_event_type_, ui::ET_MOUSE_RELEASED); 433 EXPECT_EQ(v2->location_.x(), -100); 434 EXPECT_EQ(v2->location_.y(), -100); 435 // Make sure v1 did not receive the event 436 EXPECT_EQ(v1->last_mouse_event_type_, 0); 437 438 widget->CloseNow(); 439 } 440 441 // Confirm that a view can be deleted as part of processing a mouse press. 442 TEST_F(ViewTest, DeleteOnPressed) { 443 TestView* v1 = new TestView(); 444 v1->SetBoundsRect(gfx::Rect(0, 0, 300, 300)); 445 446 TestView* v2 = new TestView(); 447 v2->SetBoundsRect(gfx::Rect(100, 100, 100, 100)); 448 449 v1->Reset(); 450 v2->Reset(); 451 452 scoped_ptr<Widget> widget(new Widget); 453 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 454 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 455 params.bounds = gfx::Rect(50, 50, 650, 650); 456 widget->Init(params); 457 View* root = widget->GetRootView(); 458 459 root->AddChildView(v1); 460 v1->AddChildView(v2); 461 462 v2->delete_on_pressed_ = true; 463 gfx::Point point(110, 120); 464 ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, point, point, 465 ui::EF_LEFT_MOUSE_BUTTON); 466 root->OnMousePressed(pressed); 467 EXPECT_EQ(0, v1->child_count()); 468 469 widget->CloseNow(); 470 } 471 472 //////////////////////////////////////////////////////////////////////////////// 473 // TouchEvent 474 //////////////////////////////////////////////////////////////////////////////// 475 void TestView::OnTouchEvent(ui::TouchEvent* event) { 476 last_touch_event_type_ = event->type(); 477 location_.SetPoint(event->x(), event->y()); 478 if (!in_touch_sequence_) { 479 if (event->type() == ui::ET_TOUCH_PRESSED) { 480 in_touch_sequence_ = true; 481 event->StopPropagation(); 482 return; 483 } 484 } else { 485 if (event->type() == ui::ET_TOUCH_RELEASED) { 486 in_touch_sequence_ = false; 487 event->SetHandled(); 488 return; 489 } 490 event->StopPropagation(); 491 return; 492 } 493 494 if (last_touch_event_was_handled_) 495 event->StopPropagation(); 496 } 497 498 void TestViewIgnoreTouch::OnTouchEvent(ui::TouchEvent* event) { 499 } 500 501 TEST_F(ViewTest, TouchEvent) { 502 TestView* v1 = new TestView(); 503 v1->SetBoundsRect(gfx::Rect(0, 0, 300, 300)); 504 505 TestView* v2 = new TestView(); 506 v2->SetBoundsRect(gfx::Rect(100, 100, 100, 100)); 507 508 TestView* v3 = new TestViewIgnoreTouch(); 509 v3->SetBoundsRect(gfx::Rect(0, 0, 100, 100)); 510 511 scoped_ptr<Widget> widget(new Widget()); 512 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 513 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 514 params.bounds = gfx::Rect(50, 50, 650, 650); 515 widget->Init(params); 516 internal::RootView* root = 517 static_cast<internal::RootView*>(widget->GetRootView()); 518 519 root->AddChildView(v1); 520 v1->AddChildView(v2); 521 v2->AddChildView(v3); 522 523 // |v3| completely obscures |v2|, but all the touch events on |v3| should 524 // reach |v2| because |v3| doesn't process any touch events. 525 526 // Make sure if none of the views handle the touch event, the gesture manager 527 // does. 528 v1->Reset(); 529 v2->Reset(); 530 531 ui::TouchEvent unhandled(ui::ET_TOUCH_MOVED, 532 gfx::Point(400, 400), 533 0, /* no flags */ 534 0, /* first finger touch */ 535 base::TimeDelta(), 536 1.0, 0.0, 1.0, 0.0); 537 root->DispatchTouchEvent(&unhandled); 538 539 EXPECT_EQ(v1->last_touch_event_type_, 0); 540 EXPECT_EQ(v2->last_touch_event_type_, 0); 541 542 // Test press, drag, release touch sequence. 543 v1->Reset(); 544 v2->Reset(); 545 546 ui::TouchEvent pressed(ui::ET_TOUCH_PRESSED, 547 gfx::Point(110, 120), 548 0, /* no flags */ 549 0, /* first finger touch */ 550 base::TimeDelta(), 551 1.0, 0.0, 1.0, 0.0); 552 v2->last_touch_event_was_handled_ = true; 553 root->DispatchTouchEvent(&pressed); 554 555 EXPECT_EQ(v2->last_touch_event_type_, ui::ET_TOUCH_PRESSED); 556 EXPECT_EQ(v2->location_.x(), 10); 557 EXPECT_EQ(v2->location_.y(), 20); 558 // Make sure v1 did not receive the event 559 EXPECT_EQ(v1->last_touch_event_type_, 0); 560 561 // Drag event out of bounds. Should still go to v2 562 v1->Reset(); 563 v2->Reset(); 564 ui::TouchEvent dragged(ui::ET_TOUCH_MOVED, 565 gfx::Point(50, 40), 566 0, /* no flags */ 567 0, /* first finger touch */ 568 base::TimeDelta(), 569 1.0, 0.0, 1.0, 0.0); 570 571 root->DispatchTouchEvent(&dragged); 572 EXPECT_EQ(v2->last_touch_event_type_, ui::ET_TOUCH_MOVED); 573 EXPECT_EQ(v2->location_.x(), -50); 574 EXPECT_EQ(v2->location_.y(), -60); 575 // Make sure v1 did not receive the event 576 EXPECT_EQ(v1->last_touch_event_type_, 0); 577 578 // Released event out of bounds. Should still go to v2 579 v1->Reset(); 580 v2->Reset(); 581 ui::TouchEvent released(ui::ET_TOUCH_RELEASED, gfx::Point(), 582 0, /* no flags */ 583 0, /* first finger */ 584 base::TimeDelta(), 585 1.0, 0.0, 1.0, 0.0); 586 v2->last_touch_event_was_handled_ = true; 587 root->DispatchTouchEvent(&released); 588 EXPECT_EQ(v2->last_touch_event_type_, ui::ET_TOUCH_RELEASED); 589 EXPECT_EQ(v2->location_.x(), -100); 590 EXPECT_EQ(v2->location_.y(), -100); 591 // Make sure v1 did not receive the event 592 EXPECT_EQ(v1->last_touch_event_type_, 0); 593 594 widget->CloseNow(); 595 } 596 597 void TestView::OnGestureEvent(ui::GestureEvent* event) { 598 } 599 600 TEST_F(ViewTest, GestureEvent) { 601 // Views hierarchy for non delivery of GestureEvent. 602 TestView* v1 = new TestViewConsumeGesture(); 603 v1->SetBoundsRect(gfx::Rect(0, 0, 300, 300)); 604 605 TestView* v2 = new TestViewConsumeGesture(); 606 v2->SetBoundsRect(gfx::Rect(100, 100, 100, 100)); 607 608 TestView* v3 = new TestViewIgnoreGesture(); 609 v3->SetBoundsRect(gfx::Rect(0, 0, 100, 100)); 610 611 scoped_ptr<Widget> widget(new Widget()); 612 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 613 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 614 params.bounds = gfx::Rect(50, 50, 650, 650); 615 widget->Init(params); 616 internal::RootView* root = 617 static_cast<internal::RootView*>(widget->GetRootView()); 618 619 root->AddChildView(v1); 620 v1->AddChildView(v2); 621 v2->AddChildView(v3); 622 623 // |v3| completely obscures |v2|, but all the gesture events on |v3| should 624 // reach |v2| because |v3| doesn't process any gesture events. However, since 625 // |v2| does process gesture events, gesture events on |v3| or |v2| should not 626 // reach |v1|. 627 628 v1->Reset(); 629 v2->Reset(); 630 v3->Reset(); 631 632 // Gesture on |v3| 633 GestureEventForTest g1(ui::ET_GESTURE_TAP, 110, 110, 0); 634 root->DispatchGestureEvent(&g1); 635 EXPECT_EQ(ui::ET_GESTURE_TAP, v2->last_gesture_event_type_); 636 EXPECT_EQ(gfx::Point(10, 10), v2->location_); 637 EXPECT_EQ(ui::ET_UNKNOWN, v1->last_gesture_event_type_); 638 639 // Simulate an up so that RootView is no longer targetting |v3|. 640 GestureEventForTest g1_up(ui::ET_GESTURE_END, 110, 110, 0); 641 root->DispatchGestureEvent(&g1_up); 642 643 v1->Reset(); 644 v2->Reset(); 645 v3->Reset(); 646 647 // Gesture on |v1| 648 GestureEventForTest g2(ui::ET_GESTURE_TAP, 80, 80, 0); 649 root->DispatchGestureEvent(&g2); 650 EXPECT_EQ(ui::ET_GESTURE_TAP, v1->last_gesture_event_type_); 651 EXPECT_EQ(gfx::Point(80, 80), v1->location_); 652 EXPECT_EQ(ui::ET_UNKNOWN, v2->last_gesture_event_type_); 653 654 // Send event |g1| again. Even though the coordinates target |v3| it should go 655 // to |v1| as that is the view the touch was initially down on. 656 v1->last_gesture_event_type_ = ui::ET_UNKNOWN; 657 v3->last_gesture_event_type_ = ui::ET_UNKNOWN; 658 root->DispatchGestureEvent(&g1); 659 EXPECT_EQ(ui::ET_GESTURE_TAP, v1->last_gesture_event_type_); 660 EXPECT_EQ(ui::ET_UNKNOWN, v3->last_gesture_event_type_); 661 EXPECT_EQ("110,110", v1->location_.ToString()); 662 663 widget->CloseNow(); 664 } 665 666 TEST_F(ViewTest, ScrollGestureEvent) { 667 // Views hierarchy for non delivery of GestureEvent. 668 TestView* v1 = new TestViewConsumeGesture(); 669 v1->SetBoundsRect(gfx::Rect(0, 0, 300, 300)); 670 671 TestView* v2 = new TestViewIgnoreScrollGestures(); 672 v2->SetBoundsRect(gfx::Rect(100, 100, 100, 100)); 673 674 TestView* v3 = new TestViewIgnoreGesture(); 675 v3->SetBoundsRect(gfx::Rect(0, 0, 100, 100)); 676 677 scoped_ptr<Widget> widget(new Widget()); 678 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 679 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 680 params.bounds = gfx::Rect(50, 50, 650, 650); 681 widget->Init(params); 682 internal::RootView* root = 683 static_cast<internal::RootView*>(widget->GetRootView()); 684 685 root->AddChildView(v1); 686 v1->AddChildView(v2); 687 v2->AddChildView(v3); 688 689 // |v3| completely obscures |v2|, but all the gesture events on |v3| should 690 // reach |v2| because |v3| doesn't process any gesture events. However, since 691 // |v2| does process gesture events, gesture events on |v3| or |v2| should not 692 // reach |v1|. 693 694 v1->Reset(); 695 v2->Reset(); 696 v3->Reset(); 697 698 // Gesture on |v3| 699 GestureEventForTest g1(ui::ET_GESTURE_TAP, 110, 110, 0); 700 root->DispatchGestureEvent(&g1); 701 EXPECT_EQ(ui::ET_GESTURE_TAP, v2->last_gesture_event_type_); 702 EXPECT_EQ(gfx::Point(10, 10), v2->location_); 703 EXPECT_EQ(ui::ET_UNKNOWN, v1->last_gesture_event_type_); 704 705 v2->Reset(); 706 707 // Send scroll gestures on |v3|. The gesture should reach |v2|, however, 708 // since it does not process scroll-gesture events, these events should reach 709 // |v1|. 710 GestureEventForTest gscroll_begin(ui::ET_GESTURE_SCROLL_BEGIN, 115, 115, 0); 711 root->DispatchGestureEvent(&gscroll_begin); 712 EXPECT_EQ(ui::ET_UNKNOWN, v2->last_gesture_event_type_); 713 EXPECT_EQ(ui::ET_GESTURE_SCROLL_BEGIN, v1->last_gesture_event_type_); 714 v1->Reset(); 715 716 // Send a second tap on |v1|. The event should reach |v2| since it is the 717 // default gesture handler, and not |v1| (even though it is the view under the 718 // point, and is the scroll event handler). 719 GestureEventForTest second_tap(ui::ET_GESTURE_TAP, 70, 70, 0); 720 root->DispatchGestureEvent(&second_tap); 721 EXPECT_EQ(ui::ET_GESTURE_TAP, v2->last_gesture_event_type_); 722 EXPECT_EQ(ui::ET_UNKNOWN, v1->last_gesture_event_type_); 723 v2->Reset(); 724 725 GestureEventForTest gscroll_end(ui::ET_GESTURE_SCROLL_END, 50, 50, 0); 726 root->DispatchGestureEvent(&gscroll_end); 727 EXPECT_EQ(ui::ET_GESTURE_SCROLL_END, v1->last_gesture_event_type_); 728 v1->Reset(); 729 730 // Simulate an up so that RootView is no longer targetting |v3|. 731 GestureEventForTest g1_up(ui::ET_GESTURE_END, 110, 110, 0); 732 root->DispatchGestureEvent(&g1_up); 733 EXPECT_EQ(ui::ET_GESTURE_END, v2->last_gesture_event_type_); 734 735 v1->Reset(); 736 v2->Reset(); 737 v3->Reset(); 738 739 // Gesture on |v1| 740 GestureEventForTest g2(ui::ET_GESTURE_TAP, 80, 80, 0); 741 root->DispatchGestureEvent(&g2); 742 EXPECT_EQ(ui::ET_GESTURE_TAP, v1->last_gesture_event_type_); 743 EXPECT_EQ(gfx::Point(80, 80), v1->location_); 744 EXPECT_EQ(ui::ET_UNKNOWN, v2->last_gesture_event_type_); 745 746 // Send event |g1| again. Even though the coordinates target |v3| it should go 747 // to |v1| as that is the view the touch was initially down on. 748 v1->last_gesture_event_type_ = ui::ET_UNKNOWN; 749 v3->last_gesture_event_type_ = ui::ET_UNKNOWN; 750 root->DispatchGestureEvent(&g1); 751 EXPECT_EQ(ui::ET_GESTURE_TAP, v1->last_gesture_event_type_); 752 EXPECT_EQ(ui::ET_UNKNOWN, v3->last_gesture_event_type_); 753 EXPECT_EQ("110,110", v1->location_.ToString()); 754 755 widget->CloseNow(); 756 } 757 758 //////////////////////////////////////////////////////////////////////////////// 759 // Painting 760 //////////////////////////////////////////////////////////////////////////////// 761 762 void TestView::Paint(gfx::Canvas* canvas) { 763 canvas->sk_canvas()->getClipBounds(&last_clip_); 764 } 765 766 void TestView::SchedulePaintInRect(const gfx::Rect& rect) { 767 scheduled_paint_rects_.push_back(rect); 768 View::SchedulePaintInRect(rect); 769 } 770 771 void CheckRect(const SkRect& check_rect, const SkRect& target_rect) { 772 EXPECT_EQ(target_rect.fLeft, check_rect.fLeft); 773 EXPECT_EQ(target_rect.fRight, check_rect.fRight); 774 EXPECT_EQ(target_rect.fTop, check_rect.fTop); 775 EXPECT_EQ(target_rect.fBottom, check_rect.fBottom); 776 } 777 778 /* This test is disabled because it is flakey on some systems. 779 TEST_F(ViewTest, DISABLED_Painting) { 780 // Determine if InvalidateRect generates an empty paint rectangle. 781 EmptyWindow paint_window(CRect(50, 50, 650, 650)); 782 paint_window.RedrawWindow(CRect(0, 0, 600, 600), NULL, 783 RDW_UPDATENOW | RDW_INVALIDATE | RDW_ALLCHILDREN); 784 bool empty_paint = paint_window.empty_paint(); 785 786 NativeWidgetWin window; 787 window.set_delete_on_destroy(false); 788 window.set_window_style(WS_OVERLAPPEDWINDOW); 789 window.Init(NULL, gfx::Rect(50, 50, 650, 650), NULL); 790 View* root = window.GetRootView(); 791 792 TestView* v1 = new TestView(); 793 v1->SetBoundsRect(gfx::Rect(0, 0, 650, 650)); 794 root->AddChildView(v1); 795 796 TestView* v2 = new TestView(); 797 v2->SetBoundsRect(gfx::Rect(10, 10, 80, 80)); 798 v1->AddChildView(v2); 799 800 TestView* v3 = new TestView(); 801 v3->SetBoundsRect(gfx::Rect(10, 10, 60, 60)); 802 v2->AddChildView(v3); 803 804 TestView* v4 = new TestView(); 805 v4->SetBoundsRect(gfx::Rect(10, 200, 100, 100)); 806 v1->AddChildView(v4); 807 808 // Make sure to paint current rects 809 PaintRootView(root, empty_paint); 810 811 812 v1->Reset(); 813 v2->Reset(); 814 v3->Reset(); 815 v4->Reset(); 816 v3->SchedulePaintInRect(gfx::Rect(10, 10, 10, 10)); 817 PaintRootView(root, empty_paint); 818 819 SkRect tmp_rect; 820 821 tmp_rect.iset(10, 10, 20, 20); 822 CheckRect(v3->last_clip_, tmp_rect); 823 824 tmp_rect.iset(20, 20, 30, 30); 825 CheckRect(v2->last_clip_, tmp_rect); 826 827 tmp_rect.iset(30, 30, 40, 40); 828 CheckRect(v1->last_clip_, tmp_rect); 829 830 // Make sure v4 was not painted 831 tmp_rect.setEmpty(); 832 CheckRect(v4->last_clip_, tmp_rect); 833 834 window.DestroyWindow(); 835 } 836 */ 837 838 TEST_F(ViewTest, RemoveNotification) { 839 ViewStorage* vs = ViewStorage::GetInstance(); 840 Widget* widget = new Widget; 841 widget->Init(CreateParams(Widget::InitParams::TYPE_POPUP)); 842 View* root_view = widget->GetRootView(); 843 844 View* v1 = new View; 845 int s1 = vs->CreateStorageID(); 846 vs->StoreView(s1, v1); 847 root_view->AddChildView(v1); 848 View* v11 = new View; 849 int s11 = vs->CreateStorageID(); 850 vs->StoreView(s11, v11); 851 v1->AddChildView(v11); 852 View* v111 = new View; 853 int s111 = vs->CreateStorageID(); 854 vs->StoreView(s111, v111); 855 v11->AddChildView(v111); 856 View* v112 = new View; 857 int s112 = vs->CreateStorageID(); 858 vs->StoreView(s112, v112); 859 v11->AddChildView(v112); 860 View* v113 = new View; 861 int s113 = vs->CreateStorageID(); 862 vs->StoreView(s113, v113); 863 v11->AddChildView(v113); 864 View* v1131 = new View; 865 int s1131 = vs->CreateStorageID(); 866 vs->StoreView(s1131, v1131); 867 v113->AddChildView(v1131); 868 View* v12 = new View; 869 int s12 = vs->CreateStorageID(); 870 vs->StoreView(s12, v12); 871 v1->AddChildView(v12); 872 873 View* v2 = new View; 874 int s2 = vs->CreateStorageID(); 875 vs->StoreView(s2, v2); 876 root_view->AddChildView(v2); 877 View* v21 = new View; 878 int s21 = vs->CreateStorageID(); 879 vs->StoreView(s21, v21); 880 v2->AddChildView(v21); 881 View* v211 = new View; 882 int s211 = vs->CreateStorageID(); 883 vs->StoreView(s211, v211); 884 v21->AddChildView(v211); 885 886 size_t stored_views = vs->view_count(); 887 888 // Try removing a leaf view. 889 v21->RemoveChildView(v211); 890 EXPECT_EQ(stored_views - 1, vs->view_count()); 891 EXPECT_EQ(NULL, vs->RetrieveView(s211)); 892 delete v211; // We won't use this one anymore. 893 894 // Now try removing a view with a hierarchy of depth 1. 895 v11->RemoveChildView(v113); 896 EXPECT_EQ(stored_views - 3, vs->view_count()); 897 EXPECT_EQ(NULL, vs->RetrieveView(s113)); 898 EXPECT_EQ(NULL, vs->RetrieveView(s1131)); 899 delete v113; // We won't use this one anymore. 900 901 // Now remove even more. 902 root_view->RemoveChildView(v1); 903 EXPECT_EQ(NULL, vs->RetrieveView(s1)); 904 EXPECT_EQ(NULL, vs->RetrieveView(s11)); 905 EXPECT_EQ(NULL, vs->RetrieveView(s12)); 906 EXPECT_EQ(NULL, vs->RetrieveView(s111)); 907 EXPECT_EQ(NULL, vs->RetrieveView(s112)); 908 909 // Put v1 back for more tests. 910 root_view->AddChildView(v1); 911 vs->StoreView(s1, v1); 912 913 // Synchronously closing the window deletes the view hierarchy, which should 914 // remove all its views from ViewStorage. 915 widget->CloseNow(); 916 EXPECT_EQ(stored_views - 10, vs->view_count()); 917 EXPECT_EQ(NULL, vs->RetrieveView(s1)); 918 EXPECT_EQ(NULL, vs->RetrieveView(s12)); 919 EXPECT_EQ(NULL, vs->RetrieveView(s11)); 920 EXPECT_EQ(NULL, vs->RetrieveView(s12)); 921 EXPECT_EQ(NULL, vs->RetrieveView(s21)); 922 EXPECT_EQ(NULL, vs->RetrieveView(s111)); 923 EXPECT_EQ(NULL, vs->RetrieveView(s112)); 924 } 925 926 namespace { 927 class HitTestView : public View { 928 public: 929 explicit HitTestView(bool has_hittest_mask) 930 : has_hittest_mask_(has_hittest_mask) { 931 } 932 virtual ~HitTestView() {} 933 934 protected: 935 // Overridden from View: 936 virtual bool HasHitTestMask() const OVERRIDE { 937 return has_hittest_mask_; 938 } 939 virtual void GetHitTestMask(gfx::Path* mask) const OVERRIDE { 940 DCHECK(has_hittest_mask_); 941 DCHECK(mask); 942 943 SkScalar w = SkIntToScalar(width()); 944 SkScalar h = SkIntToScalar(height()); 945 946 // Create a triangular mask within the bounds of this View. 947 mask->moveTo(w / 2, 0); 948 mask->lineTo(w, h); 949 mask->lineTo(0, h); 950 mask->close(); 951 } 952 953 private: 954 bool has_hittest_mask_; 955 956 DISALLOW_COPY_AND_ASSIGN(HitTestView); 957 }; 958 959 gfx::Point ConvertPointToView(View* view, const gfx::Point& p) { 960 gfx::Point tmp(p); 961 View::ConvertPointToTarget(view->GetWidget()->GetRootView(), view, &tmp); 962 return tmp; 963 } 964 965 gfx::Rect ConvertRectToView(View* view, const gfx::Rect& r) { 966 gfx::Rect tmp(r); 967 tmp.set_origin(ConvertPointToView(view, r.origin())); 968 return tmp; 969 } 970 971 void RotateCounterclockwise(gfx::Transform* transform) { 972 transform->matrix().set3x3(0, -1, 0, 973 1, 0, 0, 974 0, 0, 1); 975 } 976 977 void RotateClockwise(gfx::Transform* transform) { 978 transform->matrix().set3x3( 0, 1, 0, 979 -1, 0, 0, 980 0, 0, 1); 981 } 982 983 } // namespace 984 985 TEST_F(ViewTest, HitTestMasks) { 986 Widget* widget = new Widget; 987 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 988 widget->Init(params); 989 View* root_view = widget->GetRootView(); 990 root_view->SetBoundsRect(gfx::Rect(0, 0, 500, 500)); 991 992 gfx::Rect v1_bounds = gfx::Rect(0, 0, 100, 100); 993 HitTestView* v1 = new HitTestView(false); 994 v1->SetBoundsRect(v1_bounds); 995 root_view->AddChildView(v1); 996 997 gfx::Rect v2_bounds = gfx::Rect(105, 0, 100, 100); 998 HitTestView* v2 = new HitTestView(true); 999 v2->SetBoundsRect(v2_bounds); 1000 root_view->AddChildView(v2); 1001 1002 gfx::Point v1_centerpoint = v1_bounds.CenterPoint(); 1003 gfx::Point v2_centerpoint = v2_bounds.CenterPoint(); 1004 gfx::Point v1_origin = v1_bounds.origin(); 1005 gfx::Point v2_origin = v2_bounds.origin(); 1006 1007 gfx::Rect r1(10, 10, 110, 15); 1008 gfx::Rect r2(106, 1, 98, 98); 1009 gfx::Rect r3(0, 0, 300, 300); 1010 gfx::Rect r4(115, 342, 200, 10); 1011 1012 // Test HitTestPoint 1013 EXPECT_TRUE(v1->HitTestPoint(ConvertPointToView(v1, v1_centerpoint))); 1014 EXPECT_TRUE(v2->HitTestPoint(ConvertPointToView(v2, v2_centerpoint))); 1015 1016 EXPECT_TRUE(v1->HitTestPoint(ConvertPointToView(v1, v1_origin))); 1017 EXPECT_FALSE(v2->HitTestPoint(ConvertPointToView(v2, v2_origin))); 1018 1019 // Test HitTestRect 1020 EXPECT_TRUE(v1->HitTestRect(ConvertRectToView(v1, r1))); 1021 EXPECT_FALSE(v2->HitTestRect(ConvertRectToView(v2, r1))); 1022 1023 EXPECT_FALSE(v1->HitTestRect(ConvertRectToView(v1, r2))); 1024 EXPECT_TRUE(v2->HitTestRect(ConvertRectToView(v2, r2))); 1025 1026 EXPECT_TRUE(v1->HitTestRect(ConvertRectToView(v1, r3))); 1027 EXPECT_TRUE(v2->HitTestRect(ConvertRectToView(v2, r3))); 1028 1029 EXPECT_FALSE(v1->HitTestRect(ConvertRectToView(v1, r4))); 1030 EXPECT_FALSE(v2->HitTestRect(ConvertRectToView(v2, r4))); 1031 1032 // Test GetEventHandlerForPoint 1033 EXPECT_EQ(v1, root_view->GetEventHandlerForPoint(v1_centerpoint)); 1034 EXPECT_EQ(v2, root_view->GetEventHandlerForPoint(v2_centerpoint)); 1035 1036 EXPECT_EQ(v1, root_view->GetEventHandlerForPoint(v1_origin)); 1037 EXPECT_EQ(root_view, root_view->GetEventHandlerForPoint(v2_origin)); 1038 1039 // Test GetTooltipHandlerForPoint 1040 EXPECT_EQ(v1, root_view->GetTooltipHandlerForPoint(v1_centerpoint)); 1041 EXPECT_EQ(v2, root_view->GetTooltipHandlerForPoint(v2_centerpoint)); 1042 1043 EXPECT_EQ(v1, root_view->GetTooltipHandlerForPoint(v1_origin)); 1044 EXPECT_EQ(root_view, root_view->GetTooltipHandlerForPoint(v2_origin)); 1045 1046 EXPECT_FALSE(v1->GetTooltipHandlerForPoint(v2_origin)); 1047 1048 widget->CloseNow(); 1049 } 1050 1051 TEST_F(ViewTest, NotifyEnterExitOnChild) { 1052 Widget* widget = new Widget; 1053 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 1054 widget->Init(params); 1055 View* root_view = widget->GetRootView(); 1056 root_view->SetBoundsRect(gfx::Rect(0, 0, 500, 500)); 1057 1058 // Have this hierarchy of views (the coords here are in root coord): 1059 // v1 (0, 0, 100, 100) 1060 // - v11 (0, 0, 20, 30) 1061 // - v111 (5, 5, 5, 15) 1062 // - v12 (50, 10, 30, 90) 1063 // - v121 (60, 20, 10, 10) 1064 // v2 (105, 0, 100, 100) 1065 // - v21 (120, 10, 50, 20) 1066 1067 TestView* v1 = new TestView; 1068 v1->SetBounds(0, 0, 100, 100); 1069 root_view->AddChildView(v1); 1070 v1->set_notify_enter_exit_on_child(true); 1071 1072 TestView* v11 = new TestView; 1073 v11->SetBounds(0, 0, 20, 30); 1074 v1->AddChildView(v11); 1075 1076 TestView* v111 = new TestView; 1077 v111->SetBounds(5, 5, 5, 15); 1078 v11->AddChildView(v111); 1079 1080 TestView* v12 = new TestView; 1081 v12->SetBounds(50, 10, 30, 90); 1082 v1->AddChildView(v12); 1083 1084 TestView* v121 = new TestView; 1085 v121->SetBounds(10, 10, 10, 10); 1086 v12->AddChildView(v121); 1087 1088 TestView* v2 = new TestView; 1089 v2->SetBounds(105, 0, 100, 100); 1090 root_view->AddChildView(v2); 1091 1092 TestView* v21 = new TestView; 1093 v21->SetBounds(15, 10, 50, 20); 1094 v2->AddChildView(v21); 1095 1096 v1->Reset(); 1097 v11->Reset(); 1098 v111->Reset(); 1099 v12->Reset(); 1100 v121->Reset(); 1101 v2->Reset(); 1102 v21->Reset(); 1103 1104 // Move the mouse in v111. 1105 gfx::Point p1(6, 6); 1106 ui::MouseEvent move1(ui::ET_MOUSE_MOVED, p1, p1, 0); 1107 root_view->OnMouseMoved(move1); 1108 EXPECT_TRUE(v111->received_mouse_enter_); 1109 EXPECT_FALSE(v11->last_mouse_event_type_); 1110 EXPECT_TRUE(v1->received_mouse_enter_); 1111 1112 v111->Reset(); 1113 v1->Reset(); 1114 1115 // Now, move into v121. 1116 gfx::Point p2(65, 21); 1117 ui::MouseEvent move2(ui::ET_MOUSE_MOVED, p2, p2, 0); 1118 root_view->OnMouseMoved(move2); 1119 EXPECT_TRUE(v111->received_mouse_exit_); 1120 EXPECT_TRUE(v121->received_mouse_enter_); 1121 EXPECT_FALSE(v1->last_mouse_event_type_); 1122 1123 v111->Reset(); 1124 v121->Reset(); 1125 1126 // Now, move into v11. 1127 gfx::Point p3(1, 1); 1128 ui::MouseEvent move3(ui::ET_MOUSE_MOVED, p3, p3, 0); 1129 root_view->OnMouseMoved(move3); 1130 EXPECT_TRUE(v121->received_mouse_exit_); 1131 EXPECT_TRUE(v11->received_mouse_enter_); 1132 EXPECT_FALSE(v1->last_mouse_event_type_); 1133 1134 v121->Reset(); 1135 v11->Reset(); 1136 1137 // Move to v21. 1138 gfx::Point p4(121, 15); 1139 ui::MouseEvent move4(ui::ET_MOUSE_MOVED, p4, p4, 0); 1140 root_view->OnMouseMoved(move4); 1141 EXPECT_TRUE(v21->received_mouse_enter_); 1142 EXPECT_FALSE(v2->last_mouse_event_type_); 1143 EXPECT_TRUE(v11->received_mouse_exit_); 1144 EXPECT_TRUE(v1->received_mouse_exit_); 1145 1146 v21->Reset(); 1147 v11->Reset(); 1148 v1->Reset(); 1149 1150 // Move to v1. 1151 gfx::Point p5(21, 0); 1152 ui::MouseEvent move5(ui::ET_MOUSE_MOVED, p5, p5, 0); 1153 root_view->OnMouseMoved(move5); 1154 EXPECT_TRUE(v21->received_mouse_exit_); 1155 EXPECT_TRUE(v1->received_mouse_enter_); 1156 1157 v21->Reset(); 1158 v1->Reset(); 1159 1160 // Now, move into v11. 1161 gfx::Point p6(15, 15); 1162 ui::MouseEvent mouse6(ui::ET_MOUSE_MOVED, p6, p6, 0); 1163 root_view->OnMouseMoved(mouse6); 1164 EXPECT_TRUE(v11->received_mouse_enter_); 1165 EXPECT_FALSE(v1->last_mouse_event_type_); 1166 1167 v11->Reset(); 1168 v1->Reset(); 1169 1170 // Move back into v1. Although |v1| had already received an ENTER for mouse6, 1171 // and the mouse remains inside |v1| the whole time, it receives another ENTER 1172 // when the mouse leaves v11. 1173 gfx::Point p7(21, 0); 1174 ui::MouseEvent mouse7(ui::ET_MOUSE_MOVED, p7, p7, 0); 1175 root_view->OnMouseMoved(mouse7); 1176 EXPECT_TRUE(v11->received_mouse_exit_); 1177 EXPECT_FALSE(v1->received_mouse_enter_); 1178 1179 widget->CloseNow(); 1180 } 1181 1182 TEST_F(ViewTest, Textfield) { 1183 const string16 kText = ASCIIToUTF16("Reality is that which, when you stop " 1184 "believing it, doesn't go away."); 1185 const string16 kExtraText = ASCIIToUTF16("Pretty deep, Philip!"); 1186 const string16 kEmptyString; 1187 1188 Widget* widget = new Widget; 1189 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 1190 params.bounds = gfx::Rect(0, 0, 100, 100); 1191 widget->Init(params); 1192 View* root_view = widget->GetRootView(); 1193 1194 Textfield* textfield = new Textfield(); 1195 root_view->AddChildView(textfield); 1196 1197 // Test setting, appending text. 1198 textfield->SetText(kText); 1199 EXPECT_EQ(kText, textfield->text()); 1200 textfield->AppendText(kExtraText); 1201 EXPECT_EQ(kText + kExtraText, textfield->text()); 1202 textfield->SetText(string16()); 1203 EXPECT_EQ(kEmptyString, textfield->text()); 1204 1205 // Test selection related methods. 1206 textfield->SetText(kText); 1207 EXPECT_EQ(kEmptyString, textfield->GetSelectedText()); 1208 textfield->SelectAll(false); 1209 EXPECT_EQ(kText, textfield->text()); 1210 textfield->ClearSelection(); 1211 EXPECT_EQ(kEmptyString, textfield->GetSelectedText()); 1212 1213 widget->CloseNow(); 1214 } 1215 1216 // Tests that the Textfield view respond appropiately to cut/copy/paste. 1217 TEST_F(ViewTest, TextfieldCutCopyPaste) { 1218 const string16 kNormalText = ASCIIToUTF16("Normal"); 1219 const string16 kReadOnlyText = ASCIIToUTF16("Read only"); 1220 const string16 kPasswordText = ASCIIToUTF16("Password! ** Secret stuff **"); 1221 1222 ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread(); 1223 1224 Widget* widget = new Widget; 1225 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 1226 params.bounds = gfx::Rect(0, 0, 100, 100); 1227 widget->Init(params); 1228 View* root_view = widget->GetRootView(); 1229 1230 Textfield* normal = new Textfield(); 1231 Textfield* read_only = new Textfield(); 1232 read_only->SetReadOnly(true); 1233 Textfield* password = new Textfield(Textfield::STYLE_OBSCURED); 1234 1235 root_view->AddChildView(normal); 1236 root_view->AddChildView(read_only); 1237 root_view->AddChildView(password); 1238 1239 normal->SetText(kNormalText); 1240 read_only->SetText(kReadOnlyText); 1241 password->SetText(kPasswordText); 1242 1243 // 1244 // Test cut. 1245 // 1246 1247 normal->SelectAll(false); 1248 normal->ExecuteCommand(IDS_APP_CUT); 1249 string16 result; 1250 clipboard->ReadText(ui::Clipboard::BUFFER_STANDARD, &result); 1251 EXPECT_EQ(kNormalText, result); 1252 normal->SetText(kNormalText); // Let's revert to the original content. 1253 1254 read_only->SelectAll(false); 1255 read_only->ExecuteCommand(IDS_APP_CUT); 1256 result.clear(); 1257 clipboard->ReadText(ui::Clipboard::BUFFER_STANDARD, &result); 1258 // Cut should have failed, so the clipboard content should not have changed. 1259 EXPECT_EQ(kNormalText, result); 1260 1261 password->SelectAll(false); 1262 password->ExecuteCommand(IDS_APP_CUT); 1263 result.clear(); 1264 clipboard->ReadText(ui::Clipboard::BUFFER_STANDARD, &result); 1265 // Cut should have failed, so the clipboard content should not have changed. 1266 EXPECT_EQ(kNormalText, result); 1267 1268 // 1269 // Test copy. 1270 // 1271 1272 // Start with |read_only| to observe a change in clipboard text. 1273 read_only->SelectAll(false); 1274 read_only->ExecuteCommand(IDS_APP_COPY); 1275 result.clear(); 1276 clipboard->ReadText(ui::Clipboard::BUFFER_STANDARD, &result); 1277 EXPECT_EQ(kReadOnlyText, result); 1278 1279 normal->SelectAll(false); 1280 normal->ExecuteCommand(IDS_APP_COPY); 1281 result.clear(); 1282 clipboard->ReadText(ui::Clipboard::BUFFER_STANDARD, &result); 1283 EXPECT_EQ(kNormalText, result); 1284 1285 password->SelectAll(false); 1286 password->ExecuteCommand(IDS_APP_COPY); 1287 result.clear(); 1288 clipboard->ReadText(ui::Clipboard::BUFFER_STANDARD, &result); 1289 // Text cannot be copied from an obscured field; the clipboard won't change. 1290 EXPECT_EQ(kNormalText, result); 1291 1292 // 1293 // Test paste. 1294 // 1295 1296 // Attempting to paste kNormalText in a read-only text-field should fail. 1297 read_only->SelectAll(false); 1298 read_only->ExecuteCommand(IDS_APP_PASTE); 1299 EXPECT_EQ(kReadOnlyText, read_only->text()); 1300 1301 password->SelectAll(false); 1302 password->ExecuteCommand(IDS_APP_PASTE); 1303 EXPECT_EQ(kNormalText, password->text()); 1304 1305 // Copy from |read_only| to observe a change in the normal textfield text. 1306 read_only->SelectAll(false); 1307 read_only->ExecuteCommand(IDS_APP_COPY); 1308 normal->SelectAll(false); 1309 normal->ExecuteCommand(IDS_APP_PASTE); 1310 EXPECT_EQ(kReadOnlyText, normal->text()); 1311 widget->CloseNow(); 1312 } 1313 1314 //////////////////////////////////////////////////////////////////////////////// 1315 // Accelerators 1316 //////////////////////////////////////////////////////////////////////////////// 1317 bool TestView::AcceleratorPressed(const ui::Accelerator& accelerator) { 1318 accelerator_count_map_[accelerator]++; 1319 return true; 1320 } 1321 1322 #if defined(OS_WIN) && !defined(USE_AURA) 1323 TEST_F(ViewTest, ActivateAccelerator) { 1324 // Register a keyboard accelerator before the view is added to a window. 1325 ui::Accelerator return_accelerator(ui::VKEY_RETURN, ui::EF_NONE); 1326 TestView* view = new TestView(); 1327 view->Reset(); 1328 view->AddAccelerator(return_accelerator); 1329 EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 0); 1330 1331 // Create a window and add the view as its child. 1332 scoped_ptr<Widget> widget(new Widget); 1333 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 1334 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 1335 params.bounds = gfx::Rect(0, 0, 100, 100); 1336 widget->Init(params); 1337 View* root = widget->GetRootView(); 1338 root->AddChildView(view); 1339 widget->Show(); 1340 1341 // Get the focus manager. 1342 FocusManager* focus_manager = widget->GetFocusManager(); 1343 ASSERT_TRUE(focus_manager); 1344 1345 // Hit the return key and see if it takes effect. 1346 EXPECT_TRUE(focus_manager->ProcessAccelerator(return_accelerator)); 1347 EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 1); 1348 1349 // Hit the escape key. Nothing should happen. 1350 ui::Accelerator escape_accelerator(ui::VKEY_ESCAPE, ui::EF_NONE); 1351 EXPECT_FALSE(focus_manager->ProcessAccelerator(escape_accelerator)); 1352 EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 1); 1353 EXPECT_EQ(view->accelerator_count_map_[escape_accelerator], 0); 1354 1355 // Now register the escape key and hit it again. 1356 view->AddAccelerator(escape_accelerator); 1357 EXPECT_TRUE(focus_manager->ProcessAccelerator(escape_accelerator)); 1358 EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 1); 1359 EXPECT_EQ(view->accelerator_count_map_[escape_accelerator], 1); 1360 1361 // Remove the return key accelerator. 1362 view->RemoveAccelerator(return_accelerator); 1363 EXPECT_FALSE(focus_manager->ProcessAccelerator(return_accelerator)); 1364 EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 1); 1365 EXPECT_EQ(view->accelerator_count_map_[escape_accelerator], 1); 1366 1367 // Add it again. Hit the return key and the escape key. 1368 view->AddAccelerator(return_accelerator); 1369 EXPECT_TRUE(focus_manager->ProcessAccelerator(return_accelerator)); 1370 EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 2); 1371 EXPECT_EQ(view->accelerator_count_map_[escape_accelerator], 1); 1372 EXPECT_TRUE(focus_manager->ProcessAccelerator(escape_accelerator)); 1373 EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 2); 1374 EXPECT_EQ(view->accelerator_count_map_[escape_accelerator], 2); 1375 1376 // Remove all the accelerators. 1377 view->ResetAccelerators(); 1378 EXPECT_FALSE(focus_manager->ProcessAccelerator(return_accelerator)); 1379 EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 2); 1380 EXPECT_EQ(view->accelerator_count_map_[escape_accelerator], 2); 1381 EXPECT_FALSE(focus_manager->ProcessAccelerator(escape_accelerator)); 1382 EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 2); 1383 EXPECT_EQ(view->accelerator_count_map_[escape_accelerator], 2); 1384 1385 widget->CloseNow(); 1386 } 1387 #endif 1388 1389 #if defined(OS_WIN) && !defined(USE_AURA) 1390 TEST_F(ViewTest, HiddenViewWithAccelerator) { 1391 ui::Accelerator return_accelerator(ui::VKEY_RETURN, ui::EF_NONE); 1392 TestView* view = new TestView(); 1393 view->Reset(); 1394 view->AddAccelerator(return_accelerator); 1395 EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 0); 1396 1397 scoped_ptr<Widget> widget(new Widget); 1398 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 1399 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 1400 params.bounds = gfx::Rect(0, 0, 100, 100); 1401 widget->Init(params); 1402 View* root = widget->GetRootView(); 1403 root->AddChildView(view); 1404 widget->Show(); 1405 1406 FocusManager* focus_manager = widget->GetFocusManager(); 1407 ASSERT_TRUE(focus_manager); 1408 1409 view->SetVisible(false); 1410 EXPECT_FALSE(focus_manager->ProcessAccelerator(return_accelerator)); 1411 1412 view->SetVisible(true); 1413 EXPECT_TRUE(focus_manager->ProcessAccelerator(return_accelerator)); 1414 1415 widget->CloseNow(); 1416 } 1417 #endif 1418 1419 #if defined(OS_WIN) && !defined(USE_AURA) 1420 TEST_F(ViewTest, ViewInHiddenWidgetWithAccelerator) { 1421 ui::Accelerator return_accelerator(ui::VKEY_RETURN, ui::EF_NONE); 1422 TestView* view = new TestView(); 1423 view->Reset(); 1424 view->AddAccelerator(return_accelerator); 1425 EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 0); 1426 1427 scoped_ptr<Widget> widget(new Widget); 1428 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 1429 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 1430 params.bounds = gfx::Rect(0, 0, 100, 100); 1431 widget->Init(params); 1432 View* root = widget->GetRootView(); 1433 root->AddChildView(view); 1434 1435 FocusManager* focus_manager = widget->GetFocusManager(); 1436 ASSERT_TRUE(focus_manager); 1437 1438 EXPECT_FALSE(focus_manager->ProcessAccelerator(return_accelerator)); 1439 EXPECT_EQ(0, view->accelerator_count_map_[return_accelerator]); 1440 1441 widget->Show(); 1442 EXPECT_TRUE(focus_manager->ProcessAccelerator(return_accelerator)); 1443 EXPECT_EQ(1, view->accelerator_count_map_[return_accelerator]); 1444 1445 widget->Hide(); 1446 EXPECT_FALSE(focus_manager->ProcessAccelerator(return_accelerator)); 1447 EXPECT_EQ(1, view->accelerator_count_map_[return_accelerator]); 1448 1449 widget->CloseNow(); 1450 } 1451 #endif 1452 1453 #if defined(OS_WIN) && !defined(USE_AURA) 1454 //////////////////////////////////////////////////////////////////////////////// 1455 // Mouse-wheel message rerouting 1456 //////////////////////////////////////////////////////////////////////////////// 1457 class ScrollableTestView : public View { 1458 public: 1459 ScrollableTestView() { } 1460 1461 virtual gfx::Size GetPreferredSize() { 1462 return gfx::Size(100, 10000); 1463 } 1464 1465 virtual void Layout() { 1466 SizeToPreferredSize(); 1467 } 1468 }; 1469 1470 class TestViewWithControls : public View { 1471 public: 1472 TestViewWithControls() { 1473 text_field_ = new Textfield(); 1474 AddChildView(text_field_); 1475 } 1476 1477 Textfield* text_field_; 1478 }; 1479 1480 class SimpleWidgetDelegate : public WidgetDelegate { 1481 public: 1482 explicit SimpleWidgetDelegate(View* contents) : contents_(contents) { } 1483 1484 virtual void DeleteDelegate() { delete this; } 1485 1486 virtual View* GetContentsView() { return contents_; } 1487 1488 virtual Widget* GetWidget() { return contents_->GetWidget(); } 1489 virtual const Widget* GetWidget() const { return contents_->GetWidget(); } 1490 1491 private: 1492 View* contents_; 1493 }; 1494 1495 // Tests that the mouse-wheel messages are correctly rerouted to the window 1496 // under the mouse. 1497 // TODO(jcampan): http://crbug.com/10572 Disabled as it fails on the Vista build 1498 // bot. 1499 // Note that this fails for a variety of reasons: 1500 // - focused view is apparently reset across window activations and never 1501 // properly restored 1502 // - this test depends on you not having any other window visible open under the 1503 // area that it opens the test windows. --beng 1504 TEST_F(ViewTest, DISABLED_RerouteMouseWheelTest) { 1505 TestViewWithControls* view_with_controls = new TestViewWithControls(); 1506 Widget* window1 = Widget::CreateWindowWithBounds( 1507 new SimpleWidgetDelegate(view_with_controls), 1508 gfx::Rect(0, 0, 100, 100)); 1509 window1->Show(); 1510 ScrollView* scroll_view = new ScrollView(); 1511 scroll_view->SetContents(new ScrollableTestView()); 1512 Widget* window2 = Widget::CreateWindowWithBounds( 1513 new SimpleWidgetDelegate(scroll_view), 1514 gfx::Rect(200, 200, 100, 100)); 1515 window2->Show(); 1516 EXPECT_EQ(0, scroll_view->GetVisibleRect().y()); 1517 1518 // Make the window1 active, as this is what it would be in real-world. 1519 window1->Activate(); 1520 1521 // Let's send a mouse-wheel message to the different controls and check that 1522 // it is rerouted to the window under the mouse (effectively scrolling the 1523 // scroll-view). 1524 1525 // First to the Window's HWND. 1526 ::SendMessage(view_with_controls->GetWidget()->GetNativeView(), 1527 WM_MOUSEWHEEL, MAKEWPARAM(0, -20), MAKELPARAM(250, 250)); 1528 EXPECT_EQ(20, scroll_view->GetVisibleRect().y()); 1529 1530 // Then the text-field. 1531 ::SendMessage(view_with_controls->text_field_->GetTestingHandle(), 1532 WM_MOUSEWHEEL, MAKEWPARAM(0, -20), MAKELPARAM(250, 250)); 1533 EXPECT_EQ(80, scroll_view->GetVisibleRect().y()); 1534 1535 // Ensure we don't scroll when the mouse is not over that window. 1536 ::SendMessage(view_with_controls->text_field_->GetTestingHandle(), 1537 WM_MOUSEWHEEL, MAKEWPARAM(0, -20), MAKELPARAM(50, 50)); 1538 EXPECT_EQ(80, scroll_view->GetVisibleRect().y()); 1539 1540 window1->CloseNow(); 1541 window2->CloseNow(); 1542 } 1543 #endif 1544 1545 //////////////////////////////////////////////////////////////////////////////// 1546 // Native view hierachy 1547 //////////////////////////////////////////////////////////////////////////////// 1548 class TestNativeViewHierarchy : public View { 1549 public: 1550 TestNativeViewHierarchy() { 1551 } 1552 1553 virtual void NativeViewHierarchyChanged( 1554 bool attached, 1555 gfx::NativeView native_view, 1556 internal::RootView* root_view) OVERRIDE { 1557 NotificationInfo info; 1558 info.attached = attached; 1559 info.native_view = native_view; 1560 info.root_view = root_view; 1561 notifications_.push_back(info); 1562 }; 1563 struct NotificationInfo { 1564 bool attached; 1565 gfx::NativeView native_view; 1566 internal::RootView* root_view; 1567 }; 1568 static const size_t kTotalViews = 2; 1569 std::vector<NotificationInfo> notifications_; 1570 }; 1571 1572 class TestChangeNativeViewHierarchy { 1573 public: 1574 explicit TestChangeNativeViewHierarchy(ViewTest *view_test) { 1575 view_test_ = view_test; 1576 native_host_ = new NativeViewHost(); 1577 host_ = new Widget; 1578 Widget::InitParams params = 1579 view_test->CreateParams(Widget::InitParams::TYPE_POPUP); 1580 params.bounds = gfx::Rect(0, 0, 500, 300); 1581 host_->Init(params); 1582 host_->GetRootView()->AddChildView(native_host_); 1583 for (size_t i = 0; i < TestNativeViewHierarchy::kTotalViews; ++i) { 1584 windows_[i] = new Widget; 1585 Widget::InitParams params(Widget::InitParams::TYPE_CONTROL); 1586 params.parent = host_->GetNativeView(); 1587 params.bounds = gfx::Rect(0, 0, 500, 300); 1588 windows_[i]->Init(params); 1589 root_views_[i] = windows_[i]->GetRootView(); 1590 test_views_[i] = new TestNativeViewHierarchy; 1591 root_views_[i]->AddChildView(test_views_[i]); 1592 } 1593 } 1594 1595 ~TestChangeNativeViewHierarchy() { 1596 for (size_t i = 0; i < TestNativeViewHierarchy::kTotalViews; ++i) { 1597 windows_[i]->Close(); 1598 } 1599 host_->Close(); 1600 // Will close and self-delete widgets - no need to manually delete them. 1601 view_test_->RunPendingMessages(); 1602 } 1603 1604 void CheckEnumeratingNativeWidgets() { 1605 if (!host_->GetTopLevelWidget()) 1606 return; 1607 Widget::Widgets widgets; 1608 Widget::GetAllChildWidgets(host_->GetNativeView(), &widgets); 1609 EXPECT_EQ(TestNativeViewHierarchy::kTotalViews + 1, widgets.size()); 1610 // Unfortunately there is no guarantee the sequence of views here so always 1611 // go through all of them. 1612 for (Widget::Widgets::iterator i = widgets.begin(); 1613 i != widgets.end(); ++i) { 1614 View* root_view = (*i)->GetRootView(); 1615 if (host_->GetRootView() == root_view) 1616 continue; 1617 size_t j; 1618 for (j = 0; j < TestNativeViewHierarchy::kTotalViews; ++j) 1619 if (root_views_[j] == root_view) 1620 break; 1621 // EXPECT_LT/GT/GE() fails to compile with class-defined constants 1622 // with gcc, with error 1623 // "error: undefined reference to 'TestNativeViewHierarchy::kTotalViews'" 1624 // so I forced to use EXPECT_TRUE() instead. 1625 EXPECT_TRUE(TestNativeViewHierarchy::kTotalViews > j); 1626 } 1627 } 1628 1629 void CheckChangingHierarhy() { 1630 size_t i; 1631 for (i = 0; i < TestNativeViewHierarchy::kTotalViews; ++i) { 1632 // TODO(georgey): use actual hierarchy changes to send notifications. 1633 static_cast<internal::RootView*>(root_views_[i])-> 1634 NotifyNativeViewHierarchyChanged(false, host_->GetNativeView()); 1635 static_cast<internal::RootView*>(root_views_[i])-> 1636 NotifyNativeViewHierarchyChanged(true, host_->GetNativeView()); 1637 } 1638 for (i = 0; i < TestNativeViewHierarchy::kTotalViews; ++i) { 1639 ASSERT_EQ(static_cast<size_t>(2), test_views_[i]->notifications_.size()); 1640 EXPECT_FALSE(test_views_[i]->notifications_[0].attached); 1641 EXPECT_EQ(host_->GetNativeView(), 1642 test_views_[i]->notifications_[0].native_view); 1643 EXPECT_EQ(root_views_[i], test_views_[i]->notifications_[0].root_view); 1644 EXPECT_TRUE(test_views_[i]->notifications_[1].attached); 1645 EXPECT_EQ(host_->GetNativeView(), 1646 test_views_[i]->notifications_[1].native_view); 1647 EXPECT_EQ(root_views_[i], test_views_[i]->notifications_[1].root_view); 1648 } 1649 } 1650 1651 NativeViewHost* native_host_; 1652 Widget* host_; 1653 Widget* windows_[TestNativeViewHierarchy::kTotalViews]; 1654 View* root_views_[TestNativeViewHierarchy::kTotalViews]; 1655 TestNativeViewHierarchy* test_views_[TestNativeViewHierarchy::kTotalViews]; 1656 ViewTest* view_test_; 1657 }; 1658 1659 TEST_F(ViewTest, ChangeNativeViewHierarchyFindRoots) { 1660 // TODO(georgey): Fix the test for Linux 1661 #if defined(OS_WIN) 1662 TestChangeNativeViewHierarchy test(this); 1663 test.CheckEnumeratingNativeWidgets(); 1664 #endif 1665 } 1666 1667 TEST_F(ViewTest, ChangeNativeViewHierarchyChangeHierarchy) { 1668 // TODO(georgey): Fix the test for Linux 1669 #if defined(OS_WIN) 1670 TestChangeNativeViewHierarchy test(this); 1671 test.CheckChangingHierarhy(); 1672 #endif 1673 } 1674 1675 //////////////////////////////////////////////////////////////////////////////// 1676 // Transformations 1677 //////////////////////////////////////////////////////////////////////////////// 1678 1679 class TransformPaintView : public TestView { 1680 public: 1681 TransformPaintView() {} 1682 virtual ~TransformPaintView() {} 1683 1684 void ClearScheduledPaintRect() { 1685 scheduled_paint_rect_ = gfx::Rect(); 1686 } 1687 1688 gfx::Rect scheduled_paint_rect() const { return scheduled_paint_rect_; } 1689 1690 // Overridden from View: 1691 virtual void SchedulePaintInRect(const gfx::Rect& rect) OVERRIDE { 1692 gfx::Rect xrect = ConvertRectToParent(rect); 1693 scheduled_paint_rect_.Union(xrect); 1694 } 1695 1696 private: 1697 gfx::Rect scheduled_paint_rect_; 1698 1699 DISALLOW_COPY_AND_ASSIGN(TransformPaintView); 1700 }; 1701 1702 TEST_F(ViewTest, TransformPaint) { 1703 TransformPaintView* v1 = new TransformPaintView(); 1704 v1->SetBoundsRect(gfx::Rect(0, 0, 500, 300)); 1705 1706 TestView* v2 = new TestView(); 1707 v2->SetBoundsRect(gfx::Rect(100, 100, 200, 100)); 1708 1709 Widget* widget = new Widget; 1710 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 1711 params.bounds = gfx::Rect(50, 50, 650, 650); 1712 widget->Init(params); 1713 widget->Show(); 1714 View* root = widget->GetRootView(); 1715 1716 root->AddChildView(v1); 1717 v1->AddChildView(v2); 1718 1719 // At this moment, |v2| occupies (100, 100) to (300, 200) in |root|. 1720 v1->ClearScheduledPaintRect(); 1721 v2->SchedulePaint(); 1722 1723 EXPECT_EQ(gfx::Rect(100, 100, 200, 100), v1->scheduled_paint_rect()); 1724 1725 // Rotate |v1| counter-clockwise. 1726 gfx::Transform transform; 1727 RotateCounterclockwise(&transform); 1728 transform.matrix().set(1, 3, 500.0); 1729 v1->SetTransform(transform); 1730 1731 // |v2| now occupies (100, 200) to (200, 400) in |root|. 1732 1733 v1->ClearScheduledPaintRect(); 1734 v2->SchedulePaint(); 1735 1736 EXPECT_EQ(gfx::Rect(100, 200, 100, 200), v1->scheduled_paint_rect()); 1737 1738 widget->CloseNow(); 1739 } 1740 1741 TEST_F(ViewTest, TransformEvent) { 1742 TestView* v1 = new TestView(); 1743 v1->SetBoundsRect(gfx::Rect(0, 0, 500, 300)); 1744 1745 TestView* v2 = new TestView(); 1746 v2->SetBoundsRect(gfx::Rect(100, 100, 200, 100)); 1747 1748 Widget* widget = new Widget; 1749 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 1750 params.bounds = gfx::Rect(50, 50, 650, 650); 1751 widget->Init(params); 1752 View* root = widget->GetRootView(); 1753 1754 root->AddChildView(v1); 1755 v1->AddChildView(v2); 1756 1757 // At this moment, |v2| occupies (100, 100) to (300, 200) in |root|. 1758 1759 // Rotate |v1| counter-clockwise. 1760 gfx::Transform transform(v1->GetTransform()); 1761 RotateCounterclockwise(&transform); 1762 transform.matrix().set(1, 3, 500.0); 1763 v1->SetTransform(transform); 1764 1765 // |v2| now occupies (100, 200) to (200, 400) in |root|. 1766 v1->Reset(); 1767 v2->Reset(); 1768 1769 gfx::Point p1(110, 210); 1770 ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, p1, p1, 1771 ui::EF_LEFT_MOUSE_BUTTON); 1772 root->OnMousePressed(pressed); 1773 EXPECT_EQ(0, v1->last_mouse_event_type_); 1774 EXPECT_EQ(ui::ET_MOUSE_PRESSED, v2->last_mouse_event_type_); 1775 EXPECT_EQ(190, v2->location_.x()); 1776 EXPECT_EQ(10, v2->location_.y()); 1777 1778 ui::MouseEvent released(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(), 0); 1779 root->OnMouseReleased(released); 1780 1781 // Now rotate |v2| inside |v1| clockwise. 1782 transform = v2->GetTransform(); 1783 RotateClockwise(&transform); 1784 transform.matrix().setDouble(0, 3, 100.0); 1785 v2->SetTransform(transform); 1786 1787 // Now, |v2| occupies (100, 100) to (200, 300) in |v1|, and (100, 300) to 1788 // (300, 400) in |root|. 1789 1790 v1->Reset(); 1791 v2->Reset(); 1792 1793 gfx::Point point2(110, 320); 1794 ui::MouseEvent p2(ui::ET_MOUSE_PRESSED, point2, point2, 1795 ui::EF_LEFT_MOUSE_BUTTON); 1796 root->OnMousePressed(p2); 1797 EXPECT_EQ(0, v1->last_mouse_event_type_); 1798 EXPECT_EQ(ui::ET_MOUSE_PRESSED, v2->last_mouse_event_type_); 1799 EXPECT_EQ(10, v2->location_.x()); 1800 EXPECT_EQ(20, v2->location_.y()); 1801 1802 root->OnMouseReleased(released); 1803 1804 v1->SetTransform(gfx::Transform()); 1805 v2->SetTransform(gfx::Transform()); 1806 1807 TestView* v3 = new TestView(); 1808 v3->SetBoundsRect(gfx::Rect(10, 10, 20, 30)); 1809 v2->AddChildView(v3); 1810 1811 // Rotate |v3| clockwise with respect to |v2|. 1812 transform = v1->GetTransform(); 1813 RotateClockwise(&transform); 1814 transform.matrix().setDouble(0, 3, 30.0); 1815 v3->SetTransform(transform); 1816 1817 // Scale |v2| with respect to |v1| along both axis. 1818 transform = v2->GetTransform(); 1819 transform.matrix().setDouble(0, 0, 0.8); 1820 transform.matrix().setDouble(1, 1, 0.5); 1821 v2->SetTransform(transform); 1822 1823 // |v3| occupies (108, 105) to (132, 115) in |root|. 1824 1825 v1->Reset(); 1826 v2->Reset(); 1827 v3->Reset(); 1828 1829 gfx::Point point(112, 110); 1830 ui::MouseEvent p3(ui::ET_MOUSE_PRESSED, point, point, 1831 ui::EF_LEFT_MOUSE_BUTTON); 1832 root->OnMousePressed(p3); 1833 1834 EXPECT_EQ(ui::ET_MOUSE_PRESSED, v3->last_mouse_event_type_); 1835 EXPECT_EQ(10, v3->location_.x()); 1836 EXPECT_EQ(25, v3->location_.y()); 1837 1838 root->OnMouseReleased(released); 1839 1840 v1->SetTransform(gfx::Transform()); 1841 v2->SetTransform(gfx::Transform()); 1842 v3->SetTransform(gfx::Transform()); 1843 1844 v1->Reset(); 1845 v2->Reset(); 1846 v3->Reset(); 1847 1848 // Rotate |v3| clockwise with respect to |v2|, and scale it along both axis. 1849 transform = v3->GetTransform(); 1850 RotateClockwise(&transform); 1851 transform.matrix().setDouble(0, 3, 30.0); 1852 // Rotation sets some scaling transformation. Using SetScale would overwrite 1853 // that and pollute the rotation. So combine the scaling with the existing 1854 // transforamtion. 1855 gfx::Transform scale; 1856 scale.Scale(0.8, 0.5); 1857 transform.ConcatTransform(scale); 1858 v3->SetTransform(transform); 1859 1860 // Translate |v2| with respect to |v1|. 1861 transform = v2->GetTransform(); 1862 transform.matrix().setDouble(0, 3, 10.0); 1863 transform.matrix().setDouble(1, 3, 10.0); 1864 v2->SetTransform(transform); 1865 1866 // |v3| now occupies (120, 120) to (144, 130) in |root|. 1867 1868 gfx::Point point3(124, 125); 1869 ui::MouseEvent p4(ui::ET_MOUSE_PRESSED, point3, point3, 1870 ui::EF_LEFT_MOUSE_BUTTON); 1871 root->OnMousePressed(p4); 1872 1873 EXPECT_EQ(ui::ET_MOUSE_PRESSED, v3->last_mouse_event_type_); 1874 EXPECT_EQ(10, v3->location_.x()); 1875 EXPECT_EQ(25, v3->location_.y()); 1876 1877 root->OnMouseReleased(released); 1878 1879 widget->CloseNow(); 1880 } 1881 1882 TEST_F(ViewTest, TransformVisibleBound) { 1883 gfx::Rect viewport_bounds(0, 0, 100, 100); 1884 1885 scoped_ptr<Widget> widget(new Widget); 1886 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 1887 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 1888 params.bounds = viewport_bounds; 1889 widget->Init(params); 1890 widget->GetRootView()->SetBoundsRect(viewport_bounds); 1891 1892 View* viewport = new View; 1893 widget->SetContentsView(viewport); 1894 View* contents = new View; 1895 viewport->AddChildView(contents); 1896 viewport->SetBoundsRect(viewport_bounds); 1897 contents->SetBoundsRect(gfx::Rect(0, 0, 100, 200)); 1898 1899 View* child = new View; 1900 contents->AddChildView(child); 1901 child->SetBoundsRect(gfx::Rect(10, 90, 50, 50)); 1902 EXPECT_EQ(gfx::Rect(0, 0, 50, 10), child->GetVisibleBounds()); 1903 1904 // Rotate |child| counter-clockwise 1905 gfx::Transform transform; 1906 RotateCounterclockwise(&transform); 1907 transform.matrix().setDouble(1, 3, 50.0); 1908 child->SetTransform(transform); 1909 EXPECT_EQ(gfx::Rect(40, 0, 10, 50), child->GetVisibleBounds()); 1910 1911 widget->CloseNow(); 1912 } 1913 1914 //////////////////////////////////////////////////////////////////////////////// 1915 // OnVisibleBoundsChanged() 1916 1917 class VisibleBoundsView : public View { 1918 public: 1919 VisibleBoundsView() : received_notification_(false) {} 1920 virtual ~VisibleBoundsView() {} 1921 1922 bool received_notification() const { return received_notification_; } 1923 void set_received_notification(bool received) { 1924 received_notification_ = received; 1925 } 1926 1927 private: 1928 // Overridden from View: 1929 virtual bool NeedsNotificationWhenVisibleBoundsChange() const OVERRIDE { 1930 return true; 1931 } 1932 virtual void OnVisibleBoundsChanged() OVERRIDE { 1933 received_notification_ = true; 1934 } 1935 1936 bool received_notification_; 1937 1938 DISALLOW_COPY_AND_ASSIGN(VisibleBoundsView); 1939 }; 1940 1941 TEST_F(ViewTest, OnVisibleBoundsChanged) { 1942 gfx::Rect viewport_bounds(0, 0, 100, 100); 1943 1944 scoped_ptr<Widget> widget(new Widget); 1945 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 1946 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 1947 params.bounds = viewport_bounds; 1948 widget->Init(params); 1949 widget->GetRootView()->SetBoundsRect(viewport_bounds); 1950 1951 View* viewport = new View; 1952 widget->SetContentsView(viewport); 1953 View* contents = new View; 1954 viewport->AddChildView(contents); 1955 viewport->SetBoundsRect(viewport_bounds); 1956 contents->SetBoundsRect(gfx::Rect(0, 0, 100, 200)); 1957 1958 // Create a view that cares about visible bounds notifications, and position 1959 // it just outside the visible bounds of the viewport. 1960 VisibleBoundsView* child = new VisibleBoundsView; 1961 contents->AddChildView(child); 1962 child->SetBoundsRect(gfx::Rect(10, 110, 50, 50)); 1963 1964 // The child bound should be fully clipped. 1965 EXPECT_TRUE(child->GetVisibleBounds().IsEmpty()); 1966 1967 // Now scroll the contents, but not enough to make the child visible. 1968 contents->SetY(contents->y() - 1); 1969 1970 // We should have received the notification since the visible bounds may have 1971 // changed (even though they didn't). 1972 EXPECT_TRUE(child->received_notification()); 1973 EXPECT_TRUE(child->GetVisibleBounds().IsEmpty()); 1974 child->set_received_notification(false); 1975 1976 // Now scroll the contents, this time by enough to make the child visible by 1977 // one pixel. 1978 contents->SetY(contents->y() - 10); 1979 EXPECT_TRUE(child->received_notification()); 1980 EXPECT_EQ(1, child->GetVisibleBounds().height()); 1981 child->set_received_notification(false); 1982 1983 widget->CloseNow(); 1984 } 1985 1986 //////////////////////////////////////////////////////////////////////////////// 1987 // BoundsChanged() 1988 1989 TEST_F(ViewTest, SetBoundsPaint) { 1990 TestView top_view; 1991 TestView* child_view = new TestView; 1992 1993 top_view.SetBoundsRect(gfx::Rect(0, 0, 100, 100)); 1994 top_view.scheduled_paint_rects_.clear(); 1995 child_view->SetBoundsRect(gfx::Rect(10, 10, 20, 20)); 1996 top_view.AddChildView(child_view); 1997 1998 top_view.scheduled_paint_rects_.clear(); 1999 child_view->SetBoundsRect(gfx::Rect(30, 30, 20, 20)); 2000 EXPECT_EQ(2U, top_view.scheduled_paint_rects_.size()); 2001 2002 // There should be 2 rects, spanning from (10, 10) to (50, 50). 2003 gfx::Rect paint_rect = top_view.scheduled_paint_rects_[0]; 2004 paint_rect.Union(top_view.scheduled_paint_rects_[1]); 2005 EXPECT_EQ(gfx::Rect(10, 10, 40, 40), paint_rect); 2006 } 2007 2008 // Tests conversion methods with a transform. 2009 TEST_F(ViewTest, ConvertPointToViewWithTransform) { 2010 TestView top_view; 2011 TestView* child = new TestView; 2012 TestView* child_child = new TestView; 2013 2014 top_view.AddChildView(child); 2015 child->AddChildView(child_child); 2016 2017 top_view.SetBoundsRect(gfx::Rect(0, 0, 1000, 1000)); 2018 2019 child->SetBoundsRect(gfx::Rect(7, 19, 500, 500)); 2020 gfx::Transform transform; 2021 transform.Scale(3.0, 4.0); 2022 child->SetTransform(transform); 2023 2024 child_child->SetBoundsRect(gfx::Rect(17, 13, 100, 100)); 2025 transform.MakeIdentity(); 2026 transform.Scale(5.0, 7.0); 2027 child_child->SetTransform(transform); 2028 2029 // Sanity check to make sure basic transforms act as expected. 2030 { 2031 gfx::Transform transform; 2032 transform.Translate(110.0, -110.0); 2033 transform.Scale(100.0, 55.0); 2034 transform.Translate(1.0, 1.0); 2035 2036 // convert to a 3x3 matrix. 2037 const SkMatrix& matrix = transform.matrix(); 2038 2039 EXPECT_EQ(210, matrix.getTranslateX()); 2040 EXPECT_EQ(-55, matrix.getTranslateY()); 2041 EXPECT_EQ(100, matrix.getScaleX()); 2042 EXPECT_EQ(55, matrix.getScaleY()); 2043 EXPECT_EQ(0, matrix.getSkewX()); 2044 EXPECT_EQ(0, matrix.getSkewY()); 2045 } 2046 2047 { 2048 gfx::Transform transform; 2049 transform.Translate(1.0, 1.0); 2050 gfx::Transform t2; 2051 t2.Scale(100.0, 55.0); 2052 gfx::Transform t3; 2053 t3.Translate(110.0, -110.0); 2054 transform.ConcatTransform(t2); 2055 transform.ConcatTransform(t3); 2056 2057 // convert to a 3x3 matrix 2058 const SkMatrix& matrix = transform.matrix(); 2059 2060 EXPECT_EQ(210, matrix.getTranslateX()); 2061 EXPECT_EQ(-55, matrix.getTranslateY()); 2062 EXPECT_EQ(100, matrix.getScaleX()); 2063 EXPECT_EQ(55, matrix.getScaleY()); 2064 EXPECT_EQ(0, matrix.getSkewX()); 2065 EXPECT_EQ(0, matrix.getSkewY()); 2066 } 2067 2068 // Conversions from child->top and top->child. 2069 { 2070 gfx::Point point(5, 5); 2071 View::ConvertPointToTarget(child, &top_view, &point); 2072 EXPECT_EQ(22, point.x()); 2073 EXPECT_EQ(39, point.y()); 2074 2075 point.SetPoint(22, 39); 2076 View::ConvertPointToTarget(&top_view, child, &point); 2077 EXPECT_EQ(5, point.x()); 2078 EXPECT_EQ(5, point.y()); 2079 } 2080 2081 // Conversions from child_child->top and top->child_child. 2082 { 2083 gfx::Point point(5, 5); 2084 View::ConvertPointToTarget(child_child, &top_view, &point); 2085 EXPECT_EQ(133, point.x()); 2086 EXPECT_EQ(211, point.y()); 2087 2088 point.SetPoint(133, 211); 2089 View::ConvertPointToTarget(&top_view, child_child, &point); 2090 EXPECT_EQ(5, point.x()); 2091 EXPECT_EQ(5, point.y()); 2092 } 2093 2094 // Conversions from child_child->child and child->child_child 2095 { 2096 gfx::Point point(5, 5); 2097 View::ConvertPointToTarget(child_child, child, &point); 2098 EXPECT_EQ(42, point.x()); 2099 EXPECT_EQ(48, point.y()); 2100 2101 point.SetPoint(42, 48); 2102 View::ConvertPointToTarget(child, child_child, &point); 2103 EXPECT_EQ(5, point.x()); 2104 EXPECT_EQ(5, point.y()); 2105 } 2106 2107 // Conversions from top_view to child with a value that should be negative. 2108 // This ensures we don't round up with negative numbers. 2109 { 2110 gfx::Point point(6, 18); 2111 View::ConvertPointToTarget(&top_view, child, &point); 2112 EXPECT_EQ(-1, point.x()); 2113 EXPECT_EQ(-1, point.y()); 2114 } 2115 } 2116 2117 // Tests conversion methods for rectangles. 2118 TEST_F(ViewTest, ConvertRectWithTransform) { 2119 scoped_ptr<Widget> widget(new Widget); 2120 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 2121 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 2122 params.bounds = gfx::Rect(50, 50, 650, 650); 2123 widget->Init(params); 2124 View* root = widget->GetRootView(); 2125 2126 TestView* v1 = new TestView; 2127 TestView* v2 = new TestView; 2128 root->AddChildView(v1); 2129 v1->AddChildView(v2); 2130 2131 v1->SetBoundsRect(gfx::Rect(10, 10, 500, 500)); 2132 v2->SetBoundsRect(gfx::Rect(20, 20, 100, 200)); 2133 2134 // |v2| now occupies (30, 30) to (130, 230) in |widget| 2135 gfx::Rect rect(5, 5, 15, 40); 2136 EXPECT_EQ(gfx::Rect(25, 25, 15, 40), v2->ConvertRectToParent(rect)); 2137 EXPECT_EQ(gfx::Rect(35, 35, 15, 40), v2->ConvertRectToWidget(rect)); 2138 2139 // Rotate |v2| 2140 gfx::Transform t2; 2141 RotateCounterclockwise(&t2); 2142 t2.matrix().setDouble(1, 3, 100.0); 2143 v2->SetTransform(t2); 2144 2145 // |v2| now occupies (30, 30) to (230, 130) in |widget| 2146 EXPECT_EQ(gfx::Rect(25, 100, 40, 15), v2->ConvertRectToParent(rect)); 2147 EXPECT_EQ(gfx::Rect(35, 110, 40, 15), v2->ConvertRectToWidget(rect)); 2148 2149 // Scale down |v1| 2150 gfx::Transform t1; 2151 t1.Scale(0.5, 0.5); 2152 v1->SetTransform(t1); 2153 2154 // The rectangle should remain the same for |v1|. 2155 EXPECT_EQ(gfx::Rect(25, 100, 40, 15), v2->ConvertRectToParent(rect)); 2156 2157 // |v2| now occupies (20, 20) to (120, 70) in |widget| 2158 EXPECT_EQ(gfx::Rect(22, 60, 21, 8).ToString(), 2159 v2->ConvertRectToWidget(rect).ToString()); 2160 2161 widget->CloseNow(); 2162 } 2163 2164 class ObserverView : public View { 2165 public: 2166 ObserverView(); 2167 virtual ~ObserverView(); 2168 2169 void ResetTestState(); 2170 2171 bool has_add_details() const { return has_add_details_; } 2172 bool has_remove_details() const { return has_remove_details_; } 2173 2174 const ViewHierarchyChangedDetails& add_details() const { 2175 return add_details_; 2176 } 2177 2178 const ViewHierarchyChangedDetails& remove_details() const { 2179 return remove_details_; 2180 } 2181 2182 private: 2183 // View: 2184 virtual void ViewHierarchyChanged( 2185 const ViewHierarchyChangedDetails& details) OVERRIDE; 2186 2187 bool has_add_details_; 2188 bool has_remove_details_; 2189 ViewHierarchyChangedDetails add_details_; 2190 ViewHierarchyChangedDetails remove_details_; 2191 2192 DISALLOW_COPY_AND_ASSIGN(ObserverView); 2193 }; 2194 2195 ObserverView::ObserverView() 2196 : has_add_details_(false), 2197 has_remove_details_(false) { 2198 } 2199 2200 ObserverView::~ObserverView() {} 2201 2202 void ObserverView::ResetTestState() { 2203 has_add_details_ = false; 2204 has_remove_details_ = false; 2205 add_details_ = ViewHierarchyChangedDetails(); 2206 remove_details_ = ViewHierarchyChangedDetails(); 2207 } 2208 2209 void ObserverView::ViewHierarchyChanged( 2210 const ViewHierarchyChangedDetails& details) { 2211 if (details.is_add) { 2212 has_add_details_ = true; 2213 add_details_ = details; 2214 } else { 2215 has_remove_details_ = true; 2216 remove_details_ = details; 2217 } 2218 } 2219 2220 // Verifies that the ViewHierarchyChanged() notification is sent correctly when 2221 // a child view is added or removed to all the views in the hierarchy (up and 2222 // down). 2223 // The tree looks like this: 2224 // v1 2225 // +-- v2 2226 // +-- v3 2227 // +-- v4 (starts here, then get reparented to v1) 2228 TEST_F(ViewTest, ViewHierarchyChanged) { 2229 ObserverView v1; 2230 2231 ObserverView* v3 = new ObserverView(); 2232 2233 // Add |v3| to |v2|. 2234 scoped_ptr<ObserverView> v2(new ObserverView()); 2235 v2->AddChildView(v3); 2236 2237 // Make sure both |v2| and |v3| receive the ViewHierarchyChanged() 2238 // notification. 2239 EXPECT_TRUE(v2->has_add_details()); 2240 EXPECT_FALSE(v2->has_remove_details()); 2241 EXPECT_EQ(v2.get(), v2->add_details().parent); 2242 EXPECT_EQ(v3, v2->add_details().child); 2243 EXPECT_EQ(NULL, v2->add_details().move_view); 2244 2245 EXPECT_TRUE(v3->has_add_details()); 2246 EXPECT_FALSE(v3->has_remove_details()); 2247 EXPECT_EQ(v2.get(), v3->add_details().parent); 2248 EXPECT_EQ(v3, v3->add_details().child); 2249 EXPECT_EQ(NULL, v3->add_details().move_view); 2250 2251 // Reset everything to the initial state. 2252 v2->ResetTestState(); 2253 v3->ResetTestState(); 2254 2255 // Add |v2| to v1. 2256 v1.AddChildView(v2.get()); 2257 2258 // Verifies that |v2| is the child view *added* and the parent view is |v1|. 2259 // Make sure all the views (v1, v2, v3) received _that_ information. 2260 EXPECT_TRUE(v1.has_add_details()); 2261 EXPECT_FALSE(v1.has_remove_details()); 2262 EXPECT_EQ(&v1, v1.add_details().parent); 2263 EXPECT_EQ(v2.get(), v1.add_details().child); 2264 EXPECT_EQ(NULL, v1.add_details().move_view); 2265 2266 EXPECT_TRUE(v2->has_add_details()); 2267 EXPECT_FALSE(v2->has_remove_details()); 2268 EXPECT_EQ(&v1, v2->add_details().parent); 2269 EXPECT_EQ(v2.get(), v2->add_details().child); 2270 EXPECT_EQ(NULL, v2->add_details().move_view); 2271 2272 EXPECT_TRUE(v3->has_add_details()); 2273 EXPECT_FALSE(v3->has_remove_details()); 2274 EXPECT_EQ(&v1, v3->add_details().parent); 2275 EXPECT_EQ(v2.get(), v3->add_details().child); 2276 EXPECT_EQ(NULL, v3->add_details().move_view); 2277 2278 // Reset everything to the initial state. 2279 v1.ResetTestState(); 2280 v2->ResetTestState(); 2281 v3->ResetTestState(); 2282 2283 // Remove |v2| from |v1|. 2284 v1.RemoveChildView(v2.get()); 2285 2286 // Verifies that |v2| is the child view *removed* and the parent view is |v1|. 2287 // Make sure all the views (v1, v2, v3) received _that_ information. 2288 EXPECT_FALSE(v1.has_add_details()); 2289 EXPECT_TRUE(v1.has_remove_details()); 2290 EXPECT_EQ(&v1, v1.remove_details().parent); 2291 EXPECT_EQ(v2.get(), v1.remove_details().child); 2292 EXPECT_EQ(NULL, v1.remove_details().move_view); 2293 2294 EXPECT_FALSE(v2->has_add_details()); 2295 EXPECT_TRUE(v2->has_remove_details()); 2296 EXPECT_EQ(&v1, v2->remove_details().parent); 2297 EXPECT_EQ(v2.get(), v2->remove_details().child); 2298 EXPECT_EQ(NULL, v2->remove_details().move_view); 2299 2300 EXPECT_FALSE(v3->has_add_details()); 2301 EXPECT_TRUE(v3->has_remove_details()); 2302 EXPECT_EQ(&v1, v3->remove_details().parent); 2303 EXPECT_EQ(v3, v3->remove_details().child); 2304 EXPECT_EQ(NULL, v3->remove_details().move_view); 2305 2306 // Verifies notifications when reparenting a view. 2307 ObserverView* v4 = new ObserverView(); 2308 // Add |v4| to |v2|. 2309 v2->AddChildView(v4); 2310 2311 // Reset everything to the initial state. 2312 v1.ResetTestState(); 2313 v2->ResetTestState(); 2314 v3->ResetTestState(); 2315 v4->ResetTestState(); 2316 2317 // Reparent |v4| to |v1|. 2318 v1.AddChildView(v4); 2319 2320 // Verifies that all views receive the correct information for all the child, 2321 // parent and move views. 2322 2323 // |v1| is the new parent, |v4| is the child for add, |v2| is the old parent. 2324 EXPECT_TRUE(v1.has_add_details()); 2325 EXPECT_FALSE(v1.has_remove_details()); 2326 EXPECT_EQ(&v1, v1.add_details().parent); 2327 EXPECT_EQ(v4, v1.add_details().child); 2328 EXPECT_EQ(v2.get(), v1.add_details().move_view); 2329 2330 // |v2| is the old parent, |v4| is the child for remove, |v1| is the new 2331 // parent. 2332 EXPECT_FALSE(v2->has_add_details()); 2333 EXPECT_TRUE(v2->has_remove_details()); 2334 EXPECT_EQ(v2.get(), v2->remove_details().parent); 2335 EXPECT_EQ(v4, v2->remove_details().child); 2336 EXPECT_EQ(&v1, v2->remove_details().move_view); 2337 2338 // |v3| is not impacted by this operation, and hence receives no notification. 2339 EXPECT_FALSE(v3->has_add_details()); 2340 EXPECT_FALSE(v3->has_remove_details()); 2341 2342 // |v4| is the reparented child, so it receives notifications for the remove 2343 // and then the add. |v2| is its old parent, |v1| is its new parent. 2344 EXPECT_TRUE(v4->has_remove_details()); 2345 EXPECT_TRUE(v4->has_add_details()); 2346 EXPECT_EQ(v2.get(), v4->remove_details().parent); 2347 EXPECT_EQ(&v1, v4->add_details().parent); 2348 EXPECT_EQ(v4, v4->add_details().child); 2349 EXPECT_EQ(v4, v4->remove_details().child); 2350 EXPECT_EQ(&v1, v4->remove_details().move_view); 2351 EXPECT_EQ(v2.get(), v4->add_details().move_view); 2352 } 2353 2354 // Verifies if the child views added under the root are all deleted when calling 2355 // RemoveAllChildViews. 2356 // The tree looks like this: 2357 // root 2358 // +-- child1 2359 // +-- foo 2360 // +-- bar0 2361 // +-- bar1 2362 // +-- bar2 2363 // +-- child2 2364 // +-- child3 2365 TEST_F(ViewTest, RemoveAllChildViews) { 2366 View root; 2367 2368 View* child1 = new View; 2369 root.AddChildView(child1); 2370 2371 for (int i = 0; i < 2; ++i) 2372 root.AddChildView(new View); 2373 2374 View* foo = new View; 2375 child1->AddChildView(foo); 2376 2377 // Add some nodes to |foo|. 2378 for (int i = 0; i < 3; ++i) 2379 foo->AddChildView(new View); 2380 2381 EXPECT_EQ(3, root.child_count()); 2382 EXPECT_EQ(1, child1->child_count()); 2383 EXPECT_EQ(3, foo->child_count()); 2384 2385 // Now remove all child views from root. 2386 root.RemoveAllChildViews(true); 2387 2388 EXPECT_EQ(0, root.child_count()); 2389 EXPECT_FALSE(root.has_children()); 2390 } 2391 2392 TEST_F(ViewTest, Contains) { 2393 View v1; 2394 View* v2 = new View; 2395 View* v3 = new View; 2396 2397 v1.AddChildView(v2); 2398 v2->AddChildView(v3); 2399 2400 EXPECT_FALSE(v1.Contains(NULL)); 2401 EXPECT_TRUE(v1.Contains(&v1)); 2402 EXPECT_TRUE(v1.Contains(v2)); 2403 EXPECT_TRUE(v1.Contains(v3)); 2404 2405 EXPECT_FALSE(v2->Contains(NULL)); 2406 EXPECT_TRUE(v2->Contains(v2)); 2407 EXPECT_FALSE(v2->Contains(&v1)); 2408 EXPECT_TRUE(v2->Contains(v3)); 2409 2410 EXPECT_FALSE(v3->Contains(NULL)); 2411 EXPECT_TRUE(v3->Contains(v3)); 2412 EXPECT_FALSE(v3->Contains(&v1)); 2413 EXPECT_FALSE(v3->Contains(v2)); 2414 } 2415 2416 // Verifies if GetIndexOf() returns the correct index for the specified child 2417 // view. 2418 // The tree looks like this: 2419 // root 2420 // +-- child1 2421 // +-- foo1 2422 // +-- child2 2423 TEST_F(ViewTest, GetIndexOf) { 2424 View root; 2425 2426 View* child1 = new View; 2427 root.AddChildView(child1); 2428 2429 View* child2 = new View; 2430 root.AddChildView(child2); 2431 2432 View* foo1 = new View; 2433 child1->AddChildView(foo1); 2434 2435 EXPECT_EQ(-1, root.GetIndexOf(NULL)); 2436 EXPECT_EQ(-1, root.GetIndexOf(&root)); 2437 EXPECT_EQ(0, root.GetIndexOf(child1)); 2438 EXPECT_EQ(1, root.GetIndexOf(child2)); 2439 EXPECT_EQ(-1, root.GetIndexOf(foo1)); 2440 2441 EXPECT_EQ(-1, child1->GetIndexOf(NULL)); 2442 EXPECT_EQ(-1, child1->GetIndexOf(&root)); 2443 EXPECT_EQ(-1, child1->GetIndexOf(child1)); 2444 EXPECT_EQ(-1, child1->GetIndexOf(child2)); 2445 EXPECT_EQ(0, child1->GetIndexOf(foo1)); 2446 2447 EXPECT_EQ(-1, child2->GetIndexOf(NULL)); 2448 EXPECT_EQ(-1, child2->GetIndexOf(&root)); 2449 EXPECT_EQ(-1, child2->GetIndexOf(child2)); 2450 EXPECT_EQ(-1, child2->GetIndexOf(child1)); 2451 EXPECT_EQ(-1, child2->GetIndexOf(foo1)); 2452 } 2453 2454 // Verifies that the child views can be reordered correctly. 2455 TEST_F(ViewTest, ReorderChildren) { 2456 View root; 2457 2458 View* child = new View(); 2459 root.AddChildView(child); 2460 2461 View* foo1 = new View(); 2462 child->AddChildView(foo1); 2463 View* foo2 = new View(); 2464 child->AddChildView(foo2); 2465 View* foo3 = new View(); 2466 child->AddChildView(foo3); 2467 foo1->set_focusable(true); 2468 foo2->set_focusable(true); 2469 foo3->set_focusable(true); 2470 2471 ASSERT_EQ(0, child->GetIndexOf(foo1)); 2472 ASSERT_EQ(1, child->GetIndexOf(foo2)); 2473 ASSERT_EQ(2, child->GetIndexOf(foo3)); 2474 ASSERT_EQ(foo2, foo1->GetNextFocusableView()); 2475 ASSERT_EQ(foo3, foo2->GetNextFocusableView()); 2476 ASSERT_EQ(NULL, foo3->GetNextFocusableView()); 2477 2478 // Move |foo2| at the end. 2479 child->ReorderChildView(foo2, -1); 2480 ASSERT_EQ(0, child->GetIndexOf(foo1)); 2481 ASSERT_EQ(1, child->GetIndexOf(foo3)); 2482 ASSERT_EQ(2, child->GetIndexOf(foo2)); 2483 ASSERT_EQ(foo3, foo1->GetNextFocusableView()); 2484 ASSERT_EQ(foo2, foo3->GetNextFocusableView()); 2485 ASSERT_EQ(NULL, foo2->GetNextFocusableView()); 2486 2487 // Move |foo1| at the end. 2488 child->ReorderChildView(foo1, -1); 2489 ASSERT_EQ(0, child->GetIndexOf(foo3)); 2490 ASSERT_EQ(1, child->GetIndexOf(foo2)); 2491 ASSERT_EQ(2, child->GetIndexOf(foo1)); 2492 ASSERT_EQ(NULL, foo1->GetNextFocusableView()); 2493 ASSERT_EQ(foo2, foo1->GetPreviousFocusableView()); 2494 ASSERT_EQ(foo2, foo3->GetNextFocusableView()); 2495 ASSERT_EQ(foo1, foo2->GetNextFocusableView()); 2496 2497 // Move |foo2| to the front. 2498 child->ReorderChildView(foo2, 0); 2499 ASSERT_EQ(0, child->GetIndexOf(foo2)); 2500 ASSERT_EQ(1, child->GetIndexOf(foo3)); 2501 ASSERT_EQ(2, child->GetIndexOf(foo1)); 2502 ASSERT_EQ(NULL, foo1->GetNextFocusableView()); 2503 ASSERT_EQ(foo3, foo1->GetPreviousFocusableView()); 2504 ASSERT_EQ(foo3, foo2->GetNextFocusableView()); 2505 ASSERT_EQ(foo1, foo3->GetNextFocusableView()); 2506 } 2507 2508 // Verifies that GetViewByID returns the correctly child view from the specified 2509 // ID. 2510 // The tree looks like this: 2511 // v1 2512 // +-- v2 2513 // +-- v3 2514 // +-- v4 2515 TEST_F(ViewTest, GetViewByID) { 2516 View v1; 2517 const int kV1ID = 1; 2518 v1.set_id(kV1ID); 2519 2520 View v2; 2521 const int kV2ID = 2; 2522 v2.set_id(kV2ID); 2523 2524 View v3; 2525 const int kV3ID = 3; 2526 v3.set_id(kV3ID); 2527 2528 View v4; 2529 const int kV4ID = 4; 2530 v4.set_id(kV4ID); 2531 2532 const int kV5ID = 5; 2533 2534 v1.AddChildView(&v2); 2535 v2.AddChildView(&v3); 2536 v2.AddChildView(&v4); 2537 2538 EXPECT_EQ(&v1, v1.GetViewByID(kV1ID)); 2539 EXPECT_EQ(&v2, v1.GetViewByID(kV2ID)); 2540 EXPECT_EQ(&v4, v1.GetViewByID(kV4ID)); 2541 2542 EXPECT_EQ(NULL, v1.GetViewByID(kV5ID)); // No V5 exists. 2543 EXPECT_EQ(NULL, v2.GetViewByID(kV1ID)); // It can get only from child views. 2544 2545 const int kGroup = 1; 2546 v3.SetGroup(kGroup); 2547 v4.SetGroup(kGroup); 2548 2549 View::Views views; 2550 v1.GetViewsInGroup(kGroup, &views); 2551 EXPECT_EQ(2U, views.size()); 2552 2553 View::Views::const_iterator i(std::find(views.begin(), views.end(), &v3)); 2554 EXPECT_NE(views.end(), i); 2555 2556 i = std::find(views.begin(), views.end(), &v4); 2557 EXPECT_NE(views.end(), i); 2558 } 2559 2560 TEST_F(ViewTest, AddExistingChild) { 2561 View v1, v2, v3; 2562 2563 v1.AddChildView(&v2); 2564 v1.AddChildView(&v3); 2565 EXPECT_EQ(0, v1.GetIndexOf(&v2)); 2566 EXPECT_EQ(1, v1.GetIndexOf(&v3)); 2567 2568 // Check that there's no change in order when adding at same index. 2569 v1.AddChildViewAt(&v2, 0); 2570 EXPECT_EQ(0, v1.GetIndexOf(&v2)); 2571 EXPECT_EQ(1, v1.GetIndexOf(&v3)); 2572 v1.AddChildViewAt(&v3, 1); 2573 EXPECT_EQ(0, v1.GetIndexOf(&v2)); 2574 EXPECT_EQ(1, v1.GetIndexOf(&v3)); 2575 2576 // Add it at a different index and check for change in order. 2577 v1.AddChildViewAt(&v2, 1); 2578 EXPECT_EQ(1, v1.GetIndexOf(&v2)); 2579 EXPECT_EQ(0, v1.GetIndexOf(&v3)); 2580 v1.AddChildViewAt(&v2, 0); 2581 EXPECT_EQ(0, v1.GetIndexOf(&v2)); 2582 EXPECT_EQ(1, v1.GetIndexOf(&v3)); 2583 2584 // Check that calling |AddChildView()| does not change the order. 2585 v1.AddChildView(&v2); 2586 EXPECT_EQ(0, v1.GetIndexOf(&v2)); 2587 EXPECT_EQ(1, v1.GetIndexOf(&v3)); 2588 v1.AddChildView(&v3); 2589 EXPECT_EQ(0, v1.GetIndexOf(&v2)); 2590 EXPECT_EQ(1, v1.GetIndexOf(&v3)); 2591 } 2592 2593 //////////////////////////////////////////////////////////////////////////////// 2594 // Layers 2595 //////////////////////////////////////////////////////////////////////////////// 2596 2597 #if defined(USE_AURA) 2598 2599 namespace { 2600 2601 // Test implementation of LayerAnimator. 2602 class TestLayerAnimator : public ui::LayerAnimator { 2603 public: 2604 TestLayerAnimator(); 2605 2606 const gfx::Rect& last_bounds() const { return last_bounds_; } 2607 2608 // LayerAnimator. 2609 virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE; 2610 2611 protected: 2612 virtual ~TestLayerAnimator() { } 2613 2614 private: 2615 gfx::Rect last_bounds_; 2616 2617 DISALLOW_COPY_AND_ASSIGN(TestLayerAnimator); 2618 }; 2619 2620 TestLayerAnimator::TestLayerAnimator() 2621 : ui::LayerAnimator(base::TimeDelta::FromMilliseconds(0)) { 2622 } 2623 2624 void TestLayerAnimator::SetBounds(const gfx::Rect& bounds) { 2625 last_bounds_ = bounds; 2626 } 2627 2628 } // namespace 2629 2630 class ViewLayerTest : public ViewsTestBase { 2631 public: 2632 ViewLayerTest() : widget_(NULL), old_use_acceleration_(false) {} 2633 2634 virtual ~ViewLayerTest() { 2635 } 2636 2637 // Returns the Layer used by the RootView. 2638 ui::Layer* GetRootLayer() { 2639 return widget()->GetLayer(); 2640 } 2641 2642 virtual void SetUp() OVERRIDE { 2643 ViewTest::SetUp(); 2644 old_use_acceleration_ = View::get_use_acceleration_when_possible(); 2645 View::set_use_acceleration_when_possible(true); 2646 2647 widget_ = new Widget; 2648 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 2649 params.bounds = gfx::Rect(50, 50, 200, 200); 2650 widget_->Init(params); 2651 widget_->Show(); 2652 widget_->GetRootView()->SetBounds(0, 0, 200, 200); 2653 } 2654 2655 virtual void TearDown() OVERRIDE { 2656 View::set_use_acceleration_when_possible(old_use_acceleration_); 2657 widget_->CloseNow(); 2658 ViewsTestBase::TearDown(); 2659 } 2660 2661 Widget* widget() { return widget_; } 2662 2663 private: 2664 Widget* widget_; 2665 bool old_use_acceleration_; 2666 }; 2667 2668 2669 TEST_F(ViewLayerTest, LayerToggling) { 2670 // Because we lazily create textures the calls to DrawTree are necessary to 2671 // ensure we trigger creation of textures. 2672 ui::Layer* root_layer = widget()->GetLayer(); 2673 View* content_view = new View; 2674 widget()->SetContentsView(content_view); 2675 2676 // Create v1, give it a bounds and verify everything is set up correctly. 2677 View* v1 = new View; 2678 v1->SetPaintToLayer(true); 2679 EXPECT_TRUE(v1->layer() != NULL); 2680 v1->SetBoundsRect(gfx::Rect(20, 30, 140, 150)); 2681 content_view->AddChildView(v1); 2682 ASSERT_TRUE(v1->layer() != NULL); 2683 EXPECT_EQ(root_layer, v1->layer()->parent()); 2684 EXPECT_EQ(gfx::Rect(20, 30, 140, 150), v1->layer()->bounds()); 2685 2686 // Create v2 as a child of v1 and do basic assertion testing. 2687 View* v2 = new View; 2688 v1->AddChildView(v2); 2689 EXPECT_TRUE(v2->layer() == NULL); 2690 v2->SetBoundsRect(gfx::Rect(10, 20, 30, 40)); 2691 v2->SetPaintToLayer(true); 2692 ASSERT_TRUE(v2->layer() != NULL); 2693 EXPECT_EQ(v1->layer(), v2->layer()->parent()); 2694 EXPECT_EQ(gfx::Rect(10, 20, 30, 40), v2->layer()->bounds()); 2695 2696 // Turn off v1s layer. v2 should still have a layer but its parent should have 2697 // changed. 2698 v1->SetPaintToLayer(false); 2699 EXPECT_TRUE(v1->layer() == NULL); 2700 EXPECT_TRUE(v2->layer() != NULL); 2701 EXPECT_EQ(root_layer, v2->layer()->parent()); 2702 ASSERT_EQ(1u, root_layer->children().size()); 2703 EXPECT_EQ(root_layer->children()[0], v2->layer()); 2704 // The bounds of the layer should have changed to be relative to the root view 2705 // now. 2706 EXPECT_EQ(gfx::Rect(30, 50, 30, 40), v2->layer()->bounds()); 2707 2708 // Make v1 have a layer again and verify v2s layer is wired up correctly. 2709 gfx::Transform transform; 2710 transform.Scale(2.0, 2.0); 2711 v1->SetTransform(transform); 2712 EXPECT_TRUE(v1->layer() != NULL); 2713 EXPECT_TRUE(v2->layer() != NULL); 2714 EXPECT_EQ(root_layer, v1->layer()->parent()); 2715 EXPECT_EQ(v1->layer(), v2->layer()->parent()); 2716 ASSERT_EQ(1u, root_layer->children().size()); 2717 EXPECT_EQ(root_layer->children()[0], v1->layer()); 2718 ASSERT_EQ(1u, v1->layer()->children().size()); 2719 EXPECT_EQ(v1->layer()->children()[0], v2->layer()); 2720 EXPECT_EQ(gfx::Rect(10, 20, 30, 40), v2->layer()->bounds()); 2721 } 2722 2723 // Verifies turning on a layer wires up children correctly. 2724 TEST_F(ViewLayerTest, NestedLayerToggling) { 2725 View* content_view = new View; 2726 widget()->SetContentsView(content_view); 2727 2728 // Create v1, give it a bounds and verify everything is set up correctly. 2729 View* v1 = new View; 2730 content_view->AddChildView(v1); 2731 v1->SetBoundsRect(gfx::Rect(20, 30, 140, 150)); 2732 2733 View* v2 = new View; 2734 v1->AddChildView(v2); 2735 2736 View* v3 = new View; 2737 v3->SetPaintToLayer(true); 2738 v2->AddChildView(v3); 2739 ASSERT_TRUE(v3->layer() != NULL); 2740 2741 // At this point we have v1-v2-v3. v3 has a layer, v1 and v2 don't. 2742 2743 v1->SetPaintToLayer(true); 2744 EXPECT_EQ(v1->layer(), v3->layer()->parent()); 2745 } 2746 2747 TEST_F(ViewLayerTest, LayerAnimator) { 2748 View* content_view = new View; 2749 widget()->SetContentsView(content_view); 2750 2751 View* v1 = new View; 2752 content_view->AddChildView(v1); 2753 v1->SetPaintToLayer(true); 2754 EXPECT_TRUE(v1->layer() != NULL); 2755 2756 TestLayerAnimator* animator = new TestLayerAnimator(); 2757 v1->layer()->SetAnimator(animator); 2758 2759 gfx::Rect bounds(1, 2, 3, 4); 2760 v1->SetBoundsRect(bounds); 2761 EXPECT_EQ(bounds, animator->last_bounds()); 2762 // TestLayerAnimator doesn't update the layer. 2763 EXPECT_NE(bounds, v1->layer()->bounds()); 2764 } 2765 2766 // Verifies the bounds of a layer are updated if the bounds of ancestor that 2767 // doesn't have a layer change. 2768 TEST_F(ViewLayerTest, BoundsChangeWithLayer) { 2769 View* content_view = new View; 2770 widget()->SetContentsView(content_view); 2771 2772 View* v1 = new View; 2773 content_view->AddChildView(v1); 2774 v1->SetBoundsRect(gfx::Rect(20, 30, 140, 150)); 2775 2776 View* v2 = new View; 2777 v2->SetBoundsRect(gfx::Rect(10, 11, 40, 50)); 2778 v1->AddChildView(v2); 2779 v2->SetPaintToLayer(true); 2780 ASSERT_TRUE(v2->layer() != NULL); 2781 EXPECT_EQ(gfx::Rect(30, 41, 40, 50), v2->layer()->bounds()); 2782 2783 v1->SetPosition(gfx::Point(25, 36)); 2784 EXPECT_EQ(gfx::Rect(35, 47, 40, 50), v2->layer()->bounds()); 2785 2786 v2->SetPosition(gfx::Point(11, 12)); 2787 EXPECT_EQ(gfx::Rect(36, 48, 40, 50), v2->layer()->bounds()); 2788 2789 // Bounds of the layer should change even if the view is not invisible. 2790 v1->SetVisible(false); 2791 v1->SetPosition(gfx::Point(20, 30)); 2792 EXPECT_EQ(gfx::Rect(31, 42, 40, 50), v2->layer()->bounds()); 2793 2794 v2->SetVisible(false); 2795 v2->SetBoundsRect(gfx::Rect(10, 11, 20, 30)); 2796 EXPECT_EQ(gfx::Rect(30, 41, 20, 30), v2->layer()->bounds()); 2797 } 2798 2799 // Make sure layers are positioned correctly in RTL. 2800 TEST_F(ViewLayerTest, BoundInRTL) { 2801 std::string locale = l10n_util::GetApplicationLocale(std::string()); 2802 base::i18n::SetICUDefaultLocale("he"); 2803 2804 View* view = new View; 2805 widget()->SetContentsView(view); 2806 2807 int content_width = view->width(); 2808 2809 // |v1| is initially not attached to anything. So its layer will have the same 2810 // bounds as the view. 2811 View* v1 = new View; 2812 v1->SetPaintToLayer(true); 2813 v1->SetBounds(10, 10, 20, 10); 2814 EXPECT_EQ(gfx::Rect(10, 10, 20, 10), 2815 v1->layer()->bounds()); 2816 2817 // Once |v1| is attached to the widget, its layer will get RTL-appropriate 2818 // bounds. 2819 view->AddChildView(v1); 2820 EXPECT_EQ(gfx::Rect(content_width - 30, 10, 20, 10), 2821 v1->layer()->bounds()); 2822 gfx::Rect l1bounds = v1->layer()->bounds(); 2823 2824 // Now attach a View to the widget first, then create a layer for it. Make 2825 // sure the bounds are correct. 2826 View* v2 = new View; 2827 v2->SetBounds(50, 10, 30, 10); 2828 EXPECT_FALSE(v2->layer()); 2829 view->AddChildView(v2); 2830 v2->SetPaintToLayer(true); 2831 EXPECT_EQ(gfx::Rect(content_width - 80, 10, 30, 10), 2832 v2->layer()->bounds()); 2833 gfx::Rect l2bounds = v2->layer()->bounds(); 2834 2835 view->SetPaintToLayer(true); 2836 EXPECT_EQ(l1bounds, v1->layer()->bounds()); 2837 EXPECT_EQ(l2bounds, v2->layer()->bounds()); 2838 2839 // Move one of the views. Make sure the layer is positioned correctly 2840 // afterwards. 2841 v1->SetBounds(v1->x() - 5, v1->y(), v1->width(), v1->height()); 2842 l1bounds.set_x(l1bounds.x() + 5); 2843 EXPECT_EQ(l1bounds, v1->layer()->bounds()); 2844 2845 view->SetPaintToLayer(false); 2846 EXPECT_EQ(l1bounds, v1->layer()->bounds()); 2847 EXPECT_EQ(l2bounds, v2->layer()->bounds()); 2848 2849 // Move a view again. 2850 v2->SetBounds(v2->x() + 5, v2->y(), v2->width(), v2->height()); 2851 l2bounds.set_x(l2bounds.x() - 5); 2852 EXPECT_EQ(l2bounds, v2->layer()->bounds()); 2853 2854 // Reset locale. 2855 base::i18n::SetICUDefaultLocale(locale); 2856 } 2857 2858 // Makes sure a transform persists after toggling the visibility. 2859 TEST_F(ViewLayerTest, ToggleVisibilityWithTransform) { 2860 View* view = new View; 2861 gfx::Transform transform; 2862 transform.Scale(2.0, 2.0); 2863 view->SetTransform(transform); 2864 widget()->SetContentsView(view); 2865 EXPECT_EQ(2.0f, view->GetTransform().matrix().get(0, 0)); 2866 2867 view->SetVisible(false); 2868 EXPECT_EQ(2.0f, view->GetTransform().matrix().get(0, 0)); 2869 2870 view->SetVisible(true); 2871 EXPECT_EQ(2.0f, view->GetTransform().matrix().get(0, 0)); 2872 } 2873 2874 // Verifies a transform persists after removing/adding a view with a transform. 2875 TEST_F(ViewLayerTest, ResetTransformOnLayerAfterAdd) { 2876 View* view = new View; 2877 gfx::Transform transform; 2878 transform.Scale(2.0, 2.0); 2879 view->SetTransform(transform); 2880 widget()->SetContentsView(view); 2881 EXPECT_EQ(2.0f, view->GetTransform().matrix().get(0, 0)); 2882 ASSERT_TRUE(view->layer() != NULL); 2883 EXPECT_EQ(2.0f, view->layer()->transform().matrix().get(0, 0)); 2884 2885 View* parent = view->parent(); 2886 parent->RemoveChildView(view); 2887 parent->AddChildView(view); 2888 2889 EXPECT_EQ(2.0f, view->GetTransform().matrix().get(0, 0)); 2890 ASSERT_TRUE(view->layer() != NULL); 2891 EXPECT_EQ(2.0f, view->layer()->transform().matrix().get(0, 0)); 2892 } 2893 2894 // Makes sure that layer visibility is correct after toggling View visibility. 2895 TEST_F(ViewLayerTest, ToggleVisibilityWithLayer) { 2896 View* content_view = new View; 2897 widget()->SetContentsView(content_view); 2898 2899 // The view isn't attached to a widget or a parent view yet. But it should 2900 // still have a layer, but the layer should not be attached to the root 2901 // layer. 2902 View* v1 = new View; 2903 v1->SetPaintToLayer(true); 2904 EXPECT_TRUE(v1->layer()); 2905 EXPECT_FALSE(LayerIsAncestor(widget()->GetCompositor()->root_layer(), 2906 v1->layer())); 2907 2908 // Once the view is attached to a widget, its layer should be attached to the 2909 // root layer and visible. 2910 content_view->AddChildView(v1); 2911 EXPECT_TRUE(LayerIsAncestor(widget()->GetCompositor()->root_layer(), 2912 v1->layer())); 2913 EXPECT_TRUE(v1->layer()->IsDrawn()); 2914 2915 v1->SetVisible(false); 2916 EXPECT_FALSE(v1->layer()->IsDrawn()); 2917 2918 v1->SetVisible(true); 2919 EXPECT_TRUE(v1->layer()->IsDrawn()); 2920 2921 widget()->Hide(); 2922 EXPECT_FALSE(v1->layer()->IsDrawn()); 2923 2924 widget()->Show(); 2925 EXPECT_TRUE(v1->layer()->IsDrawn()); 2926 } 2927 2928 // Tests that the layers in the subtree are orphaned after a View is removed 2929 // from the parent. 2930 TEST_F(ViewLayerTest, OrphanLayerAfterViewRemove) { 2931 View* content_view = new View; 2932 widget()->SetContentsView(content_view); 2933 2934 View* v1 = new View; 2935 content_view->AddChildView(v1); 2936 2937 View* v2 = new View; 2938 v1->AddChildView(v2); 2939 v2->SetPaintToLayer(true); 2940 EXPECT_TRUE(LayerIsAncestor(widget()->GetCompositor()->root_layer(), 2941 v2->layer())); 2942 EXPECT_TRUE(v2->layer()->IsDrawn()); 2943 2944 content_view->RemoveChildView(v1); 2945 2946 EXPECT_FALSE(LayerIsAncestor(widget()->GetCompositor()->root_layer(), 2947 v2->layer())); 2948 2949 // Reparent |v2|. 2950 content_view->AddChildView(v2); 2951 delete v1; 2952 v1 = NULL; 2953 EXPECT_TRUE(LayerIsAncestor(widget()->GetCompositor()->root_layer(), 2954 v2->layer())); 2955 EXPECT_TRUE(v2->layer()->IsDrawn()); 2956 } 2957 2958 class PaintTrackingView : public View { 2959 public: 2960 PaintTrackingView() : painted_(false) { 2961 } 2962 2963 bool painted() const { return painted_; } 2964 void set_painted(bool value) { painted_ = value; } 2965 2966 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE { 2967 painted_ = true; 2968 } 2969 2970 private: 2971 bool painted_; 2972 2973 DISALLOW_COPY_AND_ASSIGN(PaintTrackingView); 2974 }; 2975 2976 // Makes sure child views with layers aren't painted when paint starts at an 2977 // ancestor. 2978 TEST_F(ViewLayerTest, DontPaintChildrenWithLayers) { 2979 PaintTrackingView* content_view = new PaintTrackingView; 2980 widget()->SetContentsView(content_view); 2981 content_view->SetPaintToLayer(true); 2982 GetRootLayer()->GetCompositor()->ScheduleDraw(); 2983 ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); 2984 GetRootLayer()->SchedulePaint(gfx::Rect(0, 0, 10, 10)); 2985 content_view->set_painted(false); 2986 // content_view no longer has a dirty rect. Paint from the root and make sure 2987 // PaintTrackingView isn't painted. 2988 GetRootLayer()->GetCompositor()->ScheduleDraw(); 2989 ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); 2990 EXPECT_FALSE(content_view->painted()); 2991 2992 // Make content_view have a dirty rect, paint the layers and make sure 2993 // PaintTrackingView is painted. 2994 content_view->layer()->SchedulePaint(gfx::Rect(0, 0, 10, 10)); 2995 GetRootLayer()->GetCompositor()->ScheduleDraw(); 2996 ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); 2997 EXPECT_TRUE(content_view->painted()); 2998 } 2999 3000 // Tests that the visibility of child layers are updated correctly when a View's 3001 // visibility changes. 3002 TEST_F(ViewLayerTest, VisibilityChildLayers) { 3003 View* v1 = new View; 3004 v1->SetPaintToLayer(true); 3005 widget()->SetContentsView(v1); 3006 3007 View* v2 = new View; 3008 v1->AddChildView(v2); 3009 3010 View* v3 = new View; 3011 v2->AddChildView(v3); 3012 v3->SetVisible(false); 3013 3014 View* v4 = new View; 3015 v4->SetPaintToLayer(true); 3016 v3->AddChildView(v4); 3017 3018 EXPECT_TRUE(v1->layer()->IsDrawn()); 3019 EXPECT_FALSE(v4->layer()->IsDrawn()); 3020 3021 v2->SetVisible(false); 3022 EXPECT_TRUE(v1->layer()->IsDrawn()); 3023 EXPECT_FALSE(v4->layer()->IsDrawn()); 3024 3025 v2->SetVisible(true); 3026 EXPECT_TRUE(v1->layer()->IsDrawn()); 3027 EXPECT_FALSE(v4->layer()->IsDrawn()); 3028 3029 v2->SetVisible(false); 3030 EXPECT_TRUE(v1->layer()->IsDrawn()); 3031 EXPECT_FALSE(v4->layer()->IsDrawn()); 3032 EXPECT_TRUE(ViewAndLayerTreeAreConsistent(v1, v1->layer())); 3033 3034 v3->SetVisible(true); 3035 EXPECT_TRUE(v1->layer()->IsDrawn()); 3036 EXPECT_FALSE(v4->layer()->IsDrawn()); 3037 EXPECT_TRUE(ViewAndLayerTreeAreConsistent(v1, v1->layer())); 3038 3039 // Reparent |v3| to |v1|. 3040 v1->AddChildView(v3); 3041 EXPECT_TRUE(v1->layer()->IsDrawn()); 3042 EXPECT_TRUE(v4->layer()->IsDrawn()); 3043 EXPECT_TRUE(ViewAndLayerTreeAreConsistent(v1, v1->layer())); 3044 } 3045 3046 // This test creates a random View tree, and then randomly reorders child views, 3047 // reparents views etc. Unrelated changes can appear to break this test. So 3048 // marking this as FLAKY. 3049 TEST_F(ViewLayerTest, DISABLED_ViewLayerTreesInSync) { 3050 View* content = new View; 3051 content->SetPaintToLayer(true); 3052 widget()->SetContentsView(content); 3053 widget()->Show(); 3054 3055 ConstructTree(content, 5); 3056 EXPECT_TRUE(ViewAndLayerTreeAreConsistent(content, content->layer())); 3057 3058 ScrambleTree(content); 3059 EXPECT_TRUE(ViewAndLayerTreeAreConsistent(content, content->layer())); 3060 3061 ScrambleTree(content); 3062 EXPECT_TRUE(ViewAndLayerTreeAreConsistent(content, content->layer())); 3063 3064 ScrambleTree(content); 3065 EXPECT_TRUE(ViewAndLayerTreeAreConsistent(content, content->layer())); 3066 } 3067 3068 // Verifies when views are reordered the layer is also reordered. The widget is 3069 // providing the parent layer. 3070 TEST_F(ViewLayerTest, ReorderUnderWidget) { 3071 View* content = new View; 3072 widget()->SetContentsView(content); 3073 View* c1 = new View; 3074 c1->SetPaintToLayer(true); 3075 content->AddChildView(c1); 3076 View* c2 = new View; 3077 c2->SetPaintToLayer(true); 3078 content->AddChildView(c2); 3079 3080 ui::Layer* parent_layer = c1->layer()->parent(); 3081 ASSERT_TRUE(parent_layer); 3082 ASSERT_EQ(2u, parent_layer->children().size()); 3083 EXPECT_EQ(c1->layer(), parent_layer->children()[0]); 3084 EXPECT_EQ(c2->layer(), parent_layer->children()[1]); 3085 3086 // Move c1 to the front. The layers should have moved too. 3087 content->ReorderChildView(c1, -1); 3088 EXPECT_EQ(c1->layer(), parent_layer->children()[1]); 3089 EXPECT_EQ(c2->layer(), parent_layer->children()[0]); 3090 } 3091 3092 // Verifies that the layer of a view can be acquired properly. 3093 TEST_F(ViewLayerTest, AcquireLayer) { 3094 View* content = new View; 3095 widget()->SetContentsView(content); 3096 scoped_ptr<View> c1(new View); 3097 c1->SetPaintToLayer(true); 3098 EXPECT_TRUE(c1->layer()); 3099 content->AddChildView(c1.get()); 3100 3101 scoped_ptr<ui::Layer> layer(c1->AcquireLayer()); 3102 EXPECT_EQ(layer.get(), c1->layer()); 3103 3104 scoped_ptr<ui::Layer> layer2(c1->RecreateLayer()); 3105 EXPECT_NE(c1->layer(), layer2.get()); 3106 3107 // Destroy view before destroying layer. 3108 c1.reset(); 3109 } 3110 3111 // Verify that new layer scales content only if the old layer does. 3112 TEST_F(ViewLayerTest, RecreateLayerScaling) { 3113 scoped_ptr<View> v(new View()); 3114 v->SetPaintToLayer(true); 3115 // Set to non default value. 3116 v->layer()->set_scale_content(false); 3117 scoped_ptr<ui::Layer> old_layer(v->RecreateLayer()); 3118 ui::Layer* new_layer = v->layer(); 3119 EXPECT_FALSE(new_layer->scale_content()); 3120 } 3121 3122 // Verify the z-order of the layers as a result of calling RecreateLayer(). 3123 TEST_F(ViewLayerTest, RecreateLayerZOrder) { 3124 scoped_ptr<View> v(new View()); 3125 v->SetPaintToLayer(true); 3126 3127 View* v1 = new View(); 3128 v1->SetPaintToLayer(true); 3129 v->AddChildView(v1); 3130 View* v2 = new View(); 3131 v2->SetPaintToLayer(true); 3132 v->AddChildView(v2); 3133 3134 // Test the initial z-order. 3135 const std::vector<ui::Layer*>& child_layers_pre = v->layer()->children(); 3136 ASSERT_EQ(2u, child_layers_pre.size()); 3137 EXPECT_EQ(v1->layer(), child_layers_pre[0]); 3138 EXPECT_EQ(v2->layer(), child_layers_pre[1]); 3139 3140 scoped_ptr<ui::Layer> v1_old_layer(v1->RecreateLayer()); 3141 3142 // Test the new layer order. |v1_old_layer| should be above the layers 3143 // for |v1| and |v2|. 3144 const std::vector<ui::Layer*>& child_layers_post = v->layer()->children(); 3145 ASSERT_EQ(3u, child_layers_post.size()); 3146 EXPECT_EQ(v1->layer(), child_layers_post[0]); 3147 EXPECT_EQ(v2->layer(), child_layers_post[1]); 3148 EXPECT_EQ(v1_old_layer, child_layers_post[2]); 3149 } 3150 3151 // Verify the z-order of the layers as a result of calling RecreateLayer when 3152 // the widget is the parent with the layer. 3153 TEST_F(ViewLayerTest, RecreateLayerZOrderWidgetParent) { 3154 View* v = new View(); 3155 widget()->SetContentsView(v); 3156 3157 View* v1 = new View(); 3158 v1->SetPaintToLayer(true); 3159 v->AddChildView(v1); 3160 View* v2 = new View(); 3161 v2->SetPaintToLayer(true); 3162 v->AddChildView(v2); 3163 3164 ui::Layer* root_layer = GetRootLayer(); 3165 3166 // Test the initial z-order. 3167 const std::vector<ui::Layer*>& child_layers_pre = root_layer->children(); 3168 ASSERT_EQ(2u, child_layers_pre.size()); 3169 EXPECT_EQ(v1->layer(), child_layers_pre[0]); 3170 EXPECT_EQ(v2->layer(), child_layers_pre[1]); 3171 3172 scoped_ptr<ui::Layer> v1_old_layer(v1->RecreateLayer()); 3173 3174 // Test the new layer order. |v1_old_layer| should be above the layers 3175 // for |v1| and |v2|. 3176 const std::vector<ui::Layer*>& child_layers_post = root_layer->children(); 3177 ASSERT_EQ(3u, child_layers_post.size()); 3178 EXPECT_EQ(v1->layer(), child_layers_post[0]); 3179 EXPECT_EQ(v2->layer(), child_layers_post[1]); 3180 EXPECT_EQ(v1_old_layer, child_layers_post[2]); 3181 } 3182 3183 #endif // USE_AURA 3184 3185 } // namespace views 3186