| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 <QuartzCore/QuartzCore.h> | 5 #include <QuartzCore/QuartzCore.h> |
| 6 | 6 |
| 7 #include "chrome/browser/renderer_host/render_widget_host_view_mac.h" | 7 #include "chrome/browser/renderer_host/render_widget_host_view_mac.h" |
| 8 | 8 |
| 9 #include "app/surface/io_surface_support_mac.h" | 9 #include "app/surface/io_surface_support_mac.h" |
| 10 #import "base/chrome_application_mac.h" | 10 #import "base/chrome_application_mac.h" |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 124 return NULL; | 124 return NULL; |
| 125 } | 125 } |
| 126 | 126 |
| 127 /////////////////////////////////////////////////////////////////////////////// | 127 /////////////////////////////////////////////////////////////////////////////// |
| 128 // RenderWidgetHostViewMac, public: | 128 // RenderWidgetHostViewMac, public: |
| 129 | 129 |
| 130 RenderWidgetHostViewMac::RenderWidgetHostViewMac(RenderWidgetHost* widget) | 130 RenderWidgetHostViewMac::RenderWidgetHostViewMac(RenderWidgetHost* widget) |
| 131 : render_widget_host_(widget), | 131 : render_widget_host_(widget), |
| 132 about_to_validate_and_paint_(false), | 132 about_to_validate_and_paint_(false), |
| 133 call_set_needs_display_in_rect_pending_(false), | 133 call_set_needs_display_in_rect_pending_(false), |
| 134 im_attributes_(nil), | |
| 135 im_composing_(false), | |
| 136 is_loading_(false), | 134 is_loading_(false), |
| 137 is_hidden_(false), | 135 is_hidden_(false), |
| 138 is_popup_menu_(false), | 136 is_popup_menu_(false), |
| 139 shutdown_factory_(this), | 137 shutdown_factory_(this), |
| 140 parent_view_(NULL) { | 138 parent_view_(NULL) { |
| 141 // |cocoa_view_| owns us and we will be deleted when |cocoa_view_| goes away. | 139 // |cocoa_view_| owns us and we will be deleted when |cocoa_view_| goes away. |
| 142 // Since we autorelease it, our caller must put |native_view()| into the view | 140 // Since we autorelease it, our caller must put |native_view()| into the view |
| 143 // hierarchy right after calling us. | 141 // hierarchy right after calling us. |
| 144 cocoa_view_ = [[[RenderWidgetHostViewCocoa alloc] | 142 cocoa_view_ = [[[RenderWidgetHostViewCocoa alloc] |
| 145 initWithRenderWidgetHostViewMac:this] autorelease]; | 143 initWithRenderWidgetHostViewMac:this] autorelease]; |
| 146 render_widget_host_->set_view(this); | 144 render_widget_host_->set_view(this); |
| 147 } | 145 } |
| 148 | 146 |
| 149 RenderWidgetHostViewMac::~RenderWidgetHostViewMac() { | 147 RenderWidgetHostViewMac::~RenderWidgetHostViewMac() { |
| 150 [im_attributes_ release]; | |
| 151 } | 148 } |
| 152 | 149 |
| 153 /////////////////////////////////////////////////////////////////////////////// | 150 /////////////////////////////////////////////////////////////////////////////// |
| 154 // RenderWidgetHostViewMac, RenderWidgetHostView implementation: | 151 // RenderWidgetHostViewMac, RenderWidgetHostView implementation: |
| 155 | 152 |
| 156 void RenderWidgetHostViewMac::InitAsPopup( | 153 void RenderWidgetHostViewMac::InitAsPopup( |
| 157 RenderWidgetHostView* parent_host_view, | 154 RenderWidgetHostView* parent_host_view, |
| 158 const gfx::Rect& pos) { | 155 const gfx::Rect& pos) { |
| 159 bool activatable = popup_type_ == WebKit::WebPopupTypeNone; | 156 bool activatable = popup_type_ == WebKit::WebPopupTypeNone; |
| 160 [cocoa_view_ setCloseOnDeactivate:YES]; | 157 [cocoa_view_ setCloseOnDeactivate:YES]; |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 314 | 311 |
| 315 void RenderWidgetHostViewMac::SetIsLoading(bool is_loading) { | 312 void RenderWidgetHostViewMac::SetIsLoading(bool is_loading) { |
| 316 is_loading_ = is_loading; | 313 is_loading_ = is_loading; |
| 317 UpdateCursorIfOverSelf(); | 314 UpdateCursorIfOverSelf(); |
| 318 } | 315 } |
| 319 | 316 |
| 320 void RenderWidgetHostViewMac::IMEUpdateStatus(int control, | 317 void RenderWidgetHostViewMac::IMEUpdateStatus(int control, |
| 321 const gfx::Rect& caret_rect) { | 318 const gfx::Rect& caret_rect) { |
| 322 // Reset the IME state and finish an ongoing composition in the renderer. | 319 // Reset the IME state and finish an ongoing composition in the renderer. |
| 323 if (control == IME_DISABLE || control == IME_COMPLETE_COMPOSITION) | 320 if (control == IME_DISABLE || control == IME_COMPLETE_COMPOSITION) |
| 324 IMECleanupComposition(); | 321 [cocoa_view_ cancelComposition]; |
| 325 | 322 |
| 326 // We need to convert the coordinate of the cursor rectangle sent from the | 323 // We need to convert the coordinate of the cursor rectangle sent from the |
| 327 // renderer and save it. Our IME backend uses a coordinate system whose | 324 // renderer and save it. Our IME backend uses a coordinate system whose |
| 328 // origin is the upper-left corner of this view. On the other hand, Cocoa | 325 // origin is the upper-left corner of this view. On the other hand, Cocoa |
| 329 // uses a coordinate system whose origin is the lower-left corner of this | 326 // uses a coordinate system whose origin is the lower-left corner of this |
| 330 // view. So, we convert the cursor rectangle and save it. | 327 // view. So, we convert the cursor rectangle and save it. |
| 331 NSRect view_rect = [cocoa_view_ bounds]; | 328 [cocoa_view_ setCaretRect:[cocoa_view_ RectToNSRect:caret_rect]]; |
| 332 const int y_offset = static_cast<int>(view_rect.size.height); | |
| 333 im_caret_rect_ = NSMakeRect(caret_rect.x(), | |
| 334 y_offset - caret_rect.y() - caret_rect.height(), | |
| 335 caret_rect.width(), caret_rect.height()); | |
| 336 } | 329 } |
| 337 | 330 |
| 338 void RenderWidgetHostViewMac::DidPaintBackingStoreRects( | 331 void RenderWidgetHostViewMac::DidPaintBackingStoreRects( |
| 339 const std::vector<gfx::Rect>& rects) { | 332 const std::vector<gfx::Rect>& rects) { |
| 340 if (is_hidden_) | 333 if (is_hidden_) |
| 341 return; | 334 return; |
| 342 | 335 |
| 343 for (size_t i = 0; i < rects.size(); ++i) { | 336 for (size_t i = 0; i < rects.size(); ++i) { |
| 344 NSRect ns_rect = [cocoa_view_ RectToNSRect:rects[i]]; | 337 NSRect ns_rect = [cocoa_view_ RectToNSRect:rects[i]]; |
| 345 | 338 |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 537 | 530 |
| 538 void RenderWidgetHostViewMac::KillSelf() { | 531 void RenderWidgetHostViewMac::KillSelf() { |
| 539 if (shutdown_factory_.empty()) { | 532 if (shutdown_factory_.empty()) { |
| 540 [cocoa_view_ setHidden:YES]; | 533 [cocoa_view_ setHidden:YES]; |
| 541 MessageLoop::current()->PostTask(FROM_HERE, | 534 MessageLoop::current()->PostTask(FROM_HERE, |
| 542 shutdown_factory_.NewRunnableMethod( | 535 shutdown_factory_.NewRunnableMethod( |
| 543 &RenderWidgetHostViewMac::ShutdownHost)); | 536 &RenderWidgetHostViewMac::ShutdownHost)); |
| 544 } | 537 } |
| 545 } | 538 } |
| 546 | 539 |
| 547 void RenderWidgetHostViewMac::IMECleanupComposition() { | |
| 548 if (!im_composing_) | |
| 549 return; | |
| 550 | |
| 551 // Cancel the ongoing composition. [NSInputManager markedTextAbandoned:] | |
| 552 // doesn't call any NSTextInput functions, such as setMarkedText or | |
| 553 // insertText. So, we need to send an IPC message to a renderer so it can | |
| 554 // delete the composition node. | |
| 555 NSInputManager *currentInputManager = [NSInputManager currentInputManager]; | |
| 556 [currentInputManager markedTextAbandoned:[cocoa_view_ self]]; | |
| 557 | |
| 558 render_widget_host_->ImeCancelComposition(); | |
| 559 im_text_.clear(); | |
| 560 im_composing_ = false; | |
| 561 } | |
| 562 | |
| 563 gfx::PluginWindowHandle | 540 gfx::PluginWindowHandle |
| 564 RenderWidgetHostViewMac::AllocateFakePluginWindowHandle(bool opaque) { | 541 RenderWidgetHostViewMac::AllocateFakePluginWindowHandle(bool opaque) { |
| 565 // Make sure we have a layer for the plugin to draw into. | 542 // Make sure we have a layer for the plugin to draw into. |
| 566 [cocoa_view_ ensureAcceleratedPluginLayer]; | 543 [cocoa_view_ ensureAcceleratedPluginLayer]; |
| 567 | 544 |
| 568 return plugin_container_manager_.AllocateFakePluginWindowHandle(opaque); | 545 return plugin_container_manager_.AllocateFakePluginWindowHandle(opaque); |
| 569 } | 546 } |
| 570 | 547 |
| 571 void RenderWidgetHostViewMac::DestroyFakePluginWindowHandle( | 548 void RenderWidgetHostViewMac::DestroyFakePluginWindowHandle( |
| 572 gfx::PluginWindowHandle window) { | 549 gfx::PluginWindowHandle window) { |
| (...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 773 [[EditCommandMatcher alloc] initWithEditCommands:edit_commands]); | 750 [[EditCommandMatcher alloc] initWithEditCommands:edit_commands]); |
| 774 [matcher.get() interpretKeyEvents:[NSArray arrayWithObject:theEvent]]; | 751 [matcher.get() interpretKeyEvents:[NSArray arrayWithObject:theEvent]]; |
| 775 } | 752 } |
| 776 | 753 |
| 777 @end | 754 @end |
| 778 | 755 |
| 779 // RenderWidgetHostViewCocoa --------------------------------------------------- | 756 // RenderWidgetHostViewCocoa --------------------------------------------------- |
| 780 | 757 |
| 781 @implementation RenderWidgetHostViewCocoa | 758 @implementation RenderWidgetHostViewCocoa |
| 782 | 759 |
| 760 @synthesize caretRect = caretRect_; |
| 761 |
| 783 - (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r { | 762 - (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r { |
| 784 self = [super initWithFrame:NSZeroRect]; | 763 self = [super initWithFrame:NSZeroRect]; |
| 785 if (self != nil) { | 764 if (self != nil) { |
| 786 editCommand_helper_.reset(new RWHVMEditCommandHelper); | 765 editCommand_helper_.reset(new RWHVMEditCommandHelper); |
| 787 editCommand_helper_->AddEditingSelectorsToClass([self class]); | 766 editCommand_helper_->AddEditingSelectorsToClass([self class]); |
| 788 | 767 |
| 789 renderWidgetHostView_.reset(r); | 768 renderWidgetHostView_.reset(r); |
| 790 canBeKeyView_ = YES; | 769 canBeKeyView_ = YES; |
| 791 closeOnDeactivate_ = NO; | 770 closeOnDeactivate_ = NO; |
| 792 } | 771 } |
| (...skipping 14 matching lines...) Expand all Loading... |
| 807 // popup. A click outside the text field would cause the text field to drop | 786 // popup. A click outside the text field would cause the text field to drop |
| 808 // the focus, and then EditorClientImpl::textFieldDidEndEditing() would cancel | 787 // the focus, and then EditorClientImpl::textFieldDidEndEditing() would cancel |
| 809 // the popup anyway, so we're OK. | 788 // the popup anyway, so we're OK. |
| 810 | 789 |
| 811 const WebMouseEvent& event = | 790 const WebMouseEvent& event = |
| 812 WebInputEventFactory::mouseEvent(theEvent, self); | 791 WebInputEventFactory::mouseEvent(theEvent, self); |
| 813 if (renderWidgetHostView_->render_widget_host_) | 792 if (renderWidgetHostView_->render_widget_host_) |
| 814 renderWidgetHostView_->render_widget_host_->ForwardMouseEvent(event); | 793 renderWidgetHostView_->render_widget_host_->ForwardMouseEvent(event); |
| 815 | 794 |
| 816 if ([theEvent type] == NSLeftMouseDown) { | 795 if ([theEvent type] == NSLeftMouseDown) { |
| 817 renderWidgetHostView_->IMECleanupComposition(); | 796 [self cancelComposition]; |
| 818 | 797 |
| 819 hasOpenMouseDown_ = YES; | 798 hasOpenMouseDown_ = YES; |
| 820 } | 799 } |
| 821 | 800 |
| 822 if ([theEvent type] == NSLeftMouseUp) { | 801 if ([theEvent type] == NSLeftMouseUp) { |
| 823 hasOpenMouseDown_ = NO; | 802 hasOpenMouseDown_ = NO; |
| 824 } | 803 } |
| 825 } | 804 } |
| 826 | 805 |
| 827 - (BOOL)performKeyEquivalent:(NSEvent*)theEvent { | 806 - (BOOL)performKeyEquivalent:(NSEvent*)theEvent { |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 874 !equiv == !([theEvent modifierFlags] & NSCommandKeyMask)); | 853 !equiv == !([theEvent modifierFlags] & NSCommandKeyMask)); |
| 875 | 854 |
| 876 if ([theEvent type] == NSFlagsChanged) { | 855 if ([theEvent type] == NSFlagsChanged) { |
| 877 // Ignore NSFlagsChanged events from the NumLock and Fn keys as | 856 // Ignore NSFlagsChanged events from the NumLock and Fn keys as |
| 878 // Safari does in -[WebHTMLView flagsChanged:] (of "WebHTMLView.mm"). | 857 // Safari does in -[WebHTMLView flagsChanged:] (of "WebHTMLView.mm"). |
| 879 int keyCode = [theEvent keyCode]; | 858 int keyCode = [theEvent keyCode]; |
| 880 if (!keyCode || keyCode == 10 || keyCode == 63) | 859 if (!keyCode || keyCode == 10 || keyCode == 63) |
| 881 return; | 860 return; |
| 882 } | 861 } |
| 883 | 862 |
| 863 // Don't cancel child popups; the key events are probably what's triggering |
| 864 // the popup in the first place. |
| 865 |
| 866 RenderWidgetHost* widgetHost = renderWidgetHostView_->render_widget_host_; |
| 867 DCHECK(widgetHost); |
| 868 |
| 869 NativeWebKeyboardEvent event(theEvent); |
| 870 |
| 871 // We only handle key down events and just simply forward other events. |
| 872 if ([theEvent type] != NSKeyDown) { |
| 873 widgetHost->ForwardKeyboardEvent(event); |
| 874 |
| 875 // Possibly autohide the cursor. |
| 876 if ([RenderWidgetHostViewCocoa shouldAutohideCursorForEvent:theEvent]) |
| 877 [NSCursor setHiddenUntilMouseMoves:YES]; |
| 878 |
| 879 return; |
| 880 } |
| 881 |
| 884 scoped_nsobject<RenderWidgetHostViewCocoa> keepSelfAlive([self retain]); | 882 scoped_nsobject<RenderWidgetHostViewCocoa> keepSelfAlive([self retain]); |
| 885 | 883 |
| 886 // Don't cancel child popups; the key events are probably what's triggering | 884 // Records the current marked text state, so that we can know if the marked |
| 887 // the popup in the first place. | 885 // text was deleted or not after handling the key down event. |
| 886 BOOL oldHasMarkedText = hasMarkedText_; |
| 888 | 887 |
| 889 NativeWebKeyboardEvent event(theEvent); | 888 // This method should not be called recursively. |
| 889 DCHECK(!handlingKeyDown_); |
| 890 | 890 |
| 891 // Save the modifier keys so the insertText method can use it when it sends | 891 // Tells insertText: and doCommandBySelector: that we are handling a key |
| 892 // a Char event, which is dispatched as an onkeypress() event of JavaScript. | 892 // down event. |
| 893 renderWidgetHostView_->im_modifiers_ = event.modifiers; | 893 handlingKeyDown_ = YES; |
| 894 |
| 895 // These two variables might be set when handling the keyboard event. |
| 896 // Clear them here so that we can know whether they have changed afterwards. |
| 897 textToBeInserted_.clear(); |
| 898 newMarkedText_.clear(); |
| 899 |
| 900 // Sends key down events to input method first, then we can decide what should |
| 901 // be done according to input method's feedback. |
| 902 [self interpretKeyEvents:[NSArray arrayWithObject:theEvent]]; |
| 903 |
| 904 handlingKeyDown_ = NO; |
| 894 | 905 |
| 895 // To emulate Windows, over-write |event.windowsKeyCode| to VK_PROCESSKEY | 906 // To emulate Windows, over-write |event.windowsKeyCode| to VK_PROCESSKEY |
| 896 // while an input method is composing a text. | 907 // while an input method is composing or inserting a text. |
| 897 // Gmail checks this code in its onkeydown handler to stop auto-completing | 908 // Gmail checks this code in its onkeydown handler to stop auto-completing |
| 898 // e-mail addresses while composing a CJK text. | 909 // e-mail addresses while composing a CJK text. |
| 899 if ([theEvent type] == NSKeyDown && renderWidgetHostView_->im_composing_) { | 910 // If the text to be inserted has only one character, then we don't need this |
| 911 // trick, because we'll send the text as a key press event instead. |
| 912 if (hasMarkedText_ || oldHasMarkedText || textToBeInserted_.length() > 1) { |
| 900 event.windowsKeyCode = 0xE5; // VKEY_PROCESSKEY | 913 event.windowsKeyCode = 0xE5; // VKEY_PROCESSKEY |
| 901 event.setKeyIdentifierFromWindowsKeyCode(); | 914 event.setKeyIdentifierFromWindowsKeyCode(); |
| 902 event.skip_in_browser = true; | 915 event.skip_in_browser = true; |
| 903 } | 916 } else { |
| 904 | |
| 905 // Dispatch this keyboard event to the renderer. | |
| 906 if (renderWidgetHostView_->render_widget_host_) { | |
| 907 RenderWidgetHost* widgetHost = renderWidgetHostView_->render_widget_host_; | |
| 908 // Look up shortcut, if any, for this key combination. | 917 // Look up shortcut, if any, for this key combination. |
| 909 EditCommands editCommands; | 918 EditCommands editCommands; |
| 910 [EditCommandMatcher matchEditCommands:&editCommands forEvent:theEvent]; | 919 [EditCommandMatcher matchEditCommands:&editCommands forEvent:theEvent]; |
| 911 if (!editCommands.empty()) | 920 if (!editCommands.empty()) |
| 912 widgetHost->ForwardEditCommandsForNextKeyEvent(editCommands); | 921 widgetHost->ForwardEditCommandsForNextKeyEvent(editCommands); |
| 913 widgetHost->ForwardKeyboardEvent(event); | |
| 914 } | 922 } |
| 915 | 923 |
| 916 currentKeyEvent_.reset([theEvent retain]); | 924 // Forward the key down event first. |
| 917 textInserted_ = NO; | 925 widgetHost->ForwardKeyboardEvent(event); |
| 918 | 926 |
| 919 // Dispatch a NSKeyDown event to an input method. | 927 // Calling ForwardKeyboardEvent() could have destroyed the widget. When the |
| 920 // To send an onkeydown() event before an onkeypress() event, we should | 928 // widget was destroyed, |renderWidgetHostView_->render_widget_host_| will |
| 921 // dispatch this NSKeyDown event AFTER sending it to the renderer. | 929 // be set to NULL. So we check it here and return immediately if it's NULL. |
| 922 // (See <https://bugs.webkit.org/show_bug.cgi?id=25119>). | 930 if (!renderWidgetHostView_->render_widget_host_) |
| 923 // | 931 return; |
| 924 // If this object's retainCount is 1, the only reference is the one held by | |
| 925 // keepSelfAlive. All other references may have been destroyed in the | |
| 926 // RenderWidgetHost::ForwardKeyboardEvent call above if it resulted in tab | |
| 927 // closure. Were it not for that single reference, this object would | |
| 928 // already be deallocated. In that case, there's no point in calling | |
| 929 // -interpretKeyEvents:. | |
| 930 if ([self retainCount] > 1 && [theEvent type] == NSKeyDown) { | |
| 931 [self interpretKeyEvents:[NSArray arrayWithObject:theEvent]]; | |
| 932 | 932 |
| 933 // Then send keypress and/or composition related events. |
| 934 // If there was a marked text or the text to be inserted is longer than 1 |
| 935 // character, then we send the text by calling ImeConfirmComposition(). |
| 936 // Otherwise, if the text to be inserted only contains 1 character, then we |
| 937 // can just send a keypress event which is fabricated by changing the type of |
| 938 // the keydown event, so that we can retain all necessary informations, such |
| 939 // as unmodifiedText, etc. And we need to set event.skip_in_browser to true to |
| 940 // prevent the browser from handling it again. |
| 941 // Note that, |textToBeInserted_| is a UTF-16 string, but it's fine to only |
| 942 // handle BMP characters here, as we can always insert non-BMP characters as |
| 943 // text. |
| 944 const NSUInteger kCtrlCmdKeyMask = NSControlKeyMask | NSCommandKeyMask; |
| 945 BOOL textInserted = NO; |
| 946 if (textToBeInserted_.length() > (oldHasMarkedText ? 0 : 1)) { |
| 947 widgetHost->ImeConfirmComposition(textToBeInserted_); |
| 948 textInserted = YES; |
| 949 } else if (textToBeInserted_.length() == 1) { |
| 950 event.type = WebKit::WebInputEvent::Char; |
| 951 event.text[0] = textToBeInserted_[0]; |
| 952 event.text[1] = 0; |
| 953 event.skip_in_browser = true; |
| 954 widgetHost->ForwardKeyboardEvent(event); |
| 955 } else if (([theEvent modifierFlags] & kCtrlCmdKeyMask) && |
| 956 [[theEvent characters] length] > 0) { |
| 933 // We don't get insertText: calls if ctrl is down and not even a keyDown: | 957 // We don't get insertText: calls if ctrl is down and not even a keyDown: |
| 934 // call if cmd is down, so synthesize a keypress event for these cases. | 958 // call if cmd is down, so synthesize a keypress event for these cases. |
| 935 // Note that this makes our behavior deviate from the windows and linux | 959 // Note that this makes our behavior deviate from the windows and linux |
| 936 // versions of chrome (however, see http://crbug.com/13891 ), but it makes | 960 // versions of chrome (however, see http://crbug.com/13891 ), but it makes |
| 937 // us behave similar to how Safari behaves. | 961 // us behave similar to how Safari behaves. |
| 938 if ([theEvent modifierFlags] & (NSControlKeyMask | NSCommandKeyMask) && | 962 event.type = WebKit::WebInputEvent::Char; |
| 939 !textInserted_ && [[theEvent characters] length] > 0 && | 963 event.skip_in_browser = true; |
| 940 renderWidgetHostView_->render_widget_host_) { | 964 widgetHost->ForwardKeyboardEvent(event); |
| 941 // Just fabricate a Char event by changing the type of the RawKeyDown | |
| 942 // event, to retain all necessary informations, such as unmodifiedText. | |
| 943 event.type = WebKit::WebInputEvent::Char; | |
| 944 // We fire menu items on keydown, we don't want to activate menu items | |
| 945 // twice. | |
| 946 event.skip_in_browser = true; | |
| 947 renderWidgetHostView_->render_widget_host_->ForwardKeyboardEvent(event); | |
| 948 } | |
| 949 } | 965 } |
| 950 | 966 |
| 951 currentKeyEvent_.reset(); | 967 // Updates or cancels the composition. If some text has been inserted, then |
| 968 // we don't need to cancel the composition explicitly. |
| 969 if (hasMarkedText_ && newMarkedText_.length()) { |
| 970 // Sends the updated marked text to the renderer so it can update the |
| 971 // composition node in WebKit. |
| 972 // When marked text is available, |selectedRange_| will be the range being |
| 973 // selected inside the marked text. We put the cursor at the beginning of |
| 974 // the selected range. |
| 975 widgetHost->ImeSetComposition(newMarkedText_, |
| 976 selectedRange_.location, |
| 977 selectedRange_.location, |
| 978 NSMaxRange(selectedRange_)); |
| 979 } else if (oldHasMarkedText && !hasMarkedText_ && !textInserted) { |
| 980 widgetHost->ImeCancelComposition(); |
| 981 } |
| 952 | 982 |
| 953 // Possibly autohide the cursor. | 983 // Possibly autohide the cursor. |
| 954 if ([RenderWidgetHostViewCocoa shouldAutohideCursorForEvent:theEvent]) | 984 if ([RenderWidgetHostViewCocoa shouldAutohideCursorForEvent:theEvent]) |
| 955 [NSCursor setHiddenUntilMouseMoves:YES]; | 985 [NSCursor setHiddenUntilMouseMoves:YES]; |
| 956 } | 986 } |
| 957 | 987 |
| 958 - (void)scrollWheel:(NSEvent *)theEvent { | 988 - (void)scrollWheel:(NSEvent *)theEvent { |
| 959 [self cancelChildPopups]; | 989 [self cancelChildPopups]; |
| 960 | 990 |
| 961 const WebMouseWheelEvent& event = | 991 const WebMouseWheelEvent& event = |
| (...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1141 return NO; | 1171 return NO; |
| 1142 | 1172 |
| 1143 return canBeKeyView_; | 1173 return canBeKeyView_; |
| 1144 } | 1174 } |
| 1145 | 1175 |
| 1146 - (BOOL)becomeFirstResponder { | 1176 - (BOOL)becomeFirstResponder { |
| 1147 if (!renderWidgetHostView_->render_widget_host_) | 1177 if (!renderWidgetHostView_->render_widget_host_) |
| 1148 return NO; | 1178 return NO; |
| 1149 | 1179 |
| 1150 renderWidgetHostView_->render_widget_host_->Focus(); | 1180 renderWidgetHostView_->render_widget_host_->Focus(); |
| 1181 renderWidgetHostView_->render_widget_host_->ImeSetInputMode(true); |
| 1151 return YES; | 1182 return YES; |
| 1152 } | 1183 } |
| 1153 | 1184 |
| 1154 - (BOOL)resignFirstResponder { | 1185 - (BOOL)resignFirstResponder { |
| 1155 if (!renderWidgetHostView_->render_widget_host_) | 1186 if (!renderWidgetHostView_->render_widget_host_) |
| 1156 return YES; | 1187 return YES; |
| 1157 | 1188 |
| 1158 if (closeOnDeactivate_) | 1189 if (closeOnDeactivate_) |
| 1159 renderWidgetHostView_->KillSelf(); | 1190 renderWidgetHostView_->KillSelf(); |
| 1160 | 1191 |
| 1192 renderWidgetHostView_->render_widget_host_->ImeSetInputMode(false); |
| 1161 renderWidgetHostView_->render_widget_host_->Blur(); | 1193 renderWidgetHostView_->render_widget_host_->Blur(); |
| 1162 | |
| 1163 return YES; | 1194 return YES; |
| 1164 } | 1195 } |
| 1165 | 1196 |
| 1166 - (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item { | 1197 - (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item { |
| 1167 SEL action = [item action]; | 1198 SEL action = [item action]; |
| 1168 | 1199 |
| 1169 // For now, these actions are always enabled for render view, | 1200 // For now, these actions are always enabled for render view, |
| 1170 // this is sub-optimal. | 1201 // this is sub-optimal. |
| 1171 // TODO(suzhe): Plumb the "can*" methods up from WebCore. | 1202 // TODO(suzhe): Plumb the "can*" methods up from WebCore. |
| 1172 if (action == @selector(undo:) || | 1203 if (action == @selector(undo:) || |
| (...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1487 // | 1518 // |
| 1488 // Since this implementation doesn't have to wait any IPC calls, this doesn't | 1519 // Since this implementation doesn't have to wait any IPC calls, this doesn't |
| 1489 // make any key-typing jank. --hbono 7/23/09 | 1520 // make any key-typing jank. --hbono 7/23/09 |
| 1490 // | 1521 // |
| 1491 extern "C" { | 1522 extern "C" { |
| 1492 extern NSString *NSTextInputReplacementRangeAttributeName; | 1523 extern NSString *NSTextInputReplacementRangeAttributeName; |
| 1493 } | 1524 } |
| 1494 | 1525 |
| 1495 - (NSArray *)validAttributesForMarkedText { | 1526 - (NSArray *)validAttributesForMarkedText { |
| 1496 // This code is just copied from WebKit except renaming variables. | 1527 // This code is just copied from WebKit except renaming variables. |
| 1497 if (!renderWidgetHostView_->im_attributes_) { | 1528 if (!validAttributesForMarkedText_) { |
| 1498 renderWidgetHostView_->im_attributes_ = [[NSArray alloc] initWithObjects: | 1529 validAttributesForMarkedText_.reset([[NSArray alloc] initWithObjects: |
| 1499 NSUnderlineStyleAttributeName, | 1530 NSUnderlineStyleAttributeName, |
| 1500 NSUnderlineColorAttributeName, | 1531 NSUnderlineColorAttributeName, |
| 1501 NSMarkedClauseSegmentAttributeName, | 1532 NSMarkedClauseSegmentAttributeName, |
| 1502 NSTextInputReplacementRangeAttributeName, | 1533 NSTextInputReplacementRangeAttributeName, |
| 1503 nil]; | 1534 nil]); |
| 1504 } | 1535 } |
| 1505 return renderWidgetHostView_->im_attributes_; | 1536 return validAttributesForMarkedText_.get(); |
| 1506 } | 1537 } |
| 1507 | 1538 |
| 1508 - (NSUInteger)characterIndexForPoint:(NSPoint)thePoint { | 1539 - (NSUInteger)characterIndexForPoint:(NSPoint)thePoint { |
| 1509 NOTIMPLEMENTED(); | 1540 NOTIMPLEMENTED(); |
| 1510 return NSNotFound; | 1541 return NSNotFound; |
| 1511 } | 1542 } |
| 1512 | 1543 |
| 1513 - (NSRect)firstRectForCharacterRange:(NSRange)theRange { | 1544 - (NSRect)firstRectForCharacterRange:(NSRange)theRange { |
| 1514 // An input method requests a cursor rectangle to display its candidate | 1545 // An input method requests a cursor rectangle to display its candidate |
| 1515 // window. | 1546 // window. |
| 1516 // Calculate the screen coordinate of the cursor rectangle saved in | 1547 // Calculate the screen coordinate of the cursor rectangle saved in |
| 1517 // RenderWidgetHostViewMac::IMEUpdateStatus() and send it to the IME. | 1548 // RenderWidgetHostViewMac::IMEUpdateStatus() and send it to the IME. |
| 1518 // Since this window may be moved since we receive the cursor rectangle last | 1549 // Since this window may be moved since we receive the cursor rectangle last |
| 1519 // time we sent the cursor rectangle to the IME, so we should map from the | 1550 // time we sent the cursor rectangle to the IME, so we should map from the |
| 1520 // view coordinate to the screen coordinate every time when an IME need it. | 1551 // view coordinate to the screen coordinate every time when an IME need it. |
| 1521 NSRect resultRect = renderWidgetHostView_->im_caret_rect_; | 1552 NSRect resultRect = [self convertRect:caretRect_ toView:nil]; |
| 1522 resultRect = [self convertRect:resultRect toView:nil]; | |
| 1523 NSWindow* window = [self window]; | 1553 NSWindow* window = [self window]; |
| 1524 if (window) | 1554 if (window) |
| 1525 resultRect.origin = [window convertBaseToScreen:resultRect.origin]; | 1555 resultRect.origin = [window convertBaseToScreen:resultRect.origin]; |
| 1526 return resultRect; | 1556 return resultRect; |
| 1527 } | 1557 } |
| 1528 | 1558 |
| 1529 - (NSRange)selectedRange { | 1559 - (NSRange)selectedRange { |
| 1530 // Return the selected range saved in the setMarkedText method. | 1560 // Return the selected range saved in the setMarkedText method. |
| 1531 return renderWidgetHostView_->im_selected_range_; | 1561 return hasMarkedText_ ? selectedRange_ : NSMakeRange(NSNotFound, 0); |
| 1532 } | 1562 } |
| 1533 | 1563 |
| 1534 - (NSRange)markedRange { | 1564 - (NSRange)markedRange { |
| 1535 // An input method calls this method to check if an application really has | 1565 // An input method calls this method to check if an application really has |
| 1536 // a text being composed when hasMarkedText call returns true. | 1566 // a text being composed when hasMarkedText call returns true. |
| 1537 // Returns the range saved in the setMarkedText method so the input method | 1567 // Returns the range saved in the setMarkedText method so the input method |
| 1538 // calls the setMarkedText method and we can update the composition node | 1568 // calls the setMarkedText method and we can update the composition node |
| 1539 // there. (When this method returns an empty range, the input method doesn't | 1569 // there. (When this method returns an empty range, the input method doesn't |
| 1540 // call the setMarkedText method.) | 1570 // call the setMarkedText method.) |
| 1541 return renderWidgetHostView_->im_marked_range_; | 1571 return hasMarkedText_ ? markedRange_ : NSMakeRange(NSNotFound, 0); |
| 1542 } | 1572 } |
| 1543 | 1573 |
| 1544 - (NSAttributedString *)attributedSubstringFromRange:(NSRange)nsRange { | 1574 - (NSAttributedString *)attributedSubstringFromRange:(NSRange)nsRange { |
| 1545 // TODO(hbono): Even though many input method works without implementing | 1575 // TODO(hbono): Even though many input method works without implementing |
| 1546 // this method, we need to save a copy of the string in the setMarkedText | 1576 // this method, we need to save a copy of the string in the setMarkedText |
| 1547 // method and create a NSAttributedString with the given range. | 1577 // method and create a NSAttributedString with the given range. |
| 1548 // http://crbug.com/37715 | 1578 // http://crbug.com/37715 |
| 1549 return nil; | 1579 return nil; |
| 1550 } | 1580 } |
| 1551 | 1581 |
| 1552 - (NSInteger)conversationIdentifier { | 1582 - (NSInteger)conversationIdentifier { |
| 1553 return reinterpret_cast<NSInteger>(self); | 1583 return reinterpret_cast<NSInteger>(self); |
| 1554 } | 1584 } |
| 1555 | 1585 |
| 1556 - (BOOL)hasMarkedText { | 1586 - (BOOL)hasMarkedText { |
| 1557 // An input method calls this function to figure out whether or not an | 1587 // An input method calls this function to figure out whether or not an |
| 1558 // application is really composing a text. If it is composing, it calls | 1588 // application is really composing a text. If it is composing, it calls |
| 1559 // the markedRange method, and maybe calls the setMarkedTest method. | 1589 // the markedRange method, and maybe calls the setMarkedText method. |
| 1560 // It seems an input method usually calls this function when it is about to | 1590 // It seems an input method usually calls this function when it is about to |
| 1561 // cancel an ongoing composition. If an application has a non-empty marked | 1591 // cancel an ongoing composition. If an application has a non-empty marked |
| 1562 // range, it calls the setMarkedText method to delete the range. | 1592 // range, it calls the setMarkedText method to delete the range. |
| 1563 return renderWidgetHostView_->im_composing_ ? YES : NO; | 1593 return hasMarkedText_; |
| 1564 } | 1594 } |
| 1565 | 1595 |
| 1566 - (void)unmarkText { | 1596 - (void)unmarkText { |
| 1567 // Delete the composition node of the renderer and finish an ongoing | 1597 // Delete the composition node of the renderer and finish an ongoing |
| 1568 // composition. | 1598 // composition. |
| 1569 // It seems an input method calls the setMarkedText method and set an empty | 1599 // It seems an input method calls the setMarkedText method and set an empty |
| 1570 // text when it cancels an ongoing composition, i.e. I have never seen an | 1600 // text when it cancels an ongoing composition, i.e. I have never seen an |
| 1571 // input method calls this method. | 1601 // input method calls this method. |
| 1572 renderWidgetHostView_->render_widget_host_->ImeCancelComposition(); | 1602 hasMarkedText_ = NO; |
| 1573 renderWidgetHostView_->im_composing_ = false; | 1603 |
| 1604 // If we are handling a key down event, then ImeCancelComposition() will be |
| 1605 // called in keyEvent: method. |
| 1606 if (!handlingKeyDown_) |
| 1607 renderWidgetHostView_->render_widget_host_->ImeCancelComposition(); |
| 1574 } | 1608 } |
| 1575 | 1609 |
| 1576 - (void)setMarkedText:(id)string selectedRange:(NSRange)newSelRange { | 1610 - (void)setMarkedText:(id)string selectedRange:(NSRange)newSelRange { |
| 1577 // An input method updates the composition string. | 1611 // An input method updates the composition string. |
| 1578 // We send the given text and range to the renderer so it can update the | 1612 // We send the given text and range to the renderer so it can update the |
| 1579 // composition node of WebKit. | 1613 // composition node of WebKit. |
| 1580 BOOL isAttributedString = [string isKindOfClass:[NSAttributedString class]]; | 1614 BOOL isAttributedString = [string isKindOfClass:[NSAttributedString class]]; |
| 1581 NSString* im_text = isAttributedString ? [string string] : string; | 1615 NSString* im_text = isAttributedString ? [string string] : string; |
| 1582 int length = [im_text length]; | 1616 int length = [im_text length]; |
| 1583 int cursor = newSelRange.location; | |
| 1584 | 1617 |
| 1585 int target_start; | 1618 markedRange_ = NSMakeRange(0, length); |
| 1586 int target_end; | 1619 selectedRange_ = newSelRange; |
| 1587 if (!newSelRange.length) { | 1620 newMarkedText_ = base::SysNSStringToUTF16(im_text); |
| 1588 // The given text doesn't have any range to be highlighted. Clear the | 1621 hasMarkedText_ = (length > 0); |
| 1589 // selection range. | |
| 1590 target_start = 0; | |
| 1591 target_end = 0; | |
| 1592 } else { | |
| 1593 // The given text has a range to be highlighted. | |
| 1594 // Set the selection range to the given one and put the cursor at the | |
| 1595 // beginning of the selection range. | |
| 1596 target_start = newSelRange.location; | |
| 1597 target_end = NSMaxRange(newSelRange); | |
| 1598 } | |
| 1599 | 1622 |
| 1600 // Dispatch this IME event to the renderer and update the IME state of this | 1623 // If we are handling a key down event, then ImeSetComposition() will be |
| 1601 // object. | 1624 // called in keyEvent: method. |
| 1602 // Input methods of Mac use setMarkedText calls with an empty text to cancel | 1625 // Input methods of Mac use setMarkedText calls with an empty text to cancel |
| 1603 // an ongoing composition. So, we should check whether or not the given text | 1626 // an ongoing composition. So, we should check whether or not the given text |
| 1604 // is empty to update the IME state. (Our IME backend can automatically | 1627 // is empty to update the IME state. (Our IME backend can automatically |
| 1605 // cancels an ongoing composition when we send an empty text. So, it is OK | 1628 // cancels an ongoing composition when we send an empty text. So, it is OK |
| 1606 // to send an empty text to the renderer.) | 1629 // to send an empty text to the renderer.) |
| 1607 renderWidgetHostView_->im_text_ = UTF8ToUTF16([im_text UTF8String]); | 1630 if (!handlingKeyDown_) { |
| 1608 renderWidgetHostView_->render_widget_host_->ImeSetComposition( | 1631 renderWidgetHostView_->render_widget_host_->ImeSetComposition( |
| 1609 renderWidgetHostView_->im_text_, cursor, target_start, target_end); | 1632 newMarkedText_, newSelRange.location, newSelRange.location, |
| 1610 renderWidgetHostView_->GetRenderWidgetHost()->ImeSetInputMode(true); | 1633 NSMaxRange(newSelRange)); |
| 1611 renderWidgetHostView_->im_composing_ = length > 0; | 1634 } |
| 1612 renderWidgetHostView_->im_marked_range_.location = 0; | |
| 1613 renderWidgetHostView_->im_marked_range_.length = length; | |
| 1614 renderWidgetHostView_->im_selected_range_.location = newSelRange.location; | |
| 1615 renderWidgetHostView_->im_selected_range_.length = newSelRange.length; | |
| 1616 } | 1635 } |
| 1617 | 1636 |
| 1618 - (void)doCommandBySelector:(SEL)selector { | 1637 - (void)doCommandBySelector:(SEL)selector { |
| 1619 // An input method calls this function to dispatch an editing command to be | 1638 // An input method calls this function to dispatch an editing command to be |
| 1620 // handled by this view. | 1639 // handled by this view. |
| 1621 // Even though most editing commands has been already handled by the | 1640 // Even though most editing commands has been already handled by the |
| 1622 // RWHVMEditCommandHelper object, we need to handle an insertNewline: command | 1641 // RWHVMEditCommandHelper object, we need to handle an insertNewline: command |
| 1623 // and send a '\r' character to WebKit so that WebKit dispatches this | 1642 // and send a '\r' character to WebKit so that WebKit dispatches this |
| 1624 // character to onkeypress() event handlers. | 1643 // character to onkeypress() event handlers. |
| 1625 // TODO(hbono): need to handle more commands? | 1644 // TODO(hbono): need to handle more commands? |
| 1626 if (selector == @selector(insertNewline:)) { | 1645 if (selector == @selector(insertNewline:)) { |
| 1627 if (currentKeyEvent_.get()) { | 1646 if (handlingKeyDown_) { |
| 1628 // Create the Char event from the NSEvent object, so that we can retain | 1647 // If we are handling a key down event, then we just need to append a '\r' |
| 1629 // necessary informations, especially unmodifiedText. | 1648 // character to |textToBeInserted_| which will then be handled by |
| 1630 NativeWebKeyboardEvent event(currentKeyEvent_.get()); | 1649 // keyEvent: method. |
| 1631 event.type = WebKit::WebInputEvent::Char; | 1650 textToBeInserted_.push_back('\r'); |
| 1632 event.text[0] = '\r'; | |
| 1633 event.text[1] = 0; | |
| 1634 event.skip_in_browser = true; | |
| 1635 renderWidgetHostView_->render_widget_host_->ForwardKeyboardEvent(event); | |
| 1636 } else { | 1651 } else { |
| 1637 // This call is not initiated by a key event, so just executed the | 1652 // This call is not initiated by a key event, so just executed the |
| 1638 // corresponding editor command. | 1653 // corresponding editor command. |
| 1639 renderWidgetHostView_->render_widget_host_->ForwardEditCommand( | 1654 renderWidgetHostView_->render_widget_host_->ForwardEditCommand( |
| 1640 "InsertNewline", ""); | 1655 "InsertNewline", ""); |
| 1641 } | 1656 } |
| 1642 textInserted_ = YES; | |
| 1643 } | 1657 } |
| 1644 } | 1658 } |
| 1645 | 1659 |
| 1646 - (void)insertText:(id)string { | 1660 - (void)insertText:(id)string { |
| 1647 // An input method has characters to be inserted. | 1661 // An input method has characters to be inserted. |
| 1648 // Same as Linux, Mac calls this method not only: | 1662 // Same as Linux, Mac calls this method not only: |
| 1649 // * when an input method finishs composing text, but also; | 1663 // * when an input method finishs composing text, but also; |
| 1650 // * when we type an ASCII character (without using input methods). | 1664 // * when we type an ASCII character (without using input methods). |
| 1651 // When we aren't using input methods, we should send the given character as | 1665 // When we aren't using input methods, we should send the given character as |
| 1652 // a Char event so it is dispatched to an onkeypress() event handler of | 1666 // a Char event so it is dispatched to an onkeypress() event handler of |
| 1653 // JavaScript. | 1667 // JavaScript. |
| 1654 // On the other hand, when we are using input methods, we should send the | 1668 // On the other hand, when we are using input methods, we should send the |
| 1655 // given characters as an IME event and prevent the characters from being | 1669 // given characters as an IME event and prevent the characters from being |
| 1656 // dispatched to onkeypress() event handlers. | 1670 // dispatched to onkeypress() event handlers. |
| 1657 // Text inserting might be initiated by other source instead of keyboard | 1671 // Text inserting might be initiated by other source instead of keyboard |
| 1658 // events, such as the Characters dialog. In this case the text should be | 1672 // events, such as the Characters dialog. In this case the text should be |
| 1659 // sent as an IME event as well. | 1673 // sent as an IME event as well. |
| 1660 BOOL isAttributedString = [string isKindOfClass:[NSAttributedString class]]; | 1674 BOOL isAttributedString = [string isKindOfClass:[NSAttributedString class]]; |
| 1661 NSString* im_text = isAttributedString ? [string string] : string; | 1675 NSString* im_text = isAttributedString ? [string string] : string; |
| 1662 if (!renderWidgetHostView_->im_composing_ && [im_text length] == 1 && | 1676 if (handlingKeyDown_) { |
| 1663 currentKeyEvent_.get()) { | 1677 textToBeInserted_.append(base::SysNSStringToUTF16(im_text)); |
| 1664 // Create the Char event from the NSEvent object, so that we can retain | |
| 1665 // necessary informations, especially unmodifiedText. | |
| 1666 NativeWebKeyboardEvent event(currentKeyEvent_.get()); | |
| 1667 event.type = WebKit::WebInputEvent::Char; | |
| 1668 event.text[0] = [im_text characterAtIndex:0]; | |
| 1669 event.text[1] = 0; | |
| 1670 event.skip_in_browser = true; | |
| 1671 renderWidgetHostView_->render_widget_host_->ForwardKeyboardEvent(event); | |
| 1672 } else { | 1678 } else { |
| 1673 renderWidgetHostView_->render_widget_host_->ImeConfirmComposition( | 1679 renderWidgetHostView_->render_widget_host_->ImeConfirmComposition( |
| 1674 UTF8ToUTF16([im_text UTF8String])); | 1680 base::SysNSStringToUTF16(im_text)); |
| 1675 } | 1681 } |
| 1676 renderWidgetHostView_->im_text_.clear(); | 1682 |
| 1677 renderWidgetHostView_->im_composing_ = false; | 1683 // Inserting text will delete all marked text automatically. |
| 1678 textInserted_ = YES; | 1684 hasMarkedText_ = NO; |
| 1679 } | 1685 } |
| 1680 | 1686 |
| 1681 - (void)viewDidMoveToWindow { | 1687 - (void)viewDidMoveToWindow { |
| 1682 // If we move into a new window, refresh the frame information. We don't need | 1688 // If we move into a new window, refresh the frame information. We don't need |
| 1683 // to do it if it was the same window as it used to be in, since that case | 1689 // to do it if it was the same window as it used to be in, since that case |
| 1684 // is covered by DidBecomeSelected. | 1690 // is covered by DidBecomeSelected. |
| 1685 // We only want to do this for real browser views, not popups. | 1691 // We only want to do this for real browser views, not popups. |
| 1686 if (canBeKeyView_) { | 1692 if (canBeKeyView_) { |
| 1687 NSWindow* newWindow = [self window]; | 1693 NSWindow* newWindow = [self window]; |
| 1688 // Pointer comparison only, since we don't know if lastWindow_ is still | 1694 // Pointer comparison only, since we don't know if lastWindow_ is still |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1794 | 1800 |
| 1795 [super setLayer:newLayer]; | 1801 [super setLayer:newLayer]; |
| 1796 if ([self layer]) | 1802 if ([self layer]) |
| 1797 [self attachPluginLayer]; | 1803 [self attachPluginLayer]; |
| 1798 } | 1804 } |
| 1799 | 1805 |
| 1800 - (void)drawAcceleratedPluginLayer { | 1806 - (void)drawAcceleratedPluginLayer { |
| 1801 [acceleratedPluginLayer_.get() setNeedsDisplay]; | 1807 [acceleratedPluginLayer_.get() setNeedsDisplay]; |
| 1802 } | 1808 } |
| 1803 | 1809 |
| 1810 - (void)cancelComposition { |
| 1811 if (!hasMarkedText_) |
| 1812 return; |
| 1813 |
| 1814 // Cancel the ongoing composition. [NSInputManager markedTextAbandoned:] |
| 1815 // doesn't call any NSTextInput functions, such as setMarkedText or |
| 1816 // insertText. So, we need to send an IPC message to a renderer so it can |
| 1817 // delete the composition node. |
| 1818 NSInputManager *currentInputManager = [NSInputManager currentInputManager]; |
| 1819 [currentInputManager markedTextAbandoned:self]; |
| 1820 |
| 1821 [self unmarkText]; |
| 1822 } |
| 1823 |
| 1804 @end | 1824 @end |
| OLD | NEW |