@@ -14,10 +14,12 @@ const {Runtime} = ChromeUtils.import('chrome://juggler/content/content/Runtime.j
14
14
const helper = new Helper ( ) ;
15
15
16
16
class FrameTree {
17
- constructor ( rootDocShell ) {
17
+ constructor ( rootBrowsingContext ) {
18
18
helper . decorateAsEventEmitter ( this ) ;
19
19
20
- this . _browsingContextGroup = rootDocShell . browsingContext . group ;
20
+ this . _rootBrowsingContext = rootBrowsingContext ;
21
+
22
+ this . _browsingContextGroup = rootBrowsingContext . group ;
21
23
if ( ! this . _browsingContextGroup . __jugglerFrameTrees )
22
24
this . _browsingContextGroup . __jugglerFrameTrees = new Set ( ) ;
23
25
this . _browsingContextGroup . __jugglerFrameTrees . add ( this ) ;
@@ -29,12 +31,14 @@ class FrameTree {
29
31
30
32
this . _runtime = new Runtime ( false /* isWorker */ ) ;
31
33
this . _workers = new Map ( ) ;
32
- this . _docShellToFrame = new Map ( ) ;
33
34
this . _frameIdToFrame = new Map ( ) ;
34
35
this . _pageReady = false ;
35
36
this . _javaScriptDisabled = false ;
36
- this . _mainFrame = this . _createFrame ( rootDocShell ) ;
37
- const webProgress = rootDocShell . QueryInterface ( Ci . nsIInterfaceRequestor )
37
+ for ( const browsingContext of helper . collectAllBrowsingContexts ( rootBrowsingContext ) )
38
+ this . _createFrame ( browsingContext ) ;
39
+ this . _mainFrame = this . frameForBrowsingContext ( rootBrowsingContext ) ;
40
+
41
+ const webProgress = rootBrowsingContext . docShell . QueryInterface ( Ci . nsIInterfaceRequestor )
38
42
. getInterface ( Ci . nsIWebProgress ) ;
39
43
this . QueryInterface = ChromeUtils . generateQI ( [
40
44
Ci . nsIWebProgressListener ,
@@ -58,16 +62,20 @@ class FrameTree {
58
62
Ci . nsIWebProgress . NOTIFY_LOCATION ;
59
63
this . _eventListeners = [
60
64
helper . addObserver ( ( docShell , topic , loadIdentifier ) => {
61
- const frame = this . _docShellToFrame . get ( docShell ) ;
65
+ const frame = this . frameForDocShell ( docShell ) ;
62
66
if ( ! frame )
63
67
return ;
64
68
frame . _pendingNavigationId = helper . toProtocolNavigationId ( loadIdentifier ) ;
65
69
this . emit ( FrameTree . Events . NavigationStarted , frame ) ;
66
70
} , 'juggler-navigation-started-renderer' ) ,
67
71
helper . addObserver ( this . _onDOMWindowCreated . bind ( this ) , 'content-document-global-created' ) ,
68
72
helper . addObserver ( this . _onDOMWindowCreated . bind ( this ) , 'juggler-dom-window-reused' ) ,
69
- helper . addObserver ( subject => this . _onDocShellCreated ( subject . QueryInterface ( Ci . nsIDocShell ) ) , 'webnavigation-create' ) ,
70
- helper . addObserver ( subject => this . _onDocShellDestroyed ( subject . QueryInterface ( Ci . nsIDocShell ) ) , 'webnavigation-destroy' ) ,
73
+ helper . addObserver ( ( browsingContext , topic , why ) => {
74
+ this . _onBrowsingContextAttached ( browsingContext ) ;
75
+ } , 'browsing-context-attached' ) ,
76
+ helper . addObserver ( ( browsingContext , topic , why ) => {
77
+ this . _onBrowsingContextDetached ( browsingContext ) ;
78
+ } , 'browsing-context-discarded' ) ,
71
79
helper . addProgressListener ( webProgress , this , flags ) ,
72
80
] ;
73
81
@@ -114,8 +122,7 @@ class FrameTree {
114
122
return null ;
115
123
if ( ! workerDebugger . window )
116
124
return null ;
117
- const docShell = workerDebugger . window . docShell ;
118
- return this . _docShellToFrame . get ( docShell ) || null ;
125
+ return this . frameForDocShell ( workerDebugger . window . docShell ) ;
119
126
}
120
127
121
128
_onDOMWindowCreated ( window ) {
@@ -127,7 +134,7 @@ class FrameTree {
127
134
window . windowUtils . addSheet ( sheet , styleSheetService . AGENT_SHEET ) ;
128
135
window [ this . _addedScrollbarsStylesheetSymbol ] = true ;
129
136
}
130
- const frame = this . _docShellToFrame . get ( window . docShell ) || null ;
137
+ const frame = this . frameForDocShell ( window . docShell ) ;
131
138
if ( ! frame )
132
139
return ;
133
140
frame . _onGlobalObjectCleared ( ) ;
@@ -202,8 +209,18 @@ class FrameTree {
202
209
frame . _addBinding ( worldName , name , script ) ;
203
210
}
204
211
212
+ frameForBrowsingContext ( browsingContext ) {
213
+ if ( ! browsingContext )
214
+ return null ;
215
+ const frameId = helper . browsingContextToFrameId ( browsingContext ) ;
216
+ return this . _frameIdToFrame . get ( frameId ) ?? null ;
217
+ }
218
+
205
219
frameForDocShell ( docShell ) {
206
- return this . _docShellToFrame . get ( docShell ) || null ;
220
+ if ( ! docShell )
221
+ return null ;
222
+ const frameId = helper . browsingContextToFrameId ( docShell . browsingContext ) ;
223
+ return this . _frameIdToFrame . get ( frameId ) ?? null ;
207
224
}
208
225
209
226
frame ( frameId ) {
@@ -246,9 +263,9 @@ class FrameTree {
246
263
return ;
247
264
248
265
const docShell = event . target . ownerGlobal . docShell ;
249
- const frame = this . _docShellToFrame . get ( docShell ) ;
266
+ const frame = this . frameForDocShell ( docShell ) ;
250
267
if ( ! frame ) {
251
- dump ( `WARNING: ${ event . type } for unknown frame ${ docShell . browsingContext . id } \n` ) ;
268
+ dump ( `WARNING: ${ event . type } for unknown frame ${ helper . browsingContextToFrameId ( docShell . browsingContext ) } \n` ) ;
252
269
return ;
253
270
}
254
271
if ( frame . _pendingNavigationId ) {
@@ -292,7 +309,7 @@ class FrameTree {
292
309
return ;
293
310
const channel = request . QueryInterface ( Ci . nsIChannel ) ;
294
311
const docShell = progress . DOMWindow . docShell ;
295
- const frame = this . _docShellToFrame . get ( docShell ) ;
312
+ const frame = this . frameForDocShell ( docShell ) ;
296
313
if ( ! frame )
297
314
return ;
298
315
@@ -317,38 +334,37 @@ class FrameTree {
317
334
318
335
onLocationChange ( progress , request , location , flags ) {
319
336
const docShell = progress . DOMWindow . docShell ;
320
- const frame = this . _docShellToFrame . get ( docShell ) ;
337
+ const frame = this . frameForDocShell ( docShell ) ;
321
338
const sameDocumentNavigation = ! ! ( flags & Ci . nsIWebProgressListener . LOCATION_CHANGE_SAME_DOCUMENT ) ;
322
339
if ( frame && sameDocumentNavigation ) {
323
340
frame . _url = location . spec ;
324
341
this . emit ( FrameTree . Events . SameDocumentNavigation , frame ) ;
325
342
}
326
343
}
327
344
328
- _onDocShellCreated ( docShell ) {
329
- // Bug 1142752: sometimes, the docshell appears to be immediately
330
- // destroyed, bailout early to prevent random exceptions.
331
- if ( docShell . isBeingDestroyed ( ) )
345
+ _onBrowsingContextAttached ( browsingContext ) {
346
+ // If this browsing context doesn't belong to our frame tree - do nothing.
347
+ if ( browsingContext . top !== this . _rootBrowsingContext )
332
348
return ;
333
- // If this docShell doesn't belong to our frame tree - do nothing.
334
- let root = docShell ;
335
- while ( root . parent )
336
- root = root . parent ;
337
- if ( root === this . _mainFrame . _docShell )
338
- this . _createFrame ( docShell ) ;
349
+ this . _createFrame ( browsingContext ) ;
350
+ }
351
+
352
+ _onBrowsingContextDetached ( browsingContext ) {
353
+ const frame = this . frameForBrowsingContext ( browsingContext ) ;
354
+ if ( frame )
355
+ this . _detachFrame ( frame ) ;
339
356
}
340
357
341
- _createFrame ( docShell ) {
342
- const parentFrame = this . _docShellToFrame . get ( docShell . parent ) || null ;
358
+ _createFrame ( browsingContext ) {
359
+ const parentFrame = this . frameForBrowsingContext ( browsingContext . parent ) ;
343
360
if ( ! parentFrame && this . _mainFrame ) {
344
361
dump ( `WARNING: found docShell with the same root, but no parent!\n` ) ;
345
362
return ;
346
363
}
347
- const frame = new Frame ( this , this . _runtime , docShell , parentFrame ) ;
348
- this . _docShellToFrame . set ( docShell , frame ) ;
364
+ const frame = new Frame ( this , this . _runtime , browsingContext , parentFrame ) ;
349
365
this . _frameIdToFrame . set ( frame . id ( ) , frame ) ;
350
- if ( docShell . domWindow && docShell . domWindow . location )
351
- frame . _url = docShell . domWindow . location . href ;
366
+ if ( browsingContext . docShell ? .domWindow && browsingContext . docShell ? .domWindow . location )
367
+ frame . _url = browsingContext . docShell . domWindow . location . href ;
352
368
this . emit ( FrameTree . Events . FrameAttached , frame ) ;
353
369
// Create execution context **after** reporting frame.
354
370
// This is our protocol contract.
@@ -357,12 +373,6 @@ class FrameTree {
357
373
return frame ;
358
374
}
359
375
360
- _onDocShellDestroyed ( docShell ) {
361
- const frame = this . _docShellToFrame . get ( docShell ) ;
362
- if ( frame )
363
- this . _detachFrame ( frame ) ;
364
- }
365
-
366
376
_detachFrame ( frame ) {
367
377
// Detach all children first
368
378
for ( const subframe of frame . _children )
@@ -372,7 +382,6 @@ class FrameTree {
372
382
// as it confuses the client.
373
383
return ;
374
384
}
375
- this . _docShellToFrame . delete ( frame . _docShell ) ;
376
385
this . _frameIdToFrame . delete ( frame . id ( ) ) ;
377
386
if ( frame . _parentFrame )
378
387
frame . _parentFrame . _children . delete ( frame ) ;
@@ -409,12 +418,12 @@ class IsolatedWorld {
409
418
}
410
419
411
420
class Frame {
412
- constructor ( frameTree , runtime , docShell , parentFrame ) {
421
+ constructor ( frameTree , runtime , browsingContext , parentFrame ) {
413
422
this . _frameTree = frameTree ;
414
423
this . _runtime = runtime ;
415
- this . _docShell = docShell ;
424
+ this . _browsingContext = browsingContext ;
416
425
this . _children = new Set ( ) ;
417
- this . _frameId = helper . browsingContextToFrameId ( this . _docShell . browsingContext ) ;
426
+ this . _frameId = helper . browsingContextToFrameId ( browsingContext ) ;
418
427
this . _parentFrame = null ;
419
428
this . _url = '' ;
420
429
if ( parentFrame ) {
@@ -556,7 +565,7 @@ class Frame {
556
565
557
566
_onGlobalObjectCleared ( ) {
558
567
const webSocketService = this . _frameTree . _webSocketEventService ;
559
- if ( this . _webSocketListenerInnerWindowId )
568
+ if ( this . _webSocketListenerInnerWindowId && webSocketService . hasListenerFor ( this . _webSocketListenerInnerWindowId ) )
560
569
webSocketService . removeListener ( this . _webSocketListenerInnerWindowId , this . _webSocketListener ) ;
561
570
this . _webSocketListenerInnerWindowId = this . domWindow ( ) . windowGlobalChild . innerWindowId ;
562
571
webSocketService . addListener ( this . _webSocketListenerInnerWindowId , this . _webSocketListener ) ;
@@ -591,8 +600,8 @@ class Frame {
591
600
}
592
601
593
602
_updateJavaScriptDisabled ( ) {
594
- if ( this . _docShell . browsingContext . currentWindowContext )
595
- this . _docShell . browsingContext . currentWindowContext . allowJavascript = ! this . _frameTree . _javaScriptDisabled ;
603
+ if ( this . _browsingContext . currentWindowContext )
604
+ this . _browsingContext . currentWindowContext . allowJavascript = ! this . _frameTree . _javaScriptDisabled ;
596
605
}
597
606
598
607
mainExecutionContext ( ) {
@@ -603,7 +612,7 @@ class Frame {
603
612
if ( ! this . _textInputProcessor ) {
604
613
this . _textInputProcessor = Cc [ "@mozilla.org/text-input-processor;1" ] . createInstance ( Ci . nsITextInputProcessor ) ;
605
614
}
606
- this . _textInputProcessor . beginInputTransactionForTests ( this . _docShell . DOMWindow ) ;
615
+ this . _textInputProcessor . beginInputTransactionForTests ( this . docShell ( ) . DOMWindow ) ;
607
616
return this . _textInputProcessor ;
608
617
}
609
618
@@ -616,15 +625,15 @@ class Frame {
616
625
}
617
626
618
627
docShell ( ) {
619
- return this . _docShell ;
628
+ return this . _browsingContext . docShell ;
620
629
}
621
630
622
631
domWindow ( ) {
623
- return this . _docShell . domWindow ;
632
+ return this . docShell ( ) ? .domWindow ;
624
633
}
625
634
626
635
name ( ) {
627
- const frameElement = this . _docShell . domWindow . frameElement ;
636
+ const frameElement = this . domWindow ( ) ? .frameElement ;
628
637
let name = '' ;
629
638
if ( frameElement )
630
639
name = frameElement . getAttribute ( 'name' ) || frameElement . getAttribute ( 'id' ) || '' ;
0 commit comments