Correct blacklist entry message
[chromium-blink-merge.git] / ui / views / view_unittest.cc
blobd5f387a2b5a9b942dc7cc83392c52877f4ad8f81
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.
5 #include <map>
7 #include "base/memory/scoped_ptr.h"
8 #include "base/rand_util.h"
9 #include "base/strings/string_util.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "grit/ui_strings.h"
12 #include "testing/gmock/include/gmock/gmock.h"
13 #include "ui/base/accelerators/accelerator.h"
14 #include "ui/base/clipboard/clipboard.h"
15 #include "ui/base/l10n/l10n_util.h"
16 #include "ui/compositor/compositor.h"
17 #include "ui/compositor/layer.h"
18 #include "ui/compositor/layer_animator.h"
19 #include "ui/events/event.h"
20 #include "ui/events/keycodes/keyboard_codes.h"
21 #include "ui/gfx/canvas.h"
22 #include "ui/gfx/path.h"
23 #include "ui/gfx/transform.h"
24 #include "ui/views/background.h"
25 #include "ui/views/controls/native/native_view_host.h"
26 #include "ui/views/controls/scroll_view.h"
27 #include "ui/views/controls/textfield/textfield.h"
28 #include "ui/views/focus/accelerator_handler.h"
29 #include "ui/views/focus/view_storage.h"
30 #include "ui/views/test/views_test_base.h"
31 #include "ui/views/view.h"
32 #include "ui/views/views_delegate.h"
33 #include "ui/views/widget/native_widget.h"
34 #include "ui/views/widget/root_view.h"
35 #include "ui/views/window/dialog_client_view.h"
36 #include "ui/views/window/dialog_delegate.h"
38 #if defined(OS_WIN)
39 #include "ui/views/test/test_views_delegate.h"
40 #endif
41 #if defined(USE_AURA)
42 #include "ui/aura/root_window.h"
43 #include "ui/events/gestures/gesture_recognizer.h"
44 #endif
46 using ::testing::_;
48 namespace {
50 // Returns true if |ancestor| is an ancestor of |layer|.
51 bool LayerIsAncestor(const ui::Layer* ancestor, const ui::Layer* layer) {
52 while (layer && layer != ancestor)
53 layer = layer->parent();
54 return layer == ancestor;
57 // Convenience functions for walking a View tree.
58 const views::View* FirstView(const views::View* view) {
59 const views::View* v = view;
60 while (v->has_children())
61 v = v->child_at(0);
62 return v;
65 const views::View* NextView(const views::View* view) {
66 const views::View* v = view;
67 const views::View* parent = v->parent();
68 if (!parent)
69 return NULL;
70 int next = parent->GetIndexOf(v) + 1;
71 if (next != parent->child_count())
72 return FirstView(parent->child_at(next));
73 return parent;
76 // Convenience functions for walking a Layer tree.
77 const ui::Layer* FirstLayer(const ui::Layer* layer) {
78 const ui::Layer* l = layer;
79 while (l->children().size() > 0)
80 l = l->children()[0];
81 return l;
84 const ui::Layer* NextLayer(const ui::Layer* layer) {
85 const ui::Layer* parent = layer->parent();
86 if (!parent)
87 return NULL;
88 const std::vector<ui::Layer*> children = parent->children();
89 size_t index;
90 for (index = 0; index < children.size(); index++) {
91 if (children[index] == layer)
92 break;
94 size_t next = index + 1;
95 if (next < children.size())
96 return FirstLayer(children[next]);
97 return parent;
100 // Given the root nodes of a View tree and a Layer tree, makes sure the two
101 // trees are in sync.
102 bool ViewAndLayerTreeAreConsistent(const views::View* view,
103 const ui::Layer* layer) {
104 const views::View* v = FirstView(view);
105 const ui::Layer* l = FirstLayer(layer);
106 while (v && l) {
107 // Find the view with a layer.
108 while (v && !v->layer())
109 v = NextView(v);
110 EXPECT_TRUE(v);
111 if (!v)
112 return false;
114 // Check if the View tree and the Layer tree are in sync.
115 EXPECT_EQ(l, v->layer());
116 if (v->layer() != l)
117 return false;
119 // Check if the visibility states of the View and the Layer are in sync.
120 EXPECT_EQ(l->IsDrawn(), v->IsDrawn());
121 if (v->IsDrawn() != l->IsDrawn()) {
122 for (const views::View* vv = v; vv; vv = vv->parent())
123 LOG(ERROR) << "V: " << vv << " " << vv->visible() << " "
124 << vv->IsDrawn() << " " << vv->layer();
125 for (const ui::Layer* ll = l; ll; ll = ll->parent())
126 LOG(ERROR) << "L: " << ll << " " << ll->IsDrawn();
127 return false;
130 // Check if the size of the View and the Layer are in sync.
131 EXPECT_EQ(l->bounds(), v->bounds());
132 if (v->bounds() != l->bounds())
133 return false;
135 if (v == view || l == layer)
136 return v == view && l == layer;
138 v = NextView(v);
139 l = NextLayer(l);
142 return false;
145 // Constructs a View tree with the specified depth.
146 void ConstructTree(views::View* view, int depth) {
147 if (depth == 0)
148 return;
149 int count = base::RandInt(1, 5);
150 for (int i = 0; i < count; i++) {
151 views::View* v = new views::View;
152 view->AddChildView(v);
153 if (base::RandDouble() > 0.5)
154 v->SetPaintToLayer(true);
155 if (base::RandDouble() < 0.2)
156 v->SetVisible(false);
158 ConstructTree(v, depth - 1);
162 void ScrambleTree(views::View* view) {
163 int count = view->child_count();
164 if (count == 0)
165 return;
166 for (int i = 0; i < count; i++) {
167 ScrambleTree(view->child_at(i));
170 if (count > 1) {
171 int a = base::RandInt(0, count - 1);
172 int b = base::RandInt(0, count - 1);
174 views::View* view_a = view->child_at(a);
175 views::View* view_b = view->child_at(b);
176 view->ReorderChildView(view_a, b);
177 view->ReorderChildView(view_b, a);
180 if (!view->layer() && base::RandDouble() < 0.1)
181 view->SetPaintToLayer(true);
183 if (base::RandDouble() < 0.1)
184 view->SetVisible(!view->visible());
187 // Convenience to make constructing a GestureEvent simpler.
188 class GestureEventForTest : public ui::GestureEvent {
189 public:
190 GestureEventForTest(ui::EventType type, int x, int y, int flags)
191 : GestureEvent(type, x, y, flags, base::TimeDelta(),
192 ui::GestureEventDetails(type, 0.0f, 0.0f), 0) {
195 private:
196 DISALLOW_COPY_AND_ASSIGN(GestureEventForTest);
199 } // namespace
201 namespace views {
203 typedef ViewsTestBase ViewTest;
205 // A derived class for testing purpose.
206 class TestView : public View {
207 public:
208 TestView() : View(), delete_on_pressed_(false), in_touch_sequence_(false) {}
209 virtual ~TestView() {}
211 // Reset all test state
212 void Reset() {
213 did_change_bounds_ = false;
214 last_mouse_event_type_ = 0;
215 location_.SetPoint(0, 0);
216 received_mouse_enter_ = false;
217 received_mouse_exit_ = false;
218 last_touch_event_type_ = 0;
219 last_touch_event_was_handled_ = false;
220 last_gesture_event_type_ = 0;
221 last_gesture_event_was_handled_ = false;
222 last_clip_.setEmpty();
223 accelerator_count_map_.clear();
226 virtual void OnBoundsChanged(const gfx::Rect& previous_bounds) OVERRIDE;
227 virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE;
228 virtual bool OnMouseDragged(const ui::MouseEvent& event) OVERRIDE;
229 virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE;
230 virtual void OnMouseEntered(const ui::MouseEvent& event) OVERRIDE;
231 virtual void OnMouseExited(const ui::MouseEvent& event) OVERRIDE;
233 virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE;
234 // Ignores GestureEvent by default.
235 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
237 virtual void Paint(gfx::Canvas* canvas) OVERRIDE;
238 virtual void SchedulePaintInRect(const gfx::Rect& rect) OVERRIDE;
239 virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE;
241 // OnBoundsChanged.
242 bool did_change_bounds_;
243 gfx::Rect new_bounds_;
245 // MouseEvent.
246 int last_mouse_event_type_;
247 gfx::Point location_;
248 bool received_mouse_enter_;
249 bool received_mouse_exit_;
250 bool delete_on_pressed_;
252 // Painting.
253 std::vector<gfx::Rect> scheduled_paint_rects_;
255 // GestureEvent
256 int last_gesture_event_type_;
257 bool last_gesture_event_was_handled_;
259 // TouchEvent.
260 int last_touch_event_type_;
261 bool last_touch_event_was_handled_;
262 bool in_touch_sequence_;
264 // Painting.
265 SkRect last_clip_;
267 // Accelerators.
268 std::map<ui::Accelerator, int> accelerator_count_map_;
271 // A view subclass that ignores all touch events for testing purposes.
272 class TestViewIgnoreTouch : public TestView {
273 public:
274 TestViewIgnoreTouch() : TestView() {}
275 virtual ~TestViewIgnoreTouch() {}
277 private:
278 virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE;
281 // A view subclass that consumes all Gesture events for testing purposes.
282 class TestViewConsumeGesture : public TestView {
283 public:
284 TestViewConsumeGesture() : TestView() {}
285 virtual ~TestViewConsumeGesture() {}
287 protected:
288 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
289 last_gesture_event_type_ = event->type();
290 location_.SetPoint(event->x(), event->y());
291 event->StopPropagation();
294 private:
295 DISALLOW_COPY_AND_ASSIGN(TestViewConsumeGesture);
298 // A view subclass that ignores all Gesture events.
299 class TestViewIgnoreGesture: public TestView {
300 public:
301 TestViewIgnoreGesture() : TestView() {}
302 virtual ~TestViewIgnoreGesture() {}
304 private:
305 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
308 DISALLOW_COPY_AND_ASSIGN(TestViewIgnoreGesture);
311 // A view subclass that ignores all scroll-gesture events, but consume all other
312 // gesture events.
313 class TestViewIgnoreScrollGestures : public TestViewConsumeGesture {
314 public:
315 TestViewIgnoreScrollGestures() {}
316 virtual ~TestViewIgnoreScrollGestures() {}
318 private:
319 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
320 if (event->IsScrollGestureEvent())
321 return;
322 TestViewConsumeGesture::OnGestureEvent(event);
325 DISALLOW_COPY_AND_ASSIGN(TestViewIgnoreScrollGestures);
328 ////////////////////////////////////////////////////////////////////////////////
329 // OnBoundsChanged
330 ////////////////////////////////////////////////////////////////////////////////
332 void TestView::OnBoundsChanged(const gfx::Rect& previous_bounds) {
333 did_change_bounds_ = true;
334 new_bounds_ = bounds();
337 TEST_F(ViewTest, OnBoundsChanged) {
338 TestView v;
340 gfx::Rect prev_rect(0, 0, 200, 200);
341 gfx::Rect new_rect(100, 100, 250, 250);
343 v.SetBoundsRect(prev_rect);
344 v.Reset();
345 v.SetBoundsRect(new_rect);
347 EXPECT_TRUE(v.did_change_bounds_);
348 EXPECT_EQ(v.new_bounds_, new_rect);
349 EXPECT_EQ(v.bounds(), new_rect);
352 ////////////////////////////////////////////////////////////////////////////////
353 // MouseEvent
354 ////////////////////////////////////////////////////////////////////////////////
356 bool TestView::OnMousePressed(const ui::MouseEvent& event) {
357 last_mouse_event_type_ = event.type();
358 location_.SetPoint(event.x(), event.y());
359 if (delete_on_pressed_)
360 delete this;
361 return true;
364 bool TestView::OnMouseDragged(const ui::MouseEvent& event) {
365 last_mouse_event_type_ = event.type();
366 location_.SetPoint(event.x(), event.y());
367 return true;
370 void TestView::OnMouseReleased(const ui::MouseEvent& event) {
371 last_mouse_event_type_ = event.type();
372 location_.SetPoint(event.x(), event.y());
375 void TestView::OnMouseEntered(const ui::MouseEvent& event) {
376 received_mouse_enter_ = true;
379 void TestView::OnMouseExited(const ui::MouseEvent& event) {
380 received_mouse_exit_ = true;
383 TEST_F(ViewTest, MouseEvent) {
384 TestView* v1 = new TestView();
385 v1->SetBoundsRect(gfx::Rect(0, 0, 300, 300));
387 TestView* v2 = new TestView();
388 v2->SetBoundsRect(gfx::Rect(100, 100, 100, 100));
390 scoped_ptr<Widget> widget(new Widget);
391 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
392 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
393 params.bounds = gfx::Rect(50, 50, 650, 650);
394 widget->Init(params);
395 internal::RootView* root =
396 static_cast<internal::RootView*>(widget->GetRootView());
398 root->AddChildView(v1);
399 v1->AddChildView(v2);
401 v1->Reset();
402 v2->Reset();
404 gfx::Point p1(110, 120);
405 ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, p1, p1,
406 ui::EF_LEFT_MOUSE_BUTTON);
407 root->OnMousePressed(pressed);
408 EXPECT_EQ(v2->last_mouse_event_type_, ui::ET_MOUSE_PRESSED);
409 EXPECT_EQ(v2->location_.x(), 10);
410 EXPECT_EQ(v2->location_.y(), 20);
411 // Make sure v1 did not receive the event
412 EXPECT_EQ(v1->last_mouse_event_type_, 0);
414 // Drag event out of bounds. Should still go to v2
415 v1->Reset();
416 v2->Reset();
417 gfx::Point p2(50, 40);
418 ui::MouseEvent dragged(ui::ET_MOUSE_DRAGGED, p2, p2,
419 ui::EF_LEFT_MOUSE_BUTTON);
420 root->OnMouseDragged(dragged);
421 EXPECT_EQ(v2->last_mouse_event_type_, ui::ET_MOUSE_DRAGGED);
422 EXPECT_EQ(v2->location_.x(), -50);
423 EXPECT_EQ(v2->location_.y(), -60);
424 // Make sure v1 did not receive the event
425 EXPECT_EQ(v1->last_mouse_event_type_, 0);
427 // Releasted event out of bounds. Should still go to v2
428 v1->Reset();
429 v2->Reset();
430 ui::MouseEvent released(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(), 0);
431 root->OnMouseDragged(released);
432 EXPECT_EQ(v2->last_mouse_event_type_, ui::ET_MOUSE_RELEASED);
433 EXPECT_EQ(v2->location_.x(), -100);
434 EXPECT_EQ(v2->location_.y(), -100);
435 // Make sure v1 did not receive the event
436 EXPECT_EQ(v1->last_mouse_event_type_, 0);
438 widget->CloseNow();
441 // Confirm that a view can be deleted as part of processing a mouse press.
442 TEST_F(ViewTest, DeleteOnPressed) {
443 TestView* v1 = new TestView();
444 v1->SetBoundsRect(gfx::Rect(0, 0, 300, 300));
446 TestView* v2 = new TestView();
447 v2->SetBoundsRect(gfx::Rect(100, 100, 100, 100));
449 v1->Reset();
450 v2->Reset();
452 scoped_ptr<Widget> widget(new Widget);
453 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
454 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
455 params.bounds = gfx::Rect(50, 50, 650, 650);
456 widget->Init(params);
457 View* root = widget->GetRootView();
459 root->AddChildView(v1);
460 v1->AddChildView(v2);
462 v2->delete_on_pressed_ = true;
463 gfx::Point point(110, 120);
464 ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, point, point,
465 ui::EF_LEFT_MOUSE_BUTTON);
466 root->OnMousePressed(pressed);
467 EXPECT_EQ(0, v1->child_count());
469 widget->CloseNow();
472 ////////////////////////////////////////////////////////////////////////////////
473 // TouchEvent
474 ////////////////////////////////////////////////////////////////////////////////
475 void TestView::OnTouchEvent(ui::TouchEvent* event) {
476 last_touch_event_type_ = event->type();
477 location_.SetPoint(event->x(), event->y());
478 if (!in_touch_sequence_) {
479 if (event->type() == ui::ET_TOUCH_PRESSED) {
480 in_touch_sequence_ = true;
481 event->StopPropagation();
482 return;
484 } else {
485 if (event->type() == ui::ET_TOUCH_RELEASED) {
486 in_touch_sequence_ = false;
487 event->SetHandled();
488 return;
490 event->StopPropagation();
491 return;
494 if (last_touch_event_was_handled_)
495 event->StopPropagation();
498 void TestViewIgnoreTouch::OnTouchEvent(ui::TouchEvent* event) {
501 TEST_F(ViewTest, TouchEvent) {
502 TestView* v1 = new TestView();
503 v1->SetBoundsRect(gfx::Rect(0, 0, 300, 300));
505 TestView* v2 = new TestView();
506 v2->SetBoundsRect(gfx::Rect(100, 100, 100, 100));
508 TestView* v3 = new TestViewIgnoreTouch();
509 v3->SetBoundsRect(gfx::Rect(0, 0, 100, 100));
511 scoped_ptr<Widget> widget(new Widget());
512 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
513 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
514 params.bounds = gfx::Rect(50, 50, 650, 650);
515 widget->Init(params);
516 internal::RootView* root =
517 static_cast<internal::RootView*>(widget->GetRootView());
519 root->AddChildView(v1);
520 v1->AddChildView(v2);
521 v2->AddChildView(v3);
523 // |v3| completely obscures |v2|, but all the touch events on |v3| should
524 // reach |v2| because |v3| doesn't process any touch events.
526 // Make sure if none of the views handle the touch event, the gesture manager
527 // does.
528 v1->Reset();
529 v2->Reset();
531 ui::TouchEvent unhandled(ui::ET_TOUCH_MOVED,
532 gfx::Point(400, 400),
533 0, /* no flags */
534 0, /* first finger touch */
535 base::TimeDelta(),
536 1.0, 0.0, 1.0, 0.0);
537 root->DispatchTouchEvent(&unhandled);
539 EXPECT_EQ(v1->last_touch_event_type_, 0);
540 EXPECT_EQ(v2->last_touch_event_type_, 0);
542 // Test press, drag, release touch sequence.
543 v1->Reset();
544 v2->Reset();
546 ui::TouchEvent pressed(ui::ET_TOUCH_PRESSED,
547 gfx::Point(110, 120),
548 0, /* no flags */
549 0, /* first finger touch */
550 base::TimeDelta(),
551 1.0, 0.0, 1.0, 0.0);
552 v2->last_touch_event_was_handled_ = true;
553 root->DispatchTouchEvent(&pressed);
555 EXPECT_EQ(v2->last_touch_event_type_, ui::ET_TOUCH_PRESSED);
556 EXPECT_EQ(v2->location_.x(), 10);
557 EXPECT_EQ(v2->location_.y(), 20);
558 // Make sure v1 did not receive the event
559 EXPECT_EQ(v1->last_touch_event_type_, 0);
561 // Drag event out of bounds. Should still go to v2
562 v1->Reset();
563 v2->Reset();
564 ui::TouchEvent dragged(ui::ET_TOUCH_MOVED,
565 gfx::Point(50, 40),
566 0, /* no flags */
567 0, /* first finger touch */
568 base::TimeDelta(),
569 1.0, 0.0, 1.0, 0.0);
571 root->DispatchTouchEvent(&dragged);
572 EXPECT_EQ(v2->last_touch_event_type_, ui::ET_TOUCH_MOVED);
573 EXPECT_EQ(v2->location_.x(), -50);
574 EXPECT_EQ(v2->location_.y(), -60);
575 // Make sure v1 did not receive the event
576 EXPECT_EQ(v1->last_touch_event_type_, 0);
578 // Released event out of bounds. Should still go to v2
579 v1->Reset();
580 v2->Reset();
581 ui::TouchEvent released(ui::ET_TOUCH_RELEASED, gfx::Point(),
582 0, /* no flags */
583 0, /* first finger */
584 base::TimeDelta(),
585 1.0, 0.0, 1.0, 0.0);
586 v2->last_touch_event_was_handled_ = true;
587 root->DispatchTouchEvent(&released);
588 EXPECT_EQ(v2->last_touch_event_type_, ui::ET_TOUCH_RELEASED);
589 EXPECT_EQ(v2->location_.x(), -100);
590 EXPECT_EQ(v2->location_.y(), -100);
591 // Make sure v1 did not receive the event
592 EXPECT_EQ(v1->last_touch_event_type_, 0);
594 widget->CloseNow();
597 void TestView::OnGestureEvent(ui::GestureEvent* event) {
600 TEST_F(ViewTest, GestureEvent) {
601 // Views hierarchy for non delivery of GestureEvent.
602 TestView* v1 = new TestViewConsumeGesture();
603 v1->SetBoundsRect(gfx::Rect(0, 0, 300, 300));
605 TestView* v2 = new TestViewConsumeGesture();
606 v2->SetBoundsRect(gfx::Rect(100, 100, 100, 100));
608 TestView* v3 = new TestViewIgnoreGesture();
609 v3->SetBoundsRect(gfx::Rect(0, 0, 100, 100));
611 scoped_ptr<Widget> widget(new Widget());
612 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
613 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
614 params.bounds = gfx::Rect(50, 50, 650, 650);
615 widget->Init(params);
616 internal::RootView* root =
617 static_cast<internal::RootView*>(widget->GetRootView());
619 root->AddChildView(v1);
620 v1->AddChildView(v2);
621 v2->AddChildView(v3);
623 // |v3| completely obscures |v2|, but all the gesture events on |v3| should
624 // reach |v2| because |v3| doesn't process any gesture events. However, since
625 // |v2| does process gesture events, gesture events on |v3| or |v2| should not
626 // reach |v1|.
628 v1->Reset();
629 v2->Reset();
630 v3->Reset();
632 // Gesture on |v3|
633 GestureEventForTest g1(ui::ET_GESTURE_TAP, 110, 110, 0);
634 root->DispatchGestureEvent(&g1);
635 EXPECT_EQ(ui::ET_GESTURE_TAP, v2->last_gesture_event_type_);
636 EXPECT_EQ(gfx::Point(10, 10), v2->location_);
637 EXPECT_EQ(ui::ET_UNKNOWN, v1->last_gesture_event_type_);
639 // Simulate an up so that RootView is no longer targetting |v3|.
640 GestureEventForTest g1_up(ui::ET_GESTURE_END, 110, 110, 0);
641 root->DispatchGestureEvent(&g1_up);
643 v1->Reset();
644 v2->Reset();
645 v3->Reset();
647 // Gesture on |v1|
648 GestureEventForTest g2(ui::ET_GESTURE_TAP, 80, 80, 0);
649 root->DispatchGestureEvent(&g2);
650 EXPECT_EQ(ui::ET_GESTURE_TAP, v1->last_gesture_event_type_);
651 EXPECT_EQ(gfx::Point(80, 80), v1->location_);
652 EXPECT_EQ(ui::ET_UNKNOWN, v2->last_gesture_event_type_);
654 // Send event |g1| again. Even though the coordinates target |v3| it should go
655 // to |v1| as that is the view the touch was initially down on.
656 v1->last_gesture_event_type_ = ui::ET_UNKNOWN;
657 v3->last_gesture_event_type_ = ui::ET_UNKNOWN;
658 root->DispatchGestureEvent(&g1);
659 EXPECT_EQ(ui::ET_GESTURE_TAP, v1->last_gesture_event_type_);
660 EXPECT_EQ(ui::ET_UNKNOWN, v3->last_gesture_event_type_);
661 EXPECT_EQ("110,110", v1->location_.ToString());
663 widget->CloseNow();
666 TEST_F(ViewTest, ScrollGestureEvent) {
667 // Views hierarchy for non delivery of GestureEvent.
668 TestView* v1 = new TestViewConsumeGesture();
669 v1->SetBoundsRect(gfx::Rect(0, 0, 300, 300));
671 TestView* v2 = new TestViewIgnoreScrollGestures();
672 v2->SetBoundsRect(gfx::Rect(100, 100, 100, 100));
674 TestView* v3 = new TestViewIgnoreGesture();
675 v3->SetBoundsRect(gfx::Rect(0, 0, 100, 100));
677 scoped_ptr<Widget> widget(new Widget());
678 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
679 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
680 params.bounds = gfx::Rect(50, 50, 650, 650);
681 widget->Init(params);
682 internal::RootView* root =
683 static_cast<internal::RootView*>(widget->GetRootView());
685 root->AddChildView(v1);
686 v1->AddChildView(v2);
687 v2->AddChildView(v3);
689 // |v3| completely obscures |v2|, but all the gesture events on |v3| should
690 // reach |v2| because |v3| doesn't process any gesture events. However, since
691 // |v2| does process gesture events, gesture events on |v3| or |v2| should not
692 // reach |v1|.
694 v1->Reset();
695 v2->Reset();
696 v3->Reset();
698 // Gesture on |v3|
699 GestureEventForTest g1(ui::ET_GESTURE_TAP, 110, 110, 0);
700 root->DispatchGestureEvent(&g1);
701 EXPECT_EQ(ui::ET_GESTURE_TAP, v2->last_gesture_event_type_);
702 EXPECT_EQ(gfx::Point(10, 10), v2->location_);
703 EXPECT_EQ(ui::ET_UNKNOWN, v1->last_gesture_event_type_);
705 v2->Reset();
707 // Send scroll gestures on |v3|. The gesture should reach |v2|, however,
708 // since it does not process scroll-gesture events, these events should reach
709 // |v1|.
710 GestureEventForTest gscroll_begin(ui::ET_GESTURE_SCROLL_BEGIN, 115, 115, 0);
711 root->DispatchGestureEvent(&gscroll_begin);
712 EXPECT_EQ(ui::ET_UNKNOWN, v2->last_gesture_event_type_);
713 EXPECT_EQ(ui::ET_GESTURE_SCROLL_BEGIN, v1->last_gesture_event_type_);
714 v1->Reset();
716 // Send a second tap on |v1|. The event should reach |v2| since it is the
717 // default gesture handler, and not |v1| (even though it is the view under the
718 // point, and is the scroll event handler).
719 GestureEventForTest second_tap(ui::ET_GESTURE_TAP, 70, 70, 0);
720 root->DispatchGestureEvent(&second_tap);
721 EXPECT_EQ(ui::ET_GESTURE_TAP, v2->last_gesture_event_type_);
722 EXPECT_EQ(ui::ET_UNKNOWN, v1->last_gesture_event_type_);
723 v2->Reset();
725 GestureEventForTest gscroll_end(ui::ET_GESTURE_SCROLL_END, 50, 50, 0);
726 root->DispatchGestureEvent(&gscroll_end);
727 EXPECT_EQ(ui::ET_GESTURE_SCROLL_END, v1->last_gesture_event_type_);
728 v1->Reset();
730 // Simulate an up so that RootView is no longer targetting |v3|.
731 GestureEventForTest g1_up(ui::ET_GESTURE_END, 110, 110, 0);
732 root->DispatchGestureEvent(&g1_up);
733 EXPECT_EQ(ui::ET_GESTURE_END, v2->last_gesture_event_type_);
735 v1->Reset();
736 v2->Reset();
737 v3->Reset();
739 // Gesture on |v1|
740 GestureEventForTest g2(ui::ET_GESTURE_TAP, 80, 80, 0);
741 root->DispatchGestureEvent(&g2);
742 EXPECT_EQ(ui::ET_GESTURE_TAP, v1->last_gesture_event_type_);
743 EXPECT_EQ(gfx::Point(80, 80), v1->location_);
744 EXPECT_EQ(ui::ET_UNKNOWN, v2->last_gesture_event_type_);
746 // Send event |g1| again. Even though the coordinates target |v3| it should go
747 // to |v1| as that is the view the touch was initially down on.
748 v1->last_gesture_event_type_ = ui::ET_UNKNOWN;
749 v3->last_gesture_event_type_ = ui::ET_UNKNOWN;
750 root->DispatchGestureEvent(&g1);
751 EXPECT_EQ(ui::ET_GESTURE_TAP, v1->last_gesture_event_type_);
752 EXPECT_EQ(ui::ET_UNKNOWN, v3->last_gesture_event_type_);
753 EXPECT_EQ("110,110", v1->location_.ToString());
755 widget->CloseNow();
758 ////////////////////////////////////////////////////////////////////////////////
759 // Painting
760 ////////////////////////////////////////////////////////////////////////////////
762 void TestView::Paint(gfx::Canvas* canvas) {
763 canvas->sk_canvas()->getClipBounds(&last_clip_);
766 void TestView::SchedulePaintInRect(const gfx::Rect& rect) {
767 scheduled_paint_rects_.push_back(rect);
768 View::SchedulePaintInRect(rect);
771 void CheckRect(const SkRect& check_rect, const SkRect& target_rect) {
772 EXPECT_EQ(target_rect.fLeft, check_rect.fLeft);
773 EXPECT_EQ(target_rect.fRight, check_rect.fRight);
774 EXPECT_EQ(target_rect.fTop, check_rect.fTop);
775 EXPECT_EQ(target_rect.fBottom, check_rect.fBottom);
778 /* This test is disabled because it is flakey on some systems.
779 TEST_F(ViewTest, DISABLED_Painting) {
780 // Determine if InvalidateRect generates an empty paint rectangle.
781 EmptyWindow paint_window(CRect(50, 50, 650, 650));
782 paint_window.RedrawWindow(CRect(0, 0, 600, 600), NULL,
783 RDW_UPDATENOW | RDW_INVALIDATE | RDW_ALLCHILDREN);
784 bool empty_paint = paint_window.empty_paint();
786 NativeWidgetWin window;
787 window.set_delete_on_destroy(false);
788 window.set_window_style(WS_OVERLAPPEDWINDOW);
789 window.Init(NULL, gfx::Rect(50, 50, 650, 650), NULL);
790 View* root = window.GetRootView();
792 TestView* v1 = new TestView();
793 v1->SetBoundsRect(gfx::Rect(0, 0, 650, 650));
794 root->AddChildView(v1);
796 TestView* v2 = new TestView();
797 v2->SetBoundsRect(gfx::Rect(10, 10, 80, 80));
798 v1->AddChildView(v2);
800 TestView* v3 = new TestView();
801 v3->SetBoundsRect(gfx::Rect(10, 10, 60, 60));
802 v2->AddChildView(v3);
804 TestView* v4 = new TestView();
805 v4->SetBoundsRect(gfx::Rect(10, 200, 100, 100));
806 v1->AddChildView(v4);
808 // Make sure to paint current rects
809 PaintRootView(root, empty_paint);
812 v1->Reset();
813 v2->Reset();
814 v3->Reset();
815 v4->Reset();
816 v3->SchedulePaintInRect(gfx::Rect(10, 10, 10, 10));
817 PaintRootView(root, empty_paint);
819 SkRect tmp_rect;
821 tmp_rect.iset(10, 10, 20, 20);
822 CheckRect(v3->last_clip_, tmp_rect);
824 tmp_rect.iset(20, 20, 30, 30);
825 CheckRect(v2->last_clip_, tmp_rect);
827 tmp_rect.iset(30, 30, 40, 40);
828 CheckRect(v1->last_clip_, tmp_rect);
830 // Make sure v4 was not painted
831 tmp_rect.setEmpty();
832 CheckRect(v4->last_clip_, tmp_rect);
834 window.DestroyWindow();
838 TEST_F(ViewTest, RemoveNotification) {
839 ViewStorage* vs = ViewStorage::GetInstance();
840 Widget* widget = new Widget;
841 widget->Init(CreateParams(Widget::InitParams::TYPE_POPUP));
842 View* root_view = widget->GetRootView();
844 View* v1 = new View;
845 int s1 = vs->CreateStorageID();
846 vs->StoreView(s1, v1);
847 root_view->AddChildView(v1);
848 View* v11 = new View;
849 int s11 = vs->CreateStorageID();
850 vs->StoreView(s11, v11);
851 v1->AddChildView(v11);
852 View* v111 = new View;
853 int s111 = vs->CreateStorageID();
854 vs->StoreView(s111, v111);
855 v11->AddChildView(v111);
856 View* v112 = new View;
857 int s112 = vs->CreateStorageID();
858 vs->StoreView(s112, v112);
859 v11->AddChildView(v112);
860 View* v113 = new View;
861 int s113 = vs->CreateStorageID();
862 vs->StoreView(s113, v113);
863 v11->AddChildView(v113);
864 View* v1131 = new View;
865 int s1131 = vs->CreateStorageID();
866 vs->StoreView(s1131, v1131);
867 v113->AddChildView(v1131);
868 View* v12 = new View;
869 int s12 = vs->CreateStorageID();
870 vs->StoreView(s12, v12);
871 v1->AddChildView(v12);
873 View* v2 = new View;
874 int s2 = vs->CreateStorageID();
875 vs->StoreView(s2, v2);
876 root_view->AddChildView(v2);
877 View* v21 = new View;
878 int s21 = vs->CreateStorageID();
879 vs->StoreView(s21, v21);
880 v2->AddChildView(v21);
881 View* v211 = new View;
882 int s211 = vs->CreateStorageID();
883 vs->StoreView(s211, v211);
884 v21->AddChildView(v211);
886 size_t stored_views = vs->view_count();
888 // Try removing a leaf view.
889 v21->RemoveChildView(v211);
890 EXPECT_EQ(stored_views - 1, vs->view_count());
891 EXPECT_EQ(NULL, vs->RetrieveView(s211));
892 delete v211; // We won't use this one anymore.
894 // Now try removing a view with a hierarchy of depth 1.
895 v11->RemoveChildView(v113);
896 EXPECT_EQ(stored_views - 3, vs->view_count());
897 EXPECT_EQ(NULL, vs->RetrieveView(s113));
898 EXPECT_EQ(NULL, vs->RetrieveView(s1131));
899 delete v113; // We won't use this one anymore.
901 // Now remove even more.
902 root_view->RemoveChildView(v1);
903 EXPECT_EQ(NULL, vs->RetrieveView(s1));
904 EXPECT_EQ(NULL, vs->RetrieveView(s11));
905 EXPECT_EQ(NULL, vs->RetrieveView(s12));
906 EXPECT_EQ(NULL, vs->RetrieveView(s111));
907 EXPECT_EQ(NULL, vs->RetrieveView(s112));
909 // Put v1 back for more tests.
910 root_view->AddChildView(v1);
911 vs->StoreView(s1, v1);
913 // Synchronously closing the window deletes the view hierarchy, which should
914 // remove all its views from ViewStorage.
915 widget->CloseNow();
916 EXPECT_EQ(stored_views - 10, vs->view_count());
917 EXPECT_EQ(NULL, vs->RetrieveView(s1));
918 EXPECT_EQ(NULL, vs->RetrieveView(s12));
919 EXPECT_EQ(NULL, vs->RetrieveView(s11));
920 EXPECT_EQ(NULL, vs->RetrieveView(s12));
921 EXPECT_EQ(NULL, vs->RetrieveView(s21));
922 EXPECT_EQ(NULL, vs->RetrieveView(s111));
923 EXPECT_EQ(NULL, vs->RetrieveView(s112));
926 namespace {
927 class HitTestView : public View {
928 public:
929 explicit HitTestView(bool has_hittest_mask)
930 : has_hittest_mask_(has_hittest_mask) {
932 virtual ~HitTestView() {}
934 protected:
935 // Overridden from View:
936 virtual bool HasHitTestMask() const OVERRIDE {
937 return has_hittest_mask_;
939 virtual void GetHitTestMask(HitTestSource source,
940 gfx::Path* mask) const OVERRIDE {
941 DCHECK(has_hittest_mask_);
942 DCHECK(mask);
944 SkScalar w = SkIntToScalar(width());
945 SkScalar h = SkIntToScalar(height());
947 // Create a triangular mask within the bounds of this View.
948 mask->moveTo(w / 2, 0);
949 mask->lineTo(w, h);
950 mask->lineTo(0, h);
951 mask->close();
954 private:
955 bool has_hittest_mask_;
957 DISALLOW_COPY_AND_ASSIGN(HitTestView);
960 gfx::Point ConvertPointToView(View* view, const gfx::Point& p) {
961 gfx::Point tmp(p);
962 View::ConvertPointToTarget(view->GetWidget()->GetRootView(), view, &tmp);
963 return tmp;
966 gfx::Rect ConvertRectToView(View* view, const gfx::Rect& r) {
967 gfx::Rect tmp(r);
968 tmp.set_origin(ConvertPointToView(view, r.origin()));
969 return tmp;
972 void RotateCounterclockwise(gfx::Transform* transform) {
973 transform->matrix().set3x3(0, -1, 0,
974 1, 0, 0,
975 0, 0, 1);
978 void RotateClockwise(gfx::Transform* transform) {
979 transform->matrix().set3x3( 0, 1, 0,
980 -1, 0, 0,
981 0, 0, 1);
984 } // namespace
986 TEST_F(ViewTest, HitTestMasks) {
987 Widget* widget = new Widget;
988 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
989 widget->Init(params);
990 View* root_view = widget->GetRootView();
991 root_view->SetBoundsRect(gfx::Rect(0, 0, 500, 500));
993 gfx::Rect v1_bounds = gfx::Rect(0, 0, 100, 100);
994 HitTestView* v1 = new HitTestView(false);
995 v1->SetBoundsRect(v1_bounds);
996 root_view->AddChildView(v1);
998 gfx::Rect v2_bounds = gfx::Rect(105, 0, 100, 100);
999 HitTestView* v2 = new HitTestView(true);
1000 v2->SetBoundsRect(v2_bounds);
1001 root_view->AddChildView(v2);
1003 gfx::Point v1_centerpoint = v1_bounds.CenterPoint();
1004 gfx::Point v2_centerpoint = v2_bounds.CenterPoint();
1005 gfx::Point v1_origin = v1_bounds.origin();
1006 gfx::Point v2_origin = v2_bounds.origin();
1008 gfx::Rect r1(10, 10, 110, 15);
1009 gfx::Rect r2(106, 1, 98, 98);
1010 gfx::Rect r3(0, 0, 300, 300);
1011 gfx::Rect r4(115, 342, 200, 10);
1013 // Test HitTestPoint
1014 EXPECT_TRUE(v1->HitTestPoint(ConvertPointToView(v1, v1_centerpoint)));
1015 EXPECT_TRUE(v2->HitTestPoint(ConvertPointToView(v2, v2_centerpoint)));
1017 EXPECT_TRUE(v1->HitTestPoint(ConvertPointToView(v1, v1_origin)));
1018 EXPECT_FALSE(v2->HitTestPoint(ConvertPointToView(v2, v2_origin)));
1020 // Test HitTestRect
1021 EXPECT_TRUE(v1->HitTestRect(ConvertRectToView(v1, r1)));
1022 EXPECT_FALSE(v2->HitTestRect(ConvertRectToView(v2, r1)));
1024 EXPECT_FALSE(v1->HitTestRect(ConvertRectToView(v1, r2)));
1025 EXPECT_TRUE(v2->HitTestRect(ConvertRectToView(v2, r2)));
1027 EXPECT_TRUE(v1->HitTestRect(ConvertRectToView(v1, r3)));
1028 EXPECT_TRUE(v2->HitTestRect(ConvertRectToView(v2, r3)));
1030 EXPECT_FALSE(v1->HitTestRect(ConvertRectToView(v1, r4)));
1031 EXPECT_FALSE(v2->HitTestRect(ConvertRectToView(v2, r4)));
1033 // Test GetEventHandlerForPoint
1034 EXPECT_EQ(v1, root_view->GetEventHandlerForPoint(v1_centerpoint));
1035 EXPECT_EQ(v2, root_view->GetEventHandlerForPoint(v2_centerpoint));
1037 EXPECT_EQ(v1, root_view->GetEventHandlerForPoint(v1_origin));
1038 EXPECT_EQ(root_view, root_view->GetEventHandlerForPoint(v2_origin));
1040 // Test GetTooltipHandlerForPoint
1041 EXPECT_EQ(v1, root_view->GetTooltipHandlerForPoint(v1_centerpoint));
1042 EXPECT_EQ(v2, root_view->GetTooltipHandlerForPoint(v2_centerpoint));
1044 EXPECT_EQ(v1, root_view->GetTooltipHandlerForPoint(v1_origin));
1045 EXPECT_EQ(root_view, root_view->GetTooltipHandlerForPoint(v2_origin));
1047 EXPECT_FALSE(v1->GetTooltipHandlerForPoint(v2_origin));
1049 widget->CloseNow();
1052 TEST_F(ViewTest, GetEventHandlerForRect) {
1053 Widget* widget = new Widget;
1054 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
1055 widget->Init(params);
1056 View* root_view = widget->GetRootView();
1057 root_view->SetBoundsRect(gfx::Rect(0, 0, 500, 500));
1059 // Have this hierarchy of views (the coordinates here are all in
1060 // the root view's coordinate space):
1061 // v1 (0, 0, 100, 100)
1062 // v2 (150, 0, 250, 100)
1063 // v3 (0, 200, 150, 100)
1064 // v31 (10, 210, 80, 80)
1065 // v32 (110, 210, 30, 80)
1066 // v4 (300, 200, 100, 100)
1067 // v41 (310, 210, 80, 80)
1068 // v411 (370, 275, 10, 5)
1070 // The coordinates used for SetBounds are in parent coordinates.
1072 TestView* v1 = new TestView;
1073 v1->SetBounds(0, 0, 100, 100);
1074 root_view->AddChildView(v1);
1076 TestView* v2 = new TestView;
1077 v2->SetBounds(150, 0, 250, 100);
1078 root_view->AddChildView(v2);
1080 TestView* v3 = new TestView;
1081 v3->SetBounds(0, 200, 150, 100);
1082 root_view->AddChildView(v3);
1084 TestView* v4 = new TestView;
1085 v4->SetBounds(300, 200, 100, 100);
1086 root_view->AddChildView(v4);
1088 TestView* v31 = new TestView;
1089 v31->SetBounds(10, 10, 80, 80);
1090 v3->AddChildView(v31);
1092 TestView* v32 = new TestView;
1093 v32->SetBounds(110, 10, 30, 80);
1094 v3->AddChildView(v32);
1096 TestView* v41 = new TestView;
1097 v41->SetBounds(10, 10, 80, 80);
1098 v4->AddChildView(v41);
1100 TestView* v411 = new TestView;
1101 v411->SetBounds(60, 65, 10, 5);
1102 v41->AddChildView(v411);
1104 // |touch_rect| does not intersect any descendant view of |root_view|.
1105 gfx::Rect touch_rect(105, 105, 30, 45);
1106 View* result_view = root_view->GetEventHandlerForRect(touch_rect);
1107 EXPECT_EQ(root_view, result_view);
1108 result_view = NULL;
1110 // Covers |v1| by at least 60%.
1111 touch_rect.SetRect(15, 15, 100, 100);
1112 result_view = root_view->GetEventHandlerForRect(touch_rect);
1113 EXPECT_EQ(v1, result_view);
1114 result_view = NULL;
1116 // Intersects |v1| but does not cover it by at least 60%. The center
1117 // of |touch_rect| is within |v1|.
1118 touch_rect.SetRect(50, 50, 5, 10);
1119 result_view = root_view->GetEventHandlerForRect(touch_rect);
1120 EXPECT_EQ(v1, result_view);
1121 result_view = NULL;
1123 // Intersects |v1| but does not cover it by at least 60%. The center
1124 // of |touch_rect| is not within |v1|.
1125 touch_rect.SetRect(95, 96, 21, 22);
1126 result_view = root_view->GetEventHandlerForRect(touch_rect);
1127 EXPECT_EQ(root_view, result_view);
1128 result_view = NULL;
1130 // Intersects |v1| and |v2|, but only covers |v2| by at least 60%.
1131 touch_rect.SetRect(95, 10, 300, 120);
1132 result_view = root_view->GetEventHandlerForRect(touch_rect);
1133 EXPECT_EQ(v2, result_view);
1134 result_view = NULL;
1136 // Covers both |v1| and |v2| by at least 60%, but the center point
1137 // of |touch_rect| is closer to the center line of |v2|.
1138 touch_rect.SetRect(20, 20, 400, 100);
1139 result_view = root_view->GetEventHandlerForRect(touch_rect);
1140 EXPECT_EQ(v2, result_view);
1141 result_view = NULL;
1143 // Covers both |v1| and |v2| by at least 60%, but the center point
1144 // of |touch_rect| is closer to the center line (point) of |v1|.
1145 touch_rect.SetRect(-700, -15, 1050, 110);
1146 result_view = root_view->GetEventHandlerForRect(touch_rect);
1147 EXPECT_EQ(v1, result_view);
1148 result_view = NULL;
1150 // A mouse click within |v1| will target |v1|.
1151 touch_rect.SetRect(15, 15, 1, 1);
1152 result_view = root_view->GetEventHandlerForRect(touch_rect);
1153 EXPECT_EQ(v1, result_view);
1154 result_view = NULL;
1156 // Intersects |v3| and |v31| by at least 60% and the center point
1157 // of |touch_rect| is closer to the center line of |v3|.
1158 touch_rect.SetRect(0, 200, 110, 100);
1159 result_view = root_view->GetEventHandlerForRect(touch_rect);
1160 EXPECT_EQ(v3, result_view);
1161 result_view = NULL;
1163 // Intersects |v3| and |v31| by at least 60% and the center point
1164 // of |touch_rect| is equally close to the center lines of both.
1165 touch_rect.SetRect(-60, 140, 200, 200);
1166 result_view = root_view->GetEventHandlerForRect(touch_rect);
1167 EXPECT_EQ(v31, result_view);
1168 result_view = NULL;
1170 // Intersects |v3| and |v31|, but neither by at least 60%. The
1171 // center point of |touch_rect| lies within |v31|.
1172 touch_rect.SetRect(80, 280, 15, 15);
1173 result_view = root_view->GetEventHandlerForRect(touch_rect);
1174 EXPECT_EQ(v31, result_view);
1175 result_view = NULL;
1177 // Covers |v3|, |v31|, and |v32| all by at least 60%, and the
1178 // center point of |touch_rect| is closest to the center line
1179 // of |v3|.
1180 touch_rect.SetRect(0, 200, 200, 100);
1181 result_view = root_view->GetEventHandlerForRect(touch_rect);
1182 EXPECT_EQ(v3, result_view);
1183 result_view = NULL;
1185 // Intersects all of |v3|, |v31|, and |v32|, but only covers
1186 // |v31| and |v32| by at least 60%. The center point of
1187 // |touch_rect| is closest to the center line of |v32|.
1188 touch_rect.SetRect(30, 225, 180, 115);
1189 result_view = root_view->GetEventHandlerForRect(touch_rect);
1190 EXPECT_EQ(v32, result_view);
1191 result_view = NULL;
1193 // A mouse click at the corner of |v3| will target |v3|.
1194 touch_rect.SetRect(0, 200, 1, 1);
1195 result_view = root_view->GetEventHandlerForRect(touch_rect);
1196 EXPECT_EQ(v3, result_view);
1197 result_view = NULL;
1199 // A mouse click within |v32| will target |v32|.
1200 touch_rect.SetRect(112, 211, 1, 1);
1201 result_view = root_view->GetEventHandlerForRect(touch_rect);
1202 EXPECT_EQ(v32, result_view);
1203 result_view = NULL;
1205 // Covers all of |v4|, |v41|, and |v411| by at least 60%.
1206 // The center point of |touch_rect| is equally close to
1207 // the center points of |v4| and |v41|.
1208 touch_rect.SetRect(310, 210, 80, 80);
1209 result_view = root_view->GetEventHandlerForRect(touch_rect);
1210 EXPECT_EQ(v41, result_view);
1211 result_view = NULL;
1213 // Intersects all of |v4|, |v41|, and |v411| but only covers
1214 // |v411| by at least 60%.
1215 touch_rect.SetRect(370, 275, 7, 5);
1216 result_view = root_view->GetEventHandlerForRect(touch_rect);
1217 EXPECT_EQ(v411, result_view);
1218 result_view = NULL;
1220 // Intersects |v4| and |v41| but covers neither by at least 60%.
1221 // The center point of |touch_rect| is equally close to the center
1222 // points of |v4| and |v41|.
1223 touch_rect.SetRect(345, 245, 7, 7);
1224 result_view = root_view->GetEventHandlerForRect(touch_rect);
1225 EXPECT_EQ(v41, result_view);
1226 result_view = NULL;
1228 // Intersects all of |v4|, |v41|, and |v411| and covers none of
1229 // them by at least 60%. The center point of |touch_rect| lies
1230 // within |v411|.
1231 touch_rect.SetRect(368, 272, 4, 6);
1232 result_view = root_view->GetEventHandlerForRect(touch_rect);
1233 EXPECT_EQ(v411, result_view);
1234 result_view = NULL;
1236 // Intersects all of |v4|, |v41|, and |v411| and covers none of
1237 // them by at least 60%. The center point of |touch_rect| lies
1238 // within |v41|.
1239 touch_rect.SetRect(365, 270, 7, 7);
1240 result_view = root_view->GetEventHandlerForRect(touch_rect);
1241 EXPECT_EQ(v41, result_view);
1242 result_view = NULL;
1244 // Intersects all of |v4|, |v41|, and |v411| and covers none of
1245 // them by at least 60%. The center point of |touch_rect| lies
1246 // within |v4|.
1247 touch_rect.SetRect(205, 275, 200, 2);
1248 result_view = root_view->GetEventHandlerForRect(touch_rect);
1249 EXPECT_EQ(v4, result_view);
1250 result_view = NULL;
1252 // Intersects all of |v4|, |v41|, and |v411| but only covers
1253 // |v41| by at least 60%.
1254 touch_rect.SetRect(310, 210, 61, 66);
1255 result_view = root_view->GetEventHandlerForRect(touch_rect);
1256 EXPECT_EQ(v41, result_view);
1257 result_view = NULL;
1259 // A mouse click within |v411| will target |v411|.
1260 touch_rect.SetRect(372, 275, 1, 1);
1261 result_view = root_view->GetEventHandlerForRect(touch_rect);
1262 EXPECT_EQ(v411, result_view);
1263 result_view = NULL;
1265 // A mouse click within |v41| will target |v41|.
1266 touch_rect.SetRect(350, 215, 1, 1);
1267 result_view = root_view->GetEventHandlerForRect(touch_rect);
1268 EXPECT_EQ(v41, result_view);
1269 result_view = NULL;
1271 // Covers |v3|, |v4|, and all of their descendants by at
1272 // least 60%. The center point of |touch_rect| is closest
1273 // to the center line of |v32|.
1274 touch_rect.SetRect(0, 200, 400, 100);
1275 result_view = root_view->GetEventHandlerForRect(touch_rect);
1276 EXPECT_EQ(v32, result_view);
1277 result_view = NULL;
1279 // Intersects all of |v2|, |v3|, |v32|, |v4|, |v41|, and |v411|.
1280 // Covers |v2|, |v32|, |v4|, |v41|, and |v411| by at least 60%.
1281 // The center point of |touch_rect| is closest to the center
1282 // point of |root_view|.
1283 touch_rect.SetRect(110, 15, 375, 450);
1284 result_view = root_view->GetEventHandlerForRect(touch_rect);
1285 EXPECT_EQ(root_view, result_view);
1286 result_view = NULL;
1288 // Covers all views by at least 60%. The center point of
1289 // |touch_rect| is closest to the center line of |v2|.
1290 touch_rect.SetRect(0, 0, 400, 300);
1291 result_view = root_view->GetEventHandlerForRect(touch_rect);
1292 EXPECT_EQ(v2, result_view);
1293 result_view = NULL;
1295 widget->CloseNow();
1298 TEST_F(ViewTest, NotifyEnterExitOnChild) {
1299 Widget* widget = new Widget;
1300 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
1301 widget->Init(params);
1302 View* root_view = widget->GetRootView();
1303 root_view->SetBoundsRect(gfx::Rect(0, 0, 500, 500));
1305 // Have this hierarchy of views (the coords here are in root coord):
1306 // v1 (0, 0, 100, 100)
1307 // - v11 (0, 0, 20, 30)
1308 // - v111 (5, 5, 5, 15)
1309 // - v12 (50, 10, 30, 90)
1310 // - v121 (60, 20, 10, 10)
1311 // v2 (105, 0, 100, 100)
1312 // - v21 (120, 10, 50, 20)
1314 TestView* v1 = new TestView;
1315 v1->SetBounds(0, 0, 100, 100);
1316 root_view->AddChildView(v1);
1317 v1->set_notify_enter_exit_on_child(true);
1319 TestView* v11 = new TestView;
1320 v11->SetBounds(0, 0, 20, 30);
1321 v1->AddChildView(v11);
1323 TestView* v111 = new TestView;
1324 v111->SetBounds(5, 5, 5, 15);
1325 v11->AddChildView(v111);
1327 TestView* v12 = new TestView;
1328 v12->SetBounds(50, 10, 30, 90);
1329 v1->AddChildView(v12);
1331 TestView* v121 = new TestView;
1332 v121->SetBounds(10, 10, 10, 10);
1333 v12->AddChildView(v121);
1335 TestView* v2 = new TestView;
1336 v2->SetBounds(105, 0, 100, 100);
1337 root_view->AddChildView(v2);
1339 TestView* v21 = new TestView;
1340 v21->SetBounds(15, 10, 50, 20);
1341 v2->AddChildView(v21);
1343 v1->Reset();
1344 v11->Reset();
1345 v111->Reset();
1346 v12->Reset();
1347 v121->Reset();
1348 v2->Reset();
1349 v21->Reset();
1351 // Move the mouse in v111.
1352 gfx::Point p1(6, 6);
1353 ui::MouseEvent move1(ui::ET_MOUSE_MOVED, p1, p1, 0);
1354 root_view->OnMouseMoved(move1);
1355 EXPECT_TRUE(v111->received_mouse_enter_);
1356 EXPECT_FALSE(v11->last_mouse_event_type_);
1357 EXPECT_TRUE(v1->received_mouse_enter_);
1359 v111->Reset();
1360 v1->Reset();
1362 // Now, move into v121.
1363 gfx::Point p2(65, 21);
1364 ui::MouseEvent move2(ui::ET_MOUSE_MOVED, p2, p2, 0);
1365 root_view->OnMouseMoved(move2);
1366 EXPECT_TRUE(v111->received_mouse_exit_);
1367 EXPECT_TRUE(v121->received_mouse_enter_);
1368 EXPECT_FALSE(v1->last_mouse_event_type_);
1370 v111->Reset();
1371 v121->Reset();
1373 // Now, move into v11.
1374 gfx::Point p3(1, 1);
1375 ui::MouseEvent move3(ui::ET_MOUSE_MOVED, p3, p3, 0);
1376 root_view->OnMouseMoved(move3);
1377 EXPECT_TRUE(v121->received_mouse_exit_);
1378 EXPECT_TRUE(v11->received_mouse_enter_);
1379 EXPECT_FALSE(v1->last_mouse_event_type_);
1381 v121->Reset();
1382 v11->Reset();
1384 // Move to v21.
1385 gfx::Point p4(121, 15);
1386 ui::MouseEvent move4(ui::ET_MOUSE_MOVED, p4, p4, 0);
1387 root_view->OnMouseMoved(move4);
1388 EXPECT_TRUE(v21->received_mouse_enter_);
1389 EXPECT_FALSE(v2->last_mouse_event_type_);
1390 EXPECT_TRUE(v11->received_mouse_exit_);
1391 EXPECT_TRUE(v1->received_mouse_exit_);
1393 v21->Reset();
1394 v11->Reset();
1395 v1->Reset();
1397 // Move to v1.
1398 gfx::Point p5(21, 0);
1399 ui::MouseEvent move5(ui::ET_MOUSE_MOVED, p5, p5, 0);
1400 root_view->OnMouseMoved(move5);
1401 EXPECT_TRUE(v21->received_mouse_exit_);
1402 EXPECT_TRUE(v1->received_mouse_enter_);
1404 v21->Reset();
1405 v1->Reset();
1407 // Now, move into v11.
1408 gfx::Point p6(15, 15);
1409 ui::MouseEvent mouse6(ui::ET_MOUSE_MOVED, p6, p6, 0);
1410 root_view->OnMouseMoved(mouse6);
1411 EXPECT_TRUE(v11->received_mouse_enter_);
1412 EXPECT_FALSE(v1->last_mouse_event_type_);
1414 v11->Reset();
1415 v1->Reset();
1417 // Move back into v1. Although |v1| had already received an ENTER for mouse6,
1418 // and the mouse remains inside |v1| the whole time, it receives another ENTER
1419 // when the mouse leaves v11.
1420 gfx::Point p7(21, 0);
1421 ui::MouseEvent mouse7(ui::ET_MOUSE_MOVED, p7, p7, 0);
1422 root_view->OnMouseMoved(mouse7);
1423 EXPECT_TRUE(v11->received_mouse_exit_);
1424 EXPECT_FALSE(v1->received_mouse_enter_);
1426 widget->CloseNow();
1429 TEST_F(ViewTest, Textfield) {
1430 const string16 kText = ASCIIToUTF16("Reality is that which, when you stop "
1431 "believing it, doesn't go away.");
1432 const string16 kExtraText = ASCIIToUTF16("Pretty deep, Philip!");
1433 const string16 kEmptyString;
1435 Widget* widget = new Widget;
1436 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
1437 params.bounds = gfx::Rect(0, 0, 100, 100);
1438 widget->Init(params);
1439 View* root_view = widget->GetRootView();
1441 Textfield* textfield = new Textfield();
1442 root_view->AddChildView(textfield);
1444 // Test setting, appending text.
1445 textfield->SetText(kText);
1446 EXPECT_EQ(kText, textfield->text());
1447 textfield->AppendText(kExtraText);
1448 EXPECT_EQ(kText + kExtraText, textfield->text());
1449 textfield->SetText(string16());
1450 EXPECT_EQ(kEmptyString, textfield->text());
1452 // Test selection related methods.
1453 textfield->SetText(kText);
1454 EXPECT_EQ(kEmptyString, textfield->GetSelectedText());
1455 textfield->SelectAll(false);
1456 EXPECT_EQ(kText, textfield->text());
1457 textfield->ClearSelection();
1458 EXPECT_EQ(kEmptyString, textfield->GetSelectedText());
1460 widget->CloseNow();
1463 // Tests that the Textfield view respond appropiately to cut/copy/paste.
1464 TEST_F(ViewTest, TextfieldCutCopyPaste) {
1465 const string16 kNormalText = ASCIIToUTF16("Normal");
1466 const string16 kReadOnlyText = ASCIIToUTF16("Read only");
1467 const string16 kPasswordText = ASCIIToUTF16("Password! ** Secret stuff **");
1469 ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
1471 Widget* widget = new Widget;
1472 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
1473 params.bounds = gfx::Rect(0, 0, 100, 100);
1474 widget->Init(params);
1475 View* root_view = widget->GetRootView();
1477 Textfield* normal = new Textfield();
1478 Textfield* read_only = new Textfield();
1479 read_only->SetReadOnly(true);
1480 Textfield* password = new Textfield(Textfield::STYLE_OBSCURED);
1482 root_view->AddChildView(normal);
1483 root_view->AddChildView(read_only);
1484 root_view->AddChildView(password);
1486 normal->SetText(kNormalText);
1487 read_only->SetText(kReadOnlyText);
1488 password->SetText(kPasswordText);
1491 // Test cut.
1494 normal->SelectAll(false);
1495 normal->ExecuteCommand(IDS_APP_CUT);
1496 string16 result;
1497 clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &result);
1498 EXPECT_EQ(kNormalText, result);
1499 normal->SetText(kNormalText); // Let's revert to the original content.
1501 read_only->SelectAll(false);
1502 read_only->ExecuteCommand(IDS_APP_CUT);
1503 result.clear();
1504 clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &result);
1505 // Cut should have failed, so the clipboard content should not have changed.
1506 EXPECT_EQ(kNormalText, result);
1508 password->SelectAll(false);
1509 password->ExecuteCommand(IDS_APP_CUT);
1510 result.clear();
1511 clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &result);
1512 // Cut should have failed, so the clipboard content should not have changed.
1513 EXPECT_EQ(kNormalText, result);
1516 // Test copy.
1519 // Start with |read_only| to observe a change in clipboard text.
1520 read_only->SelectAll(false);
1521 read_only->ExecuteCommand(IDS_APP_COPY);
1522 result.clear();
1523 clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &result);
1524 EXPECT_EQ(kReadOnlyText, result);
1526 normal->SelectAll(false);
1527 normal->ExecuteCommand(IDS_APP_COPY);
1528 result.clear();
1529 clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &result);
1530 EXPECT_EQ(kNormalText, result);
1532 password->SelectAll(false);
1533 password->ExecuteCommand(IDS_APP_COPY);
1534 result.clear();
1535 clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &result);
1536 // Text cannot be copied from an obscured field; the clipboard won't change.
1537 EXPECT_EQ(kNormalText, result);
1540 // Test paste.
1543 // Attempting to paste kNormalText in a read-only text-field should fail.
1544 read_only->SelectAll(false);
1545 read_only->ExecuteCommand(IDS_APP_PASTE);
1546 EXPECT_EQ(kReadOnlyText, read_only->text());
1548 password->SelectAll(false);
1549 password->ExecuteCommand(IDS_APP_PASTE);
1550 EXPECT_EQ(kNormalText, password->text());
1552 // Copy from |read_only| to observe a change in the normal textfield text.
1553 read_only->SelectAll(false);
1554 read_only->ExecuteCommand(IDS_APP_COPY);
1555 normal->SelectAll(false);
1556 normal->ExecuteCommand(IDS_APP_PASTE);
1557 EXPECT_EQ(kReadOnlyText, normal->text());
1558 widget->CloseNow();
1561 ////////////////////////////////////////////////////////////////////////////////
1562 // Accelerators
1563 ////////////////////////////////////////////////////////////////////////////////
1564 bool TestView::AcceleratorPressed(const ui::Accelerator& accelerator) {
1565 accelerator_count_map_[accelerator]++;
1566 return true;
1569 #if defined(OS_WIN) && !defined(USE_AURA)
1570 TEST_F(ViewTest, ActivateAccelerator) {
1571 // Register a keyboard accelerator before the view is added to a window.
1572 ui::Accelerator return_accelerator(ui::VKEY_RETURN, ui::EF_NONE);
1573 TestView* view = new TestView();
1574 view->Reset();
1575 view->AddAccelerator(return_accelerator);
1576 EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 0);
1578 // Create a window and add the view as its child.
1579 scoped_ptr<Widget> widget(new Widget);
1580 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
1581 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1582 params.bounds = gfx::Rect(0, 0, 100, 100);
1583 widget->Init(params);
1584 View* root = widget->GetRootView();
1585 root->AddChildView(view);
1586 widget->Show();
1588 // Get the focus manager.
1589 FocusManager* focus_manager = widget->GetFocusManager();
1590 ASSERT_TRUE(focus_manager);
1592 // Hit the return key and see if it takes effect.
1593 EXPECT_TRUE(focus_manager->ProcessAccelerator(return_accelerator));
1594 EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 1);
1596 // Hit the escape key. Nothing should happen.
1597 ui::Accelerator escape_accelerator(ui::VKEY_ESCAPE, ui::EF_NONE);
1598 EXPECT_FALSE(focus_manager->ProcessAccelerator(escape_accelerator));
1599 EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 1);
1600 EXPECT_EQ(view->accelerator_count_map_[escape_accelerator], 0);
1602 // Now register the escape key and hit it again.
1603 view->AddAccelerator(escape_accelerator);
1604 EXPECT_TRUE(focus_manager->ProcessAccelerator(escape_accelerator));
1605 EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 1);
1606 EXPECT_EQ(view->accelerator_count_map_[escape_accelerator], 1);
1608 // Remove the return key accelerator.
1609 view->RemoveAccelerator(return_accelerator);
1610 EXPECT_FALSE(focus_manager->ProcessAccelerator(return_accelerator));
1611 EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 1);
1612 EXPECT_EQ(view->accelerator_count_map_[escape_accelerator], 1);
1614 // Add it again. Hit the return key and the escape key.
1615 view->AddAccelerator(return_accelerator);
1616 EXPECT_TRUE(focus_manager->ProcessAccelerator(return_accelerator));
1617 EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 2);
1618 EXPECT_EQ(view->accelerator_count_map_[escape_accelerator], 1);
1619 EXPECT_TRUE(focus_manager->ProcessAccelerator(escape_accelerator));
1620 EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 2);
1621 EXPECT_EQ(view->accelerator_count_map_[escape_accelerator], 2);
1623 // Remove all the accelerators.
1624 view->ResetAccelerators();
1625 EXPECT_FALSE(focus_manager->ProcessAccelerator(return_accelerator));
1626 EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 2);
1627 EXPECT_EQ(view->accelerator_count_map_[escape_accelerator], 2);
1628 EXPECT_FALSE(focus_manager->ProcessAccelerator(escape_accelerator));
1629 EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 2);
1630 EXPECT_EQ(view->accelerator_count_map_[escape_accelerator], 2);
1632 widget->CloseNow();
1634 #endif
1636 #if defined(OS_WIN) && !defined(USE_AURA)
1637 TEST_F(ViewTest, HiddenViewWithAccelerator) {
1638 ui::Accelerator return_accelerator(ui::VKEY_RETURN, ui::EF_NONE);
1639 TestView* view = new TestView();
1640 view->Reset();
1641 view->AddAccelerator(return_accelerator);
1642 EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 0);
1644 scoped_ptr<Widget> widget(new Widget);
1645 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
1646 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1647 params.bounds = gfx::Rect(0, 0, 100, 100);
1648 widget->Init(params);
1649 View* root = widget->GetRootView();
1650 root->AddChildView(view);
1651 widget->Show();
1653 FocusManager* focus_manager = widget->GetFocusManager();
1654 ASSERT_TRUE(focus_manager);
1656 view->SetVisible(false);
1657 EXPECT_FALSE(focus_manager->ProcessAccelerator(return_accelerator));
1659 view->SetVisible(true);
1660 EXPECT_TRUE(focus_manager->ProcessAccelerator(return_accelerator));
1662 widget->CloseNow();
1664 #endif
1666 #if defined(OS_WIN) && !defined(USE_AURA)
1667 TEST_F(ViewTest, ViewInHiddenWidgetWithAccelerator) {
1668 ui::Accelerator return_accelerator(ui::VKEY_RETURN, ui::EF_NONE);
1669 TestView* view = new TestView();
1670 view->Reset();
1671 view->AddAccelerator(return_accelerator);
1672 EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 0);
1674 scoped_ptr<Widget> widget(new Widget);
1675 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
1676 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1677 params.bounds = gfx::Rect(0, 0, 100, 100);
1678 widget->Init(params);
1679 View* root = widget->GetRootView();
1680 root->AddChildView(view);
1682 FocusManager* focus_manager = widget->GetFocusManager();
1683 ASSERT_TRUE(focus_manager);
1685 EXPECT_FALSE(focus_manager->ProcessAccelerator(return_accelerator));
1686 EXPECT_EQ(0, view->accelerator_count_map_[return_accelerator]);
1688 widget->Show();
1689 EXPECT_TRUE(focus_manager->ProcessAccelerator(return_accelerator));
1690 EXPECT_EQ(1, view->accelerator_count_map_[return_accelerator]);
1692 widget->Hide();
1693 EXPECT_FALSE(focus_manager->ProcessAccelerator(return_accelerator));
1694 EXPECT_EQ(1, view->accelerator_count_map_[return_accelerator]);
1696 widget->CloseNow();
1698 #endif
1700 #if defined(OS_WIN) && !defined(USE_AURA)
1701 ////////////////////////////////////////////////////////////////////////////////
1702 // Mouse-wheel message rerouting
1703 ////////////////////////////////////////////////////////////////////////////////
1704 class ScrollableTestView : public View {
1705 public:
1706 ScrollableTestView() { }
1708 virtual gfx::Size GetPreferredSize() {
1709 return gfx::Size(100, 10000);
1712 virtual void Layout() {
1713 SizeToPreferredSize();
1717 class TestViewWithControls : public View {
1718 public:
1719 TestViewWithControls() {
1720 text_field_ = new Textfield();
1721 AddChildView(text_field_);
1724 Textfield* text_field_;
1727 class SimpleWidgetDelegate : public WidgetDelegate {
1728 public:
1729 explicit SimpleWidgetDelegate(View* contents) : contents_(contents) { }
1731 virtual void DeleteDelegate() { delete this; }
1733 virtual View* GetContentsView() { return contents_; }
1735 virtual Widget* GetWidget() { return contents_->GetWidget(); }
1736 virtual const Widget* GetWidget() const { return contents_->GetWidget(); }
1738 private:
1739 View* contents_;
1742 // Tests that the mouse-wheel messages are correctly rerouted to the window
1743 // under the mouse.
1744 // TODO(jcampan): http://crbug.com/10572 Disabled as it fails on the Vista build
1745 // bot.
1746 // Note that this fails for a variety of reasons:
1747 // - focused view is apparently reset across window activations and never
1748 // properly restored
1749 // - this test depends on you not having any other window visible open under the
1750 // area that it opens the test windows. --beng
1751 TEST_F(ViewTest, DISABLED_RerouteMouseWheelTest) {
1752 TestViewWithControls* view_with_controls = new TestViewWithControls();
1753 Widget* window1 = Widget::CreateWindowWithBounds(
1754 new SimpleWidgetDelegate(view_with_controls),
1755 gfx::Rect(0, 0, 100, 100));
1756 window1->Show();
1757 ScrollView* scroll_view = new ScrollView();
1758 scroll_view->SetContents(new ScrollableTestView());
1759 Widget* window2 = Widget::CreateWindowWithBounds(
1760 new SimpleWidgetDelegate(scroll_view),
1761 gfx::Rect(200, 200, 100, 100));
1762 window2->Show();
1763 EXPECT_EQ(0, scroll_view->GetVisibleRect().y());
1765 // Make the window1 active, as this is what it would be in real-world.
1766 window1->Activate();
1768 // Let's send a mouse-wheel message to the different controls and check that
1769 // it is rerouted to the window under the mouse (effectively scrolling the
1770 // scroll-view).
1772 // First to the Window's HWND.
1773 ::SendMessage(view_with_controls->GetWidget()->GetNativeView(),
1774 WM_MOUSEWHEEL, MAKEWPARAM(0, -20), MAKELPARAM(250, 250));
1775 EXPECT_EQ(20, scroll_view->GetVisibleRect().y());
1777 // Then the text-field.
1778 ::SendMessage(view_with_controls->text_field_->GetTestingHandle(),
1779 WM_MOUSEWHEEL, MAKEWPARAM(0, -20), MAKELPARAM(250, 250));
1780 EXPECT_EQ(80, scroll_view->GetVisibleRect().y());
1782 // Ensure we don't scroll when the mouse is not over that window.
1783 ::SendMessage(view_with_controls->text_field_->GetTestingHandle(),
1784 WM_MOUSEWHEEL, MAKEWPARAM(0, -20), MAKELPARAM(50, 50));
1785 EXPECT_EQ(80, scroll_view->GetVisibleRect().y());
1787 window1->CloseNow();
1788 window2->CloseNow();
1790 #endif
1792 ////////////////////////////////////////////////////////////////////////////////
1793 // Native view hierachy
1794 ////////////////////////////////////////////////////////////////////////////////
1795 class ToplevelWidgetObserverView : public View {
1796 public:
1797 ToplevelWidgetObserverView() : toplevel_(NULL) {
1799 virtual ~ToplevelWidgetObserverView() {
1802 // View overrides:
1803 virtual void ViewHierarchyChanged(
1804 const ViewHierarchyChangedDetails& details) OVERRIDE {
1805 if (details.is_add) {
1806 toplevel_ = GetWidget() ? GetWidget()->GetTopLevelWidget() : NULL;
1807 } else {
1808 toplevel_ = NULL;
1811 virtual void NativeViewHierarchyChanged() OVERRIDE {
1812 toplevel_ = GetWidget() ? GetWidget()->GetTopLevelWidget() : NULL;
1815 Widget* toplevel() { return toplevel_; }
1817 private:
1818 Widget* toplevel_;
1820 DISALLOW_COPY_AND_ASSIGN(ToplevelWidgetObserverView);
1823 // Test that a view can track the current top level widget by overriding
1824 // View::ViewHierarchyChanged() and View::NativeViewHierarchyChanged().
1825 TEST_F(ViewTest, NativeViewHierarchyChanged) {
1826 scoped_ptr<Widget> toplevel1(new Widget);
1827 Widget::InitParams toplevel1_params =
1828 CreateParams(Widget::InitParams::TYPE_POPUP);
1829 toplevel1_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1830 toplevel1->Init(toplevel1_params);
1832 scoped_ptr<Widget> toplevel2(new Widget);
1833 Widget::InitParams toplevel2_params =
1834 CreateParams(Widget::InitParams::TYPE_POPUP);
1835 toplevel2_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
1836 toplevel2->Init(toplevel2_params);
1838 Widget* child = new Widget;
1839 Widget::InitParams child_params(Widget::InitParams::TYPE_CONTROL);
1840 child_params.parent = toplevel1->GetNativeView();
1841 child->Init(child_params);
1843 ToplevelWidgetObserverView* observer_view =
1844 new ToplevelWidgetObserverView();
1845 EXPECT_EQ(NULL, observer_view->toplevel());
1847 child->SetContentsView(observer_view);
1848 EXPECT_EQ(toplevel1, observer_view->toplevel());
1850 Widget::ReparentNativeView(child->GetNativeView(),
1851 toplevel2->GetNativeView());
1852 EXPECT_EQ(toplevel2, observer_view->toplevel());
1854 observer_view->parent()->RemoveChildView(observer_view);
1855 EXPECT_EQ(NULL, observer_view->toplevel());
1857 // Make |observer_view| |child|'s contents view again so that it gets deleted
1858 // with the widget.
1859 child->SetContentsView(observer_view);
1862 ////////////////////////////////////////////////////////////////////////////////
1863 // Transformations
1864 ////////////////////////////////////////////////////////////////////////////////
1866 class TransformPaintView : public TestView {
1867 public:
1868 TransformPaintView() {}
1869 virtual ~TransformPaintView() {}
1871 void ClearScheduledPaintRect() {
1872 scheduled_paint_rect_ = gfx::Rect();
1875 gfx::Rect scheduled_paint_rect() const { return scheduled_paint_rect_; }
1877 // Overridden from View:
1878 virtual void SchedulePaintInRect(const gfx::Rect& rect) OVERRIDE {
1879 gfx::Rect xrect = ConvertRectToParent(rect);
1880 scheduled_paint_rect_.Union(xrect);
1883 private:
1884 gfx::Rect scheduled_paint_rect_;
1886 DISALLOW_COPY_AND_ASSIGN(TransformPaintView);
1889 TEST_F(ViewTest, TransformPaint) {
1890 TransformPaintView* v1 = new TransformPaintView();
1891 v1->SetBoundsRect(gfx::Rect(0, 0, 500, 300));
1893 TestView* v2 = new TestView();
1894 v2->SetBoundsRect(gfx::Rect(100, 100, 200, 100));
1896 Widget* widget = new Widget;
1897 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
1898 params.bounds = gfx::Rect(50, 50, 650, 650);
1899 widget->Init(params);
1900 widget->Show();
1901 View* root = widget->GetRootView();
1903 root->AddChildView(v1);
1904 v1->AddChildView(v2);
1906 // At this moment, |v2| occupies (100, 100) to (300, 200) in |root|.
1907 v1->ClearScheduledPaintRect();
1908 v2->SchedulePaint();
1910 EXPECT_EQ(gfx::Rect(100, 100, 200, 100), v1->scheduled_paint_rect());
1912 // Rotate |v1| counter-clockwise.
1913 gfx::Transform transform;
1914 RotateCounterclockwise(&transform);
1915 transform.matrix().set(1, 3, 500.0);
1916 v1->SetTransform(transform);
1918 // |v2| now occupies (100, 200) to (200, 400) in |root|.
1920 v1->ClearScheduledPaintRect();
1921 v2->SchedulePaint();
1923 EXPECT_EQ(gfx::Rect(100, 200, 100, 200), v1->scheduled_paint_rect());
1925 widget->CloseNow();
1928 TEST_F(ViewTest, TransformEvent) {
1929 TestView* v1 = new TestView();
1930 v1->SetBoundsRect(gfx::Rect(0, 0, 500, 300));
1932 TestView* v2 = new TestView();
1933 v2->SetBoundsRect(gfx::Rect(100, 100, 200, 100));
1935 Widget* widget = new Widget;
1936 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
1937 params.bounds = gfx::Rect(50, 50, 650, 650);
1938 widget->Init(params);
1939 View* root = widget->GetRootView();
1941 root->AddChildView(v1);
1942 v1->AddChildView(v2);
1944 // At this moment, |v2| occupies (100, 100) to (300, 200) in |root|.
1946 // Rotate |v1| counter-clockwise.
1947 gfx::Transform transform(v1->GetTransform());
1948 RotateCounterclockwise(&transform);
1949 transform.matrix().set(1, 3, 500.0);
1950 v1->SetTransform(transform);
1952 // |v2| now occupies (100, 200) to (200, 400) in |root|.
1953 v1->Reset();
1954 v2->Reset();
1956 gfx::Point p1(110, 210);
1957 ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, p1, p1,
1958 ui::EF_LEFT_MOUSE_BUTTON);
1959 root->OnMousePressed(pressed);
1960 EXPECT_EQ(0, v1->last_mouse_event_type_);
1961 EXPECT_EQ(ui::ET_MOUSE_PRESSED, v2->last_mouse_event_type_);
1962 EXPECT_EQ(190, v2->location_.x());
1963 EXPECT_EQ(10, v2->location_.y());
1965 ui::MouseEvent released(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(), 0);
1966 root->OnMouseReleased(released);
1968 // Now rotate |v2| inside |v1| clockwise.
1969 transform = v2->GetTransform();
1970 RotateClockwise(&transform);
1971 transform.matrix().set(0, 3, 100.f);
1972 v2->SetTransform(transform);
1974 // Now, |v2| occupies (100, 100) to (200, 300) in |v1|, and (100, 300) to
1975 // (300, 400) in |root|.
1977 v1->Reset();
1978 v2->Reset();
1980 gfx::Point point2(110, 320);
1981 ui::MouseEvent p2(ui::ET_MOUSE_PRESSED, point2, point2,
1982 ui::EF_LEFT_MOUSE_BUTTON);
1983 root->OnMousePressed(p2);
1984 EXPECT_EQ(0, v1->last_mouse_event_type_);
1985 EXPECT_EQ(ui::ET_MOUSE_PRESSED, v2->last_mouse_event_type_);
1986 EXPECT_EQ(10, v2->location_.x());
1987 EXPECT_EQ(20, v2->location_.y());
1989 root->OnMouseReleased(released);
1991 v1->SetTransform(gfx::Transform());
1992 v2->SetTransform(gfx::Transform());
1994 TestView* v3 = new TestView();
1995 v3->SetBoundsRect(gfx::Rect(10, 10, 20, 30));
1996 v2->AddChildView(v3);
1998 // Rotate |v3| clockwise with respect to |v2|.
1999 transform = v1->GetTransform();
2000 RotateClockwise(&transform);
2001 transform.matrix().set(0, 3, 30.f);
2002 v3->SetTransform(transform);
2004 // Scale |v2| with respect to |v1| along both axis.
2005 transform = v2->GetTransform();
2006 transform.matrix().set(0, 0, 0.8f);
2007 transform.matrix().set(1, 1, 0.5f);
2008 v2->SetTransform(transform);
2010 // |v3| occupies (108, 105) to (132, 115) in |root|.
2012 v1->Reset();
2013 v2->Reset();
2014 v3->Reset();
2016 gfx::Point point(112, 110);
2017 ui::MouseEvent p3(ui::ET_MOUSE_PRESSED, point, point,
2018 ui::EF_LEFT_MOUSE_BUTTON);
2019 root->OnMousePressed(p3);
2021 EXPECT_EQ(ui::ET_MOUSE_PRESSED, v3->last_mouse_event_type_);
2022 EXPECT_EQ(10, v3->location_.x());
2023 EXPECT_EQ(25, v3->location_.y());
2025 root->OnMouseReleased(released);
2027 v1->SetTransform(gfx::Transform());
2028 v2->SetTransform(gfx::Transform());
2029 v3->SetTransform(gfx::Transform());
2031 v1->Reset();
2032 v2->Reset();
2033 v3->Reset();
2035 // Rotate |v3| clockwise with respect to |v2|, and scale it along both axis.
2036 transform = v3->GetTransform();
2037 RotateClockwise(&transform);
2038 transform.matrix().set(0, 3, 30.f);
2039 // Rotation sets some scaling transformation. Using SetScale would overwrite
2040 // that and pollute the rotation. So combine the scaling with the existing
2041 // transforamtion.
2042 gfx::Transform scale;
2043 scale.Scale(0.8f, 0.5f);
2044 transform.ConcatTransform(scale);
2045 v3->SetTransform(transform);
2047 // Translate |v2| with respect to |v1|.
2048 transform = v2->GetTransform();
2049 transform.matrix().set(0, 3, 10.f);
2050 transform.matrix().set(1, 3, 10.f);
2051 v2->SetTransform(transform);
2053 // |v3| now occupies (120, 120) to (144, 130) in |root|.
2055 gfx::Point point3(124, 125);
2056 ui::MouseEvent p4(ui::ET_MOUSE_PRESSED, point3, point3,
2057 ui::EF_LEFT_MOUSE_BUTTON);
2058 root->OnMousePressed(p4);
2060 EXPECT_EQ(ui::ET_MOUSE_PRESSED, v3->last_mouse_event_type_);
2061 EXPECT_EQ(10, v3->location_.x());
2062 EXPECT_EQ(25, v3->location_.y());
2064 root->OnMouseReleased(released);
2066 widget->CloseNow();
2069 TEST_F(ViewTest, TransformVisibleBound) {
2070 gfx::Rect viewport_bounds(0, 0, 100, 100);
2072 scoped_ptr<Widget> widget(new Widget);
2073 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
2074 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2075 params.bounds = viewport_bounds;
2076 widget->Init(params);
2077 widget->GetRootView()->SetBoundsRect(viewport_bounds);
2079 View* viewport = new View;
2080 widget->SetContentsView(viewport);
2081 View* contents = new View;
2082 viewport->AddChildView(contents);
2083 viewport->SetBoundsRect(viewport_bounds);
2084 contents->SetBoundsRect(gfx::Rect(0, 0, 100, 200));
2086 View* child = new View;
2087 contents->AddChildView(child);
2088 child->SetBoundsRect(gfx::Rect(10, 90, 50, 50));
2089 EXPECT_EQ(gfx::Rect(0, 0, 50, 10), child->GetVisibleBounds());
2091 // Rotate |child| counter-clockwise
2092 gfx::Transform transform;
2093 RotateCounterclockwise(&transform);
2094 transform.matrix().set(1, 3, 50.f);
2095 child->SetTransform(transform);
2096 EXPECT_EQ(gfx::Rect(40, 0, 10, 50), child->GetVisibleBounds());
2098 widget->CloseNow();
2101 ////////////////////////////////////////////////////////////////////////////////
2102 // OnVisibleBoundsChanged()
2104 class VisibleBoundsView : public View {
2105 public:
2106 VisibleBoundsView() : received_notification_(false) {}
2107 virtual ~VisibleBoundsView() {}
2109 bool received_notification() const { return received_notification_; }
2110 void set_received_notification(bool received) {
2111 received_notification_ = received;
2114 private:
2115 // Overridden from View:
2116 virtual bool NeedsNotificationWhenVisibleBoundsChange() const OVERRIDE {
2117 return true;
2119 virtual void OnVisibleBoundsChanged() OVERRIDE {
2120 received_notification_ = true;
2123 bool received_notification_;
2125 DISALLOW_COPY_AND_ASSIGN(VisibleBoundsView);
2128 TEST_F(ViewTest, OnVisibleBoundsChanged) {
2129 gfx::Rect viewport_bounds(0, 0, 100, 100);
2131 scoped_ptr<Widget> widget(new Widget);
2132 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
2133 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2134 params.bounds = viewport_bounds;
2135 widget->Init(params);
2136 widget->GetRootView()->SetBoundsRect(viewport_bounds);
2138 View* viewport = new View;
2139 widget->SetContentsView(viewport);
2140 View* contents = new View;
2141 viewport->AddChildView(contents);
2142 viewport->SetBoundsRect(viewport_bounds);
2143 contents->SetBoundsRect(gfx::Rect(0, 0, 100, 200));
2145 // Create a view that cares about visible bounds notifications, and position
2146 // it just outside the visible bounds of the viewport.
2147 VisibleBoundsView* child = new VisibleBoundsView;
2148 contents->AddChildView(child);
2149 child->SetBoundsRect(gfx::Rect(10, 110, 50, 50));
2151 // The child bound should be fully clipped.
2152 EXPECT_TRUE(child->GetVisibleBounds().IsEmpty());
2154 // Now scroll the contents, but not enough to make the child visible.
2155 contents->SetY(contents->y() - 1);
2157 // We should have received the notification since the visible bounds may have
2158 // changed (even though they didn't).
2159 EXPECT_TRUE(child->received_notification());
2160 EXPECT_TRUE(child->GetVisibleBounds().IsEmpty());
2161 child->set_received_notification(false);
2163 // Now scroll the contents, this time by enough to make the child visible by
2164 // one pixel.
2165 contents->SetY(contents->y() - 10);
2166 EXPECT_TRUE(child->received_notification());
2167 EXPECT_EQ(1, child->GetVisibleBounds().height());
2168 child->set_received_notification(false);
2170 widget->CloseNow();
2173 ////////////////////////////////////////////////////////////////////////////////
2174 // BoundsChanged()
2176 TEST_F(ViewTest, SetBoundsPaint) {
2177 TestView top_view;
2178 TestView* child_view = new TestView;
2180 top_view.SetBoundsRect(gfx::Rect(0, 0, 100, 100));
2181 top_view.scheduled_paint_rects_.clear();
2182 child_view->SetBoundsRect(gfx::Rect(10, 10, 20, 20));
2183 top_view.AddChildView(child_view);
2185 top_view.scheduled_paint_rects_.clear();
2186 child_view->SetBoundsRect(gfx::Rect(30, 30, 20, 20));
2187 EXPECT_EQ(2U, top_view.scheduled_paint_rects_.size());
2189 // There should be 2 rects, spanning from (10, 10) to (50, 50).
2190 gfx::Rect paint_rect = top_view.scheduled_paint_rects_[0];
2191 paint_rect.Union(top_view.scheduled_paint_rects_[1]);
2192 EXPECT_EQ(gfx::Rect(10, 10, 40, 40), paint_rect);
2195 // Tests conversion methods with a transform.
2196 TEST_F(ViewTest, ConversionsWithTransform) {
2197 TestView top_view;
2199 // View hierarchy used to test scale transforms.
2200 TestView* child = new TestView;
2201 TestView* child_child = new TestView;
2203 // View used to test a rotation transform.
2204 TestView* child_2 = new TestView;
2206 top_view.AddChildView(child);
2207 child->AddChildView(child_child);
2209 top_view.SetBoundsRect(gfx::Rect(0, 0, 1000, 1000));
2211 child->SetBoundsRect(gfx::Rect(7, 19, 500, 500));
2212 gfx::Transform transform;
2213 transform.Scale(3.0, 4.0);
2214 child->SetTransform(transform);
2216 child_child->SetBoundsRect(gfx::Rect(17, 13, 100, 100));
2217 transform.MakeIdentity();
2218 transform.Scale(5.0, 7.0);
2219 child_child->SetTransform(transform);
2221 top_view.AddChildView(child_2);
2222 child_2->SetBoundsRect(gfx::Rect(700, 725, 100, 100));
2223 transform.MakeIdentity();
2224 RotateClockwise(&transform);
2225 child_2->SetTransform(transform);
2227 // Sanity check to make sure basic transforms act as expected.
2229 gfx::Transform transform;
2230 transform.Translate(110.0, -110.0);
2231 transform.Scale(100.0, 55.0);
2232 transform.Translate(1.0, 1.0);
2234 // convert to a 3x3 matrix.
2235 const SkMatrix& matrix = transform.matrix();
2237 EXPECT_EQ(210, matrix.getTranslateX());
2238 EXPECT_EQ(-55, matrix.getTranslateY());
2239 EXPECT_EQ(100, matrix.getScaleX());
2240 EXPECT_EQ(55, matrix.getScaleY());
2241 EXPECT_EQ(0, matrix.getSkewX());
2242 EXPECT_EQ(0, matrix.getSkewY());
2246 gfx::Transform transform;
2247 transform.Translate(1.0, 1.0);
2248 gfx::Transform t2;
2249 t2.Scale(100.0, 55.0);
2250 gfx::Transform t3;
2251 t3.Translate(110.0, -110.0);
2252 transform.ConcatTransform(t2);
2253 transform.ConcatTransform(t3);
2255 // convert to a 3x3 matrix
2256 const SkMatrix& matrix = transform.matrix();
2258 EXPECT_EQ(210, matrix.getTranslateX());
2259 EXPECT_EQ(-55, matrix.getTranslateY());
2260 EXPECT_EQ(100, matrix.getScaleX());
2261 EXPECT_EQ(55, matrix.getScaleY());
2262 EXPECT_EQ(0, matrix.getSkewX());
2263 EXPECT_EQ(0, matrix.getSkewY());
2266 // Conversions from child->top and top->child.
2268 gfx::Point point(5, 5);
2269 View::ConvertPointToTarget(child, &top_view, &point);
2270 EXPECT_EQ(22, point.x());
2271 EXPECT_EQ(39, point.y());
2273 gfx::RectF rect(5.0f, 5.0f, 10.0f, 20.0f);
2274 View::ConvertRectToTarget(child, &top_view, &rect);
2275 EXPECT_FLOAT_EQ(22.0f, rect.x());
2276 EXPECT_FLOAT_EQ(39.0f, rect.y());
2277 EXPECT_FLOAT_EQ(30.0f, rect.width());
2278 EXPECT_FLOAT_EQ(80.0f, rect.height());
2280 point.SetPoint(22, 39);
2281 View::ConvertPointToTarget(&top_view, child, &point);
2282 EXPECT_EQ(5, point.x());
2283 EXPECT_EQ(5, point.y());
2285 rect.SetRect(22.0f, 39.0f, 30.0f, 80.0f);
2286 View::ConvertRectToTarget(&top_view, child, &rect);
2287 EXPECT_FLOAT_EQ(5.0f, rect.x());
2288 EXPECT_FLOAT_EQ(5.0f, rect.y());
2289 EXPECT_FLOAT_EQ(10.0f, rect.width());
2290 EXPECT_FLOAT_EQ(20.0f, rect.height());
2293 // Conversions from child_child->top and top->child_child.
2295 gfx::Point point(5, 5);
2296 View::ConvertPointToTarget(child_child, &top_view, &point);
2297 EXPECT_EQ(133, point.x());
2298 EXPECT_EQ(211, point.y());
2300 gfx::RectF rect(5.0f, 5.0f, 10.0f, 20.0f);
2301 View::ConvertRectToTarget(child_child, &top_view, &rect);
2302 EXPECT_FLOAT_EQ(133.0f, rect.x());
2303 EXPECT_FLOAT_EQ(211.0f, rect.y());
2304 EXPECT_FLOAT_EQ(150.0f, rect.width());
2305 EXPECT_FLOAT_EQ(560.0f, rect.height());
2307 point.SetPoint(133, 211);
2308 View::ConvertPointToTarget(&top_view, child_child, &point);
2309 EXPECT_EQ(5, point.x());
2310 EXPECT_EQ(5, point.y());
2312 rect.SetRect(133.0f, 211.0f, 150.0f, 560.0f);
2313 View::ConvertRectToTarget(&top_view, child_child, &rect);
2314 EXPECT_FLOAT_EQ(5.0f, rect.x());
2315 EXPECT_FLOAT_EQ(5.0f, rect.y());
2316 EXPECT_FLOAT_EQ(10.0f, rect.width());
2317 EXPECT_FLOAT_EQ(20.0f, rect.height());
2320 // Conversions from child_child->child and child->child_child
2322 gfx::Point point(5, 5);
2323 View::ConvertPointToTarget(child_child, child, &point);
2324 EXPECT_EQ(42, point.x());
2325 EXPECT_EQ(48, point.y());
2327 gfx::RectF rect(5.0f, 5.0f, 10.0f, 20.0f);
2328 View::ConvertRectToTarget(child_child, child, &rect);
2329 EXPECT_FLOAT_EQ(42.0f, rect.x());
2330 EXPECT_FLOAT_EQ(48.0f, rect.y());
2331 EXPECT_FLOAT_EQ(50.0f, rect.width());
2332 EXPECT_FLOAT_EQ(140.0f, rect.height());
2334 point.SetPoint(42, 48);
2335 View::ConvertPointToTarget(child, child_child, &point);
2336 EXPECT_EQ(5, point.x());
2337 EXPECT_EQ(5, point.y());
2339 rect.SetRect(42.0f, 48.0f, 50.0f, 140.0f);
2340 View::ConvertRectToTarget(child, child_child, &rect);
2341 EXPECT_FLOAT_EQ(5.0f, rect.x());
2342 EXPECT_FLOAT_EQ(5.0f, rect.y());
2343 EXPECT_FLOAT_EQ(10.0f, rect.width());
2344 EXPECT_FLOAT_EQ(20.0f, rect.height());
2347 // Conversions from top_view to child with a value that should be negative.
2348 // This ensures we don't round up with negative numbers.
2350 gfx::Point point(6, 18);
2351 View::ConvertPointToTarget(&top_view, child, &point);
2352 EXPECT_EQ(-1, point.x());
2353 EXPECT_EQ(-1, point.y());
2355 float error = 0.01f;
2356 gfx::RectF rect(6.0f, 18.0f, 10.0f, 39.0f);
2357 View::ConvertRectToTarget(&top_view, child, &rect);
2358 EXPECT_NEAR(-0.33f, rect.x(), error);
2359 EXPECT_NEAR(-0.25f, rect.y(), error);
2360 EXPECT_NEAR(3.33f, rect.width(), error);
2361 EXPECT_NEAR(9.75f, rect.height(), error);
2364 // Rect conversions from top_view->child_2 and child_2->top_view.
2366 gfx::RectF rect(50.0f, 55.0f, 20.0f, 30.0f);
2367 View::ConvertRectToTarget(child_2, &top_view, &rect);
2368 EXPECT_FLOAT_EQ(615.0f, rect.x());
2369 EXPECT_FLOAT_EQ(775.0f, rect.y());
2370 EXPECT_FLOAT_EQ(30.0f, rect.width());
2371 EXPECT_FLOAT_EQ(20.0f, rect.height());
2373 rect.SetRect(615.0f, 775.0f, 30.0f, 20.0f);
2374 View::ConvertRectToTarget(&top_view, child_2, &rect);
2375 EXPECT_FLOAT_EQ(50.0f, rect.x());
2376 EXPECT_FLOAT_EQ(55.0f, rect.y());
2377 EXPECT_FLOAT_EQ(20.0f, rect.width());
2378 EXPECT_FLOAT_EQ(30.0f, rect.height());
2382 // Tests conversion methods for rectangles.
2383 TEST_F(ViewTest, ConvertRectWithTransform) {
2384 scoped_ptr<Widget> widget(new Widget);
2385 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
2386 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2387 params.bounds = gfx::Rect(50, 50, 650, 650);
2388 widget->Init(params);
2389 View* root = widget->GetRootView();
2391 TestView* v1 = new TestView;
2392 TestView* v2 = new TestView;
2393 root->AddChildView(v1);
2394 v1->AddChildView(v2);
2396 v1->SetBoundsRect(gfx::Rect(10, 10, 500, 500));
2397 v2->SetBoundsRect(gfx::Rect(20, 20, 100, 200));
2399 // |v2| now occupies (30, 30) to (130, 230) in |widget|
2400 gfx::Rect rect(5, 5, 15, 40);
2401 EXPECT_EQ(gfx::Rect(25, 25, 15, 40), v2->ConvertRectToParent(rect));
2402 EXPECT_EQ(gfx::Rect(35, 35, 15, 40), v2->ConvertRectToWidget(rect));
2404 // Rotate |v2|
2405 gfx::Transform t2;
2406 RotateCounterclockwise(&t2);
2407 t2.matrix().set(1, 3, 100.f);
2408 v2->SetTransform(t2);
2410 // |v2| now occupies (30, 30) to (230, 130) in |widget|
2411 EXPECT_EQ(gfx::Rect(25, 100, 40, 15), v2->ConvertRectToParent(rect));
2412 EXPECT_EQ(gfx::Rect(35, 110, 40, 15), v2->ConvertRectToWidget(rect));
2414 // Scale down |v1|
2415 gfx::Transform t1;
2416 t1.Scale(0.5, 0.5);
2417 v1->SetTransform(t1);
2419 // The rectangle should remain the same for |v1|.
2420 EXPECT_EQ(gfx::Rect(25, 100, 40, 15), v2->ConvertRectToParent(rect));
2422 // |v2| now occupies (20, 20) to (120, 70) in |widget|
2423 EXPECT_EQ(gfx::Rect(22, 60, 21, 8).ToString(),
2424 v2->ConvertRectToWidget(rect).ToString());
2426 widget->CloseNow();
2429 class ObserverView : public View {
2430 public:
2431 ObserverView();
2432 virtual ~ObserverView();
2434 void ResetTestState();
2436 bool has_add_details() const { return has_add_details_; }
2437 bool has_remove_details() const { return has_remove_details_; }
2439 const ViewHierarchyChangedDetails& add_details() const {
2440 return add_details_;
2443 const ViewHierarchyChangedDetails& remove_details() const {
2444 return remove_details_;
2447 private:
2448 // View:
2449 virtual void ViewHierarchyChanged(
2450 const ViewHierarchyChangedDetails& details) OVERRIDE;
2452 bool has_add_details_;
2453 bool has_remove_details_;
2454 ViewHierarchyChangedDetails add_details_;
2455 ViewHierarchyChangedDetails remove_details_;
2457 DISALLOW_COPY_AND_ASSIGN(ObserverView);
2460 ObserverView::ObserverView()
2461 : has_add_details_(false),
2462 has_remove_details_(false) {
2465 ObserverView::~ObserverView() {}
2467 void ObserverView::ResetTestState() {
2468 has_add_details_ = false;
2469 has_remove_details_ = false;
2470 add_details_ = ViewHierarchyChangedDetails();
2471 remove_details_ = ViewHierarchyChangedDetails();
2474 void ObserverView::ViewHierarchyChanged(
2475 const ViewHierarchyChangedDetails& details) {
2476 if (details.is_add) {
2477 has_add_details_ = true;
2478 add_details_ = details;
2479 } else {
2480 has_remove_details_ = true;
2481 remove_details_ = details;
2485 // Verifies that the ViewHierarchyChanged() notification is sent correctly when
2486 // a child view is added or removed to all the views in the hierarchy (up and
2487 // down).
2488 // The tree looks like this:
2489 // v1
2490 // +-- v2
2491 // +-- v3
2492 // +-- v4 (starts here, then get reparented to v1)
2493 TEST_F(ViewTest, ViewHierarchyChanged) {
2494 ObserverView v1;
2496 ObserverView* v3 = new ObserverView();
2498 // Add |v3| to |v2|.
2499 scoped_ptr<ObserverView> v2(new ObserverView());
2500 v2->AddChildView(v3);
2502 // Make sure both |v2| and |v3| receive the ViewHierarchyChanged()
2503 // notification.
2504 EXPECT_TRUE(v2->has_add_details());
2505 EXPECT_FALSE(v2->has_remove_details());
2506 EXPECT_EQ(v2.get(), v2->add_details().parent);
2507 EXPECT_EQ(v3, v2->add_details().child);
2508 EXPECT_EQ(NULL, v2->add_details().move_view);
2510 EXPECT_TRUE(v3->has_add_details());
2511 EXPECT_FALSE(v3->has_remove_details());
2512 EXPECT_EQ(v2.get(), v3->add_details().parent);
2513 EXPECT_EQ(v3, v3->add_details().child);
2514 EXPECT_EQ(NULL, v3->add_details().move_view);
2516 // Reset everything to the initial state.
2517 v2->ResetTestState();
2518 v3->ResetTestState();
2520 // Add |v2| to v1.
2521 v1.AddChildView(v2.get());
2523 // Verifies that |v2| is the child view *added* and the parent view is |v1|.
2524 // Make sure all the views (v1, v2, v3) received _that_ information.
2525 EXPECT_TRUE(v1.has_add_details());
2526 EXPECT_FALSE(v1.has_remove_details());
2527 EXPECT_EQ(&v1, v1.add_details().parent);
2528 EXPECT_EQ(v2.get(), v1.add_details().child);
2529 EXPECT_EQ(NULL, v1.add_details().move_view);
2531 EXPECT_TRUE(v2->has_add_details());
2532 EXPECT_FALSE(v2->has_remove_details());
2533 EXPECT_EQ(&v1, v2->add_details().parent);
2534 EXPECT_EQ(v2.get(), v2->add_details().child);
2535 EXPECT_EQ(NULL, v2->add_details().move_view);
2537 EXPECT_TRUE(v3->has_add_details());
2538 EXPECT_FALSE(v3->has_remove_details());
2539 EXPECT_EQ(&v1, v3->add_details().parent);
2540 EXPECT_EQ(v2.get(), v3->add_details().child);
2541 EXPECT_EQ(NULL, v3->add_details().move_view);
2543 // Reset everything to the initial state.
2544 v1.ResetTestState();
2545 v2->ResetTestState();
2546 v3->ResetTestState();
2548 // Remove |v2| from |v1|.
2549 v1.RemoveChildView(v2.get());
2551 // Verifies that |v2| is the child view *removed* and the parent view is |v1|.
2552 // Make sure all the views (v1, v2, v3) received _that_ information.
2553 EXPECT_FALSE(v1.has_add_details());
2554 EXPECT_TRUE(v1.has_remove_details());
2555 EXPECT_EQ(&v1, v1.remove_details().parent);
2556 EXPECT_EQ(v2.get(), v1.remove_details().child);
2557 EXPECT_EQ(NULL, v1.remove_details().move_view);
2559 EXPECT_FALSE(v2->has_add_details());
2560 EXPECT_TRUE(v2->has_remove_details());
2561 EXPECT_EQ(&v1, v2->remove_details().parent);
2562 EXPECT_EQ(v2.get(), v2->remove_details().child);
2563 EXPECT_EQ(NULL, v2->remove_details().move_view);
2565 EXPECT_FALSE(v3->has_add_details());
2566 EXPECT_TRUE(v3->has_remove_details());
2567 EXPECT_EQ(&v1, v3->remove_details().parent);
2568 EXPECT_EQ(v3, v3->remove_details().child);
2569 EXPECT_EQ(NULL, v3->remove_details().move_view);
2571 // Verifies notifications when reparenting a view.
2572 ObserverView* v4 = new ObserverView();
2573 // Add |v4| to |v2|.
2574 v2->AddChildView(v4);
2576 // Reset everything to the initial state.
2577 v1.ResetTestState();
2578 v2->ResetTestState();
2579 v3->ResetTestState();
2580 v4->ResetTestState();
2582 // Reparent |v4| to |v1|.
2583 v1.AddChildView(v4);
2585 // Verifies that all views receive the correct information for all the child,
2586 // parent and move views.
2588 // |v1| is the new parent, |v4| is the child for add, |v2| is the old parent.
2589 EXPECT_TRUE(v1.has_add_details());
2590 EXPECT_FALSE(v1.has_remove_details());
2591 EXPECT_EQ(&v1, v1.add_details().parent);
2592 EXPECT_EQ(v4, v1.add_details().child);
2593 EXPECT_EQ(v2.get(), v1.add_details().move_view);
2595 // |v2| is the old parent, |v4| is the child for remove, |v1| is the new
2596 // parent.
2597 EXPECT_FALSE(v2->has_add_details());
2598 EXPECT_TRUE(v2->has_remove_details());
2599 EXPECT_EQ(v2.get(), v2->remove_details().parent);
2600 EXPECT_EQ(v4, v2->remove_details().child);
2601 EXPECT_EQ(&v1, v2->remove_details().move_view);
2603 // |v3| is not impacted by this operation, and hence receives no notification.
2604 EXPECT_FALSE(v3->has_add_details());
2605 EXPECT_FALSE(v3->has_remove_details());
2607 // |v4| is the reparented child, so it receives notifications for the remove
2608 // and then the add. |v2| is its old parent, |v1| is its new parent.
2609 EXPECT_TRUE(v4->has_remove_details());
2610 EXPECT_TRUE(v4->has_add_details());
2611 EXPECT_EQ(v2.get(), v4->remove_details().parent);
2612 EXPECT_EQ(&v1, v4->add_details().parent);
2613 EXPECT_EQ(v4, v4->add_details().child);
2614 EXPECT_EQ(v4, v4->remove_details().child);
2615 EXPECT_EQ(&v1, v4->remove_details().move_view);
2616 EXPECT_EQ(v2.get(), v4->add_details().move_view);
2619 // Verifies if the child views added under the root are all deleted when calling
2620 // RemoveAllChildViews.
2621 // The tree looks like this:
2622 // root
2623 // +-- child1
2624 // +-- foo
2625 // +-- bar0
2626 // +-- bar1
2627 // +-- bar2
2628 // +-- child2
2629 // +-- child3
2630 TEST_F(ViewTest, RemoveAllChildViews) {
2631 View root;
2633 View* child1 = new View;
2634 root.AddChildView(child1);
2636 for (int i = 0; i < 2; ++i)
2637 root.AddChildView(new View);
2639 View* foo = new View;
2640 child1->AddChildView(foo);
2642 // Add some nodes to |foo|.
2643 for (int i = 0; i < 3; ++i)
2644 foo->AddChildView(new View);
2646 EXPECT_EQ(3, root.child_count());
2647 EXPECT_EQ(1, child1->child_count());
2648 EXPECT_EQ(3, foo->child_count());
2650 // Now remove all child views from root.
2651 root.RemoveAllChildViews(true);
2653 EXPECT_EQ(0, root.child_count());
2654 EXPECT_FALSE(root.has_children());
2657 TEST_F(ViewTest, Contains) {
2658 View v1;
2659 View* v2 = new View;
2660 View* v3 = new View;
2662 v1.AddChildView(v2);
2663 v2->AddChildView(v3);
2665 EXPECT_FALSE(v1.Contains(NULL));
2666 EXPECT_TRUE(v1.Contains(&v1));
2667 EXPECT_TRUE(v1.Contains(v2));
2668 EXPECT_TRUE(v1.Contains(v3));
2670 EXPECT_FALSE(v2->Contains(NULL));
2671 EXPECT_TRUE(v2->Contains(v2));
2672 EXPECT_FALSE(v2->Contains(&v1));
2673 EXPECT_TRUE(v2->Contains(v3));
2675 EXPECT_FALSE(v3->Contains(NULL));
2676 EXPECT_TRUE(v3->Contains(v3));
2677 EXPECT_FALSE(v3->Contains(&v1));
2678 EXPECT_FALSE(v3->Contains(v2));
2681 // Verifies if GetIndexOf() returns the correct index for the specified child
2682 // view.
2683 // The tree looks like this:
2684 // root
2685 // +-- child1
2686 // +-- foo1
2687 // +-- child2
2688 TEST_F(ViewTest, GetIndexOf) {
2689 View root;
2691 View* child1 = new View;
2692 root.AddChildView(child1);
2694 View* child2 = new View;
2695 root.AddChildView(child2);
2697 View* foo1 = new View;
2698 child1->AddChildView(foo1);
2700 EXPECT_EQ(-1, root.GetIndexOf(NULL));
2701 EXPECT_EQ(-1, root.GetIndexOf(&root));
2702 EXPECT_EQ(0, root.GetIndexOf(child1));
2703 EXPECT_EQ(1, root.GetIndexOf(child2));
2704 EXPECT_EQ(-1, root.GetIndexOf(foo1));
2706 EXPECT_EQ(-1, child1->GetIndexOf(NULL));
2707 EXPECT_EQ(-1, child1->GetIndexOf(&root));
2708 EXPECT_EQ(-1, child1->GetIndexOf(child1));
2709 EXPECT_EQ(-1, child1->GetIndexOf(child2));
2710 EXPECT_EQ(0, child1->GetIndexOf(foo1));
2712 EXPECT_EQ(-1, child2->GetIndexOf(NULL));
2713 EXPECT_EQ(-1, child2->GetIndexOf(&root));
2714 EXPECT_EQ(-1, child2->GetIndexOf(child2));
2715 EXPECT_EQ(-1, child2->GetIndexOf(child1));
2716 EXPECT_EQ(-1, child2->GetIndexOf(foo1));
2719 // Verifies that the child views can be reordered correctly.
2720 TEST_F(ViewTest, ReorderChildren) {
2721 View root;
2723 View* child = new View();
2724 root.AddChildView(child);
2726 View* foo1 = new View();
2727 child->AddChildView(foo1);
2728 View* foo2 = new View();
2729 child->AddChildView(foo2);
2730 View* foo3 = new View();
2731 child->AddChildView(foo3);
2732 foo1->set_focusable(true);
2733 foo2->set_focusable(true);
2734 foo3->set_focusable(true);
2736 ASSERT_EQ(0, child->GetIndexOf(foo1));
2737 ASSERT_EQ(1, child->GetIndexOf(foo2));
2738 ASSERT_EQ(2, child->GetIndexOf(foo3));
2739 ASSERT_EQ(foo2, foo1->GetNextFocusableView());
2740 ASSERT_EQ(foo3, foo2->GetNextFocusableView());
2741 ASSERT_EQ(NULL, foo3->GetNextFocusableView());
2743 // Move |foo2| at the end.
2744 child->ReorderChildView(foo2, -1);
2745 ASSERT_EQ(0, child->GetIndexOf(foo1));
2746 ASSERT_EQ(1, child->GetIndexOf(foo3));
2747 ASSERT_EQ(2, child->GetIndexOf(foo2));
2748 ASSERT_EQ(foo3, foo1->GetNextFocusableView());
2749 ASSERT_EQ(foo2, foo3->GetNextFocusableView());
2750 ASSERT_EQ(NULL, foo2->GetNextFocusableView());
2752 // Move |foo1| at the end.
2753 child->ReorderChildView(foo1, -1);
2754 ASSERT_EQ(0, child->GetIndexOf(foo3));
2755 ASSERT_EQ(1, child->GetIndexOf(foo2));
2756 ASSERT_EQ(2, child->GetIndexOf(foo1));
2757 ASSERT_EQ(NULL, foo1->GetNextFocusableView());
2758 ASSERT_EQ(foo2, foo1->GetPreviousFocusableView());
2759 ASSERT_EQ(foo2, foo3->GetNextFocusableView());
2760 ASSERT_EQ(foo1, foo2->GetNextFocusableView());
2762 // Move |foo2| to the front.
2763 child->ReorderChildView(foo2, 0);
2764 ASSERT_EQ(0, child->GetIndexOf(foo2));
2765 ASSERT_EQ(1, child->GetIndexOf(foo3));
2766 ASSERT_EQ(2, child->GetIndexOf(foo1));
2767 ASSERT_EQ(NULL, foo1->GetNextFocusableView());
2768 ASSERT_EQ(foo3, foo1->GetPreviousFocusableView());
2769 ASSERT_EQ(foo3, foo2->GetNextFocusableView());
2770 ASSERT_EQ(foo1, foo3->GetNextFocusableView());
2773 // Verifies that GetViewByID returns the correctly child view from the specified
2774 // ID.
2775 // The tree looks like this:
2776 // v1
2777 // +-- v2
2778 // +-- v3
2779 // +-- v4
2780 TEST_F(ViewTest, GetViewByID) {
2781 View v1;
2782 const int kV1ID = 1;
2783 v1.set_id(kV1ID);
2785 View v2;
2786 const int kV2ID = 2;
2787 v2.set_id(kV2ID);
2789 View v3;
2790 const int kV3ID = 3;
2791 v3.set_id(kV3ID);
2793 View v4;
2794 const int kV4ID = 4;
2795 v4.set_id(kV4ID);
2797 const int kV5ID = 5;
2799 v1.AddChildView(&v2);
2800 v2.AddChildView(&v3);
2801 v2.AddChildView(&v4);
2803 EXPECT_EQ(&v1, v1.GetViewByID(kV1ID));
2804 EXPECT_EQ(&v2, v1.GetViewByID(kV2ID));
2805 EXPECT_EQ(&v4, v1.GetViewByID(kV4ID));
2807 EXPECT_EQ(NULL, v1.GetViewByID(kV5ID)); // No V5 exists.
2808 EXPECT_EQ(NULL, v2.GetViewByID(kV1ID)); // It can get only from child views.
2810 const int kGroup = 1;
2811 v3.SetGroup(kGroup);
2812 v4.SetGroup(kGroup);
2814 View::Views views;
2815 v1.GetViewsInGroup(kGroup, &views);
2816 EXPECT_EQ(2U, views.size());
2818 View::Views::const_iterator i(std::find(views.begin(), views.end(), &v3));
2819 EXPECT_NE(views.end(), i);
2821 i = std::find(views.begin(), views.end(), &v4);
2822 EXPECT_NE(views.end(), i);
2825 TEST_F(ViewTest, AddExistingChild) {
2826 View v1, v2, v3;
2828 v1.AddChildView(&v2);
2829 v1.AddChildView(&v3);
2830 EXPECT_EQ(0, v1.GetIndexOf(&v2));
2831 EXPECT_EQ(1, v1.GetIndexOf(&v3));
2833 // Check that there's no change in order when adding at same index.
2834 v1.AddChildViewAt(&v2, 0);
2835 EXPECT_EQ(0, v1.GetIndexOf(&v2));
2836 EXPECT_EQ(1, v1.GetIndexOf(&v3));
2837 v1.AddChildViewAt(&v3, 1);
2838 EXPECT_EQ(0, v1.GetIndexOf(&v2));
2839 EXPECT_EQ(1, v1.GetIndexOf(&v3));
2841 // Add it at a different index and check for change in order.
2842 v1.AddChildViewAt(&v2, 1);
2843 EXPECT_EQ(1, v1.GetIndexOf(&v2));
2844 EXPECT_EQ(0, v1.GetIndexOf(&v3));
2845 v1.AddChildViewAt(&v2, 0);
2846 EXPECT_EQ(0, v1.GetIndexOf(&v2));
2847 EXPECT_EQ(1, v1.GetIndexOf(&v3));
2849 // Check that calling |AddChildView()| does not change the order.
2850 v1.AddChildView(&v2);
2851 EXPECT_EQ(0, v1.GetIndexOf(&v2));
2852 EXPECT_EQ(1, v1.GetIndexOf(&v3));
2853 v1.AddChildView(&v3);
2854 EXPECT_EQ(0, v1.GetIndexOf(&v2));
2855 EXPECT_EQ(1, v1.GetIndexOf(&v3));
2858 ////////////////////////////////////////////////////////////////////////////////
2859 // Layers
2860 ////////////////////////////////////////////////////////////////////////////////
2862 #if defined(USE_AURA)
2864 namespace {
2866 // Test implementation of LayerAnimator.
2867 class TestLayerAnimator : public ui::LayerAnimator {
2868 public:
2869 TestLayerAnimator();
2871 const gfx::Rect& last_bounds() const { return last_bounds_; }
2873 // LayerAnimator.
2874 virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE;
2876 protected:
2877 virtual ~TestLayerAnimator() { }
2879 private:
2880 gfx::Rect last_bounds_;
2882 DISALLOW_COPY_AND_ASSIGN(TestLayerAnimator);
2885 TestLayerAnimator::TestLayerAnimator()
2886 : ui::LayerAnimator(base::TimeDelta::FromMilliseconds(0)) {
2889 void TestLayerAnimator::SetBounds(const gfx::Rect& bounds) {
2890 last_bounds_ = bounds;
2893 } // namespace
2895 class ViewLayerTest : public ViewsTestBase {
2896 public:
2897 ViewLayerTest() : widget_(NULL), old_use_acceleration_(false) {}
2899 virtual ~ViewLayerTest() {
2902 // Returns the Layer used by the RootView.
2903 ui::Layer* GetRootLayer() {
2904 return widget()->GetLayer();
2907 virtual void SetUp() OVERRIDE {
2908 ViewTest::SetUp();
2909 old_use_acceleration_ = View::get_use_acceleration_when_possible();
2910 View::set_use_acceleration_when_possible(true);
2912 widget_ = new Widget;
2913 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
2914 params.bounds = gfx::Rect(50, 50, 200, 200);
2915 widget_->Init(params);
2916 widget_->Show();
2917 widget_->GetRootView()->SetBounds(0, 0, 200, 200);
2920 virtual void TearDown() OVERRIDE {
2921 View::set_use_acceleration_when_possible(old_use_acceleration_);
2922 widget_->CloseNow();
2923 ViewsTestBase::TearDown();
2926 Widget* widget() { return widget_; }
2928 private:
2929 Widget* widget_;
2930 bool old_use_acceleration_;
2934 TEST_F(ViewLayerTest, LayerToggling) {
2935 // Because we lazily create textures the calls to DrawTree are necessary to
2936 // ensure we trigger creation of textures.
2937 ui::Layer* root_layer = widget()->GetLayer();
2938 View* content_view = new View;
2939 widget()->SetContentsView(content_view);
2941 // Create v1, give it a bounds and verify everything is set up correctly.
2942 View* v1 = new View;
2943 v1->SetPaintToLayer(true);
2944 EXPECT_TRUE(v1->layer() != NULL);
2945 v1->SetBoundsRect(gfx::Rect(20, 30, 140, 150));
2946 content_view->AddChildView(v1);
2947 ASSERT_TRUE(v1->layer() != NULL);
2948 EXPECT_EQ(root_layer, v1->layer()->parent());
2949 EXPECT_EQ(gfx::Rect(20, 30, 140, 150), v1->layer()->bounds());
2951 // Create v2 as a child of v1 and do basic assertion testing.
2952 View* v2 = new View;
2953 v1->AddChildView(v2);
2954 EXPECT_TRUE(v2->layer() == NULL);
2955 v2->SetBoundsRect(gfx::Rect(10, 20, 30, 40));
2956 v2->SetPaintToLayer(true);
2957 ASSERT_TRUE(v2->layer() != NULL);
2958 EXPECT_EQ(v1->layer(), v2->layer()->parent());
2959 EXPECT_EQ(gfx::Rect(10, 20, 30, 40), v2->layer()->bounds());
2961 // Turn off v1s layer. v2 should still have a layer but its parent should have
2962 // changed.
2963 v1->SetPaintToLayer(false);
2964 EXPECT_TRUE(v1->layer() == NULL);
2965 EXPECT_TRUE(v2->layer() != NULL);
2966 EXPECT_EQ(root_layer, v2->layer()->parent());
2967 ASSERT_EQ(1u, root_layer->children().size());
2968 EXPECT_EQ(root_layer->children()[0], v2->layer());
2969 // The bounds of the layer should have changed to be relative to the root view
2970 // now.
2971 EXPECT_EQ(gfx::Rect(30, 50, 30, 40), v2->layer()->bounds());
2973 // Make v1 have a layer again and verify v2s layer is wired up correctly.
2974 gfx::Transform transform;
2975 transform.Scale(2.0, 2.0);
2976 v1->SetTransform(transform);
2977 EXPECT_TRUE(v1->layer() != NULL);
2978 EXPECT_TRUE(v2->layer() != NULL);
2979 EXPECT_EQ(root_layer, v1->layer()->parent());
2980 EXPECT_EQ(v1->layer(), v2->layer()->parent());
2981 ASSERT_EQ(1u, root_layer->children().size());
2982 EXPECT_EQ(root_layer->children()[0], v1->layer());
2983 ASSERT_EQ(1u, v1->layer()->children().size());
2984 EXPECT_EQ(v1->layer()->children()[0], v2->layer());
2985 EXPECT_EQ(gfx::Rect(10, 20, 30, 40), v2->layer()->bounds());
2988 // Verifies turning on a layer wires up children correctly.
2989 TEST_F(ViewLayerTest, NestedLayerToggling) {
2990 View* content_view = new View;
2991 widget()->SetContentsView(content_view);
2993 // Create v1, give it a bounds and verify everything is set up correctly.
2994 View* v1 = new View;
2995 content_view->AddChildView(v1);
2996 v1->SetBoundsRect(gfx::Rect(20, 30, 140, 150));
2998 View* v2 = new View;
2999 v1->AddChildView(v2);
3001 View* v3 = new View;
3002 v3->SetPaintToLayer(true);
3003 v2->AddChildView(v3);
3004 ASSERT_TRUE(v3->layer() != NULL);
3006 // At this point we have v1-v2-v3. v3 has a layer, v1 and v2 don't.
3008 v1->SetPaintToLayer(true);
3009 EXPECT_EQ(v1->layer(), v3->layer()->parent());
3012 TEST_F(ViewLayerTest, LayerAnimator) {
3013 View* content_view = new View;
3014 widget()->SetContentsView(content_view);
3016 View* v1 = new View;
3017 content_view->AddChildView(v1);
3018 v1->SetPaintToLayer(true);
3019 EXPECT_TRUE(v1->layer() != NULL);
3021 TestLayerAnimator* animator = new TestLayerAnimator();
3022 v1->layer()->SetAnimator(animator);
3024 gfx::Rect bounds(1, 2, 3, 4);
3025 v1->SetBoundsRect(bounds);
3026 EXPECT_EQ(bounds, animator->last_bounds());
3027 // TestLayerAnimator doesn't update the layer.
3028 EXPECT_NE(bounds, v1->layer()->bounds());
3031 // Verifies the bounds of a layer are updated if the bounds of ancestor that
3032 // doesn't have a layer change.
3033 TEST_F(ViewLayerTest, BoundsChangeWithLayer) {
3034 View* content_view = new View;
3035 widget()->SetContentsView(content_view);
3037 View* v1 = new View;
3038 content_view->AddChildView(v1);
3039 v1->SetBoundsRect(gfx::Rect(20, 30, 140, 150));
3041 View* v2 = new View;
3042 v2->SetBoundsRect(gfx::Rect(10, 11, 40, 50));
3043 v1->AddChildView(v2);
3044 v2->SetPaintToLayer(true);
3045 ASSERT_TRUE(v2->layer() != NULL);
3046 EXPECT_EQ(gfx::Rect(30, 41, 40, 50), v2->layer()->bounds());
3048 v1->SetPosition(gfx::Point(25, 36));
3049 EXPECT_EQ(gfx::Rect(35, 47, 40, 50), v2->layer()->bounds());
3051 v2->SetPosition(gfx::Point(11, 12));
3052 EXPECT_EQ(gfx::Rect(36, 48, 40, 50), v2->layer()->bounds());
3054 // Bounds of the layer should change even if the view is not invisible.
3055 v1->SetVisible(false);
3056 v1->SetPosition(gfx::Point(20, 30));
3057 EXPECT_EQ(gfx::Rect(31, 42, 40, 50), v2->layer()->bounds());
3059 v2->SetVisible(false);
3060 v2->SetBoundsRect(gfx::Rect(10, 11, 20, 30));
3061 EXPECT_EQ(gfx::Rect(30, 41, 20, 30), v2->layer()->bounds());
3064 // Make sure layers are positioned correctly in RTL.
3065 TEST_F(ViewLayerTest, BoundInRTL) {
3066 std::string locale = l10n_util::GetApplicationLocale(std::string());
3067 base::i18n::SetICUDefaultLocale("he");
3069 View* view = new View;
3070 widget()->SetContentsView(view);
3072 int content_width = view->width();
3074 // |v1| is initially not attached to anything. So its layer will have the same
3075 // bounds as the view.
3076 View* v1 = new View;
3077 v1->SetPaintToLayer(true);
3078 v1->SetBounds(10, 10, 20, 10);
3079 EXPECT_EQ(gfx::Rect(10, 10, 20, 10),
3080 v1->layer()->bounds());
3082 // Once |v1| is attached to the widget, its layer will get RTL-appropriate
3083 // bounds.
3084 view->AddChildView(v1);
3085 EXPECT_EQ(gfx::Rect(content_width - 30, 10, 20, 10),
3086 v1->layer()->bounds());
3087 gfx::Rect l1bounds = v1->layer()->bounds();
3089 // Now attach a View to the widget first, then create a layer for it. Make
3090 // sure the bounds are correct.
3091 View* v2 = new View;
3092 v2->SetBounds(50, 10, 30, 10);
3093 EXPECT_FALSE(v2->layer());
3094 view->AddChildView(v2);
3095 v2->SetPaintToLayer(true);
3096 EXPECT_EQ(gfx::Rect(content_width - 80, 10, 30, 10),
3097 v2->layer()->bounds());
3098 gfx::Rect l2bounds = v2->layer()->bounds();
3100 view->SetPaintToLayer(true);
3101 EXPECT_EQ(l1bounds, v1->layer()->bounds());
3102 EXPECT_EQ(l2bounds, v2->layer()->bounds());
3104 // Move one of the views. Make sure the layer is positioned correctly
3105 // afterwards.
3106 v1->SetBounds(v1->x() - 5, v1->y(), v1->width(), v1->height());
3107 l1bounds.set_x(l1bounds.x() + 5);
3108 EXPECT_EQ(l1bounds, v1->layer()->bounds());
3110 view->SetPaintToLayer(false);
3111 EXPECT_EQ(l1bounds, v1->layer()->bounds());
3112 EXPECT_EQ(l2bounds, v2->layer()->bounds());
3114 // Move a view again.
3115 v2->SetBounds(v2->x() + 5, v2->y(), v2->width(), v2->height());
3116 l2bounds.set_x(l2bounds.x() - 5);
3117 EXPECT_EQ(l2bounds, v2->layer()->bounds());
3119 // Reset locale.
3120 base::i18n::SetICUDefaultLocale(locale);
3123 // Makes sure a transform persists after toggling the visibility.
3124 TEST_F(ViewLayerTest, ToggleVisibilityWithTransform) {
3125 View* view = new View;
3126 gfx::Transform transform;
3127 transform.Scale(2.0, 2.0);
3128 view->SetTransform(transform);
3129 widget()->SetContentsView(view);
3130 EXPECT_EQ(2.0f, view->GetTransform().matrix().get(0, 0));
3132 view->SetVisible(false);
3133 EXPECT_EQ(2.0f, view->GetTransform().matrix().get(0, 0));
3135 view->SetVisible(true);
3136 EXPECT_EQ(2.0f, view->GetTransform().matrix().get(0, 0));
3139 // Verifies a transform persists after removing/adding a view with a transform.
3140 TEST_F(ViewLayerTest, ResetTransformOnLayerAfterAdd) {
3141 View* view = new View;
3142 gfx::Transform transform;
3143 transform.Scale(2.0, 2.0);
3144 view->SetTransform(transform);
3145 widget()->SetContentsView(view);
3146 EXPECT_EQ(2.0f, view->GetTransform().matrix().get(0, 0));
3147 ASSERT_TRUE(view->layer() != NULL);
3148 EXPECT_EQ(2.0f, view->layer()->transform().matrix().get(0, 0));
3150 View* parent = view->parent();
3151 parent->RemoveChildView(view);
3152 parent->AddChildView(view);
3154 EXPECT_EQ(2.0f, view->GetTransform().matrix().get(0, 0));
3155 ASSERT_TRUE(view->layer() != NULL);
3156 EXPECT_EQ(2.0f, view->layer()->transform().matrix().get(0, 0));
3159 // Makes sure that layer visibility is correct after toggling View visibility.
3160 TEST_F(ViewLayerTest, ToggleVisibilityWithLayer) {
3161 View* content_view = new View;
3162 widget()->SetContentsView(content_view);
3164 // The view isn't attached to a widget or a parent view yet. But it should
3165 // still have a layer, but the layer should not be attached to the root
3166 // layer.
3167 View* v1 = new View;
3168 v1->SetPaintToLayer(true);
3169 EXPECT_TRUE(v1->layer());
3170 EXPECT_FALSE(LayerIsAncestor(widget()->GetCompositor()->root_layer(),
3171 v1->layer()));
3173 // Once the view is attached to a widget, its layer should be attached to the
3174 // root layer and visible.
3175 content_view->AddChildView(v1);
3176 EXPECT_TRUE(LayerIsAncestor(widget()->GetCompositor()->root_layer(),
3177 v1->layer()));
3178 EXPECT_TRUE(v1->layer()->IsDrawn());
3180 v1->SetVisible(false);
3181 EXPECT_FALSE(v1->layer()->IsDrawn());
3183 v1->SetVisible(true);
3184 EXPECT_TRUE(v1->layer()->IsDrawn());
3186 widget()->Hide();
3187 EXPECT_FALSE(v1->layer()->IsDrawn());
3189 widget()->Show();
3190 EXPECT_TRUE(v1->layer()->IsDrawn());
3193 // Tests that the layers in the subtree are orphaned after a View is removed
3194 // from the parent.
3195 TEST_F(ViewLayerTest, OrphanLayerAfterViewRemove) {
3196 View* content_view = new View;
3197 widget()->SetContentsView(content_view);
3199 View* v1 = new View;
3200 content_view->AddChildView(v1);
3202 View* v2 = new View;
3203 v1->AddChildView(v2);
3204 v2->SetPaintToLayer(true);
3205 EXPECT_TRUE(LayerIsAncestor(widget()->GetCompositor()->root_layer(),
3206 v2->layer()));
3207 EXPECT_TRUE(v2->layer()->IsDrawn());
3209 content_view->RemoveChildView(v1);
3211 EXPECT_FALSE(LayerIsAncestor(widget()->GetCompositor()->root_layer(),
3212 v2->layer()));
3214 // Reparent |v2|.
3215 content_view->AddChildView(v2);
3216 delete v1;
3217 v1 = NULL;
3218 EXPECT_TRUE(LayerIsAncestor(widget()->GetCompositor()->root_layer(),
3219 v2->layer()));
3220 EXPECT_TRUE(v2->layer()->IsDrawn());
3223 class PaintTrackingView : public View {
3224 public:
3225 PaintTrackingView() : painted_(false) {
3228 bool painted() const { return painted_; }
3229 void set_painted(bool value) { painted_ = value; }
3231 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
3232 painted_ = true;
3235 private:
3236 bool painted_;
3238 DISALLOW_COPY_AND_ASSIGN(PaintTrackingView);
3241 // Makes sure child views with layers aren't painted when paint starts at an
3242 // ancestor.
3243 TEST_F(ViewLayerTest, DontPaintChildrenWithLayers) {
3244 PaintTrackingView* content_view = new PaintTrackingView;
3245 widget()->SetContentsView(content_view);
3246 content_view->SetPaintToLayer(true);
3247 GetRootLayer()->GetCompositor()->ScheduleDraw();
3248 ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor());
3249 GetRootLayer()->SchedulePaint(gfx::Rect(0, 0, 10, 10));
3250 content_view->set_painted(false);
3251 // content_view no longer has a dirty rect. Paint from the root and make sure
3252 // PaintTrackingView isn't painted.
3253 GetRootLayer()->GetCompositor()->ScheduleDraw();
3254 ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor());
3255 EXPECT_FALSE(content_view->painted());
3257 // Make content_view have a dirty rect, paint the layers and make sure
3258 // PaintTrackingView is painted.
3259 content_view->layer()->SchedulePaint(gfx::Rect(0, 0, 10, 10));
3260 GetRootLayer()->GetCompositor()->ScheduleDraw();
3261 ui::DrawWaiterForTest::Wait(GetRootLayer()->GetCompositor());
3262 EXPECT_TRUE(content_view->painted());
3265 // Tests that the visibility of child layers are updated correctly when a View's
3266 // visibility changes.
3267 TEST_F(ViewLayerTest, VisibilityChildLayers) {
3268 View* v1 = new View;
3269 v1->SetPaintToLayer(true);
3270 widget()->SetContentsView(v1);
3272 View* v2 = new View;
3273 v1->AddChildView(v2);
3275 View* v3 = new View;
3276 v2->AddChildView(v3);
3277 v3->SetVisible(false);
3279 View* v4 = new View;
3280 v4->SetPaintToLayer(true);
3281 v3->AddChildView(v4);
3283 EXPECT_TRUE(v1->layer()->IsDrawn());
3284 EXPECT_FALSE(v4->layer()->IsDrawn());
3286 v2->SetVisible(false);
3287 EXPECT_TRUE(v1->layer()->IsDrawn());
3288 EXPECT_FALSE(v4->layer()->IsDrawn());
3290 v2->SetVisible(true);
3291 EXPECT_TRUE(v1->layer()->IsDrawn());
3292 EXPECT_FALSE(v4->layer()->IsDrawn());
3294 v2->SetVisible(false);
3295 EXPECT_TRUE(v1->layer()->IsDrawn());
3296 EXPECT_FALSE(v4->layer()->IsDrawn());
3297 EXPECT_TRUE(ViewAndLayerTreeAreConsistent(v1, v1->layer()));
3299 v3->SetVisible(true);
3300 EXPECT_TRUE(v1->layer()->IsDrawn());
3301 EXPECT_FALSE(v4->layer()->IsDrawn());
3302 EXPECT_TRUE(ViewAndLayerTreeAreConsistent(v1, v1->layer()));
3304 // Reparent |v3| to |v1|.
3305 v1->AddChildView(v3);
3306 EXPECT_TRUE(v1->layer()->IsDrawn());
3307 EXPECT_TRUE(v4->layer()->IsDrawn());
3308 EXPECT_TRUE(ViewAndLayerTreeAreConsistent(v1, v1->layer()));
3311 // This test creates a random View tree, and then randomly reorders child views,
3312 // reparents views etc. Unrelated changes can appear to break this test. So
3313 // marking this as FLAKY.
3314 TEST_F(ViewLayerTest, DISABLED_ViewLayerTreesInSync) {
3315 View* content = new View;
3316 content->SetPaintToLayer(true);
3317 widget()->SetContentsView(content);
3318 widget()->Show();
3320 ConstructTree(content, 5);
3321 EXPECT_TRUE(ViewAndLayerTreeAreConsistent(content, content->layer()));
3323 ScrambleTree(content);
3324 EXPECT_TRUE(ViewAndLayerTreeAreConsistent(content, content->layer()));
3326 ScrambleTree(content);
3327 EXPECT_TRUE(ViewAndLayerTreeAreConsistent(content, content->layer()));
3329 ScrambleTree(content);
3330 EXPECT_TRUE(ViewAndLayerTreeAreConsistent(content, content->layer()));
3333 // Verifies when views are reordered the layer is also reordered. The widget is
3334 // providing the parent layer.
3335 TEST_F(ViewLayerTest, ReorderUnderWidget) {
3336 View* content = new View;
3337 widget()->SetContentsView(content);
3338 View* c1 = new View;
3339 c1->SetPaintToLayer(true);
3340 content->AddChildView(c1);
3341 View* c2 = new View;
3342 c2->SetPaintToLayer(true);
3343 content->AddChildView(c2);
3345 ui::Layer* parent_layer = c1->layer()->parent();
3346 ASSERT_TRUE(parent_layer);
3347 ASSERT_EQ(2u, parent_layer->children().size());
3348 EXPECT_EQ(c1->layer(), parent_layer->children()[0]);
3349 EXPECT_EQ(c2->layer(), parent_layer->children()[1]);
3351 // Move c1 to the front. The layers should have moved too.
3352 content->ReorderChildView(c1, -1);
3353 EXPECT_EQ(c1->layer(), parent_layer->children()[1]);
3354 EXPECT_EQ(c2->layer(), parent_layer->children()[0]);
3357 // Verifies that the layer of a view can be acquired properly.
3358 TEST_F(ViewLayerTest, AcquireLayer) {
3359 View* content = new View;
3360 widget()->SetContentsView(content);
3361 scoped_ptr<View> c1(new View);
3362 c1->SetPaintToLayer(true);
3363 EXPECT_TRUE(c1->layer());
3364 content->AddChildView(c1.get());
3366 scoped_ptr<ui::Layer> layer(c1->AcquireLayer());
3367 EXPECT_EQ(layer.get(), c1->layer());
3369 scoped_ptr<ui::Layer> layer2(c1->RecreateLayer());
3370 EXPECT_NE(c1->layer(), layer2.get());
3372 // Destroy view before destroying layer.
3373 c1.reset();
3376 // Verify that new layer scales content only if the old layer does.
3377 TEST_F(ViewLayerTest, RecreateLayerScaling) {
3378 scoped_ptr<View> v(new View());
3379 v->SetPaintToLayer(true);
3380 // Set to non default value.
3381 v->layer()->set_scale_content(false);
3382 scoped_ptr<ui::Layer> old_layer(v->RecreateLayer());
3383 ui::Layer* new_layer = v->layer();
3384 EXPECT_FALSE(new_layer->scale_content());
3387 // Verify the z-order of the layers as a result of calling RecreateLayer().
3388 TEST_F(ViewLayerTest, RecreateLayerZOrder) {
3389 scoped_ptr<View> v(new View());
3390 v->SetPaintToLayer(true);
3392 View* v1 = new View();
3393 v1->SetPaintToLayer(true);
3394 v->AddChildView(v1);
3395 View* v2 = new View();
3396 v2->SetPaintToLayer(true);
3397 v->AddChildView(v2);
3399 // Test the initial z-order.
3400 const std::vector<ui::Layer*>& child_layers_pre = v->layer()->children();
3401 ASSERT_EQ(2u, child_layers_pre.size());
3402 EXPECT_EQ(v1->layer(), child_layers_pre[0]);
3403 EXPECT_EQ(v2->layer(), child_layers_pre[1]);
3405 scoped_ptr<ui::Layer> v1_old_layer(v1->RecreateLayer());
3407 // Test the new layer order. |v1_old_layer| should be above the layers
3408 // for |v1| and |v2|.
3409 const std::vector<ui::Layer*>& child_layers_post = v->layer()->children();
3410 ASSERT_EQ(3u, child_layers_post.size());
3411 EXPECT_EQ(v1->layer(), child_layers_post[0]);
3412 EXPECT_EQ(v2->layer(), child_layers_post[1]);
3413 EXPECT_EQ(v1_old_layer, child_layers_post[2]);
3416 // Verify the z-order of the layers as a result of calling RecreateLayer when
3417 // the widget is the parent with the layer.
3418 TEST_F(ViewLayerTest, RecreateLayerZOrderWidgetParent) {
3419 View* v = new View();
3420 widget()->SetContentsView(v);
3422 View* v1 = new View();
3423 v1->SetPaintToLayer(true);
3424 v->AddChildView(v1);
3425 View* v2 = new View();
3426 v2->SetPaintToLayer(true);
3427 v->AddChildView(v2);
3429 ui::Layer* root_layer = GetRootLayer();
3431 // Test the initial z-order.
3432 const std::vector<ui::Layer*>& child_layers_pre = root_layer->children();
3433 ASSERT_EQ(2u, child_layers_pre.size());
3434 EXPECT_EQ(v1->layer(), child_layers_pre[0]);
3435 EXPECT_EQ(v2->layer(), child_layers_pre[1]);
3437 scoped_ptr<ui::Layer> v1_old_layer(v1->RecreateLayer());
3439 // Test the new layer order. |v1_old_layer| should be above the layers
3440 // for |v1| and |v2|.
3441 const std::vector<ui::Layer*>& child_layers_post = root_layer->children();
3442 ASSERT_EQ(3u, child_layers_post.size());
3443 EXPECT_EQ(v1->layer(), child_layers_post[0]);
3444 EXPECT_EQ(v2->layer(), child_layers_post[1]);
3445 EXPECT_EQ(v1_old_layer, child_layers_post[2]);
3448 #endif // USE_AURA
3450 } // namespace views