LCOV - code coverage report
Current view: top level - dom/xul - XULDocument.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 1110 1922 57.8 %
Date: 2017-07-14 16:53:18 Functions: 98 153 64.1 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13