OLD | NEW |
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 #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 "base/command_line.h" | 9 #include "base/command_line.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
11 #include "base/mac/scoped_cftyperef.h" | 11 #include "base/mac/scoped_cftyperef.h" |
12 #import "base/mac/scoped_nsautorelease_pool.h" | 12 #import "base/mac/scoped_nsautorelease_pool.h" |
13 #include "base/metrics/histogram.h" | 13 #include "base/metrics/histogram.h" |
14 #import "base/memory/scoped_nsobject.h" | 14 #import "base/memory/scoped_nsobject.h" |
15 #include "base/string_util.h" | 15 #include "base/string_util.h" |
16 #include "base/sys_info.h" | 16 #include "base/sys_info.h" |
17 #include "base/sys_string_conversions.h" | 17 #include "base/sys_string_conversions.h" |
18 #import "chrome/browser/accessibility/browser_accessibility_cocoa.h" | 18 #import "chrome/browser/accessibility/browser_accessibility_cocoa.h" |
19 #include "chrome/browser/accessibility/browser_accessibility_state.h" | 19 #include "chrome/browser/accessibility/browser_accessibility_state.h" |
20 #include "chrome/browser/browser_trial.h" | 20 #include "chrome/browser/browser_trial.h" |
21 #include "chrome/browser/gpu_process_host_ui_shim.h" | 21 #include "chrome/browser/gpu_process_host_ui_shim.h" |
| 22 #import "chrome/browser/renderer_host/text_input_client_mac.h" |
22 #include "chrome/browser/spellchecker_platform_engine.h" | 23 #include "chrome/browser/spellchecker_platform_engine.h" |
23 #import "chrome/browser/ui/cocoa/rwhvm_editcommand_helper.h" | 24 #import "chrome/browser/ui/cocoa/rwhvm_editcommand_helper.h" |
24 #import "chrome/browser/ui/cocoa/view_id_util.h" | 25 #import "chrome/browser/ui/cocoa/view_id_util.h" |
25 #include "chrome/common/chrome_switches.h" | 26 #include "chrome/common/chrome_switches.h" |
26 #include "chrome/common/render_messages.h" | 27 #include "chrome/common/render_messages.h" |
27 #include "content/browser/browser_thread.h" | 28 #include "content/browser/browser_thread.h" |
28 #include "content/browser/gpu_process_host.h" | 29 #include "content/browser/gpu_process_host.h" |
29 #include "content/browser/plugin_process_host.h" | 30 #include "content/browser/plugin_process_host.h" |
30 #include "content/browser/renderer_host/backing_store_mac.h" | 31 #include "content/browser/renderer_host/backing_store_mac.h" |
31 #include "content/browser/renderer_host/render_process_host.h" | 32 #include "content/browser/renderer_host/render_process_host.h" |
32 #include "content/browser/renderer_host/render_view_host.h" | 33 #include "content/browser/renderer_host/render_view_host.h" |
33 #include "content/browser/renderer_host/render_widget_host.h" | 34 #include "content/browser/renderer_host/render_widget_host.h" |
34 #include "content/common/edit_command.h" | 35 #include "content/common/edit_command.h" |
35 #include "content/common/gpu_messages.h" | 36 #include "content/common/gpu_messages.h" |
36 #include "content/common/native_web_keyboard_event.h" | 37 #include "content/common/native_web_keyboard_event.h" |
37 #include "content/common/plugin_messages.h" | 38 #include "content/common/plugin_messages.h" |
38 #include "content/common/view_messages.h" | 39 #include "content/common/view_messages.h" |
39 #include "skia/ext/platform_canvas.h" | 40 #include "skia/ext/platform_canvas.h" |
40 #import "third_party/mozilla/ComplexTextInputPanel.h" | 41 #import "third_party/mozilla/ComplexTextInputPanel.h" |
41 #include "third_party/skia/include/core/SkColor.h" | 42 #include "third_party/skia/include/core/SkColor.h" |
42 #include "third_party/WebKit/Source/WebKit/chromium/public/mac/WebInputEventFact
ory.h" | 43 #include "third_party/WebKit/Source/WebKit/chromium/public/mac/WebInputEventFact
ory.h" |
43 #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h" | 44 #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h" |
44 #include "ui/gfx/gl/gl_switches.h" | 45 #include "ui/gfx/gl/gl_switches.h" |
| 46 #include "ui/gfx/point.h" |
45 #include "ui/gfx/surface/io_surface_support_mac.h" | 47 #include "ui/gfx/surface/io_surface_support_mac.h" |
46 #include "webkit/glue/webaccessibility.h" | 48 #include "webkit/glue/webaccessibility.h" |
47 #include "webkit/plugins/npapi/webplugin.h" | 49 #include "webkit/plugins/npapi/webplugin.h" |
48 | 50 |
49 using WebKit::WebInputEvent; | 51 using WebKit::WebInputEvent; |
50 using WebKit::WebInputEventFactory; | 52 using WebKit::WebInputEventFactory; |
51 using WebKit::WebMouseEvent; | 53 using WebKit::WebMouseEvent; |
52 using WebKit::WebMouseWheelEvent; | 54 using WebKit::WebMouseWheelEvent; |
53 | 55 |
54 static inline int ToWebKitModifiers(NSUInteger flags) { | 56 static inline int ToWebKitModifiers(NSUInteger flags) { |
55 int modifiers = 0; | 57 int modifiers = 0; |
56 if (flags & NSControlKeyMask) modifiers |= WebInputEvent::ControlKey; | 58 if (flags & NSControlKeyMask) modifiers |= WebInputEvent::ControlKey; |
57 if (flags & NSShiftKeyMask) modifiers |= WebInputEvent::ShiftKey; | 59 if (flags & NSShiftKeyMask) modifiers |= WebInputEvent::ShiftKey; |
58 if (flags & NSAlternateKeyMask) modifiers |= WebInputEvent::AltKey; | 60 if (flags & NSAlternateKeyMask) modifiers |= WebInputEvent::AltKey; |
59 if (flags & NSCommandKeyMask) modifiers |= WebInputEvent::MetaKey; | 61 if (flags & NSCommandKeyMask) modifiers |= WebInputEvent::MetaKey; |
60 return modifiers; | 62 return modifiers; |
61 } | 63 } |
62 | 64 |
63 @interface RenderWidgetHostViewCocoa (Private) | 65 // Private methods: |
| 66 @interface RenderWidgetHostViewCocoa () |
| 67 @property(nonatomic, assign) NSRange selectedRange; |
| 68 @property(nonatomic, assign) NSRange markedRange; |
| 69 |
64 + (BOOL)shouldAutohideCursorForEvent:(NSEvent*)event; | 70 + (BOOL)shouldAutohideCursorForEvent:(NSEvent*)event; |
65 - (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r; | 71 - (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r; |
66 - (void)keyEvent:(NSEvent *)theEvent wasKeyEquivalent:(BOOL)equiv; | 72 - (void)keyEvent:(NSEvent*)theEvent wasKeyEquivalent:(BOOL)equiv; |
67 - (void)cancelChildPopups; | 73 - (void)cancelChildPopups; |
68 - (void)checkForPluginImeCancellation; | 74 - (void)checkForPluginImeCancellation; |
69 @end | 75 @end |
70 | 76 |
71 // This API was published since 10.6. Provide the declaration so it can be | 77 // This API was published since 10.6. Provide the declaration so it can be |
72 // // called below when building with the 10.5 SDK. | 78 // // called below when building with the 10.5 SDK. |
73 #if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5 | 79 #if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5 |
74 @class NSTextInputContext; | 80 @class NSTextInputContext; |
75 @interface NSResponder (AppKitDetails) | 81 @interface NSResponder (AppKitDetails) |
76 - (NSTextInputContext *)inputContext; | 82 - (NSTextInputContext *)inputContext; |
(...skipping 774 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
851 } | 857 } |
852 | 858 |
853 void RenderWidgetHostViewMac::ImeUpdateTextInputState( | 859 void RenderWidgetHostViewMac::ImeUpdateTextInputState( |
854 WebKit::WebTextInputType type, | 860 WebKit::WebTextInputType type, |
855 const gfx::Rect& caret_rect) { | 861 const gfx::Rect& caret_rect) { |
856 if (text_input_type_ != type) { | 862 if (text_input_type_ != type) { |
857 text_input_type_ = type; | 863 text_input_type_ = type; |
858 if (HasFocus()) | 864 if (HasFocus()) |
859 SetTextInputActive(true); | 865 SetTextInputActive(true); |
860 } | 866 } |
861 | |
862 // We need to convert the coordinate of the cursor rectangle sent from the | |
863 // renderer and save it. Our input method backend uses a coordinate system | |
864 // whose origin is the upper-left corner of this view. On the other hand, | |
865 // Cocoa uses a coordinate system whose origin is the lower-left corner of | |
866 // this view. So, we convert the cursor rectangle and save it. | |
867 [cocoa_view_ setCaretRect:[cocoa_view_ flipRectToNSRect:caret_rect]]; | |
868 } | 867 } |
869 | 868 |
870 void RenderWidgetHostViewMac::ImeCancelComposition() { | 869 void RenderWidgetHostViewMac::ImeCancelComposition() { |
871 [cocoa_view_ cancelComposition]; | 870 [cocoa_view_ cancelComposition]; |
872 } | 871 } |
873 | 872 |
| 873 void RenderWidgetHostViewMac::ImeCompositionRangeChanged( |
| 874 const ui::Range& range) { |
| 875 // The RangeChanged message is only sent with valid values. The current |
| 876 // caret position (start == end) will be sent if there is no IME range. |
| 877 [cocoa_view_ setMarkedRange:range.ToNSRange()]; |
| 878 } |
| 879 |
874 void RenderWidgetHostViewMac::DidUpdateBackingStore( | 880 void RenderWidgetHostViewMac::DidUpdateBackingStore( |
875 const gfx::Rect& scroll_rect, int scroll_dx, int scroll_dy, | 881 const gfx::Rect& scroll_rect, int scroll_dx, int scroll_dy, |
876 const std::vector<gfx::Rect>& copy_rects) { | 882 const std::vector<gfx::Rect>& copy_rects) { |
877 if (!is_hidden_) { | 883 if (!is_hidden_) { |
878 std::vector<gfx::Rect> rects(copy_rects); | 884 std::vector<gfx::Rect> rects(copy_rects); |
879 | 885 |
880 // Because the findbar might be open, we cannot use scrollRect:by: here. For | 886 // Because the findbar might be open, we cannot use scrollRect:by: here. For |
881 // now, simply mark all of scroll rect as dirty. | 887 // now, simply mark all of scroll rect as dirty. |
882 if (!scroll_rect.IsEmpty()) | 888 if (!scroll_rect.IsEmpty()) |
883 rects.push_back(scroll_rect); | 889 rects.push_back(scroll_rect); |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
981 | 987 |
982 NSString* tooltip_nsstring = base::SysWideToNSString(display_text); | 988 NSString* tooltip_nsstring = base::SysWideToNSString(display_text); |
983 [cocoa_view_ setToolTipAtMousePoint:tooltip_nsstring]; | 989 [cocoa_view_ setToolTipAtMousePoint:tooltip_nsstring]; |
984 } | 990 } |
985 } | 991 } |
986 | 992 |
987 // | 993 // |
988 // RenderWidgetHostViewCocoa uses the stored selection text, | 994 // RenderWidgetHostViewCocoa uses the stored selection text, |
989 // which implements NSServicesRequests protocol. | 995 // which implements NSServicesRequests protocol. |
990 // | 996 // |
991 void RenderWidgetHostViewMac::SelectionChanged(const std::string& text) { | 997 void RenderWidgetHostViewMac::SelectionChanged(const std::string& text, |
| 998 const ui::Range& range) { |
992 selected_text_ = text; | 999 selected_text_ = text; |
| 1000 [cocoa_view_ setSelectedRange:range.ToNSRange()]; |
993 } | 1001 } |
994 | 1002 |
995 bool RenderWidgetHostViewMac::IsPopup() const { | 1003 bool RenderWidgetHostViewMac::IsPopup() const { |
996 return popup_type_ != WebKit::WebPopupTypeNone; | 1004 return popup_type_ != WebKit::WebPopupTypeNone; |
997 } | 1005 } |
998 | 1006 |
999 BackingStore* RenderWidgetHostViewMac::AllocBackingStore( | 1007 BackingStore* RenderWidgetHostViewMac::AllocBackingStore( |
1000 const gfx::Size& size) { | 1008 const gfx::Size& size) { |
1001 return new BackingStoreMac(render_widget_host_, size); | 1009 return new BackingStoreMac(render_widget_host_, size); |
1002 } | 1010 } |
(...skipping 419 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1422 } else { | 1430 } else { |
1423 if (text_input_type_ == WebKit::WebTextInputTypePassword) | 1431 if (text_input_type_ == WebKit::WebTextInputTypePassword) |
1424 DisablePasswordInput(); | 1432 DisablePasswordInput(); |
1425 } | 1433 } |
1426 } | 1434 } |
1427 | 1435 |
1428 // RenderWidgetHostViewCocoa --------------------------------------------------- | 1436 // RenderWidgetHostViewCocoa --------------------------------------------------- |
1429 | 1437 |
1430 @implementation RenderWidgetHostViewCocoa | 1438 @implementation RenderWidgetHostViewCocoa |
1431 | 1439 |
1432 @synthesize caretRect = caretRect_; | 1440 @synthesize selectedRange = selectedRange_; |
| 1441 @synthesize markedRange = markedRange_; |
1433 | 1442 |
1434 - (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r { | 1443 - (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r { |
1435 self = [super initWithFrame:NSZeroRect]; | 1444 self = [super initWithFrame:NSZeroRect]; |
1436 if (self) { | 1445 if (self) { |
1437 editCommand_helper_.reset(new RWHVMEditCommandHelper); | 1446 editCommand_helper_.reset(new RWHVMEditCommandHelper); |
1438 editCommand_helper_->AddEditingSelectorsToClass([self class]); | 1447 editCommand_helper_->AddEditingSelectorsToClass([self class]); |
1439 | 1448 |
1440 renderWidgetHostView_.reset(r); | 1449 renderWidgetHostView_.reset(r); |
1441 canBeKeyView_ = YES; | 1450 canBeKeyView_ = YES; |
1442 focusedPluginIdentifier_ = -1; | 1451 focusedPluginIdentifier_ = -1; |
(...skipping 1098 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2541 NSUnderlineStyleAttributeName, | 2550 NSUnderlineStyleAttributeName, |
2542 NSUnderlineColorAttributeName, | 2551 NSUnderlineColorAttributeName, |
2543 NSMarkedClauseSegmentAttributeName, | 2552 NSMarkedClauseSegmentAttributeName, |
2544 NSTextInputReplacementRangeAttributeName, | 2553 NSTextInputReplacementRangeAttributeName, |
2545 nil]); | 2554 nil]); |
2546 } | 2555 } |
2547 return validAttributesForMarkedText_.get(); | 2556 return validAttributesForMarkedText_.get(); |
2548 } | 2557 } |
2549 | 2558 |
2550 - (NSUInteger)characterIndexForPoint:(NSPoint)thePoint { | 2559 - (NSUInteger)characterIndexForPoint:(NSPoint)thePoint { |
2551 NOTIMPLEMENTED(); | 2560 DCHECK([self window]); |
2552 return NSNotFound; | 2561 // |thePoint| is in screen coordinates, but needs to be converted to WebKit |
| 2562 // coordinates (upper left origin). Scroll offsets will be taken care of in |
| 2563 // the renderer. |
| 2564 thePoint = [[self window] convertScreenToBase:thePoint]; |
| 2565 thePoint = [self convertPoint:thePoint fromView:nil]; |
| 2566 thePoint.y = NSHeight([self frame]) - thePoint.y; |
| 2567 |
| 2568 NSUInteger point = |
| 2569 TextInputClientMac::GetInstance()->GetCharacterIndexAtPoint( |
| 2570 renderWidgetHostView_->render_widget_host_, |
| 2571 gfx::Point(thePoint.x, thePoint.y)); |
| 2572 NSLog(@"%s:%@ -> %d", _cmd, NSStringFromPoint(thePoint), point); |
| 2573 return point; |
2553 } | 2574 } |
2554 | 2575 |
2555 - (NSRect)firstRectForCharacterRange:(NSRange)theRange { | 2576 - (NSRect)firstRectForCharacterRange:(NSRange)theRange { |
2556 // An input method requests a cursor rectangle to display its candidate | 2577 NSRect rect = TextInputClientMac::GetInstance()->GetFirstRectForRange( |
2557 // window. | 2578 renderWidgetHostView_->render_widget_host_, theRange); |
2558 // Calculate the screen coordinate of the cursor rectangle saved in | |
2559 // RenderWidgetHostViewMac::ImeUpdateTextInputState() and send it to the | |
2560 // input method. | |
2561 // Since this window may be moved since we receive the cursor rectangle last | |
2562 // time we sent the cursor rectangle to the input method, so we should map | |
2563 // from the view coordinate to the screen coordinate every time when an input | |
2564 // method need it. | |
2565 NSRect resultRect = [self convertRect:caretRect_ toView:nil]; | |
2566 NSWindow* window = [self window]; | |
2567 if (window) | |
2568 resultRect.origin = [window convertBaseToScreen:resultRect.origin]; | |
2569 | 2579 |
2570 return resultRect; | 2580 // The returned rectangle is in WebKit coordinates (upper left origin), so |
2571 } | 2581 // flip the coordinate system and then convert it into screen coordinates for |
2572 | 2582 // return. |
2573 - (NSRange)selectedRange { | 2583 NSRect viewFrame = [self frame]; |
2574 // Return the selected range saved in the setMarkedText method. | 2584 rect.origin.y = NSHeight(viewFrame) - rect.origin.y; |
2575 return hasMarkedText_ ? selectedRange_ : NSMakeRange(NSNotFound, 0); | 2585 rect.origin.y -= rect.size.height; |
| 2586 rect = [self convertRectToBase:rect]; |
| 2587 rect.origin = [[self window] convertBaseToScreen:rect.origin]; |
| 2588 NSLog(@"%s:%@ -> %@", _cmd, NSStringFromRange(theRange), NSStringFromRect(rect
)); |
| 2589 return rect; |
2576 } | 2590 } |
2577 | 2591 |
2578 - (NSRange)markedRange { | 2592 - (NSRange)markedRange { |
2579 // An input method calls this method to check if an application really has | 2593 // An input method calls this method to check if an application really has |
2580 // a text being composed when hasMarkedText call returns true. | 2594 // a text being composed when hasMarkedText call returns true. |
2581 // Returns the range saved in the setMarkedText method so the input method | 2595 // Returns the range saved in the setMarkedText method so the input method |
2582 // calls the setMarkedText method and we can update the composition node | 2596 // calls the setMarkedText method and we can update the composition node |
2583 // there. (When this method returns an empty range, the input method doesn't | 2597 // there. (When this method returns an empty range, the input method doesn't |
2584 // call the setMarkedText method.) | 2598 // call the setMarkedText method.) |
| 2599 NSLog(@"%s -> %@", _cmd, NSStringFromRange(markedRange_)); |
2585 return hasMarkedText_ ? markedRange_ : NSMakeRange(NSNotFound, 0); | 2600 return hasMarkedText_ ? markedRange_ : NSMakeRange(NSNotFound, 0); |
2586 } | 2601 } |
2587 | 2602 |
2588 - (NSAttributedString *)attributedSubstringFromRange:(NSRange)range { | 2603 - (NSAttributedString*)attributedSubstringFromRange:(NSRange)range { |
2589 // TODO(hbono): Even though many input method works without implementing | 2604 NSAttributedString* str = |
2590 // this method, we need to save a copy of the string in the setMarkedText | 2605 TextInputClientMac::GetInstance()->GetAttributedSubstringFromRange( |
2591 // method and create a NSAttributedString with the given range. | 2606 renderWidgetHostView_->render_widget_host_, range); |
2592 // http://crbug.com/37715 | 2607 NSLog(@"%s:%@ -> %@", _cmd, NSStringFromRange(range), [str string]); |
2593 return nil; | 2608 return str; |
2594 } | 2609 } |
2595 | 2610 |
2596 - (NSInteger)conversationIdentifier { | 2611 - (NSInteger)conversationIdentifier { |
2597 return reinterpret_cast<NSInteger>(self); | 2612 return reinterpret_cast<NSInteger>(self); |
2598 } | 2613 } |
2599 | 2614 |
2600 // Each RenderWidgetHostViewCocoa has its own input context, but we return | 2615 // Each RenderWidgetHostViewCocoa has its own input context, but we return |
2601 // nil when the caret is in non-editable content or password box to avoid | 2616 // nil when the caret is in non-editable content or password box to avoid |
2602 // making input methods do their work. | 2617 // making input methods do their work. |
2603 - (NSTextInputContext *)inputContext { | 2618 - (NSTextInputContext *)inputContext { |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2642 } | 2657 } |
2643 | 2658 |
2644 - (void)setMarkedText:(id)string selectedRange:(NSRange)newSelRange { | 2659 - (void)setMarkedText:(id)string selectedRange:(NSRange)newSelRange { |
2645 // An input method updates the composition string. | 2660 // An input method updates the composition string. |
2646 // We send the given text and range to the renderer so it can update the | 2661 // We send the given text and range to the renderer so it can update the |
2647 // composition node of WebKit. | 2662 // composition node of WebKit. |
2648 BOOL isAttributedString = [string isKindOfClass:[NSAttributedString class]]; | 2663 BOOL isAttributedString = [string isKindOfClass:[NSAttributedString class]]; |
2649 NSString* im_text = isAttributedString ? [string string] : string; | 2664 NSString* im_text = isAttributedString ? [string string] : string; |
2650 int length = [im_text length]; | 2665 int length = [im_text length]; |
2651 | 2666 |
2652 markedRange_ = NSMakeRange(0, length); | 2667 // |markedRange_| will get set on a callback from ImeSetComposition(). |
2653 selectedRange_ = newSelRange; | 2668 selectedRange_ = newSelRange; |
2654 markedText_ = base::SysNSStringToUTF16(im_text); | 2669 markedText_ = base::SysNSStringToUTF16(im_text); |
2655 hasMarkedText_ = (length > 0); | 2670 hasMarkedText_ = (length > 0); |
2656 | 2671 |
2657 underlines_.clear(); | 2672 underlines_.clear(); |
2658 if (isAttributedString) { | 2673 if (isAttributedString) { |
2659 ExtractUnderlines(string, &underlines_); | 2674 ExtractUnderlines(string, &underlines_); |
2660 } else { | 2675 } else { |
2661 // Use a thin black underline by default. | 2676 // Use a thin black underline by default. |
2662 underlines_.push_back( | 2677 underlines_.push_back( |
(...skipping 271 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2934 if (!string) return NO; | 2949 if (!string) return NO; |
2935 | 2950 |
2936 // If the user is currently using an IME, confirm the IME input, | 2951 // If the user is currently using an IME, confirm the IME input, |
2937 // and then insert the text from the service, the same as TextEdit and Safari. | 2952 // and then insert the text from the service, the same as TextEdit and Safari. |
2938 [self confirmComposition]; | 2953 [self confirmComposition]; |
2939 [self insertText:string]; | 2954 [self insertText:string]; |
2940 return YES; | 2955 return YES; |
2941 } | 2956 } |
2942 | 2957 |
2943 @end | 2958 @end |
OLD | NEW |