зеркало из https://github.com/mozilla/gecko-dev.git
adds support for :not() css3 pseudo-class; b=71647, r=pierre, sr=hyatt
This commit is contained in:
Родитель
f14a83706d
Коммит
4fc3eb0ce3
|
@ -197,12 +197,16 @@ protected:
|
|||
void ParseClassSelector(PRInt32& aDataMask, nsCSSSelector& aSelector,
|
||||
PRInt32& aParsingStatus, PRInt32& aErrorCode);
|
||||
void ParsePseudoSelector(PRInt32& aDataMask, nsCSSSelector& aSelector,
|
||||
PRInt32& aParsingStatus, PRInt32& aErrorCode);
|
||||
PRInt32& aParsingStatus, PRInt32& aErrorCode,
|
||||
PRBool aIsNegated);
|
||||
void ParseAttributeSelector(PRInt32& aDataMask, nsCSSSelector& aSelector,
|
||||
PRInt32& aParsingStatus, PRInt32& aErrorCode);
|
||||
|
||||
void ParseTypeOrUniversalSelector(PRInt32& aDataMask,
|
||||
nsCSSSelector& aSelector,
|
||||
PRInt32& aParsingStatus, PRInt32& aErrorCode,
|
||||
PRBool aIsNegated);
|
||||
void ParseNegatedSimpleSelector(PRInt32& aDataMask, nsCSSSelector& aSelector,
|
||||
PRInt32& aParsingStatus, PRInt32& aErrorCode);
|
||||
|
||||
PRBool ParseSelectorList(PRInt32& aErrorCode, SelectorList*& aListHead);
|
||||
|
@ -1366,11 +1370,12 @@ static PRBool IsPseudoClass(const nsIAtom* aAtom)
|
|||
(nsCSSAtoms::enabledPseudo == aAtom) ||
|
||||
(nsCSSAtoms::firstChildPseudo == aAtom) ||
|
||||
(nsCSSAtoms::firstNodePseudo == aAtom) ||
|
||||
(nsCSSAtoms::lastNodePseudo == aAtom) ||
|
||||
(nsCSSAtoms::focusPseudo == aAtom) ||
|
||||
(nsCSSAtoms::hoverPseudo == aAtom) ||
|
||||
(nsCSSAtoms::langPseudo == aAtom) ||
|
||||
(nsCSSAtoms::lastNodePseudo == aAtom) ||
|
||||
(nsCSSAtoms::linkPseudo == aAtom) ||
|
||||
(nsCSSAtoms::outOfDatePseudo == aAtom) ||
|
||||
(nsCSSAtoms::rootPseudo == aAtom) ||
|
||||
(nsCSSAtoms::xblBoundElementPseudo == aAtom) ||
|
||||
(nsCSSAtoms::outOfDatePseudo == aAtom) ||
|
||||
|
@ -1520,6 +1525,9 @@ PRBool CSSParserImpl::ParseSelectorGroup(PRInt32& aErrorCode,
|
|||
#define SELECTOR_PARSING_STOPPED_OK 2
|
||||
#define SELECTOR_PARSING_STOPPED_ERROR 3
|
||||
|
||||
//
|
||||
// Parses an ID selector #name
|
||||
//
|
||||
void CSSParserImpl::ParseIDSelector(PRInt32& aDataMask,
|
||||
nsCSSSelector& aSelector,
|
||||
PRInt32& aParsingStatus,
|
||||
|
@ -1539,6 +1547,9 @@ void CSSParserImpl::ParseIDSelector(PRInt32& aDataMask,
|
|||
aParsingStatus = SELECTOR_PARSING_ENDED_OK;
|
||||
}
|
||||
|
||||
//
|
||||
// Parses a class selector .name
|
||||
//
|
||||
void CSSParserImpl::ParseClassSelector(PRInt32& aDataMask,
|
||||
nsCSSSelector& aSelector,
|
||||
PRInt32& aParsingStatus,
|
||||
|
@ -1560,11 +1571,15 @@ void CSSParserImpl::ParseClassSelector(PRInt32& aDataMask,
|
|||
aParsingStatus = SELECTOR_PARSING_ENDED_OK;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Parse a type element selector or a universal selector
|
||||
// namespace|type or namespace|* or *|* or *
|
||||
//
|
||||
void CSSParserImpl::ParseTypeOrUniversalSelector(PRInt32& aDataMask,
|
||||
nsCSSSelector& aSelector,
|
||||
PRInt32& aParsingStatus,
|
||||
PRInt32& aErrorCode)
|
||||
PRInt32& aErrorCode,
|
||||
PRBool aIsNegated)
|
||||
{
|
||||
nsAutoString buffer;
|
||||
if (mToken.IsSymbol('*')) { // universal element selector, or universal namespace
|
||||
|
@ -1729,8 +1744,16 @@ void CSSParserImpl::ParseTypeOrUniversalSelector(PRInt32& aDataMask,
|
|||
}
|
||||
}
|
||||
aParsingStatus = SELECTOR_PARSING_ENDED_OK;
|
||||
if (aIsNegated) {
|
||||
// restore last token read in case of a negated type selector
|
||||
UngetToken();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Parse attribute selectors [attr], [attr=value], [attr|=value],
|
||||
// [attr~=value], [attr^=value], [attr$=value] and [attr*=value]
|
||||
//
|
||||
void CSSParserImpl::ParseAttributeSelector(PRInt32& aDataMask,
|
||||
nsCSSSelector& aSelector,
|
||||
PRInt32& aParsingStatus,
|
||||
|
@ -1913,10 +1936,14 @@ void CSSParserImpl::ParseAttributeSelector(PRInt32& aDataMask,
|
|||
aParsingStatus = SELECTOR_PARSING_ENDED_OK;
|
||||
}
|
||||
|
||||
//
|
||||
// Parse pseudo-classes and pseudo-elements
|
||||
//
|
||||
void CSSParserImpl::ParsePseudoSelector(PRInt32& aDataMask,
|
||||
nsCSSSelector& aSelector,
|
||||
PRInt32& aParsingStatus,
|
||||
PRInt32& aErrorCode)
|
||||
PRInt32& aErrorCode,
|
||||
PRBool aIsNegated)
|
||||
{
|
||||
nsAutoString buffer;
|
||||
if (! GetToken(aErrorCode, PR_FALSE)) { // premature eof
|
||||
|
@ -1924,12 +1951,24 @@ void CSSParserImpl::ParsePseudoSelector(PRInt32& aDataMask,
|
|||
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
buffer.Truncate();
|
||||
buffer.AppendWithConversion(':');
|
||||
buffer.Append(mToken.mIdent);
|
||||
buffer.ToLowerCase();
|
||||
nsIAtom* pseudo = NS_NewAtom(buffer);
|
||||
|
||||
if (eCSSToken_Ident != mToken.mType) { // malformed selector
|
||||
if (eCSSToken_Function != mToken.mType ||
|
||||
!(
|
||||
#ifdef INCLUDE_XUL
|
||||
if (eCSSToken_Function != mToken.mType ||
|
||||
!IsOutlinerPseudoElement(mToken.mIdent)) {
|
||||
// -moz-outliner is a pseudo-element and therefore cannot be negated
|
||||
(!aIsNegated && IsOutlinerPseudoElement(mToken.mIdent)) ||
|
||||
#endif
|
||||
REPORT_UNEXPECTED_TOKEN(NS_LITERAL_STRING("Expected identifier for pseudo-class selector but found"));
|
||||
// the negation pseudo-class is a function
|
||||
(nsCSSAtoms::notPseudo == pseudo))) {
|
||||
REPORT_UNEXPECTED_TOKEN(NS_LITERAL_STRING("Expected identifier for pseudo-class selector not found"));
|
||||
NS_RELEASE(pseudo);
|
||||
UngetToken();
|
||||
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR;
|
||||
return;
|
||||
|
@ -1937,18 +1976,32 @@ void CSSParserImpl::ParsePseudoSelector(PRInt32& aDataMask,
|
|||
}
|
||||
#endif
|
||||
}
|
||||
buffer.Truncate();
|
||||
buffer.AppendWithConversion(':');
|
||||
buffer.Append(mToken.mIdent);
|
||||
buffer.ToLowerCase();
|
||||
nsIAtom* pseudo = NS_NewAtom(buffer);
|
||||
if (IsPseudoClass(pseudo)) {
|
||||
// XXX parse lang pseudo class
|
||||
|
||||
if (nsCSSAtoms::notPseudo == pseudo) {
|
||||
NS_RELEASE(pseudo);
|
||||
if (aIsNegated) { // :not() can't be itself negated
|
||||
REPORT_UNEXPECTED_TOKEN(NS_LITERAL_STRING("Negation pseudo-class can't be negated"));
|
||||
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR;
|
||||
return;
|
||||
}
|
||||
// CSS 3 Negation pseudo-class takes one simple selector as argument
|
||||
ParseNegatedSimpleSelector(aDataMask, aSelector, aParsingStatus, aErrorCode);
|
||||
if (SELECTOR_PARSING_ENDED_OK != aParsingStatus) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (IsPseudoClass(pseudo)) {
|
||||
// XXX parse pseudo classes accepting arguments
|
||||
aDataMask |= SEL_MASK_PCLASS;
|
||||
aSelector.AddPseudoClass(pseudo);
|
||||
NS_RELEASE(pseudo);
|
||||
}
|
||||
else {
|
||||
if (aIsNegated) { // pseudo-elements can't be negated
|
||||
REPORT_UNEXPECTED_TOKEN(NS_LITERAL_STRING("Pseudo-elements can't be negated"));
|
||||
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR;
|
||||
return;
|
||||
}
|
||||
if (0 == (aDataMask & SEL_MASK_PELEM)) {
|
||||
aDataMask |= SEL_MASK_PELEM;
|
||||
aSelector.AddPseudoClass(pseudo); // store it here, it gets pulled later
|
||||
|
@ -1992,6 +2045,76 @@ void CSSParserImpl::ParsePseudoSelector(PRInt32& aDataMask,
|
|||
aParsingStatus = SELECTOR_PARSING_ENDED_OK;
|
||||
}
|
||||
|
||||
//
|
||||
// Parse the argument of a negation pseudo-class :not()
|
||||
//
|
||||
void CSSParserImpl::ParseNegatedSimpleSelector(PRInt32& aDataMask,
|
||||
nsCSSSelector& aSelector,
|
||||
PRInt32& aParsingStatus,
|
||||
PRInt32& aErrorCode)
|
||||
{
|
||||
// Check if we have the first parenthesis
|
||||
if (ExpectSymbol(aErrorCode, '(', PR_FALSE)) {
|
||||
|
||||
if (! GetToken(aErrorCode, PR_FALSE)) { // premature eof
|
||||
REPORT_UNEXPECTED_EOF();
|
||||
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR;
|
||||
return;
|
||||
}
|
||||
aParsingStatus = SELECTOR_PARSING_ENDED_OK;
|
||||
nsCSSSelector* newSel = new nsCSSSelector();
|
||||
if (nsnull == aSelector.mNegations &&
|
||||
((eCSSToken_ID == mToken.mType) ||
|
||||
mToken.IsSymbol('.') ||
|
||||
mToken.IsSymbol(':') ||
|
||||
mToken.IsSymbol('['))) {
|
||||
// ID, class and attribute selectors and pseudo-classes are stored in
|
||||
// the first mNegations attached to a selector
|
||||
aSelector.mNegations = newSel;
|
||||
}
|
||||
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
|
||||
if (nsnull == aSelector.mNegations) {
|
||||
aSelector.mNegations = newSel;
|
||||
}
|
||||
newSel = new nsCSSSelector();
|
||||
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(NS_LITERAL_STRING("Malformed simple selector as negation pseudo-class argument"));
|
||||
return;
|
||||
}
|
||||
// close the parenthesis
|
||||
if (!ExpectSymbol(aErrorCode, ')', PR_TRUE)) {
|
||||
REPORT_UNEXPECTED_TOKEN(NS_LITERAL_STRING("Missing closing ')' in negation pseudo-class"));
|
||||
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR;
|
||||
}
|
||||
}
|
||||
else {
|
||||
REPORT_UNEXPECTED_TOKEN(NS_LITERAL_STRING("Missing argument in negation pseudo-class"));
|
||||
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the format for selectors:
|
||||
* operator? [[namespace |]? element_name]? [ ID | class | attrib | pseudo ]*
|
||||
|
@ -2007,7 +2130,7 @@ PRBool CSSParserImpl::ParseSelector(PRInt32& aErrorCode,
|
|||
return PR_FALSE;
|
||||
}
|
||||
|
||||
ParseTypeOrUniversalSelector(dataMask, aSelector, parsingStatus, aErrorCode);
|
||||
ParseTypeOrUniversalSelector(dataMask, aSelector, parsingStatus, aErrorCode, PR_FALSE);
|
||||
if (SELECTOR_PARSING_STOPPED_OK == parsingStatus) {
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
@ -2024,7 +2147,7 @@ PRBool CSSParserImpl::ParseSelector(PRInt32& aErrorCode,
|
|||
ParseClassSelector(dataMask, aSelector, parsingStatus, aErrorCode);
|
||||
}
|
||||
else if (mToken.IsSymbol(':')) { // :pseudo
|
||||
ParsePseudoSelector(dataMask, aSelector, parsingStatus, aErrorCode);
|
||||
ParsePseudoSelector(dataMask, aSelector, parsingStatus, aErrorCode, PR_FALSE);
|
||||
}
|
||||
else if (mToken.IsSymbol('[')) { // attribute
|
||||
ParseAttributeSelector(dataMask, aSelector, parsingStatus, aErrorCode);
|
||||
|
|
|
@ -90,6 +90,12 @@ static NS_DEFINE_IID(kCSSXULSID, NS_CSS_XUL_SID);
|
|||
#define NS_IF_DELETE(ptr) \
|
||||
if (nsnull != ptr) { delete ptr; ptr = nsnull; }
|
||||
|
||||
#define NS_IF_NEGATED_START(bool,str) \
|
||||
if (bool) { str.Append(NS_LITERAL_STRING(":not(")); }
|
||||
|
||||
#define NS_IF_NEGATED_END(bool,str) \
|
||||
if (bool) { str.Append(PRUnichar(')')); }
|
||||
|
||||
MOZ_DECL_CTOR_COUNTER(nsAtomList)
|
||||
|
||||
nsAtomList::nsAtomList(nsIAtom* aAtom)
|
||||
|
@ -292,6 +298,7 @@ nsCSSSelector::nsCSSSelector(void)
|
|||
mPseudoClassList(nsnull),
|
||||
mAttrList(nsnull),
|
||||
mOperator(0),
|
||||
mNegations(nsnull),
|
||||
mNext(nsnull)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsCSSSelector);
|
||||
|
@ -309,6 +316,7 @@ nsCSSSelector::nsCSSSelector(const nsCSSSelector& aCopy)
|
|||
mPseudoClassList(nsnull),
|
||||
mAttrList(nsnull),
|
||||
mOperator(aCopy.mOperator),
|
||||
mNegations(nsnull),
|
||||
mNext(nsnull)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsCSSSelector);
|
||||
|
@ -317,7 +325,8 @@ nsCSSSelector::nsCSSSelector(const nsCSSSelector& aCopy)
|
|||
NS_IF_COPY(mClassList, aCopy.mClassList, nsAtomList);
|
||||
NS_IF_COPY(mPseudoClassList, aCopy.mPseudoClassList, nsAtomList);
|
||||
NS_IF_COPY(mAttrList, aCopy.mAttrList, nsAttrSelector);
|
||||
|
||||
NS_IF_COPY(mNegations, aCopy.mNegations, nsCSSSelector);
|
||||
|
||||
#ifdef DEBUG_REFS
|
||||
gSelectorCount++;
|
||||
printf( "nsCSSSelector Instances (cp-ctor): %ld\n", (long)gSelectorCount);
|
||||
|
@ -342,7 +351,8 @@ nsCSSSelector& nsCSSSelector::operator=(const nsCSSSelector& aCopy)
|
|||
NS_IF_DELETE(mClassList);
|
||||
NS_IF_DELETE(mPseudoClassList);
|
||||
NS_IF_DELETE(mAttrList);
|
||||
|
||||
NS_IF_DELETE(mNegations);
|
||||
|
||||
mNameSpace = aCopy.mNameSpace;
|
||||
mTag = aCopy.mTag;
|
||||
NS_IF_COPY(mIDList, aCopy.mIDList, nsAtomList);
|
||||
|
@ -350,6 +360,7 @@ nsCSSSelector& nsCSSSelector::operator=(const nsCSSSelector& aCopy)
|
|||
NS_IF_COPY(mPseudoClassList, aCopy.mPseudoClassList, nsAtomList);
|
||||
NS_IF_COPY(mAttrList, aCopy.mAttrList, nsAttrSelector);
|
||||
mOperator = aCopy.mOperator;
|
||||
NS_IF_COPY(mNegations, aCopy.mNegations, nsCSSSelector);
|
||||
|
||||
NS_IF_ADDREF(mTag);
|
||||
return *this;
|
||||
|
@ -404,6 +415,11 @@ PRBool nsCSSSelector::Equals(const nsCSSSelector* aOther) const
|
|||
return PR_FALSE;
|
||||
}
|
||||
}
|
||||
if (nsnull != mNegations) {
|
||||
if (PR_FALSE == mNegations->Equals(aOther->mNegations)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
@ -419,6 +435,7 @@ void nsCSSSelector::Reset(void)
|
|||
NS_IF_DELETE(mClassList);
|
||||
NS_IF_DELETE(mPseudoClassList);
|
||||
NS_IF_DELETE(mAttrList);
|
||||
NS_IF_DELETE(mNegations);
|
||||
mOperator = PRUnichar(0);
|
||||
}
|
||||
|
||||
|
@ -534,6 +551,9 @@ PRInt32 nsCSSSelector::CalcWeight(void) const
|
|||
weight += 0x000100;
|
||||
attr = attr->mNext;
|
||||
}
|
||||
if (nsnull != mNegations) {
|
||||
weight += mNegations->CalcWeight();
|
||||
}
|
||||
return weight;
|
||||
}
|
||||
|
||||
|
@ -624,6 +644,13 @@ void nsCSSSelector::SizeOf(nsISizeOfHandler *aSizeOfHandler, PRUint32 &aSize)
|
|||
localSize = 0;
|
||||
mAttrList->SizeOf(aSizeOfHandler, localSize);
|
||||
}
|
||||
|
||||
// don't forget the negated selectors
|
||||
if(mNegations) {
|
||||
localSize = 0;
|
||||
mNegations->SizeOf(aSizeOfHandler, localSize);
|
||||
}
|
||||
|
||||
// finally chain to the next...
|
||||
if(mNext){
|
||||
localSize = 0;
|
||||
|
@ -644,19 +671,36 @@ static PRBool IsPseudoElement(nsIAtom* aAtom)
|
|||
return PR_FALSE;
|
||||
}
|
||||
|
||||
nsresult nsCSSSelector::ToString( nsAWritableString& aString, nsICSSStyleSheet* aSheet, PRBool aIsPseudoElem ) const
|
||||
void nsCSSSelector::AppendNegationToString(nsAWritableString& aString)
|
||||
{
|
||||
aString.Append(NS_LITERAL_STRING(":not("));
|
||||
}
|
||||
|
||||
//
|
||||
// Builds the textual representation of a selector. Called by DOM 2 CSS
|
||||
// StyleRule:selectorText
|
||||
//
|
||||
nsresult nsCSSSelector::ToString( nsAWritableString& aString, nsICSSStyleSheet* aSheet, PRBool aIsPseudoElem,
|
||||
PRInt8 aNegatedIndex) const
|
||||
{
|
||||
const PRUnichar* temp;
|
||||
PRBool aIsNegated = PRBool(0 < aNegatedIndex);
|
||||
|
||||
// selectors are linked from right-to-left, so the next selector in the linked list
|
||||
// actually precedes this one in the resulting string
|
||||
if (mNext) {
|
||||
mNext->ToString(aString, aSheet, IsPseudoElement(mTag));
|
||||
if (!IsPseudoElement(mTag)) {
|
||||
if (mNext) {
|
||||
mNext->ToString(aString, aSheet, IsPseudoElement(mTag), PR_FALSE);
|
||||
if (!aIsNegated && !IsPseudoElement(mTag)) {
|
||||
// don't add a leading whitespace if we have a pseudo-element
|
||||
// or a negated simple selector
|
||||
aString.Append(PRUnichar(' '));
|
||||
}
|
||||
}
|
||||
if (1 < aNegatedIndex) {
|
||||
// the first mNegations does not contain a negated type element selector
|
||||
// or a negated universal selector
|
||||
NS_IF_NEGATED_START(aIsNegated, aString)
|
||||
}
|
||||
|
||||
// append the namespace prefix
|
||||
if (mNameSpace > 0) {
|
||||
|
@ -672,23 +716,30 @@ nsresult nsCSSSelector::ToString( nsAWritableString& aString, nsICSSStyleSheet*
|
|||
aString.Append(PRUnichar('|'));
|
||||
}
|
||||
}
|
||||
|
||||
// smells like a universal selector
|
||||
if (!mTag && !mIDList && !mClassList) {
|
||||
aString.Append(PRUnichar('*'));
|
||||
if (1 != aNegatedIndex) {
|
||||
aString.Append(PRUnichar('*'));
|
||||
}
|
||||
if (1 < aNegatedIndex) {
|
||||
NS_IF_NEGATED_END(aIsNegated, aString)
|
||||
}
|
||||
} else {
|
||||
// Append the tag name, if there is one
|
||||
if (mTag) {
|
||||
mTag->GetUnicode(&temp);
|
||||
aString.Append(temp);
|
||||
NS_IF_NEGATED_END(aIsNegated, aString)
|
||||
}
|
||||
// Append the id, if there is one
|
||||
if (mIDList) {
|
||||
nsAtomList* list = mIDList;
|
||||
while (list != nsnull) {
|
||||
list->mAtom->GetUnicode(&temp);
|
||||
NS_IF_NEGATED_START(aIsNegated, aString)
|
||||
aString.Append(PRUnichar('#'));
|
||||
aString.Append(temp);
|
||||
NS_IF_NEGATED_END(aIsNegated, aString)
|
||||
list = list->mNext;
|
||||
}
|
||||
}
|
||||
|
@ -697,8 +748,10 @@ nsresult nsCSSSelector::ToString( nsAWritableString& aString, nsICSSStyleSheet*
|
|||
nsAtomList* list = mClassList;
|
||||
while (list != nsnull) {
|
||||
list->mAtom->GetUnicode(&temp);
|
||||
NS_IF_NEGATED_START(aIsNegated, aString)
|
||||
aString.Append(PRUnichar('.'));
|
||||
aString.Append(temp);
|
||||
NS_IF_NEGATED_END(aIsNegated, aString)
|
||||
list = list->mNext;
|
||||
}
|
||||
}
|
||||
|
@ -708,6 +761,7 @@ nsresult nsCSSSelector::ToString( nsAWritableString& aString, nsICSSStyleSheet*
|
|||
if (mAttrList) {
|
||||
nsAttrSelector* list = mAttrList;
|
||||
while (list != nsnull) {
|
||||
NS_IF_NEGATED_START(aIsNegated, aString)
|
||||
aString.Append(PRUnichar('['));
|
||||
// Append the namespace prefix
|
||||
if (list->mNameSpace > 0) {
|
||||
|
@ -748,6 +802,7 @@ nsresult nsCSSSelector::ToString( nsAWritableString& aString, nsICSSStyleSheet*
|
|||
// Append the value
|
||||
aString.Append(list->mValue);
|
||||
aString.Append(PRUnichar(']'));
|
||||
NS_IF_NEGATED_END(aIsNegated, aString)
|
||||
list = list->mNext;
|
||||
}
|
||||
}
|
||||
|
@ -757,18 +812,28 @@ nsresult nsCSSSelector::ToString( nsAWritableString& aString, nsICSSStyleSheet*
|
|||
nsAtomList* list = mPseudoClassList;
|
||||
while (list != nsnull) {
|
||||
list->mAtom->GetUnicode(&temp);
|
||||
NS_IF_NEGATED_START(aIsNegated, aString)
|
||||
aString.Append(temp);
|
||||
NS_IF_NEGATED_END(aIsNegated, aString)
|
||||
list = list->mNext;
|
||||
}
|
||||
}
|
||||
// Append the operator
|
||||
if (mOperator && !aIsPseudoElem) {
|
||||
|
||||
if (mNegations) {
|
||||
// chain all the negated selectors
|
||||
mNegations->ToString(aString, aSheet, PR_FALSE, aNegatedIndex + 1);
|
||||
}
|
||||
|
||||
// Append the operator only if the selector is not negated and is not
|
||||
// a pseudo-element
|
||||
if (!aIsNegated && mOperator && !aIsPseudoElem) {
|
||||
aString.Append(PRUnichar(' '));
|
||||
aString.Append(mOperator);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
// -- CSSImportantRule -------------------------------
|
||||
|
||||
static nscoord CalcLength(const nsCSSValue& aValue, const nsFont& aFont,
|
||||
|
@ -1452,7 +1517,8 @@ void CSSStyleRuleImpl::SetSourceSelectorText(const nsString& aSelectorText)
|
|||
|
||||
void CSSStyleRuleImpl::GetSourceSelectorText(nsString& aSelectorText) const
|
||||
{
|
||||
mSelector.ToString( aSelectorText, mSheet, IsPseudoElement(mSelector.mTag) );
|
||||
mSelector.ToString( aSelectorText, mSheet, IsPseudoElement(mSelector.mTag),
|
||||
0 );
|
||||
}
|
||||
|
||||
PRUint32 CSSStyleRuleImpl::GetLineNumber(void) const
|
||||
|
@ -3578,7 +3644,8 @@ CSSStyleRuleImpl::GetType(PRUint16* aType)
|
|||
NS_IMETHODIMP
|
||||
CSSStyleRuleImpl::GetCssText(nsAWritableString& aCssText)
|
||||
{
|
||||
mSelector.ToString( aCssText, mSheet, IsPseudoElement(mSelector.mTag) );
|
||||
mSelector.ToString( aCssText, mSheet, IsPseudoElement(mSelector.mTag),
|
||||
0 );
|
||||
aCssText.Append(PRUnichar(' '));
|
||||
aCssText.Append(PRUnichar('{'));
|
||||
aCssText.Append(PRUnichar(' '));
|
||||
|
@ -3619,7 +3686,7 @@ CSSStyleRuleImpl::GetParentRule(nsIDOMCSSRule** aParentRule)
|
|||
NS_IMETHODIMP
|
||||
CSSStyleRuleImpl::GetSelectorText(nsAWritableString& aSelectorText)
|
||||
{
|
||||
mSelector.ToString( aSelectorText, mSheet, IsPseudoElement(mSelector.mTag) );
|
||||
mSelector.ToString( aSelectorText, mSheet, IsPseudoElement(mSelector.mTag), 0 );
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -2931,167 +2931,229 @@ static PRBool IsSignificantChild(nsIContent* aChild, PRBool aAcceptNonWhitespace
|
|||
|
||||
static PRBool SelectorMatches(SelectorMatchesData &data,
|
||||
nsCSSSelector* aSelector,
|
||||
PRBool aTestState)
|
||||
PRBool aTestState,
|
||||
PRInt8 aNegationIndex)
|
||||
|
||||
{
|
||||
PRBool result = PR_FALSE;
|
||||
// if we are dealing with negations, reverse the values of PR_TRUE and PR_FALSE
|
||||
PRBool localFalse = PRBool(0 < aNegationIndex);
|
||||
PRBool localTrue = PRBool(0 == aNegationIndex);
|
||||
PRBool checkType = (0 == aNegationIndex) || (1 < aNegationIndex);
|
||||
PRBool result = localFalse;
|
||||
nsAutoString buffer;
|
||||
|
||||
// Bail out early if we can
|
||||
if(kNameSpaceID_Unknown != aSelector->mNameSpace) {
|
||||
if(data.mNameSpaceID != aSelector->mNameSpace) {
|
||||
// Bail out early if we can. Do not perform the test if aNegationIndex==1
|
||||
// because it then contains only negated IDs, classes, attributes and pseudo-
|
||||
// classes
|
||||
if (checkType) {
|
||||
if (kNameSpaceID_Unknown != aSelector->mNameSpace) {
|
||||
if (data.mNameSpaceID != aSelector->mNameSpace) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (checkType) {
|
||||
if (localTrue == ((nsnull != aSelector->mTag) && (aSelector->mTag != data.mContentTag))) {
|
||||
return result;
|
||||
}
|
||||
if (1 < aNegationIndex) {
|
||||
// optimization : no other selector to test on negated type or
|
||||
// universal selector
|
||||
return localTrue;
|
||||
}
|
||||
}
|
||||
|
||||
if ((nsnull == aSelector->mTag) || (aSelector->mTag == data.mContentTag)) {
|
||||
|
||||
result = PR_TRUE;
|
||||
// namespace/tag match
|
||||
if (nsnull != aSelector->mAttrList) { // test for attribute match
|
||||
// if no attributes on the content, no match
|
||||
if(!data.mHasAttributes) {
|
||||
result = PR_FALSE;
|
||||
} else {
|
||||
nsAttrSelector* attr = aSelector->mAttrList;
|
||||
do {
|
||||
nsAutoString value, partValue;
|
||||
nsresult attrState = data.mContent->GetAttribute(attr->mNameSpace, attr->mAttr, value);
|
||||
if (NS_FAILED(attrState) || (NS_CONTENT_ATTR_NOT_THERE == attrState)) {
|
||||
result = PR_FALSE;
|
||||
result = localTrue;
|
||||
// namespace/tag match
|
||||
if (nsnull != aSelector->mAttrList) { // test for attribute match
|
||||
// if no attributes on the content, no match
|
||||
if(!data.mHasAttributes) {
|
||||
result = localFalse;
|
||||
} else {
|
||||
nsAttrSelector* attr = aSelector->mAttrList;
|
||||
do {
|
||||
nsAutoString value, partValue;
|
||||
nsresult attrState = data.mContent->GetAttribute(attr->mNameSpace, attr->mAttr, value);
|
||||
if (NS_FAILED(attrState) || (NS_CONTENT_ATTR_NOT_THERE == attrState)) {
|
||||
result = localFalse;
|
||||
}
|
||||
else {
|
||||
PRBool isCaseSensitive = (attr->mCaseSensitive && !data.mIsHTMLContent); // Bug 24390: html attributes should not be case-sensitive
|
||||
switch (attr->mFunction) {
|
||||
case NS_ATTR_FUNC_SET: break;
|
||||
case NS_ATTR_FUNC_EQUALS:
|
||||
if (isCaseSensitive) {
|
||||
result = PRBool(localTrue == value.Equals(attr->mValue));
|
||||
}
|
||||
else {
|
||||
result = PRBool(localTrue == value.EqualsIgnoreCase(attr->mValue));
|
||||
}
|
||||
break;
|
||||
case NS_ATTR_FUNC_INCLUDES:
|
||||
result = PRBool(localTrue == ValueIncludes(value, attr->mValue, isCaseSensitive));
|
||||
break;
|
||||
case NS_ATTR_FUNC_DASHMATCH:
|
||||
result = PRBool(localTrue == ValueDashMatch(value, attr->mValue, isCaseSensitive));
|
||||
break;
|
||||
case NS_ATTR_FUNC_ENDSMATCH:
|
||||
value.Right(partValue, attr->mValue.Length());
|
||||
if (isCaseSensitive) {
|
||||
result = PRBool(localTrue == partValue.Equals(attr->mValue));
|
||||
}
|
||||
else {
|
||||
result = PRBool(localTrue == partValue.EqualsIgnoreCase(attr->mValue));
|
||||
}
|
||||
break;
|
||||
case NS_ATTR_FUNC_BEGINSMATCH:
|
||||
value.Left(partValue, attr->mValue.Length());
|
||||
if (isCaseSensitive) {
|
||||
result = PRBool(localTrue == partValue.Equals(attr->mValue));
|
||||
}
|
||||
else {
|
||||
result = PRBool(localTrue == partValue.EqualsIgnoreCase(attr->mValue));
|
||||
}
|
||||
break;
|
||||
case NS_ATTR_FUNC_CONTAINSMATCH:
|
||||
result = PRBool(localTrue == (-1 != value.Find(attr->mValue, isCaseSensitive)));
|
||||
break;
|
||||
}
|
||||
else {
|
||||
PRBool isCaseSensitive = (attr->mCaseSensitive && !data.mIsHTMLContent); // Bug 24390: html attributes should not be case-sensitive
|
||||
switch (attr->mFunction) {
|
||||
case NS_ATTR_FUNC_SET: break;
|
||||
case NS_ATTR_FUNC_EQUALS:
|
||||
if (isCaseSensitive) {
|
||||
result = value.Equals(attr->mValue);
|
||||
}
|
||||
else {
|
||||
result = value.EqualsIgnoreCase(attr->mValue);
|
||||
}
|
||||
break;
|
||||
case NS_ATTR_FUNC_INCLUDES:
|
||||
result = ValueIncludes(value, attr->mValue, isCaseSensitive);
|
||||
break;
|
||||
case NS_ATTR_FUNC_DASHMATCH:
|
||||
result = ValueDashMatch(value, attr->mValue, isCaseSensitive);
|
||||
break;
|
||||
case NS_ATTR_FUNC_ENDSMATCH:
|
||||
value.Right(partValue, attr->mValue.Length());
|
||||
if (isCaseSensitive) {
|
||||
result = partValue.Equals(attr->mValue);
|
||||
}
|
||||
else {
|
||||
result = partValue.EqualsIgnoreCase(attr->mValue);
|
||||
}
|
||||
break;
|
||||
case NS_ATTR_FUNC_BEGINSMATCH:
|
||||
value.Left(partValue, attr->mValue.Length());
|
||||
if (isCaseSensitive) {
|
||||
result = partValue.Equals(attr->mValue);
|
||||
}
|
||||
else {
|
||||
result = partValue.EqualsIgnoreCase(attr->mValue);
|
||||
}
|
||||
break;
|
||||
case NS_ATTR_FUNC_CONTAINSMATCH:
|
||||
result = (-1 != value.Find(attr->mValue, isCaseSensitive));
|
||||
break;
|
||||
}
|
||||
}
|
||||
attr = attr->mNext;
|
||||
} while ((PR_TRUE == result) && (nsnull != attr));
|
||||
}
|
||||
}
|
||||
attr = attr->mNext;
|
||||
} while ((localTrue == result) && (nsnull != attr));
|
||||
}
|
||||
if ((PR_TRUE == result) &&
|
||||
((nsnull != aSelector->mIDList) || (nsnull != aSelector->mClassList))) { // test for ID & class match
|
||||
result = PR_FALSE;
|
||||
if (data.mStyledContent) {
|
||||
nsAtomList* IDList = aSelector->mIDList;
|
||||
if (nsnull == IDList) {
|
||||
result = PR_TRUE;
|
||||
}
|
||||
else if (nsnull != data.mContentID) {
|
||||
result = PR_TRUE;
|
||||
while (nsnull != IDList) {
|
||||
if (IDList->mAtom != data.mContentID) {
|
||||
result = PR_FALSE;
|
||||
break;
|
||||
}
|
||||
IDList = IDList->mNext;
|
||||
}
|
||||
if ((localTrue == result) &&
|
||||
((nsnull != aSelector->mIDList) || (nsnull != aSelector->mClassList))) { // test for ID & class match
|
||||
result = localFalse;
|
||||
if (data.mStyledContent) {
|
||||
nsAtomList* IDList = aSelector->mIDList;
|
||||
if (nsnull == IDList) {
|
||||
result = localTrue;
|
||||
}
|
||||
else if (nsnull != data.mContentID) {
|
||||
result = localTrue;
|
||||
while (nsnull != IDList) {
|
||||
if (IDList->mAtom != data.mContentID) {
|
||||
result = localFalse;
|
||||
break;
|
||||
}
|
||||
IDList = IDList->mNext;
|
||||
}
|
||||
|
||||
if (PR_TRUE == result) {
|
||||
nsAtomList* classList = aSelector->mClassList;
|
||||
while (nsnull != classList) {
|
||||
if (NS_COMFALSE == data.mStyledContent->HasClass(classList->mAtom)) {
|
||||
result = PR_FALSE;
|
||||
break;
|
||||
}
|
||||
classList = classList->mNext;
|
||||
}
|
||||
|
||||
if (localTrue == result) {
|
||||
nsAtomList* classList = aSelector->mClassList;
|
||||
while (nsnull != classList) {
|
||||
if (NS_COMFALSE == data.mStyledContent->HasClass(classList->mAtom)) {
|
||||
result = localFalse;
|
||||
break;
|
||||
}
|
||||
classList = classList->mNext;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((PR_TRUE == result) &&
|
||||
(nsnull != aSelector->mPseudoClassList)) { // test for pseudo class match
|
||||
// first-child, root, lang, active, focus, hover, link, outOfDate, visited
|
||||
// XXX disabled, enabled, selected, selection
|
||||
nsAtomList* pseudoClass = aSelector->mPseudoClassList;
|
||||
}
|
||||
if ((localTrue == result) &&
|
||||
(nsnull != aSelector->mPseudoClassList)) { // test for pseudo class match
|
||||
// first-child, root, lang, active, focus, hover, link, outOfDate, visited
|
||||
// XXX disabled, enabled, selected, selection
|
||||
nsAtomList* pseudoClass = aSelector->mPseudoClassList;
|
||||
|
||||
while ((PR_TRUE == result) && (nsnull != pseudoClass)) {
|
||||
if ((nsCSSAtoms::firstChildPseudo == pseudoClass->mAtom) ||
|
||||
(nsCSSAtoms::firstNodePseudo == pseudoClass->mAtom) ) {
|
||||
nsIContent* firstChild = nsnull;
|
||||
nsIContent* parent = data.mParentContent;
|
||||
if (parent) {
|
||||
PRInt32 index = -1;
|
||||
do {
|
||||
parent->ChildAt(++index, firstChild);
|
||||
if (firstChild) { // skip text & comments (and whitespace for firstNode as well)
|
||||
if (IsSignificantChild(firstChild, (nsCSSAtoms::firstNodePseudo == pseudoClass->mAtom))) {
|
||||
break;
|
||||
}
|
||||
NS_RELEASE(firstChild);
|
||||
}
|
||||
else {
|
||||
while ((localTrue == result) && (nsnull != pseudoClass)) {
|
||||
if ((nsCSSAtoms::firstChildPseudo == pseudoClass->mAtom) ||
|
||||
(nsCSSAtoms::firstNodePseudo == pseudoClass->mAtom) ) {
|
||||
nsIContent* firstChild = nsnull;
|
||||
nsIContent* parent = data.mParentContent;
|
||||
if (parent) {
|
||||
PRInt32 index = -1;
|
||||
do {
|
||||
parent->ChildAt(++index, firstChild);
|
||||
if (firstChild) { // skip text & comments (and whitespace for firstNode as well)
|
||||
if (IsSignificantChild(firstChild, (nsCSSAtoms::firstNodePseudo == pseudoClass->mAtom))) {
|
||||
break;
|
||||
}
|
||||
} while (1 == 1);
|
||||
}
|
||||
result = PRBool(data.mContent == firstChild);
|
||||
NS_IF_RELEASE(firstChild);
|
||||
NS_RELEASE(firstChild);
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
} while (1 == 1);
|
||||
}
|
||||
else if (nsCSSAtoms::lastNodePseudo == pseudoClass->mAtom) {
|
||||
nsIContent* lastChild = nsnull;
|
||||
nsIContent* parent = data.mParentContent;
|
||||
if (parent) {
|
||||
PRInt32 index;
|
||||
parent->ChildCount(index);
|
||||
do {
|
||||
parent->ChildAt(--index, lastChild);
|
||||
if (lastChild) { // skip whitespace text & comments
|
||||
if (IsSignificantChild(lastChild, PR_TRUE)) {
|
||||
break;
|
||||
}
|
||||
NS_RELEASE(lastChild);
|
||||
}
|
||||
else {
|
||||
result = PRBool(localTrue == (data.mContent == firstChild));
|
||||
NS_IF_RELEASE(firstChild);
|
||||
}
|
||||
else if (nsCSSAtoms::lastNodePseudo == pseudoClass->mAtom) {
|
||||
nsIContent* lastChild = nsnull;
|
||||
nsIContent* parent = data.mParentContent;
|
||||
if (parent) {
|
||||
PRInt32 index;
|
||||
parent->ChildCount(index);
|
||||
do {
|
||||
parent->ChildAt(--index, lastChild);
|
||||
if (lastChild) { // skip whitespace text & comments
|
||||
if (IsSignificantChild(lastChild, PR_TRUE)) {
|
||||
break;
|
||||
}
|
||||
} while (1 == 1);
|
||||
}
|
||||
result = PRBool(data.mContent == lastChild);
|
||||
NS_IF_RELEASE(lastChild);
|
||||
NS_RELEASE(lastChild);
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
} while (1 == 1);
|
||||
}
|
||||
else if (nsCSSAtoms::rootPseudo == pseudoClass->mAtom) {
|
||||
if (data.mParentContent) {
|
||||
result = PR_FALSE;
|
||||
result = PRBool(localTrue == (data.mContent == lastChild));
|
||||
NS_IF_RELEASE(lastChild);
|
||||
}
|
||||
else if (nsCSSAtoms::rootPseudo == pseudoClass->mAtom) {
|
||||
if (data.mParentContent) {
|
||||
result = localFalse;
|
||||
}
|
||||
else {
|
||||
result = localTrue;
|
||||
}
|
||||
}
|
||||
else if (nsCSSAtoms::langPseudo == pseudoClass->mAtom) {
|
||||
// XXX not yet implemented
|
||||
result = localFalse;
|
||||
}
|
||||
else if (IsEventPseudo(pseudoClass->mAtom)) {
|
||||
// check if the element is event-sensitive
|
||||
|
||||
// Quirk Mode: check to see if the element is event-sensitive
|
||||
// - see if the selector applies to event pseudo classes
|
||||
// NOTE: we distinguish between global and subjected selectors so
|
||||
// pass that information on to the determining routine
|
||||
PRBool isSelectorGlobal = aSelector->mTag==nsnull ? PR_TRUE : PR_FALSE;
|
||||
if ((data.mIsQuirkMode) &&
|
||||
(!IsEventSensitive(pseudoClass->mAtom, data.mContentTag, isSelectorGlobal))){
|
||||
result = localFalse;
|
||||
} else if (aTestState) {
|
||||
if (nsCSSAtoms::activePseudo == pseudoClass->mAtom) {
|
||||
result = PRBool(localTrue == (0 != (data.mEventState & NS_EVENT_STATE_ACTIVE)));
|
||||
}
|
||||
else {
|
||||
result = PR_TRUE;
|
||||
else if (nsCSSAtoms::focusPseudo == pseudoClass->mAtom) {
|
||||
result = PRBool(localTrue == (0 != (data.mEventState & NS_EVENT_STATE_FOCUS)));
|
||||
}
|
||||
else if (nsCSSAtoms::hoverPseudo == pseudoClass->mAtom) {
|
||||
result = PRBool(localTrue == (0 != (data.mEventState & NS_EVENT_STATE_HOVER)));
|
||||
}
|
||||
else if (nsCSSAtoms::dragOverPseudo == pseudoClass->mAtom) {
|
||||
result = PRBool(localTrue == (0 != (data.mEventState & NS_EVENT_STATE_DRAGOVER)));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (IsLinkPseudo(pseudoClass->mAtom)) {
|
||||
if (data.mIsHTMLLink || data.mIsSimpleXLink) {
|
||||
if ((localFalse != result) && (aTestState)) {
|
||||
if (nsCSSAtoms::linkPseudo == pseudoClass->mAtom) {
|
||||
result = PRBool(localTrue == (eLinkState_Unvisited == data.mLinkState));
|
||||
}
|
||||
else if (nsCSSAtoms::outOfDatePseudo == pseudoClass->mAtom) {
|
||||
result = PRBool(localTrue == (eLinkState_OutOfDate == data.mLinkState));
|
||||
}
|
||||
else if (nsCSSAtoms::visitedPseudo == pseudoClass->mAtom) {
|
||||
result = PRBool(localTrue == (eLinkState_Visited == data.mLinkState));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (nsCSSAtoms::xblBoundElementPseudo == pseudoClass->mAtom) {
|
||||
|
@ -3106,63 +3168,22 @@ static PRBool SelectorMatches(SelectorMatchesData &data,
|
|||
if (data.mStyleRuleSupplier)
|
||||
data.mStyleRuleSupplier->MatchesScopedRoot(data.mContent, &result);
|
||||
else
|
||||
result = PR_FALSE;
|
||||
}
|
||||
else if (nsCSSAtoms::langPseudo == pseudoClass->mAtom) {
|
||||
// XXX not yet implemented
|
||||
result = PR_FALSE;
|
||||
}
|
||||
else if (IsEventPseudo(pseudoClass->mAtom)) {
|
||||
// check if the element is event-sensitive
|
||||
|
||||
// Quirk Mode: check to see if the element is event-sensitive
|
||||
// - see if the selector applies to event pseudo classes
|
||||
// NOTE: we distinguish between global and subjected selectors so
|
||||
// pass that information on to the determining routine
|
||||
PRBool isSelectorGlobal = aSelector->mTag==nsnull ? PR_TRUE : PR_FALSE;
|
||||
if ((data.mIsQuirkMode) &&
|
||||
(!IsEventSensitive(pseudoClass->mAtom, data.mContentTag, isSelectorGlobal))){
|
||||
result = PR_FALSE;
|
||||
} else if (aTestState) {
|
||||
if (nsCSSAtoms::activePseudo == pseudoClass->mAtom) {
|
||||
result = PRBool(0 != (data.mEventState & NS_EVENT_STATE_ACTIVE));
|
||||
}
|
||||
else if (nsCSSAtoms::focusPseudo == pseudoClass->mAtom) {
|
||||
result = PRBool(0 != (data.mEventState & NS_EVENT_STATE_FOCUS));
|
||||
}
|
||||
else if (nsCSSAtoms::hoverPseudo == pseudoClass->mAtom) {
|
||||
result = PRBool(0 != (data.mEventState & NS_EVENT_STATE_HOVER));
|
||||
}
|
||||
else if (nsCSSAtoms::dragOverPseudo == pseudoClass->mAtom) {
|
||||
result = PRBool(0 != (data.mEventState & NS_EVENT_STATE_DRAGOVER));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (IsLinkPseudo(pseudoClass->mAtom)) {
|
||||
if (data.mIsHTMLLink || data.mIsSimpleXLink) {
|
||||
if ((PR_FALSE != result) && (aTestState)) {
|
||||
if (nsCSSAtoms::linkPseudo == pseudoClass->mAtom) {
|
||||
result = PRBool(eLinkState_Unvisited == data.mLinkState);
|
||||
}
|
||||
else if (nsCSSAtoms::outOfDatePseudo == pseudoClass->mAtom) {
|
||||
result = PRBool(eLinkState_OutOfDate == data.mLinkState);
|
||||
}
|
||||
else if (nsCSSAtoms::visitedPseudo == pseudoClass->mAtom) {
|
||||
result = PRBool(eLinkState_Visited == data.mLinkState);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
result = PR_FALSE; // not a link
|
||||
}
|
||||
result = localFalse;
|
||||
}
|
||||
else {
|
||||
result = PR_FALSE; // unknown pseudo class
|
||||
result = localFalse; // not a link
|
||||
}
|
||||
pseudoClass = pseudoClass->mNext;
|
||||
}
|
||||
else {
|
||||
result = localFalse; // unknown pseudo class
|
||||
}
|
||||
pseudoClass = pseudoClass->mNext;
|
||||
}
|
||||
}
|
||||
// apply SelectorMatches to the negated selectors in the chain
|
||||
if ((localTrue == result) && (nsnull != aSelector->mNegations)) {
|
||||
result = SelectorMatches(data, aSelector->mNegations, aTestState, aNegationIndex+1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -3219,7 +3240,7 @@ static PRBool SelectorMatchesTree(SelectorMatchesData &data,
|
|||
nsCompatibility compat = data.mIsQuirkMode ? eCompatibility_NavQuirks : eCompatibility_Standard;
|
||||
SelectorMatchesData newdata(data.mPresContext, content, data.mParentContext,
|
||||
data.mResults, &compat);
|
||||
if (SelectorMatches(newdata, selector, PR_TRUE)) {
|
||||
if (SelectorMatches(newdata, selector, PR_TRUE, 0)) {
|
||||
// to avoid greedy matching, we need to recurse if this is a
|
||||
// descendant combinator and the next combinator is not
|
||||
if ((NS_IS_GREEDY_OPERATOR(selector->mOperator)) &&
|
||||
|
@ -3262,7 +3283,7 @@ static void ContentEnumFunc(nsICSSStyleRule* aRule, void* aData)
|
|||
ContentEnumData* data = (ContentEnumData*)aData;
|
||||
|
||||
nsCSSSelector* selector = aRule->FirstSelector();
|
||||
if (SelectorMatches(*data, selector, PR_TRUE)) {
|
||||
if (SelectorMatches(*data, selector, PR_TRUE, 0)) {
|
||||
selector = selector->mNext;
|
||||
if (SelectorMatchesTree(*data, selector)) {
|
||||
nsIStyleRule* iRule;
|
||||
|
@ -3368,7 +3389,7 @@ static void PseudoEnumFunc(nsICSSStyleRule* aRule, void* aData)
|
|||
if (PRUnichar('+') == selector->mOperator) {
|
||||
return; // not valid here, can't match
|
||||
}
|
||||
if (SelectorMatches(*data, selector, PR_TRUE)) {
|
||||
if (SelectorMatches(*data, selector, PR_TRUE, 0)) {
|
||||
selector = selector->mNext;
|
||||
}
|
||||
else {
|
||||
|
@ -3452,7 +3473,7 @@ PRBool PR_CALLBACK StateEnumFunc(void* aSelector, void* aData)
|
|||
StateEnumData* data = (StateEnumData*)aData;
|
||||
|
||||
nsCSSSelector* selector = (nsCSSSelector*)aSelector;
|
||||
if (SelectorMatches(*data, selector, PR_FALSE)) {
|
||||
if (SelectorMatches(*data, selector, PR_FALSE, 0)) {
|
||||
selector = selector->mNext;
|
||||
if (SelectorMatchesTree(*data, selector)) {
|
||||
return PR_FALSE;
|
||||
|
|
|
@ -103,7 +103,12 @@ public:
|
|||
PRInt32 CalcWeight(void) const;
|
||||
|
||||
void SizeOf(nsISizeOfHandler *aSizeOfHandler, PRUint32 &aSize);
|
||||
nsresult ToString( nsAWritableString& aString, nsICSSStyleSheet* aSheet, PRBool aIsPseudoElem ) const;
|
||||
nsresult ToString( nsAWritableString& aString, nsICSSStyleSheet* aSheet,
|
||||
PRBool aIsPseudoElem, PRInt8 aNegatedIndex ) const;
|
||||
|
||||
private:
|
||||
|
||||
void AppendNegationToString(nsAWritableString& aString);
|
||||
|
||||
public:
|
||||
PRInt32 mNameSpace;
|
||||
|
@ -113,10 +118,12 @@ public:
|
|||
nsAtomList* mPseudoClassList;
|
||||
nsAttrSelector* mAttrList;
|
||||
PRUnichar mOperator;
|
||||
nsCSSSelector* mNegations;
|
||||
|
||||
nsCSSSelector* mNext;
|
||||
};
|
||||
|
||||
|
||||
// IID for the nsICSSStyleRule interface {7c277af0-af19-11d1-8031-006008159b5a}
|
||||
#define NS_ICSS_STYLE_RULE_IID \
|
||||
{0x7c277af0, 0xaf19, 0x11d1, {0x80, 0x31, 0x00, 0x60, 0x08, 0x15, 0x9b, 0x5a}}
|
||||
|
|
|
@ -66,6 +66,8 @@ CSS_ATOM(linkPseudo, ":link")
|
|||
|
||||
CSS_ATOM(menuPseudo, ":menu")
|
||||
|
||||
CSS_ATOM(notPseudo, ":not")
|
||||
|
||||
CSS_ATOM(outOfDatePseudo, ":out-of-date")
|
||||
|
||||
CSS_ATOM(rootPseudo, ":root")
|
||||
|
|
|
@ -197,12 +197,16 @@ protected:
|
|||
void ParseClassSelector(PRInt32& aDataMask, nsCSSSelector& aSelector,
|
||||
PRInt32& aParsingStatus, PRInt32& aErrorCode);
|
||||
void ParsePseudoSelector(PRInt32& aDataMask, nsCSSSelector& aSelector,
|
||||
PRInt32& aParsingStatus, PRInt32& aErrorCode);
|
||||
PRInt32& aParsingStatus, PRInt32& aErrorCode,
|
||||
PRBool aIsNegated);
|
||||
void ParseAttributeSelector(PRInt32& aDataMask, nsCSSSelector& aSelector,
|
||||
PRInt32& aParsingStatus, PRInt32& aErrorCode);
|
||||
|
||||
void ParseTypeOrUniversalSelector(PRInt32& aDataMask,
|
||||
nsCSSSelector& aSelector,
|
||||
PRInt32& aParsingStatus, PRInt32& aErrorCode,
|
||||
PRBool aIsNegated);
|
||||
void ParseNegatedSimpleSelector(PRInt32& aDataMask, nsCSSSelector& aSelector,
|
||||
PRInt32& aParsingStatus, PRInt32& aErrorCode);
|
||||
|
||||
PRBool ParseSelectorList(PRInt32& aErrorCode, SelectorList*& aListHead);
|
||||
|
@ -1366,11 +1370,12 @@ static PRBool IsPseudoClass(const nsIAtom* aAtom)
|
|||
(nsCSSAtoms::enabledPseudo == aAtom) ||
|
||||
(nsCSSAtoms::firstChildPseudo == aAtom) ||
|
||||
(nsCSSAtoms::firstNodePseudo == aAtom) ||
|
||||
(nsCSSAtoms::lastNodePseudo == aAtom) ||
|
||||
(nsCSSAtoms::focusPseudo == aAtom) ||
|
||||
(nsCSSAtoms::hoverPseudo == aAtom) ||
|
||||
(nsCSSAtoms::langPseudo == aAtom) ||
|
||||
(nsCSSAtoms::lastNodePseudo == aAtom) ||
|
||||
(nsCSSAtoms::linkPseudo == aAtom) ||
|
||||
(nsCSSAtoms::outOfDatePseudo == aAtom) ||
|
||||
(nsCSSAtoms::rootPseudo == aAtom) ||
|
||||
(nsCSSAtoms::xblBoundElementPseudo == aAtom) ||
|
||||
(nsCSSAtoms::outOfDatePseudo == aAtom) ||
|
||||
|
@ -1520,6 +1525,9 @@ PRBool CSSParserImpl::ParseSelectorGroup(PRInt32& aErrorCode,
|
|||
#define SELECTOR_PARSING_STOPPED_OK 2
|
||||
#define SELECTOR_PARSING_STOPPED_ERROR 3
|
||||
|
||||
//
|
||||
// Parses an ID selector #name
|
||||
//
|
||||
void CSSParserImpl::ParseIDSelector(PRInt32& aDataMask,
|
||||
nsCSSSelector& aSelector,
|
||||
PRInt32& aParsingStatus,
|
||||
|
@ -1539,6 +1547,9 @@ void CSSParserImpl::ParseIDSelector(PRInt32& aDataMask,
|
|||
aParsingStatus = SELECTOR_PARSING_ENDED_OK;
|
||||
}
|
||||
|
||||
//
|
||||
// Parses a class selector .name
|
||||
//
|
||||
void CSSParserImpl::ParseClassSelector(PRInt32& aDataMask,
|
||||
nsCSSSelector& aSelector,
|
||||
PRInt32& aParsingStatus,
|
||||
|
@ -1560,11 +1571,15 @@ void CSSParserImpl::ParseClassSelector(PRInt32& aDataMask,
|
|||
aParsingStatus = SELECTOR_PARSING_ENDED_OK;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Parse a type element selector or a universal selector
|
||||
// namespace|type or namespace|* or *|* or *
|
||||
//
|
||||
void CSSParserImpl::ParseTypeOrUniversalSelector(PRInt32& aDataMask,
|
||||
nsCSSSelector& aSelector,
|
||||
PRInt32& aParsingStatus,
|
||||
PRInt32& aErrorCode)
|
||||
PRInt32& aErrorCode,
|
||||
PRBool aIsNegated)
|
||||
{
|
||||
nsAutoString buffer;
|
||||
if (mToken.IsSymbol('*')) { // universal element selector, or universal namespace
|
||||
|
@ -1729,8 +1744,16 @@ void CSSParserImpl::ParseTypeOrUniversalSelector(PRInt32& aDataMask,
|
|||
}
|
||||
}
|
||||
aParsingStatus = SELECTOR_PARSING_ENDED_OK;
|
||||
if (aIsNegated) {
|
||||
// restore last token read in case of a negated type selector
|
||||
UngetToken();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Parse attribute selectors [attr], [attr=value], [attr|=value],
|
||||
// [attr~=value], [attr^=value], [attr$=value] and [attr*=value]
|
||||
//
|
||||
void CSSParserImpl::ParseAttributeSelector(PRInt32& aDataMask,
|
||||
nsCSSSelector& aSelector,
|
||||
PRInt32& aParsingStatus,
|
||||
|
@ -1913,10 +1936,14 @@ void CSSParserImpl::ParseAttributeSelector(PRInt32& aDataMask,
|
|||
aParsingStatus = SELECTOR_PARSING_ENDED_OK;
|
||||
}
|
||||
|
||||
//
|
||||
// Parse pseudo-classes and pseudo-elements
|
||||
//
|
||||
void CSSParserImpl::ParsePseudoSelector(PRInt32& aDataMask,
|
||||
nsCSSSelector& aSelector,
|
||||
PRInt32& aParsingStatus,
|
||||
PRInt32& aErrorCode)
|
||||
PRInt32& aErrorCode,
|
||||
PRBool aIsNegated)
|
||||
{
|
||||
nsAutoString buffer;
|
||||
if (! GetToken(aErrorCode, PR_FALSE)) { // premature eof
|
||||
|
@ -1924,12 +1951,24 @@ void CSSParserImpl::ParsePseudoSelector(PRInt32& aDataMask,
|
|||
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
buffer.Truncate();
|
||||
buffer.AppendWithConversion(':');
|
||||
buffer.Append(mToken.mIdent);
|
||||
buffer.ToLowerCase();
|
||||
nsIAtom* pseudo = NS_NewAtom(buffer);
|
||||
|
||||
if (eCSSToken_Ident != mToken.mType) { // malformed selector
|
||||
if (eCSSToken_Function != mToken.mType ||
|
||||
!(
|
||||
#ifdef INCLUDE_XUL
|
||||
if (eCSSToken_Function != mToken.mType ||
|
||||
!IsOutlinerPseudoElement(mToken.mIdent)) {
|
||||
// -moz-outliner is a pseudo-element and therefore cannot be negated
|
||||
(!aIsNegated && IsOutlinerPseudoElement(mToken.mIdent)) ||
|
||||
#endif
|
||||
REPORT_UNEXPECTED_TOKEN(NS_LITERAL_STRING("Expected identifier for pseudo-class selector but found"));
|
||||
// the negation pseudo-class is a function
|
||||
(nsCSSAtoms::notPseudo == pseudo))) {
|
||||
REPORT_UNEXPECTED_TOKEN(NS_LITERAL_STRING("Expected identifier for pseudo-class selector not found"));
|
||||
NS_RELEASE(pseudo);
|
||||
UngetToken();
|
||||
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR;
|
||||
return;
|
||||
|
@ -1937,18 +1976,32 @@ void CSSParserImpl::ParsePseudoSelector(PRInt32& aDataMask,
|
|||
}
|
||||
#endif
|
||||
}
|
||||
buffer.Truncate();
|
||||
buffer.AppendWithConversion(':');
|
||||
buffer.Append(mToken.mIdent);
|
||||
buffer.ToLowerCase();
|
||||
nsIAtom* pseudo = NS_NewAtom(buffer);
|
||||
if (IsPseudoClass(pseudo)) {
|
||||
// XXX parse lang pseudo class
|
||||
|
||||
if (nsCSSAtoms::notPseudo == pseudo) {
|
||||
NS_RELEASE(pseudo);
|
||||
if (aIsNegated) { // :not() can't be itself negated
|
||||
REPORT_UNEXPECTED_TOKEN(NS_LITERAL_STRING("Negation pseudo-class can't be negated"));
|
||||
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR;
|
||||
return;
|
||||
}
|
||||
// CSS 3 Negation pseudo-class takes one simple selector as argument
|
||||
ParseNegatedSimpleSelector(aDataMask, aSelector, aParsingStatus, aErrorCode);
|
||||
if (SELECTOR_PARSING_ENDED_OK != aParsingStatus) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (IsPseudoClass(pseudo)) {
|
||||
// XXX parse pseudo classes accepting arguments
|
||||
aDataMask |= SEL_MASK_PCLASS;
|
||||
aSelector.AddPseudoClass(pseudo);
|
||||
NS_RELEASE(pseudo);
|
||||
}
|
||||
else {
|
||||
if (aIsNegated) { // pseudo-elements can't be negated
|
||||
REPORT_UNEXPECTED_TOKEN(NS_LITERAL_STRING("Pseudo-elements can't be negated"));
|
||||
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR;
|
||||
return;
|
||||
}
|
||||
if (0 == (aDataMask & SEL_MASK_PELEM)) {
|
||||
aDataMask |= SEL_MASK_PELEM;
|
||||
aSelector.AddPseudoClass(pseudo); // store it here, it gets pulled later
|
||||
|
@ -1992,6 +2045,76 @@ void CSSParserImpl::ParsePseudoSelector(PRInt32& aDataMask,
|
|||
aParsingStatus = SELECTOR_PARSING_ENDED_OK;
|
||||
}
|
||||
|
||||
//
|
||||
// Parse the argument of a negation pseudo-class :not()
|
||||
//
|
||||
void CSSParserImpl::ParseNegatedSimpleSelector(PRInt32& aDataMask,
|
||||
nsCSSSelector& aSelector,
|
||||
PRInt32& aParsingStatus,
|
||||
PRInt32& aErrorCode)
|
||||
{
|
||||
// Check if we have the first parenthesis
|
||||
if (ExpectSymbol(aErrorCode, '(', PR_FALSE)) {
|
||||
|
||||
if (! GetToken(aErrorCode, PR_FALSE)) { // premature eof
|
||||
REPORT_UNEXPECTED_EOF();
|
||||
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR;
|
||||
return;
|
||||
}
|
||||
aParsingStatus = SELECTOR_PARSING_ENDED_OK;
|
||||
nsCSSSelector* newSel = new nsCSSSelector();
|
||||
if (nsnull == aSelector.mNegations &&
|
||||
((eCSSToken_ID == mToken.mType) ||
|
||||
mToken.IsSymbol('.') ||
|
||||
mToken.IsSymbol(':') ||
|
||||
mToken.IsSymbol('['))) {
|
||||
// ID, class and attribute selectors and pseudo-classes are stored in
|
||||
// the first mNegations attached to a selector
|
||||
aSelector.mNegations = newSel;
|
||||
}
|
||||
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
|
||||
if (nsnull == aSelector.mNegations) {
|
||||
aSelector.mNegations = newSel;
|
||||
}
|
||||
newSel = new nsCSSSelector();
|
||||
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(NS_LITERAL_STRING("Malformed simple selector as negation pseudo-class argument"));
|
||||
return;
|
||||
}
|
||||
// close the parenthesis
|
||||
if (!ExpectSymbol(aErrorCode, ')', PR_TRUE)) {
|
||||
REPORT_UNEXPECTED_TOKEN(NS_LITERAL_STRING("Missing closing ')' in negation pseudo-class"));
|
||||
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR;
|
||||
}
|
||||
}
|
||||
else {
|
||||
REPORT_UNEXPECTED_TOKEN(NS_LITERAL_STRING("Missing argument in negation pseudo-class"));
|
||||
aParsingStatus = SELECTOR_PARSING_STOPPED_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the format for selectors:
|
||||
* operator? [[namespace |]? element_name]? [ ID | class | attrib | pseudo ]*
|
||||
|
@ -2007,7 +2130,7 @@ PRBool CSSParserImpl::ParseSelector(PRInt32& aErrorCode,
|
|||
return PR_FALSE;
|
||||
}
|
||||
|
||||
ParseTypeOrUniversalSelector(dataMask, aSelector, parsingStatus, aErrorCode);
|
||||
ParseTypeOrUniversalSelector(dataMask, aSelector, parsingStatus, aErrorCode, PR_FALSE);
|
||||
if (SELECTOR_PARSING_STOPPED_OK == parsingStatus) {
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
@ -2024,7 +2147,7 @@ PRBool CSSParserImpl::ParseSelector(PRInt32& aErrorCode,
|
|||
ParseClassSelector(dataMask, aSelector, parsingStatus, aErrorCode);
|
||||
}
|
||||
else if (mToken.IsSymbol(':')) { // :pseudo
|
||||
ParsePseudoSelector(dataMask, aSelector, parsingStatus, aErrorCode);
|
||||
ParsePseudoSelector(dataMask, aSelector, parsingStatus, aErrorCode, PR_FALSE);
|
||||
}
|
||||
else if (mToken.IsSymbol('[')) { // attribute
|
||||
ParseAttributeSelector(dataMask, aSelector, parsingStatus, aErrorCode);
|
||||
|
|
|
@ -90,6 +90,12 @@ static NS_DEFINE_IID(kCSSXULSID, NS_CSS_XUL_SID);
|
|||
#define NS_IF_DELETE(ptr) \
|
||||
if (nsnull != ptr) { delete ptr; ptr = nsnull; }
|
||||
|
||||
#define NS_IF_NEGATED_START(bool,str) \
|
||||
if (bool) { str.Append(NS_LITERAL_STRING(":not(")); }
|
||||
|
||||
#define NS_IF_NEGATED_END(bool,str) \
|
||||
if (bool) { str.Append(PRUnichar(')')); }
|
||||
|
||||
MOZ_DECL_CTOR_COUNTER(nsAtomList)
|
||||
|
||||
nsAtomList::nsAtomList(nsIAtom* aAtom)
|
||||
|
@ -292,6 +298,7 @@ nsCSSSelector::nsCSSSelector(void)
|
|||
mPseudoClassList(nsnull),
|
||||
mAttrList(nsnull),
|
||||
mOperator(0),
|
||||
mNegations(nsnull),
|
||||
mNext(nsnull)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsCSSSelector);
|
||||
|
@ -309,6 +316,7 @@ nsCSSSelector::nsCSSSelector(const nsCSSSelector& aCopy)
|
|||
mPseudoClassList(nsnull),
|
||||
mAttrList(nsnull),
|
||||
mOperator(aCopy.mOperator),
|
||||
mNegations(nsnull),
|
||||
mNext(nsnull)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsCSSSelector);
|
||||
|
@ -317,7 +325,8 @@ nsCSSSelector::nsCSSSelector(const nsCSSSelector& aCopy)
|
|||
NS_IF_COPY(mClassList, aCopy.mClassList, nsAtomList);
|
||||
NS_IF_COPY(mPseudoClassList, aCopy.mPseudoClassList, nsAtomList);
|
||||
NS_IF_COPY(mAttrList, aCopy.mAttrList, nsAttrSelector);
|
||||
|
||||
NS_IF_COPY(mNegations, aCopy.mNegations, nsCSSSelector);
|
||||
|
||||
#ifdef DEBUG_REFS
|
||||
gSelectorCount++;
|
||||
printf( "nsCSSSelector Instances (cp-ctor): %ld\n", (long)gSelectorCount);
|
||||
|
@ -342,7 +351,8 @@ nsCSSSelector& nsCSSSelector::operator=(const nsCSSSelector& aCopy)
|
|||
NS_IF_DELETE(mClassList);
|
||||
NS_IF_DELETE(mPseudoClassList);
|
||||
NS_IF_DELETE(mAttrList);
|
||||
|
||||
NS_IF_DELETE(mNegations);
|
||||
|
||||
mNameSpace = aCopy.mNameSpace;
|
||||
mTag = aCopy.mTag;
|
||||
NS_IF_COPY(mIDList, aCopy.mIDList, nsAtomList);
|
||||
|
@ -350,6 +360,7 @@ nsCSSSelector& nsCSSSelector::operator=(const nsCSSSelector& aCopy)
|
|||
NS_IF_COPY(mPseudoClassList, aCopy.mPseudoClassList, nsAtomList);
|
||||
NS_IF_COPY(mAttrList, aCopy.mAttrList, nsAttrSelector);
|
||||
mOperator = aCopy.mOperator;
|
||||
NS_IF_COPY(mNegations, aCopy.mNegations, nsCSSSelector);
|
||||
|
||||
NS_IF_ADDREF(mTag);
|
||||
return *this;
|
||||
|
@ -404,6 +415,11 @@ PRBool nsCSSSelector::Equals(const nsCSSSelector* aOther) const
|
|||
return PR_FALSE;
|
||||
}
|
||||
}
|
||||
if (nsnull != mNegations) {
|
||||
if (PR_FALSE == mNegations->Equals(aOther->mNegations)) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
}
|
||||
|
@ -419,6 +435,7 @@ void nsCSSSelector::Reset(void)
|
|||
NS_IF_DELETE(mClassList);
|
||||
NS_IF_DELETE(mPseudoClassList);
|
||||
NS_IF_DELETE(mAttrList);
|
||||
NS_IF_DELETE(mNegations);
|
||||
mOperator = PRUnichar(0);
|
||||
}
|
||||
|
||||
|
@ -534,6 +551,9 @@ PRInt32 nsCSSSelector::CalcWeight(void) const
|
|||
weight += 0x000100;
|
||||
attr = attr->mNext;
|
||||
}
|
||||
if (nsnull != mNegations) {
|
||||
weight += mNegations->CalcWeight();
|
||||
}
|
||||
return weight;
|
||||
}
|
||||
|
||||
|
@ -624,6 +644,13 @@ void nsCSSSelector::SizeOf(nsISizeOfHandler *aSizeOfHandler, PRUint32 &aSize)
|
|||
localSize = 0;
|
||||
mAttrList->SizeOf(aSizeOfHandler, localSize);
|
||||
}
|
||||
|
||||
// don't forget the negated selectors
|
||||
if(mNegations) {
|
||||
localSize = 0;
|
||||
mNegations->SizeOf(aSizeOfHandler, localSize);
|
||||
}
|
||||
|
||||
// finally chain to the next...
|
||||
if(mNext){
|
||||
localSize = 0;
|
||||
|
@ -644,19 +671,36 @@ static PRBool IsPseudoElement(nsIAtom* aAtom)
|
|||
return PR_FALSE;
|
||||
}
|
||||
|
||||
nsresult nsCSSSelector::ToString( nsAWritableString& aString, nsICSSStyleSheet* aSheet, PRBool aIsPseudoElem ) const
|
||||
void nsCSSSelector::AppendNegationToString(nsAWritableString& aString)
|
||||
{
|
||||
aString.Append(NS_LITERAL_STRING(":not("));
|
||||
}
|
||||
|
||||
//
|
||||
// Builds the textual representation of a selector. Called by DOM 2 CSS
|
||||
// StyleRule:selectorText
|
||||
//
|
||||
nsresult nsCSSSelector::ToString( nsAWritableString& aString, nsICSSStyleSheet* aSheet, PRBool aIsPseudoElem,
|
||||
PRInt8 aNegatedIndex) const
|
||||
{
|
||||
const PRUnichar* temp;
|
||||
PRBool aIsNegated = PRBool(0 < aNegatedIndex);
|
||||
|
||||
// selectors are linked from right-to-left, so the next selector in the linked list
|
||||
// actually precedes this one in the resulting string
|
||||
if (mNext) {
|
||||
mNext->ToString(aString, aSheet, IsPseudoElement(mTag));
|
||||
if (!IsPseudoElement(mTag)) {
|
||||
if (mNext) {
|
||||
mNext->ToString(aString, aSheet, IsPseudoElement(mTag), PR_FALSE);
|
||||
if (!aIsNegated && !IsPseudoElement(mTag)) {
|
||||
// don't add a leading whitespace if we have a pseudo-element
|
||||
// or a negated simple selector
|
||||
aString.Append(PRUnichar(' '));
|
||||
}
|
||||
}
|
||||
if (1 < aNegatedIndex) {
|
||||
// the first mNegations does not contain a negated type element selector
|
||||
// or a negated universal selector
|
||||
NS_IF_NEGATED_START(aIsNegated, aString)
|
||||
}
|
||||
|
||||
// append the namespace prefix
|
||||
if (mNameSpace > 0) {
|
||||
|
@ -672,23 +716,30 @@ nsresult nsCSSSelector::ToString( nsAWritableString& aString, nsICSSStyleSheet*
|
|||
aString.Append(PRUnichar('|'));
|
||||
}
|
||||
}
|
||||
|
||||
// smells like a universal selector
|
||||
if (!mTag && !mIDList && !mClassList) {
|
||||
aString.Append(PRUnichar('*'));
|
||||
if (1 != aNegatedIndex) {
|
||||
aString.Append(PRUnichar('*'));
|
||||
}
|
||||
if (1 < aNegatedIndex) {
|
||||
NS_IF_NEGATED_END(aIsNegated, aString)
|
||||
}
|
||||
} else {
|
||||
// Append the tag name, if there is one
|
||||
if (mTag) {
|
||||
mTag->GetUnicode(&temp);
|
||||
aString.Append(temp);
|
||||
NS_IF_NEGATED_END(aIsNegated, aString)
|
||||
}
|
||||
// Append the id, if there is one
|
||||
if (mIDList) {
|
||||
nsAtomList* list = mIDList;
|
||||
while (list != nsnull) {
|
||||
list->mAtom->GetUnicode(&temp);
|
||||
NS_IF_NEGATED_START(aIsNegated, aString)
|
||||
aString.Append(PRUnichar('#'));
|
||||
aString.Append(temp);
|
||||
NS_IF_NEGATED_END(aIsNegated, aString)
|
||||
list = list->mNext;
|
||||
}
|
||||
}
|
||||
|
@ -697,8 +748,10 @@ nsresult nsCSSSelector::ToString( nsAWritableString& aString, nsICSSStyleSheet*
|
|||
nsAtomList* list = mClassList;
|
||||
while (list != nsnull) {
|
||||
list->mAtom->GetUnicode(&temp);
|
||||
NS_IF_NEGATED_START(aIsNegated, aString)
|
||||
aString.Append(PRUnichar('.'));
|
||||
aString.Append(temp);
|
||||
NS_IF_NEGATED_END(aIsNegated, aString)
|
||||
list = list->mNext;
|
||||
}
|
||||
}
|
||||
|
@ -708,6 +761,7 @@ nsresult nsCSSSelector::ToString( nsAWritableString& aString, nsICSSStyleSheet*
|
|||
if (mAttrList) {
|
||||
nsAttrSelector* list = mAttrList;
|
||||
while (list != nsnull) {
|
||||
NS_IF_NEGATED_START(aIsNegated, aString)
|
||||
aString.Append(PRUnichar('['));
|
||||
// Append the namespace prefix
|
||||
if (list->mNameSpace > 0) {
|
||||
|
@ -748,6 +802,7 @@ nsresult nsCSSSelector::ToString( nsAWritableString& aString, nsICSSStyleSheet*
|
|||
// Append the value
|
||||
aString.Append(list->mValue);
|
||||
aString.Append(PRUnichar(']'));
|
||||
NS_IF_NEGATED_END(aIsNegated, aString)
|
||||
list = list->mNext;
|
||||
}
|
||||
}
|
||||
|
@ -757,18 +812,28 @@ nsresult nsCSSSelector::ToString( nsAWritableString& aString, nsICSSStyleSheet*
|
|||
nsAtomList* list = mPseudoClassList;
|
||||
while (list != nsnull) {
|
||||
list->mAtom->GetUnicode(&temp);
|
||||
NS_IF_NEGATED_START(aIsNegated, aString)
|
||||
aString.Append(temp);
|
||||
NS_IF_NEGATED_END(aIsNegated, aString)
|
||||
list = list->mNext;
|
||||
}
|
||||
}
|
||||
// Append the operator
|
||||
if (mOperator && !aIsPseudoElem) {
|
||||
|
||||
if (mNegations) {
|
||||
// chain all the negated selectors
|
||||
mNegations->ToString(aString, aSheet, PR_FALSE, aNegatedIndex + 1);
|
||||
}
|
||||
|
||||
// Append the operator only if the selector is not negated and is not
|
||||
// a pseudo-element
|
||||
if (!aIsNegated && mOperator && !aIsPseudoElem) {
|
||||
aString.Append(PRUnichar(' '));
|
||||
aString.Append(mOperator);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
// -- CSSImportantRule -------------------------------
|
||||
|
||||
static nscoord CalcLength(const nsCSSValue& aValue, const nsFont& aFont,
|
||||
|
@ -1452,7 +1517,8 @@ void CSSStyleRuleImpl::SetSourceSelectorText(const nsString& aSelectorText)
|
|||
|
||||
void CSSStyleRuleImpl::GetSourceSelectorText(nsString& aSelectorText) const
|
||||
{
|
||||
mSelector.ToString( aSelectorText, mSheet, IsPseudoElement(mSelector.mTag) );
|
||||
mSelector.ToString( aSelectorText, mSheet, IsPseudoElement(mSelector.mTag),
|
||||
0 );
|
||||
}
|
||||
|
||||
PRUint32 CSSStyleRuleImpl::GetLineNumber(void) const
|
||||
|
@ -3578,7 +3644,8 @@ CSSStyleRuleImpl::GetType(PRUint16* aType)
|
|||
NS_IMETHODIMP
|
||||
CSSStyleRuleImpl::GetCssText(nsAWritableString& aCssText)
|
||||
{
|
||||
mSelector.ToString( aCssText, mSheet, IsPseudoElement(mSelector.mTag) );
|
||||
mSelector.ToString( aCssText, mSheet, IsPseudoElement(mSelector.mTag),
|
||||
0 );
|
||||
aCssText.Append(PRUnichar(' '));
|
||||
aCssText.Append(PRUnichar('{'));
|
||||
aCssText.Append(PRUnichar(' '));
|
||||
|
@ -3619,7 +3686,7 @@ CSSStyleRuleImpl::GetParentRule(nsIDOMCSSRule** aParentRule)
|
|||
NS_IMETHODIMP
|
||||
CSSStyleRuleImpl::GetSelectorText(nsAWritableString& aSelectorText)
|
||||
{
|
||||
mSelector.ToString( aSelectorText, mSheet, IsPseudoElement(mSelector.mTag) );
|
||||
mSelector.ToString( aSelectorText, mSheet, IsPseudoElement(mSelector.mTag), 0 );
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -2931,167 +2931,229 @@ static PRBool IsSignificantChild(nsIContent* aChild, PRBool aAcceptNonWhitespace
|
|||
|
||||
static PRBool SelectorMatches(SelectorMatchesData &data,
|
||||
nsCSSSelector* aSelector,
|
||||
PRBool aTestState)
|
||||
PRBool aTestState,
|
||||
PRInt8 aNegationIndex)
|
||||
|
||||
{
|
||||
PRBool result = PR_FALSE;
|
||||
// if we are dealing with negations, reverse the values of PR_TRUE and PR_FALSE
|
||||
PRBool localFalse = PRBool(0 < aNegationIndex);
|
||||
PRBool localTrue = PRBool(0 == aNegationIndex);
|
||||
PRBool checkType = (0 == aNegationIndex) || (1 < aNegationIndex);
|
||||
PRBool result = localFalse;
|
||||
nsAutoString buffer;
|
||||
|
||||
// Bail out early if we can
|
||||
if(kNameSpaceID_Unknown != aSelector->mNameSpace) {
|
||||
if(data.mNameSpaceID != aSelector->mNameSpace) {
|
||||
// Bail out early if we can. Do not perform the test if aNegationIndex==1
|
||||
// because it then contains only negated IDs, classes, attributes and pseudo-
|
||||
// classes
|
||||
if (checkType) {
|
||||
if (kNameSpaceID_Unknown != aSelector->mNameSpace) {
|
||||
if (data.mNameSpaceID != aSelector->mNameSpace) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (checkType) {
|
||||
if (localTrue == ((nsnull != aSelector->mTag) && (aSelector->mTag != data.mContentTag))) {
|
||||
return result;
|
||||
}
|
||||
if (1 < aNegationIndex) {
|
||||
// optimization : no other selector to test on negated type or
|
||||
// universal selector
|
||||
return localTrue;
|
||||
}
|
||||
}
|
||||
|
||||
if ((nsnull == aSelector->mTag) || (aSelector->mTag == data.mContentTag)) {
|
||||
|
||||
result = PR_TRUE;
|
||||
// namespace/tag match
|
||||
if (nsnull != aSelector->mAttrList) { // test for attribute match
|
||||
// if no attributes on the content, no match
|
||||
if(!data.mHasAttributes) {
|
||||
result = PR_FALSE;
|
||||
} else {
|
||||
nsAttrSelector* attr = aSelector->mAttrList;
|
||||
do {
|
||||
nsAutoString value, partValue;
|
||||
nsresult attrState = data.mContent->GetAttribute(attr->mNameSpace, attr->mAttr, value);
|
||||
if (NS_FAILED(attrState) || (NS_CONTENT_ATTR_NOT_THERE == attrState)) {
|
||||
result = PR_FALSE;
|
||||
result = localTrue;
|
||||
// namespace/tag match
|
||||
if (nsnull != aSelector->mAttrList) { // test for attribute match
|
||||
// if no attributes on the content, no match
|
||||
if(!data.mHasAttributes) {
|
||||
result = localFalse;
|
||||
} else {
|
||||
nsAttrSelector* attr = aSelector->mAttrList;
|
||||
do {
|
||||
nsAutoString value, partValue;
|
||||
nsresult attrState = data.mContent->GetAttribute(attr->mNameSpace, attr->mAttr, value);
|
||||
if (NS_FAILED(attrState) || (NS_CONTENT_ATTR_NOT_THERE == attrState)) {
|
||||
result = localFalse;
|
||||
}
|
||||
else {
|
||||
PRBool isCaseSensitive = (attr->mCaseSensitive && !data.mIsHTMLContent); // Bug 24390: html attributes should not be case-sensitive
|
||||
switch (attr->mFunction) {
|
||||
case NS_ATTR_FUNC_SET: break;
|
||||
case NS_ATTR_FUNC_EQUALS:
|
||||
if (isCaseSensitive) {
|
||||
result = PRBool(localTrue == value.Equals(attr->mValue));
|
||||
}
|
||||
else {
|
||||
result = PRBool(localTrue == value.EqualsIgnoreCase(attr->mValue));
|
||||
}
|
||||
break;
|
||||
case NS_ATTR_FUNC_INCLUDES:
|
||||
result = PRBool(localTrue == ValueIncludes(value, attr->mValue, isCaseSensitive));
|
||||
break;
|
||||
case NS_ATTR_FUNC_DASHMATCH:
|
||||
result = PRBool(localTrue == ValueDashMatch(value, attr->mValue, isCaseSensitive));
|
||||
break;
|
||||
case NS_ATTR_FUNC_ENDSMATCH:
|
||||
value.Right(partValue, attr->mValue.Length());
|
||||
if (isCaseSensitive) {
|
||||
result = PRBool(localTrue == partValue.Equals(attr->mValue));
|
||||
}
|
||||
else {
|
||||
result = PRBool(localTrue == partValue.EqualsIgnoreCase(attr->mValue));
|
||||
}
|
||||
break;
|
||||
case NS_ATTR_FUNC_BEGINSMATCH:
|
||||
value.Left(partValue, attr->mValue.Length());
|
||||
if (isCaseSensitive) {
|
||||
result = PRBool(localTrue == partValue.Equals(attr->mValue));
|
||||
}
|
||||
else {
|
||||
result = PRBool(localTrue == partValue.EqualsIgnoreCase(attr->mValue));
|
||||
}
|
||||
break;
|
||||
case NS_ATTR_FUNC_CONTAINSMATCH:
|
||||
result = PRBool(localTrue == (-1 != value.Find(attr->mValue, isCaseSensitive)));
|
||||
break;
|
||||
}
|
||||
else {
|
||||
PRBool isCaseSensitive = (attr->mCaseSensitive && !data.mIsHTMLContent); // Bug 24390: html attributes should not be case-sensitive
|
||||
switch (attr->mFunction) {
|
||||
case NS_ATTR_FUNC_SET: break;
|
||||
case NS_ATTR_FUNC_EQUALS:
|
||||
if (isCaseSensitive) {
|
||||
result = value.Equals(attr->mValue);
|
||||
}
|
||||
else {
|
||||
result = value.EqualsIgnoreCase(attr->mValue);
|
||||
}
|
||||
break;
|
||||
case NS_ATTR_FUNC_INCLUDES:
|
||||
result = ValueIncludes(value, attr->mValue, isCaseSensitive);
|
||||
break;
|
||||
case NS_ATTR_FUNC_DASHMATCH:
|
||||
result = ValueDashMatch(value, attr->mValue, isCaseSensitive);
|
||||
break;
|
||||
case NS_ATTR_FUNC_ENDSMATCH:
|
||||
value.Right(partValue, attr->mValue.Length());
|
||||
if (isCaseSensitive) {
|
||||
result = partValue.Equals(attr->mValue);
|
||||
}
|
||||
else {
|
||||
result = partValue.EqualsIgnoreCase(attr->mValue);
|
||||
}
|
||||
break;
|
||||
case NS_ATTR_FUNC_BEGINSMATCH:
|
||||
value.Left(partValue, attr->mValue.Length());
|
||||
if (isCaseSensitive) {
|
||||
result = partValue.Equals(attr->mValue);
|
||||
}
|
||||
else {
|
||||
result = partValue.EqualsIgnoreCase(attr->mValue);
|
||||
}
|
||||
break;
|
||||
case NS_ATTR_FUNC_CONTAINSMATCH:
|
||||
result = (-1 != value.Find(attr->mValue, isCaseSensitive));
|
||||
break;
|
||||
}
|
||||
}
|
||||
attr = attr->mNext;
|
||||
} while ((PR_TRUE == result) && (nsnull != attr));
|
||||
}
|
||||
}
|
||||
attr = attr->mNext;
|
||||
} while ((localTrue == result) && (nsnull != attr));
|
||||
}
|
||||
if ((PR_TRUE == result) &&
|
||||
((nsnull != aSelector->mIDList) || (nsnull != aSelector->mClassList))) { // test for ID & class match
|
||||
result = PR_FALSE;
|
||||
if (data.mStyledContent) {
|
||||
nsAtomList* IDList = aSelector->mIDList;
|
||||
if (nsnull == IDList) {
|
||||
result = PR_TRUE;
|
||||
}
|
||||
else if (nsnull != data.mContentID) {
|
||||
result = PR_TRUE;
|
||||
while (nsnull != IDList) {
|
||||
if (IDList->mAtom != data.mContentID) {
|
||||
result = PR_FALSE;
|
||||
break;
|
||||
}
|
||||
IDList = IDList->mNext;
|
||||
}
|
||||
if ((localTrue == result) &&
|
||||
((nsnull != aSelector->mIDList) || (nsnull != aSelector->mClassList))) { // test for ID & class match
|
||||
result = localFalse;
|
||||
if (data.mStyledContent) {
|
||||
nsAtomList* IDList = aSelector->mIDList;
|
||||
if (nsnull == IDList) {
|
||||
result = localTrue;
|
||||
}
|
||||
else if (nsnull != data.mContentID) {
|
||||
result = localTrue;
|
||||
while (nsnull != IDList) {
|
||||
if (IDList->mAtom != data.mContentID) {
|
||||
result = localFalse;
|
||||
break;
|
||||
}
|
||||
IDList = IDList->mNext;
|
||||
}
|
||||
|
||||
if (PR_TRUE == result) {
|
||||
nsAtomList* classList = aSelector->mClassList;
|
||||
while (nsnull != classList) {
|
||||
if (NS_COMFALSE == data.mStyledContent->HasClass(classList->mAtom)) {
|
||||
result = PR_FALSE;
|
||||
break;
|
||||
}
|
||||
classList = classList->mNext;
|
||||
}
|
||||
|
||||
if (localTrue == result) {
|
||||
nsAtomList* classList = aSelector->mClassList;
|
||||
while (nsnull != classList) {
|
||||
if (NS_COMFALSE == data.mStyledContent->HasClass(classList->mAtom)) {
|
||||
result = localFalse;
|
||||
break;
|
||||
}
|
||||
classList = classList->mNext;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((PR_TRUE == result) &&
|
||||
(nsnull != aSelector->mPseudoClassList)) { // test for pseudo class match
|
||||
// first-child, root, lang, active, focus, hover, link, outOfDate, visited
|
||||
// XXX disabled, enabled, selected, selection
|
||||
nsAtomList* pseudoClass = aSelector->mPseudoClassList;
|
||||
}
|
||||
if ((localTrue == result) &&
|
||||
(nsnull != aSelector->mPseudoClassList)) { // test for pseudo class match
|
||||
// first-child, root, lang, active, focus, hover, link, outOfDate, visited
|
||||
// XXX disabled, enabled, selected, selection
|
||||
nsAtomList* pseudoClass = aSelector->mPseudoClassList;
|
||||
|
||||
while ((PR_TRUE == result) && (nsnull != pseudoClass)) {
|
||||
if ((nsCSSAtoms::firstChildPseudo == pseudoClass->mAtom) ||
|
||||
(nsCSSAtoms::firstNodePseudo == pseudoClass->mAtom) ) {
|
||||
nsIContent* firstChild = nsnull;
|
||||
nsIContent* parent = data.mParentContent;
|
||||
if (parent) {
|
||||
PRInt32 index = -1;
|
||||
do {
|
||||
parent->ChildAt(++index, firstChild);
|
||||
if (firstChild) { // skip text & comments (and whitespace for firstNode as well)
|
||||
if (IsSignificantChild(firstChild, (nsCSSAtoms::firstNodePseudo == pseudoClass->mAtom))) {
|
||||
break;
|
||||
}
|
||||
NS_RELEASE(firstChild);
|
||||
}
|
||||
else {
|
||||
while ((localTrue == result) && (nsnull != pseudoClass)) {
|
||||
if ((nsCSSAtoms::firstChildPseudo == pseudoClass->mAtom) ||
|
||||
(nsCSSAtoms::firstNodePseudo == pseudoClass->mAtom) ) {
|
||||
nsIContent* firstChild = nsnull;
|
||||
nsIContent* parent = data.mParentContent;
|
||||
if (parent) {
|
||||
PRInt32 index = -1;
|
||||
do {
|
||||
parent->ChildAt(++index, firstChild);
|
||||
if (firstChild) { // skip text & comments (and whitespace for firstNode as well)
|
||||
if (IsSignificantChild(firstChild, (nsCSSAtoms::firstNodePseudo == pseudoClass->mAtom))) {
|
||||
break;
|
||||
}
|
||||
} while (1 == 1);
|
||||
}
|
||||
result = PRBool(data.mContent == firstChild);
|
||||
NS_IF_RELEASE(firstChild);
|
||||
NS_RELEASE(firstChild);
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
} while (1 == 1);
|
||||
}
|
||||
else if (nsCSSAtoms::lastNodePseudo == pseudoClass->mAtom) {
|
||||
nsIContent* lastChild = nsnull;
|
||||
nsIContent* parent = data.mParentContent;
|
||||
if (parent) {
|
||||
PRInt32 index;
|
||||
parent->ChildCount(index);
|
||||
do {
|
||||
parent->ChildAt(--index, lastChild);
|
||||
if (lastChild) { // skip whitespace text & comments
|
||||
if (IsSignificantChild(lastChild, PR_TRUE)) {
|
||||
break;
|
||||
}
|
||||
NS_RELEASE(lastChild);
|
||||
}
|
||||
else {
|
||||
result = PRBool(localTrue == (data.mContent == firstChild));
|
||||
NS_IF_RELEASE(firstChild);
|
||||
}
|
||||
else if (nsCSSAtoms::lastNodePseudo == pseudoClass->mAtom) {
|
||||
nsIContent* lastChild = nsnull;
|
||||
nsIContent* parent = data.mParentContent;
|
||||
if (parent) {
|
||||
PRInt32 index;
|
||||
parent->ChildCount(index);
|
||||
do {
|
||||
parent->ChildAt(--index, lastChild);
|
||||
if (lastChild) { // skip whitespace text & comments
|
||||
if (IsSignificantChild(lastChild, PR_TRUE)) {
|
||||
break;
|
||||
}
|
||||
} while (1 == 1);
|
||||
}
|
||||
result = PRBool(data.mContent == lastChild);
|
||||
NS_IF_RELEASE(lastChild);
|
||||
NS_RELEASE(lastChild);
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
} while (1 == 1);
|
||||
}
|
||||
else if (nsCSSAtoms::rootPseudo == pseudoClass->mAtom) {
|
||||
if (data.mParentContent) {
|
||||
result = PR_FALSE;
|
||||
result = PRBool(localTrue == (data.mContent == lastChild));
|
||||
NS_IF_RELEASE(lastChild);
|
||||
}
|
||||
else if (nsCSSAtoms::rootPseudo == pseudoClass->mAtom) {
|
||||
if (data.mParentContent) {
|
||||
result = localFalse;
|
||||
}
|
||||
else {
|
||||
result = localTrue;
|
||||
}
|
||||
}
|
||||
else if (nsCSSAtoms::langPseudo == pseudoClass->mAtom) {
|
||||
// XXX not yet implemented
|
||||
result = localFalse;
|
||||
}
|
||||
else if (IsEventPseudo(pseudoClass->mAtom)) {
|
||||
// check if the element is event-sensitive
|
||||
|
||||
// Quirk Mode: check to see if the element is event-sensitive
|
||||
// - see if the selector applies to event pseudo classes
|
||||
// NOTE: we distinguish between global and subjected selectors so
|
||||
// pass that information on to the determining routine
|
||||
PRBool isSelectorGlobal = aSelector->mTag==nsnull ? PR_TRUE : PR_FALSE;
|
||||
if ((data.mIsQuirkMode) &&
|
||||
(!IsEventSensitive(pseudoClass->mAtom, data.mContentTag, isSelectorGlobal))){
|
||||
result = localFalse;
|
||||
} else if (aTestState) {
|
||||
if (nsCSSAtoms::activePseudo == pseudoClass->mAtom) {
|
||||
result = PRBool(localTrue == (0 != (data.mEventState & NS_EVENT_STATE_ACTIVE)));
|
||||
}
|
||||
else {
|
||||
result = PR_TRUE;
|
||||
else if (nsCSSAtoms::focusPseudo == pseudoClass->mAtom) {
|
||||
result = PRBool(localTrue == (0 != (data.mEventState & NS_EVENT_STATE_FOCUS)));
|
||||
}
|
||||
else if (nsCSSAtoms::hoverPseudo == pseudoClass->mAtom) {
|
||||
result = PRBool(localTrue == (0 != (data.mEventState & NS_EVENT_STATE_HOVER)));
|
||||
}
|
||||
else if (nsCSSAtoms::dragOverPseudo == pseudoClass->mAtom) {
|
||||
result = PRBool(localTrue == (0 != (data.mEventState & NS_EVENT_STATE_DRAGOVER)));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (IsLinkPseudo(pseudoClass->mAtom)) {
|
||||
if (data.mIsHTMLLink || data.mIsSimpleXLink) {
|
||||
if ((localFalse != result) && (aTestState)) {
|
||||
if (nsCSSAtoms::linkPseudo == pseudoClass->mAtom) {
|
||||
result = PRBool(localTrue == (eLinkState_Unvisited == data.mLinkState));
|
||||
}
|
||||
else if (nsCSSAtoms::outOfDatePseudo == pseudoClass->mAtom) {
|
||||
result = PRBool(localTrue == (eLinkState_OutOfDate == data.mLinkState));
|
||||
}
|
||||
else if (nsCSSAtoms::visitedPseudo == pseudoClass->mAtom) {
|
||||
result = PRBool(localTrue == (eLinkState_Visited == data.mLinkState));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (nsCSSAtoms::xblBoundElementPseudo == pseudoClass->mAtom) {
|
||||
|
@ -3106,63 +3168,22 @@ static PRBool SelectorMatches(SelectorMatchesData &data,
|
|||
if (data.mStyleRuleSupplier)
|
||||
data.mStyleRuleSupplier->MatchesScopedRoot(data.mContent, &result);
|
||||
else
|
||||
result = PR_FALSE;
|
||||
}
|
||||
else if (nsCSSAtoms::langPseudo == pseudoClass->mAtom) {
|
||||
// XXX not yet implemented
|
||||
result = PR_FALSE;
|
||||
}
|
||||
else if (IsEventPseudo(pseudoClass->mAtom)) {
|
||||
// check if the element is event-sensitive
|
||||
|
||||
// Quirk Mode: check to see if the element is event-sensitive
|
||||
// - see if the selector applies to event pseudo classes
|
||||
// NOTE: we distinguish between global and subjected selectors so
|
||||
// pass that information on to the determining routine
|
||||
PRBool isSelectorGlobal = aSelector->mTag==nsnull ? PR_TRUE : PR_FALSE;
|
||||
if ((data.mIsQuirkMode) &&
|
||||
(!IsEventSensitive(pseudoClass->mAtom, data.mContentTag, isSelectorGlobal))){
|
||||
result = PR_FALSE;
|
||||
} else if (aTestState) {
|
||||
if (nsCSSAtoms::activePseudo == pseudoClass->mAtom) {
|
||||
result = PRBool(0 != (data.mEventState & NS_EVENT_STATE_ACTIVE));
|
||||
}
|
||||
else if (nsCSSAtoms::focusPseudo == pseudoClass->mAtom) {
|
||||
result = PRBool(0 != (data.mEventState & NS_EVENT_STATE_FOCUS));
|
||||
}
|
||||
else if (nsCSSAtoms::hoverPseudo == pseudoClass->mAtom) {
|
||||
result = PRBool(0 != (data.mEventState & NS_EVENT_STATE_HOVER));
|
||||
}
|
||||
else if (nsCSSAtoms::dragOverPseudo == pseudoClass->mAtom) {
|
||||
result = PRBool(0 != (data.mEventState & NS_EVENT_STATE_DRAGOVER));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (IsLinkPseudo(pseudoClass->mAtom)) {
|
||||
if (data.mIsHTMLLink || data.mIsSimpleXLink) {
|
||||
if ((PR_FALSE != result) && (aTestState)) {
|
||||
if (nsCSSAtoms::linkPseudo == pseudoClass->mAtom) {
|
||||
result = PRBool(eLinkState_Unvisited == data.mLinkState);
|
||||
}
|
||||
else if (nsCSSAtoms::outOfDatePseudo == pseudoClass->mAtom) {
|
||||
result = PRBool(eLinkState_OutOfDate == data.mLinkState);
|
||||
}
|
||||
else if (nsCSSAtoms::visitedPseudo == pseudoClass->mAtom) {
|
||||
result = PRBool(eLinkState_Visited == data.mLinkState);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
result = PR_FALSE; // not a link
|
||||
}
|
||||
result = localFalse;
|
||||
}
|
||||
else {
|
||||
result = PR_FALSE; // unknown pseudo class
|
||||
result = localFalse; // not a link
|
||||
}
|
||||
pseudoClass = pseudoClass->mNext;
|
||||
}
|
||||
else {
|
||||
result = localFalse; // unknown pseudo class
|
||||
}
|
||||
pseudoClass = pseudoClass->mNext;
|
||||
}
|
||||
}
|
||||
// apply SelectorMatches to the negated selectors in the chain
|
||||
if ((localTrue == result) && (nsnull != aSelector->mNegations)) {
|
||||
result = SelectorMatches(data, aSelector->mNegations, aTestState, aNegationIndex+1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -3219,7 +3240,7 @@ static PRBool SelectorMatchesTree(SelectorMatchesData &data,
|
|||
nsCompatibility compat = data.mIsQuirkMode ? eCompatibility_NavQuirks : eCompatibility_Standard;
|
||||
SelectorMatchesData newdata(data.mPresContext, content, data.mParentContext,
|
||||
data.mResults, &compat);
|
||||
if (SelectorMatches(newdata, selector, PR_TRUE)) {
|
||||
if (SelectorMatches(newdata, selector, PR_TRUE, 0)) {
|
||||
// to avoid greedy matching, we need to recurse if this is a
|
||||
// descendant combinator and the next combinator is not
|
||||
if ((NS_IS_GREEDY_OPERATOR(selector->mOperator)) &&
|
||||
|
@ -3262,7 +3283,7 @@ static void ContentEnumFunc(nsICSSStyleRule* aRule, void* aData)
|
|||
ContentEnumData* data = (ContentEnumData*)aData;
|
||||
|
||||
nsCSSSelector* selector = aRule->FirstSelector();
|
||||
if (SelectorMatches(*data, selector, PR_TRUE)) {
|
||||
if (SelectorMatches(*data, selector, PR_TRUE, 0)) {
|
||||
selector = selector->mNext;
|
||||
if (SelectorMatchesTree(*data, selector)) {
|
||||
nsIStyleRule* iRule;
|
||||
|
@ -3368,7 +3389,7 @@ static void PseudoEnumFunc(nsICSSStyleRule* aRule, void* aData)
|
|||
if (PRUnichar('+') == selector->mOperator) {
|
||||
return; // not valid here, can't match
|
||||
}
|
||||
if (SelectorMatches(*data, selector, PR_TRUE)) {
|
||||
if (SelectorMatches(*data, selector, PR_TRUE, 0)) {
|
||||
selector = selector->mNext;
|
||||
}
|
||||
else {
|
||||
|
@ -3452,7 +3473,7 @@ PRBool PR_CALLBACK StateEnumFunc(void* aSelector, void* aData)
|
|||
StateEnumData* data = (StateEnumData*)aData;
|
||||
|
||||
nsCSSSelector* selector = (nsCSSSelector*)aSelector;
|
||||
if (SelectorMatches(*data, selector, PR_FALSE)) {
|
||||
if (SelectorMatches(*data, selector, PR_FALSE, 0)) {
|
||||
selector = selector->mNext;
|
||||
if (SelectorMatchesTree(*data, selector)) {
|
||||
return PR_FALSE;
|
||||
|
|
|
@ -103,7 +103,12 @@ public:
|
|||
PRInt32 CalcWeight(void) const;
|
||||
|
||||
void SizeOf(nsISizeOfHandler *aSizeOfHandler, PRUint32 &aSize);
|
||||
nsresult ToString( nsAWritableString& aString, nsICSSStyleSheet* aSheet, PRBool aIsPseudoElem ) const;
|
||||
nsresult ToString( nsAWritableString& aString, nsICSSStyleSheet* aSheet,
|
||||
PRBool aIsPseudoElem, PRInt8 aNegatedIndex ) const;
|
||||
|
||||
private:
|
||||
|
||||
void AppendNegationToString(nsAWritableString& aString);
|
||||
|
||||
public:
|
||||
PRInt32 mNameSpace;
|
||||
|
@ -113,10 +118,12 @@ public:
|
|||
nsAtomList* mPseudoClassList;
|
||||
nsAttrSelector* mAttrList;
|
||||
PRUnichar mOperator;
|
||||
nsCSSSelector* mNegations;
|
||||
|
||||
nsCSSSelector* mNext;
|
||||
};
|
||||
|
||||
|
||||
// IID for the nsICSSStyleRule interface {7c277af0-af19-11d1-8031-006008159b5a}
|
||||
#define NS_ICSS_STYLE_RULE_IID \
|
||||
{0x7c277af0, 0xaf19, 0x11d1, {0x80, 0x31, 0x00, 0x60, 0x08, 0x15, 0x9b, 0x5a}}
|
||||
|
|
Загрузка…
Ссылка в новой задаче