Add innerHTML parsing with HTML5 parser

This commit is contained in:
Henri Sivonen 2009-02-20 18:13:48 +02:00
Родитель 29d969d36a
Коммит a66d5e247c
10 изменённых файлов: 185 добавлений и 12 удалений

Просмотреть файл

@ -84,6 +84,7 @@ REQUIRES = xpcom \
shistory \
editor \
windowwatcher \
html5 \
$(NULL)
ifdef ACCESSIBILITY

Просмотреть файл

@ -161,6 +161,7 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_XTFSERVICE_CID);
#include "nsIOfflineCacheUpdate.h"
#include "nsCPrefetchService.h"
#include "nsIChromeRegistry.h"
#include "nsHtml5Module.h"
#ifdef IBMBIDI
#include "nsIBidiKeyboard.h"
@ -3459,6 +3460,44 @@ nsContentUtils::CreateContextualFragment(nsIDOMNode* aContextNode,
// for compiling event handlers... so just bail out.
nsCOMPtr<nsIDocument> document = node->GetOwnerDoc();
NS_ENSURE_TRUE(document, NS_ERROR_NOT_AVAILABLE);
PRBool bCaseSensitive = document->IsCaseSensitive();
nsCOMPtr<nsIHTMLDocument> htmlDoc(do_QueryInterface(document));
PRBool bHTML = htmlDoc && !bCaseSensitive;
if (bHTML && nsContentUtils::GetBoolPref("html5.enable", PR_TRUE)) {
// See if the document has a cached fragment parser. nsHTMLDocument is the
// only one that should really have one at the moment.
nsCOMPtr<nsIParser> parser = document->GetFragmentParser();
if (parser) {
// Get the parser ready to use.
parser->Reset();
}
else {
// Create a new parser for this operation.
parser = nsHtml5Module::NewHtml5Parser();
if (!parser) {
return NS_ERROR_OUT_OF_MEMORY;
}
document->SetFragmentParser(parser);
}
nsCOMPtr<nsIDOMDocumentFragment> frag;
rv = NS_NewDocumentFragment(getter_AddRefs(frag), document->NodeInfoManager());
NS_ENSURE_SUCCESS(rv, rv);
// XXX how does ownership of the fragment work here?
nsCOMPtr<nsIContent> contextAsContent = do_QueryInterface(aContextNode);
NS_ASSERTION(contextAsContent, "Context node did not QI to nsIContent");
parser->ParseFragment(aFragment, frag, contextAsContent->Tag(), contextAsContent->GetNameSpaceID());
if (!aWillOwnFragment) {
NS_ADDREF(frag);
}
*aReturn = frag;
return NS_OK;
}
nsAutoTArray<nsString, 32> tagStack;
nsAutoString uriStr, nameStr;
@ -3516,14 +3555,9 @@ nsContentUtils::CreateContextualFragment(nsIDOMNode* aContextNode,
}
nsCAutoString contentType;
PRBool bCaseSensitive = PR_TRUE;
nsAutoString buf;
document->GetContentType(buf);
LossyCopyUTF16toASCII(buf, contentType);
bCaseSensitive = document->IsCaseSensitive();
nsCOMPtr<nsIHTMLDocument> htmlDoc(do_QueryInterface(document));
PRBool bHTML = htmlDoc && !bCaseSensitive;
// See if the document has a cached fragment parser. nsHTMLDocument is the
// only one that should really have one at the moment.

Просмотреть файл

@ -49,6 +49,7 @@
#include "nsEncoderDecoderUtils.h"
#include "nsContentUtils.h"
#include "nsICharsetDetector.h"
#include "nsIScriptElement.h"
#include "nsHtml5DocumentMode.h"
#include "nsHtml5Tokenizer.h"
@ -435,6 +436,50 @@ nsHtml5Parser::ParseFragment(const nsAString& aSourceBuffer,
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsHtml5Parser::ParseFragment(const nsAString& aSourceBuffer,
nsISupports* aTargetNode,
nsIAtom* aContextLocalName,
PRInt32 aContextNamespace)
{
nsCOMPtr<nsIContent> target = do_QueryInterface(aTargetNode);
NS_ASSERTION(target, "Target did not QI to nsIContent");
mTreeBuilder->setFragmentContext(aContextLocalName, aContextNamespace, target);
mFragmentMode = PR_TRUE;
NS_ASSERTION((mLifeCycle == NOT_STARTED), "Tried to start parse without initializing the parser properly.");
mTokenizer->start();
mLifeCycle = PARSING;
mParser = this;
mNodeInfoManager = target->GetOwnerDoc()->NodeInfoManager();
if (!aSourceBuffer.IsEmpty()) {
PRBool lastWasCR = PR_FALSE;
nsHtml5UTF16Buffer buffer(aSourceBuffer.Length());
memcpy(buffer.getBuffer(), aSourceBuffer.BeginReading(), aSourceBuffer.Length() * sizeof(PRUnichar));
buffer.setEnd(aSourceBuffer.Length());
while (buffer.hasMore()) {
buffer.adjust(lastWasCR);
lastWasCR = PR_FALSE;
if (buffer.hasMore()) {
lastWasCR = mTokenizer->tokenizeBuffer(&buffer);
if (mScriptElement) {
nsCOMPtr<nsIScriptElement> script = do_QueryInterface(mScriptElement);
NS_ASSERTION(script, "mScriptElement didn't QI to nsIScriptElement!");
script->PreventExecution();
mScriptElement = nsnull;
}
}
}
}
NS_ASSERTION((mLifeCycle == STREAM_ENDING), "Bad life cycle.");
mTokenizer->eof();
mTokenizer->end();
mLifeCycle = TERMINATED;
DropParserAndPerfHint();
return NS_OK;
}
NS_IMETHODIMP
nsHtml5Parser::BuildModel(void)
{
@ -463,7 +508,46 @@ nsHtml5Parser::CancelParsingEvents()
void
nsHtml5Parser::Reset()
{
NS_NOTREACHED("Can't reset.");
mNeedsCharsetSwitch = PR_FALSE;
mLastWasCR = PR_FALSE;
mTerminated = PR_FALSE;
mLayoutStarted = PR_FALSE;
mFragmentMode = PR_FALSE;
mBlocked = PR_FALSE;
mSuspending = PR_FALSE;
mLifeCycle = NOT_STARTED;
mStreamListenerState = eNone;
mScriptElement = nsnull;
mScriptsExecuting = 0;
mRootContextKey = nsnull;
mRequest = nsnull;
mObserver = nsnull;
mContinueEvent = nsnull; // weak ref
// tree-related stuff
mDocElement = nsnull; // weak ref
// encoding-related stuff
mCharsetSource = kCharsetUninitialized;
mCharset.Assign("");
mPendingCharset.Assign("");
mUnicodeDecoder = nsnull;
mSniffingBuffer = nsnull;
mSniffingLength = 0;
mBomState = BOM_SNIFFING_NOT_STARTED;
delete mMetaScanner;
mMetaScanner = nsnull;
// Portable parser objects
nsHtml5UTF16Buffer* mFirstBuffer; // manually managed strong ref
nsHtml5UTF16Buffer* mLastBuffer; // weak ref; always points to
// a buffer of the size NS_HTML5_PARSER_READ_BUFFER_SIZE
nsHtml5TreeBuilder* mTreeBuilder; // manually managed strong ref
nsHtml5Tokenizer* mTokenizer; // manually managed strong ref
}
/* End nsIParser */

Просмотреть файл

@ -216,6 +216,10 @@ class nsHtml5Parser : public nsIParser,
const nsACString& aContentType,
nsDTDMode aMode = eDTDMode_autodetect);
NS_IMETHOD ParseFragment(const nsAString& aSourceBuffer,
nsISupports* aTargetNode,
nsIAtom* aContextLocalName,
PRInt32 aContextNamespace);
/**
* This method gets called when the tokens have been consumed, and it's time

Просмотреть файл

@ -74,7 +74,12 @@ nsHtml5TreeBuilder::startTokenization(nsHtml5Tokenizer* self)
start(fragment);
startCoalescing();
if (fragment) {
nsIContent* elt = createHtmlElementSetAsRoot(tokenizer->emptyAttributes());
nsIContent* elt;
if (!!contextNode) {
elt = contextNode;
} else {
elt = createHtmlElementSetAsRoot(tokenizer->emptyAttributes());
}
nsHtml5StackNode* node = new nsHtml5StackNode(kNameSpaceID_XHTML, nsHtml5ElementName::HTML, elt);
currentPtr++;
stack[currentPtr] = node;
@ -88,6 +93,10 @@ nsHtml5TreeBuilder::startTokenization(nsHtml5Tokenizer* self)
} else {
tokenizer->setContentModelFlag(NS_HTML5TOKENIZER_DATA, contextName);
}
nsHtml5Portability::releaseLocal(contextName);
contextName = nsnull;
nsHtml5Portability::releaseElement(contextNode);
contextNode = nsnull;
nsHtml5Portability::releaseElement(elt);
} else {
mode = NS_HTML5TREE_BUILDER_INITIAL;
@ -2717,12 +2726,15 @@ nsHtml5TreeBuilder::resetTheInsertionMode()
foreignFlag = NS_HTML5TREE_BUILDER_NOT_IN_FOREIGN;
nsHtml5StackNode* node;
nsIAtom* name;
PRInt32 ns;
for (PRInt32 i = currentPtr; i >= 0; i--) {
node = stack[i];
name = node->name;
ns = node->ns;
if (!i) {
if (!(contextName == nsHtml5Atoms::td || contextName == nsHtml5Atoms::th)) {
if (!(contextNamespace == kNameSpaceID_XHTML && (contextName == nsHtml5Atoms::td || contextName == nsHtml5Atoms::th))) {
name = contextName;
ns = contextNamespace;
} else {
mode = NS_HTML5TREE_BUILDER_IN_BODY;
return;
@ -3468,6 +3480,17 @@ nsHtml5TreeBuilder::requestSuspension()
tokenizer->requestSuspension();
}
void
nsHtml5TreeBuilder::setFragmentContext(nsIAtom* context, PRInt32 ns, nsIContent* node)
{
this->contextName = context;
nsHtml5Portability::retainLocal(context);
this->contextNamespace = ns;
this->contextNode = node;
nsHtml5Portability::retainElement(node);
this->fragment = (!!contextName);
}
nsIContent*
nsHtml5TreeBuilder::currentNode()
{

Просмотреть файл

@ -77,6 +77,7 @@ class nsHtml5TreeBuilder
PRBool fragment;
nsIAtom* contextName;
PRInt32 contextNamespace;
nsIContent* contextNode;
jArray<nsHtml5StackNode*,PRInt32> stack;
PRInt32 currentPtr;
jArray<nsHtml5StackNode*,PRInt32> listOfActiveFormattingElements;
@ -187,6 +188,9 @@ class nsHtml5TreeBuilder
void appendDoctypeToDocument(nsIAtom* name, nsString* publicIdentifier, nsString* systemIdentifier);
void elementPushed(PRInt32 ns, nsIAtom* name, nsIContent* node);
void elementPopped(PRInt32 ns, nsIAtom* name, nsIContent* node);
public:
void setFragmentContext(nsIAtom* context, PRInt32 ns, nsIContent* node);
protected:
nsIContent* currentNode();
public:
PRBool isScriptingEnabled();

Просмотреть файл

@ -291,9 +291,13 @@ nsHtml5TreeBuilder::endCoalescing()
void
nsHtml5TreeBuilder::start(PRBool fragment)
{
mHasProcessedBase = PR_FALSE;
mParser->WillBuildModelImpl();
mParser->GetDocument()->BeginLoad(); // XXX fragment?
if (fragment) {
mHasProcessedBase = PR_TRUE;
} else {
mHasProcessedBase = PR_FALSE;
mParser->WillBuildModelImpl();
mParser->GetDocument()->BeginLoad(); // XXX fragment?
}
}
void

Просмотреть файл

@ -52,6 +52,7 @@
#include "nsIDTD.h"
#include "nsStringGlue.h"
#include "nsTArray.h"
#include "nsIAtom.h"
// 3007e9c0-4d3e-4c80-8cae-fbb4723d88f2
#define NS_IPARSER_IID \
@ -258,6 +259,11 @@ class nsIParser : public nsISupports {
const nsACString& aContentType,
nsDTDMode aMode = eDTDMode_autodetect) = 0;
NS_IMETHOD ParseFragment(const nsAString& aSourceBuffer,
nsISupports* aTargetNode,
nsIAtom* aContextLocalName,
PRInt32 aContextNamespace) = 0;
/**
* This method gets called when the tokens have been consumed, and it's time
* to build the model via the content sink.

Просмотреть файл

@ -2047,6 +2047,15 @@ nsParser::Parse(const nsAString& aSourceBuffer,
return result;
}
NS_IMETHODIMP
nsParser::ParseFragment(const nsAString& aSourceBuffer,
nsISupports* aTargetNode,
nsIAtom* aContextLocalName,
PRInt32 aContextNamespace)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsParser::ParseFragment(const nsAString& aSourceBuffer,
void* aKey,

Просмотреть файл

@ -224,7 +224,11 @@ class nsParser : public nsIParser,
const nsACString& aContentType,
nsDTDMode aMode = eDTDMode_autodetect);
NS_IMETHOD ParseFragment(const nsAString& aSourceBuffer,
nsISupports* aTargetNode,
nsIAtom* aContextLocalName,
PRInt32 aContextNamespace);
/**
* This method gets called when the tokens have been consumed, and it's time
* to build the model via the content sink.