Bug 1288640 - Make TextComposition not dispatch eCompositionChange events (DOM "text" event) in the default group of web content r=smaug

The usage of our specific "text" event is enough low (0.0003%).  So, let's
stop dispatching the event in the default group of web content.  Once we
release this new behavior, we can get rid of dispatching the event even in
chrome.  Then, we can optimize the event order for new specs.

Differential Revision: https://phabricator.services.mozilla.com/D13034

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Masayuki Nakano 2018-11-27 13:26:51 +00:00
Родитель c1e04f8525
Коммит 7bd2c26c2c
7 изменённых файлов: 112 добавлений и 23 удалений

Просмотреть файл

@ -17,6 +17,7 @@
#include "mozilla/IMEStateManager.h"
#include "mozilla/MiscEvents.h"
#include "mozilla/Preferences.h"
#include "mozilla/StaticPrefs.h"
#include "mozilla/TextComposition.h"
#include "mozilla/TextEvents.h"
#include "mozilla/Unused.h"
@ -165,6 +166,11 @@ TextComposition::DispatchEvent(WidgetCompositionEvent* aDispatchEvent,
nsPluginInstanceOwner::GeneratePluginEvent(aOriginalEvent,
aDispatchEvent);
if (aDispatchEvent->mMessage == eCompositionChange &&
StaticPrefs::
dom_compositionevent_text_dispatch_only_system_group_in_content()) {
aDispatchEvent->mFlags.mOnlySystemGroupDispatchInContent = true;
}
EventDispatcher::Dispatch(mNode, mPresContext,
aDispatchEvent, nullptr, aStatus, aCallBack);

Просмотреть файл

@ -188,6 +188,7 @@ skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
[test_passive_listeners.html]
[test_paste_image.html]
skip-if = headless # Bug 1405869
[test_text_event_in_content.html]
[test_wheel_default_action.html]
skip-if = (verify && debug && (os == 'linux'))
[test_bug687787.html]

Просмотреть файл

@ -0,0 +1,71 @@
<!doctype html>
<html>
<head>
<title>Not dispatching DOM "text" event on web apps</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<input id="input">
<textarea id="textarea"></textarea>
<div contenteditable id="editor"><p><br></p></div>
<script>
SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(async function doTests() {
await SpecialPowers.pushPrefEnv({set: [
["dom.compositionevent.text.dispatch_only_system_group_in_content", true],
]});
for (let editorId of ["input", "textarea", "editor"]) {
let editor = document.getElementById(editorId);
editor.focus();
let fired = false;
function onText() {
fired = true;
}
editor.addEventListener("text", onText);
fired = false;
synthesizeCompositionChange({
composition: {string: "abc",
clauses: [{length: 3, attr: COMPOSITION_ATTR_RAW_CLAUSE}]},
caret: {start: 3, length: 0},
});
ok(!fired, `Starting composition shouldn't fire DOM "text" event in ${editorId}`);
fired = false;
synthesizeComposition({type: "compositioncommitasis", key: {key: "KEY_Enter"}});
ok(!fired, `Committing composition with the latest string shouldn't fire DOM "text" event in ${editorId}`);
fired = false;
synthesizeCompositionChange({
composition: {string: "def",
clauses: [{length: 3, attr: COMPOSITION_ATTR_RAW_CLAUSE}]},
caret: {start: 3, length: 0},
});
ok(!fired, `Restarting composition shouldn't fire DOM "text" event in ${editorId}`);
fired = false;
synthesizeComposition({type: "compositioncommit", data: "", key: {key: "KEY_Escape"}});
ok(!fired, `Committing composition with empty string shouldn't fire DOM "text" event in ${editorId}`);
fired = false;
synthesizeCompositionChange({
composition: {string: "de",
clauses: [{length: 2, attr: COMPOSITION_ATTR_RAW_CLAUSE}]},
caret: {start: 2, length: 0},
});
ok(!fired, `Restarting composition shouldn't fire DOM "text" event in ${editorId}`);
fired = false;
synthesizeComposition({type: "compositioncommit", data: "def", key: {key: "KEY_Escape"}});
ok(!fired, `Committing composition with new string shouldn't fire DOM "text" event in ${editorId}`);
fired = false;
synthesizeComposition({type: "compositioncommit", data: "ghi"});
ok(!fired, `Inserting string shouldn't fire DOM "text" event in ${editorId}`);
editor.removeEventListener("text", onText);
}
SimpleTest.finish();
});
</script>
</body>
</html>

Просмотреть файл

@ -79,14 +79,16 @@ SimpleTest.waitForFocus(() => {
clear();
// Committing at first text (eCompositionChange)
aEditor.focus();
aEditor.addEventListener("text", committer, true);
synthesizeCompositionChange({ composition: { string: "a", clauses: [{length: 1, attr: COMPOSITION_ATTR_RAW_CLAUSE }] },
caret: { start: 1, length: 0 }, key: { key: "a" }});
aEditor.removeEventListener("text", committer, true);
ok(!isComposing(), "composition in " + aEditor.id + " should be committed by text event handler");
is(value(), "", "composition in " + aEditor.id + " should have inserted any text since it's committed at first text");
clear();
if (!SpecialPowers.getBoolPref("dom.compositionevent.text.dispatch_only_system_group_in_content")) {
aEditor.focus();
aEditor.addEventListener("text", committer, true);
synthesizeCompositionChange({ composition: { string: "a", clauses: [{length: 1, attr: COMPOSITION_ATTR_RAW_CLAUSE }] },
caret: { start: 1, length: 0 }, key: { key: "a" }});
aEditor.removeEventListener("text", committer, true);
ok(!isComposing(), "composition in " + aEditor.id + " should be committed by text event handler");
is(value(), "", "composition in " + aEditor.id + " should have inserted any text since it's committed at first text");
clear();
}
// Committing at second compositionupdate
aEditor.focus();
@ -104,19 +106,21 @@ SimpleTest.waitForFocus(() => {
clear();
// Committing at second text (eCompositionChange)
aEditor.focus();
// FYI: "compositionstart" will be dispatched automatically.
synthesizeCompositionChange({ composition: { string: "a", clauses: [{length: 1, attr: COMPOSITION_ATTR_RAW_CLAUSE }] },
caret: { start: 1, length: 0 }, key: { key: "a" }});
ok(isComposing(), "composition should be in " + aEditor.id + " before dispatching second text");
is(value(), "a", "composition in " + aEditor.id + " should be 'a' before dispatching second text");
aEditor.addEventListener("text", committer, true);
synthesizeCompositionChange({ composition: { string: "ab", clauses: [{length: 2, attr: COMPOSITION_ATTR_RAW_CLAUSE }] },
caret: { start: 2, length: 0 }, key: { key: "b" }});
aEditor.removeEventListener("text", committer, true);
ok(!isComposing(), "composition in " + aEditor.id + " should be committed by text event handler");
is(value(), "ab", "composition in " + aEditor.id + " should have \"ab\" since IME committed with it");
clear();
if (!SpecialPowers.getBoolPref("dom.compositionevent.text.dispatch_only_system_group_in_content")) {
aEditor.focus();
// FYI: "compositionstart" will be dispatched automatically.
synthesizeCompositionChange({ composition: { string: "a", clauses: [{length: 1, attr: COMPOSITION_ATTR_RAW_CLAUSE }] },
caret: { start: 1, length: 0 }, key: { key: "a" }});
ok(isComposing(), "composition should be in " + aEditor.id + " before dispatching second text");
is(value(), "a", "composition in " + aEditor.id + " should be 'a' before dispatching second text");
aEditor.addEventListener("text", committer, true);
synthesizeCompositionChange({ composition: { string: "ab", clauses: [{length: 2, attr: COMPOSITION_ATTR_RAW_CLAUSE }] },
caret: { start: 2, length: 0 }, key: { key: "b" }});
aEditor.removeEventListener("text", committer, true);
ok(!isComposing(), "composition in " + aEditor.id + " should be committed by text event handler");
is(value(), "ab", "composition in " + aEditor.id + " should have \"ab\" since IME committed with it");
clear();
}
}
runTest(document.getElementById("input"));
runTest(document.getElementById("textarea"));

Просмотреть файл

@ -53,7 +53,6 @@ function runTests() {
editor.addEventListener("compositionstart", handler, true);
editor.addEventListener("compositionend", handler, true);
editor.addEventListener("compositionupdate", handler, true);
editor.addEventListener("text", handler, true);
// input first character
composingString = "\u306B";

Просмотреть файл

@ -179,6 +179,14 @@ VARCACHE_PREF(
)
#undef PREF_VALUE
// Whehter Mozilla specific "text" event should be dispatched only in the
// system group or not in content.
VARCACHE_PREF(
"dom.compositionevent.text.dispatch_only_system_group_in_content",
dom_compositionevent_text_dispatch_only_system_group_in_content,
bool, true
)
// How long a content process can take before closing its IPC channel
// after shutdown is initiated. If the process exceeds the timeout,
// we fear the worst and kill it.

Просмотреть файл

@ -337,7 +337,7 @@ const kTests = [
synthesizeComposition({ type: "compositioncommit", data: "\u306D", key: { key: "," } });
},
canRun: function () {
return true;
return !SpecialPowers.getBoolPref("dom.compositionevent.text.dispatch_only_system_group_in_content");
},
todoMismatch: [ ],
},