content/html/document/src/nsHTMLContentSink.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial