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

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

Issue 2164483006: [MacViews] Implemented text context menu (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Added test suite for TextServicesContextMenu Created 3 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
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "content/browser/renderer_host/render_widget_host_view_mac.h" 5 #include "content/browser/renderer_host/render_widget_host_view_mac.h"
6 6
7 #import <Carbon/Carbon.h> 7 #import <Carbon/Carbon.h>
8 #import <objc/runtime.h> 8 #import <objc/runtime.h>
9 #include <OpenGL/gl.h> 9 #include <OpenGL/gl.h>
10 #include <QuartzCore/QuartzCore.h> 10 #include <QuartzCore/QuartzCore.h>
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
66 #include "content/public/browser/web_contents.h" 66 #include "content/public/browser/web_contents.h"
67 #include "gpu/ipc/common/gpu_messages.h" 67 #include "gpu/ipc/common/gpu_messages.h"
68 #include "skia/ext/platform_canvas.h" 68 #include "skia/ext/platform_canvas.h"
69 #include "skia/ext/skia_utils_mac.h" 69 #include "skia/ext/skia_utils_mac.h"
70 #include "third_party/WebKit/public/platform/WebInputEvent.h" 70 #include "third_party/WebKit/public/platform/WebInputEvent.h"
71 #import "ui/base/clipboard/clipboard_util_mac.h" 71 #import "ui/base/clipboard/clipboard_util_mac.h"
72 #include "ui/base/cocoa/animation_utils.h" 72 #include "ui/base/cocoa/animation_utils.h"
73 #import "ui/base/cocoa/appkit_utils.h" 73 #import "ui/base/cocoa/appkit_utils.h"
74 #include "ui/base/cocoa/cocoa_base_utils.h" 74 #include "ui/base/cocoa/cocoa_base_utils.h"
75 #import "ui/base/cocoa/fullscreen_window_manager.h" 75 #import "ui/base/cocoa/fullscreen_window_manager.h"
76 #include "ui/base/cocoa/text_services_context_menu.h"
76 #import "ui/base/cocoa/underlay_opengl_hosting_window.h" 77 #import "ui/base/cocoa/underlay_opengl_hosting_window.h"
77 #include "ui/base/layout.h" 78 #include "ui/base/layout.h"
78 #include "ui/compositor/compositor.h" 79 #include "ui/compositor/compositor.h"
79 #include "ui/compositor/layer.h" 80 #include "ui/compositor/layer.h"
80 #include "ui/display/display.h" 81 #include "ui/display/display.h"
81 #include "ui/display/screen.h" 82 #include "ui/display/screen.h"
82 #include "ui/events/base_event_utils.h" 83 #include "ui/events/base_event_utils.h"
83 #include "ui/events/event_utils.h" 84 #include "ui/events/event_utils.h"
84 #include "ui/events/keycodes/keyboard_codes.h" 85 #include "ui/events/keycodes/keyboard_codes.h"
85 #include "ui/gfx/geometry/dip_util.h" 86 #include "ui/gfx/geometry/dip_util.h"
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
131 return render_widget_host_view; 132 return render_widget_host_view;
132 content::WebContents* guest = 133 content::WebContents* guest =
133 guest_manager->GetFullPageGuest(web_contents); 134 guest_manager->GetFullPageGuest(web_contents);
134 if (!guest) 135 if (!guest)
135 return render_widget_host_view; 136 return render_widget_host_view;
136 return guest->GetRenderWidgetHostView(); 137 return guest->GetRenderWidgetHostView();
137 } 138 }
138 139
139 } // namespace 140 } // namespace
140 141
141 // These are not documented, so use only after checking -respondsToSelector:.
142 @interface NSApplication (UndocumentedSpeechMethods)
143 - (void)speakString:(NSString*)string;
144 - (void)stopSpeaking:(id)sender;
145 - (BOOL)isSpeaking;
146 @end
147
148 // Private methods: 142 // Private methods:
149 @interface RenderWidgetHostViewCocoa () 143 @interface RenderWidgetHostViewCocoa ()
150 @property(nonatomic, assign) NSRange selectedRange; 144 @property(nonatomic, assign) NSRange selectedRange;
151 @property(nonatomic, assign) NSRange markedRange; 145 @property(nonatomic, assign) NSRange markedRange;
152 146
153 + (BOOL)shouldAutohideCursorForEvent:(NSEvent*)event; 147 + (BOOL)shouldAutohideCursorForEvent:(NSEvent*)event;
154 - (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r; 148 - (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r;
155 - (void)processedWheelEvent:(const blink::WebMouseWheelEvent&)event 149 - (void)processedWheelEvent:(const blink::WebMouseWheelEvent&)event
156 consumed:(BOOL)consumed; 150 consumed:(BOOL)consumed;
157 - (void)processedGestureScrollEvent:(const blink::WebGestureEvent&)event 151 - (void)processedGestureScrollEvent:(const blink::WebGestureEvent&)event
(...skipping 563 matching lines...) Expand 10 before | Expand all | Expand 10 after
721 715
722 if (!display_link_->GetVSyncParameters(&vsync_timebase_, &vsync_interval_)) { 716 if (!display_link_->GetVSyncParameters(&vsync_timebase_, &vsync_interval_)) {
723 vsync_timebase_ = base::TimeTicks(); 717 vsync_timebase_ = base::TimeTicks();
724 vsync_interval_ = base::TimeDelta(); 718 vsync_interval_ = base::TimeDelta();
725 return; 719 return;
726 } 720 }
727 721
728 browser_compositor_->UpdateVSyncParameters(vsync_timebase_, vsync_interval_); 722 browser_compositor_->UpdateVSyncParameters(vsync_timebase_, vsync_interval_);
729 } 723 }
730 724
731 void RenderWidgetHostViewMac::SpeakText(const std::string& text) {
732 [NSApp speakString:base::SysUTF8ToNSString(text)];
733 }
734
735 RenderWidgetHostViewBase* 725 RenderWidgetHostViewBase*
736 RenderWidgetHostViewMac::GetFocusedViewForTextSelection() { 726 RenderWidgetHostViewMac::GetFocusedViewForTextSelection() {
737 // We obtain the TextSelection from focused RWH which is obtained from the 727 // We obtain the TextSelection from focused RWH which is obtained from the
738 // frame tree. BrowserPlugin-based guests' RWH is not part of the frame tree 728 // frame tree. BrowserPlugin-based guests' RWH is not part of the frame tree
739 // and the focused RWH will be that of the embedder which is incorrect. In 729 // and the focused RWH will be that of the embedder which is incorrect. In
740 // this case we should use TextSelection for |this| since RWHV for guest 730 // this case we should use TextSelection for |this| since RWHV for guest
741 // forwards text selection information to its platform view. 731 // forwards text selection information to its platform view.
742 return is_guest_view_hack_ ? this : GetFocusedWidget() 732 return is_guest_view_hack_ ? this : GetFocusedWidget()
743 ? GetFocusedWidget()->GetView() 733 ? GetFocusedWidget()->GetView()
744 : nullptr; 734 : nullptr;
(...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after
1024 RenderWidgetHostViewBase* focused_view = GetFocusedViewForTextSelection(); 1014 RenderWidgetHostViewBase* focused_view = GetFocusedViewForTextSelection();
1025 if (!focused_view) 1015 if (!focused_view)
1026 return; 1016 return;
1027 1017
1028 const TextInputManager::TextSelection* selection = 1018 const TextInputManager::TextSelection* selection =
1029 GetTextInputManager()->GetTextSelection(focused_view); 1019 GetTextInputManager()->GetTextSelection(focused_view);
1030 1020
1031 base::string16 text; 1021 base::string16 text;
1032 if (!selection->GetSelectedText(&text)) 1022 if (!selection->GetSelectedText(&text))
1033 return; 1023 return;
1034 selected_text_ = base::UTF16ToUTF8(text); 1024 selected_text_ = text;
1035 1025
1036 [cocoa_view_ setSelectedRange:selection->range.ToNSRange()]; 1026 [cocoa_view_ setSelectedRange:selection->range.ToNSRange()];
1037 // Updates markedRange when there is no marked text so that retrieving 1027 // Updates markedRange when there is no marked text so that retrieving
1038 // markedRange immediately after calling setMarkdText: returns the current 1028 // markedRange immediately after calling setMarkdText: returns the current
1039 // caret position. 1029 // caret position.
1040 if (![cocoa_view_ hasMarkedText]) { 1030 if (![cocoa_view_ hasMarkedText]) {
1041 [cocoa_view_ setMarkedRange:selection->range.ToNSRange()]; 1031 [cocoa_view_ setMarkedRange:selection->range.ToNSRange()];
1042 } 1032 }
1043 1033
1044 // TODO(ekaramad): The following values are tracked by TextInputManager and 1034 // TODO(ekaramad): The following values are tracked by TextInputManager and
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
1112 // set it again every single time the mouse moves. 1102 // set it again every single time the mouse moves.
1113 base::string16 display_text = tooltip_text_; 1103 base::string16 display_text = tooltip_text_;
1114 if (tooltip_text_.length() > kMaxTooltipLength) 1104 if (tooltip_text_.length() > kMaxTooltipLength)
1115 display_text = tooltip_text_.substr(0, kMaxTooltipLength); 1105 display_text = tooltip_text_.substr(0, kMaxTooltipLength);
1116 1106
1117 NSString* tooltip_nsstring = base::SysUTF16ToNSString(display_text); 1107 NSString* tooltip_nsstring = base::SysUTF16ToNSString(display_text);
1118 [cocoa_view_ setToolTipAtMousePoint:tooltip_nsstring]; 1108 [cocoa_view_ setToolTipAtMousePoint:tooltip_nsstring];
1119 } 1109 }
1120 } 1110 }
1121 1111
1122 bool RenderWidgetHostViewMac::SupportsSpeech() const {
1123 return [NSApp respondsToSelector:@selector(speakString:)] &&
1124 [NSApp respondsToSelector:@selector(stopSpeaking:)];
1125 }
1126
1127 void RenderWidgetHostViewMac::SpeakSelection() { 1112 void RenderWidgetHostViewMac::SpeakSelection() {
1128 if (![NSApp respondsToSelector:@selector(speakString:)])
1129 return;
1130
1131 if (selected_text_.empty() && render_widget_host_) { 1113 if (selected_text_.empty() && render_widget_host_) {
1132 // If there's no selection, speak all text. Send an asynchronous IPC 1114 // If there's no selection, speak all text. Send an asynchronous IPC
1133 // request for fetching all the text for a webcontent. 1115 // request for fetching all the text for a webcontent.
1134 // ViewMsg_GetRenderedTextCompleted is sent back to IPC Message receiver. 1116 // ViewMsg_GetRenderedTextCompleted is sent back to IPC Message receiver.
1135 render_widget_host_->Send(new ViewMsg_GetRenderedText( 1117 render_widget_host_->Send(new ViewMsg_GetRenderedText(
1136 render_widget_host_->GetRoutingID())); 1118 render_widget_host_->GetRoutingID()));
1137 return; 1119 return;
1138 } 1120 }
1139 1121
1140 SpeakText(selected_text_); 1122 ui::TextServicesContextMenu::SpeakText(selected_text_);
1141 }
1142
1143 bool RenderWidgetHostViewMac::IsSpeaking() const {
1144 return [NSApp respondsToSelector:@selector(isSpeaking)] &&
1145 [NSApp isSpeaking];
1146 }
1147
1148 void RenderWidgetHostViewMac::StopSpeaking() {
1149 if ([NSApp respondsToSelector:@selector(stopSpeaking:)])
1150 [NSApp stopSpeaking:cocoa_view_];
1151 } 1123 }
1152 1124
1153 // 1125 //
1154 // RenderWidgetHostViewCocoa uses the stored selection text, 1126 // RenderWidgetHostViewCocoa uses the stored selection text,
1155 // which implements NSServicesRequests protocol. 1127 // which implements NSServicesRequests protocol.
1156 // 1128 //
1157 1129
1158 void RenderWidgetHostViewMac::SetShowingContextMenu(bool showing) { 1130 void RenderWidgetHostViewMac::SetShowingContextMenu(bool showing) {
1159 RenderWidgetHostViewBase::SetShowingContextMenu(showing); 1131 RenderWidgetHostViewBase::SetShowingContextMenu(showing);
1160 1132
(...skipping 538 matching lines...) Expand 10 before | Expand all | Expand 10 after
1699 else 1671 else
1700 DisablePasswordInput(); 1672 DisablePasswordInput();
1701 } else { 1673 } else {
1702 if (GetTextInputType() == ui::TEXT_INPUT_TYPE_PASSWORD) 1674 if (GetTextInputType() == ui::TEXT_INPUT_TYPE_PASSWORD)
1703 DisablePasswordInput(); 1675 DisablePasswordInput();
1704 } 1676 }
1705 } 1677 }
1706 1678
1707 void RenderWidgetHostViewMac::OnGetRenderedTextCompleted( 1679 void RenderWidgetHostViewMac::OnGetRenderedTextCompleted(
1708 const std::string& text) { 1680 const std::string& text) {
1709 SpeakText(text); 1681 ui::TextServicesContextMenu::SpeakText(base::UTF8ToUTF16(text));
1710 } 1682 }
1711 1683
1712 void RenderWidgetHostViewMac::PauseForPendingResizeOrRepaintsAndDraw() { 1684 void RenderWidgetHostViewMac::PauseForPendingResizeOrRepaintsAndDraw() {
1713 if (!render_widget_host_ || render_widget_host_->is_hidden()) 1685 if (!render_widget_host_ || render_widget_host_->is_hidden())
1714 return; 1686 return;
1715 1687
1716 // Pausing for one view prevents others from receiving frames. 1688 // Pausing for one view prevents others from receiving frames.
1717 // This may lead to large delays, causing overlaps. See crbug.com/352020. 1689 // This may lead to large delays, causing overlaps. See crbug.com/352020.
1718 if (!allow_pause_for_resize_or_repaint_) 1690 if (!allow_pause_for_resize_or_repaint_)
1719 return; 1691 return;
(...skipping 648 matching lines...) Expand 10 before | Expand all | Expand 10 after
2368 } 2340 }
2369 2341
2370 - (void)showLookUpDictionaryOverlayInternal:(NSAttributedString*) string 2342 - (void)showLookUpDictionaryOverlayInternal:(NSAttributedString*) string
2371 baselinePoint:(NSPoint) baselinePoint 2343 baselinePoint:(NSPoint) baselinePoint
2372 targetView:(NSView*) view { 2344 targetView:(NSView*) view {
2373 if ([string length] == 0) { 2345 if ([string length] == 0) {
2374 // The PDF plugin does not support getting the attributed string at point. 2346 // The PDF plugin does not support getting the attributed string at point.
2375 // Until it does, use NSPerformService(), which opens Dictionary.app. 2347 // Until it does, use NSPerformService(), which opens Dictionary.app.
2376 // TODO(shuchen): Support GetStringAtPoint() & GetStringFromRange() for PDF. 2348 // TODO(shuchen): Support GetStringAtPoint() & GetStringFromRange() for PDF.
2377 // See crbug.com/152438. 2349 // See crbug.com/152438.
2378 NSString* text = base::SysUTF8ToNSString( 2350 NSString* text =
2379 renderWidgetHostView_->selected_text()); 2351 base::SysUTF16ToNSString(renderWidgetHostView_->selected_text());
2380 if ([text length] == 0) 2352 if ([text length] == 0)
2381 return; 2353 return;
2382 scoped_refptr<ui::UniquePasteboard> pasteboard = new ui::UniquePasteboard; 2354 scoped_refptr<ui::UniquePasteboard> pasteboard = new ui::UniquePasteboard;
2383 NSArray* types = [NSArray arrayWithObject:NSStringPboardType]; 2355 NSArray* types = [NSArray arrayWithObject:NSStringPboardType];
2384 [pasteboard->get() declareTypes:types owner:nil]; 2356 [pasteboard->get() declareTypes:types owner:nil];
2385 if ([pasteboard->get() setString:text forType:NSStringPboardType]) 2357 if ([pasteboard->get() setString:text forType:NSStringPboardType])
2386 NSPerformService(@"Look Up in Dictionary", pasteboard->get()); 2358 NSPerformService(@"Look Up in Dictionary", pasteboard->get());
2387 return; 2359 return;
2388 } 2360 }
2389 dispatch_async(dispatch_get_main_queue(), ^{ 2361 dispatch_async(dispatch_get_main_queue(), ^{
(...skipping 370 matching lines...) Expand 10 before | Expand all | Expand 10 after
2760 if (known) 2732 if (known)
2761 return valid; 2733 return valid;
2762 } 2734 }
2763 2735
2764 SEL action = [item action]; 2736 SEL action = [item action];
2765 BOOL is_render_view = 2737 BOOL is_render_view =
2766 RenderViewHost::From(renderWidgetHostView_->render_widget_host_) != 2738 RenderViewHost::From(renderWidgetHostView_->render_widget_host_) !=
2767 nullptr; 2739 nullptr;
2768 2740
2769 if (action == @selector(stopSpeaking:)) 2741 if (action == @selector(stopSpeaking:))
2770 return is_render_view && renderWidgetHostView_->IsSpeaking(); 2742 return is_render_view && ui::TextServicesContextMenu::IsSpeaking();
2771 2743
2772 if (action == @selector(startSpeaking:)) 2744 if (action == @selector(startSpeaking:))
2773 return is_render_view && renderWidgetHostView_->SupportsSpeech(); 2745 return is_render_view;
2774 2746
2775 // For now, these actions are always enabled for render view, 2747 // For now, these actions are always enabled for render view,
2776 // this is sub-optimal. 2748 // this is sub-optimal.
2777 // TODO(suzhe): Plumb the "can*" methods up from WebCore. 2749 // TODO(suzhe): Plumb the "can*" methods up from WebCore.
2778 if (action == @selector(undo:) || 2750 if (action == @selector(undo:) ||
2779 action == @selector(redo:) || 2751 action == @selector(redo:) ||
2780 action == @selector(cut:) || 2752 action == @selector(cut:) ||
2781 action == @selector(copy:) || 2753 action == @selector(copy:) ||
2782 action == @selector(copyToFindPboard:) || 2754 action == @selector(copyToFindPboard:) ||
2783 action == @selector(paste:) || 2755 action == @selector(paste:) ||
(...skipping 573 matching lines...) Expand 10 before | Expand all | Expand 10 after
3357 renderWidgetHostView_->render_widget_host_->delegate(); 3329 renderWidgetHostView_->render_widget_host_->delegate();
3358 if (render_widget_host_delegate) 3330 if (render_widget_host_delegate)
3359 render_widget_host_delegate->SelectAll(); 3331 render_widget_host_delegate->SelectAll();
3360 } 3332 }
3361 3333
3362 - (void)startSpeaking:(id)sender { 3334 - (void)startSpeaking:(id)sender {
3363 GetRenderWidgetHostViewToUse(renderWidgetHostView_.get())->SpeakSelection(); 3335 GetRenderWidgetHostViewToUse(renderWidgetHostView_.get())->SpeakSelection();
3364 } 3336 }
3365 3337
3366 - (void)stopSpeaking:(id)sender { 3338 - (void)stopSpeaking:(id)sender {
3367 GetRenderWidgetHostViewToUse(renderWidgetHostView_.get())->StopSpeaking(); 3339 ui::TextServicesContextMenu::StopSpeaking();
3368 } 3340 }
3369 3341
3370 - (void)cancelComposition { 3342 - (void)cancelComposition {
3371 if (!hasMarkedText_) 3343 if (!hasMarkedText_)
3372 return; 3344 return;
3373 3345
3374 NSTextInputContext* inputContext = [self inputContext]; 3346 NSTextInputContext* inputContext = [self inputContext];
3375 [inputContext discardMarkedText]; 3347 [inputContext discardMarkedText];
3376 3348
3377 hasMarkedText_ = NO; 3349 hasMarkedText_ = NO;
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
3428 3400
3429 @end 3401 @end
3430 3402
3431 // 3403 //
3432 // Supporting application services 3404 // Supporting application services
3433 // 3405 //
3434 @implementation RenderWidgetHostViewCocoa(NSServicesRequests) 3406 @implementation RenderWidgetHostViewCocoa(NSServicesRequests)
3435 3407
3436 - (BOOL)writeSelectionToPasteboard:(NSPasteboard*)pboard 3408 - (BOOL)writeSelectionToPasteboard:(NSPasteboard*)pboard
3437 types:(NSArray*)types { 3409 types:(NSArray*)types {
3438 const std::string& str = renderWidgetHostView_->selected_text(); 3410 const base::string16& str = renderWidgetHostView_->selected_text();
3439 if (![types containsObject:NSStringPboardType] || str.empty()) return NO; 3411 if (![types containsObject:NSStringPboardType] || str.empty()) return NO;
3440 3412
3441 base::scoped_nsobject<NSString> text(
3442 [[NSString alloc] initWithUTF8String:str.c_str()]);
3443 NSArray* toDeclare = [NSArray arrayWithObject:NSStringPboardType]; 3413 NSArray* toDeclare = [NSArray arrayWithObject:NSStringPboardType];
3444 [pboard declareTypes:toDeclare owner:nil]; 3414 [pboard declareTypes:toDeclare owner:nil];
3445 return [pboard setString:text forType:NSStringPboardType]; 3415 return [pboard setString:SysUTF16ToNSString(str) forType:NSStringPboardType];
3446 } 3416 }
3447 3417
3448 - (BOOL)readSelectionFromPasteboard:(NSPasteboard*)pboard { 3418 - (BOOL)readSelectionFromPasteboard:(NSPasteboard*)pboard {
3449 NSString *string = [pboard stringForType:NSStringPboardType]; 3419 NSString *string = [pboard stringForType:NSStringPboardType];
3450 if (!string) return NO; 3420 if (!string) return NO;
3451 3421
3452 // If the user is currently using an IME, confirm the IME input, 3422 // If the user is currently using an IME, confirm the IME input,
3453 // and then insert the text from the service, the same as TextEdit and Safari. 3423 // and then insert the text from the service, the same as TextEdit and Safari.
3454 [self finishComposingText]; 3424 [self finishComposingText];
3455 [self insertText:string]; 3425 [self insertText:string];
3456 return YES; 3426 return YES;
3457 } 3427 }
3458 3428
3459 - (BOOL)isOpaque { 3429 - (BOOL)isOpaque {
3460 return opaque_; 3430 return opaque_;
3461 } 3431 }
3462 3432
3463 // "-webkit-app-region: drag | no-drag" is implemented on Mac by excluding 3433 // "-webkit-app-region: drag | no-drag" is implemented on Mac by excluding
3464 // regions that are not draggable. (See ControlRegionView in 3434 // regions that are not draggable. (See ControlRegionView in
3465 // native_app_window_cocoa.mm). This requires the render host view to be 3435 // native_app_window_cocoa.mm). This requires the render host view to be
3466 // draggable by default. 3436 // draggable by default.
3467 - (BOOL)mouseDownCanMoveWindow { 3437 - (BOOL)mouseDownCanMoveWindow {
3468 return YES; 3438 return YES;
3469 } 3439 }
3470 3440
3471 @end 3441 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698