Bug 525608 part 2. Change the CSS parser to not allow anon box selectors with more than the anon box name in them. Store the pseudo type in pseudo-element selectors. Enforce that all non-anon-box pseudo selectors have an mNext that selects the element they apply to. r=dbaron

This commit is contained in:
Boris Zbarsky 2009-12-11 02:37:40 -05:00
parent c1d4ecaf51
commit 03a58e11a7
9 changed files with 68 additions and 31 deletions

View File

@ -137,3 +137,4 @@ PEMQNoMinMaxWithoutValue=Media features with min- or max- must have a value.
PEMQExpectedFeatureValue=Found invalid value for media feature.
PEBadFontBlockStart=Expected '{' to begin @font-face rule but found '%1$S'.
PEBadFontBlockEnd=Expected '}' to end @font-face rule but found '%1$S'.
PEAnonBoxNotAlone=Did not expect anonymous box.

View File

@ -65,9 +65,6 @@ math[mode="display"], math[display="block"] {
math[display="inline"] {
display: inline;
}
::-moz-math-inline {
display: inline;
}
/**************************************************************************/
/* Style switching during frame construction depending on the context of <mi>:

View File

@ -165,8 +165,8 @@ nsMathMLFrame::ResolveMathMLCharStyle(nsPresContext* aPresContext,
PRBool aIsMutableChar)
{
nsIAtom* pseudoStyle = (aIsMutableChar) ?
nsCSSAnonBoxes::mozMathStretchy :
nsCSSAnonBoxes::mozMathAnonymous; // savings
nsCSSPseudoElements::mozMathStretchy :
nsCSSPseudoElements::mozMathAnonymous; // savings
nsRefPtr<nsStyleContext> newStyleContext;
newStyleContext = aPresContext->StyleSet()->
ResolvePseudoStyleFor(aContent, pseudoStyle, aParentStyleContext);

View File

@ -259,10 +259,6 @@ select:empty {
-moz-box-sizing: border-box ! important;
}
select::-moz-scrolled-content {
display: block !important;
}
option {
display: block;
float: none !important;

View File

@ -109,12 +109,6 @@ CSS_ANON_BOX(moztreeprogressmeter, ":-moz-tree-progressmeter")
CSS_ANON_BOX(moztreedropfeedback, ":-moz-tree-drop-feedback")
#endif
#ifdef MOZ_MATHML
CSS_ANON_BOX(mozMathStretchy, ":-moz-math-stretchy")
CSS_ANON_BOX(mozMathAnonymous, ":-moz-math-anonymous")
CSS_ANON_BOX(mozMathInline, ":-moz-math-inline")
#endif
#ifdef MOZ_SVG
CSS_ANON_BOX(mozSVGForeignContent, ":-moz-svg-foreign-content")
#endif

View File

@ -354,7 +354,8 @@ protected:
nsCSSSelector& aSelector,
PRBool aIsNegated,
nsIAtom** aPseudoElement,
nsPseudoClassList** aPseudoElementArgs);
nsPseudoClassList** aPseudoElementArgs,
nsCSSPseudoElements::Type* aPseudoElementType);
nsSelectorParsingStatus ParseAttributeSelector(PRInt32& aDataMask,
nsCSSSelector& aSelector);
@ -374,7 +375,8 @@ protected:
nsSelectorParsingStatus ParseSelector(nsCSSSelector& aSelectorResult,
nsIAtom** aPseudoElement,
nsPseudoClassList** aPseudoElementArgs);
nsPseudoClassList** aPseudoElementArgs,
nsCSSPseudoElements::Type* aPseudoElementType);
// If aTerminateAtBrace is true, the selector list is done when we
// hit a '{'. Otherwise, it's done when we hit EOF.
@ -2497,9 +2499,11 @@ CSSParserImpl::ParseSelectorGroup(nsCSSSelectorList*& aList)
}
nsCOMPtr<nsIAtom> pseudoElement;
nsAutoPtr<nsPseudoClassList> pseudoElementArgs;
nsCSSPseudoElements::Type pseudoElementType;
nsSelectorParsingStatus parsingStatus =
ParseSelector(*newSelector, getter_AddRefs(pseudoElement),
getter_Transfers(pseudoElementArgs));
getter_Transfers(pseudoElementArgs),
&pseudoElementType);
if (parsingStatus == eSelectorParsingStatus_Empty) {
if (!list) {
REPORT_UNEXPECTED(PESelectorGroupNoSelector);
@ -2510,6 +2514,13 @@ CSSParserImpl::ParseSelectorGroup(nsCSSSelectorList*& aList)
list = nsnull;
break;
}
if (pseudoElement &&
pseudoElementType == nsCSSPseudoElements::ePseudo_AnonBox &&
(list || !IsUniversalSelector(*newSelector))) {
REPORT_UNEXPECTED(PEAnonBoxNotAlone);
list = nsnull;
break;
}
if (nsnull == list) {
list = new nsCSSSelectorList();
if (nsnull == list) {
@ -2517,16 +2528,16 @@ CSSParserImpl::ParseSelectorGroup(nsCSSSelectorList*& aList)
return PR_FALSE;
}
}
list->AddSelector(newSelector);
nsCSSSelector* listSel = list->mSelectors;
// We got a pseudo-element (or anonymous box). We actually
// represent pseudo-elements as a child of the rest of the selector.
if (pseudoElement) {
if (listSel->mNext || !IsUniversalSelector(*listSel)) {
if (pseudoElementType != nsCSSPseudoElements::ePseudo_AnonBox) {
// We need to put the pseudo-element on a new selector that's a
// child of the current one. (If it's the only thing in the
// entire selector group, we can just put it on this one.)
// child of the current one.
listSel->mOperator = PRUnichar('>');
nsAutoPtr<nsCSSSelector> empty(new nsCSSSelector());
if (!empty) {
@ -2544,6 +2555,7 @@ CSSParserImpl::ParseSelectorGroup(nsCSSSelectorList*& aList)
"already initialized");
listSel->mLowercaseTag.swap(pseudoElement);
listSel->mPseudoClassList = pseudoElementArgs.forget();
listSel->SetPseudoType(pseudoElementType);
havePseudoElement = PR_TRUE;
}
@ -2991,7 +3003,8 @@ CSSParserImpl::ParsePseudoSelector(PRInt32& aDataMask,
nsCSSSelector& aSelector,
PRBool aIsNegated,
nsIAtom** aPseudoElement,
nsPseudoClassList** aPseudoElementArgs)
nsPseudoClassList** aPseudoElementArgs,
nsCSSPseudoElements::Type* aPseudoElementType)
{
NS_ASSERTION(aIsNegated || (aPseudoElement && aPseudoElementArgs),
"expected location to store pseudo element");
@ -3035,8 +3048,10 @@ CSSParserImpl::ParsePseudoSelector(PRInt32& aDataMask,
// stash away some info about this pseudo so we only have to get it once.
PRBool isTreePseudo = PR_FALSE;
nsCSSPseudoElements::Type pseudoElementType =
nsCSSPseudoElements::GetPseudoType(pseudo);
#ifdef MOZ_XUL
isTreePseudo = nsCSSAnonBoxes::IsTreePseudoElement(pseudo);
isTreePseudo = (pseudoElementType == nsCSSPseudoElements::ePseudo_XULTree);
// If a tree pseudo-element is using the function syntax, it will
// get isTree set here and will pass the check below that only
// allows functions if they are in our list of things allowed to be
@ -3046,13 +3061,21 @@ CSSParserImpl::ParsePseudoSelector(PRInt32& aDataMask,
// desired.
PRBool isTree = (eCSSToken_Function == mToken.mType) && isTreePseudo;
#endif
PRBool isPseudoElement = nsCSSPseudoElements::IsPseudoElement(pseudo);
PRBool isPseudoElement =
(pseudoElementType < nsCSSPseudoElements::ePseudo_PseudoElementCount);
// anonymous boxes are only allowed if they're the tree boxes or we have
// enabled unsafe rules
PRBool isAnonBox = nsCSSAnonBoxes::IsAnonBox(pseudo) &&
(mUnsafeRulesEnabled || isTreePseudo);
PRBool isAnonBox = isTreePseudo ||
(pseudoElementType == nsCSSPseudoElements::ePseudo_AnonBox &&
mUnsafeRulesEnabled);
PRBool isPseudoClass = nsCSSPseudoClasses::IsPseudoClass(pseudo);
NS_ASSERTION(!isPseudoClass ||
pseudoElementType == nsCSSPseudoElements::ePseudo_NotPseudoElement,
"Why is this atom both a pseudo-class and a pseudo-element?");
NS_ASSERTION(isPseudoClass + isPseudoElement + isAnonBox <= 1,
"Shouldn't be more than one of these");
if (!isPseudoClass && !isPseudoElement && !isAnonBox) {
// Not a pseudo-class, not a pseudo-element.... forget it
REPORT_UNEXPECTED_TOKEN(PEPseudoSelUnknown);
@ -3144,6 +3167,7 @@ CSSParserImpl::ParsePseudoSelector(PRInt32& aDataMask,
if (0 == (aDataMask & SEL_MASK_PELEM)) {
aDataMask |= SEL_MASK_PELEM;
NS_ADDREF(*aPseudoElement = pseudo);
*aPseudoElementType = pseudoElementType;
#ifdef MOZ_XUL
if (isTree) {
@ -3235,7 +3259,7 @@ CSSParserImpl::ParseNegatedSimpleSelector(PRInt32& aDataMask,
}
else if (mToken.IsSymbol(':')) { // :pseudo
parsingStatus = ParsePseudoSelector(aDataMask, *newSel, PR_TRUE,
nsnull, nsnull);
nsnull, nsnull, nsnull);
}
else if (mToken.IsSymbol('[')) { // [attribute
parsingStatus = ParseAttributeSelector(aDataMask, *newSel);
@ -3445,7 +3469,8 @@ CSSParserImpl::ParsePseudoClassWithNthPairArg(nsCSSSelector& aSelector,
CSSParserImpl::nsSelectorParsingStatus
CSSParserImpl::ParseSelector(nsCSSSelector& aSelector,
nsIAtom** aPseudoElement,
nsPseudoClassList** aPseudoElementArgs)
nsPseudoClassList** aPseudoElementArgs,
nsCSSPseudoElements::Type* aPseudoElementType)
{
if (! GetToken(PR_TRUE)) {
REPORT_UNEXPECTED_EOF(PESelectorEOF);
@ -3468,7 +3493,8 @@ CSSParserImpl::ParseSelector(nsCSSSelector& aSelector,
}
else if (mToken.IsSymbol(':')) { // :pseudo
parsingStatus = ParsePseudoSelector(dataMask, aSelector, PR_FALSE,
aPseudoElement, aPseudoElementArgs);
aPseudoElement, aPseudoElementArgs,
aPseudoElementType);
}
else if (mToken.IsSymbol('[')) { // [attribute
parsingStatus = ParseAttributeSelector(dataMask, aSelector);

View File

@ -81,3 +81,8 @@ CSS_PSEUDO_ELEMENT(mozFocusOuter, ":-moz-focus-outer", 0)
CSS_PSEUDO_ELEMENT(mozListBullet, ":-moz-list-bullet", 0)
CSS_PSEUDO_ELEMENT(mozListNumber, ":-moz-list-number", 0)
#ifdef MOZ_MATHML
CSS_PSEUDO_ELEMENT(mozMathStretchy, ":-moz-math-stretchy", 0)
CSS_PSEUDO_ELEMENT(mozMathAnonymous, ":-moz-math-anonymous", 0)
#endif

View File

@ -82,6 +82,8 @@
#include "nsContentErrors.h"
#include "mozAutoDocUpdate.h"
#include "prlog.h"
#define NS_IF_CLONE(member_) \
PR_BEGIN_MACRO \
if (member_) { \
@ -280,9 +282,12 @@ nsCSSSelector::nsCSSSelector(void)
mNegations(nsnull),
mNext(nsnull),
mNameSpace(kNameSpaceID_Unknown),
mOperator(0)
mOperator(0),
mPseudoType(nsCSSPseudoElements::ePseudo_NotPseudoElement)
{
MOZ_COUNT_CTOR(nsCSSSelector);
// Make sure mPseudoType can hold all nsCSSPseudoElements::Type values
PR_STATIC_ASSERT(nsCSSPseudoElements::ePseudo_MAX < PR_INT16_MAX);
}
nsCSSSelector*
@ -296,6 +301,7 @@ nsCSSSelector::Clone(PRBool aDeepNext, PRBool aDeepNegations) const
result->mLowercaseTag = mLowercaseTag;
result->mCasedTag = mCasedTag;
result->mOperator = mOperator;
result->mPseudoType = mPseudoType;
NS_IF_CLONE(mIDList);
NS_IF_CLONE(mClassList);

View File

@ -52,6 +52,7 @@
#include "nsCSSProps.h"
#include "nsCSSValue.h"
#include "nsIAtom.h"
#include "nsCSSPseudoElements.h"
class nsIAtom;
class nsCSSDeclaration;
@ -199,6 +200,15 @@ private:
PRInt32 CalcWeightWithoutNegations() const;
public:
// Get and set the selector's pseudo type
nsCSSPseudoElements::Type PseudoType() const {
return static_cast<nsCSSPseudoElements::Type>(mPseudoType);
}
void SetPseudoType(nsCSSPseudoElements::Type aType) {
NS_ASSERTION(aType > PR_INT16_MIN && aType < PR_INT16_MAX, "Out of bounds");
mPseudoType = static_cast<PRInt16>(aType);
}
// For case-sensitive documents, mLowercaseTag is the same as mCasedTag,
// but in case-insensitive documents (HTML) mLowercaseTag is lowercase.
// Also, for pseudo-elements mCasedTag will be null but mLowercaseTag
@ -214,7 +224,9 @@ public:
nsCSSSelector* mNext;
PRInt32 mNameSpace;
PRUnichar mOperator;
private:
private:
// PRInt16 to make sure it packs well with mOperator
PRInt16 mPseudoType;
// These are not supported and are not implemented!
nsCSSSelector(const nsCSSSelector& aCopy);
nsCSSSelector& operator=(const nsCSSSelector& aCopy);