Back to index

lightning-sunbird  0.9+nobinonly
nsContentUtils.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  *
00004  * ***** BEGIN LICENSE BLOCK *****
00005  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00006  *
00007  * The contents of this file are subject to the Mozilla Public License Version
00008  * 1.1 (the "License"); you may not use this file except in compliance with
00009  * the License. You may obtain a copy of the License at
00010  * http://www.mozilla.org/MPL/
00011  *
00012  * Software distributed under the License is distributed on an "AS IS" basis,
00013  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00014  * for the specific language governing rights and limitations under the
00015  * License.
00016  *
00017  * The Original Code is Mozilla Communicator client code, released
00018  * March 31, 1998.
00019  *
00020  * The Initial Developer of the Original Code is
00021  * Netscape Communications Corporation.
00022  * Portions created by the Initial Developer are Copyright (C) 1998
00023  * the Initial Developer. All Rights Reserved.
00024  *
00025  * Contributor(s):
00026  *   Johnny Stenback <jst@netscape.com>
00027  *   Christopher A. Aillon <christopher@aillon.com>
00028  *
00029  * Alternatively, the contents of this file may be used under the terms of
00030  * either of the GNU General Public License Version 2 or later (the "GPL"),
00031  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00032  * in which case the provisions of the GPL or the LGPL are applicable instead
00033  * of those above. If you wish to allow use of your version of this file only
00034  * under the terms of either the GPL or the LGPL, and not to allow others to
00035  * use your version of this file under the terms of the MPL, indicate your
00036  * decision by deleting the provisions above and replace them with the notice
00037  * and other provisions required by the GPL or the LGPL. If you do not delete
00038  * the provisions above, a recipient may use your version of this file under
00039  * the terms of any one of the MPL, the GPL or the LGPL.
00040  *
00041  * ***** END LICENSE BLOCK ***** */
00042 
00043 /* A namespace class for static layout utilities. */
00044 
00045 #include "nsJSUtils.h"
00046 #include "nsCOMPtr.h"
00047 #include "nsAString.h"
00048 #include "nsPrintfCString.h"
00049 #include "nsUnicharUtils.h"
00050 #include "nsIPrefService.h"
00051 #include "nsIPrefBranch.h"
00052 #include "nsIPrefLocalizedString.h"
00053 #include "nsServiceManagerUtils.h"
00054 #include "nsIScriptGlobalObject.h"
00055 #include "nsIScriptContext.h"
00056 #include "nsIDOMScriptObjectFactory.h"
00057 #include "nsDOMCID.h"
00058 #include "nsContentUtils.h"
00059 #include "nsIXPConnect.h"
00060 #include "nsIContent.h"
00061 #include "nsIDocument.h"
00062 #include "nsINodeInfo.h"
00063 #include "nsReadableUtils.h"
00064 #include "nsIDOMDocument.h"
00065 #include "nsIDOMNodeList.h"
00066 #include "nsIDOMNode.h"
00067 #include "nsIDOM3Node.h"
00068 #include "nsIIOService.h"
00069 #include "nsIURI.h"
00070 #include "nsNetCID.h"
00071 #include "nsNetUtil.h"
00072 #include "nsIScriptSecurityManager.h"
00073 #include "nsDOMError.h"
00074 #include "nsPIDOMWindow.h"
00075 #include "nsIJSContextStack.h"
00076 #include "nsIDocShell.h"
00077 #include "nsIDocShellTreeItem.h"
00078 #include "nsParserCIID.h"
00079 #include "nsIParserService.h"
00080 #include "nsIServiceManager.h"
00081 #include "nsIAttribute.h"
00082 #include "nsContentList.h"
00083 #include "nsIHTMLDocument.h"
00084 #include "nsIDOMHTMLDocument.h"
00085 #include "nsIDOMHTMLCollection.h"
00086 #include "nsIDOMHTMLFormElement.h"
00087 #include "nsIForm.h"
00088 #include "nsIFormControl.h"
00089 #include "nsHTMLAtoms.h"
00090 #include "nsHTMLParts.h"
00091 #include "nsISupportsPrimitives.h"
00092 #include "nsLayoutAtoms.h"
00093 #include "imgIDecoderObserver.h"
00094 #include "imgIRequest.h"
00095 #include "imgIContainer.h"
00096 #include "imgILoader.h"
00097 #include "nsIImage.h"
00098 #include "gfxIImageFrame.h"
00099 #include "nsIImageLoadingContent.h"
00100 #include "nsIInterfaceRequestor.h"
00101 #include "nsIInterfaceRequestorUtils.h"
00102 #include "nsILink.h"
00103 #include "nsILoadGroup.h"
00104 #include "nsContentPolicyUtils.h"
00105 #include "nsDOMString.h"
00106 #include "nsGenericElement.h"
00107 #include "nsNodeInfoManager.h"
00108 #include "nsCRT.h"
00109 #ifdef MOZ_XTF
00110 #include "nsIXTFService.h"
00111 static NS_DEFINE_CID(kXTFServiceCID, NS_XTFSERVICE_CID);
00112 #endif
00113 #include "nsIMIMEService.h"
00114 #include "jsdbgapi.h"
00115 #include "nsIJSRuntimeService.h"
00116 #include "nsIFragmentContentSink.h"
00117 #include "nsIScriptObjectPrincipal.h"
00118 
00119 // for ReportToConsole
00120 #include "nsIStringBundle.h"
00121 #include "nsIScriptError.h"
00122 #include "nsIConsoleService.h"
00123 
00124 static const char kJSStackContractID[] = "@mozilla.org/js/xpc/ContextStack;1";
00125 static NS_DEFINE_IID(kParserServiceCID, NS_PARSERSERVICE_CID);
00126 
00127 nsIDOMScriptObjectFactory *nsContentUtils::sDOMScriptObjectFactory = nsnull;
00128 nsIXPConnect *nsContentUtils::sXPConnect = nsnull;
00129 nsIScriptSecurityManager *nsContentUtils::sSecurityManager = nsnull;
00130 nsIThreadJSContextStack *nsContentUtils::sThreadJSContextStack = nsnull;
00131 nsIParserService *nsContentUtils::sParserService = nsnull;
00132 nsINameSpaceManager *nsContentUtils::sNameSpaceManager = nsnull;
00133 nsIIOService *nsContentUtils::sIOService = nsnull;
00134 #ifdef MOZ_XTF
00135 nsIXTFService *nsContentUtils::sXTFService = nsnull;
00136 #endif
00137 nsIPrefBranch *nsContentUtils::sPrefBranch = nsnull;
00138 nsIPref *nsContentUtils::sPref = nsnull;
00139 imgILoader *nsContentUtils::sImgLoader = nsnull;
00140 nsIConsoleService *nsContentUtils::sConsoleService;
00141 nsIStringBundleService *nsContentUtils::sStringBundleService;
00142 nsIStringBundle *nsContentUtils::sStringBundles[PropertiesFile_COUNT];
00143 nsVoidArray *nsContentUtils::sPtrsToPtrsToRelease;
00144 nsIJSRuntimeService *nsContentUtils::sJSRuntimeService;
00145 JSRuntime *nsContentUtils::sScriptRuntime;
00146 PRInt32 nsContentUtils::sScriptRootCount = 0;
00147 
00148 
00149 PRBool nsContentUtils::sInitialized = PR_FALSE;
00150 
00151 // static
00152 nsresult
00153 nsContentUtils::Init()
00154 {
00155   if (sInitialized) {
00156     NS_WARNING("Init() called twice");
00157 
00158     return NS_OK;
00159   }
00160 
00161   nsresult rv = CallGetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID,
00162                                &sSecurityManager);
00163   NS_ENSURE_SUCCESS(rv, rv);
00164 
00165   // It's ok to not have a pref service.
00166   CallGetService(NS_PREFSERVICE_CONTRACTID, &sPrefBranch);
00167 
00168   // It's ok to not have prefs too.
00169   CallGetService(NS_PREF_CONTRACTID, &sPref);
00170 
00171   rv = NS_GetNameSpaceManager(&sNameSpaceManager);
00172   NS_ENSURE_SUCCESS(rv, rv);
00173 
00174   rv = nsGenericElement::InitHashes();
00175   NS_ENSURE_SUCCESS(rv, rv);
00176 
00177   rv = CallGetService(nsIXPConnect::GetCID(), &sXPConnect);
00178   NS_ENSURE_SUCCESS(rv, rv);
00179 
00180   rv = CallGetService(kJSStackContractID, &sThreadJSContextStack);
00181   if (NS_FAILED(rv) && sXPConnect) {
00182     // However, if we can't get a context stack after getting
00183     // an nsIXPConnect, things are broken, so let's fail here.
00184 
00185     return rv;
00186   }
00187 
00188   rv = CallGetService(NS_IOSERVICE_CONTRACTID, &sIOService);
00189   if (NS_FAILED(rv)) {
00190     // This makes life easier, but we can live without it.
00191 
00192     sIOService = nsnull;
00193   }
00194 
00195   // Ignore failure and just don't load images
00196   rv = CallGetService("@mozilla.org/image/loader;1", &sImgLoader);
00197   if (NS_FAILED(rv)) {
00198     // no image loading for us.  Oh, well.
00199     sImgLoader = nsnull;
00200   }
00201 
00202   sPtrsToPtrsToRelease = new nsVoidArray();
00203   if (!sPtrsToPtrsToRelease) {
00204     return NS_ERROR_OUT_OF_MEMORY;
00205   }
00206 
00207   sInitialized = PR_TRUE;
00208 
00209   return NS_OK;
00210 }
00211 
00216 /* static */
00217 nsIParserService*
00218 nsContentUtils::GetParserServiceWeakRef()
00219 {
00220   // XXX: This isn't accessed from several threads, is it?
00221   if (!sParserService) {
00222     // Lock, recheck sCachedParserService and aquire if this should be
00223     // safe for multiple threads.
00224     nsresult rv = CallGetService(kParserServiceCID, &sParserService);
00225     if (NS_FAILED(rv)) {
00226       sParserService = nsnull;
00227     }
00228   }
00229 
00230   return sParserService;
00231 }
00232 
00233 #ifdef MOZ_XTF
00234 nsIXTFService*
00235 nsContentUtils::GetXTFServiceWeakRef()
00236 {
00237   if (!sXTFService) {
00238     nsresult rv = CallGetService(kXTFServiceCID, &sXTFService);
00239     if (NS_FAILED(rv)) {
00240       sXTFService = nsnull;
00241     }
00242   }
00243 
00244   return sXTFService;
00245 }
00246 #endif
00247 
00248 template <class OutputIterator>
00249 struct NormalizeNewlinesCharTraits {
00250   public:
00251     typedef typename OutputIterator::value_type value_type;
00252 
00253   public:
00254     NormalizeNewlinesCharTraits(OutputIterator& aIterator) : mIterator(aIterator) { }
00255     void writechar(typename OutputIterator::value_type aChar) {
00256       *mIterator++ = aChar;
00257     }
00258 
00259   private:
00260     OutputIterator mIterator;
00261 };
00262 
00263 #ifdef HAVE_CPP_PARTIAL_SPECIALIZATION
00264 
00265 template <class CharT>
00266 struct NormalizeNewlinesCharTraits<CharT*> {
00267   public:
00268     typedef CharT value_type;
00269 
00270   public:
00271     NormalizeNewlinesCharTraits(CharT* aCharPtr) : mCharPtr(aCharPtr) { }
00272     void writechar(CharT aChar) {
00273       *mCharPtr++ = aChar;
00274     }
00275 
00276   private:
00277     CharT* mCharPtr;
00278 };
00279 
00280 #else
00281 
00282 NS_SPECIALIZE_TEMPLATE
00283 struct NormalizeNewlinesCharTraits<char*> {
00284   public:
00285     typedef char value_type;
00286 
00287   public:
00288     NormalizeNewlinesCharTraits(char* aCharPtr) : mCharPtr(aCharPtr) { }
00289     void writechar(char aChar) {
00290       *mCharPtr++ = aChar;
00291     }
00292 
00293   private:
00294     char* mCharPtr;
00295 };
00296 
00297 NS_SPECIALIZE_TEMPLATE
00298 struct NormalizeNewlinesCharTraits<PRUnichar*> {
00299   public:
00300     typedef PRUnichar value_type;
00301 
00302   public:
00303     NormalizeNewlinesCharTraits(PRUnichar* aCharPtr) : mCharPtr(aCharPtr) { }
00304     void writechar(PRUnichar aChar) {
00305       *mCharPtr++ = aChar;
00306     }
00307 
00308   private:
00309     PRUnichar* mCharPtr;
00310 };
00311 
00312 #endif
00313 
00314 template <class OutputIterator>
00315 class CopyNormalizeNewlines
00316 {
00317   public:
00318     typedef typename OutputIterator::value_type value_type;
00319 
00320   public:
00321     CopyNormalizeNewlines(OutputIterator* aDestination,
00322                           PRBool aLastCharCR=PR_FALSE) :
00323       mLastCharCR(aLastCharCR),
00324       mDestination(aDestination),
00325       mWritten(0)
00326     { }
00327 
00328     PRUint32 GetCharsWritten() {
00329       return mWritten;
00330     }
00331 
00332     PRBool IsLastCharCR() {
00333       return mLastCharCR;
00334     }
00335 
00336     PRUint32 write(const typename OutputIterator::value_type* aSource, PRUint32 aSourceLength) {
00337 
00338       const typename OutputIterator::value_type* done_writing = aSource + aSourceLength;
00339 
00340       // If the last source buffer ended with a CR...
00341       if (mLastCharCR) {
00342         // ..and if the next one is a LF, then skip it since
00343         // we've already written out a newline
00344         if (aSourceLength && (*aSource == value_type('\n'))) {
00345           ++aSource;
00346         }
00347         mLastCharCR = PR_FALSE;
00348       }
00349 
00350       PRUint32 num_written = 0;
00351       while ( aSource < done_writing ) {
00352         if (*aSource == value_type('\r')) {
00353           mDestination->writechar('\n');
00354           ++aSource;
00355           // If we've reached the end of the buffer, record
00356           // that we wrote out a CR
00357           if (aSource == done_writing) {
00358             mLastCharCR = PR_TRUE;
00359           }
00360           // If the next character is a LF, skip it
00361           else if (*aSource == value_type('\n')) {
00362             ++aSource;
00363           }
00364         }
00365         else {
00366           mDestination->writechar(*aSource++);
00367         }
00368         ++num_written;
00369       }
00370 
00371       mWritten += num_written;
00372       return aSourceLength;
00373     }
00374 
00375   private:
00376     PRBool mLastCharCR;
00377     OutputIterator* mDestination;
00378     PRUint32 mWritten;
00379 };
00380 
00381 // static
00382 PRUint32
00383 nsContentUtils::CopyNewlineNormalizedUnicodeTo(const nsAString& aSource,
00384                                                PRUint32 aSrcOffset,
00385                                                PRUnichar* aDest,
00386                                                PRUint32 aLength,
00387                                                PRBool& aLastCharCR)
00388 {
00389   typedef NormalizeNewlinesCharTraits<PRUnichar*> sink_traits;
00390 
00391   sink_traits dest_traits(aDest);
00392   CopyNormalizeNewlines<sink_traits> normalizer(&dest_traits,aLastCharCR);
00393   nsReadingIterator<PRUnichar> fromBegin, fromEnd;
00394   copy_string(aSource.BeginReading(fromBegin).advance( PRInt32(aSrcOffset) ),
00395               aSource.BeginReading(fromEnd).advance( PRInt32(aSrcOffset+aLength) ),
00396               normalizer);
00397   aLastCharCR = normalizer.IsLastCharCR();
00398   return normalizer.GetCharsWritten();
00399 }
00400 
00401 // static
00402 PRUint32
00403 nsContentUtils::CopyNewlineNormalizedUnicodeTo(nsReadingIterator<PRUnichar>& aSrcStart, const nsReadingIterator<PRUnichar>& aSrcEnd, nsAString& aDest)
00404 {
00405   typedef nsWritingIterator<PRUnichar> WritingIterator;
00406   typedef NormalizeNewlinesCharTraits<WritingIterator> sink_traits;
00407 
00408   WritingIterator iter;
00409   aDest.BeginWriting(iter);
00410   sink_traits dest_traits(iter);
00411   CopyNormalizeNewlines<sink_traits> normalizer(&dest_traits);
00412   copy_string(aSrcStart, aSrcEnd, normalizer);
00413   return normalizer.GetCharsWritten();
00414 }
00415 
00416 // static
00417 void
00418 nsContentUtils::Shutdown()
00419 {
00420   sInitialized = PR_FALSE;
00421 
00422   NS_HTMLParanoidFragmentSinkShutdown();
00423   NS_XHTMLParanoidFragmentSinkShutdown();
00424 
00425   PRInt32 i;
00426   for (i = 0; i < PRInt32(PropertiesFile_COUNT); ++i)
00427     NS_IF_RELEASE(sStringBundles[i]);
00428   NS_IF_RELEASE(sStringBundleService);
00429   NS_IF_RELEASE(sConsoleService);
00430   NS_IF_RELEASE(sDOMScriptObjectFactory);
00431   NS_IF_RELEASE(sXPConnect);
00432   NS_IF_RELEASE(sSecurityManager);
00433   NS_IF_RELEASE(sThreadJSContextStack);
00434   NS_IF_RELEASE(sNameSpaceManager);
00435   NS_IF_RELEASE(sParserService);
00436   NS_IF_RELEASE(sIOService);
00437 #ifdef MOZ_XTF
00438   NS_IF_RELEASE(sXTFService);
00439 #endif
00440   NS_IF_RELEASE(sImgLoader);
00441   NS_IF_RELEASE(sPrefBranch);
00442   NS_IF_RELEASE(sPref);
00443   if (sPtrsToPtrsToRelease) {
00444     for (i = 0; i < sPtrsToPtrsToRelease->Count(); ++i) {
00445       nsISupports** ptrToPtr =
00446         NS_STATIC_CAST(nsISupports**, sPtrsToPtrsToRelease->ElementAt(i));
00447       NS_RELEASE(*ptrToPtr);
00448     }
00449     delete sPtrsToPtrsToRelease;
00450     sPtrsToPtrsToRelease = nsnull;
00451   }
00452 }
00453 
00454 // static
00455 nsISupports *
00456 nsContentUtils::GetClassInfoInstance(nsDOMClassInfoID aID)
00457 {
00458   if (!sDOMScriptObjectFactory) {
00459     static NS_DEFINE_CID(kDOMScriptObjectFactoryCID,
00460                          NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
00461 
00462     CallGetService(kDOMScriptObjectFactoryCID, &sDOMScriptObjectFactory);
00463 
00464     if (!sDOMScriptObjectFactory) {
00465       return nsnull;
00466     }
00467   }
00468 
00469   return sDOMScriptObjectFactory->GetClassInfoInstance(aID);
00470 }
00471 
00472 // static
00473 nsresult
00474 nsContentUtils::GetDocumentAndPrincipal(nsIDOMNode* aNode,
00475                                         nsIDocument** aDocument,
00476                                         nsIPrincipal** aPrincipal)
00477 {
00478   // For performance reasons it's important to try to QI the node to
00479   // nsIContent before trying to QI to nsIDocument since a QI miss on
00480   // a node is potentially expensive.
00481   nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
00482   nsCOMPtr<nsIAttribute> attr;
00483 
00484   if (!content) {
00485     CallQueryInterface(aNode, aDocument);
00486 
00487     if (!*aDocument) {
00488       attr = do_QueryInterface(aNode);
00489       if (!attr) {
00490         // aNode is not a nsIContent, a nsIAttribute or a nsIDocument,
00491         // something weird is going on...
00492 
00493         NS_ERROR("aNode is not nsIContent, nsIAttribute or nsIDocument!");
00494 
00495         return NS_ERROR_UNEXPECTED;
00496       }
00497     }
00498   }
00499 
00500   if (!*aDocument) {
00501     nsCOMPtr<nsIDOMDocument> domDoc;
00502     aNode->GetOwnerDocument(getter_AddRefs(domDoc));
00503     if (!domDoc) {
00504       // if we can't get a doc then lets try to get principal through nodeinfo
00505       // manager
00506       nsINodeInfo *ni;
00507       if (content) {
00508         ni = content->GetNodeInfo();
00509       }
00510       else {
00511         ni = attr->NodeInfo();
00512       }
00513 
00514       if (!ni) {
00515         // we can't get to the principal so we'll give up
00516 
00517         return NS_OK;
00518       }
00519 
00520       *aPrincipal = ni->NodeInfoManager()->GetDocumentPrincipal();
00521       if (!*aPrincipal) {
00522         // we can't get to the principal so we'll give up
00523 
00524         return NS_OK;
00525       }
00526 
00527       NS_ADDREF(*aPrincipal);
00528     }
00529     else {
00530       CallQueryInterface(domDoc, aDocument);
00531       if (!*aDocument) {
00532         NS_ERROR("QI to nsIDocument failed");
00533 
00534         return NS_ERROR_UNEXPECTED;
00535       }
00536     }
00537   }
00538 
00539   if (!*aPrincipal) {
00540     NS_IF_ADDREF(*aPrincipal = (*aDocument)->GetPrincipal());
00541   }
00542 
00543   return NS_OK;
00544 }
00545 
00553 // static
00554 nsresult
00555 nsContentUtils::CheckSameOrigin(nsIDOMNode *aTrustedNode,
00556                                 nsIDOMNode *aUnTrustedNode)
00557 {
00558   NS_PRECONDITION(aTrustedNode, "There must be a trusted node");
00559 
00560   PRBool isSystem = PR_FALSE;
00561   sSecurityManager->SubjectPrincipalIsSystem(&isSystem);
00562   if (isSystem) {
00563     // we're running as system, grant access to the node.
00564 
00565     return NS_OK;
00566   }
00567 
00568   /*
00569    * Get hold of each node's document or principal
00570    */
00571 
00572   // In most cases this is a document, so lets try that first
00573   nsCOMPtr<nsIDocument> trustedDoc = do_QueryInterface(aTrustedNode);
00574   nsIPrincipal* trustedPrincipal = nsnull;
00575 
00576   if (!trustedDoc) {
00577 #ifdef DEBUG
00578     nsCOMPtr<nsIContent> trustCont = do_QueryInterface(aTrustedNode);
00579     NS_ASSERTION(trustCont,
00580                  "aTrustedNode is neither nsIContent nor nsIDocument!");
00581 #endif
00582     nsCOMPtr<nsIDOMDocument> domDoc;
00583     aTrustedNode->GetOwnerDocument(getter_AddRefs(domDoc));
00584 
00585     if (!domDoc) {
00586       // In theory this should never happen. But since theory and reality are
00587       // different for XUL elements we'll try to get the principal from the
00588       // nsNodeInfoManager.
00589 
00590       nsCOMPtr<nsIContent> cont = do_QueryInterface(aTrustedNode);
00591       NS_ENSURE_TRUE(cont, NS_ERROR_UNEXPECTED);
00592 
00593       nsINodeInfo *ni = cont->GetNodeInfo();
00594       NS_ENSURE_TRUE(ni, NS_ERROR_UNEXPECTED);
00595 
00596       trustedPrincipal = ni->NodeInfoManager()->GetDocumentPrincipal();
00597 
00598       if (!trustedPrincipal) {
00599         // Can't get principal of aTrustedNode so we can't check security
00600         // against it
00601 
00602         return NS_ERROR_UNEXPECTED;
00603       }
00604     } else {
00605       trustedDoc = do_QueryInterface(domDoc);
00606       NS_ASSERTION(trustedDoc, "QI to nsIDocument failed");
00607     }
00608   }
00609 
00610   nsCOMPtr<nsIDocument> unTrustedDoc;
00611   nsCOMPtr<nsIPrincipal> unTrustedPrincipal;
00612 
00613   nsresult rv = GetDocumentAndPrincipal(aUnTrustedNode,
00614                                         getter_AddRefs(unTrustedDoc),
00615                                         getter_AddRefs(unTrustedPrincipal));
00616   NS_ENSURE_SUCCESS(rv, rv);
00617 
00618   if (!unTrustedDoc && !unTrustedPrincipal) {
00619     // We can't get hold of the principal for this node. This should happen
00620     // very rarely, like for textnodes out of the tree and <option>s created
00621     // using 'new Option'.
00622     // If we didn't allow access to nodes like this you wouldn't be able to
00623     // insert these nodes into a document.
00624 
00625     return NS_OK;
00626   }
00627 
00628   /*
00629    * Compare the principals
00630    */
00631 
00632   // If they are in the same document then everything is just fine
00633   if (trustedDoc == unTrustedDoc && trustedDoc) {
00634     return NS_OK;
00635   }
00636 
00637   if (!trustedPrincipal) {
00638     trustedPrincipal = trustedDoc->GetPrincipal();
00639 
00640     if (!trustedPrincipal) {
00641       // If the trusted node doesn't have a principal we can't check
00642       // security against it
00643 
00644       return NS_ERROR_DOM_SECURITY_ERR;
00645     }
00646   }
00647 
00648   if (!unTrustedPrincipal) {
00649     unTrustedPrincipal = unTrustedDoc->GetPrincipal();
00650 
00651     if (!unTrustedPrincipal) {
00652       // If the trusted node doesn't have a principal we can't check
00653       // security against it
00654 
00655       return NS_ERROR_DOM_SECURITY_ERR;
00656     }
00657   }
00658 
00659   return sSecurityManager->CheckSameOriginPrincipal(trustedPrincipal,
00660                                                     unTrustedPrincipal);
00661 }
00662 
00663 // static
00664 PRBool
00665 nsContentUtils::CanCallerAccess(nsIDOMNode *aNode)
00666 {
00667   nsCOMPtr<nsIPrincipal> subjectPrincipal;
00668   sSecurityManager->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
00669 
00670   if (!subjectPrincipal) {
00671     // we're running as system, grant access to the node.
00672 
00673     return PR_TRUE;
00674   }
00675 
00676   nsCOMPtr<nsIPrincipal> systemPrincipal;
00677   sSecurityManager->GetSystemPrincipal(getter_AddRefs(systemPrincipal));
00678 
00679   if (subjectPrincipal == systemPrincipal) {
00680     // we're running as system, grant access to the node.
00681 
00682     return PR_TRUE;
00683   }
00684 
00685   nsCOMPtr<nsIDocument> document;
00686   nsCOMPtr<nsIPrincipal> principal;
00687 
00688   nsresult rv = GetDocumentAndPrincipal(aNode,
00689                                         getter_AddRefs(document),
00690                                         getter_AddRefs(principal));
00691   NS_ENSURE_SUCCESS(rv, PR_FALSE);
00692 
00693   if (!document && !principal) {
00694     // We can't get hold of the principal for this node. This should happen
00695     // very rarely, like for textnodes out of the tree and <option>s created
00696     // using 'new Option'.
00697     // If we didn't allow access to nodes like this you wouldn't be able to
00698     // insert these nodes into a document.
00699 
00700     return PR_TRUE;
00701   }
00702 
00703   PRBool enabled = PR_FALSE;
00704   if (principal == systemPrincipal) {
00705     // we know subjectPrincipal != systemPrincipal so we can only
00706     // access the object if UniversalXPConnect is enabled. We can
00707     // avoid wasting time in CheckSameOriginPrincipal
00708 
00709     rv = sSecurityManager->IsCapabilityEnabled("UniversalXPConnect", &enabled);
00710     return NS_SUCCEEDED(rv) && enabled;
00711   }
00712 
00713   rv = sSecurityManager->CheckSameOriginPrincipal(subjectPrincipal, principal);
00714   if (NS_SUCCEEDED(rv)) {
00715     return PR_TRUE;
00716   }
00717 
00718   // see if the caller has otherwise been given the ability to touch
00719   // input args to DOM methods
00720 
00721   rv = sSecurityManager->IsCapabilityEnabled("UniversalBrowserRead", &enabled);
00722   return NS_SUCCEEDED(rv) && enabled;
00723 }
00724 
00725 // static
00726 PRBool
00727 nsContentUtils::CanCallerAccess(nsPIDOMWindow* aWindow)
00728 {
00729   nsCOMPtr<nsIPrincipal> subjectPrincipal;
00730   sSecurityManager->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
00731 
00732   if (!subjectPrincipal) {
00733     // we're running as system, grant access to the node.
00734 
00735     return PR_TRUE;
00736   }
00737 
00738   nsCOMPtr<nsIPrincipal> systemPrincipal;
00739   sSecurityManager->GetSystemPrincipal(getter_AddRefs(systemPrincipal));
00740 
00741   if (subjectPrincipal == systemPrincipal) {
00742     // we're running as system, grant access to the node.
00743 
00744     return PR_TRUE;
00745   }
00746 
00747   nsCOMPtr<nsIScriptObjectPrincipal> scriptObject =
00748     do_QueryInterface(aWindow->IsOuterWindow() ?
00749                       aWindow->GetCurrentInnerWindow() : aWindow);
00750   NS_ENSURE_TRUE(scriptObject, PR_FALSE);
00751   nsIPrincipal* principal = scriptObject->GetPrincipal();
00752   NS_ENSURE_TRUE(principal, PR_FALSE);
00753 
00754   PRBool enabled = PR_FALSE;
00755   nsresult rv;
00756   if (principal == systemPrincipal) {
00757     // we know subjectPrincipal != systemPrincipal so we can only
00758     // access the object if UniversalXPConnect is enabled. We can
00759     // avoid wasting time in CheckSameOriginPrincipal
00760 
00761     rv = sSecurityManager->IsCapabilityEnabled("UniversalXPConnect", &enabled);
00762     return NS_SUCCEEDED(rv) && enabled;
00763   }
00764 
00765   rv = sSecurityManager->CheckSameOriginPrincipal(subjectPrincipal, principal);
00766   if (NS_SUCCEEDED(rv)) {
00767     return PR_TRUE;
00768   }
00769 
00770   // see if the caller has otherwise been given the ability to touch
00771   // input args to DOM methods
00772 
00773   rv = sSecurityManager->IsCapabilityEnabled("UniversalBrowserRead", &enabled);
00774   return NS_SUCCEEDED(rv) && enabled;
00775 }
00776 
00777 //static
00778 PRBool
00779 nsContentUtils::InProlog(nsIDOMNode *aNode)
00780 {
00781   NS_PRECONDITION(aNode, "missing node to nsContentUtils::InProlog");
00782 
00783   // Check that there is an ancestor and that it is a document
00784   nsCOMPtr<nsIDOMNode> parent;
00785   aNode->GetParentNode(getter_AddRefs(parent));
00786   if (!parent) {
00787     return PR_FALSE;
00788   }
00789 
00790   PRUint16 type;
00791   parent->GetNodeType(&type);
00792   if (type != nsIDOMNode::DOCUMENT_NODE) {
00793     return PR_FALSE;
00794   }
00795 
00796   nsCOMPtr<nsIDocument> doc = do_QueryInterface(parent);
00797   NS_ASSERTION(doc, "document doesn't implement nsIDocument");
00798   nsCOMPtr<nsIContent> cont = do_QueryInterface(aNode);
00799   NS_ASSERTION(cont, "node doesn't implement nsIContent");
00800 
00801   // Check that there are no elements before aNode to make sure we are not
00802   // in the epilog
00803   PRInt32 pos = doc->IndexOf(cont);
00804 
00805   while (pos > 0) {
00806     --pos;
00807     nsIContent *sibl = doc->GetChildAt(pos);
00808     if (sibl->IsContentOfType(nsIContent::eELEMENT)) {
00809       return PR_FALSE;
00810     }
00811   }
00812 
00813   return PR_TRUE;
00814 }
00815 
00816 // static
00817 nsresult
00818 nsContentUtils::doReparentContentWrapper(nsIContent *aNode,
00819                                          JSContext *cx,
00820                                          JSObject *aOldGlobal,
00821                                          JSObject *aNewGlobal)
00822 {
00823   nsCOMPtr<nsIXPConnectJSObjectHolder> old_wrapper;
00824 
00825   nsresult rv;
00826 
00827   rv = sXPConnect->ReparentWrappedNativeIfFound(cx, aOldGlobal, aNewGlobal,
00828                                                 aNode,
00829                                                 getter_AddRefs(old_wrapper));
00830   NS_ENSURE_SUCCESS(rv, rv);
00831 
00832   // Whether or not aChild is already wrapped we must iterate through
00833   // its descendants since there's no guarantee that a descendant isn't
00834   // wrapped even if this child is not wrapped. That used to be true
00835   // when every DOM node's JSObject was parented at the DOM node's
00836   // parent's JSObject, but that's no longer the case.
00837 
00838   PRUint32 i, count = aNode->GetChildCount();
00839 
00840   for (i = 0; i < count; i++) {
00841     nsIContent *child = aNode->GetChildAt(i);
00842     NS_ENSURE_TRUE(child, NS_ERROR_UNEXPECTED);
00843 
00844     rv = doReparentContentWrapper(child, cx, aOldGlobal, aNewGlobal);
00845     NS_ENSURE_SUCCESS(rv, rv);
00846   }
00847 
00848   return rv;
00849 }
00850 
00851 static JSContext *
00852 GetContextFromDocument(nsIDocument *aDocument, JSObject** aGlobalObject)
00853 {
00854   nsCOMPtr<nsIDocument_MOZILLA_1_8_0_BRANCH> doc18 =
00855     do_QueryInterface(aDocument);
00856   if (!doc18) {
00857     NS_ERROR("What kind of crazy document was passed in?");
00858     return nsnull;
00859   }
00860   nsIScriptGlobalObject *sgo = doc18->GetScopeObject();
00861   if (!sgo) {
00862     // No script global, no context.
00863 
00864     *aGlobalObject = nsnull;
00865 
00866     return nsnull;
00867   }
00868 
00869   *aGlobalObject = sgo->GetGlobalJSObject();
00870 
00871   nsIScriptContext *scx = sgo->GetContext();
00872   if (!scx) {
00873     // No context left in the old scope...
00874 
00875     return nsnull;
00876   }
00877 
00878   return (JSContext *)scx->GetNativeContext();
00879 }
00880 
00881 // static
00882 nsresult
00883 nsContentUtils::ReparentContentWrapper(nsIContent *aContent,
00884                                        nsIContent *aNewParent,
00885                                        nsIDocument *aNewDocument,
00886                                        nsIDocument *aOldDocument)
00887 {
00888   if (!aNewDocument || aNewDocument == aOldDocument) {
00889     return NS_OK;
00890   }
00891 
00892 
00893   nsCOMPtr<nsIDocument_MOZILLA_1_8_0_BRANCH> doc18 =
00894     do_QueryInterface(aNewDocument);
00895   if (!doc18) {
00896     NS_ERROR("Crazy document passed in");
00897     return NS_ERROR_UNEXPECTED;
00898   }
00899   nsIScriptGlobalObject *newSGO = doc18->GetScopeObject();
00900   JSObject *newScope;
00901 
00902   // If we can't find our old document we don't know what our old
00903   // scope was so there's no way to find the old wrapper, and if there
00904   // is no new scope there's no reason to reparent.
00905   if (!aOldDocument || !newSGO || !(newScope = newSGO->GetGlobalJSObject())) {
00906     return NS_OK;
00907   }
00908 
00909   NS_ENSURE_TRUE(sXPConnect, NS_ERROR_NOT_INITIALIZED);
00910 
00911   // Make sure to get our hands on the right scope object, since
00912   // GetWrappedNativeOfNativeObject doesn't call PreCreate and hence won't get
00913   // the right scope if we pass in something bogus.  The right scope lives on
00914   // the script global of the old document.
00915   // XXXbz note that if GetWrappedNativeOfNativeObject did call PreCreate it
00916   // would get the wrong scope (that of the _new_ document), so we should be
00917   // glad it doesn't!
00918   JSObject *globalObj;
00919   JSContext *cx = GetContextFromDocument(aOldDocument, &globalObj);
00920 
00921   if (!globalObj) {
00922     // No global object around; can't find the old wrapper w/o the old
00923     // global object
00924 
00925     return NS_OK;
00926   }
00927 
00928   if (!cx) {
00929     JSObject *dummy;
00930     cx = GetContextFromDocument(aNewDocument, &dummy);
00931 
00932     if (!cx) {
00933       // No context reachable from the old or new document, use the
00934       // calling context, or the safe context if no caller can be
00935       // found.
00936 
00937       sThreadJSContextStack->Peek(&cx);
00938 
00939       if (!cx) {
00940         sThreadJSContextStack->GetSafeJSContext(&cx);
00941       }
00942     }
00943   }
00944 
00945   return doReparentContentWrapper(aContent, cx, globalObj, newScope);
00946 }
00947 
00948 nsresult
00949 nsContentUtils::ReparentContentWrappersInScope(nsIScriptGlobalObject *aOldScope,
00950                                                nsIScriptGlobalObject *aNewScope)
00951 {
00952   JSContext *cx = nsnull;
00953 
00954   // Try really hard to find a context to work on.
00955   nsIScriptContext *context = aOldScope->GetContext();
00956   if (context) {
00957     cx = NS_STATIC_CAST(JSContext *, context->GetNativeContext());
00958   }
00959 
00960   if (!cx) {
00961     context = aNewScope->GetContext();
00962     if (context) {
00963       cx = NS_STATIC_CAST(JSContext *, context->GetNativeContext());
00964     }
00965 
00966     if (!cx) {
00967       sThreadJSContextStack->Peek(&cx);
00968 
00969       if (!cx) {
00970         sThreadJSContextStack->GetSafeJSContext(&cx);
00971 
00972         if (!cx) {
00973           // Wow, this is really bad!
00974           NS_WARNING("No context reachable in ReparentContentWrappers()!");
00975 
00976           return NS_ERROR_NOT_AVAILABLE;
00977         }
00978       }
00979     }
00980   }
00981 
00982   // Now that we have a context, let's get the global objects from the two
00983   // scopes and ask XPConnect to do the rest of the work.
00984 
00985   JSObject *oldScopeObj = aOldScope->GetGlobalJSObject();
00986   JSObject *newScopeObj = aNewScope->GetGlobalJSObject();
00987 
00988   if (!newScopeObj || !oldScopeObj) {
00989     // We can't really do anything without the JSObjects.
00990 
00991     return NS_ERROR_NOT_AVAILABLE;
00992   }
00993 
00994   nsCOMPtr<nsIXPConnect_MOZILLA_1_8_BRANCH> xpconnect18 =
00995     do_QueryInterface(sXPConnect);
00996   if (!xpconnect18) {
00997     NS_ERROR("Weird things are happening in XPConnect");
00998     return NS_ERROR_FAILURE;
00999   }
01000   return xpconnect18->ReparentScopeAwareWrappers(cx, oldScopeObj, newScopeObj);
01001 }
01002 
01003 nsIDocShell *
01004 nsContentUtils::GetDocShellFromCaller()
01005 {
01006   if (!sThreadJSContextStack) {
01007     return nsnull;
01008   }
01009 
01010   JSContext *cx = nsnull;
01011   sThreadJSContextStack->Peek(&cx);
01012 
01013   if (cx) {
01014     nsIScriptGlobalObject *sgo = nsJSUtils::GetDynamicScriptGlobal(cx);
01015 
01016     if (sgo) {
01017       return sgo->GetDocShell();
01018     }
01019   }
01020 
01021   return nsnull;
01022 }
01023 
01024 nsIDOMDocument *
01025 nsContentUtils::GetDocumentFromCaller()
01026 {
01027   JSContext *cx = nsnull;
01028   sThreadJSContextStack->Peek(&cx);
01029 
01030   nsIDOMDocument *doc = nsnull;
01031 
01032   if (cx) {
01033     JSObject *callee = nsnull;
01034     JSStackFrame *fp = nsnull;
01035     while (!callee && (fp = ::JS_FrameIterator(cx, &fp))) {
01036       callee = ::JS_GetFrameCalleeObject(cx, fp);
01037     }
01038 
01039     nsCOMPtr<nsPIDOMWindow> win =
01040       do_QueryInterface(nsJSUtils::GetStaticScriptGlobal(cx, callee));
01041     if (win) {
01042       doc = win->GetExtantDocument();
01043     }
01044   }
01045 
01046   return doc;
01047 }
01048 
01049 nsIDOMDocument *
01050 nsContentUtils::GetDocumentFromContext()
01051 {
01052   if (!sThreadJSContextStack) {
01053     return nsnull;
01054   }
01055 
01056   JSContext *cx = nsnull;
01057   sThreadJSContextStack->Peek(&cx);
01058 
01059   nsCOMPtr<nsIDOMDocument> doc;
01060 
01061   if (cx) {
01062     nsIScriptGlobalObject *sgo = nsJSUtils::GetDynamicScriptGlobal(cx);
01063 
01064     nsCOMPtr<nsIDOMWindowInternal> win(do_QueryInterface(sgo));
01065     if (win) {
01066       win->GetDocument(getter_AddRefs(doc));
01067     }
01068   }
01069 
01070   // This will return a pointer to something we're about to release,
01071   // but that's ok here.
01072   return doc;
01073 }
01074 
01075 PRBool
01076 nsContentUtils::IsCallerChrome()
01077 {
01078   PRBool is_caller_chrome = PR_FALSE;
01079 
01080   if (sSecurityManager) {
01081     nsresult rv = sSecurityManager->SubjectPrincipalIsSystem(&is_caller_chrome);
01082     if (NS_FAILED(rv)) {
01083       return PR_FALSE;
01084     }
01085   }
01086 
01087   return is_caller_chrome;
01088 }
01089 
01090 PRBool
01091 nsContentUtils::IsCallerTrustedForCapability(const char* aCapability)
01092 {
01093   if (nsContentUtils::IsCallerChrome())
01094     return PR_TRUE;
01095 
01096   // The secman really should handle UniversalXPConnect case, since that
01097   // should include UniversalBrowserRead... doesn't right now, though.
01098   PRBool hasCap;
01099   nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
01100   if (NS_FAILED(ssm->IsCapabilityEnabled(aCapability, &hasCap)))
01101     return PR_FALSE;
01102   if (hasCap)
01103     return PR_TRUE;
01104     
01105   if (NS_FAILED(ssm->IsCapabilityEnabled("UniversalXPConnect", &hasCap)))
01106     return PR_FALSE;
01107   return hasCap;
01108 }
01109 
01110 PRBool
01111 nsContentUtils::IsCallerTrustedForRead()
01112 {
01113   return IsCallerTrustedForCapability("UniversalBrowserRead");
01114 }
01115 
01116 PRBool
01117 nsContentUtils::IsCallerTrustedForWrite()
01118 {
01119   return IsCallerTrustedForCapability("UniversalBrowserWrite");
01120 }
01121 
01122 // static
01123 PRBool
01124 nsContentUtils::InSameDoc(nsIDOMNode* aNode, nsIDOMNode* aOther)
01125 {
01126   if (!aNode || !aOther) {
01127     return PR_FALSE;
01128   }
01129 
01130   nsCOMPtr<nsIContent> content(do_QueryInterface(aNode));
01131   nsCOMPtr<nsIContent> other(do_QueryInterface(aOther));
01132 
01133   if (content && other) {
01134     // XXXcaa Don't bother to check that either node is in a
01135     // document.  Editor relies on us returning true if neither
01136     // node is in a document.  See bug 154401.
01137     return content->GetDocument() == other->GetDocument();
01138   }
01139 
01140   return PR_FALSE;
01141 }
01142 
01143 // static
01144 PRBool
01145 nsContentUtils::ContentIsDescendantOf(nsIContent* aPossibleDescendant,
01146                                       nsIContent* aPossibleAncestor)
01147 {
01148   NS_PRECONDITION(aPossibleDescendant, "The possible descendant is null!");
01149   NS_PRECONDITION(aPossibleAncestor, "The possible ancestor is null!");
01150 
01151   do {
01152     if (aPossibleDescendant == aPossibleAncestor)
01153       return PR_TRUE;
01154     aPossibleDescendant = aPossibleDescendant->GetParent();
01155   } while (aPossibleDescendant);
01156 
01157   return PR_FALSE;
01158 }
01159 
01160 
01161 // static
01162 nsresult
01163 nsContentUtils::GetAncestors(nsIDOMNode* aNode,
01164                              nsVoidArray* aArray)
01165 {
01166   NS_ENSURE_ARG_POINTER(aNode);
01167 
01168   nsCOMPtr<nsIDOMNode> node(aNode);
01169   nsCOMPtr<nsIDOMNode> ancestor;
01170 
01171   do {
01172     aArray->AppendElement(node.get());
01173     node->GetParentNode(getter_AddRefs(ancestor));
01174     node.swap(ancestor);
01175   } while (node);
01176 
01177   return NS_OK;
01178 }
01179 
01180 // static
01181 nsresult
01182 nsContentUtils::GetAncestorsAndOffsets(nsIDOMNode* aNode,
01183                                        PRInt32 aOffset,
01184                                        nsVoidArray* aAncestorNodes,
01185                                        nsVoidArray* aAncestorOffsets)
01186 {
01187   NS_ENSURE_ARG_POINTER(aNode);
01188 
01189   nsCOMPtr<nsIContent> content(do_QueryInterface(aNode));
01190 
01191   if (!content) {
01192     return NS_ERROR_FAILURE;
01193   }
01194 
01195   if (aAncestorNodes->Count() != 0) {
01196     NS_WARNING("aAncestorNodes is not empty");
01197     aAncestorNodes->Clear();
01198   }
01199 
01200   if (aAncestorOffsets->Count() != 0) {
01201     NS_WARNING("aAncestorOffsets is not empty");
01202     aAncestorOffsets->Clear();
01203   }
01204 
01205   // insert the node itself
01206   aAncestorNodes->AppendElement(content.get());
01207   aAncestorOffsets->AppendElement(NS_INT32_TO_PTR(aOffset));
01208 
01209   // insert all the ancestors
01210   nsIContent* child = content;
01211   nsIContent* parent = child->GetParent();
01212   while (parent) {
01213     aAncestorNodes->AppendElement(parent);
01214     aAncestorOffsets->AppendElement(NS_INT32_TO_PTR(parent->IndexOf(child)));
01215     child = parent;
01216     parent = parent->GetParent();
01217   }
01218 
01219   return NS_OK;
01220 }
01221 
01222 // static
01223 nsresult
01224 nsContentUtils::GetCommonAncestor(nsIDOMNode *aNode,
01225                                   nsIDOMNode *aOther,
01226                                   nsIDOMNode** aCommonAncestor)
01227 {
01228   *aCommonAncestor = nsnull;
01229 
01230   nsCOMArray<nsIDOMNode> nodeArray;
01231   nsresult rv = GetFirstDifferentAncestors(aNode, aOther, nodeArray);
01232   NS_ENSURE_SUCCESS(rv, rv);
01233 
01234   nsIDOMNode *common = nodeArray[0];
01235 
01236   NS_ASSERTION(common, "The common ancestor is null!  Very bad!");
01237 
01238   *aCommonAncestor = common;
01239   NS_IF_ADDREF(*aCommonAncestor);
01240 
01241   return NS_OK;
01242 }
01243 
01244 // static
01245 nsresult
01246 nsContentUtils::GetFirstDifferentAncestors(nsIDOMNode *aNode,
01247                                            nsIDOMNode *aOther,
01248                                            nsCOMArray<nsIDOMNode>& aDifferentNodes)
01249 {
01250   NS_ENSURE_ARG_POINTER(aNode);
01251   NS_ENSURE_ARG_POINTER(aOther);
01252 
01253   if (aDifferentNodes.Count() != 0) {
01254     NS_WARNING("The aDifferentNodes array passed in is not empty!");
01255     aDifferentNodes.Clear();
01256   }
01257 
01258   // Test if both are the same node.
01259   if (aNode == aOther) {
01260     aDifferentNodes.AppendObject(aNode);
01261     return NS_OK;
01262   }
01263 
01264   nsCOMArray<nsIDOMNode> nodeAncestors;
01265   nsCOMArray<nsIDOMNode> otherAncestors;
01266 
01267   // Insert all the ancestors of |aNode|
01268   nsCOMPtr<nsIDOMNode> node(aNode);
01269   nsCOMPtr<nsIDOMNode> ancestor(node);
01270   do {
01271     nodeAncestors.AppendObject(node);
01272     node->GetParentNode(getter_AddRefs(ancestor));
01273     if (ancestor == aOther) {
01274       aDifferentNodes.AppendObject(aOther);
01275       return NS_OK;
01276     }
01277     node.swap(ancestor);
01278   } while (node);
01279 
01280   // Insert all the ancestors of |aOther|
01281   nsCOMPtr<nsIDOMNode> other(aOther);
01282   ancestor = other;
01283   do {
01284     otherAncestors.AppendObject(other);
01285     other->GetParentNode(getter_AddRefs(ancestor));
01286     if (ancestor == aNode) {
01287       aDifferentNodes.AppendObject(aNode);
01288       return NS_OK;
01289     }
01290     other.swap(ancestor);
01291   } while (other);
01292 
01293   PRInt32 nodeIdx  = nodeAncestors.Count() - 1;
01294   PRInt32 otherIdx = otherAncestors.Count() - 1;
01295 
01296   if (nodeAncestors[nodeIdx] != otherAncestors[otherIdx]) {
01297     // These two nodes are disconnected.  We can't get a common ancestor.
01298     return NS_ERROR_FAILURE;
01299   }
01300 
01301   // Go back through the ancestors, starting from the root,
01302   // until the first different ancestor found.
01303   do {
01304     --nodeIdx;
01305     --otherIdx;
01306   } while (nodeAncestors[nodeIdx] == otherAncestors[otherIdx]);
01307 
01308   NS_ASSERTION(nodeIdx >= 0 && otherIdx >= 0,
01309                "Something's wrong: our indices should not be negative here!");
01310 
01311   aDifferentNodes.AppendObject(nodeAncestors[nodeIdx + 1]);
01312   aDifferentNodes.AppendObject(nodeAncestors[nodeIdx]);
01313   aDifferentNodes.AppendObject(otherAncestors[otherIdx]);
01314 
01315   return NS_OK;
01316 }
01317 
01318 PRUint16
01319 nsContentUtils::ComparePositionWithAncestors(nsIDOMNode *aNode,
01320                                              nsIDOMNode *aOther)
01321 {
01322 #ifdef DEBUG
01323   PRUint16 nodeType = 0;
01324   PRUint16 otherType = 0;
01325   aNode->GetNodeType(&nodeType);
01326   aOther->GetNodeType(&otherType);
01327 
01328   NS_PRECONDITION(nodeType != nsIDOMNode::ATTRIBUTE_NODE &&
01329                   nodeType != nsIDOMNode::DOCUMENT_NODE &&
01330                   nodeType != nsIDOMNode::DOCUMENT_FRAGMENT_NODE &&
01331                   nodeType != nsIDOMNode::ENTITY_NODE &&
01332                   nodeType != nsIDOMNode::NOTATION_NODE &&
01333                   otherType != nsIDOMNode::ATTRIBUTE_NODE &&
01334                   otherType != nsIDOMNode::DOCUMENT_NODE &&
01335                   otherType != nsIDOMNode::DOCUMENT_FRAGMENT_NODE &&
01336                   otherType != nsIDOMNode::ENTITY_NODE &&
01337                   otherType != nsIDOMNode::NOTATION_NODE,
01338                   "Bad.  Go read the documentation in the header!");
01339 #endif // DEBUG
01340 
01341   PRUint16 mask = 0;
01342 
01343   nsCOMArray<nsIDOMNode> nodeAncestors;
01344 
01345   nsresult rv =
01346     nsContentUtils::GetFirstDifferentAncestors(aNode, aOther, nodeAncestors);
01347 
01348   if (NS_FAILED(rv)) {
01349     // If there is no common container node, then the order is based upon
01350     // order between the root container of each node that is in no container.
01351     // In this case, the result is disconnected and implementation-dependent.
01352     mask = (nsIDOM3Node::DOCUMENT_POSITION_DISCONNECTED |
01353             nsIDOM3Node::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC);
01354 
01355     return mask;
01356   }
01357 
01358   nsIDOMNode* commonAncestor = nodeAncestors[0];
01359 
01360   if (commonAncestor == aNode) {
01361     mask = (nsIDOM3Node::DOCUMENT_POSITION_CONTAINED_BY |
01362             nsIDOM3Node::DOCUMENT_POSITION_FOLLOWING);
01363 
01364     return mask;
01365   }
01366 
01367   if (commonAncestor == aOther) {
01368     mask |= (nsIDOM3Node::DOCUMENT_POSITION_CONTAINS |
01369              nsIDOM3Node::DOCUMENT_POSITION_PRECEDING);
01370 
01371     return mask;
01372   }
01373 
01374   // GetFirstDifferentAncestors should only succeed if one of the
01375   // two nodes is the common ancestor, or if we have a common ancestor
01376   // and the two first different ancestors.  We checked the case above
01377   // where one of the two nodes were the common ancestor, so we must
01378   // have three items in our array now.
01379   NS_ASSERTION(commonAncestor && nodeAncestors.Count() == 3,
01380                "Something's wrong");
01381 
01382   nsIDOMNode* nodeAncestor = nodeAncestors[1];
01383   nsIDOMNode* otherAncestor = nodeAncestors[2];
01384 
01385   if (nodeAncestor && otherAncestor) {
01386     // Find out which of the two nodes comes first in the document order.
01387     // First get the children of the common ancestor.
01388     nsCOMPtr<nsIDOMNodeList> children;
01389     commonAncestor->GetChildNodes(getter_AddRefs(children));
01390     PRUint32 numKids;
01391     children->GetLength(&numKids);
01392     for (PRUint32 i = 0; i < numKids; ++i) {
01393       // Then go through the children one at a time to see which we hit first.
01394       nsCOMPtr<nsIDOMNode> childNode;
01395       children->Item(i, getter_AddRefs(childNode));
01396       if (childNode == nodeAncestor) {
01397         mask |= nsIDOM3Node::DOCUMENT_POSITION_FOLLOWING;
01398         break;
01399       }
01400 
01401       if (childNode == otherAncestor) {
01402         mask |= nsIDOM3Node::DOCUMENT_POSITION_PRECEDING;
01403         break;
01404       }
01405     }
01406   }
01407 
01408   return mask;
01409 }
01410 
01411 PRUint16
01412 nsContentUtils::ReverseDocumentPosition(PRUint16 aDocumentPosition)
01413 {
01414   // Disconnected and implementation-specific flags cannot be reversed.
01415   // Keep them.
01416   PRUint16 reversedPosition =
01417     aDocumentPosition & (nsIDOM3Node::DOCUMENT_POSITION_DISCONNECTED |
01418                          nsIDOM3Node::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC);
01419 
01420   // Following/preceding
01421   if (aDocumentPosition & nsIDOM3Node::DOCUMENT_POSITION_FOLLOWING) {
01422     reversedPosition |= nsIDOM3Node::DOCUMENT_POSITION_PRECEDING;
01423   }
01424   else if (aDocumentPosition & nsIDOM3Node::DOCUMENT_POSITION_PRECEDING) {
01425     reversedPosition |= nsIDOM3Node::DOCUMENT_POSITION_FOLLOWING;
01426   }
01427 
01428   // Is contained/contains.
01429   if (aDocumentPosition & nsIDOM3Node::DOCUMENT_POSITION_CONTAINS) {
01430     reversedPosition |= nsIDOM3Node::DOCUMENT_POSITION_CONTAINED_BY;
01431   }
01432   else if (aDocumentPosition & nsIDOM3Node::DOCUMENT_POSITION_CONTAINED_BY) {
01433     reversedPosition |= nsIDOM3Node::DOCUMENT_POSITION_CONTAINS;
01434   }
01435 
01436   return reversedPosition;
01437 }
01438 
01439 inline PRBool
01440 IsCharInSet(const char* aSet,
01441             const PRUnichar aChar)
01442 {
01443   PRUnichar ch;
01444   while ((ch = *aSet)) {
01445     if (aChar == PRUnichar(ch)) {
01446       return PR_TRUE;
01447     }
01448     ++aSet;
01449   }
01450   return PR_FALSE;
01451 }
01452 
01457 // static
01458 const nsDependentSubstring
01459 nsContentUtils::TrimCharsInSet(const char* aSet,
01460                                const nsAString& aValue)
01461 {
01462   nsAString::const_iterator valueCurrent, valueEnd;
01463 
01464   aValue.BeginReading(valueCurrent);
01465   aValue.EndReading(valueEnd);
01466 
01467   // Skip charaters in the beginning
01468   while (valueCurrent != valueEnd) {
01469     if (!IsCharInSet(aSet, *valueCurrent)) {
01470       break;
01471     }
01472     ++valueCurrent;
01473   }
01474 
01475   if (valueCurrent != valueEnd) {
01476     for (;;) {
01477       --valueEnd;
01478       if (!IsCharInSet(aSet, *valueEnd)) {
01479         break;
01480       }
01481     }
01482     ++valueEnd; // Step beyond the last character we want in the value.
01483   }
01484 
01485   // valueEnd should point to the char after the last to copy
01486   return Substring(valueCurrent, valueEnd);
01487 }
01488 
01493 // static
01494 const nsDependentSubstring
01495 nsContentUtils::TrimWhitespace(const nsAString& aStr, PRBool aTrimTrailing)
01496 {
01497   nsAString::const_iterator start, end;
01498 
01499   aStr.BeginReading(start);
01500   aStr.EndReading(end);
01501 
01502   // Skip whitespace charaters in the beginning
01503   while (start != end && nsCRT::IsAsciiSpace(*start)) {
01504     ++start;
01505   }
01506 
01507   if (aTrimTrailing) {
01508     // Skip whitespace characters in the end.
01509     while (end != start) {
01510       --end;
01511 
01512       if (!nsCRT::IsAsciiSpace(*end)) {
01513         // Step back to the last non-whitespace character.
01514         ++end;
01515 
01516         break;
01517       }
01518     }
01519   }
01520 
01521   // Return a substring for the string w/o leading and/or trailing
01522   // whitespace
01523 
01524   return Substring(start, end);
01525 }
01526 
01527 static inline void KeyAppendSep(nsACString& aKey)
01528 {
01529   if (!aKey.IsEmpty()) {
01530     aKey.Append('>');
01531   }
01532 }
01533 
01534 static inline void KeyAppendString(const nsAString& aString, nsACString& aKey)
01535 {
01536   KeyAppendSep(aKey);
01537 
01538   // Could escape separator here if collisions happen.  > is not a legal char
01539   // for a name or type attribute, so we should be safe avoiding that extra work.
01540 
01541   AppendUTF16toUTF8(aString, aKey);
01542 }
01543 
01544 static inline void KeyAppendString(const nsACString& aString, nsACString& aKey)
01545 {
01546   KeyAppendSep(aKey);
01547 
01548   // Could escape separator here if collisions happen.  > is not a legal char
01549   // for a name or type attribute, so we should be safe avoiding that extra work.
01550 
01551   aKey.Append(aString);
01552 }
01553 
01554 static inline void KeyAppendInt(PRInt32 aInt, nsACString& aKey)
01555 {
01556   KeyAppendSep(aKey);
01557 
01558   aKey.Append(nsPrintfCString("%d", aInt));
01559 }
01560 
01561 static inline void KeyAppendAtom(nsIAtom* aAtom, nsACString& aKey)
01562 {
01563   NS_PRECONDITION(aAtom, "KeyAppendAtom: aAtom can not be null!\n");
01564 
01565   const char* atomString = nsnull;
01566   aAtom->GetUTF8String(&atomString);
01567 
01568   KeyAppendString(nsDependentCString(atomString), aKey);
01569 }
01570 
01571 static inline PRBool IsAutocompleteOff(nsIDOMElement* aElement)
01572 {
01573   nsAutoString autocomplete;
01574   aElement->GetAttribute(NS_LITERAL_STRING("autocomplete"), autocomplete);
01575   return autocomplete.LowerCaseEqualsLiteral("off");
01576 }
01577 
01578 /*static*/ nsresult
01579 nsContentUtils::GenerateStateKey(nsIContent* aContent,
01580                                  nsIDocument* aDocument,
01581                                  nsIStatefulFrame::SpecialStateID aID,
01582                                  nsACString& aKey)
01583 {
01584   aKey.Truncate();
01585 
01586   PRUint32 partID = aDocument ? aDocument->GetPartID() : 0;
01587 
01588   // SpecialStateID case - e.g. scrollbars around the content window
01589   // The key in this case is the special state id (always < min(contentID))
01590   if (nsIStatefulFrame::eNoID != aID) {
01591     KeyAppendInt(partID, aKey);  // first append a partID
01592     KeyAppendInt(aID, aKey);
01593     return NS_OK;
01594   }
01595 
01596   // We must have content if we're not using a special state id
01597   NS_ENSURE_TRUE(aContent, NS_ERROR_FAILURE);
01598 
01599   // Don't capture state for anonymous content
01600   PRUint32 contentID = aContent->ContentID();
01601   if (!contentID) {
01602     return NS_OK;
01603   }
01604 
01605   nsCOMPtr<nsIDOMElement> element(do_QueryInterface(aContent));
01606   if (element && IsAutocompleteOff(element)) {
01607     return NS_OK;
01608   }
01609 
01610   nsCOMPtr<nsIHTMLDocument> htmlDocument(do_QueryInterface(aContent->GetCurrentDoc()));
01611 
01612   KeyAppendInt(partID, aKey);  // first append a partID
01613   PRBool generatedUniqueKey = PR_FALSE;
01614 
01615   if (htmlDocument) {
01616     // Flush our content model so it'll be up to date
01617     aContent->GetCurrentDoc()->FlushPendingNotifications(Flush_Content);
01618 
01619     nsContentList *htmlForms = htmlDocument->GetForms();
01620     nsRefPtr<nsContentList> htmlFormControls =
01621       GetFormControlElements(aDocument);
01622 
01623     NS_ENSURE_TRUE(htmlForms && htmlFormControls, NS_ERROR_OUT_OF_MEMORY);
01624 
01625     // If we have a form control and can calculate form information, use
01626     // that as the key - it is more reliable than contentID.
01627     // Important to have a unique key, and tag/type/name may not be.
01628     //
01629     // If the control has a form, the format of the key is:
01630     // type>IndOfFormInDoc>IndOfControlInForm>FormName>name
01631     // else:
01632     // type>IndOfControlInDoc>name
01633     //
01634     // XXX We don't need to use index if name is there
01635     //
01636     nsCOMPtr<nsIFormControl> control(do_QueryInterface(aContent));
01637     if (control && htmlFormControls && htmlForms) {
01638 
01639       // Append the control type
01640       KeyAppendInt(control->GetType(), aKey);
01641 
01642       // If in a form, add form name / index of form / index in form
01643       PRInt32 index = -1;
01644       nsCOMPtr<nsIDOMHTMLFormElement> formElement;
01645       control->GetForm(getter_AddRefs(formElement));
01646       if (formElement) {
01647 
01648         if (IsAutocompleteOff(formElement)) {
01649           aKey.Truncate();
01650           return NS_OK;
01651         }
01652 
01653         // Append the index of the form in the document
01654         nsCOMPtr<nsIContent> formContent(do_QueryInterface(formElement));
01655         index = htmlForms->IndexOf(formContent, PR_FALSE);
01656         if (index <= -1) {
01657           //
01658           // XXX HACK this uses some state that was dumped into the document
01659           // specifically to fix bug 138892.  What we are trying to do is *guess*
01660           // which form this control's state is found in, with the highly likely
01661           // guess that the highest form parsed so far is the one.
01662           // This code should not be on trunk, only branch.
01663           //
01664           index = htmlDocument->GetNumFormsSynchronous() - 1;
01665         }
01666         if (index > -1) {
01667           KeyAppendInt(index, aKey);
01668 
01669           // Append the index of the control in the form
01670           nsCOMPtr<nsIForm> form(do_QueryInterface(formElement));
01671           form->IndexOfControl(control, &index);
01672 
01673           if (index > -1) {
01674             KeyAppendInt(index, aKey);
01675             generatedUniqueKey = PR_TRUE;
01676           }
01677         }
01678 
01679         // Append the form name
01680         nsAutoString formName;
01681         formElement->GetName(formName);
01682         KeyAppendString(formName, aKey);
01683 
01684       } else {
01685 
01686         // If not in a form, add index of control in document
01687         // Less desirable than indexing by form info.
01688 
01689         // Hash by index of control in doc (we are not in a form)
01690         // These are important as they are unique, and type/name may not be.
01691 
01692         // Note that we've already flushed content, so there's no
01693         // reason to flush it again.
01694         index = htmlFormControls->IndexOf(aContent, PR_FALSE);
01695         if (index > -1) {
01696           KeyAppendInt(index, aKey);
01697           generatedUniqueKey = PR_TRUE;
01698         }
01699       }
01700 
01701       // Append the control name
01702       nsAutoString name;
01703       aContent->GetAttr(kNameSpaceID_None, nsHTMLAtoms::name, name);
01704       KeyAppendString(name, aKey);
01705     }
01706   }
01707 
01708   if (!generatedUniqueKey) {
01709 
01710     // Either we didn't have a form control or we aren't in an HTML document
01711     // so we can't figure out form info, hash by content ID instead :(
01712     KeyAppendInt(contentID, aKey);
01713   }
01714 
01715   return NS_OK;
01716 }
01717 
01718 // static
01719 nsresult
01720 nsContentUtils::NewURIWithDocumentCharset(nsIURI** aResult,
01721                                           const nsAString& aSpec,
01722                                           nsIDocument* aDocument,
01723                                           nsIURI* aBaseURI)
01724 {
01725   return NS_NewURI(aResult, aSpec,
01726                    aDocument ? aDocument->GetDocumentCharacterSet().get() : nsnull,
01727                    aBaseURI, sIOService);
01728 }
01729 
01730 // static
01731 PRBool
01732 nsContentUtils::BelongsInForm(nsIDOMHTMLFormElement *aForm,
01733                               nsIContent *aContent)
01734 {
01735   NS_PRECONDITION(aForm, "Must have a form");
01736   NS_PRECONDITION(aContent, "Must have a content node");
01737 
01738   nsCOMPtr<nsIContent> form(do_QueryInterface(aForm));
01739 
01740   if (!form) {
01741     NS_ERROR("This should not happen, form is not an nsIContent!");
01742 
01743     return PR_TRUE;
01744   }
01745 
01746   if (form == aContent) {
01747     // A form does not belong inside itself, so we return false here
01748 
01749     return PR_FALSE;
01750   }
01751 
01752   nsIContent* content = aContent->GetParent();
01753 
01754   while (content) {
01755     if (content == form) {
01756       // aContent is contained within the form so we return true.
01757 
01758       return PR_TRUE;
01759     }
01760 
01761     if (content->Tag() == nsHTMLAtoms::form &&
01762         content->IsContentOfType(nsIContent::eHTML)) {
01763       // The child is contained within a form, but not the right form
01764       // so we ignore it.
01765 
01766       return PR_FALSE;
01767     }
01768 
01769     content = content->GetParent();
01770   }
01771 
01772   if (form->GetChildCount() > 0) {
01773     // The form is a container but aContent wasn't inside the form,
01774     // return false
01775 
01776     return PR_FALSE;
01777   }
01778 
01779   // The form is a leaf and aContent wasn't inside any other form so
01780   // we check whether the content comes after the form.  If it does,
01781   // return true.  If it does not, then it couldn't have been inside
01782   // the form in the HTML.
01783   nsCOMPtr<nsIDOM3Node> contentAsDOM3(do_QueryInterface(aContent));
01784   PRUint16 comparisonFlags = 0;
01785   nsresult rv = NS_OK;
01786   if (contentAsDOM3) {
01787     rv = contentAsDOM3->CompareDocumentPosition(aForm, &comparisonFlags);
01788   }
01789   if (NS_FAILED(rv) ||
01790       comparisonFlags & nsIDOM3Node::DOCUMENT_POSITION_PRECEDING) {
01791     // We could be in this form!
01792     // In the future, we may want to get document.forms, look at the
01793     // form after aForm, and if aContent is after that form after
01794     // aForm return false here....
01795     return PR_TRUE;
01796   }
01797 
01798   return PR_FALSE;
01799 }
01800 
01801 // static
01802 nsresult
01803 nsContentUtils::CheckQName(const nsAString& aQualifiedName,
01804                            PRBool aNamespaceAware)
01805 {
01806   nsIParserService *parserService = GetParserServiceWeakRef();
01807   NS_ENSURE_TRUE(parserService, NS_ERROR_FAILURE);
01808 
01809   const PRUnichar *colon;
01810   return parserService->CheckQName(PromiseFlatString(aQualifiedName),
01811                                    aNamespaceAware, &colon);
01812 }
01813 
01814 //static
01815 nsresult
01816 nsContentUtils::SplitQName(nsIContent* aNamespaceResolver,
01817                            const nsAFlatString& aQName,
01818                            PRInt32 *aNamespace, nsIAtom **aLocalName)
01819 {
01820   nsIParserService* parserService = GetParserServiceWeakRef();
01821   NS_ENSURE_TRUE(parserService, NS_ERROR_FAILURE);
01822 
01823   const PRUnichar* colon;
01824   nsresult rv = parserService->CheckQName(aQName, PR_TRUE, &colon);
01825   NS_ENSURE_SUCCESS(rv, rv);
01826 
01827   if (colon) {
01828     const PRUnichar* end;
01829     aQName.EndReading(end);
01830     nsAutoString nameSpace;
01831     rv = LookupNamespaceURI(aNamespaceResolver, Substring(aQName.get(), colon),
01832                             nameSpace);
01833     NS_ENSURE_SUCCESS(rv, rv);
01834 
01835     GetNSManagerWeakRef()->GetNameSpaceID(nameSpace, aNamespace);
01836     if (*aNamespace == kNameSpaceID_Unknown)
01837       return NS_ERROR_FAILURE;
01838 
01839     *aLocalName = NS_NewAtom(Substring(colon + 1, end));
01840   }
01841   else {
01842     *aNamespace = kNameSpaceID_None;
01843     *aLocalName = NS_NewAtom(aQName);
01844   }
01845   NS_ENSURE_TRUE(aLocalName, NS_ERROR_OUT_OF_MEMORY);
01846   return NS_OK;
01847 }
01848 
01849 // static
01850 nsresult
01851 nsContentUtils::LookupNamespaceURI(nsIContent* aNamespaceResolver,
01852                                    const nsAString& aNamespacePrefix,
01853                                    nsAString& aNamespaceURI)
01854 {
01855   nsCOMPtr<nsIAtom> name;
01856   if (!aNamespacePrefix.IsEmpty()) {
01857     name = do_GetAtom(aNamespacePrefix);
01858     NS_ENSURE_TRUE(name, NS_ERROR_OUT_OF_MEMORY);
01859   }
01860   else {
01861     name = nsLayoutAtoms::xmlnsNameSpace;
01862   }
01863   // Trace up the content parent chain looking for the namespace
01864   // declaration that declares aNamespacePrefix.
01865   for (nsIContent* content = aNamespaceResolver; content;
01866        content = content->GetParent()) {
01867     if (content->GetAttr(kNameSpaceID_XMLNS, name, aNamespaceURI) ==
01868         NS_CONTENT_ATTR_HAS_VALUE)
01869       return NS_OK;
01870   }
01871   return NS_ERROR_FAILURE;
01872 }
01873 
01874 // static
01875 nsresult
01876 nsContentUtils::GetNodeInfoFromQName(const nsAString& aNamespaceURI,
01877                                      const nsAString& aQualifiedName,
01878                                      nsNodeInfoManager* aNodeInfoManager,
01879                                      nsINodeInfo** aNodeInfo)
01880 {
01881   nsIParserService* parserService = GetParserServiceWeakRef();
01882   NS_ENSURE_TRUE(parserService, NS_ERROR_FAILURE);
01883 
01884   const nsAFlatString& qName = PromiseFlatString(aQualifiedName);
01885   const PRUnichar* colon;
01886   nsresult rv = parserService->CheckQName(qName, PR_TRUE, &colon);
01887   NS_ENSURE_SUCCESS(rv, rv);
01888 
01889   PRInt32 nsID;
01890   sNameSpaceManager->RegisterNameSpace(aNamespaceURI, nsID);
01891   if (colon) {
01892     const PRUnichar* end;
01893     qName.EndReading(end);
01894 
01895     nsCOMPtr<nsIAtom> prefix = do_GetAtom(Substring(qName.get(), colon));
01896 
01897     rv = aNodeInfoManager->GetNodeInfo(Substring(colon + 1, end), prefix,
01898                                        nsID, aNodeInfo);
01899   }
01900   else {
01901     rv = aNodeInfoManager->GetNodeInfo(aQualifiedName, nsnull, nsID,
01902                                        aNodeInfo);
01903   }
01904   NS_ENSURE_SUCCESS(rv, rv);
01905 
01906   nsIAtom* prefix = (*aNodeInfo)->GetPrefixAtom();
01907   nsIAtom* nil = nsnull;
01908 
01909   // NAMESPACE_ERR: Raised if the qualifiedName is a malformed qualified name,
01910   // if the qualifiedName has a prefix and the namespaceURI is null, if the
01911   // qualifiedName has a prefix that is "xml" and the namespaceURI is different
01912   // from "http://www.w3.org/XML/1998/namespace", if the qualifiedName or its
01913   // prefix is "xmlns" and the namespaceURI is different from
01914   // "http://www.w3.org/2000/xmlns/", or if the namespaceURI is
01915   // "http://www.w3.org/2000/xmlns/" and neither the qualifiedName nor its
01916   // prefix is "xmlns".
01917   PRBool xmlPrefix = prefix == nsLayoutAtoms::xmlNameSpace;
01918   PRBool xmlns = (*aNodeInfo)->Equals(nsLayoutAtoms::xmlnsNameSpace, nil) ||
01919                  prefix == nsLayoutAtoms::xmlnsNameSpace;
01920 
01921   return (prefix && DOMStringIsNull(aNamespaceURI)) ||
01922          (xmlPrefix && nsID != kNameSpaceID_XML) ||
01923          (xmlns && nsID != kNameSpaceID_XMLNS) ||
01924          (nsID == kNameSpaceID_XMLNS && !xmlns) ?
01925          NS_ERROR_DOM_NAMESPACE_ERR : NS_OK;
01926 }
01927 
01928 // static
01929 void
01930 nsContentUtils::SplitExpatName(const PRUnichar *aExpatName, nsIAtom **aPrefix,
01931                                nsIAtom **aLocalName, PRInt32* aNameSpaceID)
01932 {
01943   const PRUnichar *uriEnd = nsnull;
01944   const PRUnichar *nameEnd = nsnull;
01945   const PRUnichar *pos;
01946   for (pos = aExpatName; *pos; ++pos) {
01947     if (*pos == 0xFFFF) {
01948       if (uriEnd) {
01949         nameEnd = pos;
01950       }
01951       else {
01952         uriEnd = pos;
01953       }
01954     }
01955   }
01956 
01957   const PRUnichar *nameStart;
01958   if (uriEnd) {
01959     if (sNameSpaceManager) {
01960       sNameSpaceManager->RegisterNameSpace(nsDependentSubstring(aExpatName,
01961                                                                 uriEnd),
01962                                            *aNameSpaceID);
01963     }
01964     else {
01965       *aNameSpaceID = kNameSpaceID_Unknown;
01966     }
01967 
01968     nameStart = (uriEnd + 1);
01969     if (nameEnd)  {
01970       const PRUnichar *prefixStart = nameEnd + 1;
01971       *aPrefix = NS_NewAtom(NS_ConvertUTF16toUTF8(prefixStart,
01972                                                   pos - prefixStart));
01973     }
01974     else {
01975       nameEnd = pos;
01976       *aPrefix = nsnull;
01977     }
01978   }
01979   else {
01980     *aNameSpaceID = kNameSpaceID_None;
01981     nameStart = aExpatName;
01982     nameEnd = pos;
01983     *aPrefix = nsnull;
01984   }
01985   *aLocalName = NS_NewAtom(NS_ConvertUTF16toUTF8(nameStart,
01986                                                  nameEnd - nameStart));
01987 }
01988 
01989 // static
01990 PRBool
01991 nsContentUtils::CanLoadImage(nsIURI* aURI, nsISupports* aContext,
01992                              nsIDocument* aLoadingDocument,
01993                              PRInt16* aImageBlockingStatus)
01994 {
01995   NS_PRECONDITION(aURI, "Must have a URI");
01996   NS_PRECONDITION(aLoadingDocument, "Must have a document");
01997 
01998   nsresult rv;
01999 
02000   PRUint32 appType = nsIDocShell::APP_TYPE_UNKNOWN;
02001 
02002   {
02003     nsCOMPtr<nsISupports> container = aLoadingDocument->GetContainer();
02004     nsCOMPtr<nsIDocShellTreeItem> docShellTreeItem =
02005       do_QueryInterface(container);
02006 
02007     if (docShellTreeItem) {
02008       nsCOMPtr<nsIDocShellTreeItem> root;
02009       docShellTreeItem->GetRootTreeItem(getter_AddRefs(root));
02010 
02011       nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(root));
02012 
02013       if (!docShell || NS_FAILED(docShell->GetAppType(&appType))) {
02014         appType = nsIDocShell::APP_TYPE_UNKNOWN;
02015       }
02016     }
02017   }
02018 
02019   if (appType != nsIDocShell::APP_TYPE_EDITOR) {
02020     // Editor apps get special treatment here, editors can load images
02021     // from anywhere.
02022     rv = sSecurityManager->
02023       CheckLoadURIWithPrincipal(aLoadingDocument->GetPrincipal(), aURI,
02024                                 nsIScriptSecurityManager::ALLOW_CHROME);
02025     if (NS_FAILED(rv)) {
02026       if (aImageBlockingStatus) {
02027         // Reject the request itself, not all requests to the relevant
02028         // server...
02029         *aImageBlockingStatus = nsIContentPolicy::REJECT_REQUEST;
02030       }
02031       return PR_FALSE;
02032     }
02033   }
02034 
02035   PRInt16 decision = nsIContentPolicy::ACCEPT;
02036 
02037   rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_IMAGE,
02038                                  aURI,
02039                                  aLoadingDocument->GetDocumentURI(),
02040                                  aContext,
02041                                  EmptyCString(), //mime guess
02042                                  nsnull,         //extra
02043                                  &decision);
02044 
02045   if (aImageBlockingStatus) {
02046     *aImageBlockingStatus =
02047       NS_FAILED(rv) ? nsIContentPolicy::REJECT_REQUEST : decision;
02048   }
02049   return NS_FAILED(rv) ? PR_FALSE : NS_CP_ACCEPTED(decision);
02050 }
02051 
02052 // static
02053 nsresult
02054 nsContentUtils::LoadImage(nsIURI* aURI, nsIDocument* aLoadingDocument,
02055                           nsIURI* aReferrer, imgIDecoderObserver* aObserver,
02056                           PRInt32 aLoadFlags, imgIRequest** aRequest)
02057 {
02058   NS_PRECONDITION(aURI, "Must have a URI");
02059   NS_PRECONDITION(aLoadingDocument, "Must have a document");
02060   NS_PRECONDITION(aRequest, "Null out param");
02061 
02062   if (!sImgLoader) {
02063     // nothing we can do here
02064     return NS_OK;
02065   }
02066 
02067   nsCOMPtr<nsILoadGroup> loadGroup = aLoadingDocument->GetDocumentLoadGroup();
02068   NS_WARN_IF_FALSE(loadGroup, "Could not get loadgroup; onload may fire too early");
02069 
02070   nsIURI *documentURI = aLoadingDocument->GetDocumentURI();
02071 
02072   // XXXbz using "documentURI" for the initialDocumentURI is not quite
02073   // right, but the best we can do here...
02074   return sImgLoader->LoadImage(aURI,                 /* uri to load */
02075                                documentURI,          /* initialDocumentURI */
02076                                aReferrer,            /* referrer */
02077                                loadGroup,            /* loadgroup */
02078                                aObserver,            /* imgIDecoderObserver */
02079                                aLoadingDocument,     /* uniquification key */
02080                                aLoadFlags,           /* load flags */
02081                                nsnull,               /* cache key */
02082                                nsnull,               /* existing request*/
02083                                aRequest);
02084 }
02085 
02086 // static
02087 already_AddRefed<nsIImage>
02088 nsContentUtils::GetImageFromContent(nsIImageLoadingContent* aContent,
02089                                     imgIRequest **aRequest)
02090 {
02091   if (aRequest) {
02092     *aRequest = nsnull;
02093   }
02094 
02095   NS_ENSURE_TRUE(aContent, nsnull);
02096 
02097   nsCOMPtr<imgIRequest> imgRequest;
02098   aContent->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
02099                       getter_AddRefs(imgRequest));
02100   if (!imgRequest) {
02101     return nsnull;
02102   }
02103 
02104   nsCOMPtr<imgIContainer> imgContainer;
02105   imgRequest->GetImage(getter_AddRefs(imgContainer));
02106 
02107   if (!imgContainer) {
02108     return nsnull;
02109   }
02110 
02111   nsCOMPtr<gfxIImageFrame> imgFrame;
02112   imgContainer->GetFrameAt(0, getter_AddRefs(imgFrame));
02113 
02114   if (!imgFrame) {
02115     return nsnull;
02116   }
02117 
02118   nsCOMPtr<nsIInterfaceRequestor> ir = do_QueryInterface(imgFrame);
02119 
02120   if (!ir) {
02121     return nsnull;
02122   }
02123 
02124   if (aRequest) {
02125     imgRequest.swap(*aRequest);
02126   }
02127 
02128   nsIImage* image = nsnull;
02129   CallGetInterface(ir.get(), &image);
02130   return image;
02131 }
02132 
02133 // static
02134 PRBool
02135 nsContentUtils::IsDraggableImage(nsIContent* aContent)
02136 {
02137   NS_PRECONDITION(aContent, "Must have content node to test");
02138 
02139   nsCOMPtr<nsIImageLoadingContent> imageContent(do_QueryInterface(aContent));
02140   if (!imageContent) {
02141     return PR_FALSE;
02142   }
02143 
02144   nsCOMPtr<imgIRequest> imgRequest;
02145   imageContent->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
02146                            getter_AddRefs(imgRequest));
02147 
02148   // XXXbz It may be draggable even if the request resulted in an error.  Why?
02149   // Not sure; that's what the old nsContentAreaDragDrop/nsFrame code did.
02150   return imgRequest != nsnull;
02151 }
02152 
02153 // static
02154 PRBool
02155 nsContentUtils::IsDraggableLink(nsIContent* aContent) {
02156   nsCOMPtr<nsIURI> linkURI = GetLinkURI(aContent);
02157 
02158   // Does it have a URI?  If not, it's not draggable
02159   return linkURI != nsnull;
02160 }
02161 
02162 // static
02163 already_AddRefed<nsIURI>
02164 nsContentUtils::GetLinkURI(nsIContent* aContent)
02165 {
02166   NS_PRECONDITION(aContent, "Must have content node to work with");
02167 
02168   nsCOMPtr<nsILink> link(do_QueryInterface(aContent));
02169   if (link) {
02170     nsIURI* uri = nsnull;
02171     link->GetHrefURI(&uri);
02172     if (uri) {
02173       return uri;
02174     }
02175   }
02176 
02177   // It could still be an XLink
02178   return GetXLinkURI(aContent);
02179 }
02180 
02181 // static
02182 already_AddRefed<nsIURI>
02183 nsContentUtils::GetXLinkURI(nsIContent* aContent)
02184 {
02185   NS_PRECONDITION(aContent, "Must have content node to work with");
02186 
02187   nsAutoString value;
02188   aContent->GetAttr(kNameSpaceID_XLink, nsHTMLAtoms::type, value);
02189   if (value.EqualsLiteral("simple")) {
02190     // Check that we have a URI
02191     aContent->GetAttr(kNameSpaceID_XLink, nsHTMLAtoms::href, value);
02192 
02193     if (!value.IsEmpty()) {
02194       //  Resolve it relative to aContent's base URI.
02195       nsCOMPtr<nsIURI> baseURI = aContent->GetBaseURI();
02196 
02197       nsIURI* uri = nsnull;
02198       nsContentUtils::NewURIWithDocumentCharset(&uri, value,
02199                                                 aContent->GetDocument(),
02200                                                 baseURI);
02201       return uri;
02202     }
02203   }
02204 
02205   return nsnull;
02206 }
02207 
02208 // static
02209 nsAdoptingCString
02210 nsContentUtils::GetCharPref(const char *aPref)
02211 {
02212   nsAdoptingCString result;
02213 
02214   if (sPrefBranch) {
02215     sPrefBranch->GetCharPref(aPref, getter_Copies(result));
02216   }
02217 
02218   return result;
02219 }
02220 
02221 // static
02222 PRPackedBool
02223 nsContentUtils::GetBoolPref(const char *aPref, PRBool aDefault)
02224 {
02225   PRBool result;
02226 
02227   if (!sPrefBranch ||
02228       NS_FAILED(sPrefBranch->GetBoolPref(aPref, &result))) {
02229     result = aDefault;
02230   }
02231 
02232   return (PRPackedBool)result;
02233 }
02234 
02235 // static
02236 PRInt32
02237 nsContentUtils::GetIntPref(const char *aPref, PRInt32 aDefault)
02238 {
02239   PRInt32 result;
02240 
02241   if (!sPrefBranch ||
02242       NS_FAILED(sPrefBranch->GetIntPref(aPref, &result))) {
02243     result = aDefault;
02244   }
02245 
02246   return result;
02247 }
02248 
02249 // static
02250 nsAdoptingString
02251 nsContentUtils::GetLocalizedStringPref(const char *aPref)
02252 {
02253   nsAdoptingString result;
02254 
02255   if (sPrefBranch) {
02256     nsCOMPtr<nsIPrefLocalizedString> prefLocalString;
02257     sPrefBranch->GetComplexValue(aPref, NS_GET_IID(nsIPrefLocalizedString),
02258                                  getter_AddRefs(prefLocalString));
02259     if (prefLocalString) {
02260       prefLocalString->GetData(getter_Copies(result));
02261     }
02262   }
02263 
02264   return result;
02265 }
02266 
02267 // static
02268 nsAdoptingString
02269 nsContentUtils::GetStringPref(const char *aPref)
02270 {
02271   nsAdoptingString result;
02272 
02273   if (sPrefBranch) {
02274     nsCOMPtr<nsISupportsString> theString;
02275     sPrefBranch->GetComplexValue(aPref, NS_GET_IID(nsISupportsString),
02276                                  getter_AddRefs(theString));
02277     if (theString) {
02278       theString->ToString(getter_Copies(result));
02279     }
02280   }
02281 
02282   return result;
02283 }
02284 
02285 // static
02286 void
02287 nsContentUtils::RegisterPrefCallback(const char *aPref,
02288                                      PrefChangedFunc aCallback,
02289                                      void * aClosure)
02290 {
02291   if (sPref)
02292     sPref->RegisterCallback(aPref, aCallback, aClosure);
02293 }
02294 
02295 // static
02296 void
02297 nsContentUtils::UnregisterPrefCallback(const char *aPref,
02298                                        PrefChangedFunc aCallback,
02299                                        void * aClosure)
02300 {
02301   if (sPref)
02302     sPref->UnregisterCallback(aPref, aCallback, aClosure);
02303 }
02304 
02305 
02306 static const char gEventName[] = "event";
02307 static const char gSVGEventName[] = "evt";
02308 
02309 // static
02310 const char *
02311 nsContentUtils::GetEventArgName(PRInt32 aNameSpaceID)
02312 {
02313   if (aNameSpaceID == kNameSpaceID_SVG)
02314     return gSVGEventName;
02315 
02316   return gEventName;
02317 }
02318 
02319 PRBool
02320 nsCxPusher::Push(nsISupports *aCurrentTarget)
02321 {
02322   if (mScx) {
02323     NS_ERROR("Whaaa! No double pushing with nsCxPusher::Push()!");
02324 
02325     return PR_FALSE;
02326   }
02327 
02328   nsCOMPtr<nsIScriptGlobalObject> sgo;
02329   nsCOMPtr<nsIContent> content(do_QueryInterface(aCurrentTarget));
02330   nsCOMPtr<nsIDocument> document;
02331 
02332   if (content) {
02333     document = content->GetOwnerDoc();
02334   }
02335 
02336   if (!document) {
02337     document = do_QueryInterface(aCurrentTarget);
02338   }
02339 
02340   if (document) {
02341     nsCOMPtr<nsIDocument_MOZILLA_1_8_BRANCH3> branch3doc =
02342       do_QueryInterface(document);
02343     NS_ASSERTION(branch3doc,
02344                  "Document must implement nsIDocument_MOZILLA_1_8_BRANCH3!!!");
02345     PRBool hasHadScriptObject = PR_TRUE;
02346     sgo = branch3doc->GetScriptHandlingObject(hasHadScriptObject);
02347     // It is bad if the document doesn't have event handling context,
02348     // but it used to have one.
02349     NS_ENSURE_TRUE(sgo || !hasHadScriptObject, PR_FALSE);
02350   }
02351 
02352   if (!document && !sgo) {
02353     sgo = do_QueryInterface(aCurrentTarget);
02354   }
02355 
02356   JSContext *cx = nsnull;
02357 
02358   if (sgo) {
02359     mScx = sgo->GetContext();
02360 
02361     if (mScx) {
02362       cx = (JSContext *)mScx->GetNativeContext();
02363       // Bad, no JSContext from script global object!
02364       NS_ENSURE_TRUE(cx, PR_FALSE);
02365     }
02366   }
02367 
02368   if (cx) {
02369     if (!mStack) {
02370       mStack = do_GetService(kJSStackContractID);
02371     }
02372 
02373     if (mStack) {
02374       JSContext *current = nsnull;
02375       mStack->Peek(&current);
02376 
02377       if (current) {
02378         // If there's a context on the stack, that means that a script
02379         // is running at the moment.
02380 
02381         mScriptIsRunning = PR_TRUE;
02382       }
02383 
02384       mStack->Push(cx);
02385     }
02386   } else {
02387     // If there's no native context in the script context it must be
02388     // in the process or being torn down. We don't want to notify the
02389     // script context about scripts having been evaluated in such a
02390     // case, so null out mScx.
02391 
02392     mScx = nsnull;
02393   }
02394   return PR_TRUE;
02395 }
02396 
02397 void
02398 nsCxPusher::Pop()
02399 {
02400   if (!mScx || !mStack) {
02401     mScx = nsnull;
02402 
02403     NS_ASSERTION(!mScriptIsRunning, "Huh, this can't be happening, "
02404                  "mScriptIsRunning can't be set here!");
02405 
02406     return;
02407   }
02408 
02409   JSContext *unused;
02410   mStack->Pop(&unused);
02411 
02412   if (!mScriptIsRunning) {
02413     // No JS is running, but executing the event handler might have
02414     // caused some JS to run. Tell the script context that it's done.
02415 
02416     mScx->ScriptEvaluated(PR_TRUE);
02417   }
02418 
02419   mScx = nsnull;
02420   mScriptIsRunning = PR_FALSE;
02421 }
02422 
02423 static const char gPropertiesFiles[nsContentUtils::PropertiesFile_COUNT][56] = {
02424   // Must line up with the enum values in |PropertiesFile| enum.
02425   "chrome://global/locale/css.properties",
02426   "chrome://global/locale/xbl.properties",
02427   "chrome://global/locale/xul.properties",
02428   "chrome://global/locale/layout_errors.properties",
02429   "chrome://global/locale/layout/HtmlForm.properties",
02430   "chrome://global/locale/printing.properties",
02431   "chrome://global/locale/dom/dom.properties",
02432   "chrome://branding/locale/brand.properties"
02433 };
02434 
02435 /* static */ nsresult
02436 nsContentUtils::EnsureStringBundle(PropertiesFile aFile)
02437 {
02438   if (!sStringBundles[aFile]) {
02439     if (!sStringBundleService) {
02440       nsresult rv =
02441         CallGetService(NS_STRINGBUNDLE_CONTRACTID, &sStringBundleService);
02442       NS_ENSURE_SUCCESS(rv, rv);
02443     }
02444     nsIStringBundle *bundle;
02445     nsresult rv =
02446       sStringBundleService->CreateBundle(gPropertiesFiles[aFile], &bundle);
02447     NS_ENSURE_SUCCESS(rv, rv);
02448     sStringBundles[aFile] = bundle; // transfer ownership
02449   }
02450   return NS_OK;
02451 }
02452 
02453 /* static */
02454 nsresult nsContentUtils::GetLocalizedString(PropertiesFile aFile,
02455                                             const char* aKey,
02456                                             nsXPIDLString& aResult)
02457 {
02458   nsresult rv = EnsureStringBundle(aFile);
02459   NS_ENSURE_SUCCESS(rv, rv);
02460   nsIStringBundle *bundle = sStringBundles[aFile];
02461 
02462   return bundle->GetStringFromName(NS_ConvertASCIItoUCS2(aKey).get(),
02463                                    getter_Copies(aResult));
02464 }
02465 
02466 /* static */
02467 nsresult nsContentUtils::FormatLocalizedString(PropertiesFile aFile,
02468                                                const char* aKey,
02469                                                const PRUnichar **aParams,
02470                                                PRUint32 aParamsLength,
02471                                                nsXPIDLString& aResult)
02472 {
02473   nsresult rv = EnsureStringBundle(aFile);
02474   NS_ENSURE_SUCCESS(rv, rv);
02475   nsIStringBundle *bundle = sStringBundles[aFile];
02476 
02477   return bundle->FormatStringFromName(NS_ConvertASCIItoUCS2(aKey).get(),
02478                                       aParams, aParamsLength,
02479                                       getter_Copies(aResult));
02480 }
02481 
02482 /* static */ nsresult
02483 nsContentUtils::ReportToConsole(PropertiesFile aFile,
02484                                 const char *aMessageName,
02485                                 const PRUnichar **aParams,
02486                                 PRUint32 aParamsLength,
02487                                 nsIURI* aURI,
02488                                 const nsAFlatString& aSourceLine,
02489                                 PRUint32 aLineNumber,
02490                                 PRUint32 aColumnNumber,
02491                                 PRUint32 aErrorFlags,
02492                                 const char *aCategory)
02493 {
02494   nsresult rv;
02495   if (!sConsoleService) { // only need to bother null-checking here
02496     rv = CallGetService(NS_CONSOLESERVICE_CONTRACTID, &sConsoleService);
02497     NS_ENSURE_SUCCESS(rv, rv);
02498   }
02499 
02500   nsXPIDLString errorText;
02501   rv = FormatLocalizedString(aFile, aMessageName, aParams, aParamsLength,
02502                              errorText);
02503   NS_ENSURE_SUCCESS(rv, rv);
02504 
02505   nsCAutoString spec;
02506   if (aURI)
02507     aURI->GetSpec(spec);
02508 
02509   nsCOMPtr<nsIScriptError> errorObject =
02510       do_CreateInstance(NS_SCRIPTERROR_CONTRACTID, &rv);
02511   NS_ENSURE_SUCCESS(rv, rv);
02512   rv = errorObject->Init(errorText.get(),
02513                          NS_ConvertUTF8toUTF16(spec).get(), // file name
02514                          aSourceLine.get(),
02515                          aLineNumber, aColumnNumber,
02516                          aErrorFlags, aCategory);
02517   NS_ENSURE_SUCCESS(rv, rv);
02518 
02519   return sConsoleService->LogMessage(errorObject);
02520 }
02521 
02522 static PRBool MatchFormControls(nsIContent* aContent, PRInt32 aNamespaceID,
02523                                 nsIAtom* aAtom, const nsAString& aData)
02524 {
02525   return aContent->IsContentOfType(nsIContent::eHTML_FORM_CONTROL);
02526 }
02527 
02528 /* static */ already_AddRefed<nsContentList>
02529 nsContentUtils::GetFormControlElements(nsIDocument *aDocument)
02530 {
02531   nsContentList *list = new nsContentList(aDocument,
02532                                           MatchFormControls, EmptyString());
02533   NS_IF_ADDREF(list);
02534   return list;
02535 }
02536 
02537 PRBool
02538 nsContentUtils::IsChromeDoc(nsIDocument *aDocument)
02539 {
02540   nsIPrincipal *principal;
02541   if (!aDocument || !(principal = aDocument->GetPrincipal())) {
02542     return PR_FALSE;
02543   }
02544 
02545   nsCOMPtr<nsIPrincipal> systemPrincipal;
02546   sSecurityManager->GetSystemPrincipal(getter_AddRefs(systemPrincipal));
02547 
02548   return principal == systemPrincipal;
02549 }
02550 
02551 void
02552 nsContentUtils::NotifyXPCIfExceptionPending(JSContext* aCx)
02553 {
02554   if (!::JS_IsExceptionPending(aCx)) {
02555     return;
02556   }
02557 
02558   nsCOMPtr<nsIXPCNativeCallContext> nccx;
02559   XPConnect()->GetCurrentNativeCallContext(getter_AddRefs(nccx));
02560   if (nccx) {
02561     // Check to make sure that the JSContext that nccx will mess with is the
02562     // same as the JSContext we've set an exception on.  If they're not the
02563     // same, don't mess with nccx.
02564     JSContext* cx;
02565     nccx->GetJSContext(&cx);
02566     if (cx == aCx) {
02567       nccx->SetExceptionWasThrown(PR_TRUE);
02568     }
02569   }
02570 }
02571 
02572 // static
02573 nsresult
02574 nsContentUtils::AddJSGCRoot(void* aPtr, const char* aName)
02575 {
02576   if (!sScriptRuntime) {
02577     nsresult rv = CallGetService("@mozilla.org/js/xpc/RuntimeService;1",
02578                                  &sJSRuntimeService);
02579     NS_ENSURE_TRUE(sJSRuntimeService, rv);
02580 
02581     sJSRuntimeService->GetRuntime(&sScriptRuntime);
02582     if (!sScriptRuntime) {
02583       NS_RELEASE(sJSRuntimeService);
02584       NS_WARNING("Unable to get JS runtime from JS runtime service");
02585       return NS_ERROR_FAILURE;
02586     }
02587   }
02588 
02589   PRBool ok;
02590   ok = ::JS_AddNamedRootRT(sScriptRuntime, aPtr, aName);
02591   if (!ok) {
02592     if (sScriptRootCount == 0) {
02593       // We just got the runtime... Just null things out, since no
02594       // one's expecting us to have a runtime yet
02595       NS_RELEASE(sJSRuntimeService);
02596       sScriptRuntime = nsnull;
02597     }
02598     NS_WARNING("JS_AddNamedRootRT failed");
02599     return NS_ERROR_OUT_OF_MEMORY;
02600   }
02601 
02602   // We now have one more root we added to the runtime
02603   ++sScriptRootCount;
02604 
02605   return NS_OK;
02606 }
02607 
02608 /* static */
02609 nsresult
02610 nsContentUtils::RemoveJSGCRoot(void* aPtr)
02611 {
02612   if (!sScriptRuntime) {
02613     NS_NOTREACHED("Trying to remove a JS GC root when none were added");
02614     return NS_ERROR_UNEXPECTED;
02615   }
02616 
02617   ::JS_RemoveRootRT(sScriptRuntime, aPtr);
02618 
02619   if (--sScriptRootCount == 0) {
02620     NS_RELEASE(sJSRuntimeService);
02621     sScriptRuntime = nsnull;
02622   }
02623 
02624   return NS_OK;
02625 }
02626 /* static */
02627 PRBool
02628 nsContentUtils::IsNativeAnonymous(nsIContent* aContent)
02629 {
02630   while (aContent) {
02631     nsIContent* bindingParent = aContent->GetBindingParent();
02632     if (bindingParent == aContent) {
02633       return PR_TRUE;
02634     }
02635     if (aContent->IsContentOfType(nsIContent::eTEXT)) {
02636       aContent = aContent->GetParent();
02637     } else {
02638       aContent = bindingParent;
02639     }
02640   }
02641   return PR_FALSE;
02642 }