@@ -24,6 +24,8 @@ let globalTabAndWindowActivationChain = Promise.resolve();
2424let didCreateFirstPage = false ;
2525let globalNewPageChain = Promise . resolve ( ) ;
2626
27+ let globalContextCloseCounter = 0 ;
28+
2729class DownloadInterceptor {
2830 constructor ( registry ) {
2931 this . _registry = registry
@@ -414,6 +416,8 @@ export class PageTarget {
414416 this . _browserContext = browserContext ;
415417 this . _viewportSize = undefined ;
416418 this . _deviceScaleFactor = undefined ;
419+ this . _screenSize = undefined ;
420+ this . _isMobile = undefined ;
417421 this . _zoom = 1 ;
418422 this . _initialDPPX = this . _linkedBrowser . browsingContext . overrideDPPX ;
419423 this . _url = 'about:blank' ;
@@ -447,6 +451,7 @@ export class PageTarget {
447451 this . _registry . _browserToTarget . set ( this . _linkedBrowser , this ) ;
448452
449453 const browserId = this . _linkedBrowser . browsingContext . browserId ;
454+ this . _browserId = browserId ;
450455 this . _registry . _browserIdToTarget . set ( browserId , this ) ;
451456 const actor = this . _registry . _browserIdToActor . get ( browserId ) ;
452457 if ( actor )
@@ -456,7 +461,7 @@ export class PageTarget {
456461 }
457462
458463 async activateAndRun ( callback = ( ) => { } , { muteNotificationsPopup = false } = { } ) {
459- const ownerWindow = this . _tab . linkedBrowser . ownerGlobal ;
464+ const ownerWindow = this . _tab . linkedBrowser . documentGlobal ;
460465 const tabBrowser = ownerWindow . gBrowser ;
461466 // Serialize all tab-switching commands per tabbed browser
462467 // to disallow concurrent tab switching.
@@ -528,6 +533,7 @@ export class PageTarget {
528533 this . updateLanguageOverride ( browsingContext ) ;
529534 this . updatePlatform ( browsingContext ) ;
530535 this . updateDPPXOverride ( browsingContext ) ;
536+ this . updateScreenEmulation ( browsingContext ) ;
531537 this . updateZoom ( browsingContext ) ;
532538 this . updateEmulatedMedia ( browsingContext ) ;
533539 this . updateColorSchemeOverride ( browsingContext ) ;
@@ -568,7 +574,8 @@ export class PageTarget {
568574 }
569575
570576 updateLanguageOverride ( browsingContext = undefined ) {
571- ( browsingContext || this . _linkedBrowser . browsingContext ) . languageOverride = this . _browserContext . languageOverride ;
577+ browsingContext ||= this . _linkedBrowser . browsingContext ;
578+ browsingContext . languageOverride = this . _browserContext . languageOverride || '' ;
572579 }
573580
574581 updatePlatform ( browsingContext = undefined ) {
@@ -582,6 +589,32 @@ export class PageTarget {
582589 browsingContext . overrideDPPX = dppx ;
583590 }
584591
592+ updateScreenEmulation ( browsingContext = undefined ) {
593+ browsingContext ||= this . _linkedBrowser . browsingContext ;
594+ const screenSize = this . _screenSize || this . _browserContext . screenSize ;
595+ const isMobile = this . _isMobile ?? this . _browserContext . isMobile ;
596+
597+ // `isRDMPane` is a "mobile mode": viewport media queries, touch/pointer
598+ // support, viewport media queries.
599+ browsingContext . inRDMPane = ! ! isMobile ;
600+
601+ // Set window.screen.width and window.screen.height
602+ if ( screenSize ) {
603+ browsingContext . setScreenAreaOverride ( screenSize . width , screenSize . height ) ;
604+ } else {
605+ browsingContext . resetScreenAreaOverride ( ) ;
606+ }
607+
608+ // Derive the orientation from the emulated screen size and keep it in sync
609+ // with the screen area override.
610+ if ( screenSize && isMobile ) {
611+ const isPortrait = screenSize . height >= screenSize . width ;
612+ browsingContext . setOrientationOverride ( isPortrait ? 'portrait-primary' : 'landscape-primary' , isPortrait ? 0 : 90 ) ;
613+ } else {
614+ browsingContext . resetOrientationOverride ( ) ;
615+ }
616+ }
617+
585618 async updateZoom ( browsingContext = undefined ) {
586619 browsingContext ||= this . _linkedBrowser . browsingContext ;
587620 // Update dpr first, and then UI zoom.
@@ -611,6 +644,7 @@ export class PageTarget {
611644 async updateViewportSize ( ) {
612645 await waitForWindowReady ( this . _window ) ;
613646 this . updateDPPXOverride ( ) ;
647+ this . updateScreenEmulation ( ) ;
614648
615649 // Viewport size is defined by three arguments:
616650 // 1. default size. Could be explicit if set as part of `window.open` call, e.g.
@@ -630,7 +664,6 @@ export class PageTarget {
630664 this . _linkedBrowser . closest ( '.browserStack' ) . style . setProperty ( 'overflow' , 'auto' ) ;
631665 this . _linkedBrowser . closest ( '.browserStack' ) . style . setProperty ( 'contain' , 'size' ) ;
632666 this . _linkedBrowser . closest ( '.browserStack' ) . style . setProperty ( 'scrollbar-width' , 'none' ) ;
633- this . _linkedBrowser . browsingContext . inRDMPane = true ;
634667
635668 const stackRect = this . _linkedBrowser . closest ( '.browserStack' ) . getBoundingClientRect ( ) ;
636669 const toolbarTop = stackRect . y ;
@@ -644,7 +677,6 @@ export class PageTarget {
644677 this . _linkedBrowser . closest ( '.browserStack' ) . style . removeProperty ( 'overflow' ) ;
645678 this . _linkedBrowser . closest ( '.browserStack' ) . style . removeProperty ( 'contain' ) ;
646679 this . _linkedBrowser . closest ( '.browserStack' ) . style . removeProperty ( 'scrollbar-width' ) ;
647- this . _linkedBrowser . browsingContext . inRDMPane = false ;
648680
649681 const actualSize = this . _linkedBrowser . getBoundingClientRect ( ) ;
650682 await this . _channel . connect ( '' ) . send ( 'awaitViewportDimensions' , {
@@ -706,9 +738,11 @@ export class PageTarget {
706738 await this . _channel . connect ( '' ) . send ( 'setInterceptFileChooserDialog' , enabled ) . catch ( e => { } ) ;
707739 }
708740
709- async setViewportSize ( viewportSize , deviceScaleFactor ) {
741+ async setViewportSize ( viewportSize , deviceScaleFactor , screenSize , isMobile ) {
710742 this . _viewportSize = viewportSize ;
711743 this . _deviceScaleFactor = deviceScaleFactor ;
744+ this . _screenSize = screenSize ;
745+ this . _isMobile = isMobile ;
712746 await this . updateViewportSize ( ) ;
713747 }
714748
@@ -749,7 +783,7 @@ export class PageTarget {
749783 }
750784
751785 _updateCrossProcessCookie ( ) {
752- Services . ppmm . sharedData . set ( 'juggler:page-cookie-' + this . _linkedBrowser . browsingContext . browserId , this . crossProcessCookie ) ;
786+ Services . ppmm . sharedData . set ( 'juggler:page-cookie-' + this . _browserId , this . crossProcessCookie ) ;
753787 Services . ppmm . sharedData . flush ( ) ;
754788 }
755789
@@ -787,7 +821,7 @@ export class PageTarget {
787821 if ( width < 10 || width > 10000 || height < 10 || height > 10000 )
788822 throw new Error ( "Invalid size" ) ;
789823
790- const docShell = this . _gBrowser . ownerGlobal . docShell ;
824+ const docShell = this . _gBrowser . documentGlobal . docShell ;
791825 // Exclude address bar and navigation control from the video.
792826 const rect = this . linkedBrowser ( ) . getBoundingClientRect ( ) ;
793827 const devicePixelRatio = this . _window . devicePixelRatio ;
@@ -841,7 +875,9 @@ export class PageTarget {
841875 this . stopScreencast ( ) ;
842876 this . _browserContext . pages . delete ( this ) ;
843877 this . _registry . _browserToTarget . delete ( this . _linkedBrowser ) ;
844- this . _registry . _browserIdToTarget . delete ( this . _linkedBrowser . browsingContext . browserId ) ;
878+ this . _registry . _browserIdToTarget . delete ( this . _browserId ) ;
879+ Services . ppmm . sharedData . delete ( 'juggler:page-cookie-' + this . _browserId ) ;
880+ Services . ppmm . sharedData . flush ( ) ;
845881 try {
846882 helper . removeListeners ( this . _eventListeners ) ;
847883 } catch ( e ) {
@@ -917,6 +953,8 @@ class BrowserContext {
917953 this . downloadOptions = undefined ;
918954 this . defaultViewportSize = undefined ;
919955 this . deviceScaleFactor = undefined ;
956+ this . screenSize = undefined ;
957+ this . isMobile = undefined ;
920958 this . defaultUserAgent = null ;
921959 this . timezoneOverride = undefined ;
922960 this . languageOverride = undefined ;
@@ -983,7 +1021,18 @@ class BrowserContext {
9831021 }
9841022 this . _registry . _browserContextIdToBrowserContext . delete ( this . browserContextId ) ;
9851023 this . _registry . _userContextIdToBrowserContext . delete ( this . userContextId ) ;
1024+ Services . ppmm . sharedData . delete ( 'juggler:context-cookie-' + this . userContextId ) ;
1025+ Services . ppmm . sharedData . flush ( ) ;
9861026 this . _registry . _updateProxiesWithSameAuthCacheAndDifferentCredentials ( ) ;
1027+ // Clean the memory. on every 10'th context closure. On M1 Max, this method
1028+ // takes ~150ms, so we spread them out.
1029+ if ( ++ globalContextCloseCounter % 10 === 0 ) {
1030+ await new Promise ( x => {
1031+ Cc [ "@mozilla.org/memory-reporter-manager;1" ]
1032+ . getService ( Ci . nsIMemoryReporterManager )
1033+ . minimizeMemoryUsage ( x ) ;
1034+ } ) ;
1035+ }
9871036 }
9881037
9891038 setProxy ( proxy ) {
@@ -1056,6 +1105,8 @@ class BrowserContext {
10561105 async setDefaultViewport ( viewport ) {
10571106 this . defaultViewportSize = viewport ? viewport . viewportSize : undefined ;
10581107 this . deviceScaleFactor = viewport ? viewport . deviceScaleFactor : undefined ;
1108+ this . screenSize = viewport ? viewport . screenSize : undefined ;
1109+ this . isMobile = viewport ? viewport . isMobile : undefined ;
10591110 await Promise . all ( Array . from ( this . pages ) . map ( page => page . updateViewportSize ( ) ) ) ;
10601111 }
10611112
0 commit comments