Bug 1587362 - Make sure PiP toggle mouse button listeners are attached to the right WindowRoot after tab tear out / in. r=jaws
☠☠ backed out by 1c6ab26ee4cf ☠ ☠
authorMike Conley <mconley@mozilla.com>
Fri, 11 Oct 2019 21:00:15 +0000
changeset 497312 c71f9a59bdfeebc71144091b4ebd3c2e1c2bc74b
parent 497311 04747f7ea76f015cb303527cafd79f2815cf7b9b
child 497313 d3142d807c7f5a409a4fff4b94acf129f346786c
push id36682
push userncsoregi@mozilla.com
push dateSat, 12 Oct 2019 09:52:03 +0000
treeherdermozilla-central@06ea2371f897 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjaws
bugs1587362
milestone71.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1587362 - Make sure PiP toggle mouse button listeners are attached to the right WindowRoot after tab tear out / in. r=jaws Differential Revision: https://phabricator.services.mozilla.com/D48885
toolkit/actors/PictureInPictureChild.jsm
--- a/toolkit/actors/PictureInPictureChild.jsm
+++ b/toolkit/actors/PictureInPictureChild.jsm
@@ -109,16 +109,20 @@ class PictureInPictureToggleChild extend
         // Set to the original target element on pointerdown if the user is clicking
         // the toggle - this way, we can determine if a "click" event will need to be
         // suppressed ("click" events don't fire if a "mouseup" occurs on a different
         // element from the "pointerdown" / "mousedown" event).
         clickedElement: null,
         // This is a DeferredTask to hide the toggle after a period of mouse
         // inactivity.
         hideToggleDeferredTask: null,
+        // If we reach a point where we're tracking videos for mouse movements,
+        // then this will be true. If there are no videos worth tracking, then
+        // this is false.
+        isTrackingVideos: false,
       };
       this.weakDocStates.set(this.content.document, state);
     }
 
     return state;
   }
 
   handleEvent(event) {
@@ -159,16 +163,24 @@ class PictureInPictureToggleChild extend
       case "pointerdown": {
         this.onPointerDown(event);
         break;
       }
       case "mousemove": {
         this.onMouseMove(event);
         break;
       }
+      case "pageshow": {
+        this.onPageShow(event);
+        break;
+      }
+      case "pagehide": {
+        this.onPageHide(event);
+        break;
+      }
     }
   }
 
   /**
    * Adds a <video> to the IntersectionObserver so that we know when it becomes
    * visible.
    *
    * @param {Element} video The <video> element to register.
@@ -325,36 +337,82 @@ class PictureInPictureToggleChild extend
       state.mousemoveDeferredTask = new DeferredTask(() => {
         this.checkLastMouseMove();
       }, MOUSEMOVE_PROCESSING_DELAY_MS);
     }
     this.content.document.addEventListener("mousemove", this, {
       mozSystemGroup: true,
       capture: true,
     });
+    this.content.addEventListener("pageshow", this, {
+      mozSystemGroup: true,
+    });
+    this.content.addEventListener("pagehide", this, {
+      mozSystemGroup: true,
+    });
     this.addMouseButtonListeners();
+    state.isTrackingVideos = true;
   }
 
   /**
    * If we no longer have any interesting videos in the viewport, we deregister
    * the mousemove and click listeners, and also remove any toggles that might
    * be on the page still.
    */
   stopTrackingMouseOverVideos() {
     let state = this.docState;
     state.mousemoveDeferredTask.disarm();
     this.content.document.removeEventListener("mousemove", this, {
       mozSystemGroup: true,
       capture: true,
     });
+    this.content.removeEventListener("pageshow", this, {
+      mozSystemGroup: true,
+    });
+    this.content.removeEventListener("pagehide", this, {
+      mozSystemGroup: true,
+    });
     this.removeMouseButtonListeners();
     let oldOverVideo = state.weakOverVideo && state.weakOverVideo.get();
     if (oldOverVideo) {
       this.onMouseLeaveVideo(oldOverVideo);
     }
+    state.isTrackingVideos = false;
+  }
+
+  /**
+   * This pageshow event handler will get called if and when we complete a tab
+   * tear out or in. If we happened to be tracking videos before the tear
+   * occurred, we re-add the mouse event listeners so that they're attached to
+   * the right WindowRoot.
+   *
+   * @param {Event} event The pageshow event fired when completing a tab tear
+   * out or in.
+   */
+  onPageShow(event) {
+    let state = this.docState;
+    if (state.isTrackingVideos) {
+      this.addMouseButtonListeners();
+    }
+  }
+
+  /**
+   * This pagehide event handler will get called if and when we start a tab
+   * tear out or in. If we happened to be tracking videos before the tear
+   * occurred, we remove the mouse event listeners. We'll re-add them when the
+   * pageshow event fires.
+   *
+   * @param {Event} event The pagehide event fired when starting a tab tear
+   * out or in.
+   */
+  onPageHide(event) {
+    let state = this.docState;
+    if (state.isTrackingVideos) {
+      this.removeMouseButtonListeners();
+    }
   }
 
   /**
    * If we're tracking <video> elements, this pointerdown event handler is run anytime
    * a pointerdown occurs on the document. This function is responsible for checking
    * if the user clicked on the Picture-in-Picture toggle. It does this by first
    * checking if the video is visible beneath the point that was clicked. Then
    * it tests whether or not the pointerdown occurred within the rectangle of the