| 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 7ab9a7a8060082adcaa07fe937f0226e12422237..0854ba23ba8aaf8dcf222e56bd2b189e959a9d47 100644 | 
| --- a/third_party/WebKit/Source/core/editing/InputMethodController.cpp | 
| +++ b/third_party/WebKit/Source/core/editing/InputMethodController.cpp | 
| @@ -868,6 +868,69 @@ void InputMethodController::extendSelectionAndDelete(int before, int after) { | 
| TypingCommand::deleteSelection(*frame().document()); | 
| } | 
|  | 
| +// TODO(yabinh): We should reduce the number of selectionchange events. | 
| +void InputMethodController::deleteSurroundingText(int before, int after) { | 
| +  if (!editor().canEdit()) | 
| +    return; | 
| +  const PlainTextRange selectionOffsets(getSelectionOffsets()); | 
| +  if (selectionOffsets.isNull()) | 
| +    return; | 
| +  Element* const rootEditableElement = | 
| +      frame().selection().rootEditableElement(); | 
| +  if (!rootEditableElement) | 
| +    return; | 
| +  int selectionStart = static_cast<int>(selectionOffsets.start()); | 
| +  int selectionEnd = static_cast<int>(selectionOffsets.end()); | 
| + | 
| +  // Select the text to be deleted before selectionStart. | 
| +  if (before > 0 && selectionStart > 0) { | 
| +    // In case of exceeding the left boundary. | 
| +    const int start = std::max(selectionStart - before, 0); | 
| + | 
| +    const EphemeralRange& range = | 
| +        PlainTextRange(0, start).createRange(*rootEditableElement); | 
| +    if (range.isNull()) | 
| +      return; | 
| +    const Position& position = range.endPosition(); | 
| + | 
| +    // Adjust the start of selection for multi-code text(a grapheme cluster | 
| +    // contains more than one code point). TODO(yabinh): Adjustment should be | 
| +    // based on code point instead of grapheme cluster. | 
| +    const size_t diff = computeDistanceToLeftGraphemeBoundary(position); | 
| +    const int adjustedStart = start - static_cast<int>(diff); | 
| +    if (!setSelectionOffsets(PlainTextRange(adjustedStart, selectionStart))) | 
| +      return; | 
| +    TypingCommand::deleteSelection(*frame().document()); | 
| + | 
| +    selectionEnd = selectionEnd - (selectionStart - adjustedStart); | 
| +    selectionStart = adjustedStart; | 
| +  } | 
| + | 
| +  // Select the text to be deleted after selectionEnd. | 
| +  if (after > 0) { | 
| +    // Adjust the deleted range in case of exceeding the right boundary. | 
| +    const PlainTextRange range(0, selectionEnd + after); | 
| +    if (range.isNull()) | 
| +      return; | 
| +    const EphemeralRange& validRange = range.createRange(*rootEditableElement); | 
| +    if (validRange.isNull()) | 
| +      return; | 
| +    const int end = | 
| +        PlainTextRange::create(*rootEditableElement, validRange).end(); | 
| +    const Position& position = validRange.endPosition(); | 
| + | 
| +    // Adjust the end of selection for multi-code text. TODO(yabinh): Adjustment | 
| +    // should be based on code point instead of grapheme cluster. | 
| +    const size_t diff = computeDistanceToRightGraphemeBoundary(position); | 
| +    const int adjustedEnd = end + static_cast<int>(diff); | 
| +    if (!setSelectionOffsets(PlainTextRange(selectionEnd, adjustedEnd))) | 
| +      return; | 
| +    TypingCommand::deleteSelection(*frame().document()); | 
| +  } | 
| + | 
| +  setSelectionOffsets(PlainTextRange(selectionStart, selectionEnd)); | 
| +} | 
| + | 
| DEFINE_TRACE(InputMethodController) { | 
| visitor->trace(m_frame); | 
| visitor->trace(m_compositionRange); | 
|  |