| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |