From b4f657bd5d7ce742df52f4d2cf8440fb85ce804a Mon Sep 17 00:00:00 2001 From: "hyatt%netscape.com" Date: Thu, 22 Jun 2000 00:36:19 +0000 Subject: [PATCH] XBL groundwork for 41145. r=ben git-svn-id: svn://10.0.0.236/trunk@72849 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/content/xbl/public/nsIXBLBinding.h | 1 + mozilla/content/xbl/src/nsXBLBinding.cpp | 167 ++++-------------- mozilla/content/xbl/src/nsXBLBinding.h | 161 +++++++++++++++++ mozilla/content/xbl/src/nsXBLEventHandler.cpp | 42 +++++ mozilla/content/xbl/src/nsXBLEventHandler.h | 9 + mozilla/content/xbl/src/nsXBLService.cpp | 1 + mozilla/layout/base/nsCSSFrameConstructor.cpp | 8 + .../html/style/src/nsCSSFrameConstructor.cpp | 8 + mozilla/layout/xbl/public/nsIXBLBinding.h | 1 + mozilla/layout/xbl/src/nsXBLBinding.cpp | 167 ++++-------------- mozilla/layout/xbl/src/nsXBLBinding.h | 161 +++++++++++++++++ mozilla/layout/xbl/src/nsXBLEventHandler.cpp | 42 +++++ mozilla/layout/xbl/src/nsXBLEventHandler.h | 9 + mozilla/layout/xbl/src/nsXBLService.cpp | 1 + 14 files changed, 516 insertions(+), 262 deletions(-) create mode 100644 mozilla/content/xbl/src/nsXBLBinding.h create mode 100644 mozilla/layout/xbl/src/nsXBLBinding.h diff --git a/mozilla/content/xbl/public/nsIXBLBinding.h b/mozilla/content/xbl/public/nsIXBLBinding.h index 9dc31084056..0a0216818c7 100644 --- a/mozilla/content/xbl/public/nsIXBLBinding.h +++ b/mozilla/content/xbl/public/nsIXBLBinding.h @@ -69,6 +69,7 @@ public: // Called when an attribute changes on a binding. NS_IMETHOD AttributeChanged(nsIAtom* aAttribute, PRInt32 aNameSpaceID, PRBool aRemoveFlag) = 0; + NS_IMETHOD UnhookEventHandlers() = 0; NS_IMETHOD ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocument) = 0; NS_IMETHOD GetBindingURI(nsString& aResult) = 0; diff --git a/mozilla/content/xbl/src/nsXBLBinding.cpp b/mozilla/content/xbl/src/nsXBLBinding.cpp index dd3a4d425f1..b1853259be6 100644 --- a/mozilla/content/xbl/src/nsXBLBinding.cpp +++ b/mozilla/content/xbl/src/nsXBLBinding.cpp @@ -67,7 +67,7 @@ #include "nsIDOMNamedNodeMap.h" #include "nsXBLEventHandler.h" -#include "nsIXBLBinding.h" +#include "nsXBLBinding.h" // Static IIDs/CIDs. Try to minimize these. static char kNameSpaceSeparator = ':'; @@ -130,130 +130,6 @@ XBLBindingCtor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rva return JS_FALSE; } -// *********************************************************************/ -// The XBLBinding class - -class nsXBLBinding: public nsIXBLBinding -{ - NS_DECL_ISUPPORTS - - // nsIXBLBinding - NS_IMETHOD GetBaseBinding(nsIXBLBinding** aResult); - NS_IMETHOD SetBaseBinding(nsIXBLBinding* aBinding); - - NS_IMETHOD GetAnonymousContent(nsIContent** aParent); - NS_IMETHOD SetAnonymousContent(nsIContent* aParent); - - NS_IMETHOD GetBindingElement(nsIContent** aResult); - NS_IMETHOD SetBindingElement(nsIContent* aElement); - - NS_IMETHOD GetBoundElement(nsIContent** aResult); - NS_IMETHOD SetBoundElement(nsIContent* aElement); - - NS_IMETHOD GenerateAnonymousContent(nsIContent* aBoundElement); - NS_IMETHOD InstallEventHandlers(nsIContent* aBoundElement); - NS_IMETHOD InstallProperties(nsIContent* aBoundElement); - - NS_IMETHOD GetBaseTag(PRInt32* aNameSpaceID, nsIAtom** aResult); - - NS_IMETHOD AttributeChanged(nsIAtom* aAttribute, PRInt32 aNameSpaceID, PRBool aRemoveFlag); - - NS_IMETHOD ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocument); - - NS_IMETHOD GetBindingURI(nsString& aResult); - - NS_IMETHOD GetInsertionPoint(nsIContent* aChild, nsIContent** aResult); - NS_IMETHOD GetSingleInsertionPoint(nsIContent** aResult, PRBool* aMultipleInsertionPoints); - - NS_IMETHOD IsStyleBinding(PRBool* aResult) { *aResult = mIsStyleBinding; return NS_OK; }; - NS_IMETHOD SetIsStyleBinding(PRBool aIsStyle) { mIsStyleBinding = aIsStyle; return NS_OK; }; - - NS_IMETHOD GetRootBinding(nsIXBLBinding** aResult); - NS_IMETHOD GetFirstStyleBinding(nsIXBLBinding** aResult); - -public: - nsXBLBinding(); - virtual ~nsXBLBinding(); - - NS_IMETHOD AddScriptEventListener(nsIContent* aElement, nsIAtom* aName, const nsString& aValue, REFNSIID aIID); - - PRBool AllowScripts(); - - static nsresult GetTextData(nsIContent *aParent, nsString& aResult); - -// Static members - static PRUint32 gRefCnt; - - static nsIAtom* kContentAtom; - static nsIAtom* kInterfaceAtom; - static nsIAtom* kHandlersAtom; - static nsIAtom* kExcludesAtom; - static nsIAtom* kIncludesAtom; - static nsIAtom* kInheritsAtom; - static nsIAtom* kTypeAtom; - static nsIAtom* kCapturerAtom; - static nsIAtom* kExtendsAtom; - static nsIAtom* kChildrenAtom; - static nsIAtom* kMethodAtom; - static nsIAtom* kArgumentAtom; - static nsIAtom* kBodyAtom; - static nsIAtom* kPropertyAtom; - static nsIAtom* kOnSetAtom; - static nsIAtom* kOnGetAtom; - static nsIAtom* kGetterAtom; - static nsIAtom* kSetterAtom; - static nsIAtom* kHTMLAtom; - static nsIAtom* kValueAtom; - static nsIAtom* kNameAtom; - static nsIAtom* kReadOnlyAtom; - static nsIAtom* kURIAtom; - static nsIAtom* kAttachToAtom; - - // Used to easily obtain the correct IID for an event. - struct EventHandlerMapEntry { - const char* mAttributeName; - nsIAtom* mAttributeAtom; - const nsIID* mHandlerIID; - }; - - static EventHandlerMapEntry kEventHandlerMap[]; - -// Internal member functions -protected: - NS_IMETHOD InitClass(const nsCString& aClassName, - nsIScriptContext* aContext, nsIDocument* aDocument, - void** aScriptObject, void** aClassObject); - - void GetImmediateChild(nsIAtom* aTag, nsIContent** aResult); - void GetNestedChild(nsIAtom* aTag, nsIContent* aContent, nsIContent** aResult); - void GetNestedChildren(nsIAtom* aTag, nsIContent* aContent, nsISupportsArray* aList); - void BuildInsertionTable(); - void GetNestedChildren(); - PRBool IsInExcludesList(nsIAtom* aTag, const nsString& aList); - - NS_IMETHOD ConstructAttributeTable(nsIContent* aElement); - - PRBool IsMouseHandler(const nsString& aName); - PRBool IsKeyHandler(const nsString& aName); - PRBool IsFocusHandler(const nsString& aName); - PRBool IsXULHandler(const nsString& aName); - - static void GetEventHandlerIID(nsIAtom* aName, nsIID* aIID, PRBool* aFound); - -// MEMBER VARIABLES -protected: - nsCOMPtr mBinding; // Strong. As long as we're around, the binding can't go away. - nsCOMPtr mContent; // Strong. Our anonymous content stays around with us. - nsCOMPtr mNextBinding; // Strong. The derived binding owns the base class bindings. - - nsIContent* mBoundElement; // [WEAK] We have a reference, but we don't own it. - - PRBool mIsStyleBinding; - - nsSupportsHashtable* mAttributeTable; // A table for attribute entries. - nsSupportsHashtable* mInsertionPointTable; // A table of insertion points. -}; - // Static initialization PRUint32 nsXBLBinding::gRefCnt = 0; @@ -338,7 +214,8 @@ NS_IMPL_ISUPPORTS1(nsXBLBinding, nsIXBLBinding) nsXBLBinding::nsXBLBinding(void) : mAttributeTable(nsnull), mInsertionPointTable(nsnull), - mIsStyleBinding(PR_TRUE) + mIsStyleBinding(PR_TRUE), + mFirstHandler(nsnull) { NS_INIT_REFCNT(); gRefCnt++; @@ -612,6 +489,7 @@ nsXBLBinding::InstallEventHandlers(nsIContent* aBoundElement) nsCOMPtr handlers; GetImmediateChild(kHandlersAtom, getter_AddRefs(handlers)); + nsXBLEventHandler* currHandler = nsnull; if (handlers && AllowScripts()) { // Now walk the handlers and add event listeners to the bound // element. @@ -659,6 +537,15 @@ nsXBLBinding::InstallEventHandlers(nsIContent* aBoundElement) nsXBLEventHandler* handler; NS_NewXBLEventHandler(mBoundElement, child, type, &handler); + // We chain all our event handlers together for easy + // removal later (if/when the binding dies). + if (!currHandler) + mFirstHandler = handler; + else + currHandler->SetNextHandler(handler); + + currHandler = handler; + // Figure out if we're using capturing or not. PRBool useCapture = PR_FALSE; nsAutoString capturer; @@ -1081,21 +968,34 @@ nsXBLBinding::AttributeChanged(nsIAtom* aAttribute, PRInt32 aNameSpaceID, PRBool return NS_OK; } +NS_IMETHODIMP +nsXBLBinding::UnhookEventHandlers() +{ + if (mFirstHandler) { + // Unhook our event handlers. + mFirstHandler->RemoveEventHandlers(); + mFirstHandler = nsnull; + } + + return NS_OK; +} + NS_IMETHODIMP nsXBLBinding::ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocument) { if (aOldDocument != aNewDocument) { + mFirstHandler = nsnull; + if (mNextBinding) mNextBinding->ChangeDocument(aOldDocument, aNewDocument); // Only style bindings get their prototypes unhooked. - // XXX Stay in sync! What if a layered binding has an ?! - if (!aNewDocument && !mIsStyleBinding) { + if (mIsStyleBinding) { // Now the binding dies. Unhook our prototypes. nsCOMPtr interfaceElement; GetImmediateChild(kInterfaceAtom, getter_AddRefs(interfaceElement)); - if (interfaceElement) { + if (interfaceElement) { nsCOMPtr global; aOldDocument->GetScriptGlobalObject(getter_AddRefs(global)); if (global) { @@ -1106,6 +1006,8 @@ nsXBLBinding::ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocumen nsCOMPtr owner(do_QueryInterface(mBoundElement)); owner->GetScriptObject(context, (void**)&scriptObject); if (scriptObject) { + // XXX Stay in sync! What if a layered binding has an ?! + // XXX Sanity check to make sure our class name matches // Pull ourselves out of the proto chain. JSContext* jscontext = (JSContext*)context->GetNativeContext(); @@ -1121,8 +1023,11 @@ nsXBLBinding::ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocumen // Update the anonymous content. nsCOMPtr anonymous; GetAnonymousContent(getter_AddRefs(anonymous)); - if (anonymous) - anonymous->SetDocument(aNewDocument, PR_TRUE, AllowScripts()); + if (anonymous) { + if (mIsStyleBinding) + anonymous->SetDocument(nsnull, PR_TRUE, AllowScripts()); // Kill it. + else anonymous->SetDocument(aNewDocument, PR_TRUE, AllowScripts()); // Keep it around. + } } return NS_OK; diff --git a/mozilla/content/xbl/src/nsXBLBinding.h b/mozilla/content/xbl/src/nsXBLBinding.h new file mode 100644 index 00000000000..eb7d671fb86 --- /dev/null +++ b/mozilla/content/xbl/src/nsXBLBinding.h @@ -0,0 +1,161 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Original Author: David W. Hyatt (hyatt@netscape.com) + * + * Contributor(s): + */ + +#include "nsCOMPtr.h" +#include "nsIXBLBinding.h" + +class nsIContent; +class nsIAtom; +class nsIDocument; +class nsIScriptContext; +class nsISupportsArray; +class nsSupportsHashtable; + +// *********************************************************************/ +// The XBLBinding class + +class nsXBLBinding: public nsIXBLBinding +{ + NS_DECL_ISUPPORTS + + // nsIXBLBinding + NS_IMETHOD GetBaseBinding(nsIXBLBinding** aResult); + NS_IMETHOD SetBaseBinding(nsIXBLBinding* aBinding); + + NS_IMETHOD GetAnonymousContent(nsIContent** aParent); + NS_IMETHOD SetAnonymousContent(nsIContent* aParent); + + NS_IMETHOD GetBindingElement(nsIContent** aResult); + NS_IMETHOD SetBindingElement(nsIContent* aElement); + + NS_IMETHOD GetBoundElement(nsIContent** aResult); + NS_IMETHOD SetBoundElement(nsIContent* aElement); + + NS_IMETHOD GenerateAnonymousContent(nsIContent* aBoundElement); + NS_IMETHOD InstallEventHandlers(nsIContent* aBoundElement); + NS_IMETHOD InstallProperties(nsIContent* aBoundElement); + + NS_IMETHOD GetBaseTag(PRInt32* aNameSpaceID, nsIAtom** aResult); + + NS_IMETHOD AttributeChanged(nsIAtom* aAttribute, PRInt32 aNameSpaceID, PRBool aRemoveFlag); + + NS_IMETHOD UnhookEventHandlers(); + NS_IMETHOD ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocument); + + NS_IMETHOD GetBindingURI(nsString& aResult); + + NS_IMETHOD GetInsertionPoint(nsIContent* aChild, nsIContent** aResult); + NS_IMETHOD GetSingleInsertionPoint(nsIContent** aResult, PRBool* aMultipleInsertionPoints); + + NS_IMETHOD IsStyleBinding(PRBool* aResult) { *aResult = mIsStyleBinding; return NS_OK; }; + NS_IMETHOD SetIsStyleBinding(PRBool aIsStyle) { mIsStyleBinding = aIsStyle; return NS_OK; }; + + NS_IMETHOD GetRootBinding(nsIXBLBinding** aResult); + NS_IMETHOD GetFirstStyleBinding(nsIXBLBinding** aResult); + +public: + nsXBLBinding(); + virtual ~nsXBLBinding(); + + NS_IMETHOD AddScriptEventListener(nsIContent* aElement, nsIAtom* aName, const nsString& aValue, REFNSIID aIID); + + PRBool AllowScripts(); + + static nsresult GetTextData(nsIContent *aParent, nsString& aResult); + +// Static members + static PRUint32 gRefCnt; + + static nsIAtom* kContentAtom; + static nsIAtom* kInterfaceAtom; + static nsIAtom* kHandlersAtom; + static nsIAtom* kExcludesAtom; + static nsIAtom* kIncludesAtom; + static nsIAtom* kInheritsAtom; + static nsIAtom* kTypeAtom; + static nsIAtom* kCapturerAtom; + static nsIAtom* kExtendsAtom; + static nsIAtom* kChildrenAtom; + static nsIAtom* kMethodAtom; + static nsIAtom* kArgumentAtom; + static nsIAtom* kBodyAtom; + static nsIAtom* kPropertyAtom; + static nsIAtom* kOnSetAtom; + static nsIAtom* kOnGetAtom; + static nsIAtom* kGetterAtom; + static nsIAtom* kSetterAtom; + static nsIAtom* kHTMLAtom; + static nsIAtom* kValueAtom; + static nsIAtom* kNameAtom; + static nsIAtom* kReadOnlyAtom; + static nsIAtom* kURIAtom; + static nsIAtom* kAttachToAtom; + + // 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 IsMouseHandler(const nsString& aName); + static PRBool IsKeyHandler(const nsString& aName); + static PRBool IsFocusHandler(const nsString& aName); + static PRBool IsXULHandler(const nsString& aName); + +// Internal member functions +protected: + NS_IMETHOD InitClass(const nsCString& aClassName, + nsIScriptContext* aContext, nsIDocument* aDocument, + void** aScriptObject, void** aClassObject); + + void GetImmediateChild(nsIAtom* aTag, nsIContent** aResult); + void GetNestedChild(nsIAtom* aTag, nsIContent* aContent, nsIContent** aResult); + void GetNestedChildren(nsIAtom* aTag, nsIContent* aContent, nsISupportsArray* aList); + void BuildInsertionTable(); + void GetNestedChildren(); + PRBool IsInExcludesList(nsIAtom* aTag, const nsString& aList); + + NS_IMETHOD ConstructAttributeTable(nsIContent* aElement); + + static void GetEventHandlerIID(nsIAtom* aName, nsIID* aIID, PRBool* aFound); + +// MEMBER VARIABLES +protected: + nsCOMPtr mBinding; // Strong. As long as we're around, the binding can't go away. + nsCOMPtr mContent; // Strong. Our anonymous content stays around with us. + nsCOMPtr 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. + + PRBool mIsStyleBinding; + + nsSupportsHashtable* mAttributeTable; // A table for attribute entries. + nsSupportsHashtable* mInsertionPointTable; // A table of insertion points. +}; diff --git a/mozilla/content/xbl/src/nsXBLEventHandler.cpp b/mozilla/content/xbl/src/nsXBLEventHandler.cpp index 647ff85ec25..b059446b764 100644 --- a/mozilla/content/xbl/src/nsXBLEventHandler.cpp +++ b/mozilla/content/xbl/src/nsXBLEventHandler.cpp @@ -41,6 +41,9 @@ #include "nsIDOMNSHTMLTextAreaElement.h" #include "nsIDOMNSHTMLInputElement.h" #include "nsIDOMText.h" +#include "nsIEventListenerManager.h" +#include "nsIDOMEventReceiver.h" +#include "nsXBLBinding.h" PRUint32 nsXBLEventHandler::gRefCnt = 0; nsIAtom* nsXBLEventHandler::kKeyCodeAtom = nsnull; @@ -63,6 +66,7 @@ nsXBLEventHandler::nsXBLEventHandler(nsIContent* aBoundElement, nsIContent* aHan mBoundElement = aBoundElement; mHandlerElement = aHandlerElement; mEventName.Assign(aEventName); + mNextHandler = nsnull; gRefCnt++; if (gRefCnt == 1) { kKeyCodeAtom = NS_NewAtom("keycode"); @@ -619,6 +623,44 @@ nsXBLEventHandler::GetController(nsIController** aResult) return NS_OK; } +void +nsXBLEventHandler::RemoveEventHandlers() +{ + // XXX Handle unhooking listeners attached to the document or window! + nsCOMPtr receiver(do_QueryInterface(mBoundElement)); + if (receiver) { + if (mNextHandler) + mNextHandler->RemoveEventHandlers(); + + // Figure out if we're using capturing or not. + PRBool useCapture = PR_FALSE; + nsAutoString capturer; + mHandlerElement->GetAttribute(kNameSpaceID_None, nsXBLBinding::kCapturerAtom, capturer); + if (capturer.EqualsWithConversion("true")) + useCapture = PR_TRUE; + + // XXX Will potentially be comma-separated + nsAutoString type; + mHandlerElement->GetAttribute(kNameSpaceID_None, nsXBLBinding::kTypeAtom, type); + + // Figure out our type. + PRBool mouse = nsXBLBinding::IsMouseHandler(type); + PRBool key = nsXBLBinding::IsKeyHandler(type); + PRBool focus = nsXBLBinding::IsFocusHandler(type); + PRBool xul = nsXBLBinding::IsXULHandler(type); + + // Remove the event listener. + if (mouse) + receiver->RemoveEventListener(type, (nsIDOMMouseListener*)this, useCapture); + else if(key) + receiver->RemoveEventListener(type, (nsIDOMKeyListener*)this, useCapture); + else if(focus) + receiver->RemoveEventListener(type, (nsIDOMFocusListener*)this, useCapture); + else + receiver->RemoveEventListener(type, (nsIDOMMenuListener*)this, useCapture); + } +} + /// Helpers that are relegated to the end of the file ///////////////////////////// enum { diff --git a/mozilla/content/xbl/src/nsXBLEventHandler.h b/mozilla/content/xbl/src/nsXBLEventHandler.h index 3c7e7882958..ca7217851c3 100644 --- a/mozilla/content/xbl/src/nsXBLEventHandler.h +++ b/mozilla/content/xbl/src/nsXBLEventHandler.h @@ -73,6 +73,13 @@ public: NS_DECL_ISUPPORTS +public: + void SetNextHandler(nsXBLEventHandler* aHandler) { + mNextHandler = aHandler; + } + + void RemoveEventHandlers(); + protected: inline PRBool KeyEventMatched(nsIDOMKeyEvent* aKeyEvent); inline PRBool MouseEventMatched(nsIDOMMouseEvent* aMouseEvent); @@ -104,6 +111,8 @@ protected: nsIContent* mBoundElement; // Both of these refs are weak. nsIContent* mHandlerElement; nsAutoString mEventName; + + nsXBLEventHandler* mNextHandler; // Handlers are chained for easy unloading later. }; extern nsresult diff --git a/mozilla/content/xbl/src/nsXBLService.cpp b/mozilla/content/xbl/src/nsXBLService.cpp index ac2b8d43874..5974bd9742e 100644 --- a/mozilla/content/xbl/src/nsXBLService.cpp +++ b/mozilla/content/xbl/src/nsXBLService.cpp @@ -357,6 +357,7 @@ nsXBLService::FlushStyleBindings(nsIContent* aContent) // Clear out the script references. nsCOMPtr document; aContent->GetDocument(*getter_AddRefs(document)); + styleBinding->UnhookEventHandlers(); styleBinding->ChangeDocument(document, nsnull); } diff --git a/mozilla/layout/base/nsCSSFrameConstructor.cpp b/mozilla/layout/base/nsCSSFrameConstructor.cpp index ec4ad683e50..8c2a6d3d4f0 100644 --- a/mozilla/layout/base/nsCSSFrameConstructor.cpp +++ b/mozilla/layout/base/nsCSSFrameConstructor.cpp @@ -6065,6 +6065,14 @@ nsCSSFrameConstructor::ConstructXULFrame(nsIPresShell* aPresShell, rv = NS_NewGrippyFrame(aPresShell, &newFrame); } // End of GRIPPY CONSTRUCTION logic + + else if (aTag != nsHTMLAtoms::html) { + nsCAutoString str("Invalid XUL tag encountered in file. Perhaps you used the wrong namespace?\n\nThe tag name is "); + nsAutoString tagName; + aTag->ToString(tagName); + str.AppendWithConversion(tagName); + NS_ERROR(str); + } } // If we succeeded in creating a frame then initialize it, process its diff --git a/mozilla/layout/html/style/src/nsCSSFrameConstructor.cpp b/mozilla/layout/html/style/src/nsCSSFrameConstructor.cpp index ec4ad683e50..8c2a6d3d4f0 100644 --- a/mozilla/layout/html/style/src/nsCSSFrameConstructor.cpp +++ b/mozilla/layout/html/style/src/nsCSSFrameConstructor.cpp @@ -6065,6 +6065,14 @@ nsCSSFrameConstructor::ConstructXULFrame(nsIPresShell* aPresShell, rv = NS_NewGrippyFrame(aPresShell, &newFrame); } // End of GRIPPY CONSTRUCTION logic + + else if (aTag != nsHTMLAtoms::html) { + nsCAutoString str("Invalid XUL tag encountered in file. Perhaps you used the wrong namespace?\n\nThe tag name is "); + nsAutoString tagName; + aTag->ToString(tagName); + str.AppendWithConversion(tagName); + NS_ERROR(str); + } } // If we succeeded in creating a frame then initialize it, process its diff --git a/mozilla/layout/xbl/public/nsIXBLBinding.h b/mozilla/layout/xbl/public/nsIXBLBinding.h index 9dc31084056..0a0216818c7 100644 --- a/mozilla/layout/xbl/public/nsIXBLBinding.h +++ b/mozilla/layout/xbl/public/nsIXBLBinding.h @@ -69,6 +69,7 @@ public: // Called when an attribute changes on a binding. NS_IMETHOD AttributeChanged(nsIAtom* aAttribute, PRInt32 aNameSpaceID, PRBool aRemoveFlag) = 0; + NS_IMETHOD UnhookEventHandlers() = 0; NS_IMETHOD ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocument) = 0; NS_IMETHOD GetBindingURI(nsString& aResult) = 0; diff --git a/mozilla/layout/xbl/src/nsXBLBinding.cpp b/mozilla/layout/xbl/src/nsXBLBinding.cpp index dd3a4d425f1..b1853259be6 100644 --- a/mozilla/layout/xbl/src/nsXBLBinding.cpp +++ b/mozilla/layout/xbl/src/nsXBLBinding.cpp @@ -67,7 +67,7 @@ #include "nsIDOMNamedNodeMap.h" #include "nsXBLEventHandler.h" -#include "nsIXBLBinding.h" +#include "nsXBLBinding.h" // Static IIDs/CIDs. Try to minimize these. static char kNameSpaceSeparator = ':'; @@ -130,130 +130,6 @@ XBLBindingCtor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rva return JS_FALSE; } -// *********************************************************************/ -// The XBLBinding class - -class nsXBLBinding: public nsIXBLBinding -{ - NS_DECL_ISUPPORTS - - // nsIXBLBinding - NS_IMETHOD GetBaseBinding(nsIXBLBinding** aResult); - NS_IMETHOD SetBaseBinding(nsIXBLBinding* aBinding); - - NS_IMETHOD GetAnonymousContent(nsIContent** aParent); - NS_IMETHOD SetAnonymousContent(nsIContent* aParent); - - NS_IMETHOD GetBindingElement(nsIContent** aResult); - NS_IMETHOD SetBindingElement(nsIContent* aElement); - - NS_IMETHOD GetBoundElement(nsIContent** aResult); - NS_IMETHOD SetBoundElement(nsIContent* aElement); - - NS_IMETHOD GenerateAnonymousContent(nsIContent* aBoundElement); - NS_IMETHOD InstallEventHandlers(nsIContent* aBoundElement); - NS_IMETHOD InstallProperties(nsIContent* aBoundElement); - - NS_IMETHOD GetBaseTag(PRInt32* aNameSpaceID, nsIAtom** aResult); - - NS_IMETHOD AttributeChanged(nsIAtom* aAttribute, PRInt32 aNameSpaceID, PRBool aRemoveFlag); - - NS_IMETHOD ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocument); - - NS_IMETHOD GetBindingURI(nsString& aResult); - - NS_IMETHOD GetInsertionPoint(nsIContent* aChild, nsIContent** aResult); - NS_IMETHOD GetSingleInsertionPoint(nsIContent** aResult, PRBool* aMultipleInsertionPoints); - - NS_IMETHOD IsStyleBinding(PRBool* aResult) { *aResult = mIsStyleBinding; return NS_OK; }; - NS_IMETHOD SetIsStyleBinding(PRBool aIsStyle) { mIsStyleBinding = aIsStyle; return NS_OK; }; - - NS_IMETHOD GetRootBinding(nsIXBLBinding** aResult); - NS_IMETHOD GetFirstStyleBinding(nsIXBLBinding** aResult); - -public: - nsXBLBinding(); - virtual ~nsXBLBinding(); - - NS_IMETHOD AddScriptEventListener(nsIContent* aElement, nsIAtom* aName, const nsString& aValue, REFNSIID aIID); - - PRBool AllowScripts(); - - static nsresult GetTextData(nsIContent *aParent, nsString& aResult); - -// Static members - static PRUint32 gRefCnt; - - static nsIAtom* kContentAtom; - static nsIAtom* kInterfaceAtom; - static nsIAtom* kHandlersAtom; - static nsIAtom* kExcludesAtom; - static nsIAtom* kIncludesAtom; - static nsIAtom* kInheritsAtom; - static nsIAtom* kTypeAtom; - static nsIAtom* kCapturerAtom; - static nsIAtom* kExtendsAtom; - static nsIAtom* kChildrenAtom; - static nsIAtom* kMethodAtom; - static nsIAtom* kArgumentAtom; - static nsIAtom* kBodyAtom; - static nsIAtom* kPropertyAtom; - static nsIAtom* kOnSetAtom; - static nsIAtom* kOnGetAtom; - static nsIAtom* kGetterAtom; - static nsIAtom* kSetterAtom; - static nsIAtom* kHTMLAtom; - static nsIAtom* kValueAtom; - static nsIAtom* kNameAtom; - static nsIAtom* kReadOnlyAtom; - static nsIAtom* kURIAtom; - static nsIAtom* kAttachToAtom; - - // Used to easily obtain the correct IID for an event. - struct EventHandlerMapEntry { - const char* mAttributeName; - nsIAtom* mAttributeAtom; - const nsIID* mHandlerIID; - }; - - static EventHandlerMapEntry kEventHandlerMap[]; - -// Internal member functions -protected: - NS_IMETHOD InitClass(const nsCString& aClassName, - nsIScriptContext* aContext, nsIDocument* aDocument, - void** aScriptObject, void** aClassObject); - - void GetImmediateChild(nsIAtom* aTag, nsIContent** aResult); - void GetNestedChild(nsIAtom* aTag, nsIContent* aContent, nsIContent** aResult); - void GetNestedChildren(nsIAtom* aTag, nsIContent* aContent, nsISupportsArray* aList); - void BuildInsertionTable(); - void GetNestedChildren(); - PRBool IsInExcludesList(nsIAtom* aTag, const nsString& aList); - - NS_IMETHOD ConstructAttributeTable(nsIContent* aElement); - - PRBool IsMouseHandler(const nsString& aName); - PRBool IsKeyHandler(const nsString& aName); - PRBool IsFocusHandler(const nsString& aName); - PRBool IsXULHandler(const nsString& aName); - - static void GetEventHandlerIID(nsIAtom* aName, nsIID* aIID, PRBool* aFound); - -// MEMBER VARIABLES -protected: - nsCOMPtr mBinding; // Strong. As long as we're around, the binding can't go away. - nsCOMPtr mContent; // Strong. Our anonymous content stays around with us. - nsCOMPtr mNextBinding; // Strong. The derived binding owns the base class bindings. - - nsIContent* mBoundElement; // [WEAK] We have a reference, but we don't own it. - - PRBool mIsStyleBinding; - - nsSupportsHashtable* mAttributeTable; // A table for attribute entries. - nsSupportsHashtable* mInsertionPointTable; // A table of insertion points. -}; - // Static initialization PRUint32 nsXBLBinding::gRefCnt = 0; @@ -338,7 +214,8 @@ NS_IMPL_ISUPPORTS1(nsXBLBinding, nsIXBLBinding) nsXBLBinding::nsXBLBinding(void) : mAttributeTable(nsnull), mInsertionPointTable(nsnull), - mIsStyleBinding(PR_TRUE) + mIsStyleBinding(PR_TRUE), + mFirstHandler(nsnull) { NS_INIT_REFCNT(); gRefCnt++; @@ -612,6 +489,7 @@ nsXBLBinding::InstallEventHandlers(nsIContent* aBoundElement) nsCOMPtr handlers; GetImmediateChild(kHandlersAtom, getter_AddRefs(handlers)); + nsXBLEventHandler* currHandler = nsnull; if (handlers && AllowScripts()) { // Now walk the handlers and add event listeners to the bound // element. @@ -659,6 +537,15 @@ nsXBLBinding::InstallEventHandlers(nsIContent* aBoundElement) nsXBLEventHandler* handler; NS_NewXBLEventHandler(mBoundElement, child, type, &handler); + // We chain all our event handlers together for easy + // removal later (if/when the binding dies). + if (!currHandler) + mFirstHandler = handler; + else + currHandler->SetNextHandler(handler); + + currHandler = handler; + // Figure out if we're using capturing or not. PRBool useCapture = PR_FALSE; nsAutoString capturer; @@ -1081,21 +968,34 @@ nsXBLBinding::AttributeChanged(nsIAtom* aAttribute, PRInt32 aNameSpaceID, PRBool return NS_OK; } +NS_IMETHODIMP +nsXBLBinding::UnhookEventHandlers() +{ + if (mFirstHandler) { + // Unhook our event handlers. + mFirstHandler->RemoveEventHandlers(); + mFirstHandler = nsnull; + } + + return NS_OK; +} + NS_IMETHODIMP nsXBLBinding::ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocument) { if (aOldDocument != aNewDocument) { + mFirstHandler = nsnull; + if (mNextBinding) mNextBinding->ChangeDocument(aOldDocument, aNewDocument); // Only style bindings get their prototypes unhooked. - // XXX Stay in sync! What if a layered binding has an ?! - if (!aNewDocument && !mIsStyleBinding) { + if (mIsStyleBinding) { // Now the binding dies. Unhook our prototypes. nsCOMPtr interfaceElement; GetImmediateChild(kInterfaceAtom, getter_AddRefs(interfaceElement)); - if (interfaceElement) { + if (interfaceElement) { nsCOMPtr global; aOldDocument->GetScriptGlobalObject(getter_AddRefs(global)); if (global) { @@ -1106,6 +1006,8 @@ nsXBLBinding::ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocumen nsCOMPtr owner(do_QueryInterface(mBoundElement)); owner->GetScriptObject(context, (void**)&scriptObject); if (scriptObject) { + // XXX Stay in sync! What if a layered binding has an ?! + // XXX Sanity check to make sure our class name matches // Pull ourselves out of the proto chain. JSContext* jscontext = (JSContext*)context->GetNativeContext(); @@ -1121,8 +1023,11 @@ nsXBLBinding::ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocumen // Update the anonymous content. nsCOMPtr anonymous; GetAnonymousContent(getter_AddRefs(anonymous)); - if (anonymous) - anonymous->SetDocument(aNewDocument, PR_TRUE, AllowScripts()); + if (anonymous) { + if (mIsStyleBinding) + anonymous->SetDocument(nsnull, PR_TRUE, AllowScripts()); // Kill it. + else anonymous->SetDocument(aNewDocument, PR_TRUE, AllowScripts()); // Keep it around. + } } return NS_OK; diff --git a/mozilla/layout/xbl/src/nsXBLBinding.h b/mozilla/layout/xbl/src/nsXBLBinding.h new file mode 100644 index 00000000000..eb7d671fb86 --- /dev/null +++ b/mozilla/layout/xbl/src/nsXBLBinding.h @@ -0,0 +1,161 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is Netscape Communications + * Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Original Author: David W. Hyatt (hyatt@netscape.com) + * + * Contributor(s): + */ + +#include "nsCOMPtr.h" +#include "nsIXBLBinding.h" + +class nsIContent; +class nsIAtom; +class nsIDocument; +class nsIScriptContext; +class nsISupportsArray; +class nsSupportsHashtable; + +// *********************************************************************/ +// The XBLBinding class + +class nsXBLBinding: public nsIXBLBinding +{ + NS_DECL_ISUPPORTS + + // nsIXBLBinding + NS_IMETHOD GetBaseBinding(nsIXBLBinding** aResult); + NS_IMETHOD SetBaseBinding(nsIXBLBinding* aBinding); + + NS_IMETHOD GetAnonymousContent(nsIContent** aParent); + NS_IMETHOD SetAnonymousContent(nsIContent* aParent); + + NS_IMETHOD GetBindingElement(nsIContent** aResult); + NS_IMETHOD SetBindingElement(nsIContent* aElement); + + NS_IMETHOD GetBoundElement(nsIContent** aResult); + NS_IMETHOD SetBoundElement(nsIContent* aElement); + + NS_IMETHOD GenerateAnonymousContent(nsIContent* aBoundElement); + NS_IMETHOD InstallEventHandlers(nsIContent* aBoundElement); + NS_IMETHOD InstallProperties(nsIContent* aBoundElement); + + NS_IMETHOD GetBaseTag(PRInt32* aNameSpaceID, nsIAtom** aResult); + + NS_IMETHOD AttributeChanged(nsIAtom* aAttribute, PRInt32 aNameSpaceID, PRBool aRemoveFlag); + + NS_IMETHOD UnhookEventHandlers(); + NS_IMETHOD ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocument); + + NS_IMETHOD GetBindingURI(nsString& aResult); + + NS_IMETHOD GetInsertionPoint(nsIContent* aChild, nsIContent** aResult); + NS_IMETHOD GetSingleInsertionPoint(nsIContent** aResult, PRBool* aMultipleInsertionPoints); + + NS_IMETHOD IsStyleBinding(PRBool* aResult) { *aResult = mIsStyleBinding; return NS_OK; }; + NS_IMETHOD SetIsStyleBinding(PRBool aIsStyle) { mIsStyleBinding = aIsStyle; return NS_OK; }; + + NS_IMETHOD GetRootBinding(nsIXBLBinding** aResult); + NS_IMETHOD GetFirstStyleBinding(nsIXBLBinding** aResult); + +public: + nsXBLBinding(); + virtual ~nsXBLBinding(); + + NS_IMETHOD AddScriptEventListener(nsIContent* aElement, nsIAtom* aName, const nsString& aValue, REFNSIID aIID); + + PRBool AllowScripts(); + + static nsresult GetTextData(nsIContent *aParent, nsString& aResult); + +// Static members + static PRUint32 gRefCnt; + + static nsIAtom* kContentAtom; + static nsIAtom* kInterfaceAtom; + static nsIAtom* kHandlersAtom; + static nsIAtom* kExcludesAtom; + static nsIAtom* kIncludesAtom; + static nsIAtom* kInheritsAtom; + static nsIAtom* kTypeAtom; + static nsIAtom* kCapturerAtom; + static nsIAtom* kExtendsAtom; + static nsIAtom* kChildrenAtom; + static nsIAtom* kMethodAtom; + static nsIAtom* kArgumentAtom; + static nsIAtom* kBodyAtom; + static nsIAtom* kPropertyAtom; + static nsIAtom* kOnSetAtom; + static nsIAtom* kOnGetAtom; + static nsIAtom* kGetterAtom; + static nsIAtom* kSetterAtom; + static nsIAtom* kHTMLAtom; + static nsIAtom* kValueAtom; + static nsIAtom* kNameAtom; + static nsIAtom* kReadOnlyAtom; + static nsIAtom* kURIAtom; + static nsIAtom* kAttachToAtom; + + // 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 IsMouseHandler(const nsString& aName); + static PRBool IsKeyHandler(const nsString& aName); + static PRBool IsFocusHandler(const nsString& aName); + static PRBool IsXULHandler(const nsString& aName); + +// Internal member functions +protected: + NS_IMETHOD InitClass(const nsCString& aClassName, + nsIScriptContext* aContext, nsIDocument* aDocument, + void** aScriptObject, void** aClassObject); + + void GetImmediateChild(nsIAtom* aTag, nsIContent** aResult); + void GetNestedChild(nsIAtom* aTag, nsIContent* aContent, nsIContent** aResult); + void GetNestedChildren(nsIAtom* aTag, nsIContent* aContent, nsISupportsArray* aList); + void BuildInsertionTable(); + void GetNestedChildren(); + PRBool IsInExcludesList(nsIAtom* aTag, const nsString& aList); + + NS_IMETHOD ConstructAttributeTable(nsIContent* aElement); + + static void GetEventHandlerIID(nsIAtom* aName, nsIID* aIID, PRBool* aFound); + +// MEMBER VARIABLES +protected: + nsCOMPtr mBinding; // Strong. As long as we're around, the binding can't go away. + nsCOMPtr mContent; // Strong. Our anonymous content stays around with us. + nsCOMPtr 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. + + PRBool mIsStyleBinding; + + nsSupportsHashtable* mAttributeTable; // A table for attribute entries. + nsSupportsHashtable* mInsertionPointTable; // A table of insertion points. +}; diff --git a/mozilla/layout/xbl/src/nsXBLEventHandler.cpp b/mozilla/layout/xbl/src/nsXBLEventHandler.cpp index 647ff85ec25..b059446b764 100644 --- a/mozilla/layout/xbl/src/nsXBLEventHandler.cpp +++ b/mozilla/layout/xbl/src/nsXBLEventHandler.cpp @@ -41,6 +41,9 @@ #include "nsIDOMNSHTMLTextAreaElement.h" #include "nsIDOMNSHTMLInputElement.h" #include "nsIDOMText.h" +#include "nsIEventListenerManager.h" +#include "nsIDOMEventReceiver.h" +#include "nsXBLBinding.h" PRUint32 nsXBLEventHandler::gRefCnt = 0; nsIAtom* nsXBLEventHandler::kKeyCodeAtom = nsnull; @@ -63,6 +66,7 @@ nsXBLEventHandler::nsXBLEventHandler(nsIContent* aBoundElement, nsIContent* aHan mBoundElement = aBoundElement; mHandlerElement = aHandlerElement; mEventName.Assign(aEventName); + mNextHandler = nsnull; gRefCnt++; if (gRefCnt == 1) { kKeyCodeAtom = NS_NewAtom("keycode"); @@ -619,6 +623,44 @@ nsXBLEventHandler::GetController(nsIController** aResult) return NS_OK; } +void +nsXBLEventHandler::RemoveEventHandlers() +{ + // XXX Handle unhooking listeners attached to the document or window! + nsCOMPtr receiver(do_QueryInterface(mBoundElement)); + if (receiver) { + if (mNextHandler) + mNextHandler->RemoveEventHandlers(); + + // Figure out if we're using capturing or not. + PRBool useCapture = PR_FALSE; + nsAutoString capturer; + mHandlerElement->GetAttribute(kNameSpaceID_None, nsXBLBinding::kCapturerAtom, capturer); + if (capturer.EqualsWithConversion("true")) + useCapture = PR_TRUE; + + // XXX Will potentially be comma-separated + nsAutoString type; + mHandlerElement->GetAttribute(kNameSpaceID_None, nsXBLBinding::kTypeAtom, type); + + // Figure out our type. + PRBool mouse = nsXBLBinding::IsMouseHandler(type); + PRBool key = nsXBLBinding::IsKeyHandler(type); + PRBool focus = nsXBLBinding::IsFocusHandler(type); + PRBool xul = nsXBLBinding::IsXULHandler(type); + + // Remove the event listener. + if (mouse) + receiver->RemoveEventListener(type, (nsIDOMMouseListener*)this, useCapture); + else if(key) + receiver->RemoveEventListener(type, (nsIDOMKeyListener*)this, useCapture); + else if(focus) + receiver->RemoveEventListener(type, (nsIDOMFocusListener*)this, useCapture); + else + receiver->RemoveEventListener(type, (nsIDOMMenuListener*)this, useCapture); + } +} + /// Helpers that are relegated to the end of the file ///////////////////////////// enum { diff --git a/mozilla/layout/xbl/src/nsXBLEventHandler.h b/mozilla/layout/xbl/src/nsXBLEventHandler.h index 3c7e7882958..ca7217851c3 100644 --- a/mozilla/layout/xbl/src/nsXBLEventHandler.h +++ b/mozilla/layout/xbl/src/nsXBLEventHandler.h @@ -73,6 +73,13 @@ public: NS_DECL_ISUPPORTS +public: + void SetNextHandler(nsXBLEventHandler* aHandler) { + mNextHandler = aHandler; + } + + void RemoveEventHandlers(); + protected: inline PRBool KeyEventMatched(nsIDOMKeyEvent* aKeyEvent); inline PRBool MouseEventMatched(nsIDOMMouseEvent* aMouseEvent); @@ -104,6 +111,8 @@ protected: nsIContent* mBoundElement; // Both of these refs are weak. nsIContent* mHandlerElement; nsAutoString mEventName; + + nsXBLEventHandler* mNextHandler; // Handlers are chained for easy unloading later. }; extern nsresult diff --git a/mozilla/layout/xbl/src/nsXBLService.cpp b/mozilla/layout/xbl/src/nsXBLService.cpp index ac2b8d43874..5974bd9742e 100644 --- a/mozilla/layout/xbl/src/nsXBLService.cpp +++ b/mozilla/layout/xbl/src/nsXBLService.cpp @@ -357,6 +357,7 @@ nsXBLService::FlushStyleBindings(nsIContent* aContent) // Clear out the script references. nsCOMPtr document; aContent->GetDocument(*getter_AddRefs(document)); + styleBinding->UnhookEventHandlers(); styleBinding->ChangeDocument(document, nsnull); }