OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "ui/views/cocoa/bridged_native_widget.h" | 5 #import "ui/views/cocoa/bridged_native_widget.h" |
6 | 6 |
7 #import <Cocoa/Cocoa.h> | 7 #import <Cocoa/Cocoa.h> |
8 | 8 |
9 #import "base/mac/foundation_util.h" | 9 #import "base/mac/foundation_util.h" |
10 #import "base/mac/mac_util.h" | 10 #import "base/mac/mac_util.h" |
(...skipping 25 matching lines...) Expand all Loading... | |
36 EXPECT_EQ(a.location, b.location); \ | 36 EXPECT_EQ(a.location, b.location); \ |
37 EXPECT_EQ(a.length, b.length); | 37 EXPECT_EQ(a.length, b.length); |
38 | 38 |
39 namespace { | 39 namespace { |
40 | 40 |
41 // Empty range shortcut for readibility. | 41 // Empty range shortcut for readibility. |
42 NSRange EmptyRange() { | 42 NSRange EmptyRange() { |
43 return NSMakeRange(NSNotFound, 0); | 43 return NSMakeRange(NSNotFound, 0); |
44 } | 44 } |
45 | 45 |
46 // Changes NSRect to gfx::Rect and converts it from Apple's coordinate system | |
47 // (origin at bottom left) to coordinate system with origin at top left. | |
48 gfx::Rect ConvertCoordinateSystem(NSRect rect) { | |
tapted
2015/12/17 08:42:20
gfx::ScreenRectFromNSRect
karandeepb
2015/12/18 09:15:06
Done.
| |
49 NSRect screen_rect = [[NSScreen mainScreen] frame]; | |
50 rect.origin.y = screen_rect.size.height - NSMaxY(rect); | |
51 return gfx::Rect(NSRectToCGRect(rect)); | |
52 } | |
53 | |
46 } // namespace | 54 } // namespace |
47 | 55 |
48 // Class to override -[NSWindow toggleFullScreen:] to a no-op. This simulates | 56 // Class to override -[NSWindow toggleFullScreen:] to a no-op. This simulates |
49 // NSWindow's behavior when attempting to toggle fullscreen state again, when | 57 // NSWindow's behavior when attempting to toggle fullscreen state again, when |
50 // the last attempt failed but Cocoa has not yet sent | 58 // the last attempt failed but Cocoa has not yet sent |
51 // windowDidFailToEnterFullScreen:. | 59 // windowDidFailToEnterFullScreen:. |
52 @interface BridgedNativeWidgetTestFullScreenWindow : NativeWidgetMacNSWindow { | 60 @interface BridgedNativeWidgetTestFullScreenWindow : NativeWidgetMacNSWindow { |
53 @private | 61 @private |
54 int ignoredToggleFullScreenCount_; | 62 int ignoredToggleFullScreenCount_; |
55 } | 63 } |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
121 // before the tests covering the Init() flow are ready to do that. | 129 // before the tests covering the Init() flow are ready to do that. |
122 init_params_.type = Widget::InitParams::TYPE_WINDOW_FRAMELESS; | 130 init_params_.type = Widget::InitParams::TYPE_WINDOW_FRAMELESS; |
123 | 131 |
124 // To control the lifetime without an actual window that must be closed, | 132 // To control the lifetime without an actual window that must be closed, |
125 // tests in this file need to use WIDGET_OWNS_NATIVE_WIDGET. | 133 // tests in this file need to use WIDGET_OWNS_NATIVE_WIDGET. |
126 init_params_.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; | 134 init_params_.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; |
127 | 135 |
128 // Opacity defaults to "infer" which is usually updated by ViewsDelegate. | 136 // Opacity defaults to "infer" which is usually updated by ViewsDelegate. |
129 init_params_.opacity = Widget::InitParams::OPAQUE_WINDOW; | 137 init_params_.opacity = Widget::InitParams::OPAQUE_WINDOW; |
130 | 138 |
139 init_params_.bounds = gfx::Rect(100, 100, 100, 100); | |
140 | |
131 native_widget_mac_->GetWidget()->Init(init_params_); | 141 native_widget_mac_->GetWidget()->Init(init_params_); |
132 } | 142 } |
133 | 143 |
134 protected: | 144 protected: |
135 scoped_ptr<Widget> widget_; | 145 scoped_ptr<Widget> widget_; |
136 MockNativeWidgetMac* native_widget_mac_; // Weak. Owned by |widget_|. | 146 MockNativeWidgetMac* native_widget_mac_; // Weak. Owned by |widget_|. |
137 | 147 |
138 // Make the InitParams available to tests to cover initialization codepaths. | 148 // Make the InitParams available to tests to cover initialization codepaths. |
139 Widget::InitParams init_params_; | 149 Widget::InitParams init_params_; |
140 }; | 150 }; |
(...skipping 26 matching lines...) Expand all Loading... | |
167 | 177 |
168 BridgedNativeWidgetTest::BridgedNativeWidgetTest() { | 178 BridgedNativeWidgetTest::BridgedNativeWidgetTest() { |
169 } | 179 } |
170 | 180 |
171 BridgedNativeWidgetTest::~BridgedNativeWidgetTest() { | 181 BridgedNativeWidgetTest::~BridgedNativeWidgetTest() { |
172 } | 182 } |
173 | 183 |
174 void BridgedNativeWidgetTest::InstallTextField(const std::string& text) { | 184 void BridgedNativeWidgetTest::InstallTextField(const std::string& text) { |
175 Textfield* textfield = new Textfield(); | 185 Textfield* textfield = new Textfield(); |
176 textfield->SetText(ASCIIToUTF16(text)); | 186 textfield->SetText(ASCIIToUTF16(text)); |
187 textfield->SetBoundsRect(init_params_.bounds); | |
177 view_->AddChildView(textfield); | 188 view_->AddChildView(textfield); |
178 | 189 |
179 // Request focus so the InputMethod can dispatch events to the RootView, and | 190 // Request focus so the InputMethod can dispatch events to the RootView, and |
180 // have them delivered to the textfield. Note that focusing a textfield | 191 // have them delivered to the textfield. Note that focusing a textfield |
181 // schedules a task to flash the cursor, so this requires |message_loop_|. | 192 // schedules a task to flash the cursor, so this requires |message_loop_|. |
182 textfield->RequestFocus(); | 193 textfield->RequestFocus(); |
183 | 194 |
184 [ns_view_ setTextInputClient:textfield]; | 195 [ns_view_ setTextInputClient:textfield]; |
185 } | 196 } |
186 | 197 |
(...skipping 311 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
498 EXPECT_EQ("a", GetText()); | 509 EXPECT_EQ("a", GetText()); |
499 EXPECT_EQ_RANGE(NSMakeRange(1, 0), [ns_view_ selectedRange]); | 510 EXPECT_EQ_RANGE(NSMakeRange(1, 0), [ns_view_ selectedRange]); |
500 | 511 |
501 // Should succeed after moving left first. | 512 // Should succeed after moving left first. |
502 [ns_view_ doCommandBySelector:@selector(moveLeft:)]; | 513 [ns_view_ doCommandBySelector:@selector(moveLeft:)]; |
503 [ns_view_ doCommandBySelector:@selector(deleteForward:)]; | 514 [ns_view_ doCommandBySelector:@selector(deleteForward:)]; |
504 EXPECT_EQ("", GetText()); | 515 EXPECT_EQ("", GetText()); |
505 EXPECT_EQ_RANGE(NSMakeRange(0, 0), [ns_view_ selectedRange]); | 516 EXPECT_EQ_RANGE(NSMakeRange(0, 0), [ns_view_ selectedRange]); |
506 } | 517 } |
507 | 518 |
519 TEST_F(BridgedNativeWidgetTest, TextInput_FirstRectForCharacterRange) { | |
520 InstallTextField(""); | |
521 ui::TextInputClient* textInputClient = [ns_view_ textInputClient]; | |
tapted
2015/12/17 08:42:20
hacker_style (eg. `client` for brevity too)
karandeepb
2015/12/18 09:15:06
Done.
| |
522 NSRange range; | |
523 NSRange actual_range = NSMakeRange(-1, -1); | |
524 NSRect rect; | |
525 gfx::Rect bounds; | |
526 | |
527 // Empty composition. | |
528 rect = [ns_view_ firstRectForCharacterRange:NSMakeRange(0, 0) | |
529 actualRange:&actual_range]; | |
530 bounds = textInputClient->GetCaretBounds(); | |
531 bounds.set_width(0); | |
532 EXPECT_TRUE(ConvertCoordinateSystem(rect) == bounds); | |
533 EXPECT_TRUE(NSEqualRanges(NSMakeRange(0, 0), actual_range)); | |
534 | |
535 rect = [ns_view_ firstRectForCharacterRange:NSMakeRange(1, 1) | |
536 actualRange:&actual_range]; | |
537 EXPECT_TRUE(ConvertCoordinateSystem(rect) == bounds); | |
538 EXPECT_TRUE(NSEqualRanges(NSMakeRange(1, 0), actual_range)); | |
539 | |
540 // Set composition with caret before second character('e'). | |
541 ui::CompositionText composition; | |
542 composition.selection = gfx::Range(1); | |
543 composition.text = base::UTF8ToUTF16("test_str"); | |
544 size_t count = composition.text.length(); | |
545 textInputClient->SetCompositionText(composition); | |
546 | |
547 range = NSMakeRange(1, 0); | |
548 rect = [ns_view_ firstRectForCharacterRange:range actualRange:&actual_range]; | |
549 bounds = textInputClient->GetCaretBounds(); | |
550 bounds.set_width(0); | |
551 EXPECT_TRUE(ConvertCoordinateSystem(rect) == bounds); | |
552 EXPECT_TRUE(NSEqualRanges(range, actual_range)); | |
553 | |
554 range = NSMakeRange(2, 0); | |
555 rect = [ns_view_ firstRectForCharacterRange:range actualRange:&actual_range]; | |
556 EXPECT_FALSE(ConvertCoordinateSystem(rect) == bounds); | |
557 EXPECT_TRUE(NSEqualRanges(range, actual_range)); | |
558 | |
559 // Query outside composition range. | |
560 range = NSMakeRange(count + 1, 0); | |
561 rect = [ns_view_ firstRectForCharacterRange:range actualRange:&actual_range]; | |
562 EXPECT_TRUE(ConvertCoordinateSystem(rect) == bounds); | |
563 EXPECT_TRUE(NSEqualRanges(range, actual_range)); | |
564 | |
565 std::vector<gfx::Rect> char_bounds, caret_bounds; | |
tapted
2015/12/17 08:42:20
it's uncommon to declare multiple things on a line
karandeepb
2015/12/18 09:15:06
Done.
| |
566 char_bounds.resize(count); | |
567 caret_bounds.resize(count + 1); | |
568 | |
569 // Generate caret_bounds between different characters. | |
570 for (size_t i = 0; i <= count; i++) { | |
571 composition.selection = gfx::Range(i); | |
572 textInputClient->SetCompositionText(composition); | |
573 caret_bounds[i] = textInputClient->GetCaretBounds(); | |
574 } | |
575 | |
576 // Generate individual character bounds from caret positions. | |
577 for (size_t i = 0; i < count; i++) { | |
578 char_bounds[i].set_origin(caret_bounds[i].origin()); | |
579 char_bounds[i].set_width(caret_bounds[i + 1].x() - caret_bounds[i].x()); | |
580 char_bounds[i].set_height( | |
581 std::max(caret_bounds[i].height(), caret_bounds[i + 1].height())); | |
582 } | |
583 | |
584 // Verify bounds for all valid ranges. | |
585 for (size_t i = 0; i < count; i++) { | |
586 for (size_t j = i + 1; j <= count; j++) { | |
587 range = NSMakeRange(i, j - i); | |
588 rect = | |
589 [ns_view_ firstRectForCharacterRange:range actualRange:&actual_range]; | |
590 | |
591 bounds = gfx::Rect(); | |
592 for (size_t k = i; k < j; k++) | |
593 bounds.Union(char_bounds[k]); | |
594 | |
595 EXPECT_TRUE(ConvertCoordinateSystem(rect) == bounds); | |
596 EXPECT_TRUE(NSEqualRanges(range, actual_range)); | |
597 } | |
598 } | |
599 | |
600 // Check NSZeroRect is returned if bridged_content_view has no textInputClient | |
601 // available. | |
602 [ns_view_ setTextInputClient:nil]; | |
603 rect = [ns_view_ firstRectForCharacterRange:NSMakeRange(0, 0) | |
604 actualRange:&actual_range]; | |
605 EXPECT_TRUE(NSEqualRects(rect, NSZeroRect)); | |
606 } | |
607 | |
508 typedef BridgedNativeWidgetTestBase BridgedNativeWidgetSimulateFullscreenTest; | 608 typedef BridgedNativeWidgetTestBase BridgedNativeWidgetSimulateFullscreenTest; |
509 | 609 |
510 // Simulate the notifications that AppKit would send out if a fullscreen | 610 // Simulate the notifications that AppKit would send out if a fullscreen |
511 // operation begins, and then fails and must abort. This notification sequence | 611 // operation begins, and then fails and must abort. This notification sequence |
512 // was determined by posting delayed tasks to toggle fullscreen state and then | 612 // was determined by posting delayed tasks to toggle fullscreen state and then |
513 // mashing Ctrl+Left/Right to keep OSX in a transition between Spaces to cause | 613 // mashing Ctrl+Left/Right to keep OSX in a transition between Spaces to cause |
514 // the fullscreen transition to fail. | 614 // the fullscreen transition to fail. |
515 TEST_F(BridgedNativeWidgetSimulateFullscreenTest, FailToEnterAndExit) { | 615 TEST_F(BridgedNativeWidgetSimulateFullscreenTest, FailToEnterAndExit) { |
516 if (base::mac::IsOSSnowLeopard()) | 616 if (base::mac::IsOSSnowLeopard()) |
517 return; | 617 return; |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
576 [center postNotificationName:NSWindowDidExitFullScreenNotification | 676 [center postNotificationName:NSWindowDidExitFullScreenNotification |
577 object:window]; | 677 object:window]; |
578 EXPECT_EQ(1, [window ignoredToggleFullScreenCount]); // No change. | 678 EXPECT_EQ(1, [window ignoredToggleFullScreenCount]); // No change. |
579 EXPECT_FALSE(bridge()->target_fullscreen_state()); | 679 EXPECT_FALSE(bridge()->target_fullscreen_state()); |
580 | 680 |
581 widget_->CloseNow(); | 681 widget_->CloseNow(); |
582 } | 682 } |
583 | 683 |
584 } // namespace test | 684 } // namespace test |
585 } // namespace views | 685 } // namespace views |
OLD | NEW |