diff options
| author | Peter Varga <pvarga@inf.u-szeged.hu> | 2017-04-27 11:23:55 +0200 |
|---|---|---|
| committer | Peter Varga <pvarga@inf.u-szeged.hu> | 2017-07-19 13:49:25 +0000 |
| commit | 3deea958f1485b50940e7437c0a3b73ed29ee134 (patch) | |
| tree | 27aaf5f4eb4e85aaf99f59ac1093adf538b39b5d | |
| parent | dfaf1564283dcdd222be9717a1a5ad9389ec7f1b (diff) | |
| download | qtwebengine-chromium-3deea958f1485b50940e7437c0a3b73ed29ee134.tar.gz | |
Update TextSelection for non-user initiated events
This makes Chromium Content API to be able to notify about text
selection changes triggered by non-user events (eg. JavaScript, IME,
autofill).
Based on:
https://codereview.chromium.org/2903833002
Corresponding Chromium bug report:
https://bugs.chromium.org/p/chromium/issues/detail?id=671986
Change-Id: I86a7f203d789853199469b301facd06fe5ba54bd
Task-number: QTBUG-53134
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
19 files changed, 119 insertions, 62 deletions
diff --git a/chromium/content/browser/frame_host/render_frame_host_impl.cc b/chromium/content/browser/frame_host/render_frame_host_impl.cc index 4e401ba8549..a33248ee421 100644 --- a/chromium/content/browser/frame_host/render_frame_host_impl.cc +++ b/chromium/content/browser/frame_host/render_frame_host_impl.cc @@ -2214,9 +2214,10 @@ void RenderFrameHostImpl::OnSerializeAsMHTMLResponse( void RenderFrameHostImpl::OnSelectionChanged(const base::string16& text, uint32_t offset, - const gfx::Range& range) { + const gfx::Range& range, + bool user_initiated) { has_selection_ = !text.empty(); - GetRenderWidgetHost()->SelectionChanged(text, offset, range); + GetRenderWidgetHost()->SelectionChanged(text, offset, range, user_initiated); } void RenderFrameHostImpl::OnFocusedNodeChanged( diff --git a/chromium/content/browser/frame_host/render_frame_host_impl.h b/chromium/content/browser/frame_host/render_frame_host_impl.h index caa51d7e0a1..29ed5b264a9 100644 --- a/chromium/content/browser/frame_host/render_frame_host_impl.h +++ b/chromium/content/browser/frame_host/render_frame_host_impl.h @@ -751,7 +751,8 @@ class CONTENT_EXPORT RenderFrameHostImpl base::TimeDelta renderer_main_thread_time); void OnSelectionChanged(const base::string16& text, uint32_t offset, - const gfx::Range& range); + const gfx::Range& range, + bool user_initiated); void OnFocusedNodeChanged(bool is_editable_element, const gfx::Rect& bounds_in_frame_widget); void OnSetHasReceivedUserGesture(); diff --git a/chromium/content/browser/frame_host/render_widget_host_view_guest.cc b/chromium/content/browser/frame_host/render_widget_host_view_guest.cc index 2197f73ad50..493fc1103c2 100644 --- a/chromium/content/browser/frame_host/render_widget_host_view_guest.cc +++ b/chromium/content/browser/frame_host/render_widget_host_view_guest.cc @@ -416,8 +416,9 @@ void RenderWidgetHostViewGuest::ImeCompositionRangeChanged( void RenderWidgetHostViewGuest::SelectionChanged(const base::string16& text, size_t offset, - const gfx::Range& range) { - platform_view_->SelectionChanged(text, offset, range); + const gfx::Range& range, + bool user_initiated) { + platform_view_->SelectionChanged(text, offset, range, user_initiated); } void RenderWidgetHostViewGuest::SelectionBoundsChanged( diff --git a/chromium/content/browser/frame_host/render_widget_host_view_guest.h b/chromium/content/browser/frame_host/render_widget_host_view_guest.h index fea13850ab5..b1c29f885a8 100644 --- a/chromium/content/browser/frame_host/render_widget_host_view_guest.h +++ b/chromium/content/browser/frame_host/render_widget_host_view_guest.h @@ -89,7 +89,8 @@ class CONTENT_EXPORT RenderWidgetHostViewGuest void SetTooltipText(const base::string16& tooltip_text) override; void SelectionChanged(const base::string16& text, size_t offset, - const gfx::Range& range) override; + const gfx::Range& range, + bool user_initiated) override; void SelectionBoundsChanged( const ViewHostMsg_SelectionBounds_Params& params) override; void OnSwapCompositorFrame(uint32_t compositor_frame_sink_id, diff --git a/chromium/content/browser/renderer_host/render_widget_host_impl.cc b/chromium/content/browser/renderer_host/render_widget_host_impl.cc index 980142ed724..712158308c2 100644 --- a/chromium/content/browser/renderer_host/render_widget_host_impl.cc +++ b/chromium/content/browser/renderer_host/render_widget_host_impl.cc @@ -1460,9 +1460,12 @@ const NativeWebKeyboardEvent* void RenderWidgetHostImpl::SelectionChanged(const base::string16& text, uint32_t offset, - const gfx::Range& range) { - if (view_) - view_->SelectionChanged(text, static_cast<size_t>(offset), range); + const gfx::Range& range, + bool user_initiated) { + if (view_) { + view_->SelectionChanged(text, static_cast<size_t>(offset), range, + user_initiated); + } } void RenderWidgetHostImpl::OnSelectionBoundsChanged( diff --git a/chromium/content/browser/renderer_host/render_widget_host_impl.h b/chromium/content/browser/renderer_host/render_widget_host_impl.h index a1f023bc95c..10c3c6c7330 100644 --- a/chromium/content/browser/renderer_host/render_widget_host_impl.h +++ b/chromium/content/browser/renderer_host/render_widget_host_impl.h @@ -546,7 +546,8 @@ class CONTENT_EXPORT RenderWidgetHostImpl : public RenderWidgetHost, // Called from a RenderFrameHost when the text selection has changed. void SelectionChanged(const base::string16& text, uint32_t offset, - const gfx::Range& range); + const gfx::Range& range, + bool user_initiated); // Expose increment/decrement of the in-flight event count, so // RenderViewHostImpl can account for in-flight beforeunload/unload events. diff --git a/chromium/content/browser/renderer_host/render_widget_host_view_aura.cc b/chromium/content/browser/renderer_host/render_widget_host_view_aura.cc index e2fe27bae0c..4018e4b919f 100644 --- a/chromium/content/browser/renderer_host/render_widget_host_view_aura.cc +++ b/chromium/content/browser/renderer_host/render_widget_host_view_aura.cc @@ -2364,7 +2364,8 @@ void RenderWidgetHostViewAura::OnTextSelectionChanged( const TextInputManager::TextSelection* selection = GetTextInputManager()->GetTextSelection(focused_view); - if (selection->selected_text().length()) { + if (selection->selected_text().length() + && selection->user_initiated()) { // Set the CLIPBOARD_TYPE_SELECTION to the ui::Clipboard. ui::ScopedClipboardWriter clipboard_writer(ui::CLIPBOARD_TYPE_SELECTION); clipboard_writer.WriteText(selection->selected_text()); diff --git a/chromium/content/browser/renderer_host/render_widget_host_view_base.cc b/chromium/content/browser/renderer_host/render_widget_host_view_base.cc index 029e72dcf3d..b8e032a44a3 100644 --- a/chromium/content/browser/renderer_host/render_widget_host_view_base.cc +++ b/chromium/content/browser/renderer_host/render_widget_host_view_base.cc @@ -134,9 +134,11 @@ float RenderWidgetHostViewBase::GetBottomControlsHeight() const { void RenderWidgetHostViewBase::SelectionChanged(const base::string16& text, size_t offset, - const gfx::Range& range) { + const gfx::Range& range, + bool user_initiated) { if (GetTextInputManager()) - GetTextInputManager()->SelectionChanged(this, text, offset, range); + GetTextInputManager()->SelectionChanged(this, text, offset, range, + user_initiated); } gfx::Size RenderWidgetHostViewBase::GetRequestedRendererSize() const { diff --git a/chromium/content/browser/renderer_host/render_widget_host_view_base.h b/chromium/content/browser/renderer_host/render_widget_host_view_base.h index 657ad2027f1..e514238ca7a 100644 --- a/chromium/content/browser/renderer_host/render_widget_host_view_base.h +++ b/chromium/content/browser/renderer_host/render_widget_host_view_base.h @@ -158,7 +158,8 @@ class CONTENT_EXPORT RenderWidgetHostViewBase : public RenderWidgetHostView, // Notifies the View that the renderer text selection has changed. virtual void SelectionChanged(const base::string16& text, size_t offset, - const gfx::Range& range); + const gfx::Range& range, + bool user_initiated); // The requested size of the renderer. May differ from GetViewBounds().size() // when the view requires additional throttling. diff --git a/chromium/content/browser/renderer_host/text_input_manager.cc b/chromium/content/browser/renderer_host/text_input_manager.cc index 6a96396af76..8f3f1be579c 100644 --- a/chromium/content/browser/renderer_host/text_input_manager.cc +++ b/chromium/content/browser/renderer_host/text_input_manager.cc @@ -240,9 +240,10 @@ void TextInputManager::ImeCompositionRangeChanged( void TextInputManager::SelectionChanged(RenderWidgetHostViewBase* view, const base::string16& text, size_t offset, - const gfx::Range& range) { + const gfx::Range& range, + bool user_initiated) { DCHECK(IsRegistered(view)); - text_selection_map_[view].SetSelection(text, offset, range); + text_selection_map_[view].SetSelection(text, offset, range, user_initiated); for (auto& observer : observer_list_) observer.OnTextSelectionChanged(this, view); } @@ -326,11 +327,13 @@ TextInputManager::TextSelection::~TextSelection() {} void TextInputManager::TextSelection::SetSelection(const base::string16& text, size_t offset, - const gfx::Range& range) { + const gfx::Range& range, + bool user_initiated) { text_ = text; range_.set_start(range.start()); range_.set_end(range.end()); offset_ = offset; + user_initiated_ = user_initiated; // Update the selected text. selected_text_.clear(); diff --git a/chromium/content/browser/renderer_host/text_input_manager.h b/chromium/content/browser/renderer_host/text_input_manager.h index 215b03d5e97..b40237b4428 100644 --- a/chromium/content/browser/renderer_host/text_input_manager.h +++ b/chromium/content/browser/renderer_host/text_input_manager.h @@ -105,12 +105,14 @@ class CONTENT_EXPORT TextInputManager { void SetSelection(const base::string16& text, size_t offset, - const gfx::Range& range); + const gfx::Range& range, + bool user_initiated); const base::string16& selected_text() const { return selected_text_; } size_t offset() const { return offset_; } const gfx::Range& range() const { return range_; } const base::string16& text() const { return text_; } + bool user_initiated() const { return user_initiated_; } private: // The offset of the text stored in |text| relative to the start of the web @@ -129,6 +131,9 @@ class CONTENT_EXPORT TextInputManager { // Part of the text on the page which includes the highlighted text plus // possibly several characters before and after it. base::string16 text_; + + // True if text selection is triggered by user input. + bool user_initiated_ = false; }; TextInputManager(); @@ -196,7 +201,8 @@ class CONTENT_EXPORT TextInputManager { void SelectionChanged(RenderWidgetHostViewBase* view, const base::string16& text, size_t offset, - const gfx::Range& range); + const gfx::Range& range, + bool user_initiated); // Registers the given |view| for tracking its TextInputState. This is called // by any view which has updates in its TextInputState (whether tab's RWHV or diff --git a/chromium/content/common/frame_messages.h b/chromium/content/common/frame_messages.h index 0442702b443..43c38f0c65d 100644 --- a/chromium/content/common/frame_messages.h +++ b/chromium/content/common/frame_messages.h @@ -1395,10 +1395,11 @@ IPC_MESSAGE_ROUTED1(FrameHostMsg_ContextMenu, content::ContextMenuParams) // Notification that the text selection has changed. // Note: The second parameter is the character based offset of the // base::string16 text in the document. -IPC_MESSAGE_ROUTED3(FrameHostMsg_SelectionChanged, +IPC_MESSAGE_ROUTED4(FrameHostMsg_SelectionChanged, base::string16 /* text covers the selection range */, uint32_t /* the offset of the text in the document */, - gfx::Range /* selection range in the document */) + gfx::Range /* selection range in the document */, + bool /* selection is triggered by user input */) // Response for FrameMsg_JavaScriptExecuteRequest, sent when a reply was // requested. The ID is the parameter supplied to diff --git a/chromium/content/public/renderer/render_frame.h b/chromium/content/public/renderer/render_frame.h index a6abdae8a2a..0cb46a5080f 100644 --- a/chromium/content/public/renderer/render_frame.h +++ b/chromium/content/public/renderer/render_frame.h @@ -223,7 +223,8 @@ class CONTENT_EXPORT RenderFrame : public IPC::Listener, // Notifies the browser of text selection changes made. virtual void SetSelectedText(const base::string16& selection_text, size_t offset, - const gfx::Range& range) = 0; + const gfx::Range& range, + bool user_initiated) = 0; // Ensures that builtin mojo bindings modules are available in |context|. virtual void EnsureMojoBuiltinsAreAvailable( diff --git a/chromium/content/renderer/input/render_widget_input_handler.cc b/chromium/content/renderer/input/render_widget_input_handler.cc index 248b565b087..4fea2610cdd 100644 --- a/chromium/content/renderer/input/render_widget_input_handler.cc +++ b/chromium/content/renderer/input/render_widget_input_handler.cc @@ -198,7 +198,8 @@ RenderWidgetInputHandler::RenderWidgetInputHandler( handling_event_overscroll_(nullptr), handling_event_type_(WebInputEvent::Undefined), context_menu_source_type_(ui::MENU_SOURCE_MOUSE), - suppress_next_char_events_(false) { + suppress_next_char_events_(false), + ime_composition_replacement_(false) { DCHECK(delegate); DCHECK(widget); delegate->SetInputHandler(this); diff --git a/chromium/content/renderer/input/render_widget_input_handler.h b/chromium/content/renderer/input/render_widget_input_handler.h index 04256edec6d..d589865fbfc 100644 --- a/chromium/content/renderer/input/render_widget_input_handler.h +++ b/chromium/content/renderer/input/render_widget_input_handler.h @@ -66,6 +66,13 @@ class CONTENT_EXPORT RenderWidgetInputHandler { context_menu_source_type_ = source_type; } + bool ime_composition_replacement() const { + return ime_composition_replacement_; + } + void set_ime_composition_replacement(bool ime_composition_replacement) { + ime_composition_replacement_ = ime_composition_replacement; + } + private: RenderWidgetInputHandlerDelegate* const delegate_; @@ -88,6 +95,10 @@ class CONTENT_EXPORT RenderWidgetInputHandler { // Indicates if the next sequence of Char events should be suppressed or not. bool suppress_next_char_events_; + // Used to suppress notification about text selection changes triggered by + // IME composition when it replaces text. + bool ime_composition_replacement_; + DISALLOW_COPY_AND_ASSIGN(RenderWidgetInputHandler); }; diff --git a/chromium/content/renderer/pepper/pepper_plugin_instance_impl.cc b/chromium/content/renderer/pepper/pepper_plugin_instance_impl.cc index b18b86c66c8..114c9c801a7 100644 --- a/chromium/content/renderer/pepper/pepper_plugin_instance_impl.cc +++ b/chromium/content/renderer/pepper/pepper_plugin_instance_impl.cc @@ -1382,7 +1382,7 @@ void PepperPluginInstanceImpl::SetSelectedText( const base::string16& selected_text) { selected_text_ = selected_text; gfx::Range range(0, selected_text.length()); - render_frame_->SetSelectedText(selected_text, 0, range); + render_frame_->SetSelectedText(selected_text, 0, range, true); } void PepperPluginInstanceImpl::SetLinkUnderCursor(const std::string& url) { diff --git a/chromium/content/renderer/render_frame_impl.cc b/chromium/content/renderer/render_frame_impl.cc index fc1f246b3d9..932db5d77fc 100644 --- a/chromium/content/renderer/render_frame_impl.cc +++ b/chromium/content/renderer/render_frame_impl.cc @@ -1340,7 +1340,7 @@ void RenderFrameImpl::PepperSelectionChanged( PepperPluginInstanceImpl* instance) { if (instance != focused_pepper_plugin_) return; - SyncSelectionIfRequired(false); + SyncSelectionIfRequired(false, true /* user_initiated */); } RenderWidgetFullscreenPepper* RenderFrameImpl::CreatePepperFullscreenContainer( @@ -1923,7 +1923,7 @@ void RenderFrameImpl::OnReplace(const base::string16& text) { frame_->selectWordAroundCaret(); frame_->replaceSelection(WebString::fromUTF16(text)); - SyncSelectionIfRequired(false); + SyncSelectionIfRequired(false, true /* user_initiated */); } void RenderFrameImpl::OnReplaceMisspelling(const base::string16& text) { @@ -2600,9 +2600,11 @@ void RenderFrameImpl::DetachGuest(int element_instance_id) { void RenderFrameImpl::SetSelectedText(const base::string16& selection_text, size_t offset, - const gfx::Range& range) { + const gfx::Range& range, + bool user_initiated) { Send(new FrameHostMsg_SelectionChanged(routing_id_, selection_text, - static_cast<uint32_t>(offset), range)); + static_cast<uint32_t>(offset), range, + user_initiated)); } void RenderFrameImpl::EnsureMojoBuiltinsAreAvailable( @@ -4038,10 +4040,20 @@ RenderFrameImpl::getEffectiveConnectionType() { } void RenderFrameImpl::didChangeSelection(bool is_empty_selection) { - if (!GetRenderWidget()->input_handler().handling_input_event() && - !handling_select_range_) - return; + bool user_initiated = + GetRenderWidget()->input_handler().handling_input_event() || + handling_select_range_; + + if (!user_initiated) { + // Do not update text input state unnecessarily when text selection remains + // empty. + if (is_empty_selection && selection_text_.empty()) + return; + // Ignore selection change of text replacement triggered by IME composition. + if (GetRenderWidget()->input_handler().ime_composition_replacement()) + return; + } // UpdateTextInputState should be called before SyncSelectionIfRequired. // UpdateTextInputState may send TextInputStateChanged to notify the focus @@ -4049,7 +4061,7 @@ void RenderFrameImpl::didChangeSelection(bool is_empty_selection) { // to notify the selection was changed. Focus change should be notified // before selection change. GetRenderWidget()->UpdateTextInputState(); - SyncSelectionIfRequired(is_empty_selection); + SyncSelectionIfRequired(is_empty_selection, user_initiated); } bool RenderFrameImpl::handleCurrentKeyboardEvent() { @@ -6104,10 +6116,11 @@ void RenderFrameImpl::UpdateEncoding(WebFrame* frame, Send(new FrameHostMsg_UpdateEncoding(routing_id_, encoding_name)); } -void RenderFrameImpl::SyncSelectionIfRequired(bool is_empty_selection) { +void RenderFrameImpl::SyncSelectionIfRequired(bool is_empty_selection, + bool user_initiated) { base::string16 text; size_t offset = 0; - gfx::Range range; + gfx::Range range = gfx::Range::InvalidRange(); #if BUILDFLAG(ENABLE_PLUGINS) if (focused_pepper_plugin_) { focused_pepper_plugin_->GetSurroundingText(&text, &range); @@ -6118,32 +6131,37 @@ void RenderFrameImpl::SyncSelectionIfRequired(bool is_empty_selection) { if (!is_empty_selection) { WebRange selection = GetRenderWidget()->GetWebWidget()->caretOrSelectionRange(); - if (selection.isNull()) - return; - - range = gfx::Range(selection.startOffset(), selection.endOffset()); - if (frame_->inputMethodController()->textInputType() != - blink::WebTextInputTypeNone) { - // If current focused element is editable, we will send 100 more chars - // before and after selection. It is for input method surrounding text - // feature. - if (selection.startOffset() > kExtraCharsBeforeAndAfterSelection) - offset = selection.startOffset() - kExtraCharsBeforeAndAfterSelection; - else - offset = 0; - size_t length = - selection.endOffset() - offset + kExtraCharsBeforeAndAfterSelection; - text = frame_->rangeAsText(WebRange(offset, length)).utf16(); - } else { - offset = selection.startOffset(); - text = frame_->selectionAsText().utf16(); - // http://crbug.com/101435 - // In some case, frame->selectionAsText() returned text's length is not - // equal to the length returned from - // GetWebWidget()->caretOrSelectionRange(). - // So we have to set the range according to text.length(). - range.set_end(range.start() + text.length()); + // When clearing text selection from JavaScript the selection range + // might be null but the selected text still have to be updated. + // Do not cancel sync selection if the clear was not user initiated. + if (!selection.isNull()) { + range = gfx::Range(selection.startOffset(), selection.endOffset()); + + if (frame_->inputMethodController()->textInputType() != + blink::WebTextInputTypeNone) { + // If current focused element is editable, we will send 100 more chars + // before and after selection. It is for input method surrounding text + // feature. + if (selection.startOffset() > kExtraCharsBeforeAndAfterSelection) + offset = selection.startOffset() - kExtraCharsBeforeAndAfterSelection; + else + offset = 0; + size_t length = + selection.endOffset() - offset + kExtraCharsBeforeAndAfterSelection; + text = frame_->rangeAsText(WebRange(offset, length)).utf16(); + } else { + offset = selection.startOffset(); + text = frame_->selectionAsText().utf16(); + // http://crbug.com/101435 + // In some case, frame->selectionAsText() returned text's length is not + // equal to the length returned from + // GetWebWidget()->caretOrSelectionRange(). + // So we have to set the range according to text.length(). + range.set_end(range.start() + text.length()); + } + } else if (user_initiated) { + return; } } @@ -6159,7 +6177,7 @@ void RenderFrameImpl::SyncSelectionIfRequired(bool is_empty_selection) { selection_text_ = text; selection_text_offset_ = offset; selection_range_ = range; - SetSelectedText(text, offset, range); + SetSelectedText(text, offset, range, user_initiated); } GetRenderWidget()->UpdateSelectionBounds(); } diff --git a/chromium/content/renderer/render_frame_impl.h b/chromium/content/renderer/render_frame_impl.h index 04e8dc8aa0b..33abad89a55 100644 --- a/chromium/content/renderer/render_frame_impl.h +++ b/chromium/content/renderer/render_frame_impl.h @@ -452,7 +452,8 @@ class CONTENT_EXPORT RenderFrameImpl void DetachGuest(int element_instance_id) override; void SetSelectedText(const base::string16& selection_text, size_t offset, - const gfx::Range& range) override; + const gfx::Range& range, + bool user_initiated) override; void EnsureMojoBuiltinsAreAvailable(v8::Isolate* isolate, v8::Local<v8::Context> context) override; void AddMessageToConsole(ConsoleMessageLevel level, @@ -993,7 +994,8 @@ class CONTENT_EXPORT RenderFrameImpl // it has changed. // TODO(varunjain): delete this method once we figure out how to keep // selection handles in sync with the webpage. - void SyncSelectionIfRequired(bool is_empty_selection); + void SyncSelectionIfRequired(bool is_empty_selection, + bool user_initiated); bool RunJavaScriptDialog(JavaScriptDialogType type, const base::string16& message, diff --git a/chromium/content/renderer/render_widget.cc b/chromium/content/renderer/render_widget.cc index 0b23ea4dff4..ab7debdc38c 100644 --- a/chromium/content/renderer/render_widget.cc +++ b/chromium/content/renderer/render_widget.cc @@ -1592,6 +1592,7 @@ void RenderWidget::OnImeSetComposition( } #endif ImeEventGuard guard(this); + input_handler_->set_ime_composition_replacement(replacement_range.IsValid()); blink::WebInputMethodController* controller = GetInputMethodController(); if (!controller || !controller->setComposition( @@ -1606,6 +1607,7 @@ void RenderWidget::OnImeSetComposition( // sure we are in a consistent state. Send(new InputHostMsg_ImeCancelComposition(routing_id())); } + input_handler_->set_ime_composition_replacement(false); UpdateCompositionInfo(false /* not an immediate request */); } |
