OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2006, 2007, 2008, 2011 Apple Inc. All rights reserved. | 2 * Copyright (C) 2006, 2007, 2008, 2011 Apple Inc. All rights reserved. |
3 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) | 3 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) |
4 * | 4 * |
5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
6 * modification, are permitted provided that the following conditions | 6 * modification, are permitted provided that the following conditions |
7 * are met: | 7 * are met: |
8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
77 // replaced) or the new text (text to be inserted) is empty. | 77 // replaced) or the new text (text to be inserted) is empty. |
78 if (frame.selectedText().isEmpty() || newText.isEmpty()) | 78 if (frame.selectedText().isEmpty() || newText.isEmpty()) |
79 return false; | 79 return false; |
80 | 80 |
81 return true; | 81 return true; |
82 } | 82 } |
83 | 83 |
84 // Used to insert/replace text during composition update and confirm | 84 // Used to insert/replace text during composition update and confirm |
85 // composition. | 85 // composition. |
86 // Procedure: | 86 // Procedure: |
87 // 1. Fire 'beforeinput' event for (TODO(chongz): deleted composed text) and | 87 // 1. Fire 'compositionupdate' event |
88 // inserted text | 88 // 2. Use TextEvent or TypingCommand to modify DOM, which will fire |
89 // 2. Fire 'compositionupdate' event | 89 // 'beforeinput' and 'input' |
90 // 3. Fire TextEvent and modify DOM | |
91 // TODO(chongz): 4. Fire 'input' event | |
92 void insertTextDuringCompositionWithEvents( | 90 void insertTextDuringCompositionWithEvents( |
93 LocalFrame& frame, | 91 LocalFrame& frame, |
94 const String& text, | 92 const String& text, |
95 TypingCommand::Options options, | 93 TypingCommand::Options options, |
96 TypingCommand::TextCompositionType compositionType) { | 94 TypingCommand::TextCompositionType compositionType) { |
97 DCHECK(compositionType == | 95 DCHECK(compositionType == |
98 TypingCommand::TextCompositionType::TextCompositionUpdate || | 96 TypingCommand::TextCompositionType::TextCompositionUpdate || |
99 compositionType == | 97 compositionType == |
100 TypingCommand::TextCompositionType::TextCompositionConfirm || | 98 TypingCommand::TextCompositionType::TextCompositionConfirm || |
101 compositionType == | 99 compositionType == |
102 TypingCommand::TextCompositionType::TextCompositionCancel) | 100 TypingCommand::TextCompositionType::TextCompositionCancel) |
103 << "compositionType should be TextCompositionUpdate or " | 101 << "compositionType should be TextCompositionUpdate or " |
104 "TextCompositionConfirm or TextCompositionCancel, but got " | 102 "TextCompositionConfirm or TextCompositionCancel, but got " |
105 << static_cast<int>(compositionType); | 103 << static_cast<int>(compositionType); |
106 if (!frame.document()) | 104 if (!frame.document()) |
107 return; | 105 return; |
108 | 106 |
109 Element* target = frame.document()->focusedElement(); | |
110 if (!target) | |
111 return; | |
112 | |
113 // TODO(chongz): Fire 'beforeinput' for the composed text being | |
114 // replaced/deleted. | |
115 | |
116 // Only the last confirmed text is cancelable. | |
117 InputEvent::EventCancelable beforeInputCancelable = | |
118 (compositionType == | |
119 TypingCommand::TextCompositionType::TextCompositionUpdate) | |
120 ? InputEvent::EventCancelable::NotCancelable | |
121 : InputEvent::EventCancelable::IsCancelable; | |
122 DispatchEventResult result = dispatchBeforeInputFromComposition( | |
123 target, InputEvent::InputType::InsertText, text, beforeInputCancelable); | |
124 | |
125 if (beforeInputCancelable == InputEvent::EventCancelable::IsCancelable && | |
126 result != DispatchEventResult::NotCanceled) | |
127 return; | |
128 | |
129 // 'beforeinput' event handler may destroy document. | |
130 if (!frame.document()) | |
131 return; | |
132 | |
133 dispatchCompositionUpdateEvent(frame, text); | 107 dispatchCompositionUpdateEvent(frame, text); |
134 // 'compositionupdate' event handler may destroy document. | 108 // 'compositionupdate' event handler may destroy document. |
135 if (!frame.document()) | 109 if (!frame.document() || frame.document()->frame() != &frame) |
136 return; | 110 return; |
137 | 111 |
138 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets | 112 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets |
139 // needs to be audited. see http://crbug.com/590369 for more details. | 113 // needs to be audited. see http://crbug.com/590369 for more details. |
140 frame.document()->updateStyleAndLayoutIgnorePendingStylesheets(); | 114 frame.document()->updateStyleAndLayoutIgnorePendingStylesheets(); |
141 | 115 |
142 const bool isIncrementalInsertion = needsIncrementalInsertion(frame, text); | 116 const bool isIncrementalInsertion = needsIncrementalInsertion(frame, text); |
143 | 117 |
144 switch (compositionType) { | 118 switch (compositionType) { |
145 case TypingCommand::TextCompositionType::TextCompositionUpdate: | 119 case TypingCommand::TextCompositionType::TextCompositionUpdate: |
146 case TypingCommand::TextCompositionType::TextCompositionConfirm: | 120 case TypingCommand::TextCompositionType::TextCompositionConfirm: |
147 TypingCommand::insertText( | 121 TypingCommand::insertText( |
148 *frame.document(), EditCommandSource::kMenuOrKeyBinding, text, | 122 *frame.document(), EditCommandSource::kMenuOrKeyBinding, text, |
149 options, compositionType, isIncrementalInsertion); | 123 options, compositionType, isIncrementalInsertion); |
150 break; | 124 break; |
151 case TypingCommand::TextCompositionType::TextCompositionCancel: | 125 case TypingCommand::TextCompositionType::TextCompositionCancel: |
152 // TODO(chongz): Use TypingCommand::insertText after TextEvent was | 126 // TODO(chongz): Use TypingCommand::insertText after TextEvent was |
153 // removed. (Removed from spec since 2012) | 127 // removed. (Removed from spec since 2012) |
154 // See TextEvent.idl. | 128 // See TextEvent.idl. |
155 frame.eventHandler().handleTextInputEvent(text, 0, | 129 frame.eventHandler().handleTextInputEvent(text, 0, |
156 TextEventInputComposition); | 130 TextEventInputComposition); |
157 break; | 131 break; |
158 default: | 132 default: |
159 NOTREACHED(); | 133 NOTREACHED(); |
160 } | 134 } |
161 // TODO(chongz): Fire 'input' event. | |
162 } | 135 } |
163 | 136 |
164 AtomicString getInputModeAttribute(Element* element) { | 137 AtomicString getInputModeAttribute(Element* element) { |
165 if (!element) | 138 if (!element) |
166 return AtomicString(); | 139 return AtomicString(); |
167 | 140 |
168 bool queryAttribute = false; | 141 bool queryAttribute = false; |
169 if (isHTMLInputElement(*element)) { | 142 if (isHTMLInputElement(*element)) { |
170 queryAttribute = toHTMLInputElement(*element).supportsInputModeAttribute(); | 143 queryAttribute = toHTMLInputElement(*element).supportsInputModeAttribute(); |
171 } else if (isHTMLTextAreaElement(*element)) { | 144 } else if (isHTMLTextAreaElement(*element)) { |
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
345 if (!moveCaret(absoluteCaretPosition)) | 318 if (!moveCaret(absoluteCaretPosition)) |
346 return false; | 319 return false; |
347 | 320 |
348 // No DOM update after 'compositionend'. | 321 // No DOM update after 'compositionend'. |
349 dispatchCompositionEndEvent(frame(), text); | 322 dispatchCompositionEndEvent(frame(), text); |
350 | 323 |
351 return true; | 324 return true; |
352 } | 325 } |
353 | 326 |
354 bool InputMethodController::insertText(const String& text) { | 327 bool InputMethodController::insertText(const String& text) { |
355 if (dispatchBeforeInputInsertText(document().focusedElement(), text) != | |
356 DispatchEventResult::NotCanceled) | |
357 return false; | |
358 editor().insertText(text, 0); | 328 editor().insertText(text, 0); |
359 return true; | 329 return true; |
360 } | 330 } |
361 | 331 |
362 bool InputMethodController::insertTextAndMoveCaret(const String& text, | 332 bool InputMethodController::insertTextAndMoveCaret(const String& text, |
363 int relativeCaretPosition) { | 333 int relativeCaretPosition) { |
364 PlainTextRange selectionRange = getSelectionOffsets(); | 334 PlainTextRange selectionRange = getSelectionOffsets(); |
365 if (selectionRange.isNull()) | 335 if (selectionRange.isNull()) |
366 return false; | 336 return false; |
367 int textStart = selectionRange.start(); | 337 int textStart = selectionRange.start(); |
(...skipping 12 matching lines...) Expand all Loading... |
380 if (!hasComposition()) | 350 if (!hasComposition()) |
381 return; | 351 return; |
382 | 352 |
383 Editor::RevealSelectionScope revealSelectionScope(&editor()); | 353 Editor::RevealSelectionScope revealSelectionScope(&editor()); |
384 | 354 |
385 if (frame().selection().isNone()) | 355 if (frame().selection().isNone()) |
386 return; | 356 return; |
387 | 357 |
388 clear(); | 358 clear(); |
389 | 359 |
390 // TODO(chongz): Figure out which InputType should we use here. | |
391 dispatchBeforeInputFromComposition( | |
392 document().focusedElement(), | |
393 InputEvent::InputType::DeleteComposedCharacterBackward, nullAtom, | |
394 InputEvent::EventCancelable::NotCancelable); | |
395 dispatchCompositionUpdateEvent(frame(), emptyString()); | 360 dispatchCompositionUpdateEvent(frame(), emptyString()); |
396 insertTextDuringCompositionWithEvents( | 361 insertTextDuringCompositionWithEvents( |
397 frame(), emptyString(), 0, | 362 frame(), emptyString(), 0, |
398 TypingCommand::TextCompositionType::TextCompositionCancel); | 363 TypingCommand::TextCompositionType::TextCompositionCancel); |
399 // Event handler might destroy document. | 364 // Event handler might destroy document. |
400 if (!isAvailable()) | 365 if (!isAvailable()) |
401 return; | 366 return; |
402 | 367 |
403 // An open typing command that disagrees about current selection would cause | 368 // An open typing command that disagrees about current selection would cause |
404 // issues with typing later on. | 369 // issues with typing later on. |
(...skipping 364 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
769 do { | 734 do { |
770 if (!setSelectionOffsets(PlainTextRange( | 735 if (!setSelectionOffsets(PlainTextRange( |
771 std::max(static_cast<int>(selectionOffsets.start()) - before, 0), | 736 std::max(static_cast<int>(selectionOffsets.start()) - before, 0), |
772 selectionOffsets.end() + after))) | 737 selectionOffsets.end() + after))) |
773 return; | 738 return; |
774 if (before == 0) | 739 if (before == 0) |
775 break; | 740 break; |
776 ++before; | 741 ++before; |
777 } while (frame().selection().start() == frame().selection().end() && | 742 } while (frame().selection().start() == frame().selection().end() && |
778 before <= static_cast<int>(selectionOffsets.start())); | 743 before <= static_cast<int>(selectionOffsets.start())); |
779 // TODO(chongz): Find a way to distinguish Forward and Backward. | |
780 dispatchBeforeInputEditorCommand( | |
781 document().focusedElement(), InputEvent::InputType::DeleteContentBackward, | |
782 new RangeVector(1, m_frame->selection().firstRange())); | |
783 TypingCommand::deleteSelection(document(), | 744 TypingCommand::deleteSelection(document(), |
784 EditCommandSource::kMenuOrKeyBinding); | 745 EditCommandSource::kMenuOrKeyBinding); |
785 } | 746 } |
786 | 747 |
787 // TODO(yabinh): We should reduce the number of selectionchange events. | 748 // TODO(yabinh): We should reduce the number of selectionchange events. |
788 void InputMethodController::deleteSurroundingText(int before, int after) { | 749 void InputMethodController::deleteSurroundingText(int before, int after) { |
789 if (!editor().canEdit()) | 750 if (!editor().canEdit()) |
790 return; | 751 return; |
791 const PlainTextRange selectionOffsets(getSelectionOffsets()); | 752 const PlainTextRange selectionOffsets(getSelectionOffsets()); |
792 if (selectionOffsets.isNull()) | 753 if (selectionOffsets.isNull()) |
(...skipping 270 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1063 frame().chromeClient().resetInputMethod(); | 1024 frame().chromeClient().resetInputMethod(); |
1064 } | 1025 } |
1065 | 1026 |
1066 DEFINE_TRACE(InputMethodController) { | 1027 DEFINE_TRACE(InputMethodController) { |
1067 visitor->trace(m_frame); | 1028 visitor->trace(m_frame); |
1068 visitor->trace(m_compositionRange); | 1029 visitor->trace(m_compositionRange); |
1069 SynchronousMutationObserver::trace(visitor); | 1030 SynchronousMutationObserver::trace(visitor); |
1070 } | 1031 } |
1071 | 1032 |
1072 } // namespace blink | 1033 } // namespace blink |
OLD | NEW |