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