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

Side by Side Diff: third_party/WebKit/Source/core/editing/InputMethodController.cpp

Issue 2339793002: Handle newCursorPosition correctly for Android's commitText() (Closed)
Patch Set: Fix compile error (rebased on r418371) Created 4 years, 3 months 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
OLDNEW
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 22 matching lines...) Expand all
33 #include "core/editing/Editor.h" 33 #include "core/editing/Editor.h"
34 #include "core/editing/commands/TypingCommand.h" 34 #include "core/editing/commands/TypingCommand.h"
35 #include "core/editing/markers/DocumentMarkerController.h" 35 #include "core/editing/markers/DocumentMarkerController.h"
36 #include "core/events/CompositionEvent.h" 36 #include "core/events/CompositionEvent.h"
37 #include "core/frame/LocalFrame.h" 37 #include "core/frame/LocalFrame.h"
38 #include "core/html/HTMLTextAreaElement.h" 38 #include "core/html/HTMLTextAreaElement.h"
39 #include "core/input/EventHandler.h" 39 #include "core/input/EventHandler.h"
40 #include "core/layout/LayoutObject.h" 40 #include "core/layout/LayoutObject.h"
41 #include "core/layout/LayoutTheme.h" 41 #include "core/layout/LayoutTheme.h"
42 #include "core/page/ChromeClient.h" 42 #include "core/page/ChromeClient.h"
43 #include "wtf/Optional.h"
44 43
45 namespace blink { 44 namespace blink {
46 45
47 namespace { 46 namespace {
48 47
49 void dispatchCompositionUpdateEvent(LocalFrame& frame, const String& text) 48 void dispatchCompositionUpdateEvent(LocalFrame& frame, const String& text)
50 { 49 {
51 Element* target = frame.document()->focusedElement(); 50 Element* target = frame.document()->focusedElement();
52 if (!target) 51 if (!target)
53 return; 52 return;
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
163 if (range.isNull()) 162 if (range.isNull())
164 return; 163 return;
165 164
166 // The composition can start inside a composed character sequence, so we hav e to override checks. 165 // The composition can start inside a composed character sequence, so we hav e to override checks.
167 // See <http://bugs.webkit.org/show_bug.cgi?id=15781> 166 // See <http://bugs.webkit.org/show_bug.cgi?id=15781>
168 VisibleSelection selection; 167 VisibleSelection selection;
169 selection.setWithoutValidation(range.startPosition(), range.endPosition()); 168 selection.setWithoutValidation(range.startPosition(), range.endPosition());
170 frame().selection().setSelection(selection, 0); 169 frame().selection().setSelection(selection, 0);
171 } 170 }
172 171
173 bool InputMethodController::confirmComposition() 172 bool InputMethodController::finishComposingText(ConfirmCompositionBehavior confi rmBehavior)
174 {
175 return confirmComposition(composingText());
176 }
177
178 bool InputMethodController::confirmComposition(const String& text, ConfirmCompos itionBehavior confirmBehavior)
179 { 173 {
180 if (!hasComposition()) 174 if (!hasComposition())
181 return false; 175 return false;
182 176
183 Optional<Editor::RevealSelectionScope> revealSelectionScope; 177 if (confirmBehavior == KeepSelection) {
184 if (confirmBehavior == KeepSelection) 178 PlainTextRange oldOffsets = getSelectionOffsets();
185 revealSelectionScope.emplace(&editor()); 179 Editor::RevealSelectionScope revealSelectionScope(&editor());
180
181 bool result = replaceComposition(composingText());
182
183 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesh eets
184 // needs to be audited. see http://crbug.com/590369 for more details.
185 frame().document()->updateStyleAndLayoutIgnorePendingStylesheets();
186
187 setSelectionOffsets(oldOffsets);
188 return result;
189 }
190
191 return replaceCompositionAndMoveCaret(composingText(), 0);
192 }
193
194 bool InputMethodController::commitText(const String& text, int relativeCaretPosi tion)
195 {
196 if (hasComposition())
197 return replaceCompositionAndMoveCaret(text, relativeCaretPosition);
198
199 // We should do nothing in this case, because:
200 // 1. No need to insert text when text is empty.
201 // 2. Shouldn't move caret when relativeCaretPosition == 0 to avoid
202 // duplicate selection change event.
203 if (!text.length() && !relativeCaretPosition)
204 return false;
205 return insertTextAndMoveCaret(text, relativeCaretPosition);
206 }
207
208 bool InputMethodController::replaceComposition(const String& text)
209 {
210 if (!hasComposition())
211 return false;
186 212
187 // If the composition was set from existing text and didn't change, then 213 // If the composition was set from existing text and didn't change, then
188 // there's nothing to do here (and we should avoid doing anything as that 214 // there's nothing to do here (and we should avoid doing anything as that
189 // may clobber multi-node styled text). 215 // may clobber multi-node styled text).
190 if (!m_isDirty && composingText() == text) { 216 if (!m_isDirty && composingText() == text) {
191 clear(); 217 clear();
192 return true; 218 return true;
193 } 219 }
194 220
195 // Select the text that will be deleted or replaced. 221 // Select the text that will be deleted or replaced.
(...skipping 17 matching lines...) Expand all
213 // Event handler might destroy document. 239 // Event handler might destroy document.
214 if (!frame().document()) 240 if (!frame().document())
215 return false; 241 return false;
216 242
217 // No DOM update after 'compositionend'. 243 // No DOM update after 'compositionend'.
218 dispatchCompositionEndEvent(frame(), text); 244 dispatchCompositionEndEvent(frame(), text);
219 245
220 return true; 246 return true;
221 } 247 }
222 248
223 bool InputMethodController::confirmCompositionOrInsertText(const String& text, C onfirmCompositionBehavior confirmBehavior) 249 // relativeCaretPosition is relative to the end of the text.
250 static int computeAbsoluteCaretPosition(size_t textStart, size_t textLength, int relativeCaretPosition)
224 { 251 {
225 if (!hasComposition()) { 252 return textStart + textLength + relativeCaretPosition;
226 if (!text.length()) 253 }
254
255 bool InputMethodController::replaceCompositionAndMoveCaret(const String& text, i nt relativeCaretPosition)
256 {
257 Element* rootEditableElement = frame().selection().rootEditableElement();
258 if (!rootEditableElement)
259 return false;
260 PlainTextRange compositionRange = PlainTextRange::create(*rootEditableElemen t, *m_compositionRange);
261 if (compositionRange.isNull())
262 return false;
263 int textStart = compositionRange.start();
264
265 if (!replaceComposition(text))
266 return false;
267
268 int absoluteCaretPosition = computeAbsoluteCaretPosition(textStart, text.len gth(), relativeCaretPosition);
269 return moveCaret(absoluteCaretPosition);
270 }
271
272 bool InputMethodController::insertText(const String& text)
273 {
274 if (dispatchBeforeInputInsertText(frame().document()->focusedElement(), text ) != DispatchEventResult::NotCanceled)
275 return false;
276 editor().insertText(text, 0);
277 return true;
278 }
279
280 bool InputMethodController::insertTextAndMoveCaret(const String& text, int relat iveCaretPosition)
281 {
282 PlainTextRange selectionRange = getSelectionOffsets();
283 if (selectionRange.isNull())
284 return false;
285 int textStart = selectionRange.start();
286
287 if (text.length()) {
288 if (!insertText(text))
227 return false; 289 return false;
228
229 if (dispatchBeforeInputInsertText(frame().document()->focusedElement(), text) != DispatchEventResult::NotCanceled)
230 return false;
231
232 editor().insertText(text, 0);
233 return true;
234 } 290 }
235 291
236 if (text.length()) { 292 int absoluteCaretPosition = computeAbsoluteCaretPosition(textStart, text.len gth(), relativeCaretPosition);
237 confirmComposition(text); 293 return moveCaret(absoluteCaretPosition);
238 return true;
239 }
240
241 if (confirmBehavior == DoNotKeepSelection)
242 return confirmComposition(composingText(), DoNotKeepSelection);
243
244 PlainTextRange oldOffsets = getSelectionOffsets();
245 bool result = confirmComposition();
246
247 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
248 // needs to be audited. see http://crbug.com/590369 for more details.
249 frame().document()->updateStyleAndLayoutIgnorePendingStylesheets();
250
251 setSelectionOffsets(oldOffsets);
252 return result;
253 } 294 }
254 295
255 void InputMethodController::cancelComposition() 296 void InputMethodController::cancelComposition()
256 { 297 {
257 if (!hasComposition()) 298 if (!hasComposition())
258 return; 299 return;
259 300
260 Editor::RevealSelectionScope revealSelectionScope(&editor()); 301 Editor::RevealSelectionScope revealSelectionScope(&editor());
261 302
262 if (frame().selection().isNone()) 303 if (frame().selection().isNone())
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
334 // Sending a compositionupdate event at this time ensures that at least o ne 375 // Sending a compositionupdate event at this time ensures that at least o ne
335 // compositionupdate event is dispatched. 376 // compositionupdate event is dispatched.
336 // 2. Updating the existing composition node. 377 // 2. Updating the existing composition node.
337 // Send a compositionupdate event when this function updates the existing composition 378 // Send a compositionupdate event when this function updates the existing composition
338 // node, i.e. hasComposition() && !text.isEmpty(). 379 // node, i.e. hasComposition() && !text.isEmpty().
339 // 3. Canceling the ongoing composition. 380 // 3. Canceling the ongoing composition.
340 // Send a compositionend event when function deletes the existing composi tion node, i.e. 381 // Send a compositionend event when function deletes the existing composi tion node, i.e.
341 // !hasComposition() && test.isEmpty(). 382 // !hasComposition() && test.isEmpty().
342 if (text.isEmpty()) { 383 if (text.isEmpty()) {
343 if (hasComposition()) { 384 if (hasComposition()) {
344 confirmComposition(emptyString()); 385 Editor::RevealSelectionScope revealSelectionScope(&editor());
386 replaceComposition(emptyString());
345 } else { 387 } else {
346 // It's weird to call |setComposition()| with empty text outside com position, however some IME 388 // It's weird to call |setComposition()| with empty text outside com position, however some IME
347 // (e.g. Japanese IBus-Anthy) did this, so we simply delete selectio n without sending extra events. 389 // (e.g. Japanese IBus-Anthy) did this, so we simply delete selectio n without sending extra events.
348 TypingCommand::deleteSelection(*frame().document(), TypingCommand::P reventSpellChecking); 390 TypingCommand::deleteSelection(*frame().document(), TypingCommand::P reventSpellChecking);
349 } 391 }
350 392
351 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesh eets 393 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesh eets
352 // needs to be audited. see http://crbug.com/590369 for more details. 394 // needs to be audited. see http://crbug.com/590369 for more details.
353 frame().document()->updateStyleAndLayoutIgnorePendingStylesheets(); 395 frame().document()->updateStyleAndLayoutIgnorePendingStylesheets();
354 396
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after
539 581
540 rightBoundary += textLength; 582 rightBoundary += textLength;
541 583
542 // In case of exceeding the right boundary. 584 // In case of exceeding the right boundary.
543 start = std::min(start, rightBoundary); 585 start = std::min(start, rightBoundary);
544 end = std::min(end, rightBoundary); 586 end = std::min(end, rightBoundary);
545 587
546 return PlainTextRange(start, end); 588 return PlainTextRange(start, end);
547 } 589 }
548 590
591 bool InputMethodController::moveCaret(int newCaretPosition)
592 {
593 frame().document()->updateStyleAndLayoutIgnorePendingStylesheets();
594 PlainTextRange selectedRange = createRangeForSelection(newCaretPosition, new CaretPosition, 0);
595 if (selectedRange.isNull())
596 return false;
597 return setEditableSelectionOffsets(selectedRange);
598 }
599
549 void InputMethodController::extendSelectionAndDelete(int before, int after) 600 void InputMethodController::extendSelectionAndDelete(int before, int after)
550 { 601 {
551 if (!editor().canEdit()) 602 if (!editor().canEdit())
552 return; 603 return;
553 PlainTextRange selectionOffsets(getSelectionOffsets()); 604 PlainTextRange selectionOffsets(getSelectionOffsets());
554 if (selectionOffsets.isNull()) 605 if (selectionOffsets.isNull())
555 return; 606 return;
556 607
557 // A common call of before=1 and after=0 will fail if the last character 608 // A common call of before=1 and after=0 will fail if the last character
558 // is multi-code-word UTF-16, including both multi-16bit code-points and 609 // is multi-code-word UTF-16, including both multi-16bit code-points and
(...skipping 19 matching lines...) Expand all
578 TypingCommand::deleteSelection(*frame().document()); 629 TypingCommand::deleteSelection(*frame().document());
579 } 630 }
580 631
581 DEFINE_TRACE(InputMethodController) 632 DEFINE_TRACE(InputMethodController)
582 { 633 {
583 visitor->trace(m_frame); 634 visitor->trace(m_frame);
584 visitor->trace(m_compositionRange); 635 visitor->trace(m_compositionRange);
585 } 636 }
586 637
587 } // namespace blink 638 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698