LCOV - code coverage report
Current view: top level - dom/base - nsDocument.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 1994 6174 32.3 %
Date: 2017-07-14 16:53:18 Functions: 260 695 37.4 %
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/DebugOnly.h"
      19             : #include "mozilla/EffectSet.h"
      20             : #include "mozilla/IntegerRange.h"
      21             : #include "mozilla/MemoryReporting.h"
      22             : #include "mozilla/Likely.h"
      23             : #include "mozilla/PresShell.h"
      24             : #include "mozilla/URLExtraData.h"
      25             : #include <algorithm>
      26             : 
      27             : #include "mozilla/Logging.h"
      28             : #include "plstr.h"
      29             : #include "mozilla/Sprintf.h"
      30             : 
      31             : #include "mozilla/Telemetry.h"
      32             : #include "nsIInterfaceRequestor.h"
      33             : #include "nsIInterfaceRequestorUtils.h"
      34             : #include "nsILoadContext.h"
      35             : #include "nsITextControlFrame.h"
      36             : #include "nsNumberControlFrame.h"
      37             : #include "nsUnicharUtils.h"
      38             : #include "nsContentList.h"
      39             : #include "nsCSSPseudoElements.h"
      40             : #include "nsIObserver.h"
      41             : #include "nsIBaseWindow.h"
      42             : #include "mozilla/css/Loader.h"
      43             : #include "mozilla/css/ImageLoader.h"
      44             : #include "nsDocShell.h"
      45             : #include "nsDocShellLoadTypes.h"
      46             : #include "nsIDocShellTreeItem.h"
      47             : #include "nsCOMArray.h"
      48             : #include "nsQueryObject.h"
      49             : #include "nsDOMClassInfo.h"
      50             : #include "mozilla/Services.h"
      51             : #include "nsScreen.h"
      52             : 
      53             : #include "mozilla/AsyncEventDispatcher.h"
      54             : #include "mozilla/BasicEvents.h"
      55             : #include "mozilla/EventListenerManager.h"
      56             : #include "mozilla/EventStateManager.h"
      57             : #include "nsIDOMNodeFilter.h"
      58             : 
      59             : #include "nsIDOMStyleSheet.h"
      60             : #include "mozilla/dom/Attr.h"
      61             : #include "mozilla/dom/BindingDeclarations.h"
      62             : #include "nsIDOMDOMImplementation.h"
      63             : #include "nsIDOMDocumentXBL.h"
      64             : #include "mozilla/dom/Element.h"
      65             : #include "mozilla/dom/FramingChecker.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 "nsIDOMText.h"
      77             : #include "nsIDOMComment.h"
      78             : #include "mozilla/dom/DocumentType.h"
      79             : #include "mozilla/dom/NodeIterator.h"
      80             : #include "mozilla/dom/Promise.h"
      81             : #include "mozilla/dom/PromiseNativeHandler.h"
      82             : #include "mozilla/dom/TreeWalker.h"
      83             : 
      84             : #include "nsIServiceManager.h"
      85             : #include "mozilla/dom/workers/ServiceWorkerManager.h"
      86             : #include "imgLoader.h"
      87             : 
      88             : #include "nsCanvasFrame.h"
      89             : #include "nsContentCID.h"
      90             : #include "nsError.h"
      91             : #include "nsPresContext.h"
      92             : #include "nsIJSON.h"
      93             : #include "nsThreadUtils.h"
      94             : #include "nsNodeInfoManager.h"
      95             : #include "nsIFileChannel.h"
      96             : #include "nsIMultiPartChannel.h"
      97             : #include "nsIRefreshURI.h"
      98             : #include "nsIWebNavigation.h"
      99             : #include "nsIScriptError.h"
     100             : #include "nsISimpleEnumerator.h"
     101             : #include "nsStyleSheetService.h"
     102             : 
     103             : #include "nsNetUtil.h"     // for NS_NewURI
     104             : #include "nsIInputStreamChannel.h"
     105             : #include "nsIAuthPrompt.h"
     106             : #include "nsIAuthPrompt2.h"
     107             : 
     108             : #include "nsIScriptSecurityManager.h"
     109             : #include "nsIPermissionManager.h"
     110             : #include "nsIPrincipal.h"
     111             : #include "NullPrincipal.h"
     112             : 
     113             : #include "nsIDOMWindow.h"
     114             : #include "nsPIDOMWindow.h"
     115             : #include "nsIDOMElement.h"
     116             : #include "nsFocusManager.h"
     117             : 
     118             : // for radio group stuff
     119             : #include "nsIDOMHTMLInputElement.h"
     120             : #include "nsIRadioVisitor.h"
     121             : #include "nsIFormControl.h"
     122             : 
     123             : #include "nsBidiUtils.h"
     124             : 
     125             : #include "nsIParserService.h"
     126             : #include "nsContentCreatorFunctions.h"
     127             : 
     128             : #include "nsIScriptContext.h"
     129             : #include "nsBindingManager.h"
     130             : #include "nsIDOMHTMLDocument.h"
     131             : #include "nsHTMLDocument.h"
     132             : #include "nsIDOMHTMLFormElement.h"
     133             : #include "nsIRequest.h"
     134             : #include "nsHostObjectProtocolHandler.h"
     135             : 
     136             : #include "nsCharsetSource.h"
     137             : #include "nsIParser.h"
     138             : #include "nsIContentSink.h"
     139             : 
     140             : #include "mozilla/EventDispatcher.h"
     141             : #include "mozilla/EventStates.h"
     142             : #include "mozilla/InternalMutationEvent.h"
     143             : #include "nsDOMCID.h"
     144             : 
     145             : #include "jsapi.h"
     146             : #include "nsIXPConnect.h"
     147             : #include "xpcpublic.h"
     148             : #include "nsCCUncollectableMarker.h"
     149             : #include "nsIContentPolicy.h"
     150             : #include "nsContentPolicyUtils.h"
     151             : #include "nsICategoryManager.h"
     152             : #include "nsIDocumentLoaderFactory.h"
     153             : #include "nsIDocumentLoader.h"
     154             : #include "nsIContentViewer.h"
     155             : #include "nsIXMLContentSink.h"
     156             : #include "nsIXULDocument.h"
     157             : #include "nsIPrompt.h"
     158             : #include "nsIPropertyBag2.h"
     159             : #include "mozilla/dom/PageTransitionEvent.h"
     160             : #include "mozilla/dom/StyleRuleChangeEvent.h"
     161             : #include "mozilla/dom/StyleSheetChangeEvent.h"
     162             : #include "mozilla/dom/StyleSheetApplicableStateChangeEvent.h"
     163             : #include "nsJSUtils.h"
     164             : #include "nsFrameLoader.h"
     165             : #include "nsEscape.h"
     166             : #include "nsObjectLoadingContent.h"
     167             : #include "nsHtml5TreeOpExecutor.h"
     168             : #include "mozilla/dom/HTMLLinkElement.h"
     169             : #include "mozilla/dom/HTMLMediaElement.h"
     170             : #include "mozilla/dom/HTMLIFrameElement.h"
     171             : #include "mozilla/dom/HTMLImageElement.h"
     172             : #include "mozilla/dom/MediaSource.h"
     173             : #include "mozilla/dom/FlyWebService.h"
     174             : 
     175             : #include "mozAutoDocUpdate.h"
     176             : #include "nsGlobalWindow.h"
     177             : #include "mozilla/Encoding.h"
     178             : #include "nsDOMNavigationTiming.h"
     179             : 
     180             : #include "nsSMILAnimationController.h"
     181             : #include "imgIContainer.h"
     182             : #include "nsSVGUtils.h"
     183             : 
     184             : #include "nsRefreshDriver.h"
     185             : 
     186             : // FOR CSP (autogenerated by xpidl)
     187             : #include "nsIContentSecurityPolicy.h"
     188             : #include "mozilla/dom/nsCSPContext.h"
     189             : #include "mozilla/dom/nsCSPService.h"
     190             : #include "mozilla/dom/nsCSPUtils.h"
     191             : #include "nsHTMLStyleSheet.h"
     192             : #include "nsHTMLCSSStyleSheet.h"
     193             : #include "mozilla/dom/DOMImplementation.h"
     194             : #include "mozilla/dom/ShadowRoot.h"
     195             : #include "mozilla/dom/Comment.h"
     196             : #include "nsTextNode.h"
     197             : #include "mozilla/dom/Link.h"
     198             : #include "mozilla/dom/HTMLElementBinding.h"
     199             : #include "nsXULAppAPI.h"
     200             : #include "mozilla/dom/Touch.h"
     201             : #include "mozilla/dom/TouchEvent.h"
     202             : 
     203             : #include "mozilla/Preferences.h"
     204             : 
     205             : #include "imgILoader.h"
     206             : #include "imgRequestProxy.h"
     207             : #include "nsWrapperCacheInlines.h"
     208             : #include "nsSandboxFlags.h"
     209             : #include "nsIAddonPolicyService.h"
     210             : #include "mozilla/dom/AnimatableBinding.h"
     211             : #include "mozilla/dom/AnonymousContent.h"
     212             : #include "mozilla/dom/BindingUtils.h"
     213             : #include "mozilla/dom/DocumentFragment.h"
     214             : #include "mozilla/dom/DocumentTimeline.h"
     215             : #include "mozilla/dom/Event.h"
     216             : #include "mozilla/dom/HTMLBodyElement.h"
     217             : #include "mozilla/dom/HTMLInputElement.h"
     218             : #include "mozilla/dom/ImageTracker.h"
     219             : #include "mozilla/dom/MediaQueryList.h"
     220             : #include "mozilla/dom/NodeFilterBinding.h"
     221             : #include "mozilla/OwningNonNull.h"
     222             : #include "mozilla/dom/TabChild.h"
     223             : #include "mozilla/dom/WebComponentsBinding.h"
     224             : #include "mozilla/dom/CustomElementRegistryBinding.h"
     225             : #include "mozilla/dom/CustomElementRegistry.h"
     226             : #include "mozilla/dom/TimeoutManager.h"
     227             : #include "nsFrame.h"
     228             : #include "nsDOMCaretPosition.h"
     229             : #include "nsIDOMHTMLTextAreaElement.h"
     230             : #include "nsViewportInfo.h"
     231             : #include "mozilla/StaticPtr.h"
     232             : #include "nsITextControlElement.h"
     233             : #include "nsIDOMNSEditableElement.h"
     234             : #include "nsIEditor.h"
     235             : #include "nsIDOMCSSStyleRule.h"
     236             : #include "mozilla/css/StyleRule.h"
     237             : #include "nsIHttpChannelInternal.h"
     238             : #include "nsISecurityConsoleMessage.h"
     239             : #include "nsCharSeparatedTokenizer.h"
     240             : #include "mozilla/dom/XPathEvaluator.h"
     241             : #include "mozilla/dom/XPathNSResolverBinding.h"
     242             : #include "mozilla/dom/XPathResult.h"
     243             : #include "nsIDocumentEncoder.h"
     244             : #include "nsIDocumentActivity.h"
     245             : #include "nsIStructuredCloneContainer.h"
     246             : #include "nsIMutableArray.h"
     247             : #include "mozilla/dom/DOMStringList.h"
     248             : #include "nsWindowMemoryReporter.h"
     249             : #include "mozilla/dom/Location.h"
     250             : #include "mozilla/dom/FontFaceSet.h"
     251             : #include "gfxPrefs.h"
     252             : #include "nsISupportsPrimitives.h"
     253             : #include "mozilla/StyleSetHandle.h"
     254             : #include "mozilla/StyleSetHandleInlines.h"
     255             : #include "mozilla/StyleSheet.h"
     256             : #include "mozilla/StyleSheetInlines.h"
     257             : #include "mozilla/dom/SVGSVGElement.h"
     258             : #include "mozilla/dom/DocGroup.h"
     259             : #include "mozilla/dom/TabGroup.h"
     260             : #ifdef MOZ_XUL
     261             : #include "mozilla/dom/ContainerBoxObject.h"
     262             : #include "mozilla/dom/ListBoxObject.h"
     263             : #include "mozilla/dom/MenuBoxObject.h"
     264             : #include "mozilla/dom/PopupBoxObject.h"
     265             : #include "mozilla/dom/ScrollBoxObject.h"
     266             : #include "mozilla/dom/TreeBoxObject.h"
     267             : #endif
     268             : #include "nsIPresShellInlines.h"
     269             : 
     270             : #include "mozilla/DocLoadingTimelineMarker.h"
     271             : 
     272             : #include "nsISpeculativeConnect.h"
     273             : 
     274             : #include "mozilla/MediaManager.h"
     275             : #ifdef MOZ_WEBRTC
     276             : #include "IPeerConnection.h"
     277             : #endif // MOZ_WEBRTC
     278             : 
     279             : #include "nsIURIClassifier.h"
     280             : 
     281             : using namespace mozilla;
     282             : using namespace mozilla::dom;
     283             : 
     284             : typedef nsTArray<Link*> LinkArray;
     285             : 
     286             : static LazyLogModule gDocumentLeakPRLog("DocumentLeak");
     287             : static LazyLogModule gCspPRLog("CSP");
     288             : 
     289             : static const char kChromeInContentPref[] = "security.allow_chrome_frames_inside_content";
     290             : static bool sChromeInContentAllowed = false;
     291             : static bool sChromeInContentPrefCached = false;
     292             : 
     293             : static nsresult
     294          51 : GetHttpChannelHelper(nsIChannel* aChannel, nsIHttpChannel** aHttpChannel)
     295             : {
     296         102 :   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
     297          51 :   if (httpChannel) {
     298           2 :     httpChannel.forget(aHttpChannel);
     299           2 :     return NS_OK;
     300             :   }
     301             : 
     302          98 :   nsCOMPtr<nsIMultiPartChannel> multipart = do_QueryInterface(aChannel);
     303          49 :   if (!multipart) {
     304          49 :     *aHttpChannel = nullptr;
     305          49 :     return NS_OK;
     306             :   }
     307             : 
     308           0 :   nsCOMPtr<nsIChannel> baseChannel;
     309           0 :   nsresult rv = multipart->GetBaseChannel(getter_AddRefs(baseChannel));
     310           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     311           0 :     return rv;
     312             :   }
     313             : 
     314           0 :   httpChannel = do_QueryInterface(baseChannel);
     315           0 :   httpChannel.forget(aHttpChannel);
     316             : 
     317           0 :   return NS_OK;
     318             : }
     319             : 
     320             : #define NAME_NOT_VALID ((nsSimpleContentList*)1)
     321             : 
     322        1576 : nsIdentifierMapEntry::~nsIdentifierMapEntry()
     323             : {
     324        1576 : }
     325             : 
     326             : void
     327           0 : nsIdentifierMapEntry::Traverse(nsCycleCollectionTraversalCallback* aCallback)
     328             : {
     329             :   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCallback,
     330           0 :                                      "mIdentifierMap mNameContentList");
     331           0 :   aCallback->NoteXPCOMChild(static_cast<nsIDOMNodeList*>(mNameContentList));
     332             : 
     333           0 :   if (mImageElement) {
     334             :     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCallback,
     335           0 :                                        "mIdentifierMap mImageElement element");
     336           0 :     nsIContent* imageElement = mImageElement;
     337           0 :     aCallback->NoteXPCOMChild(imageElement);
     338             :   }
     339           0 : }
     340             : 
     341             : bool
     342          28 : nsIdentifierMapEntry::IsEmpty()
     343             : {
     344          84 :   return mIdContentList.IsEmpty() && !mNameContentList &&
     345          84 :          !mChangeCallbacks && !mImageElement;
     346             : }
     347             : 
     348             : Element*
     349         403 : nsIdentifierMapEntry::GetIdElement()
     350             : {
     351         403 :   return mIdContentList.SafeElementAt(0);
     352             : }
     353             : 
     354             : Element*
     355           0 : nsIdentifierMapEntry::GetImageIdElement()
     356             : {
     357           0 :   return mImageElement ? mImageElement.get() : GetIdElement();
     358             : }
     359             : 
     360             : void
     361           4 : nsIdentifierMapEntry::AppendAllIdContent(nsCOMArray<nsIContent>* aElements)
     362             : {
     363           8 :   for (size_t i = 0; i < mIdContentList.Length(); ++i) {
     364           4 :     aElements->AppendObject(mIdContentList[i]);
     365             :   }
     366           4 : }
     367             : 
     368             : void
     369          25 : nsIdentifierMapEntry::AddContentChangeCallback(nsIDocument::IDTargetObserver aCallback,
     370             :                                                void* aData, bool aForImage)
     371             : {
     372          25 :   if (!mChangeCallbacks) {
     373          10 :     mChangeCallbacks = new nsTHashtable<ChangeCallbackEntry>;
     374             :   }
     375             : 
     376          25 :   ChangeCallback cc = { aCallback, aData, aForImage };
     377          25 :   mChangeCallbacks->PutEntry(cc);
     378          25 : }
     379             : 
     380             : void
     381           0 : nsIdentifierMapEntry::RemoveContentChangeCallback(nsIDocument::IDTargetObserver aCallback,
     382             :                                                   void* aData, bool aForImage)
     383             : {
     384           0 :   if (!mChangeCallbacks)
     385           0 :     return;
     386           0 :   ChangeCallback cc = { aCallback, aData, aForImage };
     387           0 :   mChangeCallbacks->RemoveEntry(cc);
     388           0 :   if (mChangeCallbacks->Count() == 0) {
     389           0 :     mChangeCallbacks = nullptr;
     390             :   }
     391             : }
     392             : 
     393             : void
     394        1080 : nsIdentifierMapEntry::FireChangeCallbacks(Element* aOldElement,
     395             :                                           Element* aNewElement,
     396             :                                           bool aImageOnly)
     397             : {
     398        1080 :   if (!mChangeCallbacks)
     399        1080 :     return;
     400             : 
     401           0 :   for (auto iter = mChangeCallbacks->ConstIter(); !iter.Done(); iter.Next()) {
     402           0 :     nsIdentifierMapEntry::ChangeCallbackEntry* entry = iter.Get();
     403             :     // Don't fire image changes for non-image observers, and don't fire element
     404             :     // changes for image observers when an image override is active.
     405           0 :     if (entry->mKey.mForImage ? (mImageElement && !aImageOnly) : aImageOnly) {
     406           0 :       continue;
     407             :     }
     408             : 
     409           0 :     if (!entry->mKey.mCallback(aOldElement, aNewElement, entry->mKey.mData)) {
     410           0 :       iter.Remove();
     411             :     }
     412             :   }
     413             : }
     414             : 
     415             : namespace {
     416             : 
     417             : struct PositionComparator
     418             : {
     419             :   Element* const mElement;
     420        1078 :   explicit PositionComparator(Element* const aElement) : mElement(aElement) {}
     421             : 
     422        1078 :   int operator()(void* aElement) const {
     423        1078 :     Element* curElement = static_cast<Element*>(aElement);
     424        1078 :     if (mElement == curElement) {
     425        1078 :       return 0;
     426             :     }
     427           0 :     if (nsContentUtils::PositionIsBefore(mElement, curElement)) {
     428           0 :       return -1;
     429             :     }
     430           0 :     return 1;
     431             :   }
     432             : };
     433             : 
     434             : } // namespace
     435             : 
     436             : bool
     437        2130 : nsIdentifierMapEntry::AddIdElement(Element* aElement)
     438             : {
     439        2130 :   NS_PRECONDITION(aElement, "Must have element");
     440        2130 :   NS_PRECONDITION(!mIdContentList.Contains(nullptr),
     441             :                   "Why is null in our list?");
     442             : 
     443             : #ifdef DEBUG
     444        2130 :   Element* currentElement = mIdContentList.SafeElementAt(0);
     445             : #endif
     446             : 
     447             :   // Common case
     448        2130 :   if (mIdContentList.IsEmpty()) {
     449        1052 :     if (!mIdContentList.AppendElement(aElement))
     450           0 :       return false;
     451        1052 :     NS_ASSERTION(currentElement == nullptr, "How did that happen?");
     452        1052 :     FireChangeCallbacks(nullptr, aElement);
     453        1052 :     return true;
     454             :   }
     455             : 
     456             :   // We seem to have multiple content nodes for the same id, or XUL is messing
     457             :   // with us.  Search for the right place to insert the content.
     458             : 
     459             :   size_t idx;
     460        2156 :   if (BinarySearchIf(mIdContentList, 0, mIdContentList.Length(),
     461        2156 :                      PositionComparator(aElement), &idx)) {
     462             :     // Already in the list, so already in the right spot.  Get out of here.
     463             :     // XXXbz this only happens because XUL does all sorts of random
     464             :     // UpdateIdTableEntry calls.  Hate, hate, hate!
     465        1078 :     return true;
     466             :   }
     467             : 
     468           0 :   if (!mIdContentList.InsertElementAt(idx, aElement)) {
     469           0 :     return false;
     470             :   }
     471             : 
     472           0 :   if (idx == 0) {
     473           0 :     Element* oldElement = mIdContentList.SafeElementAt(1);
     474           0 :     NS_ASSERTION(currentElement == oldElement, "How did that happen?");
     475           0 :     FireChangeCallbacks(oldElement, aElement);
     476             :   }
     477           0 :   return true;
     478             : }
     479             : 
     480             : void
     481          28 : nsIdentifierMapEntry::RemoveIdElement(Element* aElement)
     482             : {
     483          28 :   NS_PRECONDITION(aElement, "Missing element");
     484             : 
     485             :   // This should only be called while the document is in an update.
     486             :   // Assertions near the call to this method guarantee this.
     487             : 
     488             :   // This could fire in OOM situations
     489             :   // Only assert this in HTML documents for now as XUL does all sorts of weird
     490             :   // crap.
     491          28 :   NS_ASSERTION(!aElement->OwnerDoc()->IsHTMLDocument() ||
     492             :                mIdContentList.Contains(aElement),
     493             :                "Removing id entry that doesn't exist");
     494             : 
     495             :   // XXXbz should this ever Compact() I guess when all the content is gone
     496             :   // we'll just get cleaned up in the natural order of things...
     497          28 :   Element* currentElement = mIdContentList.SafeElementAt(0);
     498          28 :   mIdContentList.RemoveElement(aElement);
     499          28 :   if (currentElement == aElement) {
     500          28 :     FireChangeCallbacks(currentElement, mIdContentList.SafeElementAt(0));
     501             :   }
     502          28 : }
     503             : 
     504             : void
     505           0 : nsIdentifierMapEntry::SetImageElement(Element* aElement)
     506             : {
     507           0 :   Element* oldElement = GetImageIdElement();
     508           0 :   mImageElement = aElement;
     509           0 :   Element* newElement = GetImageIdElement();
     510           0 :   if (oldElement != newElement) {
     511           0 :     FireChangeCallbacks(oldElement, newElement, true);
     512             :   }
     513           0 : }
     514             : 
     515             : void
     516           0 : nsIdentifierMapEntry::AddNameElement(nsINode* aNode, Element* aElement)
     517             : {
     518           0 :   if (!mNameContentList) {
     519           0 :     mNameContentList = new nsSimpleContentList(aNode);
     520             :   }
     521             : 
     522           0 :   mNameContentList->AppendElement(aElement);
     523           0 : }
     524             : 
     525             : void
     526           0 : nsIdentifierMapEntry::RemoveNameElement(Element* aElement)
     527             : {
     528           0 :   if (mNameContentList) {
     529           0 :     mNameContentList->RemoveElement(aElement);
     530             :   }
     531           0 : }
     532             : 
     533             : bool
     534           0 : nsIdentifierMapEntry::HasIdElementExposedAsHTMLDocumentProperty()
     535             : {
     536           0 :   Element* idElement = GetIdElement();
     537           0 :   return idElement &&
     538           0 :          nsGenericHTMLElement::ShouldExposeIdAsHTMLDocumentProperty(idElement);
     539             : }
     540             : 
     541             : size_t
     542          31 : nsIdentifierMapEntry::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
     543             : {
     544          31 :   return mKey.mString.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
     545             : }
     546             : 
     547             : // Helper structs for the content->subdoc map
     548             : 
     549             : class SubDocMapEntry : public PLDHashEntryHdr
     550             : {
     551             : public:
     552             :   // Both of these are strong references
     553             :   Element *mKey; // must be first, to look like PLDHashEntryStub
     554             :   nsIDocument *mSubDocument;
     555             : };
     556             : 
     557             : 
     558             : /**
     559             :  * A struct that holds all the information about a radio group.
     560             :  */
     561           0 : struct nsRadioGroupStruct
     562             : {
     563           0 :   nsRadioGroupStruct()
     564           0 :     : mRequiredRadioCount(0)
     565           0 :     , mGroupSuffersFromValueMissing(false)
     566           0 :   {}
     567             : 
     568             :   /**
     569             :    * A strong pointer to the currently selected radio button.
     570             :    */
     571             :   RefPtr<HTMLInputElement> mSelectedRadioButton;
     572             :   nsCOMArray<nsIFormControl> mRadioButtons;
     573             :   uint32_t mRequiredRadioCount;
     574             :   bool mGroupSuffersFromValueMissing;
     575             : };
     576             : 
     577             : 
     578           2 : nsDOMStyleSheetList::nsDOMStyleSheetList(nsIDocument *aDocument)
     579             : {
     580           2 :   mLength = -1;
     581             :   // Not reference counted to avoid circular references.
     582             :   // The document will tell us when its going away.
     583           2 :   mDocument = aDocument;
     584           2 :   mDocument->AddObserver(this);
     585           2 : }
     586             : 
     587           0 : nsDOMStyleSheetList::~nsDOMStyleSheetList()
     588             : {
     589           0 :   if (mDocument) {
     590           0 :     mDocument->RemoveObserver(this);
     591             :   }
     592           0 : }
     593             : 
     594          52 : NS_IMPL_ISUPPORTS_INHERITED(nsDOMStyleSheetList, StyleSheetList,
     595             :                             nsIDocumentObserver,
     596             :                             nsIMutationObserver)
     597             : 
     598             : uint32_t
     599           2 : nsDOMStyleSheetList::Length()
     600             : {
     601           2 :   if (!mDocument) {
     602           0 :     return 0;
     603             :   }
     604             : 
     605             :   // XXX Find the number and then cache it. We'll use the
     606             :   // observer notification to figure out if new ones have
     607             :   // been added or removed.
     608           2 :   if (-1 == mLength) {
     609           2 :     mLength = mDocument->GetNumberOfStyleSheets();
     610             :   }
     611           2 :   return mLength;
     612             : }
     613             : 
     614             : StyleSheet*
     615           0 : nsDOMStyleSheetList::IndexedGetter(uint32_t aIndex, bool& aFound)
     616             : {
     617           0 :   if (!mDocument || aIndex >= (uint32_t)mDocument->GetNumberOfStyleSheets()) {
     618           0 :     aFound = false;
     619           0 :     return nullptr;
     620             :   }
     621           0 :   aFound = true;
     622           0 :   return mDocument->GetStyleSheetAt(aIndex);
     623             : }
     624             : 
     625             : void
     626           0 : nsDOMStyleSheetList::NodeWillBeDestroyed(const nsINode *aNode)
     627             : {
     628           0 :   mDocument = nullptr;
     629           0 : }
     630             : 
     631             : void
     632           0 : nsDOMStyleSheetList::StyleSheetAdded(StyleSheet* aStyleSheet,
     633             :                                      bool aDocumentSheet)
     634             : {
     635           0 :   if (aDocumentSheet && -1 != mLength) {
     636           0 :     mLength++;
     637             :   }
     638           0 : }
     639             : 
     640             : void
     641           0 : nsDOMStyleSheetList::StyleSheetRemoved(StyleSheet* aStyleSheet,
     642             :                                        bool aDocumentSheet)
     643             : {
     644           0 :   if (aDocumentSheet && -1 != mLength) {
     645           0 :     mLength--;
     646             :   }
     647           0 : }
     648             : 
     649             : // nsOnloadBlocker implementation
     650         444 : NS_IMPL_ISUPPORTS(nsOnloadBlocker, nsIRequest)
     651             : 
     652             : NS_IMETHODIMP
     653          82 : nsOnloadBlocker::GetName(nsACString &aResult)
     654             : {
     655          82 :   aResult.AssignLiteral("about:document-onload-blocker");
     656          82 :   return NS_OK;
     657             : }
     658             : 
     659             : NS_IMETHODIMP
     660           0 : nsOnloadBlocker::IsPending(bool *_retval)
     661             : {
     662           0 :   *_retval = true;
     663           0 :   return NS_OK;
     664             : }
     665             : 
     666             : NS_IMETHODIMP
     667           0 : nsOnloadBlocker::GetStatus(nsresult *status)
     668             : {
     669           0 :   *status = NS_OK;
     670           0 :   return NS_OK;
     671             : }
     672             : 
     673             : NS_IMETHODIMP
     674           1 : nsOnloadBlocker::Cancel(nsresult status)
     675             : {
     676           1 :   return NS_OK;
     677             : }
     678             : NS_IMETHODIMP
     679           0 : nsOnloadBlocker::Suspend(void)
     680             : {
     681           0 :   return NS_OK;
     682             : }
     683             : NS_IMETHODIMP
     684           0 : nsOnloadBlocker::Resume(void)
     685             : {
     686           0 :   return NS_OK;
     687             : }
     688             : 
     689             : NS_IMETHODIMP
     690           0 : nsOnloadBlocker::GetLoadGroup(nsILoadGroup * *aLoadGroup)
     691             : {
     692           0 :   *aLoadGroup = nullptr;
     693           0 :   return NS_OK;
     694             : }
     695             : 
     696             : NS_IMETHODIMP
     697           0 : nsOnloadBlocker::SetLoadGroup(nsILoadGroup * aLoadGroup)
     698             : {
     699           0 :   return NS_OK;
     700             : }
     701             : 
     702             : NS_IMETHODIMP
     703          45 : nsOnloadBlocker::GetLoadFlags(nsLoadFlags *aLoadFlags)
     704             : {
     705          45 :   *aLoadFlags = nsIRequest::LOAD_NORMAL;
     706          45 :   return NS_OK;
     707             : }
     708             : 
     709             : NS_IMETHODIMP
     710           0 : nsOnloadBlocker::SetLoadFlags(nsLoadFlags aLoadFlags)
     711             : {
     712           0 :   return NS_OK;
     713             : }
     714             : 
     715             : // ==================================================================
     716             : 
     717          55 : nsExternalResourceMap::nsExternalResourceMap()
     718          55 :   : mHaveShutDown(false)
     719             : {
     720          55 : }
     721             : 
     722             : nsIDocument*
     723           0 : nsExternalResourceMap::RequestResource(nsIURI* aURI,
     724             :                                        nsINode* aRequestingNode,
     725             :                                        nsDocument* aDisplayDocument,
     726             :                                        ExternalResourceLoad** aPendingLoad)
     727             : {
     728             :   // If we ever start allowing non-same-origin loads here, we might need to do
     729             :   // something interesting with aRequestingPrincipal even for the hashtable
     730             :   // gets.
     731           0 :   NS_PRECONDITION(aURI, "Must have a URI");
     732           0 :   NS_PRECONDITION(aRequestingNode, "Must have a node");
     733           0 :   *aPendingLoad = nullptr;
     734           0 :   if (mHaveShutDown) {
     735           0 :     return nullptr;
     736             :   }
     737             : 
     738             :   // First, make sure we strip the ref from aURI.
     739           0 :   nsCOMPtr<nsIURI> clone;
     740           0 :   nsresult rv = aURI->CloneIgnoringRef(getter_AddRefs(clone));
     741           0 :   if (NS_FAILED(rv) || !clone) {
     742           0 :     return nullptr;
     743             :   }
     744             : 
     745             :   ExternalResource* resource;
     746           0 :   mMap.Get(clone, &resource);
     747           0 :   if (resource) {
     748           0 :     return resource->mDocument;
     749             :   }
     750             : 
     751           0 :   RefPtr<PendingLoad>& loadEntry = mPendingLoads.GetOrInsert(clone);
     752           0 :   if (loadEntry) {
     753           0 :     RefPtr<PendingLoad> load(loadEntry);
     754           0 :     load.forget(aPendingLoad);
     755           0 :     return nullptr;
     756             :   }
     757             : 
     758           0 :   RefPtr<PendingLoad> load(new PendingLoad(aDisplayDocument));
     759           0 :   loadEntry = load;
     760             : 
     761           0 :   if (NS_FAILED(load->StartLoad(clone, aRequestingNode))) {
     762             :     // Make sure we don't thrash things by trying this load again, since
     763             :     // chances are it failed for good reasons (security check, etc).
     764           0 :     AddExternalResource(clone, nullptr, nullptr, aDisplayDocument);
     765             :   } else {
     766           0 :     load.forget(aPendingLoad);
     767             :   }
     768             : 
     769           0 :   return nullptr;
     770             : }
     771             : 
     772             : void
     773         158 : nsExternalResourceMap::EnumerateResources(nsIDocument::nsSubDocEnumFunc aCallback,
     774             :                                           void* aData)
     775             : {
     776         158 :   for (auto iter = mMap.Iter(); !iter.Done(); iter.Next()) {
     777           0 :     nsExternalResourceMap::ExternalResource* resource = iter.UserData();
     778           0 :     if (resource->mDocument && !aCallback(resource->mDocument, aData)) {
     779           0 :       break;
     780             :     }
     781             :   }
     782         158 : }
     783             : 
     784             : void
     785          15 : nsExternalResourceMap::Traverse(nsCycleCollectionTraversalCallback* aCallback) const
     786             : {
     787             :   // mPendingLoads will get cleared out as the requests complete, so
     788             :   // no need to worry about those here.
     789          15 :   for (auto iter = mMap.ConstIter(); !iter.Done(); iter.Next()) {
     790           0 :     nsExternalResourceMap::ExternalResource* resource = iter.UserData();
     791             : 
     792             :     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCallback,
     793             :                                        "mExternalResourceMap.mMap entry"
     794           0 :                                        "->mDocument");
     795           0 :     aCallback->NoteXPCOMChild(resource->mDocument);
     796             : 
     797             :     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCallback,
     798             :                                        "mExternalResourceMap.mMap entry"
     799           0 :                                        "->mViewer");
     800           0 :     aCallback->NoteXPCOMChild(resource->mViewer);
     801             : 
     802             :     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCallback,
     803             :                                        "mExternalResourceMap.mMap entry"
     804           0 :                                        "->mLoadGroup");
     805           0 :     aCallback->NoteXPCOMChild(resource->mLoadGroup);
     806             :   }
     807          15 : }
     808             : 
     809             : void
     810           4 : nsExternalResourceMap::HideViewers()
     811             : {
     812           4 :   for (auto iter = mMap.Iter(); !iter.Done(); iter.Next()) {
     813           0 :     nsCOMPtr<nsIContentViewer> viewer = iter.UserData()->mViewer;
     814           0 :     if (viewer) {
     815           0 :       viewer->Hide();
     816             :     }
     817             :   }
     818           4 : }
     819             : 
     820             : void
     821          28 : nsExternalResourceMap::ShowViewers()
     822             : {
     823          28 :   for (auto iter = mMap.Iter(); !iter.Done(); iter.Next()) {
     824           0 :     nsCOMPtr<nsIContentViewer> viewer = iter.UserData()->mViewer;
     825           0 :     if (viewer) {
     826           0 :       viewer->Show();
     827             :     }
     828             :   }
     829          28 : }
     830             : 
     831             : void
     832           0 : TransferZoomLevels(nsIDocument* aFromDoc,
     833             :                    nsIDocument* aToDoc)
     834             : {
     835           0 :   MOZ_ASSERT(aFromDoc && aToDoc,
     836             :              "transferring zoom levels from/to null doc");
     837             : 
     838           0 :   nsIPresShell* fromShell = aFromDoc->GetShell();
     839           0 :   if (!fromShell)
     840           0 :     return;
     841             : 
     842           0 :   nsPresContext* fromCtxt = fromShell->GetPresContext();
     843           0 :   if (!fromCtxt)
     844           0 :     return;
     845             : 
     846           0 :   nsIPresShell* toShell = aToDoc->GetShell();
     847           0 :   if (!toShell)
     848           0 :     return;
     849             : 
     850           0 :   nsPresContext* toCtxt = toShell->GetPresContext();
     851           0 :   if (!toCtxt)
     852           0 :     return;
     853             : 
     854           0 :   toCtxt->SetFullZoom(fromCtxt->GetFullZoom());
     855           0 :   toCtxt->SetBaseMinFontSize(fromCtxt->BaseMinFontSize());
     856           0 :   toCtxt->SetTextZoom(fromCtxt->TextZoom());
     857           0 :   toCtxt->SetOverrideDPPX(fromCtxt->GetOverrideDPPX());
     858             : }
     859             : 
     860             : void
     861           0 : TransferShowingState(nsIDocument* aFromDoc, nsIDocument* aToDoc)
     862             : {
     863           0 :   MOZ_ASSERT(aFromDoc && aToDoc,
     864             :              "transferring showing state from/to null doc");
     865             : 
     866           0 :   if (aFromDoc->IsShowing()) {
     867           0 :     aToDoc->OnPageShow(true, nullptr);
     868             :   }
     869           0 : }
     870             : 
     871             : nsresult
     872           0 : nsExternalResourceMap::AddExternalResource(nsIURI* aURI,
     873             :                                            nsIContentViewer* aViewer,
     874             :                                            nsILoadGroup* aLoadGroup,
     875             :                                            nsIDocument* aDisplayDocument)
     876             : {
     877           0 :   NS_PRECONDITION(aURI, "Unexpected call");
     878           0 :   NS_PRECONDITION((aViewer && aLoadGroup) || (!aViewer && !aLoadGroup),
     879             :                   "Must have both or neither");
     880             : 
     881           0 :   RefPtr<PendingLoad> load;
     882           0 :   mPendingLoads.Remove(aURI, getter_AddRefs(load));
     883             : 
     884           0 :   nsresult rv = NS_OK;
     885             : 
     886           0 :   nsCOMPtr<nsIDocument> doc;
     887           0 :   if (aViewer) {
     888           0 :     doc = aViewer->GetDocument();
     889           0 :     NS_ASSERTION(doc, "Must have a document");
     890             : 
     891           0 :     nsCOMPtr<nsIXULDocument> xulDoc = do_QueryInterface(doc);
     892           0 :     if (xulDoc) {
     893             :       // We don't handle XUL stuff here yet.
     894           0 :       rv = NS_ERROR_NOT_AVAILABLE;
     895             :     } else {
     896           0 :       doc->SetDisplayDocument(aDisplayDocument);
     897             : 
     898             :       // Make sure that hiding our viewer will tear down its presentation.
     899           0 :       aViewer->SetSticky(false);
     900             : 
     901           0 :       rv = aViewer->Init(nullptr, nsIntRect(0, 0, 0, 0));
     902           0 :       if (NS_SUCCEEDED(rv)) {
     903           0 :         rv = aViewer->Open(nullptr, nullptr);
     904             :       }
     905             :     }
     906             : 
     907           0 :     if (NS_FAILED(rv)) {
     908           0 :       doc = nullptr;
     909           0 :       aViewer = nullptr;
     910           0 :       aLoadGroup = nullptr;
     911             :     }
     912             :   }
     913             : 
     914           0 :   ExternalResource* newResource = new ExternalResource();
     915           0 :   mMap.Put(aURI, newResource);
     916             : 
     917           0 :   newResource->mDocument = doc;
     918           0 :   newResource->mViewer = aViewer;
     919           0 :   newResource->mLoadGroup = aLoadGroup;
     920           0 :   if (doc) {
     921           0 :     TransferZoomLevels(aDisplayDocument, doc);
     922           0 :     TransferShowingState(aDisplayDocument, doc);
     923             :   }
     924             : 
     925           0 :   const nsTArray< nsCOMPtr<nsIObserver> > & obs = load->Observers();
     926           0 :   for (uint32_t i = 0; i < obs.Length(); ++i) {
     927           0 :     obs[i]->Observe(doc, "external-resource-document-created", nullptr);
     928             :   }
     929             : 
     930           0 :   return rv;
     931             : }
     932             : 
     933           0 : NS_IMPL_ISUPPORTS(nsExternalResourceMap::PendingLoad,
     934             :                   nsIStreamListener,
     935             :                   nsIRequestObserver)
     936             : 
     937             : NS_IMETHODIMP
     938           0 : nsExternalResourceMap::PendingLoad::OnStartRequest(nsIRequest *aRequest,
     939             :                                                    nsISupports *aContext)
     940             : {
     941           0 :   nsExternalResourceMap& map = mDisplayDocument->ExternalResourceMap();
     942           0 :   if (map.HaveShutDown()) {
     943           0 :     return NS_BINDING_ABORTED;
     944             :   }
     945             : 
     946           0 :   nsCOMPtr<nsIContentViewer> viewer;
     947           0 :   nsCOMPtr<nsILoadGroup> loadGroup;
     948           0 :   nsresult rv = SetupViewer(aRequest, getter_AddRefs(viewer),
     949           0 :                             getter_AddRefs(loadGroup));
     950             : 
     951             :   // Make sure to do this no matter what
     952           0 :   nsresult rv2 = map.AddExternalResource(mURI, viewer, loadGroup,
     953           0 :                                          mDisplayDocument);
     954           0 :   if (NS_FAILED(rv)) {
     955           0 :     return rv;
     956             :   }
     957           0 :   if (NS_FAILED(rv2)) {
     958           0 :     mTargetListener = nullptr;
     959           0 :     return rv2;
     960             :   }
     961             : 
     962           0 :   return mTargetListener->OnStartRequest(aRequest, aContext);
     963             : }
     964             : 
     965             : nsresult
     966           0 : nsExternalResourceMap::PendingLoad::SetupViewer(nsIRequest* aRequest,
     967             :                                                 nsIContentViewer** aViewer,
     968             :                                                 nsILoadGroup** aLoadGroup)
     969             : {
     970           0 :   NS_PRECONDITION(!mTargetListener, "Unexpected call to OnStartRequest");
     971           0 :   *aViewer = nullptr;
     972           0 :   *aLoadGroup = nullptr;
     973             : 
     974           0 :   nsCOMPtr<nsIChannel> chan(do_QueryInterface(aRequest));
     975           0 :   NS_ENSURE_TRUE(chan, NS_ERROR_UNEXPECTED);
     976             : 
     977           0 :   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aRequest));
     978           0 :   if (httpChannel) {
     979             :     bool requestSucceeded;
     980           0 :     if (NS_FAILED(httpChannel->GetRequestSucceeded(&requestSucceeded)) ||
     981           0 :         !requestSucceeded) {
     982             :       // Bail out on this load, since it looks like we have an HTTP error page
     983           0 :       return NS_BINDING_ABORTED;
     984             :     }
     985             :   }
     986             : 
     987           0 :   nsAutoCString type;
     988           0 :   chan->GetContentType(type);
     989             : 
     990           0 :   nsCOMPtr<nsILoadGroup> loadGroup;
     991           0 :   chan->GetLoadGroup(getter_AddRefs(loadGroup));
     992             : 
     993             :   // Give this document its own loadgroup
     994             :   nsCOMPtr<nsILoadGroup> newLoadGroup =
     995           0 :         do_CreateInstance(NS_LOADGROUP_CONTRACTID);
     996           0 :   NS_ENSURE_TRUE(newLoadGroup, NS_ERROR_OUT_OF_MEMORY);
     997           0 :   newLoadGroup->SetLoadGroup(loadGroup);
     998             : 
     999           0 :   nsCOMPtr<nsIInterfaceRequestor> callbacks;
    1000           0 :   loadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks));
    1001             : 
    1002             :   nsCOMPtr<nsIInterfaceRequestor> newCallbacks =
    1003           0 :     new LoadgroupCallbacks(callbacks);
    1004           0 :   newLoadGroup->SetNotificationCallbacks(newCallbacks);
    1005             : 
    1006             :   // This is some serious hackery cribbed from docshell
    1007             :   nsCOMPtr<nsICategoryManager> catMan =
    1008           0 :     do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
    1009           0 :   NS_ENSURE_TRUE(catMan, NS_ERROR_NOT_AVAILABLE);
    1010           0 :   nsXPIDLCString contractId;
    1011           0 :   nsresult rv = catMan->GetCategoryEntry("Gecko-Content-Viewers", type.get(),
    1012           0 :                                          getter_Copies(contractId));
    1013           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1014             :   nsCOMPtr<nsIDocumentLoaderFactory> docLoaderFactory =
    1015           0 :     do_GetService(contractId);
    1016           0 :   NS_ENSURE_TRUE(docLoaderFactory, NS_ERROR_NOT_AVAILABLE);
    1017             : 
    1018           0 :   nsCOMPtr<nsIContentViewer> viewer;
    1019           0 :   nsCOMPtr<nsIStreamListener> listener;
    1020           0 :   rv = docLoaderFactory->CreateInstance("external-resource", chan, newLoadGroup,
    1021             :                                         type, nullptr, nullptr,
    1022           0 :                                         getter_AddRefs(listener),
    1023           0 :                                         getter_AddRefs(viewer));
    1024           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1025           0 :   NS_ENSURE_TRUE(viewer, NS_ERROR_UNEXPECTED);
    1026             : 
    1027           0 :   nsCOMPtr<nsIParser> parser = do_QueryInterface(listener);
    1028           0 :   if (!parser) {
    1029             :     /// We don't want to deal with the various fake documents yet
    1030           0 :     return NS_ERROR_NOT_IMPLEMENTED;
    1031             :   }
    1032             : 
    1033             :   // We can't handle HTML and other weird things here yet.
    1034           0 :   nsIContentSink* sink = parser->GetContentSink();
    1035           0 :   nsCOMPtr<nsIXMLContentSink> xmlSink = do_QueryInterface(sink);
    1036           0 :   if (!xmlSink) {
    1037           0 :     return NS_ERROR_NOT_IMPLEMENTED;
    1038             :   }
    1039             : 
    1040           0 :   listener.swap(mTargetListener);
    1041           0 :   viewer.forget(aViewer);
    1042           0 :   newLoadGroup.forget(aLoadGroup);
    1043           0 :   return NS_OK;
    1044             : }
    1045             : 
    1046             : NS_IMETHODIMP
    1047           0 : nsExternalResourceMap::PendingLoad::OnDataAvailable(nsIRequest* aRequest,
    1048             :                                                     nsISupports* aContext,
    1049             :                                                     nsIInputStream* aStream,
    1050             :                                                     uint64_t aOffset,
    1051             :                                                     uint32_t aCount)
    1052             : {
    1053           0 :   NS_PRECONDITION(mTargetListener, "Shouldn't be getting called!");
    1054           0 :   if (mDisplayDocument->ExternalResourceMap().HaveShutDown()) {
    1055           0 :     return NS_BINDING_ABORTED;
    1056             :   }
    1057           0 :   return mTargetListener->OnDataAvailable(aRequest, aContext, aStream, aOffset,
    1058           0 :                                           aCount);
    1059             : }
    1060             : 
    1061             : NS_IMETHODIMP
    1062           0 : nsExternalResourceMap::PendingLoad::OnStopRequest(nsIRequest* aRequest,
    1063             :                                                   nsISupports* aContext,
    1064             :                                                   nsresult aStatus)
    1065             : {
    1066             :   // mTargetListener might be null if SetupViewer or AddExternalResource failed
    1067           0 :   if (mTargetListener) {
    1068           0 :     nsCOMPtr<nsIStreamListener> listener;
    1069           0 :     mTargetListener.swap(listener);
    1070           0 :     return listener->OnStopRequest(aRequest, aContext, aStatus);
    1071             :   }
    1072             : 
    1073           0 :   return NS_OK;
    1074             : }
    1075             : 
    1076             : nsresult
    1077           0 : nsExternalResourceMap::PendingLoad::StartLoad(nsIURI* aURI,
    1078             :                                               nsINode* aRequestingNode)
    1079             : {
    1080           0 :   NS_PRECONDITION(aURI, "Must have a URI");
    1081           0 :   NS_PRECONDITION(aRequestingNode, "Must have a node");
    1082             : 
    1083             :   nsCOMPtr<nsILoadGroup> loadGroup =
    1084           0 :     aRequestingNode->OwnerDoc()->GetDocumentLoadGroup();
    1085             : 
    1086           0 :   nsresult rv = NS_OK;
    1087           0 :   nsCOMPtr<nsIChannel> channel;
    1088           0 :   rv = NS_NewChannel(getter_AddRefs(channel),
    1089             :                      aURI,
    1090             :                      aRequestingNode,
    1091             :                      nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS,
    1092             :                      nsIContentPolicy::TYPE_OTHER,
    1093           0 :                      loadGroup);
    1094           0 :   NS_ENSURE_SUCCESS(rv, rv);
    1095             : 
    1096           0 :   mURI = aURI;
    1097             : 
    1098           0 :   return channel->AsyncOpen2(this);
    1099             : }
    1100             : 
    1101           0 : NS_IMPL_ISUPPORTS(nsExternalResourceMap::LoadgroupCallbacks,
    1102             :                   nsIInterfaceRequestor)
    1103             : 
    1104             : #define IMPL_SHIM(_i) \
    1105             :   NS_IMPL_ISUPPORTS(nsExternalResourceMap::LoadgroupCallbacks::_i##Shim, _i)
    1106             : 
    1107           0 : IMPL_SHIM(nsILoadContext)
    1108           0 : IMPL_SHIM(nsIProgressEventSink)
    1109           0 : IMPL_SHIM(nsIChannelEventSink)
    1110           0 : IMPL_SHIM(nsISecurityEventSink)
    1111           0 : IMPL_SHIM(nsIApplicationCacheContainer)
    1112             : 
    1113             : #undef IMPL_SHIM
    1114             : 
    1115             : #define IID_IS(_i) aIID.Equals(NS_GET_IID(_i))
    1116             : 
    1117             : #define TRY_SHIM(_i)                                                       \
    1118             :   PR_BEGIN_MACRO                                                           \
    1119             :     if (IID_IS(_i)) {                                                      \
    1120             :       nsCOMPtr<_i> real = do_GetInterface(mCallbacks);                     \
    1121             :       if (!real) {                                                         \
    1122             :         return NS_NOINTERFACE;                                             \
    1123             :       }                                                                    \
    1124             :       nsCOMPtr<_i> shim = new _i##Shim(this, real);                        \
    1125             :       shim.forget(aSink);                                                  \
    1126             :       return NS_OK;                                                        \
    1127             :     }                                                                      \
    1128             :   PR_END_MACRO
    1129             : 
    1130             : NS_IMETHODIMP
    1131           0 : nsExternalResourceMap::LoadgroupCallbacks::GetInterface(const nsIID & aIID,
    1132             :                                                         void **aSink)
    1133             : {
    1134           0 :   if (mCallbacks &&
    1135           0 :       (IID_IS(nsIPrompt) || IID_IS(nsIAuthPrompt) || IID_IS(nsIAuthPrompt2) ||
    1136           0 :        IID_IS(nsITabChild))) {
    1137           0 :     return mCallbacks->GetInterface(aIID, aSink);
    1138             :   }
    1139             : 
    1140           0 :   *aSink = nullptr;
    1141             : 
    1142           0 :   TRY_SHIM(nsILoadContext);
    1143           0 :   TRY_SHIM(nsIProgressEventSink);
    1144           0 :   TRY_SHIM(nsIChannelEventSink);
    1145           0 :   TRY_SHIM(nsISecurityEventSink);
    1146           0 :   TRY_SHIM(nsIApplicationCacheContainer);
    1147             : 
    1148           0 :   return NS_NOINTERFACE;
    1149             : }
    1150             : 
    1151             : #undef TRY_SHIM
    1152             : #undef IID_IS
    1153             : 
    1154           0 : nsExternalResourceMap::ExternalResource::~ExternalResource()
    1155             : {
    1156           0 :   if (mViewer) {
    1157           0 :     mViewer->Close(nullptr);
    1158           0 :     mViewer->Destroy();
    1159             :   }
    1160           0 : }
    1161             : 
    1162             : // ==================================================================
    1163             : // =
    1164             : // ==================================================================
    1165             : 
    1166             : // If we ever have an nsIDocumentObserver notification for stylesheet title
    1167             : // changes we should update the list from that instead of overriding
    1168             : // EnsureFresh.
    1169           0 : class nsDOMStyleSheetSetList final : public DOMStringList
    1170             : {
    1171             : public:
    1172             :   explicit nsDOMStyleSheetSetList(nsIDocument* aDocument);
    1173             : 
    1174           0 :   void Disconnect()
    1175             :   {
    1176           0 :     mDocument = nullptr;
    1177           0 :   }
    1178             : 
    1179             :   virtual void EnsureFresh() override;
    1180             : 
    1181             : protected:
    1182             :   nsIDocument* mDocument;  // Our document; weak ref.  It'll let us know if it
    1183             :                            // dies.
    1184             : };
    1185             : 
    1186           0 : nsDOMStyleSheetSetList::nsDOMStyleSheetSetList(nsIDocument* aDocument)
    1187           0 :   : mDocument(aDocument)
    1188             : {
    1189           0 :   NS_ASSERTION(mDocument, "Must have document!");
    1190           0 : }
    1191             : 
    1192             : void
    1193           0 : nsDOMStyleSheetSetList::EnsureFresh()
    1194             : {
    1195           0 :   MOZ_ASSERT(NS_IsMainThread());
    1196             : 
    1197           0 :   mNames.Clear();
    1198             : 
    1199           0 :   if (!mDocument) {
    1200           0 :     return; // Spec says "no exceptions", and we have no style sets if we have
    1201             :             // no document, for sure
    1202             :   }
    1203             : 
    1204           0 :   int32_t count = mDocument->GetNumberOfStyleSheets();
    1205           0 :   nsAutoString title;
    1206           0 :   for (int32_t index = 0; index < count; index++) {
    1207           0 :     StyleSheet* sheet = mDocument->GetStyleSheetAt(index);
    1208           0 :     NS_ASSERTION(sheet, "Null sheet in sheet list!");
    1209           0 :     sheet->GetTitle(title);
    1210           0 :     if (!title.IsEmpty() && !mNames.Contains(title) && !Add(title)) {
    1211           0 :       return;
    1212             :     }
    1213             :   }
    1214             : }
    1215             : 
    1216             : // ==================================================================
    1217           2 : nsIDocument::SelectorCache::SelectorCache(nsIEventTarget* aEventTarget)
    1218             :   : nsExpirationTracker<SelectorCacheKey, 4>(
    1219           2 :       1000, "nsIDocument::SelectorCache", aEventTarget)
    1220           2 : { }
    1221             : 
    1222           0 : nsIDocument::SelectorCache::~SelectorCache()
    1223             : {
    1224           0 :   AgeAllGenerations();
    1225           0 : }
    1226             : 
    1227             : // CacheList takes ownership of aSelectorList.
    1228           7 : void nsIDocument::SelectorCache::CacheList(const nsAString& aSelector,
    1229             :                                            nsCSSSelectorList* aSelectorList)
    1230             : {
    1231           7 :   MOZ_ASSERT(NS_IsMainThread());
    1232           7 :   SelectorCacheKey* key = new SelectorCacheKey(aSelector);
    1233           7 :   mTable.Put(key->mKey, aSelectorList);
    1234           7 :   AddObject(key);
    1235           7 : }
    1236             : 
    1237           0 : void nsIDocument::SelectorCache::NotifyExpired(SelectorCacheKey* aSelector)
    1238             : {
    1239           0 :   MOZ_ASSERT(NS_IsMainThread());
    1240           0 :   MOZ_ASSERT(aSelector);
    1241             : 
    1242             :   // There is no guarantee that this method won't be re-entered when selector
    1243             :   // matching is ongoing because "memory-pressure" could be notified immediately
    1244             :   // when OOM happens according to the design of nsExpirationTracker.
    1245             :   // The perfect solution is to delete the |aSelector| and its nsCSSSelectorList
    1246             :   // in mTable asynchronously.
    1247             :   // We remove these objects synchronously for now because NotifiyExpired() will
    1248             :   // never be triggered by "memory-pressure" which is not implemented yet in
    1249             :   // the stage 2 of mozalloc_handle_oom().
    1250             :   // Once these objects are removed asynchronously, we should update the warning
    1251             :   // added in mozalloc_handle_oom() as well.
    1252           0 :   RemoveObject(aSelector);
    1253           0 :   mTable.Remove(aSelector->mKey);
    1254           0 :   delete aSelector;
    1255           0 : }
    1256             : 
    1257          12 : struct nsIDocument::FrameRequest
    1258             : {
    1259           4 :   FrameRequest(FrameRequestCallback& aCallback,
    1260           4 :                int32_t aHandle) :
    1261             :     mCallback(&aCallback),
    1262           4 :     mHandle(aHandle)
    1263           4 :   {}
    1264             : 
    1265             :   // Conversion operator so that we can append these to a
    1266             :   // FrameRequestCallbackList
    1267           4 :   operator const RefPtr<FrameRequestCallback>& () const {
    1268           4 :     return mCallback;
    1269             :   }
    1270             : 
    1271             :   // Comparator operators to allow RemoveElementSorted with an
    1272             :   // integer argument on arrays of FrameRequest
    1273           0 :   bool operator==(int32_t aHandle) const {
    1274           0 :     return mHandle == aHandle;
    1275             :   }
    1276           0 :   bool operator<(int32_t aHandle) const {
    1277           0 :     return mHandle < aHandle;
    1278             :   }
    1279             : 
    1280             :   RefPtr<FrameRequestCallback> mCallback;
    1281             :   int32_t mHandle;
    1282             : };
    1283             : 
    1284           3 : static already_AddRefed<mozilla::dom::NodeInfo> nullNodeInfo;
    1285             : 
    1286             : // ==================================================================
    1287             : // =
    1288             : // ==================================================================
    1289          55 : nsIDocument::nsIDocument()
    1290             :   : nsINode(nullNodeInfo),
    1291             :     mReferrerPolicySet(false),
    1292             :     mReferrerPolicy(mozilla::net::RP_Unset),
    1293             :     mBlockAllMixedContent(false),
    1294             :     mBlockAllMixedContentPreloads(false),
    1295             :     mUpgradeInsecureRequests(false),
    1296             :     mUpgradeInsecurePreloads(false),
    1297             :     mCharacterSet(WINDOWS_1252_ENCODING),
    1298             :     mCharacterSetSource(0),
    1299             :     mParentDocument(nullptr),
    1300             :     mCachedRootElement(nullptr),
    1301             :     mNodeInfoManager(nullptr),
    1302             :     mBidiEnabled(false),
    1303             :     mMathMLEnabled(false),
    1304             :     mIsInitialDocumentInWindow(false),
    1305             :     mIgnoreDocGroupMismatches(false),
    1306             :     mLoadedAsData(false),
    1307             :     mLoadedAsInteractiveData(false),
    1308             :     mMayStartLayout(true),
    1309             :     mHaveFiredTitleChange(false),
    1310             :     mIsShowing(false),
    1311             :     mVisible(true),
    1312             :     mHasReferrerPolicyCSP(false),
    1313             :     mRemovedFromDocShell(false),
    1314             :     // mAllowDNSPrefetch starts true, so that we can always reliably && it
    1315             :     // with various values that might disable it.  Since we never prefetch
    1316             :     // unless we get a window, and in that case the docshell value will get
    1317             :     // &&-ed in, this is safe.
    1318             :     mAllowDNSPrefetch(true),
    1319             :     mIsStaticDocument(false),
    1320             :     mCreatingStaticClone(false),
    1321             :     mInUnlinkOrDeletion(false),
    1322             :     mHasHadScriptHandlingObject(false),
    1323             :     mIsBeingUsedAsImage(false),
    1324             :     mIsSyntheticDocument(false),
    1325             :     mHasLinksToUpdate(false),
    1326             :     mHasLinksToUpdateRunnable(false),
    1327             :     mMayHaveDOMMutationObservers(false),
    1328             :     mMayHaveAnimationObservers(false),
    1329             :     mHasMixedActiveContentLoaded(false),
    1330             :     mHasMixedActiveContentBlocked(false),
    1331             :     mHasMixedDisplayContentLoaded(false),
    1332             :     mHasMixedDisplayContentBlocked(false),
    1333             :     mHasMixedContentObjectSubrequest(false),
    1334             :     mHasCSP(false),
    1335             :     mHasUnsafeEvalCSP(false),
    1336             :     mHasUnsafeInlineCSP(false),
    1337             :     mHasTrackingContentBlocked(false),
    1338             :     mHasTrackingContentLoaded(false),
    1339             :     mBFCacheDisallowed(false),
    1340             :     mHasHadDefaultView(false),
    1341             :     mStyleSheetChangeEventsEnabled(false),
    1342             :     mIsSrcdocDocument(false),
    1343             :     mDidDocumentOpen(false),
    1344             :     mHasDisplayDocument(false),
    1345             :     mFontFaceSetDirty(true),
    1346             :     mGetUserFontSetCalled(false),
    1347             :     mPostedFlushUserFontSet(false),
    1348             :     mDidFireDOMContentLoaded(true),
    1349             :     mHasScrollLinkedEffect(false),
    1350             :     mFrameRequestCallbacksScheduled(false),
    1351             :     mIsTopLevelContentDocument(false),
    1352             :     mIsContentDocument(false),
    1353             :     mIsScopedStyleEnabled(eScopedStyle_Unknown),
    1354             :     mCompatMode(eCompatibility_FullStandards),
    1355             :     mReadyState(ReadyState::READYSTATE_UNINITIALIZED),
    1356             :     mStyleBackendType(StyleBackendType::None),
    1357             : #ifdef MOZILLA_INTERNAL_API
    1358             :     mVisibilityState(dom::VisibilityState::Hidden),
    1359             : #else
    1360             :     mDummy(0),
    1361             : #endif
    1362             :     mType(eUnknown),
    1363             :     mDefaultElementType(0),
    1364             :     mAllowXULXBL(eTriUnset),
    1365             : #ifdef DEBUG
    1366             :     mIsLinkUpdateRegistrationsForbidden(false),
    1367             : #endif
    1368             :     mBidiOptions(IBMBIDI_DEFAULT_BIDI_OPTIONS),
    1369             :     mSandboxFlags(0),
    1370             :     mPartID(0),
    1371             :     mMarkedCCGeneration(0),
    1372             :     mPresShell(nullptr),
    1373             :     mSubtreeModifiedDepth(0),
    1374             :     mEventsSuppressed(0),
    1375             :     mExternalScriptsBeingEvaluated(0),
    1376             :     mFrameRequestCallbackCounter(0),
    1377             :     mStaticCloneCount(0),
    1378             :     mWindow(nullptr),
    1379             :     mBFCacheEntry(nullptr),
    1380             :     mInSyncOperationCount(0),
    1381             :     mBlockDOMContentLoaded(0),
    1382             :     mUseCounters(0),
    1383             :     mChildDocumentUseCounters(0),
    1384             :     mNotifiedPageForUseCounter(0),
    1385             :     mIncCounters(),
    1386          55 :     mUserHasInteracted(false)
    1387             : {
    1388          55 :   SetIsInDocument();
    1389         110 :   for (auto& cnt : mIncCounters) {
    1390          55 :     cnt = 0;
    1391             :   }
    1392          55 : }
    1393             : 
    1394          55 : nsDocument::nsDocument(const char* aContentType)
    1395             :   : nsIDocument()
    1396             :   , mSubDocuments(nullptr)
    1397             :   , mFlashClassification(FlashClassification::Unclassified)
    1398             :   , mHeaderData(nullptr)
    1399             :   , mIsGoingAway(false)
    1400             :   , mInDestructor(false)
    1401             :   , mMayHaveTitleElement(false)
    1402             :   , mHasWarnedAboutBoxObjects(false)
    1403             :   , mDelayFrameLoaderInitialization(false)
    1404             :   , mSynchronousDOMContentLoaded(false)
    1405             :   , mInXBLUpdate(false)
    1406             :   , mParserAborted(false)
    1407             :   , mCurrentOrientationAngle(0)
    1408             :   , mCurrentOrientationType(OrientationType::Portrait_primary)
    1409             :   , mSSApplicableStateNotificationPending(false)
    1410             :   , mReportedUseCounters(false)
    1411             :   , mStyleSetFilled(false)
    1412             :   , mPendingFullscreenRequests(0)
    1413             :   , mXMLDeclarationBits(0)
    1414             :   , mBoxObjectTable(nullptr)
    1415             :   , mUpdateNestLevel(0)
    1416             :   , mOnloadBlockCount(0)
    1417             :   , mAsyncOnloadBlockCount(0)
    1418             : #ifdef DEBUG
    1419             :   , mStyledLinksCleared(false)
    1420             : #endif
    1421             :   , mPreloadPictureDepth(0)
    1422             :   , mScrolledToRefAlready(0)
    1423             :   , mChangeScrollPosWhenScrollingToRef(0)
    1424             :   , mViewportType(Unknown)
    1425             :   , mValidWidth(false)
    1426             :   , mValidHeight(false)
    1427             :   , mAutoSize(false)
    1428             :   , mAllowZoom(false)
    1429             :   , mAllowDoubleTapZoom(false)
    1430             :   , mValidScaleFloat(false)
    1431             :   , mValidMaxScale(false)
    1432             :   , mScaleStrEmpty(false)
    1433             :   , mWidthStrEmpty(false)
    1434             :   , mStackRefCnt(0)
    1435             :   , mNeedsReleaseAfterStackRefCntRelease(false)
    1436             :   , mMaybeServiceWorkerControlled(false)
    1437             : #ifdef DEBUG
    1438          55 :   , mWillReparent(false)
    1439             : #endif
    1440             : {
    1441          55 :   SetContentTypeInternal(nsDependentCString(aContentType));
    1442             : 
    1443          55 :   MOZ_LOG(gDocumentLeakPRLog, LogLevel::Debug, ("DOCUMENT %p created", this));
    1444             : 
    1445             :   // Start out mLastStyleSheetSet as null, per spec
    1446          55 :   SetDOMStringToNull(mLastStyleSheetSet);
    1447             : 
    1448             :   // void state used to differentiate an empty source from an unselected source
    1449          55 :   mPreloadPictureFoundSource.SetIsVoid(true);
    1450          55 : }
    1451             : 
    1452             : void
    1453           0 : nsDocument::ClearAllBoxObjects()
    1454             : {
    1455           0 :   if (mBoxObjectTable) {
    1456           0 :     for (auto iter = mBoxObjectTable->Iter(); !iter.Done(); iter.Next()) {
    1457           0 :       nsPIBoxObject* boxObject = iter.UserData();
    1458           0 :       if (boxObject) {
    1459           0 :         boxObject->Clear();
    1460             :       }
    1461             :     }
    1462           0 :     delete mBoxObjectTable;
    1463           0 :     mBoxObjectTable = nullptr;
    1464             :   }
    1465           0 : }
    1466             : 
    1467           0 : nsIDocument::~nsIDocument()
    1468             : {
    1469           0 :   MOZ_ASSERT(mDOMMediaQueryLists.isEmpty(),
    1470             :              "must not have media query lists left");
    1471             : 
    1472           0 :   if (mNodeInfoManager) {
    1473           0 :     mNodeInfoManager->DropDocumentReference();
    1474             :   }
    1475             : 
    1476           0 :   if (mDocGroup) {
    1477           0 :     mDocGroup->RemoveDocument(this);
    1478             :   }
    1479             : 
    1480           0 :   UnlinkOriginalDocumentIfStatic();
    1481           0 : }
    1482             : 
    1483             : bool
    1484           0 : nsDocument::IsAboutPage() const
    1485             : {
    1486           0 :   nsCOMPtr<nsIPrincipal> principal = NodePrincipal();
    1487           0 :   nsCOMPtr<nsIURI> uri;
    1488           0 :   principal->GetURI(getter_AddRefs(uri));
    1489           0 :   bool isAboutScheme = true;
    1490           0 :   if (uri) {
    1491           0 :     uri->SchemeIs("about", &isAboutScheme);
    1492             :   }
    1493           0 :   return isAboutScheme;
    1494             : }
    1495             : 
    1496           0 : nsDocument::~nsDocument()
    1497             : {
    1498           0 :   MOZ_LOG(gDocumentLeakPRLog, LogLevel::Debug, ("DOCUMENT %p destroyed", this));
    1499             : 
    1500           0 :   NS_ASSERTION(!mIsShowing, "Destroying a currently-showing document");
    1501             : 
    1502           0 :   if (IsTopLevelContentDocument()) {
    1503             :     //don't report for about: pages
    1504           0 :     if (!IsAboutPage()) {
    1505             :       // Record the page load
    1506           0 :       uint32_t pageLoaded = 1;
    1507           0 :       Accumulate(Telemetry::MIXED_CONTENT_UNBLOCK_COUNTER, pageLoaded);
    1508             :       // Record the mixed content status of the docshell in Telemetry
    1509             :       enum {
    1510             :         NO_MIXED_CONTENT = 0, // There is no Mixed Content on the page
    1511             :         MIXED_DISPLAY_CONTENT = 1, // The page attempted to load Mixed Display Content
    1512             :         MIXED_ACTIVE_CONTENT = 2, // The page attempted to load Mixed Active Content
    1513             :         MIXED_DISPLAY_AND_ACTIVE_CONTENT = 3 // The page attempted to load Mixed Display & Mixed Active Content
    1514             :       };
    1515             : 
    1516           0 :       bool mixedActiveLoaded = GetHasMixedActiveContentLoaded();
    1517           0 :       bool mixedActiveBlocked = GetHasMixedActiveContentBlocked();
    1518             : 
    1519           0 :       bool mixedDisplayLoaded = GetHasMixedDisplayContentLoaded();
    1520           0 :       bool mixedDisplayBlocked = GetHasMixedDisplayContentBlocked();
    1521             : 
    1522           0 :       bool hasMixedDisplay = (mixedDisplayBlocked || mixedDisplayLoaded);
    1523           0 :       bool hasMixedActive = (mixedActiveBlocked || mixedActiveLoaded);
    1524             : 
    1525           0 :       uint32_t mixedContentLevel = NO_MIXED_CONTENT;
    1526           0 :       if (hasMixedDisplay && hasMixedActive) {
    1527           0 :         mixedContentLevel = MIXED_DISPLAY_AND_ACTIVE_CONTENT;
    1528           0 :       } else if (hasMixedActive){
    1529           0 :         mixedContentLevel = MIXED_ACTIVE_CONTENT;
    1530           0 :       } else if (hasMixedDisplay) {
    1531           0 :         mixedContentLevel = MIXED_DISPLAY_CONTENT;
    1532             :       }
    1533           0 :       Accumulate(Telemetry::MIXED_CONTENT_PAGE_LOAD, mixedContentLevel);
    1534             : 
    1535             :       // record mixed object subrequest telemetry
    1536           0 :       if (mHasMixedContentObjectSubrequest) {
    1537             :         /* mixed object subrequest loaded on page*/
    1538           0 :         Accumulate(Telemetry::MIXED_CONTENT_OBJECT_SUBREQUEST, 1);
    1539             :       } else {
    1540             :         /* no mixed object subrequests loaded on page*/
    1541           0 :         Accumulate(Telemetry::MIXED_CONTENT_OBJECT_SUBREQUEST, 0);
    1542             :       }
    1543             : 
    1544             :       // record CSP telemetry on this document
    1545           0 :       if (mHasCSP) {
    1546           0 :         Accumulate(Telemetry::CSP_DOCUMENTS_COUNT, 1);
    1547           0 :         Accumulate(Telemetry::CSP_REFERRER_DIRECTIVE, mHasReferrerPolicyCSP);
    1548             :       }
    1549           0 :       if (mHasUnsafeInlineCSP) {
    1550           0 :         Accumulate(Telemetry::CSP_UNSAFE_INLINE_DOCUMENTS_COUNT, 1);
    1551             :       }
    1552           0 :       if (mHasUnsafeEvalCSP) {
    1553           0 :         Accumulate(Telemetry::CSP_UNSAFE_EVAL_DOCUMENTS_COUNT, 1);
    1554             :       }
    1555             :     }
    1556             :   }
    1557             : 
    1558           0 :   ReportUseCounters();
    1559             : 
    1560           0 :   mInDestructor = true;
    1561           0 :   mInUnlinkOrDeletion = true;
    1562             : 
    1563           0 :   mozilla::DropJSObjects(this);
    1564             : 
    1565             :   // Clear mObservers to keep it in sync with the mutationobserver list
    1566           0 :   mObservers.Clear();
    1567             : 
    1568           0 :   mIntersectionObservers.Clear();
    1569             : 
    1570           0 :   if (mStyleSheetSetList) {
    1571           0 :     mStyleSheetSetList->Disconnect();
    1572             :   }
    1573             : 
    1574           0 :   if (mAnimationController) {
    1575           0 :     mAnimationController->Disconnect();
    1576             :   }
    1577             : 
    1578           0 :   MOZ_ASSERT(mTimelines.isEmpty());
    1579             : 
    1580           0 :   mParentDocument = nullptr;
    1581             : 
    1582             :   // Kill the subdocument map, doing this will release its strong
    1583             :   // references, if any.
    1584           0 :   delete mSubDocuments;
    1585           0 :   mSubDocuments = nullptr;
    1586             : 
    1587             :   // Destroy link map now so we don't waste time removing
    1588             :   // links one by one
    1589           0 :   DestroyElementMaps();
    1590             : 
    1591           0 :   nsAutoScriptBlocker scriptBlocker;
    1592             : 
    1593           0 :   for (uint32_t indx = mChildren.ChildCount(); indx-- != 0; ) {
    1594           0 :     mChildren.ChildAt(indx)->UnbindFromTree();
    1595           0 :     mChildren.RemoveChildAt(indx);
    1596             :   }
    1597           0 :   mFirstChild = nullptr;
    1598           0 :   mCachedRootElement = nullptr;
    1599             : 
    1600             :   // Let the stylesheets know we're going away
    1601           0 :   for (StyleSheet* sheet : mStyleSheets) {
    1602           0 :     sheet->ClearAssociatedDocument();
    1603             :   }
    1604           0 :   for (auto& sheets : mAdditionalSheets) {
    1605           0 :     for (StyleSheet* sheet : sheets) {
    1606           0 :       sheet->ClearAssociatedDocument();
    1607             :     }
    1608             :   }
    1609           0 :   if (mAttrStyleSheet) {
    1610           0 :     mAttrStyleSheet->SetOwningDocument(nullptr);
    1611             :   }
    1612             :   // We don't own the mOnDemandBuiltInUASheets, so we don't need to reset them.
    1613             : 
    1614           0 :   if (mListenerManager) {
    1615           0 :     mListenerManager->Disconnect();
    1616           0 :     UnsetFlags(NODE_HAS_LISTENERMANAGER);
    1617             :   }
    1618             : 
    1619           0 :   if (mScriptLoader) {
    1620           0 :     mScriptLoader->DropDocumentReference();
    1621             :   }
    1622             : 
    1623           0 :   if (mCSSLoader) {
    1624             :     // Could be null here if Init() failed or if we have been unlinked.
    1625           0 :     mCSSLoader->DropDocumentReference();
    1626             :   }
    1627             : 
    1628           0 :   if (mStyleImageLoader) {
    1629           0 :     mStyleImageLoader->DropDocumentReference();
    1630             :   }
    1631             : 
    1632           0 :   delete mHeaderData;
    1633             : 
    1634           0 :   ClearAllBoxObjects();
    1635             : 
    1636           0 :   mPendingTitleChangeEvent.Revoke();
    1637             : 
    1638           0 :   mPlugins.Clear();
    1639           0 : }
    1640             : 
    1641       10464 : NS_INTERFACE_TABLE_HEAD(nsDocument)
    1642       10464 :   NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
    1643             :   NS_INTERFACE_TABLE_BEGIN
    1644             :     NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(nsDocument, nsISupports, nsINode)
    1645             :     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsINode)
    1646             :     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDocument)
    1647             :     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOMDocument)
    1648             :     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOMNode)
    1649             :     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOMDocumentXBL)
    1650             :     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIScriptObjectPrincipal)
    1651             :     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOMEventTarget)
    1652             :     NS_INTERFACE_TABLE_ENTRY(nsDocument, mozilla::dom::EventTarget)
    1653             :     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsISupportsWeakReference)
    1654             :     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIRadioGroupContainer)
    1655             :     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIMutationObserver)
    1656             :     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIApplicationCacheContainer)
    1657             :     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIObserver)
    1658             :     NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOMXPathEvaluator)
    1659       10444 :   NS_INTERFACE_TABLE_END
    1660       10444 :   NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsDocument)
    1661         981 : NS_INTERFACE_MAP_END
    1662             : 
    1663             : 
    1664       17801 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDocument)
    1665             : NS_IMETHODIMP_(MozExternalRefCountType)
    1666       17413 : nsDocument::Release()
    1667             : {
    1668       17413 :   NS_PRECONDITION(0 != mRefCnt, "dup release");
    1669       17413 :   NS_ASSERT_OWNINGTHREAD(nsDocument);
    1670       17413 :   nsISupports* base = NS_CYCLE_COLLECTION_CLASSNAME(nsDocument)::Upcast(this);
    1671       17413 :   bool shouldDelete = false;
    1672       17413 :   nsrefcnt count = mRefCnt.decr(base, &shouldDelete);
    1673       17413 :   NS_LOG_RELEASE(this, count, "nsDocument");
    1674       17413 :   if (count == 0) {
    1675           0 :     if (mStackRefCnt && !mNeedsReleaseAfterStackRefCntRelease) {
    1676           0 :       mNeedsReleaseAfterStackRefCntRelease = true;
    1677           0 :       NS_ADDREF_THIS();
    1678           0 :       return mRefCnt.get();
    1679             :     }
    1680           0 :     mRefCnt.incr(base);
    1681           0 :     nsNodeUtils::LastRelease(this);
    1682           0 :     mRefCnt.decr(base);
    1683           0 :     if (shouldDelete) {
    1684           0 :       mRefCnt.stabilizeForDeletion();
    1685           0 :       DeleteCycleCollectable();
    1686             :     }
    1687             :   }
    1688       17413 :   return count;
    1689             : }
    1690             : 
    1691             : NS_IMETHODIMP_(void)
    1692           0 : nsDocument::DeleteCycleCollectable()
    1693             : {
    1694           0 :   delete this;
    1695           0 : }
    1696             : 
    1697           0 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsDocument)
    1698           0 :   if (Element::CanSkip(tmp, aRemovingAllowed)) {
    1699           0 :     EventListenerManager* elm = tmp->GetExistingListenerManager();
    1700           0 :     if (elm) {
    1701           0 :       elm->MarkForCC();
    1702             :     }
    1703           0 :     return true;
    1704             :   }
    1705           0 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
    1706             : 
    1707           0 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsDocument)
    1708           0 :   return Element::CanSkipInCC(tmp);
    1709             : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
    1710             : 
    1711           0 : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsDocument)
    1712           0 :   return Element::CanSkipThis(tmp);
    1713             : NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
    1714             : 
    1715             : static const char* kNSURIs[] = {
    1716             :   "([none])",
    1717             :   "(xmlns)",
    1718             :   "(xml)",
    1719             :   "(xhtml)",
    1720             :   "(XLink)",
    1721             :   "(XSLT)",
    1722             :   "(XBL)",
    1723             :   "(MathML)",
    1724             :   "(RDF)",
    1725             :   "(XUL)"
    1726             : };
    1727             : 
    1728          15 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsDocument)
    1729          15 :   if (MOZ_UNLIKELY(cb.WantDebugInfo())) {
    1730             :     char name[512];
    1731           0 :     nsAutoCString loadedAsData;
    1732           0 :     if (tmp->IsLoadedAsData()) {
    1733           0 :       loadedAsData.AssignLiteral("data");
    1734             :     } else {
    1735           0 :       loadedAsData.AssignLiteral("normal");
    1736             :     }
    1737           0 :     uint32_t nsid = tmp->GetDefaultNamespaceID();
    1738           0 :     nsAutoCString uri;
    1739           0 :     if (tmp->mDocumentURI)
    1740           0 :       uri = tmp->mDocumentURI->GetSpecOrDefault();
    1741           0 :     if (nsid < ArrayLength(kNSURIs)) {
    1742           0 :       SprintfLiteral(name, "nsDocument %s %s %s",
    1743           0 :                      loadedAsData.get(), kNSURIs[nsid], uri.get());
    1744             :     }
    1745             :     else {
    1746           0 :       SprintfLiteral(name, "nsDocument %s %s",
    1747           0 :                      loadedAsData.get(), uri.get());
    1748             :     }
    1749           0 :     cb.DescribeRefCountedNode(tmp->mRefCnt.get(), name);
    1750             :   }
    1751             :   else {
    1752          15 :     NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsDocument, tmp->mRefCnt.get())
    1753             :   }
    1754             : 
    1755          15 :   if (!nsINode::Traverse(tmp, cb)) {
    1756           0 :     return NS_SUCCESS_INTERRUPTED_TRAVERSE;
    1757             :   }
    1758             : 
    1759          15 :   if (tmp->mMaybeEndOutermostXBLUpdateRunner) {
    1760             :     // The cached runnable keeps a reference to the document object..
    1761             :     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
    1762           0 :                                        "mMaybeEndOutermostXBLUpdateRunner.mObj");
    1763           0 :     cb.NoteXPCOMChild(ToSupports(tmp));
    1764             :   }
    1765             : 
    1766          15 :   for (auto iter = tmp->mIdentifierMap.ConstIter(); !iter.Done();
    1767           0 :        iter.Next()) {
    1768           0 :     iter.Get()->Traverse(&cb);
    1769             :   }
    1770             : 
    1771          15 :   tmp->mExternalResourceMap.Traverse(&cb);
    1772             : 
    1773             :   // Traverse the mChildren nsAttrAndChildArray.
    1774          25 :   for (int32_t indx = int32_t(tmp->mChildren.ChildCount()); indx > 0; --indx) {
    1775          10 :     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mChildren[i]");
    1776          10 :     cb.NoteXPCOMChild(tmp->mChildren.ChildAt(indx - 1));
    1777             :   }
    1778             : 
    1779             :   // Traverse all nsIDocument pointer members.
    1780          15 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSecurityInfo)
    1781          15 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDisplayDocument)
    1782          15 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFontFaceSet)
    1783             : 
    1784             :   // Traverse all nsDocument nsCOMPtrs.
    1785          15 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParser)
    1786          15 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScriptGlobalObject)
    1787          15 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListenerManager)
    1788          15 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMStyleSheets)
    1789          15 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheetSetList)
    1790          15 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScriptLoader)
    1791             : 
    1792          15 :   for (auto iter = tmp->mRadioGroups.Iter(); !iter.Done(); iter.Next()) {
    1793           0 :     nsRadioGroupStruct* radioGroup = iter.UserData();
    1794             :     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(
    1795           0 :       cb, "mRadioGroups entry->mSelectedRadioButton");
    1796           0 :     cb.NoteXPCOMChild(ToSupports(radioGroup->mSelectedRadioButton));
    1797             : 
    1798           0 :     uint32_t i, count = radioGroup->mRadioButtons.Count();
    1799           0 :     for (i = 0; i < count; ++i) {
    1800             :       NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(
    1801           0 :         cb, "mRadioGroups entry->mRadioButtons[i]");
    1802           0 :       cb.NoteXPCOMChild(radioGroup->mRadioButtons[i]);
    1803             :     }
    1804             :   }
    1805             : 
    1806             :   // The boxobject for an element will only exist as long as it's in the
    1807             :   // document, so we'll traverse the table here instead of from the element.
    1808          15 :   if (tmp->mBoxObjectTable) {
    1809           0 :     for (auto iter = tmp->mBoxObjectTable->Iter(); !iter.Done(); iter.Next()) {
    1810           0 :       NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mBoxObjectTable entry");
    1811           0 :       cb.NoteXPCOMChild(iter.UserData());
    1812             :     }
    1813             :   }
    1814             : 
    1815          15 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChannel)
    1816          15 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleAttrStyleSheet)
    1817          15 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mXPathEvaluator)
    1818          15 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLayoutHistoryState)
    1819          15 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOnloadBlocker)
    1820          15 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFirstBaseNodeWithHref)
    1821          15 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMImplementation)
    1822          15 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mImageMaps)
    1823          15 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOrientationPendingPromise)
    1824          15 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOriginalDocument)
    1825          15 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCachedEncoder)
    1826          15 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStateObjectCached)
    1827          15 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentTimeline)
    1828          15 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPendingAnimationTracker)
    1829          15 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTemplateContentsOwner)
    1830          15 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChildrenCollection)
    1831          15 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAnonymousContents)
    1832             : 
    1833             :   // Traverse all our nsCOMArrays.
    1834          15 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheets)
    1835          15 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOnDemandBuiltInUASheets)
    1836          15 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPreloadingImages)
    1837             : 
    1838          15 :   for (uint32_t i = 0; i < tmp->mFrameRequestCallbacks.Length(); ++i) {
    1839           0 :     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mFrameRequestCallbacks[i]");
    1840           0 :     cb.NoteXPCOMChild(tmp->mFrameRequestCallbacks[i].mCallback);
    1841             :   }
    1842             : 
    1843             :   // Traverse animation components
    1844          15 :   if (tmp->mAnimationController) {
    1845           0 :     tmp->mAnimationController->Traverse(&cb);
    1846             :   }
    1847             : 
    1848          15 :   if (tmp->mSubDocuments) {
    1849           0 :     for (auto iter = tmp->mSubDocuments->Iter(); !iter.Done(); iter.Next()) {
    1850           0 :       auto entry = static_cast<SubDocMapEntry*>(iter.Get());
    1851             : 
    1852             :       NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
    1853           0 :                                          "mSubDocuments entry->mKey");
    1854           0 :       cb.NoteXPCOMChild(entry->mKey);
    1855             :       NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb,
    1856           0 :                                          "mSubDocuments entry->mSubDocument");
    1857           0 :       cb.NoteXPCOMChild(entry->mSubDocument);
    1858             :     }
    1859             :   }
    1860             : 
    1861          15 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCSSLoader)
    1862             : 
    1863             :   // We own only the items in mDOMMediaQueryLists that have listeners;
    1864             :   // this reference is managed by their AddListener and RemoveListener
    1865             :   // methods.
    1866          15 :   for (auto mql : tmp->mDOMMediaQueryLists) {
    1867           0 :     if (mql->HasListeners()) {
    1868           0 :       NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mDOMMediaQueryLists item");
    1869           0 :       cb.NoteXPCOMChild(mql);
    1870             :     }
    1871             :   }
    1872          15 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    1873             : 
    1874             : NS_IMPL_CYCLE_COLLECTION_CLASS(nsDocument)
    1875             : 
    1876          81 : NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(nsDocument)
    1877             : 
    1878           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument)
    1879           0 :   tmp->mInUnlinkOrDeletion = true;
    1880             : 
    1881             :   // Clear out our external resources
    1882           0 :   tmp->mExternalResourceMap.Shutdown();
    1883             : 
    1884           0 :   nsAutoScriptBlocker scriptBlocker;
    1885             : 
    1886           0 :   nsINode::Unlink(tmp);
    1887             : 
    1888             :   // Unlink the mChildren nsAttrAndChildArray.
    1889           0 :   uint32_t childCount = tmp->mChildren.ChildCount();
    1890           0 :   if (childCount) {
    1891           0 :     while (childCount-- > 0) {
    1892             :       // Hold a strong ref to the node when we remove it, because we may be
    1893             :       // the last reference to it.  We need to call TakeChildAt() and
    1894             :       // update mFirstChild before calling UnbindFromTree, since this last
    1895             :       // can notify various observers and they should really see consistent
    1896             :       // tree state.
    1897             :       // If this code changes, change the corresponding code in
    1898             :       // FragmentOrElement's unlink impl and ContentUnbinder::UnbindSubtree.
    1899           0 :       nsCOMPtr<nsIContent> child = tmp->mChildren.TakeChildAt(childCount);
    1900           0 :       if (childCount == 0) {
    1901           0 :         tmp->mFirstChild = nullptr;
    1902             :       }
    1903           0 :       child->UnbindFromTree();
    1904             :     }
    1905             :   }
    1906           0 :   tmp->mFirstChild = nullptr;
    1907             : 
    1908           0 :   tmp->UnlinkOriginalDocumentIfStatic();
    1909             : 
    1910           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mXPathEvaluator)
    1911           0 :   tmp->mCachedRootElement = nullptr; // Avoid a dangling pointer
    1912           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDisplayDocument)
    1913           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mFirstBaseNodeWithHref)
    1914           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mMaybeEndOutermostXBLUpdateRunner)
    1915           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMImplementation)
    1916           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mImageMaps)
    1917           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mCachedEncoder)
    1918           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentTimeline)
    1919           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mPendingAnimationTracker)
    1920           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mTemplateContentsOwner)
    1921           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mChildrenCollection)
    1922           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mOrientationPendingPromise)
    1923           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mFontFaceSet)
    1924             : 
    1925           0 :   tmp->mParentDocument = nullptr;
    1926             : 
    1927           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mPreloadingImages)
    1928             : 
    1929           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mIntersectionObservers)
    1930             : 
    1931           0 :   tmp->ClearAllBoxObjects();
    1932             : 
    1933           0 :   if (tmp->mListenerManager) {
    1934           0 :     tmp->mListenerManager->Disconnect();
    1935           0 :     tmp->UnsetFlags(NODE_HAS_LISTENERMANAGER);
    1936           0 :     tmp->mListenerManager = nullptr;
    1937             :   }
    1938             : 
    1939           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMStyleSheets)
    1940             : 
    1941           0 :   if (tmp->mStyleSheetSetList) {
    1942           0 :     tmp->mStyleSheetSetList->Disconnect();
    1943           0 :     tmp->mStyleSheetSetList = nullptr;
    1944             :   }
    1945             : 
    1946           0 :   delete tmp->mSubDocuments;
    1947           0 :   tmp->mSubDocuments = nullptr;
    1948             : 
    1949           0 :   tmp->mFrameRequestCallbacks.Clear();
    1950           0 :   MOZ_RELEASE_ASSERT(!tmp->mFrameRequestCallbacksScheduled,
    1951             :                      "How did we get here without our presshell going away "
    1952             :                      "first?");
    1953             : 
    1954           0 :   tmp->mRadioGroups.Clear();
    1955             : 
    1956             :   // nsDocument has a pretty complex destructor, so we're going to
    1957             :   // assume that *most* cycles you actually want to break somewhere
    1958             :   // else, and not unlink an awful lot here.
    1959             : 
    1960           0 :   tmp->mIdentifierMap.Clear();
    1961           0 :   tmp->mExpandoAndGeneration.OwnerUnlinked();
    1962             : 
    1963           0 :   if (tmp->mAnimationController) {
    1964           0 :     tmp->mAnimationController->Unlink();
    1965             :   }
    1966             : 
    1967           0 :   tmp->mPendingTitleChangeEvent.Revoke();
    1968             : 
    1969           0 :   if (tmp->mCSSLoader) {
    1970           0 :     tmp->mCSSLoader->DropDocumentReference();
    1971           0 :     NS_IMPL_CYCLE_COLLECTION_UNLINK(mCSSLoader)
    1972             :   }
    1973             : 
    1974             :   // We own only the items in mDOMMediaQueryLists that have listeners;
    1975             :   // this reference is managed by their AddListener and RemoveListener
    1976             :   // methods.
    1977           0 :   for (MediaQueryList* mql = tmp->mDOMMediaQueryLists.getFirst(); mql;) {
    1978           0 :     MediaQueryList* next = mql->getNext();
    1979           0 :     mql->Disconnect();
    1980           0 :     mql = next;
    1981             :   }
    1982             : 
    1983           0 :   tmp->mInUnlinkOrDeletion = false;
    1984           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    1985             : 
    1986             : nsresult
    1987          55 : nsDocument::Init()
    1988             : {
    1989          55 :   if (mCSSLoader || mStyleImageLoader || mNodeInfoManager || mScriptLoader) {
    1990           0 :     return NS_ERROR_ALREADY_INITIALIZED;
    1991             :   }
    1992             : 
    1993             :   // Force initialization.
    1994          55 :   nsINode::nsSlots* slots = Slots();
    1995             : 
    1996             :   // Prepend self as mutation-observer whether we need it or not (some
    1997             :   // subclasses currently do, other don't). This is because the code in
    1998             :   // nsNodeUtils always notifies the first observer first, expecting the
    1999             :   // first observer to be the document.
    2000          55 :   NS_ENSURE_TRUE(slots->mMutationObservers.PrependElementUnlessExists(static_cast<nsIMutationObserver*>(this)),
    2001             :                  NS_ERROR_OUT_OF_MEMORY);
    2002             : 
    2003             : 
    2004          55 :   mOnloadBlocker = new nsOnloadBlocker();
    2005          55 :   mCSSLoader = new mozilla::css::Loader(this);
    2006             :   // Assume we're not quirky, until we know otherwise
    2007          55 :   mCSSLoader->SetCompatibilityMode(eCompatibility_FullStandards);
    2008             : 
    2009          55 :   mStyleImageLoader = new mozilla::css::ImageLoader(this);
    2010             : 
    2011          55 :   mNodeInfoManager = new nsNodeInfoManager();
    2012          55 :   nsresult rv = mNodeInfoManager->Init(this);
    2013          55 :   NS_ENSURE_SUCCESS(rv, rv);
    2014             : 
    2015             :   // mNodeInfo keeps NodeInfoManager alive!
    2016          55 :   mNodeInfo = mNodeInfoManager->GetDocumentNodeInfo();
    2017          55 :   NS_ENSURE_TRUE(mNodeInfo, NS_ERROR_OUT_OF_MEMORY);
    2018          55 :   MOZ_ASSERT(mNodeInfo->NodeType() == nsIDOMNode::DOCUMENT_NODE,
    2019             :              "Bad NodeType in aNodeInfo");
    2020             : 
    2021          55 :   NS_ASSERTION(OwnerDoc() == this, "Our nodeinfo is busted!");
    2022             : 
    2023             :   // If after creation the owner js global is not set for a document
    2024             :   // we use the default compartment for this document, instead of creating
    2025             :   // wrapper in some random compartment when the document is exposed to js
    2026             :   // via some events.
    2027         110 :   nsCOMPtr<nsIGlobalObject> global = xpc::NativeGlobal(xpc::PrivilegedJunkScope());
    2028          55 :   NS_ENSURE_TRUE(global, NS_ERROR_FAILURE);
    2029          55 :   mScopeObject = do_GetWeakReference(global);
    2030          55 :   MOZ_ASSERT(mScopeObject);
    2031             : 
    2032          55 :   mScriptLoader = new dom::ScriptLoader(this);
    2033             : 
    2034          55 :   mozilla::HoldJSObjects(this);
    2035             : 
    2036          55 :   return NS_OK;
    2037             : }
    2038             : 
    2039             : void
    2040           0 : nsIDocument::DeleteAllProperties()
    2041             : {
    2042           0 :   for (uint32_t i = 0; i < GetPropertyTableCount(); ++i) {
    2043           0 :     PropertyTable(i)->DeleteAllProperties();
    2044             :   }
    2045           0 : }
    2046             : 
    2047             : void
    2048           0 : nsIDocument::DeleteAllPropertiesFor(nsINode* aNode)
    2049             : {
    2050           0 :   for (uint32_t i = 0; i < GetPropertyTableCount(); ++i) {
    2051           0 :     PropertyTable(i)->DeleteAllPropertiesFor(aNode);
    2052             :   }
    2053           0 : }
    2054             : 
    2055             : nsPropertyTable*
    2056           1 : nsIDocument::GetExtraPropertyTable(uint16_t aCategory)
    2057             : {
    2058           1 :   NS_ASSERTION(aCategory > 0, "Category 0 should have already been handled");
    2059           3 :   while (aCategory >= mExtraPropertyTables.Length() + 1) {
    2060           1 :     mExtraPropertyTables.AppendElement(new nsPropertyTable());
    2061             :   }
    2062           1 :   return mExtraPropertyTables[aCategory - 1];
    2063             : }
    2064             : 
    2065             : bool
    2066           0 : nsIDocument::IsVisibleConsideringAncestors() const
    2067             : {
    2068           0 :   const nsIDocument *parent = this;
    2069           0 :   do {
    2070           0 :     if (!parent->IsVisible()) {
    2071           0 :       return false;
    2072             :     }
    2073             :   } while ((parent = parent->GetParentDocument()));
    2074             : 
    2075           0 :   return true;
    2076             :       }
    2077             : 
    2078             : void
    2079          25 : nsDocument::Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup)
    2080             : {
    2081          50 :   nsCOMPtr<nsIURI> uri;
    2082          50 :   nsCOMPtr<nsIPrincipal> principal;
    2083          25 :   if (aChannel) {
    2084             :     // Note: this code is duplicated in XULDocument::StartDocumentLoad and
    2085             :     // nsScriptSecurityManager::GetChannelResultPrincipal.
    2086             :     // Note: this should match nsDocShell::OnLoadingSite
    2087          25 :     NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
    2088             : 
    2089             :     nsIScriptSecurityManager *securityManager =
    2090          25 :       nsContentUtils::GetSecurityManager();
    2091          25 :     if (securityManager) {
    2092          25 :       securityManager->GetChannelResultPrincipal(aChannel,
    2093          50 :                                                  getter_AddRefs(principal));
    2094             :     }
    2095             :   }
    2096             : 
    2097          25 :   principal = MaybeDowngradePrincipal(principal);
    2098             : 
    2099          25 :   ResetToURI(uri, aLoadGroup, principal);
    2100             : 
    2101             :   // Note that, since mTiming does not change during a reset, the
    2102             :   // navigationStart time remains unchanged and therefore any future new
    2103             :   // timeline will have the same global clock time as the old one.
    2104          25 :   mDocumentTimeline = nullptr;
    2105             : 
    2106          50 :   nsCOMPtr<nsIPropertyBag2> bag = do_QueryInterface(aChannel);
    2107          25 :   if (bag) {
    2108          50 :     nsCOMPtr<nsIURI> baseURI;
    2109         100 :     bag->GetPropertyAsInterface(NS_LITERAL_STRING("baseURI"),
    2110         100 :                                 NS_GET_IID(nsIURI), getter_AddRefs(baseURI));
    2111          25 :     if (baseURI) {
    2112           1 :       mDocumentBaseURI = baseURI;
    2113           1 :       mChromeXHRDocBaseURI = nullptr;
    2114             :     }
    2115             :   }
    2116             : 
    2117          25 :   mChannel = aChannel;
    2118          25 : }
    2119             : 
    2120             : void
    2121          29 : nsDocument::ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup,
    2122             :                        nsIPrincipal* aPrincipal)
    2123             : {
    2124          29 :   NS_PRECONDITION(aURI, "Null URI passed to ResetToURI");
    2125             : 
    2126          29 :   MOZ_LOG(gDocumentLeakPRLog, LogLevel::Debug,
    2127             :           ("DOCUMENT %p ResetToURI %s", this, aURI->GetSpecOrDefault().get()));
    2128             : 
    2129          29 :   mSecurityInfo = nullptr;
    2130             : 
    2131          29 :   mDocumentLoadGroup = nullptr;
    2132             : 
    2133             :   // Delete references to sub-documents and kill the subdocument map,
    2134             :   // if any. It holds strong references
    2135          29 :   delete mSubDocuments;
    2136          29 :   mSubDocuments = nullptr;
    2137             : 
    2138             :   // Destroy link map now so we don't waste time removing
    2139             :   // links one by one
    2140          29 :   DestroyElementMaps();
    2141             : 
    2142          29 :   bool oldVal = mInUnlinkOrDeletion;
    2143          29 :   mInUnlinkOrDeletion = true;
    2144          29 :   uint32_t count = mChildren.ChildCount();
    2145             :   { // Scope for update
    2146          58 :     MOZ_AUTO_DOC_UPDATE(this, UPDATE_CONTENT_MODEL, true);
    2147          29 :     for (int32_t i = int32_t(count) - 1; i >= 0; i--) {
    2148           0 :       nsCOMPtr<nsIContent> content = mChildren.ChildAt(i);
    2149             : 
    2150           0 :       nsIContent* previousSibling = content->GetPreviousSibling();
    2151             : 
    2152           0 :       if (nsINode::GetFirstChild() == content) {
    2153           0 :         mFirstChild = content->GetNextSibling();
    2154             :       }
    2155           0 :       mChildren.RemoveChildAt(i);
    2156           0 :       if (content == mCachedRootElement) {
    2157             :         // Immediately clear mCachedRootElement, now that it's been removed
    2158             :         // from mChildren, so that GetRootElement() will stop returning this
    2159             :         // now-stale value.
    2160           0 :         mCachedRootElement = nullptr;
    2161             :       }
    2162           0 :       nsNodeUtils::ContentRemoved(this, content, i, previousSibling);
    2163           0 :       content->UnbindFromTree();
    2164             :     }
    2165          29 :     MOZ_ASSERT(!mCachedRootElement,
    2166             :                "After removing all children, there should be no root elem");
    2167             :   }
    2168          29 :   mInUnlinkOrDeletion = oldVal;
    2169             : 
    2170             :   // Reset our stylesheets
    2171          29 :   ResetStylesheetsToURI(aURI);
    2172             : 
    2173             :   // Release the listener manager
    2174          29 :   if (mListenerManager) {
    2175           0 :     mListenerManager->Disconnect();
    2176           0 :     mListenerManager = nullptr;
    2177             :   }
    2178             : 
    2179             :   // Release the stylesheets list.
    2180          29 :   mDOMStyleSheets = nullptr;
    2181             : 
    2182             :   // Release our principal after tearing down the document, rather than before.
    2183             :   // This ensures that, during teardown, the document and the dying window (which
    2184             :   // already nulled out its document pointer and cached the principal) have
    2185             :   // matching principals.
    2186          29 :   SetPrincipal(nullptr);
    2187             : 
    2188             :   // Clear the original URI so SetDocumentURI sets it.
    2189          29 :   mOriginalURI = nullptr;
    2190             : 
    2191          29 :   SetDocumentURI(aURI);
    2192          29 :   mChromeXHRDocURI = nullptr;
    2193             :   // If mDocumentBaseURI is null, nsIDocument::GetBaseURI() returns
    2194             :   // mDocumentURI.
    2195          29 :   mDocumentBaseURI = nullptr;
    2196          29 :   mChromeXHRDocBaseURI = nullptr;
    2197             : 
    2198          29 :   if (aLoadGroup) {
    2199          29 :     mDocumentLoadGroup = do_GetWeakReference(aLoadGroup);
    2200             :     // there was an assertion here that aLoadGroup was not null.  This
    2201             :     // is no longer valid: nsDocShell::SetDocument does not create a
    2202             :     // load group, and it works just fine
    2203             : 
    2204             :     // XXXbz what does "just fine" mean exactly?  And given that there
    2205             :     // is no nsDocShell::SetDocument, what is this talking about?
    2206             :   }
    2207             : 
    2208          29 :   mLastModified.Truncate();
    2209             :   // XXXbz I guess we're assuming that the caller will either pass in
    2210             :   // a channel with a useful type or call SetContentType?
    2211          29 :   SetContentTypeInternal(EmptyCString());
    2212          29 :   mContentLanguage.Truncate();
    2213          29 :   mBaseTarget.Truncate();
    2214          29 :   mReferrer.Truncate();
    2215             : 
    2216          29 :   mXMLDeclarationBits = 0;
    2217             : 
    2218             :   // Now get our new principal
    2219          29 :   if (aPrincipal) {
    2220          27 :     SetPrincipal(aPrincipal);
    2221             :   } else {
    2222             :     nsIScriptSecurityManager *securityManager =
    2223           2 :       nsContentUtils::GetSecurityManager();
    2224           2 :     if (securityManager) {
    2225           4 :       nsCOMPtr<nsILoadContext> loadContext(mDocumentContainer);
    2226             : 
    2227           2 :       if (!loadContext && aLoadGroup) {
    2228           4 :         nsCOMPtr<nsIInterfaceRequestor> cbs;
    2229           2 :         aLoadGroup->GetNotificationCallbacks(getter_AddRefs(cbs));
    2230           2 :         loadContext = do_GetInterface(cbs);
    2231             :       }
    2232             : 
    2233           2 :       MOZ_ASSERT(loadContext,
    2234             :                  "must have a load context or pass in an explicit principal");
    2235             : 
    2236           4 :       nsCOMPtr<nsIPrincipal> principal;
    2237             :       nsresult rv = securityManager->
    2238           2 :         GetLoadContextCodebasePrincipal(mDocumentURI, loadContext,
    2239           4 :                                         getter_AddRefs(principal));
    2240           2 :       if (NS_SUCCEEDED(rv)) {
    2241           2 :         SetPrincipal(principal);
    2242             :       }
    2243             :     }
    2244             :   }
    2245             : 
    2246             :   // Refresh the principal on the compartment.
    2247          29 :   if (nsPIDOMWindowInner* win = GetInnerWindow()) {
    2248           0 :     nsGlobalWindow::Cast(win)->RefreshCompartmentPrincipal();
    2249             :   }
    2250          29 : }
    2251             : 
    2252             : already_AddRefed<nsIPrincipal>
    2253          26 : nsDocument::MaybeDowngradePrincipal(nsIPrincipal* aPrincipal)
    2254             : {
    2255          26 :   if (!aPrincipal) {
    2256           0 :     return nullptr;
    2257             :   }
    2258             : 
    2259          26 :   if (!sChromeInContentPrefCached) {
    2260           2 :     sChromeInContentPrefCached = true;
    2261             :     Preferences::AddBoolVarCache(&sChromeInContentAllowed,
    2262           2 :                                  kChromeInContentPref, false);
    2263             :   }
    2264          52 :   if (!sChromeInContentAllowed &&
    2265          26 :       nsContentUtils::IsSystemPrincipal(aPrincipal)) {
    2266             :     // We basically want the parent document here, but because this is very
    2267             :     // early in the load, GetParentDocument() returns null, so we use the
    2268             :     // docshell hierarchy to get this information instead.
    2269           3 :     if (mDocumentContainer) {
    2270           4 :       nsCOMPtr<nsIDocShellTreeItem> parentDocShellItem;
    2271           2 :       mDocumentContainer->GetParent(getter_AddRefs(parentDocShellItem));
    2272           4 :       nsCOMPtr<nsIDocShell> parentDocShell = do_QueryInterface(parentDocShellItem);
    2273           2 :       if (parentDocShell) {
    2274           2 :         nsCOMPtr<nsIDocument> parentDoc;
    2275           1 :         parentDoc = parentDocShell->GetDocument();
    2276           2 :         if (!parentDoc ||
    2277           1 :             !nsContentUtils::IsSystemPrincipal(parentDoc->NodePrincipal())) {
    2278             :           nsCOMPtr<nsIPrincipal> nullPrincipal =
    2279           0 :             do_CreateInstance("@mozilla.org/nullprincipal;1");
    2280           0 :           return nullPrincipal.forget();
    2281             :         }
    2282             :       }
    2283             :     }
    2284             :   }
    2285          52 :   nsCOMPtr<nsIPrincipal> principal(aPrincipal);
    2286          26 :   return principal.forget();
    2287             : }
    2288             : 
    2289             : void
    2290           0 : nsDocument::RemoveDocStyleSheetsFromStyleSets()
    2291             : {
    2292             :   // The stylesheets should forget us
    2293           0 :   for (StyleSheet* sheet : Reversed(mStyleSheets)) {
    2294           0 :     sheet->ClearAssociatedDocument();
    2295             : 
    2296           0 :     if (sheet->IsApplicable()) {
    2297           0 :       nsCOMPtr<nsIPresShell> shell = GetShell();
    2298           0 :       if (shell) {
    2299           0 :         shell->StyleSet()->RemoveDocStyleSheet(sheet);
    2300             :       }
    2301             :     }
    2302             :     // XXX Tell observers?
    2303             :   }
    2304           0 : }
    2305             : 
    2306             : void
    2307           0 : nsDocument::RemoveStyleSheetsFromStyleSets(
    2308             :     const nsTArray<RefPtr<StyleSheet>>& aSheets,
    2309             :     SheetType aType)
    2310             : {
    2311             :   // The stylesheets should forget us
    2312           0 :   for (StyleSheet* sheet : Reversed(aSheets)) {
    2313           0 :     sheet->ClearAssociatedDocument();
    2314             : 
    2315           0 :     if (sheet->IsApplicable()) {
    2316           0 :       nsCOMPtr<nsIPresShell> shell = GetShell();
    2317           0 :       if (shell) {
    2318           0 :         shell->StyleSet()->RemoveStyleSheet(aType, sheet);
    2319             :       }
    2320             :     }
    2321             :     // XXX Tell observers?
    2322             :   }
    2323           0 : }
    2324             : 
    2325             : void
    2326          30 : nsDocument::ResetStylesheetsToURI(nsIURI* aURI)
    2327             : {
    2328          30 :   MOZ_ASSERT(aURI);
    2329             : 
    2330          60 :   mozAutoDocUpdate upd(this, UPDATE_STYLE, true);
    2331          30 :   if (mStyleSetFilled) {
    2332             :     // Skip removing style sheets from the style set if we know we haven't
    2333             :     // filled the style set.  (This allows us to avoid calling
    2334             :     // GetStyleBackendType() too early.)
    2335           0 :     RemoveDocStyleSheetsFromStyleSets();
    2336           0 :     RemoveStyleSheetsFromStyleSets(mOnDemandBuiltInUASheets, SheetType::Agent);
    2337           0 :     RemoveStyleSheetsFromStyleSets(mAdditionalSheets[eAgentSheet], SheetType::Agent);
    2338           0 :     RemoveStyleSheetsFromStyleSets(mAdditionalSheets[eUserSheet], SheetType::User);
    2339           0 :     RemoveStyleSheetsFromStyleSets(mAdditionalSheets[eAuthorSheet], SheetType::Doc);
    2340             : 
    2341           0 :     if (nsStyleSheetService* sheetService = nsStyleSheetService::GetInstance()) {
    2342             :       RemoveStyleSheetsFromStyleSets(
    2343           0 :         *sheetService->AuthorStyleSheets(GetStyleBackendType()), SheetType::Doc);
    2344             :     }
    2345             : 
    2346           0 :     mStyleSetFilled = false;
    2347             :   }
    2348             : 
    2349             :   // Release all the sheets
    2350          30 :   mStyleSheets.Clear();
    2351          30 :   mOnDemandBuiltInUASheets.Clear();
    2352         120 :   for (auto& sheets : mAdditionalSheets) {
    2353          90 :     sheets.Clear();
    2354             :   }
    2355             : 
    2356             :   // NOTE:  We don't release the catalog sheets.  It doesn't really matter
    2357             :   // now, but it could in the future -- in which case not releasing them
    2358             :   // is probably the right thing to do.
    2359             : 
    2360             :   // Now reset our inline style and attribute sheets.
    2361          30 :   if (mAttrStyleSheet) {
    2362           0 :     mAttrStyleSheet->Reset();
    2363           0 :     mAttrStyleSheet->SetOwningDocument(this);
    2364             :   } else {
    2365          30 :     mAttrStyleSheet = new nsHTMLStyleSheet(this);
    2366             :   }
    2367             : 
    2368          30 :   if (!mStyleAttrStyleSheet) {
    2369          30 :     mStyleAttrStyleSheet = new nsHTMLCSSStyleSheet();
    2370             :   }
    2371             : 
    2372             :   // Now set up our style sets
    2373          60 :   nsCOMPtr<nsIPresShell> shell = GetShell();
    2374          30 :   if (shell) {
    2375           0 :     FillStyleSet(shell->StyleSet());
    2376             :   }
    2377          30 : }
    2378             : 
    2379             : static void
    2380          84 : AppendSheetsToStyleSet(StyleSetHandle aStyleSet,
    2381             :                        const nsTArray<RefPtr<StyleSheet>>& aSheets,
    2382             :                        SheetType aType)
    2383             : {
    2384          84 :   for (StyleSheet* sheet : Reversed(aSheets)) {
    2385           0 :     aStyleSet->AppendStyleSheet(aType, sheet);
    2386             :   }
    2387          84 : }
    2388             : 
    2389             : 
    2390             : void
    2391          28 : nsDocument::FillStyleSet(StyleSetHandle aStyleSet)
    2392             : {
    2393          28 :   NS_PRECONDITION(aStyleSet, "Must have a style set");
    2394          28 :   NS_PRECONDITION(aStyleSet->SheetCount(SheetType::Doc) == 0,
    2395             :                   "Style set already has document sheets?");
    2396             : 
    2397          28 :   MOZ_ASSERT(!mStyleSetFilled);
    2398             : 
    2399          28 :   for (StyleSheet* sheet : Reversed(mStyleSheets)) {
    2400           0 :     if (sheet->IsApplicable()) {
    2401           0 :       aStyleSet->AddDocStyleSheet(sheet, this);
    2402             :     }
    2403             :   }
    2404             : 
    2405          28 :   if (nsStyleSheetService* sheetService = nsStyleSheetService::GetInstance()) {
    2406             :     nsTArray<RefPtr<StyleSheet>>& sheets =
    2407          28 :       *sheetService->AuthorStyleSheets(aStyleSet->BackendType());
    2408          28 :     for (StyleSheet* sheet : sheets) {
    2409           0 :       aStyleSet->AppendStyleSheet(SheetType::Doc, sheet);
    2410             :     }
    2411             :   }
    2412             : 
    2413             :   // Iterate backwards to maintain order
    2414          28 :   for (StyleSheet* sheet : Reversed(mOnDemandBuiltInUASheets)) {
    2415           0 :     if (sheet->IsApplicable()) {
    2416           0 :       aStyleSet->PrependStyleSheet(SheetType::Agent, sheet);
    2417             :     }
    2418             :   }
    2419             : 
    2420          56 :   AppendSheetsToStyleSet(aStyleSet, mAdditionalSheets[eAgentSheet],
    2421          28 :                          SheetType::Agent);
    2422          56 :   AppendSheetsToStyleSet(aStyleSet, mAdditionalSheets[eUserSheet],
    2423          28 :                          SheetType::User);
    2424          56 :   AppendSheetsToStyleSet(aStyleSet, mAdditionalSheets[eAuthorSheet],
    2425          28 :                          SheetType::Doc);
    2426             : 
    2427          28 :   mStyleSetFilled = true;
    2428          28 : }
    2429             : 
    2430             : static void
    2431           3 : WarnIfSandboxIneffective(nsIDocShell* aDocShell,
    2432             :                          uint32_t aSandboxFlags,
    2433             :                          nsIChannel* aChannel)
    2434             : {
    2435             :   // If the document is sandboxed (via the HTML5 iframe sandbox
    2436             :   // attribute) and both the allow-scripts and allow-same-origin
    2437             :   // keywords are supplied, the sandboxed document can call into its
    2438             :   // parent document and remove its sandboxing entirely - we print a
    2439             :   // warning to the web console in this case.
    2440           3 :   if (aSandboxFlags & SANDBOXED_NAVIGATION &&
    2441           0 :       !(aSandboxFlags & SANDBOXED_SCRIPTS) &&
    2442           0 :       !(aSandboxFlags & SANDBOXED_ORIGIN)) {
    2443           0 :     nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
    2444           0 :     aDocShell->GetSameTypeParent(getter_AddRefs(parentAsItem));
    2445           0 :     nsCOMPtr<nsIDocShell> parentDocShell = do_QueryInterface(parentAsItem);
    2446           0 :     if (!parentDocShell) {
    2447           0 :       return;
    2448             :     }
    2449             : 
    2450             :     // Don't warn if our parent is not the top-level document.
    2451           0 :     nsCOMPtr<nsIDocShellTreeItem> grandParentAsItem;
    2452           0 :     parentDocShell->GetSameTypeParent(getter_AddRefs(grandParentAsItem));
    2453           0 :     if (grandParentAsItem) {
    2454           0 :       return;
    2455             :     }
    2456             : 
    2457           0 :     nsCOMPtr<nsIChannel> parentChannel;
    2458           0 :     parentDocShell->GetCurrentDocumentChannel(getter_AddRefs(parentChannel));
    2459           0 :     if (!parentChannel) {
    2460           0 :       return;
    2461             :     }
    2462           0 :     nsresult rv = nsContentUtils::CheckSameOrigin(aChannel, parentChannel);
    2463           0 :     if (NS_FAILED(rv)) {
    2464           0 :       return;
    2465             :     }
    2466             : 
    2467           0 :     nsCOMPtr<nsIDocument> parentDocument = parentDocShell->GetDocument();
    2468           0 :     nsCOMPtr<nsIURI> iframeUri;
    2469           0 :     parentChannel->GetURI(getter_AddRefs(iframeUri));
    2470           0 :     nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
    2471           0 :                                     NS_LITERAL_CSTRING("Iframe Sandbox"),
    2472             :                                     parentDocument,
    2473             :                                     nsContentUtils::eSECURITY_PROPERTIES,
    2474             :                                     "BothAllowScriptsAndSameOriginPresent",
    2475           0 :                                     nullptr, 0, iframeUri);
    2476             :   }
    2477             : }
    2478             : 
    2479             : nsresult
    2480          25 : nsDocument::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel,
    2481             :                               nsILoadGroup* aLoadGroup,
    2482             :                               nsISupports* aContainer,
    2483             :                               nsIStreamListener **aDocListener,
    2484             :                               bool aReset, nsIContentSink* aSink)
    2485             : {
    2486          25 :   if (MOZ_LOG_TEST(gDocumentLeakPRLog, LogLevel::Debug)) {
    2487           0 :     nsCOMPtr<nsIURI> uri;
    2488           0 :     aChannel->GetURI(getter_AddRefs(uri));
    2489           0 :     MOZ_LOG(gDocumentLeakPRLog, LogLevel::Debug,
    2490             :             ("DOCUMENT %p StartDocumentLoad %s",
    2491             :              this, uri ? uri->GetSpecOrDefault().get() : ""));
    2492             :   }
    2493             : 
    2494          25 :   MOZ_ASSERT(NodePrincipal()->GetAppId() != nsIScriptSecurityManager::UNKNOWN_APP_ID,
    2495             :              "Document should never have UNKNOWN_APP_ID");
    2496             : 
    2497          25 :   MOZ_ASSERT(GetReadyStateEnum() == nsIDocument::READYSTATE_UNINITIALIZED,
    2498             :              "Bad readyState");
    2499          25 :   SetReadyStateInternal(READYSTATE_LOADING);
    2500             : 
    2501          25 :   if (nsCRT::strcmp(kLoadAsData, aCommand) == 0) {
    2502           0 :     mLoadedAsData = true;
    2503             :     // We need to disable script & style loading in this case.
    2504             :     // We leave them disabled even in EndLoad(), and let anyone
    2505             :     // who puts the document on display to worry about enabling.
    2506             : 
    2507             :     // Do not load/process scripts when loading as data
    2508           0 :     ScriptLoader()->SetEnabled(false);
    2509             : 
    2510             :     // styles
    2511           0 :     CSSLoader()->SetEnabled(false); // Do not load/process styles when loading as data
    2512          25 :   } else if (nsCRT::strcmp("external-resource", aCommand) == 0) {
    2513             :     // Allow CSS, but not scripts
    2514          21 :     ScriptLoader()->SetEnabled(false);
    2515             :   }
    2516             : 
    2517          25 :   mMayStartLayout = false;
    2518             : 
    2519          25 :   if (aReset) {
    2520          25 :     Reset(aChannel, aLoadGroup);
    2521             :   }
    2522             : 
    2523          50 :   nsAutoCString contentType;
    2524          50 :   nsCOMPtr<nsIPropertyBag2> bag = do_QueryInterface(aChannel);
    2525          75 :   if ((bag && NS_SUCCEEDED(bag->GetPropertyAsACString(
    2526          75 :                 NS_LITERAL_STRING("contentType"), contentType))) ||
    2527          25 :       NS_SUCCEEDED(aChannel->GetContentType(contentType))) {
    2528             :     // XXX this is only necessary for viewsource:
    2529          25 :     nsACString::const_iterator start, end, semicolon;
    2530          25 :     contentType.BeginReading(start);
    2531          25 :     contentType.EndReading(end);
    2532          25 :     semicolon = start;
    2533          25 :     FindCharInReadable(';', semicolon, end);
    2534          25 :     SetContentTypeInternal(Substring(start, semicolon));
    2535             :   }
    2536             : 
    2537          25 :   RetrieveRelevantHeaders(aChannel);
    2538             : 
    2539          25 :   mChannel = aChannel;
    2540          50 :   nsCOMPtr<nsIInputStreamChannel> inStrmChan = do_QueryInterface(mChannel);
    2541          25 :   if (inStrmChan) {
    2542             :     bool isSrcdocChannel;
    2543           1 :     inStrmChan->GetIsSrcdocChannel(&isSrcdocChannel);
    2544           1 :     if (isSrcdocChannel) {
    2545           0 :       mIsSrcdocDocument = true;
    2546             :     }
    2547             :   }
    2548             : 
    2549             :   // If this document is being loaded by a docshell, copy its sandbox flags
    2550             :   // to the document, and store the fullscreen enabled flag. These are
    2551             :   // immutable after being set here.
    2552          50 :   nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(aContainer);
    2553             : 
    2554             :   // If this is an error page, don't inherit sandbox flags from docshell
    2555          50 :   nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
    2556          25 :   if (docShell && !(loadInfo && loadInfo->GetLoadErrorPage())) {
    2557           3 :     nsresult rv = docShell->GetSandboxFlags(&mSandboxFlags);
    2558           3 :     NS_ENSURE_SUCCESS(rv, rv);
    2559           3 :     WarnIfSandboxIneffective(docShell, mSandboxFlags, GetChannel());
    2560             :   }
    2561             : 
    2562             :   // The CSP directive upgrade-insecure-requests not only applies to the
    2563             :   // toplevel document, but also to nested documents. Let's propagate that
    2564             :   // flag from the parent to the nested document.
    2565          50 :   nsCOMPtr<nsIDocShellTreeItem> treeItem = this->GetDocShell();
    2566          25 :   if (treeItem) {
    2567           6 :     nsCOMPtr<nsIDocShellTreeItem> sameTypeParent;
    2568           3 :     treeItem->GetSameTypeParent(getter_AddRefs(sameTypeParent));
    2569           3 :     if (sameTypeParent) {
    2570           1 :       nsIDocument* doc = sameTypeParent->GetDocument();
    2571           1 :       mBlockAllMixedContent = doc->GetBlockAllMixedContent(false);
    2572             :       // if the parent document makes use of block-all-mixed-content
    2573             :       // then subdocument preloads should always be blocked.
    2574           1 :       mBlockAllMixedContentPreloads =
    2575           1 :         mBlockAllMixedContent || doc->GetBlockAllMixedContent(true);
    2576             : 
    2577           1 :       mUpgradeInsecureRequests = doc->GetUpgradeInsecureRequests(false);
    2578             :       // if the parent document makes use of upgrade-insecure-requests
    2579             :       // then subdocument preloads should always be upgraded.
    2580           1 :       mUpgradeInsecurePreloads =
    2581           1 :         mUpgradeInsecureRequests || doc->GetUpgradeInsecureRequests(true);
    2582             :     }
    2583             :   }
    2584             : 
    2585             :   // If this is not a data document, set CSP.
    2586          25 :   if (!mLoadedAsData) {
    2587          25 :     nsresult rv = InitCSP(aChannel);
    2588          25 :     NS_ENSURE_SUCCESS(rv, rv);
    2589             :   }
    2590             : 
    2591             :   // XFO needs to be checked after CSP because it is ignored if
    2592             :   // the CSP defines frame-ancestors.
    2593          25 :   if (!FramingChecker::CheckFrameOptions(aChannel, docShell, NodePrincipal())) {
    2594           0 :     MOZ_LOG(gCspPRLog, LogLevel::Debug,
    2595             :             ("XFO doesn't like frame's ancestry, not loading."));
    2596             :     // stop!  ERROR page!
    2597           0 :     aChannel->Cancel(NS_ERROR_CSP_FRAME_ANCESTOR_VIOLATION);
    2598             :   }
    2599             : 
    2600          25 :   return NS_OK;
    2601             : }
    2602             : 
    2603             : void
    2604           1 : nsDocument::SendToConsole(nsCOMArray<nsISecurityConsoleMessage>& aMessages)
    2605             : {
    2606           1 :   for (uint32_t i = 0; i < aMessages.Length(); ++i) {
    2607           0 :     nsAutoString messageTag;
    2608           0 :     aMessages[i]->GetTag(messageTag);
    2609             : 
    2610           0 :     nsAutoString category;
    2611           0 :     aMessages[i]->GetCategory(category);
    2612             : 
    2613           0 :     nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
    2614           0 :                                     NS_ConvertUTF16toUTF8(category),
    2615             :                                     this, nsContentUtils::eSECURITY_PROPERTIES,
    2616           0 :                                     NS_ConvertUTF16toUTF8(messageTag).get());
    2617             :   }
    2618           1 : }
    2619             : 
    2620             : void
    2621           0 : nsDocument::ApplySettingsFromCSP(bool aSpeculative)
    2622             : {
    2623           0 :   nsresult rv = NS_OK;
    2624           0 :   if (!aSpeculative) {
    2625             :     // 1) apply settings from regular CSP
    2626           0 :     nsCOMPtr<nsIContentSecurityPolicy> csp;
    2627           0 :     rv = NodePrincipal()->GetCsp(getter_AddRefs(csp));
    2628           0 :     NS_ENSURE_SUCCESS_VOID(rv);
    2629           0 :     if (csp) {
    2630             :       // Set up any Referrer Policy specified by CSP
    2631           0 :       bool hasReferrerPolicy = false;
    2632           0 :       uint32_t referrerPolicy = mozilla::net::RP_Unset;
    2633           0 :       rv = csp->GetReferrerPolicy(&referrerPolicy, &hasReferrerPolicy);
    2634           0 :       NS_ENSURE_SUCCESS_VOID(rv);
    2635           0 :       if (hasReferrerPolicy) {
    2636           0 :         mReferrerPolicy = static_cast<ReferrerPolicy>(referrerPolicy);
    2637           0 :         mReferrerPolicySet = true;
    2638             :       }
    2639             : 
    2640             :       // Set up 'block-all-mixed-content' if not already inherited
    2641             :       // from the parent context or set by any other CSP.
    2642           0 :       if (!mBlockAllMixedContent) {
    2643           0 :         rv = csp->GetBlockAllMixedContent(&mBlockAllMixedContent);
    2644           0 :         NS_ENSURE_SUCCESS_VOID(rv);
    2645             :       }
    2646           0 :       if (!mBlockAllMixedContentPreloads) {
    2647           0 :         mBlockAllMixedContentPreloads = mBlockAllMixedContent;
    2648             :      }
    2649             : 
    2650             :       // Set up 'upgrade-insecure-requests' if not already inherited
    2651             :       // from the parent context or set by any other CSP.
    2652           0 :       if (!mUpgradeInsecureRequests) {
    2653           0 :         rv = csp->GetUpgradeInsecureRequests(&mUpgradeInsecureRequests);
    2654           0 :         NS_ENSURE_SUCCESS_VOID(rv);
    2655             :       }
    2656           0 :       if (!mUpgradeInsecurePreloads) {
    2657           0 :         mUpgradeInsecurePreloads = mUpgradeInsecureRequests;
    2658             :       }
    2659             :     }
    2660           0 :     return;
    2661             :   }
    2662             : 
    2663             :   // 2) apply settings from speculative csp
    2664           0 :   nsCOMPtr<nsIContentSecurityPolicy> preloadCsp;
    2665           0 :   rv = NodePrincipal()->GetPreloadCsp(getter_AddRefs(preloadCsp));
    2666           0 :   NS_ENSURE_SUCCESS_VOID(rv);
    2667           0 :   if (preloadCsp) {
    2668           0 :     if (!mBlockAllMixedContentPreloads) {
    2669           0 :       rv = preloadCsp->GetBlockAllMixedContent(&mBlockAllMixedContentPreloads);
    2670           0 :       NS_ENSURE_SUCCESS_VOID(rv);
    2671             :     }
    2672           0 :     if (!mUpgradeInsecurePreloads) {
    2673           0 :       rv = preloadCsp->GetUpgradeInsecureRequests(&mUpgradeInsecurePreloads);
    2674           0 :       NS_ENSURE_SUCCESS_VOID(rv);
    2675             :     }
    2676             :   }
    2677             : }
    2678             : 
    2679             : nsresult
    2680          25 : nsDocument::InitCSP(nsIChannel* aChannel)
    2681             : {
    2682          25 :   MOZ_ASSERT(!mScriptGlobalObject,
    2683             :              "CSP must be initialized before mScriptGlobalObject is set!");
    2684          25 :   if (!CSPService::sCSPEnabled) {
    2685           0 :     MOZ_LOG(gCspPRLog, LogLevel::Debug,
    2686             :            ("CSP is disabled, skipping CSP init for document %p", this));
    2687           0 :     return NS_OK;
    2688             :   }
    2689             : 
    2690          50 :   nsAutoCString tCspHeaderValue, tCspROHeaderValue;
    2691             : 
    2692          50 :   nsCOMPtr<nsIHttpChannel> httpChannel;
    2693          25 :   nsresult rv = GetHttpChannelHelper(aChannel, getter_AddRefs(httpChannel));
    2694          25 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2695           0 :     return rv;
    2696             :   }
    2697             : 
    2698          25 :   if (httpChannel) {
    2699           2 :     Unused << httpChannel->GetResponseHeader(
    2700           2 :         NS_LITERAL_CSTRING("content-security-policy"),
    2701           2 :         tCspHeaderValue);
    2702             : 
    2703           2 :     Unused << httpChannel->GetResponseHeader(
    2704           2 :         NS_LITERAL_CSTRING("content-security-policy-report-only"),
    2705           2 :         tCspROHeaderValue);
    2706             :   }
    2707          50 :   NS_ConvertASCIItoUTF16 cspHeaderValue(tCspHeaderValue);
    2708          50 :   NS_ConvertASCIItoUTF16 cspROHeaderValue(tCspROHeaderValue);
    2709             : 
    2710             :   // Check if this is a document from a WebExtension.
    2711          50 :   nsString addonId;
    2712          50 :   nsCOMPtr<nsIPrincipal> principal = NodePrincipal();
    2713          25 :   principal->GetAddonId(addonId);
    2714          25 :   bool applyAddonCSP = !addonId.IsEmpty();
    2715             : 
    2716             :   // Check if this is a signed content to apply default CSP.
    2717          25 :   bool applySignedContentCSP = false;
    2718          50 :   nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
    2719          25 :   if (loadInfo && loadInfo->GetVerifySignedContent()) {
    2720           0 :     applySignedContentCSP = true;
    2721             :   }
    2722             : 
    2723             :   // If there's no CSP to apply, go ahead and return early
    2724          75 :   if (!applyAddonCSP &&
    2725          50 :       !applySignedContentCSP &&
    2726          75 :       cspHeaderValue.IsEmpty() &&
    2727          25 :       cspROHeaderValue.IsEmpty()) {
    2728          25 :     if (MOZ_LOG_TEST(gCspPRLog, LogLevel::Debug)) {
    2729           0 :       nsCOMPtr<nsIURI> chanURI;
    2730           0 :       aChannel->GetURI(getter_AddRefs(chanURI));
    2731           0 :       nsAutoCString aspec;
    2732           0 :       chanURI->GetAsciiSpec(aspec);
    2733           0 :       MOZ_LOG(gCspPRLog, LogLevel::Debug,
    2734             :              ("no CSP for document, %s",
    2735             :               aspec.get()));
    2736             :     }
    2737             : 
    2738          25 :     return NS_OK;
    2739             :   }
    2740             : 
    2741           0 :   MOZ_LOG(gCspPRLog, LogLevel::Debug, ("Document is an add-on or CSP header specified %p", this));
    2742             : 
    2743           0 :   nsCOMPtr<nsIContentSecurityPolicy> csp;
    2744           0 :   rv = principal->EnsureCSP(this, getter_AddRefs(csp));
    2745           0 :   NS_ENSURE_SUCCESS(rv, rv);
    2746             : 
    2747             :   // ----- if the doc is an addon, apply its CSP.
    2748           0 :   if (applyAddonCSP) {
    2749           0 :     nsCOMPtr<nsIAddonPolicyService> aps = do_GetService("@mozilla.org/addons/policy-service;1");
    2750             : 
    2751           0 :     nsAutoString addonCSP;
    2752           0 :     rv = aps->GetBaseCSP(addonCSP);
    2753           0 :     if (NS_SUCCEEDED(rv)) {
    2754           0 :       csp->AppendPolicy(addonCSP, false, false);
    2755             :     }
    2756             : 
    2757           0 :     rv = aps->GetAddonCSP(addonId, addonCSP);
    2758           0 :     if (NS_SUCCEEDED(rv)) {
    2759           0 :       csp->AppendPolicy(addonCSP, false, false);
    2760             :     }
    2761             :   }
    2762             : 
    2763             :   // ----- if the doc is a signed content, apply the default CSP.
    2764             :   // Note that when the content signing becomes a standard, we might have
    2765             :   // to restrict this enforcement to "remote content" only.
    2766           0 :   if (applySignedContentCSP) {
    2767             :     nsAdoptingString signedContentCSP =
    2768           0 :       Preferences::GetString("security.signed_content.CSP.default");
    2769           0 :     csp->AppendPolicy(signedContentCSP, false, false);
    2770             :   }
    2771             : 
    2772             :   // ----- if there's a full-strength CSP header, apply it.
    2773           0 :   if (!cspHeaderValue.IsEmpty()) {
    2774           0 :     rv = CSP_AppendCSPFromHeader(csp, cspHeaderValue, false);
    2775           0 :     NS_ENSURE_SUCCESS(rv, rv);
    2776             :   }
    2777             : 
    2778             :   // ----- if there's a report-only CSP header, apply it.
    2779           0 :   if (!cspROHeaderValue.IsEmpty()) {
    2780           0 :     rv = CSP_AppendCSPFromHeader(csp, cspROHeaderValue, true);
    2781           0 :     NS_ENSURE_SUCCESS(rv, rv);
    2782             :   }
    2783             : 
    2784             :   // ----- Enforce sandbox policy if supplied in CSP header
    2785             :   // The document may already have some sandbox flags set (e.g. if the document
    2786             :   // is an iframe with the sandbox attribute set). If we have a CSP sandbox
    2787             :   // directive, intersect the CSP sandbox flags with the existing flags. This
    2788             :   // corresponds to the _least_ permissive policy.
    2789           0 :   uint32_t cspSandboxFlags = SANDBOXED_NONE;
    2790           0 :   rv = csp->GetCSPSandboxFlags(&cspSandboxFlags);
    2791           0 :   NS_ENSURE_SUCCESS(rv, rv);
    2792             : 
    2793           0 :   mSandboxFlags |= cspSandboxFlags;
    2794             : 
    2795             :   // Probably the iframe sandbox attribute already caused the creation of a
    2796             :   // new NullPrincipal. Only create a new NullPrincipal if CSP requires so
    2797             :   // and no one has been created yet.
    2798             :   bool needNewNullPrincipal =
    2799           0 :     (cspSandboxFlags & SANDBOXED_ORIGIN) && !(mSandboxFlags & SANDBOXED_ORIGIN);
    2800           0 :   if (needNewNullPrincipal) {
    2801           0 :     principal = NullPrincipal::CreateWithInheritedAttributes(principal);
    2802           0 :     principal->SetCsp(csp);
    2803           0 :     SetPrincipal(principal);
    2804             :   }
    2805             : 
    2806             :   // ----- Enforce frame-ancestor policy on any applied policies
    2807           0 :   nsCOMPtr<nsIDocShell> docShell(mDocumentContainer);
    2808           0 :   if (docShell) {
    2809           0 :     bool safeAncestry = false;
    2810             : 
    2811             :     // PermitsAncestry sends violation reports when necessary
    2812           0 :     rv = csp->PermitsAncestry(docShell, &safeAncestry);
    2813             : 
    2814           0 :     if (NS_FAILED(rv) || !safeAncestry) {
    2815           0 :       MOZ_LOG(gCspPRLog, LogLevel::Debug,
    2816             :               ("CSP doesn't like frame's ancestry, not loading."));
    2817             :       // stop!  ERROR page!
    2818           0 :       aChannel->Cancel(NS_ERROR_CSP_FRAME_ANCESTOR_VIOLATION);
    2819             :     }
    2820             :   }
    2821           0 :   ApplySettingsFromCSP(false);
    2822           0 :   return NS_OK;
    2823             : }
    2824             : 
    2825             : already_AddRefed<nsIParser>
    2826           0 : nsDocument::CreatorParserOrNull()
    2827             : {
    2828           0 :   nsCOMPtr<nsIParser> parser = mParser;
    2829           0 :   return parser.forget();
    2830             : }
    2831             : 
    2832             : void
    2833           4 : nsDocument::StopDocumentLoad()
    2834             : {
    2835           4 :   if (mParser) {
    2836           0 :     mParserAborted = true;
    2837           0 :     mParser->Terminate();
    2838             :   }
    2839           4 : }
    2840             : 
    2841             : void
    2842          54 : nsDocument::SetDocumentURI(nsIURI* aURI)
    2843             : {
    2844         108 :   nsCOMPtr<nsIURI> oldBase = GetDocBaseURI();
    2845          54 :   mDocumentURI = NS_TryToMakeImmutable(aURI);
    2846          54 :   nsIURI* newBase = GetDocBaseURI();
    2847             : 
    2848          54 :   bool equalBases = false;
    2849             :   // Changing just the ref of a URI does not change how relative URIs would
    2850             :   // resolve wrt to it, so we can treat the bases as equal as long as they're
    2851             :   // equal ignoring the ref.
    2852          54 :   if (oldBase && newBase) {
    2853           0 :     oldBase->EqualsExceptRef(newBase, &equalBases);
    2854             :   }
    2855             :   else {
    2856          54 :     equalBases = !oldBase && !newBase;
    2857             :   }
    2858             : 
    2859             :   // If this is the first time we're setting the document's URI, set the
    2860             :   // document's original URI.
    2861          54 :   if (!mOriginalURI)
    2862          54 :     mOriginalURI = mDocumentURI;
    2863             : 
    2864             :   // If changing the document's URI changed the base URI of the document, we
    2865             :   // need to refresh the hrefs of all the links on the page.
    2866          54 :   if (!equalBases) {
    2867          54 :     RefreshLinkHrefs();
    2868             :   }
    2869          54 : }
    2870             : 
    2871             : void
    2872           0 : nsDocument::SetChromeXHRDocURI(nsIURI* aURI)
    2873             : {
    2874           0 :   mChromeXHRDocURI = aURI;
    2875           0 : }
    2876             : 
    2877             : void
    2878           0 : nsDocument::SetChromeXHRDocBaseURI(nsIURI* aURI)
    2879             : {
    2880           0 :   mChromeXHRDocBaseURI = aURI;
    2881           0 : }
    2882             : 
    2883             : NS_IMETHODIMP
    2884           0 : nsDocument::GetLastModified(nsAString& aLastModified)
    2885             : {
    2886           0 :   nsIDocument::GetLastModified(aLastModified);
    2887           0 :   return NS_OK;
    2888             : }
    2889             : 
    2890             : static void
    2891          25 : GetFormattedTimeString(PRTime aTime, nsAString& aFormattedTimeString)
    2892             : {
    2893             :   PRExplodedTime prtime;
    2894          25 :   PR_ExplodeTime(aTime, PR_LocalTimeParameters, &prtime);
    2895             :   // "MM/DD/YYYY hh:mm:ss"
    2896             :   char formatedTime[24];
    2897          75 :   if (SprintfLiteral(formatedTime, "%02d/%02d/%04d %02d:%02d:%02d",
    2898          50 :                      prtime.tm_month + 1, prtime.tm_mday, int(prtime.tm_year),
    2899             :                      prtime.tm_hour     ,  prtime.tm_min,  prtime.tm_sec)) {
    2900          25 :     CopyASCIItoUTF16(nsDependentCString(formatedTime), aFormattedTimeString);
    2901             :   } else {
    2902             :     // If we for whatever reason failed to find the last modified time
    2903             :     // (or even the current time), fall back to what NS4.x returned.
    2904           0 :     aFormattedTimeString.AssignLiteral(u"01/01/1970 00:00:00");
    2905             :   }
    2906          25 : }
    2907             : 
    2908             : void
    2909           0 : nsIDocument::GetLastModified(nsAString& aLastModified) const
    2910             : {
    2911           0 :   if (!mLastModified.IsEmpty()) {
    2912           0 :     aLastModified.Assign(mLastModified);
    2913             :   } else {
    2914           0 :     GetFormattedTimeString(PR_Now(), aLastModified);
    2915             :   }
    2916           0 : }
    2917             : 
    2918             : void
    2919           0 : nsDocument::AddToNameTable(Element *aElement, nsIAtom* aName)
    2920             : {
    2921           0 :   MOZ_ASSERT(nsGenericHTMLElement::ShouldExposeNameAsHTMLDocumentProperty(aElement),
    2922             :              "Only put elements that need to be exposed as document['name'] in "
    2923             :              "the named table.");
    2924             : 
    2925           0 :   nsIdentifierMapEntry* entry = mIdentifierMap.PutEntry(aName);
    2926             : 
    2927             :   // Null for out-of-memory
    2928           0 :   if (entry) {
    2929           0 :     if (!entry->HasNameElement() &&
    2930           0 :         !entry->HasIdElementExposedAsHTMLDocumentProperty()) {
    2931           0 :       ++mExpandoAndGeneration.generation;
    2932             :     }
    2933           0 :     entry->AddNameElement(this, aElement);
    2934             :   }
    2935           0 : }
    2936             : 
    2937             : void
    2938           0 : nsDocument::RemoveFromNameTable(Element *aElement, nsIAtom* aName)
    2939             : {
    2940             :   // Speed up document teardown
    2941           0 :   if (mIdentifierMap.Count() == 0)
    2942           0 :     return;
    2943             : 
    2944           0 :   nsIdentifierMapEntry* entry = mIdentifierMap.GetEntry(aName);
    2945           0 :   if (!entry) // Could be false if the element was anonymous, hence never added
    2946           0 :     return;
    2947             : 
    2948           0 :   entry->RemoveNameElement(aElement);
    2949           0 :   if (!entry->HasNameElement() &&
    2950           0 :       !entry->HasIdElementExposedAsHTMLDocumentProperty()) {
    2951           0 :     ++mExpandoAndGeneration.generation;
    2952             :   }
    2953             : }
    2954             : 
    2955             : void
    2956        2130 : nsDocument::AddToIdTable(Element *aElement, nsIAtom* aId)
    2957             : {
    2958        2130 :   nsIdentifierMapEntry* entry = mIdentifierMap.PutEntry(aId);
    2959             : 
    2960        2130 :   if (entry) { /* True except on OOM */
    2961        4260 :     if (nsGenericHTMLElement::ShouldExposeIdAsHTMLDocumentProperty(aElement) &&
    2962        2130 :         !entry->HasNameElement() &&
    2963           0 :         !entry->HasIdElementExposedAsHTMLDocumentProperty()) {
    2964           0 :       ++mExpandoAndGeneration.generation;
    2965             :     }
    2966        2130 :     entry->AddIdElement(aElement);
    2967             :   }
    2968        2130 : }
    2969             : 
    2970             : void
    2971          53 : nsDocument::RemoveFromIdTable(Element *aElement, nsIAtom* aId)
    2972             : {
    2973          53 :   NS_ASSERTION(aId, "huhwhatnow?");
    2974             : 
    2975             :   // Speed up document teardown
    2976          53 :   if (mIdentifierMap.Count() == 0) {
    2977           0 :     return;
    2978             :   }
    2979             : 
    2980          53 :   nsIdentifierMapEntry* entry = mIdentifierMap.GetEntry(aId);
    2981          53 :   if (!entry) // Can be null for XML elements with changing ids.
    2982          25 :     return;
    2983             : 
    2984          28 :   entry->RemoveIdElement(aElement);
    2985          56 :   if (nsGenericHTMLElement::ShouldExposeIdAsHTMLDocumentProperty(aElement) &&
    2986          28 :       !entry->HasNameElement() &&
    2987           0 :       !entry->HasIdElementExposedAsHTMLDocumentProperty()) {
    2988           0 :     ++mExpandoAndGeneration.generation;
    2989             :   }
    2990          28 :   if (entry->IsEmpty()) {
    2991          28 :     mIdentifierMap.RemoveEntry(entry);
    2992             :   }
    2993             : }
    2994             : 
    2995             : nsIPrincipal*
    2996          47 : nsDocument::GetPrincipal()
    2997             : {
    2998          47 :   return NodePrincipal();
    2999             : }
    3000             : 
    3001             : extern bool sDisablePrefetchHTTPSPref;
    3002             : 
    3003             : void
    3004          84 : nsDocument::SetPrincipal(nsIPrincipal *aNewPrincipal)
    3005             : {
    3006          84 :   if (aNewPrincipal && mAllowDNSPrefetch && sDisablePrefetchHTTPSPref) {
    3007         110 :     nsCOMPtr<nsIURI> uri;
    3008          55 :     aNewPrincipal->GetURI(getter_AddRefs(uri));
    3009             :     bool isHTTPS;
    3010          55 :     if (!uri || NS_FAILED(uri->SchemeIs("https", &isHTTPS)) ||
    3011             :         isHTTPS) {
    3012          30 :       mAllowDNSPrefetch = false;
    3013             :     }
    3014             :   }
    3015          84 :   mNodeInfoManager->SetDocumentPrincipal(aNewPrincipal);
    3016             : 
    3017             : #ifdef DEBUG
    3018             :   // Validate that the docgroup is set correctly by calling its getter and
    3019             :   // triggering its sanity check.
    3020             :   //
    3021             :   // If we're setting the principal to null, we don't want to perform the check,
    3022             :   // as the document is entering an intermediate state where it does not have a
    3023             :   // principal. It will be given another real principal shortly which we will
    3024             :   // check. It's not unsafe to have a document which has a null principal in the
    3025             :   // same docgroup as another document, so this should not be a problem.
    3026          84 :   if (aNewPrincipal) {
    3027          55 :     GetDocGroup();
    3028             :   }
    3029             : #endif
    3030          84 : }
    3031             : 
    3032             : mozilla::dom::DocGroup*
    3033         848 : nsIDocument::GetDocGroup() const
    3034             : {
    3035             : #ifdef DEBUG
    3036             :   // Sanity check that we have an up-to-date and accurate docgroup
    3037         848 :   if (mDocGroup) {
    3038        1586 :     nsAutoCString docGroupKey;
    3039             : 
    3040             :     // GetKey() can fail, e.g. after the TLD service has shut down.
    3041         793 :     nsresult rv = mozilla::dom::DocGroup::GetKey(NodePrincipal(), docGroupKey);
    3042         793 :     if (NS_SUCCEEDED(rv)) {
    3043         793 :       MOZ_ASSERT(mDocGroup->MatchesKey(docGroupKey));
    3044             :     }
    3045             :     // XXX: Check that the TabGroup is correct as well!
    3046             :   }
    3047             : #endif
    3048             : 
    3049         848 :   return mDocGroup;
    3050             : }
    3051             : 
    3052             : nsresult
    3053         228 : nsIDocument::Dispatch(const char* aName,
    3054             :                       TaskCategory aCategory,
    3055             :                       already_AddRefed<nsIRunnable>&& aRunnable)
    3056             : {
    3057             :   // Note that this method may be called off the main thread.
    3058         228 :   if (mDocGroup) {
    3059          98 :     return mDocGroup->Dispatch(aName, aCategory, Move(aRunnable));
    3060             :   }
    3061         130 :   return DispatcherTrait::Dispatch(aName, aCategory, Move(aRunnable));
    3062             : }
    3063             : 
    3064             : nsISerialEventTarget*
    3065          43 : nsIDocument::EventTargetFor(TaskCategory aCategory) const
    3066             : {
    3067          43 :   if (mDocGroup) {
    3068          22 :     return mDocGroup->EventTargetFor(aCategory);
    3069             :   }
    3070          21 :   return DispatcherTrait::EventTargetFor(aCategory);
    3071             : }
    3072             : 
    3073             : AbstractThread*
    3074           1 : nsIDocument::AbstractMainThreadFor(mozilla::TaskCategory aCategory)
    3075             : {
    3076           1 :   MOZ_ASSERT(NS_IsMainThread());
    3077           1 :   if (mDocGroup) {
    3078           1 :     return mDocGroup->AbstractMainThreadFor(aCategory);
    3079             :   }
    3080           0 :   return DispatcherTrait::AbstractMainThreadFor(aCategory);
    3081             : }
    3082             : 
    3083             : void
    3084           8 : nsIDocument::NoteScriptTrackingStatus(const nsACString& aURL, bool aIsTracking)
    3085             : {
    3086           8 :   if (aIsTracking) {
    3087           0 :     mTrackingScripts.PutEntry(aURL);
    3088             :   } else {
    3089           8 :     MOZ_ASSERT(!mTrackingScripts.Contains(aURL));
    3090             :   }
    3091           8 : }
    3092             : 
    3093             : bool
    3094          13 : nsIDocument::IsScriptTracking(const nsACString& aURL) const
    3095             : {
    3096          13 :   return mTrackingScripts.Contains(aURL);
    3097             : }
    3098             : 
    3099             : bool
    3100           0 : nsIDocument::PrerenderHref(nsIURI* aHref)
    3101             : {
    3102           0 :   MOZ_ASSERT(aHref);
    3103             : 
    3104             :   static bool sPrerenderEnabled = false;
    3105             :   static bool sPrerenderPrefCached = false;
    3106           0 :   if (!sPrerenderPrefCached) {
    3107           0 :     sPrerenderPrefCached = true;
    3108             :     Preferences::AddBoolVarCache(&sPrerenderEnabled,
    3109             :                                  "dom.linkPrerender.enabled",
    3110           0 :                                  false);
    3111             :   }
    3112             : 
    3113             :   // Check if prerender is enabled
    3114           0 :   if (!sPrerenderEnabled) {
    3115           0 :     return false;
    3116             :   }
    3117             : 
    3118           0 :   nsCOMPtr<nsIURI> referrer = GetDocumentURI();
    3119           0 :   bool urisMatch = false;
    3120           0 :   aHref->EqualsExceptRef(referrer, &urisMatch);
    3121           0 :   if (urisMatch) {
    3122             :     // Prerender current document isn't quite meaningful, and we may not be able
    3123             :     // to load it out of process.
    3124           0 :     return false;
    3125             :   }
    3126             : 
    3127           0 :   nsCOMPtr<nsIDocShell> docShell = GetDocShell();
    3128           0 :   nsCOMPtr<nsIWebNavigation> webNav = do_QueryInterface(docShell);
    3129           0 :   NS_ENSURE_TRUE(webNav, false);
    3130             : 
    3131           0 :   bool canGoForward = false;
    3132           0 :   nsresult rv = webNav->GetCanGoForward(&canGoForward);
    3133           0 :   if (NS_FAILED(rv) || canGoForward) {
    3134             :     // Skip prerender on history navigation as we don't support it yet.
    3135             :     // Remove this check once bug 1323650 is implemented.
    3136           0 :     return false;
    3137             :   }
    3138             : 
    3139             :   // Check if the document is in prerender state. We don't prerender in a
    3140             :   // prerendered document.
    3141           0 :   if (docShell->GetIsPrerendered()) {
    3142           0 :     return false;
    3143             :   }
    3144             : 
    3145             :   // We currently do not support prerendering in documents loaded within the
    3146             :   // chrome process.
    3147           0 :   if (!XRE_IsContentProcess()) {
    3148           0 :     return false;
    3149             :   }
    3150             : 
    3151             :   // Adopting an prerendered document is similar to performing a load within a
    3152             :   // different docshell, as the prerendering must have occurred in a different
    3153             :   // docshell.
    3154           0 :   if (!docShell->GetIsOnlyToplevelInTabGroup()) {
    3155           0 :     return false;
    3156             :   }
    3157             : 
    3158           0 :   TabChild* tabChild = TabChild::GetFrom(docShell);
    3159           0 :   NS_ENSURE_TRUE(tabChild, false);
    3160             : 
    3161           0 :   nsCOMPtr<nsIWebBrowserChrome3> wbc3;
    3162           0 :   tabChild->GetWebBrowserChrome(getter_AddRefs(wbc3));
    3163           0 :   NS_ENSURE_TRUE(wbc3, false);
    3164             : 
    3165           0 :   rv = wbc3->StartPrerenderingDocument(aHref, referrer, NodePrincipal());
    3166           0 :   NS_ENSURE_SUCCESS(rv, false);
    3167             : 
    3168           0 :   return true;
    3169             : }
    3170             : 
    3171             : NS_IMETHODIMP
    3172           3 : nsDocument::GetApplicationCache(nsIApplicationCache **aApplicationCache)
    3173             : {
    3174           3 :   NS_IF_ADDREF(*aApplicationCache = mApplicationCache);
    3175             : 
    3176           3 :   return NS_OK;
    3177             : }
    3178             : 
    3179             : NS_IMETHODIMP
    3180           0 : nsDocument::SetApplicationCache(nsIApplicationCache *aApplicationCache)
    3181             : {
    3182           0 :   mApplicationCache = aApplicationCache;
    3183             : 
    3184           0 :   return NS_OK;
    3185             : }
    3186             : 
    3187             : NS_IMETHODIMP
    3188           9 : nsDocument::GetContentType(nsAString& aContentType)
    3189             : {
    3190           9 :   CopyUTF8toUTF16(GetContentTypeInternal(), aContentType);
    3191             : 
    3192           9 :   return NS_OK;
    3193             : }
    3194             : 
    3195             : void
    3196           0 : nsDocument::SetContentType(const nsAString& aContentType)
    3197             : {
    3198           0 :   SetContentTypeInternal(NS_ConvertUTF16toUTF8(aContentType));
    3199           0 : }
    3200             : 
    3201             : bool
    3202           0 : nsDocument::GetAllowPlugins()
    3203             : {
    3204             :   // First, we ask our docshell if it allows plugins.
    3205           0 :   nsCOMPtr<nsIDocShell> docShell(mDocumentContainer);
    3206             : 
    3207           0 :   if (docShell) {
    3208           0 :     bool allowPlugins = false;
    3209           0 :     docShell->GetAllowPlugins(&allowPlugins);
    3210           0 :     if (!allowPlugins) {
    3211           0 :       return false;
    3212             :     }
    3213             : 
    3214             :     // If the docshell allows plugins, we check whether
    3215             :     // we are sandboxed and plugins should not be allowed.
    3216           0 :     if (mSandboxFlags & SANDBOXED_PLUGINS) {
    3217           0 :       return false;
    3218             :     }
    3219             :   }
    3220             : 
    3221           0 :   FlashClassification classification = DocumentFlashClassification();
    3222           0 :   if (classification == FlashClassification::Denied) {
    3223           0 :     return false;
    3224             :   }
    3225             : 
    3226           0 :   return true;
    3227             : }
    3228             : 
    3229             : bool
    3230           2 : nsDocument::IsElementAnimateEnabled(JSContext* aCx, JSObject* /*unused*/)
    3231             : {
    3232           2 :   MOZ_ASSERT(NS_IsMainThread());
    3233             : 
    3234           3 :   return nsContentUtils::IsSystemCaller(aCx) ||
    3235           2 :          nsContentUtils::AnimationsAPICoreEnabled() ||
    3236           2 :          nsContentUtils::AnimationsAPIElementAnimateEnabled();
    3237             : }
    3238             : 
    3239             : bool
    3240          16 : nsDocument::IsWebAnimationsEnabled(JSContext* aCx, JSObject* /*unused*/)
    3241             : {
    3242          16 :   MOZ_ASSERT(NS_IsMainThread());
    3243             : 
    3244          25 :   return nsContentUtils::IsSystemCaller(aCx) ||
    3245          25 :          nsContentUtils::AnimationsAPICoreEnabled();
    3246             : }
    3247             : 
    3248             : DocumentTimeline*
    3249         271 : nsDocument::Timeline()
    3250             : {
    3251         271 :   if (!mDocumentTimeline) {
    3252          44 :     mDocumentTimeline = new DocumentTimeline(this, TimeDuration(0));
    3253             :   }
    3254             : 
    3255         271 :   return mDocumentTimeline;
    3256             : }
    3257             : 
    3258             : void
    3259           0 : nsDocument::GetAnimations(nsTArray<RefPtr<Animation>>& aAnimations)
    3260             : {
    3261             :   // Hold a strong ref for the root element since Element::GetAnimations() calls
    3262             :   // FlushPendingNotifications() which may destroy the element.
    3263           0 :   RefPtr<Element> root = GetRootElement();
    3264           0 :   if (!root) {
    3265           0 :     return;
    3266             :   }
    3267           0 :   AnimationFilter filter;
    3268           0 :   filter.mSubtree = true;
    3269           0 :   root->GetAnimations(filter, aAnimations);
    3270             : }
    3271             : 
    3272             : SVGSVGElement*
    3273           0 : nsIDocument::GetSVGRootElement() const
    3274             : {
    3275           0 :   Element* root = GetRootElement();
    3276           0 :   if (!root || !root->IsSVGElement(nsGkAtoms::svg)) {
    3277           0 :     return nullptr;
    3278             :   }
    3279           0 :   return static_cast<SVGSVGElement*>(root);
    3280             : }
    3281             : 
    3282             : /* Return true if the document is in the focused top-level window, and is an
    3283             :  * ancestor of the focused DOMWindow. */
    3284             : NS_IMETHODIMP
    3285           8 : nsDocument::HasFocus(bool* aResult)
    3286             : {
    3287          16 :   ErrorResult rv;
    3288           8 :   *aResult = nsIDocument::HasFocus(rv);
    3289          16 :   return rv.StealNSResult();
    3290             : }
    3291             : 
    3292             : bool
    3293           8 : nsIDocument::HasFocus(ErrorResult& rv) const
    3294             : {
    3295           8 :   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
    3296           8 :   if (!fm) {
    3297           0 :     rv.Throw(NS_ERROR_NOT_AVAILABLE);
    3298           0 :     return false;
    3299             :   }
    3300             : 
    3301             :   // Is there a focused DOMWindow?
    3302          16 :   nsCOMPtr<mozIDOMWindowProxy> focusedWindow;
    3303           8 :   fm->GetFocusedWindow(getter_AddRefs(focusedWindow));
    3304           8 :   if (!focusedWindow) {
    3305           7 :     return false;
    3306             :   }
    3307             : 
    3308           1 :   nsPIDOMWindowOuter* piWindow = nsPIDOMWindowOuter::From(focusedWindow);
    3309             : 
    3310             :   // Are we an ancestor of the focused DOMWindow?
    3311           1 :   for (nsIDocument* currentDoc = piWindow->GetDoc(); currentDoc;
    3312             :        currentDoc = currentDoc->GetParentDocument()) {
    3313           1 :     if (currentDoc == this) {
    3314             :       // Yes, we are an ancestor
    3315           1 :       return true;
    3316             :     }
    3317             :   }
    3318             : 
    3319           0 :   return false;
    3320             : }
    3321             : 
    3322             : TimeStamp
    3323           0 : nsIDocument::LastFocusTime() const
    3324             : {
    3325           0 :   return mLastFocusTime;
    3326             : }
    3327             : 
    3328             : void
    3329           3 : nsIDocument::SetLastFocusTime(const TimeStamp& aFocusTime)
    3330             : {
    3331           3 :   MOZ_DIAGNOSTIC_ASSERT(!aFocusTime.IsNull());
    3332           3 :   MOZ_DIAGNOSTIC_ASSERT(mLastFocusTime.IsNull() ||
    3333             :                         aFocusTime >= mLastFocusTime);
    3334           3 :   mLastFocusTime = aFocusTime;
    3335           3 : }
    3336             : 
    3337             : NS_IMETHODIMP
    3338           0 : nsDocument::GetReferrer(nsAString& aReferrer)
    3339             : {
    3340           0 :   nsIDocument::GetReferrer(aReferrer);
    3341           0 :   return NS_OK;
    3342             : }
    3343             : 
    3344             : void
    3345           0 : nsIDocument::GetReferrer(nsAString& aReferrer) const
    3346             : {
    3347           0 :   if (mIsSrcdocDocument && mParentDocument)
    3348           0 :       mParentDocument->GetReferrer(aReferrer);
    3349             :   else
    3350           0 :     CopyUTF8toUTF16(mReferrer, aReferrer);
    3351           0 : }
    3352             : 
    3353             : nsresult
    3354           0 : nsIDocument::GetSrcdocData(nsAString &aSrcdocData)
    3355             : {
    3356           0 :   if (mIsSrcdocDocument) {
    3357           0 :     nsCOMPtr<nsIInputStreamChannel> inStrmChan = do_QueryInterface(mChannel);
    3358           0 :     if (inStrmChan) {
    3359           0 :       return inStrmChan->GetSrcdocData(aSrcdocData);
    3360             :     }
    3361             :   }
    3362           0 :   aSrcdocData = NullString();
    3363           0 :   return NS_OK;
    3364             : }
    3365             : 
    3366             : NS_IMETHODIMP
    3367           0 : nsDocument::GetActiveElement(nsIDOMElement **aElement)
    3368             : {
    3369           0 :   nsCOMPtr<nsIDOMElement> el(do_QueryInterface(nsIDocument::GetActiveElement()));
    3370           0 :   el.forget(aElement);
    3371           0 :   return NS_OK;
    3372             : }
    3373             : 
    3374             : Element*
    3375           1 : nsIDocument::GetActiveElement()
    3376             : {
    3377             :   // Get the focused element.
    3378           2 :   if (nsCOMPtr<nsPIDOMWindowOuter> window = GetWindow()) {
    3379           2 :     nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
    3380             :     nsIContent* focusedContent =
    3381           1 :       nsFocusManager::GetFocusedDescendant(window, false,
    3382           2 :                                            getter_AddRefs(focusedWindow));
    3383             :     // be safe and make sure the element is from this document
    3384           1 :     if (focusedContent && focusedContent->OwnerDoc() == this) {
    3385           0 :       if (focusedContent->ChromeOnlyAccess()) {
    3386           0 :         focusedContent = focusedContent->FindFirstNonChromeOnlyAccessContent();
    3387             :       }
    3388           0 :       if (focusedContent) {
    3389           0 :         return focusedContent->AsElement();
    3390             :       }
    3391             :     }
    3392             :   }
    3393             : 
    3394             :   // No focused element anywhere in this document.  Try to get the BODY.
    3395           2 :   RefPtr<nsHTMLDocument> htmlDoc = AsHTMLDocument();
    3396           1 :   if (htmlDoc) {
    3397             :     // Because of IE compatibility, return null when html document doesn't have
    3398             :     // a body.
    3399           0 :     return htmlDoc->GetBody();
    3400             :   }
    3401             : 
    3402             :   // If we couldn't get a BODY, return the root element.
    3403           1 :   return GetDocumentElement();
    3404             : }
    3405             : 
    3406             : NS_IMETHODIMP
    3407           0 : nsDocument::GetCurrentScript(nsIDOMElement **aElement)
    3408             : {
    3409           0 :   nsCOMPtr<nsIDOMElement> el(do_QueryInterface(nsIDocument::GetCurrentScript()));
    3410           0 :   el.forget(aElement);
    3411           0 :   return NS_OK;
    3412             : }
    3413             : 
    3414             : Element*
    3415           0 : nsIDocument::GetCurrentScript()
    3416             : {
    3417           0 :   nsCOMPtr<Element> el(do_QueryInterface(ScriptLoader()->GetCurrentScript()));
    3418           0 :   return el;
    3419             : }
    3420             : 
    3421             : NS_IMETHODIMP
    3422           0 : nsDocument::ElementFromPoint(float aX, float aY, nsIDOMElement** aReturn)
    3423             : {
    3424           0 :   Element* el = nsIDocument::ElementFromPoint(aX, aY);
    3425           0 :   nsCOMPtr<nsIDOMElement> retval = do_QueryInterface(el);
    3426           0 :   retval.forget(aReturn);
    3427           0 :   return NS_OK;
    3428             : }
    3429             : 
    3430             : Element*
    3431           0 : nsIDocument::ElementFromPoint(float aX, float aY)
    3432             : {
    3433           0 :   return ElementFromPointHelper(aX, aY, false, true);
    3434             : }
    3435             : 
    3436             : void
    3437           0 : nsIDocument::ElementsFromPoint(float aX, float aY,
    3438             :                                nsTArray<RefPtr<Element>>& aElements)
    3439             : {
    3440           0 :   ElementsFromPointHelper(aX, aY, nsIDocument::FLUSH_LAYOUT, aElements);
    3441           0 : }
    3442             : 
    3443             : Element*
    3444           0 : nsDocument::ElementFromPointHelper(float aX, float aY,
    3445             :                                    bool aIgnoreRootScrollFrame,
    3446             :                                    bool aFlushLayout)
    3447             : {
    3448           0 :   AutoTArray<RefPtr<Element>, 1> elementArray;
    3449           0 :   ElementsFromPointHelper(aX, aY,
    3450           0 :                           ((aIgnoreRootScrollFrame ? nsIDocument::IGNORE_ROOT_SCROLL_FRAME : 0) |
    3451           0 :                            (aFlushLayout ? nsIDocument::FLUSH_LAYOUT : 0) |
    3452             :                            nsIDocument::IS_ELEMENT_FROM_POINT),
    3453           0 :                           elementArray);
    3454           0 :   if (elementArray.IsEmpty()) {
    3455           0 :     return nullptr;
    3456             :   }
    3457           0 :   return elementArray[0];
    3458             : }
    3459             : 
    3460             : void
    3461           0 : nsDocument::ElementsFromPointHelper(float aX, float aY,
    3462             :                                     uint32_t aFlags,
    3463             :                                     nsTArray<RefPtr<mozilla::dom::Element>>& aElements)
    3464             : {
    3465             :   // As per the the spec, we return null if either coord is negative
    3466           0 :   if (!(aFlags & nsIDocument::IGNORE_ROOT_SCROLL_FRAME) && (aX < 0 || aY < 0)) {
    3467           0 :     return;
    3468             :   }
    3469             : 
    3470           0 :   nscoord x = nsPresContext::CSSPixelsToAppUnits(aX);
    3471           0 :   nscoord y = nsPresContext::CSSPixelsToAppUnits(aY);
    3472           0 :   nsPoint pt(x, y);
    3473             : 
    3474             :   // Make sure the layout information we get is up-to-date, and
    3475             :   // ensure we get a root frame (for everything but XUL)
    3476           0 :   if (aFlags & nsIDocument::FLUSH_LAYOUT) {
    3477           0 :     FlushPendingNotifications(FlushType::Layout);
    3478             :   }
    3479             : 
    3480           0 :   nsIPresShell *ps = GetShell();
    3481           0 :   if (!ps) {
    3482           0 :     return;
    3483             :   }
    3484           0 :   nsIFrame *rootFrame = ps->GetRootFrame();
    3485             : 
    3486             :   // XUL docs, unlike HTML, have no frame tree until everything's done loading
    3487           0 :   if (!rootFrame) {
    3488           0 :     return; // return null to premature XUL callers as a reminder to wait
    3489             :   }
    3490             : 
    3491           0 :   nsTArray<nsIFrame*> outFrames;
    3492             :   // Emulate what GetFrameAtPoint does, since we want all the frames under our
    3493             :   // point.
    3494           0 :   nsLayoutUtils::GetFramesForArea(rootFrame, nsRect(pt, nsSize(1, 1)), outFrames,
    3495             :     nsLayoutUtils::IGNORE_PAINT_SUPPRESSION | nsLayoutUtils::IGNORE_CROSS_DOC |
    3496           0 :     ((aFlags & nsIDocument::IGNORE_ROOT_SCROLL_FRAME) ? nsLayoutUtils::IGNORE_ROOT_SCROLL_FRAME : 0));
    3497             : 
    3498             :   // Dunno when this would ever happen, as we should at least have a root frame under us?
    3499           0 :   if (outFrames.IsEmpty()) {
    3500           0 :     return;
    3501             :   }
    3502             : 
    3503             :   // Used to filter out repeated elements in sequence.
    3504           0 :   nsIContent* lastAdded = nullptr;
    3505             : 
    3506           0 :   for (uint32_t i = 0; i < outFrames.Length(); i++) {
    3507           0 :     nsIContent* node = GetContentInThisDocument(outFrames[i]);
    3508             : 
    3509           0 :     if (!node || !node->IsElement()) {
    3510             :       // If this helper is called via ElementsFromPoint, we need to make sure
    3511             :       // our frame is an element. Otherwise return whatever the top frame is
    3512             :       // even if it isn't the top-painted element.
    3513           0 :       if (!(aFlags & nsIDocument::IS_ELEMENT_FROM_POINT)) {
    3514           0 :         continue;
    3515             :       }
    3516           0 :       node = node->GetParent();
    3517             :     }
    3518           0 :     if (node && node != lastAdded) {
    3519           0 :       aElements.AppendElement(node->AsElement());
    3520           0 :       lastAdded = node;
    3521             :       // If this helper is called via ElementFromPoint, just return the first
    3522             :       // element we find.
    3523           0 :       if (aFlags & nsIDocument::IS_ELEMENT_FROM_POINT) {
    3524           0 :         return;
    3525             :       }
    3526             :     }
    3527             :   }
    3528             : }
    3529             : 
    3530             : nsresult
    3531           0 : nsDocument::NodesFromRectHelper(float aX, float aY,
    3532             :                                 float aTopSize, float aRightSize,
    3533             :                                 float aBottomSize, float aLeftSize,
    3534             :                                 bool aIgnoreRootScrollFrame,
    3535             :                                 bool aFlushLayout,
    3536             :                                 nsIDOMNodeList** aReturn)
    3537             : {
    3538           0 :   NS_ENSURE_ARG_POINTER(aReturn);
    3539             : 
    3540           0 :   nsSimpleContentList* elements = new nsSimpleContentList(this);
    3541           0 :   NS_ADDREF(elements);
    3542           0 :   *aReturn = elements;
    3543             : 
    3544             :   // Following the same behavior of elementFromPoint,
    3545             :   // we don't return anything if either coord is negative
    3546           0 :   if (!aIgnoreRootScrollFrame && (aX < 0 || aY < 0))
    3547           0 :     return NS_OK;
    3548             : 
    3549           0 :   nscoord x = nsPresContext::CSSPixelsToAppUnits(aX - aLeftSize);
    3550           0 :   nscoord y = nsPresContext::CSSPixelsToAppUnits(aY - aTopSize);
    3551           0 :   nscoord w = nsPresContext::CSSPixelsToAppUnits(aLeftSize + aRightSize) + 1;
    3552           0 :   nscoord h = nsPresContext::CSSPixelsToAppUnits(aTopSize + aBottomSize) + 1;
    3553             : 
    3554           0 :   nsRect rect(x, y, w, h);
    3555             : 
    3556             :   // Make sure the layout information we get is up-to-date, and
    3557             :   // ensure we get a root frame (for everything but XUL)
    3558           0 :   if (aFlushLayout) {
    3559           0 :     FlushPendingNotifications(FlushType::Layout);
    3560             :   }
    3561             : 
    3562           0 :   nsIPresShell *ps = GetShell();
    3563           0 :   NS_ENSURE_STATE(ps);
    3564           0 :   nsIFrame *rootFrame = ps->GetRootFrame();
    3565             : 
    3566             :   // XUL docs, unlike HTML, have no frame tree until everything's done loading
    3567           0 :   if (!rootFrame)
    3568           0 :     return NS_OK; // return nothing to premature XUL callers as a reminder to wait
    3569             : 
    3570           0 :   AutoTArray<nsIFrame*,8> outFrames;
    3571           0 :   nsLayoutUtils::GetFramesForArea(rootFrame, rect, outFrames,
    3572             :     nsLayoutUtils::IGNORE_PAINT_SUPPRESSION | nsLayoutUtils::IGNORE_CROSS_DOC |
    3573           0 :     (aIgnoreRootScrollFrame ? nsLayoutUtils::IGNORE_ROOT_SCROLL_FRAME : 0));
    3574             : 
    3575             :   // Used to filter out repeated elements in sequence.
    3576           0 :   nsIContent* lastAdded = nullptr;
    3577             : 
    3578           0 :   for (uint32_t i = 0; i < outFrames.Length(); i++) {
    3579           0 :     nsIContent* node = GetContentInThisDocument(outFrames[i]);
    3580             : 
    3581           0 :     if (node && !node->IsElement() && !node->IsNodeOfType(nsINode::eTEXT)) {
    3582             :       // We have a node that isn't an element or a text node,
    3583             :       // use its parent content instead.
    3584           0 :       node = node->GetParent();
    3585             :     }
    3586           0 :     if (node && node != lastAdded) {
    3587           0 :       elements->AppendElement(node);
    3588           0 :       lastAdded = node;
    3589             :     }
    3590             :   }
    3591             : 
    3592           0 :   return NS_OK;
    3593             : }
    3594             : 
    3595             : NS_IMETHODIMP
    3596           0 : nsDocument::GetElementsByClassName(const nsAString& aClasses,
    3597             :                                    nsIDOMNodeList** aReturn)
    3598             : {
    3599           0 :   *aReturn = nsIDocument::GetElementsByClassName(aClasses).take();
    3600           0 :   return NS_OK;
    3601             : }
    3602             : 
    3603             : already_AddRefed<nsContentList>
    3604           0 : nsIDocument::GetElementsByClassName(const nsAString& aClasses)
    3605             : {
    3606           0 :   return nsContentUtils::GetElementsByClassName(this, aClasses);
    3607             : }
    3608             : 
    3609             : void
    3610           0 : nsIDocument::ReleaseCapture() const
    3611             : {
    3612             :   // only release the capture if the caller can access it. This prevents a
    3613             :   // page from stopping a scrollbar grab for example.
    3614           0 :   nsCOMPtr<nsINode> node = nsIPresShell::GetCapturingContent();
    3615           0 :   if (node && nsContentUtils::CanCallerAccess(node)) {
    3616           0 :     nsIPresShell::SetCapturingContent(nullptr, 0);
    3617             :   }
    3618           0 : }
    3619             : 
    3620             : already_AddRefed<nsIURI>
    3621         255 : nsIDocument::GetBaseURI(bool aTryUseXHRDocBaseURI) const
    3622             : {
    3623         510 :   nsCOMPtr<nsIURI> uri;
    3624         255 :   if (aTryUseXHRDocBaseURI && mChromeXHRDocBaseURI) {
    3625           0 :     uri = mChromeXHRDocBaseURI;
    3626             :   } else {
    3627         255 :     uri = GetDocBaseURI();
    3628             :   }
    3629             : 
    3630         510 :   return uri.forget();
    3631             : }
    3632             : 
    3633             : void
    3634          29 : nsDocument::SetBaseURI(nsIURI* aURI)
    3635             : {
    3636          29 :   if (!aURI && !mDocumentBaseURI) {
    3637          29 :     return;
    3638             :   }
    3639             : 
    3640             :   // Don't do anything if the URI wasn't actually changed.
    3641           0 :   if (aURI && mDocumentBaseURI) {
    3642           0 :     bool equalBases = false;
    3643           0 :     mDocumentBaseURI->Equals(aURI, &equalBases);
    3644           0 :     if (equalBases) {
    3645           0 :       return;
    3646             :     }
    3647             :   }
    3648             : 
    3649           0 :   if (aURI) {
    3650           0 :     mDocumentBaseURI = NS_TryToMakeImmutable(aURI);
    3651             :   } else {
    3652           0 :     mDocumentBaseURI = nullptr;
    3653             :   }
    3654           0 :   RefreshLinkHrefs();
    3655             : }
    3656             : 
    3657             : URLExtraData*
    3658           0 : nsIDocument::DefaultStyleAttrURLData()
    3659             : {
    3660             : #ifdef MOZ_STYLO
    3661             :   MOZ_ASSERT(NS_IsMainThread());
    3662             :   nsIURI* baseURI = GetDocBaseURI();
    3663             :   nsIURI* docURI = GetDocumentURI();
    3664             :   nsIPrincipal* principal = NodePrincipal();
    3665             :   if (!mCachedURLData ||
    3666             :       mCachedURLData->BaseURI() != baseURI ||
    3667             :       mCachedURLData->GetReferrer() != docURI ||
    3668             :       mCachedURLData->GetPrincipal() != principal) {
    3669             :     mCachedURLData = new URLExtraData(baseURI, docURI, principal);
    3670             :   }
    3671             :   return mCachedURLData;
    3672             : #else
    3673           0 :   MOZ_CRASH("Should not be called for non-stylo build");
    3674             :   return nullptr;
    3675             : #endif
    3676             : }
    3677             : 
    3678             : void
    3679           0 : nsDocument::GetBaseTarget(nsAString &aBaseTarget)
    3680             : {
    3681           0 :   aBaseTarget = mBaseTarget;
    3682           0 : }
    3683             : 
    3684             : void
    3685          78 : nsDocument::SetDocumentCharacterSet(NotNull<const Encoding*> aEncoding)
    3686             : {
    3687          78 :   if (mCharacterSet != aEncoding) {
    3688          54 :     mCharacterSet = aEncoding;
    3689             : 
    3690         108 :     nsAutoCString charsetID;
    3691          54 :     aEncoding->Name(charsetID);
    3692         108 :     NS_ConvertASCIItoUTF16 charset16(charsetID);
    3693             : 
    3694          54 :     int32_t n = mCharSetObservers.Length();
    3695             : 
    3696          56 :     for (int32_t i = 0; i < n; i++) {
    3697           2 :       nsIObserver* observer = mCharSetObservers.ElementAt(i);
    3698             : 
    3699           2 :       observer->Observe(static_cast<nsIDocument *>(this), "charset",
    3700           4 :                         charset16.get());
    3701             :     }
    3702             :   }
    3703          78 : }
    3704             : 
    3705             : nsresult
    3706          28 : nsDocument::AddCharSetObserver(nsIObserver* aObserver)
    3707             : {
    3708          28 :   NS_ENSURE_ARG_POINTER(aObserver);
    3709             : 
    3710          28 :   NS_ENSURE_TRUE(mCharSetObservers.AppendElement(aObserver), NS_ERROR_FAILURE);
    3711             : 
    3712          28 :   return NS_OK;
    3713             : }
    3714             : 
    3715             : void
    3716           4 : nsDocument::RemoveCharSetObserver(nsIObserver* aObserver)
    3717             : {
    3718           4 :   mCharSetObservers.RemoveElement(aObserver);
    3719           4 : }
    3720             : 
    3721             : void
    3722           0 : nsIDocument::GetSandboxFlagsAsString(nsAString& aFlags)
    3723             : {
    3724           0 :   nsContentUtils::SandboxFlagsToString(mSandboxFlags, aFlags);
    3725           0 : }
    3726             : 
    3727             : void
    3728          57 : nsDocument::GetHeaderData(nsIAtom* aHeaderField, nsAString& aData) const
    3729             : {
    3730          57 :   aData.Truncate();
    3731          57 :   const nsDocHeaderData* data = mHeaderData;
    3732          57 :   while (data) {
    3733           0 :     if (data->mField == aHeaderField) {
    3734           0 :       aData = data->mData;
    3735             : 
    3736           0 :       break;
    3737             :     }
    3738           0 :     data = data->mNext;
    3739             :   }
    3740          57 : }
    3741             : 
    3742             : void
    3743           0 : nsDocument::SetHeaderData(nsIAtom* aHeaderField, const nsAString& aData)
    3744             : {
    3745           0 :   if (!aHeaderField) {
    3746           0 :     NS_ERROR("null headerField");
    3747           0 :     return;
    3748             :   }
    3749             : 
    3750           0 :   if (!mHeaderData) {
    3751           0 :     if (!aData.IsEmpty()) { // don't bother storing empty string
    3752           0 :       mHeaderData = new nsDocHeaderData(aHeaderField, aData);
    3753             :     }
    3754             :   }
    3755             :   else {
    3756           0 :     nsDocHeaderData* data = mHeaderData;
    3757           0 :     nsDocHeaderData** lastPtr = &mHeaderData;
    3758           0 :     bool found = false;
    3759           0 :     do {  // look for existing and replace
    3760           0 :       if (data->mField == aHeaderField) {
    3761           0 :         if (!aData.IsEmpty()) {
    3762           0 :           data->mData.Assign(aData);
    3763             :         }
    3764             :         else {  // don't store empty string
    3765           0 :           *lastPtr = data->mNext;
    3766           0 :           data->mNext = nullptr;
    3767           0 :           delete data;
    3768             :         }
    3769           0 :         found = true;
    3770             : 
    3771           0 :         break;
    3772             :       }
    3773           0 :       lastPtr = &(data->mNext);
    3774           0 :       data = *lastPtr;
    3775           0 :     } while (data);
    3776             : 
    3777           0 :     if (!aData.IsEmpty() && !found) {
    3778             :       // didn't find, append
    3779           0 :       *lastPtr = new nsDocHeaderData(aHeaderField, aData);
    3780             :     }
    3781             :   }
    3782             : 
    3783           0 :   if (aHeaderField == nsGkAtoms::headerContentLanguage) {
    3784           0 :     CopyUTF16toUTF8(aData, mContentLanguage);
    3785             :   }
    3786             : 
    3787           0 :   if (aHeaderField == nsGkAtoms::headerDefaultStyle) {
    3788             :     // Only mess with our stylesheets if we don't have a lastStyleSheetSet, per
    3789             :     // spec.
    3790           0 :     if (DOMStringIsNull(mLastStyleSheetSet)) {
    3791             :       // Calling EnableStyleSheetsForSetInternal, not SetSelectedStyleSheetSet,
    3792             :       // per spec.  The idea here is that we're changing our preferred set and
    3793             :       // that shouldn't change the value of lastStyleSheetSet.  Also, we're
    3794             :       // using the Internal version so we can update the CSSLoader and not have
    3795             :       // to worry about null strings.
    3796           0 :       EnableStyleSheetsForSetInternal(aData, true);
    3797             :     }
    3798             :   }
    3799             : 
    3800           0 :   if (aHeaderField == nsGkAtoms::refresh) {
    3801             :     // We get into this code before we have a script global yet, so get to
    3802             :     // our container via mDocumentContainer.
    3803           0 :     nsCOMPtr<nsIRefreshURI> refresher(mDocumentContainer);
    3804           0 :     if (refresher) {
    3805             :       // Note: using mDocumentURI instead of mBaseURI here, for consistency
    3806             :       // (used to just use the current URI of our webnavigation, but that
    3807             :       // should really be the same thing).  Note that this code can run
    3808             :       // before the current URI of the webnavigation has been updated, so we
    3809             :       // can't assert equality here.
    3810           0 :       refresher->SetupRefreshURIFromHeader(mDocumentURI, NodePrincipal(),
    3811           0 :                                            NS_ConvertUTF16toUTF8(aData));
    3812             :     }
    3813             :   }
    3814             : 
    3815           0 :   if (aHeaderField == nsGkAtoms::headerDNSPrefetchControl &&
    3816           0 :       mAllowDNSPrefetch) {
    3817             :     // Chromium treats any value other than 'on' (case insensitive) as 'off'.
    3818           0 :     mAllowDNSPrefetch = aData.IsEmpty() || aData.LowerCaseEqualsLiteral("on");
    3819             :   }
    3820             : 
    3821           0 :   if (aHeaderField == nsGkAtoms::viewport ||
    3822           0 :       aHeaderField == nsGkAtoms::handheldFriendly ||
    3823           0 :       aHeaderField == nsGkAtoms::viewport_minimum_scale ||
    3824           0 :       aHeaderField == nsGkAtoms::viewport_maximum_scale ||
    3825           0 :       aHeaderField == nsGkAtoms::viewport_initial_scale ||
    3826           0 :       aHeaderField == nsGkAtoms::viewport_height ||
    3827           0 :       aHeaderField == nsGkAtoms::viewport_width ||
    3828           0 :       aHeaderField ==  nsGkAtoms::viewport_user_scalable) {
    3829           0 :     mViewportType = Unknown;
    3830             :   }
    3831             : 
    3832             :   // Referrer policy spec says to ignore any empty referrer policies.
    3833           0 :   if (aHeaderField == nsGkAtoms::referrer && !aData.IsEmpty()) {
    3834           0 :      ReferrerPolicy policy = mozilla::net::ReferrerPolicyFromString(aData);
    3835             :     // If policy is not the empty string, then set element's node document's
    3836             :     // referrer policy to policy
    3837           0 :     if (policy != mozilla::net::RP_Unset) {
    3838             :       // Referrer policy spec (section 6.1) says that we always use the newest
    3839             :       // referrer policy we find
    3840           0 :       mReferrerPolicy = policy;
    3841           0 :       mReferrerPolicySet = true;
    3842             :     }
    3843             :   }
    3844             : 
    3845           0 :   if (aHeaderField == nsGkAtoms::headerReferrerPolicy && !aData.IsEmpty()) {
    3846           0 :      ReferrerPolicy policy = nsContentUtils::GetReferrerPolicyFromHeader(aData);
    3847           0 :     if (policy != mozilla::net::RP_Unset) {
    3848           0 :       mReferrerPolicy = policy;
    3849           0 :       mReferrerPolicySet = true;
    3850             :     }
    3851             :   }
    3852             : 
    3853             : }
    3854             : void
    3855          25 : nsDocument::TryChannelCharset(nsIChannel *aChannel,
    3856             :                               int32_t& aCharsetSource,
    3857             :                               NotNull<const Encoding*>& aEncoding,
    3858             :                               nsHtml5TreeOpExecutor* aExecutor)
    3859             : {
    3860          25 :   if (aChannel) {
    3861          27 :     nsAutoCString charsetVal;
    3862          25 :     nsresult rv = aChannel->GetContentCharset(charsetVal);
    3863          25 :     if (NS_SUCCEEDED(rv)) {
    3864          25 :       const Encoding* preferred = Encoding::ForLabel(charsetVal);
    3865          25 :       if (preferred) {
    3866          23 :         aEncoding = WrapNotNull(preferred);
    3867          23 :         aCharsetSource = kCharsetFromChannel;
    3868          23 :         return;
    3869           2 :       } else if (aExecutor && !charsetVal.IsEmpty()) {
    3870           0 :         aExecutor->ComplainAboutBogusProtocolCharset(this);
    3871             :       }
    3872             :     }
    3873             :   }
    3874             : }
    3875             : 
    3876             : already_AddRefed<nsIPresShell>
    3877          28 : nsDocument::CreateShell(nsPresContext* aContext, nsViewManager* aViewManager,
    3878             :                         StyleSetHandle aStyleSet)
    3879             : {
    3880          28 :   NS_ASSERTION(!mPresShell, "We have a presshell already!");
    3881             : 
    3882          28 :   NS_ENSURE_FALSE(GetBFCacheEntry(), nullptr);
    3883             : 
    3884          28 :   FillStyleSet(aStyleSet);
    3885             : 
    3886          56 :   RefPtr<PresShell> shell = new PresShell;
    3887          28 :   shell->Init(this, aContext, aViewManager, aStyleSet);
    3888             : 
    3889             :   // Note: we don't hold a ref to the shell (it holds a ref to us)
    3890          28 :   mPresShell = shell;
    3891             : 
    3892             :   // Make sure to never paint if we belong to an invisible DocShell.
    3893          56 :   nsCOMPtr<nsIDocShell> docShell(mDocumentContainer);
    3894          28 :   if (docShell && docShell->IsInvisible())
    3895           0 :     shell->SetNeverPainting(true);
    3896             : 
    3897          28 :   mExternalResourceMap.ShowViewers();
    3898             : 
    3899          28 :   UpdateFrameRequestCallbackSchedulingState();
    3900             : 
    3901             :   // Now that we have a shell, we might have @font-face rules.
    3902          28 :   RebuildUserFontSet();
    3903             : 
    3904          28 :   return shell.forget();
    3905             : }
    3906             : 
    3907             : void
    3908          52 : nsIDocument::UpdateFrameRequestCallbackSchedulingState(nsIPresShell* aOldShell)
    3909             : {
    3910             :   // If the condition for shouldBeScheduled changes to depend on some other
    3911             :   // variable, add UpdateFrameRequestCallbackSchedulingState() calls to the
    3912             :   // places where that variable can change.
    3913             :   bool shouldBeScheduled =
    3914          52 :     mPresShell && IsEventHandlingEnabled() && !mFrameRequestCallbacks.IsEmpty();
    3915          52 :   if (shouldBeScheduled == mFrameRequestCallbacksScheduled) {
    3916             :     // nothing to do
    3917          48 :     return;
    3918             :   }
    3919             : 
    3920           4 :   nsIPresShell* presShell = aOldShell ? aOldShell : mPresShell;
    3921           4 :   MOZ_RELEASE_ASSERT(presShell);
    3922             : 
    3923           4 :   nsRefreshDriver* rd = presShell->GetPresContext()->RefreshDriver();
    3924           4 :   if (shouldBeScheduled) {
    3925           4 :     rd->ScheduleFrameRequestCallbacks(this);
    3926             :   } else {
    3927           0 :     rd->RevokeFrameRequestCallbacks(this);
    3928             :   }
    3929             : 
    3930           4 :   mFrameRequestCallbacksScheduled = shouldBeScheduled;
    3931             : }
    3932             : 
    3933             : void
    3934           4 : nsIDocument::TakeFrameRequestCallbacks(FrameRequestCallbackList& aCallbacks)
    3935             : {
    3936           4 :   aCallbacks.AppendElements(mFrameRequestCallbacks);
    3937           4 :   mFrameRequestCallbacks.Clear();
    3938             :   // No need to manually remove ourselves from the refresh driver; it will
    3939             :   // handle that part.  But we do have to update our state.
    3940           4 :   mFrameRequestCallbacksScheduled = false;
    3941           4 : }
    3942             : 
    3943             : bool
    3944           5 : nsIDocument::ShouldThrottleFrameRequests()
    3945             : {
    3946           5 :   if (mStaticCloneCount > 0) {
    3947             :     // Even if we're not visible, a static clone may be, so run at full speed.
    3948           0 :     return false;
    3949             :   }
    3950             : 
    3951           5 :   if (Hidden()) {
    3952             :     // We're not visible (probably in a background tab or the bf cache).
    3953           0 :     return true;
    3954             :   }
    3955             : 
    3956           5 :   if (!mPresShell) {
    3957           0 :     return false;  // Can't do anything smarter.
    3958             :   }
    3959             : 
    3960           5 :   nsIFrame* frame = mPresShell->GetRootFrame();
    3961           5 :   if (!frame) {
    3962           0 :     return false;  // Can't do anything smarter.
    3963             :   }
    3964             : 
    3965           5 :   nsIFrame* displayRootFrame = nsLayoutUtils::GetDisplayRootFrame(frame);
    3966           5 :   if (!displayRootFrame) {
    3967           0 :     return false;  // Can't do anything smarter.
    3968             :   }
    3969             : 
    3970           5 :   if (!displayRootFrame->DidPaintPresShell(mPresShell)) {
    3971             :     // We didn't get painted during the last paint, so we're not visible.
    3972             :     // Throttle. Note that because we have to paint this document at least
    3973             :     // once to unthrottle it, we will drop one requestAnimationFrame frame
    3974             :     // when a document that previously wasn't visible scrolls into view. This
    3975             :     // is acceptable since it would happen outside the viewport on APZ
    3976             :     // platforms and is unlikely to be human-perceivable on non-APZ platforms.
    3977           1 :     return true;
    3978             :   }
    3979             : 
    3980             :   // We got painted during the last paint, so run at full speed.
    3981           4 :   return false;
    3982             : }
    3983             : 
    3984             : void
    3985           4 : nsDocument::DeleteShell()
    3986             : {
    3987           4 :   mExternalResourceMap.HideViewers();
    3988           4 :   if (nsPresContext* presContext = mPresShell->GetPresContext()) {
    3989           4 :     presContext->RefreshDriver()->CancelPendingEvents(this);
    3990             :   }
    3991             : 
    3992             :   // When our shell goes away, request that all our images be immediately
    3993             :   // discarded, so we don't carry around decoded image data for a document we
    3994             :   // no longer intend to paint.
    3995           4 :   ImageTracker()->RequestDiscardAll();
    3996             : 
    3997             :   // Now that we no longer have a shell, we need to forget about any FontFace
    3998             :   // objects for @font-face rules that came from the style set.
    3999           4 :   RebuildUserFontSet();
    4000             : 
    4001           4 :   nsIPresShell* oldShell = mPresShell;
    4002           4 :   mPresShell = nullptr;
    4003           4 :   UpdateFrameRequestCallbackSchedulingState(oldShell);
    4004           4 :   mStyleSetFilled = false;
    4005           4 : }
    4006             : 
    4007             : static void
    4008           1 : SubDocClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
    4009             : {
    4010           1 :   SubDocMapEntry *e = static_cast<SubDocMapEntry *>(entry);
    4011             : 
    4012           1 :   NS_RELEASE(e->mKey);
    4013           1 :   if (e->mSubDocument) {
    4014           1 :     e->mSubDocument->SetParentDocument(nullptr);
    4015           1 :     NS_RELEASE(e->mSubDocument);
    4016             :   }
    4017           1 : }
    4018             : 
    4019             : static void
    4020           2 : SubDocInitEntry(PLDHashEntryHdr *entry, const void *key)
    4021             : {
    4022             :   SubDocMapEntry *e =
    4023             :     const_cast<SubDocMapEntry *>
    4024           2 :               (static_cast<const SubDocMapEntry *>(entry));
    4025             : 
    4026           2 :   e->mKey = const_cast<Element*>(static_cast<const Element*>(key));
    4027           2 :   NS_ADDREF(e->mKey);
    4028             : 
    4029           2 :   e->mSubDocument = nullptr;
    4030           2 : }
    4031             : 
    4032             : nsresult
    4033           3 : nsDocument::SetSubDocumentFor(Element* aElement, nsIDocument* aSubDoc)
    4034             : {
    4035           3 :   NS_ENSURE_TRUE(aElement, NS_ERROR_UNEXPECTED);
    4036             : 
    4037           3 :   if (!aSubDoc) {
    4038             :     // aSubDoc is nullptr, remove the mapping
    4039             : 
    4040           1 :     if (mSubDocuments) {
    4041           1 :       mSubDocuments->Remove(aElement);
    4042             :     }
    4043             :   } else {
    4044           2 :     if (!mSubDocuments) {
    4045             :       // Create a new hashtable
    4046             : 
    4047             :       static const PLDHashTableOps hash_table_ops =
    4048             :       {
    4049             :         PLDHashTable::HashVoidPtrKeyStub,
    4050             :         PLDHashTable::MatchEntryStub,
    4051             :         PLDHashTable::MoveEntryStub,
    4052             :         SubDocClearEntry,
    4053             :         SubDocInitEntry
    4054             :       };
    4055             : 
    4056           1 :       mSubDocuments = new PLDHashTable(&hash_table_ops, sizeof(SubDocMapEntry));
    4057             :     }
    4058             : 
    4059             :     // Add a mapping to the hash table
    4060             :     auto entry =
    4061           2 :       static_cast<SubDocMapEntry*>(mSubDocuments->Add(aElement, fallible));
    4062             : 
    4063           2 :     if (!entry) {
    4064           0 :       return NS_ERROR_OUT_OF_MEMORY;
    4065             :     }
    4066             : 
    4067           2 :     if (entry->mSubDocument) {
    4068           0 :       entry->mSubDocument->SetParentDocument(nullptr);
    4069             : 
    4070             :       // Release the old sub document
    4071           0 :       NS_RELEASE(entry->mSubDocument);
    4072             :     }
    4073             : 
    4074           2 :     entry->mSubDocument = aSubDoc;
    4075           2 :     NS_ADDREF(entry->mSubDocument);
    4076             : 
    4077           2 :     aSubDoc->SetParentDocument(this);
    4078             :   }
    4079             : 
    4080           3 :   return NS_OK;
    4081             : }
    4082             : 
    4083             : nsIDocument*
    4084          35 : nsDocument::GetSubDocumentFor(nsIContent *aContent) const
    4085             : {
    4086          35 :   if (mSubDocuments && aContent->IsElement()) {
    4087             :     auto entry = static_cast<SubDocMapEntry*>
    4088          34 :                             (mSubDocuments->Search(aContent->AsElement()));
    4089             : 
    4090          34 :     if (entry) {
    4091           0 :       return entry->mSubDocument;
    4092             :     }
    4093             :   }
    4094             : 
    4095          35 :   return nullptr;
    4096             : }
    4097             : 
    4098             : Element*
    4099           1 : nsDocument::FindContentForSubDocument(nsIDocument *aDocument) const
    4100             : {
    4101           1 :   NS_ENSURE_TRUE(aDocument, nullptr);
    4102             : 
    4103           1 :   if (!mSubDocuments) {
    4104           0 :     return nullptr;
    4105             :   }
    4106             : 
    4107           1 :   for (auto iter = mSubDocuments->Iter(); !iter.Done(); iter.Next()) {
    4108           1 :     auto entry = static_cast<SubDocMapEntry*>(iter.Get());
    4109           1 :     if (entry->mSubDocument == aDocument) {
    4110           1 :       return entry->mKey;
    4111             :     }
    4112             :   }
    4113           0 :   return nullptr;
    4114             : }
    4115             : 
    4116             : bool
    4117         397 : nsDocument::IsNodeOfType(uint32_t aFlags) const
    4118             : {
    4119         397 :     return !(aFlags & ~eDOCUMENT);
    4120             : }
    4121             : 
    4122             : Element*
    4123       44692 : nsIDocument::GetRootElement() const
    4124             : {
    4125       44840 :   return (mCachedRootElement && mCachedRootElement->GetParentNode() == this) ?
    4126       44840 :          mCachedRootElement : GetRootElementInternal();
    4127             : }
    4128             : 
    4129             : Element*
    4130         148 : nsDocument::GetRootElementInternal() const
    4131             : {
    4132             :   // We invoke GetRootElement() immediately before the servo traversal, so we
    4133             :   // should always have a cache hit from Servo.
    4134         148 :   MOZ_ASSERT(NS_IsMainThread());
    4135             : 
    4136             :   // Loop backwards because any non-elements, such as doctypes and PIs
    4137             :   // are likely to appear before the root element.
    4138             :   uint32_t i;
    4139         253 :   for (i = mChildren.ChildCount(); i > 0; --i) {
    4140         160 :     nsIContent* child = mChildren.ChildAt(i - 1);
    4141         160 :     if (child->IsElement()) {
    4142          55 :       const_cast<nsDocument*>(this)->mCachedRootElement = child->AsElement();
    4143          55 :       return child->AsElement();
    4144             :     }
    4145             :   }
    4146             : 
    4147          93 :   const_cast<nsDocument*>(this)->mCachedRootElement = nullptr;
    4148          93 :   return nullptr;
    4149             : }
    4150             : 
    4151             : nsIContent *
    4152           0 : nsDocument::GetChildAt(uint32_t aIndex) const
    4153             : {
    4154           0 :   return mChildren.GetSafeChildAt(aIndex);
    4155             : }
    4156             : 
    4157             : int32_t
    4158          10 : nsDocument::IndexOf(const nsINode* aPossibleChild) const
    4159             : {
    4160          10 :   return mChildren.IndexOfChild(aPossibleChild);
    4161             : }
    4162             : 
    4163             : uint32_t
    4164          93 : nsDocument::GetChildCount() const
    4165             : {
    4166          93 :   return mChildren.ChildCount();
    4167             : }
    4168             : 
    4169             : nsIContent * const *
    4170           0 : nsDocument::GetChildArray(uint32_t* aChildCount) const
    4171             : {
    4172           0 :   return mChildren.GetChildArray(aChildCount);
    4173             : }
    4174             : 
    4175             : 
    4176             : nsresult
    4177          88 : nsDocument::InsertChildAt(nsIContent* aKid, uint32_t aIndex,
    4178             :                           bool aNotify)
    4179             : {
    4180          88 :   if (aKid->IsElement() && GetRootElement()) {
    4181           0 :     NS_WARNING("Inserting root element when we already have one");
    4182           0 :     return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
    4183             :   }
    4184             : 
    4185          88 :   return doInsertChildAt(aKid, aIndex, aNotify, mChildren);
    4186             : }
    4187             : 
    4188             : void
    4189           0 : nsDocument::RemoveChildAt(uint32_t aIndex, bool aNotify)
    4190             : {
    4191           0 :   nsCOMPtr<nsIContent> oldKid = GetChildAt(aIndex);
    4192           0 :   if (!oldKid) {
    4193           0 :     return;
    4194             :   }
    4195             : 
    4196           0 :   if (oldKid->IsElement()) {
    4197             :     // Destroy the link map up front before we mess with the child list.
    4198           0 :     DestroyElementMaps();
    4199             :   }
    4200             : 
    4201             :   // Preemptively clear mCachedRootElement, since we may be about to remove it
    4202             :   // from our child list, and we don't want to return this maybe-obsolete value
    4203             :   // from any GetRootElement() calls that happen inside of doRemoveChildAt().
    4204             :   // (NOTE: for this to be useful, doRemoveChildAt() must NOT trigger any
    4205             :   // GetRootElement() calls until after it's removed the child from mChildren.
    4206             :   // Any call before that point would restore this soon-to-be-obsolete cached
    4207             :   // answer, and our clearing here would be fruitless.)
    4208           0 :   mCachedRootElement = nullptr;
    4209           0 :   doRemoveChildAt(aIndex, aNotify, oldKid, mChildren);
    4210           0 :   MOZ_ASSERT(mCachedRootElement != oldKid,
    4211             :              "Stale pointer in mCachedRootElement, after we tried to clear it "
    4212             :              "(maybe somebody called GetRootElement() too early?)");
    4213             : }
    4214             : 
    4215             : void
    4216          34 : nsDocument::EnsureOnDemandBuiltInUASheet(StyleSheet* aSheet)
    4217             : {
    4218          34 :   if (mOnDemandBuiltInUASheets.Contains(aSheet)) {
    4219           0 :     return;
    4220             :   }
    4221          34 :   BeginUpdate(UPDATE_STYLE);
    4222          34 :   AddOnDemandBuiltInUASheet(aSheet);
    4223          34 :   EndUpdate(UPDATE_STYLE);
    4224             : }
    4225             : 
    4226             : void
    4227          34 : nsDocument::AddOnDemandBuiltInUASheet(StyleSheet* aSheet)
    4228             : {
    4229          34 :   MOZ_ASSERT(!mOnDemandBuiltInUASheets.Contains(aSheet));
    4230             : 
    4231             :   // Prepend here so that we store the sheets in mOnDemandBuiltInUASheets in
    4232             :   // the same order that they should end up in the style set.
    4233          34 :   mOnDemandBuiltInUASheets.InsertElementAt(0, aSheet);
    4234             : 
    4235          34 :   if (aSheet->IsApplicable()) {
    4236             :     // This is like |AddStyleSheetToStyleSets|, but for an agent sheet.
    4237          68 :     nsCOMPtr<nsIPresShell> shell = GetShell();
    4238          34 :     if (shell) {
    4239             :       // Note that prepending here is necessary to make sure that html.css etc.
    4240             :       // do not override Firefox OS/Mobile's content.css sheet. Maybe we should
    4241             :       // have an insertion point to match the order of
    4242             :       // nsDocumentViewer::CreateStyleSet though?
    4243          34 :       shell->StyleSet()->PrependStyleSheet(SheetType::Agent, aSheet);
    4244             :     }
    4245             :   }
    4246             : 
    4247          34 :   NotifyStyleSheetAdded(aSheet, false);
    4248          34 : }
    4249             : 
    4250             : int32_t
    4251          14 : nsDocument::GetNumberOfStyleSheets() const
    4252             : {
    4253          14 :   return mStyleSheets.Length();
    4254             : }
    4255             : 
    4256             : StyleSheet*
    4257           5 : nsDocument::GetStyleSheetAt(int32_t aIndex) const
    4258             : {
    4259           5 :   return mStyleSheets.SafeElementAt(aIndex, nullptr);
    4260             : }
    4261             : 
    4262             : int32_t
    4263          26 : nsDocument::GetIndexOfStyleSheet(const StyleSheet* aSheet) const
    4264             : {
    4265          26 :   return mStyleSheets.IndexOf(aSheet);
    4266             : }
    4267             : 
    4268             : void
    4269          11 : nsDocument::AddStyleSheetToStyleSets(StyleSheet* aSheet)
    4270             : {
    4271          22 :   nsCOMPtr<nsIPresShell> shell = GetShell();
    4272          11 :   if (shell) {
    4273          11 :     shell->StyleSet()->AddDocStyleSheet(aSheet, this);
    4274             :   }
    4275          11 : }
    4276             : 
    4277             : #define DO_STYLESHEET_NOTIFICATION(className, type, memberName, argName)      \
    4278             :   do {                                                                        \
    4279             :     className##Init init;                                                     \
    4280             :     init.mBubbles = true;                                                     \
    4281             :     init.mCancelable = true;                                                  \
    4282             :     init.mStylesheet = aSheet;                                                \
    4283             :     init.memberName = argName;                                                \
    4284             :                                                                               \
    4285             :     RefPtr<className> event =                                               \
    4286             :       className::Constructor(this, NS_LITERAL_STRING(type), init);            \
    4287             :     event->SetTrusted(true);                                                  \
    4288             :     event->SetTarget(this);                                                   \
    4289             :     RefPtr<AsyncEventDispatcher> asyncDispatcher =                          \
    4290             :       new AsyncEventDispatcher(this, event);                                  \
    4291             :     asyncDispatcher->mOnlyChromeDispatch = true;                              \
    4292             :     asyncDispatcher->PostDOMEvent();                                          \
    4293             :   } while (0);
    4294             : 
    4295             : void
    4296          46 : nsDocument::NotifyStyleSheetAdded(StyleSheet* aSheet, bool aDocumentSheet)
    4297             : {
    4298          46 :   NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetAdded, (aSheet, aDocumentSheet));
    4299             : 
    4300          46 :   if (StyleSheetChangeEventsEnabled()) {
    4301           0 :     DO_STYLESHEET_NOTIFICATION(StyleSheetChangeEvent,
    4302             :                                "StyleSheetAdded",
    4303             :                                mDocumentSheet,
    4304             :                                aDocumentSheet);
    4305             :   }
    4306          46 : }
    4307             : 
    4308             : void
    4309           0 : nsDocument::NotifyStyleSheetRemoved(StyleSheet* aSheet, bool aDocumentSheet)
    4310             : {
    4311           0 :   NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetRemoved, (aSheet, aDocumentSheet));
    4312             : 
    4313           0 :   if (StyleSheetChangeEventsEnabled()) {
    4314           0 :     DO_STYLESHEET_NOTIFICATION(StyleSheetChangeEvent,
    4315             :                                "StyleSheetRemoved",
    4316             :                                mDocumentSheet,
    4317             :                                aDocumentSheet);
    4318             :   }
    4319           0 : }
    4320             : 
    4321             : void
    4322           0 : nsDocument::AddStyleSheet(StyleSheet* aSheet)
    4323             : {
    4324           0 :   NS_PRECONDITION(aSheet, "null arg");
    4325           0 :   mStyleSheets.AppendElement(aSheet);
    4326           0 :   aSheet->SetAssociatedDocument(this, StyleSheet::OwnedByDocument);
    4327             : 
    4328           0 :   if (aSheet->IsApplicable()) {
    4329           0 :     AddStyleSheetToStyleSets(aSheet);
    4330             :   }
    4331             : 
    4332           0 :   NotifyStyleSheetAdded(aSheet, true);
    4333           0 : }
    4334             : 
    4335             : void
    4336           0 : nsDocument::RemoveStyleSheetFromStyleSets(StyleSheet* aSheet)
    4337             : {
    4338           0 :   nsCOMPtr<nsIPresShell> shell = GetShell();
    4339           0 :   if (shell) {
    4340           0 :     shell->StyleSet()->RemoveDocStyleSheet(aSheet);
    4341             :   }
    4342           0 : }
    4343             : 
    4344             : void
    4345           0 : nsDocument::RemoveStyleSheet(StyleSheet* aSheet)
    4346             : {
    4347           0 :   NS_PRECONDITION(aSheet, "null arg");
    4348           0 :   RefPtr<StyleSheet> sheet = aSheet; // hold ref so it won't die too soon
    4349             : 
    4350           0 :   if (!mStyleSheets.RemoveElement(aSheet)) {
    4351           0 :     NS_ASSERTION(mInUnlinkOrDeletion, "stylesheet not found");
    4352           0 :     return;
    4353             :   }
    4354             : 
    4355           0 :   if (!mIsGoingAway) {
    4356           0 :     if (aSheet->IsApplicable()) {
    4357           0 :       RemoveStyleSheetFromStyleSets(aSheet);
    4358             :     }
    4359             : 
    4360           0 :     NotifyStyleSheetRemoved(aSheet, true);
    4361             :   }
    4362             : 
    4363           0 :   aSheet->ClearAssociatedDocument();
    4364             : }
    4365             : 
    4366             : void
    4367           0 : nsDocument::UpdateStyleSheets(nsTArray<RefPtr<StyleSheet>>& aOldSheets,
    4368             :                               nsTArray<RefPtr<StyleSheet>>& aNewSheets)
    4369             : {
    4370           0 :   BeginUpdate(UPDATE_STYLE);
    4371             : 
    4372             :   // XXX Need to set the sheet on the ownernode, if any
    4373           0 :   NS_PRECONDITION(aOldSheets.Length() == aNewSheets.Length(),
    4374             :                   "The lists must be the same length!");
    4375           0 :   int32_t count = aOldSheets.Length();
    4376             : 
    4377           0 :   RefPtr<StyleSheet> oldSheet;
    4378             :   int32_t i;
    4379           0 :   for (i = 0; i < count; ++i) {
    4380           0 :     oldSheet = aOldSheets[i];
    4381             : 
    4382             :     // First remove the old sheet.
    4383           0 :     NS_ASSERTION(oldSheet, "None of the old sheets should be null");
    4384           0 :     int32_t oldIndex = mStyleSheets.IndexOf(oldSheet);
    4385           0 :     RemoveStyleSheet(oldSheet);  // This does the right notifications
    4386             : 
    4387             :     // Now put the new one in its place.  If it's null, just ignore it.
    4388           0 :     StyleSheet* newSheet = aNewSheets[i];
    4389           0 :     if (newSheet) {
    4390           0 :       mStyleSheets.InsertElementAt(oldIndex, newSheet);
    4391           0 :       newSheet->SetAssociatedDocument(this, StyleSheet::OwnedByDocument);
    4392           0 :       if (newSheet->IsApplicable()) {
    4393           0 :         AddStyleSheetToStyleSets(newSheet);
    4394             :       }
    4395             : 
    4396           0 :       NotifyStyleSheetAdded(newSheet, true);
    4397             :     }
    4398             :   }
    4399             : 
    4400           0 :   EndUpdate(UPDATE_STYLE);
    4401           0 : }
    4402             : 
    4403             : void
    4404          11 : nsDocument::InsertStyleSheetAt(StyleSheet* aSheet, int32_t aIndex)
    4405             : {
    4406          11 :   NS_PRECONDITION(aSheet, "null ptr");
    4407             : 
    4408          11 :   mStyleSheets.InsertElementAt(aIndex, aSheet);
    4409             : 
    4410          11 :   aSheet->SetAssociatedDocument(this, StyleSheet::OwnedByDocument);
    4411             : 
    4412          11 :   if (aSheet->IsApplicable()) {
    4413           0 :     AddStyleSheetToStyleSets(aSheet);
    4414             :   }
    4415             : 
    4416          11 :   NotifyStyleSheetAdded(aSheet, true);
    4417          11 : }
    4418             : 
    4419             : 
    4420             : void
    4421          13 : nsDocument::SetStyleSheetApplicableState(StyleSheet* aSheet,
    4422             :                                          bool aApplicable)
    4423             : {
    4424          13 :   NS_PRECONDITION(aSheet, "null arg");
    4425             : 
    4426             :   // If we're actually in the document style sheet list
    4427          13 :   if (mStyleSheets.IndexOf(aSheet) != mStyleSheets.NoIndex) {
    4428          11 :     if (aApplicable) {
    4429          11 :       AddStyleSheetToStyleSets(aSheet);
    4430             :     } else {
    4431           0 :       RemoveStyleSheetFromStyleSets(aSheet);
    4432             :     }
    4433             :   }
    4434             : 
    4435             :   // We have to always notify, since this will be called for sheets
    4436             :   // that are children of sheets in our style set, as well as some
    4437             :   // sheets for HTMLEditor.
    4438             : 
    4439          13 :   NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetApplicableStateChanged, (aSheet));
    4440             : 
    4441          13 :   if (StyleSheetChangeEventsEnabled()) {
    4442           0 :     DO_STYLESHEET_NOTIFICATION(StyleSheetApplicableStateChangeEvent,
    4443             :                                "StyleSheetApplicableStateChanged",
    4444             :                                mApplicable,
    4445             :                                aApplicable);
    4446             :   }
    4447             : 
    4448          13 :   if (!mSSApplicableStateNotificationPending) {
    4449           7 :     MOZ_RELEASE_ASSERT(NS_IsMainThread());
    4450             :     nsCOMPtr<nsIRunnable> notification =
    4451          14 :       NewRunnableMethod("nsDocument::NotifyStyleSheetApplicableStateChanged",
    4452             :                         this,
    4453          14 :                         &nsDocument::NotifyStyleSheetApplicableStateChanged);
    4454           7 :     mSSApplicableStateNotificationPending =
    4455          14 :       NS_SUCCEEDED(
    4456             :         Dispatch("nsDocument::NotifyStyleSheetApplicableStateChanged",
    4457             :                  TaskCategory::Other, notification.forget()));
    4458             :   }
    4459          13 : }
    4460             : 
    4461             : void
    4462           7 : nsDocument::NotifyStyleSheetApplicableStateChanged()
    4463             : {
    4464           7 :   mSSApplicableStateNotificationPending = false;
    4465             :   nsCOMPtr<nsIObserverService> observerService =
    4466          14 :     mozilla::services::GetObserverService();
    4467           7 :   if (observerService) {
    4468          14 :     observerService->NotifyObservers(static_cast<nsIDocument*>(this),
    4469             :                                      "style-sheet-applicable-state-changed",
    4470          14 :                                      nullptr);
    4471             :   }
    4472           7 : }
    4473             : 
    4474             : static SheetType
    4475           1 : ConvertAdditionalSheetType(nsIDocument::additionalSheetType aType)
    4476             : {
    4477           1 :   switch(aType) {
    4478             :     case nsIDocument::eAgentSheet:
    4479           0 :       return SheetType::Agent;
    4480             :     case nsIDocument::eUserSheet:
    4481           0 :       return SheetType::User;
    4482             :     case nsIDocument::eAuthorSheet:
    4483           1 :       return SheetType::Doc;
    4484             :     default:
    4485           0 :       MOZ_ASSERT(false, "wrong type");
    4486             :       // we must return something although this should never happen
    4487             :       return SheetType::Count;
    4488             :   }
    4489             : }
    4490             : 
    4491             : static int32_t
    4492           0 : FindSheet(const nsTArray<RefPtr<StyleSheet>>& aSheets, nsIURI* aSheetURI)
    4493             : {
    4494           0 :   for (int32_t i = aSheets.Length() - 1; i >= 0; i-- ) {
    4495             :     bool bEqual;
    4496           0 :     nsIURI* uri = aSheets[i]->GetSheetURI();
    4497             : 
    4498           0 :     if (uri && NS_SUCCEEDED(uri->Equals(aSheetURI, &bEqual)) && bEqual)
    4499           0 :       return i;
    4500             :   }
    4501             : 
    4502           0 :   return -1;
    4503             : }
    4504             : 
    4505             : nsresult
    4506           0 : nsDocument::LoadAdditionalStyleSheet(additionalSheetType aType,
    4507             :                                      nsIURI* aSheetURI)
    4508             : {
    4509           0 :   NS_PRECONDITION(aSheetURI, "null arg");
    4510             : 
    4511             :   // Checking if we have loaded this one already.
    4512           0 :   if (FindSheet(mAdditionalSheets[aType], aSheetURI) >= 0)
    4513           0 :     return NS_ERROR_INVALID_ARG;
    4514             : 
    4515             :   // Loading the sheet sync.
    4516             :   RefPtr<css::Loader> loader =
    4517           0 :     new css::Loader(GetStyleBackendType(), GetDocGroup());
    4518             : 
    4519             :   css::SheetParsingMode parsingMode;
    4520           0 :   switch (aType) {
    4521             :     case nsIDocument::eAgentSheet:
    4522           0 :       parsingMode = css::eAgentSheetFeatures;
    4523           0 :       break;
    4524             : 
    4525             :     case nsIDocument::eUserSheet:
    4526           0 :       parsingMode = css::eUserSheetFeatures;
    4527           0 :       break;
    4528             : 
    4529             :     case nsIDocument::eAuthorSheet:
    4530           0 :       parsingMode = css::eAuthorSheetFeatures;
    4531           0 :       break;
    4532             : 
    4533             :     default:
    4534           0 :       MOZ_CRASH("impossible value for aType");
    4535             :   }
    4536             : 
    4537           0 :   RefPtr<StyleSheet> sheet;
    4538           0 :   nsresult rv = loader->LoadSheetSync(aSheetURI, parsingMode, true, &sheet);
    4539           0 :   NS_ENSURE_SUCCESS(rv, rv);
    4540             : 
    4541           0 :   sheet->SetAssociatedDocument(this, StyleSheet::OwnedByDocument);
    4542           0 :   MOZ_ASSERT(sheet->IsApplicable());
    4543             : 
    4544           0 :   return AddAdditionalStyleSheet(aType, sheet);
    4545             : }
    4546             : 
    4547             : nsresult
    4548           1 : nsDocument::AddAdditionalStyleSheet(additionalSheetType aType, StyleSheet* aSheet)
    4549             : {
    4550           1 :   if (mAdditionalSheets[aType].Contains(aSheet))
    4551           0 :     return NS_ERROR_INVALID_ARG;
    4552             : 
    4553           1 :   if (!aSheet->IsApplicable())
    4554           0 :     return NS_ERROR_INVALID_ARG;
    4555             : 
    4556           1 :   mAdditionalSheets[aType].AppendElement(aSheet);
    4557             : 
    4558           1 :   BeginUpdate(UPDATE_STYLE);
    4559           2 :   nsCOMPtr<nsIPresShell> shell = GetShell();
    4560           1 :   if (shell) {
    4561           1 :     SheetType type = ConvertAdditionalSheetType(aType);
    4562           1 :     shell->StyleSet()->AppendStyleSheet(type, aSheet);
    4563             :   }
    4564             : 
    4565             :   // Passing false, so documet.styleSheets.length will not be affected by
    4566             :   // these additional sheets.
    4567           1 :   NotifyStyleSheetAdded(aSheet, false);
    4568           1 :   EndUpdate(UPDATE_STYLE);
    4569           1 :   return NS_OK;
    4570             : }
    4571             : 
    4572             : void
    4573           0 : nsDocument::RemoveAdditionalStyleSheet(additionalSheetType aType, nsIURI* aSheetURI)
    4574             : {
    4575           0 :   MOZ_ASSERT(aSheetURI);
    4576             : 
    4577           0 :   nsTArray<RefPtr<StyleSheet>>& sheets = mAdditionalSheets[aType];
    4578             : 
    4579           0 :   int32_t i = FindSheet(mAdditionalSheets[aType], aSheetURI);
    4580           0 :   if (i >= 0) {
    4581           0 :     RefPtr<StyleSheet> sheetRef = sheets[i];
    4582           0 :     sheets.RemoveElementAt(i);
    4583             : 
    4584           0 :     BeginUpdate(UPDATE_STYLE);
    4585           0 :     if (!mIsGoingAway) {
    4586           0 :       MOZ_ASSERT(sheetRef->IsApplicable());
    4587           0 :       nsCOMPtr<nsIPresShell> shell = GetShell();
    4588           0 :       if (shell) {
    4589           0 :         SheetType type = ConvertAdditionalSheetType(aType);
    4590           0 :         shell->StyleSet()->RemoveStyleSheet(type, sheetRef);
    4591             :       }
    4592             :     }
    4593             : 
    4594             :     // Passing false, so documet.styleSheets.length will not be affected by
    4595             :     // these additional sheets.
    4596           0 :     NotifyStyleSheetRemoved(sheetRef, false);
    4597           0 :     EndUpdate(UPDATE_STYLE);
    4598             : 
    4599           0 :     sheetRef->ClearAssociatedDocument();
    4600             :   }
    4601           0 : }
    4602             : 
    4603             : StyleSheet*
    4604           0 : nsDocument::GetFirstAdditionalAuthorSheet()
    4605             : {
    4606           0 :   return mAdditionalSheets[eAuthorSheet].SafeElementAt(0);
    4607             : }
    4608             : 
    4609             : nsIGlobalObject*
    4610        2588 : nsDocument::GetScopeObject() const
    4611             : {
    4612        5176 :   nsCOMPtr<nsIGlobalObject> scope(do_QueryReferent(mScopeObject));
    4613        5176 :   return scope;
    4614             : }
    4615             : 
    4616             : void
    4617           8 : nsDocument::SetScopeObject(nsIGlobalObject* aGlobal)
    4618             : {
    4619           8 :   mScopeObject = do_GetWeakReference(aGlobal);
    4620           8 :   if (aGlobal) {
    4621           8 :     mHasHadScriptHandlingObject = true;
    4622             : 
    4623          16 :     nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal);
    4624           8 :     if (window) {
    4625             :       // We want to get the tabgroup unconditionally, such that we can make
    4626             :       // certain that it is cached in the inner window early enough.
    4627           8 :       mozilla::dom::TabGroup* tabgroup = window->TabGroup();
    4628             :       // We should already have the principal, and now that we have been added to a
    4629             :       // window, we should be able to join a DocGroup!
    4630          16 :       nsAutoCString docGroupKey;
    4631             :       nsresult rv =
    4632           8 :         mozilla::dom::DocGroup::GetKey(NodePrincipal(), docGroupKey);
    4633           8 :       if (mDocGroup) {
    4634           0 :         if (NS_SUCCEEDED(rv)) {
    4635           0 :           MOZ_RELEASE_ASSERT(mDocGroup->MatchesKey(docGroupKey));
    4636             :         }
    4637           0 :         MOZ_RELEASE_ASSERT(mDocGroup->GetTabGroup() == tabgroup);
    4638             :       } else {
    4639           8 :         mDocGroup = tabgroup->AddDocument(docGroupKey, this);
    4640           8 :         MOZ_ASSERT(mDocGroup);
    4641             :       }
    4642             :     }
    4643             :   }
    4644           8 : }
    4645             : 
    4646             : static void
    4647           0 : CheckIfContainsEMEContent(nsISupports* aSupports, void* aContainsEME)
    4648             : {
    4649           0 :   nsCOMPtr<nsIDOMHTMLMediaElement> domMediaElem(do_QueryInterface(aSupports));
    4650           0 :   if (domMediaElem) {
    4651           0 :     nsCOMPtr<nsIContent> content(do_QueryInterface(domMediaElem));
    4652           0 :     MOZ_ASSERT(content, "aSupports is not a content");
    4653           0 :     HTMLMediaElement* mediaElem = static_cast<HTMLMediaElement*>(content.get());
    4654           0 :     bool* contains = static_cast<bool*>(aContainsEME);
    4655           0 :     if (mediaElem->GetMediaKeys()) {
    4656           0 :       *contains = true;
    4657             :     }
    4658             :   }
    4659           0 : }
    4660             : 
    4661             : bool
    4662           0 : nsDocument::ContainsEMEContent()
    4663             : {
    4664           0 :   bool containsEME = false;
    4665           0 :   EnumerateActivityObservers(CheckIfContainsEMEContent,
    4666           0 :                              static_cast<void*>(&containsEME));
    4667           0 :   return containsEME;
    4668             : }
    4669             : 
    4670             : static void
    4671           0 : CheckIfContainsMSEContent(nsISupports* aSupports, void* aContainsMSE)
    4672             : {
    4673           0 :   nsCOMPtr<nsIDOMHTMLMediaElement> domMediaElem(do_QueryInterface(aSupports));
    4674           0 :   if (domMediaElem) {
    4675           0 :     nsCOMPtr<nsIContent> content(do_QueryInterface(domMediaElem));
    4676           0 :     MOZ_ASSERT(content, "aSupports is not a content");
    4677           0 :     HTMLMediaElement* mediaElem = static_cast<HTMLMediaElement*>(content.get());
    4678           0 :     bool* contains = static_cast<bool*>(aContainsMSE);
    4679           0 :     RefPtr<MediaSource> ms = mediaElem->GetMozMediaSourceObject();
    4680           0 :     if (ms) {
    4681           0 :       *contains = true;
    4682             :     }
    4683             :   }
    4684           0 : }
    4685             : 
    4686             : bool
    4687           0 : nsDocument::ContainsMSEContent()
    4688             : {
    4689           0 :   bool containsMSE = false;
    4690           0 :   EnumerateActivityObservers(CheckIfContainsMSEContent,
    4691           0 :                              static_cast<void*>(&containsMSE));
    4692           0 :   return containsMSE;
    4693             : }
    4694             : 
    4695             : static void
    4696           1 : NotifyActivityChanged(nsISupports *aSupports, void *aUnused)
    4697             : {
    4698           2 :   nsCOMPtr<nsIDOMHTMLMediaElement> domMediaElem(do_QueryInterface(aSupports));
    4699           1 :   if (domMediaElem) {
    4700           2 :     nsCOMPtr<nsIContent> content(do_QueryInterface(domMediaElem));
    4701           1 :     MOZ_ASSERT(content, "aSupports is not a content");
    4702           1 :     HTMLMediaElement* mediaElem = static_cast<HTMLMediaElement*>(content.get());
    4703           1 :     mediaElem->NotifyOwnerDocumentActivityChanged();
    4704             :   }
    4705           2 :   nsCOMPtr<nsIObjectLoadingContent> objectLoadingContent(do_QueryInterface(aSupports));
    4706           1 :   if (objectLoadingContent) {
    4707           0 :     nsObjectLoadingContent* olc = static_cast<nsObjectLoadingContent*>(objectLoadingContent.get());
    4708           0 :     olc->NotifyOwnerDocumentActivityChanged();
    4709             :   }
    4710           2 :   nsCOMPtr<nsIDocumentActivity> objectDocumentActivity(do_QueryInterface(aSupports));
    4711           1 :   if (objectDocumentActivity) {
    4712           0 :     objectDocumentActivity->NotifyOwnerDocumentActivityChanged();
    4713             :   }
    4714           1 : }
    4715             : 
    4716             : void
    4717          50 : nsIDocument::SetContainer(nsDocShell* aContainer)
    4718             : {
    4719          50 :   if (aContainer) {
    4720           8 :     mDocumentContainer = aContainer;
    4721             :   } else {
    4722          42 :     mDocumentContainer = WeakPtr<nsDocShell>();
    4723             :   }
    4724             : 
    4725          50 :   EnumerateActivityObservers(NotifyActivityChanged, nullptr);
    4726          50 :   if (!aContainer) {
    4727          42 :     return;
    4728             :   }
    4729             : 
    4730             :   // Get the Docshell
    4731           8 :   if (aContainer->ItemType() == nsIDocShellTreeItem::typeContent) {
    4732             :     // check if same type root
    4733           6 :     nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot;
    4734           3 :     aContainer->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot));
    4735           3 :     NS_ASSERTION(sameTypeRoot, "No document shell root tree item from document shell tree item!");
    4736             : 
    4737           3 :     if (sameTypeRoot == aContainer) {
    4738           3 :       static_cast<nsDocument*>(this)->SetIsTopLevelContentDocument(true);
    4739             :     }
    4740             : 
    4741           3 :     static_cast<nsDocument*>(this)->SetIsContentDocument(true);
    4742             :   }
    4743             : }
    4744             : 
    4745             : nsISupports*
    4746          51 : nsIDocument::GetContainer() const
    4747             : {
    4748          51 :   return static_cast<nsIDocShell*>(mDocumentContainer);
    4749             : }
    4750             : 
    4751             : void
    4752          16 : nsDocument::SetScriptGlobalObject(nsIScriptGlobalObject *aScriptGlobalObject)
    4753             : {
    4754             : #ifdef DEBUG
    4755             :   {
    4756          32 :     nsCOMPtr<nsPIDOMWindowInner> win(do_QueryInterface(aScriptGlobalObject));
    4757             : 
    4758          16 :     NS_ASSERTION(!win || win->IsInnerWindow(),
    4759             :                  "Script global object must be an inner window!");
    4760             :   }
    4761             : #endif
    4762          16 :   MOZ_ASSERT(aScriptGlobalObject || !mAnimationController ||
    4763             :              mAnimationController->IsPausedByType(
    4764             :                nsSMILTimeContainer::PAUSE_PAGEHIDE |
    4765             :                nsSMILTimeContainer::PAUSE_BEGIN),
    4766             :              "Clearing window pointer while animations are unpaused");
    4767             : 
    4768          16 :   if (mScriptGlobalObject && !aScriptGlobalObject) {
    4769             :     // We're detaching from the window.  We need to grab a pointer to
    4770             :     // our layout history state now.
    4771           4 :     mLayoutHistoryState = GetLayoutHistoryState();
    4772             : 
    4773             :     // Also make sure to remove our onload blocker now if we haven't done it yet
    4774           4 :     if (mOnloadBlockCount != 0) {
    4775           8 :       nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup();
    4776           4 :       if (loadGroup) {
    4777           4 :         loadGroup->RemoveRequest(mOnloadBlocker, nullptr, NS_OK);
    4778             :       }
    4779             :     }
    4780             : 
    4781             :     using mozilla::dom::workers::ServiceWorkerManager;
    4782           8 :     RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
    4783           4 :     if (swm) {
    4784           8 :       ErrorResult error;
    4785           4 :       if (swm->IsControlled(this, error)) {
    4786           0 :         imgLoader* loader = nsContentUtils::GetImgLoaderForDocument(this);
    4787           0 :         if (loader) {
    4788           0 :           loader->ClearCacheForControlledDocument(this);
    4789             :         }
    4790             : 
    4791             :         // We may become controlled again if this document comes back out
    4792             :         // of bfcache.  Clear our state to allow that to happen.  Only
    4793             :         // clear this flag if we are actually controlled, though, so pages
    4794             :         // that were force reloaded don't become controlled when they
    4795             :         // come out of bfcache.
    4796           0 :         mMaybeServiceWorkerControlled = false;
    4797             :       }
    4798           4 :       swm->MaybeStopControlling(this);
    4799             :     }
    4800             : 
    4801             :     // Remove ourself from the list of clients.  We only register
    4802             :     // content principal documents in this list.
    4803           6 :     if (!nsContentUtils::IsSystemPrincipal(GetPrincipal()) &&
    4804           2 :         !GetPrincipal()->GetIsNullPrincipal()) {
    4805           0 :       nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
    4806           0 :       if (os) {
    4807           0 :         os->RemoveObserver(this, "service-worker-get-client");
    4808             :       }
    4809             :     }
    4810             : 
    4811          44 :   } else if (!mScriptGlobalObject && aScriptGlobalObject &&
    4812          20 :              mDocumentContainer && GetChannel() &&
    4813          18 :              !nsContentUtils::IsSystemPrincipal(GetPrincipal()) &&
    4814           2 :              !GetPrincipal()->GetIsNullPrincipal()) {
    4815             :     // This document is being activated.  Register it in the list of
    4816             :     // clients.  We only do this for content principal documents
    4817             :     // since we can never observe system or null principals.
    4818           4 :     nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
    4819           2 :     if (os) {
    4820           2 :       os->AddObserver(this, "service-worker-get-client", /* ownsWeak */ false);
    4821             :     }
    4822             :   }
    4823             : 
    4824             :   // BlockOnload() might be called before mScriptGlobalObject is set.
    4825             :   // We may need to add the blocker once mScriptGlobalObject is set.
    4826          16 :   bool needOnloadBlocker = !mScriptGlobalObject && aScriptGlobalObject;
    4827             : 
    4828          16 :   mScriptGlobalObject = aScriptGlobalObject;
    4829             : 
    4830          16 :   if (needOnloadBlocker) {
    4831           8 :     EnsureOnloadBlocker();
    4832             :   }
    4833             : 
    4834          16 :   UpdateFrameRequestCallbackSchedulingState();
    4835             : 
    4836          16 :   if (aScriptGlobalObject) {
    4837             :     // Go back to using the docshell for the layout history state
    4838           8 :     mLayoutHistoryState = nullptr;
    4839           8 :     SetScopeObject(aScriptGlobalObject);
    4840           8 :     mHasHadDefaultView = true;
    4841             : #ifdef DEBUG
    4842           8 :     if (!mWillReparent) {
    4843             :       // We really shouldn't have a wrapper here but if we do we need to make sure
    4844             :       // it has the correct parent.
    4845           8 :       JSObject *obj = GetWrapperPreserveColor();
    4846           8 :       if (obj) {
    4847           0 :         JSObject *newScope = aScriptGlobalObject->GetGlobalJSObject();
    4848           0 :         NS_ASSERTION(js::GetGlobalForObjectCrossCompartment(obj) == newScope,
    4849             :                      "Wrong scope, this is really bad!");
    4850             :       }
    4851             :     }
    4852             : #endif
    4853             : 
    4854           8 :     if (mAllowDNSPrefetch) {
    4855           8 :       nsCOMPtr<nsIDocShell> docShell(mDocumentContainer);
    4856           4 :       if (docShell) {
    4857             : #ifdef DEBUG
    4858             :         nsCOMPtr<nsIWebNavigation> webNav =
    4859           8 :           do_GetInterface(aScriptGlobalObject);
    4860           4 :         NS_ASSERTION(SameCOMIdentity(webNav, docShell),
    4861             :                      "Unexpected container or script global?");
    4862             : #endif
    4863             :         bool allowDNSPrefetch;
    4864           4 :         docShell->GetAllowDNSPrefetch(&allowDNSPrefetch);
    4865           4 :         mAllowDNSPrefetch = allowDNSPrefetch;
    4866             :       }
    4867             :     }
    4868             : 
    4869             :     // If we are set in a window that is already focused we should remember this
    4870             :     // as the time the document gained focus.
    4871           8 :     bool focused = false;
    4872           8 :     Unused << HasFocus(&focused);
    4873           8 :     if (focused) {
    4874           1 :       SetLastFocusTime(TimeStamp::Now());
    4875             :     }
    4876             :   }
    4877             : 
    4878             :   // Remember the pointer to our window (or lack there of), to avoid
    4879             :   // having to QI every time it's asked for.
    4880          32 :   nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(mScriptGlobalObject);
    4881          16 :   mWindow = window;
    4882             : 
    4883             :   // Now that we know what our window is, we can flush the CSP errors to the
    4884             :   // Web Console. We are flushing all messages that occured and were stored
    4885             :   // in the queue prior to this point.
    4886          32 :   nsCOMPtr<nsIContentSecurityPolicy> csp;
    4887          16 :   NodePrincipal()->GetCsp(getter_AddRefs(csp));
    4888          16 :   if (csp) {
    4889           0 :     static_cast<nsCSPContext*>(csp.get())->flushConsoleMessages();
    4890             :   }
    4891             : 
    4892             :   nsCOMPtr<nsIHttpChannelInternal> internalChannel =
    4893          32 :     do_QueryInterface(GetChannel());
    4894          16 :   if (internalChannel) {
    4895           2 :     nsCOMArray<nsISecurityConsoleMessage> messages;
    4896           2 :     DebugOnly<nsresult> rv = internalChannel->TakeAllSecurityMessages(messages);
    4897           1 :     MOZ_ASSERT(NS_SUCCEEDED(rv));
    4898           1 :     SendToConsole(messages);
    4899             :   }
    4900             : 
    4901             :   // Set our visibility state, but do not fire the event.  This is correct
    4902             :   // because either we're coming out of bfcache (in which case IsVisible() will
    4903             :   // still test false at this point and no state change will happen) or we're
    4904             :   // doing the initial document load and don't want to fire the event for this
    4905             :   // change.
    4906          16 :   dom::VisibilityState oldState = mVisibilityState;
    4907          16 :   mVisibilityState = GetVisibilityState();
    4908             :   // When the visibility is changed, notify it to observers.
    4909             :   // Some observers need the notification, for example HTMLMediaElement uses
    4910             :   // it to update internal media resource allocation.
    4911             :   // When video is loaded via VideoDocument, HTMLMediaElement and MediaDecoder
    4912             :   // creation are already done before nsDocument::SetScriptGlobalObject() call.
    4913             :   // MediaDecoder decides whether starting decoding is decided based on
    4914             :   // document's visibility. When the MediaDecoder is created,
    4915             :   // nsDocument::SetScriptGlobalObject() is not yet called and document is
    4916             :   // hidden state. Therefore the MediaDecoder decides that decoding is
    4917             :   // not yet necessary. But soon after nsDocument::SetScriptGlobalObject()
    4918             :   // call, the document becomes not hidden. At the time, MediaDecoder needs
    4919             :   // to know it and needs to start updating decoding.
    4920          16 :   if (oldState != mVisibilityState) {
    4921           8 :     EnumerateActivityObservers(NotifyActivityChanged, nullptr);
    4922             :   }
    4923             : 
    4924             :   // The global in the template contents owner document should be the same.
    4925          16 :   if (mTemplateContentsOwner && mTemplateContentsOwner != this) {
    4926           0 :     mTemplateContentsOwner->SetScriptGlobalObject(aScriptGlobalObject);
    4927             :   }
    4928             : 
    4929          16 :   if (!mMaybeServiceWorkerControlled && mDocumentContainer && mScriptGlobalObject && GetChannel()) {
    4930           8 :     nsCOMPtr<nsIDocShell> docShell(mDocumentContainer);
    4931             :     uint32_t loadType;
    4932           4 :     docShell->GetLoadType(&loadType);
    4933             : 
    4934             :     // If we are shift-reloaded, don't associate with a ServiceWorker.
    4935           4 :     if (IsForceReloadType(loadType)) {
    4936           0 :       NS_WARNING("Page was shift reloaded, skipping ServiceWorker control");
    4937           0 :       return;
    4938             :     }
    4939             : 
    4940           8 :     nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
    4941           4 :     if (swm) {
    4942             :       // If this document is being resurrected from the bfcache, then we may
    4943             :       // already have a document ID.  In that case reuse the same ID.  Otherwise
    4944             :       // get our document ID from the docshell.
    4945           8 :       nsString documentId(GetId());
    4946           4 :       if (documentId.IsEmpty()) {
    4947           4 :         static_cast<nsDocShell*>(docShell.get())->GetInterceptedDocumentId(documentId);
    4948             :       }
    4949             : 
    4950           4 :       swm->MaybeStartControlling(this, documentId);
    4951           4 :       mMaybeServiceWorkerControlled = true;
    4952             :     }
    4953             :   }
    4954             : }
    4955             : 
    4956             : nsIScriptGlobalObject*
    4957          88 : nsDocument::GetScriptHandlingObjectInternal() const
    4958             : {
    4959          88 :   MOZ_ASSERT(!mScriptGlobalObject,
    4960             :              "Do not call this when mScriptGlobalObject is set!");
    4961          88 :   if (mHasHadDefaultView) {
    4962           0 :     return nullptr;
    4963             :   }
    4964             : 
    4965             :   nsCOMPtr<nsIScriptGlobalObject> scriptHandlingObject =
    4966         176 :     do_QueryReferent(mScopeObject);
    4967         176 :   nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(scriptHandlingObject);
    4968          88 :   if (win) {
    4969           0 :     nsPIDOMWindowOuter* outer = win->GetOuterWindow();
    4970           0 :     if (!outer || outer->GetCurrentInnerWindow() != win) {
    4971           0 :       NS_WARNING("Wrong inner/outer window combination!");
    4972           0 :       return nullptr;
    4973             :     }
    4974             :   }
    4975          88 :   return scriptHandlingObject;
    4976             : }
    4977             : void
    4978           0 : nsDocument::SetScriptHandlingObject(nsIScriptGlobalObject* aScriptObject)
    4979             : {
    4980           0 :   NS_ASSERTION(!mScriptGlobalObject ||
    4981             :                mScriptGlobalObject == aScriptObject,
    4982             :                "Wrong script object!");
    4983           0 :   if (aScriptObject) {
    4984           0 :     SetScopeObject(aScriptObject);
    4985           0 :     mHasHadDefaultView = false;
    4986             :   }
    4987           0 : }
    4988             : 
    4989             : nsPIDOMWindowOuter*
    4990         334 : nsDocument::GetWindowInternal() const
    4991             : {
    4992         334 :   MOZ_ASSERT(!mWindow, "This should not be called when mWindow is not null!");
    4993             :   // Let's use mScriptGlobalObject. Even if the document is already removed from
    4994             :   // the docshell, the outer window might be still obtainable from the it.
    4995         668 :   nsCOMPtr<nsPIDOMWindowOuter> win;
    4996         334 :   if (mRemovedFromDocShell) {
    4997             :     // The docshell returns the outer window we are done.
    4998           0 :     nsCOMPtr<nsIDocShell> kungFuDeathGrip(mDocumentContainer);
    4999           0 :     if (kungFuDeathGrip) {
    5000           0 :       win = kungFuDeathGrip->GetWindow();
    5001             :     }
    5002             :   } else {
    5003         668 :     if (nsCOMPtr<nsPIDOMWindowInner> inner = do_QueryInterface(mScriptGlobalObject)) {
    5004             :       // mScriptGlobalObject is always the inner window, let's get the outer.
    5005           0 :       win = inner->GetOuterWindow();
    5006             :     }
    5007             :   }
    5008             : 
    5009         668 :   return win;
    5010             : }
    5011             : 
    5012             : ScriptLoader*
    5013          81 : nsDocument::ScriptLoader()
    5014             : {
    5015          81 :   return mScriptLoader;
    5016             : }
    5017             : 
    5018             : bool
    5019          25 : nsDocument::InternalAllowXULXBL()
    5020             : {
    5021          25 :   if (nsContentUtils::AllowXULXBLForPrincipal(NodePrincipal())) {
    5022          21 :     mAllowXULXBL = eTriTrue;
    5023          21 :     return true;
    5024             :   }
    5025             : 
    5026           4 :   mAllowXULXBL = eTriFalse;
    5027           4 :   return false;
    5028             : }
    5029             : 
    5030             : // Note: We don't hold a reference to the document observer; we assume
    5031             : // that it has a live reference to the document.
    5032             : void
    5033          76 : nsDocument::AddObserver(nsIDocumentObserver* aObserver)
    5034             : {
    5035          76 :   NS_ASSERTION(mObservers.IndexOf(aObserver) == nsTArray<int>::NoIndex,
    5036             :                "Observer already in the list");
    5037          76 :   mObservers.AppendElement(aObserver);
    5038          76 :   AddMutationObserver(aObserver);
    5039          76 : }
    5040             : 
    5041             : bool
    5042          50 : nsDocument::RemoveObserver(nsIDocumentObserver* aObserver)
    5043             : {
    5044             :   // If we're in the process of destroying the document (and we're
    5045             :   // informing the observers of the destruction), don't remove the
    5046             :   // observers from the list. This is not a big deal, since we
    5047             :   // don't hold a live reference to the observers.
    5048          50 :   if (!mInDestructor) {
    5049          50 :     RemoveMutationObserver(aObserver);
    5050          50 :     return mObservers.RemoveElement(aObserver);
    5051             :   }
    5052             : 
    5053           0 :   return mObservers.Contains(aObserver);
    5054             : }
    5055             : 
    5056             : void
    5057         792 : nsDocument::MaybeEndOutermostXBLUpdate()
    5058             : {
    5059             :   // Only call BindingManager()->EndOutermostUpdate() when
    5060             :   // we're not in an update and it is safe to run scripts.
    5061         792 :   if (mUpdateNestLevel == 0 && mInXBLUpdate) {
    5062         515 :     if (nsContentUtils::IsSafeToRunScript()) {
    5063         459 :       mInXBLUpdate = false;
    5064         459 :       BindingManager()->EndOutermostUpdate();
    5065          56 :     } else if (!mInDestructor) {
    5066          56 :       if (!mMaybeEndOutermostXBLUpdateRunner) {
    5067             :         mMaybeEndOutermostXBLUpdateRunner =
    5068          62 :           NewRunnableMethod("nsDocument::MaybeEndOutermostXBLUpdate",
    5069             :                             this,
    5070          31 :                             &nsDocument::MaybeEndOutermostXBLUpdate);
    5071             :       }
    5072          56 :       nsContentUtils::AddScriptRunner(mMaybeEndOutermostXBLUpdateRunner);
    5073             :     }
    5074             :   }
    5075         792 : }
    5076             : 
    5077             : void
    5078         736 : nsDocument::BeginUpdate(nsUpdateType aUpdateType)
    5079             : {
    5080             :   // If the document is going away, then it's probably okay to do things to it
    5081             :   // in the wrong DocGroup. We're unlikely to run JS or do anything else
    5082             :   // observable at this point. We reach this point when cycle collecting a
    5083             :   // <link> element and the unlink code removes a style sheet.
    5084         736 :   if (mDocGroup && !mIsGoingAway && !mInUnlinkOrDeletion && !mIgnoreDocGroupMismatches) {
    5085         454 :     mDocGroup->ValidateAccess();
    5086             :   }
    5087             : 
    5088         736 :   if (mUpdateNestLevel == 0 && !mInXBLUpdate) {
    5089         459 :     mInXBLUpdate = true;
    5090         459 :     BindingManager()->BeginOutermostUpdate();
    5091             :   }
    5092             : 
    5093         736 :   ++mUpdateNestLevel;
    5094         736 :   nsContentUtils::AddScriptBlocker();
    5095         736 :   NS_DOCUMENT_NOTIFY_OBSERVERS(BeginUpdate, (this, aUpdateType));
    5096         736 : }
    5097             : 
    5098             : void
    5099         736 : nsDocument::EndUpdate(nsUpdateType aUpdateType)
    5100             : {
    5101         736 :   NS_DOCUMENT_NOTIFY_OBSERVERS(EndUpdate, (this, aUpdateType));
    5102             : 
    5103         736 :   nsContentUtils::RemoveScriptBlocker();
    5104             : 
    5105         736 :   --mUpdateNestLevel;
    5106             : 
    5107             :   // This set of updates may have created XBL bindings.  Let the
    5108             :   // binding manager know we're done.
    5109         736 :   MaybeEndOutermostXBLUpdate();
    5110             : 
    5111         736 :   MaybeInitializeFinalizeFrameLoaders();
    5112         736 : }
    5113             : 
    5114             : void
    5115          25 : nsDocument::BeginLoad()
    5116             : {
    5117             :   // Block onload here to prevent having to deal with blocking and
    5118             :   // unblocking it while we know the document is loading.
    5119          25 :   BlockOnload();
    5120          25 :   mDidFireDOMContentLoaded = false;
    5121          25 :   BlockDOMContentLoaded();
    5122             : 
    5123          25 :   if (mScriptLoader) {
    5124          25 :     mScriptLoader->BeginDeferringScripts();
    5125             :   }
    5126             : 
    5127          25 :   NS_DOCUMENT_NOTIFY_OBSERVERS(BeginLoad, (this));
    5128          25 : }
    5129             : 
    5130             : void
    5131           0 : nsDocument::ReportEmptyGetElementByIdArg()
    5132             : {
    5133           0 :   nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
    5134           0 :                                   NS_LITERAL_CSTRING("DOM"), this,
    5135             :                                   nsContentUtils::eDOM_PROPERTIES,
    5136           0 :                                   "EmptyGetElementByIdParam");
    5137           0 : }
    5138             : 
    5139             : Element*
    5140          25 : nsDocument::GetElementById(const nsAString& aElementId)
    5141             : {
    5142          25 :   if (!CheckGetElementByIdArg(aElementId)) {
    5143           0 :     return nullptr;
    5144             :   }
    5145             : 
    5146          25 :   nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(aElementId);
    5147          25 :   return entry ? entry->GetIdElement() : nullptr;
    5148             : }
    5149             : 
    5150             : const nsTArray<Element*>*
    5151           3 : nsDocument::GetAllElementsForId(const nsAString& aElementId) const
    5152             : {
    5153           3 :   if (aElementId.IsEmpty()) {
    5154           0 :     return nullptr;
    5155             :   }
    5156             : 
    5157           3 :   nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(aElementId);
    5158           3 :   return entry ? &entry->GetIdElements() : nullptr;
    5159             : }
    5160             : 
    5161             : NS_IMETHODIMP
    5162           9 : nsDocument::GetElementById(const nsAString& aId, nsIDOMElement** aReturn)
    5163             : {
    5164           9 :   Element *content = GetElementById(aId);
    5165           9 :   if (content) {
    5166           9 :     return CallQueryInterface(content, aReturn);
    5167             :   }
    5168             : 
    5169           0 :   *aReturn = nullptr;
    5170             : 
    5171           0 :   return NS_OK;
    5172             : }
    5173             : 
    5174             : Element*
    5175          25 : nsDocument::AddIDTargetObserver(nsIAtom* aID, IDTargetObserver aObserver,
    5176             :                                 void* aData, bool aForImage)
    5177             : {
    5178          50 :   nsDependentAtomString id(aID);
    5179             : 
    5180          25 :   if (!CheckGetElementByIdArg(id))
    5181           0 :     return nullptr;
    5182             : 
    5183          25 :   nsIdentifierMapEntry* entry = mIdentifierMap.PutEntry(aID);
    5184          25 :   NS_ENSURE_TRUE(entry, nullptr);
    5185             : 
    5186          25 :   entry->AddContentChangeCallback(aObserver, aData, aForImage);
    5187          25 :   return aForImage ? entry->GetImageIdElement() : entry->GetIdElement();
    5188             : }
    5189             : 
    5190             : void
    5191           0 : nsDocument::RemoveIDTargetObserver(nsIAtom* aID, IDTargetObserver aObserver,
    5192             :                                    void* aData, bool aForImage)
    5193             : {
    5194           0 :   nsDependentAtomString id(aID);
    5195             : 
    5196           0 :   if (!CheckGetElementByIdArg(id))
    5197           0 :     return;
    5198             : 
    5199           0 :   nsIdentifierMapEntry* entry = mIdentifierMap.GetEntry(aID);
    5200           0 :   if (!entry) {
    5201           0 :     return;
    5202             :   }
    5203             : 
    5204           0 :   entry->RemoveContentChangeCallback(aObserver, aData, aForImage);
    5205             : }
    5206             : 
    5207             : NS_IMETHODIMP
    5208           0 : nsDocument::MozSetImageElement(const nsAString& aImageElementId,
    5209             :                                nsIDOMElement* aImageElement)
    5210             : {
    5211           0 :   nsCOMPtr<Element> el = do_QueryInterface(aImageElement);
    5212           0 :   MozSetImageElement(aImageElementId, el);
    5213           0 :   return NS_OK;
    5214             : }
    5215             : 
    5216             : void
    5217           0 : nsDocument::MozSetImageElement(const nsAString& aImageElementId,
    5218             :                                Element* aElement)
    5219             : {
    5220           0 :   if (aImageElementId.IsEmpty())
    5221           0 :     return;
    5222             : 
    5223             :   // Hold a script blocker while calling SetImageElement since that can call
    5224             :   // out to id-observers
    5225           0 :   nsAutoScriptBlocker scriptBlocker;
    5226             : 
    5227           0 :   nsIdentifierMapEntry *entry = mIdentifierMap.PutEntry(aImageElementId);
    5228           0 :   if (entry) {
    5229           0 :     entry->SetImageElement(aElement);
    5230           0 :     if (entry->IsEmpty()) {
    5231           0 :       mIdentifierMap.RemoveEntry(entry);
    5232             :     }
    5233             :   }
    5234             : }
    5235             : 
    5236             : Element*
    5237           0 : nsDocument::LookupImageElement(const nsAString& aId)
    5238             : {
    5239           0 :   if (aId.IsEmpty())
    5240           0 :     return nullptr;
    5241             : 
    5242           0 :   nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(aId);
    5243           0 :   return entry ? entry->GetImageIdElement() : nullptr;
    5244             : }
    5245             : 
    5246             : void
    5247          26 : nsDocument::DispatchContentLoadedEvents()
    5248             : {
    5249             :   // If you add early returns from this method, make sure you're
    5250             :   // calling UnblockOnload properly.
    5251             : 
    5252             :   // Unpin references to preloaded images
    5253          26 :   mPreloadingImages.Clear();
    5254             : 
    5255             :   // DOM manipulation after content loaded should not care if the element
    5256             :   // came from the preloader.
    5257          26 :   mPreloadedPreconnects.Clear();
    5258             : 
    5259          26 :   if (mTiming) {
    5260          25 :     mTiming->NotifyDOMContentLoadedStart(nsIDocument::GetDocumentURI());
    5261             :   }
    5262             : 
    5263             :   // Dispatch observer notification to notify observers document is interactive.
    5264          52 :   nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
    5265          26 :   if (os) {
    5266          26 :     nsIPrincipal *principal = GetPrincipal();
    5267          52 :     os->NotifyObservers(static_cast<nsIDocument*>(this),
    5268          26 :                         nsContentUtils::IsSystemPrincipal(principal) ?
    5269             :                           "chrome-document-interactive" :
    5270             :                           "content-document-interactive",
    5271          52 :                         nullptr);
    5272             :   }
    5273             : 
    5274             :   // Fire a DOM event notifying listeners that this document has been
    5275             :   // loaded (excluding images and other loads initiated by this
    5276             :   // document).
    5277          26 :   nsContentUtils::DispatchTrustedEvent(this, static_cast<nsIDocument*>(this),
    5278          52 :                                        NS_LITERAL_STRING("DOMContentLoaded"),
    5279          52 :                                        true, false);
    5280             : 
    5281          52 :   RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
    5282          26 :   nsIDocShell* docShell = this->GetDocShell();
    5283             : 
    5284          26 :   if (timelines && timelines->HasConsumer(docShell)) {
    5285           0 :     timelines->AddMarkerForDocShell(docShell,
    5286           0 :       MakeUnique<DocLoadingTimelineMarker>("document::DOMContentLoaded"));
    5287             :   }
    5288             : 
    5289          26 :   if (mTiming) {
    5290          25 :     mTiming->NotifyDOMContentLoadedEnd(nsIDocument::GetDocumentURI());
    5291             :   }
    5292             : 
    5293             :   // If this document is a [i]frame, fire a DOMFrameContentLoaded
    5294             :   // event on all parent documents notifying that the HTML (excluding
    5295             :   // other external files such as images and stylesheets) in a frame
    5296             :   // has finished loading.
    5297             : 
    5298             :   // target_frame is the [i]frame element that will be used as the
    5299             :   // target for the event. It's the [i]frame whose content is done
    5300             :   // loading.
    5301          52 :   nsCOMPtr<EventTarget> target_frame;
    5302             : 
    5303          26 :   if (mParentDocument) {
    5304           1 :     target_frame = mParentDocument->FindContentForSubDocument(this);
    5305             :   }
    5306             : 
    5307          26 :   if (target_frame) {
    5308           2 :     nsCOMPtr<nsIDocument> parent = mParentDocument;
    5309           1 :     do {
    5310           2 :       nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(parent);
    5311             : 
    5312           2 :       nsCOMPtr<nsIDOMEvent> event;
    5313           1 :       if (domDoc) {
    5314           4 :         domDoc->CreateEvent(NS_LITERAL_STRING("Events"),
    5315           4 :                             getter_AddRefs(event));
    5316             : 
    5317             :       }
    5318             : 
    5319           1 :       if (event) {
    5320           4 :         event->InitEvent(NS_LITERAL_STRING("DOMFrameContentLoaded"), true,
    5321           3 :                          true);
    5322             : 
    5323           1 :         event->SetTarget(target_frame);
    5324           1 :         event->SetTrusted(true);
    5325             : 
    5326             :         // To dispatch this event we must manually call
    5327             :         // EventDispatcher::Dispatch() on the ancestor document since the
    5328             :         // target is not in the same document, so the event would never reach
    5329             :         // the ancestor document if we used the normal event
    5330             :         // dispatching code.
    5331             : 
    5332           1 :         WidgetEvent* innerEvent = event->WidgetEventPtr();
    5333           1 :         if (innerEvent) {
    5334           1 :           nsEventStatus status = nsEventStatus_eIgnore;
    5335             : 
    5336           1 :           nsIPresShell *shell = parent->GetShell();
    5337           1 :           if (shell) {
    5338           2 :             RefPtr<nsPresContext> context = shell->GetPresContext();
    5339             : 
    5340           1 :             if (context) {
    5341           1 :               EventDispatcher::Dispatch(parent, context, innerEvent, event,
    5342           1 :                                         &status);
    5343             :             }
    5344             :           }
    5345             :         }
    5346             :       }
    5347             : 
    5348           1 :       parent = parent->GetParentDocument();
    5349             :     } while (parent);
    5350             :   }
    5351             : 
    5352             :   // If the document has a manifest attribute, fire a MozApplicationManifest
    5353             :   // event.
    5354          26 :   Element* root = GetRootElement();
    5355          26 :   if (root && root->HasAttr(kNameSpaceID_None, nsGkAtoms::manifest)) {
    5356           0 :     nsContentUtils::DispatchChromeEvent(this, static_cast<nsIDocument*>(this),
    5357           0 :                                         NS_LITERAL_STRING("MozApplicationManifest"),
    5358           0 :                                         true, true);
    5359             :   }
    5360             : 
    5361          26 :   if (mMaybeServiceWorkerControlled) {
    5362             :     using mozilla::dom::workers::ServiceWorkerManager;
    5363           8 :     RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
    5364           4 :     if (swm) {
    5365           4 :       swm->MaybeCheckNavigationUpdate(this);
    5366             :     }
    5367             :   }
    5368             : 
    5369          26 :   UnblockOnload(true);
    5370          26 : }
    5371             : 
    5372             : void
    5373          25 : nsDocument::EndLoad()
    5374             : {
    5375             :   // Drop the ref to our parser, if any, but keep hold of the sink so that we
    5376             :   // can flush it from FlushPendingNotifications as needed.  We might have to
    5377             :   // do that to get a StartLayout() to happen.
    5378          25 :   if (mParser) {
    5379          25 :     mWeakSink = do_GetWeakReference(mParser->GetContentSink());
    5380          25 :     mParser = nullptr;
    5381             :   }
    5382             : 
    5383          25 :   NS_DOCUMENT_NOTIFY_OBSERVERS(EndLoad, (this));
    5384             : 
    5385          25 :   UnblockDOMContentLoaded();
    5386          25 : }
    5387             : 
    5388             : void
    5389          25 : nsDocument::UnblockDOMContentLoaded()
    5390             : {
    5391          25 :   MOZ_ASSERT(mBlockDOMContentLoaded);
    5392          25 :   if (--mBlockDOMContentLoaded != 0 || mDidFireDOMContentLoaded) {
    5393           0 :     return;
    5394             :   }
    5395          25 :   mDidFireDOMContentLoaded = true;
    5396             : 
    5397          25 :   MOZ_ASSERT(mReadyState == READYSTATE_INTERACTIVE);
    5398          25 :   if (!mSynchronousDOMContentLoaded) {
    5399          24 :     MOZ_RELEASE_ASSERT(NS_IsMainThread());
    5400             :     nsCOMPtr<nsIRunnable> ev =
    5401          48 :       NewRunnableMethod("nsDocument::DispatchContentLoadedEvents",
    5402             :                         this,
    5403          48 :                         &nsDocument::DispatchContentLoadedEvents);
    5404          24 :     Dispatch("nsDocument::DispatchContentLoadedEvents", TaskCategory::Other, ev.forget());
    5405             :   } else {
    5406           1 :     DispatchContentLoadedEvents();
    5407             :   }
    5408             : }
    5409             : 
    5410             : void
    5411          55 : nsDocument::ContentStateChanged(nsIContent* aContent, EventStates aStateMask)
    5412             : {
    5413          55 :   NS_PRECONDITION(!nsContentUtils::IsSafeToRunScript(),
    5414             :                   "Someone forgot a scriptblocker");
    5415          55 :   NS_DOCUMENT_NOTIFY_OBSERVERS(ContentStateChanged,
    5416             :                                (this, aContent, aStateMask));
    5417          55 : }
    5418             : 
    5419             : void
    5420           5 : nsDocument::DocumentStatesChanged(EventStates aStateMask)
    5421             : {
    5422             :   // Invalidate our cached state.
    5423           5 :   mGotDocumentState &= ~aStateMask;
    5424           5 :   mDocumentState &= ~aStateMask;
    5425             : 
    5426           5 :   NS_DOCUMENT_NOTIFY_OBSERVERS(DocumentStatesChanged, (this, aStateMask));
    5427           5 : }
    5428             : 
    5429             : void
    5430           0 : nsDocument::StyleRuleChanged(StyleSheet* aSheet,
    5431             :                              css::Rule* aStyleRule)
    5432             : {
    5433           0 :   NS_DOCUMENT_NOTIFY_OBSERVERS(StyleRuleChanged, (aSheet, aStyleRule));
    5434             : 
    5435           0 :   if (StyleSheetChangeEventsEnabled()) {
    5436           0 :     DO_STYLESHEET_NOTIFICATION(StyleRuleChangeEvent,
    5437             :                                "StyleRuleChanged",
    5438             :                                mRule,
    5439             :                                aStyleRule);
    5440             :   }
    5441           0 : }
    5442             : 
    5443             : void
    5444           0 : nsDocument::StyleRuleAdded(StyleSheet* aSheet,
    5445             :                            css::Rule* aStyleRule)
    5446             : {
    5447           0 :   NS_DOCUMENT_NOTIFY_OBSERVERS(StyleRuleAdded, (aSheet, aStyleRule));
    5448             : 
    5449           0 :   if (StyleSheetChangeEventsEnabled()) {
    5450           0 :     DO_STYLESHEET_NOTIFICATION(StyleRuleChangeEvent,
    5451             :                                "StyleRuleAdded",
    5452             :                                mRule,
    5453             :                                aStyleRule);
    5454             :   }
    5455           0 : }
    5456             : 
    5457             : void
    5458           0 : nsDocument::StyleRuleRemoved(StyleSheet* aSheet,
    5459             :                              css::Rule* aStyleRule)
    5460             : {
    5461           0 :   NS_DOCUMENT_NOTIFY_OBSERVERS(StyleRuleRemoved, (aSheet, aStyleRule));
    5462             : 
    5463           0 :   if (StyleSheetChangeEventsEnabled()) {
    5464           0 :     DO_STYLESHEET_NOTIFICATION(StyleRuleChangeEvent,
    5465             :                                "StyleRuleRemoved",
    5466             :                                mRule,
    5467             :                                aStyleRule);
    5468             :   }
    5469           0 : }
    5470             : 
    5471             : #undef DO_STYLESHEET_NOTIFICATION
    5472             : 
    5473             : already_AddRefed<AnonymousContent>
    5474           0 : nsIDocument::InsertAnonymousContent(Element& aElement, ErrorResult& aRv)
    5475             : {
    5476           0 :   nsIPresShell* shell = GetShell();
    5477           0 :   if (!shell || !shell->GetCanvasFrame()) {
    5478           0 :     aRv.Throw(NS_ERROR_UNEXPECTED);
    5479           0 :     return nullptr;
    5480             :   }
    5481             : 
    5482           0 :   nsAutoScriptBlocker scriptBlocker;
    5483           0 :   nsCOMPtr<Element> container = shell->GetCanvasFrame()
    5484           0 :                                      ->GetCustomContentContainer();
    5485           0 :   if (!container) {
    5486           0 :     aRv.Throw(NS_ERROR_UNEXPECTED);
    5487           0 :     return nullptr;
    5488             :   }
    5489             : 
    5490             :   // Clone the node to avoid returning a direct reference
    5491           0 :   nsCOMPtr<nsINode> clonedElement = aElement.CloneNode(true, aRv);
    5492           0 :   if (aRv.Failed()) {
    5493           0 :     return nullptr;
    5494             :   }
    5495             : 
    5496             :   // Insert the element into the container
    5497             :   nsresult rv;
    5498           0 :   rv = container->AppendChildTo(clonedElement->AsContent(), true);
    5499           0 :   if (NS_FAILED(rv)) {
    5500           0 :     return nullptr;
    5501             :   }
    5502             : 
    5503             :   RefPtr<AnonymousContent> anonymousContent =
    5504           0 :     new AnonymousContent(clonedElement->AsElement());
    5505           0 :   mAnonymousContents.AppendElement(anonymousContent);
    5506             : 
    5507           0 :   shell->GetCanvasFrame()->ShowCustomContentContainer();
    5508             : 
    5509           0 :   return anonymousContent.forget();
    5510             : }
    5511             : 
    5512             : void
    5513           0 : nsIDocument::RemoveAnonymousContent(AnonymousContent& aContent,
    5514             :                                     ErrorResult& aRv)
    5515             : {
    5516           0 :   nsIPresShell* shell = GetShell();
    5517           0 :   if (!shell || !shell->GetCanvasFrame()) {
    5518           0 :     aRv.Throw(NS_ERROR_UNEXPECTED);
    5519           0 :     return;
    5520             :   }
    5521             : 
    5522           0 :   nsAutoScriptBlocker scriptBlocker;
    5523           0 :   nsCOMPtr<Element> container = shell->GetCanvasFrame()
    5524           0 :                                      ->GetCustomContentContainer();
    5525           0 :   if (!container) {
    5526           0 :     aRv.Throw(NS_ERROR_UNEXPECTED);
    5527           0 :     return;
    5528             :   }
    5529             : 
    5530             :   // Iterate over mAnonymousContents to find and remove the given node.
    5531           0 :   for (size_t i = 0, len = mAnonymousContents.Length(); i < len; ++i) {
    5532           0 :     if (mAnonymousContents[i] == &aContent) {
    5533             :       // Get the node from the customContent
    5534           0 :       nsCOMPtr<Element> node = aContent.GetContentNode();
    5535             : 
    5536             :       // Remove the entry in mAnonymousContents
    5537           0 :       mAnonymousContents.RemoveElementAt(i);
    5538             : 
    5539             :       // Remove the node from its container
    5540           0 :       container->RemoveChild(*node, aRv);
    5541           0 :       if (aRv.Failed()) {
    5542           0 :         return;
    5543             :       }
    5544             : 
    5545           0 :       break;
    5546             :     }
    5547             :   }
    5548           0 :   if (mAnonymousContents.IsEmpty()) {
    5549           0 :     shell->GetCanvasFrame()->HideCustomContentContainer();
    5550             :   }
    5551             : }
    5552             : 
    5553             : Element*
    5554           0 : nsIDocument::GetAnonRootIfInAnonymousContentContainer(nsINode* aNode) const
    5555             : {
    5556           0 :   if (!aNode->IsInNativeAnonymousSubtree()) {
    5557           0 :     return nullptr;
    5558             :   }
    5559             : 
    5560           0 :   nsIPresShell* shell = GetShell();
    5561           0 :   if (!shell || !shell->GetCanvasFrame()) {
    5562           0 :     return nullptr;
    5563             :   }
    5564             : 
    5565           0 :   nsAutoScriptBlocker scriptBlocker;
    5566           0 :   nsCOMPtr<Element> customContainer = shell->GetCanvasFrame()
    5567           0 :                                            ->GetCustomContentContainer();
    5568           0 :   if (!customContainer) {
    5569           0 :     return nullptr;
    5570             :   }
    5571             : 
    5572             :   // An arbitrary number of elements can be inserted as children of the custom
    5573             :   // container frame.  We want the one that was added that contains aNode, so
    5574             :   // we need to keep track of the last child separately using |child| here.
    5575           0 :   nsINode* child = aNode;
    5576           0 :   nsINode* parent = aNode->GetParentNode();
    5577           0 :   while (parent && parent->IsInNativeAnonymousSubtree()) {
    5578           0 :     if (parent == customContainer) {
    5579           0 :       return child->IsElement() ? child->AsElement() : nullptr;
    5580             :     }
    5581           0 :     child = parent;
    5582           0 :     parent = child->GetParentNode();
    5583             :   }
    5584           0 :   return nullptr;
    5585             : }
    5586             : 
    5587             : //
    5588             : // nsIDOMDocument interface
    5589             : //
    5590             : DocumentType*
    5591           0 : nsIDocument::GetDoctype() const
    5592             : {
    5593           0 :   for (nsIContent* child = GetFirstChild();
    5594           0 :        child;
    5595           0 :        child = child->GetNextSibling()) {
    5596           0 :     if (child->NodeType() == nsIDOMNode::DOCUMENT_TYPE_NODE) {
    5597           0 :       return static_cast<DocumentType*>(child);
    5598             :     }
    5599             :   }
    5600           0 :   return nullptr;
    5601             : }
    5602             : 
    5603             : NS_IMETHODIMP
    5604           0 : nsDocument::GetDoctype(nsIDOMDocumentType** aDoctype)
    5605             : {
    5606           0 :   MOZ_ASSERT(aDoctype);
    5607           0 :   nsCOMPtr<nsIDOMDocumentType> doctype = nsIDocument::GetDoctype();
    5608           0 :   doctype.forget(aDoctype);
    5609           0 :   return NS_OK;
    5610             : }
    5611             : 
    5612             : NS_IMETHODIMP
    5613           0 : nsDocument::GetImplementation(nsIDOMDOMImplementation** aImplementation)
    5614             : {
    5615           0 :   ErrorResult rv;
    5616           0 :   *aImplementation = GetImplementation(rv);
    5617           0 :   if (rv.Failed()) {
    5618           0 :     MOZ_ASSERT(!*aImplementation);
    5619           0 :     return rv.StealNSResult();
    5620             :   }
    5621           0 :   NS_ADDREF(*aImplementation);
    5622           0 :   return NS_OK;
    5623             : }
    5624             : 
    5625             : DOMImplementation*
    5626           0 : nsDocument::GetImplementation(ErrorResult& rv)
    5627             : {
    5628           0 :   if (!mDOMImplementation) {
    5629           0 :     nsCOMPtr<nsIURI> uri;
    5630           0 :     NS_NewURI(getter_AddRefs(uri), "about:blank");
    5631           0 :     if (!uri) {
    5632           0 :       rv.Throw(NS_ERROR_OUT_OF_MEMORY);
    5633           0 :       return nullptr;
    5634             :     }
    5635           0 :     bool hasHadScriptObject = true;
    5636             :     nsIScriptGlobalObject* scriptObject =
    5637           0 :       GetScriptHandlingObject(hasHadScriptObject);
    5638           0 :     if (!scriptObject && hasHadScriptObject) {
    5639           0 :       rv.Throw(NS_ERROR_UNEXPECTED);
    5640           0 :       return nullptr;
    5641             :     }
    5642             :     mDOMImplementation = new DOMImplementation(this,
    5643           0 :       scriptObject ? scriptObject : GetScopeObject(), uri, uri);
    5644             :   }
    5645             : 
    5646           0 :   return mDOMImplementation;
    5647             : }
    5648             : 
    5649             : NS_IMETHODIMP
    5650           2 : nsDocument::GetDocumentElement(nsIDOMElement** aDocumentElement)
    5651             : {
    5652           2 :   NS_ENSURE_ARG_POINTER(aDocumentElement);
    5653             : 
    5654           2 :   Element* root = GetRootElement();
    5655           2 :   if (root) {
    5656           2 :     return CallQueryInterface(root, aDocumentElement);
    5657             :   }
    5658             : 
    5659           0 :   *aDocumentElement = nullptr;
    5660             : 
    5661           0 :   return NS_OK;
    5662             : }
    5663             : 
    5664             : NS_IMETHODIMP
    5665           0 : nsDocument::CreateElement(const nsAString& aTagName,
    5666             :                           nsIDOMElement** aReturn)
    5667             : {
    5668           0 :   *aReturn = nullptr;
    5669           0 :   ErrorResult rv;
    5670           0 :   ElementCreationOptionsOrString options;
    5671             : 
    5672           0 :   options.SetAsString();
    5673           0 :   nsCOMPtr<Element> element = CreateElement(aTagName, options, rv);
    5674           0 :   NS_ENSURE_FALSE(rv.Failed(), rv.StealNSResult());
    5675           0 :   return CallQueryInterface(element, aReturn);
    5676             : }
    5677             : 
    5678           0 : bool IsLowercaseASCII(const nsAString& aValue)
    5679             : {
    5680           0 :   int32_t len = aValue.Length();
    5681           0 :   for (int32_t i = 0; i < len; ++i) {
    5682           0 :     char16_t c = aValue[i];
    5683           0 :     if (!(0x0061 <= (c) && ((c) <= 0x007a))) {
    5684           0 :       return false;
    5685             :     }
    5686             :   }
    5687           0 :   return true;
    5688             : }
    5689             : 
    5690             : already_AddRefed<mozilla::dom::CustomElementRegistry>
    5691           0 : nsDocument::GetCustomElementRegistry()
    5692             : {
    5693           0 :   nsAutoString contentType;
    5694           0 :   GetContentType(contentType);
    5695           0 :   if (!IsHTMLDocument() &&
    5696           0 :       !contentType.EqualsLiteral("application/xhtml+xml")) {
    5697           0 :     return nullptr;
    5698             :   }
    5699             : 
    5700             :   nsCOMPtr<nsPIDOMWindowInner> window(
    5701             :     do_QueryInterface(mScriptGlobalObject ? mScriptGlobalObject
    5702           0 :                                           : GetScopeObject()));
    5703           0 :   if (!window) {
    5704           0 :     return nullptr;
    5705             :   }
    5706             : 
    5707           0 :   RefPtr<CustomElementRegistry> registry = window->CustomElements();
    5708           0 :   if (!registry) {
    5709           0 :     return nullptr;
    5710             :   }
    5711             : 
    5712           0 :   return registry.forget();
    5713             : }
    5714             : 
    5715             : // We only support pseudo-elements with two colons in this function.
    5716             : static CSSPseudoElementType
    5717           0 : GetPseudoElementType(const nsString& aString, ErrorResult& aRv)
    5718             : {
    5719           0 :   MOZ_ASSERT(!aString.IsEmpty(), "GetPseudoElementType aString should be non-null");
    5720           0 :   if (aString.Length() <= 2 || aString[0] != ':' || aString[1] != ':') {
    5721           0 :     aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
    5722           0 :     return CSSPseudoElementType::NotPseudo;
    5723             :   }
    5724           0 :   nsCOMPtr<nsIAtom> pseudo = NS_Atomize(Substring(aString, 1));
    5725           0 :   return nsCSSPseudoElements::GetPseudoType(pseudo,
    5726           0 :       nsCSSProps::EnabledState::eInUASheets);
    5727             : }
    5728             : 
    5729             : already_AddRefed<Element>
    5730          48 : nsDocument::CreateElement(const nsAString& aTagName,
    5731             :                           const ElementCreationOptionsOrString& aOptions,
    5732             :                           ErrorResult& rv)
    5733             : {
    5734          48 :   rv = nsContentUtils::CheckQName(aTagName, false);
    5735          48 :   if (rv.Failed()) {
    5736           0 :     return nullptr;
    5737             :   }
    5738             : 
    5739          48 :   bool needsLowercase = IsHTMLDocument() && !IsLowercaseASCII(aTagName);
    5740          96 :   nsAutoString lcTagName;
    5741          48 :   if (needsLowercase) {
    5742           0 :     nsContentUtils::ASCIIToLower(aTagName, lcTagName);
    5743             :   }
    5744             : 
    5745          48 :   const nsString* is = nullptr;
    5746          48 :   CSSPseudoElementType pseudoType = CSSPseudoElementType::NotPseudo;
    5747          48 :   if (aOptions.IsElementCreationOptions()) {
    5748             :     const ElementCreationOptions& options =
    5749          48 :       aOptions.GetAsElementCreationOptions();
    5750             : 
    5751          48 :     if (CustomElementRegistry::IsCustomElementEnabled() &&
    5752           0 :         options.mIs.WasPassed()) {
    5753           0 :       is = &options.mIs.Value();
    5754             :     }
    5755             : 
    5756             :     // Check 'pseudo' and throw an exception if it's not one allowed
    5757             :     // with CSS_PSEUDO_ELEMENT_IS_JS_CREATED_NAC.
    5758          48 :     if (options.mPseudo.WasPassed()) {
    5759           0 :       pseudoType = GetPseudoElementType(options.mPseudo.Value(), rv);
    5760           0 :       if (rv.Failed() ||
    5761           0 :           pseudoType == CSSPseudoElementType::NotPseudo ||
    5762           0 :           !nsCSSPseudoElements::PseudoElementIsJSCreatedNAC(pseudoType)) {
    5763           0 :         rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
    5764           0 :         return nullptr;
    5765             :       }
    5766             :     }
    5767             :   }
    5768             : 
    5769          96 :   RefPtr<Element> elem = CreateElem(
    5770         144 :     needsLowercase ? lcTagName : aTagName, nullptr, mDefaultElementType, is);
    5771             : 
    5772          48 :   if (pseudoType != CSSPseudoElementType::NotPseudo) {
    5773           0 :     elem->SetPseudoElementType(pseudoType);
    5774             :   }
    5775             : 
    5776          48 :   return elem.forget();
    5777             : }
    5778             : 
    5779             : NS_IMETHODIMP
    5780           0 : nsDocument::CreateElementNS(const nsAString& aNamespaceURI,
    5781             :                             const nsAString& aQualifiedName,
    5782             :                             nsIDOMElement** aReturn)
    5783             : {
    5784           0 :   *aReturn = nullptr;
    5785           0 :   ElementCreationOptionsOrString options;
    5786             : 
    5787           0 :   options.SetAsString();
    5788           0 :   ErrorResult rv;
    5789             :   nsCOMPtr<Element> element =
    5790           0 :     CreateElementNS(aNamespaceURI, aQualifiedName, options, rv);
    5791           0 :   NS_ENSURE_FALSE(rv.Failed(), rv.StealNSResult());
    5792           0 :   return CallQueryInterface(element, aReturn);
    5793             : }
    5794             : 
    5795             : already_AddRefed<Element>
    5796          33 : nsDocument::CreateElementNS(const nsAString& aNamespaceURI,
    5797             :                             const nsAString& aQualifiedName,
    5798             :                             const ElementCreationOptionsOrString& aOptions,
    5799             :                             ErrorResult& rv)
    5800             : {
    5801          66 :   RefPtr<mozilla::dom::NodeInfo> nodeInfo;
    5802          33 :   rv = nsContentUtils::GetNodeInfoFromQName(aNamespaceURI,
    5803             :                                             aQualifiedName,
    5804             :                                             mNodeInfoManager,
    5805             :                                             nsIDOMNode::ELEMENT_NODE,
    5806          66 :                                             getter_AddRefs(nodeInfo));
    5807          33 :   if (rv.Failed()) {
    5808           0 :     return nullptr;
    5809             :   }
    5810             : 
    5811          33 :   const nsString* is = nullptr;
    5812          33 :   if (CustomElementRegistry::IsCustomElementEnabled() &&
    5813           0 :       aOptions.IsElementCreationOptions()) {
    5814           0 :     const ElementCreationOptions& options = aOptions.GetAsElementCreationOptions();
    5815           0 :     if (options.mIs.WasPassed()) {
    5816           0 :       is = &options.mIs.Value();
    5817             :     }
    5818             :   }
    5819             : 
    5820          66 :   nsCOMPtr<Element> element;
    5821          66 :   rv = NS_NewElement(getter_AddRefs(element), nodeInfo.forget(),
    5822          33 :                      NOT_FROM_PARSER, is);
    5823          33 :   if (rv.Failed()) {
    5824           0 :     return nullptr;
    5825             :   }
    5826             : 
    5827          33 :   return element.forget();
    5828             : }
    5829             : 
    5830             : NS_IMETHODIMP
    5831           0 : nsDocument::CreateTextNode(const nsAString& aData, nsIDOMText** aReturn)
    5832             : {
    5833           0 :   *aReturn = nsIDocument::CreateTextNode(aData).take();
    5834           0 :   return NS_OK;
    5835             : }
    5836             : 
    5837             : already_AddRefed<nsTextNode>
    5838           1 : nsIDocument::CreateTextNode(const nsAString& aData) const
    5839             : {
    5840           2 :   RefPtr<nsTextNode> text = new nsTextNode(mNodeInfoManager);
    5841             :   // Don't notify; this node is still being created.
    5842           1 :   text->SetText(aData, false);
    5843           2 :   return text.forget();
    5844             : }
    5845             : 
    5846             : NS_IMETHODIMP
    5847           0 : nsDocument::CreateDocumentFragment(nsIDOMDocumentFragment** aReturn)
    5848             : {
    5849           0 :   *aReturn = nsIDocument::CreateDocumentFragment().take();
    5850           0 :   return NS_OK;
    5851             : }
    5852             : 
    5853             : already_AddRefed<DocumentFragment>
    5854           4 : nsIDocument::CreateDocumentFragment() const
    5855             : {
    5856           8 :   RefPtr<DocumentFragment> frag = new DocumentFragment(mNodeInfoManager);
    5857           8 :   return frag.forget();
    5858             : }
    5859             : 
    5860             : NS_IMETHODIMP
    5861           0 : nsDocument::CreateComment(const nsAString& aData, nsIDOMComment** aReturn)
    5862             : {
    5863           0 :   *aReturn = nsIDocument::CreateComment(aData).take();
    5864           0 :   return NS_OK;
    5865             : }
    5866             : 
    5867             : // Unfortunately, bareword "Comment" is ambiguous with some Mac system headers.
    5868             : already_AddRefed<dom::Comment>
    5869           0 : nsIDocument::CreateComment(const nsAString& aData) const
    5870             : {
    5871           0 :   RefPtr<dom::Comment> comment = new dom::Comment(mNodeInfoManager);
    5872             : 
    5873             :   // Don't notify; this node is still being created.
    5874           0 :   comment->SetText(aData, false);
    5875           0 :   return comment.forget();
    5876             : }
    5877             : 
    5878             : NS_IMETHODIMP
    5879           0 : nsDocument::CreateCDATASection(const nsAString& aData,
    5880             :                                nsIDOMCDATASection** aReturn)
    5881             : {
    5882           0 :   NS_ENSURE_ARG_POINTER(aReturn);
    5883           0 :   ErrorResult rv;
    5884           0 :   *aReturn = nsIDocument::CreateCDATASection(aData, rv).take();
    5885           0 :   return rv.StealNSResult();
    5886             : }
    5887             : 
    5888             : already_AddRefed<CDATASection>
    5889           0 : nsIDocument::CreateCDATASection(const nsAString& aData,
    5890             :                                 ErrorResult& rv)
    5891             : {
    5892           0 :   if (IsHTMLDocument()) {
    5893           0 :     rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
    5894           0 :     return nullptr;
    5895             :   }
    5896             : 
    5897           0 :   if (FindInReadable(NS_LITERAL_STRING("]]>"), aData)) {
    5898           0 :     rv.Throw(NS_ERROR_DOM_INVALID_CHARACTER_ERR);
    5899           0 :     return nullptr;
    5900             :   }
    5901             : 
    5902           0 :   RefPtr<CDATASection> cdata = new CDATASection(mNodeInfoManager);
    5903             : 
    5904             :   // Don't notify; this node is still being created.
    5905           0 :   cdata->SetText(aData, false);
    5906             : 
    5907           0 :   return cdata.forget();
    5908             : }
    5909             : 
    5910             : NS_IMETHODIMP
    5911           0 : nsDocument::CreateProcessingInstruction(const nsAString& aTarget,
    5912             :                                         const nsAString& aData,
    5913             :                                         nsIDOMProcessingInstruction** aReturn)
    5914             : {
    5915           0 :   ErrorResult rv;
    5916           0 :   *aReturn =
    5917           0 :     nsIDocument::CreateProcessingInstruction(aTarget, aData, rv).take();
    5918           0 :   return rv.StealNSResult();
    5919             : }
    5920             : 
    5921             : already_AddRefed<ProcessingInstruction>
    5922           0 : nsIDocument::CreateProcessingInstruction(const nsAString& aTarget,
    5923             :                                          const nsAString& aData,
    5924             :                                          ErrorResult& rv) const
    5925             : {
    5926           0 :   nsresult res = nsContentUtils::CheckQName(aTarget, false);
    5927           0 :   if (NS_FAILED(res)) {
    5928           0 :     rv.Throw(res);
    5929           0 :     return nullptr;
    5930             :   }
    5931             : 
    5932           0 :   if (FindInReadable(NS_LITERAL_STRING("?>"), aData)) {
    5933           0 :     rv.Throw(NS_ERROR_DOM_INVALID_CHARACTER_ERR);
    5934           0 :     return nullptr;
    5935             :   }
    5936             : 
    5937             :   RefPtr<ProcessingInstruction> pi =
    5938           0 :     NS_NewXMLProcessingInstruction(mNodeInfoManager, aTarget, aData);
    5939             : 
    5940           0 :   return pi.forget();
    5941             : }
    5942             : 
    5943             : NS_IMETHODIMP
    5944           0 : nsDocument::CreateAttribute(const nsAString& aName,
    5945             :                             nsIDOMAttr** aReturn)
    5946             : {
    5947           0 :   ErrorResult rv;
    5948           0 :   *aReturn = nsIDocument::CreateAttribute(aName, rv).take();
    5949           0 :   return rv.StealNSResult();
    5950             : }
    5951             : 
    5952             : already_AddRefed<Attr>
    5953           0 : nsIDocument::CreateAttribute(const nsAString& aName, ErrorResult& rv)
    5954             : {
    5955           0 :   WarnOnceAbout(eCreateAttribute);
    5956             : 
    5957           0 :   if (!mNodeInfoManager) {
    5958           0 :     rv.Throw(NS_ERROR_NOT_INITIALIZED);
    5959           0 :     return nullptr;
    5960             :   }
    5961             : 
    5962           0 :   nsresult res = nsContentUtils::CheckQName(aName, false);
    5963           0 :   if (NS_FAILED(res)) {
    5964           0 :     rv.Throw(res);
    5965           0 :     return nullptr;
    5966             :   }
    5967             : 
    5968           0 :   nsAutoString name;
    5969           0 :   if (IsHTMLDocument()) {
    5970           0 :     nsContentUtils::ASCIIToLower(aName, name);
    5971             :   } else {
    5972           0 :     name = aName;
    5973             :   }
    5974             : 
    5975           0 :   RefPtr<mozilla::dom::NodeInfo> nodeInfo;
    5976           0 :   res = mNodeInfoManager->GetNodeInfo(name, nullptr, kNameSpaceID_None,
    5977             :                                       nsIDOMNode::ATTRIBUTE_NODE,
    5978           0 :                                       getter_AddRefs(nodeInfo));
    5979           0 :   if (NS_FAILED(res)) {
    5980           0 :     rv.Throw(res);
    5981           0 :     return nullptr;
    5982             :   }
    5983             : 
    5984           0 :   RefPtr<Attr> attribute = new Attr(nullptr, nodeInfo.forget(),
    5985           0 :                                     EmptyString());
    5986           0 :   return attribute.forget();
    5987             : }
    5988             : 
    5989             : NS_IMETHODIMP
    5990           0 : nsDocument::CreateAttributeNS(const nsAString & aNamespaceURI,
    5991             :                               const nsAString & aQualifiedName,
    5992             :                               nsIDOMAttr **aResult)
    5993             : {
    5994           0 :   ErrorResult rv;
    5995           0 :   *aResult =
    5996           0 :     nsIDocument::CreateAttributeNS(aNamespaceURI, aQualifiedName, rv).take();
    5997           0 :   return rv.StealNSResult();
    5998             : }
    5999             : 
    6000             : already_AddRefed<Attr>
    6001           0 : nsIDocument::CreateAttributeNS(const nsAString& aNamespaceURI,
    6002             :                                const nsAString& aQualifiedName,
    6003             :                                ErrorResult& rv)
    6004             : {
    6005           0 :   WarnOnceAbout(eCreateAttributeNS);
    6006             : 
    6007           0 :   RefPtr<mozilla::dom::NodeInfo> nodeInfo;
    6008           0 :   rv = nsContentUtils::GetNodeInfoFromQName(aNamespaceURI,
    6009             :                                             aQualifiedName,
    6010             :                                             mNodeInfoManager,
    6011             :                                             nsIDOMNode::ATTRIBUTE_NODE,
    6012           0 :                                             getter_AddRefs(nodeInfo));
    6013           0 :   if (rv.Failed()) {
    6014           0 :     return nullptr;
    6015             :   }
    6016             : 
    6017           0 :   RefPtr<Attr> attribute = new Attr(nullptr, nodeInfo.forget(),
    6018           0 :                                     EmptyString());
    6019           0 :   return attribute.forget();
    6020             : }
    6021             : 
    6022             : bool
    6023           0 : nsDocument::CustomElementConstructor(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
    6024             : {
    6025           0 :   JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
    6026             : 
    6027             :   JS::Rooted<JSObject*> global(aCx,
    6028           0 :     JS_GetGlobalForObject(aCx, &args.callee()));
    6029           0 :   RefPtr<nsGlobalWindow> window;
    6030           0 :   UNWRAP_OBJECT(Window, global, window);
    6031           0 :   MOZ_ASSERT(window, "Should have a non-null window");
    6032             : 
    6033           0 :   nsDocument* document = static_cast<nsDocument*>(window->GetDoc());
    6034             : 
    6035             :   // Function name is the type of the custom element.
    6036             :   JSString* jsFunName =
    6037           0 :     JS_GetFunctionId(JS_ValueToFunction(aCx, args.calleev()));
    6038           0 :   nsAutoJSString elemName;
    6039           0 :   if (!elemName.init(aCx, jsFunName)) {
    6040           0 :     return true;
    6041             :   }
    6042             : 
    6043           0 :   RefPtr<mozilla::dom::CustomElementRegistry> registry = window->CustomElements();
    6044           0 :   if (!registry) {
    6045           0 :     return true;
    6046             :   }
    6047             : 
    6048           0 :   nsCOMPtr<nsIAtom> typeAtom(NS_Atomize(elemName));
    6049           0 :   CustomElementDefinition* definition = registry->mCustomDefinitions.Get(typeAtom);
    6050           0 :   if (!definition) {
    6051           0 :     return true;
    6052             :   }
    6053             : 
    6054           0 :   nsDependentAtomString localName(definition->mLocalName);
    6055             : 
    6056             :   nsCOMPtr<Element> element =
    6057           0 :     document->CreateElem(localName, nullptr, kNameSpaceID_XHTML);
    6058           0 :   NS_ENSURE_TRUE(element, true);
    6059             : 
    6060           0 :   if (definition->mLocalName != typeAtom) {
    6061             :     // This element is a custom element by extension, thus we need to
    6062             :     // do some special setup. For non-extended custom elements, this happens
    6063             :     // when the element is created.
    6064           0 :     nsContentUtils::SetupCustomElement(element, &elemName);
    6065             :   }
    6066             : 
    6067           0 :   nsresult rv = nsContentUtils::WrapNative(aCx, element, element, args.rval());
    6068           0 :   NS_ENSURE_SUCCESS(rv, true);
    6069             : 
    6070           0 :   return true;
    6071             : }
    6072             : 
    6073             : bool
    6074           4 : nsDocument::IsWebComponentsEnabled(JSContext* aCx, JSObject* aObject)
    6075             : {
    6076           4 :   if (!nsContentUtils::IsWebComponentsEnabled()) {
    6077           4 :     return false;
    6078             :   }
    6079             : 
    6080           0 :   JS::Rooted<JSObject*> obj(aCx, aObject);
    6081             : 
    6082           0 :   JSAutoCompartment ac(aCx, obj);
    6083           0 :   JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForObject(aCx, obj));
    6084             :   nsCOMPtr<nsPIDOMWindowInner> window =
    6085           0 :     do_QueryInterface(nsJSUtils::GetStaticScriptGlobal(global));
    6086             : 
    6087           0 :   nsIDocument* doc = window ? window->GetExtantDoc() : nullptr;
    6088           0 :   if (doc && doc->IsStyledByServo()) {
    6089           0 :     NS_WARNING("stylo: Web Components not supported yet");
    6090           0 :     return false;
    6091             :   }
    6092             : 
    6093           0 :   return true;
    6094             : }
    6095             : 
    6096             : bool
    6097           0 : nsDocument::IsWebComponentsEnabled(dom::NodeInfo* aNodeInfo)
    6098             : {
    6099           0 :   if (!nsContentUtils::IsWebComponentsEnabled()) {
    6100           0 :     return false;
    6101             :   }
    6102             : 
    6103           0 :   nsIDocument* doc = aNodeInfo->GetDocument();
    6104           0 :   if (doc->IsStyledByServo()) {
    6105           0 :     NS_WARNING("stylo: Web Components not supported yet");
    6106           0 :     return false;
    6107             :   }
    6108             : 
    6109           0 :   return true;
    6110             : }
    6111             : 
    6112             : void
    6113           0 : nsDocument::ScheduleSVGForPresAttrEvaluation(nsSVGElement* aSVG)
    6114             : {
    6115           0 :   mLazySVGPresElements.PutEntry(aSVG);
    6116           0 : }
    6117             : 
    6118             : void
    6119           0 : nsDocument::UnscheduleSVGForPresAttrEvaluation(nsSVGElement* aSVG)
    6120             : {
    6121           0 :   mLazySVGPresElements.RemoveEntry(aSVG);
    6122           0 : }
    6123             : 
    6124             : void
    6125           0 : nsDocument::ResolveScheduledSVGPresAttrs()
    6126             : {
    6127           0 :   for (auto iter = mLazySVGPresElements.Iter(); !iter.Done(); iter.Next()) {
    6128           0 :     nsSVGElement* svg = iter.Get()->GetKey();
    6129           0 :     svg->UpdateContentDeclarationBlock(StyleBackendType::Servo);
    6130             :   }
    6131           0 :   mLazySVGPresElements.Clear();
    6132           0 : }
    6133             : 
    6134             : void
    6135           0 : nsDocument::RegisterElement(JSContext* aCx, const nsAString& aType,
    6136             :                             const ElementRegistrationOptions& aOptions,
    6137             :                             JS::MutableHandle<JSObject*> aRetval,
    6138             :                             ErrorResult& rv)
    6139             : {
    6140           0 :   RefPtr<CustomElementRegistry> registry(GetCustomElementRegistry());
    6141           0 :   if (!registry) {
    6142           0 :     rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
    6143           0 :     return;
    6144             :   }
    6145             : 
    6146           0 :   AutoCEReaction ceReaction(this->GetDocGroup()->CustomElementReactionsStack());
    6147             :   // Unconditionally convert TYPE to lowercase.
    6148           0 :   nsAutoString lcType;
    6149           0 :   nsContentUtils::ASCIIToLower(aType, lcType);
    6150             : 
    6151           0 :   nsIGlobalObject* sgo = GetScopeObject();
    6152           0 :   if (!sgo) {
    6153           0 :     rv.Throw(NS_ERROR_UNEXPECTED);
    6154           0 :     return;
    6155             :   }
    6156             : 
    6157           0 :   JS::Rooted<JSObject*> global(aCx, sgo->GetGlobalJSObject());
    6158           0 :   JS::Rooted<JSObject*> protoObject(aCx);
    6159             : 
    6160           0 :   if (!aOptions.mPrototype) {
    6161           0 :     JS::Rooted<JSObject*> htmlProto(aCx);
    6162           0 :     htmlProto = HTMLElementBinding::GetProtoObjectHandle(aCx);
    6163           0 :     if (!htmlProto) {
    6164           0 :       rv.Throw(NS_ERROR_OUT_OF_MEMORY);
    6165           0 :       return;
    6166             :     }
    6167             : 
    6168           0 :     protoObject = JS_NewObjectWithGivenProto(aCx, nullptr, htmlProto);
    6169           0 :     if (!protoObject) {
    6170           0 :       rv.Throw(NS_ERROR_UNEXPECTED);
    6171           0 :       return;
    6172             :     }
    6173             :   } else {
    6174           0 :     protoObject = aOptions.mPrototype;
    6175             : 
    6176             :     // Get the unwrapped prototype to do some checks.
    6177           0 :     JS::Rooted<JSObject*> protoObjectUnwrapped(aCx, js::CheckedUnwrap(protoObject));
    6178           0 :     if (!protoObjectUnwrapped) {
    6179             :       // If the caller's compartment does not have permission to access the
    6180             :       // unwrapped prototype then throw.
    6181           0 :       rv.Throw(NS_ERROR_DOM_SECURITY_ERR);
    6182           0 :       return;
    6183             :     }
    6184             : 
    6185             :     // If PROTOTYPE is already an interface prototype object for any interface
    6186             :     // object or PROTOTYPE has a non-configurable property named constructor,
    6187             :     // throw a NotSupportedError and stop.
    6188           0 :     const js::Class* clasp = js::GetObjectClass(protoObjectUnwrapped);
    6189           0 :     if (IsDOMIfaceAndProtoClass(clasp)) {
    6190           0 :       rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
    6191           0 :       return;
    6192             :     }
    6193             : 
    6194           0 :     JS::Rooted<JS::PropertyDescriptor> descRoot(aCx);
    6195           0 :     JS::MutableHandle<JS::PropertyDescriptor> desc(&descRoot);
    6196             :     // This check may go through a wrapper, but as we checked above
    6197             :     // it should be transparent or an xray. This should be fine for now,
    6198             :     // until the spec is sorted out.
    6199           0 :     if (!JS_GetPropertyDescriptor(aCx, protoObject, "constructor", desc)) {
    6200           0 :       rv.Throw(NS_ERROR_UNEXPECTED);
    6201           0 :       return;
    6202             :     }
    6203             : 
    6204           0 :     if (!desc.configurable()) {
    6205           0 :       rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
    6206           0 :       return;
    6207             :     }
    6208             :   }
    6209             : 
    6210           0 :   JS::Rooted<JSFunction*> constructor(aCx);
    6211             :   {
    6212             :     // Go into the document's global compartment when creating the constructor
    6213             :     // function because we want to get the correct document (where the
    6214             :     // definition is registered) when it is called.
    6215           0 :     JSAutoCompartment ac(aCx, global);
    6216             : 
    6217             :     // Create constructor to return. Store the name of the custom element as the
    6218             :     // name of the function.
    6219           0 :     constructor = JS_NewFunction(aCx, nsDocument::CustomElementConstructor, 0,
    6220             :                                  JSFUN_CONSTRUCTOR,
    6221           0 :                                  NS_ConvertUTF16toUTF8(lcType).get());
    6222           0 :     if (!constructor) {
    6223           0 :       rv.Throw(NS_ERROR_OUT_OF_MEMORY);
    6224           0 :       return;
    6225             :     }
    6226             :   }
    6227             : 
    6228           0 :   JS::Rooted<JSObject*> wrappedConstructor(aCx);
    6229           0 :   wrappedConstructor = JS_GetFunctionObject(constructor);
    6230           0 :   if (!JS_WrapObject(aCx, &wrappedConstructor)) {
    6231           0 :     rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
    6232           0 :     return;
    6233             :   }
    6234             : 
    6235           0 :   if (!JS_LinkConstructorAndPrototype(aCx, wrappedConstructor, protoObject)) {
    6236           0 :     rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
    6237           0 :     return;
    6238             :   }
    6239             : 
    6240           0 :   ElementDefinitionOptions options;
    6241           0 :   if (!aOptions.mExtends.IsVoid()) {
    6242             :     // Only convert NAME to lowercase in HTML documents.
    6243           0 :     nsAutoString lcName;
    6244           0 :     IsHTMLDocument() ? nsContentUtils::ASCIIToLower(aOptions.mExtends, lcName)
    6245           0 :                      : lcName.Assign(aOptions.mExtends);
    6246             : 
    6247           0 :     options.mExtends.Construct(lcName);
    6248             :   }
    6249             : 
    6250             :   RefPtr<Function> functionConstructor =
    6251           0 :     new Function(aCx, wrappedConstructor, sgo);
    6252             : 
    6253           0 :   registry->Define(lcType, *functionConstructor, options, rv);
    6254             : 
    6255           0 :   aRetval.set(wrappedConstructor);
    6256             : }
    6257             : 
    6258             : NS_IMETHODIMP
    6259           0 : nsDocument::GetElementsByTagName(const nsAString& aTagname,
    6260             :                                  nsIDOMNodeList** aReturn)
    6261             : {
    6262           0 :   RefPtr<nsContentList> list = GetElementsByTagName(aTagname);
    6263           0 :   NS_ENSURE_TRUE(list, NS_ERROR_OUT_OF_MEMORY);
    6264             : 
    6265             :   // transfer ref to aReturn
    6266           0 :   list.forget(aReturn);
    6267           0 :   return NS_OK;
    6268             : }
    6269             : 
    6270             : long
    6271           0 : nsDocument::BlockedTrackingNodeCount() const
    6272             : {
    6273           0 :   return mBlockedTrackingNodes.Length();
    6274             : }
    6275             : 
    6276             : already_AddRefed<nsSimpleContentList>
    6277           0 : nsDocument::BlockedTrackingNodes() const
    6278             : {
    6279           0 :   RefPtr<nsSimpleContentList> list = new nsSimpleContentList(nullptr);
    6280             : 
    6281           0 :   nsTArray<nsWeakPtr> blockedTrackingNodes;
    6282           0 :   blockedTrackingNodes = mBlockedTrackingNodes;
    6283             : 
    6284           0 :   for (unsigned long i = 0; i < blockedTrackingNodes.Length(); i++) {
    6285           0 :     nsWeakPtr weakNode = blockedTrackingNodes[i];
    6286           0 :     nsCOMPtr<nsIContent> node = do_QueryReferent(weakNode);
    6287             :     // Consider only nodes to which we have managed to get strong references.
    6288             :     // Coping with nullptrs since it's expected for nodes to disappear when
    6289             :     // nobody else is referring to them.
    6290           0 :     if (node) {
    6291           0 :       list->AppendElement(node);
    6292             :     }
    6293             :   }
    6294             : 
    6295           0 :   return list.forget();
    6296             : }
    6297             : 
    6298             : already_AddRefed<nsContentList>
    6299           0 : nsIDocument::GetElementsByTagNameNS(const nsAString& aNamespaceURI,
    6300             :                                     const nsAString& aLocalName,
    6301             :                                     ErrorResult& aResult)
    6302             : {
    6303           0 :   int32_t nameSpaceId = kNameSpaceID_Wildcard;
    6304             : 
    6305           0 :   if (!aNamespaceURI.EqualsLiteral("*")) {
    6306           0 :     aResult =
    6307             :       nsContentUtils::NameSpaceManager()->RegisterNameSpace(aNamespaceURI,
    6308           0 :                                                             nameSpaceId);
    6309           0 :     if (aResult.Failed()) {
    6310           0 :       return nullptr;
    6311             :     }
    6312             :   }
    6313             : 
    6314           0 :   NS_ASSERTION(nameSpaceId != kNameSpaceID_Unknown, "Unexpected namespace ID!");
    6315             : 
    6316           0 :   return NS_GetContentList(this, nameSpaceId, aLocalName);
    6317             : }
    6318             : 
    6319             : NS_IMETHODIMP
    6320           0 : nsDocument::GetElementsByTagNameNS(const nsAString& aNamespaceURI,
    6321             :                                    const nsAString& aLocalName,
    6322             :                                    nsIDOMNodeList** aReturn)
    6323             : {
    6324           0 :   ErrorResult rv;
    6325             :   RefPtr<nsContentList> list =
    6326           0 :     nsIDocument::GetElementsByTagNameNS(aNamespaceURI, aLocalName, rv);
    6327           0 :   if (rv.Failed()) {
    6328           0 :     return rv.StealNSResult();
    6329             :   }
    6330             : 
    6331             :   // transfer ref to aReturn
    6332           0 :   list.forget(aReturn);
    6333           0 :   return NS_OK;
    6334             : }
    6335             : 
    6336             : NS_IMETHODIMP
    6337           0 : nsDocument::GetStyleSheets(nsIDOMStyleSheetList** aStyleSheets)
    6338             : {
    6339           0 :   NS_ADDREF(*aStyleSheets = StyleSheets());
    6340           0 :   return NS_OK;
    6341             : }
    6342             : 
    6343             : StyleSheetList*
    6344           2 : nsDocument::StyleSheets()
    6345             : {
    6346           2 :   if (!mDOMStyleSheets) {
    6347           2 :     mDOMStyleSheets = new nsDOMStyleSheetList(this);
    6348             :   }
    6349           2 :   return mDOMStyleSheets;
    6350             : }
    6351             : 
    6352             : NS_IMETHODIMP
    6353           0 : nsDocument::GetMozSelectedStyleSheetSet(nsAString& aSheetSet)
    6354             : {
    6355           0 :   nsIDocument::GetSelectedStyleSheetSet(aSheetSet);
    6356           0 :   return NS_OK;
    6357             : }
    6358             : 
    6359             : void
    6360           1 : nsIDocument::GetSelectedStyleSheetSet(nsAString& aSheetSet)
    6361             : {
    6362           1 :   aSheetSet.Truncate();
    6363             : 
    6364             :   // Look through our sheets, find the selected set title
    6365           1 :   int32_t count = GetNumberOfStyleSheets();
    6366           2 :   nsAutoString title;
    6367           1 :   for (int32_t index = 0; index < count; index++) {
    6368           0 :     StyleSheet* sheet = GetStyleSheetAt(index);
    6369           0 :     NS_ASSERTION(sheet, "Null sheet in sheet list!");
    6370             : 
    6371           0 :     if (sheet->Disabled()) {
    6372             :       // Disabled sheets don't affect the currently selected set
    6373           0 :       continue;
    6374             :     }
    6375             : 
    6376           0 :     sheet->GetTitle(title);
    6377             : 
    6378           0 :     if (aSheetSet.IsEmpty()) {
    6379           0 :       aSheetSet = title;
    6380           0 :     } else if (!title.IsEmpty() && !aSheetSet.Equals(title)) {
    6381             :       // Sheets from multiple sets enabled; return null string, per spec.
    6382           0 :       SetDOMStringToNull(aSheetSet);
    6383           0 :       return;
    6384             :     }
    6385             :   }
    6386             : }
    6387             : 
    6388             : NS_IMETHODIMP
    6389           0 : nsDocument::SetMozSelectedStyleSheetSet(const nsAString& aSheetSet)
    6390             : {
    6391           0 :   SetSelectedStyleSheetSet(aSheetSet);
    6392           0 :   return NS_OK;
    6393             : }
    6394             : 
    6395             : void
    6396           0 : nsDocument::SetSelectedStyleSheetSet(const nsAString& aSheetSet)
    6397             : {
    6398           0 :   if (DOMStringIsNull(aSheetSet)) {
    6399           0 :     return;
    6400             :   }
    6401             : 
    6402             :   // Must update mLastStyleSheetSet before doing anything else with stylesheets
    6403             :   // or CSSLoaders.
    6404           0 :   mLastStyleSheetSet = aSheetSet;
    6405           0 :   EnableStyleSheetsForSetInternal(aSheetSet, true);
    6406             : }
    6407             : 
    6408             : NS_IMETHODIMP
    6409           0 : nsDocument::GetLastStyleSheetSet(nsAString& aSheetSet)
    6410             : {
    6411           0 :   nsString sheetSet;
    6412           0 :   GetLastStyleSheetSet(sheetSet);
    6413           0 :   aSheetSet = sheetSet;
    6414           0 :   return NS_OK;
    6415             : }
    6416             : 
    6417             : void
    6418           1 : nsDocument::GetLastStyleSheetSet(nsString& aSheetSet)
    6419             : {
    6420           1 :   aSheetSet = mLastStyleSheetSet;
    6421           1 : }
    6422             : 
    6423             : NS_IMETHODIMP
    6424          55 : nsDocument::GetPreferredStyleSheetSet(nsAString& aSheetSet)
    6425             : {
    6426          55 :   nsIDocument::GetPreferredStyleSheetSet(aSheetSet);
    6427          55 :   return NS_OK;
    6428             : }
    6429             : 
    6430             : void
    6431          57 : nsIDocument::GetPreferredStyleSheetSet(nsAString& aSheetSet)
    6432             : {
    6433          57 :   GetHeaderData(nsGkAtoms::headerDefaultStyle, aSheetSet);
    6434          57 : }
    6435             : 
    6436             : NS_IMETHODIMP
    6437           0 : nsDocument::GetStyleSheetSets(nsISupports** aList)
    6438             : {
    6439           0 :   NS_ADDREF(*aList = StyleSheetSets());
    6440           0 :   return NS_OK;
    6441             : }
    6442             : 
    6443             : DOMStringList*
    6444           0 : nsDocument::StyleSheetSets()
    6445             : {
    6446           0 :   if (!mStyleSheetSetList) {
    6447           0 :     mStyleSheetSetList = new nsDOMStyleSheetSetList(this);
    6448             :   }
    6449           0 :   return mStyleSheetSetList;
    6450             : }
    6451             : 
    6452             : NS_IMETHODIMP
    6453           0 : nsDocument::MozEnableStyleSheetsForSet(const nsAString& aSheetSet)
    6454             : {
    6455           0 :   EnableStyleSheetsForSet(aSheetSet);
    6456           0 :   return NS_OK;
    6457             : }
    6458             : 
    6459             : void
    6460           0 : nsDocument::EnableStyleSheetsForSet(const nsAString& aSheetSet)
    6461             : {
    6462             :   // Per spec, passing in null is a no-op.
    6463           0 :   if (!DOMStringIsNull(aSheetSet)) {
    6464             :     // Note: must make sure to not change the CSSLoader's preferred sheet --
    6465             :     // that value should be equal to either our lastStyleSheetSet (if that's
    6466             :     // non-null) or to our preferredStyleSheetSet.  And this method doesn't
    6467             :     // change either of those.
    6468           0 :     EnableStyleSheetsForSetInternal(aSheetSet, false);
    6469             :   }
    6470           0 : }
    6471             : 
    6472             : void
    6473           0 : nsDocument::EnableStyleSheetsForSetInternal(const nsAString& aSheetSet,
    6474             :                                             bool aUpdateCSSLoader)
    6475             : {
    6476           0 :   BeginUpdate(UPDATE_STYLE);
    6477           0 :   int32_t count = GetNumberOfStyleSheets();
    6478           0 :   nsAutoString title;
    6479           0 :   for (int32_t index = 0; index < count; index++) {
    6480           0 :     StyleSheet* sheet = GetStyleSheetAt(index);
    6481           0 :     NS_ASSERTION(sheet, "Null sheet in sheet list!");
    6482             : 
    6483           0 :     sheet->GetTitle(title);
    6484           0 :     if (!title.IsEmpty()) {
    6485           0 :       sheet->SetEnabled(title.Equals(aSheetSet));
    6486             :     }
    6487             :   }
    6488           0 :   if (aUpdateCSSLoader) {
    6489           0 :     CSSLoader()->SetPreferredSheet(aSheetSet);
    6490             :   }
    6491           0 :   EndUpdate(UPDATE_STYLE);
    6492           0 : }
    6493             : 
    6494             : NS_IMETHODIMP
    6495           0 : nsDocument::GetCharacterSet(nsAString& aCharacterSet)
    6496             : {
    6497           0 :   nsIDocument::GetCharacterSet(aCharacterSet);
    6498           0 :   return NS_OK;
    6499             : }
    6500             : 
    6501             : void
    6502           5 : nsIDocument::GetCharacterSet(nsAString& aCharacterSet) const
    6503             : {
    6504          10 :   nsAutoCString charset;
    6505           5 :   GetDocumentCharacterSet()->Name(charset);
    6506           5 :   CopyASCIItoUTF16(charset, aCharacterSet);
    6507           5 : }
    6508             : 
    6509             : NS_IMETHODIMP
    6510           0 : nsDocument::ImportNode(nsIDOMNode* aImportedNode,
    6511             :                        bool aDeep,
    6512             :                        uint8_t aArgc,
    6513             :                        nsIDOMNode** aResult)
    6514             : {
    6515           0 :   if (aArgc == 0) {
    6516           0 :     aDeep = true;
    6517             :   }
    6518             : 
    6519           0 :   *aResult = nullptr;
    6520             : 
    6521           0 :   nsCOMPtr<nsINode> imported = do_QueryInterface(aImportedNode);
    6522           0 :   NS_ENSURE_TRUE(imported, NS_ERROR_UNEXPECTED);
    6523             : 
    6524           0 :   ErrorResult rv;
    6525           0 :   nsCOMPtr<nsINode> result = nsIDocument::ImportNode(*imported, aDeep, rv);
    6526           0 :   if (rv.Failed()) {
    6527           0 :     return rv.StealNSResult();
    6528             :   }
    6529             : 
    6530           0 :   NS_ADDREF(*aResult = result->AsDOMNode());
    6531           0 :   return NS_OK;
    6532             : }
    6533             : 
    6534             : already_AddRefed<nsINode>
    6535           0 : nsIDocument::ImportNode(nsINode& aNode, bool aDeep, ErrorResult& rv) const
    6536             : {
    6537           0 :   nsINode* imported = &aNode;
    6538             : 
    6539           0 :   switch (imported->NodeType()) {
    6540             :     case nsIDOMNode::DOCUMENT_NODE:
    6541             :     {
    6542           0 :       break;
    6543             :     }
    6544             :     case nsIDOMNode::DOCUMENT_FRAGMENT_NODE:
    6545             :     {
    6546           0 :       if (ShadowRoot::FromNode(imported)) {
    6547           0 :         break;
    6548             :       }
    6549             :       MOZ_FALLTHROUGH;
    6550             :     }
    6551             :     case nsIDOMNode::ATTRIBUTE_NODE:
    6552             :     case nsIDOMNode::ELEMENT_NODE:
    6553             :     case nsIDOMNode::PROCESSING_INSTRUCTION_NODE:
    6554             :     case nsIDOMNode::TEXT_NODE:
    6555             :     case nsIDOMNode::CDATA_SECTION_NODE:
    6556             :     case nsIDOMNode::COMMENT_NODE:
    6557             :     case nsIDOMNode::DOCUMENT_TYPE_NODE:
    6558             :     {
    6559           0 :       nsCOMPtr<nsINode> newNode;
    6560           0 :       rv = nsNodeUtils::Clone(imported, aDeep, mNodeInfoManager, nullptr,
    6561           0 :                               getter_AddRefs(newNode));
    6562           0 :       if (rv.Failed()) {
    6563           0 :         return nullptr;
    6564             :       }
    6565           0 :       return newNode.forget();
    6566             :     }
    6567             :     default:
    6568             :     {
    6569           0 :       NS_WARNING("Don't know how to clone this nodetype for importNode.");
    6570             :     }
    6571             :   }
    6572             : 
    6573           0 :   rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
    6574           0 :   return nullptr;
    6575             : }
    6576             : 
    6577             : NS_IMETHODIMP
    6578           0 : nsDocument::LoadBindingDocument(const nsAString& aURI)
    6579             : {
    6580           0 :   ErrorResult rv;
    6581           0 :   nsIDocument::LoadBindingDocument(aURI,
    6582           0 :                                    nsContentUtils::GetCurrentJSContext()
    6583           0 :                                      ? Some(nsContentUtils::SubjectPrincipal())
    6584           0 :                                      : Nothing(),
    6585           0 :                                    rv);
    6586           0 :   return rv.StealNSResult();
    6587             : }
    6588             : 
    6589             : void
    6590           0 : nsIDocument::LoadBindingDocument(const nsAString& aURI,
    6591             :                                  nsIPrincipal& aSubjectPrincipal,
    6592             :                                  ErrorResult& rv)
    6593             : {
    6594           0 :   LoadBindingDocument(aURI, Some(&aSubjectPrincipal), rv);
    6595           0 : }
    6596             : 
    6597             : void
    6598           0 : nsIDocument::LoadBindingDocument(const nsAString& aURI,
    6599             :                                  const Maybe<nsIPrincipal*>& aSubjectPrincipal,
    6600             :                                  ErrorResult& rv)
    6601             : {
    6602           0 :   nsCOMPtr<nsIURI> uri;
    6603           0 :   rv = NS_NewURI(getter_AddRefs(uri), aURI, mCharacterSet, GetDocBaseURI());
    6604           0 :   if (rv.Failed()) {
    6605           0 :     return;
    6606             :   }
    6607             : 
    6608             :   // Note - This computation of subjectPrincipal isn't necessarily sensical.
    6609             :   // It's just designed to preserve the old semantics during a mass-conversion
    6610             :   // patch.
    6611             :   nsCOMPtr<nsIPrincipal> subjectPrincipal =
    6612           0 :     aSubjectPrincipal.isSome() ? aSubjectPrincipal.value() : NodePrincipal();
    6613           0 :   BindingManager()->LoadBindingDocument(this, uri, subjectPrincipal);
    6614             : }
    6615             : 
    6616             : NS_IMETHODIMP
    6617           0 : nsDocument::GetBindingParent(nsIDOMNode* aNode, nsIDOMElement** aResult)
    6618             : {
    6619           0 :   nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
    6620           0 :   NS_ENSURE_ARG_POINTER(node);
    6621             : 
    6622           0 :   Element* bindingParent = nsIDocument::GetBindingParent(*node);
    6623           0 :   nsCOMPtr<nsIDOMElement> retval = do_QueryInterface(bindingParent);
    6624           0 :   retval.forget(aResult);
    6625           0 :   return NS_OK;
    6626             : }
    6627             : 
    6628             : Element*
    6629           2 : nsIDocument::GetBindingParent(nsINode& aNode)
    6630             : {
    6631           4 :   nsCOMPtr<nsIContent> content(do_QueryInterface(&aNode));
    6632           2 :   if (!content)
    6633           0 :     return nullptr;
    6634             : 
    6635           2 :   nsIContent* bindingParent = content->GetBindingParent();
    6636           2 :   return bindingParent ? bindingParent->AsElement() : nullptr;
    6637             : }
    6638             : 
    6639             : static Element*
    6640         149 : GetElementByAttribute(nsIContent* aContent, nsIAtom* aAttrName,
    6641             :                       const nsAString& aAttrValue, bool aUniversalMatch)
    6642             : {
    6643         149 :   if (aUniversalMatch ? aContent->HasAttr(kNameSpaceID_None, aAttrName) :
    6644             :                         aContent->AttrValueIs(kNameSpaceID_None, aAttrName,
    6645             :                                               aAttrValue, eCaseMatters)) {
    6646          19 :     return aContent->AsElement();
    6647             :   }
    6648             : 
    6649         205 :   for (nsIContent* child = aContent->GetFirstChild();
    6650         205 :        child;
    6651          75 :        child = child->GetNextSibling()) {
    6652             : 
    6653             :     Element* matchedElement =
    6654          97 :       GetElementByAttribute(child, aAttrName, aAttrValue, aUniversalMatch);
    6655          97 :     if (matchedElement)
    6656          22 :       return matchedElement;
    6657             :   }
    6658             : 
    6659         108 :   return nullptr;
    6660             : }
    6661             : 
    6662             : Element*
    6663          19 : nsDocument::GetAnonymousElementByAttribute(nsIContent* aElement,
    6664             :                                            nsIAtom* aAttrName,
    6665             :                                            const nsAString& aAttrValue) const
    6666             : {
    6667          19 :   nsINodeList* nodeList = BindingManager()->GetAnonymousNodesFor(aElement);
    6668          19 :   if (!nodeList)
    6669           0 :     return nullptr;
    6670             : 
    6671          19 :   uint32_t length = 0;
    6672          19 :   nodeList->GetLength(&length);
    6673             : 
    6674          19 :   bool universalMatch = aAttrValue.EqualsLiteral("*");
    6675             : 
    6676          52 :   for (uint32_t i = 0; i < length; ++i) {
    6677          52 :     nsIContent* current = nodeList->Item(i);
    6678             :     Element* matchedElm =
    6679          52 :       GetElementByAttribute(current, aAttrName, aAttrValue, universalMatch);
    6680          52 :     if (matchedElm)
    6681          19 :       return matchedElm;
    6682             :   }
    6683             : 
    6684           0 :   return nullptr;
    6685             : }
    6686             : 
    6687             : NS_IMETHODIMP
    6688           0 : nsDocument::GetAnonymousElementByAttribute(nsIDOMElement* aElement,
    6689             :                                            const nsAString& aAttrName,
    6690             :                                            const nsAString& aAttrValue,
    6691             :                                            nsIDOMElement** aResult)
    6692             : {
    6693           0 :   nsCOMPtr<Element> element = do_QueryInterface(aElement);
    6694           0 :   NS_ENSURE_ARG_POINTER(element);
    6695             : 
    6696             :   Element* anonEl =
    6697           0 :     nsIDocument::GetAnonymousElementByAttribute(*element, aAttrName,
    6698           0 :                                                 aAttrValue);
    6699           0 :   nsCOMPtr<nsIDOMElement> retval = do_QueryInterface(anonEl);
    6700           0 :   retval.forget(aResult);
    6701           0 :   return NS_OK;
    6702             : }
    6703             : 
    6704             : Element*
    6705          16 : nsIDocument::GetAnonymousElementByAttribute(Element& aElement,
    6706             :                                             const nsAString& aAttrName,
    6707             :                                             const nsAString& aAttrValue)
    6708             : {
    6709          32 :   nsCOMPtr<nsIAtom> attribute = NS_Atomize(aAttrName);
    6710             : 
    6711          32 :   return GetAnonymousElementByAttribute(&aElement, attribute, aAttrValue);
    6712             : }
    6713             : 
    6714             : 
    6715             : NS_IMETHODIMP
    6716           0 : nsDocument::GetAnonymousNodes(nsIDOMElement* aElement,
    6717             :                               nsIDOMNodeList** aResult)
    6718             : {
    6719           0 :   *aResult = nullptr;
    6720             : 
    6721           0 :   nsCOMPtr<nsIContent> content(do_QueryInterface(aElement));
    6722           0 :   return BindingManager()->GetAnonymousNodesFor(content, aResult);
    6723             : }
    6724             : 
    6725             : nsINodeList*
    6726           0 : nsIDocument::GetAnonymousNodes(Element& aElement)
    6727             : {
    6728           0 :   return BindingManager()->GetAnonymousNodesFor(&aElement);
    6729             : }
    6730             : 
    6731             : NS_IMETHODIMP
    6732           0 : nsDocument::CreateRange(nsIDOMRange** aReturn)
    6733             : {
    6734           0 :   ErrorResult rv;
    6735           0 :   *aReturn = nsIDocument::CreateRange(rv).take();
    6736           0 :   return rv.StealNSResult();
    6737             : }
    6738             : 
    6739             : already_AddRefed<nsRange>
    6740           2 : nsIDocument::CreateRange(ErrorResult& rv)
    6741             : {
    6742           4 :   RefPtr<nsRange> range = new nsRange(this);
    6743           2 :   nsresult res = range->CollapseTo(this, 0);
    6744           2 :   if (NS_FAILED(res)) {
    6745           0 :     rv.Throw(res);
    6746           0 :     return nullptr;
    6747             :   }
    6748             : 
    6749           2 :   return range.forget();
    6750             : }
    6751             : 
    6752             : NS_IMETHODIMP
    6753           0 : nsDocument::CreateNodeIterator(nsIDOMNode *aRoot,
    6754             :                                uint32_t aWhatToShow,
    6755             :                                nsIDOMNodeFilter *aFilter,
    6756             :                                uint8_t aOptionalArgc,
    6757             :                                nsIDOMNodeIterator **_retval)
    6758             : {
    6759           0 :   *_retval = nullptr;
    6760             : 
    6761           0 :   if (!aOptionalArgc) {
    6762           0 :     aWhatToShow = nsIDOMNodeFilter::SHOW_ALL;
    6763             :   }
    6764             : 
    6765           0 :   if (!aRoot) {
    6766           0 :     return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
    6767             :   }
    6768             : 
    6769           0 :   nsCOMPtr<nsINode> root = do_QueryInterface(aRoot);
    6770           0 :   NS_ENSURE_TRUE(root, NS_ERROR_UNEXPECTED);
    6771             : 
    6772           0 :   ErrorResult rv;
    6773           0 :   *_retval = nsIDocument::CreateNodeIterator(*root, aWhatToShow,
    6774           0 :                                              NodeFilterHolder(aFilter),
    6775           0 :                                              rv).take();
    6776           0 :   return rv.StealNSResult();
    6777             : }
    6778             : 
    6779             : already_AddRefed<NodeIterator>
    6780           0 : nsIDocument::CreateNodeIterator(nsINode& aRoot, uint32_t aWhatToShow,
    6781             :                                 NodeFilter* aFilter,
    6782             :                                 ErrorResult& rv) const
    6783             : {
    6784           0 :   return CreateNodeIterator(aRoot, aWhatToShow, NodeFilterHolder(aFilter), rv);
    6785             : }
    6786             : 
    6787             : already_AddRefed<NodeIterator>
    6788           0 : nsIDocument::CreateNodeIterator(nsINode& aRoot, uint32_t aWhatToShow,
    6789             :                                 NodeFilterHolder aFilter,
    6790             :                                 ErrorResult& rv) const
    6791             : {
    6792           0 :   nsINode* root = &aRoot;
    6793             :   RefPtr<NodeIterator> iterator = new NodeIterator(root, aWhatToShow,
    6794           0 :                                                    Move(aFilter));
    6795           0 :   return iterator.forget();
    6796             : }
    6797             : 
    6798             : NS_IMETHODIMP
    6799           0 : nsDocument::CreateTreeWalker(nsIDOMNode *aRoot,
    6800             :                              uint32_t aWhatToShow,
    6801             :                              nsIDOMNodeFilter *aFilter,
    6802             :                              uint8_t aOptionalArgc,
    6803             :                              nsIDOMTreeWalker **_retval)
    6804             : {
    6805           0 :   *_retval = nullptr;
    6806             : 
    6807           0 :   if (!aOptionalArgc) {
    6808           0 :     aWhatToShow = nsIDOMNodeFilter::SHOW_ALL;
    6809             :   }
    6810             : 
    6811           0 :   nsCOMPtr<nsINode> root = do_QueryInterface(aRoot);
    6812           0 :   NS_ENSURE_TRUE(root, NS_ERROR_DOM_NOT_SUPPORTED_ERR);
    6813             : 
    6814           0 :   ErrorResult rv;
    6815           0 :   *_retval = nsIDocument::CreateTreeWalker(*root, aWhatToShow,
    6816           0 :                                            NodeFilterHolder(aFilter),
    6817           0 :                                            rv).take();
    6818           0 :   return rv.StealNSResult();
    6819             : }
    6820             : 
    6821             : already_AddRefed<TreeWalker>
    6822           0 : nsIDocument::CreateTreeWalker(nsINode& aRoot, uint32_t aWhatToShow,
    6823             :                               NodeFilter* aFilter,
    6824             :                               ErrorResult& rv) const
    6825             : {
    6826           0 :   return CreateTreeWalker(aRoot, aWhatToShow, NodeFilterHolder(aFilter), rv);
    6827             : }
    6828             : 
    6829             : already_AddRefed<TreeWalker>
    6830           0 : nsIDocument::CreateTreeWalker(nsINode& aRoot, uint32_t aWhatToShow,
    6831             :                               NodeFilterHolder aFilter, ErrorResult& rv) const
    6832             : {
    6833           0 :   nsINode* root = &aRoot;
    6834           0 :   RefPtr<TreeWalker> walker = new TreeWalker(root, aWhatToShow, Move(aFilter));
    6835           0 :   return walker.forget();
    6836             : }
    6837             : 
    6838             : 
    6839             : NS_IMETHODIMP
    6840           0 : nsDocument::GetDefaultView(mozIDOMWindowProxy** aDefaultView)
    6841             : {
    6842           0 :   *aDefaultView = nullptr;
    6843           0 :   nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
    6844           0 :   win.forget(aDefaultView);
    6845           0 :   return NS_OK;
    6846             : }
    6847             : 
    6848             : already_AddRefed<Location>
    6849           1 : nsIDocument::GetLocation() const
    6850             : {
    6851           2 :   nsCOMPtr<nsPIDOMWindowInner> w = do_QueryInterface(mScriptGlobalObject);
    6852             : 
    6853           1 :   if (!w) {
    6854           0 :     return nullptr;
    6855             :   }
    6856             : 
    6857           1 :   nsGlobalWindow* window = nsGlobalWindow::Cast(w);
    6858           2 :   RefPtr<Location> loc = window->GetLocation();
    6859           1 :   return loc.forget();
    6860             : }
    6861             : 
    6862             : Element*
    6863         101 : nsIDocument::GetHtmlElement() const
    6864             : {
    6865         101 :   Element* rootElement = GetRootElement();
    6866         101 :   if (rootElement && rootElement->IsHTMLElement(nsGkAtoms::html))
    6867          65 :     return rootElement;
    6868          36 :   return nullptr;
    6869             : }
    6870             : 
    6871             : Element*
    6872          95 : nsIDocument::GetHtmlChildElement(nsIAtom* aTag)
    6873             : {
    6874          95 :   Element* html = GetHtmlElement();
    6875          95 :   if (!html)
    6876          36 :     return nullptr;
    6877             : 
    6878             :   // Look for the element with aTag inside html. This needs to run
    6879             :   // forwards to find the first such element.
    6880         118 :   for (nsIContent* child = html->GetFirstChild();
    6881         118 :        child;
    6882          59 :        child = child->GetNextSibling()) {
    6883         118 :     if (child->IsHTMLElement(aTag))
    6884          59 :       return child->AsElement();
    6885             :   }
    6886           0 :   return nullptr;
    6887             : }
    6888             : 
    6889             : Element*
    6890          26 : nsDocument::GetTitleElement()
    6891             : {
    6892             :   // mMayHaveTitleElement will have been set to true if any HTML or SVG
    6893             :   // <title> element has been bound to this document. So if it's false,
    6894             :   // we know there is nothing to do here. This avoids us having to search
    6895             :   // the whole DOM if someone calls document.title on a large document
    6896             :   // without a title.
    6897          26 :   if (!mMayHaveTitleElement)
    6898          25 :     return nullptr;
    6899             : 
    6900           1 :   Element* root = GetRootElement();
    6901           1 :   if (root && root->IsSVGElement(nsGkAtoms::svg)) {
    6902             :     // In SVG, the document's title must be a child
    6903           0 :     for (nsIContent* child = root->GetFirstChild();
    6904           0 :          child; child = child->GetNextSibling()) {
    6905           0 :       if (child->IsSVGElement(nsGkAtoms::title)) {
    6906           0 :         return child->AsElement();
    6907             :       }
    6908             :     }
    6909           0 :     return nullptr;
    6910             :   }
    6911             : 
    6912             :   // We check the HTML namespace even for non-HTML documents, except SVG.  This
    6913             :   // matches the spec and the behavior of all tested browsers.
    6914             :   RefPtr<nsContentList> list =
    6915           2 :     NS_GetContentList(this, kNameSpaceID_XHTML, NS_LITERAL_STRING("title"));
    6916             : 
    6917           1 :   nsIContent* first = list->Item(0, false);
    6918             : 
    6919           1 :   return first ? first->AsElement() : nullptr;
    6920             : }
    6921             : 
    6922             : NS_IMETHODIMP
    6923           0 : nsDocument::GetTitle(nsAString& aTitle)
    6924             : {
    6925           0 :   nsString title;
    6926           0 :   GetTitle(title);
    6927           0 :   aTitle = title;
    6928           0 :   return NS_OK;
    6929             : }
    6930             : 
    6931             : void
    6932          28 : nsDocument::GetTitle(nsString& aTitle)
    6933             : {
    6934          28 :   aTitle.Truncate();
    6935             : 
    6936          28 :   Element* rootElement = GetRootElement();
    6937          28 :   if (!rootElement) {
    6938          27 :     return;
    6939             :   }
    6940             : 
    6941          29 :   nsAutoString tmp;
    6942             : 
    6943             : #ifdef MOZ_XUL
    6944          27 :   if (rootElement->IsXULElement()) {
    6945           1 :     rootElement->GetAttr(kNameSpaceID_None, nsGkAtoms::title, tmp);
    6946             :   } else
    6947             : #endif
    6948             :   {
    6949          26 :     Element* title = GetTitleElement();
    6950          26 :     if (!title) {
    6951          25 :       return;
    6952             :     }
    6953           1 :     nsContentUtils::GetNodeTextContent(title, false, tmp);
    6954             :   }
    6955             : 
    6956           2 :   tmp.CompressWhitespace();
    6957           2 :   aTitle = tmp;
    6958             : }
    6959             : 
    6960             : NS_IMETHODIMP
    6961           1 : nsDocument::SetTitle(const nsAString& aTitle)
    6962             : {
    6963           1 :   Element* rootElement = GetRootElement();
    6964           1 :   if (!rootElement) {
    6965           0 :     return NS_OK;
    6966             :   }
    6967             : 
    6968             : #ifdef MOZ_XUL
    6969           1 :   if (rootElement->IsXULElement()) {
    6970           1 :     return rootElement->SetAttr(kNameSpaceID_None, nsGkAtoms::title,
    6971           1 :                                 aTitle, true);
    6972             :   }
    6973             : #endif
    6974             : 
    6975             :   // Batch updates so that mutation events don't change "the title
    6976             :   // element" under us
    6977           0 :   mozAutoDocUpdate updateBatch(this, UPDATE_CONTENT_MODEL, true);
    6978             : 
    6979           0 :   nsCOMPtr<Element> title = GetTitleElement();
    6980           0 :   if (rootElement->IsSVGElement(nsGkAtoms::svg)) {
    6981           0 :     if (!title) {
    6982             :       RefPtr<mozilla::dom::NodeInfo> titleInfo =
    6983           0 :         mNodeInfoManager->GetNodeInfo(nsGkAtoms::title, nullptr,
    6984             :                                       kNameSpaceID_SVG,
    6985           0 :                                       nsIDOMNode::ELEMENT_NODE);
    6986           0 :       NS_NewSVGElement(getter_AddRefs(title), titleInfo.forget(),
    6987           0 :                        NOT_FROM_PARSER);
    6988           0 :       if (!title) {
    6989           0 :         return NS_OK;
    6990             :       }
    6991           0 :       rootElement->InsertChildAt(title, 0, true);
    6992             :     }
    6993           0 :   } else if (rootElement->IsHTMLElement()) {
    6994           0 :     if (!title) {
    6995           0 :       Element* head = GetHeadElement();
    6996           0 :       if (!head) {
    6997           0 :         return NS_OK;
    6998             :       }
    6999             : 
    7000           0 :       RefPtr<mozilla::dom::NodeInfo> titleInfo;
    7001           0 :       titleInfo = mNodeInfoManager->GetNodeInfo(nsGkAtoms::title, nullptr,
    7002             :           kNameSpaceID_XHTML,
    7003           0 :           nsIDOMNode::ELEMENT_NODE);
    7004           0 :       title = NS_NewHTMLTitleElement(titleInfo.forget());
    7005           0 :       if (!title) {
    7006           0 :         return NS_OK;
    7007             :       }
    7008             : 
    7009           0 :       head->AppendChildTo(title, true);
    7010             :     }
    7011             :   } else {
    7012           0 :     return NS_OK;
    7013             :   }
    7014             : 
    7015           0 :   return nsContentUtils::SetNodeTextContent(title, aTitle, false);
    7016             : }
    7017             : 
    7018             : void
    7019           1 : nsDocument::SetTitle(const nsAString& aTitle, ErrorResult& rv)
    7020             : {
    7021           1 :   rv = SetTitle(aTitle);
    7022           1 : }
    7023             : 
    7024             : void
    7025          27 : nsDocument::NotifyPossibleTitleChange(bool aBoundTitleElement)
    7026             : {
    7027          27 :   NS_ASSERTION(!mInUnlinkOrDeletion || !aBoundTitleElement,
    7028             :                "Setting a title while unlinking or destroying the element?");
    7029          27 :   if (mInUnlinkOrDeletion) {
    7030           1 :     return;
    7031             :   }
    7032             : 
    7033          27 :   if (aBoundTitleElement) {
    7034           1 :     mMayHaveTitleElement = true;
    7035             :   }
    7036          27 :   if (mPendingTitleChangeEvent.IsPending())
    7037           1 :     return;
    7038             : 
    7039          26 :   MOZ_RELEASE_ASSERT(NS_IsMainThread());
    7040             :   RefPtr<nsRunnableMethod<nsDocument, void, false>> event =
    7041          52 :     NewNonOwningRunnableMethod("nsDocument::DoNotifyPossibleTitleChange",
    7042             :                                this,
    7043          52 :                                &nsDocument::DoNotifyPossibleTitleChange);
    7044          78 :   nsresult rv = Dispatch("nsDocument::DoNotifyPossibleTitleChange",
    7045          78 :                          TaskCategory::Other, do_AddRef(event));
    7046          26 :   if (NS_SUCCEEDED(rv)) {
    7047          26 :     mPendingTitleChangeEvent = event;
    7048             :   }
    7049             : }
    7050             : 
    7051             : void
    7052          26 : nsDocument::DoNotifyPossibleTitleChange()
    7053             : {
    7054          26 :   mPendingTitleChangeEvent.Forget();
    7055          26 :   mHaveFiredTitleChange = true;
    7056             : 
    7057          52 :   nsAutoString title;
    7058          26 :   GetTitle(title);
    7059             : 
    7060          52 :   nsCOMPtr<nsIPresShell> shell = GetShell();
    7061          26 :   if (shell) {
    7062             :     nsCOMPtr<nsISupports> container =
    7063          48 :       shell->GetPresContext()->GetContainerWeak();
    7064          24 :     if (container) {
    7065           6 :       nsCOMPtr<nsIBaseWindow> docShellWin = do_QueryInterface(container);
    7066           3 :       if (docShellWin) {
    7067           3 :         docShellWin->SetTitle(title.get());
    7068             :       }
    7069             :     }
    7070             :   }
    7071             : 
    7072             :   // Fire a DOM event for the title change.
    7073          26 :   nsContentUtils::DispatchChromeEvent(this, static_cast<nsIDocument*>(this),
    7074          52 :                                       NS_LITERAL_STRING("DOMTitleChanged"),
    7075          52 :                                       true, true);
    7076          26 : }
    7077             : 
    7078             : already_AddRefed<BoxObject>
    7079          12 : nsDocument::GetBoxObjectFor(Element* aElement, ErrorResult& aRv)
    7080             : {
    7081          12 :   if (!aElement) {
    7082           0 :     aRv.Throw(NS_ERROR_UNEXPECTED);
    7083           0 :     return nullptr;
    7084             :   }
    7085             : 
    7086          12 :   nsIDocument* doc = aElement->OwnerDoc();
    7087          12 :   if (doc != this) {
    7088           0 :     aRv.Throw(NS_ERROR_DOM_WRONG_DOCUMENT_ERR);
    7089           0 :     return nullptr;
    7090             :   }
    7091             : 
    7092          12 :   if (!mHasWarnedAboutBoxObjects && !aElement->IsXULElement()) {
    7093           0 :     mHasWarnedAboutBoxObjects = true;
    7094           0 :     nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
    7095           0 :                                     NS_LITERAL_CSTRING("BoxObjects"), this,
    7096             :                                     nsContentUtils::eDOM_PROPERTIES,
    7097           0 :                                     "UseOfGetBoxObjectForWarning");
    7098             :   }
    7099             : 
    7100          12 :   if (!mBoxObjectTable) {
    7101           1 :     mBoxObjectTable = new nsRefPtrHashtable<nsPtrHashKey<nsIContent>, BoxObject>(6);
    7102             :   }
    7103             : 
    7104          24 :   RefPtr<BoxObject> boxObject;
    7105          24 :   auto entry = mBoxObjectTable->LookupForAdd(aElement);
    7106          12 :   if (entry) {
    7107           1 :     boxObject = entry.Data();
    7108           1 :     return boxObject.forget();
    7109             :   }
    7110             : 
    7111             :   int32_t namespaceID;
    7112          22 :   nsCOMPtr<nsIAtom> tag = BindingManager()->ResolveTag(aElement, &namespaceID);
    7113             : #ifdef MOZ_XUL
    7114          11 :   if (namespaceID == kNameSpaceID_XUL) {
    7115          33 :     if (tag == nsGkAtoms::browser ||
    7116          22 :         tag == nsGkAtoms::editor ||
    7117          11 :         tag == nsGkAtoms::iframe) {
    7118           0 :       boxObject = new ContainerBoxObject();
    7119          11 :     } else if (tag == nsGkAtoms::menu) {
    7120           1 :       boxObject = new MenuBoxObject();
    7121          30 :     } else if (tag == nsGkAtoms::popup ||
    7122          17 :                tag == nsGkAtoms::menupopup ||
    7123          22 :                tag == nsGkAtoms::panel ||
    7124           5 :                tag == nsGkAtoms::tooltip) {
    7125           6 :       boxObject = new PopupBoxObject();
    7126           4 :     } else if (tag == nsGkAtoms::tree) {
    7127           0 :       boxObject = new TreeBoxObject();
    7128           4 :     } else if (tag == nsGkAtoms::listbox) {
    7129           0 :       boxObject = new ListBoxObject();
    7130           4 :     } else if (tag == nsGkAtoms::scrollbox) {
    7131           0 :       boxObject = new ScrollBoxObject();
    7132             :     } else {
    7133           4 :       boxObject = new BoxObject();
    7134             :     }
    7135             :   } else
    7136             : #endif // MOZ_XUL
    7137             :   {
    7138           0 :     boxObject = new BoxObject();
    7139             :   }
    7140             : 
    7141          11 :   boxObject->Init(aElement);
    7142          22 :   entry.OrInsert([&boxObject]() { return boxObject; });
    7143             : 
    7144          11 :   return boxObject.forget();
    7145             : }
    7146             : 
    7147             : void
    7148         120 : nsDocument::ClearBoxObjectFor(nsIContent* aContent)
    7149             : {
    7150         120 :   if (mBoxObjectTable) {
    7151          77 :     if (auto entry = mBoxObjectTable->Lookup(aContent)) {
    7152           0 :       nsPIBoxObject* boxObject = entry.Data();
    7153           0 :       boxObject->Clear();
    7154           0 :       entry.Remove();
    7155             :     }
    7156             :   }
    7157         120 : }
    7158             : 
    7159             : already_AddRefed<MediaQueryList>
    7160           3 : nsIDocument::MatchMedia(const nsAString& aMediaQueryList)
    7161             : {
    7162           6 :   RefPtr<MediaQueryList> result = new MediaQueryList(this, aMediaQueryList);
    7163             : 
    7164           3 :   mDOMMediaQueryLists.insertBack(result);
    7165             : 
    7166           6 :   return result.forget();
    7167             : }
    7168             : 
    7169             : void
    7170           0 : nsDocument::FlushSkinBindings()
    7171             : {
    7172           0 :   BindingManager()->FlushSkinBindings();
    7173           0 : }
    7174             : 
    7175             : nsresult
    7176           3 : nsDocument::InitializeFrameLoader(nsFrameLoader* aLoader)
    7177             : {
    7178           3 :   mInitializableFrameLoaders.RemoveElement(aLoader);
    7179             :   // Don't even try to initialize.
    7180           3 :   if (mInDestructor) {
    7181             :     NS_WARNING("Trying to initialize a frame loader while"
    7182           0 :                "document is being deleted");
    7183           0 :     return NS_ERROR_FAILURE;
    7184             :   }
    7185             : 
    7186           3 :   mInitializableFrameLoaders.AppendElement(aLoader);
    7187           3 :   if (!mFrameLoaderRunner) {
    7188             :     mFrameLoaderRunner =
    7189           6 :       NewRunnableMethod("nsDocument::MaybeInitializeFinalizeFrameLoaders",
    7190             :                         this,
    7191           3 :                         &nsDocument::MaybeInitializeFinalizeFrameLoaders);
    7192           3 :     NS_ENSURE_TRUE(mFrameLoaderRunner, NS_ERROR_OUT_OF_MEMORY);
    7193           3 :     nsContentUtils::AddScriptRunner(mFrameLoaderRunner);
    7194             :   }
    7195           3 :   return NS_OK;
    7196             : }
    7197             : 
    7198             : nsresult
    7199           1 : nsDocument::FinalizeFrameLoader(nsFrameLoader* aLoader, nsIRunnable* aFinalizer)
    7200             : {
    7201           1 :   mInitializableFrameLoaders.RemoveElement(aLoader);
    7202           1 :   if (mInDestructor) {
    7203           0 :     return NS_ERROR_FAILURE;
    7204             :   }
    7205             : 
    7206           1 :   mFrameLoaderFinalizers.AppendElement(aFinalizer);
    7207           1 :   if (!mFrameLoaderRunner) {
    7208             :     mFrameLoaderRunner =
    7209           2 :       NewRunnableMethod("nsDocument::MaybeInitializeFinalizeFrameLoaders",
    7210             :                         this,
    7211           1 :                         &nsDocument::MaybeInitializeFinalizeFrameLoaders);
    7212           1 :     NS_ENSURE_TRUE(mFrameLoaderRunner, NS_ERROR_OUT_OF_MEMORY);
    7213           1 :     nsContentUtils::AddScriptRunner(mFrameLoaderRunner);
    7214             :   }
    7215           1 :   return NS_OK;
    7216             : }
    7217             : 
    7218             : void
    7219         741 : nsDocument::MaybeInitializeFinalizeFrameLoaders()
    7220             : {
    7221         741 :   if (mDelayFrameLoaderInitialization || mUpdateNestLevel != 0) {
    7222             :     // This method will be recalled when mUpdateNestLevel drops to 0,
    7223             :     // or when !mDelayFrameLoaderInitialization.
    7224         311 :     mFrameLoaderRunner = nullptr;
    7225         311 :     return;
    7226             :   }
    7227             : 
    7228             :   // We're not in an update, but it is not safe to run scripts, so
    7229             :   // postpone frameloader initialization and finalization.
    7230         430 :   if (!nsContentUtils::IsSafeToRunScript()) {
    7231         110 :     if (!mInDestructor && !mFrameLoaderRunner &&
    7232         110 :         (mInitializableFrameLoaders.Length() ||
    7233          55 :          mFrameLoaderFinalizers.Length())) {
    7234             :       mFrameLoaderRunner =
    7235           0 :         NewRunnableMethod("nsDocument::MaybeInitializeFinalizeFrameLoaders",
    7236             :                           this,
    7237           0 :                           &nsDocument::MaybeInitializeFinalizeFrameLoaders);
    7238           0 :       nsContentUtils::AddScriptRunner(mFrameLoaderRunner);
    7239             :     }
    7240          55 :     return;
    7241             :   }
    7242         375 :   mFrameLoaderRunner = nullptr;
    7243             : 
    7244             :   // Don't use a temporary array for mInitializableFrameLoaders, because
    7245             :   // loading a frame may cause some other frameloader to be removed from the
    7246             :   // array. But be careful to keep the loader alive when starting the load!
    7247         381 :   while (mInitializableFrameLoaders.Length()) {
    7248           6 :     RefPtr<nsFrameLoader> loader = mInitializableFrameLoaders[0];
    7249           3 :     mInitializableFrameLoaders.RemoveElementAt(0);
    7250           3 :     NS_ASSERTION(loader, "null frameloader in the array?");
    7251           3 :     loader->ReallyStartLoading();
    7252             :   }
    7253             : 
    7254         375 :   uint32_t length = mFrameLoaderFinalizers.Length();
    7255         375 :   if (length > 0) {
    7256           2 :     nsTArray<nsCOMPtr<nsIRunnable> > finalizers;
    7257           1 :     mFrameLoaderFinalizers.SwapElements(finalizers);
    7258           2 :     for (uint32_t i = 0; i < length; ++i) {
    7259           1 :       finalizers[i]->Run();
    7260             :     }
    7261             :   }
    7262             : }
    7263             : 
    7264             : void
    7265           2 : nsDocument::TryCancelFrameLoaderInitialization(nsIDocShell* aShell)
    7266             : {
    7267           2 :   uint32_t length = mInitializableFrameLoaders.Length();
    7268           3 :   for (uint32_t i = 0; i < length; ++i) {
    7269           1 :     if (mInitializableFrameLoaders[i]->GetExistingDocShell() == aShell) {
    7270           0 :       mInitializableFrameLoaders.RemoveElementAt(i);
    7271           0 :       return;
    7272             :     }
    7273             :   }
    7274             : }
    7275             : 
    7276             : nsIDocument*
    7277           0 : nsDocument::RequestExternalResource(nsIURI* aURI,
    7278             :                                     nsINode* aRequestingNode,
    7279             :                                     ExternalResourceLoad** aPendingLoad)
    7280             : {
    7281           0 :   NS_PRECONDITION(aURI, "Must have a URI");
    7282           0 :   NS_PRECONDITION(aRequestingNode, "Must have a node");
    7283           0 :   if (mDisplayDocument) {
    7284           0 :     return mDisplayDocument->RequestExternalResource(aURI,
    7285             :                                                      aRequestingNode,
    7286           0 :                                                      aPendingLoad);
    7287             :   }
    7288             : 
    7289           0 :   return mExternalResourceMap.RequestResource(aURI, aRequestingNode,
    7290           0 :                                               this, aPendingLoad);
    7291             : }
    7292             : 
    7293             : void
    7294         158 : nsDocument::EnumerateExternalResources(nsSubDocEnumFunc aCallback, void* aData)
    7295             : {
    7296         158 :   mExternalResourceMap.EnumerateResources(aCallback, aData);
    7297         158 : }
    7298             : 
    7299             : nsSMILAnimationController*
    7300         350 : nsDocument::GetAnimationController()
    7301             : {
    7302             :   // We create the animation controller lazily because most documents won't want
    7303             :   // one and only SVG documents and the like will call this
    7304         350 :   if (mAnimationController)
    7305         328 :     return mAnimationController;
    7306             :   // Refuse to create an Animation Controller for data documents.
    7307          22 :   if (mLoadedAsData || mLoadedAsInteractiveData)
    7308           0 :     return nullptr;
    7309             : 
    7310          22 :   mAnimationController = new nsSMILAnimationController(this);
    7311             : 
    7312             :   // If there's a presContext then check the animation mode and pause if
    7313             :   // necessary.
    7314          22 :   nsIPresShell *shell = GetShell();
    7315          22 :   if (mAnimationController && shell) {
    7316           1 :     nsPresContext *context = shell->GetPresContext();
    7317           2 :     if (context &&
    7318           1 :         context->ImageAnimationMode() == imgIContainer::kDontAnimMode) {
    7319           0 :       mAnimationController->Pause(nsSMILTimeContainer::PAUSE_USERPREF);
    7320             :     }
    7321             :   }
    7322             : 
    7323             :   // If we're hidden (or being hidden), notify the newly-created animation
    7324             :   // controller. (Skip this check for SVG-as-an-image documents, though,
    7325             :   // because they don't get OnPageShow / OnPageHide calls).
    7326          22 :   if (!mIsShowing && !mIsBeingUsedAsImage) {
    7327           1 :     mAnimationController->OnPageHide();
    7328             :   }
    7329             : 
    7330          22 :   return mAnimationController;
    7331             : }
    7332             : 
    7333             : PendingAnimationTracker*
    7334           2 : nsDocument::GetOrCreatePendingAnimationTracker()
    7335             : {
    7336           2 :   if (!mPendingAnimationTracker) {
    7337           1 :     mPendingAnimationTracker = new PendingAnimationTracker(this);
    7338             :   }
    7339             : 
    7340           2 :   return mPendingAnimationTracker;
    7341             : }
    7342             : 
    7343             : /**
    7344             :  * Retrieve the "direction" property of the document.
    7345             :  *
    7346             :  * @lina 01/09/2001
    7347             :  */
    7348             : NS_IMETHODIMP
    7349           0 : nsDocument::GetDir(nsAString& aDirection)
    7350             : {
    7351           0 :   nsIDocument::GetDir(aDirection);
    7352           0 :   return NS_OK;
    7353             : }
    7354             : 
    7355             : void
    7356           0 : nsIDocument::GetDir(nsAString& aDirection) const
    7357             : {
    7358           0 :   aDirection.Truncate();
    7359           0 :   Element* rootElement = GetHtmlElement();
    7360           0 :   if (rootElement) {
    7361           0 :     static_cast<nsGenericHTMLElement*>(rootElement)->GetDir(aDirection);
    7362             :   }
    7363           0 : }
    7364             : 
    7365             : /**
    7366             :  * Set the "direction" property of the document.
    7367             :  *
    7368             :  * @lina 01/09/2001
    7369             :  */
    7370             : NS_IMETHODIMP
    7371           0 : nsDocument::SetDir(const nsAString& aDirection)
    7372             : {
    7373           0 :   nsIDocument::SetDir(aDirection);
    7374           0 :   return NS_OK;
    7375             : }
    7376             : 
    7377             : void
    7378           0 : nsIDocument::SetDir(const nsAString& aDirection)
    7379             : {
    7380           0 :   Element* rootElement = GetHtmlElement();
    7381           0 :   if (rootElement) {
    7382             :     rootElement->SetAttr(kNameSpaceID_None, nsGkAtoms::dir,
    7383           0 :                          aDirection, true);
    7384             :   }
    7385           0 : }
    7386             : 
    7387             : NS_IMETHODIMP
    7388           0 : nsDocument::GetInputEncoding(nsAString& aInputEncoding)
    7389             : {
    7390           0 :   nsIDocument::GetCharacterSet(aInputEncoding);
    7391           0 :   return NS_OK;
    7392             : }
    7393             : 
    7394             : NS_IMETHODIMP
    7395           0 : nsDocument::GetMozSyntheticDocument(bool *aSyntheticDocument)
    7396             : {
    7397           0 :   *aSyntheticDocument = mIsSyntheticDocument;
    7398           0 :   return NS_OK;
    7399             : }
    7400             : 
    7401             : NS_IMETHODIMP
    7402           0 : nsDocument::GetDocumentURI(nsAString& aDocumentURI)
    7403             : {
    7404           0 :   nsString temp;
    7405           0 :   nsresult rv = nsIDocument::GetDocumentURI(temp);
    7406           0 :   aDocumentURI = temp;
    7407           0 :   return rv;
    7408             : }
    7409             : 
    7410             : nsresult
    7411          12 : nsIDocument::GetDocumentURI(nsString& aDocumentURI) const
    7412             : {
    7413          12 :   if (mDocumentURI) {
    7414          24 :     nsAutoCString uri;
    7415          12 :     nsresult rv = mDocumentURI->GetSpec(uri);
    7416          12 :     NS_ENSURE_SUCCESS(rv, rv);
    7417             : 
    7418          12 :     CopyUTF8toUTF16(uri, aDocumentURI);
    7419             :   } else {
    7420           0 :     aDocumentURI.Truncate();
    7421             :   }
    7422             : 
    7423          12 :   return NS_OK;
    7424             : }
    7425             : 
    7426             : // Alias of above
    7427             : NS_IMETHODIMP
    7428           0 : nsDocument::GetURL(nsAString& aURL)
    7429             : {
    7430           0 :   return GetDocumentURI(aURL);
    7431             : }
    7432             : 
    7433             : nsresult
    7434           0 : nsIDocument::GetURL(nsString& aURL) const
    7435             : {
    7436           0 :   return GetDocumentURI(aURL);
    7437             : }
    7438             : 
    7439             : void
    7440          12 : nsIDocument::GetDocumentURIFromJS(nsString& aDocumentURI, CallerType aCallerType,
    7441             :                                   ErrorResult& aRv) const
    7442             : {
    7443          12 :   if (!mChromeXHRDocURI || aCallerType != CallerType::System) {
    7444          12 :     aRv = GetDocumentURI(aDocumentURI);
    7445          12 :     return;
    7446             :   }
    7447             : 
    7448           0 :   nsAutoCString uri;
    7449           0 :   nsresult res = mChromeXHRDocURI->GetSpec(uri);
    7450           0 :   if (NS_FAILED(res)) {
    7451           0 :     aRv.Throw(res);
    7452           0 :     return;
    7453             :   }
    7454           0 :   CopyUTF8toUTF16(uri, aDocumentURI);
    7455             : }
    7456             : 
    7457             : nsIURI*
    7458           7 : nsIDocument::GetDocumentURIObject() const
    7459             : {
    7460           7 :   if (!mChromeXHRDocURI) {
    7461           7 :     return GetDocumentURI();
    7462             :   }
    7463             : 
    7464           0 :   return mChromeXHRDocURI;
    7465             : }
    7466             : 
    7467             : void
    7468           0 : nsIDocument::GetCompatMode(nsString& aCompatMode) const
    7469             : {
    7470           0 :   NS_ASSERTION(mCompatMode == eCompatibility_NavQuirks ||
    7471             :                mCompatMode == eCompatibility_AlmostStandards ||
    7472             :                mCompatMode == eCompatibility_FullStandards,
    7473             :                "mCompatMode is neither quirks nor strict for this document");
    7474             : 
    7475           0 :   if (mCompatMode == eCompatibility_NavQuirks) {
    7476           0 :     aCompatMode.AssignLiteral("BackCompat");
    7477             :   } else {
    7478           0 :     aCompatMode.AssignLiteral("CSS1Compat");
    7479             :   }
    7480           0 : }
    7481             : 
    7482             : void
    7483           0 : nsDOMAttributeMap::BlastSubtreeToPieces(nsINode *aNode)
    7484             : {
    7485           0 :   if (aNode->IsElement()) {
    7486           0 :     Element *element = aNode->AsElement();
    7487           0 :     const nsDOMAttributeMap *map = element->GetAttributeMap();
    7488           0 :     if (map) {
    7489             :       // This non-standard style of iteration is presumably used because some
    7490             :       // of the code in the loop body can trigger element removal, which
    7491             :       // invalidates the iterator.
    7492             :       while (true) {
    7493           0 :         auto iter = map->mAttributeCache.ConstIter();
    7494           0 :         if (iter.Done()) {
    7495           0 :           break;
    7496             :         }
    7497           0 :         nsCOMPtr<nsIAttribute> attr = iter.UserData();
    7498           0 :         NS_ASSERTION(attr.get(),
    7499             :                      "non-nsIAttribute somehow made it into the hashmap?!");
    7500             : 
    7501           0 :         BlastSubtreeToPieces(attr);
    7502             : 
    7503             :         DebugOnly<nsresult> rv =
    7504           0 :           element->UnsetAttr(attr->NodeInfo()->NamespaceID(),
    7505             :                              attr->NodeInfo()->NameAtom(),
    7506           0 :                              false);
    7507             : 
    7508             :         // XXX Should we abort here?
    7509           0 :         NS_ASSERTION(NS_SUCCEEDED(rv), "Uh-oh, UnsetAttr shouldn't fail!");
    7510           0 :       }
    7511             :     }
    7512             :   }
    7513             : 
    7514           0 :   uint32_t count = aNode->GetChildCount();
    7515           0 :   for (uint32_t i = 0; i < count; ++i) {
    7516           0 :     BlastSubtreeToPieces(aNode->GetFirstChild());
    7517           0 :     aNode->RemoveChildAt(0, false);
    7518             :   }
    7519           0 : }
    7520             : 
    7521             : NS_IMETHODIMP
    7522           0 : nsDocument::AdoptNode(nsIDOMNode *aAdoptedNode, nsIDOMNode **aResult)
    7523             : {
    7524           0 :   *aResult = nullptr;
    7525             : 
    7526           0 :   nsCOMPtr<nsINode> adoptedNode = do_QueryInterface(aAdoptedNode);
    7527           0 :   NS_ENSURE_TRUE(adoptedNode, NS_ERROR_UNEXPECTED);
    7528             : 
    7529           0 :   ErrorResult rv;
    7530           0 :   nsINode* result = nsIDocument::AdoptNode(*adoptedNode, rv);
    7531           0 :   if (rv.Failed()) {
    7532           0 :     return rv.StealNSResult();
    7533             :   }
    7534             : 
    7535           0 :   NS_ADDREF(*aResult = result->AsDOMNode());
    7536           0 :   return NS_OK;
    7537             : }
    7538             : 
    7539             : nsINode*
    7540           0 : nsIDocument::AdoptNode(nsINode& aAdoptedNode, ErrorResult& rv)
    7541             : {
    7542           0 :   nsINode* adoptedNode = &aAdoptedNode;
    7543             : 
    7544             :   // Scope firing mutation events so that we don't carry any state that
    7545             :   // might be stale
    7546             :   {
    7547           0 :     nsINode* parent = adoptedNode->GetParentNode();
    7548           0 :     if (parent) {
    7549           0 :       nsContentUtils::MaybeFireNodeRemoved(adoptedNode, parent,
    7550           0 :                                            adoptedNode->OwnerDoc());
    7551             :     }
    7552             :   }
    7553             : 
    7554           0 :   nsAutoScriptBlocker scriptBlocker;
    7555             : 
    7556           0 :   switch (adoptedNode->NodeType()) {
    7557             :     case nsIDOMNode::ATTRIBUTE_NODE:
    7558             :     {
    7559             :       // Remove from ownerElement.
    7560           0 :       RefPtr<Attr> adoptedAttr = static_cast<Attr*>(adoptedNode);
    7561             : 
    7562           0 :       nsCOMPtr<Element> ownerElement = adoptedAttr->GetOwnerElement(rv);
    7563           0 :       if (rv.Failed()) {
    7564           0 :         return nullptr;
    7565             :       }
    7566             : 
    7567           0 :       if (ownerElement) {
    7568             :         RefPtr<Attr> newAttr =
    7569           0 :           ownerElement->RemoveAttributeNode(*adoptedAttr, rv);
    7570           0 :         if (rv.Failed()) {
    7571           0 :           return nullptr;
    7572             :         }
    7573             : 
    7574           0 :         newAttr.swap(adoptedAttr);
    7575             :       }
    7576             : 
    7577           0 :       break;
    7578             :     }
    7579             :     case nsIDOMNode::DOCUMENT_FRAGMENT_NODE:
    7580             :     {
    7581           0 :       if (ShadowRoot::FromNode(adoptedNode)) {
    7582           0 :         rv.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
    7583           0 :         return nullptr;
    7584             :       }
    7585             :       MOZ_FALLTHROUGH;
    7586             :     }
    7587             :     case nsIDOMNode::ELEMENT_NODE:
    7588             :     case nsIDOMNode::PROCESSING_INSTRUCTION_NODE:
    7589             :     case nsIDOMNode::TEXT_NODE:
    7590             :     case nsIDOMNode::CDATA_SECTION_NODE:
    7591             :     case nsIDOMNode::COMMENT_NODE:
    7592             :     case nsIDOMNode::DOCUMENT_TYPE_NODE:
    7593             :     {
    7594             :       // Don't allow adopting a node's anonymous subtree out from under it.
    7595           0 :       if (adoptedNode->AsContent()->IsRootOfAnonymousSubtree()) {
    7596           0 :         rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
    7597           0 :         return nullptr;
    7598             :       }
    7599             : 
    7600             :       // We don't want to adopt an element into its own contentDocument or into
    7601             :       // a descendant contentDocument, so we check if the frameElement of this
    7602             :       // document or any of its parents is the adopted node or one of its
    7603             :       // descendants.
    7604           0 :       nsIDocument *doc = this;
    7605           0 :       do {
    7606           0 :         if (nsPIDOMWindowOuter *win = doc->GetWindow()) {
    7607           0 :           nsCOMPtr<nsINode> node = win->GetFrameElementInternal();
    7608           0 :           if (node &&
    7609           0 :               nsContentUtils::ContentIsDescendantOf(node, adoptedNode)) {
    7610           0 :             rv.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
    7611           0 :             return nullptr;
    7612             :           }
    7613             :         }
    7614             :       } while ((doc = doc->GetParentDocument()));
    7615             : 
    7616             :       // Remove from parent.
    7617           0 :       nsCOMPtr<nsINode> parent = adoptedNode->GetParentNode();
    7618           0 :       if (parent) {
    7619           0 :         int32_t idx = parent->IndexOf(adoptedNode);
    7620           0 :         MOZ_ASSERT(idx >= 0);
    7621           0 :         parent->RemoveChildAt(idx, true);
    7622             :       } else {
    7623           0 :         MOZ_ASSERT(!adoptedNode->IsInUncomposedDoc());
    7624             : 
    7625             :         // If we're adopting a node that's not in a document, it might still
    7626             :         // have a binding applied. Remove the binding from the element now
    7627             :         // that it's getting adopted into a new document.
    7628             :         // TODO Fully tear down the binding.
    7629           0 :         adoptedNode->AsContent()->SetXBLBinding(nullptr);
    7630             :       }
    7631             : 
    7632           0 :       break;
    7633             :     }
    7634             :     case nsIDOMNode::DOCUMENT_NODE:
    7635             :     {
    7636           0 :       rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
    7637           0 :       return nullptr;
    7638             :     }
    7639             :     default:
    7640             :     {
    7641           0 :       NS_WARNING("Don't know how to adopt this nodetype for adoptNode.");
    7642             : 
    7643           0 :       rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
    7644           0 :       return nullptr;
    7645             :     }
    7646             :   }
    7647             : 
    7648           0 :   nsCOMPtr<nsIDocument> oldDocument = adoptedNode->OwnerDoc();
    7649           0 :   bool sameDocument = oldDocument == this;
    7650             : 
    7651           0 :   AutoJSContext cx;
    7652           0 :   JS::Rooted<JSObject*> newScope(cx, nullptr);
    7653           0 :   if (!sameDocument) {
    7654           0 :     newScope = GetWrapper();
    7655           0 :     if (!newScope && GetScopeObject() && GetScopeObject()->GetGlobalJSObject()) {
    7656             :       // Make sure cx is in a semi-sane compartment before we call WrapNative.
    7657             :       // It's kind of irrelevant, given that we're passing aAllowWrapping =
    7658             :       // false, and documents should always insist on being wrapped in an
    7659             :       // canonical scope. But we try to pass something sane anyway.
    7660           0 :       JSAutoCompartment ac(cx, GetScopeObject()->GetGlobalJSObject());
    7661           0 :       JS::Rooted<JS::Value> v(cx);
    7662           0 :       rv = nsContentUtils::WrapNative(cx, this, this, &v,
    7663           0 :                                       /* aAllowWrapping = */ false);
    7664           0 :       if (rv.Failed())
    7665           0 :         return nullptr;
    7666           0 :       newScope = &v.toObject();
    7667             :     }
    7668             :   }
    7669             : 
    7670           0 :   nsCOMArray<nsINode> nodesWithProperties;
    7671           0 :   rv = nsNodeUtils::Adopt(adoptedNode, sameDocument ? nullptr : mNodeInfoManager,
    7672           0 :                           newScope, nodesWithProperties);
    7673           0 :   if (rv.Failed()) {
    7674             :     // Disconnect all nodes from their parents, since some have the old document
    7675             :     // as their ownerDocument and some have this as their ownerDocument.
    7676           0 :     nsDOMAttributeMap::BlastSubtreeToPieces(adoptedNode);
    7677             : 
    7678           0 :     if (!sameDocument && oldDocument) {
    7679           0 :       uint32_t count = nodesWithProperties.Count();
    7680           0 :       for (uint32_t j = 0; j < oldDocument->GetPropertyTableCount(); ++j) {
    7681           0 :         for (uint32_t i = 0; i < count; ++i) {
    7682             :           // Remove all properties.
    7683             :           oldDocument->PropertyTable(j)->
    7684           0 :             DeleteAllPropertiesFor(nodesWithProperties[i]);
    7685             :         }
    7686             :       }
    7687             :     }
    7688             : 
    7689           0 :     return nullptr;
    7690             :   }
    7691             : 
    7692           0 :   uint32_t count = nodesWithProperties.Count();
    7693           0 :   if (!sameDocument && oldDocument) {
    7694           0 :     for (uint32_t j = 0; j < oldDocument->GetPropertyTableCount(); ++j) {
    7695           0 :       nsPropertyTable *oldTable = oldDocument->PropertyTable(j);
    7696           0 :       nsPropertyTable *newTable = PropertyTable(j);
    7697           0 :       for (uint32_t i = 0; i < count; ++i) {
    7698           0 :         rv = oldTable->TransferOrDeleteAllPropertiesFor(nodesWithProperties[i],
    7699           0 :                                                         newTable);
    7700             :       }
    7701             :     }
    7702             : 
    7703           0 :     if (rv.Failed()) {
    7704             :       // Disconnect all nodes from their parents.
    7705           0 :       nsDOMAttributeMap::BlastSubtreeToPieces(adoptedNode);
    7706             : 
    7707           0 :       return nullptr;
    7708             :     }
    7709             :   }
    7710             : 
    7711           0 :   NS_ASSERTION(adoptedNode->OwnerDoc() == this,
    7712             :                "Should still be in the document we just got adopted into");
    7713             : 
    7714           0 :   return adoptedNode;
    7715             : }
    7716             : 
    7717             : nsViewportInfo
    7718           1 : nsDocument::GetViewportInfo(const ScreenIntSize& aDisplaySize)
    7719             : {
    7720             :   // Compute the CSS-to-LayoutDevice pixel scale as the product of the
    7721             :   // widget scale and the full zoom.
    7722           1 :   nsPresContext* context = mPresShell->GetPresContext();
    7723             :   // When querying the full zoom, get it from the device context rather than
    7724             :   // directly from the pres context, because the device context's value can
    7725             :   // include an adjustment necessay to keep the number of app units per device
    7726             :   // pixel an integer, and we want the adjusted value.
    7727           1 :   float fullZoom = context ? context->DeviceContext()->GetFullZoom() : 1.0;
    7728           1 :   fullZoom = (fullZoom == 0.0) ? 1.0 : fullZoom;
    7729           1 :   CSSToLayoutDeviceScale layoutDeviceScale = context ? context->CSSToDevPixelScale() : CSSToLayoutDeviceScale(1);
    7730             : 
    7731             :   CSSToScreenScale defaultScale = layoutDeviceScale
    7732           1 :                                 * LayoutDeviceToScreenScale(1.0);
    7733             : 
    7734             :   // Special behaviour for desktop mode, provided we are not on an about: page
    7735           1 :   nsPIDOMWindowOuter* win = GetWindow();
    7736           1 :   if (win && win->IsDesktopModeViewport() && !IsAboutPage())
    7737             :   {
    7738           0 :     CSSCoord viewportWidth = gfxPrefs::DesktopViewportWidth() / fullZoom;
    7739           0 :     CSSToScreenScale scaleToFit(aDisplaySize.width / viewportWidth);
    7740           0 :     float aspectRatio = (float)aDisplaySize.height / aDisplaySize.width;
    7741           0 :     CSSSize viewportSize(viewportWidth, viewportWidth * aspectRatio);
    7742           0 :     ScreenIntSize fakeDesktopSize = RoundedToInt(viewportSize * scaleToFit);
    7743             :     return nsViewportInfo(fakeDesktopSize,
    7744             :                           scaleToFit,
    7745           0 :                           /*allowZoom*/ true);
    7746             :   }
    7747             : 
    7748           1 :   if (!gfxPrefs::MetaViewportEnabled()) {
    7749             :     return nsViewportInfo(aDisplaySize,
    7750             :                           defaultScale,
    7751           1 :                           /*allowZoom*/ false);
    7752             :   }
    7753             : 
    7754             :   // In cases where the width of the CSS viewport is less than or equal to the width
    7755             :   // of the display (i.e. width <= device-width) then we disable double-tap-to-zoom
    7756             :   // behaviour. See bug 941995 for details.
    7757             : 
    7758           0 :   switch (mViewportType) {
    7759             :   case DisplayWidthHeight:
    7760             :     return nsViewportInfo(aDisplaySize,
    7761             :                           defaultScale,
    7762           0 :                           /*allowZoom*/ true);
    7763             :   case Unknown:
    7764             :   {
    7765           0 :     nsAutoString viewport;
    7766           0 :     GetHeaderData(nsGkAtoms::viewport, viewport);
    7767           0 :     if (viewport.IsEmpty()) {
    7768             :       // If the docType specifies that we are on a site optimized for mobile,
    7769             :       // then we want to return specially crafted defaults for the viewport info.
    7770           0 :       nsCOMPtr<nsIDOMDocumentType> docType;
    7771           0 :       nsresult rv = GetDoctype(getter_AddRefs(docType));
    7772           0 :       if (NS_SUCCEEDED(rv) && docType) {
    7773           0 :         nsAutoString docId;
    7774           0 :         rv = docType->GetPublicId(docId);
    7775           0 :         if (NS_SUCCEEDED(rv)) {
    7776           0 :           if ((docId.Find("WAP") != -1) ||
    7777           0 :               (docId.Find("Mobile") != -1) ||
    7778           0 :               (docId.Find("WML") != -1))
    7779             :           {
    7780             :             // We're making an assumption that the docType can't change here
    7781           0 :             mViewportType = DisplayWidthHeight;
    7782             :             return nsViewportInfo(aDisplaySize,
    7783             :                                   defaultScale,
    7784           0 :                                   /*allowZoom*/true);
    7785             :           }
    7786             :         }
    7787             :       }
    7788             : 
    7789           0 :       nsAutoString handheldFriendly;
    7790           0 :       GetHeaderData(nsGkAtoms::handheldFriendly, handheldFriendly);
    7791           0 :       if (handheldFriendly.EqualsLiteral("true")) {
    7792           0 :         mViewportType = DisplayWidthHeight;
    7793             :         return nsViewportInfo(aDisplaySize,
    7794             :                               defaultScale,
    7795           0 :                               /*allowZoom*/true);
    7796             :       }
    7797             :     }
    7798             : 
    7799           0 :     nsAutoString minScaleStr;
    7800           0 :     GetHeaderData(nsGkAtoms::viewport_minimum_scale, minScaleStr);
    7801             : 
    7802             :     nsresult errorCode;
    7803           0 :     mScaleMinFloat = LayoutDeviceToScreenScale(minScaleStr.ToFloat(&errorCode));
    7804             : 
    7805           0 :     if (NS_FAILED(errorCode)) {
    7806           0 :       mScaleMinFloat = kViewportMinScale;
    7807             :     }
    7808             : 
    7809           0 :     mScaleMinFloat = mozilla::clamped(
    7810           0 :         mScaleMinFloat, kViewportMinScale, kViewportMaxScale);
    7811             : 
    7812           0 :     nsAutoString maxScaleStr;
    7813           0 :     GetHeaderData(nsGkAtoms::viewport_maximum_scale, maxScaleStr);
    7814             : 
    7815             :     // We define a special error code variable for the scale and max scale,
    7816             :     // because they are used later (see the width calculations).
    7817             :     nsresult scaleMaxErrorCode;
    7818           0 :     mScaleMaxFloat = LayoutDeviceToScreenScale(maxScaleStr.ToFloat(&scaleMaxErrorCode));
    7819             : 
    7820           0 :     if (NS_FAILED(scaleMaxErrorCode)) {
    7821           0 :       mScaleMaxFloat = kViewportMaxScale;
    7822             :     }
    7823             : 
    7824           0 :     mScaleMaxFloat = mozilla::clamped(
    7825           0 :         mScaleMaxFloat, kViewportMinScale, kViewportMaxScale);
    7826             : 
    7827           0 :     nsAutoString scaleStr;
    7828           0 :     GetHeaderData(nsGkAtoms::viewport_initial_scale, scaleStr);
    7829             : 
    7830             :     nsresult scaleErrorCode;
    7831           0 :     mScaleFloat = LayoutDeviceToScreenScale(scaleStr.ToFloat(&scaleErrorCode));
    7832             : 
    7833           0 :     nsAutoString widthStr, heightStr;
    7834             : 
    7835           0 :     GetHeaderData(nsGkAtoms::viewport_height, heightStr);
    7836           0 :     GetHeaderData(nsGkAtoms::viewport_width, widthStr);
    7837             : 
    7838           0 :     mAutoSize = false;
    7839             : 
    7840           0 :     if (widthStr.EqualsLiteral("device-width")) {
    7841           0 :       mAutoSize = true;
    7842             :     }
    7843             : 
    7844           0 :     if (widthStr.IsEmpty() &&
    7845           0 :         (heightStr.EqualsLiteral("device-height") ||
    7846           0 :          (mScaleFloat.scale == 1.0)))
    7847             :     {
    7848           0 :       mAutoSize = true;
    7849             :     }
    7850             : 
    7851             :     nsresult widthErrorCode, heightErrorCode;
    7852           0 :     mViewportSize.width = widthStr.ToInteger(&widthErrorCode);
    7853           0 :     mViewportSize.height = heightStr.ToInteger(&heightErrorCode);
    7854             : 
    7855             :     // If width or height has not been set to a valid number by this point,
    7856             :     // fall back to a default value.
    7857           0 :     mValidWidth = (!widthStr.IsEmpty() && NS_SUCCEEDED(widthErrorCode) && mViewportSize.width > 0);
    7858           0 :     mValidHeight = (!heightStr.IsEmpty() && NS_SUCCEEDED(heightErrorCode) && mViewportSize.height > 0);
    7859             : 
    7860           0 :     mAllowZoom = true;
    7861           0 :     nsAutoString userScalable;
    7862           0 :     GetHeaderData(nsGkAtoms::viewport_user_scalable, userScalable);
    7863             : 
    7864           0 :     if ((userScalable.EqualsLiteral("0")) ||
    7865           0 :         (userScalable.EqualsLiteral("no")) ||
    7866           0 :         (userScalable.EqualsLiteral("false"))) {
    7867           0 :       mAllowZoom = false;
    7868             :     }
    7869             : 
    7870           0 :     mScaleStrEmpty = scaleStr.IsEmpty();
    7871           0 :     mWidthStrEmpty = widthStr.IsEmpty();
    7872           0 :     mValidScaleFloat = !scaleStr.IsEmpty() && NS_SUCCEEDED(scaleErrorCode);
    7873           0 :     mValidMaxScale = !maxScaleStr.IsEmpty() && NS_SUCCEEDED(scaleMaxErrorCode);
    7874             : 
    7875           0 :     mViewportType = Specified;
    7876             :     MOZ_FALLTHROUGH;
    7877             :   }
    7878             :   case Specified:
    7879             :   default:
    7880           0 :     LayoutDeviceToScreenScale effectiveMinScale = mScaleMinFloat;
    7881           0 :     LayoutDeviceToScreenScale effectiveMaxScale = mScaleMaxFloat;
    7882           0 :     bool effectiveValidMaxScale = mValidMaxScale;
    7883           0 :     bool effectiveAllowZoom = mAllowZoom;
    7884           0 :     if (gfxPrefs::ForceUserScalable()) {
    7885             :       // If the pref to force user-scalable is enabled, we ignore the values
    7886             :       // from the meta-viewport tag for these properties and just assume they
    7887             :       // allow the page to be scalable. Note in particular that this code is
    7888             :       // in the "Specified" branch of the enclosing switch statement, so that
    7889             :       // calls to GetViewportInfo always use the latest value of the
    7890             :       // ForceUserScalable pref. Other codepaths that return nsViewportInfo
    7891             :       // instances are all consistent with ForceUserScalable() already.
    7892           0 :       effectiveMinScale = kViewportMinScale;
    7893           0 :       effectiveMaxScale = kViewportMaxScale;
    7894           0 :       effectiveValidMaxScale = true;
    7895           0 :       effectiveAllowZoom = true;
    7896             :     }
    7897             : 
    7898           0 :     CSSSize size = mViewportSize;
    7899             : 
    7900           0 :     if (!mValidWidth) {
    7901           0 :       if (mValidHeight && !aDisplaySize.IsEmpty()) {
    7902           0 :         size.width = size.height * aDisplaySize.width / aDisplaySize.height;
    7903             :       } else {
    7904             :         // Stretch CSS pixel size of viewport to keep device pixel size
    7905             :         // unchanged after full zoom applied.
    7906             :         // See bug 974242.
    7907           0 :         size.width = gfxPrefs::DesktopViewportWidth() / fullZoom;
    7908             :       }
    7909             :     }
    7910             : 
    7911           0 :     if (!mValidHeight) {
    7912           0 :       if (!aDisplaySize.IsEmpty()) {
    7913           0 :         size.height = size.width * aDisplaySize.height / aDisplaySize.width;
    7914             :       } else {
    7915           0 :         size.height = size.width;
    7916             :       }
    7917             :     }
    7918             : 
    7919           0 :     CSSToScreenScale scaleFloat = mScaleFloat * layoutDeviceScale;
    7920           0 :     CSSToScreenScale scaleMinFloat = effectiveMinScale * layoutDeviceScale;
    7921           0 :     CSSToScreenScale scaleMaxFloat = effectiveMaxScale * layoutDeviceScale;
    7922             : 
    7923           0 :     if (mAutoSize) {
    7924             :       // aDisplaySize is in screen pixels; convert them to CSS pixels for the viewport size.
    7925           0 :       CSSToScreenScale defaultPixelScale = layoutDeviceScale * LayoutDeviceToScreenScale(1.0f);
    7926           0 :       size = ScreenSize(aDisplaySize) / defaultPixelScale;
    7927             :     }
    7928             : 
    7929           0 :     size.width = clamped(size.width, float(kViewportMinSize.width), float(kViewportMaxSize.width));
    7930             : 
    7931             :     // Also recalculate the default zoom, if it wasn't specified in the metadata,
    7932             :     // and the width is specified.
    7933           0 :     if (mScaleStrEmpty && !mWidthStrEmpty) {
    7934           0 :       CSSToScreenScale defaultScale(float(aDisplaySize.width) / size.width);
    7935           0 :       scaleFloat = (scaleFloat > defaultScale) ? scaleFloat : defaultScale;
    7936             :     }
    7937             : 
    7938           0 :     size.height = clamped(size.height, float(kViewportMinSize.height), float(kViewportMaxSize.height));
    7939             : 
    7940             :     // We need to perform a conversion, but only if the initial or maximum
    7941             :     // scale were set explicitly by the user.
    7942           0 :     if (mValidScaleFloat && scaleFloat >= scaleMinFloat && scaleFloat <= scaleMaxFloat) {
    7943           0 :       CSSSize displaySize = ScreenSize(aDisplaySize) / scaleFloat;
    7944           0 :       size.width = std::max(size.width, displaySize.width);
    7945           0 :       size.height = std::max(size.height, displaySize.height);
    7946           0 :     } else if (effectiveValidMaxScale) {
    7947           0 :       CSSSize displaySize = ScreenSize(aDisplaySize) / scaleMaxFloat;
    7948           0 :       size.width = std::max(size.width, displaySize.width);
    7949           0 :       size.height = std::max(size.height, displaySize.height);
    7950             :     }
    7951             : 
    7952             :     return nsViewportInfo(scaleFloat, scaleMinFloat, scaleMaxFloat, size,
    7953           0 :                           mAutoSize, effectiveAllowZoom);
    7954             :   }
    7955             : }
    7956             : 
    7957             : EventListenerManager*
    7958         182 : nsDocument::GetOrCreateListenerManager()
    7959             : {
    7960         182 :   if (!mListenerManager) {
    7961             :     mListenerManager =
    7962          28 :       new EventListenerManager(static_cast<EventTarget*>(this));
    7963          28 :     SetFlags(NODE_HAS_LISTENERMANAGER);
    7964             :   }
    7965             : 
    7966         182 :   return mListenerManager;
    7967             : }
    7968             : 
    7969             : EventListenerManager*
    7970         562 : nsDocument::GetExistingListenerManager() const
    7971             : {
    7972         562 :   return mListenerManager;
    7973             : }
    7974             : 
    7975             : nsresult
    7976         388 : nsDocument::GetEventTargetParent(EventChainPreVisitor& aVisitor)
    7977             : {
    7978         559 :   if (mDocGroup && aVisitor.mEvent->mMessage != eVoidEvent &&
    7979         171 :       !mIgnoreDocGroupMismatches) {
    7980         168 :     mDocGroup->ValidateAccess();
    7981             :   }
    7982             : 
    7983         388 :   aVisitor.mCanHandle = true;
    7984             :    // FIXME! This is a hack to make middle mouse paste working also in Editor.
    7985             :    // Bug 329119
    7986         388 :   aVisitor.mForceContentDispatch = true;
    7987             : 
    7988             :   // Load events must not propagate to |window| object, see bug 335251.
    7989         388 :   if (aVisitor.mEvent->mMessage != eLoad) {
    7990         319 :     nsGlobalWindow* window = nsGlobalWindow::Cast(GetWindow());
    7991         319 :     aVisitor.mParentTarget =
    7992         319 :       window ? window->GetTargetForEventTargetChain() : nullptr;
    7993             :   }
    7994         388 :   return NS_OK;
    7995             : }
    7996             : 
    7997             : NS_IMETHODIMP
    7998         124 : nsDocument::CreateEvent(const nsAString& aEventType, nsIDOMEvent** aReturn)
    7999             : {
    8000         124 :   NS_ENSURE_ARG_POINTER(aReturn);
    8001         248 :   ErrorResult rv;
    8002         248 :   *aReturn = nsIDocument::CreateEvent(aEventType, CallerType::System,
    8003         124 :                                       rv).take();
    8004         124 :   return rv.StealNSResult();
    8005             : }
    8006             : 
    8007             : already_AddRefed<Event>
    8008         127 : nsIDocument::CreateEvent(const nsAString& aEventType, CallerType aCallerType,
    8009             :                          ErrorResult& rv) const
    8010             : {
    8011         127 :   nsIPresShell *shell = GetShell();
    8012             : 
    8013         127 :   nsPresContext *presContext = nullptr;
    8014             : 
    8015         127 :   if (shell) {
    8016             :     // Retrieve the context
    8017         119 :     presContext = shell->GetPresContext();
    8018             :   }
    8019             : 
    8020             :   // Create event even without presContext.
    8021             :   RefPtr<Event> ev =
    8022         254 :     EventDispatcher::CreateEvent(const_cast<nsIDocument*>(this), presContext,
    8023         254 :                                  nullptr, aEventType, aCallerType);
    8024         127 :   if (!ev) {
    8025           0 :     rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
    8026           0 :     return nullptr;
    8027             :   }
    8028         127 :   WidgetEvent* e = ev->WidgetEventPtr();
    8029         127 :   e->mFlags.mBubbles = false;
    8030         127 :   e->mFlags.mCancelable = false;
    8031         127 :   return ev.forget();
    8032             : }
    8033             : 
    8034             : void
    8035         594 : nsDocument::FlushPendingNotifications(FlushType aType)
    8036             : {
    8037         615 :   nsDocumentOnStack dos(this);
    8038             : 
    8039             :   // We need to flush the sink for non-HTML documents (because the XML
    8040             :   // parser still does insertion with deferred notifications).  We
    8041             :   // also need to flush the sink if this is a layout-related flush, to
    8042             :   // make sure that layout is started as needed.  But we can skip that
    8043             :   // part if we have no presshell or if it's already done an initial
    8044             :   // reflow.
    8045        1245 :   if ((!IsHTMLDocument() ||
    8046          65 :        (aType > FlushType::ContentAndNotify && mPresShell &&
    8047        1192 :         !mPresShell->DidInitialize())) &&
    8048        1076 :       (mParser || mWeakSink)) {
    8049         114 :     nsCOMPtr<nsIContentSink> sink;
    8050          57 :     if (mParser) {
    8051           0 :       sink = mParser->GetContentSink();
    8052             :     } else {
    8053          57 :       sink = do_QueryReferent(mWeakSink);
    8054          57 :       if (!sink) {
    8055           0 :         mWeakSink = nullptr;
    8056             :       }
    8057             :     }
    8058             :     // Determine if it is safe to flush the sink notifications
    8059             :     // by determining if it safe to flush all the presshells.
    8060          57 :     if (sink && (aType == FlushType::Content || IsSafeToFlush())) {
    8061          57 :       sink->FlushPendingNotifications(aType);
    8062             :     }
    8063             :   }
    8064             : 
    8065             :   // Should we be flushing pending binding constructors in here?
    8066             : 
    8067         594 :   if (aType <= FlushType::ContentAndNotify) {
    8068             :     // Nothing to do here
    8069         573 :     return;
    8070             :   }
    8071             : 
    8072             :   // If we have a parent we must flush the parent too to ensure that our
    8073             :   // container is reflowed if its size was changed.  But if it's not safe to
    8074             :   // flush ourselves, then don't flush the parent, since that can cause things
    8075             :   // like resizes of our frame's widget, which we can't handle while flushing
    8076             :   // is unsafe.
    8077             :   // Since media queries mean that a size change of our container can
    8078             :   // affect style, we need to promote a style flush on ourself to a
    8079             :   // layout flush on our parent, since we need our container to be the
    8080             :   // correct size to determine the correct style.
    8081          21 :   if (mParentDocument && IsSafeToFlush()) {
    8082           1 :     FlushType parentType = aType;
    8083           1 :     if (aType >= FlushType::Style)
    8084           1 :       parentType = std::max(FlushType::Layout, aType);
    8085           1 :     mParentDocument->FlushPendingNotifications(parentType);
    8086             :   }
    8087             : 
    8088          21 :   if (nsIPresShell* shell = GetShell()) {
    8089          19 :     shell->FlushPendingNotifications(aType);
    8090             :   }
    8091             : }
    8092             : 
    8093             : static bool
    8094           0 : Copy(nsIDocument* aDocument, void* aData)
    8095             : {
    8096             :   nsTArray<nsCOMPtr<nsIDocument> >* resources =
    8097           0 :     static_cast<nsTArray<nsCOMPtr<nsIDocument> >* >(aData);
    8098           0 :   resources->AppendElement(aDocument);
    8099           0 :   return true;
    8100             : }
    8101             : 
    8102             : void
    8103         122 : nsDocument::FlushExternalResources(FlushType aType)
    8104             : {
    8105         122 :   NS_ASSERTION(aType >= FlushType::Style,
    8106             :     "should only need to flush for style or higher in external resources");
    8107         122 :   if (GetDisplayDocument()) {
    8108           0 :     return;
    8109             :   }
    8110         244 :   nsTArray<nsCOMPtr<nsIDocument> > resources;
    8111         122 :   EnumerateExternalResources(Copy, &resources);
    8112             : 
    8113         122 :   for (uint32_t i = 0; i < resources.Length(); i++) {
    8114           0 :     resources[i]->FlushPendingNotifications(aType);
    8115             :   }
    8116             : }
    8117             : 
    8118             : void
    8119           4 : nsDocument::SetXMLDeclaration(const char16_t *aVersion,
    8120             :                               const char16_t *aEncoding,
    8121             :                               const int32_t aStandalone)
    8122             : {
    8123           4 :   if (!aVersion || *aVersion == '\0') {
    8124           0 :     mXMLDeclarationBits = 0;
    8125           0 :     return;
    8126             :   }
    8127             : 
    8128           4 :   mXMLDeclarationBits = XML_DECLARATION_BITS_DECLARATION_EXISTS;
    8129             : 
    8130           4 :   if (aEncoding && *aEncoding != '\0') {
    8131           3 :     mXMLDeclarationBits |= XML_DECLARATION_BITS_ENCODING_EXISTS;
    8132             :   }
    8133             : 
    8134           4 :   if (aStandalone == 1) {
    8135           0 :     mXMLDeclarationBits |= XML_DECLARATION_BITS_STANDALONE_EXISTS |
    8136           0 :                            XML_DECLARATION_BITS_STANDALONE_YES;
    8137             :   }
    8138           4 :   else if (aStandalone == 0) {
    8139           0 :     mXMLDeclarationBits |= XML_DECLARATION_BITS_STANDALONE_EXISTS;
    8140             :   }
    8141             : }
    8142             : 
    8143             : void
    8144           0 : nsDocument::GetXMLDeclaration(nsAString& aVersion, nsAString& aEncoding,
    8145             :                               nsAString& aStandalone)
    8146             : {
    8147           0 :   aVersion.Truncate();
    8148           0 :   aEncoding.Truncate();
    8149           0 :   aStandalone.Truncate();
    8150             : 
    8151           0 :   if (!(mXMLDeclarationBits & XML_DECLARATION_BITS_DECLARATION_EXISTS)) {
    8152           0 :     return;
    8153             :   }
    8154             : 
    8155             :   // always until we start supporting 1.1 etc.
    8156           0 :   aVersion.AssignLiteral("1.0");
    8157             : 
    8158           0 :   if (mXMLDeclarationBits & XML_DECLARATION_BITS_ENCODING_EXISTS) {
    8159             :     // This is what we have stored, not necessarily what was written
    8160             :     // in the original
    8161           0 :     GetCharacterSet(aEncoding);
    8162             :   }
    8163             : 
    8164           0 :   if (mXMLDeclarationBits & XML_DECLARATION_BITS_STANDALONE_EXISTS) {
    8165           0 :     if (mXMLDeclarationBits & XML_DECLARATION_BITS_STANDALONE_YES) {
    8166           0 :       aStandalone.AssignLiteral("yes");
    8167             :     } else {
    8168           0 :       aStandalone.AssignLiteral("no");
    8169             :     }
    8170             :   }
    8171             : }
    8172             : 
    8173             : bool
    8174          18 : nsDocument::IsScriptEnabled()
    8175             : {
    8176             :   // If this document is sandboxed without 'allow-scripts'
    8177             :   // script is not enabled
    8178          18 :   if (HasScriptsBlockedBySandbox()) {
    8179           0 :     return false;
    8180             :   }
    8181             : 
    8182          36 :   nsCOMPtr<nsIScriptGlobalObject> globalObject = do_QueryInterface(GetInnerWindow());
    8183          18 :   if (!globalObject || !globalObject->GetGlobalJSObject()) {
    8184           2 :     return false;
    8185             :   }
    8186             : 
    8187          16 :   return xpc::Scriptability::Get(globalObject->GetGlobalJSObject()).Allowed();
    8188             : }
    8189             : 
    8190             : nsRadioGroupStruct*
    8191           0 : nsDocument::GetRadioGroup(const nsAString& aName) const
    8192             : {
    8193           0 :   nsRadioGroupStruct* radioGroup = nullptr;
    8194           0 :   mRadioGroups.Get(aName, &radioGroup);
    8195           0 :   return radioGroup;
    8196             : }
    8197             : 
    8198             : nsRadioGroupStruct*
    8199           0 : nsDocument::GetOrCreateRadioGroup(const nsAString& aName)
    8200             : {
    8201           0 :   return mRadioGroups.LookupForAdd(aName).OrInsert(
    8202           0 :     [] () { return new nsRadioGroupStruct(); });
    8203             : }
    8204             : 
    8205             : void
    8206           0 : nsDocument::SetCurrentRadioButton(const nsAString& aName,
    8207             :                                   HTMLInputElement* aRadio)
    8208             : {
    8209           0 :   nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName);
    8210           0 :   radioGroup->mSelectedRadioButton = aRadio;
    8211           0 : }
    8212             : 
    8213             : HTMLInputElement*
    8214           0 : nsDocument::GetCurrentRadioButton(const nsAString& aName)
    8215             : {
    8216           0 :   return GetOrCreateRadioGroup(aName)->mSelectedRadioButton;
    8217             : }
    8218             : 
    8219             : NS_IMETHODIMP
    8220           0 : nsDocument::GetNextRadioButton(const nsAString& aName,
    8221             :                                const bool aPrevious,
    8222             :                                HTMLInputElement* aFocusedRadio,
    8223             :                                HTMLInputElement** aRadioOut)
    8224             : {
    8225             :   // XXX Can we combine the HTML radio button method impls of
    8226             :   //     nsDocument and nsHTMLFormControl?
    8227             :   // XXX Why is HTML radio button stuff in nsDocument, as
    8228             :   //     opposed to nsHTMLDocument?
    8229           0 :   *aRadioOut = nullptr;
    8230             : 
    8231           0 :   nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName);
    8232             : 
    8233             :   // Return the radio button relative to the focused radio button.
    8234             :   // If no radio is focused, get the radio relative to the selected one.
    8235           0 :   RefPtr<HTMLInputElement> currentRadio;
    8236           0 :   if (aFocusedRadio) {
    8237           0 :     currentRadio = aFocusedRadio;
    8238             :   }
    8239             :   else {
    8240           0 :     currentRadio = radioGroup->mSelectedRadioButton;
    8241           0 :     if (!currentRadio) {
    8242           0 :       return NS_ERROR_FAILURE;
    8243             :     }
    8244             :   }
    8245           0 :   int32_t index = radioGroup->mRadioButtons.IndexOf(currentRadio);
    8246           0 :   if (index < 0) {
    8247           0 :     return NS_ERROR_FAILURE;
    8248             :   }
    8249             : 
    8250           0 :   int32_t numRadios = radioGroup->mRadioButtons.Count();
    8251           0 :   RefPtr<HTMLInputElement> radio;
    8252           0 :   do {
    8253           0 :     if (aPrevious) {
    8254           0 :       if (--index < 0) {
    8255           0 :         index = numRadios -1;
    8256             :       }
    8257             :     }
    8258           0 :     else if (++index >= numRadios) {
    8259           0 :       index = 0;
    8260             :     }
    8261           0 :     NS_ASSERTION(static_cast<nsGenericHTMLFormElement*>(radioGroup->mRadioButtons[index])->IsHTMLElement(nsGkAtoms::input),
    8262             :                  "mRadioButtons holding a non-radio button");
    8263           0 :     radio = static_cast<HTMLInputElement*>(radioGroup->mRadioButtons[index]);
    8264           0 :   } while (radio->Disabled() && radio != currentRadio);
    8265             : 
    8266           0 :   radio.forget(aRadioOut);
    8267           0 :   return NS_OK;
    8268             : }
    8269             : 
    8270             : void
    8271           0 : nsDocument::AddToRadioGroup(const nsAString& aName,
    8272             :                             nsIFormControl* aRadio)
    8273             : {
    8274           0 :   nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName);
    8275           0 :   radioGroup->mRadioButtons.AppendObject(aRadio);
    8276             : 
    8277           0 :   nsCOMPtr<nsIContent> element = do_QueryInterface(aRadio);
    8278           0 :   NS_ASSERTION(element, "radio controls have to be content elements");
    8279           0 :   if (element->HasAttr(kNameSpaceID_None, nsGkAtoms::required)) {
    8280           0 :     radioGroup->mRequiredRadioCount++;
    8281             :   }
    8282           0 : }
    8283             : 
    8284             : void
    8285           0 : nsDocument::RemoveFromRadioGroup(const nsAString& aName,
    8286             :                                  nsIFormControl* aRadio)
    8287             : {
    8288           0 :   nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName);
    8289           0 :   radioGroup->mRadioButtons.RemoveObject(aRadio);
    8290             : 
    8291           0 :   nsCOMPtr<nsIContent> element = do_QueryInterface(aRadio);
    8292           0 :   NS_ASSERTION(element, "radio controls have to be content elements");
    8293           0 :   if (element->HasAttr(kNameSpaceID_None, nsGkAtoms::required)) {
    8294           0 :     NS_ASSERTION(radioGroup->mRequiredRadioCount != 0,
    8295             :                  "mRequiredRadioCount about to wrap below 0!");
    8296           0 :     radioGroup->mRequiredRadioCount--;
    8297             :   }
    8298           0 : }
    8299             : 
    8300             : NS_IMETHODIMP
    8301           0 : nsDocument::WalkRadioGroup(const nsAString& aName,
    8302             :                            nsIRadioVisitor* aVisitor,
    8303             :                            bool aFlushContent)
    8304             : {
    8305           0 :   nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName);
    8306             : 
    8307           0 :   for (int i = 0; i < radioGroup->mRadioButtons.Count(); i++) {
    8308           0 :     if (!aVisitor->Visit(radioGroup->mRadioButtons[i])) {
    8309           0 :       return NS_OK;
    8310             :     }
    8311             :   }
    8312             : 
    8313           0 :   return NS_OK;
    8314             : }
    8315             : 
    8316             : uint32_t
    8317           0 : nsDocument::GetRequiredRadioCount(const nsAString& aName) const
    8318             : {
    8319           0 :   nsRadioGroupStruct* radioGroup = GetRadioGroup(aName);
    8320           0 :   return radioGroup ? radioGroup->mRequiredRadioCount : 0;
    8321             : }
    8322             : 
    8323             : void
    8324           0 : nsDocument::RadioRequiredWillChange(const nsAString& aName, bool aRequiredAdded)
    8325             : {
    8326           0 :   nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName);
    8327             : 
    8328           0 :   if (aRequiredAdded) {
    8329           0 :     radioGroup->mRequiredRadioCount++;
    8330             :   } else {
    8331           0 :     NS_ASSERTION(radioGroup->mRequiredRadioCount != 0,
    8332             :                  "mRequiredRadioCount about to wrap below 0!");
    8333           0 :     radioGroup->mRequiredRadioCount--;
    8334             :   }
    8335           0 : }
    8336             : 
    8337             : bool
    8338           0 : nsDocument::GetValueMissingState(const nsAString& aName) const
    8339             : {
    8340           0 :   nsRadioGroupStruct* radioGroup = GetRadioGroup(aName);
    8341           0 :   return radioGroup && radioGroup->mGroupSuffersFromValueMissing;
    8342             : }
    8343             : 
    8344             : void
    8345           0 : nsDocument::SetValueMissingState(const nsAString& aName, bool aValue)
    8346             : {
    8347           0 :   nsRadioGroupStruct* radioGroup = GetOrCreateRadioGroup(aName);
    8348           0 :   radioGroup->mGroupSuffersFromValueMissing = aValue;
    8349           0 : }
    8350             : 
    8351             : void
    8352          26 : nsDocument::RetrieveRelevantHeaders(nsIChannel *aChannel)
    8353             : {
    8354          26 :   PRTime modDate = 0;
    8355             :   nsresult rv;
    8356             : 
    8357          52 :   nsCOMPtr<nsIHttpChannel> httpChannel;
    8358          26 :   rv = GetHttpChannelHelper(aChannel, getter_AddRefs(httpChannel));
    8359          26 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    8360           0 :     return;
    8361             :   }
    8362             : 
    8363          26 :   if (httpChannel) {
    8364           2 :     nsAutoCString tmp;
    8365           4 :     rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("last-modified"),
    8366           3 :                                         tmp);
    8367             : 
    8368           1 :     if (NS_SUCCEEDED(rv)) {
    8369             :       PRTime time;
    8370           1 :       PRStatus st = PR_ParseTimeString(tmp.get(), true, &time);
    8371           1 :       if (st == PR_SUCCESS) {
    8372           1 :         modDate = time;
    8373             :       }
    8374             :     }
    8375             : 
    8376             :     // The misspelled key 'referer' is as per the HTTP spec
    8377           4 :     rv = httpChannel->GetRequestHeader(NS_LITERAL_CSTRING("referer"),
    8378           3 :                                        mReferrer);
    8379             : 
    8380             :     static const char *const headers[] = {
    8381             :       "default-style",
    8382             :       "content-style-type",
    8383             :       "content-language",
    8384             :       "content-disposition",
    8385             :       "refresh",
    8386             :       "x-dns-prefetch-control",
    8387             :       "x-frame-options",
    8388             :       "referrer-policy",
    8389             :       // add more http headers if you need
    8390             :       // XXXbz don't add content-location support without reading bug
    8391             :       // 238654 and its dependencies/dups first.
    8392             :       0
    8393             :     };
    8394             : 
    8395           2 :     nsAutoCString headerVal;
    8396           1 :     const char *const *name = headers;
    8397          17 :     while (*name) {
    8398             :       rv =
    8399           8 :         httpChannel->GetResponseHeader(nsDependentCString(*name), headerVal);
    8400           8 :       if (NS_SUCCEEDED(rv) && !headerVal.IsEmpty()) {
    8401           0 :         nsCOMPtr<nsIAtom> key = NS_Atomize(*name);
    8402           0 :         SetHeaderData(key, NS_ConvertASCIItoUTF16(headerVal));
    8403             :       }
    8404           8 :       ++name;
    8405             :     }
    8406             :   } else {
    8407          50 :     nsCOMPtr<nsIFileChannel> fileChannel = do_QueryInterface(aChannel);
    8408          25 :     if (fileChannel) {
    8409          48 :       nsCOMPtr<nsIFile> file;
    8410          24 :       fileChannel->GetFile(getter_AddRefs(file));
    8411          24 :       if (file) {
    8412             :         PRTime msecs;
    8413          24 :         rv = file->GetLastModifiedTime(&msecs);
    8414             : 
    8415          24 :         if (NS_SUCCEEDED(rv)) {
    8416          24 :           modDate = msecs * int64_t(PR_USEC_PER_MSEC);
    8417             :         }
    8418             :       }
    8419             :     } else {
    8420           2 :       nsAutoCString contentDisp;
    8421           1 :       rv = aChannel->GetContentDispositionHeader(contentDisp);
    8422           1 :       if (NS_SUCCEEDED(rv)) {
    8423             :         SetHeaderData(nsGkAtoms::headerContentDisposition,
    8424           0 :                       NS_ConvertASCIItoUTF16(contentDisp));
    8425             :       }
    8426             :     }
    8427             :   }
    8428             : 
    8429          26 :   mLastModified.Truncate();
    8430          26 :   if (modDate != 0) {
    8431          25 :     GetFormattedTimeString(modDate, mLastModified);
    8432             :   }
    8433             : }
    8434             : 
    8435             : already_AddRefed<Element>
    8436         192 : nsDocument::CreateElem(const nsAString& aName, nsIAtom *aPrefix,
    8437             :                        int32_t aNamespaceID, const nsAString* aIs)
    8438             : {
    8439             : #ifdef DEBUG
    8440         384 :   nsAutoString qName;
    8441         192 :   if (aPrefix) {
    8442           0 :     aPrefix->ToString(qName);
    8443           0 :     qName.Append(':');
    8444             :   }
    8445         192 :   qName.Append(aName);
    8446             : 
    8447             :   // Note: "a:b:c" is a valid name in non-namespaces XML, and
    8448             :   // nsDocument::CreateElement can call us with such a name and no prefix,
    8449             :   // which would cause an error if we just used true here.
    8450         192 :   bool nsAware = aPrefix != nullptr || aNamespaceID != GetDefaultNamespaceID();
    8451         192 :   NS_ASSERTION(NS_SUCCEEDED(nsContentUtils::CheckQName(qName, nsAware)),
    8452             :                "Don't pass invalid prefixes to nsDocument::CreateElem, "
    8453             :                "check caller.");
    8454             : #endif
    8455             : 
    8456         384 :   RefPtr<mozilla::dom::NodeInfo> nodeInfo;
    8457         192 :   mNodeInfoManager->GetNodeInfo(aName, aPrefix, aNamespaceID,
    8458             :                                 nsIDOMNode::ELEMENT_NODE,
    8459         384 :                                 getter_AddRefs(nodeInfo));
    8460         192 :   NS_ENSURE_TRUE(nodeInfo, nullptr);
    8461             : 
    8462         384 :   nsCOMPtr<Element> element;
    8463         384 :   nsresult rv = NS_NewElement(getter_AddRefs(element), nodeInfo.forget(),
    8464         192 :                               NOT_FROM_PARSER, aIs);
    8465         192 :   return NS_SUCCEEDED(rv) ? element.forget() : nullptr;
    8466             : }
    8467             : 
    8468             : bool
    8469          58 : nsDocument::IsSafeToFlush() const
    8470             : {
    8471          58 :   nsIPresShell* shell = GetShell();
    8472          58 :   if (!shell)
    8473           1 :     return true;
    8474             : 
    8475          57 :   return shell->IsSafeToFlush();
    8476             : }
    8477             : 
    8478             : void
    8479           0 : nsDocument::Sanitize()
    8480             : {
    8481             :   // Sanitize the document by resetting all password fields and any form
    8482             :   // fields with autocomplete=off to their default values.  We do this now,
    8483             :   // instead of when the presentation is restored, to offer some protection
    8484             :   // in case there is ever an exploit that allows a cached document to be
    8485             :   // accessed from a different document.
    8486             : 
    8487             :   // First locate all input elements, regardless of whether they are
    8488             :   // in a form, and reset the password and autocomplete=off elements.
    8489             : 
    8490           0 :   RefPtr<nsContentList> nodes = GetElementsByTagName(NS_LITERAL_STRING("input"));
    8491             : 
    8492           0 :   nsAutoString value;
    8493             : 
    8494           0 :   uint32_t length = nodes->Length(true);
    8495           0 :   for (uint32_t i = 0; i < length; ++i) {
    8496           0 :     NS_ASSERTION(nodes->Item(i), "null item in node list!");
    8497             : 
    8498           0 :     RefPtr<HTMLInputElement> input = HTMLInputElement::FromContentOrNull(nodes->Item(i));
    8499           0 :     if (!input)
    8500           0 :       continue;
    8501             : 
    8502           0 :     bool resetValue = false;
    8503             : 
    8504           0 :     input->GetAttribute(NS_LITERAL_STRING("autocomplete"), value);
    8505           0 :     if (value.LowerCaseEqualsLiteral("off")) {
    8506           0 :       resetValue = true;
    8507             :     } else {
    8508           0 :       input->GetType(value);
    8509           0 :       if (value.LowerCaseEqualsLiteral("password"))
    8510           0 :         resetValue = true;
    8511             :     }
    8512             : 
    8513           0 :     if (resetValue) {
    8514           0 :       input->Reset();
    8515             :     }
    8516             :   }
    8517             : 
    8518             :   // Now locate all _form_ elements that have autocomplete=off and reset them
    8519           0 :   nodes = GetElementsByTagName(NS_LITERAL_STRING("form"));
    8520             : 
    8521           0 :   length = nodes->Length(true);
    8522           0 :   for (uint32_t i = 0; i < length; ++i) {
    8523           0 :     NS_ASSERTION(nodes->Item(i), "null item in nodelist");
    8524             : 
    8525           0 :     nsCOMPtr<nsIDOMHTMLFormElement> form = do_QueryInterface(nodes->Item(i));
    8526           0 :     if (!form)
    8527           0 :       continue;
    8528             : 
    8529           0 :     nodes->Item(i)->AsElement()->GetAttr(kNameSpaceID_None,
    8530           0 :                                          nsGkAtoms::autocomplete, value);
    8531           0 :     if (value.LowerCaseEqualsLiteral("off"))
    8532           0 :       form->Reset();
    8533             :   }
    8534           0 : }
    8535             : 
    8536             : struct SubDocEnumArgs
    8537             : {
    8538             :   nsIDocument::nsSubDocEnumFunc callback;
    8539             :   void *data;
    8540             : };
    8541             : 
    8542             : void
    8543         269 : nsDocument::EnumerateSubDocuments(nsSubDocEnumFunc aCallback, void *aData)
    8544             : {
    8545         269 :   if (!mSubDocuments) {
    8546         136 :     return;
    8547             :   }
    8548             : 
    8549             :   // PLDHashTable::Iterator can't handle modifications while iterating so we
    8550             :   // copy all entries to an array first before calling any callbacks.
    8551         266 :   AutoTArray<nsCOMPtr<nsIDocument>, 8> subdocs;
    8552         256 :   for (auto iter = mSubDocuments->Iter(); !iter.Done(); iter.Next()) {
    8553         123 :     auto entry = static_cast<SubDocMapEntry*>(iter.Get());
    8554         123 :     nsIDocument* subdoc = entry->mSubDocument;
    8555         123 :     if (subdoc) {
    8556         123 :       subdocs.AppendElement(subdoc);
    8557             :     }
    8558             :   }
    8559         256 :   for (auto subdoc : subdocs) {
    8560         123 :     if (!aCallback(subdoc, aData)) {
    8561           0 :       break;
    8562             :     }
    8563             :   }
    8564             : }
    8565             : 
    8566             : #ifdef DEBUG_bryner
    8567             : #define DEBUG_PAGE_CACHE
    8568             : #endif
    8569             : 
    8570             : bool
    8571           0 : nsDocument::CanSavePresentation(nsIRequest *aNewRequest)
    8572             : {
    8573           0 :   if (EventHandlingSuppressed()) {
    8574           0 :     return false;
    8575             :   }
    8576             : 
    8577             :   // Do not allow suspended windows to be placed in the
    8578             :   // bfcache.  This method is also used to verify a document
    8579             :   // coming out of the bfcache is ok to restore, though.  So
    8580             :   // we only want to block suspend windows that aren't also
    8581             :   // frozen.
    8582           0 :   nsPIDOMWindowInner* win = GetInnerWindow();
    8583           0 :   if (win && win->IsSuspended() && !win->IsFrozen()) {
    8584           0 :     return false;
    8585             :   }
    8586             : 
    8587             :   // Check our event listener manager for unload/beforeunload listeners.
    8588           0 :   nsCOMPtr<EventTarget> piTarget = do_QueryInterface(mScriptGlobalObject);
    8589           0 :   if (piTarget) {
    8590           0 :     EventListenerManager* manager = piTarget->GetExistingListenerManager();
    8591           0 :     if (manager && manager->HasUnloadListeners()) {
    8592           0 :       return false;
    8593             :     }
    8594             :   }
    8595             : 
    8596             :   // Check if we have pending network requests
    8597           0 :   nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup();
    8598           0 :   if (loadGroup) {
    8599           0 :     nsCOMPtr<nsISimpleEnumerator> requests;
    8600           0 :     loadGroup->GetRequests(getter_AddRefs(requests));
    8601             : 
    8602           0 :     bool hasMore = false;
    8603             : 
    8604             :     // We want to bail out if we have any requests other than aNewRequest (or
    8605             :     // in the case when aNewRequest is a part of a multipart response the base
    8606             :     // channel the multipart response is coming in on).
    8607           0 :     nsCOMPtr<nsIChannel> baseChannel;
    8608           0 :     nsCOMPtr<nsIMultiPartChannel> part(do_QueryInterface(aNewRequest));
    8609           0 :     if (part) {
    8610           0 :       part->GetBaseChannel(getter_AddRefs(baseChannel));
    8611             :     }
    8612             : 
    8613           0 :     while (NS_SUCCEEDED(requests->HasMoreElements(&hasMore)) && hasMore) {
    8614           0 :       nsCOMPtr<nsISupports> elem;
    8615           0 :       requests->GetNext(getter_AddRefs(elem));
    8616             : 
    8617           0 :       nsCOMPtr<nsIRequest> request = do_QueryInterface(elem);
    8618           0 :       if (request && request != aNewRequest && request != baseChannel) {
    8619             : #ifdef DEBUG_PAGE_CACHE
    8620             :         nsAutoCString requestName, docSpec;
    8621             :         request->GetName(requestName);
    8622             :         if (mDocumentURI)
    8623             :           mDocumentURI->GetSpec(docSpec);
    8624             : 
    8625             :         printf("document %s has request %s\n",
    8626             :                docSpec.get(), requestName.get());
    8627             : #endif
    8628           0 :         return false;
    8629             :       }
    8630             :     }
    8631             :   }
    8632             : 
    8633             :   // Check if we have active GetUserMedia use
    8634           0 :   if (MediaManager::Exists() && win &&
    8635           0 :       MediaManager::Get()->IsWindowStillActive(win->WindowID())) {
    8636           0 :     return false;
    8637             :   }
    8638             : 
    8639             : #ifdef MOZ_WEBRTC
    8640             :   // Check if we have active PeerConnections
    8641             :   nsCOMPtr<IPeerConnectionManager> pcManager =
    8642           0 :     do_GetService(IPEERCONNECTION_MANAGER_CONTRACTID);
    8643             : 
    8644           0 :   if (pcManager && win) {
    8645             :     bool active;
    8646           0 :     pcManager->HasActivePeerConnection(win->WindowID(), &active);
    8647           0 :     if (active) {
    8648           0 :       return false;
    8649             :     }
    8650             :   }
    8651             : #endif // MOZ_WEBRTC
    8652             : 
    8653             :   // Don't save presentations for documents containing EME content, so that
    8654             :   // CDMs reliably shutdown upon user navigation.
    8655           0 :   if (ContainsEMEContent()) {
    8656           0 :     return false;
    8657             :   }
    8658             : 
    8659             :   // Don't save presentations for documents containing MSE content, to
    8660             :   // reduce memory usage.
    8661           0 :   if (ContainsMSEContent()) {
    8662           0 :     return false;
    8663             :   }
    8664             : 
    8665             :   // Don't save presentation if there are active FlyWeb connections or FlyWeb
    8666             :   // servers.
    8667           0 :   FlyWebService* flyWebService = FlyWebService::GetExisting();
    8668           0 :   if (flyWebService && flyWebService->HasConnectionOrServer(win->WindowID())) {
    8669           0 :     return false;
    8670             :   }
    8671             : 
    8672           0 :   if (mSubDocuments) {
    8673           0 :     for (auto iter = mSubDocuments->Iter(); !iter.Done(); iter.Next()) {
    8674           0 :       auto entry = static_cast<SubDocMapEntry*>(iter.Get());
    8675           0 :       nsIDocument* subdoc = entry->mSubDocument;
    8676             : 
    8677             :       // The aIgnoreRequest we were passed is only for us, so don't pass it on.
    8678           0 :       bool canCache = subdoc ? subdoc->CanSavePresentation(nullptr) : false;
    8679           0 :       if (!canCache) {
    8680           0 :         return false;
    8681             :       }
    8682             :     }
    8683             :   }
    8684             : 
    8685             : 
    8686           0 :   if (win) {
    8687           0 :     auto* globalWindow = nsGlobalWindow::Cast(win);
    8688             : #ifdef MOZ_WEBSPEECH
    8689           0 :     if (globalWindow->HasActiveSpeechSynthesis()) {
    8690           0 :       return false;
    8691             :     }
    8692             : #endif
    8693           0 :     if (globalWindow->HasUsedVR()) {
    8694           0 :       return false;
    8695             :     }
    8696             :   }
    8697             : 
    8698           0 :   return true;
    8699             : }
    8700             : 
    8701             : void
    8702           4 : nsDocument::Destroy()
    8703             : {
    8704             :   // The ContentViewer wants to release the document now.  So, tell our content
    8705             :   // to drop any references to the document so that it can be destroyed.
    8706           4 :   if (mIsGoingAway)
    8707           0 :     return;
    8708             : 
    8709           4 :   mIsGoingAway = true;
    8710             : 
    8711           4 :   SetScriptGlobalObject(nullptr);
    8712           4 :   RemovedFromDocShell();
    8713             : 
    8714           4 :   bool oldVal = mInUnlinkOrDeletion;
    8715           4 :   mInUnlinkOrDeletion = true;
    8716           4 :   uint32_t i, count = mChildren.ChildCount();
    8717           8 :   for (i = 0; i < count; ++i) {
    8718           4 :     mChildren.ChildAt(i)->DestroyContent();
    8719             :   }
    8720           4 :   mInUnlinkOrDeletion = oldVal;
    8721             : 
    8722           4 :   mLayoutHistoryState = nullptr;
    8723             : 
    8724             :   // Shut down our external resource map.  We might not need this for
    8725             :   // leak-fixing if we fix nsDocumentViewer to do cycle-collection, but
    8726             :   // tearing down all those frame trees right now is the right thing to do.
    8727           4 :   mExternalResourceMap.Shutdown();
    8728             : }
    8729             : 
    8730             : void
    8731           8 : nsDocument::RemovedFromDocShell()
    8732             : {
    8733           8 :   if (mRemovedFromDocShell)
    8734           4 :     return;
    8735             : 
    8736           4 :   mRemovedFromDocShell = true;
    8737           4 :   EnumerateActivityObservers(NotifyActivityChanged, nullptr);
    8738             : 
    8739           4 :   uint32_t i, count = mChildren.ChildCount();
    8740           8 :   for (i = 0; i < count; ++i) {
    8741           4 :     mChildren.ChildAt(i)->SaveSubtreeState();
    8742             :   }
    8743             : }
    8744             : 
    8745             : already_AddRefed<nsILayoutHistoryState>
    8746          64 : nsDocument::GetLayoutHistoryState() const
    8747             : {
    8748         128 :   nsCOMPtr<nsILayoutHistoryState> state;
    8749          64 :   if (!mScriptGlobalObject) {
    8750          46 :     state = mLayoutHistoryState;
    8751             :   } else {
    8752          36 :     nsCOMPtr<nsIDocShell> docShell(mDocumentContainer);
    8753          18 :     if (docShell) {
    8754          18 :       docShell->GetLayoutHistoryState(getter_AddRefs(state));
    8755             :     }
    8756             :   }
    8757             : 
    8758         128 :   return state.forget();
    8759             : }
    8760             : 
    8761             : void
    8762           8 : nsDocument::EnsureOnloadBlocker()
    8763             : {
    8764             :   // If mScriptGlobalObject is null, we shouldn't be messing with the loadgroup
    8765             :   // -- it's not ours.
    8766           8 :   if (mOnloadBlockCount != 0 && mScriptGlobalObject) {
    8767           0 :     nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup();
    8768           0 :     if (loadGroup) {
    8769             :       // Check first to see if mOnloadBlocker is in the loadgroup.
    8770           0 :       nsCOMPtr<nsISimpleEnumerator> requests;
    8771           0 :       loadGroup->GetRequests(getter_AddRefs(requests));
    8772             : 
    8773           0 :       bool hasMore = false;
    8774           0 :       while (NS_SUCCEEDED(requests->HasMoreElements(&hasMore)) && hasMore) {
    8775           0 :         nsCOMPtr<nsISupports> elem;
    8776           0 :         requests->GetNext(getter_AddRefs(elem));
    8777           0 :         nsCOMPtr<nsIRequest> request = do_QueryInterface(elem);
    8778           0 :         if (request && request == mOnloadBlocker) {
    8779           0 :           return;
    8780             :         }
    8781             :       }
    8782             : 
    8783             :       // Not in the loadgroup, so add it.
    8784           0 :       loadGroup->AddRequest(mOnloadBlocker, nullptr);
    8785             :     }
    8786             :   }
    8787             : }
    8788             : 
    8789             : void
    8790           4 : nsDocument::AsyncBlockOnload()
    8791             : {
    8792           6 :   while (mAsyncOnloadBlockCount) {
    8793           2 :     --mAsyncOnloadBlockCount;
    8794           2 :     BlockOnload();
    8795             :   }
    8796           2 : }
    8797             : 
    8798             : void
    8799         251 : nsDocument::BlockOnload()
    8800             : {
    8801         251 :   if (mDisplayDocument) {
    8802           0 :     mDisplayDocument->BlockOnload();
    8803           0 :     return;
    8804             :   }
    8805             : 
    8806             :   // If mScriptGlobalObject is null, we shouldn't be messing with the loadgroup
    8807             :   // -- it's not ours.
    8808         251 :   if (mOnloadBlockCount == 0 && mScriptGlobalObject) {
    8809          15 :     if (!nsContentUtils::IsSafeToRunScript()) {
    8810             :       // Because AddRequest may lead to OnStateChange calls in chrome,
    8811             :       // block onload only when there are no script blockers.
    8812           2 :       ++mAsyncOnloadBlockCount;
    8813           2 :       if (mAsyncOnloadBlockCount == 1) {
    8814           4 :         nsContentUtils::AddScriptRunner(NewRunnableMethod(
    8815           2 :           "nsDocument::AsyncBlockOnload", this, &nsDocument::AsyncBlockOnload));
    8816             :       }
    8817           2 :       return;
    8818             :     }
    8819          26 :     nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup();
    8820          13 :     if (loadGroup) {
    8821          13 :       loadGroup->AddRequest(mOnloadBlocker, nullptr);
    8822             :     }
    8823             :   }
    8824         249 :   ++mOnloadBlockCount;
    8825             : }
    8826             : 
    8827             : void
    8828         249 : nsDocument::UnblockOnload(bool aFireSync)
    8829             : {
    8830         249 :   if (mDisplayDocument) {
    8831           0 :     mDisplayDocument->UnblockOnload(aFireSync);
    8832           0 :     return;
    8833             :   }
    8834             : 
    8835         249 :   if (mOnloadBlockCount == 0 && mAsyncOnloadBlockCount == 0) {
    8836           0 :     NS_NOTREACHED("More UnblockOnload() calls than BlockOnload() calls; dropping call");
    8837           0 :     return;
    8838             :   }
    8839             : 
    8840         249 :   --mOnloadBlockCount;
    8841             : 
    8842         249 :   if (mOnloadBlockCount == 0) {
    8843          36 :     if (mScriptGlobalObject) {
    8844             :       // Only manipulate the loadgroup in this case, because if mScriptGlobalObject
    8845             :       // is null, it's not ours.
    8846          14 :       if (aFireSync && mAsyncOnloadBlockCount == 0) {
    8847             :         // Increment mOnloadBlockCount, since DoUnblockOnload will decrement it
    8848           4 :         ++mOnloadBlockCount;
    8849           4 :         DoUnblockOnload();
    8850             :       } else {
    8851          10 :         PostUnblockOnloadEvent();
    8852             :       }
    8853          22 :     } else if (mIsBeingUsedAsImage) {
    8854             :       // To correctly unblock onload for a document that contains an SVG
    8855             :       // image, we need to know when all of the SVG document's resources are
    8856             :       // done loading, in a way comparable to |window.onload|. We fire this
    8857             :       // event to indicate that the SVG should be considered fully loaded.
    8858             :       // Because scripting is disabled on SVG-as-image documents, this event
    8859             :       // is not accessible to content authors. (See bug 837315.)
    8860             :       RefPtr<AsyncEventDispatcher> asyncDispatcher =
    8861             :         new AsyncEventDispatcher(this,
    8862          42 :                                  NS_LITERAL_STRING("MozSVGAsImageDocumentLoad"),
    8863             :                                  false,
    8864          63 :                                  false);
    8865          21 :       asyncDispatcher->PostDOMEvent();
    8866             :     }
    8867             :   }
    8868             : }
    8869             : 
    8870          30 : class nsUnblockOnloadEvent : public Runnable {
    8871             : public:
    8872          10 :   explicit nsUnblockOnloadEvent(nsDocument* aDoc)
    8873          10 :     : mozilla::Runnable("nsUnblockOnloadEvent")
    8874          10 :     , mDoc(aDoc)
    8875             :   {
    8876          10 :   }
    8877          10 :   NS_IMETHOD Run() override {
    8878          10 :     mDoc->DoUnblockOnload();
    8879          10 :     return NS_OK;
    8880             :   }
    8881             : private:
    8882             :   RefPtr<nsDocument> mDoc;
    8883             : };
    8884             : 
    8885             : void
    8886          10 : nsDocument::PostUnblockOnloadEvent()
    8887             : {
    8888          10 :   MOZ_RELEASE_ASSERT(NS_IsMainThread());
    8889          20 :   nsCOMPtr<nsIRunnable> evt = new nsUnblockOnloadEvent(this);
    8890             :   nsresult rv =
    8891          10 :     Dispatch("nsUnblockOnloadEvent", TaskCategory::Other, evt.forget());
    8892          10 :   if (NS_SUCCEEDED(rv)) {
    8893             :     // Stabilize block count so we don't post more events while this one is up
    8894          10 :     ++mOnloadBlockCount;
    8895             :   } else {
    8896           0 :     NS_WARNING("failed to dispatch nsUnblockOnloadEvent");
    8897             :   }
    8898          10 : }
    8899             : 
    8900             : void
    8901          14 : nsDocument::DoUnblockOnload()
    8902             : {
    8903          14 :   NS_PRECONDITION(!mDisplayDocument,
    8904             :                   "Shouldn't get here for resource document");
    8905          14 :   NS_PRECONDITION(mOnloadBlockCount != 0,
    8906             :                   "Shouldn't have a count of zero here, since we stabilized in "
    8907             :                   "PostUnblockOnloadEvent");
    8908             : 
    8909          14 :   --mOnloadBlockCount;
    8910             : 
    8911          14 :   if (mOnloadBlockCount != 0) {
    8912             :     // We blocked again after the last unblock.  Nothing to do here.  We'll
    8913             :     // post a new event when we unblock again.
    8914           1 :     return;
    8915             :   }
    8916             : 
    8917          13 :   if (mAsyncOnloadBlockCount != 0) {
    8918             :     // We need to wait until the async onload block has been handled.
    8919           0 :     PostUnblockOnloadEvent();
    8920             :   }
    8921             : 
    8922             :   // If mScriptGlobalObject is null, we shouldn't be messing with the loadgroup
    8923             :   // -- it's not ours.
    8924          13 :   if (mScriptGlobalObject) {
    8925          18 :     nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup();
    8926           9 :     if (loadGroup) {
    8927           9 :       loadGroup->RemoveRequest(mOnloadBlocker, nullptr, NS_OK);
    8928             :     }
    8929             :   }
    8930             : }
    8931             : 
    8932             : nsIContent*
    8933           0 : nsDocument::GetContentInThisDocument(nsIFrame* aFrame) const
    8934             : {
    8935           0 :   for (nsIFrame* f = aFrame; f;
    8936             :        f = nsLayoutUtils::GetParentOrPlaceholderForCrossDoc(f)) {
    8937           0 :     nsIContent* content = f->GetContent();
    8938           0 :     if (!content || content->IsInAnonymousSubtree())
    8939           0 :       continue;
    8940             : 
    8941           0 :     if (content->OwnerDoc() == this) {
    8942           0 :       return content;
    8943             :     }
    8944             :     // We must be in a subdocument so jump directly to the root frame.
    8945             :     // GetParentOrPlaceholderForCrossDoc gets called immediately to jump up to
    8946             :     // the containing document.
    8947           0 :     f = f->PresContext()->GetPresShell()->GetRootFrame();
    8948             :   }
    8949             : 
    8950           0 :   return nullptr;
    8951             : }
    8952             : 
    8953             : void
    8954           9 : nsDocument::DispatchPageTransition(EventTarget* aDispatchTarget,
    8955             :                                    const nsAString& aType,
    8956             :                                    bool aPersisted)
    8957             : {
    8958           9 :   if (!aDispatchTarget) {
    8959           0 :     return;
    8960             :   }
    8961             : 
    8962           9 :   PageTransitionEventInit init;
    8963           9 :   init.mBubbles = true;
    8964           9 :   init.mCancelable = true;
    8965           9 :   init.mPersisted = aPersisted;
    8966             : 
    8967             :   RefPtr<PageTransitionEvent> event =
    8968          18 :     PageTransitionEvent::Constructor(this, aType, init);
    8969             : 
    8970           9 :   event->SetTrusted(true);
    8971           9 :   event->SetTarget(this);
    8972             :   EventDispatcher::DispatchDOMEvent(aDispatchTarget, nullptr, event,
    8973           9 :                                     nullptr, nullptr);
    8974             : }
    8975             : 
    8976             : static bool
    8977           0 : NotifyPageShow(nsIDocument* aDocument, void* aData)
    8978             : {
    8979           0 :   const bool* aPersistedPtr = static_cast<const bool*>(aData);
    8980           0 :   aDocument->OnPageShow(*aPersistedPtr, nullptr);
    8981           0 :   return true;
    8982             : }
    8983             : 
    8984             : void
    8985           5 : nsDocument::OnPageShow(bool aPersisted,
    8986             :                        EventTarget* aDispatchStartTarget)
    8987             : {
    8988           5 :   mVisible = true;
    8989             : 
    8990           5 :   EnumerateActivityObservers(NotifyActivityChanged, nullptr);
    8991           5 :   EnumerateExternalResources(NotifyPageShow, &aPersisted);
    8992             : 
    8993           5 :   Element* root = GetRootElement();
    8994           5 :   if (aPersisted && root) {
    8995             :     // Send out notifications that our <link> elements are attached.
    8996           0 :     RefPtr<nsContentList> links = NS_GetContentList(root,
    8997             :                                                       kNameSpaceID_XHTML,
    8998           0 :                                                       NS_LITERAL_STRING("link"));
    8999             : 
    9000           0 :     uint32_t linkCount = links->Length(true);
    9001           0 :     for (uint32_t i = 0; i < linkCount; ++i) {
    9002           0 :       static_cast<HTMLLinkElement*>(links->Item(i, false))->LinkAdded();
    9003             :     }
    9004             :   }
    9005             : 
    9006             :   // See nsIDocument
    9007           5 :   if (!aDispatchStartTarget) {
    9008             :     // Set mIsShowing before firing events, in case those event handlers
    9009             :     // move us around.
    9010           5 :     mIsShowing = true;
    9011             :   }
    9012             : 
    9013           5 :   if (mAnimationController) {
    9014           1 :     mAnimationController->OnPageShow();
    9015             :   }
    9016             : 
    9017           5 :   if (aPersisted) {
    9018           0 :     ImageTracker()->SetAnimatingState(true);
    9019             :   }
    9020             : 
    9021           5 :   UpdateVisibilityState();
    9022             : 
    9023           5 :   if (!mIsBeingUsedAsImage) {
    9024             :     // Dispatch observer notification to notify observers page is shown.
    9025          10 :     nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
    9026           5 :     if (os) {
    9027           5 :       nsIPrincipal *principal = GetPrincipal();
    9028          10 :       os->NotifyObservers(static_cast<nsIDocument*>(this),
    9029           5 :                           nsContentUtils::IsSystemPrincipal(principal) ?
    9030             :                             "chrome-page-shown" :
    9031             :                             "content-page-shown",
    9032          10 :                           nullptr);
    9033             :     }
    9034             : 
    9035          10 :     nsCOMPtr<EventTarget> target = aDispatchStartTarget;
    9036           5 :     if (!target) {
    9037           5 :       target = do_QueryInterface(GetWindow());
    9038             :     }
    9039           5 :     DispatchPageTransition(target, NS_LITERAL_STRING("pageshow"), aPersisted);
    9040             :   }
    9041           5 : }
    9042             : 
    9043             : static bool
    9044           0 : NotifyPageHide(nsIDocument* aDocument, void* aData)
    9045             : {
    9046           0 :   const bool* aPersistedPtr = static_cast<const bool*>(aData);
    9047           0 :   aDocument->OnPageHide(*aPersistedPtr, nullptr);
    9048           0 :   return true;
    9049             : }
    9050             : 
    9051             : static void
    9052           0 : DispatchCustomEventWithFlush(nsINode* aTarget, const nsAString& aEventType,
    9053             :                              bool aBubbles, bool aOnlyChromeDispatch)
    9054             : {
    9055           0 :   RefPtr<Event> event = NS_NewDOMEvent(aTarget, nullptr, nullptr);
    9056           0 :   event->InitEvent(aEventType, aBubbles, false);
    9057           0 :   event->SetTrusted(true);
    9058           0 :   if (aOnlyChromeDispatch) {
    9059           0 :     event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true;
    9060             :   }
    9061           0 :   if (nsIPresShell* shell = aTarget->OwnerDoc()->GetShell()) {
    9062             :     shell->GetPresContext()->
    9063           0 :       RefreshDriver()->ScheduleEventDispatch(aTarget, event);
    9064             :   }
    9065           0 : }
    9066             : 
    9067             : static void
    9068           0 : DispatchFullScreenChange(nsIDocument* aTarget)
    9069             : {
    9070           0 :   DispatchCustomEventWithFlush(
    9071           0 :     aTarget, NS_LITERAL_STRING("fullscreenchange"),
    9072           0 :     /* Bubbles */ true, /* OnlyChrome */ false);
    9073           0 : }
    9074             : 
    9075             : static void ClearPendingFullscreenRequests(nsIDocument* aDoc);
    9076             : 
    9077             : void
    9078           4 : nsDocument::OnPageHide(bool aPersisted,
    9079             :                        EventTarget* aDispatchStartTarget)
    9080             : {
    9081             :   // Send out notifications that our <link> elements are detached,
    9082             :   // but only if this is not a full unload.
    9083           4 :   Element* root = GetRootElement();
    9084           4 :   if (aPersisted && root) {
    9085           0 :     RefPtr<nsContentList> links = NS_GetContentList(root,
    9086             :                                                       kNameSpaceID_XHTML,
    9087           0 :                                                       NS_LITERAL_STRING("link"));
    9088             : 
    9089           0 :     uint32_t linkCount = links->Length(true);
    9090           0 :     for (uint32_t i = 0; i < linkCount; ++i) {
    9091           0 :       static_cast<HTMLLinkElement*>(links->Item(i, false))->LinkRemoved();
    9092             :     }
    9093             :   }
    9094             : 
    9095             :   // See nsIDocument
    9096           4 :   if (!aDispatchStartTarget) {
    9097             :     // Set mIsShowing before firing events, in case those event handlers
    9098             :     // move us around.
    9099           4 :     mIsShowing = false;
    9100             :   }
    9101             : 
    9102           4 :   if (mAnimationController) {
    9103           0 :     mAnimationController->OnPageHide();
    9104             :   }
    9105             : 
    9106             :   // We do not stop the animations (bug 1024343)
    9107             :   // when the page is refreshing while being dragged out
    9108           4 :   nsDocShell* docShell = mDocumentContainer.get();
    9109           4 :   if (aPersisted && !(docShell && docShell->InFrameSwap())) {
    9110           0 :     ImageTracker()->SetAnimatingState(false);
    9111             :   }
    9112             : 
    9113           4 :   ExitPointerLock();
    9114             : 
    9115           4 :   if (!mIsBeingUsedAsImage) {
    9116             :     // Dispatch observer notification to notify observers page is hidden.
    9117           8 :     nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
    9118           4 :     if (os) {
    9119           4 :       nsIPrincipal* principal = GetPrincipal();
    9120           8 :       os->NotifyObservers(static_cast<nsIDocument*>(this),
    9121           4 :                           nsContentUtils::IsSystemPrincipal(principal) ?
    9122             :                             "chrome-page-hidden" :
    9123             :                             "content-page-hidden",
    9124           8 :                           nullptr);
    9125             :     }
    9126             : 
    9127             :     // Now send out a PageHide event.
    9128           8 :     nsCOMPtr<EventTarget> target = aDispatchStartTarget;
    9129           4 :     if (!target) {
    9130           4 :       target = do_QueryInterface(GetWindow());
    9131             :     }
    9132             :     {
    9133           8 :       PageUnloadingEventTimeStamp timeStamp(this);
    9134           4 :       DispatchPageTransition(target, NS_LITERAL_STRING("pagehide"), aPersisted);
    9135             :     }
    9136             :   }
    9137             : 
    9138           4 :   mVisible = false;
    9139             : 
    9140           4 :   UpdateVisibilityState();
    9141             : 
    9142           4 :   EnumerateExternalResources(NotifyPageHide, &aPersisted);
    9143           4 :   EnumerateActivityObservers(NotifyActivityChanged, nullptr);
    9144             : 
    9145           4 :   ClearPendingFullscreenRequests(this);
    9146           4 :   if (GetFullscreenElement()) {
    9147             :     // If this document was fullscreen, we should exit fullscreen in this
    9148             :     // doctree branch. This ensures that if the user navigates while in
    9149             :     // fullscreen mode we don't leave its still visible ancestor documents
    9150             :     // in fullscreen mode. So exit fullscreen in the document's fullscreen
    9151             :     // root document, as this will exit fullscreen in all the root's
    9152             :     // descendant documents. Note that documents are removed from the
    9153             :     // doctree by the time OnPageHide() is called, so we must store a
    9154             :     // reference to the root (in nsDocument::mFullscreenRoot) since we can't
    9155             :     // just traverse the doctree to get the root.
    9156           0 :     nsIDocument::ExitFullscreenInDocTree(this);
    9157             : 
    9158             :     // Since the document is removed from the doctree before OnPageHide() is
    9159             :     // called, ExitFullscreen() can't traverse from the root down to *this*
    9160             :     // document, so we must manually call CleanupFullscreenState() below too.
    9161             :     // Note that CleanupFullscreenState() clears nsDocument::mFullscreenRoot,
    9162             :     // so we *must* call it after ExitFullscreen(), not before.
    9163             :     // OnPageHide() is called in every hidden (i.e. descendant) document,
    9164             :     // so calling CleanupFullscreenState() here will ensure all hidden
    9165             :     // documents have their fullscreen state reset.
    9166           0 :     CleanupFullscreenState();
    9167             : 
    9168             :     // If anyone was listening to this document's state, advertizing the state
    9169             :     // change would be the least of the politeness.
    9170           0 :     DispatchFullScreenChange(this);
    9171             :   }
    9172           4 : }
    9173             : 
    9174             : void
    9175           0 : nsDocument::WillDispatchMutationEvent(nsINode* aTarget)
    9176             : {
    9177           0 :   NS_ASSERTION(mSubtreeModifiedDepth != 0 ||
    9178             :                mSubtreeModifiedTargets.Count() == 0,
    9179             :                "mSubtreeModifiedTargets not cleared after dispatching?");
    9180           0 :   ++mSubtreeModifiedDepth;
    9181           0 :   if (aTarget) {
    9182             :     // MayDispatchMutationEvent is often called just before this method,
    9183             :     // so it has already appended the node to mSubtreeModifiedTargets.
    9184           0 :     int32_t count = mSubtreeModifiedTargets.Count();
    9185           0 :     if (!count || mSubtreeModifiedTargets[count - 1] != aTarget) {
    9186           0 :       mSubtreeModifiedTargets.AppendObject(aTarget);
    9187             :     }
    9188             :   }
    9189           0 : }
    9190             : 
    9191             : void
    9192           0 : nsDocument::MutationEventDispatched(nsINode* aTarget)
    9193             : {
    9194           0 :   --mSubtreeModifiedDepth;
    9195           0 :   if (mSubtreeModifiedDepth == 0) {
    9196           0 :     int32_t count = mSubtreeModifiedTargets.Count();
    9197           0 :     if (!count) {
    9198           0 :       return;
    9199             :     }
    9200             : 
    9201           0 :     nsPIDOMWindowInner* window = GetInnerWindow();
    9202           0 :     if (window &&
    9203           0 :         !window->HasMutationListeners(NS_EVENT_BITS_MUTATION_SUBTREEMODIFIED)) {
    9204           0 :       mSubtreeModifiedTargets.Clear();
    9205           0 :       return;
    9206             :     }
    9207             : 
    9208           0 :     nsCOMArray<nsINode> realTargets;
    9209           0 :     for (int32_t i = 0; i < count; ++i) {
    9210           0 :       nsINode* possibleTarget = mSubtreeModifiedTargets[i];
    9211           0 :       nsCOMPtr<nsIContent> content = do_QueryInterface(possibleTarget);
    9212           0 :       if (content && content->ChromeOnlyAccess()) {
    9213           0 :         continue;
    9214             :       }
    9215             : 
    9216           0 :       nsINode* commonAncestor = nullptr;
    9217           0 :       int32_t realTargetCount = realTargets.Count();
    9218           0 :       for (int32_t j = 0; j < realTargetCount; ++j) {
    9219             :         commonAncestor =
    9220           0 :           nsContentUtils::GetCommonAncestor(possibleTarget, realTargets[j]);
    9221           0 :         if (commonAncestor) {
    9222           0 :           realTargets.ReplaceObjectAt(commonAncestor, j);
    9223           0 :           break;
    9224             :         }
    9225             :       }
    9226           0 :       if (!commonAncestor) {
    9227           0 :         realTargets.AppendObject(possibleTarget);
    9228             :       }
    9229             :     }
    9230             : 
    9231           0 :     mSubtreeModifiedTargets.Clear();
    9232             : 
    9233           0 :     int32_t realTargetCount = realTargets.Count();
    9234           0 :     for (int32_t k = 0; k < realTargetCount; ++k) {
    9235           0 :       InternalMutationEvent mutation(true, eLegacySubtreeModified);
    9236           0 :       (new AsyncEventDispatcher(realTargets[k], mutation))->
    9237           0 :         RunDOMEventWhenSafe();
    9238             :     }
    9239             :   }
    9240             : }
    9241             : 
    9242             : void
    9243           0 : nsDocument::AddStyleRelevantLink(Link* aLink)
    9244             : {
    9245           0 :   NS_ASSERTION(aLink, "Passing in a null link.  Expect crashes RSN!");
    9246             : #ifdef DEBUG
    9247           0 :   nsPtrHashKey<Link>* entry = mStyledLinks.GetEntry(aLink);
    9248           0 :   NS_ASSERTION(!entry, "Document already knows about this Link!");
    9249           0 :   mStyledLinksCleared = false;
    9250             : #endif
    9251           0 :   (void)mStyledLinks.PutEntry(aLink);
    9252           0 : }
    9253             : 
    9254             : void
    9255           0 : nsDocument::ForgetLink(Link* aLink)
    9256             : {
    9257           0 :   NS_ASSERTION(aLink, "Passing in a null link.  Expect crashes RSN!");
    9258             : #ifdef DEBUG
    9259           0 :   nsPtrHashKey<Link>* entry = mStyledLinks.GetEntry(aLink);
    9260           0 :   NS_ASSERTION(entry || mStyledLinksCleared,
    9261             :                "Document knows nothing about this Link!");
    9262             : #endif
    9263           0 :   mStyledLinks.RemoveEntry(aLink);
    9264           0 : }
    9265             : 
    9266             : void
    9267          29 : nsDocument::DestroyElementMaps()
    9268             : {
    9269             : #ifdef DEBUG
    9270          29 :   mStyledLinksCleared = true;
    9271             : #endif
    9272          29 :   mStyledLinks.Clear();
    9273          29 :   mIdentifierMap.Clear();
    9274          29 :   ++mExpandoAndGeneration.generation;
    9275          29 : }
    9276             : 
    9277             : void
    9278          54 : nsDocument::RefreshLinkHrefs()
    9279             : {
    9280             :   // Get a list of all links we know about.  We will reset them, which will
    9281             :   // remove them from the document, so we need a copy of what is in the
    9282             :   // hashtable.
    9283         108 :   LinkArray linksToNotify(mStyledLinks.Count());
    9284          54 :   for (auto iter = mStyledLinks.ConstIter(); !iter.Done(); iter.Next()) {
    9285           0 :     linksToNotify.AppendElement(iter.Get()->GetKey());
    9286             :   }
    9287             : 
    9288             :   // Reset all of our styled links.
    9289         108 :   nsAutoScriptBlocker scriptBlocker;
    9290          54 :   for (LinkArray::size_type i = 0; i < linksToNotify.Length(); i++) {
    9291           0 :     linksToNotify[i]->ResetLinkState(true, linksToNotify[i]->ElementHasHref());
    9292             :   }
    9293          54 : }
    9294             : 
    9295             : nsresult
    9296           0 : nsDocument::CloneDocHelper(nsDocument* clone, bool aPreallocateChildren) const
    9297             : {
    9298           0 :   clone->mIsStaticDocument = mCreatingStaticClone;
    9299             : 
    9300             :   // Init document
    9301           0 :   nsresult rv = clone->Init();
    9302           0 :   NS_ENSURE_SUCCESS(rv, rv);
    9303             : 
    9304           0 :   if (mCreatingStaticClone) {
    9305           0 :     nsCOMPtr<nsILoadGroup> loadGroup;
    9306             : 
    9307             :     // |mDocumentContainer| is the container of the document that is being
    9308             :     // created and not the original container. See CreateStaticClone function().
    9309           0 :     nsCOMPtr<nsIDocumentLoader> docLoader(mDocumentContainer);
    9310           0 :     if (docLoader) {
    9311           0 :       docLoader->GetLoadGroup(getter_AddRefs(loadGroup));
    9312             :     }
    9313           0 :     nsCOMPtr<nsIChannel> channel = GetChannel();
    9314           0 :     nsCOMPtr<nsIURI> uri;
    9315           0 :     if (channel) {
    9316           0 :       NS_GetFinalChannelURI(channel, getter_AddRefs(uri));
    9317             :     } else {
    9318           0 :       uri = nsIDocument::GetDocumentURI();
    9319             :     }
    9320           0 :     clone->mChannel = channel;
    9321           0 :     if (uri) {
    9322           0 :       clone->ResetToURI(uri, loadGroup, NodePrincipal());
    9323             :     }
    9324             : 
    9325           0 :     clone->SetContainer(mDocumentContainer);
    9326             :   }
    9327             : 
    9328             :   // Now ensure that our clone has the same URI, base URI, and principal as us.
    9329             :   // We do this after the mCreatingStaticClone block above, because that block
    9330             :   // can set the base URI to an incorrect value in cases when base URI
    9331             :   // information came from the channel.  So we override explicitly, and do it
    9332             :   // for all these properties, in case ResetToURI messes with any of the rest of
    9333             :   // them.
    9334           0 :   clone->nsDocument::SetDocumentURI(nsIDocument::GetDocumentURI());
    9335           0 :   clone->SetChromeXHRDocURI(mChromeXHRDocURI);
    9336           0 :   clone->SetPrincipal(NodePrincipal());
    9337           0 :   clone->mDocumentBaseURI = mDocumentBaseURI;
    9338           0 :   clone->SetChromeXHRDocBaseURI(mChromeXHRDocBaseURI);
    9339             : 
    9340           0 :   bool hasHadScriptObject = true;
    9341             :   nsIScriptGlobalObject* scriptObject =
    9342           0 :     GetScriptHandlingObject(hasHadScriptObject);
    9343           0 :   NS_ENSURE_STATE(scriptObject || !hasHadScriptObject);
    9344           0 :   if (mCreatingStaticClone) {
    9345             :     // If we're doing a static clone (print, print preview), then we're going to
    9346             :     // be setting a scope object after the clone. It's better to set it only
    9347             :     // once, so we don't do that here. However, we do want to act as if there is
    9348             :     // a script handling object. So we set mHasHadScriptHandlingObject.
    9349           0 :     clone->mHasHadScriptHandlingObject = true;
    9350           0 :   } else if (scriptObject) {
    9351           0 :     clone->SetScriptHandlingObject(scriptObject);
    9352             :   } else {
    9353           0 :     clone->SetScopeObject(GetScopeObject());
    9354             :   }
    9355             :   // Make the clone a data document
    9356           0 :   clone->SetLoadedAsData(true);
    9357             : 
    9358             :   // Misc state
    9359             : 
    9360             :   // State from nsIDocument
    9361           0 :   clone->mCharacterSet = mCharacterSet;
    9362           0 :   clone->mCharacterSetSource = mCharacterSetSource;
    9363           0 :   clone->mCompatMode = mCompatMode;
    9364           0 :   clone->mBidiOptions = mBidiOptions;
    9365           0 :   clone->mContentLanguage = mContentLanguage;
    9366           0 :   clone->SetContentTypeInternal(GetContentTypeInternal());
    9367           0 :   clone->mSecurityInfo = mSecurityInfo;
    9368             : 
    9369             :   // State from nsDocument
    9370           0 :   clone->mType = mType;
    9371           0 :   clone->mXMLDeclarationBits = mXMLDeclarationBits;
    9372           0 :   clone->mBaseTarget = mBaseTarget;
    9373             : 
    9374             :   // Preallocate attributes and child arrays
    9375           0 :   rv = clone->mChildren.EnsureCapacityToClone(mChildren, aPreallocateChildren);
    9376           0 :   NS_ENSURE_SUCCESS(rv, rv);
    9377             : 
    9378           0 :   return NS_OK;
    9379             : }
    9380             : 
    9381             : void
    9382          80 : nsDocument::SetReadyStateInternal(ReadyState rs)
    9383             : {
    9384          80 :   mReadyState = rs;
    9385          80 :   if (rs == READYSTATE_UNINITIALIZED) {
    9386             :     // Transition back to uninitialized happens only to keep assertions happy
    9387             :     // right before readyState transitions to something else. Make this
    9388             :     // transition undetectable by Web content.
    9389           0 :     return;
    9390             :   }
    9391          80 :   if (mTiming) {
    9392          28 :     switch (rs) {
    9393             :       case READYSTATE_LOADING:
    9394           0 :         mTiming->NotifyDOMLoading(nsIDocument::GetDocumentURI());
    9395           0 :         break;
    9396             :       case READYSTATE_INTERACTIVE:
    9397          24 :         mTiming->NotifyDOMInteractive(nsIDocument::GetDocumentURI());
    9398          24 :         break;
    9399             :       case READYSTATE_COMPLETE:
    9400           4 :         mTiming->NotifyDOMComplete(nsIDocument::GetDocumentURI());
    9401           4 :         break;
    9402             :       default:
    9403           0 :         NS_WARNING("Unexpected ReadyState value");
    9404           0 :         break;
    9405             :     }
    9406             :   }
    9407             :   // At the time of loading start, we don't have timing object, record time.
    9408          80 :   if (READYSTATE_LOADING == rs) {
    9409          25 :     mLoadingTimeStamp = mozilla::TimeStamp::Now();
    9410             :   }
    9411             : 
    9412             :   RefPtr<AsyncEventDispatcher> asyncDispatcher =
    9413         160 :     new AsyncEventDispatcher(this, NS_LITERAL_STRING("readystatechange"),
    9414         240 :                              false, false);
    9415          80 :   asyncDispatcher->RunDOMEventWhenSafe();
    9416             : }
    9417             : 
    9418             : NS_IMETHODIMP
    9419           0 : nsDocument::GetReadyState(nsAString& aReadyState)
    9420             : {
    9421           0 :   nsIDocument::GetReadyState(aReadyState);
    9422           0 :   return NS_OK;
    9423             : }
    9424             : 
    9425             : void
    9426          10 : nsIDocument::GetReadyState(nsAString& aReadyState) const
    9427             : {
    9428          10 :   switch(mReadyState) {
    9429             :   case READYSTATE_LOADING :
    9430           0 :     aReadyState.AssignLiteral(u"loading");
    9431           0 :     break;
    9432             :   case READYSTATE_INTERACTIVE :
    9433           0 :     aReadyState.AssignLiteral(u"interactive");
    9434           0 :     break;
    9435             :   case READYSTATE_COMPLETE :
    9436           5 :     aReadyState.AssignLiteral(u"complete");
    9437           5 :     break;
    9438             :   default:
    9439           5 :     aReadyState.AssignLiteral(u"uninitialized");
    9440             :   }
    9441          10 : }
    9442             : 
    9443             : static bool
    9444           0 : SuppressEventHandlingInDocument(nsIDocument* aDocument, void* aData)
    9445             : {
    9446           0 :   aDocument->SuppressEventHandling(*static_cast<uint32_t*>(aData));
    9447             : 
    9448           0 :   return true;
    9449             : }
    9450             : 
    9451             : void
    9452           0 : nsDocument::SuppressEventHandling(uint32_t aIncrease)
    9453             : {
    9454           0 :   mEventsSuppressed += aIncrease;
    9455           0 :   UpdateFrameRequestCallbackSchedulingState();
    9456           0 :   for (uint32_t i = 0; i < aIncrease; ++i) {
    9457           0 :     ScriptLoader()->AddExecuteBlocker();
    9458             :   }
    9459             : 
    9460           0 :   EnumerateSubDocuments(SuppressEventHandlingInDocument, &aIncrease);
    9461           0 : }
    9462             : 
    9463             : static void
    9464           0 : FireOrClearDelayedEvents(nsTArray<nsCOMPtr<nsIDocument> >& aDocuments,
    9465             :                          bool aFireEvents)
    9466             : {
    9467           0 :   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
    9468           0 :   if (!fm)
    9469           0 :     return;
    9470             : 
    9471           0 :   for (uint32_t i = 0; i < aDocuments.Length(); ++i) {
    9472             :     // NB: Don't bother trying to fire delayed events on documents that were
    9473             :     // closed before this event ran.
    9474           0 :     if (!aDocuments[i]->EventHandlingSuppressed()) {
    9475           0 :       fm->FireDelayedEvents(aDocuments[i]);
    9476           0 :       nsCOMPtr<nsIPresShell> shell = aDocuments[i]->GetShell();
    9477           0 :       if (shell) {
    9478             :         // Only fire events for active documents.
    9479           0 :         bool fire = aFireEvents &&
    9480           0 :                     aDocuments[i]->GetInnerWindow() &&
    9481           0 :                     aDocuments[i]->GetInnerWindow()->IsCurrentInnerWindow();
    9482           0 :         shell->FireOrClearDelayedEvents(fire);
    9483             :       }
    9484             :     }
    9485             :   }
    9486             : }
    9487             : 
    9488             : void
    9489           0 : nsDocument::PreloadPictureOpened()
    9490             : {
    9491           0 :   mPreloadPictureDepth++;
    9492           0 : }
    9493             : 
    9494             : void
    9495           0 : nsDocument::PreloadPictureClosed()
    9496             : {
    9497           0 :   mPreloadPictureDepth--;
    9498           0 :   if (mPreloadPictureDepth == 0) {
    9499           0 :     mPreloadPictureFoundSource.SetIsVoid(true);
    9500             :   } else {
    9501           0 :     MOZ_ASSERT(mPreloadPictureDepth >= 0);
    9502             :   }
    9503           0 : }
    9504             : 
    9505             : void
    9506           0 : nsDocument::PreloadPictureImageSource(const nsAString& aSrcsetAttr,
    9507             :                                       const nsAString& aSizesAttr,
    9508             :                                       const nsAString& aTypeAttr,
    9509             :                                       const nsAString& aMediaAttr)
    9510             : {
    9511             :   // Nested pictures are not valid syntax, so while we'll eventually load them,
    9512             :   // it's not worth tracking sources mixed between nesting levels to preload
    9513             :   // them effectively.
    9514           0 :   if (mPreloadPictureDepth == 1 && mPreloadPictureFoundSource.IsVoid()) {
    9515             :     // <picture> selects the first matching source, so if this returns a URI we
    9516             :     // needn't consider new sources until a new <picture> is encountered.
    9517             :     bool found =
    9518           0 :       HTMLImageElement::SelectSourceForTagWithAttrs(this, true, NullString(),
    9519             :                                                     aSrcsetAttr, aSizesAttr,
    9520             :                                                     aTypeAttr, aMediaAttr,
    9521           0 :                                                     mPreloadPictureFoundSource);
    9522           0 :     if (found && mPreloadPictureFoundSource.IsVoid()) {
    9523             :       // Found an empty source, which counts
    9524           0 :       mPreloadPictureFoundSource.SetIsVoid(false);
    9525             :     }
    9526             :   }
    9527           0 : }
    9528             : 
    9529             : already_AddRefed<nsIURI>
    9530           0 : nsDocument::ResolvePreloadImage(nsIURI *aBaseURI,
    9531             :                                 const nsAString& aSrcAttr,
    9532             :                                 const nsAString& aSrcsetAttr,
    9533             :                                 const nsAString& aSizesAttr)
    9534             : {
    9535           0 :   nsString sourceURL;
    9536           0 :   if (mPreloadPictureDepth == 1 && !mPreloadPictureFoundSource.IsVoid()) {
    9537             :     // We're in a <picture> element and found a URI from a source previous to
    9538             :     // this image, use it.
    9539           0 :     sourceURL = mPreloadPictureFoundSource;
    9540             :   } else {
    9541             :     // Otherwise try to use this <img> as a source
    9542           0 :     HTMLImageElement::SelectSourceForTagWithAttrs(this, false, aSrcAttr,
    9543             :                                                   aSrcsetAttr, aSizesAttr,
    9544           0 :                                                   NullString(), NullString(),
    9545           0 :                                                   sourceURL);
    9546             :   }
    9547             : 
    9548             :   // Empty sources are not loaded by <img> (i.e. not resolved to the baseURI)
    9549           0 :   if (sourceURL.IsEmpty()) {
    9550           0 :     return nullptr;
    9551             :   }
    9552             : 
    9553             :   // Construct into URI using passed baseURI (the parser may know of base URI
    9554             :   // changes that have not reached us)
    9555             :   nsresult rv;
    9556           0 :   nsCOMPtr<nsIURI> uri;
    9557           0 :   rv = nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(uri), sourceURL,
    9558           0 :                                                  this, aBaseURI);
    9559           0 :   if (NS_FAILED(rv)) {
    9560           0 :     return nullptr;
    9561             :   }
    9562             : 
    9563             :   // We don't clear mPreloadPictureFoundSource because subsequent <img> tags in
    9564             :   // this this <picture> share the same <sources> (though this is not valid per
    9565             :   // spec)
    9566           0 :   return uri.forget();
    9567             : }
    9568             : 
    9569             : void
    9570           0 : nsDocument::MaybePreLoadImage(nsIURI* uri, const nsAString &aCrossOriginAttr,
    9571             :                               ReferrerPolicy aReferrerPolicy)
    9572             : {
    9573             :   // Early exit if the img is already present in the img-cache
    9574             :   // which indicates that the "real" load has already started and
    9575             :   // that we shouldn't preload it.
    9576             :   int16_t blockingStatus;
    9577           0 :   if (nsContentUtils::IsImageInCache(uri, static_cast<nsIDocument *>(this)) ||
    9578           0 :       !nsContentUtils::CanLoadImage(uri, static_cast<nsIDocument *>(this),
    9579             :                                     this, NodePrincipal(), &blockingStatus,
    9580             :                                     nsIContentPolicy::TYPE_INTERNAL_IMAGE_PRELOAD)) {
    9581           0 :     return;
    9582             :   }
    9583             : 
    9584           0 :   nsLoadFlags loadFlags = nsIRequest::LOAD_NORMAL;
    9585           0 :   switch (Element::StringToCORSMode(aCrossOriginAttr)) {
    9586             :   case CORS_NONE:
    9587             :     // Nothing to do
    9588           0 :     break;
    9589             :   case CORS_ANONYMOUS:
    9590           0 :     loadFlags |= imgILoader::LOAD_CORS_ANONYMOUS;
    9591           0 :     break;
    9592             :   case CORS_USE_CREDENTIALS:
    9593           0 :     loadFlags |= imgILoader::LOAD_CORS_USE_CREDENTIALS;
    9594           0 :     break;
    9595             :   default:
    9596           0 :     MOZ_CRASH("Unknown CORS mode!");
    9597             :   }
    9598             : 
    9599             :   // Image not in cache - trigger preload
    9600           0 :   RefPtr<imgRequestProxy> request;
    9601             :   nsresult rv =
    9602           0 :     nsContentUtils::LoadImage(uri,
    9603             :                               static_cast<nsINode*>(this),
    9604             :                               this,
    9605             :                               NodePrincipal(),
    9606             :                               mDocumentURI, // uri of document used as referrer
    9607             :                               aReferrerPolicy,
    9608             :                               nullptr,       // no observer
    9609             :                               loadFlags,
    9610           0 :                               NS_LITERAL_STRING("img"),
    9611           0 :                               getter_AddRefs(request),
    9612           0 :                               nsIContentPolicy::TYPE_INTERNAL_IMAGE_PRELOAD);
    9613             : 
    9614             :   // Pin image-reference to avoid evicting it from the img-cache before
    9615             :   // the "real" load occurs. Unpinned in DispatchContentLoadedEvents and
    9616             :   // unlink
    9617           0 :   if (NS_SUCCEEDED(rv)) {
    9618           0 :     mPreloadingImages.Put(uri, request.forget());
    9619             :   }
    9620             : }
    9621             : 
    9622             : void
    9623           0 : nsDocument::MaybePreconnect(nsIURI* aOrigURI, mozilla::CORSMode aCORSMode)
    9624             : {
    9625           0 :   nsCOMPtr<nsIURI> uri;
    9626           0 :   if (NS_FAILED(aOrigURI->Clone(getter_AddRefs(uri)))) {
    9627           0 :       return;
    9628             :   }
    9629             : 
    9630             :   // The URI created here is used in 2 contexts. One is nsISpeculativeConnect
    9631             :   // which ignores the path and uses only the origin. The other is for the
    9632             :   // document mPreloadedPreconnects de-duplication hash. Anonymous vs
    9633             :   // non-Anonymous preconnects create different connections on the wire and
    9634             :   // therefore should not be considred duplicates of each other and we
    9635             :   // normalize the path before putting it in the hash to accomplish that.
    9636             : 
    9637           0 :   if (aCORSMode == CORS_ANONYMOUS) {
    9638           0 :     uri->SetPath(NS_LITERAL_CSTRING("/anonymous"));
    9639             :   } else {
    9640           0 :     uri->SetPath(NS_LITERAL_CSTRING("/"));
    9641             :   }
    9642             : 
    9643           0 :   auto entry = mPreloadedPreconnects.LookupForAdd(uri);
    9644           0 :   if (entry) {
    9645           0 :     return; // we found an existing entry
    9646             :   }
    9647           0 :   entry.OrInsert([] () { return true; });
    9648             : 
    9649             :   nsCOMPtr<nsISpeculativeConnect>
    9650           0 :     speculator(do_QueryInterface(nsContentUtils::GetIOService()));
    9651           0 :   if (!speculator) {
    9652           0 :     return;
    9653             :   }
    9654             : 
    9655           0 :   if (aCORSMode == CORS_ANONYMOUS) {
    9656           0 :     speculator->SpeculativeAnonymousConnect2(uri, NodePrincipal(), nullptr);
    9657             :   } else {
    9658           0 :     speculator->SpeculativeConnect2(uri, NodePrincipal(), nullptr);
    9659             :   }
    9660             : }
    9661             : 
    9662             : void
    9663           4 : nsDocument::ForgetImagePreload(nsIURI* aURI)
    9664             : {
    9665             :   // Checking count is faster than hashing the URI in the common
    9666             :   // case of empty table.
    9667           4 :   if (mPreloadingImages.Count() != 0) {
    9668           0 :     nsCOMPtr<imgIRequest> req;
    9669           0 :     mPreloadingImages.Remove(aURI, getter_AddRefs(req));
    9670           0 :     if (req) {
    9671             :       // Make sure to cancel the request so imagelib knows it's gone.
    9672           0 :       req->CancelAndForgetObserver(NS_BINDING_ABORTED);
    9673             :     }
    9674             :   }
    9675           4 : }
    9676             : 
    9677             : void
    9678         693 : nsDocument::UpdatePossiblyStaleDocumentState()
    9679             : {
    9680         693 :   if (!mGotDocumentState.HasState(NS_DOCUMENT_STATE_RTL_LOCALE)) {
    9681           1 :     if (IsDocumentRightToLeft()) {
    9682           0 :       mDocumentState |= NS_DOCUMENT_STATE_RTL_LOCALE;
    9683             :     }
    9684           1 :     mGotDocumentState |= NS_DOCUMENT_STATE_RTL_LOCALE;
    9685             :   }
    9686         693 :   if (!mGotDocumentState.HasState(NS_DOCUMENT_STATE_WINDOW_INACTIVE)) {
    9687           2 :     nsIPresShell* shell = GetShell();
    9688           4 :     if (shell && shell->GetPresContext() &&
    9689           2 :         shell->GetPresContext()->IsTopLevelWindowInactive()) {
    9690           1 :       mDocumentState |= NS_DOCUMENT_STATE_WINDOW_INACTIVE;
    9691             :     }
    9692           2 :     mGotDocumentState |= NS_DOCUMENT_STATE_WINDOW_INACTIVE;
    9693             :   }
    9694         693 : }
    9695             : 
    9696             : EventStates
    9697         693 : nsDocument::ThreadSafeGetDocumentState() const
    9698             : {
    9699         693 :   return mDocumentState;
    9700             : }
    9701             : 
    9702             : EventStates
    9703         693 : nsDocument::GetDocumentState()
    9704             : {
    9705         693 :   UpdatePossiblyStaleDocumentState();
    9706         693 :   return ThreadSafeGetDocumentState();
    9707             : }
    9708             : 
    9709             : namespace {
    9710             : 
    9711             : /**
    9712             :  * Stub for LoadSheet(), since all we want is to get the sheet into
    9713             :  * the CSSLoader's style cache
    9714             :  */
    9715           0 : class StubCSSLoaderObserver final : public nsICSSLoaderObserver {
    9716           0 :   ~StubCSSLoaderObserver() {}
    9717             : public:
    9718             :   NS_IMETHOD
    9719           0 :   StyleSheetLoaded(StyleSheet*, bool, nsresult) override
    9720             :   {
    9721           0 :     return NS_OK;
    9722             :   }
    9723             :   NS_DECL_ISUPPORTS
    9724             : };
    9725           0 : NS_IMPL_ISUPPORTS(StubCSSLoaderObserver, nsICSSLoaderObserver)
    9726             : 
    9727             : } // namespace
    9728             : 
    9729             : void
    9730           0 : nsDocument::PreloadStyle(nsIURI* uri, const nsAString& charset,
    9731             :                          const nsAString& aCrossOriginAttr,
    9732             :                          const ReferrerPolicy aReferrerPolicy,
    9733             :                          const nsAString& aIntegrity)
    9734             : {
    9735             :   // The CSSLoader will retain this object after we return.
    9736           0 :   nsCOMPtr<nsICSSLoaderObserver> obs = new StubCSSLoaderObserver();
    9737             : 
    9738             :   // Charset names are always ASCII.
    9739           0 :   CSSLoader()->LoadSheet(uri, true, NodePrincipal(),
    9740           0 :                          NS_LossyConvertUTF16toASCII(charset),
    9741             :                          obs,
    9742           0 :                          Element::StringToCORSMode(aCrossOriginAttr),
    9743           0 :                          aReferrerPolicy, aIntegrity);
    9744           0 : }
    9745             : 
    9746             : nsresult
    9747           0 : nsDocument::LoadChromeSheetSync(nsIURI* uri, bool isAgentSheet,
    9748             :                                 RefPtr<mozilla::StyleSheet>* aSheet)
    9749             : {
    9750             :   css::SheetParsingMode mode =
    9751           0 :     isAgentSheet ? css::eAgentSheetFeatures
    9752           0 :                  : css::eAuthorSheetFeatures;
    9753           0 :   return CSSLoader()->LoadSheetSync(uri, mode, isAgentSheet, aSheet);
    9754             : }
    9755             : 
    9756             : class nsDelayedEventDispatcher : public Runnable
    9757             : {
    9758             : public:
    9759           0 :   explicit nsDelayedEventDispatcher(nsTArray<nsCOMPtr<nsIDocument>>& aDocuments)
    9760           0 :     : mozilla::Runnable("nsDelayedEventDispatcher")
    9761             :   {
    9762           0 :     mDocuments.SwapElements(aDocuments);
    9763           0 :   }
    9764           0 :   virtual ~nsDelayedEventDispatcher() {}
    9765             : 
    9766           0 :   NS_IMETHOD Run() override
    9767             :   {
    9768           0 :     FireOrClearDelayedEvents(mDocuments, true);
    9769           0 :     return NS_OK;
    9770             :   }
    9771             : 
    9772             : private:
    9773             :   nsTArray<nsCOMPtr<nsIDocument> > mDocuments;
    9774             : };
    9775             : 
    9776             : static bool
    9777           0 : GetAndUnsuppressSubDocuments(nsIDocument* aDocument,
    9778             :                              void* aData)
    9779             : {
    9780           0 :   if (aDocument->EventHandlingSuppressed() > 0) {
    9781           0 :     static_cast<nsDocument*>(aDocument)->DecreaseEventSuppression();
    9782           0 :     aDocument->ScriptLoader()->RemoveExecuteBlocker();
    9783             :   }
    9784             : 
    9785             :   nsTArray<nsCOMPtr<nsIDocument> >* docs =
    9786           0 :     static_cast<nsTArray<nsCOMPtr<nsIDocument> >* >(aData);
    9787             : 
    9788           0 :   docs->AppendElement(aDocument);
    9789           0 :   aDocument->EnumerateSubDocuments(GetAndUnsuppressSubDocuments, aData);
    9790           0 :   return true;
    9791             : }
    9792             : 
    9793             : void
    9794           0 : nsDocument::UnsuppressEventHandlingAndFireEvents(bool aFireEvents)
    9795             : {
    9796           0 :   nsTArray<nsCOMPtr<nsIDocument>> documents;
    9797           0 :   GetAndUnsuppressSubDocuments(this, &documents);
    9798             : 
    9799           0 :   if (aFireEvents) {
    9800           0 :     MOZ_RELEASE_ASSERT(NS_IsMainThread());
    9801           0 :     nsCOMPtr<nsIRunnable> ded = new nsDelayedEventDispatcher(documents);
    9802           0 :     Dispatch("nsDelayedEventDispatcher", TaskCategory::Other, ded.forget());
    9803             :   } else {
    9804           0 :     FireOrClearDelayedEvents(documents, false);
    9805             :   }
    9806           0 : }
    9807             : 
    9808             : nsISupports*
    9809           0 : nsDocument::GetCurrentContentSink()
    9810             : {
    9811           0 :   return mParser ? mParser->GetContentSink() : nullptr;
    9812             : }
    9813             : 
    9814             : nsIDocument*
    9815           0 : nsDocument::GetTemplateContentsOwner()
    9816             : {
    9817           0 :   if (!mTemplateContentsOwner) {
    9818           0 :     bool hasHadScriptObject = true;
    9819             :     nsIScriptGlobalObject* scriptObject =
    9820           0 :       GetScriptHandlingObject(hasHadScriptObject);
    9821             : 
    9822           0 :     nsCOMPtr<nsIDOMDocument> domDocument;
    9823           0 :     nsresult rv = NS_NewDOMDocument(getter_AddRefs(domDocument),
    9824           0 :                                     EmptyString(), // aNamespaceURI
    9825           0 :                                     EmptyString(), // aQualifiedName
    9826             :                                     nullptr, // aDoctype
    9827             :                                     nsIDocument::GetDocumentURI(),
    9828             :                                     nsIDocument::GetDocBaseURI(),
    9829             :                                     NodePrincipal(),
    9830             :                                     true, // aLoadedAsData
    9831             :                                     scriptObject, // aEventObject
    9832           0 :                                     DocumentFlavorHTML);
    9833           0 :     NS_ENSURE_SUCCESS(rv, nullptr);
    9834             : 
    9835           0 :     mTemplateContentsOwner = do_QueryInterface(domDocument);
    9836           0 :     NS_ENSURE_TRUE(mTemplateContentsOwner, nullptr);
    9837             : 
    9838           0 :     nsDocument* doc = static_cast<nsDocument*>(mTemplateContentsOwner.get());
    9839             : 
    9840           0 :     if (!scriptObject) {
    9841           0 :       mTemplateContentsOwner->SetScopeObject(GetScopeObject());
    9842             :     }
    9843             : 
    9844           0 :     doc->mHasHadScriptHandlingObject = hasHadScriptObject;
    9845             : 
    9846             :     // Set |doc| as the template contents owner of itself so that
    9847             :     // |doc| is the template contents owner of template elements created
    9848             :     // by |doc|.
    9849           0 :     doc->mTemplateContentsOwner = doc;
    9850             :   }
    9851             : 
    9852           0 :   return mTemplateContentsOwner;
    9853             : }
    9854             : 
    9855             : void
    9856          25 : nsDocument::SetScrollToRef(nsIURI *aDocumentURI)
    9857             : {
    9858          25 :   if (!aDocumentURI) {
    9859           0 :     return;
    9860             :   }
    9861             : 
    9862          50 :   nsAutoCString ref;
    9863             : 
    9864             :   // Since all URI's that pass through here aren't URL's we can't
    9865             :   // rely on the nsIURI implementation for providing a way for
    9866             :   // finding the 'ref' part of the URI, we'll haveto revert to
    9867             :   // string routines for finding the data past '#'
    9868             : 
    9869          25 :   nsresult rv = aDocumentURI->GetSpec(ref);
    9870          25 :   if (NS_FAILED(rv)) {
    9871           0 :     Unused << aDocumentURI->GetRef(mScrollToRef);
    9872           0 :     return;
    9873             :   }
    9874             : 
    9875          25 :   nsReadingIterator<char> start, end;
    9876             : 
    9877          25 :   ref.BeginReading(start);
    9878          25 :   ref.EndReading(end);
    9879             : 
    9880          25 :   if (FindCharInReadable('#', start, end)) {
    9881           2 :     ++start; // Skip over the '#'
    9882             : 
    9883           2 :     mScrollToRef = Substring(start, end);
    9884             :   }
    9885             : }
    9886             : 
    9887             : void
    9888          30 : nsDocument::ScrollToRef()
    9889             : {
    9890          30 :   if (mScrolledToRefAlready) {
    9891           0 :     nsCOMPtr<nsIPresShell> shell = GetShell();
    9892           0 :     if (shell) {
    9893           0 :       shell->ScrollToAnchor();
    9894             :     }
    9895           0 :     return;
    9896             :   }
    9897             : 
    9898          30 :   if (mScrollToRef.IsEmpty()) {
    9899          28 :     return;
    9900             :   }
    9901             : 
    9902           2 :   char* tmpstr = ToNewCString(mScrollToRef);
    9903           2 :   if (!tmpstr) {
    9904           0 :     return;
    9905             :   }
    9906             : 
    9907           2 :   nsUnescape(tmpstr);
    9908           4 :   nsAutoCString unescapedRef;
    9909           2 :   unescapedRef.Assign(tmpstr);
    9910           2 :   free(tmpstr);
    9911             : 
    9912           2 :   nsresult rv = NS_ERROR_FAILURE;
    9913             :   // We assume that the bytes are in UTF-8, as it says in the spec:
    9914             :   // http://www.w3.org/TR/html4/appendix/notes.html#h-B.2.1
    9915           4 :   NS_ConvertUTF8toUTF16 ref(unescapedRef);
    9916             : 
    9917           4 :   nsCOMPtr<nsIPresShell> shell = GetShell();
    9918           2 :   if (shell) {
    9919             :     // Check an empty string which might be caused by the UTF-8 conversion
    9920           2 :     if (!ref.IsEmpty()) {
    9921             :       // Note that GoToAnchor will handle flushing layout as needed.
    9922           2 :       rv = shell->GoToAnchor(ref, mChangeScrollPosWhenScrollingToRef);
    9923             :     } else {
    9924           0 :       rv = NS_ERROR_FAILURE;
    9925             :     }
    9926             : 
    9927             :     // If UTF-8 URI failed then try to assume the string as a
    9928             :     // document's charset.
    9929             : 
    9930           2 :     if (NS_FAILED(rv)) {
    9931           0 :       auto encoding = GetDocumentCharacterSet();
    9932             : 
    9933           0 :       rv = encoding->DecodeWithoutBOMHandling(unescapedRef, ref);
    9934             : 
    9935           0 :       if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) {
    9936           0 :         rv = shell->GoToAnchor(ref, mChangeScrollPosWhenScrollingToRef);
    9937             :       }
    9938             :     }
    9939           2 :     if (NS_SUCCEEDED(rv)) {
    9940           2 :       mScrolledToRefAlready = true;
    9941             :     }
    9942             :   }
    9943             : }
    9944             : 
    9945             : void
    9946          25 : nsDocument::ResetScrolledToRefAlready()
    9947             : {
    9948          25 :   mScrolledToRefAlready = false;
    9949          25 : }
    9950             : 
    9951             : void
    9952           3 : nsDocument::SetChangeScrollPosWhenScrollingToRef(bool aValue)
    9953             : {
    9954           3 :   mChangeScrollPosWhenScrollingToRef = aValue;
    9955           3 : }
    9956             : 
    9957             : void
    9958           1 : nsIDocument::RegisterActivityObserver(nsISupports* aSupports)
    9959             : {
    9960           1 :   if (!mActivityObservers) {
    9961           1 :     mActivityObservers = new nsTHashtable<nsPtrHashKey<nsISupports> >();
    9962             :   }
    9963           1 :   mActivityObservers->PutEntry(aSupports);
    9964           1 : }
    9965             : 
    9966             : bool
    9967           0 : nsIDocument::UnregisterActivityObserver(nsISupports* aSupports)
    9968             : {
    9969           0 :   if (!mActivityObservers) {
    9970           0 :     return false;
    9971             :   }
    9972           0 :   nsPtrHashKey<nsISupports>* entry = mActivityObservers->GetEntry(aSupports);
    9973           0 :   if (!entry) {
    9974           0 :     return false;
    9975             :   }
    9976           0 :   mActivityObservers->RemoveEntry(entry);
    9977           0 :   return true;
    9978             : }
    9979             : 
    9980             : void
    9981          83 : nsIDocument::EnumerateActivityObservers(ActivityObserverEnumerator aEnumerator,
    9982             :                                         void* aData)
    9983             : {
    9984          83 :   if (!mActivityObservers)
    9985          82 :     return;
    9986             : 
    9987           2 :   for (auto iter = mActivityObservers->ConstIter(); !iter.Done();
    9988           1 :        iter.Next()) {
    9989           1 :     aEnumerator(iter.Get()->GetKey(), aData);
    9990             :   }
    9991             : }
    9992             : 
    9993             : void
    9994           0 : nsIDocument::RegisterPendingLinkUpdate(Link* aLink)
    9995             : {
    9996           0 :   MOZ_ASSERT(!mIsLinkUpdateRegistrationsForbidden);
    9997             : 
    9998           0 :   if (aLink->HasPendingLinkUpdate()) {
    9999           0 :     return;
   10000             :   }
   10001             : 
   10002           0 :   aLink->SetHasPendingLinkUpdate();
   10003             : 
   10004           0 :   if (!mHasLinksToUpdateRunnable) {
   10005             :     nsCOMPtr<nsIRunnable> event =
   10006           0 :       NewRunnableMethod("nsIDocument::FlushPendingLinkUpdatesFromRunnable",
   10007             :                         this,
   10008           0 :                         &nsIDocument::FlushPendingLinkUpdatesFromRunnable);
   10009             :     // Do this work in a second in the worst case.
   10010             :     nsresult rv =
   10011           0 :       NS_IdleDispatchToCurrentThread(event.forget(), 1000);
   10012           0 :     if (NS_FAILED(rv)) {
   10013             :       // If during shutdown posting a runnable doesn't succeed, we probably
   10014             :       // don't need to update link states.
   10015           0 :       return;
   10016             :     }
   10017           0 :     mHasLinksToUpdateRunnable = true;
   10018             :   }
   10019             : 
   10020           0 :   mLinksToUpdate.InfallibleAppend(aLink);
   10021           0 :   mHasLinksToUpdate = true;
   10022             : }
   10023             : 
   10024             : void
   10025           0 : nsIDocument::FlushPendingLinkUpdatesFromRunnable()
   10026             : {
   10027           0 :   MOZ_ASSERT(mHasLinksToUpdateRunnable);
   10028           0 :   mHasLinksToUpdateRunnable = false;
   10029           0 :   FlushPendingLinkUpdates();
   10030           0 : }
   10031             : 
   10032             : void
   10033        2036 : nsIDocument::FlushPendingLinkUpdates()
   10034             : {
   10035        2036 :   MOZ_ASSERT(!mIsLinkUpdateRegistrationsForbidden);
   10036        2036 :   if (!mHasLinksToUpdate)
   10037        2036 :     return;
   10038             : 
   10039             : #ifdef DEBUG
   10040           0 :   AutoRestore<bool> saved(mIsLinkUpdateRegistrationsForbidden);
   10041           0 :   mIsLinkUpdateRegistrationsForbidden = true;
   10042             : #endif
   10043           0 :   for (auto iter = mLinksToUpdate.Iter(); !iter.Done(); iter.Next()) {
   10044           0 :     Link* link = iter.Get();
   10045           0 :     Element* element = link->GetElement();
   10046           0 :     if (element->OwnerDoc() == this) {
   10047           0 :       link->ClearHasPendingLinkUpdate();
   10048           0 :       if (element->IsInComposedDoc()) {
   10049           0 :         element->UpdateLinkState(link->LinkState());
   10050             :       }
   10051             :     }
   10052             :   }
   10053           0 :   mLinksToUpdate.Clear();
   10054           0 :   mHasLinksToUpdate = false;
   10055             : }
   10056             : 
   10057             : already_AddRefed<nsIDocument>
   10058           0 : nsIDocument::CreateStaticClone(nsIDocShell* aCloneContainer)
   10059             : {
   10060           0 :   nsDocument* thisAsDoc = static_cast<nsDocument*>(this);
   10061           0 :   mCreatingStaticClone = true;
   10062             : 
   10063             :   // Make document use different container during cloning.
   10064           0 :   RefPtr<nsDocShell> originalShell = mDocumentContainer.get();
   10065           0 :   SetContainer(static_cast<nsDocShell*>(aCloneContainer));
   10066           0 :   nsCOMPtr<nsIDOMNode> clonedNode;
   10067           0 :   nsresult rv = thisAsDoc->CloneNode(true, 1, getter_AddRefs(clonedNode));
   10068           0 :   SetContainer(originalShell);
   10069             : 
   10070           0 :   RefPtr<nsDocument> clonedDoc;
   10071           0 :   if (NS_SUCCEEDED(rv)) {
   10072           0 :     nsCOMPtr<nsIDocument> tmp = do_QueryInterface(clonedNode);
   10073           0 :     if (tmp) {
   10074           0 :       clonedDoc = static_cast<nsDocument*>(tmp.get());
   10075           0 :       if (IsStaticDocument()) {
   10076           0 :         clonedDoc->mOriginalDocument = mOriginalDocument;
   10077             :       } else {
   10078           0 :         clonedDoc->mOriginalDocument = this;
   10079             :       }
   10080             : 
   10081           0 :       clonedDoc->mOriginalDocument->mStaticCloneCount++;
   10082             : 
   10083           0 :       int32_t sheetsCount = GetNumberOfStyleSheets();
   10084           0 :       for (int32_t i = 0; i < sheetsCount; ++i) {
   10085           0 :         RefPtr<StyleSheet> sheet = GetStyleSheetAt(i);
   10086           0 :         if (sheet) {
   10087           0 :           if (sheet->IsApplicable()) {
   10088             :             RefPtr<StyleSheet> clonedSheet =
   10089           0 :               sheet->Clone(nullptr, nullptr, clonedDoc, nullptr);
   10090           0 :             NS_WARNING_ASSERTION(clonedSheet,
   10091             :                                  "Cloning a stylesheet didn't work!");
   10092           0 :             if (clonedSheet) {
   10093           0 :               clonedDoc->AddStyleSheet(clonedSheet);
   10094             :             }
   10095             :           }
   10096             :         }
   10097             :       }
   10098             : 
   10099             :       // Iterate backwards to maintain order
   10100           0 :       for (StyleSheet* sheet : Reversed(thisAsDoc->mOnDemandBuiltInUASheets)) {
   10101           0 :         if (sheet) {
   10102           0 :           if (sheet->IsApplicable()) {
   10103             :             RefPtr<StyleSheet> clonedSheet =
   10104           0 :               sheet->Clone(nullptr, nullptr, clonedDoc, nullptr);
   10105           0 :             NS_WARNING_ASSERTION(clonedSheet,
   10106             :                                  "Cloning a stylesheet didn't work!");
   10107           0 :             if (clonedSheet) {
   10108           0 :               clonedDoc->AddOnDemandBuiltInUASheet(clonedSheet);
   10109             :             }
   10110             :           }
   10111             :         }
   10112             :       }
   10113             :     }
   10114             :   }
   10115           0 :   mCreatingStaticClone = false;
   10116           0 :   return clonedDoc.forget();
   10117             : }
   10118             : 
   10119             : void
   10120           0 : nsIDocument::UnlinkOriginalDocumentIfStatic()
   10121             : {
   10122           0 :   if (IsStaticDocument() && mOriginalDocument) {
   10123           0 :     MOZ_ASSERT(mOriginalDocument->mStaticCloneCount > 0);
   10124           0 :     mOriginalDocument->mStaticCloneCount--;
   10125           0 :     mOriginalDocument = nullptr;
   10126             :   }
   10127           0 :   MOZ_ASSERT(!mOriginalDocument);
   10128           0 : }
   10129             : 
   10130             : nsresult
   10131           4 : nsIDocument::ScheduleFrameRequestCallback(FrameRequestCallback& aCallback,
   10132             :                                           int32_t *aHandle)
   10133             : {
   10134           4 :   if (mFrameRequestCallbackCounter == INT32_MAX) {
   10135             :     // Can't increment without overflowing; bail out
   10136           0 :     return NS_ERROR_NOT_AVAILABLE;
   10137             :   }
   10138           4 :   int32_t newHandle = ++mFrameRequestCallbackCounter;
   10139             : 
   10140             :   DebugOnly<FrameRequest*> request =
   10141           8 :     mFrameRequestCallbacks.AppendElement(FrameRequest(aCallback, newHandle));
   10142           4 :   NS_ASSERTION(request, "This is supposed to be infallible!");
   10143           4 :   UpdateFrameRequestCallbackSchedulingState();
   10144             : 
   10145           4 :   *aHandle = newHandle;
   10146           4 :   return NS_OK;
   10147             : }
   10148             : 
   10149             : void
   10150           0 : nsIDocument::CancelFrameRequestCallback(int32_t aHandle)
   10151             : {
   10152             :   // mFrameRequestCallbacks is stored sorted by handle
   10153           0 :   if (mFrameRequestCallbacks.RemoveElementSorted(aHandle)) {
   10154           0 :     UpdateFrameRequestCallbackSchedulingState();
   10155             :   }
   10156           0 : }
   10157             : 
   10158             : nsresult
   10159           0 : nsDocument::GetStateObject(nsIVariant** aState)
   10160             : {
   10161             :   // Get the document's current state object. This is the object backing both
   10162             :   // history.state and popStateEvent.state.
   10163             :   //
   10164             :   // mStateObjectContainer may be null; this just means that there's no
   10165             :   // current state object.
   10166             : 
   10167           0 :   if (!mStateObjectCached && mStateObjectContainer) {
   10168           0 :     AutoJSContext cx;
   10169           0 :     nsIGlobalObject* sgo = GetScopeObject();
   10170           0 :     NS_ENSURE_TRUE(sgo, NS_ERROR_UNEXPECTED);
   10171           0 :     JS::Rooted<JSObject*> global(cx, sgo->GetGlobalJSObject());
   10172           0 :     NS_ENSURE_TRUE(global, NS_ERROR_UNEXPECTED);
   10173           0 :     JSAutoCompartment ac(cx, global);
   10174             : 
   10175           0 :     mStateObjectContainer->
   10176           0 :       DeserializeToVariant(cx, getter_AddRefs(mStateObjectCached));
   10177             :   }
   10178             : 
   10179           0 :   NS_IF_ADDREF(*aState = mStateObjectCached);
   10180             : 
   10181           0 :   return NS_OK;
   10182             : }
   10183             : 
   10184             : nsDOMNavigationTiming*
   10185         148 : nsDocument::GetNavigationTiming() const
   10186             : {
   10187         148 :   return mTiming;
   10188             : }
   10189             : 
   10190             : nsresult
   10191          29 : nsDocument::SetNavigationTiming(nsDOMNavigationTiming* aTiming)
   10192             : {
   10193          29 :   mTiming = aTiming;
   10194          29 :   if (!mLoadingTimeStamp.IsNull() && mTiming) {
   10195          24 :     mTiming->SetDOMLoadingTimeStamp(nsIDocument::GetDocumentURI(), mLoadingTimeStamp);
   10196             :   }
   10197          29 :   return NS_OK;
   10198             : }
   10199             : 
   10200             : Element*
   10201           0 : nsDocument::FindImageMap(const nsAString& aUseMapValue)
   10202             : {
   10203           0 :   if (aUseMapValue.IsEmpty()) {
   10204           0 :     return nullptr;
   10205             :   }
   10206             : 
   10207           0 :   nsAString::const_iterator start, end;
   10208           0 :   aUseMapValue.BeginReading(start);
   10209           0 :   aUseMapValue.EndReading(end);
   10210             : 
   10211           0 :   int32_t hash = aUseMapValue.FindChar('#');
   10212           0 :   if (hash < 0) {
   10213           0 :     return nullptr;
   10214             :   }
   10215             :   // aUsemap contains a '#', set start to point right after the '#'
   10216           0 :   start.advance(hash + 1);
   10217             : 
   10218           0 :   if (start == end) {
   10219           0 :     return nullptr; // aUsemap == "#"
   10220             :   }
   10221             : 
   10222           0 :   const nsAString& mapName = Substring(start, end);
   10223             : 
   10224           0 :   if (!mImageMaps) {
   10225           0 :     mImageMaps = new nsContentList(this, kNameSpaceID_XHTML, nsGkAtoms::map, nsGkAtoms::map);
   10226             :   }
   10227             : 
   10228           0 :   uint32_t i, n = mImageMaps->Length(true);
   10229           0 :   nsString name;
   10230           0 :   for (i = 0; i < n; ++i) {
   10231           0 :     nsIContent* map = mImageMaps->Item(i);
   10232           0 :     if (map->AttrValueIs(kNameSpaceID_None, nsGkAtoms::id, mapName,
   10233           0 :                          eCaseMatters) ||
   10234           0 :         map->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name, mapName,
   10235             :                          eCaseMatters)) {
   10236           0 :       return map->AsElement();
   10237             :     }
   10238             :   }
   10239             : 
   10240           0 :   return nullptr;
   10241             : }
   10242             : 
   10243             : #define DEPRECATED_OPERATION(_op) #_op "Warning",
   10244             : static const char* kDeprecationWarnings[] = {
   10245             : #include "nsDeprecatedOperationList.h"
   10246             :   nullptr
   10247             : };
   10248             : #undef DEPRECATED_OPERATION
   10249             : 
   10250             : #define DOCUMENT_WARNING(_op) #_op "Warning",
   10251             : static const char* kDocumentWarnings[] = {
   10252             : #include "nsDocumentWarningList.h"
   10253             :   nullptr
   10254             : };
   10255             : #undef DOCUMENT_WARNING
   10256             : 
   10257             : static UseCounter
   10258           0 : OperationToUseCounter(nsIDocument::DeprecatedOperations aOperation)
   10259             : {
   10260           0 :   switch(aOperation) {
   10261             : #define DEPRECATED_OPERATION(_op) \
   10262             :     case nsIDocument::e##_op: return eUseCounter_##_op;
   10263             : #include "nsDeprecatedOperationList.h"
   10264             : #undef DEPRECATED_OPERATION
   10265             :   default:
   10266           0 :     MOZ_CRASH();
   10267             :   }
   10268             : }
   10269             : 
   10270             : bool
   10271           8 : nsIDocument::HasWarnedAbout(DeprecatedOperations aOperation) const
   10272             : {
   10273           8 :   return mDeprecationWarnedAbout[aOperation];
   10274             : }
   10275             : 
   10276             : void
   10277           0 : nsIDocument::WarnOnceAbout(DeprecatedOperations aOperation,
   10278             :                            bool asError /* = false */) const
   10279             : {
   10280           0 :   MOZ_ASSERT(NS_IsMainThread());
   10281           0 :   if (HasWarnedAbout(aOperation)) {
   10282           0 :     return;
   10283             :   }
   10284           0 :   mDeprecationWarnedAbout[aOperation] = true;
   10285             :   // Don't count deprecated operations for about pages since those pages
   10286             :   // are almost in our control, and we always need to remove uses there
   10287             :   // before we remove the operation itself anyway.
   10288           0 :   if (!static_cast<const nsDocument*>(this)->IsAboutPage()) {
   10289             :     const_cast<nsIDocument*>(this)->
   10290           0 :       SetDocumentAndPageUseCounter(OperationToUseCounter(aOperation));
   10291             :   }
   10292           0 :   uint32_t flags = asError ? nsIScriptError::errorFlag
   10293           0 :                            : nsIScriptError::warningFlag;
   10294           0 :   nsContentUtils::ReportToConsole(flags,
   10295           0 :                                   NS_LITERAL_CSTRING("DOM Core"), this,
   10296             :                                   nsContentUtils::eDOM_PROPERTIES,
   10297           0 :                                   kDeprecationWarnings[aOperation]);
   10298             : }
   10299             : 
   10300             : bool
   10301           0 : nsIDocument::HasWarnedAbout(DocumentWarnings aWarning) const
   10302             : {
   10303           0 :   return mDocWarningWarnedAbout[aWarning];
   10304             : }
   10305             : 
   10306             : void
   10307           0 : nsIDocument::WarnOnceAbout(DocumentWarnings aWarning,
   10308             :                            bool asError /* = false */,
   10309             :                            const char16_t **aParams /* = nullptr */,
   10310             :                            uint32_t aParamsLength /* = 0 */) const
   10311             : {
   10312           0 :   MOZ_ASSERT(NS_IsMainThread());
   10313           0 :   if (HasWarnedAbout(aWarning)) {
   10314           0 :     return;
   10315             :   }
   10316           0 :   mDocWarningWarnedAbout[aWarning] = true;
   10317           0 :   uint32_t flags = asError ? nsIScriptError::errorFlag
   10318           0 :                            : nsIScriptError::warningFlag;
   10319           0 :   nsContentUtils::ReportToConsole(flags,
   10320           0 :                                   NS_LITERAL_CSTRING("DOM Core"), this,
   10321             :                                   nsContentUtils::eDOM_PROPERTIES,
   10322             :                                   kDocumentWarnings[aWarning],
   10323             :                                   aParams,
   10324           0 :                                   aParamsLength);
   10325             : }
   10326             : 
   10327             : mozilla::dom::ImageTracker*
   10328          56 : nsIDocument::ImageTracker()
   10329             : {
   10330          56 :   if (!mImageTracker) {
   10331          28 :     mImageTracker = new mozilla::dom::ImageTracker;
   10332             :   }
   10333          56 :   return mImageTracker;
   10334             : }
   10335             : 
   10336             : nsresult
   10337           0 : nsDocument::AddPlugin(nsIObjectLoadingContent* aPlugin)
   10338             : {
   10339           0 :   MOZ_ASSERT(aPlugin);
   10340           0 :   if (!mPlugins.PutEntry(aPlugin)) {
   10341           0 :     return NS_ERROR_OUT_OF_MEMORY;
   10342             :   }
   10343           0 :   return NS_OK;
   10344             : }
   10345             : 
   10346             : void
   10347           0 : nsDocument::RemovePlugin(nsIObjectLoadingContent* aPlugin)
   10348             : {
   10349           0 :   MOZ_ASSERT(aPlugin);
   10350           0 :   mPlugins.RemoveEntry(aPlugin);
   10351           0 : }
   10352             : 
   10353             : static bool
   10354           0 : AllSubDocumentPluginEnum(nsIDocument* aDocument, void* userArg)
   10355             : {
   10356             :   nsTArray<nsIObjectLoadingContent*>* plugins =
   10357           0 :     reinterpret_cast< nsTArray<nsIObjectLoadingContent*>* >(userArg);
   10358           0 :   MOZ_ASSERT(plugins);
   10359           0 :   aDocument->GetPlugins(*plugins);
   10360           0 :   return true;
   10361             : }
   10362             : 
   10363             : void
   10364           0 : nsDocument::GetPlugins(nsTArray<nsIObjectLoadingContent*>& aPlugins)
   10365             : {
   10366           0 :   aPlugins.SetCapacity(aPlugins.Length() + mPlugins.Count());
   10367           0 :   for (auto iter = mPlugins.ConstIter(); !iter.Done(); iter.Next()) {
   10368           0 :     aPlugins.AppendElement(iter.Get()->GetKey());
   10369             :   }
   10370           0 :   EnumerateSubDocuments(AllSubDocumentPluginEnum, &aPlugins);
   10371           0 : }
   10372             : 
   10373             : nsresult
   10374           0 : nsDocument::AddResponsiveContent(nsIContent* aContent)
   10375             : {
   10376           0 :   MOZ_ASSERT(aContent);
   10377           0 :   MOZ_ASSERT(aContent->IsHTMLElement(nsGkAtoms::img));
   10378           0 :   mResponsiveContent.PutEntry(aContent);
   10379           0 :   return NS_OK;
   10380             : }
   10381             : 
   10382             : void
   10383           0 : nsDocument::RemoveResponsiveContent(nsIContent* aContent)
   10384             : {
   10385           0 :   MOZ_ASSERT(aContent);
   10386           0 :   mResponsiveContent.RemoveEntry(aContent);
   10387           0 : }
   10388             : 
   10389             : void
   10390           3 : nsDocument::NotifyMediaFeatureValuesChanged()
   10391             : {
   10392           3 :   for (auto iter = mResponsiveContent.ConstIter(); !iter.Done();
   10393           0 :        iter.Next()) {
   10394           0 :     nsCOMPtr<nsIContent> content = iter.Get()->GetKey();
   10395           0 :     if (content->IsHTMLElement(nsGkAtoms::img)) {
   10396           0 :       auto* imageElement = static_cast<HTMLImageElement*>(content.get());
   10397           0 :       imageElement->MediaFeatureValuesChanged();
   10398             :     }
   10399             :   }
   10400           3 : }
   10401             : 
   10402             : already_AddRefed<Touch>
   10403           0 : nsIDocument::CreateTouch(nsGlobalWindow* aView,
   10404             :                          EventTarget* aTarget,
   10405             :                          int32_t aIdentifier,
   10406             :                          int32_t aPageX, int32_t aPageY,
   10407             :                          int32_t aScreenX, int32_t aScreenY,
   10408             :                          int32_t aClientX, int32_t aClientY,
   10409             :                          int32_t aRadiusX, int32_t aRadiusY,
   10410             :                          float aRotationAngle,
   10411             :                          float aForce)
   10412             : {
   10413           0 :   MOZ_ASSERT_IF(aView, aView->IsInnerWindow());
   10414             :   RefPtr<Touch> touch = new Touch(aTarget,
   10415             :                                   aIdentifier,
   10416             :                                   aPageX, aPageY,
   10417             :                                   aScreenX, aScreenY,
   10418             :                                   aClientX, aClientY,
   10419             :                                   aRadiusX, aRadiusY,
   10420             :                                   aRotationAngle,
   10421           0 :                                   aForce);
   10422           0 :   return touch.forget();
   10423             : }
   10424             : 
   10425             : already_AddRefed<TouchList>
   10426           0 : nsIDocument::CreateTouchList()
   10427             : {
   10428           0 :   RefPtr<TouchList> retval = new TouchList(ToSupports(this));
   10429           0 :   return retval.forget();
   10430             : }
   10431             : 
   10432             : already_AddRefed<TouchList>
   10433           0 : nsIDocument::CreateTouchList(Touch& aTouch,
   10434             :                              const Sequence<OwningNonNull<Touch> >& aTouches)
   10435             : {
   10436           0 :   RefPtr<TouchList> retval = new TouchList(ToSupports(this));
   10437           0 :   retval->Append(&aTouch);
   10438           0 :   for (uint32_t i = 0; i < aTouches.Length(); ++i) {
   10439           0 :     retval->Append(aTouches[i].get());
   10440             :   }
   10441           0 :   return retval.forget();
   10442             : }
   10443             : 
   10444             : already_AddRefed<TouchList>
   10445           0 : nsIDocument::CreateTouchList(const Sequence<OwningNonNull<Touch> >& aTouches)
   10446             : {
   10447           0 :   RefPtr<TouchList> retval = new TouchList(ToSupports(this));
   10448           0 :   for (uint32_t i = 0; i < aTouches.Length(); ++i) {
   10449           0 :     retval->Append(aTouches[i].get());
   10450             :   }
   10451           0 :   return retval.forget();
   10452             : }
   10453             : 
   10454             : already_AddRefed<nsDOMCaretPosition>
   10455           0 : nsIDocument::CaretPositionFromPoint(float aX, float aY)
   10456             : {
   10457           0 :   nscoord x = nsPresContext::CSSPixelsToAppUnits(aX);
   10458           0 :   nscoord y = nsPresContext::CSSPixelsToAppUnits(aY);
   10459           0 :   nsPoint pt(x, y);
   10460             : 
   10461           0 :   FlushPendingNotifications(FlushType::Layout);
   10462             : 
   10463           0 :   nsIPresShell *ps = GetShell();
   10464           0 :   if (!ps) {
   10465           0 :     return nullptr;
   10466             :   }
   10467             : 
   10468           0 :   nsIFrame *rootFrame = ps->GetRootFrame();
   10469             : 
   10470             :   // XUL docs, unlike HTML, have no frame tree until everything's done loading
   10471           0 :   if (!rootFrame) {
   10472           0 :     return nullptr;
   10473             :   }
   10474             : 
   10475           0 :   nsIFrame *ptFrame = nsLayoutUtils::GetFrameForPoint(rootFrame, pt,
   10476           0 :       nsLayoutUtils::IGNORE_PAINT_SUPPRESSION | nsLayoutUtils::IGNORE_CROSS_DOC);
   10477           0 :   if (!ptFrame) {
   10478           0 :     return nullptr;
   10479             :   }
   10480             : 
   10481             :   // GetContentOffsetsFromPoint requires frame-relative coordinates, so we need
   10482             :   // to adjust to frame-relative coordinates before we can perform this call.
   10483             :   // It should also not take into account the padding of the frame.
   10484           0 :   nsPoint adjustedPoint = pt - ptFrame->GetOffsetTo(rootFrame);
   10485             : 
   10486             :   nsFrame::ContentOffsets offsets =
   10487           0 :     ptFrame->GetContentOffsetsFromPoint(adjustedPoint);
   10488             : 
   10489           0 :   nsCOMPtr<nsIContent> node = offsets.content;
   10490           0 :   uint32_t offset = offsets.offset;
   10491           0 :   nsCOMPtr<nsIContent> anonNode = node;
   10492           0 :   bool nodeIsAnonymous = node && node->IsInNativeAnonymousSubtree();
   10493           0 :   if (nodeIsAnonymous) {
   10494           0 :     node = ptFrame->GetContent();
   10495           0 :     nsIContent* nonanon = node->FindFirstNonChromeOnlyAccessContent();
   10496           0 :     nsCOMPtr<nsIDOMHTMLTextAreaElement> textArea = do_QueryInterface(nonanon);
   10497           0 :     nsITextControlFrame* textFrame = do_QueryFrame(nonanon->GetPrimaryFrame());
   10498           0 :     nsNumberControlFrame* numberFrame = do_QueryFrame(nonanon->GetPrimaryFrame());
   10499           0 :     if (textFrame || numberFrame) {
   10500             :       // If the anonymous content node has a child, then we need to make sure
   10501             :       // that we get the appropriate child, as otherwise the offset may not be
   10502             :       // correct when we construct a range for it.
   10503           0 :       nsCOMPtr<nsIContent> firstChild = anonNode->GetFirstChild();
   10504           0 :       if (firstChild) {
   10505           0 :         anonNode = firstChild;
   10506             :       }
   10507             : 
   10508           0 :       if (textArea) {
   10509           0 :         offset = nsContentUtils::GetAdjustedOffsetInTextControl(ptFrame, offset);
   10510             :       }
   10511             : 
   10512           0 :       node = nonanon;
   10513             :     } else {
   10514           0 :       node = nullptr;
   10515           0 :       offset = 0;
   10516             :     }
   10517             :   }
   10518             : 
   10519           0 :   RefPtr<nsDOMCaretPosition> aCaretPos = new nsDOMCaretPosition(node, offset);
   10520           0 :   if (nodeIsAnonymous) {
   10521           0 :     aCaretPos->SetAnonymousContentNode(anonNode);
   10522             :   }
   10523           0 :   return aCaretPos.forget();
   10524             : }
   10525             : 
   10526             : NS_IMETHODIMP
   10527           0 : nsDocument::CaretPositionFromPoint(float aX, float aY, nsISupports** aCaretPos)
   10528             : {
   10529           0 :   NS_ENSURE_ARG_POINTER(aCaretPos);
   10530           0 :   *aCaretPos = nsIDocument::CaretPositionFromPoint(aX, aY).take();
   10531           0 :   return NS_OK;
   10532             : }
   10533             : 
   10534             : bool
   10535           0 : nsIDocument::IsPotentiallyScrollable(HTMLBodyElement* aBody)
   10536             : {
   10537             :   // We rely on correct frame information here, so need to flush frames.
   10538           0 :   FlushPendingNotifications(FlushType::Frames);
   10539             : 
   10540             :   // An element is potentially scrollable if all of the following conditions are
   10541             :   // true:
   10542             : 
   10543             :   // The element has an associated CSS layout box.
   10544           0 :   nsIFrame* bodyFrame = aBody->GetPrimaryFrame();
   10545           0 :   if (!bodyFrame) {
   10546           0 :     return false;
   10547             :   }
   10548             : 
   10549             :   // The element is not the HTML body element, or it is and the root element's
   10550             :   // used value of the overflow-x or overflow-y properties is not visible.
   10551           0 :   MOZ_ASSERT(aBody->GetParent() == aBody->OwnerDoc()->GetRootElement());
   10552           0 :   nsIFrame* parentFrame = aBody->GetParent()->GetPrimaryFrame();
   10553           0 :   if (parentFrame &&
   10554           0 :       parentFrame->StyleDisplay()->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE &&
   10555           0 :       parentFrame->StyleDisplay()->mOverflowY == NS_STYLE_OVERFLOW_VISIBLE) {
   10556           0 :     return false;
   10557             :   }
   10558             : 
   10559             :   // The element's used value of the overflow-x or overflow-y properties is not
   10560             :   // visible.
   10561           0 :   if (bodyFrame->StyleDisplay()->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE &&
   10562           0 :       bodyFrame->StyleDisplay()->mOverflowY == NS_STYLE_OVERFLOW_VISIBLE) {
   10563           0 :     return false;
   10564             :   }
   10565             : 
   10566           0 :   return true;
   10567             : }
   10568             : 
   10569             : Element*
   10570           0 : nsIDocument::GetScrollingElement()
   10571             : {
   10572             :   // Keep this in sync with IsScrollingElement.
   10573           0 :   if (GetCompatibilityMode() == eCompatibility_NavQuirks) {
   10574           0 :     HTMLBodyElement* body = GetBodyElement();
   10575           0 :     if (body && !IsPotentiallyScrollable(body)) {
   10576           0 :       return body;
   10577             :     }
   10578             : 
   10579           0 :     return nullptr;
   10580             :   }
   10581             : 
   10582           0 :   return GetRootElement();
   10583             : }
   10584             : 
   10585             : bool
   10586           2 : nsIDocument::IsScrollingElement(Element* aElement)
   10587             : {
   10588             :   // Keep this in sync with GetScrollingElement.
   10589           2 :   MOZ_ASSERT(aElement);
   10590             : 
   10591           2 :   if (GetCompatibilityMode() != eCompatibility_NavQuirks) {
   10592           2 :     return aElement == GetRootElement();
   10593             :   }
   10594             : 
   10595           0 :   HTMLBodyElement* body = GetBodyElement();
   10596           0 :   if (aElement != body) {
   10597           0 :     return false;
   10598             :   }
   10599             : 
   10600             :   // Now we know body is non-null, since aElement is not null.  It's the
   10601             :   // scrolling element for the document if it itself is not potentially
   10602             :   // scrollable.
   10603           0 :   return !IsPotentiallyScrollable(body);
   10604             : }
   10605             : 
   10606             : void
   10607           0 : nsIDocument::ObsoleteSheet(nsIURI *aSheetURI, ErrorResult& rv)
   10608             : {
   10609           0 :   nsresult res = CSSLoader()->ObsoleteSheet(aSheetURI);
   10610           0 :   if (NS_FAILED(res)) {
   10611           0 :     rv.Throw(res);
   10612             :   }
   10613           0 : }
   10614             : 
   10615             : void
   10616           0 : nsIDocument::ObsoleteSheet(const nsAString& aSheetURI, ErrorResult& rv)
   10617             : {
   10618           0 :   nsCOMPtr<nsIURI> uri;
   10619           0 :   nsresult res = NS_NewURI(getter_AddRefs(uri), aSheetURI);
   10620           0 :   if (NS_FAILED(res)) {
   10621           0 :     rv.Throw(res);
   10622           0 :     return;
   10623             :   }
   10624           0 :   res = CSSLoader()->ObsoleteSheet(uri);
   10625           0 :   if (NS_FAILED(res)) {
   10626           0 :     rv.Throw(res);
   10627             :   }
   10628             : }
   10629             : 
   10630             : class UnblockParsingPromiseHandler final : public PromiseNativeHandler
   10631             : {
   10632             : public:
   10633             :   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   10634           0 :   NS_DECL_CYCLE_COLLECTION_CLASS(UnblockParsingPromiseHandler)
   10635             : 
   10636           0 :   explicit UnblockParsingPromiseHandler(nsIDocument* aDocument, Promise* aPromise)
   10637           0 :     : mPromise(aPromise)
   10638             :   {
   10639           0 :     nsCOMPtr<nsIParser> parser = aDocument->CreatorParserOrNull();
   10640           0 :     if (parser) {
   10641           0 :       parser->BlockParser();
   10642           0 :       mParser = do_GetWeakReference(parser);
   10643           0 :       mDocument = aDocument;
   10644             :     }
   10645           0 :   }
   10646             : 
   10647             :   void
   10648           0 :   ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
   10649             :   {
   10650           0 :     MaybeUnblockParser();
   10651             : 
   10652           0 :     mPromise->MaybeResolve(aCx, aValue);
   10653           0 :   }
   10654             : 
   10655             :   void
   10656           0 :   RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
   10657             :   {
   10658           0 :     MaybeUnblockParser();
   10659             : 
   10660           0 :     mPromise->MaybeReject(aCx, aValue);
   10661           0 :   }
   10662             : 
   10663             : protected:
   10664           0 :   virtual ~UnblockParsingPromiseHandler()
   10665           0 :   {
   10666             :     // If we're being cleaned up by the cycle collector, our mDocument reference
   10667             :     // may have been unlinked while our mParser weak reference is still alive.
   10668           0 :     if (mDocument) {
   10669           0 :       MaybeUnblockParser();
   10670             :     }
   10671           0 :   }
   10672             : 
   10673             : private:
   10674           0 :   void MaybeUnblockParser() {
   10675           0 :     nsCOMPtr<nsIParser> parser = do_QueryReferent(mParser);
   10676           0 :     if (parser) {
   10677           0 :       MOZ_DIAGNOSTIC_ASSERT(mDocument);
   10678           0 :       nsCOMPtr<nsIParser> docParser = mDocument->CreatorParserOrNull();
   10679           0 :       if (parser == docParser) {
   10680           0 :         parser->UnblockParser();
   10681           0 :         parser->ContinueInterruptedParsingAsync();
   10682             :       }
   10683             :     }
   10684           0 :     mParser = nullptr;
   10685           0 :     mDocument = nullptr;
   10686           0 :   }
   10687             : 
   10688             :   nsWeakPtr mParser;
   10689             :   RefPtr<Promise> mPromise;
   10690             :   RefPtr<nsIDocument> mDocument;
   10691             : };
   10692             : 
   10693           0 : NS_IMPL_CYCLE_COLLECTION(UnblockParsingPromiseHandler, mDocument, mPromise)
   10694             : 
   10695           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(UnblockParsingPromiseHandler)
   10696           0 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
   10697           0 : NS_INTERFACE_MAP_END
   10698             : 
   10699           0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(UnblockParsingPromiseHandler)
   10700           0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(UnblockParsingPromiseHandler)
   10701             : 
   10702             : already_AddRefed<Promise>
   10703           0 : nsIDocument::BlockParsing(Promise& aPromise, ErrorResult& aRv)
   10704             : {
   10705           0 :   RefPtr<Promise> resultPromise = Promise::Create(aPromise.GetParentObject(), aRv);
   10706           0 :   if (aRv.Failed()) {
   10707           0 :     return nullptr;
   10708             :   }
   10709             : 
   10710           0 :   RefPtr<PromiseNativeHandler> promiseHandler = new UnblockParsingPromiseHandler(this, resultPromise);
   10711           0 :   aPromise.AppendNativeHandler(promiseHandler);
   10712             : 
   10713           0 :   return resultPromise.forget();
   10714             : }
   10715             : 
   10716             : already_AddRefed<nsIURI>
   10717           0 : nsIDocument::GetMozDocumentURIIfNotForErrorPages()
   10718             : {
   10719           0 :   if (mFailedChannel) {
   10720           0 :     nsCOMPtr<nsIURI> failedURI;
   10721           0 :     if (NS_SUCCEEDED(mFailedChannel->GetURI(getter_AddRefs(failedURI)))) {
   10722           0 :       return failedURI.forget();
   10723             :     }
   10724             :   }
   10725             : 
   10726           0 :   nsCOMPtr<nsIURI> uri = GetDocumentURIObject();
   10727           0 :   if (!uri) {
   10728           0 :     return nullptr;
   10729             :   }
   10730             : 
   10731           0 :   return uri.forget();
   10732             : }
   10733             : 
   10734             : nsIHTMLCollection*
   10735           0 : nsIDocument::Children()
   10736             : {
   10737           0 :   if (!mChildrenCollection) {
   10738           0 :     mChildrenCollection = new nsContentList(this, kNameSpaceID_Wildcard,
   10739             :                                             nsGkAtoms::_asterisk,
   10740             :                                             nsGkAtoms::_asterisk,
   10741           0 :                                             false);
   10742             :   }
   10743             : 
   10744           0 :   return mChildrenCollection;
   10745             : }
   10746             : 
   10747             : uint32_t
   10748           0 : nsIDocument::ChildElementCount()
   10749             : {
   10750           0 :   return Children()->Length();
   10751             : }
   10752             : 
   10753             : namespace mozilla {
   10754             : 
   10755             : // Singleton class to manage the list of fullscreen documents which are the
   10756             : // root of a branch which contains fullscreen documents. We maintain this list
   10757             : // so that we can easily exit all windows from fullscreen when the user
   10758             : // presses the escape key.
   10759             : class FullscreenRoots {
   10760             : public:
   10761             :   // Adds the root of given document to the manager. Calling this method
   10762             :   // with a document whose root is already contained has no effect.
   10763             :   static void Add(nsIDocument* aDoc);
   10764             : 
   10765             :   // Iterates over every root in the root list, and calls aFunction, passing
   10766             :   // each root once to aFunction. It is safe to call Add() and Remove() while
   10767             :   // iterating over the list (i.e. in aFunction). Documents that are removed
   10768             :   // from the manager during traversal are not traversed, and documents that
   10769             :   // are added to the manager during traversal are also not traversed.
   10770             :   static void ForEach(void(*aFunction)(nsIDocument* aDoc));
   10771             : 
   10772             :   // Removes the root of a specific document from the manager.
   10773             :   static void Remove(nsIDocument* aDoc);
   10774             : 
   10775             :   // Returns true if all roots added to the list have been removed.
   10776             :   static bool IsEmpty();
   10777             : 
   10778             : private:
   10779             : 
   10780           0 :   FullscreenRoots() {
   10781           0 :     MOZ_COUNT_CTOR(FullscreenRoots);
   10782           0 :   }
   10783           0 :   ~FullscreenRoots() {
   10784           0 :     MOZ_COUNT_DTOR(FullscreenRoots);
   10785           0 :   }
   10786             : 
   10787             :   enum {
   10788             :     NotFound = uint32_t(-1)
   10789             :   };
   10790             :   // Looks in mRoots for aRoot. Returns the index if found, otherwise NotFound.
   10791             :   static uint32_t Find(nsIDocument* aRoot);
   10792             : 
   10793             :   // Returns true if aRoot is in the list of fullscreen roots.
   10794             :   static bool Contains(nsIDocument* aRoot);
   10795             : 
   10796             :   // Singleton instance of the FullscreenRoots. This is instantiated when a
   10797             :   // root is added, and it is deleted when the last root is removed.
   10798             :   static FullscreenRoots* sInstance;
   10799             : 
   10800             :   // List of weak pointers to roots.
   10801             :   nsTArray<nsWeakPtr> mRoots;
   10802             : };
   10803             : 
   10804             : FullscreenRoots* FullscreenRoots::sInstance = nullptr;
   10805             : 
   10806             : /* static */
   10807             : void
   10808           0 : FullscreenRoots::ForEach(void(*aFunction)(nsIDocument* aDoc))
   10809             : {
   10810           0 :   if (!sInstance) {
   10811           0 :     return;
   10812             :   }
   10813             :   // Create a copy of the roots array, and iterate over the copy. This is so
   10814             :   // that if an element is removed from mRoots we don't mess up our iteration.
   10815           0 :   nsTArray<nsWeakPtr> roots(sInstance->mRoots);
   10816             :   // Call aFunction on all entries.
   10817           0 :   for (uint32_t i = 0; i < roots.Length(); i++) {
   10818           0 :     nsCOMPtr<nsIDocument> root = do_QueryReferent(roots[i]);
   10819             :     // Check that the root isn't in the manager. This is so that new additions
   10820             :     // while we were running don't get traversed.
   10821           0 :     if (root && FullscreenRoots::Contains(root)) {
   10822           0 :       aFunction(root);
   10823             :     }
   10824             :   }
   10825             : }
   10826             : 
   10827             : /* static */
   10828             : bool
   10829           0 : FullscreenRoots::Contains(nsIDocument* aRoot)
   10830             : {
   10831           0 :   return FullscreenRoots::Find(aRoot) != NotFound;
   10832             : }
   10833             : 
   10834             : /* static */
   10835             : void
   10836           0 : FullscreenRoots::Add(nsIDocument* aDoc)
   10837             : {
   10838           0 :   nsCOMPtr<nsIDocument> root = nsContentUtils::GetRootDocument(aDoc);
   10839           0 :   if (!FullscreenRoots::Contains(root)) {
   10840           0 :     if (!sInstance) {
   10841           0 :       sInstance = new FullscreenRoots();
   10842             :     }
   10843           0 :     sInstance->mRoots.AppendElement(do_GetWeakReference(root));
   10844             :   }
   10845           0 : }
   10846             : 
   10847             : /* static */
   10848             : uint32_t
   10849           0 : FullscreenRoots::Find(nsIDocument* aRoot)
   10850             : {
   10851           0 :   if (!sInstance) {
   10852           0 :     return NotFound;
   10853             :   }
   10854           0 :   nsTArray<nsWeakPtr>& roots = sInstance->mRoots;
   10855           0 :   for (uint32_t i = 0; i < roots.Length(); i++) {
   10856           0 :     nsCOMPtr<nsIDocument> otherRoot(do_QueryReferent(roots[i]));
   10857           0 :     if (otherRoot == aRoot) {
   10858           0 :       return i;
   10859             :     }
   10860             :   }
   10861           0 :   return NotFound;
   10862             : }
   10863             : 
   10864             : /* static */
   10865             : void
   10866           0 : FullscreenRoots::Remove(nsIDocument* aDoc)
   10867             : {
   10868           0 :   nsCOMPtr<nsIDocument> root = nsContentUtils::GetRootDocument(aDoc);
   10869           0 :   uint32_t index = Find(root);
   10870           0 :   NS_ASSERTION(index != NotFound,
   10871             :     "Should only try to remove roots which are still added!");
   10872           0 :   if (index == NotFound || !sInstance) {
   10873           0 :     return;
   10874             :   }
   10875           0 :   sInstance->mRoots.RemoveElementAt(index);
   10876           0 :   if (sInstance->mRoots.IsEmpty()) {
   10877           0 :     delete sInstance;
   10878           0 :     sInstance = nullptr;
   10879             :   }
   10880             : }
   10881             : 
   10882             : /* static */
   10883             : bool
   10884           0 : FullscreenRoots::IsEmpty()
   10885             : {
   10886           0 :   return !sInstance;
   10887             : }
   10888             : 
   10889             : } // end namespace mozilla.
   10890             : using mozilla::FullscreenRoots;
   10891             : 
   10892             : nsIDocument*
   10893           0 : nsDocument::GetFullscreenRoot()
   10894             : {
   10895           0 :   nsCOMPtr<nsIDocument> root = do_QueryReferent(mFullscreenRoot);
   10896           0 :   return root;
   10897             : }
   10898             : 
   10899             : void
   10900           0 : nsDocument::SetFullscreenRoot(nsIDocument* aRoot)
   10901             : {
   10902           0 :   mFullscreenRoot = do_GetWeakReference(aRoot);
   10903           0 : }
   10904             : 
   10905             : void
   10906           0 : nsIDocument::ExitFullscreen()
   10907             : {
   10908           0 :   RestorePreviousFullScreenState();
   10909           0 : }
   10910             : 
   10911             : static void
   10912           0 : AskWindowToExitFullscreen(nsIDocument* aDoc)
   10913             : {
   10914           0 :   if (XRE_GetProcessType() == GeckoProcessType_Content) {
   10915           0 :     nsContentUtils::DispatchEventOnlyToChrome(
   10916           0 :       aDoc, ToSupports(aDoc), NS_LITERAL_STRING("MozDOMFullscreen:Exit"),
   10917             :       /* Bubbles */ true, /* Cancelable */ false,
   10918           0 :       /* DefaultAction */ nullptr);
   10919             :   } else {
   10920           0 :     if (nsPIDOMWindowOuter* win = aDoc->GetWindow()) {
   10921           0 :       win->SetFullscreenInternal(FullscreenReason::ForFullscreenAPI, false);
   10922             :     }
   10923             :   }
   10924           0 : }
   10925             : 
   10926           0 : class nsCallExitFullscreen : public Runnable
   10927             : {
   10928             : public:
   10929           0 :   explicit nsCallExitFullscreen(nsIDocument* aDoc)
   10930           0 :     : mozilla::Runnable("nsCallExitFullscreen")
   10931           0 :     , mDoc(aDoc)
   10932             :   {
   10933           0 :   }
   10934             : 
   10935           0 :   NS_IMETHOD Run() override final
   10936             :   {
   10937           0 :     if (!mDoc) {
   10938           0 :       FullscreenRoots::ForEach(&AskWindowToExitFullscreen);
   10939             :     } else {
   10940           0 :       AskWindowToExitFullscreen(mDoc);
   10941             :     }
   10942           0 :     return NS_OK;
   10943             :   }
   10944             : 
   10945             : private:
   10946             :   nsCOMPtr<nsIDocument> mDoc;
   10947             : };
   10948             : 
   10949             : /* static */ void
   10950           0 : nsIDocument::AsyncExitFullscreen(nsIDocument* aDoc)
   10951             : {
   10952           0 :   MOZ_RELEASE_ASSERT(NS_IsMainThread());
   10953           0 :   nsCOMPtr<nsIRunnable> exit = new nsCallExitFullscreen(aDoc);
   10954           0 :   if (aDoc) {
   10955           0 :     aDoc->Dispatch("nsCallExitFullscreen", TaskCategory::Other, exit.forget());
   10956             :   } else {
   10957           0 :     NS_DispatchToCurrentThread(exit.forget());
   10958             :   }
   10959           0 : }
   10960             : 
   10961             : static bool
   10962           0 : CountFullscreenSubDocuments(nsIDocument* aDoc, void* aData)
   10963             : {
   10964           0 :   if (aDoc->GetFullscreenElement()) {
   10965           0 :     uint32_t* count = static_cast<uint32_t*>(aData);
   10966           0 :     (*count)++;
   10967             :   }
   10968           0 :   return true;
   10969             : }
   10970             : 
   10971             : static uint32_t
   10972           0 : CountFullscreenSubDocuments(nsIDocument* aDoc)
   10973             : {
   10974           0 :   uint32_t count = 0;
   10975           0 :   aDoc->EnumerateSubDocuments(CountFullscreenSubDocuments, &count);
   10976           0 :   return count;
   10977             : }
   10978             : 
   10979             : bool
   10980           0 : nsDocument::IsFullscreenLeaf()
   10981             : {
   10982             :   // A fullscreen leaf document is fullscreen, and has no fullscreen
   10983             :   // subdocuments.
   10984           0 :   if (!GetFullscreenElement()) {
   10985           0 :     return false;
   10986             :   }
   10987           0 :   return CountFullscreenSubDocuments(this) == 0;
   10988             : }
   10989             : 
   10990             : static bool
   10991           0 : ResetFullScreen(nsIDocument* aDocument, void* aData)
   10992             : {
   10993           0 :   if (aDocument->GetFullscreenElement()) {
   10994           0 :     NS_ASSERTION(CountFullscreenSubDocuments(aDocument) <= 1,
   10995             :         "Should have at most 1 fullscreen subdocument.");
   10996           0 :     static_cast<nsDocument*>(aDocument)->CleanupFullscreenState();
   10997           0 :     NS_ASSERTION(!aDocument->GetFullscreenElement(),
   10998             :                  "Should reset full-screen");
   10999           0 :     auto changed = reinterpret_cast<nsCOMArray<nsIDocument>*>(aData);
   11000           0 :     changed->AppendElement(aDocument);
   11001           0 :     aDocument->EnumerateSubDocuments(ResetFullScreen, aData);
   11002             :   }
   11003           0 :   return true;
   11004             : }
   11005             : 
   11006             : // Since nsIDocument::ExitFullscreenInDocTree() could be called from
   11007             : // Element::UnbindFromTree() where it is not safe to synchronously run
   11008             : // script. This runnable is the script part of that function.
   11009           0 : class ExitFullscreenScriptRunnable : public Runnable
   11010             : {
   11011             : public:
   11012           0 :   explicit ExitFullscreenScriptRunnable(nsCOMArray<nsIDocument>&& aDocuments)
   11013           0 :     : mozilla::Runnable("ExitFullscreenScriptRunnable")
   11014           0 :     , mDocuments(Move(aDocuments))
   11015             :   {
   11016           0 :   }
   11017             : 
   11018           0 :   NS_IMETHOD Run() override
   11019             :   {
   11020             :     // Dispatch MozDOMFullscreen:Exited to the last document in
   11021             :     // the list since we want this event to follow the same path
   11022             :     // MozDOMFullscreen:Entered dispatched.
   11023           0 :     nsIDocument* lastDocument = mDocuments[mDocuments.Length() - 1];
   11024           0 :     nsContentUtils::DispatchEventOnlyToChrome(
   11025             :       lastDocument, ToSupports(lastDocument),
   11026           0 :       NS_LITERAL_STRING("MozDOMFullscreen:Exited"),
   11027           0 :       /* Bubbles */ true, /* Cancelable */ false, /* DefaultAction */ nullptr);
   11028             :     // Ensure the window exits fullscreen.
   11029           0 :     if (nsPIDOMWindowOuter* win = mDocuments[0]->GetWindow()) {
   11030           0 :       win->SetFullscreenInternal(FullscreenReason::ForForceExitFullscreen, false);
   11031             :     }
   11032           0 :     return NS_OK;
   11033             :   }
   11034             : 
   11035             : private:
   11036             :   nsCOMArray<nsIDocument> mDocuments;
   11037             : };
   11038             : 
   11039             : /* static */ void
   11040           0 : nsIDocument::ExitFullscreenInDocTree(nsIDocument* aMaybeNotARootDoc)
   11041             : {
   11042           0 :   MOZ_ASSERT(aMaybeNotARootDoc);
   11043             : 
   11044             :   // Unlock the pointer
   11045           0 :   UnlockPointer();
   11046             : 
   11047           0 :   nsCOMPtr<nsIDocument> root = aMaybeNotARootDoc->GetFullscreenRoot();
   11048           0 :   if (!root || !root->GetFullscreenElement()) {
   11049             :     // If a document was detached before exiting from fullscreen, it is
   11050             :     // possible that the root had left fullscreen state. In this case,
   11051             :     // we would not get anything from the ResetFullScreen() call. Root's
   11052             :     // not being a fullscreen doc also means the widget should have
   11053             :     // exited fullscreen state. It means even if we do not return here,
   11054             :     // we would actually do nothing below except crashing ourselves via
   11055             :     // dispatching the "MozDOMFullscreen:Exited" event to an nonexistent
   11056             :     // document.
   11057           0 :     return;
   11058             :   }
   11059             : 
   11060             :   // Stores a list of documents to which we must dispatch "fullscreenchange".
   11061             :   // We're required by the spec to dispatch the events in leaf-to-root
   11062             :   // order when exiting fullscreen, but we traverse the doctree in a
   11063             :   // root-to-leaf order, so we save references to the documents we must
   11064             :   // dispatch to so that we dispatch in the specified order.
   11065           0 :   nsCOMArray<nsIDocument> changed;
   11066             : 
   11067             :   // Walk the tree of fullscreen documents, and reset their fullscreen state.
   11068           0 :   ResetFullScreen(root, static_cast<void*>(&changed));
   11069             : 
   11070             :   // Dispatch "fullscreenchange" events. Note this loop is in reverse
   11071             :   // order so that the events for the leaf document arrives before the root
   11072             :   // document, as required by the spec.
   11073           0 :   for (uint32_t i = 0; i < changed.Length(); ++i) {
   11074           0 :     DispatchFullScreenChange(changed[changed.Length() - i - 1]);
   11075             :   }
   11076             : 
   11077           0 :   NS_ASSERTION(!root->GetFullscreenElement(),
   11078             :     "Fullscreen root should no longer be a fullscreen doc...");
   11079             : 
   11080             :   // Move the top-level window out of fullscreen mode.
   11081           0 :   FullscreenRoots::Remove(root);
   11082             : 
   11083           0 :   nsContentUtils::AddScriptRunner(
   11084           0 :     new ExitFullscreenScriptRunnable(Move(changed)));
   11085             : }
   11086             : 
   11087             : bool
   11088           0 : GetFullscreenLeaf(nsIDocument* aDoc, void* aData)
   11089             : {
   11090           0 :   if (aDoc->IsFullscreenLeaf()) {
   11091           0 :     nsIDocument** result = static_cast<nsIDocument**>(aData);
   11092           0 :     *result = aDoc;
   11093           0 :     return false;
   11094           0 :   } else if (aDoc->GetFullscreenElement()) {
   11095           0 :     aDoc->EnumerateSubDocuments(GetFullscreenLeaf, aData);
   11096             :   }
   11097           0 :   return true;
   11098             : }
   11099             : 
   11100             : static nsIDocument*
   11101           0 : GetFullscreenLeaf(nsIDocument* aDoc)
   11102             : {
   11103           0 :   nsIDocument* leaf = nullptr;
   11104           0 :   GetFullscreenLeaf(aDoc, &leaf);
   11105           0 :   if (leaf) {
   11106           0 :     return leaf;
   11107             :   }
   11108             :   // Otherwise we could be either in a non-fullscreen doc tree, or we're
   11109             :   // below the fullscreen doc. Start the search from the root.
   11110           0 :   nsIDocument* root = nsContentUtils::GetRootDocument(aDoc);
   11111             :   // Check that the root is actually fullscreen so we don't waste time walking
   11112             :   // around its descendants.
   11113           0 :   if (!root->GetFullscreenElement()) {
   11114           0 :     return nullptr;
   11115             :   }
   11116           0 :   GetFullscreenLeaf(root, &leaf);
   11117           0 :   return leaf;
   11118             : }
   11119             : 
   11120             : void
   11121           0 : nsDocument::RestorePreviousFullScreenState()
   11122             : {
   11123           0 :   NS_ASSERTION(!GetFullscreenElement() || !FullscreenRoots::IsEmpty(),
   11124             :     "Should have at least 1 fullscreen root when fullscreen!");
   11125             : 
   11126           0 :   if (!GetFullscreenElement() || !GetWindow() || FullscreenRoots::IsEmpty()) {
   11127           0 :     return;
   11128             :   }
   11129             : 
   11130           0 :   nsCOMPtr<nsIDocument> fullScreenDoc = GetFullscreenLeaf(this);
   11131           0 :   AutoTArray<nsDocument*, 8> exitDocs;
   11132             : 
   11133           0 :   nsIDocument* doc = fullScreenDoc;
   11134             :   // Collect all subdocuments.
   11135           0 :   for (; doc != this; doc = doc->GetParentDocument()) {
   11136           0 :     exitDocs.AppendElement(static_cast<nsDocument*>(doc));
   11137             :   }
   11138           0 :   MOZ_ASSERT(doc == this, "Must have reached this doc");
   11139             :   // Collect all ancestor documents which we are going to change.
   11140           0 :   for (; doc; doc = doc->GetParentDocument()) {
   11141           0 :     nsDocument* theDoc = static_cast<nsDocument*>(doc);
   11142           0 :     MOZ_ASSERT(!theDoc->mFullScreenStack.IsEmpty(),
   11143             :                "Ancestor of fullscreen document must also be in fullscreen");
   11144           0 :     if (doc != this) {
   11145           0 :       Element* top = theDoc->FullScreenStackTop();
   11146           0 :       if (top->IsHTMLElement(nsGkAtoms::iframe)) {
   11147           0 :         if (static_cast<HTMLIFrameElement*>(top)->FullscreenFlag()) {
   11148             :           // If this is an iframe, and it explicitly requested
   11149             :           // fullscreen, don't rollback it automatically.
   11150           0 :           break;
   11151             :         }
   11152             :       }
   11153             :     }
   11154           0 :     exitDocs.AppendElement(theDoc);
   11155           0 :     if (theDoc->mFullScreenStack.Length() > 1) {
   11156           0 :       break;
   11157             :     }
   11158             :   }
   11159             : 
   11160           0 :   nsDocument* lastDoc = exitDocs.LastElement();
   11161           0 :   if (!lastDoc->GetParentDocument() &&
   11162           0 :       lastDoc->mFullScreenStack.Length() == 1) {
   11163             :     // If we are fully exiting fullscreen, don't touch anything here,
   11164             :     // just wait for the window to get out from fullscreen first.
   11165           0 :     AskWindowToExitFullscreen(this);
   11166           0 :     return;
   11167             :   }
   11168             : 
   11169             :   // If fullscreen mode is updated the pointer should be unlocked
   11170           0 :   UnlockPointer();
   11171             :   // All documents listed in the array except the last one are going to
   11172             :   // completely exit from the fullscreen state.
   11173           0 :   for (auto i : IntegerRange(exitDocs.Length() - 1)) {
   11174           0 :     exitDocs[i]->CleanupFullscreenState();
   11175             :   }
   11176             :   // The last document will either rollback one fullscreen element, or
   11177             :   // completely exit from the fullscreen state as well.
   11178             :   nsIDocument* newFullscreenDoc;
   11179           0 :   if (lastDoc->mFullScreenStack.Length() > 1) {
   11180           0 :     lastDoc->FullScreenStackPop();
   11181           0 :     newFullscreenDoc = lastDoc;
   11182             :   } else {
   11183           0 :     lastDoc->CleanupFullscreenState();
   11184           0 :     newFullscreenDoc = lastDoc->GetParentDocument();
   11185             :   }
   11186             :   // Dispatch the fullscreenchange event to all document listed.
   11187           0 :   for (nsDocument* d : exitDocs) {
   11188           0 :     DispatchFullScreenChange(d);
   11189             :   }
   11190             : 
   11191           0 :   MOZ_ASSERT(newFullscreenDoc, "If we were going to exit from fullscreen on "
   11192             :              "all documents in this doctree, we should've asked the window to "
   11193             :              "exit first instead of reaching here.");
   11194           0 :   if (fullScreenDoc != newFullscreenDoc &&
   11195           0 :       !nsContentUtils::HaveEqualPrincipals(fullScreenDoc, newFullscreenDoc)) {
   11196             :     // We've popped so enough off the stack that we've rolled back to
   11197             :     // a fullscreen element in a parent document. If this document is
   11198             :     // cross origin, dispatch an event to chrome so it knows to show
   11199             :     // the warning UI.
   11200           0 :     DispatchCustomEventWithFlush(
   11201           0 :       newFullscreenDoc, NS_LITERAL_STRING("MozDOMFullscreen:NewOrigin"),
   11202           0 :       /* Bubbles */ true, /* ChromeOnly */ true);
   11203             :   }
   11204             : }
   11205             : 
   11206           0 : class nsCallRequestFullScreen : public Runnable
   11207             : {
   11208             : public:
   11209           0 :   explicit nsCallRequestFullScreen(UniquePtr<FullscreenRequest>&& aRequest)
   11210           0 :     : mozilla::Runnable("nsCallRequestFullScreen")
   11211           0 :     , mRequest(Move(aRequest))
   11212             :   {
   11213           0 :   }
   11214             : 
   11215           0 :   NS_IMETHOD Run() override
   11216             :   {
   11217           0 :     mRequest->GetDocument()->RequestFullScreen(Move(mRequest));
   11218           0 :     return NS_OK;
   11219             :   }
   11220             : 
   11221             :   UniquePtr<FullscreenRequest> mRequest;
   11222             : };
   11223             : 
   11224             : void
   11225           0 : nsDocument::AsyncRequestFullScreen(UniquePtr<FullscreenRequest>&& aRequest)
   11226             : {
   11227           0 :   if (!aRequest->GetElement()) {
   11228           0 :     MOZ_ASSERT_UNREACHABLE(
   11229             :       "Must pass non-null element to nsDocument::AsyncRequestFullScreen");
   11230             :     return;
   11231             :   }
   11232             : 
   11233             :   // Request full-screen asynchronously.
   11234           0 :   MOZ_RELEASE_ASSERT(NS_IsMainThread());
   11235           0 :   nsCOMPtr<nsIRunnable> event = new nsCallRequestFullScreen(Move(aRequest));
   11236           0 :   Dispatch("nsCallRequestFullScreen", TaskCategory::Other, event.forget());
   11237           0 : }
   11238             : 
   11239             : void
   11240           0 : nsIDocument::DispatchFullscreenError(const char* aMessage)
   11241             : {
   11242             :   RefPtr<AsyncEventDispatcher> asyncDispatcher =
   11243             :     new AsyncEventDispatcher(this,
   11244           0 :                              NS_LITERAL_STRING("fullscreenerror"),
   11245             :                              true,
   11246           0 :                              false);
   11247           0 :   asyncDispatcher->PostDOMEvent();
   11248           0 :   nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
   11249           0 :                                   NS_LITERAL_CSTRING("DOM"), this,
   11250             :                                   nsContentUtils::eDOM_PROPERTIES,
   11251           0 :                                   aMessage);
   11252           0 : }
   11253             : 
   11254             : static void
   11255           0 : UpdateViewportScrollbarOverrideForFullscreen(nsIDocument* aDoc)
   11256             : {
   11257           0 :   if (nsIPresShell* presShell = aDoc->GetShell()) {
   11258           0 :     if (nsPresContext* presContext = presShell->GetPresContext()) {
   11259           0 :       presContext->UpdateViewportScrollbarStylesOverride();
   11260             :     }
   11261             :   }
   11262           0 : }
   11263             : 
   11264             : static void
   11265           0 : ClearFullscreenStateOnElement(Element* aElement)
   11266             : {
   11267             :   // Remove styles from existing top element.
   11268           0 :   EventStateManager::SetFullScreenState(aElement, false);
   11269             :   // Reset iframe fullscreen flag.
   11270           0 :   if (aElement->IsHTMLElement(nsGkAtoms::iframe)) {
   11271           0 :     static_cast<HTMLIFrameElement*>(aElement)->SetFullscreenFlag(false);
   11272             :   }
   11273           0 : }
   11274             : 
   11275             : void
   11276           0 : nsDocument::CleanupFullscreenState()
   11277             : {
   11278             :   // Iterate the fullscreen stack and clear the fullscreen states.
   11279             :   // Since we also need to clear the fullscreen-ancestor state, and
   11280             :   // currently fullscreen elements can only be placed in hierarchy
   11281             :   // order in the stack, reversely iterating the stack could be more
   11282             :   // efficient. NOTE that fullscreen-ancestor state would be removed
   11283             :   // in bug 1199529, and the elements may not in hierarchy order
   11284             :   // after bug 1195213.
   11285           0 :   for (nsWeakPtr& weakPtr : Reversed(mFullScreenStack)) {
   11286           0 :     if (nsCOMPtr<Element> element = do_QueryReferent(weakPtr)) {
   11287           0 :       ClearFullscreenStateOnElement(element);
   11288             :     }
   11289             :   }
   11290           0 :   mFullScreenStack.Clear();
   11291           0 :   mFullscreenRoot = nullptr;
   11292           0 :   UpdateViewportScrollbarOverrideForFullscreen(this);
   11293           0 : }
   11294             : 
   11295             : bool
   11296           0 : nsDocument::FullScreenStackPush(Element* aElement)
   11297             : {
   11298           0 :   NS_ASSERTION(aElement, "Must pass non-null to FullScreenStackPush()");
   11299           0 :   Element* top = FullScreenStackTop();
   11300           0 :   if (top == aElement || !aElement) {
   11301           0 :     return false;
   11302             :   }
   11303           0 :   EventStateManager::SetFullScreenState(aElement, true);
   11304           0 :   mFullScreenStack.AppendElement(do_GetWeakReference(aElement));
   11305           0 :   NS_ASSERTION(GetFullscreenElement() == aElement, "Should match");
   11306           0 :   UpdateViewportScrollbarOverrideForFullscreen(this);
   11307           0 :   return true;
   11308             : }
   11309             : 
   11310             : void
   11311           0 : nsDocument::FullScreenStackPop()
   11312             : {
   11313           0 :   if (mFullScreenStack.IsEmpty()) {
   11314           0 :     return;
   11315             :   }
   11316             : 
   11317           0 :   ClearFullscreenStateOnElement(FullScreenStackTop());
   11318             : 
   11319             :   // Remove top element. Note the remaining top element in the stack
   11320             :   // will not have full-screen style bits set, so we will need to restore
   11321             :   // them on the new top element before returning.
   11322           0 :   uint32_t last = mFullScreenStack.Length() - 1;
   11323           0 :   mFullScreenStack.RemoveElementAt(last);
   11324             : 
   11325             :   // Pop from the stack null elements (references to elements which have
   11326             :   // been GC'd since they were added to the stack) and elements which are
   11327             :   // no longer in this document.
   11328           0 :   while (!mFullScreenStack.IsEmpty()) {
   11329           0 :     Element* element = FullScreenStackTop();
   11330           0 :     if (!element || !element->IsInUncomposedDoc() || element->OwnerDoc() != this) {
   11331           0 :       NS_ASSERTION(!element->State().HasState(NS_EVENT_STATE_FULL_SCREEN),
   11332             :                    "Should have already removed full-screen styles");
   11333           0 :       uint32_t last = mFullScreenStack.Length() - 1;
   11334           0 :       mFullScreenStack.RemoveElementAt(last);
   11335             :     } else {
   11336             :       // The top element of the stack is now an in-doc element. Return here.
   11337           0 :       break;
   11338             :     }
   11339             :   }
   11340             : 
   11341           0 :   UpdateViewportScrollbarOverrideForFullscreen(this);
   11342             : }
   11343             : 
   11344             : Element*
   11345          32 : nsDocument::FullScreenStackTop()
   11346             : {
   11347          32 :   if (mFullScreenStack.IsEmpty()) {
   11348          32 :     return nullptr;
   11349             :   }
   11350           0 :   uint32_t last = mFullScreenStack.Length() - 1;
   11351           0 :   nsCOMPtr<Element> element(do_QueryReferent(mFullScreenStack[last]));
   11352           0 :   NS_ASSERTION(element, "Should have full-screen element!");
   11353           0 :   NS_ASSERTION(element->IsInUncomposedDoc(), "Full-screen element should be in doc");
   11354           0 :   NS_ASSERTION(element->OwnerDoc() == this, "Full-screen element should be in this doc");
   11355           0 :   return element;
   11356             : }
   11357             : 
   11358             : /* virtual */ nsTArray<Element*>
   11359          53 : nsDocument::GetFullscreenStack() const
   11360             : {
   11361          53 :   nsTArray<Element*> elements;
   11362          53 :   for (const nsWeakPtr& ptr : mFullScreenStack) {
   11363           0 :     if (nsCOMPtr<Element> elem = do_QueryReferent(ptr)) {
   11364           0 :       MOZ_ASSERT(elem->State().HasState(NS_EVENT_STATE_FULL_SCREEN));
   11365           0 :       elements.AppendElement(elem);
   11366             :     }
   11367             :   }
   11368          53 :   return elements;
   11369             : }
   11370             : 
   11371             : // Returns true if aDoc is in the focused tab in the active window.
   11372             : static bool
   11373           0 : IsInActiveTab(nsIDocument* aDoc)
   11374             : {
   11375           0 :   nsCOMPtr<nsIDocShell> docshell = aDoc->GetDocShell();
   11376           0 :   if (!docshell) {
   11377           0 :     return false;
   11378             :   }
   11379             : 
   11380           0 :   bool isActive = false;
   11381           0 :   docshell->GetIsActive(&isActive);
   11382           0 :   if (!isActive) {
   11383           0 :     return false;
   11384             :   }
   11385             : 
   11386           0 :   nsCOMPtr<nsIDocShellTreeItem> rootItem;
   11387           0 :   docshell->GetRootTreeItem(getter_AddRefs(rootItem));
   11388           0 :   if (!rootItem) {
   11389           0 :     return false;
   11390             :   }
   11391           0 :   nsCOMPtr<nsPIDOMWindowOuter> rootWin = rootItem->GetWindow();
   11392           0 :   if (!rootWin) {
   11393           0 :     return false;
   11394             :   }
   11395             : 
   11396           0 :   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
   11397           0 :   if (!fm) {
   11398           0 :     return false;
   11399             :   }
   11400             : 
   11401           0 :   nsCOMPtr<mozIDOMWindowProxy> activeWindow;
   11402           0 :   fm->GetActiveWindow(getter_AddRefs(activeWindow));
   11403           0 :   if (!activeWindow) {
   11404           0 :     return false;
   11405             :   }
   11406             : 
   11407           0 :   return activeWindow == rootWin;
   11408             : }
   11409             : 
   11410           0 : nsresult nsDocument::RemoteFrameFullscreenChanged(nsIDOMElement* aFrameElement)
   11411             : {
   11412             :   // Ensure the frame element is the fullscreen element in this document.
   11413             :   // If the frame element is already the fullscreen element in this document,
   11414             :   // this has no effect.
   11415           0 :   nsCOMPtr<nsIContent> content(do_QueryInterface(aFrameElement));
   11416           0 :   auto request = MakeUnique<FullscreenRequest>(content->AsElement());
   11417           0 :   request->mIsCallerChrome = false;
   11418           0 :   request->mShouldNotifyNewOrigin = false;
   11419           0 :   RequestFullScreen(Move(request));
   11420             : 
   11421           0 :   return NS_OK;
   11422             : }
   11423             : 
   11424           0 : nsresult nsDocument::RemoteFrameFullscreenReverted()
   11425             : {
   11426           0 :   RestorePreviousFullScreenState();
   11427           0 :   return NS_OK;
   11428             : }
   11429             : 
   11430             : /* static */ bool
   11431          37 : nsDocument::IsUnprefixedFullscreenEnabled(JSContext* aCx, JSObject* aObject)
   11432             : {
   11433          37 :   MOZ_ASSERT(NS_IsMainThread());
   11434          58 :   return nsContentUtils::IsSystemCaller(aCx) ||
   11435          58 :          nsContentUtils::IsUnprefixedFullscreenApiEnabled();
   11436             : }
   11437             : 
   11438             : static bool
   11439           0 : HasFullScreenSubDocument(nsIDocument* aDoc)
   11440             : {
   11441           0 :   uint32_t count = CountFullscreenSubDocuments(aDoc);
   11442           0 :   NS_ASSERTION(count <= 1, "Fullscreen docs should have at most 1 fullscreen child!");
   11443           0 :   return count >= 1;
   11444             : }
   11445             : 
   11446             : // Returns nullptr if a request for Fullscreen API is currently enabled
   11447             : // in the given document. Returns a static string indicates the reason
   11448             : // why it is not enabled otherwise.
   11449             : static const char*
   11450           0 : GetFullscreenError(nsIDocument* aDoc, bool aCallerIsChrome)
   11451             : {
   11452           0 :   bool apiEnabled = nsContentUtils::IsFullScreenApiEnabled();
   11453           0 :   if (apiEnabled && aCallerIsChrome) {
   11454             :     // Chrome code can always use the full-screen API, provided it's not
   11455             :     // explicitly disabled.
   11456           0 :     return nullptr;
   11457             :   }
   11458             : 
   11459           0 :   if (!apiEnabled) {
   11460           0 :     return "FullscreenDeniedDisabled";
   11461             :   }
   11462             : 
   11463             :   // Ensure that all containing elements are <iframe> and have
   11464             :   // allowfullscreen attribute set.
   11465           0 :   nsCOMPtr<nsIDocShell> docShell(aDoc->GetDocShell());
   11466           0 :   if (!docShell || !docShell->GetFullscreenAllowed()) {
   11467           0 :     return "FullscreenDeniedContainerNotAllowed";
   11468             :   }
   11469           0 :   return nullptr;
   11470             : }
   11471             : 
   11472             : bool
   11473           0 : nsDocument::FullscreenElementReadyCheck(Element* aElement,
   11474             :                                         bool aWasCallerChrome)
   11475             : {
   11476           0 :   NS_ASSERTION(aElement,
   11477             :     "Must pass non-null element to nsDocument::RequestFullScreen");
   11478           0 :   if (!aElement || aElement == GetFullscreenElement()) {
   11479           0 :     return false;
   11480             :   }
   11481           0 :   if (!aElement->IsInUncomposedDoc()) {
   11482           0 :     DispatchFullscreenError("FullscreenDeniedNotInDocument");
   11483           0 :     return false;
   11484             :   }
   11485           0 :   if (aElement->OwnerDoc() != this) {
   11486           0 :     DispatchFullscreenError("FullscreenDeniedMovedDocument");
   11487           0 :     return false;
   11488             :   }
   11489           0 :   if (!GetWindow()) {
   11490           0 :     DispatchFullscreenError("FullscreenDeniedLostWindow");
   11491           0 :     return false;
   11492             :   }
   11493           0 :   if (const char* msg = GetFullscreenError(this, aWasCallerChrome)) {
   11494           0 :     DispatchFullscreenError(msg);
   11495           0 :     return false;
   11496             :   }
   11497           0 :   if (!IsVisible()) {
   11498           0 :     DispatchFullscreenError("FullscreenDeniedHidden");
   11499           0 :     return false;
   11500             :   }
   11501           0 :   if (HasFullScreenSubDocument(this)) {
   11502           0 :     DispatchFullscreenError("FullscreenDeniedSubDocFullScreen");
   11503           0 :     return false;
   11504             :   }
   11505           0 :   if (GetFullscreenElement() &&
   11506           0 :       !nsContentUtils::ContentIsDescendantOf(aElement, GetFullscreenElement())) {
   11507             :     // If this document is full-screen, only grant full-screen requests from
   11508             :     // a descendant of the current full-screen element.
   11509           0 :     DispatchFullscreenError("FullscreenDeniedNotDescendant");
   11510           0 :     return false;
   11511             :   }
   11512           0 :   if (!nsContentUtils::IsChromeDoc(this) && !IsInActiveTab(this)) {
   11513           0 :     DispatchFullscreenError("FullscreenDeniedNotFocusedTab");
   11514           0 :     return false;
   11515             :   }
   11516             :   // Deny requests when a windowed plugin is focused.
   11517           0 :   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
   11518           0 :   if (!fm) {
   11519           0 :     NS_WARNING("Failed to retrieve focus manager in full-screen request.");
   11520           0 :     return false;
   11521             :   }
   11522           0 :   nsCOMPtr<nsIDOMElement> focusedElement;
   11523           0 :   fm->GetFocusedElement(getter_AddRefs(focusedElement));
   11524           0 :   if (focusedElement) {
   11525           0 :     nsCOMPtr<nsIContent> content = do_QueryInterface(focusedElement);
   11526           0 :     if (nsContentUtils::HasPluginWithUncontrolledEventDispatch(content)) {
   11527           0 :       DispatchFullscreenError("FullscreenDeniedFocusedPlugin");
   11528           0 :       return false;
   11529             :     }
   11530             :   }
   11531           0 :   return true;
   11532             : }
   11533             : 
   11534           0 : FullscreenRequest::FullscreenRequest(Element* aElement)
   11535             :   : mElement(aElement)
   11536           0 :   , mDocument(static_cast<nsDocument*>(aElement->OwnerDoc()))
   11537             : {
   11538           0 :   MOZ_COUNT_CTOR(FullscreenRequest);
   11539           0 : }
   11540             : 
   11541           0 : FullscreenRequest::~FullscreenRequest()
   11542             : {
   11543           0 :   MOZ_COUNT_DTOR(FullscreenRequest);
   11544           0 : }
   11545             : 
   11546             : // Any fullscreen request waiting for the widget to finish being full-
   11547             : // screen is queued here. This is declared static instead of a member
   11548             : // of nsDocument because in the majority of time, there would be at most
   11549             : // one document requesting fullscreen. We shouldn't waste the space to
   11550             : // hold for it in every document.
   11551             : class PendingFullscreenRequestList
   11552             : {
   11553             : public:
   11554           0 :   static void Add(UniquePtr<FullscreenRequest>&& aRequest)
   11555             :   {
   11556           0 :     sList.insertBack(aRequest.release());
   11557           0 :   }
   11558             : 
   11559             :   static const FullscreenRequest* GetLast()
   11560             :   {
   11561             :     return sList.getLast();
   11562             :   }
   11563             : 
   11564             :   enum IteratorOption
   11565             :   {
   11566             :     // When we are committing fullscreen changes or preparing for
   11567             :     // that, we generally want to iterate all requests in the same
   11568             :     // window with eDocumentsWithSameRoot option.
   11569             :     eDocumentsWithSameRoot,
   11570             :     // If we are removing a document from the tree, we would only
   11571             :     // want to remove the requests from the given document and its
   11572             :     // descendants. For that case, use eInclusiveDescendants.
   11573             :     eInclusiveDescendants
   11574             :   };
   11575             : 
   11576           4 :   class Iterator
   11577             :   {
   11578             :   public:
   11579           4 :     explicit Iterator(nsIDocument* aDoc, IteratorOption aOption)
   11580           4 :       : mCurrent(PendingFullscreenRequestList::sList.getFirst())
   11581           4 :       , mRootShellForIteration(aDoc->GetDocShell())
   11582             :     {
   11583           4 :       if (mCurrent) {
   11584           0 :         if (mRootShellForIteration && aOption == eDocumentsWithSameRoot) {
   11585           0 :           mRootShellForIteration->
   11586           0 :             GetRootTreeItem(getter_AddRefs(mRootShellForIteration));
   11587             :         }
   11588           0 :         SkipToNextMatch();
   11589             :       }
   11590           4 :     }
   11591             : 
   11592           0 :     void DeleteAndNext()
   11593             :     {
   11594           0 :       DeleteAndNextInternal();
   11595           0 :       SkipToNextMatch();
   11596           0 :     }
   11597           4 :     bool AtEnd() const { return mCurrent == nullptr; }
   11598           0 :     const FullscreenRequest& Get() const { return *mCurrent; }
   11599             : 
   11600             :   private:
   11601           0 :     void DeleteAndNextInternal()
   11602             :     {
   11603           0 :       FullscreenRequest* thisRequest = mCurrent;
   11604           0 :       mCurrent = mCurrent->getNext();
   11605           0 :       delete thisRequest;
   11606           0 :     }
   11607           0 :     void SkipToNextMatch()
   11608             :     {
   11609           0 :       while (mCurrent) {
   11610             :         nsCOMPtr<nsIDocShellTreeItem>
   11611           0 :           docShell = mCurrent->GetDocument()->GetDocShell();
   11612           0 :         if (!docShell) {
   11613             :           // Always automatically drop documents which has been
   11614             :           // detached from the doc shell.
   11615           0 :           DeleteAndNextInternal();
   11616             :         } else {
   11617           0 :           while (docShell && docShell != mRootShellForIteration) {
   11618           0 :             docShell->GetParent(getter_AddRefs(docShell));
   11619             :           }
   11620           0 :           if (!docShell) {
   11621             :             // We've gone over the root, but haven't find the target
   11622             :             // ancestor, so skip this item.
   11623           0 :             mCurrent = mCurrent->getNext();
   11624             :           } else {
   11625           0 :             break;
   11626             :           }
   11627             :         }
   11628             :       }
   11629           0 :     }
   11630             : 
   11631             :     FullscreenRequest* mCurrent;
   11632             :     nsCOMPtr<nsIDocShellTreeItem> mRootShellForIteration;
   11633             :   };
   11634             : 
   11635             : private:
   11636             :   PendingFullscreenRequestList() = delete;
   11637             : 
   11638             :   static LinkedList<FullscreenRequest> sList;
   11639             : };
   11640             : 
   11641           3 : /* static */ LinkedList<FullscreenRequest> PendingFullscreenRequestList::sList;
   11642             : 
   11643             : static nsCOMPtr<nsPIDOMWindowOuter>
   11644           0 : GetRootWindow(nsIDocument* aDoc)
   11645             : {
   11646           0 :   nsIDocShell* docShell = aDoc->GetDocShell();
   11647           0 :   if (!docShell) {
   11648           0 :     return nullptr;
   11649             :   }
   11650           0 :   nsCOMPtr<nsIDocShellTreeItem> rootItem;
   11651           0 :   docShell->GetRootTreeItem(getter_AddRefs(rootItem));
   11652           0 :   return rootItem ? rootItem->GetWindow() : nullptr;
   11653             : }
   11654             : 
   11655             : static bool
   11656           0 : ShouldApplyFullscreenDirectly(nsIDocument* aDoc,
   11657             :                               nsPIDOMWindowOuter* aRootWin)
   11658             : {
   11659           0 :   if (XRE_GetProcessType() == GeckoProcessType_Content) {
   11660             :     // If we are in the content process, we can apply the fullscreen
   11661             :     // state directly only if we have been in DOM fullscreen, because
   11662             :     // otherwise we always need to notify the chrome.
   11663           0 :     return !!nsContentUtils::GetRootDocument(aDoc)->GetFullscreenElement();
   11664             :   } else {
   11665             :     // If we are in the chrome process, and the window has not been in
   11666             :     // fullscreen, we certainly need to make that fullscreen first.
   11667           0 :     if (!aRootWin->GetFullScreen()) {
   11668           0 :       return false;
   11669             :     }
   11670             :     // The iterator not being at end indicates there is still some
   11671             :     // pending fullscreen request relates to this document. We have to
   11672             :     // push the request to the pending queue so requests are handled
   11673             :     // in the correct order.
   11674             :     PendingFullscreenRequestList::Iterator
   11675           0 :       iter(aDoc, PendingFullscreenRequestList::eDocumentsWithSameRoot);
   11676           0 :     if (!iter.AtEnd()) {
   11677           0 :       return false;
   11678             :     }
   11679             :     // We have to apply the fullscreen state directly in this case,
   11680             :     // because nsGlobalWindow::SetFullscreenInternal() will do nothing
   11681             :     // if it is already in fullscreen. If we do not apply the state but
   11682             :     // instead add it to the queue and wait for the window as normal,
   11683             :     // we would get stuck.
   11684           0 :     return true;
   11685             :   }
   11686             : }
   11687             : 
   11688             : void
   11689           0 : nsDocument::RequestFullScreen(UniquePtr<FullscreenRequest>&& aRequest)
   11690             : {
   11691           0 :   nsCOMPtr<nsPIDOMWindowOuter> rootWin = GetRootWindow(this);
   11692           0 :   if (!rootWin) {
   11693           0 :     return;
   11694             :   }
   11695             : 
   11696           0 :   if (ShouldApplyFullscreenDirectly(this, rootWin)) {
   11697           0 :     ApplyFullscreen(*aRequest);
   11698           0 :     return;
   11699             :   }
   11700             : 
   11701             :   // Per spec only HTML, <svg>, and <math> should be allowed, but
   11702             :   // we also need to allow XUL elements right now.
   11703           0 :   Element* elem = aRequest->GetElement();
   11704           0 :   if (!elem->IsHTMLElement() && !elem->IsXULElement() &&
   11705           0 :       !elem->IsSVGElement(nsGkAtoms::svg) &&
   11706           0 :       !elem->IsMathMLElement(nsGkAtoms::math)) {
   11707           0 :     DispatchFullscreenError("FullscreenDeniedNotHTMLSVGOrMathML");
   11708           0 :     return;
   11709             :   }
   11710             : 
   11711             :   // We don't need to check element ready before this point, because
   11712             :   // if we called ApplyFullscreen, it would check that for us.
   11713           0 :   if (!FullscreenElementReadyCheck(elem, aRequest->mIsCallerChrome)) {
   11714           0 :     return;
   11715             :   }
   11716             : 
   11717           0 :   PendingFullscreenRequestList::Add(Move(aRequest));
   11718           0 :   if (XRE_GetProcessType() == GeckoProcessType_Content) {
   11719             :     // If we are not the top level process, dispatch an event to make
   11720             :     // our parent process go fullscreen first.
   11721           0 :     nsContentUtils::DispatchEventOnlyToChrome(
   11722           0 :       this, ToSupports(this), NS_LITERAL_STRING("MozDOMFullscreen:Request"),
   11723           0 :       /* Bubbles */ true, /* Cancelable */ false, /* DefaultAction */ nullptr);
   11724             :   } else {
   11725             :     // Make the window fullscreen.
   11726           0 :     rootWin->SetFullscreenInternal(FullscreenReason::ForFullscreenAPI, true);
   11727             :   }
   11728             : }
   11729             : 
   11730             : /* static */ bool
   11731           0 : nsIDocument::HandlePendingFullscreenRequests(nsIDocument* aDoc)
   11732             : {
   11733           0 :   bool handled = false;
   11734             :   PendingFullscreenRequestList::Iterator iter(
   11735           0 :     aDoc, PendingFullscreenRequestList::eDocumentsWithSameRoot);
   11736           0 :   while (!iter.AtEnd()) {
   11737           0 :     const FullscreenRequest& request = iter.Get();
   11738           0 :     if (request.GetDocument()->ApplyFullscreen(request)) {
   11739           0 :       handled = true;
   11740             :     }
   11741           0 :     iter.DeleteAndNext();
   11742             :   }
   11743           0 :   return handled;
   11744             : }
   11745             : 
   11746             : static void
   11747           4 : ClearPendingFullscreenRequests(nsIDocument* aDoc)
   11748             : {
   11749             :   PendingFullscreenRequestList::Iterator iter(
   11750           8 :     aDoc, PendingFullscreenRequestList::eInclusiveDescendants);
   11751           4 :   while (!iter.AtEnd()) {
   11752           0 :     iter.DeleteAndNext();
   11753             :   }
   11754           4 : }
   11755             : 
   11756             : bool
   11757           0 : nsDocument::ApplyFullscreen(const FullscreenRequest& aRequest)
   11758             : {
   11759           0 :   Element* elem = aRequest.GetElement();
   11760           0 :   if (!FullscreenElementReadyCheck(elem, aRequest.mIsCallerChrome)) {
   11761           0 :     return false;
   11762             :   }
   11763             : 
   11764             :   // Stash a reference to any existing fullscreen doc, we'll use this later
   11765             :   // to detect if the origin which is fullscreen has changed.
   11766           0 :   nsCOMPtr<nsIDocument> previousFullscreenDoc = GetFullscreenLeaf(this);
   11767             : 
   11768             :   // Stores a list of documents which we must dispatch "fullscreenchange"
   11769             :   // too. We're required by the spec to dispatch the events in root-to-leaf
   11770             :   // order, but we traverse the doctree in a leaf-to-root order, so we save
   11771             :   // references to the documents we must dispatch to so that we get the order
   11772             :   // as specified.
   11773           0 :   AutoTArray<nsIDocument*, 8> changed;
   11774             : 
   11775             :   // Remember the root document, so that if a full-screen document is hidden
   11776             :   // we can reset full-screen state in the remaining visible full-screen documents.
   11777           0 :   nsIDocument* fullScreenRootDoc = nsContentUtils::GetRootDocument(this);
   11778             : 
   11779             :   // If a document is already in fullscreen, then unlock the mouse pointer
   11780             :   // before setting a new document to fullscreen
   11781           0 :   UnlockPointer();
   11782             : 
   11783             :   // Set the full-screen element. This sets the full-screen style on the
   11784             :   // element, and the full-screen-ancestor styles on ancestors of the element
   11785             :   // in this document.
   11786           0 :   DebugOnly<bool> x = FullScreenStackPush(elem);
   11787           0 :   NS_ASSERTION(x, "Full-screen state of requesting doc should always change!");
   11788             :   // Set the iframe fullscreen flag.
   11789           0 :   if (elem->IsHTMLElement(nsGkAtoms::iframe)) {
   11790           0 :     static_cast<HTMLIFrameElement*>(elem)->SetFullscreenFlag(true);
   11791             :   }
   11792           0 :   changed.AppendElement(this);
   11793             : 
   11794             :   // Propagate up the document hierarchy, setting the full-screen element as
   11795             :   // the element's container in ancestor documents. This also sets the
   11796             :   // appropriate css styles as well. Note we don't propagate down the
   11797             :   // document hierarchy, the full-screen element (or its container) is not
   11798             :   // visible there. Stop when we reach the root document.
   11799           0 :   nsIDocument* child = this;
   11800             :   while (true) {
   11801           0 :     child->SetFullscreenRoot(fullScreenRootDoc);
   11802           0 :     NS_ASSERTION(child->GetFullscreenRoot() == fullScreenRootDoc,
   11803             :         "Fullscreen root should be set!");
   11804           0 :     if (child == fullScreenRootDoc) {
   11805           0 :       break;
   11806             :     }
   11807           0 :     nsIDocument* parent = child->GetParentDocument();
   11808           0 :     Element* element = parent->FindContentForSubDocument(child)->AsElement();
   11809           0 :     if (static_cast<nsDocument*>(parent)->FullScreenStackPush(element)) {
   11810           0 :       changed.AppendElement(parent);
   11811           0 :       child = parent;
   11812             :     } else {
   11813             :       // We've reached either the root, or a point in the doctree where the
   11814             :       // new full-screen element container is the same as the previous
   11815             :       // full-screen element's container. No more changes need to be made
   11816             :       // to the full-screen stacks of documents further up the tree.
   11817           0 :       break;
   11818             :     }
   11819           0 :   }
   11820             : 
   11821           0 :   FullscreenRoots::Add(this);
   11822             : 
   11823             :   // If it is the first entry of the fullscreen, trigger an event so
   11824             :   // that the UI can response to this change, e.g. hide chrome, or
   11825             :   // notifying parent process to enter fullscreen. Note that chrome
   11826             :   // code may also want to listen to MozDOMFullscreen:NewOrigin event
   11827             :   // to pop up warning UI.
   11828           0 :   if (!previousFullscreenDoc) {
   11829           0 :     nsContentUtils::DispatchEventOnlyToChrome(
   11830           0 :       this, ToSupports(elem), NS_LITERAL_STRING("MozDOMFullscreen:Entered"),
   11831           0 :       /* Bubbles */ true, /* Cancelable */ false, /* DefaultAction */ nullptr);
   11832             :   }
   11833             : 
   11834             :   // The origin which is fullscreen gets changed. Trigger an event so
   11835             :   // that the chrome knows to pop up a warning UI. Note that
   11836             :   // previousFullscreenDoc == nullptr upon first entry, so we always
   11837             :   // take this path on the first entry. Also note that, in a multi-
   11838             :   // process browser, the code in content process is responsible for
   11839             :   // sending message with the origin to its parent, and the parent
   11840             :   // shouldn't rely on this event itself.
   11841           0 :   if (aRequest.mShouldNotifyNewOrigin &&
   11842           0 :       !nsContentUtils::HaveEqualPrincipals(previousFullscreenDoc, this)) {
   11843           0 :     DispatchCustomEventWithFlush(
   11844           0 :       this, NS_LITERAL_STRING("MozDOMFullscreen:NewOrigin"),
   11845           0 :       /* Bubbles */ true, /* ChromeOnly */ true);
   11846             :   }
   11847             : 
   11848             :   // Dispatch "fullscreenchange" events. Note this loop is in reverse
   11849             :   // order so that the events for the root document arrives before the leaf
   11850             :   // document, as required by the spec.
   11851           0 :   for (uint32_t i = 0; i < changed.Length(); ++i) {
   11852           0 :     DispatchFullScreenChange(changed[changed.Length() - i - 1]);
   11853             :   }
   11854           0 :   return true;
   11855             : }
   11856             : 
   11857             : Element*
   11858          32 : nsDocument::GetFullscreenElement()
   11859             : {
   11860          32 :   Element* element = FullScreenStackTop();
   11861          32 :   NS_ASSERTION(!element ||
   11862             :                element->State().HasState(NS_EVENT_STATE_FULL_SCREEN),
   11863             :     "Fullscreen element should have fullscreen styles applied");
   11864          32 :   return element;
   11865             : }
   11866             : 
   11867             : bool
   11868           0 : nsDocument::FullscreenEnabled(CallerType aCallerType)
   11869             : {
   11870           0 :   return !GetFullscreenError(this, aCallerType == CallerType::System);
   11871             : }
   11872             : 
   11873             : uint16_t
   11874           0 : nsDocument::CurrentOrientationAngle() const
   11875             : {
   11876           0 :   return mCurrentOrientationAngle;
   11877             : }
   11878             : 
   11879             : OrientationType
   11880           0 : nsDocument::CurrentOrientationType() const
   11881             : {
   11882           0 :   return mCurrentOrientationType;
   11883             : }
   11884             : 
   11885             : void
   11886           1 : nsDocument::SetCurrentOrientation(mozilla::dom::OrientationType aType,
   11887             :                                   uint16_t aAngle)
   11888             : {
   11889           1 :   mCurrentOrientationType = aType;
   11890           1 :   mCurrentOrientationAngle = aAngle;
   11891           1 : }
   11892             : 
   11893             : Promise*
   11894           0 : nsDocument::GetOrientationPendingPromise() const
   11895             : {
   11896           0 :   return mOrientationPendingPromise;
   11897             : }
   11898             : 
   11899             : void
   11900           0 : nsDocument::SetOrientationPendingPromise(Promise* aPromise)
   11901             : {
   11902           0 :   mOrientationPendingPromise = aPromise;
   11903           0 : }
   11904             : 
   11905             : static void
   11906           0 : DispatchPointerLockChange(nsIDocument* aTarget)
   11907             : {
   11908           0 :   if (!aTarget) {
   11909           0 :     return;
   11910             :   }
   11911             : 
   11912             :   RefPtr<AsyncEventDispatcher> asyncDispatcher =
   11913             :     new AsyncEventDispatcher(aTarget,
   11914           0 :                              NS_LITERAL_STRING("pointerlockchange"),
   11915             :                              true,
   11916           0 :                              false);
   11917           0 :   asyncDispatcher->PostDOMEvent();
   11918             : }
   11919             : 
   11920             : static void
   11921           0 : DispatchPointerLockError(nsIDocument* aTarget, const char* aMessage)
   11922             : {
   11923           0 :   if (!aTarget) {
   11924           0 :     return;
   11925             :   }
   11926             : 
   11927             :   RefPtr<AsyncEventDispatcher> asyncDispatcher =
   11928             :     new AsyncEventDispatcher(aTarget,
   11929           0 :                              NS_LITERAL_STRING("pointerlockerror"),
   11930             :                              true,
   11931           0 :                              false);
   11932           0 :   asyncDispatcher->PostDOMEvent();
   11933           0 :   nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
   11934           0 :                                   NS_LITERAL_CSTRING("DOM"), aTarget,
   11935             :                                   nsContentUtils::eDOM_PROPERTIES,
   11936           0 :                                   aMessage);
   11937             : }
   11938             : 
   11939           0 : class PointerLockRequest final : public Runnable
   11940             : {
   11941             : public:
   11942           0 :   PointerLockRequest(Element* aElement, bool aUserInputOrChromeCaller)
   11943           0 :     : mozilla::Runnable("PointerLockRequest")
   11944           0 :     , mElement(do_GetWeakReference(aElement))
   11945           0 :     , mDocument(do_GetWeakReference(aElement->OwnerDoc()))
   11946           0 :     , mUserInputOrChromeCaller(aUserInputOrChromeCaller)
   11947           0 :   {}
   11948             : 
   11949             :   NS_IMETHOD Run() final;
   11950             : 
   11951             : private:
   11952             :   nsWeakPtr mElement;
   11953             :   nsWeakPtr mDocument;
   11954             :   bool mUserInputOrChromeCaller;
   11955             : };
   11956             : 
   11957             : static const char*
   11958           0 : GetPointerLockError(Element* aElement, Element* aCurrentLock,
   11959             :                     bool aNoFocusCheck = false)
   11960             : {
   11961             :   // Check if pointer lock pref is enabled
   11962           0 :   if (!Preferences::GetBool("full-screen-api.pointer-lock.enabled")) {
   11963           0 :     return "PointerLockDeniedDisabled";
   11964             :   }
   11965             : 
   11966           0 :   nsCOMPtr<nsIDocument> ownerDoc = aElement->OwnerDoc();
   11967           0 :   if (aCurrentLock && aCurrentLock->OwnerDoc() != ownerDoc) {
   11968           0 :     return "PointerLockDeniedInUse";
   11969             :   }
   11970             : 
   11971           0 :   if (!aElement->IsInUncomposedDoc()) {
   11972           0 :     return "PointerLockDeniedNotInDocument";
   11973             :   }
   11974             : 
   11975           0 :   if (ownerDoc->GetSandboxFlags() & SANDBOXED_POINTER_LOCK) {
   11976           0 :     return "PointerLockDeniedSandboxed";
   11977             :   }
   11978             : 
   11979             :   // Check if the element is in a document with a docshell.
   11980           0 :   if (!ownerDoc->GetContainer()) {
   11981           0 :     return "PointerLockDeniedHidden";
   11982             :   }
   11983           0 :   nsCOMPtr<nsPIDOMWindowOuter> ownerWindow = ownerDoc->GetWindow();
   11984           0 :   if (!ownerWindow) {
   11985           0 :     return "PointerLockDeniedHidden";
   11986             :   }
   11987           0 :   nsCOMPtr<nsPIDOMWindowInner> ownerInnerWindow = ownerDoc->GetInnerWindow();
   11988           0 :   if (!ownerInnerWindow) {
   11989           0 :     return "PointerLockDeniedHidden";
   11990             :   }
   11991           0 :   if (ownerWindow->GetCurrentInnerWindow() != ownerInnerWindow) {
   11992           0 :     return "PointerLockDeniedHidden";
   11993             :   }
   11994             : 
   11995           0 :   nsCOMPtr<nsPIDOMWindowOuter> top = ownerWindow->GetScriptableTop();
   11996           0 :   if (!top || !top->GetExtantDoc() || top->GetExtantDoc()->Hidden()) {
   11997           0 :     return "PointerLockDeniedHidden";
   11998             :   }
   11999             : 
   12000           0 :   if (!aNoFocusCheck) {
   12001           0 :     mozilla::ErrorResult rv;
   12002           0 :     if (!top->GetExtantDoc()->HasFocus(rv)) {
   12003           0 :       return "PointerLockDeniedNotFocused";
   12004             :     }
   12005             :   }
   12006             : 
   12007           0 :   return nullptr;
   12008             : }
   12009             : 
   12010             : static void
   12011           0 : ChangePointerLockedElement(Element* aElement, nsIDocument* aDocument,
   12012             :                            Element* aPointerLockedElement)
   12013             : {
   12014             :   // aDocument here is not really necessary, as it is the uncomposed
   12015             :   // document of both aElement and aPointerLockedElement as far as one
   12016             :   // is not nullptr, and they wouldn't both be nullptr in any case.
   12017             :   // But since the caller of this function should have known what the
   12018             :   // document is, we just don't try to figure out what it should be.
   12019           0 :   MOZ_ASSERT(aDocument);
   12020           0 :   MOZ_ASSERT(aElement != aPointerLockedElement);
   12021           0 :   if (aPointerLockedElement) {
   12022           0 :     MOZ_ASSERT(aPointerLockedElement->GetUncomposedDoc() == aDocument);
   12023           0 :     aPointerLockedElement->ClearPointerLock();
   12024             :   }
   12025           0 :   if (aElement) {
   12026           0 :     MOZ_ASSERT(aElement->GetUncomposedDoc() == aDocument);
   12027           0 :     aElement->SetPointerLock();
   12028           0 :     EventStateManager::sPointerLockedElement = do_GetWeakReference(aElement);
   12029           0 :     EventStateManager::sPointerLockedDoc = do_GetWeakReference(aDocument);
   12030           0 :     NS_ASSERTION(EventStateManager::sPointerLockedElement &&
   12031             :                  EventStateManager::sPointerLockedDoc,
   12032             :                  "aElement and this should support weak references!");
   12033             :   } else {
   12034           0 :     EventStateManager::sPointerLockedElement = nullptr;
   12035           0 :     EventStateManager::sPointerLockedDoc = nullptr;
   12036             :   }
   12037             :   // Retarget all events to aElement via capture or
   12038             :   // stop retargeting if aElement is nullptr.
   12039           0 :   nsIPresShell::SetCapturingContent(aElement, CAPTURE_POINTERLOCK);
   12040           0 :   DispatchPointerLockChange(aDocument);
   12041           0 : }
   12042             : 
   12043             : NS_IMETHODIMP
   12044           0 : PointerLockRequest::Run()
   12045             : {
   12046           0 :   nsCOMPtr<Element> e = do_QueryReferent(mElement);
   12047           0 :   nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
   12048           0 :   nsDocument* d = static_cast<nsDocument*>(doc.get());
   12049           0 :   const char* error = nullptr;
   12050           0 :   if (!e || !d || !e->GetUncomposedDoc()) {
   12051           0 :     error = "PointerLockDeniedNotInDocument";
   12052           0 :   } else if (e->GetUncomposedDoc() != d) {
   12053           0 :     error = "PointerLockDeniedMovedDocument";
   12054             :   }
   12055           0 :   if (!error) {
   12056             :     nsCOMPtr<Element> pointerLockedElement =
   12057           0 :       do_QueryReferent(EventStateManager::sPointerLockedElement);
   12058           0 :     if (e == pointerLockedElement) {
   12059           0 :       DispatchPointerLockChange(d);
   12060           0 :       return NS_OK;
   12061             :     }
   12062             :     // Note, we must bypass focus change, so pass true as the last parameter!
   12063           0 :     error = GetPointerLockError(e, pointerLockedElement, true);
   12064             :     // Another element in the same document is requesting pointer lock,
   12065             :     // just grant it without user input check.
   12066           0 :     if (!error && pointerLockedElement) {
   12067           0 :       ChangePointerLockedElement(e, d, pointerLockedElement);
   12068           0 :       return NS_OK;
   12069             :     }
   12070             :   }
   12071             :   // If it is neither user input initiated, nor requested in fullscreen,
   12072             :   // it should be rejected.
   12073           0 :   if (!error && !mUserInputOrChromeCaller && !doc->GetFullscreenElement()) {
   12074           0 :     error = "PointerLockDeniedNotInputDriven";
   12075             :   }
   12076           0 :   if (!error && !d->SetPointerLock(e, NS_STYLE_CURSOR_NONE)) {
   12077           0 :     error = "PointerLockDeniedFailedToLock";
   12078             :   }
   12079           0 :   if (error) {
   12080           0 :     DispatchPointerLockError(d, error);
   12081           0 :     return NS_OK;
   12082             :   }
   12083             : 
   12084           0 :   ChangePointerLockedElement(e, d, nullptr);
   12085           0 :   nsContentUtils::DispatchEventOnlyToChrome(
   12086           0 :     doc, ToSupports(e), NS_LITERAL_STRING("MozDOMPointerLock:Entered"),
   12087           0 :     /* Bubbles */ true, /* Cancelable */ false, /* DefaultAction */ nullptr);
   12088           0 :   return NS_OK;
   12089             : }
   12090             : 
   12091             : void
   12092           0 : nsDocument::RequestPointerLock(Element* aElement, CallerType aCallerType)
   12093             : {
   12094           0 :   NS_ASSERTION(aElement,
   12095             :     "Must pass non-null element to nsDocument::RequestPointerLock");
   12096             : 
   12097             :   nsCOMPtr<Element> pointerLockedElement =
   12098           0 :     do_QueryReferent(EventStateManager::sPointerLockedElement);
   12099           0 :   if (aElement == pointerLockedElement) {
   12100           0 :     DispatchPointerLockChange(this);
   12101           0 :     return;
   12102             :   }
   12103             : 
   12104           0 :   if (const char* msg = GetPointerLockError(aElement, pointerLockedElement)) {
   12105           0 :     DispatchPointerLockError(this, msg);
   12106           0 :     return;
   12107             :   }
   12108             : 
   12109           0 :   bool userInputOrSystemCaller = EventStateManager::IsHandlingUserInput() ||
   12110           0 :                                  aCallerType == CallerType::System;
   12111             :   nsCOMPtr<nsIRunnable> request =
   12112           0 :     new PointerLockRequest(aElement, userInputOrSystemCaller);
   12113           0 :   Dispatch("PointerLockRequest", TaskCategory::Other, request.forget());
   12114             : }
   12115             : 
   12116             : bool
   12117           0 : nsDocument::SetPointerLock(Element* aElement, int aCursorStyle)
   12118             : {
   12119           0 :   MOZ_ASSERT(!aElement || aElement->OwnerDoc() == this,
   12120             :              "We should be either unlocking pointer (aElement is nullptr), "
   12121             :              "or locking pointer to an element in this document");
   12122             : #ifdef DEBUG
   12123           0 :   if (!aElement) {
   12124             :     nsCOMPtr<nsIDocument> pointerLockedDoc =
   12125           0 :       do_QueryReferent(EventStateManager::sPointerLockedDoc);
   12126           0 :     MOZ_ASSERT(pointerLockedDoc == this);
   12127             :   }
   12128             : #endif
   12129             : 
   12130           0 :   nsIPresShell* shell = GetShell();
   12131           0 :   if (!shell) {
   12132           0 :     NS_WARNING("SetPointerLock(): No PresShell");
   12133           0 :     if (!aElement) {
   12134             :       // If we are unlocking pointer lock, but for some reason the doc
   12135             :       // has already detached from the presshell, just ask the event
   12136             :       // state manager to release the pointer.
   12137           0 :       EventStateManager::SetPointerLock(nullptr, nullptr);
   12138           0 :       return true;
   12139             :     }
   12140           0 :     return false;
   12141             :   }
   12142           0 :   nsPresContext* presContext = shell->GetPresContext();
   12143           0 :   if (!presContext) {
   12144           0 :     NS_WARNING("SetPointerLock(): Unable to get PresContext");
   12145           0 :     return false;
   12146             :   }
   12147             : 
   12148           0 :   nsCOMPtr<nsIWidget> widget;
   12149           0 :   nsIFrame* rootFrame = shell->GetRootFrame();
   12150           0 :   if (!NS_WARN_IF(!rootFrame)) {
   12151           0 :     widget = rootFrame->GetNearestWidget();
   12152           0 :     NS_WARNING_ASSERTION(
   12153             :       widget,
   12154             :       "SetPointerLock(): Unable to find widget in "
   12155             :       "shell->GetRootFrame()->GetNearestWidget();");
   12156           0 :     if (aElement && !widget) {
   12157           0 :       return false;
   12158             :     }
   12159             :   }
   12160             : 
   12161             :   // Hide the cursor and set pointer lock for future mouse events
   12162           0 :   RefPtr<EventStateManager> esm = presContext->EventStateManager();
   12163           0 :   esm->SetCursor(aCursorStyle, nullptr, false,
   12164           0 :                  0.0f, 0.0f, widget, true);
   12165           0 :   EventStateManager::SetPointerLock(widget, aElement);
   12166             : 
   12167           0 :   return true;
   12168             : }
   12169             : 
   12170             : void
   12171           4 : nsDocument::UnlockPointer(nsIDocument* aDoc)
   12172             : {
   12173           4 :   if (!EventStateManager::sIsPointerLocked) {
   12174           8 :     return;
   12175             :   }
   12176             : 
   12177             :   nsCOMPtr<nsIDocument> pointerLockedDoc =
   12178           0 :     do_QueryReferent(EventStateManager::sPointerLockedDoc);
   12179           0 :   if (!pointerLockedDoc || (aDoc && aDoc != pointerLockedDoc)) {
   12180           0 :     return;
   12181             :   }
   12182           0 :   nsDocument* doc = static_cast<nsDocument*>(pointerLockedDoc.get());
   12183           0 :   if (!doc->SetPointerLock(nullptr, NS_STYLE_CURSOR_AUTO)) {
   12184           0 :     return;
   12185             :   }
   12186             : 
   12187             :   nsCOMPtr<Element> pointerLockedElement =
   12188           0 :     do_QueryReferent(EventStateManager::sPointerLockedElement);
   12189           0 :   ChangePointerLockedElement(nullptr, doc, pointerLockedElement);
   12190             : 
   12191           0 :   nsContentUtils::DispatchEventOnlyToChrome(
   12192           0 :     doc, ToSupports(pointerLockedElement),
   12193           0 :     NS_LITERAL_STRING("MozDOMPointerLock:Exited"),
   12194           0 :     /* Bubbles */ true, /* Cancelable */ false, /* DefaultAction */ nullptr);
   12195             : }
   12196             : 
   12197             : void
   12198           4 : nsIDocument::UnlockPointer(nsIDocument* aDoc)
   12199             : {
   12200           4 :   nsDocument::UnlockPointer(aDoc);
   12201           4 : }
   12202             : 
   12203             : Element*
   12204           0 : nsIDocument::GetPointerLockElement()
   12205             : {
   12206             :   nsCOMPtr<Element> pointerLockedElement =
   12207           0 :     do_QueryReferent(EventStateManager::sPointerLockedElement);
   12208           0 :   if (!pointerLockedElement) {
   12209           0 :     return nullptr;
   12210             :   }
   12211             : 
   12212             :   // Make sure pointer locked element is in the same document.
   12213             :   nsCOMPtr<nsIDocument> pointerLockedDoc =
   12214           0 :     do_QueryReferent(EventStateManager::sPointerLockedDoc);
   12215           0 :   if (pointerLockedDoc != this) {
   12216           0 :     return nullptr;
   12217             :   }
   12218             : 
   12219           0 :   return pointerLockedElement;
   12220             : }
   12221             : 
   12222             : nsresult
   12223           0 : nsDocument::Observe(nsISupports *aSubject,
   12224             :                     const char *aTopic,
   12225             :                     const char16_t *aData)
   12226             : {
   12227           0 :   if (strcmp("service-worker-get-client", aTopic) == 0) {
   12228             :     // No need to generate the ID if it doesn't exist here.  The ID being
   12229             :     // requested must already be generated in order to passed in as
   12230             :     // aSubject.
   12231           0 :     nsString clientId = GetId();
   12232           0 :     if (!clientId.IsEmpty() && clientId.Equals(aData)) {
   12233           0 :       nsCOMPtr<nsISupportsInterfacePointer> ifptr = do_QueryInterface(aSubject);
   12234           0 :       if (ifptr) {
   12235             : #ifdef DEBUG
   12236           0 :         nsCOMPtr<nsISupports> value;
   12237           0 :         MOZ_ALWAYS_SUCCEEDS(ifptr->GetData(getter_AddRefs(value)));
   12238           0 :         MOZ_ASSERT(!value);
   12239             : #endif
   12240           0 :         ifptr->SetData(static_cast<nsIDocument*>(this));
   12241           0 :         ifptr->SetDataIID(&NS_GET_IID(nsIDocument));
   12242             :       }
   12243             :     }
   12244             :   }
   12245           0 :   return NS_OK;
   12246             : }
   12247             : 
   12248             : void
   12249           9 : nsDocument::UpdateVisibilityState()
   12250             : {
   12251           9 :   dom::VisibilityState oldState = mVisibilityState;
   12252           9 :   mVisibilityState = GetVisibilityState();
   12253           9 :   if (oldState != mVisibilityState) {
   12254           4 :     nsContentUtils::DispatchTrustedEvent(this, static_cast<nsIDocument*>(this),
   12255           8 :                                          NS_LITERAL_STRING("visibilitychange"),
   12256             :                                          /* bubbles = */ true,
   12257           8 :                                          /* cancelable = */ false);
   12258           4 :     EnumerateActivityObservers(NotifyActivityChanged, nullptr);
   12259             :   }
   12260             : 
   12261           9 :   if (mVisibilityState == dom::VisibilityState::Visible) {
   12262           5 :     MaybeActiveMediaComponents();
   12263             :   }
   12264           9 : }
   12265             : 
   12266             : VisibilityState
   12267          25 : nsDocument::GetVisibilityState() const
   12268             : {
   12269             :   // We have to check a few pieces of information here:
   12270             :   // 1)  Are we in bfcache (!IsVisible())?  If so, nothing else matters.
   12271             :   // 2)  Do we have an outer window?  If not, we're hidden.  Note that we don't
   12272             :   //     want to use GetWindow here because it does weird groveling for windows
   12273             :   //     in some cases.
   12274             :   // 3)  Is our outer window background?  If so, we're hidden.
   12275             :   // Otherwise, we're visible.
   12276          38 :   if (!IsVisible() || !mWindow || !mWindow->GetOuterWindow() ||
   12277          13 :       mWindow->GetOuterWindow()->IsBackground()) {
   12278             : 
   12279             :     // Check if the document is in prerender state.
   12280          24 :     nsCOMPtr<nsIDocShell> docshell = GetDocShell();
   12281          12 :     if (docshell && docshell->GetIsPrerendered()) {
   12282           0 :       return dom::VisibilityState::Prerender;
   12283             :     }
   12284             : 
   12285          12 :     return dom::VisibilityState::Hidden;
   12286             :   }
   12287             : 
   12288          13 :   return dom::VisibilityState::Visible;
   12289             : }
   12290             : 
   12291             : /* virtual */ void
   12292           0 : nsDocument::PostVisibilityUpdateEvent()
   12293             : {
   12294             :   nsCOMPtr<nsIRunnable> event =
   12295           0 :     NewRunnableMethod("nsDocument::UpdateVisibilityState",
   12296             :                       this,
   12297           0 :                       &nsDocument::UpdateVisibilityState);
   12298           0 :   Dispatch("nsDocument::UpdateVisibilityState", TaskCategory::Other, event.forget());
   12299           0 : }
   12300             : 
   12301             : void
   12302           5 : nsDocument::MaybeActiveMediaComponents()
   12303             : {
   12304           5 :   if (!mWindow) {
   12305           0 :     return;
   12306             :   }
   12307             : 
   12308           5 :   GetWindow()->MaybeActiveMediaComponents();
   12309             : }
   12310             : 
   12311             : NS_IMETHODIMP
   12312           0 : nsDocument::GetHidden(bool* aHidden)
   12313             : {
   12314           0 :   *aHidden = Hidden();
   12315           0 :   return NS_OK;
   12316             : }
   12317             : 
   12318             : NS_IMETHODIMP
   12319           0 : nsDocument::GetVisibilityState(nsAString& aState)
   12320             : {
   12321             :   const EnumEntry& entry =
   12322           0 :     VisibilityStateValues::strings[static_cast<int>(mVisibilityState)];
   12323           0 :   aState.AssignASCII(entry.value, entry.length);
   12324           0 :   return NS_OK;
   12325             : }
   12326             : 
   12327             : /* virtual */ void
   12328          21 : nsIDocument::DocAddSizeOfExcludingThis(nsWindowSizes* aWindowSizes) const
   12329             : {
   12330          21 :   aWindowSizes->mDOMOtherSize +=
   12331          21 :     nsINode::SizeOfExcludingThis(aWindowSizes->mMallocSizeOf);
   12332             : 
   12333          21 :   if (mPresShell) {
   12334          42 :     mPresShell->AddSizeOfIncludingThis(aWindowSizes->mMallocSizeOf,
   12335             :                                        &aWindowSizes->mArenaStats,
   12336             :                                        &aWindowSizes->mLayoutPresShellSize,
   12337             :                                        &aWindowSizes->mLayoutStyleSetsSize,
   12338             :                                        &aWindowSizes->mLayoutTextRunsSize,
   12339             :                                        &aWindowSizes->mLayoutPresContextSize,
   12340          42 :                                        &aWindowSizes->mLayoutFramePropertiesSize);
   12341             :   }
   12342             : 
   12343          21 :   aWindowSizes->mPropertyTablesSize +=
   12344          21 :     mPropertyTable.SizeOfExcludingThis(aWindowSizes->mMallocSizeOf);
   12345          21 :   for (uint32_t i = 0, count = mExtraPropertyTables.Length();
   12346          21 :        i < count; ++i) {
   12347           0 :     aWindowSizes->mPropertyTablesSize +=
   12348           0 :       mExtraPropertyTables[i]->SizeOfIncludingThis(aWindowSizes->mMallocSizeOf);
   12349             :   }
   12350             : 
   12351          21 :   if (EventListenerManager* elm = GetExistingListenerManager()) {
   12352          21 :     aWindowSizes->mDOMEventListenersCount += elm->ListenerCount();
   12353             :   }
   12354             : 
   12355             :   // Measurement of the following members may be added later if DMD finds it
   12356             :   // is worthwhile:
   12357             :   // - many!
   12358          21 : }
   12359             : 
   12360             : void
   12361          21 : nsIDocument::DocAddSizeOfIncludingThis(nsWindowSizes* aWindowSizes) const
   12362             : {
   12363          21 :   aWindowSizes->mDOMOtherSize += aWindowSizes->mMallocSizeOf(this);
   12364          21 :   DocAddSizeOfExcludingThis(aWindowSizes);
   12365          21 : }
   12366             : 
   12367             : static size_t
   12368          84 : SizeOfOwnedSheetArrayExcludingThis(const nsTArray<RefPtr<StyleSheet>>& aSheets,
   12369             :                                    MallocSizeOf aMallocSizeOf)
   12370             : {
   12371          84 :   size_t n = 0;
   12372          84 :   n += aSheets.ShallowSizeOfExcludingThis(aMallocSizeOf);
   12373          89 :   for (StyleSheet* sheet : aSheets) {
   12374           5 :     if (!sheet->GetAssociatedDocument()) {
   12375             :       // Avoid over-reporting shared sheets.
   12376           0 :       continue;
   12377             :     }
   12378           5 :     n += sheet->SizeOfIncludingThis(aMallocSizeOf);
   12379             :   }
   12380          84 :   return n;
   12381             : }
   12382             : 
   12383             : size_t
   12384           0 : nsDocument::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
   12385             : {
   12386             :   // This SizeOfExcludingThis() overrides the one from nsINode.  But
   12387             :   // nsDocuments can only appear at the top of the DOM tree, and we use the
   12388             :   // specialized DocAddSizeOfExcludingThis() in that case.  So this should never
   12389             :   // be called.
   12390           0 :   MOZ_CRASH();
   12391             : }
   12392             : 
   12393             : void
   12394          21 : nsDocument::DocAddSizeOfExcludingThis(nsWindowSizes* aWindowSizes) const
   12395             : {
   12396          21 :   nsIDocument::DocAddSizeOfExcludingThis(aWindowSizes);
   12397             : 
   12398         335 :   for (nsIContent* node = nsINode::GetFirstChild();
   12399         335 :        node;
   12400         314 :        node = node->GetNextNode(this))
   12401             :   {
   12402         314 :     size_t nodeSize = node->SizeOfIncludingThis(aWindowSizes->mMallocSizeOf);
   12403             :     size_t* p;
   12404             : 
   12405         314 :     switch (node->NodeType()) {
   12406             :     case nsIDOMNode::ELEMENT_NODE:
   12407         130 :       p = &aWindowSizes->mDOMElementNodesSize;
   12408         130 :       break;
   12409             :     case nsIDOMNode::TEXT_NODE:
   12410         162 :       p = &aWindowSizes->mDOMTextNodesSize;
   12411         162 :       break;
   12412             :     case nsIDOMNode::CDATA_SECTION_NODE:
   12413           0 :       p = &aWindowSizes->mDOMCDATANodesSize;
   12414           0 :       break;
   12415             :     case nsIDOMNode::COMMENT_NODE:
   12416          22 :       p = &aWindowSizes->mDOMCommentNodesSize;
   12417          22 :       break;
   12418             :     default:
   12419           0 :       p = &aWindowSizes->mDOMOtherSize;
   12420           0 :       break;
   12421             :     }
   12422             : 
   12423         314 :     *p += nodeSize;
   12424             : 
   12425         314 :     if (EventListenerManager* elm = node->GetExistingListenerManager()) {
   12426           0 :       aWindowSizes->mDOMEventListenersCount += elm->ListenerCount();
   12427             :     }
   12428             :   }
   12429             : 
   12430          21 :   aWindowSizes->mStyleSheetsSize +=
   12431          21 :     SizeOfOwnedSheetArrayExcludingThis(mStyleSheets,
   12432          21 :                                        aWindowSizes->mMallocSizeOf);
   12433             :   // Note that we do not own the sheets pointed to by mOnDemandBuiltInUASheets
   12434             :   // (the nsLayoutStyleSheetCache singleton does).
   12435          21 :   aWindowSizes->mStyleSheetsSize +=
   12436          21 :     mOnDemandBuiltInUASheets.ShallowSizeOfExcludingThis(
   12437          21 :         aWindowSizes->mMallocSizeOf);
   12438          84 :   for (auto& sheetArray : mAdditionalSheets) {
   12439          63 :     aWindowSizes->mStyleSheetsSize +=
   12440          63 :       SizeOfOwnedSheetArrayExcludingThis(sheetArray,
   12441          63 :                                          aWindowSizes->mMallocSizeOf);
   12442             :   }
   12443             :   // Lumping in the loader with the style-sheets size is not ideal,
   12444             :   // but most of the things in there are in fact stylesheets, so it
   12445             :   // doesn't seem worthwhile to separate it out.
   12446          21 :   aWindowSizes->mStyleSheetsSize +=
   12447          21 :     CSSLoader()->SizeOfIncludingThis(aWindowSizes->mMallocSizeOf);
   12448             : 
   12449          21 :   aWindowSizes->mDOMOtherSize +=
   12450          42 :     mAttrStyleSheet ?
   12451          21 :     mAttrStyleSheet->DOMSizeOfIncludingThis(aWindowSizes->mMallocSizeOf) :
   12452          42 :     0;
   12453             : 
   12454          21 :   aWindowSizes->mDOMOtherSize +=
   12455          21 :     mStyledLinks.ShallowSizeOfExcludingThis(aWindowSizes->mMallocSizeOf);
   12456             : 
   12457          21 :   aWindowSizes->mDOMOtherSize +=
   12458          21 :     mIdentifierMap.SizeOfExcludingThis(aWindowSizes->mMallocSizeOf);
   12459             : 
   12460             :   // Measurement of the following members may be added later if DMD finds it
   12461             :   // is worthwhile:
   12462             :   // - many!
   12463          21 : }
   12464             : 
   12465             : already_AddRefed<nsIDocument>
   12466           0 : nsIDocument::Constructor(const GlobalObject& aGlobal,
   12467             :                          ErrorResult& rv)
   12468             : {
   12469           0 :   nsCOMPtr<nsIScriptGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
   12470           0 :   if (!global) {
   12471           0 :     rv.Throw(NS_ERROR_UNEXPECTED);
   12472           0 :     return nullptr;
   12473             :   }
   12474             : 
   12475           0 :   nsCOMPtr<nsIScriptObjectPrincipal> prin = do_QueryInterface(aGlobal.GetAsSupports());
   12476           0 :   if (!prin) {
   12477           0 :     rv.Throw(NS_ERROR_UNEXPECTED);
   12478           0 :     return nullptr;
   12479             :   }
   12480             : 
   12481           0 :   nsCOMPtr<nsIURI> uri;
   12482           0 :   NS_NewURI(getter_AddRefs(uri), "about:blank");
   12483           0 :   if (!uri) {
   12484           0 :     rv.Throw(NS_ERROR_OUT_OF_MEMORY);
   12485           0 :     return nullptr;
   12486             :   }
   12487             : 
   12488           0 :   nsCOMPtr<nsIDOMDocument> document;
   12489             :   nsresult res =
   12490           0 :     NS_NewDOMDocument(getter_AddRefs(document),
   12491           0 :                       NullString(),
   12492           0 :                       EmptyString(),
   12493             :                       nullptr,
   12494             :                       uri,
   12495             :                       uri,
   12496           0 :                       prin->GetPrincipal(),
   12497             :                       true,
   12498             :                       global,
   12499           0 :                       DocumentFlavorPlain);
   12500           0 :   if (NS_FAILED(res)) {
   12501           0 :     rv.Throw(res);
   12502           0 :     return nullptr;
   12503             :   }
   12504             : 
   12505           0 :   nsCOMPtr<nsIDocument> doc = do_QueryInterface(document);
   12506           0 :   doc->SetReadyStateInternal(nsIDocument::READYSTATE_COMPLETE);
   12507             : 
   12508           0 :   return doc.forget();
   12509             : }
   12510             : 
   12511             : XPathExpression*
   12512           0 : nsIDocument::CreateExpression(const nsAString& aExpression,
   12513             :                               XPathNSResolver* aResolver,
   12514             :                               ErrorResult& rv)
   12515             : {
   12516           0 :   return XPathEvaluator()->CreateExpression(aExpression, aResolver, rv);
   12517             : }
   12518             : 
   12519             : nsINode*
   12520           0 : nsIDocument::CreateNSResolver(nsINode& aNodeResolver)
   12521             : {
   12522           0 :   return XPathEvaluator()->CreateNSResolver(aNodeResolver);
   12523             : }
   12524             : 
   12525             : already_AddRefed<XPathResult>
   12526           0 : nsIDocument::Evaluate(JSContext* aCx, const nsAString& aExpression,
   12527             :                       nsINode& aContextNode, XPathNSResolver* aResolver,
   12528             :                       uint16_t aType, JS::Handle<JSObject*> aResult,
   12529             :                       ErrorResult& rv)
   12530             : {
   12531             :   return XPathEvaluator()->Evaluate(aCx, aExpression, aContextNode, aResolver,
   12532           0 :                                     aType, aResult, rv);
   12533             : }
   12534             : 
   12535             : NS_IMETHODIMP
   12536           0 : nsDocument::Evaluate(const nsAString& aExpression, nsIDOMNode* aContextNode,
   12537             :                      nsIDOMNode* aResolver, uint16_t aType,
   12538             :                      nsISupports* aInResult, nsISupports** aResult)
   12539             : {
   12540           0 :   return XPathEvaluator()->Evaluate(aExpression, aContextNode, aResolver, aType,
   12541           0 :                                     aInResult, aResult);
   12542             : }
   12543             : 
   12544             : nsIDocument*
   12545          27 : nsIDocument::GetTopLevelContentDocument()
   12546             : {
   12547             :   nsIDocument* parent;
   12548             : 
   12549          27 :   if (!mLoadedAsData) {
   12550          27 :     parent = this;
   12551             :   } else {
   12552           0 :     nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(GetScopeObject());
   12553           0 :     if (!window) {
   12554           0 :       return nullptr;
   12555             :     }
   12556             : 
   12557           0 :     parent = window->GetExtantDoc();
   12558           0 :     if (!parent) {
   12559           0 :       return nullptr;
   12560             :     }
   12561             :   }
   12562             : 
   12563           0 :   do {
   12564          27 :     if (parent->IsTopLevelContentDocument()) {
   12565           0 :       break;
   12566             :     }
   12567             : 
   12568             :     // If we ever have a non-content parent before we hit a toplevel content
   12569             :     // parent, then we're never going to find one.  Just bail.
   12570          27 :     if (!parent->IsContentDocument()) {
   12571          27 :       return nullptr;
   12572             :     }
   12573             : 
   12574           0 :     nsIDocument* candidate = parent->GetParentDocument();
   12575           0 :     parent = static_cast<nsDocument*>(candidate);
   12576           0 :   } while (parent);
   12577             : 
   12578           0 :   return parent;
   12579             : }
   12580             : 
   12581             : void
   12582          25 : nsIDocument::PropagateUseCounters(nsIDocument* aParentDocument)
   12583             : {
   12584          25 :   MOZ_ASSERT(this != aParentDocument);
   12585             : 
   12586             :   // What really matters here is that our use counters get propagated as
   12587             :   // high up in the content document hierarchy as possible.  So,
   12588             :   // starting with aParentDocument, we need to find the toplevel content
   12589             :   // document, and propagate our use counters into its
   12590             :   // mChildDocumentUseCounters.
   12591          25 :   nsIDocument* contentParent = aParentDocument->GetTopLevelContentDocument();
   12592             : 
   12593          25 :   if (!contentParent) {
   12594          25 :     return;
   12595             :   }
   12596             : 
   12597           0 :   contentParent->mChildDocumentUseCounters |= mUseCounters;
   12598           0 :   contentParent->mChildDocumentUseCounters |= mChildDocumentUseCounters;
   12599             : }
   12600             : 
   12601             : void
   12602         115 : nsIDocument::SetPageUseCounter(UseCounter aUseCounter)
   12603             : {
   12604             :   // We want to set the use counter on the "page" that owns us; the definition
   12605             :   // of "page" depends on what kind of document we are.  See the comments below
   12606             :   // for details.  In any event, checking all the conditions below is
   12607             :   // reasonably expensive, so we cache whether we've notified our owning page.
   12608         115 :   if (mNotifiedPageForUseCounter[aUseCounter]) {
   12609          89 :     return;
   12610             :   }
   12611          26 :   mNotifiedPageForUseCounter[aUseCounter] = true;
   12612             : 
   12613          26 :   if (mDisplayDocument) {
   12614             :     // If we are a resource document, we won't have a docshell and so we won't
   12615             :     // record any page use counters on this document.  Instead, we should
   12616             :     // forward it up to the document that loaded us.
   12617           0 :     MOZ_ASSERT(!mDocumentContainer);
   12618           0 :     mDisplayDocument->SetChildDocumentUseCounter(aUseCounter);
   12619           0 :     return;
   12620             :   }
   12621             : 
   12622          26 :   if (IsBeingUsedAsImage()) {
   12623             :     // If this is an SVG image document, we also won't have a docshell.
   12624          24 :     MOZ_ASSERT(!mDocumentContainer);
   12625          24 :     return;
   12626             :   }
   12627             : 
   12628             :   // We only care about use counters in content.  If we're already a toplevel
   12629             :   // content document, then we should have already set the use counter on
   12630             :   // ourselves, and we are done.
   12631           2 :   nsIDocument* contentParent = GetTopLevelContentDocument();
   12632           2 :   if (!contentParent) {
   12633           2 :     return;
   12634             :   }
   12635             : 
   12636           0 :   if (this == contentParent) {
   12637           0 :     MOZ_ASSERT(GetUseCounter(aUseCounter));
   12638           0 :     return;
   12639             :   }
   12640             : 
   12641           0 :   contentParent->SetChildDocumentUseCounter(aUseCounter);
   12642             : }
   12643             : 
   12644             : bool
   12645         577 : nsIDocument::HasScriptsBlockedBySandbox()
   12646             : {
   12647         577 :   return mSandboxFlags & SANDBOXED_SCRIPTS;
   12648             : }
   12649             : 
   12650             : bool
   12651           0 : nsIDocument::InlineScriptAllowedByCSP()
   12652             : {
   12653             :   // this function assumes the inline script is parser created
   12654             :   //  (e.g., before setting attribute(!) event handlers)
   12655           0 :   nsCOMPtr<nsIContentSecurityPolicy> csp;
   12656           0 :   nsresult rv = NodePrincipal()->GetCsp(getter_AddRefs(csp));
   12657           0 :   NS_ENSURE_SUCCESS(rv, true);
   12658           0 :   bool allowsInlineScript = true;
   12659           0 :   if (csp) {
   12660           0 :     nsresult rv = csp->GetAllowsInline(nsIContentPolicy::TYPE_SCRIPT,
   12661           0 :                                        EmptyString(), // aNonce
   12662             :                                        true,          // aParserCreated
   12663           0 :                                        EmptyString(), // FIXME get script sample (bug 1314567)
   12664             :                                        0,             // aLineNumber
   12665           0 :                                        &allowsInlineScript);
   12666           0 :     NS_ENSURE_SUCCESS(rv, true);
   12667             :   }
   12668           0 :   return allowsInlineScript;
   12669             : }
   12670             : 
   12671             : static bool
   12672           0 : MightBeAboutOrChromeScheme(nsIURI* aURI)
   12673             : {
   12674           0 :   MOZ_ASSERT(aURI);
   12675           0 :   bool isAbout = true;
   12676           0 :   bool isChrome = true;
   12677           0 :   aURI->SchemeIs("about", &isAbout);
   12678           0 :   aURI->SchemeIs("chrome", &isChrome);
   12679           0 :   return isAbout || isChrome;
   12680             : }
   12681             : 
   12682             : static bool
   12683           0 : ReportExternalResourceUseCounters(nsIDocument* aDocument, void* aData)
   12684             : {
   12685             :   const auto reportKind
   12686           0 :     = nsDocument::UseCounterReportKind::eIncludeExternalResources;
   12687           0 :   static_cast<nsDocument*>(aDocument)->ReportUseCounters(reportKind);
   12688           0 :   return true;
   12689             : }
   12690             : 
   12691             : void
   12692           0 : nsDocument::ReportUseCounters(UseCounterReportKind aKind)
   12693             : {
   12694             :   static const bool sDebugUseCounters = false;
   12695           0 :   if (mReportedUseCounters) {
   12696           0 :     return;
   12697             :   }
   12698             : 
   12699           0 :   mReportedUseCounters = true;
   12700             : 
   12701           0 :   if (aKind == UseCounterReportKind::eIncludeExternalResources) {
   12702           0 :     EnumerateExternalResources(ReportExternalResourceUseCounters, nullptr);
   12703             :   }
   12704             : 
   12705           0 :   if (Telemetry::HistogramUseCounterCount > 0 &&
   12706           0 :       (IsContentDocument() || IsResourceDoc())) {
   12707           0 :     nsCOMPtr<nsIURI> uri;
   12708           0 :     NodePrincipal()->GetURI(getter_AddRefs(uri));
   12709           0 :     if (!uri || MightBeAboutOrChromeScheme(uri)) {
   12710           0 :       return;
   12711             :     }
   12712             : 
   12713             :     if (sDebugUseCounters) {
   12714             :       nsCString spec = uri->GetSpecOrDefault();
   12715             : 
   12716             :       // URIs can be rather long for data documents, so truncate them to
   12717             :       // some reasonable length.
   12718             :       spec.Truncate(std::min(128U, spec.Length()));
   12719             :       printf("-- Use counters for %s --\n", spec.get());
   12720             :     }
   12721             : 
   12722             :     // We keep separate counts for individual documents and top-level
   12723             :     // pages to more accurately track how many web pages might break if
   12724             :     // certain features were removed.  Consider the case of a single
   12725             :     // HTML document with several SVG images and/or iframes with
   12726             :     // sub-documents of their own.  If we maintained a single set of use
   12727             :     // counters and all the sub-documents use a particular feature, then
   12728             :     // telemetry would indicate that we would be breaking N documents if
   12729             :     // that feature were removed.  Whereas with a document/top-level
   12730             :     // page split, we can see that N documents would be affected, but
   12731             :     // only a single web page would be affected.
   12732             : 
   12733             :     // The difference between the values of these two histograms and the
   12734             :     // related use counters below tell us how many pages did *not* use
   12735             :     // the feature in question.  For instance, if we see that a given
   12736             :     // session has destroyed 30 content documents, but a particular use
   12737             :     // counter shows only a count of 5, we can infer that the use
   12738             :     // counter was *not* used in 25 of those 30 documents.
   12739             :     //
   12740             :     // We do things this way, rather than accumulating a boolean flag
   12741             :     // for each use counter, to avoid sending histograms for features
   12742             :     // that don't get widely used.  Doing things in this fashion means
   12743             :     // smaller telemetry payloads and faster processing on the server
   12744             :     // side.
   12745           0 :     Telemetry::Accumulate(Telemetry::CONTENT_DOCUMENTS_DESTROYED, 1);
   12746           0 :     if (IsTopLevelContentDocument()) {
   12747           0 :       Telemetry::Accumulate(Telemetry::TOP_LEVEL_CONTENT_DOCUMENTS_DESTROYED, 1);
   12748             :     }
   12749             : 
   12750           0 :     for (int32_t c = 0;
   12751           0 :          c < eUseCounter_Count; ++c) {
   12752           0 :       UseCounter uc = static_cast<UseCounter>(c);
   12753             : 
   12754             :       Telemetry::HistogramID id =
   12755           0 :         static_cast<Telemetry::HistogramID>(Telemetry::HistogramFirstUseCounter + uc * 2);
   12756           0 :       bool value = GetUseCounter(uc);
   12757             : 
   12758           0 :       if (value) {
   12759             :         if (sDebugUseCounters) {
   12760             :           const char* name = Telemetry::GetHistogramName(id);
   12761             :           if (name) {
   12762             :             printf("  %s", name);
   12763             :           } else {
   12764             :             printf("  #%d", id);
   12765             :           }
   12766             :           printf(": %d\n", value);
   12767             :         }
   12768             : 
   12769           0 :         Telemetry::Accumulate(id, 1);
   12770             :       }
   12771             : 
   12772           0 :       if (IsTopLevelContentDocument()) {
   12773           0 :         id = static_cast<Telemetry::HistogramID>(Telemetry::HistogramFirstUseCounter +
   12774           0 :                                                  uc * 2 + 1);
   12775           0 :         value = GetUseCounter(uc) || GetChildDocumentUseCounter(uc);
   12776             : 
   12777           0 :         if (value) {
   12778             :           if (sDebugUseCounters) {
   12779             :             const char* name = Telemetry::GetHistogramName(id);
   12780             :             if (name) {
   12781             :               printf("  %s", name);
   12782             :             } else {
   12783             :               printf("  #%d", id);
   12784             :             }
   12785             :             printf(": %d\n", value);
   12786             :           }
   12787             : 
   12788           0 :           Telemetry::Accumulate(id, 1);
   12789             :         }
   12790             :       }
   12791             :     }
   12792             :   }
   12793             : 
   12794           0 :   if (IsContentDocument() || IsResourceDoc()) {
   12795           0 :     uint16_t num = mIncCounters[eIncCounter_ScriptTag];
   12796           0 :     Telemetry::Accumulate(Telemetry::DOM_SCRIPT_EVAL_PER_DOCUMENT, num);
   12797             :   }
   12798             : }
   12799             : 
   12800             : void
   12801           0 : nsDocument::AddIntersectionObserver(DOMIntersectionObserver* aObserver)
   12802             : {
   12803           0 :   MOZ_ASSERT(!mIntersectionObservers.Contains(aObserver),
   12804             :              "Intersection observer already in the list");
   12805           0 :   mIntersectionObservers.PutEntry(aObserver);
   12806           0 : }
   12807             : 
   12808             : void
   12809           0 : nsDocument::RemoveIntersectionObserver(DOMIntersectionObserver* aObserver)
   12810             : {
   12811           0 :   mIntersectionObservers.RemoveEntry(aObserver);
   12812           0 : }
   12813             : 
   12814             : void
   12815          74 : nsDocument::UpdateIntersectionObservations()
   12816             : {
   12817          74 :   if (mIntersectionObservers.IsEmpty()) {
   12818          74 :     return;
   12819             :   }
   12820             : 
   12821           0 :   DOMHighResTimeStamp time = 0;
   12822           0 :   if (nsPIDOMWindowInner* window = GetInnerWindow()) {
   12823           0 :     Performance* perf = window->GetPerformance();
   12824           0 :     if (perf) {
   12825           0 :       time = perf->Now();
   12826             :     }
   12827             :   }
   12828           0 :   for (auto iter = mIntersectionObservers.Iter(); !iter.Done(); iter.Next()) {
   12829           0 :     DOMIntersectionObserver* observer = iter.Get()->GetKey();
   12830           0 :     observer->Update(this, time);
   12831             :   }
   12832             : }
   12833             : 
   12834             : void
   12835          74 : nsDocument::ScheduleIntersectionObserverNotification()
   12836             : {
   12837          74 :   if (mIntersectionObservers.IsEmpty()) {
   12838          74 :     return;
   12839             :   }
   12840           0 :   MOZ_RELEASE_ASSERT(NS_IsMainThread());
   12841             :   nsCOMPtr<nsIRunnable> notification =
   12842           0 :     NewRunnableMethod("nsDocument::NotifyIntersectionObservers",
   12843             :                       this,
   12844           0 :                       &nsDocument::NotifyIntersectionObservers);
   12845           0 :   Dispatch("nsDocument::IntersectionObserverNotification", TaskCategory::Other,
   12846           0 :            notification.forget());
   12847             : }
   12848             : 
   12849             : void
   12850           0 : nsDocument::NotifyIntersectionObservers()
   12851             : {
   12852           0 :   nsTArray<RefPtr<DOMIntersectionObserver>> observers(mIntersectionObservers.Count());
   12853           0 :   for (auto iter = mIntersectionObservers.Iter(); !iter.Done(); iter.Next()) {
   12854           0 :     DOMIntersectionObserver* observer = iter.Get()->GetKey();
   12855           0 :     observers.AppendElement(observer);
   12856             :   }
   12857           0 :   for (const auto& observer : observers) {
   12858           0 :     observer->Notify();
   12859             :   }
   12860           0 : }
   12861             : 
   12862             : static bool
   12863           0 : NotifyLayerManagerRecreatedCallback(nsIDocument* aDocument, void* aData)
   12864             : {
   12865           0 :   aDocument->NotifyLayerManagerRecreated();
   12866           0 :   return true;
   12867             : }
   12868             : 
   12869             : void
   12870           0 : nsDocument::NotifyLayerManagerRecreated()
   12871             : {
   12872           0 :   EnumerateActivityObservers(NotifyActivityChanged, nullptr);
   12873           0 :   EnumerateSubDocuments(NotifyLayerManagerRecreatedCallback, nullptr);
   12874           0 : }
   12875             : 
   12876             : XPathEvaluator*
   12877           0 : nsIDocument::XPathEvaluator()
   12878             : {
   12879           0 :   if (!mXPathEvaluator) {
   12880           0 :     mXPathEvaluator = new dom::XPathEvaluator(this);
   12881             :   }
   12882           0 :   return mXPathEvaluator;
   12883             : }
   12884             : 
   12885             : already_AddRefed<nsIDocumentEncoder>
   12886           0 : nsIDocument::GetCachedEncoder()
   12887             : {
   12888           0 :   return mCachedEncoder.forget();
   12889             : }
   12890             : 
   12891             : void
   12892           0 : nsIDocument::SetCachedEncoder(already_AddRefed<nsIDocumentEncoder> aEncoder)
   12893             : {
   12894           0 :   mCachedEncoder = aEncoder;
   12895           0 : }
   12896             : 
   12897             : void
   12898         116 : nsIDocument::SetContentTypeInternal(const nsACString& aType)
   12899             : {
   12900         215 :   if (!IsHTMLOrXHTML() && mDefaultElementType == kNameSpaceID_None &&
   12901          99 :       aType.EqualsLiteral("application/xhtml+xml")) {
   12902           0 :     mDefaultElementType = kNameSpaceID_XHTML;
   12903             :   }
   12904             : 
   12905         116 :   mCachedEncoder = nullptr;
   12906         116 :   mContentType = aType;
   12907         116 : }
   12908             : 
   12909             : nsILoadContext*
   12910        2075 : nsIDocument::GetLoadContext() const
   12911             : {
   12912        2075 :   return mDocumentContainer;
   12913             : }
   12914             : 
   12915             : nsIDocShell*
   12916         291 : nsIDocument::GetDocShell() const
   12917             : {
   12918         291 :   return mDocumentContainer;
   12919             : }
   12920             : 
   12921             : void
   12922           1 : nsIDocument::SetStateObject(nsIStructuredCloneContainer *scContainer)
   12923             : {
   12924           1 :   mStateObjectContainer = scContainer;
   12925           1 :   mStateObjectCached = nullptr;
   12926           1 : }
   12927             : 
   12928             : already_AddRefed<Element>
   12929          23 : nsIDocument::CreateHTMLElement(nsIAtom* aTag)
   12930             : {
   12931          46 :   RefPtr<mozilla::dom::NodeInfo> nodeInfo;
   12932          46 :   nodeInfo = mNodeInfoManager->GetNodeInfo(aTag, nullptr, kNameSpaceID_XHTML,
   12933          23 :                                            nsIDOMNode::ELEMENT_NODE);
   12934          23 :   MOZ_ASSERT(nodeInfo, "GetNodeInfo should never fail");
   12935             : 
   12936          46 :   nsCOMPtr<Element> element;
   12937          46 :   DebugOnly<nsresult> rv = NS_NewHTMLElement(getter_AddRefs(element),
   12938          46 :                                              nodeInfo.forget(),
   12939          69 :                                              mozilla::dom::NOT_FROM_PARSER);
   12940             : 
   12941          23 :   MOZ_ASSERT(NS_SUCCEEDED(rv), "NS_NewHTMLElement should never fail");
   12942          46 :   return element.forget();
   12943             : }
   12944             : 
   12945             : /* static */
   12946             : nsresult
   12947           0 : nsIDocument::GenerateDocumentId(nsAString& aId)
   12948             : {
   12949             :   nsID id;
   12950           0 :   nsresult rv = nsContentUtils::GenerateUUIDInPlace(id);
   12951           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   12952           0 :     return rv;
   12953             :   }
   12954             : 
   12955             :   // Build a string in {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} format
   12956             :   char buffer[NSID_LENGTH];
   12957           0 :   id.ToProvidedString(buffer);
   12958           0 :   NS_ConvertASCIItoUTF16 uuid(buffer);
   12959             : 
   12960             :   // Remove {} and the null terminator
   12961           0 :   aId.Assign(Substring(uuid, 1, NSID_LENGTH - 3));
   12962           0 :   return NS_OK;
   12963             : }
   12964             : 
   12965             : nsresult
   12966           0 : nsIDocument::GetOrCreateId(nsAString& aId)
   12967             : {
   12968           0 :   if (mId.IsEmpty()) {
   12969           0 :     nsresult rv = GenerateDocumentId(mId);
   12970           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   12971           0 :       return rv;
   12972             :     }
   12973             :   }
   12974             : 
   12975           0 :   aId = mId;
   12976           0 :   return NS_OK;
   12977             : }
   12978             : 
   12979             : void
   12980           0 : nsIDocument::SetId(const nsAString& aId)
   12981             : {
   12982             :   // The ID should only be set one time, but we may get the same value
   12983             :   // more than once if the document is controlled coming out of bfcache.
   12984           0 :   MOZ_ASSERT_IF(mId != aId, mId.IsEmpty());
   12985           0 :   mId = aId;
   12986           0 : }
   12987             : 
   12988             : bool
   12989           0 : MarkDocumentTreeToBeInSyncOperation(nsIDocument* aDoc, void* aData)
   12990             : {
   12991             :   nsCOMArray<nsIDocument>* documents =
   12992           0 :     static_cast<nsCOMArray<nsIDocument>*>(aData);
   12993           0 :   if (aDoc) {
   12994           0 :     aDoc->SetIsInSyncOperation(true);
   12995           0 :     if (nsCOMPtr<nsPIDOMWindowInner> window = aDoc->GetInnerWindow()) {
   12996           0 :       window->TimeoutManager().BeginSyncOperation();
   12997             :     }
   12998           0 :     documents->AppendObject(aDoc);
   12999           0 :     aDoc->EnumerateSubDocuments(MarkDocumentTreeToBeInSyncOperation, aData);
   13000             :   }
   13001           0 :   return true;
   13002             : }
   13003             : 
   13004           0 : nsAutoSyncOperation::nsAutoSyncOperation(nsIDocument* aDoc)
   13005             : {
   13006           0 :   mMicroTaskLevel = nsContentUtils::MicroTaskLevel();
   13007           0 :   nsContentUtils::SetMicroTaskLevel(0);
   13008           0 :   if (aDoc) {
   13009           0 :     if (nsPIDOMWindowOuter* win = aDoc->GetWindow()) {
   13010           0 :       if (nsCOMPtr<nsPIDOMWindowOuter> top = win->GetTop()) {
   13011           0 :         nsCOMPtr<nsIDocument> doc = top->GetExtantDoc();
   13012           0 :         MarkDocumentTreeToBeInSyncOperation(doc, &mDocuments);
   13013             :       }
   13014             :     }
   13015             :   }
   13016           0 : }
   13017             : 
   13018           0 : nsAutoSyncOperation::~nsAutoSyncOperation()
   13019             : {
   13020           0 :   for (int32_t i = 0; i < mDocuments.Count(); ++i) {
   13021           0 :     if (nsCOMPtr<nsPIDOMWindowInner> window = mDocuments[i]->GetInnerWindow()) {
   13022           0 :       window->TimeoutManager().EndSyncOperation();
   13023             :     }
   13024           0 :     mDocuments[i]->SetIsInSyncOperation(false);
   13025             :   }
   13026           0 :   nsContentUtils::SetMicroTaskLevel(mMicroTaskLevel);
   13027           0 : }
   13028             : 
   13029             : gfxUserFontSet*
   13030         423 : nsIDocument::GetUserFontSet(bool aFlushUserFontSet)
   13031             : {
   13032             :   // We want to initialize the user font set lazily the first time the
   13033             :   // user asks for it, rather than building it too early and forcing
   13034             :   // rule cascade creation.  Thus we try to enforce the invariant that
   13035             :   // we *never* build the user font set until the first call to
   13036             :   // GetUserFontSet.  However, once it's been requested, we can't wait
   13037             :   // for somebody to call GetUserFontSet in order to rebuild it (see
   13038             :   // comments below in RebuildUserFontSet for why).
   13039             : #ifdef DEBUG
   13040         423 :   bool userFontSetGottenBefore = mGetUserFontSetCalled;
   13041             : #endif
   13042             :   // Set mGetUserFontSetCalled up front, so that FlushUserFontSet will actually
   13043             :   // flush.
   13044         423 :   mGetUserFontSetCalled = true;
   13045         423 :   if (mFontFaceSetDirty && aFlushUserFontSet) {
   13046             :     // If this assertion fails, and there have actually been changes to
   13047             :     // @font-face rules, then we will call StyleChangeReflow in
   13048             :     // FlushUserFontSet.  If we're in the middle of reflow,
   13049             :     // that's a bad thing to do, and the caller was responsible for
   13050             :     // flushing first.  If we're not (e.g., in frame construction), it's
   13051             :     // ok.
   13052           8 :     NS_ASSERTION(!userFontSetGottenBefore ||
   13053             :                  !GetShell() ||
   13054             :                  !GetShell()->IsReflowLocked(),
   13055             :                  "FlushUserFontSet should have been called first");
   13056           8 :     FlushUserFontSet();
   13057             :   }
   13058             : 
   13059         423 :   if (!mFontFaceSet) {
   13060         423 :     return nullptr;
   13061             :   }
   13062             : 
   13063           0 :   return mFontFaceSet->GetUserFontSet();
   13064             : }
   13065             : 
   13066             : void
   13067         204 : nsIDocument::FlushUserFontSet()
   13068             : {
   13069         204 :   if (!mGetUserFontSetCalled) {
   13070          79 :     return; // No one cares about this font set yet, but we want to be careful
   13071             :             // to not unset our mFontFaceSetDirty bit, so when someone really
   13072             :             // does we'll create it.
   13073             :   }
   13074             : 
   13075         125 :   if (mFontFaceSetDirty) {
   13076          13 :     if (gfxPlatform::GetPlatform()->DownloadableFontsEnabled()) {
   13077          26 :       nsTArray<nsFontFaceRuleContainer> rules;
   13078          13 :       nsIPresShell* shell = GetShell();
   13079          13 :       if (shell && !shell->StyleSet()->AppendFontFaceRules(rules)) {
   13080           0 :         return;
   13081             :       }
   13082             : 
   13083          13 :       bool changed = false;
   13084             : 
   13085          13 :       if (!mFontFaceSet && !rules.IsEmpty()) {
   13086           0 :         nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(GetScopeObject());
   13087           0 :         mFontFaceSet = new FontFaceSet(window, this);
   13088             :       }
   13089          13 :       if (mFontFaceSet) {
   13090           0 :         changed = mFontFaceSet->UpdateRules(rules);
   13091             :       }
   13092             : 
   13093             :       // We need to enqueue a style change reflow (for later) to
   13094             :       // reflect that we're modifying @font-face rules.  (However,
   13095             :       // without a reflow, nothing will happen to start any downloads
   13096             :       // that are needed.)
   13097          13 :       if (changed && shell) {
   13098           0 :         nsPresContext* presContext = shell->GetPresContext();
   13099           0 :         if (presContext) {
   13100           0 :           presContext->UserFontSetUpdated();
   13101             :         }
   13102             :       }
   13103             :     }
   13104             : 
   13105          13 :     mFontFaceSetDirty = false;
   13106             :   }
   13107             : }
   13108             : 
   13109             : void
   13110          89 : nsIDocument::RebuildUserFontSet()
   13111             : {
   13112          89 :   if (!mGetUserFontSetCalled) {
   13113             :     // We want to lazily build the user font set the first time it's
   13114             :     // requested (so we don't force creation of rule cascades too
   13115             :     // early), so don't do anything now.
   13116          82 :     return;
   13117             :   }
   13118             : 
   13119           7 :   mFontFaceSetDirty = true;
   13120           7 :   if (nsIPresShell* shell = GetShell()) {
   13121           7 :     shell->SetNeedStyleFlush();
   13122             :   }
   13123             : 
   13124             :   // Somebody has already asked for the user font set, so we need to
   13125             :   // post an event to rebuild it.  Setting the user font set to be dirty
   13126             :   // and lazily rebuilding it isn't sufficient, since it is only the act
   13127             :   // of rebuilding it that will trigger the style change reflow that
   13128             :   // calls GetUserFontSet.  (This reflow causes rebuilding of text runs,
   13129             :   // which starts font loads, whose completion causes another style
   13130             :   // change reflow).
   13131           7 :   if (!mPostedFlushUserFontSet) {
   13132           6 :     MOZ_RELEASE_ASSERT(NS_IsMainThread());
   13133             :     nsCOMPtr<nsIRunnable> ev =
   13134          12 :       NewRunnableMethod("nsIDocument::HandleRebuildUserFontSet",
   13135             :                         this,
   13136          12 :                         &nsIDocument::HandleRebuildUserFontSet);
   13137           6 :     if (NS_SUCCEEDED(Dispatch("nsIDocument::HandleRebuildUserFontSet",
   13138             :                               TaskCategory::Other, ev.forget()))) {
   13139           6 :       mPostedFlushUserFontSet = true;
   13140             :     }
   13141             :   }
   13142             : }
   13143             : 
   13144             : FontFaceSet*
   13145           0 : nsIDocument::Fonts()
   13146             : {
   13147           0 :   if (!mFontFaceSet) {
   13148           0 :     nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(GetScopeObject());
   13149           0 :     mFontFaceSet = new FontFaceSet(window, this);
   13150           0 :     GetUserFontSet();  // this will cause the user font set to be created/updated
   13151             :   }
   13152           0 :   return mFontFaceSet;
   13153             : }
   13154             : 
   13155             : void
   13156           0 : nsIDocument::ReportHasScrollLinkedEffect()
   13157             : {
   13158           0 :   if (mHasScrollLinkedEffect) {
   13159             :     // We already did this once for this document, don't do it again.
   13160           0 :     return;
   13161             :   }
   13162           0 :   mHasScrollLinkedEffect = true;
   13163           0 :   nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
   13164           0 :                                   NS_LITERAL_CSTRING("Async Pan/Zoom"),
   13165             :                                   this, nsContentUtils::eLAYOUT_PROPERTIES,
   13166           0 :                                   "ScrollLinkedEffectFound2");
   13167             : }
   13168             : 
   13169             : void
   13170          28 : nsIDocument::UpdateStyleBackendType()
   13171             : {
   13172          28 :   MOZ_ASSERT(mStyleBackendType == StyleBackendType::None,
   13173             :              "no need to call UpdateStyleBackendType now");
   13174             : 
   13175             :   // Assume Gecko by default.
   13176          28 :   mStyleBackendType = StyleBackendType::Gecko;
   13177             : 
   13178             : #ifdef MOZ_STYLO
   13179             :   if (nsLayoutUtils::StyloEnabled()) {
   13180             :     if (!mDocumentContainer) {
   13181             :       NS_WARNING("stylo: No docshell yet, assuming Gecko style system");
   13182             :     } else if ((IsHTMLOrXHTML() || IsSVGDocument()) &&
   13183             :                IsContentDocument()) {
   13184             :       // Disable stylo for about: pages other than about:blank, since
   13185             :       // they tend to use unsupported selectors like XUL tree pseudos.
   13186             :       bool isAbout = false;
   13187             :       mDocumentURI->SchemeIs("about", &isAbout);
   13188             :       if (!isAbout || NS_IsAboutBlank(mDocumentURI)) {
   13189             :         mStyleBackendType = StyleBackendType::Servo;
   13190             :       }
   13191             :     }
   13192             :   }
   13193             : #endif
   13194          28 : }
   13195             : 
   13196             : /**
   13197             :  * Helper function for |nsDocument::PrincipalFlashClassification|
   13198             :  *
   13199             :  * Adds a table name string to a table list (a comma separated string). The
   13200             :  * table will not be added if the name is an empty string.
   13201             :  */
   13202             : static void
   13203           0 : MaybeAddTableToTableList(const nsACString& aTableNames,
   13204             :                          nsACString& aTableList)
   13205             : {
   13206           0 :   if (aTableNames.IsEmpty()) {
   13207           0 :     return;
   13208             :   }
   13209           0 :   if (!aTableList.IsEmpty()) {
   13210           0 :     aTableList.AppendLiteral(",");
   13211             :   }
   13212           0 :   aTableList.Append(aTableNames);
   13213             : }
   13214             : 
   13215             : /**
   13216             :  * Helper function for |nsDocument::PrincipalFlashClassification|
   13217             :  *
   13218             :  * Takes an array of table names and a comma separated list of table names
   13219             :  * Returns |true| if any table name in the array matches a table name in the
   13220             :  * comma separated list.
   13221             :  */
   13222             : static bool
   13223           0 : ArrayContainsTable(const nsTArray<nsCString>& aTableArray,
   13224             :                    const nsACString& aTableNames)
   13225             : {
   13226           0 :   for (const nsCString& table : aTableArray) {
   13227             :     // This check is sufficient because table names cannot contain commas and
   13228             :     // cannot contain another existing table name.
   13229           0 :     if (FindInReadable(table, aTableNames)) {
   13230           0 :       return true;
   13231             :     }
   13232             :   }
   13233           0 :   return false;
   13234             : }
   13235             : 
   13236             : /**
   13237             :  * Retrieves the classification of the Flash plugins in the document based on
   13238             :  * the classification lists.
   13239             :  *
   13240             :  * For more information, see
   13241             :  * toolkit/components/url-classifier/flash-block-lists.rst
   13242             :  */
   13243             : FlashClassification
   13244           0 : nsDocument::PrincipalFlashClassification()
   13245             : {
   13246             :   nsresult rv;
   13247             : 
   13248           0 :   bool httpOnly = Preferences::GetBool("plugins.http_https_only", true);
   13249           0 :   bool flashBlock = Preferences::GetBool("plugins.flashBlock.enabled", false);
   13250             : 
   13251             :   // If neither pref is on, skip the null-principal and principal URI checks.
   13252           0 :   if (!httpOnly && !flashBlock) {
   13253           0 :     return FlashClassification::Unknown;
   13254             :   }
   13255             : 
   13256           0 :   nsCOMPtr<nsIPrincipal> principal = GetPrincipal();
   13257           0 :   if (principal->GetIsNullPrincipal()) {
   13258           0 :     return FlashClassification::Denied;
   13259             :   }
   13260             : 
   13261           0 :   nsCOMPtr<nsIURI> classificationURI;
   13262           0 :   rv = principal->GetURI(getter_AddRefs(classificationURI));
   13263           0 :   if (NS_FAILED(rv) || !classificationURI) {
   13264           0 :     return FlashClassification::Denied;
   13265             :   }
   13266             : 
   13267           0 :   if (httpOnly) {
   13268             :     // Only allow plugins for documents from an HTTP/HTTPS origin. This should
   13269             :     // allow dependent data: URIs to load plugins, but not:
   13270             :     // * chrome documents
   13271             :     // * "bare" data: loads
   13272             :     // * FTP/gopher/file
   13273           0 :     nsAutoCString scheme;
   13274           0 :     rv = classificationURI->GetScheme(scheme);
   13275           0 :     if (NS_WARN_IF(NS_FAILED(rv)) ||
   13276           0 :         !(scheme.EqualsLiteral("http") || scheme.EqualsLiteral("https"))) {
   13277           0 :       return FlashClassification::Denied;
   13278             :     }
   13279             :   }
   13280             : 
   13281             :   // If flash blocking is disabled, it is equivalent to all sites being
   13282             :   // on neither list.
   13283           0 :   if (!flashBlock) {
   13284           0 :     return FlashClassification::Unknown;
   13285             :   }
   13286             : 
   13287           0 :   nsAutoCString allowTables, allowExceptionsTables,
   13288           0 :                 denyTables, denyExceptionsTables,
   13289           0 :                 subDocDenyTables, subDocDenyExceptionsTables,
   13290           0 :                 tables;
   13291           0 :   Preferences::GetCString("urlclassifier.flashAllowTable", &allowTables);
   13292           0 :   MaybeAddTableToTableList(allowTables, tables);
   13293             :   Preferences::GetCString("urlclassifier.flashAllowExceptTable",
   13294           0 :                           &allowExceptionsTables);
   13295           0 :   MaybeAddTableToTableList(allowExceptionsTables, tables);
   13296           0 :   Preferences::GetCString("urlclassifier.flashTable", &denyTables);
   13297           0 :   MaybeAddTableToTableList(denyTables, tables);
   13298             :   Preferences::GetCString("urlclassifier.flashExceptTable",
   13299           0 :                           &denyExceptionsTables);
   13300           0 :   MaybeAddTableToTableList(denyExceptionsTables, tables);
   13301             : 
   13302           0 :   bool isThirdPartyDoc = IsThirdParty();
   13303           0 :   if (isThirdPartyDoc) {
   13304             :     Preferences::GetCString("urlclassifier.flashSubDocTable",
   13305           0 :                             &subDocDenyTables);
   13306           0 :     MaybeAddTableToTableList(subDocDenyTables, tables);
   13307             :     Preferences::GetCString("urlclassifier.flashSubDocExceptTable",
   13308           0 :                             &subDocDenyExceptionsTables);
   13309           0 :     MaybeAddTableToTableList(subDocDenyExceptionsTables, tables);
   13310             :   }
   13311             : 
   13312           0 :   if (tables.IsEmpty()) {
   13313           0 :     return FlashClassification::Unknown;
   13314             :   }
   13315             : 
   13316             :   nsCOMPtr<nsIURIClassifier> uriClassifier =
   13317           0 :     do_GetService(NS_URICLASSIFIERSERVICE_CONTRACTID, &rv);
   13318           0 :   if (NS_FAILED(rv)) {
   13319           0 :     return FlashClassification::Denied;
   13320             :   }
   13321             : 
   13322           0 :   nsTArray<nsCString> results;
   13323           0 :   rv = uriClassifier->ClassifyLocalWithTables(classificationURI,
   13324             :                                               tables,
   13325           0 :                                               results);
   13326           0 :   if (NS_FAILED(rv)) {
   13327           0 :     if (rv == NS_ERROR_MALFORMED_URI) {
   13328             :       // This means that the URI had no hostname (ex: file://doc.html). In this
   13329             :       // case, we allow the default (Unknown plugin) behavior.
   13330           0 :       return FlashClassification::Unknown;
   13331             :     } else {
   13332           0 :       return FlashClassification::Denied;
   13333             :     }
   13334             :   }
   13335             : 
   13336           0 :   if (results.IsEmpty()) {
   13337           0 :     return FlashClassification::Unknown;
   13338             :   }
   13339             : 
   13340           0 :   if (ArrayContainsTable(results, denyTables) &&
   13341           0 :       !ArrayContainsTable(results, denyExceptionsTables)) {
   13342           0 :     return FlashClassification::Denied;
   13343           0 :   } else if (ArrayContainsTable(results, allowTables) &&
   13344           0 :              !ArrayContainsTable(results, allowExceptionsTables)) {
   13345           0 :     return FlashClassification::Allowed;
   13346             :   }
   13347             : 
   13348           0 :   if (isThirdPartyDoc && ArrayContainsTable(results, subDocDenyTables) &&
   13349           0 :       !ArrayContainsTable(results, subDocDenyExceptionsTables)) {
   13350           0 :     return FlashClassification::Denied;
   13351             :   }
   13352             : 
   13353           0 :   return FlashClassification::Unknown;
   13354             : }
   13355             : 
   13356             : FlashClassification
   13357           0 : nsDocument::ComputeFlashClassification()
   13358             : {
   13359           0 :   nsCOMPtr<nsIDocShellTreeItem> current = this->GetDocShell();
   13360           0 :   if (!current) {
   13361           0 :     return FlashClassification::Denied;
   13362             :   }
   13363           0 :   nsCOMPtr<nsIDocShellTreeItem> parent;
   13364           0 :   DebugOnly<nsresult> rv = current->GetSameTypeParent(getter_AddRefs(parent));
   13365           0 :   MOZ_ASSERT(NS_SUCCEEDED(rv),
   13366             :              "nsIDocShellTreeItem::GetSameTypeParent should never fail");
   13367             : 
   13368           0 :   bool isTopLevel = !parent;
   13369             :   FlashClassification classification;
   13370           0 :   if (isTopLevel) {
   13371           0 :     classification = PrincipalFlashClassification();
   13372             :   } else {
   13373           0 :     nsCOMPtr<nsIDocument> parentDocument = GetParentDocument();
   13374           0 :     if (!parentDocument) {
   13375           0 :       return FlashClassification::Denied;
   13376             :     }
   13377             :     FlashClassification parentClassification =
   13378           0 :       parentDocument->DocumentFlashClassification();
   13379             : 
   13380           0 :     if (parentClassification == FlashClassification::Denied) {
   13381           0 :       classification = FlashClassification::Denied;
   13382             :     } else {
   13383           0 :       classification = PrincipalFlashClassification();
   13384             : 
   13385             :       // Allow unknown children to inherit allowed status from parent, but
   13386             :       // do not allow denied children to do so.
   13387           0 :       if (classification == FlashClassification::Unknown &&
   13388             :           parentClassification == FlashClassification::Allowed) {
   13389           0 :         classification = FlashClassification::Allowed;
   13390             :       }
   13391             :     }
   13392             :   }
   13393             : 
   13394           0 :   return classification;
   13395             : }
   13396             : 
   13397             : /**
   13398             :  * Retrieves the classification of plugins in this document. This is dependent
   13399             :  * on the classification of this document and all parent documents.
   13400             :  * This function is infallible - It must return some classification that
   13401             :  * callers can act on.
   13402             :  *
   13403             :  * This function will NOT return FlashClassification::Unclassified
   13404             :  */
   13405             : FlashClassification
   13406           0 : nsDocument::DocumentFlashClassification()
   13407             : {
   13408           0 :   if (mFlashClassification == FlashClassification::Unclassified) {
   13409           0 :     FlashClassification result = ComputeFlashClassification();
   13410           0 :     mFlashClassification = result;
   13411           0 :     MOZ_ASSERT(result != FlashClassification::Unclassified,
   13412             :       "nsDocument::GetPluginClassification should never return Unclassified");
   13413             :   }
   13414             : 
   13415           0 :   return mFlashClassification;
   13416             : }
   13417             : 
   13418             : /**
   13419             :  * Initializes |mIsThirdParty| if necessary and returns its value. The value
   13420             :  * returned represents whether this document should be considered Third-Party.
   13421             :  *
   13422             :  * A top-level document cannot be a considered Third-Party; only subdocuments
   13423             :  * may. For a subdocument to be considered Third-Party, it must meet ANY ONE
   13424             :  * of the following requirements:
   13425             :  *  - The document's parent is Third-Party
   13426             :  *  - The document has a different scheme (http/https) than its parent document
   13427             :  *  - The document's domain and subdomain do not match those of its parent
   13428             :  *    document.
   13429             :  *
   13430             :  * If there is an error in determining whether the document is Third-Party,
   13431             :  * it will be assumed to be Third-Party for security reasons.
   13432             :  */
   13433             : bool
   13434           0 : nsDocument::IsThirdParty()
   13435             : {
   13436           0 :   if (mIsThirdParty.isSome()) {
   13437           0 :     return mIsThirdParty.value();
   13438             :   }
   13439             : 
   13440           0 :   nsCOMPtr<nsIDocShellTreeItem> docshell = this->GetDocShell();
   13441           0 :   if (!docshell) {
   13442           0 :     mIsThirdParty.emplace(true);
   13443           0 :     return mIsThirdParty.value();
   13444             :   }
   13445             : 
   13446           0 :   nsCOMPtr<nsIDocShellTreeItem> parent;
   13447           0 :   nsresult rv = docshell->GetSameTypeParent(getter_AddRefs(parent));
   13448           0 :   MOZ_ASSERT(NS_SUCCEEDED(rv),
   13449             :              "nsIDocShellTreeItem::GetSameTypeParent should never fail");
   13450           0 :   bool isTopLevel = !parent;
   13451             : 
   13452           0 :   if (isTopLevel) {
   13453           0 :     mIsThirdParty.emplace(false);
   13454           0 :     return mIsThirdParty.value();
   13455             :   }
   13456             : 
   13457           0 :   nsCOMPtr<nsIDocument> parentDocument = GetParentDocument();
   13458           0 :   if (!parentDocument) {
   13459             :     // Failure
   13460           0 :     mIsThirdParty.emplace(true);
   13461           0 :     return mIsThirdParty.value();
   13462             :   }
   13463             : 
   13464           0 :   if (parentDocument->IsThirdParty()) {
   13465           0 :     mIsThirdParty.emplace(true);
   13466           0 :     return mIsThirdParty.value();
   13467             :   }
   13468             : 
   13469           0 :   nsCOMPtr<nsIPrincipal> principal = GetPrincipal();
   13470           0 :   nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(parentDocument,
   13471           0 :                                                              &rv);
   13472           0 :   if (NS_WARN_IF(NS_FAILED(rv) || !sop)) {
   13473             :     // Failure
   13474           0 :     mIsThirdParty.emplace(true);
   13475           0 :     return mIsThirdParty.value();
   13476             :   }
   13477           0 :   nsCOMPtr<nsIPrincipal> parentPrincipal = sop->GetPrincipal();
   13478             : 
   13479           0 :   bool principalsMatch = false;
   13480           0 :   rv = principal->Equals(parentPrincipal, &principalsMatch);
   13481             : 
   13482           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   13483             :     // Failure
   13484           0 :     mIsThirdParty.emplace(true);
   13485           0 :     return mIsThirdParty.value();
   13486             :   }
   13487             : 
   13488           0 :   if (!principalsMatch) {
   13489           0 :     mIsThirdParty.emplace(true);
   13490           0 :     return mIsThirdParty.value();
   13491             :   }
   13492             : 
   13493             :   // Fall-through. Document is not a Third-Party Document.
   13494           0 :   mIsThirdParty.emplace(false);
   13495           0 :   return mIsThirdParty.value();
   13496             : }
   13497             : 
   13498             : static bool
   13499           0 : IsAboutReader(nsIURI* aURI)
   13500             : {
   13501           0 :   if (!aURI) {
   13502           0 :     return false;
   13503             :   }
   13504             : 
   13505           0 :   nsCString spec;
   13506           0 :   aURI->GetSpec(spec);
   13507             : 
   13508             :   // Reader mode URLs look like about:reader?[...].
   13509           0 :   return StringBeginsWith(spec, NS_LITERAL_CSTRING("about:reader"));
   13510             : }
   13511             : 
   13512             : bool
   13513           0 : nsIDocument::IsScopedStyleEnabled()
   13514             : {
   13515           0 :   if (mIsScopedStyleEnabled == eScopedStyle_Unknown) {
   13516             :     // We allow <style scoped> in about:reader pages since on Android
   13517             :     // we use it to inject some in-page UI.  (We currently don't
   13518             :     // support styling about:reader pages in stylo anyway, so for
   13519             :     // now it's OK to enable it here.)
   13520           0 :     mIsScopedStyleEnabled = nsContentUtils::IsChromeDoc(this) ||
   13521           0 :                             IsAboutReader(mDocumentURI) ||
   13522           0 :                             nsContentUtils::IsScopedStylePrefEnabled()
   13523           0 :                               ? eScopedStyle_Enabled
   13524             :                               : eScopedStyle_Disabled;
   13525             :   }
   13526           0 :   return mIsScopedStyleEnabled == eScopedStyle_Enabled;
   13527             : }

Generated by: LCOV version 1.13