dom/events/Event.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "AccessCheck.h"
     7 #include "base/basictypes.h"
     8 #include "ipc/IPCMessageUtils.h"
     9 #include "mozilla/dom/Event.h"
    10 #include "mozilla/ContentEvents.h"
    11 #include "mozilla/DOMEventTargetHelper.h"
    12 #include "mozilla/EventStateManager.h"
    13 #include "mozilla/InternalMutationEvent.h"
    14 #include "mozilla/MiscEvents.h"
    15 #include "mozilla/MouseEvents.h"
    16 #include "mozilla/Preferences.h"
    17 #include "mozilla/TextEvents.h"
    18 #include "mozilla/TouchEvents.h"
    19 #include "nsContentUtils.h"
    20 #include "nsCOMPtr.h"
    21 #include "nsDeviceContext.h"
    22 #include "nsError.h"
    23 #include "nsGlobalWindow.h"
    24 #include "nsIFrame.h"
    25 #include "nsIContent.h"
    26 #include "nsIDocument.h"
    27 #include "nsIPresShell.h"
    28 #include "nsIScrollableFrame.h"
    29 #include "nsJSEnvironment.h"
    30 #include "nsLayoutUtils.h"
    31 #include "nsPIWindowRoot.h"
    33 namespace mozilla {
    34 namespace dom {
    36 namespace workers {
    37 extern bool IsCurrentThreadRunningChromeWorker();
    38 } // namespace workers
    40 static char *sPopupAllowedEvents;
    42 Event::Event(EventTarget* aOwner,
    43              nsPresContext* aPresContext,
    44              WidgetEvent* aEvent)
    45 {
    46   ConstructorInit(aOwner, aPresContext, aEvent);
    47 }
    49 Event::Event(nsPIDOMWindow* aParent)
    50 {
    51   ConstructorInit(static_cast<nsGlobalWindow *>(aParent), nullptr, nullptr);
    52 }
    54 void
    55 Event::ConstructorInit(EventTarget* aOwner,
    56                        nsPresContext* aPresContext,
    57                        WidgetEvent* aEvent)
    58 {
    59   SetIsDOMBinding();
    60   SetOwner(aOwner);
    61   mIsMainThreadEvent = mOwner || NS_IsMainThread();
    62   if (mIsMainThreadEvent) {
    63     nsJSContext::LikelyShortLivingObjectCreated();
    64   }
    66   mPrivateDataDuplicated = false;
    68   if (aEvent) {
    69     mEvent = aEvent;
    70     mEventIsInternal = false;
    71   }
    72   else {
    73     mEventIsInternal = true;
    74     /*
    75       A derived class might want to allocate its own type of aEvent
    76       (derived from WidgetEvent). To do this, it should take care to pass
    77       a non-nullptr aEvent to this ctor, e.g.:
    79         FooEvent::FooEvent(..., WidgetEvent* aEvent)
    80           : Event(..., aEvent ? aEvent : new WidgetEvent())
    82       Then, to override the mEventIsInternal assignments done by the
    83       base ctor, it should do this in its own ctor:
    85         FooEvent::FooEvent(..., WidgetEvent* aEvent)
    86         ...
    87         {
    88           ...
    89           if (aEvent) {
    90             mEventIsInternal = false;
    91           }
    92           else {
    93             mEventIsInternal = true;
    94           }
    95           ...
    96         }
    97      */
    98     mEvent = new WidgetEvent(false, 0);
    99     mEvent->time = PR_Now();
   100   }
   102   InitPresContextData(aPresContext);
   103 }
   105 void
   106 Event::InitPresContextData(nsPresContext* aPresContext)
   107 {
   108   mPresContext = aPresContext;
   109   // Get the explicit original target (if it's anonymous make it null)
   110   {
   111     nsCOMPtr<nsIContent> content = GetTargetFromFrame();
   112     mExplicitOriginalTarget = content;
   113     if (content && content->IsInAnonymousSubtree()) {
   114       mExplicitOriginalTarget = nullptr;
   115     }
   116   }
   117 }
   119 Event::~Event() 
   120 {
   121   NS_ASSERT_OWNINGTHREAD(Event);
   123   if (mEventIsInternal && mEvent) {
   124     delete mEvent;
   125   }
   126 }
   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(nsIDOMEvent)
   132 NS_INTERFACE_MAP_END
   134 NS_IMPL_CYCLE_COLLECTING_ADDREF(Event)
   135 NS_IMPL_CYCLE_COLLECTING_RELEASE(Event)
   137 NS_IMPL_CYCLE_COLLECTION_CLASS(Event)
   139 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Event)
   140   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
   141 NS_IMPL_CYCLE_COLLECTION_TRACE_END
   143 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Event)
   144   if (tmp->mEventIsInternal) {
   145     tmp->mEvent->target = nullptr;
   146     tmp->mEvent->currentTarget = nullptr;
   147     tmp->mEvent->originalTarget = nullptr;
   148     switch (tmp->mEvent->eventStructType) {
   149       case NS_MOUSE_EVENT:
   150       case NS_MOUSE_SCROLL_EVENT:
   151       case NS_WHEEL_EVENT:
   152       case NS_SIMPLE_GESTURE_EVENT:
   153       case NS_POINTER_EVENT:
   154         tmp->mEvent->AsMouseEventBase()->relatedTarget = nullptr;
   155         break;
   156       case NS_DRAG_EVENT: {
   157         WidgetDragEvent* dragEvent = tmp->mEvent->AsDragEvent();
   158         dragEvent->dataTransfer = nullptr;
   159         dragEvent->relatedTarget = nullptr;
   160         break;
   161       }
   162       case NS_CLIPBOARD_EVENT:
   163         tmp->mEvent->AsClipboardEvent()->clipboardData = nullptr;
   164         break;
   165       case NS_MUTATION_EVENT:
   166         tmp->mEvent->AsMutationEvent()->mRelatedNode = nullptr;
   167         break;
   168       case NS_FOCUS_EVENT:
   169         tmp->mEvent->AsFocusEvent()->relatedTarget = nullptr;
   170         break;
   171       default:
   172         break;
   173     }
   174   }
   175   NS_IMPL_CYCLE_COLLECTION_UNLINK(mPresContext);
   176   NS_IMPL_CYCLE_COLLECTION_UNLINK(mExplicitOriginalTarget);
   177   NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner);
   178   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
   179 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
   181 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Event)
   182   if (tmp->mEventIsInternal) {
   183     NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->target)
   184     NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->currentTarget)
   185     NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvent->originalTarget)
   186     switch (tmp->mEvent->eventStructType) {
   187       case NS_MOUSE_EVENT:
   188       case NS_MOUSE_SCROLL_EVENT:
   189       case NS_WHEEL_EVENT:
   190       case NS_SIMPLE_GESTURE_EVENT:
   191       case NS_POINTER_EVENT:
   192         NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->relatedTarget");
   193         cb.NoteXPCOMChild(tmp->mEvent->AsMouseEventBase()->relatedTarget);
   194         break;
   195       case NS_DRAG_EVENT: {
   196         WidgetDragEvent* dragEvent = tmp->mEvent->AsDragEvent();
   197         NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->dataTransfer");
   198         cb.NoteXPCOMChild(dragEvent->dataTransfer);
   199         NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->relatedTarget");
   200         cb.NoteXPCOMChild(dragEvent->relatedTarget);
   201         break;
   202       }
   203       case NS_CLIPBOARD_EVENT:
   204         NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->clipboardData");
   205         cb.NoteXPCOMChild(tmp->mEvent->AsClipboardEvent()->clipboardData);
   206         break;
   207       case NS_MUTATION_EVENT:
   208         NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->mRelatedNode");
   209         cb.NoteXPCOMChild(tmp->mEvent->AsMutationEvent()->mRelatedNode);
   210         break;
   211       case NS_FOCUS_EVENT:
   212         NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mEvent->relatedTarget");
   213         cb.NoteXPCOMChild(tmp->mEvent->AsFocusEvent()->relatedTarget);
   214         break;
   215       default:
   216         break;
   217     }
   218   }
   219   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPresContext)
   220   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExplicitOriginalTarget)
   221   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
   222   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
   223 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
   225 bool
   226 Event::IsChrome(JSContext* aCx) const
   227 {
   228   return mIsMainThreadEvent ?
   229     xpc::AccessCheck::isChrome(js::GetContextCompartment(aCx)) :
   230     mozilla::dom::workers::IsCurrentThreadRunningChromeWorker();
   231 }
   233 // nsIDOMEventInterface
   234 NS_METHOD
   235 Event::GetType(nsAString& aType)
   236 {
   237   if (!mIsMainThreadEvent || !mEvent->typeString.IsEmpty()) {
   238     aType = mEvent->typeString;
   239     return NS_OK;
   240   }
   241   const char* name = GetEventName(mEvent->message);
   243   if (name) {
   244     CopyASCIItoUTF16(name, aType);
   245     return NS_OK;
   246   } else if (mEvent->message == NS_USER_DEFINED_EVENT && mEvent->userType) {
   247     aType = Substring(nsDependentAtomString(mEvent->userType), 2); // Remove "on"
   248     mEvent->typeString = aType;
   249     return NS_OK;
   250   }
   252   aType.Truncate();
   253   return NS_OK;
   254 }
   256 static EventTarget*
   257 GetDOMEventTarget(nsIDOMEventTarget* aTarget)
   258 {
   259   return aTarget ? aTarget->GetTargetForDOMEvent() : nullptr;
   260 }
   262 EventTarget*
   263 Event::GetTarget() const
   264 {
   265   return GetDOMEventTarget(mEvent->target);
   266 }
   268 NS_METHOD
   269 Event::GetTarget(nsIDOMEventTarget** aTarget)
   270 {
   271   NS_IF_ADDREF(*aTarget = GetTarget());
   272   return NS_OK;
   273 }
   275 EventTarget*
   276 Event::GetCurrentTarget() const
   277 {
   278   return GetDOMEventTarget(mEvent->currentTarget);
   279 }
   281 NS_IMETHODIMP
   282 Event::GetCurrentTarget(nsIDOMEventTarget** aCurrentTarget)
   283 {
   284   NS_IF_ADDREF(*aCurrentTarget = GetCurrentTarget());
   285   return NS_OK;
   286 }
   288 //
   289 // Get the actual event target node (may have been retargeted for mouse events)
   290 //
   291 already_AddRefed<nsIContent>
   292 Event::GetTargetFromFrame()
   293 {
   294   if (!mPresContext) { return nullptr; }
   296   // Get the target frame (have to get the ESM first)
   297   nsIFrame* targetFrame = mPresContext->EventStateManager()->GetEventTarget();
   298   if (!targetFrame) { return nullptr; }
   300   // get the real content
   301   nsCOMPtr<nsIContent> realEventContent;
   302   targetFrame->GetContentForEvent(mEvent, getter_AddRefs(realEventContent));
   303   return realEventContent.forget();
   304 }
   306 EventTarget*
   307 Event::GetExplicitOriginalTarget() const
   308 {
   309   if (mExplicitOriginalTarget) {
   310     return mExplicitOriginalTarget;
   311   }
   312   return GetTarget();
   313 }
   315 NS_IMETHODIMP
   316 Event::GetExplicitOriginalTarget(nsIDOMEventTarget** aRealEventTarget)
   317 {
   318   NS_IF_ADDREF(*aRealEventTarget = GetExplicitOriginalTarget());
   319   return NS_OK;
   320 }
   322 EventTarget*
   323 Event::GetOriginalTarget() const
   324 {
   325   if (mEvent->originalTarget) {
   326     return GetDOMEventTarget(mEvent->originalTarget);
   327   }
   329   return GetTarget();
   330 }
   332 NS_IMETHODIMP
   333 Event::GetOriginalTarget(nsIDOMEventTarget** aOriginalTarget)
   334 {
   335   NS_IF_ADDREF(*aOriginalTarget = GetOriginalTarget());
   336   return NS_OK;
   337 }
   339 NS_IMETHODIMP_(void)
   340 Event::SetTrusted(bool aTrusted)
   341 {
   342   mEvent->mFlags.mIsTrusted = aTrusted;
   343 }
   345 bool
   346 Event::Init(mozilla::dom::EventTarget* aGlobal)
   347 {
   348   if (!mIsMainThreadEvent) {
   349     return nsContentUtils::ThreadsafeIsCallerChrome();
   350   }
   351   bool trusted = false;
   352   nsCOMPtr<nsPIDOMWindow> w = do_QueryInterface(aGlobal);
   353   if (w) {
   354     nsCOMPtr<nsIDocument> d = w->GetExtantDoc();
   355     if (d) {
   356       trusted = nsContentUtils::IsChromeDoc(d);
   357       nsIPresShell* s = d->GetShell();
   358       if (s) {
   359         InitPresContextData(s->GetPresContext());
   360       }
   361     }
   362   }
   363   return trusted;
   364 }
   366 // static
   367 already_AddRefed<Event>
   368 Event::Constructor(const GlobalObject& aGlobal,
   369                    const nsAString& aType,
   370                    const EventInit& aParam,
   371                    ErrorResult& aRv)
   372 {
   373   nsCOMPtr<mozilla::dom::EventTarget> t = do_QueryInterface(aGlobal.GetAsSupports());
   374   nsRefPtr<Event> e = new Event(t, nullptr, nullptr);
   375   bool trusted = e->Init(t);
   376   aRv = e->InitEvent(aType, aParam.mBubbles, aParam.mCancelable);
   377   e->SetTrusted(trusted);
   378   return e.forget();
   379 }
   381 uint16_t
   382 Event::EventPhase() const
   383 {
   384   // Note, remember to check that this works also
   385   // if or when Bug 235441 is fixed.
   386   if ((mEvent->currentTarget &&
   387        mEvent->currentTarget == mEvent->target) ||
   388        mEvent->mFlags.InTargetPhase()) {
   389     return nsIDOMEvent::AT_TARGET;
   390   }
   391   if (mEvent->mFlags.mInCapturePhase) {
   392     return nsIDOMEvent::CAPTURING_PHASE;
   393   }
   394   if (mEvent->mFlags.mInBubblingPhase) {
   395     return nsIDOMEvent::BUBBLING_PHASE;
   396   }
   397   return nsIDOMEvent::NONE;
   398 }
   400 NS_IMETHODIMP
   401 Event::GetEventPhase(uint16_t* aEventPhase)
   402 {
   403   *aEventPhase = EventPhase();
   404   return NS_OK;
   405 }
   407 NS_IMETHODIMP
   408 Event::GetBubbles(bool* aBubbles)
   409 {
   410   *aBubbles = Bubbles();
   411   return NS_OK;
   412 }
   414 NS_IMETHODIMP
   415 Event::GetCancelable(bool* aCancelable)
   416 {
   417   *aCancelable = Cancelable();
   418   return NS_OK;
   419 }
   421 NS_IMETHODIMP
   422 Event::GetTimeStamp(uint64_t* aTimeStamp)
   423 {
   424   *aTimeStamp = TimeStamp();
   425   return NS_OK;
   426 }
   428 NS_IMETHODIMP
   429 Event::StopPropagation()
   430 {
   431   mEvent->mFlags.mPropagationStopped = true;
   432   return NS_OK;
   433 }
   435 NS_IMETHODIMP
   436 Event::StopImmediatePropagation()
   437 {
   438   mEvent->mFlags.mPropagationStopped = true;
   439   mEvent->mFlags.mImmediatePropagationStopped = true;
   440   return NS_OK;
   441 }
   443 NS_IMETHODIMP
   444 Event::GetIsTrusted(bool* aIsTrusted)
   445 {
   446   *aIsTrusted = IsTrusted();
   447   return NS_OK;
   448 }
   450 NS_IMETHODIMP
   451 Event::PreventDefault()
   452 {
   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   return NS_OK;
   457 }
   459 void
   460 Event::PreventDefault(JSContext* aCx)
   461 {
   462   MOZ_ASSERT(aCx, "JS context must be specified");
   464   // Note that at handling default action, another event may be dispatched.
   465   // Then, JS in content mey be call preventDefault()
   466   // even in the event is in system event group.  Therefore, don't refer
   467   // mInSystemGroup here.
   468   PreventDefaultInternal(IsChrome(aCx));
   469 }
   471 void
   472 Event::PreventDefaultInternal(bool aCalledByDefaultHandler)
   473 {
   474   if (!mEvent->mFlags.mCancelable) {
   475     return;
   476   }
   478   mEvent->mFlags.mDefaultPrevented = true;
   480   // Note that even if preventDefault() has already been called by chrome,
   481   // a call of preventDefault() by content needs to overwrite
   482   // mDefaultPreventedByContent to true because in such case, defaultPrevented
   483   // must be true when web apps check it after they call preventDefault().
   484   if (!aCalledByDefaultHandler) {
   485     mEvent->mFlags.mDefaultPreventedByContent = true;
   486   }
   488   if (!IsTrusted()) {
   489     return;
   490   }
   492   WidgetDragEvent* dragEvent = mEvent->AsDragEvent();
   493   if (!dragEvent) {
   494     return;
   495   }
   497   nsCOMPtr<nsINode> node = do_QueryInterface(mEvent->currentTarget);
   498   if (!node) {
   499     nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(mEvent->currentTarget);
   500     if (!win) {
   501       return;
   502     }
   503     node = win->GetExtantDoc();
   504   }
   505   if (!nsContentUtils::IsChromeDoc(node->OwnerDoc())) {
   506     dragEvent->mDefaultPreventedOnContent = true;
   507   }
   508 }
   510 void
   511 Event::SetEventType(const nsAString& aEventTypeArg)
   512 {
   513   if (mIsMainThreadEvent) {
   514     mEvent->userType =
   515       nsContentUtils::GetEventIdAndAtom(aEventTypeArg, mEvent->eventStructType,
   516                                         &(mEvent->message));
   517   } else {
   518     mEvent->userType = nullptr;
   519     mEvent->message = NS_USER_DEFINED_EVENT;
   520     mEvent->typeString = aEventTypeArg;
   521   }
   522 }
   524 NS_IMETHODIMP
   525 Event::InitEvent(const nsAString& aEventTypeArg,
   526                  bool aCanBubbleArg,
   527                  bool aCancelableArg)
   528 {
   529   // Make sure this event isn't already being dispatched.
   530   NS_ENSURE_TRUE(!mEvent->mFlags.mIsBeingDispatched, NS_OK);
   532   if (IsTrusted()) {
   533     // Ensure the caller is permitted to dispatch trusted DOM events.
   534     if (!nsContentUtils::ThreadsafeIsCallerChrome()) {
   535       SetTrusted(false);
   536     }
   537   }
   539   SetEventType(aEventTypeArg);
   541   mEvent->mFlags.mBubbles = aCanBubbleArg;
   542   mEvent->mFlags.mCancelable = aCancelableArg;
   544   mEvent->mFlags.mDefaultPrevented = false;
   546   // Clearing the old targets, so that the event is targeted correctly when
   547   // re-dispatching it.
   548   mEvent->target = nullptr;
   549   mEvent->originalTarget = nullptr;
   550   return NS_OK;
   551 }
   553 NS_IMETHODIMP
   554 Event::DuplicatePrivateData()
   555 {
   556   NS_ASSERTION(mEvent, "No WidgetEvent for Event duplication!");
   557   if (mEventIsInternal) {
   558     return NS_OK;
   559   }
   561   mEvent = mEvent->Duplicate();
   562   mPresContext = nullptr;
   563   mEventIsInternal = true;
   564   mPrivateDataDuplicated = true;
   566   return NS_OK;
   567 }
   569 NS_IMETHODIMP
   570 Event::SetTarget(nsIDOMEventTarget* aTarget)
   571 {
   572 #ifdef DEBUG
   573   {
   574     nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(aTarget);
   576     NS_ASSERTION(!win || !win->IsInnerWindow(),
   577                  "Uh, inner window set as event target!");
   578   }
   579 #endif
   581   mEvent->target = do_QueryInterface(aTarget);
   582   return NS_OK;
   583 }
   585 NS_IMETHODIMP_(bool)
   586 Event::IsDispatchStopped()
   587 {
   588   return mEvent->mFlags.mPropagationStopped;
   589 }
   591 NS_IMETHODIMP_(WidgetEvent*)
   592 Event::GetInternalNSEvent()
   593 {
   594   return mEvent;
   595 }
   597 NS_IMETHODIMP_(Event*)
   598 Event::InternalDOMEvent()
   599 {
   600   return this;
   601 }
   603 // return true if eventName is contained within events, delimited by
   604 // spaces
   605 static bool
   606 PopupAllowedForEvent(const char *eventName)
   607 {
   608   if (!sPopupAllowedEvents) {
   609     Event::PopupAllowedEventsChanged();
   611     if (!sPopupAllowedEvents) {
   612       return false;
   613     }
   614   }
   616   nsDependentCString events(sPopupAllowedEvents);
   618   nsAFlatCString::const_iterator start, end;
   619   nsAFlatCString::const_iterator startiter(events.BeginReading(start));
   620   events.EndReading(end);
   622   while (startiter != end) {
   623     nsAFlatCString::const_iterator enditer(end);
   625     if (!FindInReadable(nsDependentCString(eventName), startiter, enditer))
   626       return false;
   628     // the match is surrounded by spaces, or at a string boundary
   629     if ((startiter == start || *--startiter == ' ') &&
   630         (enditer == end || *enditer == ' ')) {
   631       return true;
   632     }
   634     // Move on and see if there are other matches. (The delimitation
   635     // requirement makes it pointless to begin the next search before
   636     // the end of the invalid match just found.)
   637     startiter = enditer;
   638   }
   640   return false;
   641 }
   643 // static
   644 PopupControlState
   645 Event::GetEventPopupControlState(WidgetEvent* aEvent)
   646 {
   647   // generally if an event handler is running, new windows are disallowed.
   648   // check for exceptions:
   649   PopupControlState abuse = openAbused;
   651   switch(aEvent->eventStructType) {
   652   case NS_EVENT :
   653     // For these following events only allow popups if they're
   654     // triggered while handling user input. See
   655     // nsPresShell::HandleEventInternal() for details.
   656     if (EventStateManager::IsHandlingUserInput()) {
   657       switch(aEvent->message) {
   658       case NS_FORM_SELECTED :
   659         if (PopupAllowedForEvent("select")) {
   660           abuse = openControlled;
   661         }
   662         break;
   663       case NS_FORM_CHANGE :
   664         if (PopupAllowedForEvent("change")) {
   665           abuse = openControlled;
   666         }
   667         break;
   668       }
   669     }
   670     break;
   671   case NS_EDITOR_INPUT_EVENT :
   672     // For this following event only allow popups if it's triggered
   673     // while handling user input. See
   674     // nsPresShell::HandleEventInternal() for details.
   675     if (EventStateManager::IsHandlingUserInput()) {
   676       switch(aEvent->message) {
   677       case NS_EDITOR_INPUT:
   678         if (PopupAllowedForEvent("input")) {
   679           abuse = openControlled;
   680         }
   681         break;
   682       }
   683     }
   684     break;
   685   case NS_INPUT_EVENT :
   686     // For this following event only allow popups if it's triggered
   687     // while handling user input. See
   688     // nsPresShell::HandleEventInternal() for details.
   689     if (EventStateManager::IsHandlingUserInput()) {
   690       switch(aEvent->message) {
   691       case NS_FORM_CHANGE :
   692         if (PopupAllowedForEvent("change")) {
   693           abuse = openControlled;
   694         }
   695         break;
   696       case NS_XUL_COMMAND:
   697         abuse = openControlled;
   698         break;
   699       }
   700     }
   701     break;
   702   case NS_KEY_EVENT :
   703     if (aEvent->mFlags.mIsTrusted) {
   704       uint32_t key = aEvent->AsKeyboardEvent()->keyCode;
   705       switch(aEvent->message) {
   706       case NS_KEY_PRESS :
   707         // return key on focused button. see note at NS_MOUSE_CLICK.
   708         if (key == nsIDOMKeyEvent::DOM_VK_RETURN) {
   709           abuse = openAllowed;
   710         } else if (PopupAllowedForEvent("keypress")) {
   711           abuse = openControlled;
   712         }
   713         break;
   714       case NS_KEY_UP :
   715         // space key on focused button. see note at NS_MOUSE_CLICK.
   716         if (key == nsIDOMKeyEvent::DOM_VK_SPACE) {
   717           abuse = openAllowed;
   718         } else if (PopupAllowedForEvent("keyup")) {
   719           abuse = openControlled;
   720         }
   721         break;
   722       case NS_KEY_DOWN :
   723         if (PopupAllowedForEvent("keydown")) {
   724           abuse = openControlled;
   725         }
   726         break;
   727       }
   728     }
   729     break;
   730   case NS_TOUCH_EVENT :
   731     if (aEvent->mFlags.mIsTrusted) {
   732       switch (aEvent->message) {
   733       case NS_TOUCH_START :
   734         if (PopupAllowedForEvent("touchstart")) {
   735           abuse = openControlled;
   736         }
   737         break;
   738       case NS_TOUCH_END :
   739         if (PopupAllowedForEvent("touchend")) {
   740           abuse = openControlled;
   741         }
   742         break;
   743       }
   744     }
   745     break;
   746   case NS_MOUSE_EVENT :
   747     if (aEvent->mFlags.mIsTrusted &&
   748         aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton) {
   749       switch(aEvent->message) {
   750       case NS_MOUSE_BUTTON_UP :
   751         if (PopupAllowedForEvent("mouseup")) {
   752           abuse = openControlled;
   753         }
   754         break;
   755       case NS_MOUSE_BUTTON_DOWN :
   756         if (PopupAllowedForEvent("mousedown")) {
   757           abuse = openControlled;
   758         }
   759         break;
   760       case NS_MOUSE_CLICK :
   761         /* Click events get special treatment because of their
   762            historical status as a more legitimate event handler. If
   763            click popups are enabled in the prefs, clear the popup
   764            status completely. */
   765         if (PopupAllowedForEvent("click")) {
   766           abuse = openAllowed;
   767         }
   768         break;
   769       case NS_MOUSE_DOUBLECLICK :
   770         if (PopupAllowedForEvent("dblclick")) {
   771           abuse = openControlled;
   772         }
   773         break;
   774       }
   775     }
   776     break;
   777   case NS_FORM_EVENT :
   778     // For these following events only allow popups if they're
   779     // triggered while handling user input. See
   780     // nsPresShell::HandleEventInternal() for details.
   781     if (EventStateManager::IsHandlingUserInput()) {
   782       switch(aEvent->message) {
   783       case NS_FORM_SUBMIT :
   784         if (PopupAllowedForEvent("submit")) {
   785           abuse = openControlled;
   786         }
   787         break;
   788       case NS_FORM_RESET :
   789         if (PopupAllowedForEvent("reset")) {
   790           abuse = openControlled;
   791         }
   792         break;
   793       }
   794     }
   795     break;
   796   default:
   797     break;
   798   }
   800   return abuse;
   801 }
   803 // static
   804 void
   805 Event::PopupAllowedEventsChanged()
   806 {
   807   if (sPopupAllowedEvents) {
   808     nsMemory::Free(sPopupAllowedEvents);
   809   }
   811   nsAdoptingCString str = Preferences::GetCString("dom.popup_allowed_events");
   813   // We'll want to do this even if str is empty to avoid looking up
   814   // this pref all the time if it's not set.
   815   sPopupAllowedEvents = ToNewCString(str);
   816 }
   818 // static
   819 void
   820 Event::Shutdown()
   821 {
   822   if (sPopupAllowedEvents) {
   823     nsMemory::Free(sPopupAllowedEvents);
   824   }
   825 }
   827 nsIntPoint
   828 Event::GetScreenCoords(nsPresContext* aPresContext,
   829                        WidgetEvent* aEvent,
   830                        LayoutDeviceIntPoint aPoint)
   831 {
   832   if (!nsContentUtils::IsCallerChrome()) {
   833     // For non-chrome callers, return client coordinates instead.
   834     // For some events, the result will be zero; specifically, for dragend
   835     // events (there is no widget associated with dragend events, which
   836     // causes GetClientX() to return zero).  Since dragend is for the drag
   837     // originator and not for the receiver, it is probably not widely used
   838     // (receivers get a drop event).  Therefore, returning 0 should not break
   839     // many web pages.  Also, a few years ago Firefox returned 0.
   840     // See:  https://bugzilla.mozilla.org/show_bug.cgi?id=466379
   841     CSSIntPoint clientCoords = GetClientCoords(aPresContext, aEvent, aPoint, CSSIntPoint(0, 0));
   842     return nsIntPoint(clientCoords.x, clientCoords.y);
   843   }
   845   if (EventStateManager::sIsPointerLocked) {
   846     return EventStateManager::sLastScreenPoint;
   847   }
   849   if (!aEvent || 
   850        (aEvent->eventStructType != NS_MOUSE_EVENT &&
   851         aEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
   852         aEvent->eventStructType != NS_WHEEL_EVENT &&
   853         aEvent->eventStructType != NS_POINTER_EVENT &&
   854         aEvent->eventStructType != NS_TOUCH_EVENT &&
   855         aEvent->eventStructType != NS_DRAG_EVENT &&
   856         aEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT)) {
   857     return nsIntPoint(0, 0);
   858   }
   860   WidgetGUIEvent* guiEvent = aEvent->AsGUIEvent();
   861   if (!guiEvent->widget) {
   862     return LayoutDeviceIntPoint::ToUntyped(aPoint);
   863   }
   865   LayoutDeviceIntPoint offset = aPoint +
   866     LayoutDeviceIntPoint::FromUntyped(guiEvent->widget->WidgetToScreenOffset());
   867   nscoord factor = aPresContext->DeviceContext()->UnscaledAppUnitsPerDevPixel();
   868   return nsIntPoint(nsPresContext::AppUnitsToIntCSSPixels(offset.x * factor),
   869                     nsPresContext::AppUnitsToIntCSSPixels(offset.y * factor));
   870 }
   872 // static
   873 CSSIntPoint
   874 Event::GetPageCoords(nsPresContext* aPresContext,
   875                      WidgetEvent* aEvent,
   876                      LayoutDeviceIntPoint aPoint,
   877                      CSSIntPoint aDefaultPoint)
   878 {
   879   CSSIntPoint pagePoint =
   880     Event::GetClientCoords(aPresContext, aEvent, aPoint, aDefaultPoint);
   882   // If there is some scrolling, add scroll info to client point.
   883   if (aPresContext && aPresContext->GetPresShell()) {
   884     nsIPresShell* shell = aPresContext->GetPresShell();
   885     nsIScrollableFrame* scrollframe = shell->GetRootScrollFrameAsScrollable();
   886     if (scrollframe) {
   887       pagePoint += CSSIntPoint::FromAppUnitsRounded(scrollframe->GetScrollPosition());
   888     }
   889   }
   891   return pagePoint;
   892 }
   894 // static
   895 CSSIntPoint
   896 Event::GetClientCoords(nsPresContext* aPresContext,
   897                        WidgetEvent* aEvent,
   898                        LayoutDeviceIntPoint aPoint,
   899                        CSSIntPoint aDefaultPoint)
   900 {
   901   if (EventStateManager::sIsPointerLocked) {
   902     return EventStateManager::sLastClientPoint;
   903   }
   905   if (!aEvent ||
   906       (aEvent->eventStructType != NS_MOUSE_EVENT &&
   907        aEvent->eventStructType != NS_MOUSE_SCROLL_EVENT &&
   908        aEvent->eventStructType != NS_WHEEL_EVENT &&
   909        aEvent->eventStructType != NS_TOUCH_EVENT &&
   910        aEvent->eventStructType != NS_DRAG_EVENT &&
   911        aEvent->eventStructType != NS_POINTER_EVENT &&
   912        aEvent->eventStructType != NS_SIMPLE_GESTURE_EVENT) ||
   913       !aPresContext ||
   914       !aEvent->AsGUIEvent()->widget) {
   915     return aDefaultPoint;
   916   }
   918   nsIPresShell* shell = aPresContext->GetPresShell();
   919   if (!shell) {
   920     return CSSIntPoint(0, 0);
   921   }
   923   nsIFrame* rootFrame = shell->GetRootFrame();
   924   if (!rootFrame) {
   925     return CSSIntPoint(0, 0);
   926   }
   927   nsPoint pt =
   928     nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent,
   929       LayoutDeviceIntPoint::ToUntyped(aPoint), rootFrame);
   931   return CSSIntPoint::FromAppUnitsRounded(pt);
   932 }
   934 // To be called ONLY by Event::GetType (which has the additional
   935 // logic for handling user-defined events).
   936 // static
   937 const char*
   938 Event::GetEventName(uint32_t aEventType)
   939 {
   940   switch(aEventType) {
   941 #define ID_TO_EVENT(name_, _id, _type, _struct) \
   942   case _id: return #name_;
   943 #include "mozilla/EventNameList.h"
   944 #undef ID_TO_EVENT
   945   default:
   946     break;
   947   }
   948   // XXXldb We can hit this case for WidgetEvent objects that we didn't
   949   // create and that are not user defined events since this function and
   950   // SetEventType are incomplete.  (But fixing that requires fixing the
   951   // arrays in nsEventListenerManager too, since the events for which
   952   // this is a problem generally *are* created by Event.)
   953   return nullptr;
   954 }
   956 bool
   957 Event::DefaultPrevented(JSContext* aCx) const
   958 {
   959   MOZ_ASSERT(aCx, "JS context must be specified");
   961   NS_ENSURE_TRUE(mEvent, false);
   963   // If preventDefault() has never been called, just return false.
   964   if (!mEvent->mFlags.mDefaultPrevented) {
   965     return false;
   966   }
   968   // If preventDefault() has been called by content, return true.  Otherwise,
   969   // i.e., preventDefault() has been called by chrome, return true only when
   970   // this is called by chrome.
   971   return mEvent->mFlags.mDefaultPreventedByContent || IsChrome(aCx);
   972 }
   974 bool
   975 Event::GetPreventDefault() const
   976 {
   977   if (mOwner) {
   978     if (nsIDocument* doc = mOwner->GetExtantDoc()) {
   979       doc->WarnOnceAbout(nsIDocument::eGetPreventDefault);
   980     }
   981   }
   982   // GetPreventDefault() is legacy and Gecko specific method.  Although,
   983   // the result should be same as defaultPrevented, we don't need to break
   984   // backward compatibility of legacy method.  Let's behave traditionally.
   985   return DefaultPrevented();
   986 }
   988 NS_IMETHODIMP
   989 Event::GetPreventDefault(bool* aReturn)
   990 {
   991   NS_ENSURE_ARG_POINTER(aReturn);
   992   *aReturn = GetPreventDefault();
   993   return NS_OK;
   994 }
   996 NS_IMETHODIMP
   997 Event::GetDefaultPrevented(bool* aReturn)
   998 {
   999   NS_ENSURE_ARG_POINTER(aReturn);
  1000   // This method must be called by only event handlers implemented by C++.
  1001   // Then, the handlers must handle default action.  So, this method don't need
  1002   // to check if preventDefault() has been called by content or chrome.
  1003   *aReturn = DefaultPrevented();
  1004   return NS_OK;
  1007 NS_IMETHODIMP_(void)
  1008 Event::Serialize(IPC::Message* aMsg, bool aSerializeInterfaceType)
  1010   if (aSerializeInterfaceType) {
  1011     IPC::WriteParam(aMsg, NS_LITERAL_STRING("event"));
  1014   nsString type;
  1015   GetType(type);
  1016   IPC::WriteParam(aMsg, type);
  1018   IPC::WriteParam(aMsg, Bubbles());
  1019   IPC::WriteParam(aMsg, Cancelable());
  1020   IPC::WriteParam(aMsg, IsTrusted());
  1022   // No timestamp serialization for now!
  1025 NS_IMETHODIMP_(bool)
  1026 Event::Deserialize(const IPC::Message* aMsg, void** aIter)
  1028   nsString type;
  1029   NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &type), false);
  1031   bool bubbles = false;
  1032   NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &bubbles), false);
  1034   bool cancelable = false;
  1035   NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &cancelable), false);
  1037   bool trusted = false;
  1038   NS_ENSURE_TRUE(IPC::ReadParam(aMsg, aIter, &trusted), false);
  1040   nsresult rv = InitEvent(type, bubbles, cancelable);
  1041   NS_ENSURE_SUCCESS(rv, false);
  1042   SetTrusted(trusted);
  1044   return true;
  1047 NS_IMETHODIMP_(void)
  1048 Event::SetOwner(mozilla::dom::EventTarget* aOwner)
  1050   mOwner = nullptr;
  1052   if (!aOwner) {
  1053     return;
  1056   nsCOMPtr<nsINode> n = do_QueryInterface(aOwner);
  1057   if (n) {
  1058     mOwner = do_QueryInterface(n->OwnerDoc()->GetScopeObject());
  1059     return;
  1062   nsCOMPtr<nsPIDOMWindow> w = do_QueryInterface(aOwner);
  1063   if (w) {
  1064     if (w->IsOuterWindow()) {
  1065       mOwner = w->GetCurrentInnerWindow();
  1066     } else {
  1067       mOwner.swap(w);
  1069     return;
  1072   nsCOMPtr<DOMEventTargetHelper> eth = do_QueryInterface(aOwner);
  1073   if (eth) {
  1074     mOwner = eth->GetOwner();
  1075     return;
  1078 #ifdef DEBUG
  1079   nsCOMPtr<nsPIWindowRoot> root = do_QueryInterface(aOwner);
  1080   MOZ_ASSERT(root, "Unexpected EventTarget!");
  1081 #endif
  1084 } // namespace dom
  1085 } // namespace mozilla
  1087 using namespace mozilla;
  1088 using namespace mozilla::dom;
  1090 nsresult
  1091 NS_NewDOMEvent(nsIDOMEvent** aInstancePtrResult,
  1092                EventTarget* aOwner,
  1093                nsPresContext* aPresContext,
  1094                WidgetEvent* aEvent) 
  1096   Event* it = new Event(aOwner, aPresContext, aEvent);
  1097   NS_ADDREF(it);
  1098   *aInstancePtrResult = static_cast<Event*>(it);
  1099   return NS_OK;

mercurial