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 249 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
260 document().updateStyleAndLayoutIgnorePendingStylesheets(); | 260 document().updateStyleAndLayoutIgnorePendingStylesheets(); |
261 | 261 |
262 setSelectionOffsets(oldOffsets); | 262 setSelectionOffsets(oldOffsets); |
263 | 263 |
264 // No DOM update after 'compositionend'. | 264 // No DOM update after 'compositionend'. |
265 dispatchCompositionEndEvent(frame(), composing); | 265 dispatchCompositionEndEvent(frame(), composing); |
266 | 266 |
267 return result; | 267 return result; |
268 } | 268 } |
269 | 269 |
270 return replaceCompositionAndMoveCaret(composingText(), 0); | 270 return replaceCompositionAndMoveCaret(composingText(), 0, |
271 Vector<CompositionUnderline>()); | |
271 } | 272 } |
272 | 273 |
273 bool InputMethodController::commitText(const String& text, | 274 bool InputMethodController::commitText( |
274 int relativeCaretPosition) { | 275 const String& text, |
275 if (hasComposition()) | 276 const Vector<CompositionUnderline>& underlines, |
276 return replaceCompositionAndMoveCaret(text, relativeCaretPosition); | 277 int relativeCaretPosition) { |
278 if (hasComposition()) { | |
279 return replaceCompositionAndMoveCaret(text, relativeCaretPosition, | |
280 underlines); | |
281 } | |
277 | 282 |
278 // We should do nothing in this case, because: | 283 // We should do nothing in this case, because: |
279 // 1. No need to insert text when text is empty. | 284 // 1. No need to insert text when text is empty. |
280 // 2. Shouldn't move caret when relativeCaretPosition == 0 to avoid | 285 // 2. Shouldn't move caret when relativeCaretPosition == 0 to avoid |
281 // duplicate selection change event. | 286 // duplicate selection change event. |
282 if (!text.length() && !relativeCaretPosition) | 287 if (!text.length() && !relativeCaretPosition) { |
283 return false; | 288 return false; |
284 return insertTextAndMoveCaret(text, relativeCaretPosition); | 289 } |
290 | |
291 return insertTextAndMoveCaret(text, relativeCaretPosition, underlines); | |
285 } | 292 } |
286 | 293 |
287 bool InputMethodController::replaceComposition(const String& text) { | 294 bool InputMethodController::replaceComposition(const String& text) { |
288 if (!hasComposition()) | 295 if (!hasComposition()) |
289 return false; | 296 return false; |
290 | 297 |
291 // Select the text that will be deleted or replaced. | 298 // Select the text that will be deleted or replaced. |
292 selectComposition(); | 299 selectComposition(); |
293 | 300 |
294 if (frame().selection().isNone()) | 301 if (frame().selection().isNone()) |
(...skipping 22 matching lines...) Expand all Loading... | |
317 return true; | 324 return true; |
318 } | 325 } |
319 | 326 |
320 // relativeCaretPosition is relative to the end of the text. | 327 // relativeCaretPosition is relative to the end of the text. |
321 static int computeAbsoluteCaretPosition(size_t textStart, | 328 static int computeAbsoluteCaretPosition(size_t textStart, |
322 size_t textLength, | 329 size_t textLength, |
323 int relativeCaretPosition) { | 330 int relativeCaretPosition) { |
324 return textStart + textLength + relativeCaretPosition; | 331 return textStart + textLength + relativeCaretPosition; |
325 } | 332 } |
326 | 333 |
334 void InputMethodController::addCompositionUnderlines( | |
335 const Vector<CompositionUnderline>& underlines, | |
336 Node* baseNode, | |
337 unsigned baseOffset) { | |
338 for (const auto& underline : underlines) { | |
339 unsigned underlineStart = baseOffset + underline.startOffset(); | |
340 unsigned underlineEnd = baseOffset + underline.endOffset(); | |
341 EphemeralRange ephemeralLineRange = EphemeralRange( | |
342 Position(baseNode, underlineStart), Position(baseNode, underlineEnd)); | |
343 if (ephemeralLineRange.isNull()) | |
344 continue; | |
345 document().markers().addCompositionMarker( | |
346 ephemeralLineRange.startPosition(), ephemeralLineRange.endPosition(), | |
347 underline.color(), underline.thick(), underline.backgroundColor()); | |
348 } | |
349 } | |
350 | |
327 bool InputMethodController::replaceCompositionAndMoveCaret( | 351 bool InputMethodController::replaceCompositionAndMoveCaret( |
328 const String& text, | 352 const String& text, |
329 int relativeCaretPosition) { | 353 int relativeCaretPosition, |
354 const Vector<CompositionUnderline>& underlines) { | |
330 Element* rootEditableElement = frame().selection().rootEditableElement(); | 355 Element* rootEditableElement = frame().selection().rootEditableElement(); |
331 if (!rootEditableElement) | 356 if (!rootEditableElement) |
332 return false; | 357 return false; |
333 DCHECK(hasComposition()); | 358 DCHECK(hasComposition()); |
334 PlainTextRange compositionRange = | 359 PlainTextRange compositionRange = |
335 PlainTextRange::create(*rootEditableElement, *m_compositionRange); | 360 PlainTextRange::create(*rootEditableElement, *m_compositionRange); |
336 if (compositionRange.isNull()) | 361 if (compositionRange.isNull()) |
337 return false; | 362 return false; |
338 int textStart = compositionRange.start(); | 363 int textStart = compositionRange.start(); |
339 | 364 |
340 if (!replaceComposition(text)) | 365 if (!replaceComposition(text)) |
341 return false; | 366 return false; |
342 | 367 |
368 addCompositionUnderlines(underlines, rootEditableElement, textStart); | |
rlanday
2016/12/16 20:55:33
I don't think the Voice IME actually ever replaces
rlanday
2016/12/16 21:01:35
I'm going to try to add a test case to InputMethod
rlanday
2016/12/16 21:01:35
I'm going to try to add a test case to InputMethod
| |
369 | |
343 int absoluteCaretPosition = computeAbsoluteCaretPosition( | 370 int absoluteCaretPosition = computeAbsoluteCaretPosition( |
344 textStart, text.length(), relativeCaretPosition); | 371 textStart, text.length(), relativeCaretPosition); |
345 if (!moveCaret(absoluteCaretPosition)) | 372 if (!moveCaret(absoluteCaretPosition)) |
346 return false; | 373 return false; |
347 | 374 |
348 // No DOM update after 'compositionend'. | 375 // No DOM update after 'compositionend'. |
349 dispatchCompositionEndEvent(frame(), text); | 376 dispatchCompositionEndEvent(frame(), text); |
350 | 377 |
351 return true; | 378 return true; |
352 } | 379 } |
353 | 380 |
354 bool InputMethodController::insertText(const String& text) { | 381 bool InputMethodController::insertText(const String& text) { |
355 if (dispatchBeforeInputInsertText(document().focusedElement(), text) != | 382 if (dispatchBeforeInputInsertText(document().focusedElement(), text) != |
356 DispatchEventResult::NotCanceled) | 383 DispatchEventResult::NotCanceled) |
357 return false; | 384 return false; |
358 editor().insertText(text, 0); | 385 editor().insertText(text, 0); |
359 return true; | 386 return true; |
360 } | 387 } |
361 | 388 |
362 bool InputMethodController::insertTextAndMoveCaret(const String& text, | 389 bool InputMethodController::insertTextAndMoveCaret( |
363 int relativeCaretPosition) { | 390 const String& text, |
391 int relativeCaretPosition, | |
392 const Vector<CompositionUnderline>& underlines) { | |
364 PlainTextRange selectionRange = getSelectionOffsets(); | 393 PlainTextRange selectionRange = getSelectionOffsets(); |
365 if (selectionRange.isNull()) | 394 if (selectionRange.isNull()) |
366 return false; | 395 return false; |
367 int textStart = selectionRange.start(); | 396 int textStart = selectionRange.start(); |
368 | 397 |
369 if (text.length()) { | 398 if (text.length()) { |
399 Position base = mostForwardCaretPosition(frame().selection().base()); | |
400 Node* baseNode = base.anchorNode(); | |
401 | |
402 if (!baseNode) | |
rlanday
2016/12/16 20:55:33
Note: if I add the baseNode->isTextNode() check th
| |
403 return false; | |
404 | |
405 unsigned baseOffset = base.computeOffsetInContainerNode(); | |
406 | |
370 if (!insertText(text)) | 407 if (!insertText(text)) |
371 return false; | 408 return false; |
409 | |
410 addCompositionUnderlines(underlines, baseNode, baseOffset); | |
372 } | 411 } |
373 | 412 |
374 int absoluteCaretPosition = computeAbsoluteCaretPosition( | 413 int absoluteCaretPosition = computeAbsoluteCaretPosition( |
375 textStart, text.length(), relativeCaretPosition); | 414 textStart, text.length(), relativeCaretPosition); |
376 return moveCaret(absoluteCaretPosition); | 415 return moveCaret(absoluteCaretPosition); |
377 } | 416 } |
378 | 417 |
379 void InputMethodController::cancelComposition() { | 418 void InputMethodController::cancelComposition() { |
380 if (!hasComposition()) | 419 if (!hasComposition()) |
381 return; | 420 return; |
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
571 // We shouldn't close typing in the middle of setComposition. | 610 // We shouldn't close typing in the middle of setComposition. |
572 setEditableSelectionOffsets(selectedRange, NotUserTriggered); | 611 setEditableSelectionOffsets(selectedRange, NotUserTriggered); |
573 | 612 |
574 if (underlines.isEmpty()) { | 613 if (underlines.isEmpty()) { |
575 document().markers().addCompositionMarker( | 614 document().markers().addCompositionMarker( |
576 m_compositionRange->startPosition(), m_compositionRange->endPosition(), | 615 m_compositionRange->startPosition(), m_compositionRange->endPosition(), |
577 Color::black, false, | 616 Color::black, false, |
578 LayoutTheme::theme().platformDefaultCompositionBackgroundColor()); | 617 LayoutTheme::theme().platformDefaultCompositionBackgroundColor()); |
579 return; | 618 return; |
580 } | 619 } |
581 for (const auto& underline : underlines) { | 620 |
582 unsigned underlineStart = baseOffset + underline.startOffset(); | 621 addCompositionUnderlines(underlines, baseNode, baseOffset); |
583 unsigned underlineEnd = baseOffset + underline.endOffset(); | |
584 EphemeralRange ephemeralLineRange = EphemeralRange( | |
585 Position(baseNode, underlineStart), Position(baseNode, underlineEnd)); | |
586 if (ephemeralLineRange.isNull()) | |
587 continue; | |
588 document().markers().addCompositionMarker( | |
589 ephemeralLineRange.startPosition(), ephemeralLineRange.endPosition(), | |
590 underline.color(), underline.thick(), underline.backgroundColor()); | |
591 } | |
592 } | 622 } |
593 | 623 |
594 PlainTextRange InputMethodController::createSelectionRangeForSetComposition( | 624 PlainTextRange InputMethodController::createSelectionRangeForSetComposition( |
595 int selectionStart, | 625 int selectionStart, |
596 int selectionEnd, | 626 int selectionEnd, |
597 size_t textLength) const { | 627 size_t textLength) const { |
598 const int selectionOffsetsStart = | 628 const int selectionOffsetsStart = |
599 static_cast<int>(getSelectionOffsets().start()); | 629 static_cast<int>(getSelectionOffsets().start()); |
600 const int start = selectionOffsetsStart + selectionStart; | 630 const int start = selectionOffsetsStart + selectionStart; |
601 const int end = selectionOffsetsStart + selectionEnd; | 631 const int end = selectionOffsetsStart + selectionEnd; |
(...skipping 18 matching lines...) Expand all Loading... | |
620 const Position start = range.startPosition(); | 650 const Position start = range.startPosition(); |
621 if (rootEditableElementOf(start) != editable) | 651 if (rootEditableElementOf(start) != editable) |
622 return; | 652 return; |
623 | 653 |
624 const Position end = range.endPosition(); | 654 const Position end = range.endPosition(); |
625 if (rootEditableElementOf(end) != editable) | 655 if (rootEditableElementOf(end) != editable) |
626 return; | 656 return; |
627 | 657 |
628 clear(); | 658 clear(); |
629 | 659 |
630 for (const auto& underline : underlines) { | 660 addCompositionUnderlines(underlines, editable, compositionStart); |
631 unsigned underlineStart = compositionStart + underline.startOffset(); | |
632 unsigned underlineEnd = compositionStart + underline.endOffset(); | |
633 EphemeralRange ephemeralLineRange = | |
634 PlainTextRange(underlineStart, underlineEnd).createRange(*editable); | |
635 if (ephemeralLineRange.isNull()) | |
636 continue; | |
637 document().markers().addCompositionMarker( | |
638 ephemeralLineRange.startPosition(), ephemeralLineRange.endPosition(), | |
639 underline.color(), underline.thick(), underline.backgroundColor()); | |
640 } | |
641 | 661 |
642 m_hasComposition = true; | 662 m_hasComposition = true; |
643 if (!m_compositionRange) | 663 if (!m_compositionRange) |
644 m_compositionRange = Range::create(document()); | 664 m_compositionRange = Range::create(document()); |
645 m_compositionRange->setStart(range.startPosition()); | 665 m_compositionRange->setStart(range.startPosition()); |
646 m_compositionRange->setEnd(range.endPosition()); | 666 m_compositionRange->setEnd(range.endPosition()); |
647 } | 667 } |
648 | 668 |
649 EphemeralRange InputMethodController::compositionEphemeralRange() const { | 669 EphemeralRange InputMethodController::compositionEphemeralRange() const { |
650 if (!hasComposition()) | 670 if (!hasComposition()) |
(...skipping 412 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1063 frame().chromeClient().resetInputMethod(); | 1083 frame().chromeClient().resetInputMethod(); |
1064 } | 1084 } |
1065 | 1085 |
1066 DEFINE_TRACE(InputMethodController) { | 1086 DEFINE_TRACE(InputMethodController) { |
1067 visitor->trace(m_frame); | 1087 visitor->trace(m_frame); |
1068 visitor->trace(m_compositionRange); | 1088 visitor->trace(m_compositionRange); |
1069 SynchronousMutationObserver::trace(visitor); | 1089 SynchronousMutationObserver::trace(visitor); |
1070 } | 1090 } |
1071 | 1091 |
1072 } // namespace blink | 1092 } // namespace blink |
OLD | NEW |