LCOV - code coverage report
Current view: top level - dom/base - nsDocument.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 1093 5628 19.4 %
Date: 2018-08-07 16:35:00 Functions: 0 0 -
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 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             :  * Base class for all our document implementations.
       9             :  */
      10             : 
      11             : #include "AudioChannelService.h"
      12             : #include "nsDocument.h"
      13             : #include "nsIDocumentInlines.h"
      14             : #include "mozilla/AnimationComparator.h"
      15             : #include "mozilla/ArrayUtils.h"
      16             : #include "mozilla/AutoRestore.h"
      17             : #include "mozilla/BinarySearch.h"
      18             : #include "mozilla/CSSEnabledState.h"
      19             : #include "mozilla/DebugOnly.h"
      20             : #include "mozilla/EffectSet.h"
      21             : #include "mozilla/EnumSet.h"
      22             : #include "mozilla/IntegerRange.h"
      23             : #include "mozilla/MemoryReporting.h"
      24             : #include "mozilla/Likely.h"
      25             : #include "mozilla/PresShell.h"
      26             : #include "mozilla/URLExtraData.h"
      27             : #include <algorithm>
      28             : 
      29             : #include "mozilla/Logging.h"
      30             : #include "plstr.h"
      31             : #include "mozilla/Sprintf.h"
      32             : 
      33             : #include "mozilla/Telemetry.h"
      34             : #include "nsIInterfaceRequestor.h"
      35             : #include "nsIInterfaceRequestorUtils.h"
      36             : #include "nsILoadContext.h"
      37             : #include "nsITextControlFrame.h"
      38             : #include "nsNumberControlFrame.h"
      39             : #include "nsUnicharUtils.h"
      40             : #include "nsContentList.h"
      41             : #include "nsCSSPseudoElements.h"
      42             : #include "nsIObserver.h"
      43             : #include "nsIBaseWindow.h"
      44             : #include "mozilla/css/Loader.h"
      45             : #include "mozilla/css/ImageLoader.h"
      46             : #include "nsDocShell.h"
      47             : #include "nsDocShellLoadTypes.h"
      48             : #include "nsIDocShellTreeItem.h"
      49             : #include "nsCOMArray.h"
      50             : #include "nsQueryObject.h"
      51             : #include "mozilla/Services.h"
      52             : #include "nsScreen.h"
      53             : #include "ChildIterator.h"
      54             : 
      55             : #include "mozilla/AsyncEventDispatcher.h"
      56             : #include "mozilla/BasicEvents.h"
      57             : #include "mozilla/EventListenerManager.h"
      58             : #include "mozilla/EventStateManager.h"
      59             : 
      60             : #include "mozilla/dom/Attr.h"
      61             : #include "mozilla/dom/BindingDeclarations.h"
      62             : #include "mozilla/dom/Element.h"
      63             : #include "mozilla/dom/Event.h"
      64             : #include "mozilla/dom/FramingChecker.h"
      65             : #include "mozilla/dom/HTMLSharedElement.h"
      66             : #include "nsGenericHTMLElement.h"
      67             : #include "mozilla/dom/CDATASection.h"
      68             : #include "mozilla/dom/ProcessingInstruction.h"
      69             : #include "nsDOMString.h"
      70             : #include "nsNodeUtils.h"
      71             : #include "nsLayoutUtils.h" // for GetFrameForPoint
      72             : #include "nsIFrame.h"
      73             : #include "nsITabChild.h"
      74             : 
      75             : #include "nsRange.h"
      76             : #include "mozilla/dom/DocumentType.h"
      77             : #include "mozilla/dom/NodeIterator.h"
      78             : #include "mozilla/dom/Promise.h"
      79             : #include "mozilla/dom/PromiseNativeHandler.h"
      80             : #include "mozilla/dom/TreeWalker.h"
      81             : 
      82             : #include "nsIServiceManager.h"
      83             : #include "mozilla/dom/ServiceWorkerManager.h"
      84             : #include "imgLoader.h"
      85             : 
      86             : #include "nsAboutProtocolUtils.h"
      87             : #include "nsCanvasFrame.h"
      88             : #include "nsContentCID.h"
      89             : #include "nsError.h"
      90             : #include "nsPresContext.h"
      91             : #include "nsThreadUtils.h"
      92             : #include "nsNodeInfoManager.h"
      93             : #include "nsIFileChannel.h"
      94             : #include "nsIMultiPartChannel.h"
      95             : #include "nsIRefreshURI.h"
      96             : #include "nsIWebNavigation.h"
      97             : #include "nsIScriptError.h"
      98             : #include "nsISimpleEnumerator.h"
      99             : #include "nsIRequestContext.h"
     100             : #include "nsStyleSheetService.h"
     101             : 
     102             : #include "nsNetUtil.h"     // for NS_NewURI
     103             : #include "nsIInputStreamChannel.h"
     104             : #include "nsIAuthPrompt.h"
     105             : #include "nsIAuthPrompt2.h"
     106             : 
     107             : #include "nsIScriptSecurityManager.h"
     108             : #include "nsIPermissionManager.h"
     109             : #include "nsIPrincipal.h"
     110             : #include "ExpandedPrincipal.h"
     111             : #include "NullPrincipal.h"
     112             : 
     113             : #include "nsIDOMWindow.h"
     114             : #include "nsPIDOMWindow.h"
     115             : #include "nsFocusManager.h"
     116             : 
     117             : // for radio group stuff
     118             : #include "nsIRadioVisitor.h"
     119             : #include "nsIFormControl.h"
     120             : 
     121             : #include "nsBidiUtils.h"
     122             : 
     123             : #include "nsContentCreatorFunctions.h"
     124             : 
     125             : #include "nsIScriptContext.h"
     126             : #include "nsBindingManager.h"
     127             : #include "nsHTMLDocument.h"
     128             : #include "nsIRequest.h"
     129             : #include "mozilla/dom/BlobURLProtocolHandler.h"
     130             : 
     131             : #include "nsCharsetSource.h"
     132             : #include "nsIParser.h"
     133             : #include "nsIContentSink.h"
     134             : 
     135             : #include "mozilla/EventDispatcher.h"
     136             : #include "mozilla/EventStates.h"
     137             : #include "mozilla/InternalMutationEvent.h"
     138             : #include "nsDOMCID.h"
     139             : 
     140             : #include "jsapi.h"
     141             : #include "nsIXPConnect.h"
     142             : #include "xpcpublic.h"
     143             : #include "nsCCUncollectableMarker.h"
     144             : #include "nsIContentPolicy.h"
     145             : #include "nsContentPolicyUtils.h"
     146             : #include "nsICategoryManager.h"
     147             : #include "nsIDocumentLoaderFactory.h"
     148             : #include "nsIDocumentLoader.h"
     149             : #include "nsIContentViewer.h"
     150             : #include "nsIXMLContentSink.h"
     151             : #include "nsIPrompt.h"
     152             : #include "nsIPropertyBag2.h"
     153             : #include "mozilla/dom/PageTransitionEvent.h"
     154             : #include "mozilla/dom/StyleRuleChangeEvent.h"
     155             : #include "mozilla/dom/StyleSheetChangeEvent.h"
     156             : #include "mozilla/dom/StyleSheetApplicableStateChangeEvent.h"
     157             : #include "nsJSUtils.h"
     158             : #include "nsFrameLoader.h"
     159             : #include "nsEscape.h"
     160             : #include "nsObjectLoadingContent.h"
     161             : #include "nsHtml5TreeOpExecutor.h"
     162             : #include "mozilla/dom/HTMLFormElement.h"
     163             : #include "mozilla/dom/HTMLLinkElement.h"
     164             : #include "mozilla/dom/HTMLMediaElement.h"
     165             : #include "mozilla/dom/HTMLIFrameElement.h"
     166             : #include "mozilla/dom/HTMLImageElement.h"
     167             : #include "mozilla/dom/HTMLTextAreaElement.h"
     168             : #include "mozilla/dom/MediaSource.h"
     169             : 
     170             : #include "mozAutoDocUpdate.h"
     171             : #include "nsGlobalWindow.h"
     172             : #include "mozilla/Encoding.h"
     173             : #include "nsDOMNavigationTiming.h"
     174             : 
     175             : #include "nsSMILAnimationController.h"
     176             : #include "imgIContainer.h"
     177             : #include "nsSVGUtils.h"
     178             : 
     179             : #include "nsRefreshDriver.h"
     180             : 
     181             : // FOR CSP (autogenerated by xpidl)
     182             : #include "nsIContentSecurityPolicy.h"
     183             : #include "mozilla/dom/nsCSPContext.h"
     184             : #include "mozilla/dom/nsCSPService.h"
     185             : #include "mozilla/dom/nsCSPUtils.h"
     186             : #include "nsHTMLStyleSheet.h"
     187             : #include "nsHTMLCSSStyleSheet.h"
     188             : #include "mozilla/dom/DOMImplementation.h"
     189             : #include "mozilla/dom/ShadowRoot.h"
     190             : #include "mozilla/dom/Comment.h"
     191             : #include "nsTextNode.h"
     192             : #include "mozilla/dom/Link.h"
     193             : #include "mozilla/dom/HTMLCollectionBinding.h"
     194             : #include "mozilla/dom/HTMLElementBinding.h"
     195             : #include "nsXULAppAPI.h"
     196             : #include "mozilla/dom/Touch.h"
     197             : #include "mozilla/dom/TouchEvent.h"
     198             : 
     199             : #include "mozilla/Preferences.h"
     200             : 
     201             : #include "imgILoader.h"
     202             : #include "imgRequestProxy.h"
     203             : #include "nsWrapperCacheInlines.h"
     204             : #include "nsSandboxFlags.h"
     205             : #include "mozilla/dom/AnimatableBinding.h"
     206             : #include "mozilla/dom/AnonymousContent.h"
     207             : #include "mozilla/dom/BindingUtils.h"
     208             : #include "mozilla/dom/ClientInfo.h"
     209             : #include "mozilla/dom/ClientState.h"
     210             : #include "mozilla/dom/DocumentFragment.h"
     211             : #include "mozilla/dom/DocumentTimeline.h"
     212             : #include "mozilla/dom/Event.h"
     213             : #include "mozilla/dom/HTMLBodyElement.h"
     214             : #include "mozilla/dom/HTMLInputElement.h"
     215             : #include "mozilla/dom/ImageTracker.h"
     216             : #include "mozilla/dom/MediaQueryList.h"
     217             : #include "mozilla/dom/NodeFilterBinding.h"
     218             : #include "mozilla/OwningNonNull.h"
     219             : #include "mozilla/dom/TabChild.h"
     220             : #include "mozilla/dom/WebComponentsBinding.h"
     221             : #include "mozilla/dom/CustomElementRegistryBinding.h"
     222             : #include "mozilla/dom/CustomElementRegistry.h"
     223             : #include "mozilla/dom/ServiceWorkerDescriptor.h"
     224             : #include "mozilla/dom/TimeoutManager.h"
     225             : #include "mozilla/ExtensionPolicyService.h"
     226             : #include "nsFrame.h"
     227             : #include "nsDOMCaretPosition.h"
     228             : #include "nsViewportInfo.h"
     229             : #include "mozilla/StaticPtr.h"
     230             : #include "nsITextControlElement.h"
     231             : #include "nsIEditor.h"
     232             : #include "nsIHttpChannelInternal.h"
     233             : #include "nsISecurityConsoleMessage.h"
     234             : #include "nsCharSeparatedTokenizer.h"
     235             : #include "mozilla/dom/XPathEvaluator.h"
     236             : #include "mozilla/dom/XPathNSResolverBinding.h"
     237             : #include "mozilla/dom/XPathResult.h"
     238             : #include "nsIDocumentEncoder.h"
     239             : #include "nsIDocumentActivity.h"
     240             : #include "nsIStructuredCloneContainer.h"
     241             : #include "nsIMutableArray.h"
     242             : #include "mozilla/dom/DOMStringList.h"
     243             : #include "nsWindowSizes.h"
     244             : #include "mozilla/dom/Location.h"
     245             : #include "mozilla/dom/FontFaceSet.h"
     246             : #include "gfxPrefs.h"
     247             : #include "nsISupportsPrimitives.h"
     248             : #include "mozilla/ServoStyleSet.h"
     249             : #include "mozilla/StyleSheet.h"
     250             : #include "mozilla/StyleSheetInlines.h"
     251             : #include "mozilla/dom/SVGDocument.h"
     252             : #include "mozilla/dom/SVGSVGElement.h"
     253             : #include "mozilla/dom/DocGroup.h"
     254             : #include "mozilla/dom/TabGroup.h"
     255             : #ifdef MOZ_XUL
     256             : #include "mozilla/dom/ListBoxObject.h"
     257             : #include "mozilla/dom/MenuBoxObject.h"
     258             : #include "mozilla/dom/ScrollBoxObject.h"
     259             : #include "mozilla/dom/TreeBoxObject.h"
     260             : #include "nsIXULWindow.h"
     261             : #include "nsIDocShellTreeOwner.h"
     262             : #endif
     263             : #include "nsIPresShellInlines.h"
     264             : 
     265             : #include "mozilla/DocLoadingTimelineMarker.h"
     266             : 
     267             : #include "nsISpeculativeConnect.h"
     268             : 
     269             : #include "mozilla/MediaManager.h"
     270             : 
     271             : #include "nsIURIClassifier.h"
     272             : #include "nsIURIMutator.h"
     273             : #include "mozilla/DocumentStyleRootIterator.h"
     274             : #include "mozilla/RestyleManager.h"
     275             : #include "mozilla/ClearOnShutdown.h"
     276             : #include "nsHTMLTags.h"
     277             : 
     278             : using namespace mozilla;
     279             : using namespace mozilla::dom;
     280             : 
     281             : typedef nsTArray<Link*> LinkArray;
     282             : 
     283             : static LazyLogModule gDocumentLeakPRLog("DocumentLeak");
     284             : static LazyLogModule gCspPRLog("CSP");
     285             : static LazyLogModule gUserInteractionPRLog("UserInteraction");
     286             : 
     287          89 : static nsresult
     288             : GetHttpChannelHelper(nsIChannel* aChannel, nsIHttpChannel** aHttpChannel)
     289         178 : {
     290           0 :   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
     291           0 :   if (httpChannel) {
     292           0 :     httpChannel.forget(aHttpChannel);
     293             :     return NS_OK;
     294             :   }
     295         178 : 
     296           0 :   nsCOMPtr<nsIMultiPartChannel> multipart = do_QueryInterface(aChannel);
     297           0 :   if (!multipart) {
     298           0 :     *aHttpChannel = nullptr;
     299             :     return NS_OK;
     300             :   }
     301           0 : 
     302           0 :   nsCOMPtr<nsIChannel> baseChannel;
     303           0 :   nsresult rv = multipart->GetBaseChannel(getter_AddRefs(baseChannel));
     304             :   if (NS_WARN_IF(NS_FAILED(rv))) {
     305             :     return rv;
     306             :   }
     307           0 : 
     308           0 :   httpChannel = do_QueryInterface(baseChannel);
     309             :   httpChannel.forget(aHttpChannel);
     310           0 : 
     311             :   return NS_OK;
     312             : }
     313             : 
     314             : ////////////////////////////////////////////////////////////////////
     315             : // PrincipalFlashClassifier
     316             : 
     317             : // Classify the flash based on the document principal.
     318             : // The usage of this class is as follows:
     319             : //
     320             : // 1) Call AsyncClassify() as early as possible to asynchronously do
     321             : //    classification against all the flash blocking related tables
     322             : //    via nsIURIClassifier.asyncClassifyLocalWithTables.
     323             : //
     324             : // 2) At any time you need the classification result, call Result()
     325             : //    and it is guaranteed to give you the result. Note that you have
     326             : //    to specify "aIsThirdParty" to the function so please make sure
     327             : //    you can already correctly decide if the document is third-party.
     328             : //
     329             : //    Behind the scenes, the sync classification API
     330             : //    (nsIURIClassifier.classifyLocalWithTable) may be called as a fallback to
     331             : //    synchronously get the result if the asyncClassifyLocalWithTables hasn't
     332             : //    been done yet.
     333             : //
     334             : // 3) You can call Result() as many times as you want and only the first time
     335             : //    it may unfortunately call the blocking sync API. The subsequent call
     336             : //    will just return the result that came out at the first time.
     337             : //
     338             : class PrincipalFlashClassifier final : public nsIURIClassifierCallback
     339             : {
     340             : public:
     341             :   NS_DECL_THREADSAFE_ISUPPORTS
     342             :   NS_DECL_NSIURICLASSIFIERCALLBACK
     343             : 
     344             :   PrincipalFlashClassifier();
     345             : 
     346             :   // Fire async classification based on the given principal.
     347             :   void AsyncClassify(nsIPrincipal* aPrincipal);
     348             : 
     349             :   // Would block if the result hasn't come out.
     350             :   mozilla::dom::FlashClassification ClassifyMaybeSync(nsIPrincipal* aPrincipal,
     351             :                                                       bool aIsThirdParty);
     352             : 
     353           0 : private:
     354             :  ~PrincipalFlashClassifier() = default;
     355             : 
     356             :   void Reset();
     357             :   bool EnsureUriClassifier();
     358             :   mozilla::dom::FlashClassification CheckIfClassifyNeeded(nsIPrincipal* aPrincipal);
     359             :   mozilla::dom::FlashClassification Resolve(bool aIsThirdParty);
     360             :   mozilla::dom::FlashClassification AsyncClassifyInternal(nsIPrincipal* aPrincipal);
     361             :   void GetClassificationTables(bool aIsThirdParty, nsACString& aTables);
     362             : 
     363             :   // For the fallback sync classification.
     364             :   nsCOMPtr<nsIURI> mClassificationURI;
     365             : 
     366             :   nsCOMPtr<nsIURIClassifier> mUriClassifier;
     367             :   bool mAsyncClassified;
     368             :   nsTArray<nsCString> mMatchedTables;
     369             :   mozilla::dom::FlashClassification mResult;
     370             : };
     371             : 
     372             : 
     373             : #define NAME_NOT_VALID ((nsSimpleContentList*)1)
     374           0 : 
     375           0 : nsIdentifierMapEntry::nsIdentifierMapEntry(const nsIdentifierMapEntry::AtomOrString& aKey)
     376           0 :   : mKey(aKey)
     377             : {}
     378        1645 : 
     379           0 : nsIdentifierMapEntry::nsIdentifierMapEntry(const nsIdentifierMapEntry::AtomOrString* aKey)
     380           0 :   : mKey(aKey ? *aKey : nullptr)
     381             : {}
     382        4806 : 
     383           0 : nsIdentifierMapEntry::~nsIdentifierMapEntry()
     384             : {}
     385        2292 : 
     386           0 : nsIdentifierMapEntry::nsIdentifierMapEntry(nsIdentifierMapEntry&& aOther)
     387           0 :   : mKey(std::move(aOther.mKey))
     388           0 :   , mIdContentList(std::move(aOther.mIdContentList))
     389           0 :   , mNameContentList(std::move(aOther.mNameContentList))
     390           0 :   , mChangeCallbacks(std::move(aOther.mChangeCallbacks))
     391           0 :   , mImageElement(std::move(aOther.mImageElement))
     392             : {}
     393             : 
     394          15 : void
     395             : nsIdentifierMapEntry::Traverse(nsCycleCollectionTraversalCallback* aCallback)
     396             : {
     397          15 :   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCallback,
     398           0 :                                      "mIdentifierMap mNameContentList");
     399             :   aCallback->NoteXPCOMChild(static_cast<nsINodeList*>(mNameContentList));
     400          30 : 
     401             :   if (mImageElement) {
     402           0 :     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCallback,
     403           0 :                                        "mIdentifierMap mImageElement element");
     404           0 :     nsIContent* imageElement = mImageElement;
     405             :     aCallback->NoteXPCOMChild(imageElement);
     406          15 :   }
     407             : }
     408             : 
     409         111 : bool
     410             : nsIdentifierMapEntry::IsEmpty()
     411         555 : {
     412           0 :   return mIdContentList.IsEmpty() && !mNameContentList &&
     413             :          !mChangeCallbacks && !mImageElement;
     414             : }
     415             : 
     416           0 : bool
     417             : nsIdentifierMapEntry::HasNameElement() const
     418           0 : {
     419             :   return mNameContentList && mNameContentList->Length() != 0;
     420             : }
     421             : 
     422         248 : Element*
     423             : nsIdentifierMapEntry::GetIdElement()
     424         248 : {
     425             :   return mIdContentList.SafeElementAt(0);
     426             : }
     427             : 
     428           0 : Element*
     429             : nsIdentifierMapEntry::GetImageIdElement()
     430           0 : {
     431             :   return mImageElement ? mImageElement.get() : GetIdElement();
     432             : }
     433             : 
     434           0 : void
     435             : nsIdentifierMapEntry::AddContentChangeCallback(nsIDocument::IDTargetObserver aCallback,
     436             :                                                void* aData, bool aForImage)
     437           0 : {
     438           0 :   if (!mChangeCallbacks) {
     439             :     mChangeCallbacks = new nsTHashtable<ChangeCallbackEntry>;
     440             :   }
     441           0 : 
     442           0 :   ChangeCallback cc = { aCallback, aData, aForImage };
     443           0 :   mChangeCallbacks->PutEntry(cc);
     444             : }
     445             : 
     446           0 : void
     447             : nsIdentifierMapEntry::RemoveContentChangeCallback(nsIDocument::IDTargetObserver aCallback,
     448             :                                                   void* aData, bool aForImage)
     449           0 : {
     450             :   if (!mChangeCallbacks)
     451           0 :     return;
     452           0 :   ChangeCallback cc = { aCallback, aData, aForImage };
     453           0 :   mChangeCallbacks->RemoveEntry(cc);
     454           0 :   if (mChangeCallbacks->Count() == 0) {
     455             :     mChangeCallbacks = nullptr;
     456             :   }
     457             : }
     458             : 
     459        1756 : void
     460             : nsIdentifierMapEntry::FireChangeCallbacks(Element* aOldElement,
     461             :                                           Element* aNewElement,
     462             :                                           bool aImageOnly)
     463        3512 : {
     464             :   if (!mChangeCallbacks)
     465             :     return;
     466           0 : 
     467           0 :   for (auto iter = mChangeCallbacks->ConstIter(); !iter.Done(); iter.Next()) {
     468             :     nsIdentifierMapEntry::ChangeCallbackEntry* entry = iter.Get();
     469             :     // Don't fire image changes for non-image observers, and don't fire element
     470           0 :     // changes for image observers when an image override is active.
     471             :     if (entry->mKey.mForImage ? (mImageElement && !aImageOnly) : aImageOnly) {
     472             :       continue;
     473             :     }
     474           0 : 
     475           0 :     if (!entry->mKey.mCallback(aOldElement, aNewElement, entry->mKey.mData)) {
     476             :       iter.Remove();
     477             :     }
     478             :   }
     479             : }
     480             : 
     481             : namespace {
     482             : 
     483             : struct PositionComparator
     484             : {
     485        1047 :   Element* const mElement;
     486             :   explicit PositionComparator(Element* const aElement) : mElement(aElement) {}
     487        1109 : 
     488           0 :   int operator()(void* aElement) const {
     489           0 :     Element* curElement = static_cast<Element*>(aElement);
     490             :     if (mElement == curElement) {
     491             :       return 0;
     492          90 :     }
     493             :     if (nsContentUtils::PositionIsBefore(mElement, curElement)) {
     494             :       return -1;
     495          90 :     }
     496             :     return 1;
     497             :   }
     498             : };
     499             : 
     500             : } // namespace
     501             : 
     502        2692 : bool
     503             : nsIdentifierMapEntry::AddIdElement(Element* aElement)
     504        2692 : {
     505           0 :   MOZ_ASSERT(aElement, "Must have element");
     506             :   MOZ_ASSERT(!mIdContentList.Contains(nullptr),
     507             :                   "Why is null in our list?");
     508             : 
     509        2692 : #ifdef DEBUG
     510             :   Element* currentElement = mIdContentList.SafeElementAt(0);
     511             : #endif
     512             : 
     513        5384 :   // Common case
     514           0 :   if (mIdContentList.IsEmpty()) {
     515             :     if (!mIdContentList.AppendElement(aElement))
     516        1645 :       return false;
     517           0 :     NS_ASSERTION(currentElement == nullptr, "How did that happen?");
     518           0 :     FireChangeCallbacks(nullptr, aElement);
     519             :     return true;
     520             :   }
     521             : 
     522             :   // We seem to have multiple content nodes for the same id, or XUL is messing
     523             :   // with us.  Search for the right place to insert the content.
     524             : 
     525        3141 :   size_t idx;
     526           0 :   if (BinarySearchIf(mIdContentList, 0, mIdContentList.Length(),
     527             :                      PositionComparator(aElement), &idx)) {
     528             :     // Already in the list, so already in the right spot.  Get out of here.
     529             :     // XXXbz this only happens because XUL does all sorts of random
     530             :     // UpdateIdTableEntry calls.  Hate, hate, hate!
     531             :     return true;
     532             :   }
     533          28 : 
     534             :   if (!mIdContentList.InsertElementAt(idx, aElement)) {
     535             :     return false;
     536             :   }
     537          28 : 
     538           0 :   if (idx == 0) {
     539           0 :     Element* oldElement = mIdContentList.SafeElementAt(1);
     540           0 :     NS_ASSERTION(currentElement == oldElement, "How did that happen?");
     541             :     FireChangeCallbacks(oldElement, aElement);
     542             :   }
     543             :   return true;
     544             : }
     545             : 
     546         111 : void
     547             : nsIdentifierMapEntry::RemoveIdElement(Element* aElement)
     548         111 : {
     549             :   MOZ_ASSERT(aElement, "Missing element");
     550             : 
     551             :   // This should only be called while the document is in an update.
     552             :   // Assertions near the call to this method guarantee this.
     553             : 
     554             :   // This could fire in OOM situations
     555             :   // Only assert this in HTML documents for now as XUL does all sorts of weird
     556         111 :   // crap.
     557             :   NS_ASSERTION(!aElement->OwnerDoc()->IsHTMLDocument() ||
     558             :                mIdContentList.Contains(aElement),
     559             :                "Removing id entry that doesn't exist");
     560             : 
     561             :   // XXXbz should this ever Compact() I guess when all the content is gone
     562         111 :   // we'll just get cleaned up in the natural order of things...
     563           0 :   Element* currentElement = mIdContentList.SafeElementAt(0);
     564           0 :   mIdContentList.RemoveElement(aElement);
     565           0 :   if (currentElement == aElement) {
     566             :     FireChangeCallbacks(currentElement, mIdContentList.SafeElementAt(0));
     567         111 :   }
     568             : }
     569             : 
     570           0 : void
     571             : nsIdentifierMapEntry::SetImageElement(Element* aElement)
     572           0 : {
     573           0 :   Element* oldElement = GetImageIdElement();
     574           0 :   mImageElement = aElement;
     575           0 :   Element* newElement = GetImageIdElement();
     576           0 :   if (oldElement != newElement) {
     577             :     FireChangeCallbacks(oldElement, newElement, true);
     578           0 :   }
     579             : }
     580             : 
     581             : namespace mozilla {
     582             : namespace dom {
     583             : class SimpleHTMLCollection final : public nsSimpleContentList
     584             :                                  , public nsIHTMLCollection
     585             : {
     586           0 : public:
     587             :   explicit SimpleHTMLCollection(nsINode* aRoot) : nsSimpleContentList(aRoot) {}
     588             : 
     589             :   NS_DECL_ISUPPORTS_INHERITED
     590           0 : 
     591             :   virtual nsINode* GetParentObject() override
     592           0 :   {
     593             :     return nsSimpleContentList::GetParentObject();
     594           0 :   }
     595             :   virtual uint32_t Length() override
     596           0 :   {
     597             :     return nsSimpleContentList::Length();
     598           0 :   }
     599             :   virtual Element* GetElementAt(uint32_t aIndex) override
     600           0 :   {
     601             :     return mElements.SafeElementAt(aIndex)->AsElement();
     602             :   }
     603           0 : 
     604             :   virtual Element* GetFirstNamedElement(const nsAString& aName,
     605             :                                         bool& aFound) override
     606           0 :   {
     607           0 :     aFound = false;
     608           0 :     RefPtr<nsAtom> name = NS_Atomize(aName);
     609           0 :     for (uint32_t i = 0; i < mElements.Length(); i++) {
     610           0 :       MOZ_DIAGNOSTIC_ASSERT(mElements[i]);
     611           0 :       Element* element = mElements[i]->AsElement();
     612           0 :       if (element->GetID() == name ||
     613           0 :           (element->HasName() &&
     614           0 :            element->GetParsedAttr(nsGkAtoms::name)->GetAtomValue() == name)) {
     615           0 :         aFound = true;
     616             :         return element;
     617             :       }
     618             :     }
     619             :     return nullptr;
     620             :   }
     621           0 : 
     622             :   virtual void GetSupportedNames(nsTArray<nsString>& aNames) override
     623           0 :   {
     624           0 :     AutoTArray<nsAtom*, 8> atoms;
     625           0 :     for (uint32_t i = 0; i < mElements.Length(); i++) {
     626           0 :       MOZ_DIAGNOSTIC_ASSERT(mElements[i]);
     627             :       Element* element = mElements[i]->AsElement();
     628           0 : 
     629           0 :       nsAtom* id = element->GetID();
     630           0 :       MOZ_ASSERT(id != nsGkAtoms::_empty);
     631           0 :       if (id && !atoms.Contains(id)) {
     632             :         atoms.AppendElement(id);
     633             :       }
     634           0 : 
     635           0 :       if (element->HasName()) {
     636           0 :         nsAtom* name = element->GetParsedAttr(nsGkAtoms::name)->GetAtomValue();
     637           0 :         MOZ_ASSERT(name && name != nsGkAtoms::_empty);
     638           0 :         if (name && !atoms.Contains(name)) {
     639             :           atoms.AppendElement(name);
     640             :         }
     641             :       }
     642             :     }
     643           0 : 
     644           0 :     nsString* names = aNames.AppendElements(atoms.Length());
     645           0 :     for (uint32_t i = 0; i < atoms.Length(); i++) {
     646             :       atoms[i]->ToString(names[i]);
     647           0 :     }
     648             :   }
     649           0 : 
     650             :   virtual JSObject* GetWrapperPreserveColorInternal() override
     651           0 :   {
     652             :     return nsWrapperCache::GetWrapperPreserveColor();
     653           0 :   }
     654             :   virtual void PreserveWrapperInternal(nsISupports* aScriptObjectHolder) override
     655           0 :   {
     656           0 :     nsWrapperCache::PreserveWrapper(aScriptObjectHolder);
     657           0 :   }
     658             :   virtual JSObject* WrapObject(JSContext *aCx,
     659             :                                JS::Handle<JSObject*> aGivenProto) override
     660           0 :   {
     661             :     return HTMLCollectionBinding::Wrap(aCx, this, aGivenProto);
     662             :   }
     663             : 
     664             :   using nsBaseContentList::Item;
     665             : 
     666           0 : private:
     667             :   virtual ~SimpleHTMLCollection() {}
     668             : };
     669           0 : 
     670             : NS_IMPL_ISUPPORTS_INHERITED(SimpleHTMLCollection, nsSimpleContentList,
     671             :                             nsIHTMLCollection)
     672             : 
     673             : } // namespace dom
     674             : } // namespace mozilla
     675             : 
     676           0 : void
     677             : nsIdentifierMapEntry::AddNameElement(nsINode* aNode, Element* aElement)
     678           0 : {
     679           0 :   if (!mNameContentList) {
     680             :     mNameContentList = new SimpleHTMLCollection(aNode);
     681             :   }
     682           0 : 
     683           0 :   mNameContentList->AppendElement(aElement);
     684             : }
     685             : 
     686           0 : void
     687             : nsIdentifierMapEntry::RemoveNameElement(Element* aElement)
     688           0 : {
     689           0 :   if (mNameContentList) {
     690             :     mNameContentList->RemoveElement(aElement);
     691           0 :   }
     692             : }
     693             : 
     694           0 : bool
     695             : nsIdentifierMapEntry::HasIdElementExposedAsHTMLDocumentProperty()
     696           0 : {
     697           0 :   Element* idElement = GetIdElement();
     698           0 :   return idElement &&
     699             :          nsGenericHTMLElement::ShouldExposeIdAsHTMLDocumentProperty(idElement);
     700             : }
     701             : 
     702           0 : size_t
     703             : nsIdentifierMapEntry::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
     704           0 : {
     705             :   return mKey.mString.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
     706             : }
     707             : 
     708             : // Helper structs for the content->subdoc map
     709             : 
     710             : class SubDocMapEntry : public PLDHashEntryHdr
     711             : {
     712             : public:
     713             :   // Both of these are strong references
     714             :   Element *mKey; // must be first, to look like PLDHashEntryStub
     715             :   nsIDocument *mSubDocument;
     716             : };
     717             : 
     718             : 
     719             : /**
     720             :  * A struct that holds all the information about a radio group.
     721           0 :  */
     722             : struct nsRadioGroupStruct
     723           0 : {
     724           0 :   nsRadioGroupStruct()
     725           0 :     : mRequiredRadioCount(0)
     726           0 :     , mGroupSuffersFromValueMissing(false)
     727             :   {}
     728             : 
     729             :   /**
     730             :    * A strong pointer to the currently selected radio button.
     731             :    */
     732             :   RefPtr<HTMLInputElement> mSelectedRadioButton;
     733             :   nsCOMArray<nsIFormControl> mRadioButtons;
     734             :   uint32_t mRequiredRadioCount;
     735             :   bool mGroupSuffersFromValueMissing;
     736             : };
     737             : 
     738        1875 : // nsOnloadBlocker implementation
     739             : NS_IMPL_ISUPPORTS(nsOnloadBlocker, nsIRequest)
     740             : 
     741         132 : NS_IMETHODIMP
     742             : nsOnloadBlocker::GetName(nsACString &aResult)
     743         132 : {
     744           0 :   aResult.AssignLiteral("about:document-onload-blocker");
     745             :   return NS_OK;
     746             : }
     747             : 
     748           0 : NS_IMETHODIMP
     749             : nsOnloadBlocker::IsPending(bool *_retval)
     750           0 : {
     751           0 :   *_retval = true;
     752             :   return NS_OK;
     753             : }
     754             : 
     755           0 : NS_IMETHODIMP
     756             : nsOnloadBlocker::GetStatus(nsresult *status)
     757           0 : {
     758           0 :   *status = NS_OK;
     759             :   return NS_OK;
     760             : }
     761             : 
     762           2 : NS_IMETHODIMP
     763             : nsOnloadBlocker::Cancel(nsresult status)
     764           2 : {
     765             :   return NS_OK;
     766             : }
     767           0 : NS_IMETHODIMP
     768             : nsOnloadBlocker::Suspend(void)
     769           0 : {
     770             :   return NS_OK;
     771             : }
     772           0 : NS_IMETHODIMP
     773             : nsOnloadBlocker::Resume(void)
     774           0 : {
     775             :   return NS_OK;
     776             : }
     777             : 
     778           0 : NS_IMETHODIMP
     779             : nsOnloadBlocker::GetLoadGroup(nsILoadGroup * *aLoadGroup)
     780           0 : {
     781           0 :   *aLoadGroup = nullptr;
     782             :   return NS_OK;
     783             : }
     784             : 
     785           0 : NS_IMETHODIMP
     786             : nsOnloadBlocker::SetLoadGroup(nsILoadGroup * aLoadGroup)
     787           0 : {
     788             :   return NS_OK;
     789             : }
     790             : 
     791          94 : NS_IMETHODIMP
     792             : nsOnloadBlocker::GetLoadFlags(nsLoadFlags *aLoadFlags)
     793          94 : {
     794           0 :   *aLoadFlags = nsIRequest::LOAD_NORMAL;
     795             :   return NS_OK;
     796             : }
     797             : 
     798           0 : NS_IMETHODIMP
     799             : nsOnloadBlocker::SetLoadFlags(nsLoadFlags aLoadFlags)
     800           0 : {
     801             :   return NS_OK;
     802             : }
     803             : 
     804             : // ==================================================================
     805          60 : 
     806           0 : nsExternalResourceMap::nsExternalResourceMap()
     807             :   : mHaveShutDown(false)
     808          60 : {
     809             : }
     810             : 
     811           0 : nsIDocument*
     812             : nsExternalResourceMap::RequestResource(nsIURI* aURI,
     813             :                                        nsINode* aRequestingNode,
     814             :                                        nsIDocument* aDisplayDocument,
     815             :                                        ExternalResourceLoad** aPendingLoad)
     816             : {
     817             :   // If we ever start allowing non-same-origin loads here, we might need to do
     818             :   // something interesting with aRequestingPrincipal even for the hashtable
     819           0 :   // gets.
     820           0 :   MOZ_ASSERT(aURI, "Must have a URI");
     821           0 :   MOZ_ASSERT(aRequestingNode, "Must have a node");
     822           0 :   *aPendingLoad = nullptr;
     823             :   if (mHaveShutDown) {
     824             :     return nullptr;
     825             :   }
     826             : 
     827           0 :   // First, make sure we strip the ref from aURI.
     828           0 :   nsCOMPtr<nsIURI> clone;
     829           0 :   nsresult rv = aURI->CloneIgnoringRef(getter_AddRefs(clone));
     830             :   if (NS_FAILED(rv) || !clone) {
     831             :     return nullptr;
     832             :   }
     833             : 
     834           0 :   ExternalResource* resource;
     835           0 :   mMap.Get(clone, &resource);
     836           0 :   if (resource) {
     837             :     return resource->mDocument;
     838             :   }
     839           0 : 
     840           0 :   RefPtr<PendingLoad>& loadEntry = mPendingLoads.GetOrInsert(clone);
     841           0 :   if (loadEntry) {
     842           0 :     RefPtr<PendingLoad> load(loadEntry);
     843             :     load.forget(aPendingLoad);
     844             :     return nullptr;
     845             :   }
     846           0 : 
     847           0 :   RefPtr<PendingLoad> load(new PendingLoad(aDisplayDocument));
     848             :   loadEntry = load;
     849           0 : 
     850             :   if (NS_FAILED(load->StartLoad(clone, aRequestingNode))) {
     851             :     // Make sure we don't thrash things by trying this load again, since
     852           0 :     // chances are it failed for good reasons (security check, etc).
     853             :     AddExternalResource(clone, nullptr, nullptr, aDisplayDocument);
     854           0 :   } else {
     855             :     load.forget(aPendingLoad);
     856             :   }
     857             : 
     858             :   return nullptr;
     859             : }
     860             : 
     861         166 : void
     862             : nsExternalResourceMap::EnumerateResources(nsIDocument::nsSubDocEnumFunc aCallback,
     863             :                                           void* aData)
     864         498 : {
     865           0 :   for (auto iter = mMap.Iter(); !iter.Done(); iter.Next()) {
     866           0 :     nsExternalResourceMap::ExternalResource* resource = iter.UserData();
     867             :     if (resource->mDocument && !aCallback(resource->mDocument, aData)) {
     868             :       break;
     869             :     }
     870         166 :   }
     871             : }
     872             : 
     873          41 : void
     874             : nsExternalResourceMap::Traverse(nsCycleCollectionTraversalCallback* aCallback) const
     875             : {
     876             :   // mPendingLoads will get cleared out as the requests complete, so
     877         123 :   // no need to worry about those here.
     878           0 :   for (auto iter = mMap.ConstIter(); !iter.Done(); iter.Next()) {
     879             :     nsExternalResourceMap::ExternalResource* resource = iter.UserData();
     880             : 
     881             :     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCallback,
     882           0 :                                        "mExternalResourceMap.mMap entry"
     883           0 :                                        "->mDocument");
     884             :     aCallback->NoteXPCOMChild(resource->mDocument);
     885             : 
     886             :     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCallback,
     887           0 :                                        "mExternalResourceMap.mMap entry"
     888           0 :                                        "->mViewer");
     889             :     aCallback->NoteXPCOMChild(resource->mViewer);
     890             : 
     891             :     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCallback,
     892           0 :                                        "mExternalResourceMap.mMap entry"
     893           0 :                                        "->mLoadGroup");
     894             :     aCallback->NoteXPCOMChild(resource->mLoadGroup);
     895          41 :   }
     896             : }
     897             : 
     898           8 : void
     899             : nsExternalResourceMap::HideViewers()
     900          24 : {
     901           0 :   for (auto iter = mMap.Iter(); !iter.Done(); iter.Next()) {
     902           0 :     nsCOMPtr<nsIContentViewer> viewer = iter.UserData()->mViewer;
     903           0 :     if (viewer) {
     904             :       viewer->Hide();
     905             :     }
     906           8 :   }
     907             : }
     908             : 
     909          27 : void
     910             : nsExternalResourceMap::ShowViewers()
     911          81 : {
     912           0 :   for (auto iter = mMap.Iter(); !iter.Done(); iter.Next()) {
     913           0 :     nsCOMPtr<nsIContentViewer> viewer = iter.UserData()->mViewer;
     914           0 :     if (viewer) {
     915             :       viewer->Show();
     916             :     }
     917          27 :   }
     918             : }
     919             : 
     920           0 : void
     921             : TransferZoomLevels(nsIDocument* aFromDoc,
     922             :                    nsIDocument* aToDoc)
     923           0 : {
     924             :   MOZ_ASSERT(aFromDoc && aToDoc,
     925             :              "transferring zoom levels from/to null doc");
     926           0 : 
     927           0 :   nsPresContext* fromCtxt = aFromDoc->GetPresContext();
     928             :   if (!fromCtxt)
     929             :     return;
     930           0 : 
     931           0 :   nsPresContext* toCtxt = aToDoc->GetPresContext();
     932             :   if (!toCtxt)
     933             :     return;
     934           0 : 
     935           0 :   toCtxt->SetFullZoom(fromCtxt->GetFullZoom());
     936           0 :   toCtxt->SetBaseMinFontSize(fromCtxt->BaseMinFontSize());
     937           0 :   toCtxt->SetTextZoom(fromCtxt->TextZoom());
     938             :   toCtxt->SetOverrideDPPX(fromCtxt->GetOverrideDPPX());
     939             : }
     940             : 
     941           0 : void
     942             : TransferShowingState(nsIDocument* aFromDoc, nsIDocument* aToDoc)
     943           0 : {
     944             :   MOZ_ASSERT(aFromDoc && aToDoc,
     945             :              "transferring showing state from/to null doc");
     946           0 : 
     947           0 :   if (aFromDoc->IsShowing()) {
     948             :     aToDoc->OnPageShow(true, nullptr);
     949           0 :   }
     950             : }
     951             : 
     952           0 : nsresult
     953             : nsExternalResourceMap::AddExternalResource(nsIURI* aURI,
     954             :                                            nsIContentViewer* aViewer,
     955             :                                            nsILoadGroup* aLoadGroup,
     956             :                                            nsIDocument* aDisplayDocument)
     957           0 : {
     958           0 :   MOZ_ASSERT(aURI, "Unexpected call");
     959             :   MOZ_ASSERT((aViewer && aLoadGroup) || (!aViewer && !aLoadGroup),
     960             :              "Must have both or neither");
     961           0 : 
     962           0 :   RefPtr<PendingLoad> load;
     963             :   mPendingLoads.Remove(aURI, getter_AddRefs(load));
     964           0 : 
     965             :   nsresult rv = NS_OK;
     966           0 : 
     967           0 :   nsCOMPtr<nsIDocument> doc;
     968           0 :   if (aViewer) {
     969           0 :     doc = aViewer->GetDocument();
     970             :     NS_ASSERTION(doc, "Must have a document");
     971           0 : 
     972             :     if (doc->IsXULDocument()) {
     973             :       // We don't handle XUL stuff here yet.
     974             :       rv = NS_ERROR_NOT_AVAILABLE;
     975           0 :     } else {
     976             :       doc->SetDisplayDocument(aDisplayDocument);
     977             : 
     978           0 :       // Make sure that hiding our viewer will tear down its presentation.
     979             :       aViewer->SetSticky(false);
     980           0 : 
     981           0 :       rv = aViewer->Init(nullptr, nsIntRect(0, 0, 0, 0));
     982           0 :       if (NS_SUCCEEDED(rv)) {
     983             :         rv = aViewer->Open(nullptr, nullptr);
     984             :       }
     985             :     }
     986           0 : 
     987           0 :     if (NS_FAILED(rv)) {
     988           0 :       doc = nullptr;
     989           0 :       aViewer = nullptr;
     990             :       aLoadGroup = nullptr;
     991             :     }
     992             :   }
     993           0 : 
     994           0 :   ExternalResource* newResource = new ExternalResource();
     995             :   mMap.Put(aURI, newResource);
     996           0 : 
     997           0 :   newResource->mDocument = doc;
     998           0 :   newResource->mViewer = aViewer;
     999           0 :   newResource->mLoadGroup = aLoadGroup;
    1000           0 :   if (doc) {
    1001           0 :     TransferZoomLevels(aDisplayDocument, doc);
    1002             :     TransferShowingState(aDisplayDocument, doc);
    1003             :   }
    1004           0 : 
    1005           0 :   const nsTArray< nsCOMPtr<nsIObserver> > & obs = load->Observers();
    1006           0 :   for (uint32_t i = 0; i < obs.Length(); ++i) {
    1007             :     obs[i]->Observe(doc, "external-resource-document-created", nullptr);
    1008             :   }
    1009           0 : 
    1010             :   return rv;
    1011             : }
    1012           0 : 
    1013             : NS_IMPL_ISUPPORTS(nsExternalResourceMap::PendingLoad,
    1014             :                   nsIStreamListener,
    1015             :                   nsIRequestObserver)
    1016             : 
    1017           0 : NS_IMETHODIMP
    1018             : nsExternalResourceMap::PendingLoad::OnStartRequest(nsIRequest *aRequest,
    1019             :                                                    nsISupports *aContext)
    1020           0 : {
    1021           0 :   nsExternalResourceMap& map = mDisplayDocument->ExternalResourceMap();
    1022             :   if (map.HaveShutDown()) {
    1023             :     return NS_BINDING_ABORTED;
    1024             :   }
    1025           0 : 
    1026           0 :   nsCOMPtr<nsIContentViewer> viewer;
    1027           0 :   nsCOMPtr<nsILoadGroup> loadGroup;
    1028           0 :   nsresult rv = SetupViewer(aRequest, getter_AddRefs(viewer),
    1029             :                             getter_AddRefs(loadGroup));
    1030             : 
    1031           0 :   // Make sure to do this no matter what
    1032           0 :   nsresult rv2 = map.AddExternalResource(mURI, viewer, loadGroup,
    1033           0 :                                          mDisplayDocument);
    1034             :   if (NS_FAILED(rv)) {
    1035             :     return rv;
    1036           0 :   }
    1037           0 :   if (NS_FAILED(rv2)) {
    1038           0 :     mTargetListener = nullptr;
    1039             :     return rv2;
    1040             :   }
    1041           0 : 
    1042             :   return mTargetListener->OnStartRequest(aRequest, aContext);
    1043             : }
    1044             : 
    1045           0 : nsresult
    1046             : nsExternalResourceMap::PendingLoad::SetupViewer(nsIRequest* aRequest,
    1047             :                                                 nsIContentViewer** aViewer,
    1048             :                                                 nsILoadGroup** aLoadGroup)
    1049           0 : {
    1050           0 :   MOZ_ASSERT(!mTargetListener, "Unexpected call to OnStartRequest");
    1051           0 :   *aViewer = nullptr;
    1052             :   *aLoadGroup = nullptr;
    1053           0 : 
    1054           0 :   nsCOMPtr<nsIChannel> chan(do_QueryInterface(aRequest));
    1055             :   NS_ENSURE_TRUE(chan, NS_ERROR_UNEXPECTED);
    1056           0 : 
    1057           0 :   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aRequest));
    1058             :   if (httpChannel) {
    1059           0 :     bool requestSucceeded;
    1060           0 :     if (NS_FAILED(httpChannel->GetRequestSucceeded(&requestSucceeded)) ||
    1061             :         !requestSucceeded) {
    1062           0 :       // Bail out on this load, since it looks like we have an HTTP error page
    1063             :       return NS_BINDING_ABORTED;
    1064             :     }
    1065             :   }
    1066           0 : 
    1067           0 :   nsAutoCString type;
    1068             :   chan->GetContentType(type);
    1069           0 : 
    1070           0 :   nsCOMPtr<nsILoadGroup> loadGroup;
    1071             :   chan->GetLoadGroup(getter_AddRefs(loadGroup));
    1072             : 
    1073             :   // Give this document its own loadgroup
    1074           0 :   nsCOMPtr<nsILoadGroup> newLoadGroup =
    1075           0 :         do_CreateInstance(NS_LOADGROUP_CONTRACTID);
    1076           0 :   NS_ENSURE_TRUE(newLoadGroup, NS_ERROR_OUT_OF_MEMORY);
    1077             :   newLoadGroup->SetLoadGroup(loadGroup);
    1078           0 : 
    1079           0 :   nsCOMPtr<nsIInterfaceRequestor> callbacks;
    1080             :   loadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks));
    1081             : 
    1082           0 :   nsCOMPtr<nsIInterfaceRequestor> newCallbacks =
    1083           0 :     new LoadgroupCallbacks(callbacks);
    1084             :   newLoadGroup->SetNotificationCallbacks(newCallbacks);
    1085             : 
    1086             :   // This is some serious hackery cribbed from docshell
    1087           0 :   nsCOMPtr<nsICategoryManager> catMan =
    1088           0 :     do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
    1089           0 :   NS_ENSURE_TRUE(catMan, NS_ERROR_NOT_AVAILABLE);
    1090           0 :   nsCString contractId;
    1091           0 :   nsresult rv = catMan->GetCategoryEntry("Gecko-Content-Viewers", type.get(),
    1092           0 :                                          getter_Copies(contractId));
    1093             :   NS_ENSURE_SUCCESS(rv, rv);
    1094           0 :   nsCOMPtr<nsIDocumentLoaderFactory> docLoaderFactory =
    1095           0 :     do_GetService(contractId.get());
    1096             :   NS_ENSURE_TRUE(docLoaderFactory, NS_ERROR_NOT_AVAILABLE);
    1097           0 : 
    1098           0 :   nsCOMPtr<nsIContentViewer> viewer;
    1099           0 :   nsCOMPtr<nsIStreamListener> listener;
    1100             :   rv = docLoaderFactory->CreateInstance("external-resource", chan, newLoadGroup,
    1101           0 :                                         type, nullptr, nullptr,
    1102           0 :                                         getter_AddRefs(listener),
    1103           0 :                                         getter_AddRefs(viewer));
    1104           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1105             :   NS_ENSURE_TRUE(viewer, NS_ERROR_UNEXPECTED);
    1106           0 : 
    1107           0 :   nsCOMPtr<nsIParser> parser = do_QueryInterface(listener);
    1108             :   if (!parser) {
    1109             :     /// We don't want to deal with the various fake documents yet
    1110             :     return NS_ERROR_NOT_IMPLEMENTED;
    1111             :   }
    1112             : 
    1113           0 :   // We can't handle HTML and other weird things here yet.
    1114           0 :   nsIContentSink* sink = parser->GetContentSink();
    1115           0 :   nsCOMPtr<nsIXMLContentSink> xmlSink = do_QueryInterface(sink);
    1116             :   if (!xmlSink) {
    1117             :     return NS_ERROR_NOT_IMPLEMENTED;
    1118             :   }
    1119           0 : 
    1120           0 :   listener.swap(mTargetListener);
    1121           0 :   viewer.forget(aViewer);
    1122           0 :   newLoadGroup.forget(aLoadGroup);
    1123             :   return NS_OK;
    1124             : }
    1125             : 
    1126           0 : NS_IMETHODIMP
    1127             : nsExternalResourceMap::PendingLoad::OnDataAvailable(nsIRequest* aRequest,
    1128             :                                                     nsISupports* aContext,
    1129             :                                                     nsIInputStream* aStream,
    1130             :                                                     uint64_t aOffset,
    1131             :                                                     uint32_t aCount)
    1132             : {
    1133           0 :   // mTargetListener might be null if SetupViewer or AddExternalResource failed.
    1134           0 :   NS_ENSURE_TRUE(mTargetListener, NS_ERROR_FAILURE);
    1135             :   if (mDisplayDocument->ExternalResourceMap().HaveShutDown()) {
    1136             :     return NS_BINDING_ABORTED;
    1137           0 :   }
    1138           0 :   return mTargetListener->OnDataAvailable(aRequest, aContext, aStream, aOffset,
    1139             :                                           aCount);
    1140             : }
    1141             : 
    1142           0 : NS_IMETHODIMP
    1143             : nsExternalResourceMap::PendingLoad::OnStopRequest(nsIRequest* aRequest,
    1144             :                                                   nsISupports* aContext,
    1145             :                                                   nsresult aStatus)
    1146             : {
    1147           0 :   // mTargetListener might be null if SetupViewer or AddExternalResource failed
    1148           0 :   if (mTargetListener) {
    1149           0 :     nsCOMPtr<nsIStreamListener> listener;
    1150           0 :     mTargetListener.swap(listener);
    1151             :     return listener->OnStopRequest(aRequest, aContext, aStatus);
    1152             :   }
    1153             : 
    1154             :   return NS_OK;
    1155             : }
    1156             : 
    1157           0 : nsresult
    1158             : nsExternalResourceMap::PendingLoad::StartLoad(nsIURI* aURI,
    1159             :                                               nsINode* aRequestingNode)
    1160           0 : {
    1161           0 :   MOZ_ASSERT(aURI, "Must have a URI");
    1162             :   MOZ_ASSERT(aRequestingNode, "Must have a node");
    1163             : 
    1164           0 :   nsCOMPtr<nsILoadGroup> loadGroup =
    1165             :     aRequestingNode->OwnerDoc()->GetDocumentLoadGroup();
    1166           0 : 
    1167           0 :   nsresult rv = NS_OK;
    1168           0 :   nsCOMPtr<nsIChannel> channel;
    1169             :   rv = NS_NewChannel(getter_AddRefs(channel),
    1170             :                      aURI,
    1171             :                      aRequestingNode,
    1172             :                      nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS,
    1173             :                      nsIContentPolicy::TYPE_OTHER,
    1174           0 :                      nullptr, // aPerformanceStorage
    1175           0 :                      loadGroup);
    1176             :   NS_ENSURE_SUCCESS(rv, rv);
    1177           0 : 
    1178             :   mURI = aURI;
    1179           0 : 
    1180             :   return channel->AsyncOpen2(this);
    1181             : }
    1182           0 : 
    1183             : NS_IMPL_ISUPPORTS(nsExternalResourceMap::LoadgroupCallbacks,
    1184             :                   nsIInterfaceRequestor)
    1185             : 
    1186             : #define IMPL_SHIM(_i) \
    1187             :   NS_IMPL_ISUPPORTS(nsExternalResourceMap::LoadgroupCallbacks::_i##Shim, _i)
    1188           0 : 
    1189           0 : IMPL_SHIM(nsILoadContext)
    1190           0 : IMPL_SHIM(nsIProgressEventSink)
    1191           0 : IMPL_SHIM(nsIChannelEventSink)
    1192           0 : IMPL_SHIM(nsISecurityEventSink)
    1193             : IMPL_SHIM(nsIApplicationCacheContainer)
    1194             : 
    1195             : #undef IMPL_SHIM
    1196             : 
    1197             : #define IID_IS(_i) aIID.Equals(NS_GET_IID(_i))
    1198             : 
    1199             : #define TRY_SHIM(_i)                                                       \
    1200             :   PR_BEGIN_MACRO                                                           \
    1201             :     if (IID_IS(_i)) {                                                      \
    1202             :       nsCOMPtr<_i> real = do_GetInterface(mCallbacks);                     \
    1203             :       if (!real) {                                                         \
    1204             :         return NS_NOINTERFACE;                                             \
    1205             :       }                                                                    \
    1206             :       nsCOMPtr<_i> shim = new _i##Shim(this, real);                        \
    1207             :       shim.forget(aSink);                                                  \
    1208             :       return NS_OK;                                                        \
    1209             :     }                                                                      \
    1210             :   PR_END_MACRO
    1211             : 
    1212           0 : NS_IMETHODIMP
    1213             : nsExternalResourceMap::LoadgroupCallbacks::GetInterface(const nsIID & aIID,
    1214             :                                                         void **aSink)
    1215           0 : {
    1216           0 :   if (mCallbacks &&
    1217           0 :       (IID_IS(nsIPrompt) || IID_IS(nsIAuthPrompt) || IID_IS(nsIAuthPrompt2) ||
    1218           0 :        IID_IS(nsITabChild))) {
    1219             :     return mCallbacks->GetInterface(aIID, aSink);
    1220             :   }
    1221           0 : 
    1222             :   *aSink = nullptr;
    1223           0 : 
    1224           0 :   TRY_SHIM(nsILoadContext);
    1225           0 :   TRY_SHIM(nsIProgressEventSink);
    1226           0 :   TRY_SHIM(nsIChannelEventSink);
    1227           0 :   TRY_SHIM(nsISecurityEventSink);
    1228             :   TRY_SHIM(nsIApplicationCacheContainer);
    1229             : 
    1230             :   return NS_NOINTERFACE;
    1231             : }
    1232             : 
    1233             : #undef TRY_SHIM
    1234             : #undef IID_IS
    1235           0 : 
    1236             : nsExternalResourceMap::ExternalResource::~ExternalResource()
    1237           0 : {
    1238           0 :   if (mViewer) {
    1239           0 :     mViewer->Close(nullptr);
    1240             :     mViewer->Destroy();
    1241           0 :   }
    1242             : }
    1243             : 
    1244             : // ==================================================================
    1245             : // =
    1246             : // ==================================================================
    1247             : 
    1248             : // If we ever have an nsIDocumentObserver notification for stylesheet title
    1249             : // changes we should update the list from that instead of overriding
    1250           0 : // EnsureFresh.
    1251             : class nsDOMStyleSheetSetList final : public DOMStringList
    1252             : {
    1253             : public:
    1254             :   explicit nsDOMStyleSheetSetList(nsIDocument* aDocument);
    1255             : 
    1256             :   void Disconnect()
    1257           0 :   {
    1258             :     mDocument = nullptr;
    1259             :   }
    1260             : 
    1261             :   virtual void EnsureFresh() override;
    1262             : 
    1263             : protected:
    1264             :   nsIDocument* mDocument;  // Our document; weak ref.  It'll let us know if it
    1265             :                            // dies.
    1266             : };
    1267           0 : 
    1268           0 : nsDOMStyleSheetSetList::nsDOMStyleSheetSetList(nsIDocument* aDocument)
    1269             :   : mDocument(aDocument)
    1270           0 : {
    1271           0 :   NS_ASSERTION(mDocument, "Must have document!");
    1272             : }
    1273             : 
    1274           0 : void
    1275             : nsDOMStyleSheetSetList::EnsureFresh()
    1276           0 : {
    1277             :   MOZ_ASSERT(NS_IsMainThread());
    1278           0 : 
    1279             :   mNames.Clear();
    1280           0 : 
    1281           0 :   if (!mDocument) {
    1282             :     return; // Spec says "no exceptions", and we have no style sets if we have
    1283             :             // no document, for sure
    1284             :   }
    1285           0 : 
    1286           0 :   size_t count = mDocument->SheetCount();
    1287           0 :   nsAutoString title;
    1288           0 :   for (size_t index = 0; index < count; index++) {
    1289           0 :     StyleSheet* sheet = mDocument->SheetAt(index);
    1290           0 :     NS_ASSERTION(sheet, "Null sheet in sheet list!");
    1291           0 :     sheet->GetTitle(title);
    1292           0 :     if (!title.IsEmpty() && !mNames.Contains(title) && !Add(title)) {
    1293             :       return;
    1294             :     }
    1295             :   }
    1296             : }
    1297             : 
    1298           1 : // ==================================================================
    1299             : nsIDocument::SelectorCache::SelectorCache(nsIEventTarget* aEventTarget)
    1300           2 :   : nsExpirationTracker<SelectorCacheKey, 4>(
    1301           0 :       1000, "nsIDocument::SelectorCache", aEventTarget)
    1302             : { }
    1303           0 : 
    1304             : nsIDocument::SelectorCache::~SelectorCache()
    1305           0 : {
    1306           0 :   AgeAllGenerations();
    1307             : }
    1308           2 : 
    1309             : void nsIDocument::SelectorCache::NotifyExpired(SelectorCacheKey* aSelector)
    1310           2 : {
    1311           0 :   MOZ_ASSERT(NS_IsMainThread());
    1312             :   MOZ_ASSERT(aSelector);
    1313             : 
    1314             :   // There is no guarantee that this method won't be re-entered when selector
    1315             :   // matching is ongoing because "memory-pressure" could be notified immediately
    1316             :   // when OOM happens according to the design of nsExpirationTracker.
    1317             :   // The perfect solution is to delete the |aSelector| and its
    1318             :   // RawServoSelectorList in mTable asynchronously.
    1319             :   // We remove these objects synchronously for now because NotifyExpired() will
    1320             :   // never be triggered by "memory-pressure" which is not implemented yet in
    1321             :   // the stage 2 of mozalloc_handle_oom().
    1322             :   // Once these objects are removed asynchronously, we should update the warning
    1323           2 :   // added in mozalloc_handle_oom() as well.
    1324           0 :   RemoveObject(aSelector);
    1325           0 :   mTable.Remove(aSelector->mKey);
    1326           0 :   delete aSelector;
    1327             : }
    1328           8 : 
    1329             : struct nsIDocument::FrameRequest
    1330             : {
    1331           2 :   FrameRequest(FrameRequestCallback& aCallback,
    1332             :                int32_t aHandle) :
    1333           2 :     mCallback(&aCallback),
    1334             :     mHandle(aHandle)
    1335             :   {}
    1336             : 
    1337             :   // Conversion operator so that we can append these to a
    1338             :   // FrameRequestCallbackList
    1339           2 :   operator const RefPtr<FrameRequestCallback>& () const {
    1340             :     return mCallback;
    1341             :   }
    1342             : 
    1343             :   // Comparator operators to allow RemoveElementSorted with an
    1344             :   // integer argument on arrays of FrameRequest
    1345             :   bool operator==(int32_t aHandle) const {
    1346             :     return mHandle == aHandle;
    1347             :   }
    1348             :   bool operator<(int32_t aHandle) const {
    1349             :     return mHandle < aHandle;
    1350             :   }
    1351             : 
    1352             :   RefPtr<FrameRequestCallback> mCallback;
    1353             :   int32_t mHandle;
    1354             : };
    1355           1 : 
    1356             : static already_AddRefed<mozilla::dom::NodeInfo> nullNodeInfo;
    1357             : 
    1358             : // ==================================================================
    1359             : // =
    1360          60 : // ==================================================================
    1361             : nsIDocument::nsIDocument()
    1362             :   : nsINode(nullNodeInfo),
    1363             :     DocumentOrShadowRoot(*this),
    1364             :     mReferrerPolicySet(false),
    1365             :     mReferrerPolicy(mozilla::net::RP_Unset),
    1366             :     mBlockAllMixedContent(false),
    1367             :     mBlockAllMixedContentPreloads(false),
    1368             :     mUpgradeInsecureRequests(false),
    1369             :     mUpgradeInsecurePreloads(false),
    1370             :     mCharacterSet(WINDOWS_1252_ENCODING),
    1371             :     mCharacterSetSource(0),
    1372             :     mParentDocument(nullptr),
    1373             :     mCachedRootElement(nullptr),
    1374             :     mNodeInfoManager(nullptr),
    1375             : #ifdef DEBUG
    1376             :     mStyledLinksCleared(false),
    1377             : #endif
    1378             :     mBidiEnabled(false),
    1379             :     mMathMLEnabled(false),
    1380             :     mIsInitialDocumentInWindow(false),
    1381             :     mIgnoreDocGroupMismatches(false),
    1382             :     mLoadedAsData(false),
    1383             :     mLoadedAsInteractiveData(false),
    1384             :     mMayStartLayout(true),
    1385             :     mHaveFiredTitleChange(false),
    1386             :     mIsShowing(false),
    1387             :     mVisible(true),
    1388             :     mRemovedFromDocShell(false),
    1389             :     // mAllowDNSPrefetch starts true, so that we can always reliably && it
    1390             :     // with various values that might disable it.  Since we never prefetch
    1391             :     // unless we get a window, and in that case the docshell value will get
    1392             :     // &&-ed in, this is safe.
    1393             :     mAllowDNSPrefetch(true),
    1394             :     mIsStaticDocument(false),
    1395             :     mCreatingStaticClone(false),
    1396             :     mInUnlinkOrDeletion(false),
    1397             :     mHasHadScriptHandlingObject(false),
    1398             :     mIsBeingUsedAsImage(false),
    1399             :     mIsSyntheticDocument(false),
    1400             :     mHasLinksToUpdateRunnable(false),
    1401             :     mFlushingPendingLinkUpdates(false),
    1402             :     mMayHaveDOMMutationObservers(false),
    1403             :     mMayHaveAnimationObservers(false),
    1404             :     mHasMixedActiveContentLoaded(false),
    1405             :     mHasMixedActiveContentBlocked(false),
    1406             :     mHasMixedDisplayContentLoaded(false),
    1407             :     mHasMixedDisplayContentBlocked(false),
    1408             :     mHasMixedContentObjectSubrequest(false),
    1409             :     mHasCSP(false),
    1410             :     mHasUnsafeEvalCSP(false),
    1411             :     mHasUnsafeInlineCSP(false),
    1412             :     mHasTrackingContentBlocked(false),
    1413             :     mHasTrackingContentLoaded(false),
    1414             :     mBFCacheDisallowed(false),
    1415             :     mHasHadDefaultView(false),
    1416             :     mStyleSheetChangeEventsEnabled(false),
    1417             :     mIsSrcdocDocument(false),
    1418             :     mDidDocumentOpen(false),
    1419             :     mHasDisplayDocument(false),
    1420             :     mFontFaceSetDirty(true),
    1421             :     mGetUserFontSetCalled(false),
    1422             :     mDidFireDOMContentLoaded(true),
    1423             :     mHasScrollLinkedEffect(false),
    1424             :     mFrameRequestCallbacksScheduled(false),
    1425             :     mIsTopLevelContentDocument(false),
    1426             :     mIsContentDocument(false),
    1427             :     mDidCallBeginLoad(false),
    1428             :     mAllowPaymentRequest(false),
    1429             :     mEncodingMenuDisabled(false),
    1430             :     mIsShadowDOMEnabled(false),
    1431             :     mIsSVGGlyphsDocument(false),
    1432             :     mInDestructor(false),
    1433             :     mIsGoingAway(false),
    1434             :     mInXBLUpdate(false),
    1435             :     mNeedsReleaseAfterStackRefCntRelease(false),
    1436             :     mStyleSetFilled(false),
    1437             :     mSSApplicableStateNotificationPending(false),
    1438             :     mMayHaveTitleElement(false),
    1439             :     mDOMLoadingSet(false),
    1440             :     mDOMInteractiveSet(false),
    1441             :     mDOMCompleteSet(false),
    1442             :     mAutoFocusFired(false),
    1443             :     mScrolledToRefAlready(false),
    1444             :     mChangeScrollPosWhenScrollingToRef(false),
    1445             :     mHasWarnedAboutBoxObjects(false),
    1446             :     mDelayFrameLoaderInitialization(false),
    1447             :     mSynchronousDOMContentLoaded(false),
    1448             :     mMaybeServiceWorkerControlled(false),
    1449             :     mValidWidth(false),
    1450             :     mValidHeight(false),
    1451             :     mAutoSize(false),
    1452             :     mAllowZoom(false),
    1453             :     mAllowDoubleTapZoom(false),
    1454             :     mValidScaleFloat(false),
    1455             :     mValidMaxScale(false),
    1456             :     mScaleStrEmpty(false),
    1457             :     mWidthStrEmpty(false),
    1458             :     mParserAborted(false),
    1459             :     mReportedUseCounters(false),
    1460             :     mHasReportedShadowDOMUsage(false),
    1461             : #ifdef DEBUG
    1462             :     mWillReparent(false),
    1463             : #endif
    1464             :     mPendingFullscreenRequests(0),
    1465             :     mXMLDeclarationBits(0),
    1466             :     mOnloadBlockCount(0),
    1467             :     mAsyncOnloadBlockCount(0),
    1468             :     mCompatMode(eCompatibility_FullStandards),
    1469             :     mReadyState(ReadyState::READYSTATE_UNINITIALIZED),
    1470             : #ifdef MOZILLA_INTERNAL_API
    1471             :     mVisibilityState(dom::VisibilityState::Hidden),
    1472             : #else
    1473             :     mDummy(0),
    1474             : #endif
    1475             :     mType(eUnknown),
    1476             :     mDefaultElementType(0),
    1477             :     mAllowXULXBL(eTriUnset),
    1478             :     mBidiOptions(IBMBIDI_DEFAULT_BIDI_OPTIONS),
    1479             :     mSandboxFlags(0),
    1480             :     mPartID(0),
    1481             :     mMarkedCCGeneration(0),
    1482             :     mPresShell(nullptr),
    1483             :     mSubtreeModifiedDepth(0),
    1484             :     mPreloadPictureDepth(0),
    1485             :     mEventsSuppressed(0),
    1486             :     mIgnoreDestructiveWritesCounter(0),
    1487             :     mFrameRequestCallbackCounter(0),
    1488             :     mStaticCloneCount(0),
    1489             :     mWindow(nullptr),
    1490             :     mBFCacheEntry(nullptr),
    1491             :     mInSyncOperationCount(0),
    1492             :     mBlockDOMContentLoaded(0),
    1493             :     mUseCounters(0),
    1494             :     mChildDocumentUseCounters(0),
    1495             :     mNotifiedPageForUseCounter(0),
    1496             :     mUserHasInteracted(false),
    1497             :     mUserHasActivatedInteraction(false),
    1498             :     mStackRefCnt(0),
    1499             :     mUpdateNestLevel(0),
    1500             :     mViewportType(Unknown),
    1501             :     mViewportOverflowType(ViewportOverflowType::NoOverflow),
    1502             :     mSubDocuments(nullptr),
    1503             :     mHeaderData(nullptr),
    1504             :     mFlashClassification(FlashClassification::Unclassified),
    1505             :     mBoxObjectTable(nullptr),
    1506             :     mCurrentOrientationAngle(0),
    1507             :     mCurrentOrientationType(OrientationType::Portrait_primary),
    1508             :     mServoRestyleRootDirtyBits(0),
    1509           0 :     mThrowOnDynamicMarkupInsertionCounter(0),
    1510             :     mIgnoreOpensDuringUnloadCounter(0)
    1511           0 : {
    1512           0 :   SetIsInDocument();
    1513             : }
    1514           0 : 
    1515           0 : nsDocument::nsDocument(const char* aContentType)
    1516             :   : nsIDocument()
    1517           0 : {
    1518             :   SetContentTypeInternal(nsDependentCString(aContentType));
    1519           0 : 
    1520             :   MOZ_LOG(gDocumentLeakPRLog, LogLevel::Debug, ("DOCUMENT %p created", this));
    1521             : 
    1522           0 :   // Start out mLastStyleSheetSet as null, per spec
    1523             :   SetDOMStringToNull(mLastStyleSheetSet);
    1524             : 
    1525           0 :   // void state used to differentiate an empty source from an unselected source
    1526             :   mPreloadPictureFoundSource.SetIsVoid(true);
    1527             :   // For determining if this is a flash document which should be
    1528           0 :   // blocked based on its principal.
    1529           0 :   mPrincipalFlashClassifier = new PrincipalFlashClassifier();
    1530             : }
    1531             : 
    1532           0 : void
    1533             : nsIDocument::ClearAllBoxObjects()
    1534           0 : {
    1535           0 :   if (mBoxObjectTable) {
    1536           0 :     for (auto iter = mBoxObjectTable->Iter(); !iter.Done(); iter.Next()) {
    1537           0 :       nsPIBoxObject* boxObject = iter.UserData();
    1538           0 :       if (boxObject) {
    1539             :         boxObject->Clear();
    1540             :       }
    1541           0 :     }
    1542           0 :     delete mBoxObjectTable;
    1543             :     mBoxObjectTable = nullptr;
    1544           0 :   }
    1545             : }
    1546           0 : 
    1547             : nsIDocument::~nsIDocument()
    1548           0 : {
    1549             :   MOZ_ASSERT(mDOMMediaQueryLists.isEmpty(),
    1550             :              "must not have media query lists left");
    1551           0 : 
    1552           0 :   if (mNodeInfoManager) {
    1553             :     mNodeInfoManager->DropDocumentReference();
    1554             :   }
    1555           0 : 
    1556           0 :   if (mDocGroup) {
    1557             :     mDocGroup->RemoveDocument(this);
    1558             :   }
    1559           0 : 
    1560           0 :   UnlinkOriginalDocumentIfStatic();
    1561             : }
    1562             : 
    1563           0 : bool
    1564             : nsIDocument::IsAboutPage() const
    1565           0 : {
    1566           0 :   nsCOMPtr<nsIPrincipal> principal = NodePrincipal();
    1567           0 :   nsCOMPtr<nsIURI> uri;
    1568           0 :   principal->GetURI(getter_AddRefs(uri));
    1569           0 :   bool isAboutScheme = true;
    1570           0 :   if (uri) {
    1571             :     uri->SchemeIs("about", &isAboutScheme);
    1572           0 :   }
    1573             :   return isAboutScheme;
    1574             : }
    1575           0 : 
    1576             : nsDocument::~nsDocument()
    1577           0 : {
    1578             :   MOZ_LOG(gDocumentLeakPRLog, LogLevel::Debug, ("DOCUMENT %p destroyed", this));
    1579           0 : 
    1580             :   NS_ASSERTION(!mIsShowing, "Destroying a currently-showing document");
    1581           0 : 
    1582             :   if (IsTopLevelContentDocument()) {
    1583           0 :     //don't report for about: pages
    1584             :     if (!IsAboutPage()) {
    1585           0 :       // Record the page load
    1586           0 :       uint32_t pageLoaded = 1;
    1587             :       Accumulate(Telemetry::MIXED_CONTENT_UNBLOCK_COUNTER, pageLoaded);
    1588             :       // Record the mixed content status of the docshell in Telemetry
    1589             :       enum {
    1590             :         NO_MIXED_CONTENT = 0, // There is no Mixed Content on the page
    1591             :         MIXED_DISPLAY_CONTENT = 1, // The page attempted to load Mixed Display Content
    1592             :         MIXED_ACTIVE_CONTENT = 2, // The page attempted to load Mixed Active Content
    1593             :         MIXED_DISPLAY_AND_ACTIVE_CONTENT = 3 // The page attempted to load Mixed Display & Mixed Active Content
    1594             :       };
    1595           0 : 
    1596           0 :       bool mixedActiveLoaded = GetHasMixedActiveContentLoaded();
    1597             :       bool mixedActiveBlocked = GetHasMixedActiveContentBlocked();
    1598           0 : 
    1599           0 :       bool mixedDisplayLoaded = GetHasMixedDisplayContentLoaded();
    1600             :       bool mixedDisplayBlocked = GetHasMixedDisplayContentBlocked();
    1601           0 : 
    1602           0 :       bool hasMixedDisplay = (mixedDisplayBlocked || mixedDisplayLoaded);
    1603             :       bool hasMixedActive = (mixedActiveBlocked || mixedActiveLoaded);
    1604           0 : 
    1605           0 :       uint32_t mixedContentLevel = NO_MIXED_CONTENT;
    1606             :       if (hasMixedDisplay && hasMixedActive) {
    1607           0 :         mixedContentLevel = MIXED_DISPLAY_AND_ACTIVE_CONTENT;
    1608             :       } else if (hasMixedActive){
    1609           0 :         mixedContentLevel = MIXED_ACTIVE_CONTENT;
    1610           0 :       } else if (hasMixedDisplay) {
    1611             :         mixedContentLevel = MIXED_DISPLAY_CONTENT;
    1612           0 :       }
    1613             :       Accumulate(Telemetry::MIXED_CONTENT_PAGE_LOAD, mixedContentLevel);
    1614             : 
    1615           0 :       // record mixed object subrequest telemetry
    1616             :       if (mHasMixedContentObjectSubrequest) {
    1617           0 :         /* mixed object subrequest loaded on page*/
    1618             :         Accumulate(Telemetry::MIXED_CONTENT_OBJECT_SUBREQUEST, 1);
    1619             :       } else {
    1620           0 :         /* no mixed object subrequests loaded on page*/
    1621             :         Accumulate(Telemetry::MIXED_CONTENT_OBJECT_SUBREQUEST, 0);
    1622             :       }
    1623             : 
    1624           0 :       // record CSP telemetry on this document
    1625           0 :       if (mHasCSP) {
    1626             :         Accumulate(Telemetry::CSP_DOCUMENTS_COUNT, 1);
    1627           0 :       }
    1628           0 :       if (mHasUnsafeInlineCSP) {
    1629             :         Accumulate(Telemetry::CSP_UNSAFE_INLINE_DOCUMENTS_COUNT, 1);
    1630           0 :       }
    1631           0 :       if (mHasUnsafeEvalCSP) {
    1632             :         Accumulate(Telemetry::CSP_UNSAFE_EVAL_DOCUMENTS_COUNT, 1);
    1633             :       }
    1634           0 : 
    1635           0 :       if (MOZ_UNLIKELY(GetMathMLEnabled())) {
    1636             :         ScalarAdd(Telemetry::ScalarID::MATHML_DOC_COUNT, 1);
    1637             :       }
    1638             :     }
    1639             :   }
    1640           0 : 
    1641             :   ReportUseCounters();
    1642           0 : 
    1643           0 :   mInDestructor = true;
    1644             :   mInUnlinkOrDeletion = true;
    1645           0 : 
    1646             :   mozilla::DropJSObjects(this);
    1647             : 
    1648           0 :   // Clear mObservers to keep it in sync with the mutationobserver list
    1649             :   mObservers.Clear();
    1650           0 : 
    1651             :   mIntersectionObservers.Clear();
    1652           0 : 
    1653           0 :   if (mStyleSheetSetList) {
    1654             :     mStyleSheetSetList->Disconnect();
    1655             :   }
    1656           0 : 
    1657           0 :   if (mAnimationController) {
    1658             :     mAnimationController->Disconnect();
    1659             :   }
    1660           0 : 
    1661             :   MOZ_ASSERT(mTimelines.isEmpty());
    1662           0 : 
    1663             :   mParentDocument = nullptr;
    1664             : 
    1665             :   // Kill the subdocument map, doing this will release its strong
    1666           0 :   // references, if any.
    1667           0 :   delete mSubDocuments;
    1668             :   mSubDocuments = nullptr;
    1669             : 
    1670             :   // Destroy link map now so we don't waste time removing
    1671           0 :   // links one by one
    1672             :   DestroyElementMaps();
    1673           0 : 
    1674             :   nsAutoScriptBlocker scriptBlocker;
    1675             : 
    1676           0 :   // Invalidate cached array of child nodes
    1677             :   InvalidateChildNodes();
    1678           0 : 
    1679           0 :   for (uint32_t indx = mChildren.ChildCount(); indx-- != 0; ) {
    1680           0 :     mChildren.ChildAt(indx)->UnbindFromTree();
    1681             :     mChildren.RemoveChildAt(indx);
    1682           0 :   }
    1683           0 :   mFirstChild = nullptr;
    1684             :   mCachedRootElement = nullptr;
    1685             : 
    1686           0 :   // Let the stylesheets know we're going away
    1687           0 :   for (StyleSheet* sheet : mStyleSheets) {
    1688             :     sheet->ClearAssociatedDocumentOrShadowRoot();
    1689           0 :   }
    1690           0 :   for (auto& sheets : mAdditionalSheets) {
    1691           0 :     for (StyleSheet* sheet : sheets) {
    1692             :       sheet->ClearAssociatedDocumentOrShadowRoot();
    1693             :     }
    1694           0 :   }
    1695           0 :   if (mAttrStyleSheet) {
    1696             :     mAttrStyleSheet->SetOwningDocument(nullptr);
    1697             :   }
    1698             :   // We don't own the mOnDemandBuiltInUASheets, so we don't need to reset them.
    1699           0 : 
    1700           0 :   if (mListenerManager) {
    1701           0 :     mListenerManager->Disconnect();
    1702             :     UnsetFlags(NODE_HAS_LISTENERMANAGER);
    1703             :   }
    1704           0 : 
    1705           0 :   if (mScriptLoader) {
    1706             :     mScriptLoader->DropDocumentReference();
    1707             :   }
    1708           0 : 
    1709             :   if (mCSSLoader) {
    1710           0 :     // Could be null here if Init() failed or if we have been unlinked.
    1711             :     mCSSLoader->DropDocumentReference();
    1712             :   }
    1713           0 : 
    1714           0 :   if (mStyleImageLoader) {
    1715             :     mStyleImageLoader->DropDocumentReference();
    1716             :   }
    1717           0 : 
    1718             :   delete mHeaderData;
    1719           0 : 
    1720             :   ClearAllBoxObjects();
    1721           0 : 
    1722             :   mPendingTitleChangeEvent.Revoke();
    1723           0 : 
    1724           0 :   mPlugins.Clear();
    1725             : }
    1726           0 : 
    1727           0 : NS_INTERFACE_TABLE_HEAD(nsDocument)
    1728             :   NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
    1729             :   NS_INTERFACE_TABLE_BEGIN
    1730             :     NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(nsDocument, nsISupports, nsINode)
    1731             :     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsINode)
    1732             :     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDocument)
    1733             :     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIScriptObjectPrincipal)
    1734             :     NS_INTERFACE_TABLE_ENTRY(nsDocument, mozilla::dom::EventTarget)
    1735             :     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsISupportsWeakReference)
    1736             :     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIRadioGroupContainer)
    1737             :     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIMutationObserver)
    1738           0 :     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIApplicationCacheContainer)
    1739           0 :   NS_INTERFACE_TABLE_END
    1740           0 :   NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsDocument)
    1741             : NS_INTERFACE_MAP_END
    1742             : 
    1743           0 : 
    1744             : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDocument)
    1745           0 : NS_IMETHODIMP_(MozExternalRefCountType)
    1746             : nsDocument::Release()
    1747           0 : {
    1748           0 :   MOZ_ASSERT(0 != mRefCnt, "dup release");
    1749           0 :   NS_ASSERT_OWNINGTHREAD(nsDocument);
    1750           0 :   nsISupports* base = NS_CYCLE_COLLECTION_CLASSNAME(nsDocument)::Upcast(this);
    1751           0 :   bool shouldDelete = false;
    1752           0 :   nsrefcnt count = mRefCnt.decr(base, &shouldDelete);
    1753           0 :   NS_LOG_RELEASE(this, count, "nsDocument");
    1754           0 :   if (count == 0) {
    1755           0 :     if (mStackRefCnt && !mNeedsReleaseAfterStackRefCntRelease) {
    1756           0 :       mNeedsReleaseAfterStackRefCntRelease = true;
    1757           0 :       NS_ADDREF_THIS();
    1758             :       return mRefCnt.get();
    1759           0 :     }
    1760           0 :     mRefCnt.incr(base);
    1761           0 :     nsNodeUtils::LastRelease(this);
    1762           0 :     mRefCnt.decr(base);
    1763           0 :     if (shouldDelete) {
    1764           0 :       mRefCnt.stabilizeForDeletion();
    1765             :       DeleteCycleCollectable();
    1766             :     }
    1767           0 :   }
    1768             :   return count;
    1769             : }
    1770             : 
    1771           0 : NS_IMETHODIMP_(void)
    1772             : nsDocument::DeleteCycleCollectable()
    1773           0 : {
    1774           0 :   delete this;
    1775             : }
    1776           0 : 
    1777           0 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsDocument)
    1778           0 :   if (Element::CanSkip(tmp, aRemovingAllowed)) {
    1779           0 :     EventListenerManager* elm = tmp->GetExistingListenerManager();
    1780           0 :     if (elm) {
    1781             :       elm->MarkForCC();
    1782             :     }
    1783             :     return true;
    1784             :   }
    1785             : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
    1786           0 : 
    1787           0 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsDocument)
    1788             :   return Element::CanSkipInCC(tmp);
    1789             : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
    1790           0 : 
    1791           0 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsDocument)
    1792             :   return Element::CanSkipThis(tmp);
    1793             : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
    1794             : 
    1795             : static const char* kNSURIs[] = {
    1796             :   "([none])",
    1797             :   "(xmlns)",
    1798             :   "(xml)",
    1799             :   "(xhtml)",
    1800             :   "(XLink)",
    1801             :   "(XSLT)",
    1802             :   "(XBL)",
    1803             :   "(MathML)",
    1804             :   "(RDF)",
    1805             :   "(XUL)"
    1806             : };
    1807           0 : 
    1808           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsDocument)
    1809             :   if (MOZ_UNLIKELY(cb.WantDebugInfo())) {
    1810           0 :     char name[512];
    1811           0 :     nsAutoCString loadedAsData;
    1812           0 :     if (tmp->IsLoadedAsData()) {
    1813             :       loadedAsData.AssignLiteral("data");
    1814           0 :     } else {
    1815             :       loadedAsData.AssignLiteral("normal");
    1816           0 :     }
    1817           0 :     uint32_t nsid = tmp->GetDefaultNamespaceID();
    1818           0 :     nsAutoCString uri;
    1819           0 :     if (tmp->mDocumentURI)
    1820           0 :       uri = tmp->mDocumentURI->GetSpecOrDefault();
    1821           0 :     if (nsid < ArrayLength(kNSURIs)) {
    1822           0 :       SprintfLiteral(name, "nsDocument %s %s %s",
    1823             :                      loadedAsData.get(), kNSURIs[nsid], uri.get());
    1824             :     }
    1825           0 :     else {
    1826           0 :       SprintfLiteral(name, "nsDocument %s %s",
    1827             :                      loadedAsData.get(), uri.get());
    1828           0 :     }
    1829             :     cb.DescribeRefCountedNode(tmp->mRefCnt.get(), name);
    1830             :   }
    1831           0 :   else {
    1832             :     NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsDocument, tmp->mRefCnt.get())
    1833             :   }
    1834           0 : 
    1835             :   if (!nsINode::Traverse(tmp, cb)) {
    1836             :     return NS_SUCCESS_INTERRUPTED_TRAVERSE;
    1837             :   }
    1838           0 : 
    1839             :   if (tmp->mMaybeEndOutermostXBLUpdateRunner) {
    1840             :     // The cached runnable keeps a reference to the document object..
    1841           0 :     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
    1842           0 :                                        "mMaybeEndOutermostXBLUpdateRunner.mObj");
    1843             :     cb.NoteXPCOMChild(ToSupports(tmp));
    1844             :   }
    1845           0 : 
    1846           0 :   for (auto iter = tmp->mIdentifierMap.ConstIter(); !iter.Done();
    1847           0 :        iter.Next()) {
    1848             :     iter.Get()->Traverse(&cb);
    1849             :   }
    1850           0 : 
    1851             :   tmp->mExternalResourceMap.Traverse(&cb);
    1852             : 
    1853           0 :   // Traverse the mChildren nsAttrAndChildArray.
    1854           0 :   for (int32_t indx = int32_t(tmp->mChildren.ChildCount()); indx > 0; --indx) {
    1855           0 :     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mChildren[i]");
    1856             :     cb.NoteXPCOMChild(tmp->mChildren.ChildAt(indx - 1));
    1857             :   }
    1858             : 
    1859           0 :   // Traverse all nsIDocument pointer members.
    1860           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSecurityInfo)
    1861           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDisplayDocument)
    1862           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFontFaceSet)
    1863             :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mReadyForIdle)
    1864             : 
    1865          41 :   // Traverse all nsDocument nsCOMPtrs.
    1866           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParser)
    1867           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScriptGlobalObject)
    1868           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListenerManager)
    1869           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMStyleSheets)
    1870           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheetSetList)
    1871             :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScriptLoader)
    1872         123 : 
    1873           0 :   for (auto iter = tmp->mRadioGroups.Iter(); !iter.Done(); iter.Next()) {
    1874             :     nsRadioGroupStruct* radioGroup = iter.UserData();
    1875           0 :     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(
    1876           0 :       cb, "mRadioGroups entry->mSelectedRadioButton");
    1877             :     cb.NoteXPCOMChild(ToSupports(radioGroup->mSelectedRadioButton));
    1878           0 : 
    1879           0 :     uint32_t i, count = radioGroup->mRadioButtons.Count();
    1880             :     for (i = 0; i < count; ++i) {
    1881           0 :       NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(
    1882           0 :         cb, "mRadioGroups entry->mRadioButtons[i]");
    1883             :       cb.NoteXPCOMChild(radioGroup->mRadioButtons[i]);
    1884             :     }
    1885             :   }
    1886             : 
    1887             :   // The boxobject for an element will only exist as long as it's in the
    1888          41 :   // document, so we'll traverse the table here instead of from the element.
    1889           0 :   if (tmp->mBoxObjectTable) {
    1890           0 :     for (auto iter = tmp->mBoxObjectTable->Iter(); !iter.Done(); iter.Next()) {
    1891           0 :       NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mBoxObjectTable entry");
    1892             :       cb.NoteXPCOMChild(iter.UserData());
    1893             :     }
    1894             :   }
    1895          41 : 
    1896           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChannel)
    1897           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLayoutHistoryState)
    1898           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOnloadBlocker)
    1899           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFirstBaseNodeWithHref)
    1900           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMImplementation)
    1901           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mImageMaps)
    1902           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOrientationPendingPromise)
    1903           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOriginalDocument)
    1904           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCachedEncoder)
    1905           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStateObjectCached)
    1906           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentTimeline)
    1907           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPendingAnimationTracker)
    1908           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTemplateContentsOwner)
    1909           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChildrenCollection)
    1910           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mImages);
    1911           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEmbeds);
    1912           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLinks);
    1913           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mForms);
    1914           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScripts);
    1915           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mApplets);
    1916           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAnchors);
    1917             :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAnonymousContents)
    1918             : 
    1919          41 :   // Traverse all our nsCOMArrays.
    1920           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheets)
    1921           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOnDemandBuiltInUASheets)
    1922             :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPreloadingImages)
    1923          82 : 
    1924           0 :   for (uint32_t i = 0; i < tmp->mFrameRequestCallbacks.Length(); ++i) {
    1925           0 :     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mFrameRequestCallbacks[i]");
    1926             :     cb.NoteXPCOMChild(tmp->mFrameRequestCallbacks[i].mCallback);
    1927             :   }
    1928             : 
    1929          82 :   // Traverse animation components
    1930           0 :   if (tmp->mAnimationController) {
    1931             :     tmp->mAnimationController->Traverse(&cb);
    1932             :   }
    1933          41 : 
    1934           0 :   if (tmp->mSubDocuments) {
    1935           0 :     for (auto iter = tmp->mSubDocuments->Iter(); !iter.Done(); iter.Next()) {
    1936             :       auto entry = static_cast<SubDocMapEntry*>(iter.Get());
    1937             : 
    1938           0 :       NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
    1939           0 :                                          "mSubDocuments entry->mKey");
    1940             :       cb.NoteXPCOMChild(entry->mKey);
    1941           0 :       NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
    1942           0 :                                          "mSubDocuments entry->mSubDocument");
    1943             :       cb.NoteXPCOMChild(entry->mSubDocument);
    1944             :     }
    1945             :   }
    1946          41 : 
    1947             :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCSSLoader)
    1948             : 
    1949             :   // We own only the items in mDOMMediaQueryLists that have listeners;
    1950             :   // this reference is managed by their AddListener and RemoveListener
    1951          41 :   // methods.
    1952           0 :   for (MediaQueryList* mql = tmp->mDOMMediaQueryLists.getFirst(); mql;
    1953           0 :        mql = static_cast<LinkedListElement<MediaQueryList>*>(mql)->getNext()) {
    1954           0 :     if (mql->HasListeners()) {
    1955           0 :       NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mDOMMediaQueryLists item");
    1956             :       cb.NoteXPCOMChild(mql);
    1957             :     }
    1958             :   }
    1959             : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    1960             : 
    1961             : NS_IMPL_CYCLE_COLLECTION_CLASS(nsDocument)
    1962         164 : 
    1963             : NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(nsDocument)
    1964           0 : 
    1965           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument)
    1966             :   tmp->mInUnlinkOrDeletion = true;
    1967             : 
    1968           0 :   // Clear out our external resources
    1969             :   tmp->mExternalResourceMap.Shutdown();
    1970           0 : 
    1971             :   nsAutoScriptBlocker scriptBlocker;
    1972           0 : 
    1973             :   nsINode::Unlink(tmp);
    1974             : 
    1975           0 :   // Unlink the mChildren nsAttrAndChildArray.
    1976           0 :   uint32_t childCount = tmp->mChildren.ChildCount();
    1977           0 :   if (childCount) {
    1978             :     while (childCount-- > 0) {
    1979             :       // Hold a strong ref to the node when we remove it, because we may be
    1980             :       // the last reference to it.  We need to call TakeChildAt() and
    1981             :       // update mFirstChild before calling UnbindFromTree, since this last
    1982             :       // can notify various observers and they should really see consistent
    1983             :       // tree state.
    1984             :       // If this code changes, change the corresponding code in
    1985           0 :       // FragmentOrElement's unlink impl and ContentUnbinder::UnbindSubtree.
    1986           0 :       nsCOMPtr<nsIContent> child = tmp->mChildren.TakeChildAt(childCount);
    1987           0 :       if (childCount == 0) {
    1988             :         tmp->mFirstChild = nullptr;
    1989           0 :       }
    1990             :       child->UnbindFromTree();
    1991             :     }
    1992           0 :   }
    1993             :   tmp->mFirstChild = nullptr;
    1994           0 : 
    1995             :   tmp->UnlinkOriginalDocumentIfStatic();
    1996           0 : 
    1997           0 :   tmp->mCachedRootElement = nullptr; // Avoid a dangling pointer
    1998           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDisplayDocument)
    1999           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mFirstBaseNodeWithHref)
    2000           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mMaybeEndOutermostXBLUpdateRunner)
    2001           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMImplementation)
    2002           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mImageMaps)
    2003           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mCachedEncoder)
    2004           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentTimeline)
    2005           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mPendingAnimationTracker)
    2006           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mTemplateContentsOwner)
    2007           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mChildrenCollection)
    2008           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mImages);
    2009           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mEmbeds);
    2010           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mLinks);
    2011           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mForms);
    2012           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mScripts);
    2013           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mApplets);
    2014           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mAnchors);
    2015           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mOrientationPendingPromise)
    2016           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mFontFaceSet)
    2017             :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mReadyForIdle);
    2018           0 : 
    2019             :   tmp->mParentDocument = nullptr;
    2020           0 : 
    2021             :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mPreloadingImages)
    2022           0 : 
    2023             :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mIntersectionObservers)
    2024           0 : 
    2025             :   tmp->ClearAllBoxObjects();
    2026           0 : 
    2027           0 :   if (tmp->mListenerManager) {
    2028           0 :     tmp->mListenerManager->Disconnect();
    2029           0 :     tmp->UnsetFlags(NODE_HAS_LISTENERMANAGER);
    2030             :     tmp->mListenerManager = nullptr;
    2031             :   }
    2032           0 : 
    2033             :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMStyleSheets)
    2034           0 : 
    2035           0 :   if (tmp->mStyleSheetSetList) {
    2036           0 :     tmp->mStyleSheetSetList->Disconnect();
    2037             :     tmp->mStyleSheetSetList = nullptr;
    2038             :   }
    2039           0 : 
    2040           0 :   delete tmp->mSubDocuments;
    2041             :   tmp->mSubDocuments = nullptr;
    2042           0 : 
    2043           0 :   tmp->mFrameRequestCallbacks.Clear();
    2044             :   MOZ_RELEASE_ASSERT(!tmp->mFrameRequestCallbacksScheduled,
    2045             :                      "How did we get here without our presshell going away "
    2046             :                      "first?");
    2047           0 : 
    2048             :   tmp->mRadioGroups.Clear();
    2049             : 
    2050             :   // nsDocument has a pretty complex destructor, so we're going to
    2051             :   // assume that *most* cycles you actually want to break somewhere
    2052             :   // else, and not unlink an awful lot here.
    2053           0 : 
    2054           0 :   tmp->mIdentifierMap.Clear();
    2055             :   tmp->mExpandoAndGeneration.OwnerUnlinked();
    2056           0 : 
    2057           0 :   if (tmp->mAnimationController) {
    2058             :     tmp->mAnimationController->Unlink();
    2059             :   }
    2060           0 : 
    2061             :   tmp->mPendingTitleChangeEvent.Revoke();
    2062           0 : 
    2063           0 :   if (tmp->mCSSLoader) {
    2064           0 :     tmp->mCSSLoader->DropDocumentReference();
    2065             :     NS_IMPL_CYCLE_COLLECTION_UNLINK(mCSSLoader)
    2066             :   }
    2067             : 
    2068             :   // We own only the items in mDOMMediaQueryLists that have listeners;
    2069             :   // this reference is managed by their AddListener and RemoveListener
    2070           0 :   // methods.
    2071             :   for (MediaQueryList* mql = tmp->mDOMMediaQueryLists.getFirst(); mql;) {
    2072           0 :     MediaQueryList* next =
    2073           0 :       static_cast<LinkedListElement<MediaQueryList>*>(mql)->getNext();
    2074           0 :     mql->Disconnect();
    2075             :     mql = next;
    2076             :   }
    2077           0 : 
    2078           0 :   tmp->mInUnlinkOrDeletion = false;
    2079             : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    2080             : 
    2081          60 : nsresult
    2082             : nsDocument::Init()
    2083           0 : {
    2084             :   if (mCSSLoader || mStyleImageLoader || mNodeInfoManager || mScriptLoader) {
    2085             :     return NS_ERROR_ALREADY_INITIALIZED;
    2086             :   }
    2087             : 
    2088          60 :   // Force initialization.
    2089             :   nsINode::nsSlots* slots = Slots();
    2090             : 
    2091             :   // Prepend self as mutation-observer whether we need it or not (some
    2092             :   // subclasses currently do, other don't). This is because the code in
    2093             :   // nsNodeUtils always notifies the first observer first, expecting the
    2094          60 :   // first observer to be the document.
    2095             :   NS_ENSURE_TRUE(slots->mMutationObservers.PrependElementUnlessExists(static_cast<nsIMutationObserver*>(this)),
    2096             :                  NS_ERROR_OUT_OF_MEMORY);
    2097             : 
    2098          60 : 
    2099         120 :   mOnloadBlocker = new nsOnloadBlocker();
    2100             :   mCSSLoader = new mozilla::css::Loader(this);
    2101           0 :   // Assume we're not quirky, until we know otherwise
    2102             :   mCSSLoader->SetCompatibilityMode(eCompatibility_FullStandards);
    2103           0 : 
    2104             :   mStyleImageLoader = new mozilla::css::ImageLoader(this);
    2105           0 : 
    2106          60 :   mNodeInfoManager = new nsNodeInfoManager();
    2107           0 :   nsresult rv = mNodeInfoManager->Init(this);
    2108             :   NS_ENSURE_SUCCESS(rv, rv);
    2109             : 
    2110          60 :   // mNodeInfo keeps NodeInfoManager alive!
    2111         120 :   mNodeInfo = mNodeInfoManager->GetDocumentNodeInfo();
    2112           0 :   NS_ENSURE_TRUE(mNodeInfo, NS_ERROR_OUT_OF_MEMORY);
    2113             :   MOZ_ASSERT(mNodeInfo->NodeType() == DOCUMENT_NODE,
    2114             :              "Bad NodeType in aNodeInfo");
    2115          60 : 
    2116             :   NS_ASSERTION(OwnerDoc() == this, "Our nodeinfo is busted!");
    2117             : 
    2118             :   // Set this when document is initialized and value stays the same for the
    2119          60 :   // lifetime of the document.
    2120             :   mIsShadowDOMEnabled = nsContentUtils::IsShadowDOMEnabled();
    2121             : 
    2122             :   // If after creation the owner js global is not set for a document
    2123             :   // we use the default compartment for this document, instead of creating
    2124             :   // wrapper in some random compartment when the document is exposed to js
    2125         120 :   // via some events.
    2126          60 :   nsCOMPtr<nsIGlobalObject> global = xpc::NativeGlobal(xpc::PrivilegedJunkScope());
    2127           0 :   NS_ENSURE_TRUE(global, NS_ERROR_FAILURE);
    2128           0 :   mScopeObject = do_GetWeakReference(global);
    2129             :   MOZ_ASSERT(mScopeObject);
    2130           0 : 
    2131             :   mScriptLoader = new dom::ScriptLoader(this);
    2132           0 : 
    2133             :   mozilla::HoldJSObjects(this);
    2134           0 : 
    2135             :   return NS_OK;
    2136             : }
    2137             : 
    2138           0 : void
    2139             : nsIDocument::DeleteAllProperties()
    2140           0 : {
    2141           0 :   PropertyTable().DeleteAllProperties();
    2142             : }
    2143             : 
    2144           0 : void
    2145             : nsIDocument::DeleteAllPropertiesFor(nsINode* aNode)
    2146           0 : {
    2147           0 :   PropertyTable().DeleteAllPropertiesFor(aNode);
    2148             : }
    2149             : 
    2150           0 : bool
    2151             : nsIDocument::IsVisibleConsideringAncestors() const
    2152           0 : {
    2153           0 :   const nsIDocument *parent = this;
    2154           0 :   do {
    2155             :     if (!parent->IsVisible()) {
    2156             :       return false;
    2157             :     }
    2158             :   } while ((parent = parent->GetParentDocument()));
    2159             : 
    2160             :   return true;
    2161             :       }
    2162             : 
    2163          38 : void
    2164             : nsIDocument::Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup)
    2165           0 : {
    2166          76 :   nsCOMPtr<nsIURI> uri;
    2167           0 :   nsCOMPtr<nsIPrincipal> principal;
    2168             :   if (aChannel) {
    2169             :     // Note: this code is duplicated in XULDocument::StartDocumentLoad and
    2170             :     // nsScriptSecurityManager::GetChannelResultPrincipal.
    2171          38 :     // Note: this should match nsDocShell::OnLoadingSite
    2172             :     NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
    2173           0 : 
    2174          38 :     bool isWyciwyg = false;
    2175           0 :     uri->SchemeIs("wyciwyg", &isWyciwyg);
    2176           0 :     if (isWyciwyg) {
    2177             :       nsCOMPtr<nsIURI> cleanURI;
    2178           0 :       nsresult rv =
    2179           0 :         nsContentUtils::RemoveWyciwygScheme(uri, getter_AddRefs(cleanURI));
    2180           0 :       if (NS_SUCCEEDED(rv)) {
    2181             :         uri = cleanURI;
    2182             :       }
    2183             :     }
    2184             : 
    2185          38 :     nsIScriptSecurityManager *securityManager =
    2186          38 :       nsContentUtils::GetSecurityManager();
    2187           0 :     if (securityManager) {
    2188           0 :       securityManager->GetChannelResultPrincipal(aChannel,
    2189             :                                                  getter_AddRefs(principal));
    2190             :     }
    2191             :   }
    2192          38 : 
    2193             :   principal = MaybeDowngradePrincipal(principal);
    2194           0 : 
    2195             :   ResetToURI(uri, aLoadGroup, principal);
    2196             : 
    2197             :   // Note that, since mTiming does not change during a reset, the
    2198             :   // navigationStart time remains unchanged and therefore any future new
    2199          38 :   // timeline will have the same global clock time as the old one.
    2200             :   mDocumentTimeline = nullptr;
    2201           0 : 
    2202          38 :   nsCOMPtr<nsIPropertyBag2> bag = do_QueryInterface(aChannel);
    2203           0 :   if (bag) {
    2204           0 :     nsCOMPtr<nsIURI> baseURI;
    2205           0 :     bag->GetPropertyAsInterface(NS_LITERAL_STRING("baseURI"),
    2206           0 :                                 NS_GET_IID(nsIURI), getter_AddRefs(baseURI));
    2207           0 :     if (baseURI) {
    2208           0 :       mDocumentBaseURI = baseURI;
    2209             :       mChromeXHRDocBaseURI = nullptr;
    2210             :     }
    2211             :   }
    2212          38 : 
    2213          38 :   mChannel = aChannel;
    2214             : }
    2215             : 
    2216          46 : void
    2217             : nsIDocument::ResetToURI(nsIURI* aURI,
    2218             :                         nsILoadGroup* aLoadGroup,
    2219             :                         nsIPrincipal* aPrincipal)
    2220          46 : {
    2221             :   MOZ_ASSERT(aURI, "Null URI passed to ResetToURI");
    2222           0 : 
    2223             :   MOZ_LOG(gDocumentLeakPRLog, LogLevel::Debug,
    2224             :           ("DOCUMENT %p ResetToURI %s", this, aURI->GetSpecOrDefault().get()));
    2225          46 : 
    2226             :   mSecurityInfo = nullptr;
    2227           0 : 
    2228             :   mDocumentLoadGroup = nullptr;
    2229             : 
    2230             :   // Delete references to sub-documents and kill the subdocument map,
    2231          46 :   // if any. It holds strong references
    2232          46 :   delete mSubDocuments;
    2233             :   mSubDocuments = nullptr;
    2234             : 
    2235             :   // Destroy link map now so we don't waste time removing
    2236          46 :   // links one by one
    2237             :   DestroyElementMaps();
    2238           0 : 
    2239          46 :   bool oldVal = mInUnlinkOrDeletion;
    2240           0 :   mInUnlinkOrDeletion = true;
    2241             :   uint32_t count = mChildren.ChildCount();
    2242           0 :   { // Scope for update
    2243             :     MOZ_AUTO_DOC_UPDATE(this, true);
    2244             : 
    2245          46 :     // Invalidate cached array of child nodes
    2246             :     InvalidateChildNodes();
    2247           0 : 
    2248           0 :     for (int32_t i = int32_t(count) - 1; i >= 0; i--) {
    2249             :       nsCOMPtr<nsIContent> content = mChildren.ChildAt(i);
    2250           0 : 
    2251             :       nsIContent* previousSibling = content->GetPreviousSibling();
    2252           0 : 
    2253           0 :       if (nsINode::GetFirstChild() == content) {
    2254             :         mFirstChild = content->GetNextSibling();
    2255           0 :       }
    2256           0 :       mChildren.RemoveChildAt(i);
    2257             :       if (content == mCachedRootElement) {
    2258             :         // Immediately clear mCachedRootElement, now that it's been removed
    2259             :         // from mChildren, so that GetRootElement() will stop returning this
    2260           0 :         // now-stale value.
    2261             :         mCachedRootElement = nullptr;
    2262           0 :       }
    2263           0 :       nsNodeUtils::ContentRemoved(this, content, previousSibling);
    2264             :       content->UnbindFromTree();
    2265           0 :     }
    2266             :     MOZ_ASSERT(!mCachedRootElement,
    2267             :                "After removing all children, there should be no root elem");
    2268          46 :   }
    2269             :   mInUnlinkOrDeletion = oldVal;
    2270             : 
    2271          46 :   // Reset our stylesheets
    2272             :   ResetStylesheetsToURI(aURI);
    2273             : 
    2274          92 :   // Release the listener manager
    2275           0 :   if (mListenerManager) {
    2276           0 :     mListenerManager->Disconnect();
    2277             :     mListenerManager = nullptr;
    2278             :   }
    2279             : 
    2280          46 :   // Release the stylesheets list.
    2281             :   mDOMStyleSheets = nullptr;
    2282             : 
    2283             :   // Release our principal after tearing down the document, rather than before.
    2284             :   // This ensures that, during teardown, the document and the dying window (which
    2285             :   // already nulled out its document pointer and cached the principal) have
    2286          46 :   // matching principals.
    2287             :   SetPrincipal(nullptr);
    2288             : 
    2289          46 :   // Clear the original URI so SetDocumentURI sets it.
    2290             :   mOriginalURI = nullptr;
    2291           0 : 
    2292          46 :   SetDocumentURI(aURI);
    2293             :   mChromeXHRDocURI = nullptr;
    2294             :   // If mDocumentBaseURI is null, nsIDocument::GetBaseURI() returns
    2295          46 :   // mDocumentURI.
    2296          46 :   mDocumentBaseURI = nullptr;
    2297             :   mChromeXHRDocBaseURI = nullptr;
    2298           0 : 
    2299          45 :   if (aLoadGroup) {
    2300             :     mDocumentLoadGroup = do_GetWeakReference(aLoadGroup);
    2301             :     // there was an assertion here that aLoadGroup was not null.  This
    2302             :     // is no longer valid: nsDocShell::SetDocument does not create a
    2303             :     // load group, and it works just fine
    2304             : 
    2305             :     // XXXbz what does "just fine" mean exactly?  And given that there
    2306             :     // is no nsDocShell::SetDocument, what is this talking about?
    2307          45 : 
    2308             :     if (IsContentDocument()) {
    2309             :       // Inform the associated request context about this load start so
    2310             :       // any of its internal load progress flags gets reset.
    2311           4 :       nsCOMPtr<nsIRequestContextService> rcsvc =
    2312           2 :         do_GetService("@mozilla.org/network/request-context-service;1");
    2313           0 :       if (rcsvc) {
    2314           0 :         nsCOMPtr<nsIRequestContext> rc;
    2315           0 :         rcsvc->GetRequestContextFromLoadGroup(aLoadGroup, getter_AddRefs(rc));
    2316           0 :         if (rc) {
    2317             :           rc->BeginLoad();
    2318             :         }
    2319             :       }
    2320             :     }
    2321             :   }
    2322          46 : 
    2323             :   mLastModified.Truncate();
    2324             :   // XXXbz I guess we're assuming that the caller will either pass in
    2325          46 :   // a channel with a useful type or call SetContentType?
    2326          46 :   SetContentTypeInternal(EmptyCString());
    2327           0 :   mContentLanguage.Truncate();
    2328           0 :   mBaseTarget.Truncate();
    2329             :   mReferrer.Truncate();
    2330           0 : 
    2331             :   mXMLDeclarationBits = 0;
    2332             : 
    2333          46 :   // Now get our new principal
    2334          42 :   if (aPrincipal) {
    2335             :     SetPrincipal(aPrincipal);
    2336             :   } else {
    2337           4 :     nsIScriptSecurityManager *securityManager =
    2338           4 :       nsContentUtils::GetSecurityManager();
    2339           0 :     if (securityManager) {
    2340             :       nsCOMPtr<nsILoadContext> loadContext(mDocumentContainer);
    2341           0 : 
    2342           8 :       if (!loadContext && aLoadGroup) {
    2343           0 :         nsCOMPtr<nsIInterfaceRequestor> cbs;
    2344           0 :         aLoadGroup->GetNotificationCallbacks(getter_AddRefs(cbs));
    2345             :         loadContext = do_GetInterface(cbs);
    2346             :       }
    2347           4 : 
    2348             :       MOZ_ASSERT(loadContext,
    2349             :                  "must have a load context or pass in an explicit principal");
    2350           8 : 
    2351             :       nsCOMPtr<nsIPrincipal> principal;
    2352           0 :       nsresult rv = securityManager->
    2353          12 :         GetLoadContextCodebasePrincipal(mDocumentURI, loadContext,
    2354           0 :                                         getter_AddRefs(principal));
    2355           0 :       if (NS_SUCCEEDED(rv)) {
    2356             :         SetPrincipal(principal);
    2357             :       }
    2358             :     }
    2359             :   }
    2360          92 : 
    2361           0 :   if (mFontFaceSet) {
    2362             :     mFontFaceSet->RefreshStandardFontLoadPrincipal();
    2363             :   }
    2364             : 
    2365          46 :   // Refresh the principal on the realm.
    2366           0 :   if (nsPIDOMWindowInner* win = GetInnerWindow()) {
    2367             :     nsGlobalWindowInner::Cast(win)->RefreshRealmPrincipal();
    2368           0 :   }
    2369             : }
    2370             : 
    2371          41 : already_AddRefed<nsIPrincipal>
    2372             : nsIDocument::MaybeDowngradePrincipal(nsIPrincipal* aPrincipal)
    2373           0 : {
    2374             :   if (!aPrincipal) {
    2375             :     return nullptr;
    2376             :   }
    2377             : 
    2378             :   // We can't load a document with an expanded principal. If we're given one,
    2379             :   // automatically downgrade it to the last principal it subsumes (which is the
    2380          41 :   // extension principal, in the case of extension content scripts).
    2381          41 :   auto* basePrin = BasePrincipal::Cast(aPrincipal);
    2382           0 :   if (basePrin->Is<ExpandedPrincipal>()) {
    2383             :     MOZ_DIAGNOSTIC_ASSERT(false, "Should never try to create a document with "
    2384             :                                  "an expanded principal");
    2385             : 
    2386             :     auto* expanded = basePrin->As<ExpandedPrincipal>();
    2387             :     return do_AddRef(expanded->WhiteList().LastElement());
    2388             :   }
    2389          41 : 
    2390             :   if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
    2391             :     // We basically want the parent document here, but because this is very
    2392             :     // early in the load, GetParentDocument() returns null, so we use the
    2393          24 :     // docshell hierarchy to get this information instead.
    2394           8 :     if (mDocumentContainer) {
    2395           0 :       nsCOMPtr<nsIDocShellTreeItem> parentDocShellItem;
    2396           0 :       mDocumentContainer->GetParent(getter_AddRefs(parentDocShellItem));
    2397           0 :       nsCOMPtr<nsIDocShell> parentDocShell = do_QueryInterface(parentDocShellItem);
    2398           0 :       if (parentDocShell) {
    2399           0 :         nsCOMPtr<nsIDocument> parentDoc;
    2400           0 :         parentDoc = parentDocShell->GetDocument();
    2401           0 :         if (!parentDoc ||
    2402             :             !nsContentUtils::IsSystemPrincipal(parentDoc->NodePrincipal())) {
    2403           0 :           nsCOMPtr<nsIPrincipal> nullPrincipal =
    2404           0 :             do_CreateInstance("@mozilla.org/nullprincipal;1");
    2405             :           return nullPrincipal.forget();
    2406             :         }
    2407             :       }
    2408             :     }
    2409          82 :   }
    2410          41 :   nsCOMPtr<nsIPrincipal> principal(aPrincipal);
    2411             :   return principal.forget();
    2412             : }
    2413             : 
    2414           0 : void
    2415             : nsIDocument::RemoveDocStyleSheetsFromStyleSets()
    2416             : {
    2417           0 :   // The stylesheets should forget us
    2418           0 :   for (StyleSheet* sheet : Reversed(mStyleSheets)) {
    2419             :     sheet->ClearAssociatedDocumentOrShadowRoot();
    2420           0 : 
    2421           0 :     if (sheet->IsApplicable()) {
    2422           0 :       nsCOMPtr<nsIPresShell> shell = GetShell();
    2423           0 :       if (shell) {
    2424             :         shell->StyleSet()->RemoveDocStyleSheet(sheet);
    2425             :       }
    2426             :     }
    2427             :     // XXX Tell observers?
    2428           0 :   }
    2429             : }
    2430             : 
    2431           0 : void
    2432             : nsIDocument::RemoveStyleSheetsFromStyleSets(
    2433             :     const nsTArray<RefPtr<StyleSheet>>& aSheets,
    2434             :     SheetType aType)
    2435             : {
    2436           0 :   // The stylesheets should forget us
    2437           0 :   for (StyleSheet* sheet : Reversed(aSheets)) {
    2438             :     sheet->ClearAssociatedDocumentOrShadowRoot();
    2439           0 : 
    2440           0 :     if (sheet->IsApplicable()) {
    2441           0 :       nsCOMPtr<nsIPresShell> shell = GetShell();
    2442           0 :       if (shell) {
    2443             :         shell->StyleSet()->RemoveStyleSheet(aType, sheet);
    2444             :       }
    2445             :     }
    2446             :     // XXX Tell observers?
    2447           0 :   }
    2448             : }
    2449             : 
    2450          49 : void
    2451             : nsIDocument::ResetStylesheetsToURI(nsIURI* aURI)
    2452           0 : {
    2453             :   MOZ_ASSERT(aURI);
    2454           0 : 
    2455             :   if (mStyleSetFilled) {
    2456             :     // Skip removing style sheets from the style set if we know we haven't
    2457             :     // filled the style set.  (This allows us to avoid calling
    2458           0 :     // GetStyleBackendType() too early.)
    2459           0 :     RemoveDocStyleSheetsFromStyleSets();
    2460           0 :     RemoveStyleSheetsFromStyleSets(mOnDemandBuiltInUASheets, SheetType::Agent);
    2461           0 :     RemoveStyleSheetsFromStyleSets(mAdditionalSheets[eAgentSheet], SheetType::Agent);
    2462           0 :     RemoveStyleSheetsFromStyleSets(mAdditionalSheets[eUserSheet], SheetType::User);
    2463             :     RemoveStyleSheetsFromStyleSets(mAdditionalSheets[eAuthorSheet], SheetType::Doc);
    2464           0 : 
    2465             :     if (nsStyleSheetService* sheetService = nsStyleSheetService::GetInstance()) {
    2466           0 :       RemoveStyleSheetsFromStyleSets(
    2467             :         *sheetService->AuthorStyleSheets(), SheetType::Doc);
    2468             :     }
    2469           0 : 
    2470             :     mStyleSetFilled = false;
    2471             :   }
    2472             : 
    2473          49 :   // Release all the sheets
    2474          49 :   mStyleSheets.Clear();
    2475           0 :   mOnDemandBuiltInUASheets.Clear();
    2476           0 :   for (auto& sheets : mAdditionalSheets) {
    2477             :     sheets.Clear();
    2478             :   }
    2479             : 
    2480             :   // NOTE:  We don't release the catalog sheets.  It doesn't really matter
    2481             :   // now, but it could in the future -- in which case not releasing them
    2482             :   // is probably the right thing to do.
    2483             : 
    2484          98 :   // Now reset our inline style and attribute sheets.
    2485           0 :   if (mAttrStyleSheet) {
    2486           0 :     mAttrStyleSheet->Reset();
    2487             :     mAttrStyleSheet->SetOwningDocument(this);
    2488           0 :   } else {
    2489             :     mAttrStyleSheet = new nsHTMLStyleSheet(this);
    2490             :   }
    2491          98 : 
    2492          49 :   if (!mStyleAttrStyleSheet) {
    2493             :     mStyleAttrStyleSheet = new nsHTMLCSSStyleSheet();
    2494             :   }
    2495             : 
    2496          49 :   // Now set up our style sets
    2497           0 :   if (nsIPresShell* shell = GetShell()) {
    2498           0 :     FillStyleSet(shell->StyleSet());
    2499           0 :     if (shell->StyleSet()->StyleSheetsHaveChanged()) {
    2500             :       shell->ApplicableStylesChanged();
    2501             :     }
    2502          49 :   }
    2503             : }
    2504             : 
    2505          81 : static void
    2506             : AppendSheetsToStyleSet(ServoStyleSet* aStyleSet,
    2507             :                        const nsTArray<RefPtr<StyleSheet>>& aSheets,
    2508             :                        SheetType aType)
    2509         243 : {
    2510           0 :   for (StyleSheet* sheet : Reversed(aSheets)) {
    2511             :     aStyleSet->AppendStyleSheet(aType, sheet);
    2512           0 :   }
    2513             : }
    2514             : 
    2515             : 
    2516          27 : void
    2517             : nsIDocument::FillStyleSet(ServoStyleSet* aStyleSet)
    2518           0 : {
    2519          27 :   MOZ_ASSERT(aStyleSet, "Must have a style set");
    2520             :   MOZ_ASSERT(aStyleSet->SheetCount(SheetType::Doc) == 0,
    2521             :              "Style set already has document sheets?");
    2522          27 : 
    2523             :   MOZ_ASSERT(!mStyleSetFilled);
    2524           0 : 
    2525           0 :   for (StyleSheet* sheet : Reversed(mStyleSheets)) {
    2526           0 :     if (sheet->IsApplicable()) {
    2527             :       aStyleSet->AddDocStyleSheet(sheet, this);
    2528             :     }
    2529             :   }
    2530          27 : 
    2531             :   if (nsStyleSheetService* sheetService = nsStyleSheetService::GetInstance()) {
    2532           0 :     nsTArray<RefPtr<StyleSheet>>& sheets =
    2533          81 :       *sheetService->AuthorStyleSheets();
    2534           0 :     for (StyleSheet* sheet : sheets) {
    2535             :       aStyleSet->AppendStyleSheet(SheetType::Doc, sheet);
    2536             :     }
    2537             :   }
    2538             : 
    2539         108 :   // Iterate backwards to maintain order
    2540           0 :   for (StyleSheet* sheet : Reversed(mOnDemandBuiltInUASheets)) {
    2541           0 :     if (sheet->IsApplicable()) {
    2542             :       aStyleSet->PrependStyleSheet(SheetType::Agent, sheet);
    2543             :     }
    2544             :   }
    2545          27 : 
    2546          27 :   AppendSheetsToStyleSet(aStyleSet, mAdditionalSheets[eAgentSheet],
    2547           0 :                          SheetType::Agent);
    2548           0 :   AppendSheetsToStyleSet(aStyleSet, mAdditionalSheets[eUserSheet],
    2549           0 :                          SheetType::User);
    2550           0 :   AppendSheetsToStyleSet(aStyleSet, mAdditionalSheets[eAuthorSheet],
    2551             :                          SheetType::Doc);
    2552           0 : 
    2553          27 :   mStyleSetFilled = true;
    2554             : }
    2555             : 
    2556           4 : static void
    2557             : WarnIfSandboxIneffective(nsIDocShell* aDocShell,
    2558             :                          uint32_t aSandboxFlags,
    2559             :                          nsIChannel* aChannel)
    2560             : {
    2561             :   // If the document is sandboxed (via the HTML5 iframe sandbox
    2562             :   // attribute) and both the allow-scripts and allow-same-origin
    2563             :   // keywords are supplied, the sandboxed document can call into its
    2564             :   // parent document and remove its sandboxing entirely - we print a
    2565           4 :   // warning to the web console in this case.
    2566           4 :   if (aSandboxFlags & SANDBOXED_NAVIGATION &&
    2567             :       !(aSandboxFlags & SANDBOXED_SCRIPTS) &&
    2568           0 :       !(aSandboxFlags & SANDBOXED_ORIGIN)) {
    2569           0 :     nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
    2570           0 :     aDocShell->GetSameTypeParent(getter_AddRefs(parentAsItem));
    2571           0 :     nsCOMPtr<nsIDocShell> parentDocShell = do_QueryInterface(parentAsItem);
    2572           0 :     if (!parentDocShell) {
    2573             :       return;
    2574             :     }
    2575             : 
    2576           0 :     // Don't warn if our parent is not the top-level document.
    2577           0 :     nsCOMPtr<nsIDocShellTreeItem> grandParentAsItem;
    2578           0 :     parentDocShell->GetSameTypeParent(getter_AddRefs(grandParentAsItem));
    2579           0 :     if (grandParentAsItem) {
    2580             :       return;
    2581             :     }
    2582           0 : 
    2583           0 :     nsCOMPtr<nsIChannel> parentChannel;
    2584           0 :     parentDocShell->GetCurrentDocumentChannel(getter_AddRefs(parentChannel));
    2585           0 :     if (!parentChannel) {
    2586             :       return;
    2587           0 :     }
    2588           0 :     nsresult rv = nsContentUtils::CheckSameOrigin(aChannel, parentChannel);
    2589             :     if (NS_FAILED(rv)) {
    2590             :       return;
    2591             :     }
    2592           0 : 
    2593           0 :     nsCOMPtr<nsIDocument> parentDocument = parentDocShell->GetDocument();
    2594           0 :     nsCOMPtr<nsIURI> iframeUri;
    2595           0 :     parentChannel->GetURI(getter_AddRefs(iframeUri));
    2596           0 :     nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
    2597             :                                     NS_LITERAL_CSTRING("Iframe Sandbox"),
    2598             :                                     parentDocument,
    2599             :                                     nsContentUtils::eSECURITY_PROPERTIES,
    2600           0 :                                     "BothAllowScriptsAndSameOriginPresent",
    2601             :                                     nullptr, 0, iframeUri);
    2602             :   }
    2603             : }
    2604             : 
    2605           4 : bool
    2606          16 : nsIDocument::IsSynthesized() {
    2607           0 :   nsCOMPtr<nsILoadInfo> loadInfo = mChannel ? mChannel->GetLoadInfo() : nullptr;
    2608           0 :   return loadInfo && loadInfo->GetServiceWorkerTaintingSynthesized();
    2609           0 : }
    2610           0 : 
    2611             : bool
    2612           0 : nsDocument::IsShadowDOMEnabled(JSContext* aCx, JSObject* aObject)
    2613             : {
    2614             :   JS::Rooted<JSObject*> obj(aCx, aObject);
    2615             : 
    2616          24 :   JSAutoRealm ar(aCx, obj);
    2617             :   JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForObject(aCx, obj));
    2618           0 :   nsCOMPtr<nsPIDOMWindowInner> window =
    2619             :     do_QueryInterface(nsJSUtils::GetStaticScriptGlobal(global));
    2620           0 : 
    2621          48 :   nsIDocument* doc = window ? window->GetExtantDoc() : nullptr;
    2622             :   if (!doc) {
    2623           0 :     return false;
    2624             :   }
    2625           0 : 
    2626          24 :   return doc->IsShadowDOMEnabled();
    2627             : }
    2628             : 
    2629             : bool
    2630          13 : nsDocument::IsShadowDOMEnabled(const nsINode* aNode)
    2631             : {
    2632             :   return aNode->OwnerDoc()->IsShadowDOMEnabled();
    2633             : }
    2634      145467 : 
    2635             : nsresult
    2636           0 : nsDocument::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel,
    2637             :                               nsILoadGroup* aLoadGroup,
    2638             :                               nsISupports* aContainer,
    2639             :                               nsIStreamListener **aDocListener,
    2640          49 :                               bool aReset, nsIContentSink* aSink)
    2641             : {
    2642             :   if (MOZ_LOG_TEST(gDocumentLeakPRLog, LogLevel::Debug)) {
    2643             :     nsCOMPtr<nsIURI> uri;
    2644             :     aChannel->GetURI(getter_AddRefs(uri));
    2645             :     MOZ_LOG(gDocumentLeakPRLog, LogLevel::Debug,
    2646          49 :             ("DOCUMENT %p StartDocumentLoad %s",
    2647           0 :              this, uri ? uri->GetSpecOrDefault().get() : ""));
    2648           0 :   }
    2649           0 : 
    2650             :   MOZ_ASSERT(NodePrincipal()->GetAppId() != nsIScriptSecurityManager::UNKNOWN_APP_ID,
    2651             :              "Document should never have UNKNOWN_APP_ID");
    2652             : 
    2653             :   MOZ_ASSERT(GetReadyStateEnum() == nsIDocument::READYSTATE_UNINITIALIZED,
    2654          49 :              "Bad readyState");
    2655             :   SetReadyStateInternal(READYSTATE_LOADING);
    2656             : 
    2657          49 :   if (nsCRT::strcmp(kLoadAsData, aCommand) == 0) {
    2658             :     mLoadedAsData = true;
    2659           0 :     // We need to disable script & style loading in this case.
    2660             :     // We leave them disabled even in EndLoad(), and let anyone
    2661           0 :     // who puts the document on display to worry about enabling.
    2662          12 : 
    2663             :     // Do not load/process scripts when loading as data
    2664             :     ScriptLoader()->SetEnabled(false);
    2665             : 
    2666             :     // styles
    2667             :     CSSLoader()->SetEnabled(false); // Do not load/process styles when loading as data
    2668          24 :   } else if (nsCRT::strcmp("external-resource", aCommand) == 0) {
    2669             :     // Allow CSS, but not scripts
    2670             :     ScriptLoader()->SetEnabled(false);
    2671          24 :   }
    2672          37 : 
    2673             :   mMayStartLayout = false;
    2674           0 :   MOZ_ASSERT(!mReadyForIdle, "We should never hit DOMContentLoaded before this point");
    2675             : 
    2676             :   if (aReset) {
    2677          49 :     Reset(aChannel, aLoadGroup);
    2678          98 :   }
    2679             : 
    2680           0 :   nsAutoCString contentType;
    2681          38 :   nsCOMPtr<nsIPropertyBag2> bag = do_QueryInterface(aChannel);
    2682             :   if ((bag && NS_SUCCEEDED(bag->GetPropertyAsACString(
    2683             :                 NS_LITERAL_STRING("contentType"), contentType))) ||
    2684          98 :       NS_SUCCEEDED(aChannel->GetContentType(contentType))) {
    2685          98 :     // XXX this is only necessary for viewsource:
    2686           0 :     nsACString::const_iterator start, end, semicolon;
    2687           0 :     contentType.BeginReading(start);
    2688           0 :     contentType.EndReading(end);
    2689             :     semicolon = start;
    2690           0 :     FindCharInReadable(';', semicolon, end);
    2691          49 :     SetContentTypeInternal(Substring(start, semicolon));
    2692           0 :   }
    2693           0 : 
    2694           0 :   RetrieveRelevantHeaders(aChannel);
    2695           0 : 
    2696             :   mChannel = aChannel;
    2697             :   nsCOMPtr<nsIInputStreamChannel> inStrmChan = do_QueryInterface(mChannel);
    2698          49 :   if (inStrmChan) {
    2699             :     bool isSrcdocChannel;
    2700           0 :     inStrmChan->GetIsSrcdocChannel(&isSrcdocChannel);
    2701         196 :     if (isSrcdocChannel) {
    2702           0 :       mIsSrcdocDocument = true;
    2703             :     }
    2704           0 :   }
    2705          12 : 
    2706           0 :   if (mChannel) {
    2707             :     nsLoadFlags loadFlags;
    2708             :     mChannel->GetLoadFlags(&loadFlags);
    2709             :     bool isDocument = false;
    2710          98 :     mChannel->GetIsDocument(&isDocument);
    2711             :     if (loadFlags & nsIRequest::LOAD_DOCUMENT_NEEDS_COOKIE &&
    2712           0 :         isDocument &&
    2713          49 :         IsSynthesized() &&
    2714           0 :         XRE_IsContentProcess()) {
    2715           0 :       ContentChild::UpdateCookieStatus(mChannel);
    2716           0 :     }
    2717           0 :   }
    2718           0 : 
    2719           0 :   // If this document is being loaded by a docshell, copy its sandbox flags
    2720             :   // to the document, and store the fullscreen enabled flag. These are
    2721             :   // immutable after being set here.
    2722             :   nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(aContainer);
    2723             : 
    2724             :   // If this is an error page, don't inherit sandbox flags from docshell
    2725             :   nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
    2726          98 :   if (docShell && !(loadInfo && loadInfo->GetLoadErrorPage())) {
    2727             :     nsresult rv = docShell->GetSandboxFlags(&mSandboxFlags);
    2728             :     NS_ENSURE_SUCCESS(rv, rv);
    2729          98 :     WarnIfSandboxIneffective(docShell, mSandboxFlags, GetChannel());
    2730          53 :   }
    2731           0 : 
    2732           0 :   // The CSP directive upgrade-insecure-requests not only applies to the
    2733           0 :   // toplevel document, but also to nested documents. Let's propagate that
    2734             :   // flag from the parent to the nested document.
    2735             :   nsCOMPtr<nsIDocShellTreeItem> treeItem = this->GetDocShell();
    2736             :   if (treeItem) {
    2737             :     nsCOMPtr<nsIDocShellTreeItem> sameTypeParent;
    2738             :     treeItem->GetSameTypeParent(getter_AddRefs(sameTypeParent));
    2739          98 :     if (sameTypeParent) {
    2740          49 :       nsIDocument* doc = sameTypeParent->GetDocument();
    2741           0 :       mBlockAllMixedContent = doc->GetBlockAllMixedContent(false);
    2742           0 :       // if the parent document makes use of block-all-mixed-content
    2743           0 :       // then subdocument preloads should always be blocked.
    2744           0 :       mBlockAllMixedContentPreloads =
    2745           0 :         mBlockAllMixedContent || doc->GetBlockAllMixedContent(true);
    2746             : 
    2747             :       mUpgradeInsecureRequests = doc->GetUpgradeInsecureRequests(false);
    2748           1 :       // if the parent document makes use of upgrade-insecure-requests
    2749           2 :       // then subdocument preloads should always be upgraded.
    2750             :       mUpgradeInsecurePreloads =
    2751           0 :         mUpgradeInsecureRequests || doc->GetUpgradeInsecureRequests(true);
    2752             :     }
    2753             :   }
    2754           1 : 
    2755           2 :   // If this is not a data document, set CSP.
    2756             :   if (!mLoadedAsData) {
    2757             :     nsresult rv = InitCSP(aChannel);
    2758             :     NS_ENSURE_SUCCESS(rv, rv);
    2759             :   }
    2760          49 : 
    2761          37 :   // XFO needs to be checked after CSP because it is ignored if
    2762           0 :   // the CSP defines frame-ancestors.
    2763             :   if (!FramingChecker::CheckFrameOptions(aChannel, docShell, NodePrincipal())) {
    2764             :     MOZ_LOG(gCspPRLog, LogLevel::Debug,
    2765             :             ("XFO doesn't like frame's ancestry, not loading."));
    2766             :     // stop!  ERROR page!
    2767          98 :     aChannel->Cancel(NS_ERROR_CSP_FRAME_ANCESTOR_VIOLATION);
    2768           0 :   }
    2769             : 
    2770             :   // Perform a async flash classification based on the doc principal
    2771           0 :   // in an early stage to reduce the blocking time.
    2772             :   mFlashClassification = FlashClassification::Unclassified;
    2773             :   mPrincipalFlashClassifier->AsyncClassify(GetPrincipal());
    2774             : 
    2775             :   return NS_OK;
    2776          49 : }
    2777          49 : 
    2778             : void
    2779           0 : nsIDocument::SendToConsole(nsCOMArray<nsISecurityConsoleMessage>& aMessages)
    2780             : {
    2781             :   for (uint32_t i = 0; i < aMessages.Length(); ++i) {
    2782             :     nsAutoString messageTag;
    2783           0 :     aMessages[i]->GetTag(messageTag);
    2784             : 
    2785           0 :     nsAutoString category;
    2786           0 :     aMessages[i]->GetCategory(category);
    2787           0 : 
    2788             :     nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
    2789           0 :                                     NS_ConvertUTF16toUTF8(category),
    2790           0 :                                     this, nsContentUtils::eSECURITY_PROPERTIES,
    2791             :                                     NS_ConvertUTF16toUTF8(messageTag).get());
    2792           0 :   }
    2793           0 : }
    2794             : 
    2795           0 : void
    2796             : nsIDocument::ApplySettingsFromCSP(bool aSpeculative)
    2797           0 : {
    2798             :   nsresult rv = NS_OK;
    2799             :   if (!aSpeculative) {
    2800           2 :     // 1) apply settings from regular CSP
    2801             :     nsCOMPtr<nsIContentSecurityPolicy> csp;
    2802           0 :     rv = NodePrincipal()->GetCsp(getter_AddRefs(csp));
    2803           2 :     NS_ENSURE_SUCCESS_VOID(rv);
    2804             :     if (csp) {
    2805           0 :       // Set up 'block-all-mixed-content' if not already inherited
    2806           4 :       // from the parent context or set by any other CSP.
    2807           0 :       if (!mBlockAllMixedContent) {
    2808           0 :         rv = csp->GetBlockAllMixedContent(&mBlockAllMixedContent);
    2809             :         NS_ENSURE_SUCCESS_VOID(rv);
    2810             :       }
    2811           2 :       if (!mBlockAllMixedContentPreloads) {
    2812           2 :         mBlockAllMixedContentPreloads = mBlockAllMixedContent;
    2813           0 :      }
    2814             : 
    2815           0 :       // Set up 'upgrade-insecure-requests' if not already inherited
    2816           2 :       // from the parent context or set by any other CSP.
    2817             :       if (!mUpgradeInsecureRequests) {
    2818             :         rv = csp->GetUpgradeInsecureRequests(&mUpgradeInsecureRequests);
    2819             :         NS_ENSURE_SUCCESS_VOID(rv);
    2820             :       }
    2821           2 :       if (!mUpgradeInsecurePreloads) {
    2822           2 :         mUpgradeInsecurePreloads = mUpgradeInsecureRequests;
    2823           0 :       }
    2824             :     }
    2825           0 :     return;
    2826           2 :   }
    2827             : 
    2828             :   // 2) apply settings from speculative csp
    2829             :   nsCOMPtr<nsIContentSecurityPolicy> preloadCsp;
    2830             :   rv = NodePrincipal()->GetPreloadCsp(getter_AddRefs(preloadCsp));
    2831             :   NS_ENSURE_SUCCESS_VOID(rv);
    2832             :   if (preloadCsp) {
    2833           0 :     if (!mBlockAllMixedContentPreloads) {
    2834           0 :       rv = preloadCsp->GetBlockAllMixedContent(&mBlockAllMixedContentPreloads);
    2835           0 :       NS_ENSURE_SUCCESS_VOID(rv);
    2836           0 :     }
    2837           0 :     if (!mUpgradeInsecurePreloads) {
    2838           0 :       rv = preloadCsp->GetUpgradeInsecureRequests(&mUpgradeInsecurePreloads);
    2839           0 :       NS_ENSURE_SUCCESS_VOID(rv);
    2840             :     }
    2841           0 :   }
    2842           0 : }
    2843           0 : 
    2844             : nsresult
    2845             : nsIDocument::InitCSP(nsIChannel* aChannel)
    2846             : {
    2847             :   MOZ_ASSERT(!mScriptGlobalObject,
    2848             :              "CSP must be initialized before mScriptGlobalObject is set!");
    2849          37 :   if (!CSPService::sCSPEnabled) {
    2850             :     MOZ_LOG(gCspPRLog, LogLevel::Debug,
    2851           0 :            ("CSP is disabled, skipping CSP init for document %p", this));
    2852             :     return NS_OK;
    2853           0 :   }
    2854           0 : 
    2855             :   nsAutoCString tCspHeaderValue, tCspROHeaderValue;
    2856             : 
    2857             :   nsCOMPtr<nsIHttpChannel> httpChannel;
    2858             :   nsresult rv = GetHttpChannelHelper(aChannel, getter_AddRefs(httpChannel));
    2859          74 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2860             :     return rv;
    2861           0 :   }
    2862          37 : 
    2863           0 :   if (httpChannel) {
    2864             :     Unused << httpChannel->GetResponseHeader(
    2865             :         NS_LITERAL_CSTRING("content-security-policy"),
    2866             :         tCspHeaderValue);
    2867          37 : 
    2868           0 :     Unused << httpChannel->GetResponseHeader(
    2869           0 :         NS_LITERAL_CSTRING("content-security-policy-report-only"),
    2870           0 :         tCspROHeaderValue);
    2871             :   }
    2872           0 :   NS_ConvertASCIItoUTF16 cspHeaderValue(tCspHeaderValue);
    2873           0 :   NS_ConvertASCIItoUTF16 cspROHeaderValue(tCspROHeaderValue);
    2874           0 : 
    2875             :   // Check if this is a document from a WebExtension.
    2876           0 :   nsCOMPtr<nsIPrincipal> principal = NodePrincipal();
    2877          74 :   auto addonPolicy = BasePrincipal::Cast(principal)->AddonPolicy();
    2878             : 
    2879             :   // Check if this is a signed content to apply default CSP.
    2880          74 :   bool applySignedContentCSP = false;
    2881          37 :   nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
    2882             :   if (loadInfo && loadInfo->GetVerifySignedContent()) {
    2883             :     applySignedContentCSP = true;
    2884          37 :   }
    2885          74 : 
    2886           0 :   // If there's no CSP to apply, go ahead and return early
    2887           0 :   if (!addonPolicy &&
    2888             :       !applySignedContentCSP &&
    2889             :       cspHeaderValue.IsEmpty() &&
    2890             :       cspROHeaderValue.IsEmpty()) {
    2891         111 :     if (MOZ_LOG_TEST(gCspPRLog, LogLevel::Debug)) {
    2892          72 :       nsCOMPtr<nsIURI> chanURI;
    2893           0 :       aChannel->GetURI(getter_AddRefs(chanURI));
    2894           0 :       nsAutoCString aspec;
    2895           0 :       chanURI->GetAsciiSpec(aspec);
    2896           0 :       MOZ_LOG(gCspPRLog, LogLevel::Debug,
    2897           0 :              ("no CSP for document, %s",
    2898           0 :               aspec.get()));
    2899           0 :     }
    2900           0 : 
    2901             :     return NS_OK;
    2902             :   }
    2903             : 
    2904             :   MOZ_LOG(gCspPRLog, LogLevel::Debug, ("Document is an add-on or CSP header specified %p", this));
    2905             : 
    2906             :   nsCOMPtr<nsIContentSecurityPolicy> csp;
    2907             :   rv = principal->EnsureCSP(static_cast<nsDocument*>(this), getter_AddRefs(csp));
    2908           2 :   NS_ENSURE_SUCCESS(rv, rv);
    2909             : 
    2910           0 :   // ----- if the doc is an addon, apply its CSP.
    2911           4 :   if (addonPolicy) {
    2912           0 :     nsCOMPtr<nsIAddonPolicyService> aps = do_GetService("@mozilla.org/addons/policy-service;1");
    2913             : 
    2914             :     nsAutoString addonCSP;
    2915           2 :     Unused << ExtensionPolicyService::GetSingleton().GetBaseCSP(addonCSP);
    2916           4 :     csp->AppendPolicy(addonCSP, false, false);
    2917             : 
    2918           0 :     csp->AppendPolicy(addonPolicy->ContentSecurityPolicy(), false, false);
    2919           2 :   }
    2920           0 : 
    2921             :   // ----- if the doc is a signed content, apply the default CSP.
    2922           0 :   // Note that when the content signing becomes a standard, we might have
    2923             :   // to restrict this enforcement to "remote content" only.
    2924             :   if (applySignedContentCSP) {
    2925             :     nsAutoString signedContentCSP;
    2926             :     Preferences::GetString("security.signed_content.CSP.default",
    2927             :                            signedContentCSP);
    2928           2 :     csp->AppendPolicy(signedContentCSP, false, false);
    2929           0 :   }
    2930             : 
    2931           0 :   // ----- if there's a full-strength CSP header, apply it.
    2932           0 :   if (!cspHeaderValue.IsEmpty()) {
    2933             :     rv = CSP_AppendCSPFromHeader(csp, cspHeaderValue, false);
    2934             :     NS_ENSURE_SUCCESS(rv, rv);
    2935             :   }
    2936           2 : 
    2937           0 :   // ----- if there's a report-only CSP header, apply it.
    2938           0 :   if (!cspROHeaderValue.IsEmpty()) {
    2939             :     rv = CSP_AppendCSPFromHeader(csp, cspROHeaderValue, true);
    2940             :     NS_ENSURE_SUCCESS(rv, rv);
    2941             :   }
    2942           2 : 
    2943           0 :   // ----- Enforce sandbox policy if supplied in CSP header
    2944           0 :   // The document may already have some sandbox flags set (e.g. if the document
    2945             :   // is an iframe with the sandbox attribute set). If we have a CSP sandbox
    2946             :   // directive, intersect the CSP sandbox flags with the existing flags. This
    2947             :   // corresponds to the _least_ permissive policy.
    2948             :   uint32_t cspSandboxFlags = SANDBOXED_NONE;
    2949             :   rv = csp->GetCSPSandboxFlags(&cspSandboxFlags);
    2950             :   NS_ENSURE_SUCCESS(rv, rv);
    2951             : 
    2952           2 :   // Probably the iframe sandbox attribute already caused the creation of a
    2953           2 :   // new NullPrincipal. Only create a new NullPrincipal if CSP requires so
    2954           0 :   // and no one has been created yet.
    2955             :   bool needNewNullPrincipal =
    2956             :     (cspSandboxFlags & SANDBOXED_ORIGIN) && !(mSandboxFlags & SANDBOXED_ORIGIN);
    2957             : 
    2958             :   mSandboxFlags |= cspSandboxFlags;
    2959             : 
    2960           2 :   if (needNewNullPrincipal) {
    2961             :     principal = NullPrincipal::CreateWithInheritedAttributes(principal);
    2962           0 :     principal->SetCsp(csp);
    2963             :     SetPrincipal(principal);
    2964           0 :   }
    2965           0 : 
    2966           0 :   // ----- Enforce frame-ancestor policy on any applied policies
    2967           0 :   nsCOMPtr<nsIDocShell> docShell(mDocumentContainer);
    2968             :   if (docShell) {
    2969             :     bool safeAncestry = false;
    2970             : 
    2971           4 :     // PermitsAncestry sends violation reports when necessary
    2972           2 :     rv = csp->PermitsAncestry(docShell, &safeAncestry);
    2973           0 : 
    2974             :     if (NS_FAILED(rv) || !safeAncestry) {
    2975             :       MOZ_LOG(gCspPRLog, LogLevel::Debug,
    2976           4 :               ("CSP doesn't like frame's ancestry, not loading."));
    2977             :       // stop!  ERROR page!
    2978           0 :       aChannel->Cancel(NS_ERROR_CSP_FRAME_ANCESTOR_VIOLATION);
    2979           0 :     }
    2980             :   }
    2981             :   ApplySettingsFromCSP(false);
    2982           0 :   return NS_OK;
    2983             : }
    2984             : 
    2985           2 : void
    2986             : nsDocument::StopDocumentLoad()
    2987             : {
    2988             :   if (mParser) {
    2989             :     mParserAborted = true;
    2990           9 :     mParser->Terminate();
    2991             :   }
    2992           0 : }
    2993           0 : 
    2994           0 : void
    2995             : nsIDocument::SetDocumentURI(nsIURI* aURI)
    2996           0 : {
    2997             :   nsCOMPtr<nsIURI> oldBase = GetDocBaseURI();
    2998             :   mDocumentURI = aURI;
    2999          58 :   nsIURI* newBase = GetDocBaseURI();
    3000             : 
    3001           0 :   bool equalBases = false;
    3002          58 :   // Changing just the ref of a URI does not change how relative URIs would
    3003           0 :   // resolve wrt to it, so we can treat the bases as equal as long as they're
    3004             :   // equal ignoring the ref.
    3005           0 :   if (oldBase && newBase) {
    3006             :     oldBase->EqualsExceptRef(newBase, &equalBases);
    3007             :   }
    3008             :   else {
    3009          58 :     equalBases = !oldBase && !newBase;
    3010           1 :   }
    3011             : 
    3012             :   // If this is the first time we're setting the document's URI, set the
    3013          57 :   // document's original URI.
    3014             :   if (!mOriginalURI)
    3015             :     mOriginalURI = mDocumentURI;
    3016             : 
    3017             :   // If changing the document's URI changed the base URI of the document, we
    3018         116 :   // need to refresh the hrefs of all the links on the page.
    3019          58 :   if (!equalBases) {
    3020             :     RefreshLinkHrefs();
    3021             :   }
    3022             : }
    3023          58 : 
    3024          57 : static void
    3025             : GetFormattedTimeString(PRTime aTime, nsAString& aFormattedTimeString)
    3026           0 : {
    3027             :   PRExplodedTime prtime;
    3028             :   PR_ExplodeTime(aTime, PR_LocalTimeParameters, &prtime);
    3029           0 :   // "MM/DD/YYYY hh:mm:ss"
    3030             :   char formatedTime[24];
    3031             :   if (SprintfLiteral(formatedTime, "%02d/%02d/%04d %02d:%02d:%02d",
    3032           0 :                      prtime.tm_month + 1, prtime.tm_mday, int(prtime.tm_year),
    3033             :                      prtime.tm_hour     ,  prtime.tm_min,  prtime.tm_sec)) {
    3034             :     CopyASCIItoUTF16(nsDependentCString(formatedTime), aFormattedTimeString);
    3035           0 :   } else {
    3036           0 :     // If we for whatever reason failed to find the last modified time
    3037             :     // (or even the current time), fall back to what NS4.x returned.
    3038           0 :     aFormattedTimeString.AssignLiteral(u"01/01/1970 00:00:00");
    3039             :   }
    3040             : }
    3041             : 
    3042           0 : void
    3043             : nsIDocument::GetLastModified(nsAString& aLastModified) const
    3044           0 : {
    3045             :   if (!mLastModified.IsEmpty()) {
    3046             :     aLastModified.Assign(mLastModified);
    3047           0 :   } else {
    3048             :     GetFormattedTimeString(PR_Now(), aLastModified);
    3049           0 :   }
    3050           0 : }
    3051             : 
    3052           0 : static void
    3053             : IncrementExpandoGeneration(nsIDocument& aDoc)
    3054           0 : {
    3055             :   ++static_cast<nsDocument&>(aDoc).mExpandoAndGeneration.generation;
    3056             : }
    3057             : 
    3058             : void
    3059          46 : nsIDocument::AddToNameTable(Element* aElement, nsAtom* aName)
    3060             : {
    3061             :   MOZ_ASSERT(nsGenericHTMLElement::ShouldExposeNameAsHTMLDocumentProperty(aElement),
    3062             :              "Only put elements that need to be exposed as document['name'] in "
    3063           0 :              "the named table.");
    3064             : 
    3065           0 :   nsIdentifierMapEntry* entry = mIdentifierMap.PutEntry(aName);
    3066             : 
    3067             :   // Null for out-of-memory
    3068             :   if (entry) {
    3069           0 :     if (!entry->HasNameElement() &&
    3070             :         !entry->HasIdElementExposedAsHTMLDocumentProperty()) {
    3071             :       IncrementExpandoGeneration(*this);
    3072           0 :     }
    3073           0 :     entry->AddNameElement(this, aElement);
    3074           0 :   }
    3075             : }
    3076             : 
    3077           0 : void
    3078             : nsIDocument::RemoveFromNameTable(Element* aElement, nsAtom* aName)
    3079           0 : {
    3080             :   // Speed up document teardown
    3081             :   if (mIdentifierMap.Count() == 0)
    3082           0 :     return;
    3083             : 
    3084             :   nsIdentifierMapEntry* entry = mIdentifierMap.GetEntry(aName);
    3085           0 :   if (!entry) // Could be false if the element was anonymous, hence never added
    3086             :     return;
    3087             : 
    3088           0 :   entry->RemoveNameElement(aElement);
    3089           0 :   if (!entry->HasNameElement() &&
    3090             :       !entry->HasIdElementExposedAsHTMLDocumentProperty()) {
    3091             :     IncrementExpandoGeneration(*this);
    3092           0 :   }
    3093           0 : }
    3094           0 : 
    3095             : void
    3096             : nsIDocument::AddToIdTable(Element* aElement, nsAtom* aId)
    3097             : {
    3098             :   nsIdentifierMapEntry* entry = mIdentifierMap.PutEntry(aId);
    3099             : 
    3100        2692 :   if (entry) { /* True except on OOM */
    3101             :     if (nsGenericHTMLElement::ShouldExposeIdAsHTMLDocumentProperty(aElement) &&
    3102           0 :         !entry->HasNameElement() &&
    3103             :         !entry->HasIdElementExposedAsHTMLDocumentProperty()) {
    3104           0 :       IncrementExpandoGeneration(*this);
    3105        5384 :     }
    3106           0 :     entry->AddIdElement(aElement);
    3107           0 :   }
    3108             : }
    3109             : 
    3110        2692 : void
    3111             : nsIDocument::RemoveFromIdTable(Element* aElement, nsAtom* aId)
    3112           0 : {
    3113             :   NS_ASSERTION(aId, "huhwhatnow?");
    3114             : 
    3115         138 :   // Speed up document teardown
    3116             :   if (mIdentifierMap.Count() == 0) {
    3117           0 :     return;
    3118             :   }
    3119             : 
    3120         276 :   nsIdentifierMapEntry* entry = mIdentifierMap.GetEntry(aId);
    3121             :   if (!entry) // Can be null for XML elements with changing ids.
    3122             :     return;
    3123             : 
    3124         276 :   entry->RemoveIdElement(aElement);
    3125         138 :   if (nsGenericHTMLElement::ShouldExposeIdAsHTMLDocumentProperty(aElement) &&
    3126             :       !entry->HasNameElement() &&
    3127             :       !entry->HasIdElementExposedAsHTMLDocumentProperty()) {
    3128         111 :     IncrementExpandoGeneration(*this);
    3129         222 :   }
    3130           0 :   if (entry->IsEmpty()) {
    3131           0 :     mIdentifierMap.RemoveEntry(entry);
    3132             :   }
    3133             : }
    3134         111 : 
    3135         111 : nsIPrincipal*
    3136             : nsDocument::GetPrincipal()
    3137             : {
    3138             :   return NodePrincipal();
    3139             : }
    3140          49 : 
    3141             : extern bool sDisablePrefetchHTTPSPref;
    3142           0 : 
    3143             : void
    3144             : nsIDocument::SetPrincipal(nsIPrincipal *aNewPrincipal)
    3145             : {
    3146             :   if (aNewPrincipal && mAllowDNSPrefetch && sDisablePrefetchHTTPSPref) {
    3147             :     nsCOMPtr<nsIURI> uri;
    3148         107 :     aNewPrincipal->GetURI(getter_AddRefs(uri));
    3149             :     bool isHTTPS;
    3150           0 :     if (!uri || NS_FAILED(uri->SchemeIs("https", &isHTTPS)) ||
    3151         122 :         isHTTPS) {
    3152           0 :       mAllowDNSPrefetch = false;
    3153             :     }
    3154           0 :   }
    3155             :   mNodeInfoManager->SetDocumentPrincipal(aNewPrincipal);
    3156           0 : 
    3157             : #ifdef DEBUG
    3158             :   // Validate that the docgroup is set correctly by calling its getter and
    3159         107 :   // triggering its sanity check.
    3160             :   //
    3161             :   // If we're setting the principal to null, we don't want to perform the check,
    3162             :   // as the document is entering an intermediate state where it does not have a
    3163             :   // principal. It will be given another real principal shortly which we will
    3164             :   // check. It's not unsafe to have a document which has a null principal in the
    3165             :   // same docgroup as another document, so this should not be a problem.
    3166             :   if (aNewPrincipal) {
    3167             :     GetDocGroup();
    3168             :   }
    3169             : #endif
    3170         107 : }
    3171          61 : 
    3172             : mozilla::dom::DocGroup*
    3173             : nsIDocument::GetDocGroup() const
    3174         107 : {
    3175             : #ifdef DEBUG
    3176             :   // Sanity check that we have an up-to-date and accurate docgroup
    3177         897 :   if (mDocGroup) {
    3178             :     nsAutoCString docGroupKey;
    3179             : 
    3180             :     // GetKey() can fail, e.g. after the TLD service has shut down.
    3181        1794 :     nsresult rv = mozilla::dom::DocGroup::GetKey(NodePrincipal(), docGroupKey);
    3182        1670 :     if (NS_SUCCEEDED(rv)) {
    3183             :       MOZ_ASSERT(mDocGroup->MatchesKey(docGroupKey));
    3184             :     }
    3185         835 :     // XXX: Check that the TabGroup is correct as well!
    3186         835 :   }
    3187           0 : #endif
    3188             : 
    3189             :   return mDocGroup;
    3190             : }
    3191             : 
    3192             : nsresult
    3193        1794 : nsIDocument::Dispatch(TaskCategory aCategory,
    3194             :                       already_AddRefed<nsIRunnable>&& aRunnable)
    3195             : {
    3196             :   // Note that this method may be called off the main thread.
    3197         149 :   if (mDocGroup) {
    3198             :     return mDocGroup->Dispatch(aCategory, std::move(aRunnable));
    3199             :   }
    3200             :   return DispatcherTrait::Dispatch(aCategory, std::move(aRunnable));
    3201         298 : }
    3202          64 : 
    3203             : nsISerialEventTarget*
    3204           0 : nsIDocument::EventTargetFor(TaskCategory aCategory) const
    3205             : {
    3206             :   if (mDocGroup) {
    3207             :     return mDocGroup->EventTargetFor(aCategory);
    3208          52 :   }
    3209             :   return DispatcherTrait::EventTargetFor(aCategory);
    3210           0 : }
    3211          37 : 
    3212             : AbstractThread*
    3213           0 : nsIDocument::AbstractMainThreadFor(mozilla::TaskCategory aCategory)
    3214             : {
    3215             :   MOZ_ASSERT(NS_IsMainThread());
    3216             :   if (mDocGroup) {
    3217           2 :     return mDocGroup->AbstractMainThreadFor(aCategory);
    3218             :   }
    3219           0 :   return DispatcherTrait::AbstractMainThreadFor(aCategory);
    3220           4 : }
    3221           0 : 
    3222             : void
    3223           0 : nsIDocument::NoteScriptTrackingStatus(const nsACString& aURL, bool aIsTracking)
    3224             : {
    3225             :   if (aIsTracking) {
    3226             :     mTrackingScripts.PutEntry(aURL);
    3227           5 :   } else {
    3228             :     MOZ_ASSERT(!mTrackingScripts.Contains(aURL));
    3229           0 :   }
    3230           0 : }
    3231             : 
    3232           0 : bool
    3233             : nsIDocument::IsScriptTracking(const nsACString& aURL) const
    3234           0 : {
    3235             :   return mTrackingScripts.Contains(aURL);
    3236             : }
    3237           1 : 
    3238             : NS_IMETHODIMP
    3239           0 : nsDocument::GetApplicationCache(nsIApplicationCache **aApplicationCache)
    3240             : {
    3241             :   NS_IF_ADDREF(*aApplicationCache = mApplicationCache);
    3242             : 
    3243           0 :   return NS_OK;
    3244             : }
    3245           0 : 
    3246             : NS_IMETHODIMP
    3247           0 : nsDocument::SetApplicationCache(nsIApplicationCache *aApplicationCache)
    3248             : {
    3249             :   mApplicationCache = aApplicationCache;
    3250             : 
    3251           0 :   return NS_OK;
    3252             : }
    3253           0 : 
    3254             : void
    3255           0 : nsIDocument::GetContentType(nsAString& aContentType)
    3256             : {
    3257             :   CopyUTF8toUTF16(GetContentTypeInternal(), aContentType);
    3258             : }
    3259          23 : 
    3260             : void
    3261           0 : nsIDocument::SetContentType(const nsAString& aContentType)
    3262          23 : {
    3263             :   SetContentTypeInternal(NS_ConvertUTF16toUTF8(aContentType));
    3264             : }
    3265           0 : 
    3266             : bool
    3267           0 : nsIDocument::GetAllowPlugins()
    3268           0 : {
    3269             :   // First, we ask our docshell if it allows plugins.
    3270             :   nsCOMPtr<nsIDocShell> docShell(mDocumentContainer);
    3271           0 : 
    3272             :   if (docShell) {
    3273             :     bool allowPlugins = false;
    3274           0 :     docShell->GetAllowPlugins(&allowPlugins);
    3275             :     if (!allowPlugins) {
    3276           0 :       return false;
    3277           0 :     }
    3278           0 : 
    3279           0 :     // If the docshell allows plugins, we check whether
    3280           0 :     // we are sandboxed and plugins should not be allowed.
    3281             :     if (mSandboxFlags & SANDBOXED_PLUGINS) {
    3282             :       return false;
    3283             :     }
    3284             :   }
    3285           0 : 
    3286             :   FlashClassification classification = DocumentFlashClassification();
    3287             :   if (classification == FlashClassification::Denied) {
    3288             :     return false;
    3289             :   }
    3290           0 : 
    3291           0 :   return true;
    3292             : }
    3293             : 
    3294             : bool
    3295           0 : nsDocument::IsElementAnimateEnabled(JSContext* aCx, JSObject* /*unused*/)
    3296             : {
    3297             :   MOZ_ASSERT(NS_IsMainThread());
    3298             : 
    3299           8 :   return nsContentUtils::IsSystemCaller(aCx) ||
    3300             :          nsContentUtils::AnimationsAPICoreEnabled() ||
    3301           0 :          nsContentUtils::AnimationsAPIElementAnimateEnabled();
    3302             : }
    3303          10 : 
    3304           8 : bool
    3305           8 : nsDocument::IsWebAnimationsEnabled(JSContext* aCx, JSObject* /*unused*/)
    3306             : {
    3307             :   MOZ_ASSERT(NS_IsMainThread());
    3308             : 
    3309          40 :   return nsContentUtils::IsSystemCaller(aCx) ||
    3310             :          nsContentUtils::AnimationsAPICoreEnabled();
    3311           0 : }
    3312             : 
    3313          56 : bool
    3314          40 : nsDocument::IsWebAnimationsEnabled(CallerType aCallerType)
    3315             : {
    3316             :   MOZ_ASSERT(NS_IsMainThread());
    3317             : 
    3318           0 :   return aCallerType == dom::CallerType::System ||
    3319             :          nsContentUtils::AnimationsAPICoreEnabled();
    3320           0 : }
    3321             : 
    3322           0 : DocumentTimeline*
    3323           0 : nsIDocument::Timeline()
    3324             : {
    3325             :   if (!mDocumentTimeline) {
    3326             :     mDocumentTimeline = new DocumentTimeline(this, TimeDuration(0));
    3327          15 :   }
    3328             : 
    3329           0 :   return mDocumentTimeline;
    3330           0 : }
    3331             : 
    3332             : void
    3333          30 : nsIDocument::GetAnimations(nsTArray<RefPtr<Animation>>& aAnimations)
    3334             : {
    3335             :   // Hold a strong ref for the root element since Element::GetAnimations() calls
    3336             :   // FlushPendingNotifications() which may destroy the element.
    3337           0 :   RefPtr<Element> root = GetRootElement();
    3338             :   if (!root) {
    3339             :     return;
    3340             :   }
    3341           0 :   AnimationFilter filter;
    3342           0 :   filter.mSubtree = true;
    3343           0 :   root->GetAnimations(filter, aAnimations);
    3344             : }
    3345           0 : 
    3346           0 : SVGSVGElement*
    3347           0 : nsIDocument::GetSVGRootElement() const
    3348             : {
    3349             :   Element* root = GetRootElement();
    3350             :   if (!root || !root->IsSVGElement(nsGkAtoms::svg)) {
    3351           0 :     return nullptr;
    3352             :   }
    3353           0 :   return static_cast<SVGSVGElement*>(root);
    3354           0 : }
    3355             : 
    3356             : /* Return true if the document is in the focused top-level window, and is an
    3357           0 :  * ancestor of the focused DOMWindow. */
    3358             : bool
    3359             : nsIDocument::HasFocus(ErrorResult& rv) const
    3360             : {
    3361             :   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
    3362             :   if (!fm) {
    3363           0 :     rv.Throw(NS_ERROR_NOT_AVAILABLE);
    3364             :     return false;
    3365          15 :   }
    3366          15 : 
    3367           0 :   // Is there a focused DOMWindow?
    3368           0 :   nsCOMPtr<mozIDOMWindowProxy> focusedWindow;
    3369             :   fm->GetFocusedWindow(getter_AddRefs(focusedWindow));
    3370             :   if (!focusedWindow) {
    3371             :     return false;
    3372           0 :   }
    3373          30 : 
    3374          15 :   nsPIDOMWindowOuter* piWindow = nsPIDOMWindowOuter::From(focusedWindow);
    3375             : 
    3376             :   // Are we an ancestor of the focused DOMWindow?
    3377             :   for (nsIDocument* currentDoc = piWindow->GetDoc(); currentDoc;
    3378           0 :        currentDoc = currentDoc->GetParentDocument()) {
    3379             :     if (currentDoc == this) {
    3380             :       // Yes, we are an ancestor
    3381           0 :       return true;
    3382             :     }
    3383           5 :   }
    3384             : 
    3385             :   return false;
    3386             : }
    3387             : 
    3388             : TimeStamp
    3389             : nsIDocument::LastFocusTime() const
    3390             : {
    3391             :   return mLastFocusTime;
    3392             : }
    3393           0 : 
    3394             : void
    3395           0 : nsIDocument::SetLastFocusTime(const TimeStamp& aFocusTime)
    3396             : {
    3397             :   MOZ_DIAGNOSTIC_ASSERT(!aFocusTime.IsNull());
    3398             :   MOZ_DIAGNOSTIC_ASSERT(mLastFocusTime.IsNull() ||
    3399           0 :                         aFocusTime >= mLastFocusTime);
    3400             :   mLastFocusTime = aFocusTime;
    3401           1 : }
    3402           2 : 
    3403             : void
    3404           0 : nsIDocument::GetReferrer(nsAString& aReferrer) const
    3405           0 : {
    3406             :   if (mIsSrcdocDocument && mParentDocument)
    3407             :       mParentDocument->GetReferrer(aReferrer);
    3408           2 :   else
    3409             :     CopyUTF8toUTF16(mReferrer, aReferrer);
    3410           2 : }
    3411             : 
    3412             : nsresult
    3413           2 : nsIDocument::GetSrcdocData(nsAString &aSrcdocData)
    3414           2 : {
    3415             :   if (mIsSrcdocDocument) {
    3416             :     nsCOMPtr<nsIInputStreamChannel> inStrmChan = do_QueryInterface(mChannel);
    3417           0 :     if (inStrmChan) {
    3418             :       return inStrmChan->GetSrcdocData(aSrcdocData);
    3419           0 :     }
    3420           0 :   }
    3421           0 :   aSrcdocData = VoidString();
    3422           0 :   return NS_OK;
    3423             : }
    3424             : 
    3425           0 : Element*
    3426           0 : nsIDocument::GetActiveElement()
    3427             : {
    3428             :   // Get the focused element.
    3429             :   Element* focusedElement = GetRetargetedFocusedElement();
    3430           0 :   if (focusedElement) {
    3431             :     return focusedElement;
    3432             :   }
    3433           1 : 
    3434           1 :   // No focused element anywhere in this document.  Try to get the BODY.
    3435             :   if (IsHTMLOrXHTML()) {
    3436             :     // Because of IE compatibility, return null when html document doesn't have
    3437             :     // a body.
    3438             :     return AsHTMLDocument()->GetBody();
    3439           0 :   }
    3440             : 
    3441             :   // If we couldn't get a BODY, return the root element.
    3442           0 :   return GetDocumentElement();
    3443             : }
    3444             : 
    3445             : Element*
    3446           1 : nsIDocument::GetCurrentScript()
    3447             : {
    3448             :   nsCOMPtr<Element> el(do_QueryInterface(ScriptLoader()->GetCurrentScript()));
    3449             :   return el;
    3450           0 : }
    3451             : 
    3452           0 : nsresult
    3453           0 : nsIDocument::NodesFromRectHelper(float aX, float aY,
    3454             :                                  float aTopSize, float aRightSize,
    3455             :                                  float aBottomSize, float aLeftSize,
    3456             :                                  bool aIgnoreRootScrollFrame,
    3457           0 :                                  bool aFlushLayout,
    3458             :                                  nsINodeList** aReturn)
    3459             : {
    3460             :   NS_ENSURE_ARG_POINTER(aReturn);
    3461             : 
    3462             :   nsSimpleContentList* elements = new nsSimpleContentList(this);
    3463             :   NS_ADDREF(elements);
    3464           0 :   *aReturn = elements;
    3465             : 
    3466           0 :   // Following the same behavior of elementFromPoint,
    3467           0 :   // we don't return anything if either coord is negative
    3468           0 :   if (!aIgnoreRootScrollFrame && (aX < 0 || aY < 0))
    3469             :     return NS_OK;
    3470             : 
    3471             :   nscoord x = nsPresContext::CSSPixelsToAppUnits(aX - aLeftSize);
    3472           0 :   nscoord y = nsPresContext::CSSPixelsToAppUnits(aY - aTopSize);
    3473             :   nscoord w = nsPresContext::CSSPixelsToAppUnits(aLeftSize + aRightSize) + 1;
    3474             :   nscoord h = nsPresContext::CSSPixelsToAppUnits(aTopSize + aBottomSize) + 1;
    3475           0 : 
    3476           0 :   nsRect rect(x, y, w, h);
    3477           0 : 
    3478           0 :   // Make sure the layout information we get is up-to-date, and
    3479             :   // ensure we get a root frame (for everything but XUL)
    3480           0 :   if (aFlushLayout) {
    3481             :     FlushPendingNotifications(FlushType::Layout);
    3482             :   }
    3483             : 
    3484           0 :   nsIPresShell *ps = GetShell();
    3485           0 :   NS_ENSURE_STATE(ps);
    3486             :   nsIFrame *rootFrame = ps->GetRootFrame();
    3487             : 
    3488           0 :   // XUL docs, unlike HTML, have no frame tree until everything's done loading
    3489           0 :   if (!rootFrame)
    3490           0 :     return NS_OK; // return nothing to premature XUL callers as a reminder to wait
    3491             : 
    3492             :   AutoTArray<nsIFrame*,8> outFrames;
    3493           0 :   nsLayoutUtils::GetFramesForArea(rootFrame, rect, outFrames,
    3494             :     nsLayoutUtils::IGNORE_PAINT_SUPPRESSION | nsLayoutUtils::IGNORE_CROSS_DOC |
    3495             :     (aIgnoreRootScrollFrame ? nsLayoutUtils::IGNORE_ROOT_SCROLL_FRAME : 0));
    3496           0 : 
    3497           0 :   // Used to filter out repeated elements in sequence.
    3498             :   nsIContent* lastAdded = nullptr;
    3499           0 : 
    3500             :   for (uint32_t i = 0; i < outFrames.Length(); i++) {
    3501             :     nsIContent* node = GetContentInThisDocument(outFrames[i]);
    3502           0 : 
    3503             :     if (node && !node->IsElement() && !node->IsText()) {
    3504           0 :       // We have a node that isn't an element or a text node,
    3505           0 :       // use its parent content instead.
    3506             :       node = node->GetParent();
    3507           0 :     }
    3508             :     if (node && node != lastAdded) {
    3509             :       elements->AppendElement(node);
    3510           0 :       lastAdded = node;
    3511             :     }
    3512           0 :   }
    3513           0 : 
    3514           0 :   return NS_OK;
    3515             : }
    3516             : 
    3517             : void
    3518           0 : nsIDocument::ReleaseCapture() const
    3519             : {
    3520             :   // only release the capture if the caller can access it. This prevents a
    3521             :   // page from stopping a scrollbar grab for example.
    3522           0 :   nsCOMPtr<nsINode> node = nsIPresShell::GetCapturingContent();
    3523             :   if (node && nsContentUtils::CanCallerAccess(node)) {
    3524             :     nsIPresShell::SetCapturingContent(nullptr, 0);
    3525             :   }
    3526           0 : }
    3527           0 : 
    3528           0 : already_AddRefed<nsIURI>
    3529             : nsIDocument::GetBaseURI(bool aTryUseXHRDocBaseURI) const
    3530           0 : {
    3531             :   nsCOMPtr<nsIURI> uri;
    3532             :   if (aTryUseXHRDocBaseURI && mChromeXHRDocBaseURI) {
    3533           0 :     uri = mChromeXHRDocBaseURI;
    3534             :   } else {
    3535           0 :     uri = GetDocBaseURI();
    3536           0 :   }
    3537           0 : 
    3538             :   return uri.forget();
    3539          51 : }
    3540             : 
    3541             : void
    3542           0 : nsIDocument::SetBaseURI(nsIURI* aURI)
    3543             : {
    3544             :   if (!aURI && !mDocumentBaseURI) {
    3545             :     return;
    3546           0 :   }
    3547             : 
    3548           0 :   // Don't do anything if the URI wasn't actually changed.
    3549             :   if (aURI && mDocumentBaseURI) {
    3550             :     bool equalBases = false;
    3551             :     mDocumentBaseURI->Equals(aURI, &equalBases);
    3552             :     if (equalBases) {
    3553           2 :       return;
    3554           0 :     }
    3555           0 :   }
    3556           0 : 
    3557           0 :   mDocumentBaseURI = aURI;
    3558             :   RefreshLinkHrefs();
    3559             : }
    3560             : 
    3561           1 : URLExtraData*
    3562           0 : nsIDocument::DefaultStyleAttrURLData()
    3563             : {
    3564             :   MOZ_ASSERT(NS_IsMainThread());
    3565             :   nsIURI* baseURI = GetDocBaseURI();
    3566           1 :   nsIURI* docURI = GetDocumentURI();
    3567             :   nsIPrincipal* principal = NodePrincipal();
    3568           1 :   if (!mCachedURLData ||
    3569           1 :       mCachedURLData->BaseURI() != baseURI ||
    3570           0 :       mCachedURLData->GetReferrer() != docURI ||
    3571           0 :       mCachedURLData->GetPrincipal() != principal) {
    3572           0 :     mCachedURLData = new URLExtraData(baseURI, docURI, principal);
    3573           0 :   }
    3574           1 :   return mCachedURLData;
    3575           0 : }
    3576           0 : 
    3577             : void
    3578           2 : nsIDocument::SetDocumentCharacterSet(NotNull<const Encoding*> aEncoding)
    3579             : {
    3580             :   if (mCharacterSet != aEncoding) {
    3581             :     mCharacterSet = aEncoding;
    3582         120 :     mEncodingMenuDisabled = aEncoding == UTF_8_ENCODING;
    3583             : 
    3584           0 :     if (nsPresContext* context = GetPresContext()) {
    3585           0 :       context->DispatchCharSetChange(aEncoding);
    3586           0 :     }
    3587             :   }
    3588           0 : }
    3589           3 : 
    3590             : void
    3591             : nsIDocument::GetSandboxFlagsAsString(nsAString& aFlags)
    3592         120 : {
    3593             :   nsContentUtils::SandboxFlagsToString(mSandboxFlags, aFlags);
    3594             : }
    3595           0 : 
    3596             : void
    3597           0 : nsIDocument::GetHeaderData(nsAtom* aHeaderField, nsAString& aData) const
    3598           0 : {
    3599             :   aData.Truncate();
    3600             :   const nsDocHeaderData* data = mHeaderData;
    3601           0 :   while (data) {
    3602             :     if (data->mField == aHeaderField) {
    3603           0 :       aData = data->mData;
    3604           0 : 
    3605           0 :       break;
    3606           0 :     }
    3607           0 :     data = data->mNext;
    3608             :   }
    3609             : }
    3610             : 
    3611           0 : void
    3612             : nsIDocument::SetHeaderData(nsAtom* aHeaderField, const nsAString& aData)
    3613           0 : {
    3614             :   if (!aHeaderField) {
    3615             :     NS_ERROR("null headerField");
    3616           0 :     return;
    3617             :   }
    3618           0 : 
    3619           0 :   if (!mHeaderData) {
    3620             :     if (!aData.IsEmpty()) { // don't bother storing empty string
    3621             :       mHeaderData = new nsDocHeaderData(aHeaderField, aData);
    3622             :     }
    3623           0 :   }
    3624           0 :   else {
    3625           0 :     nsDocHeaderData* data = mHeaderData;
    3626             :     nsDocHeaderData** lastPtr = &mHeaderData;
    3627             :     bool found = false;
    3628             :     do {  // look for existing and replace
    3629           0 :       if (data->mField == aHeaderField) {
    3630           0 :         if (!aData.IsEmpty()) {
    3631           0 :           data->mData.Assign(aData);
    3632             :         }
    3633           0 :         else {  // don't store empty string
    3634           0 :           *lastPtr = data->mNext;
    3635           0 :           data->mNext = nullptr;
    3636             :           delete data;
    3637             :         }
    3638           0 :         found = true;
    3639           0 : 
    3640           0 :         break;
    3641             :       }
    3642             :       lastPtr = &(data->mNext);
    3643             :       data = *lastPtr;
    3644             :     } while (data);
    3645             : 
    3646           0 :     if (!aData.IsEmpty() && !found) {
    3647           0 :       // didn't find, append
    3648           0 :       *lastPtr = new nsDocHeaderData(aHeaderField, aData);
    3649             :     }
    3650           0 :   }
    3651             : 
    3652           0 :   if (aHeaderField == nsGkAtoms::headerContentLanguage) {
    3653             :     CopyUTF16toUTF8(aData, mContentLanguage);
    3654             :   }
    3655             : 
    3656           0 :   if (aHeaderField == nsGkAtoms::headerDefaultStyle) {
    3657           0 :     SetPreferredStyleSheetSet(aData);
    3658             :   }
    3659             : 
    3660           0 :   if (aHeaderField == nsGkAtoms::refresh) {
    3661           0 :     // We get into this code before we have a script global yet, so get to
    3662             :     // our container via mDocumentContainer.
    3663             :     nsCOMPtr<nsIRefreshURI> refresher(mDocumentContainer);
    3664           0 :     if (refresher) {
    3665             :       // Note: using mDocumentURI instead of mBaseURI here, for consistency
    3666             :       // (used to just use the current URI of our webnavigation, but that
    3667           0 :       // should really be the same thing).  Note that this code can run
    3668           0 :       // before the current URI of the webnavigation has been updated, so we
    3669             :       // can't assert equality here.
    3670             :       refresher->SetupRefreshURIFromHeader(mDocumentURI, NodePrincipal(),
    3671             :                                            NS_ConvertUTF16toUTF8(aData));
    3672             :     }
    3673             :   }
    3674           0 : 
    3675           0 :   if (aHeaderField == nsGkAtoms::headerDNSPrefetchControl &&
    3676             :       mAllowDNSPrefetch) {
    3677             :     // Chromium treats any value other than 'on' (case insensitive) as 'off'.
    3678             :     mAllowDNSPrefetch = aData.IsEmpty() || aData.LowerCaseEqualsLiteral("on");
    3679           0 :   }
    3680           0 : 
    3681             :   if (aHeaderField == nsGkAtoms::viewport ||
    3682           0 :       aHeaderField == nsGkAtoms::handheldFriendly ||
    3683             :       aHeaderField == nsGkAtoms::viewport_minimum_scale ||
    3684             :       aHeaderField == nsGkAtoms::viewport_maximum_scale ||
    3685           0 :       aHeaderField == nsGkAtoms::viewport_initial_scale ||
    3686           0 :       aHeaderField == nsGkAtoms::viewport_height ||
    3687           0 :       aHeaderField == nsGkAtoms::viewport_width ||
    3688           0 :       aHeaderField ==  nsGkAtoms::viewport_user_scalable) {
    3689           0 :     mViewportType = Unknown;
    3690           0 :     mViewportOverflowType = ViewportOverflowType::NoOverflow;
    3691           0 :   }
    3692           0 : 
    3693           0 :   // Referrer policy spec says to ignore any empty referrer policies.
    3694           0 :   if (aHeaderField == nsGkAtoms::referrer && !aData.IsEmpty()) {
    3695             :      enum mozilla::net::ReferrerPolicy policy = mozilla::net::ReferrerPolicyFromString(aData);
    3696             :     // If policy is not the empty string, then set element's node document's
    3697             :     // referrer policy to policy
    3698           0 :     if (policy != mozilla::net::RP_Unset) {
    3699           0 :       // Referrer policy spec (section 6.1) says that we always use the newest
    3700             :       // referrer policy we find
    3701             :       mReferrerPolicy = policy;
    3702           0 :       mReferrerPolicySet = true;
    3703             :     }
    3704             :   }
    3705           0 : 
    3706           0 :   if (aHeaderField == nsGkAtoms::headerReferrerPolicy && !aData.IsEmpty()) {
    3707             :      enum mozilla::net::ReferrerPolicy policy = nsContentUtils::GetReferrerPolicyFromHeader(aData);
    3708             :     if (policy != mozilla::net::RP_Unset) {
    3709             :       mReferrerPolicy = policy;
    3710           0 :       mReferrerPolicySet = true;
    3711           0 :     }
    3712           0 :   }
    3713           0 : 
    3714           0 : }
    3715             : void
    3716             : nsDocument::TryChannelCharset(nsIChannel *aChannel,
    3717             :                               int32_t& aCharsetSource,
    3718             :                               NotNull<const Encoding*>& aEncoding,
    3719             :                               nsHtml5TreeOpExecutor* aExecutor)
    3720          49 : {
    3721             :   if (aChannel) {
    3722             :     nsAutoCString charsetVal;
    3723             :     nsresult rv = aChannel->GetContentCharset(charsetVal);
    3724             :     if (NS_SUCCEEDED(rv)) {
    3725           0 :       const Encoding* preferred = Encoding::ForLabel(charsetVal);
    3726           0 :       if (preferred) {
    3727          49 :         aEncoding = WrapNotNull(preferred);
    3728          49 :         aCharsetSource = kCharsetFromChannel;
    3729          98 :         return;
    3730          49 :       } else if (aExecutor && !charsetVal.IsEmpty()) {
    3731          46 :         aExecutor->ComplainAboutBogusProtocolCharset(this);
    3732           0 :       }
    3733           0 :     }
    3734           3 :   }
    3735           0 : }
    3736             : 
    3737             : static inline void
    3738             : AssertNoStaleServoDataIn(const nsINode& aSubtreeRoot)
    3739             : {
    3740             : #ifdef DEBUG
    3741             :   for (const nsINode* node = &aSubtreeRoot;
    3742          35 :        node;
    3743             :        node = node->GetNextNode(&aSubtreeRoot)) {
    3744             :     const Element* element = Element::FromNode(node);
    3745           0 :     if (!element) {
    3746           0 :       continue;
    3747             :     }
    3748           0 :     MOZ_ASSERT(!element->HasServoData());
    3749           0 :     if (auto* shadow = element->GetShadowRoot()) {
    3750             :       AssertNoStaleServoDataIn(*shadow);
    3751             :     }
    3752          48 :     if (nsXBLBinding* binding = element->GetXBLBinding()) {
    3753          48 :       if (nsXBLBinding* bindingWithContent = binding->GetBindingWithContent()) {
    3754           0 :         nsIContent* content = bindingWithContent->GetAnonymousContent();
    3755             :         MOZ_ASSERT(!content->AsElement()->HasServoData());
    3756           0 :         for (nsINode* child = content->GetFirstChild();
    3757           0 :              child;
    3758           0 :              child = child->GetNextSibling()) {
    3759           0 :           AssertNoStaleServoDataIn(*child);
    3760           0 :         }
    3761           0 :       }
    3762             :     }
    3763           0 :   }
    3764             : #endif
    3765             : }
    3766             : 
    3767             : already_AddRefed<nsIPresShell>
    3768             : nsIDocument::CreateShell(nsPresContext* aContext,
    3769           0 :                          nsViewManager* aViewManager,
    3770             :                          UniquePtr<ServoStyleSet> aStyleSet)
    3771             : {
    3772          27 :   NS_ASSERTION(!mPresShell, "We have a presshell already!");
    3773             : 
    3774             :   NS_ENSURE_FALSE(GetBFCacheEntry(), nullptr);
    3775             : 
    3776          27 :   FillStyleSet(aStyleSet.get());
    3777             :   AssertNoStaleServoDataIn(static_cast<nsINode&>(*this));
    3778          27 : 
    3779             :   RefPtr<PresShell> shell = new PresShell;
    3780          27 :   // Note: we don't hold a ref to the shell (it holds a ref to us)
    3781          27 :   mPresShell = shell;
    3782             :   shell->Init(this, aContext, aViewManager, std::move(aStyleSet));
    3783           0 : 
    3784             :   // Make sure to never paint if we belong to an invisible DocShell.
    3785           0 :   nsCOMPtr<nsIDocShell> docShell(mDocumentContainer);
    3786           0 :   if (docShell && docShell->IsInvisible())
    3787             :     shell->SetNeverPainting(true);
    3788             : 
    3789           0 :   MOZ_LOG(gDocumentLeakPRLog, LogLevel::Debug, ("DOCUMENT %p with PressShell %p and DocShell %p",
    3790           0 :                                                 this, shell.get(), docShell.get()));
    3791           0 : 
    3792             :   mExternalResourceMap.ShowViewers();
    3793          27 : 
    3794             :   UpdateFrameRequestCallbackSchedulingState();
    3795             : 
    3796          27 :   // Now that we have a shell, we might have @font-face rules (the presence of a
    3797             :   // shell may change which rules apply to us). We don't need to do anything
    3798          27 :   // like EnsureStyleFlush or such, there's nothing to update yet and when stuff
    3799             :   // is ready to update we'll flush the font set.
    3800             :   MarkUserFontSetDirty();
    3801             : 
    3802             :   return shell.forget();
    3803             : }
    3804          27 : 
    3805             : void
    3806           0 : nsIDocument::UpdateFrameRequestCallbackSchedulingState(nsIPresShell* aOldShell)
    3807             : {
    3808             :   // If the condition for shouldBeScheduled changes to depend on some other
    3809             :   // variable, add UpdateFrameRequestCallbackSchedulingState() calls to the
    3810           0 :   // places where that variable can change.
    3811             :   bool shouldBeScheduled =
    3812             :     mPresShell && IsEventHandlingEnabled() && !mFrameRequestCallbacks.IsEmpty();
    3813             :   if (shouldBeScheduled == mFrameRequestCallbacksScheduled) {
    3814             :     // nothing to do
    3815             :     return;
    3816           0 :   }
    3817           0 : 
    3818             :   nsIPresShell* presShell = aOldShell ? aOldShell : mPresShell;
    3819             :   MOZ_RELEASE_ASSERT(presShell);
    3820             : 
    3821             :   nsRefreshDriver* rd = presShell->GetPresContext()->RefreshDriver();
    3822           2 :   if (shouldBeScheduled) {
    3823           2 :     rd->ScheduleFrameRequestCallbacks(this);
    3824             :   } else {
    3825           6 :     rd->RevokeFrameRequestCallbacks(this);
    3826           0 :   }
    3827           2 : 
    3828             :   mFrameRequestCallbacksScheduled = shouldBeScheduled;
    3829           0 : }
    3830             : 
    3831             : void
    3832           2 : nsIDocument::TakeFrameRequestCallbacks(FrameRequestCallbackList& aCallbacks)
    3833             : {
    3834             :   aCallbacks.AppendElements(mFrameRequestCallbacks);
    3835             :   mFrameRequestCallbacks.Clear();
    3836           2 :   // No need to manually remove ourselves from the refresh driver; it will
    3837             :   // handle that part.  But we do have to update our state.
    3838           0 :   mFrameRequestCallbacksScheduled = false;
    3839           2 : }
    3840             : 
    3841             : bool
    3842           0 : nsIDocument::ShouldThrottleFrameRequests()
    3843           0 : {
    3844             :   if (mStaticCloneCount > 0) {
    3845             :     // Even if we're not visible, a static clone may be, so run at full speed.
    3846           0 :     return false;
    3847             :   }
    3848           0 : 
    3849             :   if (Hidden()) {
    3850             :     // We're not visible (probably in a background tab or the bf cache).
    3851             :     return true;
    3852             :   }
    3853           0 : 
    3854             :   if (!mPresShell) {
    3855             :     return false;  // Can't do anything smarter.
    3856             :   }
    3857             : 
    3858          14 :   nsIFrame* frame = mPresShell->GetRootFrame();
    3859             :   if (!frame) {
    3860             :     return false;  // Can't do anything smarter.
    3861             :   }
    3862          28 : 
    3863           0 :   nsIFrame* displayRootFrame = nsLayoutUtils::GetDisplayRootFrame(frame);
    3864             :   if (!displayRootFrame) {
    3865             :     return false;  // Can't do anything smarter.
    3866             :   }
    3867           0 : 
    3868          14 :   if (!displayRootFrame->DidPaintPresShell(mPresShell)) {
    3869             :     // We didn't get painted during the last paint, so we're not visible.
    3870             :     // Throttle. Note that because we have to paint this document at least
    3871             :     // once to unthrottle it, we will drop one requestAnimationFrame frame
    3872          14 :     // when a document that previously wasn't visible scrolls into view. This
    3873             :     // is acceptable since it would happen outside the viewport on APZ
    3874             :     // platforms and is unlikely to be human-perceivable on non-APZ platforms.
    3875             :     return true;
    3876             :   }
    3877             : 
    3878             :   // We got painted during the last paint, so run at full speed.
    3879             :   return false;
    3880             : }
    3881             : 
    3882             : void
    3883           0 : nsIDocument::DeleteShell()
    3884             : {
    3885             :   mExternalResourceMap.HideViewers();
    3886             :   if (nsPresContext* presContext = mPresShell->GetPresContext()) {
    3887           8 :     presContext->RefreshDriver()->CancelPendingEvents(this);
    3888             :   }
    3889           0 : 
    3890          16 :   // When our shell goes away, request that all our images be immediately
    3891           8 :   // discarded, so we don't carry around decoded image data for a document we
    3892             :   // no longer intend to paint.
    3893             :   ImageTracker()->RequestDiscardAll();
    3894             : 
    3895             :   // Now that we no longer have a shell, we need to forget about any FontFace
    3896             :   // objects for @font-face rules that came from the style set. There's no need
    3897           8 :   // to call EnsureStyleFlush either, the shell is going away anyway, so there's
    3898             :   // no point on it.
    3899             :   MarkUserFontSetDirty();
    3900             : 
    3901             :   nsIPresShell* oldShell = mPresShell;
    3902             :   mPresShell = nullptr;
    3903           0 :   UpdateFrameRequestCallbackSchedulingState(oldShell);
    3904             :   mStyleSetFilled = false;
    3905           0 : 
    3906           8 :   ClearStaleServoData();
    3907           8 :   AssertNoStaleServoDataIn(static_cast<nsINode&>(*this));
    3908           8 : }
    3909             : 
    3910           0 : void
    3911           8 : nsIDocument::SetBFCacheEntry(nsIBFCacheEntry* aEntry)
    3912           8 : {
    3913             :   MOZ_ASSERT(IsBFCachingAllowed() || !aEntry, "You should have checked!");
    3914             : 
    3915           0 :   if (mPresShell) {
    3916             :     if (aEntry) {
    3917           0 :       mPresShell->StopObservingRefreshDriver();
    3918             :     } else if (mBFCacheEntry) {
    3919           0 :       mPresShell->StartObservingRefreshDriver();
    3920           0 :     }
    3921           0 :   }
    3922           0 :   mBFCacheEntry = aEntry;
    3923           0 : }
    3924             : 
    3925             : static void
    3926           0 : SubDocClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
    3927           0 : {
    3928             :   SubDocMapEntry *e = static_cast<SubDocMapEntry *>(entry);
    3929             : 
    3930           1 :   NS_RELEASE(e->mKey);
    3931             :   if (e->mSubDocument) {
    3932           1 :     e->mSubDocument->SetParentDocument(nullptr);
    3933             :     NS_RELEASE(e->mSubDocument);
    3934           1 :   }
    3935           1 : }
    3936           2 : 
    3937           1 : static void
    3938             : SubDocInitEntry(PLDHashEntryHdr *entry, const void *key)
    3939           1 : {
    3940             :   SubDocMapEntry *e =
    3941             :     const_cast<SubDocMapEntry *>
    3942           4 :               (static_cast<const SubDocMapEntry *>(entry));
    3943             : 
    3944             :   e->mKey = const_cast<Element*>(static_cast<const Element*>(key));
    3945             :   NS_ADDREF(e->mKey);
    3946           0 : 
    3947             :   e->mSubDocument = nullptr;
    3948           0 : }
    3949           4 : 
    3950             : nsresult
    3951           4 : nsIDocument::SetSubDocumentFor(Element* aElement, nsIDocument* aSubDoc)
    3952           4 : {
    3953             :   NS_ENSURE_TRUE(aElement, NS_ERROR_UNEXPECTED);
    3954             : 
    3955           7 :   if (!aSubDoc) {
    3956             :     // aSubDoc is nullptr, remove the mapping
    3957           7 : 
    3958             :     if (mSubDocuments) {
    3959           7 :       nsIDocument* subDoc = GetSubDocumentFor(aElement);
    3960             :       if (subDoc) {
    3961             :         subDoc->SetAllowPaymentRequest(false);
    3962           0 :       }
    3963           0 :       mSubDocuments->Remove(aElement);
    3964           0 :     }
    3965             :   } else {
    3966             :     if (!mSubDocuments) {
    3967           0 :       // Create a new hashtable
    3968             : 
    3969             :       static const PLDHashTableOps hash_table_ops =
    3970           6 :       {
    3971             :         PLDHashTable::HashVoidPtrKeyStub,
    3972             :         PLDHashTable::MatchEntryStub,
    3973             :         PLDHashTable::MoveEntryStub,
    3974             :         SubDocClearEntry,
    3975             :         SubDocInitEntry
    3976             :       };
    3977             : 
    3978             :       mSubDocuments = new PLDHashTable(&hash_table_ops, sizeof(SubDocMapEntry));
    3979             :     }
    3980             : 
    3981             :     // Add a mapping to the hash table
    3982           3 :     auto entry =
    3983             :       static_cast<SubDocMapEntry*>(mSubDocuments->Add(aElement, fallible));
    3984             : 
    3985             :     if (!entry) {
    3986             :       return NS_ERROR_OUT_OF_MEMORY;
    3987           0 :     }
    3988             : 
    3989           0 :     if (entry->mSubDocument) {
    3990             :       entry->mSubDocument->SetAllowPaymentRequest(false);
    3991             :       entry->mSubDocument->SetParentDocument(nullptr);
    3992             : 
    3993           0 :       // Release the old sub document
    3994           0 :       NS_RELEASE(entry->mSubDocument);
    3995           4 :     }
    3996             : 
    3997             :     entry->mSubDocument = aSubDoc;
    3998           2 :     NS_ADDREF(entry->mSubDocument);
    3999             : 
    4000             :     // set allowpaymentrequest for the binding subdocument
    4001           6 :     if (!mAllowPaymentRequest) {
    4002           6 :       aSubDoc->SetAllowPaymentRequest(false);
    4003             :     } else {
    4004             :       nsresult rv = nsContentUtils::CheckSameOrigin(aElement, aSubDoc);
    4005           0 :       if (NS_SUCCEEDED(rv)) {
    4006             :         aSubDoc->SetAllowPaymentRequest(true);
    4007             :       } else {
    4008           0 :         if (aElement->IsHTMLElement(nsGkAtoms::iframe) &&
    4009           0 :             aElement->GetBoolAttr(nsGkAtoms::allowpaymentrequest)) {
    4010             :           aSubDoc->SetAllowPaymentRequest(true);
    4011             :         } else {
    4012           0 :           aSubDoc->SetAllowPaymentRequest(false);
    4013           0 :         }
    4014             :       }
    4015             :     }
    4016             : 
    4017             :     aSubDoc->SetParentDocument(this);
    4018             :   }
    4019             : 
    4020             :   return NS_OK;
    4021           0 : }
    4022             : 
    4023             : nsIDocument*
    4024             : nsIDocument::GetSubDocumentFor(nsIContent *aContent) const
    4025             : {
    4026             :   if (mSubDocuments && aContent->IsElement()) {
    4027             :     auto entry = static_cast<SubDocMapEntry*>
    4028          30 :                             (mSubDocuments->Search(aContent->AsElement()));
    4029             : 
    4030          57 :     if (entry) {
    4031             :       return entry->mSubDocument;
    4032          27 :     }
    4033             :   }
    4034          27 : 
    4035           3 :   return nullptr;
    4036             : }
    4037             : 
    4038             : Element*
    4039             : nsIDocument::FindContentForSubDocument(nsIDocument *aDocument) const
    4040             : {
    4041             :   NS_ENSURE_TRUE(aDocument, nullptr);
    4042             : 
    4043           3 :   if (!mSubDocuments) {
    4044             :     return nullptr;
    4045           3 :   }
    4046             : 
    4047           3 :   for (auto iter = mSubDocuments->Iter(); !iter.Done(); iter.Next()) {
    4048             :     auto entry = static_cast<SubDocMapEntry*>(iter.Get());
    4049             :     if (entry->mSubDocument == aDocument) {
    4050             :       return entry->mKey;
    4051           0 :     }
    4052           0 :   }
    4053           3 :   return nullptr;
    4054           3 : }
    4055             : 
    4056             : bool
    4057           0 : nsIDocument::IsNodeOfType(uint32_t aFlags) const
    4058             : {
    4059             :   return false;
    4060             : }
    4061           0 : 
    4062             : Element*
    4063           0 : nsIDocument::GetRootElement() const
    4064             : {
    4065             :   return (mCachedRootElement && mCachedRootElement->GetParentNode() == this) ?
    4066             :          mCachedRootElement : GetRootElementInternal();
    4067       11164 : }
    4068             : 
    4069           0 : nsIContent*
    4070           0 : nsIDocument::GetUnfocusedKeyEventTarget()
    4071             : {
    4072             :   return GetRootElement();
    4073             : }
    4074           0 : 
    4075             : Element*
    4076           0 : nsIDocument::GetRootElementInternal() const
    4077             : {
    4078             :   // We invoke GetRootElement() immediately before the servo traversal, so we
    4079             :   // should always have a cache hit from Servo.
    4080         172 :   MOZ_ASSERT(NS_IsMainThread());
    4081             : 
    4082             :   // Loop backwards because any non-elements, such as doctypes and PIs
    4083             :   // are likely to appear before the root element.
    4084         172 :   for (nsIContent* child = GetLastChild(); child;
    4085             :        child = child->GetPreviousSibling()) {
    4086             :     if (Element* element = Element::FromNode(child)) {
    4087             :       const_cast<nsIDocument*>(this)->mCachedRootElement = element;
    4088             :       return element;
    4089           0 :     }
    4090         522 :   }
    4091           0 : 
    4092           0 :   const_cast<nsIDocument*>(this)->mCachedRootElement = nullptr;
    4093             :   return nullptr;
    4094             : }
    4095             : 
    4096         112 : nsresult
    4097         112 : nsIDocument::InsertChildBefore(nsIContent* aKid,
    4098             :                                nsIContent* aBeforeThis,
    4099             :                                bool aNotify)
    4100             : {
    4101          13 :   if (aKid->IsElement() && GetRootElement()) {
    4102             :     NS_WARNING("Inserting root element when we already have one");
    4103             :     return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
    4104             :   }
    4105          26 : 
    4106           0 :   int32_t index = aBeforeThis ? ComputeIndexOf(aBeforeThis) : GetChildCount();
    4107           0 :   MOZ_ASSERT(index >= 0);
    4108             : 
    4109             :   return doInsertChildAt(aKid, index, aNotify, mChildren);
    4110           0 : }
    4111           0 : 
    4112             : nsresult
    4113          13 : nsIDocument::InsertChildAt_Deprecated(nsIContent* aKid,
    4114             :                                       uint32_t aIndex,
    4115             :                                       bool aNotify)
    4116             : {
    4117         118 :   if (aKid->IsElement() && GetRootElement()) {
    4118             :     NS_WARNING("Inserting root element when we already have one");
    4119             :     return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
    4120             :   }
    4121         236 : 
    4122           0 :   return doInsertChildAt(aKid, aIndex, aNotify, mChildren);
    4123           0 : }
    4124             : 
    4125             : void
    4126           0 : nsIDocument::RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify)
    4127             : {
    4128             :   nsCOMPtr<nsIContent> oldKid = GetChildAt_Deprecated(aIndex);
    4129             :   if (!oldKid) {
    4130           0 :     return;
    4131             :   }
    4132           0 : 
    4133           0 :   if (oldKid->IsElement()) {
    4134           0 :     // Destroy the link map up front before we mess with the child list.
    4135             :     DestroyElementMaps();
    4136             :   }
    4137           0 : 
    4138             :   // Preemptively clear mCachedRootElement, since we may be about to remove it
    4139           0 :   // from our child list, and we don't want to return this maybe-obsolete value
    4140             :   // from any GetRootElement() calls that happen inside of doRemoveChildAt().
    4141             :   // (NOTE: for this to be useful, doRemoveChildAt() must NOT trigger any
    4142             :   // GetRootElement() calls until after it's removed the child from mChildren.
    4143             :   // Any call before that point would restore this soon-to-be-obsolete cached
    4144             :   // answer, and our clearing here would be fruitless.)
    4145             :   mCachedRootElement = nullptr;
    4146             :   doRemoveChildAt(aIndex, aNotify, oldKid, mChildren);
    4147             :   MOZ_ASSERT(mCachedRootElement != oldKid,
    4148             :              "Stale pointer in mCachedRootElement, after we tried to clear it "
    4149           0 :              "(maybe somebody called GetRootElement() too early?)");
    4150           0 : }
    4151           0 : 
    4152             : void
    4153             : nsIDocument::RemoveChildNode(nsIContent* aKid, bool aNotify)
    4154             : {
    4155             :   if (aKid->IsElement()) {
    4156             :     // Destroy the link map up front before we mess with the child list.
    4157           0 :     DestroyElementMaps();
    4158             :   }
    4159           0 : 
    4160             :   // Preemptively clear mCachedRootElement, since we may be about to remove it
    4161           0 :   // from our child list, and we don't want to return this maybe-obsolete value
    4162             :   // from any GetRootElement() calls that happen inside of doRemoveChildAt().
    4163             :   // (NOTE: for this to be useful, doRemoveChildAt() must NOT trigger any
    4164             :   // GetRootElement() calls until after it's removed the child from mChildren.
    4165             :   // Any call before that point would restore this soon-to-be-obsolete cached
    4166             :   // answer, and our clearing here would be fruitless.)
    4167             :   mCachedRootElement = nullptr;
    4168             :   doRemoveChildAt(ComputeIndexOf(aKid), aNotify, aKid, mChildren);
    4169             :   MOZ_ASSERT(mCachedRootElement != aKid,
    4170             :              "Stale pointer in mCachedRootElement, after we tried to clear it "
    4171           0 :              "(maybe somebody called GetRootElement() too early?)");
    4172           0 : }
    4173           0 : 
    4174             : void
    4175             : nsIDocument::EnsureOnDemandBuiltInUASheet(StyleSheet* aSheet)
    4176           0 : {
    4177             :   if (mOnDemandBuiltInUASheets.Contains(aSheet)) {
    4178             :     return;
    4179           1 :   }
    4180             :   AddOnDemandBuiltInUASheet(aSheet);
    4181          13 : }
    4182             : 
    4183             : void
    4184          13 : nsIDocument::AddOnDemandBuiltInUASheet(StyleSheet* aSheet)
    4185             : {
    4186             :   MOZ_ASSERT(!mOnDemandBuiltInUASheets.Contains(aSheet));
    4187             : 
    4188          13 :   // Prepend here so that we store the sheets in mOnDemandBuiltInUASheets in
    4189             :   // the same order that they should end up in the style set.
    4190           0 :   mOnDemandBuiltInUASheets.InsertElementAt(0, aSheet);
    4191             : 
    4192             :   if (aSheet->IsApplicable()) {
    4193             :     // This is like |AddStyleSheetToStyleSets|, but for an agent sheet.
    4194           0 :     if (nsIPresShell* shell = GetShell()) {
    4195             :       // Note that prepending here is necessary to make sure that html.css etc.
    4196           0 :       // does not override Firefox OS/Mobile's content.css sheet.
    4197             :       //
    4198          13 :       // Maybe we should have an insertion point to match the order of
    4199             :       // nsDocumentViewer::CreateStyleSet though?
    4200             :       //
    4201             :       // FIXME(emilio): We probably should, randomly prepending stuff here is
    4202             :       // very prone to subtle bugs, behavior differences...
    4203          26 :       shell->StyleSet()->PrependStyleSheet(SheetType::Agent, aSheet);
    4204          13 :       shell->ApplicableStylesChanged();
    4205             :     }
    4206             :   }
    4207             : 
    4208           0 :   NotifyStyleSheetAdded(aSheet, false);
    4209          13 : }
    4210             : 
    4211             : void
    4212          12 : nsIDocument::AddStyleSheetToStyleSets(StyleSheet* aSheet)
    4213             : {
    4214           0 :   if (nsIPresShell* shell = GetShell()) {
    4215          12 :     shell->StyleSet()->AddDocStyleSheet(aSheet, this);
    4216           0 :     shell->ApplicableStylesChanged();
    4217             :   }
    4218           0 : }
    4219             : 
    4220             : #define DO_STYLESHEET_NOTIFICATION(className, type, memberName, argName)      \
    4221             :   do {                                                                        \
    4222             :     className##Init init;                                                     \
    4223             :     init.mBubbles = true;                                                     \
    4224             :     init.mCancelable = true;                                                  \
    4225             :     init.mStylesheet = aSheet;                                                \
    4226             :     init.memberName = argName;                                                \
    4227             :                                                                               \
    4228             :     RefPtr<className> event =                                               \
    4229             :       className::Constructor(this, NS_LITERAL_STRING(type), init);            \
    4230             :     event->SetTrusted(true);                                                  \
    4231             :     event->SetTarget(this);                                                   \
    4232             :     RefPtr<AsyncEventDispatcher> asyncDispatcher =                          \
    4233             :       new AsyncEventDispatcher(this, event);                                  \
    4234             :     asyncDispatcher->mOnlyChromeDispatch = true;                              \
    4235             :     asyncDispatcher->PostDOMEvent();                                          \
    4236             :   } while (0);
    4237             : 
    4238             : void
    4239          27 : nsIDocument::NotifyStyleSheetAdded(StyleSheet* aSheet, bool aDocumentSheet)
    4240             : {
    4241           0 :   if (StyleSheetChangeEventsEnabled()) {
    4242           0 :     DO_STYLESHEET_NOTIFICATION(StyleSheetChangeEvent,
    4243             :                                "StyleSheetAdded",
    4244             :                                mDocumentSheet,
    4245             :                                aDocumentSheet);
    4246             :   }
    4247           0 : }
    4248             : 
    4249             : void
    4250           0 : nsIDocument::NotifyStyleSheetRemoved(StyleSheet* aSheet, bool aDocumentSheet)
    4251             : {
    4252           0 :   if (StyleSheetChangeEventsEnabled()) {
    4253           0 :     DO_STYLESHEET_NOTIFICATION(StyleSheetChangeEvent,
    4254             :                                "StyleSheetRemoved",
    4255             :                                mDocumentSheet,
    4256             :                                aDocumentSheet);
    4257             :   }
    4258           0 : }
    4259             : 
    4260             : void
    4261           0 : nsIDocument::AddStyleSheet(StyleSheet* aSheet)
    4262             : {
    4263           0 :   MOZ_ASSERT(aSheet);
    4264           0 :   DocumentOrShadowRoot::AppendSheet(*aSheet);
    4265             : 
    4266           0 :   if (aSheet->IsApplicable()) {
    4267           0 :     AddStyleSheetToStyleSets(aSheet);
    4268             :   }
    4269             : 
    4270           0 :   NotifyStyleSheetAdded(aSheet, true);
    4271           0 : }
    4272             : 
    4273             : void
    4274           0 : nsIDocument::RemoveStyleSheetFromStyleSets(StyleSheet* aSheet)
    4275             : {
    4276           0 :   if (nsIPresShell* shell = GetShell()) {
    4277           0 :     shell->StyleSet()->RemoveDocStyleSheet(aSheet);
    4278           0 :     shell->ApplicableStylesChanged();
    4279             :   }
    4280           0 : }
    4281             : 
    4282             : void
    4283           0 : nsIDocument::RemoveStyleSheet(StyleSheet* aSheet)
    4284             : {
    4285           0 :   MOZ_ASSERT(aSheet);
    4286           0 :   RefPtr<StyleSheet> sheet = DocumentOrShadowRoot::RemoveSheet(*aSheet);
    4287             : 
    4288           0 :   if (!sheet) {
    4289           0 :     NS_ASSERTION(mInUnlinkOrDeletion, "stylesheet not found");
    4290           0 :     return;
    4291             :   }
    4292             : 
    4293           0 :   if (!mIsGoingAway) {
    4294           0 :     if (sheet->IsApplicable()) {
    4295           0 :       RemoveStyleSheetFromStyleSets(sheet);
    4296             :     }
    4297             : 
    4298           0 :     NotifyStyleSheetRemoved(sheet, true);
    4299             :   }
    4300             : 
    4301           0 :   sheet->ClearAssociatedDocumentOrShadowRoot();
    4302             : }
    4303             : 
    4304             : void
    4305           0 : nsIDocument::UpdateStyleSheets(nsTArray<RefPtr<StyleSheet>>& aOldSheets,
    4306             :                                nsTArray<RefPtr<StyleSheet>>& aNewSheets)
    4307             : {
    4308             :   // XXX Need to set the sheet on the ownernode, if any
    4309           0 :   MOZ_ASSERT(aOldSheets.Length() == aNewSheets.Length(),
    4310             :              "The lists must be the same length!");
    4311           0 :   int32_t count = aOldSheets.Length();
    4312             : 
    4313           0 :   RefPtr<StyleSheet> oldSheet;
    4314             :   int32_t i;
    4315           0 :   for (i = 0; i < count; ++i) {
    4316           0 :     oldSheet = aOldSheets[i];
    4317             : 
    4318             :     // First remove the old sheet.
    4319           0 :     NS_ASSERTION(oldSheet, "None of the old sheets should be null");
    4320           0 :     int32_t oldIndex = mStyleSheets.IndexOf(oldSheet);
    4321           0 :     RemoveStyleSheet(oldSheet);  // This does the right notifications
    4322             : 
    4323             :     // Now put the new one in its place.  If it's null, just ignore it.
    4324           0 :     StyleSheet* newSheet = aNewSheets[i];
    4325           0 :     if (newSheet) {
    4326           0 :       DocumentOrShadowRoot::InsertSheetAt(oldIndex, *newSheet);
    4327           0 :       if (newSheet->IsApplicable()) {
    4328           0 :         AddStyleSheetToStyleSets(newSheet);
    4329             :       }
    4330             : 
    4331           0 :       NotifyStyleSheetAdded(newSheet, true);
    4332             :     }
    4333             :   }
    4334           0 : }
    4335             : 
    4336             : void
    4337           0 : nsIDocument::InsertStyleSheetAt(StyleSheet* aSheet, size_t aIndex)
    4338             : {
    4339          13 :   MOZ_ASSERT(aSheet);
    4340             : 
    4341          13 :   DocumentOrShadowRoot::InsertSheetAt(aIndex, *aSheet);
    4342             : 
    4343           0 :   if (aSheet->IsApplicable()) {
    4344           0 :     AddStyleSheetToStyleSets(aSheet);
    4345             :   }
    4346             : 
    4347           1 :   NotifyStyleSheetAdded(aSheet, true);
    4348          13 : }
    4349             : 
    4350             : 
    4351             : void
    4352           0 : nsIDocument::SetStyleSheetApplicableState(StyleSheet* aSheet, bool aApplicable)
    4353             : {
    4354          14 :   MOZ_ASSERT(aSheet, "null arg");
    4355             : 
    4356             :   // If we're actually in the document style sheet list
    4357          28 :   if (mStyleSheets.IndexOf(aSheet) != mStyleSheets.NoIndex) {
    4358           0 :     if (aApplicable) {
    4359          12 :       AddStyleSheetToStyleSets(aSheet);
    4360             :     } else {
    4361           0 :       RemoveStyleSheetFromStyleSets(aSheet);
    4362             :     }
    4363             :   }
    4364             : 
    4365          14 :   if (StyleSheetChangeEventsEnabled()) {
    4366           0 :     DO_STYLESHEET_NOTIFICATION(StyleSheetApplicableStateChangeEvent,
    4367             :                                "StyleSheetApplicableStateChanged",
    4368             :                                mApplicable,
    4369             :                                aApplicable);
    4370             :   }
    4371             : 
    4372           0 :   if (!mSSApplicableStateNotificationPending) {
    4373           1 :     MOZ_RELEASE_ASSERT(NS_IsMainThread());
    4374             :     nsCOMPtr<nsIRunnable> notification =
    4375           4 :       NewRunnableMethod("nsIDocument::NotifyStyleSheetApplicableStateChanged",
    4376             :                         this,
    4377           1 :                         &nsIDocument::NotifyStyleSheetApplicableStateChanged);
    4378           1 :     mSSApplicableStateNotificationPending =
    4379           4 :       NS_SUCCEEDED(
    4380             :         Dispatch(TaskCategory::Other, notification.forget()));
    4381             :   }
    4382           1 : }
    4383             : 
    4384             : void
    4385           1 : nsIDocument::NotifyStyleSheetApplicableStateChanged()
    4386             : {
    4387           2 :   mSSApplicableStateNotificationPending = false;
    4388             :   nsCOMPtr<nsIObserverService> observerService =
    4389           4 :     mozilla::services::GetObserverService();
    4390           2 :   if (observerService) {
    4391           0 :     observerService->NotifyObservers(this,
    4392             :                                      "style-sheet-applicable-state-changed",
    4393           4 :                                      nullptr);
    4394             :   }
    4395           2 : }
    4396             : 
    4397             : static SheetType
    4398           0 : ConvertAdditionalSheetType(nsIDocument::additionalSheetType aType)
    4399             : {
    4400           0 :   switch(aType) {
    4401             :     case nsIDocument::eAgentSheet:
    4402             :       return SheetType::Agent;
    4403             :     case nsIDocument::eUserSheet:
    4404           0 :       return SheetType::User;
    4405             :     case nsIDocument::eAuthorSheet:
    4406           1 :       return SheetType::Doc;
    4407             :     default:
    4408           0 :       MOZ_ASSERT(false, "wrong type");
    4409             :       // we must return something although this should never happen
    4410             :       return SheetType::Count;
    4411             :   }
    4412             : }
    4413             : 
    4414             : static int32_t
    4415           0 : FindSheet(const nsTArray<RefPtr<StyleSheet>>& aSheets, nsIURI* aSheetURI)
    4416             : {
    4417           0 :   for (int32_t i = aSheets.Length() - 1; i >= 0; i-- ) {
    4418             :     bool bEqual;
    4419           0 :     nsIURI* uri = aSheets[i]->GetSheetURI();
    4420             : 
    4421           0 :     if (uri && NS_SUCCEEDED(uri->Equals(aSheetURI, &bEqual)) && bEqual)
    4422           0 :       return i;
    4423             :   }
    4424             : 
    4425             :   return -1;
    4426             : }
    4427             : 
    4428             : nsresult
    4429           0 : nsIDocument::LoadAdditionalStyleSheet(additionalSheetType aType,
    4430             :                                       nsIURI* aSheetURI)
    4431             : {
    4432           0 :   MOZ_ASSERT(aSheetURI, "null arg");
    4433             : 
    4434             :   // Checking if we have loaded this one already.
    4435           0 :   if (FindSheet(mAdditionalSheets[aType], aSheetURI) >= 0)
    4436             :     return NS_ERROR_INVALID_ARG;
    4437             : 
    4438             :   // Loading the sheet sync.
    4439           0 :   RefPtr<css::Loader> loader = new css::Loader(GetDocGroup());
    4440             : 
    4441             :   css::SheetParsingMode parsingMode;
    4442           0 :   switch (aType) {
    4443             :     case nsIDocument::eAgentSheet:
    4444             :       parsingMode = css::eAgentSheetFeatures;
    4445             :       break;
    4446             : 
    4447             :     case nsIDocument::eUserSheet:
    4448           0 :       parsingMode = css::eUserSheetFeatures;
    4449           0 :       break;
    4450             : 
    4451             :     case nsIDocument::eAuthorSheet:
    4452           0 :       parsingMode = css::eAuthorSheetFeatures;
    4453           0 :       break;
    4454             : 
    4455             :     default:
    4456           0 :       MOZ_CRASH("impossible value for aType");
    4457             :   }
    4458             : 
    4459           0 :   RefPtr<StyleSheet> sheet;
    4460           0 :   nsresult rv = loader->LoadSheetSync(aSheetURI, parsingMode, true, &sheet);
    4461           0 :   NS_ENSURE_SUCCESS(rv, rv);
    4462             : 
    4463           0 :   sheet->SetAssociatedDocumentOrShadowRoot(
    4464           0 :      this, StyleSheet::OwnedByDocumentOrShadowRoot);
    4465           0 :   MOZ_ASSERT(sheet->IsApplicable());
    4466             : 
    4467           0 :   return AddAdditionalStyleSheet(aType, sheet);
    4468             : }
    4469             : 
    4470             : nsresult
    4471           1 : nsIDocument::AddAdditionalStyleSheet(additionalSheetType aType, StyleSheet* aSheet)
    4472             : {
    4473           1 :   if (mAdditionalSheets[aType].Contains(aSheet))
    4474             :     return NS_ERROR_INVALID_ARG;
    4475             : 
    4476           0 :   if (!aSheet->IsApplicable())
    4477             :     return NS_ERROR_INVALID_ARG;
    4478             : 
    4479           0 :   mAdditionalSheets[aType].AppendElement(aSheet);
    4480             : 
    4481           1 :   if (nsIPresShell* shell = GetShell()) {
    4482           1 :     SheetType type = ConvertAdditionalSheetType(aType);
    4483           2 :     shell->StyleSet()->AppendStyleSheet(type, aSheet);
    4484           1 :     shell->ApplicableStylesChanged();
    4485             :   }
    4486             : 
    4487             :   // Passing false, so documet.styleSheets.length will not be affected by
    4488             :   // these additional sheets.
    4489           0 :   NotifyStyleSheetAdded(aSheet, false);
    4490           1 :   return NS_OK;
    4491             : }
    4492             : 
    4493             : void
    4494           0 : nsIDocument::RemoveAdditionalStyleSheet(additionalSheetType aType, nsIURI* aSheetURI)
    4495             : {
    4496           0 :   MOZ_ASSERT(aSheetURI);
    4497             : 
    4498           0 :   nsTArray<RefPtr<StyleSheet>>& sheets = mAdditionalSheets[aType];
    4499             : 
    4500           0 :   int32_t i = FindSheet(mAdditionalSheets[aType], aSheetURI);
    4501           0 :   if (i >= 0) {
    4502           0 :     RefPtr<StyleSheet> sheetRef = sheets[i];
    4503           0 :     sheets.RemoveElementAt(i);
    4504             : 
    4505           0 :     if (!mIsGoingAway) {
    4506           0 :       MOZ_ASSERT(sheetRef->IsApplicable());
    4507           0 :       if (nsIPresShell* shell = GetShell()) {
    4508           0 :         SheetType type = ConvertAdditionalSheetType(aType);
    4509           0 :         shell->StyleSet()->RemoveStyleSheet(type, sheetRef);
    4510           0 :         shell->ApplicableStylesChanged();
    4511             :       }
    4512             :     }
    4513             : 
    4514             :     // Passing false, so documet.styleSheets.length will not be affected by
    4515             :     // these additional sheets.
    4516           0 :     NotifyStyleSheetRemoved(sheetRef, false);
    4517           0 :     sheetRef->ClearAssociatedDocumentOrShadowRoot();
    4518             :   }
    4519           0 : }
    4520             : 
    4521             : nsIGlobalObject*
    4522           0 : nsIDocument::GetScopeObject() const
    4523             : {
    4524           0 :   nsCOMPtr<nsIGlobalObject> scope(do_QueryReferent(mScopeObject));
    4525        4304 :   return scope;
    4526             : }
    4527             : 
    4528             : void
    4529          16 : nsIDocument::SetScopeObject(nsIGlobalObject* aGlobal)
    4530             : {
    4531          16 :   mScopeObject = do_GetWeakReference(aGlobal);
    4532          16 :   if (aGlobal) {
    4533           0 :     mHasHadScriptHandlingObject = true;
    4534             : 
    4535          32 :     nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal);
    4536           0 :     if (window) {
    4537             :       // We want to get the tabgroup unconditionally, such that we can make
    4538             :       // certain that it is cached in the inner window early enough.
    4539           0 :       mozilla::dom::TabGroup* tabgroup = window->TabGroup();
    4540             :       // We should already have the principal, and now that we have been added to a
    4541             :       // window, we should be able to join a DocGroup!
    4542          30 :       nsAutoCString docGroupKey;
    4543             :       nsresult rv =
    4544          15 :         mozilla::dom::DocGroup::GetKey(NodePrincipal(), docGroupKey);
    4545          30 :       if (mDocGroup) {
    4546           0 :         if (NS_SUCCEEDED(rv)) {
    4547           0 :           MOZ_RELEASE_ASSERT(mDocGroup->MatchesKey(docGroupKey));
    4548             :         }
    4549           0 :         MOZ_RELEASE_ASSERT(mDocGroup->GetTabGroup() == tabgroup);
    4550             :       } else {
    4551           0 :         mDocGroup = tabgroup->AddDocument(docGroupKey, this);
    4552          30 :         MOZ_ASSERT(mDocGroup);
    4553             :       }
    4554             :     }
    4555             :   }
    4556          16 : }
    4557             : 
    4558             : static void
    4559           0 : CheckIfContainsEMEContent(nsISupports* aSupports, void* aContainsEME)
    4560             : {
    4561           0 :   nsCOMPtr<nsIContent> content(do_QueryInterface(aSupports));
    4562           0 :   if (auto mediaElem = HTMLMediaElement::FromNodeOrNull(content)) {
    4563           0 :     bool* contains = static_cast<bool*>(aContainsEME);
    4564           0 :     if (mediaElem->GetMediaKeys()) {
    4565           0 :       *contains = true;
    4566             :     }
    4567             :   }
    4568           0 : }
    4569             : 
    4570             : bool
    4571           0 : nsIDocument::ContainsEMEContent()
    4572             : {
    4573           0 :   bool containsEME = false;
    4574             :   EnumerateActivityObservers(CheckIfContainsEMEContent,
    4575           0 :                              static_cast<void*>(&containsEME));
    4576           0 :   return containsEME;
    4577             : }
    4578             : 
    4579             : static void
    4580           0 : CheckIfContainsMSEContent(nsISupports* aSupports, void* aContainsMSE)
    4581             : {
    4582           0 :   nsCOMPtr<nsIContent> content(do_QueryInterface(aSupports));
    4583           0 :   if (auto mediaElem = HTMLMediaElement::FromNodeOrNull(content)) {
    4584           0 :     bool* contains = static_cast<bool*>(aContainsMSE);
    4585           0 :     RefPtr<MediaSource> ms = mediaElem->GetMozMediaSourceObject();
    4586           0 :     if (ms) {
    4587           0 :       *contains = true;
    4588             :     }
    4589             :   }
    4590           0 : }
    4591             : 
    4592             : bool
    4593           0 : nsIDocument::ContainsMSEContent()
    4594             : {
    4595           0 :   bool containsMSE = false;
    4596             :   EnumerateActivityObservers(CheckIfContainsMSEContent,
    4597           0 :                              static_cast<void*>(&containsMSE));
    4598           0 :   return containsMSE;
    4599             : }
    4600             : 
    4601             : static void
    4602           0 : NotifyActivityChanged(nsISupports *aSupports, void *aUnused)
    4603             : {
    4604           0 :   nsCOMPtr<nsIContent> content(do_QueryInterface(aSupports));
    4605           1 :   if (auto mediaElem = HTMLMediaElement::FromNodeOrNull(content)) {
    4606           0 :     mediaElem->NotifyOwnerDocumentActivityChanged();
    4607             :   }
    4608           0 :   nsCOMPtr<nsIObjectLoadingContent> objectLoadingContent(do_QueryInterface(aSupports));
    4609           0 :   if (objectLoadingContent) {
    4610           0 :     nsObjectLoadingContent* olc = static_cast<nsObjectLoadingContent*>(objectLoadingContent.get());
    4611           0 :     olc->NotifyOwnerDocumentActivityChanged();
    4612             :   }
    4613           0 :   nsCOMPtr<nsIDocumentActivity> objectDocumentActivity(do_QueryInterface(aSupports));
    4614           1 :   if (objectDocumentActivity) {
    4615           0 :     objectDocumentActivity->NotifyOwnerDocumentActivityChanged();
    4616             :   }
    4617           1 : }
    4618             : 
    4619             : bool
    4620           0 : nsIDocument::IsTopLevelWindowInactive() const
    4621             : {
    4622           1 :   nsCOMPtr<nsIDocShellTreeItem> treeItem = GetDocShell();
    4623          43 :   if (!treeItem) {
    4624             :     return false;
    4625             :   }
    4626             : 
    4627          34 :   nsCOMPtr<nsIDocShellTreeItem> rootItem;
    4628           0 :   treeItem->GetRootTreeItem(getter_AddRefs(rootItem));
    4629          17 :   if (!rootItem) {
    4630             :     return false;
    4631             :   }
    4632             : 
    4633           0 :   nsCOMPtr<nsPIDOMWindowOuter> domWindow = rootItem->GetWindow();
    4634          17 :   return domWindow && !domWindow->IsActive();
    4635             : }
    4636             : 
    4637             : void
    4638          41 : nsIDocument::SetContainer(nsDocShell* aContainer)
    4639             : {
    4640           0 :   if (aContainer) {
    4641           0 :     mDocumentContainer = aContainer;
    4642             :   } else {
    4643           0 :     mDocumentContainer = WeakPtr<nsDocShell>();
    4644             :   }
    4645             : 
    4646          41 :   EnumerateActivityObservers(NotifyActivityChanged, nullptr);
    4647             : 
    4648             :   // IsTopLevelWindowInactive depends on the docshell, so
    4649             :   // update the cached value now that it's available.
    4650           0 :   UpdateDocumentStates(NS_DOCUMENT_STATE_WINDOW_INACTIVE);
    4651          41 :   if (!aContainer) {
    4652             :     return;
    4653             :   }
    4654             : 
    4655             :   // Get the Docshell
    4656          15 :   if (aContainer->ItemType() == nsIDocShellTreeItem::typeContent) {
    4657             :     // check if same type root
    4658          10 :     nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot;
    4659           0 :     aContainer->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot));
    4660           5 :     NS_ASSERTION(sameTypeRoot, "No document shell root tree item from document shell tree item!");
    4661             : 
    4662           0 :     if (sameTypeRoot == aContainer) {
    4663           0 :       static_cast<nsDocument*>(this)->SetIsTopLevelContentDocument(true);
    4664             :     }
    4665             : 
    4666           0 :     static_cast<nsDocument*>(this)->SetIsContentDocument(true);
    4667             :   }
    4668             : 
    4669          30 :   mAncestorPrincipals = aContainer->AncestorPrincipals();
    4670           0 :   mAncestorOuterWindowIDs = aContainer->AncestorOuterWindowIDs();
    4671             : }
    4672             : 
    4673             : nsISupports*
    4674           0 : nsIDocument::GetContainer() const
    4675             : {
    4676          28 :   return static_cast<nsIDocShell*>(mDocumentContainer);
    4677             : }
    4678             : 
    4679             : void
    4680           0 : nsIDocument::SetScriptGlobalObject(nsIScriptGlobalObject *aScriptGlobalObject)
    4681             : {
    4682          47 :   MOZ_ASSERT(aScriptGlobalObject || !mAnimationController ||
    4683             :              mAnimationController->IsPausedByType(
    4684             :                nsSMILTimeContainer::PAUSE_PAGEHIDE |
    4685             :                nsSMILTimeContainer::PAUSE_BEGIN),
    4686             :              "Clearing window pointer while animations are unpaused");
    4687             : 
    4688          62 :   if (mScriptGlobalObject && !aScriptGlobalObject) {
    4689             :     // We're detaching from the window.  We need to grab a pointer to
    4690             :     // our layout history state now.
    4691           0 :     mLayoutHistoryState = GetLayoutHistoryState();
    4692             : 
    4693             :     // Also make sure to remove our onload blocker now if we haven't done it yet
    4694           8 :     if (mOnloadBlockCount != 0) {
    4695           0 :       nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup();
    4696           8 :       if (loadGroup) {
    4697           0 :         loadGroup->RemoveRequest(mOnloadBlocker, nullptr, NS_OK);
    4698             :       }
    4699             :     }
    4700             : 
    4701          16 :     ErrorResult error;
    4702          16 :     if (GetController().isSome()) {
    4703           0 :       imgLoader* loader = nsContentUtils::GetImgLoaderForDocument(this);
    4704           0 :       if (loader) {
    4705           0 :         loader->ClearCacheForControlledDocument(this);
    4706             :       }
    4707             : 
    4708             :       // We may become controlled again if this document comes back out
    4709             :       // of bfcache.  Clear our state to allow that to happen.  Only
    4710             :       // clear this flag if we are actually controlled, though, so pages
    4711             :       // that were force reloaded don't become controlled when they
    4712             :       // come out of bfcache.
    4713           0 :       mMaybeServiceWorkerControlled = false;
    4714             :     }
    4715             :   }
    4716             : 
    4717             :   // BlockOnload() might be called before mScriptGlobalObject is set.
    4718             :   // We may need to add the blocker once mScriptGlobalObject is set.
    4719           0 :   bool needOnloadBlocker = !mScriptGlobalObject && aScriptGlobalObject;
    4720             : 
    4721          31 :   mScriptGlobalObject = aScriptGlobalObject;
    4722             : 
    4723           0 :   if (needOnloadBlocker) {
    4724          15 :     EnsureOnloadBlocker();
    4725             :   }
    4726             : 
    4727           0 :   UpdateFrameRequestCallbackSchedulingState();
    4728             : 
    4729          31 :   if (aScriptGlobalObject) {
    4730             :     // Go back to using the docshell for the layout history state
    4731           0 :     mLayoutHistoryState = nullptr;
    4732          15 :     SetScopeObject(aScriptGlobalObject);
    4733           0 :     mHasHadDefaultView = true;
    4734             : #ifdef DEBUG
    4735          15 :     if (!mWillReparent) {
    4736             :       // We really shouldn't have a wrapper here but if we do we need to make sure
    4737             :       // it has the correct parent.
    4738          15 :       JSObject *obj = GetWrapperPreserveColor();
    4739           0 :       if (obj) {
    4740           0 :         JSObject *newScope = aScriptGlobalObject->GetGlobalJSObject();
    4741           0 :         NS_ASSERTION(js::GetGlobalForObjectCrossCompartment(obj) == newScope,
    4742             :                      "Wrong scope, this is really bad!");
    4743             :       }
    4744             :     }
    4745             : #endif
    4746             : 
    4747          15 :     if (mAllowDNSPrefetch) {
    4748           0 :       nsCOMPtr<nsIDocShell> docShell(mDocumentContainer);
    4749           7 :       if (docShell) {
    4750             : #ifdef DEBUG
    4751             :         nsCOMPtr<nsIWebNavigation> webNav =
    4752           0 :           do_GetInterface(aScriptGlobalObject);
    4753           0 :         NS_ASSERTION(SameCOMIdentity(webNav, docShell),
    4754             :                      "Unexpected container or script global?");
    4755             : #endif
    4756             :         bool allowDNSPrefetch;
    4757           7 :         docShell->GetAllowDNSPrefetch(&allowDNSPrefetch);
    4758           0 :         mAllowDNSPrefetch = allowDNSPrefetch;
    4759             :       }
    4760             :     }
    4761             : 
    4762             :     // If we are set in a window that is already focused we should remember this
    4763             :     // as the time the document gained focus.
    4764          30 :     IgnoredErrorResult ignored;
    4765          15 :     bool focused = HasFocus(ignored);
    4766          15 :     if (focused) {
    4767           0 :       SetLastFocusTime(TimeStamp::Now());
    4768             :     }
    4769             :   }
    4770             : 
    4771             :   // Remember the pointer to our window (or lack there of), to avoid
    4772             :   // having to QI every time it's asked for.
    4773         124 :   nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(mScriptGlobalObject);
    4774          31 :   mWindow = window;
    4775             : 
    4776             :   // Now that we know what our window is, we can flush the CSP errors to the
    4777             :   // Web Console. We are flushing all messages that occured and were stored
    4778             :   // in the queue prior to this point.
    4779          62 :   nsCOMPtr<nsIContentSecurityPolicy> csp;
    4780           0 :   NodePrincipal()->GetCsp(getter_AddRefs(csp));
    4781           0 :   if (csp) {
    4782           2 :     static_cast<nsCSPContext*>(csp.get())->flushConsoleMessages();
    4783             :   }
    4784             : 
    4785             :   nsCOMPtr<nsIHttpChannelInternal> internalChannel =
    4786           0 :     do_QueryInterface(GetChannel());
    4787          31 :   if (internalChannel) {
    4788           0 :     nsCOMArray<nsISecurityConsoleMessage> messages;
    4789           0 :     DebugOnly<nsresult> rv = internalChannel->TakeAllSecurityMessages(messages);
    4790           0 :     MOZ_ASSERT(NS_SUCCEEDED(rv));
    4791           0 :     SendToConsole(messages);
    4792             :   }
    4793             : 
    4794             :   // Set our visibility state, but do not fire the event.  This is correct
    4795             :   // because either we're coming out of bfcache (in which case IsVisible() will
    4796             :   // still test false at this point and no state change will happen) or we're
    4797             :   // doing the initial document load and don't want to fire the event for this
    4798             :   // change.
    4799          31 :   dom::VisibilityState oldState = mVisibilityState;
    4800          31 :   mVisibilityState = ComputeVisibilityState();
    4801             :   // When the visibility is changed, notify it to observers.
    4802             :   // Some observers need the notification, for example HTMLMediaElement uses
    4803             :   // it to update internal media resource allocation.
    4804             :   // When video is loaded via VideoDocument, HTMLMediaElement and MediaDecoder
    4805             :   // creation are already done before nsDocument::SetScriptGlobalObject() call.
    4806             :   // MediaDecoder decides whether starting decoding is decided based on
    4807             :   // document's visibility. When the MediaDecoder is created,
    4808             :   // nsDocument::SetScriptGlobalObject() is not yet called and document is
    4809             :   // hidden state. Therefore the MediaDecoder decides that decoding is
    4810             :   // not yet necessary. But soon after nsDocument::SetScriptGlobalObject()
    4811             :   // call, the document becomes not hidden. At the time, MediaDecoder needs
    4812             :   // to know it and needs to start updating decoding.
    4813          31 :   if (oldState != mVisibilityState) {
    4814           0 :     EnumerateActivityObservers(NotifyActivityChanged, nullptr);
    4815             :   }
    4816             : 
    4817             :   // The global in the template contents owner document should be the same.
    4818          62 :   if (mTemplateContentsOwner && mTemplateContentsOwner != this) {
    4819           0 :     mTemplateContentsOwner->SetScriptGlobalObject(aScriptGlobalObject);
    4820             :   }
    4821             : 
    4822           0 :   if (!mMaybeServiceWorkerControlled && mDocumentContainer && mScriptGlobalObject && GetChannel()) {
    4823           0 :     nsCOMPtr<nsIDocShell> docShell(mDocumentContainer);
    4824             :     uint32_t loadType;
    4825           7 :     docShell->GetLoadType(&loadType);
    4826             : 
    4827             :     // If we are shift-reloaded, don't associate with a ServiceWorker.
    4828           7 :     if (IsForceReloadType(loadType)) {
    4829           0 :       NS_WARNING("Page was shift reloaded, skipping ServiceWorker control");
    4830           0 :       return;
    4831             :     }
    4832             : 
    4833           7 :     mMaybeServiceWorkerControlled = true;
    4834             :   }
    4835             : }
    4836             : 
    4837             : nsIScriptGlobalObject*
    4838           0 : nsIDocument::GetScriptHandlingObjectInternal() const
    4839             : {
    4840       10886 :   MOZ_ASSERT(!mScriptGlobalObject,
    4841             :              "Do not call this when mScriptGlobalObject is set!");
    4842        5443 :   if (mHasHadDefaultView) {
    4843             :     return nullptr;
    4844             :   }
    4845             : 
    4846             :   nsCOMPtr<nsIScriptGlobalObject> scriptHandlingObject =
    4847           0 :     do_QueryReferent(mScopeObject);
    4848           0 :   nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(scriptHandlingObject);
    4849        5441 :   if (win) {
    4850           0 :     nsPIDOMWindowOuter* outer = win->GetOuterWindow();
    4851           0 :     if (!outer || outer->GetCurrentInnerWindow() != win) {
    4852           0 :       NS_WARNING("Wrong inner/outer window combination!");
    4853           0 :       return nullptr;
    4854             :     }
    4855             :   }
    4856           0 :   return scriptHandlingObject;
    4857             : }
    4858             : void
    4859           0 : nsIDocument::SetScriptHandlingObject(nsIScriptGlobalObject* aScriptObject)
    4860             : {
    4861           0 :   NS_ASSERTION(!mScriptGlobalObject ||
    4862             :                mScriptGlobalObject == aScriptObject,
    4863             :                "Wrong script object!");
    4864           0 :   if (aScriptObject) {
    4865           0 :     SetScopeObject(aScriptObject);
    4866           0 :     mHasHadDefaultView = false;
    4867             :   }
    4868           0 : }
    4869             : 
    4870             : nsPIDOMWindowOuter*
    4871           0 : nsIDocument::GetWindowInternal() const
    4872             : {
    4873         444 :   MOZ_ASSERT(!mWindow, "This should not be called when mWindow is not null!");
    4874             :   // Let's use mScriptGlobalObject. Even if the document is already removed from
    4875             :   // the docshell, the outer window might be still obtainable from the it.
    4876           0 :   nsCOMPtr<nsPIDOMWindowOuter> win;
    4877         444 :   if (mRemovedFromDocShell) {
    4878             :     // The docshell returns the outer window we are done.
    4879           0 :     nsCOMPtr<nsIDocShell> kungFuDeathGrip(mDocumentContainer);
    4880           0 :     if (kungFuDeathGrip) {
    4881           0 :       win = kungFuDeathGrip->GetWindow();
    4882             :     }
    4883             :   } else {
    4884        2220 :     if (nsCOMPtr<nsPIDOMWindowInner> inner = do_QueryInterface(mScriptGlobalObject)) {
    4885             :       // mScriptGlobalObject is always the inner window, let's get the outer.
    4886           0 :       win = inner->GetOuterWindow();
    4887             :     }
    4888             :   }
    4889             : 
    4890           0 :   return win;
    4891             : }
    4892             : 
    4893             : bool
    4894          11 : nsIDocument::InternalAllowXULXBL()
    4895             : {
    4896          11 :   if (nsContentUtils::AllowXULXBLForPrincipal(NodePrincipal())) {
    4897           0 :     mAllowXULXBL = eTriTrue;
    4898           4 :     return true;
    4899             :   }
    4900             : 
    4901           7 :   mAllowXULXBL = eTriFalse;
    4902           7 :   return false;
    4903             : }
    4904             : 
    4905             : // Note: We don't hold a reference to the document observer; we assume
    4906             : // that it has a live reference to the document.
    4907             : void
    4908           0 : nsIDocument::AddObserver(nsIDocumentObserver* aObserver)
    4909             : {
    4910           0 :   NS_ASSERTION(mObservers.IndexOf(aObserver) == nsTArray<int>::NoIndex,
    4911             :                "Observer already in the list");
    4912          63 :   mObservers.AppendElement(aObserver);
    4913           0 :   AddMutationObserver(aObserver);
    4914          63 : }
    4915             : 
    4916             : bool
    4917          62 : nsIDocument::RemoveObserver(nsIDocumentObserver* aObserver)
    4918             : {
    4919             :   // If we're in the process of destroying the document (and we're
    4920             :   // informing the observers of the destruction), don't remove the
    4921             :   // observers from the list. This is not a big deal, since we
    4922             :   // don't hold a live reference to the observers.
    4923           0 :   if (!mInDestructor) {
    4924          62 :     RemoveMutationObserver(aObserver);
    4925           0 :     return mObservers.RemoveElement(aObserver);
    4926             :   }
    4927             : 
    4928           0 :   return mObservers.Contains(aObserver);
    4929             : }
    4930             : 
    4931             : void
    4932         783 : nsIDocument::MaybeEndOutermostXBLUpdate()
    4933             : {
    4934             :   // Only call BindingManager()->EndOutermostUpdate() when
    4935             :   // we're not in an update and it is safe to run scripts.
    4936           0 :   if (mUpdateNestLevel == 0 && mInXBLUpdate) {
    4937           0 :     if (nsContentUtils::IsSafeToRunScript()) {
    4938           0 :       mInXBLUpdate = false;
    4939         670 :       BindingManager()->EndOutermostUpdate();
    4940          89 :     } else if (!mInDestructor) {
    4941           0 :       if (!mMaybeEndOutermostXBLUpdateRunner) {
    4942             :         mMaybeEndOutermostXBLUpdateRunner =
    4943           1 :           NewRunnableMethod("nsDocument::MaybeEndOutermostXBLUpdate",
    4944             :                             this,
    4945          18 :                             &nsDocument::MaybeEndOutermostXBLUpdate);
    4946             :       }
    4947           0 :       nsContentUtils::AddScriptRunner(mMaybeEndOutermostXBLUpdateRunner);
    4948             :     }
    4949             :   }
    4950         783 : }
    4951             : 
    4952             : void
    4953           0 : nsIDocument::BeginUpdate()
    4954             : {
    4955             :   // If the document is going away, then it's probably okay to do things to it
    4956             :   // in the wrong DocGroup. We're unlikely to run JS or do anything else
    4957             :   // observable at this point. We reach this point when cycle collecting a
    4958             :   // <link> element and the unlink code removes a style sheet.
    4959             :   //
    4960             :   // TODO(emilio): Style updates are gone, can this happen now?
    4961        1388 :   if (mDocGroup && !mIsGoingAway && !mInUnlinkOrDeletion && !mIgnoreDocGroupMismatches) {
    4962         465 :     mDocGroup->ValidateAccess();
    4963             :   }
    4964             : 
    4965           0 :   if (mUpdateNestLevel == 0 && !mInXBLUpdate) {
    4966         335 :     mInXBLUpdate = true;
    4967           0 :     BindingManager()->BeginOutermostUpdate();
    4968             :   }
    4969             : 
    4970           0 :   ++mUpdateNestLevel;
    4971           0 :   nsContentUtils::AddScriptBlocker();
    4972        3642 :   NS_DOCUMENT_NOTIFY_OBSERVERS(BeginUpdate, (this));
    4973         694 : }
    4974             : 
    4975             : void
    4976         694 : nsDocument::EndUpdate()
    4977             : {
    4978        3642 :   NS_DOCUMENT_NOTIFY_OBSERVERS(EndUpdate, (this));
    4979             : 
    4980           0 :   nsContentUtils::RemoveScriptBlocker();
    4981             : 
    4982           0 :   --mUpdateNestLevel;
    4983             : 
    4984             :   // This set of updates may have created XBL bindings.  Let the
    4985             :   // binding manager know we're done.
    4986         694 :   MaybeEndOutermostXBLUpdate();
    4987             : 
    4988         694 :   MaybeInitializeFinalizeFrameLoaders();
    4989           0 : }
    4990             : 
    4991             : void
    4992          49 : nsDocument::BeginLoad()
    4993             : {
    4994           0 :   MOZ_ASSERT(!mDidCallBeginLoad);
    4995           0 :   mDidCallBeginLoad = true;
    4996             : 
    4997             :   // Block onload here to prevent having to deal with blocking and
    4998             :   // unblocking it while we know the document is loading.
    4999          49 :   BlockOnload();
    5000           0 :   mDidFireDOMContentLoaded = false;
    5001          49 :   BlockDOMContentLoaded();
    5002             : 
    5003          98 :   if (mScriptLoader) {
    5004           0 :     mScriptLoader->BeginDeferringScripts();
    5005             :   }
    5006             : 
    5007           0 :   NS_DOCUMENT_NOTIFY_OBSERVERS(BeginLoad, (this));
    5008          49 : }
    5009             : 
    5010             : void
    5011           0 : nsIDocument::MozSetImageElement(const nsAString& aImageElementId,
    5012             :                                Element* aElement)
    5013             : {
    5014           0 :   if (aImageElementId.IsEmpty())
    5015           0 :     return;
    5016             : 
    5017             :   // Hold a script blocker while calling SetImageElement since that can call
    5018             :   // out to id-observers
    5019           0 :   nsAutoScriptBlocker scriptBlocker;
    5020             : 
    5021           0 :   nsIdentifierMapEntry* entry = mIdentifierMap.PutEntry(aImageElementId);
    5022           0 :   if (entry) {
    5023           0 :     entry->SetImageElement(aElement);
    5024           0 :     if (entry->IsEmpty()) {
    5025           0 :       mIdentifierMap.RemoveEntry(entry);
    5026             :     }
    5027             :   }
    5028             : }
    5029             : 
    5030             : Element*
    5031           0 : nsIDocument::LookupImageElement(const nsAString& aId)
    5032             : {
    5033           0 :   if (aId.IsEmpty())
    5034             :     return nullptr;
    5035             : 
    5036           0 :   nsIdentifierMapEntry* entry = mIdentifierMap.GetEntry(aId);
    5037           0 :   return entry ? entry->GetImageIdElement() : nullptr;
    5038             : }
    5039             : 
    5040             : void
    5041          52 : nsIDocument::DispatchContentLoadedEvents()
    5042             : {
    5043             :   // If you add early returns from this method, make sure you're
    5044             :   // calling UnblockOnload properly.
    5045             : 
    5046             :   // Unpin references to preloaded images
    5047         104 :   mPreloadingImages.Clear();
    5048             : 
    5049             :   // DOM manipulation after content loaded should not care if the element
    5050             :   // came from the preloader.
    5051           0 :   mPreloadedPreconnects.Clear();
    5052             : 
    5053         104 :   if (mTiming) {
    5054          20 :     mTiming->NotifyDOMContentLoadedStart(nsIDocument::GetDocumentURI());
    5055             :   }
    5056             : 
    5057             :   // Dispatch observer notification to notify observers document is interactive.
    5058           0 :   nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
    5059          52 :   if (os) {
    5060           0 :     nsIPrincipal* principal = NodePrincipal();
    5061           0 :     os->NotifyObservers(this,
    5062          52 :                         nsContentUtils::IsSystemPrincipal(principal) ?
    5063             :                           "chrome-document-interactive" :
    5064             :                           "content-document-interactive",
    5065           0 :                         nullptr);
    5066             :   }
    5067             : 
    5068             :   // Fire a DOM event notifying listeners that this document has been
    5069             :   // loaded (excluding images and other loads initiated by this
    5070             :   // document).
    5071           0 :   nsContentUtils::DispatchTrustedEvent(this, this,
    5072           0 :                                        NS_LITERAL_STRING("DOMContentLoaded"),
    5073         156 :                                        true, false);
    5074             : 
    5075          52 :   if (MayStartLayout()) {
    5076           0 :     MaybeResolveReadyForIdle();
    5077             :   }
    5078             : 
    5079           0 :   RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
    5080           0 :   nsIDocShell* docShell = this->GetDocShell();
    5081             : 
    5082           0 :   if (timelines && timelines->HasConsumer(docShell)) {
    5083           0 :     timelines->AddMarkerForDocShell(docShell,
    5084           0 :       MakeUnique<DocLoadingTimelineMarker>("document::DOMContentLoaded"));
    5085             :   }
    5086             : 
    5087         104 :   if (mTiming) {
    5088           1 :     mTiming->NotifyDOMContentLoadedEnd(nsIDocument::GetDocumentURI());
    5089             :   }
    5090             : 
    5091             :   // If this document is a [i]frame, fire a DOMFrameContentLoaded
    5092             :   // event on all parent documents notifying that the HTML (excluding
    5093             :   // other external files such as images and stylesheets) in a frame
    5094             :   // has finished loading.
    5095             : 
    5096             :   // target_frame is the [i]frame element that will be used as the
    5097             :   // target for the event. It's the [i]frame whose content is done
    5098             :   // loading.
    5099         104 :   nsCOMPtr<EventTarget> target_frame;
    5100             : 
    5101          52 :   if (mParentDocument) {
    5102           3 :     target_frame = mParentDocument->FindContentForSubDocument(this);
    5103             :   }
    5104             : 
    5105          52 :   if (target_frame) {
    5106           6 :     nsCOMPtr<nsIDocument> parent = mParentDocument;
    5107           3 :     do {
    5108           0 :       RefPtr<Event> event;
    5109           3 :       if (parent) {
    5110           0 :         IgnoredErrorResult ignored;
    5111           0 :         event = parent->CreateEvent(NS_LITERAL_STRING("Events"),
    5112           9 :                                     CallerType::System, ignored);
    5113             : 
    5114             :       }
    5115             : 
    5116           0 :       if (event) {
    5117           0 :         event->InitEvent(NS_LITERAL_STRING("DOMFrameContentLoaded"), true,
    5118           0 :                          true);
    5119             : 
    5120           3 :         event->SetTarget(target_frame);
    5121           3 :         event->SetTrusted(true);
    5122             : 
    5123             :         // To dispatch this event we must manually call
    5124             :         // EventDispatcher::Dispatch() on the ancestor document since the
    5125             :         // target is not in the same document, so the event would never reach
    5126             :         // the ancestor document if we used the normal event
    5127             :         // dispatching code.
    5128             : 
    5129           0 :         WidgetEvent* innerEvent = event->WidgetEventPtr();
    5130           0 :         if (innerEvent) {
    5131           3 :           nsEventStatus status = nsEventStatus_eIgnore;
    5132             : 
    5133           0 :           RefPtr<nsPresContext> context = parent->GetPresContext();
    5134             : 
    5135           3 :           if (context) {
    5136           0 :             EventDispatcher::Dispatch(parent, context, innerEvent, event,
    5137           0 :                                       &status);
    5138             :           }
    5139             :         }
    5140             :       }
    5141             : 
    5142           3 :       parent = parent->GetParentDocument();
    5143             :     } while (parent);
    5144             :   }
    5145             : 
    5146             :   // If the document has a manifest attribute, fire a MozApplicationManifest
    5147             :   // event.
    5148          52 :   Element* root = GetRootElement();
    5149          52 :   if (root && root->HasAttr(kNameSpaceID_None, nsGkAtoms::manifest)) {
    5150             :     nsContentUtils::DispatchChromeEvent(this, this,
    5151           0 :                                         NS_LITERAL_STRING("MozApplicationManifest"),
    5152           0 :                                         true, true);
    5153             :   }
    5154             : 
    5155          52 :   if (mMaybeServiceWorkerControlled) {
    5156             :     using mozilla::dom::ServiceWorkerManager;
    5157          21 :     RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
    5158           0 :     if (swm) {
    5159           0 :       Maybe<ClientInfo> clientInfo = GetClientInfo();
    5160           7 :       if (clientInfo.isSome()) {
    5161           7 :         swm->MaybeCheckNavigationUpdate(clientInfo.ref());
    5162             :       }
    5163             :     }
    5164             :   }
    5165             : 
    5166           0 :   UnblockOnload(true);
    5167           0 : }
    5168             : 
    5169             : #if defined(DEBUG) && !defined(ANDROID)
    5170             : // We want to get to a point where all about: pages ship with a CSP. This
    5171             : // assertion ensures that we can not deploy new about: pages without a CSP.
    5172             : // Initially we will whitelist legacy about: pages which not yet have a CSP
    5173             : // attached, but ultimately that whitelist should disappear.
    5174             : // Please note that any about: page should not use inline JS or inline CSS,
    5175             : // and instead should load JS and CSS from an external file (*.js, *.css)
    5176             : // which allows us to apply a strong CSP omitting 'unsafe-inline'. Ideally,
    5177             : // the CSP allows precisely the resources that need to be loaded; but it
    5178             : // should at least be as strong as:
    5179             : // <meta http-equiv="Content-Security-Policy" content="default-src chrome:"/>
    5180             : static void
    5181          49 : AssertContentPrivilegedAboutPageHasCSP(nsIURI* aDocumentURI, nsIPrincipal* aPrincipal)
    5182             : {
    5183             :   // Curently we can't serialize the CSP, hence we only assert if
    5184             :   // running in the content process.
    5185          49 :   if (!XRE_IsContentProcess()) {
    5186           0 :     return;
    5187             :   }
    5188             : 
    5189             :   // Check if we are loading an about: URI at all
    5190             :   bool isAboutURI =
    5191           0 :     (NS_SUCCEEDED(aDocumentURI->SchemeIs("about", &isAboutURI)) && isAboutURI);
    5192             : 
    5193           0 :   if (!isAboutURI) {
    5194             :     return;
    5195             :   }
    5196             : 
    5197             :   // Check if we are loading a content-privileged about: URI
    5198           0 :   nsCOMPtr<nsIAboutModule> aboutModule;
    5199           0 :   nsresult rv = NS_GetAboutModule(aDocumentURI, getter_AddRefs(aboutModule));
    5200           0 :   NS_ENSURE_SUCCESS_VOID(rv);
    5201             : 
    5202           0 :   uint32_t aboutModuleFlags = 0;
    5203           0 :   rv = aboutModule->GetURIFlags(aDocumentURI, &aboutModuleFlags);
    5204           0 :   NS_ENSURE_SUCCESS_VOID(rv);
    5205             : 
    5206           0 :   if (!(aboutModuleFlags & nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT)) {
    5207             :     return;
    5208             :   }
    5209             : 
    5210             :   // Potentially init the legacy whitelist of about URIs without a CSP.
    5211           0 :   static StaticAutoPtr<nsTArray<nsCString>> sLegacyAboutPagesWithNoCSP;
    5212           0 :   if (!sLegacyAboutPagesWithNoCSP) {
    5213           0 :     sLegacyAboutPagesWithNoCSP = new nsTArray<nsCString>();
    5214           0 :     nsAutoCString legacyAboutPages;
    5215             :     Preferences::GetCString("csp.content_privileged_about_uris_without_csp",
    5216           0 :       legacyAboutPages);
    5217           0 :     for (const nsACString& hostString : legacyAboutPages.Split(',')) {
    5218             :       // please note that for the actual whitelist we only store the path of
    5219             :       // about: URI. Let's reassemble the full about URI here so we don't
    5220             :       // have to remove query arguments later.
    5221           0 :       nsCString aboutURI;
    5222           0 :       aboutURI.AppendLiteral("about:");
    5223           0 :       aboutURI.Append(hostString);
    5224           0 :       sLegacyAboutPagesWithNoCSP->AppendElement(aboutURI);
    5225             :     }
    5226           0 :     ClearOnShutdown(&sLegacyAboutPagesWithNoCSP);
    5227             :   }
    5228             : 
    5229             :   // Check if the about URI is whitelisted
    5230           0 :   nsAutoCString aboutSpec;
    5231           0 :   aDocumentURI->GetSpec(aboutSpec);
    5232           0 :   for (auto& legacyPageEntry : *sLegacyAboutPagesWithNoCSP) {
    5233             :     // please note that we perform a substring match here on purpose,
    5234             :     // so we don't have to deal and parse out all the query arguments
    5235             :     // the various about pages rely on.
    5236           0 :     if (aboutSpec.Find(legacyPageEntry) == 0) {
    5237           0 :       return;
    5238             :     }
    5239             :   }
    5240             : 
    5241           0 :   nsCOMPtr<nsIContentSecurityPolicy> csp;
    5242           0 :   aPrincipal->GetCsp(getter_AddRefs(csp));
    5243           0 :   nsAutoString parsedPolicyStr;
    5244           0 :   if (csp) {
    5245           0 :     uint32_t policyCount = 0;
    5246           0 :      csp->GetPolicyCount(&policyCount);
    5247           0 :      if (policyCount > 0) {
    5248           0 :        csp->GetPolicyString(0, parsedPolicyStr);
    5249             :      }
    5250             :   }
    5251           0 :   MOZ_ASSERT(parsedPolicyStr.Find("default-src") >= 0,
    5252             :     "about: page must contain a CSP including default-src");
    5253             : }
    5254             : #endif
    5255             : 
    5256             : void
    5257           0 : nsDocument::EndLoad()
    5258             : {
    5259             : #if defined(DEBUG) && !defined(ANDROID)
    5260           0 :   AssertContentPrivilegedAboutPageHasCSP(mDocumentURI, NodePrincipal());
    5261             : #endif
    5262             : 
    5263             :   // EndLoad may have been called without a matching call to BeginLoad, in the
    5264             :   // case of a failed parse (for example, due to timeout). In such a case, we
    5265             :   // still want to execute part of this code to do appropriate cleanup, but we
    5266             :   // gate part of it because it is intended to match 1-for-1 with calls to
    5267             :   // BeginLoad. We have an explicit flag bit for this purpose, since it's
    5268             :   // complicated and error prone to derive this condition from other related
    5269             :   // flags that can be manipulated outside of a BeginLoad/EndLoad pair.
    5270             : 
    5271             :   // Part 1: Code that always executes to cleanup end of parsing, whether
    5272             :   // that parsing was successful or not.
    5273             : 
    5274             :   // Drop the ref to our parser, if any, but keep hold of the sink so that we
    5275             :   // can flush it from FlushPendingNotifications as needed.  We might have to
    5276             :   // do that to get a StartLayout() to happen.
    5277          98 :   if (mParser) {
    5278           0 :     mWeakSink = do_GetWeakReference(mParser->GetContentSink());
    5279           0 :     mParser = nullptr;
    5280             :   }
    5281             : 
    5282         222 :   NS_DOCUMENT_NOTIFY_OBSERVERS(EndLoad, (this));
    5283             : 
    5284             :   // Part 2: Code that only executes when this EndLoad matches a BeginLoad.
    5285             : 
    5286          49 :   if (!mDidCallBeginLoad) {
    5287             :     return;
    5288             :   }
    5289           0 :   mDidCallBeginLoad = false;
    5290             : 
    5291          49 :   UnblockDOMContentLoaded();
    5292             : }
    5293             : 
    5294             : void
    5295          49 : nsIDocument::UnblockDOMContentLoaded()
    5296             : {
    5297          49 :   MOZ_ASSERT(mBlockDOMContentLoaded);
    5298           0 :   if (--mBlockDOMContentLoaded != 0 || mDidFireDOMContentLoaded) {
    5299             :     return;
    5300             :   }
    5301             : 
    5302           0 :   MOZ_LOG(gDocumentLeakPRLog, LogLevel::Debug, ("DOCUMENT %p UnblockDOMContentLoaded", this));
    5303             : 
    5304           0 :   mDidFireDOMContentLoaded = true;
    5305           0 :   if (nsIPresShell* shell = GetShell()) {
    5306          16 :     shell->GetRefreshDriver()->NotifyDOMContentLoaded();
    5307             :   }
    5308             : 
    5309             : 
    5310          49 :   MOZ_ASSERT(mReadyState == READYSTATE_INTERACTIVE);
    5311          49 :   if (!mSynchronousDOMContentLoaded) {
    5312          18 :     MOZ_RELEASE_ASSERT(NS_IsMainThread());
    5313             :     nsCOMPtr<nsIRunnable> ev =
    5314           0 :       NewRunnableMethod("nsIDocument::DispatchContentLoadedEvents",
    5315             :                         this,
    5316          36 :                         &nsIDocument::DispatchContentLoadedEvents);
    5317           0 :     Dispatch(TaskCategory::Other, ev.forget());
    5318             :   } else {
    5319          31 :     DispatchContentLoadedEvents();
    5320             :   }
    5321             : }
    5322             : 
    5323             : void
    5324          10 : nsIDocument::ContentStateChanged(nsIContent* aContent, EventStates aStateMask)
    5325             : {
    5326          10 :   MOZ_ASSERT(!nsContentUtils::IsSafeToRunScript(),
    5327             :              "Someone forgot a scriptblocker");
    5328          40 :   NS_DOCUMENT_NOTIFY_OBSERVERS(ContentStateChanged,
    5329             :                                (this, aContent, aStateMask));
    5330          10 : }
    5331             : 
    5332             : void
    5333           5 : nsIDocument::DocumentStatesChanged(EventStates aStateMask)
    5334             : {
    5335           0 :   UpdateDocumentStates(aStateMask);
    5336           0 :   NS_DOCUMENT_NOTIFY_OBSERVERS(DocumentStatesChanged, (this, aStateMask));
    5337           5 : }
    5338             : 
    5339             : void
    5340           0 : nsIDocument::StyleRuleChanged(StyleSheet* aSheet, css::Rule* aStyleRule)
    5341             : {
    5342           0 :   if (nsIPresShell* shell = GetShell()) {
    5343           0 :     shell->ApplicableStylesChanged();
    5344             :   }
    5345             : 
    5346           0 :   if (!StyleSheetChangeEventsEnabled()) {
    5347             :     return;
    5348             :   }
    5349             : 
    5350           0 :   DO_STYLESHEET_NOTIFICATION(StyleRuleChangeEvent,
    5351             :                              "StyleRuleChanged",
    5352             :                              mRule,
    5353             :                              aStyleRule);
    5354             : }
    5355             : 
    5356             : void
    5357           0 : nsIDocument::StyleRuleAdded(StyleSheet* aSheet, css::Rule* aStyleRule)
    5358             : {
    5359           0 :   if (nsIPresShell* shell = GetShell()) {
    5360           0 :     shell->ApplicableStylesChanged();
    5361             :   }
    5362             : 
    5363           0 :   if (!StyleSheetChangeEventsEnabled()) {
    5364             :     return;
    5365             :   }
    5366             : 
    5367           0 :   DO_STYLESHEET_NOTIFICATION(StyleRuleChangeEvent,
    5368             :                              "StyleRuleAdded",
    5369             :                              mRule,
    5370             :                              aStyleRule);
    5371             : }
    5372             : 
    5373             : void
    5374           0 : nsIDocument::StyleRuleRemoved(StyleSheet* aSheet, css::Rule* aStyleRule)
    5375             : {
    5376           0 :   if (nsIPresShell* shell = GetShell()) {
    5377           0 :     shell->ApplicableStylesChanged();
    5378             :   }
    5379             : 
    5380           0 :   if (!StyleSheetChangeEventsEnabled()) {
    5381             :     return;
    5382             :   }
    5383             : 
    5384           0 :   DO_STYLESHEET_NOTIFICATION(StyleRuleChangeEvent,
    5385             :                              "StyleRuleRemoved",
    5386             :                              mRule,
    5387             :                              aStyleRule);
    5388             : }
    5389             : 
    5390             : #undef DO_STYLESHEET_NOTIFICATION
    5391             : 
    5392             : already_AddRefed<AnonymousContent>
    5393           0 : nsIDocument::InsertAnonymousContent(Element& aElement, ErrorResult& aRv)
    5394             : {
    5395           0 :   nsIPresShell* shell = GetShell();
    5396           0 :   if (!shell || !shell->GetCanvasFrame()) {
    5397           0 :     aRv.Throw(NS_ERROR_UNEXPECTED);
    5398             :     return nullptr;
    5399             :   }
    5400             : 
    5401           0 :   // We're about to insert random content here that will be rendered. We're
    5402           0 :   // going to need more than svg.css here...
    5403           0 :   if (IsSVGDocument()) {
    5404           0 :     AsSVGDocument()->EnsureNonSVGUserAgentStyleSheetsLoaded();
    5405           0 :   }
    5406             : 
    5407             :   nsAutoScriptBlocker scriptBlocker;
    5408             :   nsCOMPtr<Element> container = shell->GetCanvasFrame()
    5409             :                                      ->GetCustomContentContainer();
    5410           0 :   if (!container) {
    5411           0 :     aRv.Throw(NS_ERROR_UNEXPECTED);
    5412             :     return nullptr;
    5413             :   }
    5414             : 
    5415             :   // Clone the node to avoid returning a direct reference
    5416             :   nsCOMPtr<nsINode> clonedElement = aElement.CloneNode(true, aRv);
    5417           0 :   if (aRv.Failed()) {
    5418           0 :     return nullptr;
    5419             :   }
    5420             : 
    5421             :   // Insert the element into the container
    5422             :   nsresult rv;
    5423           0 :   rv = container->AppendChildTo(clonedElement->AsContent(), true);
    5424           0 :   if (NS_FAILED(rv)) {
    5425             :     return nullptr;
    5426           0 :   }
    5427             : 
    5428           0 :   RefPtr<AnonymousContent> anonymousContent =
    5429             :     new AnonymousContent(clonedElement->AsElement());
    5430             :   mAnonymousContents.AppendElement(anonymousContent);
    5431             : 
    5432           0 :   shell->GetCanvasFrame()->ShowCustomContentContainer();
    5433             : 
    5434             :   return anonymousContent.forget();
    5435           0 : }
    5436           0 : 
    5437           0 : void
    5438           0 : nsIDocument::RemoveAnonymousContent(AnonymousContent& aContent,
    5439             :                                     ErrorResult& aRv)
    5440             : {
    5441           0 :   nsIPresShell* shell = GetShell();
    5442           0 :   if (!shell || !shell->GetCanvasFrame()) {
    5443           0 :     aRv.Throw(NS_ERROR_UNEXPECTED);
    5444           0 :     return;
    5445           0 :   }
    5446           0 : 
    5447             :   nsAutoScriptBlocker scriptBlocker;
    5448             :   nsCOMPtr<Element> container = shell->GetCanvasFrame()
    5449             :                                      ->GetCustomContentContainer();
    5450           0 :   if (!container) {
    5451           0 :     aRv.Throw(NS_ERROR_UNEXPECTED);
    5452             :     return;
    5453           0 :   }
    5454             : 
    5455             :   // Iterate over mAnonymousContents to find and remove the given node.
    5456           0 :   for (size_t i = 0, len = mAnonymousContents.Length(); i < len; ++i) {
    5457             :     if (mAnonymousContents[i] == &aContent) {
    5458             :       // Get the node from the customContent
    5459           0 :       nsCOMPtr<Element> node = aContent.GetContentNode();
    5460           0 : 
    5461           0 :       // Remove the entry in mAnonymousContents
    5462             :       mAnonymousContents.RemoveElementAt(i);
    5463             : 
    5464           0 :       // Remove the node from its container
    5465             :       container->RemoveChild(*node, aRv);
    5466             :       if (aRv.Failed()) {
    5467           0 :         return;
    5468           0 :       }
    5469             : 
    5470             :       break;
    5471             :     }
    5472             :   }
    5473           0 :   if (mAnonymousContents.IsEmpty()) {
    5474             :     shell->GetCanvasFrame()->HideCustomContentContainer();
    5475           0 :   }
    5476             : }
    5477             : 
    5478             : Element*
    5479           0 : nsIDocument::GetAnonRootIfInAnonymousContentContainer(nsINode* aNode) const
    5480           0 : {
    5481             :   if (!aNode->IsInNativeAnonymousSubtree()) {
    5482             :     return nullptr;
    5483             :   }
    5484           0 : 
    5485           0 :   nsIPresShell* shell = GetShell();
    5486           0 :   if (!shell || !shell->GetCanvasFrame()) {
    5487           0 :     return nullptr;
    5488             :   }
    5489             : 
    5490             :   nsAutoScriptBlocker scriptBlocker;
    5491             :   nsCOMPtr<Element> customContainer = shell->GetCanvasFrame()
    5492             :                                            ->GetCustomContentContainer();
    5493             :   if (!customContainer) {
    5494           0 :     return nullptr;
    5495           0 :   }
    5496           0 : 
    5497           0 :   // An arbitrary number of elements can be inserted as children of the custom
    5498           0 :   // container frame.  We want the one that was added that contains aNode, so
    5499             :   // we need to keep track of the last child separately using |child| here.
    5500           0 :   nsINode* child = aNode;
    5501           0 :   nsINode* parent = aNode->GetParentNode();
    5502             :   while (parent && parent->IsInNativeAnonymousSubtree()) {
    5503             :     if (parent == customContainer) {
    5504             :       return Element::FromNode(child);
    5505             :     }
    5506             :     child = parent;
    5507           0 :     parent = child->GetParentNode();
    5508             :   }
    5509          82 :   return nullptr;
    5510           0 : }
    5511          82 : 
    5512             : Maybe<ClientInfo>
    5513             : nsIDocument::GetClientInfo() const
    5514             : {
    5515             :   nsPIDOMWindowInner* inner = GetInnerWindow();
    5516             :   if (inner) {
    5517           0 :     return inner->GetClientInfo();
    5518             :   }
    5519           0 :   return Maybe<ClientInfo>();
    5520           0 : }
    5521           0 : 
    5522             : Maybe<ClientState>
    5523             : nsIDocument::GetClientState() const
    5524             : {
    5525             :   nsPIDOMWindowInner* inner = GetInnerWindow();
    5526             :   if (inner) {
    5527         103 :     return inner->GetClientState();
    5528             :   }
    5529         103 :   return Maybe<ClientState>();
    5530           0 : }
    5531         103 : 
    5532             : Maybe<ServiceWorkerDescriptor>
    5533             : nsIDocument::GetController() const
    5534             : {
    5535             :   nsPIDOMWindowInner* inner = GetInnerWindow();
    5536             :   if (inner) {
    5537             :     return inner->GetController();
    5538             :   }
    5539             :   return Maybe<ServiceWorkerDescriptor>();
    5540           0 : }
    5541             : 
    5542           0 : //
    5543           0 : // nsIDocument interface
    5544           0 : //
    5545           0 : DocumentType*
    5546             : nsIDocument::GetDoctype() const
    5547             : {
    5548             :   for (nsIContent* child = GetFirstChild();
    5549             :        child;
    5550             :        child = child->GetNextSibling()) {
    5551             :     if (child->NodeType() == DOCUMENT_TYPE_NODE) {
    5552             :       return static_cast<DocumentType*>(child);
    5553           0 :     }
    5554             :   }
    5555           0 :   return nullptr;
    5556           0 : }
    5557           0 : 
    5558           0 : DOMImplementation*
    5559           0 : nsIDocument::GetImplementation(ErrorResult& rv)
    5560           0 : {
    5561             :   if (!mDOMImplementation) {
    5562           0 :     nsCOMPtr<nsIURI> uri;
    5563             :     NS_NewURI(getter_AddRefs(uri), "about:blank");
    5564           0 :     if (!uri) {
    5565           0 :       rv.Throw(NS_ERROR_OUT_OF_MEMORY);
    5566           0 :       return nullptr;
    5567           0 :     }
    5568             :     bool hasHadScriptObject = true;
    5569             :     nsIScriptGlobalObject* scriptObject =
    5570           0 :       GetScriptHandlingObject(hasHadScriptObject);
    5571             :     if (!scriptObject && hasHadScriptObject) {
    5572             :       rv.Throw(NS_ERROR_UNEXPECTED);
    5573           0 :       return nullptr;
    5574             :     }
    5575             :     mDOMImplementation = new DOMImplementation(this,
    5576           0 :       scriptObject ? scriptObject : GetScopeObject(), uri, uri);
    5577             :   }
    5578           0 : 
    5579           0 :   return mDOMImplementation;
    5580           0 : }
    5581           0 : 
    5582             : bool IsLowercaseASCII(const nsAString& aValue)
    5583             : {
    5584             :   int32_t len = aValue.Length();
    5585             :   for (int32_t i = 0; i < len; ++i) {
    5586             :     char16_t c = aValue[i];
    5587             :     if (!(0x0061 <= (c) && ((c) <= 0x007a))) {
    5588             :       return false;
    5589             :     }
    5590           0 :   }
    5591             :   return true;
    5592           0 : }
    5593           0 : 
    5594           0 : // We only support pseudo-elements with two colons in this function.
    5595           0 : static CSSPseudoElementType
    5596             : GetPseudoElementType(const nsString& aString, ErrorResult& aRv)
    5597           0 : {
    5598           0 :   MOZ_ASSERT(!aString.IsEmpty(), "GetPseudoElementType aString should be non-null");
    5599           0 :   if (aString.Length() <= 2 || aString[0] != ':' || aString[1] != ':') {
    5600             :     aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
    5601             :     return CSSPseudoElementType::NotPseudo;
    5602             :   }
    5603          53 :   RefPtr<nsAtom> pseudo = NS_Atomize(Substring(aString, 1));
    5604             :   return nsCSSPseudoElements::GetPseudoType(pseudo,
    5605             :       CSSEnabledState::eInUASheets);
    5606             : }
    5607         106 : 
    5608         106 : already_AddRefed<Element>
    5609             : nsIDocument::CreateElement(const nsAString& aTagName,
    5610             :                            const ElementCreationOptionsOrString& aOptions,
    5611             :                            ErrorResult& rv)
    5612           0 : {
    5613           0 :   rv = nsContentUtils::CheckQName(aTagName, false);
    5614           0 :   if (rv.Failed()) {
    5615           0 :     return nullptr;
    5616             :   }
    5617             : 
    5618          53 :   bool needsLowercase = IsHTMLDocument() && !IsLowercaseASCII(aTagName);
    5619           0 :   nsAutoString lcTagName;
    5620          53 :   if (needsLowercase) {
    5621             :     nsContentUtils::ASCIIToLower(aTagName, lcTagName);
    5622           0 :   }
    5623             : 
    5624           1 :   const nsString* is = nullptr;
    5625         106 :   CSSPseudoElementType pseudoType = CSSPseudoElementType::NotPseudo;
    5626           0 :   if (aOptions.IsElementCreationOptions()) {
    5627             :     const ElementCreationOptions& options =
    5628             :       aOptions.GetAsElementCreationOptions();
    5629             : 
    5630             :     if (CustomElementRegistry::IsCustomElementEnabled(this) &&
    5631         106 :         options.mIs.WasPassed()) {
    5632           0 :       is = &options.mIs.Value();
    5633           0 :     }
    5634           0 : 
    5635           0 :     // Check 'pseudo' and throw an exception if it's not one allowed
    5636           0 :     // with CSS_PSEUDO_ELEMENT_IS_JS_CREATED_NAC.
    5637             :     if (options.mPseudo.WasPassed()) {
    5638             :       pseudoType = GetPseudoElementType(options.mPseudo.Value(), rv);
    5639             :       if (rv.Failed() ||
    5640             :           pseudoType == CSSPseudoElementType::NotPseudo ||
    5641             :           !nsCSSPseudoElements::PseudoElementIsJSCreatedNAC(pseudoType)) {
    5642         106 :         rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
    5643         159 :         return nullptr;
    5644             :       }
    5645          53 :     }
    5646           0 :   }
    5647             : 
    5648             :   RefPtr<Element> elem = CreateElem(
    5649           0 :     needsLowercase ? lcTagName : aTagName, nullptr, mDefaultElementType, is);
    5650           0 : 
    5651             :   if (pseudoType != CSSPseudoElementType::NotPseudo) {
    5652             :     elem->SetPseudoElementType(pseudoType);
    5653          53 :   }
    5654             : 
    5655             :   if (is) {
    5656             :     elem->SetAttr(kNameSpaceID_None, nsGkAtoms::is, *is, true);
    5657           6 :   }
    5658             : 
    5659             :   return elem.forget();
    5660             : }
    5661             : 
    5662          12 : already_AddRefed<Element>
    5663           6 : nsIDocument::CreateElementNS(const nsAString& aNamespaceURI,
    5664             :                              const nsAString& aQualifiedName,
    5665             :                              const ElementCreationOptionsOrString& aOptions,
    5666             :                              ErrorResult& rv)
    5667          12 : {
    5668          12 :   RefPtr<mozilla::dom::NodeInfo> nodeInfo;
    5669             :   rv = nsContentUtils::GetNodeInfoFromQName(aNamespaceURI,
    5670             :                                             aQualifiedName,
    5671             :                                             mNodeInfoManager,
    5672           0 :                                             ELEMENT_NODE,
    5673          12 :                                             getter_AddRefs(nodeInfo));
    5674           6 :   if (rv.Failed()) {
    5675           0 :     return nullptr;
    5676           0 :   }
    5677           0 : 
    5678             :   const nsString* is = nullptr;
    5679             :   if (CustomElementRegistry::IsCustomElementEnabled(this) &&
    5680             :       aOptions.IsElementCreationOptions()) {
    5681           0 :     const ElementCreationOptions& options = aOptions.GetAsElementCreationOptions();
    5682           0 :     if (options.mIs.WasPassed()) {
    5683           0 :       is = &options.mIs.Value();
    5684          12 :     }
    5685             :   }
    5686             : 
    5687             :   nsCOMPtr<Element> element;
    5688           0 :   rv = NS_NewElement(getter_AddRefs(element), nodeInfo.forget(),
    5689           0 :                      NOT_FROM_PARSER, is);
    5690             :   if (rv.Failed()) {
    5691             :     return nullptr;
    5692           0 :   }
    5693             : 
    5694             :   if (is) {
    5695             :     element->SetAttr(kNameSpaceID_None, nsGkAtoms::is, *is, true);
    5696           0 :   }
    5697             : 
    5698           0 :   return element.forget();
    5699           0 : }
    5700             : 
    5701             : already_AddRefed<nsTextNode>
    5702             : nsIDocument::CreateEmptyTextNode() const
    5703           0 : {
    5704             :   RefPtr<nsTextNode> text = new nsTextNode(mNodeInfoManager);
    5705           0 :   return text.forget();
    5706             : }
    5707           0 : 
    5708           0 : already_AddRefed<nsTextNode>
    5709             : nsIDocument::CreateTextNode(const nsAString& aData) const
    5710             : {
    5711             :   RefPtr<nsTextNode> text = new nsTextNode(mNodeInfoManager);
    5712           0 :   // Don't notify; this node is still being created.
    5713             :   text->SetText(aData, false);
    5714           0 :   return text.forget();
    5715           0 : }
    5716             : 
    5717             : already_AddRefed<DocumentFragment>
    5718             : nsIDocument::CreateDocumentFragment() const
    5719             : {
    5720           0 :   RefPtr<DocumentFragment> frag = new DocumentFragment(mNodeInfoManager);
    5721             :   return frag.forget();
    5722           0 : }
    5723             : 
    5724             : // Unfortunately, bareword "Comment" is ambiguous with some Mac system headers.
    5725           0 : already_AddRefed<dom::Comment>
    5726           0 : nsIDocument::CreateComment(const nsAString& aData) const
    5727             : {
    5728             :   RefPtr<dom::Comment> comment = new dom::Comment(mNodeInfoManager);
    5729             : 
    5730           0 :   // Don't notify; this node is still being created.
    5731             :   comment->SetText(aData, false);
    5732             :   return comment.forget();
    5733           0 : }
    5734           0 : 
    5735             : already_AddRefed<CDATASection>
    5736             : nsIDocument::CreateCDATASection(const nsAString& aData,
    5737             :                                 ErrorResult& rv)
    5738           0 : {
    5739           0 :   if (IsHTMLDocument()) {
    5740             :     rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
    5741             :     return nullptr;
    5742             :   }
    5743           0 : 
    5744             :   if (FindInReadable(NS_LITERAL_STRING("]]>"), aData)) {
    5745             :     rv.Throw(NS_ERROR_DOM_INVALID_CHARACTER_ERR);
    5746           0 :     return nullptr;
    5747             :   }
    5748           0 : 
    5749             :   RefPtr<CDATASection> cdata = new CDATASection(mNodeInfoManager);
    5750             : 
    5751             :   // Don't notify; this node is still being created.
    5752           0 :   cdata->SetText(aData, false);
    5753             : 
    5754             :   return cdata.forget();
    5755             : }
    5756           0 : 
    5757           0 : already_AddRefed<ProcessingInstruction>
    5758           0 : nsIDocument::CreateProcessingInstruction(const nsAString& aTarget,
    5759             :                                          const nsAString& aData,
    5760             :                                          ErrorResult& rv) const
    5761             : {
    5762           0 :   nsresult res = nsContentUtils::CheckQName(aTarget, false);
    5763           0 :   if (NS_FAILED(res)) {
    5764             :     rv.Throw(res);
    5765             :     return nullptr;
    5766             :   }
    5767             : 
    5768           0 :   if (FindInReadable(NS_LITERAL_STRING("?>"), aData)) {
    5769             :     rv.Throw(NS_ERROR_DOM_INVALID_CHARACTER_ERR);
    5770           0 :     return nullptr;
    5771             :   }
    5772             : 
    5773             :   RefPtr<ProcessingInstruction> pi =
    5774           0 :     NS_NewXMLProcessingInstruction(mNodeInfoManager, aTarget, aData);
    5775             : 
    5776           0 :   return pi.forget();
    5777           0 : }
    5778             : 
    5779             : already_AddRefed<Attr>
    5780             : nsIDocument::CreateAttribute(const nsAString& aName, ErrorResult& rv)
    5781           0 : {
    5782           0 :   if (!mNodeInfoManager) {
    5783           0 :     rv.Throw(NS_ERROR_NOT_INITIALIZED);
    5784             :     return nullptr;
    5785             :   }
    5786             : 
    5787           0 :   nsresult res = nsContentUtils::CheckQName(aName, false);
    5788           0 :   if (NS_FAILED(res)) {
    5789           0 :     rv.Throw(res);
    5790             :     return nullptr;
    5791             :   }
    5792             : 
    5793             :   nsAutoString name;
    5794           0 :   if (IsHTMLDocument()) {
    5795           0 :     nsContentUtils::ASCIIToLower(aName, name);
    5796           0 :   } else {
    5797           0 :     name = aName;
    5798           0 :   }
    5799             : 
    5800             :   RefPtr<mozilla::dom::NodeInfo> nodeInfo;
    5801             :   res = mNodeInfoManager->GetNodeInfo(name, nullptr, kNameSpaceID_None,
    5802           0 :                                       ATTRIBUTE_NODE, getter_AddRefs(nodeInfo));
    5803           0 :   if (NS_FAILED(res)) {
    5804           0 :     rv.Throw(res);
    5805             :     return nullptr;
    5806             :   }
    5807             : 
    5808           0 :   RefPtr<Attr> attribute = new Attr(nullptr, nodeInfo.forget(),
    5809             :                                     EmptyString());
    5810             :   return attribute.forget();
    5811             : }
    5812           0 : 
    5813           0 : already_AddRefed<Attr>
    5814             : nsIDocument::CreateAttributeNS(const nsAString& aNamespaceURI,
    5815             :                                const nsAString& aQualifiedName,
    5816             :                                ErrorResult& rv)
    5817           0 : {
    5818           0 :   RefPtr<mozilla::dom::NodeInfo> nodeInfo;
    5819             :   rv = nsContentUtils::GetNodeInfoFromQName(aNamespaceURI,
    5820             :                                             aQualifiedName,
    5821             :                                             mNodeInfoManager,
    5822           0 :                                             ATTRIBUTE_NODE,
    5823           0 :                                             getter_AddRefs(nodeInfo));
    5824           0 :   if (rv.Failed()) {
    5825             :     return nullptr;
    5826             :   }
    5827             : 
    5828         543 :   RefPtr<Attr> attribute = new Attr(nullptr, nodeInfo.forget(),
    5829             :                                     EmptyString());
    5830        1679 :   return attribute.forget();
    5831           0 : }
    5832          25 : 
    5833             : void
    5834           1 : nsIDocument::ResolveScheduledSVGPresAttrs()
    5835         543 : {
    5836             :   for (auto iter = mLazySVGPresElements.Iter(); !iter.Done(); iter.Next()) {
    5837             :     nsSVGElement* svg = iter.Get()->GetKey();
    5838           0 :     svg->UpdateContentDeclarationBlock();
    5839             :   }
    5840           0 :   mLazySVGPresElements.Clear();
    5841             : }
    5842           0 : 
    5843           0 : already_AddRefed<nsSimpleContentList>
    5844             : nsIDocument::BlockedTrackingNodes() const
    5845           0 : {
    5846           0 :   RefPtr<nsSimpleContentList> list = new nsSimpleContentList(nullptr);
    5847           0 : 
    5848             :   nsTArray<nsWeakPtr> blockedTrackingNodes;
    5849             :   blockedTrackingNodes = mBlockedTrackingNodes;
    5850             : 
    5851           0 :   for (unsigned long i = 0; i < blockedTrackingNodes.Length(); i++) {
    5852           0 :     nsWeakPtr weakNode = blockedTrackingNodes[i];
    5853             :     nsCOMPtr<nsIContent> node = do_QueryReferent(weakNode);
    5854             :     // Consider only nodes to which we have managed to get strong references.
    5855             :     // Coping with nullptrs since it's expected for nodes to disappear when
    5856           0 :     // nobody else is referring to them.
    5857             :     if (node) {
    5858             :       list->AppendElement(node);
    5859             :     }
    5860           0 :   }
    5861             : 
    5862           0 :   return list.forget();
    5863             : }
    5864             : 
    5865           0 : void
    5866           0 : nsIDocument::GetSelectedStyleSheetSet(nsAString& aSheetSet)
    5867           0 : {
    5868           0 :   aSheetSet.Truncate();
    5869           0 : 
    5870             :   // Look through our sheets, find the selected set title
    5871           0 :   size_t count = SheetCount();
    5872             :   nsAutoString title;
    5873             :   for (size_t index = 0; index < count; index++) {
    5874             :     StyleSheet* sheet = SheetAt(index);
    5875             :     NS_ASSERTION(sheet, "Null sheet in sheet list!");
    5876           0 : 
    5877             :     if (sheet->Disabled()) {
    5878           0 :       // Disabled sheets don't affect the currently selected set
    5879             :       continue;
    5880           0 :     }
    5881             : 
    5882           0 :     sheet->GetTitle(title);
    5883           0 : 
    5884             :     if (aSheetSet.IsEmpty()) {
    5885             :       aSheetSet = title;
    5886             :     } else if (!title.IsEmpty() && !aSheetSet.Equals(title)) {
    5887             :       // Sheets from multiple sets enabled; return null string, per spec.
    5888             :       SetDOMStringToNull(aSheetSet);
    5889           0 :       return;
    5890             :     }
    5891           0 :   }
    5892             : }
    5893             : 
    5894             : void
    5895             : nsIDocument::SetSelectedStyleSheetSet(const nsAString& aSheetSet)
    5896             : {
    5897           0 :   if (DOMStringIsNull(aSheetSet)) {
    5898           0 :     return;
    5899             :   }
    5900             : 
    5901             :   // Must update mLastStyleSheetSet before doing anything else with stylesheets
    5902           0 :   // or CSSLoaders.
    5903             :   mLastStyleSheetSet = aSheetSet;
    5904           0 :   EnableStyleSheetsForSetInternal(aSheetSet, true);
    5905             : }
    5906             : 
    5907           0 : void
    5908             : nsIDocument::SetPreferredStyleSheetSet(const nsAString& aSheetSet)
    5909             : {
    5910             :   mPreferredStyleSheetSet = aSheetSet;
    5911             :   // Only mess with our stylesheets if we don't have a lastStyleSheetSet, per
    5912             :   // spec.
    5913           0 :   if (DOMStringIsNull(mLastStyleSheetSet)) {
    5914             :     // Calling EnableStyleSheetsForSetInternal, not SetSelectedStyleSheetSet,
    5915           0 :     // per spec.  The idea here is that we're changing our preferred set and
    5916             :     // that shouldn't change the value of lastStyleSheetSet.  Also, we're
    5917             :     // using the Internal version so we can update the CSSLoader and not have
    5918           0 :     // to worry about null strings.
    5919             :     EnableStyleSheetsForSetInternal(aSheetSet, true);
    5920           0 :   }
    5921           0 : }
    5922             : 
    5923           0 : DOMStringList*
    5924             : nsIDocument::StyleSheetSets()
    5925             : {
    5926             :   if (!mStyleSheetSetList) {
    5927           0 :     mStyleSheetSetList = new nsDOMStyleSheetSetList(this);
    5928             :   }
    5929             :   return mStyleSheetSetList;
    5930           0 : }
    5931             : 
    5932             : void
    5933             : nsIDocument::EnableStyleSheetsForSet(const nsAString& aSheetSet)
    5934             : {
    5935           0 :   // Per spec, passing in null is a no-op.
    5936             :   if (!DOMStringIsNull(aSheetSet)) {
    5937           0 :     // Note: must make sure to not change the CSSLoader's preferred sheet --
    5938             :     // that value should be equal to either our lastStyleSheetSet (if that's
    5939             :     // non-null) or to our preferredStyleSheetSet.  And this method doesn't
    5940           0 :     // change either of those.
    5941             :     EnableStyleSheetsForSetInternal(aSheetSet, false);
    5942             :   }
    5943           0 : }
    5944           0 : 
    5945           0 : void
    5946           0 : nsIDocument::EnableStyleSheetsForSetInternal(const nsAString& aSheetSet,
    5947           0 :                                              bool aUpdateCSSLoader)
    5948             : {
    5949           0 :   size_t count = SheetCount();
    5950           0 :   nsAutoString title;
    5951           0 :   for (size_t index = 0; index < count; index++) {
    5952             :     StyleSheet* sheet = SheetAt(index);
    5953             :     NS_ASSERTION(sheet, "Null sheet in sheet list!");
    5954           0 : 
    5955           0 :     sheet->GetTitle(title);
    5956             :     if (!title.IsEmpty()) {
    5957           0 :       sheet->SetEnabled(title.Equals(aSheetSet));
    5958           0 :     }
    5959           0 :   }
    5960             :   if (aUpdateCSSLoader) {
    5961             :     CSSLoader()->DocumentStyleSheetSetChanged();
    5962           0 :   }
    5963             :   if (nsIPresShell* shell = GetShell()) {
    5964             :     if (shell->StyleSet()->StyleSheetsHaveChanged()) {
    5965           0 :       shell->ApplicableStylesChanged();
    5966             :     }
    5967           0 :   }
    5968           0 : }
    5969           0 : 
    5970           0 : void
    5971             : nsIDocument::GetCharacterSet(nsAString& aCharacterSet) const
    5972             : {
    5973           0 :   nsAutoCString charset;
    5974             :   GetDocumentCharacterSet()->Name(charset);
    5975           0 :   CopyASCIItoUTF16(charset, aCharacterSet);
    5976             : }
    5977           0 : 
    5978             : already_AddRefed<nsINode>
    5979             : nsIDocument::ImportNode(nsINode& aNode, bool aDeep, ErrorResult& rv) const
    5980             : {
    5981             :   nsINode* imported = &aNode;
    5982             : 
    5983             :   switch (imported->NodeType()) {
    5984             :     case DOCUMENT_NODE:
    5985             :     {
    5986             :       break;
    5987             :     }
    5988             :     case DOCUMENT_FRAGMENT_NODE:
    5989             :     case ATTRIBUTE_NODE:
    5990             :     case ELEMENT_NODE:
    5991           0 :     case PROCESSING_INSTRUCTION_NODE:
    5992             :     case TEXT_NODE:
    5993             :     case CDATA_SECTION_NODE:
    5994             :     case COMMENT_NODE:
    5995           0 :     case DOCUMENT_TYPE_NODE:
    5996             :     {
    5997             :       return nsNodeUtils::Clone(imported, aDeep, mNodeInfoManager, nullptr, rv);
    5998             :     }
    5999           0 :     default:
    6000             :     {
    6001             :       NS_WARNING("Don't know how to clone this nodetype for importNode.");
    6002             :     }
    6003             :   }
    6004           0 : 
    6005             :   rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
    6006             :   return nullptr;
    6007             : }
    6008           0 : 
    6009           0 : void
    6010           0 : nsIDocument::LoadBindingDocument(const nsAString& aURI,
    6011           0 :                                  nsIPrincipal& aSubjectPrincipal,
    6012             :                                  ErrorResult& rv)
    6013             : {
    6014           0 :   nsCOMPtr<nsIURI> uri;
    6015             :   rv = NS_NewURI(getter_AddRefs(uri), aURI, mCharacterSet, GetDocBaseURI());
    6016             :   if (rv.Failed()) {
    6017             :     return;
    6018           0 :   }
    6019             : 
    6020           0 :   BindingManager()->LoadBindingDocument(this, uri, &aSubjectPrincipal);
    6021           0 : }
    6022             : 
    6023             : Element*
    6024           0 : nsIDocument::GetBindingParent(nsINode& aNode)
    6025           0 : {
    6026             :   nsCOMPtr<nsIContent> content(do_QueryInterface(&aNode));
    6027             :   if (!content)
    6028             :     return nullptr;
    6029          16 : 
    6030             :   nsIContent* bindingParent = content->GetBindingParent();
    6031             :   return bindingParent ? bindingParent->AsElement() : nullptr;
    6032           0 : }
    6033             : 
    6034             : static Element*
    6035             : GetElementByAttribute(Element* aElement, nsAtom* aAttrName,
    6036             :                       const nsAString& aAttrValue, bool aUniversalMatch)
    6037             : {
    6038          20 :   if (aUniversalMatch ? aElement->HasAttr(kNameSpaceID_None, aAttrName) :
    6039          20 :                         aElement->AttrValueIs(kNameSpaceID_None, aAttrName,
    6040           8 :                                               aAttrValue, eCaseMatters)) {
    6041          24 :     return aElement;
    6042             :   }
    6043             : 
    6044             :   for (nsIContent* child = aElement->GetFirstChild();
    6045             :        child;
    6046          10 :        child = child->GetNextSibling()) {
    6047          10 :     if (!child->IsElement()) {
    6048           0 :       continue;
    6049             :     }
    6050             : 
    6051             :     Element* matchedElement =
    6052             :       GetElementByAttribute(child->AsElement(), aAttrName, aAttrValue,
    6053             :                             aUniversalMatch);
    6054             :     if (matchedElement)
    6055             :       return matchedElement;
    6056           0 :   }
    6057             : 
    6058             :   return nullptr;
    6059             : }
    6060           8 : 
    6061           1 : Element*
    6062             : nsIDocument::GetAnonymousElementByAttribute(nsIContent* aElement,
    6063             :                                             nsAtom* aAttrName,
    6064           4 :                                             const nsAString& aAttrValue) const
    6065             : {
    6066           1 :   nsINodeList* nodeList = BindingManager()->GetAnonymousNodesFor(aElement);
    6067             :   if (!nodeList)
    6068           1 :     return nullptr;
    6069          12 : 
    6070           6 :   uint32_t length = nodeList->Length();
    6071             : 
    6072             :   bool universalMatch = aAttrValue.EqualsLiteral("*");
    6073             : 
    6074             :   for (uint32_t i = 0; i < length; ++i) {
    6075           0 :     Element* current = Element::FromNode(nodeList->Item(i));
    6076           6 :     if (!current) {
    6077             :       continue;
    6078             :     }
    6079             : 
    6080             :     Element* matchedElm =
    6081             :       GetElementByAttribute(current, aAttrName, aAttrValue, universalMatch);
    6082             :     if (matchedElm)
    6083             :       return matchedElm;
    6084           4 :   }
    6085             : 
    6086             :   return nullptr;
    6087             : }
    6088          12 : 
    6089             : Element*
    6090           8 : nsIDocument::GetAnonymousElementByAttribute(Element& aElement,
    6091             :                                             const nsAString& aAttrName,
    6092             :                                             const nsAString& aAttrValue)
    6093             : {
    6094           0 :   RefPtr<nsAtom> attribute = NS_Atomize(aAttrName);
    6095             : 
    6096           0 :   return GetAnonymousElementByAttribute(&aElement, attribute, aAttrValue);
    6097             : }
    6098             : 
    6099             : nsINodeList*
    6100           0 : nsIDocument::GetAnonymousNodes(Element& aElement)
    6101             : {
    6102           0 :   return BindingManager()->GetAnonymousNodesFor(&aElement);
    6103           0 : }
    6104           0 : 
    6105           0 : already_AddRefed<nsRange>
    6106             : nsIDocument::CreateRange(ErrorResult& rv)
    6107             : {
    6108             :   RefPtr<nsRange> range = new nsRange(this);
    6109             :   nsresult res = range->CollapseTo(this, 0);
    6110             :   if (NS_FAILED(res)) {
    6111             :     rv.Throw(res);
    6112             :     return nullptr;
    6113           0 :   }
    6114             : 
    6115             :   return range.forget();
    6116             : }
    6117             : 
    6118           0 : already_AddRefed<NodeIterator>
    6119           0 : nsIDocument::CreateNodeIterator(nsINode& aRoot, uint32_t aWhatToShow,
    6120             :                                 NodeFilter* aFilter,
    6121             :                                 ErrorResult& rv) const
    6122             : {
    6123           0 :   RefPtr<NodeIterator> iterator = new NodeIterator(&aRoot, aWhatToShow,
    6124             :                                                    aFilter);
    6125             :   return iterator.forget();
    6126             : }
    6127           0 : 
    6128           0 : already_AddRefed<TreeWalker>
    6129             : nsIDocument::CreateTreeWalker(nsINode& aRoot, uint32_t aWhatToShow,
    6130             :                               NodeFilter* aFilter,
    6131             :                               ErrorResult& rv) const
    6132             : {
    6133           0 :   RefPtr<TreeWalker> walker = new TreeWalker(&aRoot, aWhatToShow, aFilter);
    6134             :   return walker.forget();
    6135           8 : }
    6136             : 
    6137           2 : 
    6138             : already_AddRefed<Location>
    6139             : nsIDocument::GetLocation() const
    6140             : {
    6141           0 :   nsCOMPtr<nsPIDOMWindowInner> w = do_QueryInterface(mScriptGlobalObject);
    6142           4 : 
    6143           2 :   if (!w) {
    6144             :     return nullptr;
    6145             :   }
    6146             : 
    6147           0 :   nsGlobalWindowInner* window = nsGlobalWindowInner::Cast(w);
    6148             :   RefPtr<Location> loc = window->GetLocation();
    6149          66 :   return loc.forget();
    6150          66 : }
    6151             : 
    6152          30 : Element*
    6153             : nsIDocument::GetHtmlElement() const
    6154             : {
    6155             :   Element* rootElement = GetRootElement();
    6156          66 :   if (rootElement && rootElement->IsHTMLElement(nsGkAtoms::html))
    6157             :     return rootElement;
    6158          66 :   return nullptr;
    6159           0 : }
    6160             : 
    6161             : Element*
    6162             : nsIDocument::GetHtmlChildElement(nsAtom* aTag)
    6163             : {
    6164          97 :   Element* html = GetHtmlElement();
    6165          97 :   if (!html)
    6166          61 :     return nullptr;
    6167          97 : 
    6168          36 :   // Look for the element with aTag inside html. This needs to run
    6169             :   // forwards to find the first such element.
    6170             :   for (nsIContent* child = html->GetFirstChild();
    6171             :        child;
    6172             :        child = child->GetNextSibling()) {
    6173             :     if (child->IsHTMLElement(aTag))
    6174           0 :       return child->AsElement();
    6175             :   }
    6176           0 :   return nullptr;
    6177           0 : }
    6178             : 
    6179             : nsGenericHTMLElement*
    6180             : nsIDocument::GetBody()
    6181           0 : {
    6182           0 :   Element* html = GetHtmlElement();
    6183           0 :   if (!html) {
    6184           0 :     return nullptr;
    6185           0 :   }
    6186             : 
    6187             :   for (nsIContent* child = html->GetFirstChild();
    6188             :        child;
    6189             :        child = child->GetNextSibling()) {
    6190             :     if (child->IsHTMLElement(nsGkAtoms::body) ||
    6191             :         child->IsHTMLElement(nsGkAtoms::frameset)) {
    6192             :       return static_cast<nsGenericHTMLElement*>(child);
    6193             :     }
    6194           0 :   }
    6195             : 
    6196           0 :   return nullptr;
    6197             : }
    6198             : 
    6199             : void
    6200           0 : nsIDocument::SetBody(nsGenericHTMLElement* newBody, ErrorResult& rv)
    6201           0 : {
    6202           0 :   nsCOMPtr<Element> root = GetRootElement();
    6203           0 : 
    6204           0 :   // The body element must be either a body tag or a frameset tag. And we must
    6205             :   // have a root element to be able to add kids to it.
    6206             :   if (!newBody ||
    6207             :       !newBody->IsAnyOfHTMLElements(nsGkAtoms::body, nsGkAtoms::frameset) ||
    6208           0 :       !root) {
    6209           0 :     rv.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
    6210           0 :     return;
    6211             :   }
    6212           0 : 
    6213             :   // Use DOM methods so that we pass through the appropriate security checks.
    6214             :   nsCOMPtr<Element> currentBody = GetBody();
    6215             :   if (currentBody) {
    6216             :     root->ReplaceChild(*newBody, *currentBody, rv);
    6217           0 :   } else {
    6218             :     root->AppendChild(*newBody, rv);
    6219           0 :   }
    6220             : }
    6221             : 
    6222             : HTMLSharedElement*
    6223           0 : nsIDocument::GetHead()
    6224             : {
    6225             :   return static_cast<HTMLSharedElement*>(GetHeadElement());
    6226             : }
    6227             : 
    6228             : Element*
    6229             : nsIDocument::GetTitleElement()
    6230          51 : {
    6231             :   // mMayHaveTitleElement will have been set to true if any HTML or SVG
    6232             :   // <title> element has been bound to this document. So if it's false,
    6233           0 :   // we know there is nothing to do here. This avoids us having to search
    6234           0 :   // the whole DOM if someone calls document.title on a large document
    6235             :   // without a title.
    6236           0 :   if (!mMayHaveTitleElement)
    6237           0 :     return nullptr;
    6238           0 : 
    6239           0 :   Element* root = GetRootElement();
    6240             :   if (root && root->IsSVGElement(nsGkAtoms::svg)) {
    6241             :     // In SVG, the document's title must be a child
    6242             :     for (nsIContent* child = root->GetFirstChild();
    6243             :          child; child = child->GetNextSibling()) {
    6244             :       if (child->IsSVGElement(nsGkAtoms::title)) {
    6245             :         return child->AsElement();
    6246             :       }
    6247             :     }
    6248             :     return nullptr;
    6249             :   }
    6250             : 
    6251             :   // We check the HTML namespace even for non-HTML documents, except SVG.  This
    6252           4 :   // matches the spec and the behavior of all tested browsers.
    6253             :   // We avoid creating a live nsContentList since we don't need to watch for DOM
    6254           2 :   // tree mutations.
    6255             :   RefPtr<nsContentList> list = new nsContentList(this, kNameSpaceID_XHTML,
    6256           2 :                                                  nsGkAtoms::title, nsGkAtoms::title,
    6257             :                                                  /* aDeep = */ true,
    6258             :                                                  /* aLiveList = */ false);
    6259             : 
    6260           0 :   nsIContent* first = list->Item(0, false);
    6261             : 
    6262          52 :   return first ? first->AsElement() : nullptr;
    6263             : }
    6264          52 : 
    6265           0 : void
    6266           0 : nsIDocument::GetTitle(nsAString& aTitle)
    6267             : {
    6268             :   aTitle.Truncate();
    6269           0 : 
    6270             :   Element* rootElement = GetRootElement();
    6271             :   if (!rootElement) {
    6272          52 :     return;
    6273           1 :   }
    6274             : 
    6275             :   nsAutoString tmp;
    6276             : 
    6277          51 : #ifdef MOZ_XUL
    6278          51 :   if (rootElement->IsXULElement()) {
    6279             :     rootElement->GetAttr(kNameSpaceID_None, nsGkAtoms::title, tmp);
    6280             :   } else
    6281           2 : #endif
    6282             :   {
    6283             :     Element* title = GetTitleElement();
    6284           3 :     if (!title) {
    6285           3 :       return;
    6286             :     }
    6287             :     nsContentUtils::GetNodeTextContent(title, false, tmp);
    6288             :   }
    6289           0 : 
    6290             :   tmp.CompressWhitespace();
    6291           0 :   aTitle = tmp;
    6292           0 : }
    6293           0 : 
    6294             : void
    6295             : nsIDocument::SetTitle(const nsAString& aTitle, ErrorResult& aRv)
    6296             : {
    6297           0 :   Element* rootElement = GetRootElement();
    6298           0 :   if (!rootElement) {
    6299             :     return;
    6300             :   }
    6301             : 
    6302             : #ifdef MOZ_XUL
    6303             :   if (rootElement->IsXULElement()) {
    6304             :     aRv = rootElement->SetAttr(kNameSpaceID_None, nsGkAtoms::title,
    6305             :                                aTitle, true);
    6306           0 :     return;
    6307             :   }
    6308           0 : #endif
    6309           0 : 
    6310           0 :   // Batch updates so that mutation events don't change "the title
    6311             :   // element" under us
    6312           0 :   mozAutoDocUpdate updateBatch(this, true);
    6313             : 
    6314           0 :   nsCOMPtr<Element> title = GetTitleElement();
    6315           0 :   if (rootElement->IsSVGElement(nsGkAtoms::svg)) {
    6316           0 :     if (!title) {
    6317           0 :       RefPtr<mozilla::dom::NodeInfo> titleInfo =
    6318           0 :         mNodeInfoManager->GetNodeInfo(nsGkAtoms::title, nullptr,
    6319             :                                       kNameSpaceID_SVG,
    6320           0 :                                       ELEMENT_NODE);
    6321             :       NS_NewSVGElement(getter_AddRefs(title), titleInfo.forget(),
    6322           0 :                        NOT_FROM_PARSER);
    6323           0 :       if (!title) {
    6324           0 :         return;
    6325           0 :       }
    6326           0 :       rootElement->InsertChildBefore(title, rootElement->GetFirstChild(), true);
    6327             :     }
    6328             :   } else if (rootElement->IsHTMLElement()) {
    6329           0 :     if (!title) {
    6330           0 :       Element* head = GetHeadElement();
    6331           0 :       if (!head) {
    6332           0 :         return;
    6333           0 :       }
    6334           0 : 
    6335             :       RefPtr<mozilla::dom::NodeInfo> titleInfo;
    6336             :       titleInfo = mNodeInfoManager->GetNodeInfo(nsGkAtoms::title, nullptr,
    6337           0 :           kNameSpaceID_XHTML, ELEMENT_NODE);
    6338             :       title = NS_NewHTMLTitleElement(titleInfo.forget());
    6339             :       if (!title) {
    6340             :         return;
    6341             :       }
    6342             : 
    6343           0 :       head->AppendChildTo(title, true);
    6344             :     }
    6345             :   } else {
    6346             :     return;
    6347          55 :   }
    6348             : 
    6349           0 :   aRv = nsContentUtils::SetNodeTextContent(title, aTitle, false);
    6350             : }
    6351          55 : 
    6352           3 : void
    6353             : nsIDocument::NotifyPossibleTitleChange(bool aBoundTitleElement)
    6354             : {
    6355           0 :   NS_ASSERTION(!mInUnlinkOrDeletion || !aBoundTitleElement,
    6356           2 :                "Setting a title while unlinking or destroying the element?");
    6357             :   if (mInUnlinkOrDeletion) {
    6358         110 :     return;
    6359             :   }
    6360             : 
    6361          52 :   if (aBoundTitleElement) {
    6362             :     mMayHaveTitleElement = true;
    6363           0 :   }
    6364             :   if (mPendingTitleChangeEvent.IsPending())
    6365           0 :     return;
    6366           0 : 
    6367           0 :   MOZ_RELEASE_ASSERT(NS_IsMainThread());
    6368          52 :   RefPtr<nsRunnableMethod<nsIDocument, void, false>> event =
    6369             :     NewNonOwningRunnableMethod("nsIDocument::DoNotifyPossibleTitleChange",
    6370             :                                this,
    6371             :                                &nsIDocument::DoNotifyPossibleTitleChange);
    6372             :   nsresult rv = Dispatch(TaskCategory::Other, do_AddRef(event));
    6373           0 :   if (NS_SUCCEEDED(rv)) {
    6374             :     mPendingTitleChangeEvent = std::move(event);
    6375           1 :   }
    6376          52 : }
    6377             : 
    6378         104 : void
    6379           0 : nsIDocument::DoNotifyPossibleTitleChange()
    6380             : {
    6381           0 :   mPendingTitleChangeEvent.Forget();
    6382           0 :   mHaveFiredTitleChange = true;
    6383             : 
    6384          57 :   nsAutoString title;
    6385          19 :   GetTitle(title);
    6386           0 : 
    6387           0 :   nsCOMPtr<nsIPresShell> shell = GetShell();
    6388           0 :   if (shell) {
    6389             :     nsCOMPtr<nsISupports> container =
    6390             :       shell->GetPresContext()->GetContainerWeak();
    6391             :     if (container) {
    6392             :       nsCOMPtr<nsIBaseWindow> docShellWin = do_QueryInterface(container);
    6393             :       if (docShellWin) {
    6394           0 :         docShellWin->SetTitle(title);
    6395          52 :       }
    6396         156 :     }
    6397          52 :   }
    6398             : 
    6399             :   // Fire a DOM event for the title change.
    6400           0 :   nsContentUtils::DispatchChromeEvent(this, static_cast<nsIDocument*>(this),
    6401             :                                       NS_LITERAL_STRING("DOMTitleChanged"),
    6402           2 :                                       true, true);
    6403           0 : }
    6404             : 
    6405             : already_AddRefed<BoxObject>
    6406             : nsIDocument::GetBoxObjectFor(Element* aElement, ErrorResult& aRv)
    6407           2 : {
    6408           0 :   if (!aElement) {
    6409           0 :     aRv.Throw(NS_ERROR_UNEXPECTED);
    6410             :     return nullptr;
    6411             :   }
    6412             : 
    6413           0 :   nsIDocument* doc = aElement->OwnerDoc();
    6414           0 :   if (doc != this) {
    6415           0 :     aRv.Throw(NS_ERROR_DOM_WRONG_DOCUMENT_ERR);
    6416           0 :     return nullptr;
    6417             :   }
    6418           0 : 
    6419             :   if (!mHasWarnedAboutBoxObjects && !aElement->IsXULElement()) {
    6420             :     mHasWarnedAboutBoxObjects = true;
    6421           2 :     nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
    6422           0 :                                     NS_LITERAL_CSTRING("BoxObjects"), this,
    6423             :                                     nsContentUtils::eDOM_PROPERTIES,
    6424             :                                     "UseOfGetBoxObjectForWarning");
    6425           0 :   }
    6426           4 : 
    6427           2 :   if (!mBoxObjectTable) {
    6428           0 :     mBoxObjectTable = new nsRefPtrHashtable<nsPtrHashKey<nsIContent>, BoxObject>(6);
    6429             :   }
    6430             : 
    6431             :   RefPtr<BoxObject> boxObject;
    6432             :   auto entry = mBoxObjectTable->LookupForAdd(aElement);
    6433           0 :   if (entry) {
    6434             :     boxObject = entry.Data();
    6435           0 :     return boxObject.forget();
    6436           0 :   }
    6437           1 : 
    6438           0 :   int32_t namespaceID;
    6439           0 :   RefPtr<nsAtom> tag = BindingManager()->ResolveTag(aElement, &namespaceID);
    6440           2 : #ifdef MOZ_XUL
    6441           0 :   if (namespaceID == kNameSpaceID_XUL) {
    6442           0 :     if (tag == nsGkAtoms::menu) {
    6443           0 :       boxObject = new MenuBoxObject();
    6444             :     } else if (tag == nsGkAtoms::tree) {
    6445           0 :       boxObject = new TreeBoxObject();
    6446             :     } else if (tag == nsGkAtoms::listbox) {
    6447             :       boxObject = new ListBoxObject();
    6448             :     } else if (tag == nsGkAtoms::scrollbox) {
    6449             :       boxObject = new ScrollBoxObject();
    6450           0 :     } else {
    6451             :       boxObject = new BoxObject();
    6452             :     }
    6453           0 :   } else
    6454           0 : #endif // MOZ_XUL
    6455             :   {
    6456           2 :     boxObject = new BoxObject();
    6457             :   }
    6458             : 
    6459             :   boxObject->Init(aElement);
    6460           1 :   entry.OrInsert([&boxObject]() { return boxObject; });
    6461             : 
    6462          93 :   return boxObject.forget();
    6463          64 : }
    6464           0 : 
    6465           0 : void
    6466           0 : nsIDocument::ClearBoxObjectFor(nsIContent* aContent)
    6467             : {
    6468             :   if (mBoxObjectTable) {
    6469          93 :     if (auto entry = mBoxObjectTable->Lookup(aContent)) {
    6470             :       nsPIBoxObject* boxObject = entry.Data();
    6471             :       boxObject->Clear();
    6472           0 :       entry.Remove();
    6473             :     }
    6474             :   }
    6475             : }
    6476           6 : 
    6477             : already_AddRefed<MediaQueryList>
    6478           0 : nsIDocument::MatchMedia(const nsAString& aMediaQueryList,
    6479             :                         CallerType aCallerType)
    6480           6 : {
    6481             :   RefPtr<MediaQueryList> result =
    6482             :     new MediaQueryList(this, aMediaQueryList, aCallerType);
    6483             : 
    6484           0 :   mDOMMediaQueryLists.insertBack(result);
    6485             : 
    6486           0 :   return result.forget();
    6487           0 : }
    6488             : 
    6489             : void
    6490           0 : nsIDocument::FlushSkinBindings()
    6491             : {
    6492           0 :   BindingManager()->FlushSkinBindings();
    6493           0 : }
    6494             : 
    6495             : void
    6496             : nsIDocument::SetMayStartLayout(bool aMayStartLayout)
    6497           0 : {
    6498             :   mMayStartLayout = aMayStartLayout;
    6499           0 :   if (MayStartLayout()) {
    6500             :     // Before starting layout, check whether we're a toplevel chrome
    6501          49 :     // window.  If we are, setup some state so that we don't have to restyle
    6502           0 :     // the whole tree after StartLayout.
    6503             :     if (nsCOMPtr<nsIXULWindow> win = GetXULWindowIfToplevelChrome()) {
    6504          20 :         // We're the chrome document!
    6505             :         win->BeforeStartLayout();
    6506             :     }
    6507           0 :     ReadyState state = GetReadyStateEnum();
    6508             :     if (state >= READYSTATE_INTERACTIVE) {
    6509             :       // DOMContentLoaded has fired already.
    6510           0 :       MaybeResolveReadyForIdle();
    6511             :     }
    6512           5 :   }
    6513             : }
    6514           5 : 
    6515             : nsresult
    6516           0 : nsIDocument::InitializeFrameLoader(nsFrameLoader* aLoader)
    6517           0 : {
    6518             :   mInitializableFrameLoaders.RemoveElement(aLoader);
    6519             :   // Don't even try to initialize.
    6520           0 :   if (mInDestructor) {
    6521           0 :     NS_WARNING("Trying to initialize a frame loader while"
    6522             :                "document is being deleted");
    6523           0 :     return NS_ERROR_FAILURE;
    6524             :   }
    6525           5 : 
    6526           0 :   mInitializableFrameLoaders.AppendElement(aLoader);
    6527          10 :   if (!mFrameLoaderRunner) {
    6528             :     mFrameLoaderRunner =
    6529             :       NewRunnableMethod("nsIDocument::MaybeInitializeFinalizeFrameLoaders",
    6530             :                         this,
    6531             :                         &nsIDocument::MaybeInitializeFinalizeFrameLoaders);
    6532             :     NS_ENSURE_TRUE(mFrameLoaderRunner, NS_ERROR_OUT_OF_MEMORY);
    6533           0 :     nsContentUtils::AddScriptRunner(mFrameLoaderRunner);
    6534             :   }
    6535           0 :   return NS_OK;
    6536           1 : }
    6537             : 
    6538             : nsresult
    6539             : nsIDocument::FinalizeFrameLoader(nsFrameLoader* aLoader, nsIRunnable* aFinalizer)
    6540           1 : {
    6541           0 :   mInitializableFrameLoaders.RemoveElement(aLoader);
    6542             :   if (mInDestructor) {
    6543           0 :     return NS_ERROR_FAILURE;
    6544             :   }
    6545           1 : 
    6546           2 :   mFrameLoaderFinalizers.AppendElement(aFinalizer);
    6547           0 :   if (!mFrameLoaderRunner) {
    6548             :     mFrameLoaderRunner =
    6549             :       NewRunnableMethod("nsIDocument::MaybeInitializeFinalizeFrameLoaders",
    6550             :                         this,
    6551             :                         &nsIDocument::MaybeInitializeFinalizeFrameLoaders);
    6552             :     NS_ENSURE_TRUE(mFrameLoaderRunner, NS_ERROR_OUT_OF_MEMORY);
    6553         703 :     nsContentUtils::AddScriptRunner(mFrameLoaderRunner);
    6554             :   }
    6555         703 :   return NS_OK;
    6556             : }
    6557             : 
    6558           0 : void
    6559           0 : nsIDocument::MaybeInitializeFinalizeFrameLoaders()
    6560             : {
    6561             :   if (mDelayFrameLoaderInitialization || mUpdateNestLevel != 0) {
    6562             :     // This method will be recalled when mUpdateNestLevel drops to 0,
    6563             :     // or when !mDelayFrameLoaderInitialization.
    6564           0 :     mFrameLoaderRunner = nullptr;
    6565         356 :     return;
    6566         267 :   }
    6567           0 : 
    6568             :   // We're not in an update, but it is not safe to run scripts, so
    6569           0 :   // postpone frameloader initialization and finalization.
    6570             :   if (!nsContentUtils::IsSafeToRunScript()) {
    6571           0 :     if (!mInDestructor && !mFrameLoaderRunner &&
    6572           0 :         (mInitializableFrameLoaders.Length() ||
    6573             :          mFrameLoaderFinalizers.Length())) {
    6574             :       mFrameLoaderRunner =
    6575             :         NewRunnableMethod("nsIDocument::MaybeInitializeFinalizeFrameLoaders",
    6576         248 :                           this,
    6577             :                           &nsIDocument::MaybeInitializeFinalizeFrameLoaders);
    6578             :       nsContentUtils::AddScriptRunner(mFrameLoaderRunner);
    6579             :     }
    6580             :     return;
    6581         511 :   }
    6582           0 :   mFrameLoaderRunner = nullptr;
    6583           0 : 
    6584           0 :   // Don't use a temporary array for mInitializableFrameLoaders, because
    6585           5 :   // loading a frame may cause some other frameloader to be removed from the
    6586             :   // array. But be careful to keep the loader alive when starting the load!
    6587             :   while (mInitializableFrameLoaders.Length()) {
    6588         496 :     RefPtr<nsFrameLoader> loader = mInitializableFrameLoaders[0];
    6589         248 :     mInitializableFrameLoaders.RemoveElementAt(0);
    6590           0 :     NS_ASSERTION(loader, "null frameloader in the array?");
    6591           1 :     loader->ReallyStartLoading();
    6592           0 :   }
    6593           0 : 
    6594             :   uint32_t length = mFrameLoaderFinalizers.Length();
    6595             :   if (length > 0) {
    6596             :     nsTArray<nsCOMPtr<nsIRunnable> > finalizers;
    6597             :     mFrameLoaderFinalizers.SwapElements(finalizers);
    6598             :     for (uint32_t i = 0; i < length; ++i) {
    6599           6 :       finalizers[i]->Run();
    6600             :     }
    6601          12 :   }
    6602           0 : }
    6603           0 : 
    6604           0 : void
    6605           0 : nsIDocument::TryCancelFrameLoaderInitialization(nsIDocShell* aShell)
    6606             : {
    6607             :   uint32_t length = mInitializableFrameLoaders.Length();
    6608             :   for (uint32_t i = 0; i < length; ++i) {
    6609             :     if (mInitializableFrameLoaders[i]->GetExistingDocShell() == aShell) {
    6610             :       mInitializableFrameLoaders.RemoveElementAt(i);
    6611           0 :       return;
    6612             :     }
    6613             :   }
    6614             : }
    6615           0 : 
    6616           0 : nsIDocument*
    6617           0 : nsIDocument::RequestExternalResource(nsIURI* aURI,
    6618           0 :                                      nsINode* aRequestingNode,
    6619             :                                      ExternalResourceLoad** aPendingLoad)
    6620           0 : {
    6621             :   MOZ_ASSERT(aURI, "Must have a URI");
    6622             :   MOZ_ASSERT(aRequestingNode, "Must have a node");
    6623           0 :   if (mDisplayDocument) {
    6624           0 :     return mDisplayDocument->RequestExternalResource(aURI,
    6625             :                                                      aRequestingNode,
    6626             :                                                      aPendingLoad);
    6627             :   }
    6628           1 : 
    6629             :   return mExternalResourceMap.RequestResource(aURI, aRequestingNode,
    6630         166 :                                               this, aPendingLoad);
    6631          53 : }
    6632             : 
    6633             : void
    6634         168 : nsIDocument::EnumerateExternalResources(nsSubDocEnumFunc aCallback, void* aData)
    6635             : {
    6636             :   mExternalResourceMap.EnumerateResources(aCallback, aData);
    6637             : }
    6638           0 : 
    6639             : nsSMILAnimationController*
    6640             : nsIDocument::GetAnimationController()
    6641           0 : {
    6642             :   // We create the animation controller lazily because most documents won't want
    6643             :   // one and only SVG documents and the like will call this
    6644          26 :   if (mAnimationController)
    6645             :     return mAnimationController;
    6646             :   // Refuse to create an Animation Controller for data documents.
    6647             :   if (mLoadedAsData || mLoadedAsInteractiveData)
    6648           0 :     return nullptr;
    6649           0 : 
    6650           0 :   mAnimationController = new nsSMILAnimationController(this);
    6651           0 : 
    6652             :   // If there's a presContext then check the animation mode and pause if
    6653             :   // necessary.
    6654             :   nsPresContext* context = GetPresContext();
    6655             :   if (mAnimationController && context &&
    6656             :       context->ImageAnimationMode() == imgIContainer::kDontAnimMode) {
    6657          13 :     mAnimationController->Pause(nsSMILTimeContainer::PAUSE_USERPREF);
    6658           0 :   }
    6659             : 
    6660             :   // If we're hidden (or being hidden), notify the newly-created animation
    6661           0 :   // controller. (Skip this check for SVG-as-an-image documents, though,
    6662             :   // because they don't get OnPageShow / OnPageHide calls).
    6663             :   if (!mIsShowing && !mIsBeingUsedAsImage) {
    6664             :     mAnimationController->OnPageHide();
    6665           2 :   }
    6666             : 
    6667           4 :   return mAnimationController;
    6668           0 : }
    6669             : 
    6670             : PendingAnimationTracker*
    6671           4 : nsIDocument::GetOrCreatePendingAnimationTracker()
    6672             : {
    6673             :   if (!mPendingAnimationTracker) {
    6674             :     mPendingAnimationTracker = new PendingAnimationTracker(this);
    6675             :   }
    6676             : 
    6677             :   return mPendingAnimationTracker;
    6678             : }
    6679             : 
    6680           0 : /**
    6681             :  * Retrieve the "direction" property of the document.
    6682           0 :  *
    6683           0 :  * @lina 01/09/2001
    6684           0 :  */
    6685           0 : void
    6686             : nsIDocument::GetDir(nsAString& aDirection) const
    6687           0 : {
    6688             :   aDirection.Truncate();
    6689             :   Element* rootElement = GetHtmlElement();
    6690             :   if (rootElement) {
    6691             :     static_cast<nsGenericHTMLElement*>(rootElement)->GetDir(aDirection);
    6692             :   }
    6693             : }
    6694             : 
    6695           0 : /**
    6696             :  * Set the "direction" property of the document.
    6697           0 :  *
    6698           0 :  * @lina 01/09/2001
    6699           0 :  */
    6700           0 : void
    6701             : nsIDocument::SetDir(const nsAString& aDirection)
    6702           0 : {
    6703             :   Element* rootElement = GetHtmlElement();
    6704             :   if (rootElement) {
    6705           0 :     rootElement->SetAttr(kNameSpaceID_None, nsGkAtoms::dir,
    6706             :                          aDirection, true);
    6707           0 :   }
    6708           0 : }
    6709             : 
    6710           0 : nsIHTMLCollection*
    6711             : nsIDocument::Images()
    6712             : {
    6713             :   if (!mImages) {
    6714           0 :     mImages = new nsContentList(this, kNameSpaceID_XHTML, nsGkAtoms::img, nsGkAtoms::img);
    6715             :   }
    6716           0 :   return mImages;
    6717           0 : }
    6718             : 
    6719           0 : nsIHTMLCollection*
    6720             : nsIDocument::Embeds()
    6721             : {
    6722             :   if (!mEmbeds) {
    6723           0 :     mEmbeds = new nsContentList(this, kNameSpaceID_XHTML, nsGkAtoms::embed, nsGkAtoms::embed);
    6724             :   }
    6725             :   return mEmbeds;
    6726           0 : }
    6727           0 : 
    6728             : static bool
    6729             : MatchLinks(Element* aElement, int32_t aNamespaceID,
    6730             :            nsAtom* aAtom, void* aData)
    6731           0 : {
    6732             :   return aElement->IsAnyOfHTMLElements(nsGkAtoms::a, nsGkAtoms::area) &&
    6733           0 :          aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::href);
    6734           0 : }
    6735             : 
    6736           0 : nsIHTMLCollection*
    6737             : nsIDocument::Links()
    6738             : {
    6739             :   if (!mLinks) {
    6740           0 :     mLinks = new nsContentList(this, MatchLinks, nullptr, nullptr);
    6741             :   }
    6742           0 :   return mLinks;
    6743             : }
    6744           0 : 
    6745             : nsIHTMLCollection*
    6746             : nsIDocument::Forms()
    6747           0 : {
    6748             :   if (!mForms) {
    6749             :     // Please keep this in sync with nsHTMLDocument::GetFormsAndFormControls.
    6750             :     mForms = new nsContentList(this, kNameSpaceID_XHTML, nsGkAtoms::form, nsGkAtoms::form);
    6751           0 :   }
    6752             : 
    6753           0 :   return mForms;
    6754           0 : }
    6755             : 
    6756           0 : nsIHTMLCollection*
    6757             : nsIDocument::Scripts()
    6758             : {
    6759             :   if (!mScripts) {
    6760           0 :     mScripts = new nsContentList(this, kNameSpaceID_XHTML, nsGkAtoms::script, nsGkAtoms::script);
    6761             :   }
    6762           0 :   return mScripts;
    6763           0 : }
    6764             : 
    6765           0 : nsIHTMLCollection*
    6766             : nsIDocument::Applets()
    6767             : {
    6768             :   if (!mApplets) {
    6769           0 :     mApplets = new nsEmptyContentList(this);
    6770             :   }
    6771             :   return mApplets;
    6772           0 : }
    6773           0 : 
    6774             : static bool
    6775             : MatchAnchors(Element* aElement, int32_t aNamespaceID,
    6776             :              nsAtom* aAtom, void* aData)
    6777           0 : {
    6778             :   return aElement->IsHTMLElement(nsGkAtoms::a) &&
    6779           0 :          aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::name);
    6780           0 : }
    6781             : 
    6782           0 : nsIHTMLCollection*
    6783             : nsIDocument::Anchors()
    6784             : {
    6785             :   if (!mAnchors) {
    6786             :     mAnchors = new nsContentList(this, MatchAnchors, nullptr, nullptr);
    6787           0 :   }
    6788             :   return mAnchors;
    6789             : }
    6790           0 : 
    6791             : /* static */
    6792           0 : bool
    6793             : nsIDocument::MatchNameAttribute(Element* aElement, int32_t aNamespaceID,
    6794             :                                 nsAtom* aAtom, void* aData)
    6795             : {
    6796           0 :   MOZ_ASSERT(aElement, "Must have element to work with!");
    6797             : 
    6798           0 :   if (!aElement->HasName()) {
    6799           0 :     return false;
    6800             :   }
    6801             : 
    6802             :   nsString* elementName = static_cast<nsString*>(aData);
    6803             :   return
    6804             :     aElement->GetNameSpaceID() == kNameSpaceID_XHTML &&
    6805           0 :     aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name,
    6806             :                           *elementName, eCaseMatters);
    6807           0 : }
    6808             : 
    6809             : /* static */
    6810             : void*
    6811           0 : nsIDocument::UseExistingNameString(nsINode* aRootNode, const nsString* aName)
    6812             : {
    6813           0 :   return const_cast<nsString*>(aName);
    6814          36 : }
    6815          18 : 
    6816          18 : nsresult
    6817             : nsIDocument::GetDocumentURI(nsString& aDocumentURI) const
    6818          18 : {
    6819             :   if (mDocumentURI) {
    6820           0 :     nsAutoCString uri;
    6821             :     nsresult rv = mDocumentURI->GetSpec(uri);
    6822             :     NS_ENSURE_SUCCESS(rv, rv);
    6823             : 
    6824             :     CopyUTF8toUTF16(uri, aDocumentURI);
    6825             :   } else {
    6826             :     aDocumentURI.Truncate();
    6827             :   }
    6828           0 : 
    6829             :   return NS_OK;
    6830           0 : }
    6831             : 
    6832             : // Alias of above
    6833             : nsresult
    6834           0 : nsIDocument::GetURL(nsString& aURL) const
    6835             : {
    6836             :   return GetDocumentURI(aURL);
    6837           0 : }
    6838          18 : 
    6839           0 : void
    6840             : nsIDocument::GetDocumentURIFromJS(nsString& aDocumentURI, CallerType aCallerType,
    6841             :                                   ErrorResult& aRv) const
    6842           0 : {
    6843           0 :   if (!mChromeXHRDocURI || aCallerType != CallerType::System) {
    6844           0 :     aRv = GetDocumentURI(aDocumentURI);
    6845           0 :     return;
    6846             :   }
    6847             : 
    6848           0 :   nsAutoCString uri;
    6849             :   nsresult res = mChromeXHRDocURI->GetSpec(uri);
    6850             :   if (NS_FAILED(res)) {
    6851             :     aRv.Throw(res);
    6852           4 :     return;
    6853             :   }
    6854           8 :   CopyUTF8toUTF16(uri, aDocumentURI);
    6855           0 : }
    6856             : 
    6857             : nsIURI*
    6858             : nsIDocument::GetDocumentURIObject() const
    6859             : {
    6860             :   if (!mChromeXHRDocURI) {
    6861             :     return GetDocumentURI();
    6862           0 :   }
    6863             : 
    6864           0 :   return mChromeXHRDocURI;
    6865             : }
    6866             : 
    6867             : void
    6868             : nsIDocument::GetCompatMode(nsString& aCompatMode) const
    6869           0 : {
    6870           0 :   NS_ASSERTION(mCompatMode == eCompatibility_NavQuirks ||
    6871             :                mCompatMode == eCompatibility_AlmostStandards ||
    6872           0 :                mCompatMode == eCompatibility_FullStandards,
    6873             :                "mCompatMode is neither quirks nor strict for this document");
    6874           0 : 
    6875             :   if (mCompatMode == eCompatibility_NavQuirks) {
    6876             :     aCompatMode.AssignLiteral("BackCompat");
    6877           0 :   } else {
    6878             :     aCompatMode.AssignLiteral("CSS1Compat");
    6879           0 :   }
    6880           0 : }
    6881             : 
    6882           0 : void
    6883             : nsDOMAttributeMap::BlastSubtreeToPieces(nsINode* aNode)
    6884             : {
    6885             :   if (Element* element = Element::FromNode(aNode)) {
    6886             :     if (const nsDOMAttributeMap* map = element->GetAttributeMap()) {
    6887             :       while (true) {
    6888           0 :         nsCOMPtr<nsIAttribute> attr;
    6889           0 :         {
    6890             :           // Use an iterator to get an arbitrary attribute from the
    6891             :           // cache. The iterator must be destroyed before any other
    6892           0 :           // operations on mAttributeCache, to avoid hash table
    6893             :           // assertions.
    6894           0 :           auto iter = map->mAttributeCache.ConstIter();
    6895             :           if (iter.Done()) {
    6896             :             break;
    6897           0 :           }
    6898             :           attr = iter.UserData();
    6899             :         }
    6900           0 :         NS_ASSERTION(attr.get(),
    6901             :                      "non-nsIAttribute somehow made it into the hashmap?!");
    6902           0 : 
    6903             :         BlastSubtreeToPieces(attr);
    6904             : 
    6905           0 :         DebugOnly<nsresult> rv =
    6906             :           element->UnsetAttr(attr->NodeInfo()->NamespaceID(),
    6907             :                              attr->NodeInfo()->NameAtom(),
    6908             :                              false);
    6909             : 
    6910           0 :         // XXX Should we abort here?
    6911           0 :         NS_ASSERTION(NS_SUCCEEDED(rv), "Uh-oh, UnsetAttr shouldn't fail!");
    6912           0 :       }
    6913           0 :     }
    6914             :   }
    6915           0 : 
    6916             :   while (aNode->HasChildren()) {
    6917             :     nsIContent* node = aNode->GetFirstChild();
    6918           0 :     BlastSubtreeToPieces(node);
    6919             :     aNode->RemoveChildNode(node, false);
    6920           0 :   }
    6921             : }
    6922             : 
    6923             : nsINode*
    6924             : nsIDocument::AdoptNode(nsINode& aAdoptedNode, ErrorResult& rv)
    6925           0 : {
    6926           0 :   nsINode* adoptedNode = &aAdoptedNode;
    6927           0 : 
    6928             :   // Scope firing mutation events so that we don't carry any state that
    6929             :   // might be stale
    6930             :   {
    6931           0 :     nsINode* parent = adoptedNode->GetParentNode();
    6932             :     if (parent) {
    6933           0 :       nsContentUtils::MaybeFireNodeRemoved(adoptedNode, parent);
    6934             :     }
    6935             :   }
    6936             : 
    6937           0 :   nsAutoScriptBlocker scriptBlocker;
    6938             : 
    6939           0 :   switch (adoptedNode->NodeType()) {
    6940           0 :     case ATTRIBUTE_NODE:
    6941           0 :     {
    6942             :       // Remove from ownerElement.
    6943             :       RefPtr<Attr> adoptedAttr = static_cast<Attr*>(adoptedNode);
    6944           0 : 
    6945             :       nsCOMPtr<Element> ownerElement = adoptedAttr->GetOwnerElement(rv);
    6946           0 :       if (rv.Failed()) {
    6947           0 :         return nullptr;
    6948           0 :       }
    6949             : 
    6950             :       if (ownerElement) {
    6951           0 :         RefPtr<Attr> newAttr =
    6952             :           ownerElement->RemoveAttributeNode(*adoptedAttr, rv);
    6953             :         if (rv.Failed()) {
    6954           0 :           return nullptr;
    6955             :         }
    6956             : 
    6957             :         newAttr.swap(adoptedAttr);
    6958           0 :       }
    6959           0 : 
    6960           0 :       break;
    6961             :     }
    6962             :     case DOCUMENT_FRAGMENT_NODE:
    6963             :     {
    6964             :       if (adoptedNode->IsShadowRoot()) {
    6965             :         rv.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
    6966             :         return nullptr;
    6967             :       }
    6968             :       MOZ_FALLTHROUGH;
    6969             :     }
    6970             :     case ELEMENT_NODE:
    6971             :     case PROCESSING_INSTRUCTION_NODE:
    6972           0 :     case TEXT_NODE:
    6973           0 :     case CDATA_SECTION_NODE:
    6974           0 :     case COMMENT_NODE:
    6975             :     case DOCUMENT_TYPE_NODE:
    6976             :     {
    6977             :       // Don't allow adopting a node's anonymous subtree out from under it.
    6978             :       if (adoptedNode->AsContent()->IsRootOfAnonymousSubtree()) {
    6979             :         rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
    6980             :         return nullptr;
    6981             :       }
    6982           0 : 
    6983           0 :       // We don't want to adopt an element into its own contentDocument or into
    6984           0 :       // a descendant contentDocument, so we check if the frameElement of this
    6985           0 :       // document or any of its parents is the adopted node or one of its
    6986           0 :       // descendants.
    6987           0 :       nsIDocument *doc = this;
    6988           0 :       do {
    6989             :         if (nsPIDOMWindowOuter *win = doc->GetWindow()) {
    6990             :           nsCOMPtr<nsINode> node = win->GetFrameElementInternal();
    6991             :           if (node &&
    6992             :               nsContentUtils::ContentIsDescendantOf(node, adoptedNode)) {
    6993             :             rv.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
    6994           0 :             return nullptr;
    6995           0 :           }
    6996           0 :         }
    6997             :       } while ((doc = doc->GetParentDocument()));
    6998           0 : 
    6999             :       // Remove from parent.
    7000             :       nsCOMPtr<nsINode> parent = adoptedNode->GetParentNode();
    7001             :       if (parent) {
    7002             :         parent->RemoveChildNode(adoptedNode->AsContent(), true);
    7003             :       } else {
    7004           0 :         MOZ_ASSERT(!adoptedNode->IsInUncomposedDoc());
    7005           0 : 
    7006             :         // If we're adopting a node that's not in a document, it might still
    7007             :         // have a binding applied. Remove the binding from the element now
    7008             :         // that it's getting adopted into a new document.
    7009             :         // TODO Fully tear down the binding.
    7010             :         if (Element* element = Element::FromNode(adoptedNode)) {
    7011             :           element->SetXBLBinding(nullptr);
    7012             :         }
    7013           0 :       }
    7014           0 : 
    7015             :       break;
    7016             :     }
    7017             :     case DOCUMENT_NODE:
    7018           0 :     {
    7019             :       rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
    7020           0 :       return nullptr;
    7021           0 :     }
    7022             :     default:
    7023             :     {
    7024             :       NS_WARNING("Don't know how to adopt this nodetype for adoptNode.");
    7025           0 : 
    7026           0 :       rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
    7027             :       return nullptr;
    7028           0 :     }
    7029           0 :   }
    7030           0 : 
    7031           0 :   nsCOMPtr<nsIDocument> oldDocument = adoptedNode->OwnerDoc();
    7032           0 :   bool sameDocument = oldDocument == this;
    7033             : 
    7034             :   AutoJSContext cx;
    7035             :   JS::Rooted<JSObject*> newScope(cx, nullptr);
    7036             :   if (!sameDocument) {
    7037           0 :     newScope = GetWrapper();
    7038           0 :     if (!newScope && GetScopeObject() && GetScopeObject()->GetGlobalJSObject()) {
    7039           0 :       // Make sure cx is in a semi-sane compartment before we call WrapNative.
    7040           0 :       // It's kind of irrelevant, given that we're passing aAllowWrapping =
    7041           0 :       // false, and documents should always insist on being wrapped in an
    7042           0 :       // canonical scope. But we try to pass something sane anyway.
    7043           0 :       JSAutoRealm ar(cx, GetScopeObject()->GetGlobalJSObject());
    7044             :       JS::Rooted<JS::Value> v(cx);
    7045             :       rv = nsContentUtils::WrapNative(cx, this, this, &v,
    7046             :                                       /* aAllowWrapping = */ false);
    7047           0 :       if (rv.Failed())
    7048           0 :         return nullptr;
    7049           0 :       newScope = &v.toObject();
    7050           0 :     }
    7051             :   }
    7052             : 
    7053           0 :   nsCOMArray<nsINode> nodesWithProperties;
    7054             :   nsNodeUtils::Adopt(adoptedNode, sameDocument ? nullptr : mNodeInfoManager,
    7055           0 :                      newScope, nodesWithProperties, rv);
    7056           0 :   if (rv.Failed()) {
    7057             :     // Disconnect all nodes from their parents, since some have the old document
    7058           0 :     // as their ownerDocument and some have this as their ownerDocument.
    7059             :     nsDOMAttributeMap::BlastSubtreeToPieces(adoptedNode);
    7060             : 
    7061             :     if (!sameDocument && oldDocument) {
    7062             :       for (nsINode* node : nodesWithProperties) {
    7063             :         // Remove all properties.
    7064             :         oldDocument->PropertyTable().DeleteAllPropertiesFor(node);
    7065           0 :       }
    7066           0 :     }
    7067           0 : 
    7068           0 :     return nullptr;
    7069           0 :   }
    7070             : 
    7071             :   if (!sameDocument && oldDocument) {
    7072           0 :     nsPropertyTable& oldTable = oldDocument->PropertyTable();
    7073             :     nsPropertyTable& newTable = PropertyTable();
    7074           0 :     for (nsINode* node : nodesWithProperties) {
    7075             :       rv = oldTable.TransferOrDeleteAllPropertiesFor(node, newTable);
    7076           0 :     }
    7077             : 
    7078             :     if (rv.Failed()) {
    7079             :       // Disconnect all nodes from their parents.
    7080           0 :       nsDOMAttributeMap::BlastSubtreeToPieces(adoptedNode);
    7081             : 
    7082             :       return nullptr;
    7083             :     }
    7084             :   }
    7085             : 
    7086             :   NS_ASSERTION(adoptedNode->OwnerDoc() == this,
    7087           0 :                "Should still be in the document we just got adopted into");
    7088             : 
    7089           0 :   return adoptedNode;
    7090             : }
    7091             : 
    7092             : nsViewportInfo
    7093           0 : nsIDocument::GetViewportInfo(const ScreenIntSize& aDisplaySize)
    7094             : {
    7095             :   MOZ_ASSERT(mPresShell);
    7096             : 
    7097             :   // Compute the CSS-to-LayoutDevice pixel scale as the product of the
    7098           0 :   // widget scale and the full zoom.
    7099           0 :   nsPresContext* context = mPresShell->GetPresContext();
    7100           0 :   // When querying the full zoom, get it from the device context rather than
    7101             :   // directly from the pres context, because the device context's value can
    7102             :   // include an adjustment necessay to keep the number of app units per device
    7103           0 :   // pixel an integer, and we want the adjusted value.
    7104             :   float fullZoom = context ? context->DeviceContext()->GetFullZoom() : 1.0;
    7105             :   fullZoom = (fullZoom == 0.0) ? 1.0 : fullZoom;
    7106           0 :   CSSToLayoutDeviceScale layoutDeviceScale = context ? context->CSSToDevPixelScale() : CSSToLayoutDeviceScale(1);
    7107           0 : 
    7108           0 :   CSSToScreenScale defaultScale = layoutDeviceScale
    7109           0 :                                 * LayoutDeviceToScreenScale(1.0);
    7110           0 : 
    7111           0 :   // Special behaviour for desktop mode, provided we are not on an about: page
    7112           0 :   nsPIDOMWindowOuter* win = GetWindow();
    7113             :   if (win && win->IsDesktopModeViewport() && !IsAboutPage()) {
    7114             :     CSSCoord viewportWidth = gfxPrefs::DesktopViewportWidth() / fullZoom;
    7115           0 :     CSSToScreenScale scaleToFit(aDisplaySize.width / viewportWidth);
    7116             :     float aspectRatio = (float)aDisplaySize.height / aDisplaySize.width;
    7117             :     CSSSize viewportSize(viewportWidth, viewportWidth * aspectRatio);
    7118           0 :     ScreenIntSize fakeDesktopSize = RoundedToInt(viewportSize * scaleToFit);
    7119             :     return nsViewportInfo(fakeDesktopSize,
    7120             :                           scaleToFit,
    7121           0 :                           /*allowZoom*/ true);
    7122             :   }
    7123             : 
    7124             :   if (!gfxPrefs::MetaViewportEnabled()) {
    7125             :     return nsViewportInfo(aDisplaySize,
    7126             :                           defaultScale,
    7127             :                           /*allowZoom*/ false);
    7128           0 :   }
    7129             : 
    7130             :   // In cases where the width of the CSS viewport is less than or equal to the width
    7131             :   // of the display (i.e. width <= device-width) then we disable double-tap-to-zoom
    7132           0 :   // behaviour. See bug 941995 for details.
    7133             : 
    7134             :   switch (mViewportType) {
    7135           0 :   case DisplayWidthHeight:
    7136           0 :     return nsViewportInfo(aDisplaySize,
    7137           0 :                           defaultScale,
    7138             :                           /*allowZoom*/ true);
    7139             :   case Unknown:
    7140           0 :   {
    7141           0 :     nsAutoString viewport;
    7142           0 :     GetHeaderData(nsGkAtoms::viewport, viewport);
    7143           0 :     if (viewport.IsEmpty()) {
    7144           0 :       // If the docType specifies that we are on a site optimized for mobile,
    7145           0 :       // then we want to return specially crafted defaults for the viewport info.
    7146           0 :       RefPtr<DocumentType> docType = GetDoctype();
    7147             :       if (docType) {
    7148             :         nsAutoString docId;
    7149           0 :         docType->GetPublicId(docId);
    7150             :         if ((docId.Find("WAP") != -1) ||
    7151             :             (docId.Find("Mobile") != -1) ||
    7152           0 :             (docId.Find("WML") != -1))
    7153             :         {
    7154             :           // We're making an assumption that the docType can't change here
    7155             :           mViewportType = DisplayWidthHeight;
    7156           0 :           return nsViewportInfo(aDisplaySize,
    7157           0 :                                 defaultScale,
    7158           0 :                                 /*allowZoom*/true);
    7159           0 :         }
    7160             :       }
    7161           0 : 
    7162             :       nsAutoString handheldFriendly;
    7163             :       GetHeaderData(nsGkAtoms::handheldFriendly, handheldFriendly);
    7164             :       if (handheldFriendly.EqualsLiteral("true")) {
    7165           0 :         mViewportType = DisplayWidthHeight;
    7166           0 :         return nsViewportInfo(aDisplaySize, defaultScale,
    7167             :                               /*allowZoom*/true);
    7168             :       }
    7169           0 :     }
    7170             : 
    7171           0 :     nsAutoString minScaleStr;
    7172           0 :     GetHeaderData(nsGkAtoms::viewport_minimum_scale, minScaleStr);
    7173             : 
    7174             :     nsresult errorCode;
    7175           0 :     mScaleMinFloat = LayoutDeviceToScreenScale(minScaleStr.ToFloat(&errorCode));
    7176           0 : 
    7177             :     if (NS_FAILED(errorCode)) {
    7178           0 :       mScaleMinFloat = kViewportMinScale;
    7179           0 :     }
    7180             : 
    7181             :     mScaleMinFloat = mozilla::clamped(
    7182             :         mScaleMinFloat, kViewportMinScale, kViewportMaxScale);
    7183             : 
    7184           0 :     nsAutoString maxScaleStr;
    7185             :     GetHeaderData(nsGkAtoms::viewport_maximum_scale, maxScaleStr);
    7186           0 : 
    7187           0 :     // We define a special error code variable for the scale and max scale,
    7188             :     // because they are used later (see the width calculations).
    7189             :     nsresult scaleMaxErrorCode;
    7190           0 :     mScaleMaxFloat = LayoutDeviceToScreenScale(maxScaleStr.ToFloat(&scaleMaxErrorCode));
    7191           0 : 
    7192             :     if (NS_FAILED(scaleMaxErrorCode)) {
    7193           0 :       mScaleMaxFloat = kViewportMaxScale;
    7194           0 :     }
    7195             : 
    7196             :     mScaleMaxFloat = mozilla::clamped(
    7197           0 :         mScaleMaxFloat, kViewportMinScale, kViewportMaxScale);
    7198             : 
    7199           0 :     nsAutoString scaleStr;
    7200             :     GetHeaderData(nsGkAtoms::viewport_initial_scale, scaleStr);
    7201           0 : 
    7202           0 :     nsresult scaleErrorCode;
    7203             :     mScaleFloat = LayoutDeviceToScreenScale(scaleStr.ToFloat(&scaleErrorCode));
    7204           0 : 
    7205             :     nsAutoString widthStr, heightStr;
    7206           0 : 
    7207           0 :     GetHeaderData(nsGkAtoms::viewport_height, heightStr);
    7208             :     GetHeaderData(nsGkAtoms::viewport_width, widthStr);
    7209             : 
    7210           0 :     mAutoSize = false;
    7211           0 : 
    7212           0 :     if (widthStr.EqualsLiteral("device-width")) {
    7213             :       mAutoSize = true;
    7214           0 :     }
    7215             : 
    7216             :     if (widthStr.IsEmpty() &&
    7217             :         (heightStr.EqualsLiteral("device-height") ||
    7218           0 :          (mScaleFloat.scale == 1.0)))
    7219           0 :     {
    7220             :       mAutoSize = true;
    7221             :     }
    7222             : 
    7223           0 :     nsresult widthErrorCode, heightErrorCode;
    7224           0 :     mViewportSize.width = widthStr.ToInteger(&widthErrorCode);
    7225             :     mViewportSize.height = heightStr.ToInteger(&heightErrorCode);
    7226           0 : 
    7227           0 :     // If width or height has not been set to a valid number by this point,
    7228           0 :     // fall back to a default value.
    7229             :     mValidWidth = (!widthStr.IsEmpty() && NS_SUCCEEDED(widthErrorCode) && mViewportSize.width > 0);
    7230           0 :     mValidHeight = (!heightStr.IsEmpty() && NS_SUCCEEDED(heightErrorCode) && mViewportSize.height > 0);
    7231           0 : 
    7232           0 :     mAllowZoom = true;
    7233           0 :     nsAutoString userScalable;
    7234             :     GetHeaderData(nsGkAtoms::viewport_user_scalable, userScalable);
    7235             : 
    7236           0 :     if ((userScalable.EqualsLiteral("0")) ||
    7237           0 :         (userScalable.EqualsLiteral("no")) ||
    7238           0 :         (userScalable.EqualsLiteral("false"))) {
    7239           0 :       mAllowZoom = false;
    7240             :     }
    7241           0 : 
    7242           0 :     mScaleStrEmpty = scaleStr.IsEmpty();
    7243             :     mWidthStrEmpty = widthStr.IsEmpty();
    7244             :     mValidScaleFloat = !scaleStr.IsEmpty() && NS_SUCCEEDED(scaleErrorCode);
    7245             :     mValidMaxScale = !maxScaleStr.IsEmpty() && NS_SUCCEEDED(scaleMaxErrorCode);
    7246             : 
    7247           0 :     mViewportType = Specified;
    7248           0 :     mViewportOverflowType = ViewportOverflowType::NoOverflow;
    7249           0 :     MOZ_FALLTHROUGH;
    7250           0 :   }
    7251           0 :   case Specified:
    7252             :   default:
    7253             :     LayoutDeviceToScreenScale effectiveMinScale = mScaleMinFloat;
    7254             :     LayoutDeviceToScreenScale effectiveMaxScale = mScaleMaxFloat;
    7255             :     bool effectiveValidMaxScale = mValidMaxScale;
    7256             :     bool effectiveAllowZoom = mAllowZoom;
    7257             :     if (gfxPrefs::ForceUserScalable()) {
    7258             :       // If the pref to force user-scalable is enabled, we ignore the values
    7259           0 :       // from the meta-viewport tag for these properties and just assume they
    7260           0 :       // allow the page to be scalable. Note in particular that this code is
    7261           0 :       // in the "Specified" branch of the enclosing switch statement, so that
    7262           0 :       // calls to GetViewportInfo always use the latest value of the
    7263             :       // ForceUserScalable pref. Other codepaths that return nsViewportInfo
    7264             :       // instances are all consistent with ForceUserScalable() already.
    7265           0 :       effectiveMinScale = kViewportMinScale;
    7266             :       effectiveMaxScale = kViewportMaxScale;
    7267           0 :       effectiveValidMaxScale = true;
    7268           0 :       effectiveAllowZoom = true;
    7269           0 :     }
    7270             : 
    7271             :     CSSSize size = mViewportSize;
    7272             : 
    7273             :     if (!mValidWidth) {
    7274           0 :       if (mValidHeight && !aDisplaySize.IsEmpty()) {
    7275             :         size.width = size.height * aDisplaySize.width / aDisplaySize.height;
    7276             :       } else {
    7277             :         // Stretch CSS pixel size of viewport to keep device pixel size
    7278           0 :         // unchanged after full zoom applied.
    7279           0 :         // See bug 974242.
    7280           0 :         size.width = gfxPrefs::DesktopViewportWidth() / fullZoom;
    7281             :       }
    7282           0 :     }
    7283             : 
    7284             :     if (!mValidHeight) {
    7285             :       if (!aDisplaySize.IsEmpty()) {
    7286           0 :         size.height = size.width * aDisplaySize.height / aDisplaySize.width;
    7287           0 :       } else {
    7288           0 :         size.height = size.width;
    7289             :       }
    7290           0 :     }
    7291             : 
    7292           0 :     CSSToScreenScale scaleFloat = mScaleFloat * layoutDeviceScale;
    7293           0 :     CSSToScreenScale scaleMinFloat = effectiveMinScale * layoutDeviceScale;
    7294             :     CSSToScreenScale scaleMaxFloat = effectiveMaxScale * layoutDeviceScale;
    7295             : 
    7296           0 :     if (mAutoSize) {
    7297             :       // aDisplaySize is in screen pixels; convert them to CSS pixels for the viewport size.
    7298             :       CSSToScreenScale defaultPixelScale = layoutDeviceScale * LayoutDeviceToScreenScale(1.0f);
    7299             :       size = ScreenSize(aDisplaySize) / defaultPixelScale;
    7300           0 :     }
    7301           0 : 
    7302           0 :     size.width = clamped(size.width, float(kViewportMinSize.width), float(kViewportMaxSize.width));
    7303             : 
    7304             :     // Also recalculate the default zoom, if it wasn't specified in the metadata,
    7305           0 :     // and the width is specified.
    7306             :     if (mScaleStrEmpty && !mWidthStrEmpty) {
    7307             :       CSSToScreenScale defaultScale(float(aDisplaySize.width) / size.width);
    7308             :       scaleFloat = (scaleFloat > defaultScale) ? scaleFloat : defaultScale;
    7309           0 :     }
    7310           0 : 
    7311           0 :     size.height = clamped(size.height, float(kViewportMinSize.height), float(kViewportMaxSize.height));
    7312           0 : 
    7313           0 :     // We need to perform a conversion, but only if the initial or maximum
    7314           0 :     // scale were set explicitly by the user.
    7315           0 :     if (mValidScaleFloat && scaleFloat >= scaleMinFloat && scaleFloat <= scaleMaxFloat) {
    7316           0 :       CSSSize displaySize = ScreenSize(aDisplaySize) / scaleFloat;
    7317             :       size.width = std::max(size.width, displaySize.width);
    7318             :       size.height = std::max(size.height, displaySize.height);
    7319             :     } else if (effectiveValidMaxScale) {
    7320           0 :       CSSSize displaySize = ScreenSize(aDisplaySize) / scaleMaxFloat;
    7321             :       size.width = std::max(size.width, displaySize.width);
    7322             :       size.height = std::max(size.height, displaySize.height);
    7323             :     }
    7324             : 
    7325           0 :     return nsViewportInfo(scaleFloat, scaleMinFloat, scaleMaxFloat, size,
    7326             :                           mAutoSize, effectiveAllowZoom);
    7327             :   }
    7328             : }
    7329           0 : 
    7330           0 : void
    7331           0 : nsIDocument::UpdateViewportOverflowType(nscoord aScrolledWidth,
    7332             :                                         nscoord aScrollportWidth)
    7333             : {
    7334           0 : #ifdef DEBUG
    7335             :   MOZ_ASSERT(mPresShell);
    7336           0 :   nsPresContext* pc = GetPresContext();
    7337             :   MOZ_ASSERT(pc->GetViewportScrollbarStylesOverride().mHorizontal ==
    7338             :              NS_STYLE_OVERFLOW_HIDDEN,
    7339             :              "Should only be called when viewport has overflow-x: hidden");
    7340           0 :   MOZ_ASSERT(aScrolledWidth > aScrollportWidth,
    7341           0 :              "Should only be called when viewport is overflowed");
    7342           0 :   MOZ_ASSERT(IsTopLevelContentDocument(),
    7343           0 :              "Should only be called for top-level content document");
    7344             : #endif // DEBUG
    7345             : 
    7346           0 :   if (!gfxPrefs::MetaViewportEnabled() ||
    7347             :       (GetWindow() && GetWindow()->IsDesktopModeViewport())) {
    7348             :     mViewportOverflowType = ViewportOverflowType::Desktop;
    7349             :     return;
    7350             :   }
    7351             : 
    7352             :   if (mViewportType == Unknown) {
    7353             :     // The viewport info hasn't been initialized yet. Suppose we would
    7354           0 :     // get here again at some point after it's initialized.
    7355           0 :     return;
    7356             :   }
    7357             : 
    7358           0 :   static const LayoutDeviceToScreenScale
    7359             :     kBlinkDefaultMinScale = LayoutDeviceToScreenScale(0.25f);
    7360             :   LayoutDeviceToScreenScale minScale;
    7361           0 :   if (mViewportType == DisplayWidthHeight) {
    7362             :     minScale = kBlinkDefaultMinScale;
    7363             :   } else {
    7364             :     if (mScaleMinFloat == kViewportMinScale) {
    7365             :       minScale = kBlinkDefaultMinScale;
    7366             :     } else {
    7367           0 :       minScale = mScaleMinFloat;
    7368           0 :     }
    7369           0 :   }
    7370             : 
    7371           0 :   // If the content has overflowed with minimum scale applied, don't
    7372             :   // change it, otherwise update the overflow type.
    7373             :   if (mViewportOverflowType != ViewportOverflowType::MinScaleSize) {
    7374             :     if (aScrolledWidth * minScale.scale < aScrollportWidth) {
    7375             :       mViewportOverflowType = ViewportOverflowType::ButNotMinScaleSize;
    7376             :     } else {
    7377         133 :       mViewportOverflowType = ViewportOverflowType::MinScaleSize;
    7378             :     }
    7379         266 :   }
    7380             : }
    7381           0 : 
    7382          28 : EventListenerManager*
    7383             : nsDocument::GetOrCreateListenerManager()
    7384             : {
    7385           0 :   if (!mListenerManager) {
    7386             :     mListenerManager =
    7387             :       new EventListenerManager(static_cast<EventTarget*>(this));
    7388             :     SetFlags(NODE_HAS_LISTENERMANAGER);
    7389           0 :   }
    7390             : 
    7391        1324 :   return mListenerManager;
    7392             : }
    7393             : 
    7394             : EventListenerManager*
    7395           0 : nsDocument::GetExistingListenerManager() const
    7396             : {
    7397         959 :   return mListenerManager;
    7398         143 : }
    7399           0 : 
    7400             : void
    7401             : nsDocument::GetEventTargetParent(EventChainPreVisitor& aVisitor)
    7402           0 : {
    7403             :   if (mDocGroup && aVisitor.mEvent->mMessage != eVoidEvent &&
    7404             :       !mIgnoreDocGroupMismatches) {
    7405         408 :     mDocGroup->ValidateAccess();
    7406             :   }
    7407             : 
    7408         408 :   aVisitor.mCanHandle = true;
    7409           0 :    // FIXME! This is a hack to make middle mouse paste working also in Editor.
    7410         338 :    // Bug 329119
    7411             :   aVisitor.mForceContentDispatch = true;
    7412             : 
    7413           0 :   // Load events must not propagate to |window| object, see bug 335251.
    7414             :   if (aVisitor.mEvent->mMessage != eLoad) {
    7415             :     nsGlobalWindowOuter* window = nsGlobalWindowOuter::Cast(GetWindow());
    7416         203 :     aVisitor.SetParentTarget(
    7417             :       window ? window->GetTargetForEventTargetChain() : nullptr, false);
    7418             :   }
    7419         203 : }
    7420             : 
    7421             : already_AddRefed<Event>
    7422             : nsIDocument::CreateEvent(const nsAString& aEventType, CallerType aCallerType,
    7423           0 :                          ErrorResult& rv) const
    7424         406 : {
    7425         203 :   nsPresContext* presContext = GetPresContext();
    7426           0 : 
    7427             :   // Create event even without presContext.
    7428             :   RefPtr<Event> ev =
    7429           0 :     EventDispatcher::CreateEvent(const_cast<nsIDocument*>(this), presContext,
    7430           0 :                                  nullptr, aEventType, aCallerType);
    7431         203 :   if (!ev) {
    7432             :     rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
    7433             :     return nullptr;
    7434             :   }
    7435             :   WidgetEvent* e = ev->WidgetEventPtr();
    7436         504 :   e->mFlags.mBubbles = false;
    7437             :   e->mFlags.mCancelable = false;
    7438        1008 :   return ev.forget();
    7439         504 : }
    7440           0 : 
    7441             : void
    7442             : nsIDocument::FlushPendingNotifications(FlushType aType)
    7443           0 : {
    7444             :  mozilla::ChangesToFlush flush(aType, aType >= FlushType::Style);
    7445         509 :   FlushPendingNotifications(flush);
    7446             : }
    7447           0 : 
    7448             : void
    7449             : nsIDocument::FlushPendingNotifications(mozilla::ChangesToFlush aFlush)
    7450             : {
    7451             :   FlushType flushType = aFlush.mFlushType;
    7452             : 
    7453             :   nsDocumentOnStack dos(this);
    7454             : 
    7455        1055 :   // We need to flush the sink for non-HTML documents (because the XML
    7456          12 :   // parser still does insertion with deferred notifications).  We
    7457         993 :   // also need to flush the sink if this is a layout-related flush, to
    7458        1896 :   // make sure that layout is started as needed.  But we can skip that
    7459           0 :   // part if we have no presshell or if it's already done an initial
    7460           0 :   // reflow.
    7461           0 :   if ((!IsHTMLDocument() ||
    7462             :        (flushType > FlushType::ContentAndNotify && mPresShell &&
    7463           0 :         !mPresShell->DidInitialize())) &&
    7464           0 :       (mParser || mWeakSink)) {
    7465           0 :     nsCOMPtr<nsIContentSink> sink;
    7466             :     if (mParser) {
    7467             :       sink = mParser->GetContentSink();
    7468             :     } else {
    7469             :       sink = do_QueryReferent(mWeakSink);
    7470          70 :       if (!sink) {
    7471          70 :         mWeakSink = nullptr;
    7472             :       }
    7473             :     }
    7474             :     // Determine if it is safe to flush the sink notifications
    7475             :     // by determining if it safe to flush all the presshells.
    7476             :     if (sink && (flushType == FlushType::Content || IsSafeToFlush())) {
    7477         509 :       sink->FlushPendingNotifications(flushType);
    7478             :     }
    7479         440 :   }
    7480             : 
    7481             :   // Should we be flushing pending binding constructors in here?
    7482             : 
    7483             :   if (flushType <= FlushType::ContentAndNotify) {
    7484             :     // Nothing to do here
    7485             :     return;
    7486             :   }
    7487             : 
    7488             :   // If we have a parent we must flush the parent too to ensure that our
    7489             :   // container is reflowed if its size was changed.  But if it's not safe to
    7490             :   // flush ourselves, then don't flush the parent, since that can cause things
    7491          69 :   // like resizes of our frame's widget, which we can't handle while flushing
    7492           5 :   // is unsafe.
    7493           5 :   // Since media queries mean that a size change of our container can
    7494          10 :   // affect style, we need to promote a style flush on ourself to a
    7495             :   // layout flush on our parent, since we need our container to be the
    7496           0 :   // correct size to determine the correct style.
    7497             :   if (mParentDocument && IsSafeToFlush()) {
    7498             :     mozilla::ChangesToFlush parentFlush = aFlush;
    7499          69 :     if (flushType >= FlushType::Style) {
    7500           0 :       parentFlush.mFlushType = std::max(FlushType::Layout, flushType);
    7501             :     }
    7502             :     mParentDocument->FlushPendingNotifications(parentFlush);
    7503             :   }
    7504             : 
    7505           0 :   if (nsIPresShell* shell = GetShell()) {
    7506             :     shell->FlushPendingNotifications(aFlush);
    7507             :   }
    7508           0 : }
    7509           0 : 
    7510           0 : static bool
    7511             : Copy(nsIDocument* aDocument, void* aData)
    7512             : {
    7513             :   nsTArray<nsCOMPtr<nsIDocument> >* resources =
    7514           0 :     static_cast<nsTArray<nsCOMPtr<nsIDocument> >* >(aData);
    7515             :   resources->AppendElement(aDocument);
    7516          96 :   return true;
    7517             : }
    7518           0 : 
    7519           0 : void
    7520             : nsIDocument::FlushExternalResources(FlushType aType)
    7521         192 : {
    7522           0 :   NS_ASSERTION(aType >= FlushType::Style,
    7523             :     "should only need to flush for style or higher in external resources");
    7524         192 :   if (GetDisplayDocument()) {
    7525           0 :     return;
    7526             :   }
    7527             :   nsTArray<nsCOMPtr<nsIDocument> > resources;
    7528             :   EnumerateExternalResources(Copy, &resources);
    7529             : 
    7530          31 :   for (uint32_t i = 0; i < resources.Length(); i++) {
    7531             :     resources[i]->FlushPendingNotifications(aType);
    7532             :   }
    7533             : }
    7534           0 : 
    7535           0 : void
    7536           0 : nsIDocument::SetXMLDeclaration(const char16_t* aVersion,
    7537             :                                const char16_t* aEncoding,
    7538             :                                const int32_t aStandalone)
    7539           1 : {
    7540             :   if (!aVersion || *aVersion == '\0') {
    7541          31 :     mXMLDeclarationBits = 0;
    7542           4 :     return;
    7543             :   }
    7544             : 
    7545           0 :   mXMLDeclarationBits = XML_DECLARATION_BITS_DECLARATION_EXISTS;
    7546           0 : 
    7547           0 :   if (aEncoding && *aEncoding != '\0') {
    7548             :     mXMLDeclarationBits |= XML_DECLARATION_BITS_ENCODING_EXISTS;
    7549           0 :   }
    7550           0 : 
    7551             :   if (aStandalone == 1) {
    7552             :     mXMLDeclarationBits |= XML_DECLARATION_BITS_STANDALONE_EXISTS |
    7553             :                            XML_DECLARATION_BITS_STANDALONE_YES;
    7554             :   }
    7555           0 :   else if (aStandalone == 0) {
    7556             :     mXMLDeclarationBits |= XML_DECLARATION_BITS_STANDALONE_EXISTS;
    7557             :   }
    7558             : }
    7559           0 : 
    7560           0 : void
    7561           0 : nsIDocument::GetXMLDeclaration(nsAString& aVersion,
    7562             :                                nsAString& aEncoding,
    7563           0 :                                nsAString& aStandalone)
    7564             : {
    7565             :   aVersion.Truncate();
    7566             :   aEncoding.Truncate();
    7567             :   aStandalone.Truncate();
    7568           0 : 
    7569             :   if (!(mXMLDeclarationBits & XML_DECLARATION_BITS_DECLARATION_EXISTS)) {
    7570           0 :     return;
    7571             :   }
    7572             : 
    7573           0 :   // always until we start supporting 1.1 etc.
    7574             :   aVersion.AssignLiteral("1.0");
    7575             : 
    7576           0 :   if (mXMLDeclarationBits & XML_DECLARATION_BITS_ENCODING_EXISTS) {
    7577           0 :     // This is what we have stored, not necessarily what was written
    7578           0 :     // in the original
    7579             :     GetCharacterSet(aEncoding);
    7580           0 :   }
    7581             : 
    7582             :   if (mXMLDeclarationBits & XML_DECLARATION_BITS_STANDALONE_EXISTS) {
    7583             :     if (mXMLDeclarationBits & XML_DECLARATION_BITS_STANDALONE_YES) {
    7584             :       aStandalone.AssignLiteral("yes");
    7585             :     } else {
    7586          23 :       aStandalone.AssignLiteral("no");
    7587             :     }
    7588             :   }
    7589             : }
    7590           0 : 
    7591             : bool
    7592             : nsIDocument::IsScriptEnabled()
    7593             : {
    7594           0 :   // If this document is sandboxed without 'allow-scripts'
    7595          23 :   // script is not enabled
    7596             :   if (HasScriptsBlockedBySandbox()) {
    7597             :     return false;
    7598             :   }
    7599           0 : 
    7600             :   nsCOMPtr<nsIScriptGlobalObject> globalObject = do_QueryInterface(GetInnerWindow());
    7601             :   if (!globalObject || !globalObject->GetGlobalJSObject()) {
    7602             :     return false;
    7603           0 :   }
    7604             : 
    7605           0 :   return xpc::Scriptability::Get(globalObject->GetGlobalJSObject()).Allowed();
    7606           0 : }
    7607           0 : 
    7608             : nsRadioGroupStruct*
    7609             : nsDocument::GetRadioGroup(const nsAString& aName) const
    7610             : {
    7611           0 :   nsRadioGroupStruct* radioGroup = nullptr;
    7612             :   mRadioGroups.Get(aName, &radioGroup);
    7613           0 :   return radioGroup;
    7614           0 : }
    7615             : 
    7616             : nsRadioGroupStruct*
    7617             : nsDocument::GetOrCreateRadioGroup(const nsAString& aName)
    7618           0 : {
    7619             :   return mRadioGroups.LookupForAdd(aName).OrInsert(
    7620             :     [] () { return new nsRadioGroupStruct(); });
    7621           0 : }
    7622           0 : 
    7623           0 : void
    7624             : nsDocument::SetCurrentRadioButton(const nsAString& aName,
    7625             :                                   HTMLInputElement* aRadio)
    7626           0 : {
    7627             :   nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName);
    7628           0 :   radioGroup->mSelectedRadioButton = aRadio;
    7629             : }
    7630             : 
    7631             : HTMLInputElement*
    7632           0 : nsDocument::GetCurrentRadioButton(const nsAString& aName)
    7633             : {
    7634             :   return GetOrCreateRadioGroup(aName)->mSelectedRadioButton;
    7635             : }
    7636             : 
    7637             : NS_IMETHODIMP
    7638             : nsDocument::GetNextRadioButton(const nsAString& aName,
    7639             :                                const bool aPrevious,
    7640             :                                HTMLInputElement* aFocusedRadio,
    7641           0 :                                HTMLInputElement** aRadioOut)
    7642             : {
    7643           0 :   // XXX Can we combine the HTML radio button method impls of
    7644             :   //     nsDocument and nsHTMLFormControl?
    7645             :   // XXX Why is HTML radio button stuff in nsDocument, as
    7646             :   //     opposed to nsHTMLDocument?
    7647           0 :   *aRadioOut = nullptr;
    7648           0 : 
    7649             :   nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName);
    7650             : 
    7651             :   // Return the radio button relative to the focused radio button.
    7652           0 :   // If no radio is focused, get the radio relative to the selected one.
    7653           0 :   RefPtr<HTMLInputElement> currentRadio;
    7654             :   if (aFocusedRadio) {
    7655             :     currentRadio = aFocusedRadio;
    7656             :   }
    7657           0 :   else {
    7658           0 :     currentRadio = radioGroup->mSelectedRadioButton;
    7659             :     if (!currentRadio) {
    7660             :       return NS_ERROR_FAILURE;
    7661             :     }
    7662           0 :   }
    7663           0 :   int32_t index = radioGroup->mRadioButtons.IndexOf(currentRadio);
    7664           0 :   if (index < 0) {
    7665           0 :     return NS_ERROR_FAILURE;
    7666           0 :   }
    7667           0 : 
    7668             :   int32_t numRadios = radioGroup->mRadioButtons.Count();
    7669             :   RefPtr<HTMLInputElement> radio;
    7670           0 :   do {
    7671           0 :     if (aPrevious) {
    7672             :       if (--index < 0) {
    7673           0 :         index = numRadios -1;
    7674             :       }
    7675           0 :     }
    7676           0 :     else if (++index >= numRadios) {
    7677             :       index = 0;
    7678           0 :     }
    7679             :     NS_ASSERTION(static_cast<nsGenericHTMLFormElement*>(radioGroup->mRadioButtons[index])->IsHTMLElement(nsGkAtoms::input),
    7680             :                  "mRadioButtons holding a non-radio button");
    7681             :     radio = static_cast<HTMLInputElement*>(radioGroup->mRadioButtons[index]);
    7682             :   } while (radio->Disabled() && radio != currentRadio);
    7683           0 : 
    7684             :   radio.forget(aRadioOut);
    7685             :   return NS_OK;
    7686           0 : }
    7687           0 : 
    7688             : void
    7689           0 : nsDocument::AddToRadioGroup(const nsAString& aName,
    7690           0 :                             HTMLInputElement* aRadio)
    7691             : {
    7692           0 :   nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName);
    7693             :   radioGroup->mRadioButtons.AppendObject(aRadio);
    7694             : 
    7695           0 :   if (aRadio->IsRequired()) {
    7696             :     radioGroup->mRequiredRadioCount++;
    7697             :   }
    7698           0 : }
    7699           0 : 
    7700             : void
    7701           0 : nsDocument::RemoveFromRadioGroup(const nsAString& aName,
    7702           0 :                                  HTMLInputElement* aRadio)
    7703             : {
    7704           0 :   nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName);
    7705             :   radioGroup->mRadioButtons.RemoveObject(aRadio);
    7706           0 : 
    7707             :   if (aRadio->IsRequired()) {
    7708             :     NS_ASSERTION(radioGroup->mRequiredRadioCount != 0,
    7709           0 :                  "mRequiredRadioCount about to wrap below 0!");
    7710             :     radioGroup->mRequiredRadioCount--;
    7711             :   }
    7712             : }
    7713           0 : 
    7714             : NS_IMETHODIMP
    7715           0 : nsDocument::WalkRadioGroup(const nsAString& aName,
    7716           0 :                            nsIRadioVisitor* aVisitor,
    7717             :                            bool aFlushContent)
    7718             : {
    7719             :   nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName);
    7720             : 
    7721             :   for (int i = 0; i < radioGroup->mRadioButtons.Count(); i++) {
    7722             :     if (!aVisitor->Visit(radioGroup->mRadioButtons[i])) {
    7723             :       return NS_OK;
    7724             :     }
    7725           0 :   }
    7726             : 
    7727           0 :   return NS_OK;
    7728           0 : }
    7729             : 
    7730             : uint32_t
    7731             : nsDocument::GetRequiredRadioCount(const nsAString& aName) const
    7732           0 : {
    7733             :   nsRadioGroupStruct* radioGroup = GetRadioGroup(aName);
    7734           0 :   return radioGroup ? radioGroup->mRequiredRadioCount : 0;
    7735             : }
    7736           0 : 
    7737           0 : void
    7738             : nsDocument::RadioRequiredWillChange(const nsAString& aName, bool aRequiredAdded)
    7739           0 : {
    7740             :   nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName);
    7741           0 : 
    7742             :   if (aRequiredAdded) {
    7743           0 :     radioGroup->mRequiredRadioCount++;
    7744             :   } else {
    7745             :     NS_ASSERTION(radioGroup->mRequiredRadioCount != 0,
    7746           0 :                  "mRequiredRadioCount about to wrap below 0!");
    7747             :     radioGroup->mRequiredRadioCount--;
    7748           0 :   }
    7749           0 : }
    7750             : 
    7751             : bool
    7752             : nsDocument::GetValueMissingState(const nsAString& aName) const
    7753           0 : {
    7754             :   nsRadioGroupStruct* radioGroup = GetRadioGroup(aName);
    7755           0 :   return radioGroup && radioGroup->mGroupSuffersFromValueMissing;
    7756           0 : }
    7757           0 : 
    7758             : void
    7759             : nsDocument::SetValueMissingState(const nsAString& aName, bool aValue)
    7760           0 : {
    7761             :   nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName);
    7762          52 :   radioGroup->mGroupSuffersFromValueMissing = aValue;
    7763             : }
    7764             : 
    7765         104 : void
    7766           0 : nsDocument::RetrieveRelevantHeaders(nsIChannel *aChannel)
    7767          52 : {
    7768           0 :   PRTime modDate = 0;
    7769             :   nsresult rv;
    7770             : 
    7771           0 :   nsCOMPtr<nsIHttpChannel> httpChannel;
    7772           0 :   rv = GetHttpChannelHelper(aChannel, getter_AddRefs(httpChannel));
    7773           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    7774           0 :     return;
    7775             :   }
    7776           0 : 
    7777             :   if (httpChannel) {
    7778           0 :     nsAutoCString tmp;
    7779           0 :     rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("last-modified"),
    7780           0 :                                         tmp);
    7781             : 
    7782             :     if (NS_SUCCEEDED(rv)) {
    7783             :       PRTime time;
    7784             :       PRStatus st = PR_ParseTimeString(tmp.get(), true, &time);
    7785           0 :       if (st == PR_SUCCESS) {
    7786           0 :         modDate = time;
    7787             :       }
    7788             :     }
    7789             : 
    7790             :     // The misspelled key 'referer' is as per the HTTP spec
    7791             :     rv = httpChannel->GetRequestHeader(NS_LITERAL_CSTRING("referer"),
    7792             :                                        mReferrer);
    7793             : 
    7794             :     static const char *const headers[] = {
    7795             :       "default-style",
    7796             :       "content-style-type",
    7797             :       "content-language",
    7798             :       "content-disposition",
    7799             :       "refresh",
    7800             :       "x-dns-prefetch-control",
    7801             :       "x-frame-options",
    7802             :       "referrer-policy",
    7803           0 :       // add more http headers if you need
    7804           0 :       // XXXbz don't add content-location support without reading bug
    7805           0 :       // 238654 and its dependencies/dups first.
    7806             :       0
    7807           0 :     };
    7808           0 : 
    7809           0 :     nsAutoCString headerVal;
    7810           0 :     const char *const *name = headers;
    7811             :     while (*name) {
    7812           0 :       rv =
    7813             :         httpChannel->GetResponseHeader(nsDependentCString(*name), headerVal);
    7814             :       if (NS_SUCCEEDED(rv) && !headerVal.IsEmpty()) {
    7815         104 :         RefPtr<nsAtom> key = NS_Atomize(*name);
    7816           0 :         SetHeaderData(key, NS_ConvertASCIItoUTF16(headerVal));
    7817           0 :       }
    7818           0 :       ++name;
    7819           0 :     }
    7820             :   } else {
    7821           0 :     nsCOMPtr<nsIFileChannel> fileChannel = do_QueryInterface(aChannel);
    7822             :     if (fileChannel) {
    7823           0 :       nsCOMPtr<nsIFile> file;
    7824           0 :       fileChannel->GetFile(getter_AddRefs(file));
    7825             :       if (file) {
    7826             :         PRTime msecs;
    7827             :         rv = file->GetLastModifiedTime(&msecs);
    7828           0 : 
    7829          52 :         if (NS_SUCCEEDED(rv)) {
    7830          52 :           modDate = msecs * int64_t(PR_USEC_PER_MSEC);
    7831           0 :         }
    7832           0 :       }
    7833             :     } else {
    7834             :       nsAutoCString contentDisp;
    7835             :       rv = aChannel->GetContentDispositionHeader(contentDisp);
    7836             :       if (NS_SUCCEEDED(rv)) {
    7837          52 :         SetHeaderData(nsGkAtoms::headerContentDisposition,
    7838          52 :                       NS_ConvertASCIItoUTF16(contentDisp));
    7839           0 :       }
    7840             :     }
    7841             :   }
    7842             : 
    7843             :   mLastModified.Truncate();
    7844          54 :   if (modDate != 0) {
    7845             :     GetFormattedTimeString(modDate, mLastModified);
    7846             :   }
    7847             : }
    7848           0 : 
    7849          54 : already_AddRefed<Element>
    7850           0 : nsIDocument::CreateElem(const nsAString& aName, nsAtom *aPrefix,
    7851           0 :                         int32_t aNamespaceID, const nsAString* aIs)
    7852             : {
    7853           0 : #ifdef DEBUG
    7854             :   nsAutoString qName;
    7855             :   if (aPrefix) {
    7856             :     aPrefix->ToString(qName);
    7857             :     qName.Append(':');
    7858         108 :   }
    7859          54 :   qName.Append(aName);
    7860             : 
    7861             :   // Note: "a:b:c" is a valid name in non-namespaces XML, and
    7862             :   // nsIDocument::CreateElement can call us with such a name and no prefix,
    7863             :   // which would cause an error if we just used true here.
    7864         108 :   bool nsAware = aPrefix != nullptr || aNamespaceID != GetDefaultNamespaceID();
    7865          54 :   NS_ASSERTION(NS_SUCCEEDED(nsContentUtils::CheckQName(qName, nsAware)),
    7866         108 :                "Don't pass invalid prefixes to nsDocument::CreateElem, "
    7867          54 :                "check caller.");
    7868             : #endif
    7869           0 : 
    7870           0 :   RefPtr<mozilla::dom::NodeInfo> nodeInfo;
    7871           0 :   mNodeInfoManager->GetNodeInfo(aName, aPrefix, aNamespaceID,
    7872          54 :                                 ELEMENT_NODE, getter_AddRefs(nodeInfo));
    7873             :   NS_ENSURE_TRUE(nodeInfo, nullptr);
    7874             : 
    7875             :   nsCOMPtr<Element> element;
    7876           0 :   nsresult rv = NS_NewElement(getter_AddRefs(element), nodeInfo.forget(),
    7877             :                               NOT_FROM_PARSER, aIs);
    7878          75 :   return NS_SUCCEEDED(rv) ? element.forget() : nullptr;
    7879          75 : }
    7880             : 
    7881             : bool
    7882           0 : nsIDocument::IsSafeToFlush() const
    7883             : {
    7884             :   nsIPresShell* shell = GetShell();
    7885             :   if (!shell)
    7886           0 :     return true;
    7887             : 
    7888             :   return shell->IsSafeToFlush();
    7889             : }
    7890             : 
    7891             : void
    7892             : nsIDocument::Sanitize()
    7893             : {
    7894             :   // Sanitize the document by resetting all password fields and any form
    7895             :   // fields with autocomplete=off to their default values.  We do this now,
    7896             :   // instead of when the presentation is restored, to offer some protection
    7897           0 :   // in case there is ever an exploit that allows a cached document to be
    7898             :   // accessed from a different document.
    7899           0 : 
    7900             :   // First locate all input elements, regardless of whether they are
    7901           0 :   // in a form, and reset the password and autocomplete=off elements.
    7902           0 : 
    7903           0 :   RefPtr<nsContentList> nodes = GetElementsByTagName(NS_LITERAL_STRING("input"));
    7904             : 
    7905           0 :   nsAutoString value;
    7906           0 : 
    7907           0 :   uint32_t length = nodes->Length(true);
    7908             :   for (uint32_t i = 0; i < length; ++i) {
    7909           0 :     NS_ASSERTION(nodes->Item(i), "null item in node list!");
    7910             : 
    7911           0 :     RefPtr<HTMLInputElement> input = HTMLInputElement::FromNodeOrNull(nodes->Item(i));
    7912           0 :     if (!input)
    7913             :       continue;
    7914             : 
    7915           0 :     bool resetValue = false;
    7916           0 : 
    7917           0 :     input->GetAttribute(NS_LITERAL_STRING("autocomplete"), value);
    7918             :     if (value.LowerCaseEqualsLiteral("off")) {
    7919             :       resetValue = true;
    7920           0 :     } else {
    7921           0 :       input->GetType(value);
    7922             :       if (value.LowerCaseEqualsLiteral("password"))
    7923             :         resetValue = true;
    7924             :     }
    7925             : 
    7926           0 :     if (resetValue) {
    7927             :       input->Reset();
    7928           0 :     }
    7929           0 :   }
    7930           0 : 
    7931             :   // Now locate all _form_ elements that have autocomplete=off and reset them
    7932           0 :   nodes = GetElementsByTagName(NS_LITERAL_STRING("form"));
    7933           0 : 
    7934             :   length = nodes->Length(true);
    7935             :   for (uint32_t i = 0; i < length; ++i) {
    7936           0 :     NS_ASSERTION(nodes->Item(i), "null item in nodelist");
    7937           0 : 
    7938           0 :     HTMLFormElement* form = HTMLFormElement::FromNode(nodes->Item(i));
    7939             :     if (!form)
    7940           0 :       continue;
    7941             : 
    7942             :     form->GetAttr(kNameSpaceID_None, nsGkAtoms::autocomplete, value);
    7943          35 :     if (value.LowerCaseEqualsLiteral("off"))
    7944             :       form->Reset();
    7945          35 :   }
    7946          21 : }
    7947             : 
    7948             : void
    7949             : nsIDocument::EnumerateSubDocuments(nsSubDocEnumFunc aCallback, void *aData)
    7950             : {
    7951          28 :   if (!mSubDocuments) {
    7952          56 :     return;
    7953          14 :   }
    7954          14 : 
    7955           0 :   // PLDHashTable::Iterator can't handle modifications while iterating so we
    7956           0 :   // copy all entries to an array first before calling any callbacks.
    7957             :   AutoTArray<nsCOMPtr<nsIDocument>, 8> subdocs;
    7958             :   for (auto iter = mSubDocuments->Iter(); !iter.Done(); iter.Next()) {
    7959           0 :     auto entry = static_cast<SubDocMapEntry*>(iter.Get());
    7960           0 :     nsIDocument* subdoc = entry->mSubDocument;
    7961             :     if (subdoc) {
    7962             :       subdocs.AppendElement(subdoc);
    7963             :     }
    7964             :   }
    7965             :   for (auto subdoc : subdocs) {
    7966             :     if (!aCallback(subdoc, aData)) {
    7967          80 :       break;
    7968             :     }
    7969             :   }
    7970             : }
    7971           0 : 
    7972             : void
    7973             : nsIDocument::CollectDescendantDocuments(
    7974             :   nsTArray<nsCOMPtr<nsIDocument>>& aDescendants,
    7975           0 :   nsDocTestFunc aCallback) const
    7976          26 : {
    7977          26 :   if (!mSubDocuments) {
    7978          26 :     return;
    7979           0 :   }
    7980           0 : 
    7981             :   for (auto iter = mSubDocuments->Iter(); !iter.Done(); iter.Next()) {
    7982           0 :     auto entry = static_cast<SubDocMapEntry*>(iter.Get());
    7983             :     const nsIDocument* subdoc = entry->mSubDocument;
    7984             :     if (subdoc) {
    7985             :       if (aCallback(subdoc)) {
    7986             :         aDescendants.AppendElement(entry->mSubDocument);
    7987             :       }
    7988             :       subdoc->CollectDescendantDocuments(aDescendants, aCallback);
    7989             :     }
    7990             :   }
    7991             : }
    7992           0 : 
    7993             : #ifdef DEBUG_bryner
    7994           0 : #define DEBUG_PAGE_CACHE
    7995             : #endif
    7996             : 
    7997             : bool
    7998           0 : nsIDocument::CanSavePresentation(nsIRequest *aNewRequest)
    7999             : {
    8000             :   if (!IsBFCachingAllowed()) {
    8001             :     return false;
    8002             :   }
    8003             : 
    8004             :   if (EventHandlingSuppressed()) {
    8005             :     return false;
    8006             :   }
    8007           0 : 
    8008           0 :   // Do not allow suspended windows to be placed in the
    8009             :   // bfcache.  This method is also used to verify a document
    8010             :   // coming out of the bfcache is ok to restore, though.  So
    8011             :   // we only want to block suspend windows that aren't also
    8012             :   // frozen.
    8013           0 :   nsPIDOMWindowInner* win = GetInnerWindow();
    8014           0 :   if (win && win->IsSuspended() && !win->IsFrozen()) {
    8015           0 :     return false;
    8016           0 :   }
    8017             : 
    8018             :   // Check our event listener manager for unload/beforeunload listeners.
    8019             :   nsCOMPtr<EventTarget> piTarget = do_QueryInterface(mScriptGlobalObject);
    8020             :   if (piTarget) {
    8021             :     EventListenerManager* manager = piTarget->GetExistingListenerManager();
    8022           0 :     if (manager && manager->HasUnloadListeners()) {
    8023           0 :       return false;
    8024           0 :     }
    8025           0 :   }
    8026             : 
    8027           0 :   // Check if we have pending network requests
    8028             :   nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup();
    8029             :   if (loadGroup) {
    8030             :     nsCOMPtr<nsISimpleEnumerator> requests;
    8031             :     loadGroup->GetRequests(getter_AddRefs(requests));
    8032           0 : 
    8033           0 :     bool hasMore = false;
    8034           0 : 
    8035           0 :     // We want to bail out if we have any requests other than aNewRequest (or
    8036             :     // in the case when aNewRequest is a part of a multipart response the base
    8037             :     // channel the multipart response is coming in on).
    8038           0 :     nsCOMPtr<nsIChannel> baseChannel;
    8039           0 :     nsCOMPtr<nsIMultiPartChannel> part(do_QueryInterface(aNewRequest));
    8040           0 :     if (part) {
    8041             :       part->GetBaseChannel(getter_AddRefs(baseChannel));
    8042           0 :     }
    8043           0 : 
    8044             :     while (NS_SUCCEEDED(requests->HasMoreElements(&hasMore)) && hasMore) {
    8045             :       nsCOMPtr<nsISupports> elem;
    8046             :       requests->GetNext(getter_AddRefs(elem));
    8047             : 
    8048             :       nsCOMPtr<nsIRequest> request = do_QueryInterface(elem);
    8049             :       if (request && request != aNewRequest && request != baseChannel) {
    8050             : #ifdef DEBUG_PAGE_CACHE
    8051             :         nsAutoCString requestName, docSpec;
    8052             :         request->GetName(requestName);
    8053           0 :         if (mDocumentURI)
    8054             :           mDocumentURI->GetSpec(docSpec);
    8055             : 
    8056             :         printf("document %s has request %s\n",
    8057             :                docSpec.get(), requestName.get());
    8058             : #endif
    8059           0 :         return false;
    8060           0 :       }
    8061             :     }
    8062             :   }
    8063             : 
    8064             :   // Check if we have active GetUserMedia use
    8065             :   if (MediaManager::Exists() && win &&
    8066           0 :       MediaManager::Get()->IsWindowStillActive(win->WindowID())) {
    8067             :     return false;
    8068             :   }
    8069             : 
    8070             : #ifdef MOZ_WEBRTC
    8071             :   // Check if we have active PeerConnections
    8072             :   if (win && win->HasActivePeerConnections()) {
    8073           0 :     return false;
    8074             :   }
    8075             : #endif // MOZ_WEBRTC
    8076             : 
    8077             :   // Don't save presentations for documents containing EME content, so that
    8078             :   // CDMs reliably shutdown upon user navigation.
    8079           0 :   if (ContainsEMEContent()) {
    8080             :     return false;
    8081             :   }
    8082             : 
    8083           0 :   // Don't save presentations for documents containing MSE content, to
    8084           0 :   // reduce memory usage.
    8085           0 :   if (ContainsMSEContent()) {
    8086           0 :     return false;
    8087             :   }
    8088             : 
    8089           0 :   if (mSubDocuments) {
    8090           0 :     for (auto iter = mSubDocuments->Iter(); !iter.Done(); iter.Next()) {
    8091           0 :       auto entry = static_cast<SubDocMapEntry*>(iter.Get());
    8092             :       nsIDocument* subdoc = entry->mSubDocument;
    8093             : 
    8094             :       // The aIgnoreRequest we were passed is only for us, so don't pass it on.
    8095             :       bool canCache = subdoc ? subdoc->CanSavePresentation(nullptr) : false;
    8096             :       if (!canCache) {
    8097           0 :         return false;
    8098           0 :       }
    8099             :     }
    8100           0 :   }
    8101             : 
    8102             : 
    8103             :   if (win) {
    8104           0 :     auto* globalWindow = nsGlobalWindowInner::Cast(win);
    8105             : #ifdef MOZ_WEBSPEECH
    8106             :     if (globalWindow->HasActiveSpeechSynthesis()) {
    8107             :       return false;
    8108             :     }
    8109             : #endif
    8110             :     if (globalWindow->HasUsedVR()) {
    8111             :       return false;
    8112             :     }
    8113           8 :   }
    8114             : 
    8115             :   return true;
    8116             : }
    8117           0 : 
    8118             : void
    8119             : nsDocument::Destroy()
    8120           8 : {
    8121             :   // The ContentViewer wants to release the document now.  So, tell our content
    8122          24 :   // to drop any references to the document so that it can be destroyed.
    8123           8 :   if (mIsGoingAway)
    8124           0 :     return;
    8125             : 
    8126           0 :   mIsGoingAway = true;
    8127           0 : 
    8128           0 :   ScriptLoader()->Destroy();
    8129          16 :   SetScriptGlobalObject(nullptr);
    8130           0 :   RemovedFromDocShell();
    8131             : 
    8132           0 :   bool oldVal = mInUnlinkOrDeletion;
    8133             :   mInUnlinkOrDeletion = true;
    8134           0 : 
    8135             : #ifdef DEBUG
    8136             :   uint32_t oldChildCount = GetChildCount();
    8137             : #endif
    8138             : 
    8139           8 :   for (nsIContent* child = GetFirstChild(); child;
    8140             :        child = child->GetNextSibling()) {
    8141             :     child->DestroyContent();
    8142             :     MOZ_ASSERT(child->GetParentNode() == this);
    8143           0 :   }
    8144             :   MOZ_ASSERT(oldChildCount == GetChildCount());
    8145          16 : 
    8146             :   mInUnlinkOrDeletion = oldVal;
    8147             : 
    8148           8 :   mLayoutHistoryState = nullptr;
    8149           0 : 
    8150             :   // Shut down our external resource map.  We might not need this for
    8151           8 :   // leak-fixing if we fix nsDocumentViewer to do cycle-collection, but
    8152           0 :   // tearing down all those frame trees right now is the right thing to do.
    8153           0 :   mExternalResourceMap.Shutdown();
    8154             : }
    8155             : 
    8156             : void
    8157             : nsDocument::RemovedFromDocShell()
    8158          58 : {
    8159             :   if (mRemovedFromDocShell)
    8160         116 :     return;
    8161         116 : 
    8162           0 :   mRemovedFromDocShell = true;
    8163             :   EnumerateActivityObservers(NotifyActivityChanged, nullptr);
    8164           0 : 
    8165           0 :   for (nsIContent* child = GetFirstChild(); child;
    8166           0 :        child = child->GetNextSibling()) {
    8167             :     child->SaveSubtreeState();
    8168             :   }
    8169             : }
    8170           0 : 
    8171             : already_AddRefed<nsILayoutHistoryState>
    8172             : nsIDocument::GetLayoutHistoryState() const
    8173             : {
    8174           0 :   nsCOMPtr<nsILayoutHistoryState> state;
    8175             :   if (!mScriptGlobalObject) {
    8176             :     state = mLayoutHistoryState;
    8177             :   } else {
    8178           0 :     nsCOMPtr<nsIDocShell> docShell(mDocumentContainer);
    8179           0 :     if (docShell) {
    8180           0 :       docShell->GetLayoutHistoryState(getter_AddRefs(state));
    8181             :     }
    8182           0 :   }
    8183           0 : 
    8184             :   return state.forget();
    8185           0 : }
    8186           0 : 
    8187           0 : void
    8188           0 : nsIDocument::EnsureOnloadBlocker()
    8189           0 : {
    8190           0 :   // If mScriptGlobalObject is null, we shouldn't be messing with the loadgroup
    8191           0 :   // -- it's not ours.
    8192             :   if (mOnloadBlockCount != 0 && mScriptGlobalObject) {
    8193             :     nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup();
    8194             :     if (loadGroup) {
    8195             :       // Check first to see if mOnloadBlocker is in the loadgroup.
    8196           0 :       nsCOMPtr<nsISimpleEnumerator> requests;
    8197             :       loadGroup->GetRequests(getter_AddRefs(requests));
    8198             : 
    8199             :       bool hasMore = false;
    8200             :       while (NS_SUCCEEDED(requests->HasMoreElements(&hasMore)) && hasMore) {
    8201             :         nsCOMPtr<nsISupports> elem;
    8202           3 :         requests->GetNext(getter_AddRefs(elem));
    8203             :         nsCOMPtr<nsIRequest> request = do_QueryInterface(elem);
    8204           9 :         if (request && request == mOnloadBlocker) {
    8205           3 :           return;
    8206           0 :         }
    8207             :       }
    8208           0 : 
    8209             :       // Not in the loadgroup, so add it.
    8210             :       loadGroup->AddRequest(mOnloadBlocker, nullptr);
    8211         212 :     }
    8212             :   }
    8213         424 : }
    8214           0 : 
    8215           0 : void
    8216             : nsDocument::AsyncBlockOnload()
    8217             : {
    8218             :   while (mAsyncOnloadBlockCount) {
    8219             :     --mAsyncOnloadBlockCount;
    8220         280 :     BlockOnload();
    8221          23 :   }
    8222             : }
    8223             : 
    8224           0 : void
    8225           0 : nsDocument::BlockOnload()
    8226           9 : {
    8227           3 :   if (mDisplayDocument) {
    8228             :     mDisplayDocument->BlockOnload();
    8229           0 :     return;
    8230             :   }
    8231           0 : 
    8232          20 :   // If mScriptGlobalObject is null, we shouldn't be messing with the loadgroup
    8233           0 :   // -- it's not ours.
    8234             :   if (mOnloadBlockCount == 0 && mScriptGlobalObject) {
    8235             :     if (!nsContentUtils::IsSafeToRunScript()) {
    8236           0 :       // Because AddRequest may lead to OnStateChange calls in chrome,
    8237             :       // block onload only when there are no script blockers.
    8238             :       ++mAsyncOnloadBlockCount;
    8239             :       if (mAsyncOnloadBlockCount == 1) {
    8240           0 :         nsContentUtils::AddScriptRunner(NewRunnableMethod(
    8241             :           "nsDocument::AsyncBlockOnload", this, &nsDocument::AsyncBlockOnload));
    8242         418 :       }
    8243           0 :       return;
    8244           0 :     }
    8245             :     nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup();
    8246             :     if (loadGroup) {
    8247           0 :       loadGroup->AddRequest(mOnloadBlocker, nullptr);
    8248           0 :     }
    8249             :   }
    8250             :   ++mOnloadBlockCount;
    8251             : }
    8252           1 : 
    8253             : void
    8254         209 : nsDocument::UnblockOnload(bool aFireSync)
    8255         130 : {
    8256             :   if (mDisplayDocument) {
    8257             :     mDisplayDocument->UnblockOnload(aFireSync);
    8258           0 :     return;
    8259             :   }
    8260          10 : 
    8261          10 :   if (mOnloadBlockCount == 0 && mAsyncOnloadBlockCount == 0) {
    8262             :     NS_NOTREACHED("More UnblockOnload() calls than BlockOnload() calls; dropping call");
    8263          10 :     return;
    8264             :   }
    8265           0 : 
    8266             :   --mOnloadBlockCount;
    8267             : 
    8268             :   if (mOnloadBlockCount == 0) {
    8269             :     if (mScriptGlobalObject) {
    8270             :       // Only manipulate the loadgroup in this case, because if mScriptGlobalObject
    8271             :       // is null, it's not ours.
    8272             :       if (aFireSync && mAsyncOnloadBlockCount == 0) {
    8273             :         // Increment mOnloadBlockCount, since DoUnblockOnload will decrement it
    8274          13 :         ++mOnloadBlockCount;
    8275             :         DoUnblockOnload();
    8276          52 :       } else {
    8277          13 :         PostUnblockOnloadEvent();
    8278             :       }
    8279             :     } else if (mIsBeingUsedAsImage) {
    8280             :       // To correctly unblock onload for a document that contains an SVG
    8281             :       // image, we need to know when all of the SVG document's resources are
    8282          30 :       // done loading, in a way comparable to |window.onload|. We fire this
    8283             :       // event to indicate that the SVG should be considered fully loaded.
    8284          10 :       // Because scripting is disabled on SVG-as-image documents, this event
    8285          10 :       // is not accessible to content authors. (See bug 837315.)
    8286           0 :       RefPtr<AsyncEventDispatcher> asyncDispatcher =
    8287             :         new AsyncEventDispatcher(this,
    8288           0 :                                  NS_LITERAL_STRING("MozSVGAsImageDocumentLoad"),
    8289           0 :                                  false,
    8290           0 :                                  false);
    8291          10 :       asyncDispatcher->PostDOMEvent();
    8292             :     }
    8293             :   }
    8294             : }
    8295             : 
    8296             : class nsUnblockOnloadEvent : public Runnable {
    8297             : public:
    8298          10 :   explicit nsUnblockOnloadEvent(nsIDocument* aDoc)
    8299             :     : mozilla::Runnable("nsUnblockOnloadEvent")
    8300          10 :     , mDoc(aDoc)
    8301          20 :   {
    8302             :   }
    8303          10 :   NS_IMETHOD Run() override {
    8304           0 :     mDoc->DoUnblockOnload();
    8305             :     return NS_OK;
    8306          10 :   }
    8307             : private:
    8308           0 :   RefPtr<nsIDocument> mDoc;
    8309             : };
    8310           0 : 
    8311             : void
    8312             : nsIDocument::PostUnblockOnloadEvent()
    8313          20 : {
    8314             :   MOZ_RELEASE_ASSERT(NS_IsMainThread());
    8315          40 :   nsCOMPtr<nsIRunnable> evt = new nsUnblockOnloadEvent(this);
    8316             :   nsresult rv =
    8317           0 :     Dispatch(TaskCategory::Other, evt.forget());
    8318             :   if (NS_SUCCEEDED(rv)) {
    8319             :     // Stabilize block count so we don't post more events while this one is up
    8320             :     ++mOnloadBlockCount;
    8321           0 :   } else {
    8322             :     NS_WARNING("failed to dispatch nsUnblockOnloadEvent");
    8323          20 :   }
    8324             : }
    8325             : 
    8326             : void
    8327             : nsIDocument::DoUnblockOnload()
    8328             : {
    8329          20 :   MOZ_ASSERT(!mDisplayDocument,
    8330             :                   "Shouldn't get here for resource document");
    8331           0 :   MOZ_ASSERT(mOnloadBlockCount != 0,
    8332             :              "Shouldn't have a count of zero here, since we stabilized in "
    8333             :              "PostUnblockOnloadEvent");
    8334             : 
    8335             :   --mOnloadBlockCount;
    8336          40 : 
    8337          24 :   if (mOnloadBlockCount != 0) {
    8338          12 :     // We blocked again after the last unblock.  Nothing to do here.  We'll
    8339          24 :     // post a new event when we unblock again.
    8340             :     return;
    8341             :   }
    8342             : 
    8343             :   if (mAsyncOnloadBlockCount != 0) {
    8344             :     // We need to wait until the async onload block has been handled.
    8345           0 :     PostUnblockOnloadEvent();
    8346             :   }
    8347           0 : 
    8348             :   // If mScriptGlobalObject is null, we shouldn't be messing with the loadgroup
    8349           0 :   // -- it's not ours.
    8350           0 :   if (mScriptGlobalObject) {
    8351             :     nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup();
    8352             :     if (loadGroup) {
    8353           0 :       loadGroup->RemoveRequest(mOnloadBlocker, nullptr, NS_OK);
    8354             :     }
    8355             :   }
    8356             : }
    8357             : 
    8358             : nsIContent*
    8359           0 : nsIDocument::GetContentInThisDocument(nsIFrame* aFrame) const
    8360             : {
    8361             :   for (nsIFrame* f = aFrame; f;
    8362             :        f = nsLayoutUtils::GetParentOrPlaceholderForCrossDoc(f)) {
    8363             :     nsIContent* content = f->GetContent();
    8364             :     if (!content || content->IsInAnonymousSubtree())
    8365             :       continue;
    8366          17 : 
    8367             :     if (content->OwnerDoc() == this) {
    8368             :       return content;
    8369             :     }
    8370           0 :     // We must be in a subdocument so jump directly to the root frame.
    8371           0 :     // GetParentOrPlaceholderForCrossDoc gets called immediately to jump up to
    8372             :     // the containing document.
    8373             :     f = f->PresContext()->GetPresShell()->GetRootFrame();
    8374           0 :   }
    8375           0 : 
    8376          17 :   return nullptr;
    8377          17 : }
    8378             : 
    8379           0 : void
    8380           0 : nsIDocument::DispatchPageTransition(EventTarget* aDispatchTarget,
    8381             :                                     const nsAString& aType,
    8382             :                                     bool aPersisted)
    8383           0 : {
    8384             :   if (!aDispatchTarget) {
    8385          17 :     return;
    8386          17 :   }
    8387             : 
    8388          17 :   PageTransitionEventInit init;
    8389             :   init.mBubbles = true;
    8390             :   init.mCancelable = true;
    8391             :   init.mPersisted = aPersisted;
    8392           0 : 
    8393             :   nsDocShell* docShell = mDocumentContainer.get();
    8394           0 :   init.mInFrameSwap = docShell && docShell->InFrameSwap();
    8395           0 : 
    8396           0 :   RefPtr<PageTransitionEvent> event =
    8397             :     PageTransitionEvent::Constructor(this, aType, init);
    8398             : 
    8399             :   event->SetTrusted(true);
    8400           0 :   event->SetTarget(this);
    8401             :   EventDispatcher::DispatchDOMEvent(aDispatchTarget, nullptr, event,
    8402           9 :                                     nullptr, nullptr);
    8403             : }
    8404           0 : 
    8405           9 : static bool
    8406             : NotifyPageShow(nsIDocument* aDocument, void* aData)
    8407           9 : {
    8408           0 :   const bool* aPersistedPtr = static_cast<const bool*>(aData);
    8409             :   aDocument->OnPageShow(*aPersistedPtr, nullptr);
    8410           0 :   return true;
    8411             : }
    8412           0 : 
    8413             : void
    8414           0 : nsIDocument::OnPageShow(bool aPersisted, EventTarget* aDispatchStartTarget)
    8415           0 : {
    8416           0 :   mVisible = true;
    8417             : 
    8418             :   EnumerateActivityObservers(NotifyActivityChanged, nullptr);
    8419             :   EnumerateExternalResources(NotifyPageShow, &aPersisted);
    8420             : 
    8421           9 :   Element* root = GetRootElement();
    8422             :   if (aPersisted && root) {
    8423             :     // Send out notifications that our <link> elements are attached.
    8424           9 :     RefPtr<nsContentList> links = NS_GetContentList(root,
    8425             :                                                       kNameSpaceID_XHTML,
    8426             :                                                       NS_LITERAL_STRING("link"));
    8427          18 : 
    8428           0 :     uint32_t linkCount = links->Length(true);
    8429             :     for (uint32_t i = 0; i < linkCount; ++i) {
    8430             :       static_cast<HTMLLinkElement*>(links->Item(i, false))->LinkAdded();
    8431           0 :     }
    8432           0 :   }
    8433             : 
    8434             :   // See nsIDocument
    8435           0 :   if (!aDispatchStartTarget) {
    8436             :     // Set mIsShowing before firing events, in case those event handlers
    8437           9 :     // move us around.
    8438             :     mIsShowing = true;
    8439           0 :   }
    8440           9 : 
    8441           0 :   if (mAnimationController) {
    8442          18 :     mAnimationController->OnPageShow();
    8443           0 :   }
    8444             : 
    8445             :   if (aPersisted) {
    8446           0 :     ImageTracker()->SetAnimatingState(true);
    8447             :   }
    8448             : 
    8449          18 :   UpdateVisibilityState();
    8450           0 : 
    8451          18 :   if (!mIsBeingUsedAsImage) {
    8452             :     // Dispatch observer notification to notify observers page is shown.
    8453           0 :     nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
    8454             :     if (os) {
    8455           0 :       nsIPrincipal* principal = NodePrincipal();
    8456             :       os->NotifyObservers(this,
    8457             :                           nsContentUtils::IsSystemPrincipal(principal) ?
    8458           0 :                             "chrome-page-shown" :
    8459             :                             "content-page-shown",
    8460           0 :                           nullptr);
    8461           0 :     }
    8462           0 : 
    8463             :     nsCOMPtr<EventTarget> target = aDispatchStartTarget;
    8464             :     if (!target) {
    8465             :       target = do_QueryInterface(GetWindow());
    8466           0 :     }
    8467             :     DispatchPageTransition(target, NS_LITERAL_STRING("pageshow"), aPersisted);
    8468             :   }
    8469           0 : }
    8470           0 : 
    8471           0 : static bool
    8472           0 : NotifyPageHide(nsIDocument* aDocument, void* aData)
    8473           0 : {
    8474             :   const bool* aPersistedPtr = static_cast<const bool*>(aData);
    8475           0 :   aDocument->OnPageHide(*aPersistedPtr, nullptr);
    8476           0 :   return true;
    8477             : }
    8478           0 : 
    8479             : static void
    8480             : DispatchCustomEventWithFlush(nsINode* aTarget, const nsAString& aEventType,
    8481           0 :                              bool aBubbles, bool aOnlyChromeDispatch)
    8482             : {
    8483             :   RefPtr<Event> event = NS_NewDOMEvent(aTarget, nullptr, nullptr);
    8484           0 :   event->InitEvent(aEventType, aBubbles, false);
    8485           0 :   event->SetTrusted(true);
    8486           0 :   if (aOnlyChromeDispatch) {
    8487             :     event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
    8488             :   }
    8489             :   if (nsPresContext* presContext = aTarget->OwnerDoc()->GetPresContext()) {
    8490             :     presContext->RefreshDriver()->ScheduleEventDispatch(aTarget, event);
    8491           8 :   }
    8492             : }
    8493          16 : 
    8494           0 : static void
    8495           0 : DispatchFullScreenChange(nsIDocument* aTarget)
    8496             : {
    8497           0 :   DispatchCustomEventWithFlush(
    8498           0 :     aTarget, NS_LITERAL_STRING("fullscreenchange"),
    8499           0 :     /* Bubbles */ true, /* OnlyChrome */ false);
    8500           0 : }
    8501           0 : 
    8502             : static void ClearPendingFullscreenRequests(nsIDocument* aDoc);
    8503             : 
    8504             : void
    8505             : nsIDocument::OnPageHide(bool aPersisted, EventTarget* aDispatchStartTarget)
    8506             : {
    8507           8 :   if (mDocGroup && Telemetry::CanRecordExtended() &&
    8508           8 :       IsTopLevelContentDocument()) {
    8509           0 :     TabGroup* tabGroup = mDocGroup->GetTabGroup();
    8510             : 
    8511           0 :     if (tabGroup) {
    8512             :       Telemetry::Accumulate(Telemetry::ACTIVE_DOCGROUPS_PER_TABGROUP,
    8513           0 :                             tabGroup->Count(true /* aActiveOnly */));
    8514           0 :       Telemetry::Accumulate(Telemetry::TOTAL_DOCGROUPS_PER_TABGROUP,
    8515           0 :                             tabGroup->Count());
    8516             :     }
    8517             :   }
    8518             : 
    8519             :   // Send out notifications that our <link> elements are detached,
    8520           8 :   // but only if this is not a full unload.
    8521             :   Element* root = GetRootElement();
    8522             :   if (aPersisted && root) {
    8523           8 :     RefPtr<nsContentList> links = NS_GetContentList(root,
    8524             :                                                     kNameSpaceID_XHTML,
    8525             :                                                     NS_LITERAL_STRING("link"));
    8526          16 : 
    8527           0 :     uint32_t linkCount = links->Length(true);
    8528             :     for (uint32_t i = 0; i < linkCount; ++i) {
    8529             :       static_cast<HTMLLinkElement*>(links->Item(i, false))->LinkRemoved();
    8530             :     }
    8531             :   }
    8532           8 : 
    8533           8 :   // See nsIDocument
    8534           0 :   if (!aDispatchStartTarget) {
    8535             :     // Set mIsShowing before firing events, in case those event handlers
    8536             :     // move us around.
    8537           0 :     mIsShowing = false;
    8538             :   }
    8539           8 : 
    8540             :   if (mAnimationController) {
    8541           0 :     mAnimationController->OnPageHide();
    8542           8 :   }
    8543           0 : 
    8544          16 :   // We do not stop the animations (bug 1024343)
    8545           0 :   // when the page is refreshing while being dragged out
    8546             :   nsDocShell* docShell = mDocumentContainer.get();
    8547             :   if (aPersisted && !(docShell && docShell->InFrameSwap())) {
    8548           0 :     ImageTracker()->SetAnimatingState(false);
    8549             :   }
    8550             : 
    8551             :   ExitPointerLock();
    8552           0 : 
    8553           8 :   if (!mIsBeingUsedAsImage) {
    8554          16 :     // Dispatch observer notification to notify observers page is hidden.
    8555             :     nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
    8556             :     if (os) {
    8557           0 :       nsIPrincipal* principal = NodePrincipal();
    8558           0 :       os->NotifyObservers(this,
    8559             :                           nsContentUtils::IsSystemPrincipal(principal) ?
    8560             :                             "chrome-page-hidden" :
    8561             :                             "content-page-hidden",
    8562           0 :                           nullptr);
    8563             :     }
    8564           8 : 
    8565             :     // Now send out a PageHide event.
    8566           0 :     nsCOMPtr<EventTarget> target = aDispatchStartTarget;
    8567           8 :     if (!target) {
    8568             :       target = do_QueryInterface(GetWindow());
    8569           8 :     }
    8570           0 :     {
    8571             :       PageUnloadingEventTimeStamp timeStamp(this);
    8572             :       DispatchPageTransition(target, NS_LITERAL_STRING("pagehide"), aPersisted);
    8573             :     }
    8574             :   }
    8575             : 
    8576             :   mVisible = false;
    8577             : 
    8578             :   UpdateVisibilityState();
    8579             : 
    8580           0 :   EnumerateExternalResources(NotifyPageHide, &aPersisted);
    8581             :   EnumerateActivityObservers(NotifyActivityChanged, nullptr);
    8582             : 
    8583             :   ClearPendingFullscreenRequests(this);
    8584             :   if (FullScreenStackTop()) {
    8585             :     // If this document was fullscreen, we should exit fullscreen in this
    8586             :     // doctree branch. This ensures that if the user navigates while in
    8587             :     // fullscreen mode we don't leave its still visible ancestor documents
    8588             :     // in fullscreen mode. So exit fullscreen in the document's fullscreen
    8589             :     // root document, as this will exit fullscreen in all the root's
    8590           0 :     // descendant documents. Note that documents are removed from the
    8591             :     // doctree by the time OnPageHide() is called, so we must store a
    8592             :     // reference to the root (in nsDocument::mFullscreenRoot) since we can't
    8593             :     // just traverse the doctree to get the root.
    8594           0 :     nsIDocument::ExitFullscreenInDocTree(this);
    8595             : 
    8596           8 :     // Since the document is removed from the doctree before OnPageHide() is
    8597             :     // called, ExitFullscreen() can't traverse from the root down to *this*
    8598             :     // document, so we must manually call CleanupFullscreenState() below too.
    8599           0 :     // Note that CleanupFullscreenState() clears nsDocument::mFullscreenRoot,
    8600             :     // so we *must* call it after ExitFullscreen(), not before.
    8601           0 :     // OnPageHide() is called in every hidden (i.e. descendant) document,
    8602             :     // so calling CleanupFullscreenState() here will ensure all hidden
    8603             :     // documents have their fullscreen state reset.
    8604           0 :     CleanupFullscreenState();
    8605           0 : 
    8606             :     // If anyone was listening to this document's state, advertizing the state
    8607             :     // change would be the least of the politeness.
    8608           0 :     DispatchFullScreenChange(this);
    8609           0 :   }
    8610           0 : }
    8611             : 
    8612             : void
    8613           0 : nsIDocument::WillDispatchMutationEvent(nsINode* aTarget)
    8614             : {
    8615             :   NS_ASSERTION(mSubtreeModifiedDepth != 0 ||
    8616           0 :                mSubtreeModifiedTargets.Count() == 0,
    8617             :                "mSubtreeModifiedTargets not cleared after dispatching?");
    8618           0 :   ++mSubtreeModifiedDepth;
    8619           0 :   if (aTarget) {
    8620           0 :     // MayDispatchMutationEvent is often called just before this method,
    8621           0 :     // so it has already appended the node to mSubtreeModifiedTargets.
    8622           0 :     int32_t count = mSubtreeModifiedTargets.Count();
    8623             :     if (!count || mSubtreeModifiedTargets[count - 1] != aTarget) {
    8624             :       mSubtreeModifiedTargets.AppendObject(aTarget);
    8625           0 :     }
    8626           0 :   }
    8627           0 : }
    8628           0 : 
    8629           0 : void
    8630             : nsIDocument::MutationEventDispatched(nsINode* aTarget)
    8631             : {
    8632           0 :   --mSubtreeModifiedDepth;
    8633           0 :   if (mSubtreeModifiedDepth == 0) {
    8634           0 :     int32_t count = mSubtreeModifiedTargets.Count();
    8635           0 :     if (!count) {
    8636           0 :       return;
    8637           0 :     }
    8638             : 
    8639             :     nsPIDOMWindowInner* window = GetInnerWindow();
    8640           0 :     if (window &&
    8641           0 :         !window->HasMutationListeners(NS_EVENT_BITS_MUTATION_SUBTREEMODIFIED)) {
    8642           0 :       mSubtreeModifiedTargets.Clear();
    8643             :       return;
    8644           0 :     }
    8645           0 : 
    8646             :     nsCOMArray<nsINode> realTargets;
    8647             :     for (int32_t i = 0; i < count; ++i) {
    8648             :       nsINode* possibleTarget = mSubtreeModifiedTargets[i];
    8649             :       nsCOMPtr<nsIContent> content = do_QueryInterface(possibleTarget);
    8650           0 :       if (content && content->ChromeOnlyAccess()) {
    8651           0 :         continue;
    8652             :       }
    8653             : 
    8654             :       nsINode* commonAncestor = nullptr;
    8655           0 :       int32_t realTargetCount = realTargets.Count();
    8656             :       for (int32_t j = 0; j < realTargetCount; ++j) {
    8657           0 :         commonAncestor =
    8658           0 :           nsContentUtils::GetCommonAncestor(possibleTarget, realTargets[j]);
    8659           0 :         if (commonAncestor) {
    8660           0 :           realTargets.ReplaceObjectAt(commonAncestor, j);
    8661           0 :           break;
    8662             :         }
    8663             :       }
    8664             :       if (!commonAncestor) {
    8665             :         realTargets.AppendObject(possibleTarget);
    8666             :       }
    8667          46 :     }
    8668             : 
    8669             :     mSubtreeModifiedTargets.Clear();
    8670          46 : 
    8671             :     int32_t realTargetCount = realTargets.Count();
    8672          92 :     for (int32_t k = 0; k < realTargetCount; ++k) {
    8673          92 :       InternalMutationEvent mutation(true, eLegacySubtreeModified);
    8674           0 :       (new AsyncEventDispatcher(realTargets[k], mutation))->
    8675          92 :         RunDOMEventWhenSafe();
    8676           0 :     }
    8677           0 :   }
    8678             : }
    8679             : 
    8680           0 : void
    8681             : nsIDocument::DestroyElementMaps()
    8682             : {
    8683             : #ifdef DEBUG
    8684             :   mStyledLinksCleared = true;
    8685         232 : #endif
    8686         174 :   mStyledLinks.Clear();
    8687           0 :   mIdentifierMap.Clear();
    8688             :   mComposedShadowRoots.Clear();
    8689             :   mResponsiveContent.Clear();
    8690             :   IncrementExpandoGeneration(*this);
    8691           0 : }
    8692         116 : 
    8693           0 : void
    8694             : nsIDocument::RefreshLinkHrefs()
    8695           0 : {
    8696             :   // Get a list of all links we know about.  We will reset them, which will
    8697             :   // remove them from the document, so we need a copy of what is in the
    8698           0 :   // hashtable.
    8699             :   LinkArray linksToNotify(mStyledLinks.Count());
    8700           0 :   for (auto iter = mStyledLinks.ConstIter(); !iter.Done(); iter.Next()) {
    8701             :     linksToNotify.AppendElement(iter.Get()->GetKey());
    8702             :   }
    8703           0 : 
    8704           0 :   // Reset all of our styled links.
    8705             :   nsAutoScriptBlocker scriptBlocker;
    8706           0 :   for (LinkArray::size_type i = 0; i < linksToNotify.Length(); i++) {
    8707           0 :     linksToNotify[i]->ResetLinkState(true, linksToNotify[i]->ElementHasHref());
    8708             :   }
    8709             : }
    8710             : 
    8711           0 : nsresult
    8712           0 : nsDocument::CloneDocHelper(nsDocument* clone, bool aPreallocateChildren) const
    8713           0 : {
    8714             :   clone->mIsStaticDocument = mCreatingStaticClone;
    8715           0 : 
    8716           0 :   // Init document
    8717           0 :   nsresult rv = clone->Init();
    8718           0 :   NS_ENSURE_SUCCESS(rv, rv);
    8719             : 
    8720           0 :   if (mCreatingStaticClone) {
    8721             :     nsCOMPtr<nsILoadGroup> loadGroup;
    8722           0 : 
    8723           0 :     // |mDocumentContainer| is the container of the document that is being
    8724           0 :     // created and not the original container. See CreateStaticClone function().
    8725             :     nsCOMPtr<nsIDocumentLoader> docLoader(mDocumentContainer);
    8726             :     if (docLoader) {
    8727           0 :       docLoader->GetLoadGroup(getter_AddRefs(loadGroup));
    8728             :     }
    8729             :     nsCOMPtr<nsIChannel> channel = GetChannel();
    8730             :     nsCOMPtr<nsIURI> uri;
    8731             :     if (channel) {
    8732             :       NS_GetFinalChannelURI(channel, getter_AddRefs(uri));
    8733             :     } else {
    8734             :       uri = nsIDocument::GetDocumentURI();
    8735             :     }
    8736           0 :     clone->mChannel = channel;
    8737           0 :     if (uri) {
    8738           0 :       clone->ResetToURI(uri, loadGroup, NodePrincipal());
    8739           0 :     }
    8740           0 : 
    8741             :     clone->SetContainer(mDocumentContainer);
    8742           0 :   }
    8743             : 
    8744           0 :   // Now ensure that our clone has the same URI, base URI, and principal as us.
    8745           0 :   // We do this after the mCreatingStaticClone block above, because that block
    8746           0 :   // can set the base URI to an incorrect value in cases when base URI
    8747             :   // information came from the channel.  So we override explicitly, and do it
    8748             :   // for all these properties, in case ResetToURI messes with any of the rest of
    8749             :   // them.
    8750             :   clone->nsDocument::SetDocumentURI(nsIDocument::GetDocumentURI());
    8751           0 :   clone->SetChromeXHRDocURI(mChromeXHRDocURI);
    8752           0 :   clone->SetPrincipal(NodePrincipal());
    8753           0 :   clone->mDocumentBaseURI = mDocumentBaseURI;
    8754             :   clone->SetChromeXHRDocBaseURI(mChromeXHRDocBaseURI);
    8755           0 : 
    8756             :   bool hasHadScriptObject = true;
    8757             :   nsIScriptGlobalObject* scriptObject =
    8758           0 :     GetScriptHandlingObject(hasHadScriptObject);
    8759             :   NS_ENSURE_STATE(scriptObject || !hasHadScriptObject);
    8760             :   if (mCreatingStaticClone) {
    8761             :     // If we're doing a static clone (print, print preview), then we're going to
    8762             :     // be setting a scope object after the clone. It's better to set it only
    8763           0 :     // once, so we don't do that here. However, we do want to act as if there is
    8764           0 :     // a script handling object. So we set mHasHadScriptHandlingObject.
    8765           0 :     clone->mHasHadScriptHandlingObject = true;
    8766           0 :   } else if (scriptObject) {
    8767           0 :     clone->SetScriptHandlingObject(scriptObject);
    8768           0 :   } else {
    8769           0 :     clone->SetScopeObject(GetScopeObject());
    8770             :   }
    8771             :   // Make the clone a data document
    8772           0 :   clone->SetLoadedAsData(true);
    8773           0 : 
    8774           0 :   // Misc state
    8775             : 
    8776             :   // State from nsIDocument
    8777           0 :   clone->mCharacterSet = mCharacterSet;
    8778           0 :   clone->mCharacterSetSource = mCharacterSetSource;
    8779             :   clone->mCompatMode = mCompatMode;
    8780             :   clone->mBidiOptions = mBidiOptions;
    8781             :   clone->mContentLanguage = mContentLanguage;
    8782             :   clone->SetContentTypeInternal(GetContentTypeInternal());
    8783             :   clone->mSecurityInfo = mSecurityInfo;
    8784         136 : 
    8785             :   // State from nsDocument
    8786         136 :   clone->mType = mType;
    8787         136 :   clone->mXMLDeclarationBits = mXMLDeclarationBits;
    8788             :   clone->mBaseTarget = mBaseTarget;
    8789             : 
    8790             :   // Preallocate attributes and child arrays
    8791           0 :   rv = clone->mChildren.EnsureCapacityToClone(mChildren, aPreallocateChildren);
    8792             :   NS_ENSURE_SUCCESS(rv, rv);
    8793         272 : 
    8794          24 :   return NS_OK;
    8795             : }
    8796           0 : 
    8797           0 : void
    8798             : nsIDocument::SetReadyStateInternal(ReadyState rs)
    8799          17 : {
    8800           0 :   mReadyState = rs;
    8801             :   if (rs == READYSTATE_UNINITIALIZED) {
    8802           7 :     // Transition back to uninitialized happens only to keep assertions happy
    8803           0 :     // right before readyState transitions to something else. Make this
    8804             :     // transition undetectable by Web content.
    8805           0 :     return;
    8806           0 :   }
    8807             :   if (mTiming) {
    8808             :     switch (rs) {
    8809             :       case READYSTATE_LOADING:
    8810           1 :         mTiming->NotifyDOMLoading(nsIDocument::GetDocumentURI());
    8811          49 :         break;
    8812             :       case READYSTATE_INTERACTIVE:
    8813             :         mTiming->NotifyDOMInteractive(nsIDocument::GetDocumentURI());
    8814           0 :         break;
    8815             :       case READYSTATE_COMPLETE:
    8816             :         mTiming->NotifyDOMComplete(nsIDocument::GetDocumentURI());
    8817         136 :         break;
    8818           0 :       default:
    8819         136 :         NS_WARNING("Unexpected ReadyState value");
    8820             :         break;
    8821             :     }
    8822             :   }
    8823           0 :   // At the time of loading start, we don't have timing object, record time.
    8824             :   if (READYSTATE_LOADING == rs) {
    8825           5 :     mLoadingTimeStamp = mozilla::TimeStamp::Now();
    8826             :   }
    8827           0 : 
    8828           0 :   RecordNavigationTiming(rs);
    8829             : 
    8830           0 :   RefPtr<AsyncEventDispatcher> asyncDispatcher =
    8831           0 :     new AsyncEventDispatcher(this, NS_LITERAL_STRING("readystatechange"),
    8832             :                              false, false);
    8833           3 :   asyncDispatcher->RunDOMEventWhenSafe();
    8834           0 : }
    8835             : 
    8836           2 : void
    8837             : nsIDocument::GetReadyState(nsAString& aReadyState) const
    8838           0 : {
    8839             :   switch(mReadyState) {
    8840             :   case READYSTATE_LOADING :
    8841           0 :     aReadyState.AssignLiteral(u"loading");
    8842             :     break;
    8843           0 :   case READYSTATE_INTERACTIVE :
    8844             :     aReadyState.AssignLiteral(u"interactive");
    8845           0 :     break;
    8846             :   case READYSTATE_COMPLETE :
    8847             :     aReadyState.AssignLiteral(u"complete");
    8848             :     break;
    8849           0 :   default:
    8850             :     aReadyState.AssignLiteral(u"uninitialized");
    8851           0 :   }
    8852           0 : }
    8853           0 : 
    8854           0 : static bool
    8855             : SuppressEventHandlingInDocument(nsIDocument* aDocument, void* aData)
    8856             : {
    8857           0 :   aDocument->SuppressEventHandling(*static_cast<uint32_t*>(aData));
    8858           0 : 
    8859             :   return true;
    8860             : }
    8861           0 : 
    8862             : void
    8863             : nsIDocument::SuppressEventHandling(uint32_t aIncrease)
    8864           0 : {
    8865           0 :   mEventsSuppressed += aIncrease;
    8866             :   UpdateFrameRequestCallbackSchedulingState();
    8867             :   for (uint32_t i = 0; i < aIncrease; ++i) {
    8868           0 :     ScriptLoader()->AddExecuteBlocker();
    8869             :   }
    8870             : 
    8871           0 :   EnumerateSubDocuments(SuppressEventHandlingInDocument, &aIncrease);
    8872           0 : }
    8873           0 : 
    8874           0 : static void
    8875             : FireOrClearDelayedEvents(nsTArray<nsCOMPtr<nsIDocument>>& aDocuments,
    8876           0 :                          bool aFireEvents)
    8877           0 : {
    8878           0 :   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
    8879           0 :   if (!fm)
    8880             :     return;
    8881             : 
    8882             :   for (uint32_t i = 0; i < aDocuments.Length(); ++i) {
    8883             :     // NB: Don't bother trying to fire delayed events on documents that were
    8884             :     // closed before this event ran.
    8885             :     if (!aDocuments[i]->EventHandlingSuppressed()) {
    8886           0 :       fm->FireDelayedEvents(aDocuments[i]);
    8887             :       nsCOMPtr<nsIPresShell> shell = aDocuments[i]->GetShell();
    8888           0 :       if (shell) {
    8889           0 :         // Only fire events for active documents.
    8890           0 :         bool fire = aFireEvents &&
    8891           0 :                     aDocuments[i]->GetInnerWindow() &&
    8892             :                     aDocuments[i]->GetInnerWindow()->IsCurrentInnerWindow();
    8893           0 :         shell->FireOrClearDelayedEvents(fire);
    8894             :       }
    8895             :     }
    8896           0 :   }
    8897             : }
    8898             : 
    8899             : void
    8900             : nsIDocument::PreloadPictureClosed()
    8901             : {
    8902             :   MOZ_ASSERT(mPreloadPictureDepth > 0);
    8903             :   mPreloadPictureDepth--;
    8904           0 :   if (mPreloadPictureDepth == 0) {
    8905             :     mPreloadPictureFoundSource.SetIsVoid(true);
    8906             :   }
    8907             : }
    8908           0 : 
    8909             : void
    8910             : nsIDocument::PreloadPictureImageSource(const nsAString& aSrcsetAttr,
    8911           0 :                                        const nsAString& aSizesAttr,
    8912           0 :                                        const nsAString& aTypeAttr,
    8913             :                                        const nsAString& aMediaAttr)
    8914           0 : {
    8915             :   // Nested pictures are not valid syntax, so while we'll eventually load them,
    8916             :   // it's not worth tracking sources mixed between nesting levels to preload
    8917           0 :   // them effectively.
    8918             :   if (mPreloadPictureDepth == 1 && mPreloadPictureFoundSource.IsVoid()) {
    8919             :     // <picture> selects the first matching source, so if this returns a URI we
    8920           0 :     // needn't consider new sources until a new <picture> is encountered.
    8921             :     bool found =
    8922             :       HTMLImageElement::SelectSourceForTagWithAttrs(this, true, VoidString(),
    8923             :                                                     aSrcsetAttr, aSizesAttr,
    8924             :                                                     aTypeAttr, aMediaAttr,
    8925             :                                                     mPreloadPictureFoundSource);
    8926           0 :     if (found && mPreloadPictureFoundSource.IsVoid()) {
    8927             :       // Found an empty source, which counts
    8928           0 :       mPreloadPictureFoundSource.SetIsVoid(false);
    8929             :     }
    8930             :   }
    8931           0 : }
    8932           0 : 
    8933             : already_AddRefed<nsIURI>
    8934             : nsIDocument::ResolvePreloadImage(nsIURI *aBaseURI,
    8935           0 :                                  const nsAString& aSrcAttr,
    8936             :                                  const nsAString& aSrcsetAttr,
    8937           0 :                                  const nsAString& aSizesAttr,
    8938           0 :                                  bool *aIsImgSet)
    8939           0 : {
    8940             :   nsString sourceURL;
    8941             :   bool isImgSet;
    8942             :   if (mPreloadPictureDepth == 1 && !mPreloadPictureFoundSource.IsVoid()) {
    8943           0 :     // We're in a <picture> element and found a URI from a source previous to
    8944             :     // this image, use it.
    8945             :     sourceURL = mPreloadPictureFoundSource;
    8946             :     isImgSet = true;
    8947             :   } else {
    8948             :     // Otherwise try to use this <img> as a source
    8949             :     HTMLImageElement::SelectSourceForTagWithAttrs(this, false, aSrcAttr,
    8950           0 :                                                   aSrcsetAttr, aSizesAttr,
    8951           0 :                                                   VoidString(), VoidString(),
    8952           0 :                                                   sourceURL);
    8953           0 :     isImgSet = !aSrcsetAttr.IsEmpty();
    8954             :   }
    8955             : 
    8956             :   // Empty sources are not loaded by <img> (i.e. not resolved to the baseURI)
    8957           0 :   if (sourceURL.IsEmpty()) {
    8958             :     return nullptr;
    8959             :   }
    8960             : 
    8961             :   // Construct into URI using passed baseURI (the parser may know of base URI
    8962           0 :   // changes that have not reached us)
    8963             :   nsresult rv;
    8964             :   nsCOMPtr<nsIURI> uri;
    8965             :   rv = nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(uri), sourceURL,
    8966           0 :                                                  this, aBaseURI);
    8967             :   if (NS_FAILED(rv)) {
    8968             :     return nullptr;
    8969             :   }
    8970             : 
    8971             :   *aIsImgSet = isImgSet;
    8972             : 
    8973             :   // We don't clear mPreloadPictureFoundSource because subsequent <img> tags in
    8974           0 :   // this this <picture> share the same <sources> (though this is not valid per
    8975           0 :   // spec)
    8976             :   return uri.forget();
    8977             : }
    8978             : 
    8979           0 : void
    8980           0 : nsIDocument::MaybePreLoadImage(nsIURI* uri,
    8981             :                                const nsAString &aCrossOriginAttr,
    8982             :                                enum mozilla::net::ReferrerPolicy aReferrerPolicy,
    8983           0 :                                bool aIsImgSet)
    8984           0 : {
    8985             :   // Early exit if the img is already present in the img-cache
    8986             :   // which indicates that the "real" load has already started and
    8987           0 :   // that we shouldn't preload it.
    8988             :   if (nsContentUtils::IsImageInCache(uri, this)) {
    8989           0 :     return;
    8990             :   }
    8991             : 
    8992             :   nsLoadFlags loadFlags = nsIRequest::LOAD_NORMAL |
    8993             :                           nsContentUtils::CORSModeToLoadImageFlags(
    8994             :                             Element::StringToCORSMode(aCrossOriginAttr));
    8995             : 
    8996             :   nsContentPolicyType policyType =
    8997             :     aIsImgSet ? nsIContentPolicy::TYPE_IMAGESET :
    8998           0 :                 nsIContentPolicy::TYPE_INTERNAL_IMAGE_PRELOAD;
    8999           0 : 
    9000           0 :   // Image not in cache - trigger preload
    9001             :   RefPtr<imgRequestProxy> request;
    9002             :   nsresult rv =
    9003             :     nsContentUtils::LoadImage(uri,
    9004             :                               static_cast<nsINode*>(this),
    9005           0 :                               this,
    9006           0 :                               NodePrincipal(),
    9007             :                               0,
    9008             :                               mDocumentURI, // uri of document used as referrer
    9009             :                               aReferrerPolicy,
    9010             :                               nullptr,       // no observer
    9011           0 :                               loadFlags,
    9012             :                               NS_LITERAL_STRING("img"),
    9013           0 :                               getter_AddRefs(request),
    9014           0 :                               policyType);
    9015           0 : 
    9016             :   // Pin image-reference to avoid evicting it from the img-cache before
    9017             :   // the "real" load occurs. Unpinned in DispatchContentLoadedEvents and
    9018             :   // unlink
    9019             :   if (NS_SUCCEEDED(rv)) {
    9020             :     mPreloadingImages.Put(uri, request.forget());
    9021             :   }
    9022             : }
    9023             : 
    9024             : void
    9025           0 : nsIDocument::MaybePreconnect(nsIURI* aOrigURI, mozilla::CORSMode aCORSMode)
    9026           0 : {
    9027             :   NS_MutateURI mutator(aOrigURI);
    9028           0 :   if (NS_FAILED(mutator.GetStatus())) {
    9029             :       return;
    9030             :   }
    9031           0 : 
    9032           0 :   // The URI created here is used in 2 contexts. One is nsISpeculativeConnect
    9033           0 :   // which ignores the path and uses only the origin. The other is for the
    9034           0 :   // document mPreloadedPreconnects de-duplication hash. Anonymous vs
    9035             :   // non-Anonymous preconnects create different connections on the wire and
    9036             :   // therefore should not be considred duplicates of each other and we
    9037           0 :   // normalize the path before putting it in the hash to accomplish that.
    9038           0 : 
    9039           0 :   if (aCORSMode == CORS_ANONYMOUS) {
    9040             :     mutator.SetPathQueryRef(NS_LITERAL_CSTRING("/anonymous"));
    9041           0 :   } else {
    9042             :     mutator.SetPathQueryRef(NS_LITERAL_CSTRING("/"));
    9043             :   }
    9044           0 : 
    9045           0 :   nsCOMPtr<nsIURI> uri;
    9046           0 :   nsresult rv = mutator.Finalize(uri);
    9047             :   if (NS_FAILED(rv)) {
    9048             :     return;
    9049           0 :   }
    9050           0 : 
    9051             :   auto entry = mPreloadedPreconnects.LookupForAdd(uri);
    9052           0 :   if (entry) {
    9053             :     return; // we found an existing entry
    9054             :   }
    9055             :   entry.OrInsert([] () { return true; });
    9056             : 
    9057           0 :   nsCOMPtr<nsISpeculativeConnect>
    9058             :     speculator(do_QueryInterface(nsContentUtils::GetIOService()));
    9059             :   if (!speculator) {
    9060             :     return;
    9061           0 :   }
    9062           0 : 
    9063           0 :   if (aCORSMode == CORS_ANONYMOUS) {
    9064           0 :     speculator->SpeculativeAnonymousConnect2(uri, NodePrincipal(), nullptr);
    9065             :   } else {
    9066           0 :     speculator->SpeculativeConnect2(uri, NodePrincipal(), nullptr);
    9067             :   }
    9068             : }
    9069           0 : 
    9070             : void
    9071             : nsIDocument::ForgetImagePreload(nsIURI* aURI)
    9072          46 : {
    9073             :   // Checking count is faster than hashing the URI in the common
    9074          46 :   // case of empty table.
    9075           3 :   if (mPreloadingImages.Count() != 0) {
    9076           0 :     nsCOMPtr<imgIRequest> req;
    9077             :     mPreloadingImages.Remove(aURI, getter_AddRefs(req));
    9078           0 :     if (req) {
    9079             :       // Make sure to cancel the request so imagelib knows it's gone.
    9080             :       req->CancelAndForgetObserver(NS_BINDING_ABORTED);
    9081             :     }
    9082           0 :   }
    9083          43 : }
    9084          30 : 
    9085             : void
    9086           0 : nsIDocument::UpdateDocumentStates(EventStates aChangedStates)
    9087             : {
    9088             :   if (aChangedStates.HasState(NS_DOCUMENT_STATE_RTL_LOCALE)) {
    9089          46 :     if (IsDocumentRightToLeft()) {
    9090             :       mDocumentState |= NS_DOCUMENT_STATE_RTL_LOCALE;
    9091             :     } else {
    9092             :       mDocumentState &= ~NS_DOCUMENT_STATE_RTL_LOCALE;
    9093             :     }
    9094             :   }
    9095             : 
    9096             :   if (aChangedStates.HasState(NS_DOCUMENT_STATE_WINDOW_INACTIVE)) {
    9097           0 :     if (IsTopLevelWindowInactive()) {
    9098           0 :       mDocumentState |= NS_DOCUMENT_STATE_WINDOW_INACTIVE;
    9099             :     } else {
    9100             :       mDocumentState &= ~NS_DOCUMENT_STATE_WINDOW_INACTIVE;
    9101           0 :     }
    9102             :   }
    9103           0 : }
    9104             : 
    9105             : namespace {
    9106             : 
    9107           0 : /**
    9108             :  * Stub for LoadSheet(), since all we want is to get the sheet into
    9109             :  * the CSSLoader's style cache
    9110             :  */
    9111             : class StubCSSLoaderObserver final : public nsICSSLoaderObserver {
    9112           0 :   ~StubCSSLoaderObserver() {}
    9113             : public:
    9114             :   NS_IMETHOD
    9115             :   StyleSheetLoaded(StyleSheet*, bool, nsresult) override
    9116             :   {
    9117             :     return NS_OK;
    9118             :   }
    9119           0 :   NS_DECL_ISUPPORTS
    9120             : };
    9121             : NS_IMPL_ISUPPORTS(StubCSSLoaderObserver, nsICSSLoaderObserver)
    9122           0 : 
    9123             : } // namespace
    9124             : 
    9125             : void
    9126             : nsIDocument::PreloadStyle(nsIURI* uri,
    9127           0 :                           const Encoding* aEncoding,
    9128             :                           const nsAString& aCrossOriginAttr,
    9129           0 :                           const enum mozilla::net::ReferrerPolicy aReferrerPolicy,
    9130           0 :                           const nsAString& aIntegrity)
    9131             : {
    9132             :   // The CSSLoader will retain this object after we return.
    9133           0 :   nsCOMPtr<nsICSSLoaderObserver> obs = new StubCSSLoaderObserver();
    9134             : 
    9135             :   // Charset names are always ASCII.
    9136             :   CSSLoader()->LoadSheet(uri,
    9137           0 :                          true,
    9138           0 :                          NodePrincipal(),
    9139           0 :                          aEncoding,
    9140             :                          obs,
    9141             :                          Element::StringToCORSMode(aCrossOriginAttr),
    9142             :                          aReferrerPolicy,
    9143             :                          aIntegrity);
    9144             : }
    9145           0 : 
    9146           0 : nsresult
    9147             : nsIDocument::LoadChromeSheetSync(nsIURI* uri, bool isAgentSheet,
    9148           0 :                                 RefPtr<mozilla::StyleSheet>* aSheet)
    9149           0 : {
    9150           0 :   css::SheetParsingMode mode =
    9151             :     isAgentSheet ? css::eAgentSheetFeatures
    9152           0 :                  : css::eAuthorSheetFeatures;
    9153             :   return CSSLoader()->LoadSheetSync(uri, mode, isAgentSheet, aSheet);
    9154           0 : }
    9155           0 : 
    9156             : class nsDelayedEventDispatcher : public Runnable
    9157             : {
    9158             : public:
    9159             :   explicit nsDelayedEventDispatcher(nsTArray<nsCOMPtr<nsIDocument>>& aDocuments)
    9160             :     : mozilla::Runnable("nsDelayedEventDispatcher")
    9161             :   {
    9162             :     mDocuments.SwapElements(aDocuments);
    9163           0 :   }
    9164             :   virtual ~nsDelayedEventDispatcher() {}
    9165           0 : 
    9166           0 :   NS_IMETHOD Run() override
    9167           0 :   {
    9168             :     FireOrClearDelayedEvents(mDocuments, true);
    9169             :     return NS_OK;
    9170           0 :   }
    9171             : 
    9172           0 : private:
    9173           0 :   nsTArray<nsCOMPtr<nsIDocument>> mDocuments;
    9174           0 : };
    9175             : 
    9176             : static bool
    9177             : GetAndUnsuppressSubDocuments(nsIDocument* aDocument, void* aData)
    9178           0 : {
    9179             :   if (aDocument->EventHandlingSuppressed() > 0) {
    9180           0 :     aDocument->DecreaseEventSuppression();
    9181           0 :     aDocument->ScriptLoader()->RemoveExecuteBlocker();
    9182             :   }
    9183           0 : 
    9184           0 :   auto* docs = static_cast<nsTArray<nsCOMPtr<nsIDocument>>*>(aData);
    9185           0 : 
    9186           0 :   docs->AppendElement(aDocument);
    9187             :   aDocument->EnumerateSubDocuments(GetAndUnsuppressSubDocuments, aData);
    9188           0 :   return true;
    9189             : }
    9190           0 : 
    9191             : void
    9192             : nsIDocument::UnsuppressEventHandlingAndFireEvents(bool aFireEvents)
    9193           0 : {
    9194             :   nsTArray<nsCOMPtr<nsIDocument>> documents;
    9195           0 :   GetAndUnsuppressSubDocuments(this, &documents);
    9196             : 
    9197             :   if (aFireEvents) {
    9198             :     MOZ_RELEASE_ASSERT(NS_IsMainThread());
    9199           0 :     nsCOMPtr<nsIRunnable> ded = new nsDelayedEventDispatcher(documents);
    9200             :     Dispatch(TaskCategory::Other, ded.forget());
    9201           0 :   } else {
    9202           0 :     FireOrClearDelayedEvents(documents, false);
    9203             :   }
    9204           0 : }
    9205             : 
    9206           0 : nsISupports*
    9207           0 : nsIDocument::GetCurrentContentSink()
    9208           0 : {
    9209           0 :   return mParser ? mParser->GetContentSink() : nullptr;
    9210             : }
    9211             : 
    9212             : nsIDocument*
    9213             : nsIDocument::GetTemplateContentsOwner()
    9214             : {
    9215             :   if (!mTemplateContentsOwner) {
    9216           0 :     bool hasHadScriptObject = true;
    9217           0 :     nsIScriptGlobalObject* scriptObject =
    9218             :       GetScriptHandlingObject(hasHadScriptObject);
    9219           0 : 
    9220           0 :     nsCOMPtr<nsIDocument> document;
    9221             :     nsresult rv = NS_NewDOMDocument(getter_AddRefs(document),
    9222           0 :                                     EmptyString(), // aNamespaceURI
    9223             :                                     EmptyString(), // aQualifiedName
    9224           0 :                                     nullptr, // aDoctype
    9225           0 :                                     nsIDocument::GetDocumentURI(),
    9226             :                                     nsIDocument::GetDocBaseURI(),
    9227             :                                     NodePrincipal(),
    9228           0 :                                     true, // aLoadedAsData
    9229             :                                     scriptObject, // aEventObject
    9230             :                                     DocumentFlavorHTML);
    9231             :     NS_ENSURE_SUCCESS(rv, nullptr);
    9232             : 
    9233           0 :     mTemplateContentsOwner = document;
    9234             :     NS_ENSURE_TRUE(mTemplateContentsOwner, nullptr);
    9235             : 
    9236           0 :     nsDocument* doc = static_cast<nsDocument*>(mTemplateContentsOwner.get());
    9237             : 
    9238             :     if (!scriptObject) {
    9239             :       mTemplateContentsOwner->SetScopeObject(GetScopeObject());
    9240           0 :     }
    9241             : 
    9242           0 :     doc->mHasHadScriptHandlingObject = hasHadScriptObject;
    9243           0 : 
    9244             :     // Set |doc| as the template contents owner of itself so that
    9245             :     // |doc| is the template contents owner of template elements created
    9246             :     // by |doc|.
    9247           0 :     doc->mTemplateContentsOwner = doc;
    9248           0 :   }
    9249             : 
    9250             :   return mTemplateContentsOwner;
    9251             : }
    9252             : 
    9253           0 : static already_AddRefed<nsPIDOMWindowOuter>
    9254           0 : FindTopWindowForElement(Element* element)
    9255             : {
    9256           0 :   nsIDocument* document = element->OwnerDoc();
    9257             :   if (!document) {
    9258             :     return nullptr;
    9259             :   }
    9260             : 
    9261             :   nsCOMPtr<nsPIDOMWindowOuter> window = document->GetWindow();
    9262             :   if (!window) {
    9263           0 :     return nullptr;
    9264             :   }
    9265             : 
    9266           0 :   // Trying to find the top window (equivalent to window.top).
    9267             :   if (nsCOMPtr<nsPIDOMWindowOuter> top = window->GetTop()) {
    9268           0 :     window = top.forget();
    9269             :   }
    9270           0 :   return window.forget();
    9271             : }
    9272           0 : 
    9273             : /**
    9274           0 :  * nsAutoFocusEvent is used to dispatch a focus event for an
    9275             :  * nsGenericHTMLFormElement with the autofocus attribute enabled.
    9276             :  */
    9277           0 : class nsAutoFocusEvent : public Runnable
    9278           0 : {
    9279             : public:
    9280             :   explicit nsAutoFocusEvent(already_AddRefed<Element>&& aElement,
    9281             :                             already_AddRefed<nsPIDOMWindowOuter>&& aTopWindow)
    9282             :     : mozilla::Runnable("nsAutoFocusEvent")
    9283             :     , mElement(aElement)
    9284             :     , mTopWindow(aTopWindow)
    9285           0 :   {
    9286             :   }
    9287             : 
    9288             :   NS_IMETHOD Run() override
    9289           0 :   {
    9290           0 :     nsCOMPtr<nsPIDOMWindowOuter> currentTopWindow =
    9291           0 :       FindTopWindowForElement(mElement);
    9292             :     if (currentTopWindow != mTopWindow) {
    9293             :       // The element's top window changed from when the event was queued.
    9294             :       // Don't take away focus from an unrelated window.
    9295             :       return NS_OK;
    9296             :     }
    9297             : 
    9298             :     // Don't steal focus from the user.
    9299           0 :     if (mTopWindow->GetFocusedElement()) {
    9300             :       return NS_OK;
    9301           0 :     }
    9302             : 
    9303             :     mozilla::ErrorResult rv;
    9304             :     mElement->Focus(rv);
    9305             :     return rv.StealNSResult();
    9306           0 :   }
    9307             : private:
    9308             :   nsCOMPtr<Element> mElement;
    9309             :   nsCOMPtr<nsPIDOMWindowOuter> mTopWindow;
    9310             : };
    9311             : 
    9312           0 : void
    9313           0 : nsIDocument::SetAutoFocusElement(Element* aAutoFocusElement)
    9314             : {
    9315             :   if (mAutoFocusFired) {
    9316             :     // Too late.
    9317           0 :     return;
    9318             :   }
    9319          19 : 
    9320           0 :   if (mAutoFocusElement) {
    9321             :     // The spec disallows multiple autofocus elements, so we consider only the
    9322             :     // first one to preserve the old behavior.
    9323           0 :     return;
    9324             :   }
    9325             : 
    9326             :   mAutoFocusElement = do_GetWeakReference(aAutoFocusElement);
    9327             :   TriggerAutoFocus();
    9328             : }
    9329          76 : 
    9330          19 : void
    9331           0 : nsIDocument::TriggerAutoFocus()
    9332             : {
    9333             :   if (mAutoFocusFired) {
    9334           0 :     return;
    9335           0 :   }
    9336           0 : 
    9337             :   if (!mPresShell || !mPresShell->DidInitialize()) {
    9338             :     // Delay autofocus until frames are constructed so that we don't thrash
    9339             :     // style and layout calculations.
    9340             :     return;
    9341           0 :   }
    9342           0 : 
    9343           0 :   nsCOMPtr<Element> autoFocusElement = do_QueryReferent(mAutoFocusElement);
    9344             :   if (autoFocusElement && autoFocusElement->OwnerDoc() == this) {
    9345             :     mAutoFocusFired = true;
    9346             : 
    9347           0 :     nsCOMPtr<nsPIDOMWindowOuter> topWindow =
    9348           0 :       FindTopWindowForElement(autoFocusElement);
    9349           0 :     if (!topWindow) {
    9350             :       return;
    9351             :     }
    9352             : 
    9353             :     // NOTE: This may be removed in the future since the spec technically
    9354          49 :     // allows autofocus after load.
    9355             :     nsCOMPtr<nsIDocument> topDoc = topWindow->GetExtantDoc();
    9356          49 :     if (topDoc && topDoc->GetReadyStateEnum() == nsIDocument::READYSTATE_COMPLETE) {
    9357           0 :       return;
    9358             :     }
    9359             : 
    9360           0 :     nsCOMPtr<nsIRunnable> event =
    9361             :       new nsAutoFocusEvent(autoFocusElement.forget(), topWindow.forget());
    9362             :     nsresult rv = NS_DispatchToCurrentThread(event.forget());
    9363             :     NS_ENSURE_SUCCESS_VOID(rv);
    9364             :   }
    9365             : }
    9366             : 
    9367          49 : void
    9368          49 : nsIDocument::SetScrollToRef(nsIURI* aDocumentURI)
    9369           0 : {
    9370             :   if (!aDocumentURI) {
    9371             :     return;
    9372             :   }
    9373           1 : 
    9374             :   nsAutoCString ref;
    9375          49 : 
    9376          49 :   // Since all URI's that pass through here aren't URL's we can't
    9377             :   // rely on the nsIURI implementation for providing a way for
    9378          49 :   // finding the 'ref' part of the URI, we'll haveto revert to
    9379           0 :   // string routines for finding the data past '#'
    9380             : 
    9381           0 :   nsresult rv = aDocumentURI->GetSpec(ref);
    9382             :   if (NS_FAILED(rv)) {
    9383             :     Unused << aDocumentURI->GetRef(mScrollToRef);
    9384             :     return;
    9385             :   }
    9386          58 : 
    9387             :   nsReadingIterator<char> start, end;
    9388          58 : 
    9389           0 :   ref.BeginReading(start);
    9390           0 :   ref.EndReading(end);
    9391           0 : 
    9392             :   if (FindCharInReadable('#', start, end)) {
    9393             :     ++start; // Skip over the '#'
    9394             : 
    9395             :     mScrollToRef = Substring(start, end);
    9396          58 :   }
    9397             : }
    9398             : 
    9399             : void
    9400           0 : nsIDocument::ScrollToRef()
    9401           0 : {
    9402           0 :   if (mScrolledToRefAlready) {
    9403             :     nsCOMPtr<nsIPresShell> shell = GetShell();
    9404             :     if (shell) {
    9405           0 :       shell->ScrollToAnchor();
    9406             :     }
    9407           0 :     return;
    9408             :   }
    9409           0 : 
    9410             :   if (mScrollToRef.IsEmpty()) {
    9411             :     return;
    9412             :   }
    9413             : 
    9414           0 :   nsCOMPtr<nsIPresShell> shell = GetShell();
    9415           0 :   if (shell) {
    9416           0 :     nsresult rv = NS_ERROR_FAILURE;
    9417           0 :     // We assume that the bytes are in UTF-8, as it says in the spec:
    9418             :     // http://www.w3.org/TR/html4/appendix/notes.html#h-B.2.1
    9419           0 :     NS_ConvertUTF8toUTF16 ref(mScrollToRef);
    9420           0 :     // Check an empty string which might be caused by the UTF-8 conversion
    9421           0 :     if (!ref.IsEmpty()) {
    9422           0 :       // Note that GoToAnchor will handle flushing layout as needed.
    9423             :       rv = shell->GoToAnchor(ref, mChangeScrollPosWhenScrollingToRef);
    9424           0 :     } else {
    9425           0 :       rv = NS_ERROR_FAILURE;
    9426           0 :     }
    9427             : 
    9428             :     if (NS_FAILED(rv)) {
    9429             :       char* tmpstr = ToNewCString(mScrollToRef);
    9430             :       if (!tmpstr) {
    9431           0 :         return;
    9432           0 :       }
    9433           0 :       nsUnescape(tmpstr);
    9434           0 :       nsAutoCString unescapedRef;
    9435           0 :       unescapedRef.Assign(tmpstr);
    9436             :       free(tmpstr);
    9437             : 
    9438             :       NS_ConvertUTF8toUTF16 utf16Str(unescapedRef);
    9439           0 :       if (!utf16Str.IsEmpty()) {
    9440           0 :         rv = shell->GoToAnchor(utf16Str, mChangeScrollPosWhenScrollingToRef);
    9441             :       }
    9442             : 
    9443             :       // If UTF-8 URI failed then try to assume the string as a
    9444             :       // document's charset.
    9445             :       if (NS_FAILED(rv)) {
    9446           1 :         const Encoding* encoding = GetDocumentCharacterSet();
    9447             :         rv = encoding->DecodeWithoutBOMHandling(unescapedRef, ref);
    9448           2 :         if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) {
    9449           2 :           rv = shell->GoToAnchor(ref, mChangeScrollPosWhenScrollingToRef);
    9450             :         }
    9451           1 :       }
    9452           0 :     }
    9453             :     if (NS_SUCCEEDED(rv)) {
    9454             :       mScrolledToRefAlready = true;
    9455           0 :     }
    9456             :   }
    9457           0 : }
    9458             : 
    9459             : void
    9460           0 : nsIDocument::RegisterActivityObserver(nsISupports* aSupports)
    9461           0 : {
    9462             :   if (!mActivityObservers) {
    9463             :     mActivityObservers = new nsTHashtable<nsPtrHashKey<nsISupports> >();
    9464           0 :   }
    9465           0 :   mActivityObservers->PutEntry(aSupports);
    9466             : }
    9467             : 
    9468             : bool
    9469           0 : nsIDocument::UnregisterActivityObserver(nsISupports* aSupports)
    9470             : {
    9471             :   if (!mActivityObservers) {
    9472         222 :     return false;
    9473             :   }
    9474             :   nsPtrHashKey<nsISupports>* entry = mActivityObservers->GetEntry(aSupports);
    9475           5 :   if (!entry) {
    9476           0 :     return false;
    9477           1 :   }
    9478             :   mActivityObservers->RemoveEntry(entry);
    9479             :   return true;
    9480             : }
    9481             : 
    9482           8 : void
    9483             : nsIDocument::EnumerateActivityObservers(ActivityObserverEnumerator aEnumerator,
    9484          16 :                                         void* aData)
    9485             : {
    9486             :   if (!mActivityObservers)
    9487             :     return;
    9488           0 : 
    9489             :   for (auto iter = mActivityObservers->ConstIter(); !iter.Done();
    9490           8 :        iter.Next()) {
    9491             :     aEnumerator(iter.Get()->GetKey(), aData);
    9492           0 :   }
    9493             : }
    9494           0 : 
    9495             : void
    9496             : nsIDocument::RegisterPendingLinkUpdate(Link* aLink)
    9497           1 : {
    9498           0 :   if (aLink->HasPendingLinkUpdate()) {
    9499             :     return;
    9500             :   }
    9501           0 : 
    9502             :   aLink->SetHasPendingLinkUpdate();
    9503           1 : 
    9504             :   if (!mHasLinksToUpdateRunnable && !mFlushingPendingLinkUpdates) {
    9505             :     nsCOMPtr<nsIRunnable> event =
    9506           8 :       NewRunnableMethod("nsIDocument::FlushPendingLinkUpdatesFromRunnable",
    9507             :                         this,
    9508             :                         &nsIDocument::FlushPendingLinkUpdatesFromRunnable);
    9509             :     // Do this work in a second in the worst case.
    9510           0 :     nsresult rv =
    9511             :       NS_IdleDispatchToCurrentThread(event.forget(), 1000);
    9512           1 :     if (NS_FAILED(rv)) {
    9513           1 :       // If during shutdown posting a runnable doesn't succeed, we probably
    9514           0 :       // don't need to update link states.
    9515           1 :       return;
    9516             :     }
    9517             :     mHasLinksToUpdateRunnable = true;
    9518           0 :   }
    9519             : 
    9520           1 :   mLinksToUpdate.InfallibleAppend(aLink);
    9521           0 : }
    9522             : 
    9523             : void
    9524           0 : nsIDocument::FlushPendingLinkUpdatesFromRunnable()
    9525           1 : {
    9526             :   MOZ_ASSERT(mHasLinksToUpdateRunnable);
    9527           3 :   mHasLinksToUpdateRunnable = false;
    9528           0 :   FlushPendingLinkUpdates();
    9529           0 : }
    9530          16 : 
    9531           0 : void
    9532           0 : nsIDocument::FlushPendingLinkUpdates()
    9533           0 : {
    9534           0 :   if (mFlushingPendingLinkUpdates) {
    9535           0 :     return;
    9536             :   }
    9537             : 
    9538             :   auto restore = MakeScopeExit([&] { mFlushingPendingLinkUpdates = false; });
    9539             :   mFlushingPendingLinkUpdates = true;
    9540             : 
    9541             :   while (!mLinksToUpdate.IsEmpty()) {
    9542             :     LinksToUpdateList links(std::move(mLinksToUpdate));
    9543           0 :     for (auto iter = links.Iter(); !iter.Done(); iter.Next()) {
    9544             :       Link* link = iter.Get();
    9545           0 :       Element* element = link->GetElement();
    9546           0 :       if (element->OwnerDoc() == this) {
    9547             :         link->ClearHasPendingLinkUpdate();
    9548             :         if (element->IsInComposedDoc()) {
    9549           0 :           element->UpdateLinkState(link->LinkState());
    9550           0 :         }
    9551           0 :       }
    9552           0 :     }
    9553           0 :   }
    9554             : }
    9555           0 : 
    9556           0 : already_AddRefed<nsIDocument>
    9557             : nsIDocument::CreateStaticClone(nsIDocShell* aCloneContainer)
    9558           0 : {
    9559             :   nsDocument* thisAsDoc = static_cast<nsDocument*>(this);
    9560           0 :   mCreatingStaticClone = true;
    9561           0 : 
    9562           0 :   // Make document use different container during cloning.
    9563           0 :   RefPtr<nsDocShell> originalShell = mDocumentContainer.get();
    9564           0 :   SetContainer(static_cast<nsDocShell*>(aCloneContainer));
    9565             :   ErrorResult rv;
    9566           0 :   nsCOMPtr<nsINode> clonedNode = thisAsDoc->CloneNode(true, rv);
    9567             :   SetContainer(originalShell);
    9568             : 
    9569           0 :   RefPtr<nsDocument> clonedDoc;
    9570             :   if (rv.Failed()) {
    9571           0 :     // Don't return yet; we need to reset mCreatingStaticClone
    9572           0 :     rv.SuppressException();
    9573           0 :   } else {
    9574           0 :     nsCOMPtr<nsIDocument> tmp = do_QueryInterface(clonedNode);
    9575           0 :     if (tmp) {
    9576             :       clonedDoc = static_cast<nsDocument*>(tmp.get());
    9577           0 :       if (IsStaticDocument()) {
    9578           0 :         clonedDoc->mOriginalDocument = mOriginalDocument;
    9579             :       } else {
    9580           0 :         clonedDoc->mOriginalDocument = this;
    9581           0 :       }
    9582             : 
    9583             :       clonedDoc->mOriginalDocument->mStaticCloneCount++;
    9584             : 
    9585             :       size_t sheetsCount = SheetCount();
    9586             :       for (size_t i = 0; i < sheetsCount; ++i) {
    9587             :         RefPtr<StyleSheet> sheet = SheetAt(i);
    9588           0 :         if (sheet) {
    9589           0 :           if (sheet->IsApplicable()) {
    9590           0 :             RefPtr<StyleSheet> clonedSheet =
    9591             :               sheet->Clone(nullptr, nullptr, clonedDoc, nullptr);
    9592           0 :             NS_WARNING_ASSERTION(clonedSheet,
    9593           0 :                                  "Cloning a stylesheet didn't work!");
    9594             :             if (clonedSheet) {
    9595           0 :               clonedDoc->AddStyleSheet(clonedSheet);
    9596           0 :             }
    9597             :           }
    9598             :         }
    9599             :       }
    9600             : 
    9601             :       // Iterate backwards to maintain order
    9602             :       for (StyleSheet* sheet : Reversed(thisAsDoc->mOnDemandBuiltInUASheets)) {
    9603           0 :         if (sheet) {
    9604           0 :           if (sheet->IsApplicable()) {
    9605             :             RefPtr<StyleSheet> clonedSheet =
    9606             :               sheet->Clone(nullptr, nullptr, clonedDoc, nullptr);
    9607             :             NS_WARNING_ASSERTION(clonedSheet,
    9608           0 :                                  "Cloning a stylesheet didn't work!");
    9609             :             if (clonedSheet) {
    9610           0 :               clonedDoc->AddOnDemandBuiltInUASheet(clonedSheet);
    9611           0 :             }
    9612           0 :           }
    9613           0 :         }
    9614             :       }
    9615           0 :     }
    9616           0 :   }
    9617             :   mCreatingStaticClone = false;
    9618             :   return clonedDoc.forget();
    9619           0 : }
    9620             : 
    9621             : void
    9622           2 : nsIDocument::UnlinkOriginalDocumentIfStatic()
    9623             : {
    9624             :   if (IsStaticDocument() && mOriginalDocument) {
    9625             :     MOZ_ASSERT(mOriginalDocument->mStaticCloneCount > 0);
    9626           0 :     mOriginalDocument->mStaticCloneCount--;
    9627             :     mOriginalDocument = nullptr;
    9628             :   }
    9629           6 :   MOZ_ASSERT(!mOriginalDocument);
    9630           0 : }
    9631           2 : 
    9632             : nsresult
    9633           0 : nsIDocument::ScheduleFrameRequestCallback(FrameRequestCallback& aCallback,
    9634           0 :                                           int32_t *aHandle)
    9635             : {
    9636             :   if (mFrameRequestCallbackCounter == INT32_MAX) {
    9637             :     // Can't increment without overflowing; bail out
    9638           0 :     return NS_ERROR_NOT_AVAILABLE;
    9639             :   }
    9640             :   int32_t newHandle = ++mFrameRequestCallbackCounter;
    9641           0 : 
    9642           0 :   DebugOnly<FrameRequest*> request =
    9643             :     mFrameRequestCallbacks.AppendElement(FrameRequest(aCallback, newHandle));
    9644           0 :   NS_ASSERTION(request, "This is supposed to be infallible!");
    9645             :   UpdateFrameRequestCallbackSchedulingState();
    9646             : 
    9647           0 :   *aHandle = newHandle;
    9648             :   return NS_OK;
    9649             : }
    9650             : 
    9651             : void
    9652             : nsIDocument::CancelFrameRequestCallback(int32_t aHandle)
    9653             : {
    9654             :   // mFrameRequestCallbacks is stored sorted by handle
    9655           0 :   if (mFrameRequestCallbacks.RemoveElementSorted(aHandle)) {
    9656           0 :     UpdateFrameRequestCallbackSchedulingState();
    9657           0 :   }
    9658           0 : }
    9659           0 : 
    9660           0 : nsresult
    9661           0 : nsIDocument::GetStateObject(nsIVariant** aState)
    9662             : {
    9663           0 :   // Get the document's current state object. This is the object backing both
    9664           0 :   // history.state and popStateEvent.state.
    9665             :   //
    9666             :   // mStateObjectContainer may be null; this just means that there's no
    9667           0 :   // current state object.
    9668           0 : 
    9669             :   if (!mStateObjectCached && mStateObjectContainer) {
    9670             :     AutoJSContext cx;
    9671             :     nsIGlobalObject* sgo = GetScopeObject();
    9672           0 :     NS_ENSURE_TRUE(sgo, NS_ERROR_UNEXPECTED);
    9673             :     JS::Rooted<JSObject*> global(cx, sgo->GetGlobalJSObject());
    9674          56 :     NS_ENSURE_TRUE(global, NS_ERROR_UNEXPECTED);
    9675          73 :     JSAutoRealm ar(cx, global);
    9676           0 : 
    9677             :     mStateObjectContainer->
    9678           0 :       DeserializeToVariant(cx, getter_AddRefs(mStateObjectCached));
    9679             :   }
    9680             : 
    9681           0 :   NS_IF_ADDREF(*aState = mStateObjectCached);
    9682             :   return NS_OK;
    9683           0 : }
    9684             : 
    9685             : void
    9686             : nsIDocument::SetNavigationTiming(nsDOMNavigationTiming* aTiming)
    9687           0 : {
    9688           0 :   mTiming = aTiming;
    9689           0 :   if (!mLoadingTimeStamp.IsNull() && mTiming) {
    9690             :     mTiming->SetDOMLoadingTimeStamp(GetDocumentURI(), mLoadingTimeStamp);
    9691           0 :   }
    9692           0 : }
    9693             : 
    9694             : Element*
    9695             : nsIDocument::FindImageMap(const nsAString& aUseMapValue)
    9696           0 : {
    9697             :   if (aUseMapValue.IsEmpty()) {
    9698           0 :     return nullptr;
    9699             :   }
    9700             : 
    9701             :   nsAString::const_iterator start, end;
    9702           0 :   aUseMapValue.BeginReading(start);
    9703             :   aUseMapValue.EndReading(end);
    9704           0 : 
    9705           0 :   int32_t hash = aUseMapValue.FindChar('#');
    9706             :   if (hash < 0) {
    9707             :     return nullptr;
    9708           0 :   }
    9709           0 :   // aUsemap contains a '#', set start to point right after the '#'
    9710           0 :   start.advance(hash + 1);
    9711           0 : 
    9712           0 :   if (start == end) {
    9713           0 :     return nullptr; // aUsemap == "#"
    9714           0 :   }
    9715             : 
    9716           0 :   const nsAString& mapName = Substring(start, end);
    9717             : 
    9718             :   if (!mImageMaps) {
    9719             :     mImageMaps = new nsContentList(this, kNameSpaceID_XHTML, nsGkAtoms::map, nsGkAtoms::map);
    9720             :   }
    9721             : 
    9722             :   uint32_t i, n = mImageMaps->Length(true);
    9723             :   nsString name;
    9724             :   for (i = 0; i < n; ++i) {
    9725             :     nsIContent* map = mImageMaps->Item(i);
    9726             :     if (map->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::id, mapName,
    9727             :                                       eCaseMatters) ||
    9728             :         map->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name, mapName,
    9729             :                                       eCaseMatters)) {
    9730             :       return map->AsElement();
    9731             :     }
    9732             :   }
    9733             : 
    9734             :   return nullptr;
    9735             : }
    9736             : 
    9737             : #define DEPRECATED_OPERATION(_op) #_op "Warning",
    9738           0 : static const char* kDeprecationWarnings[] = {
    9739             : #include "nsDeprecatedOperationList.h"
    9740           0 :   nullptr
    9741             : };
    9742             : #undef DEPRECATED_OPERATION
    9743             : 
    9744             : #define DOCUMENT_WARNING(_op) #_op "Warning",
    9745             : static const char* kDocumentWarnings[] = {
    9746           0 : #include "nsDocumentWarningList.h"
    9747             :   nullptr
    9748             : };
    9749             : #undef DOCUMENT_WARNING
    9750             : 
    9751           0 : static UseCounter
    9752             : OperationToUseCounter(nsIDocument::DeprecatedOperations aOperation)
    9753           0 : {
    9754             :   switch(aOperation) {
    9755             : #define DEPRECATED_OPERATION(_op) \
    9756             :     case nsIDocument::e##_op: return eUseCounter_##_op;
    9757           0 : #include "nsDeprecatedOperationList.h"
    9758             : #undef DEPRECATED_OPERATION
    9759             :   default:
    9760           0 :     MOZ_CRASH();
    9761           0 :   }
    9762             : }
    9763             : 
    9764           0 : bool
    9765             : nsIDocument::HasWarnedAbout(DeprecatedOperations aOperation) const
    9766             : {
    9767             :   return mDeprecationWarnedAbout[aOperation];
    9768           0 : }
    9769             : 
    9770           0 : void
    9771             : nsIDocument::WarnOnceAbout(DeprecatedOperations aOperation,
    9772           0 :                            bool asError /* = false */) const
    9773           0 : {
    9774           0 :   MOZ_ASSERT(NS_IsMainThread());
    9775           0 :   if (HasWarnedAbout(aOperation)) {
    9776             :     return;
    9777           0 :   }
    9778             :   mDeprecationWarnedAbout[aOperation] = true;
    9779             :   // Don't count deprecated operations for about pages since those pages
    9780             :   // are almost in our control, and we always need to remove uses there
    9781           0 :   // before we remove the operation itself anyway.
    9782             :   if (!IsAboutPage()) {
    9783           0 :     const_cast<nsIDocument*>(this)->
    9784             :       SetDocumentAndPageUseCounter(OperationToUseCounter(aOperation));
    9785             :   }
    9786             :   uint32_t flags = asError ? nsIScriptError::errorFlag
    9787           0 :                            : nsIScriptError::warningFlag;
    9788             :   nsContentUtils::ReportToConsole(flags,
    9789             :                                   NS_LITERAL_CSTRING("DOM Core"), this,
    9790             :                                   nsContentUtils::eDOM_PROPERTIES,
    9791             :                                   kDeprecationWarnings[aOperation]);
    9792           0 : }
    9793           0 : 
    9794             : bool
    9795             : nsIDocument::HasWarnedAbout(DocumentWarnings aWarning) const
    9796           0 : {
    9797           0 :   return mDocWarningWarnedAbout[aWarning];
    9798           0 : }
    9799           0 : 
    9800           0 : void
    9801             : nsIDocument::WarnOnceAbout(DocumentWarnings aWarning,
    9802             :                            bool asError /* = false */,
    9803             :                            const char16_t **aParams /* = nullptr */,
    9804           0 :                            uint32_t aParamsLength /* = 0 */) const
    9805             : {
    9806             :   MOZ_ASSERT(NS_IsMainThread());
    9807             :   if (HasWarnedAbout(aWarning)) {
    9808           0 :     return;
    9809             :   }
    9810          88 :   mDocWarningWarnedAbout[aWarning] = true;
    9811          27 :   uint32_t flags = asError ? nsIScriptError::errorFlag
    9812             :                            : nsIScriptError::warningFlag;
    9813          88 :   nsContentUtils::ReportToConsole(flags,
    9814             :                                   NS_LITERAL_CSTRING("DOM Core"), this,
    9815             :                                   nsContentUtils::eDOM_PROPERTIES,
    9816             :                                   kDocumentWarnings[aWarning],
    9817           0 :                                   aParams,
    9818             :                                   aParamsLength);
    9819             : }
    9820           0 : 
    9821           0 : mozilla::dom::ImageTracker*
    9822           0 : nsIDocument::ImageTracker()
    9823           0 : {
    9824             :   if (!mImageTracker) {
    9825             :     mImageTracker = new mozilla::dom::ImageTracker;
    9826             :   }
    9827           0 :   return mImageTracker;
    9828             : }
    9829           0 : 
    9830           0 : static bool
    9831           0 : AllSubDocumentPluginEnum(nsIDocument* aDocument, void* userArg)
    9832             : {
    9833           0 :   nsTArray<nsIObjectLoadingContent*>* plugins =
    9834           0 :     reinterpret_cast<nsTArray<nsIObjectLoadingContent*>*>(userArg);
    9835             :   MOZ_ASSERT(plugins);
    9836             :   aDocument->GetPlugins(*plugins);
    9837           0 :   return true;
    9838             : }
    9839           3 : 
    9840           0 : void
    9841           0 : nsIDocument::GetPlugins(nsTArray<nsIObjectLoadingContent*>& aPlugins)
    9842           0 : {
    9843             :   aPlugins.SetCapacity(aPlugins.Length() + mPlugins.Count());
    9844           0 :   for (auto iter = mPlugins.ConstIter(); !iter.Done(); iter.Next()) {
    9845             :     aPlugins.AppendElement(iter.Get()->GetKey());
    9846             :   }
    9847           0 :   EnumerateSubDocuments(AllSubDocumentPluginEnum, &aPlugins);
    9848             : }
    9849             : 
    9850             : void
    9851             : nsIDocument::NotifyMediaFeatureValuesChanged()
    9852             : {
    9853             :   for (auto iter = mResponsiveContent.ConstIter(); !iter.Done();
    9854             :        iter.Next()) {
    9855             :     RefPtr<HTMLImageElement> imageElement = iter.Get()->GetKey();
    9856             :     imageElement->MediaFeatureValuesChanged();
    9857             :   }
    9858             : }
    9859             : 
    9860             : already_AddRefed<Touch>
    9861             : nsIDocument::CreateTouch(nsGlobalWindowInner* aView,
    9862             :                          EventTarget* aTarget,
    9863             :                          int32_t aIdentifier,
    9864           0 :                          int32_t aPageX, int32_t aPageY,
    9865           0 :                          int32_t aScreenX, int32_t aScreenY,
    9866             :                          int32_t aClientX, int32_t aClientY,
    9867             :                          int32_t aRadiusX, int32_t aRadiusY,
    9868             :                          float aRotationAngle,
    9869           0 :                          float aForce)
    9870             : {
    9871           0 :   RefPtr<Touch> touch = new Touch(aTarget,
    9872           0 :                                   aIdentifier,
    9873             :                                   aPageX, aPageY,
    9874             :                                   aScreenX, aScreenY,
    9875             :                                   aClientX, aClientY,
    9876           0 :                                   aRadiusX, aRadiusY,
    9877             :                                   aRotationAngle,
    9878             :                                   aForce);
    9879           0 :   return touch.forget();
    9880           0 : }
    9881           0 : 
    9882           0 : already_AddRefed<TouchList>
    9883             : nsIDocument::CreateTouchList()
    9884           0 : {
    9885             :   RefPtr<TouchList> retval = new TouchList(ToSupports(this));
    9886             :   return retval.forget();
    9887             : }
    9888           0 : 
    9889             : already_AddRefed<TouchList>
    9890           0 : nsIDocument::CreateTouchList(Touch& aTouch,
    9891           0 :                              const Sequence<OwningNonNull<Touch> >& aTouches)
    9892           0 : {
    9893             :   RefPtr<TouchList> retval = new TouchList(ToSupports(this));
    9894           0 :   retval->Append(&aTouch);
    9895             :   for (uint32_t i = 0; i < aTouches.Length(); ++i) {
    9896             :     retval->Append(aTouches[i].get());
    9897             :   }
    9898           0 :   return retval.forget();
    9899             : }
    9900           0 : 
    9901           0 : already_AddRefed<TouchList>
    9902           0 : nsIDocument::CreateTouchList(const Sequence<OwningNonNull<Touch> >& aTouches)
    9903             : {
    9904           0 :   RefPtr<TouchList> retval = new TouchList(ToSupports(this));
    9905             :   for (uint32_t i = 0; i < aTouches.Length(); ++i) {
    9906           0 :     retval->Append(aTouches[i].get());
    9907           0 :   }
    9908             :   return retval.forget();
    9909             : }
    9910             : 
    9911           0 : already_AddRefed<nsDOMCaretPosition>
    9912             : nsIDocument::CaretPositionFromPoint(float aX, float aY)
    9913             : {
    9914           0 :   nscoord x = nsPresContext::CSSPixelsToAppUnits(aX);
    9915             :   nscoord y = nsPresContext::CSSPixelsToAppUnits(aY);
    9916             :   nsPoint pt(x, y);
    9917             : 
    9918           0 :   FlushPendingNotifications(FlushType::Layout);
    9919           0 : 
    9920           0 :   nsIPresShell *ps = GetShell();
    9921             :   if (!ps) {
    9922             :     return nullptr;
    9923             :   }
    9924             : 
    9925           0 :   nsIFrame *rootFrame = ps->GetRootFrame();
    9926           0 : 
    9927             :   // XUL docs, unlike HTML, have no frame tree until everything's done loading
    9928           0 :   if (!rootFrame) {
    9929             :     return nullptr;
    9930           0 :   }
    9931             : 
    9932             :   nsIFrame *ptFrame = nsLayoutUtils::GetFrameForPoint(rootFrame, pt,
    9933           0 :       nsLayoutUtils::IGNORE_PAINT_SUPPRESSION | nsLayoutUtils::IGNORE_CROSS_DOC);
    9934             :   if (!ptFrame) {
    9935           0 :     return nullptr;
    9936           0 :   }
    9937           0 : 
    9938           0 :   // We require frame-relative coordinates for GetContentOffsetsFromPoint.
    9939           0 :   nsPoint aOffset;
    9940           0 :   nsCOMPtr<nsIWidget> widget = nsContentUtils::GetWidget(ps, &aOffset);
    9941           0 :   LayoutDeviceIntPoint refPoint =
    9942           0 :     nsContentUtils::ToWidgetPoint(CSSPoint(aX, aY), aOffset, GetPresContext());
    9943           0 :   nsPoint adjustedPoint =
    9944           0 :     nsLayoutUtils::GetEventCoordinatesRelativeTo(widget, refPoint, ptFrame);
    9945           0 : 
    9946             :   nsFrame::ContentOffsets offsets =
    9947             :     ptFrame->GetContentOffsetsFromPoint(adjustedPoint);
    9948             : 
    9949           0 :   nsCOMPtr<nsIContent> node = offsets.content;
    9950           0 :   uint32_t offset = offsets.offset;
    9951           0 :   nsCOMPtr<nsIContent> anonNode = node;
    9952             :   bool nodeIsAnonymous = node && node->IsInNativeAnonymousSubtree();
    9953             :   if (nodeIsAnonymous) {
    9954           0 :     node = ptFrame->GetContent();
    9955           0 :     nsIContent* nonanon = node->FindFirstNonChromeOnlyAccessContent();
    9956             :     HTMLTextAreaElement* textArea = HTMLTextAreaElement::FromNode(nonanon);
    9957             :     nsITextControlFrame* textFrame = do_QueryFrame(nonanon->GetPrimaryFrame());
    9958           0 :     nsNumberControlFrame* numberFrame = do_QueryFrame(nonanon->GetPrimaryFrame());
    9959             :     if (textFrame || numberFrame) {
    9960           0 :       // If the anonymous content node has a child, then we need to make sure
    9961           0 :       // that we get the appropriate child, as otherwise the offset may not be
    9962             :       // correct when we construct a range for it.
    9963             :       nsCOMPtr<nsIContent> firstChild = anonNode->GetFirstChild();
    9964             :       if (firstChild) {
    9965           0 :         anonNode = firstChild;
    9966           0 :       }
    9967           0 : 
    9968             :       if (textArea) {
    9969           0 :         offset = nsContentUtils::GetAdjustedOffsetInTextControl(ptFrame, offset);
    9970             :       }
    9971             : 
    9972             :       node = nonanon;
    9973           0 :     } else {
    9974             :       node = nullptr;
    9975             :       offset = 0;
    9976           0 :     }
    9977             :   }
    9978             : 
    9979             :   RefPtr<nsDOMCaretPosition> aCaretPos = new nsDOMCaretPosition(node, offset);
    9980             :   if (nodeIsAnonymous) {
    9981             :     aCaretPos->SetAnonymousContentNode(anonNode);
    9982           0 :   }
    9983           0 :   return aCaretPos.forget();
    9984             : }
    9985             : 
    9986             : bool
    9987             : nsIDocument::IsPotentiallyScrollable(HTMLBodyElement* aBody)
    9988             : {
    9989           0 :   // We rely on correct frame information here, so need to flush frames.
    9990           0 :   FlushPendingNotifications(FlushType::Frames);
    9991           0 : 
    9992           0 :   // An element is potentially scrollable if all of the following conditions are
    9993           0 :   // true:
    9994             : 
    9995             :   // The element has an associated CSS layout box.
    9996             :   nsIFrame* bodyFrame = aBody->GetPrimaryFrame();
    9997             :   if (!bodyFrame) {
    9998             :     return false;
    9999           0 :   }
   10000           0 : 
   10001             :   // The element is not the HTML body element, or it is and the root element's
   10002             :   // used value of the overflow-x or overflow-y properties is not visible.
   10003             :   MOZ_ASSERT(aBody->GetParent() == aBody->OwnerDoc()->GetRootElement());
   10004           0 :   nsIFrame* parentFrame = aBody->GetParent()->GetPrimaryFrame();
   10005             :   if (parentFrame &&
   10006             :       parentFrame->StyleDisplay()->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE &&
   10007             :       parentFrame->StyleDisplay()->mOverflowY == NS_STYLE_OVERFLOW_VISIBLE) {
   10008           0 :     return false;
   10009             :   }
   10010             : 
   10011           0 :   // The element's used value of the overflow-x or overflow-y properties is not
   10012           0 :   // visible.
   10013           0 :   if (bodyFrame->StyleDisplay()->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE &&
   10014           0 :       bodyFrame->StyleDisplay()->mOverflowY == NS_STYLE_OVERFLOW_VISIBLE) {
   10015             :     return false;
   10016             :   }
   10017             : 
   10018             :   return true;
   10019             : }
   10020           0 : 
   10021             : Element*
   10022             : nsIDocument::GetScrollingElement()
   10023             : {
   10024           0 :   // Keep this in sync with IsScrollingElement.
   10025             :   if (GetCompatibilityMode() == eCompatibility_NavQuirks) {
   10026             :     RefPtr<HTMLBodyElement> body = GetBodyElement();
   10027           0 :     if (body && !IsPotentiallyScrollable(body)) {
   10028             :       return body;
   10029           0 :     }
   10030           0 : 
   10031             :     return nullptr;
   10032             :   }
   10033             : 
   10034           0 :   return GetRootElement();
   10035           0 : }
   10036             : 
   10037             : bool
   10038             : nsIDocument::IsScrollingElement(Element* aElement)
   10039             : {
   10040             :   // Keep this in sync with GetScrollingElement.
   10041             :   MOZ_ASSERT(aElement);
   10042           0 : 
   10043           0 :   if (GetCompatibilityMode() != eCompatibility_NavQuirks) {
   10044             :     return aElement == GetRootElement();
   10045             :   }
   10046             : 
   10047           0 :   // In the common case when aElement != body, avoid refcounting.
   10048             :   HTMLBodyElement* body = GetBodyElement();
   10049           0 :   if (aElement != body) {
   10050           0 :     return false;
   10051           0 :   }
   10052             : 
   10053           0 :   // Now we know body is non-null, since aElement is not null.  It's the
   10054             :   // scrolling element for the document if it itself is not potentially
   10055             :   // scrollable.
   10056           0 :   RefPtr<HTMLBodyElement> strongBody(body);
   10057             :   return !IsPotentiallyScrollable(strongBody);
   10058           0 : }
   10059           0 : 
   10060           0 : void
   10061           0 : nsIDocument::ObsoleteSheet(nsIURI *aSheetURI, ErrorResult& rv)
   10062           0 : {
   10063             :   nsresult res = CSSLoader()->ObsoleteSheet(aSheetURI);
   10064           0 :   if (NS_FAILED(res)) {
   10065           0 :     rv.Throw(res);
   10066           0 :   }
   10067             : }
   10068             : 
   10069             : void
   10070             : nsIDocument::ObsoleteSheet(const nsAString& aSheetURI, ErrorResult& rv)
   10071             : {
   10072             :   nsCOMPtr<nsIURI> uri;
   10073             :   nsresult res = NS_NewURI(getter_AddRefs(uri), aSheetURI);
   10074           0 :   if (NS_FAILED(res)) {
   10075             :     rv.Throw(res);
   10076           0 :     return;
   10077             :   }
   10078           0 :   res = CSSLoader()->ObsoleteSheet(uri);
   10079             :   if (NS_FAILED(res)) {
   10080           0 :     rv.Throw(res);
   10081           0 :   }
   10082           0 : }
   10083           0 : 
   10084           0 : class UnblockParsingPromiseHandler final : public PromiseNativeHandler
   10085             : {
   10086           0 : public:
   10087             :   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   10088             :   NS_DECL_CYCLE_COLLECTION_CLASS(UnblockParsingPromiseHandler)
   10089           0 : 
   10090             :   explicit UnblockParsingPromiseHandler(nsIDocument* aDocument, Promise* aPromise,
   10091           0 :                                         const BlockParsingOptions& aOptions)
   10092             :     : mPromise(aPromise)
   10093           0 :   {
   10094           0 :     nsCOMPtr<nsIParser> parser = aDocument->CreatorParserOrNull();
   10095             :     if (parser && (aOptions.mBlockScriptCreated || !parser->IsScriptCreated())) {
   10096             :       parser->BlockParser();
   10097           0 :       mParser = do_GetWeakReference(parser);
   10098             :       mDocument = aDocument;
   10099           0 :     }
   10100             :   }
   10101           0 : 
   10102           0 :   void
   10103             :   ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
   10104             :   {
   10105           0 :     MaybeUnblockParser();
   10106           0 : 
   10107             :     mPromise->MaybeResolve(aCx, aValue);
   10108             :   }
   10109           0 : 
   10110           0 :   void
   10111             :   RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
   10112           0 :   {
   10113             :     MaybeUnblockParser();
   10114             : 
   10115           0 :     mPromise->MaybeReject(aCx, aValue);
   10116           0 :   }
   10117           0 : 
   10118           0 : protected:
   10119           0 :   virtual ~UnblockParsingPromiseHandler()
   10120           0 :   {
   10121           0 :     // If we're being cleaned up by the cycle collector, our mDocument reference
   10122           0 :     // may have been unlinked while our mParser weak reference is still alive.
   10123             :     if (mDocument) {
   10124             :       MaybeUnblockParser();
   10125           0 :     }
   10126           0 :   }
   10127           0 : 
   10128             : private:
   10129             :   void MaybeUnblockParser() {
   10130             :     nsCOMPtr<nsIParser> parser = do_QueryReferent(mParser);
   10131             :     if (parser) {
   10132             :       MOZ_DIAGNOSTIC_ASSERT(mDocument);
   10133             :       nsCOMPtr<nsIParser> docParser = mDocument->CreatorParserOrNull();
   10134           0 :       if (parser == docParser) {
   10135             :         parser->UnblockParser();
   10136           0 :         parser->ContinueInterruptedParsingAsync();
   10137           0 :       }
   10138           0 :     }
   10139             :     mParser = nullptr;
   10140           0 :     mDocument = nullptr;
   10141           0 :   }
   10142             : 
   10143             :   nsWeakPtr mParser;
   10144           0 :   RefPtr<Promise> mPromise;
   10145             :   RefPtr<nsIDocument> mDocument;
   10146           0 : };
   10147           0 : 
   10148             : NS_IMPL_CYCLE_COLLECTION(UnblockParsingPromiseHandler, mDocument, mPromise)
   10149             : 
   10150             : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(UnblockParsingPromiseHandler)
   10151             :   NS_INTERFACE_MAP_ENTRY(nsISupports)
   10152           0 : NS_INTERFACE_MAP_END
   10153           0 : 
   10154             : NS_IMPL_CYCLE_COLLECTING_ADDREF(UnblockParsingPromiseHandler)
   10155           0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(UnblockParsingPromiseHandler)
   10156             : 
   10157             : already_AddRefed<Promise>
   10158             : nsIDocument::BlockParsing(Promise& aPromise, const BlockParsingOptions& aOptions, ErrorResult& aRv)
   10159           0 : {
   10160             :   RefPtr<Promise> resultPromise = Promise::Create(aPromise.GetParentObject(), aRv);
   10161           0 :   if (aRv.Failed()) {
   10162           0 :     return nullptr;
   10163           0 :   }
   10164           0 : 
   10165             :   RefPtr<PromiseNativeHandler> promiseHandler = new UnblockParsingPromiseHandler(this, resultPromise,
   10166             :                                                                                  aOptions);
   10167             :   aPromise.AppendNativeHandler(promiseHandler);
   10168           0 : 
   10169           0 :   return resultPromise.forget();
   10170             : }
   10171             : 
   10172             : already_AddRefed<nsIURI>
   10173           0 : nsIDocument::GetMozDocumentURIIfNotForErrorPages()
   10174             : {
   10175             :   if (mFailedChannel) {
   10176             :     nsCOMPtr<nsIURI> failedURI;
   10177           0 :     if (NS_SUCCEEDED(mFailedChannel->GetURI(getter_AddRefs(failedURI)))) {
   10178             :       return failedURI.forget();
   10179         144 :     }
   10180          52 :   }
   10181           0 : 
   10182           0 :   nsCOMPtr<nsIURI> uri = GetDocumentURIObject();
   10183           0 :   if (!uri) {
   10184             :     return nullptr;
   10185             :   }
   10186           1 : 
   10187           1 :   return uri.forget();
   10188             : }
   10189             : 
   10190             : Promise*
   10191             : nsIDocument::GetDocumentReadyForIdle(ErrorResult& aRv)
   10192         144 : {
   10193             :   if (!mReadyForIdle) {
   10194             :     nsIGlobalObject* global = GetScopeObject();
   10195             :     if (!global) {
   10196           0 :       aRv.Throw(NS_ERROR_NOT_AVAILABLE);
   10197             :       return nullptr;
   10198         144 :     }
   10199          72 : 
   10200           0 :     mReadyForIdle = Promise::Create(global, aRv);
   10201          72 :     if (aRv.Failed()) {
   10202             :       return nullptr;
   10203           0 :     }
   10204             :   }
   10205             : 
   10206           0 :   return mReadyForIdle;
   10207             : }
   10208           0 : 
   10209             : void
   10210             : nsIDocument::MaybeResolveReadyForIdle()
   10211             : {
   10212           0 :   IgnoredErrorResult rv;
   10213             :   Promise* readyPromise = GetDocumentReadyForIdle(rv);
   10214             :   if (readyPromise) {
   10215           0 :     readyPromise->MaybeResolve(this);
   10216             :   }
   10217             : }
   10218             : 
   10219           0 : nsIHTMLCollection*
   10220             : nsIDocument::Children()
   10221           0 : {
   10222             :   if (!mChildrenCollection) {
   10223             :     mChildrenCollection = new nsContentList(this, kNameSpaceID_Wildcard,
   10224             :                                             nsGkAtoms::_asterisk,
   10225             :                                             nsGkAtoms::_asterisk,
   10226             :                                             false);
   10227             :   }
   10228             : 
   10229             :   return mChildrenCollection;
   10230             : }
   10231             : 
   10232             : uint32_t
   10233             : nsIDocument::ChildElementCount()
   10234             : {
   10235             :   return Children()->Length();
   10236             : }
   10237             : 
   10238             : namespace mozilla {
   10239             : 
   10240             : // Singleton class to manage the list of fullscreen documents which are the
   10241             : // root of a branch which contains fullscreen documents. We maintain this list
   10242             : // so that we can easily exit all windows from fullscreen when the user
   10243             : // presses the escape key.
   10244             : class FullscreenRoots {
   10245             : public:
   10246             :   // Adds the root of given document to the manager. Calling this method
   10247             :   // with a document whose root is already contained has no effect.
   10248             :   static void Add(nsIDocument* aDoc);
   10249             : 
   10250             :   // Iterates over every root in the root list, and calls aFunction, passing
   10251           0 :   // each root once to aFunction. It is safe to call Add() and Remove() while
   10252           0 :   // iterating over the list (i.e. in aFunction). Documents that are removed
   10253           0 :   // from the manager during traversal are not traversed, and documents that
   10254           0 :   // are added to the manager during traversal are also not traversed.
   10255           0 :   static void ForEach(void(*aFunction)(nsIDocument* aDoc));
   10256           0 : 
   10257             :   // Removes the root of a specific document from the manager.
   10258             :   static void Remove(nsIDocument* aDoc);
   10259             : 
   10260             :   // Returns true if all roots added to the list have been removed.
   10261             :   static bool IsEmpty();
   10262             : 
   10263             : private:
   10264             : 
   10265             :   FullscreenRoots() {
   10266             :     MOZ_COUNT_CTOR(FullscreenRoots);
   10267             :   }
   10268             :   ~FullscreenRoots() {
   10269             :     MOZ_COUNT_DTOR(FullscreenRoots);
   10270             :   }
   10271             : 
   10272             :   enum {
   10273             :     NotFound = uint32_t(-1)
   10274             :   };
   10275             :   // Looks in mRoots for aRoot. Returns the index if found, otherwise NotFound.
   10276             :   static uint32_t Find(nsIDocument* aRoot);
   10277             : 
   10278             :   // Returns true if aRoot is in the list of fullscreen roots.
   10279           0 :   static bool Contains(nsIDocument* aRoot);
   10280             : 
   10281           0 :   // Singleton instance of the FullscreenRoots. This is instantiated when a
   10282           0 :   // root is added, and it is deleted when the last root is removed.
   10283             :   static FullscreenRoots* sInstance;
   10284             : 
   10285             :   // List of weak pointers to roots.
   10286           0 :   nsTArray<nsWeakPtr> mRoots;
   10287             : };
   10288           0 : 
   10289           0 : FullscreenRoots* FullscreenRoots::sInstance = nullptr;
   10290             : 
   10291             : /* static */
   10292           0 : void
   10293           0 : FullscreenRoots::ForEach(void(*aFunction)(nsIDocument* aDoc))
   10294             : {
   10295             :   if (!sInstance) {
   10296             :     return;
   10297             :   }
   10298             :   // Create a copy of the roots array, and iterate over the copy. This is so
   10299             :   // that if an element is removed from mRoots we don't mess up our iteration.
   10300           0 :   nsTArray<nsWeakPtr> roots(sInstance->mRoots);
   10301             :   // Call aFunction on all entries.
   10302           0 :   for (uint32_t i = 0; i < roots.Length(); i++) {
   10303             :     nsCOMPtr<nsIDocument> root = do_QueryReferent(roots[i]);
   10304             :     // Check that the root isn't in the manager. This is so that new additions
   10305             :     // while we were running don't get traversed.
   10306             :     if (root && FullscreenRoots::Contains(root)) {
   10307           0 :       aFunction(root);
   10308             :     }
   10309           0 :   }
   10310           0 : }
   10311           0 : 
   10312           0 : /* static */
   10313             : bool
   10314           0 : FullscreenRoots::Contains(nsIDocument* aRoot)
   10315             : {
   10316           0 :   return FullscreenRoots::Find(aRoot) != NotFound;
   10317             : }
   10318             : 
   10319             : /* static */
   10320           0 : void
   10321             : FullscreenRoots::Add(nsIDocument* aDoc)
   10322           0 : {
   10323             :   nsCOMPtr<nsIDocument> root = nsContentUtils::GetRootDocument(aDoc);
   10324             :   if (!FullscreenRoots::Contains(root)) {
   10325             :     if (!sInstance) {
   10326           0 :       sInstance = new FullscreenRoots();
   10327           0 :     }
   10328           0 :     sInstance->mRoots.AppendElement(do_GetWeakReference(root));
   10329           0 :   }
   10330             : }
   10331             : 
   10332             : /* static */
   10333             : uint32_t
   10334             : FullscreenRoots::Find(nsIDocument* aRoot)
   10335             : {
   10336             :   if (!sInstance) {
   10337           0 :     return NotFound;
   10338             :   }
   10339           0 :   nsTArray<nsWeakPtr>& roots = sInstance->mRoots;
   10340           0 :   for (uint32_t i = 0; i < roots.Length(); i++) {
   10341           0 :     nsCOMPtr<nsIDocument> otherRoot(do_QueryReferent(roots[i]));
   10342             :     if (otherRoot == aRoot) {
   10343           0 :       return i;
   10344           0 :     }
   10345             :   }
   10346           0 :   return NotFound;
   10347           0 : }
   10348           0 : 
   10349           0 : /* static */
   10350             : void
   10351             : FullscreenRoots::Remove(nsIDocument* aDoc)
   10352             : {
   10353             :   nsCOMPtr<nsIDocument> root = nsContentUtils::GetRootDocument(aDoc);
   10354             :   uint32_t index = Find(root);
   10355           0 :   NS_ASSERTION(index != NotFound,
   10356             :     "Should only try to remove roots which are still added!");
   10357           0 :   if (index == NotFound || !sInstance) {
   10358             :     return;
   10359             :   }
   10360             :   sInstance->mRoots.RemoveElementAt(index);
   10361             :   if (sInstance->mRoots.IsEmpty()) {
   10362             :     delete sInstance;
   10363             :     sInstance = nullptr;
   10364           0 :   }
   10365             : }
   10366           0 : 
   10367           0 : /* static */
   10368             : bool
   10369             : FullscreenRoots::IsEmpty()
   10370             : {
   10371           0 :   return !sInstance;
   10372             : }
   10373           0 : 
   10374           0 : } // end namespace mozilla.
   10375             : using mozilla::FullscreenRoots;
   10376             : 
   10377           0 : nsIDocument*
   10378             : nsIDocument::GetFullscreenRoot()
   10379           0 : {
   10380           0 :   nsCOMPtr<nsIDocument> root = do_QueryReferent(mFullscreenRoot);
   10381             :   return root;
   10382             : }
   10383           0 : 
   10384             : void
   10385           0 : nsIDocument::SetFullscreenRoot(nsIDocument* aRoot)
   10386           0 : {
   10387           0 :   mFullscreenRoot = do_GetWeakReference(aRoot);
   10388             : }
   10389           0 : 
   10390             : void
   10391           0 : nsIDocument::ExitFullscreen()
   10392           0 : {
   10393             :   RestorePreviousFullScreenState();
   10394             : }
   10395           0 : 
   10396             : static void
   10397           0 : AskWindowToExitFullscreen(nsIDocument* aDoc)
   10398             : {
   10399             :   if (XRE_GetProcessType() == GeckoProcessType_Content) {
   10400           0 :     nsContentUtils::DispatchEventOnlyToChrome(
   10401           0 :       aDoc, ToSupports(aDoc), NS_LITERAL_STRING("MozDOMFullscreen:Exit"),
   10402           0 :       /* Bubbles */ true, /* Cancelable */ false,
   10403             :       /* DefaultAction */ nullptr);
   10404           0 :   } else {
   10405             :     if (nsPIDOMWindowOuter* win = aDoc->GetWindow()) {
   10406           0 :       win->SetFullscreenInternal(FullscreenReason::ForFullscreenAPI, false);
   10407             :     }
   10408           0 :   }
   10409           0 : }
   10410             : 
   10411           0 : class nsCallExitFullscreen : public Runnable
   10412             : {
   10413           0 : public:
   10414             :   explicit nsCallExitFullscreen(nsIDocument* aDoc)
   10415             :     : mozilla::Runnable("nsCallExitFullscreen")
   10416             :     , mDoc(aDoc)
   10417             :   {
   10418             :   }
   10419             : 
   10420             :   NS_IMETHOD Run() final
   10421           0 :   {
   10422             :     if (!mDoc) {
   10423           0 :       FullscreenRoots::ForEach(&AskWindowToExitFullscreen);
   10424           0 :     } else {
   10425           0 :       AskWindowToExitFullscreen(mDoc);
   10426           0 :     }
   10427             :     return NS_OK;
   10428           0 :   }
   10429             : 
   10430           0 : private:
   10431             :   nsCOMPtr<nsIDocument> mDoc;
   10432             : };
   10433           0 : 
   10434             : /* static */ void
   10435           0 : nsIDocument::AsyncExitFullscreen(nsIDocument* aDoc)
   10436           0 : {
   10437           0 :   MOZ_RELEASE_ASSERT(NS_IsMainThread());
   10438             :   nsCOMPtr<nsIRunnable> exit = new nsCallExitFullscreen(aDoc);
   10439           0 :   if (aDoc) {
   10440             :     aDoc->Dispatch(TaskCategory::Other, exit.forget());
   10441             :   } else {
   10442             :     NS_DispatchToCurrentThread(exit.forget());
   10443           0 :   }
   10444             : }
   10445           0 : 
   10446           0 : static bool
   10447           0 : CountFullscreenSubDocuments(nsIDocument* aDoc, void* aData)
   10448             : {
   10449             :   if (aDoc->FullScreenStackTop()) {
   10450             :     uint32_t* count = static_cast<uint32_t*>(aData);
   10451           0 :     (*count)++;
   10452             :   }
   10453             :   return true;
   10454             : }
   10455           0 : 
   10456             : static uint32_t
   10457             : CountFullscreenSubDocuments(nsIDocument* aDoc)
   10458           0 : {
   10459             :   uint32_t count = 0;
   10460             :   aDoc->EnumerateSubDocuments(CountFullscreenSubDocuments, &count);
   10461             :   return count;
   10462           0 : }
   10463             : 
   10464           0 : bool
   10465           0 : nsIDocument::IsFullscreenLeaf()
   10466             : {
   10467           0 :   // A fullscreen leaf document is fullscreen, and has no fullscreen
   10468           0 :   // subdocuments.
   10469             :   if (!FullScreenStackTop()) {
   10470           0 :     return false;
   10471           0 :   }
   10472           0 :   return CountFullscreenSubDocuments(this) == 0;
   10473             : }
   10474           0 : 
   10475             : static bool
   10476             : ResetFullScreen(nsIDocument* aDocument, void* aData)
   10477             : {
   10478             :   if (aDocument->FullScreenStackTop()) {
   10479             :     NS_ASSERTION(CountFullscreenSubDocuments(aDocument) <= 1,
   10480           0 :         "Should have at most 1 fullscreen subdocument.");
   10481             :     aDocument->CleanupFullscreenState();
   10482             :     NS_ASSERTION(!aDocument->FullScreenStackTop(),
   10483           0 :                  "Should reset full-screen");
   10484           0 :     auto changed = reinterpret_cast<nsCOMArray<nsIDocument>*>(aData);
   10485           0 :     changed->AppendElement(aDocument);
   10486             :     aDocument->EnumerateSubDocuments(ResetFullScreen, aData);
   10487           0 :   }
   10488             :   return true;
   10489           0 : }
   10490             : 
   10491             : // Since nsIDocument::ExitFullscreenInDocTree() could be called from
   10492             : // Element::UnbindFromTree() where it is not safe to synchronously run
   10493             : // script. This runnable is the script part of that function.
   10494           0 : class ExitFullscreenScriptRunnable : public Runnable
   10495           0 : {
   10496             : public:
   10497           0 :   explicit ExitFullscreenScriptRunnable(nsCOMArray<nsIDocument>&& aDocuments)
   10498           0 :     : mozilla::Runnable("ExitFullscreenScriptRunnable")
   10499             :     , mDocuments(std::move(aDocuments))
   10500           0 :   {
   10501           0 :   }
   10502             : 
   10503           0 :   NS_IMETHOD Run() override
   10504             :   {
   10505             :     // Dispatch MozDOMFullscreen:Exited to the last document in
   10506             :     // the list since we want this event to follow the same path
   10507             :     // MozDOMFullscreen:Entered dispatched.
   10508             :     nsIDocument* lastDocument = mDocuments[mDocuments.Length() - 1];
   10509             :     nsContentUtils::DispatchEventOnlyToChrome(
   10510             :       lastDocument, ToSupports(lastDocument),
   10511           0 :       NS_LITERAL_STRING("MozDOMFullscreen:Exited"),
   10512             :       /* Bubbles */ true, /* Cancelable */ false, /* DefaultAction */ nullptr);
   10513           0 :     // Ensure the window exits fullscreen.
   10514             :     if (nsPIDOMWindowOuter* win = mDocuments[0]->GetWindow()) {
   10515             :       win->SetFullscreenInternal(FullscreenReason::ForForceExitFullscreen, false);
   10516           0 :     }
   10517             :     return NS_OK;
   10518           0 :   }
   10519           0 : 
   10520             : private:
   10521             :   nsCOMArray<nsIDocument> mDocuments;
   10522             : };
   10523             : 
   10524             : /* static */ void
   10525             : nsIDocument::ExitFullscreenInDocTree(nsIDocument* aMaybeNotARootDoc)
   10526             : {
   10527             :   MOZ_ASSERT(aMaybeNotARootDoc);
   10528           0 : 
   10529             :   // Unlock the pointer
   10530             :   UnlockPointer();
   10531             : 
   10532             :   nsCOMPtr<nsIDocument> root = aMaybeNotARootDoc->GetFullscreenRoot();
   10533             :   if (!root || !root->FullScreenStackTop()) {
   10534             :     // If a document was detached before exiting from fullscreen, it is
   10535             :     // possible that the root had left fullscreen state. In this case,
   10536           0 :     // we would not get anything from the ResetFullScreen() call. Root's
   10537             :     // not being a fullscreen doc also means the widget should have
   10538             :     // exited fullscreen state. It means even if we do not return here,
   10539           0 :     // we would actually do nothing below except crashing ourselves via
   10540             :     // dispatching the "MozDOMFullscreen:Exited" event to an nonexistent
   10541             :     // document.
   10542             :     return;
   10543             :   }
   10544           0 : 
   10545           0 :   // Stores a list of documents to which we must dispatch "fullscreenchange".
   10546             :   // We're required by the spec to dispatch the events in leaf-to-root
   10547             :   // order when exiting fullscreen, but we traverse the doctree in a
   10548           0 :   // root-to-leaf order, so we save references to the documents we must
   10549             :   // dispatch to so that we dispatch in the specified order.
   10550             :   nsCOMArray<nsIDocument> changed;
   10551             : 
   10552           0 :   // Walk the tree of fullscreen documents, and reset their fullscreen state.
   10553             :   ResetFullScreen(root, static_cast<void*>(&changed));
   10554           0 : 
   10555           0 :   // Dispatch "fullscreenchange" events. Note this loop is in reverse
   10556             :   // order so that the events for the leaf document arrives before the root
   10557             :   // document, as required by the spec.
   10558             :   for (uint32_t i = 0; i < changed.Length(); ++i) {
   10559           0 :     DispatchFullScreenChange(changed[changed.Length() - i - 1]);
   10560             :   }
   10561           0 : 
   10562           0 :   NS_ASSERTION(!root->FullScreenStackTop(),
   10563           0 :     "Fullscreen root should no longer be a fullscreen doc...");
   10564           0 : 
   10565           0 :   // Move the top-level window out of fullscreen mode.
   10566           0 :   FullscreenRoots::Remove(root);
   10567             : 
   10568             :   nsContentUtils::AddScriptRunner(
   10569             :     new ExitFullscreenScriptRunnable(std::move(changed)));
   10570             : }
   10571             : 
   10572           0 : bool
   10573             : GetFullscreenLeaf(nsIDocument* aDoc, void* aData)
   10574           0 : {
   10575           0 :   if (aDoc->IsFullscreenLeaf()) {
   10576           0 :     nsIDocument** result = static_cast<nsIDocument**>(aData);
   10577             :     *result = aDoc;
   10578             :     return false;
   10579             :   } else if (aDoc->FullScreenStackTop()) {
   10580             :     aDoc->EnumerateSubDocuments(GetFullscreenLeaf, aData);
   10581           0 :   }
   10582             :   return true;
   10583             : }
   10584           0 : 
   10585             : static nsIDocument*
   10586             : GetFullscreenLeaf(nsIDocument* aDoc)
   10587           0 : {
   10588           0 :   nsIDocument* leaf = nullptr;
   10589             :   GetFullscreenLeaf(aDoc, &leaf);
   10590             :   if (leaf) {
   10591             :     return leaf;
   10592           0 :   }
   10593             :   // Otherwise we could be either in a non-fullscreen doc tree, or we're
   10594           0 :   // below the fullscreen doc. Start the search from the root.
   10595             :   nsIDocument* root = nsContentUtils::GetRootDocument(aDoc);
   10596             :   // Check that the root is actually fullscreen so we don't waste time walking
   10597           0 :   // around its descendants.
   10598           0 :   if (!root->FullScreenStackTop()) {
   10599             :     return nullptr;
   10600             :   }
   10601           0 :   GetFullscreenLeaf(root, &leaf);
   10602           0 :   return leaf;
   10603             : }
   10604           0 : 
   10605             : void
   10606           0 : nsIDocument::RestorePreviousFullScreenState()
   10607           0 : {
   10608             :   NS_ASSERTION(!FullScreenStackTop() || !FullscreenRoots::IsEmpty(),
   10609             :     "Should have at least 1 fullscreen root when fullscreen!");
   10610             : 
   10611           0 :   if (!FullScreenStackTop() || !GetWindow() || FullscreenRoots::IsEmpty()) {
   10612           0 :     return;
   10613             :   }
   10614           0 : 
   10615           0 :   nsCOMPtr<nsIDocument> fullScreenDoc = GetFullscreenLeaf(this);
   10616           0 :   AutoTArray<nsIDocument*, 8> exitDocs;
   10617           0 : 
   10618             :   nsIDocument* doc = fullScreenDoc;
   10619             :   // Collect all subdocuments.
   10620             :   for (; doc != this; doc = doc->GetParentDocument()) {
   10621             :     exitDocs.AppendElement(doc);
   10622             :   }
   10623             :   MOZ_ASSERT(doc == this, "Must have reached this doc");
   10624           0 :   // Collect all ancestor documents which we are going to change.
   10625           0 :   for (; doc; doc = doc->GetParentDocument()) {
   10626             :     MOZ_ASSERT(!doc->mFullScreenStack.IsEmpty(),
   10627             :                "Ancestor of fullscreen document must also be in fullscreen");
   10628             :     if (doc != this) {
   10629             :       Element* top = doc->FullScreenStackTop();
   10630           0 :       if (top->IsHTMLElement(nsGkAtoms::iframe)) {
   10631           0 :         if (static_cast<HTMLIFrameElement*>(top)->FullscreenFlag()) {
   10632           0 :           // If this is an iframe, and it explicitly requested
   10633             :           // fullscreen, don't rollback it automatically.
   10634             :           break;
   10635           0 :         }
   10636           0 :       }
   10637             :     }
   10638             :     exitDocs.AppendElement(doc);
   10639             :     if (doc->mFullScreenStack.Length() > 1) {
   10640           0 :       break;
   10641             :     }
   10642             :   }
   10643           0 : 
   10644           0 :   nsIDocument* lastDoc = exitDocs.LastElement();
   10645             :   if (!lastDoc->GetParentDocument() &&
   10646             :       lastDoc->mFullScreenStack.Length() == 1) {
   10647             :     // If we are fully exiting fullscreen, don't touch anything here,
   10648             :     // just wait for the window to get out from fullscreen first.
   10649           0 :     AskWindowToExitFullscreen(this);
   10650           0 :     return;
   10651           0 :   }
   10652             : 
   10653           0 :   // If fullscreen mode is updated the pointer should be unlocked
   10654           0 :   UnlockPointer();
   10655             :   // All documents listed in the array except the last one are going to
   10656             :   // completely exit from the fullscreen state.
   10657           0 :   for (auto i : IntegerRange(exitDocs.Length() - 1)) {
   10658           0 :     exitDocs[i]->CleanupFullscreenState();
   10659             :   }
   10660             :   // The last document will either rollback one fullscreen element, or
   10661           0 :   // completely exit from the fullscreen state as well.
   10662             :   nsIDocument* newFullscreenDoc;
   10663             :   if (lastDoc->mFullScreenStack.Length() > 1) {
   10664           0 :     lastDoc->FullScreenStackPop();
   10665           0 :     newFullscreenDoc = lastDoc;
   10666             :   } else {
   10667             :     lastDoc->CleanupFullscreenState();
   10668             :     newFullscreenDoc = lastDoc->GetParentDocument();
   10669             :   }
   10670             :   // Dispatch the fullscreenchange event to all document listed.
   10671           0 :   for (nsIDocument* d : exitDocs) {
   10672           0 :     DispatchFullScreenChange(d);
   10673             :   }
   10674             : 
   10675             :   MOZ_ASSERT(newFullscreenDoc, "If we were going to exit from fullscreen on "
   10676           0 :              "all documents in this doctree, we should've asked the window to "
   10677             :              "exit first instead of reaching here.");
   10678             :   if (fullScreenDoc != newFullscreenDoc &&
   10679           0 :       !nsContentUtils::HaveEqualPrincipals(fullScreenDoc, newFullscreenDoc)) {
   10680           0 :     // We've popped so enough off the stack that we've rolled back to
   10681           0 :     // a fullscreen element in a parent document. If this document is
   10682             :     // cross origin, dispatch an event to chrome so it knows to show
   10683           0 :     // the warning UI.
   10684             :     DispatchCustomEventWithFlush(
   10685           0 :       newFullscreenDoc, NS_LITERAL_STRING("MozDOMFullscreen:NewOrigin"),
   10686             :       /* Bubbles */ true, /* ChromeOnly */ true);
   10687           0 :   }
   10688           0 : }
   10689             : 
   10690             : class nsCallRequestFullScreen : public Runnable
   10691             : {
   10692             : public:
   10693             :   explicit nsCallRequestFullScreen(UniquePtr<FullscreenRequest>&& aRequest)
   10694             :     : mozilla::Runnable("nsCallRequestFullScreen")
   10695           0 :     , mRequest(std::move(aRequest))
   10696             :   {
   10697           0 :   }
   10698           0 : 
   10699             :   NS_IMETHOD Run() override
   10700             :   {
   10701             :     mRequest->GetDocument()->RequestFullScreen(std::move(mRequest));
   10702             :     return NS_OK;
   10703             :   }
   10704           0 : 
   10705           0 :   UniquePtr<FullscreenRequest> mRequest;
   10706           0 : };
   10707           0 : 
   10708             : void
   10709             : nsIDocument::AsyncRequestFullScreen(UniquePtr<FullscreenRequest>&& aRequest)
   10710           0 : {
   10711             :   if (!aRequest->GetElement()) {
   10712             :     MOZ_ASSERT_UNREACHABLE(
   10713             :       "Must pass non-null element to nsDocument::AsyncRequestFullScreen");
   10714           0 :     return;
   10715             :   }
   10716           0 : 
   10717           0 :   // Request full-screen asynchronously.
   10718           0 :   MOZ_RELEASE_ASSERT(NS_IsMainThread());
   10719           0 :   nsCOMPtr<nsIRunnable> event = new nsCallRequestFullScreen(std::move(aRequest));
   10720             :   Dispatch(TaskCategory::Other, event.forget());
   10721           0 : }
   10722           0 : 
   10723             : void
   10724             : nsIDocument::DispatchFullscreenError(const char* aMessage)
   10725           0 : {
   10726             :   RefPtr<AsyncEventDispatcher> asyncDispatcher =
   10727           0 :     new AsyncEventDispatcher(this,
   10728           0 :                              NS_LITERAL_STRING("fullscreenerror"),
   10729             :                              true,
   10730           0 :                              false);
   10731             :   asyncDispatcher->PostDOMEvent();
   10732             :   nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
   10733           0 :                                   NS_LITERAL_CSTRING("DOM"), this,
   10734             :                                   nsContentUtils::eDOM_PROPERTIES,
   10735             :                                   aMessage);
   10736           0 : }
   10737             : 
   10738           0 : static void
   10739             : UpdateViewportScrollbarOverrideForFullscreen(nsIDocument* aDoc)
   10740             : {
   10741           0 :   if (nsPresContext* presContext = aDoc->GetPresContext()) {
   10742             :     presContext->UpdateViewportScrollbarStylesOverride();
   10743             :   }
   10744           0 : }
   10745             : 
   10746             : static void
   10747             : ClearFullscreenStateOnElement(Element* aElement)
   10748             : {
   10749             :   // Remove styles from existing top element.
   10750             :   EventStateManager::SetFullScreenState(aElement, false);
   10751             :   // Reset iframe fullscreen flag.
   10752             :   if (aElement->IsHTMLElement(nsGkAtoms::iframe)) {
   10753           0 :     static_cast<HTMLIFrameElement*>(aElement)->SetFullscreenFlag(false);
   10754           0 :   }
   10755           0 : }
   10756             : 
   10757             : void
   10758           0 : nsIDocument::CleanupFullscreenState()
   10759           0 : {
   10760           0 :   // Iterate the fullscreen stack and clear the fullscreen states.
   10761           0 :   // Since we also need to clear the fullscreen-ancestor state, and
   10762             :   // currently fullscreen elements can only be placed in hierarchy
   10763             :   // order in the stack, reversely iterating the stack could be more
   10764           0 :   // efficient. NOTE that fullscreen-ancestor state would be removed
   10765             :   // in bug 1199529, and the elements may not in hierarchy order
   10766           0 :   // after bug 1195213.
   10767           0 :   for (nsWeakPtr& weakPtr : Reversed(mFullScreenStack)) {
   10768           0 :     if (nsCOMPtr<Element> element = do_QueryReferent(weakPtr)) {
   10769             :       ClearFullscreenStateOnElement(element);
   10770             :     }
   10771           0 :   }
   10772           0 :   mFullScreenStack.Clear();
   10773           0 :   mFullscreenRoot = nullptr;
   10774           0 :   UpdateViewportScrollbarOverrideForFullscreen(this);
   10775           0 : }
   10776             : 
   10777             : bool
   10778             : nsIDocument::FullScreenStackPush(Element* aElement)
   10779           0 : {
   10780             :   NS_ASSERTION(aElement, "Must pass non-null to FullScreenStackPush()");
   10781           0 :   Element* top = FullScreenStackTop();
   10782             :   if (top == aElement || !aElement) {
   10783             :     return false;
   10784             :   }
   10785           0 :   EventStateManager::SetFullScreenState(aElement, true);
   10786             :   mFullScreenStack.AppendElement(do_GetWeakReference(aElement));
   10787             :   NS_ASSERTION(FullScreenStackTop() == aElement, "Should match");
   10788             :   UpdateViewportScrollbarOverrideForFullscreen(this);
   10789             :   return true;
   10790           0 : }
   10791           0 : 
   10792             : void
   10793             : nsIDocument::FullScreenStackPop()
   10794             : {
   10795             :   if (mFullScreenStack.IsEmpty()) {
   10796           0 :     return;
   10797           0 :   }
   10798           0 : 
   10799           0 :   ClearFullscreenStateOnElement(FullScreenStackTop());
   10800             : 
   10801           0 :   // Remove top element. Note the remaining top element in the stack
   10802           0 :   // will not have full-screen style bits set, so we will need to restore
   10803             :   // them on the new top element before returning.
   10804             :   uint32_t last = mFullScreenStack.Length() - 1;
   10805             :   mFullScreenStack.RemoveElementAt(last);
   10806             : 
   10807             :   // Pop from the stack null elements (references to elements which have
   10808             :   // been GC'd since they were added to the stack) and elements which are
   10809           0 :   // no longer in this document.
   10810             :   while (!mFullScreenStack.IsEmpty()) {
   10811             :     Element* element = FullScreenStackTop();
   10812             :     if (!element || !element->IsInUncomposedDoc() || element->OwnerDoc() != this) {
   10813           0 :       NS_ASSERTION(!element->State().HasState(NS_EVENT_STATE_FULL_SCREEN),
   10814             :                    "Should have already removed full-screen styles");
   10815          62 :       uint32_t last = mFullScreenStack.Length() - 1;
   10816             :       mFullScreenStack.RemoveElementAt(last);
   10817             :     } else {
   10818           0 :       // The top element of the stack is now an in-doc element. Return here.
   10819           0 :       break;
   10820           0 :     }
   10821           0 :   }
   10822           0 : 
   10823           0 :   UpdateViewportScrollbarOverrideForFullscreen(this);
   10824             : }
   10825             : 
   10826             : Element*
   10827           0 : nsIDocument::FullScreenStackTop()
   10828             : {
   10829          19 :   if (mFullScreenStack.IsEmpty()) {
   10830          57 :     return nullptr;
   10831           0 :   }
   10832           0 :   uint32_t last = mFullScreenStack.Length() - 1;
   10833           0 :   nsCOMPtr<Element> element(do_QueryReferent(mFullScreenStack[last]));
   10834             :   NS_ASSERTION(element, "Should have full-screen element!");
   10835             :   NS_ASSERTION(element->IsInComposedDoc(), "Full-screen element should be in doc");
   10836           0 :   NS_ASSERTION(element->OwnerDoc() == this, "Full-screen element should be in this doc");
   10837             :   return element;
   10838             : }
   10839             : 
   10840             : nsTArray<Element*>
   10841           0 : nsIDocument::GetFullscreenStack() const
   10842             : {
   10843           0 :   nsTArray<Element*> elements;
   10844           0 :   for (const nsWeakPtr& ptr : mFullScreenStack) {
   10845             :     if (nsCOMPtr<Element> elem = do_QueryReferent(ptr)) {
   10846             :       MOZ_ASSERT(elem->State().HasState(NS_EVENT_STATE_FULL_SCREEN));
   10847             :       elements.AppendElement(elem);
   10848           0 :     }
   10849           0 :   }
   10850           0 :   return elements;
   10851             : }
   10852             : 
   10853             : // Returns true if aDoc is in the focused tab in the active window.
   10854           0 : static bool
   10855           0 : IsInActiveTab(nsIDocument* aDoc)
   10856           0 : {
   10857             :   nsCOMPtr<nsIDocShell> docshell = aDoc->GetDocShell();
   10858             :   if (!docshell) {
   10859           0 :     return false;
   10860           0 :   }
   10861             : 
   10862             :   bool isActive = false;
   10863             :   docshell->GetIsActive(&isActive);
   10864           0 :   if (!isActive) {
   10865           0 :     return false;
   10866             :   }
   10867             : 
   10868             :   nsCOMPtr<nsIDocShellTreeItem> rootItem;
   10869           0 :   docshell->GetRootTreeItem(getter_AddRefs(rootItem));
   10870           0 :   if (!rootItem) {
   10871           0 :     return false;
   10872             :   }
   10873             :   nsCOMPtr<nsPIDOMWindowOuter> rootWin = rootItem->GetWindow();
   10874             :   if (!rootWin) {
   10875           0 :     return false;
   10876             :   }
   10877             : 
   10878           0 :   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
   10879             :   if (!fm) {
   10880             :     return false;
   10881             :   }
   10882             : 
   10883           0 :   nsCOMPtr<mozIDOMWindowProxy> activeWindow;
   10884           0 :   fm->GetActiveWindow(getter_AddRefs(activeWindow));
   10885           0 :   if (!activeWindow) {
   10886           0 :     return false;
   10887             :   }
   10888           0 : 
   10889             :   return activeWindow == rootWin;
   10890             : }
   10891           0 : 
   10892             : nsresult nsIDocument::RemoteFrameFullscreenChanged(Element* aFrameElement)
   10893           0 : {
   10894           0 :   // Ensure the frame element is the fullscreen element in this document.
   10895             :   // If the frame element is already the fullscreen element in this document,
   10896             :   // this has no effect.
   10897             :   auto request = MakeUnique<FullscreenRequest>(aFrameElement);
   10898           0 :   request->mIsCallerChrome = false;
   10899             :   request->mShouldNotifyNewOrigin = false;
   10900          88 :   RequestFullScreen(std::move(request));
   10901         125 : 
   10902           0 :   return NS_OK;
   10903             : }
   10904             : 
   10905             : nsresult nsIDocument::RemoteFrameFullscreenReverted()
   10906           0 : {
   10907             :   RestorePreviousFullScreenState();
   10908           0 :   return NS_OK;
   10909           0 : }
   10910           0 : 
   10911             : /* static */ bool
   10912             : nsIDocument::IsUnprefixedFullscreenEnabled(JSContext* aCx, JSObject* aObject)
   10913             : {
   10914             :   MOZ_ASSERT(NS_IsMainThread());
   10915             :   return nsContentUtils::IsSystemCaller(aCx) ||
   10916             :          nsContentUtils::IsUnprefixedFullscreenApiEnabled();
   10917           0 : }
   10918             : 
   10919           0 : static bool
   10920           0 : HasFullScreenSubDocument(nsIDocument* aDoc)
   10921             : {
   10922             :   uint32_t count = CountFullscreenSubDocuments(aDoc);
   10923             :   NS_ASSERTION(count <= 1, "Fullscreen docs should have at most 1 fullscreen child!");
   10924             :   return count >= 1;
   10925             : }
   10926           0 : 
   10927             : // Returns nullptr if a request for Fullscreen API is currently enabled
   10928             : // in the given document. Returns a static string indicates the reason
   10929             : // why it is not enabled otherwise.
   10930             : static const char*
   10931             : GetFullscreenError(nsIDocument* aDoc, bool aCallerIsChrome)
   10932           0 : {
   10933           0 :   bool apiEnabled = nsContentUtils::IsFullScreenApiEnabled();
   10934             :   if (apiEnabled && aCallerIsChrome) {
   10935             :     // Chrome code can always use the full-screen API, provided it's not
   10936           0 :     // explicitly disabled.
   10937             :     return nullptr;
   10938             :   }
   10939             : 
   10940           0 :   if (!apiEnabled) {
   10941             :     return "FullscreenDeniedDisabled";
   10942             :   }
   10943           0 : 
   10944             :   // Ensure that all containing elements are <iframe> and have
   10945           0 :   // allowfullscreen attribute set.
   10946             :   nsCOMPtr<nsIDocShell> docShell(aDoc->GetDocShell());
   10947             :   if (!docShell || !docShell->GetFullscreenAllowed()) {
   10948           0 :     return "FullscreenDeniedContainerNotAllowed";
   10949           0 :   }
   10950           0 :   return nullptr;
   10951             : }
   10952           0 : 
   10953           0 : bool
   10954           0 : nsIDocument::FullscreenElementReadyCheck(Element* aElement,
   10955             :                                          bool aWasCallerChrome)
   10956           0 : {
   10957           0 :   NS_ASSERTION(aElement,
   10958           0 :     "Must pass non-null element to nsDocument::RequestFullScreen");
   10959             :   if (!aElement || aElement == FullScreenStackTop()) {
   10960           0 :     return false;
   10961           0 :   }
   10962           0 :   if (!aElement->IsInComposedDoc()) {
   10963             :     DispatchFullscreenError("FullscreenDeniedNotInDocument");
   10964           0 :     return false;
   10965           0 :   }
   10966           0 :   if (aElement->OwnerDoc() != this) {
   10967             :     DispatchFullscreenError("FullscreenDeniedMovedDocument");
   10968           0 :     return false;
   10969           0 :   }
   10970           0 :   if (!GetWindow()) {
   10971             :     DispatchFullscreenError("FullscreenDeniedLostWindow");
   10972             :     return false;
   10973             :   }
   10974           0 :   if (const char* msg = GetFullscreenError(this, aWasCallerChrome)) {
   10975           0 :     DispatchFullscreenError(msg);
   10976           0 :     return false;
   10977             :   }
   10978             :   if (!IsVisible()) {
   10979           0 :     DispatchFullscreenError("FullscreenDeniedHidden");
   10980           0 :     return false;
   10981             :   }
   10982           0 :   if (HasFullScreenSubDocument(this)) {
   10983           0 :     DispatchFullscreenError("FullscreenDeniedSubDocFullScreen");
   10984           0 :     return false;
   10985             :   }
   10986             :   //XXXsmaug Note, we don't follow the latest fullscreen spec here.
   10987           0 :   //         This whole check could be probably removed.
   10988           0 :   if (FullScreenStackTop() &&
   10989           0 :       !nsContentUtils::ContentIsHostIncludingDescendantOf(aElement,
   10990           0 :                                                           FullScreenStackTop())) {
   10991             :     // If this document is full-screen, only grant full-screen requests from
   10992           0 :     // a descendant of the current full-screen element.
   10993           0 :     DispatchFullscreenError("FullscreenDeniedNotDescendant");
   10994           0 :     return false;
   10995             :   }
   10996             :   if (!nsContentUtils::IsChromeDoc(this) && !IsInActiveTab(this)) {
   10997             :     DispatchFullscreenError("FullscreenDeniedNotFocusedTab");
   10998             :     return false;
   10999           0 :   }
   11000             :   // Deny requests when a windowed plugin is focused.
   11001           0 :   nsFocusManager* fm = nsFocusManager::GetFocusManager();
   11002             :   if (!fm) {
   11003           0 :     NS_WARNING("Failed to retrieve focus manager in full-screen request.");
   11004           0 :     return false;
   11005             :   }
   11006           0 :   if (nsContentUtils::HasPluginWithUncontrolledEventDispatch(fm->GetFocusedElement())) {
   11007             :     DispatchFullscreenError("FullscreenDeniedFocusedPlugin");
   11008           0 :     return false;
   11009           0 :   }
   11010             :   return true;
   11011             : }
   11012             : 
   11013             : FullscreenRequest::FullscreenRequest(Element* aElement)
   11014             :   : mElement(aElement)
   11015             :   , mDocument(static_cast<nsDocument*>(aElement->OwnerDoc()))
   11016             : {
   11017             :   MOZ_COUNT_CTOR(FullscreenRequest);
   11018             : }
   11019           0 : 
   11020             : FullscreenRequest::~FullscreenRequest()
   11021           0 : {
   11022           0 :   MOZ_COUNT_DTOR(FullscreenRequest);
   11023             : }
   11024             : 
   11025             : // Any fullscreen request waiting for the widget to finish being full-
   11026             : // screen is queued here. This is declared static instead of a member
   11027             : // of nsDocument because in the majority of time, there would be at most
   11028             : // one document requesting fullscreen. We shouldn't waste the space to
   11029             : // hold for it in every document.
   11030             : class PendingFullscreenRequestList
   11031             : {
   11032             : public:
   11033             :   static void Add(UniquePtr<FullscreenRequest>&& aRequest)
   11034             :   {
   11035             :     sList.insertBack(aRequest.release());
   11036             :   }
   11037             : 
   11038             :   static const FullscreenRequest* GetLast()
   11039             :   {
   11040             :     return sList.getLast();
   11041           8 :   }
   11042             : 
   11043             :   enum IteratorOption
   11044           8 :   {
   11045           0 :     // When we are committing fullscreen changes or preparing for
   11046           8 :     // that, we generally want to iterate all requests in the same
   11047             :     // window with eDocumentsWithSameRoot option.
   11048           0 :     eDocumentsWithSameRoot,
   11049           0 :     // If we are removing a document from the tree, we would only
   11050           0 :     // want to remove the requests from the given document and its
   11051           0 :     // descendants. For that case, use eInclusiveDescendants.
   11052             :     eInclusiveDescendants
   11053           0 :   };
   11054             : 
   11055           0 :   class Iterator
   11056             :   {
   11057           0 :   public:
   11058             :     explicit Iterator(nsIDocument* aDoc, IteratorOption aOption)
   11059           0 :       : mCurrent(PendingFullscreenRequestList::sList.getFirst())
   11060           0 :       , mRootShellForIteration(aDoc->GetDocShell())
   11061           0 :     {
   11062             :       if (mCurrent) {
   11063             :         if (mRootShellForIteration && aOption == eDocumentsWithSameRoot) {
   11064             :           mRootShellForIteration->
   11065             :             GetRootTreeItem(getter_AddRefs(mRootShellForIteration));
   11066           0 :         }
   11067             :         SkipToNextMatch();
   11068           0 :       }
   11069           0 :     }
   11070           0 : 
   11071           0 :     void DeleteAndNext()
   11072           0 :     {
   11073             :       DeleteAndNextInternal();
   11074           0 :       SkipToNextMatch();
   11075             :     }
   11076           0 :     bool AtEnd() const { return mCurrent == nullptr; }
   11077           0 :     const FullscreenRequest& Get() const { return *mCurrent; }
   11078             : 
   11079             :   private:
   11080           0 :     void DeleteAndNextInternal()
   11081             :     {
   11082           0 :       FullscreenRequest* thisRequest = mCurrent;
   11083           0 :       mCurrent = mCurrent->getNext();
   11084             :       delete thisRequest;
   11085           0 :     }
   11086             :     void SkipToNextMatch()
   11087             :     {
   11088           0 :       while (mCurrent) {
   11089             :         nsCOMPtr<nsIDocShellTreeItem>
   11090             :           docShell = mCurrent->GetDocument()->GetDocShell();
   11091             :         if (!docShell) {
   11092             :           // Always automatically drop documents which has been
   11093             :           // detached from the doc shell.
   11094           0 :           DeleteAndNextInternal();
   11095             :         } else {
   11096             :           while (docShell && docShell != mRootShellForIteration) {
   11097             :             docShell->GetParent(getter_AddRefs(docShell));
   11098             :           }
   11099             :           if (!docShell) {
   11100             :             // We've gone over the root, but haven't find the target
   11101             :             // ancestor, so skip this item.
   11102             :             mCurrent = mCurrent->getNext();
   11103             :           } else {
   11104             :             break;
   11105             :           }
   11106           1 :         }
   11107             :       }
   11108             :     }
   11109           0 : 
   11110             :     FullscreenRequest* mCurrent;
   11111           0 :     nsCOMPtr<nsIDocShellTreeItem> mRootShellForIteration;
   11112           0 :   };
   11113             : 
   11114             : private:
   11115           0 :   PendingFullscreenRequestList() = delete;
   11116           0 : 
   11117           0 :   static LinkedList<FullscreenRequest> sList;
   11118             : };
   11119             : 
   11120             : /* static */ LinkedList<FullscreenRequest> PendingFullscreenRequestList::sList;
   11121           0 : 
   11122             : static nsCOMPtr<nsPIDOMWindowOuter>
   11123             : GetRootWindow(nsIDocument* aDoc)
   11124           0 : {
   11125             :   nsIDocShell* docShell = aDoc->GetDocShell();
   11126             :   if (!docShell) {
   11127             :     return nullptr;
   11128           0 :   }
   11129             :   nsCOMPtr<nsIDocShellTreeItem> rootItem;
   11130             :   docShell->GetRootTreeItem(getter_AddRefs(rootItem));
   11131             :   return rootItem ? rootItem->GetWindow() : nullptr;
   11132           0 : }
   11133             : 
   11134             : static bool
   11135             : ShouldApplyFullscreenDirectly(nsIDocument* aDoc,
   11136             :                               nsPIDOMWindowOuter* aRootWin)
   11137             : {
   11138             :   if (XRE_GetProcessType() == GeckoProcessType_Content) {
   11139             :     // If we are in the content process, we can apply the fullscreen
   11140           0 :     // state directly only if we have been in DOM fullscreen, because
   11141           0 :     // otherwise we always need to notify the chrome.
   11142             :     return !!nsContentUtils::GetRootDocument(aDoc)->GetFullscreenElement();
   11143             :   } else {
   11144             :     // If we are in the chrome process, and the window has not been in
   11145             :     // fullscreen, we certainly need to make that fullscreen first.
   11146             :     if (!aRootWin->GetFullScreen()) {
   11147             :       return false;
   11148             :     }
   11149           0 :     // The iterator not being at end indicates there is still some
   11150             :     // pending fullscreen request relates to this document. We have to
   11151             :     // push the request to the pending queue so requests are handled
   11152             :     // in the correct order.
   11153             :     PendingFullscreenRequestList::Iterator
   11154           0 :       iter(aDoc, PendingFullscreenRequestList::eDocumentsWithSameRoot);
   11155             :     if (!iter.AtEnd()) {
   11156           0 :       return false;
   11157           0 :     }
   11158           0 :     // We have to apply the fullscreen state directly in this case,
   11159             :     // because nsGlobalWindow::SetFullscreenInternal() will do nothing
   11160             :     // if it is already in fullscreen. If we do not apply the state but
   11161           0 :     // instead add it to the queue and wait for the window as normal,
   11162           0 :     // we would get stuck.
   11163           0 :     return true;
   11164             :   }
   11165             : }
   11166             : 
   11167             : void
   11168           0 : nsIDocument::RequestFullScreen(UniquePtr<FullscreenRequest>&& aRequest)
   11169           0 : {
   11170           0 :   nsCOMPtr<nsPIDOMWindowOuter> rootWin = GetRootWindow(this);
   11171           0 :   if (!rootWin) {
   11172           0 :     return;
   11173           0 :   }
   11174             : 
   11175             :   if (ShouldApplyFullscreenDirectly(this, rootWin)) {
   11176             :     ApplyFullscreen(*aRequest);
   11177             :     return;
   11178           0 :   }
   11179             : 
   11180             :   // Per spec only HTML, <svg>, and <math> should be allowed, but
   11181             :   // we also need to allow XUL elements right now.
   11182           0 :   Element* elem = aRequest->GetElement();
   11183           0 :   if (!elem->IsHTMLElement() && !elem->IsXULElement() &&
   11184             :       !elem->IsSVGElement(nsGkAtoms::svg) &&
   11185             :       !elem->IsMathMLElement(nsGkAtoms::math)) {
   11186           0 :     DispatchFullscreenError("FullscreenDeniedNotHTMLSVGOrMathML");
   11187           0 :     return;
   11188           0 :   }
   11189             : 
   11190             :   // We don't need to check element ready before this point, because
   11191           0 :   // if we called ApplyFullscreen, it would check that for us.
   11192             :   if (!FullscreenElementReadyCheck(elem, aRequest->mIsCallerChrome)) {
   11193             :     return;
   11194             :   }
   11195             : 
   11196           0 :   PendingFullscreenRequestList::Add(std::move(aRequest));
   11197             :   if (XRE_GetProcessType() == GeckoProcessType_Content) {
   11198           0 :     // If we are not the top level process, dispatch an event to make
   11199             :     // our parent process go fullscreen first.
   11200           0 :     nsContentUtils::DispatchEventOnlyToChrome(
   11201           0 :       this, ToSupports(this), NS_LITERAL_STRING("MozDOMFullscreen:Request"),
   11202           0 :       /* Bubbles */ true, /* Cancelable */ false, /* DefaultAction */ nullptr);
   11203           0 :   } else {
   11204           0 :     // Make the window fullscreen.
   11205             :     rootWin->SetFullscreenInternal(FullscreenReason::ForFullscreenAPI, true);
   11206           0 :   }
   11207             : }
   11208           0 : 
   11209             : /* static */ bool
   11210             : nsIDocument::HandlePendingFullscreenRequests(nsIDocument* aDoc)
   11211             : {
   11212           0 :   bool handled = false;
   11213             :   PendingFullscreenRequestList::Iterator iter(
   11214             :     aDoc, PendingFullscreenRequestList::eDocumentsWithSameRoot);
   11215          16 :   while (!iter.AtEnd()) {
   11216           0 :     const FullscreenRequest& request = iter.Get();
   11217           0 :     if (request.GetDocument()->ApplyFullscreen(request)) {
   11218             :       handled = true;
   11219           0 :     }
   11220             :     iter.DeleteAndNext();
   11221             :   }
   11222           0 :   return handled;
   11223             : }
   11224           0 : 
   11225           0 : static void
   11226             : ClearPendingFullscreenRequests(nsIDocument* aDoc)
   11227             : {
   11228             :   PendingFullscreenRequestList::Iterator iter(
   11229             :     aDoc, PendingFullscreenRequestList::eInclusiveDescendants);
   11230             :   while (!iter.AtEnd()) {
   11231           0 :     iter.DeleteAndNext();
   11232             :   }
   11233             : }
   11234             : 
   11235             : bool
   11236             : nsIDocument::ApplyFullscreen(const FullscreenRequest& aRequest)
   11237             : {
   11238           0 :   Element* elem = aRequest.GetElement();
   11239             :   if (!FullscreenElementReadyCheck(elem, aRequest.mIsCallerChrome)) {
   11240             :     return false;
   11241             :   }
   11242           0 : 
   11243             :   // Stash a reference to any existing fullscreen doc, we'll use this later
   11244             :   // to detect if the origin which is fullscreen has changed.
   11245             :   nsCOMPtr<nsIDocument> previousFullscreenDoc = GetFullscreenLeaf(this);
   11246           0 : 
   11247             :   // Stores a list of documents which we must dispatch "fullscreenchange"
   11248             :   // too. We're required by the spec to dispatch the events in root-to-leaf
   11249             :   // order, but we traverse the doctree in a leaf-to-root order, so we save
   11250             :   // references to the documents we must dispatch to so that we get the order
   11251           0 :   // as specified.
   11252           0 :   AutoTArray<nsIDocument*, 8> changed;
   11253             : 
   11254           0 :   // Remember the root document, so that if a full-screen document is hidden
   11255             :   // we can reset full-screen state in the remaining visible full-screen documents.
   11256             :   nsIDocument* fullScreenRootDoc = nsContentUtils::GetRootDocument(this);
   11257           0 : 
   11258             :   // If a document is already in fullscreen, then unlock the mouse pointer
   11259             :   // before setting a new document to fullscreen
   11260             :   UnlockPointer();
   11261             : 
   11262             :   // Set the full-screen element. This sets the full-screen style on the
   11263             :   // element, and the full-screen-ancestor styles on ancestors of the element
   11264           0 :   // in this document.
   11265             :   DebugOnly<bool> x = FullScreenStackPush(elem);
   11266           0 :   NS_ASSERTION(x, "Full-screen state of requesting doc should always change!");
   11267           0 :   // Set the iframe fullscreen flag.
   11268             :   if (elem->IsHTMLElement(nsGkAtoms::iframe)) {
   11269           0 :     static_cast<HTMLIFrameElement*>(elem)->SetFullscreenFlag(true);
   11270             :   }
   11271             :   changed.AppendElement(this);
   11272           0 : 
   11273           0 :   // Propagate up the document hierarchy, setting the full-screen element as
   11274           0 :   // the element's container in ancestor documents. This also sets the
   11275           0 :   // appropriate css styles as well. Note we don't propagate down the
   11276           0 :   // document hierarchy, the full-screen element (or its container) is not
   11277             :   // visible there. Stop when we reach the root document.
   11278             :   nsIDocument* child = this;
   11279             :   while (true) {
   11280             :     child->SetFullscreenRoot(fullScreenRootDoc);
   11281             :     NS_ASSERTION(child->GetFullscreenRoot() == fullScreenRootDoc,
   11282             :         "Fullscreen root should be set!");
   11283             :     if (child == fullScreenRootDoc) {
   11284           0 :       break;
   11285             :     }
   11286           0 :     nsIDocument* parent = child->GetParentDocument();
   11287             :     Element* element = parent->FindContentForSubDocument(child);
   11288             :     if (static_cast<nsDocument*>(parent)->FullScreenStackPush(element)) {
   11289             :       changed.AppendElement(parent);
   11290             :       child = parent;
   11291             :     } else {
   11292             :       // We've reached either the root, or a point in the doctree where the
   11293           0 :       // new full-screen element container is the same as the previous
   11294           0 :       // full-screen element's container. No more changes need to be made
   11295           0 :       // to the full-screen stacks of documents further up the tree.
   11296           0 :       break;
   11297             :     }
   11298             :   }
   11299             : 
   11300             :   FullscreenRoots::Add(this);
   11301             : 
   11302             :   // If it is the first entry of the fullscreen, trigger an event so
   11303             :   // that the UI can response to this change, e.g. hide chrome, or
   11304             :   // notifying parent process to enter fullscreen. Note that chrome
   11305             :   // code may also want to listen to MozDOMFullscreen:NewOrigin event
   11306           0 :   // to pop up warning UI.
   11307           0 :   if (!previousFullscreenDoc) {
   11308           0 :     nsContentUtils::DispatchEventOnlyToChrome(
   11309           0 :       this, ToSupports(elem), NS_LITERAL_STRING("MozDOMFullscreen:Entered"),
   11310           0 :       /* Bubbles */ true, /* Cancelable */ false, /* DefaultAction */ nullptr);
   11311             :   }
   11312             : 
   11313             :   // The origin which is fullscreen gets changed. Trigger an event so
   11314             :   // that the chrome knows to pop up a warning UI. Note that
   11315             :   // previousFullscreenDoc == nullptr upon first entry, so we always
   11316           0 :   // take this path on the first entry. Also note that, in a multi-
   11317           0 :   // process browser, the code in content process is responsible for
   11318             :   // sending message with the origin to its parent, and the parent
   11319           0 :   // shouldn't rely on this event itself.
   11320             :   if (aRequest.mShouldNotifyNewOrigin &&
   11321             :       !nsContentUtils::HaveEqualPrincipals(previousFullscreenDoc, this)) {
   11322             :     DispatchCustomEventWithFlush(
   11323           0 :       this, NS_LITERAL_STRING("MozDOMFullscreen:NewOrigin"),
   11324             :       /* Bubbles */ true, /* ChromeOnly */ true);
   11325           0 :   }
   11326             : 
   11327             :   // Dispatch "fullscreenchange" events. Note this loop is in reverse
   11328             :   // order so that the events for the root document arrives before the leaf
   11329           0 :   // document, as required by the spec.
   11330             :   for (uint32_t i = 0; i < changed.Length(); ++i) {
   11331           0 :     DispatchFullScreenChange(changed[changed.Length() - i - 1]);
   11332           0 :   }
   11333             :   return true;
   11334             : }
   11335           0 : 
   11336             : bool
   11337           0 : nsIDocument::FullscreenEnabled(CallerType aCallerType)
   11338           0 : {
   11339             :   return !GetFullscreenError(this, aCallerType == CallerType::System);
   11340             : }
   11341             : 
   11342             : void
   11343           0 : nsIDocument::SetOrientationPendingPromise(Promise* aPromise)
   11344             : {
   11345           0 :   mOrientationPendingPromise = aPromise;
   11346           0 : }
   11347             : 
   11348             : static void
   11349             : DispatchPointerLockChange(nsIDocument* aTarget)
   11350           0 : {
   11351             :   if (!aTarget) {
   11352           0 :     return;
   11353           0 :   }
   11354             : 
   11355             :   RefPtr<AsyncEventDispatcher> asyncDispatcher =
   11356             :     new AsyncEventDispatcher(aTarget,
   11357             :                              NS_LITERAL_STRING("pointerlockchange"),
   11358           0 :                              true,
   11359             :                              false);
   11360           0 :   asyncDispatcher->PostDOMEvent();
   11361           0 : }
   11362           0 : 
   11363           0 : static void
   11364             : DispatchPointerLockError(nsIDocument* aTarget, const char* aMessage)
   11365           0 : {
   11366             :   if (!aTarget) {
   11367             :     return;
   11368           0 :   }
   11369             : 
   11370             :   RefPtr<AsyncEventDispatcher> asyncDispatcher =
   11371           0 :     new AsyncEventDispatcher(aTarget,
   11372           0 :                              NS_LITERAL_STRING("pointerlockerror"),
   11373           0 :                              true,
   11374           0 :                              false);
   11375           0 :   asyncDispatcher->PostDOMEvent();
   11376           0 :   nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
   11377             :                                   NS_LITERAL_CSTRING("DOM"), aTarget,
   11378             :                                   nsContentUtils::eDOM_PROPERTIES,
   11379             :                                   aMessage);
   11380             : }
   11381             : 
   11382             : class PointerLockRequest final : public Runnable
   11383             : {
   11384             : public:
   11385             :   PointerLockRequest(Element* aElement, bool aUserInputOrChromeCaller)
   11386             :     : mozilla::Runnable("PointerLockRequest")
   11387           0 :     , mElement(do_GetWeakReference(aElement))
   11388             :     , mDocument(do_GetWeakReference(aElement->OwnerDoc()))
   11389             :     , mUserInputOrChromeCaller(aUserInputOrChromeCaller)
   11390             :   {}
   11391           0 : 
   11392             :   NS_IMETHOD Run() final;
   11393             : 
   11394             : private:
   11395           0 :   nsWeakPtr mElement;
   11396           0 :   nsWeakPtr mDocument;
   11397             :   bool mUserInputOrChromeCaller;
   11398             : };
   11399             : 
   11400           0 : static const char*
   11401             : GetPointerLockError(Element* aElement, Element* aCurrentLock,
   11402             :                     bool aNoFocusCheck = false)
   11403             : {
   11404           0 :   // Check if pointer lock pref is enabled
   11405             :   if (!Preferences::GetBool("full-screen-api.pointer-lock.enabled")) {
   11406             :     return "PointerLockDeniedDisabled";
   11407             :   }
   11408             : 
   11409           0 :   nsCOMPtr<nsIDocument> ownerDoc = aElement->OwnerDoc();
   11410             :   if (aCurrentLock && aCurrentLock->OwnerDoc() != ownerDoc) {
   11411             :     return "PointerLockDeniedInUse";
   11412           0 :   }
   11413           0 : 
   11414             :   if (!aElement->IsInComposedDoc()) {
   11415             :     return "PointerLockDeniedNotInDocument";
   11416           0 :   }
   11417           0 : 
   11418             :   if (ownerDoc->GetSandboxFlags() & SANDBOXED_POINTER_LOCK) {
   11419             :     return "PointerLockDeniedSandboxed";
   11420           0 :   }
   11421             : 
   11422             :   // Check if the element is in a document with a docshell.
   11423             :   if (!ownerDoc->GetContainer()) {
   11424           0 :     return "PointerLockDeniedHidden";
   11425           0 :   }
   11426             :   nsCOMPtr<nsPIDOMWindowOuter> ownerWindow = ownerDoc->GetWindow();
   11427             :   if (!ownerWindow) {
   11428             :     return "PointerLockDeniedHidden";
   11429           0 :   }
   11430           0 :   nsCOMPtr<nsPIDOMWindowInner> ownerInnerWindow = ownerDoc->GetInnerWindow();
   11431           0 :   if (!ownerInnerWindow) {
   11432           0 :     return "PointerLockDeniedHidden";
   11433             :   }
   11434             :   if (ownerWindow->GetCurrentInnerWindow() != ownerInnerWindow) {
   11435             :     return "PointerLockDeniedHidden";
   11436             :   }
   11437             : 
   11438             :   nsCOMPtr<nsPIDOMWindowOuter> top = ownerWindow->GetScriptableTop();
   11439             :   if (!top || !top->GetExtantDoc() || top->GetExtantDoc()->Hidden()) {
   11440           0 :     return "PointerLockDeniedHidden";
   11441             :   }
   11442             : 
   11443             :   if (!aNoFocusCheck) {
   11444             :     mozilla::ErrorResult rv;
   11445             :     if (!top->GetExtantDoc()->HasFocus(rv)) {
   11446             :       return "PointerLockDeniedNotFocused";
   11447             :     }
   11448           0 :   }
   11449           0 : 
   11450           0 :   return nullptr;
   11451           0 : }
   11452           0 : 
   11453             : static void
   11454           0 : ChangePointerLockedElement(Element* aElement, nsIDocument* aDocument,
   11455           0 :                            Element* aPointerLockedElement)
   11456           0 : {
   11457           0 :   // aDocument here is not really necessary, as it is the uncomposed
   11458           0 :   // document of both aElement and aPointerLockedElement as far as one
   11459           0 :   // is not nullptr, and they wouldn't both be nullptr in any case.
   11460             :   // But since the caller of this function should have known what the
   11461             :   // document is, we just don't try to figure out what it should be.
   11462             :   MOZ_ASSERT(aDocument);
   11463           0 :   MOZ_ASSERT(aElement != aPointerLockedElement);
   11464           0 :   if (aPointerLockedElement) {
   11465             :     MOZ_ASSERT(aPointerLockedElement->GetComposedDoc() == aDocument);
   11466             :     aPointerLockedElement->ClearPointerLock();
   11467             :   }
   11468           0 :   if (aElement) {
   11469           0 :     MOZ_ASSERT(aElement->GetComposedDoc() == aDocument);
   11470           0 :     aElement->SetPointerLock();
   11471             :     EventStateManager::sPointerLockedElement = do_GetWeakReference(aElement);
   11472             :     EventStateManager::sPointerLockedDoc = do_GetWeakReference(aDocument);
   11473           0 :     NS_ASSERTION(EventStateManager::sPointerLockedElement &&
   11474             :                  EventStateManager::sPointerLockedDoc,
   11475           0 :                  "aElement and this should support weak references!");
   11476           0 :   } else {
   11477           0 :     EventStateManager::sPointerLockedElement = nullptr;
   11478           0 :     EventStateManager::sPointerLockedDoc = nullptr;
   11479           0 :   }
   11480             :   // Retarget all events to aElement via capture or
   11481           0 :   // stop retargeting if aElement is nullptr.
   11482           0 :   nsIPresShell::SetCapturingContent(aElement, CAPTURE_POINTERLOCK);
   11483             :   DispatchPointerLockChange(aDocument);
   11484           0 : }
   11485             : 
   11486           0 : NS_IMETHODIMP
   11487           0 : PointerLockRequest::Run()
   11488           0 : {
   11489           0 :   nsCOMPtr<Element> e = do_QueryReferent(mElement);
   11490             :   nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
   11491             :   nsDocument* d = static_cast<nsDocument*>(doc.get());
   11492           0 :   const char* error = nullptr;
   11493             :   if (!e || !d || !e->GetComposedDoc()) {
   11494             :     error = "PointerLockDeniedNotInDocument";
   11495           0 :   } else if (e->GetComposedDoc() != d) {
   11496           0 :     error = "PointerLockDeniedMovedDocument";
   11497           0 :   }
   11498             :   if (!error) {
   11499             :     nsCOMPtr<Element> pointerLockedElement =
   11500             :       do_QueryReferent(EventStateManager::sPointerLockedElement);
   11501             :     if (e == pointerLockedElement) {
   11502           0 :       DispatchPointerLockChange(d);
   11503           0 :       return NS_OK;
   11504             :     }
   11505           0 :     // Note, we must bypass focus change, so pass true as the last parameter!
   11506           0 :     error = GetPointerLockError(e, pointerLockedElement, true);
   11507             :     // Another element in the same document is requesting pointer lock,
   11508           0 :     // just grant it without user input check.
   11509           0 :     if (!error && pointerLockedElement) {
   11510           0 :       ChangePointerLockedElement(e, d, pointerLockedElement);
   11511             :       return NS_OK;
   11512             :     }
   11513           0 :   }
   11514           0 :   // If it is neither user input initiated, nor requested in fullscreen,
   11515           0 :   // it should be rejected.
   11516           0 :   if (!error && !mUserInputOrChromeCaller && !doc->GetFullscreenElement()) {
   11517           0 :     error = "PointerLockDeniedNotInputDriven";
   11518             :   }
   11519             :   if (!error && !d->SetPointerLock(e, NS_STYLE_CURSOR_NONE)) {
   11520             :     error = "PointerLockDeniedFailedToLock";
   11521           0 :   }
   11522             :   if (error) {
   11523           0 :     DispatchPointerLockError(d, error);
   11524             :     return NS_OK;
   11525             :   }
   11526             : 
   11527           0 :   ChangePointerLockedElement(e, d, nullptr);
   11528           0 :   nsContentUtils::DispatchEventOnlyToChrome(
   11529           0 :     doc, ToSupports(e), NS_LITERAL_STRING("MozDOMPointerLock:Entered"),
   11530           0 :     /* Bubbles */ true, /* Cancelable */ false, /* DefaultAction */ nullptr);
   11531             :   return NS_OK;
   11532             : }
   11533           0 : 
   11534           0 : void
   11535           0 : nsIDocument::RequestPointerLock(Element* aElement, CallerType aCallerType)
   11536             : {
   11537             :   NS_ASSERTION(aElement,
   11538           0 :     "Must pass non-null element to nsDocument::RequestPointerLock");
   11539           0 : 
   11540             :   nsCOMPtr<Element> pointerLockedElement =
   11541           0 :     do_QueryReferent(EventStateManager::sPointerLockedElement);
   11542           0 :   if (aElement == pointerLockedElement) {
   11543             :     DispatchPointerLockChange(this);
   11544             :     return;
   11545             :   }
   11546           0 : 
   11547             :   if (const char* msg = GetPointerLockError(aElement, pointerLockedElement)) {
   11548           0 :     DispatchPointerLockError(this, msg);
   11549             :     return;
   11550             :   }
   11551             : 
   11552           0 :   bool userInputOrSystemCaller = EventStateManager::IsHandlingUserInput() ||
   11553             :                                  aCallerType == CallerType::System;
   11554           0 :   nsCOMPtr<nsIRunnable> request =
   11555           0 :     new PointerLockRequest(aElement, userInputOrSystemCaller);
   11556             :   Dispatch(TaskCategory::Other, request.forget());
   11557             : }
   11558             : 
   11559           0 : bool
   11560           0 : nsIDocument::SetPointerLock(Element* aElement, int aCursorStyle)
   11561           0 : {
   11562           0 :   MOZ_ASSERT(!aElement || aElement->OwnerDoc() == this,
   11563             :              "We should be either unlocking pointer (aElement is nullptr), "
   11564             :              "or locking pointer to an element in this document");
   11565             : #ifdef DEBUG
   11566           0 :   if (!aElement) {
   11567           0 :     nsCOMPtr<nsIDocument> pointerLockedDoc =
   11568             :       do_QueryReferent(EventStateManager::sPointerLockedDoc);
   11569             :     MOZ_ASSERT(pointerLockedDoc == this);
   11570             :   }
   11571           0 : #endif
   11572           0 : 
   11573           0 :   nsIPresShell* shell = GetShell();
   11574           0 :   if (!shell) {
   11575             :     NS_WARNING("SetPointerLock(): No PresShell");
   11576             :     if (!aElement) {
   11577           0 :       // If we are unlocking pointer lock, but for some reason the doc
   11578           0 :       // has already detached from the presshell, just ask the event
   11579           0 :       // state manager to release the pointer.
   11580           0 :       EventStateManager::SetPointerLock(nullptr, nullptr);
   11581           0 :       return true;
   11582             :     }
   11583             :     return false;
   11584             :   }
   11585           0 :   nsPresContext* presContext = shell->GetPresContext();
   11586             :   if (!presContext) {
   11587             :     NS_WARNING("SetPointerLock(): Unable to get PresContext");
   11588             :     return false;
   11589             :   }
   11590             : 
   11591           0 :   nsCOMPtr<nsIWidget> widget;
   11592           0 :   nsIFrame* rootFrame = shell->GetRootFrame();
   11593           0 :   if (!NS_WARN_IF(!rootFrame)) {
   11594           0 :     widget = rootFrame->GetNearestWidget();
   11595             :     NS_WARNING_ASSERTION(
   11596             :       widget,
   11597             :       "SetPointerLock(): Unable to find widget in "
   11598             :       "shell->GetRootFrame()->GetNearestWidget();");
   11599             :     if (aElement && !widget) {
   11600           8 :       return false;
   11601             :     }
   11602           8 :   }
   11603           8 : 
   11604             :   // Hide the cursor and set pointer lock for future mouse events
   11605             :   RefPtr<EventStateManager> esm = presContext->EventStateManager();
   11606             :   esm->SetCursor(aCursorStyle, nullptr, false,
   11607           0 :                  0.0f, 0.0f, widget, true);
   11608           0 :   EventStateManager::SetPointerLock(widget, aElement);
   11609           0 : 
   11610             :   return true;
   11611           0 : }
   11612             : 
   11613             : void
   11614             : nsIDocument::UnlockPointer(nsIDocument* aDoc)
   11615             : {
   11616           0 :   if (!EventStateManager::sIsPointerLocked) {
   11617           0 :     return;
   11618             :   }
   11619             : 
   11620             :   nsCOMPtr<nsIDocument> pointerLockedDoc =
   11621           0 :     do_QueryReferent(EventStateManager::sPointerLockedDoc);
   11622           0 :   if (!pointerLockedDoc || (aDoc && aDoc != pointerLockedDoc)) {
   11623           0 :     return;
   11624             :   }
   11625             :   if (!pointerLockedDoc->SetPointerLock(nullptr, NS_STYLE_CURSOR_AUTO)) {
   11626             :     return;
   11627           0 :   }
   11628             : 
   11629          17 :   nsCOMPtr<Element> pointerLockedElement =
   11630          17 :     do_QueryReferent(EventStateManager::sPointerLockedElement);
   11631           0 :   ChangePointerLockedElement(nullptr, pointerLockedDoc, pointerLockedElement);
   11632           8 : 
   11633           0 :   RefPtr<AsyncEventDispatcher> asyncDispatcher =
   11634             :     new AsyncEventDispatcher(pointerLockedElement,
   11635           0 :                              NS_LITERAL_STRING("MozDOMPointerLock:Exited"),
   11636           0 :                              true, true);
   11637             :   asyncDispatcher->RunDOMEventWhenSafe();
   11638             : }
   11639           0 : 
   11640           0 : void
   11641             : nsIDocument::UpdateVisibilityState()
   11642          17 : {
   11643             :   dom::VisibilityState oldState = mVisibilityState;
   11644             :   mVisibilityState = ComputeVisibilityState();
   11645          48 :   if (oldState != mVisibilityState) {
   11646             :     nsContentUtils::DispatchTrustedEvent(this, static_cast<nsIDocument*>(this),
   11647             :                                          NS_LITERAL_STRING("visibilitychange"),
   11648             :                                          /* bubbles = */ true,
   11649             :                                          /* cancelable = */ false);
   11650             :     EnumerateActivityObservers(NotifyActivityChanged, nullptr);
   11651             :   }
   11652             : 
   11653             :   if (mVisibilityState == dom::VisibilityState::Visible) {
   11654          96 :     MaybeActiveMediaComponents();
   11655          48 :   }
   11656             : }
   11657             : 
   11658             : VisibilityState
   11659           0 : nsIDocument::ComputeVisibilityState() const
   11660             : {
   11661             :   // We have to check a few pieces of information here:
   11662             :   // 1)  Are we in bfcache (!IsVisible())?  If so, nothing else matters.
   11663           0 :   // 2)  Do we have an outer window?  If not, we're hidden.  Note that we don't
   11664             :   //     want to use GetWindow here because it does weird groveling for windows
   11665             :   //     in some cases.
   11666           0 :   // 3)  Is our outer window background?  If so, we're hidden.
   11667             :   // Otherwise, we're visible.
   11668           0 :   if (!IsVisible() || !mWindow || !mWindow->GetOuterWindow() ||
   11669           0 :       mWindow->GetOuterWindow()->IsBackground()) {
   11670           0 :     return dom::VisibilityState::Hidden;
   11671             :   }
   11672             : 
   11673           0 :   return dom::VisibilityState::Visible;
   11674             : }
   11675           9 : 
   11676             : void
   11677             : nsIDocument::PostVisibilityUpdateEvent()
   11678             : {
   11679           0 :   nsCOMPtr<nsIRunnable> event =
   11680             :     NewRunnableMethod("nsIDocument::UpdateVisibilityState",
   11681             :                       this,
   11682             :                       &nsIDocument::UpdateVisibilityState);
   11683           0 :   Dispatch(TaskCategory::Other, event.forget());
   11684             : }
   11685          13 : 
   11686             : void
   11687           0 : nsIDocument::MaybeActiveMediaComponents()
   11688          13 : {
   11689             :   if (!mWindow) {
   11690             :     return;
   11691           0 :   }
   11692           0 : 
   11693             :   GetWindow()->MaybeActiveMediaComponents();
   11694          13 : }
   11695           0 : 
   11696             : /* virtual */ void
   11697             : nsIDocument::DocAddSizeOfExcludingThis(nsWindowSizes& aSizes) const
   11698           0 : {
   11699           0 :   nsINode::AddSizeOfExcludingThis(aSizes, &aSizes.mDOMOtherSize);
   11700             : 
   11701             :   if (mPresShell) {
   11702             :     mPresShell->AddSizeOfIncludingThis(aSizes);
   11703             :   }
   11704             : 
   11705          13 :   aSizes.mPropertyTablesSize +=
   11706             :     mPropertyTable.SizeOfExcludingThis(aSizes.mState.mMallocSizeOf);
   11707             : 
   11708          13 :   if (EventListenerManager* elm = GetExistingListenerManager()) {
   11709             :     aSizes.mDOMEventListenersCount += elm->ListenerCount();
   11710          13 :   }
   11711          13 : 
   11712           0 :   if (mNodeInfoManager) {
   11713             :     mNodeInfoManager->AddSizeOfIncludingThis(aSizes);
   11714             :   }
   11715           0 : 
   11716             :   // Measurement of the following members may be added later if DMD finds it
   11717             :   // is worthwhile:
   11718          52 :   // - many!
   11719           0 : }
   11720         156 : 
   11721           0 : void
   11722             : nsIDocument::DocAddSizeOfIncludingThis(nsWindowSizes& aWindowSizes) const
   11723             : {
   11724             :   aWindowSizes.mDOMOtherSize += aWindowSizes.mState.mMallocSizeOf(this);
   11725           0 :   DocAddSizeOfExcludingThis(aWindowSizes);
   11726             : }
   11727          52 : 
   11728             : static size_t
   11729             : SizeOfOwnedSheetArrayExcludingThis(const nsTArray<RefPtr<StyleSheet>>& aSheets,
   11730             :                                    MallocSizeOf aMallocSizeOf)
   11731           0 : {
   11732             :   size_t n = 0;
   11733             :   n += aSheets.ShallowSizeOfExcludingThis(aMallocSizeOf);
   11734             :   for (StyleSheet* sheet : aSheets) {
   11735             :     if (!sheet->GetAssociatedDocumentOrShadowRoot()) {
   11736             :       // Avoid over-reporting shared sheets.
   11737             :       continue;
   11738           0 :     }
   11739             :     n += sheet->SizeOfIncludingThis(aMallocSizeOf);
   11740             :   }
   11741             :   return n;
   11742           1 : }
   11743             : 
   11744          82 : void
   11745          82 : nsDocument::AddSizeOfExcludingThis(nsWindowSizes& aSizes,
   11746             :                                    size_t* aNodeSize) const
   11747             : {
   11748             :   // This AddSizeOfExcludingThis() overrides the one from nsINode.  But
   11749           0 :   // nsDocuments can only appear at the top of the DOM tree, and we use the
   11750             :   // specialized DocAddSizeOfExcludingThis() in that case.  So this should never
   11751          41 :   // be called.
   11752          41 :   MOZ_CRASH();
   11753             : }
   11754          28 : 
   11755           0 : static void
   11756             : AddSizeOfNodeTree(nsIContent* aNode, nsWindowSizes& aWindowSizes)
   11757           0 : {
   11758           0 :   size_t nodeSize = 0;
   11759             :   aNode->AddSizeOfIncludingThis(aWindowSizes, &nodeSize);
   11760          13 : 
   11761           0 :   // This is where we transfer the nodeSize obtained from
   11762             :   // nsINode::AddSizeOfIncludingThis() to a value in nsWindowSizes.
   11763           0 :   switch (aNode->NodeType()) {
   11764           0 :   case nsINode::ELEMENT_NODE:
   11765             :     aWindowSizes.mDOMElementNodesSize += nodeSize;
   11766             :     break;
   11767           0 :   case nsINode::TEXT_NODE:
   11768           0 :     aWindowSizes.mDOMTextNodesSize += nodeSize;
   11769             :     break;
   11770             :   case nsINode::CDATA_SECTION_NODE:
   11771           0 :     aWindowSizes.mDOMCDATANodesSize += nodeSize;
   11772           0 :     break;
   11773          56 :   case nsINode::COMMENT_NODE:
   11774             :     aWindowSizes.mDOMCommentNodesSize += nodeSize;
   11775           0 :     break;
   11776             :   default:
   11777             :     aWindowSizes.mDOMOtherSize += nodeSize;
   11778          13 :     break;
   11779             :   }
   11780             : 
   11781             :   if (EventListenerManager* elm = aNode->GetExistingListenerManager()) {
   11782             :     aWindowSizes.mDOMEventListenersCount += elm->ListenerCount();
   11783             :   }
   11784             : 
   11785             :   AllChildrenIterator iter(aNode, nsIContent::eAllChildren);
   11786             :   for (nsIContent* n = iter.GetNextChild(); n; n = iter.GetNextChild()) {
   11787          39 :     AddSizeOfNodeTree(n, aWindowSizes);
   11788          39 :   }
   11789          26 : }
   11790          26 : 
   11791             : void
   11792             : nsDocument::DocAddSizeOfExcludingThis(nsWindowSizes& aWindowSizes) const
   11793             : {
   11794             :   // We use AllChildrenIterator to iterate over DOM nodes in
   11795             :   // AddSizeOfNodeTree(). The obvious place to start is at the document's root
   11796             :   // element, using GetRootElement(). However, that will miss comment nodes
   11797             :   // that are siblings of the root element. Instead we use
   11798             :   // GetFirstChild()/GetNextSibling() to traverse the document's immediate
   11799             :   // child nodes, calling AddSizeOfNodeTree() on each to measure them and then
   11800          13 :   // all their descendants. (The comment nodes won't have any descendants).
   11801             :   for (nsIContent* node = nsINode::GetFirstChild();
   11802          13 :        node;
   11803          13 :        node = node->GetNextSibling()) {
   11804           0 :     AddSizeOfNodeTree(node, aWindowSizes);
   11805             :   }
   11806             : 
   11807           0 :   // IMPORTANT: for our ComputedValues measurements, we want to measure
   11808           0 :   // ComputedValues accessible from DOM elements before ComputedValues not
   11809          26 :   // accessible from DOM elements (i.e. accessible only from the frame tree).
   11810          52 :   //
   11811           0 :   // Therefore, the measurement of the nsIDocument superclass must happen after
   11812           0 :   // the measurement of DOM nodes (above), because nsIDocument contains the
   11813           0 :   // PresShell, which contains the frame tree.
   11814             :   nsIDocument::DocAddSizeOfExcludingThis(aWindowSizes);
   11815             : 
   11816             :   aWindowSizes.mLayoutStyleSheetsSize +=
   11817             :     SizeOfOwnedSheetArrayExcludingThis(mStyleSheets,
   11818          13 :                                        aWindowSizes.mState.mMallocSizeOf);
   11819          26 :   // Note that we do not own the sheets pointed to by mOnDemandBuiltInUASheets
   11820             :   // (the nsLayoutStyleSheetCache singleton does).
   11821          13 :   aWindowSizes.mLayoutStyleSheetsSize +=
   11822           0 :     mOnDemandBuiltInUASheets.ShallowSizeOfExcludingThis(
   11823           0 :       aWindowSizes.mState.mMallocSizeOf);
   11824          39 :   for (auto& sheetArray : mAdditionalSheets) {
   11825             :     aWindowSizes.mLayoutStyleSheetsSize +=
   11826           0 :       SizeOfOwnedSheetArrayExcludingThis(sheetArray,
   11827           0 :                                          aWindowSizes.mState.mMallocSizeOf);
   11828             :   }
   11829          13 :   // Lumping in the loader with the style-sheets size is not ideal,
   11830           0 :   // but most of the things in there are in fact stylesheets, so it
   11831             :   // doesn't seem worthwhile to separate it out.
   11832             :   aWindowSizes.mLayoutStyleSheetsSize +=
   11833             :     CSSLoader()->SizeOfIncludingThis(aWindowSizes.mState.mMallocSizeOf);
   11834             : 
   11835          13 :   aWindowSizes.mDOMOtherSize += mAttrStyleSheet
   11836             :                               ? mAttrStyleSheet->DOMSizeOfIncludingThis(
   11837             :                                   aWindowSizes.mState.mMallocSizeOf)
   11838           0 :                               : 0;
   11839             : 
   11840             :   aWindowSizes.mDOMOtherSize +=
   11841           0 :     mStyledLinks.ShallowSizeOfExcludingThis(aWindowSizes.mState.mMallocSizeOf);
   11842           0 : 
   11843           0 :   aWindowSizes.mDOMOtherSize +=
   11844             :     mIdentifierMap.SizeOfExcludingThis(aWindowSizes.mState.mMallocSizeOf);
   11845             : 
   11846             :   // Measurement of the following members may be added later if DMD finds it
   11847           0 :   // is worthwhile:
   11848           0 :   // - many!
   11849           0 : }
   11850             : 
   11851             : already_AddRefed<nsIDocument>
   11852             : nsIDocument::Constructor(const GlobalObject& aGlobal,
   11853           0 :                          ErrorResult& rv)
   11854           0 : {
   11855           0 :   nsCOMPtr<nsIScriptGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
   11856           0 :   if (!global) {
   11857             :     rv.Throw(NS_ERROR_UNEXPECTED);
   11858             :     return nullptr;
   11859             :   }
   11860           0 : 
   11861             :   nsCOMPtr<nsIScriptObjectPrincipal> prin = do_QueryInterface(aGlobal.GetAsSupports());
   11862           0 :   if (!prin) {
   11863           0 :     rv.Throw(NS_ERROR_UNEXPECTED);
   11864           0 :     return nullptr;
   11865             :   }
   11866             : 
   11867             :   nsCOMPtr<nsIURI> uri;
   11868           0 :   NS_NewURI(getter_AddRefs(uri), "about:blank");
   11869             :   if (!uri) {
   11870             :     rv.Throw(NS_ERROR_OUT_OF_MEMORY);
   11871           0 :     return nullptr;
   11872           0 :   }
   11873           0 : 
   11874             :   nsCOMPtr<nsIDocument> doc;
   11875             :   nsresult res =
   11876             :     NS_NewDOMDocument(getter_AddRefs(doc),
   11877           0 :                       VoidString(),
   11878             :                       EmptyString(),
   11879           0 :                       nullptr,
   11880             :                       uri,
   11881             :                       uri,
   11882             :                       prin->GetPrincipal(),
   11883           0 :                       true,
   11884             :                       global,
   11885             :                       DocumentFlavorPlain);
   11886             :   if (NS_FAILED(res)) {
   11887           0 :     rv.Throw(res);
   11888             :     return nullptr;
   11889             :   }
   11890             : 
   11891           0 :   doc->SetReadyStateInternal(nsIDocument::READYSTATE_COMPLETE);
   11892             : 
   11893           0 :   return doc.forget();
   11894             : }
   11895             : 
   11896             : XPathExpression*
   11897           0 : nsIDocument::CreateExpression(const nsAString& aExpression,
   11898             :                               XPathNSResolver* aResolver,
   11899             :                               ErrorResult& rv)
   11900             : {
   11901             :   return XPathEvaluator()->CreateExpression(aExpression, aResolver, rv);
   11902             : }
   11903           0 : 
   11904             : nsINode*
   11905             : nsIDocument::CreateNSResolver(nsINode& aNodeResolver)
   11906             : {
   11907           0 :   return XPathEvaluator()->CreateNSResolver(aNodeResolver);
   11908             : }
   11909         104 : 
   11910          52 : already_AddRefed<XPathResult>
   11911             : nsIDocument::Evaluate(JSContext* aCx, const nsAString& aExpression,
   11912             :                       nsINode& aContextNode, XPathNSResolver* aResolver,
   11913           0 :                       uint16_t aType, JS::Handle<JSObject*> aResult,
   11914           0 :                       ErrorResult& rv)
   11915          21 : {
   11916           7 :   return XPathEvaluator()->Evaluate(aCx, aExpression, aContextNode, aResolver,
   11917             :                                     aType, aResult, rv);
   11918             : }
   11919           0 : 
   11920           0 : already_AddRefed<nsIXULWindow>
   11921           6 : nsIDocument::GetXULWindowIfToplevelChrome() const
   11922             : {
   11923             :   nsCOMPtr<nsIDocShellTreeItem> item = GetDocShell();
   11924           0 :   if (!item) {
   11925             :     return nullptr;
   11926             :   }
   11927             :   nsCOMPtr<nsIDocShellTreeOwner> owner;
   11928           0 :   item->GetTreeOwner(getter_AddRefs(owner));
   11929             :   nsCOMPtr<nsIXULWindow> xulWin = do_GetInterface(owner);
   11930             :   if (!xulWin) {
   11931             :     return nullptr;
   11932           0 :   }
   11933             :   nsCOMPtr<nsIDocShell> xulWinShell;
   11934             :   xulWin->GetDocShell(getter_AddRefs(xulWinShell));
   11935           0 :   if (!SameCOMIdentity(xulWinShell, item)) {
   11936           0 :     return nullptr;
   11937           0 :   }
   11938             :   return xulWin.forget();
   11939             : }
   11940           0 : 
   11941           0 : nsIDocument*
   11942             : nsIDocument::GetTopLevelContentDocument()
   11943             : {
   11944             :   nsIDocument* parent;
   11945             : 
   11946             :   if (!mLoadedAsData) {
   11947           0 :     parent = this;
   11948             :   } else {
   11949             :     nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(GetScopeObject());
   11950             :     if (!window) {
   11951             :       return nullptr;
   11952             :     }
   11953           0 : 
   11954             :     parent = window->GetExtantDoc();
   11955             :     if (!parent) {
   11956             :       return nullptr;
   11957           0 :     }
   11958           0 :   }
   11959           0 : 
   11960             :   do {
   11961             :     if (parent->IsTopLevelContentDocument()) {
   11962             :       break;
   11963             :     }
   11964             : 
   11965          14 :     // If we ever have a non-content parent before we hit a toplevel content
   11966             :     // parent, then we're never going to find one.  Just bail.
   11967          14 :     if (!parent->IsContentDocument()) {
   11968          14 :       return nullptr;
   11969           0 :     }
   11970          14 : 
   11971             :     nsIDocument* candidate = parent->GetParentDocument();
   11972             :     parent = static_cast<nsDocument*>(candidate);
   11973             :   } while (parent);
   11974           0 : 
   11975             :   return parent;
   11976           0 : }
   11977           0 : 
   11978           0 : static bool
   11979           0 : MightBeChromeScheme(nsIURI* aURI)
   11980             : {
   11981             :   MOZ_ASSERT(aURI);
   11982             :   bool isChrome = true;
   11983           0 :   aURI->SchemeIs("chrome", &isChrome);
   11984             :   return isChrome;
   11985          14 : }
   11986             : 
   11987             : static bool
   11988          14 : MightBeAboutOrChromeScheme(nsIURI* aURI)
   11989           0 : {
   11990          28 :   MOZ_ASSERT(aURI);
   11991          14 :   bool isAbout = true;
   11992             :   aURI->SchemeIs("about", &isAbout);
   11993             :   return isAbout || MightBeChromeScheme(aURI);
   11994             : }
   11995             : 
   11996             : void
   11997             : nsIDocument::PropagateUseCounters(nsIDocument* aParentDocument)
   11998             : {
   11999           0 :   MOZ_ASSERT(this != aParentDocument);
   12000             : 
   12001           0 :   // Don't count chrome resources, even in the web content.
   12002             :   nsCOMPtr<nsIURI> uri;
   12003             :   NodePrincipal()->GetURI(getter_AddRefs(uri));
   12004             :   if (!uri || MightBeChromeScheme(uri)) {
   12005           0 :     return;
   12006           0 :   }
   12007             : 
   12008             :   // What really matters here is that our use counters get propagated as
   12009             :   // high up in the content document hierarchy as possible.  So,
   12010           0 :   // starting with aParentDocument, we need to find the toplevel content
   12011             :   // document, and propagate our use counters into its
   12012             :   // mChildDocumentUseCounters.
   12013             :   nsIDocument* contentParent = aParentDocument->GetTopLevelContentDocument();
   12014             : 
   12015             :   if (!contentParent) {
   12016          56 :     return;
   12017             :   }
   12018             : 
   12019          52 :   contentParent->mChildDocumentUseCounters |= mUseCounters;
   12020             :   contentParent->mChildDocumentUseCounters |= mChildDocumentUseCounters;
   12021          52 : }
   12022             : 
   12023             : void
   12024             : nsIDocument::SetPageUseCounter(UseCounter aUseCounter)
   12025           0 : {
   12026           0 :   // We want to set the use counter on the "page" that owns us; the definition
   12027           0 :   // of "page" depends on what kind of document we are.  See the comments below
   12028             :   // for details.  In any event, checking all the conditions below is
   12029             :   // reasonably expensive, so we cache whether we've notified our owning page.
   12030           0 :   if (mNotifiedPageForUseCounter[aUseCounter]) {
   12031             :     return;
   12032          26 :   }
   12033             :   mNotifiedPageForUseCounter[aUseCounter] = true;
   12034             : 
   12035             :   if (mDisplayDocument) {
   12036             :     // If we are a resource document, we won't have a docshell and so we won't
   12037             :     // record any page use counters on this document.  Instead, we should
   12038             :     // forward it up to the document that loaded us.
   12039           0 :     MOZ_ASSERT(!mDocumentContainer);
   12040           0 :     mDisplayDocument->SetChildDocumentUseCounter(aUseCounter);
   12041             :     return;
   12042             :   }
   12043             : 
   12044           0 :   if (IsBeingUsedAsImage()) {
   12045           0 :     // If this is an SVG image document, we also won't have a docshell.
   12046             :     MOZ_ASSERT(!mDocumentContainer);
   12047             :     return;
   12048             :   }
   12049           0 : 
   12050             :   // We only care about use counters in content.  If we're already a toplevel
   12051             :   // content document, then we should have already set the use counter on
   12052             :   // ourselves, and we are done.
   12053           0 :   nsIDocument* contentParent = GetTopLevelContentDocument();
   12054             :   if (!contentParent) {
   12055         609 :     return;
   12056             :   }
   12057             : 
   12058             :   if (this == contentParent) {
   12059           0 :     MOZ_ASSERT(GetUseCounter(aUseCounter));
   12060             :     return;
   12061             :   }
   12062             : 
   12063           0 :   contentParent->SetChildDocumentUseCounter(aUseCounter);
   12064           0 : }
   12065           0 : 
   12066           0 : bool
   12067           0 : nsIDocument::HasScriptsBlockedBySandbox()
   12068           0 : {
   12069           0 :   return mSandboxFlags & SANDBOXED_SCRIPTS;
   12070             : }
   12071             : 
   12072             : bool
   12073           0 : nsIDocument::InlineScriptAllowedByCSP()
   12074           0 : {
   12075             :   // this function assumes the inline script is parser created
   12076           0 :   //  (e.g., before setting attribute(!) event handlers)
   12077             :   nsCOMPtr<nsIContentSecurityPolicy> csp;
   12078             :   nsresult rv = NodePrincipal()->GetCsp(getter_AddRefs(csp));
   12079             :   NS_ENSURE_SUCCESS(rv, true);
   12080           0 :   bool allowsInlineScript = true;
   12081             :   if (csp) {
   12082             :     nsresult rv = csp->GetAllowsInline(nsIContentPolicy::TYPE_SCRIPT,
   12083           0 :                                        EmptyString(), // aNonce
   12084           0 :                                        true,          // aParserCreated
   12085           0 :                                        nullptr, // FIXME get script sample (bug 1314567)
   12086             :                                        0,             // aLineNumber
   12087             :                                        &allowsInlineScript);
   12088             :     NS_ENSURE_SUCCESS(rv, true);
   12089           0 :   }
   12090             :   return allowsInlineScript;
   12091             : }
   12092           0 : 
   12093             : static bool
   12094             : ReportExternalResourceUseCounters(nsIDocument* aDocument, void* aData)
   12095             : {
   12096           0 :   const auto reportKind
   12097             :     = nsDocument::UseCounterReportKind::eIncludeExternalResources;
   12098           0 :   static_cast<nsDocument*>(aDocument)->ReportUseCounters(reportKind);
   12099             :   return true;
   12100             : }
   12101             : 
   12102           0 : void
   12103           0 : nsIDocument::ReportUseCounters(UseCounterReportKind aKind)
   12104           0 : {
   12105           0 :   static const bool sDebugUseCounters = false;
   12106           0 :   if (mReportedUseCounters) {
   12107           0 :     return;
   12108             :   }
   12109             : 
   12110             :   mReportedUseCounters = true;
   12111             : 
   12112             :   if (aKind == UseCounterReportKind::eIncludeExternalResources) {
   12113             :     EnumerateExternalResources(ReportExternalResourceUseCounters, nullptr);
   12114             :   }
   12115             : 
   12116             :   if (Telemetry::HistogramUseCounterCount > 0 &&
   12117             :       (IsContentDocument() || IsResourceDoc())) {
   12118             :     nsCOMPtr<nsIURI> uri;
   12119             :     NodePrincipal()->GetURI(getter_AddRefs(uri));
   12120             :     if (!uri || MightBeAboutOrChromeScheme(uri)) {
   12121             :       return;
   12122             :     }
   12123             : 
   12124             :     if (sDebugUseCounters) {
   12125             :       nsCString spec = uri->GetSpecOrDefault();
   12126             : 
   12127             :       // URIs can be rather long for data documents, so truncate them to
   12128             :       // some reasonable length.
   12129             :       spec.Truncate(std::min(128U, spec.Length()));
   12130             :       printf("-- Use counters for %s --\n", spec.get());
   12131             :     }
   12132             : 
   12133             :     // We keep separate counts for individual documents and top-level
   12134             :     // pages to more accurately track how many web pages might break if
   12135             :     // certain features were removed.  Consider the case of a single
   12136             :     // HTML document with several SVG images and/or iframes with
   12137             :     // sub-documents of their own.  If we maintained a single set of use
   12138             :     // counters and all the sub-documents use a particular feature, then
   12139             :     // telemetry would indicate that we would be breaking N documents if
   12140             :     // that feature were removed.  Whereas with a document/top-level
   12141             :     // page split, we can see that N documents would be affected, but
   12142           0 :     // only a single web page would be affected.
   12143           0 : 
   12144           0 :     // The difference between the values of these two histograms and the
   12145             :     // related use counters below tell us how many pages did *not* use
   12146             :     // the feature in question.  For instance, if we see that a given
   12147           0 :     // session has destroyed 30 content documents, but a particular use
   12148           0 :     // counter shows only a count of 5, we can infer that the use
   12149           0 :     // counter was *not* used in 25 of those 30 documents.
   12150             :     //
   12151             :     // We do things this way, rather than accumulating a boolean flag
   12152           0 :     // for each use counter, to avoid sending histograms for features
   12153           0 :     // that don't get widely used.  Doing things in this fashion means
   12154             :     // smaller telemetry payloads and faster processing on the server
   12155           0 :     // side.
   12156             :     Telemetry::Accumulate(Telemetry::CONTENT_DOCUMENTS_DESTROYED, 1);
   12157             :     if (IsTopLevelContentDocument()) {
   12158             :       Telemetry::Accumulate(Telemetry::TOP_LEVEL_CONTENT_DOCUMENTS_DESTROYED, 1);
   12159             :     }
   12160             : 
   12161             :     for (int32_t c = 0;
   12162             :          c < eUseCounter_Count; ++c) {
   12163             :       UseCounter uc = static_cast<UseCounter>(c);
   12164             : 
   12165             :       Telemetry::HistogramID id =
   12166           0 :         static_cast<Telemetry::HistogramID>(Telemetry::HistogramFirstUseCounter + uc * 2);
   12167             :       bool value = GetUseCounter(uc);
   12168             : 
   12169           0 :       if (value) {
   12170           0 :         if (sDebugUseCounters) {
   12171             :           const char* name = Telemetry::GetHistogramName(id);
   12172           0 :           if (name) {
   12173             :             printf("  %s", name);
   12174           0 :           } else {
   12175             :             printf("  #%d", id);
   12176             :           }
   12177             :           printf(": %d\n", value);
   12178             :         }
   12179             : 
   12180             :         Telemetry::Accumulate(id, 1);
   12181             :       }
   12182             : 
   12183             :       if (IsTopLevelContentDocument()) {
   12184             :         id = static_cast<Telemetry::HistogramID>(Telemetry::HistogramFirstUseCounter +
   12185           0 :                                                  uc * 2 + 1);
   12186             :         value = GetUseCounter(uc) || GetChildDocumentUseCounter(uc);
   12187             : 
   12188             :         if (value) {
   12189             :           if (sDebugUseCounters) {
   12190             :             const char* name = Telemetry::GetHistogramName(id);
   12191           0 :             if (name) {
   12192             :               printf("  %s", name);
   12193             :             } else {
   12194           0 :               printf("  #%d", id);
   12195             :             }
   12196             :             printf(": %d\n", value);
   12197             :           }
   12198             : 
   12199           0 :           Telemetry::Accumulate(id, 1);
   12200           0 :         }
   12201           0 :       }
   12202           0 :     }
   12203             :   }
   12204             : 
   12205           0 :   if (IsTopLevelContentDocument() && !IsResourceDoc()) {
   12206             :     using mozilla::Telemetry::LABELS_HIDDEN_VIEWPORT_OVERFLOW_TYPE;
   12207             :     LABELS_HIDDEN_VIEWPORT_OVERFLOW_TYPE label;
   12208             :     switch (mViewportOverflowType) {
   12209             : #define CASE_OVERFLOW_TYPE(t_)                            \
   12210           0 :       case ViewportOverflowType::t_:                      \
   12211             :         label = LABELS_HIDDEN_VIEWPORT_OVERFLOW_TYPE::t_; \
   12212           0 :         break;
   12213           0 :       CASE_OVERFLOW_TYPE(NoOverflow)
   12214             :       CASE_OVERFLOW_TYPE(Desktop)
   12215             :       CASE_OVERFLOW_TYPE(ButNotMinScaleSize)
   12216           0 :       CASE_OVERFLOW_TYPE(MinScaleSize)
   12217           0 : #undef CASE_OVERFLOW_TYPE
   12218           0 :     }
   12219           0 :     Telemetry::AccumulateCategorical(label);
   12220           0 :   }
   12221             : }
   12222             : 
   12223           0 : void
   12224           0 : nsIDocument::UpdateIntersectionObservations()
   12225           0 : {
   12226           0 :   if (mIntersectionObservers.IsEmpty()) {
   12227             :     return;
   12228           0 :   }
   12229           0 : 
   12230           0 :   DOMHighResTimeStamp time = 0;
   12231             :   if (nsPIDOMWindowInner* window = GetInnerWindow()) {
   12232             :     Performance* perf = window->GetPerformance();
   12233             :     if (perf) {
   12234             :       time = perf->Now();
   12235             :     }
   12236           0 :   }
   12237             :   nsTArray<RefPtr<DOMIntersectionObserver>> observers(mIntersectionObservers.Count());
   12238           0 :   for (auto iter = mIntersectionObservers.Iter(); !iter.Done(); iter.Next()) {
   12239           0 :     DOMIntersectionObserver* observer = iter.Get()->GetKey();
   12240             :     observers.AppendElement(observer);
   12241           0 :   }
   12242             :   for (const auto& observer : observers) {
   12243           0 :     if (observer) {
   12244             :       observer->Update(this, time);
   12245           0 :     }
   12246           0 :   }
   12247             : }
   12248             : 
   12249             : void
   12250           0 : nsIDocument::ScheduleIntersectionObserverNotification()
   12251             : {
   12252           0 :   if (mIntersectionObservers.IsEmpty()) {
   12253           0 :     return;
   12254           0 :   }
   12255           0 :   MOZ_RELEASE_ASSERT(NS_IsMainThread());
   12256             :   nsCOMPtr<nsIRunnable> notification =
   12257           0 :     NewRunnableMethod("nsDocument::NotifyIntersectionObservers",
   12258           0 :                       this,
   12259           0 :                       &nsDocument::NotifyIntersectionObservers);
   12260             :   Dispatch(TaskCategory::Other, notification.forget());
   12261             : }
   12262           0 : 
   12263             : void
   12264             : nsIDocument::NotifyIntersectionObservers()
   12265           0 : {
   12266             :   nsTArray<RefPtr<DOMIntersectionObserver>> observers(mIntersectionObservers.Count());
   12267           0 :   for (auto iter = mIntersectionObservers.Iter(); !iter.Done(); iter.Next()) {
   12268           0 :     DOMIntersectionObserver* observer = iter.Get()->GetKey();
   12269             :     observers.AppendElement(observer);
   12270             :   }
   12271             :   for (const auto& observer : observers) {
   12272           0 :     if (observer) {
   12273             :       observer->Notify();
   12274           0 :     }
   12275           0 :   }
   12276           0 : }
   12277             : 
   12278             : static bool
   12279           0 : NotifyLayerManagerRecreatedCallback(nsIDocument* aDocument, void* aData)
   12280             : {
   12281           0 :   aDocument->NotifyLayerManagerRecreated();
   12282           0 :   return true;
   12283             : }
   12284           0 : 
   12285             : void
   12286             : nsIDocument::NotifyLayerManagerRecreated()
   12287             : {
   12288           0 :   EnumerateActivityObservers(NotifyActivityChanged, nullptr);
   12289             :   EnumerateSubDocuments(NotifyLayerManagerRecreatedCallback, nullptr);
   12290           0 : }
   12291             : 
   12292             : XPathEvaluator*
   12293             : nsIDocument::XPathEvaluator()
   12294           0 : {
   12295             :   if (!mXPathEvaluator) {
   12296           0 :     mXPathEvaluator.reset(new dom::XPathEvaluator(this));
   12297           0 :   }
   12298             :   return mXPathEvaluator.get();
   12299             : }
   12300           0 : 
   12301             : already_AddRefed<nsIDocumentEncoder>
   12302           0 : nsIDocument::GetCachedEncoder()
   12303         137 : {
   12304           0 :   return mCachedEncoder.forget();
   12305             : }
   12306             : 
   12307         168 : void
   12308           0 : nsIDocument::SetCachedEncoder(already_AddRefed<nsIDocumentEncoder> aEncoder)
   12309         336 : {
   12310         168 :   mCachedEncoder = aEncoder;
   12311             : }
   12312             : 
   12313         618 : void
   12314             : nsIDocument::SetContentTypeInternal(const nsACString& aType)
   12315           0 : {
   12316             :   if (!IsHTMLOrXHTML() && mDefaultElementType == kNameSpaceID_None &&
   12317             :       aType.EqualsLiteral("application/xhtml+xml")) {
   12318             :     mDefaultElementType = kNameSpaceID_XHTML;
   12319           0 :   }
   12320             : 
   12321           0 :   mCachedEncoder = nullptr;
   12322             :   mContentType = aType;
   12323             :   mContentTypeForWriteCalls = aType;
   12324             : }
   12325           2 : 
   12326             : nsILoadContext*
   12327           0 : nsIDocument::GetLoadContext() const
   12328           0 : {
   12329           0 :   return mDocumentContainer;
   12330             : }
   12331             : 
   12332           0 : nsIDocShell*
   12333             : nsIDocument::GetDocShell() const
   12334          36 : {
   12335          36 :   return mDocumentContainer;
   12336           0 : }
   12337          18 : 
   12338             : void
   12339           0 : nsIDocument::SetStateObject(nsIStructuredCloneContainer *scContainer)
   12340           0 : {
   12341           0 :   mStateObjectContainer = scContainer;
   12342           0 :   mStateObjectCached = nullptr;
   12343             : }
   12344          18 : 
   12345           0 : already_AddRefed<Element>
   12346             : nsIDocument::CreateHTMLElement(nsAtom* aTag)
   12347             : {
   12348             :   RefPtr<mozilla::dom::NodeInfo> nodeInfo;
   12349           0 :   nodeInfo = mNodeInfoManager->GetNodeInfo(aTag, nullptr, kNameSpaceID_XHTML,
   12350             :                                            ELEMENT_NODE);
   12351             :   MOZ_ASSERT(nodeInfo, "GetNodeInfo should never fail");
   12352           0 : 
   12353           0 :   nsCOMPtr<Element> element;
   12354           0 :   DebugOnly<nsresult> rv = NS_NewHTMLElement(getter_AddRefs(element),
   12355           0 :                                              nodeInfo.forget(),
   12356           0 :                                              mozilla::dom::NOT_FROM_PARSER);
   12357             : 
   12358           0 :   MOZ_ASSERT(NS_SUCCEEDED(rv), "NS_NewHTMLElement should never fail");
   12359           0 :   return element.forget();
   12360             : }
   12361           0 : 
   12362             : bool
   12363             : MarkDocumentTreeToBeInSyncOperation(nsIDocument* aDoc, void* aData)
   12364           0 : {
   12365             :   nsCOMArray<nsIDocument>* documents =
   12366           0 :     static_cast<nsCOMArray<nsIDocument>*>(aData);
   12367           0 :   if (aDoc) {
   12368           0 :     aDoc->SetIsInSyncOperation(true);
   12369           0 :     if (nsCOMPtr<nsPIDOMWindowInner> window = aDoc->GetInnerWindow()) {
   12370           0 :       window->TimeoutManager().BeginSyncOperation();
   12371             :     }
   12372           0 :     documents->AppendObject(aDoc);
   12373           0 :     aDoc->EnumerateSubDocuments(MarkDocumentTreeToBeInSyncOperation, aData);
   12374           0 :   }
   12375           0 :   return true;
   12376           0 : }
   12377             : 
   12378             : nsAutoSyncOperation::nsAutoSyncOperation(nsIDocument* aDoc)
   12379             : {
   12380           0 :   mMicroTaskLevel = 0;
   12381             :   CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get();
   12382           0 :   if (ccjs) {
   12383             :     mMicroTaskLevel = ccjs->MicroTaskLevel();
   12384           0 :     ccjs->SetMicroTaskLevel(0);
   12385           0 :   }
   12386           0 :   if (aDoc) {
   12387             :     if (nsPIDOMWindowOuter* win = aDoc->GetWindow()) {
   12388           0 :       if (nsCOMPtr<nsPIDOMWindowOuter> top = win->GetTop()) {
   12389             :         nsCOMPtr<nsIDocument> doc = top->GetExtantDoc();
   12390           0 :         MarkDocumentTreeToBeInSyncOperation(doc, &mDocuments);
   12391           0 :       }
   12392           0 :     }
   12393             :   }
   12394           0 : }
   12395             : 
   12396             : nsAutoSyncOperation::~nsAutoSyncOperation()
   12397         710 : {
   12398             :   for (int32_t i = 0; i < mDocuments.Count(); ++i) {
   12399             :     if (nsCOMPtr<nsPIDOMWindowInner> window = mDocuments[i]->GetInnerWindow()) {
   12400             :       window->TimeoutManager().EndSyncOperation();
   12401             :     }
   12402             :     mDocuments[i]->SetIsInSyncOperation(false);
   12403             :   }
   12404             :   CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get();
   12405             :   if (ccjs) {
   12406             :     ccjs->SetMicroTaskLevel(mMicroTaskLevel);
   12407         710 :   }
   12408             : }
   12409             : 
   12410             : gfxUserFontSet*
   12411         710 : nsIDocument::GetUserFontSet(bool aFlushUserFontSet)
   12412         710 : {
   12413             :   // We want to initialize the user font set lazily the first time the
   12414             :   // user asks for it, rather than building it too early and forcing
   12415             :   // rule cascade creation.  Thus we try to enforce the invariant that
   12416             :   // we *never* build the user font set until the first call to
   12417             :   // GetUserFontSet.  However, once it's been requested, we can't wait
   12418             :   // for somebody to call GetUserFontSet in order to rebuild it (see
   12419          29 :   // comments below in MarkUserFontSetDirty for why).
   12420             : #ifdef DEBUG
   12421             :   bool userFontSetGottenBefore = mGetUserFontSetCalled;
   12422             : #endif
   12423           0 :   // Set mGetUserFontSetCalled up front, so that FlushUserFontSet will actually
   12424             :   // flush.
   12425             :   mGetUserFontSetCalled = true;
   12426        1420 :   if (mFontFaceSetDirty && aFlushUserFontSet) {
   12427             :     // If this assertion fails, and there have actually been changes to
   12428             :     // @font-face rules, then we will call StyleChangeReflow in
   12429             :     // FlushUserFontSet.  If we're in the middle of reflow,
   12430           0 :     // that's a bad thing to do, and the caller was responsible for
   12431             :     // flushing first.  If we're not (e.g., in frame construction), it's
   12432             :     // ok.
   12433             :     NS_ASSERTION(!userFontSetGottenBefore ||
   12434         164 :                  !GetShell() ||
   12435             :                  !GetShell()->IsReflowLocked(),
   12436           0 :                  "FlushUserFontSet should have been called first");
   12437             :     FlushUserFontSet();
   12438             :   }
   12439             : 
   12440             :   if (!mFontFaceSet) {
   12441             :     return nullptr;
   12442         152 :   }
   12443             : 
   12444             :   return mFontFaceSet->GetUserFontSet();
   12445             : }
   12446          23 : 
   12447             : void
   12448           0 : nsIDocument::FlushUserFontSet()
   12449           0 : {
   12450           0 :   if (!mGetUserFontSetCalled) {
   12451          46 :     return; // No one cares about this font set yet, but we want to be careful
   12452           0 :             // to not unset our mFontFaceSetDirty bit, so when someone really
   12453             :             // does we'll create it.
   12454             :   }
   12455             : 
   12456          69 :   if (!mFontFaceSetDirty) {
   12457           0 :     return;
   12458           0 :   }
   12459             : 
   12460             :   mFontFaceSetDirty = false;
   12461          23 : 
   12462          46 :   if (gfxPlatform::GetPlatform()->DownloadableFontsEnabled()) {
   12463           0 :     nsTArray<nsFontFaceRuleContainer> rules;
   12464             :     nsIPresShell* shell = GetShell();
   12465             :     if (shell && !shell->StyleSet()->AppendFontFaceRules(rules)) {
   12466             :       return;
   12467             :     }
   12468             : 
   12469             : 
   12470          23 :     if (!mFontFaceSet && !rules.IsEmpty()) {
   12471           0 :       nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(GetScopeObject());
   12472           0 :       mFontFaceSet = new FontFaceSet(window, this);
   12473             :     }
   12474             : 
   12475             :     bool changed = false;
   12476             :     if (mFontFaceSet) {
   12477             :       changed = mFontFaceSet->UpdateRules(rules);
   12478             :     }
   12479           0 : 
   12480             :     // We need to enqueue a style change reflow (for later) to
   12481           0 :     // reflect that we're modifying @font-face rules.  (However,
   12482             :     // without a reflow, nothing will happen to start any downloads
   12483             :     // that are needed.)
   12484             :     if (changed && shell) {
   12485             :       if (nsPresContext* presContext = shell->GetPresContext()) {
   12486             :         presContext->UserFontSetUpdated();
   12487             :       }
   12488          10 :     }
   12489             :   }
   12490             : }
   12491             : 
   12492           0 : void
   12493             : nsIDocument::MarkUserFontSetDirty()
   12494           0 : {
   12495           0 :   if (!mGetUserFontSetCalled) {
   12496           0 :     // We want to lazily build the user font set the first time it's
   12497           0 :     // requested (so we don't force creation of rule cascades too
   12498             :     // early), so don't do anything now.
   12499           0 :     return;
   12500             :   }
   12501             : 
   12502             :   mFontFaceSetDirty = true;
   12503           0 : }
   12504             : 
   12505           0 : FontFaceSet*
   12506             : nsIDocument::Fonts()
   12507             : {
   12508             :   if (!mFontFaceSet) {
   12509           0 :     nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(GetScopeObject());
   12510           0 :     mFontFaceSet = new FontFaceSet(window, this);
   12511           0 :     GetUserFontSet();  // this will cause the user font set to be created/updated
   12512             :   }
   12513           0 :   return mFontFaceSet;
   12514             : }
   12515             : 
   12516             : void
   12517           0 : nsIDocument::ReportHasScrollLinkedEffect()
   12518             : {
   12519           0 :   if (mHasScrollLinkedEffect) {
   12520             :     // We already did this once for this document, don't do it again.
   12521           0 :     return;
   12522           0 :   }
   12523             :   mHasScrollLinkedEffect = true;
   12524             :   nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
   12525           0 :                                   NS_LITERAL_CSTRING("Async Pan/Zoom"),
   12526             :                                   this, nsContentUtils::eLAYOUT_PROPERTIES,
   12527           0 :                                   "ScrollLinkedEffectFound2");
   12528             : }
   12529           0 : 
   12530           0 : void
   12531           0 : nsIDocument::SetUserHasInteracted(bool aUserHasInteracted)
   12532           0 : {
   12533           0 :   MOZ_LOG(gUserInteractionPRLog, LogLevel::Debug,
   12534             :           ("Document %p has been interacted by user.", this));
   12535           0 :   mUserHasInteracted = aUserHasInteracted;
   12536             : }
   12537             : 
   12538           0 : void
   12539             : nsIDocument::NotifyUserActivation()
   12540           0 : {
   12541           0 :   ActivateByUserGesture();
   12542           0 :   // Activate parent document which has same principle on the parent chain.
   12543           0 :   nsCOMPtr<nsIPrincipal> principal = NodePrincipal();
   12544             :   nsCOMPtr<nsIDocument> parent = GetSameTypeParentDocument();
   12545             :   while (parent) {
   12546             :     parent->MaybeActivateByUserGesture(principal);
   12547             :     parent = parent->GetSameTypeParentDocument();
   12548           0 :   }
   12549           0 : }
   12550             : 
   12551             : void
   12552             : nsIDocument::MaybeActivateByUserGesture(nsIPrincipal* aPrincipal)
   12553             : {
   12554           0 :   bool isEqual = false;
   12555             :   nsresult rv = aPrincipal->Equals(NodePrincipal(), &isEqual);
   12556           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   12557             :     return;
   12558             :   }
   12559             : 
   12560           0 :   // If a child frame is actived, it would always activate the top frame and its
   12561             :   // parent frames which has same priciple.
   12562           0 :   if (isEqual || IsTopLevelContentDocument()) {
   12563             :     ActivateByUserGesture();
   12564             :   }
   12565             : }
   12566           0 : 
   12567             : void
   12568           0 : nsIDocument::ActivateByUserGesture()
   12569             : {
   12570             :   if (mUserHasActivatedInteraction) {
   12571             :     return;
   12572           0 :   }
   12573           0 : 
   12574           0 :   MOZ_LOG(gUserInteractionPRLog, LogLevel::Debug,
   12575             :           ("Document %p has been activated by user.", this));
   12576             :   mUserHasActivatedInteraction = true;
   12577             : }
   12578           0 : 
   12579             : bool
   12580             : nsIDocument::HasBeenUserActivated()
   12581             : {
   12582           0 :   if (!mUserHasActivatedInteraction) {
   12583             :     // If one of its parent on the parent chain has been activated and has same
   12584           0 :     // principal, then this child would also be treated as activated.
   12585           0 :     nsIDocument* parent =
   12586           0 :       GetFirstParentDocumentWithSamePrincipal(NodePrincipal());
   12587           0 :     if (parent) {
   12588           0 :       mUserHasActivatedInteraction = parent->HasBeenUserActivated();
   12589           0 :     }
   12590           0 :   }
   12591             : 
   12592             :   return mUserHasActivatedInteraction;
   12593           0 : }
   12594             : 
   12595             : nsIDocument*
   12596           0 : nsIDocument::GetFirstParentDocumentWithSamePrincipal(nsIPrincipal* aPrincipal)
   12597             : {
   12598             :   MOZ_ASSERT(aPrincipal);
   12599             :   nsIDocument* parent = GetSameTypeParentDocument();
   12600             :   while (parent) {
   12601             :     bool isEqual = false;
   12602             :     nsresult rv = aPrincipal->Equals(parent->NodePrincipal(), &isEqual);
   12603           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   12604             :       return nullptr;
   12605           0 :     }
   12606           0 : 
   12607             :     if (isEqual) {
   12608             :       return parent;
   12609             :     }
   12610           0 :     parent = parent->GetSameTypeParentDocument();
   12611           0 :   }
   12612           0 :   MOZ_ASSERT(!parent);
   12613             :   return nullptr;
   12614             : }
   12615             : 
   12616           0 : nsIDocument*
   12617             : nsIDocument::GetSameTypeParentDocument()
   12618             : {
   12619             :   nsCOMPtr<nsIDocShellTreeItem> current = GetDocShell();
   12620             :   if (!current) {
   12621             :     return nullptr;
   12622             :   }
   12623             : 
   12624             :   nsCOMPtr<nsIDocShellTreeItem> parent;
   12625             :   current->GetSameTypeParent(getter_AddRefs(parent));
   12626             :   if (!parent) {
   12627             :     return nullptr;
   12628             :   }
   12629           0 : 
   12630             :   return parent->GetDocument();
   12631           0 : }
   12632           0 : 
   12633           0 : /**
   12634             :  * Retrieves the classification of the Flash plugins in the document based on
   12635             :  * the classification lists. We perform AsyncInitFlashClassification on
   12636             :  * StartDocumentLoad() and the result may not be initialized when this function
   12637             :  * gets called. In that case, We can only unfortunately have a blocking wait.
   12638             :  *
   12639             :  * For more information, see
   12640             :  * toolkit/components/url-classifier/flash-block-lists.rst
   12641             :  */
   12642             : FlashClassification
   12643           0 : nsIDocument::PrincipalFlashClassification()
   12644             : {
   12645             :   MOZ_ASSERT(mPrincipalFlashClassifier);
   12646           0 :   return mPrincipalFlashClassifier->ClassifyMaybeSync(NodePrincipal(),
   12647             :                                                       IsThirdParty());
   12648             : }
   12649           0 : 
   12650           0 : /**
   12651             :  * Helper function for |nsDocument::PrincipalFlashClassification|
   12652           0 :  *
   12653             :  * Adds a table name string to a table list (a comma separated string). The
   12654             :  * table will not be added if the name is an empty string.
   12655             :  */
   12656             : static void
   12657             : MaybeAddTableToTableList(const nsACString& aTableNames,
   12658             :                          nsACString& aTableList)
   12659             : {
   12660             :   if (aTableNames.IsEmpty()) {
   12661             :     return;
   12662             :   }
   12663           0 :   if (!aTableList.IsEmpty()) {
   12664             :     aTableList.AppendLiteral(",");
   12665             :   }
   12666           0 :   aTableList.Append(aTableNames);
   12667             : }
   12668             : 
   12669           0 : /**
   12670           0 :  * Helper function for |nsDocument::PrincipalFlashClassification|
   12671             :  *
   12672             :  * Takes an array of table names and a comma separated list of table names
   12673           0 :  * Returns |true| if any table name in the array matches a table name in the
   12674             :  * comma separated list.
   12675             :  */
   12676             : static bool
   12677             : ArrayContainsTable(const nsTArray<nsCString>& aTableArray,
   12678             :                    const nsACString& aTableNames)
   12679             : {
   12680             :   for (const nsCString& table : aTableArray) {
   12681           0 :     // This check is sufficient because table names cannot contain commas and
   12682           1 :     // cannot contain another existing table name.
   12683           0 :     if (FindInReadable(table, aTableNames)) {
   12684           0 :       return true;
   12685           1 :     }
   12686           0 :   }
   12687             :   return false;
   12688             : }
   12689           0 : 
   12690           0 : namespace {
   12691           0 : 
   12692           0 : // An object to store all preferences we need for flash blocking feature.
   12693           0 : struct PrefStore
   12694           0 : {
   12695             :   PrefStore()
   12696           0 :   {
   12697           1 :     Preferences::AddBoolVarCache(&mFlashBlockEnabled,
   12698             :                                  "plugins.flashBlock.enabled");
   12699           0 :     Preferences::AddBoolVarCache(&mPluginsHttpOnly,
   12700           0 :                                  "plugins.http_https_only");
   12701           0 : 
   12702           0 :     // We only need to register string-typed preferences.
   12703           0 :     Preferences::RegisterCallback(UpdateStringPrefs, "urlclassifier.flashAllowTable", this);
   12704           0 :     Preferences::RegisterCallback(UpdateStringPrefs, "urlclassifier.flashAllowExceptTable", this);
   12705           0 :     Preferences::RegisterCallback(UpdateStringPrefs, "urlclassifier.flashTable", this);
   12706           0 :     Preferences::RegisterCallback(UpdateStringPrefs, "urlclassifier.flashExceptTable", this);
   12707           0 :     Preferences::RegisterCallback(UpdateStringPrefs, "urlclassifier.flashSubDocTable", this);
   12708             :     Preferences::RegisterCallback(UpdateStringPrefs, "urlclassifier.flashSubDocExceptTable", this);
   12709           0 : 
   12710             :     UpdateStringPrefs();
   12711           1 :   }
   12712           1 : 
   12713           1 :   ~PrefStore()
   12714           1 :   {
   12715           1 :     Preferences::UnregisterCallback(UpdateStringPrefs, "urlclassifier.flashAllowTable", this);
   12716           1 :     Preferences::UnregisterCallback(UpdateStringPrefs, "urlclassifier.flashAllowExceptTable", this);
   12717           1 :     Preferences::UnregisterCallback(UpdateStringPrefs, "urlclassifier.flashTable", this);
   12718             :     Preferences::UnregisterCallback(UpdateStringPrefs, "urlclassifier.flashExceptTable", this);
   12719           0 :     Preferences::UnregisterCallback(UpdateStringPrefs, "urlclassifier.flashSubDocTable", this);
   12720             :     Preferences::UnregisterCallback(UpdateStringPrefs, "urlclassifier.flashSubDocExceptTable", this);
   12721           0 :   }
   12722           0 : 
   12723             :   void UpdateStringPrefs()
   12724             :   {
   12725             :     Preferences::GetCString("urlclassifier.flashAllowTable", mAllowTables);
   12726             :     Preferences::GetCString("urlclassifier.flashAllowExceptTable", mAllowExceptionsTables);
   12727             :     Preferences::GetCString("urlclassifier.flashTable", mDenyTables);
   12728             :     Preferences::GetCString("urlclassifier.flashExceptTable", mDenyExceptionsTables);
   12729             :     Preferences::GetCString("urlclassifier.flashSubDocTable", mSubDocDenyTables);
   12730             :     Preferences::GetCString("urlclassifier.flashSubDocExceptTable", mSubDocDenyExceptionsTables);
   12731             :   }
   12732             : 
   12733             :   static void UpdateStringPrefs(const char*, void* aClosure)
   12734             :   {
   12735             :     static_cast<PrefStore*>(aClosure)->UpdateStringPrefs();
   12736          49 :   }
   12737             : 
   12738           0 :   bool mFlashBlockEnabled;
   12739          49 :   bool mPluginsHttpOnly;
   12740           0 : 
   12741           1 :   nsCString mAllowTables;
   12742             :   nsCString mAllowExceptionsTables;
   12743           0 :   nsCString mDenyTables;
   12744             :   nsCString mDenyExceptionsTables;
   12745             :   nsCString mSubDocDenyTables;
   12746             :   nsCString mSubDocDenyExceptionsTables;
   12747             : };
   12748             : 
   12749             : static const
   12750             : PrefStore& GetPrefStore()
   12751           0 : {
   12752             :   static UniquePtr<PrefStore> sPrefStore;
   12753         360 :   if (!sPrefStore) {
   12754             :     sPrefStore.reset(new PrefStore());
   12755          60 :     ClearOnShutdown(&sPrefStore);
   12756          60 :   }
   12757             :   return *sPrefStore;
   12758             : }
   12759         109 : 
   12760             : } // end of unnamed namespace.
   12761           0 : 
   12762           0 : ////////////////////////////////////////////////////////////////////
   12763           0 : // PrincipalFlashClassifier implementation.
   12764         109 : 
   12765             : NS_IMPL_ISUPPORTS(PrincipalFlashClassifier, nsIURIClassifierCallback)
   12766             : 
   12767           0 : PrincipalFlashClassifier::PrincipalFlashClassifier()
   12768             : {
   12769             :   Reset();
   12770           0 : }
   12771           0 : 
   12772             : void
   12773           0 : PrincipalFlashClassifier::Reset()
   12774           0 : {
   12775           0 :   mAsyncClassified = false;
   12776           0 :   mMatchedTables.Clear();
   12777             :   mResult = FlashClassification::Unclassified;
   12778           0 : }
   12779           0 : 
   12780           0 : void
   12781             : PrincipalFlashClassifier::GetClassificationTables(bool aIsThirdParty,
   12782           0 :                                                   nsACString& aTables)
   12783             : {
   12784             :   aTables.Truncate();
   12785           0 :   auto& prefs = GetPrefStore();
   12786             : 
   12787           0 :   MaybeAddTableToTableList(prefs.mAllowTables, aTables);
   12788           0 :   MaybeAddTableToTableList(prefs.mAllowExceptionsTables, aTables);
   12789             :   MaybeAddTableToTableList(prefs.mDenyTables, aTables);
   12790             :   MaybeAddTableToTableList(prefs.mDenyExceptionsTables, aTables);
   12791           0 : 
   12792             :   if (aIsThirdParty) {
   12793             :     MaybeAddTableToTableList(prefs.mSubDocDenyTables, aTables);
   12794             :     MaybeAddTableToTableList(prefs.mSubDocDenyExceptionsTables, aTables);
   12795           0 :   }
   12796             : }
   12797           0 : 
   12798             : bool
   12799             : PrincipalFlashClassifier::EnsureUriClassifier()
   12800             : {
   12801             :   if (!mUriClassifier) {
   12802             :     mUriClassifier = do_GetService(NS_URICLASSIFIERSERVICE_CONTRACTID);
   12803             :   }
   12804           0 : 
   12805             :   return !!mUriClassifier;
   12806             : }
   12807             : 
   12808             : FlashClassification
   12809             : PrincipalFlashClassifier::ClassifyMaybeSync(nsIPrincipal* aPrincipal, bool aIsThirdParty)
   12810             : {
   12811             :   if (FlashClassification::Unclassified != mResult) {
   12812             :     // We already have the result. Just return it.
   12813             :     return mResult;
   12814             :   }
   12815           0 : 
   12816           0 :   // TODO: Bug 1342333 - Entirely remove the use of the sync API
   12817             :   // (ClassifyLocalWithTables).
   12818           0 :   if (!mAsyncClassified) {
   12819           0 : 
   12820             :     //
   12821             :     // We may
   12822             :     //   1) have called AsyncClassifyLocalWithTables but OnClassifyComplete
   12823             :     //      hasn't been called.
   12824           0 :     //   2) haven't even called AsyncClassifyLocalWithTables.
   12825           0 :     //
   12826             :     // In both cases we need to do the synchronous classification as the fallback.
   12827           0 :     //
   12828           0 : 
   12829           0 :     if (!EnsureUriClassifier()) {
   12830           0 :       return FlashClassification::Denied;
   12831           0 :     }
   12832             :     mResult = CheckIfClassifyNeeded(aPrincipal);
   12833             :     if (FlashClassification::Unclassified != mResult) {
   12834             :       return mResult;
   12835           0 :     }
   12836             : 
   12837           0 :     nsresult rv;
   12838           0 :     nsAutoCString classificationTables;
   12839           0 :     GetClassificationTables(aIsThirdParty, classificationTables);
   12840             : 
   12841             :     if (!mClassificationURI) {
   12842           0 :       rv = aPrincipal->GetURI(getter_AddRefs(mClassificationURI));
   12843             :       if (NS_FAILED(rv) || !mClassificationURI) {
   12844           0 :         mResult = FlashClassification::Denied;
   12845             :         return mResult;
   12846           0 :       }
   12847             :     }
   12848             : 
   12849             :     rv = mUriClassifier->ClassifyLocalWithTables(mClassificationURI,
   12850             :                                                  classificationTables,
   12851           0 :                                                  mMatchedTables);
   12852           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   12853             :       if (rv == NS_ERROR_MALFORMED_URI) {
   12854             :         // This means that the URI had no hostname (ex: file://doc.html). In this
   12855             :         // case, we allow the default (Unknown plugin) behavior.
   12856             :         mResult = FlashClassification::Unknown;
   12857             :       } else {
   12858             :         mResult = FlashClassification::Denied;
   12859             :       }
   12860           0 :       return mResult;
   12861             :     }
   12862             :   }
   12863             : 
   12864             :   // Resolve the result based on mMatchedTables and aIsThirdParty.
   12865           0 :   mResult = Resolve(aIsThirdParty);
   12866             :   MOZ_ASSERT(FlashClassification::Unclassified != mResult);
   12867           0 : 
   12868             :   // The subsequent call of Result() will return the resolved result
   12869             :   // and never reach here until Reset() is called.
   12870             :   return mResult;
   12871             : }
   12872             : 
   12873             : /*virtual*/ nsresult
   12874             : PrincipalFlashClassifier::OnClassifyComplete(nsresult /*aErrorCode*/,
   12875             :                                              const nsACString& aLists, // Only this matters.
   12876             :                                              const nsACString& /*aProvider*/,
   12877             :                                              const nsACString& /*aPrefix*/)
   12878             : {
   12879           0 :   mAsyncClassified = true;
   12880           0 : 
   12881           0 :   if (FlashClassification::Unclassified != mResult) {
   12882           0 :     // Result() has been called prior to this callback.
   12883           0 :     return NS_OK;
   12884           0 :   }
   12885           0 : 
   12886           0 :   // TODO: Bug 1364804 - We should use a callback type which notifies
   12887           0 :   // the result as a string array rather than a formatted string.
   12888             : 
   12889           0 :   // We only populate the matched list without resolving the classification
   12890           0 :   // result because we are not sure if the parent doc has been properly set.
   12891           0 :   // We also parse the comma-separated tables to array. (the code is copied
   12892             :   // from Classifier::SplitTables.)
   12893             :   nsACString::const_iterator begin, iter, end;
   12894             :   aLists.BeginReading(begin);
   12895             :   aLists.EndReading(end);
   12896             :   while (begin != end) {
   12897             :     iter = begin;
   12898             :     FindCharInReadable(',', iter, end);
   12899             :     nsDependentCSubstring table = Substring(begin,iter);
   12900             :     if (!table.IsEmpty()) {
   12901           0 :       mMatchedTables.AppendElement(Substring(begin, iter));
   12902             :     }
   12903           0 :     begin = iter;
   12904             :     if (begin != end) {
   12905             :       begin++;
   12906           0 :     }
   12907             :   }
   12908             : 
   12909             :   return NS_OK;
   12910           0 : }
   12911           0 : 
   12912           0 : // We resolve the classification result based on aIsThirdParty
   12913             : // and the matched tables we got ealier on (via either sync or async API).
   12914           0 : FlashClassification
   12915           0 : PrincipalFlashClassifier::Resolve(bool aIsThirdParty)
   12916             : {
   12917             :   MOZ_ASSERT(FlashClassification::Unclassified == mResult,
   12918             :              "We already have resolved classification result.");
   12919           0 : 
   12920           0 :   if (mMatchedTables.IsEmpty()) {
   12921             :     return FlashClassification::Unknown;
   12922             :   }
   12923             : 
   12924           0 :   auto& prefs = GetPrefStore();
   12925             :   if (ArrayContainsTable(mMatchedTables, prefs.mDenyTables) &&
   12926             :       !ArrayContainsTable(mMatchedTables, prefs.mDenyExceptionsTables)) {
   12927             :     return FlashClassification::Denied;
   12928           0 :   } else if (ArrayContainsTable(mMatchedTables, prefs.mAllowTables) &&
   12929             :              !ArrayContainsTable(mMatchedTables, prefs.mAllowExceptionsTables)) {
   12930          49 :     return FlashClassification::Allowed;
   12931             :   }
   12932          49 : 
   12933          49 :   if (aIsThirdParty && ArrayContainsTable(mMatchedTables, prefs.mSubDocDenyTables) &&
   12934          49 :       !ArrayContainsTable(mMatchedTables, prefs.mSubDocDenyExceptionsTables)) {
   12935             :     return FlashClassification::Denied;
   12936             :   }
   12937          49 : 
   12938             :   return FlashClassification::Unknown;
   12939             : }
   12940             : 
   12941           0 : void
   12942             : PrincipalFlashClassifier::AsyncClassify(nsIPrincipal* aPrincipal)
   12943             : {
   12944          49 :   MOZ_ASSERT(FlashClassification::Unclassified == mResult,
   12945             :              "The old classification result should be reset first.");
   12946             :   Reset();
   12947             :   mResult = AsyncClassifyInternal(aPrincipal);
   12948          98 : }
   12949          49 : 
   12950             : FlashClassification
   12951             : PrincipalFlashClassifier::CheckIfClassifyNeeded(nsIPrincipal* aPrincipal)
   12952             : {
   12953           0 :   nsresult rv;
   12954           0 : 
   12955           0 :   auto& prefs = GetPrefStore();
   12956             : 
   12957             :   // If neither pref is on, skip the null-principal and principal URI checks.
   12958             :   if (prefs.mPluginsHttpOnly && !prefs.mFlashBlockEnabled) {
   12959          16 :    return FlashClassification::Unknown;
   12960             :   }
   12961             : 
   12962             :   nsCOMPtr<nsIPrincipal> principal = aPrincipal;
   12963             :   if (principal->GetIsNullPrincipal()) {
   12964             :     return FlashClassification::Denied;
   12965          16 :   }
   12966           0 : 
   12967          48 :   nsCOMPtr<nsIURI> classificationURI;
   12968          32 :   rv = principal->GetURI(getter_AddRefs(classificationURI));
   12969          32 :   if (NS_FAILED(rv) || !classificationURI) {
   12970             :     return FlashClassification::Denied;
   12971             :   }
   12972             : 
   12973             :   if (prefs.mPluginsHttpOnly) {
   12974             :     // Only allow plugins for documents from an HTTP/HTTPS origin. This should
   12975           0 :     // allow dependent data: URIs to load plugins, but not:
   12976             :     // * chrome documents
   12977             :     // * "bare" data: loads
   12978             :     // * FTP/gopher/file
   12979           0 :     nsAutoCString scheme;
   12980             :     rv = classificationURI->GetScheme(scheme);
   12981             :     if (NS_WARN_IF(NS_FAILED(rv)) ||
   12982             :         !(scheme.EqualsLiteral("http") || scheme.EqualsLiteral("https"))) {
   12983             :       return FlashClassification::Denied;
   12984             :     }
   12985          49 :   }
   12986             : 
   12987           0 :   // If flash blocking is disabled, it is equivalent to all sites being
   12988          49 :   // on neither list.
   12989             :   if (!prefs.mFlashBlockEnabled) {
   12990             :     return FlashClassification::Unknown;
   12991             :   }
   12992             : 
   12993             :   return FlashClassification::Unclassified;
   12994             : }
   12995             : 
   12996             : // Using nsIURIClassifier.asyncClassifyLocalWithTables to do classification
   12997             : // against the flash related tables based on the given principal.
   12998             : FlashClassification
   12999           0 : PrincipalFlashClassifier::AsyncClassifyInternal(nsIPrincipal* aPrincipal)
   13000           0 : {
   13001             :   auto result = CheckIfClassifyNeeded(aPrincipal);
   13002           0 :   if (FlashClassification::Unclassified != result) {
   13003             :     return result;
   13004             :   }
   13005             : 
   13006           0 :   // We haven't been able to decide if it's a third party document
   13007             :   // since determining if a document is third-party may depend on its
   13008             :   // parent document. At the time we call AsyncClassifyInternal
   13009             :   // (i.e. StartDocumentLoad) the parent document may not have been
   13010           0 :   // set. As a result, we wait until Resolve() to be called to
   13011           0 :   // take "is third party" into account. At this point, we just assume
   13012             :   // it's third-party to include every list.
   13013             :   nsAutoCString tables;
   13014             :   GetClassificationTables(true, tables);
   13015           0 : 
   13016             :   if (tables.IsEmpty()) {
   13017           0 :     return FlashClassification::Unknown;
   13018             :   }
   13019           0 : 
   13020           0 :   if (!EnsureUriClassifier()) {
   13021             :     return FlashClassification::Denied;
   13022             :   }
   13023             : 
   13024             :   nsresult rv = aPrincipal->GetURI(getter_AddRefs(mClassificationURI));
   13025           0 :   if (NS_FAILED(rv) || !mClassificationURI) {
   13026             :     return FlashClassification::Denied;
   13027             :   }
   13028             : 
   13029             :   rv = mUriClassifier->AsyncClassifyLocalWithTables(mClassificationURI,
   13030             :                                                     tables,
   13031             :                                                     this);
   13032             : 
   13033           0 :   if (NS_FAILED(rv)) {
   13034             :     if (rv == NS_ERROR_MALFORMED_URI) {
   13035           0 :       // This means that the URI had no hostname (ex: file://doc.html). In this
   13036           0 :       // case, we allow the default (Unknown plugin) behavior.
   13037             :       return FlashClassification::Unknown;
   13038             :     } else {
   13039           0 :       return FlashClassification::Denied;
   13040           0 :     }
   13041           0 :   }
   13042             : 
   13043             :   return FlashClassification::Unclassified;
   13044           0 : }
   13045             : 
   13046           0 : FlashClassification
   13047           0 : nsIDocument::ComputeFlashClassification()
   13048             : {
   13049           0 :   nsCOMPtr<nsIDocShellTreeItem> current = this->GetDocShell();
   13050           0 :   if (!current) {
   13051           0 :     return FlashClassification::Denied;
   13052             :   }
   13053             :   nsCOMPtr<nsIDocShellTreeItem> parent;
   13054           0 :   DebugOnly<nsresult> rv = current->GetSameTypeParent(getter_AddRefs(parent));
   13055             :   MOZ_ASSERT(NS_SUCCEEDED(rv),
   13056           0 :              "nsIDocShellTreeItem::GetSameTypeParent should never fail");
   13057             : 
   13058             :   bool isTopLevel = !parent;
   13059           0 :   FlashClassification classification;
   13060             :   if (isTopLevel) {
   13061             :     classification = PrincipalFlashClassification();
   13062             :   } else {
   13063           0 :     nsCOMPtr<nsIDocument> parentDocument = GetParentDocument();
   13064           0 :     if (!parentDocument) {
   13065           0 :       return FlashClassification::Denied;
   13066             :     }
   13067             :     FlashClassification parentClassification =
   13068             :       parentDocument->DocumentFlashClassification();
   13069             : 
   13070             :     if (parentClassification == FlashClassification::Denied) {
   13071             :       classification = FlashClassification::Denied;
   13072             :     } else {
   13073             :       classification = PrincipalFlashClassification();
   13074             : 
   13075             :       // Allow unknown children to inherit allowed status from parent, but
   13076             :       // do not allow denied children to do so.
   13077             :       if (classification == FlashClassification::Unknown &&
   13078             :           parentClassification == FlashClassification::Allowed) {
   13079             :         classification = FlashClassification::Allowed;
   13080             :       }
   13081             :     }
   13082           0 :   }
   13083             : 
   13084           0 :   return classification;
   13085           0 : }
   13086           0 : 
   13087           0 : /**
   13088             :  * Retrieves the classification of plugins in this document. This is dependent
   13089             :  * on the classification of this document and all parent documents.
   13090             :  * This function is infallible - It must return some classification that
   13091           0 :  * callers can act on.
   13092             :  *
   13093             :  * This function will NOT return FlashClassification::Unclassified
   13094             :  */
   13095             : FlashClassification
   13096             : nsIDocument::DocumentFlashClassification()
   13097             : {
   13098             :   if (mFlashClassification == FlashClassification::Unclassified) {
   13099             :     FlashClassification result = ComputeFlashClassification();
   13100             :     mFlashClassification = result;
   13101             :     MOZ_ASSERT(result != FlashClassification::Unclassified,
   13102             :       "nsDocument::GetPluginClassification should never return Unclassified");
   13103             :   }
   13104             : 
   13105             :   return mFlashClassification;
   13106             : }
   13107             : 
   13108             : /**
   13109             :  * Initializes |mIsThirdParty| if necessary and returns its value. The value
   13110           0 :  * returned represents whether this document should be considered Third-Party.
   13111             :  *
   13112           0 :  * A top-level document cannot be a considered Third-Party; only subdocuments
   13113           0 :  * may. For a subdocument to be considered Third-Party, it must meet ANY ONE
   13114             :  * of the following requirements:
   13115             :  *  - The document's parent is Third-Party
   13116           0 :  *  - The document has a different scheme (http/https) than its parent document
   13117           0 :  *  - The document's domain and subdomain do not match those of its parent
   13118           0 :  *    document.
   13119           0 :  *
   13120             :  * If there is an error in determining whether the document is Third-Party,
   13121             :  * it will be assumed to be Third-Party for security reasons.
   13122           0 :  */
   13123           0 : bool
   13124           0 : nsIDocument::IsThirdParty()
   13125             : {
   13126           0 :   if (mIsThirdParty.isSome()) {
   13127             :     return mIsThirdParty.value();
   13128           0 :   }
   13129           0 : 
   13130           0 :   nsCOMPtr<nsIDocShellTreeItem> docshell = this->GetDocShell();
   13131             :   if (!docshell) {
   13132             :     mIsThirdParty.emplace(true);
   13133           0 :     return mIsThirdParty.value();
   13134           0 :   }
   13135             : 
   13136           0 :   nsCOMPtr<nsIDocShellTreeItem> parent;
   13137           0 :   nsresult rv = docshell->GetSameTypeParent(getter_AddRefs(parent));
   13138             :   MOZ_ASSERT(NS_SUCCEEDED(rv),
   13139             :              "nsIDocShellTreeItem::GetSameTypeParent should never fail");
   13140           0 :   bool isTopLevel = !parent;
   13141           0 : 
   13142           0 :   if (isTopLevel) {
   13143             :     mIsThirdParty.emplace(false);
   13144             :     return mIsThirdParty.value();
   13145           0 :   }
   13146           0 : 
   13147           0 :   nsCOMPtr<nsIDocument> parentDocument = GetParentDocument();
   13148           0 :   if (!parentDocument) {
   13149             :     // Failure
   13150           0 :     mIsThirdParty.emplace(true);
   13151           0 :     return mIsThirdParty.value();
   13152             :   }
   13153           0 : 
   13154             :   if (parentDocument->IsThirdParty()) {
   13155           0 :     mIsThirdParty.emplace(true);
   13156           0 :     return mIsThirdParty.value();
   13157             :   }
   13158           0 : 
   13159             :   nsCOMPtr<nsIPrincipal> principal = NodePrincipal();
   13160           0 :   nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(parentDocument,
   13161           0 :                                                              &rv);
   13162             :   if (NS_WARN_IF(NS_FAILED(rv) || !sop)) {
   13163             :     // Failure
   13164           0 :     mIsThirdParty.emplace(true);
   13165           0 :     return mIsThirdParty.value();
   13166           0 :   }
   13167             :   nsCOMPtr<nsIPrincipal> parentPrincipal = sop->GetPrincipal();
   13168             : 
   13169             :   bool principalsMatch = false;
   13170           0 :   rv = principal->Equals(parentPrincipal, &principalsMatch);
   13171           0 : 
   13172             :   if (NS_WARN_IF(NS_FAILED(rv))) {
   13173             :     // Failure
   13174             :     mIsThirdParty.emplace(true);
   13175           8 :     return mIsThirdParty.value();
   13176             :   }
   13177          16 : 
   13178           0 :   if (!principalsMatch) {
   13179           8 :     mIsThirdParty.emplace(true);
   13180           8 :     return mIsThirdParty.value();
   13181           8 :   }
   13182             : 
   13183             :   // Fall-through. Document is not a Third-Party Document.
   13184           0 :   mIsThirdParty.emplace(false);
   13185             :   return mIsThirdParty.value();
   13186           0 : }
   13187           0 : 
   13188             : void
   13189             : nsIDocument::ClearStaleServoData()
   13190             : {
   13191           0 :   DocumentStyleRootIterator iter(this);
   13192             :   while (Element* root = iter.GetNextStyleRoot()) {
   13193             :     RestyleManager::ClearServoDataFromSubtree(root);
   13194             :   }
   13195           0 : }
   13196             : 
   13197             : Selection*
   13198             : nsIDocument::GetSelection(ErrorResult& aRv)
   13199           0 : {
   13200             :   nsCOMPtr<nsPIDOMWindowInner> window = GetInnerWindow();
   13201           0 :   if (!window) {
   13202           0 :     return nullptr;
   13203             :   }
   13204           0 : 
   13205             :   if (!window->IsCurrentInnerWindow()) {
   13206             :     return nullptr;
   13207             :   }
   13208             : 
   13209           0 :   return nsGlobalWindowInner::Cast(window)->GetSelection(aRv);
   13210           0 : }
   13211           0 : 
   13212           0 : void
   13213             : nsIDocument::RecordNavigationTiming(ReadyState aReadyState)
   13214           0 : {
   13215           0 :   if (!XRE_IsContentProcess()) {
   13216             :     return;
   13217             :   }
   13218             :   if (!IsTopLevelContentDocument()) {
   13219           0 :     return;
   13220           0 :   }
   13221             :   // If we dont have the timing yet (mostly because the doc is still loading),
   13222           0 :   // get it from docshell.
   13223           0 :   RefPtr<nsDOMNavigationTiming> timing = mTiming;
   13224           0 :   if (!timing) {
   13225           0 :     if (!mDocumentContainer) {
   13226             :       return;
   13227             :     }
   13228             :     timing = mDocumentContainer->GetNavigationTiming();
   13229           0 :     if (!timing) {
   13230           0 :       return;
   13231           0 :     }
   13232           0 :   }
   13233             :   TimeStamp startTime = timing->GetNavigationStartTimeStamp();
   13234             :   switch (aReadyState) {
   13235             :     case READYSTATE_LOADING:
   13236           0 :       if (!mDOMLoadingSet) {
   13237           0 :         Telemetry::AccumulateTimeDelta(Telemetry::TIME_TO_DOM_LOADING_MS,
   13238           0 :                                        startTime);
   13239           0 :         mDOMLoadingSet = true;
   13240             :       }
   13241             :       break;
   13242             :     case READYSTATE_INTERACTIVE:
   13243           0 :       if (!mDOMInteractiveSet) {
   13244           0 :         Telemetry::AccumulateTimeDelta(Telemetry::TIME_TO_DOM_INTERACTIVE_MS,
   13245             :                                        startTime);
   13246             :         mDOMInteractiveSet = true;
   13247             :       }
   13248             :       break;
   13249           1 :     case READYSTATE_COMPLETE:
   13250             :       if (!mDOMCompleteSet) {
   13251             :         Telemetry::AccumulateTimeDelta(Telemetry::TIME_TO_DOM_COMPLETE_MS,
   13252             :                                        startTime);
   13253           9 :         mDOMCompleteSet = true;
   13254           1 :       }
   13255           1 :       break;
   13256             :     default:
   13257             :       NS_WARNING("Unexpected ReadyState value");
   13258           1 :       break;
   13259             :   }
   13260             : }
   13261             : 
   13262           0 : bool
   13263             : nsIDocument::ModuleScriptsEnabled()
   13264           0 : {
   13265             :   static bool sEnabledForContent = false;
   13266             :   static bool sCachedPref = false;
   13267             :   if (!sCachedPref) {
   13268           0 :     sCachedPref = true;
   13269           0 :     Preferences::AddBoolVarCache(&sEnabledForContent, "dom.moduleScripts.enabled", false);
   13270             :   }
   13271             : 
   13272             :   return nsContentUtils::IsChromeDoc(this) || sEnabledForContent;
   13273             : }
   13274             : 
   13275             : void
   13276             : nsIDocument::ReportShadowDOMUsage()
   13277             : {
   13278             :   if (mHasReportedShadowDOMUsage) {
   13279             :     return;
   13280             :   }
   13281             : 
   13282             :   nsIDocument* topLevel = GetTopLevelContentDocument();
   13283             :   if (topLevel && !topLevel->mHasReportedShadowDOMUsage) {
   13284             :     topLevel->mHasReportedShadowDOMUsage = true;
   13285             :     nsString uri;
   13286             :     Unused << topLevel->GetDocumentURI(uri);
   13287             :     if (!uri.IsEmpty()) {
   13288             :       nsAutoString msg = NS_LITERAL_STRING("Shadow DOM used in [") + uri +
   13289             :         NS_LITERAL_STRING("] or in some of its subdocuments.");
   13290             :       nsContentUtils::ReportToConsoleNonLocalized(msg, nsIScriptError::infoFlag,
   13291             :                                                   NS_LITERAL_CSTRING("DOM"),
   13292             :                                                   topLevel);
   13293             :     }
   13294             :   }
   13295             : 
   13296             :   mHasReportedShadowDOMUsage = true;
   13297             : }

Generated by: LCOV version 1.13-14-ga5dd952