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

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: Plumb selection rannge with ViewHostMsg_SelectionChanged Created 9 years, 11 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"
40 #include "gfx/point.h"
39 #include "skia/ext/platform_canvas.h" 41 #include "skia/ext/platform_canvas.h"
40 #include "third_party/skia/include/core/SkColor.h" 42 #include "third_party/skia/include/core/SkColor.h"
41 #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"
42 #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h" 44 #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.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 @interface RenderWidgetHostViewCocoa (Private)
62 + (BOOL)shouldAutohideCursorForEvent:(NSEvent*)event; 64 + (BOOL)shouldAutohideCursorForEvent:(NSEvent*)event;
63 - (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r; 65 - (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r;
64 - (void)keyEvent:(NSEvent *)theEvent wasKeyEquivalent:(BOOL)equiv; 66 - (void)keyEvent:(NSEvent*)theEvent wasKeyEquivalent:(BOOL)equiv;
65 - (void)cancelChildPopups; 67 - (void)cancelChildPopups;
68 - (void)setSelectedRange:(NSRange)range;
66 @end 69 @end
67 70
68 // This API was published since 10.6. Provide the declaration so it can be 71 // This API was published since 10.6. Provide the declaration so it can be
69 // // called below when building with the 10.5 SDK. 72 // // called below when building with the 10.5 SDK.
70 #if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5 73 #if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5
71 @class NSTextInputContext; 74 @class NSTextInputContext;
72 @interface NSResponder (AppKitDetails) 75 @interface NSResponder (AppKitDetails)
73 - (NSTextInputContext *)inputContext; 76 - (NSTextInputContext *)inputContext;
74 @end 77 @end
75 #endif 78 #endif
(...skipping 645 matching lines...) Expand 10 before | Expand all | Expand 10 after
721 } 724 }
722 725
723 void RenderWidgetHostViewMac::ImeUpdateTextInputState( 726 void RenderWidgetHostViewMac::ImeUpdateTextInputState(
724 WebKit::WebTextInputType type, 727 WebKit::WebTextInputType type,
725 const gfx::Rect& caret_rect) { 728 const gfx::Rect& caret_rect) {
726 if (text_input_type_ != type) { 729 if (text_input_type_ != type) {
727 text_input_type_ = type; 730 text_input_type_ = type;
728 if (HasFocus()) 731 if (HasFocus())
729 SetTextInputActive(true); 732 SetTextInputActive(true);
730 } 733 }
731
732 // We need to convert the coordinate of the cursor rectangle sent from the
733 // renderer and save it. Our input method backend uses a coordinate system
734 // whose origin is the upper-left corner of this view. On the other hand,
735 // Cocoa uses a coordinate system whose origin is the lower-left corner of
736 // this view. So, we convert the cursor rectangle and save it.
737 [cocoa_view_ setCaretRect:[cocoa_view_ flipRectToNSRect:caret_rect]];
738 } 734 }
739 735
740 void RenderWidgetHostViewMac::ImeCancelComposition() { 736 void RenderWidgetHostViewMac::ImeCancelComposition() {
741 [cocoa_view_ cancelComposition]; 737 [cocoa_view_ cancelComposition];
742 } 738 }
743 739
744 void RenderWidgetHostViewMac::DidUpdateBackingStore( 740 void RenderWidgetHostViewMac::DidUpdateBackingStore(
745 const gfx::Rect& scroll_rect, int scroll_dx, int scroll_dy, 741 const gfx::Rect& scroll_rect, int scroll_dx, int scroll_dy,
746 const std::vector<gfx::Rect>& copy_rects) { 742 const std::vector<gfx::Rect>& copy_rects) {
747 if (!is_hidden_) { 743 if (!is_hidden_) {
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
851 847
852 NSString* tooltip_nsstring = base::SysWideToNSString(display_text); 848 NSString* tooltip_nsstring = base::SysWideToNSString(display_text);
853 [cocoa_view_ setToolTipAtMousePoint:tooltip_nsstring]; 849 [cocoa_view_ setToolTipAtMousePoint:tooltip_nsstring];
854 } 850 }
855 } 851 }
856 852
857 // 853 //
858 // RenderWidgetHostViewCocoa uses the stored selection text, 854 // RenderWidgetHostViewCocoa uses the stored selection text,
859 // which implements NSServicesRequests protocol. 855 // which implements NSServicesRequests protocol.
860 // 856 //
861 void RenderWidgetHostViewMac::SelectionChanged(const std::string& text) { 857 void RenderWidgetHostViewMac::SelectionChanged(const std::string& text,
858 int range_start,
859 int range_end) {
862 selected_text_ = text; 860 selected_text_ = text;
861 NSRange range = NSMakeRange(range_start, range_end - range_start);
862 [cocoa_view_ setSelectedRange:range];
863 } 863 }
864 864
865 BackingStore* RenderWidgetHostViewMac::AllocBackingStore( 865 BackingStore* RenderWidgetHostViewMac::AllocBackingStore(
866 const gfx::Size& size) { 866 const gfx::Size& size) {
867 return new BackingStoreMac(render_widget_host_, size); 867 return new BackingStoreMac(render_widget_host_, size);
868 } 868 }
869 869
870 // Sets whether or not to accept first responder status. 870 // Sets whether or not to accept first responder status.
871 void RenderWidgetHostViewMac::SetTakesFocusOnlyOnMouseDown(bool flag) { 871 void RenderWidgetHostViewMac::SetTakesFocusOnlyOnMouseDown(bool flag) {
872 [cocoa_view_ setTakesFocusOnlyOnMouseDown:flag]; 872 [cocoa_view_ setTakesFocusOnlyOnMouseDown:flag];
(...skipping 439 matching lines...) Expand 10 before | Expand all | Expand 10 after
1312 } else { 1312 } else {
1313 if (text_input_type_ == WebKit::WebTextInputTypePassword) 1313 if (text_input_type_ == WebKit::WebTextInputTypePassword)
1314 DisablePasswordInput(); 1314 DisablePasswordInput();
1315 } 1315 }
1316 } 1316 }
1317 1317
1318 // RenderWidgetHostViewCocoa --------------------------------------------------- 1318 // RenderWidgetHostViewCocoa ---------------------------------------------------
1319 1319
1320 @implementation RenderWidgetHostViewCocoa 1320 @implementation RenderWidgetHostViewCocoa
1321 1321
1322 @synthesize caretRect = caretRect_;
1323
1324 - (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r { 1322 - (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r {
1325 self = [super initWithFrame:NSZeroRect]; 1323 self = [super initWithFrame:NSZeroRect];
1326 if (self) { 1324 if (self) {
1327 editCommand_helper_.reset(new RWHVMEditCommandHelper); 1325 editCommand_helper_.reset(new RWHVMEditCommandHelper);
1328 editCommand_helper_->AddEditingSelectorsToClass([self class]); 1326 editCommand_helper_->AddEditingSelectorsToClass([self class]);
1329 1327
1330 renderWidgetHostView_.reset(r); 1328 renderWidgetHostView_.reset(r);
1331 canBeKeyView_ = YES; 1329 canBeKeyView_ = YES;
1332 takesFocusOnlyOnMouseDown_ = NO; 1330 takesFocusOnlyOnMouseDown_ = NO;
1333 closeOnDeactivate_ = NO; 1331 closeOnDeactivate_ = NO;
(...skipping 1005 matching lines...) Expand 10 before | Expand all | Expand 10 after
2339 NSUnderlineStyleAttributeName, 2337 NSUnderlineStyleAttributeName,
2340 NSUnderlineColorAttributeName, 2338 NSUnderlineColorAttributeName,
2341 NSMarkedClauseSegmentAttributeName, 2339 NSMarkedClauseSegmentAttributeName,
2342 NSTextInputReplacementRangeAttributeName, 2340 NSTextInputReplacementRangeAttributeName,
2343 nil]); 2341 nil]);
2344 } 2342 }
2345 return validAttributesForMarkedText_.get(); 2343 return validAttributesForMarkedText_.get();
2346 } 2344 }
2347 2345
2348 - (NSUInteger)characterIndexForPoint:(NSPoint)thePoint { 2346 - (NSUInteger)characterIndexForPoint:(NSPoint)thePoint {
2349 NOTIMPLEMENTED(); 2347 DCHECK([self window]);
2350 return NSNotFound; 2348 // |thePoint| is in screen coordinates, but needs to be converted to WebKit
2349 // coordinates (upper left origin). Scroll offsets will be taken care of in
2350 // the renderer.
2351 thePoint = [[self window] convertScreenToBase:thePoint];
2352 thePoint = [self convertPoint:thePoint fromView:nil];
2353 thePoint.y = NSHeight([self frame]) - thePoint.y;
2354
2355 TextInputClientMac* service = TextInputClientMac::GetInstance();
2356 service->BeforeRequest();
2357 renderWidgetHostView_->render_widget_host_->Send(
2358 new ViewMsg_CharacterIndexForPoint(
2359 renderWidgetHostView_->render_widget_host_->routing_id(),
2360 gfx::Point(thePoint.x, thePoint.y)));
2361 NSUInteger index = service->WaitForCharacterIndex();
2362 service->AfterRequest();
2363 return index;
2351 } 2364 }
2352 2365
2353 - (NSRect)firstRectForCharacterRange:(NSRange)theRange { 2366 - (NSRect)firstRectForCharacterRange:(NSRange)theRange {
2354 // An input method requests a cursor rectangle to display its candidate 2367 TextInputClientMac* service = TextInputClientMac::GetInstance();
2355 // window. 2368 service->BeforeRequest();
2356 // Calculate the screen coordinate of the cursor rectangle saved in 2369 renderWidgetHostView_->render_widget_host_->Send(
2357 // RenderWidgetHostViewMac::ImeUpdateTextInputState() and send it to the 2370 new ViewMsg_FirstRectForCharacterRange(
2358 // input method. 2371 renderWidgetHostView_->render_widget_host_->routing_id(),
2359 // Since this window may be moved since we receive the cursor rectangle last 2372 theRange.location,
2360 // time we sent the cursor rectangle to the input method, so we should map 2373 theRange.length));
2361 // from the view coordinate to the screen coordinate every time when an input 2374 NSRect rect = service->WaitForFirstRect();
2362 // method need it. 2375 service->AfterRequest();
2363 NSRect resultRect = [self convertRect:caretRect_ toView:nil]; 2376 // The returned rectangle is in WebKit coordinates (upper left origin), so
2364 NSWindow* window = [self window]; 2377 // flip the coordinate system and then convert it into screen coordinates for
2365 if (window) 2378 // return.
2366 resultRect.origin = [window convertBaseToScreen:resultRect.origin]; 2379 NSRect viewFrame = [self frame];
2380 rect.origin.y = NSHeight(viewFrame) - rect.origin.y;
2381 rect.origin.y -= rect.size.height;
2382 rect = [self convertRectToBase:rect];
2383 rect.origin = [[self window] convertBaseToScreen:rect.origin];
2384 return rect;
James Su 2011/01/20 23:46:06 We probably can do an optimization here: Usually w
2385 }
2367 2386
2368 return resultRect; 2387 // Called from RWHVM::OnSelectionChanged.
2388 - (void)setSelectedRange:(NSRange)range {
2389 selectedRange_ = range;
James Su 2011/01/20 23:46:06 How about to use @synthesize for this property?
Robert Sesek 2011/01/21 23:40:07 Done.
2369 } 2390 }
2370 2391
2371 - (NSRange)selectedRange { 2392 - (NSRange)selectedRange {
2372 // Return the selected range saved in the setMarkedText method. 2393 return selectedRange_;
2373 return hasMarkedText_ ? selectedRange_ : NSMakeRange(NSNotFound, 0);
2374 } 2394 }
2375 2395
2376 - (NSRange)markedRange { 2396 - (NSRange)markedRange {
2377 // An input method calls this method to check if an application really has 2397 // An input method calls this method to check if an application really has
2378 // a text being composed when hasMarkedText call returns true. 2398 // a text being composed when hasMarkedText call returns true.
2379 // Returns the range saved in the setMarkedText method so the input method 2399 // Returns the range saved in the setMarkedText method so the input method
2380 // calls the setMarkedText method and we can update the composition node 2400 // calls the setMarkedText method and we can update the composition node
2381 // there. (When this method returns an empty range, the input method doesn't 2401 // there. (When this method returns an empty range, the input method doesn't
2382 // call the setMarkedText method.) 2402 // call the setMarkedText method.)
2383 return hasMarkedText_ ? markedRange_ : NSMakeRange(NSNotFound, 0); 2403 return hasMarkedText_ ? markedRange_ : NSMakeRange(NSNotFound, 0);
2384 } 2404 }
2385 2405
2386 - (NSAttributedString *)attributedSubstringFromRange:(NSRange)range { 2406 - (NSAttributedString*)attributedSubstringFromRange:(NSRange)range {
2387 // TODO(hbono): Even though many input method works without implementing 2407 TextInputClientMac* service = TextInputClientMac::GetInstance();
2388 // this method, we need to save a copy of the string in the setMarkedText 2408 service->BeforeRequest();
2389 // method and create a NSAttributedString with the given range. 2409 renderWidgetHostView_->render_widget_host_->Send(
2390 // http://crbug.com/37715 2410 new ViewMsg_StringForRange(
2391 return nil; 2411 renderWidgetHostView_->render_widget_host_->routing_id(),
2412 range.location,
2413 range.length));
2414 NSAttributedString* string = service->WaitForSubstring();
2415 service->AfterRequest();
2416 return string;
2392 } 2417 }
2393 2418
2394 - (NSInteger)conversationIdentifier { 2419 - (NSInteger)conversationIdentifier {
2395 return reinterpret_cast<NSInteger>(self); 2420 return reinterpret_cast<NSInteger>(self);
2396 } 2421 }
2397 2422
2398 // Each RenderWidgetHostViewCocoa has its own input context, but we return 2423 // Each RenderWidgetHostViewCocoa has its own input context, but we return
2399 // nil when the caret is in non-editable content or password box to avoid 2424 // nil when the caret is in non-editable content or password box to avoid
2400 // making input methods do their work. 2425 // making input methods do their work.
2401 - (NSTextInputContext *)inputContext { 2426 - (NSTextInputContext *)inputContext {
(...skipping 323 matching lines...) Expand 10 before | Expand all | Expand 10 after
2725 if (!string) return NO; 2750 if (!string) return NO;
2726 2751
2727 // If the user is currently using an IME, confirm the IME input, 2752 // If the user is currently using an IME, confirm the IME input,
2728 // and then insert the text from the service, the same as TextEdit and Safari. 2753 // and then insert the text from the service, the same as TextEdit and Safari.
2729 [self confirmComposition]; 2754 [self confirmComposition];
2730 [self insertText:string]; 2755 [self insertText:string];
2731 return YES; 2756 return YES;
2732 } 2757 }
2733 2758
2734 @end 2759 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698