LCOV - code coverage report
Current view: directory - content/xul/document/src - nsXULDocument.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 1914 20 1.0 %
Date: 2012-06-02 Functions: 149 3 2.0 %

       1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2                 : /* vim: set ts=4 sw=4 et tw=80: */
       3                 : /* ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is Mozilla Communicator client code.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  * Netscape Communications Corporation.
      20                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *   Chris Waterson <waterson@netscape.com>
      25                 :  *   Ben Goodger <ben@netscape.com>
      26                 :  *   Pete Collins <petejc@collab.net>
      27                 :  *   Dan Rosen <dr@netscape.com>
      28                 :  *   Johnny Stenback <jst@netscape.com>
      29                 :  *
      30                 :  * Alternatively, the contents of this file may be used under the terms of
      31                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      32                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      33                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      34                 :  * of those above. If you wish to allow use of your version of this file only
      35                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      36                 :  * use your version of this file under the terms of the MPL, indicate your
      37                 :  * decision by deleting the provisions above and replace them with the notice
      38                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      39                 :  * the provisions above, a recipient may use your version of this file under
      40                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      41                 :  *
      42                 :  * ***** END LICENSE BLOCK ***** */
      43                 : 
      44                 : /*
      45                 : 
      46                 :   An implementation for the XUL document. This implementation serves
      47                 :   as the basis for generating an NGLayout content model.
      48                 : 
      49                 :   Notes
      50                 :   -----
      51                 : 
      52                 :   1. We do some monkey business in the document observer methods to`
      53                 :      keep the element map in sync for HTML elements. Why don't we just
      54                 :      do it for _all_ elements? Well, in the case of XUL elements,
      55                 :      which may be lazily created during frame construction, the
      56                 :      document observer methods will never be called because we'll be
      57                 :      adding the XUL nodes into the content model "quietly".
      58                 : 
      59                 : */
      60                 : 
      61                 : #include "mozilla/Util.h"
      62                 : 
      63                 : // Note the ALPHABETICAL ORDERING
      64                 : #include "nsXULDocument.h"
      65                 : 
      66                 : #include "nsDOMError.h"
      67                 : #include "nsIBoxObject.h"
      68                 : #include "nsIChromeRegistry.h"
      69                 : #include "nsIView.h"
      70                 : #include "nsIViewManager.h"
      71                 : #include "nsIContentViewer.h"
      72                 : #include "nsGUIEvent.h"
      73                 : #include "nsIDOMXULElement.h"
      74                 : #include "nsIPrivateDOMEvent.h"
      75                 : #include "nsIRDFNode.h"
      76                 : #include "nsIRDFRemoteDataSource.h"
      77                 : #include "nsIRDFService.h"
      78                 : #include "nsIStreamListener.h"
      79                 : #include "nsITimer.h"
      80                 : #include "nsIDocShell.h"
      81                 : #include "nsGkAtoms.h"
      82                 : #include "nsXMLContentSink.h"
      83                 : #include "nsXULContentSink.h"
      84                 : #include "nsXULContentUtils.h"
      85                 : #include "nsIXULOverlayProvider.h"
      86                 : #include "nsNetUtil.h"
      87                 : #include "nsParserCIID.h"
      88                 : #include "nsPIBoxObject.h"
      89                 : #include "nsRDFCID.h"
      90                 : #include "nsILocalStore.h"
      91                 : #include "nsXPIDLString.h"
      92                 : #include "nsPIDOMWindow.h"
      93                 : #include "nsPIWindowRoot.h"
      94                 : #include "nsXULCommandDispatcher.h"
      95                 : #include "nsXULDocument.h"
      96                 : #include "nsXULElement.h"
      97                 : #include "prlog.h"
      98                 : #include "rdf.h"
      99                 : #include "nsIFrame.h"
     100                 : #include "mozilla/FunctionTimer.h"
     101                 : #include "nsIXBLService.h"
     102                 : #include "nsCExternalHandlerService.h"
     103                 : #include "nsMimeTypes.h"
     104                 : #include "nsIObjectInputStream.h"
     105                 : #include "nsIObjectOutputStream.h"
     106                 : #include "nsContentList.h"
     107                 : #include "nsIScriptGlobalObject.h"
     108                 : #include "nsIScriptGlobalObjectOwner.h"
     109                 : #include "nsIScriptRuntime.h"
     110                 : #include "nsIScriptSecurityManager.h"
     111                 : #include "nsNodeInfoManager.h"
     112                 : #include "nsContentCreatorFunctions.h"
     113                 : #include "nsContentUtils.h"
     114                 : #include "nsIParser.h"
     115                 : #include "nsIParserService.h"
     116                 : #include "nsCSSStyleSheet.h"
     117                 : #include "mozilla/css/Loader.h"
     118                 : #include "nsIScriptError.h"
     119                 : #include "nsIStyleSheetLinkingElement.h"
     120                 : #include "nsEventDispatcher.h"
     121                 : #include "nsContentErrors.h"
     122                 : #include "nsIObserverService.h"
     123                 : #include "nsNodeUtils.h"
     124                 : #include "nsIDocShellTreeItem.h"
     125                 : #include "nsIDocShellTreeOwner.h"
     126                 : #include "nsIXULWindow.h"
     127                 : #include "nsXULPopupManager.h"
     128                 : #include "nsCCUncollectableMarker.h"
     129                 : #include "nsURILoader.h"
     130                 : #include "mozilla/dom/Element.h"
     131                 : #include "mozilla/Preferences.h"
     132                 : 
     133                 : using namespace mozilla;
     134                 : using namespace mozilla::dom;
     135                 : 
     136                 : //----------------------------------------------------------------------
     137                 : //
     138                 : // CIDs
     139                 : //
     140                 : 
     141                 : static NS_DEFINE_CID(kParserCID,                 NS_PARSER_CID);
     142                 : 
     143               0 : static bool IsChromeURI(nsIURI* aURI)
     144                 : {
     145                 :     // why is this check a member function of nsXULDocument? -gagan
     146               0 :     bool isChrome = false;
     147               0 :     if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome)) && isChrome)
     148               0 :         return true;
     149               0 :     return false;
     150                 : }
     151                 : 
     152               0 : static bool IsOverlayAllowed(nsIURI* aURI)
     153                 : {
     154               0 :     bool canOverlay = false;
     155               0 :     if (NS_SUCCEEDED(aURI->SchemeIs("about", &canOverlay)) && canOverlay)
     156               0 :         return true;
     157               0 :     if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &canOverlay)) && canOverlay)
     158               0 :         return true;
     159               0 :     return false;
     160                 : }
     161                 : 
     162                 : //----------------------------------------------------------------------
     163                 : //
     164                 : // Miscellaneous Constants
     165                 : //
     166                 : 
     167                 : const nsForwardReference::Phase nsForwardReference::kPasses[] = {
     168                 :     nsForwardReference::eConstruction,
     169                 :     nsForwardReference::eHookup,
     170                 :     nsForwardReference::eDone
     171                 : };
     172                 : 
     173                 : const PRUint32 kMaxAttrNameLength = 512;
     174                 : const PRUint32 kMaxAttributeLength = 4096;
     175                 : 
     176                 : //----------------------------------------------------------------------
     177                 : //
     178                 : // Statics
     179                 : //
     180                 : 
     181                 : PRInt32 nsXULDocument::gRefCnt = 0;
     182                 : 
     183                 : nsIRDFService* nsXULDocument::gRDFService;
     184                 : nsIRDFResource* nsXULDocument::kNC_persist;
     185                 : nsIRDFResource* nsXULDocument::kNC_attribute;
     186                 : nsIRDFResource* nsXULDocument::kNC_value;
     187                 : 
     188                 : PRLogModuleInfo* nsXULDocument::gXULLog;
     189                 : 
     190                 : //----------------------------------------------------------------------
     191                 : 
     192                 : struct BroadcasterMapEntry : public PLDHashEntryHdr {
     193                 :     nsIDOMElement*   mBroadcaster; // [WEAK]
     194                 :     nsSmallVoidArray mListeners;   // [OWNING] of BroadcastListener objects
     195                 : };
     196                 : 
     197               0 : struct BroadcastListener {
     198                 :     nsWeakPtr mListener;
     199                 :     nsCOMPtr<nsIAtom> mAttribute;
     200                 : };
     201                 : 
     202                 : Element*
     203               0 : nsRefMapEntry::GetFirstElement()
     204                 : {
     205               0 :     return static_cast<Element*>(mRefContentList.SafeElementAt(0));
     206                 : }
     207                 : 
     208                 : void
     209               0 : nsRefMapEntry::AppendAll(nsCOMArray<nsIContent>* aElements)
     210                 : {
     211               0 :     for (PRInt32 i = 0; i < mRefContentList.Count(); ++i) {
     212               0 :         aElements->AppendObject(static_cast<nsIContent*>(mRefContentList[i]));
     213                 :     }
     214               0 : }
     215                 : 
     216                 : bool
     217               0 : nsRefMapEntry::AddElement(Element* aElement)
     218                 : {
     219               0 :     if (mRefContentList.IndexOf(aElement) >= 0)
     220               0 :         return true;
     221               0 :     return mRefContentList.AppendElement(aElement);
     222                 : }
     223                 : 
     224                 : bool
     225               0 : nsRefMapEntry::RemoveElement(Element* aElement)
     226                 : {
     227               0 :     mRefContentList.RemoveElement(aElement);
     228               0 :     return mRefContentList.Count() == 0;
     229                 : }
     230                 : 
     231                 : //----------------------------------------------------------------------
     232                 : //
     233                 : // ctors & dtors
     234                 : //
     235                 : 
     236                 :     // NOTE! nsDocument::operator new() zeroes out all members, so
     237                 :     // don't bother initializing members to 0.
     238                 : 
     239               0 : nsXULDocument::nsXULDocument(void)
     240                 :     : nsXMLDocument("application/vnd.mozilla.xul+xml"),
     241                 :       mDocLWTheme(Doc_Theme_Uninitialized),
     242                 :       mState(eState_Master),
     243               0 :       mResolutionPhase(nsForwardReference::eStart)
     244                 : {
     245                 : 
     246                 :     // NOTE! nsDocument::operator new() zeroes out all members, so don't
     247                 :     // bother initializing members to 0.
     248                 : 
     249                 :     // Override the default in nsDocument
     250               0 :     mCharacterSet.AssignLiteral("UTF-8");
     251                 : 
     252               0 :     mDefaultElementType = kNameSpaceID_XUL;
     253               0 :     mIsXUL = true;
     254                 : 
     255               0 :     mDelayFrameLoaderInitialization = true;
     256                 : 
     257               0 :     mAllowXULXBL = eTriTrue;
     258               0 : }
     259                 : 
     260               0 : nsXULDocument::~nsXULDocument()
     261                 : {
     262               0 :     NS_ASSERTION(mNextSrcLoadWaiter == nsnull,
     263                 :         "unreferenced document still waiting for script source to load?");
     264                 : 
     265                 :     // In case we failed somewhere early on and the forward observer
     266                 :     // decls never got resolved.
     267               0 :     mForwardReferences.Clear();
     268                 : 
     269                 :     // Destroy our broadcaster map.
     270               0 :     if (mBroadcasterMap) {
     271               0 :         PL_DHashTableDestroy(mBroadcasterMap);
     272                 :     }
     273                 : 
     274               0 :     if (mLocalStore) {
     275                 :         nsCOMPtr<nsIRDFRemoteDataSource> remote =
     276               0 :             do_QueryInterface(mLocalStore);
     277               0 :         if (remote)
     278               0 :             remote->Flush();
     279                 :     }
     280                 : 
     281               0 :     delete mTemplateBuilderTable;
     282                 : 
     283                 :     Preferences::UnregisterCallback(nsXULDocument::DirectionChanged,
     284               0 :                                     "intl.uidirection.", this);
     285                 : 
     286               0 :     if (--gRefCnt == 0) {
     287               0 :         NS_IF_RELEASE(gRDFService);
     288                 : 
     289               0 :         NS_IF_RELEASE(kNC_persist);
     290               0 :         NS_IF_RELEASE(kNC_attribute);
     291               0 :         NS_IF_RELEASE(kNC_value);
     292                 : 
     293                 :         // Remove the current document here from the table in
     294                 :         // case the document did not make it past StartLayout in
     295                 :         // ResumeWalk. 
     296               0 :         if (mDocumentURI)
     297               0 :             nsXULPrototypeCache::GetInstance()->RemoveFromCacheSet(mDocumentURI);
     298                 :     }
     299               0 : }
     300                 : 
     301                 : nsresult
     302               0 : NS_NewXULDocument(nsIXULDocument** result)
     303                 : {
     304               0 :     NS_PRECONDITION(result != nsnull, "null ptr");
     305               0 :     if (! result)
     306               0 :         return NS_ERROR_NULL_POINTER;
     307                 : 
     308               0 :     nsXULDocument* doc = new nsXULDocument();
     309               0 :     if (! doc)
     310               0 :         return NS_ERROR_OUT_OF_MEMORY;
     311                 : 
     312               0 :     NS_ADDREF(doc);
     313                 : 
     314                 :     nsresult rv;
     315               0 :     if (NS_FAILED(rv = doc->Init())) {
     316               0 :         NS_RELEASE(doc);
     317               0 :         return rv;
     318                 :     }
     319                 : 
     320               0 :     *result = doc;
     321               0 :     return NS_OK;
     322                 : }
     323                 : 
     324                 : 
     325                 : //----------------------------------------------------------------------
     326                 : //
     327                 : // nsISupports interface
     328                 : //
     329                 : 
     330            1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULDocument)
     331                 : 
     332                 : static PLDHashOperator
     333               0 : TraverseTemplateBuilders(nsISupports* aKey, nsIXULTemplateBuilder* aData,
     334                 :                          void* aContext)
     335                 : {
     336                 :     nsCycleCollectionTraversalCallback *cb =
     337               0 :         static_cast<nsCycleCollectionTraversalCallback*>(aContext);
     338                 : 
     339               0 :     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "mTemplateBuilderTable key");
     340               0 :     cb->NoteXPCOMChild(aKey);
     341               0 :     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "mTemplateBuilderTable value");
     342               0 :     cb->NoteXPCOMChild(aData);
     343                 : 
     344               0 :     return PL_DHASH_NEXT;
     345                 : }
     346                 : 
     347                 : static PLDHashOperator
     348               0 : TraverseObservers(nsIURI* aKey, nsIObserver* aData, void* aContext)
     349                 : {
     350                 :     nsCycleCollectionTraversalCallback *cb =
     351               0 :         static_cast<nsCycleCollectionTraversalCallback*>(aContext);
     352                 : 
     353               0 :     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "mOverlayLoadObservers/mPendingOverlayLoadNotifications value");
     354               0 :     cb->NoteXPCOMChild(aData);
     355                 : 
     356               0 :     return PL_DHASH_NEXT;
     357                 : }
     358                 : 
     359               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXULDocument, nsXMLDocument)
     360               0 :     NS_ASSERTION(!nsCCUncollectableMarker::InGeneration(cb, tmp->GetMarkedCCGeneration()),
     361                 :                  "Shouldn't traverse nsXULDocument!");
     362                 :     // XXX tmp->mForwardReferences?
     363                 :     // XXX tmp->mContextStack?
     364                 : 
     365                 :     // An element will only have a template builder as long as it's in the
     366                 :     // document, so we'll traverse the table here instead of from the element.
     367               0 :     if (tmp->mTemplateBuilderTable)
     368               0 :         tmp->mTemplateBuilderTable->EnumerateRead(TraverseTemplateBuilders, &cb);
     369                 :         
     370               0 :     NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mCurrentPrototype,
     371                 :                                                      nsIScriptGlobalObjectOwner)
     372               0 :     NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mMasterPrototype,
     373                 :                                                      nsIScriptGlobalObjectOwner)
     374               0 :     NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mCommandDispatcher,
     375                 :                                                      nsIDOMXULCommandDispatcher)
     376                 : 
     377               0 :     PRUint32 i, count = tmp->mPrototypes.Length();
     378               0 :     for (i = 0; i < count; ++i) {
     379               0 :         NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mPrototypes[i]");
     380               0 :         cb.NoteXPCOMChild(static_cast<nsIScriptGlobalObjectOwner*>(tmp->mPrototypes[i]));
     381                 :     }
     382                 : 
     383               0 :     NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mLocalStore)
     384                 : 
     385               0 :     if (tmp->mOverlayLoadObservers.IsInitialized())
     386               0 :         tmp->mOverlayLoadObservers.EnumerateRead(TraverseObservers, &cb);
     387               0 :     if (tmp->mPendingOverlayLoadNotifications.IsInitialized())
     388               0 :         tmp->mPendingOverlayLoadNotifications.EnumerateRead(TraverseObservers, &cb);
     389               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     390                 : 
     391               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsXULDocument, nsXMLDocument)
     392               0 :     delete tmp->mTemplateBuilderTable;
     393               0 :     tmp->mTemplateBuilderTable = nsnull;
     394                 : 
     395               0 :     NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mCommandDispatcher)
     396                 :     //XXX We should probably unlink all the objects we traverse.
     397               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     398                 : 
     399               0 : NS_IMPL_ADDREF_INHERITED(nsXULDocument, nsXMLDocument)
     400               0 : NS_IMPL_RELEASE_INHERITED(nsXULDocument, nsXMLDocument)
     401                 : 
     402                 : 
     403               0 : DOMCI_NODE_DATA(XULDocument, nsXULDocument)
     404                 : 
     405                 : // QueryInterface implementation for nsXULDocument
     406               0 : NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(nsXULDocument)
     407                 :     NS_DOCUMENT_INTERFACE_TABLE_BEGIN(nsXULDocument)
     408                 :       NS_INTERFACE_TABLE_ENTRY(nsXULDocument, nsIXULDocument)
     409                 :       NS_INTERFACE_TABLE_ENTRY(nsXULDocument, nsIDOMXULDocument)
     410                 :       NS_INTERFACE_TABLE_ENTRY(nsXULDocument, nsIStreamLoaderObserver)
     411                 :       NS_INTERFACE_TABLE_ENTRY(nsXULDocument, nsICSSLoaderObserver)
     412               0 :     NS_OFFSET_AND_INTERFACE_TABLE_END
     413               0 :     NS_OFFSET_AND_INTERFACE_TABLE_TO_MAP_SEGUE
     414               0 :     NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(XULDocument)
     415               0 : NS_INTERFACE_MAP_END_INHERITING(nsXMLDocument)
     416                 : 
     417                 : 
     418                 : //----------------------------------------------------------------------
     419                 : //
     420                 : // nsIDocument interface
     421                 : //
     422                 : 
     423                 : void
     424               0 : nsXULDocument::Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup)
     425                 : {
     426               0 :     NS_NOTREACHED("Reset");
     427               0 : }
     428                 : 
     429                 : void
     430               0 : nsXULDocument::ResetToURI(nsIURI* aURI, nsILoadGroup* aLoadGroup,
     431                 :                           nsIPrincipal* aPrincipal)
     432                 : {
     433               0 :     NS_NOTREACHED("ResetToURI");
     434               0 : }
     435                 : 
     436                 : // Override the nsDocument.cpp method to keep from returning the
     437                 : // "cached XUL" type which is completely internal and may confuse
     438                 : // people
     439                 : NS_IMETHODIMP
     440               0 : nsXULDocument::GetContentType(nsAString& aContentType)
     441                 : {
     442               0 :     aContentType.AssignLiteral("application/vnd.mozilla.xul+xml");
     443               0 :     return NS_OK;
     444                 : }
     445                 : 
     446                 : void
     447               0 : nsXULDocument::SetContentType(const nsAString& aContentType)
     448                 : {
     449               0 :     NS_ASSERTION(aContentType.EqualsLiteral("application/vnd.mozilla.xul+xml"),
     450                 :                  "xul-documents always has content-type application/vnd.mozilla.xul+xml");
     451                 :     // Don't do anything, xul always has the mimetype
     452                 :     // application/vnd.mozilla.xul+xml
     453               0 : }
     454                 : 
     455                 : // This is called when the master document begins loading, whether it's
     456                 : // being cached or not.
     457                 : nsresult
     458               0 : nsXULDocument::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel,
     459                 :                                  nsILoadGroup* aLoadGroup,
     460                 :                                  nsISupports* aContainer,
     461                 :                                  nsIStreamListener **aDocListener,
     462                 :                                  bool aReset, nsIContentSink* aSink)
     463                 : {
     464                 :     // NOTE: If this ever starts calling nsDocument::StartDocumentLoad
     465                 :     // we'll possibly need to reset our content type afterwards.
     466               0 :     mStillWalking = true;
     467               0 :     mMayStartLayout = false;
     468               0 :     mDocumentLoadGroup = do_GetWeakReference(aLoadGroup);
     469                 : 
     470               0 :     mChannel = aChannel;
     471                 : 
     472               0 :     mHaveInputEncoding = true;
     473                 : 
     474                 :     // Get the URI.  Note that this should match nsDocShell::OnLoadingSite
     475                 :     nsresult rv =
     476               0 :         NS_GetFinalChannelURI(aChannel, getter_AddRefs(mDocumentURI));
     477               0 :     NS_ENSURE_SUCCESS(rv, rv);
     478                 :     
     479               0 :     rv = ResetStylesheetsToURI(mDocumentURI);
     480               0 :     if (NS_FAILED(rv)) return rv;
     481                 : 
     482               0 :     RetrieveRelevantHeaders(aChannel);
     483                 : 
     484                 :     // Look in the chrome cache: we've got this puppy loaded
     485                 :     // already.
     486               0 :     nsXULPrototypeDocument* proto = IsChromeURI(mDocumentURI) ?
     487               0 :             nsXULPrototypeCache::GetInstance()->GetPrototype(mDocumentURI) :
     488               0 :             nsnull;
     489                 : 
     490                 :     // Same comment as nsChromeProtocolHandler::NewChannel and
     491                 :     // nsXULDocument::ResumeWalk
     492                 :     // - Ben Goodger
     493                 :     //
     494                 :     // We don't abort on failure here because there are too many valid
     495                 :     // cases that can return failure, and the null-ness of |proto| is enough
     496                 :     // to trigger the fail-safe parse-from-disk solution. Example failure cases
     497                 :     // (for reference) include:
     498                 :     //
     499                 :     // NS_ERROR_NOT_AVAILABLE: the URI cannot be found in the startup cache,
     500                 :     //                         parse from disk
     501                 :     // other: the startup cache file could not be found, probably
     502                 :     //        due to being accessed before a profile has been selected (e.g.
     503                 :     //        loading chrome for the profile manager itself). This must be
     504                 :     //        parsed from disk.
     505                 : 
     506               0 :     if (proto) {
     507                 :         // If we're racing with another document to load proto, wait till the
     508                 :         // load has finished loading before trying to add cloned style sheets.
     509                 :         // nsXULDocument::EndLoad will call proto->NotifyLoadDone, which will
     510                 :         // find all racing documents and notify them via OnPrototypeLoadDone,
     511                 :         // which will add style sheet clones to each document.
     512                 :         bool loaded;
     513               0 :         rv = proto->AwaitLoadDone(this, &loaded);
     514               0 :         if (NS_FAILED(rv)) return rv;
     515                 : 
     516               0 :         mMasterPrototype = mCurrentPrototype = proto;
     517                 : 
     518                 :         // Set up the right principal on ourselves.
     519               0 :         SetPrincipal(proto->DocumentPrincipal());
     520                 : 
     521                 :         // We need a listener, even if proto is not yet loaded, in which
     522                 :         // event the listener's OnStopRequest method does nothing, and all
     523                 :         // the interesting work happens below nsXULDocument::EndLoad, from
     524                 :         // the call there to mCurrentPrototype->NotifyLoadDone().
     525               0 :         *aDocListener = new CachedChromeStreamListener(this, loaded);
     526               0 :         if (! *aDocListener)
     527               0 :             return NS_ERROR_OUT_OF_MEMORY;
     528                 :     }
     529                 :     else {
     530               0 :         bool useXULCache = nsXULPrototypeCache::GetInstance()->IsEnabled();
     531               0 :         bool fillXULCache = (useXULCache && IsChromeURI(mDocumentURI));
     532                 : 
     533                 : 
     534                 :         // It's just a vanilla document load. Create a parser to deal
     535                 :         // with the stream n' stuff.
     536                 : 
     537               0 :         nsCOMPtr<nsIParser> parser;
     538                 :         rv = PrepareToLoad(aContainer, aCommand, aChannel, aLoadGroup,
     539               0 :                            getter_AddRefs(parser));
     540               0 :         if (NS_FAILED(rv)) return rv;
     541                 : 
     542                 :         // Predicate mIsWritingFastLoad on the XUL cache being enabled,
     543                 :         // so we don't have to re-check whether the cache is enabled all
     544                 :         // the time.
     545               0 :         mIsWritingFastLoad = useXULCache;
     546                 : 
     547               0 :         nsCOMPtr<nsIStreamListener> listener = do_QueryInterface(parser, &rv);
     548               0 :         NS_ASSERTION(NS_SUCCEEDED(rv), "parser doesn't support nsIStreamListener");
     549               0 :         if (NS_FAILED(rv)) return rv;
     550                 : 
     551               0 :         *aDocListener = listener;
     552                 : 
     553               0 :         parser->Parse(mDocumentURI);
     554                 : 
     555                 :         // Put the current prototype, created under PrepareToLoad, into the
     556                 :         // XUL prototype cache now.  We can't do this under PrepareToLoad or
     557                 :         // overlay loading will break; search for PutPrototype in ResumeWalk
     558                 :         // and see the comment there.
     559               0 :         if (fillXULCache) {
     560               0 :             nsXULPrototypeCache::GetInstance()->PutPrototype(mCurrentPrototype);
     561                 :         }
     562                 :     }
     563                 : 
     564               0 :     NS_IF_ADDREF(*aDocListener);
     565               0 :     return NS_OK;
     566                 : }
     567                 : 
     568                 : // This gets invoked after a prototype for this document or one of
     569                 : // its overlays is fully built in the content sink.
     570                 : void
     571               0 : nsXULDocument::EndLoad()
     572                 : {
     573                 :     // This can happen if an overlay fails to load
     574               0 :     if (!mCurrentPrototype)
     575               0 :         return;
     576                 : 
     577                 :     nsresult rv;
     578                 : 
     579                 :     // Whack the prototype document into the cache so that the next
     580                 :     // time somebody asks for it, they don't need to load it by hand.
     581                 : 
     582               0 :     nsCOMPtr<nsIURI> uri = mCurrentPrototype->GetURI();
     583               0 :     bool isChrome = IsChromeURI(uri);
     584                 : 
     585                 :     // Remember if the XUL cache is on
     586               0 :     bool useXULCache = nsXULPrototypeCache::GetInstance()->IsEnabled();
     587                 : 
     588                 :     // If the current prototype is an overlay document (non-master prototype)
     589                 :     // and we're filling the FastLoad disk cache, tell the cache we're done
     590                 :     // loading it, and write the prototype. The master prototype is put into
     591                 :     // the cache earlier in nsXULDocument::StartDocumentLoad.
     592               0 :     if (useXULCache && mIsWritingFastLoad && isChrome &&
     593               0 :         mMasterPrototype != mCurrentPrototype) {
     594               0 :         nsXULPrototypeCache::GetInstance()->WritePrototype(mCurrentPrototype);
     595                 :     }
     596                 : 
     597               0 :     if (IsOverlayAllowed(uri)) {
     598                 :         nsCOMPtr<nsIXULOverlayProvider> reg =
     599               0 :             mozilla::services::GetXULOverlayProviderService();
     600                 : 
     601               0 :         if (reg) {
     602               0 :             nsCOMPtr<nsISimpleEnumerator> overlays;
     603               0 :             rv = reg->GetStyleOverlays(uri, getter_AddRefs(overlays));
     604               0 :             if (NS_FAILED(rv)) return;
     605                 : 
     606                 :             bool moreSheets;
     607               0 :             nsCOMPtr<nsISupports> next;
     608               0 :             nsCOMPtr<nsIURI> sheetURI;
     609                 : 
     610               0 :             while (NS_SUCCEEDED(rv = overlays->HasMoreElements(&moreSheets)) &&
     611                 :                    moreSheets) {
     612               0 :                 overlays->GetNext(getter_AddRefs(next));
     613                 : 
     614               0 :                 sheetURI = do_QueryInterface(next);
     615               0 :                 if (!sheetURI) {
     616               0 :                     NS_ERROR("Chrome registry handed me a non-nsIURI object!");
     617               0 :                     continue;
     618                 :                 }
     619                 : 
     620               0 :                 if (IsChromeURI(sheetURI)) {
     621               0 :                     mCurrentPrototype->AddStyleSheetReference(sheetURI);
     622                 :                 }
     623                 :             }
     624                 :         }
     625                 : 
     626               0 :         if (isChrome && useXULCache) {
     627                 :             // If it's a chrome prototype document, then notify any
     628                 :             // documents that raced to load the prototype, and awaited
     629                 :             // its load completion via proto->AwaitLoadDone().
     630               0 :             rv = mCurrentPrototype->NotifyLoadDone();
     631               0 :             if (NS_FAILED(rv)) return;
     632                 :         }
     633                 :     }
     634                 : 
     635               0 :     OnPrototypeLoadDone(true);
     636                 : }
     637                 : 
     638                 : NS_IMETHODIMP
     639               0 : nsXULDocument::OnPrototypeLoadDone(bool aResumeWalk)
     640                 : {
     641                 :     nsresult rv;
     642                 : 
     643                 :     // Add the style overlays from chrome registry, if any.
     644               0 :     rv = AddPrototypeSheets();
     645               0 :     if (NS_FAILED(rv)) return rv;
     646                 : 
     647               0 :     rv = PrepareToWalk();
     648               0 :     NS_ASSERTION(NS_SUCCEEDED(rv), "unable to prepare for walk");
     649               0 :     if (NS_FAILED(rv)) return rv;
     650                 : 
     651               0 :     if (aResumeWalk) {
     652               0 :         rv = ResumeWalk();
     653                 :     }
     654               0 :     return rv;
     655                 : }
     656                 : 
     657                 : // called when an error occurs parsing a document
     658                 : bool
     659               0 : nsXULDocument::OnDocumentParserError()
     660                 : {
     661                 :   // don't report errors that are from overlays
     662               0 :   if (mCurrentPrototype && mMasterPrototype != mCurrentPrototype) {
     663               0 :     nsCOMPtr<nsIURI> uri = mCurrentPrototype->GetURI();
     664               0 :     if (IsChromeURI(uri)) {
     665                 :       nsCOMPtr<nsIObserverService> os =
     666               0 :         mozilla::services::GetObserverService();
     667               0 :       if (os)
     668               0 :         os->NotifyObservers(uri, "xul-overlay-parsererror",
     669               0 :                             EmptyString().get());
     670                 :     }
     671                 : 
     672               0 :     return false;
     673                 :   }
     674                 : 
     675               0 :   return true;
     676                 : }
     677                 : 
     678                 : static void
     679               0 : ClearBroadcasterMapEntry(PLDHashTable* aTable, PLDHashEntryHdr* aEntry)
     680                 : {
     681                 :     BroadcasterMapEntry* entry =
     682               0 :         static_cast<BroadcasterMapEntry*>(aEntry);
     683               0 :     for (PRInt32 i = entry->mListeners.Count() - 1; i >= 0; --i) {
     684               0 :         delete (BroadcastListener*)entry->mListeners[i];
     685                 :     }
     686                 : 
     687                 :     // N.B. that we need to manually run the dtor because we
     688                 :     // constructed the nsSmallVoidArray object in-place.
     689               0 :     entry->mListeners.~nsSmallVoidArray();
     690               0 : }
     691                 : 
     692                 : static bool
     693               0 : CanBroadcast(PRInt32 aNameSpaceID, nsIAtom* aAttribute)
     694                 : {
     695                 :     // Don't push changes to the |id|, |ref|, |persist|, |command| or
     696                 :     // |observes| attribute.
     697               0 :     if (aNameSpaceID == kNameSpaceID_None) {
     698               0 :         if ((aAttribute == nsGkAtoms::id) ||
     699                 :             (aAttribute == nsGkAtoms::ref) ||
     700                 :             (aAttribute == nsGkAtoms::persist) ||
     701                 :             (aAttribute == nsGkAtoms::command) ||
     702                 :             (aAttribute == nsGkAtoms::observes)) {
     703               0 :             return false;
     704                 :         }
     705                 :     }
     706               0 :     return true;
     707                 : }
     708                 : 
     709                 : struct nsAttrNameInfo
     710               0 : {
     711               0 :   nsAttrNameInfo(PRInt32 aNamespaceID, nsIAtom* aName, nsIAtom* aPrefix) :
     712               0 :     mNamespaceID(aNamespaceID), mName(aName), mPrefix(aPrefix) {}
     713               0 :   nsAttrNameInfo(const nsAttrNameInfo& aOther) :
     714                 :     mNamespaceID(aOther.mNamespaceID), mName(aOther.mName),
     715               0 :     mPrefix(aOther.mPrefix) {}
     716                 :   PRInt32           mNamespaceID;
     717                 :   nsCOMPtr<nsIAtom> mName;
     718                 :   nsCOMPtr<nsIAtom> mPrefix;
     719                 : };
     720                 : 
     721                 : void
     722               0 : nsXULDocument::SynchronizeBroadcastListener(nsIDOMElement   *aBroadcaster,
     723                 :                                             nsIDOMElement   *aListener,
     724                 :                                             const nsAString &aAttr)
     725                 : {
     726               0 :     if (!nsContentUtils::IsSafeToRunScript()) {
     727                 :         nsDelayedBroadcastUpdate delayedUpdate(aBroadcaster, aListener,
     728               0 :                                                aAttr);
     729               0 :         mDelayedBroadcasters.AppendElement(delayedUpdate);
     730               0 :         MaybeBroadcast();
     731                 :         return;
     732                 :     }
     733               0 :     nsCOMPtr<nsIContent> broadcaster = do_QueryInterface(aBroadcaster);
     734               0 :     nsCOMPtr<nsIContent> listener = do_QueryInterface(aListener);
     735               0 :     bool notify = mDocumentLoaded || mHandlingDelayedBroadcasters;
     736                 : 
     737                 :     // We may be copying event handlers etc, so we must also copy
     738                 :     // the script-type to the listener.
     739               0 :     listener->SetScriptTypeID(broadcaster->GetScriptTypeID());
     740                 : 
     741               0 :     if (aAttr.EqualsLiteral("*")) {
     742               0 :         PRUint32 count = broadcaster->GetAttrCount();
     743               0 :         nsTArray<nsAttrNameInfo> attributes(count);
     744               0 :         for (PRUint32 i = 0; i < count; ++i) {
     745               0 :             const nsAttrName* attrName = broadcaster->GetAttrNameAt(i);
     746               0 :             PRInt32 nameSpaceID = attrName->NamespaceID();
     747               0 :             nsIAtom* name = attrName->LocalName();
     748                 : 
     749                 :             // _Don't_ push the |id|, |ref|, or |persist| attribute's value!
     750               0 :             if (! CanBroadcast(nameSpaceID, name))
     751               0 :                 continue;
     752                 : 
     753                 :             attributes.AppendElement(nsAttrNameInfo(nameSpaceID, name,
     754               0 :                                                     attrName->GetPrefix()));
     755                 :         }
     756                 : 
     757               0 :         count = attributes.Length();
     758               0 :         while (count-- > 0) {
     759               0 :             PRInt32 nameSpaceID = attributes[count].mNamespaceID;
     760               0 :             nsIAtom* name = attributes[count].mName;
     761               0 :             nsAutoString value;
     762               0 :             if (broadcaster->GetAttr(nameSpaceID, name, value)) {
     763               0 :               listener->SetAttr(nameSpaceID, name, attributes[count].mPrefix,
     764               0 :                                 value, notify);
     765                 :             }
     766                 : 
     767                 : #if 0
     768                 :             // XXX we don't fire the |onbroadcast| handler during
     769                 :             // initial hookup: doing so would potentially run the
     770                 :             // |onbroadcast| handler before the |onload| handler,
     771                 :             // which could define JS properties that mask XBL
     772                 :             // properties, etc.
     773                 :             ExecuteOnBroadcastHandlerFor(broadcaster, aListener, name);
     774                 : #endif
     775                 :         }
     776                 :     }
     777                 :     else {
     778                 :         // Find out if the attribute is even present at all.
     779               0 :         nsCOMPtr<nsIAtom> name = do_GetAtom(aAttr);
     780                 : 
     781               0 :         nsAutoString value;
     782               0 :         if (broadcaster->GetAttr(kNameSpaceID_None, name, value)) {
     783               0 :             listener->SetAttr(kNameSpaceID_None, name, value, notify);
     784                 :         } else {
     785               0 :             listener->UnsetAttr(kNameSpaceID_None, name, notify);
     786                 :         }
     787                 : 
     788                 : #if 0
     789                 :         // XXX we don't fire the |onbroadcast| handler during initial
     790                 :         // hookup: doing so would potentially run the |onbroadcast|
     791                 :         // handler before the |onload| handler, which could define JS
     792                 :         // properties that mask XBL properties, etc.
     793                 :         ExecuteOnBroadcastHandlerFor(broadcaster, aListener, name);
     794                 : #endif
     795                 :     }
     796                 : }
     797                 : 
     798                 : NS_IMETHODIMP
     799               0 : nsXULDocument::AddBroadcastListenerFor(nsIDOMElement* aBroadcaster,
     800                 :                                        nsIDOMElement* aListener,
     801                 :                                        const nsAString& aAttr)
     802                 : {
     803               0 :     NS_ENSURE_ARG(aBroadcaster && aListener);
     804                 :     
     805                 :     nsresult rv =
     806               0 :         nsContentUtils::CheckSameOrigin(this, aBroadcaster);
     807                 : 
     808               0 :     if (NS_FAILED(rv)) {
     809               0 :         return rv;
     810                 :     }
     811                 : 
     812               0 :     rv = nsContentUtils::CheckSameOrigin(this, aListener);
     813                 : 
     814               0 :     if (NS_FAILED(rv)) {
     815               0 :         return rv;
     816                 :     }
     817                 : 
     818                 :     static PLDHashTableOps gOps = {
     819                 :         PL_DHashAllocTable,
     820                 :         PL_DHashFreeTable,
     821                 :         PL_DHashVoidPtrKeyStub,
     822                 :         PL_DHashMatchEntryStub,
     823                 :         PL_DHashMoveEntryStub,
     824                 :         ClearBroadcasterMapEntry,
     825                 :         PL_DHashFinalizeStub,
     826                 :         nsnull
     827                 :     };
     828                 : 
     829               0 :     if (! mBroadcasterMap) {
     830                 :         mBroadcasterMap =
     831                 :             PL_NewDHashTable(&gOps, nsnull, sizeof(BroadcasterMapEntry),
     832               0 :                              PL_DHASH_MIN_SIZE);
     833                 : 
     834               0 :         if (! mBroadcasterMap)
     835               0 :             return NS_ERROR_OUT_OF_MEMORY;
     836                 :     }
     837                 : 
     838                 :     BroadcasterMapEntry* entry =
     839                 :         static_cast<BroadcasterMapEntry*>
     840                 :                    (PL_DHashTableOperate(mBroadcasterMap, aBroadcaster,
     841               0 :                                             PL_DHASH_LOOKUP));
     842                 : 
     843               0 :     if (PL_DHASH_ENTRY_IS_FREE(entry)) {
     844                 :         entry =
     845                 :             static_cast<BroadcasterMapEntry*>
     846                 :                        (PL_DHashTableOperate(mBroadcasterMap, aBroadcaster,
     847               0 :                                                 PL_DHASH_ADD));
     848                 : 
     849               0 :         if (! entry)
     850               0 :             return NS_ERROR_OUT_OF_MEMORY;
     851                 : 
     852               0 :         entry->mBroadcaster = aBroadcaster;
     853                 : 
     854                 :         // N.B. placement new to construct the nsSmallVoidArray object
     855                 :         // in-place
     856               0 :         new (&entry->mListeners) nsSmallVoidArray();
     857                 :     }
     858                 : 
     859                 :     // Only add the listener if it's not there already!
     860               0 :     nsCOMPtr<nsIAtom> attr = do_GetAtom(aAttr);
     861                 : 
     862                 :     BroadcastListener* bl;
     863               0 :     for (PRInt32 i = entry->mListeners.Count() - 1; i >= 0; --i) {
     864               0 :         bl = static_cast<BroadcastListener*>(entry->mListeners[i]);
     865                 : 
     866               0 :         nsCOMPtr<nsIDOMElement> blListener = do_QueryReferent(bl->mListener);
     867                 : 
     868               0 :         if ((blListener == aListener) && (bl->mAttribute == attr))
     869               0 :             return NS_OK;
     870                 :     }
     871                 : 
     872               0 :     bl = new BroadcastListener;
     873               0 :     if (! bl)
     874               0 :         return NS_ERROR_OUT_OF_MEMORY;
     875                 : 
     876               0 :     bl->mListener  = do_GetWeakReference(aListener);
     877               0 :     bl->mAttribute = attr;
     878                 : 
     879               0 :     entry->mListeners.AppendElement(bl);
     880                 : 
     881               0 :     SynchronizeBroadcastListener(aBroadcaster, aListener, aAttr);
     882               0 :     return NS_OK;
     883                 : }
     884                 : 
     885                 : NS_IMETHODIMP
     886               0 : nsXULDocument::RemoveBroadcastListenerFor(nsIDOMElement* aBroadcaster,
     887                 :                                           nsIDOMElement* aListener,
     888                 :                                           const nsAString& aAttr)
     889                 : {
     890                 :     // If we haven't added any broadcast listeners, then there sure
     891                 :     // aren't any to remove.
     892               0 :     if (! mBroadcasterMap)
     893               0 :         return NS_OK;
     894                 : 
     895                 :     BroadcasterMapEntry* entry =
     896                 :         static_cast<BroadcasterMapEntry*>
     897                 :                    (PL_DHashTableOperate(mBroadcasterMap, aBroadcaster,
     898               0 :                                             PL_DHASH_LOOKUP));
     899                 : 
     900               0 :     if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
     901               0 :         nsCOMPtr<nsIAtom> attr = do_GetAtom(aAttr);
     902               0 :         for (PRInt32 i = entry->mListeners.Count() - 1; i >= 0; --i) {
     903                 :             BroadcastListener* bl =
     904               0 :                 static_cast<BroadcastListener*>(entry->mListeners[i]);
     905                 : 
     906               0 :             nsCOMPtr<nsIDOMElement> blListener = do_QueryReferent(bl->mListener);
     907                 : 
     908               0 :             if ((blListener == aListener) && (bl->mAttribute == attr)) {
     909               0 :                 entry->mListeners.RemoveElementAt(i);
     910               0 :                 delete bl;
     911                 : 
     912               0 :                 if (entry->mListeners.Count() == 0)
     913                 :                     PL_DHashTableOperate(mBroadcasterMap, aBroadcaster,
     914               0 :                                          PL_DHASH_REMOVE);
     915                 : 
     916                 :                 break;
     917                 :             }
     918                 :         }
     919                 :     }
     920                 : 
     921               0 :     return NS_OK;
     922                 : }
     923                 : 
     924                 : nsresult
     925               0 : nsXULDocument::ExecuteOnBroadcastHandlerFor(nsIContent* aBroadcaster,
     926                 :                                             nsIDOMElement* aListener,
     927                 :                                             nsIAtom* aAttr)
     928                 : {
     929                 :     // Now we execute the onchange handler in the context of the
     930                 :     // observer. We need to find the observer in order to
     931                 :     // execute the handler.
     932                 : 
     933               0 :     nsCOMPtr<nsIContent> listener = do_QueryInterface(aListener);
     934               0 :     for (nsIContent* child = listener->GetFirstChild();
     935                 :          child;
     936               0 :          child = child->GetNextSibling()) {
     937                 : 
     938                 :         // Look for an <observes> element beneath the listener. This
     939                 :         // ought to have an |element| attribute that refers to
     940                 :         // aBroadcaster, and an |attribute| element that tells us what
     941                 :         // attriubtes we're listening for.
     942               0 :         if (!child->NodeInfo()->Equals(nsGkAtoms::observes, kNameSpaceID_XUL))
     943               0 :             continue;
     944                 : 
     945                 :         // Is this the element that was listening to us?
     946               0 :         nsAutoString listeningToID;
     947               0 :         child->GetAttr(kNameSpaceID_None, nsGkAtoms::element, listeningToID);
     948                 : 
     949               0 :         nsAutoString broadcasterID;
     950               0 :         aBroadcaster->GetAttr(kNameSpaceID_None, nsGkAtoms::id, broadcasterID);
     951                 : 
     952               0 :         if (listeningToID != broadcasterID)
     953               0 :             continue;
     954                 : 
     955                 :         // We are observing the broadcaster, but is this the right
     956                 :         // attribute?
     957               0 :         nsAutoString listeningToAttribute;
     958                 :         child->GetAttr(kNameSpaceID_None, nsGkAtoms::attribute,
     959               0 :                        listeningToAttribute);
     960                 : 
     961               0 :         if (!aAttr->Equals(listeningToAttribute) &&
     962               0 :             !listeningToAttribute.EqualsLiteral("*")) {
     963               0 :             continue;
     964                 :         }
     965                 : 
     966                 :         // This is the right <observes> element. Execute the
     967                 :         // |onbroadcast| event handler
     968               0 :         nsEvent event(true, NS_XUL_BROADCAST);
     969                 : 
     970               0 :         nsCOMPtr<nsIPresShell> shell = GetShell();
     971               0 :         if (shell) {
     972               0 :             nsRefPtr<nsPresContext> aPresContext = shell->GetPresContext();
     973                 : 
     974                 :             // Handle the DOM event
     975               0 :             nsEventStatus status = nsEventStatus_eIgnore;
     976                 :             nsEventDispatcher::Dispatch(child, aPresContext, &event, nsnull,
     977               0 :                                         &status);
     978                 :         }
     979                 :     }
     980                 : 
     981               0 :     return NS_OK;
     982                 : }
     983                 : 
     984                 : void
     985               0 : nsXULDocument::AttributeWillChange(nsIDocument* aDocument,
     986                 :                                    Element* aElement, PRInt32 aNameSpaceID,
     987                 :                                    nsIAtom* aAttribute, PRInt32 aModType)
     988                 : {
     989               0 :     NS_ABORT_IF_FALSE(aElement, "Null content!");
     990               0 :     NS_PRECONDITION(aAttribute, "Must have an attribute that's changing!");
     991                 : 
     992                 :     // XXXbz check aNameSpaceID, dammit!
     993                 :     // See if we need to update our ref map.
     994               0 :     if (aAttribute == nsGkAtoms::ref ||
     995               0 :         (aAttribute == nsGkAtoms::id && !aElement->GetIDAttributeName())) {
     996                 :         // Might not need this, but be safe for now.
     997               0 :         nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
     998               0 :         RemoveElementFromRefMap(aElement);
     999                 :     }
    1000               0 : }
    1001                 : 
    1002                 : void
    1003               0 : nsXULDocument::AttributeChanged(nsIDocument* aDocument,
    1004                 :                                 Element* aElement, PRInt32 aNameSpaceID,
    1005                 :                                 nsIAtom* aAttribute, PRInt32 aModType)
    1006                 : {
    1007               0 :     NS_ASSERTION(aDocument == this, "unexpected doc");
    1008                 : 
    1009                 :     // Might not need this, but be safe for now.
    1010               0 :     nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
    1011                 : 
    1012                 :     // XXXbz check aNameSpaceID, dammit!
    1013                 :     // See if we need to update our ref map.
    1014               0 :     if (aAttribute == nsGkAtoms::ref ||
    1015               0 :         (aAttribute == nsGkAtoms::id && !aElement->GetIDAttributeName())) {
    1016               0 :         AddElementToRefMap(aElement);
    1017                 :     }
    1018                 :     
    1019                 :     nsresult rv;
    1020                 : 
    1021                 :     // Synchronize broadcast listeners
    1022               0 :     nsCOMPtr<nsIDOMElement> domele = do_QueryInterface(aElement);
    1023               0 :     if (domele && mBroadcasterMap &&
    1024               0 :         CanBroadcast(aNameSpaceID, aAttribute)) {
    1025                 :         BroadcasterMapEntry* entry =
    1026                 :             static_cast<BroadcasterMapEntry*>
    1027               0 :                        (PL_DHashTableOperate(mBroadcasterMap, domele.get(),
    1028               0 :                                                 PL_DHASH_LOOKUP));
    1029                 : 
    1030               0 :         if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
    1031                 :             // We've got listeners: push the value.
    1032               0 :             nsAutoString value;
    1033               0 :             bool attrSet = aElement->GetAttr(kNameSpaceID_None, aAttribute, value);
    1034                 : 
    1035                 :             PRInt32 i;
    1036               0 :             for (i = entry->mListeners.Count() - 1; i >= 0; --i) {
    1037                 :                 BroadcastListener* bl =
    1038               0 :                     static_cast<BroadcastListener*>(entry->mListeners[i]);
    1039                 : 
    1040               0 :                 if ((bl->mAttribute == aAttribute) ||
    1041               0 :                     (bl->mAttribute == nsGkAtoms::_asterix)) {
    1042                 :                     nsCOMPtr<nsIDOMElement> listenerEl
    1043               0 :                         = do_QueryReferent(bl->mListener);
    1044               0 :                     nsCOMPtr<nsIContent> l = do_QueryInterface(listenerEl);
    1045               0 :                     if (l) {
    1046               0 :                         nsAutoString currentValue;
    1047               0 :                         bool hasAttr = l->GetAttr(kNameSpaceID_None,
    1048                 :                                                     aAttribute,
    1049               0 :                                                     currentValue);
    1050                 :                         // We need to update listener only if we're
    1051                 :                         // (1) removing an existing attribute,
    1052                 :                         // (2) adding a new attribute or
    1053                 :                         // (3) changing the value of an attribute.
    1054                 :                         bool needsAttrChange =
    1055               0 :                             attrSet != hasAttr || !value.Equals(currentValue);
    1056                 :                         nsDelayedBroadcastUpdate delayedUpdate(domele,
    1057                 :                                                                listenerEl,
    1058                 :                                                                aAttribute,
    1059                 :                                                                value,
    1060                 :                                                                attrSet,
    1061               0 :                                                                needsAttrChange);
    1062                 : 
    1063                 :                         PRUint32 index =
    1064                 :                             mDelayedAttrChangeBroadcasts.IndexOf(delayedUpdate,
    1065               0 :                                 0, nsDelayedBroadcastUpdate::Comparator());
    1066               0 :                         if (index != mDelayedAttrChangeBroadcasts.NoIndex) {
    1067               0 :                             if (mHandlingDelayedAttrChange) {
    1068               0 :                                 NS_WARNING("Broadcasting loop!");
    1069               0 :                                 continue;
    1070                 :                             }
    1071               0 :                             mDelayedAttrChangeBroadcasts.RemoveElementAt(index);
    1072                 :                         }
    1073                 : 
    1074               0 :                         mDelayedAttrChangeBroadcasts.AppendElement(delayedUpdate);
    1075                 :                     }
    1076                 :                 }
    1077                 :             }
    1078                 :         }
    1079                 :     }
    1080                 : 
    1081                 :     // checks for modifications in broadcasters
    1082                 :     bool listener, resolved;
    1083               0 :     CheckBroadcasterHookup(aElement, &listener, &resolved);
    1084                 : 
    1085                 :     // See if there is anything we need to persist in the localstore.
    1086                 :     //
    1087                 :     // XXX Namespace handling broken :-(
    1088               0 :     nsAutoString persist;
    1089               0 :     aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::persist, persist);
    1090               0 :     if (!persist.IsEmpty()) {
    1091                 :         // XXXldb This should check that it's a token, not just a substring.
    1092               0 :         if (persist.Find(nsDependentAtomString(aAttribute)) >= 0) {
    1093               0 :             rv = Persist(aElement, kNameSpaceID_None, aAttribute);
    1094               0 :             if (NS_FAILED(rv)) return;
    1095                 :         }
    1096                 :     }
    1097                 : }
    1098                 : 
    1099                 : void
    1100               0 : nsXULDocument::ContentAppended(nsIDocument* aDocument,
    1101                 :                                nsIContent* aContainer,
    1102                 :                                nsIContent* aFirstNewContent,
    1103                 :                                PRInt32 aNewIndexInContainer)
    1104                 : {
    1105               0 :     NS_ASSERTION(aDocument == this, "unexpected doc");
    1106                 :     
    1107                 :     // Might not need this, but be safe for now.
    1108               0 :     nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
    1109                 : 
    1110                 :     // Update our element map
    1111               0 :     nsresult rv = NS_OK;
    1112               0 :     for (nsIContent* cur = aFirstNewContent; cur && NS_SUCCEEDED(rv);
    1113               0 :          cur = cur->GetNextSibling()) {
    1114               0 :         rv = AddSubtreeToDocument(cur);
    1115                 :     }
    1116               0 : }
    1117                 : 
    1118                 : void
    1119               0 : nsXULDocument::ContentInserted(nsIDocument* aDocument,
    1120                 :                                nsIContent* aContainer,
    1121                 :                                nsIContent* aChild,
    1122                 :                                PRInt32 aIndexInContainer)
    1123                 : {
    1124               0 :     NS_ASSERTION(aDocument == this, "unexpected doc");
    1125                 : 
    1126                 :     // Might not need this, but be safe for now.
    1127               0 :     nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
    1128                 : 
    1129               0 :     AddSubtreeToDocument(aChild);
    1130               0 : }
    1131                 : 
    1132                 : void
    1133               0 : nsXULDocument::ContentRemoved(nsIDocument* aDocument,
    1134                 :                               nsIContent* aContainer,
    1135                 :                               nsIContent* aChild,
    1136                 :                               PRInt32 aIndexInContainer,
    1137                 :                               nsIContent* aPreviousSibling)
    1138                 : {
    1139               0 :     NS_ASSERTION(aDocument == this, "unexpected doc");
    1140                 : 
    1141                 :     // Might not need this, but be safe for now.
    1142               0 :     nsCOMPtr<nsIMutationObserver> kungFuDeathGrip(this);
    1143                 : 
    1144               0 :     RemoveSubtreeFromDocument(aChild);
    1145               0 : }
    1146                 : 
    1147                 : //----------------------------------------------------------------------
    1148                 : //
    1149                 : // nsIXULDocument interface
    1150                 : //
    1151                 : 
    1152                 : void
    1153               0 : nsXULDocument::GetElementsForID(const nsAString& aID,
    1154                 :                                 nsCOMArray<nsIContent>& aElements)
    1155                 : {
    1156               0 :     aElements.Clear();
    1157                 : 
    1158               0 :     nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(aID);
    1159               0 :     if (entry) {
    1160               0 :         entry->AppendAllIdContent(&aElements);
    1161                 :     }
    1162               0 :     nsRefMapEntry *refEntry = mRefMap.GetEntry(aID);
    1163               0 :     if (refEntry) {
    1164               0 :         refEntry->AppendAll(&aElements);
    1165                 :     }
    1166               0 : }
    1167                 : 
    1168                 : nsresult
    1169               0 : nsXULDocument::AddForwardReference(nsForwardReference* aRef)
    1170                 : {
    1171               0 :     if (mResolutionPhase < aRef->GetPhase()) {
    1172               0 :         if (!mForwardReferences.AppendElement(aRef)) {
    1173               0 :             delete aRef;
    1174               0 :             return NS_ERROR_OUT_OF_MEMORY;
    1175                 :         }
    1176                 :     }
    1177                 :     else {
    1178               0 :         NS_ERROR("forward references have already been resolved");
    1179               0 :         delete aRef;
    1180                 :     }
    1181                 : 
    1182               0 :     return NS_OK;
    1183                 : }
    1184                 : 
    1185                 : nsresult
    1186               0 : nsXULDocument::ResolveForwardReferences()
    1187                 : {
    1188               0 :     if (mResolutionPhase == nsForwardReference::eDone)
    1189               0 :         return NS_OK;
    1190                 : 
    1191               0 :     NS_ASSERTION(mResolutionPhase == nsForwardReference::eStart,
    1192                 :                  "nested ResolveForwardReferences()");
    1193                 :         
    1194                 :     // Resolve each outstanding 'forward' reference. We iterate
    1195                 :     // through the list of forward references until no more forward
    1196                 :     // references can be resolved. This annealing process is
    1197                 :     // guaranteed to converge because we've "closed the gate" to new
    1198                 :     // forward references.
    1199                 : 
    1200               0 :     const nsForwardReference::Phase* pass = nsForwardReference::kPasses;
    1201               0 :     while ((mResolutionPhase = *pass) != nsForwardReference::eDone) {
    1202               0 :         PRUint32 previous = 0;
    1203               0 :         while (mForwardReferences.Length() &&
    1204               0 :                mForwardReferences.Length() != previous) {
    1205               0 :             previous = mForwardReferences.Length();
    1206                 : 
    1207               0 :             for (PRUint32 i = 0; i < mForwardReferences.Length(); ++i) {
    1208               0 :                 nsForwardReference* fwdref = mForwardReferences[i];
    1209                 : 
    1210               0 :                 if (fwdref->GetPhase() == *pass) {
    1211               0 :                     nsForwardReference::Result result = fwdref->Resolve();
    1212                 : 
    1213               0 :                     switch (result) {
    1214                 :                     case nsForwardReference::eResolve_Succeeded:
    1215                 :                     case nsForwardReference::eResolve_Error:
    1216               0 :                         mForwardReferences.RemoveElementAt(i);
    1217                 : 
    1218                 :                         // fixup because we removed from list
    1219               0 :                         --i;
    1220               0 :                         break;
    1221                 : 
    1222                 :                     case nsForwardReference::eResolve_Later:
    1223                 :                         // do nothing. we'll try again later
    1224                 :                         ;
    1225                 :                     }
    1226                 : 
    1227               0 :                     if (mResolutionPhase == nsForwardReference::eStart) {
    1228                 :                         // Resolve() loaded a dynamic overlay,
    1229                 :                         // (see nsXULDocument::LoadOverlayInternal()).
    1230                 :                         // Return for now, we will be called again.
    1231               0 :                         return NS_OK;
    1232                 :                     }
    1233                 :                 }
    1234                 :             }
    1235                 :         }
    1236                 : 
    1237               0 :         ++pass;
    1238                 :     }
    1239                 : 
    1240               0 :     mForwardReferences.Clear();
    1241               0 :     return NS_OK;
    1242                 : }
    1243                 : 
    1244                 : NS_IMETHODIMP
    1245               0 : nsXULDocument::GetScriptGlobalObjectOwner(nsIScriptGlobalObjectOwner** aGlobalOwner)
    1246                 : {
    1247               0 :     NS_IF_ADDREF(*aGlobalOwner = mMasterPrototype);
    1248               0 :     return NS_OK;
    1249                 : }
    1250                 : 
    1251                 : //----------------------------------------------------------------------
    1252                 : //
    1253                 : // nsIDOMDocument interface
    1254                 : //
    1255                 : 
    1256                 : NS_IMETHODIMP
    1257               0 : nsXULDocument::GetElementsByAttribute(const nsAString& aAttribute,
    1258                 :                                       const nsAString& aValue,
    1259                 :                                       nsIDOMNodeList** aReturn)
    1260                 : {
    1261               0 :     nsCOMPtr<nsIAtom> attrAtom(do_GetAtom(aAttribute));
    1262               0 :     NS_ENSURE_TRUE(attrAtom, NS_ERROR_OUT_OF_MEMORY);
    1263               0 :     void* attrValue = new nsString(aValue);
    1264               0 :     NS_ENSURE_TRUE(attrValue, NS_ERROR_OUT_OF_MEMORY);
    1265                 :     nsContentList *list = new nsContentList(this,
    1266                 :                                             MatchAttribute,
    1267                 :                                             nsContentUtils::DestroyMatchString,
    1268                 :                                             attrValue,
    1269                 :                                             true,
    1270                 :                                             attrAtom,
    1271               0 :                                             kNameSpaceID_Unknown);
    1272               0 :     NS_ENSURE_TRUE(list, NS_ERROR_OUT_OF_MEMORY);
    1273                 :     
    1274               0 :     NS_ADDREF(*aReturn = list);
    1275               0 :     return NS_OK;
    1276                 : }
    1277                 : 
    1278                 : NS_IMETHODIMP
    1279               0 : nsXULDocument::GetElementsByAttributeNS(const nsAString& aNamespaceURI,
    1280                 :                                         const nsAString& aAttribute,
    1281                 :                                         const nsAString& aValue,
    1282                 :                                         nsIDOMNodeList** aReturn)
    1283                 : {
    1284               0 :     nsCOMPtr<nsIAtom> attrAtom(do_GetAtom(aAttribute));
    1285               0 :     NS_ENSURE_TRUE(attrAtom, NS_ERROR_OUT_OF_MEMORY);
    1286               0 :     void* attrValue = new nsString(aValue);
    1287               0 :     NS_ENSURE_TRUE(attrValue, NS_ERROR_OUT_OF_MEMORY);
    1288                 : 
    1289               0 :     PRInt32 nameSpaceId = kNameSpaceID_Wildcard;
    1290               0 :     if (!aNamespaceURI.EqualsLiteral("*")) {
    1291                 :       nsresult rv =
    1292               0 :         nsContentUtils::NameSpaceManager()->RegisterNameSpace(aNamespaceURI,
    1293               0 :                                                               nameSpaceId);
    1294               0 :       NS_ENSURE_SUCCESS(rv, rv);
    1295                 :     }
    1296                 : 
    1297                 :     nsContentList *list = new nsContentList(this,
    1298                 :                                             MatchAttribute,
    1299                 :                                             nsContentUtils::DestroyMatchString,
    1300                 :                                             attrValue,
    1301                 :                                             true,
    1302                 :                                             attrAtom,
    1303               0 :                                             nameSpaceId);
    1304               0 :     NS_ENSURE_TRUE(list, NS_ERROR_OUT_OF_MEMORY);
    1305                 : 
    1306               0 :     NS_ADDREF(*aReturn = list);
    1307               0 :     return NS_OK;
    1308                 : }
    1309                 : 
    1310                 : NS_IMETHODIMP
    1311               0 : nsXULDocument::Persist(const nsAString& aID,
    1312                 :                        const nsAString& aAttr)
    1313                 : {
    1314                 :     // If we're currently reading persisted attributes out of the
    1315                 :     // localstore, _don't_ re-enter and try to set them again!
    1316               0 :     if (mApplyingPersistedAttrs)
    1317               0 :         return NS_OK;
    1318                 : 
    1319                 :     nsresult rv;
    1320                 : 
    1321               0 :     nsIContent *element = nsDocument::GetElementById(aID);
    1322               0 :     if (! element)
    1323               0 :         return NS_OK;
    1324                 : 
    1325               0 :     nsCOMPtr<nsIAtom> tag;
    1326                 :     PRInt32 nameSpaceID;
    1327                 : 
    1328               0 :     nsCOMPtr<nsINodeInfo> ni = element->GetExistingAttrNameFromQName(aAttr);
    1329               0 :     if (ni) {
    1330               0 :         tag = ni->NameAtom();
    1331               0 :         nameSpaceID = ni->NamespaceID();
    1332                 :     }
    1333                 :     else {
    1334                 :         // Make sure that this QName is going to be valid.
    1335               0 :         nsIParserService *parserService = nsContentUtils::GetParserService();
    1336               0 :         NS_ASSERTION(parserService, "Running scripts during shutdown?");
    1337                 : 
    1338                 :         const PRUnichar *colon;
    1339               0 :         rv = parserService->CheckQName(PromiseFlatString(aAttr), true, &colon);
    1340               0 :         if (NS_FAILED(rv)) {
    1341                 :             // There was an invalid character or it was malformed.
    1342               0 :             return NS_ERROR_INVALID_ARG;
    1343                 :         }
    1344                 : 
    1345               0 :         if (colon) {
    1346                 :             // We don't really handle namespace qualifiers in attribute names.
    1347               0 :             return NS_ERROR_NOT_IMPLEMENTED;
    1348                 :         }
    1349                 : 
    1350               0 :         tag = do_GetAtom(aAttr);
    1351               0 :         NS_ENSURE_TRUE(tag, NS_ERROR_OUT_OF_MEMORY);
    1352                 : 
    1353               0 :         nameSpaceID = kNameSpaceID_None;
    1354                 :     }
    1355                 : 
    1356               0 :     rv = Persist(element, nameSpaceID, tag);
    1357               0 :     if (NS_FAILED(rv)) return rv;
    1358                 : 
    1359               0 :     return NS_OK;
    1360                 : }
    1361                 : 
    1362                 : 
    1363                 : bool
    1364               0 : nsXULDocument::IsCapabilityEnabled(const char* aCapabilityLabel)
    1365                 : {
    1366                 :     nsresult rv;
    1367                 : 
    1368                 :     // NodePrincipal is guarantied to be non-null
    1369               0 :     bool enabled = false;
    1370               0 :     rv = NodePrincipal()->IsCapabilityEnabled(aCapabilityLabel, nsnull, &enabled);
    1371               0 :     if (NS_FAILED(rv))
    1372               0 :         return false;
    1373                 :  
    1374               0 :     return enabled;
    1375                 : }
    1376                 : 
    1377                 : 
    1378                 : nsresult
    1379               0 : nsXULDocument::Persist(nsIContent* aElement, PRInt32 aNameSpaceID,
    1380                 :                        nsIAtom* aAttribute)
    1381                 : {
    1382                 :     // For non-chrome documents, persistance is simply broken
    1383               0 :     if (!IsCapabilityEnabled("UniversalXPConnect"))
    1384               0 :         return NS_ERROR_NOT_AVAILABLE;
    1385                 : 
    1386                 :     // First make sure we _have_ a local store to stuff the persisted
    1387                 :     // information into. (We might not have one if profile information
    1388                 :     // hasn't been loaded yet...)
    1389               0 :     if (!mLocalStore)
    1390               0 :         return NS_OK;
    1391                 : 
    1392                 :     nsresult rv;
    1393                 : 
    1394               0 :     nsCOMPtr<nsIRDFResource> element;
    1395               0 :     rv = nsXULContentUtils::GetElementResource(aElement, getter_AddRefs(element));
    1396               0 :     if (NS_FAILED(rv)) return rv;
    1397                 : 
    1398                 :     // No ID, so nothing to persist.
    1399               0 :     if (! element)
    1400               0 :         return NS_OK;
    1401                 : 
    1402                 :     // Ick. Construct a property from the attribute. Punt on
    1403                 :     // namespaces for now.
    1404                 :     // Don't bother with unreasonable attributes. We clamp long values,
    1405                 :     // but truncating attribute names turns it into a different attribute
    1406                 :     // so there's no point in persisting anything at all
    1407               0 :     nsAtomCString attrstr(aAttribute);
    1408               0 :     if (attrstr.Length() > kMaxAttrNameLength) {
    1409               0 :         NS_WARNING("Can't persist, Attribute name too long");
    1410               0 :         return NS_ERROR_ILLEGAL_VALUE;
    1411                 :     }
    1412                 : 
    1413               0 :     nsCOMPtr<nsIRDFResource> attr;
    1414                 :     rv = gRDFService->GetResource(attrstr,
    1415               0 :                                   getter_AddRefs(attr));
    1416               0 :     if (NS_FAILED(rv)) return rv;
    1417                 : 
    1418                 :     // Turn the value into a literal
    1419               0 :     nsAutoString valuestr;
    1420               0 :     aElement->GetAttr(kNameSpaceID_None, aAttribute, valuestr);
    1421                 : 
    1422                 :     // prevent over-long attributes that choke the parser (bug 319846)
    1423                 :     // (can't simply Truncate without testing, it's implemented
    1424                 :     // using SetLength and will grow a short string)
    1425               0 :     if (valuestr.Length() > kMaxAttributeLength) {
    1426               0 :         NS_WARNING("Truncating persisted attribute value");
    1427               0 :         valuestr.Truncate(kMaxAttributeLength);
    1428                 :     }
    1429                 : 
    1430                 :     // See if there was an old value...
    1431               0 :     nsCOMPtr<nsIRDFNode> oldvalue;
    1432               0 :     rv = mLocalStore->GetTarget(element, attr, true, getter_AddRefs(oldvalue));
    1433               0 :     if (NS_FAILED(rv)) return rv;
    1434                 : 
    1435               0 :     if (oldvalue && valuestr.IsEmpty()) {
    1436                 :         // ...there was an oldvalue, and they've removed it. XXXThis
    1437                 :         // handling isn't quite right...
    1438               0 :         rv = mLocalStore->Unassert(element, attr, oldvalue);
    1439                 :     }
    1440                 :     else {
    1441                 :         // Now either 'change' or 'assert' based on whether there was
    1442                 :         // an old value.
    1443               0 :         nsCOMPtr<nsIRDFLiteral> newvalue;
    1444               0 :         rv = gRDFService->GetLiteral(valuestr.get(), getter_AddRefs(newvalue));
    1445               0 :         if (NS_FAILED(rv)) return rv;
    1446                 : 
    1447               0 :         if (oldvalue) {
    1448               0 :             if (oldvalue != newvalue)
    1449               0 :                 rv = mLocalStore->Change(element, attr, oldvalue, newvalue);
    1450                 :             else
    1451               0 :                 rv = NS_OK;
    1452                 :         }
    1453                 :         else {
    1454               0 :             rv = mLocalStore->Assert(element, attr, newvalue, true);
    1455                 :         }
    1456                 :     }
    1457                 : 
    1458               0 :     if (NS_FAILED(rv)) return rv;
    1459                 : 
    1460                 :     // Add it to the persisted set for this document (if it's not
    1461                 :     // there already).
    1462                 :     {
    1463               0 :         nsCAutoString docurl;
    1464               0 :         rv = mDocumentURI->GetSpec(docurl);
    1465               0 :         if (NS_FAILED(rv)) return rv;
    1466                 : 
    1467               0 :         nsCOMPtr<nsIRDFResource> doc;
    1468               0 :         rv = gRDFService->GetResource(docurl, getter_AddRefs(doc));
    1469               0 :         if (NS_FAILED(rv)) return rv;
    1470                 : 
    1471                 :         bool hasAssertion;
    1472               0 :         rv = mLocalStore->HasAssertion(doc, kNC_persist, element, true, &hasAssertion);
    1473               0 :         if (NS_FAILED(rv)) return rv;
    1474                 : 
    1475               0 :         if (! hasAssertion) {
    1476               0 :             rv = mLocalStore->Assert(doc, kNC_persist, element, true);
    1477               0 :             if (NS_FAILED(rv)) return rv;
    1478                 :         }
    1479                 :     }
    1480                 : 
    1481               0 :     return NS_OK;
    1482                 : }
    1483                 : 
    1484                 : 
    1485                 : nsresult
    1486               0 : nsXULDocument::GetViewportSize(PRInt32* aWidth,
    1487                 :                                PRInt32* aHeight)
    1488                 : {
    1489               0 :     *aWidth = *aHeight = 0;
    1490                 : 
    1491               0 :     FlushPendingNotifications(Flush_Layout);
    1492                 : 
    1493               0 :     nsIPresShell *shell = GetShell();
    1494               0 :     NS_ENSURE_TRUE(shell, NS_ERROR_FAILURE);
    1495                 : 
    1496               0 :     nsIFrame* frame = shell->GetRootFrame();
    1497               0 :     NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
    1498                 : 
    1499               0 :     nsSize size = frame->GetSize();
    1500                 : 
    1501               0 :     *aWidth = nsPresContext::AppUnitsToIntCSSPixels(size.width);
    1502               0 :     *aHeight = nsPresContext::AppUnitsToIntCSSPixels(size.height);
    1503                 : 
    1504               0 :     return NS_OK;
    1505                 : }
    1506                 : 
    1507                 : NS_IMETHODIMP
    1508               0 : nsXULDocument::GetWidth(PRInt32* aWidth)
    1509                 : {
    1510               0 :     NS_ENSURE_ARG_POINTER(aWidth);
    1511                 : 
    1512                 :     PRInt32 height;
    1513               0 :     return GetViewportSize(aWidth, &height);
    1514                 : }
    1515                 : 
    1516                 : NS_IMETHODIMP
    1517               0 : nsXULDocument::GetHeight(PRInt32* aHeight)
    1518                 : {
    1519               0 :     NS_ENSURE_ARG_POINTER(aHeight);
    1520                 : 
    1521                 :     PRInt32 width;
    1522               0 :     return GetViewportSize(&width, aHeight);
    1523                 : }
    1524                 : 
    1525                 : //----------------------------------------------------------------------
    1526                 : //
    1527                 : // nsIDOMXULDocument interface
    1528                 : //
    1529                 : 
    1530                 : NS_IMETHODIMP
    1531               0 : nsXULDocument::GetPopupNode(nsIDOMNode** aNode)
    1532                 : {
    1533               0 :     *aNode = nsnull;
    1534                 : 
    1535               0 :     nsCOMPtr<nsIDOMNode> node;
    1536               0 :     nsCOMPtr<nsPIWindowRoot> rootWin = GetWindowRoot();
    1537               0 :     if (rootWin)
    1538               0 :         node = rootWin->GetPopupNode(); // addref happens here
    1539                 : 
    1540               0 :     if (!node) {
    1541               0 :         nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
    1542               0 :         if (pm) {
    1543               0 :             node = pm->GetLastTriggerPopupNode(this);
    1544                 :         }
    1545                 :     }
    1546                 : 
    1547               0 :     if (node && nsContentUtils::CanCallerAccess(node))
    1548               0 :       node.swap(*aNode);
    1549                 : 
    1550               0 :     return NS_OK;
    1551                 : }
    1552                 : 
    1553                 : NS_IMETHODIMP
    1554               0 : nsXULDocument::SetPopupNode(nsIDOMNode* aNode)
    1555                 : {
    1556               0 :     if (aNode) {
    1557                 :         // only allow real node objects
    1558               0 :         nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
    1559               0 :         NS_ENSURE_ARG(node);
    1560                 :     }
    1561                 : 
    1562               0 :     nsCOMPtr<nsPIWindowRoot> rootWin = GetWindowRoot();
    1563               0 :     if (rootWin)
    1564               0 :         rootWin->SetPopupNode(aNode); // addref happens here
    1565                 : 
    1566               0 :     return NS_OK;
    1567                 : }
    1568                 : 
    1569                 : // Returns the rangeOffset element from the XUL Popup Manager. This is for
    1570                 : // chrome callers only.
    1571                 : NS_IMETHODIMP
    1572               0 : nsXULDocument::GetPopupRangeParent(nsIDOMNode** aRangeParent)
    1573                 : {
    1574               0 :     NS_ENSURE_ARG_POINTER(aRangeParent);
    1575               0 :     *aRangeParent = nsnull;
    1576                 : 
    1577               0 :     nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
    1578               0 :     if (!pm)
    1579               0 :         return NS_ERROR_FAILURE;
    1580                 : 
    1581                 :     PRInt32 offset;
    1582               0 :     pm->GetMouseLocation(aRangeParent, &offset);
    1583                 : 
    1584               0 :     if (*aRangeParent && !nsContentUtils::CanCallerAccess(*aRangeParent)) {
    1585               0 :         NS_RELEASE(*aRangeParent);
    1586               0 :         return NS_ERROR_DOM_SECURITY_ERR;
    1587                 :     }
    1588                 : 
    1589               0 :     return NS_OK;
    1590                 : }
    1591                 : 
    1592                 : // Returns the rangeOffset element from the XUL Popup Manager. We check the
    1593                 : // rangeParent to determine if the caller has rights to access to the data.
    1594                 : NS_IMETHODIMP
    1595               0 : nsXULDocument::GetPopupRangeOffset(PRInt32* aRangeOffset)
    1596                 : {
    1597               0 :     NS_ENSURE_ARG_POINTER(aRangeOffset);
    1598                 : 
    1599               0 :     nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
    1600               0 :     if (!pm)
    1601               0 :         return NS_ERROR_FAILURE;
    1602                 : 
    1603                 :     PRInt32 offset;
    1604               0 :     nsCOMPtr<nsIDOMNode> parent;
    1605               0 :     pm->GetMouseLocation(getter_AddRefs(parent), &offset);
    1606                 : 
    1607               0 :     if (parent && !nsContentUtils::CanCallerAccess(parent))
    1608               0 :         return NS_ERROR_DOM_SECURITY_ERR;
    1609                 : 
    1610               0 :     *aRangeOffset = offset;
    1611               0 :     return NS_OK;
    1612                 : }
    1613                 : 
    1614                 : NS_IMETHODIMP
    1615               0 : nsXULDocument::GetTooltipNode(nsIDOMNode** aNode)
    1616                 : {
    1617               0 :     *aNode = nsnull;
    1618                 : 
    1619               0 :     nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
    1620               0 :     if (pm) {
    1621               0 :         nsCOMPtr<nsIDOMNode> node = pm->GetLastTriggerTooltipNode(this);
    1622               0 :         if (node && nsContentUtils::CanCallerAccess(node))
    1623               0 :             node.swap(*aNode);
    1624                 :     }
    1625                 : 
    1626               0 :     return NS_OK;
    1627                 : }
    1628                 : 
    1629                 : NS_IMETHODIMP
    1630               0 : nsXULDocument::SetTooltipNode(nsIDOMNode* aNode)
    1631                 : {
    1632                 :     // do nothing
    1633               0 :     return NS_OK;
    1634                 : }
    1635                 : 
    1636                 : 
    1637                 : NS_IMETHODIMP
    1638               0 : nsXULDocument::GetCommandDispatcher(nsIDOMXULCommandDispatcher** aTracker)
    1639                 : {
    1640               0 :     *aTracker = mCommandDispatcher;
    1641               0 :     NS_IF_ADDREF(*aTracker);
    1642               0 :     return NS_OK;
    1643                 : }
    1644                 : 
    1645                 : Element*
    1646               0 : nsXULDocument::GetElementById(const nsAString& aId)
    1647                 : {
    1648               0 :     if (!CheckGetElementByIdArg(aId))
    1649               0 :         return nsnull;
    1650                 : 
    1651               0 :     nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(aId);
    1652               0 :     if (entry) {
    1653               0 :         Element* element = entry->GetIdElement();
    1654               0 :         if (element)
    1655               0 :             return element;
    1656                 :     }
    1657                 : 
    1658               0 :     nsRefMapEntry* refEntry = mRefMap.GetEntry(aId);
    1659               0 :     if (refEntry) {
    1660               0 :         NS_ASSERTION(refEntry->GetFirstElement(),
    1661                 :                      "nsRefMapEntries should have nonempty content lists");
    1662               0 :         return refEntry->GetFirstElement();
    1663                 :     }
    1664               0 :     return nsnull;
    1665                 : }
    1666                 : 
    1667                 : nsresult
    1668               0 : nsXULDocument::AddElementToDocumentPre(Element* aElement)
    1669                 : {
    1670                 :     // Do a bunch of work that's necessary when an element gets added
    1671                 :     // to the XUL Document.
    1672                 :     nsresult rv;
    1673                 : 
    1674                 :     // 1. Add the element to the resource-to-element map. Also add it to
    1675                 :     // the id map, since it seems this can be called when creating
    1676                 :     // elements from prototypes.
    1677               0 :     nsIAtom* id = aElement->GetID();
    1678               0 :     if (id) {
    1679               0 :         nsAutoScriptBlocker scriptBlocker;
    1680               0 :         AddToIdTable(aElement, id);
    1681                 :     }
    1682               0 :     rv = AddElementToRefMap(aElement);
    1683               0 :     if (NS_FAILED(rv)) return rv;
    1684                 : 
    1685                 :     // 2. If the element is a 'command updater' (i.e., has a
    1686                 :     // "commandupdater='true'" attribute), then add the element to the
    1687                 :     // document's command dispatcher
    1688               0 :     if (aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::commandupdater,
    1689               0 :                               nsGkAtoms::_true, eCaseMatters)) {
    1690               0 :         rv = nsXULContentUtils::SetCommandUpdater(this, aElement);
    1691               0 :         if (NS_FAILED(rv)) return rv;
    1692                 :     }
    1693                 : 
    1694                 :     // 3. Check for a broadcaster hookup attribute, in which case
    1695                 :     // we'll hook the node up as a listener on a broadcaster.
    1696                 :     bool listener, resolved;
    1697               0 :     rv = CheckBroadcasterHookup(aElement, &listener, &resolved);
    1698               0 :     if (NS_FAILED(rv)) return rv;
    1699                 : 
    1700                 :     // If it's not there yet, we may be able to defer hookup until
    1701                 :     // later.
    1702               0 :     if (listener && !resolved && (mResolutionPhase != nsForwardReference::eDone)) {
    1703               0 :         BroadcasterHookup* hookup = new BroadcasterHookup(this, aElement);
    1704               0 :         if (! hookup)
    1705               0 :             return NS_ERROR_OUT_OF_MEMORY;
    1706                 : 
    1707               0 :         rv = AddForwardReference(hookup);
    1708               0 :         if (NS_FAILED(rv)) return rv;
    1709                 :     }
    1710                 : 
    1711               0 :     return NS_OK;
    1712                 : }
    1713                 : 
    1714                 : nsresult
    1715               0 : nsXULDocument::AddElementToDocumentPost(Element* aElement)
    1716                 : {
    1717                 :     // We need to pay special attention to the keyset tag to set up a listener
    1718               0 :     if (aElement->NodeInfo()->Equals(nsGkAtoms::keyset, kNameSpaceID_XUL)) {
    1719                 :         // Create our XUL key listener and hook it up.
    1720               0 :         nsCOMPtr<nsIXBLService> xblService(do_GetService("@mozilla.org/xbl;1"));
    1721               0 :         if (xblService) {
    1722               0 :             xblService->AttachGlobalKeyHandler(aElement);
    1723                 :         }
    1724                 :     }
    1725                 : 
    1726                 :     // See if we need to attach a XUL template to this node
    1727                 :     bool needsHookup;
    1728               0 :     nsresult rv = CheckTemplateBuilderHookup(aElement, &needsHookup);
    1729               0 :     if (NS_FAILED(rv))
    1730               0 :         return rv;
    1731                 : 
    1732               0 :     if (needsHookup) {
    1733               0 :         if (mResolutionPhase == nsForwardReference::eDone) {
    1734               0 :             rv = CreateTemplateBuilder(aElement);
    1735               0 :             if (NS_FAILED(rv))
    1736               0 :                 return rv;
    1737                 :         }
    1738                 :         else {
    1739               0 :             TemplateBuilderHookup* hookup = new TemplateBuilderHookup(aElement);
    1740               0 :             if (! hookup)
    1741               0 :                 return NS_ERROR_OUT_OF_MEMORY;
    1742                 : 
    1743               0 :             rv = AddForwardReference(hookup);
    1744               0 :             if (NS_FAILED(rv))
    1745               0 :                 return rv;
    1746                 :         }
    1747                 :     }
    1748                 : 
    1749               0 :     return NS_OK;
    1750                 : }
    1751                 : 
    1752                 : NS_IMETHODIMP
    1753               0 : nsXULDocument::AddSubtreeToDocument(nsIContent* aContent)
    1754                 : {
    1755               0 :     NS_ASSERTION(aContent->GetCurrentDoc() == this, "Element not in doc!");
    1756                 :     // From here on we only care about elements.
    1757               0 :     if (!aContent->IsElement()) {
    1758               0 :         return NS_OK;
    1759                 :     }
    1760                 : 
    1761               0 :     Element* aElement = aContent->AsElement();
    1762                 : 
    1763                 :     // Do pre-order addition magic
    1764               0 :     nsresult rv = AddElementToDocumentPre(aElement);
    1765               0 :     if (NS_FAILED(rv)) return rv;
    1766                 : 
    1767                 :     // Recurse to children
    1768               0 :     for (nsIContent* child = aElement->GetLastChild();
    1769                 :          child;
    1770               0 :          child = child->GetPreviousSibling()) {
    1771                 : 
    1772               0 :         rv = AddSubtreeToDocument(child);
    1773               0 :         if (NS_FAILED(rv))
    1774               0 :             return rv;
    1775                 :     }
    1776                 : 
    1777                 :     // Do post-order addition magic
    1778               0 :     return AddElementToDocumentPost(aElement);
    1779                 : }
    1780                 : 
    1781                 : NS_IMETHODIMP
    1782               0 : nsXULDocument::RemoveSubtreeFromDocument(nsIContent* aContent)
    1783                 : {
    1784                 :     // From here on we only care about elements.
    1785               0 :     if (!aContent->IsElement()) {
    1786               0 :         return NS_OK;
    1787                 :     }
    1788                 : 
    1789               0 :     Element* aElement = aContent->AsElement();
    1790                 : 
    1791                 :     // Do a bunch of cleanup to remove an element from the XUL
    1792                 :     // document.
    1793                 :     nsresult rv;
    1794                 : 
    1795               0 :     if (aElement->NodeInfo()->Equals(nsGkAtoms::keyset, kNameSpaceID_XUL)) {
    1796               0 :         nsCOMPtr<nsIXBLService> xblService(do_GetService("@mozilla.org/xbl;1"));
    1797               0 :         if (xblService) {
    1798               0 :             xblService->DetachGlobalKeyHandler(aElement);
    1799                 :         }
    1800                 :     }
    1801                 : 
    1802                 :     // 1. Remove any children from the document.
    1803               0 :     for (nsIContent* child = aElement->GetLastChild();
    1804                 :          child;
    1805               0 :          child = child->GetPreviousSibling()) {
    1806                 : 
    1807               0 :         rv = RemoveSubtreeFromDocument(child);
    1808               0 :         if (NS_FAILED(rv))
    1809               0 :             return rv;
    1810                 :     }
    1811                 : 
    1812                 :     // 2. Remove the element from the resource-to-element map.
    1813                 :     // Also remove it from the id map, since we added it in
    1814                 :     // AddElementToDocumentPre().
    1815               0 :     RemoveElementFromRefMap(aElement);
    1816               0 :     nsIAtom* id = aElement->GetID();
    1817               0 :     if (id) {
    1818               0 :         nsAutoScriptBlocker scriptBlocker;
    1819               0 :         RemoveFromIdTable(aElement, id);
    1820                 :     }
    1821                 : 
    1822                 :     // 3. If the element is a 'command updater', then remove the
    1823                 :     // element from the document's command dispatcher.
    1824               0 :     if (aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::commandupdater,
    1825               0 :                               nsGkAtoms::_true, eCaseMatters)) {
    1826               0 :         nsCOMPtr<nsIDOMElement> domelement = do_QueryInterface(aElement);
    1827               0 :         NS_ASSERTION(domelement != nsnull, "not a DOM element");
    1828               0 :         if (! domelement)
    1829               0 :             return NS_ERROR_UNEXPECTED;
    1830                 : 
    1831               0 :         rv = mCommandDispatcher->RemoveCommandUpdater(domelement);
    1832               0 :         if (NS_FAILED(rv)) return rv;
    1833                 :     }
    1834                 : 
    1835                 :     // 4. Remove the element from our broadcaster map, since it is no longer
    1836                 :     // in the document.
    1837               0 :     nsCOMPtr<nsIDOMElement> broadcaster, listener;
    1838               0 :     nsAutoString attribute, broadcasterID;
    1839               0 :     rv = FindBroadcaster(aElement, getter_AddRefs(listener),
    1840               0 :                          broadcasterID, attribute, getter_AddRefs(broadcaster));
    1841               0 :     if (rv == NS_FINDBROADCASTER_FOUND) {
    1842               0 :         RemoveBroadcastListenerFor(broadcaster, listener, attribute);
    1843                 :     }
    1844                 : 
    1845               0 :     return NS_OK;
    1846                 : }
    1847                 : 
    1848                 : NS_IMETHODIMP
    1849               0 : nsXULDocument::SetTemplateBuilderFor(nsIContent* aContent,
    1850                 :                                      nsIXULTemplateBuilder* aBuilder)
    1851                 : {
    1852               0 :     if (! mTemplateBuilderTable) {
    1853               0 :         if (!aBuilder) {
    1854               0 :             return NS_OK;
    1855                 :         }
    1856               0 :         mTemplateBuilderTable = new BuilderTable;
    1857               0 :         if (! mTemplateBuilderTable || !mTemplateBuilderTable->Init()) {
    1858               0 :             mTemplateBuilderTable = nsnull;
    1859               0 :             return NS_ERROR_OUT_OF_MEMORY;
    1860                 :         }
    1861                 :     }
    1862                 : 
    1863               0 :     if (aBuilder) {
    1864               0 :         mTemplateBuilderTable->Put(aContent, aBuilder);
    1865                 :     }
    1866                 :     else {
    1867               0 :         mTemplateBuilderTable->Remove(aContent);
    1868                 :     }
    1869                 : 
    1870               0 :     return NS_OK;
    1871                 : }
    1872                 : 
    1873                 : NS_IMETHODIMP
    1874               0 : nsXULDocument::GetTemplateBuilderFor(nsIContent* aContent,
    1875                 :                                      nsIXULTemplateBuilder** aResult)
    1876                 : {
    1877               0 :     if (mTemplateBuilderTable) {
    1878               0 :         mTemplateBuilderTable->Get(aContent, aResult);
    1879                 :     }
    1880                 :     else
    1881               0 :         *aResult = nsnull;
    1882                 : 
    1883               0 :     return NS_OK;
    1884                 : }
    1885                 : 
    1886                 : static void
    1887               0 : GetRefMapAttribute(Element* aElement, nsAutoString* aValue)
    1888                 : {
    1889               0 :     aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::ref, *aValue);
    1890               0 :     if (aValue->IsEmpty() && !aElement->GetIDAttributeName()) {
    1891               0 :         aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::id, *aValue);
    1892                 :     }
    1893               0 : }
    1894                 : 
    1895                 : nsresult
    1896               0 : nsXULDocument::AddElementToRefMap(Element* aElement)
    1897                 : {
    1898                 :     // Look at the element's 'ref' attribute, and if set,
    1899                 :     // add an entry in the resource-to-element map to the element.
    1900               0 :     nsAutoString value;
    1901               0 :     GetRefMapAttribute(aElement, &value);
    1902               0 :     if (!value.IsEmpty()) {
    1903               0 :         nsRefMapEntry *entry = mRefMap.PutEntry(value);
    1904               0 :         if (!entry)
    1905               0 :             return NS_ERROR_OUT_OF_MEMORY;
    1906               0 :         if (!entry->AddElement(aElement))
    1907               0 :             return NS_ERROR_OUT_OF_MEMORY;
    1908                 :     }
    1909                 : 
    1910               0 :     return NS_OK;
    1911                 : }
    1912                 : 
    1913                 : void
    1914               0 : nsXULDocument::RemoveElementFromRefMap(Element* aElement)
    1915                 : {
    1916                 :     // Remove the element from the resource-to-element map.
    1917               0 :     nsAutoString value;
    1918               0 :     GetRefMapAttribute(aElement, &value);
    1919               0 :     if (!value.IsEmpty()) {
    1920               0 :         nsRefMapEntry *entry = mRefMap.GetEntry(value);
    1921               0 :         if (!entry)
    1922                 :             return;
    1923               0 :         if (entry->RemoveElement(aElement)) {
    1924               0 :             mRefMap.RawRemoveEntry(entry);
    1925                 :         }
    1926                 :     }
    1927                 : }
    1928                 : 
    1929                 : //----------------------------------------------------------------------
    1930                 : //
    1931                 : // nsIDOMNode interface
    1932                 : //
    1933                 : 
    1934                 : NS_IMETHODIMP
    1935               0 : nsXULDocument::CloneNode(bool aDeep, nsIDOMNode** aReturn)
    1936                 : {
    1937                 :     // We don't allow cloning of a document
    1938               0 :     *aReturn = nsnull;
    1939               0 :     return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
    1940                 : }
    1941                 : 
    1942                 : 
    1943                 : //----------------------------------------------------------------------
    1944                 : //
    1945                 : // Implementation methods
    1946                 : //
    1947                 : 
    1948                 : nsresult
    1949               0 : nsXULDocument::Init()
    1950                 : {
    1951               0 :     mRefMap.Init();
    1952                 : 
    1953               0 :     nsresult rv = nsXMLDocument::Init();
    1954               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1955                 : 
    1956                 :     // Create our command dispatcher and hook it up.
    1957               0 :     mCommandDispatcher = new nsXULCommandDispatcher(this);
    1958               0 :     NS_ENSURE_TRUE(mCommandDispatcher, NS_ERROR_OUT_OF_MEMORY);
    1959                 : 
    1960                 :     // this _could_ fail; e.g., if we've tried to grab the local store
    1961                 :     // before profiles have initialized. If so, no big deal; nothing
    1962                 :     // will persist.
    1963               0 :     mLocalStore = do_GetService(NS_LOCALSTORE_CONTRACTID);
    1964                 : 
    1965               0 :     if (gRefCnt++ == 0) {
    1966                 :         // Keep the RDF service cached in a member variable to make using
    1967                 :         // it a bit less painful
    1968               0 :         rv = CallGetService("@mozilla.org/rdf/rdf-service;1", &gRDFService);
    1969               0 :         NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get RDF Service");
    1970               0 :         if (NS_FAILED(rv)) return rv;
    1971                 : 
    1972               0 :         gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "persist"),
    1973               0 :                                  &kNC_persist);
    1974               0 :         gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "attribute"),
    1975               0 :                                  &kNC_attribute);
    1976               0 :         gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "value"),
    1977               0 :                                  &kNC_value);
    1978                 : 
    1979                 :         // ensure that the XUL prototype cache is instantiated successfully,
    1980                 :         // so that we can use nsXULPrototypeCache::GetInstance() without
    1981                 :         // null-checks in the rest of the class.
    1982               0 :         nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance();
    1983               0 :         if (!cache) {
    1984               0 :           NS_ERROR("Could not instantiate nsXULPrototypeCache");
    1985               0 :           return NS_ERROR_FAILURE;
    1986                 :         }
    1987                 :     }
    1988                 : 
    1989                 :     Preferences::RegisterCallback(nsXULDocument::DirectionChanged,
    1990               0 :                                   "intl.uidirection.", this);
    1991                 : 
    1992                 : #ifdef PR_LOGGING
    1993               0 :     if (! gXULLog)
    1994               0 :         gXULLog = PR_NewLogModule("nsXULDocument");
    1995                 : #endif
    1996                 : 
    1997               0 :     return NS_OK;
    1998                 : }
    1999                 : 
    2000                 : 
    2001                 : nsresult
    2002               0 : nsXULDocument::StartLayout(void)
    2003                 : {
    2004               0 :     mMayStartLayout = true;
    2005               0 :     nsCOMPtr<nsIPresShell> shell = GetShell();
    2006               0 :     if (shell) {
    2007                 :         // Resize-reflow this time
    2008               0 :         nsPresContext *cx = shell->GetPresContext();
    2009               0 :         NS_ASSERTION(cx != nsnull, "no pres context");
    2010               0 :         if (! cx)
    2011               0 :             return NS_ERROR_UNEXPECTED;
    2012                 : 
    2013               0 :         nsCOMPtr<nsISupports> container = cx->GetContainer();
    2014               0 :         NS_ASSERTION(container != nsnull, "pres context has no container");
    2015               0 :         if (! container)
    2016               0 :             return NS_ERROR_UNEXPECTED;
    2017                 : 
    2018               0 :         nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(container));
    2019               0 :         NS_ASSERTION(docShell != nsnull, "container is not a docshell");
    2020               0 :         if (! docShell)
    2021               0 :             return NS_ERROR_UNEXPECTED;
    2022                 : 
    2023               0 :         nsresult rv = NS_OK;
    2024               0 :         nsRect r = cx->GetVisibleArea();
    2025               0 :         rv = shell->InitialReflow(r.width, r.height);
    2026               0 :         NS_ENSURE_SUCCESS(rv, rv);
    2027                 :     }
    2028                 : 
    2029               0 :     return NS_OK;
    2030                 : }
    2031                 : 
    2032                 : /* static */
    2033                 : bool
    2034            2604 : nsXULDocument::MatchAttribute(nsIContent* aContent,
    2035                 :                               PRInt32 aNamespaceID,
    2036                 :                               nsIAtom* aAttrName,
    2037                 :                               void* aData)
    2038                 : {
    2039            2604 :     NS_PRECONDITION(aContent, "Must have content node to work with!");
    2040            2604 :     nsString* attrValue = static_cast<nsString*>(aData);
    2041            2604 :     if (aNamespaceID != kNameSpaceID_Unknown &&
    2042                 :         aNamespaceID != kNameSpaceID_Wildcard) {
    2043             640 :         return attrValue->EqualsLiteral("*") ?
    2044               0 :             aContent->HasAttr(aNamespaceID, aAttrName) :
    2045                 :             aContent->AttrValueIs(aNamespaceID, aAttrName, *attrValue,
    2046             640 :                                   eCaseMatters);
    2047                 :     }
    2048                 : 
    2049                 :     // Qualified name match. This takes more work.
    2050                 : 
    2051            1964 :     PRUint32 count = aContent->GetAttrCount();
    2052            3495 :     for (PRUint32 i = 0; i < count; ++i) {
    2053            2286 :         const nsAttrName* name = aContent->GetAttrNameAt(i);
    2054                 :         bool nameMatch;
    2055            2286 :         if (name->IsAtom()) {
    2056             859 :             nameMatch = name->Atom() == aAttrName;
    2057            1427 :         } else if (aNamespaceID == kNameSpaceID_Wildcard) {
    2058             357 :             nameMatch = name->NodeInfo()->Equals(aAttrName);
    2059                 :         } else {
    2060            1070 :             nameMatch = name->NodeInfo()->QualifiedNameEquals(aAttrName);
    2061                 :         }
    2062                 : 
    2063            2286 :         if (nameMatch) {
    2064             755 :             return attrValue->EqualsLiteral("*") ||
    2065                 :                 aContent->AttrValueIs(name->NamespaceID(), name->LocalName(),
    2066             755 :                                       *attrValue, eCaseMatters);
    2067                 :         }
    2068                 :     }
    2069                 : 
    2070            1209 :     return false;
    2071                 : }
    2072                 : 
    2073                 : nsresult
    2074               0 : nsXULDocument::PrepareToLoad(nsISupports* aContainer,
    2075                 :                              const char* aCommand,
    2076                 :                              nsIChannel* aChannel,
    2077                 :                              nsILoadGroup* aLoadGroup,
    2078                 :                              nsIParser** aResult)
    2079                 : {
    2080                 :     // Get the document's principal
    2081               0 :     nsCOMPtr<nsIPrincipal> principal;
    2082               0 :     nsContentUtils::GetSecurityManager()->
    2083               0 :         GetChannelPrincipal(aChannel, getter_AddRefs(principal));
    2084               0 :     return PrepareToLoadPrototype(mDocumentURI, aCommand, principal, aResult);
    2085                 : }
    2086                 : 
    2087                 : 
    2088                 : nsresult
    2089               0 : nsXULDocument::PrepareToLoadPrototype(nsIURI* aURI, const char* aCommand,
    2090                 :                                       nsIPrincipal* aDocumentPrincipal,
    2091                 :                                       nsIParser** aResult)
    2092                 : {
    2093                 :     nsresult rv;
    2094                 : 
    2095                 :     // Create a new prototype document.
    2096               0 :     rv = NS_NewXULPrototypeDocument(getter_AddRefs(mCurrentPrototype));
    2097               0 :     if (NS_FAILED(rv)) return rv;
    2098                 : 
    2099               0 :     rv = mCurrentPrototype->InitPrincipal(aURI, aDocumentPrincipal);
    2100               0 :     if (NS_FAILED(rv)) {
    2101               0 :         mCurrentPrototype = nsnull;
    2102               0 :         return rv;
    2103                 :     }    
    2104                 : 
    2105                 :     // Bootstrap the master document prototype.
    2106               0 :     if (! mMasterPrototype) {
    2107               0 :         mMasterPrototype = mCurrentPrototype;
    2108                 :         // Set our principal based on the master proto.
    2109               0 :         SetPrincipal(aDocumentPrincipal);
    2110                 :     }
    2111                 : 
    2112                 :     // Create a XUL content sink, a parser, and kick off a load for
    2113                 :     // the overlay.
    2114               0 :     nsRefPtr<XULContentSinkImpl> sink = new XULContentSinkImpl();
    2115               0 :     if (!sink) return NS_ERROR_OUT_OF_MEMORY;
    2116                 : 
    2117               0 :     rv = sink->Init(this, mCurrentPrototype);
    2118               0 :     NS_ASSERTION(NS_SUCCEEDED(rv), "Unable to initialize datasource sink");
    2119               0 :     if (NS_FAILED(rv)) return rv;
    2120                 : 
    2121               0 :     nsCOMPtr<nsIParser> parser = do_CreateInstance(kParserCID, &rv);
    2122               0 :     NS_ASSERTION(NS_SUCCEEDED(rv), "unable to create parser");
    2123               0 :     if (NS_FAILED(rv)) return rv;
    2124                 : 
    2125               0 :     parser->SetCommand(nsCRT::strcmp(aCommand, "view-source") ? eViewNormal :
    2126               0 :                        eViewSource);
    2127                 : 
    2128               0 :     parser->SetDocumentCharset(NS_LITERAL_CSTRING("UTF-8"),
    2129               0 :                                kCharsetFromDocTypeDefault);
    2130               0 :     parser->SetContentSink(sink); // grabs a reference to the parser
    2131                 : 
    2132               0 :     *aResult = parser;
    2133               0 :     NS_ADDREF(*aResult);
    2134               0 :     return NS_OK;
    2135                 : }
    2136                 : 
    2137                 : 
    2138                 : nsresult
    2139               0 : nsXULDocument::ApplyPersistentAttributes()
    2140                 : {
    2141                 :     // For non-chrome documents, persistance is simply broken
    2142               0 :     if (!IsCapabilityEnabled("UniversalXPConnect"))
    2143               0 :         return NS_ERROR_NOT_AVAILABLE;
    2144                 : 
    2145                 :     // Add all of the 'persisted' attributes into the content
    2146                 :     // model.
    2147               0 :     if (!mLocalStore)
    2148               0 :         return NS_OK;
    2149                 : 
    2150               0 :     mApplyingPersistedAttrs = true;
    2151               0 :     ApplyPersistentAttributesInternal();
    2152               0 :     mApplyingPersistedAttrs = false;
    2153                 : 
    2154               0 :     return NS_OK;
    2155                 : }
    2156                 : 
    2157                 : 
    2158                 : nsresult 
    2159               0 : nsXULDocument::ApplyPersistentAttributesInternal()
    2160                 : {
    2161               0 :     nsCOMArray<nsIContent> elements;
    2162                 : 
    2163               0 :     nsCAutoString docurl;
    2164               0 :     mDocumentURI->GetSpec(docurl);
    2165                 : 
    2166               0 :     nsCOMPtr<nsIRDFResource> doc;
    2167               0 :     gRDFService->GetResource(docurl, getter_AddRefs(doc));
    2168                 : 
    2169               0 :     nsCOMPtr<nsISimpleEnumerator> persisted;
    2170               0 :     mLocalStore->GetTargets(doc, kNC_persist, true, getter_AddRefs(persisted));
    2171                 : 
    2172               0 :     while (1) {
    2173               0 :         bool hasmore = false;
    2174               0 :         persisted->HasMoreElements(&hasmore);
    2175               0 :         if (! hasmore)
    2176                 :             break;
    2177                 : 
    2178               0 :         nsCOMPtr<nsISupports> isupports;
    2179               0 :         persisted->GetNext(getter_AddRefs(isupports));
    2180                 : 
    2181               0 :         nsCOMPtr<nsIRDFResource> resource = do_QueryInterface(isupports);
    2182               0 :         if (! resource) {
    2183               0 :             NS_WARNING("expected element to be a resource");
    2184               0 :             continue;
    2185                 :         }
    2186                 : 
    2187                 :         const char *uri;
    2188               0 :         resource->GetValueConst(&uri);
    2189               0 :         if (! uri)
    2190               0 :             continue;
    2191                 : 
    2192               0 :         nsAutoString id;
    2193               0 :         nsXULContentUtils::MakeElementID(this, nsDependentCString(uri), id);
    2194                 : 
    2195               0 :         if (id.IsEmpty())
    2196               0 :             continue;
    2197                 : 
    2198                 :         // This will clear the array if there are no elements.
    2199               0 :         GetElementsForID(id, elements);
    2200                 : 
    2201               0 :         if (!elements.Count())
    2202               0 :             continue;
    2203                 : 
    2204               0 :         ApplyPersistentAttributesToElements(resource, elements);
    2205                 :     }
    2206                 : 
    2207               0 :     return NS_OK;
    2208                 : }
    2209                 : 
    2210                 : 
    2211                 : nsresult
    2212               0 : nsXULDocument::ApplyPersistentAttributesToElements(nsIRDFResource* aResource,
    2213                 :                                                    nsCOMArray<nsIContent>& aElements)
    2214                 : {
    2215                 :     nsresult rv;
    2216                 : 
    2217               0 :     nsCOMPtr<nsISimpleEnumerator> attrs;
    2218               0 :     rv = mLocalStore->ArcLabelsOut(aResource, getter_AddRefs(attrs));
    2219               0 :     if (NS_FAILED(rv)) return rv;
    2220                 : 
    2221               0 :     while (1) {
    2222                 :         bool hasmore;
    2223               0 :         rv = attrs->HasMoreElements(&hasmore);
    2224               0 :         if (NS_FAILED(rv)) return rv;
    2225                 : 
    2226               0 :         if (! hasmore)
    2227                 :             break;
    2228                 : 
    2229               0 :         nsCOMPtr<nsISupports> isupports;
    2230               0 :         rv = attrs->GetNext(getter_AddRefs(isupports));
    2231               0 :         if (NS_FAILED(rv)) return rv;
    2232                 : 
    2233               0 :         nsCOMPtr<nsIRDFResource> property = do_QueryInterface(isupports);
    2234               0 :         if (! property) {
    2235               0 :             NS_WARNING("expected a resource");
    2236               0 :             continue;
    2237                 :         }
    2238                 : 
    2239                 :         const char* attrname;
    2240               0 :         rv = property->GetValueConst(&attrname);
    2241               0 :         if (NS_FAILED(rv)) return rv;
    2242                 : 
    2243               0 :         nsCOMPtr<nsIAtom> attr = do_GetAtom(attrname);
    2244               0 :         if (! attr)
    2245               0 :             return NS_ERROR_OUT_OF_MEMORY;
    2246                 : 
    2247                 :         // XXX could hang namespace off here, as well...
    2248                 : 
    2249               0 :         nsCOMPtr<nsIRDFNode> node;
    2250               0 :         rv = mLocalStore->GetTarget(aResource, property, true,
    2251               0 :                                     getter_AddRefs(node));
    2252               0 :         if (NS_FAILED(rv)) return rv;
    2253                 : 
    2254               0 :         nsCOMPtr<nsIRDFLiteral> literal = do_QueryInterface(node);
    2255               0 :         if (! literal) {
    2256               0 :             NS_WARNING("expected a literal");
    2257               0 :             continue;
    2258                 :         }
    2259                 : 
    2260                 :         const PRUnichar* value;
    2261               0 :         rv = literal->GetValueConst(&value);
    2262               0 :         if (NS_FAILED(rv)) return rv;
    2263                 : 
    2264               0 :         nsDependentString wrapper(value);
    2265                 : 
    2266               0 :         PRUint32 cnt = aElements.Count();
    2267                 : 
    2268               0 :         for (PRInt32 i = PRInt32(cnt) - 1; i >= 0; --i) {
    2269               0 :             nsCOMPtr<nsIContent> element = aElements.SafeObjectAt(i);
    2270               0 :             if (!element)
    2271               0 :                 continue;
    2272                 : 
    2273                 :             rv = element->SetAttr(/* XXX */ kNameSpaceID_None,
    2274                 :                                   attr,
    2275                 :                                   wrapper,
    2276               0 :                                   true);
    2277                 :         }
    2278                 :     }
    2279                 : 
    2280               0 :     return NS_OK;
    2281                 : }
    2282                 : 
    2283                 : //----------------------------------------------------------------------
    2284                 : //
    2285                 : // nsXULDocument::ContextStack
    2286                 : //
    2287                 : 
    2288               0 : nsXULDocument::ContextStack::ContextStack()
    2289               0 :     : mTop(nsnull), mDepth(0)
    2290                 : {
    2291               0 : }
    2292                 : 
    2293               0 : nsXULDocument::ContextStack::~ContextStack()
    2294                 : {
    2295               0 :     while (mTop) {
    2296               0 :         Entry* doomed = mTop;
    2297               0 :         mTop = mTop->mNext;
    2298               0 :         NS_IF_RELEASE(doomed->mElement);
    2299                 :         delete doomed;
    2300                 :     }
    2301               0 : }
    2302                 : 
    2303                 : nsresult
    2304               0 : nsXULDocument::ContextStack::Push(nsXULPrototypeElement* aPrototype,
    2305                 :                                   nsIContent* aElement)
    2306                 : {
    2307               0 :     Entry* entry = new Entry;
    2308               0 :     if (! entry)
    2309               0 :         return NS_ERROR_OUT_OF_MEMORY;
    2310                 : 
    2311               0 :     entry->mPrototype = aPrototype;
    2312               0 :     entry->mElement   = aElement;
    2313               0 :     NS_IF_ADDREF(entry->mElement);
    2314               0 :     entry->mIndex     = 0;
    2315                 : 
    2316               0 :     entry->mNext = mTop;
    2317               0 :     mTop = entry;
    2318                 : 
    2319               0 :     ++mDepth;
    2320               0 :     return NS_OK;
    2321                 : }
    2322                 : 
    2323                 : nsresult
    2324               0 : nsXULDocument::ContextStack::Pop()
    2325                 : {
    2326               0 :     if (mDepth == 0)
    2327               0 :         return NS_ERROR_UNEXPECTED;
    2328                 : 
    2329               0 :     Entry* doomed = mTop;
    2330               0 :     mTop = mTop->mNext;
    2331               0 :     --mDepth;
    2332                 : 
    2333               0 :     NS_IF_RELEASE(doomed->mElement);
    2334                 :     delete doomed;
    2335               0 :     return NS_OK;
    2336                 : }
    2337                 : 
    2338                 : nsresult
    2339               0 : nsXULDocument::ContextStack::Peek(nsXULPrototypeElement** aPrototype,
    2340                 :                                            nsIContent** aElement,
    2341                 :                                            PRInt32* aIndex)
    2342                 : {
    2343               0 :     if (mDepth == 0)
    2344               0 :         return NS_ERROR_UNEXPECTED;
    2345                 : 
    2346               0 :     *aPrototype = mTop->mPrototype;
    2347               0 :     *aElement   = mTop->mElement;
    2348               0 :     NS_IF_ADDREF(*aElement);
    2349               0 :     *aIndex     = mTop->mIndex;
    2350                 : 
    2351               0 :     return NS_OK;
    2352                 : }
    2353                 : 
    2354                 : 
    2355                 : nsresult
    2356               0 : nsXULDocument::ContextStack::SetTopIndex(PRInt32 aIndex)
    2357                 : {
    2358               0 :     if (mDepth == 0)
    2359               0 :         return NS_ERROR_UNEXPECTED;
    2360                 : 
    2361               0 :     mTop->mIndex = aIndex;
    2362               0 :     return NS_OK;
    2363                 : }
    2364                 : 
    2365                 : 
    2366                 : //----------------------------------------------------------------------
    2367                 : //
    2368                 : // Content model walking routines
    2369                 : //
    2370                 : 
    2371                 : nsresult
    2372               0 : nsXULDocument::PrepareToWalk()
    2373                 : {
    2374                 :     // Prepare to walk the mCurrentPrototype
    2375                 :     nsresult rv;
    2376                 : 
    2377                 :     // Keep an owning reference to the prototype document so that its
    2378                 :     // elements aren't yanked from beneath us.
    2379               0 :     mPrototypes.AppendElement(mCurrentPrototype);
    2380                 : 
    2381                 :     // Get the prototype's root element and initialize the context
    2382                 :     // stack for the prototype walk.
    2383               0 :     nsXULPrototypeElement* proto = mCurrentPrototype->GetRootElement();
    2384                 : 
    2385               0 :     if (! proto) {
    2386                 : #ifdef PR_LOGGING
    2387               0 :         if (PR_LOG_TEST(gXULLog, PR_LOG_ERROR)) {
    2388               0 :             nsCOMPtr<nsIURI> url = mCurrentPrototype->GetURI();
    2389                 : 
    2390               0 :             nsCAutoString urlspec;
    2391               0 :             rv = url->GetSpec(urlspec);
    2392               0 :             if (NS_FAILED(rv)) return rv;
    2393                 : 
    2394               0 :             PR_LOG(gXULLog, PR_LOG_ERROR,
    2395                 :                    ("xul: error parsing '%s'", urlspec.get()));
    2396                 :         }
    2397                 : #endif
    2398                 : 
    2399               0 :         return NS_OK;
    2400                 :     }
    2401                 : 
    2402               0 :     PRUint32 piInsertionPoint = 0;
    2403               0 :     if (mState != eState_Master) {
    2404               0 :         piInsertionPoint = IndexOf(GetRootElement());
    2405                 :         NS_ASSERTION(piInsertionPoint >= 0,
    2406                 :                      "No root content when preparing to walk overlay!");
    2407                 :     }
    2408                 : 
    2409                 :     const nsTArray<nsRefPtr<nsXULPrototypePI> >& processingInstructions =
    2410               0 :         mCurrentPrototype->GetProcessingInstructions();
    2411                 : 
    2412               0 :     PRUint32 total = processingInstructions.Length();
    2413               0 :     for (PRUint32 i = 0; i < total; ++i) {
    2414               0 :         rv = CreateAndInsertPI(processingInstructions[i],
    2415               0 :                                this, piInsertionPoint + i);
    2416               0 :         if (NS_FAILED(rv)) return rv;
    2417                 :     }
    2418                 : 
    2419                 :     // Now check the chrome registry for any additional overlays.
    2420               0 :     rv = AddChromeOverlays();
    2421               0 :     if (NS_FAILED(rv)) return rv;
    2422                 : 
    2423                 :     // Do one-time initialization if we're preparing to walk the
    2424                 :     // master document's prototype.
    2425               0 :     nsRefPtr<Element> root;
    2426                 : 
    2427               0 :     if (mState == eState_Master) {
    2428                 :         // Add the root element
    2429               0 :         rv = CreateElementFromPrototype(proto, getter_AddRefs(root));
    2430               0 :         if (NS_FAILED(rv)) return rv;
    2431                 : 
    2432               0 :         rv = AppendChildTo(root, false);
    2433               0 :         if (NS_FAILED(rv)) return rv;
    2434                 :         
    2435               0 :         rv = AddElementToRefMap(root);
    2436               0 :         if (NS_FAILED(rv)) return rv;
    2437                 : 
    2438                 :         // Block onload until we've finished building the complete
    2439                 :         // document content model.
    2440               0 :         BlockOnload();
    2441                 :     }
    2442                 : 
    2443                 :     // There'd better not be anything on the context stack at this
    2444                 :     // point! This is the basis case for our "induction" in
    2445                 :     // ResumeWalk(), below, which'll assume that there's always a
    2446                 :     // content element on the context stack if either 1) we're in the
    2447                 :     // "master" document, or 2) we're in an overlay, and we've got
    2448                 :     // more than one prototype element (the single, root "overlay"
    2449                 :     // element) on the stack.
    2450               0 :     NS_ASSERTION(mContextStack.Depth() == 0, "something's on the context stack already");
    2451               0 :     if (mContextStack.Depth() != 0)
    2452               0 :         return NS_ERROR_UNEXPECTED;
    2453                 : 
    2454               0 :     rv = mContextStack.Push(proto, root);
    2455               0 :     if (NS_FAILED(rv)) return rv;
    2456                 : 
    2457               0 :     return NS_OK;
    2458                 : }
    2459                 : 
    2460                 : nsresult
    2461               0 : nsXULDocument::CreateAndInsertPI(const nsXULPrototypePI* aProtoPI,
    2462                 :                                  nsINode* aParent, PRUint32 aIndex)
    2463                 : {
    2464               0 :     NS_PRECONDITION(aProtoPI, "null ptr");
    2465               0 :     NS_PRECONDITION(aParent, "null ptr");
    2466                 : 
    2467                 :     nsresult rv;
    2468               0 :     nsCOMPtr<nsIContent> node;
    2469                 : 
    2470               0 :     rv = NS_NewXMLProcessingInstruction(getter_AddRefs(node),
    2471                 :                                         mNodeInfoManager,
    2472                 :                                         aProtoPI->mTarget,
    2473               0 :                                         aProtoPI->mData);
    2474               0 :     if (NS_FAILED(rv)) return rv;
    2475                 : 
    2476               0 :     if (aProtoPI->mTarget.EqualsLiteral("xml-stylesheet")) {
    2477               0 :         rv = InsertXMLStylesheetPI(aProtoPI, aParent, aIndex, node);
    2478               0 :     } else if (aProtoPI->mTarget.EqualsLiteral("xul-overlay")) {
    2479               0 :         rv = InsertXULOverlayPI(aProtoPI, aParent, aIndex, node);
    2480                 :     } else {
    2481                 :         // No special processing, just add the PI to the document.
    2482               0 :         rv = aParent->InsertChildAt(node, aIndex, false);
    2483                 :     }
    2484                 : 
    2485               0 :     return rv;
    2486                 : }
    2487                 : 
    2488                 : nsresult
    2489               0 : nsXULDocument::InsertXMLStylesheetPI(const nsXULPrototypePI* aProtoPI,
    2490                 :                                      nsINode* aParent,
    2491                 :                                      PRUint32 aIndex,
    2492                 :                                      nsIContent* aPINode)
    2493                 : {
    2494               0 :     nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(aPINode));
    2495               0 :     NS_ASSERTION(ssle, "passed XML Stylesheet node does not "
    2496                 :                        "implement nsIStyleSheetLinkingElement!");
    2497                 : 
    2498                 :     nsresult rv;
    2499                 : 
    2500               0 :     ssle->InitStyleLinkElement(false);
    2501                 :     // We want to be notified when the style sheet finishes loading, so
    2502                 :     // disable style sheet loading for now.
    2503               0 :     ssle->SetEnableUpdates(false);
    2504               0 :     ssle->OverrideBaseURI(mCurrentPrototype->GetURI());
    2505                 : 
    2506               0 :     rv = aParent->InsertChildAt(aPINode, aIndex, false);
    2507               0 :     if (NS_FAILED(rv)) return rv;
    2508                 : 
    2509               0 :     ssle->SetEnableUpdates(true);
    2510                 : 
    2511                 :     // load the stylesheet if necessary, passing ourselves as
    2512                 :     // nsICSSObserver
    2513                 :     bool willNotify;
    2514                 :     bool isAlternate;
    2515               0 :     rv = ssle->UpdateStyleSheet(this, &willNotify, &isAlternate);
    2516               0 :     if (NS_SUCCEEDED(rv) && willNotify && !isAlternate) {
    2517               0 :         ++mPendingSheets;
    2518                 :     }
    2519                 : 
    2520                 :     // Ignore errors from UpdateStyleSheet; we don't want failure to
    2521                 :     // do that to break the XUL document load.  But do propagate out
    2522                 :     // NS_ERROR_OUT_OF_MEMORY.
    2523               0 :     if (rv == NS_ERROR_OUT_OF_MEMORY) {
    2524               0 :         return rv;
    2525                 :     }
    2526                 :     
    2527               0 :     return NS_OK;
    2528                 : }
    2529                 : 
    2530                 : nsresult
    2531               0 : nsXULDocument::InsertXULOverlayPI(const nsXULPrototypePI* aProtoPI,
    2532                 :                                   nsINode* aParent,
    2533                 :                                   PRUint32 aIndex,
    2534                 :                                   nsIContent* aPINode)
    2535                 : {
    2536                 :     nsresult rv;
    2537                 : 
    2538               0 :     rv = aParent->InsertChildAt(aPINode, aIndex, false);
    2539               0 :     if (NS_FAILED(rv)) return rv;
    2540                 : 
    2541                 :     // xul-overlay PI is special only in prolog
    2542               0 :     if (!nsContentUtils::InProlog(aPINode)) {
    2543               0 :         return NS_OK;
    2544                 :     }
    2545                 : 
    2546               0 :     nsAutoString href;
    2547                 :     nsContentUtils::GetPseudoAttributeValue(aProtoPI->mData,
    2548                 :                                             nsGkAtoms::href,
    2549               0 :                                             href);
    2550                 : 
    2551                 :     // If there was no href, we can't do anything with this PI
    2552               0 :     if (href.IsEmpty()) {
    2553               0 :         return NS_OK;
    2554                 :     }
    2555                 : 
    2556                 :     // Add the overlay to our list of overlays that need to be processed.
    2557               0 :     nsCOMPtr<nsIURI> uri;
    2558                 : 
    2559               0 :     rv = NS_NewURI(getter_AddRefs(uri), href, nsnull,
    2560               0 :                    mCurrentPrototype->GetURI());
    2561               0 :     if (NS_SUCCEEDED(rv)) {
    2562                 :         // We insert overlays into mUnloadedOverlays at the same index in
    2563                 :         // document order, so they end up in the reverse of the document
    2564                 :         // order in mUnloadedOverlays.
    2565                 :         // This is needed because the code in ResumeWalk loads the overlays
    2566                 :         // by processing the last item of mUnloadedOverlays and removing it
    2567                 :         // from the array.
    2568               0 :         rv = mUnloadedOverlays.InsertObjectAt(uri, 0);
    2569               0 :     } else if (rv == NS_ERROR_MALFORMED_URI) {
    2570                 :         // The URL is bad, move along. Don't propagate for now.
    2571                 :         // XXX report this to the Error Console (bug 359846)
    2572               0 :         rv = NS_OK;
    2573                 :     }
    2574                 : 
    2575               0 :     return rv;
    2576                 : }
    2577                 : 
    2578                 : nsresult
    2579               0 : nsXULDocument::AddChromeOverlays()
    2580                 : {
    2581                 :     nsresult rv;
    2582                 : 
    2583               0 :     nsCOMPtr<nsIURI> docUri = mCurrentPrototype->GetURI();
    2584                 : 
    2585                 :     /* overlays only apply to chrome or about URIs */
    2586               0 :     if (!IsOverlayAllowed(docUri)) return NS_OK;
    2587                 : 
    2588                 :     nsCOMPtr<nsIXULOverlayProvider> chromeReg =
    2589               0 :         mozilla::services::GetXULOverlayProviderService();
    2590                 :     // In embedding situations, the chrome registry may not provide overlays,
    2591                 :     // or even exist at all; that's OK.
    2592               0 :     NS_ENSURE_TRUE(chromeReg, NS_OK);
    2593                 : 
    2594               0 :     nsCOMPtr<nsISimpleEnumerator> overlays;
    2595               0 :     rv = chromeReg->GetXULOverlays(docUri, getter_AddRefs(overlays));
    2596               0 :     NS_ENSURE_SUCCESS(rv, rv);
    2597                 : 
    2598                 :     bool moreOverlays;
    2599               0 :     nsCOMPtr<nsISupports> next;
    2600               0 :     nsCOMPtr<nsIURI> uri;
    2601                 : 
    2602               0 :     while (NS_SUCCEEDED(rv = overlays->HasMoreElements(&moreOverlays)) &&
    2603                 :            moreOverlays) {
    2604                 : 
    2605               0 :         rv = overlays->GetNext(getter_AddRefs(next));
    2606               0 :         if (NS_FAILED(rv) || !next) break;
    2607                 : 
    2608               0 :         uri = do_QueryInterface(next);
    2609               0 :         if (!uri) {
    2610               0 :             NS_ERROR("Chrome registry handed me a non-nsIURI object!");
    2611               0 :             continue;
    2612                 :         }
    2613                 : 
    2614                 :         // Same comment as in nsXULDocument::InsertXULOverlayPI
    2615               0 :         rv = mUnloadedOverlays.InsertObjectAt(uri, 0);
    2616               0 :         if (NS_FAILED(rv)) break;
    2617                 :     }
    2618                 : 
    2619               0 :     return rv;
    2620                 : }
    2621                 : 
    2622                 : NS_IMETHODIMP
    2623               0 : nsXULDocument::LoadOverlay(const nsAString& aURL, nsIObserver* aObserver)
    2624                 : {
    2625                 :     nsresult rv;
    2626                 : 
    2627               0 :     nsCOMPtr<nsIURI> uri;
    2628               0 :     rv = NS_NewURI(getter_AddRefs(uri), aURL, nsnull);
    2629               0 :     if (NS_FAILED(rv)) return rv;
    2630                 : 
    2631               0 :     if (aObserver) {
    2632               0 :         nsIObserver* obs = nsnull;
    2633               0 :         NS_ENSURE_TRUE(mOverlayLoadObservers.IsInitialized() || mOverlayLoadObservers.Init(), 
    2634                 :                        NS_ERROR_OUT_OF_MEMORY);
    2635                 :         
    2636               0 :         obs = mOverlayLoadObservers.GetWeak(uri);
    2637                 : 
    2638               0 :         if (obs) {
    2639                 :             // We don't support loading the same overlay twice into the same
    2640                 :             // document - that doesn't make sense anyway.
    2641               0 :             return NS_ERROR_FAILURE;
    2642                 :         }
    2643               0 :         mOverlayLoadObservers.Put(uri, aObserver);
    2644                 :     }
    2645                 :     bool shouldReturn, failureFromContent;
    2646               0 :     rv = LoadOverlayInternal(uri, true, &shouldReturn, &failureFromContent);
    2647               0 :     if (NS_FAILED(rv) && mOverlayLoadObservers.IsInitialized())
    2648               0 :         mOverlayLoadObservers.Remove(uri); // remove the observer if LoadOverlayInternal generated an error
    2649               0 :     return rv;
    2650                 : }
    2651                 : 
    2652                 : nsresult
    2653               0 : nsXULDocument::LoadOverlayInternal(nsIURI* aURI, bool aIsDynamic,
    2654                 :                                    bool* aShouldReturn,
    2655                 :                                    bool* aFailureFromContent)
    2656                 : {
    2657                 :     nsresult rv;
    2658                 : 
    2659               0 :     *aShouldReturn = false;
    2660               0 :     *aFailureFromContent = false;
    2661                 : 
    2662                 : #ifdef PR_LOGGING
    2663               0 :     if (PR_LOG_TEST(gXULLog, PR_LOG_DEBUG)) {
    2664               0 :         nsCAutoString urlspec;
    2665               0 :         aURI->GetSpec(urlspec);
    2666                 : 
    2667               0 :         PR_LOG(gXULLog, PR_LOG_DEBUG,
    2668                 :                 ("xul: loading overlay %s", urlspec.get()));
    2669                 :     }
    2670                 : #endif
    2671                 : 
    2672               0 :     if (aIsDynamic)
    2673               0 :         mResolutionPhase = nsForwardReference::eStart;
    2674                 : 
    2675                 :     // Chrome documents are allowed to load overlays from anywhere.
    2676                 :     // In all other cases, the overlay is only allowed to load if
    2677                 :     // the master document and prototype document have the same origin.
    2678                 : 
    2679               0 :     bool documentIsChrome = IsChromeURI(mDocumentURI);
    2680               0 :     if (!documentIsChrome) {
    2681                 :         // Make sure we're allowed to load this overlay.
    2682               0 :         rv = NodePrincipal()->CheckMayLoad(aURI, true);
    2683               0 :         if (NS_FAILED(rv)) {
    2684               0 :             *aFailureFromContent = true;
    2685               0 :             return rv;
    2686                 :         }
    2687                 :     }
    2688                 : 
    2689                 :     // Look in the prototype cache for the prototype document with
    2690                 :     // the specified overlay URI. Only use the cache if the containing
    2691                 :     // document is chrome otherwise it may not have a system principal and
    2692                 :     // the cached document will, see bug 565610.
    2693               0 :     bool overlayIsChrome = IsChromeURI(aURI);
    2694                 :     mCurrentPrototype = overlayIsChrome && documentIsChrome ?
    2695               0 :         nsXULPrototypeCache::GetInstance()->GetPrototype(aURI) : nsnull;
    2696                 : 
    2697                 :     // Same comment as nsChromeProtocolHandler::NewChannel and
    2698                 :     // nsXULDocument::StartDocumentLoad
    2699                 :     // - Ben Goodger
    2700                 :     //
    2701                 :     // We don't abort on failure here because there are too many valid
    2702                 :     // cases that can return failure, and the null-ness of |proto| is
    2703                 :     // enough to trigger the fail-safe parse-from-disk solution.
    2704                 :     // Example failure cases (for reference) include:
    2705                 :     //
    2706                 :     // NS_ERROR_NOT_AVAILABLE: the URI was not found in the FastLoad file,
    2707                 :     //                         parse from disk
    2708                 :     // other: the FastLoad file, XUL.mfl, could not be found, probably
    2709                 :     //        due to being accessed before a profile has been selected
    2710                 :     //        (e.g. loading chrome for the profile manager itself).
    2711                 :     //        The .xul file must be parsed from disk.
    2712                 : 
    2713               0 :     bool useXULCache = nsXULPrototypeCache::GetInstance()->IsEnabled();
    2714               0 :     if (useXULCache && mCurrentPrototype) {
    2715                 :         bool loaded;
    2716               0 :         rv = mCurrentPrototype->AwaitLoadDone(this, &loaded);
    2717               0 :         if (NS_FAILED(rv)) return rv;
    2718                 : 
    2719               0 :         if (! loaded) {
    2720                 :             // Return to the main event loop and eagerly await the
    2721                 :             // prototype overlay load's completion. When the content
    2722                 :             // sink completes, it will trigger an EndLoad(), which'll
    2723                 :             // wind us back up here, in ResumeWalk().
    2724               0 :             *aShouldReturn = true;
    2725               0 :             return NS_OK;
    2726                 :         }
    2727                 : 
    2728               0 :         PR_LOG(gXULLog, PR_LOG_DEBUG, ("xul: overlay was cached"));
    2729                 : 
    2730                 :         // Found the overlay's prototype in the cache, fully loaded. If
    2731                 :         // this is a dynamic overlay, this will call ResumeWalk.
    2732                 :         // Otherwise, we'll return to ResumeWalk, which called us.
    2733               0 :         return OnPrototypeLoadDone(aIsDynamic);
    2734                 :     }
    2735                 :     else {
    2736                 :         // Not there. Initiate a load.
    2737               0 :         PR_LOG(gXULLog, PR_LOG_DEBUG, ("xul: overlay was not cached"));
    2738                 : 
    2739                 :         // We'll set the right principal on the proto doc when we get
    2740                 :         // OnStartRequest from the parser, so just pass in a null principal for
    2741                 :         // now.
    2742               0 :         nsCOMPtr<nsIParser> parser;
    2743               0 :         rv = PrepareToLoadPrototype(aURI, "view", nsnull, getter_AddRefs(parser));
    2744               0 :         if (NS_FAILED(rv)) return rv;
    2745                 : 
    2746                 :         // Predicate mIsWritingFastLoad on the XUL cache being enabled,
    2747                 :         // so we don't have to re-check whether the cache is enabled all
    2748                 :         // the time.
    2749               0 :         mIsWritingFastLoad = useXULCache;
    2750                 : 
    2751               0 :         nsCOMPtr<nsIStreamListener> listener = do_QueryInterface(parser);
    2752               0 :         if (! listener)
    2753               0 :             return NS_ERROR_UNEXPECTED;
    2754                 : 
    2755                 :         // Add an observer to the parser; this'll get called when
    2756                 :         // Necko fires its On[Start|Stop]Request() notifications,
    2757                 :         // and will let us recover from a missing overlay.
    2758                 :         ParserObserver* parserObserver =
    2759               0 :             new ParserObserver(this, mCurrentPrototype);
    2760               0 :         if (! parserObserver)
    2761               0 :             return NS_ERROR_OUT_OF_MEMORY;
    2762                 : 
    2763               0 :         NS_ADDREF(parserObserver);
    2764               0 :         parser->Parse(aURI, parserObserver);
    2765               0 :         NS_RELEASE(parserObserver);
    2766                 : 
    2767               0 :         nsCOMPtr<nsILoadGroup> group = do_QueryReferent(mDocumentLoadGroup);
    2768               0 :         nsCOMPtr<nsIChannel> channel;
    2769               0 :         rv = NS_NewChannel(getter_AddRefs(channel), aURI, nsnull, group);
    2770                 : 
    2771               0 :         if (NS_SUCCEEDED(rv)) {
    2772                 :             // Set the owner of the channel to be our principal so
    2773                 :             // that the overlay's JSObjects etc end up being created
    2774                 :             // with the right principal and in the correct
    2775                 :             // compartment.
    2776               0 :             channel->SetOwner(NodePrincipal());
    2777                 : 
    2778               0 :             rv = channel->AsyncOpen(listener, nsnull);
    2779                 :         }
    2780                 : 
    2781               0 :         if (NS_FAILED(rv)) {
    2782                 :             // Abandon this prototype
    2783               0 :             mCurrentPrototype = nsnull;
    2784                 : 
    2785                 :             // The parser won't get an OnStartRequest and
    2786                 :             // OnStopRequest, so it needs a Terminate.
    2787               0 :             parser->Terminate();
    2788                 : 
    2789                 :             // Just move on to the next overlay.  NS_OpenURI could fail
    2790                 :             // just because a channel could not be opened, which can happen
    2791                 :             // if a file or chrome package does not exist.
    2792               0 :             ReportMissingOverlay(aURI);
    2793                 :             
    2794                 :             // XXX the error could indicate an internal error as well...
    2795               0 :             *aFailureFromContent = true;
    2796               0 :             return rv;
    2797                 :         }
    2798                 : 
    2799                 :         // If it's a 'chrome:' prototype document, then put it into
    2800                 :         // the prototype cache; other XUL documents will be reloaded
    2801                 :         // each time.  We must do this after NS_OpenURI and AsyncOpen,
    2802                 :         // or chrome code will wrongly create a cached chrome channel
    2803                 :         // instead of a real one. Prototypes are only cached when the
    2804                 :         // document to be overlayed is chrome to avoid caching overlay
    2805                 :         // scripts with incorrect principals, see bug 565610.
    2806               0 :         if (useXULCache && overlayIsChrome && documentIsChrome) {
    2807               0 :             nsXULPrototypeCache::GetInstance()->PutPrototype(mCurrentPrototype);
    2808                 :         }
    2809                 : 
    2810                 :         // Return to the main event loop and eagerly await the
    2811                 :         // overlay load's completion. When the content sink
    2812                 :         // completes, it will trigger an EndLoad(), which'll wind
    2813                 :         // us back in ResumeWalk().
    2814               0 :         if (!aIsDynamic)
    2815               0 :             *aShouldReturn = true;
    2816                 :     }
    2817               0 :     return NS_OK;
    2818                 : }
    2819                 : 
    2820                 : static PLDHashOperator
    2821               0 : FirePendingMergeNotification(nsIURI* aKey, nsCOMPtr<nsIObserver>& aObserver, void* aClosure)
    2822                 : {
    2823               0 :     aObserver->Observe(aKey, "xul-overlay-merged", EmptyString().get());
    2824                 : 
    2825                 :     typedef nsInterfaceHashtable<nsURIHashKey,nsIObserver> table;
    2826               0 :     table* observers = static_cast<table*>(aClosure);
    2827               0 :     observers->Remove(aKey);
    2828                 : 
    2829               0 :     return PL_DHASH_REMOVE;
    2830                 : }
    2831                 : 
    2832                 : nsresult
    2833               0 : nsXULDocument::ResumeWalk()
    2834                 : {
    2835                 :     NS_TIME_FUNCTION;
    2836                 :     // Walk the prototype and build the delegate content model. The
    2837                 :     // walk is performed in a top-down, left-to-right fashion. That
    2838                 :     // is, a parent is built before any of its children; a node is
    2839                 :     // only built after all of its siblings to the left are fully
    2840                 :     // constructed.
    2841                 :     //
    2842                 :     // It is interruptable so that transcluded documents (e.g.,
    2843                 :     // <html:script src="..." />) can be properly re-loaded if the
    2844                 :     // cached copy of the document becomes stale.
    2845                 :     nsresult rv;
    2846                 :     nsCOMPtr<nsIURI> overlayURI =
    2847               0 :         mCurrentPrototype ? mCurrentPrototype->GetURI() : nsnull;
    2848                 : 
    2849               0 :     while (1) {
    2850                 :         // Begin (or resume) walking the current prototype.
    2851                 : 
    2852               0 :         while (mContextStack.Depth() > 0) {
    2853                 :             // Look at the top of the stack to determine what we're
    2854                 :             // currently working on.
    2855                 :             // This will always be a node already constructed and
    2856                 :             // inserted to the actual document.
    2857                 :             nsXULPrototypeElement* proto;
    2858               0 :             nsCOMPtr<nsIContent> element;
    2859                 :             PRInt32 indx; // all children of proto before indx (not
    2860                 :                           // inclusive) have already been constructed
    2861               0 :             rv = mContextStack.Peek(&proto, getter_AddRefs(element), &indx);
    2862               0 :             if (NS_FAILED(rv)) return rv;
    2863                 : 
    2864               0 :             if (indx >= (PRInt32)proto->mChildren.Length()) {
    2865               0 :                 if (element) {
    2866                 :                     // We've processed all of the prototype's children. If
    2867                 :                     // we're in the master prototype, do post-order
    2868                 :                     // document-level hookup. (An overlay will get its
    2869                 :                     // document hookup done when it's successfully
    2870                 :                     // resolved.)
    2871               0 :                     if (mState == eState_Master) {
    2872               0 :                         AddElementToDocumentPost(element->AsElement());
    2873                 : 
    2874               0 :                         if (element->NodeInfo()->Equals(nsGkAtoms::style,
    2875               0 :                                                         kNameSpaceID_XHTML) ||
    2876                 :                             element->NodeInfo()->Equals(nsGkAtoms::style,
    2877               0 :                                                         kNameSpaceID_SVG)) {
    2878                 :                             // XXX sucks that we have to do this -
    2879                 :                             // see bug 370111
    2880                 :                             nsCOMPtr<nsIStyleSheetLinkingElement> ssle =
    2881               0 :                                 do_QueryInterface(element);
    2882               0 :                             NS_ASSERTION(ssle, "<html:style> doesn't implement "
    2883                 :                                                "nsIStyleSheetLinkingElement?");
    2884                 :                             bool willNotify;
    2885                 :                             bool isAlternate;
    2886               0 :                             ssle->UpdateStyleSheet(nsnull, &willNotify,
    2887               0 :                                                    &isAlternate);
    2888                 :                         }
    2889                 :                     }
    2890                 : 
    2891                 : #ifdef MOZ_XTF
    2892               0 :                     if (element->GetNameSpaceID() > kNameSpaceID_LastBuiltin) {
    2893               0 :                         element->DoneAddingChildren(false);
    2894                 :                     }
    2895                 : #endif
    2896                 :                 }
    2897                 :                 // Now pop the context stack back up to the parent
    2898                 :                 // element and continue the prototype walk.
    2899               0 :                 mContextStack.Pop();
    2900               0 :                 continue;
    2901                 :             }
    2902                 : 
    2903                 :             // Grab the next child, and advance the current context stack
    2904                 :             // to the next sibling to our right.
    2905               0 :             nsXULPrototypeNode* childproto = proto->mChildren[indx];
    2906               0 :             mContextStack.SetTopIndex(++indx);
    2907                 : 
    2908                 :             // Whether we're in the "first ply" of an overlay:
    2909                 :             // the "hookup" nodes. In the case !processingOverlayHookupNodes,
    2910                 :             // we're in the master document -or- we're in an overlay, and far
    2911                 :             // enough down into the overlay's content that we can simply build
    2912                 :             // the delegates and attach them to the parent node.
    2913                 :             bool processingOverlayHookupNodes = (mState == eState_Overlay) && 
    2914               0 :                                                   (mContextStack.Depth() == 1);
    2915                 : 
    2916               0 :             NS_ASSERTION(element || processingOverlayHookupNodes,
    2917                 :                          "no element on context stack");
    2918                 : 
    2919               0 :             switch (childproto->mType) {
    2920                 :             case nsXULPrototypeNode::eType_Element: {
    2921                 :                 // An 'element', which may contain more content.
    2922                 :                 nsXULPrototypeElement* protoele =
    2923               0 :                     static_cast<nsXULPrototypeElement*>(childproto);
    2924                 : 
    2925               0 :                 nsRefPtr<Element> child;
    2926                 : 
    2927               0 :                 if (!processingOverlayHookupNodes) {
    2928                 :                     rv = CreateElementFromPrototype(protoele,
    2929               0 :                                                     getter_AddRefs(child));
    2930               0 :                     if (NS_FAILED(rv)) return rv;
    2931                 : 
    2932                 :                     // ...and append it to the content model.
    2933               0 :                     rv = element->AppendChildTo(child, false);
    2934               0 :                     if (NS_FAILED(rv)) return rv;
    2935                 : 
    2936                 :                     // do pre-order document-level hookup, but only if
    2937                 :                     // we're in the master document. For an overlay,
    2938                 :                     // this will happen when the overlay is
    2939                 :                     // successfully resolved.
    2940               0 :                     if (mState == eState_Master)
    2941               0 :                         AddElementToDocumentPre(child);
    2942                 :                 }
    2943                 :                 else {
    2944                 :                     // We're in the "first ply" of an overlay: the
    2945                 :                     // "hookup" nodes. Create an 'overlay' element so
    2946                 :                     // that we can continue to build content, and
    2947                 :                     // enter a forward reference so we can hook it up
    2948                 :                     // later.
    2949               0 :                     rv = CreateOverlayElement(protoele, getter_AddRefs(child));
    2950               0 :                     if (NS_FAILED(rv)) return rv;
    2951                 :                 }
    2952                 : 
    2953                 :                 // If it has children, push the element onto the context
    2954                 :                 // stack and begin to process them.
    2955               0 :                 if (protoele->mChildren.Length() > 0) {
    2956               0 :                     rv = mContextStack.Push(protoele, child);
    2957               0 :                     if (NS_FAILED(rv)) return rv;
    2958                 :                 }
    2959                 :                 else {
    2960               0 :                     if (mState == eState_Master) {
    2961                 :                         // If there are no children, and we're in the
    2962                 :                         // master document, do post-order document hookup
    2963                 :                         // immediately.
    2964               0 :                         AddElementToDocumentPost(child);
    2965                 :                     }
    2966                 : #ifdef MOZ_XTF
    2967               0 :                     if (child &&
    2968               0 :                         child->GetNameSpaceID() > kNameSpaceID_LastBuiltin) {
    2969               0 :                         child->DoneAddingChildren(false);
    2970                 :                     }
    2971                 : #endif
    2972                 :                 }
    2973                 :             }
    2974               0 :             break;
    2975                 : 
    2976                 :             case nsXULPrototypeNode::eType_Script: {
    2977                 :                 // A script reference. Execute the script immediately;
    2978                 :                 // this may have side effects in the content model.
    2979                 :                 nsXULPrototypeScript* scriptproto =
    2980               0 :                     static_cast<nsXULPrototypeScript*>(childproto);
    2981                 : 
    2982               0 :                 if (scriptproto->mSrcURI) {
    2983                 :                     // A transcluded script reference; this may
    2984                 :                     // "block" our prototype walk if the script isn't
    2985                 :                     // cached, or the cached copy of the script is
    2986                 :                     // stale and must be reloaded.
    2987                 :                     bool blocked;
    2988               0 :                     rv = LoadScript(scriptproto, &blocked);
    2989                 :                     // If the script cannot be loaded, just keep going!
    2990                 : 
    2991               0 :                     if (NS_SUCCEEDED(rv) && blocked)
    2992               0 :                         return NS_OK;
    2993                 :                 }
    2994               0 :                 else if (scriptproto->mScriptObject.mObject) {
    2995                 :                     // An inline script
    2996               0 :                     rv = ExecuteScript(scriptproto);
    2997               0 :                     if (NS_FAILED(rv)) return rv;
    2998                 :                 }
    2999                 :             }
    3000               0 :             break;
    3001                 : 
    3002                 :             case nsXULPrototypeNode::eType_Text: {
    3003                 :                 // A simple text node.
    3004                 : 
    3005               0 :                 if (!processingOverlayHookupNodes) {
    3006                 :                     // This does mean that text nodes that are direct children
    3007                 :                     // of <overlay> get ignored.
    3008                 : 
    3009               0 :                     nsCOMPtr<nsIContent> text;
    3010               0 :                     rv = NS_NewTextNode(getter_AddRefs(text),
    3011               0 :                                         mNodeInfoManager);
    3012               0 :                     NS_ENSURE_SUCCESS(rv, rv);
    3013                 : 
    3014                 :                     nsXULPrototypeText* textproto =
    3015               0 :                         static_cast<nsXULPrototypeText*>(childproto);
    3016               0 :                     text->SetText(textproto->mValue, false);
    3017                 : 
    3018               0 :                     rv = element->AppendChildTo(text, false);
    3019               0 :                     NS_ENSURE_SUCCESS(rv, rv);
    3020                 :                 }
    3021                 :             }
    3022               0 :             break;
    3023                 : 
    3024                 :             case nsXULPrototypeNode::eType_PI: {
    3025                 :                 nsXULPrototypePI* piProto =
    3026               0 :                     static_cast<nsXULPrototypePI*>(childproto);
    3027                 : 
    3028                 :                 // <?xul-overlay?> and <?xml-stylesheet?> don't have effect
    3029                 :                 // outside the prolog, like they used to. Issue a warning.
    3030                 : 
    3031               0 :                 if (piProto->mTarget.EqualsLiteral("xml-stylesheet") ||
    3032               0 :                     piProto->mTarget.EqualsLiteral("xul-overlay")) {
    3033                 : 
    3034               0 :                     const PRUnichar* params[] = { piProto->mTarget.get() };
    3035                 : 
    3036                 :                     nsContentUtils::ReportToConsole(
    3037                 :                                         nsIScriptError::warningFlag,
    3038                 :                                         "XUL Document", nsnull,
    3039                 :                                         nsContentUtils::eXUL_PROPERTIES,
    3040                 :                                         "PINotInProlog",
    3041                 :                                         params, ArrayLength(params),
    3042               0 :                                         overlayURI);
    3043                 :                 }
    3044                 : 
    3045                 :                 nsIContent* parent = processingOverlayHookupNodes ?
    3046               0 :                     GetRootElement() : element.get();
    3047                 : 
    3048               0 :                 if (parent) {
    3049                 :                     // an inline script could have removed the root element
    3050                 :                     rv = CreateAndInsertPI(piProto, parent,
    3051               0 :                                            parent->GetChildCount());
    3052               0 :                     NS_ENSURE_SUCCESS(rv, rv);
    3053                 :                 }
    3054                 :             }
    3055               0 :             break;
    3056                 : 
    3057                 :             default:
    3058               0 :                 NS_NOTREACHED("Unexpected nsXULPrototypeNode::Type value");
    3059                 :             }
    3060                 :         }
    3061                 : 
    3062                 :         // Once we get here, the context stack will have been
    3063                 :         // depleted. That means that the entire prototype has been
    3064                 :         // walked and content has been constructed.
    3065                 : 
    3066                 :         // If we're not already, mark us as now processing overlays.
    3067               0 :         mState = eState_Overlay;
    3068                 : 
    3069                 :         // If there are no overlay URIs, then we're done.
    3070               0 :         PRUint32 count = mUnloadedOverlays.Count();
    3071               0 :         if (! count)
    3072                 :             break;
    3073                 : 
    3074               0 :         nsCOMPtr<nsIURI> uri = mUnloadedOverlays[count-1];
    3075               0 :         mUnloadedOverlays.RemoveObjectAt(count-1);
    3076                 : 
    3077                 :         bool shouldReturn, failureFromContent;
    3078                 :         rv = LoadOverlayInternal(uri, false, &shouldReturn,
    3079               0 :                                  &failureFromContent);
    3080               0 :         if (failureFromContent)
    3081                 :             // The failure |rv| was the result of a problem in the content
    3082                 :             // rather than an unexpected problem in our implementation, so
    3083                 :             // just continue with the next overlay.
    3084               0 :             continue;
    3085               0 :         if (NS_FAILED(rv))
    3086               0 :             return rv;
    3087               0 :         if (mOverlayLoadObservers.IsInitialized()) {
    3088               0 :             nsIObserver *obs = mOverlayLoadObservers.GetWeak(overlayURI);
    3089               0 :             if (obs) {
    3090                 :                 // This overlay has an unloaded overlay, so it will never
    3091                 :                 // notify. The best we can do is to notify for the unloaded
    3092                 :                 // overlay instead, assuming nobody is already notifiable
    3093                 :                 // for it. Note that this will confuse the observer.
    3094               0 :                 if (!mOverlayLoadObservers.GetWeak(uri))
    3095               0 :                     mOverlayLoadObservers.Put(uri, obs);
    3096               0 :                 mOverlayLoadObservers.Remove(overlayURI);
    3097                 :             }
    3098                 :         }
    3099               0 :         if (shouldReturn)
    3100               0 :             return NS_OK;
    3101               0 :         overlayURI.swap(uri);
    3102                 :     }
    3103                 : 
    3104                 :     // If we get here, there is nothing left for us to walk. The content
    3105                 :     // model is built and ready for layout.
    3106               0 :     rv = ResolveForwardReferences();
    3107               0 :     if (NS_FAILED(rv)) return rv;
    3108                 : 
    3109               0 :     ApplyPersistentAttributes();
    3110                 : 
    3111               0 :     mStillWalking = false;
    3112               0 :     if (mPendingSheets == 0) {
    3113               0 :         rv = DoneWalking();
    3114                 :     }
    3115               0 :     return rv;
    3116                 : }
    3117                 : 
    3118                 : nsresult
    3119               0 : nsXULDocument::DoneWalking()
    3120                 : {
    3121               0 :     NS_PRECONDITION(mPendingSheets == 0, "there are sheets to be loaded");
    3122               0 :     NS_PRECONDITION(!mStillWalking, "walk not done");
    3123                 : 
    3124                 :     // XXXldb This is where we should really be setting the chromehidden
    3125                 :     // attribute.
    3126                 : 
    3127               0 :     PRUint32 count = mOverlaySheets.Length();
    3128               0 :     for (PRUint32 i = 0; i < count; ++i) {
    3129               0 :         AddStyleSheet(mOverlaySheets[i]);
    3130                 :     }
    3131               0 :     mOverlaySheets.Clear();
    3132                 : 
    3133               0 :     if (!mDocumentLoaded) {
    3134                 :         // Make sure we don't reenter here from StartLayout().  Note that
    3135                 :         // setting mDocumentLoaded to true here means that if StartLayout()
    3136                 :         // causes ResumeWalk() to be reentered, we'll take the other branch of
    3137                 :         // the |if (!mDocumentLoaded)| check above and since
    3138                 :         // mInitialLayoutComplete will be false will follow the else branch
    3139                 :         // there too.  See the big comment there for how such reentry can
    3140                 :         // happen.
    3141               0 :         mDocumentLoaded = true;
    3142                 : 
    3143               0 :         NotifyPossibleTitleChange(false);
    3144                 : 
    3145                 :         // Before starting layout, check whether we're a toplevel chrome
    3146                 :         // window.  If we are, set our chrome flags now, so that we don't have
    3147                 :         // to restyle the whole frame tree after StartLayout.
    3148               0 :         nsCOMPtr<nsISupports> container = GetContainer();
    3149               0 :         nsCOMPtr<nsIDocShellTreeItem> item = do_QueryInterface(container);
    3150               0 :         if (item) {
    3151               0 :             nsCOMPtr<nsIDocShellTreeOwner> owner;
    3152               0 :             item->GetTreeOwner(getter_AddRefs(owner));
    3153               0 :             nsCOMPtr<nsIXULWindow> xulWin = do_GetInterface(owner);
    3154               0 :             if (xulWin) {
    3155               0 :                 nsCOMPtr<nsIDocShell> xulWinShell;
    3156               0 :                 xulWin->GetDocShell(getter_AddRefs(xulWinShell));
    3157               0 :                 if (SameCOMIdentity(xulWinShell, container)) {
    3158                 :                     // We're the chrome document!  Apply our chrome flags now.
    3159               0 :                     xulWin->ApplyChromeFlags();
    3160                 :                 }
    3161                 :             }
    3162                 :         }
    3163                 : 
    3164               0 :         StartLayout();
    3165                 : 
    3166               0 :         if (mIsWritingFastLoad && IsChromeURI(mDocumentURI))
    3167               0 :             nsXULPrototypeCache::GetInstance()->WritePrototype(mMasterPrototype);
    3168                 : 
    3169               0 :         NS_ASSERTION(mDelayFrameLoaderInitialization,
    3170                 :                      "mDelayFrameLoaderInitialization should be true!");
    3171               0 :         mDelayFrameLoaderInitialization = false;
    3172               0 :         NS_WARN_IF_FALSE(mUpdateNestLevel == 0,
    3173                 :                          "Constructing XUL document in middle of an update?");
    3174               0 :         if (mUpdateNestLevel == 0) {
    3175               0 :             MaybeInitializeFinalizeFrameLoaders();
    3176                 :         }
    3177                 : 
    3178               0 :         NS_DOCUMENT_NOTIFY_OBSERVERS(EndLoad, (this));
    3179                 : 
    3180                 :         // DispatchContentLoadedEvents undoes the onload-blocking we
    3181                 :         // did in PrepareToWalk().
    3182               0 :         DispatchContentLoadedEvents();
    3183                 : 
    3184               0 :         mInitialLayoutComplete = true;
    3185                 : 
    3186                 :         // Walk the set of pending load notifications and notify any observers.
    3187                 :         // See below for detail.
    3188               0 :         if (mPendingOverlayLoadNotifications.IsInitialized())
    3189               0 :             mPendingOverlayLoadNotifications.Enumerate(FirePendingMergeNotification, (void*)&mOverlayLoadObservers);
    3190                 :     }
    3191                 :     else {
    3192               0 :         if (mOverlayLoadObservers.IsInitialized()) {
    3193               0 :             nsCOMPtr<nsIURI> overlayURI = mCurrentPrototype->GetURI();
    3194               0 :             nsCOMPtr<nsIObserver> obs;
    3195               0 :             if (mInitialLayoutComplete) {
    3196                 :                 // We have completed initial layout, so just send the notification.
    3197               0 :                 mOverlayLoadObservers.Get(overlayURI, getter_AddRefs(obs));
    3198               0 :                 if (obs)
    3199               0 :                     obs->Observe(overlayURI, "xul-overlay-merged", EmptyString().get());
    3200               0 :                 mOverlayLoadObservers.Remove(overlayURI);
    3201                 :             }
    3202                 :             else {
    3203                 :                 // If we have not yet displayed the document for the first time 
    3204                 :                 // (i.e. we came in here as the result of a dynamic overlay load
    3205                 :                 // which was spawned by a binding-attached event caused by 
    3206                 :                 // StartLayout() on the master prototype - we must remember that
    3207                 :                 // this overlay has been merged and tell the listeners after 
    3208                 :                 // StartLayout() is completely finished rather than doing so 
    3209                 :                 // immediately - otherwise we may be executing code that needs to
    3210                 :                 // access XBL Binding implementations on nodes for which frames 
    3211                 :                 // have not yet been constructed because their bindings have not
    3212                 :                 // yet been attached. This can be a race condition because dynamic
    3213                 :                 // overlay loading can take varying amounts of time depending on
    3214                 :                 // whether or not the overlay prototype is in the XUL cache. The
    3215                 :                 // most likely effect of this bug is odd UI initialization due to
    3216                 :                 // methods and properties that do not work.
    3217                 :                 // XXXbz really, we shouldn't be firing binding constructors
    3218                 :                 // until after StartLayout returns!
    3219                 : 
    3220               0 :                 NS_ENSURE_TRUE(mPendingOverlayLoadNotifications.IsInitialized() || mPendingOverlayLoadNotifications.Init(), 
    3221                 :                                NS_ERROR_OUT_OF_MEMORY);
    3222                 :                 
    3223               0 :                 mPendingOverlayLoadNotifications.Get(overlayURI, getter_AddRefs(obs));
    3224               0 :                 if (!obs) {
    3225               0 :                     mOverlayLoadObservers.Get(overlayURI, getter_AddRefs(obs));
    3226               0 :                     NS_ASSERTION(obs, "null overlay load observer?");
    3227               0 :                     mPendingOverlayLoadNotifications.Put(overlayURI, obs);
    3228                 :                 }
    3229                 :             }
    3230                 :         }
    3231                 :     }
    3232                 : 
    3233               0 :     return NS_OK;
    3234                 : }
    3235                 : 
    3236                 : NS_IMETHODIMP
    3237               0 : nsXULDocument::StyleSheetLoaded(nsCSSStyleSheet* aSheet,
    3238                 :                                 bool aWasAlternate,
    3239                 :                                 nsresult aStatus)
    3240                 : {
    3241               0 :     if (!aWasAlternate) {
    3242                 :         // Don't care about when alternate sheets finish loading
    3243                 : 
    3244               0 :         NS_ASSERTION(mPendingSheets > 0,
    3245                 :             "Unexpected StyleSheetLoaded notification");
    3246                 : 
    3247               0 :         --mPendingSheets;
    3248                 : 
    3249               0 :         if (!mStillWalking && mPendingSheets == 0) {
    3250               0 :             return DoneWalking();
    3251                 :         }
    3252                 :     }
    3253                 : 
    3254               0 :     return NS_OK;
    3255                 : }
    3256                 : 
    3257                 : void
    3258               0 : nsXULDocument::MaybeBroadcast()
    3259                 : {
    3260                 :     // Only broadcast when not in an update and when safe to run scripts.
    3261               0 :     if (mUpdateNestLevel == 0 &&
    3262               0 :         (mDelayedAttrChangeBroadcasts.Length() ||
    3263               0 :          mDelayedBroadcasters.Length())) {
    3264               0 :         if (!nsContentUtils::IsSafeToRunScript()) {
    3265               0 :             if (!mInDestructor) {
    3266                 :                 nsContentUtils::AddScriptRunner(
    3267               0 :                     NS_NewRunnableMethod(this, &nsXULDocument::MaybeBroadcast));
    3268                 :             }
    3269               0 :             return;
    3270                 :         }
    3271               0 :         if (!mHandlingDelayedAttrChange) {
    3272               0 :             mHandlingDelayedAttrChange = true;
    3273               0 :             for (PRUint32 i = 0; i < mDelayedAttrChangeBroadcasts.Length(); ++i) {
    3274               0 :                 nsIAtom* attrName = mDelayedAttrChangeBroadcasts[i].mAttrName;
    3275               0 :                 if (mDelayedAttrChangeBroadcasts[i].mNeedsAttrChange) {
    3276                 :                     nsCOMPtr<nsIContent> listener =
    3277               0 :                         do_QueryInterface(mDelayedAttrChangeBroadcasts[i].mListener);
    3278               0 :                     nsString value = mDelayedAttrChangeBroadcasts[i].mAttr;
    3279               0 :                     if (mDelayedAttrChangeBroadcasts[i].mSetAttr) {
    3280                 :                         listener->SetAttr(kNameSpaceID_None, attrName, value,
    3281               0 :                                           true);
    3282                 :                     } else {
    3283               0 :                         listener->UnsetAttr(kNameSpaceID_None, attrName,
    3284               0 :                                             true);
    3285                 :                     }
    3286                 :                 }
    3287                 :                 nsCOMPtr<nsIContent> broadcaster =
    3288               0 :                     do_QueryInterface(mDelayedAttrChangeBroadcasts[i].mBroadcaster);
    3289                 :                 ExecuteOnBroadcastHandlerFor(broadcaster,
    3290               0 :                                              mDelayedAttrChangeBroadcasts[i].mListener,
    3291               0 :                                              attrName);
    3292                 :             }
    3293               0 :             mDelayedAttrChangeBroadcasts.Clear();
    3294               0 :             mHandlingDelayedAttrChange = false;
    3295                 :         }
    3296                 : 
    3297               0 :         PRUint32 length = mDelayedBroadcasters.Length();
    3298               0 :         if (length) {
    3299               0 :             bool oldValue = mHandlingDelayedBroadcasters;
    3300               0 :             mHandlingDelayedBroadcasters = true;
    3301               0 :             nsTArray<nsDelayedBroadcastUpdate> delayedBroadcasters;
    3302               0 :             mDelayedBroadcasters.SwapElements(delayedBroadcasters);
    3303               0 :             for (PRUint32 i = 0; i < length; ++i) {
    3304               0 :                 SynchronizeBroadcastListener(delayedBroadcasters[i].mBroadcaster,
    3305               0 :                                              delayedBroadcasters[i].mListener,
    3306               0 :                                              delayedBroadcasters[i].mAttr);
    3307                 :             }
    3308               0 :             mHandlingDelayedBroadcasters = oldValue;
    3309                 :         }
    3310                 :     }
    3311                 : }
    3312                 : 
    3313                 : void
    3314               0 : nsXULDocument::EndUpdate(nsUpdateType aUpdateType)
    3315                 : {
    3316               0 :     nsXMLDocument::EndUpdate(aUpdateType);
    3317                 : 
    3318               0 :     MaybeBroadcast();
    3319               0 : }
    3320                 : 
    3321                 : void
    3322               0 : nsXULDocument::ReportMissingOverlay(nsIURI* aURI)
    3323                 : {
    3324               0 :     NS_PRECONDITION(aURI, "Must have a URI");
    3325                 :     
    3326               0 :     nsCAutoString spec;
    3327               0 :     aURI->GetSpec(spec);
    3328                 : 
    3329               0 :     NS_ConvertUTF8toUTF16 utfSpec(spec);
    3330               0 :     const PRUnichar* params[] = { utfSpec.get() };
    3331                 :     nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
    3332                 :                                     "XUL Document", this,
    3333                 :                                     nsContentUtils::eXUL_PROPERTIES,
    3334                 :                                     "MissingOverlay",
    3335               0 :                                     params, ArrayLength(params));
    3336               0 : }
    3337                 : 
    3338                 : nsresult
    3339               0 : nsXULDocument::LoadScript(nsXULPrototypeScript* aScriptProto, bool* aBlock)
    3340                 : {
    3341                 :     // Load a transcluded script
    3342                 :     nsresult rv;
    3343                 : 
    3344               0 :     bool isChromeDoc = IsChromeURI(mDocumentURI);
    3345                 : 
    3346               0 :     if (isChromeDoc && aScriptProto->mScriptObject.mObject) {
    3347               0 :         rv = ExecuteScript(aScriptProto);
    3348                 : 
    3349                 :         // Ignore return value from execution, and don't block
    3350               0 :         *aBlock = false;
    3351               0 :         return NS_OK;
    3352                 :     }
    3353                 : 
    3354                 :     // Try the XUL script cache, in case two XUL documents source the same
    3355                 :     // .js file (e.g., strres.js from navigator.xul and utilityOverlay.xul).
    3356                 :     // XXXbe the cache relies on aScriptProto's GC root!
    3357               0 :     bool useXULCache = nsXULPrototypeCache::GetInstance()->IsEnabled();
    3358                 : 
    3359               0 :     if (isChromeDoc && useXULCache) {
    3360               0 :         PRUint32 fetchedLang = nsIProgrammingLanguage::UNKNOWN;
    3361                 :         JSScript* newScriptObject =
    3362                 :             nsXULPrototypeCache::GetInstance()->GetScript(
    3363                 :                                    aScriptProto->mSrcURI,
    3364               0 :                                    &fetchedLang);
    3365               0 :         if (newScriptObject) {
    3366                 :             // The script language for a proto must remain constant - we
    3367                 :             // can't just change it for this unexpected language.
    3368               0 :             if (aScriptProto->mScriptObject.mLangID != fetchedLang) {
    3369               0 :                 NS_ERROR("XUL cache gave me an incorrect script language");
    3370               0 :                 return NS_ERROR_UNEXPECTED;
    3371                 :             }
    3372               0 :             aScriptProto->Set(newScriptObject);
    3373                 :         }
    3374                 : 
    3375               0 :         if (aScriptProto->mScriptObject.mObject) {
    3376               0 :             rv = ExecuteScript(aScriptProto);
    3377                 : 
    3378                 :             // Ignore return value from execution, and don't block
    3379               0 :             *aBlock = false;
    3380               0 :             return NS_OK;
    3381                 :         }
    3382                 :     }
    3383                 : 
    3384                 :     // Allow security manager and content policies to veto the load. Note that
    3385                 :     // at this point we already lost context information of the script.
    3386                 :     rv = nsScriptLoader::ShouldLoadScript(
    3387                 :                             this,
    3388                 :                             static_cast<nsIDocument*>(this),
    3389                 :                             aScriptProto->mSrcURI,
    3390               0 :                             NS_LITERAL_STRING("application/x-javascript"));
    3391               0 :     if (NS_FAILED(rv)) {
    3392               0 :       *aBlock = false;
    3393               0 :       return rv;
    3394                 :     }
    3395                 : 
    3396                 :     // Release script objects from FastLoad since we decided against using them
    3397               0 :     aScriptProto->UnlinkJSObjects();
    3398                 : 
    3399                 :     // Set the current script prototype so that OnStreamComplete can report
    3400                 :     // the right file if there are errors in the script.
    3401               0 :     NS_ASSERTION(!mCurrentScriptProto,
    3402                 :                  "still loading a script when starting another load?");
    3403               0 :     mCurrentScriptProto = aScriptProto;
    3404                 : 
    3405               0 :     if (aScriptProto->mSrcLoading) {
    3406                 :         // Another XULDocument load has started, which is still in progress.
    3407                 :         // Remember to ResumeWalk this document when the load completes.
    3408               0 :         mNextSrcLoadWaiter = aScriptProto->mSrcLoadWaiters;
    3409               0 :         aScriptProto->mSrcLoadWaiters = this;
    3410               0 :         NS_ADDREF_THIS();
    3411                 :     }
    3412                 :     else {
    3413               0 :         nsCOMPtr<nsILoadGroup> group = do_QueryReferent(mDocumentLoadGroup);
    3414                 : 
    3415                 :         // Note: the loader will keep itself alive while it's loading.
    3416               0 :         nsCOMPtr<nsIStreamLoader> loader;
    3417               0 :         rv = NS_NewStreamLoader(getter_AddRefs(loader), aScriptProto->mSrcURI,
    3418               0 :                                 this, nsnull, group);
    3419               0 :         if (NS_FAILED(rv)) {
    3420               0 :             mCurrentScriptProto = nsnull;
    3421               0 :             return rv;
    3422                 :         }
    3423                 : 
    3424               0 :         aScriptProto->mSrcLoading = true;
    3425                 :     }
    3426                 : 
    3427                 :     // Block until OnStreamComplete resumes us.
    3428               0 :     *aBlock = true;
    3429               0 :     return NS_OK;
    3430                 : }
    3431                 : 
    3432                 : 
    3433                 : NS_IMETHODIMP
    3434               0 : nsXULDocument::OnStreamComplete(nsIStreamLoader* aLoader,
    3435                 :                                 nsISupports* context,
    3436                 :                                 nsresult aStatus,
    3437                 :                                 PRUint32 stringLen,
    3438                 :                                 const PRUint8* string)
    3439                 : {
    3440               0 :     nsCOMPtr<nsIRequest> request;
    3441               0 :     aLoader->GetRequest(getter_AddRefs(request));
    3442               0 :     nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
    3443                 : 
    3444                 : #ifdef DEBUG
    3445                 :     // print a load error on bad status
    3446               0 :     if (NS_FAILED(aStatus)) {
    3447               0 :         if (channel) {
    3448               0 :             nsCOMPtr<nsIURI> uri;
    3449               0 :             channel->GetURI(getter_AddRefs(uri));
    3450               0 :             if (uri) {
    3451               0 :                 nsCAutoString uriSpec;
    3452               0 :                 uri->GetSpec(uriSpec);
    3453               0 :                 printf("Failed to load %s\n", uriSpec.get());
    3454                 :             }
    3455                 :         }
    3456                 :     }
    3457                 : #endif
    3458                 : 
    3459                 :     // This is the completion routine that will be called when a
    3460                 :     // transcluded script completes. Compile and execute the script
    3461                 :     // if the load was successful, then continue building content
    3462                 :     // from the prototype.
    3463                 :     nsresult rv;
    3464                 : 
    3465               0 :     NS_ASSERTION(mCurrentScriptProto && mCurrentScriptProto->mSrcLoading,
    3466                 :                  "script source not loading on unichar stream complete?");
    3467               0 :     if (!mCurrentScriptProto) {
    3468                 :         // XXX Wallpaper for bug 270042
    3469               0 :         return NS_OK;
    3470                 :     }
    3471                 : 
    3472                 :     // Clear mCurrentScriptProto now, but save it first for use below in
    3473                 :     // the compile/execute code, and in the while loop that resumes walks
    3474                 :     // of other documents that raced to load this script
    3475               0 :     nsXULPrototypeScript* scriptProto = mCurrentScriptProto;
    3476               0 :     mCurrentScriptProto = nsnull;
    3477                 : 
    3478                 :     // Clear the prototype's loading flag before executing the script or
    3479                 :     // resuming document walks, in case any of those control flows starts a
    3480                 :     // new script load.
    3481               0 :     scriptProto->mSrcLoading = false;
    3482                 : 
    3483               0 :     if (NS_SUCCEEDED(aStatus)) {
    3484                 :         // If the including XUL document is a FastLoad document, and we're
    3485                 :         // compiling an out-of-line script (one with src=...), then we must
    3486                 :         // be writing a new FastLoad file.  If we were reading this script
    3487                 :         // from the FastLoad file, XULContentSinkImpl::OpenScript (over in
    3488                 :         // nsXULContentSink.cpp) would have already deserialized a non-null
    3489                 :         // script->mScriptObject, causing control flow at the top of LoadScript
    3490                 :         // not to reach here.
    3491               0 :         nsCOMPtr<nsIURI> uri = scriptProto->mSrcURI;
    3492                 : 
    3493                 :         // XXX should also check nsIHttpChannel::requestSucceeded
    3494                 : 
    3495               0 :         nsString stringStr;
    3496                 :         rv = nsScriptLoader::ConvertToUTF16(channel, string, stringLen,
    3497               0 :                                             EmptyString(), this, stringStr);
    3498               0 :         if (NS_SUCCEEDED(rv)) {
    3499               0 :             rv = scriptProto->Compile(stringStr.get(), stringStr.Length(),
    3500               0 :                                       uri, 1, this, mCurrentPrototype);
    3501                 :         }
    3502                 : 
    3503               0 :         aStatus = rv;
    3504               0 :         if (NS_SUCCEEDED(rv)) {
    3505               0 :             if (nsScriptLoader::ShouldExecuteScript(this, channel)) {
    3506               0 :                 rv = ExecuteScript(scriptProto);
    3507                 :             }
    3508                 : 
    3509                 :             // If the XUL cache is enabled, save the script object there in
    3510                 :             // case different XUL documents source the same script.
    3511                 :             //
    3512                 :             // But don't save the script in the cache unless the master XUL
    3513                 :             // document URL is a chrome: URL.  It is valid for a URL such as
    3514                 :             // about:config to translate into a master document URL, whose
    3515                 :             // prototype document nodes -- including prototype scripts that
    3516                 :             // hold GC roots protecting their mJSObject pointers -- are not
    3517                 :             // cached in the XUL prototype cache.  See StartDocumentLoad,
    3518                 :             // the fillXULCache logic.
    3519                 :             //
    3520                 :             // A document such as about:config is free to load a script via
    3521                 :             // a URL such as chrome://global/content/config.js, and we must
    3522                 :             // not cache that script object without a prototype cache entry
    3523                 :             // containing a companion nsXULPrototypeScript node that owns a
    3524                 :             // GC root protecting the script object.  Otherwise, the script
    3525                 :             // cache entry will dangle once the uncached prototype document
    3526                 :             // is released when its owning nsXULDocument is unloaded.
    3527                 :             //
    3528                 :             // (See http://bugzilla.mozilla.org/show_bug.cgi?id=98207 for
    3529                 :             // the true crime story.)
    3530               0 :             bool useXULCache = nsXULPrototypeCache::GetInstance()->IsEnabled();
    3531                 :   
    3532               0 :             if (useXULCache && IsChromeURI(mDocumentURI)) {
    3533                 :                 nsXULPrototypeCache::GetInstance()->PutScript(
    3534                 :                                    scriptProto->mSrcURI,
    3535                 :                                    scriptProto->mScriptObject.mLangID,
    3536               0 :                                    scriptProto->mScriptObject.mObject);
    3537                 :             }
    3538                 : 
    3539               0 :             if (mIsWritingFastLoad && mCurrentPrototype != mMasterPrototype) {
    3540                 :                 // If we are loading an overlay script, try to serialize
    3541                 :                 // it to the FastLoad file here.  Master scripts will be
    3542                 :                 // serialized when the master prototype document gets
    3543                 :                 // written, at the bottom of ResumeWalk.  That way, master
    3544                 :                 // out-of-line scripts are serialized in the same order that
    3545                 :                 // they'll be read, in the FastLoad file, which reduces the
    3546                 :                 // number of seeks that dump the underlying stream's buffer.
    3547                 :                 //
    3548                 :                 // Ignore the return value, as we don't need to propagate
    3549                 :                 // a failure to write to the FastLoad file, because this
    3550                 :                 // method aborts that whole process on error.
    3551                 :                 nsIScriptGlobalObject* global =
    3552               0 :                     mCurrentPrototype->GetScriptGlobalObject();
    3553                 : 
    3554               0 :                 NS_ASSERTION(global != nsnull, "master prototype w/o global?!");
    3555               0 :                 if (global) {
    3556               0 :                     PRUint32 stid = scriptProto->mScriptObject.mLangID;
    3557                 :                     nsIScriptContext *scriptContext = \
    3558               0 :                           global->GetScriptContext(stid);
    3559               0 :                     NS_ASSERTION(scriptContext != nsnull,
    3560                 :                                  "Failed to get script context for language");
    3561               0 :                     if (scriptContext)
    3562               0 :                         scriptProto->SerializeOutOfLine(nsnull, global);
    3563                 :                 }
    3564                 :             }
    3565                 :         }
    3566                 :         // ignore any evaluation errors
    3567                 :     }
    3568                 : 
    3569               0 :     rv = ResumeWalk();
    3570                 : 
    3571                 :     // Load a pointer to the prototype-script's list of nsXULDocuments who
    3572                 :     // raced to load the same script
    3573               0 :     nsXULDocument** docp = &scriptProto->mSrcLoadWaiters;
    3574                 : 
    3575                 :     // Resume walking other documents that waited for this one's load, first
    3576                 :     // executing the script we just compiled, in each doc's script context
    3577                 :     nsXULDocument* doc;
    3578               0 :     while ((doc = *docp) != nsnull) {
    3579               0 :         NS_ASSERTION(doc->mCurrentScriptProto == scriptProto,
    3580                 :                      "waiting for wrong script to load?");
    3581               0 :         doc->mCurrentScriptProto = nsnull;
    3582                 : 
    3583                 :         // Unlink doc from scriptProto's list before executing and resuming
    3584               0 :         *docp = doc->mNextSrcLoadWaiter;
    3585               0 :         doc->mNextSrcLoadWaiter = nsnull;
    3586                 : 
    3587                 :         // Execute only if we loaded and compiled successfully, then resume
    3588               0 :         if (NS_SUCCEEDED(aStatus) && scriptProto->mScriptObject.mObject &&
    3589               0 :             nsScriptLoader::ShouldExecuteScript(doc, channel)) {
    3590               0 :             doc->ExecuteScript(scriptProto);
    3591                 :         }
    3592               0 :         doc->ResumeWalk();
    3593               0 :         NS_RELEASE(doc);
    3594                 :     }
    3595                 : 
    3596               0 :     return rv;
    3597                 : }
    3598                 : 
    3599                 : 
    3600                 : nsresult
    3601               0 : nsXULDocument::ExecuteScript(nsIScriptContext * aContext, JSScript* aScriptObject)
    3602                 : {
    3603               0 :     NS_PRECONDITION(aScriptObject != nsnull && aContext != nsnull, "null ptr");
    3604               0 :     if (! aScriptObject || ! aContext)
    3605               0 :         return NS_ERROR_NULL_POINTER;
    3606                 : 
    3607               0 :     NS_ENSURE_TRUE(mScriptGlobalObject, NS_ERROR_NOT_INITIALIZED);
    3608                 : 
    3609               0 :     NS_ABORT_IF_FALSE(aContext->GetScriptTypeID() == nsIProgrammingLanguage::JAVASCRIPT,
    3610                 :                       "Should have a JavaScript nsIScriptContext.");
    3611                 :     // Execute the precompiled script with the given version
    3612               0 :     JSObject* global = mScriptGlobalObject->GetGlobalJSObject();
    3613               0 :     return aContext->ExecuteScript(aScriptObject, global, nsnull, nsnull);
    3614                 : }
    3615                 : 
    3616                 : nsresult
    3617               0 : nsXULDocument::ExecuteScript(nsXULPrototypeScript *aScript)
    3618                 : {
    3619               0 :     NS_PRECONDITION(aScript != nsnull, "null ptr");
    3620               0 :     NS_ENSURE_TRUE(aScript, NS_ERROR_NULL_POINTER);
    3621               0 :     NS_ENSURE_TRUE(mScriptGlobalObject, NS_ERROR_NOT_INITIALIZED);
    3622               0 :     PRUint32 stid = aScript->mScriptObject.mLangID;
    3623                 : 
    3624                 :     nsresult rv;
    3625               0 :     rv = mScriptGlobalObject->EnsureScriptEnvironment(stid);
    3626               0 :     NS_ENSURE_SUCCESS(rv, rv);
    3627                 : 
    3628                 :     nsCOMPtr<nsIScriptContext> context =
    3629               0 :       mScriptGlobalObject->GetScriptContext(stid);
    3630                 :     // failure getting a script context is fatal.
    3631               0 :     NS_ENSURE_TRUE(context != nsnull, NS_ERROR_UNEXPECTED);
    3632                 : 
    3633               0 :     if (aScript->mScriptObject.mObject)
    3634               0 :         rv = ExecuteScript(context, aScript->mScriptObject.mObject);
    3635                 :     else
    3636               0 :         rv = NS_ERROR_UNEXPECTED;
    3637               0 :     return rv;
    3638                 : }
    3639                 : 
    3640                 : 
    3641                 : nsresult
    3642               0 : nsXULDocument::CreateElementFromPrototype(nsXULPrototypeElement* aPrototype,
    3643                 :                                           Element** aResult)
    3644                 : {
    3645                 :     // Create a content model element from a prototype element.
    3646               0 :     NS_PRECONDITION(aPrototype != nsnull, "null ptr");
    3647               0 :     if (! aPrototype)
    3648               0 :         return NS_ERROR_NULL_POINTER;
    3649                 : 
    3650               0 :     *aResult = nsnull;
    3651               0 :     nsresult rv = NS_OK;
    3652                 : 
    3653                 : #ifdef PR_LOGGING
    3654               0 :     if (PR_LOG_TEST(gXULLog, PR_LOG_NOTICE)) {
    3655               0 :         PR_LOG(gXULLog, PR_LOG_NOTICE,
    3656                 :                ("xul: creating <%s> from prototype",
    3657                 :                 NS_ConvertUTF16toUTF8(aPrototype->mNodeInfo->QualifiedName()).get()));
    3658                 :     }
    3659                 : #endif
    3660                 : 
    3661               0 :     nsRefPtr<Element> result;
    3662                 : 
    3663               0 :     if (aPrototype->mNodeInfo->NamespaceEquals(kNameSpaceID_XUL)) {
    3664                 :         // If it's a XUL element, it'll be lightweight until somebody
    3665                 :         // monkeys with it.
    3666               0 :         rv = nsXULElement::Create(aPrototype, this, true, getter_AddRefs(result));
    3667               0 :         if (NS_FAILED(rv)) return rv;
    3668                 :     }
    3669                 :     else {
    3670                 :         // If it's not a XUL element, it's gonna be heavyweight no matter
    3671                 :         // what. So we need to copy everything out of the prototype
    3672                 :         // into the element.  Get a nodeinfo from our nodeinfo manager
    3673                 :         // for this node.
    3674               0 :         nsCOMPtr<nsINodeInfo> newNodeInfo;
    3675                 :         newNodeInfo = mNodeInfoManager->GetNodeInfo(aPrototype->mNodeInfo->NameAtom(),
    3676                 :                                                     aPrototype->mNodeInfo->GetPrefixAtom(),
    3677                 :                                                     aPrototype->mNodeInfo->NamespaceID(),
    3678               0 :                                                     nsIDOMNode::ELEMENT_NODE);
    3679               0 :         if (!newNodeInfo) return NS_ERROR_OUT_OF_MEMORY;
    3680               0 :         nsCOMPtr<nsIContent> content;
    3681               0 :         nsCOMPtr<nsINodeInfo> xtfNi = newNodeInfo;
    3682               0 :         rv = NS_NewElement(getter_AddRefs(content), newNodeInfo.forget(),
    3683               0 :                            NOT_FROM_PARSER);
    3684               0 :         if (NS_FAILED(rv))
    3685               0 :             return rv;
    3686                 : 
    3687               0 :         result = content->AsElement();
    3688                 : 
    3689                 : #ifdef MOZ_XTF
    3690               0 :         if (result && xtfNi->NamespaceID() > kNameSpaceID_LastBuiltin) {
    3691               0 :             result->BeginAddingChildren();
    3692                 :         }
    3693                 : #endif
    3694                 : 
    3695               0 :         rv = AddAttributes(aPrototype, result);
    3696               0 :         if (NS_FAILED(rv)) return rv;
    3697                 :     }
    3698                 : 
    3699               0 :     result.swap(*aResult);
    3700                 : 
    3701               0 :     return NS_OK;
    3702                 : }
    3703                 : 
    3704                 : nsresult
    3705               0 : nsXULDocument::CreateOverlayElement(nsXULPrototypeElement* aPrototype,
    3706                 :                                     Element** aResult)
    3707                 : {
    3708                 :     nsresult rv;
    3709                 : 
    3710               0 :     nsRefPtr<Element> element;
    3711               0 :     rv = CreateElementFromPrototype(aPrototype, getter_AddRefs(element));
    3712               0 :     if (NS_FAILED(rv)) return rv;
    3713                 : 
    3714                 :     OverlayForwardReference* fwdref =
    3715               0 :         new OverlayForwardReference(this, element);
    3716               0 :     if (! fwdref)
    3717               0 :         return NS_ERROR_OUT_OF_MEMORY;
    3718                 : 
    3719                 :     // transferring ownership to ya...
    3720               0 :     rv = AddForwardReference(fwdref);
    3721               0 :     if (NS_FAILED(rv)) return rv;
    3722                 : 
    3723               0 :     NS_ADDREF(*aResult = element);
    3724               0 :     return NS_OK;
    3725                 : }
    3726                 : 
    3727                 : nsresult
    3728               0 : nsXULDocument::AddAttributes(nsXULPrototypeElement* aPrototype,
    3729                 :                              nsIContent* aElement)
    3730                 : {
    3731                 :     nsresult rv;
    3732                 : 
    3733               0 :     for (PRUint32 i = 0; i < aPrototype->mNumAttributes; ++i) {
    3734               0 :         nsXULPrototypeAttribute* protoattr = &(aPrototype->mAttributes[i]);
    3735               0 :         nsAutoString  valueStr;
    3736               0 :         protoattr->mValue.ToString(valueStr);
    3737                 : 
    3738                 :         rv = aElement->SetAttr(protoattr->mName.NamespaceID(),
    3739                 :                                protoattr->mName.LocalName(),
    3740                 :                                protoattr->mName.GetPrefix(),
    3741                 :                                valueStr,
    3742               0 :                                false);
    3743               0 :         if (NS_FAILED(rv)) return rv;
    3744                 :     }
    3745                 : 
    3746               0 :     return NS_OK;
    3747                 : }
    3748                 : 
    3749                 : 
    3750                 : nsresult
    3751               0 : nsXULDocument::CheckTemplateBuilderHookup(nsIContent* aElement,
    3752                 :                                           bool* aNeedsHookup)
    3753                 : {
    3754                 :     // See if the element already has a `database' attribute. If it
    3755                 :     // does, then the template builder has already been created.
    3756                 :     //
    3757                 :     // XXX This approach will crash and burn (well, maybe not _that_
    3758                 :     // bad) if aElement is not a XUL element.
    3759                 :     //
    3760                 :     // XXXvarga Do we still want to support non XUL content?
    3761               0 :     nsCOMPtr<nsIDOMXULElement> xulElement = do_QueryInterface(aElement);
    3762               0 :     if (xulElement) {
    3763               0 :         nsCOMPtr<nsIRDFCompositeDataSource> ds;
    3764               0 :         xulElement->GetDatabase(getter_AddRefs(ds));
    3765               0 :         if (ds) {
    3766               0 :             *aNeedsHookup = false;
    3767               0 :             return NS_OK;
    3768                 :         }
    3769                 :     }
    3770                 : 
    3771                 :     // Check aElement for a 'datasources' attribute, if it has
    3772                 :     // one a XUL template builder needs to be hooked up.
    3773                 :     *aNeedsHookup = aElement->HasAttr(kNameSpaceID_None,
    3774               0 :                                       nsGkAtoms::datasources);
    3775               0 :     return NS_OK;
    3776                 : }
    3777                 : 
    3778                 : /* static */ nsresult
    3779               0 : nsXULDocument::CreateTemplateBuilder(nsIContent* aElement)
    3780                 : {
    3781                 :     // Check if need to construct a tree builder or content builder.
    3782               0 :     bool isTreeBuilder = false;
    3783                 : 
    3784                 :     // return successful if the element is not is a document, as an inline
    3785                 :     // script could have removed it
    3786               0 :     nsIDocument *document = aElement->GetCurrentDoc();
    3787               0 :     NS_ENSURE_TRUE(document, NS_OK);
    3788                 : 
    3789                 :     PRInt32 nameSpaceID;
    3790                 :     nsIAtom* baseTag = document->BindingManager()->
    3791               0 :       ResolveTag(aElement, &nameSpaceID);
    3792                 : 
    3793               0 :     if ((nameSpaceID == kNameSpaceID_XUL) && (baseTag == nsGkAtoms::tree)) {
    3794                 :         // By default, we build content for a tree and then we attach
    3795                 :         // the tree content view. However, if the `dont-build-content'
    3796                 :         // flag is set, then we we'll attach a tree builder which
    3797                 :         // directly implements the tree view.
    3798                 : 
    3799               0 :         nsAutoString flags;
    3800               0 :         aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::flags, flags);
    3801               0 :         if (flags.Find(NS_LITERAL_STRING("dont-build-content")) >= 0) {
    3802               0 :             isTreeBuilder = true;
    3803                 :         }
    3804                 :     }
    3805                 : 
    3806               0 :     if (isTreeBuilder) {
    3807                 :         // Create and initialize a tree builder.
    3808                 :         nsCOMPtr<nsIXULTemplateBuilder> builder =
    3809               0 :             do_CreateInstance("@mozilla.org/xul/xul-tree-builder;1");
    3810                 : 
    3811               0 :         if (! builder)
    3812               0 :             return NS_ERROR_FAILURE;
    3813                 : 
    3814               0 :         builder->Init(aElement);
    3815                 : 
    3816                 :         // Create a <treechildren> if one isn't there already.
    3817                 :         // XXXvarga what about attributes?
    3818               0 :         nsCOMPtr<nsIContent> bodyContent;
    3819                 :         nsXULContentUtils::FindChildByTag(aElement, kNameSpaceID_XUL,
    3820                 :                                           nsGkAtoms::treechildren,
    3821               0 :                                           getter_AddRefs(bodyContent));
    3822                 : 
    3823               0 :         if (! bodyContent) {
    3824                 :             nsresult rv =
    3825               0 :                 document->CreateElem(nsDependentAtomString(nsGkAtoms::treechildren),
    3826                 :                                      nsnull, kNameSpaceID_XUL,
    3827               0 :                                      getter_AddRefs(bodyContent));
    3828               0 :             NS_ENSURE_SUCCESS(rv, rv);
    3829                 : 
    3830               0 :             aElement->AppendChildTo(bodyContent, false);
    3831                 :         }
    3832                 :     }
    3833                 :     else {
    3834                 :         // Create and initialize a content builder.
    3835                 :         nsCOMPtr<nsIXULTemplateBuilder> builder
    3836               0 :             = do_CreateInstance("@mozilla.org/xul/xul-template-builder;1");
    3837                 : 
    3838               0 :         if (! builder)
    3839               0 :             return NS_ERROR_FAILURE;
    3840                 : 
    3841               0 :         builder->Init(aElement);
    3842               0 :         builder->CreateContents(aElement, false);
    3843                 :     }
    3844                 : 
    3845               0 :     return NS_OK;
    3846                 : }
    3847                 : 
    3848                 : 
    3849                 : nsresult
    3850               0 : nsXULDocument::AddPrototypeSheets()
    3851                 : {
    3852                 :     nsresult rv;
    3853                 : 
    3854               0 :     const nsCOMArray<nsIURI>& sheets = mCurrentPrototype->GetStyleSheetReferences();
    3855                 : 
    3856               0 :     for (PRInt32 i = 0; i < sheets.Count(); i++) {
    3857               0 :         nsCOMPtr<nsIURI> uri = sheets[i];
    3858                 : 
    3859               0 :         nsRefPtr<nsCSSStyleSheet> incompleteSheet;
    3860                 :         rv = CSSLoader()->LoadSheet(uri,
    3861                 :                                     mCurrentPrototype->DocumentPrincipal(),
    3862               0 :                                     EmptyCString(), this,
    3863               0 :                                     getter_AddRefs(incompleteSheet));
    3864                 : 
    3865                 :         // XXXldb We need to prevent bogus sheets from being held in the
    3866                 :         // prototype's list, but until then, don't propagate the failure
    3867                 :         // from LoadSheet (and thus exit the loop).
    3868               0 :         if (NS_SUCCEEDED(rv)) {
    3869               0 :             ++mPendingSheets;
    3870               0 :             if (!mOverlaySheets.AppendElement(incompleteSheet)) {
    3871               0 :                 return NS_ERROR_OUT_OF_MEMORY;
    3872                 :             }
    3873                 :         }
    3874                 :     }
    3875                 : 
    3876               0 :     return NS_OK;
    3877                 : }
    3878                 : 
    3879                 : 
    3880                 : //----------------------------------------------------------------------
    3881                 : //
    3882                 : // nsXULDocument::OverlayForwardReference
    3883                 : //
    3884                 : 
    3885                 : nsForwardReference::Result
    3886               0 : nsXULDocument::OverlayForwardReference::Resolve()
    3887                 : {
    3888                 :     // Resolve a forward reference from an overlay element; attempt to
    3889                 :     // hook it up into the main document.
    3890                 :     nsresult rv;
    3891               0 :     nsCOMPtr<nsIContent> target;
    3892                 : 
    3893               0 :     nsIPresShell *shell = mDocument->GetShell();
    3894               0 :     bool notify = shell && shell->DidInitialReflow();
    3895                 : 
    3896               0 :     nsAutoString id;
    3897               0 :     mOverlay->GetAttr(kNameSpaceID_None, nsGkAtoms::id, id);
    3898               0 :     if (id.IsEmpty()) {
    3899                 :         // mOverlay is a direct child of <overlay> and has no id.
    3900                 :         // Insert it under the root element in the base document.
    3901               0 :         Element* root = mDocument->GetRootElement();
    3902               0 :         if (!root) {
    3903               0 :             return eResolve_Error;
    3904                 :         }
    3905                 : 
    3906               0 :         rv = mDocument->InsertElement(root, mOverlay, notify);
    3907               0 :         if (NS_FAILED(rv)) return eResolve_Error;
    3908                 : 
    3909               0 :         target = mOverlay;
    3910                 :     }
    3911                 :     else {
    3912                 :         // The hook-up element has an id, try to match it with an element
    3913                 :         // with the same id in the base document.
    3914               0 :         target = mDocument->GetElementById(id);
    3915                 : 
    3916                 :         // If we can't find the element in the document, defer the hookup
    3917                 :         // until later.
    3918               0 :         if (!target)
    3919               0 :             return eResolve_Later;
    3920                 : 
    3921                 :         // While merging, set the default script language of the element to be
    3922                 :         // the language from the overlay - attributes will then be correctly
    3923                 :         // hooked up with the appropriate language (while child nodes ignore
    3924                 :         // the default language - they have it in their proto.
    3925               0 :         PRUint32 oldDefLang = target->GetScriptTypeID();
    3926               0 :         target->SetScriptTypeID(mOverlay->GetScriptTypeID());
    3927               0 :         rv = Merge(target, mOverlay, notify);
    3928               0 :         target->SetScriptTypeID(oldDefLang);
    3929               0 :         if (NS_FAILED(rv)) return eResolve_Error;
    3930                 :     }
    3931                 : 
    3932                 :     // Check if 'target' is still in our document --- it might not be!
    3933               0 :     if (!notify && target->GetCurrentDoc() == mDocument) {
    3934                 :         // Add child and any descendants to the element map
    3935                 :         // XXX this is bogus, the content in 'target' might already be
    3936                 :         // in the document
    3937               0 :         rv = mDocument->AddSubtreeToDocument(target);
    3938               0 :         if (NS_FAILED(rv)) return eResolve_Error;
    3939                 :     }
    3940                 : 
    3941                 : #ifdef PR_LOGGING
    3942               0 :     if (PR_LOG_TEST(gXULLog, PR_LOG_NOTICE)) {
    3943               0 :         nsCAutoString idC;
    3944               0 :         idC.AssignWithConversion(id);
    3945               0 :         PR_LOG(gXULLog, PR_LOG_NOTICE,
    3946                 :                ("xul: overlay resolved '%s'",
    3947                 :                 idC.get()));
    3948                 :     }
    3949                 : #endif
    3950                 : 
    3951               0 :     mResolved = true;
    3952               0 :     return eResolve_Succeeded;
    3953                 : }
    3954                 : 
    3955                 : 
    3956                 : 
    3957                 : nsresult
    3958               0 : nsXULDocument::OverlayForwardReference::Merge(nsIContent* aTargetNode,
    3959                 :                                               nsIContent* aOverlayNode, 
    3960                 :                                               bool aNotify)
    3961                 : {
    3962                 :     // This function is given:
    3963                 :     // aTargetNode:  the node in the document whose 'id' attribute
    3964                 :     //               matches a toplevel node in our overlay.
    3965                 :     // aOverlayNode: the node in the overlay document that matches
    3966                 :     //               a node in the actual document.
    3967                 :     // aNotify:      whether or not content manipulation methods should
    3968                 :     //               use the aNotify parameter. After the initial 
    3969                 :     //               reflow (i.e. in the dynamic overlay merge case),
    3970                 :     //               we want all the content manipulation methods we
    3971                 :     //               call to notify so that frames are constructed 
    3972                 :     //               etc. Otherwise do not, since that's during initial
    3973                 :     //               document construction before StartLayout has been
    3974                 :     //               called which will do everything for us.
    3975                 :     //
    3976                 :     // This function merges the tree from the overlay into the tree in
    3977                 :     // the document, overwriting attributes and appending child content
    3978                 :     // nodes appropriately. (See XUL overlay reference for details)
    3979                 : 
    3980                 :     nsresult rv;
    3981                 : 
    3982                 :     // Merge attributes from the overlay content node to that of the
    3983                 :     // actual document.
    3984                 :     PRUint32 i;
    3985                 :     const nsAttrName* name;
    3986               0 :     for (i = 0; (name = aOverlayNode->GetAttrNameAt(i)); ++i) {
    3987                 :         // We don't want to swap IDs, they should be the same.
    3988               0 :         if (name->Equals(nsGkAtoms::id))
    3989               0 :             continue;
    3990                 : 
    3991                 :         // In certain cases merging command or observes is unsafe, so don't.
    3992               0 :         if (!aNotify) {
    3993               0 :             if (aTargetNode->NodeInfo()->Equals(nsGkAtoms::observes,
    3994               0 :                                                 kNameSpaceID_XUL))
    3995               0 :                 continue;
    3996                 : 
    3997               0 :             if (name->Equals(nsGkAtoms::observes) &&
    3998               0 :                 aTargetNode->HasAttr(kNameSpaceID_None, nsGkAtoms::observes))
    3999               0 :                 continue;
    4000                 : 
    4001               0 :             if (name->Equals(nsGkAtoms::command) &&
    4002               0 :                 aTargetNode->HasAttr(kNameSpaceID_None, nsGkAtoms::command) &&
    4003                 :                 !aTargetNode->NodeInfo()->Equals(nsGkAtoms::key,
    4004               0 :                                                  kNameSpaceID_XUL) &&
    4005                 :                 !aTargetNode->NodeInfo()->Equals(nsGkAtoms::menuitem,
    4006               0 :                                                  kNameSpaceID_XUL))
    4007               0 :                 continue;
    4008                 :         }
    4009                 : 
    4010               0 :         PRInt32 nameSpaceID = name->NamespaceID();
    4011               0 :         nsIAtom* attr = name->LocalName();
    4012               0 :         nsIAtom* prefix = name->GetPrefix();
    4013                 : 
    4014               0 :         nsAutoString value;
    4015               0 :         aOverlayNode->GetAttr(nameSpaceID, attr, value);
    4016                 : 
    4017                 :         // Element in the overlay has the 'removeelement' attribute set
    4018                 :         // so remove it from the actual document.
    4019               0 :         if (attr == nsGkAtoms::removeelement &&
    4020               0 :             value.EqualsLiteral("true")) {
    4021                 : 
    4022               0 :             nsCOMPtr<nsIContent> parent = aTargetNode->GetParent();
    4023               0 :             rv = RemoveElement(parent, aTargetNode);
    4024               0 :             if (NS_FAILED(rv)) return rv;
    4025                 : 
    4026               0 :             return NS_OK;
    4027                 :         }
    4028                 : 
    4029               0 :         rv = aTargetNode->SetAttr(nameSpaceID, attr, prefix, value, aNotify);
    4030               0 :         if (!NS_FAILED(rv) && !aNotify)
    4031                 :             rv = mDocument->BroadcastAttributeChangeFromOverlay(aTargetNode,
    4032                 :                                                                 nameSpaceID,
    4033                 :                                                                 attr, prefix,
    4034               0 :                                                                 value);
    4035               0 :         if (NS_FAILED(rv)) return rv;
    4036                 :     }
    4037                 : 
    4038                 : 
    4039                 :     // Walk our child nodes, looking for elements that have the 'id'
    4040                 :     // attribute set. If we find any, we must do a parent check in the
    4041                 :     // actual document to ensure that the structure matches that of
    4042                 :     // the actual document. If it does, we can call ourselves and attempt
    4043                 :     // to merge inside that subtree. If not, we just append the tree to
    4044                 :     // the parent like any other.
    4045                 : 
    4046               0 :     PRUint32 childCount = aOverlayNode->GetChildCount();
    4047                 : 
    4048                 :     // This must be a strong reference since it will be the only
    4049                 :     // reference to a content object during part of this loop.
    4050               0 :     nsCOMPtr<nsIContent> currContent;
    4051                 : 
    4052               0 :     for (i = 0; i < childCount; ++i) {
    4053               0 :         currContent = aOverlayNode->GetFirstChild();
    4054                 : 
    4055               0 :         nsIAtom *idAtom = currContent->GetID();
    4056                 : 
    4057               0 :         nsIContent *elementInDocument = nsnull;
    4058               0 :         if (idAtom) {
    4059               0 :             nsDependentAtomString id(idAtom);
    4060                 : 
    4061               0 :             if (!id.IsEmpty()) {
    4062               0 :                 nsIDocument *doc = aTargetNode->GetDocument();
    4063               0 :                 if (!doc) return NS_ERROR_FAILURE;
    4064                 : 
    4065               0 :                 elementInDocument = doc->GetElementById(id);
    4066                 :             }
    4067                 :         }
    4068                 : 
    4069                 :         // The item has an 'id' attribute set, and we need to check with
    4070                 :         // the actual document to see if an item with this id exists at
    4071                 :         // this locale. If so, we want to merge the subtree under that
    4072                 :         // node. Otherwise, we just do an append as if the element had
    4073                 :         // no id attribute.
    4074               0 :         if (elementInDocument) {
    4075                 :             // Given two parents, aTargetNode and aOverlayNode, we want
    4076                 :             // to call merge on currContent if we find an associated
    4077                 :             // node in the document with the same id as currContent that
    4078                 :             // also has aTargetNode as its parent.
    4079                 : 
    4080               0 :             nsIContent *elementParent = elementInDocument->GetParent();
    4081                 : 
    4082               0 :             nsIAtom *parentID = elementParent->GetID();
    4083               0 :             if (parentID &&
    4084                 :                 aTargetNode->AttrValueIs(kNameSpaceID_None, nsGkAtoms::id,
    4085               0 :                                          nsDependentAtomString(parentID),
    4086               0 :                                          eCaseMatters)) {
    4087                 :                 // The element matches. "Go Deep!"
    4088               0 :                 rv = Merge(elementInDocument, currContent, aNotify);
    4089               0 :                 if (NS_FAILED(rv)) return rv;
    4090               0 :                 rv = aOverlayNode->RemoveChildAt(0, false);
    4091               0 :                 if (NS_FAILED(rv)) return rv;
    4092                 : 
    4093               0 :                 continue;
    4094                 :             }
    4095                 :         }
    4096                 : 
    4097               0 :         rv = aOverlayNode->RemoveChildAt(0, false);
    4098               0 :         if (NS_FAILED(rv)) return rv;
    4099                 : 
    4100               0 :         rv = InsertElement(aTargetNode, currContent, aNotify);
    4101               0 :         if (NS_FAILED(rv)) return rv;
    4102                 :     }
    4103                 : 
    4104               0 :     return NS_OK;
    4105                 : }
    4106                 : 
    4107                 : 
    4108                 : 
    4109               0 : nsXULDocument::OverlayForwardReference::~OverlayForwardReference()
    4110                 : {
    4111                 : #ifdef PR_LOGGING
    4112               0 :     if (PR_LOG_TEST(gXULLog, PR_LOG_WARNING) && !mResolved) {
    4113               0 :         nsAutoString id;
    4114               0 :         mOverlay->GetAttr(kNameSpaceID_None, nsGkAtoms::id, id);
    4115                 : 
    4116               0 :         nsCAutoString idC;
    4117               0 :         idC.AssignWithConversion(id);
    4118               0 :         PR_LOG(gXULLog, PR_LOG_WARNING,
    4119                 :                ("xul: overlay failed to resolve '%s'",
    4120                 :                 idC.get()));
    4121                 :     }
    4122                 : #endif
    4123               0 : }
    4124                 : 
    4125                 : 
    4126                 : //----------------------------------------------------------------------
    4127                 : //
    4128                 : // nsXULDocument::BroadcasterHookup
    4129                 : //
    4130                 : 
    4131                 : nsForwardReference::Result
    4132               0 : nsXULDocument::BroadcasterHookup::Resolve()
    4133                 : {
    4134                 :     nsresult rv;
    4135                 : 
    4136                 :     bool listener;
    4137               0 :     rv = mDocument->CheckBroadcasterHookup(mObservesElement, &listener, &mResolved);
    4138               0 :     if (NS_FAILED(rv)) return eResolve_Error;
    4139                 : 
    4140               0 :     return mResolved ? eResolve_Succeeded : eResolve_Later;
    4141                 : }
    4142                 : 
    4143                 : 
    4144               0 : nsXULDocument::BroadcasterHookup::~BroadcasterHookup()
    4145                 : {
    4146                 : #ifdef PR_LOGGING
    4147               0 :     if (PR_LOG_TEST(gXULLog, PR_LOG_WARNING) && !mResolved) {
    4148                 :         // Tell the world we failed
    4149               0 :         nsIAtom *tag = mObservesElement->Tag();
    4150                 : 
    4151               0 :         nsAutoString broadcasterID;
    4152               0 :         nsAutoString attribute;
    4153                 : 
    4154               0 :         if (tag == nsGkAtoms::observes) {
    4155               0 :             mObservesElement->GetAttr(kNameSpaceID_None, nsGkAtoms::element, broadcasterID);
    4156               0 :             mObservesElement->GetAttr(kNameSpaceID_None, nsGkAtoms::attribute, attribute);
    4157                 :         }
    4158                 :         else {
    4159               0 :             mObservesElement->GetAttr(kNameSpaceID_None, nsGkAtoms::observes, broadcasterID);
    4160               0 :             attribute.AssignLiteral("*");
    4161                 :         }
    4162                 : 
    4163               0 :         nsCAutoString attributeC,broadcasteridC;
    4164               0 :         attributeC.AssignWithConversion(attribute);
    4165               0 :         broadcasteridC.AssignWithConversion(broadcasterID);
    4166               0 :         PR_LOG(gXULLog, PR_LOG_WARNING,
    4167                 :                ("xul: broadcaster hookup failed <%s attribute='%s'> to %s",
    4168                 :                 nsAtomCString(tag).get(),
    4169                 :                 attributeC.get(),
    4170                 :                 broadcasteridC.get()));
    4171                 :     }
    4172                 : #endif
    4173               0 : }
    4174                 : 
    4175                 : 
    4176                 : //----------------------------------------------------------------------
    4177                 : //
    4178                 : // nsXULDocument::TemplateBuilderHookup
    4179                 : //
    4180                 : 
    4181                 : nsForwardReference::Result
    4182               0 : nsXULDocument::TemplateBuilderHookup::Resolve()
    4183                 : {
    4184                 :     bool needsHookup;
    4185               0 :     nsresult rv = CheckTemplateBuilderHookup(mElement, &needsHookup);
    4186               0 :     if (NS_FAILED(rv))
    4187               0 :         return eResolve_Error;
    4188                 : 
    4189               0 :     if (needsHookup) {
    4190               0 :         rv = CreateTemplateBuilder(mElement);
    4191               0 :         if (NS_FAILED(rv))
    4192               0 :             return eResolve_Error;
    4193                 :     }
    4194                 : 
    4195               0 :     return eResolve_Succeeded;
    4196                 : }
    4197                 : 
    4198                 : 
    4199                 : //----------------------------------------------------------------------
    4200                 : 
    4201                 : nsresult
    4202               0 : nsXULDocument::BroadcastAttributeChangeFromOverlay(nsIContent* aNode,
    4203                 :                                                    PRInt32 aNameSpaceID,
    4204                 :                                                    nsIAtom* aAttribute,
    4205                 :                                                    nsIAtom* aPrefix,
    4206                 :                                                    const nsAString& aValue)
    4207                 : {
    4208               0 :     nsresult rv = NS_OK;
    4209                 : 
    4210               0 :     if (!mBroadcasterMap || !CanBroadcast(aNameSpaceID, aAttribute))
    4211               0 :         return rv;
    4212                 : 
    4213               0 :     nsCOMPtr<nsIDOMElement> domele = do_QueryInterface(aNode);
    4214               0 :     if (!domele)
    4215               0 :         return rv;
    4216                 : 
    4217                 :     BroadcasterMapEntry* entry = static_cast<BroadcasterMapEntry*>
    4218               0 :         (PL_DHashTableOperate(mBroadcasterMap, domele.get(), PL_DHASH_LOOKUP));
    4219               0 :     if (!PL_DHASH_ENTRY_IS_BUSY(entry))
    4220               0 :         return rv;
    4221                 : 
    4222                 :     // We've got listeners: push the value.
    4223                 :     PRInt32 i;
    4224               0 :     for (i = entry->mListeners.Count() - 1; i >= 0; --i) {
    4225                 :         BroadcastListener* bl = static_cast<BroadcastListener*>
    4226               0 :             (entry->mListeners[i]);
    4227                 : 
    4228               0 :         if ((bl->mAttribute != aAttribute) &&
    4229               0 :             (bl->mAttribute != nsGkAtoms::_asterix))
    4230               0 :             continue;
    4231                 : 
    4232               0 :         nsCOMPtr<nsIContent> l = do_QueryReferent(bl->mListener);
    4233               0 :         if (l) {
    4234               0 :             rv = l->SetAttr(aNameSpaceID, aAttribute,
    4235               0 :                             aPrefix, aValue, false);
    4236               0 :             if (NS_FAILED(rv)) return rv;
    4237                 :         }
    4238                 :     }
    4239               0 :     return rv;
    4240                 : }
    4241                 : 
    4242                 : nsresult
    4243               0 : nsXULDocument::FindBroadcaster(Element* aElement,
    4244                 :                                nsIDOMElement** aListener,
    4245                 :                                nsString& aBroadcasterID,
    4246                 :                                nsString& aAttribute,
    4247                 :                                nsIDOMElement** aBroadcaster)
    4248                 : {
    4249                 :     nsresult rv;
    4250               0 :     nsINodeInfo *ni = aElement->NodeInfo();
    4251               0 :     *aListener = nsnull;
    4252               0 :     *aBroadcaster = nsnull;
    4253                 : 
    4254               0 :     if (ni->Equals(nsGkAtoms::observes, kNameSpaceID_XUL)) {
    4255                 :         // It's an <observes> element, which means that the actual
    4256                 :         // listener is the _parent_ node. This element should have an
    4257                 :         // 'element' attribute that specifies the ID of the
    4258                 :         // broadcaster element, and an 'attribute' element, which
    4259                 :         // specifies the name of the attribute to observe.
    4260               0 :         nsIContent* parent = aElement->GetParent();
    4261               0 :         if (!parent) {
    4262                 :              // <observes> is the root element
    4263               0 :             return NS_FINDBROADCASTER_NOT_FOUND;
    4264                 :         }
    4265                 : 
    4266                 :         // If we're still parented by an 'overlay' tag, then we haven't
    4267                 :         // made it into the real document yet. Defer hookup.
    4268               0 :         if (parent->NodeInfo()->Equals(nsGkAtoms::overlay,
    4269               0 :                                        kNameSpaceID_XUL)) {
    4270               0 :             return NS_FINDBROADCASTER_AWAIT_OVERLAYS;
    4271                 :         }
    4272                 : 
    4273               0 :         if (NS_FAILED(CallQueryInterface(parent, aListener)))
    4274               0 :             *aListener = nsnull;
    4275                 : 
    4276               0 :         aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::element, aBroadcasterID);
    4277               0 :         if (aBroadcasterID.IsEmpty()) {
    4278               0 :             return NS_FINDBROADCASTER_NOT_FOUND;
    4279                 :         }
    4280               0 :         aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::attribute, aAttribute);
    4281                 :     }
    4282                 :     else {
    4283                 :         // It's a generic element, which means that we'll use the
    4284                 :         // value of the 'observes' attribute to determine the ID of
    4285                 :         // the broadcaster element, and we'll watch _all_ of its
    4286                 :         // values.
    4287               0 :         aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::observes, aBroadcasterID);
    4288                 : 
    4289                 :         // Bail if there's no aBroadcasterID
    4290               0 :         if (aBroadcasterID.IsEmpty()) {
    4291                 :             // Try the command attribute next.
    4292               0 :             aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::command, aBroadcasterID);
    4293               0 :             if (!aBroadcasterID.IsEmpty()) {
    4294                 :                 // We've got something in the command attribute.  We
    4295                 :                 // only treat this as a normal broadcaster if we are
    4296                 :                 // not a menuitem or a key.
    4297                 : 
    4298               0 :                 if (ni->Equals(nsGkAtoms::menuitem, kNameSpaceID_XUL) ||
    4299               0 :                     ni->Equals(nsGkAtoms::key, kNameSpaceID_XUL)) {
    4300               0 :                 return NS_FINDBROADCASTER_NOT_FOUND;
    4301                 :               }
    4302                 :             }
    4303                 :             else {
    4304               0 :               return NS_FINDBROADCASTER_NOT_FOUND;
    4305                 :             }
    4306                 :         }
    4307                 : 
    4308               0 :         if (NS_FAILED(CallQueryInterface(aElement, aListener)))
    4309               0 :             *aListener = nsnull;
    4310                 : 
    4311               0 :         aAttribute.AssignLiteral("*");
    4312                 :     }
    4313                 : 
    4314                 :     // Make sure we got a valid listener.
    4315               0 :     NS_ENSURE_TRUE(*aListener, NS_ERROR_UNEXPECTED);
    4316                 : 
    4317                 :     // Try to find the broadcaster element in the document.
    4318               0 :     rv = GetElementById(aBroadcasterID, aBroadcaster);
    4319               0 :     if (NS_FAILED(rv)) return rv;
    4320                 : 
    4321                 :     // If we can't find the broadcaster, then we'll need to defer the
    4322                 :     // hookup. We may need to resolve some of the other overlays
    4323                 :     // first.
    4324               0 :     if (! *aBroadcaster) {
    4325               0 :         return NS_FINDBROADCASTER_AWAIT_OVERLAYS;
    4326                 :     }
    4327                 : 
    4328               0 :     return NS_FINDBROADCASTER_FOUND;
    4329                 : }
    4330                 : 
    4331                 : nsresult
    4332               0 : nsXULDocument::CheckBroadcasterHookup(Element* aElement,
    4333                 :                                       bool* aNeedsHookup,
    4334                 :                                       bool* aDidResolve)
    4335                 : {
    4336                 :     // Resolve a broadcaster hookup. Look at the element that we're
    4337                 :     // trying to resolve: it could be an '<observes>' element, or just
    4338                 :     // a vanilla element with an 'observes' attribute on it.
    4339                 :     nsresult rv;
    4340                 : 
    4341               0 :     *aDidResolve = false;
    4342                 : 
    4343               0 :     nsCOMPtr<nsIDOMElement> listener;
    4344               0 :     nsAutoString broadcasterID;
    4345               0 :     nsAutoString attribute;
    4346               0 :     nsCOMPtr<nsIDOMElement> broadcaster;
    4347                 : 
    4348               0 :     rv = FindBroadcaster(aElement, getter_AddRefs(listener),
    4349               0 :                          broadcasterID, attribute, getter_AddRefs(broadcaster));
    4350               0 :     switch (rv) {
    4351                 :         case NS_FINDBROADCASTER_NOT_FOUND:
    4352               0 :             *aNeedsHookup = false;
    4353               0 :             return NS_OK;
    4354                 :         case NS_FINDBROADCASTER_AWAIT_OVERLAYS:
    4355               0 :             *aNeedsHookup = true;
    4356               0 :             return NS_OK;
    4357                 :         case NS_FINDBROADCASTER_FOUND:
    4358                 :             break;
    4359                 :         default:
    4360               0 :             return rv;
    4361                 :     }
    4362                 : 
    4363               0 :     rv = AddBroadcastListenerFor(broadcaster, listener, attribute);
    4364               0 :     if (NS_FAILED(rv)) return rv;
    4365                 : 
    4366                 : #ifdef PR_LOGGING
    4367                 :     // Tell the world we succeeded
    4368               0 :     if (PR_LOG_TEST(gXULLog, PR_LOG_NOTICE)) {
    4369                 :         nsCOMPtr<nsIContent> content =
    4370               0 :             do_QueryInterface(listener);
    4371                 : 
    4372               0 :         NS_ASSERTION(content != nsnull, "not an nsIContent");
    4373               0 :         if (! content)
    4374               0 :             return rv;
    4375                 : 
    4376               0 :         nsCAutoString attributeC,broadcasteridC;
    4377               0 :         attributeC.AssignWithConversion(attribute);
    4378               0 :         broadcasteridC.AssignWithConversion(broadcasterID);
    4379               0 :         PR_LOG(gXULLog, PR_LOG_NOTICE,
    4380                 :                ("xul: broadcaster hookup <%s attribute='%s'> to %s",
    4381                 :                 nsAtomCString(content->Tag()).get(),
    4382                 :                 attributeC.get(),
    4383                 :                 broadcasteridC.get()));
    4384                 :     }
    4385                 : #endif
    4386                 : 
    4387               0 :     *aNeedsHookup = false;
    4388               0 :     *aDidResolve = true;
    4389               0 :     return NS_OK;
    4390                 : }
    4391                 : 
    4392                 : nsresult
    4393               0 : nsXULDocument::InsertElement(nsIContent* aParent, nsIContent* aChild,
    4394                 :                              bool aNotify)
    4395                 : {
    4396                 :     // Insert aChild appropriately into aParent, accounting for a
    4397                 :     // 'pos' attribute set on aChild.
    4398                 : 
    4399               0 :     nsAutoString posStr;
    4400               0 :     bool wasInserted = false;
    4401                 : 
    4402                 :     // insert after an element of a given id
    4403               0 :     aChild->GetAttr(kNameSpaceID_None, nsGkAtoms::insertafter, posStr);
    4404               0 :     bool isInsertAfter = true;
    4405                 : 
    4406               0 :     if (posStr.IsEmpty()) {
    4407               0 :         aChild->GetAttr(kNameSpaceID_None, nsGkAtoms::insertbefore, posStr);
    4408               0 :         isInsertAfter = false;
    4409                 :     }
    4410                 : 
    4411               0 :     if (!posStr.IsEmpty()) {
    4412               0 :         nsIDocument *document = aParent->OwnerDoc();
    4413                 : 
    4414               0 :         nsIContent *content = nsnull;
    4415                 : 
    4416               0 :         char* str = ToNewCString(posStr);
    4417                 :         char* rest;
    4418               0 :         char* token = nsCRT::strtok(str, ", ", &rest);
    4419                 : 
    4420               0 :         while (token) {
    4421               0 :             content = document->GetElementById(NS_ConvertASCIItoUTF16(token));
    4422               0 :             if (content)
    4423               0 :                 break;
    4424                 : 
    4425               0 :             token = nsCRT::strtok(rest, ", ", &rest);
    4426                 :         }
    4427               0 :         nsMemory::Free(str);
    4428                 : 
    4429               0 :         if (content) {
    4430               0 :             PRInt32 pos = aParent->IndexOf(content);
    4431                 : 
    4432               0 :             if (pos != -1) {
    4433               0 :                 pos = isInsertAfter ? pos + 1 : pos;
    4434               0 :                 nsresult rv = aParent->InsertChildAt(aChild, pos, aNotify);
    4435               0 :                 if (NS_FAILED(rv))
    4436               0 :                     return rv;
    4437                 : 
    4438               0 :                 wasInserted = true;
    4439                 :             }
    4440                 :         }
    4441                 :     }
    4442                 : 
    4443               0 :     if (!wasInserted) {
    4444                 : 
    4445               0 :         aChild->GetAttr(kNameSpaceID_None, nsGkAtoms::position, posStr);
    4446               0 :         if (!posStr.IsEmpty()) {
    4447                 :             nsresult rv;
    4448                 :             // Positions are one-indexed.
    4449               0 :             PRInt32 pos = posStr.ToInteger(reinterpret_cast<PRInt32*>(&rv));
    4450                 :             // Note: if the insertion index (which is |pos - 1|) would be less
    4451                 :             // than 0 or greater than the number of children aParent has, then
    4452                 :             // don't insert, since the position is bogus.  Just skip on to
    4453                 :             // appending.
    4454               0 :             if (NS_SUCCEEDED(rv) && pos > 0 &&
    4455               0 :                 PRUint32(pos - 1) <= aParent->GetChildCount()) {
    4456               0 :                 rv = aParent->InsertChildAt(aChild, pos - 1, aNotify);
    4457               0 :                 if (NS_SUCCEEDED(rv))
    4458               0 :                     wasInserted = true;
    4459                 :                 // If the insertion fails, then we should still
    4460                 :                 // attempt an append.  Thus, rather than returning rv
    4461                 :                 // immediately, we fall through to the final
    4462                 :                 // "catch-all" case that just does an AppendChildTo.
    4463                 :             }
    4464                 :         }
    4465                 :     }
    4466                 : 
    4467               0 :     if (!wasInserted) {
    4468               0 :         return aParent->AppendChildTo(aChild, aNotify);
    4469                 :     }
    4470               0 :     return NS_OK;
    4471                 : }
    4472                 : 
    4473                 : nsresult
    4474               0 : nsXULDocument::RemoveElement(nsIContent* aParent, nsIContent* aChild)
    4475                 : {
    4476               0 :     PRInt32 nodeOffset = aParent->IndexOf(aChild);
    4477                 : 
    4478               0 :     return aParent->RemoveChildAt(nodeOffset, true);
    4479                 : }
    4480                 : 
    4481                 : //----------------------------------------------------------------------
    4482                 : //
    4483                 : // CachedChromeStreamListener
    4484                 : //
    4485                 : 
    4486               0 : nsXULDocument::CachedChromeStreamListener::CachedChromeStreamListener(nsXULDocument* aDocument, bool aProtoLoaded)
    4487                 :     : mDocument(aDocument),
    4488               0 :       mProtoLoaded(aProtoLoaded)
    4489                 : {
    4490               0 :     NS_ADDREF(mDocument);
    4491               0 : }
    4492                 : 
    4493                 : 
    4494               0 : nsXULDocument::CachedChromeStreamListener::~CachedChromeStreamListener()
    4495                 : {
    4496               0 :     NS_RELEASE(mDocument);
    4497               0 : }
    4498                 : 
    4499                 : 
    4500               0 : NS_IMPL_ISUPPORTS2(nsXULDocument::CachedChromeStreamListener,
    4501                 :                    nsIRequestObserver, nsIStreamListener)
    4502                 : 
    4503                 : NS_IMETHODIMP
    4504               0 : nsXULDocument::CachedChromeStreamListener::OnStartRequest(nsIRequest *request,
    4505                 :                                                           nsISupports* acontext)
    4506                 : {
    4507               0 :     return NS_ERROR_PARSED_DATA_CACHED;
    4508                 : }
    4509                 : 
    4510                 : 
    4511                 : NS_IMETHODIMP
    4512               0 : nsXULDocument::CachedChromeStreamListener::OnStopRequest(nsIRequest *request,
    4513                 :                                                          nsISupports* aContext,
    4514                 :                                                          nsresult aStatus)
    4515                 : {
    4516               0 :     if (! mProtoLoaded)
    4517               0 :         return NS_OK;
    4518                 : 
    4519               0 :     return mDocument->OnPrototypeLoadDone(true);
    4520                 : }
    4521                 : 
    4522                 : 
    4523                 : NS_IMETHODIMP
    4524               0 : nsXULDocument::CachedChromeStreamListener::OnDataAvailable(nsIRequest *request,
    4525                 :                                                            nsISupports* aContext,
    4526                 :                                                            nsIInputStream* aInStr,
    4527                 :                                                            PRUint32 aSourceOffset,
    4528                 :                                                            PRUint32 aCount)
    4529                 : {
    4530               0 :     NS_NOTREACHED("CachedChromeStream doesn't receive data");
    4531               0 :     return NS_ERROR_UNEXPECTED;
    4532                 : }
    4533                 : 
    4534                 : //----------------------------------------------------------------------
    4535                 : //
    4536                 : // ParserObserver
    4537                 : //
    4538                 : 
    4539               0 : nsXULDocument::ParserObserver::ParserObserver(nsXULDocument* aDocument,
    4540                 :                                               nsXULPrototypeDocument* aPrototype)
    4541               0 :     : mDocument(aDocument), mPrototype(aPrototype)
    4542                 : {
    4543               0 : }
    4544                 : 
    4545               0 : nsXULDocument::ParserObserver::~ParserObserver()
    4546                 : {
    4547               0 : }
    4548                 : 
    4549               0 : NS_IMPL_ISUPPORTS1(nsXULDocument::ParserObserver, nsIRequestObserver)
    4550                 : 
    4551                 : NS_IMETHODIMP
    4552               0 : nsXULDocument::ParserObserver::OnStartRequest(nsIRequest *request,
    4553                 :                                               nsISupports* aContext)
    4554                 : {
    4555                 :     // Guard against buggy channels calling OnStartRequest multiple times.
    4556               0 :     if (mPrototype) {
    4557               0 :         nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
    4558               0 :         nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
    4559               0 :         if (channel && secMan) {
    4560               0 :             nsCOMPtr<nsIPrincipal> principal;
    4561               0 :             secMan->GetChannelPrincipal(channel, getter_AddRefs(principal));
    4562                 : 
    4563                 :             // Failure there is ok -- it'll just set a (safe) null principal
    4564               0 :             mPrototype->SetDocumentPrincipal(principal);
    4565                 :         }
    4566                 : 
    4567                 :         // Make sure to avoid cycles
    4568               0 :         mPrototype = nsnull;
    4569                 :     }
    4570                 :         
    4571               0 :     return NS_OK;
    4572                 : }
    4573                 : 
    4574                 : NS_IMETHODIMP
    4575               0 : nsXULDocument::ParserObserver::OnStopRequest(nsIRequest *request,
    4576                 :                                              nsISupports* aContext,
    4577                 :                                              nsresult aStatus)
    4578                 : {
    4579               0 :     nsresult rv = NS_OK;
    4580                 : 
    4581               0 :     if (NS_FAILED(aStatus)) {
    4582                 :         // If an overlay load fails, we need to nudge the prototype
    4583                 :         // walk along.
    4584               0 :         nsCOMPtr<nsIChannel> aChannel = do_QueryInterface(request);
    4585               0 :         if (aChannel) {
    4586               0 :             nsCOMPtr<nsIURI> uri;
    4587               0 :             aChannel->GetOriginalURI(getter_AddRefs(uri));
    4588               0 :             if (uri) {
    4589               0 :                 mDocument->ReportMissingOverlay(uri);
    4590                 :             }
    4591                 :         }
    4592                 : 
    4593               0 :         rv = mDocument->ResumeWalk();
    4594                 :     }
    4595                 : 
    4596                 :     // Drop the reference to the document to break cycle between the
    4597                 :     // document, the parser, the content sink, and the parser
    4598                 :     // observer.
    4599               0 :     mDocument = nsnull;
    4600                 : 
    4601               0 :     return rv;
    4602                 : }
    4603                 : 
    4604                 : already_AddRefed<nsPIWindowRoot>
    4605               0 : nsXULDocument::GetWindowRoot()
    4606                 : {
    4607               0 :     nsCOMPtr<nsIInterfaceRequestor> ir = do_QueryReferent(mDocumentContainer);
    4608               0 :     nsCOMPtr<nsIDOMWindow> window(do_GetInterface(ir));
    4609               0 :     nsCOMPtr<nsPIDOMWindow> piWin(do_QueryInterface(window));
    4610               0 :     return piWin ? piWin->GetTopWindowRoot() : nsnull;
    4611                 : }
    4612                 : 
    4613                 : bool
    4614               0 : nsXULDocument::IsDocumentRightToLeft()
    4615                 : {
    4616                 :     // setting the localedir attribute on the root element forces a
    4617                 :     // specific direction for the document.
    4618               0 :     Element* element = GetRootElement();
    4619               0 :     if (element) {
    4620                 :         static nsIContent::AttrValuesArray strings[] =
    4621                 :             {&nsGkAtoms::ltr, &nsGkAtoms::rtl, nsnull};
    4622               0 :         switch (element->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::localedir,
    4623               0 :                                          strings, eCaseMatters)) {
    4624               0 :             case 0: return false;
    4625               0 :             case 1: return true;
    4626                 :             default: break; // otherwise, not a valid value, so fall through
    4627                 :         }
    4628                 :     }
    4629                 : 
    4630                 :     // otherwise, get the locale from the chrome registry and
    4631                 :     // look up the intl.uidirection.<locale> preference
    4632                 :     nsCOMPtr<nsIXULChromeRegistry> reg =
    4633               0 :         mozilla::services::GetXULChromeRegistryService();
    4634               0 :     if (!reg)
    4635               0 :         return false;
    4636                 : 
    4637               0 :     nsCAutoString package;
    4638                 :     bool isChrome;
    4639               0 :     if (NS_SUCCEEDED(mDocumentURI->SchemeIs("chrome", &isChrome)) &&
    4640                 :         isChrome) {
    4641               0 :         mDocumentURI->GetHostPort(package);
    4642                 :     }
    4643                 :     else {
    4644                 :         // use the 'global' package for about and resource uris.
    4645                 :         // otherwise, just default to left-to-right.
    4646                 :         bool isAbout, isResource;
    4647               0 :         if (NS_SUCCEEDED(mDocumentURI->SchemeIs("about", &isAbout)) &&
    4648                 :             isAbout) {
    4649               0 :             package.AssignLiteral("global");
    4650                 :         }
    4651               0 :         else if (NS_SUCCEEDED(mDocumentURI->SchemeIs("resource", &isResource)) &&
    4652                 :             isResource) {
    4653               0 :             package.AssignLiteral("global");
    4654                 :         }
    4655                 :         else {
    4656               0 :             return false;
    4657                 :         }
    4658                 :     }
    4659                 : 
    4660               0 :     bool isRTL = false;
    4661               0 :     reg->IsLocaleRTL(package, &isRTL);
    4662               0 :     return isRTL;
    4663                 : }
    4664                 : 
    4665                 : void
    4666               0 : nsXULDocument::ResetDocumentDirection()
    4667                 : {
    4668               0 :     DocumentStatesChanged(NS_DOCUMENT_STATE_RTL_LOCALE);
    4669               0 : }
    4670                 : 
    4671                 : int
    4672               0 : nsXULDocument::DirectionChanged(const char* aPrefName, void* aData)
    4673                 : {
    4674                 :   // Reset the direction and restyle the document if necessary.
    4675               0 :   nsXULDocument* doc = (nsXULDocument *)aData;
    4676               0 :   if (doc) {
    4677               0 :       doc->ResetDocumentDirection();
    4678                 :   }
    4679                 : 
    4680               0 :   return 0;
    4681                 : }
    4682                 : 
    4683                 : int
    4684               0 : nsXULDocument::GetDocumentLWTheme()
    4685                 : {
    4686               0 :     if (mDocLWTheme == Doc_Theme_Uninitialized) {
    4687               0 :         mDocLWTheme = Doc_Theme_None; // No lightweight theme by default
    4688                 : 
    4689               0 :         Element* element = GetRootElement();
    4690               0 :         nsAutoString hasLWTheme;
    4691               0 :         if (element &&
    4692               0 :             element->GetAttr(kNameSpaceID_None, nsGkAtoms::lwtheme, hasLWTheme) &&
    4693               0 :             !(hasLWTheme.IsEmpty()) &&
    4694               0 :             hasLWTheme.EqualsLiteral("true")) {
    4695               0 :             mDocLWTheme = Doc_Theme_Neutral;
    4696               0 :             nsAutoString lwTheme;
    4697               0 :             element->GetAttr(kNameSpaceID_None, nsGkAtoms::lwthemetextcolor, lwTheme);
    4698               0 :             if (!(lwTheme.IsEmpty())) {
    4699               0 :                 if (lwTheme.EqualsLiteral("dark"))
    4700               0 :                     mDocLWTheme = Doc_Theme_Dark;
    4701               0 :                 else if (lwTheme.EqualsLiteral("bright"))
    4702               0 :                     mDocLWTheme = Doc_Theme_Bright;
    4703                 :             }
    4704                 :         }
    4705                 :     }
    4706               0 :     return mDocLWTheme;
    4707                 : }
    4708                 : 
    4709                 : NS_IMETHODIMP
    4710               0 : nsXULDocument::GetBoxObjectFor(nsIDOMElement* aElement, nsIBoxObject** aResult)
    4711                 : {
    4712               0 :     return nsDocument::GetBoxObjectFor(aElement, aResult);
    4713            4392 : }

Generated by: LCOV version 1.7