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 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
58 void dispatchCompositionEndEvent(LocalFrame& frame, const String& text) { | 58 void dispatchCompositionEndEvent(LocalFrame& frame, const String& text) { |
59 Element* target = frame.document()->focusedElement(); | 59 Element* target = frame.document()->focusedElement(); |
60 if (!target) | 60 if (!target) |
61 return; | 61 return; |
62 | 62 |
63 CompositionEvent* event = CompositionEvent::create( | 63 CompositionEvent* event = CompositionEvent::create( |
64 EventTypeNames::compositionend, frame.domWindow(), text); | 64 EventTypeNames::compositionend, frame.domWindow(), text); |
65 target->dispatchEvent(event); | 65 target->dispatchEvent(event); |
66 } | 66 } |
67 | 67 |
68 // Used to insert/replace text during composition update and confirm composition
. | 68 // Used to insert/replace text during composition update and confirm |
| 69 // composition. |
69 // Procedure: | 70 // Procedure: |
70 // 1. Fire 'beforeinput' event for (TODO(chongz): deleted composed text) and i
nserted text | 71 // 1. Fire 'beforeinput' event for (TODO(chongz): deleted composed text) and |
| 72 // inserted text |
71 // 2. Fire 'compositionupdate' event | 73 // 2. Fire 'compositionupdate' event |
72 // 3. Fire TextEvent and modify DOM | 74 // 3. Fire TextEvent and modify DOM |
73 // TODO(chongz): 4. Fire 'input' event | 75 // TODO(chongz): 4. Fire 'input' event |
74 void insertTextDuringCompositionWithEvents( | 76 void insertTextDuringCompositionWithEvents( |
75 LocalFrame& frame, | 77 LocalFrame& frame, |
76 const String& text, | 78 const String& text, |
77 TypingCommand::Options options, | 79 TypingCommand::Options options, |
78 TypingCommand::TextCompositionType compositionType) { | 80 TypingCommand::TextCompositionType compositionType) { |
79 DCHECK(compositionType == | 81 DCHECK(compositionType == |
80 TypingCommand::TextCompositionType::TextCompositionUpdate || | 82 TypingCommand::TextCompositionType::TextCompositionUpdate || |
81 compositionType == | 83 compositionType == |
82 TypingCommand::TextCompositionType::TextCompositionConfirm) | 84 TypingCommand::TextCompositionType::TextCompositionConfirm) |
83 << "compositionType should be TextCompositionUpdate or " | 85 << "compositionType should be TextCompositionUpdate or " |
84 "TextCompositionConfirm, but got " | 86 "TextCompositionConfirm, but got " |
85 << static_cast<int>(compositionType); | 87 << static_cast<int>(compositionType); |
86 if (!frame.document()) | 88 if (!frame.document()) |
87 return; | 89 return; |
88 | 90 |
89 Element* target = frame.document()->focusedElement(); | 91 Element* target = frame.document()->focusedElement(); |
90 if (!target) | 92 if (!target) |
91 return; | 93 return; |
92 | 94 |
93 // TODO(chongz): Fire 'beforeinput' for the composed text being replaced/delet
ed. | 95 // TODO(chongz): Fire 'beforeinput' for the composed text being |
| 96 // replaced/deleted. |
94 | 97 |
95 // Only the last confirmed text is cancelable. | 98 // Only the last confirmed text is cancelable. |
96 InputEvent::EventCancelable beforeInputCancelable = | 99 InputEvent::EventCancelable beforeInputCancelable = |
97 (compositionType == | 100 (compositionType == |
98 TypingCommand::TextCompositionType::TextCompositionUpdate) | 101 TypingCommand::TextCompositionType::TextCompositionUpdate) |
99 ? InputEvent::EventCancelable::NotCancelable | 102 ? InputEvent::EventCancelable::NotCancelable |
100 : InputEvent::EventCancelable::IsCancelable; | 103 : InputEvent::EventCancelable::IsCancelable; |
101 DispatchEventResult result = dispatchBeforeInputFromComposition( | 104 DispatchEventResult result = dispatchBeforeInputFromComposition( |
102 target, InputEvent::InputType::InsertText, text, beforeInputCancelable); | 105 target, InputEvent::InputType::InsertText, text, beforeInputCancelable); |
103 | 106 |
104 if (beforeInputCancelable == InputEvent::EventCancelable::IsCancelable && | 107 if (beforeInputCancelable == InputEvent::EventCancelable::IsCancelable && |
105 result != DispatchEventResult::NotCanceled) | 108 result != DispatchEventResult::NotCanceled) |
106 return; | 109 return; |
107 | 110 |
108 // 'beforeinput' event handler may destroy document. | 111 // 'beforeinput' event handler may destroy document. |
109 if (!frame.document()) | 112 if (!frame.document()) |
110 return; | 113 return; |
111 | 114 |
112 dispatchCompositionUpdateEvent(frame, text); | 115 dispatchCompositionUpdateEvent(frame, text); |
113 // 'compositionupdate' event handler may destroy document. | 116 // 'compositionupdate' event handler may destroy document. |
114 if (!frame.document()) | 117 if (!frame.document()) |
115 return; | 118 return; |
116 | 119 |
117 switch (compositionType) { | 120 switch (compositionType) { |
118 case TypingCommand::TextCompositionType::TextCompositionUpdate: | 121 case TypingCommand::TextCompositionType::TextCompositionUpdate: |
119 TypingCommand::insertText(*frame.document(), text, options, | 122 TypingCommand::insertText(*frame.document(), text, options, |
120 compositionType); | 123 compositionType); |
121 break; | 124 break; |
122 case TypingCommand::TextCompositionType::TextCompositionConfirm: | 125 case TypingCommand::TextCompositionType::TextCompositionConfirm: |
123 // TODO(chongz): Use TypingCommand::insertText after TextEvent was removed
. (Removed from spec since 2012) | 126 // TODO(chongz): Use TypingCommand::insertText after TextEvent was |
| 127 // removed. (Removed from spec since 2012) |
124 // See TextEvent.idl. | 128 // See TextEvent.idl. |
125 frame.eventHandler().handleTextInputEvent(text, 0, | 129 frame.eventHandler().handleTextInputEvent(text, 0, |
126 TextEventInputComposition); | 130 TextEventInputComposition); |
127 break; | 131 break; |
128 default: | 132 default: |
129 NOTREACHED(); | 133 NOTREACHED(); |
130 } | 134 } |
131 // TODO(chongz): Fire 'input' event. | 135 // TODO(chongz): Fire 'input' event. |
132 } | 136 } |
133 | 137 |
(...skipping 27 matching lines...) Expand all Loading... |
161 void InputMethodController::documentDetached() { | 165 void InputMethodController::documentDetached() { |
162 clear(); | 166 clear(); |
163 m_compositionRange = nullptr; | 167 m_compositionRange = nullptr; |
164 } | 168 } |
165 | 169 |
166 void InputMethodController::selectComposition() const { | 170 void InputMethodController::selectComposition() const { |
167 const EphemeralRange range = compositionEphemeralRange(); | 171 const EphemeralRange range = compositionEphemeralRange(); |
168 if (range.isNull()) | 172 if (range.isNull()) |
169 return; | 173 return; |
170 | 174 |
171 // The composition can start inside a composed character sequence, so we have
to override checks. | 175 // The composition can start inside a composed character sequence, so we have |
172 // See <http://bugs.webkit.org/show_bug.cgi?id=15781> | 176 // to override checks. See <http://bugs.webkit.org/show_bug.cgi?id=15781> |
173 VisibleSelection selection; | 177 VisibleSelection selection; |
174 selection.setWithoutValidation(range.startPosition(), range.endPosition()); | 178 selection.setWithoutValidation(range.startPosition(), range.endPosition()); |
175 frame().selection().setSelection(selection, 0); | 179 frame().selection().setSelection(selection, 0); |
176 } | 180 } |
177 | 181 |
178 bool InputMethodController::finishComposingText( | 182 bool InputMethodController::finishComposingText( |
179 ConfirmCompositionBehavior confirmBehavior) { | 183 ConfirmCompositionBehavior confirmBehavior) { |
180 if (!hasComposition()) | 184 if (!hasComposition()) |
181 return false; | 185 return false; |
182 | 186 |
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
378 // needs to be audited. see http://crbug.com/590369 for more details. | 382 // needs to be audited. see http://crbug.com/590369 for more details. |
379 frame().document()->updateStyleAndLayoutIgnorePendingStylesheets(); | 383 frame().document()->updateStyleAndLayoutIgnorePendingStylesheets(); |
380 | 384 |
381 int selectionOffsetsStart = static_cast<int>(getSelectionOffsets().start()); | 385 int selectionOffsetsStart = static_cast<int>(getSelectionOffsets().start()); |
382 int start = selectionOffsetsStart + selectionStart; | 386 int start = selectionOffsetsStart + selectionStart; |
383 int end = selectionOffsetsStart + selectionEnd; | 387 int end = selectionOffsetsStart + selectionEnd; |
384 PlainTextRange selectedRange = | 388 PlainTextRange selectedRange = |
385 createRangeForSelection(start, end, text.length()); | 389 createRangeForSelection(start, end, text.length()); |
386 | 390 |
387 // Dispatch an appropriate composition event to the focused node. | 391 // Dispatch an appropriate composition event to the focused node. |
388 // We check the composition status and choose an appropriate composition event
since this | 392 // We check the composition status and choose an appropriate composition event |
389 // function is used for three purposes: | 393 // since this function is used for three purposes: |
390 // 1. Starting a new composition. | 394 // 1. Starting a new composition. |
391 // Send a compositionstart and a compositionupdate event when this function
creates | 395 // Send a compositionstart and a compositionupdate event when this function |
392 // a new composition node, i.e. | 396 // creates a new composition node, i.e. !hasComposition() && |
393 // !hasComposition() && !text.isEmpty(). | 397 // !text.isEmpty(). |
394 // Sending a compositionupdate event at this time ensures that at least one | 398 // Sending a compositionupdate event at this time ensures that at least one |
395 // compositionupdate event is dispatched. | 399 // compositionupdate event is dispatched. |
396 // 2. Updating the existing composition node. | 400 // 2. Updating the existing composition node. |
397 // Send a compositionupdate event when this function updates the existing c
omposition | 401 // Send a compositionupdate event when this function updates the existing |
398 // node, i.e. hasComposition() && !text.isEmpty(). | 402 // composition node, i.e. hasComposition() && !text.isEmpty(). |
399 // 3. Canceling the ongoing composition. | 403 // 3. Canceling the ongoing composition. |
400 // Send a compositionend event when function deletes the existing compositi
on node, i.e. | 404 // Send a compositionend event when function deletes the existing |
401 // !hasComposition() && test.isEmpty(). | 405 // composition node, i.e. !hasComposition() && test.isEmpty(). |
402 if (text.isEmpty()) { | 406 if (text.isEmpty()) { |
403 if (hasComposition()) { | 407 if (hasComposition()) { |
404 Editor::RevealSelectionScope revealSelectionScope(&editor()); | 408 Editor::RevealSelectionScope revealSelectionScope(&editor()); |
405 replaceComposition(emptyString()); | 409 replaceComposition(emptyString()); |
406 } else { | 410 } else { |
407 // It's weird to call |setComposition()| with empty text outside compositi
on, however some IME | 411 // It's weird to call |setComposition()| with empty text outside |
408 // (e.g. Japanese IBus-Anthy) did this, so we simply delete selection with
out sending extra events. | 412 // composition, however some IME (e.g. Japanese IBus-Anthy) did this, so |
| 413 // we simply delete selection without sending extra events. |
409 TypingCommand::deleteSelection(*frame().document(), | 414 TypingCommand::deleteSelection(*frame().document(), |
410 TypingCommand::PreventSpellChecking); | 415 TypingCommand::PreventSpellChecking); |
411 } | 416 } |
412 | 417 |
413 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets | 418 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets |
414 // needs to be audited. see http://crbug.com/590369 for more details. | 419 // needs to be audited. see http://crbug.com/590369 for more details. |
415 frame().document()->updateStyleAndLayoutIgnorePendingStylesheets(); | 420 frame().document()->updateStyleAndLayoutIgnorePendingStylesheets(); |
416 | 421 |
417 setEditableSelectionOffsets(selectedRange); | 422 setEditableSelectionOffsets(selectedRange); |
418 return; | 423 return; |
419 } | 424 } |
420 | 425 |
421 // We should send a 'compositionstart' event only when the given text is not e
mpty because this | 426 // We should send a 'compositionstart' event only when the given text is not |
422 // function doesn't create a composition node when the text is empty. | 427 // empty because this function doesn't create a composition node when the text |
| 428 // is empty. |
423 if (!hasComposition()) { | 429 if (!hasComposition()) { |
424 target->dispatchEvent( | 430 target->dispatchEvent( |
425 CompositionEvent::create(EventTypeNames::compositionstart, | 431 CompositionEvent::create(EventTypeNames::compositionstart, |
426 frame().domWindow(), frame().selectedText())); | 432 frame().domWindow(), frame().selectedText())); |
427 if (!frame().document()) | 433 if (!frame().document()) |
428 return; | 434 return; |
429 } | 435 } |
430 | 436 |
431 DCHECK(!text.isEmpty()); | 437 DCHECK(!text.isEmpty()); |
432 | 438 |
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
678 new RangeVector(1, m_frame->selection().firstRange())); | 684 new RangeVector(1, m_frame->selection().firstRange())); |
679 TypingCommand::deleteSelection(*frame().document()); | 685 TypingCommand::deleteSelection(*frame().document()); |
680 } | 686 } |
681 | 687 |
682 DEFINE_TRACE(InputMethodController) { | 688 DEFINE_TRACE(InputMethodController) { |
683 visitor->trace(m_frame); | 689 visitor->trace(m_frame); |
684 visitor->trace(m_compositionRange); | 690 visitor->trace(m_compositionRange); |
685 } | 691 } |
686 | 692 |
687 } // namespace blink | 693 } // namespace blink |
OLD | NEW |