Fix for bug 206321 (Share event listeners between XBL event handlers).r=jkeiser, sr=bryner.

This commit is contained in:
peter%propagandism.org 2003-09-11 12:25:06 +00:00
parent 47b9d983ff
commit 453b136450
11 changed files with 408 additions and 533 deletions

View File

@ -102,18 +102,6 @@
#include "nsXBLPrototypeHandler.h"
#include "nsXBLKeyHandler.h"
#include "nsXBLFocusHandler.h"
#include "nsXBLMouseHandler.h"
#include "nsXBLMouseMotionHandler.h"
#include "nsXBLMutationHandler.h"
#include "nsXBLXULHandler.h"
#include "nsXBLScrollHandler.h"
#include "nsXBLFormHandler.h"
#include "nsXBLDragHandler.h"
#include "nsXBLLoadHandler.h"
#include "nsXBLContextMenuHandler.h"
#include "nsXBLCustomHandler.h"
#include "nsXBLPrototypeBinding.h"
#include "nsXBLBinding.h"
@ -166,74 +154,6 @@ nsXBLJSClass::Destroy()
return 0;
}
// Static initialization
PRUint32 nsXBLBinding::gRefCnt = 0;
nsXBLBinding::EventHandlerMapEntry
nsXBLBinding::kEventHandlerMap[] = {
{ "click", nsnull, &NS_GET_IID(nsIDOMMouseListener) },
{ "dblclick", nsnull, &NS_GET_IID(nsIDOMMouseListener) },
{ "mousedown", nsnull, &NS_GET_IID(nsIDOMMouseListener) },
{ "mouseup", nsnull, &NS_GET_IID(nsIDOMMouseListener) },
{ "mouseover", nsnull, &NS_GET_IID(nsIDOMMouseListener) },
{ "mouseout", nsnull, &NS_GET_IID(nsIDOMMouseListener) },
{ "mousemove", nsnull, &NS_GET_IID(nsIDOMMouseMotionListener) },
{ "keydown", nsnull, &NS_GET_IID(nsIDOMKeyListener) },
{ "keyup", nsnull, &NS_GET_IID(nsIDOMKeyListener) },
{ "keypress", nsnull, &NS_GET_IID(nsIDOMKeyListener) },
{ "load", nsnull, &NS_GET_IID(nsIDOMLoadListener) },
{ "unload", nsnull, &NS_GET_IID(nsIDOMLoadListener) },
{ "abort", nsnull, &NS_GET_IID(nsIDOMLoadListener) },
{ "error", nsnull, &NS_GET_IID(nsIDOMLoadListener) },
{ "popupshowing", nsnull, &NS_GET_IID(nsIDOMXULListener) },
{ "popupshown", nsnull, &NS_GET_IID(nsIDOMXULListener) },
{ "popuphiding" , nsnull, &NS_GET_IID(nsIDOMXULListener) },
{ "popuphidden", nsnull, &NS_GET_IID(nsIDOMXULListener) },
{ "close", nsnull, &NS_GET_IID(nsIDOMXULListener) },
{ "command", nsnull, &NS_GET_IID(nsIDOMXULListener) },
{ "broadcast", nsnull, &NS_GET_IID(nsIDOMXULListener) },
{ "commandupdate", nsnull, &NS_GET_IID(nsIDOMXULListener) },
{ "overflow", nsnull, &NS_GET_IID(nsIDOMScrollListener) },
{ "underflow", nsnull, &NS_GET_IID(nsIDOMScrollListener) },
{ "overflowchanged", nsnull, &NS_GET_IID(nsIDOMScrollListener) },
{ "focus", nsnull, &NS_GET_IID(nsIDOMFocusListener) },
{ "blur", nsnull, &NS_GET_IID(nsIDOMFocusListener) },
{ "submit", nsnull, &NS_GET_IID(nsIDOMFormListener) },
{ "reset", nsnull, &NS_GET_IID(nsIDOMFormListener) },
{ "change", nsnull, &NS_GET_IID(nsIDOMFormListener) },
{ "select", nsnull, &NS_GET_IID(nsIDOMFormListener) },
{ "input", nsnull, &NS_GET_IID(nsIDOMFormListener) },
{ "paint", nsnull, &NS_GET_IID(nsIDOMPaintListener) },
{ "resize", nsnull, &NS_GET_IID(nsIDOMPaintListener) },
{ "scroll", nsnull, &NS_GET_IID(nsIDOMPaintListener) },
{ "dragenter", nsnull, &NS_GET_IID(nsIDOMDragListener) },
{ "dragover", nsnull, &NS_GET_IID(nsIDOMDragListener) },
{ "dragexit", nsnull, &NS_GET_IID(nsIDOMDragListener) },
{ "dragdrop", nsnull, &NS_GET_IID(nsIDOMDragListener) },
{ "draggesture", nsnull, &NS_GET_IID(nsIDOMDragListener) },
{ "DOMSubtreeModified", nsnull, &NS_GET_IID(nsIDOMMutationListener) },
{ "DOMAttrModified", nsnull, &NS_GET_IID(nsIDOMMutationListener) },
{ "DOMCharacterDataModified", nsnull, &NS_GET_IID(nsIDOMMutationListener) },
{ "DOMNodeInserted", nsnull, &NS_GET_IID(nsIDOMMutationListener) },
{ "DOMNodeRemoved", nsnull, &NS_GET_IID(nsIDOMMutationListener) },
{ "DOMNodeInsertedIntoDocument", nsnull, &NS_GET_IID(nsIDOMMutationListener) },
{ "DOMNodeRemovedFromDocument", nsnull, &NS_GET_IID(nsIDOMMutationListener) },
{ "contextmenu", nsnull, &NS_GET_IID(nsIDOMContextMenuListener) },
{ nsnull, nsnull, nsnull }
};
// Implementation /////////////////////////////////////////////////////////////////
// Implement our nsISupports methods
@ -241,39 +161,17 @@ NS_IMPL_ISUPPORTS1(nsXBLBinding, nsIXBLBinding)
// Constructors/Destructors
nsXBLBinding::nsXBLBinding(nsXBLPrototypeBinding* aBinding)
: mFirstHandler(nsnull),
: mPrototypeBinding(aBinding),
mInsertionPointTable(nsnull),
mIsStyleBinding(PR_TRUE),
mMarkedForDeath(PR_FALSE)
{
mPrototypeBinding = aBinding;
gRefCnt++;
// printf("REF COUNT UP: %d %s\n", gRefCnt, (const char*)mID);
if (gRefCnt == 1) {
EventHandlerMapEntry* entry = kEventHandlerMap;
while (entry->mAttributeName) {
entry->mAttributeAtom = NS_NewAtom(entry->mAttributeName);
++entry;
}
}
}
nsXBLBinding::~nsXBLBinding(void)
{
delete mInsertionPointTable;
gRefCnt--;
// printf("REF COUNT DOWN: %d %s\n", gRefCnt, (const char*)mID);
if (gRefCnt == 0) {
EventHandlerMapEntry* entry = kEventHandlerMap;
while (entry->mAttributeName) {
NS_IF_RELEASE(entry->mAttributeAtom);
++entry;
}
}
}
// nsIXBLBinding Interface ////////////////////////////////////////////////////////////////
@ -825,33 +723,27 @@ nsXBLBinding::InstallEventHandlers()
return NS_ERROR_FAILURE;
nsXBLPrototypeHandler* handlerChain = mPrototypeBinding->GetPrototypeHandlers();
nsXBLEventHandler* currHandler = nsnull;
if (handlerChain) {
nsCOMPtr<nsIDOMEventReceiver> receiver = do_QueryInterface(mBoundElement);
nsCOMPtr<nsIDOM3EventTarget> target = do_QueryInterface(receiver);
nsCOMPtr<nsIDOMEventGroup> systemEventGroup;
for (nsXBLPrototypeHandler* curr = handlerChain; curr;
curr = curr->GetNextHandler()) {
nsXBLPrototypeHandler* curr;
for (curr = handlerChain; curr; curr = curr->GetNextHandler()) {
// Fetch the event type.
nsCOMPtr<nsIAtom> eventAtom = curr->GetEventName();
if (!eventAtom)
if (!eventAtom ||
eventAtom == nsXBLAtoms::keyup ||
eventAtom == nsXBLAtoms::keydown ||
eventAtom == nsXBLAtoms::keypress)
continue;
// Figure out if we're using capturing or not.
PRUint8 phase = curr->GetPhase();
PRBool useCapture = (phase == NS_PHASE_CAPTURING);
// Create a new nsXBLEventHandler.
nsXBLEventHandler* handler = nsnull;
nsAutoString type;
eventAtom->ToString(type);
nsIID iid;
PRBool found = PR_FALSE;
GetEventHandlerIID(eventAtom, &iid, &found);
// Figure out if we're using capturing or not.
PRBool useCapture = (curr->GetPhase() == NS_PHASE_CAPTURING);
// If this is a command, add it in the system event group, otherwise
// add it to the standard event group.
@ -865,145 +757,39 @@ nsXBLBinding::InstallEventHandlers()
eventGroup = systemEventGroup;
}
if (found) {
/*
// Disable ATTACHTO capability for Mozilla 1.0
nsAutoString attachType;
child->GetAttr(kNameSpaceID_None, kAttachToAtom, attachType);
if (attachType == NS_LITERAL_STRING("_document") ||
attachType == NS_LITERAL_STRING("_window"))
{
nsCOMPtr<nsIDocument> boundDoc;
mBoundElement->GetDocument(getter_AddRefs(boundDoc));
if (attachType == NS_LITERAL_STRING("_window")) {
nsCOMPtr<nsIScriptGlobalObject> global;
boundDoc->GetScriptGlobalObject(getter_AddRefs(global));
receiver = do_QueryInterface(global);
}
else receiver = do_QueryInterface(boundDoc);
}
else if (!attachType.IsEmpty() && !attachType.Equals(NS_LITERAL_STRING("_element"))) {
nsCOMPtr<nsIDocument> boundDoc;
mBoundElement->GetDocument(getter_AddRefs(boundDoc));
nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(boundDoc));
nsCOMPtr<nsIDOMElement> otherElement;
domDoc->GetElementById(attachType, getter_AddRefs(otherElement));
receiver = do_QueryInterface(otherElement);
}
*/
if (iid.Equals(NS_GET_IID(nsIDOMMouseListener))) {
nsXBLMouseHandler* mouseHandler;
NS_NewXBLMouseHandler(receiver, curr, &mouseHandler);
target->AddGroupedEventListener(type,
(nsIDOMMouseListener*)mouseHandler,
useCapture, eventGroup);
handler = mouseHandler;
}
else if(iid.Equals(NS_GET_IID(nsIDOMKeyListener))) {
nsXBLKeyHandler* keyHandler;
NS_NewXBLKeyHandler(receiver, curr, &keyHandler);
target->AddGroupedEventListener(type,
(nsIDOMKeyListener*)keyHandler,
useCapture, eventGroup);
handler = keyHandler;
}
else if (iid.Equals(NS_GET_IID(nsIDOMMouseMotionListener))) {
nsXBLMouseMotionHandler* mouseHandler;
NS_NewXBLMouseMotionHandler(receiver, curr, &mouseHandler);
target->AddGroupedEventListener(type,
(nsIDOMMouseListener*)mouseHandler,
useCapture, eventGroup);
handler = mouseHandler;
}
else if(iid.Equals(NS_GET_IID(nsIDOMFocusListener))) {
nsXBLFocusHandler* focusHandler;
NS_NewXBLFocusHandler(receiver, curr, &focusHandler);
target->AddGroupedEventListener(type,
(nsIDOMFocusListener*)focusHandler,
useCapture, eventGroup);
handler = focusHandler;
}
else if (iid.Equals(NS_GET_IID(nsIDOMXULListener))) {
nsXBLXULHandler* xulHandler;
NS_NewXBLXULHandler(receiver, curr, &xulHandler);
target->AddGroupedEventListener(type,
(nsIDOMXULListener*)xulHandler,
useCapture, eventGroup);
handler = xulHandler;
}
else if (iid.Equals(NS_GET_IID(nsIDOMScrollListener))) {
nsXBLScrollHandler* scrollHandler;
NS_NewXBLScrollHandler(receiver, curr, &scrollHandler);
target->AddGroupedEventListener(type,
(nsIDOMScrollListener*)scrollHandler,
useCapture, eventGroup);
handler = scrollHandler;
}
else if (iid.Equals(NS_GET_IID(nsIDOMFormListener))) {
nsXBLFormHandler* formHandler;
NS_NewXBLFormHandler(receiver, curr, &formHandler);
target->AddGroupedEventListener(type,
(nsIDOMFormListener*)formHandler,
useCapture, eventGroup);
handler = formHandler;
}
else if(iid.Equals(NS_GET_IID(nsIDOMDragListener))) {
nsXBLDragHandler* dragHandler;
NS_NewXBLDragHandler(receiver, curr, &dragHandler);
target->AddGroupedEventListener(type,
(nsIDOMDragListener*)dragHandler,
useCapture, eventGroup);
handler = dragHandler;
}
else if(iid.Equals(NS_GET_IID(nsIDOMLoadListener))) {
nsXBLLoadHandler* loadHandler;
NS_NewXBLLoadHandler(receiver, curr, &loadHandler);
target->AddGroupedEventListener(type,
(nsIDOMLoadListener*)loadHandler,
useCapture, eventGroup);
handler = loadHandler;
}
else if(iid.Equals(NS_GET_IID(nsIDOMMutationListener))) {
nsXBLMutationHandler* mutationHandler;
NS_NewXBLMutationHandler(receiver, curr, &mutationHandler);
target->AddGroupedEventListener(type,
(nsIDOMMutationListener*)mutationHandler,
useCapture, eventGroup);
handler = mutationHandler;
}
else if(iid.Equals(NS_GET_IID(nsIDOMContextMenuListener))) {
nsXBLContextMenuHandler* menuHandler;
NS_NewXBLContextMenuHandler(receiver, curr, &menuHandler);
target->AddGroupedEventListener(type,
(nsIDOMContextMenuListener*)menuHandler,
useCapture, eventGroup);
handler = menuHandler;
}
}
else {
nsXBLCustomHandler* customHandler;
NS_NewXBLCustomHandler(receiver, curr, &customHandler);
target->AddGroupedEventListener(type,
(nsIDOMEventListener*)customHandler,
useCapture, eventGroup);
handler = customHandler;
}
// We chain all our event handlers together for easy
// removal later (if/when the binding dies).
nsXBLEventHandler* handler = curr->GetEventHandler();
if (handler) {
if (!currHandler)
mFirstHandler = handler;
else
currHandler->SetNextHandler(handler);
currHandler = handler;
// Let the listener manager hold on to the handler.
NS_RELEASE(handler);
target->AddGroupedEventListener(type, handler, useCapture,
eventGroup);
}
}
const nsCOMArray<nsXBLKeyEventHandler>* keyHandlers =
mPrototypeBinding->GetKeyEventHandlers();
PRInt32 i;
for (i = 0; i < keyHandlers->Count(); ++i) {
nsXBLKeyEventHandler* handler = keyHandlers->ObjectAt(i);
nsAutoString type;
handler->GetEventName(type);
// Figure out if we're using capturing or not.
PRBool useCapture = (handler->GetPhase() == NS_PHASE_CAPTURING);
// If this is a command, add it in the system event group, otherwise
// add it to the standard event group.
// This is a weak ref. systemEventGroup above is already a
// strong ref, so we are guaranteed it will not go away.
nsIDOMEventGroup* eventGroup = nsnull;
if (handler->GetType() & NS_HANDLER_TYPE_XBL_COMMAND) {
if (!systemEventGroup)
receiver->GetSystemEventGroup(getter_AddRefs(systemEventGroup));
eventGroup = systemEventGroup;
}
target->AddGroupedEventListener(type, handler, useCapture, eventGroup);
}
}
}
@ -1082,10 +868,74 @@ nsXBLBinding::ExecuteDetachedHandler()
NS_IMETHODIMP
nsXBLBinding::UnhookEventHandlers()
{
if (mFirstHandler) {
// Unhook our event handlers.
mFirstHandler->RemoveEventHandlers();
mFirstHandler = nsnull;
nsXBLPrototypeHandler* handlerChain = mPrototypeBinding->GetPrototypeHandlers();
if (handlerChain) {
nsCOMPtr<nsIDOMEventReceiver> receiver = do_QueryInterface(mBoundElement);
nsCOMPtr<nsIDOM3EventTarget> target = do_QueryInterface(receiver);
nsCOMPtr<nsIDOMEventGroup> systemEventGroup;
nsXBLPrototypeHandler* curr;
for (curr = handlerChain; curr; curr = curr->GetNextHandler()) {
nsXBLEventHandler* handler = curr->GetCachedEventHandler();
if (handler) {
nsCOMPtr<nsIAtom> eventAtom = curr->GetEventName();
if (!eventAtom ||
eventAtom == nsXBLAtoms::keyup ||
eventAtom == nsXBLAtoms::keydown ||
eventAtom == nsXBLAtoms::keypress)
continue;
nsAutoString type;
eventAtom->ToString(type);
// Figure out if we're using capturing or not.
PRBool useCapture = (curr->GetPhase() == NS_PHASE_CAPTURING);
// If this is a command, remove it from the system event group, otherwise
// remove it from the standard event group.
// This is a weak ref. systemEventGroup above is already a
// strong ref, so we are guaranteed it will not go away.
nsIDOMEventGroup* eventGroup = nsnull;
if (curr->GetType() & NS_HANDLER_TYPE_XBL_COMMAND) {
if (!systemEventGroup)
receiver->GetSystemEventGroup(getter_AddRefs(systemEventGroup));
eventGroup = systemEventGroup;
}
target->RemoveGroupedEventListener(type, handler, useCapture,
eventGroup);
}
}
const nsCOMArray<nsXBLKeyEventHandler>* keyHandlers =
mPrototypeBinding->GetKeyEventHandlers();
PRInt32 i;
for (i = 0; i < keyHandlers->Count(); ++i) {
nsXBLKeyEventHandler* handler = keyHandlers->ObjectAt(i);
nsAutoString type;
handler->GetEventName(type);
// Figure out if we're using capturing or not.
PRBool useCapture = (handler->GetPhase() == NS_PHASE_CAPTURING);
// If this is a command, remove it from the system event group, otherwise
// remove it from the standard event group.
// This is a weak ref. systemEventGroup above is already a
// strong ref, so we are guaranteed it will not go away.
nsIDOMEventGroup* eventGroup = nsnull;
if (handler->GetType() & NS_HANDLER_TYPE_XBL_COMMAND) {
if (!systemEventGroup)
receiver->GetSystemEventGroup(getter_AddRefs(systemEventGroup));
eventGroup = systemEventGroup;
}
target->RemoveGroupedEventListener(type, handler, useCapture,
eventGroup);
}
}
return NS_OK;
@ -1095,11 +945,6 @@ NS_IMETHODIMP
nsXBLBinding::ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocument)
{
if (aOldDocument != aNewDocument) {
if (mFirstHandler) {
mFirstHandler->MarkForDeath();
mFirstHandler = nsnull;
}
if (mNextBinding)
mNextBinding->ChangeDocument(aOldDocument, aNewDocument);
@ -1439,22 +1284,6 @@ nsXBLBinding::IsInExcludesList(nsIAtom* aTag, const nsString& aList)
return PR_TRUE;
}
void
nsXBLBinding::GetEventHandlerIID(nsIAtom* aName, nsIID* aIID, PRBool* aFound)
{
*aFound = PR_FALSE;
EventHandlerMapEntry* entry = kEventHandlerMap;
while (entry->mAttributeAtom) {
if (entry->mAttributeAtom == aName) {
*aIID = *entry->mHandlerIID;
*aFound = PR_TRUE;
break;
}
++entry;
}
}
NS_IMETHODIMP
nsXBLBinding::AddScriptEventListener(nsIContent* aElement, nsIAtom* aName,
const nsString& aValue)

View File

@ -138,22 +138,6 @@ public:
const nsAFlatCString& aClassName,
void **aClassObject);
// Static members
static PRUint32 gRefCnt;
// Used to easily obtain the correct IID for an event.
struct EventHandlerMapEntry {
const char* mAttributeName;
nsIAtom* mAttributeAtom;
const nsIID* mHandlerIID;
};
static EventHandlerMapEntry kEventHandlerMap[];
static PRBool IsSupportedHandler(const nsIID* aIID);
static void GetEventHandlerIID(nsIAtom* aName, nsIID* aIID, PRBool* aFound);
// Internal member functions
protected:
nsresult InitClass(const nsCString& aClassName, nsIScriptContext* aContext,
@ -166,14 +150,10 @@ protected:
// MEMBER VARIABLES
protected:
nsRefPtr<nsXBLPrototypeBinding> mPrototypeBinding; // Strong. We share ownership with other bindings and the docinfo.
nsCOMPtr<nsIContent> mContent; // Strong. Our anonymous content stays around with us.
nsCOMPtr<nsIXBLBinding> mNextBinding; // Strong. The derived binding owns the base class bindings.
nsXBLEventHandler* mFirstHandler; // Weak. Our bound element owns the handler
// through the event listener manager.
nsIContent* mBoundElement; // [WEAK] We have a reference, but we don't own it.
nsObjectHashtable* mInsertionPointTable; // A hash from nsIContent* -> (a sorted array of nsXBLInsertionPoint*)

View File

@ -40,127 +40,159 @@
* ***** END LICENSE BLOCK ***** */
#include "nsCOMPtr.h"
#include "nsXBLPrototypeHandler.h"
#include "nsXBLEventHandler.h"
#include "nsIContent.h"
#include "nsIAtom.h"
#include "nsIContent.h"
#include "nsIDOMEventGroup.h"
#include "nsIDOMEventReceiver.h"
#include "nsIDOMKeyEvent.h"
#include "nsIDOMMouseEvent.h"
#include "nsIScriptContext.h"
#include "nsIScriptGlobalObject.h"
#include "nsIDocument.h"
#include "nsIDOMDocument.h"
#include "nsIJSEventListener.h"
#include "nsIController.h"
#include "nsIControllers.h"
#include "nsIDOMXULElement.h"
#include "nsIDOMNSHTMLTextAreaElement.h"
#include "nsIDOMNSHTMLInputElement.h"
#include "nsIDOMText.h"
#include "nsIEventListenerManager.h"
#include "nsIDOMEventReceiver.h"
#include "nsIDOMEventListener.h"
#include "nsXBLBinding.h"
#include "nsIPrivateDOMEvent.h"
#include "nsIDOMWindowInternal.h"
#include "nsIServiceManager.h"
#include "nsIURI.h"
#include "nsXPIDLString.h"
#include "nsIDOMFocusListener.h"
#include "nsIDOMKeyListener.h"
#include "nsIDOMXULListener.h"
#include "nsIDOMMouseListener.h"
#include "nsIDOMDragListener.h"
#include "nsIDOMScrollListener.h"
#include "nsIDOMFormListener.h"
#include "nsXBLAtoms.h"
#include "nsIDOMEventGroup.h"
#include "nsIDOM3EventTarget.h"
#include "nsXBLAtoms.h"
#include "nsXBLPrototypeHandler.h"
nsXBLEventHandler::nsXBLEventHandler(nsIDOMEventReceiver* aEventReceiver,
nsXBLPrototypeHandler* aHandler)
nsXBLEventHandler::nsXBLEventHandler(nsXBLPrototypeHandler* aHandler)
: mProtoHandler(aHandler)
{
mEventReceiver = aEventReceiver;
mProtoHandler = aHandler;
mNextHandler = nsnull;
}
nsXBLEventHandler::~nsXBLEventHandler()
{
}
NS_IMPL_ISUPPORTS1(nsXBLEventHandler, nsISupports)
NS_IMPL_ISUPPORTS1(nsXBLEventHandler, nsIDOMEventListener)
void
nsXBLEventHandler::RemoveEventHandlers()
NS_IMETHODIMP
nsXBLEventHandler::HandleEvent(nsIDOMEvent* aEvent)
{
if (mNextHandler)
mNextHandler->RemoveEventHandlers();
// Figure out if we're using capturing or not.
if (!mProtoHandler)
return;
return NS_ERROR_FAILURE;
nsCOMPtr<nsIAtom> eventName = mProtoHandler->GetEventName();
nsAutoString type;
eventName->ToString(type);
PRUint8 phase = mProtoHandler->GetPhase();
PRBool useCapture = (phase == NS_PHASE_CAPTURING);
PRBool found = PR_FALSE;
nsIID iid;
nsXBLBinding::GetEventHandlerIID(eventName, &iid, &found);
nsCOMPtr<nsIDOMEventListener> listener(do_QueryInterface(this));
// are we in the system event group?
nsCOMPtr<nsIDOMEventGroup> eventGroup;
if (mProtoHandler->GetType() & NS_HANDLER_TYPE_XBL_COMMAND)
mEventReceiver->GetSystemEventGroup(getter_AddRefs(eventGroup));
if (found && listener) {
nsCOMPtr<nsIDOM3EventTarget> target = do_QueryInterface(mEventReceiver);
target->RemoveGroupedEventListener(type, listener, useCapture, eventGroup);
if (phase == NS_PHASE_TARGET) {
PRUint16 eventPhase;
aEvent->GetEventPhase(&eventPhase);
if (eventPhase != nsIDOMEvent::AT_TARGET)
return NS_OK;
}
if (!EventMatched(aEvent))
return NS_OK;
nsCOMPtr<nsIDOMEventTarget> target;
aEvent->GetCurrentTarget(getter_AddRefs(target));
nsCOMPtr<nsIDOMEventReceiver> receiver = do_QueryInterface(target);
mProtoHandler->ExecuteHandler(receiver, aEvent);
return NS_OK;
}
/// Helpers that are relegated to the end of the file /////////////////////////////
nsresult
nsXBLEventHandler::GetTextData(nsIContent *aParent, nsAString& aResult)
nsXBLMouseEventHandler::nsXBLMouseEventHandler(nsXBLPrototypeHandler* aHandler)
: nsXBLEventHandler(aHandler)
{
aResult.Truncate(0);
}
nsCOMPtr<nsIContent> textChild;
PRInt32 textCount;
aParent->ChildCount(textCount);
nsXBLMouseEventHandler::~nsXBLMouseEventHandler()
{
}
for (PRInt32 j = 0; j < textCount; j++) {
// Get the child.
aParent->ChildAt(j, getter_AddRefs(textChild));
nsCOMPtr<nsIDOMText> text(do_QueryInterface(textChild));
if (text) {
nsAutoString data;
text->GetData(data);
aResult.Append(data);
}
PRBool
nsXBLMouseEventHandler::EventMatched(nsIDOMEvent* aEvent)
{
nsCOMPtr<nsIDOMMouseEvent> mouse(do_QueryInterface(aEvent));
return mProtoHandler->MouseEventMatched(mouse);
}
nsXBLKeyEventHandler::nsXBLKeyEventHandler(nsIAtom* aEventType, PRUint8 aPhase,
PRUint8 aType)
: mEventType(aEventType),
mPhase(aPhase),
mType(aType)
{
}
nsXBLKeyEventHandler::~nsXBLKeyEventHandler()
{
}
NS_IMPL_ISUPPORTS1(nsXBLKeyEventHandler, nsIDOMEventListener)
NS_IMETHODIMP
nsXBLKeyEventHandler::HandleEvent(nsIDOMEvent* aEvent)
{
PRUint32 count = mProtoHandlers.Count();
if (count == 0)
return NS_ERROR_FAILURE;
if (mPhase == NS_PHASE_TARGET) {
PRUint16 eventPhase;
aEvent->GetEventPhase(&eventPhase);
if (eventPhase != nsIDOMEvent::AT_TARGET)
return NS_OK;
}
nsCOMPtr<nsIDOMEventTarget> target;
aEvent->GetCurrentTarget(getter_AddRefs(target));
nsCOMPtr<nsIDOMEventReceiver> receiver = do_QueryInterface(target);
nsCOMPtr<nsIDOMKeyEvent> key(do_QueryInterface(aEvent));
PRUint32 i;
for (i = 0; i < count; ++i) {
nsXBLPrototypeHandler* handler = NS_STATIC_CAST(nsXBLPrototypeHandler*,
mProtoHandlers[i]);
if (handler->KeyEventMatched(key))
handler->ExecuteHandler(receiver, aEvent);
}
return NS_OK;
}
///////////////////////////////////////////////////////////////////////////////////
nsresult
NS_NewXBLEventHandler(nsIDOMEventReceiver* aRec,
nsXBLPrototypeHandler* aHandler,
NS_NewXBLEventHandler(nsXBLPrototypeHandler* aHandler,
nsIAtom* aEventType,
nsXBLEventHandler** aResult)
{
*aResult = new nsXBLEventHandler(aRec, aHandler);
if (aEventType == nsXBLAtoms::mousedown ||
aEventType == nsXBLAtoms::mouseup ||
aEventType == nsXBLAtoms::click ||
aEventType == nsXBLAtoms::dblclick ||
aEventType == nsXBLAtoms::mouseover ||
aEventType == nsXBLAtoms::mouseout ||
aEventType == nsXBLAtoms::mousemove ||
aEventType == nsXBLAtoms::contextmenu ||
aEventType == nsXBLAtoms::dragenter ||
aEventType == nsXBLAtoms::dragover ||
aEventType == nsXBLAtoms::dragdrop ||
aEventType == nsXBLAtoms::dragexit ||
aEventType == nsXBLAtoms::draggesture) {
*aResult = new nsXBLMouseEventHandler(aHandler);
}
else {
*aResult = new nsXBLEventHandler(aHandler);
}
if (!*aResult)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(*aResult);
return NS_OK;
}
nsresult
NS_NewXBLKeyEventHandler(nsIAtom* aEventType, PRUint8 aPhase, PRUint8 aType,
nsXBLKeyEventHandler** aResult)
{
*aResult = new nsXBLKeyEventHandler(aEventType, aPhase, aType);
if (!*aResult)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(*aResult);
return NS_OK;
}

View File

@ -40,118 +40,98 @@
#ifndef nsXBLEventHandler_h__
#define nsXBLEventHandler_h__
#include "nsIDOMEventReceiver.h"
#include "nsCOMPtr.h"
#include "nsXBLPrototypeHandler.h"
#include "nsIDOMKeyEvent.h"
#include "nsIDOMMouseEvent.h"
#include "nsIDOMEventReceiver.h"
#include "nsIDOMEventListener.h"
#include "nsVoidArray.h"
class nsIXBLBinding;
class nsIDOMEvent;
class nsIContent;
class nsIDOMUIEvent;
class nsIDOMKeyEvent;
class nsIDOMMouseEvent;
class nsIAtom;
class nsIController;
class nsIContent;
class nsIDOM3EventTarget;
class nsIDOMEventReceiver;
class nsXBLPrototypeHandler;
// XXX This should be broken up into subclasses for each listener IID type, so we
// can cut down on the bloat of the handlers.
class nsXBLEventHandler : public nsISupports
class nsXBLEventHandler : public nsIDOMEventListener
{
public:
nsXBLEventHandler(nsIDOMEventReceiver* aReceiver,
nsXBLPrototypeHandler* aHandler);
nsXBLEventHandler(nsXBLPrototypeHandler* aHandler);
virtual ~nsXBLEventHandler();
NS_DECL_ISUPPORTS
public:
void SetNextHandler(nsXBLEventHandler* aHandler) {
mNextHandler = aHandler;
}
void RemoveEventHandlers();
void MarkForDeath() {
if (mNextHandler) mNextHandler->MarkForDeath(); mProtoHandler = nsnull; mEventReceiver = nsnull;
}
static nsresult GetTextData(nsIContent *aParent, nsAString& aResult);
NS_DECL_NSIDOMEVENTLISTENER
protected:
nsCOMPtr<nsIDOMEventReceiver> mEventReceiver;
nsXBLPrototypeHandler* mProtoHandler;
nsXBLEventHandler* mNextHandler; // Handlers are chained for easy unloading later.
inline nsresult DoGeneric(nsIAtom* aEventType, nsIDOMEvent* aEvent)
private:
nsXBLEventHandler();
virtual PRBool EventMatched(nsIDOMEvent* aEvent)
{
if (!mProtoHandler)
return NS_ERROR_FAILURE;
PRUint8 phase = mProtoHandler->GetPhase();
if (phase == NS_PHASE_TARGET) {
PRUint16 eventPhase;
aEvent->GetEventPhase(&eventPhase);
if (eventPhase != nsIDOMEvent::AT_TARGET)
return NS_OK;
}
if (aEventType) {
nsCOMPtr<nsIAtom> eventName = mProtoHandler->GetEventName();
if (eventName != aEventType)
return NS_OK;
}
mProtoHandler->ExecuteHandler(mEventReceiver, aEvent);
return NS_OK;
}
inline nsresult DoKey(nsIAtom* aEventType, nsIDOMEvent* aKeyEvent)
{
if (!mProtoHandler)
return NS_ERROR_FAILURE;
PRUint8 phase = mProtoHandler->GetPhase();
if (phase == NS_PHASE_TARGET) {
PRUint16 eventPhase;
aKeyEvent->GetEventPhase(&eventPhase);
if (eventPhase != nsIDOMEvent::AT_TARGET)
return NS_OK;
}
nsCOMPtr<nsIDOMKeyEvent> key(do_QueryInterface(aKeyEvent));
if (mProtoHandler->KeyEventMatched(aEventType, key))
mProtoHandler->ExecuteHandler(mEventReceiver, aKeyEvent);
return NS_OK;
}
inline nsresult DoMouse(nsIAtom* aEventType, nsIDOMEvent* aMouseEvent)
{
if (!mProtoHandler)
return NS_ERROR_FAILURE;
PRUint8 phase = mProtoHandler->GetPhase();
if (phase == NS_PHASE_TARGET) {
PRUint16 eventPhase;
aMouseEvent->GetEventPhase(&eventPhase);
if (eventPhase != nsIDOMEvent::AT_TARGET)
return NS_OK;
}
nsCOMPtr<nsIDOMMouseEvent> mouse(do_QueryInterface(aMouseEvent));
if (mProtoHandler->MouseEventMatched(aEventType, mouse))
mProtoHandler->ExecuteHandler(mEventReceiver, aMouseEvent);
return NS_OK;
return PR_TRUE;
}
};
class nsXBLMouseEventHandler : public nsXBLEventHandler
{
public:
nsXBLMouseEventHandler(nsXBLPrototypeHandler* aHandler);
virtual ~nsXBLMouseEventHandler();
private:
PRBool EventMatched(nsIDOMEvent* aEvent);
};
class nsXBLKeyEventHandler : public nsIDOMEventListener
{
public:
nsXBLKeyEventHandler(nsIAtom* aEventType, PRUint8 aPhase, PRUint8 aType);
virtual ~nsXBLKeyEventHandler();
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMEVENTLISTENER
void AddProtoHandler(nsXBLPrototypeHandler* aProtoHandler)
{
mProtoHandlers.AppendElement(aProtoHandler);
}
PRBool Matches(nsIAtom* aEventType, PRUint8 aPhase, PRUint8 aType) const
{
return (mEventType == aEventType && mPhase == aPhase && mType == aType);
}
void GetEventName(nsAString& aString) const
{
mEventType->ToString(aString);
}
PRUint8 GetPhase() const
{
return mPhase;
}
PRUint8 GetType() const
{
return mType;
}
private:
nsXBLKeyEventHandler();
nsVoidArray mProtoHandlers;
nsCOMPtr<nsIAtom> mEventType;
PRUint8 mPhase;
PRUint8 mType;
};
nsresult
NS_NewXBLEventHandler(nsIDOMEventReceiver* aEventReceiver,
nsXBLPrototypeHandler* aHandlerElement,
NS_NewXBLEventHandler(nsXBLPrototypeHandler* aHandler,
nsIAtom* aEventType,
nsXBLEventHandler** aResult);
nsresult
NS_NewXBLKeyEventHandler(nsIAtom* aEventType, PRUint8 aPhase,
PRUint8 aType, nsXBLKeyEventHandler** aResult);
#endif

View File

@ -223,11 +223,11 @@ static const PRInt32 kInsInitialSize = (NS_SIZE_IN_HEAP(sizeof(nsXBLInsertionPoi
nsXBLPrototypeBinding::nsXBLPrototypeBinding(const nsACString& aID,
nsIXBLDocumentInfo* aInfo,
nsIContent* aElement)
: mPrototypeHandler(nsnull),
mImplementation(nsnull),
: mImplementation(nsnull),
mBaseBinding(nsnull),
mInheritStyle(PR_TRUE),
mHasBaseProto(PR_TRUE),
mKeyHandlersRegistered(PR_FALSE),
mResources(nsnull),
mAttributeTable(nsnull),
mInsertionPointTable(nsnull),
@ -269,7 +269,6 @@ nsXBLPrototypeBinding::~nsXBLPrototypeBinding(void)
delete mInsertionPointTable;
delete mInterfaceTable;
delete mImplementation;
delete mPrototypeHandler;
gRefCnt--;
if (gRefCnt == 0) {
delete kAttrPool;
@ -1267,3 +1266,38 @@ nsXBLPrototypeBinding::AddResourceListener(nsIContent* aBoundElement)
mResources->AddResourceListener(aBoundElement);
return NS_OK;
}
void
nsXBLPrototypeBinding::CreateKeyHandlers()
{
nsXBLPrototypeHandler* curr = mPrototypeHandler;
while (curr) {
nsCOMPtr<nsIAtom> eventAtom = curr->GetEventName();
if (eventAtom == nsXBLAtoms::keyup ||
eventAtom == nsXBLAtoms::keydown ||
eventAtom == nsXBLAtoms::keypress) {
PRUint8 phase = curr->GetPhase();
PRUint8 type = curr->GetType();
PRInt32 count = mKeyHandlers.Count();
PRInt32 i;
nsXBLKeyEventHandler* handler;
for (i = 0; i < count; ++i) {
handler = mKeyHandlers[i];
if (handler->Matches(eventAtom, phase, type))
break;
}
if (i == count) {
NS_NewXBLKeyEventHandler(eventAtom, phase, type, &handler);
if (handler)
mKeyHandlers.AppendObject(handler);
}
if (handler)
handler->AddProtoHandler(curr);
}
curr = curr->GetNextHandler();
}
}

View File

@ -49,6 +49,7 @@
#include "nsIContent.h"
#include "nsHashtable.h"
#include "nsIXBLDocumentInfo.h"
#include "nsCOMArray.h"
class nsIAtom;
class nsIDocument;
@ -148,6 +149,16 @@ public:
void Initialize();
const nsCOMArray<nsXBLKeyEventHandler>* GetKeyEventHandlers()
{
if (!mKeyHandlersRegistered) {
CreateKeyHandlers();
mKeyHandlersRegistered = PR_TRUE;
}
return &mKeyHandlers;
}
public:
nsXBLPrototypeBinding(const nsACString& aRef, nsIXBLDocumentInfo* aInfo, nsIContent* aElement);
~nsXBLPrototypeBinding();
@ -187,6 +198,7 @@ protected:
void ConstructInsertionTable(nsIContent* aElement);
void GetNestedChildren(nsIAtom* aTag, nsIContent* aContent,
nsISupportsArray** aList);
void CreateKeyHandlers();
protected:
// Internal helper class for managing our IID table.
@ -217,7 +229,7 @@ protected:
char* mID;
nsCOMPtr<nsIContent> mBinding; // Strong. We own a ref to our content element in the binding doc.
nsXBLPrototypeHandler* mPrototypeHandler; // Strong. DocInfo owns us, and we own the handlers.
nsAutoPtr<nsXBLPrototypeHandler> mPrototypeHandler; // Strong. DocInfo owns us, and we own the handlers.
nsXBLProtoImpl* mImplementation; // Our prototype implementation (includes methods, properties, fields,
// the constructor, and the destructor).
@ -225,6 +237,7 @@ protected:
nsXBLPrototypeBinding* mBaseBinding; // Weak. The docinfo will own our base binding.
PRPackedBool mInheritStyle;
PRPackedBool mHasBaseProto;
PRPackedBool mKeyHandlersRegistered;
nsXBLPrototypeResources* mResources; // If we have any resources, this will be non-null.
@ -242,6 +255,8 @@ protected:
nsCOMPtr<nsIAtom> mBaseTag; // be stored in here.
nsAutoRefCnt mRefCnt;
nsCOMArray<nsXBLKeyEventHandler> mKeyHandlers;
};
#endif

View File

@ -81,6 +81,7 @@
#include "nsUnicharUtils.h"
#include "nsReadableUtils.h"
#include "nsCRT.h"
#include "nsXBLEventHandler.h"
static NS_DEFINE_CID(kDOMScriptObjectFactoryCID,
NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
@ -591,13 +592,9 @@ nsXBLPrototypeHandler::GetController(nsIDOMEventReceiver* aReceiver)
return controller;
}
PRBool
nsXBLPrototypeHandler::KeyEventMatched(nsIAtom* aEventType, nsIDOMKeyEvent* aKeyEvent)
nsXBLPrototypeHandler::KeyEventMatched(nsIDOMKeyEvent* aKeyEvent)
{
if (aEventType != mEventName.get())
return PR_FALSE;
if (mDetail == -1 && mMisc == 0 && mKeyMask == 0)
return PR_TRUE; // No filters set up. It's generic.
@ -622,11 +619,8 @@ nsXBLPrototypeHandler::KeyEventMatched(nsIAtom* aEventType, nsIDOMKeyEvent* aKey
}
PRBool
nsXBLPrototypeHandler::MouseEventMatched(nsIAtom* aEventType, nsIDOMMouseEvent* aMouseEvent)
nsXBLPrototypeHandler::MouseEventMatched(nsIDOMMouseEvent* aMouseEvent)
{
if (aEventType != mEventName.get())
return PR_FALSE;
if (mDetail == -1 && mMisc == 0 && mKeyMask == 0)
return PR_TRUE; // No filters set up. It's generic.
@ -977,26 +971,3 @@ nsXBLPrototypeHandler::ModifiersMatchMask(nsIDOMUIEvent* aEvent,
return PR_TRUE;
}
nsresult
nsXBLPrototypeHandler::GetTextData(nsIContent *aParent, nsString& aResult)
{
aResult.Truncate(0);
nsCOMPtr<nsIContent> textChild;
PRInt32 textCount;
aParent->ChildCount(textCount);
nsAutoString answer;
for (PRInt32 j = 0; j < textCount; j++) {
// Get the child.
aParent->ChildAt(j, getter_AddRefs(textChild));
nsCOMPtr<nsIDOMText> text(do_QueryInterface(textChild));
if (text) {
nsAutoString data;
text->GetData(data);
aResult += data;
}
}
return NS_OK;
}

View File

@ -44,6 +44,8 @@
#include "nsString.h"
#include "nsCOMPtr.h"
#include "nsIController.h"
#include "nsAutoPtr.h"
#include "nsXBLEventHandler.h"
class nsIDOMEvent;
class nsIContent;
@ -51,6 +53,7 @@ class nsIDOMUIEvent;
class nsIDOMKeyEvent;
class nsIDOMMouseEvent;
class nsIDOMEventReceiver;
class nsIDOM3EventTarget;
class nsXBLPrototypeBinding;
#define NS_HANDLER_TYPE_XBL_JS (1 << 0)
@ -77,9 +80,26 @@ public:
nsXBLPrototypeHandler(nsIContent* aKeyElement);
~nsXBLPrototypeHandler();
PRBool MouseEventMatched(nsIAtom* aEventType, nsIDOMMouseEvent* aEvent);
PRBool KeyEventMatched(nsIAtom* aEventType, nsIDOMKeyEvent* aEvent);
PRBool KeyEventMatched(nsIDOMKeyEvent* aKeyEvent);
inline PRBool KeyEventMatched(nsIAtom* aEventType,
nsIDOMKeyEvent* aEvent)
{
if (aEventType != mEventName)
return PR_FALSE;
return KeyEventMatched(aEvent);
}
PRBool MouseEventMatched(nsIDOMMouseEvent* aMouseEvent);
inline PRBool MouseEventMatched(nsIAtom* aEventType,
nsIDOMMouseEvent* aEvent)
{
if (aEventType != mEventName)
return PR_FALSE;
return MouseEventMatched(aEvent);
}
already_AddRefed<nsIContent> GetHandlerElement();
@ -102,10 +122,23 @@ public:
nsresult BindingAttached(nsIDOMEventReceiver* aReceiver);
nsresult BindingDetached(nsIDOMEventReceiver* aReceiver);
public:
static nsresult GetTextData(nsIContent *aParent, nsString& aResult);
nsXBLEventHandler* GetEventHandler()
{
if (!mHandler) {
NS_NewXBLEventHandler(this, mEventName, getter_AddRefs(mHandler));
// XXX Need to signal out of memory?
}
return mHandler;
}
nsXBLEventHandler* GetCachedEventHandler()
{
return mHandler;
}
public:
static PRUint32 gRefCnt;
protected:
@ -122,9 +155,6 @@ protected:
void GetEventType(nsAString& type);
PRBool ModifiersMatchMask(nsIDOMUIEvent* aEvent, PRInt32 aModifiersMask);
inline PRBool KeyEventMatched(nsIDOMKeyEvent* aKeyEvent);
inline PRBool MouseEventMatched(nsIDOMMouseEvent* aMouseEvent);
PRInt32 KeyToMask(PRInt32 key);
static PRInt32 kAccelKey;
@ -169,6 +199,7 @@ protected:
// Prototype handlers are chained. We own the next handler in the chain.
nsXBLPrototypeHandler* mNextHandler;
nsCOMPtr<nsIAtom> mEventName; // The type of the event, e.g., "keypress"
nsRefPtr<nsXBLEventHandler> mHandler;
nsXBLPrototypeBinding* mPrototypeBinding; // the binding owns us
};

View File

@ -56,7 +56,11 @@ public:
virtual ~nsXBLWindowDragHandler();
// nsIDOMetc.
NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent) { return NS_OK; };
NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent)
{
return NS_OK;
};
NS_IMETHOD DragGesture(nsIDOMEvent* aMouseEvent) ;
NS_IMETHOD DragOver(nsIDOMEvent* aMouseEvent) ;
NS_IMETHOD DragEnter(nsIDOMEvent* aMouseEvent) ;

View File

@ -82,11 +82,6 @@ protected:
nsIAtom* aEventType,
nsXBLPrototypeHandler* aHandler);
// create the event handler list from the given document/URI
void GetHandlers(nsIXBLDocumentInfo* aInfo,
const nsACString& aRef,
nsXBLPrototypeHandler** aResult);
// does the handler care about the particular event?
virtual PRBool EventMatched(nsXBLPrototypeHandler* inHandler,
nsIAtom* inEventType,

View File

@ -55,7 +55,11 @@ public:
virtual ~nsXBLWindowKeyHandler();
// nsIDOMetc.
NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent) { return NS_OK; };
NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent)
{
return NS_OK;
};
NS_IMETHOD KeyUp(nsIDOMEvent* aKeyEvent);
NS_IMETHOD KeyDown(nsIDOMEvent* aKeyEvent);
NS_IMETHOD KeyPress(nsIDOMEvent* aKeyEvent);