Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/parser/html/nsHtml5TreeOperation.cpp
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 "nsHtml5TreeOperation.h"
8
#include "mozAutoDocUpdate.h"
9
#include "mozilla/Likely.h"
10
#include "mozilla/Services.h"
11
#include "mozilla/dom/Comment.h"
12
#include "mozilla/dom/DocumentType.h"
13
#include "mozilla/dom/Element.h"
14
#include "mozilla/dom/HTMLFormElement.h"
15
#include "mozilla/dom/HTMLImageElement.h"
16
#include "mozilla/dom/HTMLTemplateElement.h"
17
#include "mozilla/dom/Text.h"
18
#include "nsAttrName.h"
19
#include "nsBindingManager.h"
20
#include "nsContentCreatorFunctions.h"
21
#include "nsContentUtils.h"
22
#include "nsDocElementCreatedNotificationRunner.h"
23
#include "nsEscape.h"
24
#include "nsHtml5AutoPauseUpdate.h"
25
#include "nsHtml5DocumentMode.h"
26
#include "nsHtml5HtmlAttributes.h"
27
#include "nsHtml5SVGLoadDispatcher.h"
28
#include "nsHtml5TreeBuilder.h"
29
#include "nsIDTD.h"
30
#include "nsIFormControl.h"
31
#include "nsIFormProcessor.h"
32
#include "nsIHTMLDocument.h"
33
#include "nsIMutationObserver.h"
34
#include "nsINode.h"
35
#include "nsIObserverService.h"
36
#include "nsIProtocolHandler.h"
37
#include "nsIScriptElement.h"
38
#include "nsIServiceManager.h"
39
#include "nsIStyleSheetLinkingElement.h"
40
#include "nsISupportsImpl.h"
41
#include "nsIURI.h"
42
#include "nsNetUtil.h"
43
#include "nsNodeUtils.h"
44
#include "nsTextNode.h"
45
#include "nsXBLBinding.h"
46
47
using namespace mozilla;
48
49
static NS_DEFINE_CID(kFormProcessorCID, NS_FORMPROCESSOR_CID);
50
51
/**
52
 * Helper class that opens a notification batch if the current doc
53
 * is different from the executor doc.
54
 */
55
class MOZ_STACK_CLASS nsHtml5OtherDocUpdate
56
{
57
public:
58
  nsHtml5OtherDocUpdate(nsIDocument* aCurrentDoc, nsIDocument* aExecutorDoc)
59
0
  {
60
0
    MOZ_ASSERT(aCurrentDoc, "Node has no doc?");
61
0
    MOZ_ASSERT(aExecutorDoc, "Executor has no doc?");
62
0
    if (MOZ_LIKELY(aCurrentDoc == aExecutorDoc)) {
63
0
      mDocument = nullptr;
64
0
    } else {
65
0
      mDocument = aCurrentDoc;
66
0
      aCurrentDoc->BeginUpdate();
67
0
    }
68
0
  }
69
70
  ~nsHtml5OtherDocUpdate()
71
0
  {
72
0
    if (MOZ_UNLIKELY(mDocument)) {
73
0
      mDocument->EndUpdate();
74
0
    }
75
0
  }
76
77
private:
78
  nsCOMPtr<nsIDocument> mDocument;
79
};
80
81
nsHtml5TreeOperation::nsHtml5TreeOperation()
82
  : mOpCode(eTreeOpUninitialized)
83
  , mOne{}
84
  , mTwo{}
85
  , mThree{}
86
  , mFour{}
87
  , mFive{}
88
0
{
89
0
  MOZ_COUNT_CTOR(nsHtml5TreeOperation);
90
0
}
91
92
nsHtml5TreeOperation::~nsHtml5TreeOperation()
93
0
{
94
0
  MOZ_COUNT_DTOR(nsHtml5TreeOperation);
95
0
  NS_ASSERTION(mOpCode != eTreeOpUninitialized, "Uninitialized tree op.");
96
0
  switch (mOpCode) {
97
0
    case eTreeOpAddAttributes:
98
0
      delete mTwo.attributes;
99
0
      break;
100
0
    case eTreeOpCreateHTMLElementNetwork:
101
0
    case eTreeOpCreateHTMLElementNotNetwork:
102
0
    case eTreeOpCreateSVGElementNetwork:
103
0
    case eTreeOpCreateSVGElementNotNetwork:
104
0
    case eTreeOpCreateMathMLElement:
105
0
      delete mThree.attributes;
106
0
      break;
107
0
    case eTreeOpAppendDoctypeToDocument:
108
0
      delete mTwo.stringPair;
109
0
      break;
110
0
    case eTreeOpFosterParentText:
111
0
    case eTreeOpAppendText:
112
0
    case eTreeOpAppendComment:
113
0
    case eTreeOpAppendCommentToDocument:
114
0
    case eTreeOpAddViewSourceHref:
115
0
    case eTreeOpAddViewSourceBase:
116
0
      delete[] mTwo.unicharPtr;
117
0
      break;
118
0
    case eTreeOpSetDocumentCharset:
119
0
    case eTreeOpNeedsCharsetSwitchTo:
120
0
      break;
121
0
    case eTreeOpProcessOfflineManifest:
122
0
      free(mOne.unicharPtr);
123
0
      break;
124
0
    default: // keep the compiler happy
125
0
      break;
126
0
  }
127
0
}
128
129
nsresult
130
nsHtml5TreeOperation::AppendTextToTextNode(const char16_t* aBuffer,
131
                                           uint32_t aLength,
132
                                           dom::Text* aTextNode,
133
                                           nsHtml5DocumentBuilder* aBuilder)
134
0
{
135
0
  MOZ_ASSERT(aTextNode, "Got null text node.");
136
0
  MOZ_ASSERT(aBuilder);
137
0
  MOZ_ASSERT(aBuilder->IsInDocUpdate());
138
0
  uint32_t oldLength = aTextNode->TextLength();
139
0
  CharacterDataChangeInfo info = { true, oldLength, oldLength, aLength };
140
0
  nsNodeUtils::CharacterDataWillChange(aTextNode, info);
141
0
142
0
  nsresult rv = aTextNode->AppendText(aBuffer, aLength, false);
143
0
  NS_ENSURE_SUCCESS(rv, rv);
144
0
145
0
  nsNodeUtils::CharacterDataChanged(aTextNode, info);
146
0
  return rv;
147
0
}
148
149
nsresult
150
nsHtml5TreeOperation::AppendText(const char16_t* aBuffer,
151
                                 uint32_t aLength,
152
                                 nsIContent* aParent,
153
                                 nsHtml5DocumentBuilder* aBuilder)
154
0
{
155
0
  nsresult rv = NS_OK;
156
0
  nsIContent* lastChild = aParent->GetLastChild();
157
0
  if (lastChild && lastChild->IsText()) {
158
0
    nsHtml5OtherDocUpdate update(aParent->OwnerDoc(), aBuilder->GetDocument());
159
0
    return AppendTextToTextNode(aBuffer, aLength, lastChild->GetAsText(),
160
0
                                aBuilder);
161
0
  }
162
0
163
0
  nsNodeInfoManager* nodeInfoManager = aParent->OwnerDoc()->NodeInfoManager();
164
0
  RefPtr<nsTextNode> text = new nsTextNode(nodeInfoManager);
165
0
  NS_ASSERTION(text, "Infallible malloc failed?");
166
0
  rv = text->SetText(aBuffer, aLength, false);
167
0
  NS_ENSURE_SUCCESS(rv, rv);
168
0
169
0
  return Append(text, aParent, aBuilder);
170
0
}
171
172
nsresult
173
nsHtml5TreeOperation::Append(nsIContent* aNode,
174
                             nsIContent* aParent,
175
                             nsHtml5DocumentBuilder* aBuilder)
176
0
{
177
0
  MOZ_ASSERT(aBuilder);
178
0
  MOZ_ASSERT(aBuilder->IsInDocUpdate());
179
0
  nsresult rv = NS_OK;
180
0
  nsHtml5OtherDocUpdate update(aParent->OwnerDoc(), aBuilder->GetDocument());
181
0
  rv = aParent->AppendChildTo(aNode, false);
182
0
  if (NS_SUCCEEDED(rv)) {
183
0
    aNode->SetParserHasNotified();
184
0
    nsNodeUtils::ContentAppended(aParent, aNode);
185
0
  }
186
0
  return rv;
187
0
}
188
189
nsresult
190
nsHtml5TreeOperation::AppendToDocument(nsIContent* aNode,
191
                                       nsHtml5DocumentBuilder* aBuilder)
192
0
{
193
0
  MOZ_ASSERT(aBuilder);
194
0
  MOZ_ASSERT(aBuilder->GetDocument() == aNode->OwnerDoc());
195
0
  MOZ_ASSERT(aBuilder->IsInDocUpdate());
196
0
  nsresult rv = NS_OK;
197
0
198
0
  nsIDocument* doc = aBuilder->GetDocument();
199
0
  rv = doc->AppendChildTo(aNode, false);
200
0
  if (rv == NS_ERROR_DOM_HIERARCHY_REQUEST_ERR) {
201
0
    aNode->SetParserHasNotified();
202
0
    return NS_OK;
203
0
  }
204
0
  NS_ENSURE_SUCCESS(rv, rv);
205
0
  aNode->SetParserHasNotified();
206
0
  nsNodeUtils::ContentInserted(doc, aNode);
207
0
208
0
  NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
209
0
               "Someone forgot to block scripts");
210
0
  if (aNode->IsElement()) {
211
0
    nsContentUtils::AddScriptRunner(
212
0
      new nsDocElementCreatedNotificationRunner(doc));
213
0
  }
214
0
  return rv;
215
0
}
216
217
static bool
218
IsElementOrTemplateContent(nsINode* aNode)
219
0
{
220
0
  if (aNode) {
221
0
    if (aNode->IsElement()) {
222
0
      return true;
223
0
    }
224
0
    if (aNode->IsDocumentFragment()) {
225
0
      // Check if the node is a template content.
226
0
      nsIContent* fragHost = aNode->AsDocumentFragment()->GetHost();
227
0
      if (fragHost && nsNodeUtils::IsTemplateElement(fragHost)) {
228
0
        return true;
229
0
      }
230
0
    }
231
0
  }
232
0
  return false;
233
0
}
234
235
void
236
nsHtml5TreeOperation::Detach(nsIContent* aNode,
237
                             nsHtml5DocumentBuilder* aBuilder)
238
0
{
239
0
  MOZ_ASSERT(aBuilder);
240
0
  MOZ_ASSERT(aBuilder->IsInDocUpdate());
241
0
  nsCOMPtr<nsINode> parent = aNode->GetParentNode();
242
0
  if (parent) {
243
0
    nsHtml5OtherDocUpdate update(parent->OwnerDoc(), aBuilder->GetDocument());
244
0
    parent->RemoveChildNode(aNode, true);
245
0
  }
246
0
}
247
248
nsresult
249
nsHtml5TreeOperation::AppendChildrenToNewParent(
250
  nsIContent* aNode,
251
  nsIContent* aParent,
252
  nsHtml5DocumentBuilder* aBuilder)
253
0
{
254
0
  MOZ_ASSERT(aBuilder);
255
0
  MOZ_ASSERT(aBuilder->IsInDocUpdate());
256
0
  nsHtml5OtherDocUpdate update(aParent->OwnerDoc(), aBuilder->GetDocument());
257
0
258
0
  bool didAppend = false;
259
0
  while (aNode->HasChildren()) {
260
0
    nsCOMPtr<nsIContent> child = aNode->GetFirstChild();
261
0
    aNode->RemoveChildNode(child, true);
262
0
    nsresult rv = aParent->AppendChildTo(child, false);
263
0
    NS_ENSURE_SUCCESS(rv, rv);
264
0
    didAppend = true;
265
0
  }
266
0
  if (didAppend) {
267
0
    nsNodeUtils::ContentAppended(aParent, aParent->GetLastChild());
268
0
  }
269
0
  return NS_OK;
270
0
}
271
272
nsresult
273
nsHtml5TreeOperation::FosterParent(nsIContent* aNode,
274
                                   nsIContent* aParent,
275
                                   nsIContent* aTable,
276
                                   nsHtml5DocumentBuilder* aBuilder)
277
0
{
278
0
  MOZ_ASSERT(aBuilder);
279
0
  MOZ_ASSERT(aBuilder->IsInDocUpdate());
280
0
  nsIContent* foster = aTable->GetParent();
281
0
282
0
  if (IsElementOrTemplateContent(foster)) {
283
0
284
0
    nsHtml5OtherDocUpdate update(foster->OwnerDoc(), aBuilder->GetDocument());
285
0
286
0
    nsresult rv = foster->InsertChildBefore(aNode, aTable, false);
287
0
    NS_ENSURE_SUCCESS(rv, rv);
288
0
    nsNodeUtils::ContentInserted(foster, aNode);
289
0
    return rv;
290
0
  }
291
0
292
0
  return Append(aNode, aParent, aBuilder);
293
0
}
294
295
nsresult
296
nsHtml5TreeOperation::AddAttributes(nsIContent* aNode,
297
                                    nsHtml5HtmlAttributes* aAttributes,
298
                                    nsHtml5DocumentBuilder* aBuilder)
299
0
{
300
0
  dom::Element* node = aNode->AsElement();
301
0
  nsHtml5OtherDocUpdate update(node->OwnerDoc(), aBuilder->GetDocument());
302
0
303
0
  int32_t len = aAttributes->getLength();
304
0
  for (int32_t i = len; i > 0;) {
305
0
    --i;
306
0
    // prefix doesn't need regetting. it is always null or a static atom
307
0
    // local name is never null
308
0
    RefPtr<nsAtom> localName = Reget(aAttributes->getLocalNameNoBoundsCheck(i));
309
0
    int32_t nsuri = aAttributes->getURINoBoundsCheck(i);
310
0
    if (!node->HasAttr(nsuri, localName)) {
311
0
      // prefix doesn't need regetting. it is always null or a static atom
312
0
      // local name is never null
313
0
      nsString value; // Not Auto, because using it to hold nsStringBuffer*
314
0
      aAttributes->getValueNoBoundsCheck(i).ToString(value);
315
0
      node->SetAttr(
316
0
        nsuri, localName, aAttributes->getPrefixNoBoundsCheck(i), value, true);
317
0
      // XXX what to do with nsresult?
318
0
    }
319
0
  }
320
0
  return NS_OK;
321
0
}
322
323
void
324
nsHtml5TreeOperation::SetHTMLElementAttributes(
325
  dom::Element* aElement,
326
  nsAtom* aName,
327
  nsHtml5HtmlAttributes* aAttributes)
328
0
{
329
0
  int32_t len = aAttributes->getLength();
330
0
  for (int32_t i = 0; i < len; i++) {
331
0
    nsHtml5String val = aAttributes->getValueNoBoundsCheck(i);
332
0
    nsAtom* klass = val.MaybeAsAtom();
333
0
    if (klass) {
334
0
      aElement->SetSingleClassFromParser(klass);
335
0
    } else {
336
0
      // prefix doesn't need regetting. it is always null or a static atom
337
0
      // local name is never null
338
0
      RefPtr<nsAtom> localName =
339
0
        Reget(aAttributes->getLocalNameNoBoundsCheck(i));
340
0
      RefPtr<nsAtom> prefix = aAttributes->getPrefixNoBoundsCheck(i);
341
0
      int32_t nsuri = aAttributes->getURINoBoundsCheck(i);
342
0
343
0
      nsString value; // Not Auto, because using it to hold nsStringBuffer*
344
0
      val.ToString(value);
345
0
      if (nsGkAtoms::a == aName && nsGkAtoms::name == localName) {
346
0
        // This is an HTML5-incompliant Geckoism.
347
0
        // Remove when fixing bug 582361
348
0
        NS_ConvertUTF16toUTF8 cname(value);
349
0
        NS_ConvertUTF8toUTF16 uv(nsUnescape(cname.BeginWriting()));
350
0
        aElement->SetAttr(nsuri, localName, prefix, uv, false);
351
0
      } else {
352
0
        aElement->SetAttr(nsuri, localName, prefix, value, false);
353
0
      }
354
0
    }
355
0
  }
356
0
}
357
358
nsIContent*
359
nsHtml5TreeOperation::CreateHTMLElement(
360
  nsAtom* aName,
361
  nsHtml5HtmlAttributes* aAttributes,
362
  mozilla::dom::FromParser aFromParser,
363
  nsNodeInfoManager* aNodeInfoManager,
364
  nsHtml5DocumentBuilder* aBuilder,
365
  mozilla::dom::HTMLContentCreatorFunction aCreator)
366
0
{
367
0
  bool isKeygen = (aName == nsGkAtoms::keygen);
368
0
  if (MOZ_UNLIKELY(isKeygen)) {
369
0
    aName = nsGkAtoms::select;
370
0
    aCreator = NS_NewHTMLSelectElement;
371
0
  }
372
0
373
0
  RefPtr<dom::NodeInfo> nodeInfo = aNodeInfoManager->GetNodeInfo(
374
0
    aName, nullptr, kNameSpaceID_XHTML, nsINode::ELEMENT_NODE);
375
0
  NS_ASSERTION(nodeInfo, "Got null nodeinfo.");
376
0
377
0
  dom::Element* newContent = nullptr;
378
0
  nsIDocument* document = nodeInfo->GetDocument();
379
0
  bool willExecuteScript = false;
380
0
  bool isCustomElement = false;
381
0
  RefPtr<nsAtom> isAtom;
382
0
  dom::CustomElementDefinition* definition = nullptr;
383
0
384
0
  // Avoid overhead by checking if custom elements pref is enabled or not.
385
0
  if (dom::CustomElementRegistry::IsCustomElementEnabled(document)) {
386
0
    if (aAttributes) {
387
0
      nsHtml5String is = aAttributes->getValue(nsHtml5AttributeName::ATTR_IS);
388
0
      if (is) {
389
0
        nsAutoString isValue;
390
0
        is.ToString(isValue);
391
0
        isAtom = NS_Atomize(isValue);
392
0
      }
393
0
    }
394
0
395
0
    isCustomElement = (aCreator == NS_NewCustomElement || isAtom);
396
0
    if (isCustomElement && aFromParser != dom::FROM_PARSER_FRAGMENT) {
397
0
      RefPtr<nsAtom> tagAtom = nodeInfo->NameAtom();
398
0
      RefPtr<nsAtom> typeAtom =
399
0
        (aCreator == NS_NewCustomElement) ? tagAtom : isAtom;
400
0
401
0
      MOZ_ASSERT(nodeInfo->NameAtom()->Equals(nodeInfo->LocalName()));
402
0
      definition = nsContentUtils::LookupCustomElementDefinition(
403
0
        document, nodeInfo->NameAtom(), nodeInfo->NamespaceID(), typeAtom);
404
0
405
0
      if (definition) {
406
0
        willExecuteScript = true;
407
0
      }
408
0
    }
409
0
  }
410
0
411
0
  if (willExecuteScript) { // This will cause custom element constructors to run
412
0
    AutoSetThrowOnDynamicMarkupInsertionCounter
413
0
      throwOnDynamicMarkupInsertionCounter(document);
414
0
    nsHtml5AutoPauseUpdate autoPauseContentUpdate(aBuilder);
415
0
    {
416
0
      nsAutoMicroTask mt;
417
0
    }
418
0
    dom::AutoCEReaction autoCEReaction(
419
0
      document->GetDocGroup()->CustomElementReactionsStack(), nullptr);
420
0
421
0
    nsCOMPtr<dom::Element> newElement;
422
0
    NS_NewHTMLElement(getter_AddRefs(newElement),
423
0
                      nodeInfo.forget(),
424
0
                      aFromParser,
425
0
                      isAtom,
426
0
                      definition);
427
0
428
0
    MOZ_ASSERT(newElement, "Element creation created null pointer.");
429
0
    newContent = newElement;
430
0
    aBuilder->HoldElement(newElement.forget());
431
0
432
0
    if (MOZ_UNLIKELY(aName == nsGkAtoms::style || aName == nsGkAtoms::link)) {
433
0
      nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(newContent));
434
0
      if (ssle) {
435
0
        ssle->InitStyleLinkElement(false);
436
0
        ssle->SetEnableUpdates(false);
437
0
      }
438
0
    }
439
0
440
0
    if (!aAttributes) {
441
0
      return newContent;
442
0
    }
443
0
444
0
    SetHTMLElementAttributes(newContent, aName, aAttributes);
445
0
  } else {
446
0
    nsCOMPtr<dom::Element> newElement;
447
0
448
0
    if (isCustomElement) {
449
0
      NS_NewHTMLElement(getter_AddRefs(newElement),
450
0
                        nodeInfo.forget(),
451
0
                        aFromParser,
452
0
                        isAtom,
453
0
                        definition);
454
0
    } else {
455
0
      newElement = aCreator(nodeInfo.forget(), aFromParser);
456
0
    }
457
0
458
0
    MOZ_ASSERT(newElement, "Element creation created null pointer.");
459
0
460
0
    newContent = newElement;
461
0
    aBuilder->HoldElement(newElement.forget());
462
0
463
0
    if (MOZ_UNLIKELY(aName == nsGkAtoms::style || aName == nsGkAtoms::link)) {
464
0
      nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(newContent));
465
0
      if (ssle) {
466
0
        ssle->InitStyleLinkElement(false);
467
0
        ssle->SetEnableUpdates(false);
468
0
      }
469
0
    } else if (MOZ_UNLIKELY(isKeygen)) {
470
0
      // Adapted from CNavDTD
471
0
      nsresult rv;
472
0
      nsCOMPtr<nsIFormProcessor> theFormProcessor =
473
0
        do_GetService(kFormProcessorCID, &rv);
474
0
      if (NS_FAILED(rv)) {
475
0
        return newContent;
476
0
      }
477
0
478
0
      nsTArray<nsString> theContent;
479
0
      nsAutoString theAttribute;
480
0
481
0
      (void)theFormProcessor->ProvideContent(
482
0
        NS_LITERAL_STRING("select"), theContent, theAttribute);
483
0
484
0
      newContent->SetAttr(
485
0
        kNameSpaceID_None, nsGkAtoms::moztype, nullptr, theAttribute, false);
486
0
487
0
      RefPtr<dom::NodeInfo> optionNodeInfo = aNodeInfoManager->GetNodeInfo(
488
0
        nsGkAtoms::option, nullptr, kNameSpaceID_XHTML, nsINode::ELEMENT_NODE);
489
0
490
0
      for (uint32_t i = 0; i < theContent.Length(); ++i) {
491
0
        RefPtr<dom::NodeInfo> ni = optionNodeInfo;
492
0
        nsCOMPtr<dom::Element> optionElt =
493
0
          NS_NewHTMLOptionElement(ni.forget(), aFromParser);
494
0
        RefPtr<nsTextNode> optionText = new nsTextNode(aNodeInfoManager);
495
0
        (void)optionText->SetText(theContent[i], false);
496
0
        optionElt->AppendChildTo(optionText, false);
497
0
        newContent->AppendChildTo(optionElt, false);
498
0
      }
499
0
      newContent->DoneAddingChildren(false);
500
0
    }
501
0
502
0
    if (!aAttributes) {
503
0
      return newContent;
504
0
    }
505
0
506
0
    SetHTMLElementAttributes(newContent, aName, aAttributes);
507
0
  }
508
0
509
0
  return newContent;
510
0
}
511
512
nsIContent*
513
nsHtml5TreeOperation::CreateSVGElement(
514
  nsAtom* aName,
515
  nsHtml5HtmlAttributes* aAttributes,
516
  mozilla::dom::FromParser aFromParser,
517
  nsNodeInfoManager* aNodeInfoManager,
518
  nsHtml5DocumentBuilder* aBuilder,
519
  mozilla::dom::SVGContentCreatorFunction aCreator)
520
0
{
521
0
  nsCOMPtr<nsIContent> newElement;
522
0
  if (MOZ_LIKELY(aNodeInfoManager->SVGEnabled())) {
523
0
    RefPtr<dom::NodeInfo> nodeInfo = aNodeInfoManager->GetNodeInfo(
524
0
      aName, nullptr, kNameSpaceID_SVG, nsINode::ELEMENT_NODE);
525
0
    MOZ_ASSERT(nodeInfo, "Got null nodeinfo.");
526
0
527
0
    mozilla::DebugOnly<nsresult> rv =
528
0
      aCreator(getter_AddRefs(newElement), nodeInfo.forget(), aFromParser);
529
0
    MOZ_ASSERT(NS_SUCCEEDED(rv) && newElement);
530
0
  } else {
531
0
    RefPtr<dom::NodeInfo> nodeInfo = aNodeInfoManager->GetNodeInfo(
532
0
      aName, nullptr, kNameSpaceID_disabled_SVG, nsINode::ELEMENT_NODE);
533
0
    MOZ_ASSERT(nodeInfo, "Got null nodeinfo.");
534
0
535
0
    // The mismatch between NS_NewXMLElement and SVGContentCreatorFunction
536
0
    // argument types is annoying.
537
0
    nsCOMPtr<dom::Element> xmlElement;
538
0
    mozilla::DebugOnly<nsresult> rv =
539
0
      NS_NewXMLElement(getter_AddRefs(xmlElement), nodeInfo.forget());
540
0
    MOZ_ASSERT(NS_SUCCEEDED(rv) && xmlElement);
541
0
    newElement = xmlElement;
542
0
  }
543
0
544
0
  dom::Element* newContent = newElement->AsElement();
545
0
  aBuilder->HoldElement(newElement.forget());
546
0
547
0
  if (MOZ_UNLIKELY(aName == nsGkAtoms::style)) {
548
0
    nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(newContent));
549
0
    if (ssle) {
550
0
      ssle->InitStyleLinkElement(false);
551
0
      ssle->SetEnableUpdates(false);
552
0
    }
553
0
  }
554
0
555
0
  if (!aAttributes) {
556
0
    return newContent;
557
0
  }
558
0
559
0
  int32_t len = aAttributes->getLength();
560
0
  for (int32_t i = 0; i < len; i++) {
561
0
    nsHtml5String val = aAttributes->getValueNoBoundsCheck(i);
562
0
    nsAtom* klass = val.MaybeAsAtom();
563
0
    if (klass) {
564
0
      newContent->SetSingleClassFromParser(klass);
565
0
    } else {
566
0
      // prefix doesn't need regetting. it is always null or a static atom
567
0
      // local name is never null
568
0
      RefPtr<nsAtom> localName =
569
0
        Reget(aAttributes->getLocalNameNoBoundsCheck(i));
570
0
      RefPtr<nsAtom> prefix = aAttributes->getPrefixNoBoundsCheck(i);
571
0
      int32_t nsuri = aAttributes->getURINoBoundsCheck(i);
572
0
573
0
      nsString value; // Not Auto, because using it to hold nsStringBuffer*
574
0
      val.ToString(value);
575
0
      newContent->SetAttr(nsuri, localName, prefix, value, false);
576
0
    }
577
0
  }
578
0
  return newContent;
579
0
}
580
581
nsIContent*
582
nsHtml5TreeOperation::CreateMathMLElement(nsAtom* aName,
583
                                          nsHtml5HtmlAttributes* aAttributes,
584
                                          nsNodeInfoManager* aNodeInfoManager,
585
                                          nsHtml5DocumentBuilder* aBuilder)
586
0
{
587
0
  nsCOMPtr<dom::Element> newElement;
588
0
  if (MOZ_LIKELY(aNodeInfoManager->MathMLEnabled())) {
589
0
    RefPtr<dom::NodeInfo> nodeInfo = aNodeInfoManager->GetNodeInfo(
590
0
      aName, nullptr, kNameSpaceID_MathML, nsINode::ELEMENT_NODE);
591
0
    NS_ASSERTION(nodeInfo, "Got null nodeinfo.");
592
0
593
0
    mozilla::DebugOnly<nsresult> rv =
594
0
      NS_NewMathMLElement(getter_AddRefs(newElement), nodeInfo.forget());
595
0
    MOZ_ASSERT(NS_SUCCEEDED(rv) && newElement);
596
0
  } else {
597
0
    RefPtr<dom::NodeInfo> nodeInfo = aNodeInfoManager->GetNodeInfo(
598
0
      aName, nullptr, kNameSpaceID_disabled_MathML, nsINode::ELEMENT_NODE);
599
0
    NS_ASSERTION(nodeInfo, "Got null nodeinfo.");
600
0
601
0
    mozilla::DebugOnly<nsresult> rv =
602
0
      NS_NewXMLElement(getter_AddRefs(newElement), nodeInfo.forget());
603
0
    MOZ_ASSERT(NS_SUCCEEDED(rv) && newElement);
604
0
  }
605
0
606
0
  dom::Element* newContent = newElement;
607
0
  aBuilder->HoldElement(newElement.forget());
608
0
609
0
  if (!aAttributes) {
610
0
    return newContent;
611
0
  }
612
0
613
0
  int32_t len = aAttributes->getLength();
614
0
  for (int32_t i = 0; i < len; i++) {
615
0
    nsHtml5String val = aAttributes->getValueNoBoundsCheck(i);
616
0
    nsAtom* klass = val.MaybeAsAtom();
617
0
    if (klass) {
618
0
      newContent->SetSingleClassFromParser(klass);
619
0
    } else {
620
0
      // prefix doesn't need regetting. it is always null or a static atom
621
0
      // local name is never null
622
0
      RefPtr<nsAtom> localName =
623
0
        Reget(aAttributes->getLocalNameNoBoundsCheck(i));
624
0
      RefPtr<nsAtom> prefix = aAttributes->getPrefixNoBoundsCheck(i);
625
0
      int32_t nsuri = aAttributes->getURINoBoundsCheck(i);
626
0
627
0
      nsString value; // Not Auto, because using it to hold nsStringBuffer*
628
0
      val.ToString(value);
629
0
      newContent->SetAttr(nsuri, localName, prefix, value, false);
630
0
    }
631
0
  }
632
0
  return newContent;
633
0
}
634
635
void
636
nsHtml5TreeOperation::SetFormElement(nsIContent* aNode, nsIContent* aParent)
637
0
{
638
0
  nsCOMPtr<nsIFormControl> formControl(do_QueryInterface(aNode));
639
0
  RefPtr<dom::HTMLImageElement> domImageElement =
640
0
    dom::HTMLImageElement::FromNodeOrNull(aNode);
641
0
  // NS_ASSERTION(formControl, "Form-associated element did not implement
642
0
  // nsIFormControl.");
643
0
  // TODO: uncomment the above line when <keygen> (bug 101019) is supported by
644
0
  // Gecko
645
0
  RefPtr<dom::HTMLFormElement> formElement =
646
0
    dom::HTMLFormElement::FromNodeOrNull(aParent);
647
0
  NS_ASSERTION(formElement,
648
0
               "The form element doesn't implement HTMLFormElement.");
649
0
  // avoid crashing on <keygen>
650
0
  if (formControl &&
651
0
      !aNode->AsElement()->HasAttr(kNameSpaceID_None, nsGkAtoms::form)) {
652
0
    formControl->SetForm(formElement);
653
0
  } else if (domImageElement) {
654
0
    domImageElement->SetForm(formElement);
655
0
  }
656
0
}
657
658
nsresult
659
nsHtml5TreeOperation::FosterParentText(nsIContent* aStackParent,
660
                                       char16_t* aBuffer,
661
                                       uint32_t aLength,
662
                                       nsIContent* aTable,
663
                                       nsHtml5DocumentBuilder* aBuilder)
664
0
{
665
0
  MOZ_ASSERT(aBuilder);
666
0
  MOZ_ASSERT(aBuilder->IsInDocUpdate());
667
0
  nsresult rv = NS_OK;
668
0
  nsIContent* foster = aTable->GetParent();
669
0
670
0
  if (IsElementOrTemplateContent(foster)) {
671
0
    nsHtml5OtherDocUpdate update(foster->OwnerDoc(), aBuilder->GetDocument());
672
0
673
0
    nsIContent* previousSibling = aTable->GetPreviousSibling();
674
0
    if (previousSibling && previousSibling->IsText()) {
675
0
      return AppendTextToTextNode(aBuffer, aLength,
676
0
                                  previousSibling->GetAsText(), aBuilder);
677
0
    }
678
0
679
0
    nsNodeInfoManager* nodeInfoManager =
680
0
      aStackParent->OwnerDoc()->NodeInfoManager();
681
0
    RefPtr<nsTextNode> text = new nsTextNode(nodeInfoManager);
682
0
    NS_ASSERTION(text, "Infallible malloc failed?");
683
0
    rv = text->SetText(aBuffer, aLength, false);
684
0
    NS_ENSURE_SUCCESS(rv, rv);
685
0
686
0
    rv = foster->InsertChildBefore(text, aTable, false);
687
0
    NS_ENSURE_SUCCESS(rv, rv);
688
0
    nsNodeUtils::ContentInserted(foster, text);
689
0
    return rv;
690
0
  }
691
0
692
0
  return AppendText(aBuffer, aLength, aStackParent, aBuilder);
693
0
}
694
695
nsresult
696
nsHtml5TreeOperation::AppendComment(nsIContent* aParent,
697
                                    char16_t* aBuffer,
698
                                    int32_t aLength,
699
                                    nsHtml5DocumentBuilder* aBuilder)
700
0
{
701
0
  nsNodeInfoManager* nodeInfoManager = aParent->OwnerDoc()->NodeInfoManager();
702
0
  RefPtr<dom::Comment> comment = new dom::Comment(nodeInfoManager);
703
0
  NS_ASSERTION(comment, "Infallible malloc failed?");
704
0
  nsresult rv = comment->SetText(aBuffer, aLength, false);
705
0
  NS_ENSURE_SUCCESS(rv, rv);
706
0
707
0
  return Append(comment, aParent, aBuilder);
708
0
}
709
710
nsresult
711
nsHtml5TreeOperation::AppendCommentToDocument(char16_t* aBuffer,
712
                                              int32_t aLength,
713
                                              nsHtml5DocumentBuilder* aBuilder)
714
0
{
715
0
  RefPtr<dom::Comment> comment =
716
0
    new dom::Comment(aBuilder->GetNodeInfoManager());
717
0
  NS_ASSERTION(comment, "Infallible malloc failed?");
718
0
  nsresult rv = comment->SetText(aBuffer, aLength, false);
719
0
  NS_ENSURE_SUCCESS(rv, rv);
720
0
721
0
  return AppendToDocument(comment, aBuilder);
722
0
}
723
724
nsresult
725
nsHtml5TreeOperation::AppendDoctypeToDocument(nsAtom* aName,
726
                                              const nsAString& aPublicId,
727
                                              const nsAString& aSystemId,
728
                                              nsHtml5DocumentBuilder* aBuilder)
729
0
{
730
0
  // Adapted from nsXMLContentSink
731
0
  // Create a new doctype node
732
0
  RefPtr<dom::DocumentType> docType = NS_NewDOMDocumentType(
733
0
    aBuilder->GetNodeInfoManager(), aName, aPublicId, aSystemId, VoidString());
734
0
  return AppendToDocument(docType, aBuilder);
735
0
}
736
737
nsIContent*
738
nsHtml5TreeOperation::GetDocumentFragmentForTemplate(nsIContent* aNode)
739
0
{
740
0
  dom::HTMLTemplateElement* tempElem =
741
0
    static_cast<dom::HTMLTemplateElement*>(aNode);
742
0
  RefPtr<dom::DocumentFragment> frag = tempElem->Content();
743
0
  return frag;
744
0
}
745
746
nsIContent*
747
nsHtml5TreeOperation::GetFosterParent(nsIContent* aTable,
748
                                      nsIContent* aStackParent)
749
0
{
750
0
  nsIContent* tableParent = aTable->GetParent();
751
0
  return IsElementOrTemplateContent(tableParent) ? tableParent : aStackParent;
752
0
}
753
754
void
755
nsHtml5TreeOperation::PreventScriptExecution(nsIContent* aNode)
756
0
{
757
0
  nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(aNode);
758
0
  if (sele) {
759
0
    sele->PreventExecution();
760
0
  } else {
761
0
    MOZ_ASSERT(nsNameSpaceManager::GetInstance()->mSVGDisabled,
762
0
               "Node didn't QI to script, but SVG wasn't disabled.");
763
0
  }
764
0
}
765
766
void
767
nsHtml5TreeOperation::DoneAddingChildren(nsIContent* aNode)
768
0
{
769
0
  aNode->DoneAddingChildren(aNode->HasParserNotified());
770
0
}
771
772
void
773
nsHtml5TreeOperation::DoneCreatingElement(nsIContent* aNode)
774
0
{
775
0
  aNode->DoneCreatingElement();
776
0
}
777
778
void
779
nsHtml5TreeOperation::SvgLoad(nsIContent* aNode)
780
0
{
781
0
  nsCOMPtr<nsIRunnable> event = new nsHtml5SVGLoadDispatcher(aNode);
782
0
  if (NS_FAILED(
783
0
        aNode->OwnerDoc()->Dispatch(TaskCategory::Network, event.forget()))) {
784
0
    NS_WARNING("failed to dispatch svg load dispatcher");
785
0
  }
786
0
}
787
788
void
789
nsHtml5TreeOperation::MarkMalformedIfScript(nsIContent* aNode)
790
0
{
791
0
  nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(aNode);
792
0
  if (sele) {
793
0
    // Make sure to serialize this script correctly, for nice round tripping.
794
0
    sele->SetIsMalformed();
795
0
  }
796
0
}
797
798
nsresult
799
nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor* aBuilder,
800
                              nsIContent** aScriptElement,
801
                              bool* aInterrupted,
802
                              bool* aStreamEnded)
803
0
{
804
0
  switch (mOpCode) {
805
0
    case eTreeOpUninitialized: {
806
0
      MOZ_CRASH("eTreeOpUninitialized");
807
0
    }
808
0
    case eTreeOpAppend: {
809
0
      nsIContent* node = *(mOne.node);
810
0
      nsIContent* parent = *(mTwo.node);
811
0
      return Append(node, parent, aBuilder);
812
0
    }
813
0
    case eTreeOpDetach: {
814
0
      nsIContent* node = *(mOne.node);
815
0
      Detach(node, aBuilder);
816
0
      return NS_OK;
817
0
    }
818
0
    case eTreeOpAppendChildrenToNewParent: {
819
0
      nsCOMPtr<nsIContent> node = *(mOne.node);
820
0
      nsIContent* parent = *(mTwo.node);
821
0
      return AppendChildrenToNewParent(node, parent, aBuilder);
822
0
    }
823
0
    case eTreeOpFosterParent: {
824
0
      nsIContent* node = *(mOne.node);
825
0
      nsIContent* parent = *(mTwo.node);
826
0
      nsIContent* table = *(mThree.node);
827
0
      return FosterParent(node, parent, table, aBuilder);
828
0
    }
829
0
    case eTreeOpAppendToDocument: {
830
0
      nsIContent* node = *(mOne.node);
831
0
      nsresult rv = AppendToDocument(node, aBuilder);
832
0
833
0
      aBuilder->PauseDocUpdate(aInterrupted);
834
0
      return rv;
835
0
    }
836
0
    case eTreeOpAddAttributes: {
837
0
      nsIContent* node = *(mOne.node);
838
0
      nsHtml5HtmlAttributes* attributes = mTwo.attributes;
839
0
      return AddAttributes(node, attributes, aBuilder);
840
0
    }
841
0
    case eTreeOpDocumentMode: {
842
0
      aBuilder->SetDocumentMode(mOne.mode);
843
0
      return NS_OK;
844
0
    }
845
0
    case eTreeOpCreateHTMLElementNetwork:
846
0
    case eTreeOpCreateHTMLElementNotNetwork: {
847
0
      nsIContent** target = mOne.node;
848
0
      mozilla::dom::HTMLContentCreatorFunction creator = mFour.htmlCreator;
849
0
      RefPtr<nsAtom> name = Reget(mTwo.atom);
850
0
      nsHtml5HtmlAttributes* attributes = mThree.attributes;
851
0
      nsIContent* intendedParent = mFive.node ? *(mFive.node) : nullptr;
852
0
853
0
      // intendedParent == nullptr is a special case where the
854
0
      // intended parent is the document.
855
0
      nsNodeInfoManager* nodeInfoManager =
856
0
        intendedParent ? intendedParent->OwnerDoc()->NodeInfoManager()
857
0
                       : aBuilder->GetNodeInfoManager();
858
0
859
0
      *target = CreateHTMLElement(name,
860
0
                                  attributes,
861
0
                                  mOpCode == eTreeOpCreateHTMLElementNetwork
862
0
                                    ? dom::FROM_PARSER_NETWORK
863
0
                                    : dom::FROM_PARSER_DOCUMENT_WRITE,
864
0
                                  nodeInfoManager,
865
0
                                  aBuilder,
866
0
                                  creator);
867
0
      return NS_OK;
868
0
    }
869
0
    case eTreeOpCreateSVGElementNetwork:
870
0
    case eTreeOpCreateSVGElementNotNetwork: {
871
0
      nsIContent** target = mOne.node;
872
0
      mozilla::dom::SVGContentCreatorFunction creator = mFour.svgCreator;
873
0
      RefPtr<nsAtom> name = Reget(mTwo.atom);
874
0
      nsHtml5HtmlAttributes* attributes = mThree.attributes;
875
0
      nsIContent* intendedParent = mFive.node ? *(mFive.node) : nullptr;
876
0
877
0
      // intendedParent == nullptr is a special case where the
878
0
      // intended parent is the document.
879
0
      nsNodeInfoManager* nodeInfoManager =
880
0
        intendedParent ? intendedParent->OwnerDoc()->NodeInfoManager()
881
0
                       : aBuilder->GetNodeInfoManager();
882
0
883
0
      *target = CreateSVGElement(name,
884
0
                                 attributes,
885
0
                                 mOpCode == eTreeOpCreateSVGElementNetwork
886
0
                                   ? dom::FROM_PARSER_NETWORK
887
0
                                   : dom::FROM_PARSER_DOCUMENT_WRITE,
888
0
                                 nodeInfoManager,
889
0
                                 aBuilder,
890
0
                                 creator);
891
0
      return NS_OK;
892
0
    }
893
0
    case eTreeOpCreateMathMLElement: {
894
0
      nsIContent** target = mOne.node;
895
0
      RefPtr<nsAtom> name = Reget(mTwo.atom);
896
0
      nsHtml5HtmlAttributes* attributes = mThree.attributes;
897
0
      nsIContent* intendedParent = mFive.node ? *(mFive.node) : nullptr;
898
0
899
0
      // intendedParent == nullptr is a special case where the
900
0
      // intended parent is the document.
901
0
      nsNodeInfoManager* nodeInfoManager =
902
0
        intendedParent ? intendedParent->OwnerDoc()->NodeInfoManager()
903
0
                       : aBuilder->GetNodeInfoManager();
904
0
905
0
      *target =
906
0
        CreateMathMLElement(name, attributes, nodeInfoManager, aBuilder);
907
0
      return NS_OK;
908
0
    }
909
0
    case eTreeOpSetFormElement: {
910
0
      nsIContent* node = *(mOne.node);
911
0
      nsIContent* parent = *(mTwo.node);
912
0
      SetFormElement(node, parent);
913
0
      return NS_OK;
914
0
    }
915
0
    case eTreeOpAppendText: {
916
0
      nsIContent* parent = *mOne.node;
917
0
      char16_t* buffer = mTwo.unicharPtr;
918
0
      uint32_t length = mFour.integer;
919
0
      return AppendText(buffer, length, parent, aBuilder);
920
0
    }
921
0
    case eTreeOpFosterParentText: {
922
0
      nsIContent* stackParent = *mOne.node;
923
0
      char16_t* buffer = mTwo.unicharPtr;
924
0
      uint32_t length = mFour.integer;
925
0
      nsIContent* table = *mThree.node;
926
0
      return FosterParentText(stackParent, buffer, length, table, aBuilder);
927
0
    }
928
0
    case eTreeOpAppendComment: {
929
0
      nsIContent* parent = *mOne.node;
930
0
      char16_t* buffer = mTwo.unicharPtr;
931
0
      int32_t length = mFour.integer;
932
0
      return AppendComment(parent, buffer, length, aBuilder);
933
0
    }
934
0
    case eTreeOpAppendCommentToDocument: {
935
0
      char16_t* buffer = mTwo.unicharPtr;
936
0
      int32_t length = mFour.integer;
937
0
      return AppendCommentToDocument(buffer, length, aBuilder);
938
0
    }
939
0
    case eTreeOpAppendDoctypeToDocument: {
940
0
      RefPtr<nsAtom> name = Reget(mOne.atom);
941
0
      nsHtml5TreeOperationStringPair* pair = mTwo.stringPair;
942
0
      nsString publicId;
943
0
      nsString systemId;
944
0
      pair->Get(publicId, systemId);
945
0
      return AppendDoctypeToDocument(name, publicId, systemId, aBuilder);
946
0
    }
947
0
    case eTreeOpGetDocumentFragmentForTemplate: {
948
0
      nsIContent* node = *(mOne.node);
949
0
      *mTwo.node = GetDocumentFragmentForTemplate(node);
950
0
      return NS_OK;
951
0
    }
952
0
    case eTreeOpGetFosterParent: {
953
0
      nsIContent* table = *(mOne.node);
954
0
      nsIContent* stackParent = *(mTwo.node);
955
0
      nsIContent* fosterParent = GetFosterParent(table, stackParent);
956
0
      *mThree.node = fosterParent;
957
0
      return NS_OK;
958
0
    }
959
0
    case eTreeOpMarkAsBroken: {
960
0
      return mOne.result;
961
0
    }
962
0
    case eTreeOpRunScript: {
963
0
      nsIContent* node = *(mOne.node);
964
0
      nsAHtml5TreeBuilderState* snapshot = mTwo.state;
965
0
      if (snapshot) {
966
0
        aBuilder->InitializeDocWriteParserState(snapshot, mFour.integer);
967
0
      }
968
0
      *aScriptElement = node;
969
0
      return NS_OK;
970
0
    }
971
0
    case eTreeOpRunScriptAsyncDefer: {
972
0
      nsIContent* node = *(mOne.node);
973
0
      aBuilder->RunScript(node);
974
0
      return NS_OK;
975
0
    }
976
0
    case eTreeOpPreventScriptExecution: {
977
0
      nsIContent* node = *(mOne.node);
978
0
      PreventScriptExecution(node);
979
0
      return NS_OK;
980
0
    }
981
0
    case eTreeOpDoneAddingChildren: {
982
0
      nsIContent* node = *(mOne.node);
983
0
      node->DoneAddingChildren(node->HasParserNotified());
984
0
      return NS_OK;
985
0
    }
986
0
    case eTreeOpDoneCreatingElement: {
987
0
      nsIContent* node = *(mOne.node);
988
0
      DoneCreatingElement(node);
989
0
      return NS_OK;
990
0
    }
991
0
    case eTreeOpSetDocumentCharset: {
992
0
      auto encoding = WrapNotNull(mOne.encoding);
993
0
      int32_t charsetSource = mFour.integer;
994
0
      aBuilder->SetDocumentCharsetAndSource(encoding, charsetSource);
995
0
      return NS_OK;
996
0
    }
997
0
    case eTreeOpNeedsCharsetSwitchTo: {
998
0
      auto encoding = WrapNotNull(mOne.encoding);
999
0
      int32_t charsetSource = mFour.integer;
1000
0
      int32_t lineNumber = mTwo.integer;
1001
0
      aBuilder->NeedsCharsetSwitchTo(
1002
0
        encoding, charsetSource, (uint32_t)lineNumber);
1003
0
      return NS_OK;
1004
0
    }
1005
0
    case eTreeOpUpdateStyleSheet: {
1006
0
      nsIContent* node = *(mOne.node);
1007
0
      aBuilder->UpdateStyleSheet(node);
1008
0
      return NS_OK;
1009
0
    }
1010
0
    case eTreeOpProcessMeta: {
1011
0
      nsIContent* node = *(mOne.node);
1012
0
      return aBuilder->ProcessMETATag(node);
1013
0
    }
1014
0
    case eTreeOpProcessOfflineManifest: {
1015
0
      char16_t* str = mOne.unicharPtr;
1016
0
      nsDependentString dependentString(str);
1017
0
      aBuilder->ProcessOfflineManifest(dependentString);
1018
0
      return NS_OK;
1019
0
    }
1020
0
    case eTreeOpMarkMalformedIfScript: {
1021
0
      nsIContent* node = *(mOne.node);
1022
0
      MarkMalformedIfScript(node);
1023
0
      return NS_OK;
1024
0
    }
1025
0
    case eTreeOpStreamEnded: {
1026
0
      *aStreamEnded = true;
1027
0
      return NS_OK;
1028
0
    }
1029
0
    case eTreeOpSetStyleLineNumber: {
1030
0
      nsIContent* node = *(mOne.node);
1031
0
      nsCOMPtr<nsIStyleSheetLinkingElement> ssle = do_QueryInterface(node);
1032
0
      if (ssle) {
1033
0
        ssle->SetLineNumber(mFour.integer);
1034
0
      } else {
1035
0
        MOZ_ASSERT(nsNameSpaceManager::GetInstance()->mSVGDisabled,
1036
0
                   "Node didn't QI to style, but SVG wasn't disabled.");
1037
0
      }
1038
0
      return NS_OK;
1039
0
    }
1040
0
    case eTreeOpSetScriptLineNumberAndFreeze: {
1041
0
      nsIContent* node = *(mOne.node);
1042
0
      nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(node);
1043
0
      if (sele) {
1044
0
        sele->SetScriptLineNumber(mFour.integer);
1045
0
        sele->FreezeExecutionAttrs(node->OwnerDoc());
1046
0
      } else {
1047
0
        MOZ_ASSERT(nsNameSpaceManager::GetInstance()->mSVGDisabled,
1048
0
                   "Node didn't QI to script, but SVG wasn't disabled.");
1049
0
      }
1050
0
      return NS_OK;
1051
0
    }
1052
0
    case eTreeOpSvgLoad: {
1053
0
      nsIContent* node = *(mOne.node);
1054
0
      SvgLoad(node);
1055
0
      return NS_OK;
1056
0
    }
1057
0
    case eTreeOpMaybeComplainAboutCharset: {
1058
0
      char* msgId = mOne.charPtr;
1059
0
      bool error = mTwo.integer;
1060
0
      int32_t lineNumber = mThree.integer;
1061
0
      aBuilder->MaybeComplainAboutCharset(msgId, error, (uint32_t)lineNumber);
1062
0
      return NS_OK;
1063
0
    }
1064
0
    case eTreeOpEnableEncodingMenu: {
1065
0
      nsIDocument* doc = aBuilder->GetDocument();
1066
0
      doc->EnableEncodingMenu();
1067
0
      return NS_OK;
1068
0
    }
1069
0
    case eTreeOpAddClass: {
1070
0
      Element* element = (*(mOne.node))->AsElement();
1071
0
      char16_t* str = mTwo.unicharPtr;
1072
0
      nsDependentString depStr(str);
1073
0
      // See viewsource.css for the possible classes
1074
0
      nsAutoString klass;
1075
0
      element->GetAttr(kNameSpaceID_None, nsGkAtoms::_class, klass);
1076
0
      if (!klass.IsEmpty()) {
1077
0
        klass.Append(' ');
1078
0
        klass.Append(depStr);
1079
0
        element->SetAttr(kNameSpaceID_None, nsGkAtoms::_class, klass, true);
1080
0
      } else {
1081
0
        element->SetAttr(kNameSpaceID_None, nsGkAtoms::_class, depStr, true);
1082
0
      }
1083
0
      return NS_OK;
1084
0
    }
1085
0
    case eTreeOpAddViewSourceHref: {
1086
0
      Element* element = (*mOne.node)->AsElement();
1087
0
      char16_t* buffer = mTwo.unicharPtr;
1088
0
      int32_t length = mFour.integer;
1089
0
1090
0
      nsDependentString relative(buffer, length);
1091
0
1092
0
      nsIDocument* doc = aBuilder->GetDocument();
1093
0
1094
0
      auto encoding = doc->GetDocumentCharacterSet();
1095
0
      nsCOMPtr<nsIURI> uri;
1096
0
      nsresult rv = NS_NewURI(getter_AddRefs(uri),
1097
0
                              relative,
1098
0
                              encoding,
1099
0
                              aBuilder->GetViewSourceBaseURI());
1100
0
      NS_ENSURE_SUCCESS(rv, NS_OK);
1101
0
1102
0
      // Reuse the fix for bug 467852
1103
0
      // URLs that execute script (e.g. "javascript:" URLs) should just be
1104
0
      // ignored.  There's nothing reasonable we can do with them, and allowing
1105
0
      // them to execute in the context of the view-source window presents a
1106
0
      // security risk.  Just return the empty string in this case.
1107
0
      bool openingExecutesScript = false;
1108
0
      rv = NS_URIChainHasFlags(uri,
1109
0
                               nsIProtocolHandler::URI_OPENING_EXECUTES_SCRIPT,
1110
0
                               &openingExecutesScript);
1111
0
      if (NS_FAILED(rv) || openingExecutesScript) {
1112
0
        return NS_OK;
1113
0
      }
1114
0
1115
0
      nsAutoCString viewSourceUrl;
1116
0
1117
0
      // URLs that return data (e.g. "http:" URLs) should be prefixed with
1118
0
      // "view-source:".  URLs that don't return data should just be returned
1119
0
      // undecorated.
1120
0
      bool doesNotReturnData = false;
1121
0
      rv = NS_URIChainHasFlags(
1122
0
        uri, nsIProtocolHandler::URI_DOES_NOT_RETURN_DATA, &doesNotReturnData);
1123
0
      NS_ENSURE_SUCCESS(rv, NS_OK);
1124
0
      if (!doesNotReturnData) {
1125
0
        viewSourceUrl.AssignLiteral("view-source:");
1126
0
      }
1127
0
1128
0
      nsAutoCString spec;
1129
0
      rv = uri->GetSpec(spec);
1130
0
      NS_ENSURE_SUCCESS(rv, rv);
1131
0
1132
0
      viewSourceUrl.Append(spec);
1133
0
1134
0
      nsAutoString utf16;
1135
0
      CopyUTF8toUTF16(viewSourceUrl, utf16);
1136
0
1137
0
      element->SetAttr(kNameSpaceID_None, nsGkAtoms::href, utf16, true);
1138
0
      return NS_OK;
1139
0
    }
1140
0
    case eTreeOpAddViewSourceBase: {
1141
0
      char16_t* buffer = mTwo.unicharPtr;
1142
0
      int32_t length = mFour.integer;
1143
0
      nsDependentString baseUrl(buffer, length);
1144
0
      aBuilder->AddBase(baseUrl);
1145
0
      return NS_OK;
1146
0
    }
1147
0
    case eTreeOpAddError: {
1148
0
      Element* element = (*(mOne.node))->AsElement();
1149
0
      char* msgId = mTwo.charPtr;
1150
0
      RefPtr<nsAtom> atom = Reget(mThree.atom);
1151
0
      RefPtr<nsAtom> otherAtom = Reget(mFour.atom);
1152
0
      // See viewsource.css for the possible classes in addition to "error".
1153
0
      nsAutoString klass;
1154
0
      element->GetAttr(kNameSpaceID_None, nsGkAtoms::_class, klass);
1155
0
      if (!klass.IsEmpty()) {
1156
0
        klass.AppendLiteral(" error");
1157
0
        element->SetAttr(kNameSpaceID_None, nsGkAtoms::_class, klass, true);
1158
0
      } else {
1159
0
        element->SetAttr(kNameSpaceID_None,
1160
0
                         nsGkAtoms::_class,
1161
0
                         NS_LITERAL_STRING("error"),
1162
0
                         true);
1163
0
      }
1164
0
1165
0
      nsresult rv;
1166
0
      nsAutoString message;
1167
0
      if (otherAtom) {
1168
0
        const char16_t* params[] = { atom->GetUTF16String(),
1169
0
                                     otherAtom->GetUTF16String() };
1170
0
        rv = nsContentUtils::FormatLocalizedString(
1171
0
          nsContentUtils::eHTMLPARSER_PROPERTIES, msgId, params, message);
1172
0
        NS_ENSURE_SUCCESS(rv, NS_OK);
1173
0
      } else if (atom) {
1174
0
        const char16_t* params[] = { atom->GetUTF16String() };
1175
0
        rv = nsContentUtils::FormatLocalizedString(
1176
0
          nsContentUtils::eHTMLPARSER_PROPERTIES, msgId, params, message);
1177
0
        NS_ENSURE_SUCCESS(rv, NS_OK);
1178
0
      } else {
1179
0
        rv = nsContentUtils::GetLocalizedString(
1180
0
          nsContentUtils::eHTMLPARSER_PROPERTIES, msgId, message);
1181
0
        NS_ENSURE_SUCCESS(rv, NS_OK);
1182
0
      }
1183
0
1184
0
      nsAutoString title;
1185
0
      element->GetAttr(kNameSpaceID_None, nsGkAtoms::title, title);
1186
0
      if (!title.IsEmpty()) {
1187
0
        title.Append('\n');
1188
0
        title.Append(message);
1189
0
        element->SetAttr(kNameSpaceID_None, nsGkAtoms::title, title, true);
1190
0
      } else {
1191
0
        element->SetAttr(kNameSpaceID_None, nsGkAtoms::title, message, true);
1192
0
      }
1193
0
      return rv;
1194
0
    }
1195
0
    case eTreeOpAddLineNumberId: {
1196
0
      Element* element = (*(mOne.node))->AsElement();
1197
0
      int32_t lineNumber = mFour.integer;
1198
0
      nsAutoString val(NS_LITERAL_STRING("line"));
1199
0
      val.AppendInt(lineNumber);
1200
0
      element->SetAttr(kNameSpaceID_None, nsGkAtoms::id, val, true);
1201
0
      return NS_OK;
1202
0
    }
1203
0
    case eTreeOpStartLayout: {
1204
0
      aBuilder->StartLayout(
1205
0
        aInterrupted); // this causes a notification flush anyway
1206
0
      return NS_OK;
1207
0
    }
1208
0
    default: {
1209
0
      MOZ_CRASH("Bogus tree op");
1210
0
    }
1211
0
  }
1212
0
  return NS_OK; // keep compiler happy
1213
0
}