diff --git a/mozilla/content/html/style/src/nsCSSParser.cpp b/mozilla/content/html/style/src/nsCSSParser.cpp
index 399fdee4115..1f78dc087de 100644
--- a/mozilla/content/html/style/src/nsCSSParser.cpp
+++ b/mozilla/content/html/style/src/nsCSSParser.cpp
@@ -1855,7 +1855,10 @@ PRBool CSSParserImpl::ParseSelector(PRInt32& aErrorCode,
}
if ((eCSSToken_Symbol == mToken.mType) ||
(eCSSToken_Includes == mToken.mType) ||
- (eCSSToken_Dashmatch == mToken.mType)) {
+ (eCSSToken_Dashmatch == mToken.mType) ||
+ (eCSSToken_Beginsmatch == mToken.mType) ||
+ (eCSSToken_Endsmatch == mToken.mType) ||
+ (eCSSToken_Containsmatch == mToken.mType)) {
mToken.AppendToString(aSource);
PRUint8 func;
if (eCSSToken_Includes == mToken.mType) {
@@ -1864,6 +1867,15 @@ PRBool CSSParserImpl::ParseSelector(PRInt32& aErrorCode,
else if (eCSSToken_Dashmatch == mToken.mType) {
func = NS_ATTR_FUNC_DASHMATCH;
}
+ else if (eCSSToken_Beginsmatch == mToken.mType) {
+ func = NS_ATTR_FUNC_BEGINSMATCH;
+ }
+ else if (eCSSToken_Endsmatch == mToken.mType) {
+ func = NS_ATTR_FUNC_ENDSMATCH;
+ }
+ else if (eCSSToken_Containsmatch == mToken.mType) {
+ func = NS_ATTR_FUNC_CONTAINSMATCH;
+ }
else if (']' == mToken.mSymbol) {
dataMask |= SEL_MASK_ATTRIB;
aSelector.AddAttribute(nameSpaceID, attr);
diff --git a/mozilla/content/html/style/src/nsCSSScanner.cpp b/mozilla/content/html/style/src/nsCSSScanner.cpp
index a6130965379..db2cd4d7166 100644
--- a/mozilla/content/html/style/src/nsCSSScanner.cpp
+++ b/mozilla/content/html/style/src/nsCSSScanner.cpp
@@ -18,6 +18,7 @@
* Rights Reserved.
*
* Contributor(s):
+ * Daniel Glazman
*/
#include "nsCSSScanner.h"
#include "nsIInputStream.h"
@@ -501,10 +502,25 @@ PRBool nsCSSScanner::Next(PRInt32& aErrorCode, nsCSSToken& aToken)
}
// INCLUDES ("~=") and DASHMATCH ("|=")
- if (( ch == '|' ) || ( ch == '~')) {
+ if (( ch == '|' ) || ( ch == '~' ) || ( ch == '^' ) ||
+ ( ch == '$' ) || ( ch == '*' )) {
PRInt32 nextChar = Read(aErrorCode);
if ( nextChar == '=' ) {
- aToken.mType = (ch == '~') ? eCSSToken_Includes : eCSSToken_Dashmatch;
+ if (ch == '~') {
+ aToken.mType = eCSSToken_Includes;
+ }
+ else if (ch == '|') {
+ aToken.mType = eCSSToken_Dashmatch;
+ }
+ else if (ch == '^') {
+ aToken.mType = eCSSToken_Beginsmatch;
+ }
+ else if (ch == '$') {
+ aToken.mType = eCSSToken_Endsmatch;
+ }
+ else if (ch == '*') {
+ aToken.mType = eCSSToken_Containsmatch;
+ }
return PR_TRUE;
} else {
Pushback(nextChar);
diff --git a/mozilla/content/html/style/src/nsCSSScanner.h b/mozilla/content/html/style/src/nsCSSScanner.h
index 30af7d91403..bf5df043203 100644
--- a/mozilla/content/html/style/src/nsCSSScanner.h
+++ b/mozilla/content/html/style/src/nsCSSScanner.h
@@ -18,6 +18,7 @@
* Rights Reserved.
*
* Contributor(s):
+ * Daniel Glazman
*/
#ifndef nsCSSScanner_h___
#define nsCSSScanner_h___
@@ -67,7 +68,10 @@ enum nsCSSTokenType {
eCSSToken_HTMLComment = 12, // ""
eCSSToken_Includes = 13, // "~="
- eCSSToken_Dashmatch = 14 // "|="
+ eCSSToken_Dashmatch = 14, // "|="
+ eCSSToken_Beginsmatch = 15, // "^="
+ eCSSToken_Endsmatch = 16, // "$="
+ eCSSToken_Containsmatch = 17 // "*="
};
diff --git a/mozilla/content/html/style/src/nsCSSStyleRule.cpp b/mozilla/content/html/style/src/nsCSSStyleRule.cpp
index 468dac7cbdc..c629319d87f 100644
--- a/mozilla/content/html/style/src/nsCSSStyleRule.cpp
+++ b/mozilla/content/html/style/src/nsCSSStyleRule.cpp
@@ -732,6 +732,15 @@ nsresult nsCSSSelector::ToString( nsAWritableString& aString, nsICSSStyleSheet*
} else if (list->mFunction == NS_ATTR_FUNC_DASHMATCH) {
aString.Append(PRUnichar('|'));
aString.Append(PRUnichar('='));
+ } else if (list->mFunction == NS_ATTR_FUNC_BEGINSMATCH) {
+ aString.Append(PRUnichar('^'));
+ aString.Append(PRUnichar('='));
+ } else if (list->mFunction == NS_ATTR_FUNC_ENDSMATCH) {
+ aString.Append(PRUnichar('$'));
+ aString.Append(PRUnichar('='));
+ } else if (list->mFunction == NS_ATTR_FUNC_CONTAINSMATCH) {
+ aString.Append(PRUnichar('*'));
+ aString.Append(PRUnichar('='));
}
// Append the value
aString.Append(list->mValue);
diff --git a/mozilla/content/html/style/src/nsCSSStyleSheet.cpp b/mozilla/content/html/style/src/nsCSSStyleSheet.cpp
index 74d84555303..0835332b0fe 100644
--- a/mozilla/content/html/style/src/nsCSSStyleSheet.cpp
+++ b/mozilla/content/html/style/src/nsCSSStyleSheet.cpp
@@ -2951,7 +2951,7 @@ static PRBool SelectorMatches(SelectorMatchesData &data,
} else {
nsAttrSelector* attr = aSelector->mAttrList;
do {
- nsAutoString value;
+ 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;
@@ -2974,6 +2974,27 @@ static PRBool SelectorMatches(SelectorMatchesData &data,
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;
diff --git a/mozilla/content/html/style/src/nsICSSStyleRule.h b/mozilla/content/html/style/src/nsICSSStyleRule.h
index 0bae18801e6..6fb1b739bfc 100644
--- a/mozilla/content/html/style/src/nsICSSStyleRule.h
+++ b/mozilla/content/html/style/src/nsICSSStyleRule.h
@@ -51,6 +51,9 @@ public:
#define NS_ATTR_FUNC_EQUALS 1 // [attr=value]
#define NS_ATTR_FUNC_INCLUDES 2 // [attr~=value] (space separated)
#define NS_ATTR_FUNC_DASHMATCH 3 // [attr|=value] ('-' truncated)
+#define NS_ATTR_FUNC_BEGINSMATCH 4 // [attr^=value] (begins with)
+#define NS_ATTR_FUNC_ENDSMATCH 5 // [attr$=value] (ends with)
+#define NS_ATTR_FUNC_CONTAINSMATCH 6 // [attr*=value] (contains substring)
struct nsAttrSelector {
public:
diff --git a/mozilla/layout/style/nsCSSParser.cpp b/mozilla/layout/style/nsCSSParser.cpp
index 399fdee4115..1f78dc087de 100644
--- a/mozilla/layout/style/nsCSSParser.cpp
+++ b/mozilla/layout/style/nsCSSParser.cpp
@@ -1855,7 +1855,10 @@ PRBool CSSParserImpl::ParseSelector(PRInt32& aErrorCode,
}
if ((eCSSToken_Symbol == mToken.mType) ||
(eCSSToken_Includes == mToken.mType) ||
- (eCSSToken_Dashmatch == mToken.mType)) {
+ (eCSSToken_Dashmatch == mToken.mType) ||
+ (eCSSToken_Beginsmatch == mToken.mType) ||
+ (eCSSToken_Endsmatch == mToken.mType) ||
+ (eCSSToken_Containsmatch == mToken.mType)) {
mToken.AppendToString(aSource);
PRUint8 func;
if (eCSSToken_Includes == mToken.mType) {
@@ -1864,6 +1867,15 @@ PRBool CSSParserImpl::ParseSelector(PRInt32& aErrorCode,
else if (eCSSToken_Dashmatch == mToken.mType) {
func = NS_ATTR_FUNC_DASHMATCH;
}
+ else if (eCSSToken_Beginsmatch == mToken.mType) {
+ func = NS_ATTR_FUNC_BEGINSMATCH;
+ }
+ else if (eCSSToken_Endsmatch == mToken.mType) {
+ func = NS_ATTR_FUNC_ENDSMATCH;
+ }
+ else if (eCSSToken_Containsmatch == mToken.mType) {
+ func = NS_ATTR_FUNC_CONTAINSMATCH;
+ }
else if (']' == mToken.mSymbol) {
dataMask |= SEL_MASK_ATTRIB;
aSelector.AddAttribute(nameSpaceID, attr);
diff --git a/mozilla/layout/style/nsCSSScanner.cpp b/mozilla/layout/style/nsCSSScanner.cpp
index a6130965379..db2cd4d7166 100644
--- a/mozilla/layout/style/nsCSSScanner.cpp
+++ b/mozilla/layout/style/nsCSSScanner.cpp
@@ -18,6 +18,7 @@
* Rights Reserved.
*
* Contributor(s):
+ * Daniel Glazman
*/
#include "nsCSSScanner.h"
#include "nsIInputStream.h"
@@ -501,10 +502,25 @@ PRBool nsCSSScanner::Next(PRInt32& aErrorCode, nsCSSToken& aToken)
}
// INCLUDES ("~=") and DASHMATCH ("|=")
- if (( ch == '|' ) || ( ch == '~')) {
+ if (( ch == '|' ) || ( ch == '~' ) || ( ch == '^' ) ||
+ ( ch == '$' ) || ( ch == '*' )) {
PRInt32 nextChar = Read(aErrorCode);
if ( nextChar == '=' ) {
- aToken.mType = (ch == '~') ? eCSSToken_Includes : eCSSToken_Dashmatch;
+ if (ch == '~') {
+ aToken.mType = eCSSToken_Includes;
+ }
+ else if (ch == '|') {
+ aToken.mType = eCSSToken_Dashmatch;
+ }
+ else if (ch == '^') {
+ aToken.mType = eCSSToken_Beginsmatch;
+ }
+ else if (ch == '$') {
+ aToken.mType = eCSSToken_Endsmatch;
+ }
+ else if (ch == '*') {
+ aToken.mType = eCSSToken_Containsmatch;
+ }
return PR_TRUE;
} else {
Pushback(nextChar);
diff --git a/mozilla/layout/style/nsCSSScanner.h b/mozilla/layout/style/nsCSSScanner.h
index 30af7d91403..bf5df043203 100644
--- a/mozilla/layout/style/nsCSSScanner.h
+++ b/mozilla/layout/style/nsCSSScanner.h
@@ -18,6 +18,7 @@
* Rights Reserved.
*
* Contributor(s):
+ * Daniel Glazman
*/
#ifndef nsCSSScanner_h___
#define nsCSSScanner_h___
@@ -67,7 +68,10 @@ enum nsCSSTokenType {
eCSSToken_HTMLComment = 12, // ""
eCSSToken_Includes = 13, // "~="
- eCSSToken_Dashmatch = 14 // "|="
+ eCSSToken_Dashmatch = 14, // "|="
+ eCSSToken_Beginsmatch = 15, // "^="
+ eCSSToken_Endsmatch = 16, // "$="
+ eCSSToken_Containsmatch = 17 // "*="
};
diff --git a/mozilla/layout/style/nsCSSStyleRule.cpp b/mozilla/layout/style/nsCSSStyleRule.cpp
index 468dac7cbdc..c629319d87f 100644
--- a/mozilla/layout/style/nsCSSStyleRule.cpp
+++ b/mozilla/layout/style/nsCSSStyleRule.cpp
@@ -732,6 +732,15 @@ nsresult nsCSSSelector::ToString( nsAWritableString& aString, nsICSSStyleSheet*
} else if (list->mFunction == NS_ATTR_FUNC_DASHMATCH) {
aString.Append(PRUnichar('|'));
aString.Append(PRUnichar('='));
+ } else if (list->mFunction == NS_ATTR_FUNC_BEGINSMATCH) {
+ aString.Append(PRUnichar('^'));
+ aString.Append(PRUnichar('='));
+ } else if (list->mFunction == NS_ATTR_FUNC_ENDSMATCH) {
+ aString.Append(PRUnichar('$'));
+ aString.Append(PRUnichar('='));
+ } else if (list->mFunction == NS_ATTR_FUNC_CONTAINSMATCH) {
+ aString.Append(PRUnichar('*'));
+ aString.Append(PRUnichar('='));
}
// Append the value
aString.Append(list->mValue);
diff --git a/mozilla/layout/style/nsCSSStyleSheet.cpp b/mozilla/layout/style/nsCSSStyleSheet.cpp
index 74d84555303..0835332b0fe 100644
--- a/mozilla/layout/style/nsCSSStyleSheet.cpp
+++ b/mozilla/layout/style/nsCSSStyleSheet.cpp
@@ -2951,7 +2951,7 @@ static PRBool SelectorMatches(SelectorMatchesData &data,
} else {
nsAttrSelector* attr = aSelector->mAttrList;
do {
- nsAutoString value;
+ 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;
@@ -2974,6 +2974,27 @@ static PRBool SelectorMatches(SelectorMatchesData &data,
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;
diff --git a/mozilla/layout/style/nsICSSStyleRule.h b/mozilla/layout/style/nsICSSStyleRule.h
index 0bae18801e6..6fb1b739bfc 100644
--- a/mozilla/layout/style/nsICSSStyleRule.h
+++ b/mozilla/layout/style/nsICSSStyleRule.h
@@ -51,6 +51,9 @@ public:
#define NS_ATTR_FUNC_EQUALS 1 // [attr=value]
#define NS_ATTR_FUNC_INCLUDES 2 // [attr~=value] (space separated)
#define NS_ATTR_FUNC_DASHMATCH 3 // [attr|=value] ('-' truncated)
+#define NS_ATTR_FUNC_BEGINSMATCH 4 // [attr^=value] (begins with)
+#define NS_ATTR_FUNC_ENDSMATCH 5 // [attr$=value] (ends with)
+#define NS_ATTR_FUNC_CONTAINSMATCH 6 // [attr*=value] (contains substring)
struct nsAttrSelector {
public: