| 
									
										
										
										
											2020-06-03 07:51:13 +08:00
										 |  |  | /* This Source Code Form is subject to the terms of the Mozilla Public | 
					
						
							|  |  |  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | 
					
						
							|  |  |  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | "use strict"; | 
					
						
							|  |  |  | const Ci = Components.interfaces; | 
					
						
							|  |  |  | const Cr = Components.results; | 
					
						
							|  |  |  | const Cu = Components.utils; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js'); | 
					
						
							|  |  |  | const {SimpleChannel} = ChromeUtils.import('chrome://juggler/content/SimpleChannel.js'); | 
					
						
							|  |  |  | const {Runtime} = ChromeUtils.import('chrome://juggler/content/content/Runtime.js'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const helper = new Helper(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class FrameTree { | 
					
						
							|  |  |  |   constructor(rootDocShell) { | 
					
						
							| 
									
										
										
										
											2023-01-24 03:29:48 +08:00
										 |  |  |     helper.decorateAsEventEmitter(this); | 
					
						
							| 
									
										
										
										
											2020-06-03 07:51:13 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     this._browsingContextGroup = rootDocShell.browsingContext.group; | 
					
						
							|  |  |  |     if (!this._browsingContextGroup.__jugglerFrameTrees) | 
					
						
							|  |  |  |       this._browsingContextGroup.__jugglerFrameTrees = new Set(); | 
					
						
							|  |  |  |     this._browsingContextGroup.__jugglerFrameTrees.add(this); | 
					
						
							| 
									
										
										
										
											2021-04-30 06:09:10 +08:00
										 |  |  |     this._isolatedWorlds = new Map(); | 
					
						
							| 
									
										
										
										
											2020-06-03 07:51:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-30 07:33:50 +08:00
										 |  |  |     this._webSocketEventService = Cc[ | 
					
						
							|  |  |  |       "@mozilla.org/websocketevent/service;1" | 
					
						
							|  |  |  |     ].getService(Ci.nsIWebSocketEventService); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-03 07:51:13 +08:00
										 |  |  |     this._runtime = new Runtime(false /* isWorker */); | 
					
						
							|  |  |  |     this._workers = new Map(); | 
					
						
							|  |  |  |     this._docShellToFrame = new Map(); | 
					
						
							|  |  |  |     this._frameIdToFrame = new Map(); | 
					
						
							|  |  |  |     this._pageReady = false; | 
					
						
							| 
									
										
										
										
											2023-01-24 03:29:48 +08:00
										 |  |  |     this._javaScriptDisabled = false; | 
					
						
							| 
									
										
										
										
											2020-06-03 07:51:13 +08:00
										 |  |  |     this._mainFrame = this._createFrame(rootDocShell); | 
					
						
							|  |  |  |     const webProgress = rootDocShell.QueryInterface(Ci.nsIInterfaceRequestor) | 
					
						
							|  |  |  |                                 .getInterface(Ci.nsIWebProgress); | 
					
						
							|  |  |  |     this.QueryInterface = ChromeUtils.generateQI([ | 
					
						
							|  |  |  |       Ci.nsIWebProgressListener, | 
					
						
							|  |  |  |       Ci.nsIWebProgressListener2, | 
					
						
							|  |  |  |       Ci.nsISupportsWeakReference, | 
					
						
							|  |  |  |     ]); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-14 23:06:34 +08:00
										 |  |  |     this._addedScrollbarsStylesheetSymbol = Symbol('_addedScrollbarsStylesheetSymbol'); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-03 07:51:13 +08:00
										 |  |  |     this._wdm = Cc["@mozilla.org/dom/workers/workerdebuggermanager;1"].createInstance(Ci.nsIWorkerDebuggerManager); | 
					
						
							|  |  |  |     this._wdmListener = { | 
					
						
							|  |  |  |       QueryInterface: ChromeUtils.generateQI([Ci.nsIWorkerDebuggerManagerListener]), | 
					
						
							|  |  |  |       onRegister: this._onWorkerCreated.bind(this), | 
					
						
							|  |  |  |       onUnregister: this._onWorkerDestroyed.bind(this), | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     this._wdm.addListener(this._wdmListener); | 
					
						
							|  |  |  |     for (const workerDebugger of this._wdm.getWorkerDebuggerEnumerator()) | 
					
						
							|  |  |  |       this._onWorkerCreated(workerDebugger); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const flags = Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT | | 
					
						
							| 
									
										
										
										
											2021-04-02 07:49:01 +08:00
										 |  |  |                   Ci.nsIWebProgress.NOTIFY_LOCATION; | 
					
						
							| 
									
										
										
										
											2020-06-03 07:51:13 +08:00
										 |  |  |     this._eventListeners = [ | 
					
						
							|  |  |  |       helper.addObserver(this._onDOMWindowCreated.bind(this), 'content-document-global-created'), | 
					
						
							| 
									
										
										
										
											2020-07-02 04:28:13 +08:00
										 |  |  |       helper.addObserver(this._onDOMWindowCreated.bind(this), 'juggler-dom-window-reused'), | 
					
						
							| 
									
										
										
										
											2020-06-03 07:51:13 +08:00
										 |  |  |       helper.addObserver(subject => this._onDocShellCreated(subject.QueryInterface(Ci.nsIDocShell)), 'webnavigation-create'), | 
					
						
							|  |  |  |       helper.addObserver(subject => this._onDocShellDestroyed(subject.QueryInterface(Ci.nsIDocShell)), 'webnavigation-destroy'), | 
					
						
							|  |  |  |       helper.addProgressListener(webProgress, this, flags), | 
					
						
							|  |  |  |     ]; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   workers() { | 
					
						
							|  |  |  |     return [...this._workers.values()]; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   runtime() { | 
					
						
							|  |  |  |     return this._runtime; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-15 12:32:12 +08:00
										 |  |  |   setInitScripts(scripts) { | 
					
						
							|  |  |  |     for (const world of this._isolatedWorlds.values()) | 
					
						
							|  |  |  |       world._scriptsToEvaluateOnNewDocument = []; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (let { worldName, script } of scripts) { | 
					
						
							|  |  |  |       worldName = worldName || ''; | 
					
						
							|  |  |  |       const existing = this._isolatedWorlds.has(worldName); | 
					
						
							|  |  |  |       const world = this._ensureWorld(worldName); | 
					
						
							|  |  |  |       world._scriptsToEvaluateOnNewDocument.push(script); | 
					
						
							|  |  |  |       // FIXME: 'should inherit http credentials from browser context' fails without this
 | 
					
						
							|  |  |  |       if (worldName && !existing) { | 
					
						
							|  |  |  |         for (const frame of this.frames()) | 
					
						
							|  |  |  |           frame._createIsolatedContext(worldName); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2021-04-30 06:09:10 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-12 23:52:08 +08:00
										 |  |  |   _ensureWorld(worldName) { | 
					
						
							|  |  |  |     worldName = worldName || ''; | 
					
						
							|  |  |  |     let world = this._isolatedWorlds.get(worldName); | 
					
						
							|  |  |  |     if (!world) { | 
					
						
							|  |  |  |       world = new IsolatedWorld(worldName); | 
					
						
							|  |  |  |       this._isolatedWorlds.set(worldName, world); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return world; | 
					
						
							| 
									
										
										
										
											2021-04-30 06:09:10 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-03 07:51:13 +08:00
										 |  |  |   _frameForWorker(workerDebugger) { | 
					
						
							|  |  |  |     if (workerDebugger.type !== Ci.nsIWorkerDebugger.TYPE_DEDICATED) | 
					
						
							|  |  |  |       return null; | 
					
						
							| 
									
										
										
										
											2020-06-09 06:54:47 +08:00
										 |  |  |     if (!workerDebugger.window) | 
					
						
							|  |  |  |       return null; | 
					
						
							| 
									
										
										
										
											2020-06-03 07:51:13 +08:00
										 |  |  |     const docShell = workerDebugger.window.docShell; | 
					
						
							|  |  |  |     return this._docShellToFrame.get(docShell) || null; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   _onDOMWindowCreated(window) { | 
					
						
							| 
									
										
										
										
											2021-05-14 23:06:34 +08:00
										 |  |  |     if (!window[this._addedScrollbarsStylesheetSymbol] && this.scrollbarsHidden) { | 
					
						
							|  |  |  |       const styleSheetService = Cc["@mozilla.org/content/style-sheet-service;1"].getService(Components.interfaces.nsIStyleSheetService); | 
					
						
							|  |  |  |       const ioService = Cc["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService); | 
					
						
							|  |  |  |       const uri = ioService.newURI('chrome://juggler/content/content/hidden-scrollbars.css', null, null); | 
					
						
							|  |  |  |       const sheet = styleSheetService.preloadSheet(uri, styleSheetService.AGENT_SHEET); | 
					
						
							|  |  |  |       window.windowUtils.addSheet(sheet, styleSheetService.AGENT_SHEET); | 
					
						
							|  |  |  |       window[this._addedScrollbarsStylesheetSymbol] = true; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-06-03 07:51:13 +08:00
										 |  |  |     const frame = this._docShellToFrame.get(window.docShell) || null; | 
					
						
							|  |  |  |     if (!frame) | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     frame._onGlobalObjectCleared(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-14 23:06:34 +08:00
										 |  |  |   setScrollbarsHidden(hidden) { | 
					
						
							|  |  |  |     this.scrollbarsHidden = hidden; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-24 03:29:48 +08:00
										 |  |  |   setJavaScriptDisabled(javaScriptDisabled) { | 
					
						
							|  |  |  |     this._javaScriptDisabled = javaScriptDisabled; | 
					
						
							|  |  |  |     for (const frame of this.frames()) | 
					
						
							|  |  |  |       frame._updateJavaScriptDisabled(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-03 07:51:13 +08:00
										 |  |  |   _onWorkerCreated(workerDebugger) { | 
					
						
							|  |  |  |     // Note: we do not interoperate with firefox devtools.
 | 
					
						
							|  |  |  |     if (workerDebugger.isInitialized) | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     const frame = this._frameForWorker(workerDebugger); | 
					
						
							|  |  |  |     if (!frame) | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     const worker = new Worker(frame, workerDebugger); | 
					
						
							|  |  |  |     this._workers.set(workerDebugger, worker); | 
					
						
							|  |  |  |     this.emit(FrameTree.Events.WorkerCreated, worker); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   _onWorkerDestroyed(workerDebugger) { | 
					
						
							|  |  |  |     const worker = this._workers.get(workerDebugger); | 
					
						
							|  |  |  |     if (!worker) | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     worker.dispose(); | 
					
						
							|  |  |  |     this._workers.delete(workerDebugger); | 
					
						
							|  |  |  |     this.emit(FrameTree.Events.WorkerDestroyed, worker); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   allFramesInBrowsingContextGroup(group) { | 
					
						
							|  |  |  |     const frames = []; | 
					
						
							|  |  |  |     for (const frameTree of (group.__jugglerFrameTrees || [])) | 
					
						
							|  |  |  |       frames.push(...frameTree.frames()); | 
					
						
							|  |  |  |     return frames; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   isPageReady() { | 
					
						
							|  |  |  |     return this._pageReady; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   forcePageReady() { | 
					
						
							|  |  |  |     if (this._pageReady) | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  |     this._pageReady = true; | 
					
						
							|  |  |  |     this.emit(FrameTree.Events.PageReady); | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-12 00:27:39 +08:00
										 |  |  |   addBinding(worldName, name, script) { | 
					
						
							| 
									
										
										
										
											2021-05-12 23:52:08 +08:00
										 |  |  |     worldName = worldName || ''; | 
					
						
							|  |  |  |     const world = this._ensureWorld(worldName); | 
					
						
							|  |  |  |     world._bindings.set(name, script); | 
					
						
							| 
									
										
										
										
											2020-06-03 07:51:13 +08:00
										 |  |  |     for (const frame of this.frames()) | 
					
						
							| 
									
										
										
										
											2021-05-12 00:27:39 +08:00
										 |  |  |       frame._addBinding(worldName, name, script); | 
					
						
							| 
									
										
										
										
											2020-06-03 07:51:13 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   frameForDocShell(docShell) { | 
					
						
							|  |  |  |     return this._docShellToFrame.get(docShell) || null; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   frame(frameId) { | 
					
						
							|  |  |  |     return this._frameIdToFrame.get(frameId) || null; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   frames() { | 
					
						
							|  |  |  |     let result = []; | 
					
						
							|  |  |  |     collect(this._mainFrame); | 
					
						
							|  |  |  |     return result; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     function collect(frame) { | 
					
						
							|  |  |  |       result.push(frame); | 
					
						
							|  |  |  |       for (const subframe of frame._children) | 
					
						
							|  |  |  |         collect(subframe); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   mainFrame() { | 
					
						
							|  |  |  |     return this._mainFrame; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   dispose() { | 
					
						
							|  |  |  |     this._browsingContextGroup.__jugglerFrameTrees.delete(this); | 
					
						
							|  |  |  |     this._wdm.removeListener(this._wdmListener); | 
					
						
							|  |  |  |     this._runtime.dispose(); | 
					
						
							|  |  |  |     helper.removeListeners(this._eventListeners); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   onStateChange(progress, request, flag, status) { | 
					
						
							|  |  |  |     if (!(request instanceof Ci.nsIChannel)) | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     const channel = request.QueryInterface(Ci.nsIChannel); | 
					
						
							|  |  |  |     const docShell = progress.DOMWindow.docShell; | 
					
						
							|  |  |  |     const frame = this._docShellToFrame.get(docShell); | 
					
						
							|  |  |  |     if (!frame) { | 
					
						
							| 
									
										
										
										
											2023-01-24 03:29:48 +08:00
										 |  |  |       dump(`WARNING: got a state changed event for un-tracked docshell!\n`); | 
					
						
							| 
									
										
										
										
											2020-06-03 07:51:13 +08:00
										 |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-10 01:29:34 +08:00
										 |  |  |     if (!channel.isDocument) { | 
					
						
							|  |  |  |       // Somehow, we can get worker requests here,
 | 
					
						
							|  |  |  |       // while we are only interested in frame documents.
 | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-03 07:51:13 +08:00
										 |  |  |     const isStart = flag & Ci.nsIWebProgressListener.STATE_START; | 
					
						
							|  |  |  |     const isTransferring = flag & Ci.nsIWebProgressListener.STATE_TRANSFERRING; | 
					
						
							|  |  |  |     const isStop = flag & Ci.nsIWebProgressListener.STATE_STOP; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (isStart) { | 
					
						
							|  |  |  |       // Starting a new navigation.
 | 
					
						
							| 
									
										
										
										
											2020-10-30 07:33:50 +08:00
										 |  |  |       frame._pendingNavigationId = channelId(channel); | 
					
						
							| 
									
										
										
										
											2020-06-03 07:51:13 +08:00
										 |  |  |       frame._pendingNavigationURL = channel.URI.spec; | 
					
						
							|  |  |  |       this.emit(FrameTree.Events.NavigationStarted, frame); | 
					
						
							| 
									
										
										
										
											2020-10-06 15:15:24 +08:00
										 |  |  |     } else if (isTransferring || (isStop && frame._pendingNavigationId && !status)) { | 
					
						
							| 
									
										
										
										
											2020-06-03 07:51:13 +08:00
										 |  |  |       // Navigation is committed.
 | 
					
						
							|  |  |  |       for (const subframe of frame._children) | 
					
						
							|  |  |  |         this._detachFrame(subframe); | 
					
						
							|  |  |  |       const navigationId = frame._pendingNavigationId; | 
					
						
							|  |  |  |       frame._pendingNavigationId = null; | 
					
						
							|  |  |  |       frame._pendingNavigationURL = null; | 
					
						
							|  |  |  |       frame._lastCommittedNavigationId = navigationId; | 
					
						
							|  |  |  |       frame._url = channel.URI.spec; | 
					
						
							|  |  |  |       this.emit(FrameTree.Events.NavigationCommitted, frame); | 
					
						
							|  |  |  |       if (frame === this._mainFrame) | 
					
						
							|  |  |  |         this.forcePageReady(); | 
					
						
							| 
									
										
										
										
											2020-10-06 15:15:24 +08:00
										 |  |  |     } else if (isStop && frame._pendingNavigationId && status) { | 
					
						
							| 
									
										
										
										
											2020-06-03 07:51:13 +08:00
										 |  |  |       // Navigation is aborted.
 | 
					
						
							|  |  |  |       const navigationId = frame._pendingNavigationId; | 
					
						
							|  |  |  |       frame._pendingNavigationId = null; | 
					
						
							|  |  |  |       frame._pendingNavigationURL = null; | 
					
						
							|  |  |  |       // Always report download navigation as failure to match other browsers.
 | 
					
						
							| 
									
										
										
										
											2020-10-06 15:15:24 +08:00
										 |  |  |       const errorText = helper.getNetworkErrorStatusText(status); | 
					
						
							| 
									
										
										
										
											2020-06-03 07:51:13 +08:00
										 |  |  |       this.emit(FrameTree.Events.NavigationAborted, frame, navigationId, errorText); | 
					
						
							| 
									
										
										
										
											2020-10-06 15:15:24 +08:00
										 |  |  |       if (frame === this._mainFrame && status !== Cr.NS_BINDING_ABORTED) | 
					
						
							| 
									
										
										
										
											2020-06-03 07:51:13 +08:00
										 |  |  |         this.forcePageReady(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-02 07:49:01 +08:00
										 |  |  |   onLocationChange(progress, request, location, flags) { | 
					
						
							| 
									
										
										
										
											2020-06-03 07:51:13 +08:00
										 |  |  |     const docShell = progress.DOMWindow.docShell; | 
					
						
							|  |  |  |     const frame = this._docShellToFrame.get(docShell); | 
					
						
							|  |  |  |     const sameDocumentNavigation = !!(flags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT); | 
					
						
							|  |  |  |     if (frame && sameDocumentNavigation) { | 
					
						
							|  |  |  |       frame._url = location.spec; | 
					
						
							|  |  |  |       this.emit(FrameTree.Events.SameDocumentNavigation, frame); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   _onDocShellCreated(docShell) { | 
					
						
							|  |  |  |     // Bug 1142752: sometimes, the docshell appears to be immediately
 | 
					
						
							|  |  |  |     // destroyed, bailout early to prevent random exceptions.
 | 
					
						
							|  |  |  |     if (docShell.isBeingDestroyed()) | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     // If this docShell doesn't belong to our frame tree - do nothing.
 | 
					
						
							|  |  |  |     let root = docShell; | 
					
						
							|  |  |  |     while (root.parent) | 
					
						
							|  |  |  |       root = root.parent; | 
					
						
							|  |  |  |     if (root === this._mainFrame._docShell) | 
					
						
							|  |  |  |       this._createFrame(docShell); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   _createFrame(docShell) { | 
					
						
							|  |  |  |     const parentFrame = this._docShellToFrame.get(docShell.parent) || null; | 
					
						
							| 
									
										
										
										
											2023-01-24 03:29:48 +08:00
										 |  |  |     if (!parentFrame && this._mainFrame) { | 
					
						
							|  |  |  |       dump(`WARNING: found docShell with the same root, but no parent!\n`); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-06-03 07:51:13 +08:00
										 |  |  |     const frame = new Frame(this, this._runtime, docShell, parentFrame); | 
					
						
							|  |  |  |     this._docShellToFrame.set(docShell, frame); | 
					
						
							|  |  |  |     this._frameIdToFrame.set(frame.id(), frame); | 
					
						
							|  |  |  |     this.emit(FrameTree.Events.FrameAttached, frame); | 
					
						
							|  |  |  |     // Create execution context **after** reporting frame.
 | 
					
						
							|  |  |  |     // This is our protocol contract.
 | 
					
						
							|  |  |  |     if (frame.domWindow()) | 
					
						
							|  |  |  |       frame._onGlobalObjectCleared(); | 
					
						
							|  |  |  |     return frame; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   _onDocShellDestroyed(docShell) { | 
					
						
							|  |  |  |     const frame = this._docShellToFrame.get(docShell); | 
					
						
							|  |  |  |     if (frame) | 
					
						
							|  |  |  |       this._detachFrame(frame); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   _detachFrame(frame) { | 
					
						
							|  |  |  |     // Detach all children first
 | 
					
						
							|  |  |  |     for (const subframe of frame._children) | 
					
						
							|  |  |  |       this._detachFrame(subframe); | 
					
						
							| 
									
										
										
										
											2023-01-24 03:29:48 +08:00
										 |  |  |     if (frame === this._mainFrame) { | 
					
						
							|  |  |  |       // Do not detach main frame (happens during cross-process navigation),
 | 
					
						
							|  |  |  |       // as it confuses the client.
 | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-06-03 07:51:13 +08:00
										 |  |  |     this._docShellToFrame.delete(frame._docShell); | 
					
						
							|  |  |  |     this._frameIdToFrame.delete(frame.id()); | 
					
						
							|  |  |  |     if (frame._parentFrame) | 
					
						
							|  |  |  |       frame._parentFrame._children.delete(frame); | 
					
						
							|  |  |  |     frame._parentFrame = null; | 
					
						
							|  |  |  |     frame.dispose(); | 
					
						
							|  |  |  |     this.emit(FrameTree.Events.FrameDetached, frame); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | FrameTree.Events = { | 
					
						
							|  |  |  |   FrameAttached: 'frameattached', | 
					
						
							|  |  |  |   FrameDetached: 'framedetached', | 
					
						
							|  |  |  |   WorkerCreated: 'workercreated', | 
					
						
							|  |  |  |   WorkerDestroyed: 'workerdestroyed', | 
					
						
							| 
									
										
										
										
											2020-10-30 07:33:50 +08:00
										 |  |  |   WebSocketCreated: 'websocketcreated', | 
					
						
							|  |  |  |   WebSocketOpened: 'websocketopened', | 
					
						
							|  |  |  |   WebSocketClosed: 'websocketclosed', | 
					
						
							|  |  |  |   WebSocketFrameReceived: 'websocketframereceived', | 
					
						
							|  |  |  |   WebSocketFrameSent: 'websocketframesent', | 
					
						
							| 
									
										
										
										
											2020-06-03 07:51:13 +08:00
										 |  |  |   NavigationStarted: 'navigationstarted', | 
					
						
							|  |  |  |   NavigationCommitted: 'navigationcommitted', | 
					
						
							|  |  |  |   NavigationAborted: 'navigationaborted', | 
					
						
							|  |  |  |   SameDocumentNavigation: 'samedocumentnavigation', | 
					
						
							|  |  |  |   PageReady: 'pageready', | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-12 23:52:08 +08:00
										 |  |  | class IsolatedWorld { | 
					
						
							|  |  |  |   constructor(name) { | 
					
						
							|  |  |  |     this._name = name; | 
					
						
							|  |  |  |     this._scriptsToEvaluateOnNewDocument = []; | 
					
						
							|  |  |  |     this._bindings = new Map(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-03 07:51:13 +08:00
										 |  |  | class Frame { | 
					
						
							|  |  |  |   constructor(frameTree, runtime, docShell, parentFrame) { | 
					
						
							|  |  |  |     this._frameTree = frameTree; | 
					
						
							|  |  |  |     this._runtime = runtime; | 
					
						
							|  |  |  |     this._docShell = docShell; | 
					
						
							|  |  |  |     this._children = new Set(); | 
					
						
							| 
									
										
										
										
											2020-09-30 02:22:00 +08:00
										 |  |  |     this._frameId = helper.browsingContextToFrameId(this._docShell.browsingContext); | 
					
						
							| 
									
										
										
										
											2020-06-03 07:51:13 +08:00
										 |  |  |     this._parentFrame = null; | 
					
						
							|  |  |  |     this._url = ''; | 
					
						
							|  |  |  |     if (docShell.domWindow && docShell.domWindow.location) | 
					
						
							|  |  |  |       this._url = docShell.domWindow.location.href; | 
					
						
							|  |  |  |     if (parentFrame) { | 
					
						
							|  |  |  |       this._parentFrame = parentFrame; | 
					
						
							|  |  |  |       parentFrame._children.add(this); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     this._lastCommittedNavigationId = null; | 
					
						
							|  |  |  |     this._pendingNavigationId = null; | 
					
						
							|  |  |  |     this._pendingNavigationURL = null; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     this._textInputProcessor = null; | 
					
						
							| 
									
										
										
										
											2020-10-30 07:33:50 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-12 23:52:08 +08:00
										 |  |  |     this._worldNameToContext = new Map(); | 
					
						
							| 
									
										
										
										
											2021-04-30 06:09:10 +08:00
										 |  |  |     this._initialNavigationDone = false; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-30 07:33:50 +08:00
										 |  |  |     this._webSocketListenerInnerWindowId = 0; | 
					
						
							|  |  |  |     // WebSocketListener calls frameReceived event before webSocketOpened.
 | 
					
						
							|  |  |  |     // To avoid this, serialize event reporting.
 | 
					
						
							|  |  |  |     this._webSocketInfos = new Map(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const dispatchWebSocketFrameReceived = (webSocketSerialID, frame) => this._frameTree.emit(FrameTree.Events.WebSocketFrameReceived, { | 
					
						
							|  |  |  |       frameId: this._frameId, | 
					
						
							|  |  |  |       wsid: webSocketSerialID + '', | 
					
						
							|  |  |  |       opcode: frame.opCode, | 
					
						
							|  |  |  |       data: frame.opCode !== 1 ? btoa(frame.payload) : frame.payload, | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     this._webSocketListener = { | 
					
						
							|  |  |  |       QueryInterface: ChromeUtils.generateQI([Ci.nsIWebSocketEventListener, ]), | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       webSocketCreated: (webSocketSerialID, uri, protocols) => { | 
					
						
							|  |  |  |         this._frameTree.emit(FrameTree.Events.WebSocketCreated, { | 
					
						
							|  |  |  |           frameId: this._frameId, | 
					
						
							|  |  |  |           wsid: webSocketSerialID + '', | 
					
						
							|  |  |  |           requestURL: uri, | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |         this._webSocketInfos.set(webSocketSerialID, { | 
					
						
							|  |  |  |           opened: false, | 
					
						
							|  |  |  |           pendingIncomingFrames: [], | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       webSocketOpened: (webSocketSerialID, effectiveURI, protocols, extensions, httpChannelId) => { | 
					
						
							|  |  |  |         this._frameTree.emit(FrameTree.Events.WebSocketOpened, { | 
					
						
							|  |  |  |           frameId: this._frameId, | 
					
						
							|  |  |  |           requestId: httpChannelId + '', | 
					
						
							|  |  |  |           wsid: webSocketSerialID + '', | 
					
						
							|  |  |  |           effectiveURL: effectiveURI, | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |         const info = this._webSocketInfos.get(webSocketSerialID); | 
					
						
							|  |  |  |         info.opened = true; | 
					
						
							|  |  |  |         for (const frame of info.pendingIncomingFrames) | 
					
						
							|  |  |  |           dispatchWebSocketFrameReceived(webSocketSerialID, frame); | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       webSocketMessageAvailable: (webSocketSerialID, data, messageType) => { | 
					
						
							|  |  |  |         // We don't use this event.
 | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       webSocketClosed: (webSocketSerialID, wasClean, code, reason) => { | 
					
						
							|  |  |  |         this._webSocketInfos.delete(webSocketSerialID); | 
					
						
							|  |  |  |         let error = ''; | 
					
						
							|  |  |  |         if (!wasClean) { | 
					
						
							|  |  |  |           const keys = Object.keys(Ci.nsIWebSocketChannel); | 
					
						
							|  |  |  |           for (const key of keys) { | 
					
						
							|  |  |  |             if (Ci.nsIWebSocketChannel[key] === code) | 
					
						
							|  |  |  |               error = key; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         this._frameTree.emit(FrameTree.Events.WebSocketClosed, { | 
					
						
							|  |  |  |           frameId: this._frameId, | 
					
						
							|  |  |  |           wsid: webSocketSerialID + '', | 
					
						
							|  |  |  |           error, | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       frameReceived: (webSocketSerialID, frame) => { | 
					
						
							|  |  |  |         // Report only text and binary frames.
 | 
					
						
							|  |  |  |         if (frame.opCode !== 1 && frame.opCode !== 2) | 
					
						
							|  |  |  |           return; | 
					
						
							|  |  |  |         const info = this._webSocketInfos.get(webSocketSerialID); | 
					
						
							|  |  |  |         if (info.opened) | 
					
						
							|  |  |  |           dispatchWebSocketFrameReceived(webSocketSerialID, frame); | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |           info.pendingIncomingFrames.push(frame); | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       frameSent: (webSocketSerialID, frame) => { | 
					
						
							|  |  |  |         // Report only text and binary frames.
 | 
					
						
							|  |  |  |         if (frame.opCode !== 1 && frame.opCode !== 2) | 
					
						
							|  |  |  |           return; | 
					
						
							|  |  |  |         this._frameTree.emit(FrameTree.Events.WebSocketFrameSent, { | 
					
						
							|  |  |  |           frameId: this._frameId, | 
					
						
							|  |  |  |           wsid: webSocketSerialID + '', | 
					
						
							|  |  |  |           opcode: frame.opCode, | 
					
						
							|  |  |  |           data: frame.opCode !== 1 ? btoa(frame.payload) : frame.payload, | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2020-06-03 07:51:13 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-12 23:52:08 +08:00
										 |  |  |   _createIsolatedContext(name) { | 
					
						
							| 
									
										
										
										
											2021-04-30 06:09:10 +08:00
										 |  |  |     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, | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2021-05-12 23:52:08 +08:00
										 |  |  |     this._worldNameToContext.set(name, world); | 
					
						
							| 
									
										
										
										
											2021-04-30 06:09:10 +08:00
										 |  |  |     return world; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   unsafeObject(objectId) { | 
					
						
							| 
									
										
										
										
											2021-05-12 23:52:08 +08:00
										 |  |  |     for (const context of this._worldNameToContext.values()) { | 
					
						
							| 
									
										
										
										
											2021-04-30 06:09:10 +08:00
										 |  |  |       const result = context.unsafeObject(objectId); | 
					
						
							|  |  |  |       if (result) | 
					
						
							|  |  |  |         return result.object; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     throw new Error('Cannot find object with id = ' + objectId); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-03 07:51:13 +08:00
										 |  |  |   dispose() { | 
					
						
							| 
									
										
										
										
											2021-05-12 23:52:08 +08:00
										 |  |  |     for (const context of this._worldNameToContext.values()) | 
					
						
							|  |  |  |       this._runtime.destroyExecutionContext(context); | 
					
						
							|  |  |  |     this._worldNameToContext.clear(); | 
					
						
							| 
									
										
										
										
											2021-05-12 00:27:39 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   _addBinding(worldName, name, script) { | 
					
						
							| 
									
										
										
										
											2021-05-12 23:52:08 +08:00
										 |  |  |     let executionContext = this._worldNameToContext.get(worldName); | 
					
						
							|  |  |  |     if (worldName && !executionContext) | 
					
						
							|  |  |  |       executionContext = this._createIsolatedContext(worldName); | 
					
						
							| 
									
										
										
										
											2021-05-12 00:27:39 +08:00
										 |  |  |     if (executionContext) | 
					
						
							|  |  |  |       executionContext.addBinding(name, script); | 
					
						
							| 
									
										
										
										
											2021-05-09 09:06:56 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-03 07:51:13 +08:00
										 |  |  |   _onGlobalObjectCleared() { | 
					
						
							| 
									
										
										
										
											2020-10-30 07:33:50 +08:00
										 |  |  |     const webSocketService = this._frameTree._webSocketEventService; | 
					
						
							|  |  |  |     if (this._webSocketListenerInnerWindowId) | 
					
						
							|  |  |  |       webSocketService.removeListener(this._webSocketListenerInnerWindowId, this._webSocketListener); | 
					
						
							|  |  |  |     this._webSocketListenerInnerWindowId = this.domWindow().windowGlobalChild.innerWindowId; | 
					
						
							|  |  |  |     webSocketService.addListener(this._webSocketListenerInnerWindowId, this._webSocketListener); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-12 23:52:08 +08:00
										 |  |  |     for (const context of this._worldNameToContext.values()) | 
					
						
							|  |  |  |       this._runtime.destroyExecutionContext(context); | 
					
						
							|  |  |  |     this._worldNameToContext.clear(); | 
					
						
							| 
									
										
										
										
											2021-05-12 00:27:39 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-12 23:52:08 +08:00
										 |  |  |     this._worldNameToContext.set('', this._runtime.createExecutionContext(this.domWindow(), this.domWindow(), { | 
					
						
							| 
									
										
										
										
											2020-06-03 07:51:13 +08:00
										 |  |  |       frameId: this._frameId, | 
					
						
							|  |  |  |       name: '', | 
					
						
							| 
									
										
										
										
											2021-05-12 23:52:08 +08:00
										 |  |  |     })); | 
					
						
							|  |  |  |     for (const [name, world] of this._frameTree._isolatedWorlds) { | 
					
						
							|  |  |  |       if (name) | 
					
						
							|  |  |  |         this._createIsolatedContext(name); | 
					
						
							|  |  |  |       const executionContext = this._worldNameToContext.get(name); | 
					
						
							|  |  |  |       // Add bindings before evaluating scripts.
 | 
					
						
							|  |  |  |       for (const [name, script] of world._bindings) | 
					
						
							|  |  |  |         executionContext.addBinding(name, script); | 
					
						
							|  |  |  |       for (const script of world._scriptsToEvaluateOnNewDocument) | 
					
						
							|  |  |  |         executionContext.evaluateScriptSafely(script); | 
					
						
							| 
									
										
										
										
											2021-04-30 06:09:10 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-01-24 03:29:48 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     const url = this.domWindow().location?.href; | 
					
						
							|  |  |  |     if (url === 'about:blank' && !this._url) { | 
					
						
							|  |  |  |       // Sometimes FrameTree is created too early, before the location has been set.
 | 
					
						
							|  |  |  |       this._url = url; | 
					
						
							|  |  |  |       this._frameTree.emit(FrameTree.Events.NavigationCommitted, this); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     this._updateJavaScriptDisabled(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   _updateJavaScriptDisabled() { | 
					
						
							|  |  |  |     if (this._docShell.browsingContext.currentWindowContext) | 
					
						
							|  |  |  |       this._docShell.browsingContext.currentWindowContext.allowJavascript = !this._frameTree._javaScriptDisabled; | 
					
						
							| 
									
										
										
										
											2020-06-03 07:51:13 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-12 23:52:08 +08:00
										 |  |  |   mainExecutionContext() { | 
					
						
							|  |  |  |     return this._worldNameToContext.get(''); | 
					
						
							| 
									
										
										
										
											2020-06-03 07:51:13 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   textInputProcessor() { | 
					
						
							|  |  |  |     if (!this._textInputProcessor) { | 
					
						
							|  |  |  |       this._textInputProcessor = Cc["@mozilla.org/text-input-processor;1"].createInstance(Ci.nsITextInputProcessor); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-11-12 02:23:00 +08:00
										 |  |  |     this._textInputProcessor.beginInputTransactionForTests(this._docShell.DOMWindow); | 
					
						
							| 
									
										
										
										
											2020-06-03 07:51:13 +08:00
										 |  |  |     return this._textInputProcessor; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   pendingNavigationId() { | 
					
						
							|  |  |  |     return this._pendingNavigationId; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   pendingNavigationURL() { | 
					
						
							|  |  |  |     return this._pendingNavigationURL; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   lastCommittedNavigationId() { | 
					
						
							|  |  |  |     return this._lastCommittedNavigationId; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   docShell() { | 
					
						
							|  |  |  |     return this._docShell; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   domWindow() { | 
					
						
							|  |  |  |     return this._docShell.domWindow; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   name() { | 
					
						
							|  |  |  |     const frameElement = this._docShell.domWindow.frameElement; | 
					
						
							|  |  |  |     let name = ''; | 
					
						
							|  |  |  |     if (frameElement) | 
					
						
							|  |  |  |       name = frameElement.getAttribute('name') || frameElement.getAttribute('id') || ''; | 
					
						
							|  |  |  |     return name; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   parentFrame() { | 
					
						
							|  |  |  |     return this._parentFrame; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   id() { | 
					
						
							|  |  |  |     return this._frameId; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   url() { | 
					
						
							|  |  |  |     return this._url; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Worker { | 
					
						
							|  |  |  |   constructor(frame, workerDebugger) { | 
					
						
							|  |  |  |     this._frame = frame; | 
					
						
							|  |  |  |     this._workerId = helper.generateId(); | 
					
						
							|  |  |  |     this._workerDebugger = workerDebugger; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     workerDebugger.initialize('chrome://juggler/content/content/WorkerMain.js'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     this._channel = new SimpleChannel(`content::worker[${this._workerId}]`); | 
					
						
							| 
									
										
										
										
											2020-11-03 08:21:34 +08:00
										 |  |  |     this._channel.setTransport({ | 
					
						
							| 
									
										
										
										
											2020-06-03 07:51:13 +08:00
										 |  |  |       sendMessage: obj => workerDebugger.postMessage(JSON.stringify(obj)), | 
					
						
							|  |  |  |       dispose: () => {}, | 
					
						
							| 
									
										
										
										
											2020-11-03 08:21:34 +08:00
										 |  |  |     }); | 
					
						
							| 
									
										
										
										
											2020-06-03 07:51:13 +08:00
										 |  |  |     this._workerDebuggerListener = { | 
					
						
							|  |  |  |       QueryInterface: ChromeUtils.generateQI([Ci.nsIWorkerDebuggerListener]), | 
					
						
							|  |  |  |       onMessage: msg => void this._channel._onMessage(JSON.parse(msg)), | 
					
						
							|  |  |  |       onClose: () => void this._channel.dispose(), | 
					
						
							|  |  |  |       onError: (filename, lineno, message) => { | 
					
						
							| 
									
										
										
										
											2023-01-24 03:29:48 +08:00
										 |  |  |         dump(`WARNING: Error in worker: ${message} @${filename}:${lineno}\n`); | 
					
						
							| 
									
										
										
										
											2020-06-03 07:51:13 +08:00
										 |  |  |       }, | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     workerDebugger.addListener(this._workerDebuggerListener); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   channel() { | 
					
						
							|  |  |  |     return this._channel; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   frame() { | 
					
						
							|  |  |  |     return this._frame; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   id() { | 
					
						
							|  |  |  |     return this._workerId; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   url() { | 
					
						
							|  |  |  |     return this._workerDebugger.url; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   dispose() { | 
					
						
							|  |  |  |     this._channel.dispose(); | 
					
						
							|  |  |  |     this._workerDebugger.removeListener(this._workerDebuggerListener); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-30 07:33:50 +08:00
										 |  |  | function channelId(channel) { | 
					
						
							|  |  |  |   if (channel instanceof Ci.nsIIdentChannel) { | 
					
						
							|  |  |  |     const identChannel = channel.QueryInterface(Ci.nsIIdentChannel); | 
					
						
							|  |  |  |     return String(identChannel.channelId); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return helper.generateId(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-03 07:51:13 +08:00
										 |  |  | var EXPORTED_SYMBOLS = ['FrameTree']; | 
					
						
							|  |  |  | this.FrameTree = FrameTree; | 
					
						
							|  |  |  | 
 |