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

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: Create AttributedStringCoder Created 9 years, 8 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 #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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698