parser/html/nsHtml5Highlighter.cpp

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

     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"
     6 #include "nsDebug.h"
     7 #include "nsHtml5Tokenizer.h"
     8 #include "nsHtml5AttributeName.h"
     9 #include "nsString.h"
    10 #include "nsThreadUtils.h"
    11 #include "nsHtml5ViewSourceUtils.h"
    12 #include "mozilla/Preferences.h"
    14 using namespace mozilla;
    16 // The old code had a limit of 16 tokens. 1300 is a number picked my measuring
    17 // the size of 16 tokens on cnn.com.
    18 #define NS_HTML5_HIGHLIGHTER_PRE_BREAK_THRESHOLD 1300
    20 char16_t nsHtml5Highlighter::sComment[] =
    21   { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
    23 char16_t nsHtml5Highlighter::sCdata[] =
    24   { 'c', 'd', 'a', 't', 'a', 0 };
    26 char16_t nsHtml5Highlighter::sEntity[] =
    27   { 'e', 'n', 't', 'i', 't', 'y', 0 };
    29 char16_t nsHtml5Highlighter::sEndTag[] =
    30   { 'e', 'n', 'd', '-', 't', 'a', 'g', 0 };
    32 char16_t nsHtml5Highlighter::sStartTag[] =
    33   { 's', 't', 'a', 'r', 't', '-', '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[] =
    39   { 'a', 't', 't', 'r', 'i', 'b', 'u', 't', 'e', '-',
    40     'v', 'a', 'l', 'u', 'e', 0 };
    42 char16_t nsHtml5Highlighter::sDoctype[] =
    43   { 'd', 'o', 'c', 't', 'y', 'p', 'e', 0 };
    45 char16_t nsHtml5Highlighter::sPi[] =
    46   { 'p', 'i', 0 };
    48 nsHtml5Highlighter::nsHtml5Highlighter(nsAHtml5TreeOpSink* aOpSink)
    49  : mState(NS_HTML5TOKENIZER_DATA)
    50  , mCStart(INT32_MAX)
    51  , mPos(0)
    52  , mLineNumber(1)
    53  , mInlinesOpen(0)
    54  , mInCharacters(false)
    55  , mBuffer(nullptr)
    56  , mSyntaxHighlight(Preferences::GetBool("view_source.syntax_highlight",
    57                                          true))
    58  , mOpSink(aOpSink)
    59  , mCurrentRun(nullptr)
    60  , mAmpersand(nullptr)
    61  , mSlash(nullptr)
    62  , mHandles(new nsIContent*[NS_HTML5_HIGHLIGHTER_HANDLE_ARRAY_LENGTH])
    63  , mHandlesUsed(0)
    64 {
    65   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
    66 }
    68 nsHtml5Highlighter::~nsHtml5Highlighter()
    69 {
    70   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
    71 }
    73 void
    74 nsHtml5Highlighter::Start(const nsAutoString& aTitle)
    75 {
    76   // Doctype
    77   mOpQueue.AppendElement()->Init(nsGkAtoms::html, EmptyString(), EmptyString());
    79   mOpQueue.AppendElement()->Init(STANDARDS_MODE);
    81   nsIContent** root = CreateElement(nsHtml5Atoms::html, nullptr);
    82   mOpQueue.AppendElement()->Init(eTreeOpAppendToDocument, root);
    83   mStack.AppendElement(root);
    85   Push(nsGkAtoms::head, nullptr);
    87   Push(nsGkAtoms::title, nullptr);
    88   // XUL will add the "Source of: " prefix.
    89   uint32_t length = aTitle.Length();
    90   if (length > INT32_MAX) {
    91     length = INT32_MAX;
    92   }
    93   AppendCharacters(aTitle.get(), 0, (int32_t)length);
    94   Pop(); // title
    96   Push(nsGkAtoms::link, nsHtml5ViewSourceUtils::NewLinkAttributes());
    98   mOpQueue.AppendElement()->Init(eTreeOpUpdateStyleSheet, CurrentNode());
   100   Pop(); // link
   102   Pop(); // head
   104   Push(nsGkAtoms::body, nsHtml5ViewSourceUtils::NewBodyAttributes());
   106   nsHtml5HtmlAttributes* preAttrs = new nsHtml5HtmlAttributes(0);
   107   nsString* preId = new nsString(NS_LITERAL_STRING("line1"));
   108   preAttrs->addAttribute(nsHtml5AttributeName::ATTR_ID, preId);
   109   Push(nsGkAtoms::pre, preAttrs);
   111   StartCharacters();
   113   mOpQueue.AppendElement()->Init(eTreeOpStartLayout);
   114 }
   116 int32_t
   117 nsHtml5Highlighter::Transition(int32_t aState, bool aReconsume, int32_t aPos)
   118 {
   119   mPos = aPos;
   120   switch (mState) {
   121     case NS_HTML5TOKENIZER_SCRIPT_DATA:
   122     case NS_HTML5TOKENIZER_RAWTEXT:
   123     case NS_HTML5TOKENIZER_RCDATA:
   124     case NS_HTML5TOKENIZER_DATA:
   125       // We can transition on < and on &. Either way, we don't yet know the
   126       // role of the token, so open a span without class.
   127       if (aState == NS_HTML5TOKENIZER_CONSUME_CHARACTER_REFERENCE) {
   128         StartSpan();
   129         // Start another span for highlighting the ampersand
   130         StartSpan();
   131         mAmpersand = CurrentNode();
   132       } else {
   133         EndCharactersAndStartMarkupRun();
   134       }
   135       break;
   136     case NS_HTML5TOKENIZER_TAG_OPEN:
   137       switch (aState) {
   138         case NS_HTML5TOKENIZER_TAG_NAME:
   139           StartSpan(sStartTag);
   140           break;
   141         case NS_HTML5TOKENIZER_DATA:
   142           FinishTag(); // DATA
   143           break;
   144         case NS_HTML5TOKENIZER_PROCESSING_INSTRUCTION:
   145           AddClass(sPi);
   146           break;
   147       }
   148       break;
   149     case NS_HTML5TOKENIZER_TAG_NAME:
   150       switch (aState) {
   151         case NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_NAME:
   152           EndSpanOrA(); // NS_HTML5TOKENIZER_TAG_NAME
   153           break;
   154         case NS_HTML5TOKENIZER_SELF_CLOSING_START_TAG:
   155           EndSpanOrA(); // NS_HTML5TOKENIZER_TAG_NAME
   156           StartSpan(); // for highlighting the slash
   157           mSlash = CurrentNode();
   158           break;
   159         default:
   160           FinishTag();
   161           break;
   162       }
   163       break;
   164     case NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_NAME:
   165       switch (aState) {
   166         case NS_HTML5TOKENIZER_ATTRIBUTE_NAME:
   167           StartSpan(sAttributeName);
   168           break;
   169         case NS_HTML5TOKENIZER_SELF_CLOSING_START_TAG:
   170           StartSpan(); // for highlighting the slash
   171           mSlash = CurrentNode();
   172           break;
   173         default:
   174           FinishTag();
   175           break;
   176       }
   177       break;
   178     case NS_HTML5TOKENIZER_ATTRIBUTE_NAME:
   179       switch (aState) {
   180         case NS_HTML5TOKENIZER_AFTER_ATTRIBUTE_NAME:
   181         case NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_VALUE:
   182           EndSpanOrA(); // NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_NAME
   183           break;
   184         case NS_HTML5TOKENIZER_SELF_CLOSING_START_TAG:
   185           EndSpanOrA(); // NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_NAME
   186           StartSpan(); // for highlighting the slash
   187           mSlash = CurrentNode();
   188           break;
   189         default:
   190           FinishTag();
   191           break;
   192       }
   193       break;
   194     case NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_VALUE:
   195       switch (aState) {
   196         case NS_HTML5TOKENIZER_ATTRIBUTE_VALUE_DOUBLE_QUOTED:
   197         case NS_HTML5TOKENIZER_ATTRIBUTE_VALUE_SINGLE_QUOTED:
   198           FlushCurrent();
   199           StartA();
   200           break;
   201         case NS_HTML5TOKENIZER_ATTRIBUTE_VALUE_UNQUOTED:
   202           StartA();
   203           break;
   204         default:
   205           FinishTag();
   206           break;
   207       }
   208       break;
   209     case NS_HTML5TOKENIZER_ATTRIBUTE_VALUE_DOUBLE_QUOTED:
   210     case NS_HTML5TOKENIZER_ATTRIBUTE_VALUE_SINGLE_QUOTED:
   211       switch (aState) {
   212         case NS_HTML5TOKENIZER_AFTER_ATTRIBUTE_VALUE_QUOTED:
   213           EndSpanOrA();
   214           break;
   215         case NS_HTML5TOKENIZER_CONSUME_CHARACTER_REFERENCE:
   216           StartSpan();
   217           StartSpan(); // for ampersand itself
   218           mAmpersand = CurrentNode();
   219           break;
   220         default:
   221           NS_NOTREACHED("Impossible transition.");
   222           break;
   223       }
   224       break;
   225     case NS_HTML5TOKENIZER_AFTER_ATTRIBUTE_VALUE_QUOTED:
   226       switch (aState) {
   227         case NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_NAME:
   228           break;
   229         case NS_HTML5TOKENIZER_SELF_CLOSING_START_TAG:
   230           StartSpan(); // for highlighting the slash
   231           mSlash = CurrentNode();
   232           break;
   233         default:
   234           FinishTag();
   235           break;
   236       }
   237       break;
   238     case NS_HTML5TOKENIZER_SELF_CLOSING_START_TAG:
   239       EndSpanOrA(); // end the slash highlight
   240       switch (aState) {
   241         case NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_NAME:
   242           break;
   243         default:
   244           FinishTag();
   245           break;
   246       }
   247       break;
   248     case NS_HTML5TOKENIZER_ATTRIBUTE_VALUE_UNQUOTED:
   249       switch (aState) {
   250         case NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_NAME:
   251           EndSpanOrA();
   252           break;
   253         case NS_HTML5TOKENIZER_CONSUME_CHARACTER_REFERENCE:
   254           StartSpan();
   255           StartSpan(); // for ampersand itself
   256           mAmpersand = CurrentNode();
   257           break;
   258         default:
   259           FinishTag();
   260           break;
   261       }
   262       break;
   263     case NS_HTML5TOKENIZER_AFTER_ATTRIBUTE_NAME:
   264       switch (aState) {
   265         case NS_HTML5TOKENIZER_SELF_CLOSING_START_TAG:
   266           StartSpan(); // for highlighting the slash
   267           mSlash = CurrentNode();
   268           break;
   269         case NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_VALUE:
   270           break;
   271         case NS_HTML5TOKENIZER_ATTRIBUTE_NAME:
   272           StartSpan(sAttributeName);
   273           break;
   274         default:
   275           FinishTag();
   276           break;
   277       }
   278       break;
   279       // most comment states are omitted, because they don't matter to
   280       // highlighting
   281     case NS_HTML5TOKENIZER_COMMENT_START:
   282     case NS_HTML5TOKENIZER_COMMENT_END:
   283     case NS_HTML5TOKENIZER_COMMENT_END_BANG:
   284     case NS_HTML5TOKENIZER_COMMENT_START_DASH:
   285     case NS_HTML5TOKENIZER_BOGUS_COMMENT:
   286     case NS_HTML5TOKENIZER_BOGUS_COMMENT_HYPHEN:
   287       if (aState == NS_HTML5TOKENIZER_DATA) {
   288         AddClass(sComment);
   289         FinishTag();
   290       }
   291       break;
   292       // most cdata states are omitted, because they don't matter to
   293       // highlighting
   294     case NS_HTML5TOKENIZER_CDATA_RSQB_RSQB:
   295       if (aState == NS_HTML5TOKENIZER_DATA) {
   296         AddClass(sCdata);
   297         FinishTag();
   298       }
   299       break;
   300     case NS_HTML5TOKENIZER_CONSUME_CHARACTER_REFERENCE:
   301       EndSpanOrA(); // the span for the ampersand
   302       switch (aState) {
   303         case NS_HTML5TOKENIZER_CONSUME_NCR:
   304         case NS_HTML5TOKENIZER_CHARACTER_REFERENCE_HILO_LOOKUP:
   305           break;
   306         default:
   307           // not actually a character reference
   308           EndSpanOrA();
   309           break;
   310       }
   311       break;
   312     case NS_HTML5TOKENIZER_CHARACTER_REFERENCE_HILO_LOOKUP:
   313       if (aState == NS_HTML5TOKENIZER_CHARACTER_REFERENCE_TAIL) {
   314         break;
   315       }
   316       // not actually a character reference
   317       EndSpanOrA();
   318       break;
   319     case NS_HTML5TOKENIZER_CHARACTER_REFERENCE_TAIL:
   320       if (!aReconsume) {
   321         FlushCurrent();
   322       }
   323       EndSpanOrA();
   324       break;
   325     case NS_HTML5TOKENIZER_DECIMAL_NRC_LOOP:
   326     case NS_HTML5TOKENIZER_HEX_NCR_LOOP:
   327       switch (aState) {
   328         case NS_HTML5TOKENIZER_HANDLE_NCR_VALUE:
   329           AddClass(sEntity);
   330           FlushCurrent();
   331           break;
   332         case NS_HTML5TOKENIZER_HANDLE_NCR_VALUE_RECONSUME:
   333           AddClass(sEntity);
   334           break;
   335       }
   336       EndSpanOrA();
   337       break;
   338     case NS_HTML5TOKENIZER_CLOSE_TAG_OPEN:
   339       switch (aState) {
   340         case NS_HTML5TOKENIZER_DATA:
   341           FinishTag();
   342           break;
   343         case NS_HTML5TOKENIZER_TAG_NAME:
   344           StartSpan(sEndTag);
   345           break;
   346       }
   347       break;
   348     case NS_HTML5TOKENIZER_RAWTEXT_RCDATA_LESS_THAN_SIGN:
   349       if (aState == NS_HTML5TOKENIZER_NON_DATA_END_TAG_NAME) {
   350         FlushCurrent();
   351         StartSpan(); // don't know if it is "end-tag" yet :-(
   352         break;
   353       }
   354       EndSpanOrA();
   355       StartCharacters();
   356       break;
   357     case NS_HTML5TOKENIZER_NON_DATA_END_TAG_NAME:
   358       switch (aState) {
   359         case NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_NAME:
   360           AddClass(sEndTag);
   361           EndSpanOrA();
   362           break;
   363         case NS_HTML5TOKENIZER_SELF_CLOSING_START_TAG:
   364           AddClass(sEndTag);
   365           EndSpanOrA();
   366           StartSpan(); // for highlighting the slash
   367           mSlash = CurrentNode();
   368           break;
   369         case NS_HTML5TOKENIZER_DATA: // yes, as a result of emitting the token
   370           AddClass(sEndTag);
   371           FinishTag();
   372           break;
   373         default:
   374           FinishTag();
   375           break;
   376       }
   377       break;
   378     case NS_HTML5TOKENIZER_SCRIPT_DATA_LESS_THAN_SIGN:
   379     case NS_HTML5TOKENIZER_SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN:
   380       if (aState == NS_HTML5TOKENIZER_NON_DATA_END_TAG_NAME) {
   381         FlushCurrent();
   382         StartSpan(); // don't know if it is "end-tag" yet :-(
   383         break;
   384       }
   385       FinishTag();
   386       break;
   387     case NS_HTML5TOKENIZER_SCRIPT_DATA_ESCAPED_DASH_DASH:
   388     case NS_HTML5TOKENIZER_SCRIPT_DATA_ESCAPED:
   389     case NS_HTML5TOKENIZER_SCRIPT_DATA_ESCAPED_DASH:
   390       if (aState == NS_HTML5TOKENIZER_SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN) {
   391         EndCharactersAndStartMarkupRun();
   392       }
   393       break;
   394       // Lots of double escape states omitted, because they don't highlight.
   395       // Likewise, only doctype states that can emit the doctype are of
   396       // interest. Otherwise, the transition out of bogus comment deals.
   397     case NS_HTML5TOKENIZER_BEFORE_DOCTYPE_NAME:
   398     case NS_HTML5TOKENIZER_DOCTYPE_NAME:
   399     case NS_HTML5TOKENIZER_AFTER_DOCTYPE_NAME:
   400     case NS_HTML5TOKENIZER_AFTER_DOCTYPE_PUBLIC_KEYWORD:
   401     case NS_HTML5TOKENIZER_BEFORE_DOCTYPE_PUBLIC_IDENTIFIER:
   402     case NS_HTML5TOKENIZER_DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED:
   403     case NS_HTML5TOKENIZER_AFTER_DOCTYPE_PUBLIC_IDENTIFIER:
   404     case NS_HTML5TOKENIZER_BETWEEN_DOCTYPE_PUBLIC_AND_SYSTEM_IDENTIFIERS:
   405     case NS_HTML5TOKENIZER_DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED:
   406     case NS_HTML5TOKENIZER_AFTER_DOCTYPE_SYSTEM_IDENTIFIER:
   407     case NS_HTML5TOKENIZER_BOGUS_DOCTYPE:
   408     case NS_HTML5TOKENIZER_AFTER_DOCTYPE_SYSTEM_KEYWORD:
   409     case NS_HTML5TOKENIZER_BEFORE_DOCTYPE_SYSTEM_IDENTIFIER:
   410     case NS_HTML5TOKENIZER_DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED:
   411     case NS_HTML5TOKENIZER_DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED:
   412       if (aState == NS_HTML5TOKENIZER_DATA) {
   413         AddClass(sDoctype);
   414         FinishTag();
   415       }
   416       break;
   417     case NS_HTML5TOKENIZER_PROCESSING_INSTRUCTION_QUESTION_MARK:
   418       if (aState == NS_HTML5TOKENIZER_DATA) {
   419         FinishTag();
   420       }
   421       break;
   422     default:
   423       break;
   424   }
   425   mState = aState;
   426   return aState;
   427 }
   429 void
   430 nsHtml5Highlighter::End()
   431 {
   432   switch (mState) {
   433     case NS_HTML5TOKENIZER_COMMENT_END:
   434     case NS_HTML5TOKENIZER_COMMENT_END_BANG:
   435     case NS_HTML5TOKENIZER_COMMENT_START_DASH:
   436     case NS_HTML5TOKENIZER_BOGUS_COMMENT:
   437     case NS_HTML5TOKENIZER_BOGUS_COMMENT_HYPHEN:
   438       AddClass(sComment);
   439       break;
   440     case NS_HTML5TOKENIZER_CDATA_RSQB_RSQB:
   441       AddClass(sCdata);
   442       break;
   443     case NS_HTML5TOKENIZER_DECIMAL_NRC_LOOP:
   444     case NS_HTML5TOKENIZER_HEX_NCR_LOOP:
   445       // XXX need tokenizer help here
   446       break;
   447     case NS_HTML5TOKENIZER_BEFORE_DOCTYPE_NAME:
   448     case NS_HTML5TOKENIZER_DOCTYPE_NAME:
   449     case NS_HTML5TOKENIZER_AFTER_DOCTYPE_NAME:
   450     case NS_HTML5TOKENIZER_AFTER_DOCTYPE_PUBLIC_KEYWORD:
   451     case NS_HTML5TOKENIZER_BEFORE_DOCTYPE_PUBLIC_IDENTIFIER:
   452     case NS_HTML5TOKENIZER_DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED:
   453     case NS_HTML5TOKENIZER_AFTER_DOCTYPE_PUBLIC_IDENTIFIER:
   454     case NS_HTML5TOKENIZER_BETWEEN_DOCTYPE_PUBLIC_AND_SYSTEM_IDENTIFIERS:
   455     case NS_HTML5TOKENIZER_DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED:
   456     case NS_HTML5TOKENIZER_AFTER_DOCTYPE_SYSTEM_IDENTIFIER:
   457     case NS_HTML5TOKENIZER_BOGUS_DOCTYPE:
   458     case NS_HTML5TOKENIZER_AFTER_DOCTYPE_SYSTEM_KEYWORD:
   459     case NS_HTML5TOKENIZER_BEFORE_DOCTYPE_SYSTEM_IDENTIFIER:
   460     case NS_HTML5TOKENIZER_DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED:
   461     case NS_HTML5TOKENIZER_DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED:
   462       AddClass(sDoctype);
   463       break;
   464     default:
   465       break;
   466   }
   467   nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
   468   NS_ASSERTION(treeOp, "Tree op allocation failed.");
   469   treeOp->Init(eTreeOpStreamEnded);
   470   FlushOps();
   471 }
   473 void
   474 nsHtml5Highlighter::SetBuffer(nsHtml5UTF16Buffer* aBuffer)
   475 {
   476   NS_PRECONDITION(!mBuffer, "Old buffer still here!");
   477   mBuffer = aBuffer;
   478   mCStart = aBuffer->getStart();
   479 }
   481 void
   482 nsHtml5Highlighter::DropBuffer(int32_t aPos)
   483 {
   484   NS_PRECONDITION(mBuffer, "No buffer to drop!");
   485   mPos = aPos;
   486   FlushChars();
   487   mBuffer = nullptr;
   488 }
   490 void
   491 nsHtml5Highlighter::StartSpan()
   492 {
   493   FlushChars();
   494   Push(nsGkAtoms::span, nullptr);
   495   ++mInlinesOpen;
   496 }
   498 void
   499 nsHtml5Highlighter::StartSpan(const char16_t* aClass)
   500 {
   501   StartSpan();
   502   AddClass(aClass);
   503 }
   505 void
   506 nsHtml5Highlighter::EndSpanOrA()
   507 {
   508   FlushChars();
   509   Pop();
   510   --mInlinesOpen;
   511 }
   513 void
   514 nsHtml5Highlighter::StartCharacters()
   515 {
   516   NS_PRECONDITION(!mInCharacters, "Already in characters!");
   517   FlushChars();
   518   Push(nsGkAtoms::span, nullptr);
   519   mCurrentRun = CurrentNode();
   520   mInCharacters = true;
   521 }
   523 void
   524 nsHtml5Highlighter::EndCharactersAndStartMarkupRun()
   525 {
   526   NS_PRECONDITION(mInCharacters, "Not in characters!");
   527   FlushChars();
   528   Pop();
   529   mInCharacters = false;
   530   // Now start markup run
   531   StartSpan();
   532   mCurrentRun = CurrentNode();
   533 }
   535 void
   536 nsHtml5Highlighter::StartA()
   537 {
   538   FlushChars();
   539   Push(nsGkAtoms::a, nullptr);
   540   AddClass(sAttributeValue);
   541   ++mInlinesOpen;
   542 }
   544 void
   545 nsHtml5Highlighter::FinishTag()
   546 {
   547   while (mInlinesOpen > 1) {
   548     EndSpanOrA();
   549   }
   550   FlushCurrent(); // >
   551   EndSpanOrA(); // DATA
   552   NS_ASSERTION(!mInlinesOpen, "mInlinesOpen got out of sync!");
   553   StartCharacters();
   554 }
   556 void
   557 nsHtml5Highlighter::FlushChars()
   558 {
   559   if (mCStart < mPos) {
   560     char16_t* buf = mBuffer->getBuffer();
   561     int32_t i = mCStart;
   562     while (i < mPos) {
   563       char16_t c = buf[i];
   564       switch (c) {
   565         case '\r':
   566           // The input this code sees has been normalized so that there are
   567           // CR breaks and LF breaks but no CRLF breaks. Overwrite CR with LF
   568           // to show consistent LF line breaks to layout. It is OK to mutate
   569           // the input data, because there are no reparses in the View Source
   570           // case, so we won't need the original data in the buffer anymore.
   571           buf[i] = '\n';
   572           // fall through
   573         case '\n': {
   574           ++i;
   575           if (mCStart < i) {
   576             int32_t len = i - mCStart;
   577             AppendCharacters(buf, mCStart, len);
   578             mCStart = i;
   579           }
   580           ++mLineNumber;
   581           Push(nsGkAtoms::span, nullptr);
   582           nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
   583           NS_ASSERTION(treeOp, "Tree op allocation failed.");
   584           treeOp->InitAddLineNumberId(CurrentNode(), mLineNumber);
   585           Pop();
   586           break;
   587         }
   588         default:
   589           ++i;
   590           break;
   591       }
   592     }
   593     if (mCStart < mPos) {
   594       int32_t len = mPos - mCStart;
   595       AppendCharacters(buf, mCStart, len);
   596       mCStart = mPos;
   597     }
   598   }
   599 }
   601 void
   602 nsHtml5Highlighter::FlushCurrent()
   603 {
   604   mPos++;
   605   FlushChars();
   606 }
   608 bool
   609 nsHtml5Highlighter::FlushOps()
   610 {
   611   bool hasOps = !mOpQueue.IsEmpty();
   612   if (hasOps) {
   613     mOpSink->MoveOpsFrom(mOpQueue);
   614   }
   615   return hasOps;
   616 }
   618 void
   619 nsHtml5Highlighter::MaybeLinkifyAttributeValue(nsHtml5AttributeName* aName,
   620                                                nsString* aValue)
   621 {
   622   if (!(nsHtml5AttributeName::ATTR_HREF == aName ||
   623         nsHtml5AttributeName::ATTR_SRC == aName ||
   624         nsHtml5AttributeName::ATTR_ACTION == aName ||
   625         nsHtml5AttributeName::ATTR_CITE == aName ||
   626         nsHtml5AttributeName::ATTR_BACKGROUND == aName ||
   627         nsHtml5AttributeName::ATTR_LONGDESC == aName ||
   628         nsHtml5AttributeName::ATTR_XLINK_HREF == aName ||
   629         nsHtml5AttributeName::ATTR_DEFINITIONURL == aName)) {
   630     return;
   631   }
   632   AddViewSourceHref(*aValue);
   633 }
   635 void
   636 nsHtml5Highlighter::CompletedNamedCharacterReference()
   637 {
   638   AddClass(sEntity);
   639 }
   641 nsIContent**
   642 nsHtml5Highlighter::AllocateContentHandle()
   643 {
   644   if (mHandlesUsed == NS_HTML5_HIGHLIGHTER_HANDLE_ARRAY_LENGTH) {
   645     mOldHandles.AppendElement(mHandles.forget());
   646     mHandles = new nsIContent*[NS_HTML5_HIGHLIGHTER_HANDLE_ARRAY_LENGTH];
   647     mHandlesUsed = 0;
   648   }
   649 #ifdef DEBUG
   650   mHandles[mHandlesUsed] = (nsIContent*)0xC0DEDBAD;
   651 #endif
   652   return &mHandles[mHandlesUsed++];
   653 }
   655 nsIContent**
   656 nsHtml5Highlighter::CreateElement(nsIAtom* aName,
   657                                   nsHtml5HtmlAttributes* aAttributes)
   658 {
   659   NS_PRECONDITION(aName, "Got null name.");
   660   nsIContent** content = AllocateContentHandle();
   661   mOpQueue.AppendElement()->Init(kNameSpaceID_XHTML,
   662                                  aName,
   663                                  aAttributes,
   664                                  content,
   665                                  true);
   666   return content;
   667 }
   669 nsIContent**
   670 nsHtml5Highlighter::CurrentNode()
   671 {
   672   NS_PRECONDITION(mStack.Length() >= 1, "Must have something on stack.");
   673   return mStack[mStack.Length() - 1];
   674 }
   676 void
   677 nsHtml5Highlighter::Push(nsIAtom* aName,
   678                          nsHtml5HtmlAttributes* aAttributes)
   679 {
   680   NS_PRECONDITION(mStack.Length() >= 1, "Pushing without root.");
   681   nsIContent** elt = CreateElement(aName, aAttributes); // Don't inline below!
   682   mOpQueue.AppendElement()->Init(eTreeOpAppend, elt, CurrentNode());
   683   mStack.AppendElement(elt);
   684 }
   686 void
   687 nsHtml5Highlighter::Pop()
   688 {
   689   NS_PRECONDITION(mStack.Length() >= 2, "Popping when stack too short.");
   690   mStack.RemoveElementAt(mStack.Length() - 1);
   691 }
   693 void
   694 nsHtml5Highlighter::AppendCharacters(const char16_t* aBuffer,
   695                                      int32_t aStart,
   696                                      int32_t aLength)
   697 {
   698   NS_PRECONDITION(aBuffer, "Null buffer");
   700   char16_t* bufferCopy = new char16_t[aLength];
   701   memcpy(bufferCopy, aBuffer + aStart, aLength * sizeof(char16_t));
   703   mOpQueue.AppendElement()->Init(eTreeOpAppendText,
   704                                  bufferCopy,
   705                                  aLength,
   706                                  CurrentNode());
   707 }
   710 void
   711 nsHtml5Highlighter::AddClass(const char16_t* aClass)
   712 {
   713   if (!mSyntaxHighlight) {
   714     return;
   715   }
   716   mOpQueue.AppendElement()->InitAddClass(CurrentNode(), aClass);
   717 }
   719 void
   720 nsHtml5Highlighter::AddViewSourceHref(const nsString& aValue)
   721 {
   722   char16_t* bufferCopy = new char16_t[aValue.Length() + 1];
   723   memcpy(bufferCopy, aValue.get(), aValue.Length() * sizeof(char16_t));
   724   bufferCopy[aValue.Length()] = 0;
   726   mOpQueue.AppendElement()->Init(eTreeOpAddViewSourceHref,
   727                                  bufferCopy,
   728                                  aValue.Length(),
   729                                  CurrentNode());
   730 }
   732 void
   733 nsHtml5Highlighter::AddErrorToCurrentNode(const char* aMsgId)
   734 {
   735   if (!mSyntaxHighlight) {
   736     return;
   737   }
   738   nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
   739   NS_ASSERTION(treeOp, "Tree op allocation failed.");
   740   treeOp->Init(CurrentNode(), aMsgId);
   741 }
   743 void
   744 nsHtml5Highlighter::AddErrorToCurrentRun(const char* aMsgId)
   745 {
   746   if (!mSyntaxHighlight) {
   747     return;
   748   }
   749   NS_PRECONDITION(mCurrentRun, "Adding error to run without one!");
   750   nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
   751   NS_ASSERTION(treeOp, "Tree op allocation failed.");
   752   treeOp->Init(mCurrentRun, aMsgId);
   753 }
   755 void
   756 nsHtml5Highlighter::AddErrorToCurrentRun(const char* aMsgId,
   757                                          nsIAtom* aName)
   758 {
   759   if (!mSyntaxHighlight) {
   760     return;
   761   }
   762   NS_PRECONDITION(mCurrentRun, "Adding error to run without one!");
   763   nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
   764   NS_ASSERTION(treeOp, "Tree op allocation failed.");
   765   treeOp->Init(mCurrentRun, aMsgId, aName);
   766 }
   768 void
   769 nsHtml5Highlighter::AddErrorToCurrentRun(const char* aMsgId,
   770                                          nsIAtom* aName,
   771                                          nsIAtom* aOther)
   772 {
   773   if (!mSyntaxHighlight) {
   774     return;
   775   }
   776   NS_PRECONDITION(mCurrentRun, "Adding error to run without one!");
   777   nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
   778   NS_ASSERTION(treeOp, "Tree op allocation failed.");
   779   treeOp->Init(mCurrentRun, aMsgId, aName, aOther);
   780 }
   782 void
   783 nsHtml5Highlighter::AddErrorToCurrentAmpersand(const char* aMsgId)
   784 {
   785   if (!mSyntaxHighlight) {
   786     return;
   787   }
   788   NS_PRECONDITION(mAmpersand, "Adding error to ampersand without one!");
   789   nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
   790   NS_ASSERTION(treeOp, "Tree op allocation failed.");
   791   treeOp->Init(mAmpersand, aMsgId);
   792 }
   794 void
   795 nsHtml5Highlighter::AddErrorToCurrentSlash(const char* aMsgId)
   796 {
   797   if (!mSyntaxHighlight) {
   798     return;
   799   }
   800   NS_PRECONDITION(mSlash, "Adding error to slash without one!");
   801   nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
   802   NS_ASSERTION(treeOp, "Tree op allocation failed.");
   803   treeOp->Init(mSlash, aMsgId);
   804 }

mercurial