dom/events/DOMEventTargetHelper.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 "nsContentUtils.h"
     7 #include "nsIDocument.h"
     8 #include "prprf.h"
     9 #include "nsGlobalWindow.h"
    10 #include "ScriptSettings.h"
    11 #include "mozilla/DOMEventTargetHelper.h"
    12 #include "mozilla/EventDispatcher.h"
    13 #include "mozilla/EventListenerManager.h"
    14 #include "mozilla/Likely.h"
    16 namespace mozilla {
    18 using namespace dom;
    20 NS_IMPL_CYCLE_COLLECTION_CLASS(DOMEventTargetHelper)
    22 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(DOMEventTargetHelper)
    23   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
    24 NS_IMPL_CYCLE_COLLECTION_TRACE_END
    26 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(DOMEventTargetHelper)
    27   if (MOZ_UNLIKELY(cb.WantDebugInfo())) {
    28     char name[512];
    29     nsAutoString uri;
    30     if (tmp->mOwnerWindow && tmp->mOwnerWindow->GetExtantDoc()) {
    31       tmp->mOwnerWindow->GetExtantDoc()->GetDocumentURI(uri);
    32     }
    33     PR_snprintf(name, sizeof(name), "DOMEventTargetHelper %s",
    34                 NS_ConvertUTF16toUTF8(uri).get());
    35     cb.DescribeRefCountedNode(tmp->mRefCnt.get(), name);
    36   } else {
    37     NS_IMPL_CYCLE_COLLECTION_DESCRIBE(DOMEventTargetHelper, tmp->mRefCnt.get())
    38   }
    40   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
    41   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListenerManager)
    42 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    44 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMEventTargetHelper)
    45   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
    46   NS_IMPL_CYCLE_COLLECTION_UNLINK(mListenerManager)
    47 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    49 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(DOMEventTargetHelper)
    50   if (tmp->IsBlack()) {
    51     if (tmp->mListenerManager) {
    52       tmp->mListenerManager->MarkForCC();
    53     }
    54     return true;
    55   }
    56 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
    58 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(DOMEventTargetHelper)
    59   return tmp->IsBlackAndDoesNotNeedTracing(tmp);
    60 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
    62 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(DOMEventTargetHelper)
    63   return tmp->IsBlack();
    64 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
    66 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMEventTargetHelper)
    67   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
    68   NS_INTERFACE_MAP_ENTRY(nsISupports)
    69   NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
    70   NS_INTERFACE_MAP_ENTRY(dom::EventTarget)
    71   NS_INTERFACE_MAP_ENTRY(DOMEventTargetHelper)
    72 NS_INTERFACE_MAP_END
    74 NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMEventTargetHelper)
    75 NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(DOMEventTargetHelper,
    76                                                    LastRelease())
    78 NS_IMPL_DOMTARGET_DEFAULTS(DOMEventTargetHelper)
    80 DOMEventTargetHelper::~DOMEventTargetHelper()
    81 {
    82   if (nsPIDOMWindow* owner = GetOwner()) {
    83     static_cast<nsGlobalWindow*>(owner)->RemoveEventTargetObject(this);
    84   }
    85   if (mListenerManager) {
    86     mListenerManager->Disconnect();
    87   }
    88   ReleaseWrapper(this);
    89 }
    91 void
    92 DOMEventTargetHelper::BindToOwner(nsPIDOMWindow* aOwner)
    93 {
    94   MOZ_ASSERT(!aOwner || aOwner->IsInnerWindow());
    95   nsCOMPtr<nsIGlobalObject> glob = do_QueryInterface(aOwner);
    96   BindToOwner(glob);
    97 }
    99 void
   100 DOMEventTargetHelper::BindToOwner(nsIGlobalObject* aOwner)
   101 {
   102   if (mParentObject) {
   103     if (mOwnerWindow) {
   104       static_cast<nsGlobalWindow*>(mOwnerWindow)->RemoveEventTargetObject(this);
   105       mOwnerWindow = nullptr;
   106     }
   107     mParentObject = nullptr;
   108     mHasOrHasHadOwnerWindow = false;
   109   }
   110   if (aOwner) {
   111     mParentObject = aOwner;
   112     // Let's cache the result of this QI for fast access and off main thread usage
   113     mOwnerWindow = nsCOMPtr<nsPIDOMWindow>(do_QueryInterface(aOwner)).get();
   114     if (mOwnerWindow) {
   115       mHasOrHasHadOwnerWindow = true;
   116       static_cast<nsGlobalWindow*>(mOwnerWindow)->AddEventTargetObject(this);
   117     }
   118   }
   119 }
   121 void
   122 DOMEventTargetHelper::BindToOwner(DOMEventTargetHelper* aOther)
   123 {
   124   if (mOwnerWindow) {
   125     static_cast<nsGlobalWindow*>(mOwnerWindow)->RemoveEventTargetObject(this);
   126     mOwnerWindow = nullptr;
   127     mParentObject = nullptr;
   128     mHasOrHasHadOwnerWindow = false;
   129   }
   130   if (aOther) {
   131     mHasOrHasHadOwnerWindow = aOther->HasOrHasHadOwner();
   132     if (aOther->GetParentObject()) {
   133       mParentObject = aOther->GetParentObject();
   134       // Let's cache the result of this QI for fast access and off main thread usage
   135       mOwnerWindow = nsCOMPtr<nsPIDOMWindow>(do_QueryInterface(mParentObject)).get();
   136       if (mOwnerWindow) {
   137         mHasOrHasHadOwnerWindow = true;
   138         static_cast<nsGlobalWindow*>(mOwnerWindow)->AddEventTargetObject(this);
   139       }
   140     }
   141   }
   142 }
   144 void
   145 DOMEventTargetHelper::DisconnectFromOwner()
   146 {
   147   mOwnerWindow = nullptr;
   148   mParentObject = nullptr;
   149   // Event listeners can't be handled anymore, so we can release them here.
   150   if (mListenerManager) {
   151     mListenerManager->Disconnect();
   152     mListenerManager = nullptr;
   153   }
   154 }
   156 NS_IMETHODIMP
   157 DOMEventTargetHelper::RemoveEventListener(const nsAString& aType,
   158                                           nsIDOMEventListener* aListener,
   159                                           bool aUseCapture)
   160 {
   161   EventListenerManager* elm = GetExistingListenerManager();
   162   if (elm) {
   163     elm->RemoveEventListener(aType, aListener, aUseCapture);
   164   }
   166   return NS_OK;
   167 }
   169 NS_IMPL_REMOVE_SYSTEM_EVENT_LISTENER(DOMEventTargetHelper)
   171 NS_IMETHODIMP
   172 DOMEventTargetHelper::AddEventListener(const nsAString& aType,
   173                                        nsIDOMEventListener* aListener,
   174                                        bool aUseCapture,
   175                                        bool aWantsUntrusted,
   176                                        uint8_t aOptionalArgc)
   177 {
   178   NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1,
   179                "Won't check if this is chrome, you want to set "
   180                "aWantsUntrusted to false or make the aWantsUntrusted "
   181                "explicit by making aOptionalArgc non-zero.");
   183   if (aOptionalArgc < 2) {
   184     nsresult rv = WantsUntrusted(&aWantsUntrusted);
   185     NS_ENSURE_SUCCESS(rv, rv);
   186   }
   188   EventListenerManager* elm = GetOrCreateListenerManager();
   189   NS_ENSURE_STATE(elm);
   190   elm->AddEventListener(aType, aListener, aUseCapture, aWantsUntrusted);
   191   return NS_OK;
   192 }
   194 void
   195 DOMEventTargetHelper::AddEventListener(const nsAString& aType,
   196                                        EventListener* aListener,
   197                                        bool aUseCapture,
   198                                        const Nullable<bool>& aWantsUntrusted,
   199                                        ErrorResult& aRv)
   200 {
   201   bool wantsUntrusted;
   202   if (aWantsUntrusted.IsNull()) {
   203     nsresult rv = WantsUntrusted(&wantsUntrusted);
   204     if (NS_FAILED(rv)) {
   205       aRv.Throw(rv);
   206       return;
   207     }
   208   } else {
   209     wantsUntrusted = aWantsUntrusted.Value();
   210   }
   212   EventListenerManager* elm = GetOrCreateListenerManager();
   213   if (!elm) {
   214     aRv.Throw(NS_ERROR_UNEXPECTED);
   215     return;
   216   }
   217   elm->AddEventListener(aType, aListener, aUseCapture, wantsUntrusted);
   218 }
   220 NS_IMETHODIMP
   221 DOMEventTargetHelper::AddSystemEventListener(const nsAString& aType,
   222                                              nsIDOMEventListener* aListener,
   223                                              bool aUseCapture,
   224                                              bool aWantsUntrusted,
   225                                              uint8_t aOptionalArgc)
   226 {
   227   NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1,
   228                "Won't check if this is chrome, you want to set "
   229                "aWantsUntrusted to false or make the aWantsUntrusted "
   230                "explicit by making aOptionalArgc non-zero.");
   232   if (aOptionalArgc < 2) {
   233     nsresult rv = WantsUntrusted(&aWantsUntrusted);
   234     NS_ENSURE_SUCCESS(rv, rv);
   235   }
   237   return NS_AddSystemEventListener(this, aType, aListener, aUseCapture,
   238                                    aWantsUntrusted);
   239 }
   241 NS_IMETHODIMP
   242 DOMEventTargetHelper::DispatchEvent(nsIDOMEvent* aEvent, bool* aRetVal)
   243 {
   244   nsEventStatus status = nsEventStatus_eIgnore;
   245   nsresult rv =
   246     EventDispatcher::DispatchDOMEvent(this, nullptr, aEvent, nullptr, &status);
   248   *aRetVal = (status != nsEventStatus_eConsumeNoDefault);
   249   return rv;
   250 }
   252 nsresult
   253 DOMEventTargetHelper::DispatchTrustedEvent(const nsAString& aEventName)
   254 {
   255   nsCOMPtr<nsIDOMEvent> event;
   256   NS_NewDOMEvent(getter_AddRefs(event), this, nullptr, nullptr);
   257   nsresult rv = event->InitEvent(aEventName, false, false);
   258   NS_ENSURE_SUCCESS(rv, rv);
   260   return DispatchTrustedEvent(event);
   261 }
   263 nsresult
   264 DOMEventTargetHelper::DispatchTrustedEvent(nsIDOMEvent* event)
   265 {
   266   event->SetTrusted(true);
   268   bool dummy;
   269   return DispatchEvent(event, &dummy);
   270 }
   272 nsresult
   273 DOMEventTargetHelper::SetEventHandler(nsIAtom* aType,
   274                                       JSContext* aCx,
   275                                       const JS::Value& aValue)
   276 {
   277   nsRefPtr<EventHandlerNonNull> handler;
   278   JS::Rooted<JSObject*> callable(aCx);
   279   if (aValue.isObject() &&
   280       JS_ObjectIsCallable(aCx, callable = &aValue.toObject())) {
   281     handler = new EventHandlerNonNull(callable, dom::GetIncumbentGlobal());
   282   }
   283   SetEventHandler(aType, EmptyString(), handler);
   284   return NS_OK;
   285 }
   287 void
   288 DOMEventTargetHelper::GetEventHandler(nsIAtom* aType,
   289                                       JSContext* aCx,
   290                                       JS::Value* aValue)
   291 {
   292   EventHandlerNonNull* handler = GetEventHandler(aType, EmptyString());
   293   if (handler) {
   294     *aValue = JS::ObjectValue(*handler->Callable());
   295   } else {
   296     *aValue = JS::NullValue();
   297   }
   298 }
   300 nsresult
   301 DOMEventTargetHelper::PreHandleEvent(EventChainPreVisitor& aVisitor)
   302 {
   303   aVisitor.mCanHandle = true;
   304   aVisitor.mParentTarget = nullptr;
   305   return NS_OK;
   306 }
   308 nsresult
   309 DOMEventTargetHelper::PostHandleEvent(EventChainPostVisitor& aVisitor)
   310 {
   311   return NS_OK;
   312 }
   314 nsresult
   315 DOMEventTargetHelper::DispatchDOMEvent(WidgetEvent* aEvent,
   316                                        nsIDOMEvent* aDOMEvent,
   317                                        nsPresContext* aPresContext,
   318                                        nsEventStatus* aEventStatus)
   319 {
   320   return EventDispatcher::DispatchDOMEvent(this, aEvent, aDOMEvent,
   321                                            aPresContext, aEventStatus);
   322 }
   324 EventListenerManager*
   325 DOMEventTargetHelper::GetOrCreateListenerManager()
   326 {
   327   if (!mListenerManager) {
   328     mListenerManager = new EventListenerManager(this);
   329   }
   331   return mListenerManager;
   332 }
   334 EventListenerManager*
   335 DOMEventTargetHelper::GetExistingListenerManager() const
   336 {
   337   return mListenerManager;
   338 }
   340 nsIScriptContext*
   341 DOMEventTargetHelper::GetContextForEventHandlers(nsresult* aRv)
   342 {
   343   *aRv = CheckInnerWindowCorrectness();
   344   if (NS_FAILED(*aRv)) {
   345     return nullptr;
   346   }
   347   nsPIDOMWindow* owner = GetOwner();
   348   return owner ? static_cast<nsGlobalWindow*>(owner)->GetContextInternal()
   349                : nullptr;
   350 }
   352 nsresult
   353 DOMEventTargetHelper::WantsUntrusted(bool* aRetVal)
   354 {
   355   nsresult rv;
   356   nsIScriptContext* context = GetContextForEventHandlers(&rv);
   357   NS_ENSURE_SUCCESS(rv, rv);
   358   nsCOMPtr<nsIDocument> doc =
   359     nsContentUtils::GetDocumentFromScriptContext(context);
   360   // We can let listeners on workers to always handle all the events.
   361   *aRetVal = (doc && !nsContentUtils::IsChromeDoc(doc)) || !NS_IsMainThread();
   362   return rv;
   363 }
   365 void
   366 DOMEventTargetHelper::EventListenerAdded(nsIAtom* aType)
   367 {
   368   ErrorResult rv;
   369   EventListenerWasAdded(Substring(nsDependentAtomString(aType), 2), rv);
   370 }
   372 void
   373 DOMEventTargetHelper::EventListenerRemoved(nsIAtom* aType)
   374 {
   375   ErrorResult rv;
   376   EventListenerWasRemoved(Substring(nsDependentAtomString(aType), 2), rv);
   377 }
   379 } // namespace mozilla

mercurial