Fixing bug 81115 that causes the identity of event receivers and event targets to be incorrect in the case where the target/reveiver is an nsGenericElement or a nsGenericDOMDataNode. The problem was the those classes use the event listener manager as a tearoff but QI'ing that tearoff to nsISupports returns the event listener manager and not the element/node, this causes XPConnect to create different wrappers for the same element/node when the event listener tearoff is wrapped in stead of directly wrapping the element/node. This causes problems with event.target in JS, among other things. The solution for this problem was to create a separate tearoff that works correctly and leave the event listener manager alone since it can not be used as a tearoff in all cases. r=pollmann@netscape.com, sr=vidur@netscape.com

This commit is contained in:
jst%netscape.com 2001-05-19 07:02:50 +00:00
Родитель 06d3952507
Коммит aabe6d5306
11 изменённых файлов: 276 добавлений и 118 удалений

Просмотреть файл

@ -39,6 +39,7 @@ class nsISupportsArray;
class nsIDOMRange;
class nsISizeOfHandler;
class nsINodeInfo;
class nsIEventListenerManager;
// IID for the nsIContent interface
#define NS_ICONTENT_IID \
@ -311,6 +312,8 @@ public:
* type, such as HTML, XUL, Text, ...
*/
NS_IMETHOD_(PRBool) IsContentOfType(PRUint32 aFlags) = 0;
NS_IMETHOD GetListenerManager(nsIEventListenerManager** aResult) = 0;
};
// nsresult codes for GetAttribute

Просмотреть файл

@ -183,6 +183,10 @@ public:
return PR_FALSE;
}
NS_IMETHOD GetListenerManager(nsIEventListenerManager** aResult) {
return mInner.GetListenerManager(this, aResult);
}
NS_IMETHOD SizeOf(nsISizeOfHandler* aSizer, PRUint32* aResult) const {
if (!aResult) {
return NS_ERROR_NULL_POINTER;

Просмотреть файл

@ -200,6 +200,9 @@ struct nsGenericDOMDataNode {
nsresult GetBindingParent(nsIContent** aContent);
nsresult SetBindingParent(nsIContent* aParent);
nsresult GetListenerManager(nsIContent* aOuterContent,
nsIEventListenerManager** aInstancePtrResult);
nsresult SizeOf(nsISizeOfHandler* aSizer, PRUint32* aResult,
size_t aInstanceSize) const;
@ -256,8 +259,6 @@ struct nsGenericDOMDataNode {
//----------------------------------------
nsresult GetListenerManager(nsIContent* aOuterContent, nsIEventListenerManager** aInstancePtrResult);
void ToCString(nsAWritableString& aBuf, PRInt32 aOffset, PRInt32 aLen) const;
nsIDocument* mDocument;
@ -526,7 +527,11 @@ struct nsGenericDOMDataNode {
NS_IMETHOD SetBindingParent(nsIContent* aParent) { \
return _g.SetBindingParent(aParent); \
} \
NS_IMETHOD_(PRBool) IsContentOfType(PRUint32 aFlags);
NS_IMETHOD_(PRBool) IsContentOfType(PRUint32 aFlags); \
NS_IMETHOD GetListenerManager(nsIEventListenerManager** aResult) { \
return _g.GetListenerManager(this, aResult); \
}
/**
* Implement the nsIDOMText API by forwarding the methods to a
@ -578,21 +583,11 @@ struct nsGenericDOMDataNode {
#define NS_INTERFACE_MAP_ENTRY_DOM_DATA() \
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContent) \
NS_INTERFACE_MAP_ENTRY(nsIDOMNode) \
if (aIID.Equals(NS_GET_IID(nsIDOMEventReceiver))) { \
nsCOMPtr<nsIEventListenerManager> man; \
if (NS_SUCCEEDED(mInner.GetListenerManager(this, getter_AddRefs(man)))) { \
return man->QueryInterface(NS_GET_IID(nsIDOMEventReceiver), \
(void**)aInstancePtr); \
} \
return NS_NOINTERFACE; \
} else \
if (aIID.Equals(NS_GET_IID(nsIDOMEventTarget))) { \
nsCOMPtr<nsIEventListenerManager> man; \
if (NS_SUCCEEDED(mInner.GetListenerManager(this, getter_AddRefs(man)))){ \
return man->QueryInterface(NS_GET_IID(nsIDOMEventTarget), \
(void**)aInstancePtr); \
} \
return NS_NOINTERFACE; \
if (aIID.Equals(NS_GET_IID(nsIDOMEventReceiver)) || \
aIID.Equals(NS_GET_IID(nsIDOMEventTarget))) { \
foundInterface = NS_STATIC_CAST(nsIDOMEventReceiver *, \
nsDOMEventRTTearoff::Create(this)); \
NS_ENSURE_TRUE(foundInterface, NS_ERROR_OUT_OF_MEMORY); \
} else \
NS_INTERFACE_MAP_ENTRY(nsIContent) \
NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOM3Node, nsNode3Tearoff(this))

Просмотреть файл

@ -421,12 +421,184 @@ nsNode3Tearoff::GetBaseURI(nsAWritableString& aURI)
return NS_OK;
}
nsDOMEventRTTearoff *nsDOMEventRTTearoff::mCachedEventTearoff[];
PRUint32 nsDOMEventRTTearoff::mCachedEventTearoffCount = 0;
nsDOMEventRTTearoff::nsDOMEventRTTearoff(nsIContent *aContent)
: mContent(aContent)
{
NS_INIT_ISUPPORTS();
}
nsDOMEventRTTearoff::~nsDOMEventRTTearoff()
{
};
NS_IMETHODIMP
nsDOMEventRTTearoff::QueryInterface(REFNSIID aIID, void** aInstancePtr)
{
if (aIID.Equals(NS_GET_IID(nsIDOMEventTarget)) ||
aIID.Equals(NS_GET_IID(nsIDOMEventReceiver))) {
nsIDOMEventReceiver *inst = this;
NS_ADDREF(inst);
*aInstancePtr = inst;
return NS_OK;
}
return mContent->QueryInterface(aIID, aInstancePtr);
}
NS_IMPL_ADDREF(nsDOMEventRTTearoff)
NS_IMPL_RELEASE_WITH_DESTROY(nsDOMEventRTTearoff, LastRelease())
nsDOMEventRTTearoff *
nsDOMEventRTTearoff::Create(nsIContent *aContent)
{
if (mCachedEventTearoffCount) {
// We have cached unused instances of this class, return a cached
// instance in stead of always creating a new one.
nsDOMEventRTTearoff *tearoff =
mCachedEventTearoff[--mCachedEventTearoffCount];
// Set the back pointer to the content object
tearoff->mContent = aContent;
return tearoff;
}
// The cache is empty, this means we haveto create a new instance.
return new nsDOMEventRTTearoff(aContent);
}
// static
void
nsDOMEventRTTearoff::Shutdown()
{
// Clear our cache.
while (mCachedEventTearoffCount) {
delete mCachedEventTearoff[--mCachedEventTearoffCount];
}
}
void
nsDOMEventRTTearoff::LastRelease()
{
if (mCachedEventTearoffCount < NS_EVENT_TEAROFF_CACHE_SIZE) {
// There's still space in the cache for one more instance, put
// this instance in the cache in stead of deleting it.
mCachedEventTearoff[mCachedEventTearoffCount++] = this;
mContent = nsnull;
// The defcount balancing and destructor re-entrancy code in
// Release() sets mRefCnt to 1 so we haveto set it to 0 here to
// prevent leaks
mRefCnt = 0;
return;
}
delete this;
}
nsresult
nsDOMEventRTTearoff::GetEventReceiver(nsIDOMEventReceiver **aReceiver)
{
nsCOMPtr<nsIEventListenerManager> listener_manager;
nsresult rv = mContent->GetListenerManager(getter_AddRefs(listener_manager));
NS_ENSURE_SUCCESS(rv, rv);
return CallQueryInterface(listener_manager, aReceiver);
}
NS_IMETHODIMP
nsDOMEventRTTearoff::AddEventListenerByIID(nsIDOMEventListener *aListener,
const nsIID& aIID)
{
nsCOMPtr<nsIDOMEventReceiver> event_receiver;
nsresult rv = GetEventReceiver(getter_AddRefs(event_receiver));
NS_ENSURE_SUCCESS(rv, rv);
return event_receiver->AddEventListenerByIID(aListener, aIID);
}
NS_IMETHODIMP
nsDOMEventRTTearoff::RemoveEventListenerByIID(nsIDOMEventListener *aListener,
const nsIID& aIID)
{
nsCOMPtr<nsIDOMEventReceiver> event_receiver;
nsresult rv = GetEventReceiver(getter_AddRefs(event_receiver));
NS_ENSURE_SUCCESS(rv, rv);
return event_receiver->RemoveEventListenerByIID(aListener, aIID);
}
NS_IMETHODIMP
nsDOMEventRTTearoff::GetListenerManager(nsIEventListenerManager** aResult)
{
return mContent->GetListenerManager(aResult);
}
NS_IMETHODIMP
nsDOMEventRTTearoff::HandleEvent(nsIDOMEvent *aEvent)
{
nsCOMPtr<nsIDOMEventReceiver> event_receiver;
nsresult rv = GetEventReceiver(getter_AddRefs(event_receiver));
NS_ENSURE_SUCCESS(rv, rv);
return event_receiver->HandleEvent(aEvent);
}
// nsIDOMEventTarget
NS_IMETHODIMP
nsDOMEventRTTearoff::AddEventListener(const nsAReadableString& type,
nsIDOMEventListener *listener,
PRBool useCapture)
{
nsCOMPtr<nsIDOMEventReceiver> event_receiver;
nsresult rv = GetEventReceiver(getter_AddRefs(event_receiver));
NS_ENSURE_SUCCESS(rv, rv);
return event_receiver->AddEventListener(type, listener, useCapture);
}
NS_IMETHODIMP
nsDOMEventRTTearoff::RemoveEventListener(const nsAReadableString& type,
nsIDOMEventListener *listener,
PRBool useCapture)
{
nsCOMPtr<nsIDOMEventReceiver> event_receiver;
nsresult rv = GetEventReceiver(getter_AddRefs(event_receiver));
NS_ENSURE_SUCCESS(rv, rv);
return event_receiver->RemoveEventListener(type, listener, useCapture);
}
NS_IMETHODIMP
nsDOMEventRTTearoff::DispatchEvent(nsIDOMEvent *evt)
{
nsCOMPtr<nsIDOMEventReceiver> event_receiver;
nsresult rv = GetEventReceiver(getter_AddRefs(event_receiver));
NS_ENSURE_SUCCESS(rv, rv);
return event_receiver->DispatchEvent(evt);
}
//----------------------------------------------------------------------
/* static */ void
nsGenericElement::Shutdown()
{
nsDOMEventRTTearoff::Shutdown();
}
nsGenericElement::nsGenericElement() : mDocument(nsnull), mParent(nsnull),
@ -2372,27 +2544,22 @@ nsGenericElement::QueryInterface(REFNSIID aIID, void** aInstancePtr)
inst = NS_STATIC_CAST(nsIContent *, this);
} else if (aIID.Equals(NS_GET_IID(nsIStyledContent))) {
inst = NS_STATIC_CAST(nsIStyledContent *, this);
} else if (aIID.Equals(NS_GET_IID(nsIDOM3Node))) {
inst = new nsNode3Tearoff(this);
NS_ENSURE_TRUE(inst, NS_ERROR_OUT_OF_MEMORY);
} else if (aIID.Equals(NS_GET_IID(nsIDOMEventReceiver)) ||
aIID.Equals(NS_GET_IID(nsIDOMEventTarget))) {
nsCOMPtr<nsIEventListenerManager> man;
GetListenerManager(getter_AddRefs(man));
if (man) {
return man->QueryInterface(aIID, aInstancePtr);
}
return NS_NOINTERFACE;
}
else if (mDocument) {
inst = NS_STATIC_CAST(nsIDOMEventReceiver *,
nsDOMEventRTTearoff::Create(this));
NS_ENSURE_TRUE(inst, NS_ERROR_OUT_OF_MEMORY);
} else if (mDocument) {
nsCOMPtr<nsIBindingManager> manager;
mDocument->GetBindingManager(getter_AddRefs(manager));
if (manager)
return manager->GetBindingImplementation(this, aIID, aInstancePtr);
return NS_NOINTERFACE;
}
else {
} else {
return NS_NOINTERFACE;
}

Просмотреть файл

@ -29,6 +29,7 @@
#include "nsIDOMElement.h"
#include "nsIDOMNodeList.h"
#include "nsIDOMLinkStyle.h"
#include "nsIDOMEventReceiver.h"
#include "nsIStyleSheetLinkingElement.h"
#include "nsICSSStyleSheet.h"
#include "nsICSSLoaderObserver.h"
@ -141,6 +142,61 @@ private:
};
// nsDOMEventRTTearoff is a tearoff class used by nsGenericElement and
// nsGenericDOMDataNode classes for implemeting the interfaces
// nsIDOMEventReceiver and nsIDOMEventTarget
#define NS_EVENT_TEAROFF_CACHE_SIZE 4
class nsDOMEventRTTearoff : public nsIDOMEventReceiver
{
private:
// This class uses a caching scheme so we don't let users of this
// class create new instances with 'new', in stead the callers
// should use the static method
// nsDOMEventRTTearoff::Create(). That's why the constructor and
// destrucor of this class is private.
nsDOMEventRTTearoff(nsIContent *aContent);
virtual ~nsDOMEventRTTearoff();
static nsDOMEventRTTearoff *mCachedEventTearoff[NS_EVENT_TEAROFF_CACHE_SIZE];
static PRUint32 mCachedEventTearoffCount;
// This method gets called by Release() when it's time to delete the
// this object, in stead of always deleting the object we'll put the
// object in the cache if unless the cache is already full.
void LastRelease();
nsresult GetEventReceiver(nsIDOMEventReceiver **aReceiver);
public:
// Use this static method to create instances of this tearoff class.
static nsDOMEventRTTearoff *Create(nsIContent *aContent);
static void Shutdown();
// nsISupports
NS_DECL_ISUPPORTS
// nsIDOMEventTarget
NS_DECL_NSIDOMEVENTTARGET
// nsIDOMEventReceiver
NS_IMETHOD AddEventListenerByIID(nsIDOMEventListener *aListener,
const nsIID& aIID);
NS_IMETHOD RemoveEventListenerByIID(nsIDOMEventListener *aListener,
const nsIID& aIID);
NS_IMETHOD GetListenerManager(nsIEventListenerManager** aResult);
NS_IMETHOD HandleEvent(nsIDOMEvent *aEvent);
private:
// Strong reference back to the content object from where an
// instance of this class was 'torn off'
nsCOMPtr<nsIContent> mContent;
};
class nsGenericElement : public nsIHTMLContent
{
public:
@ -210,6 +266,8 @@ public:
NS_IMETHOD GetBindingParent(nsIContent** aContent);
NS_IMETHOD SetBindingParent(nsIContent* aParent);
NS_IMETHOD_(PRBool) IsContentOfType(PRUint32 aFlags);
NS_IMETHOD GetListenerManager(nsIEventListenerManager** aInstancePtrResult);
// nsIStyledContent interface methods
NS_IMETHOD GetID(nsIAtom*& aResult) const;
@ -305,8 +363,6 @@ public:
//----------------------------------------
nsresult GetListenerManager(nsIEventListenerManager** aInstancePtrResult);
nsresult RenderFrame(nsIPresContext*);
nsresult AddScriptEventListener(nsIAtom* aAttribute,

Просмотреть файл

@ -166,50 +166,14 @@ nsresult nsEventListenerManager::RemoveAllListeners(PRBool aScriptOnly)
NS_IMPL_ADDREF(nsEventListenerManager)
NS_IMPL_RELEASE(nsEventListenerManager)
// We need to return to the old QI form briefly to deal with the
// results of the partial aggregation we began using nsGenericElement
// and nsGenericDOMDataNode. We should look for a better long term
// solution. -joki
NS_IMETHODIMP
nsEventListenerManager::QueryInterface(REFNSIID aIID, void** aInstancePtr)
{
if (nsnull == aInstancePtr) {
return NS_ERROR_NULL_POINTER;
}
if (aIID.Equals(NS_GET_IID(nsIEventListenerManager))) {
*aInstancePtr = (void*)(nsIEventListenerManager*)this;
AddRef();
return NS_OK;
}
if (aIID.Equals(NS_GET_IID(nsIDOMEventTarget))) {
*aInstancePtr = (void*)(nsIDOMEventTarget*)this;
AddRef();
return NS_OK;
}
if (aIID.Equals(NS_GET_IID(nsIDOMEventReceiver))) {
*aInstancePtr = (void*)(nsIDOMEventReceiver*)this;
AddRef();
return NS_OK;
}
if (mTarget) {
return mTarget->QueryInterface(aIID, aInstancePtr);
}
if (aIID.Equals(NS_GET_IID(nsISupports))) {
*aInstancePtr = (void*)(nsISupports*)(nsIEventListenerManager*)this;
AddRef();
return NS_OK;
}
return NS_NOINTERFACE;
}
#if 0
NS_INTERFACE_MAP_BEGIN(nsEventListenerManager)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIEventListenerManager)
NS_INTERFACE_MAP_ENTRY(nsIEventListenerManager)
NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
NS_INTERFACE_MAP_ENTRY(nsIDOMEventReceiver)
NS_INTERFACE_MAP_END
#endif
nsVoidArray* nsEventListenerManager::GetListenersByType(EventArrayType aType,
nsHashKey* aKey,

Просмотреть файл

@ -23,7 +23,6 @@
#include "nsIAttributeContent.h"
#include "nsGenericElement.h"
#include "nsIDocument.h"
#include "nsIEventListenerManager.h"
#include "nsIDocument.h"
#include "nsIDOMRange.h"
#include "nsIDOMDocument.h"
@ -52,9 +51,7 @@
#include "nsITextContent.h"
class nsIDOMAttr;
class nsIDOMEventListener;
class nsIDOMNodeList;
class nsIEventListenerManager;
class nsIFrame;
class nsIStyleContext;
class nsIStyleRule;
@ -122,6 +119,10 @@ public:
return !(aFlags & ~eTEXT);
}
NS_IMETHOD GetListenerManager(nsIEventListenerManager **aResult) {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHOD SetAttribute(PRInt32 aNameSpaceID, nsIAtom* aAttribute, const nsAReadableString& aValue,
PRBool aNotify) { return NS_OK; }
NS_IMETHOD SetAttribute(nsINodeInfo *aNodeInfo, const nsAReadableString& aValue,
@ -211,11 +212,6 @@ public:
};
NS_IMPL_ADDREF(nsAttributeContent)
NS_IMPL_RELEASE(nsAttributeContent)
nsresult
NS_NewAttributeContent(nsIContent** aContent)
{
@ -271,42 +267,18 @@ nsAttributeContent::Init(nsIContent* aContent, PRInt32 aNameSpaceID, nsIAtom* aA
* @param _classiiddef The name of the #define symbol that defines the IID
* for the class (e.g. NS_ISUPPORTS_IID)
*
*/
nsresult nsAttributeContent::QueryInterface(const nsIID& aIID, void** aInstancePtr)
{
*/
if (NULL == aInstancePtr) {
return NS_ERROR_NULL_POINTER;
}
if (aIID.Equals(NS_GET_IID(nsIContent))) {
*aInstancePtr = (void*) ((nsIContent*)this);
NS_ADDREF_THIS();
return NS_OK;
}
if (aIID.Equals(NS_GET_IID(nsITextContent))) {
*aInstancePtr = (void*) ((nsITextContent*)this);
NS_ADDREF_THIS();
return NS_OK;
}
if (aIID.Equals(NS_GET_IID(nsIAttributeContent))) {
*aInstancePtr = (void*) ((nsIAttributeContent*)this);
NS_ADDREF_THIS();
return NS_OK;
}
if (aIID.Equals(NS_GET_IID(nsISupports))) {
*aInstancePtr = (void*) ((nsISupports*)(nsIContent*)this);
NS_ADDREF_THIS();
return NS_OK;
}
return NS_NOINTERFACE;
}
NS_INTERFACE_MAP_BEGIN(nsAttributeContent)
NS_INTERFACE_MAP_ENTRY(nsIContent)
NS_INTERFACE_MAP_ENTRY(nsITextContent)
NS_INTERFACE_MAP_ENTRY(nsIAttributeContent)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContent)
NS_INTERFACE_MAP_END
NS_IMPL_ADDREF(nsAttributeContent)
NS_IMPL_RELEASE(nsAttributeContent)
//----------------------------------------------------------------------

Просмотреть файл

@ -517,9 +517,6 @@ nsGenericHTMLElement::DOMQueryInterface(nsIDOMHTMLElement *aElement,
inst = NS_STATIC_CAST(nsIDOMElementCSSInlineStyle *,
new nsGenericHTMLElementTearoff(this));
NS_ENSURE_TRUE(inst, NS_ERROR_OUT_OF_MEMORY);
} else if (aIID.Equals(NS_GET_IID(nsIDOM3Node))) {
inst = new nsNode3Tearoff(this);
NS_ENSURE_TRUE(inst, NS_ERROR_OUT_OF_MEMORY);
} else {
return NS_NOINTERFACE;
}

Просмотреть файл

@ -72,7 +72,7 @@ protected:
static nsIAtom* kModifiersAtom;
protected:
nsIDOMEventReceiver* mEventReceiver; // Both of these refs are weak.
nsCOMPtr<nsIDOMEventReceiver> mEventReceiver;
nsCOMPtr<nsIXBLPrototypeHandler> mProtoHandler;
nsXBLEventHandler* mNextHandler; // Handlers are chained for easy unloading later.

Просмотреть файл

@ -145,9 +145,6 @@ nsXMLElement::QueryInterface(REFNSIID aIID, void** aInstancePtr)
inst = NS_STATIC_CAST(nsIDOMElement *, this);
} else if (aIID.Equals(NS_GET_IID(nsIXMLContent))) {
inst = NS_STATIC_CAST(nsIXMLContent *, this);
} else if (aIID.Equals(NS_GET_IID(nsIDOM3Node))) {
inst = new nsNode3Tearoff(this);
NS_ENSURE_TRUE(inst, NS_ERROR_OUT_OF_MEMORY);
} else if (aIID.Equals(NS_GET_IID(nsIClassInfo))) {
inst = nsContentUtils::GetClassInfoInstance(eDOMClassInfo_Element_id,
GetElementIIDs,

Просмотреть файл

@ -250,6 +250,9 @@ public:
return mInner.SetBindingParent(aParent);
}
NS_IMETHOD_(PRBool) IsContentOfType(PRUint32 aFlags);
NS_IMETHOD GetListenerManager(nsIEventListenerManager **aResult) {
return mInner.GetListenerManager(this, aResult);
}
NS_IMETHOD SizeOf(nsISizeOfHandler* aSizer, PRUint32* aResult) const;