Bug 1327097 - Part II, Trap mouse/touch/pointer events in audio/video element, r=smaug draft
authorTimothy Guan-tin Chien <timdream@gmail.com>
Mon, 13 Mar 2017 16:19:37 +0800
changeset 498047 603c08eee763ef25856786569440985f32949670
parent 497379 c498aea8d5a0886c3174fe2e08e4c42bc8e0726a
child 498995 05470b84aab326cc86ce6e2f55772a4db253b8a2
push id49093
push userbmo:timdream@gmail.com
push dateTue, 14 Mar 2017 06:56:10 +0000
reviewerssmaug
bugs1327097
milestone55.0a1
Bug 1327097 - Part II, Trap mouse/touch/pointer events in audio/video element, r=smaug This patch implements HTMLMediaElement::GetEventTargetParent and set aVisitor.mCanHandle to false to mouse/touch/pointer events, when the media control is present. This tells the event dispatcher that these events are supposed to be handled exclusively by the videocontrol binding within the media element, and should not dispatch nor consumed by the content. MozReview-Commit-ID: BXWZX9SYsuC
dom/html/HTMLMediaElement.cpp
dom/html/HTMLMediaElement.h
toolkit/content/tests/widgets/test_videocontrols.html
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -9,16 +9,17 @@
 #include "mozilla/dom/HTMLSourceElement.h"
 #include "mozilla/dom/ElementInlines.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/AsyncEventDispatcher.h"
 #include "mozilla/dom/MediaEncryptedEvent.h"
 #include "mozilla/EMEUtils.h"
+#include "mozilla/EventDispatcher.h"
 
 #include "base/basictypes.h"
 #include "nsIDOMHTMLMediaElement.h"
 #include "nsIDOMHTMLSourceElement.h"
 #include "TimeRanges.h"
 #include "nsGenericHTMLElement.h"
 #include "nsAttrValueInlines.h"
 #include "nsPresContext.h"
@@ -4066,16 +4067,45 @@ HTMLMediaElement::OutputMediaStream::Out
 
 HTMLMediaElement::OutputMediaStream::~OutputMediaStream()
 {
   for (auto pair : mTrackPorts) {
     pair.second()->Destroy();
   }
 }
 
+nsresult
+HTMLMediaElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
+{
+  if (!this->Controls() || !aVisitor.mEvent->mFlags.mIsTrusted) {
+    return nsGenericHTMLElement::GetEventTargetParent(aVisitor);
+  }
+
+  // We will need to trap pointer, touch, and mouse events within the media
+  // element, allowing media control exclusive consumption on these events,
+  // and preventing the content from handling them.
+  switch (aVisitor.mEvent->mMessage) {
+    case ePointerDown:
+    case ePointerMove:
+    case ePointerUp:
+    case eTouchEnd:
+    case eTouchMove:
+    case eTouchStart:
+    case eMouseClick:
+    case eMouseDoubleClick:
+    case eMouseDown:
+    case eMouseMove:
+    case eMouseUp:
+      aVisitor.mCanHandle = false;
+      return NS_OK;
+    default:
+      return nsGenericHTMLElement::GetEventTargetParent(aVisitor);
+  }
+}
+
 bool HTMLMediaElement::ParseAttribute(int32_t aNamespaceID,
                                       nsIAtom* aAttribute,
                                       const nsAString& aValue,
                                       nsAttrValue& aResult)
 {
   // Mappings from 'preload' attribute strings to an enumeration.
   static const nsAttrValue::EnumTable kPreloadTable[] = {
     { "",         HTMLMediaElement::PRELOAD_ATTR_EMPTY },
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -115,16 +115,20 @@ public:
   // nsIDOMHTMLMediaElement
   NS_DECL_NSIDOMHTMLMEDIAELEMENT
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLMediaElement,
                                            nsGenericHTMLElement)
 
+  // nsIDOMEventTarget
+  virtual nsresult
+  GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
+
   virtual bool ParseAttribute(int32_t aNamespaceID,
                               nsIAtom* aAttribute,
                               const nsAString& aValue,
                               nsAttrValue& aResult) override;
   // SetAttr override.  C++ is stupid, so have to override both
   // overloaded methods.
   nsresult SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
                    const nsAString& aValue, bool aNotify)
--- a/toolkit/content/tests/widgets/test_videocontrols.html
+++ b/toolkit/content/tests/widgets/test_videocontrols.html
@@ -408,16 +408,25 @@ function canplaythroughevent(event) {
   video.removeEventListener("canplaythrough", canplaythroughevent);
   // Other events expected by the test.
   video.addEventListener("play", runTest);
   video.addEventListener("pause", runTest);
   video.addEventListener("volumechange", runTest);
   video.addEventListener("seeking", runTest);
   video.addEventListener("seeked", runTest);
   document.addEventListener("mozfullscreenchange", runTest);
+
+  ["mousedown", "mousemove", "mouseup", "dblclick", "click"]
+    .forEach((eventType) => {
+      document.body.addEventListener(eventType, (evt) => {
+        evt.preventDefault();
+        is(false, "Event " + eventType + " should not reach document.");
+      });
+    });
+
   // Begin the test.
   runTest(event);
 }
 
 function startMediaLoad() {
   // Kick off test once video has loaded, in its canplaythrough event handler.
   video.src = "seek_with_sound.ogg";
   video.addEventListener("canplaythrough", canplaythroughevent);