summaryrefslogtreecommitdiffstats
path: root/webkit/glue/editor_client_impl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'webkit/glue/editor_client_impl.cc')
-rw-r--r--webkit/glue/editor_client_impl.cc121
1 files changed, 84 insertions, 37 deletions
diff --git a/webkit/glue/editor_client_impl.cc b/webkit/glue/editor_client_impl.cc
index 722d5fb..27c2657 100644
--- a/webkit/glue/editor_client_impl.cc
+++ b/webkit/glue/editor_client_impl.cc
@@ -17,6 +17,7 @@ MSVC_PUSH_WARNING_LEVEL(0);
#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_PUSH_WARNING_LEVEL(0);
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 @@ MSVC_POP_WARNING();
// 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 @@ EditorClientImpl::EditorClientImpl(WebView* web_view)
: 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 @@ bool EditorClientImpl::shouldDeleteRange(WebCore::Range* range) {
return true;
}
-void EditorClientImpl::PreserveSelection() {
- preserve_ = true;
-}
-
bool EditorClientImpl::shouldChangeSelectedRange(WebCore::Range* fromRange,
WebCore::Range* toRange,
WebCore::EAffinity affinity,
@@ -200,12 +205,6 @@ bool EditorClientImpl::shouldChangeSelectedRange(WebCore::Range* fromRange,
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::respondToChangedSelection() {
}
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::textFieldDidBeginEditing(WebCore::Element*) {
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_));
+}
+
+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() == static_cast<int>(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*,
- WebCore::KeyboardEvent*) {
+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.