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

Side by Side Diff: chrome/browser/renderer_host/render_widget_host_view_mac.mm

Issue 6289009: [Mac] Implement the system dictionary popup by implementing NSTextInput methods. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix Clang Created 9 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #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 #import "chrome/browser/renderer_host/text_input_client_mac.h"
21 #include "chrome/browser/spellchecker_platform_engine.h" 22 #include "chrome/browser/spellchecker_platform_engine.h"
22 #import "chrome/browser/ui/cocoa/rwhvm_editcommand_helper.h" 23 #import "chrome/browser/ui/cocoa/rwhvm_editcommand_helper.h"
23 #import "chrome/browser/ui/cocoa/view_id_util.h" 24 #import "chrome/browser/ui/cocoa/view_id_util.h"
24 #include "chrome/common/chrome_switches.h" 25 #include "chrome/common/chrome_switches.h"
25 #include "chrome/common/render_messages.h" 26 #include "chrome/common/render_messages.h"
26 #include "chrome/common/spellcheck_messages.h" 27 #include "chrome/common/spellcheck_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/gpu_process_host_ui_shim.h" 30 #include "content/browser/gpu_process_host_ui_shim.h"
30 #include "content/browser/plugin_process_host.h" 31 #include "content/browser/plugin_process_host.h"
31 #include "content/browser/renderer_host/backing_store_mac.h" 32 #include "content/browser/renderer_host/backing_store_mac.h"
32 #include "content/browser/renderer_host/render_process_host.h" 33 #include "content/browser/renderer_host/render_process_host.h"
33 #include "content/browser/renderer_host/render_view_host.h" 34 #include "content/browser/renderer_host/render_view_host.h"
34 #include "content/browser/renderer_host/render_widget_host.h" 35 #include "content/browser/renderer_host/render_widget_host.h"
35 #include "content/common/edit_command.h" 36 #include "content/common/edit_command.h"
36 #include "content/common/gpu/gpu_messages.h" 37 #include "content/common/gpu/gpu_messages.h"
37 #include "content/common/native_web_keyboard_event.h" 38 #include "content/common/native_web_keyboard_event.h"
38 #include "content/common/plugin_messages.h" 39 #include "content/common/plugin_messages.h"
39 #include "content/common/view_messages.h" 40 #include "content/common/view_messages.h"
40 #include "skia/ext/platform_canvas.h" 41 #include "skia/ext/platform_canvas.h"
41 #import "third_party/mozilla/ComplexTextInputPanel.h" 42 #import "third_party/mozilla/ComplexTextInputPanel.h"
42 #include "third_party/skia/include/core/SkColor.h" 43 #include "third_party/skia/include/core/SkColor.h"
43 #include "third_party/WebKit/Source/WebKit/chromium/public/mac/WebInputEventFact ory.h" 44 #include "third_party/WebKit/Source/WebKit/chromium/public/mac/WebInputEventFact ory.h"
44 #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h" 45 #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h"
45 #include "ui/gfx/gl/gl_switches.h" 46 #include "ui/gfx/gl/gl_switches.h"
47 #include "ui/gfx/point.h"
46 #include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h" 48 #include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
47 #include "ui/gfx/surface/io_surface_support_mac.h" 49 #include "ui/gfx/surface/io_surface_support_mac.h"
48 #include "webkit/glue/webaccessibility.h" 50 #include "webkit/glue/webaccessibility.h"
49 #include "webkit/plugins/npapi/webplugin.h" 51 #include "webkit/plugins/npapi/webplugin.h"
50 52
51 using WebKit::WebInputEvent; 53 using WebKit::WebInputEvent;
52 using WebKit::WebInputEventFactory; 54 using WebKit::WebInputEventFactory;
53 using WebKit::WebMouseEvent; 55 using WebKit::WebMouseEvent;
54 using WebKit::WebMouseWheelEvent; 56 using WebKit::WebMouseWheelEvent;
55 57
56 static inline int ToWebKitModifiers(NSUInteger flags) { 58 static inline int ToWebKitModifiers(NSUInteger flags) {
57 int modifiers = 0; 59 int modifiers = 0;
58 if (flags & NSControlKeyMask) modifiers |= WebInputEvent::ControlKey; 60 if (flags & NSControlKeyMask) modifiers |= WebInputEvent::ControlKey;
59 if (flags & NSShiftKeyMask) modifiers |= WebInputEvent::ShiftKey; 61 if (flags & NSShiftKeyMask) modifiers |= WebInputEvent::ShiftKey;
60 if (flags & NSAlternateKeyMask) modifiers |= WebInputEvent::AltKey; 62 if (flags & NSAlternateKeyMask) modifiers |= WebInputEvent::AltKey;
61 if (flags & NSCommandKeyMask) modifiers |= WebInputEvent::MetaKey; 63 if (flags & NSCommandKeyMask) modifiers |= WebInputEvent::MetaKey;
62 return modifiers; 64 return modifiers;
63 } 65 }
64 66
65 @interface RenderWidgetHostViewCocoa (Private) 67 // Private methods:
68 @interface RenderWidgetHostViewCocoa ()
69 @property(nonatomic, assign) NSRange selectedRange;
70 @property(nonatomic, assign) NSRange markedRange;
71
66 + (BOOL)shouldAutohideCursorForEvent:(NSEvent*)event; 72 + (BOOL)shouldAutohideCursorForEvent:(NSEvent*)event;
67 - (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r; 73 - (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r;
68 - (void)keyEvent:(NSEvent *)theEvent wasKeyEquivalent:(BOOL)equiv; 74 - (void)keyEvent:(NSEvent*)theEvent wasKeyEquivalent:(BOOL)equiv;
69 - (void)cancelChildPopups; 75 - (void)cancelChildPopups;
70 - (void)checkForPluginImeCancellation; 76 - (void)checkForPluginImeCancellation;
71 @end 77 @end
72 78
73 // This API was published since 10.6. Provide the declaration so it can be 79 // This API was published since 10.6. Provide the declaration so it can be
74 // // called below when building with the 10.5 SDK. 80 // // called below when building with the 10.5 SDK.
75 #if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5 81 #if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5
76 @class NSTextInputContext; 82 @class NSTextInputContext;
77 @interface NSResponder (AppKitDetails) 83 @interface NSResponder (AppKitDetails)
78 - (NSTextInputContext *)inputContext; 84 - (NSTextInputContext *)inputContext;
(...skipping 768 matching lines...) Expand 10 before | Expand all | Expand 10 after
847 } 853 }
848 854
849 void RenderWidgetHostViewMac::ImeUpdateTextInputState( 855 void RenderWidgetHostViewMac::ImeUpdateTextInputState(
850 WebKit::WebTextInputType type, 856 WebKit::WebTextInputType type,
851 const gfx::Rect& caret_rect) { 857 const gfx::Rect& caret_rect) {
852 if (text_input_type_ != type) { 858 if (text_input_type_ != type) {
853 text_input_type_ = type; 859 text_input_type_ = type;
854 if (HasFocus()) 860 if (HasFocus())
855 SetTextInputActive(true); 861 SetTextInputActive(true);
856 } 862 }
857
858 // We need to convert the coordinate of the cursor rectangle sent from the
859 // renderer and save it. Our input method backend uses a coordinate system
860 // whose origin is the upper-left corner of this view. On the other hand,
861 // Cocoa uses a coordinate system whose origin is the lower-left corner of
862 // this view. So, we convert the cursor rectangle and save it.
863 [cocoa_view_ setCaretRect:[cocoa_view_ flipRectToNSRect:caret_rect]];
864 } 863 }
865 864
866 void RenderWidgetHostViewMac::ImeCancelComposition() { 865 void RenderWidgetHostViewMac::ImeCancelComposition() {
867 [cocoa_view_ cancelComposition]; 866 [cocoa_view_ cancelComposition];
868 } 867 }
869 868
869 void RenderWidgetHostViewMac::ImeCompositionRangeChanged(
870 const ui::Range& range) {
871 // The RangeChanged message is only sent with valid values. The current
872 // caret position (start == end) will be sent if there is no IME range.
873 [cocoa_view_ setMarkedRange:range.ToNSRange()];
874 }
875
870 void RenderWidgetHostViewMac::DidUpdateBackingStore( 876 void RenderWidgetHostViewMac::DidUpdateBackingStore(
871 const gfx::Rect& scroll_rect, int scroll_dx, int scroll_dy, 877 const gfx::Rect& scroll_rect, int scroll_dx, int scroll_dy,
872 const std::vector<gfx::Rect>& copy_rects) { 878 const std::vector<gfx::Rect>& copy_rects) {
873 if (!is_hidden_) { 879 if (!is_hidden_) {
874 std::vector<gfx::Rect> rects(copy_rects); 880 std::vector<gfx::Rect> rects(copy_rects);
875 881
876 // Because the findbar might be open, we cannot use scrollRect:by: here. For 882 // Because the findbar might be open, we cannot use scrollRect:by: here. For
877 // now, simply mark all of scroll rect as dirty. 883 // now, simply mark all of scroll rect as dirty.
878 if (!scroll_rect.IsEmpty()) 884 if (!scroll_rect.IsEmpty())
879 rects.push_back(scroll_rect); 885 rects.push_back(scroll_rect);
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
976 982
977 NSString* tooltip_nsstring = base::SysWideToNSString(display_text); 983 NSString* tooltip_nsstring = base::SysWideToNSString(display_text);
978 [cocoa_view_ setToolTipAtMousePoint:tooltip_nsstring]; 984 [cocoa_view_ setToolTipAtMousePoint:tooltip_nsstring];
979 } 985 }
980 } 986 }
981 987
982 // 988 //
983 // RenderWidgetHostViewCocoa uses the stored selection text, 989 // RenderWidgetHostViewCocoa uses the stored selection text,
984 // which implements NSServicesRequests protocol. 990 // which implements NSServicesRequests protocol.
985 // 991 //
986 void RenderWidgetHostViewMac::SelectionChanged(const std::string& text) { 992 void RenderWidgetHostViewMac::SelectionChanged(const std::string& text,
993 const ui::Range& range) {
987 selected_text_ = text; 994 selected_text_ = text;
995 [cocoa_view_ setSelectedRange:range.ToNSRange()];
988 } 996 }
989 997
990 bool RenderWidgetHostViewMac::IsPopup() const { 998 bool RenderWidgetHostViewMac::IsPopup() const {
991 return popup_type_ != WebKit::WebPopupTypeNone; 999 return popup_type_ != WebKit::WebPopupTypeNone;
992 } 1000 }
993 1001
994 BackingStore* RenderWidgetHostViewMac::AllocBackingStore( 1002 BackingStore* RenderWidgetHostViewMac::AllocBackingStore(
995 const gfx::Size& size) { 1003 const gfx::Size& size) {
996 return new BackingStoreMac(render_widget_host_, size); 1004 return new BackingStoreMac(render_widget_host_, size);
997 } 1005 }
(...skipping 381 matching lines...) Expand 10 before | Expand all | Expand 10 after
1379 } else { 1387 } else {
1380 if (text_input_type_ == WebKit::WebTextInputTypePassword) 1388 if (text_input_type_ == WebKit::WebTextInputTypePassword)
1381 DisablePasswordInput(); 1389 DisablePasswordInput();
1382 } 1390 }
1383 } 1391 }
1384 1392
1385 // RenderWidgetHostViewCocoa --------------------------------------------------- 1393 // RenderWidgetHostViewCocoa ---------------------------------------------------
1386 1394
1387 @implementation RenderWidgetHostViewCocoa 1395 @implementation RenderWidgetHostViewCocoa
1388 1396
1389 @synthesize caretRect = caretRect_; 1397 @synthesize selectedRange = selectedRange_;
1398 @synthesize markedRange = markedRange_;
1390 1399
1391 - (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r { 1400 - (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r {
1392 self = [super initWithFrame:NSZeroRect]; 1401 self = [super initWithFrame:NSZeroRect];
1393 if (self) { 1402 if (self) {
1394 editCommand_helper_.reset(new RWHVMEditCommandHelper); 1403 editCommand_helper_.reset(new RWHVMEditCommandHelper);
1395 editCommand_helper_->AddEditingSelectorsToClass([self class]); 1404 editCommand_helper_->AddEditingSelectorsToClass([self class]);
1396 1405
1397 renderWidgetHostView_.reset(r); 1406 renderWidgetHostView_.reset(r);
1398 canBeKeyView_ = YES; 1407 canBeKeyView_ = YES;
1399 focusedPluginIdentifier_ = -1; 1408 focusedPluginIdentifier_ = -1;
(...skipping 1104 matching lines...) Expand 10 before | Expand all | Expand 10 after
2504 NSUnderlineStyleAttributeName, 2513 NSUnderlineStyleAttributeName,
2505 NSUnderlineColorAttributeName, 2514 NSUnderlineColorAttributeName,
2506 NSMarkedClauseSegmentAttributeName, 2515 NSMarkedClauseSegmentAttributeName,
2507 NSTextInputReplacementRangeAttributeName, 2516 NSTextInputReplacementRangeAttributeName,
2508 nil]); 2517 nil]);
2509 } 2518 }
2510 return validAttributesForMarkedText_.get(); 2519 return validAttributesForMarkedText_.get();
2511 } 2520 }
2512 2521
2513 - (NSUInteger)characterIndexForPoint:(NSPoint)thePoint { 2522 - (NSUInteger)characterIndexForPoint:(NSPoint)thePoint {
2514 NOTIMPLEMENTED(); 2523 DCHECK([self window]);
2515 return NSNotFound; 2524 // |thePoint| is in screen coordinates, but needs to be converted to WebKit
2525 // coordinates (upper left origin). Scroll offsets will be taken care of in
2526 // the renderer.
2527 thePoint = [[self window] convertScreenToBase:thePoint];
2528 thePoint = [self convertPoint:thePoint fromView:nil];
2529 thePoint.y = NSHeight([self frame]) - thePoint.y;
2530
2531 NSUInteger point =
2532 TextInputClientMac::GetInstance()->GetCharacterIndexAtPoint(
2533 renderWidgetHostView_->render_widget_host_,
2534 gfx::Point(thePoint.x, thePoint.y));
2535 return point;
2516 } 2536 }
2517 2537
2518 - (NSRect)firstRectForCharacterRange:(NSRange)theRange { 2538 - (NSRect)firstRectForCharacterRange:(NSRange)theRange {
2519 // An input method requests a cursor rectangle to display its candidate 2539 NSRect rect = TextInputClientMac::GetInstance()->GetFirstRectForRange(
2520 // window. 2540 renderWidgetHostView_->render_widget_host_, theRange);
2521 // Calculate the screen coordinate of the cursor rectangle saved in
2522 // RenderWidgetHostViewMac::ImeUpdateTextInputState() and send it to the
2523 // input method.
2524 // Since this window may be moved since we receive the cursor rectangle last
2525 // time we sent the cursor rectangle to the input method, so we should map
2526 // from the view coordinate to the screen coordinate every time when an input
2527 // method need it.
2528 NSRect resultRect = [self convertRect:caretRect_ toView:nil];
2529 NSWindow* window = [self window];
2530 if (window)
2531 resultRect.origin = [window convertBaseToScreen:resultRect.origin];
2532 2541
2533 return resultRect; 2542 // The returned rectangle is in WebKit coordinates (upper left origin), so
2534 } 2543 // flip the coordinate system and then convert it into screen coordinates for
2535 2544 // return.
2536 - (NSRange)selectedRange { 2545 NSRect viewFrame = [self frame];
2537 // Return the selected range saved in the setMarkedText method. 2546 rect.origin.y = NSHeight(viewFrame) - rect.origin.y;
2538 return hasMarkedText_ ? selectedRange_ : NSMakeRange(NSNotFound, 0); 2547 rect.origin.y -= rect.size.height;
2548 rect = [self convertRectToBase:rect];
2549 rect.origin = [[self window] convertBaseToScreen:rect.origin];
2550 return rect;
2539 } 2551 }
2540 2552
2541 - (NSRange)markedRange { 2553 - (NSRange)markedRange {
2542 // An input method calls this method to check if an application really has 2554 // An input method calls this method to check if an application really has
2543 // a text being composed when hasMarkedText call returns true. 2555 // a text being composed when hasMarkedText call returns true.
2544 // Returns the range saved in the setMarkedText method so the input method 2556 // Returns the range saved in the setMarkedText method so the input method
2545 // calls the setMarkedText method and we can update the composition node 2557 // calls the setMarkedText method and we can update the composition node
2546 // there. (When this method returns an empty range, the input method doesn't 2558 // there. (When this method returns an empty range, the input method doesn't
2547 // call the setMarkedText method.) 2559 // call the setMarkedText method.)
2548 return hasMarkedText_ ? markedRange_ : NSMakeRange(NSNotFound, 0); 2560 return hasMarkedText_ ? markedRange_ : NSMakeRange(NSNotFound, 0);
2549 } 2561 }
2550 2562
2551 - (NSAttributedString *)attributedSubstringFromRange:(NSRange)range { 2563 - (NSAttributedString*)attributedSubstringFromRange:(NSRange)range {
2552 // TODO(hbono): Even though many input method works without implementing 2564 NSAttributedString* str =
2553 // this method, we need to save a copy of the string in the setMarkedText 2565 TextInputClientMac::GetInstance()->GetAttributedSubstringFromRange(
2554 // method and create a NSAttributedString with the given range. 2566 renderWidgetHostView_->render_widget_host_, range);
2555 // http://crbug.com/37715 2567 return str;
2556 return nil;
2557 } 2568 }
2558 2569
2559 - (NSInteger)conversationIdentifier { 2570 - (NSInteger)conversationIdentifier {
2560 return reinterpret_cast<NSInteger>(self); 2571 return reinterpret_cast<NSInteger>(self);
2561 } 2572 }
2562 2573
2563 // Each RenderWidgetHostViewCocoa has its own input context, but we return 2574 // Each RenderWidgetHostViewCocoa has its own input context, but we return
2564 // nil when the caret is in non-editable content or password box to avoid 2575 // nil when the caret is in non-editable content or password box to avoid
2565 // making input methods do their work. 2576 // making input methods do their work.
2566 - (NSTextInputContext *)inputContext { 2577 - (NSTextInputContext *)inputContext {
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
2605 } 2616 }
2606 2617
2607 - (void)setMarkedText:(id)string selectedRange:(NSRange)newSelRange { 2618 - (void)setMarkedText:(id)string selectedRange:(NSRange)newSelRange {
2608 // An input method updates the composition string. 2619 // An input method updates the composition string.
2609 // We send the given text and range to the renderer so it can update the 2620 // We send the given text and range to the renderer so it can update the
2610 // composition node of WebKit. 2621 // composition node of WebKit.
2611 BOOL isAttributedString = [string isKindOfClass:[NSAttributedString class]]; 2622 BOOL isAttributedString = [string isKindOfClass:[NSAttributedString class]];
2612 NSString* im_text = isAttributedString ? [string string] : string; 2623 NSString* im_text = isAttributedString ? [string string] : string;
2613 int length = [im_text length]; 2624 int length = [im_text length];
2614 2625
2615 markedRange_ = NSMakeRange(0, length); 2626 // |markedRange_| will get set on a callback from ImeSetComposition().
2616 selectedRange_ = newSelRange; 2627 selectedRange_ = newSelRange;
2617 markedText_ = base::SysNSStringToUTF16(im_text); 2628 markedText_ = base::SysNSStringToUTF16(im_text);
2618 hasMarkedText_ = (length > 0); 2629 hasMarkedText_ = (length > 0);
2619 2630
2620 underlines_.clear(); 2631 underlines_.clear();
2621 if (isAttributedString) { 2632 if (isAttributedString) {
2622 ExtractUnderlines(string, &underlines_); 2633 ExtractUnderlines(string, &underlines_);
2623 } else { 2634 } else {
2624 // Use a thin black underline by default. 2635 // Use a thin black underline by default.
2625 underlines_.push_back( 2636 underlines_.push_back(
(...skipping 271 matching lines...) Expand 10 before | Expand all | Expand 10 after
2897 if (!string) return NO; 2908 if (!string) return NO;
2898 2909
2899 // If the user is currently using an IME, confirm the IME input, 2910 // If the user is currently using an IME, confirm the IME input,
2900 // and then insert the text from the service, the same as TextEdit and Safari. 2911 // and then insert the text from the service, the same as TextEdit and Safari.
2901 [self confirmComposition]; 2912 [self confirmComposition];
2902 [self insertText:string]; 2913 [self insertText:string];
2903 return YES; 2914 return YES;
2904 } 2915 }
2905 2916
2906 @end 2917 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698