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.
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"
39 #include "ui/views/test/test_views_delegate.h"
42 #include "ui/aura/root_window.h"
43 #include "ui/events/gestures/gesture_recognizer.h"
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())
65 const views::View
* NextView(const views::View
* view
) {
66 const views::View
* v
= view
;
67 const views::View
* parent
= v
->parent();
70 int next
= parent
->GetIndexOf(v
) + 1;
71 if (next
!= parent
->child_count())
72 return FirstView(parent
->child_at(next
));
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)
84 const ui::Layer
* NextLayer(const ui::Layer
* layer
) {
85 const ui::Layer
* parent
= layer
->parent();
88 const std::vector
<ui::Layer
*> children
= parent
->children();
90 for (index
= 0; index
< children
.size(); index
++) {
91 if (children
[index
] == layer
)
94 size_t next
= index
+ 1;
95 if (next
< children
.size())
96 return FirstLayer(children
[next
]);
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
);
107 // Find the view with a layer.
108 while (v
&& !v
->layer())
114 // Check if the View tree and the Layer tree are in sync.
115 EXPECT_EQ(l
, v
->layer());
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();
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())
135 if (v
== view
|| l
== layer
)
136 return v
== view
&& l
== layer
;
145 // Constructs a View tree with the specified depth.
146 void ConstructTree(views::View
* view
, int depth
) {
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();
166 for (int i
= 0; i
< count
; i
++) {
167 ScrambleTree(view
->child_at(i
));
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
{
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) {
196 DISALLOW_COPY_AND_ASSIGN(GestureEventForTest
);
203 typedef ViewsTestBase ViewTest
;
205 // A derived class for testing purpose.
206 class TestView
: public View
{
208 TestView() : View(), delete_on_pressed_(false), in_touch_sequence_(false) {}
209 virtual ~TestView() {}
211 // Reset all test state
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
;
242 bool did_change_bounds_
;
243 gfx::Rect new_bounds_
;
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_
;
253 std::vector
<gfx::Rect
> scheduled_paint_rects_
;
256 int last_gesture_event_type_
;
257 bool last_gesture_event_was_handled_
;
260 int last_touch_event_type_
;
261 bool last_touch_event_was_handled_
;
262 bool in_touch_sequence_
;
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
{
274 TestViewIgnoreTouch() : TestView() {}
275 virtual ~TestViewIgnoreTouch() {}
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
{
284 TestViewConsumeGesture() : TestView() {}
285 virtual ~TestViewConsumeGesture() {}
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();
295 DISALLOW_COPY_AND_ASSIGN(TestViewConsumeGesture
);
298 // A view subclass that ignores all Gesture events.
299 class TestViewIgnoreGesture
: public TestView
{
301 TestViewIgnoreGesture() : TestView() {}
302 virtual ~TestViewIgnoreGesture() {}
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
313 class TestViewIgnoreScrollGestures
: public TestViewConsumeGesture
{
315 TestViewIgnoreScrollGestures() {}
316 virtual ~TestViewIgnoreScrollGestures() {}
319 virtual void OnGestureEvent(ui::GestureEvent
* event
) OVERRIDE
{
320 if (event
->IsScrollGestureEvent())
322 TestViewConsumeGesture::OnGestureEvent(event
);
325 DISALLOW_COPY_AND_ASSIGN(TestViewIgnoreScrollGestures
);
328 ////////////////////////////////////////////////////////////////////////////////
330 ////////////////////////////////////////////////////////////////////////////////
332 void TestView::OnBoundsChanged(const gfx::Rect
& previous_bounds
) {
333 did_change_bounds_
= true;
334 new_bounds_
= bounds();
337 TEST_F(ViewTest
, OnBoundsChanged
) {
340 gfx::Rect
prev_rect(0, 0, 200, 200);
341 gfx::Rect
new_rect(100, 100, 250, 250);
343 v
.SetBoundsRect(prev_rect
);
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 ////////////////////////////////////////////////////////////////////////////////
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_
)
364 bool TestView::OnMouseDragged(const ui::MouseEvent
& event
) {
365 last_mouse_event_type_
= event
.type();
366 location_
.SetPoint(event
.x(), event
.y());
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
);
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
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
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);
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));
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());
472 ////////////////////////////////////////////////////////////////////////////////
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();
485 if (event
->type() == ui::ET_TOUCH_RELEASED
) {
486 in_touch_sequence_
= false;
490 event
->StopPropagation();
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
531 ui::TouchEvent
unhandled(ui::ET_TOUCH_MOVED
,
532 gfx::Point(400, 400),
534 0, /* first finger touch */
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.
546 ui::TouchEvent
pressed(ui::ET_TOUCH_PRESSED
,
547 gfx::Point(110, 120),
549 0, /* first finger touch */
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
564 ui::TouchEvent
dragged(ui::ET_TOUCH_MOVED
,
567 0, /* first finger touch */
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
581 ui::TouchEvent
released(ui::ET_TOUCH_RELEASED
, gfx::Point(),
583 0, /* first finger */
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);
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
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
);
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());
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
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_
);
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
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_
);
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_
);
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_
);
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_
);
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());
758 ////////////////////////////////////////////////////////////////////////////////
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);
816 v3->SchedulePaintInRect(gfx::Rect(10, 10, 10, 10));
817 PaintRootView(root, empty_paint);
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
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();
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
);
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.
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
));
927 class HitTestView
: public View
{
929 explicit HitTestView(bool has_hittest_mask
)
930 : has_hittest_mask_(has_hittest_mask
) {
932 virtual ~HitTestView() {}
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_
);
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);
955 bool has_hittest_mask_
;
957 DISALLOW_COPY_AND_ASSIGN(HitTestView
);
960 gfx::Point
ConvertPointToView(View
* view
, const gfx::Point
& p
) {
962 View::ConvertPointToTarget(view
->GetWidget()->GetRootView(), view
, &tmp
);
966 gfx::Rect
ConvertRectToView(View
* view
, const gfx::Rect
& r
) {
968 tmp
.set_origin(ConvertPointToView(view
, r
.origin()));
972 void RotateCounterclockwise(gfx::Transform
* transform
) {
973 transform
->matrix().set3x3(0, -1, 0,
978 void RotateClockwise(gfx::Transform
* transform
) {
979 transform
->matrix().set3x3( 0, 1, 0,
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
)));
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
));
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
1180 touch_rect
.SetRect(0, 200, 200, 100);
1181 result_view
= root_view
->GetEventHandlerForRect(touch_rect
);
1182 EXPECT_EQ(v3
, result_view
);
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
);
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
);
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
);
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
);
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
);
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
);
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
1231 touch_rect
.SetRect(368, 272, 4, 6);
1232 result_view
= root_view
->GetEventHandlerForRect(touch_rect
);
1233 EXPECT_EQ(v411
, result_view
);
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
1239 touch_rect
.SetRect(365, 270, 7, 7);
1240 result_view
= root_view
->GetEventHandlerForRect(touch_rect
);
1241 EXPECT_EQ(v41
, result_view
);
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
1247 touch_rect
.SetRect(205, 275, 200, 2);
1248 result_view
= root_view
->GetEventHandlerForRect(touch_rect
);
1249 EXPECT_EQ(v4
, result_view
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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_
);
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_
);
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_
);
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_
);
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_
);
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_
);
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_
);
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());
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
);
1494 normal
->SelectAll(false);
1495 normal
->ExecuteCommand(IDS_APP_CUT
);
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
);
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
);
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
);
1519 // Start with |read_only| to observe a change in clipboard text.
1520 read_only
->SelectAll(false);
1521 read_only
->ExecuteCommand(IDS_APP_COPY
);
1523 clipboard
->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE
, &result
);
1524 EXPECT_EQ(kReadOnlyText
, result
);
1526 normal
->SelectAll(false);
1527 normal
->ExecuteCommand(IDS_APP_COPY
);
1529 clipboard
->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE
, &result
);
1530 EXPECT_EQ(kNormalText
, result
);
1532 password
->SelectAll(false);
1533 password
->ExecuteCommand(IDS_APP_COPY
);
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
);
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());
1561 ////////////////////////////////////////////////////////////////////////////////
1563 ////////////////////////////////////////////////////////////////////////////////
1564 bool TestView::AcceleratorPressed(const ui::Accelerator
& accelerator
) {
1565 accelerator_count_map_
[accelerator
]++;
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();
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
);
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);
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();
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
);
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
));
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();
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
]);
1689 EXPECT_TRUE(focus_manager
->ProcessAccelerator(return_accelerator
));
1690 EXPECT_EQ(1, view
->accelerator_count_map_
[return_accelerator
]);
1693 EXPECT_FALSE(focus_manager
->ProcessAccelerator(return_accelerator
));
1694 EXPECT_EQ(1, view
->accelerator_count_map_
[return_accelerator
]);
1700 #if defined(OS_WIN) && !defined(USE_AURA)
1701 ////////////////////////////////////////////////////////////////////////////////
1702 // Mouse-wheel message rerouting
1703 ////////////////////////////////////////////////////////////////////////////////
1704 class ScrollableTestView
: public View
{
1706 ScrollableTestView() { }
1708 virtual gfx::Size
GetPreferredSize() {
1709 return gfx::Size(100, 10000);
1712 virtual void Layout() {
1713 SizeToPreferredSize();
1717 class TestViewWithControls
: public View
{
1719 TestViewWithControls() {
1720 text_field_
= new Textfield();
1721 AddChildView(text_field_
);
1724 Textfield
* text_field_
;
1727 class SimpleWidgetDelegate
: public WidgetDelegate
{
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(); }
1742 // Tests that the mouse-wheel messages are correctly rerouted to the window
1744 // TODO(jcampan): http://crbug.com/10572 Disabled as it fails on the Vista build
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));
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));
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
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();
1792 ////////////////////////////////////////////////////////////////////////////////
1793 // Native view hierachy
1794 ////////////////////////////////////////////////////////////////////////////////
1795 class ToplevelWidgetObserverView
: public View
{
1797 ToplevelWidgetObserverView() : toplevel_(NULL
) {
1799 virtual ~ToplevelWidgetObserverView() {
1803 virtual void ViewHierarchyChanged(
1804 const ViewHierarchyChangedDetails
& details
) OVERRIDE
{
1805 if (details
.is_add
) {
1806 toplevel_
= GetWidget() ? GetWidget()->GetTopLevelWidget() : NULL
;
1811 virtual void NativeViewHierarchyChanged() OVERRIDE
{
1812 toplevel_
= GetWidget() ? GetWidget()->GetTopLevelWidget() : NULL
;
1815 Widget
* toplevel() { return 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
1859 child
->SetContentsView(observer_view
);
1862 ////////////////////////////////////////////////////////////////////////////////
1864 ////////////////////////////////////////////////////////////////////////////////
1866 class TransformPaintView
: public TestView
{
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
);
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
);
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());
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|.
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|.
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|.
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());
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
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
);
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());
2101 ////////////////////////////////////////////////////////////////////////////////
2102 // OnVisibleBoundsChanged()
2104 class VisibleBoundsView
: public View
{
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
;
2115 // Overridden from View:
2116 virtual bool NeedsNotificationWhenVisibleBoundsChange() const OVERRIDE
{
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
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);
2173 ////////////////////////////////////////////////////////////////////////////////
2176 TEST_F(ViewTest
, SetBoundsPaint
) {
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
) {
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);
2249 t2
.Scale(100.0, 55.0);
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
));
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
));
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());
2429 class ObserverView
: public View
{
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_
;
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
;
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
2488 // The tree looks like this:
2492 // +-- v4 (starts here, then get reparented to v1)
2493 TEST_F(ViewTest
, ViewHierarchyChanged
) {
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()
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();
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
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:
2630 TEST_F(ViewTest
, RemoveAllChildViews
) {
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
) {
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
2683 // The tree looks like this:
2688 TEST_F(ViewTest
, GetIndexOf
) {
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
) {
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
2775 // The tree looks like this:
2780 TEST_F(ViewTest
, GetViewByID
) {
2782 const int kV1ID
= 1;
2786 const int kV2ID
= 2;
2790 const int kV3ID
= 3;
2794 const int kV4ID
= 4;
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
);
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
) {
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 ////////////////////////////////////////////////////////////////////////////////
2860 ////////////////////////////////////////////////////////////////////////////////
2862 #if defined(USE_AURA)
2866 // Test implementation of LayerAnimator.
2867 class TestLayerAnimator
: public ui::LayerAnimator
{
2869 TestLayerAnimator();
2871 const gfx::Rect
& last_bounds() const { return last_bounds_
; }
2874 virtual void SetBounds(const gfx::Rect
& bounds
) OVERRIDE
;
2877 virtual ~TestLayerAnimator() { }
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
;
2895 class ViewLayerTest
: public ViewsTestBase
{
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
{
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
);
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_
; }
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
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
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
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
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());
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
3167 View
* v1
= new View
;
3168 v1
->SetPaintToLayer(true);
3169 EXPECT_TRUE(v1
->layer());
3170 EXPECT_FALSE(LayerIsAncestor(widget()->GetCompositor()->root_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(),
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());
3187 EXPECT_FALSE(v1
->layer()->IsDrawn());
3190 EXPECT_TRUE(v1
->layer()->IsDrawn());
3193 // Tests that the layers in the subtree are orphaned after a View is removed
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(),
3207 EXPECT_TRUE(v2
->layer()->IsDrawn());
3209 content_view
->RemoveChildView(v1
);
3211 EXPECT_FALSE(LayerIsAncestor(widget()->GetCompositor()->root_layer(),
3215 content_view
->AddChildView(v2
);
3218 EXPECT_TRUE(LayerIsAncestor(widget()->GetCompositor()->root_layer(),
3220 EXPECT_TRUE(v2
->layer()->IsDrawn());
3223 class PaintTrackingView
: public View
{
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
{
3238 DISALLOW_COPY_AND_ASSIGN(PaintTrackingView
);
3241 // Makes sure child views with layers aren't painted when paint starts at an
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
);
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.
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]);
3450 } // namespace views