зеркало из https://github.com/mozilla/gecko-dev.git
Add innerHTML parsing with HTML5 parser
This commit is contained in:
Родитель
29d969d36a
Коммит
a66d5e247c
|
@ -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.
|
||||
|
|
Загрузка…
Ссылка в новой задаче