Index: webkit/glue/editor_client_impl.cc |
=================================================================== |
--- webkit/glue/editor_client_impl.cc (revision 5576) |
+++ webkit/glue/editor_client_impl.cc (working copy) |
@@ -17,6 +17,7 @@ |
#include "EventNames.h" |
#include "KeyboardCodes.h" |
#include "HTMLInputElement.h" |
+#include "HTMLNames.h" |
#include "Frame.h" |
#include "KeyboardEvent.h" |
#include "PlatformKeyboardEvent.h" |
@@ -24,6 +25,7 @@ |
MSVC_POP_WARNING(); |
#undef LOG |
+#include "base/message_loop.h" |
#include "base/string_util.h" |
#include "webkit/glue/editor_client_impl.h" |
#include "webkit/glue/glue_util.h" |
@@ -37,6 +39,10 @@ |
// into a single action. |
static const size_t kMaximumUndoStackDepth = 1000; |
+// The size above which we stop triggering autofill for an input text field |
+// (so to avoid sending long strings through IPC). |
+static const size_t kMaximumTextSizeForAutofill = 1000; |
+ |
namespace { |
// Record an editor command from the keyDownEntries[] below. We ignore the |
@@ -63,8 +69,11 @@ |
: web_view_(static_cast<WebViewImpl*>(web_view)), |
use_editor_delegate_(false), |
in_redo_(false), |
- preserve_(false), |
- pending_inline_autocompleted_element_(NULL) { |
+ backspace_pressed_(false), |
+// Don't complain about using "this" in initializer list. |
+MSVC_PUSH_DISABLE_WARNING(4355) |
+ autofill_factory_(this) { |
+MSVC_POP_WARNING() |
} |
EditorClientImpl::~EditorClientImpl() { |
@@ -182,10 +191,6 @@ |
return true; |
} |
-void EditorClientImpl::PreserveSelection() { |
- preserve_ = true; |
-} |
- |
bool EditorClientImpl::shouldChangeSelectedRange(WebCore::Range* fromRange, |
WebCore::Range* toRange, |
WebCore::EAffinity affinity, |
@@ -200,12 +205,6 @@ |
stillSelecting); |
} |
} |
- // Have we been told to preserve the selection? |
- // (See comments for PreserveSelection in header). |
- if (preserve_) { |
- preserve_ = false; |
- return false; |
- } |
return true; |
} |
@@ -242,25 +241,6 @@ |
} |
void EditorClientImpl::respondToChangedContents() { |
- // Ugly Hack. (See also webkit bug #16976). |
- // Something is wrong with webcore's focusController in that when selection |
- // is set to a region within a text element when handling an input event, if |
- // you don't re-focus the node then it only _APPEARS_ to have successfully |
- // changed the selection (the UI "looks" right) but in reality there is no |
- // selection of text. And to make matters worse, you can't just re-focus it, |
- // you have to re-focus it in code executed after the entire event listener |
- // loop has finished; and hence here we are. Oh, and to make matters worse, |
- // this sequence of events _doesn't_ happen when you debug through the code |
- // -- in that case it works perfectly fine -- because swapping to the debugger |
- // causes the refocusing we artificially reproduce here. |
- // TODO (timsteele): Clean this up once root webkit problem is identified and |
- // the bug is patched. |
- if (pending_inline_autocompleted_element_) { |
- pending_inline_autocompleted_element_->blur(); |
- pending_inline_autocompleted_element_->focus(); |
- pending_inline_autocompleted_element_ = NULL; |
- } |
- |
if (use_editor_delegate_) { |
WebViewDelegate* d = web_view_->delegate(); |
if (d) |
@@ -621,17 +601,84 @@ |
void EditorClientImpl::textFieldDidEndEditing(WebCore::Element*) { |
// Notification that focus was lost. Be careful with this, it's also sent |
// when the page is being closed. |
+ |
+ // Cancel any pending DoAutofill calls. |
+ autofill_factory_.RevokeAll(); |
} |
void EditorClientImpl::textDidChangeInTextField(WebCore::Element* element) { |
- // Track the element so we can blur/focus it in respondToChangedContents |
- // so that the selected range is properly set. (See respondToChangedContents). |
- if (static_cast<WebCore::HTMLInputElement*>(element)->autofilled()) |
- pending_inline_autocompleted_element_ = element; |
+ DCHECK(element->hasLocalName(WebCore::HTMLNames::inputTag)); |
+ |
+ // Cancel any pending DoAutofill calls. |
+ autofill_factory_.RevokeAll(); |
+ |
+ // Let's try to trigger autofill for that field, if applicable. |
+ WebCore::HTMLInputElement* input_element = |
+ static_cast<WebCore::HTMLInputElement*>(element); |
+ if (!input_element->isEnabled() || !input_element->isTextField() || |
+ input_element->isPasswordField() || !input_element->autoComplete()) { |
+ return; |
+ } |
+ |
+ std::wstring name = webkit_glue::StringToStdWString(input_element->name()); |
+ if (name.empty()) // If the field has no name, then we won't have values. |
+ return; |
+ |
+ // Don't attempt to autofill with values that are too large. |
+ if (input_element->value().length() > kMaximumTextSizeForAutofill) |
+ return; |
+ |
+ // We post a task for doing the autofill as the caret position is not set |
+ // properly at this point ( http://bugs.webkit.org/show_bug.cgi?id=16976) |
+ // and we need it to determine whether or not to trigger autofill. |
+ std::wstring value = webkit_glue::StringToStdWString(input_element->value()); |
+ MessageLoop::current()->PostTask( |
+ FROM_HERE, |
+ autofill_factory_.NewRunnableMethod(&EditorClientImpl::DoAutofill, |
+ input_element, |
+ backspace_pressed_)); |
} |
-bool EditorClientImpl::doTextFieldCommandFromEvent(WebCore::Element*, |
- WebCore::KeyboardEvent*) { |
+void EditorClientImpl::DoAutofill(WebCore::HTMLInputElement* input_element, |
+ bool backspace) { |
+ std::wstring value = webkit_glue::StringToStdWString(input_element->value()); |
+ |
+ // Only autofill when there is some text and the caret is at the end. |
+ bool caret_at_end = |
+ input_element->selectionStart() == input_element->selectionEnd() && |
+ input_element->selectionEnd() == value.length(); |
+ if (value.empty() || !caret_at_end) |
+ return; |
+ |
+ // First let's see if there is a password listener for that element. |
+ WebFrameImpl* webframe = |
+ WebFrameImpl::FromFrame(input_element->form()->document()->frame()); |
+ webkit_glue::PasswordAutocompleteListener* listener = |
+ webframe->GetPasswordListener(input_element); |
+ if (listener) { |
+ if (backspace) // No autocomplete for password on backspace. |
+ return; |
+ |
+ listener->OnInlineAutocompleteNeeded(input_element, value); |
+ return; |
+ } |
+ |
+ // Then trigger form autofill. |
+ std::wstring name = webkit_glue::StringToStdWString(input_element-> |
+ name().string()); |
+ web_view_->delegate()->QueryFormFieldAutofill(name, value, |
+ reinterpret_cast<int64>(input_element)); |
+} |
+ |
+bool EditorClientImpl::doTextFieldCommandFromEvent( |
+ WebCore::Element* element, |
+ WebCore::KeyboardEvent* event) { |
+ // Remember if backspace was pressed for the autofill. It is not clear how to |
+ // find if backspace was pressed from textFieldDidBeginEditing and |
+ // textDidChangeInTextField as when these methods are called the value of the |
+ // input element already contains the type character. |
+ backspace_pressed_ = (event->keyCode() == WebCore::VKEY_BACK); |
+ |
// The Mac code appears to use this method as a hook to implement special |
// keyboard commands specific to Safari's auto-fill implementation. We |
// just return false to allow the default action. |