parser/html/nsHtml5Highlighter.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial