Back to index

lightning-sunbird  0.9+nobinonly
nsGenericElement.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* vim: set ts=2 sw=2 et tw=78: */
00003 /* ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is Mozilla Communicator client code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 #include "nsGenericElement.h"
00039 
00040 #include "nsDOMAttribute.h"
00041 #include "nsDOMAttributeMap.h"
00042 #include "nsIAtom.h"
00043 #include "nsINodeInfo.h"
00044 #include "nsIDocument.h"
00045 #include "nsIDocumentEncoder.h"
00046 #include "nsIDOMNodeList.h"
00047 #include "nsIDOMDocument.h"
00048 #include "nsIDOMRange.h"
00049 #include "nsIDOMText.h"
00050 #include "nsIDOMEventReceiver.h"
00051 #include "nsITextContent.h"
00052 #include "nsIContentIterator.h"
00053 #include "nsRange.h"
00054 #include "nsIEventListenerManager.h"
00055 #include "nsILinkHandler.h"
00056 #include "nsIScriptGlobalObject.h"
00057 #include "nsISupportsArray.h"
00058 #include "nsIURL.h"
00059 #include "nsNetUtil.h"
00060 #include "nsIFrame.h"
00061 #include "nsIPresShell.h"
00062 #include "nsPresContext.h"
00063 #include "nsStyleConsts.h"
00064 #include "nsIView.h"
00065 #include "nsIViewManager.h"
00066 #include "nsString.h"
00067 #include "nsUnicharUtils.h"
00068 #include "nsIEventStateManager.h"
00069 #include "nsIDOMEvent.h"
00070 #include "nsIPrivateDOMEvent.h"
00071 #include "nsDOMCID.h"
00072 #include "nsIServiceManager.h"
00073 #include "nsIDOMCSSStyleDeclaration.h"
00074 #include "nsDOMCSSDeclaration.h"
00075 #include "nsINameSpaceManager.h"
00076 #include "nsContentList.h"
00077 #include "nsDOMError.h"
00078 #include "nsDOMString.h"
00079 #include "nsIScriptSecurityManager.h"
00080 #include "nsIDOMMutationEvent.h"
00081 #include "nsMutationEvent.h"
00082 
00083 #include "nsIBindingManager.h"
00084 #include "nsXBLBinding.h"
00085 #include "nsIDOMCSSStyleDeclaration.h"
00086 #include "nsIDOMViewCSS.h"
00087 #include "nsIXBLService.h"
00088 #include "nsPIDOMWindow.h"
00089 #include "nsIBoxObject.h"
00090 #include "nsPIBoxObject.h"
00091 #include "nsIDOMNSDocument.h"
00092 
00093 #include "nsLayoutAtoms.h"
00094 #include "nsHTMLAtoms.h"
00095 #include "nsContentUtils.h"
00096 #include "nsIJSContextStack.h"
00097 
00098 #include "nsIServiceManager.h"
00099 #include "nsIDOMEventListener.h"
00100 
00101 #include "nsIWebNavigation.h"
00102 #include "nsIBaseWindow.h"
00103 
00104 #include "jsapi.h"
00105 
00106 #include "nsIDOMXPathEvaluator.h"
00107 #include "nsNodeInfoManager.h"
00108 #include "nsICategoryManager.h"
00109 #include "nsIDOMNSFeatureFactory.h"
00110 #include "nsIDOMDocumentType.h"
00111 
00112 
00127 static nsresult
00128 doInsertChildAt(nsIContent* aKid, PRUint32 aIndex, PRBool aNotify,
00129                 nsIContent* aParent, nsIDocument* aDocument,
00130                 nsAttrAndChildArray& aChildArray);
00131 
00146 extern nsresult
00147 doRemoveChildAt(PRUint32 aIndex, PRBool aNotify, nsIContent* aKid,
00148                 nsIContent* aParent, nsIDocument* aDocument,
00149                 nsAttrAndChildArray& aChildArray);
00150 
00151 #ifdef MOZ_SVG
00152 PRBool NS_SVG_TestFeature(const nsAString &fstr);
00153 #endif /* MOZ_SVG */
00154 
00155 #ifdef DEBUG_waterson
00156 
00160 void
00161 DebugListContentTree(nsIContent* aElement)
00162 {
00163   aElement->List(stdout, 0);
00164   printf("\n");
00165 }
00166 
00167 #endif
00168 
00169 PLDHashTable nsGenericElement::sRangeListsHash;
00170 PLDHashTable nsGenericElement::sEventListenerManagersHash;
00171 PRInt32 nsIContent::sTabFocusModel = eTabFocus_any;
00172 PRBool nsIContent::sTabFocusModelAppliesToXUL = PR_FALSE;
00173 nsresult NS_NewContentIterator(nsIContentIterator** aInstancePtrResult);
00174 //----------------------------------------------------------------------
00175 
00176 nsChildContentList::nsChildContentList(nsIContent *aContent)
00177 {
00178   // This reference is not reference-counted. The content
00179   // object tells us when its about to go away.
00180   mContent = aContent;
00181 }
00182 
00183 nsChildContentList::~nsChildContentList()
00184 {
00185 }
00186 
00187 NS_IMETHODIMP
00188 nsChildContentList::GetLength(PRUint32* aLength)
00189 {
00190   if (mContent) {
00191     *aLength = mContent->GetChildCount();
00192   } else {
00193     *aLength = 0;
00194   }
00195 
00196   return NS_OK;
00197 }
00198 
00199 NS_IMETHODIMP
00200 nsChildContentList::Item(PRUint32 aIndex, nsIDOMNode** aReturn)
00201 {
00202   if (mContent) {
00203     nsIContent *content = mContent->GetChildAt(aIndex);
00204     if (content) {
00205       return CallQueryInterface(content, aReturn);
00206     }
00207   }
00208 
00209   *aReturn = nsnull;
00210 
00211   return NS_OK;
00212 }
00213 
00214 void
00215 nsChildContentList::DropReference()
00216 {
00217   mContent = nsnull;
00218 }
00219 
00220 NS_INTERFACE_MAP_BEGIN(nsNode3Tearoff)
00221   NS_INTERFACE_MAP_ENTRY(nsIDOM3Node)
00222 NS_INTERFACE_MAP_END_AGGREGATED(mContent)
00223 
00224 NS_IMPL_ADDREF(nsNode3Tearoff)
00225 NS_IMPL_RELEASE(nsNode3Tearoff)
00226 
00227 NS_IMETHODIMP
00228 nsNode3Tearoff::GetBaseURI(nsAString& aURI)
00229 {
00230   nsCOMPtr<nsIURI> baseURI = mContent->GetBaseURI();
00231   nsCAutoString spec;
00232 
00233   if (baseURI) {
00234     baseURI->GetSpec(spec);
00235   }
00236 
00237   CopyUTF8toUTF16(spec, aURI);
00238   
00239   return NS_OK;
00240 }
00241 
00242 NS_IMETHODIMP
00243 nsNode3Tearoff::GetTextContent(nsAString &aTextContent)
00244 {
00245   nsCOMPtr<nsIDOMNode> node(do_QueryInterface(mContent));
00246   NS_ASSERTION(node, "We have an nsIContent which doesn't support nsIDOMNode");
00247 
00248   PRUint16 nodeType;
00249   node->GetNodeType(&nodeType);
00250   if (nodeType == nsIDOMNode::DOCUMENT_TYPE_NODE ||
00251       nodeType == nsIDOMNode::NOTATION_NODE) {
00252     SetDOMStringToNull(aTextContent);
00253 
00254     return NS_OK;
00255   }
00256 
00257   if (nodeType == nsIDOMNode::TEXT_NODE ||
00258       nodeType == nsIDOMNode::CDATA_SECTION_NODE ||
00259       nodeType == nsIDOMNode::COMMENT_NODE ||
00260       nodeType == nsIDOMNode::PROCESSING_INSTRUCTION_NODE) {
00261     return node->GetNodeValue(aTextContent);
00262   }
00263 
00264   return GetTextContent(mContent, aTextContent);
00265 }
00266 
00267 // static
00268 nsresult
00269 nsNode3Tearoff::GetTextContent(nsIContent *aContent,
00270                                nsAString &aTextContent)
00271 {
00272   NS_ENSURE_ARG_POINTER(aContent);
00273 
00274   nsCOMPtr<nsIContentIterator> iter;
00275   NS_NewContentIterator(getter_AddRefs(iter));
00276   iter->Init(aContent);
00277 
00278   nsString tempString;
00279   aTextContent.Truncate();
00280   while (!iter->IsDone()) {
00281     nsIContent *content = iter->GetCurrentNode();
00282     if (content->IsContentOfType(nsIContent::eTEXT)) {
00283       nsCOMPtr<nsITextContent> textContent(do_QueryInterface(iter->GetCurrentNode()));
00284       if (textContent)
00285         textContent->AppendTextTo(aTextContent);
00286     }
00287     iter->Next();
00288   }
00289   return NS_OK;
00290 }
00291 
00292 NS_IMETHODIMP
00293 nsNode3Tearoff::SetTextContent(const nsAString &aTextContent)
00294 {
00295   nsCOMPtr<nsIDOMNode> node(do_QueryInterface(mContent));
00296   NS_ASSERTION(node, "We have an nsIContent which doesn't support nsIDOMNode");
00297 
00298   PRUint16 nodeType;
00299   node->GetNodeType(&nodeType);
00300   if (nodeType == nsIDOMNode::DOCUMENT_TYPE_NODE ||
00301       nodeType == nsIDOMNode::NOTATION_NODE) {
00302     return NS_OK;
00303   }
00304 
00305   if (nodeType == nsIDOMNode::TEXT_NODE ||
00306       nodeType == nsIDOMNode::CDATA_SECTION_NODE ||
00307       nodeType == nsIDOMNode::COMMENT_NODE ||
00308       nodeType == nsIDOMNode::PROCESSING_INSTRUCTION_NODE) {
00309     return node->SetNodeValue(aTextContent);
00310   }
00311 
00312   return SetTextContent(mContent, aTextContent);
00313 }
00314 
00315 // static
00316 nsresult
00317 nsNode3Tearoff::SetTextContent(nsIContent* aContent,
00318                                const nsAString &aTextContent)
00319 {
00320   PRUint32 childCount = aContent->GetChildCount();
00321 
00322   // i is unsigned, so i >= is always true
00323   for (PRUint32 i = childCount; i-- != 0; ) {
00324     aContent->RemoveChildAt(i, PR_TRUE);
00325   }
00326 
00327   if (!aTextContent.IsEmpty()) {
00328     nsCOMPtr<nsITextContent> textContent;
00329     nsresult rv = NS_NewTextNode(getter_AddRefs(textContent),
00330                                  aContent->GetNodeInfo()->NodeInfoManager());
00331     NS_ENSURE_SUCCESS(rv, rv);
00332 
00333     textContent->SetText(aTextContent, PR_TRUE);
00334 
00335     aContent->AppendChildTo(textContent, PR_TRUE);
00336   }
00337 
00338   return NS_OK;
00339 }
00340 
00341 NS_IMETHODIMP
00342 nsNode3Tearoff::CompareDocumentPosition(nsIDOMNode* aOther,
00343                                         PRUint16* aReturn)
00344 {
00345   NS_ENSURE_ARG_POINTER(aOther);
00346   NS_PRECONDITION(aReturn, "Must have an out parameter");
00347 
00348   nsCOMPtr<nsIDOMNode> node(do_QueryInterface(mContent));
00349   if (node == aOther) {
00350     // If the two nodes being compared are the same node,
00351     // then no flags are set on the return.
00352     *aReturn = 0;
00353     return NS_OK;
00354   }
00355 
00356   PRUint16 mask = 0;
00357 
00358   // If the other node is an attribute, document, or document fragment,
00359   // we can find the position easier by comparing this node relative to
00360   // the other node, and then reversing positions.
00361   PRUint16 otherType = 0;
00362   aOther->GetNodeType(&otherType);
00363   if (otherType == nsIDOMNode::ATTRIBUTE_NODE ||
00364       otherType == nsIDOMNode::DOCUMENT_NODE  ||
00365       otherType == nsIDOMNode::DOCUMENT_FRAGMENT_NODE) {
00366     PRUint16 otherMask = 0;
00367     nsCOMPtr<nsIDOM3Node> other(do_QueryInterface(aOther));
00368     other->CompareDocumentPosition(node, &otherMask);
00369 
00370     *aReturn = nsContentUtils::ReverseDocumentPosition(otherMask);
00371     return NS_OK;
00372   }
00373 
00374 #ifdef DEBUG
00375   {
00376     PRUint16 nodeType = 0;
00377     node->GetNodeType(&nodeType);
00378 
00379     if (nodeType == nsIDOMNode::ENTITY_NODE ||
00380         nodeType == nsIDOMNode::NOTATION_NODE) {
00381       NS_NOTYETIMPLEMENTED("Entities and Notations are not fully supported yet");
00382     }
00383     else {
00384       NS_ASSERTION((nodeType == nsIDOMNode::ELEMENT_NODE ||
00385                     nodeType == nsIDOMNode::TEXT_NODE ||
00386                     nodeType == nsIDOMNode::CDATA_SECTION_NODE ||
00387                     nodeType == nsIDOMNode::ENTITY_REFERENCE_NODE ||
00388                     nodeType == nsIDOMNode::PROCESSING_INSTRUCTION_NODE ||
00389                     nodeType == nsIDOMNode::COMMENT_NODE),
00390                    "Invalid node type!");
00391     }
00392   }
00393 #endif
00394 
00395   mask |= nsContentUtils::ComparePositionWithAncestors(node, aOther);
00396 
00397   *aReturn = mask;
00398   return NS_OK;
00399 }
00400 
00401 NS_IMETHODIMP
00402 nsNode3Tearoff::IsSameNode(nsIDOMNode* aOther,
00403                            PRBool* aReturn)
00404 {
00405   PRBool sameNode = PR_FALSE;
00406 
00407   nsCOMPtr<nsIContent> other(do_QueryInterface(aOther));
00408   if (mContent == other) {
00409     sameNode = PR_TRUE;
00410   }
00411 
00412   *aReturn = sameNode;
00413   return NS_OK;
00414 }
00415 
00416 NS_IMETHODIMP
00417 nsNode3Tearoff::IsEqualNode(nsIDOMNode* aOther, PRBool* aReturn)
00418 {
00419   NS_NOTYETIMPLEMENTED("nsNode3Tearoff::IsEqualNode()");
00420 
00421   return NS_ERROR_NOT_IMPLEMENTED;
00422 }
00423 
00424 NS_IMETHODIMP
00425 nsNode3Tearoff::GetFeature(const nsAString& aFeature,
00426                            const nsAString& aVersion,
00427                            nsISupports** aReturn)
00428 {
00429   return nsGenericElement::InternalGetFeature(this, aFeature, aVersion, aReturn);
00430 }
00431 
00432 NS_IMETHODIMP
00433 nsNode3Tearoff::SetUserData(const nsAString& aKey,
00434                             nsIVariant* aData,
00435                             nsIDOMUserDataHandler* aHandler,
00436                             nsIVariant** aReturn)
00437 {
00438   NS_NOTYETIMPLEMENTED("nsNode3Tearoff::SetUserData()");
00439 
00440   return NS_ERROR_NOT_IMPLEMENTED;
00441 }
00442 
00443 NS_IMETHODIMP
00444 nsNode3Tearoff::GetUserData(const nsAString& aKey,
00445                             nsIVariant** aReturn)
00446 {
00447   NS_NOTYETIMPLEMENTED("nsNode3Tearoff::GetUserData()");
00448 
00449   return NS_ERROR_NOT_IMPLEMENTED;
00450 }
00451 
00452 NS_IMETHODIMP
00453 nsNode3Tearoff::LookupPrefix(const nsAString& aNamespaceURI,
00454                              nsAString& aPrefix)
00455 {
00456   SetDOMStringToNull(aPrefix);
00457 
00458   // XXX Waiting for DOM spec to list error codes.
00459 
00460   // Get the namespace id for the URI
00461   PRInt32 namespaceId;
00462   nsContentUtils::GetNSManagerWeakRef()->GetNameSpaceID(aNamespaceURI,
00463                                                         &namespaceId);
00464   if (namespaceId == kNameSpaceID_Unknown) {
00465     return NS_OK;
00466   }
00467 
00468   nsCOMPtr<nsIAtom> name, prefix;
00469   PRInt32 namespace_id;
00470   nsAutoString ns;
00471 
00472   // Trace up the content parent chain looking for the namespace
00473   // declaration that defines the aNamespaceURI namespace. Once found,
00474   // return the prefix (i.e. the attribute localName).
00475   for (nsIContent* content = mContent; content;
00476        content = content->GetParent()) {
00477     PRUint32 attrCount = content->GetAttrCount();
00478 
00479     for (PRUint32 i = 0; i < attrCount; ++i) {
00480       content->GetAttrNameAt(i, &namespace_id, getter_AddRefs(name),
00481                              getter_AddRefs(prefix));
00482 
00483       if (namespace_id == kNameSpaceID_XMLNS) {
00484         nsresult rv = content->GetAttr(namespace_id, name, ns);
00485 
00486         if (rv == NS_CONTENT_ATTR_HAS_VALUE && ns.Equals(aNamespaceURI)) {
00487           name->ToString(aPrefix);
00488 
00489           return NS_OK;
00490         }
00491       }
00492     }
00493   }
00494 
00495   return NS_OK;
00496 }
00497 
00498 NS_IMETHODIMP
00499 nsNode3Tearoff::LookupNamespaceURI(const nsAString& aNamespacePrefix,
00500                                    nsAString& aNamespaceURI)
00501 {
00502   if (NS_FAILED(nsContentUtils::LookupNamespaceURI(mContent,
00503                                                    aNamespacePrefix,
00504                                                    aNamespaceURI))) {
00505     SetDOMStringToNull(aNamespaceURI);
00506   }
00507   return NS_OK;
00508 }
00509 
00510 NS_IMETHODIMP
00511 nsNode3Tearoff::IsDefaultNamespace(const nsAString& aNamespaceURI,
00512                                    PRBool* aReturn)
00513 {
00514   nsAutoString defaultNamespace;
00515   LookupNamespaceURI(EmptyString(), defaultNamespace);
00516   *aReturn = aNamespaceURI.Equals(defaultNamespace);
00517   return NS_OK;
00518 }
00519 
00520 nsDOMEventRTTearoff *
00521 nsDOMEventRTTearoff::mCachedEventTearoff[NS_EVENT_TEAROFF_CACHE_SIZE];
00522 
00523 PRUint32 nsDOMEventRTTearoff::mCachedEventTearoffCount = 0;
00524 
00525 
00526 nsDOMEventRTTearoff::nsDOMEventRTTearoff(nsIContent *aContent)
00527   : mContent(aContent)
00528 {
00529 }
00530 
00531 nsDOMEventRTTearoff::~nsDOMEventRTTearoff()
00532 {
00533 }
00534 
00535 NS_INTERFACE_MAP_BEGIN(nsDOMEventRTTearoff)
00536   NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)
00537   NS_INTERFACE_MAP_ENTRY(nsIDOMEventReceiver)
00538   NS_INTERFACE_MAP_ENTRY(nsIDOM3EventTarget)
00539   NS_INTERFACE_MAP_ENTRY(nsIDOMNSEventTarget)
00540 NS_INTERFACE_MAP_END_AGGREGATED(mContent)
00541 
00542 NS_IMPL_ADDREF(nsDOMEventRTTearoff)
00543 NS_IMPL_RELEASE_WITH_DESTROY(nsDOMEventRTTearoff, LastRelease())
00544 
00545 nsDOMEventRTTearoff *
00546 nsDOMEventRTTearoff::Create(nsIContent *aContent)
00547 {
00548   if (mCachedEventTearoffCount) {
00549     // We have cached unused instances of this class, return a cached
00550     // instance in stead of always creating a new one.
00551     nsDOMEventRTTearoff *tearoff =
00552       mCachedEventTearoff[--mCachedEventTearoffCount];
00553 
00554     // Set the back pointer to the content object
00555     tearoff->mContent = aContent;
00556 
00557     return tearoff;
00558   }
00559 
00560   // The cache is empty, this means we haveto create a new instance.
00561   return new nsDOMEventRTTearoff(aContent);
00562 }
00563 
00564 // static
00565 void
00566 nsDOMEventRTTearoff::Shutdown()
00567 {
00568   // Clear our cache.
00569   while (mCachedEventTearoffCount) {
00570     delete mCachedEventTearoff[--mCachedEventTearoffCount];
00571   }
00572 }
00573 
00574 void
00575 nsDOMEventRTTearoff::LastRelease()
00576 {
00577   if (mCachedEventTearoffCount < NS_EVENT_TEAROFF_CACHE_SIZE) {
00578     // There's still space in the cache for one more instance, put
00579     // this instance in the cache in stead of deleting it.
00580     mCachedEventTearoff[mCachedEventTearoffCount++] = this;
00581 
00582     // Don't set mContent to null directly since setting mContent to null
00583     // could result in code that grabs a tearoff from the cache and we don't
00584     // want to get reused while still being torn down.
00585     // See bug 330526.
00586     nsCOMPtr<nsIContent> kungFuDeathGrip;
00587     kungFuDeathGrip.swap(mContent);
00588 
00589     // The refcount balancing and destructor re-entrancy protection
00590     // code in Release() sets mRefCnt to 1 so we have to set it to 0
00591     // here to prevent leaks
00592     mRefCnt = 0;
00593 
00594     return;
00595   }
00596 
00597   delete this;
00598 }
00599 
00600 nsresult
00601 nsDOMEventRTTearoff::GetEventReceiver(nsIDOMEventReceiver **aReceiver)
00602 {
00603   nsCOMPtr<nsIEventListenerManager> listener_manager;
00604   nsresult rv = mContent->GetListenerManager(getter_AddRefs(listener_manager));
00605   NS_ENSURE_SUCCESS(rv, rv);
00606 
00607   return CallQueryInterface(listener_manager, aReceiver);
00608 }
00609 
00610 nsresult
00611 nsDOMEventRTTearoff::GetDOM3EventTarget(nsIDOM3EventTarget **aTarget)
00612 {
00613   nsCOMPtr<nsIEventListenerManager> listener_manager;
00614   nsresult rv = mContent->GetListenerManager(getter_AddRefs(listener_manager));
00615   NS_ENSURE_SUCCESS(rv, rv);
00616 
00617   return CallQueryInterface(listener_manager, aTarget);
00618 }
00619 
00620 NS_IMETHODIMP
00621 nsDOMEventRTTearoff::AddEventListenerByIID(nsIDOMEventListener *aListener,
00622                                            const nsIID& aIID)
00623 {
00624   nsCOMPtr<nsIDOMEventReceiver> event_receiver;
00625   nsresult rv = GetEventReceiver(getter_AddRefs(event_receiver));
00626   NS_ENSURE_SUCCESS(rv, rv);
00627 
00628   return event_receiver->AddEventListenerByIID(aListener, aIID);
00629 }
00630 
00631 NS_IMETHODIMP
00632 nsDOMEventRTTearoff::RemoveEventListenerByIID(nsIDOMEventListener *aListener,
00633                                               const nsIID& aIID)
00634 {
00635   nsCOMPtr<nsIDOMEventReceiver> event_receiver;
00636   nsresult rv = GetEventReceiver(getter_AddRefs(event_receiver));
00637   NS_ENSURE_SUCCESS(rv, rv);
00638 
00639   return event_receiver->RemoveEventListenerByIID(aListener, aIID);
00640 }
00641 
00642 NS_IMETHODIMP
00643 nsDOMEventRTTearoff::GetListenerManager(nsIEventListenerManager** aResult)
00644 {
00645   return mContent->GetListenerManager(aResult);
00646 }
00647 
00648 NS_IMETHODIMP
00649 nsDOMEventRTTearoff::HandleEvent(nsIDOMEvent *aEvent)
00650 {
00651   nsCOMPtr<nsIDOMEventReceiver> event_receiver;
00652   nsresult rv = GetEventReceiver(getter_AddRefs(event_receiver));
00653   NS_ENSURE_SUCCESS(rv, rv);
00654 
00655   return event_receiver->HandleEvent(aEvent);
00656 }
00657 
00658 NS_IMETHODIMP
00659 nsDOMEventRTTearoff::GetSystemEventGroup(nsIDOMEventGroup **aGroup)
00660 {
00661   nsCOMPtr<nsIEventListenerManager> manager;
00662   GetListenerManager(getter_AddRefs(manager));
00663 
00664   if (!manager) {
00665     return NS_ERROR_FAILURE;
00666   }
00667 
00668   return manager->GetSystemEventGroupLM(aGroup);
00669 }
00670 
00671 // nsIDOMEventTarget
00672 NS_IMETHODIMP
00673 nsDOMEventRTTearoff::AddEventListener(const nsAString& aType,
00674                                       nsIDOMEventListener *aListener,
00675                                       PRBool useCapture)
00676 {
00677   return
00678     AddEventListener(aType, aListener, useCapture,
00679                      !nsContentUtils::IsChromeDoc(mContent->GetOwnerDoc()));
00680 }
00681 
00682 NS_IMETHODIMP
00683 nsDOMEventRTTearoff::RemoveEventListener(const nsAString& type,
00684                                          nsIDOMEventListener *listener,
00685                                          PRBool useCapture)
00686 {
00687   nsCOMPtr<nsIDOMEventReceiver> event_receiver;
00688   nsresult rv = GetEventReceiver(getter_AddRefs(event_receiver));
00689   NS_ENSURE_SUCCESS(rv, rv);
00690 
00691   return event_receiver->RemoveEventListener(type, listener, useCapture);
00692 }
00693 
00694 NS_IMETHODIMP
00695 nsDOMEventRTTearoff::DispatchEvent(nsIDOMEvent *evt, PRBool* _retval)
00696 {
00697   nsCOMPtr<nsIDOMEventReceiver> event_receiver;
00698   nsresult rv = GetEventReceiver(getter_AddRefs(event_receiver));
00699   NS_ENSURE_SUCCESS(rv, rv);
00700 
00701   return event_receiver->DispatchEvent(evt, _retval);
00702 }
00703 
00704 // nsIDOM3EventTarget
00705 NS_IMETHODIMP
00706 nsDOMEventRTTearoff::AddGroupedEventListener(const nsAString& aType,
00707                                              nsIDOMEventListener *aListener,
00708                                              PRBool aUseCapture,
00709                                              nsIDOMEventGroup *aEvtGrp)
00710 {
00711   nsCOMPtr<nsIDOM3EventTarget> event_target;
00712   nsresult rv = GetDOM3EventTarget(getter_AddRefs(event_target));
00713   NS_ENSURE_SUCCESS(rv, rv);
00714 
00715   return event_target->AddGroupedEventListener(aType, aListener, aUseCapture,
00716                                                aEvtGrp);
00717 }
00718 
00719 NS_IMETHODIMP
00720 nsDOMEventRTTearoff::RemoveGroupedEventListener(const nsAString& aType,
00721                                                 nsIDOMEventListener *aListener,
00722                                                 PRBool aUseCapture,
00723                                                 nsIDOMEventGroup *aEvtGrp)
00724 {
00725   nsCOMPtr<nsIDOM3EventTarget> event_target;
00726   nsresult rv = GetDOM3EventTarget(getter_AddRefs(event_target));
00727   NS_ENSURE_SUCCESS(rv, rv);
00728 
00729   return event_target->RemoveGroupedEventListener(aType, aListener,
00730                                                   aUseCapture, aEvtGrp);
00731 }
00732 
00733 NS_IMETHODIMP
00734 nsDOMEventRTTearoff::CanTrigger(const nsAString & type, PRBool *_retval)
00735 {
00736   return NS_ERROR_NOT_IMPLEMENTED;
00737 }
00738 
00739 NS_IMETHODIMP
00740 nsDOMEventRTTearoff::IsRegisteredHere(const nsAString & type, PRBool *_retval)
00741 {
00742   return NS_ERROR_NOT_IMPLEMENTED;
00743 }
00744 
00745 // nsIDOMNSEventTarget
00746 NS_IMETHODIMP
00747 nsDOMEventRTTearoff::AddEventListener(const nsAString& aType,
00748                                       nsIDOMEventListener *aListener,
00749                                       PRBool aUseCapture,
00750                                       PRBool aWantsUntrusted)
00751 {
00752   nsCOMPtr<nsIEventListenerManager> listener_manager;
00753   nsresult rv = mContent->GetListenerManager(getter_AddRefs(listener_manager));
00754   NS_ENSURE_SUCCESS(rv, rv);
00755 
00756   PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
00757 
00758   if (aWantsUntrusted) {
00759     flags |= NS_PRIV_EVENT_UNTRUSTED_PERMITTED;
00760   }
00761 
00762   return listener_manager->AddEventListenerByType(aListener, aType, flags,
00763                                                   nsnull);
00764 }
00765 
00766 //----------------------------------------------------------------------
00767 
00768 PRUint32 nsMutationGuard::sMutationCount = 0;
00769 
00770 nsDOMSlots::nsDOMSlots(PtrBits aFlags)
00771   : mFlags(aFlags & ~GENERIC_ELEMENT_CONTENT_ID_MASK),
00772     mBindingParent(nsnull),
00773     mContentID(aFlags >> GENERIC_ELEMENT_CONTENT_ID_BITS_OFFSET)
00774 {
00775 }
00776 
00777 nsDOMSlots::~nsDOMSlots()
00778 {
00779   if (mChildNodes) {
00780     mChildNodes->DropReference();
00781   }
00782 
00783   if (mStyle) {
00784     mStyle->DropReference();
00785   }
00786 
00787   if (mAttributeMap) {
00788     mAttributeMap->DropReference();
00789   }
00790 }
00791 
00792 PRBool
00793 nsDOMSlots::IsEmpty()
00794 {
00795   return (!mChildNodes && !mStyle && !mAttributeMap && !mBindingParent &&
00796           mContentID < GENERIC_ELEMENT_CONTENT_ID_MAX_VALUE);
00797 }
00798 
00799 PR_STATIC_CALLBACK(void)
00800 NopClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
00801 {
00802   // Do nothing
00803 }
00804 
00805 // static
00806 void
00807 nsGenericElement::Shutdown()
00808 {
00809   nsDOMEventRTTearoff::Shutdown();
00810 
00811   if (sRangeListsHash.ops) {
00812     NS_ASSERTION(sRangeListsHash.entryCount == 0,
00813                  "nsGenericElement's range hash not empty at shutdown!");
00814 
00815     // We're already being shut down and if there are entries left in
00816     // this hash at this point it means we leaked nsGenericElements or
00817     // nsGenericDOMDataNodes. Since we're already partly through the
00818     // shutdown process it's too late to release what's held on to by
00819     // this hash (since the teardown code relies on some things being
00820     // around that aren't around any more) so we rather leak what's
00821     // already leaked in stead of crashing trying to release what
00822     // should've been released much earlier on.
00823 
00824     // Copy the ops out of the hash table
00825     PLDHashTableOps hash_table_ops = *sRangeListsHash.ops;
00826 
00827     // Set the clearEntry hook to be a nop
00828     hash_table_ops.clearEntry = NopClearEntry;
00829 
00830     // Set the ops in the hash table to be the new ops
00831     sRangeListsHash.ops = &hash_table_ops;
00832 
00833     PL_DHashTableFinish(&sRangeListsHash);
00834 
00835     sRangeListsHash.ops = nsnull;
00836   }
00837 
00838   if (sEventListenerManagersHash.ops) {
00839     NS_ASSERTION(sEventListenerManagersHash.entryCount == 0,
00840                  "nsGenericElement's event listener manager hash not empty "
00841                  "at shutdown!");
00842 
00843     // See comment above.
00844 
00845     // However, we have to handle this table differently.  If it still
00846     // has entries, we want to leak it too, so that we can keep it alive
00847     // in case any elements are destroyed.  Because if they are, we need
00848     // their event listener managers to be destroyed too, or otherwise
00849     // it could leave dangling references in DOMClassInfo's preserved
00850     // wrapper table.
00851 
00852     if (sEventListenerManagersHash.entryCount == 0) {
00853       PL_DHashTableFinish(&sEventListenerManagersHash);
00854       sEventListenerManagersHash.ops = nsnull;
00855     }
00856   }
00857 }
00858 
00859 nsGenericElement::nsGenericElement(nsINodeInfo *aNodeInfo)
00860   : mNodeInfo(aNodeInfo),
00861     mFlagsOrSlots(GENERIC_ELEMENT_DOESNT_HAVE_DOMSLOTS)
00862 {
00863   NS_ASSERTION(mNodeInfo, "No nsINodeInfo passed to nsGenericElement, "
00864                "PREPARE TO CRASH!!!");
00865 }
00866 
00867 nsGenericElement::~nsGenericElement()
00868 {
00869   NS_PRECONDITION(!IsInDoc(),
00870                   "Please remove this from the document properly");
00871   
00872   // pop any enclosed ranges out
00873   // nsRange::OwnerGone(mContent); not used for now
00874 
00875   if (HasRangeList()) {
00876 #ifdef DEBUG
00877     {
00878       RangeListMapEntry *entry =
00879         NS_STATIC_CAST(RangeListMapEntry *,
00880                        PL_DHashTableOperate(&sRangeListsHash, this,
00881                                             PL_DHASH_LOOKUP));
00882 
00883       if (PL_DHASH_ENTRY_IS_FREE(entry)) {
00884         NS_ERROR("Huh, our bit says we have a range list, but there's nothing "
00885                  "in the hash!?!!");
00886       }
00887     }
00888 #endif
00889 
00890     PL_DHashTableOperate(&sRangeListsHash, this, PL_DHASH_REMOVE);
00891   }
00892 
00893   if (HasEventListenerManager()) {
00894     EventListenerManagerMapEntry *entry =
00895       NS_STATIC_CAST(EventListenerManagerMapEntry *,
00896                      PL_DHashTableOperate(&sEventListenerManagersHash, this,
00897                                           PL_DHASH_LOOKUP));
00898     NS_ASSERTION(!PL_DHASH_ENTRY_IS_FREE(entry),
00899                  "Huh, our bit says we have a listener manager list, "
00900                  "but there's nothing in the hash!?!!");
00901     if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
00902       nsCOMPtr<nsIEventListenerManager> listenerManager;
00903       listenerManager.swap(entry->mListenerManager);
00904       // Remove the entry and *then* do operations that could cause further
00905       // modification of sEventListenerManagersHash.  See bug 334177.
00906       PL_DHashTableRawRemove(&sEventListenerManagersHash, entry);
00907       if (listenerManager) {
00908         listenerManager->Disconnect();
00909       }
00910     }
00911   }
00912 
00913   if (HasDOMSlots()) {
00914     nsDOMSlots *slots = GetDOMSlots();
00915 
00916     delete slots;
00917   }
00918 
00919   // No calling GetFlags() beyond this point...
00920 }
00921 
00922 PR_STATIC_CALLBACK(PRBool)
00923 RangeListHashInitEntry(PLDHashTable *table, PLDHashEntryHdr *entry,
00924                        const void *key)
00925 {
00926   // Initialize the entry with placement new
00927   new (entry) RangeListMapEntry(key);
00928   return PR_TRUE;
00929 }
00930 
00931 PR_STATIC_CALLBACK(void)
00932 RangeListHashClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
00933 {
00934   RangeListMapEntry *r = NS_STATIC_CAST(RangeListMapEntry *, entry);
00935 
00936   // Let the RangeListMapEntry clean itself up...
00937   r->~RangeListMapEntry();
00938 }
00939 
00940 PR_STATIC_CALLBACK(PRBool)
00941 EventListenerManagerHashInitEntry(PLDHashTable *table, PLDHashEntryHdr *entry,
00942                                   const void *key)
00943 {
00944   // Initialize the entry with placement new
00945   new (entry) EventListenerManagerMapEntry(key);
00946   return PR_TRUE;
00947 }
00948 
00949 PR_STATIC_CALLBACK(void)
00950 EventListenerManagerHashClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
00951 {
00952   EventListenerManagerMapEntry *lm =
00953     NS_STATIC_CAST(EventListenerManagerMapEntry *, entry);
00954 
00955   // Let the EventListenerManagerMapEntry clean itself up...
00956   lm->~EventListenerManagerMapEntry();
00957 }
00958 
00959 
00960 // static
00961 nsresult
00962 nsGenericElement::InitHashes()
00963 {
00964   NS_ASSERTION(sizeof(PtrBits) == sizeof(void *),
00965                "Eeek! You'll need to adjust the size of PtrBits to the size "
00966                "of a pointer on your platform.");
00967 
00968   if (!sRangeListsHash.ops) {
00969     static PLDHashTableOps hash_table_ops =
00970     {
00971       PL_DHashAllocTable,
00972       PL_DHashFreeTable,
00973       PL_DHashGetKeyStub,
00974       PL_DHashVoidPtrKeyStub,
00975       PL_DHashMatchEntryStub,
00976       PL_DHashMoveEntryStub,
00977       RangeListHashClearEntry,
00978       PL_DHashFinalizeStub,
00979       RangeListHashInitEntry
00980     };
00981 
00982     if (!PL_DHashTableInit(&sRangeListsHash, &hash_table_ops, nsnull,
00983                            sizeof(RangeListMapEntry), 16)) {
00984       sRangeListsHash.ops = nsnull;
00985 
00986       return NS_ERROR_OUT_OF_MEMORY;
00987     }
00988   }
00989 
00990   if (!sEventListenerManagersHash.ops) {
00991     static PLDHashTableOps hash_table_ops =
00992     {
00993       PL_DHashAllocTable,
00994       PL_DHashFreeTable,
00995       PL_DHashGetKeyStub,
00996       PL_DHashVoidPtrKeyStub,
00997       PL_DHashMatchEntryStub,
00998       PL_DHashMoveEntryStub,
00999       EventListenerManagerHashClearEntry,
01000       PL_DHashFinalizeStub,
01001       EventListenerManagerHashInitEntry
01002     };
01003 
01004     if (!PL_DHashTableInit(&sEventListenerManagersHash, &hash_table_ops,
01005                            nsnull, sizeof(EventListenerManagerMapEntry), 16)) {
01006       sEventListenerManagersHash.ops = nsnull;
01007 
01008       PL_DHashTableFinish(&sRangeListsHash);
01009       sRangeListsHash.ops = nsnull;
01010 
01011       return NS_ERROR_OUT_OF_MEMORY;
01012     }
01013   }
01014 
01015   return NS_OK;
01016 }
01017 
01028 nsIDOMGCParticipant*
01029 nsGenericElement::GetSCCIndex()
01030 {
01031   // This is an optimized way of walking nsIDOMNode::GetParentNode to
01032   // the top of the tree.
01033   nsCOMPtr<nsIDOMGCParticipant> result = do_QueryInterface(GetCurrentDoc());
01034   if (!result) {
01035     nsIContent *top = this;
01036     while (top->GetParent())
01037       top = top->GetParent();
01038     result = do_QueryInterface(top);
01039   }
01040 
01041   return result;
01042 }
01043 
01044 void
01045 nsGenericElement::AppendReachableList(nsCOMArray<nsIDOMGCParticipant>& aArray)
01046 {
01047   NS_ASSERTION(GetCurrentDoc() == nsnull,
01048                "shouldn't be an SCC index if we're in a doc");
01049 
01050   // This node is the root of a subtree that's been removed from the
01051   // document (since AppendReachableList is only called on SCC index
01052   // nodes).  The document is reachable from it (through
01053   // .ownerDocument), but it's not reachable from the document.
01054   nsCOMPtr<nsIDOMGCParticipant> participant = do_QueryInterface(GetOwnerDoc());
01055   aArray.AppendObject(participant);
01056 }
01057 
01058 NS_IMETHODIMP
01059 nsGenericElement::GetNodeName(nsAString& aNodeName)
01060 {
01061   mNodeInfo->GetQualifiedName(aNodeName);
01062   return NS_OK;
01063 }
01064 
01065 NS_IMETHODIMP
01066 nsGenericElement::GetLocalName(nsAString& aLocalName)
01067 {
01068   mNodeInfo->GetLocalName(aLocalName);
01069   return NS_OK;
01070 }
01071 
01072 NS_IMETHODIMP
01073 nsGenericElement::GetNodeValue(nsAString& aNodeValue)
01074 {
01075   SetDOMStringToNull(aNodeValue);
01076 
01077   return NS_OK;
01078 }
01079 
01080 NS_IMETHODIMP
01081 nsGenericElement::SetNodeValue(const nsAString& aNodeValue)
01082 {
01083   // The DOM spec says that when nodeValue is defined to be null "setting it
01084   // has no effect", so we don't throw an exception.
01085   return NS_OK;
01086 }
01087 
01088 NS_IMETHODIMP
01089 nsGenericElement::GetNodeType(PRUint16* aNodeType)
01090 {
01091   *aNodeType = (PRUint16)nsIDOMNode::ELEMENT_NODE;
01092   return NS_OK;
01093 }
01094 
01095 NS_IMETHODIMP
01096 nsGenericElement::GetParentNode(nsIDOMNode** aParentNode)
01097 {
01098   nsIContent *parent = GetParent();
01099   if (parent) {
01100     return CallQueryInterface(parent, aParentNode);
01101   }
01102 
01103   nsIDocument* doc = GetCurrentDoc();
01104   if (doc) {
01105     // If we don't have a parent, but we're in the document, we must
01106     // be the root node of the document. The DOM says that the root
01107     // is the document.
01108 
01109     return CallQueryInterface(doc, aParentNode);
01110   }
01111 
01112   *aParentNode = nsnull;
01113 
01114   return NS_OK;
01115 }
01116 
01117 NS_IMETHODIMP
01118 nsGenericElement::GetPreviousSibling(nsIDOMNode** aPrevSibling)
01119 {
01120   *aPrevSibling = nsnull;
01121 
01122   nsIContent *sibling = nsnull;
01123   nsresult rv = NS_OK;
01124 
01125   nsIContent *parent = GetParent();
01126   if (parent) {
01127     PRInt32 pos = parent->IndexOf(this);
01128     if (pos > 0 ) {
01129       sibling = parent->GetChildAt(pos - 1);
01130     }
01131   } else {
01132     nsIDocument* document = GetCurrentDoc();
01133     if (document) {
01134       // Nodes that are just below the document (their parent is the
01135       // document) need to go to the document to find their next sibling.
01136       PRInt32 pos = document->IndexOf(this);
01137       if (pos > 0 ) {
01138         sibling = document->GetChildAt(pos - 1);
01139       }
01140     }
01141   }
01142 
01143   if (sibling) {
01144     rv = CallQueryInterface(sibling, aPrevSibling);
01145     NS_ASSERTION(*aPrevSibling, "Must be a DOM Node");
01146   }
01147 
01148   return rv;
01149 }
01150 
01151 NS_IMETHODIMP
01152 nsGenericElement::GetNextSibling(nsIDOMNode** aNextSibling)
01153 {
01154   *aNextSibling = nsnull;
01155 
01156   nsIContent *sibling = nsnull;
01157   nsresult rv = NS_OK;
01158 
01159   nsIContent *parent = GetParent();
01160   if (parent) {
01161     PRInt32 pos = parent->IndexOf(this);
01162     if (pos > -1 ) {
01163       sibling = parent->GetChildAt(pos + 1);
01164     }
01165   } else {
01166     nsIDocument* document = GetCurrentDoc();
01167     if (document) {
01168       // Nodes that are just below the document (their parent is the
01169       // document) need to go to the document to find their next sibling.
01170       PRInt32 pos = document->IndexOf(this);
01171       if (pos > -1 ) {
01172         sibling = document->GetChildAt(pos + 1);
01173       }
01174     }
01175   }
01176 
01177   if (sibling) {
01178     rv = CallQueryInterface(sibling, aNextSibling);
01179     NS_ASSERTION(*aNextSibling, "Must be a DOM Node");
01180   }
01181 
01182   return rv;
01183 }
01184 
01185 NS_IMETHODIMP
01186 nsGenericElement::GetOwnerDocument(nsIDOMDocument** aOwnerDocument)
01187 {
01188   nsIDocument *doc = GetOwnerDoc();
01189   if (doc) {
01190     return CallQueryInterface(doc, aOwnerDocument);
01191   }
01192 
01193   *aOwnerDocument = nsnull;
01194 
01195   return NS_OK;
01196 }
01197 
01198 NS_IMETHODIMP
01199 nsGenericElement::GetNamespaceURI(nsAString& aNamespaceURI)
01200 {
01201   return mNodeInfo->GetNamespaceURI(aNamespaceURI);
01202 }
01203 
01204 NS_IMETHODIMP
01205 nsGenericElement::GetPrefix(nsAString& aPrefix)
01206 {
01207   mNodeInfo->GetPrefix(aPrefix);
01208   return NS_OK;
01209 }
01210 
01211 NS_IMETHODIMP
01212 nsGenericElement::SetPrefix(const nsAString& aPrefix)
01213 {
01214   // XXX: Validate the prefix string!
01215 
01216   nsCOMPtr<nsIAtom> prefix;
01217 
01218   if (!aPrefix.IsEmpty()) {
01219     prefix = do_GetAtom(aPrefix);
01220     NS_ENSURE_TRUE(prefix, NS_ERROR_OUT_OF_MEMORY);
01221   }
01222 
01223   nsCOMPtr<nsINodeInfo> newNodeInfo;
01224   nsresult rv = nsContentUtils::PrefixChanged(mNodeInfo, prefix,
01225                                               getter_AddRefs(newNodeInfo));
01226   NS_ENSURE_SUCCESS(rv, rv);
01227 
01228   mNodeInfo = newNodeInfo;
01229 
01230   return NS_OK;
01231 }
01232 
01233 extern PRBool gCheckedForXPathDOM;
01234 extern PRBool gHaveXPathDOM;
01235 
01236 nsresult
01237 nsGenericElement::InternalIsSupported(nsISupports* aObject,
01238                                       const nsAString& aFeature,
01239                                       const nsAString& aVersion,
01240                                       PRBool* aReturn)
01241 {
01242   NS_ENSURE_ARG_POINTER(aReturn);
01243   *aReturn = PR_FALSE;
01244 
01245   // Convert the incoming UTF16 strings to raw char*'s to save us some
01246   // code when doing all those string compares.
01247   NS_ConvertUTF16toUTF8 feature(aFeature);
01248   NS_ConvertUTF16toUTF8 version(aVersion);
01249 
01250   const char *f = feature.get();
01251   const char *v = version.get();
01252 
01253   if (PL_strcasecmp(f, "XML") == 0 ||
01254       PL_strcasecmp(f, "HTML") == 0) {
01255     if (aVersion.IsEmpty() ||
01256         PL_strcmp(v, "1.0") == 0 ||
01257         PL_strcmp(v, "2.0") == 0) {
01258       *aReturn = PR_TRUE;
01259     }
01260   } else if (PL_strcasecmp(f, "Views") == 0 ||
01261              PL_strcasecmp(f, "StyleSheets") == 0 ||
01262              PL_strcasecmp(f, "Core") == 0 ||
01263              PL_strcasecmp(f, "CSS") == 0 ||
01264              PL_strcasecmp(f, "CSS2") == 0 ||
01265              PL_strcasecmp(f, "Events") == 0 ||
01266              PL_strcasecmp(f, "UIEvents") == 0 ||
01267              PL_strcasecmp(f, "MouseEvents") == 0 ||
01268              // Non-standard!
01269              PL_strcasecmp(f, "MouseScrollEvents") == 0 ||
01270              PL_strcasecmp(f, "HTMLEvents") == 0 ||
01271              PL_strcasecmp(f, "Range") == 0 ||
01272              PL_strcasecmp(f, "XHTML") == 0) {
01273     if (aVersion.IsEmpty() ||
01274         PL_strcmp(v, "2.0") == 0) {
01275       *aReturn = PR_TRUE;
01276     }
01277   } else if ((!gCheckedForXPathDOM || gHaveXPathDOM) &&
01278              PL_strcasecmp(f, "XPath") == 0 &&
01279              (aVersion.IsEmpty() ||
01280               PL_strcmp(v, "3.0") == 0)) {
01281     if (!gCheckedForXPathDOM) {
01282       nsCOMPtr<nsIDOMXPathEvaluator> evaluator =
01283         do_CreateInstance(NS_XPATH_EVALUATOR_CONTRACTID);
01284       gHaveXPathDOM = (evaluator != nsnull);
01285       gCheckedForXPathDOM = PR_TRUE;
01286     }
01287 
01288     *aReturn = gHaveXPathDOM;
01289   }
01290 #ifdef MOZ_SVG
01291   else if (PL_strcasecmp(f, "SVGEvents") == 0 ||
01292            PL_strcasecmp(f, "SVGZoomEvents") == 0 ||
01293            NS_SVG_TestFeature(aFeature)) {
01294     if (aVersion.IsEmpty() ||
01295         PL_strcmp(v, "1.0") == 0 ||
01296         PL_strcmp(v, "1.1") == 0) {
01297       *aReturn = PR_TRUE;
01298     }
01299   }
01300 #endif /* MOZ_SVG */
01301   else {
01302     nsCOMPtr<nsIDOMNSFeatureFactory> factory =
01303       GetDOMFeatureFactory(aFeature, aVersion);
01304 
01305     if (factory) {
01306       factory->HasFeature(aObject, aFeature, aVersion, aReturn);
01307     }
01308   }
01309   return NS_OK;
01310 }
01311 
01312 nsresult
01313 nsGenericElement::InternalGetFeature(nsISupports* aObject,
01314                                     const nsAString& aFeature,
01315                                     const nsAString& aVersion,
01316                                     nsISupports** aReturn)
01317 {
01318   *aReturn = nsnull;
01319   nsCOMPtr<nsIDOMNSFeatureFactory> factory =
01320     GetDOMFeatureFactory(aFeature, aVersion);
01321 
01322   if (factory) {
01323     factory->GetFeature(aObject, aFeature, aVersion, aReturn);
01324   }
01325 
01326   return NS_OK;
01327 }
01328 
01329 already_AddRefed<nsIDOMNSFeatureFactory>
01330 nsGenericElement::GetDOMFeatureFactory(const nsAString& aFeature,
01331                                        const nsAString& aVersion)
01332 {
01333   nsIDOMNSFeatureFactory *factory = nsnull;
01334   nsCOMPtr<nsICategoryManager> categoryManager =
01335     do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
01336   if (categoryManager) {
01337     nsCAutoString featureCategory(NS_DOMNS_FEATURE_PREFIX);
01338     AppendUTF16toUTF8(aFeature, featureCategory);
01339     nsXPIDLCString contractID;
01340     nsresult rv = categoryManager->GetCategoryEntry(featureCategory.get(),
01341                                                     NS_ConvertUTF16toUTF8(aVersion).get(),
01342                                                     getter_Copies(contractID));
01343     if (NS_SUCCEEDED(rv)) {
01344       CallGetService(contractID.get(), &factory);  // addrefs
01345     }
01346   }
01347   return factory;
01348 }
01349 
01350 NS_IMETHODIMP
01351 nsGenericElement::IsSupported(const nsAString& aFeature,
01352                               const nsAString& aVersion,
01353                               PRBool* aReturn)
01354 {
01355   return InternalIsSupported(this, aFeature, aVersion, aReturn);
01356 }
01357 
01358 NS_IMETHODIMP
01359 nsGenericElement::HasAttributes(PRBool* aReturn)
01360 {
01361   NS_ENSURE_ARG_POINTER(aReturn);
01362 
01363   *aReturn = GetAttrCount() > 0;
01364 
01365   return NS_OK;
01366 }
01367 
01368 NS_IMETHODIMP
01369 nsGenericElement::GetAttributes(nsIDOMNamedNodeMap** aAttributes)
01370 {
01371   NS_ENSURE_ARG_POINTER(aAttributes);
01372   nsDOMSlots *slots = GetDOMSlots();
01373 
01374   if (!slots) {
01375     return NS_ERROR_OUT_OF_MEMORY;
01376   }
01377 
01378   if (!slots->mAttributeMap) {
01379     slots->mAttributeMap = new nsDOMAttributeMap(this);
01380     if (!slots->mAttributeMap) {
01381       return NS_ERROR_OUT_OF_MEMORY;
01382     }
01383     if (!slots->mAttributeMap->Init()) {
01384       slots->mAttributeMap = nsnull;
01385       return NS_ERROR_FAILURE;
01386     }
01387   }
01388 
01389   NS_ADDREF(*aAttributes = slots->mAttributeMap);
01390 
01391   return NS_OK;
01392 }
01393 
01394 nsresult
01395 nsGenericElement::GetChildNodes(nsIDOMNodeList** aChildNodes)
01396 {
01397   nsDOMSlots *slots = GetDOMSlots();
01398 
01399   if (!slots) {
01400     return NS_ERROR_OUT_OF_MEMORY;
01401   }
01402 
01403   if (!slots->mChildNodes) {
01404     slots->mChildNodes = new nsChildContentList(this);
01405     if (!slots->mChildNodes) {
01406       return NS_ERROR_OUT_OF_MEMORY;
01407     }
01408   }
01409 
01410   NS_ADDREF(*aChildNodes = slots->mChildNodes);
01411 
01412   return NS_OK;
01413 }
01414 
01415 nsresult
01416 nsGenericElement::HasChildNodes(PRBool* aReturn)
01417 {
01418   *aReturn = mAttrsAndChildren.ChildCount() > 0;
01419 
01420   return NS_OK;
01421 }
01422 
01423 nsresult
01424 nsGenericElement::GetFirstChild(nsIDOMNode** aNode)
01425 {
01426   nsIContent *child = mAttrsAndChildren.GetSafeChildAt(0);
01427   if (child) {
01428     return CallQueryInterface(child, aNode);
01429   }
01430 
01431   *aNode = nsnull;
01432 
01433   return NS_OK;
01434 }
01435 
01436 nsresult
01437 nsGenericElement::GetLastChild(nsIDOMNode** aNode)
01438 {
01439   PRUint32 count = mAttrsAndChildren.ChildCount();
01440   
01441   if (count > 0) {
01442     return CallQueryInterface(mAttrsAndChildren.ChildAt(count - 1), aNode);
01443   }
01444 
01445   *aNode = nsnull;
01446 
01447   return NS_OK;
01448 }
01449 
01450 NS_IMETHODIMP
01451 nsGenericElement::GetTagName(nsAString& aTagName)
01452 {
01453   mNodeInfo->GetQualifiedName(aTagName);
01454   return NS_OK;
01455 }
01456 
01457 nsresult
01458 nsGenericElement::GetAttribute(const nsAString& aName,
01459                                nsAString& aReturn)
01460 {
01461   const nsAttrName* name = InternalGetExistingAttrNameFromQName(aName);
01462 
01463   if (!name) {
01464     if (mNodeInfo->NamespaceID() == kNameSpaceID_XUL) {
01465       // XXX should be SetDOMStringToNull(aReturn);
01466       // See bug 232598
01467       aReturn.Truncate();
01468     }
01469     else {
01470       SetDOMStringToNull(aReturn);
01471     }
01472 
01473     return NS_OK;
01474   }
01475 
01476   GetAttr(name->NamespaceID(), name->LocalName(), aReturn);
01477 
01478   return NS_OK;
01479 }
01480 
01481 nsresult
01482 nsGenericElement::SetAttribute(const nsAString& aName,
01483                                const nsAString& aValue)
01484 {
01485   const nsAttrName* name = InternalGetExistingAttrNameFromQName(aName);
01486 
01487   if (!name) {
01488     nsresult rv = nsContentUtils::CheckQName(aName, PR_FALSE);
01489     NS_ENSURE_SUCCESS(rv, rv);
01490 
01491     nsCOMPtr<nsIAtom> nameAtom = do_GetAtom(aName);
01492     NS_ENSURE_TRUE(nameAtom, NS_ERROR_OUT_OF_MEMORY);
01493 
01494     return SetAttr(kNameSpaceID_None, nameAtom, aValue, PR_TRUE);
01495   }
01496 
01497   return SetAttr(name->NamespaceID(), name->LocalName(), name->GetPrefix(),
01498                  aValue, PR_TRUE);
01499 }
01500 
01501 nsresult
01502 nsGenericElement::RemoveAttribute(const nsAString& aName)
01503 {
01504   const nsAttrName* name = InternalGetExistingAttrNameFromQName(aName);
01505 
01506   if (!name) {
01507     return NS_OK;
01508   }
01509 
01510   // Hold a strong reference here so that the atom or nodeinfo doesn't go
01511   // away during UnsetAttr. If it did UnsetAttr would be left with a
01512   // dangling pointer as argument without knowing it.
01513   nsAttrName tmp(*name);
01514 
01515   return UnsetAttr(name->NamespaceID(), name->LocalName(), PR_TRUE);
01516 }
01517 
01518 nsresult
01519 nsGenericElement::GetAttributeNode(const nsAString& aName,
01520                                    nsIDOMAttr** aReturn)
01521 {
01522   NS_ENSURE_ARG_POINTER(aReturn);
01523   *aReturn = nsnull;
01524 
01525   nsCOMPtr<nsIDOMNamedNodeMap> map;
01526   nsresult rv = GetAttributes(getter_AddRefs(map));
01527   NS_ENSURE_SUCCESS(rv, rv);
01528 
01529   nsCOMPtr<nsIDOMNode> node;
01530   rv = map->GetNamedItem(aName, getter_AddRefs(node));
01531 
01532   if (NS_SUCCEEDED(rv) && node) {
01533     rv = CallQueryInterface(node, aReturn);
01534   }
01535 
01536   return rv;
01537 }
01538 
01539 nsresult
01540 nsGenericElement::SetAttributeNode(nsIDOMAttr* aAttribute,
01541                                    nsIDOMAttr** aReturn)
01542 {
01543   NS_ENSURE_ARG_POINTER(aReturn);
01544   NS_ENSURE_ARG_POINTER(aAttribute);
01545 
01546   *aReturn = nsnull;
01547 
01548   nsCOMPtr<nsIDOMNamedNodeMap> map;
01549   nsresult rv = GetAttributes(getter_AddRefs(map));
01550   NS_ENSURE_SUCCESS(rv, rv);
01551 
01552   nsCOMPtr<nsIDOMNode> returnNode;
01553   rv = map->SetNamedItem(aAttribute, getter_AddRefs(returnNode));
01554   NS_ENSURE_SUCCESS(rv, rv);
01555 
01556   if (returnNode) {
01557     rv = CallQueryInterface(returnNode, aReturn);
01558   }
01559 
01560   return rv;
01561 }
01562 
01563 nsresult
01564 nsGenericElement::RemoveAttributeNode(nsIDOMAttr* aAttribute,
01565                                       nsIDOMAttr** aReturn)
01566 {
01567   NS_ENSURE_ARG_POINTER(aReturn);
01568   NS_ENSURE_ARG_POINTER(aAttribute);
01569 
01570   *aReturn = nsnull;
01571 
01572   nsCOMPtr<nsIDOMNamedNodeMap> map;
01573   nsresult rv = GetAttributes(getter_AddRefs(map));
01574   NS_ENSURE_SUCCESS(rv, rv);
01575 
01576   nsAutoString name;
01577 
01578   rv = aAttribute->GetName(name);
01579   if (NS_SUCCEEDED(rv)) {
01580     nsCOMPtr<nsIDOMNode> node;
01581     rv = map->RemoveNamedItem(name, getter_AddRefs(node));
01582 
01583     if (NS_SUCCEEDED(rv) && node) {
01584       rv = CallQueryInterface(node, aReturn);
01585     }
01586   }
01587 
01588   return rv;
01589 }
01590 
01591 nsresult
01592 nsGenericElement::GetElementsByTagName(const nsAString& aTagname,
01593                                        nsIDOMNodeList** aReturn)
01594 {
01595   nsCOMPtr<nsIAtom> nameAtom = do_GetAtom(aTagname);
01596   NS_ENSURE_TRUE(nameAtom, NS_ERROR_OUT_OF_MEMORY);
01597 
01598   nsContentList *list = NS_GetContentList(GetCurrentDoc(), nameAtom,
01599                                           kNameSpaceID_Unknown, this).get();
01600   NS_ENSURE_TRUE(list, NS_ERROR_OUT_OF_MEMORY);
01601 
01602   // transfer ref to aReturn
01603   *aReturn = list;
01604   return NS_OK;
01605 }
01606 
01607 nsresult
01608 nsGenericElement::GetAttributeNS(const nsAString& aNamespaceURI,
01609                                  const nsAString& aLocalName,
01610                                  nsAString& aReturn)
01611 {
01612   PRInt32 nsid;
01613   nsContentUtils::GetNSManagerWeakRef()->GetNameSpaceID(aNamespaceURI, &nsid);
01614 
01615   if (nsid == kNameSpaceID_Unknown) {
01616     // Unknown namespace means no attr...
01617 
01618     aReturn.Truncate();
01619 
01620     return NS_OK;
01621   }
01622 
01623   nsCOMPtr<nsIAtom> name = do_GetAtom(aLocalName);
01624   GetAttr(nsid, name, aReturn);
01625 
01626   return NS_OK;
01627 }
01628 
01629 nsresult
01630 nsGenericElement::SetAttributeNS(const nsAString& aNamespaceURI,
01631                                  const nsAString& aQualifiedName,
01632                                  const nsAString& aValue)
01633 {
01634   nsCOMPtr<nsINodeInfo> ni;
01635   nsresult rv =
01636     nsContentUtils::GetNodeInfoFromQName(aNamespaceURI, aQualifiedName,
01637                                          mNodeInfo->NodeInfoManager(),
01638                                          getter_AddRefs(ni));
01639   NS_ENSURE_SUCCESS(rv, rv);
01640 
01641   return SetAttr(ni->NamespaceID(), ni->NameAtom(), ni->GetPrefixAtom(),
01642                  aValue, PR_TRUE);
01643 }
01644 
01645 nsresult
01646 nsGenericElement::RemoveAttributeNS(const nsAString& aNamespaceURI,
01647                                     const nsAString& aLocalName)
01648 {
01649   nsCOMPtr<nsIAtom> name = do_GetAtom(aLocalName);
01650   PRInt32 nsid;
01651 
01652   nsContentUtils::GetNSManagerWeakRef()->GetNameSpaceID(aNamespaceURI, &nsid);
01653 
01654   if (nsid == kNameSpaceID_Unknown) {
01655     // Unknown namespace means no attr...
01656 
01657     return NS_OK;
01658   }
01659 
01660   nsAutoString tmp;
01661   UnsetAttr(nsid, name, PR_TRUE);
01662 
01663   return NS_OK;
01664 }
01665 
01666 nsresult
01667 nsGenericElement::GetAttributeNodeNS(const nsAString& aNamespaceURI,
01668                                      const nsAString& aLocalName,
01669                                      nsIDOMAttr** aReturn)
01670 {
01671   NS_ENSURE_ARG_POINTER(aReturn);
01672 
01673   *aReturn = nsnull;
01674 
01675   nsCOMPtr<nsIDOMNamedNodeMap> map;
01676   nsresult rv = GetAttributes(getter_AddRefs(map));
01677   NS_ENSURE_SUCCESS(rv, rv);
01678 
01679   nsCOMPtr<nsIDOMNode> node;
01680   rv = map->GetNamedItemNS(aNamespaceURI, aLocalName, getter_AddRefs(node));
01681 
01682   if (NS_SUCCEEDED(rv) && node) {
01683     rv = CallQueryInterface(node, aReturn);
01684   }
01685 
01686   return rv;
01687 }
01688 
01689 nsresult
01690 nsGenericElement::SetAttributeNodeNS(nsIDOMAttr* aNewAttr,
01691                                      nsIDOMAttr** aReturn)
01692 {
01693   NS_ENSURE_ARG_POINTER(aReturn);
01694   NS_ENSURE_ARG_POINTER(aNewAttr);
01695 
01696   *aReturn = nsnull;
01697 
01698   nsCOMPtr<nsIDOMNamedNodeMap> map;
01699   nsresult rv = GetAttributes(getter_AddRefs(map));
01700   NS_ENSURE_SUCCESS(rv, rv);
01701 
01702   nsCOMPtr<nsIDOMNode> returnNode;
01703   rv = map->SetNamedItemNS(aNewAttr, getter_AddRefs(returnNode));
01704   NS_ENSURE_SUCCESS(rv, rv);
01705 
01706   if (returnNode) {
01707     rv = CallQueryInterface(returnNode, aReturn);
01708   }
01709 
01710   return rv;
01711 }
01712 
01713 nsresult
01714 nsGenericElement::GetElementsByTagNameNS(const nsAString& aNamespaceURI,
01715                                          const nsAString& aLocalName,
01716                                          nsIDOMNodeList** aReturn)
01717 {
01718   PRInt32 nameSpaceId = kNameSpaceID_Unknown;
01719 
01720   nsContentList *list = nsnull;
01721 
01722   nsIDocument* document = GetCurrentDoc();
01723   if (!aNamespaceURI.EqualsLiteral("*")) {
01724     nsContentUtils::GetNSManagerWeakRef()->GetNameSpaceID(aNamespaceURI,
01725                                                           &nameSpaceId);
01726 
01727     if (nameSpaceId == kNameSpaceID_Unknown) {
01728       // Unknown namespace means no matches, we create an empty list...
01729       list = NS_GetContentList(document, nsnull,
01730                                kNameSpaceID_None, nsnull).get();
01731       NS_ENSURE_TRUE(list, NS_ERROR_OUT_OF_MEMORY);
01732     }
01733   }
01734 
01735   if (!list) {
01736     nsCOMPtr<nsIAtom> nameAtom = do_GetAtom(aLocalName);
01737     NS_ENSURE_TRUE(nameAtom, NS_ERROR_OUT_OF_MEMORY);
01738 
01739     list = NS_GetContentList(document, nameAtom, nameSpaceId, this).get();
01740     NS_ENSURE_TRUE(list, NS_ERROR_OUT_OF_MEMORY);
01741   }
01742 
01743   // transfer ref to aReturn
01744   *aReturn = list;
01745   return NS_OK;
01746 }
01747 
01748 nsresult
01749 nsGenericElement::HasAttribute(const nsAString& aName, PRBool* aReturn)
01750 {
01751   NS_ENSURE_ARG_POINTER(aReturn);
01752 
01753   const nsAttrName* name = InternalGetExistingAttrNameFromQName(aName);
01754   *aReturn = (name != nsnull);
01755 
01756   return NS_OK;
01757 }
01758 
01759 nsresult
01760 nsGenericElement::HasAttributeNS(const nsAString& aNamespaceURI,
01761                                  const nsAString& aLocalName,
01762                                  PRBool* aReturn)
01763 {
01764   NS_ENSURE_ARG_POINTER(aReturn);
01765 
01766   PRInt32 nsid;
01767   nsContentUtils::GetNSManagerWeakRef()->GetNameSpaceID(aNamespaceURI, &nsid);
01768 
01769   if (nsid == kNameSpaceID_Unknown) {
01770     // Unknown namespace means no attr...
01771 
01772     *aReturn = PR_FALSE;
01773 
01774     return NS_OK;
01775   }
01776 
01777   nsCOMPtr<nsIAtom> name = do_GetAtom(aLocalName);
01778   *aReturn = HasAttr(nsid, name);
01779 
01780   return NS_OK;
01781 }
01782 
01783 nsresult
01784 nsGenericElement::JoinTextNodes(nsIContent* aFirst,
01785                                 nsIContent* aSecond)
01786 {
01787   nsresult rv = NS_OK;
01788   nsCOMPtr<nsIDOMText> firstText(do_QueryInterface(aFirst, &rv));
01789 
01790   if (NS_SUCCEEDED(rv)) {
01791     nsCOMPtr<nsIDOMText> secondText(do_QueryInterface(aSecond, &rv));
01792 
01793     if (NS_SUCCEEDED(rv)) {
01794       nsAutoString str;
01795 
01796       rv = secondText->GetData(str);
01797       if (NS_SUCCEEDED(rv)) {
01798         rv = firstText->AppendData(str);
01799       }
01800     }
01801   }
01802 
01803   return rv;
01804 }
01805 
01806 nsresult
01807 nsGenericElement::Normalize()
01808 {
01809   nsresult result = NS_OK;
01810   PRUint32 index, count = GetChildCount();
01811 
01812   for (index = 0; (index < count) && (NS_OK == result); index++) {
01813     nsIContent *child = GetChildAt(index);
01814 
01815     nsCOMPtr<nsIDOMNode> node = do_QueryInterface(child);
01816     if (node) {
01817       PRUint16 nodeType;
01818       node->GetNodeType(&nodeType);
01819 
01820       switch (nodeType) {
01821         case nsIDOMNode::TEXT_NODE:
01822 
01823           if (index+1 < count) {
01824             // Get the sibling. If it's also a text node, then
01825             // remove it from the tree and join the two text
01826             // nodes.
01827             nsIContent *sibling = GetChildAt(index + 1);
01828 
01829             nsCOMPtr<nsIDOMNode> siblingNode = do_QueryInterface(sibling);
01830 
01831             if (siblingNode) {
01832               PRUint16 siblingNodeType;
01833               siblingNode->GetNodeType(&siblingNodeType);
01834 
01835               if (siblingNodeType == nsIDOMNode::TEXT_NODE) {
01836                 result = RemoveChildAt(index+1, PR_TRUE);
01837                 if (NS_FAILED(result)) {
01838                   return result;
01839                 }
01840 
01841                 result = JoinTextNodes(child, sibling);
01842                 if (NS_FAILED(result)) {
01843                   return result;
01844                 }
01845                 count--;
01846                 index--;
01847               }
01848             }
01849           }
01850           break;
01851 
01852         case nsIDOMNode::ELEMENT_NODE:
01853           nsCOMPtr<nsIDOMElement> element = do_QueryInterface(child);
01854 
01855           if (element) {
01856             result = element->Normalize();
01857           }
01858           break;
01859       }
01860     }
01861   }
01862 
01863   return result;
01864 }
01865 
01866 nsresult
01867 nsGenericElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
01868                              nsIContent* aBindingParent,
01869                              PRBool aCompileEventHandlers)
01870 {
01871   NS_PRECONDITION(aParent || aDocument, "Must have document if no parent!");
01872   // XXXbz XUL elements are confused about their current doc when they're
01873   // cloned, so we don't assert if aParent is a XUL element and aDocument is
01874   // null, even if aParent->GetCurrentDoc() is non-null
01875   //  NS_PRECONDITION(!aParent || aDocument == aParent->GetCurrentDoc(),
01876   //                  "aDocument must be current doc of aParent");
01877   NS_PRECONDITION(!aParent ||
01878                   (aParent->IsContentOfType(eXUL) && aDocument == nsnull) ||
01879                   aDocument == aParent->GetCurrentDoc(),
01880                   "aDocument must be current doc of aParent");
01881   NS_PRECONDITION(!GetCurrentDoc(), "Already have a document.  Unbind first!");
01882   // Note that as we recurse into the kids, they'll have a non-null parent.  So
01883   // only assert if our parent is _changing_ while we have a parent.
01884   NS_PRECONDITION(!GetParent() || aParent == GetParent(),
01885                   "Already have a parent.  Unbind first!");
01886   NS_PRECONDITION(!GetBindingParent() ||
01887                   aBindingParent == GetBindingParent() ||
01888                   (!aBindingParent && aParent &&
01889                    aParent->GetBindingParent() == GetBindingParent()),
01890                   "Already have a binding parent.  Unbind first!");
01891   
01892   if (!aBindingParent && aParent) {
01893     aBindingParent = aParent->GetBindingParent();
01894   }
01895 
01896   // First set the binding parent
01897   if (aBindingParent) {
01898     nsDOMSlots *slots = GetDOMSlots();
01899 
01900     if (!slots) {
01901       return NS_ERROR_OUT_OF_MEMORY;
01902     }
01903 
01904     slots->mBindingParent = aBindingParent; // Weak, so no addref happens.
01905   }
01906 
01907   // Now set the parent; make sure to preserve the bits we have stashed there
01908   // Note that checking whether aParent == GetParent() is probably not worth it
01909   // here.
01910   PtrBits new_bits = NS_REINTERPRET_CAST(PtrBits, aParent);
01911   new_bits |= mParentPtrBits & nsIContent::kParentBitMask;
01912   mParentPtrBits = new_bits;
01913 
01914   nsresult rv;
01915   
01916   nsIDocument *oldOwnerDocument = GetOwnerDoc();
01917   nsIDocument *newOwnerDocument;
01918   nsNodeInfoManager* nodeInfoManager;
01919 
01920   // XXXbz sXBL/XBL2 issue!
01921 
01922   // Finally, set the document
01923   if (aDocument) {
01924     // Notify XBL- & nsIAnonymousContentCreator-generated
01925     // anonymous content that the document is changing.
01926     // XXXbz ordering issues here?  Probably not, since ChangeDocumentFor is
01927     // just pretty broken anyway....  Need to get it working.
01928     // XXXbz XBL doesn't handle this (asserts), and we don't really want
01929     // to be doing this during parsing anyway... sort this out.    
01930     //    aDocument->BindingManager()->ChangeDocumentFor(this, nsnull,
01931     //                                                   aDocument);
01932 
01933     // Being added to a document.
01934     mParentPtrBits |= PARENT_BIT_INDOCUMENT;
01935 
01936     newOwnerDocument = aDocument;
01937     nodeInfoManager = newOwnerDocument->NodeInfoManager();
01938   } else {
01939     newOwnerDocument = aParent->GetOwnerDoc();
01940     nodeInfoManager = aParent->GetNodeInfo()->NodeInfoManager();
01941   }
01942 
01943   // Handle a change in our owner document.
01944 
01945   if (oldOwnerDocument && oldOwnerDocument != newOwnerDocument) {
01946     // Remove all properties.
01947     oldOwnerDocument->PropertyTable()->DeleteAllPropertiesFor(this);
01948     nsCOMPtr<nsIDOMElement> domElement = do_QueryInterface(this);
01949     if (domElement) {
01950       nsCOMPtr<nsIDOMNSDocument> nsDoc = do_QueryInterface(oldOwnerDocument);
01951       if (nsDoc) {
01952         nsDoc->SetBoxObjectFor(domElement, nsnull);
01953       }
01954     }
01955   }
01956 
01957   if (mNodeInfo->NodeInfoManager() != nodeInfoManager) {
01958     nsCOMPtr<nsINodeInfo> newNodeInfo;
01959     rv = nodeInfoManager->GetNodeInfo(mNodeInfo->NameAtom(),
01960                                       mNodeInfo->GetPrefixAtom(),
01961                                       mNodeInfo->NamespaceID(),
01962                                       getter_AddRefs(newNodeInfo));
01963     NS_ENSURE_SUCCESS(rv, rv);
01964     NS_ASSERTION(newNodeInfo, "GetNodeInfo lies");
01965     mNodeInfo.swap(newNodeInfo);
01966   }
01967 
01968   // Now recurse into our kids
01969   PRUint32 i;
01970   for (i = 0; i < GetChildCount(); ++i) {
01971     // The child can remove itself from the parent in BindToTree.
01972     nsCOMPtr<nsIContent> child = mAttrsAndChildren.ChildAt(i);
01973     rv = child->BindToTree(aDocument, this, aBindingParent,
01974                            aCompileEventHandlers);
01975     NS_ENSURE_SUCCESS(rv, rv);
01976   }
01977 
01978   // XXXbz script execution during binding can trigger some of these
01979   // postcondition asserts....  But we do want that, since things will
01980   // generally be quite broken when that happens.
01981   NS_POSTCONDITION(aDocument == GetCurrentDoc(), "Bound to wrong document");
01982   NS_POSTCONDITION(aParent == GetParent(), "Bound to wrong parent");
01983   NS_POSTCONDITION(aBindingParent == GetBindingParent(),
01984                    "Bound to wrong binding parent");
01985   
01986   return NS_OK;
01987 }
01988 
01989 void
01990 nsGenericElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
01991 {
01992   NS_PRECONDITION(aDeep || (!GetCurrentDoc() && !GetBindingParent()),
01993                   "Shallow unbind won't clear document and binding parent on "
01994                   "kids!");
01995   // Make sure to unbind this node before doing the kids
01996   nsIDocument *document = GetCurrentDoc();
01997   if (document) {
01998     // Notify XBL- & nsIAnonymousContentCreator-generated
01999     // anonymous content that the document is changing.
02000     document->BindingManager()->ChangeDocumentFor(this, document, nsnull);
02001 
02002     if (HasAttr(kNameSpaceID_XLink, nsHTMLAtoms::href)) {
02003       document->ForgetLink(this);
02004     }
02005 
02006     nsCOMPtr<nsIDOMElement> domElement = do_QueryInterface(this);
02007 
02008     if (domElement) {
02009       nsCOMPtr<nsIDOMNSDocument> nsDoc = do_QueryInterface(document);
02010       nsDoc->SetBoxObjectFor(domElement, nsnull);
02011     }
02012   }
02013 
02014   // Unset things in the reverse order from how we set them in BindToTree
02015   mParentPtrBits &= ~PARENT_BIT_INDOCUMENT;
02016   
02017   if (aNullParent) {
02018     // Just mask it out
02019     mParentPtrBits &= nsIContent::kParentBitMask;
02020   }
02021   
02022   nsDOMSlots *slots = GetExistingDOMSlots();
02023   if (slots) {
02024     slots->mBindingParent = nsnull;
02025   }
02026 
02027   if (aDeep) {
02028     // Do the kids
02029     PRUint32 i, n = GetChildCount();
02030 
02031     for (i = 0; i < n; ++i) {
02032       // Note that we pass PR_FALSE for aNullParent here, since we don't want
02033       // the kids to forget us.  We _do_ want them to forget their binding
02034       // parent, though, since this only walks non-anonymous kids.
02035       mAttrsAndChildren.ChildAt(i)->UnbindFromTree(PR_TRUE, PR_FALSE);
02036     }
02037   }
02038 }
02039 
02040 PRBool
02041 nsGenericElement::IsNativeAnonymous() const
02042 {
02043   return !!(GetFlags() & GENERIC_ELEMENT_IS_ANONYMOUS);
02044 }
02045 
02046 void
02047 nsGenericElement::SetNativeAnonymous(PRBool aAnonymous)
02048 {
02049   if (aAnonymous) {
02050     SetFlags(GENERIC_ELEMENT_IS_ANONYMOUS);
02051   } else {
02052     UnsetFlags(GENERIC_ELEMENT_IS_ANONYMOUS);
02053   }
02054 }
02055 
02056 PRInt32
02057 nsGenericElement::GetNameSpaceID() const
02058 {
02059   return mNodeInfo->NamespaceID();
02060 }
02061 
02062 nsIAtom *
02063 nsGenericElement::Tag() const
02064 {
02065   return mNodeInfo->NameAtom();
02066 }
02067 
02068 nsINodeInfo *
02069 nsGenericElement::GetNodeInfo() const
02070 {
02071   return mNodeInfo;
02072 }
02073 
02074 nsresult
02075 nsGenericElement::HandleDOMEvent(nsPresContext* aPresContext,
02076                                  nsEvent* aEvent,
02077                                  nsIDOMEvent** aDOMEvent,
02078                                  PRUint32 aFlags,
02079                                  nsEventStatus* aEventStatus)
02080 {
02081   // Make sure to tell the event that dispatch has started.
02082   NS_MARK_EVENT_DISPATCH_STARTED(aEvent);
02083 
02084   nsresult ret = NS_OK;
02085   PRBool retarget = PR_FALSE;
02086   PRBool externalDOMEvent = PR_FALSE;
02087   nsCOMPtr<nsIDOMEventTarget> oldTarget;
02088 
02089   nsIDOMEvent* domEvent = nsnull;
02090   if (NS_EVENT_FLAG_INIT & aFlags) {
02091     if (aDOMEvent) {
02092       if (*aDOMEvent) {
02093         externalDOMEvent = PR_TRUE;   
02094       }
02095     } else {
02096       aDOMEvent = &domEvent;
02097     }
02098     aEvent->flags |= aFlags;
02099     aFlags &= ~(NS_EVENT_FLAG_CANT_BUBBLE | NS_EVENT_FLAG_CANT_CANCEL);
02100     aFlags |= NS_EVENT_FLAG_BUBBLE | NS_EVENT_FLAG_CAPTURE;
02101   }
02102 
02103   // Find out whether we're anonymous.
02104   if (IsNativeAnonymous()) {
02105     retarget = PR_TRUE;
02106   } else {
02107     nsIContent* parent = GetParent();
02108     if (parent) {
02109       if (*aDOMEvent) {
02110         (*aDOMEvent)->GetTarget(getter_AddRefs(oldTarget));
02111         nsCOMPtr<nsIContent> content(do_QueryInterface(oldTarget));
02112         if (content && content->GetBindingParent() == parent)
02113           retarget = PR_TRUE;
02114       } else if (GetBindingParent() == parent) {
02115         retarget = PR_TRUE;
02116       }
02117     }
02118   }
02119 
02120   // check for an anonymous parent
02121   nsCOMPtr<nsIContent> parent;
02122   nsIDocument* ownerDoc = GetOwnerDoc();
02123   if (ownerDoc) {
02124     ownerDoc->BindingManager()->GetInsertionParent(this,
02125                                                    getter_AddRefs(parent));
02126   }
02127   if (!parent) {
02128     // if we didn't find an anonymous parent, use the explicit one,
02129     // whether it's null or not...
02130     parent = GetParent();
02131   }
02132 
02133   if (retarget || (parent.get() != GetParent())) {
02134     if (!*aDOMEvent) {
02135       // We haven't made a DOMEvent yet.  Force making one now.
02136       nsCOMPtr<nsIEventListenerManager> listenerManager;
02137       if (NS_FAILED(ret = GetListenerManager(getter_AddRefs(listenerManager)))) {
02138         return ret;
02139       }
02140       nsAutoString empty;
02141       if (NS_FAILED(ret = listenerManager->CreateEvent(aPresContext, aEvent,
02142                                                        empty, aDOMEvent)))
02143         return ret;
02144     }
02145 
02146     if (!*aDOMEvent) {
02147       return NS_ERROR_FAILURE;
02148     }
02149     nsCOMPtr<nsIPrivateDOMEvent> privateEvent = do_QueryInterface(*aDOMEvent);
02150     if (!privateEvent) {
02151       return NS_ERROR_FAILURE;
02152     }
02153 
02154     (*aDOMEvent)->GetTarget(getter_AddRefs(oldTarget));
02155 
02156     PRBool hasOriginal;
02157     privateEvent->HasOriginalTarget(&hasOriginal);
02158 
02159     if (!hasOriginal)
02160       privateEvent->SetOriginalTarget(oldTarget);
02161 
02162     if (retarget) {
02163       nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(GetParent());
02164       privateEvent->SetTarget(target);
02165     }
02166   }
02167 
02168   //Capturing stage evaluation
02169   if (NS_EVENT_FLAG_CAPTURE & aFlags &&
02170       aEvent->message != NS_PAGE_LOAD &&
02171       aEvent->message != NS_SCRIPT_LOAD &&
02172       aEvent->message != NS_IMAGE_LOAD &&
02173       aEvent->message != NS_IMAGE_ERROR &&
02174       aEvent->message != NS_SCROLL_EVENT &&
02175       !(aEvent->eventStructType == NS_MUTATION_EVENT &&
02176         IsAnonymousForEvents())) {
02177     //Initiate capturing phase.  Special case first call to document
02178     if (parent) {
02179       parent->HandleDOMEvent(aPresContext, aEvent, aDOMEvent,
02180                              aFlags & NS_EVENT_CAPTURE_MASK,
02181                              aEventStatus);
02182     } else {
02183       nsIDocument* document = GetCurrentDoc();
02184       if (document) {
02185         ret = document->HandleDOMEvent(aPresContext, aEvent,
02186                                        aDOMEvent,
02187                                        aFlags & NS_EVENT_CAPTURE_MASK,
02188                                        aEventStatus);
02189       }
02190     }
02191   }
02192 
02193   if (retarget) {
02194     // The event originated beneath us, and we performed a retargeting.
02195     // We need to restore the original target of the event.
02196     nsCOMPtr<nsIPrivateDOMEvent> privateEvent = do_QueryInterface(*aDOMEvent);
02197     if (privateEvent)
02198       privateEvent->SetTarget(oldTarget);
02199   }
02200 
02201   // Weak pointer, which is fine since the hash table owns the
02202   // listener manager
02203   nsIEventListenerManager *lm = nsnull;
02204 
02205   if (HasEventListenerManager()) {
02206     EventListenerManagerMapEntry *entry =
02207       NS_STATIC_CAST(EventListenerManagerMapEntry *,
02208                      PL_DHashTableOperate(&sEventListenerManagersHash, this,
02209                                           PL_DHASH_LOOKUP));
02210 
02211     if (PL_DHASH_ENTRY_IS_FREE(entry)) {
02212       NS_ERROR("Huh, our bit says we have an event listener manager, but "
02213                "there's nothing in the hash!?!!");
02214 
02215       return NS_ERROR_UNEXPECTED;
02216     }
02217 
02218     lm = entry->mListenerManager;
02219   }
02220 
02221   //Local handling stage
02222   if (lm &&
02223       !(NS_EVENT_FLAG_CANT_BUBBLE & aEvent->flags &&
02224         NS_EVENT_FLAG_BUBBLE & aFlags && !(NS_EVENT_FLAG_INIT & aFlags)) &&
02225       !(aEvent->flags & NS_EVENT_FLAG_NO_CONTENT_DISPATCH)) {
02226     aEvent->flags |= aFlags;
02227 
02228     nsCOMPtr<nsIDOMEventTarget> curTarg =
02229       do_QueryInterface(NS_STATIC_CAST(nsIXMLContent *, this));
02230 
02231     lm->HandleEvent(aPresContext, aEvent, aDOMEvent, curTarg, aFlags,
02232                     aEventStatus);
02233 
02234     aEvent->flags &= ~aFlags;
02235   }
02236 
02237   if (retarget) {
02238     // The event originated beneath us, and we need to perform a
02239     // retargeting.
02240     nsCOMPtr<nsIPrivateDOMEvent> privateEvent = do_QueryInterface(*aDOMEvent);
02241     if (privateEvent) {
02242       nsCOMPtr<nsIDOMEventTarget> parentTarget(do_QueryInterface(GetParent()));
02243       privateEvent->SetTarget(parentTarget);
02244     }
02245   }
02246 
02247   //Bubbling stage
02248   if (NS_EVENT_FLAG_BUBBLE & aFlags && IsInDoc() &&
02249       aEvent->message != NS_PAGE_LOAD && aEvent->message != NS_SCRIPT_LOAD &&
02250       aEvent->message != NS_IMAGE_ERROR && aEvent->message != NS_IMAGE_LOAD &&
02251       // scroll events fired at elements don't bubble (although scroll events
02252       // fired at documents do, to the window)
02253       aEvent->message != NS_SCROLL_EVENT &&
02254       !(aEvent->eventStructType == NS_MUTATION_EVENT &&
02255         IsAnonymousForEvents())) {
02256     if (parent) {
02257       // If there's a parent we pass the event to the parent...
02258 
02259       ret = parent->HandleDOMEvent(aPresContext, aEvent, aDOMEvent,
02260                                    aFlags & NS_EVENT_BUBBLE_MASK,
02261                                    aEventStatus);
02262     } else {
02263       // If there's no parent but there is a document (i.e. this is
02264       // the root node) we pass the event to the document...
02265       nsIDocument* document = GetCurrentDoc();
02266       if (document) {
02267         ret = document->HandleDOMEvent(aPresContext, aEvent, aDOMEvent,
02268                                        aFlags & NS_EVENT_BUBBLE_MASK, 
02269                                        aEventStatus);
02270       }
02271     }
02272   }
02273 
02274   if (retarget) {
02275     // The event originated beneath us, and we performed a
02276     // retargeting.  We need to restore the original target of the
02277     // event.
02278 
02279     nsCOMPtr<nsIPrivateDOMEvent> privateEvent = do_QueryInterface(*aDOMEvent);
02280     if (privateEvent)
02281       privateEvent->SetTarget(oldTarget);
02282   }
02283 
02284   if (NS_EVENT_FLAG_INIT & aFlags) {
02285     // We're leaving the DOM event loop so if we created a DOM event,
02286     // release here.  If externalDOMEvent is set the event was passed
02287     // in and we don't own it
02288 
02289     if (*aDOMEvent && !externalDOMEvent) {
02290       nsrefcnt rc;
02291       NS_RELEASE2(*aDOMEvent, rc);
02292       if (0 != rc) {
02293         // Okay, so someone in the DOM loop (a listener, JS object)
02294         // still has a ref to the DOM Event but the internal data
02295         // hasn't been malloc'd.  Force a copy of the data here so the
02296         // DOM Event is still valid.
02297 
02298         nsCOMPtr<nsIPrivateDOMEvent> privateEvent =
02299           do_QueryInterface(*aDOMEvent);
02300 
02301         if (privateEvent) {
02302           privateEvent->DuplicatePrivateData();
02303         }
02304       }
02305 
02306       aDOMEvent = nsnull;
02307     }
02308 
02309     // Now that we're done with this event, remove the flag that says
02310     // we're in the process of dispatching this event.
02311     NS_MARK_EVENT_DISPATCH_DONE(aEvent);
02312   }
02313 
02314   return ret;
02315 }
02316 
02317 PRUint32
02318 nsGenericElement::ContentID() const
02319 {
02320   nsDOMSlots *slots = GetExistingDOMSlots();
02321 
02322   if (slots) {
02323     return slots->mContentID;
02324   }
02325 
02326   PtrBits flags = GetFlags();
02327 
02328   return flags >> GENERIC_ELEMENT_CONTENT_ID_BITS_OFFSET;
02329 }
02330 
02331 void
02332 nsGenericElement::SetContentID(PRUint32 aID)
02333 {
02334   // This should be in the constructor!!!
02335 
02336   if (HasDOMSlots() || aID > GENERIC_ELEMENT_CONTENT_ID_MAX_VALUE) {
02337     nsDOMSlots *slots = GetDOMSlots();
02338 
02339     if (slots) {
02340       slots->mContentID = aID;
02341     }
02342   } else {
02343     UnsetFlags(GENERIC_ELEMENT_CONTENT_ID_MASK);
02344     SetFlags(aID << GENERIC_ELEMENT_CONTENT_ID_BITS_OFFSET);
02345   }
02346 }
02347 
02348 NS_IMETHODIMP
02349 nsGenericElement::MaybeTriggerAutoLink(nsIDocShell *aShell)
02350 {
02351   return NS_OK;
02352 }
02353 
02354 nsIAtom*
02355 nsGenericElement::GetID() const
02356 {
02357   nsIAtom* IDName = GetIDAttributeName();
02358   if (IDName) {
02359     const nsAttrValue* attrVal = mAttrsAndChildren.GetAttr(IDName);
02360     if (attrVal){
02361       if (attrVal->Type() == nsAttrValue::eAtom) {
02362         return attrVal->GetAtomValue();
02363       }
02364       if(attrVal->IsEmptyString()){
02365         return nsnull;
02366       }
02367       // Check if the ID has been stored as a string.
02368       // This would occur if the ID attribute name changed after 
02369       // the ID was parsed. 
02370       if (attrVal->Type() == nsAttrValue::eString) {
02371         nsAutoString idVal(attrVal->GetStringValue());
02372 
02373         // Create an atom from the value and set it into the attribute list. 
02374         NS_CONST_CAST(nsAttrValue*, attrVal)->ParseAtom(idVal);
02375         return attrVal->GetAtomValue();
02376       }
02377     }
02378   }
02379   return nsnull;
02380 }
02381 
02382 const nsAttrValue*
02383 nsGenericElement::GetClasses() const
02384 {
02385   return nsnull;
02386 }
02387 
02388 NS_IMETHODIMP_(PRBool)
02389 nsGenericElement::HasClass(nsIAtom* aClass, PRBool aCaseSensitive) const
02390 {
02391   return PR_FALSE;
02392 }
02393 
02394 NS_IMETHODIMP
02395 nsGenericElement::WalkContentStyleRules(nsRuleWalker* aRuleWalker)
02396 {
02397   return NS_OK;
02398 }
02399 
02400 nsICSSStyleRule*
02401 nsGenericElement::GetInlineStyleRule()
02402 {
02403   return nsnull;
02404 }
02405 
02406 NS_IMETHODIMP
02407 nsGenericElement::SetInlineStyleRule(nsICSSStyleRule* aStyleRule,
02408                                      PRBool aNotify)
02409 {
02410   NS_NOTYETIMPLEMENTED("nsGenericElement::SetInlineStyleRule");
02411   return NS_ERROR_NOT_IMPLEMENTED;
02412 }
02413 
02414 NS_IMETHODIMP_(PRBool)
02415 nsGenericElement::IsAttributeMapped(const nsIAtom* aAttribute) const
02416 {
02417   return PR_FALSE;
02418 }
02419 
02420 nsChangeHint
02421 nsGenericElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
02422                                          PRInt32 aModType) const
02423 {
02424   return nsChangeHint(0);
02425 }
02426 
02427 nsIAtom *
02428 nsGenericElement::GetIDAttributeName() const
02429 {
02430   return mNodeInfo->GetIDAttributeAtom();
02431 }
02432 
02433 nsIAtom *
02434 nsGenericElement::GetClassAttributeName() const
02435 {
02436   return nsnull;
02437 }
02438 
02439 PRBool
02440 nsGenericElement::FindAttributeDependence(const nsIAtom* aAttribute,
02441                                           const MappedAttributeEntry* const aMaps[],
02442                                           PRUint32 aMapCount)
02443 {
02444   for (PRUint32 mapindex = 0; mapindex < aMapCount; ++mapindex) {
02445     for (const MappedAttributeEntry* map = aMaps[mapindex];
02446          map->attribute; ++map) {
02447       if (aAttribute == *map->attribute) {
02448         return PR_TRUE;
02449       }
02450     }
02451   }
02452 
02453   return PR_FALSE;
02454 }
02455 
02456 already_AddRefed<nsINodeInfo>
02457 nsGenericElement::GetExistingAttrNameFromQName(const nsAString& aStr) const
02458 {
02459   const nsAttrName* name = InternalGetExistingAttrNameFromQName(aStr);
02460   if (!name) {
02461     return nsnull;
02462   }
02463 
02464   nsINodeInfo* nodeInfo;
02465   if (name->IsAtom()) {
02466     mNodeInfo->NodeInfoManager()->GetNodeInfo(name->Atom(), nsnull,
02467                                               kNameSpaceID_None, &nodeInfo);
02468   }
02469   else {
02470     NS_ADDREF(nodeInfo = name->NodeInfo());
02471   }
02472 
02473   return nodeInfo;
02474 }
02475 
02476 already_AddRefed<nsIURI>
02477 nsGenericElement::GetBaseURI() const
02478 {
02479   nsIDocument* doc = GetOwnerDoc();
02480   if (!doc) {
02481     // We won't be able to do security checks, etc.  So don't go any
02482     // further.  That said, this really shouldn't happen...
02483     NS_ERROR("Element without owner document");
02484     return nsnull;
02485   }
02486 
02487   // Our base URL depends on whether we have an xml:base attribute, as
02488   // well as on whether any of our ancestors do.
02489   nsCOMPtr<nsIURI> parentBase;
02490 
02491   nsIContent *parent = GetParent();
02492   if (parent) {
02493     parentBase = parent->GetBaseURI();
02494   } else {
02495     // No parent, so just use the document (we must be the root or not in the
02496     // tree).
02497     parentBase = doc->GetBaseURI();
02498   }
02499   
02500   // Now check for an xml:base attr 
02501   nsAutoString value;
02502   nsresult rv = GetAttr(kNameSpaceID_XML, nsHTMLAtoms::base, value);
02503   if (rv != NS_CONTENT_ATTR_HAS_VALUE) {
02504     // No xml:base, so we just use the parent's base URL
02505     nsIURI *base = parentBase;
02506     NS_IF_ADDREF(base);
02507 
02508     return base;
02509   }
02510 
02511   nsCOMPtr<nsIURI> ourBase;
02512   rv = NS_NewURI(getter_AddRefs(ourBase), value,
02513                  doc->GetDocumentCharacterSet().get(), parentBase);
02514   if (NS_SUCCEEDED(rv)) {
02515     // do a security check, almost the same as nsDocument::SetBaseURL()
02516     rv = nsContentUtils::GetSecurityManager()->
02517       CheckLoadURIWithPrincipal(doc->GetPrincipal(), ourBase,
02518                                 nsIScriptSecurityManager::STANDARD);
02519   }
02520 
02521   nsIURI *base;
02522   if (NS_FAILED(rv)) {
02523     base = parentBase;
02524   } else {
02525     base = ourBase;
02526   }
02527 
02528   NS_IF_ADDREF(base);
02529 
02530   return base;    
02531 }
02532 
02533 nsresult
02534 nsGenericElement::RangeAdd(nsIDOMRange* aRange)
02535 {
02536   if (!sRangeListsHash.ops) {
02537     // We've already been shut down, don't bother adding a range...
02538 
02539     return NS_OK;
02540   }
02541 
02542   RangeListMapEntry *entry =
02543     NS_STATIC_CAST(RangeListMapEntry *,
02544                    PL_DHashTableOperate(&sRangeListsHash, this, PL_DHASH_ADD));
02545 
02546   if (!entry) {
02547     return NS_ERROR_OUT_OF_MEMORY;
02548   }
02549 
02550   // lazy allocation of range list
02551   if (!entry->mRangeList) {
02552     NS_ASSERTION(!(GetFlags() & GENERIC_ELEMENT_HAS_RANGELIST),
02553                  "Huh, nsGenericElement flags don't reflect reality!!!");
02554 
02555     entry->mRangeList = new nsAutoVoidArray();
02556 
02557     if (!entry->mRangeList) {
02558       PL_DHashTableRawRemove(&sRangeListsHash, entry);
02559 
02560       return NS_ERROR_OUT_OF_MEMORY;
02561     }
02562 
02563     SetFlags(GENERIC_ELEMENT_HAS_RANGELIST);
02564   }
02565 
02566   // Make sure we don't add a range that is already in the list!
02567   PRInt32 i = entry->mRangeList->IndexOf(aRange);
02568 
02569   if (i >= 0) {
02570     // Range is already in the list, so there is nothing to do!
02571 
02572     return NS_OK;
02573   }
02574 
02575   // dont need to addref - this call is made by the range object
02576   // itself
02577   PRBool rv = entry->mRangeList->AppendElement(aRange);
02578   if (!rv) {
02579     if (entry->mRangeList->Count() == 0) {
02580       // Fresh entry, remove it from the hash...
02581 
02582       PL_DHashTableRawRemove(&sRangeListsHash, entry);
02583     }
02584 
02585     return NS_ERROR_OUT_OF_MEMORY;
02586   }
02587 
02588   return NS_OK;
02589 }
02590 
02591 
02592 void
02593 nsGenericElement::RangeRemove(nsIDOMRange* aRange)
02594 {
02595   if (!HasRangeList()) {
02596     return;
02597   }
02598 
02599   RangeListMapEntry *entry =
02600     NS_STATIC_CAST(RangeListMapEntry *,
02601                    PL_DHashTableOperate(&sRangeListsHash, this,
02602                                         PL_DHASH_LOOKUP));
02603 
02604   if (PL_DHASH_ENTRY_IS_FREE(entry)) {
02605     NS_ERROR("Huh, our bit says we have a range list, but there's nothing "
02606              "in the hash!?!!");
02607 
02608     return;
02609   }
02610 
02611   if (!entry->mRangeList) {
02612     return;
02613   }
02614 
02615   // dont need to release - this call is made by the range object itself
02616   entry->mRangeList->RemoveElement(aRange);
02617 
02618   if (entry->mRangeList->Count() == 0) {
02619     PL_DHashTableRawRemove(&sRangeListsHash, entry);
02620 
02621     UnsetFlags(GENERIC_ELEMENT_HAS_RANGELIST);
02622   }
02623 }
02624 
02625 const nsVoidArray *
02626 nsGenericElement::GetRangeList() const
02627 {
02628   if (!HasRangeList()) {
02629     return nsnull;
02630   }
02631 
02632   RangeListMapEntry *entry =
02633     NS_STATIC_CAST(RangeListMapEntry *,
02634                    PL_DHashTableOperate(&sRangeListsHash, this,
02635                                         PL_DHASH_LOOKUP));
02636 
02637   if (PL_DHASH_ENTRY_IS_FREE(entry)) {
02638     NS_ERROR("Huh, our bit says we have a range list, but there's nothing "
02639              "in the hash!?!!");
02640 
02641     return nsnull;
02642   }
02643 
02644   return entry->mRangeList;
02645 }
02646 
02647 void
02648 nsGenericElement::SetFocus(nsPresContext* aPresContext)
02649 {
02650   // Traditionally focusable elements can take focus as long as they don't set
02651   // the disabled attribute
02652 
02653   nsIFrame* frame = nsnull;
02654   nsCOMPtr<nsIPresShell> presShell = aPresContext->PresShell();
02655   presShell->GetPrimaryFrameFor(this, &frame);
02656   if (frame && frame->IsFocusable()) {
02657     aPresContext->EventStateManager()->SetContentState(this,
02658                                                         NS_EVENT_STATE_FOCUS);
02659     // Setting content state can cause the frame to be destroyed because of
02660     // style changes so we need to lookup the frame again (bug 330367).
02661     presShell->GetPrimaryFrameFor(this, &frame);
02662     if (frame) {
02663       presShell->ScrollFrameIntoView(frame, NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE,
02664                                      NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE);
02665     }
02666   }
02667 }
02668 
02669 // static
02670 PRBool
02671 nsGenericElement::ShouldFocus(nsIContent *aContent)
02672 {
02673   // Default to false, since if the document is not attached to a window,
02674   // we should not focus any of its content.
02675   PRBool visible = PR_FALSE;
02676 
02677   // Figure out if we're focusing an element in an inactive (hidden)
02678   // tab (whose docshell is not visible), if so, drop this focus
02679   // request on the floor
02680 
02681   nsIDocument *document = aContent->GetDocument();
02682 
02683   if (document) {
02684     nsIScriptGlobalObject *sgo = document->GetScriptGlobalObject();
02685 
02686     if (sgo) {
02687       nsCOMPtr<nsIWebNavigation> webNav(do_GetInterface(sgo));
02688       nsCOMPtr<nsIBaseWindow> baseWin(do_QueryInterface(webNav));
02689 
02690       if (baseWin) {
02691         baseWin->GetVisibility(&visible);
02692       }
02693     }
02694   }
02695 
02696   return visible;
02697 }
02698 
02699 nsIContent*
02700 nsGenericElement::GetBindingParent() const
02701 {
02702   nsDOMSlots *slots = GetExistingDOMSlots();
02703 
02704   if (slots) {
02705     return slots->mBindingParent;
02706   }
02707   return nsnull;
02708 }
02709 
02710 PRBool
02711 nsGenericElement::IsContentOfType(PRUint32 aFlags) const
02712 {
02713   return !(aFlags & ~eELEMENT);
02714 }
02715 
02716 //----------------------------------------------------------------------
02717 
02718 nsresult
02719 nsGenericElement::GetListenerManager(nsIEventListenerManager **aResult)
02720 {
02721   *aResult = nsnull;
02722 
02723   if (!sEventListenerManagersHash.ops) {
02724     // We're already shut down, don't bother creating a event listener
02725     // manager.
02726 
02727     return NS_ERROR_NOT_AVAILABLE;
02728   }
02729 
02730   EventListenerManagerMapEntry *entry =
02731     NS_STATIC_CAST(EventListenerManagerMapEntry *,
02732                    PL_DHashTableOperate(&sEventListenerManagersHash, this,
02733                                         PL_DHASH_ADD));
02734 
02735   if (!entry) {
02736     return NS_ERROR_OUT_OF_MEMORY;
02737   }
02738 
02739   if (!entry->mListenerManager) {
02740     nsresult rv =
02741       NS_NewEventListenerManager(getter_AddRefs(entry->mListenerManager));
02742 
02743     if (NS_FAILED(rv)) {
02744       PL_DHashTableRawRemove(&sEventListenerManagersHash, entry);
02745 
02746       return rv;
02747     }
02748 
02749     entry->mListenerManager->SetListenerTarget(NS_STATIC_CAST(nsIXMLContent *,
02750                                                               this));
02751 
02752     SetFlags(GENERIC_ELEMENT_HAS_LISTENERMANAGER);
02753   }
02754 
02755   *aResult = entry->mListenerManager;
02756   NS_ADDREF(*aResult);
02757 
02758   return NS_OK;
02759 }
02760 
02761 // virtual
02762 void
02763 nsGenericElement::SetMayHaveFrame(PRBool aMayHaveFrame)
02764 {
02765   if (aMayHaveFrame) {
02766     SetFlags(GENERIC_ELEMENT_MAY_HAVE_FRAME);
02767   } else {
02768     UnsetFlags(GENERIC_ELEMENT_MAY_HAVE_FRAME);
02769   }
02770 }
02771 
02772 // virtual
02773 PRBool
02774 nsGenericElement::MayHaveFrame() const
02775 {
02776   return !!(GetFlags() & GENERIC_ELEMENT_MAY_HAVE_FRAME);
02777 }
02778 
02779 nsresult
02780 nsGenericElement::InsertChildAt(nsIContent* aKid,
02781                                 PRUint32 aIndex,
02782                                 PRBool aNotify)
02783 {
02784   NS_PRECONDITION(aKid, "null ptr");
02785 
02786   return doInsertChildAt(aKid, aIndex, aNotify, this, GetCurrentDoc(),
02787                          mAttrsAndChildren);
02788 }
02789 
02790 
02791 static nsresult
02792 doInsertChildAt(nsIContent* aKid, PRUint32 aIndex, PRBool aNotify,
02793                 nsIContent* aParent, nsIDocument* aDocument,
02794                 nsAttrAndChildArray& aChildArray)
02795 {
02796   NS_PRECONDITION(aParent || aDocument, "Must have document if no parent!");
02797   NS_PRECONDITION(!aParent || aParent->GetCurrentDoc() == aDocument,
02798                   "Incorrect aDocument");
02799 
02800   PRUint32 childCount = aChildArray.ChildCount();
02801   NS_ENSURE_TRUE(aIndex <= childCount, NS_ERROR_ILLEGAL_VALUE);
02802 
02803   nsMutationGuard::DidMutate();
02804 
02805   PRBool isAppend = (aIndex == childCount);
02806 
02807   mozAutoDocUpdate updateBatch(aDocument, UPDATE_CONTENT_MODEL, aNotify);
02808   
02809   // Note that SetRootContent already deals with binding, so if we plan to call
02810   // it we shouldn't bind ourselves.
02811   // XXXbz this doesn't put aKid in the right spot, really... We really need a
02812   // better api for handling kids on documents.
02813   if (!aParent && aKid->IsContentOfType(nsIContent::eELEMENT)) {
02814     nsresult rv = aDocument->SetRootContent(aKid);
02815     NS_ENSURE_SUCCESS(rv, rv);
02816   } else {
02817     nsresult rv = aChildArray.InsertChildAt(aKid, aIndex);
02818     NS_ENSURE_SUCCESS(rv, rv);
02819 
02820     rv = aKid->BindToTree(aDocument, aParent, nsnull, PR_TRUE);
02821     if (NS_FAILED(rv)) {
02822       aChildArray.RemoveChildAt(aIndex);
02823       aKid->UnbindFromTree();
02824       return rv;
02825     }
02826   }
02827   
02828   if (aParent && !aParent->IsContentOfType(nsIContent::eXUL)) {
02829     nsRange::OwnerChildInserted(aParent, aIndex);
02830   }
02831   
02832   // The kid may have removed its parent from the document, so recheck that
02833   // that's still in the document before proceeding.  Also, the kid may have
02834   // just removed itself, in which case we don't really want to fire
02835   // ContentAppended or a mutation event.
02836   // XXXbz What if the kid just moved us in the document?  Scripts suck.  We
02837   // really need to stop running them while we're in the middle of modifying
02838   // the DOM....
02839   if (aNotify && aDocument && aKid->GetCurrentDoc() == aDocument &&
02840       (!aParent || aKid->GetParent() == aParent)) {
02841     // Note that we always want to call ContentInserted when things are added
02842     // as kids to documents
02843     if (aParent && isAppend) {
02844       aDocument->ContentAppended(aParent, aIndex);
02845     } else {
02846       aDocument->ContentInserted(aParent, aKid, aIndex);
02847     }
02848     
02849     // XXXbz how come we're not firing mutation listeners for adding to
02850     // documents?
02851     if (aParent &&
02852         nsGenericElement::HasMutationListeners(aParent,
02853                                                NS_EVENT_BITS_MUTATION_NODEINSERTED)) {
02854       nsMutationEvent mutation(PR_TRUE, NS_MUTATION_NODEINSERTED, aKid);
02855       mutation.mRelatedNode = do_QueryInterface(aParent);
02856         
02857       nsEventStatus status = nsEventStatus_eIgnore;
02858       aKid->HandleDOMEvent(nsnull, &mutation, nsnull, NS_EVENT_FLAG_INIT, &status);
02859     }
02860   }
02861 
02862   return NS_OK;
02863 }
02864 
02865 nsresult
02866 nsGenericElement::AppendChildTo(nsIContent* aKid, PRBool aNotify)
02867 {
02868   NS_PRECONDITION(aKid && this != aKid, "null ptr");
02869   nsIDocument *document = GetCurrentDoc();
02870   mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
02871   
02872   nsresult rv = mAttrsAndChildren.AppendChild(aKid);
02873   NS_ENSURE_SUCCESS(rv, rv);
02874   
02875   rv = aKid->BindToTree(document, this, nsnull, PR_TRUE);
02876   if (NS_FAILED(rv)) {
02877     mAttrsAndChildren.RemoveChildAt(GetChildCount() - 1);
02878     aKid->UnbindFromTree();
02879     return rv;
02880   }
02881   // ranges don't need adjustment since new child is at end of list
02882 
02883   // The kid may have removed us from the document, so recheck that we're still
02884   // in the document before proceeding.  Also, the kid may have just removed
02885   // itself, in which case we don't really want to fire ContentAppended or a
02886   // mutation event.
02887   // XXXbz What if the kid just moved us in the document?  Scripts suck.  We
02888   // really need to stop running them while we're in the middle of modifying
02889   // the DOM....
02890   if (aNotify && document && document == GetCurrentDoc() &&
02891       aKid->GetParent() == this) {
02892     document->ContentAppended(this, GetChildCount() - 1);
02893     
02894     if (HasMutationListeners(this, NS_EVENT_BITS_MUTATION_NODEINSERTED)) {
02895       nsMutationEvent mutation(PR_TRUE, NS_MUTATION_NODEINSERTED, aKid);
02896       mutation.mRelatedNode = do_QueryInterface(this);
02897       
02898       nsEventStatus status = nsEventStatus_eIgnore;
02899       aKid->HandleDOMEvent(nsnull, &mutation, nsnull, NS_EVENT_FLAG_INIT, 
02900                            &status);
02901     }
02902   }
02903 
02904   return NS_OK;
02905 }
02906 
02907 nsresult
02908 nsGenericElement::RemoveChildAt(PRUint32 aIndex, PRBool aNotify)
02909 {
02910   nsCOMPtr<nsIContent> oldKid = mAttrsAndChildren.GetSafeChildAt(aIndex);
02911   NS_ASSERTION(oldKid == GetChildAt(aIndex), "Unexpected child in RemoveChildAt");
02912 
02913   if (oldKid) {
02914     return doRemoveChildAt(aIndex, aNotify, oldKid, this, GetCurrentDoc(),
02915                            mAttrsAndChildren);
02916   }
02917 
02918   return NS_OK;
02919 }
02920 
02921 // Note: A lot of methods like IndexOf(), GetChildCount(), etc, need to do more
02922 // than just look at the child array for some subclasses, so make sure to call
02923 // them instead of just messing with aChildArray
02924 struct nsContentOrDocument {
02925   nsContentOrDocument(nsIContent* aContent, nsIDocument* aDocument) :
02926     mContent(aContent), mDocument(aDocument)
02927   {}
02928 
02929   PRInt32 IndexOf(nsIContent* aPossibleChild)
02930   {
02931     return mContent ? mContent->IndexOf(aPossibleChild) :
02932       mDocument->IndexOf(aPossibleChild);
02933   }
02934 
02935   PRUint32 GetChildCount()
02936   {
02937     return mContent ? mContent->GetChildCount() :
02938       mDocument->GetChildCount();
02939   }
02940 
02941   nsIContent* GetChildAt(PRUint32 aIndex)
02942   {
02943     return mContent ? mContent->GetChildAt(aIndex) :
02944       mDocument->GetChildAt(aIndex);
02945   }
02946 
02947   nsIDocument* GetOwnerDoc()
02948   {
02949     return mContent ? mContent->GetOwnerDoc() : mDocument;
02950   }
02951 
02952   nsresult InsertChildAt(nsIContent* aKid, PRUint32 aIndex, PRBool aNotify,
02953                          nsAttrAndChildArray& aChildArray)
02954   {
02955     // XXXbz can't quite use doInsertChildAt because InsertChildAt has this
02956     // random subclass notification it now does... and because subclasses
02957     // might be intercepting InsertChildAt and doing stuff.
02958     return mContent ? mContent->InsertChildAt(aKid, aIndex, aNotify) :
02959       doInsertChildAt(aKid, aIndex, aNotify, mContent, mDocument, aChildArray);
02960   }
02961 
02962   nsresult RemoveChildAt(PRUint32 aIndex, PRBool aNotify)
02963   {
02964     // XXXbz can't quite use doRemoveChildAt because RemoveChildAt has this
02965     // random subclass notification it now does... and because subclasses
02966     // might be intercepting RemoveChildAt and doing stuff.
02967     if (mContent) {
02968       return mContent->RemoveChildAt(aIndex, aNotify);
02969     }
02970 
02971     nsCOMPtr<nsIDocument_MOZILLA_1_8_0_BRANCH> doc =
02972       do_QueryInterface(mDocument);
02973 
02974     return doc->RemoveChildAt(aIndex, aNotify);
02975   }
02976   
02977   PRBool Equals(nsContentOrDocument& aOther)
02978   {
02979     return mContent ? mContent == aOther.mContent :
02980                       mDocument == aOther.mDocument;
02981   }
02982   
02983   nsIContent* mContent;
02984   nsIDocument* mDocument;
02985 };
02986 
02987 
02988 nsresult
02989 doRemoveChildAt(PRUint32 aIndex, PRBool aNotify, nsIContent* aKid,
02990                 nsIContent* aParent, nsIDocument* aDocument,
02991                 nsAttrAndChildArray& aChildArray)
02992 {
02993   NS_PRECONDITION(aParent || aDocument, "Must have document if no parent!");
02994   NS_PRECONDITION(!aParent || aParent->GetCurrentDoc() == aDocument,
02995                   "Incorrect aDocument");
02996 
02997   nsMutationGuard::DidMutate();
02998 
02999   nsContentOrDocument container(aParent, aDocument);
03000   
03001   NS_PRECONDITION(aKid && aKid->GetParent() == aParent &&
03002                   aKid == container.GetChildAt(aIndex) &&
03003                   container.IndexOf(aKid) == (PRInt32)aIndex, "Bogus aKid");
03004 
03005   mozAutoDocUpdate updateBatch(aDocument, UPDATE_CONTENT_MODEL, aNotify);
03006 
03007   if (aNotify) {
03008     nsMutationGuard guard;
03009 
03010     if (aParent && 
03011         nsGenericElement::HasMutationListeners(aParent,
03012                                                NS_EVENT_BITS_MUTATION_NODEREMOVED)) {
03013       nsMutationEvent mutation(PR_TRUE, NS_MUTATION_NODEREMOVED, aKid);
03014       mutation.mRelatedNode = do_QueryInterface(aParent);
03015       
03016       nsEventStatus status = nsEventStatus_eIgnore;
03017       aKid->HandleDOMEvent(nsnull, &mutation, nsnull,
03018                            NS_EVENT_FLAG_INIT, &status);
03019     }
03020     
03021     // Someone may have removed the kid or any of its siblings while that event
03022     // was processing.
03023     if (guard.Mutated(0)) {
03024       aIndex = container.IndexOf(aKid);
03025       if (aIndex == (PRUint32)(-1)) {
03026         return NS_OK;
03027       }
03028     }
03029   }
03030 
03031   if (aParent && !aParent->IsContentOfType(nsIContent::eXUL)) {
03032     nsRange::OwnerChildRemoved(aParent, aIndex, aKid);
03033   }
03034 
03035   // Note that SetRootContent already deals with unbinding, so if we plan to
03036   // call it we shouldn't unbind ourselves.  It also deals with removing the
03037   // node from the child array, but not with notifying, unfortunately.  So we
03038   // have to call ContentRemoved ourselves after setting the root content.
03039   if (!aParent && aKid->IsContentOfType(nsIContent::eELEMENT)) {
03040     aDocument->SetRootContent(nsnull);
03041     if (aNotify) {
03042       aDocument->ContentRemoved(aParent, aKid, aIndex);
03043     }
03044   } else {
03045     aChildArray.RemoveChildAt(aIndex);
03046 
03047     if (aNotify && aDocument) {
03048       aDocument->ContentRemoved(aParent, aKid, aIndex);
03049     }
03050 
03051     aKid->UnbindFromTree();
03052   }
03053 
03054   return NS_OK;
03055 }
03056 
03057 
03058 
03059 //----------------------------------------------------------------------
03060 
03061 // Generic DOMNode implementations
03062 
03063 /*
03064  * This helper function checks if aChild is the same as aNode or if
03065  * aChild is one of aNode's ancestors. -- jst@citec.fi
03066  */
03067 
03068 NS_IMETHODIMP
03069 nsGenericElement::InsertBefore(nsIDOMNode *aNewChild, nsIDOMNode *aRefChild,
03070                                nsIDOMNode **aReturn)
03071 {
03072   return doReplaceOrInsertBefore(PR_FALSE, aNewChild, aRefChild, this,
03073                                  GetCurrentDoc(), mAttrsAndChildren, aReturn);
03074 }
03075 
03076 NS_IMETHODIMP
03077 nsGenericElement::ReplaceChild(nsIDOMNode* aNewChild, nsIDOMNode* aOldChild,
03078                                nsIDOMNode** aReturn)
03079 {
03080   return doReplaceOrInsertBefore(PR_TRUE, aNewChild, aOldChild, this,
03081                                  GetCurrentDoc(), mAttrsAndChildren, aReturn);
03082 }
03083 
03084 // When replacing, aRefContent is the content being replaced; when
03085 // inserting it's the content before which we're inserting.  In the
03086 // latter case it may be null.
03087 static
03088 PRBool IsAllowedAsChild(nsIContent* aNewChild, PRUint16 aNewNodeType,
03089                         nsIContent* aParent, nsIDocument* aDocument,
03090                         PRBool aIsReplace, nsIContent* aRefContent)
03091 {
03092   NS_PRECONDITION(aNewChild, "Must have new child");
03093   NS_PRECONDITION(!aIsReplace || aRefContent,
03094                   "Must have ref content for replace");
03095 #ifdef DEBUG
03096   PRUint16 debugNodeType = 0;
03097   nsCOMPtr<nsIDOMNode> debugNode(do_QueryInterface(aNewChild));
03098   nsresult debugRv = debugNode->GetNodeType(&debugNodeType);
03099 
03100   NS_PRECONDITION(NS_SUCCEEDED(debugRv) && debugNodeType == aNewNodeType,
03101                   "Bogus node type passed");
03102 #endif
03103 
03104   if (aParent && nsContentUtils::ContentIsDescendantOf(aParent, aNewChild)) {
03105     return PR_FALSE;
03106   }
03107 
03108   // The allowed child nodes differ for documents and elements
03109   switch (aNewNodeType) {
03110   case nsIDOMNode::COMMENT_NODE :
03111   case nsIDOMNode::PROCESSING_INSTRUCTION_NODE :
03112     // OK in both cases
03113     return PR_TRUE;
03114   case nsIDOMNode::TEXT_NODE :
03115   case nsIDOMNode::CDATA_SECTION_NODE :
03116   case nsIDOMNode::ENTITY_REFERENCE_NODE :
03117     // Only allowed under elements
03118     return aParent != nsnull;
03119   case nsIDOMNode::ELEMENT_NODE :
03120     {
03121       if (aParent) {
03122         // Always ok to have elements under other elements
03123         return PR_TRUE;
03124       }
03125 
03126       nsIContent* rootContent = aDocument->GetRootContent();
03127       if (rootContent) {
03128         // Already have a documentElement, so this is only OK if we're
03129         // replacing it.
03130         return aIsReplace && rootContent == aRefContent;
03131       }
03132 
03133       // We don't have a documentElement yet.  Our one remaining constraint is
03134       // that the documentElement must come after the doctype.
03135       if (!aRefContent) {
03136         // Appending is just fine.
03137         return PR_TRUE;
03138       }
03139 
03140       // Now grovel for a doctype
03141       nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(aDocument);
03142       NS_ASSERTION(doc, "Shouldn't happen");
03143       nsCOMPtr<nsIDOMDocumentType> docType;
03144       doc->GetDoctype(getter_AddRefs(docType));
03145       nsCOMPtr<nsIContent> docTypeContent = do_QueryInterface(docType);
03146       
03147       if (!docTypeContent) {
03148         // It's all good.
03149         return PR_TRUE;
03150       }
03151 
03152       PRInt32 doctypeIndex = aDocument->IndexOf(docTypeContent);
03153       PRInt32 insertIndex = aDocument->IndexOf(aRefContent);
03154 
03155       // Now we're OK in the following two cases only:
03156       // 1) We're replacing something that's not before the doctype
03157       // 2) We're inserting before something that comes after the doctype 
03158       return aIsReplace ? (insertIndex >= doctypeIndex) :
03159         insertIndex > doctypeIndex;
03160     }
03161   case nsIDOMNode::DOCUMENT_TYPE_NODE :
03162     {
03163       if (aParent) {
03164         // no doctypes allowed under elements
03165         return PR_FALSE;
03166       }
03167 
03168       nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(aDocument);
03169       NS_ASSERTION(doc, "Shouldn't happen");
03170       nsCOMPtr<nsIDOMDocumentType> docType;
03171       doc->GetDoctype(getter_AddRefs(docType));
03172       nsCOMPtr<nsIContent> docTypeContent = do_QueryInterface(docType);
03173       if (docTypeContent) {
03174         // Already have a doctype, so this is only OK if we're replacing it
03175         return aIsReplace && docTypeContent == aRefContent;
03176       }
03177 
03178       // We don't have a doctype yet.  Our one remaining constraint is
03179       // that the doctype must come before the documentElement.
03180       nsIContent* rootContent = aDocument->GetRootContent();
03181       if (!rootContent) {
03182         // It's all good
03183         return PR_TRUE;
03184       }
03185 
03186       if (!aRefContent) {
03187         // Trying to append a doctype, but have a documentElement
03188         return PR_FALSE;
03189       }
03190 
03191       PRInt32 rootIndex = aDocument->IndexOf(rootContent);
03192       PRInt32 insertIndex = aDocument->IndexOf(aRefContent);
03193 
03194       // Now we're OK if and only if insertIndex <= rootIndex.  Indeed, either
03195       // we end up replacing aRefContent or we end up before it.  Either one is
03196       // ok as long as aRefContent is not after rootContent.
03197       return insertIndex <= rootIndex;
03198     }
03199   case nsIDOMNode::DOCUMENT_FRAGMENT_NODE :
03200     {
03201       // Note that for now we only allow nodes inside document fragments if
03202       // they're allowed inside elements.  If we ever change this to allow
03203       // doctype nodes in document fragments, we'll need to update this code
03204       if (aParent) {
03205         // All good here
03206         return PR_TRUE;
03207       }
03208 
03209       PRBool sawElement = PR_FALSE;
03210       PRUint32 count = aNewChild->GetChildCount();
03211       for (PRUint32 index = 0; index < count; ++index) {
03212         nsIContent* childContent = aNewChild->GetChildAt(index);
03213         NS_ASSERTION(childContent, "Something went wrong");
03214         if (childContent->IsContentOfType(nsIContent::eELEMENT)) {
03215           if (sawElement) {
03216             // Can't put two elements into a document
03217             return PR_FALSE;
03218           }
03219           sawElement = PR_TRUE;
03220         }
03221         // If we can put this content at the the right place, we might be ok;
03222         // if not, we bail out.
03223         nsCOMPtr<nsIDOMNode> childNode(do_QueryInterface(childContent));
03224         PRUint16 type;
03225         childNode->GetNodeType(&type);
03226         if (!IsAllowedAsChild(childContent, type, aParent, aDocument,
03227                               aIsReplace, aRefContent)) {
03228           return PR_FALSE;
03229         }
03230       }
03231 
03232       // Everything in the fragment checked out ok, so we can stick it in here
03233       return PR_TRUE;
03234     }
03235   default:
03236     /*
03237      * aNewChild is of invalid type.
03238      */
03239     break;
03240   }
03241 
03242   return PR_FALSE;
03243 }
03244 
03245 class nsFragmentObserver : public nsStubDocumentObserver {
03246 public:
03247   NS_DECL_ISUPPORTS
03248   
03249   nsFragmentObserver(PRUint32 aOldChildCount, nsIContent* aParent,
03250                      nsIDocument* aDocument) :
03251     mOldChildCount(aOldChildCount),
03252     mChildrenBound(0),
03253     mParent(aParent),
03254     mDocument(aDocument)
03255   {
03256     NS_ASSERTION(mParent, "Must have parent!");
03257   }
03258 
03259   virtual void BeginUpdate(nsIDocument* aDocument, nsUpdateType aUpdateType) {
03260     // Make sure to notify on whatever content has been appended thus far
03261     Notify();
03262   }
03263 
03264   virtual void DocumentWillBeDestroyed(nsIDocument *aDocument) {
03265     Disconnect();
03266   }
03267 
03268   void Connect() {
03269     if (mDocument) {
03270       mDocument->AddObserver(this);
03271     }
03272   }
03273 
03274   void Disconnect() {
03275     if (mDocument) {
03276       mDocument->RemoveObserver(this);
03277     }
03278     mDocument = nsnull;
03279   }
03280 
03281   void Finish() {
03282     // Notify on any remaining content
03283     Notify();
03284     Disconnect();
03285   }
03286 
03287   void Notify() {
03288     if (mDocument && mDocument == mParent->GetCurrentDoc()) {
03289       if (mChildrenBound > 0) {
03290         // Some stuff got bound since we notified last time.  Notify on it.
03291         PRUint32 boundCount = mOldChildCount + mChildrenBound;
03292         PRUint32 notifySlot = mOldChildCount;
03293         // Make sure to update mChildrenBound and mOldChildCount so that if
03294         // ContentAppended calls BeginUpdate for some reason (eg XBL) so we
03295         // reenter Notify() we won't double-notify.
03296         mChildrenBound = 0;
03297         mOldChildCount = boundCount;
03298         PRUint32 i;
03299         nsIContent *child;
03300         if (boundCount == mParent->GetChildCount()) {
03301           // All the kids have been bound already.  Just append
03302           mDocument->ContentAppended(mParent, notifySlot);
03303         } else {
03304           // Just notify on the already-bound kids
03305           for (i = notifySlot; i < boundCount; ++i) {
03306             child = mParent->GetChildAt(i);
03307             // Could have no child if script has rearranged the DOM or
03308             // something...
03309             if (child) {
03310               mDocument->ContentInserted(mParent, child, i);
03311             }
03312           }
03313         }
03314         
03315         const PRUint32 eventBits = NS_EVENT_BITS_MUTATION_NODEINSERTED;
03316         if (nsGenericElement::HasMutationListeners(mParent, eventBits)) {
03317           // Walk over the child nodes and collect those we will fire
03318           // notifications for
03319           nsCOMArray<nsIContent> kidsToNotify;
03320           for (i = notifySlot; i < boundCount; ++i) {
03321             kidsToNotify.AppendObject(mParent->GetChildAt(i));
03322           }
03323 
03324           nsCOMPtr<nsIDOMNode> parentNode = do_QueryInterface(mParent);
03325 
03326           PRUint32 length = kidsToNotify.Count();
03327           for (i = 0; i < length; ++i) {
03328             child = kidsToNotify[i];
03329             nsMutationEvent mutation(PR_TRUE, NS_MUTATION_NODEINSERTED, child);
03330             mutation.mRelatedNode = parentNode;
03331             
03332             nsEventStatus status = nsEventStatus_eIgnore;
03333             child->HandleDOMEvent(nsnull, &mutation, nsnull,
03334                                   NS_EVENT_FLAG_INIT, &status);
03335           }
03336         }
03337       }
03338     }
03339   }
03340 
03341   void ChildBound() {
03342     ++mChildrenBound;
03343   }
03344 
03345 private:
03346   PRUint32 mOldChildCount;
03347   PRUint32 mChildrenBound;  // Number of children bound since we last notified
03348   nsCOMPtr<nsIContent> mParent;
03349   nsIDocument* mDocument;
03350 };
03351 
03352 
03353 NS_IMPL_ISUPPORTS1(nsFragmentObserver, nsIDocumentObserver)
03354 
03355 /* static */
03356 nsresult
03357 nsGenericElement::doReplaceOrInsertBefore(PRBool aReplace,
03358                                           nsIDOMNode* aNewChild,
03359                                           nsIDOMNode* aRefChild,
03360                                           nsIContent* aParent,
03361                                           nsIDocument* aDocument,
03362                                           nsAttrAndChildArray& aChildArray,
03363                                           nsIDOMNode** aReturn)
03364 {
03365   NS_PRECONDITION(aParent || aDocument, "Must have document if no parent!");
03366   NS_PRECONDITION(!aParent || aParent->GetCurrentDoc() == aDocument,
03367                   "Incorrect aDocument");
03368 
03369   *aReturn = nsnull;
03370 
03371   if (!aNewChild || (aReplace && !aRefChild)) {
03372     return NS_ERROR_NULL_POINTER;
03373   }
03374 
03375   // Keep a strong reference to the node that we'll return to ensure it
03376   // doesn't go away.
03377   nsCOMPtr<nsIDOMNode> returnVal = aReplace ? aRefChild : aNewChild;
03378 
03379   nsCOMPtr<nsIContent> refContent;
03380   nsresult res = NS_OK;
03381   PRInt32 insPos;
03382 
03383   nsContentOrDocument container(aParent, aDocument);
03384 
03385   // Figure out which index to insert at
03386   if (aRefChild) {
03387     refContent = do_QueryInterface(aRefChild);
03388     insPos = container.IndexOf(refContent);
03389     if (insPos < 0) {
03390       return NS_ERROR_DOM_NOT_FOUND_ERR;
03391     }
03392 
03393     if (aRefChild == aNewChild) {
03394       NS_ADDREF(*aReturn = aNewChild);
03395 
03396       return NS_OK;
03397     }
03398   } else {
03399     insPos = container.GetChildCount();
03400   }
03401 
03402   nsCOMPtr<nsIContent> newContent = do_QueryInterface(aNewChild);
03403   if (!newContent) {
03404     return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
03405   }
03406 
03407   PRUint16 nodeType = 0;
03408   res = aNewChild->GetNodeType(&nodeType);
03409   NS_ENSURE_SUCCESS(res, res);
03410 
03411   // Make sure that the inserted node is allowed as a child of its new parent.
03412   if (!IsAllowedAsChild(newContent, nodeType, aParent, aDocument, aReplace,
03413                         refContent)) {
03414     return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
03415   }
03416 
03417   nsIDocument* old_doc = newContent->GetOwnerDoc();
03418 
03419   // XXXbz The document code and content code have two totally different
03420   // security checks here.  Why?  Because I'm afraid to change such things this
03421   // close to 1.8.  But which should we do here, really?  Or both?  For example
03422   // what should a caller with UniversalBrowserRead/Write/whatever be able to
03423   // do, exactly?  Do we need to be more careful with documents because random
03424   // callers _can_ get access to them?  That might be....
03425   if (old_doc && old_doc != container.GetOwnerDoc()) {
03426     if (aParent) {
03427       if (!nsContentUtils::CanCallerAccess(aNewChild)) {
03428         return NS_ERROR_DOM_SECURITY_ERR;
03429       }
03430     } else {
03431       nsCOMPtr<nsIDOMNode> doc(do_QueryInterface(aDocument));
03432       if (NS_FAILED(nsContentUtils::CheckSameOrigin(doc, aNewChild))) {
03433         return NS_ERROR_DOM_SECURITY_ERR;
03434       }
03435     }
03436   }
03437 
03438   // We want an update batch when we expect several mutations to be performed,
03439   // which is when we're replacing a node, or when we're inserting a fragment.
03440   mozAutoDocUpdate updateBatch(aDocument, UPDATE_CONTENT_MODEL,
03441     aReplace || nodeType == nsIDOMNode::DOCUMENT_FRAGMENT_NODE);
03442 
03443   // If we're replacing
03444   if (aReplace) {
03445     // Getting (and addrefing) the following child here is sort of wasteful
03446     // in the common case, but really, it's not that expensive. Get over it.
03447     refContent = container.GetChildAt(insPos + 1);
03448 
03449     nsMutationGuard guard;
03450 
03451     res = container.RemoveChildAt(insPos, PR_TRUE);
03452     NS_ENSURE_SUCCESS(res, res);
03453 
03454     if (guard.Mutated(1)) {
03455       insPos = refContent ? container.IndexOf(refContent) :
03456                             container.GetChildCount();
03457       if (insPos < 0) {
03458         return NS_ERROR_DOM_NOT_FOUND_ERR;
03459       }
03460 
03461       // Passing PR_FALSE for aIsReplace since we now have removed the node
03462       // to be replaced.
03463       if (!IsAllowedAsChild(newContent, nodeType, aParent, aDocument,
03464                             PR_FALSE, refContent)) {
03465         return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
03466       }
03467     }
03468   }
03469 
03470   /*
03471    * Check if we're inserting a document fragment. If we are, we need
03472    * to remove the children of the document fragment and add them
03473    * individually (i.e. we don't add the actual document fragment).
03474    */
03475   if (nodeType == nsIDOMNode::DOCUMENT_FRAGMENT_NODE) {
03476     PRUint32 count = newContent->GetChildCount();
03477     PRBool do_notify = refContent || !aParent;
03478 
03479     // Copy the children into a separate array to avoid having to deal with
03480     // mutations to the fragment while we're inserting.
03481     nsCOMArray<nsIContent> fragChildren;
03482     PRUint32 i;
03483     for (i = 0; i < count; i++) {
03484       nsIContent* child = newContent->GetChildAt(i);
03485       NS_ASSERTION(child->GetCurrentDoc() == nsnull,
03486                    "How did we get a child with a current doc?");
03487       if (!fragChildren.AppendObject(child)) {
03488         return NS_ERROR_OUT_OF_MEMORY;
03489       }
03490     }
03491 
03492     // Remove the children from the fragment and flag for possible mutations.
03493     PRBool mutated = PR_FALSE;
03494     for (i = count; i > 0;) {
03495       // We don't need to update i if someone mutates the DOM. The only thing
03496       // that'd happen is that the resulting child list might be unexpected,
03497       // but we should never crash since RemoveChildAt is out-of-bounds safe.
03498       nsMutationGuard guard;
03499       newContent->RemoveChildAt(--i, PR_TRUE);
03500       mutated = mutated || guard.Mutated(1);
03501     }
03502 
03503     nsRefPtr<nsFragmentObserver> fragmentObs;
03504     if (count && !do_notify) {
03505       fragmentObs = new nsFragmentObserver(container.GetChildCount(), aParent, aDocument);
03506       NS_ENSURE_TRUE(fragmentObs, NS_ERROR_OUT_OF_MEMORY);
03507       fragmentObs->Connect();
03508     }
03509 
03510     // If do_notify is true, then we don't have to handle the notifications
03511     // ourselves...  Also, if count is 0 there will be no updates.  So we only
03512     // want an update batch to happen if count is nonzero and do_notify is not
03513     // true.
03514     mozAutoDocUpdate updateBatch(aDocument, UPDATE_CONTENT_MODEL,
03515                                  count && !do_notify);
03516     
03517     // Iterate through the fragment's children, and insert them in the new
03518     // parent
03519     for (i = 0; i < count; ++i) {
03520       // Get the n:th child from the array.
03521       nsIContent* childContent = fragChildren[i];
03522 
03523       // If we've had any unexpeted mutations so far we need to recheck that
03524       // the child can still be inserted.
03525       if (mutated) {
03526         // We really only need to update insPos if we *just* got an unexpected
03527         // mutation as opposed to 3 insertions ago. But this is an edgecase so
03528         // no need to over optimize.
03529         insPos = refContent ? container.IndexOf(refContent) :
03530                               container.GetChildCount();
03531         if (insPos < 0) {
03532           // Someone seriously messed up the childlist. We have no idea
03533           // where to insert the remaining children, so just bail.
03534           res = NS_ERROR_DOM_NOT_FOUND_ERR;
03535           break;
03536         }
03537 
03538         nsCOMPtr<nsIDOMNode> tmpNode = do_QueryInterface(childContent);
03539         PRUint16 tmpType = 0;
03540         tmpNode->GetNodeType(&tmpType);
03541 
03542         if (childContent->GetParent() || childContent->IsInDoc() ||
03543             !IsAllowedAsChild(childContent, tmpType, aParent, aDocument, PR_FALSE,
03544                               refContent)) {
03545           res = NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
03546           break;
03547         }
03548       }
03549 
03550       nsMutationGuard guard;
03551 
03552       // XXXbz how come no reparenting here?  That seems odd...
03553       // Insert the child.
03554       res = container.InsertChildAt(childContent, insPos, do_notify,
03555                                     aChildArray);
03556 
03557       if (NS_FAILED(res)) {
03558         break;
03559       }
03560 
03561       if (fragmentObs) {
03562         fragmentObs->ChildBound();
03563       }
03564 
03565       // Check to see if any evil mutation events mucked around with the
03566       // child list.
03567       mutated = mutated || guard.Mutated(1);
03568 
03569       ++insPos;
03570     }
03571 
03572     if (NS_FAILED(res)) {
03573       if (fragmentObs) {
03574         fragmentObs->Disconnect();
03575       }
03576 
03577       // We could try to put the nodes back into the fragment here if we
03578       // really cared.
03579 
03580       return res;
03581     }
03582 
03583     if (fragmentObs) {
03584       NS_ASSERTION(count && !do_notify, "Unexpected state");
03585       fragmentObs->Finish();
03586     }
03587 
03588   }
03589   else {
03590     PRBool newContentIsXUL = newContent->IsContentOfType(eXUL);
03591 
03592     // Remove the element from the old parent if one exists
03593     nsIDocument* oldParentDoc = nsnull;
03594     nsIContent* oldParentCont = newContent->GetParent();
03595     if (!oldParentCont) {
03596       oldParentDoc = newContent->GetCurrentDoc();
03597 
03598       // See bug 53901. Crappy XUL sometimes lies about being in the document
03599       if (oldParentDoc && newContentIsXUL && oldParentDoc->IndexOf(newContent) < 0) {
03600         oldParentDoc = nsnull;
03601       }
03602     }
03603     if (oldParentCont || oldParentDoc) {
03604       nsContentOrDocument oldParent(oldParentCont, oldParentDoc);
03605       PRInt32 removeIndex = oldParent.IndexOf(newContent);
03606 
03607       if (removeIndex < 0) {
03608         // newContent is anonymous.  We can't deal with this, so just bail
03609         return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
03610       }
03611       
03612       NS_ASSERTION(!(oldParent.Equals(container) && removeIndex == insPos),
03613                    "invalid removeIndex");
03614 
03615       nsMutationGuard guard;
03616 
03617       res = oldParent.RemoveChildAt(removeIndex, PR_TRUE);
03618       NS_ENSURE_SUCCESS(res, res);
03619 
03620       // Adjust insert index if the node we ripped out was a sibling
03621       // of the node we're inserting before
03622       if (oldParent.Equals(container) && removeIndex < insPos) {
03623         --insPos;
03624       }
03625 
03626       if (guard.Mutated(1)) {
03627         insPos = refContent ? container.IndexOf(refContent) :
03628                               container.GetChildCount();
03629         if (insPos < 0) {
03630           // Someone seriously messed up the childlist. We have no idea
03631           // where to insert the new child, so just bail.
03632           return NS_ERROR_DOM_NOT_FOUND_ERR;
03633         }
03634 
03635         if (newContent->GetParent() || newContent->IsInDoc() ||
03636             !IsAllowedAsChild(newContent, nodeType, aParent, aDocument, PR_FALSE,
03637                               refContent)) {
03638           return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
03639         }
03640       }
03641     }
03642 
03643     if (!newContentIsXUL) {
03644       nsContentUtils::ReparentContentWrapper(newContent, aParent,
03645                                              container.GetOwnerDoc(),
03646                                              old_doc);
03647     }
03648 
03649     res = container.InsertChildAt(newContent, insPos, PR_TRUE, aChildArray);
03650     NS_ENSURE_SUCCESS(res, res);
03651   }
03652 
03653   returnVal.swap(*aReturn);
03654 
03655   return res;
03656 }
03657 
03658 NS_IMETHODIMP
03659 nsGenericElement::RemoveChild(nsIDOMNode *aOldChild, nsIDOMNode **aReturn)
03660 {
03661   *aReturn = nsnull;
03662 
03663   if (!aOldChild) {
03664     return NS_ERROR_NULL_POINTER;
03665   }
03666 
03667   nsresult res;
03668 
03669   nsCOMPtr<nsIContent> content(do_QueryInterface(aOldChild, &res));
03670 
03671   if (NS_FAILED(res)) {
03672     /*
03673      * If we're asked to remove something that doesn't support nsIContent
03674      * it can not be one of our children, i.e. we return NOT_FOUND_ERR.
03675      */
03676     return NS_ERROR_DOM_NOT_FOUND_ERR;
03677   }
03678 
03679   PRInt32 pos = IndexOf(content);
03680 
03681   if (pos < 0) {
03682     /*
03683      * aOldChild isn't one of our children.
03684      */
03685     return NS_ERROR_DOM_NOT_FOUND_ERR;
03686   }
03687 
03688   res = RemoveChildAt(pos, PR_TRUE);
03689 
03690   *aReturn = aOldChild;
03691   NS_ADDREF(aOldChild);
03692 
03693   return res;
03694 }
03695 
03696 //----------------------------------------------------------------------
03697 
03698 // nsISupports implementation
03699 
03700 NS_INTERFACE_MAP_BEGIN(nsGenericElement)
03701   NS_INTERFACE_MAP_ENTRY(nsIContent)
03702   NS_INTERFACE_MAP_ENTRY(nsIStyledContent)
03703   NS_INTERFACE_MAP_ENTRY(nsIDOMGCParticipant)
03704   NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOM3Node, new nsNode3Tearoff(this))
03705   NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMEventReceiver,
03706                                  nsDOMEventRTTearoff::Create(this))
03707   NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMEventTarget,
03708                                  nsDOMEventRTTearoff::Create(this))
03709   NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOM3EventTarget,
03710                                  nsDOMEventRTTearoff::Create(this))
03711   NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMNSEventTarget,
03712                                  nsDOMEventRTTearoff::Create(this))
03713   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContent)
03714 NS_INTERFACE_MAP_END
03715 
03716 NS_IMPL_ADDREF(nsGenericElement)
03717 NS_IMPL_RELEASE(nsGenericElement)
03718 
03719 nsresult
03720 nsGenericElement::PostQueryInterface(REFNSIID aIID, void** aInstancePtr)
03721 {
03722   nsIDocument *document = GetOwnerDoc();
03723   if (document) {
03724     return document->BindingManager()->GetBindingImplementation(this, aIID,
03725                                                                 aInstancePtr);
03726   }
03727 
03728   return NS_NOINTERFACE;
03729 }
03730 
03731 //----------------------------------------------------------------------
03732 nsresult
03733 nsGenericElement::LeaveLink(nsPresContext* aPresContext)
03734 {
03735   nsILinkHandler *handler = aPresContext->GetLinkHandler();
03736   if (!handler) {
03737     return NS_OK;
03738   }
03739 
03740   return handler->OnLeaveLink();
03741 }
03742 
03743 nsresult
03744 nsGenericElement::TriggerLink(nsPresContext* aPresContext,
03745                               nsLinkVerb aVerb,
03746                               nsIURI* aLinkURI,
03747                               const nsAFlatString& aTargetSpec,
03748                               PRBool aClick,
03749                               PRBool aIsUserTriggered)
03750 {
03751   NS_PRECONDITION(aLinkURI, "No link URI");
03752   nsresult rv = NS_OK;
03753 
03754   nsIDocument* doc = GetOwnerDoc();
03755   nsIURI* originURI = nsnull;
03756   if (doc) {
03757     originURI = doc->GetDocumentURI();
03758   }
03759   NS_ENSURE_TRUE(originURI, NS_ERROR_FAILURE);
03760 
03761   nsILinkHandler *handler = aPresContext->GetLinkHandler();
03762   if (!handler) return NS_OK;
03763 
03764   if (aClick) {
03765     nsresult proceed = NS_OK;
03766     // Check that this page is allowed to load this URI.
03767     nsCOMPtr<nsIScriptSecurityManager> securityManager = 
03768              do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
03769     if (NS_SUCCEEDED(rv)) {
03770       PRUint32 flag = aIsUserTriggered ?
03771                       (PRUint32) nsIScriptSecurityManager::STANDARD :
03772                       (PRUint32) nsIScriptSecurityManager::DISALLOW_FROM_MAIL;
03773       proceed =
03774         securityManager->CheckLoadURI(originURI, aLinkURI, flag);
03775     }
03776 
03777     // Only pass off the click event if the script security manager
03778     // says it's ok.
03779     if (NS_SUCCEEDED(proceed))
03780       handler->OnLinkClick(this, aVerb, aLinkURI, aTargetSpec.get());
03781   } else {
03782     handler->OnOverLink(this, aLinkURI, aTargetSpec.get());
03783   }
03784   return rv;
03785 }
03786 
03787 nsresult
03788 nsGenericElement::AddScriptEventListener(nsIAtom* aAttribute,
03789                                          const nsAString& aValue)
03790 {
03791   nsresult rv = NS_OK;
03792   nsISupports *target = NS_STATIC_CAST(nsIContent *, this);
03793   PRBool defer = PR_TRUE;
03794 
03795   nsCOMPtr<nsIEventListenerManager> manager;
03796 
03797   // Attributes on the body and frameset tags get set on the global object
03798   if (mNodeInfo->Equals(nsHTMLAtoms::body) ||
03799       mNodeInfo->Equals(nsHTMLAtoms::frameset)) {
03800     nsIScriptGlobalObject *sgo;
03801 
03802     // If we have a document, and it has a script global, add the
03803     // event listener on the global. If not, proceed as normal.
03804     // XXXbz should we instead use GetCurrentDoc() here, override
03805     // BindToTree for those classes and munge event listeners there?
03806     nsIDocument *document = GetOwnerDoc();
03807     nsCOMPtr<nsPIDOMWindow> win;
03808     if (document && (sgo = document->GetScriptGlobalObject()) &&
03809         (win = do_QueryInterface(sgo)) && win->IsInnerWindow()) {
03810       nsCOMPtr<nsIDOMEventReceiver> receiver(do_QueryInterface(sgo));
03811       NS_ENSURE_TRUE(receiver, NS_ERROR_FAILURE);
03812 
03813       receiver->GetListenerManager(getter_AddRefs(manager));
03814 
03815       target = sgo;
03816       defer = PR_FALSE;
03817     }
03818   } else {
03819     GetListenerManager(getter_AddRefs(manager));
03820   }
03821 
03822   if (manager) {
03823     nsIDocument *ownerDoc = GetOwnerDoc();
03824 
03825     rv =
03826       manager->AddScriptEventListener(target, aAttribute, aValue, defer,
03827                                       !nsContentUtils::IsChromeDoc(ownerDoc));
03828   }
03829 
03830   return rv;
03831 }
03832 
03833 
03834 //----------------------------------------------------------------------
03835 
03836 const nsAttrName*
03837 nsGenericElement::InternalGetExistingAttrNameFromQName(const nsAString& aStr) const
03838 {
03839   return mAttrsAndChildren.GetExistingAttrNameFromQName(
03840     NS_ConvertUTF16toUTF8(aStr));
03841 }
03842 
03843 nsresult
03844 nsGenericElement::CopyInnerTo(nsGenericElement* aDst, PRBool aDeep)
03845 {
03846   nsresult rv;
03847   PRUint32 i, count = mAttrsAndChildren.AttrCount();
03848   for (i = 0; i < count; ++i) {
03849     const nsAttrName* name = mAttrsAndChildren.GetSafeAttrNameAt(i);
03850     const nsAttrValue* value = mAttrsAndChildren.AttrAt(i);
03851     nsAutoString valStr;
03852     value->ToString(valStr);
03853     rv = aDst->SetAttr(name->NamespaceID(), name->LocalName(),
03854                        name->GetPrefix(), valStr, PR_FALSE);
03855     NS_ENSURE_SUCCESS(rv, rv);
03856   }
03857 
03858   if (!aDeep) {
03859     return NS_OK;
03860   }
03861 
03862   count = mAttrsAndChildren.ChildCount();
03863   for (i = 0; i < count; ++i) {
03864     nsCOMPtr<nsIDOMNode> node =
03865       do_QueryInterface(mAttrsAndChildren.ChildAt(i));
03866     NS_ASSERTION(node, "child doesn't implement nsIDOMNode");
03867 
03868     nsCOMPtr<nsIDOMNode> newNode;
03869     rv = node->CloneNode(PR_TRUE, getter_AddRefs(newNode));
03870     NS_ENSURE_SUCCESS(rv, rv);
03871 
03872     nsCOMPtr<nsIContent> newContent = do_QueryInterface(newNode);
03873     rv = aDst->AppendChildTo(newContent, PR_FALSE);
03874     NS_ENSURE_SUCCESS(rv, rv);
03875   }
03876 
03877   return NS_OK;
03878 }
03879 
03880 static PRBool
03881 NodeHasMutationListeners(nsISupports* aNode)
03882 {
03883   nsCOMPtr<nsIDOMEventReceiver> rec(do_QueryInterface(aNode));
03884   if (rec) {
03885     nsCOMPtr<nsIEventListenerManager> manager;
03886     rec->GetListenerManager(getter_AddRefs(manager));
03887     if (manager) {
03888       PRBool hasMutationListeners = PR_FALSE;
03889       manager->HasMutationListeners(&hasMutationListeners);
03890       if (hasMutationListeners)
03891         return PR_TRUE;
03892     }
03893   }
03894   return PR_FALSE;
03895 }
03896 
03897 // Static helper method
03898 
03899 PRBool
03900 nsGenericElement::HasMutationListeners(nsIContent* aContent, PRUint32 aType)
03901 {
03902   nsIDocument* doc = aContent->GetDocument();
03903   if (!doc)
03904     return PR_FALSE;
03905 
03906   nsIScriptGlobalObject *global = doc->GetScriptGlobalObject();
03907   if (!global)
03908     return PR_FALSE;
03909 
03910   nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(global));
03911   if (!window)
03912     return PR_FALSE;
03913 
03914   if (!window->HasMutationListeners(aType))
03915     return PR_FALSE;
03916 
03917   // We know a mutation listener is registered, but it might not
03918   // be in our chain.  Check quickly to see.
03919 
03920   for (nsIContent* curr = aContent; curr; curr = curr->GetParent())
03921     if (NodeHasMutationListeners(curr))
03922       return PR_TRUE;
03923 
03924   return NodeHasMutationListeners(doc) || NodeHasMutationListeners(window);
03925 }
03926 
03927 nsresult
03928 nsGenericElement::SetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
03929                           nsIAtom* aPrefix, const nsAString& aValue,
03930                           PRBool aNotify)
03931 {
03932   NS_ENSURE_ARG_POINTER(aName);
03933   NS_ASSERTION(aNamespaceID != kNameSpaceID_Unknown,
03934                "Don't call SetAttr with unknown namespace");
03935 
03936   if (kNameSpaceID_XLink == aNamespaceID && nsHTMLAtoms::href == aName) {
03937     // XLink URI(s) might be changing. Drop the link from the map. If it
03938     // is still style relevant it will be re-added by
03939     // nsStyleUtil::IsSimpleXlink. Make sure to keep the style system
03940     // consistent so this remains true! In particular if the style system
03941     // were to get smarter and not restyling an XLink element if the href
03942     // doesn't change in a "significant" way, we'd need to do the same
03943     // significance check here.
03944     nsIDocument* doc = GetCurrentDoc();
03945     if (doc) {
03946       doc->ForgetLink(this);
03947     }
03948   }
03949 
03950   PRBool modification = PR_FALSE;
03951   nsAutoString oldValue;
03952 
03953   PRInt32 index = mAttrsAndChildren.IndexOfAttr(aName, aNamespaceID);
03954   if (index >= 0) {
03955     modification = PR_TRUE;
03956     
03957     // Get old value and see if it's the same as new one
03958     const nsAttrName* attrName = mAttrsAndChildren.GetSafeAttrNameAt(index);
03959     const nsAttrValue* val = mAttrsAndChildren.AttrAt(index);
03960     NS_ASSERTION(attrName && val, "attribute is supposed to be there");
03961     val->ToString(oldValue);
03962     if (oldValue.Equals(aValue) &&
03963         aPrefix == attrName->GetPrefix()) {
03964       // Nothing to do
03965 
03966       return NS_OK;
03967     }
03968   }
03969 
03970   // Begin the update _before_ changing the attr value
03971   nsIDocument *document = GetCurrentDoc();
03972   mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
03973   
03974   if (aNotify && document) {
03975     document->AttributeWillChange(this, aNamespaceID, aName);
03976   }
03977 
03978   nsresult rv;
03979   if (aNamespaceID == kNameSpaceID_None) {
03980     if (aName == GetIDAttributeName() && !aValue.IsEmpty()) {
03981       // Store id as atom. id="" means that the element has no id, not that it has
03982       // an emptystring as the id.
03983       nsAttrValue attrValue;
03984       attrValue.ParseAtom(aValue);
03985       rv = mAttrsAndChildren.SetAndTakeAttr(aName, attrValue);
03986       NS_ENSURE_SUCCESS(rv, rv);
03987     }
03988     else {
03989       rv = mAttrsAndChildren.SetAttr(aName, aValue);
03990       NS_ENSURE_SUCCESS(rv, rv);
03991     }
03992   }
03993   else {
03994     nsCOMPtr<nsINodeInfo> ni;
03995     rv = mNodeInfo->NodeInfoManager()->GetNodeInfo(aName, aPrefix,
03996                                                    aNamespaceID,
03997                                                    getter_AddRefs(ni));
03998     NS_ENSURE_SUCCESS(rv, rv);
03999 
04000     nsAttrValue attrVal(aValue);
04001     rv = mAttrsAndChildren.SetAndTakeAttr(ni, attrVal);
04002     NS_ENSURE_SUCCESS(rv, rv);
04003   }
04004 
04005   if (document) {
04006     nsRefPtr<nsXBLBinding> binding = document->BindingManager()->GetBinding(this);
04007     if (binding)
04008       binding->AttributeChanged(aName, aNamespaceID, PR_FALSE, aNotify);
04009 
04010     if (aNotify) {
04011       PRInt32 modHint = modification ? PRInt32(nsIDOMMutationEvent::MODIFICATION)
04012                                      : PRInt32(nsIDOMMutationEvent::ADDITION);
04013       document->AttributeChanged(this, aNamespaceID, aName, modHint);
04014 
04015       if (HasMutationListeners(this, NS_EVENT_BITS_MUTATION_ATTRMODIFIED)) {
04016         nsCOMPtr<nsIDOMEventTarget> node =
04017           do_QueryInterface(NS_STATIC_CAST(nsIContent *, this));
04018         nsMutationEvent mutation(PR_TRUE, NS_MUTATION_ATTRMODIFIED, node);
04019 
04020         nsAutoString attrName;
04021         aName->ToString(attrName);
04022         nsCOMPtr<nsIDOMAttr> attrNode;
04023         GetAttributeNode(attrName, getter_AddRefs(attrNode));
04024         mutation.mRelatedNode = attrNode;
04025 
04026         mutation.mAttrName = aName;
04027         if (!oldValue.IsEmpty()) {
04028           mutation.mPrevAttrValue = do_GetAtom(oldValue);
04029         }
04030 
04031         if (!aValue.IsEmpty()) {
04032           mutation.mNewAttrValue = do_GetAtom(aValue);
04033         }
04034 
04035         if (modification) {
04036           mutation.mAttrChange = nsIDOMMutationEvent::MODIFICATION;
04037         } else {
04038           mutation.mAttrChange = nsIDOMMutationEvent::ADDITION;
04039         }
04040 
04041         nsEventStatus status = nsEventStatus_eIgnore;
04042         HandleDOMEvent(nsnull, &mutation, nsnull,
04043                        NS_EVENT_FLAG_INIT, &status);
04044       }
04045     }
04046   }
04047 
04048   if (aNamespaceID == kNameSpaceID_XMLEvents && aName == nsHTMLAtoms::_event && 
04049       mNodeInfo->GetDocument()) {
04050     mNodeInfo->GetDocument()->AddXMLEventsContent(this);
04051   }
04052 
04053   return NS_OK;
04054 }
04055 
04056 nsresult
04057 nsGenericElement::GetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
04058                           nsAString& aResult) const
04059 {
04060   NS_ASSERTION(nsnull != aName, "must have attribute name");
04061   NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown,
04062                "must have a real namespace ID!");
04063 
04064   const nsAttrValue* val = mAttrsAndChildren.GetAttr(aName, aNameSpaceID);
04065   if (!val) {
04066     // Since we are returning a success code we'd better do
04067     // something about the out parameters (someone may have
04068     // given us a non-empty string).
04069     aResult.Truncate();
04070     
04071     return NS_CONTENT_ATTR_NOT_THERE;
04072   }
04073 
04074   val->ToString(aResult);
04075 
04076   return aResult.IsEmpty() ? NS_CONTENT_ATTR_NO_VALUE :
04077                              NS_CONTENT_ATTR_HAS_VALUE;
04078 }
04079 
04080 PRBool
04081 nsGenericElement::HasAttr(PRInt32 aNameSpaceID, nsIAtom* aName) const
04082 {
04083   NS_ASSERTION(nsnull != aName, "must have attribute name");
04084   NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown,
04085                "must have a real namespace ID!");
04086 
04087   return mAttrsAndChildren.IndexOfAttr(aName, aNameSpaceID) >= 0;
04088 }
04089 
04090 nsresult
04091 nsGenericElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
04092                             PRBool aNotify)
04093 {
04094   NS_ASSERTION(nsnull != aName, "must have attribute name");
04095 
04096   PRInt32 index = mAttrsAndChildren.IndexOfAttr(aName, aNameSpaceID);
04097   if (index < 0) {
04098     return NS_OK;
04099   }
04100 
04101   nsIDocument *document = GetCurrentDoc();    
04102   mozAutoDocUpdate updateBatch(document, UPDATE_CONTENT_MODEL, aNotify);
04103 
04104   //  we do not need to look for mutation listeners if
04105   //  aNotify is false, because there is no use of that knowledge then
04106   //  (mutation events won't be fired).
04107   PRBool hasMutationListeners = aNotify && document &&
04108     HasMutationListeners(this, NS_EVENT_BITS_MUTATION_ATTRMODIFIED);
04109   // Grab the attr node if needed before we remove it from the attr map
04110   nsCOMPtr<nsIDOMAttr> attrNode;
04111   
04112   if (document) {
04113     if (kNameSpaceID_XLink == aNameSpaceID && nsHTMLAtoms::href == aName) {
04114       // XLink URI might be changing.
04115       document->ForgetLink(this);
04116     }
04117 
04118     if (aNotify) {
04119       document->AttributeWillChange(this, aNameSpaceID, aName);
04120     
04121       if (hasMutationListeners) {
04122         nsAutoString attrName;
04123         aName->ToString(attrName);
04124         GetAttributeNode(attrName, getter_AddRefs(attrNode));
04125       }
04126     }
04127   }
04128 
04129   // Clear binding to nsIDOMNamedNodeMap
04130   nsDOMSlots *slots = GetExistingDOMSlots();
04131   if (slots && slots->mAttributeMap) {
04132     slots->mAttributeMap->DropAttribute(aNameSpaceID, aName);
04133   }
04134 
04135   nsAttrValue oldValue;
04136   nsresult rv = mAttrsAndChildren.RemoveAttrAt(index, oldValue);
04137   NS_ENSURE_SUCCESS(rv, rv);
04138 
04139   if (document) {
04140     nsRefPtr<nsXBLBinding> binding = document->BindingManager()->GetBinding(this);
04141     if (binding)
04142       binding->AttributeChanged(aName, aNameSpaceID, PR_TRUE, aNotify);
04143 
04144     if (aNotify) {
04145       document->AttributeChanged(this, aNameSpaceID, aName,
04146                                  nsIDOMMutationEvent::REMOVAL);
04147 
04148       if (hasMutationListeners) {
04149         nsCOMPtr<nsIDOMEventTarget> node =
04150           do_QueryInterface(NS_STATIC_CAST(nsIContent *, this));
04151         nsMutationEvent mutation(PR_TRUE, NS_MUTATION_ATTRMODIFIED, node);
04152 
04153         mutation.mRelatedNode = attrNode;
04154         mutation.mAttrName = aName;
04155 
04156         nsAutoString value;
04157         oldValue.ToString(value);
04158         if (!value.IsEmpty())
04159           mutation.mPrevAttrValue = do_GetAtom(value);
04160         mutation.mAttrChange = nsIDOMMutationEvent::REMOVAL;
04161 
04162         nsEventStatus status = nsEventStatus_eIgnore;
04163         HandleDOMEvent(nsnull, &mutation, nsnull,
04164                        NS_EVENT_FLAG_INIT, &status);
04165       }
04166     }
04167   }
04168 
04169   return NS_OK;
04170 }
04171 
04172 nsresult
04173 nsGenericElement::GetAttrNameAt(PRUint32 aIndex, PRInt32* aNameSpaceID,
04174                                 nsIAtom** aName, nsIAtom** aPrefix) const
04175 {
04176   const nsAttrName* name = mAttrsAndChildren.GetSafeAttrNameAt(aIndex);
04177   if (name) {
04178     *aNameSpaceID = name->NamespaceID();
04179     NS_ADDREF(*aName = name->LocalName());
04180     NS_IF_ADDREF(*aPrefix = name->GetPrefix());
04181 
04182     return NS_OK;
04183   }
04184 
04185   *aNameSpaceID = kNameSpaceID_None;
04186   *aName = nsnull;
04187   *aPrefix = nsnull;
04188 
04189   return NS_ERROR_ILLEGAL_VALUE;
04190 }
04191 
04192 PRUint32
04193 nsGenericElement::GetAttrCount() const
04194 {
04195   return mAttrsAndChildren.AttrCount();
04196 }
04197 
04198 #ifdef DEBUG
04199 void
04200 nsGenericElement::List(FILE* out, PRInt32 aIndent) const
04201 {
04202   NS_PRECONDITION(IsInDoc(), "bad content");
04203 
04204   PRInt32 index;
04205   for (index = aIndent; --index >= 0; ) fputs("  ", out);
04206 
04207   nsAutoString buf;
04208   mNodeInfo->GetQualifiedName(buf);
04209   fputs(NS_LossyConvertUCS2toASCII(buf).get(), out);
04210 
04211   fprintf(out, "@%p", (void *)this);
04212 
04213   PRUint32 attrcount = mAttrsAndChildren.AttrCount();
04214   for (index = 0; index < attrcount; index++) {
04215     nsAutoString buffer;
04216 
04217     // name
04218     mAttrsAndChildren.GetSafeAttrNameAt(index)->GetQualifiedName(buffer);
04219 
04220     // value
04221     buffer.AppendLiteral("=");
04222     nsAutoString value;
04223     mAttrsAndChildren.AttrAt(index)->ToString(value);
04224     buffer.Append(value);
04225 
04226     fputs(" ", out);
04227     fputs(NS_LossyConvertUCS2toASCII(buffer).get(), out);
04228   }
04229 
04230   fprintf(out, " refcount=%d<", mRefCnt.get());
04231 
04232   fputs("\n", out);
04233   PRUint32 kids = GetChildCount();
04234 
04235   for (index = 0; index < kids; index++) {
04236     nsIContent *kid = GetChildAt(index);
04237     kid->List(out, aIndent + 1);
04238   }
04239   for (index = aIndent; --index >= 0; ) fputs("  ", out);
04240 
04241   fputs(">\n", out);
04242 
04243   nsIDocument *document = GetOwnerDoc();
04244   if (document) {
04245     nsIBindingManager* bindingManager = document->BindingManager();
04246     nsCOMPtr<nsIDOMNodeList> anonymousChildren;
04247     bindingManager->GetAnonymousNodesFor(NS_CONST_CAST(nsGenericElement*, this),
04248                                          getter_AddRefs(anonymousChildren));
04249 
04250     if (anonymousChildren) {
04251       PRUint32 length;
04252       anonymousChildren->GetLength(&length);
04253       if (length) {
04254         for (index = aIndent; --index >= 0; ) fputs("  ", out);
04255         fputs("anonymous-children<\n", out);
04256 
04257         for (PRUint32 i = 0; i < length; ++i) {
04258           nsCOMPtr<nsIDOMNode> node;
04259           anonymousChildren->Item(i, getter_AddRefs(node));
04260           nsCOMPtr<nsIContent> child = do_QueryInterface(node);
04261           child->List(out, aIndent + 1);
04262         }
04263 
04264         for (index = aIndent; --index >= 0; ) fputs("  ", out);
04265         fputs(">\n", out);
04266       }
04267     }
04268 
04269     PRBool hasContentList;
04270     bindingManager->HasContentListFor(NS_CONST_CAST(nsGenericElement*, this),
04271                                       &hasContentList);
04272 
04273     if (hasContentList) {
04274       nsCOMPtr<nsIDOMNodeList> contentList;
04275       bindingManager->GetContentListFor(NS_CONST_CAST(nsGenericElement*, this),
04276                                         getter_AddRefs(contentList));
04277 
04278       NS_ASSERTION(contentList != nsnull, "oops, binding manager lied");
04279 
04280       PRUint32 length;
04281       contentList->GetLength(&length);
04282       if (length) {
04283         for (index = aIndent; --index >= 0; ) fputs("  ", out);
04284         fputs("content-list<\n", out);
04285 
04286         for (PRUint32 i = 0; i < length; ++i) {
04287           nsCOMPtr<nsIDOMNode> node;
04288           contentList->Item(i, getter_AddRefs(node));
04289           nsCOMPtr<nsIContent> child = do_QueryInterface(node);
04290           child->List(out, aIndent + 1);
04291         }
04292 
04293         for (index = aIndent; --index >= 0; ) fputs("  ", out);
04294         fputs(">\n", out);
04295       }
04296     }
04297   }
04298 }
04299 
04300 void
04301 nsGenericElement::DumpContent(FILE* out, PRInt32 aIndent,
04302                               PRBool aDumpAll) const
04303 {
04304 }
04305 #endif
04306 
04307 PRUint32
04308 nsGenericElement::GetChildCount() const
04309 {
04310   return mAttrsAndChildren.ChildCount();
04311 }
04312 
04313 nsIContent *
04314 nsGenericElement::GetChildAt(PRUint32 aIndex) const
04315 {
04316   return mAttrsAndChildren.GetSafeChildAt(aIndex);
04317 }
04318 
04319 PRInt32
04320 nsGenericElement::IndexOf(nsIContent* aPossibleChild) const
04321 {
04322   NS_PRECONDITION(nsnull != aPossibleChild, "null ptr");
04323 
04324   return mAttrsAndChildren.IndexOfChild(aPossibleChild);
04325 }
04326 
04327 void
04328 nsGenericElement::GetContentsAsText(nsAString& aText)
04329 {
04330   aText.Truncate();
04331   PRInt32 children = GetChildCount();
04332 
04333   nsCOMPtr<nsITextContent> tc;
04334 
04335   PRInt32 i;
04336   for (i = 0; i < children; ++i) {
04337     nsIContent *child = GetChildAt(i);
04338 
04339     if (child->IsContentOfType(eTEXT)) {
04340       tc = do_QueryInterface(child);
04341 
04342       tc->AppendTextTo(aText);
04343     }
04344   }
04345 }
04346 
04347 void*
04348 nsGenericElement::GetProperty(nsIAtom  *aPropertyName, nsresult *aStatus) const
04349 {
04350   nsIDocument *doc = GetOwnerDoc();
04351   if (!doc)
04352     return nsnull;
04353 
04354   return doc->PropertyTable()->GetProperty(this, aPropertyName, aStatus);
04355 }
04356 
04357 nsresult
04358 nsGenericElement::SetProperty(nsIAtom            *aPropertyName,
04359                               void               *aValue,
04360                               NSPropertyDtorFunc  aDtor)
04361 {
04362   nsIDocument *doc = GetOwnerDoc();
04363   if (!doc)
04364     return NS_ERROR_FAILURE;
04365 
04366   nsresult rv = doc->PropertyTable()->SetProperty(this, aPropertyName,
04367                                                   aValue, aDtor, nsnull);
04368   if (NS_SUCCEEDED(rv))
04369     SetFlags(GENERIC_ELEMENT_HAS_PROPERTIES);
04370 
04371   return rv;
04372 }
04373 
04374 nsresult
04375 nsGenericElement::DeleteProperty(nsIAtom *aPropertyName)
04376 {
04377   nsIDocument *doc = GetOwnerDoc();
04378   if (!doc)
04379     return nsnull;
04380 
04381   return doc->PropertyTable()->DeleteProperty(this, aPropertyName);
04382 }
04383 
04384 void*
04385 nsGenericElement::UnsetProperty(nsIAtom  *aPropertyName, nsresult *aStatus)
04386 {
04387   nsIDocument *doc = GetOwnerDoc();
04388   if (!doc)
04389     return nsnull;
04390 
04391   return doc->PropertyTable()->UnsetProperty(this, aPropertyName, aStatus);
04392 }