LCOV - code coverage report
Current view: top level - dom/html - nsHTMLContentSink.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 269 402 66.9 %
Date: 2017-07-14 16:53:18 Functions: 35 50 70.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : /**
       8             :  * This file is near-OBSOLETE. It is used for about:blank only and for the
       9             :  * HTML element factory.
      10             :  * Don't bother adding new stuff in this file.
      11             :  */
      12             : 
      13             : #include "mozilla/ArrayUtils.h"
      14             : 
      15             : #include "nsContentSink.h"
      16             : #include "nsCOMPtr.h"
      17             : #include "nsReadableUtils.h"
      18             : #include "nsUnicharUtils.h"
      19             : #include "nsIHTMLContentSink.h"
      20             : #include "nsIInterfaceRequestor.h"
      21             : #include "nsIInterfaceRequestorUtils.h"
      22             : #include "nsIURI.h"
      23             : #include "nsIContentViewer.h"
      24             : #include "mozilla/dom/NodeInfo.h"
      25             : #include "mozilla/dom/ScriptLoader.h"
      26             : #include "nsIAppShell.h"
      27             : #include "nsCRT.h"
      28             : #include "prtime.h"
      29             : #include "mozilla/Logging.h"
      30             : #include "nsNodeUtils.h"
      31             : #include "nsIContent.h"
      32             : #include "mozilla/dom/Element.h"
      33             : #include "mozilla/Preferences.h"
      34             : 
      35             : #include "nsGenericHTMLElement.h"
      36             : 
      37             : #include "nsIDOMDocument.h"
      38             : #include "nsIDOMDocumentType.h"
      39             : #include "nsIScriptElement.h"
      40             : 
      41             : #include "nsIComponentManager.h"
      42             : #include "nsIServiceManager.h"
      43             : 
      44             : #include "nsGkAtoms.h"
      45             : #include "nsContentUtils.h"
      46             : #include "nsIChannel.h"
      47             : #include "nsIHttpChannel.h"
      48             : #include "nsIDocShell.h"
      49             : #include "nsIDocument.h"
      50             : #include "nsStubDocumentObserver.h"
      51             : #include "nsIHTMLDocument.h"
      52             : #include "nsIDOMHTMLMapElement.h"
      53             : #include "nsICookieService.h"
      54             : #include "nsTArray.h"
      55             : #include "nsIScriptSecurityManager.h"
      56             : #include "nsIPrincipal.h"
      57             : #include "nsTextFragment.h"
      58             : #include "nsIScriptGlobalObject.h"
      59             : #include "nsNameSpaceManager.h"
      60             : 
      61             : #include "nsIParserService.h"
      62             : 
      63             : #include "nsIStyleSheetLinkingElement.h"
      64             : #include "nsITimer.h"
      65             : #include "nsError.h"
      66             : #include "nsContentPolicyUtils.h"
      67             : #include "nsIScriptContext.h"
      68             : #include "nsStyleLinkElement.h"
      69             : 
      70             : #include "nsWeakReference.h" // nsHTMLElementFactory supports weak references
      71             : #include "nsIPrompt.h"
      72             : #include "nsLayoutCID.h"
      73             : #include "nsIDocShellTreeItem.h"
      74             : 
      75             : #include "nsEscape.h"
      76             : #include "nsNodeInfoManager.h"
      77             : #include "nsContentCreatorFunctions.h"
      78             : #include "mozAutoDocUpdate.h"
      79             : #include "nsTextNode.h"
      80             : 
      81             : using namespace mozilla;
      82             : using namespace mozilla::dom;
      83             : 
      84             : //----------------------------------------------------------------------
      85             : 
      86             : typedef nsGenericHTMLElement*
      87             :   (*contentCreatorCallback)(already_AddRefed<mozilla::dom::NodeInfo>&&,
      88             :                             FromParser aFromParser);
      89             : 
      90             : nsGenericHTMLElement*
      91           0 : NS_NewHTMLNOTUSEDElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
      92             :                          FromParser aFromParser)
      93             : {
      94           0 :   NS_NOTREACHED("The element ctor should never be called");
      95           0 :   return nullptr;
      96             : }
      97             : 
      98             : #define HTML_TAG(_tag, _classname, _interfacename) NS_NewHTML##_classname##Element,
      99             : #define HTML_OTHER(_tag) NS_NewHTMLNOTUSEDElement,
     100             : static const contentCreatorCallback sContentCreatorCallbacks[] = {
     101             :   NS_NewHTMLUnknownElement,
     102             : #include "nsHTMLTagList.h"
     103             : #undef HTML_TAG
     104             : #undef HTML_OTHER
     105             :   NS_NewHTMLUnknownElement
     106             : };
     107             : 
     108             : class SinkContext;
     109             : class HTMLContentSink;
     110             : 
     111             : /**
     112             :  * This class is near-OBSOLETE. It is used for about:blank only.
     113             :  * Don't bother adding new stuff in this file.
     114             :  */
     115             : class HTMLContentSink : public nsContentSink,
     116             :                         public nsIHTMLContentSink
     117             : {
     118             : public:
     119             :   friend class SinkContext;
     120             : 
     121             :   HTMLContentSink();
     122             : 
     123             :   nsresult Init(nsIDocument* aDoc, nsIURI* aURI, nsISupports* aContainer,
     124             :                 nsIChannel* aChannel);
     125             : 
     126             :   // nsISupports
     127             :   NS_DECL_ISUPPORTS_INHERITED
     128           1 :   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLContentSink, nsContentSink)
     129             : 
     130             :   // nsIContentSink
     131             :   NS_IMETHOD WillParse(void) override;
     132             :   NS_IMETHOD WillBuildModel(nsDTDMode aDTDMode) override;
     133             :   NS_IMETHOD DidBuildModel(bool aTerminated) override;
     134             :   NS_IMETHOD WillInterrupt(void) override;
     135             :   NS_IMETHOD WillResume(void) override;
     136             :   NS_IMETHOD SetParser(nsParserBase* aParser) override;
     137             :   virtual void FlushPendingNotifications(FlushType aType) override;
     138             :   virtual void SetDocumentCharset(NotNull<const Encoding*> aEncoding) override;
     139             :   virtual nsISupports *GetTarget() override;
     140             :   virtual bool IsScriptExecuting() override;
     141             : 
     142             :   // nsIHTMLContentSink
     143             :   NS_IMETHOD OpenContainer(ElementType aNodeType) override;
     144             :   NS_IMETHOD CloseContainer(ElementType aTag) override;
     145             : 
     146             : protected:
     147             :   virtual ~HTMLContentSink();
     148             : 
     149             :   nsCOMPtr<nsIHTMLDocument> mHTMLDocument;
     150             : 
     151             :   // The maximum length of a text run
     152             :   int32_t mMaxTextRun;
     153             : 
     154             :   RefPtr<nsGenericHTMLElement> mRoot;
     155             :   RefPtr<nsGenericHTMLElement> mBody;
     156             :   RefPtr<nsGenericHTMLElement> mHead;
     157             : 
     158             :   AutoTArray<SinkContext*, 8> mContextStack;
     159             :   SinkContext* mCurrentContext;
     160             :   SinkContext* mHeadContext;
     161             : 
     162             :   // Boolean indicating whether we've seen a <head> tag that might have had
     163             :   // attributes once already.
     164             :   bool mHaveSeenHead;
     165             : 
     166             :   // Boolean indicating whether we've notified insertion of our root content
     167             :   // yet.  We want to make sure to only do this once.
     168             :   bool mNotifiedRootInsertion;
     169             : 
     170             :   nsresult FlushTags() override;
     171             : 
     172             :   // Routines for tags that require special handling
     173             :   nsresult CloseHTML();
     174             :   nsresult OpenBody();
     175             :   nsresult CloseBody();
     176             : 
     177             :   void CloseHeadContext();
     178             : 
     179             :   // nsContentSink overrides
     180             :   void UpdateChildCounts() override;
     181             : 
     182             :   void NotifyInsert(nsIContent* aContent,
     183             :                     nsIContent* aChildContent,
     184             :                     int32_t aIndexInContainer);
     185             :   void NotifyRootInsertion();
     186             : };
     187             : 
     188             : class SinkContext
     189             : {
     190             : public:
     191             :   explicit SinkContext(HTMLContentSink* aSink);
     192             :   ~SinkContext();
     193             : 
     194             :   nsresult Begin(nsHTMLTag aNodeType, nsGenericHTMLElement* aRoot,
     195             :                  uint32_t aNumFlushed, int32_t aInsertionPoint);
     196             :   nsresult OpenBody();
     197             :   nsresult CloseBody();
     198             :   nsresult End();
     199             : 
     200             :   nsresult GrowStack();
     201             :   nsresult FlushTags();
     202             : 
     203             :   bool     IsCurrentContainer(nsHTMLTag mType);
     204             : 
     205             :   void DidAddContent(nsIContent* aContent);
     206             :   void UpdateChildCounts();
     207             : 
     208             : private:
     209             :   // Function to check whether we've notified for the current content.
     210             :   // What this actually does is check whether we've notified for all
     211             :   // of the parent's kids.
     212             :   bool HaveNotifiedForCurrentContent() const;
     213             : 
     214             : public:
     215             :   HTMLContentSink* mSink;
     216             :   int32_t mNotifyLevel;
     217             : 
     218             :   struct Node {
     219             :     nsHTMLTag mType;
     220             :     nsGenericHTMLElement* mContent;
     221             :     uint32_t mNumFlushed;
     222             :     int32_t mInsertionPoint;
     223             : 
     224             :     nsIContent *Add(nsIContent *child);
     225             :   };
     226             : 
     227             :   Node* mStack;
     228             :   int32_t mStackSize;
     229             :   int32_t mStackPos;
     230             : };
     231             : 
     232             : nsresult
     233          74 : NS_NewHTMLElement(Element** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
     234             :                   FromParser aFromParser, const nsAString* aIs)
     235             : {
     236          74 :   *aResult = nullptr;
     237             : 
     238         148 :   RefPtr<mozilla::dom::NodeInfo> nodeInfo = aNodeInfo;
     239             : 
     240          74 :   nsIParserService* parserService = nsContentUtils::GetParserService();
     241          74 :   if (!parserService)
     242           0 :     return NS_ERROR_OUT_OF_MEMORY;
     243             : 
     244          74 :   nsIAtom *name = nodeInfo->NameAtom();
     245             : 
     246          74 :   NS_ASSERTION(nodeInfo->NamespaceEquals(kNameSpaceID_XHTML),
     247             :                "Trying to HTML elements that don't have the XHTML namespace");
     248             : 
     249          74 :   int32_t tag = parserService->HTMLCaseSensitiveAtomTagToId(name);
     250             : 
     251             :   // Per the Custom Element specification, unknown tags that are valid custom
     252             :   // element names should be HTMLElement instead of HTMLUnknownElement.
     253          74 :   bool isCustomElementName = (tag == eHTMLTag_userdefined &&
     254          74 :                               nsContentUtils::IsCustomElementName(name));
     255          74 :   if (isCustomElementName) {
     256           0 :     NS_IF_ADDREF(*aResult = NS_NewHTMLElement(nodeInfo.forget(), aFromParser));
     257             :   } else {
     258          74 :     *aResult = CreateHTMLElement(tag, nodeInfo.forget(), aFromParser).take();
     259             :   }
     260             : 
     261          74 :   if (!*aResult) {
     262           0 :     return NS_ERROR_OUT_OF_MEMORY;
     263             :   }
     264             : 
     265          74 :   if (CustomElementRegistry::IsCustomElementEnabled() &&
     266           0 :       (isCustomElementName || aIs)) {
     267           0 :     nsContentUtils::SetupCustomElement(*aResult, aIs);
     268             :   }
     269             : 
     270          74 :   return NS_OK;
     271             : }
     272             : 
     273             : already_AddRefed<nsGenericHTMLElement>
     274          74 : CreateHTMLElement(uint32_t aNodeType,
     275             :                   already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
     276             :                   FromParser aFromParser)
     277             : {
     278          74 :   NS_ASSERTION(aNodeType <= NS_HTML_TAG_MAX ||
     279             :                aNodeType == eHTMLTag_userdefined,
     280             :                "aNodeType is out of bounds");
     281             : 
     282          74 :   contentCreatorCallback cb = sContentCreatorCallbacks[aNodeType];
     283             : 
     284          74 :   NS_ASSERTION(cb != NS_NewHTMLNOTUSEDElement,
     285             :                "Don't know how to construct tag element!");
     286             : 
     287         148 :   RefPtr<nsGenericHTMLElement> result = cb(Move(aNodeInfo), aFromParser);
     288             : 
     289         148 :   return result.forget();
     290             : }
     291             : 
     292             : //----------------------------------------------------------------------
     293             : 
     294           1 : SinkContext::SinkContext(HTMLContentSink* aSink)
     295             :   : mSink(aSink),
     296             :     mNotifyLevel(0),
     297             :     mStack(nullptr),
     298             :     mStackSize(0),
     299           1 :     mStackPos(0)
     300             : {
     301           1 :   MOZ_COUNT_CTOR(SinkContext);
     302           1 : }
     303             : 
     304           0 : SinkContext::~SinkContext()
     305             : {
     306           0 :   MOZ_COUNT_DTOR(SinkContext);
     307             : 
     308           0 :   if (mStack) {
     309           0 :     for (int32_t i = 0; i < mStackPos; i++) {
     310           0 :       NS_RELEASE(mStack[i].mContent);
     311             :     }
     312           0 :     delete [] mStack;
     313             :   }
     314           0 : }
     315             : 
     316             : nsresult
     317           1 : SinkContext::Begin(nsHTMLTag aNodeType,
     318             :                    nsGenericHTMLElement* aRoot,
     319             :                    uint32_t aNumFlushed,
     320             :                    int32_t aInsertionPoint)
     321             : {
     322           1 :   if (mStackSize < 1) {
     323           1 :     nsresult rv = GrowStack();
     324           1 :     if (NS_FAILED(rv)) {
     325           0 :       return rv;
     326             :     }
     327             :   }
     328             : 
     329           1 :   mStack[0].mType = aNodeType;
     330           1 :   mStack[0].mContent = aRoot;
     331           1 :   mStack[0].mNumFlushed = aNumFlushed;
     332           1 :   mStack[0].mInsertionPoint = aInsertionPoint;
     333           1 :   NS_ADDREF(aRoot);
     334           1 :   mStackPos = 1;
     335             : 
     336           1 :   return NS_OK;
     337             : }
     338             : 
     339             : bool
     340           1 : SinkContext::IsCurrentContainer(nsHTMLTag aTag)
     341             : {
     342           1 :   if (aTag == mStack[mStackPos - 1].mType) {
     343           0 :     return true;
     344             :   }
     345             : 
     346           1 :   return false;
     347             : }
     348             : 
     349             : void
     350           1 : SinkContext::DidAddContent(nsIContent* aContent)
     351             : {
     352           1 :   if ((mStackPos == 2) && (mSink->mBody == mStack[1].mContent)) {
     353             :     // We just finished adding something to the body
     354           0 :     mNotifyLevel = 0;
     355             :   }
     356             : 
     357             :   // If we just added content to a node for which
     358             :   // an insertion happen, we need to do an immediate
     359             :   // notification for that insertion.
     360           3 :   if (0 < mStackPos &&
     361           1 :       mStack[mStackPos - 1].mInsertionPoint != -1 &&
     362           0 :       mStack[mStackPos - 1].mNumFlushed <
     363           0 :       mStack[mStackPos - 1].mContent->GetChildCount()) {
     364           0 :     nsIContent* parent = mStack[mStackPos - 1].mContent;
     365           0 :     int32_t childIndex = mStack[mStackPos - 1].mInsertionPoint - 1;
     366           0 :     NS_ASSERTION(parent->GetChildAt(childIndex) == aContent,
     367             :                  "Flushing the wrong child.");
     368           0 :     mSink->NotifyInsert(parent, aContent, childIndex);
     369           0 :     mStack[mStackPos - 1].mNumFlushed = parent->GetChildCount();
     370           1 :   } else if (mSink->IsTimeToNotify()) {
     371           0 :     FlushTags();
     372             :   }
     373           1 : }
     374             : 
     375             : nsresult
     376           1 : SinkContext::OpenBody()
     377             : {
     378           1 :   if (mStackPos <= 0) {
     379           0 :     NS_ERROR("container w/o parent");
     380             : 
     381           0 :     return NS_ERROR_FAILURE;
     382             :   }
     383             : 
     384             :   nsresult rv;
     385           1 :   if (mStackPos + 1 > mStackSize) {
     386           0 :     rv = GrowStack();
     387           0 :     if (NS_FAILED(rv)) {
     388           0 :       return rv;
     389             :     }
     390             :   }
     391             : 
     392             :     RefPtr<mozilla::dom::NodeInfo> nodeInfo =
     393           2 :       mSink->mNodeInfoManager->GetNodeInfo(nsGkAtoms::body, nullptr,
     394             :                                            kNameSpaceID_XHTML,
     395           2 :                                            nsIDOMNode::ELEMENT_NODE);
     396           1 :   NS_ENSURE_TRUE(nodeInfo, NS_ERROR_UNEXPECTED);
     397             : 
     398             :   // Make the content object
     399             :   RefPtr<nsGenericHTMLElement> body =
     400           2 :     NS_NewHTMLBodyElement(nodeInfo.forget(), FROM_PARSER_NETWORK);
     401           1 :   if (!body) {
     402           0 :     return NS_ERROR_OUT_OF_MEMORY;
     403             :   }
     404             : 
     405           1 :   mStack[mStackPos].mType = eHTMLTag_body;
     406           1 :   body.forget(&mStack[mStackPos].mContent);
     407           1 :   mStack[mStackPos].mNumFlushed = 0;
     408           1 :   mStack[mStackPos].mInsertionPoint = -1;
     409           1 :   ++mStackPos;
     410           1 :   mStack[mStackPos - 2].Add(mStack[mStackPos - 1].mContent);
     411             : 
     412           1 :   return NS_OK;
     413             : }
     414             : 
     415             : bool
     416           0 : SinkContext::HaveNotifiedForCurrentContent() const
     417             : {
     418           0 :   if (0 < mStackPos) {
     419           0 :     nsIContent* parent = mStack[mStackPos - 1].mContent;
     420           0 :     return mStack[mStackPos-1].mNumFlushed == parent->GetChildCount();
     421             :   }
     422             : 
     423           0 :   return true;
     424             : }
     425             : 
     426             : nsIContent *
     427           1 : SinkContext::Node::Add(nsIContent *child)
     428             : {
     429           1 :   NS_ASSERTION(mContent, "No parent to insert/append into!");
     430           1 :   if (mInsertionPoint != -1) {
     431           0 :     NS_ASSERTION(mNumFlushed == mContent->GetChildCount(),
     432             :                  "Inserting multiple children without flushing.");
     433           0 :     mContent->InsertChildAt(child, mInsertionPoint++, false);
     434             :   } else {
     435           1 :     mContent->AppendChildTo(child, false);
     436             :   }
     437           1 :   return child;
     438             : }
     439             : 
     440             : nsresult
     441           1 : SinkContext::CloseBody()
     442             : {
     443           1 :   NS_ASSERTION(mStackPos > 0,
     444             :                "stack out of bounds. wrong context probably!");
     445             : 
     446           1 :   if (mStackPos <= 0) {
     447           0 :     return NS_OK; // Fix crash - Ref. bug 45975 or 45007
     448             :   }
     449             : 
     450           1 :   --mStackPos;
     451           1 :   NS_ASSERTION(mStack[mStackPos].mType == eHTMLTag_body,
     452             :                "Tag mismatch.  Closing tag on wrong context or something?");
     453             : 
     454           1 :   nsGenericHTMLElement* content = mStack[mStackPos].mContent;
     455             : 
     456           1 :   content->Compact();
     457             : 
     458             :   // If we're in a state where we do append notifications as
     459             :   // we go up the tree, and we're at the level where the next
     460             :   // notification needs to be done, do the notification.
     461           1 :   if (mNotifyLevel >= mStackPos) {
     462             :     // Check to see if new content has been added after our last
     463             :     // notification
     464             : 
     465           1 :     if (mStack[mStackPos].mNumFlushed < content->GetChildCount()) {
     466           0 :       mSink->NotifyAppend(content, mStack[mStackPos].mNumFlushed);
     467           0 :       mStack[mStackPos].mNumFlushed = content->GetChildCount();
     468             :     }
     469             : 
     470             :     // Indicate that notification has now happened at this level
     471           1 :     mNotifyLevel = mStackPos - 1;
     472             :   }
     473             : 
     474           1 :   DidAddContent(content);
     475           1 :   NS_IF_RELEASE(content);
     476             : 
     477           1 :   return NS_OK;
     478             : }
     479             : 
     480             : nsresult
     481           0 : SinkContext::End()
     482             : {
     483           0 :   for (int32_t i = 0; i < mStackPos; i++) {
     484           0 :     NS_RELEASE(mStack[i].mContent);
     485             :   }
     486             : 
     487           0 :   mStackPos = 0;
     488             : 
     489           0 :   return NS_OK;
     490             : }
     491             : 
     492             : nsresult
     493           1 : SinkContext::GrowStack()
     494             : {
     495           1 :   int32_t newSize = mStackSize * 2;
     496           1 :   if (newSize == 0) {
     497           1 :     newSize = 32;
     498             :   }
     499             : 
     500           2 :   Node* stack = new Node[newSize];
     501             : 
     502           1 :   if (mStackPos != 0) {
     503           0 :     memcpy(stack, mStack, sizeof(Node) * mStackPos);
     504           0 :     delete [] mStack;
     505             :   }
     506             : 
     507           1 :   mStack = stack;
     508           1 :   mStackSize = newSize;
     509             : 
     510           1 :   return NS_OK;
     511             : }
     512             : 
     513             : /**
     514             :  * NOTE!! Forked into nsXMLContentSink. Please keep in sync.
     515             :  *
     516             :  * Flush all elements that have been seen so far such that
     517             :  * they are visible in the tree. Specifically, make sure
     518             :  * that they are all added to their respective parents.
     519             :  * Also, do notification at the top for all content that
     520             :  * has been newly added so that the frame tree is complete.
     521             :  */
     522             : nsresult
     523           3 : SinkContext::FlushTags()
     524             : {
     525           3 :   mSink->mDeferredFlushTags = false;
     526           3 :   bool oldBeganUpdate = mSink->mBeganUpdate;
     527           3 :   uint32_t oldUpdates = mSink->mUpdatesInNotification;
     528             : 
     529           3 :   ++(mSink->mInNotification);
     530           3 :   mSink->mUpdatesInNotification = 0;
     531             :   {
     532             :     // Scope so we call EndUpdate before we decrease mInNotification
     533           3 :     mozAutoDocUpdate updateBatch(mSink->mDocument, UPDATE_CONTENT_MODEL,
     534           6 :                                  true);
     535           3 :     mSink->mBeganUpdate = true;
     536             : 
     537             :     // Start from the base of the stack (growing downward) and do
     538             :     // a notification from the node that is closest to the root of
     539             :     // tree for any content that has been added.
     540             : 
     541             :     // Note that we can start at stackPos == 0 here, because it's the caller's
     542             :     // responsibility to handle flushing interactions between contexts (see
     543             :     // HTMLContentSink::BeginContext).
     544           3 :     int32_t stackPos = 0;
     545           3 :     bool flushed = false;
     546             :     uint32_t childCount;
     547             :     nsGenericHTMLElement* content;
     548             : 
     549          13 :     while (stackPos < mStackPos) {
     550           5 :       content = mStack[stackPos].mContent;
     551           5 :       childCount = content->GetChildCount();
     552             : 
     553           5 :       if (!flushed && (mStack[stackPos].mNumFlushed < childCount)) {
     554           0 :         if (mStack[stackPos].mInsertionPoint != -1) {
     555             :           // We might have popped the child off our stack already
     556             :           // but not notified on it yet, which is why we have to get it
     557             :           // directly from its parent node.
     558             : 
     559           0 :           int32_t childIndex = mStack[stackPos].mInsertionPoint - 1;
     560           0 :           nsIContent* child = content->GetChildAt(childIndex);
     561             :           // Child not on stack anymore; can't assert it's correct
     562           0 :           NS_ASSERTION(!(mStackPos > (stackPos + 1)) ||
     563             :                        (child == mStack[stackPos + 1].mContent),
     564             :                        "Flushing the wrong child.");
     565           0 :           mSink->NotifyInsert(content, child, childIndex);
     566             :         } else {
     567           0 :           mSink->NotifyAppend(content, mStack[stackPos].mNumFlushed);
     568             :         }
     569             : 
     570           0 :         flushed = true;
     571             :       }
     572             : 
     573           5 :       mStack[stackPos].mNumFlushed = childCount;
     574           5 :       stackPos++;
     575             :     }
     576           3 :     mNotifyLevel = mStackPos - 1;
     577             :   }
     578           3 :   --(mSink->mInNotification);
     579             : 
     580           3 :   if (mSink->mUpdatesInNotification > 1) {
     581           0 :     UpdateChildCounts();
     582             :   }
     583             : 
     584           3 :   mSink->mUpdatesInNotification = oldUpdates;
     585           3 :   mSink->mBeganUpdate = oldBeganUpdate;
     586             : 
     587           3 :   return NS_OK;
     588             : }
     589             : 
     590             : /**
     591             :  * NOTE!! Forked into nsXMLContentSink. Please keep in sync.
     592             :  */
     593             : void
     594           2 : SinkContext::UpdateChildCounts()
     595             : {
     596             :   // Start from the top of the stack (growing upwards) and see if any
     597             :   // new content has been appended. If so, we recognize that reflows
     598             :   // have been generated for it and we should make sure that no
     599             :   // further reflows occur.  Note that we have to include stackPos == 0
     600             :   // to properly notify on kids of <html>.
     601           2 :   int32_t stackPos = mStackPos - 1;
     602           6 :   while (stackPos >= 0) {
     603           2 :     Node & node = mStack[stackPos];
     604           2 :     node.mNumFlushed = node.mContent->GetChildCount();
     605             : 
     606           2 :     stackPos--;
     607             :   }
     608             : 
     609           2 :   mNotifyLevel = mStackPos - 1;
     610           2 : }
     611             : 
     612             : nsresult
     613           1 : NS_NewHTMLContentSink(nsIHTMLContentSink** aResult,
     614             :                       nsIDocument* aDoc,
     615             :                       nsIURI* aURI,
     616             :                       nsISupports* aContainer,
     617             :                       nsIChannel* aChannel)
     618             : {
     619           1 :   NS_ENSURE_ARG_POINTER(aResult);
     620             : 
     621           2 :   RefPtr<HTMLContentSink> it = new HTMLContentSink();
     622             : 
     623           1 :   nsresult rv = it->Init(aDoc, aURI, aContainer, aChannel);
     624             : 
     625           1 :   NS_ENSURE_SUCCESS(rv, rv);
     626             : 
     627           1 :   *aResult = it;
     628           1 :   NS_ADDREF(*aResult);
     629             : 
     630           1 :   return NS_OK;
     631             : }
     632             : 
     633           1 : HTMLContentSink::HTMLContentSink()
     634             :   : mMaxTextRun(0)
     635             :   , mCurrentContext(nullptr)
     636             :   , mHeadContext(nullptr)
     637             :   , mHaveSeenHead(false)
     638           1 :   , mNotifiedRootInsertion(false)
     639             : {
     640           1 : }
     641             : 
     642           0 : HTMLContentSink::~HTMLContentSink()
     643             : {
     644           0 :   if (mNotificationTimer) {
     645           0 :     mNotificationTimer->Cancel();
     646             :   }
     647             : 
     648           0 :   int32_t numContexts = mContextStack.Length();
     649             : 
     650           0 :   if (mCurrentContext == mHeadContext && numContexts > 0) {
     651             :     // Pop off the second html context if it's not done earlier
     652           0 :     mContextStack.RemoveElementAt(--numContexts);
     653             :   }
     654             : 
     655             :   int32_t i;
     656           0 :   for (i = 0; i < numContexts; i++) {
     657           0 :     SinkContext* sc = mContextStack.ElementAt(i);
     658           0 :     if (sc) {
     659           0 :       sc->End();
     660           0 :       if (sc == mCurrentContext) {
     661           0 :         mCurrentContext = nullptr;
     662             :       }
     663             : 
     664           0 :       delete sc;
     665             :     }
     666             :   }
     667             : 
     668           0 :   if (mCurrentContext == mHeadContext) {
     669           0 :     mCurrentContext = nullptr;
     670             :   }
     671             : 
     672           0 :   delete mCurrentContext;
     673             : 
     674           0 :   delete mHeadContext;
     675           0 : }
     676             : 
     677             : NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLContentSink)
     678             : 
     679           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLContentSink, nsContentSink)
     680           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mHTMLDocument)
     681           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mRoot)
     682           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mBody)
     683           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mHead)
     684           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     685           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLContentSink,
     686             :                                                   nsContentSink)
     687           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHTMLDocument)
     688           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRoot)
     689           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBody)
     690           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHead)
     691           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     692             : 
     693           6 : NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLContentSink)
     694             :   NS_INTERFACE_TABLE_BEGIN
     695             :     NS_INTERFACE_TABLE_ENTRY(HTMLContentSink, nsIContentSink)
     696             :     NS_INTERFACE_TABLE_ENTRY(HTMLContentSink, nsIHTMLContentSink)
     697           5 :   NS_INTERFACE_TABLE_END
     698           5 : NS_INTERFACE_TABLE_TAIL_INHERITING(nsContentSink)
     699             : 
     700          19 : NS_IMPL_ADDREF_INHERITED(HTMLContentSink, nsContentSink)
     701          19 : NS_IMPL_RELEASE_INHERITED(HTMLContentSink, nsContentSink)
     702             : 
     703             : nsresult
     704           1 : HTMLContentSink::Init(nsIDocument* aDoc,
     705             :                       nsIURI* aURI,
     706             :                       nsISupports* aContainer,
     707             :                       nsIChannel* aChannel)
     708             : {
     709           1 :   NS_ENSURE_TRUE(aContainer, NS_ERROR_NULL_POINTER);
     710             : 
     711           1 :   nsresult rv = nsContentSink::Init(aDoc, aURI, aContainer, aChannel);
     712           1 :   if (NS_FAILED(rv)) {
     713           0 :     return rv;
     714             :   }
     715             : 
     716           1 :   aDoc->AddObserver(this);
     717           1 :   mIsDocumentObserver = true;
     718           1 :   mHTMLDocument = do_QueryInterface(aDoc);
     719             : 
     720           1 :   NS_ASSERTION(mDocShell, "oops no docshell!");
     721             : 
     722             :   // Changed from 8192 to greatly improve page loading performance on
     723             :   // large pages.  See bugzilla bug 77540.
     724           1 :   mMaxTextRun = Preferences::GetInt("content.maxtextrun", 8191);
     725             : 
     726           2 :   RefPtr<mozilla::dom::NodeInfo> nodeInfo;
     727           2 :   nodeInfo = mNodeInfoManager->GetNodeInfo(nsGkAtoms::html, nullptr,
     728             :                                            kNameSpaceID_XHTML,
     729           1 :                                            nsIDOMNode::ELEMENT_NODE);
     730             : 
     731             :   // Make root part
     732           1 :   mRoot = NS_NewHTMLHtmlElement(nodeInfo.forget());
     733           1 :   if (!mRoot) {
     734           0 :     return NS_ERROR_OUT_OF_MEMORY;
     735             :   }
     736             : 
     737           1 :   NS_ASSERTION(mDocument->GetChildCount() == 0,
     738             :                "Document should have no kids here!");
     739           1 :   rv = mDocument->AppendChildTo(mRoot, false);
     740           1 :   NS_ENSURE_SUCCESS(rv, rv);
     741             : 
     742             :   // Make head part
     743           2 :   nodeInfo = mNodeInfoManager->GetNodeInfo(nsGkAtoms::head,
     744             :                                            nullptr, kNameSpaceID_XHTML,
     745           1 :                                            nsIDOMNode::ELEMENT_NODE);
     746             : 
     747           1 :   mHead = NS_NewHTMLHeadElement(nodeInfo.forget());
     748           1 :   if (NS_FAILED(rv)) {
     749           0 :     return NS_ERROR_OUT_OF_MEMORY;
     750             :   }
     751             : 
     752           1 :   mRoot->AppendChildTo(mHead, false);
     753             : 
     754           1 :   mCurrentContext = new SinkContext(this);
     755           1 :   mCurrentContext->Begin(eHTMLTag_html, mRoot, 0, -1);
     756           1 :   mContextStack.AppendElement(mCurrentContext);
     757             : 
     758           1 :   return NS_OK;
     759             : }
     760             : 
     761             : NS_IMETHODIMP
     762           1 : HTMLContentSink::WillParse(void)
     763             : {
     764           1 :   return WillParseImpl();
     765             : }
     766             : 
     767             : NS_IMETHODIMP
     768           1 : HTMLContentSink::WillBuildModel(nsDTDMode aDTDMode)
     769             : {
     770           1 :   WillBuildModelImpl();
     771             : 
     772           1 :   if (mHTMLDocument) {
     773           1 :     nsCompatibility mode = eCompatibility_NavQuirks;
     774           1 :     switch (aDTDMode) {
     775             :       case eDTDMode_full_standards:
     776           0 :         mode = eCompatibility_FullStandards;
     777           0 :         break;
     778             :       case eDTDMode_almost_standards:
     779           0 :         mode = eCompatibility_AlmostStandards;
     780           0 :         break;
     781             :       default:
     782           1 :         break;
     783             :     }
     784           1 :     mHTMLDocument->SetCompatibilityMode(mode);
     785             :   }
     786             : 
     787             :   // Notify document that the load is beginning
     788           1 :   mDocument->BeginLoad();
     789             : 
     790           1 :   return NS_OK;
     791             : }
     792             : 
     793             : NS_IMETHODIMP
     794           1 : HTMLContentSink::DidBuildModel(bool aTerminated)
     795             : {
     796           1 :   DidBuildModelImpl(aTerminated);
     797             : 
     798             :   // Reflow the last batch of content
     799           1 :   if (mBody) {
     800           1 :     mCurrentContext->FlushTags();
     801           0 :   } else if (!mLayoutStarted) {
     802             :     // We never saw the body, and layout never got started. Force
     803             :     // layout *now*, to get an initial reflow.
     804             :     // NOTE: only force the layout if we are NOT destroying the
     805             :     // docshell. If we are destroying it, then starting layout will
     806             :     // likely cause us to crash, or at best waste a lot of time as we
     807             :     // are just going to tear it down anyway.
     808           0 :     bool bDestroying = true;
     809           0 :     if (mDocShell) {
     810           0 :       mDocShell->IsBeingDestroyed(&bDestroying);
     811             :     }
     812             : 
     813           0 :     if (!bDestroying) {
     814           0 :       StartLayout(false);
     815             :     }
     816             :   }
     817             : 
     818           1 :   ScrollToRef();
     819             : 
     820             :   // Make sure we no longer respond to document mutations.  We've flushed all
     821             :   // our notifications out, so there's no need to do anything else here.
     822             : 
     823             :   // XXXbz I wonder whether we could End() our contexts here too, or something,
     824             :   // just to make sure we no longer notify...  Or is the mIsDocumentObserver
     825             :   // thing sufficient?
     826           1 :   mDocument->RemoveObserver(this);
     827           1 :   mIsDocumentObserver = false;
     828             : 
     829           1 :   mDocument->EndLoad();
     830             : 
     831           1 :   DropParserAndPerfHint();
     832             : 
     833           1 :   return NS_OK;
     834             : }
     835             : 
     836             : NS_IMETHODIMP
     837           1 : HTMLContentSink::SetParser(nsParserBase* aParser)
     838             : {
     839           1 :   NS_PRECONDITION(aParser, "Should have a parser here!");
     840           1 :   mParser = aParser;
     841           1 :   return NS_OK;
     842             : }
     843             : 
     844             : nsresult
     845           1 : HTMLContentSink::CloseHTML()
     846             : {
     847           1 :   if (mHeadContext) {
     848           0 :     if (mCurrentContext == mHeadContext) {
     849           0 :       uint32_t numContexts = mContextStack.Length();
     850             : 
     851             :       // Pop off the second html context if it's not done earlier
     852           0 :       mCurrentContext = mContextStack.ElementAt(--numContexts);
     853           0 :       mContextStack.RemoveElementAt(numContexts);
     854             :     }
     855             : 
     856           0 :     mHeadContext->End();
     857             : 
     858           0 :     delete mHeadContext;
     859           0 :     mHeadContext = nullptr;
     860             :   }
     861             : 
     862           1 :   return NS_OK;
     863             : }
     864             : 
     865             : nsresult
     866           1 : HTMLContentSink::OpenBody()
     867             : {
     868           1 :   CloseHeadContext();  // do this just in case if the HEAD was left open!
     869             : 
     870             :   // if we already have a body we're done
     871           1 :   if (mBody) {
     872           0 :     return NS_OK;
     873             :   }
     874             : 
     875           1 :   nsresult rv = mCurrentContext->OpenBody();
     876             : 
     877           1 :   if (NS_FAILED(rv)) {
     878           0 :     return rv;
     879             :   }
     880             : 
     881           1 :   mBody = mCurrentContext->mStack[mCurrentContext->mStackPos - 1].mContent;
     882             : 
     883           1 :   if (mCurrentContext->mStackPos > 1) {
     884           1 :     int32_t parentIndex    = mCurrentContext->mStackPos - 2;
     885           1 :     nsGenericHTMLElement *parent = mCurrentContext->mStack[parentIndex].mContent;
     886           1 :     int32_t numFlushed     = mCurrentContext->mStack[parentIndex].mNumFlushed;
     887           1 :     int32_t childCount = parent->GetChildCount();
     888           1 :     NS_ASSERTION(numFlushed < childCount, "Already notified on the body?");
     889             : 
     890             :     int32_t insertionPoint =
     891           1 :       mCurrentContext->mStack[parentIndex].mInsertionPoint;
     892             : 
     893             :     // XXX: I have yet to see a case where numFlushed is non-zero and
     894             :     // insertionPoint is not -1, but this code will try to handle
     895             :     // those cases too.
     896             : 
     897           1 :     uint32_t oldUpdates = mUpdatesInNotification;
     898           1 :     mUpdatesInNotification = 0;
     899           1 :     if (insertionPoint != -1) {
     900           0 :       NotifyInsert(parent, mBody, insertionPoint - 1);
     901             :     } else {
     902           1 :       NotifyAppend(parent, numFlushed);
     903             :     }
     904           1 :     mCurrentContext->mStack[parentIndex].mNumFlushed = childCount;
     905           1 :     if (mUpdatesInNotification > 1) {
     906           0 :       UpdateChildCounts();
     907             :     }
     908           1 :     mUpdatesInNotification = oldUpdates;
     909             :   }
     910             : 
     911           1 :   StartLayout(false);
     912             : 
     913           1 :   return NS_OK;
     914             : }
     915             : 
     916             : nsresult
     917           1 : HTMLContentSink::CloseBody()
     918             : {
     919             :   // Flush out anything that's left
     920           1 :   mCurrentContext->FlushTags();
     921           1 :   mCurrentContext->CloseBody();
     922             : 
     923           1 :   return NS_OK;
     924             : }
     925             : 
     926             : NS_IMETHODIMP
     927           2 : HTMLContentSink::OpenContainer(ElementType aElementType)
     928             : {
     929           2 :   nsresult rv = NS_OK;
     930             : 
     931           2 :   switch (aElementType) {
     932             :     case eBody:
     933           1 :       rv = OpenBody();
     934           1 :       break;
     935             :     case eHTML:
     936           1 :       if (mRoot) {
     937             :         // If we've already hit this code once, then we're done
     938           1 :         if (!mNotifiedRootInsertion) {
     939           1 :           NotifyRootInsertion();
     940             :         }
     941           1 :         ProcessOfflineManifest(mRoot);
     942             :       }
     943           1 :       break;
     944             :   }
     945             : 
     946           2 :   return rv;
     947             : }
     948             : 
     949             : NS_IMETHODIMP
     950           2 : HTMLContentSink::CloseContainer(const ElementType aTag)
     951             : {
     952           2 :   nsresult rv = NS_OK;
     953             : 
     954           2 :   switch (aTag) {
     955             :     case eBody:
     956           1 :       rv = CloseBody();
     957           1 :       break;
     958             :     case eHTML:
     959           1 :       rv = CloseHTML();
     960           1 :       break;
     961             :   }
     962             : 
     963           2 :   return rv;
     964             : }
     965             : 
     966             : NS_IMETHODIMP
     967           0 : HTMLContentSink::WillInterrupt()
     968             : {
     969           0 :   return WillInterruptImpl();
     970             : }
     971             : 
     972             : NS_IMETHODIMP
     973           1 : HTMLContentSink::WillResume()
     974             : {
     975           1 :   return WillResumeImpl();
     976             : }
     977             : 
     978             : void
     979           1 : HTMLContentSink::CloseHeadContext()
     980             : {
     981           1 :   if (mCurrentContext) {
     982           1 :     if (!mCurrentContext->IsCurrentContainer(eHTMLTag_head))
     983           1 :       return;
     984             : 
     985           0 :     mCurrentContext->FlushTags();
     986             :   }
     987             : 
     988           0 :   if (!mContextStack.IsEmpty())
     989             :   {
     990           0 :     uint32_t n = mContextStack.Length() - 1;
     991           0 :     mCurrentContext = mContextStack.ElementAt(n);
     992           0 :     mContextStack.RemoveElementAt(n);
     993             :   }
     994             : }
     995             : 
     996             : void
     997           1 : HTMLContentSink::NotifyInsert(nsIContent* aContent,
     998             :                               nsIContent* aChildContent,
     999             :                               int32_t aIndexInContainer)
    1000             : {
    1001           1 :   if (aContent && aContent->GetUncomposedDoc() != mDocument) {
    1002             :     // aContent is not actually in our document anymore.... Just bail out of
    1003             :     // here; notifying on our document for this insert would be wrong.
    1004           0 :     return;
    1005             :   }
    1006             : 
    1007           1 :   mInNotification++;
    1008             : 
    1009             :   {
    1010             :     // Scope so we call EndUpdate before we decrease mInNotification
    1011           2 :     MOZ_AUTO_DOC_UPDATE(mDocument, UPDATE_CONTENT_MODEL, !mBeganUpdate);
    1012           1 :     nsNodeUtils::ContentInserted(NODE_FROM(aContent, mDocument),
    1013           1 :                                  aChildContent, aIndexInContainer);
    1014           1 :     mLastNotificationTime = PR_Now();
    1015             :   }
    1016             : 
    1017           1 :   mInNotification--;
    1018             : }
    1019             : 
    1020             : void
    1021           1 : HTMLContentSink::NotifyRootInsertion()
    1022             : {
    1023           1 :   NS_PRECONDITION(!mNotifiedRootInsertion, "Double-notifying on root?");
    1024           1 :   NS_ASSERTION(!mLayoutStarted,
    1025             :                "How did we start layout without notifying on root?");
    1026             :   // Now make sure to notify that we have now inserted our root.  If
    1027             :   // there has been no initial reflow yet it'll be a no-op, but if
    1028             :   // there has been one we need this to get its frames constructed.
    1029             :   // Note that if mNotifiedRootInsertion is true we don't notify here,
    1030             :   // since that just means there are multiple <html> tags in the
    1031             :   // document; in those cases we just want to put all the attrs on one
    1032             :   // tag.
    1033           1 :   mNotifiedRootInsertion = true;
    1034           1 :   int32_t index = mDocument->IndexOf(mRoot);
    1035           1 :   NS_ASSERTION(index != -1, "mRoot not child of document?");
    1036           1 :   NotifyInsert(nullptr, mRoot, index);
    1037             : 
    1038             :   // Now update the notification information in all our
    1039             :   // contexts, since we just inserted the root and notified on
    1040             :   // our whole tree
    1041           1 :   UpdateChildCounts();
    1042           1 : }
    1043             : 
    1044             : void
    1045           1 : HTMLContentSink::UpdateChildCounts()
    1046             : {
    1047           1 :   uint32_t numContexts = mContextStack.Length();
    1048           2 :   for (uint32_t i = 0; i < numContexts; i++) {
    1049           1 :     SinkContext* sc = mContextStack.ElementAt(i);
    1050             : 
    1051           1 :     sc->UpdateChildCounts();
    1052             :   }
    1053             : 
    1054           1 :   mCurrentContext->UpdateChildCounts();
    1055           1 : }
    1056             : 
    1057             : void
    1058           0 : HTMLContentSink::FlushPendingNotifications(FlushType aType)
    1059             : {
    1060             :   // Only flush tags if we're not doing the notification ourselves
    1061             :   // (since we aren't reentrant)
    1062           0 :   if (!mInNotification) {
    1063             :     // Only flush if we're still a document observer (so that our child counts
    1064             :     // should be correct).
    1065           0 :     if (mIsDocumentObserver) {
    1066           0 :       if (aType >= FlushType::ContentAndNotify) {
    1067           0 :         FlushTags();
    1068             :       }
    1069             :     }
    1070           0 :     if (aType >= FlushType::EnsurePresShellInitAndFrames) {
    1071             :       // Make sure that layout has started so that the reflow flush
    1072             :       // will actually happen.
    1073           0 :       StartLayout(true);
    1074             :     }
    1075             :   }
    1076           0 : }
    1077             : 
    1078             : nsresult
    1079           1 : HTMLContentSink::FlushTags()
    1080             : {
    1081           1 :   if (!mNotifiedRootInsertion) {
    1082           0 :     NotifyRootInsertion();
    1083           0 :     return NS_OK;
    1084             :   }
    1085             : 
    1086           1 :   return mCurrentContext ? mCurrentContext->FlushTags() : NS_OK;
    1087             : }
    1088             : 
    1089             : void
    1090           0 : HTMLContentSink::SetDocumentCharset(NotNull<const Encoding*> aEncoding)
    1091             : {
    1092           0 :   MOZ_ASSERT_UNREACHABLE("<meta charset> case doesn't occur with about:blank");
    1093             : }
    1094             : 
    1095             : nsISupports *
    1096           0 : HTMLContentSink::GetTarget()
    1097             : {
    1098           0 :   return mDocument;
    1099             : }
    1100             : 
    1101             : bool
    1102           1 : HTMLContentSink::IsScriptExecuting()
    1103             : {
    1104           1 :   return IsScriptExecutingImpl();
    1105             : }

Generated by: LCOV version 1.13