From c65cfadd094f951d65b5561df40c778d3ba583d6 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 22 Feb 2016 11:51:41 +0800 Subject: [PATCH 1/8] v8Util.createObjectWithName is no longer used --- atom/browser/lib/rpc-server.js | 4 +++- atom/common/api/atom_api_v8_util.cc | 35 ----------------------------- 2 files changed, 3 insertions(+), 36 deletions(-) diff --git a/atom/browser/lib/rpc-server.js b/atom/browser/lib/rpc-server.js index 64785879b3f2..c3e5159cd9ef 100644 --- a/atom/browser/lib/rpc-server.js +++ b/atom/browser/lib/rpc-server.js @@ -162,7 +162,9 @@ var unwrapArgs = function(sender, args) { then: metaToValue(meta.then) }); case 'object': { - let ret = v8Util.createObjectWithName(meta.name); + let ret = {}; + Object.defineProperty(ret.constructor, 'name', { value: meta.name }); + ref = meta.members; for (i = 0, len = ref.length; i < len; i++) { member = ref[i]; diff --git a/atom/common/api/atom_api_v8_util.cc b/atom/common/api/atom_api_v8_util.cc index c86335adb15e..f50d3485eba6 100644 --- a/atom/common/api/atom_api_v8_util.cc +++ b/atom/common/api/atom_api_v8_util.cc @@ -2,49 +2,15 @@ // Use of this source code is governed by the MIT license that can be // found in the LICENSE file. -#include #include #include "atom/common/api/object_life_monitor.h" #include "atom/common/node_includes.h" -#include "base/stl_util.h" #include "native_mate/dictionary.h" #include "v8/include/v8-profiler.h" namespace { -// A Persistent that can be copied and will not free itself. -template -struct LeakedPersistentTraits { - typedef v8::Persistent > LeakedPersistent; - static const bool kResetInDestructor = false; - template - static V8_INLINE void Copy(const v8::Persistent& source, - LeakedPersistent* dest) { - // do nothing, just allow copy - } -}; - -// The handles are leaked on purpose. -using FunctionTemplateHandle = - LeakedPersistentTraits::LeakedPersistent; -std::map function_templates_; - -v8::Local CreateObjectWithName(v8::Isolate* isolate, - const std::string& name) { - if (name == "Object") - return v8::Object::New(isolate); - - if (ContainsKey(function_templates_, name)) - return v8::Local::New( - isolate, function_templates_[name])->GetFunction()->NewInstance(); - - v8::Local t = v8::FunctionTemplate::New(isolate); - t->SetClassName(mate::StringToV8(isolate, name)); - function_templates_[name] = FunctionTemplateHandle(isolate, t); - return t->GetFunction()->NewInstance(); -} - v8::Local GetHiddenValue(v8::Local object, v8::Local key) { return object->GetHiddenValue(key); @@ -78,7 +44,6 @@ void TakeHeapSnapshot(v8::Isolate* isolate) { void Initialize(v8::Local exports, v8::Local unused, v8::Local context, void* priv) { mate::Dictionary dict(context->GetIsolate(), exports); - dict.SetMethod("createObjectWithName", &CreateObjectWithName); dict.SetMethod("getHiddenValue", &GetHiddenValue); dict.SetMethod("setHiddenValue", &SetHiddenValue); dict.SetMethod("deleteHiddenValue", &DeleteHiddenValue); From fe7462b3526d9c74534133273305223180ed0fd5 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 22 Feb 2016 12:26:41 +0800 Subject: [PATCH 2/8] No longer needs cache for methods of remote Refs #4517. --- atom/renderer/api/lib/remote.js | 56 +++++---------------------------- 1 file changed, 8 insertions(+), 48 deletions(-) diff --git a/atom/renderer/api/lib/remote.js b/atom/renderer/api/lib/remote.js index d28ec6dfcbd0..a9798338faa6 100644 --- a/atom/renderer/api/lib/remote.js +++ b/atom/renderer/api/lib/remote.js @@ -141,7 +141,7 @@ let setObjectPrototype = function(object, metaId, descriptor) { }; // Convert meta data from browser into real value. -var metaToValue = function(meta) { +let metaToValue = function(meta) { var el, i, len, ref1, results, ret; switch (meta.type) { case 'value': @@ -257,73 +257,33 @@ for (var name in browserModules) { } // Get remote module. -// (Just like node's require, the modules are cached permanently, note that this -// is safe leak since the object is not expected to get freed in browser) -var moduleCache = {}; - exports.require = function(module) { - var meta; - if (moduleCache[module] != null) { - return moduleCache[module]; - } - meta = ipcRenderer.sendSync('ATOM_BROWSER_REQUIRE', module); - return moduleCache[module] = metaToValue(meta); + return metaToValue(ipcRenderer.sendSync('ATOM_BROWSER_REQUIRE', module)); }; -// Optimize require('electron'). -moduleCache.electron = exports; - // Alias to remote.require('electron').xxx. -var builtinCache = {}; - exports.getBuiltin = function(module) { - var meta; - if (builtinCache[module] != null) { - return builtinCache[module]; - } - meta = ipcRenderer.sendSync('ATOM_BROWSER_GET_BUILTIN', module); - return builtinCache[module] = metaToValue(meta); + return metaToValue(ipcRenderer.sendSync('ATOM_BROWSER_GET_BUILTIN', module)); }; -// Get current BrowserWindow object. -var windowCache = null; - +// Get current BrowserWindow. exports.getCurrentWindow = function() { - var meta; - if (windowCache != null) { - return windowCache; - } - meta = ipcRenderer.sendSync('ATOM_BROWSER_CURRENT_WINDOW'); - return windowCache = metaToValue(meta); + return metaToValue(ipcRenderer.sendSync('ATOM_BROWSER_CURRENT_WINDOW')); }; // Get current WebContents object. -var webContentsCache = null; - exports.getCurrentWebContents = function() { - var meta; - if (webContentsCache != null) { - return webContentsCache; - } - meta = ipcRenderer.sendSync('ATOM_BROWSER_CURRENT_WEB_CONTENTS'); - return webContentsCache = metaToValue(meta); + return metaToValue(ipcRenderer.sendSync('ATOM_BROWSER_CURRENT_WEB_CONTENTS')); }; // Get a global object in browser. exports.getGlobal = function(name) { - var meta; - meta = ipcRenderer.sendSync('ATOM_BROWSER_GLOBAL', name); - return metaToValue(meta); + return metaToValue(ipcRenderer.sendSync('ATOM_BROWSER_GLOBAL', name)); }; // Get the process object in browser. -var processCache = null; - exports.__defineGetter__('process', function() { - if (processCache == null) { - processCache = exports.getGlobal('process'); - } - return processCache; + return exports.getGlobal('process'); }); // Create a funtion that will return the specifed value when called in browser. From 2b04af434937d4cde9a5b6584c19603cc586e6c3 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 22 Feb 2016 14:03:31 +0800 Subject: [PATCH 3/8] No longer need to count the references in webContents All remote objects are now cached in renderer process, so there is always only one reference to one remote object for each webContents. --- atom/browser/lib/objects-registry.js | 73 +++++++++++----------------- atom/browser/lib/rpc-server.js | 2 +- 2 files changed, 30 insertions(+), 45 deletions(-) diff --git a/atom/browser/lib/objects-registry.js b/atom/browser/lib/objects-registry.js index e9d6d365fa5b..90d1fe80e537 100644 --- a/atom/browser/lib/objects-registry.js +++ b/atom/browser/lib/objects-registry.js @@ -15,70 +15,57 @@ class ObjectsRegistry extends EventEmitter { this.storage = {}; // Stores the IDs of objects referenced by WebContents. - // (webContentsId) => {(id) => (count)} + // (webContentsId) => [id] this.owners = {}; } - // Register a new object, the object would be kept referenced until you release - // it explicitly. + // Register a new object and return its assigned ID. If the object is already + // registered then the already assigned ID would be returned. add(webContentsId, obj) { - var base, base1, id; - id = this.saveToStorage(obj); + // Get or assign an ID to the object. + let id = this.saveToStorage(obj); - // Remember the owner. - if ((base = this.owners)[webContentsId] == null) { - base[webContentsId] = {}; + // Add object to the set of referenced objects. + let owner = this.owners[webContentsId]; + if (!owner) + owner = this.owners[webContentsId] = new Set(); + if (!owner.has(id)) { + owner.add(id); + // Increase reference count if not referenced before. + this.storage[id].count++; } - if ((base1 = this.owners[webContentsId])[id] == null) { - base1[id] = 0; - } - this.owners[webContentsId][id]++; - - // Returns object's id return id; } // Get an object according to its ID. get(id) { - var ref; - return (ref = this.storage[id]) != null ? ref.object : void 0; + return this.storage[id].object; } // Dereference an object according to its ID. remove(webContentsId, id) { - var pointer; - this.dereference(id, 1); + // Dereference from the storage. + this.dereference(id); - // Also reduce the count in owner. - pointer = this.owners[webContentsId]; - if (pointer == null) { - return; - } - --pointer[id]; - if (pointer[id] === 0) { - return delete pointer[id]; - } + // Also remove the reference in owner. + this.owners[webContentsId].delete(id); } // Clear all references to objects refrenced by the WebContents. clear(webContentsId) { - var count, id, ref; - this.emit("clear-" + webContentsId); - if (this.owners[webContentsId] == null) { + this.emit(`clear-${webContentsId}`); + + let owner = this.owners[webContentsId]; + if (!owner) return; - } - ref = this.owners[webContentsId]; - for (id in ref) { - count = ref[id]; - this.dereference(id, count); - } - return delete this.owners[webContentsId]; + for (let id of owner) + this.dereference(id); + delete this.owners[webContentsId]; } // Private: Saves the object into storage and assigns an ID for it. saveToStorage(object) { - var id; - id = v8Util.getHiddenValue(object, 'atomId'); + let id = v8Util.getHiddenValue(object, 'atomId'); if (!id) { id = ++this.nextId; this.storage[id] = { @@ -87,18 +74,16 @@ class ObjectsRegistry extends EventEmitter { }; v8Util.setHiddenValue(object, 'atomId', id); } - ++this.storage[id].count; return id; } // Private: Dereference the object from store. - dereference(id, count) { - var pointer; - pointer = this.storage[id]; + dereference(id) { + let pointer = this.storage[id]; if (pointer == null) { return; } - pointer.count -= count; + pointer.count -= 1; if (pointer.count === 0) { v8Util.deleteHiddenValue(pointer.object, 'atomId'); return delete this.storage[id]; diff --git a/atom/browser/lib/rpc-server.js b/atom/browser/lib/rpc-server.js index c3e5159cd9ef..f366eb43a52b 100644 --- a/atom/browser/lib/rpc-server.js +++ b/atom/browser/lib/rpc-server.js @@ -145,7 +145,7 @@ var exceptionToMeta = function(error) { var unwrapArgs = function(sender, args) { var metaToValue; metaToValue = function(meta) { - var i, len, member, ref, rendererReleased, returnValue; + var i, len, member, ref, returnValue; switch (meta.type) { case 'value': return meta.value; From 59d6e7d6ef769118a7357c2a0d266223819f1459 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 22 Feb 2016 14:10:25 +0800 Subject: [PATCH 4/8] ObjectsRegistry no longer needs to send events --- atom/browser/lib/objects-registry.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/atom/browser/lib/objects-registry.js b/atom/browser/lib/objects-registry.js index 90d1fe80e537..9677c7fea22d 100644 --- a/atom/browser/lib/objects-registry.js +++ b/atom/browser/lib/objects-registry.js @@ -1,13 +1,9 @@ 'use strict'; -const EventEmitter = require('events').EventEmitter; const v8Util = process.atomBinding('v8_util'); -class ObjectsRegistry extends EventEmitter { +class ObjectsRegistry { constructor() { - super(); - - this.setMaxListeners(Number.MAX_VALUE); this.nextId = 0; // Stores all objects by ref-counting. @@ -53,8 +49,6 @@ class ObjectsRegistry extends EventEmitter { // Clear all references to objects refrenced by the WebContents. clear(webContentsId) { - this.emit(`clear-${webContentsId}`); - let owner = this.owners[webContentsId]; if (!owner) return; From d4c954870a14c90f114482e03ef4cc3b60b092bd Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 22 Feb 2016 14:15:51 +0800 Subject: [PATCH 5/8] Remove a few CoffeeScript generated junks --- atom/browser/lib/rpc-server.js | 35 ++++++++++++---------------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/atom/browser/lib/rpc-server.js b/atom/browser/lib/rpc-server.js index f366eb43a52b..c3ea8ca6b094 100644 --- a/atom/browser/lib/rpc-server.js +++ b/atom/browser/lib/rpc-server.js @@ -11,8 +11,6 @@ const FUNCTION_PROPERTIES = [ 'length', 'name', 'arguments', 'caller', 'prototype', ]; -var slice = [].slice; - // Return the description of object's members: let getObjectMemebers = function(object) { let names = Object.getOwnPropertyNames(object); @@ -281,14 +279,13 @@ ipcMain.on('ATOM_BROWSER_CURRENT_WEB_CONTENTS', function(event) { }); ipcMain.on('ATOM_BROWSER_CONSTRUCTOR', function(event, id, args) { - var constructor, obj; try { args = unwrapArgs(event.sender, args); - constructor = objectsRegistry.get(id); + let constructor = objectsRegistry.get(id); // Call new with array of arguments. // http://stackoverflow.com/questions/1606797/use-of-apply-with-new-operator-is-this-possible - obj = new (Function.prototype.bind.apply(constructor, [null].concat(args))); + let obj = new (Function.prototype.bind.apply(constructor, [null].concat(args))); return event.returnValue = valueToMeta(event.sender, obj); } catch (error) { return event.returnValue = exceptionToMeta(error); @@ -296,10 +293,9 @@ ipcMain.on('ATOM_BROWSER_CONSTRUCTOR', function(event, id, args) { }); ipcMain.on('ATOM_BROWSER_FUNCTION_CALL', function(event, id, args) { - var func; try { args = unwrapArgs(event.sender, args); - func = objectsRegistry.get(id); + let func = objectsRegistry.get(id); return callFunction(event, func, global, args); } catch (error) { return event.returnValue = exceptionToMeta(error); @@ -307,13 +303,12 @@ ipcMain.on('ATOM_BROWSER_FUNCTION_CALL', function(event, id, args) { }); ipcMain.on('ATOM_BROWSER_MEMBER_CONSTRUCTOR', function(event, id, method, args) { - var constructor, obj; try { args = unwrapArgs(event.sender, args); - constructor = objectsRegistry.get(id)[method]; + let constructor = objectsRegistry.get(id)[method]; // Call new with array of arguments. - obj = new (Function.prototype.bind.apply(constructor, [null].concat(args))); + let obj = new (Function.prototype.bind.apply(constructor, [null].concat(args))); return event.returnValue = valueToMeta(event.sender, obj); } catch (error) { return event.returnValue = exceptionToMeta(error); @@ -321,10 +316,9 @@ ipcMain.on('ATOM_BROWSER_MEMBER_CONSTRUCTOR', function(event, id, method, args) }); ipcMain.on('ATOM_BROWSER_MEMBER_CALL', function(event, id, method, args) { - var obj; try { args = unwrapArgs(event.sender, args); - obj = objectsRegistry.get(id); + let obj = objectsRegistry.get(id); return callFunction(event, obj[method], obj, args); } catch (error) { return event.returnValue = exceptionToMeta(error); @@ -332,9 +326,8 @@ ipcMain.on('ATOM_BROWSER_MEMBER_CALL', function(event, id, method, args) { }); ipcMain.on('ATOM_BROWSER_MEMBER_SET', function(event, id, name, value) { - var obj; try { - obj = objectsRegistry.get(id); + let obj = objectsRegistry.get(id); obj[name] = value; return event.returnValue = null; } catch (error) { @@ -343,9 +336,8 @@ ipcMain.on('ATOM_BROWSER_MEMBER_SET', function(event, id, name, value) { }); ipcMain.on('ATOM_BROWSER_MEMBER_GET', function(event, id, name) { - var obj; try { - obj = objectsRegistry.get(id); + let obj = objectsRegistry.get(id); return event.returnValue = valueToMeta(event.sender, obj[name]); } catch (error) { return event.returnValue = exceptionToMeta(error); @@ -357,21 +349,18 @@ ipcMain.on('ATOM_BROWSER_DEREFERENCE', function(event, id) { }); ipcMain.on('ATOM_BROWSER_GUEST_WEB_CONTENTS', function(event, guestInstanceId) { - var guestViewManager; try { - guestViewManager = require('./guest-view-manager'); + let guestViewManager = require('./guest-view-manager'); return event.returnValue = valueToMeta(event.sender, guestViewManager.getGuest(guestInstanceId)); } catch (error) { return event.returnValue = exceptionToMeta(error); } }); -ipcMain.on('ATOM_BROWSER_ASYNC_CALL_TO_GUEST_VIEW', function() { - var args, event, guest, guestInstanceId, guestViewManager, method; - event = arguments[0], guestInstanceId = arguments[1], method = arguments[2], args = 4 <= arguments.length ? slice.call(arguments, 3) : []; +ipcMain.on('ATOM_BROWSER_ASYNC_CALL_TO_GUEST_VIEW', function(event, guestInstanceId, method, ...args) { try { - guestViewManager = require('./guest-view-manager'); - guest = guestViewManager.getGuest(guestInstanceId); + let guestViewManager = require('./guest-view-manager'); + let guest = guestViewManager.getGuest(guestInstanceId); return guest[method].apply(guest, args); } catch (error) { return event.returnValue = exceptionToMeta(error); From 593a79ce20296f0178e6f38016039e5e12a1f77a Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 22 Feb 2016 14:36:50 +0800 Subject: [PATCH 6/8] Separate renderer functions by renderer process ID Close #4324. --- atom/browser/lib/rpc-server.js | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/atom/browser/lib/rpc-server.js b/atom/browser/lib/rpc-server.js index c3ea8ca6b094..7b59648eda13 100644 --- a/atom/browser/lib/rpc-server.js +++ b/atom/browser/lib/rpc-server.js @@ -11,6 +11,10 @@ const FUNCTION_PROPERTIES = [ 'length', 'name', 'arguments', 'caller', 'prototype', ]; +// The remote functions in renderer processes. +// (webContentsId) => {id: Function} +let rendererFunctions = {}; + // Return the description of object's members: let getObjectMemebers = function(object) { let names = Object.getOwnPropertyNames(object); @@ -177,32 +181,30 @@ var unwrapArgs = function(sender, args) { }; case 'function': { // Cache the callbacks in renderer. - if (!sender.callbacks) { - sender.callbacks = new IDWeakMap; - sender.on('render-view-deleted', function() { - return this.callbacks.clear(); + let webContentsId = sender.getId(); + let callbacks = rendererFunctions[webContentsId]; + if (!callbacks) { + callbacks = rendererFunctions[webContentsId] = new IDWeakMap; + sender.once('render-view-deleted', function(event, id) { + callbacks.clear(); + delete rendererFunctions[id]; }); } - if (sender.callbacks.has(meta.id)) - return sender.callbacks.get(meta.id); - - // Prevent the callback from being called when its page is gone. - rendererReleased = false; - sender.once('render-view-deleted', function() { - rendererReleased = true; - }); + if (callbacks.has(meta.id)) + return callbacks.get(meta.id); let callIntoRenderer = function(...args) { - if (rendererReleased || sender.isDestroyed()) + if ((webContentsId in rendererFunctions) && !sender.isDestroyed()) + sender.send('ATOM_RENDERER_CALLBACK', meta.id, valueToMeta(sender, args)); + else throw new Error(`Attempting to call a function in a renderer window that has been closed or released. Function provided here: ${meta.location}.`); - sender.send('ATOM_RENDERER_CALLBACK', meta.id, valueToMeta(sender, args)); }; v8Util.setDestructor(callIntoRenderer, function() { - if (!rendererReleased && !sender.isDestroyed()) + if ((webContentsId in rendererFunctions) && !sender.isDestroyed()) sender.send('ATOM_RENDERER_RELEASE_CALLBACK', meta.id); }); - sender.callbacks.set(meta.id, callIntoRenderer); + callbacks.set(meta.id, callIntoRenderer); return callIntoRenderer; } default: From 6753fcc1b4bae07bad8cae674770da220bf9fafb Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 22 Feb 2016 14:54:55 +0800 Subject: [PATCH 7/8] Get rid of the ATOM_BROWSER_RELEASE_RENDER_VIEW event --- atom/browser/api/atom_api_web_contents.cc | 12 +----------- atom/browser/lib/objects-registry.js | 10 ++++++++-- atom/browser/lib/rpc-server.js | 7 +------ 3 files changed, 10 insertions(+), 19 deletions(-) diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index a7946786c514..72443bdb815a 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -485,17 +485,7 @@ void WebContents::BeforeUnloadFired(const base::TimeTicks& proceed_time) { } void WebContents::RenderViewDeleted(content::RenderViewHost* render_view_host) { - int process_id = render_view_host->GetProcess()->GetID(); - Emit("render-view-deleted", process_id); - - // process.emit('ATOM_BROWSER_RELEASE_RENDER_VIEW', processId); - // Tell the rpc server that a render view has been deleted and we need to - // release all objects owned by it. - v8::Locker locker(isolate()); - v8::HandleScope handle_scope(isolate()); - node::Environment* env = node::Environment::GetCurrent(isolate()); - mate::EmitEvent(isolate(), env->process_object(), - "ATOM_BROWSER_RELEASE_RENDER_VIEW", process_id); + Emit("render-view-deleted", render_view_host->GetProcess()->GetID()); } void WebContents::RenderProcessGone(base::TerminationStatus status) { diff --git a/atom/browser/lib/objects-registry.js b/atom/browser/lib/objects-registry.js index 9677c7fea22d..c3f70c976ecb 100644 --- a/atom/browser/lib/objects-registry.js +++ b/atom/browser/lib/objects-registry.js @@ -17,14 +17,20 @@ class ObjectsRegistry { // Register a new object and return its assigned ID. If the object is already // registered then the already assigned ID would be returned. - add(webContentsId, obj) { + add(webContents, obj) { // Get or assign an ID to the object. let id = this.saveToStorage(obj); // Add object to the set of referenced objects. + let webContentsId = webContents.getId(); let owner = this.owners[webContentsId]; - if (!owner) + if (!owner) { owner = this.owners[webContentsId] = new Set(); + // Clear the storage when webContents is reloaded/navigated. + webContents.once('render-view-deleted', (event, id) => { + this.clear(id); + }); + } if (!owner.has(id)) { owner.add(id); // Increase reference count if not referenced before. diff --git a/atom/browser/lib/rpc-server.js b/atom/browser/lib/rpc-server.js index 7b59648eda13..20ee8fbdeae1 100644 --- a/atom/browser/lib/rpc-server.js +++ b/atom/browser/lib/rpc-server.js @@ -100,7 +100,7 @@ var valueToMeta = function(sender, value, optimizeSimpleObject) { // Reference the original value if it's an object, because when it's // passed to renderer we would assume the renderer keeps a reference of // it. - meta.id = objectsRegistry.add(sender.getId(), value); + meta.id = objectsRegistry.add(sender, value); meta.members = getObjectMemebers(value); meta.proto = getObjectPrototype(value); } else if (meta.type === 'buffer') { @@ -239,11 +239,6 @@ var callFunction = function(event, func, caller, args) { } }; -// Send by BrowserWindow when its render view is deleted. -process.on('ATOM_BROWSER_RELEASE_RENDER_VIEW', function(id) { - return objectsRegistry.clear(id); -}); - ipcMain.on('ATOM_BROWSER_REQUIRE', function(event, module) { try { return event.returnValue = valueToMeta(event.sender, process.mainModule.require(module)); From 96b2705bd3ec3fe7a92bc27bf061613d4871ae19 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 22 Feb 2016 15:20:23 +0800 Subject: [PATCH 8/8] Fix render-view-deleted being emitted twice --- atom/browser/api/atom_api_web_contents.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index 72443bdb815a..ee6ad94ba77a 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -296,6 +296,7 @@ WebContents::~WebContents() { // The WebContentsDestroyed will not be called automatically because we // unsubscribe from webContents before destroying it. So we have to manually // call it here to make sure "destroyed" event is emitted. + RenderViewDeleted(web_contents()->GetRenderViewHost()); WebContentsDestroyed(); } } @@ -665,9 +666,6 @@ bool WebContents::OnMessageReceived(const IPC::Message& message) { // be destroyed on close, and WebContentsDestroyed would be called for it, so // we need to make sure the api::WebContents is also deleted. void WebContents::WebContentsDestroyed() { - // The RenderViewDeleted was not called when the WebContents is destroyed. - RenderViewDeleted(web_contents()->GetRenderViewHost()); - // This event is only for internal use, which is emitted when WebContents is // being destroyed. Emit("will-destroy");