1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "nsHtml5Highlighter.h"
8 #include "nsHtml5AttributeName.h"
9 #include "nsHtml5Tokenizer.h"
10 #include "nsHtml5ViewSourceUtils.h"
12 #include "nsThreadUtils.h"
14 #include "mozilla/Attributes.h"
15 #include "mozilla/Preferences.h"
17 using namespace mozilla
;
19 // The old code had a limit of 16 tokens. 1300 is a number picked my measuring
20 // the size of 16 tokens on cnn.com.
21 #define NS_HTML5_HIGHLIGHTER_PRE_BREAK_THRESHOLD 1300
23 char16_t
nsHtml5Highlighter::sComment
[] = {'c', 'o', 'm', 'm',
26 char16_t
nsHtml5Highlighter::sCdata
[] = {'c', 'd', 'a', 't', 'a', 0};
28 char16_t
nsHtml5Highlighter::sEntity
[] = {'e', 'n', 't', 'i', 't', 'y', 0};
30 char16_t
nsHtml5Highlighter::sEndTag
[] = {'e', 'n', 'd', '-', 't', 'a', 'g', 0};
32 char16_t
nsHtml5Highlighter::sStartTag
[] = {'s', 't', 'a', 'r', 't',
33 '-', 't', 'a', 'g', 0};
35 char16_t
nsHtml5Highlighter::sAttributeName
[] = {
36 'a', 't', 't', 'r', 'i', 'b', 'u', 't', 'e', '-', 'n', 'a', 'm', 'e', 0};
38 char16_t
nsHtml5Highlighter::sAttributeValue
[] = {'a', 't', 't', 'r', 'i', 'b',
39 'u', 't', 'e', '-', 'v', 'a',
42 char16_t
nsHtml5Highlighter::sDoctype
[] = {'d', 'o', 'c', 't',
45 char16_t
nsHtml5Highlighter::sPi
[] = {'p', 'i', 0};
47 nsHtml5Highlighter::nsHtml5Highlighter(nsAHtml5TreeOpSink
* aOpSink
)
48 : mState(nsHtml5Tokenizer::DATA
),
60 MakeUnique
<nsIContent
*[]>(NS_HTML5_HIGHLIGHTER_HANDLE_ARRAY_LENGTH
)),
63 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
66 nsHtml5Highlighter::~nsHtml5Highlighter() {
67 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
70 void nsHtml5Highlighter::SetOpSink(nsAHtml5TreeOpSink
* aOpSink
) {
74 void nsHtml5Highlighter::Rewind() {
80 mInCharacters
= false;
83 mCurrentRun
= nullptr;
86 // Pop until we have three elements on the stack:
87 // html, body, and pre.
88 while (mStack
.Length() > 3) {
94 void nsHtml5Highlighter::Start(const nsAutoString
& aTitle
) {
96 opAppendDoctypeToDocument
operation(nsGkAtoms::html
, u
""_ns
, u
""_ns
);
97 mOpQueue
.AppendElement()->Init(mozilla::AsVariant(operation
));
99 mOpQueue
.AppendElement()->Init(mozilla::AsVariant(STANDARDS_MODE
));
101 // <html> uses NS_NewHTMLSharedElement creator
103 CreateElement(nsGkAtoms::html
, nullptr, nullptr, NS_NewHTMLSharedElement
);
104 opAppendToDocument
appendOp(root
);
105 mOpQueue
.AppendElement()->Init(mozilla::AsVariant(appendOp
));
106 mStack
.AppendElement(root
);
108 // <head> uses NS_NewHTMLSharedElement creator
109 Push(nsGkAtoms::head
, nullptr, NS_NewHTMLSharedElement
);
111 Push(nsGkAtoms::meta
, nsHtml5ViewSourceUtils::NewMetaViewportAttributes(),
112 NS_NewHTMLMetaElement
);
115 Push(nsGkAtoms::title
, nullptr, NS_NewHTMLTitleElement
);
116 // XUL will add the "Source of: " prefix.
117 uint32_t length
= aTitle
.Length();
118 if (length
> INT32_MAX
) {
121 AppendCharacters(aTitle
.BeginReading(), 0, (int32_t)length
);
124 Push(nsGkAtoms::link
, nsHtml5ViewSourceUtils::NewLinkAttributes(),
125 NS_NewHTMLLinkElement
);
127 opUpdateStyleSheet
updateOp(CurrentNode());
128 mOpQueue
.AppendElement()->Init(mozilla::AsVariant(updateOp
));
134 Push(nsGkAtoms::body
, nsHtml5ViewSourceUtils::NewBodyAttributes(),
135 NS_NewHTMLBodyElement
);
137 nsHtml5HtmlAttributes
* preAttrs
= new nsHtml5HtmlAttributes(0);
138 nsHtml5String preId
= nsHtml5Portability::newStringFromLiteral("line1");
139 preAttrs
->addAttribute(nsHtml5AttributeName::ATTR_ID
, preId
, -1);
140 Push(nsGkAtoms::pre
, preAttrs
, NS_NewHTMLPreElement
);
142 // Don't call StartCharacters here in order to be able to put it in
145 mOpQueue
.AppendElement()->Init(mozilla::AsVariant(opStartLayout()));
148 void nsHtml5Highlighter::UpdateCharsetSource(nsCharsetSource aCharsetSource
) {
149 opUpdateCharsetSource
operation(aCharsetSource
);
150 mOpQueue
.AppendElement()->Init(mozilla::AsVariant(operation
));
153 int32_t nsHtml5Highlighter::Transition(int32_t aState
, bool aReconsume
,
157 case nsHtml5Tokenizer::SCRIPT_DATA
:
158 case nsHtml5Tokenizer::RAWTEXT
:
159 case nsHtml5Tokenizer::RCDATA
:
160 case nsHtml5Tokenizer::DATA
:
161 // We can transition on < and on &. Either way, we don't yet know the
162 // role of the token, so open a span without class.
163 if (aState
== nsHtml5Tokenizer::CONSUME_CHARACTER_REFERENCE
) {
165 // Start another span for highlighting the ampersand
167 mAmpersand
= CurrentNode();
169 EndCharactersAndStartMarkupRun();
172 case nsHtml5Tokenizer::TAG_OPEN
:
174 case nsHtml5Tokenizer::TAG_NAME
:
175 StartSpan(sStartTag
);
177 case nsHtml5Tokenizer::DATA
:
180 case nsHtml5Tokenizer::PROCESSING_INSTRUCTION
:
185 case nsHtml5Tokenizer::TAG_NAME
:
187 case nsHtml5Tokenizer::BEFORE_ATTRIBUTE_NAME
:
188 EndSpanOrA(); // nsHtml5Tokenizer::TAG_NAME
190 case nsHtml5Tokenizer::SELF_CLOSING_START_TAG
:
191 EndSpanOrA(); // nsHtml5Tokenizer::TAG_NAME
192 StartSpan(); // for highlighting the slash
193 mSlash
= CurrentNode();
200 case nsHtml5Tokenizer::BEFORE_ATTRIBUTE_NAME
:
202 case nsHtml5Tokenizer::ATTRIBUTE_NAME
:
203 StartSpan(sAttributeName
);
205 case nsHtml5Tokenizer::SELF_CLOSING_START_TAG
:
206 StartSpan(); // for highlighting the slash
207 mSlash
= CurrentNode();
214 case nsHtml5Tokenizer::ATTRIBUTE_NAME
:
216 case nsHtml5Tokenizer::AFTER_ATTRIBUTE_NAME
:
217 case nsHtml5Tokenizer::BEFORE_ATTRIBUTE_VALUE
:
218 EndSpanOrA(); // nsHtml5Tokenizer::BEFORE_ATTRIBUTE_NAME
220 case nsHtml5Tokenizer::SELF_CLOSING_START_TAG
:
221 EndSpanOrA(); // nsHtml5Tokenizer::BEFORE_ATTRIBUTE_NAME
222 StartSpan(); // for highlighting the slash
223 mSlash
= CurrentNode();
230 case nsHtml5Tokenizer::BEFORE_ATTRIBUTE_VALUE
:
232 case nsHtml5Tokenizer::ATTRIBUTE_VALUE_DOUBLE_QUOTED
:
233 case nsHtml5Tokenizer::ATTRIBUTE_VALUE_SINGLE_QUOTED
:
237 case nsHtml5Tokenizer::ATTRIBUTE_VALUE_UNQUOTED
:
245 case nsHtml5Tokenizer::ATTRIBUTE_VALUE_DOUBLE_QUOTED
:
246 case nsHtml5Tokenizer::ATTRIBUTE_VALUE_SINGLE_QUOTED
:
248 case nsHtml5Tokenizer::AFTER_ATTRIBUTE_VALUE_QUOTED
:
251 case nsHtml5Tokenizer::CONSUME_CHARACTER_REFERENCE
:
253 StartSpan(); // for ampersand itself
254 mAmpersand
= CurrentNode();
257 MOZ_ASSERT_UNREACHABLE("Impossible transition.");
261 case nsHtml5Tokenizer::AFTER_ATTRIBUTE_VALUE_QUOTED
:
263 case nsHtml5Tokenizer::BEFORE_ATTRIBUTE_NAME
:
265 case nsHtml5Tokenizer::SELF_CLOSING_START_TAG
:
266 StartSpan(); // for highlighting the slash
267 mSlash
= CurrentNode();
274 case nsHtml5Tokenizer::SELF_CLOSING_START_TAG
:
275 EndSpanOrA(); // end the slash highlight
277 case nsHtml5Tokenizer::BEFORE_ATTRIBUTE_NAME
:
284 case nsHtml5Tokenizer::ATTRIBUTE_VALUE_UNQUOTED
:
286 case nsHtml5Tokenizer::BEFORE_ATTRIBUTE_NAME
:
289 case nsHtml5Tokenizer::CONSUME_CHARACTER_REFERENCE
:
291 StartSpan(); // for ampersand itself
292 mAmpersand
= CurrentNode();
299 case nsHtml5Tokenizer::AFTER_ATTRIBUTE_NAME
:
301 case nsHtml5Tokenizer::SELF_CLOSING_START_TAG
:
302 StartSpan(); // for highlighting the slash
303 mSlash
= CurrentNode();
305 case nsHtml5Tokenizer::BEFORE_ATTRIBUTE_VALUE
:
307 case nsHtml5Tokenizer::ATTRIBUTE_NAME
:
308 StartSpan(sAttributeName
);
315 // most comment states are omitted, because they don't matter to
317 case nsHtml5Tokenizer::COMMENT_START
:
318 case nsHtml5Tokenizer::COMMENT_END
:
319 case nsHtml5Tokenizer::COMMENT_END_BANG
:
320 case nsHtml5Tokenizer::COMMENT_START_DASH
:
321 case nsHtml5Tokenizer::BOGUS_COMMENT
:
322 case nsHtml5Tokenizer::BOGUS_COMMENT_HYPHEN
:
323 case nsHtml5Tokenizer::COMMENT_LESSTHAN_BANG_DASH_DASH
:
324 if (aState
== nsHtml5Tokenizer::DATA
) {
329 // most cdata states are omitted, because they don't matter to
331 case nsHtml5Tokenizer::CDATA_RSQB_RSQB
:
332 if (aState
== nsHtml5Tokenizer::DATA
) {
337 case nsHtml5Tokenizer::CONSUME_CHARACTER_REFERENCE
:
338 EndSpanOrA(); // the span for the ampersand
340 case nsHtml5Tokenizer::CONSUME_NCR
:
341 case nsHtml5Tokenizer::CHARACTER_REFERENCE_HILO_LOOKUP
:
344 // not actually a character reference
349 case nsHtml5Tokenizer::CHARACTER_REFERENCE_HILO_LOOKUP
:
350 if (aState
== nsHtml5Tokenizer::CHARACTER_REFERENCE_TAIL
) {
353 // not actually a character reference
356 case nsHtml5Tokenizer::CHARACTER_REFERENCE_TAIL
:
362 case nsHtml5Tokenizer::DECIMAL_NRC_LOOP
:
363 case nsHtml5Tokenizer::HEX_NCR_LOOP
:
365 case nsHtml5Tokenizer::HANDLE_NCR_VALUE
:
369 case nsHtml5Tokenizer::HANDLE_NCR_VALUE_RECONSUME
:
375 case nsHtml5Tokenizer::CLOSE_TAG_OPEN
:
377 case nsHtml5Tokenizer::DATA
:
380 case nsHtml5Tokenizer::TAG_NAME
:
385 case nsHtml5Tokenizer::RAWTEXT_RCDATA_LESS_THAN_SIGN
:
386 if (aState
== nsHtml5Tokenizer::NON_DATA_END_TAG_NAME
) {
388 StartSpan(); // don't know if it is "end-tag" yet :-(
394 case nsHtml5Tokenizer::NON_DATA_END_TAG_NAME
:
396 case nsHtml5Tokenizer::BEFORE_ATTRIBUTE_NAME
:
400 case nsHtml5Tokenizer::SELF_CLOSING_START_TAG
:
403 StartSpan(); // for highlighting the slash
404 mSlash
= CurrentNode();
406 case nsHtml5Tokenizer::DATA
: // yes, as a result of emitting the token
415 case nsHtml5Tokenizer::SCRIPT_DATA_LESS_THAN_SIGN
:
416 case nsHtml5Tokenizer::SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN
:
417 if (aState
== nsHtml5Tokenizer::NON_DATA_END_TAG_NAME
) {
419 StartSpan(); // don't know if it is "end-tag" yet :-(
424 case nsHtml5Tokenizer::SCRIPT_DATA_ESCAPED_DASH_DASH
:
425 case nsHtml5Tokenizer::SCRIPT_DATA_ESCAPED
:
426 case nsHtml5Tokenizer::SCRIPT_DATA_ESCAPED_DASH
:
427 if (aState
== nsHtml5Tokenizer::SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN
) {
428 EndCharactersAndStartMarkupRun();
431 // Lots of double escape states omitted, because they don't highlight.
432 // Likewise, only doctype states that can emit the doctype are of
433 // interest. Otherwise, the transition out of bogus comment deals.
434 case nsHtml5Tokenizer::BEFORE_DOCTYPE_NAME
:
435 case nsHtml5Tokenizer::DOCTYPE_NAME
:
436 case nsHtml5Tokenizer::AFTER_DOCTYPE_NAME
:
437 case nsHtml5Tokenizer::AFTER_DOCTYPE_PUBLIC_KEYWORD
:
438 case nsHtml5Tokenizer::BEFORE_DOCTYPE_PUBLIC_IDENTIFIER
:
439 case nsHtml5Tokenizer::DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED
:
440 case nsHtml5Tokenizer::AFTER_DOCTYPE_PUBLIC_IDENTIFIER
:
441 case nsHtml5Tokenizer::BETWEEN_DOCTYPE_PUBLIC_AND_SYSTEM_IDENTIFIERS
:
442 case nsHtml5Tokenizer::DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED
:
443 case nsHtml5Tokenizer::AFTER_DOCTYPE_SYSTEM_IDENTIFIER
:
444 case nsHtml5Tokenizer::BOGUS_DOCTYPE
:
445 case nsHtml5Tokenizer::AFTER_DOCTYPE_SYSTEM_KEYWORD
:
446 case nsHtml5Tokenizer::BEFORE_DOCTYPE_SYSTEM_IDENTIFIER
:
447 case nsHtml5Tokenizer::DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED
:
448 case nsHtml5Tokenizer::DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED
:
449 if (aState
== nsHtml5Tokenizer::DATA
) {
454 case nsHtml5Tokenizer::PROCESSING_INSTRUCTION_QUESTION_MARK
:
455 if (aState
== nsHtml5Tokenizer::DATA
) {
466 [[nodiscard
]] bool nsHtml5Highlighter::End() {
468 case nsHtml5Tokenizer::COMMENT_END
:
469 case nsHtml5Tokenizer::COMMENT_END_BANG
:
470 case nsHtml5Tokenizer::COMMENT_START_DASH
:
471 case nsHtml5Tokenizer::BOGUS_COMMENT
:
472 case nsHtml5Tokenizer::BOGUS_COMMENT_HYPHEN
:
475 case nsHtml5Tokenizer::CDATA_RSQB_RSQB
:
478 case nsHtml5Tokenizer::DECIMAL_NRC_LOOP
:
479 case nsHtml5Tokenizer::HEX_NCR_LOOP
:
480 // XXX need tokenizer help here
482 case nsHtml5Tokenizer::BEFORE_DOCTYPE_NAME
:
483 case nsHtml5Tokenizer::DOCTYPE_NAME
:
484 case nsHtml5Tokenizer::AFTER_DOCTYPE_NAME
:
485 case nsHtml5Tokenizer::AFTER_DOCTYPE_PUBLIC_KEYWORD
:
486 case nsHtml5Tokenizer::BEFORE_DOCTYPE_PUBLIC_IDENTIFIER
:
487 case nsHtml5Tokenizer::DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED
:
488 case nsHtml5Tokenizer::AFTER_DOCTYPE_PUBLIC_IDENTIFIER
:
489 case nsHtml5Tokenizer::BETWEEN_DOCTYPE_PUBLIC_AND_SYSTEM_IDENTIFIERS
:
490 case nsHtml5Tokenizer::DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED
:
491 case nsHtml5Tokenizer::AFTER_DOCTYPE_SYSTEM_IDENTIFIER
:
492 case nsHtml5Tokenizer::BOGUS_DOCTYPE
:
493 case nsHtml5Tokenizer::AFTER_DOCTYPE_SYSTEM_KEYWORD
:
494 case nsHtml5Tokenizer::BEFORE_DOCTYPE_SYSTEM_IDENTIFIER
:
495 case nsHtml5Tokenizer::DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED
:
496 case nsHtml5Tokenizer::DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED
:
502 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
503 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
504 treeOp
->Init(mozilla::AsVariant(opStreamEnded()));
505 return FlushOps().isOk();
508 void nsHtml5Highlighter::SetBuffer(nsHtml5UTF16Buffer
* aBuffer
) {
509 MOZ_ASSERT(!mBuffer
, "Old buffer still here!");
511 mCStart
= aBuffer
->getStart();
514 void nsHtml5Highlighter::DropBuffer(int32_t aPos
) {
515 MOZ_ASSERT(mBuffer
, "No buffer to drop!");
521 void nsHtml5Highlighter::StartSpan() {
523 Push(nsGkAtoms::span
, nullptr, NS_NewHTMLSpanElement
);
527 void nsHtml5Highlighter::StartSpan(const char16_t
* aClass
) {
532 void nsHtml5Highlighter::EndSpanOrA() {
538 void nsHtml5Highlighter::StartCharacters() {
539 MOZ_ASSERT(!mInCharacters
, "Already in characters!");
541 Push(nsGkAtoms::span
, nullptr, NS_NewHTMLSpanElement
);
542 mCurrentRun
= CurrentNode();
543 mInCharacters
= true;
546 void nsHtml5Highlighter::EndCharactersAndStartMarkupRun() {
547 MOZ_ASSERT(mInCharacters
, "Not in characters!");
550 mInCharacters
= false;
551 // Now start markup run
553 mCurrentRun
= CurrentNode();
556 void nsHtml5Highlighter::StartA() {
558 Push(nsGkAtoms::a
, nullptr, NS_NewHTMLAnchorElement
);
559 AddClass(sAttributeValue
);
563 void nsHtml5Highlighter::FinishTag() {
564 while (mInlinesOpen
> 1) {
568 EndSpanOrA(); // DATA
569 NS_ASSERTION(!mInlinesOpen
, "mInlinesOpen got out of sync!");
573 void nsHtml5Highlighter::FlushChars() {
574 if (mCStart
< mPos
) {
575 char16_t
* buf
= mBuffer
->getBuffer();
581 // The input this code sees has been normalized so that there are
582 // CR breaks and LF breaks but no CRLF breaks. Overwrite CR with LF
583 // to show consistent LF line breaks to layout. It is OK to mutate
584 // the input data, because there are no reparses in the View Source
585 // case, so we won't need the original data in the buffer anymore.
591 int32_t len
= i
- mCStart
;
592 AppendCharacters(buf
, mCStart
, len
);
596 Push(nsGkAtoms::span
, nullptr, NS_NewHTMLSpanElement
);
597 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
598 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
599 opAddLineNumberId
operation(CurrentNode(), mLineNumber
);
600 treeOp
->Init(mozilla::AsVariant(operation
));
609 if (mCStart
< mPos
) {
610 int32_t len
= mPos
- mCStart
;
611 AppendCharacters(buf
, mCStart
, len
);
617 void nsHtml5Highlighter::FlushCurrent() {
622 bool nsHtml5Highlighter::ShouldFlushOps() {
623 // Arbitrary threshold that doesn't have an exact justification.
624 // The general idea is to flush much, much sooner than reaching
625 // the maximum size of `nsTArray`.
626 return mOpQueue
.Length() > 100000;
629 mozilla::Result
<bool, nsresult
> nsHtml5Highlighter::FlushOps() {
630 bool hasOps
= !mOpQueue
.IsEmpty();
632 if (!mOpSink
->MoveOpsFrom(mOpQueue
)) {
633 return Err(NS_ERROR_OUT_OF_MEMORY
);
639 void nsHtml5Highlighter::MaybeLinkifyAttributeValue(nsHtml5AttributeName
* aName
,
640 nsHtml5String aValue
) {
641 if (!(nsHtml5AttributeName::ATTR_HREF
== aName
||
642 nsHtml5AttributeName::ATTR_SRC
== aName
||
643 nsHtml5AttributeName::ATTR_ACTION
== aName
||
644 nsHtml5AttributeName::ATTR_CITE
== aName
||
645 nsHtml5AttributeName::ATTR_BACKGROUND
== aName
||
646 nsHtml5AttributeName::ATTR_LONGDESC
== aName
||
647 nsHtml5AttributeName::ATTR_XLINK_HREF
== aName
||
648 nsHtml5AttributeName::ATTR_DEFINITIONURL
== aName
)) {
651 AddViewSourceHref(aValue
);
654 void nsHtml5Highlighter::CompletedNamedCharacterReference() {
658 nsIContent
** nsHtml5Highlighter::AllocateContentHandle() {
659 if (mHandlesUsed
== NS_HTML5_HIGHLIGHTER_HANDLE_ARRAY_LENGTH
) {
660 mOldHandles
.AppendElement(std::move(mHandles
));
662 MakeUnique
<nsIContent
*[]>(NS_HTML5_HIGHLIGHTER_HANDLE_ARRAY_LENGTH
);
666 mHandles
[mHandlesUsed
] = reinterpret_cast<nsIContent
*>(uintptr_t(0xC0DEDBAD));
668 return &mHandles
[mHandlesUsed
++];
671 nsIContent
** nsHtml5Highlighter::CreateElement(
672 nsAtom
* aName
, nsHtml5HtmlAttributes
* aAttributes
,
673 nsIContent
** aIntendedParent
,
674 mozilla::dom::HTMLContentCreatorFunction aCreator
) {
675 MOZ_ASSERT(aName
, "Got null name.");
676 nsIContent
** content
= AllocateContentHandle();
677 opCreateHTMLElement
opeation(content
, aName
, aAttributes
, aCreator
,
679 mozilla::dom::FROM_PARSER_NETWORK
);
680 mOpQueue
.AppendElement()->Init(mozilla::AsVariant(opeation
));
684 nsIContent
** nsHtml5Highlighter::CurrentNode() {
685 MOZ_ASSERT(mStack
.Length() >= 1, "Must have something on stack.");
686 return mStack
[mStack
.Length() - 1];
689 void nsHtml5Highlighter::Push(
690 nsAtom
* aName
, nsHtml5HtmlAttributes
* aAttributes
,
691 mozilla::dom::HTMLContentCreatorFunction aCreator
) {
692 MOZ_ASSERT(mStack
.Length() >= 1, "Pushing without root.");
693 nsIContent
** elt
= CreateElement(aName
, aAttributes
, CurrentNode(),
694 aCreator
); // Don't inline below!
695 opAppend
operation(elt
, CurrentNode(), mozilla::dom::FROM_PARSER_NETWORK
);
696 mOpQueue
.AppendElement()->Init(mozilla::AsVariant(operation
));
697 mStack
.AppendElement(elt
);
700 void nsHtml5Highlighter::Pop() {
701 MOZ_ASSERT(mStack
.Length() >= 2, "Popping when stack too short.");
702 mStack
.RemoveLastElement();
705 void nsHtml5Highlighter::AppendCharacters(const char16_t
* aBuffer
,
706 int32_t aStart
, int32_t aLength
) {
707 MOZ_ASSERT(aBuffer
, "Null buffer");
709 char16_t
* bufferCopy
= new char16_t
[aLength
];
710 memcpy(bufferCopy
, aBuffer
+ aStart
, aLength
* sizeof(char16_t
));
712 opAppendText
operation(CurrentNode(), bufferCopy
, aLength
);
713 mOpQueue
.AppendElement()->Init(mozilla::AsVariant(operation
));
716 void nsHtml5Highlighter::AddClass(const char16_t
* aClass
) {
717 opAddClass
operation(CurrentNode(), (char16_t
*)aClass
);
718 mOpQueue
.AppendElement()->Init(mozilla::AsVariant(operation
));
721 void nsHtml5Highlighter::AddViewSourceHref(nsHtml5String aValue
) {
722 char16_t
* bufferCopy
= new char16_t
[aValue
.Length() + 1];
723 aValue
.CopyToBuffer(bufferCopy
);
724 bufferCopy
[aValue
.Length()] = 0;
726 opAddViewSourceHref
operation(CurrentNode(), bufferCopy
, aValue
.Length());
727 mOpQueue
.AppendElement()->Init(mozilla::AsVariant(operation
));
730 void nsHtml5Highlighter::AddBase(nsHtml5String aValue
) {
735 char16_t
* bufferCopy
= new char16_t
[aValue
.Length() + 1];
736 aValue
.CopyToBuffer(bufferCopy
);
737 bufferCopy
[aValue
.Length()] = 0;
739 opAddViewSourceBase
operation(bufferCopy
, aValue
.Length());
740 mOpQueue
.AppendElement()->Init(mozilla::AsVariant(operation
));
743 void nsHtml5Highlighter::AddErrorToCurrentNode(const char* aMsgId
) {
744 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
745 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
746 opAddErrorType
operation(CurrentNode(), (char*)aMsgId
);
747 treeOp
->Init(mozilla::AsVariant(operation
));
750 void nsHtml5Highlighter::AddErrorToCurrentRun(const char* aMsgId
) {
751 MOZ_ASSERT(mCurrentRun
, "Adding error to run without one!");
752 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
753 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
754 opAddErrorType
operation(mCurrentRun
, (char*)aMsgId
);
755 treeOp
->Init(mozilla::AsVariant(operation
));
758 void nsHtml5Highlighter::AddErrorToCurrentRun(const char* aMsgId
,
760 MOZ_ASSERT(mCurrentRun
, "Adding error to run without one!");
761 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
762 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
763 opAddErrorType
operation(mCurrentRun
, (char*)aMsgId
, aName
);
764 treeOp
->Init(mozilla::AsVariant(operation
));
767 void nsHtml5Highlighter::AddErrorToCurrentRun(const char* aMsgId
, nsAtom
* aName
,
769 MOZ_ASSERT(mCurrentRun
, "Adding error to run without one!");
770 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
771 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
772 opAddErrorType
operation(mCurrentRun
, (char*)aMsgId
, aName
, aOther
);
773 treeOp
->Init(mozilla::AsVariant(operation
));
776 void nsHtml5Highlighter::AddErrorToCurrentAmpersand(const char* aMsgId
) {
777 MOZ_ASSERT(mAmpersand
, "Adding error to ampersand without one!");
778 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
779 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
780 opAddErrorType
operation(mAmpersand
, (char*)aMsgId
);
781 treeOp
->Init(mozilla::AsVariant(operation
));
784 void nsHtml5Highlighter::AddErrorToCurrentSlash(const char* aMsgId
) {
785 MOZ_ASSERT(mSlash
, "Adding error to slash without one!");
786 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
787 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
788 opAddErrorType
operation(mSlash
, (char*)aMsgId
);
789 treeOp
->Init(mozilla::AsVariant(operation
));