Commit 193fde17 authored by Shimi Zhang's avatar Shimi Zhang Committed by Commit Bot

[Android] Add FLAG_AUTO_CORRESION support for spell checking

Add basic support for SuggestionSpan.FLAG_AUTO_CORRESION flag, make it
show underline for this type.

Bug: 869261
Cq-Include-Trybots: luci.chromium.try:linux_layout_tests_layout_ng
Change-Id: I6db973826ebf761902506905d31968ec4b78819a
Reviewed-on: https://chromium-review.googlesource.com/c/1285312
Commit-Queue: Shimi Zhang <ctzsm@chromium.org>
Reviewed-by: default avatarYoshifumi Inoue <yosin@chromium.org>
Reviewed-by: default avatarChangwan Ryu <changwan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#601669}
parent 0865005c
......@@ -1011,23 +1011,26 @@ public class ImeAdapterImpl implements ImeAdapter, WindowEventObserver, UserData
} else if (span instanceof SuggestionSpan) {
final SuggestionSpan suggestionSpan = (SuggestionSpan) span;
// We currently only support FLAG_EASY_CORRECT and FLAG_MISSPELLED SuggestionSpans.
// Other types:
// - FLAG_AUTO_CORRECTION is used e.g. by Samsung's IME to flash a blue background
// on a word being replaced by an autocorrect suggestion. We don't currently
// support this.
//
// We support all three flags of SuggestionSpans with caveat:
// - FLAG_EASY_CORRECT, full support.
// - FLAG_MISSPELLED, full support.
// - FLAG_AUTO_CORRECTION, no animation support for this flag for
// commitCorrection().
// Note that FLAG_AUTO_CORRECTION has precedence than the other two flags.
// Other cases:
// - Some IMEs (e.g. the AOSP keyboard on Jelly Bean) add SuggestionSpans with no
// flags set and no underline color to add suggestions to words marked as
// misspelled (instead of having the spell checker return the suggestions when
// called). We don't support these either.
final boolean isEasyCorrectSpan =
(suggestionSpan.getFlags() & SuggestionSpan.FLAG_EASY_CORRECT) != 0;
final boolean isMisspellingSpan =
(suggestionSpan.getFlags() & SuggestionSpan.FLAG_MISSPELLED) != 0;
if (suggestionSpan.getFlags() != SuggestionSpan.FLAG_EASY_CORRECT
&& !isMisspellingSpan) {
continue;
}
final boolean isAutoCorrectionSpan =
(suggestionSpan.getFlags() & SuggestionSpan.FLAG_AUTO_CORRECTION) != 0;
if (!isEasyCorrectSpan && !isMisspellingSpan && !isAutoCorrectionSpan) continue;
// Copied from Android's Editor.java so we use the same colors
// as the native Android text widget.
......@@ -1037,10 +1040,14 @@ public class ImeAdapterImpl implements ImeAdapter, WindowEventObserver, UserData
final int suggestionHighlightColor =
(underlineColor & 0x00FFFFFF) + (newAlpha << 24);
// In native side, we treat FLAG_AUTO_CORRECTION span as kMisspellingSuggestion
// marker with 0 suggestion.
nativeAppendSuggestionSpan(imeTextSpans,
spannableString.getSpanStart(suggestionSpan),
spannableString.getSpanEnd(suggestionSpan), isMisspellingSpan,
underlineColor, suggestionHighlightColor, suggestionSpan.getSuggestions());
spannableString.getSpanEnd(suggestionSpan),
isMisspellingSpan || isAutoCorrectionSpan, underlineColor,
suggestionHighlightColor,
isAutoCorrectionSpan ? new String[0] : suggestionSpan.getSuggestions());
}
}
}
......
......@@ -290,6 +290,25 @@ public class TextSuggestionMenuTest {
waitForMenuToHide(webContents);
}
@Test
@LargeTest
public void testAutoCorrectionSuggestionSpan() throws InterruptedException, Throwable {
WebContents webContents = mRule.getWebContents();
DOMUtils.focusNode(webContents, "div");
SpannableString textToCommit = new SpannableString("hello");
SuggestionSpan suggestionSpan = new SuggestionSpan(
mRule.getActivity(), new String[0], SuggestionSpan.FLAG_AUTO_CORRECTION);
textToCommit.setSpan(suggestionSpan, 0, 5, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
mRule.commitText(textToCommit, 1);
Assert.assertEquals("1",
JavaScriptUtils.executeJavaScriptAndWaitForResult(webContents,
"internals.markerCountForNode("
+ "document.getElementById('div').firstChild, 'suggestion')"));
}
private void waitForMenuToShow(WebContents webContents) {
CriteriaHelper.pollUiThread(new Criteria() {
@Override
......
......@@ -232,6 +232,11 @@ void TextSuggestionController::HandlePotentialSuggestionTap(
if (!node_and_marker.first)
return;
const SuggestionMarker* marker =
ToSuggestionMarkerOrNull(node_and_marker.second);
if (marker && marker->Suggestions().IsEmpty())
return;
if (!text_suggestion_host_) {
GetFrame().GetInterfaceProvider().GetInterface(
mojo::MakeRequest(&text_suggestion_host_));
......
......@@ -47,6 +47,7 @@ class CORE_EXPORT TextSuggestionController final
void Trace(blink::Visitor*) override;
private:
friend class TextSuggestionControllerTest;
Document& GetDocument() const;
bool IsAvailable() const;
LocalFrame& GetFrame() const;
......
......@@ -17,7 +17,15 @@ using ws::mojom::ImeTextSpanThickness;
namespace blink {
class TextSuggestionControllerTest : public EditingTestBase {};
class TextSuggestionControllerTest : public EditingTestBase {
public:
bool IsTextSuggestionHostAvailable() {
return bool(GetDocument()
.GetFrame()
->GetTextSuggestionController()
.text_suggestion_host_);
}
};
TEST_F(TextSuggestionControllerTest, ApplySpellCheckSuggestion) {
SetBodyContent(
......@@ -439,4 +447,66 @@ TEST_F(TextSuggestionControllerTest, CallbackHappensAfterDocumentDestroyed) {
frame.GetTextSuggestionController().SuggestionMenuTimeoutCallback(0);
}
TEST_F(TextSuggestionControllerTest, SuggestionMarkerWithEmptySuggestion) {
SetBodyContent(
"<div contenteditable>"
"hello"
"</div>");
Element* div = GetDocument().QuerySelector("div");
Text* text = ToText(div->firstChild());
// Set suggestion marker with empty suggestion list.
GetDocument().Markers().AddSuggestionMarker(
EphemeralRange(Position(text, 0), Position(text, 5)),
SuggestionMarkerProperties::Builder()
.SetSuggestions(Vector<String>())
.Build());
// Set the caret inside the word.
GetDocument().GetFrame()->Selection().SetSelectionAndEndTyping(
SelectionInDOMTree::Builder()
.SetBaseAndExtent(Position(text, 3), Position(text, 3))
.Build());
// Handle potential suggestion tap on the caret position.
GetDocument()
.GetFrame()
->GetTextSuggestionController()
.HandlePotentialSuggestionTap(PositionInFlatTree(text, 3));
// We don't trigger menu in this case so there shouldn't be any mojom
// connection available.
EXPECT_FALSE(IsTextSuggestionHostAvailable());
}
TEST_F(TextSuggestionControllerTest, SuggestionMarkerWithSuggestion) {
SetBodyContent(
"<div contenteditable>"
"hello"
"</div>");
Element* div = GetDocument().QuerySelector("div");
Text* text = ToText(div->firstChild());
// Set suggestion marker with two suggestions.
GetDocument().Markers().AddSuggestionMarker(
EphemeralRange(Position(text, 0), Position(text, 5)),
SuggestionMarkerProperties::Builder()
.SetSuggestions(Vector<String>({"marker1", "marker2"}))
.Build());
// Set the caret inside the word.
GetDocument().GetFrame()->Selection().SetSelectionAndEndTyping(
SelectionInDOMTree::Builder()
.SetBaseAndExtent(Position(text, 3), Position(text, 3))
.Build());
// Handle potential suggestion tap on the caret position.
GetDocument()
.GetFrame()
->GetTextSuggestionController()
.HandlePotentialSuggestionTap(PositionInFlatTree(text, 3));
EXPECT_TRUE(IsTextSuggestionHostAvailable());
}
} // namespace blink
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment