OLD | NEW |
1 // Copyright (c) 2010 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 "app/app_switches.h" | 9 #include "app/app_switches.h" |
10 #include "app/surface/io_surface_support_mac.h" | 10 #include "app/surface/io_surface_support_mac.h" |
11 #include "base/command_line.h" | 11 #include "base/command_line.h" |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/mac/scoped_cftyperef.h" | 13 #include "base/mac/scoped_cftyperef.h" |
14 #import "base/mac/scoped_nsautorelease_pool.h" | 14 #import "base/mac/scoped_nsautorelease_pool.h" |
15 #include "base/metrics/histogram.h" | 15 #include "base/metrics/histogram.h" |
16 #import "base/scoped_nsobject.h" | 16 #import "base/scoped_nsobject.h" |
17 #include "base/string_util.h" | 17 #include "base/string_util.h" |
18 #include "base/sys_info.h" | 18 #include "base/sys_info.h" |
19 #include "base/sys_string_conversions.h" | 19 #include "base/sys_string_conversions.h" |
20 #import "chrome/browser/accessibility/browser_accessibility_cocoa.h" | 20 #import "chrome/browser/accessibility/browser_accessibility_cocoa.h" |
21 #include "chrome/browser/accessibility/browser_accessibility_state.h" | 21 #include "chrome/browser/accessibility/browser_accessibility_state.h" |
22 #include "chrome/browser/browser_thread.h" | 22 #include "chrome/browser/browser_thread.h" |
23 #include "chrome/browser/browser_trial.h" | 23 #include "chrome/browser/browser_trial.h" |
24 #include "chrome/browser/gpu_process_host.h" | 24 #include "chrome/browser/gpu_process_host.h" |
25 #include "chrome/browser/gpu_process_host_ui_shim.h" | 25 #include "chrome/browser/gpu_process_host_ui_shim.h" |
26 #include "chrome/browser/plugin_process_host.h" | 26 #include "chrome/browser/plugin_process_host.h" |
27 #include "chrome/browser/renderer_host/backing_store_mac.h" | 27 #include "chrome/browser/renderer_host/backing_store_mac.h" |
28 #include "chrome/browser/renderer_host/render_process_host.h" | 28 #include "chrome/browser/renderer_host/render_process_host.h" |
29 #include "chrome/browser/renderer_host/render_view_host.h" | 29 #include "chrome/browser/renderer_host/render_view_host.h" |
30 #include "chrome/browser/renderer_host/render_widget_host.h" | 30 #include "chrome/browser/renderer_host/render_widget_host.h" |
| 31 #import "chrome/browser/renderer_host/text_input_client_mac.h" |
31 #include "chrome/browser/spellchecker_platform_engine.h" | 32 #include "chrome/browser/spellchecker_platform_engine.h" |
32 #import "chrome/browser/ui/cocoa/rwhvm_editcommand_helper.h" | 33 #import "chrome/browser/ui/cocoa/rwhvm_editcommand_helper.h" |
33 #import "chrome/browser/ui/cocoa/view_id_util.h" | 34 #import "chrome/browser/ui/cocoa/view_id_util.h" |
34 #include "chrome/common/chrome_switches.h" | 35 #include "chrome/common/chrome_switches.h" |
35 #include "chrome/common/native_web_keyboard_event.h" | 36 #include "chrome/common/native_web_keyboard_event.h" |
36 #include "chrome/common/edit_command.h" | 37 #include "chrome/common/edit_command.h" |
37 #include "chrome/common/gpu_messages.h" | 38 #include "chrome/common/gpu_messages.h" |
38 #include "chrome/common/plugin_messages.h" | 39 #include "chrome/common/plugin_messages.h" |
39 #include "chrome/common/render_messages.h" | 40 #include "chrome/common/render_messages.h" |
40 #include "skia/ext/platform_canvas.h" | 41 #include "skia/ext/platform_canvas.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" |
| 45 #include "ui/gfx/point.h" |
44 #include "webkit/glue/webaccessibility.h" | 46 #include "webkit/glue/webaccessibility.h" |
45 #include "webkit/plugins/npapi/webplugin.h" | 47 #include "webkit/plugins/npapi/webplugin.h" |
46 #import "third_party/mozilla/ComplexTextInputPanel.h" | 48 #import "third_party/mozilla/ComplexTextInputPanel.h" |
47 | 49 |
48 using WebKit::WebInputEvent; | 50 using WebKit::WebInputEvent; |
49 using WebKit::WebInputEventFactory; | 51 using WebKit::WebInputEventFactory; |
50 using WebKit::WebMouseEvent; | 52 using WebKit::WebMouseEvent; |
51 using WebKit::WebMouseWheelEvent; | 53 using WebKit::WebMouseWheelEvent; |
52 | 54 |
53 static inline int ToWebKitModifiers(NSUInteger flags) { | 55 static inline int ToWebKitModifiers(NSUInteger flags) { |
54 int modifiers = 0; | 56 int modifiers = 0; |
55 if (flags & NSControlKeyMask) modifiers |= WebInputEvent::ControlKey; | 57 if (flags & NSControlKeyMask) modifiers |= WebInputEvent::ControlKey; |
56 if (flags & NSShiftKeyMask) modifiers |= WebInputEvent::ShiftKey; | 58 if (flags & NSShiftKeyMask) modifiers |= WebInputEvent::ShiftKey; |
57 if (flags & NSAlternateKeyMask) modifiers |= WebInputEvent::AltKey; | 59 if (flags & NSAlternateKeyMask) modifiers |= WebInputEvent::AltKey; |
58 if (flags & NSCommandKeyMask) modifiers |= WebInputEvent::MetaKey; | 60 if (flags & NSCommandKeyMask) modifiers |= WebInputEvent::MetaKey; |
59 return modifiers; | 61 return modifiers; |
60 } | 62 } |
61 | 63 |
62 @interface RenderWidgetHostViewCocoa (Private) | 64 // Private methods: |
| 65 @interface RenderWidgetHostViewCocoa () |
| 66 @property(nonatomic, assign) NSRange selectedRange; |
| 67 @property(nonatomic, assign) NSRange markedRange; |
| 68 |
63 + (BOOL)shouldAutohideCursorForEvent:(NSEvent*)event; | 69 + (BOOL)shouldAutohideCursorForEvent:(NSEvent*)event; |
64 - (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r; | 70 - (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r; |
65 - (void)keyEvent:(NSEvent *)theEvent wasKeyEquivalent:(BOOL)equiv; | 71 - (void)keyEvent:(NSEvent*)theEvent wasKeyEquivalent:(BOOL)equiv; |
66 - (void)cancelChildPopups; | 72 - (void)cancelChildPopups; |
67 - (void)checkForPluginImeCancellation; | 73 - (void)checkForPluginImeCancellation; |
68 @end | 74 @end |
69 | 75 |
70 // This API was published since 10.6. Provide the declaration so it can be | 76 // This API was published since 10.6. Provide the declaration so it can be |
71 // // called below when building with the 10.5 SDK. | 77 // // called below when building with the 10.5 SDK. |
72 #if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5 | 78 #if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5 |
73 @class NSTextInputContext; | 79 @class NSTextInputContext; |
74 @interface NSResponder (AppKitDetails) | 80 @interface NSResponder (AppKitDetails) |
75 - (NSTextInputContext *)inputContext; | 81 - (NSTextInputContext *)inputContext; |
(...skipping 744 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
820 } | 826 } |
821 | 827 |
822 void RenderWidgetHostViewMac::ImeUpdateTextInputState( | 828 void RenderWidgetHostViewMac::ImeUpdateTextInputState( |
823 WebKit::WebTextInputType type, | 829 WebKit::WebTextInputType type, |
824 const gfx::Rect& caret_rect) { | 830 const gfx::Rect& caret_rect) { |
825 if (text_input_type_ != type) { | 831 if (text_input_type_ != type) { |
826 text_input_type_ = type; | 832 text_input_type_ = type; |
827 if (HasFocus()) | 833 if (HasFocus()) |
828 SetTextInputActive(true); | 834 SetTextInputActive(true); |
829 } | 835 } |
830 | |
831 // We need to convert the coordinate of the cursor rectangle sent from the | |
832 // renderer and save it. Our input method backend uses a coordinate system | |
833 // whose origin is the upper-left corner of this view. On the other hand, | |
834 // Cocoa uses a coordinate system whose origin is the lower-left corner of | |
835 // this view. So, we convert the cursor rectangle and save it. | |
836 [cocoa_view_ setCaretRect:[cocoa_view_ flipRectToNSRect:caret_rect]]; | |
837 } | 836 } |
838 | 837 |
839 void RenderWidgetHostViewMac::ImeCancelComposition() { | 838 void RenderWidgetHostViewMac::ImeCancelComposition() { |
840 [cocoa_view_ cancelComposition]; | 839 [cocoa_view_ cancelComposition]; |
841 } | 840 } |
842 | 841 |
| 842 void RenderWidgetHostViewMac::ImeCompositionRangeChanged(int start, int end) { |
| 843 // The RangeChanged message is only sent with valid values. The current |
| 844 // caret position (start == end) will be sent if there is no IME range. |
| 845 [cocoa_view_ setMarkedRange:NSMakeRange(start, end - start)]; |
| 846 } |
| 847 |
843 void RenderWidgetHostViewMac::DidUpdateBackingStore( | 848 void RenderWidgetHostViewMac::DidUpdateBackingStore( |
844 const gfx::Rect& scroll_rect, int scroll_dx, int scroll_dy, | 849 const gfx::Rect& scroll_rect, int scroll_dx, int scroll_dy, |
845 const std::vector<gfx::Rect>& copy_rects) { | 850 const std::vector<gfx::Rect>& copy_rects) { |
846 if (!is_hidden_) { | 851 if (!is_hidden_) { |
847 std::vector<gfx::Rect> rects(copy_rects); | 852 std::vector<gfx::Rect> rects(copy_rects); |
848 | 853 |
849 // Because the findbar might be open, we cannot use scrollRect:by: here. For | 854 // Because the findbar might be open, we cannot use scrollRect:by: here. For |
850 // now, simply mark all of scroll rect as dirty. | 855 // now, simply mark all of scroll rect as dirty. |
851 if (!scroll_rect.IsEmpty()) | 856 if (!scroll_rect.IsEmpty()) |
852 rects.push_back(scroll_rect); | 857 rects.push_back(scroll_rect); |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
950 | 955 |
951 NSString* tooltip_nsstring = base::SysWideToNSString(display_text); | 956 NSString* tooltip_nsstring = base::SysWideToNSString(display_text); |
952 [cocoa_view_ setToolTipAtMousePoint:tooltip_nsstring]; | 957 [cocoa_view_ setToolTipAtMousePoint:tooltip_nsstring]; |
953 } | 958 } |
954 } | 959 } |
955 | 960 |
956 // | 961 // |
957 // RenderWidgetHostViewCocoa uses the stored selection text, | 962 // RenderWidgetHostViewCocoa uses the stored selection text, |
958 // which implements NSServicesRequests protocol. | 963 // which implements NSServicesRequests protocol. |
959 // | 964 // |
960 void RenderWidgetHostViewMac::SelectionChanged(const std::string& text) { | 965 void RenderWidgetHostViewMac::SelectionChanged(const std::string& text, |
| 966 int range_start, |
| 967 int range_end) { |
961 selected_text_ = text; | 968 selected_text_ = text; |
| 969 NSRange range = NSMakeRange(range_start, range_end - range_start); |
| 970 if (range_start == 0 && range_end == 0) |
| 971 range.location = NSNotFound; |
| 972 [cocoa_view_ setSelectedRange:range]; |
962 } | 973 } |
963 | 974 |
964 BackingStore* RenderWidgetHostViewMac::AllocBackingStore( | 975 BackingStore* RenderWidgetHostViewMac::AllocBackingStore( |
965 const gfx::Size& size) { | 976 const gfx::Size& size) { |
966 return new BackingStoreMac(render_widget_host_, size); | 977 return new BackingStoreMac(render_widget_host_, size); |
967 } | 978 } |
968 | 979 |
969 // Sets whether or not to accept first responder status. | 980 // Sets whether or not to accept first responder status. |
970 void RenderWidgetHostViewMac::SetTakesFocusOnlyOnMouseDown(bool flag) { | 981 void RenderWidgetHostViewMac::SetTakesFocusOnlyOnMouseDown(bool flag) { |
971 [cocoa_view_ setTakesFocusOnlyOnMouseDown:flag]; | 982 [cocoa_view_ setTakesFocusOnlyOnMouseDown:flag]; |
(...skipping 394 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1366 } else { | 1377 } else { |
1367 if (text_input_type_ == WebKit::WebTextInputTypePassword) | 1378 if (text_input_type_ == WebKit::WebTextInputTypePassword) |
1368 DisablePasswordInput(); | 1379 DisablePasswordInput(); |
1369 } | 1380 } |
1370 } | 1381 } |
1371 | 1382 |
1372 // RenderWidgetHostViewCocoa --------------------------------------------------- | 1383 // RenderWidgetHostViewCocoa --------------------------------------------------- |
1373 | 1384 |
1374 @implementation RenderWidgetHostViewCocoa | 1385 @implementation RenderWidgetHostViewCocoa |
1375 | 1386 |
1376 @synthesize caretRect = caretRect_; | 1387 @synthesize selectedRange = selectedRange_; |
| 1388 @synthesize markedRange = markedRange_; |
1377 | 1389 |
1378 - (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r { | 1390 - (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r { |
1379 self = [super initWithFrame:NSZeroRect]; | 1391 self = [super initWithFrame:NSZeroRect]; |
1380 if (self) { | 1392 if (self) { |
1381 editCommand_helper_.reset(new RWHVMEditCommandHelper); | 1393 editCommand_helper_.reset(new RWHVMEditCommandHelper); |
1382 editCommand_helper_->AddEditingSelectorsToClass([self class]); | 1394 editCommand_helper_->AddEditingSelectorsToClass([self class]); |
1383 | 1395 |
1384 renderWidgetHostView_.reset(r); | 1396 renderWidgetHostView_.reset(r); |
1385 canBeKeyView_ = YES; | 1397 canBeKeyView_ = YES; |
1386 takesFocusOnlyOnMouseDown_ = NO; | 1398 takesFocusOnlyOnMouseDown_ = NO; |
(...skipping 1049 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2436 NSUnderlineStyleAttributeName, | 2448 NSUnderlineStyleAttributeName, |
2437 NSUnderlineColorAttributeName, | 2449 NSUnderlineColorAttributeName, |
2438 NSMarkedClauseSegmentAttributeName, | 2450 NSMarkedClauseSegmentAttributeName, |
2439 NSTextInputReplacementRangeAttributeName, | 2451 NSTextInputReplacementRangeAttributeName, |
2440 nil]); | 2452 nil]); |
2441 } | 2453 } |
2442 return validAttributesForMarkedText_.get(); | 2454 return validAttributesForMarkedText_.get(); |
2443 } | 2455 } |
2444 | 2456 |
2445 - (NSUInteger)characterIndexForPoint:(NSPoint)thePoint { | 2457 - (NSUInteger)characterIndexForPoint:(NSPoint)thePoint { |
2446 NOTIMPLEMENTED(); | 2458 DCHECK([self window]); |
2447 return NSNotFound; | 2459 // |thePoint| is in screen coordinates, but needs to be converted to WebKit |
| 2460 // coordinates (upper left origin). Scroll offsets will be taken care of in |
| 2461 // the renderer. |
| 2462 thePoint = [[self window] convertScreenToBase:thePoint]; |
| 2463 thePoint = [self convertPoint:thePoint fromView:nil]; |
| 2464 thePoint.y = NSHeight([self frame]) - thePoint.y; |
| 2465 |
| 2466 NSUInteger point = |
| 2467 TextInputClientMac::GetInstance()->GetCharacterIndexAtPoint( |
| 2468 renderWidgetHostView_->render_widget_host_, |
| 2469 gfx::Point(thePoint.x, thePoint.y)); |
| 2470 NSLog(@"%s:%@ -> %d", _cmd, NSStringFromPoint(thePoint), point); |
| 2471 return point; |
2448 } | 2472 } |
2449 | 2473 |
2450 - (NSRect)firstRectForCharacterRange:(NSRange)theRange { | 2474 - (NSRect)firstRectForCharacterRange:(NSRange)theRange { |
2451 // An input method requests a cursor rectangle to display its candidate | 2475 NSRect rect = TextInputClientMac::GetInstance()->GetFirstRectForRange( |
2452 // window. | 2476 renderWidgetHostView_->render_widget_host_, theRange); |
2453 // Calculate the screen coordinate of the cursor rectangle saved in | |
2454 // RenderWidgetHostViewMac::ImeUpdateTextInputState() and send it to the | |
2455 // input method. | |
2456 // Since this window may be moved since we receive the cursor rectangle last | |
2457 // time we sent the cursor rectangle to the input method, so we should map | |
2458 // from the view coordinate to the screen coordinate every time when an input | |
2459 // method need it. | |
2460 NSRect resultRect = [self convertRect:caretRect_ toView:nil]; | |
2461 NSWindow* window = [self window]; | |
2462 if (window) | |
2463 resultRect.origin = [window convertBaseToScreen:resultRect.origin]; | |
2464 | 2477 |
2465 return resultRect; | 2478 // The returned rectangle is in WebKit coordinates (upper left origin), so |
2466 } | 2479 // flip the coordinate system and then convert it into screen coordinates for |
2467 | 2480 // return. |
2468 - (NSRange)selectedRange { | 2481 NSRect viewFrame = [self frame]; |
2469 // Return the selected range saved in the setMarkedText method. | 2482 rect.origin.y = NSHeight(viewFrame) - rect.origin.y; |
2470 return hasMarkedText_ ? selectedRange_ : NSMakeRange(NSNotFound, 0); | 2483 rect.origin.y -= rect.size.height; |
| 2484 rect = [self convertRectToBase:rect]; |
| 2485 rect.origin = [[self window] convertBaseToScreen:rect.origin]; |
| 2486 NSLog(@"%s:%@ -> %@", _cmd, NSStringFromRange(theRange), NSStringFromRect(rect
)); |
| 2487 return rect; |
2471 } | 2488 } |
2472 | 2489 |
2473 - (NSRange)markedRange { | 2490 - (NSRange)markedRange { |
2474 // An input method calls this method to check if an application really has | 2491 // An input method calls this method to check if an application really has |
2475 // a text being composed when hasMarkedText call returns true. | 2492 // a text being composed when hasMarkedText call returns true. |
2476 // Returns the range saved in the setMarkedText method so the input method | 2493 // Returns the range saved in the setMarkedText method so the input method |
2477 // calls the setMarkedText method and we can update the composition node | 2494 // calls the setMarkedText method and we can update the composition node |
2478 // there. (When this method returns an empty range, the input method doesn't | 2495 // there. (When this method returns an empty range, the input method doesn't |
2479 // call the setMarkedText method.) | 2496 // call the setMarkedText method.) |
| 2497 NSLog(@"%s -> %@", _cmd, NSStringFromRange(markedRange_)); |
2480 return hasMarkedText_ ? markedRange_ : NSMakeRange(NSNotFound, 0); | 2498 return hasMarkedText_ ? markedRange_ : NSMakeRange(NSNotFound, 0); |
2481 } | 2499 } |
2482 | 2500 |
2483 - (NSAttributedString *)attributedSubstringFromRange:(NSRange)range { | 2501 - (NSAttributedString*)attributedSubstringFromRange:(NSRange)range { |
2484 // TODO(hbono): Even though many input method works without implementing | 2502 NSAttributedString* str = |
2485 // this method, we need to save a copy of the string in the setMarkedText | 2503 TextInputClientMac::GetInstance()->GetAttributedSubstringFromRange( |
2486 // method and create a NSAttributedString with the given range. | 2504 renderWidgetHostView_->render_widget_host_, range); |
2487 // http://crbug.com/37715 | 2505 NSLog(@"%s:%@ -> %@", _cmd, NSStringFromRange(range), [str string]); |
2488 return nil; | 2506 return str; |
2489 } | 2507 } |
2490 | 2508 |
2491 - (NSInteger)conversationIdentifier { | 2509 - (NSInteger)conversationIdentifier { |
2492 return reinterpret_cast<NSInteger>(self); | 2510 return reinterpret_cast<NSInteger>(self); |
2493 } | 2511 } |
2494 | 2512 |
2495 // Each RenderWidgetHostViewCocoa has its own input context, but we return | 2513 // Each RenderWidgetHostViewCocoa has its own input context, but we return |
2496 // nil when the caret is in non-editable content or password box to avoid | 2514 // nil when the caret is in non-editable content or password box to avoid |
2497 // making input methods do their work. | 2515 // making input methods do their work. |
2498 - (NSTextInputContext *)inputContext { | 2516 - (NSTextInputContext *)inputContext { |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2537 } | 2555 } |
2538 | 2556 |
2539 - (void)setMarkedText:(id)string selectedRange:(NSRange)newSelRange { | 2557 - (void)setMarkedText:(id)string selectedRange:(NSRange)newSelRange { |
2540 // An input method updates the composition string. | 2558 // An input method updates the composition string. |
2541 // We send the given text and range to the renderer so it can update the | 2559 // We send the given text and range to the renderer so it can update the |
2542 // composition node of WebKit. | 2560 // composition node of WebKit. |
2543 BOOL isAttributedString = [string isKindOfClass:[NSAttributedString class]]; | 2561 BOOL isAttributedString = [string isKindOfClass:[NSAttributedString class]]; |
2544 NSString* im_text = isAttributedString ? [string string] : string; | 2562 NSString* im_text = isAttributedString ? [string string] : string; |
2545 int length = [im_text length]; | 2563 int length = [im_text length]; |
2546 | 2564 |
2547 markedRange_ = NSMakeRange(0, length); | 2565 // |markedRange_| will get set on a callback from ImeSetComposition(). |
2548 selectedRange_ = newSelRange; | 2566 selectedRange_ = newSelRange; |
2549 markedText_ = base::SysNSStringToUTF16(im_text); | 2567 markedText_ = base::SysNSStringToUTF16(im_text); |
2550 hasMarkedText_ = (length > 0); | 2568 hasMarkedText_ = (length > 0); |
2551 | 2569 |
2552 underlines_.clear(); | 2570 underlines_.clear(); |
2553 if (isAttributedString) { | 2571 if (isAttributedString) { |
2554 ExtractUnderlines(string, &underlines_); | 2572 ExtractUnderlines(string, &underlines_); |
2555 } else { | 2573 } else { |
2556 // Use a thin black underline by default. | 2574 // Use a thin black underline by default. |
2557 underlines_.push_back( | 2575 underlines_.push_back( |
(...skipping 271 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2829 if (!string) return NO; | 2847 if (!string) return NO; |
2830 | 2848 |
2831 // If the user is currently using an IME, confirm the IME input, | 2849 // If the user is currently using an IME, confirm the IME input, |
2832 // and then insert the text from the service, the same as TextEdit and Safari. | 2850 // and then insert the text from the service, the same as TextEdit and Safari. |
2833 [self confirmComposition]; | 2851 [self confirmComposition]; |
2834 [self insertText:string]; | 2852 [self insertText:string]; |
2835 return YES; | 2853 return YES; |
2836 } | 2854 } |
2837 | 2855 |
2838 @end | 2856 @end |
OLD | NEW |