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 "ui/base/accelerators/accelerator.h" 13 #include "ui/base/clipboard/clipboard.h" 14 #include "ui/base/l10n/l10n_util.h" 15 #include "ui/compositor/compositor.h" 16 #include "ui/compositor/layer.h" 17 #include "ui/compositor/layer_animator.h" 18 #include "ui/compositor/test/draw_waiter_for_test.h" 19 #include "ui/events/event.h" 20 #include "ui/events/gestures/gesture_recognizer.h" 21 #include "ui/events/keycodes/keyboard_codes.h" 22 #include "ui/gfx/canvas.h" 23 #include "ui/gfx/path.h" 24 #include "ui/gfx/transform.h" 25 #include "ui/views/background.h" 26 #include "ui/views/controls/native/native_view_host.h" 27 #include "ui/views/controls/scroll_view.h" 28 #include "ui/views/controls/textfield/textfield.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 using base::ASCIIToUTF16; 39 40 namespace { 41 42 // Returns true if |ancestor| is an ancestor of |layer|. 43 bool LayerIsAncestor(const ui::Layer* ancestor, const ui::Layer* layer) { 44 while (layer && layer != ancestor) 45 layer = layer->parent(); 46 return layer == ancestor; 47 } 48 49 // Convenience functions for walking a View tree. 50 const views::View* FirstView(const views::View* view) { 51 const views::View* v = view; 52 while (v->has_children()) 53 v = v->child_at(0); 54 return v; 55 } 56 57 const views::View* NextView(const views::View* view) { 58 const views::View* v = view; 59 const views::View* parent = v->parent(); 60 if (!parent) 61 return NULL; 62 int next = parent->GetIndexOf(v) + 1; 63 if (next != parent->child_count()) 64 return FirstView(parent->child_at(next)); 65 return parent; 66 } 67 68 // Convenience functions for walking a Layer tree. 69 const ui::Layer* FirstLayer(const ui::Layer* layer) { 70 const ui::Layer* l = layer; 71 while (l->children().size() > 0) 72 l = l->children()[0]; 73 return l; 74 } 75 76 const ui::Layer* NextLayer(const ui::Layer* layer) { 77 const ui::Layer* parent = layer->parent(); 78 if (!parent) 79 return NULL; 80 const std::vector<ui::Layer*> children = parent->children(); 81 size_t index; 82 for (index = 0; index < children.size(); index++) { 83 if (children[index] == layer) 84 break; 85 } 86 size_t next = index + 1; 87 if (next < children.size()) 88 return FirstLayer(children[next]); 89 return parent; 90 } 91 92 // Given the root nodes of a View tree and a Layer tree, makes sure the two 93 // trees are in sync. 94 bool ViewAndLayerTreeAreConsistent(const views::View* view, 95 const ui::Layer* layer) { 96 const views::View* v = FirstView(view); 97 const ui::Layer* l = FirstLayer(layer); 98 while (v && l) { 99 // Find the view with a layer. 100 while (v && !v->layer()) 101 v = NextView(v); 102 EXPECT_TRUE(v); 103 if (!v) 104 return false; 105 106 // Check if the View tree and the Layer tree are in sync. 107 EXPECT_EQ(l, v->layer()); 108 if (v->layer() != l) 109 return false; 110 111 // Check if the visibility states of the View and the Layer are in sync. 112 EXPECT_EQ(l->IsDrawn(), v->IsDrawn()); 113 if (v->IsDrawn() != l->IsDrawn()) { 114 for (const views::View* vv = v; vv; vv = vv->parent()) 115 LOG(ERROR) << "V: " << vv << " " << vv->visible() << " " 116 << vv->IsDrawn() << " " << vv->layer(); 117 for (const ui::Layer* ll = l; ll; ll = ll->parent()) 118 LOG(ERROR) << "L: " << ll << " " << ll->IsDrawn(); 119 return false; 120 } 121 122 // Check if the size of the View and the Layer are in sync. 123 EXPECT_EQ(l->bounds(), v->bounds()); 124 if (v->bounds() != l->bounds()) 125 return false; 126 127 if (v == view || l == layer) 128 return v == view && l == layer; 129 130 v = NextView(v); 131 l = NextLayer(l); 132 } 133 134 return false; 135 } 136 137 // Constructs a View tree with the specified depth. 138 void ConstructTree(views::View* view, int depth) { 139 if (depth == 0) 140 return; 141 int count = base::RandInt(1, 5); 142 for (int i = 0; i < count; i++) { 143 views::View* v = new views::View; 144 view->AddChildView(v); 145 if (base::RandDouble() > 0.5) 146 v->SetPaintToLayer(true); 147 if (base::RandDouble() < 0.2) 148 v->SetVisible(false); 149 150 ConstructTree(v, depth - 1); 151 } 152 } 153 154 void ScrambleTree(views::View* view) { 155 int count = view->child_count(); 156 if (count == 0) 157 return; 158 for (int i = 0; i < count; i++) { 159 ScrambleTree(view->child_at(i)); 160 } 161 162 if (count > 1) { 163 int a = base::RandInt(0, count - 1); 164 int b = base::RandInt(0, count - 1); 165 166 views::View* view_a = view->child_at(a); 167 views::View* view_b = view->child_at(b); 168 view->ReorderChildView(view_a, b); 169 view->ReorderChildView(view_b, a); 170 } 171 172 if (!view->layer() && base::RandDouble() < 0.1) 173 view->SetPaintToLayer(true); 174 175 if (base::RandDouble() < 0.1) 176 view->SetVisible(!view->visible()); 177 } 178 179 // Convenience to make constructing a GestureEvent simpler. 180 class GestureEventForTest : public ui::GestureEvent { 181 public: 182 GestureEventForTest(ui::EventType type, int x, int y, int flags) 183 : GestureEvent(type, x, y, flags, base::TimeDelta(), 184 ui::GestureEventDetails(type, 0.0f, 0.0f), 0) { 185 } 186 187 private: 188 DISALLOW_COPY_AND_ASSIGN(GestureEventForTest); 189 }; 190 191 } // namespace 192 193 namespace views { 194 195 typedef ViewsTestBase ViewTest; 196 197 // A derived class for testing purpose. 198 class TestView : public View { 199 public: 200 TestView() 201 : View(), 202 delete_on_pressed_(false), 203 native_theme_(NULL), 204 can_process_events_within_subtree_(true) {} 205 virtual ~TestView() {} 206 207 // Reset all test state 208 void Reset() { 209 did_change_bounds_ = false; 210 last_mouse_event_type_ = 0; 211 location_.SetPoint(0, 0); 212 received_mouse_enter_ = false; 213 received_mouse_exit_ = false; 214 last_gesture_event_type_ = 0; 215 last_gesture_event_was_handled_ = false; 216 last_clip_.setEmpty(); 217 accelerator_count_map_.clear(); 218 can_process_events_within_subtree_ = true; 219 } 220 221 // Exposed as public for testing. 222 void DoFocus() { 223 views::View::Focus(); 224 } 225 226 void DoBlur() { 227 views::View::Blur(); 228 } 229 230 bool focusable() const { return View::focusable(); } 231 232 void set_can_process_events_within_subtree(bool can_process) { 233 can_process_events_within_subtree_ = can_process; 234 } 235 236 virtual bool CanProcessEventsWithinSubtree() const OVERRIDE { 237 return can_process_events_within_subtree_; 238 } 239 240 virtual void OnBoundsChanged(const gfx::Rect& previous_bounds) OVERRIDE; 241 virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE; 242 virtual bool OnMouseDragged(const ui::MouseEvent& event) OVERRIDE; 243 virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE; 244 virtual void OnMouseEntered(const ui::MouseEvent& event) OVERRIDE; 245 virtual void OnMouseExited(const ui::MouseEvent& event) OVERRIDE; 246 247 // Ignores GestureEvent by default. 248 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE; 249 250 virtual void Paint(gfx::Canvas* canvas, const CullSet& cull_set) OVERRIDE; 251 virtual void SchedulePaintInRect(const gfx::Rect& rect) OVERRIDE; 252 virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE; 253 254 virtual void OnNativeThemeChanged(const ui::NativeTheme* native_theme) 255 OVERRIDE; 256 257 // OnBoundsChanged. 258 bool did_change_bounds_; 259 gfx::Rect new_bounds_; 260 261 // MouseEvent. 262 int last_mouse_event_type_; 263 gfx::Point location_; 264 bool received_mouse_enter_; 265 bool received_mouse_exit_; 266 bool delete_on_pressed_; 267 268 // Painting. 269 std::vector<gfx::Rect> scheduled_paint_rects_; 270 271 // GestureEvent 272 int last_gesture_event_type_; 273 bool last_gesture_event_was_handled_; 274 275 // Painting. 276 SkRect last_clip_; 277 278 // Accelerators. 279 std::map<ui::Accelerator, int> accelerator_count_map_; 280 281 // Native theme. 282 const ui::NativeTheme* native_theme_; 283 284 // Value to return from CanProcessEventsWithinSubtree(). 285 bool can_process_events_within_subtree_; 286 }; 287 288 // A view subclass that consumes all Gesture events for testing purposes. 289 class TestViewConsumeGesture : public TestView { 290 public: 291 TestViewConsumeGesture() : TestView() {} 292 virtual ~TestViewConsumeGesture() {} 293 294 protected: 295 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE { 296 last_gesture_event_type_ = event->type(); 297 location_.SetPoint(event->x(), event->y()); 298 event->StopPropagation(); 299 } 300 301 private: 302 DISALLOW_COPY_AND_ASSIGN(TestViewConsumeGesture); 303 }; 304 305 // A view subclass that ignores all Gesture events. 306 class TestViewIgnoreGesture: public TestView { 307 public: 308 TestViewIgnoreGesture() : TestView() {} 309 virtual ~TestViewIgnoreGesture() {} 310 311 private: 312 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE { 313 } 314 315 DISALLOW_COPY_AND_ASSIGN(TestViewIgnoreGesture); 316 }; 317 318 // A view subclass that ignores all scroll-gesture events, but consume all other 319 // gesture events. 320 class TestViewIgnoreScrollGestures : public TestViewConsumeGesture { 321 public: 322 TestViewIgnoreScrollGestures() {} 323 virtual ~TestViewIgnoreScrollGestures() {} 324 325 private: 326 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE { 327 if (event->IsScrollGestureEvent()) 328 return; 329 TestViewConsumeGesture::OnGestureEvent(event); 330 } 331 332 DISALLOW_COPY_AND_ASSIGN(TestViewIgnoreScrollGestures); 333 }; 334 335 //////////////////////////////////////////////////////////////////////////////// 336 // OnBoundsChanged 337 //////////////////////////////////////////////////////////////////////////////// 338 339 void TestView::OnBoundsChanged(const gfx::Rect& previous_bounds) { 340 did_change_bounds_ = true; 341 new_bounds_ = bounds(); 342 } 343 344 TEST_F(ViewTest, OnBoundsChanged) { 345 TestView v; 346 347 gfx::Rect prev_rect(0, 0, 200, 200); 348 gfx::Rect new_rect(100, 100, 250, 250); 349 350 v.SetBoundsRect(prev_rect); 351 v.Reset(); 352 v.SetBoundsRect(new_rect); 353 354 EXPECT_TRUE(v.did_change_bounds_); 355 EXPECT_EQ(v.new_bounds_, new_rect); 356 EXPECT_EQ(v.bounds(), new_rect); 357 } 358 359 //////////////////////////////////////////////////////////////////////////////// 360 // MouseEvent 361 //////////////////////////////////////////////////////////////////////////////// 362 363 bool TestView::OnMousePressed(const ui::MouseEvent& event) { 364 last_mouse_event_type_ = event.type(); 365 location_.SetPoint(event.x(), event.y()); 366 if (delete_on_pressed_) 367 delete this; 368 return true; 369 } 370 371 bool TestView::OnMouseDragged(const ui::MouseEvent& event) { 372 last_mouse_event_type_ = event.type(); 373 location_.SetPoint(event.x(), event.y()); 374 return true; 375 } 376 377 void TestView::OnMouseReleased(const ui::MouseEvent& event) { 378 last_mouse_event_type_ = event.type(); 379 location_.SetPoint(event.x(), event.y()); 380 } 381 382 void TestView::OnMouseEntered(const ui::MouseEvent& event) { 383 received_mouse_enter_ = true; 384 } 385 386 void TestView::OnMouseExited(const ui::MouseEvent& event) { 387 received_mouse_exit_ = true; 388 } 389 390 TEST_F(ViewTest, MouseEvent) { 391 TestView* v1 = new TestView(); 392 v1->SetBoundsRect(gfx::Rect(0, 0, 300, 300)); 393 394 TestView* v2 = new TestView(); 395 v2->SetBoundsRect(gfx::Rect(100, 100, 100, 100)); 396 397 scoped_ptr<Widget> widget(new Widget); 398 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 399 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 400 params.bounds = gfx::Rect(50, 50, 650, 650); 401 widget->Init(params); 402 internal::RootView* root = 403 static_cast<internal::RootView*>(widget->GetRootView()); 404 405 root->AddChildView(v1); 406 v1->AddChildView(v2); 407 408 v1->Reset(); 409 v2->Reset(); 410 411 gfx::Point p1(110, 120); 412 ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, p1, p1, 413 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); 414 root->OnMousePressed(pressed); 415 EXPECT_EQ(v2->last_mouse_event_type_, ui::ET_MOUSE_PRESSED); 416 EXPECT_EQ(v2->location_.x(), 10); 417 EXPECT_EQ(v2->location_.y(), 20); 418 // Make sure v1 did not receive the event 419 EXPECT_EQ(v1->last_mouse_event_type_, 0); 420 421 // Drag event out of bounds. Should still go to v2 422 v1->Reset(); 423 v2->Reset(); 424 gfx::Point p2(50, 40); 425 ui::MouseEvent dragged(ui::ET_MOUSE_DRAGGED, p2, p2, 426 ui::EF_LEFT_MOUSE_BUTTON, 0); 427 root->OnMouseDragged(dragged); 428 EXPECT_EQ(v2->last_mouse_event_type_, ui::ET_MOUSE_DRAGGED); 429 EXPECT_EQ(v2->location_.x(), -50); 430 EXPECT_EQ(v2->location_.y(), -60); 431 // Make sure v1 did not receive the event 432 EXPECT_EQ(v1->last_mouse_event_type_, 0); 433 434 // Releasted event out of bounds. Should still go to v2 435 v1->Reset(); 436 v2->Reset(); 437 ui::MouseEvent released(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(), 0, 438 0); 439 root->OnMouseDragged(released); 440 EXPECT_EQ(v2->last_mouse_event_type_, ui::ET_MOUSE_RELEASED); 441 EXPECT_EQ(v2->location_.x(), -100); 442 EXPECT_EQ(v2->location_.y(), -100); 443 // Make sure v1 did not receive the event 444 EXPECT_EQ(v1->last_mouse_event_type_, 0); 445 446 widget->CloseNow(); 447 } 448 449 // Confirm that a view can be deleted as part of processing a mouse press. 450 TEST_F(ViewTest, DeleteOnPressed) { 451 TestView* v1 = new TestView(); 452 v1->SetBoundsRect(gfx::Rect(0, 0, 300, 300)); 453 454 TestView* v2 = new TestView(); 455 v2->SetBoundsRect(gfx::Rect(100, 100, 100, 100)); 456 457 v1->Reset(); 458 v2->Reset(); 459 460 scoped_ptr<Widget> widget(new Widget); 461 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 462 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 463 params.bounds = gfx::Rect(50, 50, 650, 650); 464 widget->Init(params); 465 View* root = widget->GetRootView(); 466 467 root->AddChildView(v1); 468 v1->AddChildView(v2); 469 470 v2->delete_on_pressed_ = true; 471 gfx::Point point(110, 120); 472 ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, point, point, 473 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); 474 root->OnMousePressed(pressed); 475 EXPECT_EQ(0, v1->child_count()); 476 477 widget->CloseNow(); 478 } 479 480 //////////////////////////////////////////////////////////////////////////////// 481 // GestureEvent 482 //////////////////////////////////////////////////////////////////////////////// 483 484 void TestView::OnGestureEvent(ui::GestureEvent* event) { 485 } 486 487 TEST_F(ViewTest, GestureEvent) { 488 // Views hierarchy for non delivery of GestureEvent. 489 TestView* v1 = new TestViewConsumeGesture(); 490 v1->SetBoundsRect(gfx::Rect(0, 0, 300, 300)); 491 492 TestView* v2 = new TestViewConsumeGesture(); 493 v2->SetBoundsRect(gfx::Rect(100, 100, 100, 100)); 494 495 TestView* v3 = new TestViewIgnoreGesture(); 496 v3->SetBoundsRect(gfx::Rect(0, 0, 100, 100)); 497 498 scoped_ptr<Widget> widget(new Widget()); 499 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 500 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 501 params.bounds = gfx::Rect(50, 50, 650, 650); 502 widget->Init(params); 503 internal::RootView* root = 504 static_cast<internal::RootView*>(widget->GetRootView()); 505 ui::EventDispatchDetails details; 506 507 root->AddChildView(v1); 508 v1->AddChildView(v2); 509 v2->AddChildView(v3); 510 511 // |v3| completely obscures |v2|, but all the gesture events on |v3| should 512 // reach |v2| because |v3| doesn't process any gesture events. However, since 513 // |v2| does process gesture events, gesture events on |v3| or |v2| should not 514 // reach |v1|. 515 516 v1->Reset(); 517 v2->Reset(); 518 v3->Reset(); 519 520 // Gesture on |v3| 521 GestureEventForTest g1(ui::ET_GESTURE_TAP, 110, 110, 0); 522 details = root->OnEventFromSource(&g1); 523 EXPECT_FALSE(details.dispatcher_destroyed); 524 EXPECT_FALSE(details.target_destroyed); 525 526 EXPECT_EQ(ui::ET_GESTURE_TAP, v2->last_gesture_event_type_); 527 EXPECT_EQ(gfx::Point(10, 10), v2->location_); 528 EXPECT_EQ(ui::ET_UNKNOWN, v1->last_gesture_event_type_); 529 530 // Simulate an up so that RootView is no longer targetting |v3|. 531 GestureEventForTest g1_up(ui::ET_GESTURE_END, 110, 110, 0); 532 details = root->OnEventFromSource(&g1_up); 533 EXPECT_FALSE(details.dispatcher_destroyed); 534 EXPECT_FALSE(details.target_destroyed); 535 536 v1->Reset(); 537 v2->Reset(); 538 v3->Reset(); 539 540 // Gesture on |v1| 541 GestureEventForTest g2(ui::ET_GESTURE_TAP, 80, 80, 0); 542 details = root->OnEventFromSource(&g2); 543 EXPECT_FALSE(details.dispatcher_destroyed); 544 EXPECT_FALSE(details.target_destroyed); 545 546 EXPECT_EQ(ui::ET_GESTURE_TAP, v1->last_gesture_event_type_); 547 EXPECT_EQ(gfx::Point(80, 80), v1->location_); 548 EXPECT_EQ(ui::ET_UNKNOWN, v2->last_gesture_event_type_); 549 550 // Send event |g1| again. Even though the coordinates target |v3| it should go 551 // to |v1| as that is the view the touch was initially down on. 552 v1->last_gesture_event_type_ = ui::ET_UNKNOWN; 553 v3->last_gesture_event_type_ = ui::ET_UNKNOWN; 554 details = root->OnEventFromSource(&g1); 555 EXPECT_FALSE(details.dispatcher_destroyed); 556 EXPECT_FALSE(details.target_destroyed); 557 558 EXPECT_EQ(ui::ET_GESTURE_TAP, v1->last_gesture_event_type_); 559 EXPECT_EQ(ui::ET_UNKNOWN, v3->last_gesture_event_type_); 560 EXPECT_EQ("110,110", v1->location_.ToString()); 561 562 widget->CloseNow(); 563 } 564 565 TEST_F(ViewTest, ScrollGestureEvent) { 566 // Views hierarchy for non delivery of GestureEvent. 567 TestView* v1 = new TestViewConsumeGesture(); 568 v1->SetBoundsRect(gfx::Rect(0, 0, 300, 300)); 569 570 TestView* v2 = new TestViewIgnoreScrollGestures(); 571 v2->SetBoundsRect(gfx::Rect(100, 100, 100, 100)); 572 573 TestView* v3 = new TestViewIgnoreGesture(); 574 v3->SetBoundsRect(gfx::Rect(0, 0, 100, 100)); 575 576 scoped_ptr<Widget> widget(new Widget()); 577 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 578 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 579 params.bounds = gfx::Rect(50, 50, 650, 650); 580 widget->Init(params); 581 internal::RootView* root = 582 static_cast<internal::RootView*>(widget->GetRootView()); 583 ui::EventDispatchDetails details; 584 585 root->AddChildView(v1); 586 v1->AddChildView(v2); 587 v2->AddChildView(v3); 588 589 // |v3| completely obscures |v2|, but all the gesture events on |v3| should 590 // reach |v2| because |v3| doesn't process any gesture events. However, since 591 // |v2| does process gesture events, gesture events on |v3| or |v2| should not 592 // reach |v1|. 593 594 v1->Reset(); 595 v2->Reset(); 596 v3->Reset(); 597 598 // Gesture on |v3| 599 GestureEventForTest g1(ui::ET_GESTURE_TAP, 110, 110, 0); 600 details = root->OnEventFromSource(&g1); 601 EXPECT_FALSE(details.dispatcher_destroyed); 602 EXPECT_FALSE(details.target_destroyed); 603 604 EXPECT_EQ(ui::ET_GESTURE_TAP, v2->last_gesture_event_type_); 605 EXPECT_EQ(gfx::Point(10, 10), v2->location_); 606 EXPECT_EQ(ui::ET_UNKNOWN, v1->last_gesture_event_type_); 607 608 v2->Reset(); 609 610 // Send scroll gestures on |v3|. The gesture should reach |v2|, however, 611 // since it does not process scroll-gesture events, these events should reach 612 // |v1|. 613 GestureEventForTest gscroll_begin(ui::ET_GESTURE_SCROLL_BEGIN, 115, 115, 0); 614 details = root->OnEventFromSource(&gscroll_begin); 615 EXPECT_FALSE(details.dispatcher_destroyed); 616 EXPECT_FALSE(details.target_destroyed); 617 618 EXPECT_EQ(ui::ET_UNKNOWN, v2->last_gesture_event_type_); 619 EXPECT_EQ(ui::ET_GESTURE_SCROLL_BEGIN, v1->last_gesture_event_type_); 620 v1->Reset(); 621 622 // Send a second tap on |v1|. The event should reach |v2| since it is the 623 // default gesture handler, and not |v1| (even though it is the view under the 624 // point, and is the scroll event handler). 625 GestureEventForTest second_tap(ui::ET_GESTURE_TAP, 70, 70, 0); 626 details = root->OnEventFromSource(&second_tap); 627 EXPECT_FALSE(details.dispatcher_destroyed); 628 EXPECT_FALSE(details.target_destroyed); 629 630 EXPECT_EQ(ui::ET_GESTURE_TAP, v2->last_gesture_event_type_); 631 EXPECT_EQ(ui::ET_UNKNOWN, v1->last_gesture_event_type_); 632 v2->Reset(); 633 634 GestureEventForTest gscroll_end(ui::ET_GESTURE_SCROLL_END, 50, 50, 0); 635 details = root->OnEventFromSource(&gscroll_end); 636 EXPECT_FALSE(details.dispatcher_destroyed); 637 EXPECT_FALSE(details.target_destroyed); 638 639 EXPECT_EQ(ui::ET_GESTURE_SCROLL_END, v1->last_gesture_event_type_); 640 v1->Reset(); 641 642 // Simulate an up so that RootView is no longer targetting |v3|. 643 GestureEventForTest g1_up(ui::ET_GESTURE_END, 110, 110, 0); 644 details = root->OnEventFromSource(&g1_up); 645 EXPECT_FALSE(details.dispatcher_destroyed); 646 EXPECT_FALSE(details.target_destroyed); 647 648 EXPECT_EQ(ui::ET_GESTURE_END, v2->last_gesture_event_type_); 649 650 v1->Reset(); 651 v2->Reset(); 652 v3->Reset(); 653 654 // Gesture on |v1| 655 GestureEventForTest g2(ui::ET_GESTURE_TAP, 80, 80, 0); 656 details = root->OnEventFromSource(&g2); 657 EXPECT_FALSE(details.dispatcher_destroyed); 658 EXPECT_FALSE(details.target_destroyed); 659 660 EXPECT_EQ(ui::ET_GESTURE_TAP, v1->last_gesture_event_type_); 661 EXPECT_EQ(gfx::Point(80, 80), v1->location_); 662 EXPECT_EQ(ui::ET_UNKNOWN, v2->last_gesture_event_type_); 663 664 // Send event |g1| again. Even though the coordinates target |v3| it should go 665 // to |v1| as that is the view the touch was initially down on. 666 v1->last_gesture_event_type_ = ui::ET_UNKNOWN; 667 v3->last_gesture_event_type_ = ui::ET_UNKNOWN; 668 details = root->OnEventFromSource(&g1); 669 EXPECT_FALSE(details.dispatcher_destroyed); 670 EXPECT_FALSE(details.target_destroyed); 671 672 EXPECT_EQ(ui::ET_GESTURE_TAP, v1->last_gesture_event_type_); 673 EXPECT_EQ(ui::ET_UNKNOWN, v3->last_gesture_event_type_); 674 EXPECT_EQ("110,110", v1->location_.ToString()); 675 676 widget->CloseNow(); 677 } 678 679 //////////////////////////////////////////////////////////////////////////////// 680 // Painting 681 //////////////////////////////////////////////////////////////////////////////// 682 683 void TestView::Paint(gfx::Canvas* canvas, const CullSet& cull_set) { 684 canvas->sk_canvas()->getClipBounds(&last_clip_); 685 } 686 687 void TestView::SchedulePaintInRect(const gfx::Rect& rect) { 688 scheduled_paint_rects_.push_back(rect); 689 View::SchedulePaintInRect(rect); 690 } 691 692 void CheckRect(const SkRect& check_rect, const SkRect& target_rect) { 693 EXPECT_EQ(target_rect.fLeft, check_rect.fLeft); 694 EXPECT_EQ(target_rect.fRight, check_rect.fRight); 695 EXPECT_EQ(target_rect.fTop, check_rect.fTop); 696 EXPECT_EQ(target_rect.fBottom, check_rect.fBottom); 697 } 698 699 TEST_F(ViewTest, RemoveNotification) { 700 ViewStorage* vs = ViewStorage::GetInstance(); 701 Widget* widget = new Widget; 702 widget->Init(CreateParams(Widget::InitParams::TYPE_POPUP)); 703 View* root_view = widget->GetRootView(); 704 705 View* v1 = new View; 706 int s1 = vs->CreateStorageID(); 707 vs->StoreView(s1, v1); 708 root_view->AddChildView(v1); 709 View* v11 = new View; 710 int s11 = vs->CreateStorageID(); 711 vs->StoreView(s11, v11); 712 v1->AddChildView(v11); 713 View* v111 = new View; 714 int s111 = vs->CreateStorageID(); 715 vs->StoreView(s111, v111); 716 v11->AddChildView(v111); 717 View* v112 = new View; 718 int s112 = vs->CreateStorageID(); 719 vs->StoreView(s112, v112); 720 v11->AddChildView(v112); 721 View* v113 = new View; 722 int s113 = vs->CreateStorageID(); 723 vs->StoreView(s113, v113); 724 v11->AddChildView(v113); 725 View* v1131 = new View; 726 int s1131 = vs->CreateStorageID(); 727 vs->StoreView(s1131, v1131); 728 v113->AddChildView(v1131); 729 View* v12 = new View; 730 int s12 = vs->CreateStorageID(); 731 vs->StoreView(s12, v12); 732 v1->AddChildView(v12); 733 734 View* v2 = new View; 735 int s2 = vs->CreateStorageID(); 736 vs->StoreView(s2, v2); 737 root_view->AddChildView(v2); 738 View* v21 = new View; 739 int s21 = vs->CreateStorageID(); 740 vs->StoreView(s21, v21); 741 v2->AddChildView(v21); 742 View* v211 = new View; 743 int s211 = vs->CreateStorageID(); 744 vs->StoreView(s211, v211); 745 v21->AddChildView(v211); 746 747 size_t stored_views = vs->view_count(); 748 749 // Try removing a leaf view. 750 v21->RemoveChildView(v211); 751 EXPECT_EQ(stored_views - 1, vs->view_count()); 752 EXPECT_EQ(NULL, vs->RetrieveView(s211)); 753 delete v211; // We won't use this one anymore. 754 755 // Now try removing a view with a hierarchy of depth 1. 756 v11->RemoveChildView(v113); 757 EXPECT_EQ(stored_views - 3, vs->view_count()); 758 EXPECT_EQ(NULL, vs->RetrieveView(s113)); 759 EXPECT_EQ(NULL, vs->RetrieveView(s1131)); 760 delete v113; // We won't use this one anymore. 761 762 // Now remove even more. 763 root_view->RemoveChildView(v1); 764 EXPECT_EQ(NULL, vs->RetrieveView(s1)); 765 EXPECT_EQ(NULL, vs->RetrieveView(s11)); 766 EXPECT_EQ(NULL, vs->RetrieveView(s12)); 767 EXPECT_EQ(NULL, vs->RetrieveView(s111)); 768 EXPECT_EQ(NULL, vs->RetrieveView(s112)); 769 770 // Put v1 back for more tests. 771 root_view->AddChildView(v1); 772 vs->StoreView(s1, v1); 773 774 // Synchronously closing the window deletes the view hierarchy, which should 775 // remove all its views from ViewStorage. 776 widget->CloseNow(); 777 EXPECT_EQ(stored_views - 10, vs->view_count()); 778 EXPECT_EQ(NULL, vs->RetrieveView(s1)); 779 EXPECT_EQ(NULL, vs->RetrieveView(s12)); 780 EXPECT_EQ(NULL, vs->RetrieveView(s11)); 781 EXPECT_EQ(NULL, vs->RetrieveView(s12)); 782 EXPECT_EQ(NULL, vs->RetrieveView(s21)); 783 EXPECT_EQ(NULL, vs->RetrieveView(s111)); 784 EXPECT_EQ(NULL, vs->RetrieveView(s112)); 785 } 786 787 namespace { 788 class HitTestView : public View { 789 public: 790 explicit HitTestView(bool has_hittest_mask) 791 : has_hittest_mask_(has_hittest_mask) { 792 } 793 virtual ~HitTestView() {} 794 795 protected: 796 // Overridden from View: 797 virtual bool HasHitTestMask() const OVERRIDE { 798 return has_hittest_mask_; 799 } 800 virtual void GetHitTestMask(HitTestSource source, 801 gfx::Path* mask) const OVERRIDE { 802 DCHECK(has_hittest_mask_); 803 DCHECK(mask); 804 805 SkScalar w = SkIntToScalar(width()); 806 SkScalar h = SkIntToScalar(height()); 807 808 // Create a triangular mask within the bounds of this View. 809 mask->moveTo(w / 2, 0); 810 mask->lineTo(w, h); 811 mask->lineTo(0, h); 812 mask->close(); 813 } 814 815 private: 816 bool has_hittest_mask_; 817 818 DISALLOW_COPY_AND_ASSIGN(HitTestView); 819 }; 820 821 gfx::Point ConvertPointToView(View* view, const gfx::Point& p) { 822 gfx::Point tmp(p); 823 View::ConvertPointToTarget(view->GetWidget()->GetRootView(), view, &tmp); 824 return tmp; 825 } 826 827 gfx::Rect ConvertRectToView(View* view, const gfx::Rect& r) { 828 gfx::Rect tmp(r); 829 tmp.set_origin(ConvertPointToView(view, r.origin())); 830 return tmp; 831 } 832 833 void RotateCounterclockwise(gfx::Transform* transform) { 834 transform->matrix().set3x3(0, -1, 0, 835 1, 0, 0, 836 0, 0, 1); 837 } 838 839 void RotateClockwise(gfx::Transform* transform) { 840 transform->matrix().set3x3( 0, 1, 0, 841 -1, 0, 0, 842 0, 0, 1); 843 } 844 845 } // namespace 846 847 TEST_F(ViewTest, HitTestMasks) { 848 Widget* widget = new Widget; 849 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 850 widget->Init(params); 851 View* root_view = widget->GetRootView(); 852 root_view->SetBoundsRect(gfx::Rect(0, 0, 500, 500)); 853 854 gfx::Rect v1_bounds = gfx::Rect(0, 0, 100, 100); 855 HitTestView* v1 = new HitTestView(false); 856 v1->SetBoundsRect(v1_bounds); 857 root_view->AddChildView(v1); 858 859 gfx::Rect v2_bounds = gfx::Rect(105, 0, 100, 100); 860 HitTestView* v2 = new HitTestView(true); 861 v2->SetBoundsRect(v2_bounds); 862 root_view->AddChildView(v2); 863 864 gfx::Point v1_centerpoint = v1_bounds.CenterPoint(); 865 gfx::Point v2_centerpoint = v2_bounds.CenterPoint(); 866 gfx::Point v1_origin = v1_bounds.origin(); 867 gfx::Point v2_origin = v2_bounds.origin(); 868 869 gfx::Rect r1(10, 10, 110, 15); 870 gfx::Rect r2(106, 1, 98, 98); 871 gfx::Rect r3(0, 0, 300, 300); 872 gfx::Rect r4(115, 342, 200, 10); 873 874 // Test HitTestPoint 875 EXPECT_TRUE(v1->HitTestPoint(ConvertPointToView(v1, v1_centerpoint))); 876 EXPECT_TRUE(v2->HitTestPoint(ConvertPointToView(v2, v2_centerpoint))); 877 878 EXPECT_TRUE(v1->HitTestPoint(ConvertPointToView(v1, v1_origin))); 879 EXPECT_FALSE(v2->HitTestPoint(ConvertPointToView(v2, v2_origin))); 880 881 // Test HitTestRect 882 EXPECT_TRUE(v1->HitTestRect(ConvertRectToView(v1, r1))); 883 EXPECT_FALSE(v2->HitTestRect(ConvertRectToView(v2, r1))); 884 885 EXPECT_FALSE(v1->HitTestRect(ConvertRectToView(v1, r2))); 886 EXPECT_TRUE(v2->HitTestRect(ConvertRectToView(v2, r2))); 887 888 EXPECT_TRUE(v1->HitTestRect(ConvertRectToView(v1, r3))); 889 EXPECT_TRUE(v2->HitTestRect(ConvertRectToView(v2, r3))); 890 891 EXPECT_FALSE(v1->HitTestRect(ConvertRectToView(v1, r4))); 892 EXPECT_FALSE(v2->HitTestRect(ConvertRectToView(v2, r4))); 893 894 // Test GetEventHandlerForPoint 895 EXPECT_EQ(v1, root_view->GetEventHandlerForPoint(v1_centerpoint)); 896 EXPECT_EQ(v2, root_view->GetEventHandlerForPoint(v2_centerpoint)); 897 898 EXPECT_EQ(v1, root_view->GetEventHandlerForPoint(v1_origin)); 899 EXPECT_EQ(root_view, root_view->GetEventHandlerForPoint(v2_origin)); 900 901 // Test GetTooltipHandlerForPoint 902 EXPECT_EQ(v1, root_view->GetTooltipHandlerForPoint(v1_centerpoint)); 903 EXPECT_EQ(v2, root_view->GetTooltipHandlerForPoint(v2_centerpoint)); 904 905 EXPECT_EQ(v1, root_view->GetTooltipHandlerForPoint(v1_origin)); 906 EXPECT_EQ(root_view, root_view->GetTooltipHandlerForPoint(v2_origin)); 907 908 EXPECT_FALSE(v1->GetTooltipHandlerForPoint(v2_origin)); 909 910 widget->CloseNow(); 911 } 912 913 // Tests the correctness of the rect-based targeting algorithm implemented in 914 // View::GetEventHandlerForRect(). See http://goo.gl/3Jp2BD for a description 915 // of rect-based targeting. 916 TEST_F(ViewTest, GetEventHandlerForRect) { 917 Widget* widget = new Widget; 918 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 919 widget->Init(params); 920 View* root_view = widget->GetRootView(); 921 root_view->SetBoundsRect(gfx::Rect(0, 0, 500, 500)); 922 923 // Have this hierarchy of views (the coordinates here are all in 924 // the root view's coordinate space): 925 // v1 (0, 0, 100, 100) 926 // v2 (150, 0, 250, 100) 927 // v3 (0, 200, 150, 100) 928 // v31 (10, 210, 80, 80) 929 // v32 (110, 210, 30, 80) 930 // v4 (300, 200, 100, 100) 931 // v41 (310, 210, 80, 80) 932 // v411 (370, 275, 10, 5) 933 // v5 (450, 197, 30, 36) 934 // v51 (450, 200, 30, 30) 935 936 // The coordinates used for SetBounds are in parent coordinates. 937 938 TestView* v1 = new TestView; 939 v1->SetBounds(0, 0, 100, 100); 940 root_view->AddChildView(v1); 941 942 TestView* v2 = new TestView; 943 v2->SetBounds(150, 0, 250, 100); 944 root_view->AddChildView(v2); 945 946 TestView* v3 = new TestView; 947 v3->SetBounds(0, 200, 150, 100); 948 root_view->AddChildView(v3); 949 950 TestView* v4 = new TestView; 951 v4->SetBounds(300, 200, 100, 100); 952 root_view->AddChildView(v4); 953 954 TestView* v31 = new TestView; 955 v31->SetBounds(10, 10, 80, 80); 956 v3->AddChildView(v31); 957 958 TestView* v32 = new TestView; 959 v32->SetBounds(110, 10, 30, 80); 960 v3->AddChildView(v32); 961 962 TestView* v41 = new TestView; 963 v41->SetBounds(10, 10, 80, 80); 964 v4->AddChildView(v41); 965 966 TestView* v411 = new TestView; 967 v411->SetBounds(60, 65, 10, 5); 968 v41->AddChildView(v411); 969 970 TestView* v5 = new TestView; 971 v5->SetBounds(450, 197, 30, 36); 972 root_view->AddChildView(v5); 973 974 TestView* v51 = new TestView; 975 v51->SetBounds(0, 3, 30, 30); 976 v5->AddChildView(v51); 977 978 // |touch_rect| does not intersect any descendant view of |root_view|. 979 gfx::Rect touch_rect(105, 105, 30, 45); 980 View* result_view = root_view->GetEventHandlerForRect(touch_rect); 981 EXPECT_EQ(root_view, result_view); 982 result_view = NULL; 983 984 // Covers |v1| by at least 60%. 985 touch_rect.SetRect(15, 15, 100, 100); 986 result_view = root_view->GetEventHandlerForRect(touch_rect); 987 EXPECT_EQ(v1, result_view); 988 result_view = NULL; 989 990 // Intersects |v1| but does not cover it by at least 60%. The center 991 // of |touch_rect| is within |v1|. 992 touch_rect.SetRect(50, 50, 5, 10); 993 result_view = root_view->GetEventHandlerForRect(touch_rect); 994 EXPECT_EQ(v1, result_view); 995 result_view = NULL; 996 997 // Intersects |v1| but does not cover it by at least 60%. The center 998 // of |touch_rect| is not within |v1|. 999 touch_rect.SetRect(95, 96, 21, 22); 1000 result_view = root_view->GetEventHandlerForRect(touch_rect); 1001 EXPECT_EQ(root_view, result_view); 1002 result_view = NULL; 1003 1004 // Intersects |v1| and |v2|, but only covers |v2| by at least 60%. 1005 touch_rect.SetRect(95, 10, 300, 120); 1006 result_view = root_view->GetEventHandlerForRect(touch_rect); 1007 EXPECT_EQ(v2, result_view); 1008 result_view = NULL; 1009 1010 // Covers both |v1| and |v2| by at least 60%, but the center point 1011 // of |touch_rect| is closer to the center point of |v2|. 1012 touch_rect.SetRect(20, 20, 400, 100); 1013 result_view = root_view->GetEventHandlerForRect(touch_rect); 1014 EXPECT_EQ(v2, result_view); 1015 result_view = NULL; 1016 1017 // Covers both |v1| and |v2| by at least 60%, but the center point 1018 // of |touch_rect| is closer to the center point of |v1|. 1019 touch_rect.SetRect(-700, -15, 1050, 110); 1020 result_view = root_view->GetEventHandlerForRect(touch_rect); 1021 EXPECT_EQ(v1, result_view); 1022 result_view = NULL; 1023 1024 // A mouse click within |v1| will target |v1|. 1025 touch_rect.SetRect(15, 15, 1, 1); 1026 result_view = root_view->GetEventHandlerForRect(touch_rect); 1027 EXPECT_EQ(v1, result_view); 1028 result_view = NULL; 1029 1030 // Intersects |v3| and |v31| by at least 60% and the center point 1031 // of |touch_rect| is closer to the center point of |v31|. 1032 touch_rect.SetRect(0, 200, 110, 100); 1033 result_view = root_view->GetEventHandlerForRect(touch_rect); 1034 EXPECT_EQ(v31, result_view); 1035 result_view = NULL; 1036 1037 // Intersects |v3| and |v31|, but neither by at least 60%. The 1038 // center point of |touch_rect| lies within |v31|. 1039 touch_rect.SetRect(80, 280, 15, 15); 1040 result_view = root_view->GetEventHandlerForRect(touch_rect); 1041 EXPECT_EQ(v31, result_view); 1042 result_view = NULL; 1043 1044 // Covers |v3|, |v31|, and |v32| all by at least 60%, and the 1045 // center point of |touch_rect| is closest to the center point 1046 // of |v32|. 1047 touch_rect.SetRect(0, 200, 200, 100); 1048 result_view = root_view->GetEventHandlerForRect(touch_rect); 1049 EXPECT_EQ(v32, result_view); 1050 result_view = NULL; 1051 1052 // Intersects all of |v3|, |v31|, and |v32|, but only covers 1053 // |v31| and |v32| by at least 60%. The center point of 1054 // |touch_rect| is closest to the center point of |v32|. 1055 touch_rect.SetRect(30, 225, 180, 115); 1056 result_view = root_view->GetEventHandlerForRect(touch_rect); 1057 EXPECT_EQ(v32, result_view); 1058 result_view = NULL; 1059 1060 // A mouse click at the corner of |v3| will target |v3|. 1061 touch_rect.SetRect(0, 200, 1, 1); 1062 result_view = root_view->GetEventHandlerForRect(touch_rect); 1063 EXPECT_EQ(v3, result_view); 1064 result_view = NULL; 1065 1066 // A mouse click within |v32| will target |v32|. 1067 touch_rect.SetRect(112, 211, 1, 1); 1068 result_view = root_view->GetEventHandlerForRect(touch_rect); 1069 EXPECT_EQ(v32, result_view); 1070 result_view = NULL; 1071 1072 // Covers all of |v4|, |v41|, and |v411| by at least 60%. 1073 // The center point of |touch_rect| is equally close to 1074 // the center points of |v4| and |v41|. 1075 touch_rect.SetRect(310, 210, 80, 80); 1076 result_view = root_view->GetEventHandlerForRect(touch_rect); 1077 EXPECT_EQ(v41, result_view); 1078 result_view = NULL; 1079 1080 // Intersects all of |v4|, |v41|, and |v411| but only covers 1081 // |v411| by at least 60%. 1082 touch_rect.SetRect(370, 275, 7, 5); 1083 result_view = root_view->GetEventHandlerForRect(touch_rect); 1084 EXPECT_EQ(v411, result_view); 1085 result_view = NULL; 1086 1087 // Intersects |v4| and |v41| but covers neither by at least 60%. 1088 // The center point of |touch_rect| is equally close to the center 1089 // points of |v4| and |v41|. 1090 touch_rect.SetRect(345, 245, 7, 7); 1091 result_view = root_view->GetEventHandlerForRect(touch_rect); 1092 EXPECT_EQ(v41, result_view); 1093 result_view = NULL; 1094 1095 // Intersects all of |v4|, |v41|, and |v411| and covers none of 1096 // them by at least 60%. The center point of |touch_rect| lies 1097 // within |v411|. 1098 touch_rect.SetRect(368, 272, 4, 6); 1099 result_view = root_view->GetEventHandlerForRect(touch_rect); 1100 EXPECT_EQ(v411, result_view); 1101 result_view = NULL; 1102 1103 // Intersects all of |v4|, |v41|, and |v411| and covers none of 1104 // them by at least 60%. The center point of |touch_rect| lies 1105 // within |v41|. 1106 touch_rect.SetRect(365, 270, 7, 7); 1107 result_view = root_view->GetEventHandlerForRect(touch_rect); 1108 EXPECT_EQ(v41, result_view); 1109 result_view = NULL; 1110 1111 // Intersects all of |v4|, |v41|, and |v411| and covers none of 1112 // them by at least 60%. The center point of |touch_rect| lies 1113 // within |v4|. 1114 touch_rect.SetRect(205, 275, 200, 2); 1115 result_view = root_view->GetEventHandlerForRect(touch_rect); 1116 EXPECT_EQ(v4, result_view); 1117 result_view = NULL; 1118 1119 // Intersects all of |v4|, |v41|, and |v411| but only covers 1120 // |v41| by at least 60%. 1121 touch_rect.SetRect(310, 210, 61, 66); 1122 result_view = root_view->GetEventHandlerForRect(touch_rect); 1123 EXPECT_EQ(v41, result_view); 1124 result_view = NULL; 1125 1126 // A mouse click within |v411| will target |v411|. 1127 touch_rect.SetRect(372, 275, 1, 1); 1128 result_view = root_view->GetEventHandlerForRect(touch_rect); 1129 EXPECT_EQ(v411, result_view); 1130 result_view = NULL; 1131 1132 // A mouse click within |v41| will target |v41|. 1133 touch_rect.SetRect(350, 215, 1, 1); 1134 result_view = root_view->GetEventHandlerForRect(touch_rect); 1135 EXPECT_EQ(v41, result_view); 1136 result_view = NULL; 1137 1138 // Covers |v3|, |v4|, and all of their descendants by at 1139 // least 60%. The center point of |touch_rect| is closest 1140 // to the center point of |v32|. 1141 touch_rect.SetRect(0, 200, 400, 100); 1142 result_view = root_view->GetEventHandlerForRect(touch_rect); 1143 EXPECT_EQ(v32, result_view); 1144 result_view = NULL; 1145 1146 // Intersects all of |v2|, |v3|, |v32|, |v4|, |v41|, and |v411|. 1147 // Covers |v2|, |v32|, |v4|, |v41|, and |v411| by at least 60%. 1148 // The center point of |touch_rect| is closest to the center 1149 // point of |root_view|. 1150 touch_rect.SetRect(110, 15, 375, 450); 1151 result_view = root_view->GetEventHandlerForRect(touch_rect); 1152 EXPECT_EQ(root_view, result_view); 1153 result_view = NULL; 1154 1155 // Covers all views (except |v5| and |v51|) by at least 60%. The 1156 // center point of |touch_rect| is equally close to the center 1157 // points of |v2| and |v32|. One is not a descendant of the other, 1158 // so in this case the view selected is arbitrary (i.e., 1159 // it depends only on the ordering of nodes in the views 1160 // hierarchy). 1161 touch_rect.SetRect(0, 0, 400, 300); 1162 result_view = root_view->GetEventHandlerForRect(touch_rect); 1163 EXPECT_EQ(v32, result_view); 1164 result_view = NULL; 1165 1166 // Covers |v5| and |v51| by at least 60%, and the center point of 1167 // the touch is located within both views. Since both views share 1168 // the same center point, the child view should be selected. 1169 touch_rect.SetRect(440, 190, 40, 40); 1170 result_view = root_view->GetEventHandlerForRect(touch_rect); 1171 EXPECT_EQ(v51, result_view); 1172 result_view = NULL; 1173 1174 // Covers |v5| and |v51| by at least 60%, but the center point of 1175 // the touch is not located within either view. Since both views 1176 // share the same center point, the child view should be selected. 1177 touch_rect.SetRect(455, 187, 60, 60); 1178 result_view = root_view->GetEventHandlerForRect(touch_rect); 1179 EXPECT_EQ(v51, result_view); 1180 result_view = NULL; 1181 1182 // Covers neither |v5| nor |v51| by at least 60%, but the center 1183 // of the touch is located within |v51|. 1184 touch_rect.SetRect(450, 197, 10, 10); 1185 result_view = root_view->GetEventHandlerForRect(touch_rect); 1186 EXPECT_EQ(v51, result_view); 1187 result_view = NULL; 1188 1189 // Covers neither |v5| nor |v51| by at least 60% but intersects both. 1190 // The center point is located outside of both views. 1191 touch_rect.SetRect(433, 180, 24, 24); 1192 result_view = root_view->GetEventHandlerForRect(touch_rect); 1193 EXPECT_EQ(root_view, result_view); 1194 result_view = NULL; 1195 1196 // Only intersects |v5| but does not cover it by at least 60%. The 1197 // center point of the touch region is located within |v5|. 1198 touch_rect.SetRect(449, 196, 3, 3); 1199 result_view = root_view->GetEventHandlerForRect(touch_rect); 1200 EXPECT_EQ(v5, result_view); 1201 result_view = NULL; 1202 1203 // A mouse click within |v5| (but not |v51|) should target |v5|. 1204 touch_rect.SetRect(462, 199, 1, 1); 1205 result_view = root_view->GetEventHandlerForRect(touch_rect); 1206 EXPECT_EQ(v5, result_view); 1207 result_view = NULL; 1208 1209 // A mouse click |v5| and |v51| should target the child view. 1210 touch_rect.SetRect(452, 226, 1, 1); 1211 result_view = root_view->GetEventHandlerForRect(touch_rect); 1212 EXPECT_EQ(v51, result_view); 1213 result_view = NULL; 1214 1215 // A mouse click on the center of |v5| and |v51| should target 1216 // the child view. 1217 touch_rect.SetRect(465, 215, 1, 1); 1218 result_view = root_view->GetEventHandlerForRect(touch_rect); 1219 EXPECT_EQ(v51, result_view); 1220 result_view = NULL; 1221 1222 widget->CloseNow(); 1223 } 1224 1225 // Tests that GetEventHandlerForRect() and GetTooltipHandlerForPoint() behave 1226 // as expected when different views in the view hierarchy return false 1227 // when CanProcessEventsWithinSubtree() is called. 1228 TEST_F(ViewTest, CanProcessEventsWithinSubtree) { 1229 Widget* widget = new Widget; 1230 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 1231 widget->Init(params); 1232 View* root_view = widget->GetRootView(); 1233 root_view->SetBoundsRect(gfx::Rect(0, 0, 500, 500)); 1234 1235 // Have this hierarchy of views (the coords here are in the coordinate 1236 // space of the root view): 1237 // v (0, 0, 100, 100) 1238 // - v_child (0, 0, 20, 30) 1239 // - v_grandchild (5, 5, 5, 15) 1240 1241 TestView* v = new TestView; 1242 v->SetBounds(0, 0, 100, 100); 1243 root_view->AddChildView(v); 1244 v->set_notify_enter_exit_on_child(true); 1245 1246 TestView* v_child = new TestView; 1247 v_child->SetBounds(0, 0, 20, 30); 1248 v->AddChildView(v_child); 1249 1250 TestView* v_grandchild = new TestView; 1251 v_grandchild->SetBounds(5, 5, 5, 15); 1252 v_child->AddChildView(v_grandchild); 1253 1254 v->Reset(); 1255 v_child->Reset(); 1256 v_grandchild->Reset(); 1257 1258 // Define rects and points within the views in the hierarchy. 1259 gfx::Rect rect_in_v_grandchild(7, 7, 3, 3); 1260 gfx::Point point_in_v_grandchild(rect_in_v_grandchild.origin()); 1261 gfx::Rect rect_in_v_child(12, 3, 5, 5); 1262 gfx::Point point_in_v_child(rect_in_v_child.origin()); 1263 gfx::Rect rect_in_v(50, 50, 25, 30); 1264 gfx::Point point_in_v(rect_in_v.origin()); 1265 1266 // When all three views return true when CanProcessEventsWithinSubtree() 1267 // is called, targeting should behave as expected. 1268 1269 View* result_view = root_view->GetEventHandlerForRect(rect_in_v_grandchild); 1270 EXPECT_EQ(v_grandchild, result_view); 1271 result_view = NULL; 1272 result_view = root_view->GetTooltipHandlerForPoint(point_in_v_grandchild); 1273 EXPECT_EQ(v_grandchild, result_view); 1274 result_view = NULL; 1275 1276 result_view = root_view->GetEventHandlerForRect(rect_in_v_child); 1277 EXPECT_EQ(v_child, result_view); 1278 result_view = NULL; 1279 result_view = root_view->GetTooltipHandlerForPoint(point_in_v_child); 1280 EXPECT_EQ(v_child, result_view); 1281 result_view = NULL; 1282 1283 result_view = root_view->GetEventHandlerForRect(rect_in_v); 1284 EXPECT_EQ(v, result_view); 1285 result_view = NULL; 1286 result_view = root_view->GetTooltipHandlerForPoint(point_in_v); 1287 EXPECT_EQ(v, result_view); 1288 result_view = NULL; 1289 1290 // When |v_grandchild| returns false when CanProcessEventsWithinSubtree() 1291 // is called, then |v_grandchild| cannot be returned as a target. 1292 1293 v_grandchild->set_can_process_events_within_subtree(false); 1294 1295 result_view = root_view->GetEventHandlerForRect(rect_in_v_grandchild); 1296 EXPECT_EQ(v_child, result_view); 1297 result_view = NULL; 1298 result_view = root_view->GetTooltipHandlerForPoint(point_in_v_grandchild); 1299 EXPECT_EQ(v_child, result_view); 1300 result_view = NULL; 1301 1302 result_view = root_view->GetEventHandlerForRect(rect_in_v_child); 1303 EXPECT_EQ(v_child, result_view); 1304 result_view = NULL; 1305 result_view = root_view->GetTooltipHandlerForPoint(point_in_v_child); 1306 EXPECT_EQ(v_child, result_view); 1307 result_view = NULL; 1308 1309 result_view = root_view->GetEventHandlerForRect(rect_in_v); 1310 EXPECT_EQ(v, result_view); 1311 result_view = NULL; 1312 result_view = root_view->GetTooltipHandlerForPoint(point_in_v); 1313 EXPECT_EQ(v, result_view); 1314 1315 // When |v_grandchild| returns false when CanProcessEventsWithinSubtree() 1316 // is called, then NULL should be returned as a target if we call 1317 // GetTooltipHandlerForPoint() with |v_grandchild| as the root of the 1318 // views tree. Note that the location must be in the coordinate space 1319 // of the root view (|v_grandchild| in this case), so use (1, 1). 1320 1321 result_view = v_grandchild; 1322 result_view = v_grandchild->GetTooltipHandlerForPoint(gfx::Point(1, 1)); 1323 EXPECT_EQ(NULL, result_view); 1324 result_view = NULL; 1325 1326 // When |v_child| returns false when CanProcessEventsWithinSubtree() 1327 // is called, then neither |v_child| nor |v_grandchild| can be returned 1328 // as a target (|v| should be returned as the target for each case). 1329 1330 v_grandchild->Reset(); 1331 v_child->set_can_process_events_within_subtree(false); 1332 1333 result_view = root_view->GetEventHandlerForRect(rect_in_v_grandchild); 1334 EXPECT_EQ(v, result_view); 1335 result_view = NULL; 1336 result_view = root_view->GetTooltipHandlerForPoint(point_in_v_grandchild); 1337 EXPECT_EQ(v, result_view); 1338 result_view = NULL; 1339 1340 result_view = root_view->GetEventHandlerForRect(rect_in_v_child); 1341 EXPECT_EQ(v, result_view); 1342 result_view = NULL; 1343 result_view = root_view->GetTooltipHandlerForPoint(point_in_v_child); 1344 EXPECT_EQ(v, result_view); 1345 result_view = NULL; 1346 1347 result_view = root_view->GetEventHandlerForRect(rect_in_v); 1348 EXPECT_EQ(v, result_view); 1349 result_view = NULL; 1350 result_view = root_view->GetTooltipHandlerForPoint(point_in_v); 1351 EXPECT_EQ(v, result_view); 1352 result_view = NULL; 1353 1354 // When |v| returns false when CanProcessEventsWithinSubtree() 1355 // is called, then none of |v|, |v_child|, and |v_grandchild| can be returned 1356 // as a target (|root_view| should be returned as the target for each case). 1357 1358 v_child->Reset(); 1359 v->set_can_process_events_within_subtree(false); 1360 1361 result_view = root_view->GetEventHandlerForRect(rect_in_v_grandchild); 1362 EXPECT_EQ(root_view, result_view); 1363 result_view = NULL; 1364 result_view = root_view->GetTooltipHandlerForPoint(point_in_v_grandchild); 1365 EXPECT_EQ(root_view, result_view); 1366 result_view = NULL; 1367 1368 result_view = root_view->GetEventHandlerForRect(rect_in_v_child); 1369 EXPECT_EQ(root_view, result_view); 1370 result_view = NULL; 1371 result_view = root_view->GetTooltipHandlerForPoint(point_in_v_child); 1372 EXPECT_EQ(root_view, result_view); 1373 result_view = NULL; 1374 1375 result_view = root_view->GetEventHandlerForRect(rect_in_v); 1376 EXPECT_EQ(root_view, result_view); 1377 result_view = NULL; 1378 result_view = root_view->GetTooltipHandlerForPoint(point_in_v); 1379 EXPECT_EQ(root_view, result_view); 1380 } 1381 1382 TEST_F(ViewTest, NotifyEnterExitOnChild) { 1383 Widget* widget = new Widget; 1384 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 1385 widget->Init(params); 1386 View* root_view = widget->GetRootView(); 1387 root_view->SetBoundsRect(gfx::Rect(0, 0, 500, 500)); 1388 1389 // Have this hierarchy of views (the coords here are in root coord): 1390 // v1 (0, 0, 100, 100) 1391 // - v11 (0, 0, 20, 30) 1392 // - v111 (5, 5, 5, 15) 1393 // - v12 (50, 10, 30, 90) 1394 // - v121 (60, 20, 10, 10) 1395 // v2 (105, 0, 100, 100) 1396 // - v21 (120, 10, 50, 20) 1397 1398 TestView* v1 = new TestView; 1399 v1->SetBounds(0, 0, 100, 100); 1400 root_view->AddChildView(v1); 1401 v1->set_notify_enter_exit_on_child(true); 1402 1403 TestView* v11 = new TestView; 1404 v11->SetBounds(0, 0, 20, 30); 1405 v1->AddChildView(v11); 1406 1407 TestView* v111 = new TestView; 1408 v111->SetBounds(5, 5, 5, 15); 1409 v11->AddChildView(v111); 1410 1411 TestView* v12 = new TestView; 1412 v12->SetBounds(50, 10, 30, 90); 1413 v1->AddChildView(v12); 1414 1415 TestView* v121 = new TestView; 1416 v121->SetBounds(10, 10, 10, 10); 1417 v12->AddChildView(v121); 1418 1419 TestView* v2 = new TestView; 1420 v2->SetBounds(105, 0, 100, 100); 1421 root_view->AddChildView(v2); 1422 1423 TestView* v21 = new TestView; 1424 v21->SetBounds(15, 10, 50, 20); 1425 v2->AddChildView(v21); 1426 1427 v1->Reset(); 1428 v11->Reset(); 1429 v111->Reset(); 1430 v12->Reset(); 1431 v121->Reset(); 1432 v2->Reset(); 1433 v21->Reset(); 1434 1435 // Move the mouse in v111. 1436 gfx::Point p1(6, 6); 1437 ui::MouseEvent move1(ui::ET_MOUSE_MOVED, p1, p1, 0, 0); 1438 root_view->OnMouseMoved(move1); 1439 EXPECT_TRUE(v111->received_mouse_enter_); 1440 EXPECT_FALSE(v11->last_mouse_event_type_); 1441 EXPECT_TRUE(v1->received_mouse_enter_); 1442 1443 v111->Reset(); 1444 v1->Reset(); 1445 1446 // Now, move into v121. 1447 gfx::Point p2(65, 21); 1448 ui::MouseEvent move2(ui::ET_MOUSE_MOVED, p2, p2, 0, 0); 1449 root_view->OnMouseMoved(move2); 1450 EXPECT_TRUE(v111->received_mouse_exit_); 1451 EXPECT_TRUE(v121->received_mouse_enter_); 1452 EXPECT_FALSE(v1->last_mouse_event_type_); 1453 1454 v111->Reset(); 1455 v121->Reset(); 1456 1457 // Now, move into v11. 1458 gfx::Point p3(1, 1); 1459 ui::MouseEvent move3(ui::ET_MOUSE_MOVED, p3, p3, 0, 0); 1460 root_view->OnMouseMoved(move3); 1461 EXPECT_TRUE(v121->received_mouse_exit_); 1462 EXPECT_TRUE(v11->received_mouse_enter_); 1463 EXPECT_FALSE(v1->last_mouse_event_type_); 1464 1465 v121->Reset(); 1466 v11->Reset(); 1467 1468 // Move to v21. 1469 gfx::Point p4(121, 15); 1470 ui::MouseEvent move4(ui::ET_MOUSE_MOVED, p4, p4, 0, 0); 1471 root_view->OnMouseMoved(move4); 1472 EXPECT_TRUE(v21->received_mouse_enter_); 1473 EXPECT_FALSE(v2->last_mouse_event_type_); 1474 EXPECT_TRUE(v11->received_mouse_exit_); 1475 EXPECT_TRUE(v1->received_mouse_exit_); 1476 1477 v21->Reset(); 1478 v11->Reset(); 1479 v1->Reset(); 1480 1481 // Move to v1. 1482 gfx::Point p5(21, 0); 1483 ui::MouseEvent move5(ui::ET_MOUSE_MOVED, p5, p5, 0, 0); 1484 root_view->OnMouseMoved(move5); 1485 EXPECT_TRUE(v21->received_mouse_exit_); 1486 EXPECT_TRUE(v1->received_mouse_enter_); 1487 1488 v21->Reset(); 1489 v1->Reset(); 1490 1491 // Now, move into v11. 1492 gfx::Point p6(15, 15); 1493 ui::MouseEvent mouse6(ui::ET_MOUSE_MOVED, p6, p6, 0, 0); 1494 root_view->OnMouseMoved(mouse6); 1495 EXPECT_TRUE(v11->received_mouse_enter_); 1496 EXPECT_FALSE(v1->last_mouse_event_type_); 1497 1498 v11->Reset(); 1499 v1->Reset(); 1500 1501 // Move back into v1. Although |v1| had already received an ENTER for mouse6, 1502 // and the mouse remains inside |v1| the whole time, it receives another ENTER 1503 // when the mouse leaves v11. 1504 gfx::Point p7(21, 0); 1505 ui::MouseEvent mouse7(ui::ET_MOUSE_MOVED, p7, p7, 0, 0); 1506 root_view->OnMouseMoved(mouse7); 1507 EXPECT_TRUE(v11->received_mouse_exit_); 1508 EXPECT_FALSE(v1->received_mouse_enter_); 1509 1510 widget->CloseNow(); 1511 } 1512 1513 TEST_F(ViewTest, Textfield) { 1514 const base::string16 kText = ASCIIToUTF16( 1515 "Reality is that which, when you stop believing it, doesn't go away."); 1516 const base::string16 kExtraText = ASCIIToUTF16("Pretty deep, Philip!"); 1517 const base::string16 kEmptyString; 1518 1519 Widget* widget = new Widget; 1520 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 1521 params.bounds = gfx::Rect(0, 0, 100, 100); 1522 widget->Init(params); 1523 View* root_view = widget->GetRootView(); 1524 1525 Textfield* textfield = new Textfield(); 1526 root_view->AddChildView(textfield); 1527 1528 // Test setting, appending text. 1529 textfield->SetText(kText); 1530 EXPECT_EQ(kText, textfield->text()); 1531 textfield->AppendText(kExtraText); 1532 EXPECT_EQ(kText + kExtraText, textfield->text()); 1533 textfield->SetText(base::string16()); 1534 EXPECT_EQ(kEmptyString, textfield->text()); 1535 1536 // Test selection related methods. 1537 textfield->SetText(kText); 1538 EXPECT_EQ(kEmptyString, textfield->GetSelectedText()); 1539 textfield->SelectAll(false); 1540 EXPECT_EQ(kText, textfield->text()); 1541 textfield->ClearSelection(); 1542 EXPECT_EQ(kEmptyString, textfield->GetSelectedText()); 1543 1544 widget->CloseNow(); 1545 } 1546 1547 // Tests that the Textfield view respond appropiately to cut/copy/paste. 1548 TEST_F(ViewTest, TextfieldCutCopyPaste) { 1549 const base::string16 kNormalText = ASCIIToUTF16("Normal"); 1550 const base::string16 kReadOnlyText = ASCIIToUTF16("Read only"); 1551 const base::string16 kPasswordText = 1552 ASCIIToUTF16("Password! ** Secret stuff **"); 1553 1554 ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread(); 1555 1556 Widget* widget = new Widget; 1557 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 1558 params.bounds = gfx::Rect(0, 0, 100, 100); 1559 widget->Init(params); 1560 View* root_view = widget->GetRootView(); 1561 1562 Textfield* normal = new Textfield(); 1563 Textfield* read_only = new Textfield(); 1564 read_only->SetReadOnly(true); 1565 Textfield* password = new Textfield(); 1566 password->SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD); 1567 1568 root_view->AddChildView(normal); 1569 root_view->AddChildView(read_only); 1570 root_view->AddChildView(password); 1571 1572 normal->SetText(kNormalText); 1573 read_only->SetText(kReadOnlyText); 1574 password->SetText(kPasswordText); 1575 1576 // 1577 // Test cut. 1578 // 1579 1580 normal->SelectAll(false); 1581 normal->ExecuteCommand(IDS_APP_CUT); 1582 base::string16 result; 1583 clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &result); 1584 EXPECT_EQ(kNormalText, result); 1585 normal->SetText(kNormalText); // Let's revert to the original content. 1586 1587 read_only->SelectAll(false); 1588 read_only->ExecuteCommand(IDS_APP_CUT); 1589 result.clear(); 1590 clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &result); 1591 // Cut should have failed, so the clipboard content should not have changed. 1592 EXPECT_EQ(kNormalText, result); 1593 1594 password->SelectAll(false); 1595 password->ExecuteCommand(IDS_APP_CUT); 1596 result.clear(); 1597 clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &result); 1598 // Cut should have failed, so the clipboard content should not have changed. 1599 EXPECT_EQ(kNormalText, result); 1600 1601 // 1602 // Test copy. 1603 // 1604 1605 // Start with |read_only| to observe a change in clipboard text. 1606 read_only->SelectAll(false); 1607 read_only->ExecuteCommand(IDS_APP_COPY); 1608 result.clear(); 1609 clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &result); 1610 EXPECT_EQ(kReadOnlyText, result); 1611 1612 normal->SelectAll(false); 1613 normal->ExecuteCommand(IDS_APP_COPY); 1614 result.clear(); 1615 clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &result); 1616 EXPECT_EQ(kNormalText, result); 1617 1618 password->SelectAll(false); 1619 password->ExecuteCommand(IDS_APP_COPY); 1620 result.clear(); 1621 clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &result); 1622 // Text cannot be copied from an obscured field; the clipboard won't change. 1623 EXPECT_EQ(kNormalText, result); 1624 1625 // 1626 // Test paste. 1627 // 1628 1629 // Attempting to paste kNormalText in a read-only text-field should fail. 1630 read_only->SelectAll(false); 1631 read_only->ExecuteCommand(IDS_APP_PASTE); 1632 EXPECT_EQ(kReadOnlyText, read_only->text()); 1633 1634 password->SelectAll(false); 1635 password->ExecuteCommand(IDS_APP_PASTE); 1636 EXPECT_EQ(kNormalText, password->text()); 1637 1638 // Copy from |read_only| to observe a change in the normal textfield text. 1639 read_only->SelectAll(false); 1640 read_only->ExecuteCommand(IDS_APP_COPY); 1641 normal->SelectAll(false); 1642 normal->ExecuteCommand(IDS_APP_PASTE); 1643 EXPECT_EQ(kReadOnlyText, normal->text()); 1644 widget->CloseNow(); 1645 } 1646 1647 //////////////////////////////////////////////////////////////////////////////// 1648 // Accelerators 1649 //////////////////////////////////////////////////////////////////////////////// 1650 bool TestView::AcceleratorPressed(const ui::Accelerator& accelerator) { 1651 accelerator_count_map_[accelerator]++; 1652 return true; 1653 } 1654 1655 // TODO: these tests were initially commented out when getting aura to 1656 // run. Figure out if still valuable and either nuke or fix. 1657 #if 0 1658 TEST_F(ViewTest, ActivateAccelerator) { 1659 // Register a keyboard accelerator before the view is added to a window. 1660 ui::Accelerator return_accelerator(ui::VKEY_RETURN, ui::EF_NONE); 1661 TestView* view = new TestView(); 1662 view->Reset(); 1663 view->AddAccelerator(return_accelerator); 1664 EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 0); 1665 1666 // Create a window and add the view as its child. 1667 scoped_ptr<Widget> widget(new Widget); 1668 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 1669 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 1670 params.bounds = gfx::Rect(0, 0, 100, 100); 1671 widget->Init(params); 1672 View* root = widget->GetRootView(); 1673 root->AddChildView(view); 1674 widget->Show(); 1675 1676 // Get the focus manager. 1677 FocusManager* focus_manager = widget->GetFocusManager(); 1678 ASSERT_TRUE(focus_manager); 1679 1680 // Hit the return key and see if it takes effect. 1681 EXPECT_TRUE(focus_manager->ProcessAccelerator(return_accelerator)); 1682 EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 1); 1683 1684 // Hit the escape key. Nothing should happen. 1685 ui::Accelerator escape_accelerator(ui::VKEY_ESCAPE, ui::EF_NONE); 1686 EXPECT_FALSE(focus_manager->ProcessAccelerator(escape_accelerator)); 1687 EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 1); 1688 EXPECT_EQ(view->accelerator_count_map_[escape_accelerator], 0); 1689 1690 // Now register the escape key and hit it again. 1691 view->AddAccelerator(escape_accelerator); 1692 EXPECT_TRUE(focus_manager->ProcessAccelerator(escape_accelerator)); 1693 EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 1); 1694 EXPECT_EQ(view->accelerator_count_map_[escape_accelerator], 1); 1695 1696 // Remove the return key accelerator. 1697 view->RemoveAccelerator(return_accelerator); 1698 EXPECT_FALSE(focus_manager->ProcessAccelerator(return_accelerator)); 1699 EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 1); 1700 EXPECT_EQ(view->accelerator_count_map_[escape_accelerator], 1); 1701 1702 // Add it again. Hit the return key and the escape key. 1703 view->AddAccelerator(return_accelerator); 1704 EXPECT_TRUE(focus_manager->ProcessAccelerator(return_accelerator)); 1705 EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 2); 1706 EXPECT_EQ(view->accelerator_count_map_[escape_accelerator], 1); 1707 EXPECT_TRUE(focus_manager->ProcessAccelerator(escape_accelerator)); 1708 EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 2); 1709 EXPECT_EQ(view->accelerator_count_map_[escape_accelerator], 2); 1710 1711 // Remove all the accelerators. 1712 view->ResetAccelerators(); 1713 EXPECT_FALSE(focus_manager->ProcessAccelerator(return_accelerator)); 1714 EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 2); 1715 EXPECT_EQ(view->accelerator_count_map_[escape_accelerator], 2); 1716 EXPECT_FALSE(focus_manager->ProcessAccelerator(escape_accelerator)); 1717 EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 2); 1718 EXPECT_EQ(view->accelerator_count_map_[escape_accelerator], 2); 1719 1720 widget->CloseNow(); 1721 } 1722 1723 TEST_F(ViewTest, HiddenViewWithAccelerator) { 1724 ui::Accelerator return_accelerator(ui::VKEY_RETURN, ui::EF_NONE); 1725 TestView* view = new TestView(); 1726 view->Reset(); 1727 view->AddAccelerator(return_accelerator); 1728 EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 0); 1729 1730 scoped_ptr<Widget> widget(new Widget); 1731 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 1732 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 1733 params.bounds = gfx::Rect(0, 0, 100, 100); 1734 widget->Init(params); 1735 View* root = widget->GetRootView(); 1736 root->AddChildView(view); 1737 widget->Show(); 1738 1739 FocusManager* focus_manager = widget->GetFocusManager(); 1740 ASSERT_TRUE(focus_manager); 1741 1742 view->SetVisible(false); 1743 EXPECT_FALSE(focus_manager->ProcessAccelerator(return_accelerator)); 1744 1745 view->SetVisible(true); 1746 EXPECT_TRUE(focus_manager->ProcessAccelerator(return_accelerator)); 1747 1748 widget->CloseNow(); 1749 } 1750 1751 TEST_F(ViewTest, ViewInHiddenWidgetWithAccelerator) { 1752 ui::Accelerator return_accelerator(ui::VKEY_RETURN, ui::EF_NONE); 1753 TestView* view = new TestView(); 1754 view->Reset(); 1755 view->AddAccelerator(return_accelerator); 1756 EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 0); 1757 1758 scoped_ptr<Widget> widget(new Widget); 1759 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 1760 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 1761 params.bounds = gfx::Rect(0, 0, 100, 100); 1762 widget->Init(params); 1763 View* root = widget->GetRootView(); 1764 root->AddChildView(view); 1765 1766 FocusManager* focus_manager = widget->GetFocusManager(); 1767 ASSERT_TRUE(focus_manager); 1768 1769 EXPECT_FALSE(focus_manager->ProcessAccelerator(return_accelerator)); 1770 EXPECT_EQ(0, view->accelerator_count_map_[return_accelerator]); 1771 1772 widget->Show(); 1773 EXPECT_TRUE(focus_manager->ProcessAccelerator(return_accelerator)); 1774 EXPECT_EQ(1, view->accelerator_count_map_[return_accelerator]); 1775 1776 widget->Hide(); 1777 EXPECT_FALSE(focus_manager->ProcessAccelerator(return_accelerator)); 1778 EXPECT_EQ(1, view->accelerator_count_map_[return_accelerator]); 1779 1780 widget->CloseNow(); 1781 } 1782 1783 //////////////////////////////////////////////////////////////////////////////// 1784 // Mouse-wheel message rerouting 1785 //////////////////////////////////////////////////////////////////////////////// 1786 class ScrollableTestView : public View { 1787 public: 1788 ScrollableTestView() { } 1789 1790 virtual gfx::Size GetPreferredSize() { 1791 return gfx::Size(100, 10000); 1792 } 1793 1794 virtual void Layout() { 1795 SizeToPreferredSize(); 1796 } 1797 }; 1798 1799 class TestViewWithControls : public View { 1800 public: 1801 TestViewWithControls() { 1802 text_field_ = new Textfield(); 1803 AddChildView(text_field_); 1804 } 1805 1806 Textfield* text_field_; 1807 }; 1808 1809 class SimpleWidgetDelegate : public WidgetDelegate { 1810 public: 1811 explicit SimpleWidgetDelegate(View* contents) : contents_(contents) { } 1812 1813 virtual void DeleteDelegate() { delete this; } 1814 1815 virtual View* GetContentsView() { return contents_; } 1816 1817 virtual Widget* GetWidget() { return contents_->GetWidget(); } 1818 virtual const Widget* GetWidget() const { return contents_->GetWidget(); } 1819 1820 private: 1821 View* contents_; 1822 }; 1823 1824 // Tests that the mouse-wheel messages are correctly rerouted to the window 1825 // under the mouse. 1826 // TODO(jcampan): http://crbug.com/10572 Disabled as it fails on the Vista build 1827 // bot. 1828 // Note that this fails for a variety of reasons: 1829 // - focused view is apparently reset across window activations and never 1830 // properly restored 1831 // - this test depends on you not having any other window visible open under the 1832 // area that it opens the test windows. --beng 1833 TEST_F(ViewTest, DISABLED_RerouteMouseWheelTest) { 1834 TestViewWithControls* view_with_controls = new TestViewWithControls(); 1835 Widget* window1 = Widget::CreateWindowWithBounds( 1836 new SimpleWidgetDelegate(view_with_controls), 1837 gfx::Rect(0, 0, 100, 100)); 1838 window1->Show(); 1839 ScrollView* scroll_view = new ScrollView(); 1840 scroll_view->SetContents(new ScrollableTestView()); 1841 Widget* window2 = Widget::CreateWindowWithBounds( 1842 new SimpleWidgetDelegate(scroll_view), 1843 gfx::Rect(200, 200, 100, 100)); 1844 window2->Show(); 1845 EXPECT_EQ(0, scroll_view->GetVisibleRect().y()); 1846 1847 // Make the window1 active, as this is what it would be in real-world. 1848 window1->Activate(); 1849 1850 // Let's send a mouse-wheel message to the different controls and check that 1851 // it is rerouted to the window under the mouse (effectively scrolling the 1852 // scroll-view). 1853 1854 // First to the Window's HWND. 1855 ::SendMessage(view_with_controls->GetWidget()->GetNativeView(), 1856 WM_MOUSEWHEEL, MAKEWPARAM(0, -20), MAKELPARAM(250, 250)); 1857 EXPECT_EQ(20, scroll_view->GetVisibleRect().y()); 1858 1859 window1->CloseNow(); 1860 window2->CloseNow(); 1861 } 1862 #endif // 0 1863 1864 //////////////////////////////////////////////////////////////////////////////// 1865 // Native view hierachy 1866 //////////////////////////////////////////////////////////////////////////////// 1867 class ToplevelWidgetObserverView : public View { 1868 public: 1869 ToplevelWidgetObserverView() : toplevel_(NULL) { 1870 } 1871 virtual ~ToplevelWidgetObserverView() { 1872 } 1873 1874 // View overrides: 1875 virtual void ViewHierarchyChanged( 1876 const ViewHierarchyChangedDetails& details) OVERRIDE { 1877 if (details.is_add) { 1878 toplevel_ = GetWidget() ? GetWidget()->GetTopLevelWidget() : NULL; 1879 } else { 1880 toplevel_ = NULL; 1881 } 1882 } 1883 virtual void NativeViewHierarchyChanged() OVERRIDE { 1884 toplevel_ = GetWidget() ? GetWidget()->GetTopLevelWidget() : NULL; 1885 } 1886 1887 Widget* toplevel() { return toplevel_; } 1888 1889 private: 1890 Widget* toplevel_; 1891 1892 DISALLOW_COPY_AND_ASSIGN(ToplevelWidgetObserverView); 1893 }; 1894 1895 // Test that a view can track the current top level widget by overriding 1896 // View::ViewHierarchyChanged() and View::NativeViewHierarchyChanged(). 1897 TEST_F(ViewTest, NativeViewHierarchyChanged) { 1898 scoped_ptr<Widget> toplevel1(new Widget); 1899 Widget::InitParams toplevel1_params = 1900 CreateParams(Widget::InitParams::TYPE_POPUP); 1901 toplevel1_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 1902 toplevel1->Init(toplevel1_params); 1903 1904 scoped_ptr<Widget> toplevel2(new Widget); 1905 Widget::InitParams toplevel2_params = 1906 CreateParams(Widget::InitParams::TYPE_POPUP); 1907 toplevel2_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 1908 toplevel2->Init(toplevel2_params); 1909 1910 Widget* child = new Widget; 1911 Widget::InitParams child_params(Widget::InitParams::TYPE_CONTROL); 1912 child_params.parent = toplevel1->GetNativeView(); 1913 child->Init(child_params); 1914 1915 ToplevelWidgetObserverView* observer_view = 1916 new ToplevelWidgetObserverView(); 1917 EXPECT_EQ(NULL, observer_view->toplevel()); 1918 1919 child->SetContentsView(observer_view); 1920 EXPECT_EQ(toplevel1, observer_view->toplevel()); 1921 1922 Widget::ReparentNativeView(child->GetNativeView(), 1923 toplevel2->GetNativeView()); 1924 EXPECT_EQ(toplevel2, observer_view->toplevel()); 1925 1926 observer_view->parent()->RemoveChildView(observer_view); 1927 EXPECT_EQ(NULL, observer_view->toplevel()); 1928 1929 // Make |observer_view| |child|'s contents view again so that it gets deleted 1930 // with the widget. 1931 child->SetContentsView(observer_view); 1932 } 1933 1934 //////////////////////////////////////////////////////////////////////////////// 1935 // Transformations 1936 //////////////////////////////////////////////////////////////////////////////// 1937 1938 class TransformPaintView : public TestView { 1939 public: 1940 TransformPaintView() {} 1941 virtual ~TransformPaintView() {} 1942 1943 void ClearScheduledPaintRect() { 1944 scheduled_paint_rect_ = gfx::Rect(); 1945 } 1946 1947 gfx::Rect scheduled_paint_rect() const { return scheduled_paint_rect_; } 1948 1949 // Overridden from View: 1950 virtual void SchedulePaintInRect(const gfx::Rect& rect) OVERRIDE { 1951 gfx::Rect xrect = ConvertRectToParent(rect); 1952 scheduled_paint_rect_.Union(xrect); 1953 } 1954 1955 private: 1956 gfx::Rect scheduled_paint_rect_; 1957 1958 DISALLOW_COPY_AND_ASSIGN(TransformPaintView); 1959 }; 1960 1961 TEST_F(ViewTest, TransformPaint) { 1962 TransformPaintView* v1 = new TransformPaintView(); 1963 v1->SetBoundsRect(gfx::Rect(0, 0, 500, 300)); 1964 1965 TestView* v2 = new TestView(); 1966 v2->SetBoundsRect(gfx::Rect(100, 100, 200, 100)); 1967 1968 Widget* widget = new Widget; 1969 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 1970 params.bounds = gfx::Rect(50, 50, 650, 650); 1971 widget->Init(params); 1972 widget->Show(); 1973 View* root = widget->GetRootView(); 1974 1975 root->AddChildView(v1); 1976 v1->AddChildView(v2); 1977 1978 // At this moment, |v2| occupies (100, 100) to (300, 200) in |root|. 1979 v1->ClearScheduledPaintRect(); 1980 v2->SchedulePaint(); 1981 1982 EXPECT_EQ(gfx::Rect(100, 100, 200, 100), v1->scheduled_paint_rect()); 1983 1984 // Rotate |v1| counter-clockwise. 1985 gfx::Transform transform; 1986 RotateCounterclockwise(&transform); 1987 transform.matrix().set(1, 3, 500.0); 1988 v1->SetTransform(transform); 1989 1990 // |v2| now occupies (100, 200) to (200, 400) in |root|. 1991 1992 v1->ClearScheduledPaintRect(); 1993 v2->SchedulePaint(); 1994 1995 EXPECT_EQ(gfx::Rect(100, 200, 100, 200), v1->scheduled_paint_rect()); 1996 1997 widget->CloseNow(); 1998 } 1999 2000 TEST_F(ViewTest, TransformEvent) { 2001 TestView* v1 = new TestView(); 2002 v1->SetBoundsRect(gfx::Rect(0, 0, 500, 300)); 2003 2004 TestView* v2 = new TestView(); 2005 v2->SetBoundsRect(gfx::Rect(100, 100, 200, 100)); 2006 2007 Widget* widget = new Widget; 2008 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 2009 params.bounds = gfx::Rect(50, 50, 650, 650); 2010 widget->Init(params); 2011 View* root = widget->GetRootView(); 2012 2013 root->AddChildView(v1); 2014 v1->AddChildView(v2); 2015 2016 // At this moment, |v2| occupies (100, 100) to (300, 200) in |root|. 2017 2018 // Rotate |v1| counter-clockwise. 2019 gfx::Transform transform(v1->GetTransform()); 2020 RotateCounterclockwise(&transform); 2021 transform.matrix().set(1, 3, 500.0); 2022 v1->SetTransform(transform); 2023 2024 // |v2| now occupies (100, 200) to (200, 400) in |root|. 2025 v1->Reset(); 2026 v2->Reset(); 2027 2028 gfx::Point p1(110, 210); 2029 ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, p1, p1, 2030 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); 2031 root->OnMousePressed(pressed); 2032 EXPECT_EQ(0, v1->last_mouse_event_type_); 2033 EXPECT_EQ(ui::ET_MOUSE_PRESSED, v2->last_mouse_event_type_); 2034 EXPECT_EQ(190, v2->location_.x()); 2035 EXPECT_EQ(10, v2->location_.y()); 2036 2037 ui::MouseEvent released(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(), 0, 2038 0); 2039 root->OnMouseReleased(released); 2040 2041 // Now rotate |v2| inside |v1| clockwise. 2042 transform = v2->GetTransform(); 2043 RotateClockwise(&transform); 2044 transform.matrix().set(0, 3, 100.f); 2045 v2->SetTransform(transform); 2046 2047 // Now, |v2| occupies (100, 100) to (200, 300) in |v1|, and (100, 300) to 2048 // (300, 400) in |root|. 2049 2050 v1->Reset(); 2051 v2->Reset(); 2052 2053 gfx::Point point2(110, 320); 2054 ui::MouseEvent p2(ui::ET_MOUSE_PRESSED, point2, point2, 2055 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); 2056 root->OnMousePressed(p2); 2057 EXPECT_EQ(0, v1->last_mouse_event_type_); 2058 EXPECT_EQ(ui::ET_MOUSE_PRESSED, v2->last_mouse_event_type_); 2059 EXPECT_EQ(10, v2->location_.x()); 2060 EXPECT_EQ(20, v2->location_.y()); 2061 2062 root->OnMouseReleased(released); 2063 2064 v1->SetTransform(gfx::Transform()); 2065 v2->SetTransform(gfx::Transform()); 2066 2067 TestView* v3 = new TestView(); 2068 v3->SetBoundsRect(gfx::Rect(10, 10, 20, 30)); 2069 v2->AddChildView(v3); 2070 2071 // Rotate |v3| clockwise with respect to |v2|. 2072 transform = v1->GetTransform(); 2073 RotateClockwise(&transform); 2074 transform.matrix().set(0, 3, 30.f); 2075 v3->SetTransform(transform); 2076 2077 // Scale |v2| with respect to |v1| along both axis. 2078 transform = v2->GetTransform(); 2079 transform.matrix().set(0, 0, 0.8f); 2080 transform.matrix().set(1, 1, 0.5f); 2081 v2->SetTransform(transform); 2082 2083 // |v3| occupies (108, 105) to (132, 115) in |root|. 2084 2085 v1->Reset(); 2086 v2->Reset(); 2087 v3->Reset(); 2088 2089 gfx::Point point(112, 110); 2090 ui::MouseEvent p3(ui::ET_MOUSE_PRESSED, point, point, 2091 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); 2092 root->OnMousePressed(p3); 2093 2094 EXPECT_EQ(ui::ET_MOUSE_PRESSED, v3->last_mouse_event_type_); 2095 EXPECT_EQ(10, v3->location_.x()); 2096 EXPECT_EQ(25, v3->location_.y()); 2097 2098 root->OnMouseReleased(released); 2099 2100 v1->SetTransform(gfx::Transform()); 2101 v2->SetTransform(gfx::Transform()); 2102 v3->SetTransform(gfx::Transform()); 2103 2104 v1->Reset(); 2105 v2->Reset(); 2106 v3->Reset(); 2107 2108 // Rotate |v3| clockwise with respect to |v2|, and scale it along both axis. 2109 transform = v3->GetTransform(); 2110 RotateClockwise(&transform); 2111 transform.matrix().set(0, 3, 30.f); 2112 // Rotation sets some scaling transformation. Using SetScale would overwrite 2113 // that and pollute the rotation. So combine the scaling with the existing 2114 // transforamtion. 2115 gfx::Transform scale; 2116 scale.Scale(0.8f, 0.5f); 2117 transform.ConcatTransform(scale); 2118 v3->SetTransform(transform); 2119 2120 // Translate |v2| with respect to |v1|. 2121 transform = v2->GetTransform(); 2122 transform.matrix().set(0, 3, 10.f); 2123 transform.matrix().set(1, 3, 10.f); 2124 v2->SetTransform(transform); 2125 2126 // |v3| now occupies (120, 120) to (144, 130) in |root|. 2127 2128 gfx::Point point3(124, 125); 2129 ui::MouseEvent p4(ui::ET_MOUSE_PRESSED, point3, point3, 2130 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON); 2131 root->OnMousePressed(p4); 2132 2133 EXPECT_EQ(ui::ET_MOUSE_PRESSED, v3->last_mouse_event_type_); 2134 EXPECT_EQ(10, v3->location_.x()); 2135 EXPECT_EQ(25, v3->location_.y()); 2136 2137 root->OnMouseReleased(released); 2138 2139 widget->CloseNow(); 2140 } 2141 2142 TEST_F(ViewTest, TransformVisibleBound) { 2143 gfx::Rect viewport_bounds(0, 0, 100, 100); 2144 2145 scoped_ptr<Widget> widget(new Widget); 2146 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 2147 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 2148 params.bounds = viewport_bounds; 2149 widget->Init(params); 2150 widget->GetRootView()->SetBoundsRect(viewport_bounds); 2151 2152 View* viewport = new View; 2153 widget->SetContentsView(viewport); 2154 View* contents = new View; 2155 viewport->AddChildView(contents); 2156 viewport->SetBoundsRect(viewport_bounds); 2157 contents->SetBoundsRect(gfx::Rect(0, 0, 100, 200)); 2158 2159 View* child = new View; 2160 contents->AddChildView(child); 2161 child->SetBoundsRect(gfx::Rect(10, 90, 50, 50)); 2162 EXPECT_EQ(gfx::Rect(0, 0, 50, 10), child->GetVisibleBounds()); 2163 2164 // Rotate |child| counter-clockwise 2165 gfx::Transform transform; 2166 RotateCounterclockwise(&transform); 2167 transform.matrix().set(1, 3, 50.f); 2168 child->SetTransform(transform); 2169 EXPECT_EQ(gfx::Rect(40, 0, 10, 50), child->GetVisibleBounds()); 2170 2171 widget->CloseNow(); 2172 } 2173 2174 //////////////////////////////////////////////////////////////////////////////// 2175 // OnVisibleBoundsChanged() 2176 2177 class VisibleBoundsView : public View { 2178 public: 2179 VisibleBoundsView() : received_notification_(false) {} 2180 virtual ~VisibleBoundsView() {} 2181 2182 bool received_notification() const { return received_notification_; } 2183 void set_received_notification(bool received) { 2184 received_notification_ = received; 2185 } 2186 2187 private: 2188 // Overridden from View: 2189 virtual bool NeedsNotificationWhenVisibleBoundsChange() const OVERRIDE { 2190 return true; 2191 } 2192 virtual void OnVisibleBoundsChanged() OVERRIDE { 2193 received_notification_ = true; 2194 } 2195 2196 bool received_notification_; 2197 2198 DISALLOW_COPY_AND_ASSIGN(VisibleBoundsView); 2199 }; 2200 2201 TEST_F(ViewTest, OnVisibleBoundsChanged) { 2202 gfx::Rect viewport_bounds(0, 0, 100, 100); 2203 2204 scoped_ptr<Widget> widget(new Widget); 2205 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 2206 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 2207 params.bounds = viewport_bounds; 2208 widget->Init(params); 2209 widget->GetRootView()->SetBoundsRect(viewport_bounds); 2210 2211 View* viewport = new View; 2212 widget->SetContentsView(viewport); 2213 View* contents = new View; 2214 viewport->AddChildView(contents); 2215 viewport->SetBoundsRect(viewport_bounds); 2216 contents->SetBoundsRect(gfx::Rect(0, 0, 100, 200)); 2217 2218 // Create a view that cares about visible bounds notifications, and position 2219 // it just outside the visible bounds of the viewport. 2220 VisibleBoundsView* child = new VisibleBoundsView; 2221 contents->AddChildView(child); 2222 child->SetBoundsRect(gfx::Rect(10, 110, 50, 50)); 2223 2224 // The child bound should be fully clipped. 2225 EXPECT_TRUE(child->GetVisibleBounds().IsEmpty()); 2226 2227 // Now scroll the contents, but not enough to make the child visible. 2228 contents->SetY(contents->y() - 1); 2229 2230 // We should have received the notification since the visible bounds may have 2231 // changed (even though they didn't). 2232 EXPECT_TRUE(child->received_notification()); 2233 EXPECT_TRUE(child->GetVisibleBounds().IsEmpty()); 2234 child->set_received_notification(false); 2235 2236 // Now scroll the contents, this time by enough to make the child visible by 2237 // one pixel. 2238 contents->SetY(contents->y() - 10); 2239 EXPECT_TRUE(child->received_notification()); 2240 EXPECT_EQ(1, child->GetVisibleBounds().height()); 2241 child->set_received_notification(false); 2242 2243 widget->CloseNow(); 2244 } 2245 2246 TEST_F(ViewTest, SetBoundsPaint) { 2247 TestView top_view; 2248 TestView* child_view = new TestView; 2249 2250 top_view.SetBoundsRect(gfx::Rect(0, 0, 100, 100)); 2251 top_view.scheduled_paint_rects_.clear(); 2252 child_view->SetBoundsRect(gfx::Rect(10, 10, 20, 20)); 2253 top_view.AddChildView(child_view); 2254 2255 top_view.scheduled_paint_rects_.clear(); 2256 child_view->SetBoundsRect(gfx::Rect(30, 30, 20, 20)); 2257 EXPECT_EQ(2U, top_view.scheduled_paint_rects_.size()); 2258 2259 // There should be 2 rects, spanning from (10, 10) to (50, 50). 2260 gfx::Rect paint_rect = top_view.scheduled_paint_rects_[0]; 2261 paint_rect.Union(top_view.scheduled_paint_rects_[1]); 2262 EXPECT_EQ(gfx::Rect(10, 10, 40, 40), paint_rect); 2263 } 2264 2265 // Assertions around painting and focus gain/lost. 2266 TEST_F(ViewTest, FocusBlurPaints) { 2267 TestView parent_view; 2268 TestView* child_view1 = new TestView; // Owned by |parent_view|. 2269 2270 parent_view.SetBoundsRect(gfx::Rect(0, 0, 100, 100)); 2271 2272 child_view1->SetBoundsRect(gfx::Rect(0, 0, 20, 20)); 2273 parent_view.AddChildView(child_view1); 2274 2275 parent_view.scheduled_paint_rects_.clear(); 2276 child_view1->scheduled_paint_rects_.clear(); 2277 2278 // Focus change shouldn't trigger paints. 2279 child_view1->DoFocus(); 2280 2281 EXPECT_TRUE(parent_view.scheduled_paint_rects_.empty()); 2282 EXPECT_TRUE(child_view1->scheduled_paint_rects_.empty()); 2283 2284 child_view1->DoBlur(); 2285 EXPECT_TRUE(parent_view.scheduled_paint_rects_.empty()); 2286 EXPECT_TRUE(child_view1->scheduled_paint_rects_.empty()); 2287 } 2288 2289 // Verifies SetBounds(same bounds) doesn't trigger a SchedulePaint(). 2290 TEST_F(ViewTest, SetBoundsSameBoundsDoesntSchedulePaint) { 2291 TestView view; 2292 2293 view.SetBoundsRect(gfx::Rect(0, 0, 100, 100)); 2294 view.InvalidateLayout(); 2295 view.scheduled_paint_rects_.clear(); 2296 view.SetBoundsRect(gfx::Rect(0, 0, 100, 100)); 2297 EXPECT_TRUE(view.scheduled_paint_rects_.empty()); 2298 } 2299 2300 // Verifies AddChildView() and RemoveChildView() schedule appropriate paints. 2301 TEST_F(ViewTest, AddAndRemoveSchedulePaints) { 2302 gfx::Rect viewport_bounds(0, 0, 100, 100); 2303 2304 // We have to put the View hierarchy into a Widget or no paints will be 2305 // scheduled. 2306 scoped_ptr<Widget> widget(new Widget); 2307 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 2308 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 2309 params.bounds = viewport_bounds; 2310 widget->Init(params); 2311 widget->GetRootView()->SetBoundsRect(viewport_bounds); 2312 2313 TestView* parent_view = new TestView; 2314 widget->SetContentsView(parent_view); 2315 parent_view->SetBoundsRect(viewport_bounds); 2316 parent_view->scheduled_paint_rects_.clear(); 2317 2318 View* child_view = new View; 2319 child_view->SetBoundsRect(gfx::Rect(0, 0, 20, 20)); 2320 parent_view->AddChildView(child_view); 2321 ASSERT_EQ(1U, parent_view->scheduled_paint_rects_.size()); 2322 EXPECT_EQ(child_view->bounds(), parent_view->scheduled_paint_rects_.front()); 2323 2324 parent_view->scheduled_paint_rects_.clear(); 2325 parent_view->RemoveChildView(child_view); 2326 scoped_ptr<View> child_deleter(child_view); 2327 ASSERT_EQ(1U, parent_view->scheduled_paint_rects_.size()); 2328 EXPECT_EQ(child_view->bounds(), parent_view->scheduled_paint_rects_.front()); 2329 2330 widget->CloseNow(); 2331 } 2332 2333 // Tests conversion methods with a transform. 2334 TEST_F(ViewTest, ConversionsWithTransform) { 2335 TestView top_view; 2336 2337 // View hierarchy used to test scale transforms. 2338 TestView* child = new TestView; 2339 TestView* child_child = new TestView; 2340 2341 // View used to test a rotation transform. 2342 TestView* child_2 = new TestView; 2343 2344 top_view.AddChildView(child); 2345 child->AddChildView(child_child); 2346 2347 top_view.SetBoundsRect(gfx::Rect(0, 0, 1000, 1000)); 2348 2349 child->SetBoundsRect(gfx::Rect(7, 19, 500, 500)); 2350 gfx::Transform transform; 2351 transform.Scale(3.0, 4.0); 2352 child->SetTransform(transform); 2353 2354 child_child->SetBoundsRect(gfx::Rect(17, 13, 100, 100)); 2355 transform.MakeIdentity(); 2356 transform.Scale(5.0, 7.0); 2357 child_child->SetTransform(transform); 2358 2359 top_view.AddChildView(child_2); 2360 child_2->SetBoundsRect(gfx::Rect(700, 725, 100, 100)); 2361 transform.MakeIdentity(); 2362 RotateClockwise(&transform); 2363 child_2->SetTransform(transform); 2364 2365 // Sanity check to make sure basic transforms act as expected. 2366 { 2367 gfx::Transform transform; 2368 transform.Translate(110.0, -110.0); 2369 transform.Scale(100.0, 55.0); 2370 transform.Translate(1.0, 1.0); 2371 2372 // convert to a 3x3 matrix. 2373 const SkMatrix& matrix = transform.matrix(); 2374 2375 EXPECT_EQ(210, matrix.getTranslateX()); 2376 EXPECT_EQ(-55, matrix.getTranslateY()); 2377 EXPECT_EQ(100, matrix.getScaleX()); 2378 EXPECT_EQ(55, matrix.getScaleY()); 2379 EXPECT_EQ(0, matrix.getSkewX()); 2380 EXPECT_EQ(0, matrix.getSkewY()); 2381 } 2382 2383 { 2384 gfx::Transform transform; 2385 transform.Translate(1.0, 1.0); 2386 gfx::Transform t2; 2387 t2.Scale(100.0, 55.0); 2388 gfx::Transform t3; 2389 t3.Translate(110.0, -110.0); 2390 transform.ConcatTransform(t2); 2391 transform.ConcatTransform(t3); 2392 2393 // convert to a 3x3 matrix 2394 const SkMatrix& matrix = transform.matrix(); 2395 2396 EXPECT_EQ(210, matrix.getTranslateX()); 2397 EXPECT_EQ(-55, matrix.getTranslateY()); 2398 EXPECT_EQ(100, matrix.getScaleX()); 2399 EXPECT_EQ(55, matrix.getScaleY()); 2400 EXPECT_EQ(0, matrix.getSkewX()); 2401 EXPECT_EQ(0, matrix.getSkewY()); 2402 } 2403 2404 // Conversions from child->top and top->child. 2405 { 2406 gfx::Point point(5, 5); 2407 View::ConvertPointToTarget(child, &top_view, &point); 2408 EXPECT_EQ(22, point.x()); 2409 EXPECT_EQ(39, point.y()); 2410 2411 gfx::RectF rect(5.0f, 5.0f, 10.0f, 20.0f); 2412 View::ConvertRectToTarget(child, &top_view, &rect); 2413 EXPECT_FLOAT_EQ(22.0f, rect.x()); 2414 EXPECT_FLOAT_EQ(39.0f, rect.y()); 2415 EXPECT_FLOAT_EQ(30.0f, rect.width()); 2416 EXPECT_FLOAT_EQ(80.0f, rect.height()); 2417 2418 point.SetPoint(22, 39); 2419 View::ConvertPointToTarget(&top_view, child, &point); 2420 EXPECT_EQ(5, point.x()); 2421 EXPECT_EQ(5, point.y()); 2422 2423 rect.SetRect(22.0f, 39.0f, 30.0f, 80.0f); 2424 View::ConvertRectToTarget(&top_view, child, &rect); 2425 EXPECT_FLOAT_EQ(5.0f, rect.x()); 2426 EXPECT_FLOAT_EQ(5.0f, rect.y()); 2427 EXPECT_FLOAT_EQ(10.0f, rect.width()); 2428 EXPECT_FLOAT_EQ(20.0f, rect.height()); 2429 } 2430 2431 // Conversions from child_child->top and top->child_child. 2432 { 2433 gfx::Point point(5, 5); 2434 View::ConvertPointToTarget(child_child, &top_view, &point); 2435 EXPECT_EQ(133, point.x()); 2436 EXPECT_EQ(211, point.y()); 2437 2438 gfx::RectF rect(5.0f, 5.0f, 10.0f, 20.0f); 2439 View::ConvertRectToTarget(child_child, &top_view, &rect); 2440 EXPECT_FLOAT_EQ(133.0f, rect.x()); 2441 EXPECT_FLOAT_EQ(211.0f, rect.y()); 2442 EXPECT_FLOAT_EQ(150.0f, rect.width()); 2443 EXPECT_FLOAT_EQ(560.0f, rect.height()); 2444 2445 point.SetPoint(133, 211); 2446 View::ConvertPointToTarget(&top_view, child_child, &point); 2447 EXPECT_EQ(5, point.x()); 2448 EXPECT_EQ(5, point.y()); 2449 2450 rect.SetRect(133.0f, 211.0f, 150.0f, 560.0f); 2451 View::ConvertRectToTarget(&top_view, child_child, &rect); 2452 EXPECT_FLOAT_EQ(5.0f, rect.x()); 2453 EXPECT_FLOAT_EQ(5.0f, rect.y()); 2454 EXPECT_FLOAT_EQ(10.0f, rect.width()); 2455 EXPECT_FLOAT_EQ(20.0f, rect.height()); 2456 } 2457 2458 // Conversions from child_child->child and child->child_child 2459 { 2460 gfx::Point point(5, 5); 2461 View::ConvertPointToTarget(child_child, child, &point); 2462 EXPECT_EQ(42, point.x()); 2463 EXPECT_EQ(48, point.y()); 2464 2465 gfx::RectF rect(5.0f, 5.0f, 10.0f, 20.0f); 2466 View::ConvertRectToTarget(child_child, child, &rect); 2467 EXPECT_FLOAT_EQ(42.0f, rect.x()); 2468 EXPECT_FLOAT_EQ(48.0f, rect.y()); 2469 EXPECT_FLOAT_EQ(50.0f, rect.width()); 2470 EXPECT_FLOAT_EQ(140.0f, rect.height()); 2471 2472 point.SetPoint(42, 48); 2473 View::ConvertPointToTarget(child, child_child, &point); 2474 EXPECT_EQ(5, point.x()); 2475 EXPECT_EQ(5, point.y()); 2476 2477 rect.SetRect(42.0f, 48.0f, 50.0f, 140.0f); 2478 View::ConvertRectToTarget(child, child_child, &rect); 2479 EXPECT_FLOAT_EQ(5.0f, rect.x()); 2480 EXPECT_FLOAT_EQ(5.0f, rect.y()); 2481 EXPECT_FLOAT_EQ(10.0f, rect.width()); 2482 EXPECT_FLOAT_EQ(20.0f, rect.height()); 2483 } 2484 2485 // Conversions from top_view to child with a value that should be negative. 2486 // This ensures we don't round up with negative numbers. 2487 { 2488 gfx::Point point(6, 18); 2489 View::ConvertPointToTarget(&top_view, child, &point); 2490 EXPECT_EQ(-1, point.x()); 2491 EXPECT_EQ(-1, point.y()); 2492 2493 float error = 0.01f; 2494 gfx::RectF rect(6.0f, 18.0f, 10.0f, 39.0f); 2495 View::ConvertRectToTarget(&top_view, child, &rect); 2496 EXPECT_NEAR(-0.33f, rect.x(), error); 2497 EXPECT_NEAR(-0.25f, rect.y(), error); 2498 EXPECT_NEAR(3.33f, rect.width(), error); 2499 EXPECT_NEAR(9.75f, rect.height(), error); 2500 } 2501 2502 // Rect conversions from top_view->child_2 and child_2->top_view. 2503 { 2504 gfx::RectF rect(50.0f, 55.0f, 20.0f, 30.0f); 2505 View::ConvertRectToTarget(child_2, &top_view, &rect); 2506 EXPECT_FLOAT_EQ(615.0f, rect.x()); 2507 EXPECT_FLOAT_EQ(775.0f, rect.y()); 2508 EXPECT_FLOAT_EQ(30.0f, rect.width()); 2509 EXPECT_FLOAT_EQ(20.0f, rect.height()); 2510 2511 rect.SetRect(615.0f, 775.0f, 30.0f, 20.0f); 2512 View::ConvertRectToTarget(&top_view, child_2, &rect); 2513 EXPECT_FLOAT_EQ(50.0f, rect.x()); 2514 EXPECT_FLOAT_EQ(55.0f, rect.y()); 2515 EXPECT_FLOAT_EQ(20.0f, rect.width()); 2516 EXPECT_FLOAT_EQ(30.0f, rect.height()); 2517 } 2518 } 2519 2520 // Tests conversion methods to and from screen coordinates. 2521 TEST_F(ViewTest, ConversionsToFromScreen) { 2522 scoped_ptr<Widget> widget(new Widget); 2523 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 2524 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 2525 params.bounds = gfx::Rect(50, 50, 650, 650); 2526 widget->Init(params); 2527 2528 View* child = new View; 2529 widget->GetRootView()->AddChildView(child); 2530 child->SetBounds(10, 10, 100, 200); 2531 gfx::Transform t; 2532 t.Scale(0.5, 0.5); 2533 child->SetTransform(t); 2534 2535 gfx::Point point_in_screen(100, 90); 2536 gfx::Point point_in_child(80,60); 2537 2538 gfx::Point point = point_in_screen; 2539 View::ConvertPointFromScreen(child, &point); 2540 EXPECT_EQ(point_in_child.ToString(), point.ToString()); 2541 2542 View::ConvertPointToScreen(child, &point); 2543 EXPECT_EQ(point_in_screen.ToString(), point.ToString()); 2544 } 2545 2546 // Tests conversion methods for rectangles. 2547 TEST_F(ViewTest, ConvertRectWithTransform) { 2548 scoped_ptr<Widget> widget(new Widget); 2549 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 2550 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 2551 params.bounds = gfx::Rect(50, 50, 650, 650); 2552 widget->Init(params); 2553 View* root = widget->GetRootView(); 2554 2555 TestView* v1 = new TestView; 2556 TestView* v2 = new TestView; 2557 root->AddChildView(v1); 2558 v1->AddChildView(v2); 2559 2560 v1->SetBoundsRect(gfx::Rect(10, 10, 500, 500)); 2561 v2->SetBoundsRect(gfx::Rect(20, 20, 100, 200)); 2562 2563 // |v2| now occupies (30, 30) to (130, 230) in |widget| 2564 gfx::Rect rect(5, 5, 15, 40); 2565 EXPECT_EQ(gfx::Rect(25, 25, 15, 40), v2->ConvertRectToParent(rect)); 2566 EXPECT_EQ(gfx::Rect(35, 35, 15, 40), v2->ConvertRectToWidget(rect)); 2567 2568 // Rotate |v2| 2569 gfx::Transform t2; 2570 RotateCounterclockwise(&t2); 2571 t2.matrix().set(1, 3, 100.f); 2572 v2->SetTransform(t2); 2573 2574 // |v2| now occupies (30, 30) to (230, 130) in |widget| 2575 EXPECT_EQ(gfx::Rect(25, 100, 40, 15), v2->ConvertRectToParent(rect)); 2576 EXPECT_EQ(gfx::Rect(35, 110, 40, 15), v2->ConvertRectToWidget(rect)); 2577 2578 // Scale down |v1| 2579 gfx::Transform t1; 2580 t1.Scale(0.5, 0.5); 2581 v1->SetTransform(t1); 2582 2583 // The rectangle should remain the same for |v1|. 2584 EXPECT_EQ(gfx::Rect(25, 100, 40, 15), v2->ConvertRectToParent(rect)); 2585 2586 // |v2| now occupies (20, 20) to (120, 70) in |widget| 2587 EXPECT_EQ(gfx::Rect(22, 60, 21, 8).ToString(), 2588 v2->ConvertRectToWidget(rect).ToString()); 2589 2590 widget->CloseNow(); 2591 } 2592 2593 class ObserverView : public View { 2594 public: 2595 ObserverView(); 2596 virtual ~ObserverView(); 2597 2598 void ResetTestState(); 2599 2600 bool has_add_details() const { return has_add_details_; } 2601 bool has_remove_details() const { return has_remove_details_; } 2602 2603 const ViewHierarchyChangedDetails& add_details() const { 2604 return add_details_; 2605 } 2606 2607 const ViewHierarchyChangedDetails& remove_details() const { 2608 return remove_details_; 2609 } 2610 2611 private: 2612 // View: 2613 virtual void ViewHierarchyChanged( 2614 const ViewHierarchyChangedDetails& details) OVERRIDE; 2615 2616 bool has_add_details_; 2617 bool has_remove_details_; 2618 ViewHierarchyChangedDetails add_details_; 2619 ViewHierarchyChangedDetails remove_details_; 2620 2621 DISALLOW_COPY_AND_ASSIGN(ObserverView); 2622 }; 2623 2624 ObserverView::ObserverView() 2625 : has_add_details_(false), 2626 has_remove_details_(false) { 2627 } 2628 2629 ObserverView::~ObserverView() {} 2630 2631 void ObserverView::ResetTestState() { 2632 has_add_details_ = false; 2633 has_remove_details_ = false; 2634 add_details_ = ViewHierarchyChangedDetails(); 2635 remove_details_ = ViewHierarchyChangedDetails(); 2636 } 2637 2638 void ObserverView::ViewHierarchyChanged( 2639 const ViewHierarchyChangedDetails& details) { 2640 if (details.is_add) { 2641 has_add_details_ = true; 2642 add_details_ = details; 2643 } else { 2644 has_remove_details_ = true; 2645 remove_details_ = details; 2646 } 2647 } 2648 2649 // Verifies that the ViewHierarchyChanged() notification is sent correctly when 2650 // a child view is added or removed to all the views in the hierarchy (up and 2651 // down). 2652 // The tree looks like this: 2653 // v1 2654 // +-- v2 2655 // +-- v3 2656 // +-- v4 (starts here, then get reparented to v1) 2657 TEST_F(ViewTest, ViewHierarchyChanged) { 2658 ObserverView v1; 2659 2660 ObserverView* v3 = new ObserverView(); 2661 2662 // Add |v3| to |v2|. 2663 scoped_ptr<ObserverView> v2(new ObserverView()); 2664 v2->AddChildView(v3); 2665 2666 // Make sure both |v2| and |v3| receive the ViewHierarchyChanged() 2667 // notification. 2668 EXPECT_TRUE(v2->has_add_details()); 2669 EXPECT_FALSE(v2->has_remove_details()); 2670 EXPECT_EQ(v2.get(), v2->add_details().parent); 2671 EXPECT_EQ(v3, v2->add_details().child); 2672 EXPECT_EQ(NULL, v2->add_details().move_view); 2673 2674 EXPECT_TRUE(v3->has_add_details()); 2675 EXPECT_FALSE(v3->has_remove_details()); 2676 EXPECT_EQ(v2.get(), v3->add_details().parent); 2677 EXPECT_EQ(v3, v3->add_details().child); 2678 EXPECT_EQ(NULL, v3->add_details().move_view); 2679 2680 // Reset everything to the initial state. 2681 v2->ResetTestState(); 2682 v3->ResetTestState(); 2683 2684 // Add |v2| to v1. 2685 v1.AddChildView(v2.get()); 2686 2687 // Verifies that |v2| is the child view *added* and the parent view is |v1|. 2688 // Make sure all the views (v1, v2, v3) received _that_ information. 2689 EXPECT_TRUE(v1.has_add_details()); 2690 EXPECT_FALSE(v1.has_remove_details()); 2691 EXPECT_EQ(&v1, v1.add_details().parent); 2692 EXPECT_EQ(v2.get(), v1.add_details().child); 2693 EXPECT_EQ(NULL, v1.add_details().move_view); 2694 2695 EXPECT_TRUE(v2->has_add_details()); 2696 EXPECT_FALSE(v2->has_remove_details()); 2697 EXPECT_EQ(&v1, v2->add_details().parent); 2698 EXPECT_EQ(v2.get(), v2->add_details().child); 2699 EXPECT_EQ(NULL, v2->add_details().move_view); 2700 2701 EXPECT_TRUE(v3->has_add_details()); 2702 EXPECT_FALSE(v3->has_remove_details()); 2703 EXPECT_EQ(&v1, v3->add_details().parent); 2704 EXPECT_EQ(v2.get(), v3->add_details().child); 2705 EXPECT_EQ(NULL, v3->add_details().move_view); 2706 2707 // Reset everything to the initial state. 2708 v1.ResetTestState(); 2709 v2->ResetTestState(); 2710 v3->ResetTestState(); 2711 2712 // Remove |v2| from |v1|. 2713 v1.RemoveChildView(v2.get()); 2714 2715 // Verifies that |v2| is the child view *removed* and the parent view is |v1|. 2716 // Make sure all the views (v1, v2, v3) received _that_ information. 2717 EXPECT_FALSE(v1.has_add_details()); 2718 EXPECT_TRUE(v1.has_remove_details()); 2719 EXPECT_EQ(&v1, v1.remove_details().parent); 2720 EXPECT_EQ(v2.get(), v1.remove_details().child); 2721 EXPECT_EQ(NULL, v1.remove_details().move_view); 2722 2723 EXPECT_FALSE(v2->has_add_details()); 2724 EXPECT_TRUE(v2->has_remove_details()); 2725 EXPECT_EQ(&v1, v2->remove_details().parent); 2726 EXPECT_EQ(v2.get(), v2->remove_details().child); 2727 EXPECT_EQ(NULL, v2->remove_details().move_view); 2728 2729 EXPECT_FALSE(v3->has_add_details()); 2730 EXPECT_TRUE(v3->has_remove_details()); 2731 EXPECT_EQ(&v1, v3->remove_details().parent); 2732 EXPECT_EQ(v3, v3->remove_details().child); 2733 EXPECT_EQ(NULL, v3->remove_details().move_view); 2734 2735 // Verifies notifications when reparenting a view. 2736 ObserverView* v4 = new ObserverView(); 2737 // Add |v4| to |v2|. 2738 v2->AddChildView(v4); 2739 2740 // Reset everything to the initial state. 2741 v1.ResetTestState(); 2742 v2->ResetTestState(); 2743 v3->ResetTestState(); 2744 v4->ResetTestState(); 2745 2746 // Reparent |v4| to |v1|. 2747 v1.AddChildView(v4); 2748 2749 // Verifies that all views receive the correct information for all the child, 2750 // parent and move views. 2751 2752 // |v1| is the new parent, |v4| is the child for add, |v2| is the old parent. 2753 EXPECT_TRUE(v1.has_add_details()); 2754 EXPECT_FALSE(v1.has_remove_details()); 2755 EXPECT_EQ(&v1, v1.add_details().parent); 2756 EXPECT_EQ(v4, v1.add_details().child); 2757 EXPECT_EQ(v2.get(), v1.add_details().move_view); 2758 2759 // |v2| is the old parent, |v4| is the child for remove, |v1| is the new 2760 // parent. 2761 EXPECT_FALSE(v2->has_add_details()); 2762 EXPECT_TRUE(v2->has_remove_details()); 2763 EXPECT_EQ(v2.get(), v2->remove_details().parent); 2764 EXPECT_EQ(v4, v2->remove_details().child); 2765 EXPECT_EQ(&v1, v2->remove_details().move_view); 2766 2767 // |v3| is not impacted by this operation, and hence receives no notification. 2768 EXPECT_FALSE(v3->has_add_details()); 2769 EXPECT_FALSE(v3->has_remove_details()); 2770 2771 // |v4| is the reparented child, so it receives notifications for the remove 2772 // and then the add. |v2| is its old parent, |v1| is its new parent. 2773 EXPECT_TRUE(v4->has_remove_details()); 2774 EXPECT_TRUE(v4->has_add_details()); 2775 EXPECT_EQ(v2.get(), v4->remove_details().parent); 2776 EXPECT_EQ(&v1, v4->add_details().parent); 2777 EXPECT_EQ(v4, v4->add_details().child); 2778 EXPECT_EQ(v4, v4->remove_details().child); 2779 EXPECT_EQ(&v1, v4->remove_details().move_view); 2780 EXPECT_EQ(v2.get(), v4->add_details().move_view); 2781 } 2782 2783 // Verifies if the child views added under the root are all deleted when calling 2784 // RemoveAllChildViews. 2785 // The tree looks like this: 2786 // root 2787 // +-- child1 2788 // +-- foo 2789 // +-- bar0 2790 // +-- bar1 2791 // +-- bar2 2792 // +-- child2 2793 // +-- child3 2794 TEST_F(ViewTest, RemoveAllChildViews) { 2795 View root; 2796 2797 View* child1 = new View; 2798 root.AddChildView(child1); 2799 2800 for (int i = 0; i < 2; ++i) 2801 root.AddChildView(new View); 2802 2803 View* foo = new View; 2804 child1->AddChildView(foo); 2805 2806 // Add some nodes to |foo|. 2807 for (int i = 0; i < 3; ++i) 2808 foo->AddChildView(new View); 2809 2810 EXPECT_EQ(3, root.child_count()); 2811 EXPECT_EQ(1, child1->child_count()); 2812 EXPECT_EQ(3, foo->child_count()); 2813 2814 // Now remove all child views from root. 2815 root.RemoveAllChildViews(true); 2816 2817 EXPECT_EQ(0, root.child_count()); 2818 EXPECT_FALSE(root.has_children()); 2819 } 2820 2821 TEST_F(ViewTest, Contains) { 2822 View v1; 2823 View* v2 = new View; 2824 View* v3 = new View; 2825 2826 v1.AddChildView(v2); 2827 v2->AddChildView(v3); 2828 2829 EXPECT_FALSE(v1.Contains(NULL)); 2830 EXPECT_TRUE(v1.Contains(&v1)); 2831 EXPECT_TRUE(v1.Contains(v2)); 2832 EXPECT_TRUE(v1.Contains(v3)); 2833 2834 EXPECT_FALSE(v2->Contains(NULL)); 2835 EXPECT_TRUE(v2->Contains(v2)); 2836 EXPECT_FALSE(v2->Contains(&v1)); 2837 EXPECT_TRUE(v2->Contains(v3)); 2838 2839 EXPECT_FALSE(v3->Contains(NULL)); 2840 EXPECT_TRUE(v3->Contains(v3)); 2841 EXPECT_FALSE(v3->Contains(&v1)); 2842 EXPECT_FALSE(v3->Contains(v2)); 2843 } 2844 2845 // Verifies if GetIndexOf() returns the correct index for the specified child 2846 // view. 2847 // The tree looks like this: 2848 // root 2849 // +-- child1 2850 // +-- foo1 2851 // +-- child2 2852 TEST_F(ViewTest, GetIndexOf) { 2853 View root; 2854 2855 View* child1 = new View; 2856 root.AddChildView(child1); 2857 2858 View* child2 = new View; 2859 root.AddChildView(child2); 2860 2861 View* foo1 = new View; 2862 child1->AddChildView(foo1); 2863 2864 EXPECT_EQ(-1, root.GetIndexOf(NULL)); 2865 EXPECT_EQ(-1, root.GetIndexOf(&root)); 2866 EXPECT_EQ(0, root.GetIndexOf(child1)); 2867 EXPECT_EQ(1, root.GetIndexOf(child2)); 2868 EXPECT_EQ(-1, root.GetIndexOf(foo1)); 2869 2870 EXPECT_EQ(-1, child1->GetIndexOf(NULL)); 2871 EXPECT_EQ(-1, child1->GetIndexOf(&root)); 2872 EXPECT_EQ(-1, child1->GetIndexOf(child1)); 2873 EXPECT_EQ(-1, child1->GetIndexOf(child2)); 2874 EXPECT_EQ(0, child1->GetIndexOf(foo1)); 2875 2876 EXPECT_EQ(-1, child2->GetIndexOf(NULL)); 2877 EXPECT_EQ(-1, child2->GetIndexOf(&root)); 2878 EXPECT_EQ(-1, child2->GetIndexOf(child2)); 2879 EXPECT_EQ(-1, child2->GetIndexOf(child1)); 2880 EXPECT_EQ(-1, child2->GetIndexOf(foo1)); 2881 } 2882 2883 // Verifies that the child views can be reordered correctly. 2884 TEST_F(ViewTest, ReorderChildren) { 2885 View root; 2886 2887 View* child = new View(); 2888 root.AddChildView(child); 2889 2890 View* foo1 = new View(); 2891 child->AddChildView(foo1); 2892 View* foo2 = new View(); 2893 child->AddChildView(foo2); 2894 View* foo3 = new View(); 2895 child->AddChildView(foo3); 2896 foo1->SetFocusable(true); 2897 foo2->SetFocusable(true); 2898 foo3->SetFocusable(true); 2899 2900 ASSERT_EQ(0, child->GetIndexOf(foo1)); 2901 ASSERT_EQ(1, child->GetIndexOf(foo2)); 2902 ASSERT_EQ(2, child->GetIndexOf(foo3)); 2903 ASSERT_EQ(foo2, foo1->GetNextFocusableView()); 2904 ASSERT_EQ(foo3, foo2->GetNextFocusableView()); 2905 ASSERT_EQ(NULL, foo3->GetNextFocusableView()); 2906 2907 // Move |foo2| at the end. 2908 child->ReorderChildView(foo2, -1); 2909 ASSERT_EQ(0, child->GetIndexOf(foo1)); 2910 ASSERT_EQ(1, child->GetIndexOf(foo3)); 2911 ASSERT_EQ(2, child->GetIndexOf(foo2)); 2912 ASSERT_EQ(foo3, foo1->GetNextFocusableView()); 2913 ASSERT_EQ(foo2, foo3->GetNextFocusableView()); 2914 ASSERT_EQ(NULL, foo2->GetNextFocusableView()); 2915 2916 // Move |foo1| at the end. 2917 child->ReorderChildView(foo1, -1); 2918 ASSERT_EQ(0, child->GetIndexOf(foo3)); 2919 ASSERT_EQ(1, child->GetIndexOf(foo2)); 2920 ASSERT_EQ(2, child->GetIndexOf(foo1)); 2921 ASSERT_EQ(NULL, foo1->GetNextFocusableView()); 2922 ASSERT_EQ(foo2, foo1->GetPreviousFocusableView()); 2923 ASSERT_EQ(foo2, foo3->GetNextFocusableView()); 2924 ASSERT_EQ(foo1, foo2->GetNextFocusableView()); 2925 2926 // Move |foo2| to the front. 2927 child->ReorderChildView(foo2, 0); 2928 ASSERT_EQ(0, child->GetIndexOf(foo2)); 2929 ASSERT_EQ(1, child->GetIndexOf(foo3)); 2930 ASSERT_EQ(2, child->GetIndexOf(foo1)); 2931 ASSERT_EQ(NULL, foo1->GetNextFocusableView()); 2932 ASSERT_EQ(foo3, foo1->GetPreviousFocusableView()); 2933 ASSERT_EQ(foo3, foo2->GetNextFocusableView()); 2934 ASSERT_EQ(foo1, foo3->GetNextFocusableView()); 2935 } 2936 2937 // Verifies that GetViewByID returns the correctly child view from the specified 2938 // ID. 2939 // The tree looks like this: 2940 // v1 2941 // +-- v2 2942 // +-- v3 2943 // +-- v4 2944 TEST_F(ViewTest, GetViewByID) { 2945 View v1; 2946 const int kV1ID = 1; 2947 v1.set_id(kV1ID); 2948 2949 View v2; 2950 const int kV2ID = 2; 2951 v2.set_id(kV2ID); 2952 2953 View v3; 2954 const int kV3ID = 3; 2955 v3.set_id(kV3ID); 2956 2957 View v4; 2958 const int kV4ID = 4; 2959 v4.set_id(kV4ID); 2960 2961 const int kV5ID = 5; 2962 2963 v1.AddChildView(&v2); 2964 v2.AddChildView(&v3); 2965 v2.AddChildView(&v4); 2966 2967 EXPECT_EQ(&v1, v1.GetViewByID(kV1ID)); 2968 EXPECT_EQ(&v2, v1.GetViewByID(kV2ID)); 2969 EXPECT_EQ(&v4, v1.GetViewByID(kV4ID)); 2970 2971 EXPECT_EQ(NULL, v1.GetViewByID(kV5ID)); // No V5 exists. 2972 EXPECT_EQ(NULL, v2.GetViewByID(kV1ID)); // It can get only from child views. 2973 2974 const int kGroup = 1; 2975 v3.SetGroup(kGroup); 2976 v4.SetGroup(kGroup); 2977 2978 View::Views views; 2979 v1.GetViewsInGroup(kGroup, &views); 2980 EXPECT_EQ(2U, views.size()); 2981 2982 View::Views::const_iterator i(std::find(views.begin(), views.end(), &v3)); 2983 EXPECT_NE(views.end(), i); 2984 2985 i = std::find(views.begin(), views.end(), &v4); 2986 EXPECT_NE(views.end(), i); 2987 } 2988 2989 TEST_F(ViewTest, AddExistingChild) { 2990 View v1, v2, v3; 2991 2992 v1.AddChildView(&v2); 2993 v1.AddChildView(&v3); 2994 EXPECT_EQ(0, v1.GetIndexOf(&v2)); 2995 EXPECT_EQ(1, v1.GetIndexOf(&v3)); 2996 2997 // Check that there's no change in order when adding at same index. 2998 v1.AddChildViewAt(&v2, 0); 2999 EXPECT_EQ(0, v1.GetIndexOf(&v2)); 3000 EXPECT_EQ(1, v1.GetIndexOf(&v3)); 3001 v1.AddChildViewAt(&v3, 1); 3002 EXPECT_EQ(0, v1.GetIndexOf(&v2)); 3003 EXPECT_EQ(1, v1.GetIndexOf(&v3)); 3004 3005 // Add it at a different index and check for change in order. 3006 v1.AddChildViewAt(&v2, 1); 3007 EXPECT_EQ(1, v1.GetIndexOf(&v2)); 3008 EXPECT_EQ(0, v1.GetIndexOf(&v3)); 3009 v1.AddChildViewAt(&v2, 0); 3010 EXPECT_EQ(0, v1.GetIndexOf(&v2)); 3011 EXPECT_EQ(1, v1.GetIndexOf(&v3)); 3012 3013 // Check that calling |AddChildView()| does not change the order. 3014 v1.AddChildView(&v2); 3015 EXPECT_EQ(0, v1.GetIndexOf(&v2)); 3016 EXPECT_EQ(1, v1.GetIndexOf(&v3)); 3017 v1.AddChildView(&v3); 3018 EXPECT_EQ(0, v1.GetIndexOf(&v2)); 3019 EXPECT_EQ(1, v1.GetIndexOf(&v3)); 3020 } 3021 3022 //////////////////////////////////////////////////////////////////////////////// 3023 // Layers 3024 //////////////////////////////////////////////////////////////////////////////// 3025 3026 namespace { 3027 3028 // Test implementation of LayerAnimator. 3029 class TestLayerAnimator : public ui::LayerAnimator { 3030 public: 3031 TestLayerAnimator(); 3032 3033 const gfx::Rect& last_bounds() const { return last_bounds_; } 3034 3035 // LayerAnimator. 3036 virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE; 3037 3038 protected: 3039 virtual ~TestLayerAnimator() { } 3040 3041 private: 3042 gfx::Rect last_bounds_; 3043 3044 DISALLOW_COPY_AND_ASSIGN(TestLayerAnimator); 3045 }; 3046 3047 TestLayerAnimator::TestLayerAnimator() 3048 : ui::LayerAnimator(base::TimeDelta::FromMilliseconds(0)) { 3049 } 3050 3051 void TestLayerAnimator::SetBounds(const gfx::Rect& bounds) { 3052 last_bounds_ = bounds; 3053 } 3054 3055 } // namespace 3056 3057 class ViewLayerTest : public ViewsTestBase { 3058 public: 3059 ViewLayerTest() : widget_(NULL) {} 3060 3061 virtual ~ViewLayerTest() { 3062 } 3063 3064 // Returns the Layer used by the RootView. 3065 ui::Layer* GetRootLayer() { 3066 return widget()->GetLayer(); 3067 } 3068 3069 virtual void SetUp() OVERRIDE { 3070 ViewTest::SetUp(); 3071 widget_ = new Widget; 3072 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 3073 params.bounds = gfx::Rect(50, 50, 200, 200); 3074 widget_->Init(params); 3075 widget_->Show(); 3076 widget_->GetRootView()->SetBounds(0, 0, 200, 200); 3077 } 3078 3079 virtual void TearDown() OVERRIDE { 3080 widget_->CloseNow(); 3081 ViewsTestBase::TearDown(); 3082 } 3083 3084 Widget* widget() { return widget_; } 3085 3086 private: 3087 Widget* widget_; 3088 }; 3089 3090 3091 TEST_F(ViewLayerTest, LayerToggling) { 3092 // Because we lazily create textures the calls to DrawTree are necessary to 3093 // ensure we trigger creation of textures. 3094 ui::Layer* root_layer = widget()->GetLayer(); 3095 View* content_view = new View; 3096 widget()->SetContentsView(content_view); 3097 3098 // Create v1, give it a bounds and verify everything is set up correctly. 3099 View* v1 = new View; 3100 v1->SetPaintToLayer(true); 3101 EXPECT_TRUE(v1->layer() != NULL); 3102 v1->SetBoundsRect(gfx::Rect(20, 30, 140, 150)); 3103 content_view->AddChildView(v1); 3104 ASSERT_TRUE(v1->layer() != NULL); 3105 EXPECT_EQ(root_layer, v1->layer()->parent()); 3106 EXPECT_EQ(gfx::Rect(20, 30, 140, 150), v1->layer()->bounds()); 3107 3108 // Create v2 as a child of v1 and do basic assertion testing. 3109 View* v2 = new View; 3110 v1->AddChildView(v2); 3111 EXPECT_TRUE(v2->layer() == NULL); 3112 v2->SetBoundsRect(gfx::Rect(10, 20, 30, 40)); 3113 v2->SetPaintToLayer(true); 3114 ASSERT_TRUE(v2->layer() != NULL); 3115 EXPECT_EQ(v1->layer(), v2->layer()->parent()); 3116 EXPECT_EQ(gfx::Rect(10, 20, 30, 40), v2->layer()->bounds()); 3117 3118 // Turn off v1s layer. v2 should still have a layer but its parent should have 3119 // changed. 3120 v1->SetPaintToLayer(false); 3121 EXPECT_TRUE(v1->layer() == NULL); 3122 EXPECT_TRUE(v2->layer() != NULL); 3123 EXPECT_EQ(root_layer, v2->layer()->parent()); 3124 ASSERT_EQ(1u, root_layer->children().size()); 3125 EXPECT_EQ(root_layer->children()[0], v2->layer()); 3126 // The bounds of the layer should have changed to be relative to the root view 3127 // now. 3128 EXPECT_EQ(gfx::Rect(30, 50, 30, 40), v2->layer()->bounds()); 3129 3130 // Make v1 have a layer again and verify v2s layer is wired up correctly. 3131 gfx::Transform transform; 3132 transform.Scale(2.0, 2.0); 3133 v1->SetTransform(transform); 3134 EXPECT_TRUE(v1->layer() != NULL); 3135 EXPECT_TRUE(v2->layer() != NULL); 3136 EXPECT_EQ(root_layer, v1->layer()->parent()); 3137 EXPECT_EQ(v1->layer(), v2->layer()->parent()); 3138 ASSERT_EQ(1u, root_layer->children().size()); 3139 EXPECT_EQ(root_layer->children()[0], v1->layer()); 3140 ASSERT_EQ(1u, v1->layer()->children().size()); 3141 EXPECT_EQ(v1->layer()->children()[0], v2->layer()); 3142 EXPECT_EQ(gfx::Rect(10, 20, 30, 40), v2->layer()->bounds()); 3143 } 3144 3145 // Verifies turning on a layer wires up children correctly. 3146 TEST_F(ViewLayerTest, NestedLayerToggling) { 3147 View* content_view = new View; 3148 widget()->SetContentsView(content_view); 3149 3150 // Create v1, give it a bounds and verify everything is set up correctly. 3151 View* v1 = new View; 3152 content_view->AddChildView(v1); 3153 v1->SetBoundsRect(gfx::Rect(20, 30, 140, 150)); 3154 3155 View* v2 = new View; 3156 v1->AddChildView(v2); 3157 3158 View* v3 = new View; 3159 v3->SetPaintToLayer(true); 3160 v2->AddChildView(v3); 3161 ASSERT_TRUE(v3->layer() != NULL); 3162 3163 // At this point we have v1-v2-v3. v3 has a layer, v1 and v2 don't. 3164 3165 v1->SetPaintToLayer(true); 3166 EXPECT_EQ(v1->layer(), v3->layer()->parent()); 3167 } 3168 3169 TEST_F(ViewLayerTest, LayerAnimator) { 3170 View* content_view = new View; 3171 widget()->SetContentsView(content_view); 3172 3173 View* v1 = new View; 3174 content_view->AddChildView(v1); 3175 v1->SetPaintToLayer(true); 3176 EXPECT_TRUE(v1->layer() != NULL); 3177 3178 TestLayerAnimator* animator = new TestLayerAnimator(); 3179 v1->layer()->SetAnimator(animator); 3180 3181 gfx::Rect bounds(1, 2, 3, 4); 3182 v1->SetBoundsRect(bounds); 3183 EXPECT_EQ(bounds, animator->last_bounds()); 3184 // TestLayerAnimator doesn't update the layer. 3185 EXPECT_NE(bounds, v1->layer()->bounds()); 3186 } 3187 3188 // Verifies the bounds of a layer are updated if the bounds of ancestor that 3189 // doesn't have a layer change. 3190 TEST_F(ViewLayerTest, BoundsChangeWithLayer) { 3191 View* content_view = new View; 3192 widget()->SetContentsView(content_view); 3193 3194 View* v1 = new View; 3195 content_view->AddChildView(v1); 3196 v1->SetBoundsRect(gfx::Rect(20, 30, 140, 150)); 3197 3198 View* v2 = new View; 3199 v2->SetBoundsRect(gfx::Rect(10, 11, 40, 50)); 3200 v1->AddChildView(v2); 3201 v2->SetPaintToLayer(true); 3202 ASSERT_TRUE(v2->layer() != NULL); 3203 EXPECT_EQ(gfx::Rect(30, 41, 40, 50), v2->layer()->bounds()); 3204 3205 v1->SetPosition(gfx::Point(25, 36)); 3206 EXPECT_EQ(gfx::Rect(35, 47, 40, 50), v2->layer()->bounds()); 3207 3208 v2->SetPosition(gfx::Point(11, 12)); 3209 EXPECT_EQ(gfx::Rect(36, 48, 40, 50), v2->layer()->bounds()); 3210 3211 // Bounds of the layer should change even if the view is not invisible. 3212 v1->SetVisible(false); 3213 v1->SetPosition(gfx::Point(20, 30)); 3214 EXPECT_EQ(gfx::Rect(31, 42, 40, 50), v2->layer()->bounds()); 3215 3216 v2->SetVisible(false); 3217 v2->SetBoundsRect(gfx::Rect(10, 11, 20, 30)); 3218 EXPECT_EQ(gfx::Rect(30, 41, 20, 30), v2->layer()->bounds()); 3219 } 3220 3221 // Make sure layers are positioned correctly in RTL. 3222 TEST_F(ViewLayerTest, BoundInRTL) { 3223 std::string locale = l10n_util::GetApplicationLocale(std::string()); 3224 base::i18n::SetICUDefaultLocale("he"); 3225 3226 View* view = new View; 3227 widget()->SetContentsView(view); 3228 3229 int content_width = view->width(); 3230 3231 // |v1| is initially not attached to anything. So its layer will have the same 3232 // bounds as the view. 3233 View* v1 = new View; 3234 v1->SetPaintToLayer(true); 3235 v1->SetBounds(10, 10, 20, 10); 3236 EXPECT_EQ(gfx::Rect(10, 10, 20, 10), 3237 v1->layer()->bounds()); 3238 3239 // Once |v1| is attached to the widget, its layer will get RTL-appropriate 3240 // bounds. 3241 view->AddChildView(v1); 3242 EXPECT_EQ(gfx::Rect(content_width - 30, 10, 20, 10), 3243 v1->layer()->bounds()); 3244 gfx::Rect l1bounds = v1->layer()->bounds(); 3245 3246 // Now attach a View to the widget first, then create a layer for it. Make 3247 // sure the bounds are correct. 3248 View* v2 = new View; 3249 v2->SetBounds(50, 10, 30, 10); 3250 EXPECT_FALSE(v2->layer()); 3251 view->AddChildView(v2); 3252 v2->SetPaintToLayer(true); 3253 EXPECT_EQ(gfx::Rect(content_width - 80, 10, 30, 10), 3254 v2->layer()->bounds()); 3255 gfx::Rect l2bounds = v2->layer()->bounds(); 3256 3257 view->SetPaintToLayer(true); 3258 EXPECT_EQ(l1bounds, v1->layer()->bounds()); 3259 EXPECT_EQ(l2bounds, v2->layer()->bounds()); 3260 3261 // Move one of the views. Make sure the layer is positioned correctly 3262 // afterwards. 3263 v1->SetBounds(v1->x() - 5, v1->y(), v1->width(), v1->height()); 3264 l1bounds.set_x(l1bounds.x() + 5); 3265 EXPECT_EQ(l1bounds, v1->layer()->bounds()); 3266 3267 view->SetPaintToLayer(false); 3268 EXPECT_EQ(l1bounds, v1->layer()->bounds()); 3269 EXPECT_EQ(l2bounds, v2->layer()->bounds()); 3270 3271 // Move a view again. 3272 v2->SetBounds(v2->x() + 5, v2->y(), v2->width(), v2->height()); 3273 l2bounds.set_x(l2bounds.x() - 5); 3274 EXPECT_EQ(l2bounds, v2->layer()->bounds()); 3275 3276 // Reset locale. 3277 base::i18n::SetICUDefaultLocale(locale); 3278 } 3279 3280 // Makes sure a transform persists after toggling the visibility. 3281 TEST_F(ViewLayerTest, ToggleVisibilityWithTransform) { 3282 View* view = new View; 3283 gfx::Transform transform; 3284 transform.Scale(2.0, 2.0); 3285 view->SetTransform(transform); 3286 widget()->SetContentsView(view); 3287 EXPECT_EQ(2.0f, view->GetTransform().matrix().get(0, 0)); 3288 3289 view->SetVisible(false); 3290 EXPECT_EQ(2.0f, view->GetTransform().matrix().get(0, 0)); 3291 3292 view->SetVisible(true); 3293 EXPECT_EQ(2.0f, view->GetTransform().matrix().get(0, 0)); 3294 } 3295 3296 // Verifies a transform persists after removing/adding a view with a transform. 3297 TEST_F(ViewLayerTest, ResetTransformOnLayerAfterAdd) { 3298 View* view = new View; 3299 gfx::Transform transform; 3300 transform.Scale(2.0, 2.0); 3301 view->SetTransform(transform); 3302 widget()->SetContentsView(view); 3303 EXPECT_EQ(2.0f, view->GetTransform().matrix().get(0, 0)); 3304 ASSERT_TRUE(view->layer() != NULL); 3305 EXPECT_EQ(2.0f, view->layer()->transform().matrix().get(0, 0)); 3306 3307 View* parent = view->parent(); 3308 parent->RemoveChildView(view); 3309 parent->AddChildView(view); 3310 3311 EXPECT_EQ(2.0f, view->GetTransform().matrix().get(0, 0)); 3312 ASSERT_TRUE(view->layer() != NULL); 3313 EXPECT_EQ(2.0f, view->layer()->transform().matrix().get(0, 0)); 3314 } 3315 3316 // Makes sure that layer visibility is correct after toggling View visibility. 3317 TEST_F(ViewLayerTest, ToggleVisibilityWithLayer) { 3318 View* content_view = new View; 3319 widget()->SetContentsView(content_view); 3320 3321 // The view isn't attached to a widget or a parent view yet. But it should 3322 // still have a layer, but the layer should not be attached to the root 3323 // layer. 3324 View* v1 = new View; 3325 v1->SetPaintToLayer(true); 3326 EXPECT_TRUE(v1->layer()); 3327 EXPECT_FALSE(LayerIsAncestor(widget()->GetCompositor()->root_layer(), 3328 v1->layer())); 3329 3330 // Once the view is attached to a widget, its layer should be attached to the 3331 // root layer and visible. 3332 content_view->AddChildView(v1); 3333 EXPECT_TRUE(LayerIsAncestor(widget()->GetCompositor()->root_layer(), 3334 v1->layer())); 3335 EXPECT_TRUE(v1->layer()->IsDrawn()); 3336 3337 v1->SetVisible(false); 3338 EXPECT_FALSE(v1->layer()->IsDrawn()); 3339 3340 v1->SetVisible(true); 3341 EXPECT_TRUE(v1->layer()->IsDrawn()); 3342 3343 widget()->Hide(); 3344 EXPECT_FALSE(v1->layer()->IsDrawn()); 3345 3346 widget()->Show(); 3347 EXPECT_TRUE(v1->layer()->IsDrawn()); 3348 } 3349 3350 // Tests that the layers in the subtree are orphaned after a View is removed 3351 // from the parent. 3352 TEST_F(ViewLayerTest, OrphanLayerAfterViewRemove) { 3353 View* content_view = new View; 3354 widget()->SetContentsView(content_view); 3355 3356 View* v1 = new View; 3357 content_view->AddChildView(v1); 3358 3359 View* v2 = new View; 3360 v1->AddChildView(v2); 3361 v2->SetPaintToLayer(true); 3362 EXPECT_TRUE(LayerIsAncestor(widget()->GetCompositor()->root_layer(), 3363 v2->layer())); 3364 EXPECT_TRUE(v2->layer()->IsDrawn()); 3365 3366 content_view->RemoveChildView(v1); 3367 3368 EXPECT_FALSE(LayerIsAncestor(widget()->GetCompositor()->root_layer(), 3369 v2->layer())); 3370 3371 // Reparent |v2|. 3372 content_view->AddChildView(v2); 3373 delete v1; 3374 v1 = NULL; 3375 EXPECT_TRUE(LayerIsAncestor(widget()->GetCompositor()->root_layer(), 3376 v2->layer())); 3377 EXPECT_TRUE(v2->layer()->IsDrawn()); 3378 } 3379 3380 class PaintTrackingView : public View { 3381 public: 3382 PaintTrackingView() : painted_(false) { 3383 } 3384 3385 bool painted() const { return painted_; } 3386 void set_painted(bool value) { painted_ = value; } 3387 3388 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE { 3389 painted_ = true; 3390 } 3391 3392 private: 3393 bool painted_; 3394 3395 DISALLOW_COPY_AND_ASSIGN(PaintTrackingView); 3396 }; 3397 3398 // Makes sure child views with layers aren't painted when paint starts at an 3399 // ancestor. 3400 TEST_F(ViewLayerTest, DontPaintChildrenWithLayers) { 3401 PaintTrackingView* content_view = new PaintTrackingView; 3402 widget()->SetContentsView(content_view); 3403 content_view->SetPaintToLayer(true); 3404 GetRootLayer()->GetCompositor()->ScheduleDraw(); 3405 ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); 3406 GetRootLayer()->SchedulePaint(gfx::Rect(0, 0, 10, 10)); 3407 content_view->set_painted(false); 3408 // content_view no longer has a dirty rect. Paint from the root and make sure 3409 // PaintTrackingView isn't painted. 3410 GetRootLayer()->GetCompositor()->ScheduleDraw(); 3411 ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); 3412 EXPECT_FALSE(content_view->painted()); 3413 3414 // Make content_view have a dirty rect, paint the layers and make sure 3415 // PaintTrackingView is painted. 3416 content_view->layer()->SchedulePaint(gfx::Rect(0, 0, 10, 10)); 3417 GetRootLayer()->GetCompositor()->ScheduleDraw(); 3418 ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); 3419 EXPECT_TRUE(content_view->painted()); 3420 } 3421 3422 // Tests that the visibility of child layers are updated correctly when a View's 3423 // visibility changes. 3424 TEST_F(ViewLayerTest, VisibilityChildLayers) { 3425 View* v1 = new View; 3426 v1->SetPaintToLayer(true); 3427 widget()->SetContentsView(v1); 3428 3429 View* v2 = new View; 3430 v1->AddChildView(v2); 3431 3432 View* v3 = new View; 3433 v2->AddChildView(v3); 3434 v3->SetVisible(false); 3435 3436 View* v4 = new View; 3437 v4->SetPaintToLayer(true); 3438 v3->AddChildView(v4); 3439 3440 EXPECT_TRUE(v1->layer()->IsDrawn()); 3441 EXPECT_FALSE(v4->layer()->IsDrawn()); 3442 3443 v2->SetVisible(false); 3444 EXPECT_TRUE(v1->layer()->IsDrawn()); 3445 EXPECT_FALSE(v4->layer()->IsDrawn()); 3446 3447 v2->SetVisible(true); 3448 EXPECT_TRUE(v1->layer()->IsDrawn()); 3449 EXPECT_FALSE(v4->layer()->IsDrawn()); 3450 3451 v2->SetVisible(false); 3452 EXPECT_TRUE(v1->layer()->IsDrawn()); 3453 EXPECT_FALSE(v4->layer()->IsDrawn()); 3454 EXPECT_TRUE(ViewAndLayerTreeAreConsistent(v1, v1->layer())); 3455 3456 v3->SetVisible(true); 3457 EXPECT_TRUE(v1->layer()->IsDrawn()); 3458 EXPECT_FALSE(v4->layer()->IsDrawn()); 3459 EXPECT_TRUE(ViewAndLayerTreeAreConsistent(v1, v1->layer())); 3460 3461 // Reparent |v3| to |v1|. 3462 v1->AddChildView(v3); 3463 EXPECT_TRUE(v1->layer()->IsDrawn()); 3464 EXPECT_TRUE(v4->layer()->IsDrawn()); 3465 EXPECT_TRUE(ViewAndLayerTreeAreConsistent(v1, v1->layer())); 3466 } 3467 3468 // This test creates a random View tree, and then randomly reorders child views, 3469 // reparents views etc. Unrelated changes can appear to break this test. So 3470 // marking this as FLAKY. 3471 TEST_F(ViewLayerTest, DISABLED_ViewLayerTreesInSync) { 3472 View* content = new View; 3473 content->SetPaintToLayer(true); 3474 widget()->SetContentsView(content); 3475 widget()->Show(); 3476 3477 ConstructTree(content, 5); 3478 EXPECT_TRUE(ViewAndLayerTreeAreConsistent(content, content->layer())); 3479 3480 ScrambleTree(content); 3481 EXPECT_TRUE(ViewAndLayerTreeAreConsistent(content, content->layer())); 3482 3483 ScrambleTree(content); 3484 EXPECT_TRUE(ViewAndLayerTreeAreConsistent(content, content->layer())); 3485 3486 ScrambleTree(content); 3487 EXPECT_TRUE(ViewAndLayerTreeAreConsistent(content, content->layer())); 3488 } 3489 3490 // Verifies when views are reordered the layer is also reordered. The widget is 3491 // providing the parent layer. 3492 TEST_F(ViewLayerTest, ReorderUnderWidget) { 3493 View* content = new View; 3494 widget()->SetContentsView(content); 3495 View* c1 = new View; 3496 c1->SetPaintToLayer(true); 3497 content->AddChildView(c1); 3498 View* c2 = new View; 3499 c2->SetPaintToLayer(true); 3500 content->AddChildView(c2); 3501 3502 ui::Layer* parent_layer = c1->layer()->parent(); 3503 ASSERT_TRUE(parent_layer); 3504 ASSERT_EQ(2u, parent_layer->children().size()); 3505 EXPECT_EQ(c1->layer(), parent_layer->children()[0]); 3506 EXPECT_EQ(c2->layer(), parent_layer->children()[1]); 3507 3508 // Move c1 to the front. The layers should have moved too. 3509 content->ReorderChildView(c1, -1); 3510 EXPECT_EQ(c1->layer(), parent_layer->children()[1]); 3511 EXPECT_EQ(c2->layer(), parent_layer->children()[0]); 3512 } 3513 3514 // Verifies that the layer of a view can be acquired properly. 3515 TEST_F(ViewLayerTest, AcquireLayer) { 3516 View* content = new View; 3517 widget()->SetContentsView(content); 3518 scoped_ptr<View> c1(new View); 3519 c1->SetPaintToLayer(true); 3520 EXPECT_TRUE(c1->layer()); 3521 content->AddChildView(c1.get()); 3522 3523 scoped_ptr<ui::Layer> layer(c1->AcquireLayer()); 3524 EXPECT_EQ(layer.get(), c1->layer()); 3525 3526 scoped_ptr<ui::Layer> layer2(c1->RecreateLayer()); 3527 EXPECT_NE(c1->layer(), layer2.get()); 3528 3529 // Destroy view before destroying layer. 3530 c1.reset(); 3531 } 3532 3533 // Verify the z-order of the layers as a result of calling RecreateLayer(). 3534 TEST_F(ViewLayerTest, RecreateLayerZOrder) { 3535 scoped_ptr<View> v(new View()); 3536 v->SetPaintToLayer(true); 3537 3538 View* v1 = new View(); 3539 v1->SetPaintToLayer(true); 3540 v->AddChildView(v1); 3541 View* v2 = new View(); 3542 v2->SetPaintToLayer(true); 3543 v->AddChildView(v2); 3544 3545 // Test the initial z-order. 3546 const std::vector<ui::Layer*>& child_layers_pre = v->layer()->children(); 3547 ASSERT_EQ(2u, child_layers_pre.size()); 3548 EXPECT_EQ(v1->layer(), child_layers_pre[0]); 3549 EXPECT_EQ(v2->layer(), child_layers_pre[1]); 3550 3551 scoped_ptr<ui::Layer> v1_old_layer(v1->RecreateLayer()); 3552 3553 // Test the new layer order. We expect: |v1| |v1_old_layer| |v2|. 3554 // for |v1| and |v2|. 3555 const std::vector<ui::Layer*>& child_layers_post = v->layer()->children(); 3556 ASSERT_EQ(3u, child_layers_post.size()); 3557 EXPECT_EQ(v1->layer(), child_layers_post[0]); 3558 EXPECT_EQ(v1_old_layer, child_layers_post[1]); 3559 EXPECT_EQ(v2->layer(), child_layers_post[2]); 3560 } 3561 3562 // Verify the z-order of the layers as a result of calling RecreateLayer when 3563 // the widget is the parent with the layer. 3564 TEST_F(ViewLayerTest, RecreateLayerZOrderWidgetParent) { 3565 View* v = new View(); 3566 widget()->SetContentsView(v); 3567 3568 View* v1 = new View(); 3569 v1->SetPaintToLayer(true); 3570 v->AddChildView(v1); 3571 View* v2 = new View(); 3572 v2->SetPaintToLayer(true); 3573 v->AddChildView(v2); 3574 3575 ui::Layer* root_layer = GetRootLayer(); 3576 3577 // Test the initial z-order. 3578 const std::vector<ui::Layer*>& child_layers_pre = root_layer->children(); 3579 ASSERT_EQ(2u, child_layers_pre.size()); 3580 EXPECT_EQ(v1->layer(), child_layers_pre[0]); 3581 EXPECT_EQ(v2->layer(), child_layers_pre[1]); 3582 3583 scoped_ptr<ui::Layer> v1_old_layer(v1->RecreateLayer()); 3584 3585 // Test the new layer order. We expect: |v1| |v1_old_layer| |v2|. 3586 const std::vector<ui::Layer*>& child_layers_post = root_layer->children(); 3587 ASSERT_EQ(3u, child_layers_post.size()); 3588 EXPECT_EQ(v1->layer(), child_layers_post[0]); 3589 EXPECT_EQ(v1_old_layer, child_layers_post[1]); 3590 EXPECT_EQ(v2->layer(), child_layers_post[2]); 3591 } 3592 3593 // Verifies RecreateLayer() moves all Layers over, even those that don't have 3594 // a View. 3595 TEST_F(ViewLayerTest, RecreateLayerMovesNonViewChildren) { 3596 View v; 3597 v.SetPaintToLayer(true); 3598 View child; 3599 child.SetPaintToLayer(true); 3600 v.AddChildView(&child); 3601 ASSERT_TRUE(v.layer() != NULL); 3602 ASSERT_EQ(1u, v.layer()->children().size()); 3603 EXPECT_EQ(v.layer()->children()[0], child.layer()); 3604 3605 ui::Layer layer(ui::LAYER_NOT_DRAWN); 3606 v.layer()->Add(&layer); 3607 v.layer()->StackAtBottom(&layer); 3608 3609 scoped_ptr<ui::Layer> old_layer(v.RecreateLayer()); 3610 3611 // All children should be moved from old layer to new layer. 3612 ASSERT_TRUE(old_layer.get() != NULL); 3613 EXPECT_TRUE(old_layer->children().empty()); 3614 3615 // And new layer should have the two children. 3616 ASSERT_TRUE(v.layer() != NULL); 3617 ASSERT_EQ(2u, v.layer()->children().size()); 3618 EXPECT_EQ(v.layer()->children()[0], &layer); 3619 EXPECT_EQ(v.layer()->children()[1], child.layer()); 3620 } 3621 3622 class BoundsTreeTestView : public View { 3623 public: 3624 BoundsTreeTestView() {} 3625 3626 virtual void PaintChildren(gfx::Canvas* canvas, 3627 const CullSet& cull_set) OVERRIDE { 3628 // Save out a copy of the cull_set before calling the base implementation. 3629 last_cull_set_.clear(); 3630 if (cull_set.cull_set_) { 3631 for (base::hash_set<intptr_t>::iterator it = cull_set.cull_set_->begin(); 3632 it != cull_set.cull_set_->end(); 3633 ++it) { 3634 last_cull_set_.insert(reinterpret_cast<View*>(*it)); 3635 } 3636 } 3637 View::PaintChildren(canvas, cull_set); 3638 } 3639 3640 std::set<View*> last_cull_set_; 3641 }; 3642 3643 TEST_F(ViewLayerTest, BoundsTreePaintUpdatesCullSet) { 3644 BoundsTreeTestView* test_view = new BoundsTreeTestView; 3645 widget()->SetContentsView(test_view); 3646 3647 View* v1 = new View(); 3648 v1->SetBoundsRect(gfx::Rect(10, 15, 150, 151)); 3649 test_view->AddChildView(v1); 3650 3651 View* v2 = new View(); 3652 v2->SetBoundsRect(gfx::Rect(20, 33, 40, 50)); 3653 v1->AddChildView(v2); 3654 3655 // Schedule a full-view paint to get everyone's rectangles updated. 3656 test_view->SchedulePaintInRect(test_view->bounds()); 3657 GetRootLayer()->GetCompositor()->ScheduleDraw(); 3658 ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); 3659 3660 // Now we have test_view - v1 - v2. Damage to only test_view should only 3661 // return root_view and test_view. 3662 test_view->SchedulePaintInRect(gfx::Rect(0, 0, 1, 1)); 3663 GetRootLayer()->GetCompositor()->ScheduleDraw(); 3664 ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); 3665 EXPECT_EQ(2U, test_view->last_cull_set_.size()); 3666 EXPECT_EQ(1U, test_view->last_cull_set_.count(widget()->GetRootView())); 3667 EXPECT_EQ(1U, test_view->last_cull_set_.count(test_view)); 3668 3669 // Damage to v1 only should only return root_view, test_view, and v1. 3670 test_view->SchedulePaintInRect(gfx::Rect(11, 16, 1, 1)); 3671 GetRootLayer()->GetCompositor()->ScheduleDraw(); 3672 ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); 3673 EXPECT_EQ(3U, test_view->last_cull_set_.size()); 3674 EXPECT_EQ(1U, test_view->last_cull_set_.count(widget()->GetRootView())); 3675 EXPECT_EQ(1U, test_view->last_cull_set_.count(test_view)); 3676 EXPECT_EQ(1U, test_view->last_cull_set_.count(v1)); 3677 3678 // A Damage rect inside v2 should get all 3 views back in the |last_cull_set_| 3679 // on call to TestView::Paint(), along with the widget root view. 3680 test_view->SchedulePaintInRect(gfx::Rect(31, 49, 1, 1)); 3681 GetRootLayer()->GetCompositor()->ScheduleDraw(); 3682 ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); 3683 EXPECT_EQ(4U, test_view->last_cull_set_.size()); 3684 EXPECT_EQ(1U, test_view->last_cull_set_.count(widget()->GetRootView())); 3685 EXPECT_EQ(1U, test_view->last_cull_set_.count(test_view)); 3686 EXPECT_EQ(1U, test_view->last_cull_set_.count(v1)); 3687 EXPECT_EQ(1U, test_view->last_cull_set_.count(v2)); 3688 } 3689 3690 TEST_F(ViewLayerTest, BoundsTreeWithRTL) { 3691 std::string locale = l10n_util::GetApplicationLocale(std::string()); 3692 base::i18n::SetICUDefaultLocale("ar"); 3693 3694 BoundsTreeTestView* test_view = new BoundsTreeTestView; 3695 widget()->SetContentsView(test_view); 3696 3697 // Add child views, which should be in RTL coordinate space of parent view. 3698 View* v1 = new View; 3699 v1->SetBoundsRect(gfx::Rect(10, 12, 25, 26)); 3700 test_view->AddChildView(v1); 3701 3702 View* v2 = new View; 3703 v2->SetBoundsRect(gfx::Rect(5, 6, 7, 8)); 3704 v1->AddChildView(v2); 3705 3706 // Schedule a full-view paint to get everyone's rectangles updated. 3707 test_view->SchedulePaintInRect(test_view->bounds()); 3708 GetRootLayer()->GetCompositor()->ScheduleDraw(); 3709 ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); 3710 3711 // Damage to the right side of the parent view should touch both child views. 3712 gfx::Rect rtl_damage(test_view->bounds().width() - 16, 18, 1, 1); 3713 test_view->SchedulePaintInRect(rtl_damage); 3714 GetRootLayer()->GetCompositor()->ScheduleDraw(); 3715 ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); 3716 EXPECT_EQ(4U, test_view->last_cull_set_.size()); 3717 EXPECT_EQ(1U, test_view->last_cull_set_.count(widget()->GetRootView())); 3718 EXPECT_EQ(1U, test_view->last_cull_set_.count(test_view)); 3719 EXPECT_EQ(1U, test_view->last_cull_set_.count(v1)); 3720 EXPECT_EQ(1U, test_view->last_cull_set_.count(v2)); 3721 3722 // Damage to the left side of the parent view should only touch the 3723 // container views. 3724 gfx::Rect ltr_damage(16, 18, 1, 1); 3725 test_view->SchedulePaintInRect(ltr_damage); 3726 GetRootLayer()->GetCompositor()->ScheduleDraw(); 3727 ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); 3728 EXPECT_EQ(2U, test_view->last_cull_set_.size()); 3729 EXPECT_EQ(1U, test_view->last_cull_set_.count(widget()->GetRootView())); 3730 EXPECT_EQ(1U, test_view->last_cull_set_.count(test_view)); 3731 3732 // Reset locale. 3733 base::i18n::SetICUDefaultLocale(locale); 3734 } 3735 3736 TEST_F(ViewLayerTest, BoundsTreeSetBoundsChangesCullSet) { 3737 BoundsTreeTestView* test_view = new BoundsTreeTestView; 3738 widget()->SetContentsView(test_view); 3739 3740 View* v1 = new View; 3741 v1->SetBoundsRect(gfx::Rect(5, 6, 100, 101)); 3742 test_view->AddChildView(v1); 3743 3744 View* v2 = new View; 3745 v2->SetBoundsRect(gfx::Rect(20, 33, 40, 50)); 3746 v1->AddChildView(v2); 3747 3748 // Schedule a full-view paint to get everyone's rectangles updated. 3749 test_view->SchedulePaintInRect(test_view->bounds()); 3750 GetRootLayer()->GetCompositor()->ScheduleDraw(); 3751 ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); 3752 3753 // Move v1 to a new origin out of the way of our next query. 3754 v1->SetBoundsRect(gfx::Rect(50, 60, 100, 101)); 3755 // The move will force a repaint. 3756 GetRootLayer()->GetCompositor()->ScheduleDraw(); 3757 ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); 3758 3759 // Schedule a paint with damage rect where v1 used to be. 3760 test_view->SchedulePaintInRect(gfx::Rect(5, 6, 10, 11)); 3761 GetRootLayer()->GetCompositor()->ScheduleDraw(); 3762 ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); 3763 3764 // Should only have picked up root_view and test_view. 3765 EXPECT_EQ(2U, test_view->last_cull_set_.size()); 3766 EXPECT_EQ(1U, test_view->last_cull_set_.count(widget()->GetRootView())); 3767 EXPECT_EQ(1U, test_view->last_cull_set_.count(test_view)); 3768 } 3769 3770 TEST_F(ViewLayerTest, BoundsTreeLayerChangeMakesNewTree) { 3771 BoundsTreeTestView* test_view = new BoundsTreeTestView; 3772 widget()->SetContentsView(test_view); 3773 3774 View* v1 = new View; 3775 v1->SetBoundsRect(gfx::Rect(5, 10, 15, 20)); 3776 test_view->AddChildView(v1); 3777 3778 View* v2 = new View; 3779 v2->SetBoundsRect(gfx::Rect(1, 2, 3, 4)); 3780 v1->AddChildView(v2); 3781 3782 // Schedule a full-view paint to get everyone's rectangles updated. 3783 test_view->SchedulePaintInRect(test_view->bounds()); 3784 GetRootLayer()->GetCompositor()->ScheduleDraw(); 3785 ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); 3786 3787 // Set v1 to paint to its own layer, it should remove itself from the 3788 // test_view heiarchy and no longer intersect with damage rects in that cull 3789 // set. 3790 v1->SetPaintToLayer(true); 3791 3792 // Schedule another full-view paint. 3793 test_view->SchedulePaintInRect(test_view->bounds()); 3794 GetRootLayer()->GetCompositor()->ScheduleDraw(); 3795 ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); 3796 // v1 and v2 should no longer be present in the test_view cull_set. 3797 EXPECT_EQ(2U, test_view->last_cull_set_.size()); 3798 EXPECT_EQ(0U, test_view->last_cull_set_.count(v1)); 3799 EXPECT_EQ(0U, test_view->last_cull_set_.count(v2)); 3800 3801 // Now set v1 back to not painting to a layer. 3802 v1->SetPaintToLayer(false); 3803 // Schedule another full-view paint. 3804 test_view->SchedulePaintInRect(test_view->bounds()); 3805 GetRootLayer()->GetCompositor()->ScheduleDraw(); 3806 ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); 3807 // We should be back to the full cull set including v1 and v2. 3808 EXPECT_EQ(4U, test_view->last_cull_set_.size()); 3809 EXPECT_EQ(1U, test_view->last_cull_set_.count(widget()->GetRootView())); 3810 EXPECT_EQ(1U, test_view->last_cull_set_.count(test_view)); 3811 EXPECT_EQ(1U, test_view->last_cull_set_.count(v1)); 3812 EXPECT_EQ(1U, test_view->last_cull_set_.count(v2)); 3813 } 3814 3815 TEST_F(ViewLayerTest, BoundsTreeRemoveChildRemovesBounds) { 3816 BoundsTreeTestView* test_view = new BoundsTreeTestView; 3817 widget()->SetContentsView(test_view); 3818 3819 View* v1 = new View; 3820 v1->SetBoundsRect(gfx::Rect(5, 10, 15, 20)); 3821 test_view->AddChildView(v1); 3822 3823 View* v2 = new View; 3824 v2->SetBoundsRect(gfx::Rect(1, 2, 3, 4)); 3825 v1->AddChildView(v2); 3826 3827 // Schedule a full-view paint to get everyone's rectangles updated. 3828 test_view->SchedulePaintInRect(test_view->bounds()); 3829 GetRootLayer()->GetCompositor()->ScheduleDraw(); 3830 ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); 3831 3832 // Now remove v1 from the root view. 3833 test_view->RemoveChildView(v1); 3834 3835 // Schedule another full-view paint. 3836 test_view->SchedulePaintInRect(test_view->bounds()); 3837 GetRootLayer()->GetCompositor()->ScheduleDraw(); 3838 ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); 3839 // v1 and v2 should no longer be present in the test_view cull_set. 3840 EXPECT_EQ(2U, test_view->last_cull_set_.size()); 3841 EXPECT_EQ(0U, test_view->last_cull_set_.count(v1)); 3842 EXPECT_EQ(0U, test_view->last_cull_set_.count(v2)); 3843 3844 // View v1 and v2 are no longer part of view hierarchy and therefore won't be 3845 // deleted with that hierarchy. 3846 delete v1; 3847 } 3848 3849 TEST_F(ViewLayerTest, BoundsTreeMoveViewMovesBounds) { 3850 BoundsTreeTestView* test_view = new BoundsTreeTestView; 3851 widget()->SetContentsView(test_view); 3852 3853 // Build hierarchy v1 - v2 - v3. 3854 View* v1 = new View; 3855 v1->SetBoundsRect(gfx::Rect(20, 30, 150, 160)); 3856 test_view->AddChildView(v1); 3857 3858 View* v2 = new View; 3859 v2->SetBoundsRect(gfx::Rect(5, 10, 40, 50)); 3860 v1->AddChildView(v2); 3861 3862 View* v3 = new View; 3863 v3->SetBoundsRect(gfx::Rect(1, 2, 3, 4)); 3864 v2->AddChildView(v3); 3865 3866 // Schedule a full-view paint and ensure all views are present in the cull. 3867 test_view->SchedulePaintInRect(test_view->bounds()); 3868 GetRootLayer()->GetCompositor()->ScheduleDraw(); 3869 ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); 3870 EXPECT_EQ(5U, test_view->last_cull_set_.size()); 3871 EXPECT_EQ(1U, test_view->last_cull_set_.count(widget()->GetRootView())); 3872 EXPECT_EQ(1U, test_view->last_cull_set_.count(test_view)); 3873 EXPECT_EQ(1U, test_view->last_cull_set_.count(v1)); 3874 EXPECT_EQ(1U, test_view->last_cull_set_.count(v2)); 3875 EXPECT_EQ(1U, test_view->last_cull_set_.count(v3)); 3876 3877 // Build an unrelated view hierarchy and move v2 in to it. 3878 scoped_ptr<Widget> test_widget(new Widget); 3879 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP); 3880 params.bounds = gfx::Rect(10, 10, 500, 500); 3881 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 3882 test_widget->Init(params); 3883 test_widget->Show(); 3884 BoundsTreeTestView* widget_view = new BoundsTreeTestView; 3885 test_widget->SetContentsView(widget_view); 3886 widget_view->AddChildView(v2); 3887 3888 // Now schedule full-view paints in both widgets. 3889 test_view->SchedulePaintInRect(test_view->bounds()); 3890 widget_view->SchedulePaintInRect(widget_view->bounds()); 3891 GetRootLayer()->GetCompositor()->ScheduleDraw(); 3892 ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor()); 3893 3894 // Only v1 should be present in the first cull set. 3895 EXPECT_EQ(3U, test_view->last_cull_set_.size()); 3896 EXPECT_EQ(1U, test_view->last_cull_set_.count(widget()->GetRootView())); 3897 EXPECT_EQ(1U, test_view->last_cull_set_.count(test_view)); 3898 EXPECT_EQ(1U, test_view->last_cull_set_.count(v1)); 3899 3900 // We should find v2 and v3 in the widget_view cull_set. 3901 EXPECT_EQ(4U, widget_view->last_cull_set_.size()); 3902 EXPECT_EQ(1U, widget_view->last_cull_set_.count(test_widget->GetRootView())); 3903 EXPECT_EQ(1U, widget_view->last_cull_set_.count(widget_view)); 3904 EXPECT_EQ(1U, widget_view->last_cull_set_.count(v2)); 3905 EXPECT_EQ(1U, widget_view->last_cull_set_.count(v3)); 3906 } 3907 3908 TEST_F(ViewTest, FocusableAssertions) { 3909 // View subclasses may change insets based on whether they are focusable, 3910 // which effects the preferred size. To avoid preferred size changing around 3911 // these Views need to key off the last value set to SetFocusable(), not 3912 // whether the View is focusable right now. For this reason it's important 3913 // that focusable() return the last value passed to SetFocusable and not 3914 // whether the View is focusable right now. 3915 TestView view; 3916 view.SetFocusable(true); 3917 EXPECT_TRUE(view.focusable()); 3918 view.SetEnabled(false); 3919 EXPECT_TRUE(view.focusable()); 3920 view.SetFocusable(false); 3921 EXPECT_FALSE(view.focusable()); 3922 } 3923 3924 // Verifies when a view is deleted it is removed from ViewStorage. 3925 TEST_F(ViewTest, UpdateViewStorageOnDelete) { 3926 ViewStorage* view_storage = ViewStorage::GetInstance(); 3927 const int storage_id = view_storage->CreateStorageID(); 3928 { 3929 View view; 3930 view_storage->StoreView(storage_id, &view); 3931 } 3932 EXPECT_TRUE(view_storage->RetrieveView(storage_id) == NULL); 3933 } 3934 3935 //////////////////////////////////////////////////////////////////////////////// 3936 // NativeTheme 3937 //////////////////////////////////////////////////////////////////////////////// 3938 3939 void TestView::OnNativeThemeChanged(const ui::NativeTheme* native_theme) { 3940 native_theme_ = native_theme; 3941 } 3942 3943 TEST_F(ViewTest, OnNativeThemeChanged) { 3944 TestView* test_view = new TestView(); 3945 EXPECT_FALSE(test_view->native_theme_); 3946 TestView* test_view_child = new TestView(); 3947 EXPECT_FALSE(test_view_child->native_theme_); 3948 3949 // Child view added before the widget hierarchy exists should get the 3950 // new native theme notification. 3951 test_view->AddChildView(test_view_child); 3952 3953 scoped_ptr<Widget> widget(new Widget); 3954 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW); 3955 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 3956 widget->Init(params); 3957 3958 widget->GetRootView()->AddChildView(test_view); 3959 EXPECT_TRUE(test_view->native_theme_); 3960 EXPECT_EQ(widget->GetNativeTheme(), test_view->native_theme_); 3961 EXPECT_TRUE(test_view_child->native_theme_); 3962 EXPECT_EQ(widget->GetNativeTheme(), test_view_child->native_theme_); 3963 3964 // Child view added after the widget hierarchy exists should also get the 3965 // notification. 3966 TestView* test_view_child_2 = new TestView(); 3967 test_view->AddChildView(test_view_child_2); 3968 EXPECT_TRUE(test_view_child_2->native_theme_); 3969 EXPECT_EQ(widget->GetNativeTheme(), test_view_child_2->native_theme_); 3970 3971 widget->CloseNow(); 3972 } 3973 3974 } // namespace views 3975