diff --git a/browser_patches/firefox/BUILD_NUMBER b/browser_patches/firefox/BUILD_NUMBER index 029a4ec45ec7a..09ceb6eec1d53 100644 --- a/browser_patches/firefox/BUILD_NUMBER +++ b/browser_patches/firefox/BUILD_NUMBER @@ -1,2 +1,2 @@ -1248 -Changed: aslushnikov@gmail.com Mon Apr 26 12:48:04 -05 2021 +1249 +Changed: yurys@chromium.org Thu 29 Apr 2021 02:45:14 PM PDT diff --git a/browser_patches/firefox/juggler/content/FrameTree.js b/browser_patches/firefox/juggler/content/FrameTree.js index 1dd040fbf271c..4380dc7f8e3e1 100644 --- a/browser_patches/firefox/juggler/content/FrameTree.js +++ b/browser_patches/firefox/juggler/content/FrameTree.js @@ -23,6 +23,7 @@ class FrameTree { this._browsingContextGroup.__jugglerFrameTrees = new Set(); this._browsingContextGroup.__jugglerFrameTrees.add(this); this._scriptsToEvaluateOnNewDocument = new Map(); + this._isolatedWorlds = new Map(); this._webSocketEventService = Cc[ "@mozilla.org/websocketevent/service;1" @@ -72,6 +73,25 @@ class FrameTree { return this._runtime; } + addScriptToEvaluateOnNewDocument(script, worldName) { + const scriptId = helper.generateId(); + if (worldName) { + this._isolatedWorlds.set(scriptId, {script, worldName}); + for (const frame of this.frames()) + frame.createIsolatedWorld(worldName); + } else { + this._scriptsToEvaluateOnNewDocument.set(scriptId, script); + } + return {scriptId}; + } + + removeScriptToEvaluateOnNewDocument(scriptId) { + if (this._isolatedWorlds.has(scriptId)) + this._isolatedWorlds.delete(scriptId); + else + this._scriptsToEvaluateOnNewDocument.delete(scriptId); + } + _frameForWorker(workerDebugger) { if (workerDebugger.type !== Ci.nsIWorkerDebugger.TYPE_DEDICATED) return null; @@ -86,7 +106,6 @@ class FrameTree { if (!frame) return; frame._onGlobalObjectCleared(); - this.emit(FrameTree.Events.GlobalObjectCreated, { frame, window }); } _onWorkerCreated(workerDebugger) { @@ -129,16 +148,6 @@ class FrameTree { return true; } - addScriptToEvaluateOnNewDocument(script) { - const scriptId = helper.generateId(); - this._scriptsToEvaluateOnNewDocument.set(scriptId, script); - return scriptId; - } - - removeScriptToEvaluateOnNewDocument(scriptId) { - this._scriptsToEvaluateOnNewDocument.delete(scriptId); - } - addBinding(name, script) { this._bindings.set(name, script); for (const frame of this.frames()) @@ -291,7 +300,6 @@ FrameTree.Events = { BindingCalled: 'bindingcalled', FrameAttached: 'frameattached', FrameDetached: 'framedetached', - GlobalObjectCreated: 'globalobjectcreated', WorkerCreated: 'workercreated', WorkerDestroyed: 'workerdestroyed', WebSocketCreated: 'websocketcreated', @@ -330,6 +338,9 @@ class Frame { this._textInputProcessor = null; this._executionContext = null; + this._isolatedWorlds = new Map(); + this._initialNavigationDone = false; + this._webSocketListenerInnerWindowId = 0; // WebSocketListener calls frameReceived event before webSocketOpened. // To avoid this, serialize event reporting. @@ -415,7 +426,36 @@ class Frame { }; } + createIsolatedWorld(name) { + const principal = [this.domWindow()]; // extended principal + const sandbox = Cu.Sandbox(principal, { + sandboxPrototype: this.domWindow(), + wantComponents: false, + wantExportHelpers: false, + wantXrays: true, + }); + const world = this._runtime.createExecutionContext(this.domWindow(), sandbox, { + frameId: this.id(), + name, + }); + this._isolatedWorlds.set(world.id(), world); + return world; + } + + unsafeObject(objectId) { + const contexts = [this.executionContext(), ...this._isolatedWorlds.values()]; + for (const context of contexts) { + const result = context.unsafeObject(objectId); + if (result) + return result.object; + } + throw new Error('Cannot find object with id = ' + objectId); + } + dispose() { + for (const world of this._isolatedWorlds.values()) + this._runtime.destroyExecutionContext(world); + this._isolatedWorlds.clear(); if (this._executionContext) this._runtime.destroyExecutionContext(this._executionContext); this._executionContext = null; @@ -458,6 +498,19 @@ class Frame { dump(`ERROR: ${e.message}\n${e.stack}\n`); } } + + for (const world of this._isolatedWorlds.values()) + this._runtime.destroyExecutionContext(world); + this._isolatedWorlds.clear(); + for (const {script, worldName} of this._frameTree._isolatedWorlds.values()) { + const context = worldName ? this.createIsolatedWorld(worldName) : this.executionContext(); + try { + let result = context.evaluateScript(script); + if (result && result.objectId) + context.disposeObject(result.objectId); + } catch (e) { + } + } } executionContext() { diff --git a/browser_patches/firefox/juggler/content/PageAgent.js b/browser_patches/firefox/juggler/content/PageAgent.js index bb278e5f27ba8..25205bcaa6e35 100644 --- a/browser_patches/firefox/juggler/content/PageAgent.js +++ b/browser_patches/firefox/juggler/content/PageAgent.js @@ -49,65 +49,6 @@ class WorkerData { } } -class FrameData { - constructor(agent, runtime, frame) { - this._agent = agent; - this._runtime = runtime; - this._frame = frame; - this._isolatedWorlds = new Map(); - this._initialNavigationDone = false; - this.reset(); - } - - reset() { - for (const world of this._isolatedWorlds.values()) - this._runtime.destroyExecutionContext(world); - this._isolatedWorlds.clear(); - - for (const {script, worldName} of this._agent._isolatedWorlds.values()) { - const context = worldName ? this.createIsolatedWorld(worldName) : this._frame.executionContext(); - try { - let result = context.evaluateScript(script); - if (result && result.objectId) - context.disposeObject(result.objectId); - } catch (e) { - } - } - } - - createIsolatedWorld(name) { - const principal = [this._frame.domWindow()]; // extended principal - const sandbox = Cu.Sandbox(principal, { - sandboxPrototype: this._frame.domWindow(), - wantComponents: false, - wantExportHelpers: false, - wantXrays: true, - }); - const world = this._runtime.createExecutionContext(this._frame.domWindow(), sandbox, { - frameId: this._frame.id(), - name, - }); - this._isolatedWorlds.set(world.id(), world); - return world; - } - - unsafeObject(objectId) { - const contexts = [this._frame.executionContext(), ...this._isolatedWorlds.values()]; - for (const context of contexts) { - const result = context.unsafeObject(objectId); - if (result) - return result.object; - } - throw new Error('Cannot find object with id = ' + objectId); - } - - dispose() { - for (const world of this._isolatedWorlds.values()) - this._runtime.destroyExecutionContext(world); - this._isolatedWorlds.clear(); - } -} - class PageAgent { constructor(messageManager, browserChannel, frameTree) { this._messageManager = messageManager; @@ -116,10 +57,7 @@ class PageAgent { this._frameTree = frameTree; this._runtime = frameTree.runtime(); - this._frameData = new Map(); this._workerData = new Map(); - this._scriptsToEvaluateOnNewDocument = new Map(); - this._isolatedWorlds = new Map(); const docShell = frameTree.mainFrame().docShell(); this._docShell = docShell; @@ -169,7 +107,6 @@ class PageAgent { helper.on(this._frameTree, 'bindingcalled', this._onBindingCalled.bind(this)), helper.on(this._frameTree, 'frameattached', this._onFrameAttached.bind(this)), helper.on(this._frameTree, 'framedetached', this._onFrameDetached.bind(this)), - helper.on(this._frameTree, 'globalobjectcreated', this._onGlobalObjectCreated.bind(this)), helper.on(this._frameTree, 'navigationstarted', this._onNavigationStarted.bind(this)), helper.on(this._frameTree, 'navigationcommitted', this._onNavigationCommitted.bind(this)), helper.on(this._frameTree, 'navigationaborted', this._onNavigationAborted.bind(this)), @@ -198,7 +135,7 @@ class PageAgent { this._runtime.events.onExecutionContextDestroyed(this._onExecutionContextDestroyed.bind(this)), browserChannel.register('page', { addBinding: ({ name, script }) => this._frameTree.addBinding(name, script), - addScriptToEvaluateOnNewDocument: this._addScriptToEvaluateOnNewDocument.bind(this), + addScriptToEvaluateOnNewDocument: ({script, worldName}) => this._frameTree.addScriptToEvaluateOnNewDocument(script, worldName), adoptNode: this._adoptNode.bind(this), crash: this._crash.bind(this), describeNode: this._describeNode.bind(this), @@ -213,7 +150,7 @@ class PageAgent { insertText: this._insertText.bind(this), navigate: this._navigate.bind(this), reload: this._reload.bind(this), - removeScriptToEvaluateOnNewDocument: this._removeScriptToEvaluateOnNewDocument.bind(this), + removeScriptToEvaluateOnNewDocument: ({scriptId}) => this._frameTree.removeScriptToEvaluateOnNewDocument(scriptId), screenshot: this._screenshot.bind(this), scrollIntoViewIfNeeded: this._scrollIntoViewIfNeeded.bind(this), setCacheDisabled: this._setCacheDisabled.bind(this), @@ -227,27 +164,6 @@ class PageAgent { ]; } - _addScriptToEvaluateOnNewDocument({script, worldName}) { - if (worldName) - return this._createIsolatedWorld({script, worldName}); - return {scriptId: this._frameTree.addScriptToEvaluateOnNewDocument(script)}; - } - - _createIsolatedWorld({script, worldName}) { - const scriptId = helper.generateId(); - this._isolatedWorlds.set(scriptId, {script, worldName}); - for (const frameData of this._frameData.values()) - frameData.createIsolatedWorld(worldName); - return {scriptId}; - } - - _removeScriptToEvaluateOnNewDocument({scriptId}) { - if (this._isolatedWorlds.has(scriptId)) - this._isolatedWorlds.delete(scriptId); - else - this._frameTree.removeScriptToEvaluateOnNewDocument(scriptId); - } - _setCacheDisabled({cacheDisabled}) { const enable = Ci.nsIRequest.LOAD_NORMAL; const disable = Ci.nsIRequest.LOAD_BYPASS_CACHE | @@ -333,16 +249,16 @@ class PageAgent { _filePickerShown(inputElement) { if (inputElement.ownerGlobal.docShell !== this._docShell) return; - const frameData = this._findFrameForNode(inputElement); + const frame = this._findFrameForNode(inputElement); this._browserPage.emit('pageFileChooserOpened', { - executionContextId: frameData._frame.executionContext().id(), - element: frameData._frame.executionContext().rawValueToRemoteObject(inputElement) + executionContextId: frame.executionContext().id(), + element: frame.executionContext().rawValueToRemoteObject(inputElement) }); } _findFrameForNode(node) { - return Array.from(this._frameData.values()).find(data => { - const doc = data._frame.domWindow().document; + return this._frameTree.frames().find(frame => { + const doc = frame.domWindow().document; return node === doc || node.ownerDocument === doc; }); } @@ -404,10 +320,9 @@ class PageAgent { navigationId, errorText, }); - const frameData = this._frameData.get(frame); - if (!frameData._initialNavigationDone && frame !== this._frameTree.mainFrame()) + if (!frame._initialNavigationDone && frame !== this._frameTree.mainFrame()) this._emitAllEvents(frame); - frameData._initialNavigationDone = true; + frame._initialNavigationDone = true; } _onSameDocumentNavigation(frame) { @@ -424,11 +339,7 @@ class PageAgent { url: frame.url(), name: frame.name(), }); - this._frameData.get(frame)._initialNavigationDone = true; - } - - _onGlobalObjectCreated({ frame }) { - this._frameData.get(frame).reset(); + frame._initialNavigationDone = true; } _onFrameAttached(frame) { @@ -436,11 +347,9 @@ class PageAgent { frameId: frame.id(), parentFrameId: frame.parentFrame() ? frame.parentFrame().id() : undefined, }); - this._frameData.set(frame, new FrameData(this, this._runtime, frame)); } _onFrameDetached(frame) { - this._frameData.delete(frame); this._browserPage.emit('pageFrameDetached', { frameId: frame.id(), }); @@ -458,9 +367,6 @@ class PageAgent { for (const workerData of this._workerData.values()) workerData.dispose(); this._workerData.clear(); - for (const frameData of this._frameData.values()) - frameData.dispose(); - this._frameData.clear(); helper.removeListeners(this._eventListeners); } @@ -525,7 +431,7 @@ class PageAgent { const frame = this._frameTree.frame(frameId); if (!frame) throw new Error('Failed to find frame with id = ' + frameId); - const unsafeObject = this._frameData.get(frame).unsafeObject(objectId); + const unsafeObject = frame.unsafeObject(objectId); const context = this._runtime.findExecutionContext(executionContextId); const fromPrincipal = unsafeObject.nodePrincipal; const toFrame = this._frameTree.frame(context.auxData().frameId); @@ -539,7 +445,7 @@ class PageAgent { const frame = this._frameTree.frame(frameId); if (!frame) throw new Error('Failed to find frame with id = ' + frameId); - const unsafeObject = this._frameData.get(frame).unsafeObject(objectId); + const unsafeObject = frame.unsafeObject(objectId); if (!unsafeObject) throw new Error('Object is not input!'); const nsFiles = await Promise.all(files.map(filePath => File.createFromFileName(filePath))); @@ -550,7 +456,7 @@ class PageAgent { const frame = this._frameTree.frame(frameId); if (!frame) throw new Error('Failed to find frame with id = ' + frameId); - const unsafeObject = this._frameData.get(frame).unsafeObject(objectId); + const unsafeObject = frame.unsafeObject(objectId); if (!unsafeObject.getBoxQuads) throw new Error('RemoteObject is not a node'); const quads = unsafeObject.getBoxQuads({relativeTo: this._frameTree.mainFrame().domWindow().document}).map(quad => { @@ -568,7 +474,7 @@ class PageAgent { const frame = this._frameTree.frame(frameId); if (!frame) throw new Error('Failed to find frame with id = ' + frameId); - const unsafeObject = this._frameData.get(frame).unsafeObject(objectId); + const unsafeObject = frame.unsafeObject(objectId); const browsingContextGroup = frame.docShell().browsingContext.group; const frames = this._frameTree.allFramesInBrowsingContextGroup(browsingContextGroup); let contentFrame; @@ -590,7 +496,7 @@ class PageAgent { const frame = this._frameTree.frame(frameId); if (!frame) throw new Error('Failed to find frame with id = ' + frameId); - const unsafeObject = this._frameData.get(frame).unsafeObject(objectId); + const unsafeObject = frame.unsafeObject(objectId); if (!unsafeObject.isConnected) throw new Error('Node is detached from document'); if (!rect) @@ -877,7 +783,7 @@ class PageAgent { async _getFullAXTree({objectId}) { let unsafeObject = null; if (objectId) { - unsafeObject = this._frameData.get(this._frameTree.mainFrame()).unsafeObject(objectId); + unsafeObject = this._frameTree.mainFrame().unsafeObject(objectId); if (!unsafeObject) throw new Error(`No object found for id "${objectId}"`); }