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
--- 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);