1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ui/views/view.h"
6
7 #include <stddef.h>
8
9 #include <map>
10 #include <memory>
11
12 #include "base/bind.h"
13 #include "base/command_line.h"
14 #include "base/i18n/rtl.h"
15
16 #include "base/macros.h"
17 #include "base/rand_util.h"
18 #include "base/run_loop.h"
19 #include "base/stl_util.h"
20 #include "base/strings/string_util.h"
21 #include "base/strings/stringprintf.h"
22 #include "base/strings/utf_string_conversions.h"
23 #include "base/test/icu_test_util.h"
24 #include "base/test/scoped_feature_list.h"
25 #include "base/time/time.h"
26 #include "build/build_config.h"
27 #include "cc/paint/display_item_list.h"
28 #include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
29 #include "ui/accessibility/ax_enums.mojom.h"
30 #include "ui/base/accelerators/accelerator.h"
31 #include "ui/base/clipboard/clipboard.h"
32 #include "ui/base/l10n/l10n_util.h"
33 #include "ui/compositor/compositor.h"
34 #include "ui/compositor/compositor_switches.h"
35 #include "ui/compositor/layer.h"
36 #include "ui/compositor/layer_animator.h"
37 #include "ui/compositor/paint_context.h"
38 #include "ui/compositor/test/draw_waiter_for_test.h"
39 #include "ui/compositor/test/test_layers.h"
40 #include "ui/events/event.h"
41 #include "ui/events/event_utils.h"
42 #include "ui/events/keycodes/keyboard_codes.h"
43 #include "ui/events/scoped_target_handler.h"
44 #include "ui/events/test/event_generator.h"
45 #include "ui/gfx/canvas.h"
46 #include "ui/gfx/transform.h"
47 #include "ui/native_theme/native_theme.h"
48 #include "ui/native_theme/test_native_theme.h"
49 #include "ui/strings/grit/ui_strings.h"
50 #include "ui/views/background.h"
51 #include "ui/views/controls/native/native_view_host.h"
52 #include "ui/views/controls/scroll_view.h"
53 #include "ui/views/controls/textfield/textfield.h"
54 #include "ui/views/metadata/metadata_types.h"
55 #include "ui/views/paint_info.h"
56 #include "ui/views/test/views_test_base.h"
57 #include "ui/views/view_observer.h"
58 #include "ui/views/views_features.h"
59 #include "ui/views/widget/native_widget.h"
60 #include "ui/views/widget/root_view.h"
61 #include "ui/views/window/dialog_delegate.h"
62
63 using base::ASCIIToUTF16;
64
65 namespace {
66
67 // Returns true if |ancestor| is an ancestor of |layer|.
LayerIsAncestor(const ui::Layer * ancestor,const ui::Layer * layer)68 bool LayerIsAncestor(const ui::Layer* ancestor, const ui::Layer* layer) {
69 while (layer && layer != ancestor)
70 layer = layer->parent();
71 return layer == ancestor;
72 }
73
74 // Convenience functions for walking a View tree.
FirstView(const views::View * view)75 const views::View* FirstView(const views::View* view) {
76 const views::View* v = view;
77 while (!v->children().empty())
78 v = v->children().front();
79 return v;
80 }
81
NextView(const views::View * view)82 const views::View* NextView(const views::View* view) {
83 const views::View* v = view;
84 const views::View* parent = v->parent();
85 if (!parent)
86 return nullptr;
87 const auto next = std::next(parent->FindChild(v));
88 return (next == parent->children().cend()) ? parent : FirstView(*next);
89 }
90
91 // Convenience functions for walking a Layer tree.
FirstLayer(const ui::Layer * layer)92 const ui::Layer* FirstLayer(const ui::Layer* layer) {
93 const ui::Layer* l = layer;
94 while (!l->children().empty())
95 l = l->children().front();
96 return l;
97 }
98
NextLayer(const ui::Layer * layer)99 const ui::Layer* NextLayer(const ui::Layer* layer) {
100 const ui::Layer* parent = layer->parent();
101 if (!parent)
102 return nullptr;
103 const std::vector<ui::Layer*> children = parent->children();
104 const auto i = std::find(children.cbegin(), children.cend(), layer) + 1;
105 return (i == children.cend()) ? parent : FirstLayer(*i);
106 }
107
108 // Given the root nodes of a View tree and a Layer tree, makes sure the two
109 // trees are in sync.
ViewAndLayerTreeAreConsistent(const views::View * view,const ui::Layer * layer)110 bool ViewAndLayerTreeAreConsistent(const views::View* view,
111 const ui::Layer* layer) {
112 const views::View* v = FirstView(view);
113 const ui::Layer* l = FirstLayer(layer);
114 while (v && l) {
115 // Find the view with a layer.
116 while (v && !v->layer())
117 v = NextView(v);
118 EXPECT_TRUE(v);
119 if (!v)
120 return false;
121
122 // Check if the View tree and the Layer tree are in sync.
123 EXPECT_EQ(l, v->layer());
124 if (v->layer() != l)
125 return false;
126
127 // Check if the visibility states of the View and the Layer are in sync.
128 EXPECT_EQ(l->IsDrawn(), v->IsDrawn());
129 if (v->IsDrawn() != l->IsDrawn()) {
130 for (const views::View* vv = v; vv; vv = vv->parent())
131 LOG(ERROR) << "V: " << vv << " " << vv->GetVisible() << " "
132 << vv->IsDrawn() << " " << vv->layer();
133 for (const ui::Layer* ll = l; ll; ll = ll->parent())
134 LOG(ERROR) << "L: " << ll << " " << ll->IsDrawn();
135 return false;
136 }
137
138 // Check if the size of the View and the Layer are in sync.
139 EXPECT_EQ(l->bounds(), v->bounds());
140 if (v->bounds() != l->bounds())
141 return false;
142
143 if (v == view || l == layer)
144 return v == view && l == layer;
145
146 v = NextView(v);
147 l = NextLayer(l);
148 }
149
150 return false;
151 }
152
153 // Constructs a View tree with the specified depth.
ConstructTree(views::View * view,int depth)154 void ConstructTree(views::View* view, int depth) {
155 if (depth == 0)
156 return;
157 int count = base::RandInt(1, 5);
158 for (int i = 0; i < count; i++) {
159 views::View* v = new views::View;
160 view->AddChildView(v);
161 if (base::RandDouble() > 0.5)
162 v->SetPaintToLayer();
163 if (base::RandDouble() < 0.2)
164 v->SetVisible(false);
165
166 ConstructTree(v, depth - 1);
167 }
168 }
169
ScrambleTree(views::View * view)170 void ScrambleTree(views::View* view) {
171 if (view->children().empty())
172 return;
173
174 for (views::View* child : view->children())
175 ScrambleTree(child);
176
177 size_t count = view->children().size();
178 if (count > 1) {
179 const uint64_t max = count - 1;
180 size_t a = size_t{base::RandGenerator(max)};
181 size_t b = size_t{base::RandGenerator(max)};
182
183 if (a != b) {
184 views::View* view_a = view->children()[a];
185 views::View* view_b = view->children()[b];
186 view->ReorderChildView(view_a, b);
187 view->ReorderChildView(view_b, a);
188 }
189 }
190
191 if (!view->layer() && base::RandDouble() < 0.1)
192 view->SetPaintToLayer();
193
194 if (base::RandDouble() < 0.1)
195 view->SetVisible(!view->GetVisible());
196 }
197
198 } // namespace
199
200 namespace views {
201
202 using ViewTest = ViewsTestBase;
203
204 // A derived class for testing purpose.
205 class TestView : public View {
206 public:
207 TestView() = default;
208 ~TestView() override = default;
209
210 // Reset all test state
Reset()211 void Reset() {
212 did_change_bounds_ = false;
213 did_layout_ = false;
214 last_mouse_event_type_ = 0;
215 location_.SetPoint(0, 0);
216 received_mouse_enter_ = false;
217 received_mouse_exit_ = false;
218 did_paint_ = false;
219 accelerator_count_map_.clear();
220 can_process_events_within_subtree_ = true;
221 }
222
223 // Exposed as public for testing.
DoFocus()224 void DoFocus() { views::View::Focus(); }
225
DoBlur()226 void DoBlur() { views::View::Blur(); }
227
set_can_process_events_within_subtree(bool can_process)228 void set_can_process_events_within_subtree(bool can_process) {
229 can_process_events_within_subtree_ = can_process;
230 }
231
CanProcessEventsWithinSubtree() const232 bool CanProcessEventsWithinSubtree() const override {
233 return can_process_events_within_subtree_;
234 }
235
Layout()236 void Layout() override {
237 did_layout_ = true;
238 View::Layout();
239 }
240
241 void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
242 bool OnMousePressed(const ui::MouseEvent& event) override;
243 bool OnMouseDragged(const ui::MouseEvent& event) override;
244 void OnMouseReleased(const ui::MouseEvent& event) override;
245 void OnMouseEntered(const ui::MouseEvent& event) override;
246 void OnMouseExited(const ui::MouseEvent& event) override;
247
248 void OnPaint(gfx::Canvas* canvas) override;
249 void OnDidSchedulePaint(const gfx::Rect& rect) override;
250 bool AcceleratorPressed(const ui::Accelerator& accelerator) override;
251
252 void OnThemeChanged() override;
253
254 void OnAccessibilityEvent(ax::mojom::Event event_type) override;
255
256 // OnBoundsChanged.
257 bool did_change_bounds_;
258 gfx::Rect new_bounds_;
259
260 // Layout.
261 bool did_layout_ = false;
262
263 // MouseEvent.
264 int last_mouse_event_type_;
265 gfx::Point location_;
266 bool received_mouse_enter_;
267 bool received_mouse_exit_;
268 bool delete_on_pressed_ = false;
269
270 // Painting.
271 std::vector<gfx::Rect> scheduled_paint_rects_;
272 bool did_paint_ = false;
273
274 // Accelerators.
275 std::map<ui::Accelerator, int> accelerator_count_map_;
276
277 // Native theme.
278 const ui::NativeTheme* native_theme_ = nullptr;
279
280 // Value to return from CanProcessEventsWithinSubtree().
281 bool can_process_events_within_subtree_ = true;
282
283 // Accessibility events
284 ax::mojom::Event last_a11y_event_;
285 };
286
287 ////////////////////////////////////////////////////////////////////////////////
288 // Layout
289 ////////////////////////////////////////////////////////////////////////////////
290
TEST_F(ViewTest,LayoutCalledInvalidateAndOriginChanges)291 TEST_F(ViewTest, LayoutCalledInvalidateAndOriginChanges) {
292 TestView parent;
293 TestView* child = new TestView;
294 gfx::Rect parent_rect(0, 0, 100, 100);
295 parent.SetBoundsRect(parent_rect);
296
297 parent.Reset();
298 // |AddChildView| invalidates parent's layout.
299 parent.AddChildView(child);
300 // Change rect so that only rect's origin is affected.
301 parent.SetBoundsRect(parent_rect + gfx::Vector2d(10, 0));
302
303 EXPECT_TRUE(parent.did_layout_);
304
305 // After child layout is invalidated, parent and child must be laid out
306 // during parent->BoundsChanged(...) call.
307 parent.Reset();
308 child->Reset();
309
310 child->InvalidateLayout();
311 parent.SetBoundsRect(parent_rect + gfx::Vector2d(20, 0));
312 EXPECT_TRUE(parent.did_layout_);
313 EXPECT_TRUE(child->did_layout_);
314 }
315
316 // Tests that SizeToPreferredSize will trigger a Layout if the size has changed
317 // or if layout is marked invalid.
TEST_F(ViewTest,SizeToPreferredSizeInducesLayout)318 TEST_F(ViewTest, SizeToPreferredSizeInducesLayout) {
319 TestView example_view;
320 example_view.SetPreferredSize(gfx::Size(101, 102));
321 example_view.SizeToPreferredSize();
322 EXPECT_TRUE(example_view.did_layout_);
323
324 example_view.Reset();
325 example_view.SizeToPreferredSize();
326 EXPECT_FALSE(example_view.did_layout_);
327
328 example_view.InvalidateLayout();
329 example_view.SizeToPreferredSize();
330 EXPECT_TRUE(example_view.did_layout_);
331 }
332
333 ////////////////////////////////////////////////////////////////////////////////
334 // OnBoundsChanged
335 ////////////////////////////////////////////////////////////////////////////////
336
OnAccessibilityEvent(ax::mojom::Event event_type)337 void TestView::OnAccessibilityEvent(ax::mojom::Event event_type) {
338 last_a11y_event_ = event_type;
339 }
340
TEST_F(ViewTest,OnBoundsChangedFiresA11yEvent)341 TEST_F(ViewTest, OnBoundsChangedFiresA11yEvent) {
342 TestView v;
343
344 // Should change when scaled or moved.
345 gfx::Rect initial(0, 0, 200, 200);
346 gfx::Rect scaled(0, 0, 250, 250);
347 gfx::Rect moved(100, 100, 250, 250);
348
349 v.last_a11y_event_ = ax::mojom::Event::kNone;
350 v.SetBoundsRect(initial);
351 EXPECT_EQ(v.last_a11y_event_, ax::mojom::Event::kLocationChanged);
352
353 v.last_a11y_event_ = ax::mojom::Event::kNone;
354 v.SetBoundsRect(scaled);
355 EXPECT_EQ(v.last_a11y_event_, ax::mojom::Event::kLocationChanged);
356
357 v.last_a11y_event_ = ax::mojom::Event::kNone;
358 v.SetBoundsRect(moved);
359 EXPECT_EQ(v.last_a11y_event_, ax::mojom::Event::kLocationChanged);
360 }
361
OnBoundsChanged(const gfx::Rect & previous_bounds)362 void TestView::OnBoundsChanged(const gfx::Rect& previous_bounds) {
363 did_change_bounds_ = true;
364 new_bounds_ = bounds();
365 }
366
TEST_F(ViewTest,OnBoundsChanged)367 TEST_F(ViewTest, OnBoundsChanged) {
368 TestView v;
369
370 gfx::Rect prev_rect(0, 0, 200, 200);
371 gfx::Rect new_rect(100, 100, 250, 250);
372
373 v.SetBoundsRect(prev_rect);
374 v.Reset();
375 v.SetBoundsRect(new_rect);
376
377 EXPECT_TRUE(v.did_change_bounds_);
378 EXPECT_EQ(v.new_bounds_, new_rect);
379 EXPECT_EQ(v.bounds(), new_rect);
380 }
381
382 ////////////////////////////////////////////////////////////////////////////////
383 // OnStateChanged
384 ////////////////////////////////////////////////////////////////////////////////
385
TEST_F(ViewTest,OnStateChangedFiresA11yEvent)386 TEST_F(ViewTest, OnStateChangedFiresA11yEvent) {
387 TestView v;
388
389 v.last_a11y_event_ = ax::mojom::Event::kNone;
390 v.SetEnabled(false);
391 EXPECT_EQ(v.last_a11y_event_, ax::mojom::Event::kStateChanged);
392
393 v.last_a11y_event_ = ax::mojom::Event::kNone;
394 v.SetEnabled(true);
395 EXPECT_EQ(v.last_a11y_event_, ax::mojom::Event::kStateChanged);
396 }
397
398 ////////////////////////////////////////////////////////////////////////////////
399 // MouseEvent
400 ////////////////////////////////////////////////////////////////////////////////
401
OnMousePressed(const ui::MouseEvent & event)402 bool TestView::OnMousePressed(const ui::MouseEvent& event) {
403 last_mouse_event_type_ = event.type();
404 location_.SetPoint(event.x(), event.y());
405 if (delete_on_pressed_)
406 delete this;
407 return true;
408 }
409
OnMouseDragged(const ui::MouseEvent & event)410 bool TestView::OnMouseDragged(const ui::MouseEvent& event) {
411 last_mouse_event_type_ = event.type();
412 location_.SetPoint(event.x(), event.y());
413 return true;
414 }
415
OnMouseReleased(const ui::MouseEvent & event)416 void TestView::OnMouseReleased(const ui::MouseEvent& event) {
417 last_mouse_event_type_ = event.type();
418 location_.SetPoint(event.x(), event.y());
419 }
420
OnMouseEntered(const ui::MouseEvent & event)421 void TestView::OnMouseEntered(const ui::MouseEvent& event) {
422 received_mouse_enter_ = true;
423 }
424
OnMouseExited(const ui::MouseEvent & event)425 void TestView::OnMouseExited(const ui::MouseEvent& event) {
426 received_mouse_exit_ = true;
427 }
428
TEST_F(ViewTest,MouseEvent)429 TEST_F(ViewTest, MouseEvent) {
430 TestView* v1 = new TestView();
431 v1->SetBoundsRect(gfx::Rect(0, 0, 300, 300));
432
433 TestView* v2 = new TestView();
434 v2->SetBoundsRect(gfx::Rect(100, 100, 100, 100));
435
436 std::unique_ptr<Widget> widget(new Widget);
437 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
438 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
439 params.bounds = gfx::Rect(50, 50, 650, 650);
440 widget->Init(std::move(params));
441 internal::RootView* root =
442 static_cast<internal::RootView*>(widget->GetRootView());
443
444 root->AddChildView(v1);
445 v1->AddChildView(v2);
446
447 v1->Reset();
448 v2->Reset();
449
450 gfx::Point p1(110, 120);
451 ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, p1, p1, ui::EventTimeForNow(),
452 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
453 root->OnMousePressed(pressed);
454 EXPECT_EQ(v2->last_mouse_event_type_, ui::ET_MOUSE_PRESSED);
455 EXPECT_EQ(v2->location_.x(), 10);
456 EXPECT_EQ(v2->location_.y(), 20);
457 // Make sure v1 did not receive the event
458 EXPECT_EQ(v1->last_mouse_event_type_, 0);
459
460 // Drag event out of bounds. Should still go to v2
461 v1->Reset();
462 v2->Reset();
463 gfx::Point p2(50, 40);
464 ui::MouseEvent dragged(ui::ET_MOUSE_DRAGGED, p2, p2, ui::EventTimeForNow(),
465 ui::EF_LEFT_MOUSE_BUTTON, 0);
466 root->OnMouseDragged(dragged);
467 EXPECT_EQ(v2->last_mouse_event_type_, ui::ET_MOUSE_DRAGGED);
468 EXPECT_EQ(v2->location_.x(), -50);
469 EXPECT_EQ(v2->location_.y(), -60);
470 // Make sure v1 did not receive the event
471 EXPECT_EQ(v1->last_mouse_event_type_, 0);
472
473 // Releasted event out of bounds. Should still go to v2
474 v1->Reset();
475 v2->Reset();
476 ui::MouseEvent released(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(),
477 ui::EventTimeForNow(), 0, 0);
478 root->OnMouseDragged(released);
479 EXPECT_EQ(v2->last_mouse_event_type_, ui::ET_MOUSE_RELEASED);
480 EXPECT_EQ(v2->location_.x(), -100);
481 EXPECT_EQ(v2->location_.y(), -100);
482 // Make sure v1 did not receive the event
483 EXPECT_EQ(v1->last_mouse_event_type_, 0);
484
485 widget->CloseNow();
486 }
487
488 // Confirm that a view can be deleted as part of processing a mouse press.
TEST_F(ViewTest,DeleteOnPressed)489 TEST_F(ViewTest, DeleteOnPressed) {
490 TestView* v1 = new TestView();
491 v1->SetBoundsRect(gfx::Rect(0, 0, 300, 300));
492
493 TestView* v2 = new TestView();
494 v2->SetBoundsRect(gfx::Rect(100, 100, 100, 100));
495
496 v1->Reset();
497 v2->Reset();
498
499 std::unique_ptr<Widget> widget(new Widget);
500 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
501 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
502 params.bounds = gfx::Rect(50, 50, 650, 650);
503 widget->Init(std::move(params));
504 View* root = widget->GetRootView();
505
506 root->AddChildView(v1);
507 v1->AddChildView(v2);
508
509 v2->delete_on_pressed_ = true;
510 gfx::Point point(110, 120);
511 ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, point, point,
512 ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
513 ui::EF_LEFT_MOUSE_BUTTON);
514 root->OnMousePressed(pressed);
515 EXPECT_TRUE(v1->children().empty());
516
517 widget->CloseNow();
518 }
519
520 ////////////////////////////////////////////////////////////////////////////////
521 // Painting
522 ////////////////////////////////////////////////////////////////////////////////
523
OnPaint(gfx::Canvas * canvas)524 void TestView::OnPaint(gfx::Canvas* canvas) {
525 did_paint_ = true;
526 }
527
528 namespace {
529
530 // Helper class to create a Widget with standard parameters that is closed when
531 // the helper class goes out of scope.
532 class ScopedTestPaintWidget {
533 public:
ScopedTestPaintWidget(Widget::InitParams params)534 explicit ScopedTestPaintWidget(Widget::InitParams params)
535 : widget_(new Widget) {
536 widget_->Init(std::move(params));
537 widget_->GetRootView()->SetBounds(0, 0, 25, 26);
538 }
539
~ScopedTestPaintWidget()540 ~ScopedTestPaintWidget() { widget_->CloseNow(); }
541
operator ->()542 Widget* operator->() { return widget_; }
543
544 private:
545 Widget* widget_;
546
547 DISALLOW_COPY_AND_ASSIGN(ScopedTestPaintWidget);
548 };
549
550 } // namespace
551
TEST_F(ViewTest,PaintEmptyView)552 TEST_F(ViewTest, PaintEmptyView) {
553 ScopedTestPaintWidget widget(CreateParams(Widget::InitParams::TYPE_POPUP));
554 View* root_view = widget->GetRootView();
555
556 // |v1| is empty.
557 TestView* v1 = new TestView;
558 v1->SetBounds(10, 11, 0, 1);
559 root_view->AddChildView(v1);
560
561 // |v11| is a child of an empty |v1|.
562 TestView* v11 = new TestView;
563 v11->SetBounds(3, 4, 6, 5);
564 v1->AddChildView(v11);
565
566 // |v2| is not.
567 TestView* v2 = new TestView;
568 v2->SetBounds(3, 4, 6, 5);
569 root_view->AddChildView(v2);
570
571 // Paint "everything".
572 gfx::Rect first_paint(1, 1);
573 auto list = base::MakeRefCounted<cc::DisplayItemList>();
574 root_view->Paint(PaintInfo::CreateRootPaintInfo(
575 ui::PaintContext(list.get(), 1.f, first_paint, false),
576 first_paint.size()));
577
578 // The empty view has nothing to paint so it doesn't try build a cache, nor do
579 // its children which would be clipped by its (empty) self.
580 EXPECT_FALSE(v1->did_paint_);
581 EXPECT_FALSE(v11->did_paint_);
582 EXPECT_TRUE(v2->did_paint_);
583 }
584
TEST_F(ViewTest,PaintWithMovedViewUsesCache)585 TEST_F(ViewTest, PaintWithMovedViewUsesCache) {
586 ScopedTestPaintWidget widget(CreateParams(Widget::InitParams::TYPE_POPUP));
587 View* root_view = widget->GetRootView();
588 TestView* v1 = new TestView;
589 v1->SetBounds(10, 11, 12, 13);
590 root_view->AddChildView(v1);
591
592 // Paint everything once, since it has to build its cache. Then we can test
593 // invalidation.
594 gfx::Rect pixel_rect = gfx::Rect(1, 1);
595 float device_scale_factor = 1.f;
596 auto list = base::MakeRefCounted<cc::DisplayItemList>();
597 root_view->PaintFromPaintRoot(
598 ui::PaintContext(list.get(), device_scale_factor, pixel_rect, false));
599 EXPECT_TRUE(v1->did_paint_);
600 v1->Reset();
601 // The visual rects for (clip, drawing, transform) should be in layer space.
602 gfx::Rect expected_visual_rect_in_layer_space(10, 11, 12, 13);
603 int item_index = 3;
604 EXPECT_EQ(expected_visual_rect_in_layer_space,
605 list->VisualRectForTesting(item_index++));
606 EXPECT_EQ(expected_visual_rect_in_layer_space,
607 list->VisualRectForTesting(item_index++));
608 EXPECT_EQ(expected_visual_rect_in_layer_space,
609 list->VisualRectForTesting(item_index));
610
611 // If invalidation doesn't intersect v1, we paint with the cache.
612 list = base::MakeRefCounted<cc::DisplayItemList>();
613 root_view->PaintFromPaintRoot(
614 ui::PaintContext(list.get(), device_scale_factor, pixel_rect, false));
615 EXPECT_FALSE(v1->did_paint_);
616 v1->Reset();
617
618 // If invalidation does intersect v1, we don't paint with the cache.
619 list = base::MakeRefCounted<cc::DisplayItemList>();
620 root_view->PaintFromPaintRoot(
621 ui::PaintContext(list.get(), device_scale_factor, v1->bounds(), false));
622 EXPECT_TRUE(v1->did_paint_);
623 v1->Reset();
624
625 // Moving the view should still use the cache when the invalidation doesn't
626 // intersect v1.
627 list = base::MakeRefCounted<cc::DisplayItemList>();
628 v1->SetX(9);
629 root_view->PaintFromPaintRoot(
630 ui::PaintContext(list.get(), device_scale_factor, pixel_rect, false));
631 EXPECT_FALSE(v1->did_paint_);
632 v1->Reset();
633 item_index = 3;
634 expected_visual_rect_in_layer_space.SetRect(9, 11, 12, 13);
635 EXPECT_EQ(expected_visual_rect_in_layer_space,
636 list->VisualRectForTesting(item_index++));
637 EXPECT_EQ(expected_visual_rect_in_layer_space,
638 list->VisualRectForTesting(item_index++));
639 EXPECT_EQ(expected_visual_rect_in_layer_space,
640 list->VisualRectForTesting(item_index));
641
642 // Moving the view should not use the cache when painting without
643 // invalidation.
644 list = base::MakeRefCounted<cc::DisplayItemList>();
645 v1->SetX(8);
646 root_view->PaintFromPaintRoot(ui::PaintContext(
647 ui::PaintContext(list.get(), device_scale_factor, pixel_rect, false),
648 ui::PaintContext::CLONE_WITHOUT_INVALIDATION));
649 EXPECT_TRUE(v1->did_paint_);
650 v1->Reset();
651 item_index = 3;
652 expected_visual_rect_in_layer_space.SetRect(8, 11, 12, 13);
653 EXPECT_EQ(expected_visual_rect_in_layer_space,
654 list->VisualRectForTesting(item_index++));
655 EXPECT_EQ(expected_visual_rect_in_layer_space,
656 list->VisualRectForTesting(item_index++));
657 EXPECT_EQ(expected_visual_rect_in_layer_space,
658 list->VisualRectForTesting(item_index));
659 }
660
TEST_F(ViewTest,PaintWithMovedViewUsesCacheInRTL)661 TEST_F(ViewTest, PaintWithMovedViewUsesCacheInRTL) {
662 base::test::ScopedRestoreICUDefaultLocale scoped_locale_("he");
663 ScopedTestPaintWidget widget(CreateParams(Widget::InitParams::TYPE_POPUP));
664 View* root_view = widget->GetRootView();
665 TestView* v1 = new TestView;
666 v1->SetBounds(10, 11, 12, 13);
667 root_view->AddChildView(v1);
668
669 // Paint everything once, since it has to build its cache. Then we can test
670 // invalidation.
671 gfx::Rect pixel_rect = gfx::Rect(1, 1);
672 float device_scale_factor = 1.f;
673 auto list = base::MakeRefCounted<cc::DisplayItemList>();
674 root_view->PaintFromPaintRoot(
675 ui::PaintContext(list.get(), device_scale_factor, pixel_rect, false));
676 EXPECT_TRUE(v1->did_paint_);
677 v1->Reset();
678 // The visual rects for (clip, drawing, transform) should be in layer space.
679 // x: 25 - 10(x) - 12(width) = 3
680 gfx::Rect expected_visual_rect_in_layer_space(3, 11, 12, 13);
681 int item_index = 3;
682 EXPECT_EQ(expected_visual_rect_in_layer_space,
683 list->VisualRectForTesting(item_index++));
684 EXPECT_EQ(expected_visual_rect_in_layer_space,
685 list->VisualRectForTesting(item_index++));
686 EXPECT_EQ(expected_visual_rect_in_layer_space,
687 list->VisualRectForTesting(item_index));
688
689 // If invalidation doesn't intersect v1, we paint with the cache.
690 list = base::MakeRefCounted<cc::DisplayItemList>();
691 root_view->PaintFromPaintRoot(
692 ui::PaintContext(list.get(), device_scale_factor, pixel_rect, false));
693 EXPECT_FALSE(v1->did_paint_);
694 v1->Reset();
695
696 // If invalidation does intersect v1, we don't paint with the cache.
697 list = base::MakeRefCounted<cc::DisplayItemList>();
698 root_view->PaintFromPaintRoot(
699 ui::PaintContext(list.get(), device_scale_factor, v1->bounds(), false));
700 EXPECT_TRUE(v1->did_paint_);
701 v1->Reset();
702
703 // Moving the view should still use the cache when the invalidation doesn't
704 // intersect v1.
705 list = base::MakeRefCounted<cc::DisplayItemList>();
706 v1->SetX(9);
707 root_view->PaintFromPaintRoot(
708 ui::PaintContext(list.get(), device_scale_factor, pixel_rect, false));
709 EXPECT_FALSE(v1->did_paint_);
710 v1->Reset();
711 item_index = 3;
712 // x: 25 - 9(x) - 12(width) = 4
713 expected_visual_rect_in_layer_space.SetRect(4, 11, 12, 13);
714 EXPECT_EQ(expected_visual_rect_in_layer_space,
715 list->VisualRectForTesting(item_index++));
716 EXPECT_EQ(expected_visual_rect_in_layer_space,
717 list->VisualRectForTesting(item_index++));
718 EXPECT_EQ(expected_visual_rect_in_layer_space,
719 list->VisualRectForTesting(item_index));
720
721 // Moving the view should not use the cache when painting without
722 // invalidation.
723 list = base::MakeRefCounted<cc::DisplayItemList>();
724 v1->SetX(8);
725 root_view->PaintFromPaintRoot(ui::PaintContext(
726 ui::PaintContext(list.get(), device_scale_factor, pixel_rect, false),
727 ui::PaintContext::CLONE_WITHOUT_INVALIDATION));
728 EXPECT_TRUE(v1->did_paint_);
729 v1->Reset();
730 item_index = 3;
731 // x: 25 - 8(x) - 12(width) = 5
732 expected_visual_rect_in_layer_space.SetRect(5, 11, 12, 13);
733 EXPECT_EQ(expected_visual_rect_in_layer_space,
734 list->VisualRectForTesting(item_index++));
735 EXPECT_EQ(expected_visual_rect_in_layer_space,
736 list->VisualRectForTesting(item_index++));
737 EXPECT_EQ(expected_visual_rect_in_layer_space,
738 list->VisualRectForTesting(item_index));
739 }
740
TEST_F(ViewTest,PaintWithUnknownInvalidation)741 TEST_F(ViewTest, PaintWithUnknownInvalidation) {
742 ScopedTestPaintWidget widget(CreateParams(Widget::InitParams::TYPE_POPUP));
743 View* root_view = widget->GetRootView();
744
745 TestView* v1 = new TestView;
746 v1->SetBounds(10, 11, 12, 13);
747 root_view->AddChildView(v1);
748
749 TestView* v2 = new TestView;
750 v2->SetBounds(3, 4, 6, 5);
751 v1->AddChildView(v2);
752
753 // Paint everything once, since it has to build its cache. Then we can test
754 // invalidation.
755 gfx::Rect first_paint(1, 1);
756 auto list = base::MakeRefCounted<cc::DisplayItemList>();
757 root_view->PaintFromPaintRoot(
758 ui::PaintContext(list.get(), 1.f, first_paint, false));
759 v1->Reset();
760 v2->Reset();
761
762 gfx::Rect paint_area(1, 1);
763 gfx::Rect root_area(root_view->size());
764 list = base::MakeRefCounted<cc::DisplayItemList>();
765
766 // With a known invalidation, v1 and v2 are not painted.
767 EXPECT_FALSE(v1->did_paint_);
768 EXPECT_FALSE(v2->did_paint_);
769 root_view->PaintFromPaintRoot(
770 ui::PaintContext(list.get(), 1.f, paint_area, false));
771 EXPECT_FALSE(v1->did_paint_);
772 EXPECT_FALSE(v2->did_paint_);
773
774 // With unknown invalidation, v1 and v2 are painted.
775 root_view->PaintFromPaintRoot(
776 ui::PaintContext(ui::PaintContext(list.get(), 1.f, paint_area, false),
777 ui::PaintContext::CLONE_WITHOUT_INVALIDATION));
778 EXPECT_TRUE(v1->did_paint_);
779 EXPECT_TRUE(v2->did_paint_);
780 }
781
TEST_F(ViewTest,PaintContainsChildren)782 TEST_F(ViewTest, PaintContainsChildren) {
783 ScopedTestPaintWidget widget(CreateParams(Widget::InitParams::TYPE_POPUP));
784 View* root_view = widget->GetRootView();
785
786 TestView* v1 = new TestView;
787 v1->SetBounds(10, 11, 12, 13);
788 root_view->AddChildView(v1);
789
790 TestView* v2 = new TestView;
791 v2->SetBounds(3, 4, 6, 5);
792 v1->AddChildView(v2);
793
794 // Paint everything once, since it has to build its cache. Then we can test
795 // invalidation.
796 gfx::Rect first_paint(1, 1);
797 auto list = base::MakeRefCounted<cc::DisplayItemList>();
798 root_view->Paint(PaintInfo::CreateRootPaintInfo(
799 ui::PaintContext(list.get(), 1.f, first_paint, false),
800 root_view->size()));
801 v1->Reset();
802 v2->Reset();
803
804 gfx::Rect paint_area(25, 26);
805 gfx::Rect root_area(root_view->size());
806 list = base::MakeRefCounted<cc::DisplayItemList>();
807
808 EXPECT_FALSE(v1->did_paint_);
809 EXPECT_FALSE(v2->did_paint_);
810 root_view->Paint(PaintInfo::CreateRootPaintInfo(
811 ui::PaintContext(list.get(), 1.f, paint_area, false), root_view->size()));
812 EXPECT_TRUE(v1->did_paint_);
813 EXPECT_TRUE(v2->did_paint_);
814 }
815
TEST_F(ViewTest,PaintContainsChildrenInRTL)816 TEST_F(ViewTest, PaintContainsChildrenInRTL) {
817 base::test::ScopedRestoreICUDefaultLocale scoped_locale_("he");
818 ScopedTestPaintWidget widget(CreateParams(Widget::InitParams::TYPE_POPUP));
819 View* root_view = widget->GetRootView();
820
821 TestView* v1 = new TestView;
822 v1->SetBounds(10, 11, 12, 13);
823 root_view->AddChildView(v1);
824
825 TestView* v2 = new TestView;
826 v2->SetBounds(3, 4, 6, 5);
827 v1->AddChildView(v2);
828
829 // Verify where the layers actually appear.
830 v1->SetPaintToLayer();
831 // x: 25 - 10(x) - 12(width) = 3
832 EXPECT_EQ(gfx::Rect(3, 11, 12, 13), v1->layer()->bounds());
833 v1->DestroyLayer();
834
835 v2->SetPaintToLayer();
836 // x: 25 - 10(parent x) - 3(x) - 6(width) = 6
837 EXPECT_EQ(gfx::Rect(6, 15, 6, 5), v2->layer()->bounds());
838 v2->DestroyLayer();
839
840 // Paint everything once, since it has to build its cache. Then we can test
841 // invalidation.
842 gfx::Rect first_paint(1, 1);
843 auto list = base::MakeRefCounted<cc::DisplayItemList>();
844 root_view->Paint(PaintInfo::CreateRootPaintInfo(
845 ui::PaintContext(list.get(), 1.f, first_paint, false),
846 root_view->size()));
847 v1->Reset();
848 v2->Reset();
849
850 gfx::Rect paint_area(25, 26);
851 gfx::Rect root_area(root_view->size());
852 list = base::MakeRefCounted<cc::DisplayItemList>();
853
854 EXPECT_FALSE(v1->did_paint_);
855 EXPECT_FALSE(v2->did_paint_);
856 root_view->Paint(PaintInfo::CreateRootPaintInfo(
857 ui::PaintContext(list.get(), 1.f, paint_area, false), root_view->size()));
858 EXPECT_TRUE(v1->did_paint_);
859 EXPECT_TRUE(v2->did_paint_);
860 }
861
TEST_F(ViewTest,PaintIntersectsChildren)862 TEST_F(ViewTest, PaintIntersectsChildren) {
863 ScopedTestPaintWidget widget(CreateParams(Widget::InitParams::TYPE_POPUP));
864 View* root_view = widget->GetRootView();
865
866 TestView* v1 = new TestView;
867 v1->SetBounds(10, 11, 12, 13);
868 root_view->AddChildView(v1);
869
870 TestView* v2 = new TestView;
871 v2->SetBounds(3, 4, 6, 5);
872 v1->AddChildView(v2);
873
874 // Paint everything once, since it has to build its cache. Then we can test
875 // invalidation.
876 gfx::Rect first_paint(1, 1);
877 auto list = base::MakeRefCounted<cc::DisplayItemList>();
878 root_view->Paint(PaintInfo::CreateRootPaintInfo(
879 ui::PaintContext(list.get(), 1.f, first_paint, false),
880 root_view->size()));
881 v1->Reset();
882 v2->Reset();
883
884 gfx::Rect paint_area(9, 10, 5, 6);
885 gfx::Rect root_area(root_view->size());
886 list = base::MakeRefCounted<cc::DisplayItemList>();
887
888 EXPECT_FALSE(v1->did_paint_);
889 EXPECT_FALSE(v2->did_paint_);
890 root_view->Paint(PaintInfo::CreateRootPaintInfo(
891 ui::PaintContext(list.get(), 1.f, paint_area, false), root_view->size()));
892 EXPECT_TRUE(v1->did_paint_);
893 EXPECT_TRUE(v2->did_paint_);
894 }
895
TEST_F(ViewTest,PaintIntersectsChildrenInRTL)896 TEST_F(ViewTest, PaintIntersectsChildrenInRTL) {
897 base::test::ScopedRestoreICUDefaultLocale scoped_locale_("he");
898 ScopedTestPaintWidget widget(CreateParams(Widget::InitParams::TYPE_POPUP));
899 View* root_view = widget->GetRootView();
900
901 TestView* v1 = new TestView;
902 v1->SetBounds(10, 11, 12, 13);
903 root_view->AddChildView(v1);
904
905 TestView* v2 = new TestView;
906 v2->SetBounds(3, 4, 6, 5);
907 v1->AddChildView(v2);
908
909 // Verify where the layers actually appear.
910 v1->SetPaintToLayer();
911 // x: 25 - 10(x) - 12(width) = 3
912 EXPECT_EQ(gfx::Rect(3, 11, 12, 13), v1->layer()->bounds());
913 v1->DestroyLayer();
914
915 v2->SetPaintToLayer();
916 // x: 25 - 10(parent x) - 3(x) - 6(width) = 6
917 EXPECT_EQ(gfx::Rect(6, 15, 6, 5), v2->layer()->bounds());
918 v2->DestroyLayer();
919
920 // Paint everything once, since it has to build its cache. Then we can test
921 // invalidation.
922 gfx::Rect first_paint(1, 1);
923 auto list = base::MakeRefCounted<cc::DisplayItemList>();
924 root_view->Paint(PaintInfo::CreateRootPaintInfo(
925 ui::PaintContext(list.get(), 1.f, first_paint, false),
926 root_view->size()));
927 v1->Reset();
928 v2->Reset();
929
930 gfx::Rect paint_area(2, 10, 5, 6);
931 gfx::Rect root_area(root_view->size());
932 list = base::MakeRefCounted<cc::DisplayItemList>();
933
934 EXPECT_FALSE(v1->did_paint_);
935 EXPECT_FALSE(v2->did_paint_);
936 root_view->Paint(PaintInfo::CreateRootPaintInfo(
937 ui::PaintContext(list.get(), 1.f, paint_area, false), root_view->size()));
938 EXPECT_TRUE(v1->did_paint_);
939 EXPECT_TRUE(v2->did_paint_);
940 }
941
TEST_F(ViewTest,PaintIntersectsChildButNotGrandChild)942 TEST_F(ViewTest, PaintIntersectsChildButNotGrandChild) {
943 ScopedTestPaintWidget widget(CreateParams(Widget::InitParams::TYPE_POPUP));
944 View* root_view = widget->GetRootView();
945
946 TestView* v1 = new TestView;
947 v1->SetBounds(10, 11, 12, 13);
948 root_view->AddChildView(v1);
949
950 TestView* v2 = new TestView;
951 v2->SetBounds(3, 4, 6, 5);
952 v1->AddChildView(v2);
953
954 // Paint everything once, since it has to build its cache. Then we can test
955 // invalidation.
956 gfx::Rect first_paint(1, 1);
957 auto list = base::MakeRefCounted<cc::DisplayItemList>();
958 root_view->Paint(PaintInfo::CreateRootPaintInfo(
959 ui::PaintContext(list.get(), 1.f, first_paint, false),
960 root_view->size()));
961 v1->Reset();
962 v2->Reset();
963
964 gfx::Rect paint_area(9, 10, 2, 3);
965 gfx::Rect root_area(root_view->size());
966 list = base::MakeRefCounted<cc::DisplayItemList>();
967
968 EXPECT_FALSE(v1->did_paint_);
969 EXPECT_FALSE(v2->did_paint_);
970 root_view->Paint(PaintInfo::CreateRootPaintInfo(
971 ui::PaintContext(list.get(), 1.f, paint_area, false), root_view->size()));
972 EXPECT_TRUE(v1->did_paint_);
973 EXPECT_FALSE(v2->did_paint_);
974 }
975
TEST_F(ViewTest,PaintIntersectsChildButNotGrandChildInRTL)976 TEST_F(ViewTest, PaintIntersectsChildButNotGrandChildInRTL) {
977 base::test::ScopedRestoreICUDefaultLocale scoped_locale_("he");
978 ScopedTestPaintWidget widget(CreateParams(Widget::InitParams::TYPE_POPUP));
979 View* root_view = widget->GetRootView();
980
981 TestView* v1 = new TestView;
982 v1->SetBounds(10, 11, 12, 13);
983 root_view->AddChildView(v1);
984
985 TestView* v2 = new TestView;
986 v2->SetBounds(3, 4, 6, 5);
987 v1->AddChildView(v2);
988
989 // Verify where the layers actually appear.
990 v1->SetPaintToLayer();
991 // x: 25 - 10(x) - 12(width) = 3
992 EXPECT_EQ(gfx::Rect(3, 11, 12, 13), v1->layer()->bounds());
993 v1->DestroyLayer();
994
995 v2->SetPaintToLayer();
996 // x: 25 - 10(parent x) - 3(x) - 6(width) = 6
997 EXPECT_EQ(gfx::Rect(6, 15, 6, 5), v2->layer()->bounds());
998 v2->DestroyLayer();
999
1000 // Paint everything once, since it has to build its cache. Then we can test
1001 // invalidation.
1002 gfx::Rect first_paint(1, 1);
1003 auto list = base::MakeRefCounted<cc::DisplayItemList>();
1004 root_view->Paint(PaintInfo::CreateRootPaintInfo(
1005 ui::PaintContext(list.get(), 1.f, first_paint, false),
1006 root_view->size()));
1007 v1->Reset();
1008 v2->Reset();
1009
1010 gfx::Rect paint_area(2, 10, 2, 3);
1011 gfx::Rect root_area(root_view->size());
1012 list = base::MakeRefCounted<cc::DisplayItemList>();
1013
1014 EXPECT_FALSE(v1->did_paint_);
1015 EXPECT_FALSE(v2->did_paint_);
1016 root_view->Paint(PaintInfo::CreateRootPaintInfo(
1017 ui::PaintContext(list.get(), 1.f, paint_area, false), root_view->size()));
1018 EXPECT_TRUE(v1->did_paint_);
1019 EXPECT_FALSE(v2->did_paint_);
1020 }
1021
TEST_F(ViewTest,PaintIntersectsNoChildren)1022 TEST_F(ViewTest, PaintIntersectsNoChildren) {
1023 ScopedTestPaintWidget widget(CreateParams(Widget::InitParams::TYPE_POPUP));
1024 View* root_view = widget->GetRootView();
1025
1026 TestView* v1 = new TestView;
1027 v1->SetBounds(10, 11, 12, 13);
1028 root_view->AddChildView(v1);
1029
1030 TestView* v2 = new TestView;
1031 v2->SetBounds(3, 4, 6, 5);
1032 v1->AddChildView(v2);
1033
1034 // Paint everything once, since it has to build its cache. Then we can test
1035 // invalidation.
1036 gfx::Rect first_paint(1, 1);
1037 auto list = base::MakeRefCounted<cc::DisplayItemList>();
1038 root_view->Paint(PaintInfo::CreateRootPaintInfo(
1039 ui::PaintContext(list.get(), 1.f, first_paint, false),
1040 root_view->size()));
1041 v1->Reset();
1042 v2->Reset();
1043
1044 gfx::Rect paint_area(9, 10, 2, 1);
1045 gfx::Rect root_area(root_view->size());
1046 list = base::MakeRefCounted<cc::DisplayItemList>();
1047
1048 EXPECT_FALSE(v1->did_paint_);
1049 EXPECT_FALSE(v2->did_paint_);
1050 root_view->Paint(PaintInfo::CreateRootPaintInfo(
1051 ui::PaintContext(list.get(), 1.f, paint_area, false), root_view->size()));
1052 EXPECT_FALSE(v1->did_paint_);
1053 EXPECT_FALSE(v2->did_paint_);
1054 }
1055
TEST_F(ViewTest,PaintIntersectsNoChildrenInRTL)1056 TEST_F(ViewTest, PaintIntersectsNoChildrenInRTL) {
1057 base::test::ScopedRestoreICUDefaultLocale scoped_locale_("he");
1058 ScopedTestPaintWidget widget(CreateParams(Widget::InitParams::TYPE_POPUP));
1059 View* root_view = widget->GetRootView();
1060
1061 TestView* v1 = new TestView;
1062 v1->SetBounds(10, 11, 12, 13);
1063 root_view->AddChildView(v1);
1064
1065 TestView* v2 = new TestView;
1066 v2->SetBounds(3, 4, 6, 5);
1067 v1->AddChildView(v2);
1068
1069 // Verify where the layers actually appear.
1070 v1->SetPaintToLayer();
1071 // x: 25 - 10(x) - 12(width) = 3
1072 EXPECT_EQ(gfx::Rect(3, 11, 12, 13), v1->layer()->bounds());
1073 v1->DestroyLayer();
1074
1075 v2->SetPaintToLayer();
1076 // x: 25 - 10(parent x) - 3(x) - 6(width) = 6
1077 EXPECT_EQ(gfx::Rect(6, 15, 6, 5), v2->layer()->bounds());
1078 v2->DestroyLayer();
1079
1080 // Paint everything once, since it has to build its cache. Then we can test
1081 // invalidation.
1082 gfx::Rect first_paint(1, 1);
1083 auto list = base::MakeRefCounted<cc::DisplayItemList>();
1084 root_view->Paint(PaintInfo::CreateRootPaintInfo(
1085 ui::PaintContext(list.get(), 1.f, first_paint, false),
1086 root_view->size()));
1087 v1->Reset();
1088 v2->Reset();
1089
1090 gfx::Rect paint_area(2, 10, 2, 1);
1091 gfx::Rect root_area(root_view->size());
1092 list = base::MakeRefCounted<cc::DisplayItemList>();
1093
1094 EXPECT_FALSE(v1->did_paint_);
1095 EXPECT_FALSE(v2->did_paint_);
1096 root_view->Paint(PaintInfo::CreateRootPaintInfo(
1097 ui::PaintContext(list.get(), 1.f, paint_area, false), root_view->size()));
1098 EXPECT_FALSE(v1->did_paint_);
1099 EXPECT_FALSE(v2->did_paint_);
1100 }
1101
TEST_F(ViewTest,PaintIntersectsOneChild)1102 TEST_F(ViewTest, PaintIntersectsOneChild) {
1103 ScopedTestPaintWidget widget(CreateParams(Widget::InitParams::TYPE_POPUP));
1104 View* root_view = widget->GetRootView();
1105
1106 TestView* v1 = new TestView;
1107 v1->SetBounds(10, 11, 12, 13);
1108 root_view->AddChildView(v1);
1109
1110 TestView* v2 = new TestView;
1111 v2->SetBounds(3, 4, 6, 5);
1112 root_view->AddChildView(v2);
1113
1114 // Paint everything once, since it has to build its cache. Then we can test
1115 // invalidation.
1116 gfx::Rect first_paint(1, 1);
1117 auto list = base::MakeRefCounted<cc::DisplayItemList>();
1118 root_view->Paint(PaintInfo::CreateRootPaintInfo(
1119 ui::PaintContext(list.get(), 1.f, first_paint, false),
1120 root_view->size()));
1121 v1->Reset();
1122 v2->Reset();
1123
1124 // Intersects with the second child only.
1125 gfx::Rect paint_area(3, 3, 1, 2);
1126 gfx::Rect root_area(root_view->size());
1127 list = base::MakeRefCounted<cc::DisplayItemList>();
1128
1129 EXPECT_FALSE(v1->did_paint_);
1130 EXPECT_FALSE(v2->did_paint_);
1131 root_view->Paint(PaintInfo::CreateRootPaintInfo(
1132 ui::PaintContext(list.get(), 1.f, paint_area, false), root_view->size()));
1133 EXPECT_FALSE(v1->did_paint_);
1134 EXPECT_TRUE(v2->did_paint_);
1135
1136 // Intersects with the first child only.
1137 paint_area = gfx::Rect(20, 10, 1, 2);
1138
1139 v1->Reset();
1140 v2->Reset();
1141 EXPECT_FALSE(v1->did_paint_);
1142 EXPECT_FALSE(v2->did_paint_);
1143 root_view->Paint(PaintInfo::CreateRootPaintInfo(
1144 ui::PaintContext(list.get(), 1.f, paint_area, false), root_view->size()));
1145 EXPECT_TRUE(v1->did_paint_);
1146 EXPECT_FALSE(v2->did_paint_);
1147 }
1148
TEST_F(ViewTest,PaintIntersectsOneChildInRTL)1149 TEST_F(ViewTest, PaintIntersectsOneChildInRTL) {
1150 base::test::ScopedRestoreICUDefaultLocale scoped_locale_("he");
1151 ScopedTestPaintWidget widget(CreateParams(Widget::InitParams::TYPE_POPUP));
1152 View* root_view = widget->GetRootView();
1153
1154 TestView* v1 = new TestView;
1155 v1->SetBounds(10, 11, 12, 13);
1156 root_view->AddChildView(v1);
1157
1158 TestView* v2 = new TestView;
1159 v2->SetBounds(3, 4, 6, 5);
1160 root_view->AddChildView(v2);
1161
1162 // Verify where the layers actually appear.
1163 v1->SetPaintToLayer();
1164 // x: 25 - 10(x) - 12(width) = 3
1165 EXPECT_EQ(gfx::Rect(3, 11, 12, 13), v1->layer()->bounds());
1166 v1->DestroyLayer();
1167
1168 v2->SetPaintToLayer();
1169 // x: 25 - 3(x) - 6(width) = 16
1170 EXPECT_EQ(gfx::Rect(16, 4, 6, 5), v2->layer()->bounds());
1171 v2->DestroyLayer();
1172
1173 // Paint everything once, since it has to build its cache. Then we can test
1174 // invalidation.
1175 gfx::Rect first_paint(1, 1);
1176 auto list = base::MakeRefCounted<cc::DisplayItemList>();
1177 root_view->Paint(PaintInfo::CreateRootPaintInfo(
1178 ui::PaintContext(list.get(), 1.f, first_paint, false),
1179 root_view->size()));
1180 v1->Reset();
1181 v2->Reset();
1182
1183 // Intersects with the first child only.
1184 gfx::Rect paint_area(3, 10, 1, 2);
1185 gfx::Rect root_area(root_view->size());
1186 list = base::MakeRefCounted<cc::DisplayItemList>();
1187
1188 EXPECT_FALSE(v1->did_paint_);
1189 EXPECT_FALSE(v2->did_paint_);
1190 root_view->Paint(PaintInfo::CreateRootPaintInfo(
1191 ui::PaintContext(list.get(), 1.f, paint_area, false), root_view->size()));
1192 EXPECT_TRUE(v1->did_paint_);
1193 EXPECT_FALSE(v2->did_paint_);
1194
1195 // Intersects with the second child only.
1196 paint_area = gfx::Rect(21, 3, 1, 2);
1197
1198 v1->Reset();
1199 v2->Reset();
1200 EXPECT_FALSE(v1->did_paint_);
1201 EXPECT_FALSE(v2->did_paint_);
1202 root_view->Paint(PaintInfo::CreateRootPaintInfo(
1203 ui::PaintContext(list.get(), 1.f, paint_area, false), root_view->size()));
1204 EXPECT_FALSE(v1->did_paint_);
1205 EXPECT_TRUE(v2->did_paint_);
1206 }
1207
TEST_F(ViewTest,PaintInPromotedToLayer)1208 TEST_F(ViewTest, PaintInPromotedToLayer) {
1209 ScopedTestPaintWidget widget(CreateParams(Widget::InitParams::TYPE_POPUP));
1210 View* root_view = widget->GetRootView();
1211
1212 TestView* v1 = new TestView;
1213 v1->SetPaintToLayer();
1214 v1->SetBounds(10, 11, 12, 13);
1215 root_view->AddChildView(v1);
1216
1217 TestView* v2 = new TestView;
1218 v2->SetBounds(3, 4, 6, 5);
1219 v1->AddChildView(v2);
1220
1221 // Paint everything once, since it has to build its cache. Then we can test
1222 // invalidation.
1223 gfx::Rect first_paint(1, 1);
1224 auto list = base::MakeRefCounted<cc::DisplayItemList>();
1225 v1->Paint(PaintInfo::CreateRootPaintInfo(
1226 ui::PaintContext(list.get(), 1.f, first_paint, false), v1->size()));
1227 v1->Reset();
1228 v2->Reset();
1229
1230 {
1231 gfx::Rect paint_area(25, 26);
1232 gfx::Rect view_area(root_view->size());
1233 auto list = base::MakeRefCounted<cc::DisplayItemList>();
1234
1235 // The promoted views are not painted as they are separate paint roots.
1236 root_view->Paint(PaintInfo::CreateRootPaintInfo(
1237 ui::PaintContext(list.get(), 1.f, paint_area, false),
1238 root_view->size()));
1239 EXPECT_FALSE(v1->did_paint_);
1240 EXPECT_FALSE(v2->did_paint_);
1241 }
1242
1243 {
1244 gfx::Rect paint_area(1, 1);
1245 gfx::Rect view_area(v1->size());
1246 auto list = base::MakeRefCounted<cc::DisplayItemList>();
1247
1248 // The |v1| view is painted. If it used its offset incorrect, it would think
1249 // its at (10,11) instead of at (0,0) since it is the paint root.
1250 v1->Paint(PaintInfo::CreateRootPaintInfo(
1251 ui::PaintContext(list.get(), 1.f, paint_area, false), v1->size()));
1252 EXPECT_TRUE(v1->did_paint_);
1253 EXPECT_FALSE(v2->did_paint_);
1254 }
1255
1256 v1->Reset();
1257
1258 {
1259 gfx::Rect paint_area(3, 3, 1, 2);
1260 gfx::Rect view_area(v1->size());
1261 auto list = base::MakeRefCounted<cc::DisplayItemList>();
1262
1263 // The |v2| view is painted also. If it used its offset incorrect, it would
1264 // think its at (13,15) instead of at (3,4) since |v1| is the paint root.
1265 v1->Paint(PaintInfo::CreateRootPaintInfo(
1266 ui::PaintContext(list.get(), 1.f, paint_area, false), v1->size()));
1267 EXPECT_TRUE(v1->did_paint_);
1268 EXPECT_TRUE(v2->did_paint_);
1269 }
1270 }
1271
1272 // A derived class for testing paint.
1273 class TestPaintView : public TestView {
1274 public:
TestPaintView()1275 TestPaintView() : canvas_bounds_(gfx::Rect()) {}
1276 ~TestPaintView() override = default;
1277
OnPaint(gfx::Canvas * canvas)1278 void OnPaint(gfx::Canvas* canvas) override {
1279 did_paint_ = true;
1280 // Get the bounds from the canvas this view paints to.
1281 EXPECT_TRUE(canvas->GetClipBounds(&canvas_bounds_));
1282 }
1283
canvas_bounds() const1284 gfx::Rect canvas_bounds() const { return canvas_bounds_; }
1285
1286 private:
1287 gfx::Rect canvas_bounds_;
1288 };
1289
TEST_F(ViewTest,PaintLocalBounds)1290 TEST_F(ViewTest, PaintLocalBounds) {
1291 ScopedTestPaintWidget widget(CreateParams(Widget::InitParams::TYPE_POPUP));
1292 View* root_view = widget->GetRootView();
1293 // Make |root_view|'s bounds larger so |v1|'s visible bounds is not clipped by
1294 // |root_view|.
1295 root_view->SetBounds(0, 0, 200, 200);
1296
1297 TestPaintView* v1 = new TestPaintView;
1298 v1->SetPaintToLayer();
1299
1300 // Set bounds for |v1| such that it has an offset to its parent and only part
1301 // of it is visible. The visible bounds does not intersect with |root_view|'s
1302 // bounds.
1303 v1->SetBounds(0, -1000, 100, 1100);
1304 root_view->AddChildView(v1);
1305 EXPECT_EQ(gfx::Rect(0, 0, 100, 1100), v1->GetLocalBounds());
1306 EXPECT_EQ(gfx::Rect(0, 1000, 100, 100), v1->GetVisibleBounds());
1307
1308 auto list = base::MakeRefCounted<cc::DisplayItemList>();
1309 ui::PaintContext context(list.get(), 1.f, gfx::Rect(), false);
1310
1311 v1->Paint(PaintInfo::CreateRootPaintInfo(context, gfx::Size()));
1312 EXPECT_TRUE(v1->did_paint_);
1313
1314 // Check that the canvas produced by |v1| for paint contains all of |v1|'s
1315 // visible bounds.
1316 EXPECT_TRUE(v1->canvas_bounds().Contains(v1->GetVisibleBounds()));
1317 }
1318
OnDidSchedulePaint(const gfx::Rect & rect)1319 void TestView::OnDidSchedulePaint(const gfx::Rect& rect) {
1320 scheduled_paint_rects_.push_back(rect);
1321 View::OnDidSchedulePaint(rect);
1322 }
1323
1324 namespace {
1325
RotateCounterclockwise(gfx::Transform * transform)1326 void RotateCounterclockwise(gfx::Transform* transform) {
1327 // clang-format off
1328 transform->matrix().set3x3(0, -1, 0,
1329 1, 0, 0,
1330 0, 0, 1);
1331 // clang-format on
1332 }
1333
RotateClockwise(gfx::Transform * transform)1334 void RotateClockwise(gfx::Transform* transform) {
1335 // clang-format off
1336 transform->matrix().set3x3( 0, 1, 0, // NOLINT
1337 -1, 0, 0,
1338 0, 0, 1);
1339 // clang-format on
1340 }
1341
1342 } // namespace
1343
1344 // Tests the correctness of the rect-based targeting algorithm implemented in
1345 // View::GetEventHandlerForRect(). See http://goo.gl/3Jp2BD for a description
1346 // of rect-based targeting.
TEST_F(ViewTest,GetEventHandlerForRect)1347 TEST_F(ViewTest, GetEventHandlerForRect) {
1348 Widget* widget = new Widget;
1349 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
1350 widget->Init(std::move(params));
1351 View* root_view = widget->GetRootView();
1352 root_view->SetBoundsRect(gfx::Rect(0, 0, 500, 500));
1353
1354 // Have this hierarchy of views (the coordinates here are all in
1355 // the root view's coordinate space):
1356 // v1 (0, 0, 100, 100)
1357 // v2 (150, 0, 250, 100)
1358 // v3 (0, 200, 150, 100)
1359 // v31 (10, 210, 80, 80)
1360 // v32 (110, 210, 30, 80)
1361 // v4 (300, 200, 100, 100)
1362 // v41 (310, 210, 80, 80)
1363 // v411 (370, 275, 10, 5)
1364 // v5 (450, 197, 30, 36)
1365 // v51 (450, 200, 30, 30)
1366
1367 // The coordinates used for SetBounds are in parent coordinates.
1368
1369 TestView* v1 = new TestView;
1370 v1->SetBounds(0, 0, 100, 100);
1371 root_view->AddChildView(v1);
1372
1373 TestView* v2 = new TestView;
1374 v2->SetBounds(150, 0, 250, 100);
1375 root_view->AddChildView(v2);
1376
1377 TestView* v3 = new TestView;
1378 v3->SetBounds(0, 200, 150, 100);
1379 root_view->AddChildView(v3);
1380
1381 TestView* v4 = new TestView;
1382 v4->SetBounds(300, 200, 100, 100);
1383 root_view->AddChildView(v4);
1384
1385 TestView* v31 = new TestView;
1386 v31->SetBounds(10, 10, 80, 80);
1387 v3->AddChildView(v31);
1388
1389 TestView* v32 = new TestView;
1390 v32->SetBounds(110, 10, 30, 80);
1391 v3->AddChildView(v32);
1392
1393 TestView* v41 = new TestView;
1394 v41->SetBounds(10, 10, 80, 80);
1395 v4->AddChildView(v41);
1396
1397 TestView* v411 = new TestView;
1398 v411->SetBounds(60, 65, 10, 5);
1399 v41->AddChildView(v411);
1400
1401 TestView* v5 = new TestView;
1402 v5->SetBounds(450, 197, 30, 36);
1403 root_view->AddChildView(v5);
1404
1405 TestView* v51 = new TestView;
1406 v51->SetBounds(0, 3, 30, 30);
1407 v5->AddChildView(v51);
1408
1409 // |touch_rect| does not intersect any descendant view of |root_view|.
1410 gfx::Rect touch_rect(105, 105, 30, 45);
1411 View* result_view = root_view->GetEventHandlerForRect(touch_rect);
1412 EXPECT_EQ(root_view, result_view);
1413 result_view = nullptr;
1414
1415 // Covers |v1| by at least 60%.
1416 touch_rect.SetRect(15, 15, 100, 100);
1417 result_view = root_view->GetEventHandlerForRect(touch_rect);
1418 EXPECT_EQ(v1, result_view);
1419 result_view = nullptr;
1420
1421 // Intersects |v1| but does not cover it by at least 60%. The center
1422 // of |touch_rect| is within |v1|.
1423 touch_rect.SetRect(50, 50, 5, 10);
1424 result_view = root_view->GetEventHandlerForRect(touch_rect);
1425 EXPECT_EQ(v1, result_view);
1426 result_view = nullptr;
1427
1428 // Intersects |v1| but does not cover it by at least 60%. The center
1429 // of |touch_rect| is not within |v1|.
1430 touch_rect.SetRect(95, 96, 21, 22);
1431 result_view = root_view->GetEventHandlerForRect(touch_rect);
1432 EXPECT_EQ(root_view, result_view);
1433 result_view = nullptr;
1434
1435 // Intersects |v1| and |v2|, but only covers |v2| by at least 60%.
1436 touch_rect.SetRect(95, 10, 300, 120);
1437 result_view = root_view->GetEventHandlerForRect(touch_rect);
1438 EXPECT_EQ(v2, result_view);
1439 result_view = nullptr;
1440
1441 // Covers both |v1| and |v2| by at least 60%, but the center point
1442 // of |touch_rect| is closer to the center point of |v2|.
1443 touch_rect.SetRect(20, 20, 400, 100);
1444 result_view = root_view->GetEventHandlerForRect(touch_rect);
1445 EXPECT_EQ(v2, result_view);
1446 result_view = nullptr;
1447
1448 // Covers both |v1| and |v2| by at least 60%, but the center point
1449 // of |touch_rect| is closer to the center point of |v1|.
1450 touch_rect.SetRect(-700, -15, 1050, 110);
1451 result_view = root_view->GetEventHandlerForRect(touch_rect);
1452 EXPECT_EQ(v1, result_view);
1453 result_view = nullptr;
1454
1455 // A mouse click within |v1| will target |v1|.
1456 touch_rect.SetRect(15, 15, 1, 1);
1457 result_view = root_view->GetEventHandlerForRect(touch_rect);
1458 EXPECT_EQ(v1, result_view);
1459 result_view = nullptr;
1460
1461 // Intersects |v3| and |v31| by at least 60% and the center point
1462 // of |touch_rect| is closer to the center point of |v31|.
1463 touch_rect.SetRect(0, 200, 110, 100);
1464 result_view = root_view->GetEventHandlerForRect(touch_rect);
1465 EXPECT_EQ(v31, result_view);
1466 result_view = nullptr;
1467
1468 // Intersects |v3| and |v31|, but neither by at least 60%. The
1469 // center point of |touch_rect| lies within |v31|.
1470 touch_rect.SetRect(80, 280, 15, 15);
1471 result_view = root_view->GetEventHandlerForRect(touch_rect);
1472 EXPECT_EQ(v31, result_view);
1473 result_view = nullptr;
1474
1475 // Covers |v3|, |v31|, and |v32| all by at least 60%, and the
1476 // center point of |touch_rect| is closest to the center point
1477 // of |v32|.
1478 touch_rect.SetRect(0, 200, 200, 100);
1479 result_view = root_view->GetEventHandlerForRect(touch_rect);
1480 EXPECT_EQ(v32, result_view);
1481 result_view = nullptr;
1482
1483 // Intersects all of |v3|, |v31|, and |v32|, but only covers
1484 // |v31| and |v32| by at least 60%. The center point of
1485 // |touch_rect| is closest to the center point of |v32|.
1486 touch_rect.SetRect(30, 225, 180, 115);
1487 result_view = root_view->GetEventHandlerForRect(touch_rect);
1488 EXPECT_EQ(v32, result_view);
1489 result_view = nullptr;
1490
1491 // A mouse click at the corner of |v3| will target |v3|.
1492 touch_rect.SetRect(0, 200, 1, 1);
1493 result_view = root_view->GetEventHandlerForRect(touch_rect);
1494 EXPECT_EQ(v3, result_view);
1495 result_view = nullptr;
1496
1497 // A mouse click within |v32| will target |v32|.
1498 touch_rect.SetRect(112, 211, 1, 1);
1499 result_view = root_view->GetEventHandlerForRect(touch_rect);
1500 EXPECT_EQ(v32, result_view);
1501 result_view = nullptr;
1502
1503 // Covers all of |v4|, |v41|, and |v411| by at least 60%.
1504 // The center point of |touch_rect| is equally close to
1505 // the center points of |v4| and |v41|.
1506 touch_rect.SetRect(310, 210, 80, 80);
1507 result_view = root_view->GetEventHandlerForRect(touch_rect);
1508 EXPECT_EQ(v41, result_view);
1509 result_view = nullptr;
1510
1511 // Intersects all of |v4|, |v41|, and |v411| but only covers
1512 // |v411| by at least 60%.
1513 touch_rect.SetRect(370, 275, 7, 5);
1514 result_view = root_view->GetEventHandlerForRect(touch_rect);
1515 EXPECT_EQ(v411, result_view);
1516 result_view = nullptr;
1517
1518 // Intersects |v4| and |v41| but covers neither by at least 60%.
1519 // The center point of |touch_rect| is equally close to the center
1520 // points of |v4| and |v41|.
1521 touch_rect.SetRect(345, 245, 7, 7);
1522 result_view = root_view->GetEventHandlerForRect(touch_rect);
1523 EXPECT_EQ(v41, result_view);
1524 result_view = nullptr;
1525
1526 // Intersects all of |v4|, |v41|, and |v411| and covers none of
1527 // them by at least 60%. The center point of |touch_rect| lies
1528 // within |v411|.
1529 touch_rect.SetRect(368, 272, 4, 6);
1530 result_view = root_view->GetEventHandlerForRect(touch_rect);
1531 EXPECT_EQ(v411, result_view);
1532 result_view = nullptr;
1533
1534 // Intersects all of |v4|, |v41|, and |v411| and covers none of
1535 // them by at least 60%. The center point of |touch_rect| lies
1536 // within |v41|.
1537 touch_rect.SetRect(365, 270, 7, 7);
1538 result_view = root_view->GetEventHandlerForRect(touch_rect);
1539 EXPECT_EQ(v41, result_view);
1540 result_view = nullptr;
1541
1542 // Intersects all of |v4|, |v41|, and |v411| and covers none of
1543 // them by at least 60%. The center point of |touch_rect| lies
1544 // within |v4|.
1545 touch_rect.SetRect(205, 275, 200, 2);
1546 result_view = root_view->GetEventHandlerForRect(touch_rect);
1547 EXPECT_EQ(v4, result_view);
1548 result_view = nullptr;
1549
1550 // Intersects all of |v4|, |v41|, and |v411| but only covers
1551 // |v41| by at least 60%.
1552 touch_rect.SetRect(310, 210, 61, 66);
1553 result_view = root_view->GetEventHandlerForRect(touch_rect);
1554 EXPECT_EQ(v41, result_view);
1555 result_view = nullptr;
1556
1557 // A mouse click within |v411| will target |v411|.
1558 touch_rect.SetRect(372, 275, 1, 1);
1559 result_view = root_view->GetEventHandlerForRect(touch_rect);
1560 EXPECT_EQ(v411, result_view);
1561 result_view = nullptr;
1562
1563 // A mouse click within |v41| will target |v41|.
1564 touch_rect.SetRect(350, 215, 1, 1);
1565 result_view = root_view->GetEventHandlerForRect(touch_rect);
1566 EXPECT_EQ(v41, result_view);
1567 result_view = nullptr;
1568
1569 // Covers |v3|, |v4|, and all of their descendants by at
1570 // least 60%. The center point of |touch_rect| is closest
1571 // to the center point of |v32|.
1572 touch_rect.SetRect(0, 200, 400, 100);
1573 result_view = root_view->GetEventHandlerForRect(touch_rect);
1574 EXPECT_EQ(v32, result_view);
1575 result_view = nullptr;
1576
1577 // Intersects all of |v2|, |v3|, |v32|, |v4|, |v41|, and |v411|.
1578 // Covers |v2|, |v32|, |v4|, |v41|, and |v411| by at least 60%.
1579 // The center point of |touch_rect| is closest to the center
1580 // point of |root_view|.
1581 touch_rect.SetRect(110, 15, 375, 450);
1582 result_view = root_view->GetEventHandlerForRect(touch_rect);
1583 EXPECT_EQ(root_view, result_view);
1584 result_view = nullptr;
1585
1586 // Covers all views (except |v5| and |v51|) by at least 60%. The
1587 // center point of |touch_rect| is equally close to the center
1588 // points of |v2| and |v32|. One is not a descendant of the other,
1589 // so in this case the view selected is arbitrary (i.e.,
1590 // it depends only on the ordering of nodes in the views
1591 // hierarchy).
1592 touch_rect.SetRect(0, 0, 400, 300);
1593 result_view = root_view->GetEventHandlerForRect(touch_rect);
1594 EXPECT_EQ(v32, result_view);
1595 result_view = nullptr;
1596
1597 // Covers |v5| and |v51| by at least 60%, and the center point of
1598 // the touch is located within both views. Since both views share
1599 // the same center point, the child view should be selected.
1600 touch_rect.SetRect(440, 190, 40, 40);
1601 result_view = root_view->GetEventHandlerForRect(touch_rect);
1602 EXPECT_EQ(v51, result_view);
1603 result_view = nullptr;
1604
1605 // Covers |v5| and |v51| by at least 60%, but the center point of
1606 // the touch is not located within either view. Since both views
1607 // share the same center point, the child view should be selected.
1608 touch_rect.SetRect(455, 187, 60, 60);
1609 result_view = root_view->GetEventHandlerForRect(touch_rect);
1610 EXPECT_EQ(v51, result_view);
1611 result_view = nullptr;
1612
1613 // Covers neither |v5| nor |v51| by at least 60%, but the center
1614 // of the touch is located within |v51|.
1615 touch_rect.SetRect(450, 197, 10, 10);
1616 result_view = root_view->GetEventHandlerForRect(touch_rect);
1617 EXPECT_EQ(v51, result_view);
1618 result_view = nullptr;
1619
1620 // Covers neither |v5| nor |v51| by at least 60% but intersects both.
1621 // The center point is located outside of both views.
1622 touch_rect.SetRect(433, 180, 24, 24);
1623 result_view = root_view->GetEventHandlerForRect(touch_rect);
1624 EXPECT_EQ(root_view, result_view);
1625 result_view = nullptr;
1626
1627 // Only intersects |v5| but does not cover it by at least 60%. The
1628 // center point of the touch region is located within |v5|.
1629 touch_rect.SetRect(449, 196, 3, 3);
1630 result_view = root_view->GetEventHandlerForRect(touch_rect);
1631 EXPECT_EQ(v5, result_view);
1632 result_view = nullptr;
1633
1634 // A mouse click within |v5| (but not |v51|) should target |v5|.
1635 touch_rect.SetRect(462, 199, 1, 1);
1636 result_view = root_view->GetEventHandlerForRect(touch_rect);
1637 EXPECT_EQ(v5, result_view);
1638 result_view = nullptr;
1639
1640 // A mouse click |v5| and |v51| should target the child view.
1641 touch_rect.SetRect(452, 226, 1, 1);
1642 result_view = root_view->GetEventHandlerForRect(touch_rect);
1643 EXPECT_EQ(v51, result_view);
1644 result_view = nullptr;
1645
1646 // A mouse click on the center of |v5| and |v51| should target
1647 // the child view.
1648 touch_rect.SetRect(465, 215, 1, 1);
1649 result_view = root_view->GetEventHandlerForRect(touch_rect);
1650 EXPECT_EQ(v51, result_view);
1651 result_view = nullptr;
1652
1653 widget->CloseNow();
1654 }
1655
1656 // Tests that GetEventHandlerForRect() and GetTooltipHandlerForPoint() behave
1657 // as expected when different views in the view hierarchy return false
1658 // when CanProcessEventsWithinSubtree() is called.
TEST_F(ViewTest,CanProcessEventsWithinSubtree)1659 TEST_F(ViewTest, CanProcessEventsWithinSubtree) {
1660 Widget* widget = new Widget;
1661 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
1662 widget->Init(std::move(params));
1663 View* root_view = widget->GetRootView();
1664 root_view->SetBoundsRect(gfx::Rect(0, 0, 500, 500));
1665
1666 // Have this hierarchy of views (the coords here are in the coordinate
1667 // space of the root view):
1668 // v (0, 0, 100, 100)
1669 // - v_child (0, 0, 20, 30)
1670 // - v_grandchild (5, 5, 5, 15)
1671
1672 TestView* v = new TestView;
1673 v->SetBounds(0, 0, 100, 100);
1674 root_view->AddChildView(v);
1675 v->set_notify_enter_exit_on_child(true);
1676
1677 TestView* v_child = new TestView;
1678 v_child->SetBounds(0, 0, 20, 30);
1679 v->AddChildView(v_child);
1680
1681 TestView* v_grandchild = new TestView;
1682 v_grandchild->SetBounds(5, 5, 5, 15);
1683 v_child->AddChildView(v_grandchild);
1684
1685 v->Reset();
1686 v_child->Reset();
1687 v_grandchild->Reset();
1688
1689 // Define rects and points within the views in the hierarchy.
1690 gfx::Rect rect_in_v_grandchild(7, 7, 3, 3);
1691 gfx::Point point_in_v_grandchild(rect_in_v_grandchild.origin());
1692 gfx::Rect rect_in_v_child(12, 3, 5, 5);
1693 gfx::Point point_in_v_child(rect_in_v_child.origin());
1694 gfx::Rect rect_in_v(50, 50, 25, 30);
1695 gfx::Point point_in_v(rect_in_v.origin());
1696
1697 // When all three views return true when CanProcessEventsWithinSubtree()
1698 // is called, targeting should behave as expected.
1699
1700 View* result_view = root_view->GetEventHandlerForRect(rect_in_v_grandchild);
1701 EXPECT_EQ(v_grandchild, result_view);
1702 result_view = nullptr;
1703 result_view = root_view->GetTooltipHandlerForPoint(point_in_v_grandchild);
1704 EXPECT_EQ(v_grandchild, result_view);
1705 result_view = nullptr;
1706
1707 result_view = root_view->GetEventHandlerForRect(rect_in_v_child);
1708 EXPECT_EQ(v_child, result_view);
1709 result_view = nullptr;
1710 result_view = root_view->GetTooltipHandlerForPoint(point_in_v_child);
1711 EXPECT_EQ(v_child, result_view);
1712 result_view = nullptr;
1713
1714 result_view = root_view->GetEventHandlerForRect(rect_in_v);
1715 EXPECT_EQ(v, result_view);
1716 result_view = nullptr;
1717 result_view = root_view->GetTooltipHandlerForPoint(point_in_v);
1718 EXPECT_EQ(v, result_view);
1719 result_view = nullptr;
1720
1721 // When |v_grandchild| returns false when CanProcessEventsWithinSubtree()
1722 // is called, then |v_grandchild| cannot be returned as a target.
1723
1724 v_grandchild->set_can_process_events_within_subtree(false);
1725
1726 result_view = root_view->GetEventHandlerForRect(rect_in_v_grandchild);
1727 EXPECT_EQ(v_child, result_view);
1728 result_view = nullptr;
1729 result_view = root_view->GetTooltipHandlerForPoint(point_in_v_grandchild);
1730 EXPECT_EQ(v_child, result_view);
1731 result_view = nullptr;
1732
1733 result_view = root_view->GetEventHandlerForRect(rect_in_v_child);
1734 EXPECT_EQ(v_child, result_view);
1735 result_view = nullptr;
1736 result_view = root_view->GetTooltipHandlerForPoint(point_in_v_child);
1737 EXPECT_EQ(v_child, result_view);
1738 result_view = nullptr;
1739
1740 result_view = root_view->GetEventHandlerForRect(rect_in_v);
1741 EXPECT_EQ(v, result_view);
1742 result_view = nullptr;
1743 result_view = root_view->GetTooltipHandlerForPoint(point_in_v);
1744 EXPECT_EQ(v, result_view);
1745
1746 // When |v_grandchild| returns false when CanProcessEventsWithinSubtree()
1747 // is called, then NULL should be returned as a target if we call
1748 // GetTooltipHandlerForPoint() with |v_grandchild| as the root of the
1749 // views tree. Note that the location must be in the coordinate space
1750 // of the root view (|v_grandchild| in this case), so use (1, 1).
1751
1752 result_view = v_grandchild;
1753 result_view = v_grandchild->GetTooltipHandlerForPoint(gfx::Point(1, 1));
1754 EXPECT_EQ(nullptr, result_view);
1755 result_view = nullptr;
1756
1757 // When |v_child| returns false when CanProcessEventsWithinSubtree()
1758 // is called, then neither |v_child| nor |v_grandchild| can be returned
1759 // as a target (|v| should be returned as the target for each case).
1760
1761 v_grandchild->Reset();
1762 v_child->set_can_process_events_within_subtree(false);
1763
1764 result_view = root_view->GetEventHandlerForRect(rect_in_v_grandchild);
1765 EXPECT_EQ(v, result_view);
1766 result_view = nullptr;
1767 result_view = root_view->GetTooltipHandlerForPoint(point_in_v_grandchild);
1768 EXPECT_EQ(v, result_view);
1769 result_view = nullptr;
1770
1771 result_view = root_view->GetEventHandlerForRect(rect_in_v_child);
1772 EXPECT_EQ(v, result_view);
1773 result_view = nullptr;
1774 result_view = root_view->GetTooltipHandlerForPoint(point_in_v_child);
1775 EXPECT_EQ(v, result_view);
1776 result_view = nullptr;
1777
1778 result_view = root_view->GetEventHandlerForRect(rect_in_v);
1779 EXPECT_EQ(v, result_view);
1780 result_view = nullptr;
1781 result_view = root_view->GetTooltipHandlerForPoint(point_in_v);
1782 EXPECT_EQ(v, result_view);
1783 result_view = nullptr;
1784
1785 // When |v| returns false when CanProcessEventsWithinSubtree()
1786 // is called, then none of |v|, |v_child|, and |v_grandchild| can be returned
1787 // as a target (|root_view| should be returned as the target for each case).
1788
1789 v_child->Reset();
1790 v->set_can_process_events_within_subtree(false);
1791
1792 result_view = root_view->GetEventHandlerForRect(rect_in_v_grandchild);
1793 EXPECT_EQ(root_view, result_view);
1794 result_view = nullptr;
1795 result_view = root_view->GetTooltipHandlerForPoint(point_in_v_grandchild);
1796 EXPECT_EQ(root_view, result_view);
1797 result_view = nullptr;
1798
1799 result_view = root_view->GetEventHandlerForRect(rect_in_v_child);
1800 EXPECT_EQ(root_view, result_view);
1801 result_view = nullptr;
1802 result_view = root_view->GetTooltipHandlerForPoint(point_in_v_child);
1803 EXPECT_EQ(root_view, result_view);
1804 result_view = nullptr;
1805
1806 result_view = root_view->GetEventHandlerForRect(rect_in_v);
1807 EXPECT_EQ(root_view, result_view);
1808 result_view = nullptr;
1809 result_view = root_view->GetTooltipHandlerForPoint(point_in_v);
1810 EXPECT_EQ(root_view, result_view);
1811
1812 widget->CloseNow();
1813 }
1814
TEST_F(ViewTest,NotifyEnterExitOnChild)1815 TEST_F(ViewTest, NotifyEnterExitOnChild) {
1816 Widget* widget = new Widget;
1817 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
1818 widget->Init(std::move(params));
1819 View* root_view = widget->GetRootView();
1820 root_view->SetBoundsRect(gfx::Rect(0, 0, 500, 500));
1821
1822 // Have this hierarchy of views (the coords here are in root coord):
1823 // v1 (0, 0, 100, 100)
1824 // - v11 (0, 0, 20, 30)
1825 // - v111 (5, 5, 5, 15)
1826 // - v12 (50, 10, 30, 90)
1827 // - v121 (60, 20, 10, 10)
1828 // v2 (105, 0, 100, 100)
1829 // - v21 (120, 10, 50, 20)
1830
1831 TestView* v1 = new TestView;
1832 v1->SetBounds(0, 0, 100, 100);
1833 root_view->AddChildView(v1);
1834 v1->set_notify_enter_exit_on_child(true);
1835
1836 TestView* v11 = new TestView;
1837 v11->SetBounds(0, 0, 20, 30);
1838 v1->AddChildView(v11);
1839
1840 TestView* v111 = new TestView;
1841 v111->SetBounds(5, 5, 5, 15);
1842 v11->AddChildView(v111);
1843
1844 TestView* v12 = new TestView;
1845 v12->SetBounds(50, 10, 30, 90);
1846 v1->AddChildView(v12);
1847
1848 TestView* v121 = new TestView;
1849 v121->SetBounds(10, 10, 10, 10);
1850 v12->AddChildView(v121);
1851
1852 TestView* v2 = new TestView;
1853 v2->SetBounds(105, 0, 100, 100);
1854 root_view->AddChildView(v2);
1855
1856 TestView* v21 = new TestView;
1857 v21->SetBounds(15, 10, 50, 20);
1858 v2->AddChildView(v21);
1859
1860 v1->Reset();
1861 v11->Reset();
1862 v111->Reset();
1863 v12->Reset();
1864 v121->Reset();
1865 v2->Reset();
1866 v21->Reset();
1867
1868 // Move the mouse in v111.
1869 gfx::Point p1(6, 6);
1870 ui::MouseEvent move1(ui::ET_MOUSE_MOVED, p1, p1, ui::EventTimeForNow(), 0, 0);
1871 root_view->OnMouseMoved(move1);
1872 EXPECT_TRUE(v111->received_mouse_enter_);
1873 EXPECT_FALSE(v11->last_mouse_event_type_);
1874 EXPECT_TRUE(v1->received_mouse_enter_);
1875
1876 v111->Reset();
1877 v1->Reset();
1878
1879 // Now, move into v121.
1880 gfx::Point p2(65, 21);
1881 ui::MouseEvent move2(ui::ET_MOUSE_MOVED, p2, p2, ui::EventTimeForNow(), 0, 0);
1882 root_view->OnMouseMoved(move2);
1883 EXPECT_TRUE(v111->received_mouse_exit_);
1884 EXPECT_TRUE(v121->received_mouse_enter_);
1885 EXPECT_FALSE(v1->last_mouse_event_type_);
1886
1887 v111->Reset();
1888 v121->Reset();
1889
1890 // Now, move into v11.
1891 gfx::Point p3(1, 1);
1892 ui::MouseEvent move3(ui::ET_MOUSE_MOVED, p3, p3, ui::EventTimeForNow(), 0, 0);
1893 root_view->OnMouseMoved(move3);
1894 EXPECT_TRUE(v121->received_mouse_exit_);
1895 EXPECT_TRUE(v11->received_mouse_enter_);
1896 EXPECT_FALSE(v1->last_mouse_event_type_);
1897
1898 v121->Reset();
1899 v11->Reset();
1900
1901 // Move to v21.
1902 gfx::Point p4(121, 15);
1903 ui::MouseEvent move4(ui::ET_MOUSE_MOVED, p4, p4, ui::EventTimeForNow(), 0, 0);
1904 root_view->OnMouseMoved(move4);
1905 EXPECT_TRUE(v21->received_mouse_enter_);
1906 EXPECT_FALSE(v2->last_mouse_event_type_);
1907 EXPECT_TRUE(v11->received_mouse_exit_);
1908 EXPECT_TRUE(v1->received_mouse_exit_);
1909
1910 v21->Reset();
1911 v11->Reset();
1912 v1->Reset();
1913
1914 // Move to v1.
1915 gfx::Point p5(21, 0);
1916 ui::MouseEvent move5(ui::ET_MOUSE_MOVED, p5, p5, ui::EventTimeForNow(), 0, 0);
1917 root_view->OnMouseMoved(move5);
1918 EXPECT_TRUE(v21->received_mouse_exit_);
1919 EXPECT_TRUE(v1->received_mouse_enter_);
1920
1921 v21->Reset();
1922 v1->Reset();
1923
1924 // Now, move into v11.
1925 gfx::Point p6(15, 15);
1926 ui::MouseEvent mouse6(ui::ET_MOUSE_MOVED, p6, p6, ui::EventTimeForNow(), 0,
1927 0);
1928 root_view->OnMouseMoved(mouse6);
1929 EXPECT_TRUE(v11->received_mouse_enter_);
1930 EXPECT_FALSE(v1->last_mouse_event_type_);
1931
1932 v11->Reset();
1933 v1->Reset();
1934
1935 // Move back into v1. Although |v1| had already received an ENTER for mouse6,
1936 // and the mouse remains inside |v1| the whole time, it receives another ENTER
1937 // when the mouse leaves v11.
1938 gfx::Point p7(21, 0);
1939 ui::MouseEvent mouse7(ui::ET_MOUSE_MOVED, p7, p7, ui::EventTimeForNow(), 0,
1940 0);
1941 root_view->OnMouseMoved(mouse7);
1942 EXPECT_TRUE(v11->received_mouse_exit_);
1943 EXPECT_FALSE(v1->received_mouse_enter_);
1944
1945 widget->CloseNow();
1946 }
1947
TEST_F(ViewTest,Textfield)1948 TEST_F(ViewTest, Textfield) {
1949 const base::string16 kText = ASCIIToUTF16(
1950 "Reality is that which, when you stop believing it, doesn't go away.");
1951 const base::string16 kExtraText = ASCIIToUTF16("Pretty deep, Philip!");
1952
1953 Widget* widget = new Widget;
1954 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
1955 params.bounds = gfx::Rect(0, 0, 100, 100);
1956 widget->Init(std::move(params));
1957 View* root_view = widget->GetRootView();
1958
1959 Textfield* textfield = new Textfield();
1960 root_view->AddChildView(textfield);
1961
1962 // Test setting, appending text.
1963 textfield->SetText(kText);
1964 EXPECT_EQ(kText, textfield->GetText());
1965 textfield->AppendText(kExtraText);
1966 EXPECT_EQ(kText + kExtraText, textfield->GetText());
1967 textfield->SetText(base::string16());
1968 EXPECT_TRUE(textfield->GetText().empty());
1969
1970 // Test selection related methods.
1971 textfield->SetText(kText);
1972 EXPECT_TRUE(textfield->GetSelectedText().empty());
1973 textfield->SelectAll(false);
1974 EXPECT_EQ(kText, textfield->GetText());
1975 textfield->ClearSelection();
1976 EXPECT_TRUE(textfield->GetSelectedText().empty());
1977
1978 widget->CloseNow();
1979 }
1980
1981 // Tests that the Textfield view respond appropiately to cut/copy/paste.
TEST_F(ViewTest,TextfieldCutCopyPaste)1982 TEST_F(ViewTest, TextfieldCutCopyPaste) {
1983 const base::string16 kNormalText = ASCIIToUTF16("Normal");
1984 const base::string16 kReadOnlyText = ASCIIToUTF16("Read only");
1985 const base::string16 kPasswordText =
1986 ASCIIToUTF16("Password! ** Secret stuff **");
1987
1988 ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
1989
1990 Widget* widget = new Widget;
1991 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
1992 params.bounds = gfx::Rect(0, 0, 100, 100);
1993 widget->Init(std::move(params));
1994 View* root_view = widget->GetRootView();
1995
1996 Textfield* normal = new Textfield();
1997 Textfield* read_only = new Textfield();
1998 read_only->SetReadOnly(true);
1999 Textfield* password = new Textfield();
2000 password->SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD);
2001
2002 root_view->AddChildView(normal);
2003 root_view->AddChildView(read_only);
2004 root_view->AddChildView(password);
2005
2006 normal->SetText(kNormalText);
2007 read_only->SetText(kReadOnlyText);
2008 password->SetText(kPasswordText);
2009
2010 //
2011 // Test cut.
2012 //
2013
2014 normal->SelectAll(false);
2015 normal->ExecuteCommand(IDS_APP_CUT, 0);
2016 base::string16 result;
2017 clipboard->ReadText(ui::ClipboardBuffer::kCopyPaste, &result);
2018 EXPECT_EQ(kNormalText, result);
2019 normal->SetText(kNormalText); // Let's revert to the original content.
2020
2021 read_only->SelectAll(false);
2022 read_only->ExecuteCommand(IDS_APP_CUT, 0);
2023 result.clear();
2024 clipboard->ReadText(ui::ClipboardBuffer::kCopyPaste, &result);
2025 // Cut should have failed, so the clipboard content should not have changed.
2026 EXPECT_EQ(kNormalText, result);
2027
2028 password->SelectAll(false);
2029 password->ExecuteCommand(IDS_APP_CUT, 0);
2030 result.clear();
2031 clipboard->ReadText(ui::ClipboardBuffer::kCopyPaste, &result);
2032 // Cut should have failed, so the clipboard content should not have changed.
2033 EXPECT_EQ(kNormalText, result);
2034
2035 //
2036 // Test copy.
2037 //
2038
2039 // Start with |read_only| to observe a change in clipboard text.
2040 read_only->SelectAll(false);
2041 read_only->ExecuteCommand(IDS_APP_COPY, 0);
2042 result.clear();
2043 clipboard->ReadText(ui::ClipboardBuffer::kCopyPaste, &result);
2044 EXPECT_EQ(kReadOnlyText, result);
2045
2046 normal->SelectAll(false);
2047 normal->ExecuteCommand(IDS_APP_COPY, 0);
2048 result.clear();
2049 clipboard->ReadText(ui::ClipboardBuffer::kCopyPaste, &result);
2050 EXPECT_EQ(kNormalText, result);
2051
2052 password->SelectAll(false);
2053 password->ExecuteCommand(IDS_APP_COPY, 0);
2054 result.clear();
2055 clipboard->ReadText(ui::ClipboardBuffer::kCopyPaste, &result);
2056 // Text cannot be copied from an obscured field; the clipboard won't change.
2057 EXPECT_EQ(kNormalText, result);
2058
2059 //
2060 // Test paste.
2061 //
2062
2063 // Attempting to paste kNormalText in a read-only text-field should fail.
2064 read_only->SelectAll(false);
2065 read_only->ExecuteCommand(IDS_APP_PASTE, 0);
2066 EXPECT_EQ(kReadOnlyText, read_only->GetText());
2067
2068 password->SelectAll(false);
2069 password->ExecuteCommand(IDS_APP_PASTE, 0);
2070 EXPECT_EQ(kNormalText, password->GetText());
2071
2072 // Copy from |read_only| to observe a change in the normal textfield text.
2073 read_only->SelectAll(false);
2074 read_only->ExecuteCommand(IDS_APP_COPY, 0);
2075 normal->SelectAll(false);
2076 normal->ExecuteCommand(IDS_APP_PASTE, 0);
2077 EXPECT_EQ(kReadOnlyText, normal->GetText());
2078 widget->CloseNow();
2079 }
2080
2081 class ViewPaintOptimizationTest : public ViewsTestBase {
2082 public:
2083 ViewPaintOptimizationTest() = default;
2084
2085 ~ViewPaintOptimizationTest() override = default;
2086
SetUp()2087 void SetUp() override {
2088 scoped_feature_list_.InitAndEnableFeature(
2089 views::features::kEnableViewPaintOptimization);
2090 ViewTest::SetUp();
2091 }
2092
2093 private:
2094 base::test::ScopedFeatureList scoped_feature_list_;
2095
2096 DISALLOW_COPY_AND_ASSIGN(ViewPaintOptimizationTest);
2097 };
2098
2099 // Tests that only Views where SchedulePaint was invoked get repainted.
TEST_F(ViewPaintOptimizationTest,PaintDirtyViewsOnly)2100 TEST_F(ViewPaintOptimizationTest, PaintDirtyViewsOnly) {
2101 ScopedTestPaintWidget widget(CreateParams(Widget::InitParams::TYPE_POPUP));
2102 View* root_view = widget->GetRootView();
2103
2104 TestView* v1 = root_view->AddChildView(std::make_unique<TestView>());
2105 v1->SetBounds(10, 11, 12, 13);
2106
2107 TestView* v2 = root_view->AddChildView(std::make_unique<TestView>());
2108 v2->SetBounds(3, 4, 6, 5);
2109
2110 TestView* v21 = v2->AddChildView(std::make_unique<TestView>());
2111 v21->SetBounds(2, 3, 4, 5);
2112
2113 // Paint everything once, since it has to build its cache. Then we can test
2114 // invalidation.
2115 gfx::Rect first_paint(1, 1);
2116 auto list = base::MakeRefCounted<cc::DisplayItemList>();
2117 root_view->Paint(PaintInfo::CreateRootPaintInfo(
2118 ui::PaintContext(list.get(), 1.f, first_paint, false),
2119 root_view->size()));
2120 v1->Reset();
2121 v2->Reset();
2122 v21->Reset();
2123
2124 gfx::Rect paint_area(10, 11, 12, 13);
2125 list = base::MakeRefCounted<cc::DisplayItemList>();
2126
2127 // Schedule a paint on v2 which marks it invalidated.
2128 v2->SchedulePaint();
2129 EXPECT_FALSE(v1->did_paint_);
2130 EXPECT_FALSE(v2->did_paint_);
2131 EXPECT_FALSE(v21->did_paint_);
2132
2133 // Paint with an unknown invalidation. The invalidation is irrelevant since
2134 // repainting a view only depends on whether the view had a scheduled paint.
2135 gfx::Rect empty_rect;
2136 EXPECT_TRUE(empty_rect.IsEmpty());
2137
2138 root_view->Paint(PaintInfo::CreateRootPaintInfo(
2139 ui::PaintContext(list.get(), 1.f, paint_area, false), empty_rect.size()));
2140
2141 // Only v2 should be repainted.
2142 EXPECT_FALSE(v1->did_paint_);
2143 EXPECT_TRUE(v2->did_paint_);
2144 EXPECT_FALSE(v21->did_paint_);
2145 }
2146
2147 ////////////////////////////////////////////////////////////////////////////////
2148 // Accelerators
2149 ////////////////////////////////////////////////////////////////////////////////
AcceleratorPressed(const ui::Accelerator & accelerator)2150 bool TestView::AcceleratorPressed(const ui::Accelerator& accelerator) {
2151 accelerator_count_map_[accelerator]++;
2152 return true;
2153 }
2154
2155 namespace {
2156
2157 // A Widget with a TestView in the view hierarchy. Used for accelerator tests.
2158 class TestViewWidget {
2159 public:
TestViewWidget(Widget::InitParams create_params,ui::Accelerator * initial_accelerator,bool show_after_init=true)2160 TestViewWidget(Widget::InitParams create_params,
2161 ui::Accelerator* initial_accelerator,
2162 bool show_after_init = true)
2163 : view_(new TestView) {
2164 view_->Reset();
2165
2166 // Register a keyboard accelerator before the view is added to a window.
2167 if (initial_accelerator) {
2168 view_->AddAccelerator(*initial_accelerator);
2169 EXPECT_EQ(view_->accelerator_count_map_[*initial_accelerator], 0);
2170 }
2171
2172 // Create a window and add the view as its child.
2173 Widget::InitParams params = std::move(create_params);
2174 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2175 params.bounds = gfx::Rect(0, 0, 100, 100);
2176 widget_.Init(std::move(params));
2177 View* root = widget_.GetRootView();
2178 root->AddChildView(view_);
2179 if (show_after_init)
2180 widget_.Show();
2181
2182 EXPECT_TRUE(widget_.GetFocusManager());
2183 }
2184
view()2185 TestView* view() { return view_; }
widget()2186 Widget* widget() { return &widget_; }
2187
2188 private:
2189 TestView* view_;
2190 Widget widget_;
2191
2192 DISALLOW_COPY_AND_ASSIGN(TestViewWidget);
2193 };
2194
2195 } // namespace
2196
2197 // On non-ChromeOS aura there is extra logic to determine whether a view should
2198 // handle accelerators or not (see View::CanHandleAccelerators for details).
2199 // This test targets that extra logic, but should also work on other platforms.
TEST_F(ViewTest,HandleAccelerator)2200 TEST_F(ViewTest, HandleAccelerator) {
2201 ui::Accelerator return_accelerator(ui::VKEY_RETURN, ui::EF_NONE);
2202 TestViewWidget test_widget(CreateParams(Widget::InitParams::TYPE_POPUP),
2203 &return_accelerator);
2204 TestView* view = test_widget.view();
2205 Widget* widget = test_widget.widget();
2206 FocusManager* focus_manager = widget->GetFocusManager();
2207
2208 #if BUILDFLAG(ENABLE_DESKTOP_AURA)
2209 // When a non-child view is not active, it shouldn't handle accelerators.
2210 EXPECT_FALSE(widget->IsActive());
2211 EXPECT_FALSE(focus_manager->ProcessAccelerator(return_accelerator));
2212 EXPECT_EQ(0, view->accelerator_count_map_[return_accelerator]);
2213 #endif
2214
2215 // TYPE_POPUP widgets default to non-activatable, so the Show() above wouldn't
2216 // have activated the Widget. First, allow activation.
2217 widget->widget_delegate()->SetCanActivate(true);
2218
2219 // When a non-child view is active, it should handle accelerators.
2220 view->accelerator_count_map_[return_accelerator] = 0;
2221 widget->Activate();
2222 EXPECT_TRUE(widget->IsActive());
2223 EXPECT_TRUE(focus_manager->ProcessAccelerator(return_accelerator));
2224 EXPECT_EQ(1, view->accelerator_count_map_[return_accelerator]);
2225
2226 // Add a child view associated with a child widget.
2227 TestView* child_view = new TestView();
2228 child_view->Reset();
2229 child_view->AddAccelerator(return_accelerator);
2230 EXPECT_EQ(child_view->accelerator_count_map_[return_accelerator], 0);
2231 Widget* child_widget = new Widget;
2232 Widget::InitParams child_params =
2233 CreateParams(Widget::InitParams::TYPE_CONTROL);
2234 child_params.parent = widget->GetNativeView();
2235 child_widget->Init(std::move(child_params));
2236 child_widget->SetContentsView(child_view);
2237
2238 FocusManager* child_focus_manager = child_widget->GetFocusManager();
2239 ASSERT_TRUE(child_focus_manager);
2240
2241 // When a child view is in focus, it should handle accelerators.
2242 child_view->accelerator_count_map_[return_accelerator] = 0;
2243 view->accelerator_count_map_[return_accelerator] = 0;
2244 child_focus_manager->SetFocusedView(child_view);
2245 EXPECT_FALSE(child_view->GetWidget()->IsActive());
2246 EXPECT_TRUE(child_focus_manager->ProcessAccelerator(return_accelerator));
2247 EXPECT_EQ(1, child_view->accelerator_count_map_[return_accelerator]);
2248 EXPECT_EQ(0, view->accelerator_count_map_[return_accelerator]);
2249
2250 #if BUILDFLAG(ENABLE_DESKTOP_AURA)
2251 // When a child view is not in focus, its parent should handle accelerators.
2252 child_view->accelerator_count_map_[return_accelerator] = 0;
2253 view->accelerator_count_map_[return_accelerator] = 0;
2254 child_focus_manager->ClearFocus();
2255 EXPECT_FALSE(child_view->GetWidget()->IsActive());
2256 EXPECT_TRUE(child_focus_manager->ProcessAccelerator(return_accelerator));
2257 EXPECT_EQ(0, child_view->accelerator_count_map_[return_accelerator]);
2258 EXPECT_EQ(1, view->accelerator_count_map_[return_accelerator]);
2259 #endif
2260 }
2261
2262 // TODO(themblsha): Bring this up on non-Mac platforms. It currently fails
2263 // because TestView::AcceleratorPressed() is not called. See
2264 // http://crbug.com/667757.
2265 #if defined(OS_MACOSX)
2266 // Test that BridgedContentView correctly handles Accelerator key events when
2267 // subject to OS event dispatch.
TEST_F(ViewTest,ActivateAcceleratorOnMac)2268 TEST_F(ViewTest, ActivateAcceleratorOnMac) {
2269 // Cmd+1 translates to "noop:" command by interpretKeyEvents.
2270 ui::Accelerator command_accelerator(ui::VKEY_1, ui::EF_COMMAND_DOWN);
2271 TestViewWidget test_widget(CreateParams(Widget::InitParams::TYPE_POPUP),
2272 &command_accelerator);
2273 TestView* view = test_widget.view();
2274
2275 ui::test::EventGenerator event_generator(
2276 test_widget.widget()->GetNativeWindow());
2277 // Emulate normal event dispatch through -[NSWindow sendEvent:].
2278 event_generator.set_target(ui::test::EventGenerator::Target::WINDOW);
2279
2280 event_generator.PressKey(command_accelerator.key_code(),
2281 command_accelerator.modifiers());
2282 event_generator.ReleaseKey(command_accelerator.key_code(),
2283 command_accelerator.modifiers());
2284 EXPECT_EQ(view->accelerator_count_map_[command_accelerator], 1);
2285
2286 // Without an _wantsKeyDownForEvent: override we'll only get a keyUp: event
2287 // for this accelerator.
2288 ui::Accelerator key_up_accelerator(ui::VKEY_TAB,
2289 ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN);
2290 view->AddAccelerator(key_up_accelerator);
2291 event_generator.PressKey(key_up_accelerator.key_code(),
2292 key_up_accelerator.modifiers());
2293 event_generator.ReleaseKey(key_up_accelerator.key_code(),
2294 key_up_accelerator.modifiers());
2295 EXPECT_EQ(view->accelerator_count_map_[key_up_accelerator], 1);
2296
2297 // We should handle this accelerator inside keyDown: as it doesn't translate
2298 // to any command by default.
2299 ui::Accelerator key_down_accelerator(
2300 ui::VKEY_L, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN | ui::EF_SHIFT_DOWN);
2301 view->AddAccelerator(key_down_accelerator);
2302 event_generator.PressKey(key_down_accelerator.key_code(),
2303 key_down_accelerator.modifiers());
2304 event_generator.ReleaseKey(key_down_accelerator.key_code(),
2305 key_down_accelerator.modifiers());
2306 EXPECT_EQ(view->accelerator_count_map_[key_down_accelerator], 1);
2307 }
2308 #endif // OS_MACOSX
2309
2310 // TODO(crbug.com/667757): these tests were initially commented out when getting
2311 // aura to run. Figure out if still valuable and either nuke or fix.
2312 #if defined(OS_MACOSX)
TEST_F(ViewTest,ActivateAccelerator)2313 TEST_F(ViewTest, ActivateAccelerator) {
2314 ui::Accelerator return_accelerator(ui::VKEY_RETURN, ui::EF_NONE);
2315 TestViewWidget test_widget(CreateParams(Widget::InitParams::TYPE_POPUP),
2316 &return_accelerator);
2317 TestView* view = test_widget.view();
2318 FocusManager* focus_manager = test_widget.widget()->GetFocusManager();
2319
2320 // Hit the return key and see if it takes effect.
2321 EXPECT_TRUE(focus_manager->ProcessAccelerator(return_accelerator));
2322 EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 1);
2323
2324 // Hit the escape key. Nothing should happen.
2325 ui::Accelerator escape_accelerator(ui::VKEY_ESCAPE, ui::EF_NONE);
2326 EXPECT_FALSE(focus_manager->ProcessAccelerator(escape_accelerator));
2327 EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 1);
2328 EXPECT_EQ(view->accelerator_count_map_[escape_accelerator], 0);
2329
2330 // Now register the escape key and hit it again.
2331 view->AddAccelerator(escape_accelerator);
2332 EXPECT_TRUE(focus_manager->ProcessAccelerator(escape_accelerator));
2333 EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 1);
2334 EXPECT_EQ(view->accelerator_count_map_[escape_accelerator], 1);
2335
2336 // Remove the return key accelerator.
2337 view->RemoveAccelerator(return_accelerator);
2338 EXPECT_FALSE(focus_manager->ProcessAccelerator(return_accelerator));
2339 EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 1);
2340 EXPECT_EQ(view->accelerator_count_map_[escape_accelerator], 1);
2341
2342 // Add it again. Hit the return key and the escape key.
2343 view->AddAccelerator(return_accelerator);
2344 EXPECT_TRUE(focus_manager->ProcessAccelerator(return_accelerator));
2345 EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 2);
2346 EXPECT_EQ(view->accelerator_count_map_[escape_accelerator], 1);
2347 EXPECT_TRUE(focus_manager->ProcessAccelerator(escape_accelerator));
2348 EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 2);
2349 EXPECT_EQ(view->accelerator_count_map_[escape_accelerator], 2);
2350
2351 // Remove all the accelerators.
2352 view->ResetAccelerators();
2353 EXPECT_FALSE(focus_manager->ProcessAccelerator(return_accelerator));
2354 EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 2);
2355 EXPECT_EQ(view->accelerator_count_map_[escape_accelerator], 2);
2356 EXPECT_FALSE(focus_manager->ProcessAccelerator(escape_accelerator));
2357 EXPECT_EQ(view->accelerator_count_map_[return_accelerator], 2);
2358 EXPECT_EQ(view->accelerator_count_map_[escape_accelerator], 2);
2359 }
2360
TEST_F(ViewTest,HiddenViewWithAccelerator)2361 TEST_F(ViewTest, HiddenViewWithAccelerator) {
2362 ui::Accelerator return_accelerator(ui::VKEY_RETURN, ui::EF_NONE);
2363 TestViewWidget test_widget(CreateParams(Widget::InitParams::TYPE_POPUP),
2364 &return_accelerator);
2365 TestView* view = test_widget.view();
2366 FocusManager* focus_manager = test_widget.widget()->GetFocusManager();
2367
2368 view->SetVisible(false);
2369 EXPECT_FALSE(focus_manager->ProcessAccelerator(return_accelerator));
2370
2371 view->SetVisible(true);
2372 EXPECT_TRUE(focus_manager->ProcessAccelerator(return_accelerator));
2373 }
2374
TEST_F(ViewTest,ViewInHiddenWidgetWithAccelerator)2375 TEST_F(ViewTest, ViewInHiddenWidgetWithAccelerator) {
2376 ui::Accelerator return_accelerator(ui::VKEY_RETURN, ui::EF_NONE);
2377 TestViewWidget test_widget(CreateParams(Widget::InitParams::TYPE_POPUP),
2378 &return_accelerator, false);
2379 TestView* view = test_widget.view();
2380 Widget* widget = test_widget.widget();
2381 FocusManager* focus_manager = test_widget.widget()->GetFocusManager();
2382
2383 EXPECT_FALSE(focus_manager->ProcessAccelerator(return_accelerator));
2384 EXPECT_EQ(0, view->accelerator_count_map_[return_accelerator]);
2385
2386 widget->Show();
2387 EXPECT_TRUE(focus_manager->ProcessAccelerator(return_accelerator));
2388 EXPECT_EQ(1, view->accelerator_count_map_[return_accelerator]);
2389
2390 widget->Hide();
2391 EXPECT_FALSE(focus_manager->ProcessAccelerator(return_accelerator));
2392 EXPECT_EQ(1, view->accelerator_count_map_[return_accelerator]);
2393 }
2394 #endif // OS_MACOSX
2395
2396 // TODO(crbug.com/667757): these tests were initially commented out when getting
2397 // aura to run. Figure out if still valuable and either nuke or fix.
2398 #if 0
2399 ////////////////////////////////////////////////////////////////////////////////
2400 // Mouse-wheel message rerouting
2401 ////////////////////////////////////////////////////////////////////////////////
2402 class ScrollableTestView : public View {
2403 public:
2404 ScrollableTestView() { }
2405
2406 virtual gfx::Size GetPreferredSize() {
2407 return gfx::Size(100, 10000);
2408 }
2409
2410 virtual void Layout() {
2411 SizeToPreferredSize();
2412 }
2413 };
2414
2415 class TestViewWithControls : public View {
2416 public:
2417 TestViewWithControls() {
2418 text_field_ = new Textfield();
2419 AddChildView(text_field_);
2420 }
2421
2422 Textfield* text_field_;
2423 };
2424
2425 class SimpleWidgetDelegate : public WidgetDelegate {
2426 public:
2427 explicit SimpleWidgetDelegate(View* contents) : contents_(contents) { }
2428
2429 virtual void DeleteDelegate() { delete this; }
2430
2431 virtual View* GetContentsView() { return contents_; }
2432
2433 virtual Widget* GetWidget() { return contents_->GetWidget(); }
2434 virtual const Widget* GetWidget() const { return contents_->GetWidget(); }
2435
2436 private:
2437 View* contents_;
2438 };
2439
2440 // Tests that the mouse-wheel messages are correctly rerouted to the window
2441 // under the mouse.
2442 // TODO(jcampan): http://crbug.com/10572 Disabled as it fails on the Vista build
2443 // bot.
2444 // Note that this fails for a variety of reasons:
2445 // - focused view is apparently reset across window activations and never
2446 // properly restored
2447 // - this test depends on you not having any other window visible open under the
2448 // area that it opens the test windows. --beng
2449 TEST_F(ViewTest, DISABLED_RerouteMouseWheelTest) {
2450 TestViewWithControls* view_with_controls = new TestViewWithControls();
2451 Widget* window1 = Widget::CreateWindowWithBounds(
2452 new SimpleWidgetDelegate(view_with_controls),
2453 gfx::Rect(0, 0, 100, 100));
2454 window1->Show();
2455 ScrollView* scroll_view = new ScrollView();
2456 scroll_view->SetContents(new ScrollableTestView());
2457 Widget* window2 = Widget::CreateWindowWithBounds(
2458 new SimpleWidgetDelegate(scroll_view),
2459 gfx::Rect(200, 200, 100, 100));
2460 window2->Show();
2461 EXPECT_EQ(0, scroll_view->GetVisibleRect().y());
2462
2463 // Make the window1 active, as this is what it would be in real-world.
2464 window1->Activate();
2465
2466 // Let's send a mouse-wheel message to the different controls and check that
2467 // it is rerouted to the window under the mouse (effectively scrolling the
2468 // scroll-view).
2469
2470 // First to the Window's HWND.
2471 ::SendMessage(view_with_controls->GetWidget()->GetNativeView(),
2472 WM_MOUSEWHEEL, MAKEWPARAM(0, -20), MAKELPARAM(250, 250));
2473 EXPECT_EQ(20, scroll_view->GetVisibleRect().y());
2474
2475 window1->CloseNow();
2476 window2->CloseNow();
2477 }
2478 #endif // 0
2479
2480 ////////////////////////////////////////////////////////////////////////////////
2481 // Native view hierachy
2482 ////////////////////////////////////////////////////////////////////////////////
2483 class ToplevelWidgetObserverView : public View {
2484 public:
2485 ToplevelWidgetObserverView() = default;
2486 ~ToplevelWidgetObserverView() override = default;
2487
2488 // View overrides:
ViewHierarchyChanged(const ViewHierarchyChangedDetails & details)2489 void ViewHierarchyChanged(
2490 const ViewHierarchyChangedDetails& details) override {
2491 if (details.is_add) {
2492 toplevel_ = GetWidget() ? GetWidget()->GetTopLevelWidget() : nullptr;
2493 } else {
2494 toplevel_ = nullptr;
2495 }
2496 }
NativeViewHierarchyChanged()2497 void NativeViewHierarchyChanged() override {
2498 toplevel_ = GetWidget() ? GetWidget()->GetTopLevelWidget() : nullptr;
2499 }
2500
toplevel()2501 Widget* toplevel() { return toplevel_; }
2502
2503 private:
2504 Widget* toplevel_ = nullptr;
2505
2506 DISALLOW_COPY_AND_ASSIGN(ToplevelWidgetObserverView);
2507 };
2508
2509 // Test that a view can track the current top level widget by overriding
2510 // View::ViewHierarchyChanged() and View::NativeViewHierarchyChanged().
TEST_F(ViewTest,NativeViewHierarchyChanged)2511 TEST_F(ViewTest, NativeViewHierarchyChanged) {
2512 std::unique_ptr<Widget> toplevel1(new Widget);
2513 Widget::InitParams toplevel1_params =
2514 CreateParams(Widget::InitParams::TYPE_POPUP);
2515 toplevel1_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2516 toplevel1->Init(std::move(toplevel1_params));
2517
2518 std::unique_ptr<Widget> toplevel2(new Widget);
2519 Widget::InitParams toplevel2_params =
2520 CreateParams(Widget::InitParams::TYPE_POPUP);
2521 toplevel2_params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2522 toplevel2->Init(std::move(toplevel2_params));
2523
2524 Widget* child = new Widget;
2525 Widget::InitParams child_params(Widget::InitParams::TYPE_CONTROL);
2526 child_params.parent = toplevel1->GetNativeView();
2527 child->Init(std::move(child_params));
2528
2529 ToplevelWidgetObserverView* observer_view = new ToplevelWidgetObserverView();
2530 EXPECT_EQ(nullptr, observer_view->toplevel());
2531
2532 child->SetContentsView(observer_view);
2533 EXPECT_EQ(toplevel1.get(), observer_view->toplevel());
2534
2535 Widget::ReparentNativeView(child->GetNativeView(),
2536 toplevel2->GetNativeView());
2537 EXPECT_EQ(toplevel2.get(), observer_view->toplevel());
2538
2539 observer_view->parent()->RemoveChildView(observer_view);
2540 EXPECT_EQ(nullptr, observer_view->toplevel());
2541
2542 // Make |observer_view| |child|'s contents view again so that it gets deleted
2543 // with the widget.
2544 child->SetContentsView(observer_view);
2545 }
2546
2547 ////////////////////////////////////////////////////////////////////////////////
2548 // Transformations
2549 ////////////////////////////////////////////////////////////////////////////////
2550
2551 class TransformPaintView : public TestView {
2552 public:
2553 TransformPaintView() = default;
2554 ~TransformPaintView() override = default;
2555
ClearScheduledPaintRect()2556 void ClearScheduledPaintRect() { scheduled_paint_rect_ = gfx::Rect(); }
2557
scheduled_paint_rect() const2558 gfx::Rect scheduled_paint_rect() const { return scheduled_paint_rect_; }
2559
2560 // Overridden from View:
OnDidSchedulePaint(const gfx::Rect & rect)2561 void OnDidSchedulePaint(const gfx::Rect& rect) override {
2562 gfx::Rect xrect = ConvertRectToParent(rect);
2563 scheduled_paint_rect_.Union(xrect);
2564 }
2565
2566 private:
2567 gfx::Rect scheduled_paint_rect_;
2568
2569 DISALLOW_COPY_AND_ASSIGN(TransformPaintView);
2570 };
2571
TEST_F(ViewTest,TransformPaint)2572 TEST_F(ViewTest, TransformPaint) {
2573 TransformPaintView* v1 = new TransformPaintView();
2574 v1->SetBoundsRect(gfx::Rect(0, 0, 500, 300));
2575
2576 TestView* v2 = new TestView();
2577 v2->SetBoundsRect(gfx::Rect(100, 100, 200, 100));
2578
2579 Widget* widget = new Widget;
2580 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
2581 params.bounds = gfx::Rect(50, 50, 650, 650);
2582 widget->Init(std::move(params));
2583 widget->Show();
2584 View* root = widget->GetRootView();
2585
2586 root->AddChildView(v1);
2587 v1->AddChildView(v2);
2588
2589 // At this moment, |v2| occupies (100, 100) to (300, 200) in |root|.
2590 v1->ClearScheduledPaintRect();
2591 v2->SchedulePaint();
2592
2593 EXPECT_EQ(gfx::Rect(100, 100, 200, 100), v1->scheduled_paint_rect());
2594
2595 // Rotate |v1| counter-clockwise.
2596 gfx::Transform transform;
2597 RotateCounterclockwise(&transform);
2598 transform.matrix().set(1, 3, 500.0);
2599 v1->SetTransform(transform);
2600
2601 // |v2| now occupies (100, 200) to (200, 400) in |root|.
2602
2603 v1->ClearScheduledPaintRect();
2604 v2->SchedulePaint();
2605
2606 EXPECT_EQ(gfx::Rect(100, 200, 100, 200), v1->scheduled_paint_rect());
2607
2608 widget->CloseNow();
2609 }
2610
TEST_F(ViewTest,TransformEvent)2611 TEST_F(ViewTest, TransformEvent) {
2612 TestView* v1 = new TestView();
2613 v1->SetBoundsRect(gfx::Rect(0, 0, 500, 300));
2614
2615 TestView* v2 = new TestView();
2616 v2->SetBoundsRect(gfx::Rect(100, 100, 200, 100));
2617
2618 Widget* widget = new Widget;
2619 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
2620 params.bounds = gfx::Rect(50, 50, 650, 650);
2621 widget->Init(std::move(params));
2622 View* root = widget->GetRootView();
2623
2624 root->AddChildView(v1);
2625 v1->AddChildView(v2);
2626
2627 // At this moment, |v2| occupies (100, 100) to (300, 200) in |root|.
2628
2629 // Rotate |v1| counter-clockwise.
2630 gfx::Transform transform(v1->GetTransform());
2631 RotateCounterclockwise(&transform);
2632 transform.matrix().set(1, 3, 500.0);
2633 v1->SetTransform(transform);
2634
2635 // |v2| now occupies (100, 200) to (200, 400) in |root|.
2636 v1->Reset();
2637 v2->Reset();
2638
2639 gfx::Point p1(110, 210);
2640 ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, p1, p1, ui::EventTimeForNow(),
2641 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
2642 root->OnMousePressed(pressed);
2643 EXPECT_EQ(0, v1->last_mouse_event_type_);
2644 EXPECT_EQ(ui::ET_MOUSE_PRESSED, v2->last_mouse_event_type_);
2645 EXPECT_EQ(190, v2->location_.x());
2646 EXPECT_EQ(10, v2->location_.y());
2647
2648 ui::MouseEvent released(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(),
2649 ui::EventTimeForNow(), 0, 0);
2650 root->OnMouseReleased(released);
2651
2652 // Now rotate |v2| inside |v1| clockwise.
2653 transform = v2->GetTransform();
2654 RotateClockwise(&transform);
2655 transform.matrix().set(0, 3, 100.f);
2656 v2->SetTransform(transform);
2657
2658 // Now, |v2| occupies (100, 100) to (200, 300) in |v1|, and (100, 300) to
2659 // (300, 400) in |root|.
2660
2661 v1->Reset();
2662 v2->Reset();
2663
2664 gfx::Point point2(110, 320);
2665 ui::MouseEvent p2(ui::ET_MOUSE_PRESSED, point2, point2, ui::EventTimeForNow(),
2666 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
2667 root->OnMousePressed(p2);
2668 EXPECT_EQ(0, v1->last_mouse_event_type_);
2669 EXPECT_EQ(ui::ET_MOUSE_PRESSED, v2->last_mouse_event_type_);
2670 EXPECT_EQ(10, v2->location_.x());
2671 EXPECT_EQ(20, v2->location_.y());
2672
2673 root->OnMouseReleased(released);
2674
2675 v1->SetTransform(gfx::Transform());
2676 v2->SetTransform(gfx::Transform());
2677
2678 TestView* v3 = new TestView();
2679 v3->SetBoundsRect(gfx::Rect(10, 10, 20, 30));
2680 v2->AddChildView(v3);
2681
2682 // Rotate |v3| clockwise with respect to |v2|.
2683 transform = v1->GetTransform();
2684 RotateClockwise(&transform);
2685 transform.matrix().set(0, 3, 30.f);
2686 v3->SetTransform(transform);
2687
2688 // Scale |v2| with respect to |v1| along both axis.
2689 transform = v2->GetTransform();
2690 transform.matrix().set(0, 0, 0.8f);
2691 transform.matrix().set(1, 1, 0.5f);
2692 v2->SetTransform(transform);
2693
2694 // |v3| occupies (108, 105) to (132, 115) in |root|.
2695
2696 v1->Reset();
2697 v2->Reset();
2698 v3->Reset();
2699
2700 gfx::Point point(112, 110);
2701 ui::MouseEvent p3(ui::ET_MOUSE_PRESSED, point, point, ui::EventTimeForNow(),
2702 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
2703 root->OnMousePressed(p3);
2704
2705 EXPECT_EQ(ui::ET_MOUSE_PRESSED, v3->last_mouse_event_type_);
2706 EXPECT_EQ(10, v3->location_.x());
2707 EXPECT_EQ(25, v3->location_.y());
2708
2709 root->OnMouseReleased(released);
2710
2711 v1->SetTransform(gfx::Transform());
2712 v2->SetTransform(gfx::Transform());
2713 v3->SetTransform(gfx::Transform());
2714
2715 v1->Reset();
2716 v2->Reset();
2717 v3->Reset();
2718
2719 // Rotate |v3| clockwise with respect to |v2|, and scale it along both axis.
2720 transform = v3->GetTransform();
2721 RotateClockwise(&transform);
2722 transform.matrix().set(0, 3, 30.f);
2723 // Rotation sets some scaling transformation. Using SetScale would overwrite
2724 // that and pollute the rotation. So combine the scaling with the existing
2725 // transforamtion.
2726 gfx::Transform scale;
2727 scale.Scale(0.8f, 0.5f);
2728 transform.ConcatTransform(scale);
2729 v3->SetTransform(transform);
2730
2731 // Translate |v2| with respect to |v1|.
2732 transform = v2->GetTransform();
2733 transform.matrix().set(0, 3, 10.f);
2734 transform.matrix().set(1, 3, 10.f);
2735 v2->SetTransform(transform);
2736
2737 // |v3| now occupies (120, 120) to (144, 130) in |root|.
2738
2739 gfx::Point point3(124, 125);
2740 ui::MouseEvent p4(ui::ET_MOUSE_PRESSED, point3, point3, ui::EventTimeForNow(),
2741 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
2742 root->OnMousePressed(p4);
2743
2744 EXPECT_EQ(ui::ET_MOUSE_PRESSED, v3->last_mouse_event_type_);
2745 EXPECT_EQ(10, v3->location_.x());
2746 EXPECT_EQ(25, v3->location_.y());
2747
2748 root->OnMouseReleased(released);
2749
2750 widget->CloseNow();
2751 }
2752
TEST_F(ViewTest,TransformVisibleBound)2753 TEST_F(ViewTest, TransformVisibleBound) {
2754 gfx::Rect viewport_bounds(0, 0, 100, 100);
2755
2756 std::unique_ptr<Widget> widget(new Widget);
2757 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
2758 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2759 params.bounds = viewport_bounds;
2760 widget->Init(std::move(params));
2761 widget->GetRootView()->SetBoundsRect(viewport_bounds);
2762
2763 View* viewport = new View;
2764 widget->SetContentsView(viewport);
2765 View* contents = new View;
2766 viewport->AddChildView(contents);
2767 viewport->SetBoundsRect(viewport_bounds);
2768 contents->SetBoundsRect(gfx::Rect(0, 0, 100, 200));
2769
2770 View* child = new View;
2771 contents->AddChildView(child);
2772 child->SetBoundsRect(gfx::Rect(10, 90, 50, 50));
2773 EXPECT_EQ(gfx::Rect(0, 0, 50, 10), child->GetVisibleBounds());
2774
2775 // Rotate |child| counter-clockwise
2776 gfx::Transform transform;
2777 RotateCounterclockwise(&transform);
2778 transform.matrix().set(1, 3, 50.f);
2779 child->SetTransform(transform);
2780 EXPECT_EQ(gfx::Rect(40, 0, 10, 50), child->GetVisibleBounds());
2781
2782 widget->CloseNow();
2783 }
2784
2785 ////////////////////////////////////////////////////////////////////////////////
2786 // OnVisibleBoundsChanged()
2787
2788 class VisibleBoundsView : public View {
2789 public:
2790 VisibleBoundsView() = default;
2791 ~VisibleBoundsView() override = default;
2792
received_notification() const2793 bool received_notification() const { return received_notification_; }
set_received_notification(bool received)2794 void set_received_notification(bool received) {
2795 received_notification_ = received;
2796 }
2797
2798 private:
2799 // Overridden from View:
GetNeedsNotificationWhenVisibleBoundsChange() const2800 bool GetNeedsNotificationWhenVisibleBoundsChange() const override {
2801 return true;
2802 }
OnVisibleBoundsChanged()2803 void OnVisibleBoundsChanged() override { received_notification_ = true; }
2804
2805 bool received_notification_ = false;
2806
2807 DISALLOW_COPY_AND_ASSIGN(VisibleBoundsView);
2808 };
2809
TEST_F(ViewTest,OnVisibleBoundsChanged)2810 TEST_F(ViewTest, OnVisibleBoundsChanged) {
2811 gfx::Rect viewport_bounds(0, 0, 100, 100);
2812
2813 std::unique_ptr<Widget> widget(new Widget);
2814 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
2815 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2816 params.bounds = viewport_bounds;
2817 widget->Init(std::move(params));
2818 widget->GetRootView()->SetBoundsRect(viewport_bounds);
2819
2820 View* viewport = new View;
2821 widget->SetContentsView(viewport);
2822 View* contents = new View;
2823 viewport->AddChildView(contents);
2824 viewport->SetBoundsRect(viewport_bounds);
2825 contents->SetBoundsRect(gfx::Rect(0, 0, 100, 200));
2826
2827 // Create a view that cares about visible bounds notifications, and position
2828 // it just outside the visible bounds of the viewport.
2829 VisibleBoundsView* child = new VisibleBoundsView;
2830 contents->AddChildView(child);
2831 child->SetBoundsRect(gfx::Rect(10, 110, 50, 50));
2832
2833 // The child bound should be fully clipped.
2834 EXPECT_TRUE(child->GetVisibleBounds().IsEmpty());
2835
2836 // Now scroll the contents, but not enough to make the child visible.
2837 contents->SetY(contents->y() - 1);
2838
2839 // We should have received the notification since the visible bounds may have
2840 // changed (even though they didn't).
2841 EXPECT_TRUE(child->received_notification());
2842 EXPECT_TRUE(child->GetVisibleBounds().IsEmpty());
2843 child->set_received_notification(false);
2844
2845 // Now scroll the contents, this time by enough to make the child visible by
2846 // one pixel.
2847 contents->SetY(contents->y() - 10);
2848 EXPECT_TRUE(child->received_notification());
2849 EXPECT_EQ(1, child->GetVisibleBounds().height());
2850 child->set_received_notification(false);
2851
2852 widget->CloseNow();
2853 }
2854
TEST_F(ViewTest,SetBoundsPaint)2855 TEST_F(ViewTest, SetBoundsPaint) {
2856 TestView top_view;
2857 TestView* child_view = new TestView;
2858
2859 top_view.SetBoundsRect(gfx::Rect(0, 0, 100, 100));
2860 top_view.scheduled_paint_rects_.clear();
2861 child_view->SetBoundsRect(gfx::Rect(10, 10, 20, 20));
2862 top_view.AddChildView(child_view);
2863
2864 top_view.scheduled_paint_rects_.clear();
2865 child_view->SetBoundsRect(gfx::Rect(30, 30, 20, 20));
2866 EXPECT_EQ(2U, top_view.scheduled_paint_rects_.size());
2867
2868 // There should be 2 rects, spanning from (10, 10) to (50, 50).
2869 gfx::Rect paint_rect = top_view.scheduled_paint_rects_[0];
2870 paint_rect.Union(top_view.scheduled_paint_rects_[1]);
2871 EXPECT_EQ(gfx::Rect(10, 10, 40, 40), paint_rect);
2872 }
2873
2874 // Assertions around painting and focus gain/lost.
TEST_F(ViewTest,FocusBlurPaints)2875 TEST_F(ViewTest, FocusBlurPaints) {
2876 TestView parent_view;
2877 TestView* child_view1 = new TestView; // Owned by |parent_view|.
2878
2879 parent_view.SetBoundsRect(gfx::Rect(0, 0, 100, 100));
2880
2881 child_view1->SetBoundsRect(gfx::Rect(0, 0, 20, 20));
2882 parent_view.AddChildView(child_view1);
2883
2884 parent_view.scheduled_paint_rects_.clear();
2885 child_view1->scheduled_paint_rects_.clear();
2886
2887 // Focus change shouldn't trigger paints.
2888 child_view1->DoFocus();
2889
2890 EXPECT_TRUE(parent_view.scheduled_paint_rects_.empty());
2891 EXPECT_TRUE(child_view1->scheduled_paint_rects_.empty());
2892
2893 child_view1->DoBlur();
2894 EXPECT_TRUE(parent_view.scheduled_paint_rects_.empty());
2895 EXPECT_TRUE(child_view1->scheduled_paint_rects_.empty());
2896 }
2897
2898 // Verifies SetBounds(same bounds) doesn't trigger a SchedulePaint().
TEST_F(ViewTest,SetBoundsSameBoundsDoesntSchedulePaint)2899 TEST_F(ViewTest, SetBoundsSameBoundsDoesntSchedulePaint) {
2900 TestView view;
2901
2902 view.SetBoundsRect(gfx::Rect(0, 0, 100, 100));
2903 view.InvalidateLayout();
2904 view.scheduled_paint_rects_.clear();
2905 view.SetBoundsRect(gfx::Rect(0, 0, 100, 100));
2906 EXPECT_TRUE(view.scheduled_paint_rects_.empty());
2907 }
2908
2909 // Verifies AddChildView() and RemoveChildView() schedule appropriate paints.
TEST_F(ViewTest,AddAndRemoveSchedulePaints)2910 TEST_F(ViewTest, AddAndRemoveSchedulePaints) {
2911 gfx::Rect viewport_bounds(0, 0, 100, 100);
2912
2913 // We have to put the View hierarchy into a Widget or no paints will be
2914 // scheduled.
2915 std::unique_ptr<Widget> widget(new Widget);
2916 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
2917 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
2918 params.bounds = viewport_bounds;
2919 widget->Init(std::move(params));
2920 widget->GetRootView()->SetBoundsRect(viewport_bounds);
2921
2922 TestView* parent_view = new TestView;
2923 widget->SetContentsView(parent_view);
2924 parent_view->SetBoundsRect(viewport_bounds);
2925 parent_view->scheduled_paint_rects_.clear();
2926
2927 View* child_view = new View;
2928 child_view->SetBoundsRect(gfx::Rect(0, 0, 20, 20));
2929 parent_view->AddChildView(child_view);
2930 ASSERT_EQ(1U, parent_view->scheduled_paint_rects_.size());
2931 EXPECT_EQ(child_view->bounds(), parent_view->scheduled_paint_rects_.front());
2932
2933 parent_view->scheduled_paint_rects_.clear();
2934 parent_view->RemoveChildView(child_view);
2935 std::unique_ptr<View> child_deleter(child_view);
2936 ASSERT_EQ(1U, parent_view->scheduled_paint_rects_.size());
2937 EXPECT_EQ(child_view->bounds(), parent_view->scheduled_paint_rects_.front());
2938
2939 widget->CloseNow();
2940 }
2941
2942 // Tests conversion methods with a transform.
TEST_F(ViewTest,ConversionsWithTransform)2943 TEST_F(ViewTest, ConversionsWithTransform) {
2944 TestView top_view;
2945
2946 // View hierarchy used to test scale transforms.
2947 TestView* child = new TestView;
2948 TestView* child_child = new TestView;
2949
2950 // View used to test a rotation transform.
2951 TestView* child_2 = new TestView;
2952
2953 top_view.AddChildView(child);
2954 child->AddChildView(child_child);
2955
2956 top_view.SetBoundsRect(gfx::Rect(0, 0, 1000, 1000));
2957
2958 child->SetBoundsRect(gfx::Rect(7, 19, 500, 500));
2959 gfx::Transform transform;
2960 transform.Scale(3.0, 4.0);
2961 child->SetTransform(transform);
2962
2963 child_child->SetBoundsRect(gfx::Rect(17, 13, 100, 100));
2964 transform.MakeIdentity();
2965 transform.Scale(5.0, 7.0);
2966 child_child->SetTransform(transform);
2967
2968 top_view.AddChildView(child_2);
2969 child_2->SetBoundsRect(gfx::Rect(700, 725, 100, 100));
2970 transform.MakeIdentity();
2971 RotateClockwise(&transform);
2972 child_2->SetTransform(transform);
2973
2974 // Sanity check to make sure basic transforms act as expected.
2975 {
2976 gfx::Transform transform;
2977 transform.Translate(110.0, -110.0);
2978 transform.Scale(100.0, 55.0);
2979 transform.Translate(1.0, 1.0);
2980
2981 // convert to a 3x3 matrix.
2982 const SkMatrix& matrix = SkMatrix(transform.matrix());
2983
2984 EXPECT_EQ(210, matrix.getTranslateX());
2985 EXPECT_EQ(-55, matrix.getTranslateY());
2986 EXPECT_EQ(100, matrix.getScaleX());
2987 EXPECT_EQ(55, matrix.getScaleY());
2988 EXPECT_EQ(0, matrix.getSkewX());
2989 EXPECT_EQ(0, matrix.getSkewY());
2990 }
2991
2992 {
2993 gfx::Transform transform;
2994 transform.Translate(1.0, 1.0);
2995 gfx::Transform t2;
2996 t2.Scale(100.0, 55.0);
2997 gfx::Transform t3;
2998 t3.Translate(110.0, -110.0);
2999 transform.ConcatTransform(t2);
3000 transform.ConcatTransform(t3);
3001
3002 // convert to a 3x3 matrix
3003 const SkMatrix& matrix = SkMatrix(transform.matrix());
3004
3005 EXPECT_EQ(210, matrix.getTranslateX());
3006 EXPECT_EQ(-55, matrix.getTranslateY());
3007 EXPECT_EQ(100, matrix.getScaleX());
3008 EXPECT_EQ(55, matrix.getScaleY());
3009 EXPECT_EQ(0, matrix.getSkewX());
3010 EXPECT_EQ(0, matrix.getSkewY());
3011 }
3012
3013 // Conversions from child->top and top->child.
3014 {
3015 gfx::Point point(5, 5);
3016 View::ConvertPointToTarget(child, &top_view, &point);
3017 EXPECT_EQ(22, point.x());
3018 EXPECT_EQ(39, point.y());
3019
3020 gfx::RectF rect(5.0f, 5.0f, 10.0f, 20.0f);
3021 View::ConvertRectToTarget(child, &top_view, &rect);
3022 EXPECT_FLOAT_EQ(22.0f, rect.x());
3023 EXPECT_FLOAT_EQ(39.0f, rect.y());
3024 EXPECT_FLOAT_EQ(30.0f, rect.width());
3025 EXPECT_FLOAT_EQ(80.0f, rect.height());
3026
3027 point.SetPoint(22, 39);
3028 View::ConvertPointToTarget(&top_view, child, &point);
3029 EXPECT_EQ(5, point.x());
3030 EXPECT_EQ(5, point.y());
3031
3032 rect.SetRect(22.0f, 39.0f, 30.0f, 80.0f);
3033 View::ConvertRectToTarget(&top_view, child, &rect);
3034 EXPECT_FLOAT_EQ(5.0f, rect.x());
3035 EXPECT_FLOAT_EQ(5.0f, rect.y());
3036 EXPECT_FLOAT_EQ(10.0f, rect.width());
3037 EXPECT_FLOAT_EQ(20.0f, rect.height());
3038 }
3039
3040 // Conversions from child_child->top and top->child_child.
3041 {
3042 gfx::Point point(5, 5);
3043 View::ConvertPointToTarget(child_child, &top_view, &point);
3044 EXPECT_EQ(133, point.x());
3045 EXPECT_EQ(211, point.y());
3046
3047 gfx::RectF rect(5.0f, 5.0f, 10.0f, 20.0f);
3048 View::ConvertRectToTarget(child_child, &top_view, &rect);
3049 EXPECT_FLOAT_EQ(133.0f, rect.x());
3050 EXPECT_FLOAT_EQ(211.0f, rect.y());
3051 EXPECT_FLOAT_EQ(150.0f, rect.width());
3052 EXPECT_FLOAT_EQ(560.0f, rect.height());
3053
3054 point.SetPoint(133, 211);
3055 View::ConvertPointToTarget(&top_view, child_child, &point);
3056 EXPECT_EQ(5, point.x());
3057 EXPECT_EQ(5, point.y());
3058
3059 rect.SetRect(133.0f, 211.0f, 150.0f, 560.0f);
3060 View::ConvertRectToTarget(&top_view, child_child, &rect);
3061 EXPECT_FLOAT_EQ(5.0f, rect.x());
3062 EXPECT_FLOAT_EQ(5.0f, rect.y());
3063 EXPECT_FLOAT_EQ(10.0f, rect.width());
3064 EXPECT_FLOAT_EQ(20.0f, rect.height());
3065 }
3066
3067 // Conversions from child_child->child and child->child_child
3068 {
3069 gfx::Point point(5, 5);
3070 View::ConvertPointToTarget(child_child, child, &point);
3071 EXPECT_EQ(42, point.x());
3072 EXPECT_EQ(48, point.y());
3073
3074 gfx::RectF rect(5.0f, 5.0f, 10.0f, 20.0f);
3075 View::ConvertRectToTarget(child_child, child, &rect);
3076 EXPECT_FLOAT_EQ(42.0f, rect.x());
3077 EXPECT_FLOAT_EQ(48.0f, rect.y());
3078 EXPECT_FLOAT_EQ(50.0f, rect.width());
3079 EXPECT_FLOAT_EQ(140.0f, rect.height());
3080
3081 point.SetPoint(42, 48);
3082 View::ConvertPointToTarget(child, child_child, &point);
3083 EXPECT_EQ(5, point.x());
3084 EXPECT_EQ(5, point.y());
3085
3086 rect.SetRect(42.0f, 48.0f, 50.0f, 140.0f);
3087 View::ConvertRectToTarget(child, child_child, &rect);
3088 EXPECT_FLOAT_EQ(5.0f, rect.x());
3089 EXPECT_FLOAT_EQ(5.0f, rect.y());
3090 EXPECT_FLOAT_EQ(10.0f, rect.width());
3091 EXPECT_FLOAT_EQ(20.0f, rect.height());
3092 }
3093
3094 // Conversions from top_view to child with a value that should be negative.
3095 // This ensures we don't round up with negative numbers.
3096 {
3097 gfx::Point point(6, 18);
3098 View::ConvertPointToTarget(&top_view, child, &point);
3099 EXPECT_EQ(-1, point.x());
3100 EXPECT_EQ(-1, point.y());
3101
3102 float error = 0.01f;
3103 gfx::RectF rect(6.0f, 18.0f, 10.0f, 39.0f);
3104 View::ConvertRectToTarget(&top_view, child, &rect);
3105 EXPECT_NEAR(-0.33f, rect.x(), error);
3106 EXPECT_NEAR(-0.25f, rect.y(), error);
3107 EXPECT_NEAR(3.33f, rect.width(), error);
3108 EXPECT_NEAR(9.75f, rect.height(), error);
3109 }
3110
3111 // Rect conversions from top_view->child_2 and child_2->top_view.
3112 {
3113 gfx::RectF rect(50.0f, 55.0f, 20.0f, 30.0f);
3114 View::ConvertRectToTarget(child_2, &top_view, &rect);
3115 EXPECT_FLOAT_EQ(615.0f, rect.x());
3116 EXPECT_FLOAT_EQ(775.0f, rect.y());
3117 EXPECT_FLOAT_EQ(30.0f, rect.width());
3118 EXPECT_FLOAT_EQ(20.0f, rect.height());
3119
3120 rect.SetRect(615.0f, 775.0f, 30.0f, 20.0f);
3121 View::ConvertRectToTarget(&top_view, child_2, &rect);
3122 EXPECT_FLOAT_EQ(50.0f, rect.x());
3123 EXPECT_FLOAT_EQ(55.0f, rect.y());
3124 EXPECT_FLOAT_EQ(20.0f, rect.width());
3125 EXPECT_FLOAT_EQ(30.0f, rect.height());
3126 }
3127 }
3128
3129 // Tests conversion methods to and from screen coordinates.
TEST_F(ViewTest,ConversionsToFromScreen)3130 TEST_F(ViewTest, ConversionsToFromScreen) {
3131 std::unique_ptr<Widget> widget(new Widget);
3132 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
3133 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
3134 params.bounds = gfx::Rect(50, 50, 650, 650);
3135 widget->Init(std::move(params));
3136
3137 View* child = new View;
3138 widget->GetRootView()->AddChildView(child);
3139 child->SetBounds(10, 10, 100, 200);
3140 gfx::Transform t;
3141 t.Scale(0.5, 0.5);
3142 child->SetTransform(t);
3143
3144 gfx::Size size(10, 10);
3145 gfx::Point point_in_screen(100, 90);
3146 gfx::Point point_in_child(80, 60);
3147 gfx::Rect rect_in_screen(point_in_screen, size);
3148 gfx::Rect rect_in_child(point_in_child, size);
3149
3150 gfx::Point point = point_in_screen;
3151 View::ConvertPointFromScreen(child, &point);
3152 EXPECT_EQ(point_in_child.ToString(), point.ToString());
3153
3154 View::ConvertPointToScreen(child, &point);
3155 EXPECT_EQ(point_in_screen.ToString(), point.ToString());
3156
3157 View::ConvertRectToScreen(child, &rect_in_child);
3158 EXPECT_EQ(rect_in_screen.ToString(), rect_in_child.ToString());
3159 }
3160
3161 // Tests conversion methods for rectangles.
TEST_F(ViewTest,ConvertRectWithTransform)3162 TEST_F(ViewTest, ConvertRectWithTransform) {
3163 std::unique_ptr<Widget> widget(new Widget);
3164 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
3165 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
3166 params.bounds = gfx::Rect(50, 50, 650, 650);
3167 widget->Init(std::move(params));
3168 View* root = widget->GetRootView();
3169
3170 TestView* v1 = new TestView;
3171 TestView* v2 = new TestView;
3172 root->AddChildView(v1);
3173 v1->AddChildView(v2);
3174
3175 v1->SetBoundsRect(gfx::Rect(10, 10, 500, 500));
3176 v2->SetBoundsRect(gfx::Rect(20, 20, 100, 200));
3177
3178 // |v2| now occupies (30, 30) to (130, 230) in |widget|
3179 gfx::Rect rect(5, 5, 15, 40);
3180 EXPECT_EQ(gfx::Rect(25, 25, 15, 40), v2->ConvertRectToParent(rect));
3181 EXPECT_EQ(gfx::Rect(35, 35, 15, 40), v2->ConvertRectToWidget(rect));
3182
3183 // Rotate |v2|
3184 gfx::Transform t2;
3185 RotateCounterclockwise(&t2);
3186 t2.matrix().set(1, 3, 100.f);
3187 v2->SetTransform(t2);
3188
3189 // |v2| now occupies (30, 30) to (230, 130) in |widget|
3190 EXPECT_EQ(gfx::Rect(25, 100, 40, 15), v2->ConvertRectToParent(rect));
3191 EXPECT_EQ(gfx::Rect(35, 110, 40, 15), v2->ConvertRectToWidget(rect));
3192
3193 // Scale down |v1|
3194 gfx::Transform t1;
3195 t1.Scale(0.5, 0.5);
3196 v1->SetTransform(t1);
3197
3198 // The rectangle should remain the same for |v1|.
3199 EXPECT_EQ(gfx::Rect(25, 100, 40, 15), v2->ConvertRectToParent(rect));
3200
3201 // |v2| now occupies (20, 20) to (120, 70) in |widget|
3202 EXPECT_EQ(gfx::Rect(22, 60, 21, 8).ToString(),
3203 v2->ConvertRectToWidget(rect).ToString());
3204
3205 widget->CloseNow();
3206 }
3207
3208 class ObserverView : public View {
3209 public:
3210 ObserverView();
3211 ~ObserverView() override;
3212
3213 void ResetTestState();
3214
has_add_details() const3215 bool has_add_details() const { return has_add_details_; }
has_remove_details() const3216 bool has_remove_details() const { return has_remove_details_; }
3217
add_details() const3218 const ViewHierarchyChangedDetails& add_details() const {
3219 return add_details_;
3220 }
3221
remove_details() const3222 const ViewHierarchyChangedDetails& remove_details() const {
3223 return remove_details_;
3224 }
3225
3226 private:
3227 // View:
3228 void ViewHierarchyChanged(
3229 const ViewHierarchyChangedDetails& details) override;
3230
3231 bool has_add_details_ = false;
3232 bool has_remove_details_ = false;
3233 ViewHierarchyChangedDetails add_details_;
3234 ViewHierarchyChangedDetails remove_details_;
3235
3236 DISALLOW_COPY_AND_ASSIGN(ObserverView);
3237 };
3238
3239 ObserverView::ObserverView() = default;
3240
3241 ObserverView::~ObserverView() = default;
3242
ResetTestState()3243 void ObserverView::ResetTestState() {
3244 has_add_details_ = false;
3245 has_remove_details_ = false;
3246 add_details_ = ViewHierarchyChangedDetails();
3247 remove_details_ = ViewHierarchyChangedDetails();
3248 }
3249
ViewHierarchyChanged(const ViewHierarchyChangedDetails & details)3250 void ObserverView::ViewHierarchyChanged(
3251 const ViewHierarchyChangedDetails& details) {
3252 if (details.is_add) {
3253 has_add_details_ = true;
3254 add_details_ = details;
3255 } else {
3256 has_remove_details_ = true;
3257 remove_details_ = details;
3258 }
3259 }
3260
3261 // Verifies that the ViewHierarchyChanged() notification is sent correctly when
3262 // a child view is added or removed to all the views in the hierarchy (up and
3263 // down).
3264 // The tree looks like this:
3265 // v1
3266 // +-- v2
3267 // +-- v3
3268 // +-- v4 (starts here, then get reparented to v1)
TEST_F(ViewTest,ViewHierarchyChanged)3269 TEST_F(ViewTest, ViewHierarchyChanged) {
3270 ObserverView v1;
3271
3272 ObserverView* v3 = new ObserverView();
3273
3274 // Add |v3| to |v2|.
3275 std::unique_ptr<ObserverView> v2(new ObserverView());
3276 v2->AddChildView(v3);
3277
3278 // Make sure both |v2| and |v3| receive the ViewHierarchyChanged()
3279 // notification.
3280 EXPECT_TRUE(v2->has_add_details());
3281 EXPECT_FALSE(v2->has_remove_details());
3282 EXPECT_EQ(v2.get(), v2->add_details().parent);
3283 EXPECT_EQ(v3, v2->add_details().child);
3284 EXPECT_EQ(nullptr, v2->add_details().move_view);
3285
3286 EXPECT_TRUE(v3->has_add_details());
3287 EXPECT_FALSE(v3->has_remove_details());
3288 EXPECT_EQ(v2.get(), v3->add_details().parent);
3289 EXPECT_EQ(v3, v3->add_details().child);
3290 EXPECT_EQ(nullptr, v3->add_details().move_view);
3291
3292 // Reset everything to the initial state.
3293 v2->ResetTestState();
3294 v3->ResetTestState();
3295
3296 // Add |v2| to v1.
3297 v1.AddChildView(v2.get());
3298
3299 // Verifies that |v2| is the child view *added* and the parent view is |v1|.
3300 // Make sure all the views (v1, v2, v3) received _that_ information.
3301 EXPECT_TRUE(v1.has_add_details());
3302 EXPECT_FALSE(v1.has_remove_details());
3303 EXPECT_EQ(&v1, v1.add_details().parent);
3304 EXPECT_EQ(v2.get(), v1.add_details().child);
3305 EXPECT_EQ(nullptr, v1.add_details().move_view);
3306
3307 EXPECT_TRUE(v2->has_add_details());
3308 EXPECT_FALSE(v2->has_remove_details());
3309 EXPECT_EQ(&v1, v2->add_details().parent);
3310 EXPECT_EQ(v2.get(), v2->add_details().child);
3311 EXPECT_EQ(nullptr, v2->add_details().move_view);
3312
3313 EXPECT_TRUE(v3->has_add_details());
3314 EXPECT_FALSE(v3->has_remove_details());
3315 EXPECT_EQ(&v1, v3->add_details().parent);
3316 EXPECT_EQ(v2.get(), v3->add_details().child);
3317 EXPECT_EQ(nullptr, v3->add_details().move_view);
3318
3319 // Reset everything to the initial state.
3320 v1.ResetTestState();
3321 v2->ResetTestState();
3322 v3->ResetTestState();
3323
3324 // Remove |v2| from |v1|.
3325 v1.RemoveChildView(v2.get());
3326
3327 // Verifies that |v2| is the child view *removed* and the parent view is |v1|.
3328 // Make sure all the views (v1, v2, v3) received _that_ information.
3329 EXPECT_FALSE(v1.has_add_details());
3330 EXPECT_TRUE(v1.has_remove_details());
3331 EXPECT_EQ(&v1, v1.remove_details().parent);
3332 EXPECT_EQ(v2.get(), v1.remove_details().child);
3333 EXPECT_EQ(nullptr, v1.remove_details().move_view);
3334
3335 EXPECT_FALSE(v2->has_add_details());
3336 EXPECT_TRUE(v2->has_remove_details());
3337 EXPECT_EQ(&v1, v2->remove_details().parent);
3338 EXPECT_EQ(v2.get(), v2->remove_details().child);
3339 EXPECT_EQ(nullptr, v2->remove_details().move_view);
3340
3341 EXPECT_FALSE(v3->has_add_details());
3342 EXPECT_TRUE(v3->has_remove_details());
3343 EXPECT_EQ(&v1, v3->remove_details().parent);
3344 EXPECT_EQ(v3, v3->remove_details().child);
3345 EXPECT_EQ(nullptr, v3->remove_details().move_view);
3346
3347 // Verifies notifications when reparenting a view.
3348 ObserverView* v4 = new ObserverView();
3349 // Add |v4| to |v2|.
3350 v2->AddChildView(v4);
3351
3352 // Reset everything to the initial state.
3353 v1.ResetTestState();
3354 v2->ResetTestState();
3355 v3->ResetTestState();
3356 v4->ResetTestState();
3357
3358 // Reparent |v4| to |v1|.
3359 v1.AddChildView(v4);
3360
3361 // Verifies that all views receive the correct information for all the child,
3362 // parent and move views.
3363
3364 // |v1| is the new parent, |v4| is the child for add, |v2| is the old parent.
3365 EXPECT_TRUE(v1.has_add_details());
3366 EXPECT_FALSE(v1.has_remove_details());
3367 EXPECT_EQ(&v1, v1.add_details().parent);
3368 EXPECT_EQ(v4, v1.add_details().child);
3369 EXPECT_EQ(v2.get(), v1.add_details().move_view);
3370
3371 // |v2| is the old parent, |v4| is the child for remove, |v1| is the new
3372 // parent.
3373 EXPECT_FALSE(v2->has_add_details());
3374 EXPECT_TRUE(v2->has_remove_details());
3375 EXPECT_EQ(v2.get(), v2->remove_details().parent);
3376 EXPECT_EQ(v4, v2->remove_details().child);
3377 EXPECT_EQ(&v1, v2->remove_details().move_view);
3378
3379 // |v3| is not impacted by this operation, and hence receives no notification.
3380 EXPECT_FALSE(v3->has_add_details());
3381 EXPECT_FALSE(v3->has_remove_details());
3382
3383 // |v4| is the reparented child, so it receives notifications for the remove
3384 // and then the add. |v2| is its old parent, |v1| is its new parent.
3385 EXPECT_TRUE(v4->has_remove_details());
3386 EXPECT_TRUE(v4->has_add_details());
3387 EXPECT_EQ(v2.get(), v4->remove_details().parent);
3388 EXPECT_EQ(&v1, v4->add_details().parent);
3389 EXPECT_EQ(v4, v4->add_details().child);
3390 EXPECT_EQ(v4, v4->remove_details().child);
3391 EXPECT_EQ(&v1, v4->remove_details().move_view);
3392 EXPECT_EQ(v2.get(), v4->add_details().move_view);
3393 }
3394
3395 class WidgetObserverView : public View {
3396 public:
3397 WidgetObserverView();
3398 ~WidgetObserverView() override;
3399
3400 void ResetTestState();
3401
added_to_widget_count()3402 int added_to_widget_count() { return added_to_widget_count_; }
removed_from_widget_count()3403 int removed_from_widget_count() { return removed_from_widget_count_; }
3404
3405 private:
3406 void AddedToWidget() override;
3407 void RemovedFromWidget() override;
3408
3409 int added_to_widget_count_ = 0;
3410 int removed_from_widget_count_ = 0;
3411
3412 DISALLOW_COPY_AND_ASSIGN(WidgetObserverView);
3413 };
3414
WidgetObserverView()3415 WidgetObserverView::WidgetObserverView() {
3416 ResetTestState();
3417 }
3418
3419 WidgetObserverView::~WidgetObserverView() = default;
3420
ResetTestState()3421 void WidgetObserverView::ResetTestState() {
3422 added_to_widget_count_ = 0;
3423 removed_from_widget_count_ = 0;
3424 }
3425
AddedToWidget()3426 void WidgetObserverView::AddedToWidget() {
3427 ++added_to_widget_count_;
3428 }
3429
RemovedFromWidget()3430 void WidgetObserverView::RemovedFromWidget() {
3431 ++removed_from_widget_count_;
3432 }
3433
3434 // Verifies that AddedToWidget and RemovedFromWidget are called for a view when
3435 // it is added to hierarchy.
3436 // The tree looks like this:
3437 // widget
3438 // +-- root
3439 //
3440 // then v1 is added to root:
3441 //
3442 // v1
3443 // +-- v2
3444 //
3445 // finally v1 is removed from root.
TEST_F(ViewTest,AddedToRemovedFromWidget)3446 TEST_F(ViewTest, AddedToRemovedFromWidget) {
3447 Widget widget;
3448 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
3449 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
3450 params.bounds = gfx::Rect(50, 50, 650, 650);
3451 widget.Init(std::move(params));
3452
3453 View* root = widget.GetRootView();
3454
3455 auto v1 = std::make_unique<WidgetObserverView>();
3456 auto v2 = std::make_unique<WidgetObserverView>();
3457 auto v3 = std::make_unique<WidgetObserverView>();
3458
3459 auto* v2_ptr = v1->AddChildView(std::move(v2));
3460 EXPECT_EQ(0, v2_ptr->added_to_widget_count());
3461 EXPECT_EQ(0, v2_ptr->removed_from_widget_count());
3462
3463 auto* v1_ptr = root->AddChildView(std::move(v1));
3464 EXPECT_EQ(1, v1_ptr->added_to_widget_count());
3465 EXPECT_EQ(0, v1_ptr->removed_from_widget_count());
3466 EXPECT_EQ(1, v2_ptr->added_to_widget_count());
3467 EXPECT_EQ(0, v2_ptr->removed_from_widget_count());
3468
3469 v1_ptr->ResetTestState();
3470 v2_ptr->ResetTestState();
3471
3472 auto* v3_ptr = v2_ptr->AddChildView(std::move(v3));
3473 EXPECT_EQ(0, v1_ptr->added_to_widget_count());
3474 EXPECT_EQ(0, v1_ptr->removed_from_widget_count());
3475 EXPECT_EQ(0, v2_ptr->added_to_widget_count());
3476 EXPECT_EQ(0, v2_ptr->removed_from_widget_count());
3477
3478 v1_ptr->ResetTestState();
3479 v2_ptr->ResetTestState();
3480
3481 v1 = root->RemoveChildViewT(v1_ptr);
3482 EXPECT_EQ(0, v1->added_to_widget_count());
3483 EXPECT_EQ(1, v1->removed_from_widget_count());
3484 EXPECT_EQ(0, v2_ptr->added_to_widget_count());
3485 EXPECT_EQ(1, v2_ptr->removed_from_widget_count());
3486
3487 v2_ptr->ResetTestState();
3488 v2 = v1->RemoveChildViewT(v2_ptr);
3489 EXPECT_EQ(0, v2->removed_from_widget_count());
3490
3491 // Test move between parents in a single Widget.
3492 v3 = v2->RemoveChildViewT(v3_ptr);
3493 v1->ResetTestState();
3494 v2->ResetTestState();
3495 v3->ResetTestState();
3496
3497 v2_ptr = v1->AddChildView(std::move(v2));
3498 v1_ptr = root->AddChildView(std::move(v1));
3499 v3_ptr = root->AddChildView(std::move(v3));
3500 EXPECT_EQ(1, v1_ptr->added_to_widget_count());
3501 EXPECT_EQ(1, v2_ptr->added_to_widget_count());
3502 EXPECT_EQ(1, v3_ptr->added_to_widget_count());
3503
3504 // This should not invoke added or removed to/from the widget.
3505 v1_ptr = v3_ptr->AddChildView(v1_ptr);
3506 EXPECT_EQ(1, v1_ptr->added_to_widget_count());
3507 EXPECT_EQ(0, v1_ptr->removed_from_widget_count());
3508 EXPECT_EQ(1, v2_ptr->added_to_widget_count());
3509 EXPECT_EQ(0, v2_ptr->removed_from_widget_count());
3510 EXPECT_EQ(1, v3_ptr->added_to_widget_count());
3511 EXPECT_EQ(0, v3_ptr->removed_from_widget_count());
3512
3513 // Test move between widgets.
3514 Widget second_widget;
3515 params.bounds = gfx::Rect(150, 150, 650, 650);
3516 second_widget.Init(std::move(params));
3517
3518 View* second_root = second_widget.GetRootView();
3519
3520 v1_ptr->ResetTestState();
3521 v2_ptr->ResetTestState();
3522 v3_ptr->ResetTestState();
3523
3524 v1_ptr =
3525 second_root->AddChildView(v1_ptr->parent()->RemoveChildViewT(v1_ptr));
3526 EXPECT_EQ(1, v1_ptr->removed_from_widget_count());
3527 EXPECT_EQ(1, v1_ptr->added_to_widget_count());
3528 EXPECT_EQ(1, v2_ptr->added_to_widget_count());
3529 EXPECT_EQ(1, v2_ptr->removed_from_widget_count());
3530 EXPECT_EQ(0, v3_ptr->added_to_widget_count());
3531 EXPECT_EQ(0, v3_ptr->removed_from_widget_count());
3532 }
3533
3534 // Verifies if the child views added under the root are all deleted when calling
3535 // RemoveAllChildViews.
3536 // The tree looks like this:
3537 // root
3538 // +-- child1
3539 // +-- foo
3540 // +-- bar0
3541 // +-- bar1
3542 // +-- bar2
3543 // +-- child2
3544 // +-- child3
TEST_F(ViewTest,RemoveAllChildViews)3545 TEST_F(ViewTest, RemoveAllChildViews) {
3546 View root;
3547
3548 View* child1 = root.AddChildView(std::make_unique<View>());
3549
3550 for (size_t i = 0; i < 2; ++i)
3551 root.AddChildView(std::make_unique<View>());
3552
3553 View* foo = child1->AddChildView(std::make_unique<View>());
3554
3555 // Add some nodes to |foo|.
3556 for (size_t i = 0; i < 3; ++i)
3557 foo->AddChildView(std::make_unique<View>());
3558
3559 EXPECT_EQ(3u, root.children().size());
3560 EXPECT_EQ(1u, child1->children().size());
3561 EXPECT_EQ(3u, foo->children().size());
3562
3563 // Now remove all child views from root.
3564 root.RemoveAllChildViews(true);
3565
3566 EXPECT_TRUE(root.children().empty());
3567 }
3568
TEST_F(ViewTest,Contains)3569 TEST_F(ViewTest, Contains) {
3570 auto v1 = std::make_unique<View>();
3571
3572 auto* v2 = v1->AddChildView(std::make_unique<View>());
3573 auto* v3 = v2->AddChildView(std::make_unique<View>());
3574
3575 EXPECT_FALSE(v1->Contains(nullptr));
3576 EXPECT_TRUE(v1->Contains(v1.get()));
3577 EXPECT_TRUE(v1->Contains(v2));
3578 EXPECT_TRUE(v1->Contains(v3));
3579
3580 EXPECT_FALSE(v2->Contains(nullptr));
3581 EXPECT_TRUE(v2->Contains(v2));
3582 EXPECT_FALSE(v2->Contains(v1.get()));
3583 EXPECT_TRUE(v2->Contains(v3));
3584
3585 EXPECT_FALSE(v3->Contains(nullptr));
3586 EXPECT_TRUE(v3->Contains(v3));
3587 EXPECT_FALSE(v3->Contains(v1.get()));
3588 EXPECT_FALSE(v3->Contains(v2));
3589 }
3590
3591 // Verifies if GetIndexOf() returns the correct index for the specified child
3592 // view.
3593 // The tree looks like this:
3594 // root
3595 // +-- child1
3596 // +-- foo1
3597 // +-- child2
TEST_F(ViewTest,GetIndexOf)3598 TEST_F(ViewTest, GetIndexOf) {
3599 auto root = std::make_unique<View>();
3600
3601 auto* child1 = root->AddChildView(std::make_unique<View>());
3602
3603 auto* child2 = root->AddChildView(std::make_unique<View>());
3604
3605 auto* foo1 = child1->AddChildView(std::make_unique<View>());
3606
3607 EXPECT_EQ(-1, root->GetIndexOf(nullptr));
3608 EXPECT_EQ(-1, root->GetIndexOf(root.get()));
3609 EXPECT_EQ(0, root->GetIndexOf(child1));
3610 EXPECT_EQ(1, root->GetIndexOf(child2));
3611 EXPECT_EQ(-1, root->GetIndexOf(foo1));
3612
3613 EXPECT_EQ(-1, child1->GetIndexOf(nullptr));
3614 EXPECT_EQ(-1, child1->GetIndexOf(root.get()));
3615 EXPECT_EQ(-1, child1->GetIndexOf(child1));
3616 EXPECT_EQ(-1, child1->GetIndexOf(child2));
3617 EXPECT_EQ(0, child1->GetIndexOf(foo1));
3618
3619 EXPECT_EQ(-1, child2->GetIndexOf(nullptr));
3620 EXPECT_EQ(-1, child2->GetIndexOf(root.get()));
3621 EXPECT_EQ(-1, child2->GetIndexOf(child2));
3622 EXPECT_EQ(-1, child2->GetIndexOf(child1));
3623 EXPECT_EQ(-1, child2->GetIndexOf(foo1));
3624 }
3625
3626 // Verifies that the child views can be reordered correctly.
TEST_F(ViewTest,ReorderChildren)3627 TEST_F(ViewTest, ReorderChildren) {
3628 auto root = std::make_unique<View>();
3629
3630 auto* child = root->AddChildView(std::make_unique<View>());
3631
3632 auto* foo1 = child->AddChildView(std::make_unique<View>());
3633 View* foo2 = child->AddChildView(std::make_unique<View>());
3634 View* foo3 = child->AddChildView(std::make_unique<View>());
3635 foo1->SetFocusBehavior(View::FocusBehavior::ALWAYS);
3636 foo2->SetFocusBehavior(View::FocusBehavior::ALWAYS);
3637 foo3->SetFocusBehavior(View::FocusBehavior::ALWAYS);
3638
3639 ASSERT_EQ(0, child->GetIndexOf(foo1));
3640 ASSERT_EQ(1, child->GetIndexOf(foo2));
3641 ASSERT_EQ(2, child->GetIndexOf(foo3));
3642 ASSERT_EQ(foo2, foo1->GetNextFocusableView());
3643 ASSERT_EQ(foo3, foo2->GetNextFocusableView());
3644 ASSERT_EQ(nullptr, foo3->GetNextFocusableView());
3645
3646 // Move |foo2| at the end.
3647 child->ReorderChildView(foo2, -1);
3648 ASSERT_EQ(0, child->GetIndexOf(foo1));
3649 ASSERT_EQ(1, child->GetIndexOf(foo3));
3650 ASSERT_EQ(2, child->GetIndexOf(foo2));
3651 ASSERT_EQ(foo3, foo1->GetNextFocusableView());
3652 ASSERT_EQ(foo2, foo3->GetNextFocusableView());
3653 ASSERT_EQ(nullptr, foo2->GetNextFocusableView());
3654
3655 // Move |foo1| at the end.
3656 child->ReorderChildView(foo1, -1);
3657 ASSERT_EQ(0, child->GetIndexOf(foo3));
3658 ASSERT_EQ(1, child->GetIndexOf(foo2));
3659 ASSERT_EQ(2, child->GetIndexOf(foo1));
3660 ASSERT_EQ(nullptr, foo1->GetNextFocusableView());
3661 ASSERT_EQ(foo2, foo1->GetPreviousFocusableView());
3662 ASSERT_EQ(foo2, foo3->GetNextFocusableView());
3663 ASSERT_EQ(foo1, foo2->GetNextFocusableView());
3664
3665 // Move |foo2| to the front.
3666 child->ReorderChildView(foo2, 0);
3667 ASSERT_EQ(0, child->GetIndexOf(foo2));
3668 ASSERT_EQ(1, child->GetIndexOf(foo3));
3669 ASSERT_EQ(2, child->GetIndexOf(foo1));
3670 ASSERT_EQ(nullptr, foo1->GetNextFocusableView());
3671 ASSERT_EQ(foo3, foo1->GetPreviousFocusableView());
3672 ASSERT_EQ(foo3, foo2->GetNextFocusableView());
3673 ASSERT_EQ(foo1, foo3->GetNextFocusableView());
3674 }
3675
3676 // Verifies that GetViewByID returns the correctly child view from the specified
3677 // ID.
3678 // The tree looks like this:
3679 // v1
3680 // +-- v2
3681 // +-- v3
3682 // +-- v4
TEST_F(ViewTest,GetViewByID)3683 TEST_F(ViewTest, GetViewByID) {
3684 View v1;
3685 const int kV1ID = 1;
3686 v1.SetID(kV1ID);
3687
3688 View v2;
3689 const int kV2ID = 2;
3690 v2.SetID(kV2ID);
3691
3692 View v3;
3693 const int kV3ID = 3;
3694 v3.SetID(kV3ID);
3695
3696 View v4;
3697 const int kV4ID = 4;
3698 v4.SetID(kV4ID);
3699
3700 const int kV5ID = 5;
3701
3702 v1.AddChildView(&v2);
3703 v2.AddChildView(&v3);
3704 v2.AddChildView(&v4);
3705
3706 EXPECT_EQ(&v1, v1.GetViewByID(kV1ID));
3707 EXPECT_EQ(&v2, v1.GetViewByID(kV2ID));
3708 EXPECT_EQ(&v4, v1.GetViewByID(kV4ID));
3709
3710 EXPECT_EQ(nullptr, v1.GetViewByID(kV5ID)); // No V5 exists.
3711 EXPECT_EQ(nullptr,
3712 v2.GetViewByID(kV1ID)); // It can get only from child views.
3713
3714 const int kGroup = 1;
3715 v3.SetGroup(kGroup);
3716 v4.SetGroup(kGroup);
3717
3718 View::Views views;
3719 v1.GetViewsInGroup(kGroup, &views);
3720 EXPECT_EQ(2U, views.size());
3721 EXPECT_TRUE(base::Contains(views, &v3));
3722 EXPECT_TRUE(base::Contains(views, &v4));
3723 }
3724
TEST_F(ViewTest,AddExistingChild)3725 TEST_F(ViewTest, AddExistingChild) {
3726 View v1, v2, v3;
3727
3728 v1.AddChildView(&v2);
3729 v1.AddChildView(&v3);
3730 EXPECT_EQ(0, v1.GetIndexOf(&v2));
3731 EXPECT_EQ(1, v1.GetIndexOf(&v3));
3732
3733 // Check that there's no change in order when adding at same index.
3734 v1.AddChildViewAt(&v2, 0);
3735 EXPECT_EQ(0, v1.GetIndexOf(&v2));
3736 EXPECT_EQ(1, v1.GetIndexOf(&v3));
3737 v1.AddChildViewAt(&v3, 1);
3738 EXPECT_EQ(0, v1.GetIndexOf(&v2));
3739 EXPECT_EQ(1, v1.GetIndexOf(&v3));
3740
3741 // Add it at a different index and check for change in order.
3742 v1.AddChildViewAt(&v2, 1);
3743 EXPECT_EQ(1, v1.GetIndexOf(&v2));
3744 EXPECT_EQ(0, v1.GetIndexOf(&v3));
3745 v1.AddChildViewAt(&v2, 0);
3746 EXPECT_EQ(0, v1.GetIndexOf(&v2));
3747 EXPECT_EQ(1, v1.GetIndexOf(&v3));
3748
3749 // Check that calling AddChildView() moves to the end.
3750 v1.AddChildView(&v2);
3751 EXPECT_EQ(1, v1.GetIndexOf(&v2));
3752 EXPECT_EQ(0, v1.GetIndexOf(&v3));
3753 v1.AddChildView(&v3);
3754 EXPECT_EQ(0, v1.GetIndexOf(&v2));
3755 EXPECT_EQ(1, v1.GetIndexOf(&v3));
3756 }
3757
3758 ////////////////////////////////////////////////////////////////////////////////
3759 // FocusManager
3760 ////////////////////////////////////////////////////////////////////////////////
3761
3762 // A widget that always claims to be active, regardless of its real activation
3763 // status.
3764 class ActiveWidget : public Widget {
3765 public:
3766 ActiveWidget() = default;
3767 ~ActiveWidget() override = default;
3768
IsActive() const3769 bool IsActive() const override { return true; }
3770
3771 private:
3772 DISALLOW_COPY_AND_ASSIGN(ActiveWidget);
3773 };
3774
TEST_F(ViewTest,AdvanceFocusIfNecessaryForUnfocusableView)3775 TEST_F(ViewTest, AdvanceFocusIfNecessaryForUnfocusableView) {
3776 // Create a widget with two views and give the first one focus.
3777 ActiveWidget widget;
3778 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
3779 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
3780 widget.Init(std::move(params));
3781
3782 View* view1 = widget.GetRootView()->AddChildView(std::make_unique<View>());
3783 view1->SetFocusBehavior(View::FocusBehavior::ALWAYS);
3784
3785 View* view2 = widget.GetRootView()->AddChildView(std::make_unique<View>());
3786 view2->SetFocusBehavior(View::FocusBehavior::ALWAYS);
3787
3788 FocusManager* focus_manager = widget.GetFocusManager();
3789 ASSERT_TRUE(focus_manager);
3790
3791 focus_manager->SetFocusedView(view1);
3792 EXPECT_EQ(view1, focus_manager->GetFocusedView());
3793
3794 // Disable the focused view and check if the next view gets focused.
3795 view1->SetEnabled(false);
3796 EXPECT_EQ(view2, focus_manager->GetFocusedView());
3797
3798 // Re-enable and re-focus.
3799 view1->SetEnabled(true);
3800 focus_manager->SetFocusedView(view1);
3801 EXPECT_EQ(view1, focus_manager->GetFocusedView());
3802
3803 // Hide the focused view and check it the next view gets focused.
3804 view1->SetVisible(false);
3805 EXPECT_EQ(view2, focus_manager->GetFocusedView());
3806
3807 // Re-show and re-focus.
3808 view1->SetVisible(true);
3809 focus_manager->SetFocusedView(view1);
3810 EXPECT_EQ(view1, focus_manager->GetFocusedView());
3811
3812 // Set the focused view as not focusable and check if the next view gets
3813 // focused.
3814 view1->SetFocusBehavior(View::FocusBehavior::NEVER);
3815 EXPECT_EQ(view2, focus_manager->GetFocusedView());
3816 }
3817
3818 ////////////////////////////////////////////////////////////////////////////////
3819 // Layers
3820 ////////////////////////////////////////////////////////////////////////////////
3821
3822 namespace {
3823
3824 // Test implementation of LayerAnimator.
3825 class TestLayerAnimator : public ui::LayerAnimator {
3826 public:
3827 TestLayerAnimator();
3828
last_bounds() const3829 const gfx::Rect& last_bounds() const { return last_bounds_; }
3830
3831 // LayerAnimator.
3832 void SetBounds(const gfx::Rect& bounds) override;
3833
3834 protected:
3835 ~TestLayerAnimator() override = default;
3836
3837 private:
3838 gfx::Rect last_bounds_;
3839
3840 DISALLOW_COPY_AND_ASSIGN(TestLayerAnimator);
3841 };
3842
TestLayerAnimator()3843 TestLayerAnimator::TestLayerAnimator()
3844 : ui::LayerAnimator(base::TimeDelta::FromMilliseconds(0)) {}
3845
SetBounds(const gfx::Rect & bounds)3846 void TestLayerAnimator::SetBounds(const gfx::Rect& bounds) {
3847 last_bounds_ = bounds;
3848 }
3849
3850 class TestingLayerViewObserver : public ViewObserver {
3851 public:
TestingLayerViewObserver(View * view)3852 explicit TestingLayerViewObserver(View* view) : view_(view) {
3853 view_->AddObserver(this);
3854 }
~TestingLayerViewObserver()3855 ~TestingLayerViewObserver() override { view_->RemoveObserver(this); }
3856
GetLastLayerBoundsAndReset()3857 gfx::Rect GetLastLayerBoundsAndReset() {
3858 gfx::Rect value = last_layer_bounds_;
3859 last_layer_bounds_ = gfx::Rect();
3860 return value;
3861 }
3862
3863 private:
3864 // ViewObserver:
OnLayerTargetBoundsChanged(View * view)3865 void OnLayerTargetBoundsChanged(View* view) override {
3866 last_layer_bounds_ = view->layer()->bounds();
3867 }
3868
3869 gfx::Rect last_layer_bounds_;
3870 View* view_;
3871
3872 DISALLOW_COPY_AND_ASSIGN(TestingLayerViewObserver);
3873 };
3874
3875 } // namespace
3876
3877 class ViewLayerTest : public ViewsTestBase {
3878 public:
3879 ViewLayerTest() = default;
3880
3881 ~ViewLayerTest() override = default;
3882
3883 // Returns the Layer used by the RootView.
GetRootLayer()3884 ui::Layer* GetRootLayer() { return widget()->GetLayer(); }
3885
SetUp()3886 void SetUp() override {
3887 SetUpPixelCanvas();
3888 ViewTest::SetUp();
3889 widget_ = new Widget;
3890 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
3891 params.bounds = gfx::Rect(50, 50, 200, 200);
3892 widget_->Init(std::move(params));
3893 widget_->Show();
3894 widget_->GetRootView()->SetBounds(0, 0, 200, 200);
3895 }
3896
TearDown()3897 void TearDown() override {
3898 widget_->CloseNow();
3899 ViewsTestBase::TearDown();
3900 }
3901
widget()3902 Widget* widget() { return widget_; }
3903
SetUpPixelCanvas()3904 virtual void SetUpPixelCanvas() {
3905 scoped_feature_list_.InitAndDisableFeature(
3906 ::features::kEnablePixelCanvasRecording);
3907 }
3908
3909 protected:
3910 // Accessors to View internals.
SchedulePaintOnParent(View * view)3911 void SchedulePaintOnParent(View* view) { view->SchedulePaintOnParent(); }
3912
3913 private:
3914 Widget* widget_ = nullptr;
3915 base::test::ScopedFeatureList scoped_feature_list_;
3916 };
3917
TEST_F(ViewLayerTest,LayerCreationAndDestruction)3918 TEST_F(ViewLayerTest, LayerCreationAndDestruction) {
3919 View view;
3920 EXPECT_EQ(nullptr, view.layer());
3921
3922 view.SetPaintToLayer();
3923 EXPECT_NE(nullptr, view.layer());
3924
3925 view.DestroyLayer();
3926 EXPECT_EQ(nullptr, view.layer());
3927 }
3928
TEST_F(ViewLayerTest,SetTransformCreatesAndDestroysLayer)3929 TEST_F(ViewLayerTest, SetTransformCreatesAndDestroysLayer) {
3930 View view;
3931 EXPECT_EQ(nullptr, view.layer());
3932
3933 // Set an arbitrary non-identity transform, which should cause a layer to be
3934 // created.
3935 gfx::Transform transform;
3936 transform.Translate(1.0, 1.0);
3937 view.SetTransform(transform);
3938 EXPECT_NE(nullptr, view.layer());
3939
3940 // Set the identity transform, which should destroy the layer.
3941 view.SetTransform(gfx::Transform());
3942 EXPECT_EQ(nullptr, view.layer());
3943 }
3944
3945 // Verify that setting an identity transform after SetPaintToLayer() has been
3946 // called doesn't destroy the layer.
TEST_F(ViewLayerTest,IdentityTransformDoesntOverrideSetPaintToLayer)3947 TEST_F(ViewLayerTest, IdentityTransformDoesntOverrideSetPaintToLayer) {
3948 View view;
3949 EXPECT_EQ(nullptr, view.layer());
3950
3951 view.SetPaintToLayer();
3952 EXPECT_NE(nullptr, view.layer());
3953
3954 gfx::Transform transform;
3955 transform.Translate(1.0, 1.0);
3956 view.SetTransform(transform);
3957 EXPECT_NE(nullptr, view.layer());
3958
3959 view.SetTransform(transform);
3960 EXPECT_NE(nullptr, view.layer());
3961 }
3962
3963 // Verify that calling DestroyLayer() while a non-identity transform is present
3964 // doesn't destroy the layer.
TEST_F(ViewLayerTest,DestroyLayerDoesntOverrideTransform)3965 TEST_F(ViewLayerTest, DestroyLayerDoesntOverrideTransform) {
3966 View view;
3967 EXPECT_EQ(nullptr, view.layer());
3968
3969 view.SetPaintToLayer();
3970 EXPECT_NE(nullptr, view.layer());
3971
3972 gfx::Transform transform;
3973 transform.Translate(1.0, 1.0);
3974 view.SetTransform(transform);
3975 EXPECT_NE(nullptr, view.layer());
3976
3977 view.DestroyLayer();
3978 EXPECT_NE(nullptr, view.layer());
3979 }
3980
TEST_F(ViewLayerTest,LayerToggling)3981 TEST_F(ViewLayerTest, LayerToggling) {
3982 // Because we lazily create textures the calls to DrawTree are necessary to
3983 // ensure we trigger creation of textures.
3984 ui::Layer* root_layer = widget()->GetLayer();
3985 View* content_view = new View;
3986 widget()->SetContentsView(content_view);
3987
3988 // Create v1, give it a bounds and verify everything is set up correctly.
3989 View* v1 = new View;
3990 v1->SetPaintToLayer();
3991 EXPECT_TRUE(v1->layer() != nullptr);
3992 v1->SetBoundsRect(gfx::Rect(20, 30, 140, 150));
3993 content_view->AddChildView(v1);
3994 ASSERT_TRUE(v1->layer() != nullptr);
3995 EXPECT_EQ(root_layer, v1->layer()->parent());
3996 EXPECT_EQ(gfx::Rect(20, 30, 140, 150), v1->layer()->bounds());
3997
3998 // Create v2 as a child of v1 and do basic assertion testing.
3999 View* v2 = new View;
4000 TestingLayerViewObserver v2_observer(v2);
4001 v1->AddChildView(v2);
4002 EXPECT_TRUE(v2->layer() == nullptr);
4003 v2->SetBoundsRect(gfx::Rect(10, 20, 30, 40));
4004 v2->SetPaintToLayer();
4005 ASSERT_TRUE(v2->layer() != nullptr);
4006 EXPECT_EQ(v1->layer(), v2->layer()->parent());
4007 EXPECT_EQ(gfx::Rect(10, 20, 30, 40), v2->layer()->bounds());
4008 EXPECT_EQ(v2->layer()->bounds(), v2_observer.GetLastLayerBoundsAndReset());
4009
4010 // Turn off v1s layer. v2 should still have a layer but its parent should have
4011 // changed.
4012 v1->DestroyLayer();
4013 EXPECT_TRUE(v1->layer() == nullptr);
4014 EXPECT_TRUE(v2->layer() != nullptr);
4015 EXPECT_EQ(root_layer, v2->layer()->parent());
4016 ASSERT_EQ(1u, root_layer->children().size());
4017 EXPECT_EQ(root_layer->children()[0], v2->layer());
4018 // The bounds of the layer should have changed to be relative to the root view
4019 // now.
4020 EXPECT_EQ(gfx::Rect(30, 50, 30, 40), v2->layer()->bounds());
4021 EXPECT_EQ(v2->layer()->bounds(), v2_observer.GetLastLayerBoundsAndReset());
4022
4023 // Make v1 have a layer again and verify v2s layer is wired up correctly.
4024 gfx::Transform transform;
4025 transform.Scale(2.0, 2.0);
4026 v1->SetTransform(transform);
4027 EXPECT_TRUE(v1->layer() != nullptr);
4028 EXPECT_TRUE(v2->layer() != nullptr);
4029 EXPECT_EQ(root_layer, v1->layer()->parent());
4030 EXPECT_EQ(v1->layer(), v2->layer()->parent());
4031 ASSERT_EQ(1u, root_layer->children().size());
4032 EXPECT_EQ(root_layer->children()[0], v1->layer());
4033 ASSERT_EQ(1u, v1->layer()->children().size());
4034 EXPECT_EQ(v1->layer()->children()[0], v2->layer());
4035 EXPECT_EQ(gfx::Rect(10, 20, 30, 40), v2->layer()->bounds());
4036 EXPECT_EQ(v2->layer()->bounds(), v2_observer.GetLastLayerBoundsAndReset());
4037 }
4038
4039 // Verifies turning on a layer wires up children correctly.
TEST_F(ViewLayerTest,NestedLayerToggling)4040 TEST_F(ViewLayerTest, NestedLayerToggling) {
4041 View* content_view = new View;
4042 widget()->SetContentsView(content_view);
4043
4044 // Create v1, give it a bounds and verify everything is set up correctly.
4045 View* v1 = content_view->AddChildView(std::make_unique<View>());
4046 v1->SetBoundsRect(gfx::Rect(20, 30, 140, 150));
4047
4048 View* v2 = v1->AddChildView(std::make_unique<View>());
4049 v2->SetBoundsRect(gfx::Rect(10, 10, 100, 100));
4050
4051 View* v3 = v2->AddChildView(std::make_unique<View>());
4052 TestingLayerViewObserver v3_observer(v3);
4053 v3->SetBoundsRect(gfx::Rect(0, 0, 100, 100));
4054 v3->SetPaintToLayer();
4055 ASSERT_TRUE(v3->layer() != nullptr);
4056 EXPECT_EQ(v3->layer()->bounds(), v3_observer.GetLastLayerBoundsAndReset());
4057
4058 // At this point we have v1-v2-v3. v3 has a layer, v1 and v2 don't.
4059
4060 v1->SetPaintToLayer();
4061 EXPECT_EQ(v1->layer(), v3->layer()->parent());
4062 EXPECT_EQ(v3->layer()->bounds(), v3_observer.GetLastLayerBoundsAndReset());
4063 }
4064
TEST_F(ViewLayerTest,LayerAnimator)4065 TEST_F(ViewLayerTest, LayerAnimator) {
4066 View* content_view = new View;
4067 widget()->SetContentsView(content_view);
4068
4069 View* v1 = content_view->AddChildView(std::make_unique<View>());
4070 v1->SetPaintToLayer();
4071 EXPECT_TRUE(v1->layer() != nullptr);
4072
4073 TestLayerAnimator* animator = new TestLayerAnimator();
4074 v1->layer()->SetAnimator(animator);
4075
4076 gfx::Rect bounds(1, 2, 3, 4);
4077 v1->SetBoundsRect(bounds);
4078 EXPECT_EQ(bounds, animator->last_bounds());
4079 // TestLayerAnimator doesn't update the layer.
4080 EXPECT_NE(bounds, v1->layer()->bounds());
4081 }
4082
4083 // Verifies the bounds of a layer are updated if the bounds of ancestor that
4084 // doesn't have a layer change.
TEST_F(ViewLayerTest,BoundsChangeWithLayer)4085 TEST_F(ViewLayerTest, BoundsChangeWithLayer) {
4086 View* content_view = new View;
4087 widget()->SetContentsView(content_view);
4088
4089 View* v1 = content_view->AddChildView(std::make_unique<View>());
4090 v1->SetBoundsRect(gfx::Rect(20, 30, 140, 150));
4091
4092 View* v2 = v1->AddChildView(std::make_unique<View>());
4093 TestingLayerViewObserver v2_observer(v2);
4094 v2->SetBoundsRect(gfx::Rect(10, 11, 40, 50));
4095 v2->SetPaintToLayer();
4096 ASSERT_TRUE(v2->layer() != nullptr);
4097 EXPECT_EQ(gfx::Rect(30, 41, 40, 50), v2->layer()->bounds());
4098 EXPECT_EQ(v2->layer()->bounds(), v2_observer.GetLastLayerBoundsAndReset());
4099
4100 v1->SetPosition(gfx::Point(25, 36));
4101 EXPECT_EQ(gfx::Rect(35, 47, 40, 50), v2->layer()->bounds());
4102 EXPECT_EQ(v2->layer()->bounds(), v2_observer.GetLastLayerBoundsAndReset());
4103
4104 v2->SetPosition(gfx::Point(11, 12));
4105 EXPECT_EQ(gfx::Rect(36, 48, 40, 50), v2->layer()->bounds());
4106 EXPECT_EQ(v2->layer()->bounds(), v2_observer.GetLastLayerBoundsAndReset());
4107
4108 // Bounds of the layer should change even if the view is not invisible.
4109 v1->SetVisible(false);
4110 v1->SetPosition(gfx::Point(20, 30));
4111 EXPECT_EQ(gfx::Rect(31, 42, 40, 50), v2->layer()->bounds());
4112 EXPECT_EQ(v2->layer()->bounds(), v2_observer.GetLastLayerBoundsAndReset());
4113
4114 v2->SetVisible(false);
4115 v2->SetBoundsRect(gfx::Rect(10, 11, 20, 30));
4116 EXPECT_EQ(gfx::Rect(30, 41, 20, 30), v2->layer()->bounds());
4117 EXPECT_EQ(v2->layer()->bounds(), v2_observer.GetLastLayerBoundsAndReset());
4118 }
4119
4120 // Make sure layers are positioned correctly in RTL.
TEST_F(ViewLayerTest,BoundInRTL)4121 TEST_F(ViewLayerTest, BoundInRTL) {
4122 base::test::ScopedRestoreICUDefaultLocale scoped_locale_("he");
4123 View* view = new View;
4124 widget()->SetContentsView(view);
4125
4126 int content_width = view->width();
4127
4128 // |v1| is initially not attached to anything. So its layer will have the same
4129 // bounds as the view.
4130 View* v1 = new View;
4131 v1->SetPaintToLayer();
4132 v1->SetBounds(10, 10, 20, 10);
4133 EXPECT_EQ(gfx::Rect(10, 10, 20, 10), v1->layer()->bounds());
4134
4135 // Once |v1| is attached to the widget, its layer will get RTL-appropriate
4136 // bounds.
4137 view->AddChildView(v1);
4138 EXPECT_EQ(gfx::Rect(content_width - 30, 10, 20, 10), v1->layer()->bounds());
4139 gfx::Rect l1bounds = v1->layer()->bounds();
4140
4141 // Now attach a View to the widget first, then create a layer for it. Make
4142 // sure the bounds are correct.
4143 View* v2 = new View;
4144 v2->SetBounds(50, 10, 30, 10);
4145 EXPECT_FALSE(v2->layer());
4146 view->AddChildView(v2);
4147 v2->SetPaintToLayer();
4148 EXPECT_EQ(gfx::Rect(content_width - 80, 10, 30, 10), v2->layer()->bounds());
4149 gfx::Rect l2bounds = v2->layer()->bounds();
4150
4151 view->SetPaintToLayer();
4152 EXPECT_EQ(l1bounds, v1->layer()->bounds());
4153 EXPECT_EQ(l2bounds, v2->layer()->bounds());
4154
4155 // Move one of the views. Make sure the layer is positioned correctly
4156 // afterwards.
4157 v1->SetBounds(v1->x() - 5, v1->y(), v1->width(), v1->height());
4158 l1bounds.set_x(l1bounds.x() + 5);
4159 EXPECT_EQ(l1bounds, v1->layer()->bounds());
4160
4161 view->DestroyLayer();
4162 EXPECT_EQ(l1bounds, v1->layer()->bounds());
4163 EXPECT_EQ(l2bounds, v2->layer()->bounds());
4164
4165 // Move a view again.
4166 v2->SetBounds(v2->x() + 5, v2->y(), v2->width(), v2->height());
4167 l2bounds.set_x(l2bounds.x() - 5);
4168 EXPECT_EQ(l2bounds, v2->layer()->bounds());
4169 }
4170
4171 // Make sure that resizing a parent in RTL correctly repositions its children.
TEST_F(ViewLayerTest,ResizeParentInRTL)4172 TEST_F(ViewLayerTest, ResizeParentInRTL) {
4173 base::test::ScopedRestoreICUDefaultLocale scoped_locale_("he");
4174 View* view = new View;
4175 widget()->SetContentsView(view);
4176
4177 int content_width = view->width();
4178
4179 // Create a paints-to-layer view |v1|.
4180 View* v1 = view->AddChildView(std::make_unique<View>());
4181 v1->SetPaintToLayer();
4182 v1->SetBounds(10, 10, 20, 10);
4183 EXPECT_EQ(gfx::Rect(content_width - 30, 10, 20, 10), v1->layer()->bounds());
4184
4185 // Attach a paints-to-layer child view to |v1|.
4186 View* v2 = new View;
4187 v2->SetPaintToLayer();
4188 v2->SetBounds(3, 5, 6, 4);
4189 EXPECT_EQ(gfx::Rect(3, 5, 6, 4), v2->layer()->bounds());
4190 v1->AddChildView(v2);
4191 // Check that |v2| now has RTL-appropriate bounds.
4192 EXPECT_EQ(gfx::Rect(11, 5, 6, 4), v2->layer()->bounds());
4193
4194 // Attach a non-layer child view to |v1|, and give it a paints-to-layer child.
4195 View* v3 = new View;
4196 v3->SetBounds(1, 1, 18, 8);
4197 View* v4 = new View;
4198 v4->SetPaintToLayer();
4199 v4->SetBounds(2, 4, 6, 4);
4200 EXPECT_EQ(gfx::Rect(2, 4, 6, 4), v4->layer()->bounds());
4201 v3->AddChildView(v4);
4202 EXPECT_EQ(gfx::Rect(10, 4, 6, 4), v4->layer()->bounds());
4203 v1->AddChildView(v3);
4204 // Check that |v4| now has RTL-appropriate bounds.
4205 EXPECT_EQ(gfx::Rect(11, 5, 6, 4), v4->layer()->bounds());
4206
4207 // Resize |v1|. Make sure that |v2| and |v4|'s layers have been moved
4208 // correctly to RTL-appropriate bounds.
4209 v1->SetSize(gfx::Size(30, 10));
4210 EXPECT_EQ(gfx::Rect(21, 5, 6, 4), v2->layer()->bounds());
4211 EXPECT_EQ(gfx::Rect(21, 5, 6, 4), v4->layer()->bounds());
4212
4213 // Move and resize |v3|. Make sure that |v4|'s layer has been moved correctly
4214 // to RTL-appropriate bounds.
4215 v3->SetBounds(2, 1, 12, 8);
4216 EXPECT_EQ(gfx::Rect(20, 5, 6, 4), v4->layer()->bounds());
4217 }
4218
4219 // Makes sure a transform persists after toggling the visibility.
TEST_F(ViewLayerTest,ToggleVisibilityWithTransform)4220 TEST_F(ViewLayerTest, ToggleVisibilityWithTransform) {
4221 View* view = new View;
4222 gfx::Transform transform;
4223 transform.Scale(2.0, 2.0);
4224 view->SetTransform(transform);
4225 widget()->SetContentsView(view);
4226 EXPECT_EQ(2.0f, view->GetTransform().matrix().get(0, 0));
4227
4228 view->SetVisible(false);
4229 EXPECT_EQ(2.0f, view->GetTransform().matrix().get(0, 0));
4230
4231 view->SetVisible(true);
4232 EXPECT_EQ(2.0f, view->GetTransform().matrix().get(0, 0));
4233 }
4234
4235 // Verifies a transform persists after removing/adding a view with a transform.
TEST_F(ViewLayerTest,ResetTransformOnLayerAfterAdd)4236 TEST_F(ViewLayerTest, ResetTransformOnLayerAfterAdd) {
4237 View* view = new View;
4238 gfx::Transform transform;
4239 transform.Scale(2.0, 2.0);
4240 view->SetTransform(transform);
4241 widget()->SetContentsView(view);
4242 EXPECT_EQ(2.0f, view->GetTransform().matrix().get(0, 0));
4243 ASSERT_TRUE(view->layer() != nullptr);
4244 EXPECT_EQ(2.0f, view->layer()->transform().matrix().get(0, 0));
4245
4246 View* parent = view->parent();
4247 parent->RemoveChildView(view);
4248 parent->AddChildView(view);
4249
4250 EXPECT_EQ(2.0f, view->GetTransform().matrix().get(0, 0));
4251 ASSERT_TRUE(view->layer() != nullptr);
4252 EXPECT_EQ(2.0f, view->layer()->transform().matrix().get(0, 0));
4253 }
4254
4255 // Makes sure that layer visibility is correct after toggling View visibility.
TEST_F(ViewLayerTest,ToggleVisibilityWithLayer)4256 TEST_F(ViewLayerTest, ToggleVisibilityWithLayer) {
4257 View* content_view = new View;
4258 widget()->SetContentsView(content_view);
4259
4260 // The view isn't attached to a widget or a parent view yet. But it should
4261 // still have a layer, but the layer should not be attached to the root
4262 // layer.
4263 View* v1 = new View;
4264 v1->SetPaintToLayer();
4265 EXPECT_TRUE(v1->layer());
4266 EXPECT_FALSE(
4267 LayerIsAncestor(widget()->GetCompositor()->root_layer(), v1->layer()));
4268
4269 // Once the view is attached to a widget, its layer should be attached to the
4270 // root layer and visible.
4271 content_view->AddChildView(v1);
4272 EXPECT_TRUE(
4273 LayerIsAncestor(widget()->GetCompositor()->root_layer(), v1->layer()));
4274 EXPECT_TRUE(v1->layer()->IsDrawn());
4275
4276 v1->SetVisible(false);
4277 EXPECT_FALSE(v1->layer()->IsDrawn());
4278
4279 v1->SetVisible(true);
4280 EXPECT_TRUE(v1->layer()->IsDrawn());
4281
4282 widget()->Hide();
4283 EXPECT_FALSE(v1->layer()->IsDrawn());
4284
4285 widget()->Show();
4286 EXPECT_TRUE(v1->layer()->IsDrawn());
4287 }
4288
4289 // Tests that the layers in the subtree are orphaned after a View is removed
4290 // from the parent.
TEST_F(ViewLayerTest,OrphanLayerAfterViewRemove)4291 TEST_F(ViewLayerTest, OrphanLayerAfterViewRemove) {
4292 View* content_view = new View;
4293 widget()->SetContentsView(content_view);
4294
4295 View* v1 = new View;
4296 content_view->AddChildView(v1);
4297
4298 View* v2 = new View;
4299 v1->AddChildView(v2);
4300 v2->SetPaintToLayer();
4301 EXPECT_TRUE(
4302 LayerIsAncestor(widget()->GetCompositor()->root_layer(), v2->layer()));
4303 EXPECT_TRUE(v2->layer()->IsDrawn());
4304
4305 content_view->RemoveChildView(v1);
4306
4307 EXPECT_FALSE(
4308 LayerIsAncestor(widget()->GetCompositor()->root_layer(), v2->layer()));
4309
4310 // Reparent |v2|.
4311 v1->RemoveChildView(v2);
4312 content_view->AddChildView(v2);
4313 delete v1;
4314 v1 = nullptr;
4315 EXPECT_TRUE(
4316 LayerIsAncestor(widget()->GetCompositor()->root_layer(), v2->layer()));
4317 EXPECT_TRUE(v2->layer()->IsDrawn());
4318 }
4319
4320 class PaintTrackingView : public View {
4321 public:
4322 PaintTrackingView() = default;
4323
painted() const4324 bool painted() const { return painted_; }
set_painted(bool value)4325 void set_painted(bool value) { painted_ = value; }
4326
OnPaint(gfx::Canvas * canvas)4327 void OnPaint(gfx::Canvas* canvas) override { painted_ = true; }
4328
4329 private:
4330 bool painted_ = false;
4331
4332 DISALLOW_COPY_AND_ASSIGN(PaintTrackingView);
4333 };
4334
4335 // Makes sure child views with layers aren't painted when paint starts at an
4336 // ancestor.
TEST_F(ViewLayerTest,DontPaintChildrenWithLayers)4337 TEST_F(ViewLayerTest, DontPaintChildrenWithLayers) {
4338 PaintTrackingView* content_view = new PaintTrackingView;
4339 widget()->SetContentsView(content_view);
4340 content_view->SetPaintToLayer();
4341 GetRootLayer()->GetCompositor()->ScheduleDraw();
4342 ui::DrawWaiterForTest::WaitForCompositingEnded(
4343 GetRootLayer()->GetCompositor());
4344 GetRootLayer()->SchedulePaint(gfx::Rect(0, 0, 10, 10));
4345 content_view->set_painted(false);
4346 // content_view no longer has a dirty rect. Paint from the root and make sure
4347 // PaintTrackingView isn't painted.
4348 GetRootLayer()->GetCompositor()->ScheduleDraw();
4349 ui::DrawWaiterForTest::WaitForCompositingEnded(
4350 GetRootLayer()->GetCompositor());
4351 EXPECT_FALSE(content_view->painted());
4352
4353 // Make content_view have a dirty rect, paint the layers and make sure
4354 // PaintTrackingView is painted.
4355 content_view->layer()->SchedulePaint(gfx::Rect(0, 0, 10, 10));
4356 GetRootLayer()->GetCompositor()->ScheduleDraw();
4357 ui::DrawWaiterForTest::WaitForCompositingEnded(
4358 GetRootLayer()->GetCompositor());
4359 EXPECT_TRUE(content_view->painted());
4360 }
4361
TEST_F(ViewLayerTest,NoCrashWhenParentlessViewSchedulesPaintOnParent)4362 TEST_F(ViewLayerTest, NoCrashWhenParentlessViewSchedulesPaintOnParent) {
4363 TestView v;
4364 SchedulePaintOnParent(&v);
4365 }
4366
TEST_F(ViewLayerTest,ScheduledRectsInParentAfterSchedulingPaint)4367 TEST_F(ViewLayerTest, ScheduledRectsInParentAfterSchedulingPaint) {
4368 TestView parent_view;
4369 parent_view.SetBounds(10, 10, 100, 100);
4370
4371 TestView* child_view = parent_view.AddChildView(std::make_unique<TestView>());
4372 child_view->SetBounds(5, 6, 10, 20);
4373
4374 parent_view.scheduled_paint_rects_.clear();
4375 SchedulePaintOnParent(child_view);
4376 ASSERT_EQ(1U, parent_view.scheduled_paint_rects_.size());
4377 EXPECT_EQ(gfx::Rect(5, 6, 10, 20),
4378 parent_view.scheduled_paint_rects_.front());
4379 }
4380
TEST_F(ViewLayerTest,ParentPaintWhenSwitchingPaintToLayerFromFalseToTrue)4381 TEST_F(ViewLayerTest, ParentPaintWhenSwitchingPaintToLayerFromFalseToTrue) {
4382 TestView parent_view;
4383 parent_view.SetBounds(10, 11, 12, 13);
4384
4385 TestView* child_view = parent_view.AddChildView(std::make_unique<TestView>());
4386
4387 parent_view.scheduled_paint_rects_.clear();
4388 child_view->SetPaintToLayer();
4389 EXPECT_EQ(1U, parent_view.scheduled_paint_rects_.size());
4390 }
4391
TEST_F(ViewLayerTest,NoParentPaintWhenSwitchingPaintToLayerFromTrueToTrue)4392 TEST_F(ViewLayerTest, NoParentPaintWhenSwitchingPaintToLayerFromTrueToTrue) {
4393 TestView parent_view;
4394 parent_view.SetBounds(10, 11, 12, 13);
4395
4396 TestView* child_view = parent_view.AddChildView(std::make_unique<TestView>());
4397 child_view->SetPaintToLayer();
4398
4399 parent_view.scheduled_paint_rects_.clear();
4400 EXPECT_EQ(0U, parent_view.scheduled_paint_rects_.size());
4401 }
4402
4403 // Tests that the visibility of child layers are updated correctly when a View's
4404 // visibility changes.
TEST_F(ViewLayerTest,VisibilityChildLayers)4405 TEST_F(ViewLayerTest, VisibilityChildLayers) {
4406 View* v1 = new View;
4407 v1->SetPaintToLayer();
4408 widget()->SetContentsView(v1);
4409
4410 View* v2 = v1->AddChildView(std::make_unique<View>());
4411
4412 View* v3 = v2->AddChildView(std::make_unique<View>());
4413 v3->SetVisible(false);
4414
4415 View* v4 = v3->AddChildView(std::make_unique<View>());
4416 v4->SetPaintToLayer();
4417
4418 EXPECT_TRUE(v1->layer()->IsDrawn());
4419 EXPECT_FALSE(v4->layer()->IsDrawn());
4420
4421 v2->SetVisible(false);
4422 EXPECT_TRUE(v1->layer()->IsDrawn());
4423 EXPECT_FALSE(v4->layer()->IsDrawn());
4424
4425 v2->SetVisible(true);
4426 EXPECT_TRUE(v1->layer()->IsDrawn());
4427 EXPECT_FALSE(v4->layer()->IsDrawn());
4428
4429 v2->SetVisible(false);
4430 EXPECT_TRUE(v1->layer()->IsDrawn());
4431 EXPECT_FALSE(v4->layer()->IsDrawn());
4432 EXPECT_TRUE(ViewAndLayerTreeAreConsistent(v1, v1->layer()));
4433
4434 v3->SetVisible(true);
4435 EXPECT_TRUE(v1->layer()->IsDrawn());
4436 EXPECT_FALSE(v4->layer()->IsDrawn());
4437 EXPECT_TRUE(ViewAndLayerTreeAreConsistent(v1, v1->layer()));
4438
4439 // Reparent |v3| to |v1|.
4440 v2->RemoveChildView(v3);
4441 v1->AddChildView(v3);
4442 EXPECT_TRUE(v1->layer()->IsDrawn());
4443 EXPECT_TRUE(v4->layer()->IsDrawn());
4444 EXPECT_TRUE(ViewAndLayerTreeAreConsistent(v1, v1->layer()));
4445 }
4446
4447 // This test creates a random View tree, and then randomly reorders child views,
4448 // reparents views etc. Unrelated changes can appear to break this test. So
4449 // marking this as FLAKY.
TEST_F(ViewLayerTest,DISABLED_ViewLayerTreesInSync)4450 TEST_F(ViewLayerTest, DISABLED_ViewLayerTreesInSync) {
4451 View* content = new View;
4452 content->SetPaintToLayer();
4453 widget()->SetContentsView(content);
4454 widget()->Show();
4455
4456 ConstructTree(content, 5);
4457 EXPECT_TRUE(ViewAndLayerTreeAreConsistent(content, content->layer()));
4458
4459 ScrambleTree(content);
4460 EXPECT_TRUE(ViewAndLayerTreeAreConsistent(content, content->layer()));
4461
4462 ScrambleTree(content);
4463 EXPECT_TRUE(ViewAndLayerTreeAreConsistent(content, content->layer()));
4464
4465 ScrambleTree(content);
4466 EXPECT_TRUE(ViewAndLayerTreeAreConsistent(content, content->layer()));
4467 }
4468
4469 // Verifies when views are reordered the layer is also reordered. The widget is
4470 // providing the parent layer.
TEST_F(ViewLayerTest,ReorderUnderWidget)4471 TEST_F(ViewLayerTest, ReorderUnderWidget) {
4472 View* content = new View;
4473 widget()->SetContentsView(content);
4474 View* c1 = content->AddChildView(std::make_unique<View>());
4475 c1->SetPaintToLayer();
4476 View* c2 = content->AddChildView(std::make_unique<View>());
4477 c2->SetPaintToLayer();
4478
4479 ui::Layer* parent_layer = c1->layer()->parent();
4480 ASSERT_TRUE(parent_layer);
4481 ASSERT_EQ(2u, parent_layer->children().size());
4482 EXPECT_EQ(c1->layer(), parent_layer->children()[0]);
4483 EXPECT_EQ(c2->layer(), parent_layer->children()[1]);
4484
4485 // Move c1 to the front. The layers should have moved too.
4486 content->ReorderChildView(c1, -1);
4487 EXPECT_EQ(c1->layer(), parent_layer->children()[1]);
4488 EXPECT_EQ(c2->layer(), parent_layer->children()[0]);
4489 }
4490
4491 // Verifies that the layer of a view can be acquired properly.
TEST_F(ViewLayerTest,AcquireLayer)4492 TEST_F(ViewLayerTest, AcquireLayer) {
4493 View* content = new View;
4494 widget()->SetContentsView(content);
4495 std::unique_ptr<View> c1(new View);
4496 c1->SetPaintToLayer();
4497 EXPECT_TRUE(c1->layer());
4498 content->AddChildView(c1.get());
4499
4500 std::unique_ptr<ui::Layer> layer(c1->AcquireLayer());
4501 EXPECT_EQ(layer.get(), c1->layer());
4502
4503 std::unique_ptr<ui::Layer> layer2(c1->RecreateLayer());
4504 EXPECT_NE(c1->layer(), layer2.get());
4505
4506 // Destroy view before destroying layer.
4507 c1.reset();
4508 }
4509
4510 // Verify the z-order of the layers as a result of calling RecreateLayer().
TEST_F(ViewLayerTest,RecreateLayerZOrder)4511 TEST_F(ViewLayerTest, RecreateLayerZOrder) {
4512 std::unique_ptr<View> v(new View());
4513 v->SetPaintToLayer();
4514
4515 View* v1 = v->AddChildView(std::make_unique<View>());
4516 v1->SetPaintToLayer();
4517 View* v2 = v->AddChildView(std::make_unique<View>());
4518 v2->SetPaintToLayer();
4519
4520 // Test the initial z-order.
4521 const std::vector<ui::Layer*>& child_layers_pre = v->layer()->children();
4522 ASSERT_EQ(2u, child_layers_pre.size());
4523 EXPECT_EQ(v1->layer(), child_layers_pre[0]);
4524 EXPECT_EQ(v2->layer(), child_layers_pre[1]);
4525
4526 std::unique_ptr<ui::Layer> v1_old_layer(v1->RecreateLayer());
4527
4528 // Test the new layer order. We expect: |v1| |v1_old_layer| |v2|.
4529 // for |v1| and |v2|.
4530 const std::vector<ui::Layer*>& child_layers_post = v->layer()->children();
4531 ASSERT_EQ(3u, child_layers_post.size());
4532 EXPECT_EQ(v1->layer(), child_layers_post[0]);
4533 EXPECT_EQ(v1_old_layer.get(), child_layers_post[1]);
4534 EXPECT_EQ(v2->layer(), child_layers_post[2]);
4535 }
4536
4537 // Verify the z-order of the layers as a result of calling RecreateLayer when
4538 // the widget is the parent with the layer.
TEST_F(ViewLayerTest,RecreateLayerZOrderWidgetParent)4539 TEST_F(ViewLayerTest, RecreateLayerZOrderWidgetParent) {
4540 View* v = new View();
4541 widget()->SetContentsView(v);
4542
4543 View* v1 = v->AddChildView(std::make_unique<View>());
4544 v1->SetPaintToLayer();
4545 View* v2 = v->AddChildView(std::make_unique<View>());
4546 v2->SetPaintToLayer();
4547
4548 ui::Layer* root_layer = GetRootLayer();
4549
4550 // Test the initial z-order.
4551 const std::vector<ui::Layer*>& child_layers_pre = root_layer->children();
4552 ASSERT_EQ(2u, child_layers_pre.size());
4553 EXPECT_EQ(v1->layer(), child_layers_pre[0]);
4554 EXPECT_EQ(v2->layer(), child_layers_pre[1]);
4555
4556 std::unique_ptr<ui::Layer> v1_old_layer(v1->RecreateLayer());
4557
4558 // Test the new layer order. We expect: |v1| |v1_old_layer| |v2|.
4559 const std::vector<ui::Layer*>& child_layers_post = root_layer->children();
4560 ASSERT_EQ(3u, child_layers_post.size());
4561 EXPECT_EQ(v1->layer(), child_layers_post[0]);
4562 EXPECT_EQ(v1_old_layer.get(), child_layers_post[1]);
4563 EXPECT_EQ(v2->layer(), child_layers_post[2]);
4564 }
4565
4566 // Verifies RecreateLayer() moves all Layers over, even those that don't have
4567 // a View.
TEST_F(ViewLayerTest,RecreateLayerMovesNonViewChildren)4568 TEST_F(ViewLayerTest, RecreateLayerMovesNonViewChildren) {
4569 View v;
4570 v.SetPaintToLayer();
4571 View child;
4572 child.SetPaintToLayer();
4573 v.AddChildView(&child);
4574 ASSERT_TRUE(v.layer() != nullptr);
4575 ASSERT_EQ(1u, v.layer()->children().size());
4576 EXPECT_EQ(v.layer()->children()[0], child.layer());
4577
4578 ui::Layer layer(ui::LAYER_NOT_DRAWN);
4579 v.layer()->Add(&layer);
4580 v.layer()->StackAtBottom(&layer);
4581
4582 std::unique_ptr<ui::Layer> old_layer(v.RecreateLayer());
4583
4584 // All children should be moved from old layer to new layer.
4585 ASSERT_TRUE(old_layer.get() != nullptr);
4586 EXPECT_TRUE(old_layer->children().empty());
4587
4588 // And new layer should have the two children.
4589 ASSERT_TRUE(v.layer() != nullptr);
4590 ASSERT_EQ(2u, v.layer()->children().size());
4591 EXPECT_EQ(v.layer()->children()[0], &layer);
4592 EXPECT_EQ(v.layer()->children()[1], child.layer());
4593 }
4594
4595 namespace {
4596
ToString(const gfx::Vector2dF & vector)4597 std::string ToString(const gfx::Vector2dF& vector) {
4598 // Explicitly round it because linux uses banker's rounding
4599 // while Windows is using "away-from-zero" in printf.
4600 return base::StringPrintf("%0.2f %0.2f", std::round(vector.x() * 100) / 100.f,
4601 std::round(vector.y() * 100) / 100.f);
4602 }
4603
4604 } // namespace
4605
TEST_F(ViewLayerTest,SnapLayerToPixel)4606 TEST_F(ViewLayerTest, SnapLayerToPixel) {
4607 viz::ParentLocalSurfaceIdAllocator allocator;
4608 allocator.GenerateId();
4609 View* v1 = new View;
4610
4611 View* v11 = v1->AddChildView(std::make_unique<View>());
4612
4613 widget()->SetContentsView(v1);
4614
4615 const gfx::Size& size = GetRootLayer()->GetCompositor()->size();
4616 GetRootLayer()->GetCompositor()->SetScaleAndSize(
4617 1.25f, size, allocator.GetCurrentLocalSurfaceIdAllocation());
4618
4619 v11->SetBoundsRect(gfx::Rect(1, 1, 10, 10));
4620 v1->SetBoundsRect(gfx::Rect(1, 1, 10, 10));
4621 v11->SetPaintToLayer();
4622
4623 EXPECT_EQ("0.40 0.40", ToString(v11->layer()->GetSubpixelOffset()));
4624
4625 // Creating a layer in parent should update the child view's layer offset.
4626 v1->SetPaintToLayer();
4627 EXPECT_EQ("-0.20 -0.20", ToString(v1->layer()->GetSubpixelOffset()));
4628 EXPECT_EQ("-0.20 -0.20", ToString(v11->layer()->GetSubpixelOffset()));
4629
4630 // DSF change should get propagated and update offsets.
4631 GetRootLayer()->GetCompositor()->SetScaleAndSize(
4632 1.5f, size, allocator.GetCurrentLocalSurfaceIdAllocation());
4633 EXPECT_EQ("0.33 0.33", ToString(v1->layer()->GetSubpixelOffset()));
4634 EXPECT_EQ("0.33 0.33", ToString(v11->layer()->GetSubpixelOffset()));
4635
4636 // Deleting parent's layer should update the child view's layer's offset.
4637 v1->DestroyLayer();
4638 EXPECT_EQ("0.00 0.00", ToString(v11->layer()->GetSubpixelOffset()));
4639
4640 // Setting parent view should update the child view's layer's offset.
4641 v1->SetBoundsRect(gfx::Rect(2, 2, 10, 10));
4642 EXPECT_EQ("0.33 0.33", ToString(v11->layer()->GetSubpixelOffset()));
4643
4644 // Setting integral DSF should reset the offset.
4645 GetRootLayer()->GetCompositor()->SetScaleAndSize(
4646 2.0f, size, allocator.GetCurrentLocalSurfaceIdAllocation());
4647 EXPECT_EQ("0.00 0.00", ToString(v11->layer()->GetSubpixelOffset()));
4648
4649 // DSF reset followed by DSF change should update the offset.
4650 GetRootLayer()->GetCompositor()->SetScaleAndSize(
4651 1.0f, size, allocator.GetCurrentLocalSurfaceIdAllocation());
4652 EXPECT_EQ("0.00 0.00", ToString(v11->layer()->GetSubpixelOffset()));
4653 GetRootLayer()->GetCompositor()->SetScaleAndSize(
4654 1.5f, size, allocator.GetCurrentLocalSurfaceIdAllocation());
4655 EXPECT_EQ("0.33 0.33", ToString(v11->layer()->GetSubpixelOffset()));
4656 }
4657
TEST_F(ViewLayerTest,LayerBeneathTriggersPaintToLayer)4658 TEST_F(ViewLayerTest, LayerBeneathTriggersPaintToLayer) {
4659 View root;
4660 root.SetPaintToLayer();
4661
4662 View* view = root.AddChildView(std::make_unique<View>());
4663 EXPECT_EQ(nullptr, view->layer());
4664
4665 ui::Layer layer1;
4666 ui::Layer layer2;
4667 view->AddLayerBeneathView(&layer1);
4668 EXPECT_NE(nullptr, view->layer());
4669 view->AddLayerBeneathView(&layer2);
4670 EXPECT_NE(nullptr, view->layer());
4671
4672 view->RemoveLayerBeneathView(&layer1);
4673 EXPECT_NE(nullptr, view->layer());
4674 view->RemoveLayerBeneathView(&layer2);
4675 EXPECT_EQ(nullptr, view->layer());
4676 }
4677
TEST_F(ViewLayerTest,LayerBeneathAddedToTree)4678 TEST_F(ViewLayerTest, LayerBeneathAddedToTree) {
4679 View root;
4680 root.SetPaintToLayer();
4681
4682 ui::Layer layer;
4683 View* view = root.AddChildView(std::make_unique<View>());
4684
4685 view->AddLayerBeneathView(&layer);
4686 ASSERT_NE(nullptr, view->layer());
4687 EXPECT_TRUE(view->layer()->parent()->Contains(&layer));
4688
4689 view->RemoveLayerBeneathView(&layer);
4690 EXPECT_EQ(nullptr, layer.parent());
4691 }
4692
TEST_F(ViewLayerTest,LayerBeneathAtFractionalScale)4693 TEST_F(ViewLayerTest, LayerBeneathAtFractionalScale) {
4694 constexpr float device_scale = 1.5f;
4695
4696 viz::ParentLocalSurfaceIdAllocator allocator;
4697 allocator.GenerateId();
4698 const gfx::Size& size = GetRootLayer()->GetCompositor()->size();
4699 GetRootLayer()->GetCompositor()->SetScaleAndSize(
4700 device_scale, size, allocator.GetCurrentLocalSurfaceIdAllocation());
4701
4702 View* view = new View;
4703 widget()->SetContentsView(view);
4704
4705 ui::Layer layer;
4706 view->AddLayerBeneathView(&layer);
4707
4708 view->SetBoundsRect(gfx::Rect(1, 1, 10, 10));
4709 EXPECT_NE(gfx::Vector2dF(), view->layer()->GetSubpixelOffset());
4710 EXPECT_EQ(view->layer()->GetSubpixelOffset(), layer.GetSubpixelOffset());
4711
4712 view->RemoveLayerBeneathView(&layer);
4713 }
4714
TEST_F(ViewLayerTest,LayerBeneathRemovedOnDestruction)4715 TEST_F(ViewLayerTest, LayerBeneathRemovedOnDestruction) {
4716 View root;
4717 root.SetPaintToLayer();
4718
4719 auto layer = std::make_unique<ui::Layer>();
4720 View* view = root.AddChildView(std::make_unique<View>());
4721
4722 // No assertions, just get coverage of deleting the layer while it is added.
4723 view->AddLayerBeneathView(layer.get());
4724 layer.reset();
4725 root.RemoveChildView(view);
4726 delete view;
4727 }
4728
TEST_F(ViewLayerTest,LayerBeneathVisibilityUpdated)4729 TEST_F(ViewLayerTest, LayerBeneathVisibilityUpdated) {
4730 View root;
4731 root.SetPaintToLayer();
4732
4733 ui::Layer layer;
4734
4735 // Make a parent view that has no layer, and a child view that has a layer.
4736 View* parent = root.AddChildView(std::make_unique<View>());
4737 View* child = parent->AddChildView(std::make_unique<View>());
4738 child->AddLayerBeneathView(&layer);
4739
4740 EXPECT_EQ(nullptr, parent->layer());
4741 EXPECT_NE(nullptr, child->layer());
4742
4743 // Test setting the views' visbilities in various orders.
4744 EXPECT_TRUE(layer.visible());
4745 child->SetVisible(false);
4746 EXPECT_FALSE(layer.visible());
4747 child->SetVisible(true);
4748 EXPECT_TRUE(layer.visible());
4749
4750 parent->SetVisible(false);
4751 EXPECT_FALSE(layer.visible());
4752 parent->SetVisible(true);
4753 EXPECT_TRUE(layer.visible());
4754
4755 parent->SetVisible(false);
4756 EXPECT_FALSE(layer.visible());
4757 child->SetVisible(false);
4758 EXPECT_FALSE(layer.visible());
4759 parent->SetVisible(true);
4760 EXPECT_FALSE(layer.visible());
4761 child->SetVisible(true);
4762 EXPECT_TRUE(layer.visible());
4763
4764 child->RemoveLayerBeneathView(&layer);
4765
4766 // Now check the visibility upon adding.
4767 child->SetVisible(false);
4768 child->AddLayerBeneathView(&layer);
4769 EXPECT_FALSE(layer.visible());
4770 child->SetVisible(true);
4771 EXPECT_TRUE(layer.visible());
4772
4773 child->RemoveLayerBeneathView(&layer);
4774 }
4775
TEST_F(ViewLayerTest,LayerBeneathHasCorrectBounds)4776 TEST_F(ViewLayerTest, LayerBeneathHasCorrectBounds) {
4777 View root;
4778 root.SetBoundsRect(gfx::Rect(100, 100));
4779 root.SetPaintToLayer();
4780
4781 View* view = root.AddChildView(std::make_unique<View>());
4782 view->SetBoundsRect(gfx::Rect(25, 25, 50, 50));
4783
4784 // The layer's position will be changed, but its size should be respected.
4785 ui::Layer layer;
4786 layer.SetBounds(gfx::Rect(25, 25));
4787
4788 // First check when |view| is already painting to a layer.
4789 view->SetPaintToLayer();
4790 view->AddLayerBeneathView(&layer);
4791 EXPECT_NE(nullptr, layer.parent());
4792 EXPECT_EQ(gfx::Rect(25, 25, 25, 25), layer.bounds());
4793
4794 view->RemoveLayerBeneathView(&layer);
4795 EXPECT_EQ(nullptr, layer.parent());
4796 layer.SetBounds(gfx::Rect(25, 25));
4797
4798 // Next check when |view| wasn't painting to a layer.
4799 view->DestroyLayer();
4800 EXPECT_EQ(nullptr, view->layer());
4801 view->AddLayerBeneathView(&layer);
4802 EXPECT_NE(nullptr, view->layer());
4803 EXPECT_NE(nullptr, layer.parent());
4804 EXPECT_EQ(gfx::Rect(25, 25, 25, 25), layer.bounds());
4805
4806 // Finally check that moving |view| also moves the layer.
4807 view->SetBoundsRect(gfx::Rect(50, 50, 50, 50));
4808 EXPECT_EQ(gfx::Rect(50, 50, 25, 25), layer.bounds());
4809
4810 view->RemoveLayerBeneathView(&layer);
4811 }
4812
TEST_F(ViewLayerTest,LayerBeneathTransformed)4813 TEST_F(ViewLayerTest, LayerBeneathTransformed) {
4814 View root;
4815 root.SetPaintToLayer();
4816
4817 ui::Layer layer;
4818 View* view = root.AddChildView(std::make_unique<View>());
4819 view->SetPaintToLayer();
4820 view->AddLayerBeneathView(&layer);
4821 EXPECT_TRUE(layer.transform().IsIdentity());
4822
4823 gfx::Transform transform;
4824 transform.Rotate(90);
4825 view->SetTransform(transform);
4826 EXPECT_EQ(transform, layer.transform());
4827 view->SetTransform(gfx::Transform());
4828 EXPECT_TRUE(layer.transform().IsIdentity());
4829 }
4830
TEST_F(ViewLayerTest,LayerBeneathStackedCorrectly)4831 TEST_F(ViewLayerTest, LayerBeneathStackedCorrectly) {
4832 using ui::test::ChildLayerNamesAsString;
4833
4834 View root;
4835 root.SetPaintToLayer();
4836
4837 ui::Layer layer;
4838 layer.SetName("layer");
4839
4840 View* v1 = root.AddChildView(std::make_unique<View>());
4841 View* v2 = root.AddChildView(std::make_unique<View>());
4842 View* v3 = root.AddChildView(std::make_unique<View>());
4843
4844 // Check that |layer| is stacked correctly as we add more layers to the tree.
4845 v2->AddLayerBeneathView(&layer);
4846 v2->layer()->SetName("v2");
4847 EXPECT_EQ(ChildLayerNamesAsString(*root.layer()), "layer v2");
4848 v3->SetPaintToLayer();
4849 v3->layer()->SetName("v3");
4850 EXPECT_EQ(ChildLayerNamesAsString(*root.layer()), "layer v2 v3");
4851 v1->SetPaintToLayer();
4852 v1->layer()->SetName("v1");
4853 EXPECT_EQ(ChildLayerNamesAsString(*root.layer()), "v1 layer v2 v3");
4854
4855 v2->RemoveLayerBeneathView(&layer);
4856 }
4857
TEST_F(ViewLayerTest,LayerBeneathOrphanedOnRemoval)4858 TEST_F(ViewLayerTest, LayerBeneathOrphanedOnRemoval) {
4859 View root;
4860 root.SetPaintToLayer();
4861
4862 ui::Layer layer;
4863 View* view = root.AddChildView(std::make_unique<View>());
4864 view->AddLayerBeneathView(&layer);
4865 EXPECT_EQ(layer.parent(), root.layer());
4866
4867 // Ensure that the layer beneath is orphaned and re-parented appropriately.
4868 root.RemoveChildView(view);
4869 EXPECT_EQ(layer.parent(), nullptr);
4870 root.AddChildView(view);
4871 EXPECT_EQ(layer.parent(), root.layer());
4872
4873 view->RemoveLayerBeneathView(&layer);
4874 }
4875
TEST_F(ViewLayerTest,LayerBeneathMovedWithView)4876 TEST_F(ViewLayerTest, LayerBeneathMovedWithView) {
4877 using ui::test::ChildLayerNamesAsString;
4878
4879 View root;
4880 root.SetPaintToLayer();
4881 root.layer()->SetName("root");
4882
4883 ui::Layer layer;
4884 layer.SetName("layer");
4885
4886 View* v1 = root.AddChildView(std::make_unique<View>());
4887 View* v2 = root.AddChildView(std::make_unique<View>());
4888 View* v3 = v1->AddChildView(std::make_unique<View>());
4889
4890 v1->SetPaintToLayer();
4891 v1->layer()->SetName("v1");
4892 v2->SetPaintToLayer();
4893 v2->layer()->SetName("v2");
4894 v3->SetPaintToLayer();
4895 v3->layer()->SetName("v3");
4896
4897 // Verify that |layer| is stacked correctly.
4898 v3->AddLayerBeneathView(&layer);
4899 EXPECT_EQ(ChildLayerNamesAsString(*v1->layer()), "layer v3");
4900
4901 // Move |v3| to under |v2| and check |layer|'s stacking.
4902 v1->RemoveChildView(v3);
4903 v2->AddChildView(std::unique_ptr<View>(v3));
4904 EXPECT_EQ(ChildLayerNamesAsString(*v2->layer()), "layer v3");
4905 }
4906
4907 namespace {
4908
4909 class PaintLayerView : public View {
4910 public:
4911 PaintLayerView() = default;
4912
PaintChildren(const PaintInfo & info)4913 void PaintChildren(const PaintInfo& info) override {
4914 last_paint_info_ = std::make_unique<PaintInfo>(info);
4915 View::PaintChildren(info);
4916 }
4917
GetLastPaintInfo()4918 std::unique_ptr<PaintInfo> GetLastPaintInfo() {
4919 return std::move(last_paint_info_);
4920 }
4921
4922 private:
4923 std::unique_ptr<PaintInfo> last_paint_info_;
4924
4925 DISALLOW_COPY_AND_ASSIGN(PaintLayerView);
4926 };
4927
4928 } // namespace
4929
4930 class ViewLayerPixelCanvasTest : public ViewLayerTest {
4931 public:
4932 ViewLayerPixelCanvasTest() = default;
4933
4934 ~ViewLayerPixelCanvasTest() override = default;
4935
SetUpPixelCanvas()4936 void SetUpPixelCanvas() override {
4937 scoped_feature_list_.InitAndEnableFeature(
4938 ::features::kEnablePixelCanvasRecording);
4939 }
4940
4941 // Test if the recording rects are same with and without layer.
PaintRecordingSizeTest(PaintLayerView * v3,const gfx::Size & expected_size)4942 void PaintRecordingSizeTest(PaintLayerView* v3,
4943 const gfx::Size& expected_size) {
4944 v3->DestroyLayer();
4945 ui::Compositor* compositor = widget()->GetCompositor();
4946 auto list = base::MakeRefCounted<cc::DisplayItemList>();
4947 ui::PaintContext context(list.get(), compositor->device_scale_factor(),
4948 gfx::Rect(compositor->size()), true);
4949 widget()->GetRootView()->PaintFromPaintRoot(context);
4950 EXPECT_EQ(expected_size, v3->GetLastPaintInfo()->paint_recording_size());
4951 v3->SetPaintToLayer();
4952 v3->OnPaintLayer(context);
4953 EXPECT_EQ(expected_size, v3->GetLastPaintInfo()->paint_recording_size());
4954 }
4955
4956 private:
4957 base::test::ScopedFeatureList scoped_feature_list_;
4958
4959 DISALLOW_COPY_AND_ASSIGN(ViewLayerPixelCanvasTest);
4960 };
4961
TEST_F(ViewLayerPixelCanvasTest,SnapLayerToPixel)4962 TEST_F(ViewLayerPixelCanvasTest, SnapLayerToPixel) {
4963 viz::ParentLocalSurfaceIdAllocator allocator;
4964 allocator.GenerateId();
4965 View* v1 = new View;
4966 View* v2 = v1->AddChildView(std::make_unique<View>());
4967 PaintLayerView* v3 = v2->AddChildView(std::make_unique<PaintLayerView>());
4968
4969 widget()->SetContentsView(v1);
4970
4971 const gfx::Size& size = GetRootLayer()->GetCompositor()->size();
4972 GetRootLayer()->GetCompositor()->SetScaleAndSize(
4973 1.6f, size, allocator.GetCurrentLocalSurfaceIdAllocation());
4974
4975 v3->SetBoundsRect(gfx::Rect(14, 13, 13, 5));
4976 v2->SetBoundsRect(gfx::Rect(7, 7, 50, 50));
4977 v1->SetBoundsRect(gfx::Rect(9, 9, 100, 100));
4978
4979 PaintRecordingSizeTest(v3, gfx::Size(21, 8)); // Enclosing Rect = (21, 8)
4980 EXPECT_EQ("-0.63 -0.25", ToString(v3->layer()->GetSubpixelOffset()));
4981
4982 // Creating a layer in parent should update the child view's layer offset.
4983 v1->SetPaintToLayer();
4984 EXPECT_EQ("-0.25 -0.25", ToString(v1->layer()->GetSubpixelOffset()));
4985 EXPECT_EQ("-0.37 -0.00", ToString(v3->layer()->GetSubpixelOffset()));
4986
4987 // DSF change should get propagated and update offsets.
4988 GetRootLayer()->GetCompositor()->SetScaleAndSize(
4989 1.5f, size, allocator.GetCurrentLocalSurfaceIdAllocation());
4990
4991 EXPECT_EQ("0.33 0.33", ToString(v1->layer()->GetSubpixelOffset()));
4992 EXPECT_EQ("0.33 0.67", ToString(v3->layer()->GetSubpixelOffset()));
4993
4994 v1->DestroyLayer();
4995 PaintRecordingSizeTest(v3, gfx::Size(20, 7)); // Enclosing Rect = (20, 8)
4996 v1->SetPaintToLayer();
4997
4998 GetRootLayer()->GetCompositor()->SetScaleAndSize(
4999 1.33f, size, allocator.GetCurrentLocalSurfaceIdAllocation());
5000
5001 EXPECT_EQ("0.02 0.02", ToString(v1->layer()->GetSubpixelOffset()));
5002 EXPECT_EQ("0.05 -0.45", ToString(v3->layer()->GetSubpixelOffset()));
5003
5004 v1->DestroyLayer();
5005 PaintRecordingSizeTest(v3, gfx::Size(17, 7)); // Enclosing Rect = (18, 7)
5006
5007 // Deleting parent's layer should update the child view's layer's offset.
5008 EXPECT_EQ("0.08 -0.43", ToString(v3->layer()->GetSubpixelOffset()));
5009
5010 // Setting parent view should update the child view's layer's offset.
5011 v1->SetBoundsRect(gfx::Rect(3, 3, 10, 10));
5012 EXPECT_EQ("0.06 -0.44", ToString(v3->layer()->GetSubpixelOffset()));
5013
5014 // Setting integral DSF should reset the offset.
5015 GetRootLayer()->GetCompositor()->SetScaleAndSize(
5016 2.0f, size, allocator.GetCurrentLocalSurfaceIdAllocation());
5017 EXPECT_EQ("0.00 0.00", ToString(v3->layer()->GetSubpixelOffset()));
5018
5019 // DSF reset followed by DSF change should update the offset.
5020 GetRootLayer()->GetCompositor()->SetScaleAndSize(
5021 1.0f, size, allocator.GetCurrentLocalSurfaceIdAllocation());
5022 EXPECT_EQ("0.00 0.00", ToString(v3->layer()->GetSubpixelOffset()));
5023 GetRootLayer()->GetCompositor()->SetScaleAndSize(
5024 1.33f, size, allocator.GetCurrentLocalSurfaceIdAllocation());
5025 EXPECT_EQ("0.06 -0.44", ToString(v3->layer()->GetSubpixelOffset()));
5026 }
5027
TEST_F(ViewLayerPixelCanvasTest,LayerBeneathOnPixelCanvas)5028 TEST_F(ViewLayerPixelCanvasTest, LayerBeneathOnPixelCanvas) {
5029 constexpr float device_scale = 1.5f;
5030
5031 viz::ParentLocalSurfaceIdAllocator allocator;
5032 allocator.GenerateId();
5033 const gfx::Size& size = GetRootLayer()->GetCompositor()->size();
5034 GetRootLayer()->GetCompositor()->SetScaleAndSize(
5035 device_scale, size, allocator.GetCurrentLocalSurfaceIdAllocation());
5036
5037 View* view = new View;
5038 widget()->SetContentsView(view);
5039
5040 ui::Layer layer;
5041 view->AddLayerBeneathView(&layer);
5042
5043 view->SetBoundsRect(gfx::Rect(1, 1, 10, 10));
5044 EXPECT_NE(gfx::Vector2dF(), view->layer()->GetSubpixelOffset());
5045 EXPECT_EQ(view->layer()->GetSubpixelOffset(), layer.GetSubpixelOffset());
5046
5047 view->RemoveLayerBeneathView(&layer);
5048 }
5049
TEST_F(ViewTest,FocusableAssertions)5050 TEST_F(ViewTest, FocusableAssertions) {
5051 // View subclasses may change insets based on whether they are focusable,
5052 // which effects the preferred size. To avoid preferred size changing around
5053 // these Views need to key off the last value set to SetFocusBehavior(), not
5054 // whether the View is focusable right now. For this reason it's important
5055 // that the return value of GetFocusBehavior() depends on the last value
5056 // passed to SetFocusBehavior and not whether the View is focusable right now.
5057 TestView view;
5058 view.SetFocusBehavior(View::FocusBehavior::ALWAYS);
5059 EXPECT_EQ(View::FocusBehavior::ALWAYS, view.GetFocusBehavior());
5060 view.SetEnabled(false);
5061 EXPECT_EQ(View::FocusBehavior::ALWAYS, view.GetFocusBehavior());
5062 view.SetFocusBehavior(View::FocusBehavior::NEVER);
5063 EXPECT_EQ(View::FocusBehavior::NEVER, view.GetFocusBehavior());
5064 view.SetFocusBehavior(View::FocusBehavior::ACCESSIBLE_ONLY);
5065 EXPECT_EQ(View::FocusBehavior::ACCESSIBLE_ONLY, view.GetFocusBehavior());
5066 }
5067
5068 ////////////////////////////////////////////////////////////////////////////////
5069 // NativeTheme
5070 ////////////////////////////////////////////////////////////////////////////////
5071
OnThemeChanged()5072 void TestView::OnThemeChanged() {
5073 View::OnThemeChanged();
5074 native_theme_ = GetNativeTheme();
5075 }
5076
TEST_F(ViewTest,OnThemeChanged)5077 TEST_F(ViewTest, OnThemeChanged) {
5078 TestView* test_view = new TestView();
5079 EXPECT_FALSE(test_view->native_theme_);
5080
5081 // Child view added before the widget hierarchy exists should get the
5082 // new native theme notification.
5083 TestView* test_view_child =
5084 test_view->AddChildView(std::make_unique<TestView>());
5085 EXPECT_FALSE(test_view_child->native_theme_);
5086
5087 std::unique_ptr<Widget> widget(new Widget);
5088 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
5089 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
5090 widget->Init(std::move(params));
5091
5092 widget->GetRootView()->AddChildView(test_view);
5093 EXPECT_TRUE(test_view->native_theme_);
5094 EXPECT_EQ(widget->GetNativeTheme(), test_view->native_theme_);
5095 EXPECT_TRUE(test_view_child->native_theme_);
5096 EXPECT_EQ(widget->GetNativeTheme(), test_view_child->native_theme_);
5097
5098 // Child view added after the widget hierarchy exists should also get the
5099 // notification.
5100 TestView* test_view_child_2 =
5101 test_view->AddChildView(std::make_unique<TestView>());
5102 EXPECT_TRUE(test_view_child_2->native_theme_);
5103 EXPECT_EQ(widget->GetNativeTheme(), test_view_child_2->native_theme_);
5104
5105 widget->CloseNow();
5106 }
5107
5108 class TestEventHandler : public ui::EventHandler {
5109 public:
TestEventHandler(TestView * view)5110 explicit TestEventHandler(TestView* view)
5111 : view_(view), had_mouse_event_(false) {}
5112 ~TestEventHandler() override = default;
5113
OnMouseEvent(ui::MouseEvent * event)5114 void OnMouseEvent(ui::MouseEvent* event) override {
5115 // The |view_| should have received the event first.
5116 EXPECT_EQ(ui::ET_MOUSE_PRESSED, view_->last_mouse_event_type_);
5117 had_mouse_event_ = true;
5118 }
5119
5120 TestView* view_;
5121 bool had_mouse_event_;
5122 };
5123
TEST_F(ViewTest,ScopedTargetHandlerReceivesEvents)5124 TEST_F(ViewTest, ScopedTargetHandlerReceivesEvents) {
5125 std::unique_ptr<Widget> widget(new Widget);
5126 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
5127 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
5128 params.bounds = gfx::Rect(50, 50, 350, 350);
5129 widget->Init(std::move(params));
5130 View* root = widget->GetRootView();
5131 TestView* v = root->AddChildView(std::make_unique<TestView>());
5132 v->SetBoundsRect(gfx::Rect(0, 0, 300, 300));
5133 v->Reset();
5134 {
5135 TestEventHandler handler(v);
5136 ui::ScopedTargetHandler scoped_target_handler(v, &handler);
5137 // View's target EventHandler should be set to the |scoped_target_handler|.
5138 EXPECT_EQ(&scoped_target_handler,
5139 v->SetTargetHandler(&scoped_target_handler));
5140
5141 EXPECT_EQ(ui::ET_UNKNOWN, v->last_mouse_event_type_);
5142 gfx::Point p(10, 120);
5143 ui::MouseEvent pressed(ui::ET_MOUSE_PRESSED, p, p, ui::EventTimeForNow(),
5144 ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
5145 root->OnMousePressed(pressed);
5146
5147 // Both the View |v| and the |handler| should have received the event.
5148 EXPECT_EQ(ui::ET_MOUSE_PRESSED, v->last_mouse_event_type_);
5149 EXPECT_TRUE(handler.had_mouse_event_);
5150 }
5151
5152 // The View should continue receiving events after the |handler| is deleted.
5153 v->Reset();
5154 ui::MouseEvent released(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(),
5155 ui::EventTimeForNow(), 0, 0);
5156 root->OnMouseReleased(released);
5157 EXPECT_EQ(ui::ET_MOUSE_RELEASED, v->last_mouse_event_type_);
5158 }
5159
5160 // See comment above test for details.
5161 class WidgetWithCustomTheme : public Widget {
5162 public:
WidgetWithCustomTheme(ui::NativeTheme * theme)5163 explicit WidgetWithCustomTheme(ui::NativeTheme* theme) : theme_(theme) {}
5164 ~WidgetWithCustomTheme() override = default;
5165
5166 // Widget:
GetNativeTheme() const5167 const ui::NativeTheme* GetNativeTheme() const override { return theme_; }
5168
5169 private:
5170 ui::NativeTheme* theme_;
5171
5172 DISALLOW_COPY_AND_ASSIGN(WidgetWithCustomTheme);
5173 };
5174
5175 // See comment above test for details.
5176 class ViewThatAddsViewInOnThemeChanged : public View {
5177 public:
ViewThatAddsViewInOnThemeChanged()5178 ViewThatAddsViewInOnThemeChanged() { SetPaintToLayer(); }
5179 ~ViewThatAddsViewInOnThemeChanged() override = default;
5180
on_native_theme_changed_called() const5181 bool on_native_theme_changed_called() const {
5182 return on_native_theme_changed_called_;
5183 }
5184
5185 // View:
OnThemeChanged()5186 void OnThemeChanged() override {
5187 View::OnThemeChanged();
5188 on_native_theme_changed_called_ = true;
5189 GetWidget()->GetRootView()->AddChildView(std::make_unique<View>());
5190 }
5191
5192 private:
5193 bool on_native_theme_changed_called_ = false;
5194
5195 DISALLOW_COPY_AND_ASSIGN(ViewThatAddsViewInOnThemeChanged);
5196 };
5197
5198 // Creates and adds a new child view to |parent| that has a layer.
AddViewWithChildLayer(View * parent)5199 void AddViewWithChildLayer(View* parent) {
5200 View* child = parent->AddChildView(std::make_unique<View>());
5201 child->SetPaintToLayer();
5202 }
5203
5204 // This test does the following:
5205 // . creates a couple of views with layers added to the root.
5206 // . Add a view that overrides OnThemeChanged(). In OnThemeChanged() another
5207 // view is added. This sequence triggered DCHECKs or crashes previously. This
5208 // tests verifies that doesn't happen. Reason for crash was OnThemeChanged() was
5209 // called before the layer hierarchy was updated. OnThemeChanged() should be
5210 // called after the layer hierarchy matches the view hierarchy.
TEST_F(ViewTest,CrashOnAddFromFromOnThemeChanged)5211 TEST_F(ViewTest, CrashOnAddFromFromOnThemeChanged) {
5212 ui::TestNativeTheme theme;
5213 WidgetWithCustomTheme widget(&theme);
5214 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
5215 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
5216 params.bounds = gfx::Rect(50, 50, 350, 350);
5217 widget.Init(std::move(params));
5218
5219 AddViewWithChildLayer(widget.GetRootView());
5220 ViewThatAddsViewInOnThemeChanged* v = widget.GetRootView()->AddChildView(
5221 std::make_unique<ViewThatAddsViewInOnThemeChanged>());
5222 EXPECT_TRUE(v->on_native_theme_changed_called());
5223 }
5224
5225 // A View that removes its Layer when hidden.
5226 class NoLayerWhenHiddenView : public View {
5227 public:
5228 using RemovedFromWidgetCallback = base::OnceCallback<void()>;
NoLayerWhenHiddenView(RemovedFromWidgetCallback removed_from_widget)5229 explicit NoLayerWhenHiddenView(RemovedFromWidgetCallback removed_from_widget)
5230 : removed_from_widget_(std::move(removed_from_widget)) {
5231 SetPaintToLayer();
5232 SetBounds(0, 0, 100, 100);
5233 }
5234
was_hidden() const5235 bool was_hidden() const { return was_hidden_; }
5236
5237 // View:
VisibilityChanged(View * starting_from,bool is_visible)5238 void VisibilityChanged(View* starting_from, bool is_visible) override {
5239 if (!is_visible) {
5240 was_hidden_ = true;
5241 DestroyLayer();
5242 }
5243 }
5244
RemovedFromWidget()5245 void RemovedFromWidget() override {
5246 if (removed_from_widget_)
5247 std::move(removed_from_widget_).Run();
5248 }
5249
5250 private:
5251 bool was_hidden_ = false;
5252 RemovedFromWidgetCallback removed_from_widget_;
5253
5254 DISALLOW_COPY_AND_ASSIGN(NoLayerWhenHiddenView);
5255 };
5256
5257 // Test that Views can safely manipulate Layers during Widget closure.
TEST_F(ViewTest,DestroyLayerInClose)5258 TEST_F(ViewTest, DestroyLayerInClose) {
5259 bool removed_from_widget = false;
5260 auto widget = std::make_unique<Widget>();
5261 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
5262 widget->Init(std::move(params));
5263 widget->SetBounds(gfx::Rect(0, 0, 100, 100));
5264 auto* view = widget->GetContentsView()->AddChildView(
5265 std::make_unique<NoLayerWhenHiddenView>(base::BindOnce(
5266 [](bool* removed_from_widget) { *removed_from_widget = true; },
5267 &removed_from_widget)));
5268 widget->Show();
5269
5270 EXPECT_TRUE(view->layer());
5271 EXPECT_TRUE(view->GetWidget());
5272 EXPECT_FALSE(view->was_hidden());
5273
5274 // Release and close the widget. It will be destroyed once it closes.
5275 widget.release()->Close();
5276 EXPECT_FALSE(view->layer());
5277 // Ensure the layer went away via VisibilityChanged().
5278 EXPECT_TRUE(view->was_hidden());
5279
5280 // Not removed from Widget until Close() completes.
5281 EXPECT_FALSE(removed_from_widget);
5282 base::RunLoop().RunUntilIdle(); // Let the Close() complete.
5283 EXPECT_TRUE(removed_from_widget);
5284 }
5285
5286 // A View that keeps the children with a special ID above other children.
5287 class OrderableView : public View {
5288 public:
5289 // ID used by the children that are stacked above other children.
5290 static constexpr int VIEW_ID_RAISED = 1000;
5291
5292 OrderableView() = default;
5293 ~OrderableView() override = default;
5294
GetChildrenInZOrder()5295 View::Views GetChildrenInZOrder() override {
5296 View::Views children_in_z_order = children();
5297 std::stable_partition(
5298 children_in_z_order.begin(), children_in_z_order.end(),
5299 [](const View* child) { return child->GetID() != VIEW_ID_RAISED; });
5300 return children_in_z_order;
5301 }
5302
5303 private:
5304 DISALLOW_COPY_AND_ASSIGN(OrderableView);
5305 };
5306
TEST_F(ViewTest,ChildViewZOrderChanged)5307 TEST_F(ViewTest, ChildViewZOrderChanged) {
5308 const size_t kNumChildren = 4;
5309 auto view = std::make_unique<OrderableView>();
5310 view->SetPaintToLayer();
5311 for (size_t i = 0; i < kNumChildren; ++i)
5312 AddViewWithChildLayer(view.get());
5313 View::Views children = view->GetChildrenInZOrder();
5314 const std::vector<ui::Layer*>& layers = view->layer()->children();
5315 ASSERT_EQ(kNumChildren, children.size());
5316 ASSERT_EQ(kNumChildren, layers.size());
5317 for (size_t i = 0; i < kNumChildren; ++i) {
5318 EXPECT_EQ(view->children()[i], children[i]);
5319 EXPECT_EQ(view->children()[i]->layer(), layers[i]);
5320 }
5321
5322 // Raise one of the children in z-order and add another child to reorder.
5323 view->children()[2]->SetID(OrderableView::VIEW_ID_RAISED);
5324 AddViewWithChildLayer(view.get());
5325
5326 // 2nd child should be now on top, i.e. the last element in the array returned
5327 // by GetChildrenInZOrder(). Its layer should also be above the others.
5328 // The rest of the children and layers order should be unchanged.
5329 const size_t expected_order[] = {0, 1, 3, 4, 2};
5330 children = view->GetChildrenInZOrder();
5331 EXPECT_EQ(kNumChildren + 1, children.size());
5332 EXPECT_EQ(kNumChildren + 1, layers.size());
5333 for (size_t i = 0; i < kNumChildren + 1; ++i) {
5334 EXPECT_EQ(view->children()[expected_order[i]], children[i]);
5335 EXPECT_EQ(view->children()[expected_order[i]]->layer(), layers[i]);
5336 }
5337 }
5338
TEST_F(ViewTest,AttachChildViewWithComplicatedLayers)5339 TEST_F(ViewTest, AttachChildViewWithComplicatedLayers) {
5340 std::unique_ptr<View> grand_parent_view = std::make_unique<View>();
5341 grand_parent_view->SetPaintToLayer();
5342
5343 auto parent_view = std::make_unique<OrderableView>();
5344 parent_view->SetPaintToLayer();
5345
5346 // child_view1 has layer and has id OrderableView::VIEW_ID_RAISED.
5347 View* child_view1 = parent_view->AddChildView(std::make_unique<View>());
5348 child_view1->SetPaintToLayer();
5349 child_view1->SetID(OrderableView::VIEW_ID_RAISED);
5350
5351 // child_view2 has no layer.
5352 View* child_view2 = parent_view->AddChildView(std::make_unique<View>());
5353 // grand_child_view has layer.
5354 View* grand_child_view = child_view2->AddChildView(std::make_unique<View>());
5355 grand_child_view->SetPaintToLayer();
5356 const std::vector<ui::Layer*>& layers = parent_view->layer()->children();
5357 EXPECT_EQ(2u, layers.size());
5358 EXPECT_EQ(layers[0], grand_child_view->layer());
5359 EXPECT_EQ(layers[1], child_view1->layer());
5360
5361 // Attach parent_view to grand_parent_view. children layers of parent_view
5362 // should not change.
5363 auto* parent_view_ptr =
5364 grand_parent_view->AddChildView(std::move(parent_view));
5365 const std::vector<ui::Layer*>& layers_after_attached =
5366 parent_view_ptr->layer()->children();
5367 EXPECT_EQ(2u, layers_after_attached.size());
5368 EXPECT_EQ(layers_after_attached[0], grand_child_view->layer());
5369 EXPECT_EQ(layers_after_attached[1], child_view1->layer());
5370 }
5371
TEST_F(ViewTest,TestEnabledPropertyMetadata)5372 TEST_F(ViewTest, TestEnabledPropertyMetadata) {
5373 auto test_view = std::make_unique<View>();
5374 bool enabled_changed = false;
5375 auto subscription = test_view->AddEnabledChangedCallback(base::BindRepeating(
5376 [](bool* enabled_changed) { *enabled_changed = true; },
5377 &enabled_changed));
5378 views::metadata::ClassMetaData* view_metadata = View::MetaData();
5379 ASSERT_TRUE(view_metadata);
5380 views::metadata::MemberMetaDataBase* enabled_property =
5381 view_metadata->FindMemberData("Enabled");
5382 ASSERT_TRUE(enabled_property);
5383 base::string16 false_value = base::ASCIIToUTF16("false");
5384 enabled_property->SetValueAsString(test_view.get(), false_value);
5385 EXPECT_TRUE(enabled_changed);
5386 EXPECT_FALSE(test_view->GetEnabled());
5387 EXPECT_EQ(enabled_property->GetValueAsString(test_view.get()), false_value);
5388 }
5389
TEST_F(ViewTest,TestEnabledChangedCallback)5390 TEST_F(ViewTest, TestEnabledChangedCallback) {
5391 auto test_view = std::make_unique<View>();
5392 bool enabled_changed = false;
5393 auto subscription = test_view->AddEnabledChangedCallback(base::BindRepeating(
5394 [](bool* enabled_changed) { *enabled_changed = true; },
5395 &enabled_changed));
5396 test_view->SetEnabled(false);
5397 EXPECT_TRUE(enabled_changed);
5398 EXPECT_FALSE(test_view->GetEnabled());
5399 }
5400
TEST_F(ViewTest,TestVisibleChangedCallback)5401 TEST_F(ViewTest, TestVisibleChangedCallback) {
5402 auto test_view = std::make_unique<View>();
5403 bool visibility_changed = false;
5404 auto subscription = test_view->AddVisibleChangedCallback(base::BindRepeating(
5405 [](bool* visibility_changed) { *visibility_changed = true; },
5406 &visibility_changed));
5407 test_view->SetVisible(false);
5408 EXPECT_TRUE(visibility_changed);
5409 EXPECT_FALSE(test_view->GetVisible());
5410 }
5411
TEST_F(ViewTest,TooltipShowsForDisabledView)5412 TEST_F(ViewTest, TooltipShowsForDisabledView) {
5413 auto widget = std::make_unique<Widget>();
5414 Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
5415 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
5416 widget->Init(std::move(params));
5417 widget->SetBounds(gfx::Rect(0, 0, 100, 100));
5418
5419 View enabled_parent;
5420 View* const disabled_child =
5421 enabled_parent.AddChildView(std::make_unique<View>());
5422 disabled_child->SetEnabled(false);
5423
5424 enabled_parent.SetBoundsRect(gfx::Rect(0, 0, 100, 100));
5425 disabled_child->SetBoundsRect(gfx::Rect(0, 0, 100, 100));
5426 widget->GetContentsView()->AddChildView(&enabled_parent);
5427 widget->Show();
5428
5429 EXPECT_EQ(disabled_child,
5430 enabled_parent.GetTooltipHandlerForPoint(gfx::Point(50, 50)));
5431 }
5432
5433 ////////////////////////////////////////////////////////////////////////////////
5434 // Observer tests.
5435 ////////////////////////////////////////////////////////////////////////////////
5436
5437 class ViewObserverTest : public ViewTest, public ViewObserver {
5438 public:
5439 ViewObserverTest() = default;
5440
5441 ~ViewObserverTest() override = default;
5442
5443 // ViewObserver:
OnChildViewAdded(View * parent,View * child)5444 void OnChildViewAdded(View* parent, View* child) override {
5445 child_view_added_times_++;
5446 child_view_added_ = child;
5447 child_view_added_parent_ = parent;
5448 }
OnChildViewRemoved(View * parent,View * child)5449 void OnChildViewRemoved(View* parent, View* child) override {
5450 child_view_removed_times_++;
5451 child_view_removed_ = child;
5452 child_view_removed_parent_ = parent;
5453 }
5454
OnViewVisibilityChanged(View * view,View * starting_view)5455 void OnViewVisibilityChanged(View* view, View* starting_view) override {
5456 view_visibility_changed_ = view;
5457 view_visibility_changed_starting_ = starting_view;
5458 }
5459
OnViewBoundsChanged(View * view)5460 void OnViewBoundsChanged(View* view) override { view_bounds_changed_ = view; }
5461
OnChildViewReordered(View * parent,View * view)5462 void OnChildViewReordered(View* parent, View* view) override {
5463 view_reordered_ = view;
5464 }
5465
reset()5466 void reset() {
5467 child_view_added_times_ = 0;
5468 child_view_removed_times_ = 0;
5469 child_view_added_ = nullptr;
5470 child_view_added_parent_ = nullptr;
5471 child_view_removed_ = nullptr;
5472 child_view_removed_parent_ = nullptr;
5473 view_visibility_changed_ = nullptr;
5474 view_bounds_changed_ = nullptr;
5475 view_reordered_ = nullptr;
5476 }
5477
NewView()5478 std::unique_ptr<View> NewView() {
5479 auto view = std::make_unique<View>();
5480 view->AddObserver(this);
5481 return view;
5482 }
5483
child_view_added_times()5484 int child_view_added_times() { return child_view_added_times_; }
child_view_removed_times()5485 int child_view_removed_times() { return child_view_removed_times_; }
child_view_added() const5486 const View* child_view_added() const { return child_view_added_; }
child_view_added_parent() const5487 const View* child_view_added_parent() const {
5488 return child_view_added_parent_;
5489 }
child_view_removed() const5490 const View* child_view_removed() const { return child_view_removed_; }
child_view_removed_parent() const5491 const View* child_view_removed_parent() const {
5492 return child_view_removed_parent_;
5493 }
view_visibility_changed() const5494 const View* view_visibility_changed() const {
5495 return view_visibility_changed_;
5496 }
view_visibility_changed_starting() const5497 const View* view_visibility_changed_starting() const {
5498 return view_visibility_changed_starting_;
5499 }
view_bounds_changed() const5500 const View* view_bounds_changed() const { return view_bounds_changed_; }
view_reordered() const5501 const View* view_reordered() const { return view_reordered_; }
5502
5503 private:
5504 int child_view_added_times_ = 0;
5505 int child_view_removed_times_ = 0;
5506
5507 View* child_view_added_parent_ = nullptr;
5508 View* child_view_added_ = nullptr;
5509 View* child_view_removed_ = nullptr;
5510 View* child_view_removed_parent_ = nullptr;
5511 View* view_visibility_changed_ = nullptr;
5512 View* view_visibility_changed_starting_ = nullptr;
5513 View* view_bounds_changed_ = nullptr;
5514 View* view_reordered_ = nullptr;
5515
5516 DISALLOW_COPY_AND_ASSIGN(ViewObserverTest);
5517 };
5518
TEST_F(ViewObserverTest,ViewParentChanged)5519 TEST_F(ViewObserverTest, ViewParentChanged) {
5520 std::unique_ptr<View> parent1 = NewView();
5521 std::unique_ptr<View> parent2 = NewView();
5522 std::unique_ptr<View> child_view = NewView();
5523
5524 parent1->AddChildView(child_view.get());
5525 EXPECT_EQ(0, child_view_removed_times());
5526 EXPECT_EQ(1, child_view_added_times());
5527 EXPECT_EQ(child_view.get(), child_view_added());
5528 EXPECT_EQ(child_view->parent(), child_view_added_parent());
5529 EXPECT_EQ(child_view->parent(), parent1.get());
5530 reset();
5531
5532 // Removed from parent1, added to parent2
5533 parent1->RemoveChildView(child_view.get());
5534 parent2->AddChildView(child_view.get());
5535 EXPECT_EQ(1, child_view_removed_times());
5536 EXPECT_EQ(1, child_view_added_times());
5537 EXPECT_EQ(child_view.get(), child_view_removed());
5538 EXPECT_EQ(parent1.get(), child_view_removed_parent());
5539 EXPECT_EQ(child_view.get(), child_view_added());
5540 EXPECT_EQ(child_view->parent(), parent2.get());
5541
5542 reset();
5543
5544 parent2->RemoveChildView(child_view.get());
5545 EXPECT_EQ(1, child_view_removed_times());
5546 EXPECT_EQ(0, child_view_added_times());
5547 EXPECT_EQ(child_view.get(), child_view_removed());
5548 EXPECT_EQ(parent2.get(), child_view_removed_parent());
5549 }
5550
TEST_F(ViewObserverTest,ViewVisibilityChanged)5551 TEST_F(ViewObserverTest, ViewVisibilityChanged) {
5552 std::unique_ptr<View> parent(new View);
5553 View* view = parent->AddChildView(NewView());
5554
5555 // Ensure setting |view| itself not visible calls the observer.
5556 view->SetVisible(false);
5557 EXPECT_EQ(view, view_visibility_changed());
5558 EXPECT_EQ(view, view_visibility_changed_starting());
5559 reset();
5560
5561 // Ditto for setting it visible.
5562 view->SetVisible(true);
5563 EXPECT_EQ(view, view_visibility_changed());
5564 EXPECT_EQ(view, view_visibility_changed_starting());
5565 reset();
5566
5567 // Ensure setting |parent| not visible also calls the
5568 // observer. |view->GetVisible()| should still return true however.
5569 parent->SetVisible(false);
5570 EXPECT_EQ(view, view_visibility_changed());
5571 EXPECT_EQ(parent.get(), view_visibility_changed_starting());
5572 }
5573
TEST_F(ViewObserverTest,ViewBoundsChanged)5574 TEST_F(ViewObserverTest, ViewBoundsChanged) {
5575 std::unique_ptr<View> view = NewView();
5576 gfx::Rect bounds(2, 2, 2, 2);
5577 view->SetBoundsRect(bounds);
5578 EXPECT_EQ(view.get(), view_bounds_changed());
5579 EXPECT_EQ(bounds, view->bounds());
5580
5581 reset();
5582
5583 gfx::Rect new_bounds(1, 1, 1, 1);
5584 view->SetBoundsRect(new_bounds);
5585 EXPECT_EQ(view.get(), view_bounds_changed());
5586 EXPECT_EQ(new_bounds, view->bounds());
5587 }
5588
TEST_F(ViewObserverTest,ChildViewReordered)5589 TEST_F(ViewObserverTest, ChildViewReordered) {
5590 std::unique_ptr<View> view = NewView();
5591 view->AddChildView(NewView());
5592 View* child_view2 = view->AddChildView(NewView());
5593 view->ReorderChildView(child_view2, 0);
5594 EXPECT_EQ(child_view2, view_reordered());
5595 }
5596
5597 // Provides a simple parent view implementation which tracks layer change
5598 // notifications from child views.
5599 class TestParentView : public View {
5600 public:
5601 TestParentView() = default;
5602
Reset()5603 void Reset() {
5604 received_layer_change_notification_ = false;
5605 layer_change_count_ = 0;
5606 }
5607
received_layer_change_notification() const5608 bool received_layer_change_notification() const {
5609 return received_layer_change_notification_;
5610 }
5611
layer_change_count() const5612 int layer_change_count() const { return layer_change_count_; }
5613
5614 // View overrides.
OnChildLayerChanged(View * child)5615 void OnChildLayerChanged(View* child) override {
5616 received_layer_change_notification_ = true;
5617 layer_change_count_++;
5618 }
5619
5620 private:
5621 // Set to true if we receive the OnChildLayerChanged() notification for a
5622 // child.
5623 bool received_layer_change_notification_ = false;
5624
5625 // Contains the number of OnChildLayerChanged() notifications for a child.
5626 int layer_change_count_ = 0;
5627
5628 DISALLOW_COPY_AND_ASSIGN(TestParentView);
5629 };
5630
5631 // Tests the following cases.
5632 // 1. We receive the OnChildLayerChanged() notification when a layer change
5633 // occurs in a child view.
5634 // 2. We don't receive two layer changes when a child with an existing layer
5635 // creates a new layer.
TEST_F(ViewObserverTest,ChildViewLayerNotificationTest)5636 TEST_F(ViewObserverTest, ChildViewLayerNotificationTest) {
5637 std::unique_ptr<TestParentView> parent_view(new TestParentView);
5638 std::unique_ptr<View> child_view = NewView();
5639 parent_view->AddChildView(child_view.get());
5640
5641 EXPECT_FALSE(parent_view->received_layer_change_notification());
5642 EXPECT_EQ(0, parent_view->layer_change_count());
5643
5644 child_view->SetPaintToLayer(ui::LAYER_TEXTURED);
5645 EXPECT_TRUE(parent_view->received_layer_change_notification());
5646 EXPECT_EQ(1, parent_view->layer_change_count());
5647
5648 parent_view->Reset();
5649 child_view->SetPaintToLayer(ui::LAYER_SOLID_COLOR);
5650 EXPECT_TRUE(parent_view->received_layer_change_notification());
5651 EXPECT_EQ(1, parent_view->layer_change_count());
5652 }
5653
5654 } // namespace views
5655