Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* vim: set ts=8 sts=4 et sw=4 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.
10 *
11 * For more information on XUL,
12 * see http://developer.mozilla.org/en/docs/XUL
13 */
15 #include "nsXULContentSink.h"
17 #include "jsfriendapi.h"
19 #include "nsCOMPtr.h"
20 #include "nsForwardReference.h"
21 #include "nsHTMLStyleSheet.h"
22 #include "nsIContentSink.h"
23 #include "nsIDocument.h"
24 #include "nsIDOMEventListener.h"
25 #include "nsIDOMHTMLFormElement.h"
26 #include "nsIDOMXULDocument.h"
27 #include "nsIFormControl.h"
28 #include "nsINodeInfo.h"
29 #include "nsIScriptContext.h"
30 #include "nsIScriptGlobalObject.h"
31 #include "nsIServiceManager.h"
32 #include "nsIURL.h"
33 #include "nsNameSpaceManager.h"
34 #include "nsParserBase.h"
35 #include "nsViewManager.h"
36 #include "nsIXULDocument.h"
37 #include "nsIScriptSecurityManager.h"
38 #include "nsLayoutCID.h"
39 #include "nsNetUtil.h"
40 #include "nsRDFCID.h"
41 #include "nsXPIDLString.h"
42 #include "nsReadableUtils.h"
43 #include "nsXULElement.h"
44 #include "prlog.h"
45 #include "prmem.h"
46 #include "nsCRT.h"
48 #include "nsXULPrototypeDocument.h" // XXXbe temporary
49 #include "mozilla/css/Loader.h"
51 #include "nsUnicharUtils.h"
52 #include "nsGkAtoms.h"
53 #include "nsContentUtils.h"
54 #include "nsAttrName.h"
55 #include "nsXMLContentSink.h"
56 #include "nsIConsoleService.h"
57 #include "nsIScriptError.h"
58 #include "nsContentTypeParser.h"
60 #ifdef PR_LOGGING
61 static PRLogModuleInfo* gContentSinkLog;
62 #endif
64 //----------------------------------------------------------------------
66 XULContentSinkImpl::ContextStack::ContextStack()
67 : mTop(nullptr), mDepth(0)
68 {
69 }
71 XULContentSinkImpl::ContextStack::~ContextStack()
72 {
73 while (mTop) {
74 Entry* doomed = mTop;
75 mTop = mTop->mNext;
76 delete doomed;
77 }
78 }
80 nsresult
81 XULContentSinkImpl::ContextStack::Push(nsXULPrototypeNode* aNode, State aState)
82 {
83 Entry* entry = new Entry;
84 if (! entry)
85 return NS_ERROR_OUT_OF_MEMORY;
87 entry->mNode = aNode;
88 entry->mState = aState;
89 entry->mNext = mTop;
90 mTop = entry;
92 ++mDepth;
93 return NS_OK;
94 }
96 nsresult
97 XULContentSinkImpl::ContextStack::Pop(State* aState)
98 {
99 if (mDepth == 0)
100 return NS_ERROR_UNEXPECTED;
102 Entry* entry = mTop;
103 mTop = mTop->mNext;
104 --mDepth;
106 *aState = entry->mState;
107 delete entry;
109 return NS_OK;
110 }
113 nsresult
114 XULContentSinkImpl::ContextStack::GetTopNode(nsRefPtr<nsXULPrototypeNode>& aNode)
115 {
116 if (mDepth == 0)
117 return NS_ERROR_UNEXPECTED;
119 aNode = mTop->mNode;
120 return NS_OK;
121 }
124 nsresult
125 XULContentSinkImpl::ContextStack::GetTopChildren(nsPrototypeArray** aChildren)
126 {
127 if (mDepth == 0)
128 return NS_ERROR_UNEXPECTED;
130 *aChildren = &(mTop->mChildren);
131 return NS_OK;
132 }
134 void
135 XULContentSinkImpl::ContextStack::Clear()
136 {
137 Entry *cur = mTop;
138 while (cur) {
139 // Release the root element (and its descendants).
140 Entry *next = cur->mNext;
141 delete cur;
142 cur = next;
143 }
145 mTop = nullptr;
146 mDepth = 0;
147 }
149 void
150 XULContentSinkImpl::ContextStack::Traverse(nsCycleCollectionTraversalCallback& aCb)
151 {
152 nsCycleCollectionTraversalCallback& cb = aCb;
153 for (ContextStack::Entry* tmp = mTop; tmp; tmp = tmp->mNext) {
154 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNode)
155 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChildren)
156 }
157 }
159 //----------------------------------------------------------------------
162 XULContentSinkImpl::XULContentSinkImpl()
163 : mText(nullptr),
164 mTextLength(0),
165 mTextSize(0),
166 mConstrainSize(true),
167 mState(eInProlog),
168 mParser(nullptr)
169 {
171 #ifdef PR_LOGGING
172 if (! gContentSinkLog)
173 gContentSinkLog = PR_NewLogModule("nsXULContentSink");
174 #endif
175 }
178 XULContentSinkImpl::~XULContentSinkImpl()
179 {
180 NS_IF_RELEASE(mParser); // XXX should've been released by now, unless error.
182 // The context stack _should_ be empty, unless something has gone wrong.
183 NS_ASSERTION(mContextStack.Depth() == 0, "Context stack not empty?");
184 mContextStack.Clear();
186 moz_free(mText);
187 }
189 //----------------------------------------------------------------------
190 // nsISupports interface
192 NS_IMPL_CYCLE_COLLECTION_CLASS(XULContentSinkImpl)
194 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(XULContentSinkImpl)
195 NS_IMPL_CYCLE_COLLECTION_UNLINK(mNodeInfoManager)
196 tmp->mContextStack.Clear();
197 NS_IMPL_CYCLE_COLLECTION_UNLINK(mPrototype)
198 NS_IF_RELEASE(tmp->mParser);
199 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
201 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(XULContentSinkImpl)
202 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNodeInfoManager)
203 tmp->mContextStack.Traverse(cb);
204 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrototype)
205 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mParser)
206 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
208 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(XULContentSinkImpl)
209 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXMLContentSink)
210 NS_INTERFACE_MAP_ENTRY(nsIXMLContentSink)
211 NS_INTERFACE_MAP_ENTRY(nsIExpatSink)
212 NS_INTERFACE_MAP_ENTRY(nsIContentSink)
213 NS_INTERFACE_MAP_END
215 NS_IMPL_CYCLE_COLLECTING_ADDREF(XULContentSinkImpl)
216 NS_IMPL_CYCLE_COLLECTING_RELEASE(XULContentSinkImpl)
218 //----------------------------------------------------------------------
219 // nsIContentSink interface
221 NS_IMETHODIMP
222 XULContentSinkImpl::WillBuildModel(nsDTDMode aDTDMode)
223 {
224 #if FIXME
225 if (! mParentContentSink) {
226 // If we're _not_ an overlay, then notify the document that
227 // the load is beginning.
228 mDocument->BeginLoad();
229 }
230 #endif
232 return NS_OK;
233 }
235 NS_IMETHODIMP
236 XULContentSinkImpl::DidBuildModel(bool aTerminated)
237 {
238 nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
239 if (doc) {
240 doc->EndLoad();
241 mDocument = nullptr;
242 }
244 // Drop our reference to the parser to get rid of a circular
245 // reference.
246 NS_IF_RELEASE(mParser);
247 return NS_OK;
248 }
250 NS_IMETHODIMP
251 XULContentSinkImpl::WillInterrupt(void)
252 {
253 // XXX Notify the docshell, if necessary
254 return NS_OK;
255 }
257 NS_IMETHODIMP
258 XULContentSinkImpl::WillResume(void)
259 {
260 // XXX Notify the docshell, if necessary
261 return NS_OK;
262 }
264 NS_IMETHODIMP
265 XULContentSinkImpl::SetParser(nsParserBase* aParser)
266 {
267 NS_IF_RELEASE(mParser);
268 mParser = aParser;
269 NS_IF_ADDREF(mParser);
270 return NS_OK;
271 }
273 NS_IMETHODIMP
274 XULContentSinkImpl::SetDocumentCharset(nsACString& aCharset)
275 {
276 nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
277 if (doc) {
278 doc->SetDocumentCharacterSet(aCharset);
279 }
281 return NS_OK;
282 }
284 nsISupports *
285 XULContentSinkImpl::GetTarget()
286 {
287 nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
288 return doc;
289 }
291 //----------------------------------------------------------------------
293 nsresult
294 XULContentSinkImpl::Init(nsIDocument* aDocument,
295 nsXULPrototypeDocument* aPrototype)
296 {
297 NS_PRECONDITION(aDocument != nullptr, "null ptr");
298 if (! aDocument)
299 return NS_ERROR_NULL_POINTER;
301 nsresult rv;
303 mDocument = do_GetWeakReference(aDocument);
304 mPrototype = aPrototype;
306 mDocumentURL = mPrototype->GetURI();
308 // XXX this presumes HTTP header info is already set in document
309 // XXX if it isn't we need to set it here...
310 // XXXbz not like GetHeaderData on the proto doc _does_ anything....
311 nsAutoString preferredStyle;
312 rv = mPrototype->GetHeaderData(nsGkAtoms::headerDefaultStyle,
313 preferredStyle);
314 if (NS_FAILED(rv)) return rv;
316 if (!preferredStyle.IsEmpty()) {
317 aDocument->SetHeaderData(nsGkAtoms::headerDefaultStyle,
318 preferredStyle);
319 }
321 // Set the right preferred style on the document's CSSLoader.
322 aDocument->CSSLoader()->SetPreferredSheet(preferredStyle);
324 mNodeInfoManager = aPrototype->GetNodeInfoManager();
325 if (! mNodeInfoManager)
326 return NS_ERROR_UNEXPECTED;
328 mState = eInProlog;
329 return NS_OK;
330 }
333 //----------------------------------------------------------------------
334 //
335 // Text buffering
336 //
338 bool
339 XULContentSinkImpl::IsDataInBuffer(char16_t* buffer, int32_t length)
340 {
341 for (int32_t i = 0; i < length; ++i) {
342 if (buffer[i] == ' ' ||
343 buffer[i] == '\t' ||
344 buffer[i] == '\n' ||
345 buffer[i] == '\r')
346 continue;
348 return true;
349 }
350 return false;
351 }
354 nsresult
355 XULContentSinkImpl::FlushText(bool aCreateTextNode)
356 {
357 nsresult rv;
359 do {
360 // Don't do anything if there's no text to create a node from, or
361 // if they've told us not to create a text node
362 if (! mTextLength)
363 break;
365 if (! aCreateTextNode)
366 break;
368 nsRefPtr<nsXULPrototypeNode> node;
369 rv = mContextStack.GetTopNode(node);
370 if (NS_FAILED(rv)) return rv;
372 bool stripWhitespace = false;
373 if (node->mType == nsXULPrototypeNode::eType_Element) {
374 nsINodeInfo *nodeInfo =
375 static_cast<nsXULPrototypeElement*>(node.get())->mNodeInfo;
377 if (nodeInfo->NamespaceEquals(kNameSpaceID_XUL))
378 stripWhitespace = !nodeInfo->Equals(nsGkAtoms::label) &&
379 !nodeInfo->Equals(nsGkAtoms::description);
380 }
382 // Don't bother if there's nothing but whitespace.
383 if (stripWhitespace && ! IsDataInBuffer(mText, mTextLength))
384 break;
386 // Don't bother if we're not in XUL document body
387 if (mState != eInDocumentElement || mContextStack.Depth() == 0)
388 break;
390 nsXULPrototypeText* text = new nsXULPrototypeText();
391 if (! text)
392 return NS_ERROR_OUT_OF_MEMORY;
394 text->mValue.Assign(mText, mTextLength);
395 if (stripWhitespace)
396 text->mValue.Trim(" \t\n\r");
398 // hook it up
399 nsPrototypeArray* children = nullptr;
400 rv = mContextStack.GetTopChildren(&children);
401 if (NS_FAILED(rv)) return rv;
403 // transfer ownership of 'text' to the children array
404 children->AppendElement(text);
405 } while (0);
407 // Reset our text buffer
408 mTextLength = 0;
409 return NS_OK;
410 }
412 //----------------------------------------------------------------------
414 nsresult
415 XULContentSinkImpl::NormalizeAttributeString(const char16_t *aExpatName,
416 nsAttrName &aName)
417 {
418 int32_t nameSpaceID;
419 nsCOMPtr<nsIAtom> prefix, localName;
420 nsContentUtils::SplitExpatName(aExpatName, getter_AddRefs(prefix),
421 getter_AddRefs(localName), &nameSpaceID);
423 if (nameSpaceID == kNameSpaceID_None) {
424 aName.SetTo(localName);
426 return NS_OK;
427 }
429 nsCOMPtr<nsINodeInfo> ni;
430 ni = mNodeInfoManager->GetNodeInfo(localName, prefix,
431 nameSpaceID,
432 nsIDOMNode::ATTRIBUTE_NODE);
433 aName.SetTo(ni);
435 return NS_OK;
436 }
438 nsresult
439 XULContentSinkImpl::CreateElement(nsINodeInfo *aNodeInfo,
440 nsXULPrototypeElement** aResult)
441 {
442 nsXULPrototypeElement* element = new nsXULPrototypeElement();
443 if (! element)
444 return NS_ERROR_OUT_OF_MEMORY;
446 element->mNodeInfo = aNodeInfo;
448 *aResult = element;
449 return NS_OK;
450 }
452 /**** BEGIN NEW APIs ****/
455 NS_IMETHODIMP
456 XULContentSinkImpl::HandleStartElement(const char16_t *aName,
457 const char16_t **aAtts,
458 uint32_t aAttsCount,
459 int32_t aIndex,
460 uint32_t aLineNumber)
461 {
462 // XXX Hopefully the parser will flag this before we get here. If
463 // we're in the epilog, there should be no new elements
464 NS_PRECONDITION(mState != eInEpilog, "tag in XUL doc epilog");
465 NS_PRECONDITION(aIndex >= -1, "Bogus aIndex");
466 NS_PRECONDITION(aAttsCount % 2 == 0, "incorrect aAttsCount");
467 // Adjust aAttsCount so it's the actual number of attributes
468 aAttsCount /= 2;
470 if (mState == eInEpilog)
471 return NS_ERROR_UNEXPECTED;
473 if (mState != eInScript) {
474 FlushText();
475 }
477 int32_t nameSpaceID;
478 nsCOMPtr<nsIAtom> prefix, localName;
479 nsContentUtils::SplitExpatName(aName, getter_AddRefs(prefix),
480 getter_AddRefs(localName), &nameSpaceID);
482 nsCOMPtr<nsINodeInfo> nodeInfo;
483 nodeInfo = mNodeInfoManager->GetNodeInfo(localName, prefix, nameSpaceID,
484 nsIDOMNode::ELEMENT_NODE);
486 nsresult rv = NS_OK;
487 switch (mState) {
488 case eInProlog:
489 // We're the root document element
490 rv = OpenRoot(aAtts, aAttsCount, nodeInfo);
491 break;
493 case eInDocumentElement:
494 rv = OpenTag(aAtts, aAttsCount, aLineNumber, nodeInfo);
495 break;
497 case eInEpilog:
498 case eInScript:
499 PR_LOG(gContentSinkLog, PR_LOG_WARNING,
500 ("xul: warning: unexpected tags in epilog at line %d",
501 aLineNumber));
502 rv = NS_ERROR_UNEXPECTED; // XXX
503 break;
504 }
506 // Set the ID attribute atom on the node info object for this node
507 if (aIndex != -1 && NS_SUCCEEDED(rv)) {
508 nsCOMPtr<nsIAtom> IDAttr = do_GetAtom(aAtts[aIndex]);
510 if (IDAttr) {
511 nodeInfo->SetIDAttributeAtom(IDAttr);
512 }
513 }
515 return rv;
516 }
518 NS_IMETHODIMP
519 XULContentSinkImpl::HandleEndElement(const char16_t *aName)
520 {
521 // Never EVER return anything but NS_OK or
522 // NS_ERROR_HTMLPARSER_BLOCK from this method. Doing so will blow
523 // the parser's little mind all over the planet.
524 nsresult rv;
526 nsRefPtr<nsXULPrototypeNode> node;
527 rv = mContextStack.GetTopNode(node);
529 if (NS_FAILED(rv)) {
530 return NS_OK;
531 }
533 switch (node->mType) {
534 case nsXULPrototypeNode::eType_Element: {
535 // Flush any text _now_, so that we'll get text nodes created
536 // before popping the stack.
537 FlushText();
539 // Pop the context stack and do prototype hookup.
540 nsPrototypeArray* children = nullptr;
541 rv = mContextStack.GetTopChildren(&children);
542 if (NS_FAILED(rv)) return rv;
544 nsXULPrototypeElement* element =
545 static_cast<nsXULPrototypeElement*>(node.get());
547 int32_t count = children->Length();
548 if (count) {
549 element->mChildren.SetCapacity(count);
551 for (int32_t i = 0; i < count; ++i)
552 element->mChildren.AppendElement(children->ElementAt(i));
554 }
555 }
556 break;
558 case nsXULPrototypeNode::eType_Script: {
559 nsXULPrototypeScript* script =
560 static_cast<nsXULPrototypeScript*>(node.get());
562 // If given a src= attribute, we must ignore script tag content.
563 if (!script->mSrcURI && !script->GetScriptObject()) {
564 nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
566 script->mOutOfLine = false;
567 if (doc)
568 script->Compile(mText, mTextLength, mDocumentURL,
569 script->mLineNo, doc, mPrototype);
570 }
572 FlushText(false);
573 }
574 break;
576 default:
577 NS_ERROR("didn't expect that");
578 break;
579 }
581 rv = mContextStack.Pop(&mState);
582 NS_ASSERTION(NS_SUCCEEDED(rv), "context stack corrupted");
583 if (NS_FAILED(rv)) return rv;
585 if (mContextStack.Depth() == 0) {
586 // The root element should -always- be an element, because
587 // it'll have been created via XULContentSinkImpl::OpenRoot().
588 NS_ASSERTION(node->mType == nsXULPrototypeNode::eType_Element, "root is not an element");
589 if (node->mType != nsXULPrototypeNode::eType_Element)
590 return NS_ERROR_UNEXPECTED;
592 // Now that we're done parsing, set the prototype document's
593 // root element. This transfers ownership of the prototype
594 // element tree to the prototype document.
595 nsXULPrototypeElement* element =
596 static_cast<nsXULPrototypeElement*>(node.get());
598 mPrototype->SetRootElement(element);
599 mState = eInEpilog;
600 }
602 return NS_OK;
603 }
605 NS_IMETHODIMP
606 XULContentSinkImpl::HandleComment(const char16_t *aName)
607 {
608 FlushText();
609 return NS_OK;
610 }
612 NS_IMETHODIMP
613 XULContentSinkImpl::HandleCDataSection(const char16_t *aData, uint32_t aLength)
614 {
615 FlushText();
616 return AddText(aData, aLength);
617 }
619 NS_IMETHODIMP
620 XULContentSinkImpl::HandleDoctypeDecl(const nsAString & aSubset,
621 const nsAString & aName,
622 const nsAString & aSystemId,
623 const nsAString & aPublicId,
624 nsISupports* aCatalogData)
625 {
626 return NS_OK;
627 }
629 NS_IMETHODIMP
630 XULContentSinkImpl::HandleCharacterData(const char16_t *aData,
631 uint32_t aLength)
632 {
633 if (aData && mState != eInProlog && mState != eInEpilog) {
634 return AddText(aData, aLength);
635 }
636 return NS_OK;
637 }
639 NS_IMETHODIMP
640 XULContentSinkImpl::HandleProcessingInstruction(const char16_t *aTarget,
641 const char16_t *aData)
642 {
643 FlushText();
645 const nsDependentString target(aTarget);
646 const nsDependentString data(aData);
648 // Note: the created nsXULPrototypePI has mRefCnt == 1
649 nsRefPtr<nsXULPrototypePI> pi = new nsXULPrototypePI();
650 if (!pi)
651 return NS_ERROR_OUT_OF_MEMORY;
653 pi->mTarget = target;
654 pi->mData = data;
656 if (mState == eInProlog) {
657 // Note: passing in already addrefed pi
658 return mPrototype->AddProcessingInstruction(pi);
659 }
661 nsresult rv;
662 nsPrototypeArray* children = nullptr;
663 rv = mContextStack.GetTopChildren(&children);
664 if (NS_FAILED(rv)) {
665 return rv;
666 }
668 if (!children->AppendElement(pi)) {
669 return NS_ERROR_OUT_OF_MEMORY;
670 }
672 return NS_OK;
673 }
676 NS_IMETHODIMP
677 XULContentSinkImpl::HandleXMLDeclaration(const char16_t *aVersion,
678 const char16_t *aEncoding,
679 int32_t aStandalone)
680 {
681 return NS_OK;
682 }
685 NS_IMETHODIMP
686 XULContentSinkImpl::ReportError(const char16_t* aErrorText,
687 const char16_t* aSourceText,
688 nsIScriptError *aError,
689 bool *_retval)
690 {
691 NS_PRECONDITION(aError && aSourceText && aErrorText, "Check arguments!!!");
693 // The expat driver should report the error.
694 *_retval = true;
696 nsresult rv = NS_OK;
698 // make sure to empty the context stack so that
699 // <parsererror> could become the root element.
700 mContextStack.Clear();
702 mState = eInProlog;
704 // Clear any buffered-up text we have. It's enough to set the length to 0.
705 // The buffer itself is allocated when we're created and deleted in our
706 // destructor, so don't mess with it.
707 mTextLength = 0;
709 nsCOMPtr<nsIXULDocument> doc = do_QueryReferent(mDocument);
710 if (doc && !doc->OnDocumentParserError()) {
711 // The overlay was broken. Don't add a messy element to the master doc.
712 return NS_OK;
713 }
715 const char16_t* noAtts[] = { 0, 0 };
717 NS_NAMED_LITERAL_STRING(errorNs,
718 "http://www.mozilla.org/newlayout/xml/parsererror.xml");
720 nsAutoString parsererror(errorNs);
721 parsererror.Append((char16_t)0xFFFF);
722 parsererror.AppendLiteral("parsererror");
724 rv = HandleStartElement(parsererror.get(), noAtts, 0, -1, 0);
725 NS_ENSURE_SUCCESS(rv,rv);
727 rv = HandleCharacterData(aErrorText, NS_strlen(aErrorText));
728 NS_ENSURE_SUCCESS(rv,rv);
730 nsAutoString sourcetext(errorNs);
731 sourcetext.Append((char16_t)0xFFFF);
732 sourcetext.AppendLiteral("sourcetext");
734 rv = HandleStartElement(sourcetext.get(), noAtts, 0, -1, 0);
735 NS_ENSURE_SUCCESS(rv,rv);
737 rv = HandleCharacterData(aSourceText, NS_strlen(aSourceText));
738 NS_ENSURE_SUCCESS(rv,rv);
740 rv = HandleEndElement(sourcetext.get());
741 NS_ENSURE_SUCCESS(rv,rv);
743 rv = HandleEndElement(parsererror.get());
744 NS_ENSURE_SUCCESS(rv,rv);
746 return rv;
747 }
749 nsresult
750 XULContentSinkImpl::OpenRoot(const char16_t** aAttributes,
751 const uint32_t aAttrLen,
752 nsINodeInfo *aNodeInfo)
753 {
754 NS_ASSERTION(mState == eInProlog, "how'd we get here?");
755 if (mState != eInProlog)
756 return NS_ERROR_UNEXPECTED;
758 nsresult rv;
760 if (aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML) ||
761 aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XUL)) {
762 PR_LOG(gContentSinkLog, PR_LOG_ERROR,
763 ("xul: script tag not allowed as root content element"));
765 return NS_ERROR_UNEXPECTED;
766 }
768 // Create the element
769 nsXULPrototypeElement* element;
770 rv = CreateElement(aNodeInfo, &element);
772 if (NS_FAILED(rv)) {
773 #ifdef PR_LOGGING
774 if (PR_LOG_TEST(gContentSinkLog, PR_LOG_ERROR)) {
775 nsAutoString anodeC;
776 aNodeInfo->GetName(anodeC);
777 PR_LOG(gContentSinkLog, PR_LOG_ERROR,
778 ("xul: unable to create element '%s' at line %d",
779 NS_ConvertUTF16toUTF8(anodeC).get(),
780 -1)); // XXX pass in line number
781 }
782 #endif
784 return rv;
785 }
787 // Push the element onto the context stack, so that child
788 // containers will hook up to us as their parent.
789 rv = mContextStack.Push(element, mState);
790 if (NS_FAILED(rv)) {
791 element->Release();
792 return rv;
793 }
795 // Add the attributes
796 rv = AddAttributes(aAttributes, aAttrLen, element);
797 if (NS_FAILED(rv)) return rv;
799 mState = eInDocumentElement;
800 return NS_OK;
801 }
803 nsresult
804 XULContentSinkImpl::OpenTag(const char16_t** aAttributes,
805 const uint32_t aAttrLen,
806 const uint32_t aLineNumber,
807 nsINodeInfo *aNodeInfo)
808 {
809 nsresult rv;
811 // Create the element
812 nsXULPrototypeElement* element;
813 rv = CreateElement(aNodeInfo, &element);
815 if (NS_FAILED(rv)) {
816 #ifdef PR_LOGGING
817 if (PR_LOG_TEST(gContentSinkLog, PR_LOG_ERROR)) {
818 nsAutoString anodeC;
819 aNodeInfo->GetName(anodeC);
820 PR_LOG(gContentSinkLog, PR_LOG_ERROR,
821 ("xul: unable to create element '%s' at line %d",
822 NS_ConvertUTF16toUTF8(anodeC).get(),
823 aLineNumber));
824 }
825 #endif
827 return rv;
828 }
830 // Link this element to its parent.
831 nsPrototypeArray* children = nullptr;
832 rv = mContextStack.GetTopChildren(&children);
833 if (NS_FAILED(rv)) {
834 delete element;
835 return rv;
836 }
838 // Add the attributes
839 rv = AddAttributes(aAttributes, aAttrLen, element);
840 if (NS_FAILED(rv)) return rv;
842 children->AppendElement(element);
844 if (aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML) ||
845 aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XUL)) {
846 // Do scripty things now
847 rv = OpenScript(aAttributes, aLineNumber);
848 NS_ENSURE_SUCCESS(rv, rv);
850 NS_ASSERTION(mState == eInScript || mState == eInDocumentElement,
851 "Unexpected state");
852 if (mState == eInScript) {
853 // OpenScript has pushed the nsPrototypeScriptElement onto the
854 // stack, so we're done.
855 return NS_OK;
856 }
857 }
859 // Push the element onto the context stack, so that child
860 // containers will hook up to us as their parent.
861 rv = mContextStack.Push(element, mState);
862 if (NS_FAILED(rv)) return rv;
864 mState = eInDocumentElement;
865 return NS_OK;
866 }
868 nsresult
869 XULContentSinkImpl::OpenScript(const char16_t** aAttributes,
870 const uint32_t aLineNumber)
871 {
872 uint32_t langID = nsIProgrammingLanguage::JAVASCRIPT;
873 uint32_t version = JSVERSION_LATEST;
874 nsresult rv;
876 // Look for SRC attribute and look for a LANGUAGE attribute
877 nsAutoString src;
878 while (*aAttributes) {
879 const nsDependentString key(aAttributes[0]);
880 if (key.EqualsLiteral("src")) {
881 src.Assign(aAttributes[1]);
882 }
883 else if (key.EqualsLiteral("type")) {
884 nsDependentString str(aAttributes[1]);
885 nsContentTypeParser parser(str);
886 nsAutoString mimeType;
887 rv = parser.GetType(mimeType);
888 if (NS_FAILED(rv)) {
889 if (rv == NS_ERROR_INVALID_ARG) {
890 // Might as well bail out now instead of setting langID to
891 // nsIProgrammingLanguage::UNKNOWN and bailing out later.
892 return NS_OK;
893 }
894 // We do want the warning here
895 NS_ENSURE_SUCCESS(rv, rv);
896 }
898 if (nsContentUtils::IsJavascriptMIMEType(mimeType)) {
899 langID = nsIProgrammingLanguage::JAVASCRIPT;
900 version = JSVERSION_LATEST;
901 } else {
902 langID = nsIProgrammingLanguage::UNKNOWN;
903 }
905 if (langID != nsIProgrammingLanguage::UNKNOWN) {
906 // Get the version string, and ensure the language supports it.
907 nsAutoString versionName;
908 rv = parser.GetParameter("version", versionName);
910 if (NS_SUCCEEDED(rv)) {
911 version = nsContentUtils::ParseJavascriptVersion(versionName);
912 } else if (rv != NS_ERROR_INVALID_ARG) {
913 return rv;
914 }
915 }
916 }
917 else if (key.EqualsLiteral("language")) {
918 // Language is deprecated, and the impl in nsScriptLoader ignores the
919 // various version strings anyway. So we make no attempt to support
920 // languages other than JS for language=
921 nsAutoString lang(aAttributes[1]);
922 if (nsContentUtils::IsJavaScriptLanguage(lang)) {
923 version = JSVERSION_DEFAULT;
924 langID = nsIProgrammingLanguage::JAVASCRIPT;
925 }
926 }
927 aAttributes += 2;
928 }
930 // Not all script languages have a "sandbox" concept. At time of
931 // writing, Python is the only other language, and it does not.
932 // For such languages, neither any inline script nor remote script are
933 // safe to execute from untrusted sources.
934 // So for such languages, we only allow script when the document
935 // itself is from chrome. We then don't bother to check the
936 // "src=" tag - we trust chrome to do the right thing.
937 // (See also similar code in nsScriptLoader.cpp)
938 nsCOMPtr<nsIDocument> doc(do_QueryReferent(mDocument));
939 if (langID != nsIProgrammingLanguage::UNKNOWN &&
940 langID != nsIProgrammingLanguage::JAVASCRIPT &&
941 doc && !nsContentUtils::IsChromeDoc(doc)) {
942 langID = nsIProgrammingLanguage::UNKNOWN;
943 NS_WARNING("Non JS language called from non chrome - ignored");
944 }
946 // Don't process scripts that aren't known
947 if (langID != nsIProgrammingLanguage::UNKNOWN) {
948 nsCOMPtr<nsIScriptGlobalObject> globalObject;
949 if (doc)
950 globalObject = do_QueryInterface(doc->GetWindow());
951 nsRefPtr<nsXULPrototypeScript> script =
952 new nsXULPrototypeScript(aLineNumber, version);
953 if (! script)
954 return NS_ERROR_OUT_OF_MEMORY;
956 // If there is a SRC attribute...
957 if (! src.IsEmpty()) {
958 // Use the SRC attribute value to load the URL
959 rv = NS_NewURI(getter_AddRefs(script->mSrcURI), src, nullptr, mDocumentURL);
961 // Check if this document is allowed to load a script from this source
962 // NOTE: if we ever allow scripts added via the DOM to run, we need to
963 // add a CheckLoadURI call for that as well.
964 if (NS_SUCCEEDED(rv)) {
965 if (!mSecMan)
966 mSecMan = do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
967 if (NS_SUCCEEDED(rv)) {
968 nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument, &rv);
970 if (NS_SUCCEEDED(rv)) {
971 rv = mSecMan->
972 CheckLoadURIWithPrincipal(doc->NodePrincipal(),
973 script->mSrcURI,
974 nsIScriptSecurityManager::ALLOW_CHROME);
975 }
976 }
977 }
979 if (NS_FAILED(rv)) {
980 return rv;
981 }
983 // Attempt to deserialize an out-of-line script from the FastLoad
984 // file right away. Otherwise we'll end up reloading the script and
985 // corrupting the FastLoad file trying to serialize it, in the case
986 // where it's already there.
987 script->DeserializeOutOfLine(nullptr, mPrototype);
988 }
990 nsPrototypeArray* children = nullptr;
991 rv = mContextStack.GetTopChildren(&children);
992 if (NS_FAILED(rv)) {
993 return rv;
994 }
996 children->AppendElement(script);
998 mConstrainSize = false;
1000 mContextStack.Push(script, mState);
1001 mState = eInScript;
1002 }
1004 return NS_OK;
1005 }
1007 nsresult
1008 XULContentSinkImpl::AddAttributes(const char16_t** aAttributes,
1009 const uint32_t aAttrLen,
1010 nsXULPrototypeElement* aElement)
1011 {
1012 // Add tag attributes to the element
1013 nsresult rv;
1015 // Create storage for the attributes
1016 nsXULPrototypeAttribute* attrs = nullptr;
1017 if (aAttrLen > 0) {
1018 attrs = new nsXULPrototypeAttribute[aAttrLen];
1019 if (! attrs)
1020 return NS_ERROR_OUT_OF_MEMORY;
1021 }
1023 aElement->mAttributes = attrs;
1024 aElement->mNumAttributes = aAttrLen;
1026 // Copy the attributes into the prototype
1027 uint32_t i;
1028 for (i = 0; i < aAttrLen; ++i) {
1029 rv = NormalizeAttributeString(aAttributes[i * 2], attrs[i].mName);
1030 NS_ENSURE_SUCCESS(rv, rv);
1032 rv = aElement->SetAttrAt(i, nsDependentString(aAttributes[i * 2 + 1]),
1033 mDocumentURL);
1034 NS_ENSURE_SUCCESS(rv, rv);
1036 #ifdef PR_LOGGING
1037 if (PR_LOG_TEST(gContentSinkLog, PR_LOG_DEBUG)) {
1038 nsAutoString extraWhiteSpace;
1039 int32_t cnt = mContextStack.Depth();
1040 while (--cnt >= 0)
1041 extraWhiteSpace.AppendLiteral(" ");
1042 nsAutoString qnameC,valueC;
1043 qnameC.Assign(aAttributes[0]);
1044 valueC.Assign(aAttributes[1]);
1045 PR_LOG(gContentSinkLog, PR_LOG_DEBUG,
1046 ("xul: %.5d. %s %s=%s",
1047 -1, // XXX pass in line number
1048 NS_ConvertUTF16toUTF8(extraWhiteSpace).get(),
1049 NS_ConvertUTF16toUTF8(qnameC).get(),
1050 NS_ConvertUTF16toUTF8(valueC).get()));
1051 }
1052 #endif
1053 }
1055 return NS_OK;
1056 }
1058 nsresult
1059 XULContentSinkImpl::AddText(const char16_t* aText,
1060 int32_t aLength)
1061 {
1062 // Create buffer when we first need it
1063 if (0 == mTextSize) {
1064 mText = (char16_t *) moz_malloc(sizeof(char16_t) * 4096);
1065 if (nullptr == mText) {
1066 return NS_ERROR_OUT_OF_MEMORY;
1067 }
1068 mTextSize = 4096;
1069 }
1071 // Copy data from string into our buffer; flush buffer when it fills up
1072 int32_t offset = 0;
1073 while (0 != aLength) {
1074 int32_t amount = mTextSize - mTextLength;
1075 if (amount > aLength) {
1076 amount = aLength;
1077 }
1078 if (0 == amount) {
1079 if (mConstrainSize) {
1080 nsresult rv = FlushText();
1081 if (NS_OK != rv) {
1082 return rv;
1083 }
1084 }
1085 else {
1086 mTextSize += aLength;
1087 mText = (char16_t *) moz_realloc(mText, sizeof(char16_t) * mTextSize);
1088 if (nullptr == mText) {
1089 return NS_ERROR_OUT_OF_MEMORY;
1090 }
1091 }
1092 }
1093 memcpy(&mText[mTextLength],aText + offset, sizeof(char16_t) * amount);
1095 mTextLength += amount;
1096 offset += amount;
1097 aLength -= amount;
1098 }
1100 return NS_OK;
1101 }