nsHtml5StringParser.cpp (4894B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #include "nsHtml5StringParser.h" 6 #include "nsHtml5DependentUTF16Buffer.h" 7 #include "nsHtml5Tokenizer.h" 8 #include "nsHtml5TreeBuilder.h" 9 #include "nsHtml5TreeOpExecutor.h" 10 #include "nsIContent.h" 11 #include "mozilla/dom/Document.h" 12 #include "mozilla/dom/DocumentFragment.h" 13 14 using mozilla::dom::Document; 15 16 NS_IMPL_ISUPPORTS0(nsHtml5StringParser) 17 18 nsHtml5StringParser::nsHtml5StringParser() 19 : mBuilder(new nsHtml5OplessBuilder()), 20 mTreeBuilder(new nsHtml5TreeBuilder(mBuilder)), 21 mTokenizer(new nsHtml5Tokenizer(mTreeBuilder.get(), false)) { 22 mTokenizer->setInterner(&mAtomTable); 23 mTokenizer->setKeepBuffer(true); 24 mTreeBuilder->setKeepBuffer(true); 25 } 26 27 nsHtml5StringParser::~nsHtml5StringParser() { ClearCaches(); } 28 29 nsresult nsHtml5StringParser::ParseFragment( 30 const nsAString& aSourceBuffer, nsIContent* aTargetNode, 31 nsAtom* aContextLocalName, int32_t aContextNamespace, bool aQuirks, 32 bool aPreventScriptExecution, bool aAllowDeclarativeShadowRoots) { 33 NS_ENSURE_TRUE(aSourceBuffer.Length() <= INT32_MAX, NS_ERROR_OUT_OF_MEMORY); 34 35 Document* doc = aTargetNode->OwnerDoc(); 36 nsIURI* uri = doc->GetDocumentURI(); 37 NS_ENSURE_TRUE(uri, NS_ERROR_NOT_AVAILABLE); 38 39 mTreeBuilder->setFragmentContext(aContextLocalName, aContextNamespace, 40 aTargetNode, aQuirks); 41 42 #ifdef DEBUG 43 if (!aPreventScriptExecution) { 44 NS_ASSERTION(!aTargetNode->IsInUncomposedDoc(), 45 "If script execution isn't prevented, " 46 "the target node must not be in doc."); 47 NS_ASSERTION( 48 aTargetNode->NodeType() == nsINode::DOCUMENT_FRAGMENT_NODE, 49 "If script execution isn't prevented, must parse to DOM fragment."); 50 } 51 #endif 52 53 mTreeBuilder->SetPreventScriptExecution(aPreventScriptExecution); 54 55 return Tokenize(aSourceBuffer, doc, true, aAllowDeclarativeShadowRoots); 56 } 57 58 nsresult nsHtml5StringParser::ParseDocument( 59 const nsAString& aSourceBuffer, Document* aTargetDoc, 60 bool aScriptingEnabledForNoscriptParsing) { 61 MOZ_ASSERT(!aTargetDoc->GetFirstChild()); 62 63 NS_ENSURE_TRUE(aSourceBuffer.Length() <= INT32_MAX, NS_ERROR_OUT_OF_MEMORY); 64 65 mTreeBuilder->setFragmentContext(nullptr, kNameSpaceID_None, nullptr, false); 66 67 mTreeBuilder->SetPreventScriptExecution(true); 68 69 return Tokenize(aSourceBuffer, aTargetDoc, 70 aScriptingEnabledForNoscriptParsing, 71 aTargetDoc->AllowsDeclarativeShadowRoots()); 72 } 73 74 void nsHtml5StringParser::ClearCaches() { 75 mTokenizer->dropBufferIfLongerThan(0); 76 mTreeBuilder->dropBufferIfLongerThan(0); 77 if (mCacheClearer) { 78 mCacheClearer->Disconnect(); 79 mCacheClearer = nullptr; 80 } 81 } 82 83 void nsHtml5StringParser::TryCache() { 84 const int32_t kMaxBuffer = 1024 * 1024; 85 bool didDrop = mTokenizer->dropBufferIfLongerThan(kMaxBuffer); 86 didDrop |= mTreeBuilder->dropBufferIfLongerThan(kMaxBuffer); 87 if (didDrop) { 88 return; 89 } 90 91 if (!mCacheClearer) { 92 mCacheClearer = new CacheClearer(this); 93 nsCOMPtr<nsIRunnable> runnable = mCacheClearer.get(); 94 NS_DispatchToMainThreadQueue(runnable.forget(), 95 mozilla::EventQueuePriority::Idle); 96 } 97 } 98 99 nsresult nsHtml5StringParser::Tokenize(const nsAString& aSourceBuffer, 100 Document* aDocument, 101 bool aScriptingEnabledForNoscriptParsing, 102 bool aDeclarativeShadowRootsAllowed) { 103 nsIURI* uri = aDocument->GetDocumentURI(); 104 105 mBuilder->Init(aDocument, uri, nullptr, nullptr); 106 107 mBuilder->SetParser(this); 108 mBuilder->SetNodeInfoManager(aDocument->NodeInfoManager()); 109 110 // Mark the parser as *not* broken by passing NS_OK 111 nsresult rv = mBuilder->MarkAsBroken(NS_OK); 112 113 mTreeBuilder->setScriptingEnabled(aScriptingEnabledForNoscriptParsing); 114 mTreeBuilder->setIsSrcdocDocument(aDocument->IsSrcdocDocument()); 115 mTreeBuilder->setAllowDeclarativeShadowRoots(aDeclarativeShadowRootsAllowed); 116 mBuilder->Start(); 117 mTokenizer->start(); 118 if (!aSourceBuffer.IsEmpty()) { 119 bool lastWasCR = false; 120 nsHtml5DependentUTF16Buffer buffer(aSourceBuffer); 121 while (buffer.hasMore()) { 122 buffer.adjust(lastWasCR); 123 lastWasCR = false; 124 if (buffer.hasMore()) { 125 if (!mTokenizer->EnsureBufferSpace(buffer.getLength())) { 126 rv = mBuilder->MarkAsBroken(NS_ERROR_OUT_OF_MEMORY); 127 break; 128 } 129 lastWasCR = mTokenizer->tokenizeBuffer(&buffer); 130 if (NS_FAILED(rv = mBuilder->IsBroken())) { 131 break; 132 } 133 } 134 } 135 } 136 if (NS_SUCCEEDED(rv)) { 137 mTokenizer->eof(); 138 } 139 140 mTokenizer->end(); 141 mBuilder->Finish(); 142 mAtomTable.Clear(); 143 TryCache(); 144 return rv; 145 }