1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/parser/html/nsHtml5Highlighter.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,804 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#include "nsHtml5Highlighter.h" 1.9 +#include "nsDebug.h" 1.10 +#include "nsHtml5Tokenizer.h" 1.11 +#include "nsHtml5AttributeName.h" 1.12 +#include "nsString.h" 1.13 +#include "nsThreadUtils.h" 1.14 +#include "nsHtml5ViewSourceUtils.h" 1.15 +#include "mozilla/Preferences.h" 1.16 + 1.17 +using namespace mozilla; 1.18 + 1.19 +// The old code had a limit of 16 tokens. 1300 is a number picked my measuring 1.20 +// the size of 16 tokens on cnn.com. 1.21 +#define NS_HTML5_HIGHLIGHTER_PRE_BREAK_THRESHOLD 1300 1.22 + 1.23 +char16_t nsHtml5Highlighter::sComment[] = 1.24 + { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 }; 1.25 + 1.26 +char16_t nsHtml5Highlighter::sCdata[] = 1.27 + { 'c', 'd', 'a', 't', 'a', 0 }; 1.28 + 1.29 +char16_t nsHtml5Highlighter::sEntity[] = 1.30 + { 'e', 'n', 't', 'i', 't', 'y', 0 }; 1.31 + 1.32 +char16_t nsHtml5Highlighter::sEndTag[] = 1.33 + { 'e', 'n', 'd', '-', 't', 'a', 'g', 0 }; 1.34 + 1.35 +char16_t nsHtml5Highlighter::sStartTag[] = 1.36 + { 's', 't', 'a', 'r', 't', '-', 't', 'a', 'g', 0 }; 1.37 + 1.38 +char16_t nsHtml5Highlighter::sAttributeName[] = 1.39 + { 'a', 't', 't', 'r', 'i', 'b', 'u', 't', 'e', '-', 'n', 'a', 'm', 'e', 0 }; 1.40 + 1.41 +char16_t nsHtml5Highlighter::sAttributeValue[] = 1.42 + { 'a', 't', 't', 'r', 'i', 'b', 'u', 't', 'e', '-', 1.43 + 'v', 'a', 'l', 'u', 'e', 0 }; 1.44 + 1.45 +char16_t nsHtml5Highlighter::sDoctype[] = 1.46 + { 'd', 'o', 'c', 't', 'y', 'p', 'e', 0 }; 1.47 + 1.48 +char16_t nsHtml5Highlighter::sPi[] = 1.49 + { 'p', 'i', 0 }; 1.50 + 1.51 +nsHtml5Highlighter::nsHtml5Highlighter(nsAHtml5TreeOpSink* aOpSink) 1.52 + : mState(NS_HTML5TOKENIZER_DATA) 1.53 + , mCStart(INT32_MAX) 1.54 + , mPos(0) 1.55 + , mLineNumber(1) 1.56 + , mInlinesOpen(0) 1.57 + , mInCharacters(false) 1.58 + , mBuffer(nullptr) 1.59 + , mSyntaxHighlight(Preferences::GetBool("view_source.syntax_highlight", 1.60 + true)) 1.61 + , mOpSink(aOpSink) 1.62 + , mCurrentRun(nullptr) 1.63 + , mAmpersand(nullptr) 1.64 + , mSlash(nullptr) 1.65 + , mHandles(new nsIContent*[NS_HTML5_HIGHLIGHTER_HANDLE_ARRAY_LENGTH]) 1.66 + , mHandlesUsed(0) 1.67 +{ 1.68 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.69 +} 1.70 + 1.71 +nsHtml5Highlighter::~nsHtml5Highlighter() 1.72 +{ 1.73 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.74 +} 1.75 + 1.76 +void 1.77 +nsHtml5Highlighter::Start(const nsAutoString& aTitle) 1.78 +{ 1.79 + // Doctype 1.80 + mOpQueue.AppendElement()->Init(nsGkAtoms::html, EmptyString(), EmptyString()); 1.81 + 1.82 + mOpQueue.AppendElement()->Init(STANDARDS_MODE); 1.83 + 1.84 + nsIContent** root = CreateElement(nsHtml5Atoms::html, nullptr); 1.85 + mOpQueue.AppendElement()->Init(eTreeOpAppendToDocument, root); 1.86 + mStack.AppendElement(root); 1.87 + 1.88 + Push(nsGkAtoms::head, nullptr); 1.89 + 1.90 + Push(nsGkAtoms::title, nullptr); 1.91 + // XUL will add the "Source of: " prefix. 1.92 + uint32_t length = aTitle.Length(); 1.93 + if (length > INT32_MAX) { 1.94 + length = INT32_MAX; 1.95 + } 1.96 + AppendCharacters(aTitle.get(), 0, (int32_t)length); 1.97 + Pop(); // title 1.98 + 1.99 + Push(nsGkAtoms::link, nsHtml5ViewSourceUtils::NewLinkAttributes()); 1.100 + 1.101 + mOpQueue.AppendElement()->Init(eTreeOpUpdateStyleSheet, CurrentNode()); 1.102 + 1.103 + Pop(); // link 1.104 + 1.105 + Pop(); // head 1.106 + 1.107 + Push(nsGkAtoms::body, nsHtml5ViewSourceUtils::NewBodyAttributes()); 1.108 + 1.109 + nsHtml5HtmlAttributes* preAttrs = new nsHtml5HtmlAttributes(0); 1.110 + nsString* preId = new nsString(NS_LITERAL_STRING("line1")); 1.111 + preAttrs->addAttribute(nsHtml5AttributeName::ATTR_ID, preId); 1.112 + Push(nsGkAtoms::pre, preAttrs); 1.113 + 1.114 + StartCharacters(); 1.115 + 1.116 + mOpQueue.AppendElement()->Init(eTreeOpStartLayout); 1.117 +} 1.118 + 1.119 +int32_t 1.120 +nsHtml5Highlighter::Transition(int32_t aState, bool aReconsume, int32_t aPos) 1.121 +{ 1.122 + mPos = aPos; 1.123 + switch (mState) { 1.124 + case NS_HTML5TOKENIZER_SCRIPT_DATA: 1.125 + case NS_HTML5TOKENIZER_RAWTEXT: 1.126 + case NS_HTML5TOKENIZER_RCDATA: 1.127 + case NS_HTML5TOKENIZER_DATA: 1.128 + // We can transition on < and on &. Either way, we don't yet know the 1.129 + // role of the token, so open a span without class. 1.130 + if (aState == NS_HTML5TOKENIZER_CONSUME_CHARACTER_REFERENCE) { 1.131 + StartSpan(); 1.132 + // Start another span for highlighting the ampersand 1.133 + StartSpan(); 1.134 + mAmpersand = CurrentNode(); 1.135 + } else { 1.136 + EndCharactersAndStartMarkupRun(); 1.137 + } 1.138 + break; 1.139 + case NS_HTML5TOKENIZER_TAG_OPEN: 1.140 + switch (aState) { 1.141 + case NS_HTML5TOKENIZER_TAG_NAME: 1.142 + StartSpan(sStartTag); 1.143 + break; 1.144 + case NS_HTML5TOKENIZER_DATA: 1.145 + FinishTag(); // DATA 1.146 + break; 1.147 + case NS_HTML5TOKENIZER_PROCESSING_INSTRUCTION: 1.148 + AddClass(sPi); 1.149 + break; 1.150 + } 1.151 + break; 1.152 + case NS_HTML5TOKENIZER_TAG_NAME: 1.153 + switch (aState) { 1.154 + case NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_NAME: 1.155 + EndSpanOrA(); // NS_HTML5TOKENIZER_TAG_NAME 1.156 + break; 1.157 + case NS_HTML5TOKENIZER_SELF_CLOSING_START_TAG: 1.158 + EndSpanOrA(); // NS_HTML5TOKENIZER_TAG_NAME 1.159 + StartSpan(); // for highlighting the slash 1.160 + mSlash = CurrentNode(); 1.161 + break; 1.162 + default: 1.163 + FinishTag(); 1.164 + break; 1.165 + } 1.166 + break; 1.167 + case NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_NAME: 1.168 + switch (aState) { 1.169 + case NS_HTML5TOKENIZER_ATTRIBUTE_NAME: 1.170 + StartSpan(sAttributeName); 1.171 + break; 1.172 + case NS_HTML5TOKENIZER_SELF_CLOSING_START_TAG: 1.173 + StartSpan(); // for highlighting the slash 1.174 + mSlash = CurrentNode(); 1.175 + break; 1.176 + default: 1.177 + FinishTag(); 1.178 + break; 1.179 + } 1.180 + break; 1.181 + case NS_HTML5TOKENIZER_ATTRIBUTE_NAME: 1.182 + switch (aState) { 1.183 + case NS_HTML5TOKENIZER_AFTER_ATTRIBUTE_NAME: 1.184 + case NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_VALUE: 1.185 + EndSpanOrA(); // NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_NAME 1.186 + break; 1.187 + case NS_HTML5TOKENIZER_SELF_CLOSING_START_TAG: 1.188 + EndSpanOrA(); // NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_NAME 1.189 + StartSpan(); // for highlighting the slash 1.190 + mSlash = CurrentNode(); 1.191 + break; 1.192 + default: 1.193 + FinishTag(); 1.194 + break; 1.195 + } 1.196 + break; 1.197 + case NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_VALUE: 1.198 + switch (aState) { 1.199 + case NS_HTML5TOKENIZER_ATTRIBUTE_VALUE_DOUBLE_QUOTED: 1.200 + case NS_HTML5TOKENIZER_ATTRIBUTE_VALUE_SINGLE_QUOTED: 1.201 + FlushCurrent(); 1.202 + StartA(); 1.203 + break; 1.204 + case NS_HTML5TOKENIZER_ATTRIBUTE_VALUE_UNQUOTED: 1.205 + StartA(); 1.206 + break; 1.207 + default: 1.208 + FinishTag(); 1.209 + break; 1.210 + } 1.211 + break; 1.212 + case NS_HTML5TOKENIZER_ATTRIBUTE_VALUE_DOUBLE_QUOTED: 1.213 + case NS_HTML5TOKENIZER_ATTRIBUTE_VALUE_SINGLE_QUOTED: 1.214 + switch (aState) { 1.215 + case NS_HTML5TOKENIZER_AFTER_ATTRIBUTE_VALUE_QUOTED: 1.216 + EndSpanOrA(); 1.217 + break; 1.218 + case NS_HTML5TOKENIZER_CONSUME_CHARACTER_REFERENCE: 1.219 + StartSpan(); 1.220 + StartSpan(); // for ampersand itself 1.221 + mAmpersand = CurrentNode(); 1.222 + break; 1.223 + default: 1.224 + NS_NOTREACHED("Impossible transition."); 1.225 + break; 1.226 + } 1.227 + break; 1.228 + case NS_HTML5TOKENIZER_AFTER_ATTRIBUTE_VALUE_QUOTED: 1.229 + switch (aState) { 1.230 + case NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_NAME: 1.231 + break; 1.232 + case NS_HTML5TOKENIZER_SELF_CLOSING_START_TAG: 1.233 + StartSpan(); // for highlighting the slash 1.234 + mSlash = CurrentNode(); 1.235 + break; 1.236 + default: 1.237 + FinishTag(); 1.238 + break; 1.239 + } 1.240 + break; 1.241 + case NS_HTML5TOKENIZER_SELF_CLOSING_START_TAG: 1.242 + EndSpanOrA(); // end the slash highlight 1.243 + switch (aState) { 1.244 + case NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_NAME: 1.245 + break; 1.246 + default: 1.247 + FinishTag(); 1.248 + break; 1.249 + } 1.250 + break; 1.251 + case NS_HTML5TOKENIZER_ATTRIBUTE_VALUE_UNQUOTED: 1.252 + switch (aState) { 1.253 + case NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_NAME: 1.254 + EndSpanOrA(); 1.255 + break; 1.256 + case NS_HTML5TOKENIZER_CONSUME_CHARACTER_REFERENCE: 1.257 + StartSpan(); 1.258 + StartSpan(); // for ampersand itself 1.259 + mAmpersand = CurrentNode(); 1.260 + break; 1.261 + default: 1.262 + FinishTag(); 1.263 + break; 1.264 + } 1.265 + break; 1.266 + case NS_HTML5TOKENIZER_AFTER_ATTRIBUTE_NAME: 1.267 + switch (aState) { 1.268 + case NS_HTML5TOKENIZER_SELF_CLOSING_START_TAG: 1.269 + StartSpan(); // for highlighting the slash 1.270 + mSlash = CurrentNode(); 1.271 + break; 1.272 + case NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_VALUE: 1.273 + break; 1.274 + case NS_HTML5TOKENIZER_ATTRIBUTE_NAME: 1.275 + StartSpan(sAttributeName); 1.276 + break; 1.277 + default: 1.278 + FinishTag(); 1.279 + break; 1.280 + } 1.281 + break; 1.282 + // most comment states are omitted, because they don't matter to 1.283 + // highlighting 1.284 + case NS_HTML5TOKENIZER_COMMENT_START: 1.285 + case NS_HTML5TOKENIZER_COMMENT_END: 1.286 + case NS_HTML5TOKENIZER_COMMENT_END_BANG: 1.287 + case NS_HTML5TOKENIZER_COMMENT_START_DASH: 1.288 + case NS_HTML5TOKENIZER_BOGUS_COMMENT: 1.289 + case NS_HTML5TOKENIZER_BOGUS_COMMENT_HYPHEN: 1.290 + if (aState == NS_HTML5TOKENIZER_DATA) { 1.291 + AddClass(sComment); 1.292 + FinishTag(); 1.293 + } 1.294 + break; 1.295 + // most cdata states are omitted, because they don't matter to 1.296 + // highlighting 1.297 + case NS_HTML5TOKENIZER_CDATA_RSQB_RSQB: 1.298 + if (aState == NS_HTML5TOKENIZER_DATA) { 1.299 + AddClass(sCdata); 1.300 + FinishTag(); 1.301 + } 1.302 + break; 1.303 + case NS_HTML5TOKENIZER_CONSUME_CHARACTER_REFERENCE: 1.304 + EndSpanOrA(); // the span for the ampersand 1.305 + switch (aState) { 1.306 + case NS_HTML5TOKENIZER_CONSUME_NCR: 1.307 + case NS_HTML5TOKENIZER_CHARACTER_REFERENCE_HILO_LOOKUP: 1.308 + break; 1.309 + default: 1.310 + // not actually a character reference 1.311 + EndSpanOrA(); 1.312 + break; 1.313 + } 1.314 + break; 1.315 + case NS_HTML5TOKENIZER_CHARACTER_REFERENCE_HILO_LOOKUP: 1.316 + if (aState == NS_HTML5TOKENIZER_CHARACTER_REFERENCE_TAIL) { 1.317 + break; 1.318 + } 1.319 + // not actually a character reference 1.320 + EndSpanOrA(); 1.321 + break; 1.322 + case NS_HTML5TOKENIZER_CHARACTER_REFERENCE_TAIL: 1.323 + if (!aReconsume) { 1.324 + FlushCurrent(); 1.325 + } 1.326 + EndSpanOrA(); 1.327 + break; 1.328 + case NS_HTML5TOKENIZER_DECIMAL_NRC_LOOP: 1.329 + case NS_HTML5TOKENIZER_HEX_NCR_LOOP: 1.330 + switch (aState) { 1.331 + case NS_HTML5TOKENIZER_HANDLE_NCR_VALUE: 1.332 + AddClass(sEntity); 1.333 + FlushCurrent(); 1.334 + break; 1.335 + case NS_HTML5TOKENIZER_HANDLE_NCR_VALUE_RECONSUME: 1.336 + AddClass(sEntity); 1.337 + break; 1.338 + } 1.339 + EndSpanOrA(); 1.340 + break; 1.341 + case NS_HTML5TOKENIZER_CLOSE_TAG_OPEN: 1.342 + switch (aState) { 1.343 + case NS_HTML5TOKENIZER_DATA: 1.344 + FinishTag(); 1.345 + break; 1.346 + case NS_HTML5TOKENIZER_TAG_NAME: 1.347 + StartSpan(sEndTag); 1.348 + break; 1.349 + } 1.350 + break; 1.351 + case NS_HTML5TOKENIZER_RAWTEXT_RCDATA_LESS_THAN_SIGN: 1.352 + if (aState == NS_HTML5TOKENIZER_NON_DATA_END_TAG_NAME) { 1.353 + FlushCurrent(); 1.354 + StartSpan(); // don't know if it is "end-tag" yet :-( 1.355 + break; 1.356 + } 1.357 + EndSpanOrA(); 1.358 + StartCharacters(); 1.359 + break; 1.360 + case NS_HTML5TOKENIZER_NON_DATA_END_TAG_NAME: 1.361 + switch (aState) { 1.362 + case NS_HTML5TOKENIZER_BEFORE_ATTRIBUTE_NAME: 1.363 + AddClass(sEndTag); 1.364 + EndSpanOrA(); 1.365 + break; 1.366 + case NS_HTML5TOKENIZER_SELF_CLOSING_START_TAG: 1.367 + AddClass(sEndTag); 1.368 + EndSpanOrA(); 1.369 + StartSpan(); // for highlighting the slash 1.370 + mSlash = CurrentNode(); 1.371 + break; 1.372 + case NS_HTML5TOKENIZER_DATA: // yes, as a result of emitting the token 1.373 + AddClass(sEndTag); 1.374 + FinishTag(); 1.375 + break; 1.376 + default: 1.377 + FinishTag(); 1.378 + break; 1.379 + } 1.380 + break; 1.381 + case NS_HTML5TOKENIZER_SCRIPT_DATA_LESS_THAN_SIGN: 1.382 + case NS_HTML5TOKENIZER_SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN: 1.383 + if (aState == NS_HTML5TOKENIZER_NON_DATA_END_TAG_NAME) { 1.384 + FlushCurrent(); 1.385 + StartSpan(); // don't know if it is "end-tag" yet :-( 1.386 + break; 1.387 + } 1.388 + FinishTag(); 1.389 + break; 1.390 + case NS_HTML5TOKENIZER_SCRIPT_DATA_ESCAPED_DASH_DASH: 1.391 + case NS_HTML5TOKENIZER_SCRIPT_DATA_ESCAPED: 1.392 + case NS_HTML5TOKENIZER_SCRIPT_DATA_ESCAPED_DASH: 1.393 + if (aState == NS_HTML5TOKENIZER_SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN) { 1.394 + EndCharactersAndStartMarkupRun(); 1.395 + } 1.396 + break; 1.397 + // Lots of double escape states omitted, because they don't highlight. 1.398 + // Likewise, only doctype states that can emit the doctype are of 1.399 + // interest. Otherwise, the transition out of bogus comment deals. 1.400 + case NS_HTML5TOKENIZER_BEFORE_DOCTYPE_NAME: 1.401 + case NS_HTML5TOKENIZER_DOCTYPE_NAME: 1.402 + case NS_HTML5TOKENIZER_AFTER_DOCTYPE_NAME: 1.403 + case NS_HTML5TOKENIZER_AFTER_DOCTYPE_PUBLIC_KEYWORD: 1.404 + case NS_HTML5TOKENIZER_BEFORE_DOCTYPE_PUBLIC_IDENTIFIER: 1.405 + case NS_HTML5TOKENIZER_DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED: 1.406 + case NS_HTML5TOKENIZER_AFTER_DOCTYPE_PUBLIC_IDENTIFIER: 1.407 + case NS_HTML5TOKENIZER_BETWEEN_DOCTYPE_PUBLIC_AND_SYSTEM_IDENTIFIERS: 1.408 + case NS_HTML5TOKENIZER_DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED: 1.409 + case NS_HTML5TOKENIZER_AFTER_DOCTYPE_SYSTEM_IDENTIFIER: 1.410 + case NS_HTML5TOKENIZER_BOGUS_DOCTYPE: 1.411 + case NS_HTML5TOKENIZER_AFTER_DOCTYPE_SYSTEM_KEYWORD: 1.412 + case NS_HTML5TOKENIZER_BEFORE_DOCTYPE_SYSTEM_IDENTIFIER: 1.413 + case NS_HTML5TOKENIZER_DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED: 1.414 + case NS_HTML5TOKENIZER_DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED: 1.415 + if (aState == NS_HTML5TOKENIZER_DATA) { 1.416 + AddClass(sDoctype); 1.417 + FinishTag(); 1.418 + } 1.419 + break; 1.420 + case NS_HTML5TOKENIZER_PROCESSING_INSTRUCTION_QUESTION_MARK: 1.421 + if (aState == NS_HTML5TOKENIZER_DATA) { 1.422 + FinishTag(); 1.423 + } 1.424 + break; 1.425 + default: 1.426 + break; 1.427 + } 1.428 + mState = aState; 1.429 + return aState; 1.430 +} 1.431 + 1.432 +void 1.433 +nsHtml5Highlighter::End() 1.434 +{ 1.435 + switch (mState) { 1.436 + case NS_HTML5TOKENIZER_COMMENT_END: 1.437 + case NS_HTML5TOKENIZER_COMMENT_END_BANG: 1.438 + case NS_HTML5TOKENIZER_COMMENT_START_DASH: 1.439 + case NS_HTML5TOKENIZER_BOGUS_COMMENT: 1.440 + case NS_HTML5TOKENIZER_BOGUS_COMMENT_HYPHEN: 1.441 + AddClass(sComment); 1.442 + break; 1.443 + case NS_HTML5TOKENIZER_CDATA_RSQB_RSQB: 1.444 + AddClass(sCdata); 1.445 + break; 1.446 + case NS_HTML5TOKENIZER_DECIMAL_NRC_LOOP: 1.447 + case NS_HTML5TOKENIZER_HEX_NCR_LOOP: 1.448 + // XXX need tokenizer help here 1.449 + break; 1.450 + case NS_HTML5TOKENIZER_BEFORE_DOCTYPE_NAME: 1.451 + case NS_HTML5TOKENIZER_DOCTYPE_NAME: 1.452 + case NS_HTML5TOKENIZER_AFTER_DOCTYPE_NAME: 1.453 + case NS_HTML5TOKENIZER_AFTER_DOCTYPE_PUBLIC_KEYWORD: 1.454 + case NS_HTML5TOKENIZER_BEFORE_DOCTYPE_PUBLIC_IDENTIFIER: 1.455 + case NS_HTML5TOKENIZER_DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED: 1.456 + case NS_HTML5TOKENIZER_AFTER_DOCTYPE_PUBLIC_IDENTIFIER: 1.457 + case NS_HTML5TOKENIZER_BETWEEN_DOCTYPE_PUBLIC_AND_SYSTEM_IDENTIFIERS: 1.458 + case NS_HTML5TOKENIZER_DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED: 1.459 + case NS_HTML5TOKENIZER_AFTER_DOCTYPE_SYSTEM_IDENTIFIER: 1.460 + case NS_HTML5TOKENIZER_BOGUS_DOCTYPE: 1.461 + case NS_HTML5TOKENIZER_AFTER_DOCTYPE_SYSTEM_KEYWORD: 1.462 + case NS_HTML5TOKENIZER_BEFORE_DOCTYPE_SYSTEM_IDENTIFIER: 1.463 + case NS_HTML5TOKENIZER_DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED: 1.464 + case NS_HTML5TOKENIZER_DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED: 1.465 + AddClass(sDoctype); 1.466 + break; 1.467 + default: 1.468 + break; 1.469 + } 1.470 + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); 1.471 + NS_ASSERTION(treeOp, "Tree op allocation failed."); 1.472 + treeOp->Init(eTreeOpStreamEnded); 1.473 + FlushOps(); 1.474 +} 1.475 + 1.476 +void 1.477 +nsHtml5Highlighter::SetBuffer(nsHtml5UTF16Buffer* aBuffer) 1.478 +{ 1.479 + NS_PRECONDITION(!mBuffer, "Old buffer still here!"); 1.480 + mBuffer = aBuffer; 1.481 + mCStart = aBuffer->getStart(); 1.482 +} 1.483 + 1.484 +void 1.485 +nsHtml5Highlighter::DropBuffer(int32_t aPos) 1.486 +{ 1.487 + NS_PRECONDITION(mBuffer, "No buffer to drop!"); 1.488 + mPos = aPos; 1.489 + FlushChars(); 1.490 + mBuffer = nullptr; 1.491 +} 1.492 + 1.493 +void 1.494 +nsHtml5Highlighter::StartSpan() 1.495 +{ 1.496 + FlushChars(); 1.497 + Push(nsGkAtoms::span, nullptr); 1.498 + ++mInlinesOpen; 1.499 +} 1.500 + 1.501 +void 1.502 +nsHtml5Highlighter::StartSpan(const char16_t* aClass) 1.503 +{ 1.504 + StartSpan(); 1.505 + AddClass(aClass); 1.506 +} 1.507 + 1.508 +void 1.509 +nsHtml5Highlighter::EndSpanOrA() 1.510 +{ 1.511 + FlushChars(); 1.512 + Pop(); 1.513 + --mInlinesOpen; 1.514 +} 1.515 + 1.516 +void 1.517 +nsHtml5Highlighter::StartCharacters() 1.518 +{ 1.519 + NS_PRECONDITION(!mInCharacters, "Already in characters!"); 1.520 + FlushChars(); 1.521 + Push(nsGkAtoms::span, nullptr); 1.522 + mCurrentRun = CurrentNode(); 1.523 + mInCharacters = true; 1.524 +} 1.525 + 1.526 +void 1.527 +nsHtml5Highlighter::EndCharactersAndStartMarkupRun() 1.528 +{ 1.529 + NS_PRECONDITION(mInCharacters, "Not in characters!"); 1.530 + FlushChars(); 1.531 + Pop(); 1.532 + mInCharacters = false; 1.533 + // Now start markup run 1.534 + StartSpan(); 1.535 + mCurrentRun = CurrentNode(); 1.536 +} 1.537 + 1.538 +void 1.539 +nsHtml5Highlighter::StartA() 1.540 +{ 1.541 + FlushChars(); 1.542 + Push(nsGkAtoms::a, nullptr); 1.543 + AddClass(sAttributeValue); 1.544 + ++mInlinesOpen; 1.545 +} 1.546 + 1.547 +void 1.548 +nsHtml5Highlighter::FinishTag() 1.549 +{ 1.550 + while (mInlinesOpen > 1) { 1.551 + EndSpanOrA(); 1.552 + } 1.553 + FlushCurrent(); // > 1.554 + EndSpanOrA(); // DATA 1.555 + NS_ASSERTION(!mInlinesOpen, "mInlinesOpen got out of sync!"); 1.556 + StartCharacters(); 1.557 +} 1.558 + 1.559 +void 1.560 +nsHtml5Highlighter::FlushChars() 1.561 +{ 1.562 + if (mCStart < mPos) { 1.563 + char16_t* buf = mBuffer->getBuffer(); 1.564 + int32_t i = mCStart; 1.565 + while (i < mPos) { 1.566 + char16_t c = buf[i]; 1.567 + switch (c) { 1.568 + case '\r': 1.569 + // The input this code sees has been normalized so that there are 1.570 + // CR breaks and LF breaks but no CRLF breaks. Overwrite CR with LF 1.571 + // to show consistent LF line breaks to layout. It is OK to mutate 1.572 + // the input data, because there are no reparses in the View Source 1.573 + // case, so we won't need the original data in the buffer anymore. 1.574 + buf[i] = '\n'; 1.575 + // fall through 1.576 + case '\n': { 1.577 + ++i; 1.578 + if (mCStart < i) { 1.579 + int32_t len = i - mCStart; 1.580 + AppendCharacters(buf, mCStart, len); 1.581 + mCStart = i; 1.582 + } 1.583 + ++mLineNumber; 1.584 + Push(nsGkAtoms::span, nullptr); 1.585 + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); 1.586 + NS_ASSERTION(treeOp, "Tree op allocation failed."); 1.587 + treeOp->InitAddLineNumberId(CurrentNode(), mLineNumber); 1.588 + Pop(); 1.589 + break; 1.590 + } 1.591 + default: 1.592 + ++i; 1.593 + break; 1.594 + } 1.595 + } 1.596 + if (mCStart < mPos) { 1.597 + int32_t len = mPos - mCStart; 1.598 + AppendCharacters(buf, mCStart, len); 1.599 + mCStart = mPos; 1.600 + } 1.601 + } 1.602 +} 1.603 + 1.604 +void 1.605 +nsHtml5Highlighter::FlushCurrent() 1.606 +{ 1.607 + mPos++; 1.608 + FlushChars(); 1.609 +} 1.610 + 1.611 +bool 1.612 +nsHtml5Highlighter::FlushOps() 1.613 +{ 1.614 + bool hasOps = !mOpQueue.IsEmpty(); 1.615 + if (hasOps) { 1.616 + mOpSink->MoveOpsFrom(mOpQueue); 1.617 + } 1.618 + return hasOps; 1.619 +} 1.620 + 1.621 +void 1.622 +nsHtml5Highlighter::MaybeLinkifyAttributeValue(nsHtml5AttributeName* aName, 1.623 + nsString* aValue) 1.624 +{ 1.625 + if (!(nsHtml5AttributeName::ATTR_HREF == aName || 1.626 + nsHtml5AttributeName::ATTR_SRC == aName || 1.627 + nsHtml5AttributeName::ATTR_ACTION == aName || 1.628 + nsHtml5AttributeName::ATTR_CITE == aName || 1.629 + nsHtml5AttributeName::ATTR_BACKGROUND == aName || 1.630 + nsHtml5AttributeName::ATTR_LONGDESC == aName || 1.631 + nsHtml5AttributeName::ATTR_XLINK_HREF == aName || 1.632 + nsHtml5AttributeName::ATTR_DEFINITIONURL == aName)) { 1.633 + return; 1.634 + } 1.635 + AddViewSourceHref(*aValue); 1.636 +} 1.637 + 1.638 +void 1.639 +nsHtml5Highlighter::CompletedNamedCharacterReference() 1.640 +{ 1.641 + AddClass(sEntity); 1.642 +} 1.643 + 1.644 +nsIContent** 1.645 +nsHtml5Highlighter::AllocateContentHandle() 1.646 +{ 1.647 + if (mHandlesUsed == NS_HTML5_HIGHLIGHTER_HANDLE_ARRAY_LENGTH) { 1.648 + mOldHandles.AppendElement(mHandles.forget()); 1.649 + mHandles = new nsIContent*[NS_HTML5_HIGHLIGHTER_HANDLE_ARRAY_LENGTH]; 1.650 + mHandlesUsed = 0; 1.651 + } 1.652 +#ifdef DEBUG 1.653 + mHandles[mHandlesUsed] = (nsIContent*)0xC0DEDBAD; 1.654 +#endif 1.655 + return &mHandles[mHandlesUsed++]; 1.656 +} 1.657 + 1.658 +nsIContent** 1.659 +nsHtml5Highlighter::CreateElement(nsIAtom* aName, 1.660 + nsHtml5HtmlAttributes* aAttributes) 1.661 +{ 1.662 + NS_PRECONDITION(aName, "Got null name."); 1.663 + nsIContent** content = AllocateContentHandle(); 1.664 + mOpQueue.AppendElement()->Init(kNameSpaceID_XHTML, 1.665 + aName, 1.666 + aAttributes, 1.667 + content, 1.668 + true); 1.669 + return content; 1.670 +} 1.671 + 1.672 +nsIContent** 1.673 +nsHtml5Highlighter::CurrentNode() 1.674 +{ 1.675 + NS_PRECONDITION(mStack.Length() >= 1, "Must have something on stack."); 1.676 + return mStack[mStack.Length() - 1]; 1.677 +} 1.678 + 1.679 +void 1.680 +nsHtml5Highlighter::Push(nsIAtom* aName, 1.681 + nsHtml5HtmlAttributes* aAttributes) 1.682 +{ 1.683 + NS_PRECONDITION(mStack.Length() >= 1, "Pushing without root."); 1.684 + nsIContent** elt = CreateElement(aName, aAttributes); // Don't inline below! 1.685 + mOpQueue.AppendElement()->Init(eTreeOpAppend, elt, CurrentNode()); 1.686 + mStack.AppendElement(elt); 1.687 +} 1.688 + 1.689 +void 1.690 +nsHtml5Highlighter::Pop() 1.691 +{ 1.692 + NS_PRECONDITION(mStack.Length() >= 2, "Popping when stack too short."); 1.693 + mStack.RemoveElementAt(mStack.Length() - 1); 1.694 +} 1.695 + 1.696 +void 1.697 +nsHtml5Highlighter::AppendCharacters(const char16_t* aBuffer, 1.698 + int32_t aStart, 1.699 + int32_t aLength) 1.700 +{ 1.701 + NS_PRECONDITION(aBuffer, "Null buffer"); 1.702 + 1.703 + char16_t* bufferCopy = new char16_t[aLength]; 1.704 + memcpy(bufferCopy, aBuffer + aStart, aLength * sizeof(char16_t)); 1.705 + 1.706 + mOpQueue.AppendElement()->Init(eTreeOpAppendText, 1.707 + bufferCopy, 1.708 + aLength, 1.709 + CurrentNode()); 1.710 +} 1.711 + 1.712 + 1.713 +void 1.714 +nsHtml5Highlighter::AddClass(const char16_t* aClass) 1.715 +{ 1.716 + if (!mSyntaxHighlight) { 1.717 + return; 1.718 + } 1.719 + mOpQueue.AppendElement()->InitAddClass(CurrentNode(), aClass); 1.720 +} 1.721 + 1.722 +void 1.723 +nsHtml5Highlighter::AddViewSourceHref(const nsString& aValue) 1.724 +{ 1.725 + char16_t* bufferCopy = new char16_t[aValue.Length() + 1]; 1.726 + memcpy(bufferCopy, aValue.get(), aValue.Length() * sizeof(char16_t)); 1.727 + bufferCopy[aValue.Length()] = 0; 1.728 + 1.729 + mOpQueue.AppendElement()->Init(eTreeOpAddViewSourceHref, 1.730 + bufferCopy, 1.731 + aValue.Length(), 1.732 + CurrentNode()); 1.733 +} 1.734 + 1.735 +void 1.736 +nsHtml5Highlighter::AddErrorToCurrentNode(const char* aMsgId) 1.737 +{ 1.738 + if (!mSyntaxHighlight) { 1.739 + return; 1.740 + } 1.741 + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); 1.742 + NS_ASSERTION(treeOp, "Tree op allocation failed."); 1.743 + treeOp->Init(CurrentNode(), aMsgId); 1.744 +} 1.745 + 1.746 +void 1.747 +nsHtml5Highlighter::AddErrorToCurrentRun(const char* aMsgId) 1.748 +{ 1.749 + if (!mSyntaxHighlight) { 1.750 + return; 1.751 + } 1.752 + NS_PRECONDITION(mCurrentRun, "Adding error to run without one!"); 1.753 + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); 1.754 + NS_ASSERTION(treeOp, "Tree op allocation failed."); 1.755 + treeOp->Init(mCurrentRun, aMsgId); 1.756 +} 1.757 + 1.758 +void 1.759 +nsHtml5Highlighter::AddErrorToCurrentRun(const char* aMsgId, 1.760 + nsIAtom* aName) 1.761 +{ 1.762 + if (!mSyntaxHighlight) { 1.763 + return; 1.764 + } 1.765 + NS_PRECONDITION(mCurrentRun, "Adding error to run without one!"); 1.766 + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); 1.767 + NS_ASSERTION(treeOp, "Tree op allocation failed."); 1.768 + treeOp->Init(mCurrentRun, aMsgId, aName); 1.769 +} 1.770 + 1.771 +void 1.772 +nsHtml5Highlighter::AddErrorToCurrentRun(const char* aMsgId, 1.773 + nsIAtom* aName, 1.774 + nsIAtom* aOther) 1.775 +{ 1.776 + if (!mSyntaxHighlight) { 1.777 + return; 1.778 + } 1.779 + NS_PRECONDITION(mCurrentRun, "Adding error to run without one!"); 1.780 + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); 1.781 + NS_ASSERTION(treeOp, "Tree op allocation failed."); 1.782 + treeOp->Init(mCurrentRun, aMsgId, aName, aOther); 1.783 +} 1.784 + 1.785 +void 1.786 +nsHtml5Highlighter::AddErrorToCurrentAmpersand(const char* aMsgId) 1.787 +{ 1.788 + if (!mSyntaxHighlight) { 1.789 + return; 1.790 + } 1.791 + NS_PRECONDITION(mAmpersand, "Adding error to ampersand without one!"); 1.792 + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); 1.793 + NS_ASSERTION(treeOp, "Tree op allocation failed."); 1.794 + treeOp->Init(mAmpersand, aMsgId); 1.795 +} 1.796 + 1.797 +void 1.798 +nsHtml5Highlighter::AddErrorToCurrentSlash(const char* aMsgId) 1.799 +{ 1.800 + if (!mSyntaxHighlight) { 1.801 + return; 1.802 + } 1.803 + NS_PRECONDITION(mSlash, "Adding error to slash without one!"); 1.804 + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); 1.805 + NS_ASSERTION(treeOp, "Tree op allocation failed."); 1.806 + treeOp->Init(mSlash, aMsgId); 1.807 +}