EventListenerManager::Listener*
EventListenerManager::SetEventHandlerInternal(
                        JS::Handle<JSObject*> aScopeObject,
                        nsIAtom* aName,
                        const nsAString& aTypeString,
                        const nsEventHandler& aHandler,
                        bool aPermitUntrustedEvents)
{
  MOZ_ASSERT(aScopeObject || aHandler.HasEventHandler(),
             "Must have one or the other!");
  MOZ_ASSERT(aName || !aTypeString.IsEmpty());

  uint32_t eventType = nsContentUtils::GetEventId(aName);
  Listener* listener = FindEventHandler(eventType, aName, aTypeString);

  if (!listener) {
    // If we didn't find a script listener or no listeners existed
    // create and add a new one.
    EventListenerFlags flags;
    flags.mListenerIsJSListener = true;

    nsCOMPtr<nsIJSEventListener> jsListener;
    NS_NewJSEventListener(aScopeObject, mTarget, aName,
                          aHandler, getter_AddRefs(jsListener));
    EventListenerHolder listenerHolder(jsListener);
    AddEventListenerInternal(listenerHolder, eventType, aName, aTypeString,
                             flags, true);

    listener = FindEventHandler(eventType, aName, aTypeString);
  } else {
    nsIJSEventListener* jsListener = listener->GetJSListener();
    MOZ_ASSERT(jsListener,
               "How can we have an event handler with no nsIJSEventListener?");

    bool same = jsListener->GetHandler() == aHandler;
    // Possibly the same listener, but update still the context and scope.
    jsListener->SetHandler(aHandler, aScopeObject);
    if (mTarget && !same && aName) {
      mTarget->EventListenerRemoved(aName);
      mTarget->EventListenerAdded(aName);
    }
  }

  // Set flag to indicate possible need for compilation later
  listener->mHandlerIsString = !aHandler.HasEventHandler();
  if (aPermitUntrustedEvents) {
    listener->mFlags.mAllowUntrustedEvents = true;
  }

  return listener;
}
nsresult
nsXBLPrototypeHandler::ExecuteHandler(nsPIDOMEventTarget* aTarget,
                                      nsIDOMEvent* aEvent)
{
  nsresult rv = NS_ERROR_FAILURE;

  // Prevent default action?
  if (mType & NS_HANDLER_TYPE_PREVENTDEFAULT) {
    aEvent->PreventDefault();
    // If we prevent default, then it's okay for
    // mHandlerElement and mHandlerText to be null
    rv = NS_OK;
  }

  if (!mHandlerElement) // This works for both types of handlers.  In both cases, the union's var should be defined.
    return rv;

  // See if our event receiver is a content node (and not us).
  PRBool isXULKey = !!(mType & NS_HANDLER_TYPE_XUL);
  PRBool isXBLCommand = !!(mType & NS_HANDLER_TYPE_XBL_COMMAND);
  NS_ASSERTION(!(isXULKey && isXBLCommand),
               "can't be both a key and xbl command handler");

  // XUL handlers and commands shouldn't be triggered by non-trusted
  // events.
  if (isXULKey || isXBLCommand) {
    nsCOMPtr<nsIDOMNSEvent> domNSEvent = do_QueryInterface(aEvent);
    PRBool trustedEvent = PR_FALSE;
    if (domNSEvent) {
      domNSEvent->GetIsTrusted(&trustedEvent);
    }

    if (!trustedEvent)
      return NS_OK;
  }
    
  if (isXBLCommand) {
    return DispatchXBLCommand(aTarget, aEvent);
  }

  // If we're executing on a XUL key element, just dispatch a command
  // event at the element.  It will take care of retargeting it to its
  // command element, if applicable, and executing the event handler.
  if (isXULKey) {
    return DispatchXULKeyCommand(aEvent);
  }

  // Look for a compiled handler on the element. 
  // Should be compiled and bound with "on" in front of the name.
  nsAutoString onEvent(NS_LITERAL_STRING("onxbl"));
  nsAutoString str;
  mEventName->ToString(str);
  onEvent += str;
  nsCOMPtr<nsIAtom> onEventAtom = do_GetAtom(onEvent);

  // Compile the event handler.
  PRUint32 stID = nsIProgrammingLanguage::JAVASCRIPT;

  // Compile the handler and bind it to the element.
  nsCOMPtr<nsIScriptGlobalObject> boundGlobal;
  nsCOMPtr<nsPIWindowRoot> winRoot(do_QueryInterface(aTarget));
  nsCOMPtr<nsIDOMWindow> window;

  if (winRoot) {
    window = winRoot->GetWindow();
  }

  if (window) {
    nsCOMPtr<nsPIDOMWindow> piWin(do_QueryInterface(window));

    if (piWin) {
      piWin = piWin->GetCurrentInnerWindow();
      NS_ENSURE_TRUE(piWin, NS_ERROR_UNEXPECTED);
    }

    boundGlobal = do_QueryInterface(piWin->GetPrivateRoot());
  }
  else boundGlobal = do_QueryInterface(aTarget);

  if (!boundGlobal) {
    nsCOMPtr<nsIDocument> boundDocument(do_QueryInterface(aTarget));
    if (!boundDocument) {
      // We must be an element.
      nsCOMPtr<nsIContent> content(do_QueryInterface(aTarget));
      if (!content)
        return NS_OK;
      boundDocument = content->GetOwnerDoc();
      if (!boundDocument)
        return NS_OK;
    }

    boundGlobal = boundDocument->GetScopeObject();
  }

  if (!boundGlobal)
    return NS_OK;

  nsIScriptContext *boundContext = boundGlobal->GetScriptContext(stID);
  if (!boundContext)
    return NS_OK;

  nsScriptObjectHolder handler(boundContext);
  nsISupports *scriptTarget;

  if (winRoot) {
    scriptTarget = boundGlobal;
  } else {
    scriptTarget = aTarget;
  }

  rv = EnsureEventHandler(boundGlobal, boundContext, onEventAtom, handler);
  NS_ENSURE_SUCCESS(rv, rv);

  // Temporarily bind it to the bound element
  void *scope = boundGlobal->GetScriptGlobal(stID);
  rv = boundContext->BindCompiledEventHandler(scriptTarget, scope,
                                              onEventAtom, handler);
  NS_ENSURE_SUCCESS(rv, rv);

  // Execute it.
  nsCOMPtr<nsIDOMEventListener> eventListener;
  NS_NewJSEventListener(boundContext, scope,
                        scriptTarget, getter_AddRefs(eventListener));

  nsCOMPtr<nsIJSEventListener> jsListener(do_QueryInterface(eventListener));
  jsListener->SetEventName(onEventAtom);
  
  // Handle the event.
  eventListener->HandleEvent(aEvent);
  return NS_OK;
}