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 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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::confirmComposition() |
187 { | 187 { |
188 return confirmComposition(composingText()); | 188 return replaceComposition(composingText(), KeepSelection); |
189 } | 189 } |
190 | 190 |
191 bool InputMethodController::confirmComposition(const String& text, ConfirmCompos
itionBehavior confirmBehavior) | 191 bool InputMethodController::replaceComposition(const String& text, ConfirmCompos
itionBehavior confirmBehavior) |
192 { | 192 { |
193 if (!hasComposition()) | 193 if (!hasComposition()) |
194 return false; | 194 return false; |
195 | 195 |
196 Optional<Editor::RevealSelectionScope> revealSelectionScope; | 196 Optional<Editor::RevealSelectionScope> revealSelectionScope; |
197 if (confirmBehavior == KeepSelection) | 197 if (confirmBehavior == KeepSelection) |
198 revealSelectionScope.emplace(&editor()); | 198 revealSelectionScope.emplace(&editor()); |
199 | 199 |
200 // If the composition was set from existing text and didn't change, then | 200 // 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 | 201 // there's nothing to do here (and we should avoid doing anything as that |
(...skipping 24 matching lines...) Expand all Loading... |
226 // Event handler might destroy document. | 226 // Event handler might destroy document. |
227 if (!frame().document()) | 227 if (!frame().document()) |
228 return false; | 228 return false; |
229 | 229 |
230 // No DOM update after 'compositionend'. | 230 // No DOM update after 'compositionend'. |
231 dispatchCompositionEndEvent(frame(), text); | 231 dispatchCompositionEndEvent(frame(), text); |
232 | 232 |
233 return true; | 233 return true; |
234 } | 234 } |
235 | 235 |
236 bool InputMethodController::confirmCompositionOrInsertText(const String& text, C
onfirmCompositionBehavior confirmBehavior) | 236 bool InputMethodController::confirmComposition(const String& text) |
237 { | 237 { |
238 if (!hasComposition()) { | 238 if (!hasComposition()) |
239 if (!text.length()) | 239 return insertText(text); |
240 return false; | |
241 | 240 |
242 if (dispatchBeforeInputInsertText(frame().document()->focusedElement(),
text) != DispatchEventResult::NotCanceled) | 241 if (text.length()) { |
243 return false; | 242 replaceComposition(text, KeepSelection); |
244 | |
245 editor().insertText(text, 0); | |
246 return true; | 243 return true; |
247 } | 244 } |
248 | 245 |
249 if (text.length()) { | |
250 confirmComposition(text); | |
251 return true; | |
252 } | |
253 | |
254 if (confirmBehavior == DoNotKeepSelection) | |
255 return confirmComposition(composingText(), DoNotKeepSelection); | |
256 | |
257 SelectionOffsetsScope selectionOffsetsScope(this); | 246 SelectionOffsetsScope selectionOffsetsScope(this); |
258 return confirmComposition(); | 247 return confirmComposition(); |
259 } | 248 } |
260 | 249 |
| 250 bool InputMethodController::confirmCompositionWithCursor(const String& text, int
relativeCursorPosition) |
| 251 { |
| 252 // The relativeCursorPosition is relative to the composing text if any, or |
| 253 // relative to the selection if no composing text. |
| 254 // This is to match Android behavior. See: |
| 255 // https://developer.android.com/reference/android/view/inputmethod/InputCon
nection.html#commitText(java.lang.CharSequence, int) |
| 256 int textStart, textLength; |
| 257 if (hasComposition()) { |
| 258 Element* rootEditableElement = frame().selection().rootEditableElement()
; |
| 259 if (!rootEditableElement) |
| 260 return false; |
| 261 PlainTextRange compositionRange = PlainTextRange::create(*rootEditableEl
ement, *m_compositionRange); |
| 262 |
| 263 textStart = compositionRange.start(); |
| 264 |
| 265 // If |text| is empty, we will confirm the composing text; otherwise, we |
| 266 // will insert the |text|. |
| 267 textLength = text.length() ? text.length() : compositionRange.length(); |
| 268 } else { |
| 269 PlainTextRange selectionRange = getSelectionOffsets(); |
| 270 if (selectionRange.isNull()) |
| 271 return false; |
| 272 |
| 273 textStart = getSelectionOffsets().start(); |
| 274 textLength = text.length(); |
| 275 } |
| 276 |
| 277 // If relativeCursorPosition > 0, it's relative to the end of the text - 1; |
| 278 // if relativeCursorPosition <= 0, it is relative to the start of the text. |
| 279 // This is also to match Android behavior. |
| 280 if (relativeCursorPosition > 0) |
| 281 relativeCursorPosition += textLength - 1; |
| 282 int absoluteCursorPosition = textStart + relativeCursorPosition; |
| 283 |
| 284 bool result = false; |
| 285 if (!hasComposition()) { |
| 286 result = insertText(text); |
| 287 } else if (text.length()) { |
| 288 result = replaceComposition(text, DoNotKeepSelection); |
| 289 } else { |
| 290 result = replaceComposition(composingText(), DoNotKeepSelection); |
| 291 } |
| 292 if (!result) |
| 293 return false; |
| 294 |
| 295 frame().document()->updateStyleAndLayoutIgnorePendingStylesheets(); |
| 296 |
| 297 PlainTextRange selectedRange = createRangeForSelection(absoluteCursorPositio
n, absoluteCursorPosition, 0); |
| 298 if (selectedRange.isNull()) |
| 299 return false; |
| 300 return setEditableSelectionOffsets(selectedRange); |
| 301 } |
| 302 |
| 303 bool InputMethodController::insertText(const String& text) |
| 304 { |
| 305 if (!text.length()) |
| 306 return false; |
| 307 |
| 308 if (dispatchBeforeInputInsertText(frame().document()->focusedElement(), text
) != DispatchEventResult::NotCanceled) |
| 309 return false; |
| 310 |
| 311 editor().insertText(text, 0); |
| 312 return true; |
| 313 } |
| 314 |
261 void InputMethodController::cancelComposition() | 315 void InputMethodController::cancelComposition() |
262 { | 316 { |
263 if (!hasComposition()) | 317 if (!hasComposition()) |
264 return; | 318 return; |
265 | 319 |
266 Editor::RevealSelectionScope revealSelectionScope(&editor()); | 320 Editor::RevealSelectionScope revealSelectionScope(&editor()); |
267 | 321 |
268 if (frame().selection().isNone()) | 322 if (frame().selection().isNone()) |
269 return; | 323 return; |
270 | 324 |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
336 // Sending a compositionupdate event at this time ensures that at least o
ne | 390 // Sending a compositionupdate event at this time ensures that at least o
ne |
337 // compositionupdate event is dispatched. | 391 // compositionupdate event is dispatched. |
338 // 2. Updating the existing composition node. | 392 // 2. Updating the existing composition node. |
339 // Send a compositionupdate event when this function updates the existing
composition | 393 // Send a compositionupdate event when this function updates the existing
composition |
340 // node, i.e. hasComposition() && !text.isEmpty(). | 394 // node, i.e. hasComposition() && !text.isEmpty(). |
341 // 3. Canceling the ongoing composition. | 395 // 3. Canceling the ongoing composition. |
342 // Send a compositionend event when function deletes the existing composi
tion node, i.e. | 396 // Send a compositionend event when function deletes the existing composi
tion node, i.e. |
343 // !hasComposition() && test.isEmpty(). | 397 // !hasComposition() && test.isEmpty(). |
344 if (text.isEmpty()) { | 398 if (text.isEmpty()) { |
345 if (hasComposition()) { | 399 if (hasComposition()) { |
346 confirmComposition(emptyString()); | 400 replaceComposition(emptyString(), KeepSelection); |
347 } else { | 401 } else { |
348 // It's weird to call |setComposition()| with empty text outside com
position, however some IME | 402 // It's weird to call |setComposition()| with empty text outside com
position, however some IME |
349 // (e.g. Japanese IBus-Anthy) did this, so we simply delete selectio
n without sending extra events. | 403 // (e.g. Japanese IBus-Anthy) did this, so we simply delete selectio
n without sending extra events. |
350 TypingCommand::deleteSelection(*frame().document(), TypingCommand::P
reventSpellChecking); | 404 TypingCommand::deleteSelection(*frame().document(), TypingCommand::P
reventSpellChecking); |
351 } | 405 } |
352 | 406 |
353 setEditableSelectionOffsets(selectedRange); | 407 setEditableSelectionOffsets(selectedRange); |
354 return; | 408 return; |
355 } | 409 } |
356 | 410 |
(...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
575 TypingCommand::deleteSelection(*frame().document()); | 629 TypingCommand::deleteSelection(*frame().document()); |
576 } | 630 } |
577 | 631 |
578 DEFINE_TRACE(InputMethodController) | 632 DEFINE_TRACE(InputMethodController) |
579 { | 633 { |
580 visitor->trace(m_frame); | 634 visitor->trace(m_frame); |
581 visitor->trace(m_compositionRange); | 635 visitor->trace(m_compositionRange); |
582 } | 636 } |
583 | 637 |
584 } // namespace blink | 638 } // namespace blink |
OLD | NEW |