Bug 1731274 [wpt PR 30792] - Add WebIDL.idl as a dependency for webtransport idlharne...
[gecko.git] / dom / xul / nsXULContentSink.cpp
blob8913e50ec35924f1468fcc10f19466e727ffd29d
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /*
8 * An implementation for a Gecko-style content sink that knows how
9 * to build a content model (the "prototype" document) from XUL.
11 * For more information on XUL,
12 * see http://developer.mozilla.org/en/docs/XUL
15 #include "nsXULContentSink.h"
17 #include "jsfriendapi.h"
19 #include "nsCOMPtr.h"
20 #include "nsHTMLStyleSheet.h"
21 #include "nsIContentSink.h"
22 #include "mozilla/dom/Document.h"
23 #include "nsIFormControl.h"
24 #include "mozilla/dom/NodeInfo.h"
25 #include "nsIScriptContext.h"
26 #include "nsIScriptGlobalObject.h"
27 #include "nsNameSpaceManager.h"
28 #include "nsParserBase.h"
29 #include "nsViewManager.h"
30 #include "nsIScriptSecurityManager.h"
31 #include "nsLayoutCID.h"
32 #include "nsNetUtil.h"
33 #include "nsString.h"
34 #include "nsReadableUtils.h"
35 #include "nsXULElement.h"
36 #include "mozilla/Logging.h"
37 #include "nsCRT.h"
39 #include "nsXULPrototypeDocument.h" // XXXbe temporary
40 #include "mozilla/css/Loader.h"
42 #include "nsUnicharUtils.h"
43 #include "nsGkAtoms.h"
44 #include "nsContentUtils.h"
45 #include "nsAttrName.h"
46 #include "nsXMLContentSink.h"
47 #include "nsIScriptError.h"
48 #include "nsContentTypeParser.h"
50 static mozilla::LazyLogModule gContentSinkLog("nsXULContentSink");
52 using namespace mozilla;
53 using namespace mozilla::dom;
54 //----------------------------------------------------------------------
56 XULContentSinkImpl::ContextStack::ContextStack() : mTop(nullptr), mDepth(0) {}
58 XULContentSinkImpl::ContextStack::~ContextStack() {
59 while (mTop) {
60 Entry* doomed = mTop;
61 mTop = mTop->mNext;
62 delete doomed;
66 void XULContentSinkImpl::ContextStack::Push(RefPtr<nsXULPrototypeNode>&& aNode,
67 State aState) {
68 mTop = new Entry(std::move(aNode), aState, mTop);
69 ++mDepth;
72 nsresult XULContentSinkImpl::ContextStack::Pop(State* aState) {
73 if (mDepth == 0) return NS_ERROR_UNEXPECTED;
75 Entry* entry = mTop;
76 mTop = mTop->mNext;
77 --mDepth;
79 *aState = entry->mState;
80 delete entry;
82 return NS_OK;
85 nsresult XULContentSinkImpl::ContextStack::GetTopNode(
86 RefPtr<nsXULPrototypeNode>& aNode) {
87 if (mDepth == 0) return NS_ERROR_UNEXPECTED;
89 aNode = mTop->mNode;
90 return NS_OK;
93 nsresult XULContentSinkImpl::ContextStack::GetTopChildren(
94 nsPrototypeArray** aChildren) {
95 if (mDepth == 0) return NS_ERROR_UNEXPECTED;
97 *aChildren = &(mTop->mChildren);
98 return NS_OK;
101 void XULContentSinkImpl::ContextStack::Clear() {
102 Entry* cur = mTop;
103 while (cur) {
104 // Release the root element (and its descendants).
105 Entry* next = cur->mNext;
106 delete cur;
107 cur = next;
110 mTop = nullptr;
111 mDepth = 0;
114 void XULContentSinkImpl::ContextStack::Traverse(
115 nsCycleCollectionTraversalCallback& aCb) {
116 nsCycleCollectionTraversalCallback& cb = aCb;
117 for (ContextStack::Entry* tmp = mTop; tmp; tmp = tmp->mNext) {
118 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNode)
119 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChildren)
123 //----------------------------------------------------------------------
125 XULContentSinkImpl::XULContentSinkImpl()
126 : mText(nullptr),
127 mTextLength(0),
128 mTextSize(0),
129 mConstrainSize(true),
130 mState(eInProlog) {}
132 XULContentSinkImpl::~XULContentSinkImpl() {
133 // The context stack _should_ be empty, unless something has gone wrong.
134 NS_ASSERTION(mContextStack.Depth() == 0, "Context stack not empty?");
135 mContextStack.Clear();
137 free(mText);
140 //----------------------------------------------------------------------
141 // nsISupports interface
143 NS_IMPL_CYCLE_COLLECTION_CLASS(XULContentSinkImpl)
145 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(XULContentSinkImpl)
146 NS_IMPL_CYCLE_COLLECTION_UNLINK(mNodeInfoManager)
147 tmp->mContextStack.Clear();
148 NS_IMPL_CYCLE_COLLECTION_UNLINK(mPrototype)
149 NS_IMPL_CYCLE_COLLECTION_UNLINK(mParser)
150 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
152 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(XULContentSinkImpl)
153 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNodeInfoManager)
154 tmp->mContextStack.Traverse(cb);
155 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrototype)
156 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParser)
157 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
159 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(XULContentSinkImpl)
160 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXMLContentSink)
161 NS_INTERFACE_MAP_ENTRY(nsIXMLContentSink)
162 NS_INTERFACE_MAP_ENTRY(nsIExpatSink)
163 NS_INTERFACE_MAP_ENTRY(nsIContentSink)
164 NS_INTERFACE_MAP_END
166 NS_IMPL_CYCLE_COLLECTING_ADDREF(XULContentSinkImpl)
167 NS_IMPL_CYCLE_COLLECTING_RELEASE(XULContentSinkImpl)
169 //----------------------------------------------------------------------
170 // nsIContentSink interface
172 NS_IMETHODIMP
173 XULContentSinkImpl::WillBuildModel(nsDTDMode aDTDMode) {
174 #if FIXME
175 if (!mParentContentSink) {
176 // If we're _not_ an overlay, then notify the document that
177 // the load is beginning.
178 mDocument->BeginLoad();
180 #endif
182 return NS_OK;
185 NS_IMETHODIMP
186 XULContentSinkImpl::DidBuildModel(bool aTerminated) {
187 nsCOMPtr<Document> doc = do_QueryReferent(mDocument);
188 if (doc) {
189 mPrototype->NotifyLoadDone();
190 mDocument = nullptr;
193 // Drop our reference to the parser to get rid of a circular
194 // reference.
195 mParser = nullptr;
196 return NS_OK;
199 NS_IMETHODIMP
200 XULContentSinkImpl::WillInterrupt(void) {
201 // XXX Notify the docshell, if necessary
202 return NS_OK;
205 NS_IMETHODIMP
206 XULContentSinkImpl::WillResume(void) {
207 // XXX Notify the docshell, if necessary
208 return NS_OK;
211 NS_IMETHODIMP
212 XULContentSinkImpl::SetParser(nsParserBase* aParser) {
213 mParser = aParser;
214 return NS_OK;
217 void XULContentSinkImpl::SetDocumentCharset(
218 NotNull<const Encoding*> aEncoding) {
219 nsCOMPtr<Document> doc = do_QueryReferent(mDocument);
220 if (doc) {
221 doc->SetDocumentCharacterSet(aEncoding);
225 nsISupports* XULContentSinkImpl::GetTarget() {
226 nsCOMPtr<Document> doc = do_QueryReferent(mDocument);
227 return ToSupports(doc);
230 //----------------------------------------------------------------------
232 nsresult XULContentSinkImpl::Init(Document* aDocument,
233 nsXULPrototypeDocument* aPrototype) {
234 MOZ_ASSERT(aDocument != nullptr, "null ptr");
235 if (!aDocument) return NS_ERROR_NULL_POINTER;
237 mDocument = do_GetWeakReference(aDocument);
238 mPrototype = aPrototype;
240 mDocumentURL = mPrototype->GetURI();
241 mNodeInfoManager = aPrototype->GetNodeInfoManager();
242 if (!mNodeInfoManager) return NS_ERROR_UNEXPECTED;
244 mState = eInProlog;
245 return NS_OK;
248 //----------------------------------------------------------------------
250 // Text buffering
253 bool XULContentSinkImpl::IsDataInBuffer(char16_t* buffer, int32_t length) {
254 for (int32_t i = 0; i < length; ++i) {
255 if (buffer[i] == ' ' || buffer[i] == '\t' || buffer[i] == '\n' ||
256 buffer[i] == '\r')
257 continue;
259 return true;
261 return false;
264 nsresult XULContentSinkImpl::FlushText(bool aCreateTextNode) {
265 nsresult rv;
267 do {
268 // Don't do anything if there's no text to create a node from, or
269 // if they've told us not to create a text node
270 if (!mTextLength) break;
272 if (!aCreateTextNode) break;
274 RefPtr<nsXULPrototypeNode> node;
275 rv = mContextStack.GetTopNode(node);
276 if (NS_FAILED(rv)) return rv;
278 bool stripWhitespace = false;
279 if (node->mType == nsXULPrototypeNode::eType_Element) {
280 mozilla::dom::NodeInfo* nodeInfo =
281 static_cast<nsXULPrototypeElement*>(node.get())->mNodeInfo;
283 if (nodeInfo->NamespaceEquals(kNameSpaceID_XUL))
284 stripWhitespace = !nodeInfo->Equals(nsGkAtoms::label) &&
285 !nodeInfo->Equals(nsGkAtoms::description);
288 // Don't bother if there's nothing but whitespace.
289 if (stripWhitespace && !IsDataInBuffer(mText, mTextLength)) break;
291 // Don't bother if we're not in XUL document body
292 if (mState != eInDocumentElement || mContextStack.Depth() == 0) break;
294 RefPtr<nsXULPrototypeText> text = new nsXULPrototypeText();
295 text->mValue.Assign(mText, mTextLength);
296 if (stripWhitespace) text->mValue.Trim(" \t\n\r");
298 // hook it up
299 nsPrototypeArray* children = nullptr;
300 rv = mContextStack.GetTopChildren(&children);
301 if (NS_FAILED(rv)) return rv;
303 children->AppendElement(text.forget());
304 } while (0);
306 // Reset our text buffer
307 mTextLength = 0;
308 return NS_OK;
311 //----------------------------------------------------------------------
313 nsresult XULContentSinkImpl::NormalizeAttributeString(
314 const char16_t* aExpatName, nsAttrName& aName) {
315 int32_t nameSpaceID;
316 RefPtr<nsAtom> prefix, localName;
317 nsContentUtils::SplitExpatName(aExpatName, getter_AddRefs(prefix),
318 getter_AddRefs(localName), &nameSpaceID);
320 if (nameSpaceID == kNameSpaceID_None) {
321 aName.SetTo(localName);
323 return NS_OK;
326 RefPtr<mozilla::dom::NodeInfo> ni;
327 ni = mNodeInfoManager->GetNodeInfo(localName, prefix, nameSpaceID,
328 nsINode::ATTRIBUTE_NODE);
329 aName.SetTo(ni);
331 return NS_OK;
334 /**** BEGIN NEW APIs ****/
336 NS_IMETHODIMP
337 XULContentSinkImpl::HandleStartElement(const char16_t* aName,
338 const char16_t** aAtts,
339 uint32_t aAttsCount,
340 uint32_t aLineNumber,
341 uint32_t aColumnNumber) {
342 // XXX Hopefully the parser will flag this before we get here. If
343 // we're in the epilog, there should be no new elements
344 MOZ_ASSERT(mState != eInEpilog, "tag in XUL doc epilog");
345 MOZ_ASSERT(aAttsCount % 2 == 0, "incorrect aAttsCount");
347 // Adjust aAttsCount so it's the actual number of attributes
348 aAttsCount /= 2;
350 if (mState == eInEpilog) return NS_ERROR_UNEXPECTED;
352 if (mState != eInScript) {
353 FlushText();
356 int32_t nameSpaceID;
357 RefPtr<nsAtom> prefix, localName;
358 nsContentUtils::SplitExpatName(aName, getter_AddRefs(prefix),
359 getter_AddRefs(localName), &nameSpaceID);
361 RefPtr<mozilla::dom::NodeInfo> nodeInfo;
362 nodeInfo = mNodeInfoManager->GetNodeInfo(localName, prefix, nameSpaceID,
363 nsINode::ELEMENT_NODE);
365 nsresult rv = NS_OK;
366 switch (mState) {
367 case eInProlog:
368 // We're the root document element
369 rv = OpenRoot(aAtts, aAttsCount, nodeInfo);
370 break;
372 case eInDocumentElement:
373 rv = OpenTag(aAtts, aAttsCount, aLineNumber, nodeInfo);
374 break;
376 case eInEpilog:
377 case eInScript:
378 MOZ_LOG(
379 gContentSinkLog, LogLevel::Warning,
380 ("xul: warning: unexpected tags in epilog at line %d", aLineNumber));
381 rv = NS_ERROR_UNEXPECTED; // XXX
382 break;
385 return rv;
388 NS_IMETHODIMP
389 XULContentSinkImpl::HandleEndElement(const char16_t* aName) {
390 // Never EVER return anything but NS_OK or
391 // NS_ERROR_HTMLPARSER_BLOCK from this method. Doing so will blow
392 // the parser's little mind all over the planet.
393 nsresult rv;
395 RefPtr<nsXULPrototypeNode> node;
396 rv = mContextStack.GetTopNode(node);
398 if (NS_FAILED(rv)) {
399 return NS_OK;
402 switch (node->mType) {
403 case nsXULPrototypeNode::eType_Element: {
404 // Flush any text _now_, so that we'll get text nodes created
405 // before popping the stack.
406 FlushText();
408 // Pop the context stack and do prototype hookup.
409 nsPrototypeArray* children = nullptr;
410 rv = mContextStack.GetTopChildren(&children);
411 if (NS_FAILED(rv)) return rv;
413 nsXULPrototypeElement* element =
414 static_cast<nsXULPrototypeElement*>(node.get());
416 int32_t count = children->Length();
417 if (count) {
418 element->mChildren.SetCapacity(count);
420 for (int32_t i = 0; i < count; ++i)
421 element->mChildren.AppendElement(children->ElementAt(i));
423 } break;
425 case nsXULPrototypeNode::eType_Script: {
426 nsXULPrototypeScript* script =
427 static_cast<nsXULPrototypeScript*>(node.get());
429 // If given a src= attribute, we must ignore script tag content.
430 if (!script->mSrcURI && !script->HasStencil()) {
431 nsCOMPtr<Document> doc = do_QueryReferent(mDocument);
433 script->mOutOfLine = false;
434 if (doc) {
435 script->Compile(mText, mTextLength, JS::SourceOwnership::Borrowed,
436 mDocumentURL, script->mLineNo, doc);
440 FlushText(false);
441 } break;
443 default:
444 NS_ERROR("didn't expect that");
445 break;
448 rv = mContextStack.Pop(&mState);
449 NS_ASSERTION(NS_SUCCEEDED(rv), "context stack corrupted");
450 if (NS_FAILED(rv)) return rv;
452 if (mContextStack.Depth() == 0) {
453 // The root element should -always- be an element, because
454 // it'll have been created via XULContentSinkImpl::OpenRoot().
455 NS_ASSERTION(node->mType == nsXULPrototypeNode::eType_Element,
456 "root is not an element");
457 if (node->mType != nsXULPrototypeNode::eType_Element)
458 return NS_ERROR_UNEXPECTED;
460 // Now that we're done parsing, set the prototype document's
461 // root element. This transfers ownership of the prototype
462 // element tree to the prototype document.
463 nsXULPrototypeElement* element =
464 static_cast<nsXULPrototypeElement*>(node.get());
466 mPrototype->SetRootElement(element);
467 mState = eInEpilog;
470 return NS_OK;
473 NS_IMETHODIMP
474 XULContentSinkImpl::HandleComment(const char16_t* aName) {
475 FlushText();
476 return NS_OK;
479 NS_IMETHODIMP
480 XULContentSinkImpl::HandleCDataSection(const char16_t* aData,
481 uint32_t aLength) {
482 FlushText();
483 return AddText(aData, aLength);
486 NS_IMETHODIMP
487 XULContentSinkImpl::HandleDoctypeDecl(const nsAString& aSubset,
488 const nsAString& aName,
489 const nsAString& aSystemId,
490 const nsAString& aPublicId,
491 nsISupports* aCatalogData) {
492 return NS_OK;
495 NS_IMETHODIMP
496 XULContentSinkImpl::HandleCharacterData(const char16_t* aData,
497 uint32_t aLength) {
498 if (aData && mState != eInProlog && mState != eInEpilog) {
499 return AddText(aData, aLength);
501 return NS_OK;
504 NS_IMETHODIMP
505 XULContentSinkImpl::HandleProcessingInstruction(const char16_t* aTarget,
506 const char16_t* aData) {
507 FlushText();
509 const nsDependentString target(aTarget);
510 const nsDependentString data(aData);
512 // Note: the created nsXULPrototypePI has mRefCnt == 1
513 RefPtr<nsXULPrototypePI> pi = new nsXULPrototypePI();
514 pi->mTarget = target;
515 pi->mData = data;
517 if (mState == eInProlog) {
518 // Note: passing in already addrefed pi
519 return mPrototype->AddProcessingInstruction(pi);
522 nsresult rv;
523 nsPrototypeArray* children = nullptr;
524 rv = mContextStack.GetTopChildren(&children);
525 if (NS_FAILED(rv)) {
526 return rv;
529 // XXX(Bug 1631371) Check if this should use a fallible operation as it
530 // pretended earlier.
531 children->AppendElement(pi);
533 return NS_OK;
536 NS_IMETHODIMP
537 XULContentSinkImpl::HandleXMLDeclaration(const char16_t* aVersion,
538 const char16_t* aEncoding,
539 int32_t aStandalone) {
540 return NS_OK;
543 NS_IMETHODIMP
544 XULContentSinkImpl::ReportError(const char16_t* aErrorText,
545 const char16_t* aSourceText,
546 nsIScriptError* aError, bool* _retval) {
547 MOZ_ASSERT(aError && aSourceText && aErrorText, "Check arguments!!!");
549 // The expat driver should report the error.
550 *_retval = true;
552 nsresult rv = NS_OK;
554 // make sure to empty the context stack so that
555 // <parsererror> could become the root element.
556 mContextStack.Clear();
558 mState = eInProlog;
560 // Clear any buffered-up text we have. It's enough to set the length to 0.
561 // The buffer itself is allocated when we're created and deleted in our
562 // destructor, so don't mess with it.
563 mTextLength = 0;
565 // return leaving the document empty if we're asked to not add a <parsererror>
566 // root node
567 nsCOMPtr<Document> idoc = do_QueryReferent(mDocument);
568 if (idoc && idoc->SuppressParserErrorElement()) {
569 return NS_OK;
572 const char16_t* noAtts[] = {0, 0};
574 constexpr auto errorNs =
575 u"http://www.mozilla.org/newlayout/xml/parsererror.xml"_ns;
577 nsAutoString parsererror(errorNs);
578 parsererror.Append((char16_t)0xFFFF);
579 parsererror.AppendLiteral("parsererror");
581 rv = HandleStartElement(parsererror.get(), noAtts, 0, 0, 0);
582 NS_ENSURE_SUCCESS(rv, rv);
584 rv = HandleCharacterData(aErrorText, NS_strlen(aErrorText));
585 NS_ENSURE_SUCCESS(rv, rv);
587 nsAutoString sourcetext(errorNs);
588 sourcetext.Append((char16_t)0xFFFF);
589 sourcetext.AppendLiteral("sourcetext");
591 rv = HandleStartElement(sourcetext.get(), noAtts, 0, 0, 0);
592 NS_ENSURE_SUCCESS(rv, rv);
594 rv = HandleCharacterData(aSourceText, NS_strlen(aSourceText));
595 NS_ENSURE_SUCCESS(rv, rv);
597 rv = HandleEndElement(sourcetext.get());
598 NS_ENSURE_SUCCESS(rv, rv);
600 rv = HandleEndElement(parsererror.get());
601 NS_ENSURE_SUCCESS(rv, rv);
603 return rv;
606 nsresult XULContentSinkImpl::OpenRoot(const char16_t** aAttributes,
607 const uint32_t aAttrLen,
608 mozilla::dom::NodeInfo* aNodeInfo) {
609 NS_ASSERTION(mState == eInProlog, "how'd we get here?");
610 if (mState != eInProlog) return NS_ERROR_UNEXPECTED;
612 if (aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML) ||
613 aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XUL)) {
614 MOZ_LOG(gContentSinkLog, LogLevel::Error,
615 ("xul: script tag not allowed as root content element"));
617 return NS_ERROR_UNEXPECTED;
620 // Create the element
621 RefPtr<nsXULPrototypeElement> element = new nsXULPrototypeElement(aNodeInfo);
623 // Add the attributes
624 nsresult rv = AddAttributes(aAttributes, aAttrLen, element);
625 if (NS_FAILED(rv)) return rv;
627 // Push the element onto the context stack, so that child
628 // containers will hook up to us as their parent.
629 mContextStack.Push(std::move(element), mState);
631 mState = eInDocumentElement;
632 return NS_OK;
635 nsresult XULContentSinkImpl::OpenTag(const char16_t** aAttributes,
636 const uint32_t aAttrLen,
637 const uint32_t aLineNumber,
638 mozilla::dom::NodeInfo* aNodeInfo) {
639 // Create the element
640 RefPtr<nsXULPrototypeElement> element = new nsXULPrototypeElement(aNodeInfo);
642 // Link this element to its parent.
643 nsPrototypeArray* children = nullptr;
644 nsresult rv = mContextStack.GetTopChildren(&children);
645 if (NS_FAILED(rv)) {
646 return rv;
649 // Add the attributes
650 rv = AddAttributes(aAttributes, aAttrLen, element);
651 if (NS_FAILED(rv)) return rv;
653 children->AppendElement(element);
655 if (aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML) ||
656 aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XUL)) {
657 // Do scripty things now
658 rv = OpenScript(aAttributes, aLineNumber);
659 NS_ENSURE_SUCCESS(rv, rv);
661 NS_ASSERTION(mState == eInScript || mState == eInDocumentElement,
662 "Unexpected state");
663 if (mState == eInScript) {
664 // OpenScript has pushed the nsPrototypeScriptElement onto the
665 // stack, so we're done.
666 return NS_OK;
670 // Push the element onto the context stack, so that child
671 // containers will hook up to us as their parent.
672 mContextStack.Push(std::move(element), mState);
674 mState = eInDocumentElement;
675 return NS_OK;
678 nsresult XULContentSinkImpl::OpenScript(const char16_t** aAttributes,
679 const uint32_t aLineNumber) {
680 bool isJavaScript = true;
681 nsresult rv;
683 // Look for SRC attribute and look for a LANGUAGE attribute
684 nsAutoString src;
685 while (*aAttributes) {
686 const nsDependentString key(aAttributes[0]);
687 if (key.EqualsLiteral("src")) {
688 src.Assign(aAttributes[1]);
689 } else if (key.EqualsLiteral("type")) {
690 nsDependentString str(aAttributes[1]);
691 nsContentTypeParser parser(str);
692 nsAutoString mimeType;
693 rv = parser.GetType(mimeType);
694 if (NS_FAILED(rv)) {
695 if (rv == NS_ERROR_INVALID_ARG) {
696 // Fail immediately rather than checking if later things
697 // are okay.
698 return NS_OK;
700 // We do want the warning here
701 NS_ENSURE_SUCCESS(rv, rv);
704 // NOTE(emilio): Module scripts don't pass this test, aren't cached yet.
705 // If they become cached, then we need to tweak
706 // PrototypeDocumentContentSink and remove the special cases there.
707 if (nsContentUtils::IsJavascriptMIMEType(mimeType)) {
708 isJavaScript = true;
710 // Get the version string, and ensure that JavaScript supports it.
711 nsAutoString versionName;
712 rv = parser.GetParameter("version", versionName);
714 if (NS_SUCCEEDED(rv)) {
715 nsContentUtils::ReportToConsoleNonLocalized(
716 u"Versioned JavaScripts are no longer supported. "
717 "Please remove the version parameter."_ns,
718 nsIScriptError::errorFlag, "XUL Document"_ns, nullptr,
719 mDocumentURL, u""_ns, aLineNumber);
720 isJavaScript = false;
721 } else if (rv != NS_ERROR_INVALID_ARG) {
722 return rv;
724 } else {
725 isJavaScript = false;
727 } else if (key.EqualsLiteral("language")) {
728 // Language is deprecated, and the impl in ScriptLoader ignores the
729 // various version strings anyway. So we make no attempt to support
730 // languages other than JS for language=
731 nsAutoString lang(aAttributes[1]);
732 if (nsContentUtils::IsJavaScriptLanguage(lang)) {
733 isJavaScript = true;
736 aAttributes += 2;
739 // Don't process scripts that aren't JavaScript.
740 if (!isJavaScript) {
741 return NS_OK;
744 nsCOMPtr<Document> doc(do_QueryReferent(mDocument));
745 nsCOMPtr<nsIScriptGlobalObject> globalObject;
746 if (doc) globalObject = do_QueryInterface(doc->GetWindow());
747 RefPtr<nsXULPrototypeScript> script = new nsXULPrototypeScript(aLineNumber);
749 // If there is a SRC attribute...
750 if (!src.IsEmpty()) {
751 // Use the SRC attribute value to load the URL
752 rv = NS_NewURI(getter_AddRefs(script->mSrcURI), src, nullptr, mDocumentURL);
754 // Check if this document is allowed to load a script from this source
755 // NOTE: if we ever allow scripts added via the DOM to run, we need to
756 // add a CheckLoadURI call for that as well.
757 if (NS_SUCCEEDED(rv)) {
758 if (!mSecMan)
759 mSecMan = do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
760 if (NS_SUCCEEDED(rv)) {
761 nsCOMPtr<Document> doc = do_QueryReferent(mDocument, &rv);
763 if (NS_SUCCEEDED(rv)) {
764 rv = mSecMan->CheckLoadURIWithPrincipal(
765 doc->NodePrincipal(), script->mSrcURI,
766 nsIScriptSecurityManager::ALLOW_CHROME, doc->InnerWindowID());
771 if (NS_FAILED(rv)) {
772 return rv;
775 // Attempt to deserialize an out-of-line script from the FastLoad
776 // file right away. Otherwise we'll end up reloading the script and
777 // corrupting the FastLoad file trying to serialize it, in the case
778 // where it's already there.
779 script->DeserializeOutOfLine(nullptr, mPrototype);
782 nsPrototypeArray* children = nullptr;
783 rv = mContextStack.GetTopChildren(&children);
784 if (NS_FAILED(rv)) {
785 return rv;
788 children->AppendElement(script);
790 mConstrainSize = false;
792 mContextStack.Push(script, mState);
793 mState = eInScript;
795 return NS_OK;
798 nsresult XULContentSinkImpl::AddAttributes(const char16_t** aAttributes,
799 const uint32_t aAttrLen,
800 nsXULPrototypeElement* aElement) {
801 // Add tag attributes to the element
802 nsresult rv;
804 // Create storage for the attributes
805 nsXULPrototypeAttribute* attrs = nullptr;
806 if (aAttrLen > 0) {
807 attrs = aElement->mAttributes.AppendElements(aAttrLen);
810 // Copy the attributes into the prototype
811 uint32_t i;
812 for (i = 0; i < aAttrLen; ++i) {
813 rv = NormalizeAttributeString(aAttributes[i * 2], attrs[i].mName);
814 NS_ENSURE_SUCCESS(rv, rv);
816 rv = aElement->SetAttrAt(i, nsDependentString(aAttributes[i * 2 + 1]),
817 mDocumentURL);
818 NS_ENSURE_SUCCESS(rv, rv);
820 if (MOZ_LOG_TEST(gContentSinkLog, LogLevel::Debug)) {
821 nsAutoString extraWhiteSpace;
822 int32_t cnt = mContextStack.Depth();
823 while (--cnt >= 0) extraWhiteSpace.AppendLiteral(" ");
824 nsAutoString qnameC, valueC;
825 qnameC.Assign(aAttributes[0]);
826 valueC.Assign(aAttributes[1]);
827 MOZ_LOG(gContentSinkLog, LogLevel::Debug,
828 ("xul: %.5d. %s %s=%s",
829 -1, // XXX pass in line number
830 NS_ConvertUTF16toUTF8(extraWhiteSpace).get(),
831 NS_ConvertUTF16toUTF8(qnameC).get(),
832 NS_ConvertUTF16toUTF8(valueC).get()));
836 return NS_OK;
839 nsresult XULContentSinkImpl::AddText(const char16_t* aText, int32_t aLength) {
840 // Create buffer when we first need it
841 if (0 == mTextSize) {
842 mText = (char16_t*)malloc(sizeof(char16_t) * 4096);
843 if (nullptr == mText) {
844 return NS_ERROR_OUT_OF_MEMORY;
846 mTextSize = 4096;
849 // Copy data from string into our buffer; flush buffer when it fills up
850 int32_t offset = 0;
851 while (0 != aLength) {
852 int32_t amount = mTextSize - mTextLength;
853 if (amount > aLength) {
854 amount = aLength;
856 if (0 == amount) {
857 if (mConstrainSize) {
858 nsresult rv = FlushText();
859 if (NS_OK != rv) {
860 return rv;
862 } else {
863 CheckedInt32 size = mTextSize;
864 size += aLength;
865 if (!size.isValid()) {
866 return NS_ERROR_OUT_OF_MEMORY;
868 mTextSize = size.value();
870 mText = (char16_t*)realloc(mText, sizeof(char16_t) * mTextSize);
871 if (nullptr == mText) {
872 return NS_ERROR_OUT_OF_MEMORY;
876 memcpy(&mText[mTextLength], aText + offset, sizeof(char16_t) * amount);
878 mTextLength += amount;
879 offset += amount;
880 aLength -= amount;
883 return NS_OK;