Bug 1292063 - Part 1: Add Event.composed. r=smaug
authorStone Shih <sshih@mozilla.com>
Wed, 31 Aug 2016 11:16:11 +0800
changeset 359190 22cf15bb84d4425107834b15b993f8414807ab50
parent 359189 64c6e5121479fd7d68ca7c757b44abf8e3182087
child 359191 79c5fa0ce1c61f250c7c5e05266ae61a1f1129e8
push id6795
push userjlund@mozilla.com
push dateMon, 23 Jan 2017 14:19:46 +0000
treeherdermozilla-beta@76101b503191 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1292063
milestone52.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 1292063 - Part 1: Add Event.composed. r=smaug
dom/base/FragmentOrElement.cpp
dom/bindings/Codegen.py
dom/bluetooth/common/webapi/BluetoothLeDeviceEvent.cpp
dom/events/AnimationEvent.cpp
dom/events/ClipboardEvent.cpp
dom/events/CustomEvent.cpp
dom/events/DeviceMotionEvent.cpp
dom/events/DragEvent.cpp
dom/events/Event.cpp
dom/events/Event.h
dom/events/FocusEvent.cpp
dom/events/InputEvent.cpp
dom/events/MouseEvent.cpp
dom/events/PointerEvent.cpp
dom/events/SpeechRecognitionError.cpp
dom/events/StorageEvent.cpp
dom/events/TouchEvent.cpp
dom/events/TransitionEvent.cpp
dom/events/UIEvent.cpp
dom/events/WheelEvent.cpp
dom/media/eme/MediaKeyMessageEvent.cpp
dom/notification/NotificationEvent.h
dom/webidl/Event.webidl
dom/workers/ServiceWorkerEvents.cpp
dom/workers/ServiceWorkerEvents.h
widget/BasicEvents.h
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -801,60 +801,17 @@ nsIContent::PreHandleEvent(EventChainPre
       parent = aVisitor.mDestInsertionPoints.LastElement();
       aVisitor.mDestInsertionPoints.SetLength(
         aVisitor.mDestInsertionPoints.Length() - 1);
     }
   }
 
   ShadowRoot* thisShadowRoot = ShadowRoot::FromNode(this);
   if (thisShadowRoot) {
-    // The following events must always be stopped at the root node of the node tree:
-    //   abort
-    //   error
-    //   select
-    //   change
-    //   load
-    //   reset
-    //   resize
-    //   scroll
-    //   selectstart
-    bool stopEvent = false;
-    switch (aVisitor.mEvent->mMessage) {
-      case eImageAbort:
-      case eLoadError:
-      case eFormSelect:
-      case eFormChange:
-      case eLoad:
-      case eFormReset:
-      case eResize:
-      case eScroll:
-      case eSelectStart:
-        stopEvent = true;
-        break;
-      case eUnidentifiedEvent:
-        if (aVisitor.mDOMEvent) {
-          nsAutoString eventType;
-          aVisitor.mDOMEvent->GetType(eventType);
-          if (eventType.EqualsLiteral("abort") ||
-              eventType.EqualsLiteral("error") ||
-              eventType.EqualsLiteral("select") ||
-              eventType.EqualsLiteral("change") ||
-              eventType.EqualsLiteral("load") ||
-              eventType.EqualsLiteral("reset") ||
-              eventType.EqualsLiteral("resize") ||
-              eventType.EqualsLiteral("scroll")) {
-            stopEvent = true;
-          }
-        }
-        break;
-      default:
-        break;
-    }
-
-    if (stopEvent) {
+    if (!aVisitor.mEvent->mFlags.mComposed) {
       // If we do stop propagation, we still want to propagate
       // the event to chrome (nsPIDOMWindow::GetParentTarget()).
       // The load event is special in that we don't ever propagate it
       // to chrome.
       nsCOMPtr<nsPIDOMWindowOuter> win = OwnerDoc()->GetWindow();
       EventTarget* parentTarget = win && aVisitor.mEvent->mMessage != eLoad
         ? win->GetParentTarget() : nullptr;
 
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -16702,16 +16702,17 @@ class CGEventMethod(CGNativeMember):
 
         self.body = fill(
             """
             RefPtr<${nativeType}> e = new ${nativeType}(aOwner);
             bool trusted = e->Init(aOwner);
             e->InitEvent(${eventType}, ${eventInit}.mBubbles, ${eventInit}.mCancelable);
             $*{members}
             e->SetTrusted(trusted);
+            e->SetComposed(${eventInit}.mComposed);
             $*{holdJS}
             return e.forget();
             """,
             nativeType=self.descriptorProvider.nativeType.split('::')[-1],
             eventType=self.args[0].name,
             eventInit=self.args[1].name,
             members=members,
             holdJS=holdJS)
--- a/dom/bluetooth/common/webapi/BluetoothLeDeviceEvent.cpp
+++ b/dom/bluetooth/common/webapi/BluetoothLeDeviceEvent.cpp
@@ -102,16 +102,17 @@ BluetoothLeDeviceEvent::Constructor(
                                          scanRecord.Data());
     if (!e->mScanRecord) {
       aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
       return nullptr;
     }
   }
 
   e->SetTrusted(trusted);
+  e->SetComposed(aEventInitDict.mComposed);
   return e.forget();
 }
 
 BluetoothDevice*
 BluetoothLeDeviceEvent::GetDevice() const
 {
   return mDevice;
 }
--- a/dom/events/AnimationEvent.cpp
+++ b/dom/events/AnimationEvent.cpp
@@ -47,16 +47,17 @@ AnimationEvent::Constructor(const Global
   e->InitEvent(aType, aParam.mBubbles, aParam.mCancelable);
 
   InternalAnimationEvent* internalEvent = e->mEvent->AsAnimationEvent();
   internalEvent->mAnimationName = aParam.mAnimationName;
   internalEvent->mElapsedTime = aParam.mElapsedTime;
   internalEvent->mPseudoElement = aParam.mPseudoElement;
 
   e->SetTrusted(trusted);
+  e->SetComposed(aParam.mComposed);
   return e.forget();
 }
 
 NS_IMETHODIMP
 AnimationEvent::GetAnimationName(nsAString& aAnimationName)
 {
   aAnimationName = mEvent->AsAnimationEvent()->mAnimationName;
   return NS_OK;
--- a/dom/events/ClipboardEvent.cpp
+++ b/dom/events/ClipboardEvent.cpp
@@ -79,16 +79,17 @@ ClipboardEvent::Constructor(const Global
                              Some(aGlobal.GetSubjectPrincipal()), aRv);
       NS_ENSURE_TRUE(!aRv.Failed(), nullptr);
     }
   }
 
   e->InitClipboardEvent(aType, aParam.mBubbles, aParam.mCancelable,
                         clipboardData);
   e->SetTrusted(trusted);
+  e->SetComposed(aParam.mComposed);
   return e.forget();
 }
 
 NS_IMETHODIMP
 ClipboardEvent::GetClipboardData(nsIDOMDataTransfer** aClipboardData)
 {
   NS_IF_ADDREF(*aClipboardData = GetClipboardData());
   return NS_OK;
--- a/dom/events/CustomEvent.cpp
+++ b/dom/events/CustomEvent.cpp
@@ -55,16 +55,17 @@ CustomEvent::Constructor(const GlobalObj
                          ErrorResult& aRv)
 {
   nsCOMPtr<mozilla::dom::EventTarget> t = do_QueryInterface(aGlobal.GetAsSupports());
   RefPtr<CustomEvent> e = new CustomEvent(t, nullptr, nullptr);
   bool trusted = e->Init(t);
   JS::Rooted<JS::Value> detail(aGlobal.Context(), aParam.mDetail);
   e->InitCustomEvent(aGlobal.Context(), aType, aParam.mBubbles, aParam.mCancelable, detail, aRv);
   e->SetTrusted(trusted);
+  e->SetComposed(aParam.mComposed);
   return e.forget();
 }
 
 JSObject*
 CustomEvent::WrapObjectInternal(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return mozilla::dom::CustomEventBinding::Wrap(aCx, this, aGivenProto);
 }
--- a/dom/events/DeviceMotionEvent.cpp
+++ b/dom/events/DeviceMotionEvent.cpp
@@ -94,17 +94,17 @@ DeviceMotionEvent::Constructor(const Glo
 
   e->mRotationRate = new DeviceRotationRate(e,
     aEventInitDict.mRotationRate.mAlpha,
     aEventInitDict.mRotationRate.mBeta,
     aEventInitDict.mRotationRate.mGamma);
 
   e->mInterval = aEventInitDict.mInterval;
   e->SetTrusted(trusted);
-
+  e->SetComposed(aEventInitDict.mComposed);
   return e.forget();
 }
 
 /******************************************************************************
  * DeviceAcceleration
  *****************************************************************************/
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DeviceAcceleration, mOwner)
--- a/dom/events/DragEvent.cpp
+++ b/dom/events/DragEvent.cpp
@@ -106,16 +106,17 @@ DragEvent::Constructor(const GlobalObjec
   e->InitDragEvent(aType, aParam.mBubbles, aParam.mCancelable,
                    aParam.mView, aParam.mDetail, aParam.mScreenX,
                    aParam.mScreenY, aParam.mClientX, aParam.mClientY,
                    aParam.mCtrlKey, aParam.mAltKey, aParam.mShiftKey,
                    aParam.mMetaKey, aParam.mButton, aParam.mRelatedTarget,
                    aParam.mDataTransfer);
   e->InitializeExtraMouseEventDictionaryMembers(aParam);
   e->SetTrusted(trusted);
+  e->SetComposed(aParam.mComposed);
   return e.forget();
 }
 
 } // namespace dom
 } // namespace mozilla
 
 using namespace mozilla;
 using namespace mozilla::dom;
--- a/dom/events/Event.cpp
+++ b/dom/events/Event.cpp
@@ -410,16 +410,17 @@ Event::Constructor(const GlobalObject& a
                    const EventInit& aParam,
                    ErrorResult& aRv)
 {
   nsCOMPtr<mozilla::dom::EventTarget> t = do_QueryInterface(aGlobal.GetAsSupports());
   RefPtr<Event> e = new Event(t, nullptr, nullptr);
   bool trusted = e->Init(t);
   e->InitEvent(aType, aParam.mBubbles, aParam.mCancelable);
   e->SetTrusted(trusted);
+  e->SetComposed(aParam.mComposed);
   return e.forget();
 }
 
 uint16_t
 Event::EventPhase() const
 {
   // Note, remember to check that this works also
   // if or when Bug 235441 is fixed.
@@ -562,20 +563,22 @@ Event::PreventDefaultInternal(bool aCall
 void
 Event::SetEventType(const nsAString& aEventTypeArg)
 {
   if (mIsMainThreadEvent) {
     mEvent->mSpecifiedEventTypeString.Truncate();
     mEvent->mSpecifiedEventType =
       nsContentUtils::GetEventMessageAndAtom(aEventTypeArg, mEvent->mClass,
                                              &(mEvent->mMessage));
+    mEvent->SetDefaultComposed();
   } else {
     mEvent->mSpecifiedEventType = nullptr;
     mEvent->mMessage = eUnidentifiedEvent;
     mEvent->mSpecifiedEventTypeString = aEventTypeArg;
+    mEvent->SetComposed(aEventTypeArg);
   }
 }
 
 void
 Event::InitEvent(const nsAString& aEventTypeArg,
                  bool aCanBubbleArg,
                  bool aCancelableArg)
 {
@@ -1162,16 +1165,17 @@ Event::Serialize(IPC::Message* aMsg, boo
 
   nsString type;
   GetType(type);
   IPC::WriteParam(aMsg, type);
 
   IPC::WriteParam(aMsg, Bubbles());
   IPC::WriteParam(aMsg, Cancelable());
   IPC::WriteParam(aMsg, IsTrusted());
+  IPC::WriteParam(aMsg, Composed());
 
   // No timestamp serialization for now!
 }
 
 NS_IMETHODIMP_(bool)
 Event::Deserialize(const IPC::Message* aMsg, PickleIterator* aIter)
 {
   nsString type;
@@ -1181,18 +1185,22 @@ Event::Deserialize(const IPC::Message* a
   NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &bubbles), false);
 
   bool cancelable = false;
   NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &cancelable), false);
 
   bool trusted = false;
   NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &trusted), false);
 
+  bool composed = false;
+  NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &composed), false);
+
   InitEvent(type, bubbles, cancelable);
   SetTrusted(trusted);
+  SetComposed(composed);
 
   return true;
 }
 
 NS_IMETHODIMP_(void)
 Event::SetOwner(mozilla::dom::EventTarget* aOwner)
 {
   mOwner = nullptr;
--- a/dom/events/Event.h
+++ b/dom/events/Event.h
@@ -165,16 +165,21 @@ public:
     return mEvent->mFlags.mBubbles;
   }
 
   bool Cancelable() const
   {
     return mEvent->mFlags.mCancelable;
   }
 
+  bool Composed() const
+  {
+    return mEvent->mFlags.mComposed;
+  }
+
   // xpidl implementation
   // void PreventDefault();
 
   // You MUST NOT call PreventDefaultJ(JSContext*) from C++ code.  A call of
   // this method always sets Event.defaultPrevented true for web contents.
   // If default action handler calls this, web applications meet wrong
   // defaultPrevented value.
   virtual void PreventDefault(JSContext* aCx);
@@ -269,16 +274,21 @@ protected:
   }
 
   /**
    * IsChrome() returns true if aCx is chrome context or the event is created
    * in chrome's thread.  Otherwise, false.
    */
   bool IsChrome(JSContext* aCx) const;
 
+  void SetComposed(bool aComposed)
+  {
+    mEvent->SetComposed(aComposed);
+  }
+
   mozilla::WidgetEvent*       mEvent;
   RefPtr<nsPresContext>     mPresContext;
   nsCOMPtr<EventTarget>       mExplicitOriginalTarget;
   nsCOMPtr<nsIGlobalObject>   mOwner;
   bool                        mEventIsInternal;
   bool                        mPrivateDataDuplicated;
   bool                        mIsMainThreadEvent;
   // True when popup control check should rely on event.type, not
--- a/dom/events/FocusEvent.cpp
+++ b/dom/events/FocusEvent.cpp
@@ -60,16 +60,17 @@ FocusEvent::Constructor(const GlobalObje
                         ErrorResult& aRv)
 {
   nsCOMPtr<EventTarget> t = do_QueryInterface(aGlobal.GetAsSupports());
   RefPtr<FocusEvent> e = new FocusEvent(t, nullptr, nullptr);
   bool trusted = e->Init(t);
   e->InitFocusEvent(aType, aParam.mBubbles, aParam.mCancelable, aParam.mView,
                     aParam.mDetail, aParam.mRelatedTarget);
   e->SetTrusted(trusted);
+  e->SetComposed(aParam.mComposed);
   return e.forget();
 }
 
 } // namespace dom
 } // namespace mozilla
 
 using namespace mozilla;
 using namespace mozilla::dom;
--- a/dom/events/InputEvent.cpp
+++ b/dom/events/InputEvent.cpp
@@ -51,16 +51,17 @@ InputEvent::Constructor(const GlobalObje
   RefPtr<InputEvent> e = new InputEvent(t, nullptr, nullptr);
   bool trusted = e->Init(t);
   auto* view = aParam.mView ? aParam.mView->AsInner() : nullptr;
   e->InitUIEvent(aType, aParam.mBubbles, aParam.mCancelable, view,
                  aParam.mDetail);
   InternalEditorInputEvent* internalEvent = e->mEvent->AsEditorInputEvent();
   internalEvent->mIsComposing = aParam.mIsComposing;
   e->SetTrusted(trusted);
+  e->SetComposed(aParam.mComposed);
   return e.forget();
 }
 
 } // namespace dom
 } // namespace mozilla
 
 using namespace mozilla;
 using namespace mozilla::dom;
--- a/dom/events/MouseEvent.cpp
+++ b/dom/events/MouseEvent.cpp
@@ -182,17 +182,17 @@ MouseEvent::Constructor(const GlobalObje
   bool trusted = e->Init(t);
   e->InitMouseEvent(aType, aParam.mBubbles, aParam.mCancelable,
                     aParam.mView, aParam.mDetail, aParam.mScreenX,
                     aParam.mScreenY, aParam.mClientX, aParam.mClientY,
                     aParam.mCtrlKey, aParam.mAltKey, aParam.mShiftKey,
                     aParam.mMetaKey, aParam.mButton, aParam.mRelatedTarget);
   e->InitializeExtraMouseEventDictionaryMembers(aParam);
   e->SetTrusted(trusted);
-
+  e->SetComposed(aParam.mComposed);
   return e.forget();
 }
 
 void
 MouseEvent::InitNSMouseEvent(const nsAString& aType,
                              bool aCanBubble,
                              bool aCancelable,
                              nsGlobalWindow* aView,
--- a/dom/events/PointerEvent.cpp
+++ b/dom/events/PointerEvent.cpp
@@ -95,16 +95,17 @@ PointerEvent::Constructor(EventTarget* a
   widgetEvent->pressure = aParam.mPressure;
   widgetEvent->tiltX = aParam.mTiltX;
   widgetEvent->tiltY = aParam.mTiltY;
   widgetEvent->inputSource = ConvertStringToPointerType(aParam.mPointerType);
   widgetEvent->mIsPrimary = aParam.mIsPrimary;
   widgetEvent->buttons = aParam.mButtons;
 
   e->SetTrusted(trusted);
+  e->SetComposed(aParam.mComposed);
   return e.forget();
 }
 
 // static
 already_AddRefed<PointerEvent>
 PointerEvent::Constructor(const GlobalObject& aGlobal,
                           const nsAString& aType,
                           const PointerEventInit& aParam,
--- a/dom/events/SpeechRecognitionError.cpp
+++ b/dom/events/SpeechRecognitionError.cpp
@@ -26,16 +26,17 @@ SpeechRecognitionError::Constructor(cons
                                     const SpeechRecognitionErrorInit& aParam,
                                     ErrorResult& aRv)
 {
   nsCOMPtr<mozilla::dom::EventTarget> t = do_QueryInterface(aGlobal.GetAsSupports());
   RefPtr<SpeechRecognitionError> e = new SpeechRecognitionError(t, nullptr, nullptr);
   bool trusted = e->Init(t);
   e->InitSpeechRecognitionError(aType, aParam.mBubbles, aParam.mCancelable, aParam.mError, aParam.mMessage);
   e->SetTrusted(trusted);
+  e->SetComposed(aParam.mComposed);
   return e.forget();
 }
 
 void
 SpeechRecognitionError::InitSpeechRecognitionError(const nsAString& aType,
                                                    bool aCanBubble,
                                                    bool aCancelable,
                                                    SpeechRecognitionErrorCode aError,
--- a/dom/events/StorageEvent.cpp
+++ b/dom/events/StorageEvent.cpp
@@ -60,17 +60,17 @@ StorageEvent::Constructor(EventTarget* a
   bool trusted = e->Init(aOwner);
   e->InitEvent(aType, aEventInitDict.mBubbles, aEventInitDict.mCancelable);
   e->mKey = aEventInitDict.mKey;
   e->mOldValue = aEventInitDict.mOldValue;
   e->mNewValue = aEventInitDict.mNewValue;
   e->mUrl = aEventInitDict.mUrl;
   e->mStorageArea = aEventInitDict.mStorageArea;
   e->SetTrusted(trusted);
-
+  e->SetComposed(aEventInitDict.mComposed);
   return e.forget();
 }
 
 already_AddRefed<StorageEvent>
 StorageEvent::Constructor(const GlobalObject& aGlobal,
                           const nsAString& aType,
                           const StorageEventInit& aEventInitDict,
                           ErrorResult& aRv)
--- a/dom/events/TouchEvent.cpp
+++ b/dom/events/TouchEvent.cpp
@@ -240,16 +240,17 @@ TouchEvent::Constructor(const GlobalObje
   RefPtr<TouchList> touches = e->CopyTouches(aParam.mTouches);
   RefPtr<TouchList> targetTouches = e->CopyTouches(aParam.mTargetTouches);
   RefPtr<TouchList> changedTouches = e->CopyTouches(aParam.mChangedTouches);
   e->InitTouchEvent(aType, aParam.mBubbles, aParam.mCancelable, aParam.mView,
                     aParam.mDetail, aParam.mCtrlKey, aParam.mAltKey,
                     aParam.mShiftKey, aParam.mMetaKey, touches, targetTouches,
                     changedTouches);
   e->SetTrusted(trusted);
+  e->SetComposed(aParam.mComposed);
   return e.forget();
 }
 
 
 already_AddRefed<TouchList>
 TouchEvent::CopyTouches(const Sequence<OwningNonNull<Touch>>& aTouches)
 {
   RefPtr<TouchList> list = new TouchList(GetParentObject());
--- a/dom/events/TransitionEvent.cpp
+++ b/dom/events/TransitionEvent.cpp
@@ -47,16 +47,17 @@ TransitionEvent::Constructor(const Globa
   e->InitEvent(aType, aParam.mBubbles, aParam.mCancelable);
 
   InternalTransitionEvent* internalEvent = e->mEvent->AsTransitionEvent();
   internalEvent->mPropertyName = aParam.mPropertyName;
   internalEvent->mElapsedTime = aParam.mElapsedTime;
   internalEvent->mPseudoElement = aParam.mPseudoElement;
 
   e->SetTrusted(trusted);
+  e->SetComposed(aParam.mComposed);
   return e.forget();
 }
 
 NS_IMETHODIMP
 TransitionEvent::GetPropertyName(nsAString& aPropertyName)
 {
   aPropertyName = mEvent->AsTransitionEvent()->mPropertyName;
   return NS_OK;
--- a/dom/events/UIEvent.cpp
+++ b/dom/events/UIEvent.cpp
@@ -85,16 +85,17 @@ UIEvent::Constructor(const GlobalObject&
                      ErrorResult& aRv)
 {
   nsCOMPtr<EventTarget> t = do_QueryInterface(aGlobal.GetAsSupports());
   RefPtr<UIEvent> e = new UIEvent(t, nullptr, nullptr);
   bool trusted = e->Init(t);
   e->InitUIEvent(aType, aParam.mBubbles, aParam.mCancelable, aParam.mView,
                  aParam.mDetail);
   e->SetTrusted(trusted);
+  e->SetComposed(aParam.mComposed);
   return e.forget();
 }
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(UIEvent, Event,
                                    mView)
 
 NS_IMPL_ADDREF_INHERITED(UIEvent, Event)
 NS_IMPL_RELEASE_INHERITED(UIEvent, Event)
--- a/dom/events/WheelEvent.cpp
+++ b/dom/events/WheelEvent.cpp
@@ -120,16 +120,17 @@ WheelEvent::Constructor(const GlobalObje
                     aParam.mView, aParam.mDetail,
                     aParam.mScreenX, aParam.mScreenY,
                     aParam.mClientX, aParam.mClientY,
                     aParam.mButton, aParam.mRelatedTarget,
                     EmptyString(), aParam.mDeltaX,
                     aParam.mDeltaY, aParam.mDeltaZ, aParam.mDeltaMode);
   e->InitializeExtraMouseEventDictionaryMembers(aParam);
   e->SetTrusted(trusted);
+  e->SetComposed(aParam.mComposed);
   return e.forget();
 }
 
 } // namespace dom
 } // namespace mozilla
 
 using namespace mozilla;
 using namespace mozilla::dom;
--- a/dom/media/eme/MediaKeyMessageEvent.cpp
+++ b/dom/media/eme/MediaKeyMessageEvent.cpp
@@ -95,16 +95,17 @@ MediaKeyMessageEvent::Constructor(const 
   }
   e->mMessage = ArrayBuffer::Create(aGlobal.Context(), length, data);
   if (!e->mMessage) {
     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
     return nullptr;
   }
   e->mMessageType = aEventInitDict.mMessageType;
   e->SetTrusted(trusted);
+  e->SetComposed(aEventInitDict.mComposed);
   return e.forget();
 }
 
 void
 MediaKeyMessageEvent::GetMessage(JSContext* cx,
                                  JS::MutableHandle<JSObject*> aMessage,
                                  ErrorResult& aRv)
 {
--- a/dom/notification/NotificationEvent.h
+++ b/dom/notification/NotificationEvent.h
@@ -38,16 +38,17 @@ public:
               const nsAString& aType,
               const NotificationEventInit& aOptions,
               ErrorResult& aRv)
   {
     RefPtr<NotificationEvent> e = new NotificationEvent(aOwner);
     bool trusted = e->Init(aOwner);
     e->InitEvent(aType, aOptions.mBubbles, aOptions.mCancelable);
     e->SetTrusted(trusted);
+    e->SetComposed(aOptions.mComposed);
     e->mNotification = aOptions.mNotification;
     e->SetWantsPopupControlCheck(e->IsTrusted());
     return e.forget();
   }
 
   static already_AddRefed<NotificationEvent>
   Constructor(const GlobalObject& aGlobal,
               const nsAString& aType,
--- a/dom/webidl/Event.webidl
+++ b/dom/webidl/Event.webidl
@@ -36,16 +36,18 @@ interface Event {
   readonly attribute boolean cancelable;
   void preventDefault();
   [Pure]
   readonly attribute boolean defaultPrevented;
   [ChromeOnly, Pure]
   readonly attribute boolean defaultPreventedByChrome;
   [ChromeOnly, Pure]
   readonly attribute boolean defaultPreventedByContent;
+  [Pure]
+  readonly attribute boolean composed;
 
   [Unforgeable, Pure]
   readonly attribute boolean isTrusted;
   [Pure]
   readonly attribute DOMHighResTimeStamp timeStamp;
 
   void initEvent(DOMString type, boolean bubbles, boolean cancelable);
 };
@@ -64,9 +66,10 @@ partial interface Event {
   [ChromeOnly] readonly attribute boolean isSynthesized;
 
   boolean getPreventDefault();
 };
 
 dictionary EventInit {
   boolean bubbles = false;
   boolean cancelable = false;
+  boolean composed = false;
 };
--- a/dom/workers/ServiceWorkerEvents.cpp
+++ b/dom/workers/ServiceWorkerEvents.cpp
@@ -144,16 +144,17 @@ FetchEvent::Constructor(const GlobalObje
                         ErrorResult& aRv)
 {
   RefPtr<EventTarget> owner = do_QueryObject(aGlobal.GetAsSupports());
   MOZ_ASSERT(owner);
   RefPtr<FetchEvent> e = new FetchEvent(owner);
   bool trusted = e->Init(owner);
   e->InitEvent(aType, aOptions.mBubbles, aOptions.mCancelable);
   e->SetTrusted(trusted);
+  e->SetComposed(aOptions.mComposed);
   e->mRequest = aOptions.mRequest;
   e->mClientId = aOptions.mClientId;
   e->mIsReload = aOptions.mIsReload;
   return e.forget();
 }
 
 namespace {
 
@@ -1136,16 +1137,17 @@ PushEvent::Constructor(mozilla::dom::Eve
                        const nsAString& aType,
                        const PushEventInit& aOptions,
                        ErrorResult& aRv)
 {
   RefPtr<PushEvent> e = new PushEvent(aOwner);
   bool trusted = e->Init(aOwner);
   e->InitEvent(aType, aOptions.mBubbles, aOptions.mCancelable);
   e->SetTrusted(trusted);
+  e->SetComposed(aOptions.mComposed);
   if(aOptions.mData.WasPassed()){
     nsTArray<uint8_t> bytes;
     nsresult rv = ExtractBytesFromData(aOptions.mData.Value(), bytes);
     if (NS_FAILED(rv)) {
       aRv.Throw(rv);
       return nullptr;
     }
     e->mData = new PushMessageData(aOwner, Move(bytes));
--- a/dom/workers/ServiceWorkerEvents.h
+++ b/dom/workers/ServiceWorkerEvents.h
@@ -72,16 +72,17 @@ public:
   Constructor(mozilla::dom::EventTarget* aOwner,
               const nsAString& aType,
               const EventInit& aOptions)
   {
     RefPtr<ExtendableEvent> e = new ExtendableEvent(aOwner);
     bool trusted = e->Init(aOwner);
     e->InitEvent(aType, aOptions.mBubbles, aOptions.mCancelable);
     e->SetTrusted(trusted);
+    e->SetComposed(aOptions.mComposed);
     return e.forget();
   }
 
   static already_AddRefed<ExtendableEvent>
   Constructor(const GlobalObject& aGlobal,
               const nsAString& aType,
               const EventInit& aOptions,
               ErrorResult& aRv)
--- a/widget/BasicEvents.h
+++ b/widget/BasicEvents.h
@@ -121,16 +121,19 @@ public:
   bool mWantReplyFromContentProcess : 1;
   // The event's action will be handled by APZ. The main thread should not
   // perform its associated action. This is currently only relevant for
   // wheel and touch events.
   bool mHandledByAPZ : 1;
   // True if the event is currently being handled by an event listener that
   // was registered as a passive listener.
   bool mInPassiveListener: 1;
+  // If mComposed is true, the event fired by nodes in shadow DOM can cross the
+  // boundary of shadow DOM and light DOM.
+  bool mComposed : 1;
 
   // If the event is being handled in target phase, returns true.
   inline bool InTargetPhase() const
   {
     return (mInBubblingPhase && mInCapturePhase);
   }
 
   /**
@@ -334,16 +337,17 @@ protected:
     , mRefPoint(0, 0)
     , mLastRefPoint(0, 0)
     , mSpecifiedEventType(nullptr)
   {
     MOZ_COUNT_CTOR(WidgetEvent);
     mFlags.Clear();
     mFlags.mIsTrusted = aIsTrusted;
     SetDefaultCancelableAndBubbles();
+    SetDefaultComposed();
   }
 
   WidgetEvent()
     : WidgetEventTime()
   {
     MOZ_COUNT_CTOR(WidgetEvent);
   }
 
@@ -537,16 +541,150 @@ public:
    * handled by the last focused DOM element of the last focused DOM window in
    * the last focused window.
    */
   bool IsTargetedAtFocusedContent() const;
   /**
    * Whether the event should cause a DOM event.
    */
   bool IsAllowedToDispatchDOMEvent() const;
+  /**
+   * Initialize mComposed
+   */
+  void SetDefaultComposed()
+  {
+    switch (mClass) {
+      case eCompositionEventClass:
+        mFlags.mComposed = mMessage == eCompositionStart ||
+                           mMessage == eCompositionUpdate ||
+                           mMessage == eCompositionEnd;
+        break;
+      case eDragEventClass:
+        // All drag & drop events are composed
+        mFlags.mComposed = mMessage == eDrag || mMessage == eDragEnd ||
+                           mMessage == eDragEnter || mMessage == eDragExit ||
+                           mMessage == eDragLeave || mMessage == eDragOver ||
+                           mMessage == eDragStart || mMessage == eDrop;
+        break;
+      case eEditorInputEventClass:
+        mFlags.mComposed = mMessage == eEditorInput;
+        break;
+      case eFocusEventClass:
+        mFlags.mComposed = mMessage == eBlur || mMessage == eFocus;
+        break;
+      case eKeyboardEventClass:
+        mFlags.mComposed = mMessage == eKeyDown || mMessage == eKeyUp ||
+                           mMessage == eKeyPress;
+        break;
+      case eMouseEventClass:
+        mFlags.mComposed = mMessage == eMouseClick ||
+                           mMessage == eMouseDoubleClick ||
+                           mMessage == eMouseDown || mMessage == eMouseUp ||
+                           mMessage == eMouseEnter || mMessage == eMouseLeave ||
+                           mMessage == eMouseOver || mMessage == eMouseOut ||
+                           mMessage == eMouseMove || mMessage == eContextMenu;
+        break;
+      case ePointerEventClass:
+        // All pointer events are composed
+        mFlags.mComposed = mMessage == ePointerDown ||
+                           mMessage == ePointerMove || mMessage == ePointerUp ||
+                           mMessage == ePointerCancel ||
+                           mMessage == ePointerOver ||
+                           mMessage == ePointerOut ||
+                           mMessage == ePointerEnter ||
+                           mMessage == ePointerLeave ||
+                           mMessage == ePointerGotCapture ||
+                           mMessage == ePointerLostCapture;
+        break;
+      case eTouchEventClass:
+        // All touch events are composed
+        mFlags.mComposed = mMessage == eTouchStart || mMessage == eTouchEnd ||
+                           mMessage == eTouchMove || mMessage == eTouchCancel;
+        break;
+      case eUIEventClass:
+        mFlags.mComposed = mMessage == eLegacyDOMFocusIn ||
+                           mMessage == eLegacyDOMFocusOut ||
+                           mMessage == eLegacyDOMActivate;
+        break;
+      case eWheelEventClass:
+        // All wheel events are composed
+        mFlags.mComposed = mMessage == eWheel;
+        break;
+      default:
+        mFlags.mComposed = false;
+        break;
+    }
+  }
+
+  void SetComposed(const nsAString& aEventTypeArg)
+  {
+    mFlags.mComposed = // composition events
+                       aEventTypeArg.EqualsLiteral("compositionstart") ||
+                       aEventTypeArg.EqualsLiteral("compositionupdate") ||
+                       aEventTypeArg.EqualsLiteral("compositionend") ||
+                       // drag and drop events
+                       aEventTypeArg.EqualsLiteral("dragstart") ||
+                       aEventTypeArg.EqualsLiteral("drag") ||
+                       aEventTypeArg.EqualsLiteral("dragenter") ||
+                       aEventTypeArg.EqualsLiteral("dragexit") ||
+                       aEventTypeArg.EqualsLiteral("dragleave") ||
+                       aEventTypeArg.EqualsLiteral("dragover") ||
+                       aEventTypeArg.EqualsLiteral("drop") ||
+                       aEventTypeArg.EqualsLiteral("dropend") ||
+                       // editor input events
+                       aEventTypeArg.EqualsLiteral("input") ||
+                       aEventTypeArg.EqualsLiteral("beforeinput") ||
+                       // focus events
+                       aEventTypeArg.EqualsLiteral("blur") ||
+                       aEventTypeArg.EqualsLiteral("focus") ||
+                       aEventTypeArg.EqualsLiteral("focusin") ||
+                       aEventTypeArg.EqualsLiteral("focusout") ||
+                       // keyboard events
+                       aEventTypeArg.EqualsLiteral("keydown") ||
+                       aEventTypeArg.EqualsLiteral("keyup") ||
+                       aEventTypeArg.EqualsLiteral("keypress") ||
+                       // mouse events
+                       aEventTypeArg.EqualsLiteral("click") ||
+                       aEventTypeArg.EqualsLiteral("dblclick") ||
+                       aEventTypeArg.EqualsLiteral("mousedown") ||
+                       aEventTypeArg.EqualsLiteral("mouseup") ||
+                       aEventTypeArg.EqualsLiteral("mouseenter") ||
+                       aEventTypeArg.EqualsLiteral("mouseleave") ||
+                       aEventTypeArg.EqualsLiteral("mouseover") ||
+                       aEventTypeArg.EqualsLiteral("mouseout") ||
+                       aEventTypeArg.EqualsLiteral("mousemove") ||
+                       aEventTypeArg.EqualsLiteral("contextmenu") ||
+                       // pointer events
+                       aEventTypeArg.EqualsLiteral("pointerdown") ||
+                       aEventTypeArg.EqualsLiteral("pointermove") ||
+                       aEventTypeArg.EqualsLiteral("pointerup") ||
+                       aEventTypeArg.EqualsLiteral("pointercancel") ||
+                       aEventTypeArg.EqualsLiteral("pointerover") ||
+                       aEventTypeArg.EqualsLiteral("pointerout") ||
+                       aEventTypeArg.EqualsLiteral("pointerenter") ||
+                       aEventTypeArg.EqualsLiteral("pointerleave") ||
+                       aEventTypeArg.EqualsLiteral("gotpointercapture") ||
+                       aEventTypeArg.EqualsLiteral("lostpointercapture") ||
+                       // touch events
+                       aEventTypeArg.EqualsLiteral("touchstart") ||
+                       aEventTypeArg.EqualsLiteral("touchend") ||
+                       aEventTypeArg.EqualsLiteral("touchmove") ||
+                       aEventTypeArg.EqualsLiteral("touchcancel") ||
+                       // UI legacy events
+                       aEventTypeArg.EqualsLiteral("DOMFocusIn") ||
+                       aEventTypeArg.EqualsLiteral("DOMFocusOut") ||
+                       aEventTypeArg.EqualsLiteral("DOMActivate") ||
+                       // wheel events
+                       aEventTypeArg.EqualsLiteral("wheel");
+  }
+
+  void SetComposed(bool aComposed)
+  {
+    mFlags.mComposed = aComposed;
+  }
 };
 
 /******************************************************************************
  * mozilla::NativeEventData
  *
  * WidgetGUIEvent's mPluginEvent member used to be a void* pointer,
  * used to reference external, OS-specific data structures.
  *