tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Event.cpp (31235B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "Event.h"
      8 
      9 #include "AccessCheck.h"
     10 #include "base/basictypes.h"
     11 #include "ipc/IPCMessageUtils.h"
     12 #include "ipc/IPCMessageUtilsSpecializations.h"
     13 #include "mozilla/BasePrincipal.h"
     14 #include "mozilla/ContentEvents.h"
     15 #include "mozilla/DOMEventTargetHelper.h"
     16 #include "mozilla/EventDispatcher.h"
     17 #include "mozilla/EventStateManager.h"
     18 #include "mozilla/MiscEvents.h"
     19 #include "mozilla/MouseEvents.h"
     20 #include "mozilla/PointerLockManager.h"
     21 #include "mozilla/Preferences.h"
     22 #include "mozilla/PresShell.h"
     23 #include "mozilla/SVGOuterSVGFrame.h"
     24 #include "mozilla/SVGUtils.h"
     25 #include "mozilla/ScrollContainerFrame.h"
     26 #include "mozilla/StaticPrefs_dom.h"
     27 #include "mozilla/TextEvents.h"
     28 #include "mozilla/TouchEvents.h"
     29 #include "mozilla/ViewportUtils.h"
     30 #include "mozilla/dom/Document.h"
     31 #include "mozilla/dom/DocumentInlines.h"
     32 #include "mozilla/dom/FragmentOrElement.h"
     33 #include "mozilla/dom/Performance.h"
     34 #include "mozilla/dom/ShadowRoot.h"
     35 #include "mozilla/dom/WorkerPrivate.h"
     36 #include "mozilla/dom/WorkerScope.h"
     37 #include "nsCOMPtr.h"
     38 #include "nsContentUtils.h"
     39 #include "nsDeviceContext.h"
     40 #include "nsError.h"
     41 #include "nsGlobalWindowInner.h"
     42 #include "nsIContent.h"
     43 #include "nsIContentInlines.h"
     44 #include "nsIFrame.h"
     45 #include "nsJSEnvironment.h"
     46 #include "nsLayoutUtils.h"
     47 #include "nsPIWindowRoot.h"
     48 #include "nsRFPService.h"
     49 
     50 namespace mozilla::dom {
     51 
     52 Event::Event(EventTarget* aOwner, nsPresContext* aPresContext,
     53             WidgetEvent* aEvent) {
     54  ConstructorInit(aOwner, aPresContext, aEvent);
     55 }
     56 
     57 Event::Event(nsPIDOMWindowInner* aParent) {
     58  ConstructorInit(nsGlobalWindowInner::Cast(aParent), nullptr, nullptr);
     59 }
     60 
     61 void Event::ConstructorInit(EventTarget* aOwner, nsPresContext* aPresContext,
     62                            WidgetEvent* aEvent) {
     63  SetOwner(aOwner);
     64  mIsMainThreadEvent = NS_IsMainThread();
     65  if (mIsMainThreadEvent) {
     66    mRefCnt.SetIsOnMainThread();
     67  }
     68 
     69  mPrivateDataDuplicated = false;
     70  mWantsPopupControlCheck = false;
     71 
     72  if (aEvent) {
     73    mEvent = aEvent;
     74    mEventIsInternal = false;
     75  } else {
     76    mEventIsInternal = true;
     77    /*
     78      A derived class might want to allocate its own type of aEvent
     79      (derived from WidgetEvent). To do this, it should take care to pass
     80      a non-nullptr aEvent to this ctor, e.g.:
     81 
     82        FooEvent::FooEvent(..., WidgetEvent* aEvent)
     83          : Event(..., aEvent ? aEvent : new WidgetEvent())
     84 
     85      Then, to override the mEventIsInternal assignments done by the
     86      base ctor, it should do this in its own ctor:
     87 
     88        FooEvent::FooEvent(..., WidgetEvent* aEvent)
     89        ...
     90        {
     91          ...
     92          if (aEvent) {
     93            mEventIsInternal = false;
     94          }
     95          else {
     96            mEventIsInternal = true;
     97          }
     98          ...
     99        }
    100     */
    101    mEvent = new WidgetEvent(false, eVoidEvent);
    102  }
    103 
    104  InitPresContextData(aPresContext);
    105 }
    106 
    107 void Event::InitPresContextData(nsPresContext* aPresContext) {
    108  mPresContext = aPresContext;
    109  // Get the explicit original target (if it's anonymous make it null)
    110  {
    111    nsIContent* content = GetTargetFromFrame();
    112    if (content && !content->IsInNativeAnonymousSubtree()) {
    113      mExplicitOriginalTarget = content;
    114    } else {
    115      mExplicitOriginalTarget = nullptr;
    116    }
    117  }
    118 }
    119 
    120 Event::~Event() {
    121  NS_ASSERT_OWNINGTHREAD(Event);
    122 
    123  if (mEventIsInternal && mEvent) {
    124    delete mEvent;
    125  }
    126 }
    127 
    128 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Event)
    129  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
    130  NS_INTERFACE_MAP_ENTRY(nsISupports)
    131  NS_INTERFACE_MAP_ENTRY(Event)
    132 NS_INTERFACE_MAP_END
    133 
    134 NS_IMPL_CYCLE_COLLECTING_ADDREF(Event)
    135 NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(Event, LastRelease())
    136 
    137 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(Event)
    138 
    139 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Event)
    140  if (tmp->mEventIsInternal) {
    141    tmp->mEvent->mTarget = nullptr;
    142    tmp->mEvent->mCurrentTarget = nullptr;
    143    tmp->mEvent->mOriginalTarget = nullptr;
    144    tmp->mEvent->mRelatedTarget = nullptr;
    145    tmp->mEvent->mOriginalRelatedTarget = nullptr;
    146    switch (tmp->mEvent->mClass) {
    147      case eDragEventClass: {
    148        WidgetDragEvent* dragEvent = tmp->mEvent->AsDragEvent();
    149        dragEvent->mDataTransfer = nullptr;
    150        break;
    151      }
    152      case eClipboardEventClass:
    153        tmp->mEvent->AsClipboardEvent()->mClipboardData = nullptr;
    154        break;
    155      case eEditorInputEventClass: {
    156        InternalEditorInputEvent* inputEvent =
    157            tmp->mEvent->AsEditorInputEvent();
    158        inputEvent->mDataTransfer = nullptr;
    159        inputEvent->mTargetRanges.Clear();
    160        break;
    161      }
    162      default:
    163        break;
    164    }
    165 
    166    if (WidgetMouseEvent* mouseEvent = tmp->mEvent->AsMouseEvent()) {
    167      mouseEvent->mClickTarget = nullptr;
    168      mouseEvent->mTriggerEvent = nullptr;
    169    }
    170  }
    171  NS_IMPL_CYCLE_COLLECTION_UNLINK(mExplicitOriginalTarget);
    172  NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner);
    173  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
    174 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    175 
    176 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Event)
    177  if (tmp->mEventIsInternal) {
    178    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->mTarget)
    179    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->mCurrentTarget)
    180    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->mOriginalTarget)
    181    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->mRelatedTarget)
    182    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->mOriginalRelatedTarget);
    183    switch (tmp->mEvent->mClass) {
    184      case eDragEventClass: {
    185        WidgetDragEvent* dragEvent = tmp->mEvent->AsDragEvent();
    186        NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->mDataTransfer");
    187        cb.NoteXPCOMChild(dragEvent->mDataTransfer);
    188        break;
    189      }
    190      case eClipboardEventClass:
    191        NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->mClipboardData");
    192        cb.NoteXPCOMChild(tmp->mEvent->AsClipboardEvent()->mClipboardData);
    193        break;
    194      case eEditorInputEventClass:
    195        NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->mDataTransfer");
    196        cb.NoteXPCOMChild(tmp->mEvent->AsEditorInputEvent()->mDataTransfer);
    197        NS_IMPL_CYCLE_COLLECTION_TRAVERSE(
    198            mEvent->AsEditorInputEvent()->mTargetRanges);
    199        break;
    200      default:
    201        break;
    202    }
    203 
    204    if (WidgetMouseEvent* mouseEvent = tmp->mEvent->AsMouseEvent()) {
    205      NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->mClickTarget");
    206      cb.NoteXPCOMChild(mouseEvent->mClickTarget);
    207      NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->mTriggerEvent");
    208      cb.NoteXPCOMChild(mouseEvent->mTriggerEvent);
    209    }
    210  }
    211  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExplicitOriginalTarget)
    212  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
    213 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    214 
    215 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(Event)
    216  if (tmp->HasKnownLiveWrapper()) {
    217    if (tmp->mEventIsInternal) {
    218      if (WidgetEvent* event = tmp->mEvent) {
    219        auto mark = [](EventTarget* aTarget) {
    220          if (!aTarget) {
    221            return;
    222          }
    223          if (nsINode* node = aTarget->GetAsNode()) {
    224            FragmentOrElement::MarkNodeChildren(node);
    225            if (node->HasKnownLiveWrapper()) {
    226              // Use CanSkip to possibly mark more nodes to be certainly alive.
    227              FragmentOrElement::CanSkip(node, true);
    228            }
    229          }
    230        };
    231 
    232        mark(event->mTarget);
    233        mark(event->mCurrentTarget);
    234        mark(event->mOriginalTarget);
    235        mark(event->mRelatedTarget);
    236        mark(event->mOriginalRelatedTarget);
    237      }
    238    }
    239    return true;
    240  }
    241 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
    242 
    243 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(Event)
    244  return tmp->HasKnownLiveWrapperAndDoesNotNeedTracing(tmp);
    245 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
    246 
    247 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(Event)
    248  return tmp->HasKnownLiveWrapper();
    249 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
    250 
    251 void Event::LastRelease() {
    252  nsISupports* supports = nullptr;
    253  QueryInterface(NS_GET_IID(nsCycleCollectionISupports),
    254                 reinterpret_cast<void**>(&supports));
    255  nsXPCOMCycleCollectionParticipant* p = nullptr;
    256  CallQueryInterface(this, &p);
    257  p->Unlink(supports);
    258 }
    259 
    260 JSObject* Event::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
    261  return WrapObjectInternal(aCx, aGivenProto);
    262 }
    263 
    264 JSObject* Event::WrapObjectInternal(JSContext* aCx,
    265                                    JS::Handle<JSObject*> aGivenProto) {
    266  return Event_Binding::Wrap(aCx, this, aGivenProto);
    267 }
    268 
    269 void Event::GetType(nsAString& aType) const {
    270  GetWidgetEventType(mEvent, aType);
    271 }
    272 
    273 EventTarget* Event::GetTarget() const { return mEvent->GetDOMEventTarget(); }
    274 
    275 already_AddRefed<Document> Event::GetDocument() const {
    276  nsCOMPtr<EventTarget> eventTarget = GetTarget();
    277 
    278  if (!eventTarget) {
    279    return nullptr;
    280  }
    281 
    282  nsIGlobalObject* global = eventTarget->GetOwnerGlobal();
    283  if (!global) {
    284    return nullptr;
    285  }
    286 
    287  nsPIDOMWindowInner* win = global->GetAsInnerWindow();
    288  if (!win) {
    289    return nullptr;
    290  }
    291 
    292  nsCOMPtr<Document> doc;
    293  doc = win->GetExtantDoc();
    294 
    295  return doc.forget();
    296 }
    297 
    298 EventTarget* Event::GetCurrentTarget() const {
    299  return mEvent->GetCurrentDOMEventTarget();
    300 }
    301 
    302 void Event::ComposedPath(nsTArray<RefPtr<EventTarget>>& aPath) {
    303  EventDispatcher::GetComposedPathFor(mEvent, aPath);
    304 }
    305 
    306 //
    307 // Get the actual event target node (may have been retargeted for mouse events)
    308 //
    309 nsIContent* Event::GetTargetFromFrame() {
    310  if (!mPresContext) {
    311    return nullptr;
    312  }
    313 
    314  // Get the mTarget frame (have to get the ESM first)
    315  nsIFrame* targetFrame = mPresContext->EventStateManager()->GetEventTarget();
    316  if (!targetFrame) {
    317    return nullptr;
    318  }
    319 
    320  // get the real content
    321  return targetFrame->GetContentForEvent(mEvent);
    322 }
    323 
    324 EventTarget* Event::GetExplicitOriginalTarget() const {
    325  if (mExplicitOriginalTarget) {
    326    return mExplicitOriginalTarget;
    327  }
    328  return GetTarget();
    329 }
    330 
    331 EventTarget* Event::GetOriginalTarget() const {
    332  return mEvent->GetOriginalDOMEventTarget();
    333 }
    334 
    335 EventTarget* Event::GetOriginalTarget(CallerType aCallerType) const {
    336  if (aCallerType == CallerType::System || nsContentUtils::IsCallerUAWidget()) {
    337    return GetOriginalTarget();
    338  }
    339 
    340  EventTarget* et = mEvent->GetOriginalDOMEventTarget();
    341  nsIContent* content = nsIContent::FromEventTargetOrNull(et);
    342  if (!content) {
    343    return et;
    344  }
    345  return content->FindFirstNonChromeOnlyAccessContent();
    346 }
    347 
    348 EventTarget* Event::GetComposedTarget() const {
    349  EventTarget* et = GetOriginalTarget();
    350  nsIContent* content = nsIContent::FromEventTargetOrNull(et);
    351  if (!content) {
    352    return et;
    353  }
    354  nsIContent* nonChrome = content->FindFirstNonChromeOnlyAccessContent();
    355  return nonChrome ? static_cast<EventTarget*>(nonChrome)
    356                   : static_cast<EventTarget*>(content->GetComposedDoc());
    357 }
    358 
    359 void Event::SetTrusted(bool aTrusted) { mEvent->mFlags.mIsTrusted = aTrusted; }
    360 
    361 bool Event::ShouldIgnoreChromeEventTargetListener() const {
    362  MOZ_ASSERT(NS_IsMainThread());
    363  if (!XRE_IsParentProcess()) {
    364    return false;
    365  }
    366  if (EventTarget* currentTarget = GetCurrentTarget();
    367      NS_WARN_IF(!currentTarget) || !currentTarget->IsRootWindow()) {
    368    return false;
    369  }
    370  EventTarget* et = GetOriginalTarget();
    371  if (NS_WARN_IF(!et)) {
    372    return false;
    373  }
    374  nsIGlobalObject* global = et->GetOwnerGlobal();
    375  if (NS_WARN_IF(!global)) {
    376    return false;
    377  }
    378  nsPIDOMWindowInner* win = global->GetAsInnerWindow();
    379  if (NS_WARN_IF(!win)) {
    380    return false;
    381  }
    382  BrowsingContext* bc = win->GetBrowsingContext();
    383  if (NS_WARN_IF(!bc)) {
    384    return false;
    385  }
    386  // If this is a content event on an nsWindowRoot, then we also handle this in
    387  // InProcessBrowserChildMessageManager, so we can ignore this event.
    388  return bc->IsContent();
    389 }
    390 
    391 bool Event::Init(mozilla::dom::EventTarget* aGlobal) {
    392  if (!mIsMainThreadEvent) {
    393    return IsCurrentThreadRunningChromeWorker();
    394  }
    395  bool trusted = false;
    396  if (aGlobal) {
    397    if (nsPIDOMWindowInner* w = aGlobal->GetAsInnerWindow()) {
    398      if (Document* d = w->GetExtantDoc()) {
    399        trusted = nsContentUtils::IsChromeDoc(d);
    400        if (nsPresContext* presContext = d->GetPresContext()) {
    401          InitPresContextData(presContext);
    402        }
    403      }
    404    }
    405  }
    406  return trusted;
    407 }
    408 
    409 // static
    410 already_AddRefed<Event> Event::Constructor(const GlobalObject& aGlobal,
    411                                           const nsAString& aType,
    412                                           const EventInit& aParam) {
    413  nsCOMPtr<mozilla::dom::EventTarget> t =
    414      do_QueryInterface(aGlobal.GetAsSupports());
    415  return Constructor(t, aType, aParam);
    416 }
    417 
    418 // static
    419 already_AddRefed<Event> Event::Constructor(EventTarget* aEventTarget,
    420                                           const nsAString& aType,
    421                                           const EventInit& aParam) {
    422  RefPtr<Event> e = new Event(aEventTarget, nullptr, nullptr);
    423  bool trusted = e->Init(aEventTarget);
    424  e->InitEvent(aType, aParam.mBubbles, aParam.mCancelable);
    425  e->SetTrusted(trusted);
    426  e->SetComposed(aParam.mComposed);
    427  return e.forget();
    428 }
    429 
    430 uint16_t Event::EventPhase() const {
    431  if ((mEvent->mCurrentTarget && mEvent->mCurrentTarget == mEvent->mTarget) ||
    432      mEvent->mFlags.mInTargetPhase) {
    433    return Event_Binding::AT_TARGET;
    434  }
    435  if (mEvent->mFlags.mInCapturePhase) {
    436    return Event_Binding::CAPTURING_PHASE;
    437  }
    438  if (mEvent->mFlags.mInBubblingPhase) {
    439    return Event_Binding::BUBBLING_PHASE;
    440  }
    441  return Event_Binding::NONE;
    442 }
    443 
    444 void Event::StopPropagation() { mEvent->StopPropagation(); }
    445 
    446 void Event::StopImmediatePropagation() { mEvent->StopImmediatePropagation(); }
    447 
    448 void Event::StopCrossProcessForwarding() {
    449  mEvent->StopCrossProcessForwarding();
    450 }
    451 
    452 void Event::PreventDefault() {
    453  // This method is called only from C++ code which must handle default action
    454  // of this event.  So, pass true always.
    455  PreventDefaultInternal(true);
    456 }
    457 
    458 void Event::PreventDefault(JSContext* aCx, CallerType aCallerType) {
    459  // Note that at handling default action, another event may be dispatched.
    460  // Then, JS in content mey be call preventDefault()
    461  // even in the event is in system event group.  Therefore, don't refer
    462  // mInSystemGroup here.
    463  nsIPrincipal* principal =
    464      mIsMainThreadEvent ? nsContentUtils::SubjectPrincipal(aCx) : nullptr;
    465 
    466  PreventDefaultInternal(aCallerType == CallerType::System, principal);
    467 }
    468 
    469 void Event::PreventDefaultInternal(bool aCalledByDefaultHandler,
    470                                   nsIPrincipal* aPrincipal) {
    471  if (mEvent->mFlags.mInPassiveListener) {
    472    if (mOwner) {
    473      if (nsPIDOMWindowInner* win = mOwner->GetAsInnerWindow()) {
    474        if (Document* doc = win->GetExtantDoc()) {
    475          if (!doc->HasWarnedAbout(
    476                  Document::ePreventDefaultFromPassiveListener)) {
    477            AutoTArray<nsString, 1> params;
    478            GetType(*params.AppendElement());
    479            doc->WarnOnceAbout(Document::ePreventDefaultFromPassiveListener,
    480                               false, params);
    481          }
    482        }
    483      }
    484    }
    485    return;
    486  }
    487  if (!mEvent->mFlags.mCancelable) {
    488    return;
    489  }
    490 
    491  mEvent->PreventDefault(aCalledByDefaultHandler, aPrincipal);
    492 
    493  if (!IsTrusted()) {
    494    return;
    495  }
    496 
    497  if (mEvent->mClass == eDragEventClass) {
    498    UpdateDefaultPreventedOnContentForDragEvent();
    499  }
    500 }
    501 
    502 void Event::UpdateDefaultPreventedOnContentForDragEvent() {
    503  WidgetDragEvent* dragEvent = mEvent->AsDragEvent();
    504  if (!dragEvent) {
    505    return;
    506  }
    507 
    508  nsIPrincipal* principal = nullptr;
    509  // Since we now have HTMLEditorEventListener registered on nsWindowRoot,
    510  // mCurrentTarget could be nsWindowRoot, so we need to use
    511  // mTarget if that's the case.
    512  MOZ_ASSERT_IF(dragEvent->mInHTMLEditorEventListener,
    513                mEvent->mCurrentTarget->IsRootWindow());
    514  EventTarget* target = dragEvent->mInHTMLEditorEventListener
    515                            ? mEvent->mTarget
    516                            : mEvent->mCurrentTarget;
    517 
    518  nsINode* node = nsINode::FromEventTargetOrNull(target);
    519  if (node) {
    520    principal = node->NodePrincipal();
    521  } else {
    522    nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(target);
    523    if (sop) {
    524      principal = sop->GetPrincipal();
    525    }
    526  }
    527  if (principal && !principal->IsSystemPrincipal()) {
    528    dragEvent->mDefaultPreventedOnContent = true;
    529  }
    530 }
    531 
    532 void Event::SetEventType(const nsAString& aEventTypeArg) {
    533  mEvent->mSpecifiedEventTypeString.Truncate();
    534  if (mIsMainThreadEvent) {
    535    EventClassID classID = mEvent->mClass;
    536    if (classID == eMouseEventClass) {
    537      // Some pointer event types were changed from MouseEvent.  For backward
    538      // compatibility, we need to handle untrusted events of them created with
    539      // MouseEvent instance in some places.
    540      if (aEventTypeArg.EqualsLiteral(u"click") ||
    541          aEventTypeArg.EqualsLiteral(u"auxclick") ||
    542          aEventTypeArg.EqualsLiteral(u"contextmenu")) {
    543        classID = ePointerEventClass;
    544      }
    545    }
    546    mEvent->mSpecifiedEventType = nsContentUtils::GetEventMessageAndAtom(
    547        aEventTypeArg, classID, &(mEvent->mMessage));
    548    mEvent->SetDefaultComposed();
    549  } else {
    550    mEvent->mSpecifiedEventType = NS_Atomize(u"on"_ns + aEventTypeArg);
    551    mEvent->mMessage = eUnidentifiedEvent;
    552    mEvent->SetComposed(aEventTypeArg);
    553  }
    554  mEvent->SetDefaultComposedInNativeAnonymousContent();
    555 }
    556 
    557 already_AddRefed<EventTarget> Event::EnsureWebAccessibleRelatedTarget(
    558    EventTarget* aRelatedTarget) {
    559  nsCOMPtr<EventTarget> relatedTarget = aRelatedTarget;
    560  if (relatedTarget) {
    561    nsIContent* content = nsIContent::FromEventTarget(relatedTarget);
    562    if (content && content->ChromeOnlyAccess() &&
    563        !nsContentUtils::CanAccessNativeAnon()) {
    564      content = content->FindFirstNonChromeOnlyAccessContent();
    565      relatedTarget = content;
    566    }
    567 
    568    if (relatedTarget) {
    569      relatedTarget = relatedTarget->GetTargetForDOMEvent();
    570    }
    571  }
    572  return relatedTarget.forget();
    573 }
    574 
    575 void Event::InitEvent(const nsAString& aEventTypeArg,
    576                      mozilla::CanBubble aCanBubbleArg,
    577                      mozilla::Cancelable aCancelableArg,
    578                      mozilla::Composed aComposedArg) {
    579  // Make sure this event isn't already being dispatched.
    580  NS_ENSURE_TRUE_VOID(!mEvent->mFlags.mIsBeingDispatched);
    581 
    582  if (IsTrusted()) {
    583    // Ensure the caller is permitted to dispatch trusted DOM events.
    584    if (!nsContentUtils::ThreadsafeIsCallerChrome()) {
    585      SetTrusted(false);
    586    }
    587  }
    588 
    589  SetEventType(aEventTypeArg);
    590 
    591  mEvent->mFlags.mBubbles = aCanBubbleArg == CanBubble::eYes;
    592  mEvent->mFlags.mCancelable = aCancelableArg == Cancelable::eYes;
    593  if (aComposedArg != Composed::eDefault) {
    594    mEvent->mFlags.mComposed = aComposedArg == Composed::eYes;
    595  }
    596 
    597  mEvent->mFlags.mDefaultPrevented = false;
    598  mEvent->mFlags.mDefaultPreventedByContent = false;
    599  mEvent->mFlags.mDefaultPreventedByChrome = false;
    600  mEvent->mFlags.mPropagationStopped = false;
    601  mEvent->mFlags.mImmediatePropagationStopped = false;
    602 
    603  // Clearing the old targets, so that the event is targeted correctly when
    604  // re-dispatching it.
    605  mEvent->mTarget = nullptr;
    606  mEvent->mOriginalTarget = nullptr;
    607 }
    608 
    609 void Event::DuplicatePrivateData() {
    610  NS_ASSERTION(mEvent, "No WidgetEvent for Event duplication!");
    611  if (mEventIsInternal) {
    612    return;
    613  }
    614 
    615  mEvent = mEvent->Duplicate();
    616  mPresContext = nullptr;
    617  mEventIsInternal = true;
    618  mPrivateDataDuplicated = true;
    619 }
    620 
    621 void Event::SetTarget(EventTarget* aTarget) { mEvent->mTarget = aTarget; }
    622 
    623 bool Event::IsDispatchStopped() { return mEvent->PropagationStopped(); }
    624 
    625 WidgetEvent* Event::WidgetEventPtr() { return mEvent; }
    626 
    627 // static
    628 Maybe<CSSDoublePoint> Event::GetScreenCoords(
    629    nsPresContext* aPresContext, WidgetEvent* aEvent,
    630    const LayoutDeviceDoublePoint& aWidgetOrScreenRelativePoint) {
    631  if (PointerLockManager::IsLocked()) {
    632    return Some(EventStateManager::sLastScreenPoint);
    633  }
    634 
    635  if (!aEvent || !aEvent->DOMEventSupportsCoords()) {
    636    return Nothing();
    637  }
    638 
    639  // Doing a straight conversion from LayoutDeviceDoublePoint to CSSDoublePoint
    640  // seem incorrect, but it is needed to maintain legacy functionality.
    641  const WidgetGUIEvent* guiEvent = aEvent->AsGUIEvent();
    642  if (MOZ_UNLIKELY(!aPresContext) || !(guiEvent && guiEvent->mWidget)) {
    643    // XXX aPresContext is usually available.  Then, we can know the latest
    644    // scale of the document.  Should we apply it?
    645    return Some(CSSDoublePoint(aWidgetOrScreenRelativePoint.x,
    646                               aWidgetOrScreenRelativePoint.y));
    647  }
    648 
    649  // (Potentially) transform the point from the coordinate space of an
    650  // out-of-process iframe to the coordinate space of the native
    651  // window. The transform can only be applied to a point whose components
    652  // are floating-point values, so convert the integer point first, then
    653  // transform, and then round the result back to an integer point.
    654  const LayoutDeviceIntPoint topLevelPoint = LayoutDeviceIntPoint::Round(
    655      guiEvent->mWidget->WidgetToTopLevelWidgetTransform().TransformPoint(
    656          aWidgetOrScreenRelativePoint));
    657  const CSSPoint pt = CSSPixel::FromAppUnits(
    658      LayoutDevicePixel::ToAppUnits(
    659          topLevelPoint, aPresContext->DeviceContext()->AppUnitsPerDevPixel()) +
    660      LayoutDevicePixel::ToAppUnits(
    661          guiEvent->mWidget->TopLevelWidgetToScreenOffset(),
    662          aPresContext->DeviceContext()->AppUnitsPerDevPixel()));
    663  return Some(CSSDoublePoint(pt.x, pt.y));
    664 }
    665 
    666 // static
    667 CSSDoublePoint Event::GetPageCoords(
    668    nsPresContext* aPresContext, WidgetEvent* aEvent,
    669    const LayoutDeviceDoublePoint& aWidgetOrScreenRelativePoint,
    670    const CSSDoublePoint& aDefaultClientPoint) {
    671  const CSSDoublePoint clientCoords = Event::GetClientCoords(
    672      aPresContext, aEvent, aWidgetOrScreenRelativePoint, aDefaultClientPoint);
    673 
    674  // If there is some scrolling, add scroll info to client point.
    675  const CSSPoint scrollPoint = CSSPixel::FromAppUnits([&]() {
    676    if (aPresContext && aPresContext->GetPresShell()) {
    677      if (const ScrollContainerFrame* const sf =
    678              aPresContext->PresShell()->GetRootScrollContainerFrame()) {
    679        return sf->GetScrollPosition();
    680      }
    681    }
    682    return nsPoint{};
    683  }());
    684  return clientCoords + CSSDoublePoint(scrollPoint.x, scrollPoint.y);
    685 }
    686 
    687 // static
    688 CSSDoublePoint Event::GetClientCoords(
    689    nsPresContext* aPresContext, WidgetEvent* aEvent,
    690    const LayoutDeviceDoublePoint& aWidgetOrScreenRelativePoint,
    691    const CSSDoublePoint& aDefaultClientPoint) {
    692  if (PointerLockManager::IsLocked()) {
    693    return EventStateManager::sLastClientPoint;
    694  }
    695 
    696  if (MOZ_UNLIKELY(!aPresContext) || MOZ_UNLIKELY(!aEvent) ||
    697      !aEvent->DOMEventSupportsCoords() ||
    698      MOZ_UNLIKELY(!aEvent->AsGUIEvent()->mWidget)) {
    699    return aDefaultClientPoint;
    700  }
    701 
    702  const PresShell* const presShell = aPresContext->GetPresShell();
    703  if (MOZ_UNLIKELY(!presShell)) {
    704    return CSSDoublePoint(0, 0);
    705  }
    706  // XXX Why don't we flush pending notifications before computing the offset
    707  // from the root frame?
    708  const nsIFrame* const rootFrame = presShell->GetRootFrame();
    709  if (MOZ_UNLIKELY(!rootFrame)) {
    710    return CSSDoublePoint(0, 0);
    711  }
    712  const CSSPoint pt =
    713      CSSPixel::FromAppUnits(nsLayoutUtils::GetEventCoordinatesRelativeTo(
    714          aEvent, LayoutDeviceIntPoint::Round(aWidgetOrScreenRelativePoint),
    715          RelativeTo{rootFrame}));
    716  return CSSDoublePoint(pt.x, pt.y);
    717 }
    718 
    719 // static
    720 nsIFrame* Event::GetPrimaryFrameOfEventTarget(const nsPresContext& aPresContext,
    721                                              const WidgetEvent& aEvent) {
    722  const nsCOMPtr<nsIContent> content =
    723      nsIContent::FromEventTargetOrNull(aEvent.mTarget);
    724  if (!content) {
    725    return nullptr;
    726  }
    727  // XXX Even after the event target content is moved to different document, we
    728  // may get its primary frame.  In this case, should we return nullptr here?
    729  nsIFrame* const frame = content->GetPrimaryFrame(FlushType::Layout);
    730  if (MOZ_UNLIKELY(!frame || frame->PresContext() != &aPresContext)) {
    731    return nullptr;
    732  }
    733  // For compat, see https://github.com/w3c/csswg-drafts/issues/1508. In SVG
    734  // we just return the coordinates of the outer SVG box. This is all kinda
    735  // unfortunate.
    736  if (frame->HasAnyStateBits(NS_FRAME_SVG_LAYOUT) &&
    737      StaticPrefs::dom_events_offset_in_svg_relative_to_svg_root()) {
    738    return SVGUtils::GetOuterSVGFrame(frame);
    739  }
    740  return frame;
    741 }
    742 
    743 // static
    744 CSSDoublePoint Event::GetOffsetCoords(
    745    nsPresContext* aPresContext, WidgetEvent* aEvent,
    746    const LayoutDeviceDoublePoint& aWidgetOrScreenRelativePoint,
    747    const CSSDoublePoint& aDefaultClientPoint) {
    748  if (!aEvent->mTarget) {
    749    return GetPageCoords(aPresContext, aEvent, aWidgetOrScreenRelativePoint,
    750                         aDefaultClientPoint);
    751  }
    752  if (!nsIContent::FromEventTarget(aEvent->mTarget) || !aPresContext) {
    753    return CSSDoublePoint();
    754  }
    755  const nsIFrame* const frame =
    756      GetPrimaryFrameOfEventTarget(*aPresContext, *aEvent);
    757  if (MOZ_UNLIKELY(!frame)) {
    758    return CSSDoublePoint();
    759  }
    760  MOZ_ASSERT(aPresContext->PresShell()->GetRootFrame());
    761  const CSSDoublePoint clientCoords = GetClientCoords(
    762      aPresContext, aEvent, aWidgetOrScreenRelativePoint, aDefaultClientPoint);
    763  nsPoint ptInAppUnits = CSSPixel::ToAppUnits(CSSPoint(
    764      static_cast<float>(clientCoords.x), static_cast<float>(clientCoords.y)));
    765  if (nsLayoutUtils::TransformPoint(
    766          RelativeTo{aPresContext->PresShell()->GetRootFrame()},
    767          RelativeTo{frame},
    768          ptInAppUnits) != nsLayoutUtils::TRANSFORM_SUCCEEDED) {
    769    return CSSDoublePoint();
    770  }
    771  ptInAppUnits -= frame->GetPaddingRectRelativeToSelf().TopLeft();
    772  const CSSPoint pt = CSSPixel::FromAppUnits(ptInAppUnits);
    773  return CSSDoublePoint(pt.x, pt.y);
    774 }
    775 
    776 // To be called ONLY by Event::GetType (which has the additional
    777 // logic for handling user-defined events).
    778 // static
    779 const char16_t* Event::GetEventName(EventMessage aEventType) {
    780  switch (aEventType) {
    781 #define MESSAGE_TO_EVENT(name_, _message, _type, _struct) \
    782  case _message:                                          \
    783    return u"" #name_;
    784 #include "mozilla/EventNameList.h"
    785 #undef MESSAGE_TO_EVENT
    786    default:
    787      break;
    788  }
    789  // XXXldb We can hit this case for WidgetEvent objects that we didn't
    790  // create and that are not user defined events since this function and
    791  // SetEventType are incomplete.  (But fixing that requires fixing the
    792  // arrays in nsEventListenerManager too, since the events for which
    793  // this is a problem generally *are* created by Event.)
    794  return nullptr;
    795 }
    796 
    797 bool Event::DefaultPrevented(CallerType aCallerType) const {
    798  NS_ENSURE_TRUE(mEvent, false);
    799 
    800  // If preventDefault() has never been called, just return false.
    801  if (!mEvent->DefaultPrevented()) {
    802    return false;
    803  }
    804 
    805  // If preventDefault() has been called by content, return true.  Otherwise,
    806  // i.e., preventDefault() has been called by chrome, return true only when
    807  // this is called by chrome.
    808  return mEvent->DefaultPreventedByContent() ||
    809         aCallerType == CallerType::System;
    810 }
    811 
    812 bool Event::ReturnValue(CallerType aCallerType) const {
    813  return !DefaultPrevented(aCallerType);
    814 }
    815 
    816 void Event::SetReturnValue(bool aReturnValue, CallerType aCallerType) {
    817  if (!aReturnValue) {
    818    PreventDefaultInternal(aCallerType == CallerType::System);
    819  }
    820 }
    821 
    822 double Event::TimeStamp() {
    823  if (mEvent->mTimeStamp.IsNull()) {
    824    return 0.0;
    825  }
    826 
    827  if (mIsMainThreadEvent) {
    828    if (NS_WARN_IF(!mOwner)) {
    829      return 0.0;
    830    }
    831 
    832    nsPIDOMWindowInner* win = mOwner->GetAsInnerWindow();
    833    if (NS_WARN_IF(!win)) {
    834      return 0.0;
    835    }
    836 
    837    Performance* perf = win->GetPerformance();
    838    if (NS_WARN_IF(!perf)) {
    839      return 0.0;
    840    }
    841 
    842    double ret =
    843        perf->GetDOMTiming()->TimeStampToDOMHighRes(mEvent->mTimeStamp);
    844    MOZ_ASSERT(mOwner->PrincipalOrNull());
    845 
    846    return nsRFPService::ReduceTimePrecisionAsMSecs(
    847        ret, perf->GetRandomTimelineSeed(), perf->GetRTPCallerType());
    848  }
    849 
    850  WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
    851  MOZ_ASSERT(workerPrivate);
    852 
    853  double ret = workerPrivate->TimeStampToDOMHighRes(mEvent->mTimeStamp);
    854 
    855  return nsRFPService::ReduceTimePrecisionAsMSecs(
    856      ret, workerPrivate->GetRandomTimelineSeed(),
    857      workerPrivate->GlobalScope()->GetRTPCallerType());
    858 }
    859 
    860 void Event::Serialize(IPC::MessageWriter* aWriter,
    861                      bool aSerializeInterfaceType) {
    862  if (aSerializeInterfaceType) {
    863    IPC::WriteParam(aWriter, u"event"_ns);
    864  }
    865 
    866  nsString type;
    867  GetType(type);
    868  IPC::WriteParam(aWriter, type);
    869 
    870  IPC::WriteParam(aWriter, Bubbles());
    871  IPC::WriteParam(aWriter, Cancelable());
    872  IPC::WriteParam(aWriter, IsTrusted());
    873  IPC::WriteParam(aWriter, Composed());
    874 
    875  // No timestamp serialization for now!
    876 }
    877 
    878 bool Event::Deserialize(IPC::MessageReader* aReader) {
    879  nsString type;
    880  NS_ENSURE_TRUE(IPC::ReadParam(aReader, &type), false);
    881 
    882  bool bubbles = false;
    883  NS_ENSURE_TRUE(IPC::ReadParam(aReader, &bubbles), false);
    884 
    885  bool cancelable = false;
    886  NS_ENSURE_TRUE(IPC::ReadParam(aReader, &cancelable), false);
    887 
    888  bool trusted = false;
    889  NS_ENSURE_TRUE(IPC::ReadParam(aReader, &trusted), false);
    890 
    891  bool composed = false;
    892  NS_ENSURE_TRUE(IPC::ReadParam(aReader, &composed), false);
    893 
    894  InitEvent(type, bubbles, cancelable);
    895  SetTrusted(trusted);
    896  SetComposed(composed);
    897 
    898  return true;
    899 }
    900 
    901 void Event::SetOwner(EventTarget* aOwner) {
    902  mOwner = nullptr;
    903 
    904  if (!aOwner) {
    905    return;
    906  }
    907 
    908  if (nsINode* n = aOwner->GetAsNode()) {
    909    mOwner = n->OwnerDoc()->GetScopeObject();
    910    return;
    911  }
    912 
    913  if (nsPIDOMWindowInner* w = aOwner->GetAsInnerWindow()) {
    914    mOwner = w->AsGlobal();
    915    return;
    916  }
    917 
    918  nsCOMPtr<DOMEventTargetHelper> eth = do_QueryInterface(aOwner);
    919  if (eth) {
    920    mOwner = eth->GetParentObject();
    921    return;
    922  }
    923 
    924 #ifdef DEBUG
    925  nsCOMPtr<nsPIWindowRoot> root = do_QueryInterface(aOwner);
    926  MOZ_ASSERT(root, "Unexpected EventTarget!");
    927 #endif
    928 }
    929 
    930 void Event::GetWidgetEventType(WidgetEvent* aEvent, nsAString& aType) {
    931  if (!aEvent->mSpecifiedEventTypeString.IsEmpty()) {
    932    aType = aEvent->mSpecifiedEventTypeString;
    933    return;
    934  }
    935 
    936  const char16_t* name = GetEventName(aEvent->mMessage);
    937 
    938  if (name) {
    939    aType.AssignLiteral(name, nsString::char_traits::length(name));
    940    return;
    941  } else if (aEvent->mMessage == eUnidentifiedEvent &&
    942             aEvent->mSpecifiedEventType) {
    943    // Remove "on"
    944    aType = Substring(nsDependentAtomString(aEvent->mSpecifiedEventType), 2);
    945    aEvent->mSpecifiedEventTypeString = aType;
    946    return;
    947  }
    948 
    949  aType.Truncate();
    950 }
    951 
    952 bool Event::IsDragExitEnabled(JSContext* aCx, JSObject* aGlobal) {
    953  return StaticPrefs::dom_event_dragexit_enabled() ||
    954         nsContentUtils::IsSystemCaller(aCx);
    955 }
    956 
    957 }  // namespace mozilla::dom
    958 
    959 using namespace mozilla;
    960 using namespace mozilla::dom;
    961 
    962 already_AddRefed<Event> NS_NewDOMEvent(EventTarget* aOwner,
    963                                       nsPresContext* aPresContext,
    964                                       WidgetEvent* aEvent) {
    965  RefPtr<Event> it = new Event(aOwner, aPresContext, aEvent);
    966  return it.forget();
    967 }