gecko/parser/html/nsHtml5TreeOperation.h

398 lines
13 KiB
C++

/* 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/. */
#ifndef nsHtml5TreeOperation_h
#define nsHtml5TreeOperation_h
#include "nsHtml5DocumentMode.h"
#include "nsHtml5HtmlAttributes.h"
#include "nsXPCOMStrings.h"
class nsIContent;
class nsHtml5TreeOpExecutor;
class nsHtml5StateSnapshot;
enum eHtml5TreeOperation {
#ifdef DEBUG
eTreeOpUninitialized,
#endif
// main HTML5 ops
eTreeOpAppend,
eTreeOpDetach,
eTreeOpAppendChildrenToNewParent,
eTreeOpFosterParent,
eTreeOpAppendToDocument,
eTreeOpAddAttributes,
eTreeOpDocumentMode,
eTreeOpCreateElementNetwork,
eTreeOpCreateElementNotNetwork,
eTreeOpSetFormElement,
eTreeOpAppendText,
eTreeOpAppendIsindexPrompt,
eTreeOpFosterParentText,
eTreeOpAppendComment,
eTreeOpAppendCommentToDocument,
eTreeOpAppendDoctypeToDocument,
eTreeOpGetDocumentFragmentForTemplate,
// Gecko-specific on-pop ops
eTreeOpMarkAsBroken,
eTreeOpRunScript,
eTreeOpRunScriptAsyncDefer,
eTreeOpPreventScriptExecution,
eTreeOpDoneAddingChildren,
eTreeOpDoneCreatingElement,
eTreeOpFlushPendingAppendNotifications,
eTreeOpSetDocumentCharset,
eTreeOpNeedsCharsetSwitchTo,
eTreeOpUpdateStyleSheet,
eTreeOpProcessMeta,
eTreeOpProcessOfflineManifest,
eTreeOpMarkMalformedIfScript,
eTreeOpStreamEnded,
eTreeOpSetStyleLineNumber,
eTreeOpSetScriptLineNumberAndFreeze,
eTreeOpSvgLoad,
eTreeOpMaybeComplainAboutCharset,
eTreeOpAddClass,
eTreeOpAddViewSourceHref,
eTreeOpAddError,
eTreeOpAddLineNumberId,
eTreeOpAddErrorAtom,
eTreeOpAddErrorTwoAtoms,
eTreeOpStartLayout
};
class nsHtml5TreeOperationStringPair {
private:
nsString mPublicId;
nsString mSystemId;
public:
nsHtml5TreeOperationStringPair(const nsAString& aPublicId,
const nsAString& aSystemId)
: mPublicId(aPublicId)
, mSystemId(aSystemId) {
MOZ_COUNT_CTOR(nsHtml5TreeOperationStringPair);
}
~nsHtml5TreeOperationStringPair() {
MOZ_COUNT_DTOR(nsHtml5TreeOperationStringPair);
}
inline void Get(nsAString& aPublicId, nsAString& aSystemId) {
aPublicId.Assign(mPublicId);
aSystemId.Assign(mSystemId);
}
};
class nsHtml5TreeOperation {
public:
nsHtml5TreeOperation();
~nsHtml5TreeOperation();
inline void Init(eHtml5TreeOperation aOpCode) {
NS_PRECONDITION(mOpCode == eTreeOpUninitialized,
"Op code must be uninitialized when initializing.");
mOpCode = aOpCode;
}
inline void Init(eHtml5TreeOperation aOpCode, nsIContent** aNode) {
NS_PRECONDITION(mOpCode == eTreeOpUninitialized,
"Op code must be uninitialized when initializing.");
NS_PRECONDITION(aNode, "Initialized tree op with null node.");
mOpCode = aOpCode;
mOne.node = aNode;
}
inline void Init(eHtml5TreeOperation aOpCode,
nsIContent** aNode,
nsIContent** aParent) {
NS_PRECONDITION(mOpCode == eTreeOpUninitialized,
"Op code must be uninitialized when initializing.");
NS_PRECONDITION(aNode, "Initialized tree op with null node.");
NS_PRECONDITION(aParent, "Initialized tree op with null parent.");
mOpCode = aOpCode;
mOne.node = aNode;
mTwo.node = aParent;
}
inline void Init(eHtml5TreeOperation aOpCode,
const nsACString& aString,
int32_t aInt32) {
NS_PRECONDITION(mOpCode == eTreeOpUninitialized,
"Op code must be uninitialized when initializing.");
int32_t len = aString.Length();
char* str = new char[len + 1];
const char* start = aString.BeginReading();
for (int32_t i = 0; i < len; ++i) {
str[i] = start[i];
}
str[len] = '\0';
mOpCode = aOpCode;
mOne.charPtr = str;
mFour.integer = aInt32;
}
inline void Init(eHtml5TreeOperation aOpCode,
const nsACString& aString,
int32_t aInt32,
int32_t aLineNumber) {
Init(aOpCode, aString, aInt32);
mTwo.integer = aLineNumber;
}
inline void Init(eHtml5TreeOperation aOpCode,
nsIContent** aNode,
nsIContent** aParent,
nsIContent** aTable) {
NS_PRECONDITION(mOpCode == eTreeOpUninitialized,
"Op code must be uninitialized when initializing.");
NS_PRECONDITION(aNode, "Initialized tree op with null node.");
NS_PRECONDITION(aParent, "Initialized tree op with null parent.");
NS_PRECONDITION(aTable, "Initialized tree op with null table.");
mOpCode = aOpCode;
mOne.node = aNode;
mTwo.node = aParent;
mThree.node = aTable;
}
inline void Init(nsHtml5DocumentMode aMode) {
NS_PRECONDITION(mOpCode == eTreeOpUninitialized,
"Op code must be uninitialized when initializing.");
mOpCode = eTreeOpDocumentMode;
mOne.mode = aMode;
}
inline void InitScript(nsIContent** aNode) {
NS_PRECONDITION(mOpCode == eTreeOpUninitialized,
"Op code must be uninitialized when initializing.");
NS_PRECONDITION(aNode, "Initialized tree op with null node.");
mOpCode = eTreeOpRunScript;
mOne.node = aNode;
mTwo.state = nullptr;
}
inline void Init(int32_t aNamespace,
nsIAtom* aName,
nsHtml5HtmlAttributes* aAttributes,
nsIContent** aTarget,
bool aFromNetwork) {
NS_PRECONDITION(mOpCode == eTreeOpUninitialized,
"Op code must be uninitialized when initializing.");
NS_PRECONDITION(aName, "Initialized tree op with null name.");
NS_PRECONDITION(aTarget, "Initialized tree op with null target node.");
mOpCode = aFromNetwork ?
eTreeOpCreateElementNetwork :
eTreeOpCreateElementNotNetwork;
mFour.integer = aNamespace;
mOne.node = aTarget;
mTwo.atom = aName;
if (aAttributes == nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES) {
mThree.attributes = nullptr;
} else {
mThree.attributes = aAttributes;
}
}
inline void Init(eHtml5TreeOperation aOpCode,
PRUnichar* aBuffer,
int32_t aLength,
nsIContent** aStackParent,
nsIContent** aTable) {
NS_PRECONDITION(mOpCode == eTreeOpUninitialized,
"Op code must be uninitialized when initializing.");
NS_PRECONDITION(aBuffer, "Initialized tree op with null buffer.");
mOpCode = aOpCode;
mOne.node = aStackParent;
mTwo.unicharPtr = aBuffer;
mThree.node = aTable;
mFour.integer = aLength;
}
inline void Init(eHtml5TreeOperation aOpCode,
PRUnichar* aBuffer,
int32_t aLength,
nsIContent** aParent) {
NS_PRECONDITION(mOpCode == eTreeOpUninitialized,
"Op code must be uninitialized when initializing.");
NS_PRECONDITION(aBuffer, "Initialized tree op with null buffer.");
mOpCode = aOpCode;
mOne.node = aParent;
mTwo.unicharPtr = aBuffer;
mFour.integer = aLength;
}
inline void Init(eHtml5TreeOperation aOpCode,
PRUnichar* aBuffer,
int32_t aLength) {
NS_PRECONDITION(mOpCode == eTreeOpUninitialized,
"Op code must be uninitialized when initializing.");
NS_PRECONDITION(aBuffer, "Initialized tree op with null buffer.");
mOpCode = aOpCode;
mTwo.unicharPtr = aBuffer;
mFour.integer = aLength;
}
inline void Init(nsIContent** aElement,
nsHtml5HtmlAttributes* aAttributes) {
NS_PRECONDITION(mOpCode == eTreeOpUninitialized,
"Op code must be uninitialized when initializing.");
NS_PRECONDITION(aElement, "Initialized tree op with null element.");
mOpCode = eTreeOpAddAttributes;
mOne.node = aElement;
mTwo.attributes = aAttributes;
}
inline void Init(nsIAtom* aName,
const nsAString& aPublicId,
const nsAString& aSystemId) {
NS_PRECONDITION(mOpCode == eTreeOpUninitialized,
"Op code must be uninitialized when initializing.");
mOpCode = eTreeOpAppendDoctypeToDocument;
mOne.atom = aName;
mTwo.stringPair = new nsHtml5TreeOperationStringPair(aPublicId, aSystemId);
}
inline void Init(nsIContent** aElement,
const char* aMsgId,
nsIAtom* aAtom,
nsIAtom* aOtherAtom) {
NS_PRECONDITION(mOpCode == eTreeOpUninitialized,
"Op code must be uninitialized when initializing.");
mOpCode = eTreeOpAddError;
mOne.node = aElement;
mTwo.charPtr = (char*)aMsgId;
mThree.atom = aAtom;
mFour.atom = aOtherAtom;
}
inline void Init(nsIContent** aElement,
const char* aMsgId,
nsIAtom* aAtom) {
Init(aElement, aMsgId, aAtom, nullptr);
}
inline void Init(nsIContent** aElement,
const char* aMsgId) {
Init(aElement, aMsgId, nullptr, nullptr);
}
inline void Init(const char* aMsgId,
bool aError,
int32_t aLineNumber) {
NS_PRECONDITION(mOpCode == eTreeOpUninitialized,
"Op code must be uninitialized when initializing.");
mOpCode = eTreeOpMaybeComplainAboutCharset;
mOne.charPtr = const_cast<char*>(aMsgId);
mTwo.integer = aError;
mThree.integer = aLineNumber;
}
inline void Init(eHtml5TreeOperation aOpCode, const nsAString& aString) {
NS_PRECONDITION(mOpCode == eTreeOpUninitialized,
"Op code must be uninitialized when initializing.");
PRUnichar* str = NS_StringCloneData(aString);
mOpCode = aOpCode;
mOne.unicharPtr = str;
}
inline void Init(eHtml5TreeOperation aOpCode,
nsIContent** aNode,
int32_t aInt) {
NS_PRECONDITION(mOpCode == eTreeOpUninitialized,
"Op code must be uninitialized when initializing.");
NS_PRECONDITION(aNode, "Initialized tree op with null node.");
mOpCode = aOpCode;
mOne.node = aNode;
mFour.integer = aInt;
}
inline void InitAddClass(nsIContent** aNode, const PRUnichar* aClass) {
NS_PRECONDITION(mOpCode == eTreeOpUninitialized,
"Op code must be uninitialized when initializing.");
NS_PRECONDITION(aNode, "Initialized tree op with null node.");
NS_PRECONDITION(aClass, "Initialized tree op with null string.");
// aClass must be a literal string that does not need freeing
mOpCode = eTreeOpAddClass;
mOne.node = aNode;
mTwo.unicharPtr = (PRUnichar*)aClass;
}
inline void InitAddLineNumberId(nsIContent** aNode,
const int32_t aLineNumber) {
NS_PRECONDITION(mOpCode == eTreeOpUninitialized,
"Op code must be uninitialized when initializing.");
NS_PRECONDITION(aNode, "Initialized tree op with null node.");
NS_PRECONDITION(aLineNumber > 0, "Initialized tree op with line number.");
// aClass must be a literal string that does not need freeing
mOpCode = eTreeOpAddLineNumberId;
mOne.node = aNode;
mFour.integer = aLineNumber;
}
inline bool IsRunScript() {
return mOpCode == eTreeOpRunScript;
}
inline void SetSnapshot(nsAHtml5TreeBuilderState* aSnapshot, int32_t aLine) {
NS_ASSERTION(IsRunScript(),
"Setting a snapshot for a tree operation other than eTreeOpRunScript!");
NS_PRECONDITION(aSnapshot, "Initialized tree op with null snapshot.");
mTwo.state = aSnapshot;
mFour.integer = aLine;
}
nsresult Perform(nsHtml5TreeOpExecutor* aBuilder, nsIContent** aScriptElement);
inline already_AddRefed<nsIAtom> Reget(nsIAtom* aAtom) {
if (!aAtom || aAtom->IsStaticAtom()) {
return dont_AddRef(aAtom);
}
nsAutoString str;
aAtom->ToString(str);
return do_GetAtom(str);
}
private:
nsresult AppendTextToTextNode(const PRUnichar* aBuffer,
uint32_t aLength,
nsIContent* aTextNode,
nsHtml5TreeOpExecutor* aBuilder);
nsresult AppendText(const PRUnichar* aBuffer,
uint32_t aLength,
nsIContent* aParent,
nsHtml5TreeOpExecutor* aBuilder);
nsresult Append(nsIContent* aNode,
nsIContent* aParent,
nsHtml5TreeOpExecutor* aBuilder);
nsresult AppendToDocument(nsIContent* aNode,
nsHtml5TreeOpExecutor* aBuilder);
// possible optimization:
// Make the queue take items the size of pointer and make the op code
// decide how many operands it dequeues after it.
eHtml5TreeOperation mOpCode;
union {
nsIContent** node;
nsIAtom* atom;
nsHtml5HtmlAttributes* attributes;
nsHtml5DocumentMode mode;
PRUnichar* unicharPtr;
char* charPtr;
nsHtml5TreeOperationStringPair* stringPair;
nsAHtml5TreeBuilderState* state;
int32_t integer;
} mOne, mTwo, mThree, mFour;
};
#endif // nsHtml5TreeOperation_h