Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/parser/html/nsHtml5TreeBuilderCppSupplement.h
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=2 sw=2 et tw=78: */
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
#include "nsError.h"
8
#include "nsIPresShell.h"
9
#include "nsNodeUtils.h"
10
#include "nsIFrame.h"
11
#include "mozilla/CheckedInt.h"
12
#include "mozilla/Likely.h"
13
#include "mozilla/UniquePtr.h"
14
15
nsHtml5TreeBuilder::nsHtml5TreeBuilder(nsHtml5OplessBuilder* aBuilder)
16
  : mode(0)
17
  , originalMode(0)
18
  , framesetOk(false)
19
  , tokenizer(nullptr)
20
  , scriptingEnabled(false)
21
  , needToDropLF(false)
22
  , fragment(false)
23
  , contextName(nullptr)
24
  , contextNamespace(kNameSpaceID_None)
25
  , contextNode(nullptr)
26
  , templateModePtr(0)
27
  , stackNodesIdx(0)
28
  , numStackNodes(0)
29
  , currentPtr(0)
30
  , listPtr(0)
31
  , formPointer(nullptr)
32
  , headPointer(nullptr)
33
  , deepTreeSurrogateParent(nullptr)
34
  , charBufferLen(0)
35
  , quirks(false)
36
  , isSrcdocDocument(false)
37
  , mBuilder(aBuilder)
38
  , mViewSource(nullptr)
39
  , mOpSink(nullptr)
40
  , mHandles(nullptr)
41
  , mHandlesUsed(0)
42
  , mSpeculativeLoadStage(nullptr)
43
  , mBroken(NS_OK)
44
  , mCurrentHtmlScriptIsAsyncOrDefer(false)
45
  , mPreventScriptExecution(false)
46
#ifdef DEBUG
47
  , mActive(false)
48
#endif
49
0
{
50
0
  MOZ_COUNT_CTOR(nsHtml5TreeBuilder);
51
0
}
52
53
nsHtml5TreeBuilder::nsHtml5TreeBuilder(nsAHtml5TreeOpSink* aOpSink,
54
                                       nsHtml5TreeOpStage* aStage)
55
  : mode(0)
56
  , originalMode(0)
57
  , framesetOk(false)
58
  , tokenizer(nullptr)
59
  , scriptingEnabled(false)
60
  , needToDropLF(false)
61
  , fragment(false)
62
  , contextName(nullptr)
63
  , contextNamespace(kNameSpaceID_None)
64
  , contextNode(nullptr)
65
  , templateModePtr(0)
66
  , stackNodesIdx(0)
67
  , numStackNodes(0)
68
  , currentPtr(0)
69
  , listPtr(0)
70
  , formPointer(nullptr)
71
  , headPointer(nullptr)
72
  , deepTreeSurrogateParent(nullptr)
73
  , charBufferLen(0)
74
  , quirks(false)
75
  , isSrcdocDocument(false)
76
  , mBuilder(nullptr)
77
  , mViewSource(nullptr)
78
  , mOpSink(aOpSink)
79
  , mHandles(new nsIContent*[NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH])
80
  , mHandlesUsed(0)
81
  , mSpeculativeLoadStage(aStage)
82
  , mBroken(NS_OK)
83
  , mCurrentHtmlScriptIsAsyncOrDefer(false)
84
  , mPreventScriptExecution(false)
85
#ifdef DEBUG
86
  , mActive(false)
87
#endif
88
0
{
89
0
  MOZ_COUNT_CTOR(nsHtml5TreeBuilder);
90
0
}
91
92
nsHtml5TreeBuilder::~nsHtml5TreeBuilder()
93
0
{
94
0
  MOZ_COUNT_DTOR(nsHtml5TreeBuilder);
95
0
  NS_ASSERTION(!mActive,
96
0
               "nsHtml5TreeBuilder deleted without ever calling end() on it!");
97
0
  mOpQueue.Clear();
98
0
}
99
100
nsIContentHandle*
101
nsHtml5TreeBuilder::createElement(int32_t aNamespace,
102
                                  nsAtom* aName,
103
                                  nsHtml5HtmlAttributes* aAttributes,
104
                                  nsIContentHandle* aIntendedParent,
105
                                  nsHtml5ContentCreatorFunction aCreator)
106
0
{
107
0
  MOZ_ASSERT(aAttributes, "Got null attributes.");
108
0
  MOZ_ASSERT(aName, "Got null name.");
109
0
  MOZ_ASSERT(aNamespace == kNameSpaceID_XHTML ||
110
0
               aNamespace == kNameSpaceID_SVG ||
111
0
               aNamespace == kNameSpaceID_MathML,
112
0
             "Bogus namespace.");
113
0
114
0
  if (mBuilder) {
115
0
    RefPtr<nsAtom> name = nsHtml5TreeOperation::Reget(aName);
116
0
117
0
    nsIContent* intendedParent =
118
0
      aIntendedParent ? static_cast<nsIContent*>(aIntendedParent) : nullptr;
119
0
120
0
    // intendedParent == nullptr is a special case where the
121
0
    // intended parent is the document.
122
0
    nsNodeInfoManager* nodeInfoManager =
123
0
      intendedParent ? intendedParent->OwnerDoc()->NodeInfoManager()
124
0
                     : mBuilder->GetNodeInfoManager();
125
0
126
0
    nsIContent* elem;
127
0
    if (aNamespace == kNameSpaceID_XHTML) {
128
0
      elem = nsHtml5TreeOperation::CreateHTMLElement(
129
0
        name,
130
0
        aAttributes,
131
0
        mozilla::dom::FROM_PARSER_FRAGMENT,
132
0
        nodeInfoManager,
133
0
        mBuilder,
134
0
        aCreator.html);
135
0
    } else if (aNamespace == kNameSpaceID_SVG) {
136
0
      elem = nsHtml5TreeOperation::CreateSVGElement(
137
0
        name,
138
0
        aAttributes,
139
0
        mozilla::dom::FROM_PARSER_FRAGMENT,
140
0
        nodeInfoManager,
141
0
        mBuilder,
142
0
        aCreator.svg);
143
0
    } else {
144
0
      MOZ_ASSERT(aNamespace == kNameSpaceID_MathML);
145
0
      elem = nsHtml5TreeOperation::CreateMathMLElement(
146
0
        name, aAttributes, nodeInfoManager, mBuilder);
147
0
    }
148
0
    if (MOZ_UNLIKELY(aAttributes != tokenizer->GetAttributes() &&
149
0
                     aAttributes != nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES)) {
150
0
      delete aAttributes;
151
0
    }
152
0
    return elem;
153
0
  }
154
0
155
0
  nsIContentHandle* content = AllocateContentHandle();
156
0
  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
157
0
  if (MOZ_UNLIKELY(!treeOp)) {
158
0
    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
159
0
    return nullptr;
160
0
  }
161
0
  treeOp->Init(aNamespace,
162
0
               aName,
163
0
               aAttributes,
164
0
               content,
165
0
               aIntendedParent,
166
0
               !!mSpeculativeLoadStage,
167
0
               aCreator);
168
0
  // mSpeculativeLoadStage is non-null only in the off-the-main-thread
169
0
  // tree builder, which handles the network stream
170
0
171
0
  // Start wall of code for speculative loading and line numbers
172
0
173
0
  if (mSpeculativeLoadStage) {
174
0
    switch (aNamespace) {
175
0
      case kNameSpaceID_XHTML:
176
0
        if (nsGkAtoms::img == aName) {
177
0
          nsHtml5String url =
178
0
            aAttributes->getValue(nsHtml5AttributeName::ATTR_SRC);
179
0
          nsHtml5String srcset =
180
0
            aAttributes->getValue(nsHtml5AttributeName::ATTR_SRCSET);
181
0
          nsHtml5String crossOrigin =
182
0
            aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN);
183
0
          nsHtml5String referrerPolicy =
184
0
            aAttributes->getValue(nsHtml5AttributeName::ATTR_REFERRERPOLICY);
185
0
          nsHtml5String sizes =
186
0
            aAttributes->getValue(nsHtml5AttributeName::ATTR_SIZES);
187
0
          mSpeculativeLoadQueue.AppendElement()->InitImage(
188
0
            url, crossOrigin, referrerPolicy, srcset, sizes);
189
0
        } else if (nsGkAtoms::source == aName) {
190
0
          nsHtml5String srcset =
191
0
            aAttributes->getValue(nsHtml5AttributeName::ATTR_SRCSET);
192
0
          // Sources without srcset cannot be selected. The source could also be
193
0
          // for a media element, but in that context doesn't use srcset.  See
194
0
          // comments in nsHtml5SpeculativeLoad.h about <picture> preloading
195
0
          if (srcset) {
196
0
            nsHtml5String sizes =
197
0
              aAttributes->getValue(nsHtml5AttributeName::ATTR_SIZES);
198
0
            nsHtml5String type =
199
0
              aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE);
200
0
            nsHtml5String media =
201
0
              aAttributes->getValue(nsHtml5AttributeName::ATTR_MEDIA);
202
0
            mSpeculativeLoadQueue.AppendElement()->InitPictureSource(
203
0
              srcset, sizes, type, media);
204
0
          }
205
0
        } else if (nsGkAtoms::script == aName) {
206
0
          nsHtml5TreeOperation* treeOp =
207
0
            mOpQueue.AppendElement(mozilla::fallible);
208
0
          if (MOZ_UNLIKELY(!treeOp)) {
209
0
            MarkAsBrokenAndRequestSuspensionWithoutBuilder(
210
0
              NS_ERROR_OUT_OF_MEMORY);
211
0
            return nullptr;
212
0
          }
213
0
          treeOp->Init(eTreeOpSetScriptLineNumberAndFreeze,
214
0
                       content,
215
0
                       tokenizer->getLineNumber());
216
0
217
0
          nsHtml5String url =
218
0
            aAttributes->getValue(nsHtml5AttributeName::ATTR_SRC);
219
0
          if (url) {
220
0
            nsHtml5String charset =
221
0
              aAttributes->getValue(nsHtml5AttributeName::ATTR_CHARSET);
222
0
            nsHtml5String type =
223
0
              aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE);
224
0
            nsHtml5String crossOrigin =
225
0
              aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN);
226
0
            nsHtml5String integrity =
227
0
              aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY);
228
0
            bool async =
229
0
              aAttributes->contains(nsHtml5AttributeName::ATTR_ASYNC);
230
0
            bool defer =
231
0
              aAttributes->contains(nsHtml5AttributeName::ATTR_DEFER);
232
0
            bool noModule =
233
0
              aAttributes->contains(nsHtml5AttributeName::ATTR_NOMODULE);
234
0
            mSpeculativeLoadQueue.AppendElement()->InitScript(
235
0
              url,
236
0
              charset,
237
0
              type,
238
0
              crossOrigin,
239
0
              integrity,
240
0
              mode == nsHtml5TreeBuilder::IN_HEAD,
241
0
              async,
242
0
              defer,
243
0
              noModule);
244
0
            mCurrentHtmlScriptIsAsyncOrDefer = async || defer;
245
0
          }
246
0
        } else if (nsGkAtoms::link == aName) {
247
0
          nsHtml5String rel =
248
0
            aAttributes->getValue(nsHtml5AttributeName::ATTR_REL);
249
0
          // Not splitting on space here is bogus but the old parser didn't even
250
0
          // do a case-insensitive check.
251
0
          if (rel) {
252
0
            if (rel.LowerCaseEqualsASCII("stylesheet")) {
253
0
              nsHtml5String url =
254
0
                aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF);
255
0
              if (url) {
256
0
                nsHtml5String charset =
257
0
                  aAttributes->getValue(nsHtml5AttributeName::ATTR_CHARSET);
258
0
                nsHtml5String crossOrigin =
259
0
                  aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN);
260
0
                nsHtml5String integrity =
261
0
                  aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY);
262
0
                nsHtml5String referrerPolicy = aAttributes->getValue(
263
0
                  nsHtml5AttributeName::ATTR_REFERRERPOLICY);
264
0
                mSpeculativeLoadQueue.AppendElement()->InitStyle(
265
0
                  url, charset, crossOrigin, referrerPolicy, integrity);
266
0
              }
267
0
            } else if (rel.LowerCaseEqualsASCII("preconnect")) {
268
0
              nsHtml5String url =
269
0
                aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF);
270
0
              if (url) {
271
0
                nsHtml5String crossOrigin =
272
0
                  aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN);
273
0
                mSpeculativeLoadQueue.AppendElement()->InitPreconnect(
274
0
                  url, crossOrigin);
275
0
              }
276
0
            }
277
0
          }
278
0
        } else if (nsGkAtoms::video == aName) {
279
0
          nsHtml5String url =
280
0
            aAttributes->getValue(nsHtml5AttributeName::ATTR_POSTER);
281
0
          if (url) {
282
0
            mSpeculativeLoadQueue.AppendElement()->InitImage(
283
0
              url, nullptr, nullptr, nullptr, nullptr);
284
0
          }
285
0
        } else if (nsGkAtoms::style == aName) {
286
0
          nsHtml5TreeOperation* treeOp =
287
0
            mOpQueue.AppendElement(mozilla::fallible);
288
0
          if (MOZ_UNLIKELY(!treeOp)) {
289
0
            MarkAsBrokenAndRequestSuspensionWithoutBuilder(
290
0
              NS_ERROR_OUT_OF_MEMORY);
291
0
            return nullptr;
292
0
          }
293
0
          treeOp->Init(
294
0
            eTreeOpSetStyleLineNumber, content, tokenizer->getLineNumber());
295
0
        } else if (nsGkAtoms::html == aName) {
296
0
          nsHtml5String url =
297
0
            aAttributes->getValue(nsHtml5AttributeName::ATTR_MANIFEST);
298
0
          mSpeculativeLoadQueue.AppendElement()->InitManifest(url);
299
0
        } else if (nsGkAtoms::base == aName) {
300
0
          nsHtml5String url =
301
0
            aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF);
302
0
          if (url) {
303
0
            mSpeculativeLoadQueue.AppendElement()->InitBase(url);
304
0
          }
305
0
        } else if (nsGkAtoms::meta == aName) {
306
0
          if (nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString(
307
0
                "content-security-policy",
308
0
                aAttributes->getValue(nsHtml5AttributeName::ATTR_HTTP_EQUIV))) {
309
0
            nsHtml5String csp =
310
0
              aAttributes->getValue(nsHtml5AttributeName::ATTR_CONTENT);
311
0
            if (csp) {
312
0
              mSpeculativeLoadQueue.AppendElement()->InitMetaCSP(csp);
313
0
            }
314
0
          } else if (nsHtml5Portability::
315
0
                       lowerCaseLiteralEqualsIgnoreAsciiCaseString(
316
0
                         "referrer",
317
0
                         aAttributes->getValue(
318
0
                           nsHtml5AttributeName::ATTR_NAME))) {
319
0
            nsHtml5String referrerPolicy =
320
0
              aAttributes->getValue(nsHtml5AttributeName::ATTR_CONTENT);
321
0
            if (referrerPolicy) {
322
0
              mSpeculativeLoadQueue.AppendElement()->InitMetaReferrerPolicy(
323
0
                referrerPolicy);
324
0
            }
325
0
          }
326
0
        }
327
0
        break;
328
0
      case kNameSpaceID_SVG:
329
0
        if (nsGkAtoms::image == aName) {
330
0
          nsHtml5String url =
331
0
            aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF);
332
0
          if (url) {
333
0
            mSpeculativeLoadQueue.AppendElement()->InitImage(
334
0
              url, nullptr, nullptr, nullptr, nullptr);
335
0
          }
336
0
        } else if (nsGkAtoms::script == aName) {
337
0
          nsHtml5TreeOperation* treeOp =
338
0
            mOpQueue.AppendElement(mozilla::fallible);
339
0
          if (MOZ_UNLIKELY(!treeOp)) {
340
0
            MarkAsBrokenAndRequestSuspensionWithoutBuilder(
341
0
              NS_ERROR_OUT_OF_MEMORY);
342
0
            return nullptr;
343
0
          }
344
0
          treeOp->Init(eTreeOpSetScriptLineNumberAndFreeze,
345
0
                       content,
346
0
                       tokenizer->getLineNumber());
347
0
348
0
          nsHtml5String url =
349
0
            aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF);
350
0
          if (url) {
351
0
            nsHtml5String type =
352
0
              aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE);
353
0
            nsHtml5String crossOrigin =
354
0
              aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN);
355
0
            nsHtml5String integrity =
356
0
              aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY);
357
0
            mSpeculativeLoadQueue.AppendElement()->InitScript(
358
0
              url,
359
0
              nullptr,
360
0
              type,
361
0
              crossOrigin,
362
0
              integrity,
363
0
              mode == nsHtml5TreeBuilder::IN_HEAD,
364
0
              false,
365
0
              false,
366
0
              false);
367
0
          }
368
0
        } else if (nsGkAtoms::style == aName) {
369
0
          nsHtml5TreeOperation* treeOp =
370
0
            mOpQueue.AppendElement(mozilla::fallible);
371
0
          if (MOZ_UNLIKELY(!treeOp)) {
372
0
            MarkAsBrokenAndRequestSuspensionWithoutBuilder(
373
0
              NS_ERROR_OUT_OF_MEMORY);
374
0
            return nullptr;
375
0
          }
376
0
          treeOp->Init(
377
0
            eTreeOpSetStyleLineNumber, content, tokenizer->getLineNumber());
378
0
379
0
          nsHtml5String url =
380
0
            aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF);
381
0
          if (url) {
382
0
            nsHtml5String crossOrigin =
383
0
              aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN);
384
0
            nsHtml5String integrity =
385
0
              aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY);
386
0
            nsHtml5String referrerPolicy =
387
0
              aAttributes->getValue(nsHtml5AttributeName::ATTR_REFERRERPOLICY);
388
0
            mSpeculativeLoadQueue.AppendElement()->InitStyle(
389
0
              url, nullptr, crossOrigin, referrerPolicy, integrity);
390
0
          }
391
0
        }
392
0
        break;
393
0
    }
394
0
  } else if (aNamespace != kNameSpaceID_MathML) {
395
0
    // No speculative loader--just line numbers and defer/async check
396
0
    if (nsGkAtoms::style == aName) {
397
0
      nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
398
0
      if (MOZ_UNLIKELY(!treeOp)) {
399
0
        MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
400
0
        return nullptr;
401
0
      }
402
0
      treeOp->Init(
403
0
        eTreeOpSetStyleLineNumber, content, tokenizer->getLineNumber());
404
0
    } else if (nsGkAtoms::script == aName) {
405
0
      nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
406
0
      if (MOZ_UNLIKELY(!treeOp)) {
407
0
        MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
408
0
        return nullptr;
409
0
      }
410
0
      treeOp->Init(eTreeOpSetScriptLineNumberAndFreeze,
411
0
                   content,
412
0
                   tokenizer->getLineNumber());
413
0
      if (aNamespace == kNameSpaceID_XHTML) {
414
0
        mCurrentHtmlScriptIsAsyncOrDefer =
415
0
          aAttributes->contains(nsHtml5AttributeName::ATTR_SRC) &&
416
0
          (aAttributes->contains(nsHtml5AttributeName::ATTR_ASYNC) ||
417
0
           aAttributes->contains(nsHtml5AttributeName::ATTR_DEFER));
418
0
      }
419
0
    } else if (aNamespace == kNameSpaceID_XHTML) {
420
0
      if (nsGkAtoms::html == aName) {
421
0
        nsHtml5String url =
422
0
          aAttributes->getValue(nsHtml5AttributeName::ATTR_MANIFEST);
423
0
        nsHtml5TreeOperation* treeOp =
424
0
          mOpQueue.AppendElement(mozilla::fallible);
425
0
        if (MOZ_UNLIKELY(!treeOp)) {
426
0
          MarkAsBrokenAndRequestSuspensionWithoutBuilder(
427
0
            NS_ERROR_OUT_OF_MEMORY);
428
0
          return nullptr;
429
0
        }
430
0
        if (url) {
431
0
          nsString
432
0
            urlString; // Not Auto, because using it to hold nsStringBuffer*
433
0
          url.ToString(urlString);
434
0
          treeOp->Init(eTreeOpProcessOfflineManifest, urlString);
435
0
        } else {
436
0
          treeOp->Init(eTreeOpProcessOfflineManifest, EmptyString());
437
0
        }
438
0
      } else if (nsGkAtoms::base == aName && mViewSource) {
439
0
        nsHtml5String url =
440
0
          aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF);
441
0
        if (url) {
442
0
          mViewSource->AddBase(url);
443
0
        }
444
0
      }
445
0
    }
446
0
  }
447
0
448
0
  // End wall of code for speculative loading
449
0
450
0
  return content;
451
0
}
452
453
nsIContentHandle*
454
nsHtml5TreeBuilder::createElement(int32_t aNamespace,
455
                                  nsAtom* aName,
456
                                  nsHtml5HtmlAttributes* aAttributes,
457
                                  nsIContentHandle* aFormElement,
458
                                  nsIContentHandle* aIntendedParent,
459
                                  nsHtml5ContentCreatorFunction aCreator)
460
0
{
461
0
  nsIContentHandle* content =
462
0
    createElement(aNamespace, aName, aAttributes, aIntendedParent, aCreator);
463
0
  if (aFormElement) {
464
0
    if (mBuilder) {
465
0
      nsHtml5TreeOperation::SetFormElement(
466
0
        static_cast<nsIContent*>(content),
467
0
        static_cast<nsIContent*>(aFormElement));
468
0
    } else {
469
0
      nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
470
0
      if (MOZ_UNLIKELY(!treeOp)) {
471
0
        MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
472
0
        return nullptr;
473
0
      }
474
0
      treeOp->Init(eTreeOpSetFormElement, content, aFormElement);
475
0
    }
476
0
  }
477
0
  return content;
478
0
}
479
480
nsIContentHandle*
481
nsHtml5TreeBuilder::createHtmlElementSetAsRoot(
482
  nsHtml5HtmlAttributes* aAttributes)
483
0
{
484
0
  nsHtml5ContentCreatorFunction creator;
485
0
  // <html> uses NS_NewHTMLSharedElement creator
486
0
  creator.html = NS_NewHTMLSharedElement;
487
0
  nsIContentHandle* content = createElement(
488
0
    kNameSpaceID_XHTML, nsGkAtoms::html, aAttributes, nullptr, creator);
489
0
  if (mBuilder) {
490
0
    nsresult rv = nsHtml5TreeOperation::AppendToDocument(
491
0
      static_cast<nsIContent*>(content), mBuilder);
492
0
    if (NS_FAILED(rv)) {
493
0
      MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
494
0
    }
495
0
  } else {
496
0
    nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
497
0
    if (MOZ_UNLIKELY(!treeOp)) {
498
0
      MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
499
0
      return nullptr;
500
0
    }
501
0
    treeOp->Init(eTreeOpAppendToDocument, content);
502
0
  }
503
0
  return content;
504
0
}
505
506
nsIContentHandle*
507
nsHtml5TreeBuilder::createAndInsertFosterParentedElement(
508
  int32_t aNamespace,
509
  nsAtom* aName,
510
  nsHtml5HtmlAttributes* aAttributes,
511
  nsIContentHandle* aFormElement,
512
  nsIContentHandle* aTable,
513
  nsIContentHandle* aStackParent,
514
  nsHtml5ContentCreatorFunction aCreator)
515
0
{
516
0
  MOZ_ASSERT(aTable, "Null table");
517
0
  MOZ_ASSERT(aStackParent, "Null stack parent");
518
0
519
0
  if (mBuilder) {
520
0
    // Get the foster parent to use as the intended parent when creating
521
0
    // the child element.
522
0
    nsIContent* fosterParent = nsHtml5TreeOperation::GetFosterParent(
523
0
      static_cast<nsIContent*>(aTable), static_cast<nsIContent*>(aStackParent));
524
0
525
0
    nsIContentHandle* child = createElement(
526
0
      aNamespace, aName, aAttributes, aFormElement, fosterParent, aCreator);
527
0
528
0
    insertFosterParentedChild(child, aTable, aStackParent);
529
0
530
0
    return child;
531
0
  }
532
0
533
0
  // Tree op to get the foster parent that we use as the intended parent
534
0
  // when creating the child element.
535
0
  nsHtml5TreeOperation* fosterParentTreeOp = mOpQueue.AppendElement();
536
0
  NS_ASSERTION(fosterParentTreeOp, "Tree op allocation failed.");
537
0
  nsIContentHandle* fosterParentHandle = AllocateContentHandle();
538
0
  fosterParentTreeOp->Init(
539
0
    eTreeOpGetFosterParent, aTable, aStackParent, fosterParentHandle);
540
0
541
0
  // Create the element with the correct intended parent.
542
0
  nsIContentHandle* child = createElement(
543
0
    aNamespace, aName, aAttributes, aFormElement, fosterParentHandle, aCreator);
544
0
545
0
  // Insert the child into the foster parent.
546
0
  insertFosterParentedChild(child, aTable, aStackParent);
547
0
548
0
  return child;
549
0
}
550
551
void
552
nsHtml5TreeBuilder::detachFromParent(nsIContentHandle* aElement)
553
0
{
554
0
  MOZ_ASSERT(aElement, "Null element");
555
0
556
0
  if (mBuilder) {
557
0
    nsHtml5TreeOperation::Detach(static_cast<nsIContent*>(aElement), mBuilder);
558
0
    return;
559
0
  }
560
0
561
0
  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
562
0
  if (MOZ_UNLIKELY(!treeOp)) {
563
0
    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
564
0
    return;
565
0
  }
566
0
  treeOp->Init(eTreeOpDetach, aElement);
567
0
}
568
569
void
570
nsHtml5TreeBuilder::appendElement(nsIContentHandle* aChild,
571
                                  nsIContentHandle* aParent)
572
0
{
573
0
  MOZ_ASSERT(aChild, "Null child");
574
0
  MOZ_ASSERT(aParent, "Null parent");
575
0
  if (deepTreeSurrogateParent) {
576
0
    return;
577
0
  }
578
0
579
0
  if (mBuilder) {
580
0
    nsresult rv =
581
0
      nsHtml5TreeOperation::Append(static_cast<nsIContent*>(aChild),
582
0
                                   static_cast<nsIContent*>(aParent),
583
0
                                   mBuilder);
584
0
    if (NS_FAILED(rv)) {
585
0
      MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
586
0
    }
587
0
    return;
588
0
  }
589
0
590
0
  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
591
0
  if (MOZ_UNLIKELY(!treeOp)) {
592
0
    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
593
0
    return;
594
0
  }
595
0
  treeOp->Init(eTreeOpAppend, aChild, aParent);
596
0
}
597
598
void
599
nsHtml5TreeBuilder::appendChildrenToNewParent(nsIContentHandle* aOldParent,
600
                                              nsIContentHandle* aNewParent)
601
0
{
602
0
  MOZ_ASSERT(aOldParent, "Null old parent");
603
0
  MOZ_ASSERT(aNewParent, "Null new parent");
604
0
605
0
  if (mBuilder) {
606
0
    nsresult rv = nsHtml5TreeOperation::AppendChildrenToNewParent(
607
0
      static_cast<nsIContent*>(aOldParent),
608
0
      static_cast<nsIContent*>(aNewParent),
609
0
      mBuilder);
610
0
    if (NS_FAILED(rv)) {
611
0
      MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
612
0
    }
613
0
    return;
614
0
  }
615
0
616
0
  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
617
0
  if (MOZ_UNLIKELY(!treeOp)) {
618
0
    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
619
0
    return;
620
0
  }
621
0
  treeOp->Init(eTreeOpAppendChildrenToNewParent, aOldParent, aNewParent);
622
0
}
623
624
void
625
nsHtml5TreeBuilder::insertFosterParentedCharacters(
626
  char16_t* aBuffer,
627
  int32_t aStart,
628
  int32_t aLength,
629
  nsIContentHandle* aTable,
630
  nsIContentHandle* aStackParent)
631
0
{
632
0
  MOZ_ASSERT(aBuffer, "Null buffer");
633
0
  MOZ_ASSERT(aTable, "Null table");
634
0
  MOZ_ASSERT(aStackParent, "Null stack parent");
635
0
  MOZ_ASSERT(!aStart, "aStart must always be zero.");
636
0
637
0
  if (mBuilder) {
638
0
    nsresult rv = nsHtml5TreeOperation::FosterParentText(
639
0
      static_cast<nsIContent*>(aStackParent),
640
0
      aBuffer, // XXX aStart always ignored???
641
0
      aLength,
642
0
      static_cast<nsIContent*>(aTable),
643
0
      mBuilder);
644
0
    if (NS_FAILED(rv)) {
645
0
      MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
646
0
    }
647
0
    return;
648
0
  }
649
0
650
0
  auto bufferCopy = mozilla::MakeUniqueFallible<char16_t[]>(aLength);
651
0
  if (!bufferCopy) {
652
0
    // Just assigning mBroken instead of generating tree op. The caller
653
0
    // of tokenizeBuffer() will call MarkAsBroken() as appropriate.
654
0
    mBroken = NS_ERROR_OUT_OF_MEMORY;
655
0
    requestSuspension();
656
0
    return;
657
0
  }
658
0
659
0
  memcpy(bufferCopy.get(), aBuffer, aLength * sizeof(char16_t));
660
0
661
0
  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
662
0
  if (MOZ_UNLIKELY(!treeOp)) {
663
0
    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
664
0
    return;
665
0
  }
666
0
  treeOp->Init(eTreeOpFosterParentText,
667
0
               bufferCopy.release(),
668
0
               aLength,
669
0
               aStackParent,
670
0
               aTable);
671
0
}
672
673
void
674
nsHtml5TreeBuilder::insertFosterParentedChild(nsIContentHandle* aChild,
675
                                              nsIContentHandle* aTable,
676
                                              nsIContentHandle* aStackParent)
677
0
{
678
0
  MOZ_ASSERT(aChild, "Null child");
679
0
  MOZ_ASSERT(aTable, "Null table");
680
0
  MOZ_ASSERT(aStackParent, "Null stack parent");
681
0
682
0
  if (mBuilder) {
683
0
    nsresult rv =
684
0
      nsHtml5TreeOperation::FosterParent(static_cast<nsIContent*>(aChild),
685
0
                                         static_cast<nsIContent*>(aStackParent),
686
0
                                         static_cast<nsIContent*>(aTable),
687
0
                                         mBuilder);
688
0
    if (NS_FAILED(rv)) {
689
0
      MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
690
0
    }
691
0
    return;
692
0
  }
693
0
694
0
  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
695
0
  if (MOZ_UNLIKELY(!treeOp)) {
696
0
    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
697
0
    return;
698
0
  }
699
0
  treeOp->Init(eTreeOpFosterParent, aChild, aStackParent, aTable);
700
0
}
701
702
void
703
nsHtml5TreeBuilder::appendCharacters(nsIContentHandle* aParent,
704
                                     char16_t* aBuffer,
705
                                     int32_t aStart,
706
                                     int32_t aLength)
707
0
{
708
0
  MOZ_ASSERT(aBuffer, "Null buffer");
709
0
  MOZ_ASSERT(aParent, "Null parent");
710
0
  MOZ_ASSERT(!aStart, "aStart must always be zero.");
711
0
712
0
  if (mBuilder) {
713
0
    nsresult rv = nsHtml5TreeOperation::AppendText(
714
0
      aBuffer, // XXX aStart always ignored???
715
0
      aLength,
716
0
      static_cast<nsIContent*>(deepTreeSurrogateParent ? deepTreeSurrogateParent
717
0
                                                       : aParent),
718
0
      mBuilder);
719
0
    if (NS_FAILED(rv)) {
720
0
      MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
721
0
    }
722
0
    return;
723
0
  }
724
0
725
0
  auto bufferCopy = mozilla::MakeUniqueFallible<char16_t[]>(aLength);
726
0
  if (!bufferCopy) {
727
0
    // Just assigning mBroken instead of generating tree op. The caller
728
0
    // of tokenizeBuffer() will call MarkAsBroken() as appropriate.
729
0
    mBroken = NS_ERROR_OUT_OF_MEMORY;
730
0
    requestSuspension();
731
0
    return;
732
0
  }
733
0
734
0
  memcpy(bufferCopy.get(), aBuffer, aLength * sizeof(char16_t));
735
0
736
0
  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
737
0
  if (MOZ_UNLIKELY(!treeOp)) {
738
0
    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
739
0
    return;
740
0
  }
741
0
  treeOp->Init(eTreeOpAppendText,
742
0
               bufferCopy.release(),
743
0
               aLength,
744
0
               deepTreeSurrogateParent ? deepTreeSurrogateParent : aParent);
745
0
}
746
747
void
748
nsHtml5TreeBuilder::appendComment(nsIContentHandle* aParent,
749
                                  char16_t* aBuffer,
750
                                  int32_t aStart,
751
                                  int32_t aLength)
752
0
{
753
0
  MOZ_ASSERT(aBuffer, "Null buffer");
754
0
  MOZ_ASSERT(aParent, "Null parent");
755
0
  MOZ_ASSERT(!aStart, "aStart must always be zero.");
756
0
757
0
  if (deepTreeSurrogateParent) {
758
0
    return;
759
0
  }
760
0
761
0
  if (mBuilder) {
762
0
    nsresult rv = nsHtml5TreeOperation::AppendComment(
763
0
      static_cast<nsIContent*>(aParent),
764
0
      aBuffer, // XXX aStart always ignored???
765
0
      aLength,
766
0
      mBuilder);
767
0
    if (NS_FAILED(rv)) {
768
0
      MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
769
0
    }
770
0
    return;
771
0
  }
772
0
773
0
  auto bufferCopy = mozilla::MakeUniqueFallible<char16_t[]>(aLength);
774
0
  if (!bufferCopy) {
775
0
    // Just assigning mBroken instead of generating tree op. The caller
776
0
    // of tokenizeBuffer() will call MarkAsBroken() as appropriate.
777
0
    mBroken = NS_ERROR_OUT_OF_MEMORY;
778
0
    requestSuspension();
779
0
    return;
780
0
  }
781
0
782
0
  memcpy(bufferCopy.get(), aBuffer, aLength * sizeof(char16_t));
783
0
784
0
  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
785
0
  if (MOZ_UNLIKELY(!treeOp)) {
786
0
    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
787
0
    return;
788
0
  }
789
0
  treeOp->Init(eTreeOpAppendComment, bufferCopy.release(), aLength, aParent);
790
0
}
791
792
void
793
nsHtml5TreeBuilder::appendCommentToDocument(char16_t* aBuffer,
794
                                            int32_t aStart,
795
                                            int32_t aLength)
796
0
{
797
0
  MOZ_ASSERT(aBuffer, "Null buffer");
798
0
  MOZ_ASSERT(!aStart, "aStart must always be zero.");
799
0
800
0
  if (mBuilder) {
801
0
    nsresult rv = nsHtml5TreeOperation::AppendCommentToDocument(
802
0
      aBuffer, // XXX aStart always ignored???
803
0
      aLength,
804
0
      mBuilder);
805
0
    if (NS_FAILED(rv)) {
806
0
      MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
807
0
    }
808
0
    return;
809
0
  }
810
0
811
0
  auto bufferCopy = mozilla::MakeUniqueFallible<char16_t[]>(aLength);
812
0
  if (!bufferCopy) {
813
0
    // Just assigning mBroken instead of generating tree op. The caller
814
0
    // of tokenizeBuffer() will call MarkAsBroken() as appropriate.
815
0
    mBroken = NS_ERROR_OUT_OF_MEMORY;
816
0
    requestSuspension();
817
0
    return;
818
0
  }
819
0
820
0
  memcpy(bufferCopy.get(), aBuffer, aLength * sizeof(char16_t));
821
0
822
0
  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
823
0
  if (MOZ_UNLIKELY(!treeOp)) {
824
0
    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
825
0
    return;
826
0
  }
827
0
  treeOp->Init(eTreeOpAppendCommentToDocument, bufferCopy.release(), aLength);
828
0
}
829
830
void
831
nsHtml5TreeBuilder::addAttributesToElement(nsIContentHandle* aElement,
832
                                           nsHtml5HtmlAttributes* aAttributes)
833
0
{
834
0
  MOZ_ASSERT(aElement, "Null element");
835
0
  MOZ_ASSERT(aAttributes, "Null attributes");
836
0
837
0
  if (aAttributes == nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES) {
838
0
    return;
839
0
  }
840
0
841
0
  if (mBuilder) {
842
0
    MOZ_ASSERT(
843
0
      aAttributes == tokenizer->GetAttributes(),
844
0
      "Using attribute other than the tokenizer's to add to body or html.");
845
0
    nsresult rv = nsHtml5TreeOperation::AddAttributes(
846
0
      static_cast<nsIContent*>(aElement), aAttributes, mBuilder);
847
0
    if (NS_FAILED(rv)) {
848
0
      MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
849
0
    }
850
0
    return;
851
0
  }
852
0
853
0
  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
854
0
  if (MOZ_UNLIKELY(!treeOp)) {
855
0
    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
856
0
    return;
857
0
  }
858
0
  treeOp->Init(aElement, aAttributes);
859
0
}
860
861
void
862
nsHtml5TreeBuilder::markMalformedIfScript(nsIContentHandle* aElement)
863
0
{
864
0
  MOZ_ASSERT(aElement, "Null element");
865
0
866
0
  if (mBuilder) {
867
0
    nsHtml5TreeOperation::MarkMalformedIfScript(
868
0
      static_cast<nsIContent*>(aElement));
869
0
    return;
870
0
  }
871
0
872
0
  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
873
0
  if (MOZ_UNLIKELY(!treeOp)) {
874
0
    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
875
0
    return;
876
0
  }
877
0
  treeOp->Init(eTreeOpMarkMalformedIfScript, aElement);
878
0
}
879
880
void
881
nsHtml5TreeBuilder::start(bool fragment)
882
0
{
883
0
  mCurrentHtmlScriptIsAsyncOrDefer = false;
884
0
  deepTreeSurrogateParent = nullptr;
885
#ifdef DEBUG
886
  mActive = true;
887
#endif
888
}
889
890
void
891
nsHtml5TreeBuilder::end()
892
0
{
893
0
  mOpQueue.Clear();
894
#ifdef DEBUG
895
  mActive = false;
896
#endif
897
}
898
899
void
900
nsHtml5TreeBuilder::appendDoctypeToDocument(nsAtom* aName,
901
                                            nsHtml5String aPublicId,
902
                                            nsHtml5String aSystemId)
903
0
{
904
0
  MOZ_ASSERT(aName, "Null name");
905
0
  nsString publicId; // Not Auto, because using it to hold nsStringBuffer*
906
0
  nsString systemId; // Not Auto, because using it to hold nsStringBuffer*
907
0
  aPublicId.ToString(publicId);
908
0
  aSystemId.ToString(systemId);
909
0
  if (mBuilder) {
910
0
    RefPtr<nsAtom> name = nsHtml5TreeOperation::Reget(aName);
911
0
    nsresult rv = nsHtml5TreeOperation::AppendDoctypeToDocument(
912
0
      name, publicId, systemId, mBuilder);
913
0
    if (NS_FAILED(rv)) {
914
0
      MarkAsBrokenAndRequestSuspensionWithBuilder(rv);
915
0
    }
916
0
    return;
917
0
  }
918
0
919
0
  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
920
0
  if (MOZ_UNLIKELY(!treeOp)) {
921
0
    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
922
0
    return;
923
0
  }
924
0
  treeOp->Init(aName, publicId, systemId);
925
0
  // nsXMLContentSink can flush here, but what's the point?
926
0
  // It can also interrupt here, but we can't.
927
0
}
928
929
void
930
nsHtml5TreeBuilder::elementPushed(int32_t aNamespace,
931
                                  nsAtom* aName,
932
                                  nsIContentHandle* aElement)
933
0
{
934
0
  NS_ASSERTION(aNamespace == kNameSpaceID_XHTML ||
935
0
                 aNamespace == kNameSpaceID_SVG ||
936
0
                 aNamespace == kNameSpaceID_MathML,
937
0
               "Element isn't HTML, SVG or MathML!");
938
0
  NS_ASSERTION(aName, "Element doesn't have local name!");
939
0
  NS_ASSERTION(aElement, "No element!");
940
0
  /*
941
0
   * The frame constructor uses recursive algorithms, so it can't deal with
942
0
   * arbitrarily deep trees. This is especially a problem on Windows where
943
0
   * the permitted depth of the runtime stack is rather small.
944
0
   *
945
0
   * The following is a protection against author incompetence--not against
946
0
   * malice. There are other ways to make the DOM deep anyway.
947
0
   *
948
0
   * The basic idea is that when the tree builder stack gets too deep,
949
0
   * append operations no longer append to the node that the HTML parsing
950
0
   * algorithm says they should but instead text nodes are append to the last
951
0
   * element that was seen before a magic tree builder stack threshold was
952
0
   * reached and element and comment nodes aren't appended to the DOM at all.
953
0
   *
954
0
   * However, for security reasons, non-child descendant text nodes inside an
955
0
   * SVG script or style element should not become children. Also, non-cell
956
0
   * table elements shouldn't be used as surrogate parents for user experience
957
0
   * reasons.
958
0
   */
959
0
  if (!deepTreeSurrogateParent && currentPtr >= MAX_REFLOW_DEPTH &&
960
0
      !(aName == nsGkAtoms::script || aName == nsGkAtoms::table ||
961
0
        aName == nsGkAtoms::thead || aName == nsGkAtoms::tfoot ||
962
0
        aName == nsGkAtoms::tbody || aName == nsGkAtoms::tr ||
963
0
        aName == nsGkAtoms::colgroup || aName == nsGkAtoms::style)) {
964
0
    deepTreeSurrogateParent = aElement;
965
0
  }
966
0
  if (aNamespace != kNameSpaceID_XHTML) {
967
0
    return;
968
0
  }
969
0
  if (aName == nsGkAtoms::body || aName == nsGkAtoms::frameset) {
970
0
    if (mBuilder) {
971
0
      // InnerHTML and DOMParser shouldn't start layout anyway
972
0
      return;
973
0
    }
974
0
    nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
975
0
    if (MOZ_UNLIKELY(!treeOp)) {
976
0
      MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
977
0
      return;
978
0
    }
979
0
    treeOp->Init(eTreeOpStartLayout);
980
0
    return;
981
0
  }
982
0
  if (aName == nsGkAtoms::input || aName == nsGkAtoms::button) {
983
0
    if (mBuilder) {
984
0
      nsHtml5TreeOperation::DoneCreatingElement(
985
0
        static_cast<nsIContent*>(aElement));
986
0
    } else {
987
0
      mOpQueue.AppendElement()->Init(eTreeOpDoneCreatingElement, aElement);
988
0
    }
989
0
    return;
990
0
  }
991
0
  if (aName == nsGkAtoms::audio || aName == nsGkAtoms::video ||
992
0
      aName == nsGkAtoms::menuitem) {
993
0
    if (mBuilder) {
994
0
      nsHtml5TreeOperation::DoneCreatingElement(
995
0
        static_cast<nsIContent*>(aElement));
996
0
    } else {
997
0
      mOpQueue.AppendElement()->Init(eTreeOpDoneCreatingElement, aElement);
998
0
    }
999
0
    return;
1000
0
  }
1001
0
  if (mSpeculativeLoadStage && aName == nsGkAtoms::picture) {
1002
0
    // mSpeculativeLoadStage is non-null only in the off-the-main-thread
1003
0
    // tree builder, which handles the network stream
1004
0
    //
1005
0
    // See comments in nsHtml5SpeculativeLoad.h about <picture> preloading
1006
0
    mSpeculativeLoadQueue.AppendElement()->InitOpenPicture();
1007
0
  }
1008
0
}
1009
1010
void
1011
nsHtml5TreeBuilder::elementPopped(int32_t aNamespace,
1012
                                  nsAtom* aName,
1013
                                  nsIContentHandle* aElement)
1014
0
{
1015
0
  NS_ASSERTION(aNamespace == kNameSpaceID_XHTML ||
1016
0
                 aNamespace == kNameSpaceID_SVG ||
1017
0
                 aNamespace == kNameSpaceID_MathML,
1018
0
               "Element isn't HTML, SVG or MathML!");
1019
0
  NS_ASSERTION(aName, "Element doesn't have local name!");
1020
0
  NS_ASSERTION(aElement, "No element!");
1021
0
  if (deepTreeSurrogateParent && currentPtr <= MAX_REFLOW_DEPTH) {
1022
0
    deepTreeSurrogateParent = nullptr;
1023
0
  }
1024
0
  if (aNamespace == kNameSpaceID_MathML) {
1025
0
    return;
1026
0
  }
1027
0
  // we now have only SVG and HTML
1028
0
  if (aName == nsGkAtoms::script) {
1029
0
    if (mPreventScriptExecution) {
1030
0
      if (mBuilder) {
1031
0
        nsHtml5TreeOperation::PreventScriptExecution(
1032
0
          static_cast<nsIContent*>(aElement));
1033
0
        return;
1034
0
      }
1035
0
      mOpQueue.AppendElement()->Init(eTreeOpPreventScriptExecution, aElement);
1036
0
      return;
1037
0
    }
1038
0
    if (mBuilder) {
1039
0
      return;
1040
0
    }
1041
0
    if (mCurrentHtmlScriptIsAsyncOrDefer) {
1042
0
      NS_ASSERTION(aNamespace == kNameSpaceID_XHTML,
1043
0
                   "Only HTML scripts may be async/defer.");
1044
0
      nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
1045
0
      if (MOZ_UNLIKELY(!treeOp)) {
1046
0
        MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
1047
0
        return;
1048
0
      }
1049
0
      treeOp->Init(eTreeOpRunScriptAsyncDefer, aElement);
1050
0
      mCurrentHtmlScriptIsAsyncOrDefer = false;
1051
0
      return;
1052
0
    }
1053
0
    requestSuspension();
1054
0
    nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
1055
0
    if (MOZ_UNLIKELY(!treeOp)) {
1056
0
      MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
1057
0
      return;
1058
0
    }
1059
0
    treeOp->InitScript(aElement);
1060
0
    return;
1061
0
  }
1062
0
  if (aName == nsGkAtoms::title) {
1063
0
    if (mBuilder) {
1064
0
      nsHtml5TreeOperation::DoneAddingChildren(
1065
0
        static_cast<nsIContent*>(aElement));
1066
0
      return;
1067
0
    }
1068
0
    nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
1069
0
    if (MOZ_UNLIKELY(!treeOp)) {
1070
0
      MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
1071
0
      return;
1072
0
    }
1073
0
    treeOp->Init(eTreeOpDoneAddingChildren, aElement);
1074
0
    return;
1075
0
  }
1076
0
  if (aName == nsGkAtoms::style ||
1077
0
      (aNamespace == kNameSpaceID_XHTML && aName == nsGkAtoms::link)) {
1078
0
    if (mBuilder) {
1079
0
      MOZ_ASSERT(!nsContentUtils::IsSafeToRunScript(),
1080
0
                 "Scripts must be blocked.");
1081
0
      mBuilder->UpdateStyleSheet(static_cast<nsIContent*>(aElement));
1082
0
      return;
1083
0
    }
1084
0
    nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
1085
0
    if (MOZ_UNLIKELY(!treeOp)) {
1086
0
      MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
1087
0
      return;
1088
0
    }
1089
0
    treeOp->Init(eTreeOpUpdateStyleSheet, aElement);
1090
0
    return;
1091
0
  }
1092
0
  if (aNamespace == kNameSpaceID_SVG) {
1093
0
    if (aName == nsGkAtoms::svg) {
1094
0
      if (mBuilder) {
1095
0
        nsHtml5TreeOperation::SvgLoad(static_cast<nsIContent*>(aElement));
1096
0
        return;
1097
0
      }
1098
0
      nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
1099
0
      if (MOZ_UNLIKELY(!treeOp)) {
1100
0
        MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
1101
0
        return;
1102
0
      }
1103
0
      treeOp->Init(eTreeOpSvgLoad, aElement);
1104
0
    }
1105
0
    return;
1106
0
  }
1107
0
  // we now have only HTML
1108
0
  // Some HTML nodes need DoneAddingChildren() called to initialize
1109
0
  // properly (e.g. form state restoration).
1110
0
  // XXX expose ElementName group here and do switch
1111
0
  if (aName == nsGkAtoms::object || aName == nsGkAtoms::select ||
1112
0
      aName == nsGkAtoms::textarea || aName == nsGkAtoms::output ||
1113
0
      aName == nsGkAtoms::head) {
1114
0
    if (mBuilder) {
1115
0
      nsHtml5TreeOperation::DoneAddingChildren(
1116
0
        static_cast<nsIContent*>(aElement));
1117
0
      return;
1118
0
    }
1119
0
    nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
1120
0
    if (MOZ_UNLIKELY(!treeOp)) {
1121
0
      MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
1122
0
      return;
1123
0
    }
1124
0
    treeOp->Init(eTreeOpDoneAddingChildren, aElement);
1125
0
    return;
1126
0
  }
1127
0
  if (aName == nsGkAtoms::meta && !fragment && !mBuilder) {
1128
0
    nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
1129
0
    if (MOZ_UNLIKELY(!treeOp)) {
1130
0
      MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
1131
0
      return;
1132
0
    }
1133
0
    treeOp->Init(eTreeOpProcessMeta, aElement);
1134
0
    return;
1135
0
  }
1136
0
  if (mSpeculativeLoadStage && aName == nsGkAtoms::picture) {
1137
0
    // mSpeculativeLoadStage is non-null only in the off-the-main-thread
1138
0
    // tree builder, which handles the network stream
1139
0
    //
1140
0
    // See comments in nsHtml5SpeculativeLoad.h about <picture> preloading
1141
0
    mSpeculativeLoadQueue.AppendElement()->InitEndPicture();
1142
0
  }
1143
0
}
1144
1145
void
1146
nsHtml5TreeBuilder::accumulateCharacters(const char16_t* aBuf,
1147
                                         int32_t aStart,
1148
                                         int32_t aLength)
1149
0
{
1150
0
  MOZ_RELEASE_ASSERT(charBufferLen + aLength <= charBuffer.length,
1151
0
                     "About to memcpy past the end of the buffer!");
1152
0
  memcpy(charBuffer + charBufferLen, aBuf + aStart, sizeof(char16_t) * aLength);
1153
0
  charBufferLen += aLength;
1154
0
}
1155
1156
// INT32_MAX is (2^31)-1. Therefore, the highest power-of-two that fits
1157
// is 2^30. Note that this is counting char16_t units. The underlying
1158
// bytes will be twice that, but they fit even in 32-bit size_t even
1159
// if a contiguous chunk of memory of that size is pretty unlikely to
1160
// be available on a 32-bit system.
1161
0
#define MAX_POWER_OF_TWO_IN_INT32 0x40000000
1162
1163
bool
1164
nsHtml5TreeBuilder::EnsureBufferSpace(int32_t aLength)
1165
0
{
1166
0
  // TODO: Unify nsHtml5Tokenizer::strBuf and nsHtml5TreeBuilder::charBuffer
1167
0
  // so that this method becomes unnecessary.
1168
0
  mozilla::CheckedInt<int32_t> worstCase(charBufferLen);
1169
0
  worstCase += aLength;
1170
0
  if (!worstCase.isValid()) {
1171
0
    return false;
1172
0
  }
1173
0
  if (worstCase.value() > MAX_POWER_OF_TWO_IN_INT32) {
1174
0
    return false;
1175
0
  }
1176
0
  if (!charBuffer) {
1177
0
    if (worstCase.value() < MAX_POWER_OF_TWO_IN_INT32) {
1178
0
      // Add one to round to the next power of two to avoid immediate
1179
0
      // reallocation once there are a few characters in the buffer.
1180
0
      worstCase += 1;
1181
0
    }
1182
0
    charBuffer = jArray<char16_t, int32_t>::newFallibleJArray(
1183
0
      mozilla::RoundUpPow2(worstCase.value()));
1184
0
    if (!charBuffer) {
1185
0
      return false;
1186
0
    }
1187
0
  } else if (worstCase.value() > charBuffer.length) {
1188
0
    jArray<char16_t, int32_t> newBuf =
1189
0
      jArray<char16_t, int32_t>::newFallibleJArray(
1190
0
        mozilla::RoundUpPow2(worstCase.value()));
1191
0
    if (!newBuf) {
1192
0
      return false;
1193
0
    }
1194
0
    memcpy(newBuf, charBuffer, sizeof(char16_t) * size_t(charBufferLen));
1195
0
    charBuffer = newBuf;
1196
0
  }
1197
0
  return true;
1198
0
}
1199
1200
nsIContentHandle*
1201
nsHtml5TreeBuilder::AllocateContentHandle()
1202
0
{
1203
0
  if (MOZ_UNLIKELY(mBuilder)) {
1204
0
    MOZ_ASSERT_UNREACHABLE("Must never allocate a handle with builder.");
1205
0
    return nullptr;
1206
0
  }
1207
0
  if (mHandlesUsed == NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH) {
1208
0
    mOldHandles.AppendElement(std::move(mHandles));
1209
0
    mHandles = mozilla::MakeUnique<nsIContent* []>(
1210
0
      NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH);
1211
0
    mHandlesUsed = 0;
1212
0
  }
1213
#ifdef DEBUG
1214
  mHandles[mHandlesUsed] = reinterpret_cast<nsIContent*>(uintptr_t(0xC0DEDBAD));
1215
#endif
1216
  return &mHandles[mHandlesUsed++];
1217
0
}
1218
1219
bool
1220
nsHtml5TreeBuilder::HasScript()
1221
0
{
1222
0
  uint32_t len = mOpQueue.Length();
1223
0
  if (!len) {
1224
0
    return false;
1225
0
  }
1226
0
  return mOpQueue.ElementAt(len - 1).IsRunScript();
1227
0
}
1228
1229
bool
1230
nsHtml5TreeBuilder::Flush(bool aDiscretionary)
1231
0
{
1232
0
  if (MOZ_UNLIKELY(mBuilder)) {
1233
0
    MOZ_ASSERT_UNREACHABLE("Must never flush with builder.");
1234
0
    return false;
1235
0
  }
1236
0
  if (NS_SUCCEEDED(mBroken)) {
1237
0
    if (!aDiscretionary || !(charBufferLen && currentPtr >= 0 &&
1238
0
                             stack[currentPtr]->isFosterParenting())) {
1239
0
      // Don't flush text on discretionary flushes if the current element on
1240
0
      // the stack is a foster-parenting element and there's pending text,
1241
0
      // because flushing in that case would make the tree shape dependent on
1242
0
      // where the flush points fall.
1243
0
      flushCharacters();
1244
0
    }
1245
0
    FlushLoads();
1246
0
  }
1247
0
  if (mOpSink) {
1248
0
    bool hasOps = !mOpQueue.IsEmpty();
1249
0
    if (hasOps) {
1250
0
      // If the builder is broken and mOpQueue is not empty, there must be
1251
0
      // one op and it must be eTreeOpMarkAsBroken.
1252
0
      if (NS_FAILED(mBroken)) {
1253
0
        MOZ_ASSERT(mOpQueue.Length() == 1,
1254
0
                   "Tree builder is broken with a non-empty op queue whose "
1255
0
                   "length isn't 1.");
1256
0
        MOZ_ASSERT(mOpQueue[0].IsMarkAsBroken(),
1257
0
                   "Tree builder is broken but the op in queue is not marked "
1258
0
                   "as broken.");
1259
0
      }
1260
0
      mOpSink->MoveOpsFrom(mOpQueue);
1261
0
    }
1262
0
    return hasOps;
1263
0
  }
1264
0
  // no op sink: throw away ops
1265
0
  mOpQueue.Clear();
1266
0
  return false;
1267
0
}
1268
1269
void
1270
nsHtml5TreeBuilder::FlushLoads()
1271
0
{
1272
0
  if (MOZ_UNLIKELY(mBuilder)) {
1273
0
    MOZ_ASSERT_UNREACHABLE("Must never flush loads with builder.");
1274
0
    return;
1275
0
  }
1276
0
  if (!mSpeculativeLoadQueue.IsEmpty()) {
1277
0
    mSpeculativeLoadStage->MoveSpeculativeLoadsFrom(mSpeculativeLoadQueue);
1278
0
  }
1279
0
}
1280
1281
void
1282
nsHtml5TreeBuilder::SetDocumentCharset(NotNull<const Encoding*> aEncoding,
1283
                                       int32_t aCharsetSource)
1284
0
{
1285
0
  if (mBuilder) {
1286
0
    mBuilder->SetDocumentCharsetAndSource(aEncoding, aCharsetSource);
1287
0
  } else if (mSpeculativeLoadStage) {
1288
0
    mSpeculativeLoadQueue.AppendElement()->InitSetDocumentCharset(
1289
0
      aEncoding, aCharsetSource);
1290
0
  } else {
1291
0
    mOpQueue.AppendElement()->Init(
1292
0
      eTreeOpSetDocumentCharset, aEncoding, aCharsetSource);
1293
0
  }
1294
0
}
1295
1296
void
1297
nsHtml5TreeBuilder::StreamEnded()
1298
0
{
1299
0
  MOZ_ASSERT(!mBuilder, "Must not call StreamEnded with builder.");
1300
0
  MOZ_ASSERT(!fragment, "Must not parse fragments off the main thread.");
1301
0
  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
1302
0
  if (MOZ_UNLIKELY(!treeOp)) {
1303
0
    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
1304
0
    return;
1305
0
  }
1306
0
  treeOp->Init(eTreeOpStreamEnded);
1307
0
}
1308
1309
void
1310
nsHtml5TreeBuilder::NeedsCharsetSwitchTo(NotNull<const Encoding*> aEncoding,
1311
                                         int32_t aCharsetSource,
1312
                                         int32_t aLineNumber)
1313
0
{
1314
0
  if (MOZ_UNLIKELY(mBuilder)) {
1315
0
    MOZ_ASSERT_UNREACHABLE("Must never switch charset with builder.");
1316
0
    return;
1317
0
  }
1318
0
  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
1319
0
  if (MOZ_UNLIKELY(!treeOp)) {
1320
0
    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
1321
0
    return;
1322
0
  }
1323
0
  treeOp->Init(
1324
0
    eTreeOpNeedsCharsetSwitchTo, aEncoding, aCharsetSource, aLineNumber);
1325
0
}
1326
1327
void
1328
nsHtml5TreeBuilder::MaybeComplainAboutCharset(const char* aMsgId,
1329
                                              bool aError,
1330
                                              int32_t aLineNumber)
1331
0
{
1332
0
  if (MOZ_UNLIKELY(mBuilder)) {
1333
0
    MOZ_ASSERT_UNREACHABLE("Must never complain about charset with builder.");
1334
0
    return;
1335
0
  }
1336
0
  mOpQueue.AppendElement()->Init(aMsgId, aError, aLineNumber);
1337
0
}
1338
1339
void
1340
nsHtml5TreeBuilder::TryToEnableEncodingMenu()
1341
0
{
1342
0
  if (MOZ_UNLIKELY(mBuilder)) {
1343
0
    MOZ_ASSERT_UNREACHABLE("Must never disable encoding menu with builder.");
1344
0
    return;
1345
0
  }
1346
0
  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
1347
0
  NS_ASSERTION(treeOp, "Tree op allocation failed.");
1348
0
  treeOp->Init(eTreeOpEnableEncodingMenu);
1349
0
}
1350
1351
void
1352
nsHtml5TreeBuilder::AddSnapshotToScript(nsAHtml5TreeBuilderState* aSnapshot,
1353
                                        int32_t aLine)
1354
0
{
1355
0
  if (MOZ_UNLIKELY(mBuilder)) {
1356
0
    MOZ_ASSERT_UNREACHABLE("Must never use snapshots with builder.");
1357
0
    return;
1358
0
  }
1359
0
  MOZ_ASSERT(HasScript(), "No script to add a snapshot to!");
1360
0
  MOZ_ASSERT(aSnapshot, "Got null snapshot.");
1361
0
  mOpQueue.ElementAt(mOpQueue.Length() - 1).SetSnapshot(aSnapshot, aLine);
1362
0
}
1363
1364
void
1365
nsHtml5TreeBuilder::DropHandles()
1366
0
{
1367
0
  MOZ_ASSERT(!mBuilder, "Must not drop handles with builder.");
1368
0
  mOldHandles.Clear();
1369
0
  mHandlesUsed = 0;
1370
0
}
1371
1372
void
1373
nsHtml5TreeBuilder::MarkAsBroken(nsresult aRv)
1374
0
{
1375
0
  if (MOZ_UNLIKELY(mBuilder)) {
1376
0
    MOZ_ASSERT_UNREACHABLE("Must not call this with builder.");
1377
0
    return;
1378
0
  }
1379
0
  mBroken = aRv;
1380
0
  mOpQueue.Clear(); // Previous ops don't matter anymore
1381
0
  mOpQueue.AppendElement()->Init(aRv);
1382
0
}
1383
1384
void
1385
nsHtml5TreeBuilder::MarkAsBrokenFromPortability(nsresult aRv)
1386
0
{
1387
0
  if (mBuilder) {
1388
0
    MarkAsBrokenAndRequestSuspensionWithBuilder(aRv);
1389
0
    return;
1390
0
  }
1391
0
  mBroken = aRv;
1392
0
  requestSuspension();
1393
0
}
1394
1395
void
1396
nsHtml5TreeBuilder::StartPlainTextViewSource(const nsAutoString& aTitle)
1397
0
{
1398
0
  MOZ_ASSERT(!mBuilder, "Must not view source with builder.");
1399
0
1400
0
  startTag(nsHtml5ElementName::ELT_META,
1401
0
           nsHtml5ViewSourceUtils::NewMetaViewportAttributes(),
1402
0
           false);
1403
0
1404
0
  startTag(nsHtml5ElementName::ELT_TITLE,
1405
0
           nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES,
1406
0
           false);
1407
0
1408
0
  // XUL will add the "Source of: " prefix.
1409
0
  uint32_t length = aTitle.Length();
1410
0
  if (length > INT32_MAX) {
1411
0
    length = INT32_MAX;
1412
0
  }
1413
0
  characters(aTitle.get(), 0, (int32_t)length);
1414
0
  endTag(nsHtml5ElementName::ELT_TITLE);
1415
0
1416
0
  startTag(nsHtml5ElementName::ELT_LINK,
1417
0
           nsHtml5ViewSourceUtils::NewLinkAttributes(),
1418
0
           false);
1419
0
1420
0
  startTag(nsHtml5ElementName::ELT_BODY,
1421
0
           nsHtml5ViewSourceUtils::NewBodyAttributes(),
1422
0
           false);
1423
0
1424
0
  StartPlainTextBody();
1425
0
}
1426
1427
void
1428
nsHtml5TreeBuilder::StartPlainText()
1429
0
{
1430
0
  MOZ_ASSERT(!mBuilder, "Must not view source with builder.");
1431
0
  startTag(nsHtml5ElementName::ELT_LINK,
1432
0
           nsHtml5PlainTextUtils::NewLinkAttributes(),
1433
0
           false);
1434
0
1435
0
  StartPlainTextBody();
1436
0
}
1437
1438
void
1439
nsHtml5TreeBuilder::StartPlainTextBody()
1440
0
{
1441
0
  MOZ_ASSERT(!mBuilder, "Must not view source with builder.");
1442
0
  startTag(nsHtml5ElementName::ELT_PRE,
1443
0
           nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES,
1444
0
           false);
1445
0
  needToDropLF = false;
1446
0
}
1447
1448
// DocumentModeHandler
1449
void
1450
nsHtml5TreeBuilder::documentMode(nsHtml5DocumentMode m)
1451
0
{
1452
0
  if (mBuilder) {
1453
0
    mBuilder->SetDocumentMode(m);
1454
0
    return;
1455
0
  }
1456
0
  if (mSpeculativeLoadStage) {
1457
0
    mSpeculativeLoadQueue.AppendElement()->InitSetDocumentMode(m);
1458
0
    return;
1459
0
  }
1460
0
  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
1461
0
  if (MOZ_UNLIKELY(!treeOp)) {
1462
0
    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
1463
0
    return;
1464
0
  }
1465
0
  treeOp->Init(m);
1466
0
}
1467
1468
nsIContentHandle*
1469
nsHtml5TreeBuilder::getDocumentFragmentForTemplate(nsIContentHandle* aTemplate)
1470
0
{
1471
0
  if (mBuilder) {
1472
0
    return nsHtml5TreeOperation::GetDocumentFragmentForTemplate(
1473
0
      static_cast<nsIContent*>(aTemplate));
1474
0
  }
1475
0
  nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible);
1476
0
  if (MOZ_UNLIKELY(!treeOp)) {
1477
0
    MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY);
1478
0
    return nullptr;
1479
0
  }
1480
0
  nsIContentHandle* fragHandle = AllocateContentHandle();
1481
0
  treeOp->Init(eTreeOpGetDocumentFragmentForTemplate, aTemplate, fragHandle);
1482
0
  return fragHandle;
1483
0
}
1484
1485
nsIContentHandle*
1486
nsHtml5TreeBuilder::getFormPointerForContext(nsIContentHandle* aContext)
1487
0
{
1488
0
  MOZ_ASSERT(mBuilder, "Must have builder.");
1489
0
  if (!aContext) {
1490
0
    return nullptr;
1491
0
  }
1492
0
1493
0
  MOZ_ASSERT(NS_IsMainThread());
1494
0
1495
0
  // aContext must always be an element that already exists
1496
0
  // in the document.
1497
0
  nsIContent* contextNode = static_cast<nsIContent*>(aContext);
1498
0
  nsIContent* currentAncestor = contextNode;
1499
0
1500
0
  // We traverse the ancestors of the context node to find the nearest
1501
0
  // form pointer. This traversal is why aContext must not be an emtpy handle.
1502
0
  nsIContent* nearestForm = nullptr;
1503
0
  while (currentAncestor) {
1504
0
    if (currentAncestor->IsHTMLElement(nsGkAtoms::form)) {
1505
0
      nearestForm = currentAncestor;
1506
0
      break;
1507
0
    }
1508
0
    currentAncestor = currentAncestor->GetParent();
1509
0
  }
1510
0
1511
0
  if (!nearestForm) {
1512
0
    return nullptr;
1513
0
  }
1514
0
1515
0
  return nearestForm;
1516
0
}
1517
1518
// Error reporting
1519
1520
void
1521
nsHtml5TreeBuilder::EnableViewSource(nsHtml5Highlighter* aHighlighter)
1522
0
{
1523
0
  MOZ_ASSERT(!mBuilder, "Must not view source with builder.");
1524
0
  mViewSource = aHighlighter;
1525
0
}
1526
1527
void
1528
nsHtml5TreeBuilder::errStrayStartTag(nsAtom* aName)
1529
0
{
1530
0
  if (MOZ_UNLIKELY(mViewSource)) {
1531
0
    mViewSource->AddErrorToCurrentRun("errStrayStartTag2", aName);
1532
0
  }
1533
0
}
1534
1535
void
1536
nsHtml5TreeBuilder::errStrayEndTag(nsAtom* aName)
1537
0
{
1538
0
  if (MOZ_UNLIKELY(mViewSource)) {
1539
0
    mViewSource->AddErrorToCurrentRun("errStrayEndTag", aName);
1540
0
  }
1541
0
}
1542
1543
void
1544
nsHtml5TreeBuilder::errUnclosedElements(int32_t aIndex, nsAtom* aName)
1545
0
{
1546
0
  if (MOZ_UNLIKELY(mViewSource)) {
1547
0
    mViewSource->AddErrorToCurrentRun("errUnclosedElements", aName);
1548
0
  }
1549
0
}
1550
1551
void
1552
nsHtml5TreeBuilder::errUnclosedElementsImplied(int32_t aIndex, nsAtom* aName)
1553
0
{
1554
0
  if (MOZ_UNLIKELY(mViewSource)) {
1555
0
    mViewSource->AddErrorToCurrentRun("errUnclosedElementsImplied", aName);
1556
0
  }
1557
0
}
1558
1559
void
1560
nsHtml5TreeBuilder::errUnclosedElementsCell(int32_t aIndex)
1561
0
{
1562
0
  if (MOZ_UNLIKELY(mViewSource)) {
1563
0
    mViewSource->AddErrorToCurrentRun("errUnclosedElementsCell");
1564
0
  }
1565
0
}
1566
1567
void
1568
nsHtml5TreeBuilder::errStrayDoctype()
1569
0
{
1570
0
  if (MOZ_UNLIKELY(mViewSource)) {
1571
0
    mViewSource->AddErrorToCurrentRun("errStrayDoctype");
1572
0
  }
1573
0
}
1574
1575
void
1576
nsHtml5TreeBuilder::errAlmostStandardsDoctype()
1577
0
{
1578
0
  if (MOZ_UNLIKELY(mViewSource) && !isSrcdocDocument) {
1579
0
    mViewSource->AddErrorToCurrentRun("errAlmostStandardsDoctype");
1580
0
  }
1581
0
}
1582
1583
void
1584
nsHtml5TreeBuilder::errQuirkyDoctype()
1585
0
{
1586
0
  if (MOZ_UNLIKELY(mViewSource) && !isSrcdocDocument) {
1587
0
    mViewSource->AddErrorToCurrentRun("errQuirkyDoctype");
1588
0
  }
1589
0
}
1590
1591
void
1592
nsHtml5TreeBuilder::errNonSpaceInTrailer()
1593
0
{
1594
0
  if (MOZ_UNLIKELY(mViewSource)) {
1595
0
    mViewSource->AddErrorToCurrentRun("errNonSpaceInTrailer");
1596
0
  }
1597
0
}
1598
1599
void
1600
nsHtml5TreeBuilder::errNonSpaceAfterFrameset()
1601
0
{
1602
0
  if (MOZ_UNLIKELY(mViewSource)) {
1603
0
    mViewSource->AddErrorToCurrentRun("errNonSpaceAfterFrameset");
1604
0
  }
1605
0
}
1606
1607
void
1608
nsHtml5TreeBuilder::errNonSpaceInFrameset()
1609
0
{
1610
0
  if (MOZ_UNLIKELY(mViewSource)) {
1611
0
    mViewSource->AddErrorToCurrentRun("errNonSpaceInFrameset");
1612
0
  }
1613
0
}
1614
1615
void
1616
nsHtml5TreeBuilder::errNonSpaceAfterBody()
1617
0
{
1618
0
  if (MOZ_UNLIKELY(mViewSource)) {
1619
0
    mViewSource->AddErrorToCurrentRun("errNonSpaceAfterBody");
1620
0
  }
1621
0
}
1622
1623
void
1624
nsHtml5TreeBuilder::errNonSpaceInColgroupInFragment()
1625
0
{
1626
0
  if (MOZ_UNLIKELY(mViewSource)) {
1627
0
    mViewSource->AddErrorToCurrentRun("errNonSpaceInColgroupInFragment");
1628
0
  }
1629
0
}
1630
1631
void
1632
nsHtml5TreeBuilder::errNonSpaceInNoscriptInHead()
1633
0
{
1634
0
  if (MOZ_UNLIKELY(mViewSource)) {
1635
0
    mViewSource->AddErrorToCurrentRun("errNonSpaceInNoscriptInHead");
1636
0
  }
1637
0
}
1638
1639
void
1640
nsHtml5TreeBuilder::errFooBetweenHeadAndBody(nsAtom* aName)
1641
0
{
1642
0
  if (MOZ_UNLIKELY(mViewSource)) {
1643
0
    mViewSource->AddErrorToCurrentRun("errFooBetweenHeadAndBody", aName);
1644
0
  }
1645
0
}
1646
1647
void
1648
nsHtml5TreeBuilder::errStartTagWithoutDoctype()
1649
0
{
1650
0
  if (MOZ_UNLIKELY(mViewSource) && !isSrcdocDocument) {
1651
0
    mViewSource->AddErrorToCurrentRun("errStartTagWithoutDoctype");
1652
0
  }
1653
0
}
1654
1655
void
1656
nsHtml5TreeBuilder::errNoSelectInTableScope()
1657
0
{
1658
0
  if (MOZ_UNLIKELY(mViewSource)) {
1659
0
    mViewSource->AddErrorToCurrentRun("errNoSelectInTableScope");
1660
0
  }
1661
0
}
1662
1663
void
1664
nsHtml5TreeBuilder::errStartSelectWhereEndSelectExpected()
1665
0
{
1666
0
  if (MOZ_UNLIKELY(mViewSource)) {
1667
0
    mViewSource->AddErrorToCurrentRun("errStartSelectWhereEndSelectExpected");
1668
0
  }
1669
0
}
1670
1671
void
1672
nsHtml5TreeBuilder::errStartTagWithSelectOpen(nsAtom* aName)
1673
0
{
1674
0
  if (MOZ_UNLIKELY(mViewSource)) {
1675
0
    mViewSource->AddErrorToCurrentRun("errStartTagWithSelectOpen", aName);
1676
0
  }
1677
0
}
1678
1679
void
1680
nsHtml5TreeBuilder::errBadStartTagInHead(nsAtom* aName)
1681
0
{
1682
0
  if (MOZ_UNLIKELY(mViewSource)) {
1683
0
    mViewSource->AddErrorToCurrentRun("errBadStartTagInHead2", aName);
1684
0
  }
1685
0
}
1686
1687
void
1688
nsHtml5TreeBuilder::errImage()
1689
0
{
1690
0
  if (MOZ_UNLIKELY(mViewSource)) {
1691
0
    mViewSource->AddErrorToCurrentRun("errImage");
1692
0
  }
1693
0
}
1694
1695
void
1696
nsHtml5TreeBuilder::errIsindex()
1697
0
{
1698
0
  if (MOZ_UNLIKELY(mViewSource)) {
1699
0
    mViewSource->AddErrorToCurrentRun("errIsindex");
1700
0
  }
1701
0
}
1702
1703
void
1704
nsHtml5TreeBuilder::errFooSeenWhenFooOpen(nsAtom* aName)
1705
0
{
1706
0
  if (MOZ_UNLIKELY(mViewSource)) {
1707
0
    mViewSource->AddErrorToCurrentRun("errFooSeenWhenFooOpen", aName);
1708
0
  }
1709
0
}
1710
1711
void
1712
nsHtml5TreeBuilder::errHeadingWhenHeadingOpen()
1713
0
{
1714
0
  if (MOZ_UNLIKELY(mViewSource)) {
1715
0
    mViewSource->AddErrorToCurrentRun("errHeadingWhenHeadingOpen");
1716
0
  }
1717
0
}
1718
1719
void
1720
nsHtml5TreeBuilder::errFramesetStart()
1721
0
{
1722
0
  if (MOZ_UNLIKELY(mViewSource)) {
1723
0
    mViewSource->AddErrorToCurrentRun("errFramesetStart");
1724
0
  }
1725
0
}
1726
1727
void
1728
nsHtml5TreeBuilder::errNoCellToClose()
1729
0
{
1730
0
  if (MOZ_UNLIKELY(mViewSource)) {
1731
0
    mViewSource->AddErrorToCurrentRun("errNoCellToClose");
1732
0
  }
1733
0
}
1734
1735
void
1736
nsHtml5TreeBuilder::errStartTagInTable(nsAtom* aName)
1737
0
{
1738
0
  if (MOZ_UNLIKELY(mViewSource)) {
1739
0
    mViewSource->AddErrorToCurrentRun("errStartTagInTable", aName);
1740
0
  }
1741
0
}
1742
1743
void
1744
nsHtml5TreeBuilder::errFormWhenFormOpen()
1745
0
{
1746
0
  if (MOZ_UNLIKELY(mViewSource)) {
1747
0
    mViewSource->AddErrorToCurrentRun("errFormWhenFormOpen");
1748
0
  }
1749
0
}
1750
1751
void
1752
nsHtml5TreeBuilder::errTableSeenWhileTableOpen()
1753
0
{
1754
0
  if (MOZ_UNLIKELY(mViewSource)) {
1755
0
    mViewSource->AddErrorToCurrentRun("errTableSeenWhileTableOpen");
1756
0
  }
1757
0
}
1758
1759
void
1760
nsHtml5TreeBuilder::errStartTagInTableBody(nsAtom* aName)
1761
0
{
1762
0
  if (MOZ_UNLIKELY(mViewSource)) {
1763
0
    mViewSource->AddErrorToCurrentRun("errStartTagInTableBody", aName);
1764
0
  }
1765
0
}
1766
1767
void
1768
nsHtml5TreeBuilder::errEndTagSeenWithoutDoctype()
1769
0
{
1770
0
  if (MOZ_UNLIKELY(mViewSource) && !isSrcdocDocument) {
1771
0
    mViewSource->AddErrorToCurrentRun("errEndTagSeenWithoutDoctype");
1772
0
  }
1773
0
}
1774
1775
void
1776
nsHtml5TreeBuilder::errEndTagAfterBody()
1777
0
{
1778
0
  if (MOZ_UNLIKELY(mViewSource)) {
1779
0
    mViewSource->AddErrorToCurrentRun("errEndTagAfterBody");
1780
0
  }
1781
0
}
1782
1783
void
1784
nsHtml5TreeBuilder::errEndTagSeenWithSelectOpen(nsAtom* aName)
1785
0
{
1786
0
  if (MOZ_UNLIKELY(mViewSource)) {
1787
0
    mViewSource->AddErrorToCurrentRun("errEndTagSeenWithSelectOpen", aName);
1788
0
  }
1789
0
}
1790
1791
void
1792
nsHtml5TreeBuilder::errGarbageInColgroup()
1793
0
{
1794
0
  if (MOZ_UNLIKELY(mViewSource)) {
1795
0
    mViewSource->AddErrorToCurrentRun("errGarbageInColgroup");
1796
0
  }
1797
0
}
1798
1799
void
1800
nsHtml5TreeBuilder::errEndTagBr()
1801
0
{
1802
0
  if (MOZ_UNLIKELY(mViewSource)) {
1803
0
    mViewSource->AddErrorToCurrentRun("errEndTagBr");
1804
0
  }
1805
0
}
1806
1807
void
1808
nsHtml5TreeBuilder::errNoElementToCloseButEndTagSeen(nsAtom* aName)
1809
0
{
1810
0
  if (MOZ_UNLIKELY(mViewSource)) {
1811
0
    mViewSource->AddErrorToCurrentRun("errNoElementToCloseButEndTagSeen",
1812
0
                                      aName);
1813
0
  }
1814
0
}
1815
1816
void
1817
nsHtml5TreeBuilder::errHtmlStartTagInForeignContext(nsAtom* aName)
1818
0
{
1819
0
  if (MOZ_UNLIKELY(mViewSource)) {
1820
0
    mViewSource->AddErrorToCurrentRun("errHtmlStartTagInForeignContext", aName);
1821
0
  }
1822
0
}
1823
1824
void
1825
nsHtml5TreeBuilder::errTableClosedWhileCaptionOpen()
1826
0
{
1827
0
  if (MOZ_UNLIKELY(mViewSource)) {
1828
0
    mViewSource->AddErrorToCurrentRun("errTableClosedWhileCaptionOpen");
1829
0
  }
1830
0
}
1831
1832
void
1833
nsHtml5TreeBuilder::errNoTableRowToClose()
1834
0
{
1835
0
  if (MOZ_UNLIKELY(mViewSource)) {
1836
0
    mViewSource->AddErrorToCurrentRun("errNoTableRowToClose");
1837
0
  }
1838
0
}
1839
1840
void
1841
nsHtml5TreeBuilder::errNonSpaceInTable()
1842
0
{
1843
0
  if (MOZ_UNLIKELY(mViewSource)) {
1844
0
    mViewSource->AddErrorToCurrentRun("errNonSpaceInTable");
1845
0
  }
1846
0
}
1847
1848
void
1849
nsHtml5TreeBuilder::errUnclosedChildrenInRuby()
1850
0
{
1851
0
  if (MOZ_UNLIKELY(mViewSource)) {
1852
0
    mViewSource->AddErrorToCurrentRun("errUnclosedChildrenInRuby");
1853
0
  }
1854
0
}
1855
1856
void
1857
nsHtml5TreeBuilder::errStartTagSeenWithoutRuby(nsAtom* aName)
1858
0
{
1859
0
  if (MOZ_UNLIKELY(mViewSource)) {
1860
0
    mViewSource->AddErrorToCurrentRun("errStartTagSeenWithoutRuby", aName);
1861
0
  }
1862
0
}
1863
1864
void
1865
nsHtml5TreeBuilder::errSelfClosing()
1866
0
{
1867
0
  if (MOZ_UNLIKELY(mViewSource)) {
1868
0
    mViewSource->AddErrorToCurrentSlash("errSelfClosing");
1869
0
  }
1870
0
}
1871
1872
void
1873
nsHtml5TreeBuilder::errNoCheckUnclosedElementsOnStack()
1874
0
{
1875
0
  if (MOZ_UNLIKELY(mViewSource)) {
1876
0
    mViewSource->AddErrorToCurrentRun("errNoCheckUnclosedElementsOnStack");
1877
0
  }
1878
0
}
1879
1880
void
1881
nsHtml5TreeBuilder::errEndTagDidNotMatchCurrentOpenElement(nsAtom* aName,
1882
                                                           nsAtom* aOther)
1883
0
{
1884
0
  if (MOZ_UNLIKELY(mViewSource)) {
1885
0
    mViewSource->AddErrorToCurrentRun(
1886
0
      "errEndTagDidNotMatchCurrentOpenElement", aName, aOther);
1887
0
  }
1888
0
}
1889
1890
void
1891
nsHtml5TreeBuilder::errEndTagViolatesNestingRules(nsAtom* aName)
1892
0
{
1893
0
  if (MOZ_UNLIKELY(mViewSource)) {
1894
0
    mViewSource->AddErrorToCurrentRun("errEndTagViolatesNestingRules", aName);
1895
0
  }
1896
0
}
1897
1898
void
1899
nsHtml5TreeBuilder::errEndWithUnclosedElements(nsAtom* aName)
1900
0
{
1901
0
  if (MOZ_UNLIKELY(mViewSource)) {
1902
0
    mViewSource->AddErrorToCurrentRun("errEndWithUnclosedElements", aName);
1903
0
  }
1904
0
}