/* -*- 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/. */
// XXX Open Issues: // 1) what's not allowed - We need to figure out which HTML tags // (prefixed with a HTML namespace qualifier) are explicitly not // allowed (if any). // 2) factoring code with nsHTMLContentSink - There's some amount of // common code between this and the HTML content sink. This will // increase as we support more and more HTML elements. How can code // from the code be factored?
nsresult NS_NewXMLContentSink(nsIXMLContentSink** aResult, Document* aDoc,
nsIURI* aURI, nsISupports* aContainer,
nsIChannel* aChannel) {
MOZ_ASSERT(nullptr != aResult, "null ptr"); if (nullptr == aResult) { return NS_ERROR_NULL_POINTER;
}
RefPtr<nsXMLContentSink> it = new nsXMLContentSink();
nsresult nsXMLContentSink::MaybePrettyPrint() { if (!CanStillPrettyPrint()) {
mPrettyPrintXML = false;
return NS_OK;
}
{ // Try to perform a microtask checkpoint; this avoids always breaking // pretty-printing if webextensions insert new content right after the // document loads.
nsAutoMicroTask mt;
}
// stop observing in order to avoid crashing when replacing content
mDocument->RemoveObserver(this);
mIsDocumentObserver = false;
// Reenable the CSSLoader so that the prettyprinting stylesheets can load if (mCSSLoader) {
mCSSLoader->SetEnabled(true);
}
// Check for namespace declarations if (target.EqualsLiteral("xslt-param-namespace")) {
aPi->GetData(data);
nsAutoString prefix, namespaceAttr;
nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::prefix, prefix); if (!prefix.IsEmpty() && nsContentUtils::GetPseudoAttributeValue(
data, nsGkAtoms::_namespace, namespaceAttr)) {
aProcessor->AddXSLTParamNamespace(prefix, namespaceAttr);
}
}
// Check for actual parameters elseif (target.EqualsLiteral("xslt-param")) {
aPi->GetData(data);
nsAutoString name, namespaceAttr, select, value;
nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::name, name);
nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::_namespace,
namespaceAttr); if (!nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::select,
select)) {
select.SetIsVoid(true);
} if (!nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::value,
value)) {
value.SetIsVoid(true);
} if (!name.IsEmpty()) {
aProcessor->AddXSLTParam(name, namespaceAttr, select, value, aSource);
}
}
}
NS_IMETHODIMP
nsXMLContentSink::DidBuildModel(bool aTerminated) { if (!mParser) { // If mParser is null, this parse has already been terminated and must // not been terminated again. However, Document may still think that // the parse has not been terminated and call back into here in the case // where the XML parser has finished but the XSLT transform associated // with the document has not. return NS_OK;
}
FlushTags();
DidBuildModelImpl(aTerminated);
if (mXSLTProcessor) { // stop observing in order to avoid crashing when replacing content
mDocument->RemoveObserver(this);
mIsDocumentObserver = false;
ErrorResult rv;
RefPtr<DocumentFragment> source = mDocument->CreateDocumentFragment(); for (nsIContent* child : mDocumentChildren) { // XPath data model doesn't have DocumentType nodes. if (child->NodeType() != nsINode::DOCUMENT_TYPE_NODE) {
source->AppendChild(*child, rv); if (rv.Failed()) { return rv.StealNSResult();
}
}
}
// Check for xslt-param and xslt-param-namespace PIs for (nsIContent* child : mDocumentChildren) { if (auto pi = ProcessingInstruction::FromNode(child)) {
CheckXSLTParamPI(pi, mXSLTProcessor, source);
} elseif (child->IsElement()) { // Only honor PIs in the prolog break;
}
}
mXSLTProcessor->SetSourceContentModel(source); // Since the processor now holds a reference to us we drop our reference // to it to avoid owning cycles
mXSLTProcessor = nullptr;
} else { // Kick off layout for non-XSLT transformed documents.
// Check if we want to prettyprint
MaybePrettyPrint();
bool startLayout = true;
if (mPrettyPrinting) {
NS_ASSERTION(!mPendingSheetCount, "Shouldn't have pending sheets here!");
// We're pretty-printing now. See whether we should wait up on // stylesheet loads if (mDocument->CSSLoader()->HasPendingLoads()) {
mDocument->CSSLoader()->AddObserver(this); // wait for those sheets to load
startLayout = false;
}
}
RefPtr<Document> doc = mDocument; if (!mDeferredLayoutStart && doc->IsBeingUsedAsImage()) { // Eagerly layout image documents, so that layout-triggered loads have a // chance of blocking the load event, see bug 1901414.
doc->FlushPendingNotifications(FlushType::Layout);
}
nsCOMPtr<nsIDocumentViewer> viewer;
mDocShell->GetDocViewer(getter_AddRefs(viewer)); // Make sure that we haven't loaded a new document into the documentviewer // after starting the XSLT transform. if (viewer && viewer->GetDocument() == aSourceDocument) { return viewer->SetDocumentInternal(aResultDocument, true);
} return NS_OK;
}
nsresult nsXMLContentSink::OnTransformDone(Document* aSourceDocument,
nsresult aResult,
Document* aResultDocument) {
MOZ_ASSERT(aResultDocument, "Don't notify about transform end without a document.");
// Make sure that we haven't loaded a new document into the documentviewer // after starting the XSLT transform. if (viewer && (viewer->GetDocument() == aSourceDocument ||
viewer->GetDocument() == aResultDocument)) { if (NS_FAILED(aResult)) { // Transform failed.
aResultDocument->SetMayStartLayout(false); // We have an error document.
viewer->SetDocument(aResultDocument);
}
if (!mRunsToCompletion) { // This BlockOnload call corresponds to the UnblockOnload call in // nsContentSink::DropParserAndPerfHint.
aResultDocument->BlockOnload();
mIsBlockingOnload = true;
} // Transform succeeded, or it failed and we have an error document to // display.
mDocument = aResultDocument;
aResultDocument->SetDocWriteDisabled(false);
// Notify document observers that all the content has been stuck // into the document. // XXX do we need to notify for things like PIs? Or just the // documentElement?
nsIContent* rootElement = mDocument->GetRootElement(); if (rootElement) {
NS_ASSERTION(mDocument->ComputeIndexOf(rootElement).isSome(), "rootElement not in doc?");
mDocument->BeginUpdate();
MutationObservers::NotifyContentInserted(mDocument, rootElement);
mDocument->EndUpdate();
}
// Start the layout process
StartLayout(false);
ScrollToRef();
}
originalDocument->EndLoad(); if (blockingOnload) { // This UnblockOnload call corresponds to the BlockOnload call in // nsContentSink::WillBuildModelImpl.
originalDocument->UnblockOnload(true);
}
DropParserAndPerfHint();
// By this point, the result document has been set in the content viewer. But // the content viewer does not call Destroy on the original document, so we // won't end up reporting document use counters. It's possible we should be // detaching the document from the window, but for now, we call // ReportDocumentUseCounters on the original document here, to avoid // assertions in ~Document about not having reported them.
originalDocument->ReportDocumentUseCounters();
RefPtr<mozilla::dom::NodeInfo> ni = aNodeInfo;
RefPtr<Element> element;
// https://html.spec.whatwg.org/#create-an-element-for-the-token // Step 5: Let is be the value of the "is" attribute in the given token, if // such an attribute exists, or null otherwise. const char16_t* is = nullptr;
RefPtr<nsAtom> isAtom;
uint32_t namespaceID = ni->NamespaceID(); bool isXHTMLOrXUL =
namespaceID == kNameSpaceID_XHTML || namespaceID == kNameSpaceID_XUL; if (isXHTMLOrXUL && FindIsAttrValue(aAtts, &is)) {
isAtom = NS_AtomizeMainThread(nsDependentString(is));
}
// Step 6: Let definition be the result of looking up a custom element // definition given document, given namespace, local name, and is. // Step 7: If definition is non-null and the parser was not created as part of // the HTML fragment parsing algorithm, then let will execute script be true. // Otherwise, let it be false. // // Note that the check that the parser was not created as part of the HTML // fragment parsing algorithm is done by the check for a non-null mDocument.
CustomElementDefinition* customElementDefinition = nullptr;
nsAtom* nameAtom = ni->NameAtom(); if (mDocument && !mDocument->IsLoadedAsData() && isXHTMLOrXUL &&
(isAtom || nsContentUtils::IsCustomElementName(nameAtom, namespaceID))) {
nsAtom* typeAtom = is ? isAtom.get() : nameAtom;
if (customElementDefinition) { // Since we are possibly going to run a script for the custom element // constructor, we should first flush any remaining elements.
FlushTags();
{ nsAutoMicroTask mt; }
if (aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML) ||
aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_SVG)) { if (nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(element)) {
sele->SetScriptLineNumber(aLineNumber);
sele->SetScriptColumnNumber(
JS::ColumnNumberOneOrigin::fromZeroOrigin(aColumnNumber));
sele->SetCreatorParser(GetParser());
} else {
MOZ_ASSERT(nsNameSpaceManager::GetInstance()->mSVGDisabled, "Node didn't QI to script, but SVG wasn't disabled.");
}
}
// XHTML needs some special attention if (aNodeInfo->NamespaceEquals(kNameSpaceID_XHTML)) {
mPrettyPrintHasFactoredElements = true;
} else { // If we care, find out if we just used a special factory. if (!mPrettyPrintHasFactoredElements && !mPrettyPrintHasSpecialRoot &&
mPrettyPrintXML) {
mPrettyPrintHasFactoredElements =
nsNameSpaceManager::GetInstance()->HasElementCreator(
aNodeInfo->NamespaceID());
}
if (!aNodeInfo->NamespaceEquals(kNameSpaceID_SVG)) {
element.forget(aResult); return NS_OK;
}
}
if (auto* linkStyle = LinkStyle::FromNode(*element)) { if (aFromParser) {
linkStyle->DisableUpdates();
} if (!aNodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML)) {
linkStyle->SetLineNumber(aFromParser ? aLineNumber : 0);
linkStyle->SetColumnNumber(aFromParser ? aColumnNumber + 1 : 1);
}
}
element.forget(aResult); return NS_OK;
}
nsresult nsXMLContentSink::CloseElement(nsIContent* aContent) {
NS_ASSERTION(aContent, "missing element to close");
// Some HTML nodes need DoneAddingChildren() called to initialize // properly (eg form state restoration). if (nsIContent::RequiresDoneAddingChildren(nodeInfo->NamespaceID(),
nodeInfo->NameAtom())) {
aContent->DoneAddingChildren(HaveNotifiedForCurrentContent());
}
if (IsMonolithicContainer(nodeInfo)) {
mInMonolithicContainer--;
}
if (!nodeInfo->NamespaceEquals(kNameSpaceID_XHTML) &&
!nodeInfo->NamespaceEquals(kNameSpaceID_SVG)) { return NS_OK;
}
if (nodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML) ||
nodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_SVG)) {
nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(aContent); if (!sele) {
MOZ_ASSERT(nsNameSpaceManager::GetInstance()->mSVGDisabled, "Node didn't QI to script, but SVG wasn't disabled."); return NS_OK;
}
if (mPreventScriptExecution) {
sele->PreventExecution(); return NS_OK;
}
// Always check the clock in nsContentSink right after a script
StopDeflecting();
// Flush any previously parsed elements before executing a script, in order // to prevent a script that adds a mutation observer from observing that // script element being adding to the tree.
FlushTags();
// Now tell the script that it's ready to go. This may execute the script // or return true, or neither if the script doesn't need executing. bool block = sele->AttemptToExecute(); if (mParser) { if (block) {
GetParser()->BlockParser();
}
// If the parser got blocked, make sure to return the appropriate rv. // I'm not sure if this is actually needed or not. if (!mParser->IsParserEnabled()) {
block = true;
}
}
nsresult nsXMLContentSink::AddContentAsLeaf(nsIContent* aContent) {
nsresult result = NS_OK;
if (mState == eXMLContentSinkState_InProlog) {
NS_ASSERTION(mDocument, "Fragments have no prolog");
mDocumentChildren.AppendElement(aContent);
} elseif (mState == eXMLContentSinkState_InEpilog) {
NS_ASSERTION(mDocument, "Fragments have no epilog"); if (mXSLTProcessor) {
mDocumentChildren.AppendElement(aContent);
} else {
mDocument->AppendChildTo(aContent, false, IgnoreErrors());
}
} else {
nsCOMPtr<nsIContent> parent = GetCurrentContent();
if (parent) {
ErrorResult rv;
parent->AppendChildTo(aContent, false, rv);
result = rv.StealNSResult();
}
} return result;
}
// Create an XML parser and an XSL content sink and start parsing // the XSL stylesheet located at the given URI.
nsresult nsXMLContentSink::LoadXSLStyleSheet(nsIURI* aUrl) {
nsCOMPtr<nsIDocumentTransformer> processor = new txMozillaXSLTProcessor();
mDocument->SetUseCounter(eUseCounter_custom_XSLStylesheet);
processor->SetTransformObserver(this);
if (NS_SUCCEEDED(processor->LoadStyleSheet(aUrl, mDocument))) {
mXSLTProcessor.swap(processor);
}
// Intentionally ignore errors here, we should continue loading the // XML document whether we're able to load the XSLT stylesheet or // not.
nsAutoCString cmd; if (mParser) GetParser()->GetCommand(cmd); if (cmd.EqualsASCII(kLoadAsData)) return NS_OK; // Do not load stylesheets when loading as data
// Otherwise fall through to nsContentSink to handle CSS Link headers. return nsContentSink::ProcessStyleLinkFromHeader(
aHref, aAlternate, aTitle, aIntegrity, aType, aMedia, aReferrerPolicy,
aFetchPriority);
}
nsCOMPtr<nsILoadInfo> secCheckLoadInfo = new net::LoadInfo(mDocument->NodePrincipal(), // loading principal
mDocument->NodePrincipal(), // triggering principal
aProcessingInstruction,
nsILoadInfo::SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK,
nsIContentPolicy::TYPE_XSLT);
if (mTextLength != 0) { if (mLastTextNode) { bool notify = HaveNotifiedForCurrentContent(); // We could probably always increase mInNotification here since // if AppendText doesn't notify it shouldn't trigger evil code. // But just in case it does, we don't want to mask any notifications. if (notify) {
++mInNotification;
}
rv = mLastTextNode->AppendText(mText, mTextLength, notify); if (notify) {
--mInNotification;
}
nsresult nsXMLContentSink::PushContent(nsIContent* aContent) {
MOZ_ASSERT(aContent, "Null content being pushed!");
StackNode* sn = mContentStack.AppendElement();
NS_ENSURE_TRUE(sn, NS_ERROR_OUT_OF_MEMORY);
nsIContent* contentToPush = aContent;
// When an XML parser would append a node to a template element, it // must instead append it to the template element's template contents. if (contentToPush->IsHTMLElement(nsGkAtoms::_template)) {
HTMLTemplateElement* templateElement = static_cast<HTMLTemplateElement*>(contentToPush);
contentToPush = templateElement->Content();
}
void nsXMLContentSink::MaybeStartLayout(bool aIgnorePendingSheets) { // XXXbz if aIgnorePendingSheets is true, what should we do when // mXSLTProcessor or CanStillPrettyPrint()? if (mLayoutStarted || mXSLTProcessor || CanStillPrettyPrint()) { return;
}
StartLayout(aIgnorePendingSheets);
}
if (mXSLTProcessor) {
mDocumentChildren.AppendElement(aContent); returntrue;
}
if (!mDocumentChildren.IsEmpty()) { for (nsIContent* child : mDocumentChildren) {
mDocument->AppendChildTo(child, false, IgnoreErrors());
}
mDocumentChildren.Clear();
}
// check for root elements that needs special handling for // prettyprinting if (aNameSpaceID == kNameSpaceID_XSLT &&
(aTagName == nsGkAtoms::stylesheet || aTagName == nsGkAtoms::transform)) {
mPrettyPrintHasSpecialRoot = true; if (mPrettyPrintXML) { // In this case, disable script execution, stylesheet // loading, and auto XLinks since we plan to prettyprint.
mDocument->ScriptLoader()->SetEnabled(false); if (mCSSLoader) {
mCSSLoader->SetEnabled(false);
}
}
}
IgnoredErrorResult rv;
mDocument->AppendChildTo(mDocElement, NotifyForDocElement(), rv); if (rv.Failed()) { // If we return false here, the caller will bail out because it won't // find a parent content node to append to, which is fine. returnfalse;
}
nsresult nsXMLContentSink::HandleStartElement( const char16_t* aName, const char16_t** aAtts, uint32_t aAttsCount,
uint32_t aLineNumber, uint32_t aColumnNumber, bool aInterruptable) {
MOZ_ASSERT(aAttsCount % 2 == 0, "incorrect aAttsCount"); // Adjust aAttsCount so it's the actual number of attributes
aAttsCount /= 2;
nsresult result = NS_OK; bool appendContent = true;
nsCOMPtr<nsIContent> content;
// XXX Hopefully the parser will flag this before we get // here. If we're in the epilog, there should be no // new elements
MOZ_ASSERT(eXMLContentSinkState_InEpilog != mState);
// Have to do this before we push the new content on the stack... and have to // do that before we set attributes, call BindToTree, etc. Ideally we'd push // on the stack inside CreateElement (which is effectively what the HTML sink // does), but that's hard with all the subclass overrides going on.
nsCOMPtr<nsIContent> parent = GetCurrentContent();
result = PushContent(content);
NS_ENSURE_SUCCESS(result, result);
// Set the attributes on the new content element
result = AddAttributes(aAtts, content->AsElement());
if (NS_OK == result) { // Store the element if (!SetDocElement(nameSpaceID, localName, content) && appendContent) {
NS_ENSURE_TRUE(parent, NS_ERROR_UNEXPECTED);
// Some HTML nodes need DoneCreatingElement() called to initialize // properly (eg form state restoration). if (nsIContent::RequiresDoneCreatingElement(nodeInfo->NamespaceID(),
nodeInfo->NameAtom())) {
content->DoneCreatingElement();
}
if (IsMonolithicContainer(nodeInfo)) {
mInMonolithicContainer++;
}
if (!mXSLTProcessor) { if (content == mDocElement) {
nsContentUtils::AddScriptRunner( new nsDocElementCreatedNotificationRunner(mDocument));
if (aInterruptable && NS_SUCCEEDED(result) && mParser &&
!mParser->IsParserEnabled()) { return NS_ERROR_HTMLPARSER_BLOCK;
}
} elseif (!mCurrentHead) { // This isn't the root and we're not inside an XHTML <head>. // Might need to start layout
MaybeStartLayout(false);
}
}
// XXX Hopefully the parser will flag this before we get // here. If we're in the prolog or epilog, there should be // no close tags for elements.
MOZ_ASSERT(eXMLContentSinkState_InDocumentElement == mState);
FlushText();
StackNode* sn = GetCurrentStackNode(); if (!sn) { return NS_ERROR_UNEXPECTED;
}
PopContent();
NS_ASSERTION(content, "failed to pop content"); #ifdef DEBUG // Check that we're closing the right thing
RefPtr<nsAtom> debugNameSpacePrefix, debugTagAtom;
int32_t debugNameSpaceID;
nsContentUtils::SplitExpatName(aName, getter_AddRefs(debugNameSpacePrefix),
getter_AddRefs(debugTagAtom),
&debugNameSpaceID); // Check if we are closing a template element because template // elements do not get pushed on the stack, the template // element content is pushed instead. bool isTemplateElement = debugTagAtom == nsGkAtoms::_template &&
debugNameSpaceID == kNameSpaceID_XHTML;
NS_ASSERTION(
content->NodeInfo()->Equals(debugTagAtom, debugNameSpaceID) ||
(debugNameSpaceID == kNameSpaceID_MathML &&
content->NodeInfo()->NamespaceID() == kNameSpaceID_disabled_MathML &&
content->NodeInfo()->Equals(debugTagAtom)) ||
(debugNameSpaceID == kNameSpaceID_SVG &&
content->NodeInfo()->NamespaceID() == kNameSpaceID_disabled_SVG &&
content->NodeInfo()->Equals(debugTagAtom)) ||
isTemplateElement, "Wrong element being closed"); #endif
// Make sure to notify on our kids before we call out to any other code that // might reenter us and call FlushTags, in a state in which we've already // popped "content" from the stack but haven't notified on its kids yet.
int32_t stackLen = mContentStack.Length(); if (mNotifyLevel >= stackLen) { if (numFlushed < content->GetChildCount()) {
NotifyAppend(content, numFlushed);
}
mNotifyLevel = stackLen - 1;
}
result = CloseElement(content);
if (mCurrentHead == content) {
mCurrentHead = nullptr;
}
if (mDocElement == content) { // XXXbz for roots that don't want to be appended on open, we // probably need to deal here.... (and stop appending them on open).
mState = eXMLContentSinkState_InEpilog;
mDocument->OnParsingCompleted();
// We might have had no occasion to start layout yet. Do so now.
MaybeStartLayout(false);
}
DidAddContent();
if (content->IsSVGElement(nsGkAtoms::svg)) {
FlushTags();
nsCOMPtr<nsIRunnable> event = new nsHtml5SVGLoadDispatcher(content); if (NS_FAILED(content->OwnerDoc()->Dispatch(event.forget()))) {
NS_WARNING("failed to dispatch svg load dispatcher");
}
}
NS_IMETHODIMP
nsXMLContentSink::HandleCDataSection(const char16_t* aData, uint32_t aLength) { // XSLT doesn't differentiate between text and cdata and wants adjacent // textnodes merged, so add as text. if (mXSLTProcessor) { return AddText(aData, aLength);
}
if (linkStyle) { // This is an xml-stylesheet processing instruction... but it might not be // a CSS one if the type is set to something else. auto updateOrError = linkStyle->EnableUpdatesAndUpdateStyleSheet(
mRunsToCompletion ? nullptr : this); if (updateOrError.isErr()) { return updateOrError.unwrapErr();
}
auto update = updateOrError.unwrap(); if (update.WillNotify()) { // Successfully started a stylesheet load if (update.ShouldBlock() && !mRunsToCompletion) {
++mPendingSheetCount;
mScriptLoader->AddParserBlockingScriptExecutionBlocker();
} return NS_OK;
}
}
// Check whether this is a CSS stylesheet PI. Make sure the type // handling here matches // XMLStylesheetProcessingInstruction::GetStyleSheetInfo.
nsAutoString type;
nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::type, type);
nsAutoString mimeType, notUsed;
nsContentUtils::SplitMimeType(type, mimeType, notUsed);
if (mState != eXMLContentSinkState_InProlog ||
!target.EqualsLiteral("xml-stylesheet") || mimeType.IsEmpty() ||
mimeType.LowerCaseEqualsLiteral("text/css")) { // Either not a useful stylesheet PI, or a CSS stylesheet PI that // got handled above by the "ssle" bits. We're done here. return DidProcessATokenImpl();
}
// If it's not a CSS stylesheet PI...
nsAutoString href, title, media; bool isAlternate = false;
// If there was no href, we can't do anything with this PI if (!ParsePIData(data, href, title, media, isAlternate)) { return DidProcessATokenImpl();
}
// <?xml-stylesheet?> processing instructions don't have a referrerpolicy // pseudo-attribute, so we pass in an empty string
rv =
MaybeProcessXSLTLink(node, href, isAlternate, title, type, media, u""_ns); return NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
}
/* static */ bool nsXMLContentSink::ParsePIData(const nsString& aData, nsString& aHref,
nsString& aTitle, nsString& aMedia, bool& aIsAlternate) { // If there was no href, we can't do anything with this PI if (!nsContentUtils::GetPseudoAttributeValue(aData, nsGkAtoms::href, aHref)) { returnfalse;
}
// The expat driver should report the error. We're just cleaning up the mess.
*_retval = true;
mPrettyPrintXML = false;
mState = eXMLContentSinkState_InProlog;
// XXX need to stop scripts here -- hsivonen
// stop observing in order to avoid crashing when removing content
mDocument->RemoveObserver(this);
mIsDocumentObserver = false;
// Clear the current content
mDocumentChildren.Clear(); while (mDocument->GetLastChild()) {
mDocument->GetLastChild()->Remove();
}
mDocElement = nullptr;
// Clear any buffered-up text we have. It's enough to set the length to 0. // The buffer itself is allocated when we're created and deleted in our // destructor, so don't mess with it.
mTextLength = 0;
if (mXSLTProcessor) { // Get rid of the XSLT processor.
mXSLTProcessor->CancelLoads();
mXSLTProcessor = nullptr;
}
// release the nodes on stack
mContentStack.Clear();
mNotifyLevel = 0;
// return leaving the document empty if we're asked to not add a <parsererror> // root node if (mDocument->SuppressParserErrorElement()) { return NS_OK;
}
// prepare to set <parsererror> as the document root
rv = HandleProcessingInstruction(
u"xml-stylesheet",
u"href=\"chrome://global/locale/intl.css\" type=\"text/css\"");
NS_ENSURE_SUCCESS(rv, rv);
void nsXMLContentSink::FlushPendingNotifications(FlushType aType) { // Only flush tags if we're not doing the notification ourselves // (since we aren't reentrant) if (!mInNotification) { if (mIsDocumentObserver) { // Only flush if we're still a document observer (so that our child // counts should be correct). if (aType >= FlushType::ContentAndNotify) {
FlushTags();
} else {
FlushText(false);
}
} if (aType >= FlushType::EnsurePresShellInitAndFrames) { // Make sure that layout has started so that the reflow flush // will actually happen.
MaybeStartLayout(true);
}
}
}
/** * NOTE!! Forked from SinkContext. 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 nsXMLContentSink::FlushTags() {
mDeferredFlushTags = false;
uint32_t oldUpdates = mUpdatesInNotification;
mUpdatesInNotification = 0;
++mInNotification;
{ // Scope so we call EndUpdate before we decrease mInNotification
mozAutoDocUpdate updateBatch(mDocument, true);
// Don't release last text node in case we need to add to it again
FlushText(false);
// 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!! Forked from SinkContext. Please keep in sync.
*/ void nsXMLContentSink::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 stackLen = mContentStack.Length();
int32_t stackPos = stackLen - 1; while (stackPos >= 0) {
StackNode& node = mContentStack[stackPos];
node.mNumFlushed = node.mContent->GetChildCount();
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.