Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(6)

Side by Side Diff: chrome/browser/ui/views/tabs/tab_unittest.cc

Issue 591963002: Tab audio mute control (views UI), behind a switch (off by default). (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix generated_resources.grd changes for Mac compile. Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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.h" 5 #include "chrome/browser/ui/views/tabs/tab.h"
6 6
7 #include "base/i18n/rtl.h"
7 #include "base/strings/utf_string_conversions.h" 8 #include "base/strings/utf_string_conversions.h"
9 #include "chrome/browser/ui/views/tabs/media_indicator_button.h"
8 #include "chrome/browser/ui/views/tabs/tab_controller.h" 10 #include "chrome/browser/ui/views/tabs/tab_controller.h"
9 #include "testing/gtest/include/gtest/gtest.h" 11 #include "testing/gtest/include/gtest/gtest.h"
10 #include "ui/base/models/list_selection_model.h" 12 #include "ui/base/models/list_selection_model.h"
11 #include "ui/views/controls/button/image_button.h" 13 #include "ui/views/controls/button/image_button.h"
12 #include "ui/views/controls/label.h" 14 #include "ui/views/controls/label.h"
13 #include "ui/views/test/views_test_base.h" 15 #include "ui/views/test/views_test_base.h"
14 #include "ui/views/widget/widget.h" 16 #include "ui/views/widget/widget.h"
15 17
16 using views::Widget; 18 using views::Widget;
17 19
18 class FakeTabController : public TabController { 20 class FakeTabController : public TabController {
19 public: 21 public:
20 FakeTabController() : immersive_style_(false), active_tab_(false) { 22 FakeTabController() : immersive_style_(false), active_tab_(false) {
21 } 23 }
22 virtual ~FakeTabController() {} 24 virtual ~FakeTabController() {}
23 25
24 void set_immersive_style(bool value) { immersive_style_ = value; } 26 void set_immersive_style(bool value) { immersive_style_ = value; }
25 void set_active_tab(bool value) { active_tab_ = value; } 27 void set_active_tab(bool value) { active_tab_ = value; }
26 28
27 virtual const ui::ListSelectionModel& GetSelectionModel() OVERRIDE { 29 virtual const ui::ListSelectionModel& GetSelectionModel() OVERRIDE {
28 return selection_model_; 30 return selection_model_;
29 } 31 }
30 virtual bool SupportsMultipleSelection() OVERRIDE { return false; } 32 virtual bool SupportsMultipleSelection() OVERRIDE { return false; }
31 virtual void SelectTab(Tab* tab) OVERRIDE {} 33 virtual void SelectTab(Tab* tab) OVERRIDE {}
32 virtual void ExtendSelectionTo(Tab* tab) OVERRIDE {} 34 virtual void ExtendSelectionTo(Tab* tab) OVERRIDE {}
33 virtual void ToggleSelected(Tab* tab) OVERRIDE {} 35 virtual void ToggleSelected(Tab* tab) OVERRIDE {}
34 virtual void AddSelectionFromAnchorTo(Tab* tab) OVERRIDE {} 36 virtual void AddSelectionFromAnchorTo(Tab* tab) OVERRIDE {}
35 virtual void CloseTab(Tab* tab, CloseTabSource source) OVERRIDE {} 37 virtual void CloseTab(Tab* tab, CloseTabSource source) OVERRIDE {}
38 virtual void ToggleTabAudioMute(Tab* tab) OVERRIDE {}
36 virtual void ShowContextMenuForTab(Tab* tab, 39 virtual void ShowContextMenuForTab(Tab* tab,
37 const gfx::Point& p, 40 const gfx::Point& p,
38 ui::MenuSourceType source_type) OVERRIDE {} 41 ui::MenuSourceType source_type) OVERRIDE {}
39 virtual bool IsActiveTab(const Tab* tab) const OVERRIDE { 42 virtual bool IsActiveTab(const Tab* tab) const OVERRIDE {
40 return active_tab_; 43 return active_tab_;
41 } 44 }
42 virtual bool IsTabSelected(const Tab* tab) const OVERRIDE { 45 virtual bool IsTabSelected(const Tab* tab) const OVERRIDE {
43 return false; 46 return false;
44 } 47 }
45 virtual bool IsTabPinned(const Tab* tab) const OVERRIDE { return false; } 48 virtual bool IsTabPinned(const Tab* tab) const OVERRIDE { return false; }
(...skipping 18 matching lines...) Expand all
64 ui::AXViewState* state) OVERRIDE{}; 67 ui::AXViewState* state) OVERRIDE{};
65 68
66 private: 69 private:
67 ui::ListSelectionModel selection_model_; 70 ui::ListSelectionModel selection_model_;
68 bool immersive_style_; 71 bool immersive_style_;
69 bool active_tab_; 72 bool active_tab_;
70 73
71 DISALLOW_COPY_AND_ASSIGN(FakeTabController); 74 DISALLOW_COPY_AND_ASSIGN(FakeTabController);
72 }; 75 };
73 76
74 class TabTest : public views::ViewsTestBase { 77 class TabTest : public views::ViewsTestBase,
78 public ::testing::WithParamInterface<bool> {
75 public: 79 public:
76 TabTest() {} 80 TabTest() {}
77 virtual ~TabTest() {} 81 virtual ~TabTest() {}
78 82
79 static void DisableMediaIndicatorAnimation(Tab* tab) { 83 bool testing_for_rtl_locale() const { return GetParam(); }
80 tab->media_indicator_animation_.reset(); 84
81 tab->animating_media_state_ = tab->data_.media_state; 85 virtual void SetUp() OVERRIDE {
86 if (testing_for_rtl_locale()) {
87 original_locale_ = base::i18n::GetConfiguredLocale();
88 base::i18n::SetICUDefaultLocale("he");
89 }
90 views::ViewsTestBase::SetUp();
91 }
92
93 virtual void TearDown() OVERRIDE {
94 views::ViewsTestBase::TearDown();
95 if (testing_for_rtl_locale()) {
sky 2014/09/25 19:25:05 nit: no {}
miu 2014/09/25 22:49:36 Done.
96 base::i18n::SetICUDefaultLocale(original_locale_);
97 }
98 }
99
100 bool ShouldSkipRTLTestOnUnsupportedPlatform() const {
101 if (!testing_for_rtl_locale()) {
102 EXPECT_FALSE(base::i18n::IsRTL());
103 return false;
sky 2014/09/25 19:25:05 I don't get what you're trying to do here. If not
miu 2014/09/25 22:49:36 I thought of a cleaner way to do this to make it m
104 }
105 return !base::i18n::IsRTL();
82 } 106 }
83 107
84 static void CheckForExpectedLayoutAndVisibilityOfElements(const Tab& tab) { 108 static void CheckForExpectedLayoutAndVisibilityOfElements(const Tab& tab) {
85 // Check whether elements are visible when they are supposed to be, given 109 // Check whether elements are visible when they are supposed to be, given
86 // Tab size and TabRendererData state. 110 // Tab size and TabRendererData state.
87 if (tab.data_.mini) { 111 if (tab.data_.mini) {
88 EXPECT_EQ(1, tab.IconCapacity()); 112 EXPECT_EQ(1, tab.IconCapacity());
89 if (tab.data_.media_state != TAB_MEDIA_STATE_NONE) { 113 if (tab.data_.media_state != TAB_MEDIA_STATE_NONE) {
90 EXPECT_FALSE(tab.ShouldShowIcon()); 114 EXPECT_FALSE(tab.ShouldShowIcon());
91 EXPECT_TRUE(tab.ShouldShowMediaIndicator()); 115 EXPECT_TRUE(tab.ShouldShowMediaIndicator());
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
152 // are fully within the contents bounds. 176 // are fully within the contents bounds.
153 const gfx::Rect contents_bounds = tab.GetContentsBounds(); 177 const gfx::Rect contents_bounds = tab.GetContentsBounds();
154 if (tab.ShouldShowIcon()) { 178 if (tab.ShouldShowIcon()) {
155 EXPECT_LE(contents_bounds.x(), tab.favicon_bounds_.x()); 179 EXPECT_LE(contents_bounds.x(), tab.favicon_bounds_.x());
156 if (tab.title_->width() > 0) 180 if (tab.title_->width() > 0)
157 EXPECT_LE(tab.favicon_bounds_.right(), tab.title_->x()); 181 EXPECT_LE(tab.favicon_bounds_.right(), tab.title_->x());
158 EXPECT_LE(contents_bounds.y(), tab.favicon_bounds_.y()); 182 EXPECT_LE(contents_bounds.y(), tab.favicon_bounds_.y());
159 EXPECT_LE(tab.favicon_bounds_.bottom(), contents_bounds.bottom()); 183 EXPECT_LE(tab.favicon_bounds_.bottom(), contents_bounds.bottom());
160 } 184 }
161 if (tab.ShouldShowIcon() && tab.ShouldShowMediaIndicator()) 185 if (tab.ShouldShowIcon() && tab.ShouldShowMediaIndicator())
162 EXPECT_LE(tab.favicon_bounds_.right(), tab.media_indicator_bounds_.x()); 186 EXPECT_LE(tab.favicon_bounds_.right(), GetMediaIndicatorBounds(tab).x());
163 if (tab.ShouldShowMediaIndicator()) { 187 if (tab.ShouldShowMediaIndicator()) {
164 if (tab.title_->width() > 0) { 188 if (tab.title_->width() > 0) {
165 EXPECT_LE(tab.title_->bounds().right(), 189 EXPECT_LE(tab.title_->bounds().right(),
166 tab.media_indicator_bounds_.x()); 190 GetMediaIndicatorBounds(tab).x());
167 } 191 }
168 EXPECT_LE(tab.media_indicator_bounds_.right(), contents_bounds.right()); 192 EXPECT_LE(GetMediaIndicatorBounds(tab).right(), contents_bounds.right());
169 EXPECT_LE(contents_bounds.y(), tab.media_indicator_bounds_.y()); 193 EXPECT_LE(contents_bounds.y(), GetMediaIndicatorBounds(tab).y());
170 EXPECT_LE(tab.media_indicator_bounds_.bottom(), contents_bounds.bottom()); 194 EXPECT_LE(GetMediaIndicatorBounds(tab).bottom(),
195 contents_bounds.bottom());
171 } 196 }
172 if (tab.ShouldShowMediaIndicator() && tab.ShouldShowCloseBox()) { 197 if (tab.ShouldShowMediaIndicator() && tab.ShouldShowCloseBox()) {
173 // Note: The media indicator can overlap the left-insets of the close box, 198 // Note: The media indicator can overlap the left-insets of the close box,
174 // but should otherwise be to the left of the close button. 199 // but should otherwise be to the left of the close button.
175 EXPECT_LE(tab.media_indicator_bounds_.right(), 200 EXPECT_LE(GetMediaIndicatorBounds(tab).right(),
176 tab.close_button_->bounds().x() + 201 tab.close_button_->bounds().x() +
177 tab.close_button_->GetInsets().left()); 202 tab.close_button_->GetInsets().left());
178 } 203 }
179 if (tab.ShouldShowCloseBox()) { 204 if (tab.ShouldShowCloseBox()) {
180 // Note: The title bounds can overlap the left-insets of the close box, 205 // Note: The title bounds can overlap the left-insets of the close box,
181 // but should otherwise be to the left of the close button. 206 // but should otherwise be to the left of the close button.
182 if (tab.title_->width() > 0) { 207 if (tab.title_->width() > 0) {
183 EXPECT_LE(tab.title_->bounds().right(), 208 EXPECT_LE(tab.title_->bounds().right(),
184 tab.close_button_->bounds().x() + 209 tab.close_button_->bounds().x() +
185 tab.close_button_->GetInsets().left()); 210 tab.close_button_->GetInsets().left());
186 } 211 }
187 EXPECT_LE(tab.close_button_->bounds().right(), contents_bounds.right()); 212 EXPECT_LE(tab.close_button_->bounds().right(), contents_bounds.right());
188 EXPECT_LE(contents_bounds.y(), tab.close_button_->bounds().y()); 213 EXPECT_LE(contents_bounds.y(), tab.close_button_->bounds().y());
189 EXPECT_LE(tab.close_button_->bounds().bottom(), contents_bounds.bottom()); 214 EXPECT_LE(tab.close_button_->bounds().bottom(), contents_bounds.bottom());
190 } 215 }
191 } 216 }
217
218 private:
219 static gfx::Rect GetMediaIndicatorBounds(const Tab& tab) {
220 if (!tab.media_indicator_button_) {
221 ADD_FAILURE();
222 return gfx::Rect();
223 }
224 return tab.media_indicator_button_->bounds();
225 }
226
227 std::string original_locale_;
192 }; 228 };
193 229
194 TEST_F(TabTest, HitTestTopPixel) { 230 TEST_P(TabTest, HitTestTopPixel) {
231 if (ShouldSkipRTLTestOnUnsupportedPlatform()) {
232 LOG(WARNING) << "Testing of RTL locale not supported on current platform.";
233 return;
234 }
235
195 Widget widget; 236 Widget widget;
196 Widget::InitParams params(CreateParams(Widget::InitParams::TYPE_WINDOW)); 237 Widget::InitParams params(CreateParams(Widget::InitParams::TYPE_WINDOW));
197 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 238 params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
198 params.bounds.SetRect(10, 20, 300, 400); 239 params.bounds.SetRect(10, 20, 300, 400);
199 widget.Init(params); 240 widget.Init(params);
200 241
201 FakeTabController tab_controller; 242 FakeTabController tab_controller;
202 Tab tab(&tab_controller); 243 Tab tab(&tab_controller);
203 widget.GetContentsView()->AddChildView(&tab); 244 widget.GetContentsView()->AddChildView(&tab);
204 tab.SetBoundsRect(gfx::Rect(gfx::Point(0, 0), Tab::GetStandardSize())); 245 tab.SetBoundsRect(gfx::Rect(gfx::Point(0, 0), Tab::GetStandardSize()));
205 246
206 // Tabs have some shadow in the top, so by default we don't hit the tab there. 247 // Tabs have some shadow in the top, so by default we don't hit the tab there.
207 int middle_x = tab.width() / 2; 248 int middle_x = tab.width() / 2;
208 EXPECT_FALSE(tab.HitTestPoint(gfx::Point(middle_x, 0))); 249 EXPECT_FALSE(tab.HitTestPoint(gfx::Point(middle_x, 0)));
209 250
210 // Tabs are slanted, so a click halfway down the left edge won't hit it. 251 // Tabs are slanted, so a click halfway down the left edge won't hit it.
211 int middle_y = tab.height() / 2; 252 int middle_y = tab.height() / 2;
212 EXPECT_FALSE(tab.HitTestPoint(gfx::Point(0, middle_y))); 253 EXPECT_FALSE(tab.HitTestPoint(gfx::Point(0, middle_y)));
213 254
214 // If the window is maximized, however, we want clicks in the top edge to 255 // If the window is maximized, however, we want clicks in the top edge to
215 // select the tab. 256 // select the tab.
216 widget.Maximize(); 257 widget.Maximize();
217 EXPECT_TRUE(tab.HitTestPoint(gfx::Point(middle_x, 0))); 258 EXPECT_TRUE(tab.HitTestPoint(gfx::Point(middle_x, 0)));
218 259
219 // But clicks in the area above the slanted sides should still miss. 260 // But clicks in the area above the slanted sides should still miss.
220 EXPECT_FALSE(tab.HitTestPoint(gfx::Point(0, 0))); 261 EXPECT_FALSE(tab.HitTestPoint(gfx::Point(0, 0)));
221 EXPECT_FALSE(tab.HitTestPoint(gfx::Point(tab.width() - 1, 0))); 262 EXPECT_FALSE(tab.HitTestPoint(gfx::Point(tab.width() - 1, 0)));
222 } 263 }
223 264
224 TEST_F(TabTest, LayoutAndVisibilityOfElements) { 265 TEST_P(TabTest, LayoutAndVisibilityOfElements) {
266 if (ShouldSkipRTLTestOnUnsupportedPlatform()) {
267 LOG(WARNING) << "Testing of RTL locale not supported on current platform.";
268 return;
269 }
270
225 static const TabMediaState kMediaStatesToTest[] = { 271 static const TabMediaState kMediaStatesToTest[] = {
226 TAB_MEDIA_STATE_NONE, TAB_MEDIA_STATE_CAPTURING, 272 TAB_MEDIA_STATE_NONE, TAB_MEDIA_STATE_CAPTURING,
227 TAB_MEDIA_STATE_AUDIO_PLAYING 273 TAB_MEDIA_STATE_AUDIO_PLAYING, TAB_MEDIA_STATE_AUDIO_MUTING
228 }; 274 };
229 275
230 FakeTabController controller; 276 FakeTabController controller;
231 Tab tab(&controller); 277 Tab tab(&controller);
232 278
233 SkBitmap bitmap; 279 SkBitmap bitmap;
234 bitmap.allocN32Pixels(16, 16); 280 bitmap.allocN32Pixels(16, 16);
235 TabRendererData data; 281 TabRendererData data;
236 data.favicon = gfx::ImageSkia::CreateFrom1xBitmap(bitmap); 282 data.favicon = gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
237 283
238 // Perform layout over all possible combinations, checking for correct 284 // Perform layout over all possible combinations, checking for correct
239 // results. 285 // results.
240 for (int is_mini_tab = 0; is_mini_tab < 2; ++is_mini_tab) { 286 for (int is_mini_tab = 0; is_mini_tab < 2; ++is_mini_tab) {
241 for (int is_active_tab = 0; is_active_tab < 2; ++is_active_tab) { 287 for (int is_active_tab = 0; is_active_tab < 2; ++is_active_tab) {
242 for (size_t media_state_index = 0; 288 for (size_t media_state_index = 0;
243 media_state_index < arraysize(kMediaStatesToTest); 289 media_state_index < arraysize(kMediaStatesToTest);
244 ++media_state_index) { 290 ++media_state_index) {
245 const TabMediaState media_state = kMediaStatesToTest[media_state_index]; 291 const TabMediaState media_state = kMediaStatesToTest[media_state_index];
246 SCOPED_TRACE(::testing::Message() 292 SCOPED_TRACE(::testing::Message()
247 << (is_active_tab ? "Active" : "Inactive") << ' ' 293 << (is_active_tab ? "Active" : "Inactive") << ' '
248 << (is_mini_tab ? "Mini " : "") 294 << (is_mini_tab ? "Mini " : "")
249 << "Tab with media indicator state " << media_state); 295 << "Tab with media indicator state " << media_state);
250 296
251 data.mini = !!is_mini_tab; 297 data.mini = !!is_mini_tab;
252 controller.set_active_tab(!!is_active_tab); 298 controller.set_active_tab(!!is_active_tab);
253 data.media_state = media_state; 299 data.media_state = media_state;
254 tab.SetData(data); 300 tab.SetData(data);
255 301
256 // Disable the media indicator animation so that the layout/visibility
257 // logic can be tested effectively. If the animation was left enabled,
258 // the ShouldShowMediaIndicator() method would return true during
259 // fade-out transitions.
260 DisableMediaIndicatorAnimation(&tab);
261
262 // Test layout for every width from standard to minimum. 302 // Test layout for every width from standard to minimum.
263 gfx::Rect bounds(gfx::Point(0, 0), Tab::GetStandardSize()); 303 gfx::Rect bounds(gfx::Point(0, 0), Tab::GetStandardSize());
264 int min_width; 304 int min_width;
265 if (is_mini_tab) { 305 if (is_mini_tab) {
266 bounds.set_width(Tab::GetMiniWidth()); 306 bounds.set_width(Tab::GetMiniWidth());
267 min_width = Tab::GetMiniWidth(); 307 min_width = Tab::GetMiniWidth();
268 } else { 308 } else {
269 min_width = is_active_tab ? Tab::GetMinimumSelectedSize().width() : 309 min_width = is_active_tab ? Tab::GetMinimumSelectedSize().width() :
270 Tab::GetMinimumUnselectedSize().width(); 310 Tab::GetMinimumUnselectedSize().width();
271 } 311 }
272 while (bounds.width() >= min_width) { 312 while (bounds.width() >= min_width) {
273 SCOPED_TRACE(::testing::Message() << "bounds=" << bounds.ToString()); 313 SCOPED_TRACE(::testing::Message() << "bounds=" << bounds.ToString());
274 tab.SetBoundsRect(bounds); // Invokes Tab::Layout(). 314 tab.SetBoundsRect(bounds); // Invokes Tab::Layout().
275 CheckForExpectedLayoutAndVisibilityOfElements(tab); 315 CheckForExpectedLayoutAndVisibilityOfElements(tab);
276 bounds.set_width(bounds.width() - 1); 316 bounds.set_width(bounds.width() - 1);
277 } 317 }
278 } 318 }
279 } 319 }
280 } 320 }
281 } 321 }
282 322
283 // Regression test for http://crbug.com/226253. Calling Layout() more than once 323 // Regression test for http://crbug.com/226253. Calling Layout() more than once
284 // shouldn't change the insets of the close button. 324 // shouldn't change the insets of the close button.
285 TEST_F(TabTest, CloseButtonLayout) { 325 TEST_P(TabTest, CloseButtonLayout) {
326 if (ShouldSkipRTLTestOnUnsupportedPlatform()) {
327 LOG(WARNING) << "Testing of RTL locale not supported on current platform.";
328 return;
329 }
330
286 FakeTabController tab_controller; 331 FakeTabController tab_controller;
287 Tab tab(&tab_controller); 332 Tab tab(&tab_controller);
288 tab.SetBounds(0, 0, 100, 50); 333 tab.SetBounds(0, 0, 100, 50);
289 tab.Layout(); 334 tab.Layout();
290 gfx::Insets close_button_insets = tab.close_button_->GetInsets(); 335 gfx::Insets close_button_insets = tab.close_button_->GetInsets();
291 tab.Layout(); 336 tab.Layout();
292 gfx::Insets close_button_insets_2 = tab.close_button_->GetInsets(); 337 gfx::Insets close_button_insets_2 = tab.close_button_->GetInsets();
293 EXPECT_EQ(close_button_insets.top(), close_button_insets_2.top()); 338 EXPECT_EQ(close_button_insets.top(), close_button_insets_2.top());
294 EXPECT_EQ(close_button_insets.left(), close_button_insets_2.left()); 339 EXPECT_EQ(close_button_insets.left(), close_button_insets_2.left());
295 EXPECT_EQ(close_button_insets.bottom(), close_button_insets_2.bottom()); 340 EXPECT_EQ(close_button_insets.bottom(), close_button_insets_2.bottom());
296 EXPECT_EQ(close_button_insets.right(), close_button_insets_2.right()); 341 EXPECT_EQ(close_button_insets.right(), close_button_insets_2.right());
297 342
298 // Also make sure the close button is sized as large as the tab. 343 // Also make sure the close button is sized as large as the tab.
299 EXPECT_EQ(50, tab.close_button_->bounds().height()); 344 EXPECT_EQ(50, tab.close_button_->bounds().height());
300 } 345 }
346
347 // Test in both a LTR and a RTL locale. Note: The fact that the UI code is
348 // configured for an RTL locale does *not* change how the coordinates are
349 // examined in the tests above because views::View and friends are supposed to
350 // auto-mirror the widgets when painting. Thus, what we're testing here is that
351 // there's no code in Tab that will erroneously subvert this automatic
352 // coordinate translation. http://crbug.com/384179
353 INSTANTIATE_TEST_CASE_P(, TabTest, ::testing::Values(false, true));
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698