/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/** * This file is near-OBSOLETE. It is used for about:blank only and for the * HTML element factory. * Don't bother adding new stuff in this file.
*/
nsGenericHTMLElement* NS_NewHTMLNOTUSEDElement(
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
FromParser aFromParser) {
MOZ_ASSERT_UNREACHABLE("The element ctor should never be called"); return nullptr;
}
/** * This class is near-OBSOLETE. It is used for about:blank only. * Don't bother adding new stuff in this file.
*/ class HTMLContentSink : public nsContentSink, public nsIHTMLContentSink { public: friendclass SinkContext;
// Boolean indicating whether we've seen a <head> tag that might have had // attributes once already. bool mHaveSeenHead;
// Boolean indicating whether we've notified insertion of our root content // yet. We want to make sure to only do this once. bool mNotifiedRootInsertion;
nsresult FlushTags() override;
// Routines for tags that require special handling
nsresult CloseHTML();
nsresult OpenBody();
nsresult CloseBody();
private: // Function to check whether we've notified for the current content. // What this actually does is check whether we've notified for all // of the parent's kids. bool HaveNotifiedForCurrentContent() const;
void SinkContext::DidAddContent(nsIContent* aContent) { if ((mStackPos == 2) && (mSink->mBody == mStack[1].mContent)) { // We just finished adding something to the body
mNotifyLevel = 0;
}
// If we just added content to a node for which // an insertion happen, we need to do an immediate // notification for that insertion. if (0 < mStackPos && mStack[mStackPos - 1].mInsertionPoint != -1 &&
mStack[mStackPos - 1].mNumFlushed <
mStack[mStackPos - 1].mContent->GetChildCount()) {
nsIContent* parent = mStack[mStackPos - 1].mContent;
mSink->NotifyInsert(parent, aContent);
mStack[mStackPos - 1].mNumFlushed = parent->GetChildCount();
} elseif (mSink->IsTimeToNotify()) {
FlushTags();
}
}
// Make the content object
RefPtr<nsGenericHTMLElement> body =
NS_NewHTMLBodyElement(nodeInfo.forget(), FROM_PARSER_NETWORK); if (!body) { return NS_ERROR_OUT_OF_MEMORY;
}
// If we're in a state where we do append notifications as // we go up the tree, and we're at the level where the next // notification needs to be done, do the notification. if (mNotifyLevel >= mStackPos) { // Check to see if new content has been added after our last // notification
/** * NOTE!! Forked into nsXMLContentSink. Please keep in sync. * * Flush all elements that have been seen so far such that * they are visible in the tree. Specifically, make sure * that they are all added to their respective parents. * Also, do notification at the top for all content that * has been newly added so that the frame tree is complete.
*/
nsresult SinkContext::FlushTags() {
mSink->mDeferredFlushTags = false;
uint32_t oldUpdates = mSink->mUpdatesInNotification;
++(mSink->mInNotification);
mSink->mUpdatesInNotification = 0;
{ // Scope so we call EndUpdate before we decrease mInNotification
mozAutoDocUpdate updateBatch(mSink->mDocument, true);
// Start from the base of the stack (growing downward) and do // a notification from the node that is closest to the root of // tree for any content that has been added.
// Note that we can start at stackPos == 0 here, because it's the caller's // responsibility to handle flushing interactions between contexts (see // HTMLContentSink::BeginContext).
int32_t stackPos = 0; bool flushed = false;
uint32_t childCount;
nsGenericHTMLElement* content;
if (!flushed && (mStack[stackPos].mNumFlushed < childCount)) { if (mStack[stackPos].mInsertionPoint != -1) { // We might have popped the child off our stack already // but not notified on it yet, which is why we have to get it // directly from its parent node.
if (mSink->mUpdatesInNotification > 1) {
UpdateChildCounts();
}
mSink->mUpdatesInNotification = oldUpdates;
return NS_OK;
}
/** * NOTE!! Forked into nsXMLContentSink. Please keep in sync.
*/ void SinkContext::UpdateChildCounts() { // Start from the top of the stack (growing upwards) and see if any // new content has been appended. If so, we recognize that reflows // have been generated for it and we should make sure that no // further reflows occur. Note that we have to include stackPos == 0 // to properly notify on kids of <html>.
int32_t stackPos = mStackPos - 1; while (stackPos >= 0) {
Node& node = mStack[stackPos];
node.mNumFlushed = node.mContent->GetChildCount();
HTMLContentSink::~HTMLContentSink() { if (mNotificationTimer) {
mNotificationTimer->Cancel();
}
if (mCurrentContext == mHeadContext && !mContextStack.IsEmpty()) { // Pop off the second html context if it's not done earlier
mContextStack.RemoveLastElement();
}
for (int32_t i = 0, numContexts = mContextStack.Length(); i < numContexts;
i++) {
SinkContext* sc = mContextStack.ElementAt(i); if (sc) {
sc->End(); if (sc == mCurrentContext) {
mCurrentContext = nullptr;
}
delete sc;
}
}
if (mCurrentContext == mHeadContext) {
mCurrentContext = nullptr;
}
// Changed from 8192 to greatly improve page loading performance on // large pages. See bugzilla bug 77540.
mMaxTextRun = Preferences::GetInt("content.maxtextrun", 8191);
// Make root part
mRoot = NS_NewHTMLHtmlElement(nodeInfo.forget()); if (!mRoot) { return NS_ERROR_OUT_OF_MEMORY;
}
NS_ASSERTION(mDocument->GetChildCount() == 0, "Document should have no kids here!");
ErrorResult error;
mDocument->AppendChildTo(mRoot, false, error); if (error.Failed()) { return error.StealNSResult();
}
// Make head part
nodeInfo = mNodeInfoManager->GetNodeInfo(
nsGkAtoms::head, nullptr, kNameSpaceID_XHTML, nsINode::ELEMENT_NODE);
mHead = NS_NewHTMLHeadElement(nodeInfo.forget()); if (NS_FAILED(rv)) { return NS_ERROR_OUT_OF_MEMORY;
}
// Reflow the last batch of content if (mBody) {
mCurrentContext->FlushTags();
} elseif (!mLayoutStarted) { // We never saw the body, and layout never got started. Force // layout *now*, to get an initial reflow. // NOTE: only force the layout if we are NOT destroying the // docshell. If we are destroying it, then starting layout will // likely cause us to crash, or at best waste a lot of time as we // are just going to tear it down anyway. bool bDestroying = true; if (mDocShell) {
mDocShell->IsBeingDestroyed(&bDestroying);
}
if (!bDestroying) {
StartLayout(false);
}
}
ScrollToRef();
// Make sure we no longer respond to document mutations. We've flushed all // our notifications out, so there's no need to do anything else here.
// XXXbz I wonder whether we could End() our contexts here too, or something, // just to make sure we no longer notify... Or is the mIsDocumentObserver // thing sufficient?
mDocument->RemoveObserver(this);
mIsDocumentObserver = false;
mDocument->EndLoad();
DropParserAndPerfHint();
return NS_OK;
}
NS_IMETHODIMP
HTMLContentSink::SetParser(nsParserBase* aParser) {
MOZ_ASSERT(aParser, "Should have a parser here!");
mParser = aParser; return NS_OK;
}
nsresult HTMLContentSink::CloseHTML() { if (mHeadContext) { if (mCurrentContext == mHeadContext) { // Pop off the second html context if it's not done earlier
mCurrentContext = mContextStack.PopLastElement();
}
mHeadContext->End();
delete mHeadContext;
mHeadContext = nullptr;
}
return NS_OK;
}
nsresult HTMLContentSink::OpenBody() {
CloseHeadContext(); // do this just in case if the HEAD was left open!
// if we already have a body we're done if (mBody) { return NS_OK;
}
switch (aElementType) { case eBody:
rv = OpenBody(); break; case eHTML: if (mRoot) { // If we've already hit this code once, then we're done if (!mNotifiedRootInsertion) {
NotifyRootInsertion();
}
} break;
}
{ // Scope so we call EndUpdate before we decrease mInNotification // Note that aContent->OwnerDoc() may be different to mDocument already.
MOZ_AUTO_DOC_UPDATE(aContent ? aContent->OwnerDoc() : mDocument.get(), true);
MutationObservers::NotifyContentInserted(NODE_FROM(aContent, mDocument),
aChildContent);
mLastNotificationTime = PR_Now();
}
mInNotification--;
}
void HTMLContentSink::NotifyRootInsertion() {
MOZ_ASSERT(!mNotifiedRootInsertion, "Double-notifying on root?");
NS_ASSERTION(!mLayoutStarted, "How did we start layout without notifying on root?"); // Now make sure to notify that we have now inserted our root. If // there has been no initial reflow yet it'll be a no-op, but if // there has been one we need this to get its frames constructed. // Note that if mNotifiedRootInsertion is true we don't notify here, // since that just means there are multiple <html> tags in the // document; in those cases we just want to put all the attrs on one // tag.
mNotifiedRootInsertion = true;
NotifyInsert(nullptr, mRoot);
// Now update the notification information in all our // contexts, since we just inserted the root and notified on // our whole tree
UpdateChildCounts();
nsContentUtils::AddScriptRunner( new nsDocElementCreatedNotificationRunner(mDocument));
}
void HTMLContentSink::UpdateChildCounts() {
uint32_t numContexts = mContextStack.Length(); for (uint32_t i = 0; i < numContexts; i++) {
SinkContext* sc = mContextStack.ElementAt(i);
sc->UpdateChildCounts();
}
mCurrentContext->UpdateChildCounts();
}
void HTMLContentSink::FlushPendingNotifications(FlushType aType) { // Only flush tags if we're not doing the notification ourselves // (since we aren't reentrant) if (!mInNotification) { // Only flush if we're still a document observer (so that our child counts // should be correct). if (mIsDocumentObserver) { if (aType >= FlushType::ContentAndNotify) {
FlushTags();
}
} if (aType >= FlushType::EnsurePresShellInitAndFrames) { // Make sure that layout has started so that the reflow flush // will actually happen.
StartLayout(true);
}
}
}
nsresult HTMLContentSink::FlushTags() { if (!mNotifiedRootInsertion) {
NotifyRootInsertion(); return NS_OK;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.