Bug 1437680 - Don't change media feature in the callback for MediaQueryListEvent. r=jryans

In our current implementation for media query stuff, it's possible to change
media features inside the callback for media query list events and the events
are dispatched at an early stage in flush pending styles.  Whereas at a later
stage in flush pending styles, we don't allow pending media feature changes.
According to the spec [1], the media query list events have to be dispatched
in a different place from flush pending styles.  We have to move the event
handling someday, but as for test_contentViewer_overrideDPPX.html, we don't
need to change media features inside the callbacks (precisely it has done
inside a Promise for the callbacks), so we add setTimeout call to make sure
the media feature changes are processed after the flush pending styles.

[1] https://html.spec.whatwg.org/multipage/webappapis.html#processing-model-8

MozReview-Commit-ID: 5VoQJ1uGUwD

--HG--
extra : rebase_source : 47443f7dc00aa62a35f570796eeec547526d8142
This commit is contained in:
Hiroyuki Ikezoe 2018-02-13 09:41:44 +09:00
Родитель 23bfb18da8
Коммит 272f2f4dd8
1 изменённых файлов: 24 добавлений и 41 удалений

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

@ -78,6 +78,22 @@ const assertValuesAreInitial = () => {
"fullZoom has the original value.");
}
const waitForMediaQueryListEvent = (mediaQueryList) => {
return new Promise(resolve => {
mediaQueryList.addListener(function listener() {
ok(true, "MediaQueryList's listener invoked for " + mediaQueryList.media);
mediaQueryList.removeListener(listener);
// We need to evacuate a media query list event to avoid changing any
// media features inside this callback (and microtasks for the callbacks),
// because we currently dispatch media query list events during flush
// pending styles, and we want to make sure there is no pending media
// feature changes after the event handling.
// This workaround should be dropped in bug 1437688.
setTimeout(resolve, 0);
});
});
}
const gTests = {
"test overrideDPPX with devicePixelRatio": (done) => {
assertValuesAreInitial();
@ -234,24 +250,10 @@ const gTests = {
assertValuesAreInitial();
let promises = [
new Promise(resolve => {
let mql = window.matchMedia(`(resolution: ${dppx}dppx)`);
mql.addListener(function listener() {
ok(true, "MediaQueryList's listener invoked.")
mql.removeListener(listener);
resolve();
});
}),
new Promise(resolve => {
let mql = frameWindow.matchMedia(`(resolution: ${dppx}dppx)`);
mql.addListener(function listener() {
ok(true, "frame's MediaQueryList's listener invoked.")
mql.removeListener(listener);
resolve();
});
})
waitForMediaQueryListEvent(
window.matchMedia(`(resolution: ${dppx}dppx)`)),
waitForMediaQueryListEvent(
frameWindow.matchMedia(`(resolution: ${dppx}dppx)`)),
];
Promise.all(promises)
@ -263,30 +265,11 @@ const gTests = {
"test OverrideDPPX with MediaQueryList and fullZoom": (done) => {
assertValuesAreInitial();
let overridden = false;
let promises = [
new Promise(resolve => {
let mql = window.matchMedia(`(resolution: ${dppx}dppx)`);
mql.addListener(function listener() {
ok(true, "MediaQueryList's listener for dppx invoked.");
mql.removeListener(listener);
overridden = true;
resolve();
});
}),
new Promise(resolve => {
let mql = window.matchMedia(`(resolution: ${originalDPR * zoom}dppx)`);
mql.addListener(function listener() {
ok(overridden,
"MediaQueryList's listener for zoom invoked in the right order");
mql.removeListener(listener);
resolve();
});
})
waitForMediaQueryListEvent(
window.matchMedia(`(resolution: ${dppx}dppx)`)),
waitForMediaQueryListEvent(
window.matchMedia(`(resolution: ${originalDPR * zoom}dppx)`)),
];
setOverrideDPPX(dppx);