Making invalid selectors ignore the following rule in more cases. b=265542 r=bzbarsky sr=dbaron

This commit is contained in:
mats.palmgren%bredband.net 2004-11-26 21:05:45 +00:00
Родитель f98dac5a17
Коммит 6a6fc8d7ac
2 изменённых файлов: 478 добавлений и 532 удалений

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

@ -179,28 +179,51 @@ protected:
PRBool ParseFontFaceRule(nsresult& aErrorCode, RuleAppendFunc aAppendFunc, void* aProcessData); PRBool ParseFontFaceRule(nsresult& aErrorCode, RuleAppendFunc aAppendFunc, void* aProcessData);
PRBool ParsePageRule(nsresult& aErrorCode, RuleAppendFunc aAppendFunc, void* aProcessData); PRBool ParsePageRule(nsresult& aErrorCode, RuleAppendFunc aAppendFunc, void* aProcessData);
void ParseIDSelector(PRInt32& aDataMask, nsCSSSelector& aSelector, enum nsSelectorParsingStatus {
PRInt32& aParsingStatus, nsresult& aErrorCode); // we have parsed a selector and we saw a token that cannot be part of a selector:
void ParseClassSelector(PRInt32& aDataMask, nsCSSSelector& aSelector, eSelectorParsingStatus_Done,
PRInt32& aParsingStatus, nsresult& aErrorCode); // we should continue parsing the selector:
void ParsePseudoSelector(PRInt32& aDataMask, nsCSSSelector& aSelector, eSelectorParsingStatus_Continue,
PRInt32& aParsingStatus, nsresult& aErrorCode, // same as "Done" but we did not find a selector:
PRBool aIsNegated); eSelectorParsingStatus_Empty,
void ParseAttributeSelector(PRInt32& aDataMask, nsCSSSelector& aSelector, // we saw an unexpected token or token value,
PRInt32& aParsingStatus, nsresult& aErrorCode); // or we saw end-of-file with an unfinished selector:
eSelectorParsingStatus_Error
};
nsSelectorParsingStatus ParseIDSelector(PRInt32& aDataMask,
nsCSSSelector& aSelector,
nsresult& aErrorCode);
void ParseTypeOrUniversalSelector(PRInt32& aDataMask, nsSelectorParsingStatus ParseClassSelector(PRInt32& aDataMask,
nsCSSSelector& aSelector, nsCSSSelector& aSelector,
PRInt32& aParsingStatus, nsresult& aErrorCode, nsresult& aErrorCode);
PRBool aIsNegated);
void ParseNegatedSimpleSelector(PRInt32& aDataMask, nsCSSSelector& aSelector, nsSelectorParsingStatus ParsePseudoSelector(PRInt32& aDataMask,
PRInt32& aParsingStatus, nsresult& aErrorCode); nsCSSSelector& aSelector,
void ParseLangSelector(nsCSSSelector& aSelector, PRInt32& aParsingStatus, nsresult& aErrorCode,
nsresult& aErrorCode); PRBool aIsNegated);
nsSelectorParsingStatus ParseAttributeSelector(PRInt32& aDataMask,
nsCSSSelector& aSelector,
nsresult& aErrorCode);
nsSelectorParsingStatus ParseTypeOrUniversalSelector(PRInt32& aDataMask,
nsCSSSelector& aSelector,
nsresult& aErrorCode,
PRBool aIsNegated);
nsSelectorParsingStatus ParseLangSelector(nsCSSSelector& aSelector,
nsresult& aErrorCode);
nsSelectorParsingStatus ParseNegatedSimpleSelector(PRInt32& aDataMask,
nsCSSSelector& aSelector,
nsresult& aErrorCode);
nsSelectorParsingStatus ParseSelector(nsresult& aErrorCode,
nsCSSSelector& aSelectorResult);
PRBool ParseSelectorList(nsresult& aErrorCode, nsCSSSelectorList*& aListHead); PRBool ParseSelectorList(nsresult& aErrorCode, nsCSSSelectorList*& aListHead);
PRBool ParseSelectorGroup(nsresult& aErrorCode, nsCSSSelectorList*& aListHead); PRBool ParseSelectorGroup(nsresult& aErrorCode, nsCSSSelectorList*& aListHead);
PRBool ParseSelector(nsresult& aErrorCode, nsCSSSelector& aSelectorResult);
nsCSSDeclaration* ParseDeclarationBlock(nsresult& aErrorCode, nsCSSDeclaration* ParseDeclarationBlock(nsresult& aErrorCode,
PRBool aCheckForBraces); PRBool aCheckForBraces);
PRBool ParseDeclaration(nsresult& aErrorCode, PRBool ParseDeclaration(nsresult& aErrorCode,
@ -1651,7 +1674,18 @@ PRBool CSSParserImpl::ParseSelectorGroup(nsresult& aErrorCode,
PRBool done = PR_FALSE; PRBool done = PR_FALSE;
while (!done) { while (!done) {
nsCSSSelector selector; nsCSSSelector selector;
if (! ParseSelector(aErrorCode, selector)) { nsSelectorParsingStatus parsingStatus = ParseSelector(aErrorCode, selector);
if (parsingStatus == eSelectorParsingStatus_Empty) {
if (!list) {
REPORT_UNEXPECTED(PESelectorGroupNoSelector);
}
break;
}
if (parsingStatus == eSelectorParsingStatus_Error) {
if (list) {
delete list;
list = nsnull;
}
break; break;
} }
if (nsnull == list) { if (nsnull == list) {
@ -1747,14 +1781,12 @@ PRBool CSSParserImpl::ParseSelectorGroup(nsresult& aErrorCode,
weight += selector.CalcWeight(); weight += selector.CalcWeight();
} }
} }
if (!list) {
REPORT_UNEXPECTED(PESelectorGroupNoSelector);
}
if (PRUnichar(0) != combinator) { // no dangling combinators if (PRUnichar(0) != combinator) { // no dangling combinators
if (list) { if (list) {
delete list; delete list;
list = nsnull;
} }
list = nsnull;
// This should report the problematic combinator // This should report the problematic combinator
REPORT_UNEXPECTED(PESelectorGroupExtraCombinator); REPORT_UNEXPECTED(PESelectorGroupExtraCombinator);
} }
@ -1773,17 +1805,13 @@ PRBool CSSParserImpl::ParseSelectorGroup(nsresult& aErrorCode,
#define SEL_MASK_PCLASS 0x20 #define SEL_MASK_PCLASS 0x20
#define SEL_MASK_PELEM 0x40 #define SEL_MASK_PELEM 0x40
#define SELECTOR_PARSING_ENDED_OK 1
#define SELECTOR_PARSING_STOPPED_OK 2
#define SELECTOR_PARSING_STOPPED_ERROR 3
// //
// Parses an ID selector #name // Parses an ID selector #name
// //
void CSSParserImpl::ParseIDSelector(PRInt32& aDataMask, CSSParserImpl::nsSelectorParsingStatus
nsCSSSelector& aSelector, CSSParserImpl::ParseIDSelector(PRInt32& aDataMask,
PRInt32& aParsingStatus, nsCSSSelector& aSelector,
nsresult& aErrorCode) nsresult& aErrorCode)
{ {
if (!mToken.mIdent.IsEmpty()) { // verify is legal ID if (!mToken.mIdent.IsEmpty()) { // verify is legal ID
PRUnichar first = mToken.mIdent.First(); PRUnichar first = mToken.mIdent.First();
@ -1795,8 +1823,7 @@ void CSSParserImpl::ParseIDSelector(PRInt32& aDataMask,
nsCSSScanner::GetLexTable())) { nsCSSScanner::GetLexTable())) {
REPORT_UNEXPECTED_TOKEN(PEIDSelNotIdent); REPORT_UNEXPECTED_TOKEN(PEIDSelNotIdent);
UngetToken(); UngetToken();
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
aDataMask |= SEL_MASK_ID; aDataMask |= SEL_MASK_ID;
aSelector.AddID(mToken.mIdent); aSelector.AddID(mToken.mIdent);
@ -1804,47 +1831,44 @@ void CSSParserImpl::ParseIDSelector(PRInt32& aDataMask,
else { else {
REPORT_UNEXPECTED_TOKEN(PEIDSelEmpty); REPORT_UNEXPECTED_TOKEN(PEIDSelEmpty);
UngetToken(); UngetToken();
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
aParsingStatus = SELECTOR_PARSING_ENDED_OK; return eSelectorParsingStatus_Continue;
} }
// //
// Parses a class selector .name // Parses a class selector .name
// //
void CSSParserImpl::ParseClassSelector(PRInt32& aDataMask, CSSParserImpl::nsSelectorParsingStatus
nsCSSSelector& aSelector, CSSParserImpl::ParseClassSelector(PRInt32& aDataMask,
PRInt32& aParsingStatus, nsCSSSelector& aSelector,
nsresult& aErrorCode) nsresult& aErrorCode)
{ {
if (! GetToken(aErrorCode, PR_FALSE)) { // get ident if (! GetToken(aErrorCode, PR_FALSE)) { // get ident
REPORT_UNEXPECTED_EOF(PEClassSelEOF); REPORT_UNEXPECTED_EOF(PEClassSelEOF);
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
if (eCSSToken_Ident != mToken.mType) { // malformed selector if (eCSSToken_Ident != mToken.mType) { // malformed selector
REPORT_UNEXPECTED_TOKEN(PEClassSelNotIdent); REPORT_UNEXPECTED_TOKEN(PEClassSelNotIdent);
UngetToken(); UngetToken();
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
aDataMask |= SEL_MASK_CLASS; aDataMask |= SEL_MASK_CLASS;
aSelector.AddClass(mToken.mIdent); aSelector.AddClass(mToken.mIdent);
aParsingStatus = SELECTOR_PARSING_ENDED_OK; return eSelectorParsingStatus_Continue;
} }
// //
// Parse a type element selector or a universal selector // Parse a type element selector or a universal selector
// namespace|type or namespace|* or *|* or * // namespace|type or namespace|* or *|* or *
// //
void CSSParserImpl::ParseTypeOrUniversalSelector(PRInt32& aDataMask, CSSParserImpl::nsSelectorParsingStatus
nsCSSSelector& aSelector, CSSParserImpl::ParseTypeOrUniversalSelector(PRInt32& aDataMask,
PRInt32& aParsingStatus, nsCSSSelector& aSelector,
nsresult& aErrorCode, nsresult& aErrorCode,
PRBool aIsNegated) PRBool aIsNegated)
{ {
nsAutoString buffer; nsAutoString buffer;
if (mToken.IsSymbol('*')) { // universal element selector, or universal namespace if (mToken.IsSymbol('*')) { // universal element selector, or universal namespace
@ -1854,8 +1878,7 @@ void CSSParserImpl::ParseTypeOrUniversalSelector(PRInt32& aDataMask,
if (! GetToken(aErrorCode, PR_FALSE)) { if (! GetToken(aErrorCode, PR_FALSE)) {
REPORT_UNEXPECTED_EOF(PETypeSelEOF); REPORT_UNEXPECTED_EOF(PETypeSelEOF);
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
if (eCSSToken_Ident == mToken.mType) { // element name if (eCSSToken_Ident == mToken.mType) { // element name
aDataMask |= SEL_MASK_ELEM; aDataMask |= SEL_MASK_ELEM;
@ -1874,8 +1897,7 @@ void CSSParserImpl::ParseTypeOrUniversalSelector(PRInt32& aDataMask,
else { else {
REPORT_UNEXPECTED_TOKEN(PETypeSelNotType); REPORT_UNEXPECTED_TOKEN(PETypeSelNotType);
UngetToken(); UngetToken();
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
} }
else { // was universal element selector else { // was universal element selector
@ -1893,8 +1915,7 @@ void CSSParserImpl::ParseTypeOrUniversalSelector(PRInt32& aDataMask,
// don't set any tag in the selector // don't set any tag in the selector
} }
if (! GetToken(aErrorCode, PR_FALSE)) { // premature eof is ok (here!) if (! GetToken(aErrorCode, PR_FALSE)) { // premature eof is ok (here!)
aParsingStatus = SELECTOR_PARSING_STOPPED_OK; return eSelectorParsingStatus_Done;
return;
} }
} }
else if (eCSSToken_Ident == mToken.mType) { // element name or namespace name else if (eCSSToken_Ident == mToken.mType) { // element name or namespace name
@ -1913,15 +1934,13 @@ void CSSParserImpl::ParseTypeOrUniversalSelector(PRInt32& aDataMask,
buffer.get() buffer.get()
}; };
REPORT_UNEXPECTED_P(PEUnknownNamespacePrefix, params); REPORT_UNEXPECTED_P(PEUnknownNamespacePrefix, params);
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
aSelector.SetNameSpace(nameSpaceID); aSelector.SetNameSpace(nameSpaceID);
if (! GetToken(aErrorCode, PR_FALSE)) { if (! GetToken(aErrorCode, PR_FALSE)) {
REPORT_UNEXPECTED_EOF(PETypeSelEOF); REPORT_UNEXPECTED_EOF(PETypeSelEOF);
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
if (eCSSToken_Ident == mToken.mType) { // element name if (eCSSToken_Ident == mToken.mType) { // element name
aDataMask |= SEL_MASK_ELEM; aDataMask |= SEL_MASK_ELEM;
@ -1940,8 +1959,7 @@ void CSSParserImpl::ParseTypeOrUniversalSelector(PRInt32& aDataMask,
else { else {
REPORT_UNEXPECTED_TOKEN(PETypeSelNotType); REPORT_UNEXPECTED_TOKEN(PETypeSelNotType);
UngetToken(); UngetToken();
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
} }
else { // was element name else { // was element name
@ -1965,8 +1983,7 @@ void CSSParserImpl::ParseTypeOrUniversalSelector(PRInt32& aDataMask,
aDataMask |= SEL_MASK_ELEM; aDataMask |= SEL_MASK_ELEM;
} }
if (! GetToken(aErrorCode, PR_FALSE)) { // premature eof is ok (here!) if (! GetToken(aErrorCode, PR_FALSE)) { // premature eof is ok (here!)
aParsingStatus = SELECTOR_PARSING_STOPPED_OK; return eSelectorParsingStatus_Done;
return;
} }
} }
else if (mToken.IsSymbol('|')) { // No namespace else if (mToken.IsSymbol('|')) { // No namespace
@ -1976,8 +1993,7 @@ void CSSParserImpl::ParseTypeOrUniversalSelector(PRInt32& aDataMask,
// get mandatory tag // get mandatory tag
if (! GetToken(aErrorCode, PR_FALSE)) { if (! GetToken(aErrorCode, PR_FALSE)) {
REPORT_UNEXPECTED_EOF(PETypeSelEOF); REPORT_UNEXPECTED_EOF(PETypeSelEOF);
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
if (eCSSToken_Ident == mToken.mType) { // element name if (eCSSToken_Ident == mToken.mType) { // element name
aDataMask |= SEL_MASK_ELEM; aDataMask |= SEL_MASK_ELEM;
@ -1996,12 +2012,10 @@ void CSSParserImpl::ParseTypeOrUniversalSelector(PRInt32& aDataMask,
else { else {
REPORT_UNEXPECTED_TOKEN(PETypeSelNotType); REPORT_UNEXPECTED_TOKEN(PETypeSelNotType);
UngetToken(); UngetToken();
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
if (! GetToken(aErrorCode, PR_FALSE)) { // premature eof is ok (here!) if (! GetToken(aErrorCode, PR_FALSE)) { // premature eof is ok (here!)
aParsingStatus = SELECTOR_PARSING_STOPPED_OK; return eSelectorParsingStatus_Done;
return;
} }
} }
else { else {
@ -2019,26 +2033,25 @@ void CSSParserImpl::ParseTypeOrUniversalSelector(PRInt32& aDataMask,
} }
} }
aParsingStatus = SELECTOR_PARSING_ENDED_OK;
if (aIsNegated) { if (aIsNegated) {
// restore last token read in case of a negated type selector // restore last token read in case of a negated type selector
UngetToken(); UngetToken();
} }
return eSelectorParsingStatus_Continue;
} }
// //
// Parse attribute selectors [attr], [attr=value], [attr|=value], // Parse attribute selectors [attr], [attr=value], [attr|=value],
// [attr~=value], [attr^=value], [attr$=value] and [attr*=value] // [attr~=value], [attr^=value], [attr$=value] and [attr*=value]
// //
void CSSParserImpl::ParseAttributeSelector(PRInt32& aDataMask, CSSParserImpl::nsSelectorParsingStatus
CSSParserImpl::ParseAttributeSelector(PRInt32& aDataMask,
nsCSSSelector& aSelector, nsCSSSelector& aSelector,
PRInt32& aParsingStatus, nsresult& aErrorCode)
nsresult& aErrorCode)
{ {
if (! GetToken(aErrorCode, PR_TRUE)) { // premature EOF if (! GetToken(aErrorCode, PR_TRUE)) { // premature EOF
REPORT_UNEXPECTED_EOF(PEAttributeNameEOF); REPORT_UNEXPECTED_EOF(PEAttributeNameEOF);
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
PRInt32 nameSpaceID = kNameSpaceID_None; PRInt32 nameSpaceID = kNameSpaceID_None;
@ -2048,8 +2061,7 @@ void CSSParserImpl::ParseAttributeSelector(PRInt32& aDataMask,
if (ExpectSymbol(aErrorCode, '|', PR_FALSE)) { if (ExpectSymbol(aErrorCode, '|', PR_FALSE)) {
if (! GetToken(aErrorCode, PR_FALSE)) { // premature EOF if (! GetToken(aErrorCode, PR_FALSE)) { // premature EOF
REPORT_UNEXPECTED_EOF(PEAttributeNameEOF); REPORT_UNEXPECTED_EOF(PEAttributeNameEOF);
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
if (eCSSToken_Ident == mToken.mType) { // attr name if (eCSSToken_Ident == mToken.mType) { // attr name
attr = mToken.mIdent; attr = mToken.mIdent;
@ -2057,21 +2069,18 @@ void CSSParserImpl::ParseAttributeSelector(PRInt32& aDataMask,
else { else {
REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected); REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected);
UngetToken(); UngetToken();
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
} }
else { else {
REPORT_UNEXPECTED_TOKEN(PEAttSelNoBar); REPORT_UNEXPECTED_TOKEN(PEAttSelNoBar);
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
} }
else if (mToken.IsSymbol('|')) { // NO namespace else if (mToken.IsSymbol('|')) { // NO namespace
if (! GetToken(aErrorCode, PR_FALSE)) { // premature EOF if (! GetToken(aErrorCode, PR_FALSE)) { // premature EOF
REPORT_UNEXPECTED_EOF(PEAttributeNameEOF); REPORT_UNEXPECTED_EOF(PEAttributeNameEOF);
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
if (eCSSToken_Ident == mToken.mType) { // attr name if (eCSSToken_Ident == mToken.mType) { // attr name
attr = mToken.mIdent; attr = mToken.mIdent;
@ -2079,8 +2088,7 @@ void CSSParserImpl::ParseAttributeSelector(PRInt32& aDataMask,
else { else {
REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected); REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected);
UngetToken(); UngetToken();
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
} }
else if (eCSSToken_Ident == mToken.mType) { // attr name or namespace else if (eCSSToken_Ident == mToken.mType) { // attr name or namespace
@ -2097,13 +2105,11 @@ void CSSParserImpl::ParseAttributeSelector(PRInt32& aDataMask,
attr.get() attr.get()
}; };
REPORT_UNEXPECTED_P(PEUnknownNamespacePrefix, params); REPORT_UNEXPECTED_P(PEUnknownNamespacePrefix, params);
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
if (! GetToken(aErrorCode, PR_FALSE)) { // premature EOF if (! GetToken(aErrorCode, PR_FALSE)) { // premature EOF
REPORT_UNEXPECTED_EOF(PEAttributeNameEOF); REPORT_UNEXPECTED_EOF(PEAttributeNameEOF);
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
if (eCSSToken_Ident == mToken.mType) { // attr name if (eCSSToken_Ident == mToken.mType) { // attr name
attr = mToken.mIdent; attr = mToken.mIdent;
@ -2111,16 +2117,14 @@ void CSSParserImpl::ParseAttributeSelector(PRInt32& aDataMask,
else { else {
REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected); REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected);
UngetToken(); UngetToken();
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
} }
} }
else { // malformed else { // malformed
REPORT_UNEXPECTED_TOKEN(PEAttributeNameOrNamespaceExpected); REPORT_UNEXPECTED_TOKEN(PEAttributeNameOrNamespaceExpected);
UngetToken(); UngetToken();
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
if (! mCaseSensitive) { if (! mCaseSensitive) {
@ -2128,8 +2132,7 @@ void CSSParserImpl::ParseAttributeSelector(PRInt32& aDataMask,
} }
if (! GetToken(aErrorCode, PR_TRUE)) { // premature EOF if (! GetToken(aErrorCode, PR_TRUE)) { // premature EOF
REPORT_UNEXPECTED_EOF(PEAttSelInnerEOF); REPORT_UNEXPECTED_EOF(PEAttSelInnerEOF);
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
if ((eCSSToken_Symbol == mToken.mType) || if ((eCSSToken_Symbol == mToken.mType) ||
(eCSSToken_Includes == mToken.mType) || (eCSSToken_Includes == mToken.mType) ||
@ -2164,21 +2167,18 @@ void CSSParserImpl::ParseAttributeSelector(PRInt32& aDataMask,
else { else {
REPORT_UNEXPECTED_TOKEN(PEAttSelUnexpected); REPORT_UNEXPECTED_TOKEN(PEAttSelUnexpected);
UngetToken(); // bad function UngetToken(); // bad function
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
if (NS_ATTR_FUNC_SET != func) { // get value if (NS_ATTR_FUNC_SET != func) { // get value
if (! GetToken(aErrorCode, PR_TRUE)) { // premature EOF if (! GetToken(aErrorCode, PR_TRUE)) { // premature EOF
REPORT_UNEXPECTED_EOF(PEAttSelValueEOF); REPORT_UNEXPECTED_EOF(PEAttSelValueEOF);
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
if ((eCSSToken_Ident == mToken.mType) || (eCSSToken_String == mToken.mType)) { if ((eCSSToken_Ident == mToken.mType) || (eCSSToken_String == mToken.mType)) {
nsAutoString value(mToken.mIdent); nsAutoString value(mToken.mIdent);
if (! GetToken(aErrorCode, PR_TRUE)) { // premature EOF if (! GetToken(aErrorCode, PR_TRUE)) { // premature EOF
REPORT_UNEXPECTED_EOF(PEAttSelCloseEOF); REPORT_UNEXPECTED_EOF(PEAttSelCloseEOF);
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
if (mToken.IsSymbol(']')) { if (mToken.IsSymbol(']')) {
PRBool isCaseSensitive = mCaseSensitive; PRBool isCaseSensitive = mCaseSensitive;
@ -2207,40 +2207,36 @@ void CSSParserImpl::ParseAttributeSelector(PRInt32& aDataMask,
else { else {
REPORT_UNEXPECTED_TOKEN(PEAttSelNoClose); REPORT_UNEXPECTED_TOKEN(PEAttSelNoClose);
UngetToken(); UngetToken();
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
} }
else { else {
REPORT_UNEXPECTED_TOKEN(PEAttSelBadValue); REPORT_UNEXPECTED_TOKEN(PEAttSelBadValue);
UngetToken(); UngetToken();
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
} }
} }
else { else {
REPORT_UNEXPECTED_TOKEN(PEAttSelUnexpected); REPORT_UNEXPECTED_TOKEN(PEAttSelUnexpected);
UngetToken(); // bad dog, no biscut! UngetToken(); // bad dog, no biscut!
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
aParsingStatus = SELECTOR_PARSING_ENDED_OK; return eSelectorParsingStatus_Continue;
} }
// //
// Parse pseudo-classes and pseudo-elements // Parse pseudo-classes and pseudo-elements
// //
void CSSParserImpl::ParsePseudoSelector(PRInt32& aDataMask, CSSParserImpl::nsSelectorParsingStatus
nsCSSSelector& aSelector, CSSParserImpl::ParsePseudoSelector(PRInt32& aDataMask,
PRInt32& aParsingStatus, nsCSSSelector& aSelector,
nsresult& aErrorCode, nsresult& aErrorCode,
PRBool aIsNegated) PRBool aIsNegated)
{ {
if (! GetToken(aErrorCode, PR_FALSE)) { // premature eof if (! GetToken(aErrorCode, PR_FALSE)) { // premature eof
REPORT_UNEXPECTED_EOF(PEPseudoSelEOF); REPORT_UNEXPECTED_EOF(PEPseudoSelEOF);
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
// First, find out whether we are parsing a CSS3 pseudo-element // First, find out whether we are parsing a CSS3 pseudo-element
@ -2249,8 +2245,7 @@ void CSSParserImpl::ParsePseudoSelector(PRInt32& aDataMask,
parsingPseudoElement = PR_TRUE; parsingPseudoElement = PR_TRUE;
if (! GetToken(aErrorCode, PR_FALSE)) { // premature eof if (! GetToken(aErrorCode, PR_FALSE)) { // premature eof
REPORT_UNEXPECTED_EOF(PEPseudoSelEOF); REPORT_UNEXPECTED_EOF(PEPseudoSelEOF);
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
} }
@ -2259,8 +2254,7 @@ void CSSParserImpl::ParsePseudoSelector(PRInt32& aDataMask,
// malformed selector // malformed selector
REPORT_UNEXPECTED_TOKEN(PEPseudoSelBadName); REPORT_UNEXPECTED_TOKEN(PEPseudoSelBadName);
UngetToken(); UngetToken();
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
// OK, now we know we have an mIdent. Atomize it. All the atoms, for // OK, now we know we have an mIdent. Atomize it. All the atoms, for
@ -2297,8 +2291,7 @@ void CSSParserImpl::ParsePseudoSelector(PRInt32& aDataMask,
nsCSSPseudoClasses::lang == pseudo)) { // There are no other function pseudos nsCSSPseudoClasses::lang == pseudo)) { // There are no other function pseudos
REPORT_UNEXPECTED_TOKEN(PEPseudoSelNonFunc); REPORT_UNEXPECTED_TOKEN(PEPseudoSelNonFunc);
UngetToken(); UngetToken();
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
// If it starts with "::", it better be a pseudo-element // If it starts with "::", it better be a pseudo-element
@ -2307,36 +2300,35 @@ void CSSParserImpl::ParsePseudoSelector(PRInt32& aDataMask,
!isAnonBox) { !isAnonBox) {
REPORT_UNEXPECTED_TOKEN(PEPseudoSelNotPE); REPORT_UNEXPECTED_TOKEN(PEPseudoSelNotPE);
UngetToken(); UngetToken();
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
if (nsCSSPseudoClasses::notPseudo == pseudo) { if (nsCSSPseudoClasses::notPseudo == pseudo) {
if (aIsNegated) { // :not() can't be itself negated if (aIsNegated) { // :not() can't be itself negated
REPORT_UNEXPECTED_TOKEN(PEPseudoSelDoubleNot); REPORT_UNEXPECTED_TOKEN(PEPseudoSelDoubleNot);
UngetToken(); UngetToken();
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
// CSS 3 Negation pseudo-class takes one simple selector as argument // CSS 3 Negation pseudo-class takes one simple selector as argument
ParseNegatedSimpleSelector(aDataMask, aSelector, aParsingStatus, aErrorCode); nsSelectorParsingStatus parsingStatus =
if (SELECTOR_PARSING_ENDED_OK != aParsingStatus) { ParseNegatedSimpleSelector(aDataMask, aSelector, aErrorCode);
return; if (eSelectorParsingStatus_Continue != parsingStatus) {
return parsingStatus;
} }
} }
else if (!parsingPseudoElement && else if (!parsingPseudoElement &&
nsCSSPseudoClasses::IsPseudoClass(pseudo)) { nsCSSPseudoClasses::IsPseudoClass(pseudo)) {
aDataMask |= SEL_MASK_PCLASS; aDataMask |= SEL_MASK_PCLASS;
if (nsCSSPseudoClasses::lang == pseudo) { if (nsCSSPseudoClasses::lang == pseudo) {
ParseLangSelector(aSelector, aParsingStatus, aErrorCode); nsSelectorParsingStatus parsingStatus = ParseLangSelector(aSelector, aErrorCode);
if (eSelectorParsingStatus_Continue != parsingStatus) {
return parsingStatus;
}
} }
// XXX are there more pseudo classes which accept arguments ? // XXX are there more pseudo classes which accept arguments ?
else { else {
aSelector.AddPseudoClass(pseudo); aSelector.AddPseudoClass(pseudo);
} }
if (SELECTOR_PARSING_ENDED_OK != aParsingStatus) {
return;
}
} }
else if (isPseudoElement || isAnonBox) { else if (isPseudoElement || isAnonBox) {
// Pseudo-element. Make some more sanity checks. // Pseudo-element. Make some more sanity checks.
@ -2344,8 +2336,7 @@ void CSSParserImpl::ParsePseudoSelector(PRInt32& aDataMask,
if (aIsNegated) { // pseudo-elements can't be negated if (aIsNegated) { // pseudo-elements can't be negated
REPORT_UNEXPECTED_TOKEN(PEPseudoSelPEInNot); REPORT_UNEXPECTED_TOKEN(PEPseudoSelPEInNot);
UngetToken(); UngetToken();
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
// CSS2 pseudo-elements and -moz-tree-* pseudo-elements are allowed // CSS2 pseudo-elements and -moz-tree-* pseudo-elements are allowed
// to have a single ':' on them. Others (CSS3+ pseudo-elements and // to have a single ':' on them. Others (CSS3+ pseudo-elements and
@ -2359,8 +2350,7 @@ void CSSParserImpl::ParsePseudoSelector(PRInt32& aDataMask,
) { ) {
REPORT_UNEXPECTED_TOKEN(PEPseudoSelNewStyleOnly); REPORT_UNEXPECTED_TOKEN(PEPseudoSelNewStyleOnly);
UngetToken(); UngetToken();
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
if (0 == (aDataMask & SEL_MASK_PELEM)) { if (0 == (aDataMask & SEL_MASK_PELEM)) {
@ -2374,8 +2364,7 @@ void CSSParserImpl::ParsePseudoSelector(PRInt32& aDataMask,
// item in the list to the pseudoclass list. They will be pulled // item in the list to the pseudoclass list. They will be pulled
// from the list later along with the pseudo-element. // from the list later along with the pseudo-element.
if (!ParseTreePseudoElement(aErrorCode, aSelector)) { if (!ParseTreePseudoElement(aErrorCode, aSelector)) {
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
} }
#endif #endif
@ -2385,194 +2374,178 @@ void CSSParserImpl::ParsePseudoSelector(PRInt32& aDataMask,
if ((eCSSToken_WhiteSpace == mToken.mType) || if ((eCSSToken_WhiteSpace == mToken.mType) ||
(mToken.IsSymbol('{') || mToken.IsSymbol(','))) { (mToken.IsSymbol('{') || mToken.IsSymbol(','))) {
UngetToken(); UngetToken();
aParsingStatus = SELECTOR_PARSING_STOPPED_OK; return eSelectorParsingStatus_Done;
return;
} }
REPORT_UNEXPECTED_TOKEN(PEPseudoSelTrailing); REPORT_UNEXPECTED_TOKEN(PEPseudoSelTrailing);
UngetToken(); UngetToken();
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
} }
else { // multiple pseudo elements, not legal else { // multiple pseudo elements, not legal
REPORT_UNEXPECTED_TOKEN(PEPseudoSelMultiplePE); REPORT_UNEXPECTED_TOKEN(PEPseudoSelMultiplePE);
UngetToken(); UngetToken();
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
} else { } else {
// Not a pseudo-class, not a pseudo-element.... forget it // Not a pseudo-class, not a pseudo-element.... forget it
REPORT_UNEXPECTED_TOKEN(PEPseudoSelUnknown); REPORT_UNEXPECTED_TOKEN(PEPseudoSelUnknown);
UngetToken(); UngetToken();
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
aParsingStatus = SELECTOR_PARSING_ENDED_OK; return eSelectorParsingStatus_Continue;
} }
// //
// Parse the argument of a negation pseudo-class :not() // Parse the argument of a negation pseudo-class :not()
// //
void CSSParserImpl::ParseNegatedSimpleSelector(PRInt32& aDataMask, CSSParserImpl::nsSelectorParsingStatus
nsCSSSelector& aSelector, CSSParserImpl::ParseNegatedSimpleSelector(PRInt32& aDataMask,
PRInt32& aParsingStatus, nsCSSSelector& aSelector,
nsresult& aErrorCode) nsresult& aErrorCode)
{ {
// Check if we have the first parenthesis // Check if we have the first parenthesis
if (ExpectSymbol(aErrorCode, '(', PR_FALSE)) { if (!ExpectSymbol(aErrorCode, '(', PR_FALSE)) {
REPORT_UNEXPECTED_TOKEN(PENegationBadArg);
if (! GetToken(aErrorCode, PR_FALSE)) { // premature eof return eSelectorParsingStatus_Error;
REPORT_UNEXPECTED_EOF(PENegationEOF); }
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR;
return; if (! GetToken(aErrorCode, PR_FALSE)) { // premature eof
} REPORT_UNEXPECTED_EOF(PENegationEOF);
aParsingStatus = SELECTOR_PARSING_ENDED_OK; return eSelectorParsingStatus_Error;
}
if (!aSelector.mNegations) {
aSelector.mNegations = new nsCSSSelector();
if (!aSelector.mNegations) { if (!aSelector.mNegations) {
aSelector.mNegations = new nsCSSSelector(); aErrorCode = NS_ERROR_OUT_OF_MEMORY;
if (!aSelector.mNegations) { return eSelectorParsingStatus_Error;
aErrorCode = NS_ERROR_OUT_OF_MEMORY;
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR;
return;
}
}
// ID, class and attribute selectors and pseudo-classes are stored in
// the first mNegations attached to a selector
if (eCSSToken_ID == mToken.mType) { // #id
ParseIDSelector(aDataMask, *aSelector.mNegations, aParsingStatus, aErrorCode);
}
else if (mToken.IsSymbol('.')) { // .class
ParseClassSelector(aDataMask, *aSelector.mNegations, aParsingStatus, aErrorCode);
}
else if (mToken.IsSymbol(':')) { // :pseudo
ParsePseudoSelector(aDataMask, *aSelector.mNegations, aParsingStatus, aErrorCode, PR_TRUE);
}
else if (mToken.IsSymbol('[')) { // attribute
ParseAttributeSelector(aDataMask, *aSelector.mNegations, aParsingStatus, aErrorCode);
}
else {
// then it should be a type element or universal selector
nsCSSSelector *newSel = new nsCSSSelector();
if (!newSel) {
aErrorCode = NS_ERROR_OUT_OF_MEMORY;
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR;
return;
}
nsCSSSelector* negations = aSelector.mNegations;
while (nsnull != negations->mNegations) {
negations = negations->mNegations;
}
// negated type element selectors and universal selectors are stored after the first
// mNegations containing only negated IDs, classes, attributes and pseudo-classes
negations->mNegations = newSel;
ParseTypeOrUniversalSelector(aDataMask, *newSel, aParsingStatus, aErrorCode, PR_TRUE);
}
if (SELECTOR_PARSING_STOPPED_ERROR == aParsingStatus) {
REPORT_UNEXPECTED_TOKEN(PENegationBadInner);
return;
}
// close the parenthesis
if (!ExpectSymbol(aErrorCode, ')', PR_TRUE)) {
REPORT_UNEXPECTED_TOKEN(PENegationNoClose);
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR;
} }
} }
// ID, class and attribute selectors and pseudo-classes are stored in
// the first mNegations attached to a selector
nsSelectorParsingStatus parsingStatus;
if (eCSSToken_ID == mToken.mType) { // #id
parsingStatus = ParseIDSelector(aDataMask, *aSelector.mNegations, aErrorCode);
}
else if (mToken.IsSymbol('.')) { // .class
parsingStatus = ParseClassSelector(aDataMask, *aSelector.mNegations, aErrorCode);
}
else if (mToken.IsSymbol(':')) { // :pseudo
parsingStatus = ParsePseudoSelector(aDataMask, *aSelector.mNegations, aErrorCode, PR_TRUE);
}
else if (mToken.IsSymbol('[')) { // [attribute
parsingStatus = ParseAttributeSelector(aDataMask, *aSelector.mNegations, aErrorCode);
}
else { else {
REPORT_UNEXPECTED_TOKEN(PENegationBadArg); // then it should be a type element or universal selector
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; nsCSSSelector *newSel = new nsCSSSelector();
if (!newSel) {
aErrorCode = NS_ERROR_OUT_OF_MEMORY;
return eSelectorParsingStatus_Error;
}
nsCSSSelector* negations = aSelector.mNegations;
while (nsnull != negations->mNegations) {
negations = negations->mNegations;
}
// negated type element selectors and universal selectors are stored after the first
// mNegations containing only negated IDs, classes, attributes and pseudo-classes
negations->mNegations = newSel;
parsingStatus = ParseTypeOrUniversalSelector(aDataMask, *newSel, aErrorCode, PR_TRUE);
} }
if (eSelectorParsingStatus_Error == parsingStatus) {
REPORT_UNEXPECTED_TOKEN(PENegationBadInner);
return parsingStatus;
}
// close the parenthesis
if (!ExpectSymbol(aErrorCode, ')', PR_TRUE)) {
REPORT_UNEXPECTED_TOKEN(PENegationNoClose);
return eSelectorParsingStatus_Error;
}
return eSelectorParsingStatus_Continue;
} }
// //
// Parse the argument of a pseudo-class :lang() // Parse the argument of a pseudo-class :lang()
// //
void CSSParserImpl::ParseLangSelector(nsCSSSelector& aSelector, CSSParserImpl::nsSelectorParsingStatus
PRInt32& aParsingStatus, CSSParserImpl::ParseLangSelector(nsCSSSelector& aSelector, nsresult& aErrorCode)
nsresult& aErrorCode)
{ {
// Check if we have the first parenthesis // Check if we have the first parenthesis
if (ExpectSymbol(aErrorCode, '(', PR_FALSE)) { if (!ExpectSymbol(aErrorCode, '(', PR_FALSE)) {
if (! GetToken(aErrorCode, PR_TRUE)) { // premature eof
REPORT_UNEXPECTED_EOF(PELangArgEOF);
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR;
return;
}
// We expect an identifier with a language abbreviation
if (eCSSToken_Ident != mToken.mType) {
REPORT_UNEXPECTED_TOKEN(PELangArgNotIdent);
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR;
return;
}
// Add the pseudo with the language parameter
aSelector.AddPseudoClass(nsCSSPseudoClasses::lang, mToken.mIdent.get());
// close the parenthesis
if (!ExpectSymbol(aErrorCode, ')', PR_TRUE)) {
REPORT_UNEXPECTED_TOKEN(PELangNoClose);
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR;
}
}
else {
REPORT_UNEXPECTED_TOKEN(PELangNoArg); REPORT_UNEXPECTED_TOKEN(PELangNoArg);
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
} }
if (! GetToken(aErrorCode, PR_TRUE)) { // premature eof
REPORT_UNEXPECTED_EOF(PELangArgEOF);
return eSelectorParsingStatus_Error;
}
// We expect an identifier with a language abbreviation
if (eCSSToken_Ident != mToken.mType) {
REPORT_UNEXPECTED_TOKEN(PELangArgNotIdent);
UngetToken();
return eSelectorParsingStatus_Error;
}
// Add the pseudo with the language parameter
aSelector.AddPseudoClass(nsCSSPseudoClasses::lang, mToken.mIdent.get());
// close the parenthesis
if (!ExpectSymbol(aErrorCode, ')', PR_TRUE)) {
REPORT_UNEXPECTED_TOKEN(PELangNoClose);
return eSelectorParsingStatus_Error;
}
return eSelectorParsingStatus_Continue;
} }
/** /**
* This is the format for selectors: * This is the format for selectors:
* operator? [[namespace |]? element_name]? [ ID | class | attrib | pseudo ]* * operator? [[namespace |]? element_name]? [ ID | class | attrib | pseudo ]*
*/ */
PRBool CSSParserImpl::ParseSelector(nsresult& aErrorCode, CSSParserImpl::nsSelectorParsingStatus
nsCSSSelector& aSelector) CSSParserImpl::ParseSelector(nsresult& aErrorCode, nsCSSSelector& aSelector)
{ {
PRInt32 dataMask = 0;
PRInt32 parsingStatus = SELECTOR_PARSING_ENDED_OK;
if (! GetToken(aErrorCode, PR_TRUE)) { if (! GetToken(aErrorCode, PR_TRUE)) {
REPORT_UNEXPECTED_EOF(PESelectorEOF); REPORT_UNEXPECTED_EOF(PESelectorEOF);
return PR_FALSE; return eSelectorParsingStatus_Error;
} }
ParseTypeOrUniversalSelector(dataMask, aSelector, parsingStatus, aErrorCode, PR_FALSE); PRInt32 dataMask = 0;
if (SELECTOR_PARSING_STOPPED_OK == parsingStatus) { nsSelectorParsingStatus parsingStatus =
return PR_TRUE; ParseTypeOrUniversalSelector(dataMask, aSelector, aErrorCode, PR_FALSE);
} if (parsingStatus != eSelectorParsingStatus_Continue) {
else if (SELECTOR_PARSING_STOPPED_ERROR == parsingStatus) { return parsingStatus;
return PR_FALSE;
} }
for (;;) { for (;;) {
parsingStatus = SELECTOR_PARSING_ENDED_OK; if (eCSSToken_ID == mToken.mType) { // #id
if (eCSSToken_ID == mToken.mType) { // #id parsingStatus = ParseIDSelector(dataMask, aSelector, aErrorCode);
ParseIDSelector(dataMask, aSelector, parsingStatus, aErrorCode);
} }
else if (mToken.IsSymbol('.')) { // .class else if (mToken.IsSymbol('.')) { // .class
ParseClassSelector(dataMask, aSelector, parsingStatus, aErrorCode); parsingStatus = ParseClassSelector(dataMask, aSelector, aErrorCode);
} }
else if (mToken.IsSymbol(':')) { // :pseudo else if (mToken.IsSymbol(':')) { // :pseudo
ParsePseudoSelector(dataMask, aSelector, parsingStatus, aErrorCode, PR_FALSE); parsingStatus = ParsePseudoSelector(dataMask, aSelector, aErrorCode, PR_FALSE);
} }
else if (mToken.IsSymbol('[')) { // attribute else if (mToken.IsSymbol('[')) { // [attribute
ParseAttributeSelector(dataMask, aSelector, parsingStatus, aErrorCode); parsingStatus = ParseAttributeSelector(dataMask, aSelector, aErrorCode);
} }
else { // not a selector token, we're done else { // not a selector token, we're done
parsingStatus = eSelectorParsingStatus_Done;
break; break;
} }
if (SELECTOR_PARSING_STOPPED_OK == parsingStatus) { if (parsingStatus != eSelectorParsingStatus_Continue) {
return PR_TRUE; return parsingStatus;
} }
else if (SELECTOR_PARSING_STOPPED_ERROR == parsingStatus) {
return PR_FALSE;
}
if (! GetToken(aErrorCode, PR_FALSE)) { // premature eof is ok (here!) if (! GetToken(aErrorCode, PR_FALSE)) { // premature eof is ok (here!)
return PR_TRUE; return eSelectorParsingStatus_Done;
} }
} }
UngetToken(); UngetToken();
return PRBool(0 != dataMask); return dataMask ? parsingStatus : eSelectorParsingStatus_Empty;
} }
nsCSSDeclaration* nsCSSDeclaration*

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

@ -179,28 +179,51 @@ protected:
PRBool ParseFontFaceRule(nsresult& aErrorCode, RuleAppendFunc aAppendFunc, void* aProcessData); PRBool ParseFontFaceRule(nsresult& aErrorCode, RuleAppendFunc aAppendFunc, void* aProcessData);
PRBool ParsePageRule(nsresult& aErrorCode, RuleAppendFunc aAppendFunc, void* aProcessData); PRBool ParsePageRule(nsresult& aErrorCode, RuleAppendFunc aAppendFunc, void* aProcessData);
void ParseIDSelector(PRInt32& aDataMask, nsCSSSelector& aSelector, enum nsSelectorParsingStatus {
PRInt32& aParsingStatus, nsresult& aErrorCode); // we have parsed a selector and we saw a token that cannot be part of a selector:
void ParseClassSelector(PRInt32& aDataMask, nsCSSSelector& aSelector, eSelectorParsingStatus_Done,
PRInt32& aParsingStatus, nsresult& aErrorCode); // we should continue parsing the selector:
void ParsePseudoSelector(PRInt32& aDataMask, nsCSSSelector& aSelector, eSelectorParsingStatus_Continue,
PRInt32& aParsingStatus, nsresult& aErrorCode, // same as "Done" but we did not find a selector:
PRBool aIsNegated); eSelectorParsingStatus_Empty,
void ParseAttributeSelector(PRInt32& aDataMask, nsCSSSelector& aSelector, // we saw an unexpected token or token value,
PRInt32& aParsingStatus, nsresult& aErrorCode); // or we saw end-of-file with an unfinished selector:
eSelectorParsingStatus_Error
};
nsSelectorParsingStatus ParseIDSelector(PRInt32& aDataMask,
nsCSSSelector& aSelector,
nsresult& aErrorCode);
void ParseTypeOrUniversalSelector(PRInt32& aDataMask, nsSelectorParsingStatus ParseClassSelector(PRInt32& aDataMask,
nsCSSSelector& aSelector, nsCSSSelector& aSelector,
PRInt32& aParsingStatus, nsresult& aErrorCode, nsresult& aErrorCode);
PRBool aIsNegated);
void ParseNegatedSimpleSelector(PRInt32& aDataMask, nsCSSSelector& aSelector, nsSelectorParsingStatus ParsePseudoSelector(PRInt32& aDataMask,
PRInt32& aParsingStatus, nsresult& aErrorCode); nsCSSSelector& aSelector,
void ParseLangSelector(nsCSSSelector& aSelector, PRInt32& aParsingStatus, nsresult& aErrorCode,
nsresult& aErrorCode); PRBool aIsNegated);
nsSelectorParsingStatus ParseAttributeSelector(PRInt32& aDataMask,
nsCSSSelector& aSelector,
nsresult& aErrorCode);
nsSelectorParsingStatus ParseTypeOrUniversalSelector(PRInt32& aDataMask,
nsCSSSelector& aSelector,
nsresult& aErrorCode,
PRBool aIsNegated);
nsSelectorParsingStatus ParseLangSelector(nsCSSSelector& aSelector,
nsresult& aErrorCode);
nsSelectorParsingStatus ParseNegatedSimpleSelector(PRInt32& aDataMask,
nsCSSSelector& aSelector,
nsresult& aErrorCode);
nsSelectorParsingStatus ParseSelector(nsresult& aErrorCode,
nsCSSSelector& aSelectorResult);
PRBool ParseSelectorList(nsresult& aErrorCode, nsCSSSelectorList*& aListHead); PRBool ParseSelectorList(nsresult& aErrorCode, nsCSSSelectorList*& aListHead);
PRBool ParseSelectorGroup(nsresult& aErrorCode, nsCSSSelectorList*& aListHead); PRBool ParseSelectorGroup(nsresult& aErrorCode, nsCSSSelectorList*& aListHead);
PRBool ParseSelector(nsresult& aErrorCode, nsCSSSelector& aSelectorResult);
nsCSSDeclaration* ParseDeclarationBlock(nsresult& aErrorCode, nsCSSDeclaration* ParseDeclarationBlock(nsresult& aErrorCode,
PRBool aCheckForBraces); PRBool aCheckForBraces);
PRBool ParseDeclaration(nsresult& aErrorCode, PRBool ParseDeclaration(nsresult& aErrorCode,
@ -1651,7 +1674,18 @@ PRBool CSSParserImpl::ParseSelectorGroup(nsresult& aErrorCode,
PRBool done = PR_FALSE; PRBool done = PR_FALSE;
while (!done) { while (!done) {
nsCSSSelector selector; nsCSSSelector selector;
if (! ParseSelector(aErrorCode, selector)) { nsSelectorParsingStatus parsingStatus = ParseSelector(aErrorCode, selector);
if (parsingStatus == eSelectorParsingStatus_Empty) {
if (!list) {
REPORT_UNEXPECTED(PESelectorGroupNoSelector);
}
break;
}
if (parsingStatus == eSelectorParsingStatus_Error) {
if (list) {
delete list;
list = nsnull;
}
break; break;
} }
if (nsnull == list) { if (nsnull == list) {
@ -1747,14 +1781,12 @@ PRBool CSSParserImpl::ParseSelectorGroup(nsresult& aErrorCode,
weight += selector.CalcWeight(); weight += selector.CalcWeight();
} }
} }
if (!list) {
REPORT_UNEXPECTED(PESelectorGroupNoSelector);
}
if (PRUnichar(0) != combinator) { // no dangling combinators if (PRUnichar(0) != combinator) { // no dangling combinators
if (list) { if (list) {
delete list; delete list;
list = nsnull;
} }
list = nsnull;
// This should report the problematic combinator // This should report the problematic combinator
REPORT_UNEXPECTED(PESelectorGroupExtraCombinator); REPORT_UNEXPECTED(PESelectorGroupExtraCombinator);
} }
@ -1773,17 +1805,13 @@ PRBool CSSParserImpl::ParseSelectorGroup(nsresult& aErrorCode,
#define SEL_MASK_PCLASS 0x20 #define SEL_MASK_PCLASS 0x20
#define SEL_MASK_PELEM 0x40 #define SEL_MASK_PELEM 0x40
#define SELECTOR_PARSING_ENDED_OK 1
#define SELECTOR_PARSING_STOPPED_OK 2
#define SELECTOR_PARSING_STOPPED_ERROR 3
// //
// Parses an ID selector #name // Parses an ID selector #name
// //
void CSSParserImpl::ParseIDSelector(PRInt32& aDataMask, CSSParserImpl::nsSelectorParsingStatus
nsCSSSelector& aSelector, CSSParserImpl::ParseIDSelector(PRInt32& aDataMask,
PRInt32& aParsingStatus, nsCSSSelector& aSelector,
nsresult& aErrorCode) nsresult& aErrorCode)
{ {
if (!mToken.mIdent.IsEmpty()) { // verify is legal ID if (!mToken.mIdent.IsEmpty()) { // verify is legal ID
PRUnichar first = mToken.mIdent.First(); PRUnichar first = mToken.mIdent.First();
@ -1795,8 +1823,7 @@ void CSSParserImpl::ParseIDSelector(PRInt32& aDataMask,
nsCSSScanner::GetLexTable())) { nsCSSScanner::GetLexTable())) {
REPORT_UNEXPECTED_TOKEN(PEIDSelNotIdent); REPORT_UNEXPECTED_TOKEN(PEIDSelNotIdent);
UngetToken(); UngetToken();
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
aDataMask |= SEL_MASK_ID; aDataMask |= SEL_MASK_ID;
aSelector.AddID(mToken.mIdent); aSelector.AddID(mToken.mIdent);
@ -1804,47 +1831,44 @@ void CSSParserImpl::ParseIDSelector(PRInt32& aDataMask,
else { else {
REPORT_UNEXPECTED_TOKEN(PEIDSelEmpty); REPORT_UNEXPECTED_TOKEN(PEIDSelEmpty);
UngetToken(); UngetToken();
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
aParsingStatus = SELECTOR_PARSING_ENDED_OK; return eSelectorParsingStatus_Continue;
} }
// //
// Parses a class selector .name // Parses a class selector .name
// //
void CSSParserImpl::ParseClassSelector(PRInt32& aDataMask, CSSParserImpl::nsSelectorParsingStatus
nsCSSSelector& aSelector, CSSParserImpl::ParseClassSelector(PRInt32& aDataMask,
PRInt32& aParsingStatus, nsCSSSelector& aSelector,
nsresult& aErrorCode) nsresult& aErrorCode)
{ {
if (! GetToken(aErrorCode, PR_FALSE)) { // get ident if (! GetToken(aErrorCode, PR_FALSE)) { // get ident
REPORT_UNEXPECTED_EOF(PEClassSelEOF); REPORT_UNEXPECTED_EOF(PEClassSelEOF);
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
if (eCSSToken_Ident != mToken.mType) { // malformed selector if (eCSSToken_Ident != mToken.mType) { // malformed selector
REPORT_UNEXPECTED_TOKEN(PEClassSelNotIdent); REPORT_UNEXPECTED_TOKEN(PEClassSelNotIdent);
UngetToken(); UngetToken();
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
aDataMask |= SEL_MASK_CLASS; aDataMask |= SEL_MASK_CLASS;
aSelector.AddClass(mToken.mIdent); aSelector.AddClass(mToken.mIdent);
aParsingStatus = SELECTOR_PARSING_ENDED_OK; return eSelectorParsingStatus_Continue;
} }
// //
// Parse a type element selector or a universal selector // Parse a type element selector or a universal selector
// namespace|type or namespace|* or *|* or * // namespace|type or namespace|* or *|* or *
// //
void CSSParserImpl::ParseTypeOrUniversalSelector(PRInt32& aDataMask, CSSParserImpl::nsSelectorParsingStatus
nsCSSSelector& aSelector, CSSParserImpl::ParseTypeOrUniversalSelector(PRInt32& aDataMask,
PRInt32& aParsingStatus, nsCSSSelector& aSelector,
nsresult& aErrorCode, nsresult& aErrorCode,
PRBool aIsNegated) PRBool aIsNegated)
{ {
nsAutoString buffer; nsAutoString buffer;
if (mToken.IsSymbol('*')) { // universal element selector, or universal namespace if (mToken.IsSymbol('*')) { // universal element selector, or universal namespace
@ -1854,8 +1878,7 @@ void CSSParserImpl::ParseTypeOrUniversalSelector(PRInt32& aDataMask,
if (! GetToken(aErrorCode, PR_FALSE)) { if (! GetToken(aErrorCode, PR_FALSE)) {
REPORT_UNEXPECTED_EOF(PETypeSelEOF); REPORT_UNEXPECTED_EOF(PETypeSelEOF);
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
if (eCSSToken_Ident == mToken.mType) { // element name if (eCSSToken_Ident == mToken.mType) { // element name
aDataMask |= SEL_MASK_ELEM; aDataMask |= SEL_MASK_ELEM;
@ -1874,8 +1897,7 @@ void CSSParserImpl::ParseTypeOrUniversalSelector(PRInt32& aDataMask,
else { else {
REPORT_UNEXPECTED_TOKEN(PETypeSelNotType); REPORT_UNEXPECTED_TOKEN(PETypeSelNotType);
UngetToken(); UngetToken();
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
} }
else { // was universal element selector else { // was universal element selector
@ -1893,8 +1915,7 @@ void CSSParserImpl::ParseTypeOrUniversalSelector(PRInt32& aDataMask,
// don't set any tag in the selector // don't set any tag in the selector
} }
if (! GetToken(aErrorCode, PR_FALSE)) { // premature eof is ok (here!) if (! GetToken(aErrorCode, PR_FALSE)) { // premature eof is ok (here!)
aParsingStatus = SELECTOR_PARSING_STOPPED_OK; return eSelectorParsingStatus_Done;
return;
} }
} }
else if (eCSSToken_Ident == mToken.mType) { // element name or namespace name else if (eCSSToken_Ident == mToken.mType) { // element name or namespace name
@ -1913,15 +1934,13 @@ void CSSParserImpl::ParseTypeOrUniversalSelector(PRInt32& aDataMask,
buffer.get() buffer.get()
}; };
REPORT_UNEXPECTED_P(PEUnknownNamespacePrefix, params); REPORT_UNEXPECTED_P(PEUnknownNamespacePrefix, params);
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
aSelector.SetNameSpace(nameSpaceID); aSelector.SetNameSpace(nameSpaceID);
if (! GetToken(aErrorCode, PR_FALSE)) { if (! GetToken(aErrorCode, PR_FALSE)) {
REPORT_UNEXPECTED_EOF(PETypeSelEOF); REPORT_UNEXPECTED_EOF(PETypeSelEOF);
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
if (eCSSToken_Ident == mToken.mType) { // element name if (eCSSToken_Ident == mToken.mType) { // element name
aDataMask |= SEL_MASK_ELEM; aDataMask |= SEL_MASK_ELEM;
@ -1940,8 +1959,7 @@ void CSSParserImpl::ParseTypeOrUniversalSelector(PRInt32& aDataMask,
else { else {
REPORT_UNEXPECTED_TOKEN(PETypeSelNotType); REPORT_UNEXPECTED_TOKEN(PETypeSelNotType);
UngetToken(); UngetToken();
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
} }
else { // was element name else { // was element name
@ -1965,8 +1983,7 @@ void CSSParserImpl::ParseTypeOrUniversalSelector(PRInt32& aDataMask,
aDataMask |= SEL_MASK_ELEM; aDataMask |= SEL_MASK_ELEM;
} }
if (! GetToken(aErrorCode, PR_FALSE)) { // premature eof is ok (here!) if (! GetToken(aErrorCode, PR_FALSE)) { // premature eof is ok (here!)
aParsingStatus = SELECTOR_PARSING_STOPPED_OK; return eSelectorParsingStatus_Done;
return;
} }
} }
else if (mToken.IsSymbol('|')) { // No namespace else if (mToken.IsSymbol('|')) { // No namespace
@ -1976,8 +1993,7 @@ void CSSParserImpl::ParseTypeOrUniversalSelector(PRInt32& aDataMask,
// get mandatory tag // get mandatory tag
if (! GetToken(aErrorCode, PR_FALSE)) { if (! GetToken(aErrorCode, PR_FALSE)) {
REPORT_UNEXPECTED_EOF(PETypeSelEOF); REPORT_UNEXPECTED_EOF(PETypeSelEOF);
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
if (eCSSToken_Ident == mToken.mType) { // element name if (eCSSToken_Ident == mToken.mType) { // element name
aDataMask |= SEL_MASK_ELEM; aDataMask |= SEL_MASK_ELEM;
@ -1996,12 +2012,10 @@ void CSSParserImpl::ParseTypeOrUniversalSelector(PRInt32& aDataMask,
else { else {
REPORT_UNEXPECTED_TOKEN(PETypeSelNotType); REPORT_UNEXPECTED_TOKEN(PETypeSelNotType);
UngetToken(); UngetToken();
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
if (! GetToken(aErrorCode, PR_FALSE)) { // premature eof is ok (here!) if (! GetToken(aErrorCode, PR_FALSE)) { // premature eof is ok (here!)
aParsingStatus = SELECTOR_PARSING_STOPPED_OK; return eSelectorParsingStatus_Done;
return;
} }
} }
else { else {
@ -2019,26 +2033,25 @@ void CSSParserImpl::ParseTypeOrUniversalSelector(PRInt32& aDataMask,
} }
} }
aParsingStatus = SELECTOR_PARSING_ENDED_OK;
if (aIsNegated) { if (aIsNegated) {
// restore last token read in case of a negated type selector // restore last token read in case of a negated type selector
UngetToken(); UngetToken();
} }
return eSelectorParsingStatus_Continue;
} }
// //
// Parse attribute selectors [attr], [attr=value], [attr|=value], // Parse attribute selectors [attr], [attr=value], [attr|=value],
// [attr~=value], [attr^=value], [attr$=value] and [attr*=value] // [attr~=value], [attr^=value], [attr$=value] and [attr*=value]
// //
void CSSParserImpl::ParseAttributeSelector(PRInt32& aDataMask, CSSParserImpl::nsSelectorParsingStatus
CSSParserImpl::ParseAttributeSelector(PRInt32& aDataMask,
nsCSSSelector& aSelector, nsCSSSelector& aSelector,
PRInt32& aParsingStatus, nsresult& aErrorCode)
nsresult& aErrorCode)
{ {
if (! GetToken(aErrorCode, PR_TRUE)) { // premature EOF if (! GetToken(aErrorCode, PR_TRUE)) { // premature EOF
REPORT_UNEXPECTED_EOF(PEAttributeNameEOF); REPORT_UNEXPECTED_EOF(PEAttributeNameEOF);
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
PRInt32 nameSpaceID = kNameSpaceID_None; PRInt32 nameSpaceID = kNameSpaceID_None;
@ -2048,8 +2061,7 @@ void CSSParserImpl::ParseAttributeSelector(PRInt32& aDataMask,
if (ExpectSymbol(aErrorCode, '|', PR_FALSE)) { if (ExpectSymbol(aErrorCode, '|', PR_FALSE)) {
if (! GetToken(aErrorCode, PR_FALSE)) { // premature EOF if (! GetToken(aErrorCode, PR_FALSE)) { // premature EOF
REPORT_UNEXPECTED_EOF(PEAttributeNameEOF); REPORT_UNEXPECTED_EOF(PEAttributeNameEOF);
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
if (eCSSToken_Ident == mToken.mType) { // attr name if (eCSSToken_Ident == mToken.mType) { // attr name
attr = mToken.mIdent; attr = mToken.mIdent;
@ -2057,21 +2069,18 @@ void CSSParserImpl::ParseAttributeSelector(PRInt32& aDataMask,
else { else {
REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected); REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected);
UngetToken(); UngetToken();
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
} }
else { else {
REPORT_UNEXPECTED_TOKEN(PEAttSelNoBar); REPORT_UNEXPECTED_TOKEN(PEAttSelNoBar);
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
} }
else if (mToken.IsSymbol('|')) { // NO namespace else if (mToken.IsSymbol('|')) { // NO namespace
if (! GetToken(aErrorCode, PR_FALSE)) { // premature EOF if (! GetToken(aErrorCode, PR_FALSE)) { // premature EOF
REPORT_UNEXPECTED_EOF(PEAttributeNameEOF); REPORT_UNEXPECTED_EOF(PEAttributeNameEOF);
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
if (eCSSToken_Ident == mToken.mType) { // attr name if (eCSSToken_Ident == mToken.mType) { // attr name
attr = mToken.mIdent; attr = mToken.mIdent;
@ -2079,8 +2088,7 @@ void CSSParserImpl::ParseAttributeSelector(PRInt32& aDataMask,
else { else {
REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected); REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected);
UngetToken(); UngetToken();
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
} }
else if (eCSSToken_Ident == mToken.mType) { // attr name or namespace else if (eCSSToken_Ident == mToken.mType) { // attr name or namespace
@ -2097,13 +2105,11 @@ void CSSParserImpl::ParseAttributeSelector(PRInt32& aDataMask,
attr.get() attr.get()
}; };
REPORT_UNEXPECTED_P(PEUnknownNamespacePrefix, params); REPORT_UNEXPECTED_P(PEUnknownNamespacePrefix, params);
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
if (! GetToken(aErrorCode, PR_FALSE)) { // premature EOF if (! GetToken(aErrorCode, PR_FALSE)) { // premature EOF
REPORT_UNEXPECTED_EOF(PEAttributeNameEOF); REPORT_UNEXPECTED_EOF(PEAttributeNameEOF);
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
if (eCSSToken_Ident == mToken.mType) { // attr name if (eCSSToken_Ident == mToken.mType) { // attr name
attr = mToken.mIdent; attr = mToken.mIdent;
@ -2111,16 +2117,14 @@ void CSSParserImpl::ParseAttributeSelector(PRInt32& aDataMask,
else { else {
REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected); REPORT_UNEXPECTED_TOKEN(PEAttributeNameExpected);
UngetToken(); UngetToken();
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
} }
} }
else { // malformed else { // malformed
REPORT_UNEXPECTED_TOKEN(PEAttributeNameOrNamespaceExpected); REPORT_UNEXPECTED_TOKEN(PEAttributeNameOrNamespaceExpected);
UngetToken(); UngetToken();
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
if (! mCaseSensitive) { if (! mCaseSensitive) {
@ -2128,8 +2132,7 @@ void CSSParserImpl::ParseAttributeSelector(PRInt32& aDataMask,
} }
if (! GetToken(aErrorCode, PR_TRUE)) { // premature EOF if (! GetToken(aErrorCode, PR_TRUE)) { // premature EOF
REPORT_UNEXPECTED_EOF(PEAttSelInnerEOF); REPORT_UNEXPECTED_EOF(PEAttSelInnerEOF);
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
if ((eCSSToken_Symbol == mToken.mType) || if ((eCSSToken_Symbol == mToken.mType) ||
(eCSSToken_Includes == mToken.mType) || (eCSSToken_Includes == mToken.mType) ||
@ -2164,21 +2167,18 @@ void CSSParserImpl::ParseAttributeSelector(PRInt32& aDataMask,
else { else {
REPORT_UNEXPECTED_TOKEN(PEAttSelUnexpected); REPORT_UNEXPECTED_TOKEN(PEAttSelUnexpected);
UngetToken(); // bad function UngetToken(); // bad function
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
if (NS_ATTR_FUNC_SET != func) { // get value if (NS_ATTR_FUNC_SET != func) { // get value
if (! GetToken(aErrorCode, PR_TRUE)) { // premature EOF if (! GetToken(aErrorCode, PR_TRUE)) { // premature EOF
REPORT_UNEXPECTED_EOF(PEAttSelValueEOF); REPORT_UNEXPECTED_EOF(PEAttSelValueEOF);
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
if ((eCSSToken_Ident == mToken.mType) || (eCSSToken_String == mToken.mType)) { if ((eCSSToken_Ident == mToken.mType) || (eCSSToken_String == mToken.mType)) {
nsAutoString value(mToken.mIdent); nsAutoString value(mToken.mIdent);
if (! GetToken(aErrorCode, PR_TRUE)) { // premature EOF if (! GetToken(aErrorCode, PR_TRUE)) { // premature EOF
REPORT_UNEXPECTED_EOF(PEAttSelCloseEOF); REPORT_UNEXPECTED_EOF(PEAttSelCloseEOF);
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
if (mToken.IsSymbol(']')) { if (mToken.IsSymbol(']')) {
PRBool isCaseSensitive = mCaseSensitive; PRBool isCaseSensitive = mCaseSensitive;
@ -2207,40 +2207,36 @@ void CSSParserImpl::ParseAttributeSelector(PRInt32& aDataMask,
else { else {
REPORT_UNEXPECTED_TOKEN(PEAttSelNoClose); REPORT_UNEXPECTED_TOKEN(PEAttSelNoClose);
UngetToken(); UngetToken();
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
} }
else { else {
REPORT_UNEXPECTED_TOKEN(PEAttSelBadValue); REPORT_UNEXPECTED_TOKEN(PEAttSelBadValue);
UngetToken(); UngetToken();
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
} }
} }
else { else {
REPORT_UNEXPECTED_TOKEN(PEAttSelUnexpected); REPORT_UNEXPECTED_TOKEN(PEAttSelUnexpected);
UngetToken(); // bad dog, no biscut! UngetToken(); // bad dog, no biscut!
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
aParsingStatus = SELECTOR_PARSING_ENDED_OK; return eSelectorParsingStatus_Continue;
} }
// //
// Parse pseudo-classes and pseudo-elements // Parse pseudo-classes and pseudo-elements
// //
void CSSParserImpl::ParsePseudoSelector(PRInt32& aDataMask, CSSParserImpl::nsSelectorParsingStatus
nsCSSSelector& aSelector, CSSParserImpl::ParsePseudoSelector(PRInt32& aDataMask,
PRInt32& aParsingStatus, nsCSSSelector& aSelector,
nsresult& aErrorCode, nsresult& aErrorCode,
PRBool aIsNegated) PRBool aIsNegated)
{ {
if (! GetToken(aErrorCode, PR_FALSE)) { // premature eof if (! GetToken(aErrorCode, PR_FALSE)) { // premature eof
REPORT_UNEXPECTED_EOF(PEPseudoSelEOF); REPORT_UNEXPECTED_EOF(PEPseudoSelEOF);
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
// First, find out whether we are parsing a CSS3 pseudo-element // First, find out whether we are parsing a CSS3 pseudo-element
@ -2249,8 +2245,7 @@ void CSSParserImpl::ParsePseudoSelector(PRInt32& aDataMask,
parsingPseudoElement = PR_TRUE; parsingPseudoElement = PR_TRUE;
if (! GetToken(aErrorCode, PR_FALSE)) { // premature eof if (! GetToken(aErrorCode, PR_FALSE)) { // premature eof
REPORT_UNEXPECTED_EOF(PEPseudoSelEOF); REPORT_UNEXPECTED_EOF(PEPseudoSelEOF);
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
} }
@ -2259,8 +2254,7 @@ void CSSParserImpl::ParsePseudoSelector(PRInt32& aDataMask,
// malformed selector // malformed selector
REPORT_UNEXPECTED_TOKEN(PEPseudoSelBadName); REPORT_UNEXPECTED_TOKEN(PEPseudoSelBadName);
UngetToken(); UngetToken();
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
// OK, now we know we have an mIdent. Atomize it. All the atoms, for // OK, now we know we have an mIdent. Atomize it. All the atoms, for
@ -2297,8 +2291,7 @@ void CSSParserImpl::ParsePseudoSelector(PRInt32& aDataMask,
nsCSSPseudoClasses::lang == pseudo)) { // There are no other function pseudos nsCSSPseudoClasses::lang == pseudo)) { // There are no other function pseudos
REPORT_UNEXPECTED_TOKEN(PEPseudoSelNonFunc); REPORT_UNEXPECTED_TOKEN(PEPseudoSelNonFunc);
UngetToken(); UngetToken();
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
// If it starts with "::", it better be a pseudo-element // If it starts with "::", it better be a pseudo-element
@ -2307,36 +2300,35 @@ void CSSParserImpl::ParsePseudoSelector(PRInt32& aDataMask,
!isAnonBox) { !isAnonBox) {
REPORT_UNEXPECTED_TOKEN(PEPseudoSelNotPE); REPORT_UNEXPECTED_TOKEN(PEPseudoSelNotPE);
UngetToken(); UngetToken();
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
if (nsCSSPseudoClasses::notPseudo == pseudo) { if (nsCSSPseudoClasses::notPseudo == pseudo) {
if (aIsNegated) { // :not() can't be itself negated if (aIsNegated) { // :not() can't be itself negated
REPORT_UNEXPECTED_TOKEN(PEPseudoSelDoubleNot); REPORT_UNEXPECTED_TOKEN(PEPseudoSelDoubleNot);
UngetToken(); UngetToken();
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
// CSS 3 Negation pseudo-class takes one simple selector as argument // CSS 3 Negation pseudo-class takes one simple selector as argument
ParseNegatedSimpleSelector(aDataMask, aSelector, aParsingStatus, aErrorCode); nsSelectorParsingStatus parsingStatus =
if (SELECTOR_PARSING_ENDED_OK != aParsingStatus) { ParseNegatedSimpleSelector(aDataMask, aSelector, aErrorCode);
return; if (eSelectorParsingStatus_Continue != parsingStatus) {
return parsingStatus;
} }
} }
else if (!parsingPseudoElement && else if (!parsingPseudoElement &&
nsCSSPseudoClasses::IsPseudoClass(pseudo)) { nsCSSPseudoClasses::IsPseudoClass(pseudo)) {
aDataMask |= SEL_MASK_PCLASS; aDataMask |= SEL_MASK_PCLASS;
if (nsCSSPseudoClasses::lang == pseudo) { if (nsCSSPseudoClasses::lang == pseudo) {
ParseLangSelector(aSelector, aParsingStatus, aErrorCode); nsSelectorParsingStatus parsingStatus = ParseLangSelector(aSelector, aErrorCode);
if (eSelectorParsingStatus_Continue != parsingStatus) {
return parsingStatus;
}
} }
// XXX are there more pseudo classes which accept arguments ? // XXX are there more pseudo classes which accept arguments ?
else { else {
aSelector.AddPseudoClass(pseudo); aSelector.AddPseudoClass(pseudo);
} }
if (SELECTOR_PARSING_ENDED_OK != aParsingStatus) {
return;
}
} }
else if (isPseudoElement || isAnonBox) { else if (isPseudoElement || isAnonBox) {
// Pseudo-element. Make some more sanity checks. // Pseudo-element. Make some more sanity checks.
@ -2344,8 +2336,7 @@ void CSSParserImpl::ParsePseudoSelector(PRInt32& aDataMask,
if (aIsNegated) { // pseudo-elements can't be negated if (aIsNegated) { // pseudo-elements can't be negated
REPORT_UNEXPECTED_TOKEN(PEPseudoSelPEInNot); REPORT_UNEXPECTED_TOKEN(PEPseudoSelPEInNot);
UngetToken(); UngetToken();
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
// CSS2 pseudo-elements and -moz-tree-* pseudo-elements are allowed // CSS2 pseudo-elements and -moz-tree-* pseudo-elements are allowed
// to have a single ':' on them. Others (CSS3+ pseudo-elements and // to have a single ':' on them. Others (CSS3+ pseudo-elements and
@ -2359,8 +2350,7 @@ void CSSParserImpl::ParsePseudoSelector(PRInt32& aDataMask,
) { ) {
REPORT_UNEXPECTED_TOKEN(PEPseudoSelNewStyleOnly); REPORT_UNEXPECTED_TOKEN(PEPseudoSelNewStyleOnly);
UngetToken(); UngetToken();
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
if (0 == (aDataMask & SEL_MASK_PELEM)) { if (0 == (aDataMask & SEL_MASK_PELEM)) {
@ -2374,8 +2364,7 @@ void CSSParserImpl::ParsePseudoSelector(PRInt32& aDataMask,
// item in the list to the pseudoclass list. They will be pulled // item in the list to the pseudoclass list. They will be pulled
// from the list later along with the pseudo-element. // from the list later along with the pseudo-element.
if (!ParseTreePseudoElement(aErrorCode, aSelector)) { if (!ParseTreePseudoElement(aErrorCode, aSelector)) {
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
} }
#endif #endif
@ -2385,194 +2374,178 @@ void CSSParserImpl::ParsePseudoSelector(PRInt32& aDataMask,
if ((eCSSToken_WhiteSpace == mToken.mType) || if ((eCSSToken_WhiteSpace == mToken.mType) ||
(mToken.IsSymbol('{') || mToken.IsSymbol(','))) { (mToken.IsSymbol('{') || mToken.IsSymbol(','))) {
UngetToken(); UngetToken();
aParsingStatus = SELECTOR_PARSING_STOPPED_OK; return eSelectorParsingStatus_Done;
return;
} }
REPORT_UNEXPECTED_TOKEN(PEPseudoSelTrailing); REPORT_UNEXPECTED_TOKEN(PEPseudoSelTrailing);
UngetToken(); UngetToken();
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
} }
else { // multiple pseudo elements, not legal else { // multiple pseudo elements, not legal
REPORT_UNEXPECTED_TOKEN(PEPseudoSelMultiplePE); REPORT_UNEXPECTED_TOKEN(PEPseudoSelMultiplePE);
UngetToken(); UngetToken();
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
} else { } else {
// Not a pseudo-class, not a pseudo-element.... forget it // Not a pseudo-class, not a pseudo-element.... forget it
REPORT_UNEXPECTED_TOKEN(PEPseudoSelUnknown); REPORT_UNEXPECTED_TOKEN(PEPseudoSelUnknown);
UngetToken(); UngetToken();
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
return;
} }
aParsingStatus = SELECTOR_PARSING_ENDED_OK; return eSelectorParsingStatus_Continue;
} }
// //
// Parse the argument of a negation pseudo-class :not() // Parse the argument of a negation pseudo-class :not()
// //
void CSSParserImpl::ParseNegatedSimpleSelector(PRInt32& aDataMask, CSSParserImpl::nsSelectorParsingStatus
nsCSSSelector& aSelector, CSSParserImpl::ParseNegatedSimpleSelector(PRInt32& aDataMask,
PRInt32& aParsingStatus, nsCSSSelector& aSelector,
nsresult& aErrorCode) nsresult& aErrorCode)
{ {
// Check if we have the first parenthesis // Check if we have the first parenthesis
if (ExpectSymbol(aErrorCode, '(', PR_FALSE)) { if (!ExpectSymbol(aErrorCode, '(', PR_FALSE)) {
REPORT_UNEXPECTED_TOKEN(PENegationBadArg);
if (! GetToken(aErrorCode, PR_FALSE)) { // premature eof return eSelectorParsingStatus_Error;
REPORT_UNEXPECTED_EOF(PENegationEOF); }
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR;
return; if (! GetToken(aErrorCode, PR_FALSE)) { // premature eof
} REPORT_UNEXPECTED_EOF(PENegationEOF);
aParsingStatus = SELECTOR_PARSING_ENDED_OK; return eSelectorParsingStatus_Error;
}
if (!aSelector.mNegations) {
aSelector.mNegations = new nsCSSSelector();
if (!aSelector.mNegations) { if (!aSelector.mNegations) {
aSelector.mNegations = new nsCSSSelector(); aErrorCode = NS_ERROR_OUT_OF_MEMORY;
if (!aSelector.mNegations) { return eSelectorParsingStatus_Error;
aErrorCode = NS_ERROR_OUT_OF_MEMORY;
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR;
return;
}
}
// ID, class and attribute selectors and pseudo-classes are stored in
// the first mNegations attached to a selector
if (eCSSToken_ID == mToken.mType) { // #id
ParseIDSelector(aDataMask, *aSelector.mNegations, aParsingStatus, aErrorCode);
}
else if (mToken.IsSymbol('.')) { // .class
ParseClassSelector(aDataMask, *aSelector.mNegations, aParsingStatus, aErrorCode);
}
else if (mToken.IsSymbol(':')) { // :pseudo
ParsePseudoSelector(aDataMask, *aSelector.mNegations, aParsingStatus, aErrorCode, PR_TRUE);
}
else if (mToken.IsSymbol('[')) { // attribute
ParseAttributeSelector(aDataMask, *aSelector.mNegations, aParsingStatus, aErrorCode);
}
else {
// then it should be a type element or universal selector
nsCSSSelector *newSel = new nsCSSSelector();
if (!newSel) {
aErrorCode = NS_ERROR_OUT_OF_MEMORY;
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR;
return;
}
nsCSSSelector* negations = aSelector.mNegations;
while (nsnull != negations->mNegations) {
negations = negations->mNegations;
}
// negated type element selectors and universal selectors are stored after the first
// mNegations containing only negated IDs, classes, attributes and pseudo-classes
negations->mNegations = newSel;
ParseTypeOrUniversalSelector(aDataMask, *newSel, aParsingStatus, aErrorCode, PR_TRUE);
}
if (SELECTOR_PARSING_STOPPED_ERROR == aParsingStatus) {
REPORT_UNEXPECTED_TOKEN(PENegationBadInner);
return;
}
// close the parenthesis
if (!ExpectSymbol(aErrorCode, ')', PR_TRUE)) {
REPORT_UNEXPECTED_TOKEN(PENegationNoClose);
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR;
} }
} }
// ID, class and attribute selectors and pseudo-classes are stored in
// the first mNegations attached to a selector
nsSelectorParsingStatus parsingStatus;
if (eCSSToken_ID == mToken.mType) { // #id
parsingStatus = ParseIDSelector(aDataMask, *aSelector.mNegations, aErrorCode);
}
else if (mToken.IsSymbol('.')) { // .class
parsingStatus = ParseClassSelector(aDataMask, *aSelector.mNegations, aErrorCode);
}
else if (mToken.IsSymbol(':')) { // :pseudo
parsingStatus = ParsePseudoSelector(aDataMask, *aSelector.mNegations, aErrorCode, PR_TRUE);
}
else if (mToken.IsSymbol('[')) { // [attribute
parsingStatus = ParseAttributeSelector(aDataMask, *aSelector.mNegations, aErrorCode);
}
else { else {
REPORT_UNEXPECTED_TOKEN(PENegationBadArg); // then it should be a type element or universal selector
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; nsCSSSelector *newSel = new nsCSSSelector();
if (!newSel) {
aErrorCode = NS_ERROR_OUT_OF_MEMORY;
return eSelectorParsingStatus_Error;
}
nsCSSSelector* negations = aSelector.mNegations;
while (nsnull != negations->mNegations) {
negations = negations->mNegations;
}
// negated type element selectors and universal selectors are stored after the first
// mNegations containing only negated IDs, classes, attributes and pseudo-classes
negations->mNegations = newSel;
parsingStatus = ParseTypeOrUniversalSelector(aDataMask, *newSel, aErrorCode, PR_TRUE);
} }
if (eSelectorParsingStatus_Error == parsingStatus) {
REPORT_UNEXPECTED_TOKEN(PENegationBadInner);
return parsingStatus;
}
// close the parenthesis
if (!ExpectSymbol(aErrorCode, ')', PR_TRUE)) {
REPORT_UNEXPECTED_TOKEN(PENegationNoClose);
return eSelectorParsingStatus_Error;
}
return eSelectorParsingStatus_Continue;
} }
// //
// Parse the argument of a pseudo-class :lang() // Parse the argument of a pseudo-class :lang()
// //
void CSSParserImpl::ParseLangSelector(nsCSSSelector& aSelector, CSSParserImpl::nsSelectorParsingStatus
PRInt32& aParsingStatus, CSSParserImpl::ParseLangSelector(nsCSSSelector& aSelector, nsresult& aErrorCode)
nsresult& aErrorCode)
{ {
// Check if we have the first parenthesis // Check if we have the first parenthesis
if (ExpectSymbol(aErrorCode, '(', PR_FALSE)) { if (!ExpectSymbol(aErrorCode, '(', PR_FALSE)) {
if (! GetToken(aErrorCode, PR_TRUE)) { // premature eof
REPORT_UNEXPECTED_EOF(PELangArgEOF);
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR;
return;
}
// We expect an identifier with a language abbreviation
if (eCSSToken_Ident != mToken.mType) {
REPORT_UNEXPECTED_TOKEN(PELangArgNotIdent);
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR;
return;
}
// Add the pseudo with the language parameter
aSelector.AddPseudoClass(nsCSSPseudoClasses::lang, mToken.mIdent.get());
// close the parenthesis
if (!ExpectSymbol(aErrorCode, ')', PR_TRUE)) {
REPORT_UNEXPECTED_TOKEN(PELangNoClose);
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR;
}
}
else {
REPORT_UNEXPECTED_TOKEN(PELangNoArg); REPORT_UNEXPECTED_TOKEN(PELangNoArg);
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR; return eSelectorParsingStatus_Error;
} }
if (! GetToken(aErrorCode, PR_TRUE)) { // premature eof
REPORT_UNEXPECTED_EOF(PELangArgEOF);
return eSelectorParsingStatus_Error;
}
// We expect an identifier with a language abbreviation
if (eCSSToken_Ident != mToken.mType) {
REPORT_UNEXPECTED_TOKEN(PELangArgNotIdent);
UngetToken();
return eSelectorParsingStatus_Error;
}
// Add the pseudo with the language parameter
aSelector.AddPseudoClass(nsCSSPseudoClasses::lang, mToken.mIdent.get());
// close the parenthesis
if (!ExpectSymbol(aErrorCode, ')', PR_TRUE)) {
REPORT_UNEXPECTED_TOKEN(PELangNoClose);
return eSelectorParsingStatus_Error;
}
return eSelectorParsingStatus_Continue;
} }
/** /**
* This is the format for selectors: * This is the format for selectors:
* operator? [[namespace |]? element_name]? [ ID | class | attrib | pseudo ]* * operator? [[namespace |]? element_name]? [ ID | class | attrib | pseudo ]*
*/ */
PRBool CSSParserImpl::ParseSelector(nsresult& aErrorCode, CSSParserImpl::nsSelectorParsingStatus
nsCSSSelector& aSelector) CSSParserImpl::ParseSelector(nsresult& aErrorCode, nsCSSSelector& aSelector)
{ {
PRInt32 dataMask = 0;
PRInt32 parsingStatus = SELECTOR_PARSING_ENDED_OK;
if (! GetToken(aErrorCode, PR_TRUE)) { if (! GetToken(aErrorCode, PR_TRUE)) {
REPORT_UNEXPECTED_EOF(PESelectorEOF); REPORT_UNEXPECTED_EOF(PESelectorEOF);
return PR_FALSE; return eSelectorParsingStatus_Error;
} }
ParseTypeOrUniversalSelector(dataMask, aSelector, parsingStatus, aErrorCode, PR_FALSE); PRInt32 dataMask = 0;
if (SELECTOR_PARSING_STOPPED_OK == parsingStatus) { nsSelectorParsingStatus parsingStatus =
return PR_TRUE; ParseTypeOrUniversalSelector(dataMask, aSelector, aErrorCode, PR_FALSE);
} if (parsingStatus != eSelectorParsingStatus_Continue) {
else if (SELECTOR_PARSING_STOPPED_ERROR == parsingStatus) { return parsingStatus;
return PR_FALSE;
} }
for (;;) { for (;;) {
parsingStatus = SELECTOR_PARSING_ENDED_OK; if (eCSSToken_ID == mToken.mType) { // #id
if (eCSSToken_ID == mToken.mType) { // #id parsingStatus = ParseIDSelector(dataMask, aSelector, aErrorCode);
ParseIDSelector(dataMask, aSelector, parsingStatus, aErrorCode);
} }
else if (mToken.IsSymbol('.')) { // .class else if (mToken.IsSymbol('.')) { // .class
ParseClassSelector(dataMask, aSelector, parsingStatus, aErrorCode); parsingStatus = ParseClassSelector(dataMask, aSelector, aErrorCode);
} }
else if (mToken.IsSymbol(':')) { // :pseudo else if (mToken.IsSymbol(':')) { // :pseudo
ParsePseudoSelector(dataMask, aSelector, parsingStatus, aErrorCode, PR_FALSE); parsingStatus = ParsePseudoSelector(dataMask, aSelector, aErrorCode, PR_FALSE);
} }
else if (mToken.IsSymbol('[')) { // attribute else if (mToken.IsSymbol('[')) { // [attribute
ParseAttributeSelector(dataMask, aSelector, parsingStatus, aErrorCode); parsingStatus = ParseAttributeSelector(dataMask, aSelector, aErrorCode);
} }
else { // not a selector token, we're done else { // not a selector token, we're done
parsingStatus = eSelectorParsingStatus_Done;
break; break;
} }
if (SELECTOR_PARSING_STOPPED_OK == parsingStatus) { if (parsingStatus != eSelectorParsingStatus_Continue) {
return PR_TRUE; return parsingStatus;
} }
else if (SELECTOR_PARSING_STOPPED_ERROR == parsingStatus) {
return PR_FALSE;
}
if (! GetToken(aErrorCode, PR_FALSE)) { // premature eof is ok (here!) if (! GetToken(aErrorCode, PR_FALSE)) { // premature eof is ok (here!)
return PR_TRUE; return eSelectorParsingStatus_Done;
} }
} }
UngetToken(); UngetToken();
return PRBool(0 != dataMask); return dataMask ? parsingStatus : eSelectorParsingStatus_Empty;
} }
nsCSSDeclaration* nsCSSDeclaration*