diff --git a/layout/style/nsCSSScanner.cpp b/layout/style/nsCSSScanner.cpp index d157e91a605..5b8e4228a01 100644 --- a/layout/style/nsCSSScanner.cpp +++ b/layout/style/nsCSSScanner.cpp @@ -75,13 +75,16 @@ static const PRUint8 IS_HEX_DIGIT = 0x01; static const PRUint8 START_IDENT = 0x02; static const PRUint8 IS_IDENT = 0x04; static const PRUint8 IS_WHITESPACE = 0x08; +static const PRUint8 IS_URL_CHAR = 0x10; -#define W IS_WHITESPACE -#define I IS_IDENT -#define S START_IDENT -#define SI IS_IDENT|START_IDENT -#define XI IS_IDENT |IS_HEX_DIGIT -#define XSI IS_IDENT|START_IDENT|IS_HEX_DIGIT +#define W IS_WHITESPACE +#define I IS_IDENT +#define U IS_URL_CHAR +#define S START_IDENT +#define UI IS_IDENT |IS_URL_CHAR +#define USI IS_IDENT|START_IDENT |IS_URL_CHAR +#define UXI IS_IDENT |IS_HEX_DIGIT|IS_URL_CHAR +#define UXSI IS_IDENT|START_IDENT|IS_HEX_DIGIT|IS_URL_CHAR static const PRUint8 gLexTable[] = { // TAB LF FF CR @@ -89,33 +92,33 @@ static const PRUint8 gLexTable[] = { // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // SPC ! " # $ % & ' ( ) * + , - . / - W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, I, 0, 0, + W, U, 0, U, U, U, U, 0, 0, 0, U, U, U, UI, U, U, // 0 1 2 3 4 5 6 7 8 9 : ; < = > ? - XI, XI, XI, XI, XI, XI, XI, XI, XI, XI, 0, 0, 0, 0, 0, 0, -// @ A B C D E F G H I J K L M N O - 0, XSI,XSI,XSI,XSI,XSI,XSI,SI, SI, SI, SI, SI, SI, SI, SI, SI, + UXI,UXI,UXI,UXI,UXI,UXI,UXI,UXI,UXI,UXI,U, U, U, U, U, U, +// @ A B C D E F G H I J K L M N O + U,UXSI,UXSI,UXSI,UXSI,UXSI,UXSI,USI,USI,USI,USI,USI,USI,USI,USI,USI, // P Q R S T U V W X Y Z [ \ ] ^ _ - SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, 0, S, 0, 0, SI, -// ` a b c d e f g h i j k l m n o - 0, XSI,XSI,XSI,XSI,XSI,XSI,SI, SI, SI, SI, SI, SI, SI, SI, SI, + USI,USI,USI,USI,USI,USI,USI,USI,USI,USI,USI,U, S, U, U, USI, +// ` a b c d e f g h i j k l m n o + U,UXSI,UXSI,UXSI,UXSI,UXSI,UXSI,USI,USI,USI,USI,USI,USI,USI,USI,USI, // p q r s t u v w x y z { | } ~ - SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, 0, 0, 0, 0, 0, + USI,USI,USI,USI,USI,USI,USI,USI,USI,USI,USI,U, U, U, U, 0, // U+008* 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // U+009* 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // U+00A* - SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, + USI,USI,USI,USI,USI,USI,USI,USI,USI,USI,USI,USI,USI,USI,USI,USI, // U+00B* - SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, + USI,USI,USI,USI,USI,USI,USI,USI,USI,USI,USI,USI,USI,USI,USI,USI, // U+00C* - SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, + USI,USI,USI,USI,USI,USI,USI,USI,USI,USI,USI,USI,USI,USI,USI,USI, // U+00D* - SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, + USI,USI,USI,USI,USI,USI,USI,USI,USI,USI,USI,USI,USI,USI,USI,USI, // U+00E* - SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, + USI,USI,USI,USI,USI,USI,USI,USI,USI,USI,USI,USI,USI,USI,USI,USI, // U+00F* - SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, + USI,USI,USI,USI,USI,USI,USI,USI,USI,USI,USI,USI,USI,USI,USI,USI }; MOZ_STATIC_ASSERT(NS_ARRAY_LENGTH(gLexTable) == 256, @@ -124,9 +127,11 @@ MOZ_STATIC_ASSERT(NS_ARRAY_LENGTH(gLexTable) == 256, #undef W #undef S #undef I -#undef XI -#undef SI -#undef XSI +#undef U +#undef UI +#undef USI +#undef UXI +#undef UXSI static inline bool IsIdentStart(PRInt32 aChar) @@ -162,6 +167,11 @@ IsIdent(PRInt32 ch) { return ch >= 0 && (ch >= 256 || (gLexTable[ch] & IS_IDENT) != 0); } +static inline bool +IsURLChar(PRInt32 ch) { + return ch >= 0 && (ch >= 256 || (gLexTable[ch] & IS_URL_CHAR) != 0); +} + static inline PRUint32 DecimalDigitValue(PRInt32 ch) { @@ -887,37 +897,38 @@ nsCSSScanner::NextURL(nsCSSToken& aToken) nsString& ident = aToken.mIdent; ident.SetLength(0); - Pushback(ch); - // start of a non-quoted url (which may be empty) bool ok = true; for (;;) { - ch = Read(); - if (ch < 0) break; - if (ch == '\\') { - if (!ParseAndAppendEscape(ident, false)) { - ok = false; - Pushback(ch); - break; - } + if (IsURLChar(ch)) { + // A regular url character. + ident.Append(PRUnichar(ch)); + } else if (ch == ')') { + // All done + break; } else if (IsWhitespace(ch)) { // Whitespace is allowed at the end of the URL EatWhiteSpace(); // Consume the close paren if we have it; if not we're an invalid URL. ok = LookAheadOrEOF(')'); break; - } else if (ch == '"' || ch == '\'' || ch == '(' || ch < PRUnichar(' ')) { + } else if (ch == '\\') { + if (!ParseAndAppendEscape(ident, false)) { + ok = false; + Pushback(ch); + break; + } + } else { // This is an invalid URL spec ok = false; Pushback(ch); // push it back so the parser can match tokens and // then closing parenthesis break; - } else if (ch == ')') { - // All done + } + + ch = Read(); + if (ch < 0) { break; - } else { - // A regular url character. - ident.Append(PRUnichar(ch)); } } diff --git a/layout/style/test/test_parse_url.html b/layout/style/test/test_parse_url.html index 6b64e131f23..bb4ddd7f805 100644 --- a/layout/style/test/test_parse_url.html +++ b/layout/style/test/test_parse_url.html @@ -153,7 +153,10 @@ is(div.style.listStyleImage, 'url("bad")', "unquoted URL with spaces not allowed"); var chars = [ 1, 2, 3, 4, 5, 6, 7, 8, 11, 14, 15, 16, 17, 18, 19, 20, - 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 ]; + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 127, 128, 129, + 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, + 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, + 154, 155, 156, 157, 158, 159]; for (var i in chars) { var charcode = chars[i]; @@ -162,6 +165,9 @@ for (var i in chars) { "unquoted URL with control character " + charcode + " not allowed"); } +div.style.listStyleImage = 'url(\u00ff)'; +is(div.style.listStyleImage, 'url("\u00ff")', "U+A0-U+FF allowed in unquoted URL"); + div.style.listStyleImage = 'url(\\f good)'; is(div.style.listStyleImage, 'url("\\F good")', "URL allowed"); div.style.listStyleImage = 'url( \\f good)';