Source code

Revision control

Other Tools

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