Merge pull request #8693 from electron/zoom_specs

webContents: add basic zoom specs
This commit is contained in:
Kevin Sawicki 2017-02-17 12:50:26 -08:00 committed by GitHub
commit 1f75df0253
12 changed files with 372 additions and 26 deletions

View file

@ -1672,9 +1672,9 @@ void WebContents::BuildPrototype(v8::Isolate* isolate,
.SetMethod("getFrameRate", &WebContents::GetFrameRate)
.SetMethod("invalidate", &WebContents::Invalidate)
.SetMethod("setZoomLevel", &WebContents::SetZoomLevel)
.SetMethod("getZoomLevel", &WebContents::GetZoomLevel)
.SetMethod("_getZoomLevel", &WebContents::GetZoomLevel)
.SetMethod("setZoomFactor", &WebContents::SetZoomFactor)
.SetMethod("getZoomFactor", &WebContents::GetZoomFactor)
.SetMethod("_getZoomFactor", &WebContents::GetZoomFactor)
.SetMethod("getType", &WebContents::GetType)
.SetMethod("getWebPreferences", &WebContents::GetWebPreferences)
.SetMethod("getOwnerBrowserWindow", &WebContents::GetOwnerBrowserWindow)

View file

@ -112,8 +112,7 @@ void WebContentsZoomController::DidFinishNavigation(
return;
}
if (!navigation_handle->IsSamePage())
SetZoomFactorOnNavigationIfNeeded(navigation_handle->GetURL());
SetZoomFactorOnNavigationIfNeeded(navigation_handle->GetURL());
}
void WebContentsZoomController::WebContentsDestroyed() {

View file

@ -206,6 +206,26 @@ WebContents.prototype.printToPDF = function (options, callback) {
this._printToPDF(printingSetting, callback)
}
WebContents.prototype.getZoomLevel = function (callback) {
if (typeof callback !== 'function') {
throw new Error('Must pass function as an argument')
}
process.nextTick(() => {
const zoomLevel = this._getZoomLevel()
callback(zoomLevel)
})
}
WebContents.prototype.getZoomFactor = function (callback) {
if (typeof callback !== 'function') {
throw new Error('Must pass function as an argument')
}
process.nextTick(() => {
const zoomFactor = this._getZoomFactor()
callback(zoomFactor)
})
}
// Add JavaScript wrappers for WebContents class.
WebContents.prototype._init = function () {
// The navigation controller.

View file

@ -184,7 +184,7 @@ const attachGuest = function (event, elementInstanceId, guestInstanceId, params)
guestInstanceId: guestInstanceId,
nodeIntegration: params.nodeintegration != null ? params.nodeintegration : false,
plugins: params.plugins,
zoomFactor: embedder.getZoomFactor(),
zoomFactor: embedder._getZoomFactor(),
webSecurity: !params.disablewebsecurity,
blinkFeatures: params.blinkfeatures,
disableBlinkFeatures: params.disableblinkfeatures

View file

@ -374,7 +374,11 @@ var registerWebViewElement = function () {
'print',
'printToPDF',
'showDefinitionForSelection',
'capturePage'
'capturePage',
'setZoomFactor',
'setZoomLevel',
'getZoomLevel',
'getZoomFactor'
]
const nonblockMethods = [
'insertCSS',
@ -383,8 +387,6 @@ var registerWebViewElement = function () {
'sendInputEvent',
'setLayoutZoomLevelLimits',
'setVisualZoomLevelLimits',
'setZoomFactor',
'setZoomLevel',
// TODO(kevinsawicki): Remove in 2.0, deprecate before then with warnings
'setZoomLevelLimits'
]

View file

@ -1,11 +1,12 @@
'use strict'
const assert = require('assert')
const http = require('http')
const path = require('path')
const {closeWindow} = require('./window-helpers')
const {ipcRenderer, remote} = require('electron')
const {BrowserWindow, webContents, ipcMain} = remote
const {BrowserWindow, webContents, ipcMain, session} = remote
const isCi = remote.getGlobal('isCi')
@ -322,4 +323,208 @@ describe('webContents module', function () {
})
})
})
describe('zoom api', () => {
const zoomScheme = remote.getGlobal('zoomScheme')
const hostZoomMap = {
host1: 0.3,
host2: 0.7,
host3: 0.2
}
before((done) => {
const protocol = session.defaultSession.protocol
protocol.registerStringProtocol(zoomScheme, (request, callback) => {
const response = `<script>
const {ipcRenderer, remote} = require('electron')
ipcRenderer.send('set-zoom', window.location.hostname)
ipcRenderer.on(window.location.hostname + '-zoom-set', () => {
remote.getCurrentWebContents().getZoomLevel((zoomLevel) => {
ipcRenderer.send(window.location.hostname + '-zoom-level', zoomLevel)
})
})
</script>`
callback({data: response, mimeType: 'text/html'})
}, (error) => done(error))
})
after((done) => {
const protocol = session.defaultSession.protocol
protocol.unregisterProtocol(zoomScheme, (error) => done(error))
})
it('can set the correct zoom level', (done) => {
w.loadURL('about:blank')
w.webContents.on('did-finish-load', () => {
w.webContents.getZoomLevel((zoomLevel) => {
assert.equal(zoomLevel, 0.0)
w.webContents.setZoomLevel(0.5)
w.webContents.getZoomLevel((zoomLevel) => {
assert.equal(zoomLevel, 0.5)
w.webContents.setZoomLevel(0)
done()
})
})
})
})
it('can persist zoom level across navigation', (done) => {
let finalNavigation = false
ipcMain.on('set-zoom', (e, host) => {
const zoomLevel = hostZoomMap[host]
if (!finalNavigation) {
w.webContents.setZoomLevel(zoomLevel)
}
e.sender.send(`${host}-zoom-set`)
})
ipcMain.on('host1-zoom-level', (e, zoomLevel) => {
const expectedZoomLevel = hostZoomMap.host1
assert.equal(zoomLevel, expectedZoomLevel)
if (finalNavigation) {
done()
} else {
w.loadURL(`${zoomScheme}://host2`)
}
})
ipcMain.once('host2-zoom-level', (e, zoomLevel) => {
const expectedZoomLevel = hostZoomMap.host2
assert.equal(zoomLevel, expectedZoomLevel)
finalNavigation = true
w.webContents.goBack()
})
w.loadURL(`${zoomScheme}://host1`)
})
it('can propagate zoom level across same session', (done) => {
const w2 = new BrowserWindow({
show: false
})
w2.webContents.on('did-finish-load', () => {
w.webContents.getZoomLevel((zoomLevel1) => {
assert.equal(zoomLevel1, hostZoomMap.host3)
w2.webContents.getZoomLevel((zoomLevel2) => {
assert.equal(zoomLevel1, zoomLevel2)
w2.setClosable(true)
w2.close()
done()
})
})
})
w.webContents.on('did-finish-load', () => {
w.webContents.setZoomLevel(hostZoomMap.host3)
w2.loadURL(`${zoomScheme}://host3`)
})
w.loadURL(`${zoomScheme}://host3`)
})
it('cannot propagate zoom level across different session', (done) => {
const w2 = new BrowserWindow({
show: false,
webPreferences: {
partition: 'temp'
}
})
const protocol = w2.webContents.session.protocol
protocol.registerStringProtocol(zoomScheme, (request, callback) => {
callback('hello')
}, (error) => {
if (error) return done(error)
w2.webContents.on('did-finish-load', () => {
w.webContents.getZoomLevel((zoomLevel1) => {
assert.equal(zoomLevel1, hostZoomMap.host3)
w2.webContents.getZoomLevel((zoomLevel2) => {
assert.equal(zoomLevel2, 0)
assert.notEqual(zoomLevel1, zoomLevel2)
protocol.unregisterProtocol(zoomScheme, (error) => {
if (error) return done(error)
w2.setClosable(true)
w2.close()
done()
})
})
})
})
w.webContents.on('did-finish-load', () => {
w.webContents.setZoomLevel(hostZoomMap.host3)
w2.loadURL(`${zoomScheme}://host3`)
})
w.loadURL(`${zoomScheme}://host3`)
})
})
it('can persist when it contains iframe', (done) => {
const server = http.createServer(function (req, res) {
setTimeout(() => {
res.end()
}, 200)
})
server.listen(0, '127.0.0.1', function () {
const url = 'http://127.0.0.1:' + server.address().port
const content = `<iframe src=${url}></iframe>`
w.webContents.on('did-frame-finish-load', (e, isMainFrame) => {
if (!isMainFrame) {
w.webContents.getZoomLevel((zoomLevel) => {
assert.equal(zoomLevel, 2.0)
w.webContents.setZoomLevel(0)
server.close()
done()
})
}
})
w.webContents.on('dom-ready', () => {
w.webContents.setZoomLevel(2.0)
})
w.loadURL(`data:text/html,${content}`)
})
})
it('cannot propagate when used with webframe', (done) => {
let finalZoomLevel = 0
const w2 = new BrowserWindow({
show: false
})
w2.webContents.on('did-finish-load', () => {
w.webContents.getZoomLevel((zoomLevel1) => {
assert.equal(zoomLevel1, finalZoomLevel)
w2.webContents.getZoomLevel((zoomLevel2) => {
assert.equal(zoomLevel2, 0)
assert.notEqual(zoomLevel1, zoomLevel2)
w2.setClosable(true)
w2.close()
done()
})
})
})
ipcMain.once('temporary-zoom-set', (e, zoomLevel) => {
w2.loadURL(`file://${fixtures}/pages/c.html`)
finalZoomLevel = zoomLevel
})
w.loadURL(`file://${fixtures}/pages/webframe-zoom.html`)
})
it('cannot persist zoom level after navigation with webFrame', (done) => {
let initialNavigation = true
const source = `
const {ipcRenderer, webFrame} = require('electron')
webFrame.setZoomLevel(0.6)
ipcRenderer.send('zoom-level-set', webFrame.getZoomLevel())
`
w.webContents.on('did-finish-load', () => {
if (initialNavigation) {
w.webContents.executeJavaScript(source, () => {})
} else {
w.webContents.getZoomLevel((zoomLevel) => {
assert.equal(zoomLevel, 0)
done()
})
}
})
ipcMain.once('zoom-level-set', (e, zoomLevel) => {
assert.equal(zoomLevel, 0.6)
w.loadURL(`file://${fixtures}/pages/d.html`)
initialNavigation = false
})
w.loadURL(`file://${fixtures}/pages/c.html`)
})
})
})

View file

@ -0,0 +1,9 @@
<html>
<body>
<script type="text/javascript" charset="utf-8">
const {ipcRenderer, webFrame} = require('electron')
webFrame.setZoomLevel(1.0)
ipcRenderer.send('temporary-zoom-set', webFrame.getZoomLevel())
</script>
</body>
</html>

View file

@ -0,0 +1,26 @@
<html>
<body>
<webview nodeintegration src="zoom://host1" id="view" partition="webview-temp"/>
</body>
<script>
const {ipcRenderer, webFrame} = require('electron')
const view = document.getElementById('view')
let finalNavigation = false
view.addEventListener('dom-ready', () => {
if (!finalNavigation && !view.canGoBack()) {
view.setZoomLevel(2.0)
}
view.getZoomLevel((zoomLevel) => {
view.getZoomFactor((zoomFactor) => {
ipcRenderer.send('webview-zoom-level', zoomLevel, zoomFactor, view.canGoBack(), finalNavigation)
if (!view.canGoBack() && !finalNavigation) {
view.src = 'zoom://host2'
} else if (!finalNavigation) {
finalNavigation = true
view.goBack()
}
})
})
})
</script>
</html>

View file

@ -0,0 +1,32 @@
<html>
<body>
<webview nodeintegration src="zoom://host1" id="view" partition="webview-temp"/>
</body>
<script>
const {ipcRenderer, webFrame} = require('electron')
const view = document.getElementById('view')
let finalNavigation = false
function SendZoomLevel() {
return new Promise((resolve, reject) => {
view.getZoomLevel((zoomLevel) => {
view.getZoomFactor((zoomFactor) => {
ipcRenderer.send('webview-zoom-in-page', zoomLevel, zoomFactor, finalNavigation)
resolve()
})
})
})
}
view.addEventListener('dom-ready', () => {
view.setZoomLevel(2.0)
SendZoomLevel().then(() => {
if (!finalNavigation) {
finalNavigation = true
view.executeJavaScript('window.location.hash=123', () => {})
}
})
})
view.addEventListener('did-navigate-in-page', () => {
SendZoomLevel()
})
</script>
</html>

View file

@ -2,7 +2,7 @@
<body>
<script type="text/javascript" charset="utf-8">
const {ipcRenderer, webFrame} = require('electron')
ipcRenderer.send('pong', webFrame.getZoomFactor(), webFrame.getZoomLevel())
ipcRenderer.send('webview-parent-zoom-level', webFrame.getZoomFactor(), webFrame.getZoomLevel())
</script>
</body>
</html>

View file

@ -93,7 +93,8 @@ if (global.isCi) {
// Register app as standard scheme.
global.standardScheme = 'app'
protocol.registerStandardSchemes([global.standardScheme], { secure: true })
global.zoomScheme = 'zoom'
protocol.registerStandardSchemes([global.standardScheme, global.zoomScheme], { secure: true })
app.on('window-all-closed', function () {
app.quit()

View file

@ -1067,21 +1067,6 @@ describe('<webview> tag', function () {
})
})
it('inherits the zoomFactor of the parent window', function (done) {
w = new BrowserWindow({
show: false,
webPreferences: {
zoomFactor: 1.2
}
})
ipcMain.once('pong', function (event, zoomFactor, zoomLevel) {
assert.equal(zoomFactor, 1.2)
assert.equal(zoomLevel, 1)
done()
})
w.loadURL('file://' + fixtures + '/pages/webview-zoom-factor.html')
})
it('inherits the parent window visibility state and receives visibilitychange events', function (done) {
w = new BrowserWindow({
show: false
@ -1540,4 +1525,71 @@ describe('<webview> tag', function () {
})
})
})
describe('zoom behavior', () => {
const zoomScheme = remote.getGlobal('zoomScheme')
const webviewSession = session.fromPartition('webview-temp')
before((done) => {
const protocol = webviewSession.protocol
protocol.registerStringProtocol(zoomScheme, (request, callback) => {
callback('hello')
}, (error) => done(error))
})
after((done) => {
const protocol = webviewSession.protocol
protocol.unregisterProtocol(zoomScheme, (error) => done(error))
})
it('inherits the zoomFactor of the parent window', (done) => {
w = new BrowserWindow({
show: false,
webPreferences: {
zoomFactor: 1.2
}
})
ipcMain.once('webview-parent-zoom-level', (event, zoomFactor, zoomLevel) => {
assert.equal(zoomFactor, 1.2)
assert.equal(zoomLevel, 1)
done()
})
w.loadURL(`file://${fixtures}/pages/webview-zoom-factor.html`)
})
it('maintains zoom level on navigation', (done) => {
w = new BrowserWindow({
show: false,
webPreferences: {
zoomFactor: 1.2
}
})
ipcMain.on('webview-zoom-level', (event, zoomLevel, zoomFactor, newHost, final) => {
if (!newHost) {
assert.equal(zoomFactor, 1.44)
assert.equal(zoomLevel, 2.0)
} else {
assert.equal(zoomFactor, 1.2)
assert.equal(zoomLevel, 1)
}
if (final) done()
})
w.loadURL(`file://${fixtures}/pages/webview-custom-zoom-level.html`)
})
it('maintains zoom level when navigating within same page', (done) => {
w = new BrowserWindow({
show: false,
webPreferences: {
zoomFactor: 1.2
}
})
ipcMain.on('webview-zoom-in-page', (event, zoomLevel, zoomFactor, final) => {
assert.equal(zoomFactor, 1.44)
assert.equal(zoomLevel, 2.0)
if (final) done()
})
w.loadURL(`file://${fixtures}/pages/webview-in-page-navigate.html`)
})
})
})