1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/parser/html/nsHtml5TreeBuilderCppSupplement.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1461 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=2 sw=2 et tw=78: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "nsError.h" 1.11 +#include "nsIPresShell.h" 1.12 +#include "nsNodeUtils.h" 1.13 +#include "nsIFrame.h" 1.14 +#include "mozilla/Likely.h" 1.15 + 1.16 +class nsPresContext; 1.17 + 1.18 +nsHtml5TreeBuilder::nsHtml5TreeBuilder(nsHtml5OplessBuilder* aBuilder) 1.19 + : scriptingEnabled(false) 1.20 + , fragment(false) 1.21 + , contextNode(nullptr) 1.22 + , formPointer(nullptr) 1.23 + , headPointer(nullptr) 1.24 + , mBuilder(aBuilder) 1.25 + , mViewSource(nullptr) 1.26 + , mOpSink(nullptr) 1.27 + , mHandles(nullptr) 1.28 + , mHandlesUsed(0) 1.29 + , mSpeculativeLoadStage(nullptr) 1.30 + , mCurrentHtmlScriptIsAsyncOrDefer(false) 1.31 + , mPreventScriptExecution(false) 1.32 +#ifdef DEBUG 1.33 + , mActive(false) 1.34 +#endif 1.35 +{ 1.36 + MOZ_COUNT_CTOR(nsHtml5TreeBuilder); 1.37 +} 1.38 + 1.39 +nsHtml5TreeBuilder::nsHtml5TreeBuilder(nsAHtml5TreeOpSink* aOpSink, 1.40 + nsHtml5TreeOpStage* aStage) 1.41 + : scriptingEnabled(false) 1.42 + , fragment(false) 1.43 + , contextNode(nullptr) 1.44 + , formPointer(nullptr) 1.45 + , headPointer(nullptr) 1.46 + , mBuilder(nullptr) 1.47 + , mViewSource(nullptr) 1.48 + , mOpSink(aOpSink) 1.49 + , mHandles(new nsIContent*[NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH]) 1.50 + , mHandlesUsed(0) 1.51 + , mSpeculativeLoadStage(aStage) 1.52 + , mCurrentHtmlScriptIsAsyncOrDefer(false) 1.53 + , mPreventScriptExecution(false) 1.54 +#ifdef DEBUG 1.55 + , mActive(false) 1.56 +#endif 1.57 +{ 1.58 + MOZ_COUNT_CTOR(nsHtml5TreeBuilder); 1.59 +} 1.60 + 1.61 +nsHtml5TreeBuilder::~nsHtml5TreeBuilder() 1.62 +{ 1.63 + MOZ_COUNT_DTOR(nsHtml5TreeBuilder); 1.64 + NS_ASSERTION(!mActive, "nsHtml5TreeBuilder deleted without ever calling end() on it!"); 1.65 + mOpQueue.Clear(); 1.66 +} 1.67 + 1.68 +nsIContentHandle* 1.69 +nsHtml5TreeBuilder::createElement(int32_t aNamespace, nsIAtom* aName, nsHtml5HtmlAttributes* aAttributes) 1.70 +{ 1.71 + NS_PRECONDITION(aAttributes, "Got null attributes."); 1.72 + NS_PRECONDITION(aName, "Got null name."); 1.73 + NS_PRECONDITION(aNamespace == kNameSpaceID_XHTML || 1.74 + aNamespace == kNameSpaceID_SVG || 1.75 + aNamespace == kNameSpaceID_MathML, 1.76 + "Bogus namespace."); 1.77 + 1.78 + if (mBuilder) { 1.79 + nsCOMPtr<nsIAtom> name = nsHtml5TreeOperation::Reget(aName); 1.80 + nsIContent* elem = 1.81 + nsHtml5TreeOperation::CreateElement(aNamespace, 1.82 + name, 1.83 + aAttributes, 1.84 + mozilla::dom::FROM_PARSER_FRAGMENT, 1.85 + mBuilder); 1.86 + if (MOZ_UNLIKELY(aAttributes != tokenizer->GetAttributes() && 1.87 + aAttributes != nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES)) { 1.88 + delete aAttributes; 1.89 + } 1.90 + return elem; 1.91 + } 1.92 + 1.93 + nsIContentHandle* content = AllocateContentHandle(); 1.94 + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); 1.95 + NS_ASSERTION(treeOp, "Tree op allocation failed."); 1.96 + treeOp->Init(aNamespace, 1.97 + aName, 1.98 + aAttributes, 1.99 + content, 1.100 + !!mSpeculativeLoadStage); 1.101 + // mSpeculativeLoadStage is non-null only in the off-the-main-thread 1.102 + // tree builder, which handles the network stream 1.103 + 1.104 + // Start wall of code for speculative loading and line numbers 1.105 + 1.106 + if (mSpeculativeLoadStage) { 1.107 + switch (aNamespace) { 1.108 + case kNameSpaceID_XHTML: 1.109 + if (nsHtml5Atoms::img == aName) { 1.110 + nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_SRC); 1.111 + if (url) { 1.112 + nsString* crossOrigin = 1.113 + aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN); 1.114 + mSpeculativeLoadQueue.AppendElement()-> 1.115 + InitImage(*url, 1.116 + crossOrigin ? *crossOrigin : NullString()); 1.117 + } 1.118 + } else if (nsHtml5Atoms::script == aName) { 1.119 + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); 1.120 + NS_ASSERTION(treeOp, "Tree op allocation failed."); 1.121 + treeOp->Init(eTreeOpSetScriptLineNumberAndFreeze, content, tokenizer->getLineNumber()); 1.122 + 1.123 + nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_SRC); 1.124 + if (url) { 1.125 + nsString* charset = aAttributes->getValue(nsHtml5AttributeName::ATTR_CHARSET); 1.126 + nsString* type = aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE); 1.127 + nsString* crossOrigin = 1.128 + aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN); 1.129 + mSpeculativeLoadQueue.AppendElement()-> 1.130 + InitScript(*url, 1.131 + (charset) ? *charset : EmptyString(), 1.132 + (type) ? *type : EmptyString(), 1.133 + (crossOrigin) ? *crossOrigin : NullString(), 1.134 + mode == NS_HTML5TREE_BUILDER_IN_HEAD); 1.135 + mCurrentHtmlScriptIsAsyncOrDefer = 1.136 + aAttributes->contains(nsHtml5AttributeName::ATTR_ASYNC) || 1.137 + aAttributes->contains(nsHtml5AttributeName::ATTR_DEFER); 1.138 + } 1.139 + } else if (nsHtml5Atoms::link == aName) { 1.140 + nsString* rel = aAttributes->getValue(nsHtml5AttributeName::ATTR_REL); 1.141 + // Not splitting on space here is bogus but the old parser didn't even 1.142 + // do a case-insensitive check. 1.143 + if (rel && rel->LowerCaseEqualsASCII("stylesheet")) { 1.144 + nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF); 1.145 + if (url) { 1.146 + nsString* charset = aAttributes->getValue(nsHtml5AttributeName::ATTR_CHARSET); 1.147 + nsString* crossOrigin = 1.148 + aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN); 1.149 + mSpeculativeLoadQueue.AppendElement()-> 1.150 + InitStyle(*url, 1.151 + (charset) ? *charset : EmptyString(), 1.152 + (crossOrigin) ? *crossOrigin : NullString()); 1.153 + } 1.154 + } 1.155 + } else if (nsHtml5Atoms::video == aName) { 1.156 + nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_POSTER); 1.157 + if (url) { 1.158 + mSpeculativeLoadQueue.AppendElement()->InitImage(*url, NullString()); 1.159 + } 1.160 + } else if (nsHtml5Atoms::style == aName) { 1.161 + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); 1.162 + NS_ASSERTION(treeOp, "Tree op allocation failed."); 1.163 + treeOp->Init(eTreeOpSetStyleLineNumber, content, tokenizer->getLineNumber()); 1.164 + } else if (nsHtml5Atoms::html == aName) { 1.165 + nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_MANIFEST); 1.166 + if (url) { 1.167 + mSpeculativeLoadQueue.AppendElement()->InitManifest(*url); 1.168 + } else { 1.169 + mSpeculativeLoadQueue.AppendElement()->InitManifest(EmptyString()); 1.170 + } 1.171 + } else if (nsHtml5Atoms::base == aName) { 1.172 + nsString* url = 1.173 + aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF); 1.174 + if (url) { 1.175 + mSpeculativeLoadQueue.AppendElement()->InitBase(*url); 1.176 + } 1.177 + } 1.178 + break; 1.179 + case kNameSpaceID_SVG: 1.180 + if (nsHtml5Atoms::image == aName) { 1.181 + nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF); 1.182 + if (url) { 1.183 + mSpeculativeLoadQueue.AppendElement()->InitImage(*url, NullString()); 1.184 + } 1.185 + } else if (nsHtml5Atoms::script == aName) { 1.186 + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); 1.187 + NS_ASSERTION(treeOp, "Tree op allocation failed."); 1.188 + treeOp->Init(eTreeOpSetScriptLineNumberAndFreeze, content, tokenizer->getLineNumber()); 1.189 + 1.190 + nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF); 1.191 + if (url) { 1.192 + nsString* type = aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE); 1.193 + nsString* crossOrigin = 1.194 + aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN); 1.195 + mSpeculativeLoadQueue.AppendElement()-> 1.196 + InitScript(*url, 1.197 + EmptyString(), 1.198 + (type) ? *type : EmptyString(), 1.199 + (crossOrigin) ? *crossOrigin : NullString(), 1.200 + mode == NS_HTML5TREE_BUILDER_IN_HEAD); 1.201 + } 1.202 + } else if (nsHtml5Atoms::style == aName) { 1.203 + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); 1.204 + NS_ASSERTION(treeOp, "Tree op allocation failed."); 1.205 + treeOp->Init(eTreeOpSetStyleLineNumber, content, tokenizer->getLineNumber()); 1.206 + 1.207 + nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF); 1.208 + if (url) { 1.209 + nsString* crossOrigin = 1.210 + aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN); 1.211 + mSpeculativeLoadQueue.AppendElement()-> 1.212 + InitStyle(*url, EmptyString(), 1.213 + (crossOrigin) ? *crossOrigin : NullString()); 1.214 + } 1.215 + } 1.216 + break; 1.217 + } 1.218 + } else if (aNamespace != kNameSpaceID_MathML) { 1.219 + // No speculative loader--just line numbers and defer/async check 1.220 + if (nsHtml5Atoms::style == aName) { 1.221 + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); 1.222 + NS_ASSERTION(treeOp, "Tree op allocation failed."); 1.223 + treeOp->Init(eTreeOpSetStyleLineNumber, content, tokenizer->getLineNumber()); 1.224 + } else if (nsHtml5Atoms::script == aName) { 1.225 + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); 1.226 + NS_ASSERTION(treeOp, "Tree op allocation failed."); 1.227 + treeOp->Init(eTreeOpSetScriptLineNumberAndFreeze, content, tokenizer->getLineNumber()); 1.228 + if (aNamespace == kNameSpaceID_XHTML) { 1.229 + mCurrentHtmlScriptIsAsyncOrDefer = 1.230 + aAttributes->contains(nsHtml5AttributeName::ATTR_SRC) && 1.231 + (aAttributes->contains(nsHtml5AttributeName::ATTR_ASYNC) || 1.232 + aAttributes->contains(nsHtml5AttributeName::ATTR_DEFER)); 1.233 + } 1.234 + } else if (aNamespace == kNameSpaceID_XHTML && nsHtml5Atoms::html == aName) { 1.235 + nsString* url = aAttributes->getValue(nsHtml5AttributeName::ATTR_MANIFEST); 1.236 + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); 1.237 + NS_ASSERTION(treeOp, "Tree op allocation failed."); 1.238 + if (url) { 1.239 + treeOp->Init(eTreeOpProcessOfflineManifest, *url); 1.240 + } else { 1.241 + treeOp->Init(eTreeOpProcessOfflineManifest, EmptyString()); 1.242 + } 1.243 + } 1.244 + } 1.245 + 1.246 + // End wall of code for speculative loading 1.247 + 1.248 + return content; 1.249 +} 1.250 + 1.251 +nsIContentHandle* 1.252 +nsHtml5TreeBuilder::createElement(int32_t aNamespace, nsIAtom* aName, nsHtml5HtmlAttributes* aAttributes, nsIContentHandle* aFormElement) 1.253 +{ 1.254 + nsIContentHandle* content = createElement(aNamespace, aName, aAttributes); 1.255 + if (aFormElement) { 1.256 + if (mBuilder) { 1.257 + nsHtml5TreeOperation::SetFormElement(static_cast<nsIContent*>(content), 1.258 + static_cast<nsIContent*>(aFormElement)); 1.259 + } else { 1.260 + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); 1.261 + NS_ASSERTION(treeOp, "Tree op allocation failed."); 1.262 + treeOp->Init(eTreeOpSetFormElement, content, aFormElement); 1.263 + } 1.264 + } 1.265 + return content; 1.266 +} 1.267 + 1.268 +nsIContentHandle* 1.269 +nsHtml5TreeBuilder::createHtmlElementSetAsRoot(nsHtml5HtmlAttributes* aAttributes) 1.270 +{ 1.271 + nsIContentHandle* content = createElement(kNameSpaceID_XHTML, nsHtml5Atoms::html, aAttributes); 1.272 + if (mBuilder) { 1.273 + nsresult rv = nsHtml5TreeOperation::AppendToDocument(static_cast<nsIContent*>(content), 1.274 + mBuilder); 1.275 + if (NS_FAILED(rv)) { 1.276 + MarkAsBrokenAndRequestSuspension(rv); 1.277 + } 1.278 + } else { 1.279 + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); 1.280 + NS_ASSERTION(treeOp, "Tree op allocation failed."); 1.281 + treeOp->Init(eTreeOpAppendToDocument, content); 1.282 + } 1.283 + return content; 1.284 +} 1.285 + 1.286 +void 1.287 +nsHtml5TreeBuilder::detachFromParent(nsIContentHandle* aElement) 1.288 +{ 1.289 + NS_PRECONDITION(aElement, "Null element"); 1.290 + 1.291 + if (mBuilder) { 1.292 + nsHtml5TreeOperation::Detach(static_cast<nsIContent*>(aElement), 1.293 + mBuilder); 1.294 + return; 1.295 + } 1.296 + 1.297 + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); 1.298 + NS_ASSERTION(treeOp, "Tree op allocation failed."); 1.299 + treeOp->Init(eTreeOpDetach, aElement); 1.300 +} 1.301 + 1.302 +void 1.303 +nsHtml5TreeBuilder::appendElement(nsIContentHandle* aChild, nsIContentHandle* aParent) 1.304 +{ 1.305 + NS_PRECONDITION(aChild, "Null child"); 1.306 + NS_PRECONDITION(aParent, "Null parent"); 1.307 + if (deepTreeSurrogateParent) { 1.308 + return; 1.309 + } 1.310 + 1.311 + if (mBuilder) { 1.312 + nsresult rv = nsHtml5TreeOperation::Append(static_cast<nsIContent*>(aChild), 1.313 + static_cast<nsIContent*>(aParent), 1.314 + mBuilder); 1.315 + if (NS_FAILED(rv)) { 1.316 + MarkAsBrokenAndRequestSuspension(rv); 1.317 + } 1.318 + return; 1.319 + } 1.320 + 1.321 + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); 1.322 + NS_ASSERTION(treeOp, "Tree op allocation failed."); 1.323 + treeOp->Init(eTreeOpAppend, aChild, aParent); 1.324 +} 1.325 + 1.326 +void 1.327 +nsHtml5TreeBuilder::appendChildrenToNewParent(nsIContentHandle* aOldParent, nsIContentHandle* aNewParent) 1.328 +{ 1.329 + NS_PRECONDITION(aOldParent, "Null old parent"); 1.330 + NS_PRECONDITION(aNewParent, "Null new parent"); 1.331 + 1.332 + if (mBuilder) { 1.333 + nsresult rv = nsHtml5TreeOperation::AppendChildrenToNewParent( 1.334 + static_cast<nsIContent*>(aOldParent), 1.335 + static_cast<nsIContent*>(aNewParent), 1.336 + mBuilder); 1.337 + if (NS_FAILED(rv)) { 1.338 + MarkAsBrokenAndRequestSuspension(rv); 1.339 + } 1.340 + return; 1.341 + } 1.342 + 1.343 + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); 1.344 + NS_ASSERTION(treeOp, "Tree op allocation failed."); 1.345 + treeOp->Init(eTreeOpAppendChildrenToNewParent, aOldParent, aNewParent); 1.346 +} 1.347 + 1.348 +void 1.349 +nsHtml5TreeBuilder::insertFosterParentedCharacters(char16_t* aBuffer, int32_t aStart, int32_t aLength, nsIContentHandle* aTable, nsIContentHandle* aStackParent) 1.350 +{ 1.351 + NS_PRECONDITION(aBuffer, "Null buffer"); 1.352 + NS_PRECONDITION(aTable, "Null table"); 1.353 + NS_PRECONDITION(aStackParent, "Null stack parent"); 1.354 + MOZ_ASSERT(!aStart, "aStart must always be zero."); 1.355 + 1.356 + if (mBuilder) { 1.357 + nsresult rv = nsHtml5TreeOperation::FosterParentText( 1.358 + static_cast<nsIContent*>(aStackParent), 1.359 + aBuffer, // XXX aStart always ignored??? 1.360 + aLength, 1.361 + static_cast<nsIContent*>(aTable), 1.362 + mBuilder); 1.363 + if (NS_FAILED(rv)) { 1.364 + MarkAsBrokenAndRequestSuspension(rv); 1.365 + } 1.366 + return; 1.367 + } 1.368 + 1.369 + char16_t* bufferCopy = new char16_t[aLength]; 1.370 + memcpy(bufferCopy, aBuffer, aLength * sizeof(char16_t)); 1.371 + 1.372 + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); 1.373 + NS_ASSERTION(treeOp, "Tree op allocation failed."); 1.374 + treeOp->Init(eTreeOpFosterParentText, bufferCopy, aLength, aStackParent, aTable); 1.375 +} 1.376 + 1.377 +void 1.378 +nsHtml5TreeBuilder::insertFosterParentedChild(nsIContentHandle* aChild, nsIContentHandle* aTable, nsIContentHandle* aStackParent) 1.379 +{ 1.380 + NS_PRECONDITION(aChild, "Null child"); 1.381 + NS_PRECONDITION(aTable, "Null table"); 1.382 + NS_PRECONDITION(aStackParent, "Null stack parent"); 1.383 + 1.384 + if (mBuilder) { 1.385 + nsresult rv = nsHtml5TreeOperation::FosterParent( 1.386 + static_cast<nsIContent*>(aChild), 1.387 + static_cast<nsIContent*>(aStackParent), 1.388 + static_cast<nsIContent*>(aTable), 1.389 + mBuilder); 1.390 + if (NS_FAILED(rv)) { 1.391 + MarkAsBrokenAndRequestSuspension(rv); 1.392 + } 1.393 + return; 1.394 + } 1.395 + 1.396 + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); 1.397 + NS_ASSERTION(treeOp, "Tree op allocation failed."); 1.398 + treeOp->Init(eTreeOpFosterParent, aChild, aStackParent, aTable); 1.399 +} 1.400 + 1.401 +void 1.402 +nsHtml5TreeBuilder::appendCharacters(nsIContentHandle* aParent, char16_t* aBuffer, int32_t aStart, int32_t aLength) 1.403 +{ 1.404 + NS_PRECONDITION(aBuffer, "Null buffer"); 1.405 + NS_PRECONDITION(aParent, "Null parent"); 1.406 + MOZ_ASSERT(!aStart, "aStart must always be zero."); 1.407 + 1.408 + if (mBuilder) { 1.409 + nsresult rv = nsHtml5TreeOperation::AppendText( 1.410 + aBuffer, // XXX aStart always ignored??? 1.411 + aLength, 1.412 + static_cast<nsIContent*>(deepTreeSurrogateParent ? 1.413 + deepTreeSurrogateParent : aParent), 1.414 + mBuilder); 1.415 + if (NS_FAILED(rv)) { 1.416 + MarkAsBrokenAndRequestSuspension(rv); 1.417 + } 1.418 + return; 1.419 + } 1.420 + 1.421 + char16_t* bufferCopy = new char16_t[aLength]; 1.422 + memcpy(bufferCopy, aBuffer, aLength * sizeof(char16_t)); 1.423 + 1.424 + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); 1.425 + NS_ASSERTION(treeOp, "Tree op allocation failed."); 1.426 + treeOp->Init(eTreeOpAppendText, bufferCopy, aLength, 1.427 + deepTreeSurrogateParent ? deepTreeSurrogateParent : aParent); 1.428 +} 1.429 + 1.430 +void 1.431 +nsHtml5TreeBuilder::appendIsindexPrompt(nsIContentHandle* aParent) 1.432 +{ 1.433 + NS_PRECONDITION(aParent, "Null parent"); 1.434 + 1.435 + if (mBuilder) { 1.436 + nsresult rv = nsHtml5TreeOperation::AppendIsindexPrompt( 1.437 + static_cast<nsIContent*>(aParent), 1.438 + mBuilder); 1.439 + if (NS_FAILED(rv)) { 1.440 + MarkAsBrokenAndRequestSuspension(rv); 1.441 + } 1.442 + return; 1.443 + } 1.444 + 1.445 + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); 1.446 + NS_ASSERTION(treeOp, "Tree op allocation failed."); 1.447 + treeOp->Init(eTreeOpAppendIsindexPrompt, aParent); 1.448 +} 1.449 + 1.450 +void 1.451 +nsHtml5TreeBuilder::appendComment(nsIContentHandle* aParent, char16_t* aBuffer, int32_t aStart, int32_t aLength) 1.452 +{ 1.453 + NS_PRECONDITION(aBuffer, "Null buffer"); 1.454 + NS_PRECONDITION(aParent, "Null parent"); 1.455 + MOZ_ASSERT(!aStart, "aStart must always be zero."); 1.456 + 1.457 + if (deepTreeSurrogateParent) { 1.458 + return; 1.459 + } 1.460 + 1.461 + if (mBuilder) { 1.462 + nsresult rv = nsHtml5TreeOperation::AppendComment( 1.463 + static_cast<nsIContent*>(aParent), 1.464 + aBuffer, // XXX aStart always ignored??? 1.465 + aLength, 1.466 + mBuilder); 1.467 + if (NS_FAILED(rv)) { 1.468 + MarkAsBrokenAndRequestSuspension(rv); 1.469 + } 1.470 + return; 1.471 + } 1.472 + 1.473 + char16_t* bufferCopy = new char16_t[aLength]; 1.474 + memcpy(bufferCopy, aBuffer, aLength * sizeof(char16_t)); 1.475 + 1.476 + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); 1.477 + NS_ASSERTION(treeOp, "Tree op allocation failed."); 1.478 + treeOp->Init(eTreeOpAppendComment, bufferCopy, aLength, aParent); 1.479 +} 1.480 + 1.481 +void 1.482 +nsHtml5TreeBuilder::appendCommentToDocument(char16_t* aBuffer, int32_t aStart, int32_t aLength) 1.483 +{ 1.484 + NS_PRECONDITION(aBuffer, "Null buffer"); 1.485 + MOZ_ASSERT(!aStart, "aStart must always be zero."); 1.486 + 1.487 + if (mBuilder) { 1.488 + nsresult rv = nsHtml5TreeOperation::AppendCommentToDocument( 1.489 + aBuffer, // XXX aStart always ignored??? 1.490 + aLength, 1.491 + mBuilder); 1.492 + if (NS_FAILED(rv)) { 1.493 + MarkAsBrokenAndRequestSuspension(rv); 1.494 + } 1.495 + return; 1.496 + } 1.497 + 1.498 + char16_t* bufferCopy = new char16_t[aLength]; 1.499 + memcpy(bufferCopy, aBuffer, aLength * sizeof(char16_t)); 1.500 + 1.501 + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); 1.502 + NS_ASSERTION(treeOp, "Tree op allocation failed."); 1.503 + treeOp->Init(eTreeOpAppendCommentToDocument, bufferCopy, aLength); 1.504 +} 1.505 + 1.506 +void 1.507 +nsHtml5TreeBuilder::addAttributesToElement(nsIContentHandle* aElement, nsHtml5HtmlAttributes* aAttributes) 1.508 +{ 1.509 + NS_PRECONDITION(aElement, "Null element"); 1.510 + NS_PRECONDITION(aAttributes, "Null attributes"); 1.511 + 1.512 + if (aAttributes == nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES) { 1.513 + return; 1.514 + } 1.515 + 1.516 + if (mBuilder) { 1.517 + MOZ_ASSERT(aAttributes == tokenizer->GetAttributes(), 1.518 + "Using attribute other than the tokenizer's to add to body or html."); 1.519 + nsresult rv = nsHtml5TreeOperation::AddAttributes( 1.520 + static_cast<nsIContent*>(aElement), 1.521 + aAttributes, 1.522 + mBuilder); 1.523 + if (NS_FAILED(rv)) { 1.524 + MarkAsBrokenAndRequestSuspension(rv); 1.525 + } 1.526 + return; 1.527 + } 1.528 + 1.529 + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); 1.530 + NS_ASSERTION(treeOp, "Tree op allocation failed."); 1.531 + treeOp->Init(aElement, aAttributes); 1.532 +} 1.533 + 1.534 +void 1.535 +nsHtml5TreeBuilder::markMalformedIfScript(nsIContentHandle* aElement) 1.536 +{ 1.537 + NS_PRECONDITION(aElement, "Null element"); 1.538 + 1.539 + if (mBuilder) { 1.540 + nsHtml5TreeOperation::MarkMalformedIfScript( 1.541 + static_cast<nsIContent*>(aElement)); 1.542 + return; 1.543 + } 1.544 + 1.545 + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); 1.546 + NS_ASSERTION(treeOp, "Tree op allocation failed."); 1.547 + treeOp->Init(eTreeOpMarkMalformedIfScript, aElement); 1.548 +} 1.549 + 1.550 +void 1.551 +nsHtml5TreeBuilder::start(bool fragment) 1.552 +{ 1.553 + mCurrentHtmlScriptIsAsyncOrDefer = false; 1.554 + deepTreeSurrogateParent = nullptr; 1.555 +#ifdef DEBUG 1.556 + mActive = true; 1.557 +#endif 1.558 +} 1.559 + 1.560 +void 1.561 +nsHtml5TreeBuilder::end() 1.562 +{ 1.563 + mOpQueue.Clear(); 1.564 +#ifdef DEBUG 1.565 + mActive = false; 1.566 +#endif 1.567 +} 1.568 + 1.569 +void 1.570 +nsHtml5TreeBuilder::appendDoctypeToDocument(nsIAtom* aName, nsString* aPublicId, nsString* aSystemId) 1.571 +{ 1.572 + NS_PRECONDITION(aName, "Null name"); 1.573 + 1.574 + if (mBuilder) { 1.575 + nsCOMPtr<nsIAtom> name = nsHtml5TreeOperation::Reget(aName); 1.576 + nsresult rv = 1.577 + nsHtml5TreeOperation::AppendDoctypeToDocument(name, 1.578 + *aPublicId, 1.579 + *aSystemId, 1.580 + mBuilder); 1.581 + if (NS_FAILED(rv)) { 1.582 + MarkAsBrokenAndRequestSuspension(rv); 1.583 + } 1.584 + return; 1.585 + } 1.586 + 1.587 + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); 1.588 + NS_ASSERTION(treeOp, "Tree op allocation failed."); 1.589 + treeOp->Init(aName, *aPublicId, *aSystemId); 1.590 + // nsXMLContentSink can flush here, but what's the point? 1.591 + // It can also interrupt here, but we can't. 1.592 +} 1.593 + 1.594 +void 1.595 +nsHtml5TreeBuilder::elementPushed(int32_t aNamespace, nsIAtom* aName, nsIContentHandle* aElement) 1.596 +{ 1.597 + NS_ASSERTION(aNamespace == kNameSpaceID_XHTML || aNamespace == kNameSpaceID_SVG || aNamespace == kNameSpaceID_MathML, "Element isn't HTML, SVG or MathML!"); 1.598 + NS_ASSERTION(aName, "Element doesn't have local name!"); 1.599 + NS_ASSERTION(aElement, "No element!"); 1.600 + /* 1.601 + * The frame constructor uses recursive algorithms, so it can't deal with 1.602 + * arbitrarily deep trees. This is especially a problem on Windows where 1.603 + * the permitted depth of the runtime stack is rather small. 1.604 + * 1.605 + * The following is a protection against author incompetence--not against 1.606 + * malice. There are other ways to make the DOM deep anyway. 1.607 + * 1.608 + * The basic idea is that when the tree builder stack gets too deep, 1.609 + * append operations no longer append to the node that the HTML parsing 1.610 + * algorithm says they should but instead text nodes are append to the last 1.611 + * element that was seen before a magic tree builder stack threshold was 1.612 + * reached and element and comment nodes aren't appended to the DOM at all. 1.613 + * 1.614 + * However, for security reasons, non-child descendant text nodes inside an 1.615 + * SVG script or style element should not become children. Also, non-cell 1.616 + * table elements shouldn't be used as surrogate parents for user experience 1.617 + * reasons. 1.618 + */ 1.619 + if (!deepTreeSurrogateParent && currentPtr >= MAX_REFLOW_DEPTH && 1.620 + !(aName == nsHtml5Atoms::script || 1.621 + aName == nsHtml5Atoms::table || 1.622 + aName == nsHtml5Atoms::thead || 1.623 + aName == nsHtml5Atoms::tfoot || 1.624 + aName == nsHtml5Atoms::tbody || 1.625 + aName == nsHtml5Atoms::tr || 1.626 + aName == nsHtml5Atoms::colgroup || 1.627 + aName == nsHtml5Atoms::style)) { 1.628 + deepTreeSurrogateParent = aElement; 1.629 + } 1.630 + if (aNamespace != kNameSpaceID_XHTML) { 1.631 + return; 1.632 + } 1.633 + if (aName == nsHtml5Atoms::body || aName == nsHtml5Atoms::frameset) { 1.634 + if (mBuilder) { 1.635 + // InnerHTML and DOMParser shouldn't start layout anyway 1.636 + return; 1.637 + } 1.638 + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); 1.639 + NS_ASSERTION(treeOp, "Tree op allocation failed."); 1.640 + treeOp->Init(eTreeOpStartLayout); 1.641 + return; 1.642 + } 1.643 + if (aName == nsHtml5Atoms::input || 1.644 + aName == nsHtml5Atoms::button) { 1.645 + if (!formPointer) { 1.646 + // If form inputs don't belong to a form, their state preservation 1.647 + // won't work right without an append notification flush at this 1.648 + // point. See bug 497861. 1.649 + if (mBuilder) { 1.650 + mBuilder->FlushPendingAppendNotifications(); 1.651 + } else { 1.652 + mOpQueue.AppendElement()->Init(eTreeOpFlushPendingAppendNotifications); 1.653 + } 1.654 + } 1.655 + if (mBuilder) { 1.656 + nsHtml5TreeOperation::DoneCreatingElement(static_cast<nsIContent*>(aElement)); 1.657 + } else { 1.658 + mOpQueue.AppendElement()->Init(eTreeOpDoneCreatingElement, aElement); 1.659 + } 1.660 + return; 1.661 + } 1.662 + if (aName == nsHtml5Atoms::audio || 1.663 + aName == nsHtml5Atoms::video || 1.664 + aName == nsHtml5Atoms::menuitem) { 1.665 + if (mBuilder) { 1.666 + nsHtml5TreeOperation::DoneCreatingElement(static_cast<nsIContent*>(aElement)); 1.667 + } else { 1.668 + mOpQueue.AppendElement()->Init(eTreeOpDoneCreatingElement, aElement); 1.669 + } 1.670 + return; 1.671 + } 1.672 +} 1.673 + 1.674 +void 1.675 +nsHtml5TreeBuilder::elementPopped(int32_t aNamespace, nsIAtom* aName, nsIContentHandle* aElement) 1.676 +{ 1.677 + NS_ASSERTION(aNamespace == kNameSpaceID_XHTML || aNamespace == kNameSpaceID_SVG || aNamespace == kNameSpaceID_MathML, "Element isn't HTML, SVG or MathML!"); 1.678 + NS_ASSERTION(aName, "Element doesn't have local name!"); 1.679 + NS_ASSERTION(aElement, "No element!"); 1.680 + if (deepTreeSurrogateParent && currentPtr <= MAX_REFLOW_DEPTH) { 1.681 + deepTreeSurrogateParent = nullptr; 1.682 + } 1.683 + if (aNamespace == kNameSpaceID_MathML) { 1.684 + return; 1.685 + } 1.686 + // we now have only SVG and HTML 1.687 + if (aName == nsHtml5Atoms::script) { 1.688 + if (mPreventScriptExecution) { 1.689 + if (mBuilder) { 1.690 + nsHtml5TreeOperation::PreventScriptExecution(static_cast<nsIContent*>(aElement)); 1.691 + return; 1.692 + } 1.693 + mOpQueue.AppendElement()->Init(eTreeOpPreventScriptExecution, aElement); 1.694 + return; 1.695 + } 1.696 + if (mBuilder) { 1.697 + return; 1.698 + } 1.699 + if (mCurrentHtmlScriptIsAsyncOrDefer) { 1.700 + NS_ASSERTION(aNamespace == kNameSpaceID_XHTML, 1.701 + "Only HTML scripts may be async/defer."); 1.702 + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); 1.703 + NS_ASSERTION(treeOp, "Tree op allocation failed."); 1.704 + treeOp->Init(eTreeOpRunScriptAsyncDefer, aElement); 1.705 + mCurrentHtmlScriptIsAsyncOrDefer = false; 1.706 + return; 1.707 + } 1.708 + requestSuspension(); 1.709 + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); 1.710 + NS_ASSERTION(treeOp, "Tree op allocation failed."); 1.711 + treeOp->InitScript(aElement); 1.712 + return; 1.713 + } 1.714 + if (aName == nsHtml5Atoms::title) { 1.715 + if (mBuilder) { 1.716 + nsHtml5TreeOperation::DoneAddingChildren(static_cast<nsIContent*>(aElement), mBuilder); 1.717 + return; 1.718 + } 1.719 + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); 1.720 + NS_ASSERTION(treeOp, "Tree op allocation failed."); 1.721 + treeOp->Init(eTreeOpDoneAddingChildren, aElement); 1.722 + return; 1.723 + } 1.724 + if (aName == nsHtml5Atoms::style || (aNamespace == kNameSpaceID_XHTML && aName == nsHtml5Atoms::link)) { 1.725 + if (mBuilder) { 1.726 + MOZ_ASSERT(!nsContentUtils::IsSafeToRunScript(), 1.727 + "Scripts must be blocked."); 1.728 + mBuilder->FlushPendingAppendNotifications(); 1.729 + mBuilder->UpdateStyleSheet(static_cast<nsIContent*>(aElement)); 1.730 + return; 1.731 + } 1.732 + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); 1.733 + NS_ASSERTION(treeOp, "Tree op allocation failed."); 1.734 + treeOp->Init(eTreeOpUpdateStyleSheet, aElement); 1.735 + return; 1.736 + } 1.737 + if (aNamespace == kNameSpaceID_SVG) { 1.738 + if (aName == nsHtml5Atoms::svg) { 1.739 + if (mBuilder) { 1.740 + nsHtml5TreeOperation::SvgLoad(static_cast<nsIContent*>(aElement)); 1.741 + return; 1.742 + } 1.743 + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); 1.744 + NS_ASSERTION(treeOp, "Tree op allocation failed."); 1.745 + treeOp->Init(eTreeOpSvgLoad, aElement); 1.746 + } 1.747 + return; 1.748 + } 1.749 + // we now have only HTML 1.750 + // Some HTML nodes need DoneAddingChildren() called to initialize 1.751 + // properly (e.g. form state restoration). 1.752 + // XXX expose ElementName group here and do switch 1.753 + if (aName == nsHtml5Atoms::object || 1.754 + aName == nsHtml5Atoms::applet) { 1.755 + if (mBuilder) { 1.756 + nsHtml5TreeOperation::DoneAddingChildren(static_cast<nsIContent*>(aElement), mBuilder); 1.757 + return; 1.758 + } 1.759 + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); 1.760 + NS_ASSERTION(treeOp, "Tree op allocation failed."); 1.761 + treeOp->Init(eTreeOpDoneAddingChildren, aElement); 1.762 + return; 1.763 + } 1.764 + if (aName == nsHtml5Atoms::select || 1.765 + aName == nsHtml5Atoms::textarea) { 1.766 + if (!formPointer) { 1.767 + // If form inputs don't belong to a form, their state preservation 1.768 + // won't work right without an append notification flush at this 1.769 + // point. See bug 497861 and bug 539895. 1.770 + if (mBuilder) { 1.771 + mBuilder->FlushPendingAppendNotifications(); 1.772 + } else { 1.773 + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); 1.774 + NS_ASSERTION(treeOp, "Tree op allocation failed."); 1.775 + treeOp->Init(eTreeOpFlushPendingAppendNotifications); 1.776 + } 1.777 + } 1.778 + if (mBuilder) { 1.779 + nsHtml5TreeOperation::DoneAddingChildren(static_cast<nsIContent*>(aElement), mBuilder); 1.780 + return; 1.781 + } 1.782 + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); 1.783 + NS_ASSERTION(treeOp, "Tree op allocation failed."); 1.784 + treeOp->Init(eTreeOpDoneAddingChildren, aElement); 1.785 + return; 1.786 + } 1.787 + if (aName == nsHtml5Atoms::meta && !fragment && !mBuilder) { 1.788 + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); 1.789 + NS_ASSERTION(treeOp, "Tree op allocation failed."); 1.790 + treeOp->Init(eTreeOpProcessMeta, aElement); 1.791 + return; 1.792 + } 1.793 + return; 1.794 +} 1.795 + 1.796 +void 1.797 +nsHtml5TreeBuilder::accumulateCharacters(const char16_t* aBuf, int32_t aStart, int32_t aLength) 1.798 +{ 1.799 + int32_t newFillLen = charBufferLen + aLength; 1.800 + if (newFillLen > charBuffer.length) { 1.801 + int32_t newAllocLength = newFillLen + (newFillLen >> 1); 1.802 + jArray<char16_t,int32_t> newBuf = jArray<char16_t,int32_t>::newJArray(newAllocLength); 1.803 + memcpy(newBuf, charBuffer, sizeof(char16_t) * charBufferLen); 1.804 + charBuffer = newBuf; 1.805 + } 1.806 + memcpy(charBuffer + charBufferLen, aBuf + aStart, sizeof(char16_t) * aLength); 1.807 + charBufferLen = newFillLen; 1.808 +} 1.809 + 1.810 +nsIContentHandle* 1.811 +nsHtml5TreeBuilder::AllocateContentHandle() 1.812 +{ 1.813 + if (MOZ_UNLIKELY(mBuilder)) { 1.814 + MOZ_ASSUME_UNREACHABLE("Must never allocate a handle with builder."); 1.815 + return nullptr; 1.816 + } 1.817 + if (mHandlesUsed == NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH) { 1.818 + mOldHandles.AppendElement(mHandles.forget()); 1.819 + mHandles = new nsIContent*[NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH]; 1.820 + mHandlesUsed = 0; 1.821 + } 1.822 +#ifdef DEBUG 1.823 + mHandles[mHandlesUsed] = (nsIContent*)0xC0DEDBAD; 1.824 +#endif 1.825 + return &mHandles[mHandlesUsed++]; 1.826 +} 1.827 + 1.828 +bool 1.829 +nsHtml5TreeBuilder::HasScript() 1.830 +{ 1.831 + uint32_t len = mOpQueue.Length(); 1.832 + if (!len) { 1.833 + return false; 1.834 + } 1.835 + return mOpQueue.ElementAt(len - 1).IsRunScript(); 1.836 +} 1.837 + 1.838 +bool 1.839 +nsHtml5TreeBuilder::Flush(bool aDiscretionary) 1.840 +{ 1.841 + if (MOZ_UNLIKELY(mBuilder)) { 1.842 + MOZ_ASSUME_UNREACHABLE("Must never flush with builder."); 1.843 + return false; 1.844 + } 1.845 + if (!aDiscretionary || 1.846 + !(charBufferLen && 1.847 + currentPtr >= 0 && 1.848 + stack[currentPtr]->isFosterParenting())) { 1.849 + // Don't flush text on discretionary flushes if the current element on 1.850 + // the stack is a foster-parenting element and there's pending text, 1.851 + // because flushing in that case would make the tree shape dependent on 1.852 + // where the flush points fall. 1.853 + flushCharacters(); 1.854 + } 1.855 + FlushLoads(); 1.856 + if (mOpSink) { 1.857 + bool hasOps = !mOpQueue.IsEmpty(); 1.858 + if (hasOps) { 1.859 + mOpSink->MoveOpsFrom(mOpQueue); 1.860 + } 1.861 + return hasOps; 1.862 + } 1.863 + // no op sink: throw away ops 1.864 + mOpQueue.Clear(); 1.865 + return false; 1.866 +} 1.867 + 1.868 +void 1.869 +nsHtml5TreeBuilder::FlushLoads() 1.870 +{ 1.871 + if (MOZ_UNLIKELY(mBuilder)) { 1.872 + MOZ_ASSUME_UNREACHABLE("Must never flush loads with builder."); 1.873 + return; 1.874 + } 1.875 + if (!mSpeculativeLoadQueue.IsEmpty()) { 1.876 + mSpeculativeLoadStage->MoveSpeculativeLoadsFrom(mSpeculativeLoadQueue); 1.877 + } 1.878 +} 1.879 + 1.880 +void 1.881 +nsHtml5TreeBuilder::SetDocumentCharset(nsACString& aCharset, 1.882 + int32_t aCharsetSource) 1.883 +{ 1.884 + if (mBuilder) { 1.885 + mBuilder->SetDocumentCharsetAndSource(aCharset, aCharsetSource); 1.886 + } else if (mSpeculativeLoadStage) { 1.887 + mSpeculativeLoadQueue.AppendElement()->InitSetDocumentCharset( 1.888 + aCharset, aCharsetSource); 1.889 + } else { 1.890 + mOpQueue.AppendElement()->Init( 1.891 + eTreeOpSetDocumentCharset, aCharset, aCharsetSource); 1.892 + } 1.893 +} 1.894 + 1.895 +void 1.896 +nsHtml5TreeBuilder::StreamEnded() 1.897 +{ 1.898 + MOZ_ASSERT(!mBuilder, "Must not call StreamEnded with builder."); 1.899 + MOZ_ASSERT(!fragment, "Must not parse fragments off the main thread."); 1.900 + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); 1.901 + NS_ASSERTION(treeOp, "Tree op allocation failed."); 1.902 + treeOp->Init(eTreeOpStreamEnded); 1.903 +} 1.904 + 1.905 +void 1.906 +nsHtml5TreeBuilder::NeedsCharsetSwitchTo(const nsACString& aCharset, 1.907 + int32_t aCharsetSource, 1.908 + int32_t aLineNumber) 1.909 +{ 1.910 + if (MOZ_UNLIKELY(mBuilder)) { 1.911 + MOZ_ASSUME_UNREACHABLE("Must never switch charset with builder."); 1.912 + return; 1.913 + } 1.914 + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); 1.915 + NS_ASSERTION(treeOp, "Tree op allocation failed."); 1.916 + treeOp->Init(eTreeOpNeedsCharsetSwitchTo, 1.917 + aCharset, 1.918 + aCharsetSource, 1.919 + aLineNumber); 1.920 +} 1.921 + 1.922 +void 1.923 +nsHtml5TreeBuilder::MaybeComplainAboutCharset(const char* aMsgId, 1.924 + bool aError, 1.925 + int32_t aLineNumber) 1.926 +{ 1.927 + if (MOZ_UNLIKELY(mBuilder)) { 1.928 + MOZ_ASSUME_UNREACHABLE("Must never complain about charset with builder."); 1.929 + return; 1.930 + } 1.931 + mOpQueue.AppendElement()->Init(aMsgId, aError, aLineNumber); 1.932 +} 1.933 + 1.934 +void 1.935 +nsHtml5TreeBuilder::AddSnapshotToScript(nsAHtml5TreeBuilderState* aSnapshot, int32_t aLine) 1.936 +{ 1.937 + if (MOZ_UNLIKELY(mBuilder)) { 1.938 + MOZ_ASSUME_UNREACHABLE("Must never use snapshots with builder."); 1.939 + return; 1.940 + } 1.941 + NS_PRECONDITION(HasScript(), "No script to add a snapshot to!"); 1.942 + NS_PRECONDITION(aSnapshot, "Got null snapshot."); 1.943 + mOpQueue.ElementAt(mOpQueue.Length() - 1).SetSnapshot(aSnapshot, aLine); 1.944 +} 1.945 + 1.946 +void 1.947 +nsHtml5TreeBuilder::DropHandles() 1.948 +{ 1.949 + MOZ_ASSERT(!mBuilder, "Must not drop handles with builder."); 1.950 + mOldHandles.Clear(); 1.951 + mHandlesUsed = 0; 1.952 +} 1.953 + 1.954 +void 1.955 +nsHtml5TreeBuilder::MarkAsBroken(nsresult aRv) 1.956 +{ 1.957 + if (MOZ_UNLIKELY(mBuilder)) { 1.958 + MOZ_ASSUME_UNREACHABLE("Must not call this with builder."); 1.959 + return; 1.960 + } 1.961 + mOpQueue.Clear(); // Previous ops don't matter anymore 1.962 + mOpQueue.AppendElement()->Init(aRv); 1.963 +} 1.964 + 1.965 +void 1.966 +nsHtml5TreeBuilder::StartPlainTextViewSource(const nsAutoString& aTitle) 1.967 +{ 1.968 + MOZ_ASSERT(!mBuilder, "Must not view source with builder."); 1.969 + startTag(nsHtml5ElementName::ELT_TITLE, 1.970 + nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES, 1.971 + false); 1.972 + 1.973 + // XUL will add the "Source of: " prefix. 1.974 + uint32_t length = aTitle.Length(); 1.975 + if (length > INT32_MAX) { 1.976 + length = INT32_MAX; 1.977 + } 1.978 + characters(aTitle.get(), 0, (int32_t)length); 1.979 + endTag(nsHtml5ElementName::ELT_TITLE); 1.980 + 1.981 + startTag(nsHtml5ElementName::ELT_LINK, 1.982 + nsHtml5ViewSourceUtils::NewLinkAttributes(), 1.983 + false); 1.984 + 1.985 + startTag(nsHtml5ElementName::ELT_BODY, 1.986 + nsHtml5ViewSourceUtils::NewBodyAttributes(), 1.987 + false); 1.988 + 1.989 + StartPlainTextBody(); 1.990 +} 1.991 + 1.992 +void 1.993 +nsHtml5TreeBuilder::StartPlainText() 1.994 +{ 1.995 + MOZ_ASSERT(!mBuilder, "Must not view source with builder."); 1.996 + startTag(nsHtml5ElementName::ELT_LINK, 1.997 + nsHtml5PlainTextUtils::NewLinkAttributes(), 1.998 + false); 1.999 + 1.1000 + StartPlainTextBody(); 1.1001 +} 1.1002 + 1.1003 +void 1.1004 +nsHtml5TreeBuilder::StartPlainTextBody() 1.1005 +{ 1.1006 + MOZ_ASSERT(!mBuilder, "Must not view source with builder."); 1.1007 + startTag(nsHtml5ElementName::ELT_PRE, 1.1008 + nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES, 1.1009 + false); 1.1010 + needToDropLF = false; 1.1011 +} 1.1012 + 1.1013 +// DocumentModeHandler 1.1014 +void 1.1015 +nsHtml5TreeBuilder::documentMode(nsHtml5DocumentMode m) 1.1016 +{ 1.1017 + if (mBuilder) { 1.1018 + mBuilder->SetDocumentMode(m); 1.1019 + return; 1.1020 + } 1.1021 + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); 1.1022 + NS_ASSERTION(treeOp, "Tree op allocation failed."); 1.1023 + treeOp->Init(m); 1.1024 +} 1.1025 + 1.1026 +nsIContentHandle* 1.1027 +nsHtml5TreeBuilder::getDocumentFragmentForTemplate(nsIContentHandle* aTemplate) 1.1028 +{ 1.1029 + if (mBuilder) { 1.1030 + return nsHtml5TreeOperation::GetDocumentFragmentForTemplate(static_cast<nsIContent*>(aTemplate)); 1.1031 + } 1.1032 + nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); 1.1033 + NS_ASSERTION(treeOp, "Tree op allocation failed."); 1.1034 + nsIContentHandle* fragHandle = AllocateContentHandle(); 1.1035 + treeOp->Init(eTreeOpGetDocumentFragmentForTemplate, aTemplate, fragHandle); 1.1036 + return fragHandle; 1.1037 +} 1.1038 + 1.1039 +nsIContentHandle* 1.1040 +nsHtml5TreeBuilder::getFormPointerForContext(nsIContentHandle* aContext) 1.1041 +{ 1.1042 + MOZ_ASSERT(mBuilder, "Must have builder."); 1.1043 + if (!aContext) { 1.1044 + return nullptr; 1.1045 + } 1.1046 + 1.1047 + MOZ_ASSERT(NS_IsMainThread()); 1.1048 + 1.1049 + // aContext must always be an element that already exists 1.1050 + // in the document. 1.1051 + nsIContent* contextNode = static_cast<nsIContent*>(aContext); 1.1052 + nsIContent* currentAncestor = contextNode; 1.1053 + 1.1054 + // We traverse the ancestors of the context node to find the nearest 1.1055 + // form pointer. This traversal is why aContext must not be an emtpy handle. 1.1056 + nsIContent* nearestForm = nullptr; 1.1057 + while (currentAncestor) { 1.1058 + if (currentAncestor->IsHTML(nsGkAtoms::form)) { 1.1059 + nearestForm = currentAncestor; 1.1060 + break; 1.1061 + } 1.1062 + currentAncestor = currentAncestor->GetParent(); 1.1063 + } 1.1064 + 1.1065 + if (!nearestForm) { 1.1066 + return nullptr; 1.1067 + } 1.1068 + 1.1069 + return nearestForm; 1.1070 +} 1.1071 + 1.1072 +// Error reporting 1.1073 + 1.1074 +void 1.1075 +nsHtml5TreeBuilder::EnableViewSource(nsHtml5Highlighter* aHighlighter) 1.1076 +{ 1.1077 + MOZ_ASSERT(!mBuilder, "Must not view source with builder."); 1.1078 + mViewSource = aHighlighter; 1.1079 +} 1.1080 + 1.1081 +void 1.1082 +nsHtml5TreeBuilder::errStrayStartTag(nsIAtom* aName) 1.1083 +{ 1.1084 + if (MOZ_UNLIKELY(mViewSource)) { 1.1085 + mViewSource->AddErrorToCurrentRun("errStrayStartTag2", aName); 1.1086 + } 1.1087 +} 1.1088 + 1.1089 +void 1.1090 +nsHtml5TreeBuilder::errStrayEndTag(nsIAtom* aName) 1.1091 +{ 1.1092 + if (MOZ_UNLIKELY(mViewSource)) { 1.1093 + mViewSource->AddErrorToCurrentRun("errStrayEndTag", aName); 1.1094 + } 1.1095 +} 1.1096 + 1.1097 +void 1.1098 +nsHtml5TreeBuilder::errUnclosedElements(int32_t aIndex, nsIAtom* aName) 1.1099 +{ 1.1100 + if (MOZ_UNLIKELY(mViewSource)) { 1.1101 + mViewSource->AddErrorToCurrentRun("errUnclosedElements", aName); 1.1102 + } 1.1103 +} 1.1104 + 1.1105 +void 1.1106 +nsHtml5TreeBuilder::errUnclosedElementsImplied(int32_t aIndex, nsIAtom* aName) 1.1107 +{ 1.1108 + if (MOZ_UNLIKELY(mViewSource)) { 1.1109 + mViewSource->AddErrorToCurrentRun("errUnclosedElementsImplied", 1.1110 + aName); 1.1111 + } 1.1112 +} 1.1113 + 1.1114 +void 1.1115 +nsHtml5TreeBuilder::errUnclosedElementsCell(int32_t aIndex) 1.1116 +{ 1.1117 + if (MOZ_UNLIKELY(mViewSource)) { 1.1118 + mViewSource->AddErrorToCurrentRun("errUnclosedElementsCell"); 1.1119 + } 1.1120 +} 1.1121 + 1.1122 +void 1.1123 +nsHtml5TreeBuilder::errStrayDoctype() 1.1124 +{ 1.1125 + if (MOZ_UNLIKELY(mViewSource)) { 1.1126 + mViewSource->AddErrorToCurrentRun("errStrayDoctype"); 1.1127 + } 1.1128 +} 1.1129 + 1.1130 +void 1.1131 +nsHtml5TreeBuilder::errAlmostStandardsDoctype() 1.1132 +{ 1.1133 + if (MOZ_UNLIKELY(mViewSource) && !isSrcdocDocument) { 1.1134 + mViewSource->AddErrorToCurrentRun("errAlmostStandardsDoctype"); 1.1135 + } 1.1136 +} 1.1137 + 1.1138 +void 1.1139 +nsHtml5TreeBuilder::errQuirkyDoctype() 1.1140 +{ 1.1141 + if (MOZ_UNLIKELY(mViewSource) && !isSrcdocDocument) { 1.1142 + mViewSource->AddErrorToCurrentRun("errQuirkyDoctype"); 1.1143 + } 1.1144 +} 1.1145 + 1.1146 +void 1.1147 +nsHtml5TreeBuilder::errNonSpaceInTrailer() 1.1148 +{ 1.1149 + if (MOZ_UNLIKELY(mViewSource)) { 1.1150 + mViewSource->AddErrorToCurrentRun("errNonSpaceInTrailer"); 1.1151 + } 1.1152 +} 1.1153 + 1.1154 +void 1.1155 +nsHtml5TreeBuilder::errNonSpaceAfterFrameset() 1.1156 +{ 1.1157 + if (MOZ_UNLIKELY(mViewSource)) { 1.1158 + mViewSource->AddErrorToCurrentRun("errNonSpaceAfterFrameset"); 1.1159 + } 1.1160 +} 1.1161 + 1.1162 +void 1.1163 +nsHtml5TreeBuilder::errNonSpaceInFrameset() 1.1164 +{ 1.1165 + if (MOZ_UNLIKELY(mViewSource)) { 1.1166 + mViewSource->AddErrorToCurrentRun("errNonSpaceInFrameset"); 1.1167 + } 1.1168 +} 1.1169 + 1.1170 +void 1.1171 +nsHtml5TreeBuilder::errNonSpaceAfterBody() 1.1172 +{ 1.1173 + if (MOZ_UNLIKELY(mViewSource)) { 1.1174 + mViewSource->AddErrorToCurrentRun("errNonSpaceAfterBody"); 1.1175 + } 1.1176 +} 1.1177 + 1.1178 +void 1.1179 +nsHtml5TreeBuilder::errNonSpaceInColgroupInFragment() 1.1180 +{ 1.1181 + if (MOZ_UNLIKELY(mViewSource)) { 1.1182 + mViewSource->AddErrorToCurrentRun("errNonSpaceInColgroupInFragment"); 1.1183 + } 1.1184 +} 1.1185 + 1.1186 +void 1.1187 +nsHtml5TreeBuilder::errNonSpaceInNoscriptInHead() 1.1188 +{ 1.1189 + if (MOZ_UNLIKELY(mViewSource)) { 1.1190 + mViewSource->AddErrorToCurrentRun("errNonSpaceInNoscriptInHead"); 1.1191 + } 1.1192 +} 1.1193 + 1.1194 +void 1.1195 +nsHtml5TreeBuilder::errFooBetweenHeadAndBody(nsIAtom* aName) 1.1196 +{ 1.1197 + if (MOZ_UNLIKELY(mViewSource)) { 1.1198 + mViewSource->AddErrorToCurrentRun("errFooBetweenHeadAndBody", aName); 1.1199 + } 1.1200 +} 1.1201 + 1.1202 +void 1.1203 +nsHtml5TreeBuilder::errStartTagWithoutDoctype() 1.1204 +{ 1.1205 + if (MOZ_UNLIKELY(mViewSource) && !isSrcdocDocument) { 1.1206 + mViewSource->AddErrorToCurrentRun("errStartTagWithoutDoctype"); 1.1207 + } 1.1208 +} 1.1209 + 1.1210 +void 1.1211 +nsHtml5TreeBuilder::errNoSelectInTableScope() 1.1212 +{ 1.1213 + if (MOZ_UNLIKELY(mViewSource)) { 1.1214 + mViewSource->AddErrorToCurrentRun("errNoSelectInTableScope"); 1.1215 + } 1.1216 +} 1.1217 + 1.1218 +void 1.1219 +nsHtml5TreeBuilder::errStartSelectWhereEndSelectExpected() 1.1220 +{ 1.1221 + if (MOZ_UNLIKELY(mViewSource)) { 1.1222 + mViewSource->AddErrorToCurrentRun( 1.1223 + "errStartSelectWhereEndSelectExpected"); 1.1224 + } 1.1225 +} 1.1226 + 1.1227 +void 1.1228 +nsHtml5TreeBuilder::errStartTagWithSelectOpen(nsIAtom* aName) 1.1229 +{ 1.1230 + if (MOZ_UNLIKELY(mViewSource)) { 1.1231 + mViewSource->AddErrorToCurrentRun("errStartTagWithSelectOpen", aName); 1.1232 + } 1.1233 +} 1.1234 + 1.1235 +void 1.1236 +nsHtml5TreeBuilder::errBadStartTagInHead(nsIAtom* aName) 1.1237 +{ 1.1238 + if (MOZ_UNLIKELY(mViewSource)) { 1.1239 + mViewSource->AddErrorToCurrentRun("errBadStartTagInHead2", aName); 1.1240 + } 1.1241 +} 1.1242 + 1.1243 +void 1.1244 +nsHtml5TreeBuilder::errImage() 1.1245 +{ 1.1246 + if (MOZ_UNLIKELY(mViewSource)) { 1.1247 + mViewSource->AddErrorToCurrentRun("errImage"); 1.1248 + } 1.1249 +} 1.1250 + 1.1251 +void 1.1252 +nsHtml5TreeBuilder::errIsindex() 1.1253 +{ 1.1254 + if (MOZ_UNLIKELY(mViewSource)) { 1.1255 + mViewSource->AddErrorToCurrentRun("errIsindex"); 1.1256 + } 1.1257 +} 1.1258 + 1.1259 +void 1.1260 +nsHtml5TreeBuilder::errFooSeenWhenFooOpen(nsIAtom* aName) 1.1261 +{ 1.1262 + if (MOZ_UNLIKELY(mViewSource)) { 1.1263 + mViewSource->AddErrorToCurrentRun("errFooSeenWhenFooOpen", aName); 1.1264 + } 1.1265 +} 1.1266 + 1.1267 +void 1.1268 +nsHtml5TreeBuilder::errHeadingWhenHeadingOpen() 1.1269 +{ 1.1270 + if (MOZ_UNLIKELY(mViewSource)) { 1.1271 + mViewSource->AddErrorToCurrentRun("errHeadingWhenHeadingOpen"); 1.1272 + } 1.1273 +} 1.1274 + 1.1275 +void 1.1276 +nsHtml5TreeBuilder::errFramesetStart() 1.1277 +{ 1.1278 + if (MOZ_UNLIKELY(mViewSource)) { 1.1279 + mViewSource->AddErrorToCurrentRun("errFramesetStart"); 1.1280 + } 1.1281 +} 1.1282 + 1.1283 +void 1.1284 +nsHtml5TreeBuilder::errNoCellToClose() 1.1285 +{ 1.1286 + if (MOZ_UNLIKELY(mViewSource)) { 1.1287 + mViewSource->AddErrorToCurrentRun("errNoCellToClose"); 1.1288 + } 1.1289 +} 1.1290 + 1.1291 +void 1.1292 +nsHtml5TreeBuilder::errStartTagInTable(nsIAtom* aName) 1.1293 +{ 1.1294 + if (MOZ_UNLIKELY(mViewSource)) { 1.1295 + mViewSource->AddErrorToCurrentRun("errStartTagInTable", aName); 1.1296 + } 1.1297 +} 1.1298 + 1.1299 +void 1.1300 +nsHtml5TreeBuilder::errFormWhenFormOpen() 1.1301 +{ 1.1302 + if (MOZ_UNLIKELY(mViewSource)) { 1.1303 + mViewSource->AddErrorToCurrentRun("errFormWhenFormOpen"); 1.1304 + } 1.1305 +} 1.1306 + 1.1307 +void 1.1308 +nsHtml5TreeBuilder::errTableSeenWhileTableOpen() 1.1309 +{ 1.1310 + if (MOZ_UNLIKELY(mViewSource)) { 1.1311 + mViewSource->AddErrorToCurrentRun("errTableSeenWhileTableOpen"); 1.1312 + } 1.1313 +} 1.1314 + 1.1315 +void 1.1316 +nsHtml5TreeBuilder::errStartTagInTableBody(nsIAtom* aName) 1.1317 +{ 1.1318 + if (MOZ_UNLIKELY(mViewSource)) { 1.1319 + mViewSource->AddErrorToCurrentRun("errStartTagInTableBody", aName); 1.1320 + } 1.1321 +} 1.1322 + 1.1323 +void 1.1324 +nsHtml5TreeBuilder::errEndTagSeenWithoutDoctype() 1.1325 +{ 1.1326 + if (MOZ_UNLIKELY(mViewSource) && !isSrcdocDocument) { 1.1327 + mViewSource->AddErrorToCurrentRun("errEndTagSeenWithoutDoctype"); 1.1328 + } 1.1329 +} 1.1330 + 1.1331 +void 1.1332 +nsHtml5TreeBuilder::errEndTagAfterBody() 1.1333 +{ 1.1334 + if (MOZ_UNLIKELY(mViewSource)) { 1.1335 + mViewSource->AddErrorToCurrentRun("errEndTagAfterBody"); 1.1336 + } 1.1337 +} 1.1338 + 1.1339 +void 1.1340 +nsHtml5TreeBuilder::errEndTagSeenWithSelectOpen(nsIAtom* aName) 1.1341 +{ 1.1342 + if (MOZ_UNLIKELY(mViewSource)) { 1.1343 + mViewSource->AddErrorToCurrentRun("errEndTagSeenWithSelectOpen", 1.1344 + aName); 1.1345 + } 1.1346 +} 1.1347 + 1.1348 +void 1.1349 +nsHtml5TreeBuilder::errGarbageInColgroup() 1.1350 +{ 1.1351 + if (MOZ_UNLIKELY(mViewSource)) { 1.1352 + mViewSource->AddErrorToCurrentRun("errGarbageInColgroup"); 1.1353 + } 1.1354 +} 1.1355 + 1.1356 +void 1.1357 +nsHtml5TreeBuilder::errEndTagBr() 1.1358 +{ 1.1359 + if (MOZ_UNLIKELY(mViewSource)) { 1.1360 + mViewSource->AddErrorToCurrentRun("errEndTagBr"); 1.1361 + } 1.1362 +} 1.1363 + 1.1364 +void 1.1365 +nsHtml5TreeBuilder::errNoElementToCloseButEndTagSeen(nsIAtom* aName) 1.1366 +{ 1.1367 + if (MOZ_UNLIKELY(mViewSource)) { 1.1368 + mViewSource->AddErrorToCurrentRun( 1.1369 + "errNoElementToCloseButEndTagSeen", aName); 1.1370 + } 1.1371 +} 1.1372 + 1.1373 +void 1.1374 +nsHtml5TreeBuilder::errHtmlStartTagInForeignContext(nsIAtom* aName) 1.1375 +{ 1.1376 + if (MOZ_UNLIKELY(mViewSource)) { 1.1377 + mViewSource->AddErrorToCurrentRun("errHtmlStartTagInForeignContext", 1.1378 + aName); 1.1379 + } 1.1380 +} 1.1381 + 1.1382 +void 1.1383 +nsHtml5TreeBuilder::errTableClosedWhileCaptionOpen() 1.1384 +{ 1.1385 + if (MOZ_UNLIKELY(mViewSource)) { 1.1386 + mViewSource->AddErrorToCurrentRun("errTableClosedWhileCaptionOpen"); 1.1387 + } 1.1388 +} 1.1389 + 1.1390 +void 1.1391 +nsHtml5TreeBuilder::errNoTableRowToClose() 1.1392 +{ 1.1393 + if (MOZ_UNLIKELY(mViewSource)) { 1.1394 + mViewSource->AddErrorToCurrentRun("errNoTableRowToClose"); 1.1395 + } 1.1396 +} 1.1397 + 1.1398 +void 1.1399 +nsHtml5TreeBuilder::errNonSpaceInTable() 1.1400 +{ 1.1401 + if (MOZ_UNLIKELY(mViewSource)) { 1.1402 + mViewSource->AddErrorToCurrentRun("errNonSpaceInTable"); 1.1403 + } 1.1404 +} 1.1405 + 1.1406 +void 1.1407 +nsHtml5TreeBuilder::errUnclosedChildrenInRuby() 1.1408 +{ 1.1409 + if (MOZ_UNLIKELY(mViewSource)) { 1.1410 + mViewSource->AddErrorToCurrentRun("errUnclosedChildrenInRuby"); 1.1411 + } 1.1412 +} 1.1413 + 1.1414 +void 1.1415 +nsHtml5TreeBuilder::errStartTagSeenWithoutRuby(nsIAtom* aName) 1.1416 +{ 1.1417 + if (MOZ_UNLIKELY(mViewSource)) { 1.1418 + mViewSource->AddErrorToCurrentRun("errStartTagSeenWithoutRuby", 1.1419 + aName); 1.1420 + } 1.1421 +} 1.1422 + 1.1423 +void 1.1424 +nsHtml5TreeBuilder::errSelfClosing() 1.1425 +{ 1.1426 + if (MOZ_UNLIKELY(mViewSource)) { 1.1427 + mViewSource->AddErrorToCurrentSlash("errSelfClosing"); 1.1428 + } 1.1429 +} 1.1430 + 1.1431 +void 1.1432 +nsHtml5TreeBuilder::errNoCheckUnclosedElementsOnStack() 1.1433 +{ 1.1434 + if (MOZ_UNLIKELY(mViewSource)) { 1.1435 + mViewSource->AddErrorToCurrentRun( 1.1436 + "errNoCheckUnclosedElementsOnStack"); 1.1437 + } 1.1438 +} 1.1439 + 1.1440 +void 1.1441 +nsHtml5TreeBuilder::errEndTagDidNotMatchCurrentOpenElement(nsIAtom* aName, 1.1442 + nsIAtom* aOther) 1.1443 +{ 1.1444 + if (MOZ_UNLIKELY(mViewSource)) { 1.1445 + mViewSource->AddErrorToCurrentRun( 1.1446 + "errEndTagDidNotMatchCurrentOpenElement", aName, aOther); 1.1447 + } 1.1448 +} 1.1449 + 1.1450 +void 1.1451 +nsHtml5TreeBuilder::errEndTagViolatesNestingRules(nsIAtom* aName) 1.1452 +{ 1.1453 + if (MOZ_UNLIKELY(mViewSource)) { 1.1454 + mViewSource->AddErrorToCurrentRun("errEndTagViolatesNestingRules", aName); 1.1455 + } 1.1456 +} 1.1457 + 1.1458 +void 1.1459 +nsHtml5TreeBuilder::errEndWithUnclosedElements(nsIAtom* aName) 1.1460 +{ 1.1461 + if (MOZ_UNLIKELY(mViewSource)) { 1.1462 + mViewSource->AddErrorToCurrentRun("errEndWithUnclosedElements", aName); 1.1463 + } 1.1464 +}