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

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

Powered by Google App Engine
This is Rietveld 408576698