Line data Source code
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/. */
6 :
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 : */
14 :
15 : #include "nsXULContentSink.h"
16 :
17 : #include "jsfriendapi.h"
18 :
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 "mozilla/dom/NodeInfo.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 "mozilla/Logging.h"
45 : #include "nsCRT.h"
46 :
47 : #include "nsXULPrototypeDocument.h" // XXXbe temporary
48 : #include "mozilla/css/Loader.h"
49 :
50 : #include "nsUnicharUtils.h"
51 : #include "nsGkAtoms.h"
52 : #include "nsContentUtils.h"
53 : #include "nsAttrName.h"
54 : #include "nsXMLContentSink.h"
55 : #include "nsIConsoleService.h"
56 : #include "nsIScriptError.h"
57 : #include "nsContentTypeParser.h"
58 :
59 : static mozilla::LazyLogModule gContentSinkLog("nsXULContentSink");;
60 :
61 : //----------------------------------------------------------------------
62 :
63 0 : XULContentSinkImpl::ContextStack::ContextStack()
64 0 : : mTop(nullptr), mDepth(0)
65 : {
66 0 : }
67 :
68 0 : XULContentSinkImpl::ContextStack::~ContextStack()
69 : {
70 0 : while (mTop) {
71 0 : Entry* doomed = mTop;
72 0 : mTop = mTop->mNext;
73 0 : delete doomed;
74 : }
75 0 : }
76 :
77 : nsresult
78 0 : XULContentSinkImpl::ContextStack::Push(nsXULPrototypeNode* aNode, State aState)
79 : {
80 0 : Entry* entry = new Entry;
81 0 : entry->mNode = aNode;
82 0 : entry->mState = aState;
83 0 : entry->mNext = mTop;
84 :
85 0 : mTop = entry;
86 :
87 0 : ++mDepth;
88 0 : return NS_OK;
89 : }
90 :
91 : nsresult
92 0 : XULContentSinkImpl::ContextStack::Pop(State* aState)
93 : {
94 0 : if (mDepth == 0)
95 0 : return NS_ERROR_UNEXPECTED;
96 :
97 0 : Entry* entry = mTop;
98 0 : mTop = mTop->mNext;
99 0 : --mDepth;
100 :
101 0 : *aState = entry->mState;
102 0 : delete entry;
103 :
104 0 : return NS_OK;
105 : }
106 :
107 :
108 : nsresult
109 0 : XULContentSinkImpl::ContextStack::GetTopNode(RefPtr<nsXULPrototypeNode>& aNode)
110 : {
111 0 : if (mDepth == 0)
112 0 : return NS_ERROR_UNEXPECTED;
113 :
114 0 : aNode = mTop->mNode;
115 0 : return NS_OK;
116 : }
117 :
118 :
119 : nsresult
120 0 : XULContentSinkImpl::ContextStack::GetTopChildren(nsPrototypeArray** aChildren)
121 : {
122 0 : if (mDepth == 0)
123 0 : return NS_ERROR_UNEXPECTED;
124 :
125 0 : *aChildren = &(mTop->mChildren);
126 0 : return NS_OK;
127 : }
128 :
129 : void
130 0 : XULContentSinkImpl::ContextStack::Clear()
131 : {
132 0 : Entry *cur = mTop;
133 0 : while (cur) {
134 : // Release the root element (and its descendants).
135 0 : Entry *next = cur->mNext;
136 0 : delete cur;
137 0 : cur = next;
138 : }
139 :
140 0 : mTop = nullptr;
141 0 : mDepth = 0;
142 0 : }
143 :
144 : void
145 0 : XULContentSinkImpl::ContextStack::Traverse(nsCycleCollectionTraversalCallback& aCb)
146 : {
147 0 : nsCycleCollectionTraversalCallback& cb = aCb;
148 0 : for (ContextStack::Entry* tmp = mTop; tmp; tmp = tmp->mNext) {
149 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNode)
150 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChildren)
151 : }
152 0 : }
153 :
154 : //----------------------------------------------------------------------
155 :
156 :
157 0 : XULContentSinkImpl::XULContentSinkImpl()
158 : : mText(nullptr),
159 : mTextLength(0),
160 : mTextSize(0),
161 : mConstrainSize(true),
162 0 : mState(eInProlog)
163 : {
164 0 : }
165 :
166 :
167 0 : XULContentSinkImpl::~XULContentSinkImpl()
168 : {
169 : // The context stack _should_ be empty, unless something has gone wrong.
170 0 : NS_ASSERTION(mContextStack.Depth() == 0, "Context stack not empty?");
171 0 : mContextStack.Clear();
172 :
173 0 : free(mText);
174 0 : }
175 :
176 : //----------------------------------------------------------------------
177 : // nsISupports interface
178 :
179 : NS_IMPL_CYCLE_COLLECTION_CLASS(XULContentSinkImpl)
180 :
181 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(XULContentSinkImpl)
182 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mNodeInfoManager)
183 0 : tmp->mContextStack.Clear();
184 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mPrototype)
185 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mParser)
186 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
187 :
188 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(XULContentSinkImpl)
189 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNodeInfoManager)
190 0 : tmp->mContextStack.Traverse(cb);
191 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrototype)
192 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParser)
193 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
194 :
195 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(XULContentSinkImpl)
196 0 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXMLContentSink)
197 0 : NS_INTERFACE_MAP_ENTRY(nsIXMLContentSink)
198 0 : NS_INTERFACE_MAP_ENTRY(nsIExpatSink)
199 0 : NS_INTERFACE_MAP_ENTRY(nsIContentSink)
200 0 : NS_INTERFACE_MAP_END
201 :
202 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(XULContentSinkImpl)
203 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(XULContentSinkImpl)
204 :
205 : //----------------------------------------------------------------------
206 : // nsIContentSink interface
207 :
208 : NS_IMETHODIMP
209 0 : XULContentSinkImpl::WillBuildModel(nsDTDMode aDTDMode)
210 : {
211 : #if FIXME
212 : if (! mParentContentSink) {
213 : // If we're _not_ an overlay, then notify the document that
214 : // the load is beginning.
215 : mDocument->BeginLoad();
216 : }
217 : #endif
218 :
219 0 : return NS_OK;
220 : }
221 :
222 : NS_IMETHODIMP
223 0 : XULContentSinkImpl::DidBuildModel(bool aTerminated)
224 : {
225 0 : nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
226 0 : if (doc) {
227 0 : doc->EndLoad();
228 0 : mDocument = nullptr;
229 : }
230 :
231 : // Drop our reference to the parser to get rid of a circular
232 : // reference.
233 0 : mParser = nullptr;
234 0 : return NS_OK;
235 : }
236 :
237 : NS_IMETHODIMP
238 0 : XULContentSinkImpl::WillInterrupt(void)
239 : {
240 : // XXX Notify the docshell, if necessary
241 0 : return NS_OK;
242 : }
243 :
244 : NS_IMETHODIMP
245 0 : XULContentSinkImpl::WillResume(void)
246 : {
247 : // XXX Notify the docshell, if necessary
248 0 : return NS_OK;
249 : }
250 :
251 : NS_IMETHODIMP
252 0 : XULContentSinkImpl::SetParser(nsParserBase* aParser)
253 : {
254 0 : mParser = aParser;
255 0 : return NS_OK;
256 : }
257 :
258 : void
259 0 : XULContentSinkImpl::SetDocumentCharset(NotNull<const Encoding*> aEncoding)
260 : {
261 0 : nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
262 0 : if (doc) {
263 0 : doc->SetDocumentCharacterSet(aEncoding);
264 : }
265 0 : }
266 :
267 : nsISupports *
268 0 : XULContentSinkImpl::GetTarget()
269 : {
270 0 : nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
271 0 : return doc;
272 : }
273 :
274 : //----------------------------------------------------------------------
275 :
276 : nsresult
277 0 : XULContentSinkImpl::Init(nsIDocument* aDocument,
278 : nsXULPrototypeDocument* aPrototype)
279 : {
280 0 : NS_PRECONDITION(aDocument != nullptr, "null ptr");
281 0 : if (! aDocument)
282 0 : return NS_ERROR_NULL_POINTER;
283 :
284 : nsresult rv;
285 :
286 0 : mDocument = do_GetWeakReference(aDocument);
287 0 : mPrototype = aPrototype;
288 :
289 0 : mDocumentURL = mPrototype->GetURI();
290 :
291 : // XXX this presumes HTTP header info is already set in document
292 : // XXX if it isn't we need to set it here...
293 : // XXXbz not like GetHeaderData on the proto doc _does_ anything....
294 0 : nsAutoString preferredStyle;
295 0 : rv = mPrototype->GetHeaderData(nsGkAtoms::headerDefaultStyle,
296 0 : preferredStyle);
297 0 : if (NS_FAILED(rv)) return rv;
298 :
299 0 : if (!preferredStyle.IsEmpty()) {
300 : aDocument->SetHeaderData(nsGkAtoms::headerDefaultStyle,
301 0 : preferredStyle);
302 : }
303 :
304 : // Set the right preferred style on the document's CSSLoader.
305 0 : aDocument->CSSLoader()->SetPreferredSheet(preferredStyle);
306 :
307 0 : mNodeInfoManager = aPrototype->GetNodeInfoManager();
308 0 : if (! mNodeInfoManager)
309 0 : return NS_ERROR_UNEXPECTED;
310 :
311 0 : mState = eInProlog;
312 0 : return NS_OK;
313 : }
314 :
315 :
316 : //----------------------------------------------------------------------
317 : //
318 : // Text buffering
319 : //
320 :
321 : bool
322 0 : XULContentSinkImpl::IsDataInBuffer(char16_t* buffer, int32_t length)
323 : {
324 0 : for (int32_t i = 0; i < length; ++i) {
325 0 : if (buffer[i] == ' ' ||
326 0 : buffer[i] == '\t' ||
327 0 : buffer[i] == '\n' ||
328 0 : buffer[i] == '\r')
329 0 : continue;
330 :
331 0 : return true;
332 : }
333 0 : return false;
334 : }
335 :
336 :
337 : nsresult
338 0 : XULContentSinkImpl::FlushText(bool aCreateTextNode)
339 : {
340 : nsresult rv;
341 :
342 : do {
343 : // Don't do anything if there's no text to create a node from, or
344 : // if they've told us not to create a text node
345 0 : if (! mTextLength)
346 0 : break;
347 :
348 0 : if (! aCreateTextNode)
349 0 : break;
350 :
351 0 : RefPtr<nsXULPrototypeNode> node;
352 0 : rv = mContextStack.GetTopNode(node);
353 0 : if (NS_FAILED(rv)) return rv;
354 :
355 0 : bool stripWhitespace = false;
356 0 : if (node->mType == nsXULPrototypeNode::eType_Element) {
357 : mozilla::dom::NodeInfo *nodeInfo =
358 0 : static_cast<nsXULPrototypeElement*>(node.get())->mNodeInfo;
359 :
360 0 : if (nodeInfo->NamespaceEquals(kNameSpaceID_XUL))
361 0 : stripWhitespace = !nodeInfo->Equals(nsGkAtoms::label) &&
362 0 : !nodeInfo->Equals(nsGkAtoms::description);
363 : }
364 :
365 : // Don't bother if there's nothing but whitespace.
366 0 : if (stripWhitespace && ! IsDataInBuffer(mText, mTextLength))
367 0 : break;
368 :
369 : // Don't bother if we're not in XUL document body
370 0 : if (mState != eInDocumentElement || mContextStack.Depth() == 0)
371 0 : break;
372 :
373 0 : nsXULPrototypeText* text = new nsXULPrototypeText();
374 0 : text->mValue.Assign(mText, mTextLength);
375 0 : if (stripWhitespace)
376 0 : text->mValue.Trim(" \t\n\r");
377 :
378 : // hook it up
379 0 : nsPrototypeArray* children = nullptr;
380 0 : rv = mContextStack.GetTopChildren(&children);
381 0 : if (NS_FAILED(rv)) return rv;
382 :
383 : // transfer ownership of 'text' to the children array
384 0 : children->AppendElement(text);
385 : } while (0);
386 :
387 : // Reset our text buffer
388 0 : mTextLength = 0;
389 0 : return NS_OK;
390 : }
391 :
392 : //----------------------------------------------------------------------
393 :
394 : nsresult
395 0 : XULContentSinkImpl::NormalizeAttributeString(const char16_t *aExpatName,
396 : nsAttrName &aName)
397 : {
398 : int32_t nameSpaceID;
399 0 : nsCOMPtr<nsIAtom> prefix, localName;
400 0 : nsContentUtils::SplitExpatName(aExpatName, getter_AddRefs(prefix),
401 0 : getter_AddRefs(localName), &nameSpaceID);
402 :
403 0 : if (nameSpaceID == kNameSpaceID_None) {
404 0 : aName.SetTo(localName);
405 :
406 0 : return NS_OK;
407 : }
408 :
409 0 : RefPtr<mozilla::dom::NodeInfo> ni;
410 0 : ni = mNodeInfoManager->GetNodeInfo(localName, prefix,
411 : nameSpaceID,
412 0 : nsIDOMNode::ATTRIBUTE_NODE);
413 0 : aName.SetTo(ni);
414 :
415 0 : return NS_OK;
416 : }
417 :
418 : nsresult
419 0 : XULContentSinkImpl::CreateElement(mozilla::dom::NodeInfo *aNodeInfo,
420 : nsXULPrototypeElement** aResult)
421 : {
422 0 : nsXULPrototypeElement* element = new nsXULPrototypeElement();
423 0 : element->mNodeInfo = aNodeInfo;
424 :
425 0 : *aResult = element;
426 0 : return NS_OK;
427 : }
428 :
429 : /**** BEGIN NEW APIs ****/
430 :
431 :
432 : NS_IMETHODIMP
433 0 : XULContentSinkImpl::HandleStartElement(const char16_t *aName,
434 : const char16_t **aAtts,
435 : uint32_t aAttsCount,
436 : uint32_t aLineNumber)
437 : {
438 : // XXX Hopefully the parser will flag this before we get here. If
439 : // we're in the epilog, there should be no new elements
440 0 : NS_PRECONDITION(mState != eInEpilog, "tag in XUL doc epilog");
441 0 : NS_PRECONDITION(aAttsCount % 2 == 0, "incorrect aAttsCount");
442 : // Adjust aAttsCount so it's the actual number of attributes
443 0 : aAttsCount /= 2;
444 :
445 0 : if (mState == eInEpilog)
446 0 : return NS_ERROR_UNEXPECTED;
447 :
448 0 : if (mState != eInScript) {
449 0 : FlushText();
450 : }
451 :
452 : int32_t nameSpaceID;
453 0 : nsCOMPtr<nsIAtom> prefix, localName;
454 0 : nsContentUtils::SplitExpatName(aName, getter_AddRefs(prefix),
455 0 : getter_AddRefs(localName), &nameSpaceID);
456 :
457 0 : RefPtr<mozilla::dom::NodeInfo> nodeInfo;
458 0 : nodeInfo = mNodeInfoManager->GetNodeInfo(localName, prefix, nameSpaceID,
459 0 : nsIDOMNode::ELEMENT_NODE);
460 :
461 0 : nsresult rv = NS_OK;
462 0 : switch (mState) {
463 : case eInProlog:
464 : // We're the root document element
465 0 : rv = OpenRoot(aAtts, aAttsCount, nodeInfo);
466 0 : break;
467 :
468 : case eInDocumentElement:
469 0 : rv = OpenTag(aAtts, aAttsCount, aLineNumber, nodeInfo);
470 0 : break;
471 :
472 : case eInEpilog:
473 : case eInScript:
474 0 : MOZ_LOG(gContentSinkLog, LogLevel::Warning,
475 : ("xul: warning: unexpected tags in epilog at line %d",
476 : aLineNumber));
477 0 : rv = NS_ERROR_UNEXPECTED; // XXX
478 0 : break;
479 : }
480 :
481 0 : return rv;
482 : }
483 :
484 : NS_IMETHODIMP
485 0 : XULContentSinkImpl::HandleEndElement(const char16_t *aName)
486 : {
487 : // Never EVER return anything but NS_OK or
488 : // NS_ERROR_HTMLPARSER_BLOCK from this method. Doing so will blow
489 : // the parser's little mind all over the planet.
490 : nsresult rv;
491 :
492 0 : RefPtr<nsXULPrototypeNode> node;
493 0 : rv = mContextStack.GetTopNode(node);
494 :
495 0 : if (NS_FAILED(rv)) {
496 0 : return NS_OK;
497 : }
498 :
499 0 : switch (node->mType) {
500 : case nsXULPrototypeNode::eType_Element: {
501 : // Flush any text _now_, so that we'll get text nodes created
502 : // before popping the stack.
503 0 : FlushText();
504 :
505 : // Pop the context stack and do prototype hookup.
506 0 : nsPrototypeArray* children = nullptr;
507 0 : rv = mContextStack.GetTopChildren(&children);
508 0 : if (NS_FAILED(rv)) return rv;
509 :
510 : nsXULPrototypeElement* element =
511 0 : static_cast<nsXULPrototypeElement*>(node.get());
512 :
513 0 : int32_t count = children->Length();
514 0 : if (count) {
515 0 : element->mChildren.SetCapacity(count);
516 :
517 0 : for (int32_t i = 0; i < count; ++i)
518 0 : element->mChildren.AppendElement(children->ElementAt(i));
519 :
520 : }
521 : }
522 0 : break;
523 :
524 : case nsXULPrototypeNode::eType_Script: {
525 : nsXULPrototypeScript* script =
526 0 : static_cast<nsXULPrototypeScript*>(node.get());
527 :
528 : // If given a src= attribute, we must ignore script tag content.
529 0 : if (!script->mSrcURI && !script->HasScriptObject()) {
530 0 : nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
531 :
532 0 : script->mOutOfLine = false;
533 0 : if (doc)
534 0 : script->Compile(mText, mTextLength, mDocumentURL,
535 0 : script->mLineNo, doc);
536 : }
537 :
538 0 : FlushText(false);
539 : }
540 0 : break;
541 :
542 : default:
543 0 : NS_ERROR("didn't expect that");
544 0 : break;
545 : }
546 :
547 0 : rv = mContextStack.Pop(&mState);
548 0 : NS_ASSERTION(NS_SUCCEEDED(rv), "context stack corrupted");
549 0 : if (NS_FAILED(rv)) return rv;
550 :
551 0 : if (mContextStack.Depth() == 0) {
552 : // The root element should -always- be an element, because
553 : // it'll have been created via XULContentSinkImpl::OpenRoot().
554 0 : NS_ASSERTION(node->mType == nsXULPrototypeNode::eType_Element, "root is not an element");
555 0 : if (node->mType != nsXULPrototypeNode::eType_Element)
556 0 : return NS_ERROR_UNEXPECTED;
557 :
558 : // Now that we're done parsing, set the prototype document's
559 : // root element. This transfers ownership of the prototype
560 : // element tree to the prototype document.
561 : nsXULPrototypeElement* element =
562 0 : static_cast<nsXULPrototypeElement*>(node.get());
563 :
564 0 : mPrototype->SetRootElement(element);
565 0 : mState = eInEpilog;
566 : }
567 :
568 0 : return NS_OK;
569 : }
570 :
571 : NS_IMETHODIMP
572 0 : XULContentSinkImpl::HandleComment(const char16_t *aName)
573 : {
574 0 : FlushText();
575 0 : return NS_OK;
576 : }
577 :
578 : NS_IMETHODIMP
579 0 : XULContentSinkImpl::HandleCDataSection(const char16_t *aData, uint32_t aLength)
580 : {
581 0 : FlushText();
582 0 : return AddText(aData, aLength);
583 : }
584 :
585 : NS_IMETHODIMP
586 0 : XULContentSinkImpl::HandleDoctypeDecl(const nsAString & aSubset,
587 : const nsAString & aName,
588 : const nsAString & aSystemId,
589 : const nsAString & aPublicId,
590 : nsISupports* aCatalogData)
591 : {
592 0 : return NS_OK;
593 : }
594 :
595 : NS_IMETHODIMP
596 0 : XULContentSinkImpl::HandleCharacterData(const char16_t *aData,
597 : uint32_t aLength)
598 : {
599 0 : if (aData && mState != eInProlog && mState != eInEpilog) {
600 0 : return AddText(aData, aLength);
601 : }
602 0 : return NS_OK;
603 : }
604 :
605 : NS_IMETHODIMP
606 0 : XULContentSinkImpl::HandleProcessingInstruction(const char16_t *aTarget,
607 : const char16_t *aData)
608 : {
609 0 : FlushText();
610 :
611 0 : const nsDependentString target(aTarget);
612 0 : const nsDependentString data(aData);
613 :
614 : // Note: the created nsXULPrototypePI has mRefCnt == 1
615 0 : RefPtr<nsXULPrototypePI> pi = new nsXULPrototypePI();
616 0 : pi->mTarget = target;
617 0 : pi->mData = data;
618 :
619 0 : if (mState == eInProlog) {
620 : // Note: passing in already addrefed pi
621 0 : return mPrototype->AddProcessingInstruction(pi);
622 : }
623 :
624 : nsresult rv;
625 0 : nsPrototypeArray* children = nullptr;
626 0 : rv = mContextStack.GetTopChildren(&children);
627 0 : if (NS_FAILED(rv)) {
628 0 : return rv;
629 : }
630 :
631 0 : if (!children->AppendElement(pi)) {
632 0 : return NS_ERROR_OUT_OF_MEMORY;
633 : }
634 :
635 0 : return NS_OK;
636 : }
637 :
638 :
639 : NS_IMETHODIMP
640 0 : XULContentSinkImpl::HandleXMLDeclaration(const char16_t *aVersion,
641 : const char16_t *aEncoding,
642 : int32_t aStandalone)
643 : {
644 0 : return NS_OK;
645 : }
646 :
647 :
648 : NS_IMETHODIMP
649 0 : XULContentSinkImpl::ReportError(const char16_t* aErrorText,
650 : const char16_t* aSourceText,
651 : nsIScriptError *aError,
652 : bool *_retval)
653 : {
654 0 : NS_PRECONDITION(aError && aSourceText && aErrorText, "Check arguments!!!");
655 :
656 : // The expat driver should report the error.
657 0 : *_retval = true;
658 :
659 0 : nsresult rv = NS_OK;
660 :
661 : // make sure to empty the context stack so that
662 : // <parsererror> could become the root element.
663 0 : mContextStack.Clear();
664 :
665 0 : mState = eInProlog;
666 :
667 : // Clear any buffered-up text we have. It's enough to set the length to 0.
668 : // The buffer itself is allocated when we're created and deleted in our
669 : // destructor, so don't mess with it.
670 0 : mTextLength = 0;
671 :
672 : // return leaving the document empty if we're asked to not add a <parsererror> root node
673 0 : nsCOMPtr<nsIDocument> idoc = do_QueryReferent(mDocument);
674 0 : if (idoc && idoc->SuppressParserErrorElement()) {
675 0 : return NS_OK;
676 : };
677 :
678 0 : nsCOMPtr<nsIXULDocument> doc = do_QueryReferent(mDocument);
679 0 : if (doc && !doc->OnDocumentParserError()) {
680 : // The overlay was broken. Don't add a messy element to the master doc.
681 0 : return NS_OK;
682 : }
683 :
684 0 : const char16_t* noAtts[] = { 0, 0 };
685 :
686 0 : NS_NAMED_LITERAL_STRING(errorNs,
687 : "http://www.mozilla.org/newlayout/xml/parsererror.xml");
688 :
689 0 : nsAutoString parsererror(errorNs);
690 0 : parsererror.Append((char16_t)0xFFFF);
691 0 : parsererror.AppendLiteral("parsererror");
692 :
693 0 : rv = HandleStartElement(parsererror.get(), noAtts, 0, 0);
694 0 : NS_ENSURE_SUCCESS(rv,rv);
695 :
696 0 : rv = HandleCharacterData(aErrorText, NS_strlen(aErrorText));
697 0 : NS_ENSURE_SUCCESS(rv,rv);
698 :
699 0 : nsAutoString sourcetext(errorNs);
700 0 : sourcetext.Append((char16_t)0xFFFF);
701 0 : sourcetext.AppendLiteral("sourcetext");
702 :
703 0 : rv = HandleStartElement(sourcetext.get(), noAtts, 0, 0);
704 0 : NS_ENSURE_SUCCESS(rv,rv);
705 :
706 0 : rv = HandleCharacterData(aSourceText, NS_strlen(aSourceText));
707 0 : NS_ENSURE_SUCCESS(rv,rv);
708 :
709 0 : rv = HandleEndElement(sourcetext.get());
710 0 : NS_ENSURE_SUCCESS(rv,rv);
711 :
712 0 : rv = HandleEndElement(parsererror.get());
713 0 : NS_ENSURE_SUCCESS(rv,rv);
714 :
715 0 : return rv;
716 : }
717 :
718 : nsresult
719 0 : XULContentSinkImpl::OpenRoot(const char16_t** aAttributes,
720 : const uint32_t aAttrLen,
721 : mozilla::dom::NodeInfo *aNodeInfo)
722 : {
723 0 : NS_ASSERTION(mState == eInProlog, "how'd we get here?");
724 0 : if (mState != eInProlog)
725 0 : return NS_ERROR_UNEXPECTED;
726 :
727 : nsresult rv;
728 :
729 0 : if (aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML) ||
730 0 : aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XUL)) {
731 0 : MOZ_LOG(gContentSinkLog, LogLevel::Error,
732 : ("xul: script tag not allowed as root content element"));
733 :
734 0 : return NS_ERROR_UNEXPECTED;
735 : }
736 :
737 : // Create the element
738 : nsXULPrototypeElement* element;
739 0 : rv = CreateElement(aNodeInfo, &element);
740 :
741 0 : if (NS_FAILED(rv)) {
742 0 : if (MOZ_LOG_TEST(gContentSinkLog, LogLevel::Error)) {
743 0 : nsAutoString anodeC;
744 0 : aNodeInfo->GetName(anodeC);
745 0 : MOZ_LOG(gContentSinkLog, LogLevel::Error,
746 : ("xul: unable to create element '%s' at line %d",
747 : NS_ConvertUTF16toUTF8(anodeC).get(),
748 : -1)); // XXX pass in line number
749 : }
750 :
751 0 : return rv;
752 : }
753 :
754 : // Push the element onto the context stack, so that child
755 : // containers will hook up to us as their parent.
756 0 : rv = mContextStack.Push(element, mState);
757 0 : if (NS_FAILED(rv)) {
758 0 : element->Release();
759 0 : return rv;
760 : }
761 :
762 : // Add the attributes
763 0 : rv = AddAttributes(aAttributes, aAttrLen, element);
764 0 : if (NS_FAILED(rv)) return rv;
765 :
766 0 : mState = eInDocumentElement;
767 0 : return NS_OK;
768 : }
769 :
770 : nsresult
771 0 : XULContentSinkImpl::OpenTag(const char16_t** aAttributes,
772 : const uint32_t aAttrLen,
773 : const uint32_t aLineNumber,
774 : mozilla::dom::NodeInfo *aNodeInfo)
775 : {
776 : nsresult rv;
777 :
778 : // Create the element
779 : nsXULPrototypeElement* element;
780 0 : rv = CreateElement(aNodeInfo, &element);
781 :
782 0 : if (NS_FAILED(rv)) {
783 0 : if (MOZ_LOG_TEST(gContentSinkLog, LogLevel::Error)) {
784 0 : nsAutoString anodeC;
785 0 : aNodeInfo->GetName(anodeC);
786 0 : MOZ_LOG(gContentSinkLog, LogLevel::Error,
787 : ("xul: unable to create element '%s' at line %d",
788 : NS_ConvertUTF16toUTF8(anodeC).get(),
789 : aLineNumber));
790 : }
791 :
792 0 : return rv;
793 : }
794 :
795 : // Link this element to its parent.
796 0 : nsPrototypeArray* children = nullptr;
797 0 : rv = mContextStack.GetTopChildren(&children);
798 0 : if (NS_FAILED(rv)) {
799 0 : delete element;
800 0 : return rv;
801 : }
802 :
803 : // Add the attributes
804 0 : rv = AddAttributes(aAttributes, aAttrLen, element);
805 0 : if (NS_FAILED(rv)) return rv;
806 :
807 0 : children->AppendElement(element);
808 :
809 0 : if (aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML) ||
810 0 : aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XUL)) {
811 : // Do scripty things now
812 0 : rv = OpenScript(aAttributes, aLineNumber);
813 0 : NS_ENSURE_SUCCESS(rv, rv);
814 :
815 0 : NS_ASSERTION(mState == eInScript || mState == eInDocumentElement,
816 : "Unexpected state");
817 0 : if (mState == eInScript) {
818 : // OpenScript has pushed the nsPrototypeScriptElement onto the
819 : // stack, so we're done.
820 0 : return NS_OK;
821 : }
822 : }
823 :
824 : // Push the element onto the context stack, so that child
825 : // containers will hook up to us as their parent.
826 0 : rv = mContextStack.Push(element, mState);
827 0 : if (NS_FAILED(rv)) return rv;
828 :
829 0 : mState = eInDocumentElement;
830 0 : return NS_OK;
831 : }
832 :
833 : nsresult
834 0 : XULContentSinkImpl::OpenScript(const char16_t** aAttributes,
835 : const uint32_t aLineNumber)
836 : {
837 0 : bool isJavaScript = true;
838 0 : uint32_t version = JSVERSION_LATEST;
839 : nsresult rv;
840 :
841 : // Look for SRC attribute and look for a LANGUAGE attribute
842 0 : nsAutoString src;
843 0 : while (*aAttributes) {
844 0 : const nsDependentString key(aAttributes[0]);
845 0 : if (key.EqualsLiteral("src")) {
846 0 : src.Assign(aAttributes[1]);
847 0 : } else if (key.EqualsLiteral("type")) {
848 0 : nsDependentString str(aAttributes[1]);
849 0 : nsContentTypeParser parser(str);
850 0 : nsAutoString mimeType;
851 0 : rv = parser.GetType(mimeType);
852 0 : if (NS_FAILED(rv)) {
853 0 : if (rv == NS_ERROR_INVALID_ARG) {
854 : // Fail immediately rather than checking if later things
855 : // are okay.
856 0 : return NS_OK;
857 : }
858 : // We do want the warning here
859 0 : NS_ENSURE_SUCCESS(rv, rv);
860 : }
861 :
862 0 : if (nsContentUtils::IsJavascriptMIMEType(mimeType)) {
863 0 : isJavaScript = true;
864 0 : version = JSVERSION_LATEST;
865 :
866 : // Get the version string, and ensure that JavaScript supports it.
867 0 : nsAutoString versionName;
868 0 : rv = parser.GetParameter("version", versionName);
869 :
870 0 : if (NS_SUCCEEDED(rv)) {
871 0 : version = nsContentUtils::ParseJavascriptVersion(versionName);
872 0 : } else if (rv != NS_ERROR_INVALID_ARG) {
873 0 : return rv;
874 : }
875 : } else {
876 0 : isJavaScript = false;
877 : }
878 0 : } else if (key.EqualsLiteral("language")) {
879 : // Language is deprecated, and the impl in ScriptLoader ignores the
880 : // various version strings anyway. So we make no attempt to support
881 : // languages other than JS for language=
882 0 : nsAutoString lang(aAttributes[1]);
883 0 : if (nsContentUtils::IsJavaScriptLanguage(lang)) {
884 0 : isJavaScript = true;
885 0 : version = JSVERSION_DEFAULT;
886 : }
887 : }
888 0 : aAttributes += 2;
889 : }
890 :
891 : // Don't process scripts that aren't JavaScript.
892 0 : if (!isJavaScript) {
893 0 : return NS_OK;
894 : }
895 :
896 0 : nsCOMPtr<nsIDocument> doc(do_QueryReferent(mDocument));
897 0 : nsCOMPtr<nsIScriptGlobalObject> globalObject;
898 0 : if (doc)
899 0 : globalObject = do_QueryInterface(doc->GetWindow());
900 : RefPtr<nsXULPrototypeScript> script =
901 0 : new nsXULPrototypeScript(aLineNumber, version);
902 :
903 : // If there is a SRC attribute...
904 0 : if (! src.IsEmpty()) {
905 : // Use the SRC attribute value to load the URL
906 0 : rv = NS_NewURI(getter_AddRefs(script->mSrcURI), src, nullptr, mDocumentURL);
907 :
908 : // Check if this document is allowed to load a script from this source
909 : // NOTE: if we ever allow scripts added via the DOM to run, we need to
910 : // add a CheckLoadURI call for that as well.
911 0 : if (NS_SUCCEEDED(rv)) {
912 0 : if (!mSecMan)
913 0 : mSecMan = do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
914 0 : if (NS_SUCCEEDED(rv)) {
915 0 : nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument, &rv);
916 :
917 0 : if (NS_SUCCEEDED(rv)) {
918 0 : rv = mSecMan->
919 0 : CheckLoadURIWithPrincipal(doc->NodePrincipal(),
920 0 : script->mSrcURI,
921 0 : nsIScriptSecurityManager::ALLOW_CHROME);
922 : }
923 : }
924 : }
925 :
926 0 : if (NS_FAILED(rv)) {
927 0 : return rv;
928 : }
929 :
930 : // Attempt to deserialize an out-of-line script from the FastLoad
931 : // file right away. Otherwise we'll end up reloading the script and
932 : // corrupting the FastLoad file trying to serialize it, in the case
933 : // where it's already there.
934 0 : script->DeserializeOutOfLine(nullptr, mPrototype);
935 : }
936 :
937 0 : nsPrototypeArray* children = nullptr;
938 0 : rv = mContextStack.GetTopChildren(&children);
939 0 : if (NS_FAILED(rv)) {
940 0 : return rv;
941 : }
942 :
943 0 : children->AppendElement(script);
944 :
945 0 : mConstrainSize = false;
946 :
947 0 : mContextStack.Push(script, mState);
948 0 : mState = eInScript;
949 :
950 0 : return NS_OK;
951 : }
952 :
953 : nsresult
954 0 : XULContentSinkImpl::AddAttributes(const char16_t** aAttributes,
955 : const uint32_t aAttrLen,
956 : nsXULPrototypeElement* aElement)
957 : {
958 : // Add tag attributes to the element
959 : nsresult rv;
960 :
961 : // Create storage for the attributes
962 0 : nsXULPrototypeAttribute* attrs = nullptr;
963 0 : if (aAttrLen > 0) {
964 0 : attrs = new nsXULPrototypeAttribute[aAttrLen];
965 : }
966 :
967 0 : aElement->mAttributes = attrs;
968 0 : aElement->mNumAttributes = aAttrLen;
969 :
970 : // Copy the attributes into the prototype
971 : uint32_t i;
972 0 : for (i = 0; i < aAttrLen; ++i) {
973 0 : rv = NormalizeAttributeString(aAttributes[i * 2], attrs[i].mName);
974 0 : NS_ENSURE_SUCCESS(rv, rv);
975 :
976 0 : rv = aElement->SetAttrAt(i, nsDependentString(aAttributes[i * 2 + 1]),
977 0 : mDocumentURL);
978 0 : NS_ENSURE_SUCCESS(rv, rv);
979 :
980 0 : if (MOZ_LOG_TEST(gContentSinkLog, LogLevel::Debug)) {
981 0 : nsAutoString extraWhiteSpace;
982 0 : int32_t cnt = mContextStack.Depth();
983 0 : while (--cnt >= 0)
984 0 : extraWhiteSpace.AppendLiteral(" ");
985 0 : nsAutoString qnameC,valueC;
986 0 : qnameC.Assign(aAttributes[0]);
987 0 : valueC.Assign(aAttributes[1]);
988 0 : MOZ_LOG(gContentSinkLog, LogLevel::Debug,
989 : ("xul: %.5d. %s %s=%s",
990 : -1, // XXX pass in line number
991 : NS_ConvertUTF16toUTF8(extraWhiteSpace).get(),
992 : NS_ConvertUTF16toUTF8(qnameC).get(),
993 : NS_ConvertUTF16toUTF8(valueC).get()));
994 : }
995 : }
996 :
997 0 : return NS_OK;
998 : }
999 :
1000 : nsresult
1001 0 : XULContentSinkImpl::AddText(const char16_t* aText,
1002 : int32_t aLength)
1003 : {
1004 : // Create buffer when we first need it
1005 0 : if (0 == mTextSize) {
1006 0 : mText = (char16_t *) malloc(sizeof(char16_t) * 4096);
1007 0 : if (nullptr == mText) {
1008 0 : return NS_ERROR_OUT_OF_MEMORY;
1009 : }
1010 0 : mTextSize = 4096;
1011 : }
1012 :
1013 : // Copy data from string into our buffer; flush buffer when it fills up
1014 0 : int32_t offset = 0;
1015 0 : while (0 != aLength) {
1016 0 : int32_t amount = mTextSize - mTextLength;
1017 0 : if (amount > aLength) {
1018 0 : amount = aLength;
1019 : }
1020 0 : if (0 == amount) {
1021 0 : if (mConstrainSize) {
1022 0 : nsresult rv = FlushText();
1023 0 : if (NS_OK != rv) {
1024 0 : return rv;
1025 : }
1026 : } else {
1027 0 : CheckedInt32 size = mTextSize;
1028 0 : size += aLength;
1029 0 : if (!size.isValid()) {
1030 0 : return NS_ERROR_OUT_OF_MEMORY;
1031 : }
1032 0 : mTextSize = size.value();
1033 :
1034 0 : mText = (char16_t *) realloc(mText, sizeof(char16_t) * mTextSize);
1035 0 : if (nullptr == mText) {
1036 0 : return NS_ERROR_OUT_OF_MEMORY;
1037 : }
1038 : }
1039 : }
1040 0 : memcpy(&mText[mTextLength],aText + offset, sizeof(char16_t) * amount);
1041 :
1042 0 : mTextLength += amount;
1043 0 : offset += amount;
1044 0 : aLength -= amount;
1045 : }
1046 :
1047 0 : return NS_OK;
1048 : }
|