Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(233)

Side by Side Diff: webkit/glue/editor_client_impl.cc

Issue 11479: New take at implementing autofill using the editor client API (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 12 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « webkit/glue/editor_client_impl.h ('k') | webkit/glue/form_autocomplete_listener.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 // The Mac interface forwards most of these commands to the application layer, 5 // The Mac interface forwards most of these commands to the application layer,
6 // and I'm not really sure what to do about most of them. 6 // and I'm not really sure what to do about most of them.
7 7
8 #include "config.h" 8 #include "config.h"
9 9
10 #include "base/compiler_specific.h" 10 #include "base/compiler_specific.h"
11 11
12 MSVC_PUSH_WARNING_LEVEL(0); 12 MSVC_PUSH_WARNING_LEVEL(0);
13 #include "Document.h" 13 #include "Document.h"
14 #include "EditCommand.h" 14 #include "EditCommand.h"
15 #include "Editor.h" 15 #include "Editor.h"
16 #include "EventHandler.h" 16 #include "EventHandler.h"
17 #include "EventNames.h" 17 #include "EventNames.h"
18 #include "KeyboardCodes.h" 18 #include "KeyboardCodes.h"
19 #include "HTMLInputElement.h" 19 #include "HTMLInputElement.h"
20 #include "HTMLNames.h"
20 #include "Frame.h" 21 #include "Frame.h"
21 #include "KeyboardEvent.h" 22 #include "KeyboardEvent.h"
22 #include "PlatformKeyboardEvent.h" 23 #include "PlatformKeyboardEvent.h"
23 #include "PlatformString.h" 24 #include "PlatformString.h"
24 MSVC_POP_WARNING(); 25 MSVC_POP_WARNING();
25 26
26 #undef LOG 27 #undef LOG
28 #include "base/message_loop.h"
27 #include "base/string_util.h" 29 #include "base/string_util.h"
28 #include "webkit/glue/editor_client_impl.h" 30 #include "webkit/glue/editor_client_impl.h"
29 #include "webkit/glue/glue_util.h" 31 #include "webkit/glue/glue_util.h"
30 #include "webkit/glue/webkit_glue.h" 32 #include "webkit/glue/webkit_glue.h"
31 #include "webkit/glue/webview.h" 33 #include "webkit/glue/webview.h"
32 #include "webkit/glue/webview_impl.h" 34 #include "webkit/glue/webview_impl.h"
33 35
34 // Arbitrary depth limit for the undo stack, to keep it from using 36 // Arbitrary depth limit for the undo stack, to keep it from using
35 // unbounded memory. This is the maximum number of distinct undoable 37 // unbounded memory. This is the maximum number of distinct undoable
36 // actions -- unbroken stretches of typed characters are coalesced 38 // actions -- unbroken stretches of typed characters are coalesced
37 // into a single action. 39 // into a single action.
38 static const size_t kMaximumUndoStackDepth = 1000; 40 static const size_t kMaximumUndoStackDepth = 1000;
39 41
42 // The size above which we stop triggering autofill for an input text field
43 // (so to avoid sending long strings through IPC).
44 static const size_t kMaximumTextSizeForAutofill = 1000;
45
40 namespace { 46 namespace {
41 47
42 // Record an editor command from the keyDownEntries[] below. We ignore the 48 // Record an editor command from the keyDownEntries[] below. We ignore the
43 // Move* and Insert* commands because they're not that interesting. 49 // Move* and Insert* commands because they're not that interesting.
44 void MaybeRecordCommand(WebViewDelegate* d, const char* command_name) { 50 void MaybeRecordCommand(WebViewDelegate* d, const char* command_name) {
45 if (!d) 51 if (!d)
46 return; 52 return;
47 53
48 const char* move_prefix = "Move"; 54 const char* move_prefix = "Move";
49 const char* insert_prefix = "Insert"; 55 const char* insert_prefix = "Insert";
50 const char* delete_prefix = "Delete"; 56 const char* delete_prefix = "Delete";
51 // Ignore all the Move*, Insert*, and Delete* commands. 57 // Ignore all the Move*, Insert*, and Delete* commands.
52 if (0 == strncmp(command_name, move_prefix, sizeof(move_prefix)) || 58 if (0 == strncmp(command_name, move_prefix, sizeof(move_prefix)) ||
53 0 == strncmp(command_name, insert_prefix, sizeof(insert_prefix)) || 59 0 == strncmp(command_name, insert_prefix, sizeof(insert_prefix)) ||
54 0 == strncmp(command_name, delete_prefix, sizeof(delete_prefix))) { 60 0 == strncmp(command_name, delete_prefix, sizeof(delete_prefix))) {
55 return; 61 return;
56 } 62 }
57 d->UserMetricsRecordComputedAction(UTF8ToWide(command_name)); 63 d->UserMetricsRecordComputedAction(UTF8ToWide(command_name));
58 } 64 }
59 65
60 } 66 }
61 67
62 EditorClientImpl::EditorClientImpl(WebView* web_view) 68 EditorClientImpl::EditorClientImpl(WebView* web_view)
63 : web_view_(static_cast<WebViewImpl*>(web_view)), 69 : web_view_(static_cast<WebViewImpl*>(web_view)),
64 use_editor_delegate_(false), 70 use_editor_delegate_(false),
65 in_redo_(false), 71 in_redo_(false),
66 preserve_(false), 72 backspace_pressed_(false),
67 pending_inline_autocompleted_element_(NULL) { 73 // Don't complain about using "this" in initializer list.
74 MSVC_PUSH_DISABLE_WARNING(4355)
75 autofill_factory_(this) {
76 MSVC_POP_WARNING()
68 } 77 }
69 78
70 EditorClientImpl::~EditorClientImpl() { 79 EditorClientImpl::~EditorClientImpl() {
71 } 80 }
72 81
73 void EditorClientImpl::pageDestroyed() { 82 void EditorClientImpl::pageDestroyed() {
74 // Called by the Page (which owns the editor client) when the page is going 83 // Called by the Page (which owns the editor client) when the page is going
75 // away. This should cause us to delete ourselves, which is stupid. The page 84 // away. This should cause us to delete ourselves, which is stupid. The page
76 // should just delete us when it's going away. Oh well. 85 // should just delete us when it's going away. Oh well.
77 delete this; 86 delete this;
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
175 184
176 bool EditorClientImpl::shouldDeleteRange(WebCore::Range* range) { 185 bool EditorClientImpl::shouldDeleteRange(WebCore::Range* range) {
177 if (use_editor_delegate_) { 186 if (use_editor_delegate_) {
178 WebViewDelegate* d = web_view_->delegate(); 187 WebViewDelegate* d = web_view_->delegate();
179 if (d) 188 if (d)
180 return d->ShouldDeleteRange(web_view_, Describe(range)); 189 return d->ShouldDeleteRange(web_view_, Describe(range));
181 } 190 }
182 return true; 191 return true;
183 } 192 }
184 193
185 void EditorClientImpl::PreserveSelection() {
186 preserve_ = true;
187 }
188
189 bool EditorClientImpl::shouldChangeSelectedRange(WebCore::Range* fromRange, 194 bool EditorClientImpl::shouldChangeSelectedRange(WebCore::Range* fromRange,
190 WebCore::Range* toRange, 195 WebCore::Range* toRange,
191 WebCore::EAffinity affinity, 196 WebCore::EAffinity affinity,
192 bool stillSelecting) { 197 bool stillSelecting) {
193 if (use_editor_delegate_) { 198 if (use_editor_delegate_) {
194 WebViewDelegate* d = web_view_->delegate(); 199 WebViewDelegate* d = web_view_->delegate();
195 if (d) { 200 if (d) {
196 return d->ShouldChangeSelectedRange(web_view_, 201 return d->ShouldChangeSelectedRange(web_view_,
197 Describe(fromRange), 202 Describe(fromRange),
198 Describe(toRange), 203 Describe(toRange),
199 Describe(affinity), 204 Describe(affinity),
200 stillSelecting); 205 stillSelecting);
201 } 206 }
202 } 207 }
203 // Have we been told to preserve the selection?
204 // (See comments for PreserveSelection in header).
205 if (preserve_) {
206 preserve_ = false;
207 return false;
208 }
209 return true; 208 return true;
210 } 209 }
211 210
212 bool EditorClientImpl::shouldApplyStyle(WebCore::CSSStyleDeclaration* style, 211 bool EditorClientImpl::shouldApplyStyle(WebCore::CSSStyleDeclaration* style,
213 WebCore::Range* range) { 212 WebCore::Range* range) {
214 if (use_editor_delegate_) { 213 if (use_editor_delegate_) {
215 WebViewDelegate* d = web_view_->delegate(); 214 WebViewDelegate* d = web_view_->delegate();
216 if (d) 215 if (d)
217 return d->ShouldApplyStyle(web_view_, Describe(style), Describe(range)); 216 return d->ShouldApplyStyle(web_view_, Describe(style), Describe(range));
218 } 217 }
(...skipping 16 matching lines...) Expand all
235 234
236 void EditorClientImpl::respondToChangedSelection() { 235 void EditorClientImpl::respondToChangedSelection() {
237 if (use_editor_delegate_) { 236 if (use_editor_delegate_) {
238 WebViewDelegate* d = web_view_->delegate(); 237 WebViewDelegate* d = web_view_->delegate();
239 if (d) 238 if (d)
240 d->DidChangeSelection(); 239 d->DidChangeSelection();
241 } 240 }
242 } 241 }
243 242
244 void EditorClientImpl::respondToChangedContents() { 243 void EditorClientImpl::respondToChangedContents() {
245 // Ugly Hack. (See also webkit bug #16976).
246 // Something is wrong with webcore's focusController in that when selection
247 // is set to a region within a text element when handling an input event, if
248 // you don't re-focus the node then it only _APPEARS_ to have successfully
249 // changed the selection (the UI "looks" right) but in reality there is no
250 // selection of text. And to make matters worse, you can't just re-focus it,
251 // you have to re-focus it in code executed after the entire event listener
252 // loop has finished; and hence here we are. Oh, and to make matters worse,
253 // this sequence of events _doesn't_ happen when you debug through the code
254 // -- in that case it works perfectly fine -- because swapping to the debugger
255 // causes the refocusing we artificially reproduce here.
256 // TODO (timsteele): Clean this up once root webkit problem is identified and
257 // the bug is patched.
258 if (pending_inline_autocompleted_element_) {
259 pending_inline_autocompleted_element_->blur();
260 pending_inline_autocompleted_element_->focus();
261 pending_inline_autocompleted_element_ = NULL;
262 }
263
264 if (use_editor_delegate_) { 244 if (use_editor_delegate_) {
265 WebViewDelegate* d = web_view_->delegate(); 245 WebViewDelegate* d = web_view_->delegate();
266 if (d) 246 if (d)
267 d->DidChangeContents(); 247 d->DidChangeContents();
268 } 248 }
269 } 249 }
270 250
271 void EditorClientImpl::didEndEditing() { 251 void EditorClientImpl::didEndEditing() {
272 if (use_editor_delegate_) { 252 if (use_editor_delegate_) {
273 WebViewDelegate* d = web_view_->delegate(); 253 WebViewDelegate* d = web_view_->delegate();
(...skipping 340 matching lines...) Expand 10 before | Expand all | Expand 10 after
614 void EditorClientImpl::handleInputMethodKeydown(WebCore::KeyboardEvent* keyEvent ) { 594 void EditorClientImpl::handleInputMethodKeydown(WebCore::KeyboardEvent* keyEvent ) {
615 NOTIMPLEMENTED(); 595 NOTIMPLEMENTED();
616 } 596 }
617 597
618 void EditorClientImpl::textFieldDidBeginEditing(WebCore::Element*) { 598 void EditorClientImpl::textFieldDidBeginEditing(WebCore::Element*) {
619 } 599 }
620 600
621 void EditorClientImpl::textFieldDidEndEditing(WebCore::Element*) { 601 void EditorClientImpl::textFieldDidEndEditing(WebCore::Element*) {
622 // Notification that focus was lost. Be careful with this, it's also sent 602 // Notification that focus was lost. Be careful with this, it's also sent
623 // when the page is being closed. 603 // when the page is being closed.
604
605 // Cancel any pending DoAutofill calls.
606 autofill_factory_.RevokeAll();
624 } 607 }
625 608
626 void EditorClientImpl::textDidChangeInTextField(WebCore::Element* element) { 609 void EditorClientImpl::textDidChangeInTextField(WebCore::Element* element) {
627 // Track the element so we can blur/focus it in respondToChangedContents 610 DCHECK(element->hasLocalName(WebCore::HTMLNames::inputTag));
628 // so that the selected range is properly set. (See respondToChangedContents). 611
629 if (static_cast<WebCore::HTMLInputElement*>(element)->autofilled()) 612 // Cancel any pending DoAutofill calls.
630 pending_inline_autocompleted_element_ = element; 613 autofill_factory_.RevokeAll();
614
615 // Let's try to trigger autofill for that field, if applicable.
616 WebCore::HTMLInputElement* input_element =
617 static_cast<WebCore::HTMLInputElement*>(element);
618 if (!input_element->isEnabled() || !input_element->isTextField() ||
619 input_element->isPasswordField() || !input_element->autoComplete()) {
620 return;
621 }
622
623 std::wstring name = webkit_glue::StringToStdWString(input_element->name());
624 if (name.empty()) // If the field has no name, then we won't have values.
625 return;
626
627 // Don't attempt to autofill with values that are too large.
628 if (input_element->value().length() > kMaximumTextSizeForAutofill)
629 return;
630
631 // We post a task for doing the autofill as the caret position is not set
632 // properly at this point ( http://bugs.webkit.org/show_bug.cgi?id=16976)
633 // and we need it to determine whether or not to trigger autofill.
634 std::wstring value = webkit_glue::StringToStdWString(input_element->value());
635 MessageLoop::current()->PostTask(
636 FROM_HERE,
637 autofill_factory_.NewRunnableMethod(&EditorClientImpl::DoAutofill,
638 input_element,
639 backspace_pressed_));
631 } 640 }
632 641
633 bool EditorClientImpl::doTextFieldCommandFromEvent(WebCore::Element*, 642 void EditorClientImpl::DoAutofill(WebCore::HTMLInputElement* input_element,
634 WebCore::KeyboardEvent*) { 643 bool backspace) {
644 std::wstring value = webkit_glue::StringToStdWString(input_element->value());
645
646 // Only autofill when there is some text and the caret is at the end.
647 bool caret_at_end =
648 input_element->selectionStart() == input_element->selectionEnd() &&
649 input_element->selectionEnd() == value.length();
650 if (value.empty() || !caret_at_end)
651 return;
652
653 // First let's see if there is a password listener for that element.
654 WebFrameImpl* webframe =
655 WebFrameImpl::FromFrame(input_element->form()->document()->frame());
656 webkit_glue::PasswordAutocompleteListener* listener =
657 webframe->GetPasswordListener(input_element);
658 if (listener) {
659 if (backspace) // No autocomplete for password on backspace.
660 return;
661
662 listener->OnInlineAutocompleteNeeded(input_element, value);
663 return;
664 }
665
666 // Then trigger form autofill.
667 std::wstring name = webkit_glue::StringToStdWString(input_element->
668 name().string());
669 web_view_->delegate()->QueryFormFieldAutofill(name, value,
670 reinterpret_cast<int64>(input_element));
671 }
672
673 bool EditorClientImpl::doTextFieldCommandFromEvent(
674 WebCore::Element* element,
675 WebCore::KeyboardEvent* event) {
676 // Remember if backspace was pressed for the autofill. It is not clear how to
677 // find if backspace was pressed from textFieldDidBeginEditing and
678 // textDidChangeInTextField as when these methods are called the value of the
679 // input element already contains the type character.
680 backspace_pressed_ = (event->keyCode() == WebCore::VKEY_BACK);
681
635 // The Mac code appears to use this method as a hook to implement special 682 // The Mac code appears to use this method as a hook to implement special
636 // keyboard commands specific to Safari's auto-fill implementation. We 683 // keyboard commands specific to Safari's auto-fill implementation. We
637 // just return false to allow the default action. 684 // just return false to allow the default action.
638 return false; 685 return false;
639 } 686 }
640 687
641 void EditorClientImpl::textWillBeDeletedInTextField(WebCore::Element*) { 688 void EditorClientImpl::textWillBeDeletedInTextField(WebCore::Element*) {
642 } 689 }
643 690
644 void EditorClientImpl::textDidChangeInTextArea(WebCore::Element*) { 691 void EditorClientImpl::textDidChangeInTextArea(WebCore::Element*) {
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after
793 return L"(UNKNOWN AFFINITY)"; 840 return L"(UNKNOWN AFFINITY)";
794 } 841 }
795 842
796 std::wstring EditorClientImpl::Describe(WebCore::CSSStyleDeclaration* style) { 843 std::wstring EditorClientImpl::Describe(WebCore::CSSStyleDeclaration* style) {
797 // TODO(pamg): Implement me. It's not clear what WebKit produces for this 844 // TODO(pamg): Implement me. It's not clear what WebKit produces for this
798 // (their [style description] method), and none of the layout tests provide 845 // (their [style description] method), and none of the layout tests provide
799 // an example. But because none of them use it, it's not yet important. 846 // an example. But because none of them use it, it's not yet important.
800 return std::wstring(); 847 return std::wstring();
801 } 848 }
802 849
OLDNEW
« no previous file with comments | « webkit/glue/editor_client_impl.h ('k') | webkit/glue/form_autocomplete_listener.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698