Bug 1725806 - Part 3. Autocorrect support in InputContext. r=masayuki

Add autocorrect flag to `InputContext` to handle this by widget.

Since autocorrect is on-by-default, `mAutocorrect` is true by constructor.

But, I would like off-by-default in Chrome. Since Chrome UI may not want to
enable autocorrect by default such as bug 1881783.

Differential Revision: https://phabricator.services.mozilla.com/D221571
This commit is contained in:
Makoto Kato 2024-10-28 17:06:49 +00:00
parent 234fe7b310
commit dc8f6495f8
10 changed files with 172 additions and 1 deletions

View File

@ -2316,6 +2316,16 @@ nsDOMWindowUtils::GetFocusedAutocapitalize(nsAString& aAutocapitalize) {
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::GetFocusedAutocorrect(bool* aAutocorrect) {
nsCOMPtr<nsIWidget> widget = GetWidget();
if (!widget) {
return NS_ERROR_FAILURE;
}
*aAutocorrect = widget->GetInputContext().mAutocorrect;
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::GetViewId(Element* aElement, nsViewID* aResult) {
if (aElement && nsLayoutUtils::FindIDFor(aElement, aResult)) {

View File

@ -1904,6 +1904,31 @@ static void GetAutocapitalize(const IMEState& aState, const Element& aElement,
}
}
static bool GetAutocorrect(const IMEState& aState, const Element& aElement,
const InputContext& aInputContext) {
if (!StaticPrefs::dom_forms_autocorrect()) {
#ifdef ANDROID
// Autocorrect was on-by-default on Android by bug 806349, despite
// autocorrect preference.
return true;
#else
return false;
#endif
}
if (aElement.IsHTMLElement() && aState.IsEditable()) {
if (nsContentUtils::IsChromeDoc(aElement.OwnerDoc()) &&
!aElement.HasAttr(nsGkAtoms::autocorrect)) {
// Since Chrome UI may not want to enable autocorrect by default such as
// bug 1881783.
return false;
}
return nsGenericHTMLElement::FromNode(&aElement)->Autocorrect();
}
return true;
}
// static
void IMEStateManager::SetIMEState(const IMEState& aState,
const nsPresContext* aPresContext,
@ -1972,6 +1997,7 @@ void IMEStateManager::SetIMEState(const IMEState& aState,
GetInputMode(aState, *focusedElement, context.mHTMLInputMode);
GetAutocapitalize(aState, *focusedElement, context,
context.mAutocapitalize);
context.mAutocorrect = GetAutocorrect(aState, *focusedElement, context);
}
if (aAction.mCause == InputContextAction::CAUSE_UNKNOWN &&

View File

@ -1779,6 +1779,11 @@ interface nsIDOMWindowUtils : nsISupports {
*/
readonly attribute AString focusedAutocapitalize;
/**
* Get the autocorrect of the currently focused editing host, if any.
*/
readonly attribute boolean focusedAutocorrect;
/**
* Find the view ID for a given element. This is the reverse of
* findElementWithViewId().

View File

@ -244,7 +244,9 @@ std::ostream& operator<<(std::ostream& aStream, const InputContext& aContext) {
<< aContext.mHTMLInputType << "\", mHTMLInputMode=\""
<< aContext.mHTMLInputMode << "\", mActionHint=\""
<< aContext.mActionHint << "\", mAutocapitalize=\""
<< aContext.mAutocapitalize << "\", mIsPrivateBrowsing="
<< aContext.mAutocapitalize
<< "\", mAutocorrect=" << (aContext.mAutocorrect ? "true" : "false")
<< ", mIsPrivateBrowsing="
<< (aContext.mInPrivateBrowsing ? "true" : "false") << " }";
return aStream;
}

View File

@ -425,6 +425,7 @@ struct InputContext final {
mHTMLInputMode.Truncate();
mActionHint.Truncate();
mAutocapitalize.Truncate();
mAutocorrect = true;
}
bool IsPasswordEditor() const {
@ -466,6 +467,11 @@ struct InputContext final {
#if defined(ANDROID) || defined(XP_IOS)
// enterkeyhint is only supported by Android IME API and iOS API.
mActionHint != aOldContext.mActionHint ||
#endif
#if defined(ANDROID) || defined(XP_DARWIN)
// autocorrect is only supported by Android IME API, macOS text
// substitution and iOS API.
mAutocorrect != aOldContext.mAutocorrect ||
#endif
false;
}
@ -487,6 +493,9 @@ struct InputContext final {
/* A hint for autocapitalize */
nsString mAutocapitalize;
/* A hint for autocorrect */
bool mAutocorrect = true; // on-by-default
/**
* mOrigin indicates whether this focus event refers to main or remote
* content.

View File

@ -846,6 +846,7 @@ struct ParamTraits<mozilla::widget::InputContext> {
WriteParam(aWriter, aParam.mHTMLInputMode);
WriteParam(aWriter, aParam.mActionHint);
WriteParam(aWriter, aParam.mAutocapitalize);
WriteParam(aWriter, aParam.mAutocorrect);
WriteParam(aWriter, aParam.mOrigin);
WriteParam(aWriter, aParam.mHasHandledUserInput);
WriteParam(aWriter, aParam.mInPrivateBrowsing);
@ -858,6 +859,7 @@ struct ParamTraits<mozilla::widget::InputContext> {
ReadParam(aReader, &aResult->mHTMLInputMode) &&
ReadParam(aReader, &aResult->mActionHint) &&
ReadParam(aReader, &aResult->mAutocapitalize) &&
ReadParam(aReader, &aResult->mAutocorrect) &&
ReadParam(aReader, &aResult->mOrigin) &&
ReadParam(aReader, &aResult->mHasHandledUserInput) &&
ReadParam(aReader, &aResult->mInPrivateBrowsing) &&

View File

@ -8,6 +8,8 @@ tags = "os_integration"
["test_alwaysontop_focus.xhtml"]
["test_autocorrect_in_parent.html"]
# Privacy relevant
["test_bug343416.xhtml"]

View File

@ -18,6 +18,8 @@ skip-if = [
["test_autocapitalize.html"]
["test_autocorrect.html"]
["test_clipboard.html"]
skip-if = [
"headless", # bug 1852983

View File

@ -0,0 +1,66 @@
<!DOCTYPE html>
<html>
<head>
<title>Tests for autocorrect</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script src="/tests/SimpleTest/SpecialPowers.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none"></div>
<div>
<input type="text" id="a1"><br>
<input type="text" id="a2" autocorrect="on"><br>
<input type="text" id="a3" autocorrect="off"><br>
<input type="url" id="a4" autocorrect="on"><br>
<input type="email" id="a5" autocorrect="on"><br>
<input type="password" id="a6" autocorrect="on"><br>
<textarea id="b1"></textarea><br>
<textarea id="b2" autocorrect="on"></textarea><br>
<textarea id="b3" autocorrect="off"></textarea><br>
<div contenteditable id="c1"></div><br>
<div contenteditable id="c2" autocorrect="on"></div><br>
<div contenteditable id="c3" autocorrect="off"></div><br>
<form><input type="text" id="d1" autocorrect="on"></form><br>
<form autocorrect="on"><input type="text" id="d2"></form><br>
<form autocorrect="off"><input type="text" id="d3" autocorrect="on"></form><br>
</div>
<pre id="test">
<script class="testbody" type="application/javascript">
SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(async () => {
await SpecialPowers.setBoolPref("dom.forms.autocorrect", true);
const tests = [
{ id: "a1", autocorrect: true, desc: "input without autocorrect" },
{ id: "a2", autocorrect: true, desc: "input with autocorrect=on" },
{ id: "a3", autocorrect: false, desc: "input with autocorrect=off" },
{ id: "a4", autocorrect: false, desc: "input type=url with autocorrect=on" },
{ id: "a5", autocorrect: false, desc: "input type=email with autocorrect=on" },
{ id: "a6", autocorrect: false, desc: "input type=password with autocorrect=on" },
{ id: "b1", autocorrect: true, desc: "textarea without autocorrect" },
{ id: "b2", autocorrect: true, desc: "textarea with autocorrect=on" },
{ id: "b3", autocorrect: false, desc: "textarea with autocorrect=off" },
{ id: "c1", autocorrect: true, desc: "contenteditable without autocorrect" },
{ id: "c2", autocorrect: true, desc: "contenteditable with autocorrect=on" },
{ id: "c3", autocorrect: false, desc: "contenteditable with autocorrect=off" },
{ id: "d1", autocorrect: true, desc: "input with autocorrect=on in form" },
{ id: "d2", autocorrect: true, desc: "input in form with autocorrect=on" },
{ id: "d3", autocorrect: true, desc: "input with autocorrect=on in form" },
];
for (let test of tests) {
document.getElementById(test.id).focus();
is(SpecialPowers.DOMWindowUtils.focusedAutocorrect, test.autocorrect, test.desc);
}
SimpleTest.finish();
});
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,47 @@
<!DOCTYPE html>
<html>
<head>
<title>Tests for default of autocorrect in parent</title>
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="chrome://mochikit/content/tests/SimpleTest/test.css">
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none"></div>
<div>
<input type="text" id="a1"><br>
<input type="text" id="a2" autocorrect="on"><br>
<textarea id="b1"></textarea><br>
<textarea id="b2" autocorrect="on"></textarea><br>
<div contenteditable id="c1"></div><br>
<div contenteditable id="c2" autocorrect="on"></div><br>
</div>
<pre id="test">
<script class="testbody" type="application/javascript">
SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(async () => {
await SpecialPowers.setBoolPref("dom.forms.autocorrect", true);
const tests = [
{ id: "a1", autocorrect: false, desc: "input without autocorrect" },
{ id: "a2", autocorrect: true, desc: "input with autocorrect" },
{ id: "b1", autocorrect: false, desc: "textarea without autocorrect" },
{ id: "b2", autocorrect: true, desc: "textarea with autocorrect" },
{ id: "c1", autocorrect: false, desc: "contenteditable without autocorrect" },
{ id: "c2", autocorrect: true, desc: "contenteditable with autocorrect" },
];
for (let test of tests) {
document.getElementById(test.id).focus();
is(window.windowUtils.focusedAutocorrect, test.autocorrect, test.desc);
}
SimpleTest.finish();
});
</script>
</pre>
</body>
</html>