Blame dom/events/EventListenerService.cpp

Packit f0b94e
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
Packit f0b94e
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
Packit f0b94e
/* This Source Code Form is subject to the terms of the Mozilla Public
Packit f0b94e
 * License, v. 2.0. If a copy of the MPL was not distributed with this
Packit f0b94e
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
Packit f0b94e
Packit f0b94e
#include "EventListenerService.h"
Packit f0b94e
#include "mozilla/BasicEvents.h"
Packit f0b94e
#include "mozilla/EventDispatcher.h"
Packit f0b94e
#include "mozilla/EventListenerManager.h"
Packit f0b94e
#include "mozilla/JSEventHandler.h"
Packit f0b94e
#include "mozilla/Maybe.h"
Packit f0b94e
#include "nsArrayUtils.h"
Packit f0b94e
#include "nsCOMArray.h"
Packit f0b94e
#include "nsDOMClassInfoID.h"
Packit f0b94e
#include "nsIXPConnect.h"
Packit f0b94e
#include "nsJSUtils.h"
Packit f0b94e
#include "nsMemory.h"
Packit f0b94e
#include "nsServiceManagerUtils.h"
Packit f0b94e
#include "nsArray.h"
Packit f0b94e
#include "nsThreadUtils.h"
Packit f0b94e
Packit f0b94e
namespace mozilla {
Packit f0b94e
Packit f0b94e
using namespace dom;
Packit f0b94e
Packit f0b94e
/******************************************************************************
Packit f0b94e
 * mozilla::EventListenerChange
Packit f0b94e
 ******************************************************************************/
Packit f0b94e
Packit f0b94e
NS_IMPL_ISUPPORTS(EventListenerChange, nsIEventListenerChange)
Packit f0b94e
Packit f0b94e
EventListenerChange::~EventListenerChange() {}
Packit f0b94e
Packit f0b94e
EventListenerChange::EventListenerChange(dom::EventTarget* aTarget)
Packit f0b94e
    : mTarget(aTarget) {}
Packit f0b94e
Packit f0b94e
void EventListenerChange::AddChangedListenerName(nsAtom* aEventName) {
Packit f0b94e
  mChangedListenerNames.AppendElement(aEventName);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
EventListenerChange::GetTarget(nsIDOMEventTarget** aTarget) {
Packit f0b94e
  NS_ENSURE_ARG_POINTER(aTarget);
Packit f0b94e
  NS_ADDREF(*aTarget = mTarget);
Packit f0b94e
  return NS_OK;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
EventListenerChange::GetCountOfEventListenerChangesAffectingAccessibility(
Packit f0b94e
    uint32_t* aCount) {
Packit f0b94e
  *aCount = 0;
Packit f0b94e
Packit f0b94e
  size_t length = mChangedListenerNames.Length();
Packit f0b94e
  for (size_t i = 0; i < length; i++) {
Packit f0b94e
    RefPtr<nsAtom> listenerName = mChangedListenerNames[i];
Packit f0b94e
Packit f0b94e
    // These are the event listener changes which may make an element
Packit f0b94e
    // accessible or inaccessible.
Packit f0b94e
    if (listenerName == nsGkAtoms::onclick ||
Packit f0b94e
        listenerName == nsGkAtoms::onmousedown ||
Packit f0b94e
        listenerName == nsGkAtoms::onmouseup) {
Packit f0b94e
      *aCount += 1;
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  return NS_OK;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
/******************************************************************************
Packit f0b94e
 * mozilla::EventListenerInfo
Packit f0b94e
 ******************************************************************************/
Packit f0b94e
Packit f0b94e
NS_IMPL_CYCLE_COLLECTION(EventListenerInfo, mListener)
Packit f0b94e
Packit f0b94e
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(EventListenerInfo)
Packit f0b94e
  NS_INTERFACE_MAP_ENTRY(nsIEventListenerInfo)
Packit f0b94e
  NS_INTERFACE_MAP_ENTRY(nsISupports)
Packit f0b94e
NS_INTERFACE_MAP_END
Packit f0b94e
Packit f0b94e
NS_IMPL_CYCLE_COLLECTING_ADDREF(EventListenerInfo)
Packit f0b94e
NS_IMPL_CYCLE_COLLECTING_RELEASE(EventListenerInfo)
Packit f0b94e
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
EventListenerInfo::GetType(nsAString& aType) {
Packit f0b94e
  aType = mType;
Packit f0b94e
  return NS_OK;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
EventListenerInfo::GetCapturing(bool* aCapturing) {
Packit f0b94e
  *aCapturing = mCapturing;
Packit f0b94e
  return NS_OK;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
EventListenerInfo::GetAllowsUntrusted(bool* aAllowsUntrusted) {
Packit f0b94e
  *aAllowsUntrusted = mAllowsUntrusted;
Packit f0b94e
  return NS_OK;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
EventListenerInfo::GetInSystemEventGroup(bool* aInSystemEventGroup) {
Packit f0b94e
  *aInSystemEventGroup = mInSystemEventGroup;
Packit f0b94e
  return NS_OK;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
EventListenerInfo::GetListenerObject(JSContext* aCx,
Packit f0b94e
                                     JS::MutableHandle<JS::Value> aObject) {
Packit f0b94e
  Maybe<JSAutoCompartment> ac;
Packit f0b94e
  GetJSVal(aCx, ac, aObject);
Packit f0b94e
  return NS_OK;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
/******************************************************************************
Packit f0b94e
 * mozilla::EventListenerService
Packit f0b94e
 ******************************************************************************/
Packit f0b94e
Packit f0b94e
NS_IMPL_ISUPPORTS(EventListenerService, nsIEventListenerService)
Packit f0b94e
Packit f0b94e
bool EventListenerInfo::GetJSVal(JSContext* aCx, Maybe<JSAutoCompartment>& aAc,
Packit f0b94e
                                 JS::MutableHandle<JS::Value> aJSVal) {
Packit f0b94e
  aJSVal.setNull();
Packit f0b94e
  nsCOMPtr<nsIXPConnectWrappedJS> wrappedJS = do_QueryInterface(mListener);
Packit f0b94e
  if (wrappedJS) {
Packit f0b94e
    JS::Rooted<JSObject*> object(aCx, wrappedJS->GetJSObject());
Packit f0b94e
    if (!object) {
Packit f0b94e
      return false;
Packit f0b94e
    }
Packit f0b94e
    aAc.emplace(aCx, object);
Packit f0b94e
    aJSVal.setObject(*object);
Packit f0b94e
    return true;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  nsCOMPtr<JSEventHandler> jsHandler = do_QueryInterface(mListener);
Packit f0b94e
  if (jsHandler && jsHandler->GetTypedEventHandler().HasEventHandler()) {
Packit f0b94e
    JS::Handle<JSObject*> handler =
Packit f0b94e
        jsHandler->GetTypedEventHandler().Ptr()->CallableOrNull();
Packit f0b94e
    if (handler) {
Packit f0b94e
      aAc.emplace(aCx, handler);
Packit f0b94e
      aJSVal.setObject(*handler);
Packit f0b94e
      return true;
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
  return false;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
EventListenerInfo::ToSource(nsAString& aResult) {
Packit f0b94e
  aResult.SetIsVoid(true);
Packit f0b94e
Packit f0b94e
  AutoSafeJSContext cx;
Packit f0b94e
  Maybe<JSAutoCompartment> ac;
Packit f0b94e
  JS::Rooted<JS::Value> v(cx);
Packit f0b94e
  if (GetJSVal(cx, ac, &v)) {
Packit f0b94e
    JSString* str = JS_ValueToSource(cx, v);
Packit f0b94e
    if (str) {
Packit f0b94e
      nsAutoJSString autoStr;
Packit f0b94e
      if (autoStr.init(cx, str)) {
Packit f0b94e
        aResult.Assign(autoStr);
Packit f0b94e
      }
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
  return NS_OK;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
EventListenerService* EventListenerService::sInstance = nullptr;
Packit f0b94e
Packit f0b94e
EventListenerService::EventListenerService() {
Packit f0b94e
  MOZ_ASSERT(!sInstance);
Packit f0b94e
  sInstance = this;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
EventListenerService::~EventListenerService() {
Packit f0b94e
  MOZ_ASSERT(sInstance == this);
Packit f0b94e
  sInstance = nullptr;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
EventListenerService::GetListenerInfoFor(nsIDOMEventTarget* aEventTarget,
Packit f0b94e
                                         uint32_t* aCount,
Packit f0b94e
                                         nsIEventListenerInfo*** aOutArray) {
Packit f0b94e
  NS_ENSURE_ARG_POINTER(aEventTarget);
Packit f0b94e
  *aCount = 0;
Packit f0b94e
  *aOutArray = nullptr;
Packit f0b94e
  nsCOMArray<nsIEventListenerInfo> listenerInfos;
Packit f0b94e
Packit f0b94e
  nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(aEventTarget);
Packit f0b94e
  NS_ENSURE_TRUE(eventTarget, NS_ERROR_NO_INTERFACE);
Packit f0b94e
Packit f0b94e
  EventListenerManager* elm = eventTarget->GetExistingListenerManager();
Packit f0b94e
  if (elm) {
Packit f0b94e
    elm->GetListenerInfo(&listenerInfos);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  int32_t count = listenerInfos.Count();
Packit f0b94e
  if (count == 0) {
Packit f0b94e
    return NS_OK;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  listenerInfos.Forget(aOutArray);
Packit f0b94e
  *aCount = count;
Packit f0b94e
  return NS_OK;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
EventListenerService::GetEventTargetChainFor(nsIDOMEventTarget* aEventTarget,
Packit f0b94e
                                             bool aComposed, uint32_t* aCount,
Packit f0b94e
                                             nsIDOMEventTarget*** aOutArray) {
Packit f0b94e
  *aCount = 0;
Packit f0b94e
  *aOutArray = nullptr;
Packit f0b94e
  NS_ENSURE_ARG(aEventTarget);
Packit f0b94e
  WidgetEvent event(true, eVoidEvent);
Packit f0b94e
  event.SetComposed(aComposed);
Packit f0b94e
  nsTArray<EventTarget*> targets;
Packit f0b94e
  nsresult rv = EventDispatcher::Dispatch(aEventTarget, nullptr, &event,
Packit f0b94e
                                          nullptr, nullptr, nullptr, &targets;;
Packit f0b94e
  NS_ENSURE_SUCCESS(rv, rv);
Packit f0b94e
  int32_t count = targets.Length();
Packit f0b94e
  if (count == 0) {
Packit f0b94e
    return NS_OK;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  *aOutArray = static_cast<nsIDOMEventTarget**>(
Packit f0b94e
      moz_xmalloc(sizeof(nsIDOMEventTarget*) * count));
Packit f0b94e
  NS_ENSURE_TRUE(*aOutArray, NS_ERROR_OUT_OF_MEMORY);
Packit f0b94e
Packit f0b94e
  for (int32_t i = 0; i < count; ++i) {
Packit f0b94e
    NS_ADDREF((*aOutArray)[i] = targets[i]);
Packit f0b94e
  }
Packit f0b94e
  *aCount = count;
Packit f0b94e
Packit f0b94e
  return NS_OK;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
EventListenerService::HasListenersFor(nsIDOMEventTarget* aEventTarget,
Packit f0b94e
                                      const nsAString& aType, bool* aRetVal) {
Packit f0b94e
  nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(aEventTarget);
Packit f0b94e
  NS_ENSURE_TRUE(eventTarget, NS_ERROR_NO_INTERFACE);
Packit f0b94e
Packit f0b94e
  EventListenerManager* elm = eventTarget->GetExistingListenerManager();
Packit f0b94e
  *aRetVal = elm && elm->HasListenersFor(aType);
Packit f0b94e
  return NS_OK;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
EventListenerService::AddSystemEventListener(nsIDOMEventTarget* aTarget,
Packit f0b94e
                                             const nsAString& aType,
Packit f0b94e
                                             nsIDOMEventListener* aListener,
Packit f0b94e
                                             bool aUseCapture) {
Packit f0b94e
  NS_PRECONDITION(aTarget, "Missing target");
Packit f0b94e
  NS_PRECONDITION(aListener, "Missing listener");
Packit f0b94e
Packit f0b94e
  nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(aTarget);
Packit f0b94e
  NS_ENSURE_TRUE(eventTarget, NS_ERROR_NO_INTERFACE);
Packit f0b94e
Packit f0b94e
  EventListenerManager* manager = eventTarget->GetOrCreateListenerManager();
Packit f0b94e
  NS_ENSURE_STATE(manager);
Packit f0b94e
Packit f0b94e
  EventListenerFlags flags = aUseCapture ? TrustedEventsAtSystemGroupCapture()
Packit f0b94e
                                         : TrustedEventsAtSystemGroupBubble();
Packit f0b94e
  manager->AddEventListenerByType(aListener, aType, flags);
Packit f0b94e
  return NS_OK;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
EventListenerService::RemoveSystemEventListener(nsIDOMEventTarget* aTarget,
Packit f0b94e
                                                const nsAString& aType,
Packit f0b94e
                                                nsIDOMEventListener* aListener,
Packit f0b94e
                                                bool aUseCapture) {
Packit f0b94e
  NS_PRECONDITION(aTarget, "Missing target");
Packit f0b94e
  NS_PRECONDITION(aListener, "Missing listener");
Packit f0b94e
Packit f0b94e
  nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(aTarget);
Packit f0b94e
  NS_ENSURE_TRUE(eventTarget, NS_ERROR_NO_INTERFACE);
Packit f0b94e
Packit f0b94e
  EventListenerManager* manager = eventTarget->GetExistingListenerManager();
Packit f0b94e
  if (manager) {
Packit f0b94e
    EventListenerFlags flags = aUseCapture ? TrustedEventsAtSystemGroupCapture()
Packit f0b94e
                                           : TrustedEventsAtSystemGroupBubble();
Packit f0b94e
    manager->RemoveEventListenerByType(aListener, aType, flags);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  return NS_OK;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
EventListenerService::AddListenerForAllEvents(nsIDOMEventTarget* aTarget,
Packit f0b94e
                                              nsIDOMEventListener* aListener,
Packit f0b94e
                                              bool aUseCapture,
Packit f0b94e
                                              bool aWantsUntrusted,
Packit f0b94e
                                              bool aSystemEventGroup) {
Packit f0b94e
  NS_ENSURE_STATE(aTarget && aListener);
Packit f0b94e
Packit f0b94e
  nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(aTarget);
Packit f0b94e
  NS_ENSURE_TRUE(eventTarget, NS_ERROR_NO_INTERFACE);
Packit f0b94e
Packit f0b94e
  EventListenerManager* manager = eventTarget->GetOrCreateListenerManager();
Packit f0b94e
  NS_ENSURE_STATE(manager);
Packit f0b94e
  manager->AddListenerForAllEvents(aListener, aUseCapture, aWantsUntrusted,
Packit f0b94e
                                   aSystemEventGroup);
Packit f0b94e
  return NS_OK;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
EventListenerService::RemoveListenerForAllEvents(nsIDOMEventTarget* aTarget,
Packit f0b94e
                                                 nsIDOMEventListener* aListener,
Packit f0b94e
                                                 bool aUseCapture,
Packit f0b94e
                                                 bool aSystemEventGroup) {
Packit f0b94e
  NS_ENSURE_STATE(aTarget && aListener);
Packit f0b94e
Packit f0b94e
  nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(aTarget);
Packit f0b94e
  NS_ENSURE_TRUE(eventTarget, NS_ERROR_NO_INTERFACE);
Packit f0b94e
Packit f0b94e
  EventListenerManager* manager = eventTarget->GetExistingListenerManager();
Packit f0b94e
  if (manager) {
Packit f0b94e
    manager->RemoveListenerForAllEvents(aListener, aUseCapture,
Packit f0b94e
                                        aSystemEventGroup);
Packit f0b94e
  }
Packit f0b94e
  return NS_OK;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
EventListenerService::AddListenerChangeListener(
Packit f0b94e
    nsIListenerChangeListener* aListener) {
Packit f0b94e
  if (!mChangeListeners.Contains(aListener)) {
Packit f0b94e
    mChangeListeners.AppendElement(aListener);
Packit f0b94e
  }
Packit f0b94e
  return NS_OK;
Packit f0b94e
};
Packit f0b94e
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
EventListenerService::RemoveListenerChangeListener(
Packit f0b94e
    nsIListenerChangeListener* aListener) {
Packit f0b94e
  mChangeListeners.RemoveElement(aListener);
Packit f0b94e
  return NS_OK;
Packit f0b94e
};
Packit f0b94e
Packit f0b94e
void EventListenerService::NotifyAboutMainThreadListenerChangeInternal(
Packit f0b94e
    dom::EventTarget* aTarget, nsAtom* aName) {
Packit f0b94e
  MOZ_ASSERT(NS_IsMainThread());
Packit f0b94e
  MOZ_ASSERT(aTarget);
Packit f0b94e
  if (mChangeListeners.IsEmpty()) {
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (!mPendingListenerChanges) {
Packit f0b94e
    mPendingListenerChanges = nsArrayBase::Create();
Packit f0b94e
    nsCOMPtr<nsIRunnable> runnable =
Packit f0b94e
        NewRunnableMethod("EventListenerService::NotifyPendingChanges", this,
Packit f0b94e
                          &EventListenerService::NotifyPendingChanges);
Packit f0b94e
    if (nsCOMPtr<nsIGlobalObject> global = aTarget->GetOwnerGlobal()) {
Packit f0b94e
      global->Dispatch(TaskCategory::Other, runnable.forget());
Packit f0b94e
    } else if (nsCOMPtr<nsINode> node = do_QueryInterface(aTarget)) {
Packit f0b94e
      node->OwnerDoc()->Dispatch(TaskCategory::Other, runnable.forget());
Packit f0b94e
    } else {
Packit f0b94e
      NS_DispatchToCurrentThread(runnable);
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  RefPtr<EventListenerChange> changes =
Packit f0b94e
      mPendingListenerChangesSet.LookupForAdd(aTarget).OrInsert(
Packit f0b94e
          [this, aTarget]() {
Packit f0b94e
            EventListenerChange* c = new EventListenerChange(aTarget);
Packit f0b94e
            mPendingListenerChanges->AppendElement(c);
Packit f0b94e
            return c;
Packit f0b94e
          });
Packit f0b94e
  changes->AddChangedListenerName(aName);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void EventListenerService::NotifyPendingChanges() {
Packit f0b94e
  nsCOMPtr<nsIMutableArray> changes;
Packit f0b94e
  mPendingListenerChanges.swap(changes);
Packit f0b94e
  mPendingListenerChangesSet.Clear();
Packit f0b94e
Packit f0b94e
  nsTObserverArray<nsCOMPtr<nsIListenerChangeListener>>::EndLimitedIterator
Packit f0b94e
      iter(mChangeListeners);
Packit f0b94e
  while (iter.HasMore()) {
Packit f0b94e
    nsCOMPtr<nsIListenerChangeListener> listener = iter.GetNext();
Packit f0b94e
    listener->ListenersChanged(changes);
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
}  // namespace mozilla
Packit f0b94e
Packit f0b94e
nsresult NS_NewEventListenerService(nsIEventListenerService** aResult) {
Packit f0b94e
  *aResult = new mozilla::EventListenerService();
Packit f0b94e
  NS_ADDREF(*aResult);
Packit f0b94e
  return NS_OK;
Packit f0b94e
}