Coverage Report

Created: 2018-09-25 14:53

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