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

Side by Side Diff: chrome/browser/ui/cocoa/tabs/tab_controller_unittest.mm

Issue 2488833002: [Mac] Reverse tabs in RTL mode (Closed)
Patch Set: Update icon mask and add force RTL direction Created 4 years, 1 month 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
« no previous file with comments | « chrome/browser/ui/cocoa/tabs/tab_controller.mm ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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 #import <Cocoa/Cocoa.h> 5 #import <Cocoa/Cocoa.h>
6 #include <stddef.h> 6 #include <stddef.h>
7 7
8 #include "base/i18n/rtl.h"
8 #import "base/mac/scoped_nsobject.h" 9 #import "base/mac/scoped_nsobject.h"
9 #include "base/macros.h" 10 #include "base/macros.h"
10 #include "base/message_loop/message_loop.h" 11 #include "base/message_loop/message_loop.h"
11 #include "base/strings/utf_string_conversions.h" 12 #include "base/strings/utf_string_conversions.h"
13 #include "base/test/scoped_feature_list.h"
12 #include "chrome/browser/ui/cocoa/cocoa_test_helper.h" 14 #include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
15 #include "chrome/browser/ui/cocoa/l10n_util.h"
13 #import "chrome/browser/ui/cocoa/tabs/alert_indicator_button_cocoa.h" 16 #import "chrome/browser/ui/cocoa/tabs/alert_indicator_button_cocoa.h"
14 #import "chrome/browser/ui/cocoa/tabs/tab_controller.h" 17 #import "chrome/browser/ui/cocoa/tabs/tab_controller.h"
15 #import "chrome/browser/ui/cocoa/tabs/tab_controller_target.h" 18 #import "chrome/browser/ui/cocoa/tabs/tab_controller_target.h"
16 #import "chrome/browser/ui/cocoa/tabs/tab_strip_drag_controller.h" 19 #import "chrome/browser/ui/cocoa/tabs/tab_strip_drag_controller.h"
17 #import "chrome/browser/ui/cocoa/tabs/tab_view.h" 20 #import "chrome/browser/ui/cocoa/tabs/tab_view.h"
18 #include "testing/gtest/include/gtest/gtest.h" 21 #include "testing/gtest/include/gtest/gtest.h"
19 #import "testing/gtest_mac.h" 22 #import "testing/gtest_mac.h"
20 #include "testing/platform_test.h" 23 #include "testing/platform_test.h"
21 #include "ui/base/resource/resource_bundle.h" 24 #include "ui/base/resource/resource_bundle.h"
22 #include "ui/resources/grit/ui_resources.h" 25 #include "ui/resources/grit/ui_resources.h"
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
97 CGFloat RightMargin(NSRect superFrame, NSRect subFrame) { 100 CGFloat RightMargin(NSRect superFrame, NSRect subFrame) {
98 return NSMaxX(superFrame) - NSMaxX(subFrame); 101 return NSMaxX(superFrame) - NSMaxX(subFrame);
99 } 102 }
100 103
101 // The dragging code in TabView makes heavy use of autorelease pools so 104 // The dragging code in TabView makes heavy use of autorelease pools so
102 // inherit from CocoaTest to have one created for us. 105 // inherit from CocoaTest to have one created for us.
103 class TabControllerTest : public CocoaTest { 106 class TabControllerTest : public CocoaTest {
104 public: 107 public:
105 TabControllerTest() { } 108 TabControllerTest() { }
106 109
110 protected:
111 void CheckLayoutAndVisibilityOfSubviewsForAllStates(bool is_rtl) {
112 static const TabAlertState kAlertStatesToTest[] = {
113 TabAlertState::NONE, TabAlertState::TAB_CAPTURING,
114 TabAlertState::AUDIO_PLAYING, TabAlertState::AUDIO_MUTING};
115
116 NSWindow* const window = test_window();
117
118 // Create TabController instance and place its view into the test window.
119 base::scoped_nsobject<TabController> controller(
120 [[TabController alloc] init]);
121 [[window contentView] addSubview:[controller view]];
122
123 // Create favicon.
124 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
125 base::scoped_nsobject<NSImage> favicon(
126 rb.GetNativeImageNamed(IDR_DEFAULT_FAVICON).CopyNSImage());
127
128 // Trigger TabController to auto-create the AlertIndicatorButton.
129 [controller setAlertState:TabAlertState::AUDIO_PLAYING];
130 [controller setAlertState:TabAlertState::NONE];
131 base::scoped_nsobject<AlertIndicatorButton> alertIndicatorButton(
132 [[controller alertIndicatorButton] retain]);
133 ASSERT_TRUE(alertIndicatorButton.get());
134
135 // Perform layout over all possible combinations, checking for correct
136 // results.
137 for (int isPinnedTab = 0; isPinnedTab < 2; ++isPinnedTab) {
138 for (int isActiveTab = 0; isActiveTab < 2; ++isActiveTab) {
139 for (size_t alertStateIndex = 0;
140 alertStateIndex < arraysize(kAlertStatesToTest);
141 ++alertStateIndex) {
142 const TabAlertState alertState = kAlertStatesToTest[alertStateIndex];
143 SCOPED_TRACE(::testing::Message()
144 << (isActiveTab ? "Active" : "Inactive") << ' '
145 << (isPinnedTab ? "Pinned " : "")
146 << "Tab with alert indicator state "
147 << static_cast<uint8_t>(alertState));
148
149 // Simulate what tab_strip_controller would do to set up the
150 // TabController state.
151 [controller setPinned:(isPinnedTab ? YES : NO)];
152 [controller setActive:(isActiveTab ? YES : NO)];
153 [controller setIconImage:favicon];
154 [controller setAlertState:alertState];
155 [controller updateVisibility];
156
157 // Test layout for every width from maximum to minimum.
158 NSRect tabFrame = [[controller view] frame];
159 int minWidth;
160 if (isPinnedTab) {
161 tabFrame.size.width = minWidth = [TabController pinnedTabWidth];
162 } else {
163 tabFrame.size.width = [TabController maxTabWidth];
164 minWidth = isActiveTab ? [TabController minActiveTabWidth]
165 : [TabController minTabWidth];
166 }
167 while (NSWidth(tabFrame) >= minWidth) {
168 SCOPED_TRACE(::testing::Message() << "width="
169 << tabFrame.size.width);
170 [[controller view] setFrame:tabFrame];
171 if (is_rtl)
172 CheckForExpectedLayoutAndVisibilityOfSubviewsRTL(controller);
173 else
174 CheckForExpectedLayoutAndVisibilityOfSubviews(controller);
175 --tabFrame.size.width;
176 }
177 }
178 }
179 }
180 }
181
182 private:
107 static void CheckForExpectedLayoutAndVisibilityOfSubviews( 183 static void CheckForExpectedLayoutAndVisibilityOfSubviews(
108 const TabController* controller) { 184 const TabController* controller) {
185 CheckVisibilityOfSubviews(controller);
186
187 // Check positioning of elements with respect to each other, and that they
188 // are fully within the tab frame.
189 const NSRect tabFrame = [[controller view] frame];
190 const NSRect titleFrame = [[controller tabView] titleFrame];
191 if ([controller shouldShowIcon]) {
192 const NSRect iconFrame = [[controller iconView] frame];
193 EXPECT_LE(NSMinX(tabFrame), NSMinX(iconFrame));
194 if (NSWidth(titleFrame) > 0)
195 EXPECT_LE(NSMaxX(iconFrame), NSMinX(titleFrame));
196 EXPECT_LE(NSMinY(tabFrame), NSMinY(iconFrame));
197 EXPECT_LE(NSMaxY(iconFrame), NSMaxY(tabFrame));
198 }
199 if ([controller shouldShowIcon] && [controller shouldShowAlertIndicator]) {
200 EXPECT_LE(NSMaxX([[controller iconView] frame]),
201 NSMinX([[controller alertIndicatorButton] frame]));
202 }
203 if ([controller shouldShowAlertIndicator]) {
204 const NSRect alertIndicatorFrame =
205 [[controller alertIndicatorButton] frame];
206 if (NSWidth(titleFrame) > 0)
207 EXPECT_LE(NSMaxX(titleFrame), NSMinX(alertIndicatorFrame));
208 EXPECT_LE(NSMaxX(alertIndicatorFrame), NSMaxX(tabFrame));
209 EXPECT_LE(NSMinY(tabFrame), NSMinY(alertIndicatorFrame));
210 EXPECT_LE(NSMaxY(alertIndicatorFrame), NSMaxY(tabFrame));
211 }
212 if ([controller shouldShowAlertIndicator] &&
213 [controller shouldShowCloseButton]) {
214 EXPECT_LE(NSMaxX([[controller alertIndicatorButton] frame]),
215 NSMinX([[controller closeButton] frame]));
216 }
217 if ([controller shouldShowCloseButton]) {
218 const NSRect closeButtonFrame = [[controller closeButton] frame];
219 if (NSWidth(titleFrame) > 0)
220 EXPECT_LE(NSMaxX(titleFrame), NSMinX(closeButtonFrame));
221 EXPECT_LE(NSMaxX(closeButtonFrame), NSMaxX(tabFrame));
222 EXPECT_LE(NSMinY(tabFrame), NSMinY(closeButtonFrame));
223 EXPECT_LE(NSMaxY(closeButtonFrame), NSMaxY(tabFrame));
224 }
225 }
226 static void CheckForExpectedLayoutAndVisibilityOfSubviewsRTL(
227 const TabController* controller) {
228 CheckVisibilityOfSubviews(controller);
229 // Check positioning of elements with respect to each other, and that they
230 // are fully within the tab frame.
231 const NSRect tabFrame = [[controller view] frame];
232 const NSRect titleFrame = [[controller tabView] titleFrame];
233 if ([controller shouldShowCloseButton]) {
234 const NSRect closeButtonFrame = [[controller closeButton] frame];
235 EXPECT_TRUE(NSContainsRect(tabFrame, closeButtonFrame));
236 if (NSWidth(titleFrame) > 0)
237 EXPECT_LE(NSMaxX(closeButtonFrame), NSMinX(titleFrame));
238 }
239 if ([controller shouldShowCloseButton] &&
240 [controller shouldShowAlertIndicator]) {
241 EXPECT_LE(NSMaxX([[controller closeButton] frame]),
242 NSMinX([[controller alertIndicatorButton] frame]));
243 }
244 if ([controller shouldShowAlertIndicator]) {
245 const NSRect alertIndicatorFrame =
246 [[controller alertIndicatorButton] frame];
247 EXPECT_TRUE(NSContainsRect(tabFrame, alertIndicatorFrame));
248 if (NSWidth(titleFrame) > 0)
249 EXPECT_LE(NSMaxX(alertIndicatorFrame), NSMinX(titleFrame));
250 }
251 if ([controller shouldShowAlertIndicator] && [controller shouldShowIcon]) {
252 EXPECT_LE(NSMaxX([[controller alertIndicatorButton] frame]),
253 NSMinX([[controller iconView] frame]));
254 }
255 if ([controller shouldShowIcon]) {
256 const NSRect iconFrame = [[controller iconView] frame];
257 EXPECT_TRUE(NSContainsRect(tabFrame, iconFrame));
258 if (NSWidth(titleFrame) > 0)
259 EXPECT_LE(NSMaxX(titleFrame), NSMinX(iconFrame));
260 }
261 }
262 // Common for RTL and LTR
263 static void CheckVisibilityOfSubviews(const TabController* controller) {
109 // Check whether subviews should be visible when they are supposed to be, 264 // Check whether subviews should be visible when they are supposed to be,
110 // given Tab size and TabRendererData state. 265 // given Tab size and TabRendererData state.
111 const TabAlertState indicatorState = 266 const TabAlertState indicatorState =
112 [[controller alertIndicatorButton] showingAlertState]; 267 [[controller alertIndicatorButton] showingAlertState];
113 if ([controller pinned]) { 268 if ([controller pinned]) {
114 EXPECT_EQ(1, [controller iconCapacity]); 269 EXPECT_EQ(1, [controller iconCapacity]);
115 if (indicatorState != TabAlertState::NONE) { 270 if (indicatorState != TabAlertState::NONE) {
116 EXPECT_FALSE([controller shouldShowIcon]); 271 EXPECT_FALSE([controller shouldShowIcon]);
117 EXPECT_TRUE([controller shouldShowAlertIndicator]); 272 EXPECT_TRUE([controller shouldShowAlertIndicator]);
118 } else { 273 } else {
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
166 default: 321 default:
167 EXPECT_LE(2, [controller iconCapacity]); 322 EXPECT_LE(2, [controller iconCapacity]);
168 EXPECT_TRUE([controller shouldShowIcon]); 323 EXPECT_TRUE([controller shouldShowIcon]);
169 if (indicatorState != TabAlertState::NONE) 324 if (indicatorState != TabAlertState::NONE)
170 EXPECT_TRUE([controller shouldShowAlertIndicator]); 325 EXPECT_TRUE([controller shouldShowAlertIndicator]);
171 else 326 else
172 EXPECT_FALSE([controller shouldShowAlertIndicator]); 327 EXPECT_FALSE([controller shouldShowAlertIndicator]);
173 break; 328 break;
174 } 329 }
175 } 330 }
176
177 // Make sure the NSView's "isHidden" state jives with the "shouldShowXXX."
178 EXPECT_TRUE([controller shouldShowIcon] ==
179 (!![controller iconView] && ![[controller iconView] isHidden]));
180 EXPECT_TRUE([controller pinned] == [[controller tabView] titleHidden]);
181 EXPECT_TRUE([controller shouldShowAlertIndicator] ==
182 ![[controller alertIndicatorButton] isHidden]);
183 EXPECT_TRUE([controller shouldShowCloseButton] !=
184 [[controller closeButton] isHidden]);
185
186 // Check positioning of elements with respect to each other, and that they
187 // are fully within the tab frame.
188 const NSRect tabFrame = [[controller view] frame];
189 const NSRect titleFrame = [[controller tabView] titleFrame];
190 if ([controller shouldShowIcon]) {
191 const NSRect iconFrame = [[controller iconView] frame];
192 EXPECT_LE(NSMinX(tabFrame), NSMinX(iconFrame));
193 if (NSWidth(titleFrame) > 0)
194 EXPECT_LE(NSMaxX(iconFrame), NSMinX(titleFrame));
195 EXPECT_LE(NSMinY(tabFrame), NSMinY(iconFrame));
196 EXPECT_LE(NSMaxY(iconFrame), NSMaxY(tabFrame));
197 }
198 if ([controller shouldShowIcon] && [controller shouldShowAlertIndicator]) {
199 EXPECT_LE(NSMaxX([[controller iconView] frame]),
200 NSMinX([[controller alertIndicatorButton] frame]));
201 }
202 if ([controller shouldShowAlertIndicator]) {
203 const NSRect alertIndicatorFrame =
204 [[controller alertIndicatorButton] frame];
205 if (NSWidth(titleFrame) > 0)
206 EXPECT_LE(NSMaxX(titleFrame), NSMinX(alertIndicatorFrame));
207 EXPECT_LE(NSMaxX(alertIndicatorFrame), NSMaxX(tabFrame));
208 EXPECT_LE(NSMinY(tabFrame), NSMinY(alertIndicatorFrame));
209 EXPECT_LE(NSMaxY(alertIndicatorFrame), NSMaxY(tabFrame));
210 }
211 if ([controller shouldShowAlertIndicator] &&
212 [controller shouldShowCloseButton]) {
213 EXPECT_LE(NSMaxX([[controller alertIndicatorButton] frame]),
214 NSMinX([[controller closeButton] frame]));
215 }
216 if ([controller shouldShowCloseButton]) {
217 const NSRect closeButtonFrame = [[controller closeButton] frame];
218 if (NSWidth(titleFrame) > 0)
219 EXPECT_LE(NSMaxX(titleFrame), NSMinX(closeButtonFrame));
220 EXPECT_LE(NSMaxX(closeButtonFrame), NSMaxX(tabFrame));
221 EXPECT_LE(NSMinY(tabFrame), NSMinY(closeButtonFrame));
222 EXPECT_LE(NSMaxY(closeButtonFrame), NSMaxY(tabFrame));
223 }
224 } 331 }
225 332
226 private:
227 base::MessageLoop message_loop_; 333 base::MessageLoop message_loop_;
228 }; 334 };
229 335
230 // Tests creating the controller, sticking it in a window, and removing it. 336 // Tests creating the controller, sticking it in a window, and removing it.
231 TEST_F(TabControllerTest, Creation) { 337 TEST_F(TabControllerTest, Creation) {
232 NSWindow* window = test_window(); 338 NSWindow* window = test_window();
233 base::scoped_nsobject<TabController> controller([[TabController alloc] init]); 339 base::scoped_nsobject<TabController> controller([[TabController alloc] init]);
234 [[window contentView] addSubview:[controller view]]; 340 [[window contentView] addSubview:[controller view]];
235 EXPECT_TRUE([controller tabView]); 341 EXPECT_TRUE([controller tabView]);
236 EXPECT_EQ([[controller view] window], window); 342 EXPECT_EQ([[controller view] window], window);
(...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after
467 NSWidth([[controller tabView] titleFrame])); 573 NSWidth([[controller tabView] titleFrame]));
468 EXPECT_EQ(LeftMargin(originalTabFrame, originalTitleFrame), 574 EXPECT_EQ(LeftMargin(originalTabFrame, originalTitleFrame),
469 LeftMargin([[controller view] frame], 575 LeftMargin([[controller view] frame],
470 [[controller tabView] titleFrame])); 576 [[controller tabView] titleFrame]));
471 EXPECT_EQ(RightMargin(originalTabFrame, originalTitleFrame), 577 EXPECT_EQ(RightMargin(originalTabFrame, originalTitleFrame),
472 RightMargin([[controller view] frame], 578 RightMargin([[controller view] frame],
473 [[controller tabView] titleFrame])); 579 [[controller tabView] titleFrame]));
474 } 580 }
475 581
476 TEST_F(TabControllerTest, LayoutAndVisibilityOfSubviews) { 582 TEST_F(TabControllerTest, LayoutAndVisibilityOfSubviews) {
477 static const TabAlertState kAlertStatesToTest[] = { 583 CheckLayoutAndVisibilityOfSubviewsForAllStates(false);
478 TabAlertState::NONE, TabAlertState::TAB_CAPTURING, 584 }
479 TabAlertState::AUDIO_PLAYING, TabAlertState::AUDIO_MUTING
480 };
481 585
482 NSWindow* const window = test_window(); 586 TEST_F(TabControllerTest, LayoutAndVisibilityOfSubviewsRTL) {
587 std::string old_locale(base::i18n::GetConfiguredLocale());
588 base::i18n::SetICUDefaultLocale("he");
589 base::test::ScopedFeatureList scoped_feature_list;
590 scoped_feature_list.InitAndEnableFeature(
591 cocoa_l10n_util::kExperimentalMacRTL);
592 // TODO(lgrey): Create ScopedNSUserDefaults or similar to do
593 // this automatically.
594 NSString* const appleTextDirectionDefaultsKey = @"AppleTextDirection";
595 NSString* const forceRTLWritingDirectionDefaultsKey =
596 @"NSForceRightToLeftWritingDirection";
597 NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
598 BOOL oldTextDirection = [defaults boolForKey:appleTextDirectionDefaultsKey];
599 BOOL oldRTLWritingDirection =
600 [defaults boolForKey:forceRTLWritingDirectionDefaultsKey];
601 [defaults setBool:YES forKey:appleTextDirectionDefaultsKey];
602 [defaults setBool:YES forKey:forceRTLWritingDirectionDefaultsKey];
483 603
484 // Create TabController instance and place its view into the test window. 604 CheckLayoutAndVisibilityOfSubviewsForAllStates(true);
485 base::scoped_nsobject<TabController> controller([[TabController alloc] init]);
486 [[window contentView] addSubview:[controller view]];
487 605
488 // Create favicon. 606 base::i18n::SetICUDefaultLocale(old_locale);
489 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 607 [defaults setBool:oldTextDirection forKey:appleTextDirectionDefaultsKey];
490 base::scoped_nsobject<NSImage> favicon( 608 [defaults setBool:oldRTLWritingDirection
491 rb.GetNativeImageNamed(IDR_DEFAULT_FAVICON).CopyNSImage()); 609 forKey:forceRTLWritingDirectionDefaultsKey];
492
493 // Trigger TabController to auto-create the AlertIndicatorButton.
494 [controller setAlertState:TabAlertState::AUDIO_PLAYING];
495 [controller setAlertState:TabAlertState::NONE];
496 base::scoped_nsobject<AlertIndicatorButton> alertIndicatorButton(
497 [[controller alertIndicatorButton] retain]);
498 ASSERT_TRUE(alertIndicatorButton.get());
499
500 // Perform layout over all possible combinations, checking for correct
501 // results.
502 for (int isPinnedTab = 0; isPinnedTab < 2; ++isPinnedTab) {
503 for (int isActiveTab = 0; isActiveTab < 2; ++isActiveTab) {
504 for (size_t alertStateIndex = 0;
505 alertStateIndex < arraysize(kAlertStatesToTest);
506 ++alertStateIndex) {
507 const TabAlertState alertState = kAlertStatesToTest[alertStateIndex];
508 SCOPED_TRACE(::testing::Message()
509 << (isActiveTab ? "Active" : "Inactive") << ' '
510 << (isPinnedTab ? "Pinned " : "")
511 << "Tab with alert indicator state "
512 << static_cast<uint8_t>(alertState));
513
514 // Simulate what tab_strip_controller would do to set up the
515 // TabController state.
516 [controller setPinned:(isPinnedTab ? YES : NO)];
517 [controller setActive:(isActiveTab ? YES : NO)];
518 [controller setIconImage:favicon];
519 [controller setAlertState:alertState];
520 [controller updateVisibility];
521
522 // Test layout for every width from maximum to minimum.
523 NSRect tabFrame = [[controller view] frame];
524 int minWidth;
525 if (isPinnedTab) {
526 tabFrame.size.width = minWidth = [TabController pinnedTabWidth];
527 } else {
528 tabFrame.size.width = [TabController maxTabWidth];
529 minWidth = isActiveTab ? [TabController minActiveTabWidth] :
530 [TabController minTabWidth];
531 }
532 while (NSWidth(tabFrame) >= minWidth) {
533 SCOPED_TRACE(::testing::Message() << "width=" << tabFrame.size.width);
534 [[controller view] setFrame:tabFrame];
535 CheckForExpectedLayoutAndVisibilityOfSubviews(controller);
536 --tabFrame.size.width;
537 }
538 }
539 }
540 }
541 } 610 }
542 611
543 } // namespace 612 } // namespace
OLDNEW
« no previous file with comments | « chrome/browser/ui/cocoa/tabs/tab_controller.mm ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698