OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/ui/views/tabs/tab_strip.h" | 5 #include "chrome/browser/ui/views/tabs/tab_strip.h" |
6 | 6 |
7 #include "base/macros.h" | 7 #include "base/macros.h" |
8 #include "base/message_loop/message_loop.h" | 8 #include "base/message_loop/message_loop.h" |
| 9 #include "chrome/browser/ui/layout_constants.h" |
9 #include "chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.h" | 10 #include "chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.h" |
10 #include "chrome/browser/ui/views/tabs/tab.h" | 11 #include "chrome/browser/ui/views/tabs/tab.h" |
11 #include "chrome/browser/ui/views/tabs/tab_renderer_data.h" | 12 #include "chrome/browser/ui/views/tabs/tab_renderer_data.h" |
12 #include "chrome/browser/ui/views/tabs/tab_strip.h" | 13 #include "chrome/browser/ui/views/tabs/tab_strip.h" |
13 #include "chrome/browser/ui/views/tabs/tab_strip_controller.h" | 14 #include "chrome/browser/ui/views/tabs/tab_strip_controller.h" |
14 #include "chrome/browser/ui/views/tabs/tab_strip_observer.h" | 15 #include "chrome/browser/ui/views/tabs/tab_strip_observer.h" |
15 #include "chrome/test/base/testing_profile.h" | 16 #include "chrome/test/base/testing_profile.h" |
16 #include "testing/gtest/include/gtest/gtest.h" | 17 #include "testing/gtest/include/gtest/gtest.h" |
17 #include "ui/base/material_design/material_design_controller.h" | 18 #include "ui/base/material_design/material_design_controller.h" |
18 #include "ui/gfx/canvas.h" | 19 #include "ui/gfx/canvas.h" |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
126 widget_.reset(); | 127 widget_.reset(); |
127 views::ViewsTestBase::TearDown(); | 128 views::ViewsTestBase::TearDown(); |
128 } | 129 } |
129 | 130 |
130 protected: | 131 protected: |
131 bool IsShowingPinnedTabTitleChangedIndicator(int model_index) { | 132 bool IsShowingPinnedTabTitleChangedIndicator(int model_index) { |
132 return tab_strip_->tab_at(model_index) | 133 return tab_strip_->tab_at(model_index) |
133 ->showing_pinned_tab_title_changed_indicator_; | 134 ->showing_pinned_tab_title_changed_indicator_; |
134 } | 135 } |
135 | 136 |
136 // Returns the rectangular hit test region of |tab| in |tab|'s local | |
137 // coordinate space. | |
138 gfx::Rect GetTabHitTestMask(Tab* tab) { | |
139 views::ViewTargeter* targeter = tab->targeter(); | |
140 DCHECK(targeter); | |
141 views::MaskedTargeterDelegate* delegate = | |
142 static_cast<views::MaskedTargeterDelegate*>(tab); | |
143 | |
144 gfx::Path mask; | |
145 bool valid_mask = delegate->GetHitTestMask(&mask); | |
146 DCHECK(valid_mask); | |
147 | |
148 return gfx::ToEnclosingRect((gfx::SkRectToRectF(mask.getBounds()))); | |
149 } | |
150 | |
151 // Returns the rectangular hit test region of the tab close button of | |
152 // |tab| in |tab|'s coordinate space (including padding if |padding| | |
153 // is true). | |
154 gfx::Rect GetTabCloseHitTestMask(Tab* tab, bool padding) { | |
155 gfx::RectF bounds_f = gfx::RectF(tab->close_button_->GetContentsBounds()); | |
156 if (padding) | |
157 bounds_f = gfx::RectF(tab->close_button_->GetLocalBounds()); | |
158 views::View::ConvertRectToTarget(tab->close_button_, tab, &bounds_f); | |
159 return gfx::ToEnclosingRect(bounds_f); | |
160 } | |
161 | |
162 // Checks whether |tab| contains |point_in_tabstrip_coords|, where the point | 137 // Checks whether |tab| contains |point_in_tabstrip_coords|, where the point |
163 // is in |tab_strip_| coordinates. | 138 // is in |tab_strip_| coordinates. |
164 bool IsPointInTab(Tab* tab, const gfx::Point& point_in_tabstrip_coords) { | 139 bool IsPointInTab(Tab* tab, const gfx::Point& point_in_tabstrip_coords) { |
165 gfx::Point point_in_tab_coords(point_in_tabstrip_coords); | 140 gfx::Point point_in_tab_coords(point_in_tabstrip_coords); |
166 views::View::ConvertPointToTarget(tab_strip_, tab, &point_in_tab_coords); | 141 views::View::ConvertPointToTarget(tab_strip_, tab, &point_in_tab_coords); |
167 return tab->HitTestPoint(point_in_tab_coords); | 142 return tab->HitTestPoint(point_in_tab_coords); |
168 } | 143 } |
169 | 144 |
170 void DoLayout() { tab_strip_->DoLayout(); } | 145 void DoLayout() { tab_strip_->DoLayout(); } |
171 | 146 |
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
319 EXPECT_TRUE(tab_strip_->IsImmersiveStyle()); | 294 EXPECT_TRUE(tab_strip_->IsImmersiveStyle()); |
320 | 295 |
321 // Now tabs have the immersive height. | 296 // Now tabs have the immersive height. |
322 int immersive_height = Tab::GetImmersiveHeight(); | 297 int immersive_height = Tab::GetImmersiveHeight(); |
323 EXPECT_EQ(immersive_height, tab_strip_->GetPreferredSize().height()); | 298 EXPECT_EQ(immersive_height, tab_strip_->GetPreferredSize().height()); |
324 | 299 |
325 // Sanity-check immersive tabs are shorter than normal tabs. | 300 // Sanity-check immersive tabs are shorter than normal tabs. |
326 EXPECT_LT(immersive_height, normal_height); | 301 EXPECT_LT(immersive_height, normal_height); |
327 } | 302 } |
328 | 303 |
329 // Creates a tab strip in stacked layout mode and verifies the correctness | 304 // Creates a tab strip in stacked layout mode and verifies that as we move |
330 // of hit tests against the visible/occluded regions of a tab and the tab | 305 // across the strip at the top, middle, and bottom, events will target each tab |
331 // close button of the active tab. | 306 // in order. |
332 // TODO(pkasting): Update the test for Material Design layout. | 307 TEST_F(TabStripTest, TabForEventWhenStacked) { |
333 // crbug.com/575327 | 308 tab_strip_->SetBounds(0, 0, 200, GetLayoutConstant(TAB_HEIGHT)); |
334 TEST_F(TabStripTest, DISABLED_TabHitTestMaskWhenStacked) { | |
335 tab_strip_->SetBounds(0, 0, 300, 20); | |
336 | 309 |
337 controller_->AddTab(0, false); | 310 controller_->AddTab(0, false); |
338 controller_->AddTab(1, true); | 311 controller_->AddTab(1, true); |
339 controller_->AddTab(2, false); | 312 controller_->AddTab(2, false); |
340 controller_->AddTab(3, false); | 313 controller_->AddTab(3, false); |
341 ASSERT_EQ(4, tab_strip_->tab_count()); | 314 ASSERT_EQ(4, tab_strip_->tab_count()); |
342 | 315 |
343 Tab* left_tab = tab_strip_->tab_at(0); | |
344 left_tab->SetBoundsRect(gfx::Rect(gfx::Point(0, 0), gfx::Size(200, 20))); | |
345 | |
346 Tab* active_tab = tab_strip_->tab_at(1); | |
347 active_tab->SetBoundsRect(gfx::Rect(gfx::Point(150, 0), gfx::Size(200, 20))); | |
348 ASSERT_TRUE(active_tab->IsActive()); | |
349 | |
350 Tab* right_tab = tab_strip_->tab_at(2); | |
351 right_tab->SetBoundsRect(gfx::Rect(gfx::Point(300, 0), gfx::Size(200, 20))); | |
352 | |
353 Tab* most_right_tab = tab_strip_->tab_at(3); | |
354 most_right_tab->SetBoundsRect(gfx::Rect(gfx::Point(450, 0), | |
355 gfx::Size(200, 20))); | |
356 | |
357 // Switch to stacked layout mode and force a layout to ensure tabs stack. | 316 // Switch to stacked layout mode and force a layout to ensure tabs stack. |
358 tab_strip_->SetStackedLayout(true); | 317 tab_strip_->SetStackedLayout(true); |
359 tab_strip_->DoLayout(); | 318 tab_strip_->DoLayout(); |
360 | 319 |
361 // Tests involving |left_tab|, which has part of its bounds occluded by | 320 gfx::Point p; |
362 // |active_tab|. | 321 for (int y : {0, tab_strip_->height() / 2, tab_strip_->height() - 1}) { |
363 | 322 p.set_y(y); |
364 // Bounds of the tab's hit test mask. | 323 int previous_tab = -1; |
365 gfx::Rect tab_bounds = GetTabHitTestMask(left_tab); | 324 for (int x = 0; x < tab_strip_->width(); ++x) { |
366 EXPECT_EQ(gfx::Rect(6, 2, 61, 27).ToString(), tab_bounds.ToString()); | 325 p.set_x(x); |
367 | 326 int tab = tab_strip_->GetModelIndexOfTab(tab_strip_->FindTabForEvent(p)); |
368 // Hit tests in the non-occuluded region of the tab. | 327 if (tab == previous_tab) |
369 EXPECT_TRUE(left_tab->HitTestRect(gfx::Rect(6, 2, 2, 2))); | 328 continue; |
370 EXPECT_TRUE(left_tab->HitTestRect(gfx::Rect(6, 2, 1, 1))); | 329 if ((tab != -1) || (previous_tab != tab_strip_->tab_count() - 1)) |
371 EXPECT_TRUE(left_tab->HitTestRect(gfx::Rect(30, 15, 1, 1))); | 330 EXPECT_EQ(previous_tab + 1, tab) << "p = " << p.ToString(); |
372 EXPECT_TRUE(left_tab->HitTestRect(gfx::Rect(30, 15, 25, 35))); | 331 previous_tab = tab; |
373 EXPECT_TRUE(left_tab->HitTestRect(gfx::Rect(-10, -5, 20, 30))); | 332 } |
374 | 333 } |
375 // Hit tests in the occluded region of the tab. | |
376 EXPECT_FALSE(left_tab->HitTestRect(gfx::Rect(70, 15, 2, 2))); | |
377 EXPECT_FALSE(left_tab->HitTestRect(gfx::Rect(70, -15, 30, 40))); | |
378 EXPECT_FALSE(left_tab->HitTestRect(gfx::Rect(87, 20, 5, 3))); | |
379 | |
380 // Hit tests completely outside of the tab. | |
381 EXPECT_FALSE(left_tab->HitTestRect(gfx::Rect(-20, -25, 1, 1))); | |
382 EXPECT_FALSE(left_tab->HitTestRect(gfx::Rect(-20, -25, 3, 19))); | |
383 | |
384 | |
385 // Tests involving |active_tab|, which is completely visible. | |
386 | |
387 tab_bounds = GetTabHitTestMask(active_tab); | |
388 EXPECT_EQ(gfx::Rect(6, 2, 108, 27).ToString(), tab_bounds.ToString()); | |
389 gfx::Rect contents_bounds = GetTabCloseHitTestMask(active_tab, false); | |
390 // TODO(tdanderson): Uncomment this line once crbug.com/311609 is resolved. | |
391 // EXPECT_EQ(gfx::Rect(84, 8, 18, 18).ToString(), contents_bounds.ToString()); | |
392 | |
393 // Verify that the tab close button is not occluded. | |
394 EXPECT_TRUE(tab_bounds.Contains(contents_bounds)); | |
395 | |
396 // Bounds of the tab close button (with padding) in the tab's coordinate | |
397 // space. | |
398 gfx::Rect local_bounds = GetTabCloseHitTestMask(active_tab, true); | |
399 EXPECT_EQ(gfx::Rect(82, 0, 38, 29).ToString(), local_bounds.ToString()); | |
400 | |
401 // Hit tests within the tab. | |
402 EXPECT_TRUE(active_tab->HitTestRect(gfx::Rect(30, 15, 1, 1))); | |
403 EXPECT_TRUE(active_tab->HitTestRect(gfx::Rect(30, 15, 2, 2))); | |
404 | |
405 // Hit tests against the tab close button. Note that hit tests from either | |
406 // mouse or touch should both fail if they are strictly contained within | |
407 // the button's padding. | |
408 views::ImageButton* active_close = active_tab->close_button_; | |
409 EXPECT_FALSE(active_close->HitTestRect(gfx::Rect(1, 1, 1, 1))); | |
410 EXPECT_FALSE(active_close->HitTestRect(gfx::Rect(1, 1, 2, 2))); | |
411 EXPECT_TRUE(active_close->HitTestRect(gfx::Rect(10, 10, 1, 1))); | |
412 EXPECT_TRUE(active_close->HitTestRect(gfx::Rect(10, 10, 25, 35))); | |
413 | |
414 | |
415 // Tests involving |most_right_tab|, which has part of its bounds occluded | |
416 // by |right_tab|. | |
417 | |
418 tab_bounds = GetTabHitTestMask(most_right_tab); | |
419 EXPECT_EQ(gfx::Rect(84, 2, 30, 27).ToString(), tab_bounds.ToString()); | |
420 | |
421 // Hit tests in the occluded region of the tab. | |
422 EXPECT_FALSE(most_right_tab->HitTestRect(gfx::Rect(20, 15, 1, 1))); | |
423 EXPECT_FALSE(most_right_tab->HitTestRect(gfx::Rect(20, 15, 5, 6))); | |
424 | |
425 // Hit tests in the non-occluded region of the tab. | |
426 EXPECT_TRUE(most_right_tab->HitTestRect(gfx::Rect(85, 15, 1, 1))); | |
427 EXPECT_TRUE(most_right_tab->HitTestRect(gfx::Rect(85, 15, 2, 2))); | |
428 } | 334 } |
429 | 335 |
430 // Tests that the tab close buttons of non-active tabs are hidden when | 336 // Tests that the tab close buttons of non-active tabs are hidden when |
431 // the tabstrip is in stacked tab mode. | 337 // the tabstrip is in stacked tab mode. |
432 TEST_F(TabStripTest, TabCloseButtonVisibilityWhenStacked) { | 338 TEST_F(TabStripTest, TabCloseButtonVisibilityWhenStacked) { |
433 tab_strip_->SetBounds(0, 0, 300, 20); | 339 tab_strip_->SetBounds(0, 0, 300, 20); |
434 controller_->AddTab(0, false); | 340 controller_->AddTab(0, false); |
435 controller_->AddTab(1, true); | 341 controller_->AddTab(1, true); |
436 controller_->AddTab(2, false); | 342 controller_->AddTab(2, false); |
437 ASSERT_EQ(3, tab_strip_->tab_count()); | 343 ASSERT_EQ(3, tab_strip_->tab_count()); |
(...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
652 | 558 |
653 // Change the title of the second tab (first tab is selected). | 559 // Change the title of the second tab (first tab is selected). |
654 tab_strip_->TabTitleChangedNotLoading(1); | 560 tab_strip_->TabTitleChangedNotLoading(1); |
655 // Indicator should be shown. | 561 // Indicator should be shown. |
656 EXPECT_TRUE(IsShowingPinnedTabTitleChangedIndicator(1)); | 562 EXPECT_TRUE(IsShowingPinnedTabTitleChangedIndicator(1)); |
657 // Select the second tab. | 563 // Select the second tab. |
658 controller_->SelectTab(1); | 564 controller_->SelectTab(1); |
659 // Indicator should hide. | 565 // Indicator should hide. |
660 EXPECT_FALSE(IsShowingPinnedTabTitleChangedIndicator(1)); | 566 EXPECT_FALSE(IsShowingPinnedTabTitleChangedIndicator(1)); |
661 } | 567 } |
OLD | NEW |