Merge pull request #8142 from electron/1-3-backports

Backports to 1.3
This commit is contained in:
Kevin Sawicki
2016-12-06 14:12:25 -08:00
committed by GitHub
23 changed files with 194 additions and 91 deletions

View File

@@ -71,7 +71,7 @@ app.allowNTLMCredentialsForAllDomains = function (allow) {
const events = ['login', 'certificate-error', 'select-client-certificate']
for (let name of events) {
app.on(name, (event, webContents, ...args) => {
webContents.emit.apply(webContents, [name, event].concat(args))
webContents.emit(name, event, ...args)
})
}

View File

@@ -119,19 +119,19 @@ BrowserWindow.fromDevToolsWebContents = (webContents) => {
// Helpers.
Object.assign(BrowserWindow.prototype, {
loadURL (...args) {
return this.webContents.loadURL.apply(this.webContents, args)
return this.webContents.loadURL(...args)
},
getURL (...args) {
return this.webContents.getURL()
},
reload (...args) {
return this.webContents.reload.apply(this.webContents, args)
return this.webContents.reload(...args)
},
send (...args) {
return this.webContents.send.apply(this.webContents, args)
return this.webContents.send(...args)
},
openDevTools (...args) {
return this.webContents.openDevTools.apply(this.webContents, args)
return this.webContents.openDevTools(...args)
},
closeDevTools () {
return this.webContents.closeDevTools()
@@ -146,7 +146,7 @@ Object.assign(BrowserWindow.prototype, {
return this.webContents.toggleDevTools()
},
inspectElement (...args) {
return this.webContents.inspectElement.apply(this.webContents, args)
return this.webContents.inspectElement(...args)
},
inspectServiceWorker () {
return this.webContents.inspectServiceWorker()
@@ -155,7 +155,7 @@ Object.assign(BrowserWindow.prototype, {
return this.webContents.showDefinitionForSelection()
},
capturePage (...args) {
return this.webContents.capturePage.apply(this.webContents, args)
return this.webContents.capturePage(...args)
}
})

View File

@@ -50,7 +50,7 @@ module.exports = {
showOpenDialog: function (...args) {
var prop, properties, value, wrappedCallback
checkAppInitialized()
let [window, options, callback] = parseArgs.apply(null, args)
let [window, options, callback] = parseArgs(...args)
if (options == null) {
options = {
title: 'Open',
@@ -97,7 +97,7 @@ module.exports = {
showSaveDialog: function (...args) {
var wrappedCallback
checkAppInitialized()
let [window, options, callback] = parseArgs.apply(null, args)
let [window, options, callback] = parseArgs(...args)
if (options == null) {
options = {
title: 'Save'
@@ -130,7 +130,7 @@ module.exports = {
showMessageBox: function (...args) {
var flags, i, j, len, messageBoxType, ref2, ref3, text
checkAppInitialized()
let [window, options, callback] = parseArgs.apply(null, args)
let [window, options, callback] = parseArgs(...args)
if (options == null) {
options = {
type: 'none'
@@ -185,7 +185,7 @@ module.exports = {
},
showErrorBox: function (...args) {
return binding.showErrorBox.apply(binding, args)
return binding.showErrorBox(...args)
}
}

View File

@@ -4,13 +4,11 @@ const {ipcMain} = require('electron')
// The history operation in renderer is redirected to browser.
ipcMain.on('ELECTRON_NAVIGATION_CONTROLLER', function (event, method, ...args) {
var ref
(ref = event.sender)[method].apply(ref, args)
event.sender[method](...args)
})
ipcMain.on('ELECTRON_SYNC_NAVIGATION_CONTROLLER', function (event, method, ...args) {
var ref
event.returnValue = (ref = event.sender)[method].apply(ref, args)
event.returnValue = event.sender[method](...args)
})
// JavaScript implementation of Chromium's NavigationController.

View File

@@ -237,7 +237,7 @@ WebContents.prototype._init = function () {
// Delays the page-title-updated event to next tick.
this.on('-page-title-updated', function (...args) {
setImmediate(() => {
this.emit.apply(this, ['page-title-updated'].concat(args))
this.emit('page-title-updated', ...args)
})
})

View File

@@ -153,7 +153,7 @@ ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_METHOD', function (event, guest
const guestWindow = getGuestWindow(guestContents)
if (guestWindow != null) {
event.returnValue = guestWindow[method].apply(guestWindow, args)
event.returnValue = guestWindow[method](...args)
} else {
event.returnValue = null
}
@@ -177,7 +177,7 @@ ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', function (event,
if (guestContents == null) return
if (canAccessWindow(event.sender, guestContents)) {
guestContents[method].apply(guestContents, args)
guestContents[method](...args)
} else {
console.error(`Blocked ${event.sender.getURL()} from calling ${method} on its opener.`)
}
@@ -191,7 +191,7 @@ ipcMain.on('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD_SYNC', function (e
}
if (canAccessWindow(event.sender, guestContents)) {
event.returnValue = guestContents[method].apply(guestContents, args)
event.returnValue = guestContents[method](...args)
} else {
console.error(`Blocked ${event.sender.getURL()} from calling ${method} on its opener.`)
event.returnValue = null

View File

@@ -26,7 +26,7 @@ if (process.platform === 'win32') {
// Redirect node's console to use our own implementations, since node can not
// handle console output when running as GUI program.
var consoleLog = function (...args) {
return process.log(util.format.apply(util, args) + '\n')
return process.log(util.format(...args) + '\n')
}
var streamWrite = function (chunk, encoding, callback) {
if (Buffer.isBuffer(chunk)) {

View File

@@ -19,17 +19,14 @@ class ObjectsRegistry {
// registered then the already assigned ID would be returned.
add (webContents, obj) {
// Get or assign an ID to the object.
let id = this.saveToStorage(obj)
const id = this.saveToStorage(obj)
// Add object to the set of referenced objects.
let webContentsId = webContents.getId()
const webContentsId = webContents.getId()
let owner = this.owners[webContentsId]
if (!owner) {
owner = this.owners[webContentsId] = new Set()
// Clear the storage when webContents is reloaded/navigated.
webContents.once('render-view-deleted', () => {
this.clear(webContentsId)
})
this.registerDeleteListener(webContents, webContentsId)
}
if (!owner.has(id)) {
owner.add(id)
@@ -89,9 +86,20 @@ class ObjectsRegistry {
pointer.count -= 1
if (pointer.count === 0) {
v8Util.deleteHiddenValue(pointer.object, 'atomId')
return delete this.storage[id]
delete this.storage[id]
}
}
// Private: Clear the storage when webContents is reloaded/navigated.
registerDeleteListener (webContents, webContentsId) {
const listener = (event, deletedProcessId) => {
if (deletedProcessId === webContentsId) {
webContents.removeListener('render-view-deleted', listener)
this.clear(webContentsId)
}
}
webContents.on('render-view-deleted', listener)
}
}
module.exports = new ObjectsRegistry()

View File

@@ -371,3 +371,34 @@ ipcMain.on('ELECTRON_BROWSER_SEND_TO', function (event, sendToAll, webContentsId
contents.send(channel, ...args)
}
})
// Implements window.alert(message, title)
ipcMain.on('ELECTRON_BROWSER_WINDOW_ALERT', function (event, message, title) {
if (message == null) message = ''
if (title == null) title = ''
event.returnValue = electron.dialog.showMessageBox(event.sender.getOwnerBrowserWindow(), {
message: `${message}`,
title: `${title}`,
buttons: ['OK']
})
})
// Implements window.confirm(message, title)
ipcMain.on('ELECTRON_BROWSER_WINDOW_CONFIRM', function (event, message, title) {
if (message == null) message = ''
if (title == null) title = ''
event.returnValue = !electron.dialog.showMessageBox(event.sender.getOwnerBrowserWindow(), {
message: `${message}`,
title: `${title}`,
buttons: ['OK', 'Cancel'],
cancelId: 1
})
})
// Implements window.close()
ipcMain.on('ELECTRON_BROWSER_WINDOW_CLOSE', function (event) {
event.sender.getOwnerBrowserWindow().close()
event.returnValue = null
})

View File

@@ -44,14 +44,8 @@ class CallbacksRegistry {
return (ref = this.callbacks[id]) != null ? ref : function () {}
}
call (id, ...args) {
var ref
return (ref = this.get(id)).call.apply(ref, [global].concat(args))
}
apply (id, ...args) {
var ref
return (ref = this.get(id)).apply.apply(ref, [global].concat(args))
return this.get(id).apply(global, ...args)
}
remove (id) {

View File

@@ -1,11 +1,13 @@
const timers = require('timers')
const {binding} = process
process.atomBinding = function (name) {
try {
return process.binding('atom_' + process.type + '_' + name)
return binding('atom_' + process.type + '_' + name)
} catch (error) {
if (/No such module/.test(error.message)) {
return process.binding('atom_common_' + name)
return binding('atom_common_' + name)
}
}
}

View File

@@ -88,7 +88,7 @@ const wrapArgs = function (args, visited) {
}
}
}
return Array.prototype.slice.call(args).map(valueToMeta)
return args.map(valueToMeta)
}
// Populate object's members from descriptors.
@@ -100,14 +100,14 @@ const setObjectMembers = function (ref, object, metaId, members) {
let descriptor = { enumerable: member.enumerable }
if (member.type === 'method') {
const remoteMemberFunction = function () {
const remoteMemberFunction = function (...args) {
if (this && this.constructor === remoteMemberFunction) {
// Constructor call.
let ret = ipcRenderer.sendSync('ELECTRON_BROWSER_MEMBER_CONSTRUCTOR', metaId, member.name, wrapArgs(arguments))
let ret = ipcRenderer.sendSync('ELECTRON_BROWSER_MEMBER_CONSTRUCTOR', metaId, member.name, wrapArgs(args))
return metaToValue(ret)
} else {
// Call member function.
let ret = ipcRenderer.sendSync('ELECTRON_BROWSER_MEMBER_CALL', metaId, member.name, wrapArgs(arguments))
let ret = ipcRenderer.sendSync('ELECTRON_BROWSER_MEMBER_CALL', metaId, member.name, wrapArgs(args))
return metaToValue(ret)
}
}
@@ -213,17 +213,17 @@ const metaToValue = function (meta) {
if (meta.type === 'function') {
// A shadow class to represent the remote function object.
let remoteFunction = function () {
let remoteFunction = function (...args) {
if (this && this.constructor === remoteFunction) {
// Constructor call.
let obj = ipcRenderer.sendSync('ELECTRON_BROWSER_CONSTRUCTOR', meta.id, wrapArgs(arguments))
let obj = ipcRenderer.sendSync('ELECTRON_BROWSER_CONSTRUCTOR', meta.id, wrapArgs(args))
// Returning object in constructor will replace constructed object
// with the returned object.
// http://stackoverflow.com/questions/1978049/what-values-can-a-constructor-return-to-avoid-returning-this
return metaToValue(obj)
} else {
// Function call.
let obj = ipcRenderer.sendSync('ELECTRON_BROWSER_FUNCTION_CALL', meta.id, wrapArgs(arguments))
let obj = ipcRenderer.sendSync('ELECTRON_BROWSER_FUNCTION_CALL', meta.id, wrapArgs(args))
return metaToValue(obj)
}
}

View File

@@ -29,20 +29,18 @@ const electron = require('electron')
// Call webFrame method.
electron.ipcRenderer.on('ELECTRON_INTERNAL_RENDERER_WEB_FRAME_METHOD', (event, method, args) => {
electron.webFrame[method].apply(electron.webFrame, args)
electron.webFrame[method](...args)
})
electron.ipcRenderer.on('ELECTRON_INTERNAL_RENDERER_SYNC_WEB_FRAME_METHOD', (event, requestId, method, args) => {
const result = electron.webFrame[method].apply(electron.webFrame, args)
const result = electron.webFrame[method](...args)
event.sender.send(`ELECTRON_INTERNAL_BROWSER_SYNC_WEB_FRAME_RESPONSE_${requestId}`, result)
})
electron.ipcRenderer.on('ELECTRON_INTERNAL_RENDERER_ASYNC_WEB_FRAME_METHOD', (event, requestId, method, args) => {
const responseCallback = function (result) {
electron.webFrame[method](...args, function (result) {
event.sender.send(`ELECTRON_INTERNAL_BROWSER_ASYNC_WEB_FRAME_RESPONSE_${requestId}`, result)
}
args.push(responseCallback)
electron.webFrame[method].apply(electron.webFrame, args)
})
})
// Process command line arguments.

View File

@@ -1,23 +1,27 @@
'use strict'
const ipcRenderer = require('electron').ipcRenderer
const remote = require('electron').remote
const {ipcRenderer} = require('electron')
const {defineProperty} = Object
// Helper function to resolve relative url.
var a = window.top.document.createElement('a')
var resolveURL = function (url) {
const a = window.top.document.createElement('a')
const resolveURL = function (url) {
a.href = url
return a.href
}
// Window object returned by "window.open".
var BrowserWindowProxy = (function () {
const BrowserWindowProxy = (function () {
BrowserWindowProxy.proxies = {}
BrowserWindowProxy.getOrCreate = function (guestId) {
var base = this.proxies
base[guestId] != null ? base[guestId] : base[guestId] = new BrowserWindowProxy(guestId)
return base[guestId]
let proxy = this.proxies[guestId]
if (proxy == null) {
proxy = new BrowserWindowProxy(guestId)
this.proxies[guestId] = proxy
}
return proxy
}
BrowserWindowProxy.remove = function (guestId) {
@@ -25,7 +29,7 @@ var BrowserWindowProxy = (function () {
}
function BrowserWindowProxy (guestId1) {
Object.defineProperty(this, 'guestId', {
defineProperty(this, 'guestId', {
configurable: false,
enumerable: true,
writeable: false,
@@ -55,7 +59,7 @@ var BrowserWindowProxy = (function () {
ipcRenderer.send('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', this.guestId, 'print')
}
Object.defineProperty(BrowserWindowProxy.prototype, 'location', {
defineProperty(BrowserWindowProxy.prototype, 'location', {
get: function () {
return ipcRenderer.sendSync('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD_SYNC', this.guestId, 'getURL')
},
@@ -73,7 +77,7 @@ var BrowserWindowProxy = (function () {
}
BrowserWindowProxy.prototype['eval'] = function (...args) {
ipcRenderer.send.apply(ipcRenderer, ['ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', this.guestId, 'executeJavaScript'].concat(args))
ipcRenderer.send('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', this.guestId, 'executeJavaScript', ...args)
}
return BrowserWindowProxy
@@ -82,7 +86,7 @@ var BrowserWindowProxy = (function () {
if (process.guestInstanceId == null) {
// Override default window.close.
window.close = function () {
return remote.getCurrentWindow().close()
ipcRenderer.sendSync('ELECTRON_BROWSER_WINDOW_CLOSE')
}
}
@@ -158,29 +162,12 @@ window.open = function (url, frameName, features) {
}
}
// Use the dialog API to implement alert().
window.alert = function (message = '', title = '') {
remote.dialog.showMessageBox(remote.getCurrentWindow(), {
message: String(message),
title: String(title),
buttons: ['OK']
})
window.alert = function (message, title) {
ipcRenderer.sendSync('ELECTRON_BROWSER_WINDOW_ALERT', message, title)
}
// And the confirm().
window.confirm = function (message, title) {
var buttons, cancelId
if (title == null) {
title = ''
}
buttons = ['OK', 'Cancel']
cancelId = 1
return !remote.dialog.showMessageBox(remote.getCurrentWindow(), {
message: message,
title: title,
buttons: buttons,
cancelId: cancelId
})
return ipcRenderer.sendSync('ELECTRON_BROWSER_WINDOW_CONFIRM', message, title)
}
// But we do not support prompt().
@@ -205,11 +192,11 @@ ipcRenderer.on('ELECTRON_GUEST_WINDOW_POSTMESSAGE', function (event, sourceId, m
// Forward history operations to browser.
var sendHistoryOperation = function (...args) {
ipcRenderer.send.apply(ipcRenderer, ['ELECTRON_NAVIGATION_CONTROLLER'].concat(args))
ipcRenderer.send('ELECTRON_NAVIGATION_CONTROLLER', ...args)
}
var getHistoryOperation = function (...args) {
return ipcRenderer.sendSync.apply(ipcRenderer, ['ELECTRON_SYNC_NAVIGATION_CONTROLLER'].concat(args))
return ipcRenderer.sendSync('ELECTRON_SYNC_NAVIGATION_CONTROLLER', ...args)
}
window.history.back = function () {
@@ -224,7 +211,7 @@ window.history.go = function (offset) {
sendHistoryOperation('goToOffset', offset)
}
Object.defineProperty(window.history, 'length', {
defineProperty(window.history, 'length', {
get: function () {
return getHistoryOperation('length')
}
@@ -242,13 +229,13 @@ ipcRenderer.on('ELECTRON_RENDERER_WINDOW_VISIBILITY_CHANGE', function (event, vi
})
// Make document.hidden and document.visibilityState return the correct value.
Object.defineProperty(document, 'hidden', {
defineProperty(document, 'hidden', {
get: function () {
return cachedVisibilityState !== 'visible'
}
})
Object.defineProperty(document, 'visibilityState', {
defineProperty(document, 'visibilityState', {
get: function () {
return cachedVisibilityState
}

View File

@@ -46,7 +46,7 @@ var DEPRECATED_EVENTS = {
var dispatchEvent = function (webView, eventName, eventKey, ...args) {
var domEvent, f, i, j, len, ref1
if (DEPRECATED_EVENTS[eventName] != null) {
dispatchEvent.apply(null, [webView, DEPRECATED_EVENTS[eventName], eventKey].concat(args))
dispatchEvent(webView, DEPRECATED_EVENTS[eventName], eventKey, ...args)
}
domEvent = new Event(eventName)
ref1 = WEB_VIEW_EVENTS[eventKey]
@@ -63,7 +63,7 @@ var dispatchEvent = function (webView, eventName, eventKey, ...args) {
module.exports = {
registerEvents: function (webView, viewInstanceId) {
ipcRenderer.on('ELECTRON_GUEST_VIEW_INTERNAL_DISPATCH_EVENT-' + viewInstanceId, function (event, eventName, ...args) {
dispatchEvent.apply(null, [webView, eventName, eventName].concat(args))
dispatchEvent(webView, eventName, eventName, ...args)
})
ipcRenderer.on('ELECTRON_GUEST_VIEW_INTERNAL_IPC_MESSAGE-' + viewInstanceId, function (event, channel, ...args) {

View File

@@ -407,7 +407,7 @@ var registerWebViewElement = function () {
return function (...args) {
const internal = v8Util.getHiddenValue(this, 'internal')
if (internal.webContents) {
return internal.webContents[m].apply(internal.webContents, args)
return internal.webContents[m](...args)
} else {
throw new Error(`Cannot call ${m} because the webContents is unavailable. The WebView must be attached to the DOM and the dom-ready event emitted before this method can be called.`)
}
@@ -420,7 +420,7 @@ var registerWebViewElement = function () {
createNonBlockHandler = function (m) {
return function (...args) {
const internal = v8Util.getHiddenValue(this, 'internal')
return ipcRenderer.send.apply(ipcRenderer, ['ELECTRON_BROWSER_ASYNC_CALL_TO_GUEST_VIEW', null, internal.guestInstanceId, m].concat(args))
return ipcRenderer.send('ELECTRON_BROWSER_ASYNC_CALL_TO_GUEST_VIEW', null, internal.guestInstanceId, m, ...args)
}
}
for (j = 0, len1 = nonblockMethods.length; j < len1; j++) {

View File

@@ -0,0 +1,5 @@
#!/usr/bin/env bash
export TARGET_ARCH=arm
script/cibuild-linux

View File

@@ -0,0 +1,5 @@
#!/usr/bin/env bash
export TARGET_ARCH=ia32
script/cibuild-linux

View File

@@ -0,0 +1,5 @@
#!/usr/bin/env bash
export TARGET_ARCH=x64
script/cibuild-linux

23
script/cibuild-linux Executable file
View File

@@ -0,0 +1,23 @@
#!/usr/bin/env bash
MESSAGE="$(git log --format=%B -n 1 HEAD)"
case ${MESSAGE} in
Bump* ) export ELECTRON_RELEASE=1 ;;
esac
set +x
export ELECTRON_GITHUB_TOKEN="$BUILD_ELECTRON_ELECTRON_GITHUB_TOKEN"
export ELECTRON_S3_BUCKET="$BUILD_ELECTRON_ELECTRON_S3_BUCKET"
export ELECTRON_S3_ACCESS_KEY="$BUILD_ELECTRON_ELECTRON_S3_ACCESS_KEY"
export ELECTRON_S3_SECRET_KEY="$BUILD_ELECTRON_ELECTRON_S3_SECRET_KEY"
if [[ -z "${ELECTRON_RELEASE}" ]]; then
echo "Generating Linux $TARGET_ARCH debug build"
else
echo "Generating Linux $TARGET_ARCH release build"
fi
set -x
script/cibuild

View File

@@ -9,7 +9,7 @@ import sys
BASE_URL = os.getenv('LIBCHROMIUMCONTENT_MIRROR') or \
'https://s3.amazonaws.com/github-janky-artifacts/libchromiumcontent'
LIBCHROMIUMCONTENT_COMMIT = os.getenv('LIBCHROMIUMCONTENT_COMMIT') or \
'c5cf295ef93d4ee88bff0c4b06b28ff0969a890e'
'27add4cfef98f21d5910539bebb47ae175f024c2'
PLATFORM = {
'cygwin': 'win32',

View File

@@ -492,4 +492,19 @@ describe('ipc module', function () {
assert.equal(w.listenerCount('test'), 0)
})
})
describe('remote objects registry', function () {
it('does not dereference until the render view is deleted (regression)', function (done) {
w = new BrowserWindow({
show: false
})
ipcMain.once('error-message', (event, message) => {
assert(message.startsWith('Cannot read property \'object\' of undefined'), message)
done()
})
w.loadURL('file://' + path.join(fixtures, 'api', 'render-view-deleted.html'))
})
})
})

View File

@@ -0,0 +1,32 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script>
const {ipcRenderer, remote} = require('electron')
const contents = remote.getCurrentWebContents()
// This should not trigger a dereference and a remote getURL call should not fail
contents.emit('render-view-deleted', {}, 'not-a-process-id')
try {
contents.getURL()
} catch (error) {
ipcRenderer.send('error-message', 'Unexpected error on getURL call')
}
// This should trigger a dereference and a remote getURL call should fail
contents.emit('render-view-deleted', {}, contents.getId())
try {
contents.getURL()
ipcRenderer.send('error-message', 'No error thrown')
} catch (error) {
ipcRenderer.send('error-message', error.message)
}
</script>
</head>
<body>
</body>
</html>