Bug 1601933 - Use visual viewport width or height for GeckoView::ScrollBy and ScrollTo. r=botond,rbarker,agi

Since bug 1514429 window.inner{Width,Height} don't return the visual viewport
size so once after the content scale changed, i.e. the visual viewport size
doesn't match window inner size, GeckoView::ScrollBy and ScrollTo don't work
as expected.  This commit has JUnit tests to generate the situation by calling
nsIDOMWindowUtils.setResolutionAndScaleTo.

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Hiroyuki Ikezoe 2019-12-13 00:09:17 +00:00
Родитель a20a9e1065
Коммит abc58dd4e5
7 изменённых файлов: 101 добавлений и 3 удалений

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

@ -100,9 +100,9 @@ class GeckoViewContentChild extends GeckoViewChildModule {
if (aType === SCREEN_LENGTH_TYPE_PIXEL) { if (aType === SCREEN_LENGTH_TYPE_PIXEL) {
return aLength; return aLength;
} else if (aType === SCREEN_LENGTH_TYPE_VIEWPORT_WIDTH) { } else if (aType === SCREEN_LENGTH_TYPE_VIEWPORT_WIDTH) {
return aLength * content.innerWidth; return aLength * content.visualViewport.width;
} else if (aType === SCREEN_LENGTH_TYPE_VIEWPORT_HEIGHT) { } else if (aType === SCREEN_LENGTH_TYPE_VIEWPORT_HEIGHT) {
return aLength * content.innerHeight; return aLength * content.visualViewport.height;
} else if (aType === SCREEN_LENGTH_DOCUMENT_WIDTH) { } else if (aType === SCREEN_LENGTH_DOCUMENT_WIDTH) {
return aLength * content.document.body.scrollWidth; return aLength * content.document.body.scrollWidth;
} else if (aType === SCREEN_LENGTH_DOCUMENT_HEIGHT) { } else if (aType === SCREEN_LENGTH_DOCUMENT_HEIGHT) {

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

@ -26,6 +26,9 @@ const APIS = {
SetPrefs: function({ oldPrefs, newPrefs }) { SetPrefs: function({ oldPrefs, newPrefs }) {
return browser.test.setPrefs(oldPrefs, newPrefs); return browser.test.setPrefs(oldPrefs, newPrefs);
}, },
SetResolutionAndScaleTo: function({ resolution }) {
return browser.test.setResolutionAndScaleTo(resolution);
},
}; };
port.onMessage.addListener(async message => { port.onMessage.addListener(async message => {

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

@ -35,6 +35,15 @@ function linkColorFrameScript() {
}); });
} }
function setResolutionAndScaleToFrameScript(resolution) {
addMessageListener("PanZoomControllerTest:SetResolutionAndScaleTo", () => {
content.window.visualViewport.addEventListener("resize", () => {
sendAsyncMessage("PanZoomControllerTest:SetResolutionAndScaleTo");
});
content.windowUtils.setResolutionAndScaleTo(resolution);
});
}
this.test = class extends ExtensionAPI { this.test = class extends ExtensionAPI {
getAPI(context) { getAPI(context) {
return { return {
@ -112,6 +121,31 @@ this.test = class extends ExtensionAPI {
async setScalar(id, value) { async setScalar(id, value) {
return Services.telemetry.scalarSet(id, value); return Services.telemetry.scalarSet(id, value);
}, },
async setResolutionAndScaleTo(resolution) {
const frameScript = `data:text/javascript,(${encodeURI(
setResolutionAndScaleToFrameScript
)}).call(this, ${resolution})`;
Services.mm.loadFrameScript(frameScript, true);
return new Promise(resolve => {
const onMessage = () => {
Services.mm.removeMessageListener(
"PanZoomControllerTest:SetResolutionAndScaleTo",
onMessage
);
resolve();
};
Services.mm.addMessageListener(
"PanZoomControllerTest:SetResolutionAndScaleTo",
onMessage
);
Services.mm.broadcastAsyncMessage(
"PanZoomControllerTest:SetResolutionAndScaleTo"
);
});
},
}, },
}; };
} }

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

@ -104,6 +104,18 @@
"name": "value" "name": "value"
} }
] ]
},
{
"name": "setResolutionAndScaleTo",
"type": "function",
"async": true,
"description": "Invokes nsIDOMWindowUtils.setResolutionAndScaleTo.",
"parameters": [
{
"type": "number",
"name": "resolution"
}
]
} }
] ]
} }

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

@ -1,7 +1,7 @@
<html> <html>
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=0.5">
<style type="text/css"> <style type="text/css">
body { body {
background-color: white; background-color: white;

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

@ -163,6 +163,46 @@ class PanZoomControllerTest : BaseSessionTest() {
scrollToVertical(PanZoomController.SCROLL_BEHAVIOR_AUTO) scrollToVertical(PanZoomController.SCROLL_BEHAVIOR_AUTO)
} }
private fun scrollToVerticalOnZoomedContent(mode: Int) {
setup()
val originalVH = mainSession.evaluateJS("window.visualViewport.height") as Double
assertThat("Visual viewport height is not zero", originalVH, greaterThan(0.0))
val innerHeight = mainSession.evaluateJS("window.innerHeight") as Double
assertThat("Visual viewport height equals to window.innerHeight", originalVH, equalTo(innerHeight))
val originalScale = mainSession.evaluateJS("visualViewport.scale") as Double
assertThat("Visual viewport scale is the initial scale", originalScale, closeTo(0.5, 0.01))
// Change the resolution so that the visual viewport will be different from the layout viewport.
sessionRule.setResolutionAndScaleTo(2.0f)
val scale = mainSession.evaluateJS("visualViewport.scale") as Double
assertThat("Visual viewport scale is now greater than the initial scale", scale, greaterThan(originalScale))
val vh = mainSession.evaluateJS("window.visualViewport.height") as Double
assertThat("Visual viewport height has been changed", vh, lessThan(originalVH))
sessionRule.session.panZoomController.scrollTo(ScreenLength.zero(), ScreenLength.fromViewportHeight(1.0), mode)
waitForVerticalScroll(vh, scrollWaitTimeout)
val scrollY = mainSession.evaluateJS("window.visualViewport.pageTop") as Double
assertThat("scrollBy should have scrolled along y axis one viewport", scrollY, closeTo(vh, errorEpsilon))
}
@WithDisplay(width = 100, height = 100)
@Test
fun scrollToVerticalOnZoomedContentSmooth() {
scrollToVerticalOnZoomedContent(PanZoomController.SCROLL_BEHAVIOR_SMOOTH)
}
@WithDisplay(width = 100, height = 100)
@Test
fun scrollToVerticalOnZoomedContentAuto() {
scrollToVerticalOnZoomedContent(PanZoomController.SCROLL_BEHAVIOR_AUTO)
}
private fun scrollToVerticalTwice(mode: Int) { private fun scrollToVerticalTwice(mode: Int) {
setup() setup()
val vh = mainSession.evaluateJS("window.innerHeight") as Double val vh = mainSession.evaluateJS("window.innerHeight") as Double

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

@ -2060,6 +2060,15 @@ public class GeckoSessionTestRule implements TestRule {
}); });
} }
/**
* Invokes nsIDOMWindowUtils.setResolutionAndScaleTo.
*/
public void setResolutionAndScaleTo(final float resolution) {
webExtensionApiCall("SetResolutionAndScaleTo", args -> {
args.put("resolution", resolution);
});
}
private Object webExtensionApiCall(final String apiName, SetArgs argsSetter) { private Object webExtensionApiCall(final String apiName, SetArgs argsSetter) {
// Ensure background script is connected // Ensure background script is connected
UiThreadUtils.waitForCondition(() -> RuntimeCreator.backgroundPort() != null, UiThreadUtils.waitForCondition(() -> RuntimeCreator.backgroundPort() != null,