Chromium Code Reviews| Index: third_party/WebKit/Source/core/editing/InputMethodController.cpp |
| diff --git a/third_party/WebKit/Source/core/editing/InputMethodController.cpp b/third_party/WebKit/Source/core/editing/InputMethodController.cpp |
| index bae3cea1d0ff453dbdafaf3f688cb67b036bec9d..cc6c6280ba58b85f9c3f3bcba96bc4cf119c930a 100644 |
| --- a/third_party/WebKit/Source/core/editing/InputMethodController.cpp |
| +++ b/third_party/WebKit/Source/core/editing/InputMethodController.cpp |
| @@ -97,6 +97,21 @@ void insertTextDuringCompositionWithEvents( |
| if (!target) |
| return; |
| + // LOG(ERROR)<<"aba: tagName:"<<target->tagName().utf8().data(); |
| + // LOG(ERROR)<<"aba: oldText:"<<oldText.utf8().data(); |
| + /* |
| + String oldText2 = oldText; |
| + // No need to preserve style for 'input' element, so we can delete the |
| + // existing composition and insert new text. |
| + if(target->tagName() == String("INPUT")) |
| + oldText2 = emptyString(); |
| + |
| + if(!newText.isEmpty() && !oldText2.isEmpty()) { |
| + DCHECK(oldText2 == frame.selectedText())<<"oldText:["<<oldText.utf8().data() |
| + <<"] selected:["<<frame.selectedText().utf8().data()<<"]"; |
| + } |
| + |
| + */ |
| // TODO(chongz): Fire 'beforeinput' for the composed text being |
| // replaced/deleted. |
| @@ -122,12 +137,23 @@ void insertTextDuringCompositionWithEvents( |
| if (!frame.document()) |
| return; |
| + // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets |
| + // needs to be audited. see http://crbug.com/590369 for more details. |
| + frame.document()->updateStyleAndLayoutIgnorePendingStylesheets(); |
| + |
| + // needIncrementalInsertion? |
| + const bool isIncrementalInsertion = |
| + !frame.selectedText().isEmpty() && !text.isEmpty(); |
| + // or |
| + // !frame.selectedText().isEmpty(); |
| + // patch set 30 works... |
| + |
| switch (compositionType) { |
| case TypingCommand::TextCompositionType::TextCompositionUpdate: |
| + case TypingCommand::TextCompositionType::TextCompositionConfirm: |
| TypingCommand::insertText(*frame.document(), text, options, |
| - compositionType); |
| + compositionType, isIncrementalInsertion); |
| break; |
| - case TypingCommand::TextCompositionType::TextCompositionConfirm: |
| case TypingCommand::TextCompositionType::TextCompositionCancel: |
| // TODO(chongz): Use TypingCommand::insertText after TextEvent was |
| // removed. (Removed from spec since 2012) |
| @@ -171,7 +197,7 @@ InputMethodController* InputMethodController::create(LocalFrame& frame) { |
| } |
| InputMethodController::InputMethodController(LocalFrame& frame) |
| - : m_frame(&frame), m_isDirty(false), m_hasComposition(false) {} |
| + : m_frame(&frame), m_hasComposition(false) {} |
| InputMethodController::~InputMethodController() = default; |
| @@ -200,7 +226,6 @@ void InputMethodController::clear() { |
| m_compositionRange->collapse(true); |
| } |
| document().markers().removeMarkers(DocumentMarker::Composition); |
| - m_isDirty = false; |
| } |
| void InputMethodController::contextDestroyed() { |
| @@ -269,14 +294,6 @@ bool InputMethodController::replaceComposition(const String& text) { |
| if (!hasComposition()) |
| return false; |
| - // If the composition was set from existing text and didn't change, then |
| - // there's nothing to do here (and we should avoid doing anything as that |
| - // may clobber multi-node styled text). |
| - if (!m_isDirty && composingText() == text) { |
| - clear(); |
| - return true; |
| - } |
| - |
| // Select the text that will be deleted or replaced. |
| selectComposition(); |
| @@ -286,14 +303,22 @@ bool InputMethodController::replaceComposition(const String& text) { |
| if (!isAvailable()) |
| return false; |
| + // ??? |
| + // clear(); // do we need clear??? |
|
yabinh
2017/02/08 09:59:59
It turns out that we should clear.
|
| + |
| // If text is empty, then delete the old composition here. If text is |
| // non-empty, InsertTextCommand::input will delete the old composition with |
| // an optimized replace operation. |
| - if (text.isEmpty()) |
| + if (text.isEmpty()) { |
| TypingCommand::deleteSelection(document(), 0); |
| - clear(); |
| + // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets |
| + // needs to be audited. see http://crbug.com/590369 for more details. |
| + document().updateStyleAndLayoutIgnorePendingStylesheets(); |
| + } |
| + // LOG(ERROR) << "hyb: frame().selectedText():" |
| + //<< frame().selectedText().utf8().data(); |
| insertTextDuringCompositionWithEvents( |
| frame(), text, 0, |
| TypingCommand::TextCompositionType::TextCompositionConfirm); |
| @@ -380,6 +405,9 @@ void InputMethodController::cancelComposition() { |
| InputEvent::InputType::DeleteComposedCharacterBackward, nullAtom, |
| InputEvent::EventCancelable::NotCancelable); |
| dispatchCompositionUpdateEvent(frame(), emptyString()); |
| + |
| + // LOG(ERROR) << "hyb: frame().selectedText():" |
| + //<< frame().selectedText().utf8().data(); |
| insertTextDuringCompositionWithEvents( |
| frame(), emptyString(), 0, |
| TypingCommand::TextCompositionType::TextCompositionCancel); |
| @@ -411,28 +439,6 @@ void InputMethodController::cancelCompositionIfSelectionIsInvalid() { |
| frame().chromeClient().didCancelCompositionOnSelectionChange(); |
| } |
| -static size_t computeCommonPrefixLength(const String& str1, |
| - const String& str2) { |
| - const size_t maxCommonPrefixLength = std::min(str1.length(), str2.length()); |
| - for (size_t index = 0; index < maxCommonPrefixLength; ++index) { |
| - if (str1[index] != str2[index]) |
| - return index; |
| - } |
| - return maxCommonPrefixLength; |
| -} |
| - |
| -static size_t computeCommonSuffixLength(const String& str1, |
| - const String& str2) { |
| - const size_t length1 = str1.length(); |
| - const size_t length2 = str2.length(); |
| - const size_t maxCommonSuffixLength = std::min(length1, length2); |
| - for (size_t index = 0; index < maxCommonSuffixLength; ++index) { |
| - if (str1[length1 - index - 1] != str2[length2 - index - 1]) |
| - return index; |
| - } |
| - return maxCommonSuffixLength; |
| -} |
| - |
| // If current position is at grapheme boundary, return 0; otherwise, return the |
| // distance to its nearest left grapheme boundary. |
| static size_t computeDistanceToLeftGraphemeBoundary(const Position& position) { |
| @@ -446,23 +452,6 @@ static size_t computeDistanceToLeftGraphemeBoundary(const Position& position) { |
| adjustedPosition.computeOffsetInContainerNode()); |
| } |
| -static size_t computeCommonGraphemeClusterPrefixLengthForSetComposition( |
| - const String& oldText, |
| - const String& newText, |
| - const Element* rootEditableElement) { |
| - const size_t commonPrefixLength = computeCommonPrefixLength(oldText, newText); |
| - |
| - // For grapheme cluster, we should adjust it for grapheme boundary. |
| - const EphemeralRange& range = |
| - PlainTextRange(0, commonPrefixLength).createRange(*rootEditableElement); |
| - if (range.isNull()) |
| - return 0; |
| - const Position& position = range.endPosition(); |
| - const size_t diff = computeDistanceToLeftGraphemeBoundary(position); |
| - DCHECK_GE(commonPrefixLength, diff); |
| - return commonPrefixLength - diff; |
| -} |
| - |
| // If current position is at grapheme boundary, return 0; otherwise, return the |
| // distance to its nearest right grapheme boundary. |
| static size_t computeDistanceToRightGraphemeBoundary(const Position& position) { |
| @@ -476,107 +465,6 @@ static size_t computeDistanceToRightGraphemeBoundary(const Position& position) { |
| position.computeOffsetInContainerNode()); |
| } |
| -static size_t computeCommonGraphemeClusterSuffixLengthForSetComposition( |
| - const String& oldText, |
| - const String& newText, |
| - const Element* rootEditableElement) { |
| - const size_t commonSuffixLength = computeCommonSuffixLength(oldText, newText); |
| - |
| - // For grapheme cluster, we should adjust it for grapheme boundary. |
| - const EphemeralRange& range = |
| - PlainTextRange(0, oldText.length() - commonSuffixLength) |
| - .createRange(*rootEditableElement); |
| - if (range.isNull()) |
| - return 0; |
| - const Position& position = range.endPosition(); |
| - const size_t diff = computeDistanceToRightGraphemeBoundary(position); |
| - DCHECK_GE(commonSuffixLength, diff); |
| - return commonSuffixLength - diff; |
| -} |
| - |
| -void InputMethodController::setCompositionWithIncrementalText( |
| - const String& text, |
| - const Vector<CompositionUnderline>& underlines, |
| - int selectionStart, |
| - int selectionEnd) { |
| - Element* editable = frame().selection().rootEditableElement(); |
| - if (!editable) |
| - return; |
| - |
| - DCHECK_LE(selectionStart, selectionEnd); |
| - String composing = composingText(); |
| - const size_t commonPrefixLength = |
| - computeCommonGraphemeClusterPrefixLengthForSetComposition(composing, text, |
| - editable); |
| - |
| - // We should ignore common prefix when finding common suffix. |
| - const size_t commonSuffixLength = |
| - computeCommonGraphemeClusterSuffixLengthForSetComposition( |
| - composing.right(composing.length() - commonPrefixLength), |
| - text.right(text.length() - commonPrefixLength), editable); |
| - |
| - const bool inserting = |
| - text.length() > commonPrefixLength + commonSuffixLength; |
| - const bool deleting = |
| - composing.length() > commonPrefixLength + commonSuffixLength; |
| - |
| - if (inserting || deleting) { |
| - // Select the text to be deleted. |
| - const size_t compositionStart = |
| - PlainTextRange::create(*editable, compositionEphemeralRange()).start(); |
| - const size_t deletionStart = compositionStart + commonPrefixLength; |
| - const size_t deletionEnd = |
| - compositionStart + composing.length() - commonSuffixLength; |
| - const EphemeralRange& deletionRange = |
| - PlainTextRange(deletionStart, deletionEnd).createRange(*editable); |
| - Document& currentDocument = document(); |
| - frame().selection().setSelection( |
| - SelectionInDOMTree::Builder().setBaseAndExtent(deletionRange).build(), |
| - 0); |
| - clear(); |
| - |
| - // FrameSeleciton::setSelection() can change document associate to |frame|. |
| - if (!isAvailable() || currentDocument != document()) |
| - return; |
| - if (!currentDocument.focusedElement()) |
| - return; |
| - |
| - // Insert the incremental text. |
| - const size_t insertionLength = |
| - text.length() - commonPrefixLength - commonSuffixLength; |
| - const String& insertingText = |
| - text.substring(commonPrefixLength, insertionLength); |
| - insertTextDuringCompositionWithEvents(frame(), insertingText, |
| - TypingCommand::PreventSpellChecking, |
| - TypingCommand::TextCompositionUpdate); |
| - |
| - // Event handlers might destroy document. |
| - if (!isAvailable() || currentDocument != document()) |
| - return; |
| - |
| - // TODO(yosin): The use of updateStyleAndLayoutIgnorePendingStylesheets |
| - // needs to be audited. see http://crbug.com/590369 for more details. |
| - document().updateStyleAndLayoutIgnorePendingStylesheets(); |
| - |
| - // Now recreate the composition starting at its original start, and |
| - // apply the specified final selection offsets. |
| - setCompositionFromExistingText(underlines, compositionStart, |
| - compositionStart + text.length()); |
| - } |
| - |
| - selectComposition(); |
| - |
| - // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets |
| - // needs to be audited. see http://crbug.com/590369 for more details. |
| - document().updateStyleAndLayoutIgnorePendingStylesheets(); |
| - |
| - const PlainTextRange& selectedRange = createSelectionRangeForSetComposition( |
| - selectionStart, selectionEnd, text.length()); |
| - // We shouldn't close typing in the middle of setComposition. |
| - setEditableSelectionOffsets(selectedRange, NotUserTriggered); |
| - m_isDirty = true; |
| -} |
| - |
| void InputMethodController::setComposition( |
| const String& text, |
| const Vector<CompositionUnderline>& underlines, |
| @@ -589,14 +477,6 @@ void InputMethodController::setComposition( |
| // See https://bugs.webkit.org/show_bug.cgi?id=46868 |
| document().updateStyleAndLayoutTree(); |
| - // When the IME only wants to change a few characters at the end of the |
| - // composition, only touch those characters in order to preserve rich text |
| - // substructure. |
| - if (hasComposition() && text.length()) { |
| - return setCompositionWithIncrementalText(text, underlines, selectionStart, |
| - selectionEnd); |
| - } |
| - |
| selectComposition(); |
| if (frame().selection().isNone()) |
| @@ -663,8 +543,11 @@ void InputMethodController::setComposition( |
| DCHECK(!text.isEmpty()); |
| + // const String& composing = composingText(); |
| clear(); |
| + // LOG(ERROR) << "hyb: frame().selectedText():" |
| + //<< frame().selectedText().utf8().data(); |
| insertTextDuringCompositionWithEvents( |
| frame(), text, |
| TypingCommand::SelectInsertedText | TypingCommand::PreventSpellChecking, |
| @@ -685,20 +568,15 @@ void InputMethodController::setComposition( |
| Position extent = frame().selection().extent(); |
| Node* extentNode = extent.anchorNode(); |
| - if (baseNode != extentNode) |
| - return; |
| unsigned extentOffset = extent.computeOffsetInContainerNode(); |
| unsigned baseOffset = base.computeOffsetInContainerNode(); |
| - if (baseOffset + text.length() != extentOffset) |
| - return; |
| - m_isDirty = true; |
| m_hasComposition = true; |
| if (!m_compositionRange) |
| m_compositionRange = Range::create(document()); |
| m_compositionRange->setStart(baseNode, baseOffset); |
| - m_compositionRange->setEnd(baseNode, extentOffset); |
| + m_compositionRange->setEnd(extentNode, extentOffset); |
| if (baseNode->layoutObject()) |
| baseNode->layoutObject()->setShouldDoFullPaintInvalidation(); |