зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
c1e04f8525
Коммит
7bd2c26c2c
|
@ -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: [ ],
|
||||
},
|
||||
|
|
Загрузка…
Ссылка в новой задаче