Bug 1852740: add tests for the `fetchpriority` attribute in Link headers. r=necko...
[gecko.git] / dom / xul / nsXULContentSink.cpp
blob3b4ee8c00d240136354a2f6476a9f2f661593b22
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 "nsIContentSink.h"
21 #include "mozilla/dom/Document.h"
22 #include "nsIFormControl.h"
23 #include "mozilla/dom/NodeInfo.h"
24 #include "nsIScriptContext.h"
25 #include "nsIScriptGlobalObject.h"
26 #include "nsNameSpaceManager.h"
27 #include "nsParserBase.h"
28 #include "nsViewManager.h"
29 #include "nsIScriptSecurityManager.h"
30 #include "nsLayoutCID.h"
31 #include "nsNetUtil.h"
32 #include "nsString.h"
33 #include "nsReadableUtils.h"
34 #include "nsXULElement.h"
35 #include "mozilla/Logging.h"
36 #include "nsCRT.h"
38 #include "nsXULPrototypeDocument.h" // XXXbe temporary
39 #include "mozilla/css/Loader.h"
41 #include "nsUnicharUtils.h"
42 #include "nsGkAtoms.h"
43 #include "nsContentUtils.h"
44 #include "nsAttrName.h"
45 #include "nsXMLContentSink.h"
46 #include "nsIScriptError.h"
47 #include "nsContentTypeParser.h"
49 static mozilla::LazyLogModule gContentSinkLog("nsXULContentSink");
51 using namespace mozilla;
52 using namespace mozilla::dom;
53 //----------------------------------------------------------------------
55 XULContentSinkImpl::ContextStack::ContextStack() : mTop(nullptr), mDepth(0) {}
57 XULContentSinkImpl::ContextStack::~ContextStack() {
58 while (mTop) {
59 Entry* doomed = mTop;
60 mTop = mTop->mNext;
61 delete doomed;
65 void XULContentSinkImpl::ContextStack::Push(RefPtr<nsXULPrototypeNode>&& aNode,
66 State aState) {
67 mTop = new Entry(std::move(aNode), aState, mTop);
68 ++mDepth;
71 nsresult XULContentSinkImpl::ContextStack::Pop(State* aState) {
72 if (mDepth == 0) return NS_ERROR_UNEXPECTED;
74 Entry* entry = mTop;
75 mTop = mTop->mNext;
76 --mDepth;
78 *aState = entry->mState;
79 delete entry;
81 return NS_OK;
84 nsresult XULContentSinkImpl::ContextStack::GetTopNode(
85 RefPtr<nsXULPrototypeNode>& aNode) {
86 if (mDepth == 0) return NS_ERROR_UNEXPECTED;
88 aNode = mTop->mNode;
89 return NS_OK;
92 nsresult XULContentSinkImpl::ContextStack::GetTopChildren(
93 nsPrototypeArray** aChildren) {
94 if (mDepth == 0) return NS_ERROR_UNEXPECTED;
96 *aChildren = &(mTop->mChildren);
97 return NS_OK;
100 void XULContentSinkImpl::ContextStack::Clear() {
101 Entry* cur = mTop;
102 while (cur) {
103 // Release the root element (and its descendants).
104 Entry* next = cur->mNext;
105 delete cur;
106 cur = next;
109 mTop = nullptr;
110 mDepth = 0;
113 void XULContentSinkImpl::ContextStack::Traverse(
114 nsCycleCollectionTraversalCallback& aCb) {
115 nsCycleCollectionTraversalCallback& cb = aCb;
116 for (ContextStack::Entry* tmp = mTop; tmp; tmp = tmp->mNext) {
117 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNode)
118 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChildren)
122 //----------------------------------------------------------------------
124 XULContentSinkImpl::XULContentSinkImpl()
125 : mText(nullptr),
126 mTextLength(0),
127 mTextSize(0),
128 mConstrainSize(true),
129 mState(eInProlog) {}
131 XULContentSinkImpl::~XULContentSinkImpl() {
132 // The context stack _should_ be empty, unless something has gone wrong.
133 NS_ASSERTION(mContextStack.Depth() == 0, "Context stack not empty?");
134 mContextStack.Clear();
136 free(mText);
139 //----------------------------------------------------------------------
140 // nsISupports interface
142 NS_IMPL_CYCLE_COLLECTION_CLASS(XULContentSinkImpl)
144 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(XULContentSinkImpl)
145 NS_IMPL_CYCLE_COLLECTION_UNLINK(mNodeInfoManager)
146 tmp->mContextStack.Clear();
147 NS_IMPL_CYCLE_COLLECTION_UNLINK(mPrototype)
148 NS_IMPL_CYCLE_COLLECTION_UNLINK(mParser)
149 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
151 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(XULContentSinkImpl)
152 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNodeInfoManager)
153 tmp->mContextStack.Traverse(cb);
154 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrototype)
155 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParser)
156 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
158 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(XULContentSinkImpl)
159 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXMLContentSink)
160 NS_INTERFACE_MAP_ENTRY(nsIXMLContentSink)
161 NS_INTERFACE_MAP_ENTRY(nsIExpatSink)
162 NS_INTERFACE_MAP_ENTRY(nsIContentSink)
163 NS_INTERFACE_MAP_END
165 NS_IMPL_CYCLE_COLLECTING_ADDREF(XULContentSinkImpl)
166 NS_IMPL_CYCLE_COLLECTING_RELEASE(XULContentSinkImpl)
168 //----------------------------------------------------------------------
169 // nsIContentSink interface
171 NS_IMETHODIMP
172 XULContentSinkImpl::DidBuildModel(bool aTerminated) {
173 nsCOMPtr<Document> doc = do_QueryReferent(mDocument);
174 if (doc) {
175 mPrototype->NotifyLoadDone();
176 mDocument = nullptr;
179 // Drop our reference to the parser to get rid of a circular
180 // reference.
181 mParser = nullptr;
182 return NS_OK;
185 NS_IMETHODIMP
186 XULContentSinkImpl::WillInterrupt(void) {
187 // XXX Notify the docshell, if necessary
188 return NS_OK;
191 void XULContentSinkImpl::WillResume() {
192 // XXX Notify the docshell, if necessary
195 NS_IMETHODIMP
196 XULContentSinkImpl::SetParser(nsParserBase* aParser) {
197 mParser = aParser;
198 return NS_OK;
201 void XULContentSinkImpl::SetDocumentCharset(
202 NotNull<const Encoding*> aEncoding) {
203 nsCOMPtr<Document> doc = do_QueryReferent(mDocument);
204 if (doc) {
205 doc->SetDocumentCharacterSet(aEncoding);
209 nsISupports* XULContentSinkImpl::GetTarget() {
210 nsCOMPtr<Document> doc = do_QueryReferent(mDocument);
211 return ToSupports(doc);
214 //----------------------------------------------------------------------
216 nsresult XULContentSinkImpl::Init(Document* aDocument,
217 nsXULPrototypeDocument* aPrototype) {
218 MOZ_ASSERT(aDocument != nullptr, "null ptr");
219 if (!aDocument) return NS_ERROR_NULL_POINTER;
221 mDocument = do_GetWeakReference(aDocument);
222 mPrototype = aPrototype;
224 mDocumentURL = mPrototype->GetURI();
225 mNodeInfoManager = aPrototype->GetNodeInfoManager();
226 if (!mNodeInfoManager) return NS_ERROR_UNEXPECTED;
228 mState = eInProlog;
229 return NS_OK;
232 //----------------------------------------------------------------------
234 // Text buffering
237 bool XULContentSinkImpl::IsDataInBuffer(char16_t* buffer, int32_t length) {
238 for (int32_t i = 0; i < length; ++i) {
239 if (buffer[i] == ' ' || buffer[i] == '\t' || buffer[i] == '\n' ||
240 buffer[i] == '\r')
241 continue;
243 return true;
245 return false;
248 nsresult XULContentSinkImpl::FlushText(bool aCreateTextNode) {
249 nsresult rv;
251 do {
252 // Don't do anything if there's no text to create a node from, or
253 // if they've told us not to create a text node
254 if (!mTextLength) break;
256 if (!aCreateTextNode) break;
258 RefPtr<nsXULPrototypeNode> node;
259 rv = mContextStack.GetTopNode(node);
260 if (NS_FAILED(rv)) return rv;
262 bool stripWhitespace = false;
263 if (node->mType == nsXULPrototypeNode::eType_Element) {
264 mozilla::dom::NodeInfo* nodeInfo =
265 static_cast<nsXULPrototypeElement*>(node.get())->mNodeInfo;
267 if (nodeInfo->NamespaceEquals(kNameSpaceID_XUL))
268 stripWhitespace = !nodeInfo->Equals(nsGkAtoms::label) &&
269 !nodeInfo->Equals(nsGkAtoms::description);
272 // Don't bother if there's nothing but whitespace.
273 if (stripWhitespace && !IsDataInBuffer(mText, mTextLength)) break;
275 // Don't bother if we're not in XUL document body
276 if (mState != eInDocumentElement || mContextStack.Depth() == 0) break;
278 RefPtr<nsXULPrototypeText> text = new nsXULPrototypeText();
279 text->mValue.Assign(mText, mTextLength);
280 if (stripWhitespace) text->mValue.Trim(" \t\n\r");
282 // hook it up
283 nsPrototypeArray* children = nullptr;
284 rv = mContextStack.GetTopChildren(&children);
285 if (NS_FAILED(rv)) return rv;
287 children->AppendElement(text.forget());
288 } while (0);
290 // Reset our text buffer
291 mTextLength = 0;
292 return NS_OK;
295 //----------------------------------------------------------------------
297 nsresult XULContentSinkImpl::NormalizeAttributeString(
298 const char16_t* aExpatName, nsAttrName& aName) {
299 int32_t nameSpaceID;
300 RefPtr<nsAtom> prefix, localName;
301 nsContentUtils::SplitExpatName(aExpatName, getter_AddRefs(prefix),
302 getter_AddRefs(localName), &nameSpaceID);
304 if (nameSpaceID == kNameSpaceID_None) {
305 aName.SetTo(localName);
307 return NS_OK;
310 RefPtr<mozilla::dom::NodeInfo> ni;
311 ni = mNodeInfoManager->GetNodeInfo(localName, prefix, nameSpaceID,
312 nsINode::ATTRIBUTE_NODE);
313 aName.SetTo(ni);
315 return NS_OK;
318 /**** BEGIN NEW APIs ****/
320 NS_IMETHODIMP
321 XULContentSinkImpl::HandleStartElement(const char16_t* aName,
322 const char16_t** aAtts,
323 uint32_t aAttsCount,
324 uint32_t aLineNumber,
325 uint32_t aColumnNumber) {
326 // XXX Hopefully the parser will flag this before we get here. If
327 // we're in the epilog, there should be no new elements
328 MOZ_ASSERT(mState != eInEpilog, "tag in XUL doc epilog");
329 MOZ_ASSERT(aAttsCount % 2 == 0, "incorrect aAttsCount");
331 // Adjust aAttsCount so it's the actual number of attributes
332 aAttsCount /= 2;
334 if (mState == eInEpilog) return NS_ERROR_UNEXPECTED;
336 if (mState != eInScript) {
337 FlushText();
340 int32_t nameSpaceID;
341 RefPtr<nsAtom> prefix, localName;
342 nsContentUtils::SplitExpatName(aName, getter_AddRefs(prefix),
343 getter_AddRefs(localName), &nameSpaceID);
345 RefPtr<mozilla::dom::NodeInfo> nodeInfo;
346 nodeInfo = mNodeInfoManager->GetNodeInfo(localName, prefix, nameSpaceID,
347 nsINode::ELEMENT_NODE);
349 nsresult rv = NS_OK;
350 switch (mState) {
351 case eInProlog:
352 // We're the root document element
353 rv = OpenRoot(aAtts, aAttsCount, nodeInfo);
354 break;
356 case eInDocumentElement:
357 rv = OpenTag(aAtts, aAttsCount, aLineNumber, nodeInfo);
358 break;
360 case eInEpilog:
361 case eInScript:
362 MOZ_LOG(
363 gContentSinkLog, LogLevel::Warning,
364 ("xul: warning: unexpected tags in epilog at line %d", aLineNumber));
365 rv = NS_ERROR_UNEXPECTED; // XXX
366 break;
369 return rv;
372 NS_IMETHODIMP
373 XULContentSinkImpl::HandleEndElement(const char16_t* aName) {
374 // Never EVER return anything but NS_OK or
375 // NS_ERROR_HTMLPARSER_BLOCK from this method. Doing so will blow
376 // the parser's little mind all over the planet.
377 nsresult rv;
379 RefPtr<nsXULPrototypeNode> node;
380 rv = mContextStack.GetTopNode(node);
382 if (NS_FAILED(rv)) {
383 return NS_OK;
386 switch (node->mType) {
387 case nsXULPrototypeNode::eType_Element: {
388 // Flush any text _now_, so that we'll get text nodes created
389 // before popping the stack.
390 FlushText();
392 // Pop the context stack and do prototype hookup.
393 nsPrototypeArray* children = nullptr;
394 rv = mContextStack.GetTopChildren(&children);
395 if (NS_FAILED(rv)) return rv;
397 nsXULPrototypeElement* element =
398 static_cast<nsXULPrototypeElement*>(node.get());
400 int32_t count = children->Length();
401 if (count) {
402 element->mChildren.SetCapacity(count);
404 for (int32_t i = 0; i < count; ++i)
405 element->mChildren.AppendElement(children->ElementAt(i));
407 } break;
409 case nsXULPrototypeNode::eType_Script: {
410 nsXULPrototypeScript* script =
411 static_cast<nsXULPrototypeScript*>(node.get());
413 // If given a src= attribute, we must ignore script tag content.
414 if (!script->mSrcURI && !script->HasStencil()) {
415 nsCOMPtr<Document> doc = do_QueryReferent(mDocument);
417 script->mOutOfLine = false;
418 if (doc) {
419 script->Compile(mText, mTextLength, mDocumentURL, script->mLineNo,
420 doc);
424 FlushText(false);
425 } break;
427 default:
428 NS_ERROR("didn't expect that");
429 break;
432 rv = mContextStack.Pop(&mState);
433 NS_ASSERTION(NS_SUCCEEDED(rv), "context stack corrupted");
434 if (NS_FAILED(rv)) return rv;
436 if (mContextStack.Depth() == 0) {
437 // The root element should -always- be an element, because
438 // it'll have been created via XULContentSinkImpl::OpenRoot().
439 NS_ASSERTION(node->mType == nsXULPrototypeNode::eType_Element,
440 "root is not an element");
441 if (node->mType != nsXULPrototypeNode::eType_Element)
442 return NS_ERROR_UNEXPECTED;
444 // Now that we're done parsing, set the prototype document's
445 // root element. This transfers ownership of the prototype
446 // element tree to the prototype document.
447 nsXULPrototypeElement* element =
448 static_cast<nsXULPrototypeElement*>(node.get());
450 mPrototype->SetRootElement(element);
451 mState = eInEpilog;
454 return NS_OK;
457 NS_IMETHODIMP
458 XULContentSinkImpl::HandleComment(const char16_t* aName) {
459 FlushText();
460 return NS_OK;
463 NS_IMETHODIMP
464 XULContentSinkImpl::HandleCDataSection(const char16_t* aData,
465 uint32_t aLength) {
466 FlushText();
467 return AddText(aData, aLength);
470 NS_IMETHODIMP
471 XULContentSinkImpl::HandleDoctypeDecl(const nsAString& aSubset,
472 const nsAString& aName,
473 const nsAString& aSystemId,
474 const nsAString& aPublicId,
475 nsISupports* aCatalogData) {
476 return NS_OK;
479 NS_IMETHODIMP
480 XULContentSinkImpl::HandleCharacterData(const char16_t* aData,
481 uint32_t aLength) {
482 if (aData && mState != eInProlog && mState != eInEpilog) {
483 return AddText(aData, aLength);
485 return NS_OK;
488 NS_IMETHODIMP
489 XULContentSinkImpl::HandleProcessingInstruction(const char16_t* aTarget,
490 const char16_t* aData) {
491 FlushText();
493 const nsDependentString target(aTarget);
494 const nsDependentString data(aData);
496 // Note: the created nsXULPrototypePI has mRefCnt == 1
497 RefPtr<nsXULPrototypePI> pi = new nsXULPrototypePI();
498 pi->mTarget = target;
499 pi->mData = data;
501 if (mState == eInProlog) {
502 // Note: passing in already addrefed pi
503 return mPrototype->AddProcessingInstruction(pi);
506 nsresult rv;
507 nsPrototypeArray* children = nullptr;
508 rv = mContextStack.GetTopChildren(&children);
509 if (NS_FAILED(rv)) {
510 return rv;
513 // XXX(Bug 1631371) Check if this should use a fallible operation as it
514 // pretended earlier.
515 children->AppendElement(pi);
517 return NS_OK;
520 NS_IMETHODIMP
521 XULContentSinkImpl::HandleXMLDeclaration(const char16_t* aVersion,
522 const char16_t* aEncoding,
523 int32_t aStandalone) {
524 return NS_OK;
527 NS_IMETHODIMP
528 XULContentSinkImpl::ReportError(const char16_t* aErrorText,
529 const char16_t* aSourceText,
530 nsIScriptError* aError, bool* _retval) {
531 MOZ_ASSERT(aError && aSourceText && aErrorText, "Check arguments!!!");
533 // The expat driver should report the error.
534 *_retval = true;
536 nsresult rv = NS_OK;
538 // make sure to empty the context stack so that
539 // <parsererror> could become the root element.
540 mContextStack.Clear();
542 mState = eInProlog;
544 // Clear any buffered-up text we have. It's enough to set the length to 0.
545 // The buffer itself is allocated when we're created and deleted in our
546 // destructor, so don't mess with it.
547 mTextLength = 0;
549 // return leaving the document empty if we're asked to not add a <parsererror>
550 // root node
551 nsCOMPtr<Document> idoc = do_QueryReferent(mDocument);
552 if (idoc && idoc->SuppressParserErrorElement()) {
553 return NS_OK;
556 const char16_t* noAtts[] = {0, 0};
558 constexpr auto errorNs =
559 u"http://www.mozilla.org/newlayout/xml/parsererror.xml"_ns;
561 nsAutoString parsererror(errorNs);
562 parsererror.Append((char16_t)0xFFFF);
563 parsererror.AppendLiteral("parsererror");
565 rv = HandleStartElement(parsererror.get(), noAtts, 0, 0, 0);
566 NS_ENSURE_SUCCESS(rv, rv);
568 rv = HandleCharacterData(aErrorText, NS_strlen(aErrorText));
569 NS_ENSURE_SUCCESS(rv, rv);
571 nsAutoString sourcetext(errorNs);
572 sourcetext.Append((char16_t)0xFFFF);
573 sourcetext.AppendLiteral("sourcetext");
575 rv = HandleStartElement(sourcetext.get(), noAtts, 0, 0, 0);
576 NS_ENSURE_SUCCESS(rv, rv);
578 rv = HandleCharacterData(aSourceText, NS_strlen(aSourceText));
579 NS_ENSURE_SUCCESS(rv, rv);
581 rv = HandleEndElement(sourcetext.get());
582 NS_ENSURE_SUCCESS(rv, rv);
584 rv = HandleEndElement(parsererror.get());
585 NS_ENSURE_SUCCESS(rv, rv);
587 return rv;
590 nsresult XULContentSinkImpl::OpenRoot(const char16_t** aAttributes,
591 const uint32_t aAttrLen,
592 mozilla::dom::NodeInfo* aNodeInfo) {
593 NS_ASSERTION(mState == eInProlog, "how'd we get here?");
594 if (mState != eInProlog) return NS_ERROR_UNEXPECTED;
596 if (aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML) ||
597 aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XUL)) {
598 MOZ_LOG(gContentSinkLog, LogLevel::Error,
599 ("xul: script tag not allowed as root content element"));
601 return NS_ERROR_UNEXPECTED;
604 // Create the element
605 RefPtr<nsXULPrototypeElement> element = new nsXULPrototypeElement(aNodeInfo);
607 // Add the attributes
608 nsresult rv = AddAttributes(aAttributes, aAttrLen, element);
609 if (NS_FAILED(rv)) return rv;
611 // Push the element onto the context stack, so that child
612 // containers will hook up to us as their parent.
613 mContextStack.Push(std::move(element), mState);
615 mState = eInDocumentElement;
616 return NS_OK;
619 nsresult XULContentSinkImpl::OpenTag(const char16_t** aAttributes,
620 const uint32_t aAttrLen,
621 const uint32_t aLineNumber,
622 mozilla::dom::NodeInfo* aNodeInfo) {
623 // Create the element
624 RefPtr<nsXULPrototypeElement> element = new nsXULPrototypeElement(aNodeInfo);
626 // Link this element to its parent.
627 nsPrototypeArray* children = nullptr;
628 nsresult rv = mContextStack.GetTopChildren(&children);
629 if (NS_FAILED(rv)) {
630 return rv;
633 // Add the attributes
634 rv = AddAttributes(aAttributes, aAttrLen, element);
635 if (NS_FAILED(rv)) return rv;
637 children->AppendElement(element);
639 if (aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML) ||
640 aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XUL)) {
641 // Do scripty things now
642 rv = OpenScript(aAttributes, aLineNumber);
643 NS_ENSURE_SUCCESS(rv, rv);
645 NS_ASSERTION(mState == eInScript || mState == eInDocumentElement,
646 "Unexpected state");
647 if (mState == eInScript) {
648 // OpenScript has pushed the nsPrototypeScriptElement onto the
649 // stack, so we're done.
650 return NS_OK;
654 // Push the element onto the context stack, so that child
655 // containers will hook up to us as their parent.
656 mContextStack.Push(std::move(element), mState);
658 mState = eInDocumentElement;
659 return NS_OK;
662 nsresult XULContentSinkImpl::OpenScript(const char16_t** aAttributes,
663 const uint32_t aLineNumber) {
664 bool isJavaScript = true;
665 nsresult rv;
667 // Look for SRC attribute and look for a LANGUAGE attribute
668 nsAutoString src;
669 while (*aAttributes) {
670 const nsDependentString key(aAttributes[0]);
671 if (key.EqualsLiteral("src")) {
672 src.Assign(aAttributes[1]);
673 } else if (key.EqualsLiteral("type")) {
674 nsDependentString str(aAttributes[1]);
675 nsContentTypeParser parser(str);
676 nsAutoString mimeType;
677 rv = parser.GetType(mimeType);
678 if (NS_FAILED(rv)) {
679 if (rv == NS_ERROR_INVALID_ARG) {
680 // Fail immediately rather than checking if later things
681 // are okay.
682 return NS_OK;
684 // We do want the warning here
685 NS_ENSURE_SUCCESS(rv, rv);
688 // NOTE(emilio): Module scripts don't pass this test, aren't cached yet.
689 // If they become cached, then we need to tweak
690 // PrototypeDocumentContentSink and remove the special cases there.
691 if (nsContentUtils::IsJavascriptMIMEType(mimeType)) {
692 isJavaScript = true;
694 // Get the version string, and ensure that JavaScript supports it.
695 nsAutoString versionName;
696 rv = parser.GetParameter("version", versionName);
698 if (NS_SUCCEEDED(rv)) {
699 nsContentUtils::ReportToConsoleNonLocalized(
700 u"Versioned JavaScripts are no longer supported. "
701 "Please remove the version parameter."_ns,
702 nsIScriptError::errorFlag, "XUL Document"_ns, nullptr,
703 mDocumentURL, u""_ns, aLineNumber);
704 isJavaScript = false;
705 } else if (rv != NS_ERROR_INVALID_ARG) {
706 return rv;
708 } else {
709 isJavaScript = false;
711 } else if (key.EqualsLiteral("language")) {
712 // Language is deprecated, and the impl in ScriptLoader ignores the
713 // various version strings anyway. So we make no attempt to support
714 // languages other than JS for language=
715 nsAutoString lang(aAttributes[1]);
716 if (nsContentUtils::IsJavaScriptLanguage(lang)) {
717 isJavaScript = true;
720 aAttributes += 2;
723 // Don't process scripts that aren't JavaScript.
724 if (!isJavaScript) {
725 return NS_OK;
728 nsCOMPtr<Document> doc(do_QueryReferent(mDocument));
729 nsCOMPtr<nsIScriptGlobalObject> globalObject;
730 if (doc) globalObject = do_QueryInterface(doc->GetWindow());
731 RefPtr<nsXULPrototypeScript> script = new nsXULPrototypeScript(aLineNumber);
733 // If there is a SRC attribute...
734 if (!src.IsEmpty()) {
735 // Use the SRC attribute value to load the URL
736 rv = NS_NewURI(getter_AddRefs(script->mSrcURI), src, nullptr, mDocumentURL);
738 // Check if this document is allowed to load a script from this source
739 // NOTE: if we ever allow scripts added via the DOM to run, we need to
740 // add a CheckLoadURI call for that as well.
741 if (NS_SUCCEEDED(rv)) {
742 if (!mSecMan)
743 mSecMan = do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
744 if (NS_SUCCEEDED(rv)) {
745 nsCOMPtr<Document> doc = do_QueryReferent(mDocument, &rv);
747 if (NS_SUCCEEDED(rv)) {
748 rv = mSecMan->CheckLoadURIWithPrincipal(
749 doc->NodePrincipal(), script->mSrcURI,
750 nsIScriptSecurityManager::ALLOW_CHROME, doc->InnerWindowID());
755 if (NS_FAILED(rv)) {
756 return rv;
759 // Attempt to deserialize an out-of-line script from the FastLoad
760 // file right away. Otherwise we'll end up reloading the script and
761 // corrupting the FastLoad file trying to serialize it, in the case
762 // where it's already there.
763 script->DeserializeOutOfLine(nullptr, mPrototype);
766 nsPrototypeArray* children = nullptr;
767 rv = mContextStack.GetTopChildren(&children);
768 if (NS_FAILED(rv)) {
769 return rv;
772 children->AppendElement(script);
774 mConstrainSize = false;
776 mContextStack.Push(script, mState);
777 mState = eInScript;
779 return NS_OK;
782 nsresult XULContentSinkImpl::AddAttributes(const char16_t** aAttributes,
783 const uint32_t aAttrLen,
784 nsXULPrototypeElement* aElement) {
785 // Add tag attributes to the element
786 nsresult rv;
788 // Create storage for the attributes
789 nsXULPrototypeAttribute* attrs = nullptr;
790 if (aAttrLen > 0) {
791 attrs = aElement->mAttributes.AppendElements(aAttrLen);
794 // Copy the attributes into the prototype
795 uint32_t i;
796 for (i = 0; i < aAttrLen; ++i) {
797 rv = NormalizeAttributeString(aAttributes[i * 2], attrs[i].mName);
798 NS_ENSURE_SUCCESS(rv, rv);
800 rv = aElement->SetAttrAt(i, nsDependentString(aAttributes[i * 2 + 1]),
801 mDocumentURL);
802 NS_ENSURE_SUCCESS(rv, rv);
804 if (MOZ_LOG_TEST(gContentSinkLog, LogLevel::Debug)) {
805 nsAutoString extraWhiteSpace;
806 int32_t cnt = mContextStack.Depth();
807 while (--cnt >= 0) extraWhiteSpace.AppendLiteral(" ");
808 nsAutoString qnameC, valueC;
809 qnameC.Assign(aAttributes[0]);
810 valueC.Assign(aAttributes[1]);
811 MOZ_LOG(gContentSinkLog, LogLevel::Debug,
812 ("xul: %.5d. %s %s=%s",
813 -1, // XXX pass in line number
814 NS_ConvertUTF16toUTF8(extraWhiteSpace).get(),
815 NS_ConvertUTF16toUTF8(qnameC).get(),
816 NS_ConvertUTF16toUTF8(valueC).get()));
820 return NS_OK;
823 nsresult XULContentSinkImpl::AddText(const char16_t* aText, int32_t aLength) {
824 // Create buffer when we first need it
825 if (0 == mTextSize) {
826 mText = (char16_t*)malloc(sizeof(char16_t) * 4096);
827 if (nullptr == mText) {
828 return NS_ERROR_OUT_OF_MEMORY;
830 mTextSize = 4096;
833 // Copy data from string into our buffer; flush buffer when it fills up
834 int32_t offset = 0;
835 while (0 != aLength) {
836 int32_t amount = mTextSize - mTextLength;
837 if (amount > aLength) {
838 amount = aLength;
840 if (0 == amount) {
841 if (mConstrainSize) {
842 nsresult rv = FlushText();
843 if (NS_OK != rv) {
844 return rv;
846 } else {
847 CheckedInt32 size = mTextSize;
848 size += aLength;
849 if (!size.isValid()) {
850 return NS_ERROR_OUT_OF_MEMORY;
852 mTextSize = size.value();
854 mText = (char16_t*)realloc(mText, sizeof(char16_t) * mTextSize);
855 if (nullptr == mText) {
856 return NS_ERROR_OUT_OF_MEMORY;
860 memcpy(&mText[mTextLength], aText + offset, sizeof(char16_t) * amount);
862 mTextLength += amount;
863 offset += amount;
864 aLength -= amount;
867 return NS_OK;