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 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
176 if (range.isNull()) | 176 if (range.isNull()) |
177 return; | 177 return; |
178 | 178 |
179 // The composition can start inside a composed character sequence, so we hav
e to override checks. | 179 // The composition can start inside a composed character sequence, so we hav
e to override checks. |
180 // See <http://bugs.webkit.org/show_bug.cgi?id=15781> | 180 // See <http://bugs.webkit.org/show_bug.cgi?id=15781> |
181 VisibleSelection selection; | 181 VisibleSelection selection; |
182 selection.setWithoutValidation(range.startPosition(), range.endPosition()); | 182 selection.setWithoutValidation(range.startPosition(), range.endPosition()); |
183 frame().selection().setSelection(selection, 0); | 183 frame().selection().setSelection(selection, 0); |
184 } | 184 } |
185 | 185 |
186 bool InputMethodController::confirmComposition() | 186 bool InputMethodController::finishComposingText(ConfirmCompositionBehavior confi
rmBehavior) |
187 { | |
188 return confirmComposition(composingText()); | |
189 } | |
190 | |
191 bool InputMethodController::confirmComposition(const String& text, ConfirmCompos
itionBehavior confirmBehavior) | |
192 { | 187 { |
193 if (!hasComposition()) | 188 if (!hasComposition()) |
194 return false; | 189 return false; |
195 | 190 |
196 Optional<Editor::RevealSelectionScope> revealSelectionScope; | 191 if (confirmBehavior == KeepSelection) { |
197 if (confirmBehavior == KeepSelection) | 192 SelectionOffsetsScope selectionOffsetsScope(this); |
| 193 Optional<Editor::RevealSelectionScope> revealSelectionScope; |
198 revealSelectionScope.emplace(&editor()); | 194 revealSelectionScope.emplace(&editor()); |
| 195 return replaceComposition(composingText()); |
| 196 } |
| 197 |
| 198 return replaceCompositionAndMoveCaret(composingText(), 0); |
| 199 } |
| 200 |
| 201 bool InputMethodController::commitText(const String& text, int relativeCaretPosi
tion) |
| 202 { |
| 203 if (hasComposition()) |
| 204 return replaceCompositionAndMoveCaret(text, relativeCaretPosition); |
| 205 |
| 206 // We should do nothing in this case, because: |
| 207 // 1. No need to insert text when text is empty. |
| 208 // 2. Shouldn't move caret when relativeCaretPosition == 0 to avoid |
| 209 // duplicate selection change event. |
| 210 if (!text.length() && !relativeCaretPosition) |
| 211 return false; |
| 212 return insertTextAndMoveCaret(text, relativeCaretPosition); |
| 213 } |
| 214 |
| 215 bool InputMethodController::replaceComposition(const String& text) |
| 216 { |
| 217 if (!hasComposition()) |
| 218 return false; |
199 | 219 |
200 // If the composition was set from existing text and didn't change, then | 220 // If the composition was set from existing text and didn't change, then |
201 // there's nothing to do here (and we should avoid doing anything as that | 221 // there's nothing to do here (and we should avoid doing anything as that |
202 // may clobber multi-node styled text). | 222 // may clobber multi-node styled text). |
203 if (!m_isDirty && composingText() == text) { | 223 if (!m_isDirty && composingText() == text) { |
204 clear(); | 224 clear(); |
205 return true; | 225 return true; |
206 } | 226 } |
207 | 227 |
208 // Select the text that will be deleted or replaced. | 228 // Select the text that will be deleted or replaced. |
(...skipping 17 matching lines...) Expand all Loading... |
226 // Event handler might destroy document. | 246 // Event handler might destroy document. |
227 if (!frame().document()) | 247 if (!frame().document()) |
228 return false; | 248 return false; |
229 | 249 |
230 // No DOM update after 'compositionend'. | 250 // No DOM update after 'compositionend'. |
231 dispatchCompositionEndEvent(frame(), text); | 251 dispatchCompositionEndEvent(frame(), text); |
232 | 252 |
233 return true; | 253 return true; |
234 } | 254 } |
235 | 255 |
236 bool InputMethodController::confirmCompositionOrInsertText(const String& text, C
onfirmCompositionBehavior confirmBehavior) | 256 // relativeCaretPosition is relative to the end of the text. |
| 257 static int computeAbsoluteCaretPosition(size_t textStart, size_t textLength, int
relativeCaretPosition) |
237 { | 258 { |
238 if (!hasComposition()) { | 259 return textStart + textLength + relativeCaretPosition; |
239 if (!text.length()) | 260 } |
| 261 |
| 262 bool InputMethodController::replaceCompositionAndMoveCaret(const String& text, i
nt relativeCaretPosition) |
| 263 { |
| 264 Element* rootEditableElement = frame().selection().rootEditableElement(); |
| 265 if (!rootEditableElement) |
| 266 return false; |
| 267 PlainTextRange compositionRange = PlainTextRange::create(*rootEditableElemen
t, *m_compositionRange); |
| 268 if (compositionRange.isNull()) |
| 269 return false; |
| 270 int textStart = compositionRange.start(); |
| 271 |
| 272 if (!replaceComposition(text)) |
| 273 return false; |
| 274 |
| 275 int absoluteCaretPosition = computeAbsoluteCaretPosition(textStart, text.len
gth(), relativeCaretPosition); |
| 276 return moveCaret(absoluteCaretPosition); |
| 277 } |
| 278 |
| 279 bool InputMethodController::insertText(const String& text) |
| 280 { |
| 281 if (dispatchBeforeInputInsertText(frame().document()->focusedElement(), text
) != DispatchEventResult::NotCanceled) |
| 282 return false; |
| 283 editor().insertText(text, 0); |
| 284 return true; |
| 285 } |
| 286 |
| 287 bool InputMethodController::insertTextAndMoveCaret(const String& text, int relat
iveCaretPosition) |
| 288 { |
| 289 PlainTextRange selectionRange = getSelectionOffsets(); |
| 290 if (selectionRange.isNull()) |
| 291 return false; |
| 292 int textStart = selectionRange.start(); |
| 293 |
| 294 if (text.length()) { |
| 295 if (!insertText(text)) |
240 return false; | 296 return false; |
241 | |
242 if (dispatchBeforeInputInsertText(frame().document()->focusedElement(),
text) != DispatchEventResult::NotCanceled) | |
243 return false; | |
244 | |
245 editor().insertText(text, 0); | |
246 return true; | |
247 } | 297 } |
248 | 298 |
249 if (text.length()) { | 299 int absoluteCaretPosition = computeAbsoluteCaretPosition(textStart, text.len
gth(), relativeCaretPosition); |
250 confirmComposition(text); | 300 return moveCaret(absoluteCaretPosition); |
251 return true; | |
252 } | |
253 | |
254 if (confirmBehavior == DoNotKeepSelection) | |
255 return confirmComposition(composingText(), DoNotKeepSelection); | |
256 | |
257 SelectionOffsetsScope selectionOffsetsScope(this); | |
258 return confirmComposition(); | |
259 } | 301 } |
260 | 302 |
261 void InputMethodController::cancelComposition() | 303 void InputMethodController::cancelComposition() |
262 { | 304 { |
263 if (!hasComposition()) | 305 if (!hasComposition()) |
264 return; | 306 return; |
265 | 307 |
266 Editor::RevealSelectionScope revealSelectionScope(&editor()); | 308 Editor::RevealSelectionScope revealSelectionScope(&editor()); |
267 | 309 |
268 if (frame().selection().isNone()) | 310 if (frame().selection().isNone()) |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
340 // Sending a compositionupdate event at this time ensures that at least o
ne | 382 // Sending a compositionupdate event at this time ensures that at least o
ne |
341 // compositionupdate event is dispatched. | 383 // compositionupdate event is dispatched. |
342 // 2. Updating the existing composition node. | 384 // 2. Updating the existing composition node. |
343 // Send a compositionupdate event when this function updates the existing
composition | 385 // Send a compositionupdate event when this function updates the existing
composition |
344 // node, i.e. hasComposition() && !text.isEmpty(). | 386 // node, i.e. hasComposition() && !text.isEmpty(). |
345 // 3. Canceling the ongoing composition. | 387 // 3. Canceling the ongoing composition. |
346 // Send a compositionend event when function deletes the existing composi
tion node, i.e. | 388 // Send a compositionend event when function deletes the existing composi
tion node, i.e. |
347 // !hasComposition() && test.isEmpty(). | 389 // !hasComposition() && test.isEmpty(). |
348 if (text.isEmpty()) { | 390 if (text.isEmpty()) { |
349 if (hasComposition()) { | 391 if (hasComposition()) { |
350 confirmComposition(emptyString()); | 392 Optional<Editor::RevealSelectionScope> revealSelectionScope; |
| 393 revealSelectionScope.emplace(&editor()); |
| 394 replaceComposition(emptyString()); |
351 } else { | 395 } else { |
352 // It's weird to call |setComposition()| with empty text outside com
position, however some IME | 396 // It's weird to call |setComposition()| with empty text outside com
position, however some IME |
353 // (e.g. Japanese IBus-Anthy) did this, so we simply delete selectio
n without sending extra events. | 397 // (e.g. Japanese IBus-Anthy) did this, so we simply delete selectio
n without sending extra events. |
354 TypingCommand::deleteSelection(*frame().document(), TypingCommand::P
reventSpellChecking); | 398 TypingCommand::deleteSelection(*frame().document(), TypingCommand::P
reventSpellChecking); |
355 } | 399 } |
356 | 400 |
357 setEditableSelectionOffsets(selectedRange); | 401 setEditableSelectionOffsets(selectedRange); |
358 return; | 402 return; |
359 } | 403 } |
360 | 404 |
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
541 | 585 |
542 rightBoundary += textLength; | 586 rightBoundary += textLength; |
543 | 587 |
544 // In case of exceeding the right boundary. | 588 // In case of exceeding the right boundary. |
545 start = std::min(start, rightBoundary); | 589 start = std::min(start, rightBoundary); |
546 end = std::min(end, rightBoundary); | 590 end = std::min(end, rightBoundary); |
547 | 591 |
548 return PlainTextRange(start, end); | 592 return PlainTextRange(start, end); |
549 } | 593 } |
550 | 594 |
| 595 bool InputMethodController::moveCaret(int newCaretPosition) |
| 596 { |
| 597 frame().document()->updateStyleAndLayoutIgnorePendingStylesheets(); |
| 598 PlainTextRange selectedRange = createRangeForSelection(newCaretPosition, new
CaretPosition, 0); |
| 599 if (selectedRange.isNull()) |
| 600 return false; |
| 601 return setEditableSelectionOffsets(selectedRange); |
| 602 } |
| 603 |
551 void InputMethodController::extendSelectionAndDelete(int before, int after) | 604 void InputMethodController::extendSelectionAndDelete(int before, int after) |
552 { | 605 { |
553 if (!editor().canEdit()) | 606 if (!editor().canEdit()) |
554 return; | 607 return; |
555 PlainTextRange selectionOffsets(getSelectionOffsets()); | 608 PlainTextRange selectionOffsets(getSelectionOffsets()); |
556 if (selectionOffsets.isNull()) | 609 if (selectionOffsets.isNull()) |
557 return; | 610 return; |
558 | 611 |
559 // A common call of before=1 and after=0 will fail if the last character | 612 // A common call of before=1 and after=0 will fail if the last character |
560 // is multi-code-word UTF-16, including both multi-16bit code-points and | 613 // is multi-code-word UTF-16, including both multi-16bit code-points and |
(...skipping 19 matching lines...) Expand all Loading... |
580 TypingCommand::deleteSelection(*frame().document()); | 633 TypingCommand::deleteSelection(*frame().document()); |
581 } | 634 } |
582 | 635 |
583 DEFINE_TRACE(InputMethodController) | 636 DEFINE_TRACE(InputMethodController) |
584 { | 637 { |
585 visitor->trace(m_frame); | 638 visitor->trace(m_frame); |
586 visitor->trace(m_compositionRange); | 639 visitor->trace(m_compositionRange); |
587 } | 640 } |
588 | 641 |
589 } // namespace blink | 642 } // namespace blink |
OLD | NEW |