Bug 1292063 - Part 1: Add Event.composed. r=smaug
authorStone Shih <sshih@mozilla.com>
Wed, 31 Aug 2016 11:16:11 +0800
changeset 347078 22cf15bb84d4425107834b15b993f8414807ab50
parent 347077 64c6e5121479fd7d68ca7c757b44abf8e3182087
child 347079 79c5fa0ce1c61f250c7c5e05266ae61a1f1129e8
push id10
push userfmarier@mozilla.com
push dateWed, 05 Oct 2016 23:37:28 +0000
reviewerssmaug
bugs1292063
milestone52.0a1
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.
  *