| 
									
										
										
										
											2017-05-19 21:35:13 +02:00
										 |  |  | // Copyright (c) 2017 GitHub, Inc.
 | 
					
						
							|  |  |  | // Use of this source code is governed by the MIT license that can be
 | 
					
						
							|  |  |  | // found in the LICENSE file.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "atom/renderer/atom_autofill_agent.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-19 21:52:18 +02:00
										 |  |  | #include <vector>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-19 21:35:13 +02:00
										 |  |  | #include "atom/common/api/api_messages.h"
 | 
					
						
							|  |  |  | #include "content/public/renderer/render_frame.h"
 | 
					
						
							|  |  |  | #include "content/public/renderer/render_view.h"
 | 
					
						
							| 
									
										
										
										
											2018-07-20 18:08:18 +02:00
										 |  |  | #include "third_party/blink/public/platform/web_keyboard_event.h"
 | 
					
						
							|  |  |  | #include "third_party/blink/public/platform/web_string.h"
 | 
					
						
							|  |  |  | #include "third_party/blink/public/web/web_document.h"
 | 
					
						
							|  |  |  | #include "third_party/blink/public/web/web_local_frame.h"
 | 
					
						
							|  |  |  | #include "third_party/blink/public/web/web_option_element.h"
 | 
					
						
							|  |  |  | #include "third_party/blink/public/web/web_user_gesture_indicator.h"
 | 
					
						
							| 
									
										
										
										
											2017-05-19 21:35:13 +02:00
										 |  |  | #include "ui/events/keycodes/keyboard_codes.h"
 | 
					
						
							|  |  |  | #include "ui/gfx/geometry/rect_f.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace atom { | 
					
						
							| 
									
										
										
										
											2017-05-19 21:52:18 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-19 21:35:13 +02:00
										 |  |  | namespace { | 
					
						
							|  |  |  | const size_t kMaxDataLength = 1024; | 
					
						
							|  |  |  | const size_t kMaxListSize = 512; | 
					
						
							| 
									
										
										
										
											2017-05-19 21:52:18 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-19 21:35:13 +02:00
										 |  |  | void GetDataListSuggestions(const blink::WebInputElement& element, | 
					
						
							| 
									
										
										
										
											2018-04-17 21:55:30 -04:00
										 |  |  |                             std::vector<base::string16>* values, | 
					
						
							|  |  |  |                             std::vector<base::string16>* labels) { | 
					
						
							| 
									
										
										
										
											2017-06-16 23:42:33 +03:00
										 |  |  |   for (const auto& option : element.FilteredDataListOptions()) { | 
					
						
							|  |  |  |     values->push_back(option.Value().Utf16()); | 
					
						
							|  |  |  |     if (option.Value() != option.Label()) | 
					
						
							|  |  |  |       labels->push_back(option.Label().Utf16()); | 
					
						
							| 
									
										
										
										
											2017-05-19 21:35:13 +02:00
										 |  |  |     else | 
					
						
							|  |  |  |       labels->push_back(base::string16()); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void TrimStringVectorForIPC(std::vector<base::string16>* strings) { | 
					
						
							|  |  |  |   // Limit the size of the vector.
 | 
					
						
							|  |  |  |   if (strings->size() > kMaxListSize) | 
					
						
							|  |  |  |     strings->resize(kMaxListSize); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Limit the size of the strings in the vector.
 | 
					
						
							|  |  |  |   for (size_t i = 0; i < strings->size(); ++i) { | 
					
						
							|  |  |  |     if ((*strings)[i].length() > kMaxDataLength) | 
					
						
							|  |  |  |       (*strings)[i].resize(kMaxDataLength); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2017-05-19 21:52:18 +02:00
										 |  |  | }  // namespace
 | 
					
						
							| 
									
										
										
										
											2017-05-19 21:35:13 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-17 21:55:30 -04:00
										 |  |  | AutofillAgent::AutofillAgent(content::RenderFrame* frame) | 
					
						
							| 
									
										
										
										
											2018-05-22 00:18:38 +02:00
										 |  |  |     : content::RenderFrameObserver(frame), weak_ptr_factory_(this) { | 
					
						
							| 
									
										
										
										
											2017-06-16 23:42:33 +03:00
										 |  |  |   render_frame()->GetWebFrame()->SetAutofillClient(this); | 
					
						
							| 
									
										
										
										
											2017-05-20 04:21:11 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-17 16:37:22 -07:00
										 |  |  | AutofillAgent::~AutofillAgent() = default; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-19 21:35:13 +02:00
										 |  |  | void AutofillAgent::OnDestruct() { | 
					
						
							|  |  |  |   delete this; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AutofillAgent::DidChangeScrollOffset() { | 
					
						
							|  |  |  |   HidePopup(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-22 12:55:37 -07:00
										 |  |  | void AutofillAgent::FocusedElementChanged(const blink::WebElement&) { | 
					
						
							| 
									
										
										
										
											2017-05-21 19:55:19 +02:00
										 |  |  |   focused_node_was_last_clicked_ = false; | 
					
						
							| 
									
										
										
										
											2017-05-20 04:21:11 +02:00
										 |  |  |   was_focused_before_now_ = false; | 
					
						
							| 
									
										
										
										
											2017-05-19 21:35:13 +02:00
										 |  |  |   HidePopup(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-17 21:55:30 -04:00
										 |  |  | void AutofillAgent::TextFieldDidEndEditing(const blink::WebInputElement&) { | 
					
						
							| 
									
										
										
										
											2017-05-19 21:35:13 +02:00
										 |  |  |   HidePopup(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-16 23:42:33 +03:00
										 |  |  | void AutofillAgent::TextFieldDidChange( | 
					
						
							| 
									
										
										
										
											2017-05-19 21:52:18 +02:00
										 |  |  |     const blink::WebFormControlElement& element) { | 
					
						
							| 
									
										
										
										
											2017-05-19 21:35:13 +02:00
										 |  |  |   if (!IsUserGesture() && !render_frame()->IsPasting()) | 
					
						
							|  |  |  |     return; | 
					
						
							| 
									
										
										
										
											2017-05-19 21:52:18 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-19 21:35:13 +02:00
										 |  |  |   weak_ptr_factory_.InvalidateWeakPtrs(); | 
					
						
							|  |  |  |   base::ThreadTaskRunnerHandle::Get()->PostTask( | 
					
						
							| 
									
										
										
										
											2018-04-20 16:25:05 +05:30
										 |  |  |       FROM_HERE, base::BindOnce(&AutofillAgent::TextFieldDidChangeImpl, | 
					
						
							|  |  |  |                                 weak_ptr_factory_.GetWeakPtr(), element)); | 
					
						
							| 
									
										
										
										
											2017-05-19 21:35:13 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-16 23:42:33 +03:00
										 |  |  | void AutofillAgent::TextFieldDidChangeImpl( | 
					
						
							| 
									
										
										
										
											2017-05-19 21:52:18 +02:00
										 |  |  |     const blink::WebFormControlElement& element) { | 
					
						
							| 
									
										
										
										
											2017-05-19 21:35:13 +02:00
										 |  |  |   ShowSuggestionsOptions options; | 
					
						
							|  |  |  |   options.requires_caret_at_end = true; | 
					
						
							|  |  |  |   ShowSuggestions(element, options); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-16 23:42:33 +03:00
										 |  |  | void AutofillAgent::TextFieldDidReceiveKeyDown( | 
					
						
							| 
									
										
										
										
											2017-05-19 21:52:18 +02:00
										 |  |  |     const blink::WebInputElement& element, | 
					
						
							| 
									
										
										
										
											2017-05-19 21:35:13 +02:00
										 |  |  |     const blink::WebKeyboardEvent& event) { | 
					
						
							| 
									
										
										
										
											2017-06-16 23:42:33 +03:00
										 |  |  |   if (event.windows_key_code == ui::VKEY_DOWN || | 
					
						
							|  |  |  |       event.windows_key_code == ui::VKEY_UP) { | 
					
						
							| 
									
										
										
										
											2017-05-19 21:35:13 +02:00
										 |  |  |     ShowSuggestionsOptions options; | 
					
						
							|  |  |  |     options.autofill_on_empty_values = true; | 
					
						
							|  |  |  |     options.requires_caret_at_end = true; | 
					
						
							|  |  |  |     ShowSuggestions(element, options); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-16 23:42:33 +03:00
										 |  |  | void AutofillAgent::OpenTextDataListChooser( | 
					
						
							| 
									
										
										
										
											2017-05-19 21:35:13 +02:00
										 |  |  |     const blink::WebInputElement& element) { | 
					
						
							|  |  |  |   ShowSuggestionsOptions options; | 
					
						
							|  |  |  |   options.autofill_on_empty_values = true; | 
					
						
							|  |  |  |   ShowSuggestions(element, options); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-16 23:42:33 +03:00
										 |  |  | void AutofillAgent::DataListOptionsChanged( | 
					
						
							| 
									
										
										
										
											2017-05-19 21:35:13 +02:00
										 |  |  |     const blink::WebInputElement& element) { | 
					
						
							| 
									
										
										
										
											2017-06-16 23:42:33 +03:00
										 |  |  |   if (!element.Focused()) | 
					
						
							| 
									
										
										
										
											2017-05-19 21:35:13 +02:00
										 |  |  |     return; | 
					
						
							| 
									
										
										
										
											2017-05-19 21:52:18 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-19 21:35:13 +02:00
										 |  |  |   ShowSuggestionsOptions options; | 
					
						
							|  |  |  |   options.requires_caret_at_end = true; | 
					
						
							|  |  |  |   ShowSuggestions(element, options); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AutofillAgent::ShowSuggestionsOptions::ShowSuggestionsOptions() | 
					
						
							| 
									
										
										
										
											2018-04-17 21:55:30 -04:00
										 |  |  |     : autofill_on_empty_values(false), requires_caret_at_end(false) {} | 
					
						
							| 
									
										
										
										
											2017-05-19 21:35:13 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-17 21:55:30 -04:00
										 |  |  | void AutofillAgent::ShowSuggestions(const blink::WebFormControlElement& element, | 
					
						
							|  |  |  |                                     const ShowSuggestionsOptions& options) { | 
					
						
							| 
									
										
										
										
											2017-06-16 23:42:33 +03:00
										 |  |  |   if (!element.IsEnabled() || element.IsReadOnly()) | 
					
						
							| 
									
										
										
										
											2017-05-19 21:35:13 +02:00
										 |  |  |     return; | 
					
						
							| 
									
										
										
										
											2017-06-16 23:42:33 +03:00
										 |  |  |   const blink::WebInputElement* input_element = ToWebInputElement(&element); | 
					
						
							| 
									
										
										
										
											2017-05-19 21:35:13 +02:00
										 |  |  |   if (input_element) { | 
					
						
							| 
									
										
										
										
											2017-06-16 23:42:33 +03:00
										 |  |  |     if (!input_element->IsTextField()) | 
					
						
							| 
									
										
										
										
											2017-05-19 21:35:13 +02:00
										 |  |  |       return; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-05-19 21:52:18 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-16 23:42:33 +03:00
										 |  |  |   blink::WebString value = element.EditingValue(); | 
					
						
							| 
									
										
										
										
											2017-05-19 21:35:13 +02:00
										 |  |  |   if (value.length() > kMaxDataLength || | 
					
						
							| 
									
										
										
										
											2017-06-16 23:42:33 +03:00
										 |  |  |       (!options.autofill_on_empty_values && value.IsEmpty()) || | 
					
						
							| 
									
										
										
										
											2017-05-19 21:35:13 +02:00
										 |  |  |       (options.requires_caret_at_end && | 
					
						
							| 
									
										
										
										
											2017-06-16 23:42:33 +03:00
										 |  |  |        (element.SelectionStart() != element.SelectionEnd() || | 
					
						
							|  |  |  |         element.SelectionEnd() != static_cast<int>(value.length())))) { | 
					
						
							| 
									
										
										
										
											2017-05-19 21:35:13 +02:00
										 |  |  |     HidePopup(); | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-05-19 21:52:18 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-19 21:35:13 +02:00
										 |  |  |   std::vector<base::string16> data_list_values; | 
					
						
							|  |  |  |   std::vector<base::string16> data_list_labels; | 
					
						
							|  |  |  |   if (input_element) { | 
					
						
							| 
									
										
										
										
											2018-04-17 21:55:30 -04:00
										 |  |  |     GetDataListSuggestions(*input_element, &data_list_values, | 
					
						
							|  |  |  |                            &data_list_labels); | 
					
						
							| 
									
										
										
										
											2017-05-19 21:35:13 +02:00
										 |  |  |     TrimStringVectorForIPC(&data_list_values); | 
					
						
							|  |  |  |     TrimStringVectorForIPC(&data_list_labels); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-05-19 21:52:18 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-19 21:35:13 +02:00
										 |  |  |   ShowPopup(element, data_list_values, data_list_labels); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-29 16:50:55 -07:00
										 |  |  | void AutofillAgent::DidReceiveLeftMouseDownOrGestureTapInNode( | 
					
						
							|  |  |  |     const blink::WebNode& node) { | 
					
						
							| 
									
										
										
										
											2017-06-22 01:47:01 +03:00
										 |  |  |   focused_node_was_last_clicked_ = !node.IsNull() && node.Focused(); | 
					
						
							| 
									
										
										
										
											2017-05-20 04:21:11 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-22 01:47:01 +03:00
										 |  |  | void AutofillAgent::DidCompleteFocusChangeInFrame() { | 
					
						
							|  |  |  |   DoFocusChangeComplete(); | 
					
						
							| 
									
										
										
										
											2017-05-19 21:35:13 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool AutofillAgent::OnMessageReceived(const IPC::Message& message) { | 
					
						
							|  |  |  |   bool handled = true; | 
					
						
							|  |  |  |   IPC_BEGIN_MESSAGE_MAP(AutofillAgent, message) | 
					
						
							| 
									
										
										
										
											2017-05-26 03:38:27 +02:00
										 |  |  |     IPC_MESSAGE_HANDLER(AtomAutofillFrameMsg_AcceptSuggestion, | 
					
						
							| 
									
										
										
										
											2018-04-17 21:55:30 -04:00
										 |  |  |                         OnAcceptSuggestion) | 
					
						
							| 
									
										
										
										
											2017-05-19 21:35:13 +02:00
										 |  |  |     IPC_MESSAGE_UNHANDLED(handled = false) | 
					
						
							|  |  |  |   IPC_END_MESSAGE_MAP() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return handled; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool AutofillAgent::IsUserGesture() const { | 
					
						
							| 
									
										
										
										
											2019-01-12 06:30:43 +05:30
										 |  |  |   return blink::WebUserGestureIndicator::IsProcessingUserGesture( | 
					
						
							|  |  |  |       render_frame()->GetWebFrame()); | 
					
						
							| 
									
										
										
										
											2017-05-19 21:35:13 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AutofillAgent::HidePopup() { | 
					
						
							| 
									
										
										
										
											2017-05-26 03:38:27 +02:00
										 |  |  |   Send(new AtomAutofillFrameHostMsg_HidePopup(render_frame()->GetRoutingID())); | 
					
						
							| 
									
										
										
										
											2017-05-19 21:35:13 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-17 21:55:30 -04:00
										 |  |  | void AutofillAgent::ShowPopup(const blink::WebFormControlElement& element, | 
					
						
							|  |  |  |                               const std::vector<base::string16>& values, | 
					
						
							|  |  |  |                               const std::vector<base::string16>& labels) { | 
					
						
							| 
									
										
										
										
											2017-05-19 21:52:18 +02:00
										 |  |  |   gfx::RectF bounds = | 
					
						
							| 
									
										
										
										
											2018-04-17 21:55:30 -04:00
										 |  |  |       render_frame()->GetRenderView()->ElementBoundsInWindow(element); | 
					
						
							|  |  |  |   Send(new AtomAutofillFrameHostMsg_ShowPopup(render_frame()->GetRoutingID(), | 
					
						
							|  |  |  |                                               bounds, values, labels)); | 
					
						
							| 
									
										
										
										
											2017-05-19 21:35:13 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-20 04:21:11 +02:00
										 |  |  | void AutofillAgent::OnAcceptSuggestion(base::string16 suggestion) { | 
					
						
							| 
									
										
										
										
											2017-06-16 23:42:33 +03:00
										 |  |  |   auto element = render_frame()->GetWebFrame()->GetDocument().FocusedElement(); | 
					
						
							|  |  |  |   if (element.IsFormControlElement()) { | 
					
						
							| 
									
										
										
										
											2017-09-10 22:11:56 +02:00
										 |  |  |     ToWebInputElement(&element)->SetAutofillValue( | 
					
						
							| 
									
										
										
										
											2018-04-17 21:55:30 -04:00
										 |  |  |         blink::WebString::FromUTF16(suggestion)); | 
					
						
							| 
									
										
										
										
											2017-05-20 04:21:11 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AutofillAgent::DoFocusChangeComplete() { | 
					
						
							| 
									
										
										
										
											2017-06-16 23:42:33 +03:00
										 |  |  |   auto element = render_frame()->GetWebFrame()->GetDocument().FocusedElement(); | 
					
						
							|  |  |  |   if (element.IsNull() || !element.IsFormControlElement()) | 
					
						
							| 
									
										
										
										
											2017-05-20 04:21:11 +02:00
										 |  |  |     return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (focused_node_was_last_clicked_ && was_focused_before_now_) { | 
					
						
							|  |  |  |     ShowSuggestionsOptions options; | 
					
						
							|  |  |  |     options.autofill_on_empty_values = true; | 
					
						
							| 
									
										
										
										
											2018-04-17 15:41:47 -07:00
										 |  |  |     auto* input_element = ToWebInputElement(&element); | 
					
						
							| 
									
										
										
										
											2017-05-21 19:55:19 +02:00
										 |  |  |     if (input_element) | 
					
						
							|  |  |  |       ShowSuggestions(*input_element, options); | 
					
						
							| 
									
										
										
										
											2017-05-20 04:21:11 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   was_focused_before_now_ = true; | 
					
						
							|  |  |  |   focused_node_was_last_clicked_ = false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-19 21:52:18 +02:00
										 |  |  | }  // namespace atom
 |