diff options
author | shuchen <shuchen@chromium.org> | 2015-09-22 09:08:24 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-09-22 16:09:09 +0000 |
commit | 3146b3a43b240dcc6d64d5dc6986a311505104e8 (patch) | |
tree | b0a0a83521fc5179f9ac423ea8a74eb943a21207 | |
parent | bcffdcb5dc5b6baa0de7d763ee58d32d4a483b70 (diff) | |
download | chromium_src-3146b3a43b240dcc6d64d5dc6986a311505104e8.zip chromium_src-3146b3a43b240dcc6d64d5dc6986a311505104e8.tar.gz chromium_src-3146b3a43b240dcc6d64d5dc6986a311505104e8.tar.bz2 |
Implement "Look Up In Dictionary" context menu item asynchronously. (OS X)
Reduces the number of callers of the synchronous IPC in
TextInputClientMac::GetAttributedSubstringFromRange() (so that
eventually we can remove it).
Note: This is the second attempt to commit cl
https://codereview.chromium.org/1313553006, which caused regression
crbug.com/528929, because the point getten from selection range may not
be accurate to get the string through GetStringAtPoint.
This cl fixes that issue by leveraging
TextInputClientMsg_StringForRange IPCs instead of
TextInputClientMsg_StringAtPoint.
The change is cross browser & blink so it is 2-way patches.
This cl is based on the blink cl https://codereview.chromium.org/1329103002.
TextInputClientObserver::OnStringForRange() will send the IPC
TextInputClientReplyMsg_GotStringForRange to carry the basepiont info,
which is got by the new change in blink.
So this cl should be landed after https://codereview.chromium.org/1329103002
is landed.
TBR=sievers@chromium.org
BUG=121917
TEST=crbug.com/528929 not repro; Select multiple words and lookup
dictionary by context menu can work well; Select non-English words (e.g.
Japanese/Chinese) and lookup dictionary by context menu can work well.
Review URL: https://codereview.chromium.org/1318483007
Cr-Commit-Position: refs/heads/master@{#350164}
9 files changed, 112 insertions, 61 deletions
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.h b/content/browser/renderer_host/render_widget_host_view_mac.h index ee840c4..40f7d5b 100644 --- a/content/browser/renderer_host/render_widget_host_view_mac.h +++ b/content/browser/renderer_host/render_widget_host_view_mac.h @@ -208,6 +208,8 @@ class Layer; - (void)updateCursor:(NSCursor*)cursor; - (NSRect)firstViewRectForCharacterRange:(NSRange)theRange actualRange:(NSRangePointer)actualRange; +- (void)showLookUpDictionaryOverlayAtPoint:(NSPoint)point; +- (void)showLookUpDictionaryOverlayFromRange:(NSRange)range; @end namespace content { diff --git a/content/browser/renderer_host/render_widget_host_view_mac.mm b/content/browser/renderer_host/render_widget_host_view_mac.mm index 085e9f1..c05856c 100644 --- a/content/browser/renderer_host/render_widget_host_view_mac.mm +++ b/content/browser/renderer_host/render_widget_host_view_mac.mm @@ -180,6 +180,8 @@ static BOOL SupportsBackingPropertiesChangedNotification() { - (void)updateScreenProperties; - (void)setResponderDelegate: (NSObject<RenderWidgetHostViewMacDelegate>*)delegate; +- (void)showLookUpDictionaryOverlayInternal:(NSAttributedString*) string + baselinePoint:(NSPoint) baselinePoint; @end // A window subclass that allows the fullscreen window to become main and gain @@ -2430,24 +2432,58 @@ void RenderWidgetHostViewMac::OnDisplayMetricsChanged( } } -// This is invoked only on 10.8 or newer when the user taps a word using -// three fingers. -- (void)quickLookWithEvent:(NSEvent*)event { - NSPoint point = [self convertPoint:[event locationInWindow] fromView:nil]; +- (void)showLookUpDictionaryOverlayInternal:(NSAttributedString*) string + baselinePoint:(NSPoint) baselinePoint { + if ([string length] == 0) { + // The PDF plugin does not support getting the attributed string at point. + // Until it does, use NSPerformService(), which opens Dictionary.app. + // TODO(shuchen): Support GetStringAtPoint() & GetStringFromRange() for PDF. + // See crbug.com/152438. + NSString* text = base::SysUTF8ToNSString( + renderWidgetHostView_->selected_text()); + if ([text length] == 0) + return; + NSPasteboard* pasteboard = [NSPasteboard pasteboardWithUniqueName]; + NSArray* types = [NSArray arrayWithObject:NSStringPboardType]; + [pasteboard declareTypes:types owner:nil]; + if ([pasteboard setString:text forType:NSStringPboardType]) + NSPerformService(@"Look Up in Dictionary", pasteboard); + return; + } + dispatch_async(dispatch_get_main_queue(), ^{ + [self showDefinitionForAttributedString:string + atPoint:baselinePoint]; + }); +} + +- (void)showLookUpDictionaryOverlayFromRange:(NSRange)range { + TextInputClientMac::GetInstance()->GetStringFromRange( + renderWidgetHostView_->render_widget_host_, range, + ^(NSAttributedString* string, NSPoint baselinePoint) { + [self showLookUpDictionaryOverlayInternal:string + baselinePoint:baselinePoint]; + } + ); +} + +- (void)showLookUpDictionaryOverlayAtPoint:(NSPoint)point { TextInputClientMac::GetInstance()->GetStringAtPoint( renderWidgetHostView_->render_widget_host_, gfx::Point(point.x, NSHeight([self frame]) - point.y), ^(NSAttributedString* string, NSPoint baselinePoint) { - if (string && [string length] > 0) { - dispatch_async(dispatch_get_main_queue(), ^{ - [self showDefinitionForAttributedString:string - atPoint:baselinePoint]; - }); - } + [self showLookUpDictionaryOverlayInternal:string + baselinePoint:baselinePoint]; } ); } +// This is invoked only on 10.8 or newer when the user taps a word using +// three fingers. +- (void)quickLookWithEvent:(NSEvent*)event { + NSPoint point = [self convertPoint:[event locationInWindow] fromView:nil]; + [self showLookUpDictionaryOverlayAtPoint:point]; +} + // This method handles 2 different types of hardware events. // (Apple does not distinguish between them). // a. Scrolling the middle wheel of a mouse. diff --git a/content/browser/renderer_host/render_widget_host_view_mac_dictionary_helper.mm b/content/browser/renderer_host/render_widget_host_view_mac_dictionary_helper.mm index 92f10bc2..e004177 100644 --- a/content/browser/renderer_host/render_widget_host_view_mac_dictionary_helper.mm +++ b/content/browser/renderer_host/render_widget_host_view_mac_dictionary_helper.mm @@ -22,38 +22,7 @@ void RenderWidgetHostViewMacDictionaryHelper::SetTargetView( void RenderWidgetHostViewMacDictionaryHelper::ShowDefinitionForSelection() { NSRange selection_range = [view_->cocoa_view() selectedRange]; - NSAttributedString* attr_string = - [view_->cocoa_view() attributedSubstringForProposedRange:selection_range - actualRange:nil]; - if (!attr_string) { - if (view_->selected_text().empty()) - return; - // The PDF plugin does not support getting the attributed string. Until it - // does, use NSPerformService(), which opens Dictionary.app. - // http://crbug.com/152438 - // TODO(asvitkine): This should be removed after the above support is added. - NSString* text = base::SysUTF8ToNSString(view_->selected_text()); - NSPasteboard* pasteboard = [NSPasteboard pasteboardWithUniqueName]; - NSArray* types = [NSArray arrayWithObject:NSStringPboardType]; - [pasteboard declareTypes:types owner:nil]; - if ([pasteboard setString:text forType:NSStringPboardType]) - NSPerformService(@"Look Up in Dictionary", pasteboard); - return; - } - - NSRect rect = - [view_->cocoa_view() firstViewRectForCharacterRange:selection_range - actualRange:nil]; - - NSDictionary* attrs = [attr_string attributesAtIndex:0 effectiveRange:nil]; - NSFont* font = [attrs objectForKey:NSFontAttributeName]; - rect.origin.y += NSHeight(rect) - [font ascender]; - - rect.origin.x += offset_.x(); - rect.origin.y += offset_.y(); - - [target_view_->cocoa_view() showDefinitionForAttributedString:attr_string - atPoint:rect.origin]; + [view_->cocoa_view() showLookUpDictionaryOverlayFromRange:selection_range]; } } // namespace content diff --git a/content/browser/renderer_host/text_input_client_mac.h b/content/browser/renderer_host/text_input_client_mac.h index d682ebd..02d60142 100644 --- a/content/browser/renderer_host/text_input_client_mac.h +++ b/content/browser/renderer_host/text_input_client_mac.h @@ -73,16 +73,31 @@ class CONTENT_EXPORT TextInputClientMac { // This async method is invoked from RenderWidgetHostViewCocoa's // -quickLookWithEvent:, when the user taps a word using 3 fingers. - // The reply callback will be invoked from the IO thread, the caller is + // The reply callback will be invoked from the IO thread; the caller is // responsible for bouncing to the main thread if necessary. // The callback parameters provide the attributed word under the point and // the lower left baseline point of the text. void GetStringAtPoint(RenderWidgetHost* rwh, gfx::Point point, - void (^replyHandler)(NSAttributedString*, NSPoint)); + void (^reply_handler)(NSAttributedString*, NSPoint)); + // This is called on the IO thread when we get the renderer's reply for // GetStringAtPoint. - void GetStringAtPointReply(NSAttributedString*, NSPoint); + void GetStringAtPointReply(NSAttributedString* string, NSPoint point); + + // This async method is invoked when browser tries to retreive the text for + // certain range and doesn't want to wait for the reply from blink. + // The reply callback will be invoked from the IO thread; the caller is + // responsible for bouncing to the main thread if necessary. + // The callback parameters provide the attributed word under the point and + // the lower left baseline point of the text. + void GetStringFromRange(RenderWidgetHost* rwh, + NSRange range, + void (^reply_handler)(NSAttributedString*, NSPoint)); + + // This is called on the IO thread when we get the renderer's reply for + // GetStringFromRange. + void GetStringFromRangeReply(NSAttributedString* string, NSPoint point); private: friend struct base::DefaultSingletonTraits<TextInputClientMac>; @@ -105,7 +120,13 @@ class CONTENT_EXPORT TextInputClientMac { base::Lock lock_; base::ConditionVariable condition_; - base::mac::ScopedBlock<void(^)(NSAttributedString*, NSPoint)> replyHandler_; + // The callback when received IPC TextInputClientReplyMsg_GotStringAtPoint. + base::mac::ScopedBlock<void(^)(NSAttributedString*, NSPoint)> + replyForPointHandler_; + + // The callback when received IPC TextInputClientReplyMsg_GotStringForRange. + base::mac::ScopedBlock<void(^)(NSAttributedString*, NSPoint)> + replyForRangeHandler_; DISALLOW_COPY_AND_ASSIGN(TextInputClientMac); }; diff --git a/content/browser/renderer_host/text_input_client_mac.mm b/content/browser/renderer_host/text_input_client_mac.mm index dac24b3..58bf35f 100644 --- a/content/browser/renderer_host/text_input_client_mac.mm +++ b/content/browser/renderer_host/text_input_client_mac.mm @@ -36,18 +36,38 @@ TextInputClientMac* TextInputClientMac::GetInstance() { void TextInputClientMac::GetStringAtPoint( RenderWidgetHost* rwh, gfx::Point point, - void (^replyHandler)(NSAttributedString*, NSPoint)) { - DCHECK(replyHandler_.get() == nil); - replyHandler_.reset(replyHandler, base::scoped_policy::RETAIN); + void (^reply_handler)(NSAttributedString*, NSPoint)) { + DCHECK(replyForPointHandler_.get() == nil); + replyForPointHandler_.reset(reply_handler, base::scoped_policy::RETAIN); RenderWidgetHostImpl* rwhi = RenderWidgetHostImpl::From(rwh); rwhi->Send(new TextInputClientMsg_StringAtPoint(rwhi->GetRoutingID(), point)); } void TextInputClientMac::GetStringAtPointReply(NSAttributedString* string, NSPoint point) { - if (replyHandler_.get()) { - replyHandler_.get()(string, point); - replyHandler_.reset(); + if (replyForPointHandler_.get()) { + replyForPointHandler_.get()(string, point); + replyForPointHandler_.reset(); + } +} + +void TextInputClientMac::GetStringFromRange( + RenderWidgetHost* rwh, + NSRange range, + void (^reply_handler)(NSAttributedString*, NSPoint)) { + DCHECK(replyForRangeHandler_.get() == nil); + replyForRangeHandler_.reset(reply_handler, base::scoped_policy::RETAIN); + RenderWidgetHostImpl* rwhi = RenderWidgetHostImpl::From(rwh); + rwhi->Send(new TextInputClientMsg_StringForRange(rwhi->GetRoutingID(), + gfx::Range(range))); +} + +void TextInputClientMac::GetStringFromRangeReply(NSAttributedString* string, + NSPoint point) { + SetSubstringAndSignal(string); + if (replyForRangeHandler_.get()) { + replyForRangeHandler_.get()(string, point); + replyForRangeHandler_.reset(); } } diff --git a/content/browser/renderer_host/text_input_client_message_filter.h b/content/browser/renderer_host/text_input_client_message_filter.h index 1918620..992a9a2 100644 --- a/content/browser/renderer_host/text_input_client_message_filter.h +++ b/content/browser/renderer_host/text_input_client_message_filter.h @@ -38,7 +38,8 @@ class CONTENT_EXPORT TextInputClientMessageFilter void OnGotCharacterIndexForPoint(size_t index); void OnGotFirstRectForRange(const gfx::Rect& rect); void OnGotStringFromRange( - const mac::AttributedStringCoder::EncodedString& string); + const mac::AttributedStringCoder::EncodedString& string, + const gfx::Point& point); // Child process id. int child_process_id_; diff --git a/content/browser/renderer_host/text_input_client_message_filter.mm b/content/browser/renderer_host/text_input_client_message_filter.mm index 090daaa..34e9467 100644 --- a/content/browser/renderer_host/text_input_client_message_filter.mm +++ b/content/browser/renderer_host/text_input_client_message_filter.mm @@ -65,13 +65,13 @@ void TextInputClientMessageFilter::OnGotFirstRectForRange( } void TextInputClientMessageFilter::OnGotStringFromRange( - const mac::AttributedStringCoder::EncodedString& encoded_string) { + const mac::AttributedStringCoder::EncodedString& encoded_string, + const gfx::Point& point) { TextInputClientMac* service = TextInputClientMac::GetInstance(); NSAttributedString* string = mac::AttributedStringCoder::Decode(&encoded_string); - if (![string length]) - string = nil; - service->SetSubstringAndSignal(string); + service->GetStringFromRangeReply( + string, NSPointFromCGPoint(point.ToCGPoint())); } } // namespace content diff --git a/content/common/text_input_client_messages.h b/content/common/text_input_client_messages.h index 860bf10..8bd0db2 100644 --- a/content/common/text_input_client_messages.h +++ b/content/common/text_input_client_messages.h @@ -53,8 +53,9 @@ IPC_MESSAGE_ROUTED1(TextInputClientReplyMsg_GotFirstRectForRange, #if defined(OS_MACOSX) // Reply message for TextInputClientMsg_StringForRange. -IPC_MESSAGE_ROUTED1(TextInputClientReplyMsg_GotStringForRange, - mac::AttributedStringCoder::EncodedString) +IPC_MESSAGE_ROUTED2(TextInputClientReplyMsg_GotStringForRange, + mac::AttributedStringCoder::EncodedString, + gfx::Point) // Reply message for TextInputClientMsg_StringAtPoint IPC_MESSAGE_ROUTED2(TextInputClientReplyMsg_GotStringAtPoint, diff --git a/content/renderer/text_input_client_observer.cc b/content/renderer/text_input_client_observer.cc index 049f87c..87c7486 100644 --- a/content/renderer/text_input_client_observer.cc +++ b/content/renderer/text_input_client_observer.cc @@ -88,16 +88,17 @@ void TextInputClientObserver::OnFirstRectForCharacterRange(gfx::Range range) { void TextInputClientObserver::OnStringForRange(gfx::Range range) { #if defined(OS_MACOSX) + blink::WebPoint baselinePoint; NSAttributedString* string = nil; blink::WebLocalFrame* frame = webview()->focusedFrame()->toWebLocalFrame(); if (frame) { string = blink::WebSubstringUtil::attributedSubstringInRange( - frame, range.start(), range.length()); + frame, range.start(), range.length(), &baselinePoint); } scoped_ptr<const mac::AttributedStringCoder::EncodedString> encoded( mac::AttributedStringCoder::Encode(string)); Send(new TextInputClientReplyMsg_GotStringForRange(routing_id(), - *encoded.get())); + *encoded.get(), baselinePoint)); #else NOTIMPLEMENTED(); #endif |