michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set sw=2 ts=2 et tw=78: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /** michael@0: * This file is near-OBSOLETE. It is used for about:blank only and for the michael@0: * HTML element factory. michael@0: * Don't bother adding new stuff in this file. michael@0: */ michael@0: michael@0: #include "mozilla/ArrayUtils.h" michael@0: michael@0: #include "nsContentSink.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsReadableUtils.h" michael@0: #include "nsUnicharUtils.h" michael@0: #include "nsIHTMLContentSink.h" michael@0: #include "nsIInterfaceRequestor.h" michael@0: #include "nsIInterfaceRequestorUtils.h" michael@0: #include "nsScriptLoader.h" michael@0: #include "nsIURI.h" michael@0: #include "nsNetUtil.h" michael@0: #include "nsIContentViewer.h" michael@0: #include "nsIMarkupDocumentViewer.h" michael@0: #include "nsINodeInfo.h" michael@0: #include "nsToken.h" michael@0: #include "nsIAppShell.h" michael@0: #include "nsCRT.h" michael@0: #include "prtime.h" michael@0: #include "prlog.h" michael@0: #include "nsNodeUtils.h" michael@0: #include "nsIContent.h" michael@0: #include "mozilla/dom/Element.h" michael@0: #include "mozilla/Preferences.h" michael@0: michael@0: #include "nsGenericHTMLElement.h" michael@0: michael@0: #include "nsIDOMDocument.h" michael@0: #include "nsIDOMDocumentType.h" michael@0: #include "nsIScriptElement.h" michael@0: michael@0: #include "nsIComponentManager.h" michael@0: #include "nsIServiceManager.h" michael@0: michael@0: #include "nsGkAtoms.h" michael@0: #include "nsContentUtils.h" michael@0: #include "nsIChannel.h" michael@0: #include "nsIHttpChannel.h" michael@0: #include "nsIDocShell.h" michael@0: #include "nsIDocument.h" michael@0: #include "nsStubDocumentObserver.h" michael@0: #include "nsIHTMLDocument.h" michael@0: #include "nsIDOMHTMLMapElement.h" michael@0: #include "nsICookieService.h" michael@0: #include "nsTArray.h" michael@0: #include "nsIScriptSecurityManager.h" michael@0: #include "nsIPrincipal.h" michael@0: #include "nsTextFragment.h" michael@0: #include "nsIScriptGlobalObject.h" michael@0: #include "nsNameSpaceManager.h" michael@0: michael@0: #include "nsIParserService.h" michael@0: michael@0: #include "nsIStyleSheetLinkingElement.h" michael@0: #include "nsITimer.h" michael@0: #include "nsError.h" michael@0: #include "nsContentPolicyUtils.h" michael@0: #include "nsIScriptContext.h" michael@0: #include "nsStyleLinkElement.h" michael@0: michael@0: #include "nsWeakReference.h" // nsHTMLElementFactory supports weak references michael@0: #include "nsIPrompt.h" michael@0: #include "nsLayoutCID.h" michael@0: #include "nsIDocShellTreeItem.h" michael@0: michael@0: #include "nsEscape.h" michael@0: #include "nsNodeInfoManager.h" michael@0: #include "nsContentCreatorFunctions.h" michael@0: #include "mozAutoDocUpdate.h" michael@0: #include "nsTextNode.h" michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::dom; michael@0: michael@0: //---------------------------------------------------------------------- michael@0: michael@0: typedef nsGenericHTMLElement* michael@0: (*contentCreatorCallback)(already_AddRefed&&, michael@0: FromParser aFromParser); michael@0: michael@0: nsGenericHTMLElement* michael@0: NS_NewHTMLNOTUSEDElement(already_AddRefed&& aNodeInfo, michael@0: FromParser aFromParser) michael@0: { michael@0: NS_NOTREACHED("The element ctor should never be called"); michael@0: return nullptr; michael@0: } michael@0: michael@0: #define HTML_TAG(_tag, _classname) NS_NewHTML##_classname##Element, michael@0: #define HTML_HTMLELEMENT_TAG(_tag) NS_NewHTMLElement, michael@0: #define HTML_OTHER(_tag) NS_NewHTMLNOTUSEDElement, michael@0: static const contentCreatorCallback sContentCreatorCallbacks[] = { michael@0: NS_NewHTMLUnknownElement, michael@0: #include "nsHTMLTagList.h" michael@0: #undef HTML_TAG michael@0: #undef HTML_HTMLELEMENT_TAG michael@0: #undef HTML_OTHER michael@0: NS_NewHTMLUnknownElement michael@0: }; michael@0: michael@0: class SinkContext; michael@0: class HTMLContentSink; michael@0: michael@0: /** michael@0: * This class is near-OBSOLETE. It is used for about:blank only. michael@0: * Don't bother adding new stuff in this file. michael@0: */ michael@0: class HTMLContentSink : public nsContentSink, michael@0: public nsIHTMLContentSink michael@0: { michael@0: public: michael@0: friend class SinkContext; michael@0: michael@0: HTMLContentSink(); michael@0: virtual ~HTMLContentSink(); michael@0: michael@0: NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW michael@0: michael@0: nsresult Init(nsIDocument* aDoc, nsIURI* aURI, nsISupports* aContainer, michael@0: nsIChannel* aChannel); michael@0: michael@0: // nsISupports michael@0: NS_DECL_ISUPPORTS_INHERITED michael@0: NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLContentSink, nsContentSink) michael@0: michael@0: // nsIContentSink michael@0: NS_IMETHOD WillParse(void); michael@0: NS_IMETHOD WillBuildModel(nsDTDMode aDTDMode); michael@0: NS_IMETHOD DidBuildModel(bool aTerminated); michael@0: NS_IMETHOD WillInterrupt(void); michael@0: NS_IMETHOD WillResume(void); michael@0: NS_IMETHOD SetParser(nsParserBase* aParser); michael@0: virtual void FlushPendingNotifications(mozFlushType aType); michael@0: NS_IMETHOD SetDocumentCharset(nsACString& aCharset); michael@0: virtual nsISupports *GetTarget(); michael@0: virtual bool IsScriptExecuting(); michael@0: michael@0: // nsIHTMLContentSink michael@0: NS_IMETHOD OpenContainer(ElementType aNodeType); michael@0: NS_IMETHOD CloseContainer(ElementType aTag); michael@0: michael@0: protected: michael@0: nsCOMPtr mHTMLDocument; michael@0: michael@0: // The maximum length of a text run michael@0: int32_t mMaxTextRun; michael@0: michael@0: nsRefPtr mRoot; michael@0: nsRefPtr mBody; michael@0: nsRefPtr mHead; michael@0: michael@0: nsAutoTArray mContextStack; michael@0: SinkContext* mCurrentContext; michael@0: SinkContext* mHeadContext; michael@0: michael@0: // Boolean indicating whether we've seen a tag that might have had michael@0: // attributes once already. michael@0: bool mHaveSeenHead; michael@0: michael@0: // Boolean indicating whether we've notified insertion of our root content michael@0: // yet. We want to make sure to only do this once. michael@0: bool mNotifiedRootInsertion; michael@0: michael@0: uint8_t mScriptEnabled : 1; michael@0: uint8_t mFramesEnabled : 1; michael@0: uint8_t unused : 6; // bits available if someone needs one michael@0: michael@0: nsINodeInfo* mNodeInfoCache[NS_HTML_TAG_MAX + 1]; michael@0: michael@0: nsresult FlushTags(); michael@0: michael@0: // Routines for tags that require special handling michael@0: nsresult CloseHTML(); michael@0: nsresult OpenBody(); michael@0: nsresult CloseBody(); michael@0: michael@0: void CloseHeadContext(); michael@0: michael@0: // nsContentSink overrides michael@0: void UpdateChildCounts(); michael@0: michael@0: void NotifyInsert(nsIContent* aContent, michael@0: nsIContent* aChildContent, michael@0: int32_t aIndexInContainer); michael@0: void NotifyRootInsertion(); michael@0: }; michael@0: michael@0: class SinkContext michael@0: { michael@0: public: michael@0: SinkContext(HTMLContentSink* aSink); michael@0: ~SinkContext(); michael@0: michael@0: nsresult Begin(nsHTMLTag aNodeType, nsGenericHTMLElement* aRoot, michael@0: uint32_t aNumFlushed, int32_t aInsertionPoint); michael@0: nsresult OpenBody(); michael@0: nsresult CloseBody(); michael@0: nsresult End(); michael@0: michael@0: nsresult GrowStack(); michael@0: nsresult FlushTags(); michael@0: michael@0: bool IsCurrentContainer(nsHTMLTag mType); michael@0: michael@0: void DidAddContent(nsIContent* aContent); michael@0: void UpdateChildCounts(); michael@0: michael@0: private: michael@0: // Function to check whether we've notified for the current content. michael@0: // What this actually does is check whether we've notified for all michael@0: // of the parent's kids. michael@0: bool HaveNotifiedForCurrentContent() const; michael@0: michael@0: public: michael@0: HTMLContentSink* mSink; michael@0: int32_t mNotifyLevel; michael@0: michael@0: struct Node { michael@0: nsHTMLTag mType; michael@0: nsGenericHTMLElement* mContent; michael@0: uint32_t mNumFlushed; michael@0: int32_t mInsertionPoint; michael@0: michael@0: nsIContent *Add(nsIContent *child); michael@0: }; michael@0: michael@0: Node* mStack; michael@0: int32_t mStackSize; michael@0: int32_t mStackPos; michael@0: }; michael@0: michael@0: nsresult michael@0: NS_NewHTMLElement(Element** aResult, already_AddRefed&& aNodeInfo, michael@0: FromParser aFromParser) michael@0: { michael@0: *aResult = nullptr; michael@0: michael@0: nsCOMPtr nodeInfo = aNodeInfo; michael@0: michael@0: nsIParserService* parserService = nsContentUtils::GetParserService(); michael@0: if (!parserService) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: nsIAtom *name = nodeInfo->NameAtom(); michael@0: michael@0: NS_ASSERTION(nodeInfo->NamespaceEquals(kNameSpaceID_XHTML), michael@0: "Trying to HTML elements that don't have the XHTML namespace"); michael@0: michael@0: // Per the Custom Element specification, unknown tags that are valid custom michael@0: // element names should be HTMLElement instead of HTMLUnknownElement. michael@0: int32_t tag = parserService->HTMLCaseSensitiveAtomTagToId(name); michael@0: if (tag == eHTMLTag_userdefined && michael@0: nsContentUtils::IsCustomElementName(name)) { michael@0: nsIDocument* doc = nodeInfo->GetDocument(); michael@0: michael@0: NS_IF_ADDREF(*aResult = NS_NewHTMLElement(nodeInfo.forget(), aFromParser)); michael@0: if (!*aResult) { michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: michael@0: // Element may be unresolved at this point. michael@0: doc->RegisterUnresolvedElement(*aResult); michael@0: michael@0: // Try to enqueue a created callback. The custom element data will be set michael@0: // and created callback will be enqueued if the custom element type michael@0: // has already been registered. michael@0: doc->EnqueueLifecycleCallback(nsIDocument::eCreated, *aResult); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: *aResult = CreateHTMLElement(tag, michael@0: nodeInfo.forget(), aFromParser).take(); michael@0: return *aResult ? NS_OK : NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: michael@0: already_AddRefed michael@0: CreateHTMLElement(uint32_t aNodeType, michael@0: already_AddRefed&& aNodeInfo, michael@0: FromParser aFromParser) michael@0: { michael@0: NS_ASSERTION(aNodeType <= NS_HTML_TAG_MAX || michael@0: aNodeType == eHTMLTag_userdefined, michael@0: "aNodeType is out of bounds"); michael@0: michael@0: contentCreatorCallback cb = sContentCreatorCallbacks[aNodeType]; michael@0: michael@0: NS_ASSERTION(cb != NS_NewHTMLNOTUSEDElement, michael@0: "Don't know how to construct tag element!"); michael@0: michael@0: nsRefPtr result = cb(Move(aNodeInfo), aFromParser); michael@0: michael@0: return result.forget(); michael@0: } michael@0: michael@0: //---------------------------------------------------------------------- michael@0: michael@0: SinkContext::SinkContext(HTMLContentSink* aSink) michael@0: : mSink(aSink), michael@0: mNotifyLevel(0), michael@0: mStack(nullptr), michael@0: mStackSize(0), michael@0: mStackPos(0) michael@0: { michael@0: MOZ_COUNT_CTOR(SinkContext); michael@0: } michael@0: michael@0: SinkContext::~SinkContext() michael@0: { michael@0: MOZ_COUNT_DTOR(SinkContext); michael@0: michael@0: if (mStack) { michael@0: for (int32_t i = 0; i < mStackPos; i++) { michael@0: NS_RELEASE(mStack[i].mContent); michael@0: } michael@0: delete [] mStack; michael@0: } michael@0: } michael@0: michael@0: nsresult michael@0: SinkContext::Begin(nsHTMLTag aNodeType, michael@0: nsGenericHTMLElement* aRoot, michael@0: uint32_t aNumFlushed, michael@0: int32_t aInsertionPoint) michael@0: { michael@0: if (mStackSize < 1) { michael@0: nsresult rv = GrowStack(); michael@0: if (NS_FAILED(rv)) { michael@0: return rv; michael@0: } michael@0: } michael@0: michael@0: mStack[0].mType = aNodeType; michael@0: mStack[0].mContent = aRoot; michael@0: mStack[0].mNumFlushed = aNumFlushed; michael@0: mStack[0].mInsertionPoint = aInsertionPoint; michael@0: NS_ADDREF(aRoot); michael@0: mStackPos = 1; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: bool michael@0: SinkContext::IsCurrentContainer(nsHTMLTag aTag) michael@0: { michael@0: if (aTag == mStack[mStackPos - 1].mType) { michael@0: return true; michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: michael@0: void michael@0: SinkContext::DidAddContent(nsIContent* aContent) michael@0: { michael@0: if ((mStackPos == 2) && (mSink->mBody == mStack[1].mContent)) { michael@0: // We just finished adding something to the body michael@0: mNotifyLevel = 0; michael@0: } michael@0: michael@0: // If we just added content to a node for which michael@0: // an insertion happen, we need to do an immediate michael@0: // notification for that insertion. michael@0: if (0 < mStackPos && michael@0: mStack[mStackPos - 1].mInsertionPoint != -1 && michael@0: mStack[mStackPos - 1].mNumFlushed < michael@0: mStack[mStackPos - 1].mContent->GetChildCount()) { michael@0: nsIContent* parent = mStack[mStackPos - 1].mContent; michael@0: int32_t childIndex = mStack[mStackPos - 1].mInsertionPoint - 1; michael@0: NS_ASSERTION(parent->GetChildAt(childIndex) == aContent, michael@0: "Flushing the wrong child."); michael@0: mSink->NotifyInsert(parent, aContent, childIndex); michael@0: mStack[mStackPos - 1].mNumFlushed = parent->GetChildCount(); michael@0: } else if (mSink->IsTimeToNotify()) { michael@0: FlushTags(); michael@0: } michael@0: } michael@0: michael@0: nsresult michael@0: SinkContext::OpenBody() michael@0: { michael@0: if (mStackPos <= 0) { michael@0: NS_ERROR("container w/o parent"); michael@0: michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: nsresult rv; michael@0: if (mStackPos + 1 > mStackSize) { michael@0: rv = GrowStack(); michael@0: if (NS_FAILED(rv)) { michael@0: return rv; michael@0: } michael@0: } michael@0: michael@0: nsCOMPtr nodeInfo = michael@0: mSink->mNodeInfoManager->GetNodeInfo(nsGkAtoms::body, nullptr, michael@0: kNameSpaceID_XHTML, michael@0: nsIDOMNode::ELEMENT_NODE); michael@0: NS_ENSURE_TRUE(nodeInfo, NS_ERROR_UNEXPECTED); michael@0: michael@0: // Make the content object michael@0: nsRefPtr body = michael@0: NS_NewHTMLBodyElement(nodeInfo.forget(), FROM_PARSER_NETWORK); michael@0: if (!body) { michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: michael@0: mStack[mStackPos].mType = eHTMLTag_body; michael@0: body.forget(&mStack[mStackPos].mContent); michael@0: mStack[mStackPos].mNumFlushed = 0; michael@0: mStack[mStackPos].mInsertionPoint = -1; michael@0: ++mStackPos; michael@0: mStack[mStackPos - 2].Add(mStack[mStackPos - 1].mContent); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: bool michael@0: SinkContext::HaveNotifiedForCurrentContent() const michael@0: { michael@0: if (0 < mStackPos) { michael@0: nsIContent* parent = mStack[mStackPos - 1].mContent; michael@0: return mStack[mStackPos-1].mNumFlushed == parent->GetChildCount(); michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: nsIContent * michael@0: SinkContext::Node::Add(nsIContent *child) michael@0: { michael@0: NS_ASSERTION(mContent, "No parent to insert/append into!"); michael@0: if (mInsertionPoint != -1) { michael@0: NS_ASSERTION(mNumFlushed == mContent->GetChildCount(), michael@0: "Inserting multiple children without flushing."); michael@0: mContent->InsertChildAt(child, mInsertionPoint++, false); michael@0: } else { michael@0: mContent->AppendChildTo(child, false); michael@0: } michael@0: return child; michael@0: } michael@0: michael@0: nsresult michael@0: SinkContext::CloseBody() michael@0: { michael@0: NS_ASSERTION(mStackPos > 0, michael@0: "stack out of bounds. wrong context probably!"); michael@0: michael@0: if (mStackPos <= 0) { michael@0: return NS_OK; // Fix crash - Ref. bug 45975 or 45007 michael@0: } michael@0: michael@0: --mStackPos; michael@0: NS_ASSERTION(mStack[mStackPos].mType == eHTMLTag_body, michael@0: "Tag mismatch. Closing tag on wrong context or something?"); michael@0: michael@0: nsGenericHTMLElement* content = mStack[mStackPos].mContent; michael@0: michael@0: content->Compact(); michael@0: michael@0: // If we're in a state where we do append notifications as michael@0: // we go up the tree, and we're at the level where the next michael@0: // notification needs to be done, do the notification. michael@0: if (mNotifyLevel >= mStackPos) { michael@0: // Check to see if new content has been added after our last michael@0: // notification michael@0: michael@0: if (mStack[mStackPos].mNumFlushed < content->GetChildCount()) { michael@0: mSink->NotifyAppend(content, mStack[mStackPos].mNumFlushed); michael@0: mStack[mStackPos].mNumFlushed = content->GetChildCount(); michael@0: } michael@0: michael@0: // Indicate that notification has now happened at this level michael@0: mNotifyLevel = mStackPos - 1; michael@0: } michael@0: michael@0: DidAddContent(content); michael@0: NS_IF_RELEASE(content); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: SinkContext::End() michael@0: { michael@0: for (int32_t i = 0; i < mStackPos; i++) { michael@0: NS_RELEASE(mStack[i].mContent); michael@0: } michael@0: michael@0: mStackPos = 0; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: SinkContext::GrowStack() michael@0: { michael@0: int32_t newSize = mStackSize * 2; michael@0: if (newSize == 0) { michael@0: newSize = 32; michael@0: } michael@0: michael@0: Node* stack = new Node[newSize]; michael@0: michael@0: if (mStackPos != 0) { michael@0: memcpy(stack, mStack, sizeof(Node) * mStackPos); michael@0: delete [] mStack; michael@0: } michael@0: michael@0: mStack = stack; michael@0: mStackSize = newSize; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: /** michael@0: * NOTE!! Forked into nsXMLContentSink. Please keep in sync. michael@0: * michael@0: * Flush all elements that have been seen so far such that michael@0: * they are visible in the tree. Specifically, make sure michael@0: * that they are all added to their respective parents. michael@0: * Also, do notification at the top for all content that michael@0: * has been newly added so that the frame tree is complete. michael@0: */ michael@0: nsresult michael@0: SinkContext::FlushTags() michael@0: { michael@0: mSink->mDeferredFlushTags = false; michael@0: bool oldBeganUpdate = mSink->mBeganUpdate; michael@0: uint32_t oldUpdates = mSink->mUpdatesInNotification; michael@0: michael@0: ++(mSink->mInNotification); michael@0: mSink->mUpdatesInNotification = 0; michael@0: { michael@0: // Scope so we call EndUpdate before we decrease mInNotification michael@0: mozAutoDocUpdate updateBatch(mSink->mDocument, UPDATE_CONTENT_MODEL, michael@0: true); michael@0: mSink->mBeganUpdate = true; michael@0: michael@0: // Start from the base of the stack (growing downward) and do michael@0: // a notification from the node that is closest to the root of michael@0: // tree for any content that has been added. michael@0: michael@0: // Note that we can start at stackPos == 0 here, because it's the caller's michael@0: // responsibility to handle flushing interactions between contexts (see michael@0: // HTMLContentSink::BeginContext). michael@0: int32_t stackPos = 0; michael@0: bool flushed = false; michael@0: uint32_t childCount; michael@0: nsGenericHTMLElement* content; michael@0: michael@0: while (stackPos < mStackPos) { michael@0: content = mStack[stackPos].mContent; michael@0: childCount = content->GetChildCount(); michael@0: michael@0: if (!flushed && (mStack[stackPos].mNumFlushed < childCount)) { michael@0: if (mStack[stackPos].mInsertionPoint != -1) { michael@0: // We might have popped the child off our stack already michael@0: // but not notified on it yet, which is why we have to get it michael@0: // directly from its parent node. michael@0: michael@0: int32_t childIndex = mStack[stackPos].mInsertionPoint - 1; michael@0: nsIContent* child = content->GetChildAt(childIndex); michael@0: // Child not on stack anymore; can't assert it's correct michael@0: NS_ASSERTION(!(mStackPos > (stackPos + 1)) || michael@0: (child == mStack[stackPos + 1].mContent), michael@0: "Flushing the wrong child."); michael@0: mSink->NotifyInsert(content, child, childIndex); michael@0: } else { michael@0: mSink->NotifyAppend(content, mStack[stackPos].mNumFlushed); michael@0: } michael@0: michael@0: flushed = true; michael@0: } michael@0: michael@0: mStack[stackPos].mNumFlushed = childCount; michael@0: stackPos++; michael@0: } michael@0: mNotifyLevel = mStackPos - 1; michael@0: } michael@0: --(mSink->mInNotification); michael@0: michael@0: if (mSink->mUpdatesInNotification > 1) { michael@0: UpdateChildCounts(); michael@0: } michael@0: michael@0: mSink->mUpdatesInNotification = oldUpdates; michael@0: mSink->mBeganUpdate = oldBeganUpdate; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: /** michael@0: * NOTE!! Forked into nsXMLContentSink. Please keep in sync. michael@0: */ michael@0: void michael@0: SinkContext::UpdateChildCounts() michael@0: { michael@0: // Start from the top of the stack (growing upwards) and see if any michael@0: // new content has been appended. If so, we recognize that reflows michael@0: // have been generated for it and we should make sure that no michael@0: // further reflows occur. Note that we have to include stackPos == 0 michael@0: // to properly notify on kids of . michael@0: int32_t stackPos = mStackPos - 1; michael@0: while (stackPos >= 0) { michael@0: Node & node = mStack[stackPos]; michael@0: node.mNumFlushed = node.mContent->GetChildCount(); michael@0: michael@0: stackPos--; michael@0: } michael@0: michael@0: mNotifyLevel = mStackPos - 1; michael@0: } michael@0: michael@0: nsresult michael@0: NS_NewHTMLContentSink(nsIHTMLContentSink** aResult, michael@0: nsIDocument* aDoc, michael@0: nsIURI* aURI, michael@0: nsISupports* aContainer, michael@0: nsIChannel* aChannel) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aResult); michael@0: michael@0: nsRefPtr it = new HTMLContentSink(); michael@0: michael@0: nsresult rv = it->Init(aDoc, aURI, aContainer, aChannel); michael@0: michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: *aResult = it; michael@0: NS_ADDREF(*aResult); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: HTMLContentSink::HTMLContentSink() michael@0: { michael@0: // Note: operator new zeros our memory michael@0: } michael@0: michael@0: HTMLContentSink::~HTMLContentSink() michael@0: { michael@0: if (mNotificationTimer) { michael@0: mNotificationTimer->Cancel(); michael@0: } michael@0: michael@0: int32_t numContexts = mContextStack.Length(); michael@0: michael@0: if (mCurrentContext == mHeadContext && numContexts > 0) { michael@0: // Pop off the second html context if it's not done earlier michael@0: mContextStack.RemoveElementAt(--numContexts); michael@0: } michael@0: michael@0: int32_t i; michael@0: for (i = 0; i < numContexts; i++) { michael@0: SinkContext* sc = mContextStack.ElementAt(i); michael@0: if (sc) { michael@0: sc->End(); michael@0: if (sc == mCurrentContext) { michael@0: mCurrentContext = nullptr; michael@0: } michael@0: michael@0: delete sc; michael@0: } michael@0: } michael@0: michael@0: if (mCurrentContext == mHeadContext) { michael@0: mCurrentContext = nullptr; michael@0: } michael@0: michael@0: delete mCurrentContext; michael@0: michael@0: delete mHeadContext; michael@0: michael@0: for (i = 0; uint32_t(i) < ArrayLength(mNodeInfoCache); ++i) { michael@0: NS_IF_RELEASE(mNodeInfoCache[i]); michael@0: } michael@0: } michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLContentSink) michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLContentSink, nsContentSink) michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK(mHTMLDocument) michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK(mRoot) michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK(mBody) michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK(mHead) michael@0: for (uint32_t i = 0; i < ArrayLength(tmp->mNodeInfoCache); ++i) { michael@0: NS_IF_RELEASE(tmp->mNodeInfoCache[i]); michael@0: } michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK_END michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLContentSink, michael@0: nsContentSink) michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHTMLDocument) michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRoot) michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBody) michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHead) michael@0: for (uint32_t i = 0; i < ArrayLength(tmp->mNodeInfoCache); ++i) { michael@0: NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mNodeInfoCache[i]"); michael@0: cb.NoteXPCOMChild(tmp->mNodeInfoCache[i]); michael@0: } michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END michael@0: michael@0: NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLContentSink) michael@0: NS_INTERFACE_TABLE_BEGIN michael@0: NS_INTERFACE_TABLE_ENTRY(HTMLContentSink, nsIContentSink) michael@0: NS_INTERFACE_TABLE_ENTRY(HTMLContentSink, nsIHTMLContentSink) michael@0: NS_INTERFACE_TABLE_END michael@0: NS_INTERFACE_TABLE_TAIL_INHERITING(nsContentSink) michael@0: michael@0: NS_IMPL_ADDREF_INHERITED(HTMLContentSink, nsContentSink) michael@0: NS_IMPL_RELEASE_INHERITED(HTMLContentSink, nsContentSink) michael@0: michael@0: static bool michael@0: IsScriptEnabled(nsIDocument *aDoc, nsIDocShell *aContainer) michael@0: { michael@0: NS_ENSURE_TRUE(aDoc && aContainer, true); michael@0: michael@0: nsCOMPtr globalObject = michael@0: do_QueryInterface(aDoc->GetInnerWindow()); michael@0: michael@0: // Getting context is tricky if the document hasn't had its michael@0: // GlobalObject set yet michael@0: if (!globalObject) { michael@0: globalObject = aContainer->GetScriptGlobalObject(); michael@0: } michael@0: michael@0: NS_ENSURE_TRUE(globalObject && globalObject->GetGlobalJSObject(), true); michael@0: return nsContentUtils::GetSecurityManager()-> michael@0: ScriptAllowed(globalObject->GetGlobalJSObject()); michael@0: } michael@0: michael@0: nsresult michael@0: HTMLContentSink::Init(nsIDocument* aDoc, michael@0: nsIURI* aURI, michael@0: nsISupports* aContainer, michael@0: nsIChannel* aChannel) michael@0: { michael@0: NS_ENSURE_TRUE(aContainer, NS_ERROR_NULL_POINTER); michael@0: michael@0: nsresult rv = nsContentSink::Init(aDoc, aURI, aContainer, aChannel); michael@0: if (NS_FAILED(rv)) { michael@0: return rv; michael@0: } michael@0: michael@0: aDoc->AddObserver(this); michael@0: mIsDocumentObserver = true; michael@0: mHTMLDocument = do_QueryInterface(aDoc); michael@0: michael@0: NS_ASSERTION(mDocShell, "oops no docshell!"); michael@0: michael@0: // Find out if subframes are enabled michael@0: if (mDocShell) { michael@0: bool subFramesEnabled = true; michael@0: mDocShell->GetAllowSubframes(&subFramesEnabled); michael@0: if (subFramesEnabled) { michael@0: mFramesEnabled = true; michael@0: } michael@0: } michael@0: michael@0: // Find out if scripts are enabled, if not, show