Backed out 2 changesets (bug 1908320) for causing wr failures on align-items-baseline...
[gecko.git] / dom / xul / nsXULContentSink.cpp
blob9a4f2deb2355cbb0a2c19c11d56a1b0488d61d1d
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 "nsNetUtil.h"
31 #include "nsString.h"
32 #include "nsReadableUtils.h"
33 #include "nsXULElement.h"
34 #include "mozilla/Logging.h"
35 #include "nsCRT.h"
37 #include "nsXULPrototypeDocument.h" // XXXbe temporary
38 #include "mozilla/css/Loader.h"
40 #include "nsUnicharUtils.h"
41 #include "nsGkAtoms.h"
42 #include "nsContentUtils.h"
43 #include "nsAttrName.h"
44 #include "nsXMLContentSink.h"
45 #include "nsIScriptError.h"
46 #include "nsContentTypeParser.h"
48 static mozilla::LazyLogModule gContentSinkLog("nsXULContentSink");
50 using namespace mozilla;
51 using namespace mozilla::dom;
52 //----------------------------------------------------------------------
54 XULContentSinkImpl::ContextStack::ContextStack() : mTop(nullptr), mDepth(0) {}
56 XULContentSinkImpl::ContextStack::~ContextStack() {
57 while (mTop) {
58 Entry* doomed = mTop;
59 mTop = mTop->mNext;
60 delete doomed;
64 void XULContentSinkImpl::ContextStack::Push(RefPtr<nsXULPrototypeNode>&& aNode,
65 State aState) {
66 mTop = new Entry(std::move(aNode), aState, mTop);
67 ++mDepth;
70 nsresult XULContentSinkImpl::ContextStack::Pop(State* aState) {
71 if (mDepth == 0) return NS_ERROR_UNEXPECTED;
73 Entry* entry = mTop;
74 mTop = mTop->mNext;
75 --mDepth;
77 *aState = entry->mState;
78 delete entry;
80 return NS_OK;
83 nsresult XULContentSinkImpl::ContextStack::GetTopNode(
84 RefPtr<nsXULPrototypeNode>& aNode) {
85 if (mDepth == 0) return NS_ERROR_UNEXPECTED;
87 aNode = mTop->mNode;
88 return NS_OK;
91 nsresult XULContentSinkImpl::ContextStack::GetTopChildren(
92 nsPrototypeArray** aChildren) {
93 if (mDepth == 0) return NS_ERROR_UNEXPECTED;
95 *aChildren = &(mTop->mChildren);
96 return NS_OK;
99 void XULContentSinkImpl::ContextStack::Clear() {
100 Entry* cur = mTop;
101 while (cur) {
102 // Release the root element (and its descendants).
103 Entry* next = cur->mNext;
104 delete cur;
105 cur = next;
108 mTop = nullptr;
109 mDepth = 0;
112 void XULContentSinkImpl::ContextStack::Traverse(
113 nsCycleCollectionTraversalCallback& aCb) {
114 nsCycleCollectionTraversalCallback& cb = aCb;
115 for (ContextStack::Entry* tmp = mTop; tmp; tmp = tmp->mNext) {
116 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNode)
117 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChildren)
121 //----------------------------------------------------------------------
123 XULContentSinkImpl::XULContentSinkImpl()
124 : mText(nullptr),
125 mTextLength(0),
126 mTextSize(0),
127 mConstrainSize(true),
128 mState(eInProlog) {}
130 XULContentSinkImpl::~XULContentSinkImpl() {
131 // The context stack _should_ be empty, unless something has gone wrong.
132 NS_ASSERTION(mContextStack.Depth() == 0, "Context stack not empty?");
133 mContextStack.Clear();
135 free(mText);
138 //----------------------------------------------------------------------
139 // nsISupports interface
141 NS_IMPL_CYCLE_COLLECTION_CLASS(XULContentSinkImpl)
143 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(XULContentSinkImpl)
144 NS_IMPL_CYCLE_COLLECTION_UNLINK(mNodeInfoManager)
145 tmp->mContextStack.Clear();
146 NS_IMPL_CYCLE_COLLECTION_UNLINK(mPrototype)
147 NS_IMPL_CYCLE_COLLECTION_UNLINK(mParser)
148 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
150 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(XULContentSinkImpl)
151 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNodeInfoManager)
152 tmp->mContextStack.Traverse(cb);
153 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrototype)
154 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParser)
155 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
157 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(XULContentSinkImpl)
158 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXMLContentSink)
159 NS_INTERFACE_MAP_ENTRY(nsIXMLContentSink)
160 NS_INTERFACE_MAP_ENTRY(nsIExpatSink)
161 NS_INTERFACE_MAP_ENTRY(nsIContentSink)
162 NS_INTERFACE_MAP_END
164 NS_IMPL_CYCLE_COLLECTING_ADDREF(XULContentSinkImpl)
165 NS_IMPL_CYCLE_COLLECTING_RELEASE(XULContentSinkImpl)
167 //----------------------------------------------------------------------
168 // nsIContentSink interface
170 NS_IMETHODIMP
171 XULContentSinkImpl::DidBuildModel(bool aTerminated) {
172 nsCOMPtr<Document> doc(mDocument);
173 if (doc) {
174 mPrototype->NotifyLoadDone();
175 mDocument = nullptr;
178 // Drop our reference to the parser to get rid of a circular
179 // reference.
180 mParser = nullptr;
181 return NS_OK;
184 NS_IMETHODIMP
185 XULContentSinkImpl::WillInterrupt(void) {
186 // XXX Notify the docshell, if necessary
187 return NS_OK;
190 void XULContentSinkImpl::WillResume() {
191 // XXX Notify the docshell, if necessary
194 NS_IMETHODIMP
195 XULContentSinkImpl::SetParser(nsParserBase* aParser) {
196 mParser = aParser;
197 return NS_OK;
200 void XULContentSinkImpl::SetDocumentCharset(
201 NotNull<const Encoding*> aEncoding) {
202 nsCOMPtr<Document> doc(mDocument);
203 if (doc) {
204 doc->SetDocumentCharacterSet(aEncoding);
208 nsISupports* XULContentSinkImpl::GetTarget() { return ToSupports(mDocument); }
210 //----------------------------------------------------------------------
212 nsresult XULContentSinkImpl::Init(Document* aDocument,
213 nsXULPrototypeDocument* aPrototype) {
214 MOZ_ASSERT(aDocument != nullptr, "null ptr");
215 if (!aDocument) return NS_ERROR_NULL_POINTER;
217 mDocument = aDocument;
218 mPrototype = aPrototype;
220 mDocumentURL = mPrototype->GetURI();
221 mNodeInfoManager = aPrototype->GetNodeInfoManager();
222 if (!mNodeInfoManager) return NS_ERROR_UNEXPECTED;
224 mState = eInProlog;
225 return NS_OK;
228 //----------------------------------------------------------------------
230 // Text buffering
233 bool XULContentSinkImpl::IsDataInBuffer(char16_t* buffer, int32_t length) {
234 for (int32_t i = 0; i < length; ++i) {
235 if (buffer[i] == ' ' || buffer[i] == '\t' || buffer[i] == '\n' ||
236 buffer[i] == '\r')
237 continue;
239 return true;
241 return false;
244 nsresult XULContentSinkImpl::FlushText(bool aCreateTextNode) {
245 nsresult rv;
247 do {
248 // Don't do anything if there's no text to create a node from, or
249 // if they've told us not to create a text node
250 if (!mTextLength) break;
252 if (!aCreateTextNode) break;
254 RefPtr<nsXULPrototypeNode> node;
255 rv = mContextStack.GetTopNode(node);
256 if (NS_FAILED(rv)) return rv;
258 bool stripWhitespace = false;
259 if (node->mType == nsXULPrototypeNode::eType_Element) {
260 mozilla::dom::NodeInfo* nodeInfo =
261 static_cast<nsXULPrototypeElement*>(node.get())->mNodeInfo;
263 if (nodeInfo->NamespaceEquals(kNameSpaceID_XUL))
264 stripWhitespace = !nodeInfo->Equals(nsGkAtoms::label) &&
265 !nodeInfo->Equals(nsGkAtoms::description);
268 // Don't bother if there's nothing but whitespace.
269 if (stripWhitespace && !IsDataInBuffer(mText, mTextLength)) break;
271 // Don't bother if we're not in XUL document body
272 if (mState != eInDocumentElement || mContextStack.Depth() == 0) break;
274 RefPtr<nsXULPrototypeText> text = new nsXULPrototypeText();
275 text->mValue.Assign(mText, mTextLength);
276 if (stripWhitespace) text->mValue.Trim(" \t\n\r");
278 // hook it up
279 nsPrototypeArray* children = nullptr;
280 rv = mContextStack.GetTopChildren(&children);
281 if (NS_FAILED(rv)) return rv;
283 children->AppendElement(text.forget());
284 } while (0);
286 // Reset our text buffer
287 mTextLength = 0;
288 return NS_OK;
291 //----------------------------------------------------------------------
293 nsresult XULContentSinkImpl::NormalizeAttributeString(
294 const char16_t* aExpatName, nsAttrName& aName) {
295 int32_t nameSpaceID;
296 RefPtr<nsAtom> prefix, localName;
297 nsContentUtils::SplitExpatName(aExpatName, getter_AddRefs(prefix),
298 getter_AddRefs(localName), &nameSpaceID);
300 if (nameSpaceID == kNameSpaceID_None) {
301 aName.SetTo(localName);
303 return NS_OK;
306 RefPtr<mozilla::dom::NodeInfo> ni;
307 ni = mNodeInfoManager->GetNodeInfo(localName, prefix, nameSpaceID,
308 nsINode::ATTRIBUTE_NODE);
309 aName.SetTo(ni);
311 return NS_OK;
314 /**** BEGIN NEW APIs ****/
316 NS_IMETHODIMP
317 XULContentSinkImpl::HandleStartElement(const char16_t* aName,
318 const char16_t** aAtts,
319 uint32_t aAttsCount,
320 uint32_t aLineNumber,
321 uint32_t aColumnNumber) {
322 // XXX Hopefully the parser will flag this before we get here. If
323 // we're in the epilog, there should be no new elements
324 MOZ_ASSERT(mState != eInEpilog, "tag in XUL doc epilog");
325 MOZ_ASSERT(aAttsCount % 2 == 0, "incorrect aAttsCount");
327 // Adjust aAttsCount so it's the actual number of attributes
328 aAttsCount /= 2;
330 if (mState == eInEpilog) return NS_ERROR_UNEXPECTED;
332 if (mState != eInScript) {
333 FlushText();
336 int32_t nameSpaceID;
337 RefPtr<nsAtom> prefix, localName;
338 nsContentUtils::SplitExpatName(aName, getter_AddRefs(prefix),
339 getter_AddRefs(localName), &nameSpaceID);
341 RefPtr<mozilla::dom::NodeInfo> nodeInfo;
342 nodeInfo = mNodeInfoManager->GetNodeInfo(localName, prefix, nameSpaceID,
343 nsINode::ELEMENT_NODE);
345 nsresult rv = NS_OK;
346 switch (mState) {
347 case eInProlog:
348 // We're the root document element
349 rv = OpenRoot(aAtts, aAttsCount, nodeInfo);
350 break;
352 case eInDocumentElement:
353 rv = OpenTag(aAtts, aAttsCount, aLineNumber, nodeInfo);
354 break;
356 case eInEpilog:
357 case eInScript:
358 MOZ_LOG(
359 gContentSinkLog, LogLevel::Warning,
360 ("xul: warning: unexpected tags in epilog at line %d", aLineNumber));
361 rv = NS_ERROR_UNEXPECTED; // XXX
362 break;
365 return rv;
368 NS_IMETHODIMP
369 XULContentSinkImpl::HandleEndElement(const char16_t* aName) {
370 // Never EVER return anything but NS_OK or
371 // NS_ERROR_HTMLPARSER_BLOCK from this method. Doing so will blow
372 // the parser's little mind all over the planet.
373 nsresult rv;
375 RefPtr<nsXULPrototypeNode> node;
376 rv = mContextStack.GetTopNode(node);
378 if (NS_FAILED(rv)) {
379 return NS_OK;
382 switch (node->mType) {
383 case nsXULPrototypeNode::eType_Element: {
384 // Flush any text _now_, so that we'll get text nodes created
385 // before popping the stack.
386 FlushText();
388 // Pop the context stack and do prototype hookup.
389 nsPrototypeArray* children = nullptr;
390 rv = mContextStack.GetTopChildren(&children);
391 if (NS_FAILED(rv)) return rv;
393 nsXULPrototypeElement* element =
394 static_cast<nsXULPrototypeElement*>(node.get());
396 int32_t count = children->Length();
397 if (count) {
398 element->mChildren.SetCapacity(count);
400 for (int32_t i = 0; i < count; ++i)
401 element->mChildren.AppendElement(children->ElementAt(i));
403 } break;
405 case nsXULPrototypeNode::eType_Script: {
406 nsXULPrototypeScript* script =
407 static_cast<nsXULPrototypeScript*>(node.get());
409 // If given a src= attribute, we must ignore script tag content.
410 if (!script->mSrcURI && !script->HasStencil()) {
411 nsCOMPtr<Document> doc(mDocument);
413 script->mOutOfLine = false;
414 if (doc) {
415 script->Compile(mText, mTextLength, mDocumentURL, script->mLineNo,
416 doc);
420 FlushText(false);
421 } break;
423 default:
424 NS_ERROR("didn't expect that");
425 break;
428 rv = mContextStack.Pop(&mState);
429 NS_ASSERTION(NS_SUCCEEDED(rv), "context stack corrupted");
430 if (NS_FAILED(rv)) return rv;
432 if (mContextStack.Depth() == 0) {
433 // The root element should -always- be an element, because
434 // it'll have been created via XULContentSinkImpl::OpenRoot().
435 NS_ASSERTION(node->mType == nsXULPrototypeNode::eType_Element,
436 "root is not an element");
437 if (node->mType != nsXULPrototypeNode::eType_Element)
438 return NS_ERROR_UNEXPECTED;
440 // Now that we're done parsing, set the prototype document's
441 // root element. This transfers ownership of the prototype
442 // element tree to the prototype document.
443 nsXULPrototypeElement* element =
444 static_cast<nsXULPrototypeElement*>(node.get());
446 mPrototype->SetRootElement(element);
447 mState = eInEpilog;
450 return NS_OK;
453 NS_IMETHODIMP
454 XULContentSinkImpl::HandleComment(const char16_t* aName) {
455 FlushText();
456 return NS_OK;
459 NS_IMETHODIMP
460 XULContentSinkImpl::HandleCDataSection(const char16_t* aData,
461 uint32_t aLength) {
462 FlushText();
463 return AddText(aData, aLength);
466 NS_IMETHODIMP
467 XULContentSinkImpl::HandleDoctypeDecl(const nsAString& aSubset,
468 const nsAString& aName,
469 const nsAString& aSystemId,
470 const nsAString& aPublicId,
471 nsISupports* aCatalogData) {
472 return NS_OK;
475 NS_IMETHODIMP
476 XULContentSinkImpl::HandleCharacterData(const char16_t* aData,
477 uint32_t aLength) {
478 if (aData && mState != eInProlog && mState != eInEpilog) {
479 return AddText(aData, aLength);
481 return NS_OK;
484 NS_IMETHODIMP
485 XULContentSinkImpl::HandleProcessingInstruction(const char16_t* aTarget,
486 const char16_t* aData) {
487 FlushText();
489 const nsDependentString target(aTarget);
490 const nsDependentString data(aData);
492 // Note: the created nsXULPrototypePI has mRefCnt == 1
493 RefPtr<nsXULPrototypePI> pi = new nsXULPrototypePI();
494 pi->mTarget = target;
495 pi->mData = data;
497 if (mState == eInProlog) {
498 // Note: passing in already addrefed pi
499 return mPrototype->AddProcessingInstruction(pi);
502 nsresult rv;
503 nsPrototypeArray* children = nullptr;
504 rv = mContextStack.GetTopChildren(&children);
505 if (NS_FAILED(rv)) {
506 return rv;
509 // XXX(Bug 1631371) Check if this should use a fallible operation as it
510 // pretended earlier.
511 children->AppendElement(pi);
513 return NS_OK;
516 NS_IMETHODIMP
517 XULContentSinkImpl::HandleXMLDeclaration(const char16_t* aVersion,
518 const char16_t* aEncoding,
519 int32_t aStandalone) {
520 return NS_OK;
523 NS_IMETHODIMP
524 XULContentSinkImpl::ReportError(const char16_t* aErrorText,
525 const char16_t* aSourceText,
526 nsIScriptError* aError, bool* _retval) {
527 MOZ_ASSERT(aError && aSourceText && aErrorText, "Check arguments!!!");
529 // The expat driver should report the error.
530 *_retval = true;
532 nsresult rv = NS_OK;
534 // make sure to empty the context stack so that
535 // <parsererror> could become the root element.
536 mContextStack.Clear();
538 mState = eInProlog;
540 // Clear any buffered-up text we have. It's enough to set the length to 0.
541 // The buffer itself is allocated when we're created and deleted in our
542 // destructor, so don't mess with it.
543 mTextLength = 0;
545 // return leaving the document empty if we're asked to not add a <parsererror>
546 // root node
547 nsCOMPtr<Document> idoc(mDocument);
548 if (idoc && idoc->SuppressParserErrorElement()) {
549 return NS_OK;
552 const char16_t* noAtts[] = {0, 0};
554 constexpr auto errorNs =
555 u"http://www.mozilla.org/newlayout/xml/parsererror.xml"_ns;
557 nsAutoString parsererror(errorNs);
558 parsererror.Append((char16_t)0xFFFF);
559 parsererror.AppendLiteral("parsererror");
561 rv = HandleStartElement(parsererror.get(), noAtts, 0, 0, 0);
562 NS_ENSURE_SUCCESS(rv, rv);
564 rv = HandleCharacterData(aErrorText, NS_strlen(aErrorText));
565 NS_ENSURE_SUCCESS(rv, rv);
567 nsAutoString sourcetext(errorNs);
568 sourcetext.Append((char16_t)0xFFFF);
569 sourcetext.AppendLiteral("sourcetext");
571 rv = HandleStartElement(sourcetext.get(), noAtts, 0, 0, 0);
572 NS_ENSURE_SUCCESS(rv, rv);
574 rv = HandleCharacterData(aSourceText, NS_strlen(aSourceText));
575 NS_ENSURE_SUCCESS(rv, rv);
577 rv = HandleEndElement(sourcetext.get());
578 NS_ENSURE_SUCCESS(rv, rv);
580 rv = HandleEndElement(parsererror.get());
581 NS_ENSURE_SUCCESS(rv, rv);
583 return rv;
586 nsresult XULContentSinkImpl::OpenRoot(const char16_t** aAttributes,
587 const uint32_t aAttrLen,
588 mozilla::dom::NodeInfo* aNodeInfo) {
589 NS_ASSERTION(mState == eInProlog, "how'd we get here?");
590 if (mState != eInProlog) return NS_ERROR_UNEXPECTED;
592 if (aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML) ||
593 aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XUL)) {
594 MOZ_LOG(gContentSinkLog, LogLevel::Error,
595 ("xul: script tag not allowed as root content element"));
597 return NS_ERROR_UNEXPECTED;
600 // Create the element
601 RefPtr<nsXULPrototypeElement> element = new nsXULPrototypeElement(aNodeInfo);
603 // Add the attributes
604 nsresult rv = AddAttributes(aAttributes, aAttrLen, element);
605 if (NS_FAILED(rv)) return rv;
607 // Push the element onto the context stack, so that child
608 // containers will hook up to us as their parent.
609 mContextStack.Push(std::move(element), mState);
611 mState = eInDocumentElement;
612 return NS_OK;
615 nsresult XULContentSinkImpl::OpenTag(const char16_t** aAttributes,
616 const uint32_t aAttrLen,
617 const uint32_t aLineNumber,
618 mozilla::dom::NodeInfo* aNodeInfo) {
619 // Create the element
620 RefPtr<nsXULPrototypeElement> element = new nsXULPrototypeElement(aNodeInfo);
622 // Link this element to its parent.
623 nsPrototypeArray* children = nullptr;
624 nsresult rv = mContextStack.GetTopChildren(&children);
625 if (NS_FAILED(rv)) {
626 return rv;
629 // Add the attributes
630 rv = AddAttributes(aAttributes, aAttrLen, element);
631 if (NS_FAILED(rv)) return rv;
633 children->AppendElement(element);
635 if (aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML) ||
636 aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XUL)) {
637 // Do scripty things now
638 rv = OpenScript(aAttributes, aLineNumber);
639 NS_ENSURE_SUCCESS(rv, rv);
641 NS_ASSERTION(mState == eInScript || mState == eInDocumentElement,
642 "Unexpected state");
643 if (mState == eInScript) {
644 // OpenScript has pushed the nsPrototypeScriptElement onto the
645 // stack, so we're done.
646 return NS_OK;
650 // Push the element onto the context stack, so that child
651 // containers will hook up to us as their parent.
652 mContextStack.Push(std::move(element), mState);
654 mState = eInDocumentElement;
655 return NS_OK;
658 nsresult XULContentSinkImpl::OpenScript(const char16_t** aAttributes,
659 const uint32_t aLineNumber) {
660 bool isJavaScript = true;
661 nsresult rv;
663 // Look for SRC attribute and look for a LANGUAGE attribute
664 nsAutoString src;
665 while (*aAttributes) {
666 const nsDependentString key(aAttributes[0]);
667 if (key.EqualsLiteral("src")) {
668 src.Assign(aAttributes[1]);
669 } else if (key.EqualsLiteral("type")) {
670 nsDependentString str(aAttributes[1]);
671 nsContentTypeParser parser(str);
672 nsAutoString mimeType;
673 rv = parser.GetType(mimeType);
674 if (NS_FAILED(rv)) {
675 if (rv == NS_ERROR_INVALID_ARG) {
676 // Fail immediately rather than checking if later things
677 // are okay.
678 return NS_OK;
680 // We do want the warning here
681 NS_ENSURE_SUCCESS(rv, rv);
684 // NOTE(emilio): Module scripts don't pass this test, aren't cached yet.
685 // If they become cached, then we need to tweak
686 // PrototypeDocumentContentSink and remove the special cases there.
687 if (nsContentUtils::IsJavascriptMIMEType(mimeType)) {
688 isJavaScript = true;
690 // Get the version string, and ensure that JavaScript supports it.
691 nsAutoString versionName;
692 rv = parser.GetParameter("version", versionName);
694 if (NS_SUCCEEDED(rv)) {
695 nsContentUtils::ReportToConsoleNonLocalized(
696 u"Versioned JavaScripts are no longer supported. "
697 "Please remove the version parameter."_ns,
698 nsIScriptError::errorFlag, "XUL Document"_ns, nullptr,
699 mDocumentURL, u""_ns, aLineNumber);
700 isJavaScript = false;
701 } else if (rv != NS_ERROR_INVALID_ARG) {
702 return rv;
704 } else {
705 isJavaScript = false;
707 } else if (key.EqualsLiteral("language")) {
708 // Language is deprecated, and the impl in ScriptLoader ignores the
709 // various version strings anyway. So we make no attempt to support
710 // languages other than JS for language=
711 nsAutoString lang(aAttributes[1]);
712 if (nsContentUtils::IsJavaScriptLanguage(lang)) {
713 isJavaScript = true;
716 aAttributes += 2;
719 // Don't process scripts that aren't JavaScript.
720 if (!isJavaScript) {
721 return NS_OK;
724 nsCOMPtr<Document> doc(mDocument);
725 nsCOMPtr<nsIScriptGlobalObject> globalObject;
726 if (doc) globalObject = do_QueryInterface(doc->GetWindow());
727 RefPtr<nsXULPrototypeScript> script = new nsXULPrototypeScript(aLineNumber);
729 // If there is a SRC attribute...
730 if (!src.IsEmpty()) {
731 // Use the SRC attribute value to load the URL
732 rv = NS_NewURI(getter_AddRefs(script->mSrcURI), src, nullptr, mDocumentURL);
734 // Check if this document is allowed to load a script from this source
735 // NOTE: if we ever allow scripts added via the DOM to run, we need to
736 // add a CheckLoadURI call for that as well.
737 if (NS_SUCCEEDED(rv)) {
738 if (!mSecMan)
739 mSecMan = do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
740 if (NS_SUCCEEDED(rv) && doc) {
741 rv = mSecMan->CheckLoadURIWithPrincipal(
742 doc->NodePrincipal(), script->mSrcURI,
743 nsIScriptSecurityManager::ALLOW_CHROME, doc->InnerWindowID());
747 if (NS_FAILED(rv)) {
748 return rv;
751 // Attempt to deserialize an out-of-line script from the FastLoad
752 // file right away. Otherwise we'll end up reloading the script and
753 // corrupting the FastLoad file trying to serialize it, in the case
754 // where it's already there.
755 script->DeserializeOutOfLine(nullptr, mPrototype);
758 nsPrototypeArray* children = nullptr;
759 rv = mContextStack.GetTopChildren(&children);
760 if (NS_FAILED(rv)) {
761 return rv;
764 children->AppendElement(script);
766 mConstrainSize = false;
768 mContextStack.Push(script, mState);
769 mState = eInScript;
771 return NS_OK;
774 nsresult XULContentSinkImpl::AddAttributes(const char16_t** aAttributes,
775 const uint32_t aAttrLen,
776 nsXULPrototypeElement* aElement) {
777 // Add tag attributes to the element
778 nsresult rv;
780 // Create storage for the attributes
781 nsXULPrototypeAttribute* attrs = nullptr;
782 if (aAttrLen > 0) {
783 attrs = aElement->mAttributes.AppendElements(aAttrLen);
786 // Copy the attributes into the prototype
787 uint32_t i;
788 for (i = 0; i < aAttrLen; ++i) {
789 rv = NormalizeAttributeString(aAttributes[i * 2], attrs[i].mName);
790 NS_ENSURE_SUCCESS(rv, rv);
792 rv = aElement->SetAttrAt(i, nsDependentString(aAttributes[i * 2 + 1]),
793 mDocumentURL);
794 NS_ENSURE_SUCCESS(rv, rv);
796 if (MOZ_LOG_TEST(gContentSinkLog, LogLevel::Debug)) {
797 nsAutoString extraWhiteSpace;
798 int32_t cnt = mContextStack.Depth();
799 while (--cnt >= 0) extraWhiteSpace.AppendLiteral(" ");
800 nsAutoString qnameC, valueC;
801 qnameC.Assign(aAttributes[0]);
802 valueC.Assign(aAttributes[1]);
803 MOZ_LOG(gContentSinkLog, LogLevel::Debug,
804 ("xul: %.5d. %s %s=%s",
805 -1, // XXX pass in line number
806 NS_ConvertUTF16toUTF8(extraWhiteSpace).get(),
807 NS_ConvertUTF16toUTF8(qnameC).get(),
808 NS_ConvertUTF16toUTF8(valueC).get()));
812 return NS_OK;
815 nsresult XULContentSinkImpl::AddText(const char16_t* aText, int32_t aLength) {
816 // Create buffer when we first need it
817 if (0 == mTextSize) {
818 mText = (char16_t*)malloc(sizeof(char16_t) * 4096);
819 if (nullptr == mText) {
820 return NS_ERROR_OUT_OF_MEMORY;
822 mTextSize = 4096;
825 // Copy data from string into our buffer; flush buffer when it fills up
826 int32_t offset = 0;
827 while (0 != aLength) {
828 int32_t amount = mTextSize - mTextLength;
829 if (amount > aLength) {
830 amount = aLength;
832 if (0 == amount) {
833 if (mConstrainSize) {
834 nsresult rv = FlushText();
835 if (NS_OK != rv) {
836 return rv;
838 } else {
839 CheckedInt32 size = mTextSize;
840 size += aLength;
841 if (!size.isValid()) {
842 return NS_ERROR_OUT_OF_MEMORY;
844 mTextSize = size.value();
846 mText = (char16_t*)realloc(mText, sizeof(char16_t) * mTextSize);
847 if (nullptr == mText) {
848 return NS_ERROR_OUT_OF_MEMORY;
852 memcpy(&mText[mTextLength], aText + offset, sizeof(char16_t) * amount);
854 mTextLength += amount;
855 offset += amount;
856 aLength -= amount;
859 return NS_OK;