@@ -20,7 +20,13 @@ impl ast::ComponentValue {
2020 css. push_char ( '@' ) ;
2121 serialize_identifier ( value. as_slice ( ) , css) ;
2222 } ,
23- Hash ( ref value) | IDHash ( ref value) => {
23+ Hash ( ref value) => {
24+ css. push_char ( '#' ) ;
25+ for c in value. iter ( ) {
26+ serialize_char ( c, css, /* is_identifier_start = */ false ) ;
27+ }
28+ } ,
29+ IDHash ( ref value) => {
2430 css. push_char ( '#' ) ;
2531 serialize_identifier ( value. as_slice ( ) , css) ;
2632 }
@@ -39,7 +45,16 @@ impl ast::ComponentValue {
3945 } ,
4046 Dimension ( ref value, ref unit) => {
4147 css. push_str ( value. representation ) ;
42- serialize_identifier ( unit. as_slice ( ) , css) ;
48+ // Disambiguate with scientific notation.
49+ let unit = unit. as_slice ( ) ;
50+ if unit == "e" || unit == "E" || unit. starts_with ( "e-" ) || unit. starts_with ( "E-" ) {
51+ css. push_str ( "\\ 65 " ) ;
52+ for c in unit. slice_from ( 1 ) . iter ( ) {
53+ serialize_char ( c, css, /* is_identifier_start = */ false ) ;
54+ }
55+ } else {
56+ serialize_identifier ( unit, css)
57+ }
4358 } ,
4459
4560 UnicodeRange ( start, end) => {
@@ -104,32 +119,34 @@ pub fn serialize_identifier(value: &str, css: &mut ~str) {
104119 Some ( c) => { css. push_char ( '-' ) ; c } ,
105120 }
106121 } ;
107- serialize_char ( c, css, /* is_start = */ true ) ;
122+ serialize_char ( c, css, /* is_identifier_start = */ true ) ;
108123 for c in iter {
109- serialize_char ( c, css, /* is_start = */ false ) ;
124+ serialize_char ( c, css, /* is_identifier_start = */ false ) ;
110125 }
126+ }
111127
112- # [ inline ]
113- fn serialize_char ( c : char , css : & mut ~ str , is_start : bool ) {
114- match c {
115- '0' .. '9' if is_start => css . push_str ( format ! ( " \\ \\ 3{} " , c ) ) ,
116- '-' if is_start => css. push_str ( "\\ -" ) ,
117- '0' .. '9' | 'A' .. 'Z' | 'a' .. 'z' | '_' | '-' => css. push_char ( c ) ,
118- _ if c > '\x7F ' => css. push_char ( c) ,
119- '\n ' => css. push_str ( " \\ A " ) ,
120- '\r ' => css. push_str ( "\\ D " ) ,
121- '\x0C ' => css. push_str ( "\\ C " ) ,
122- _ => { css. push_char ( '\\' ) ; css . push_char ( c ) } ,
123- }
128+
129+ # [ inline ]
130+ fn serialize_char ( c : char , css : & mut ~ str , is_identifier_start : bool ) {
131+ match c {
132+ '0' .. '9' if is_identifier_start => css. push_str ( format ! ( "\\ \\ 3{} " , c ) ) ,
133+ '-' if is_identifier_start => css. push_str ( " \\ -" ) ,
134+ '0' .. '9' | 'A' .. 'Z' | 'a' .. 'z' | '_' | '- ' => css. push_char ( c) ,
135+ _ if c > '\x7F ' => css. push_char ( c ) ,
136+ '\n ' => css. push_str ( "\\ A " ) ,
137+ '\r ' => css. push_str ( "\\ D " ) ,
138+ '\x0C' => css. push_str ( " \\ C " ) ,
139+ _ => { css . push_char ( '\\' ) ; css . push_char ( c ) } ,
124140 }
125141}
126142
143+
127144pub fn serialize_string ( value : & str , css : & mut ~str ) {
128145 css. push_char ( '"' ) ;
129146 // TODO: avoid decoding/re-encoding UTF-8?
130147 for c in value. iter ( ) {
131148 match c {
132- '"' => css. push_str ( "\" " ) ,
149+ '"' => css. push_str ( "\\ \ " " ) ,
133150 '\\' => css. push_str ( "\\ \\ " ) ,
134151 '\n' => css. push_str ( "\\ A " ) ,
135152 '\r' => css. push_str ( "\\ D " ) ,
@@ -163,44 +180,52 @@ impl<'self, I: Iterator<&'self ComponentValue>> ToCss for I {
163180 match $value { $( $pattern) |+ => true , _ => false }
164181 ) ;
165182 )
183+ // This does not borrow-check: for component_value in self {
166184 loop { match self . next ( ) { None => break , Some ( component_value) => {
167- let ( _a, _b) = ( previous, component_value) ;
168- // FIXME: this is incorrect.
169- // See https://github.com/mozilla-servo/rust-cssparser/issues/24
170- // if (
171- // matches!(*a, Hash(*) | IDHash(*) | AtKeyword(*)) &&
172- // matches!(*b, Number(*) | Percentage(*) | Ident(*) | Dimension(*) |
173- // UnicodeRange(*) | URL(*) | Function(*))
174- // ) || (
175- // matches!(*a, Number(*) | Ident(*) | Dimension(*)) &&
176- // matches!(*b, Number(*) | Ident(*) | Dimension(*))
177- // ) || (
178- // matches!(*a, Number(*) | Ident(*) | Dimension(*)) &&
179- // matches!(*b, Percentage(*) | UnicodeRange(*) | URL(*) | Function(*))
180- // ) || (
181- // matches!(*a, Ident(*)) &&
182- // matches!(*b, ParenthesisBlock(*))
183- // ) || (
184- // matches!(*a, Delim('#') | Delim('@')) &&
185- // !matches!(*b, WhiteSpace)
186- // ) || (
187- // matches!(*a, Delim('-') | Delim('+') | Delim('.') | Delim('<') |
188- // Delim('>') | Delim('!')) &&
189- // !matches!(*b, WhiteSpace)
190- // ) || (
191- // !matches!(*a, WhiteSpace) &&
192- // matches!(*b, Delim('-') | Delim('+') | Delim('.') | Delim('<') |
193- // Delim('>') | Delim('!'))
194- // ) || (
195- // matches!(*a, Delim('/')) &&
196- // matches!(*b, Delim('*'))
197- // ) || (
198- // matches!(*a, Delim('*')) &&
199- // matches!(*b, Delim('/'))
200- // ) {
201- // css.push_str("/**/")
202- // }
203- component_value. to_css_push ( css) ;
185+ let ( a, b) = ( previous, component_value) ;
186+ if (
187+ matches ! ( * a, Ident ( * ) | AtKeyword ( * ) | Hash ( * ) | IDHash ( * ) |
188+ Dimension ( * ) | Delim ( '#' ) | Delim ( '-' ) | Number ( * ) ) &&
189+ matches ! ( * b, Ident ( * ) | Function ( * ) | URL ( * ) | BadURL ( * ) |
190+ Number ( * ) | Percentage ( * ) | Dimension ( * ) | UnicodeRange ( * ) )
191+ ) || (
192+ matches ! ( * a, Ident ( * ) ) &&
193+ matches ! ( * b, ParenthesisBlock ( * ) )
194+ ) || (
195+ matches ! ( * a, Ident ( * ) | AtKeyword ( * ) | Hash ( * ) | IDHash ( * ) | Dimension ( * ) ) &&
196+ matches ! ( * b, Delim ( '-' ) | CDC )
197+ ) || (
198+ matches ! ( * a, Delim ( '#' ) | Delim ( '-' ) | Number ( * ) | Delim ( '@' ) ) &&
199+ matches ! ( * b, Ident ( * ) | Function ( * ) | URL ( * ) | BadURL ( * ) )
200+ ) || (
201+ matches ! ( * a, Delim ( '@' ) ) &&
202+ matches ! ( * b, Ident ( * ) | Function ( * ) | URL ( * ) | BadURL ( * ) |
203+ UnicodeRange ( * ) | Delim ( '-' ) )
204+ ) || (
205+ matches ! ( * a, UnicodeRange ( * ) | Delim ( '.' ) | Delim ( '+' ) ) &&
206+ matches ! ( * b, Number ( * ) | Percentage ( * ) | Dimension ( * ) )
207+ ) || (
208+ matches ! ( * a, UnicodeRange ( * ) ) &&
209+ matches ! ( * b, Ident ( * ) | Function ( * ) | Delim ( '?' ) )
210+ ) || ( match ( a, b) { ( & Delim ( a) , & Delim ( b) ) => matches ! ( ( a, b) ,
211+ ( '#' , '-' ) |
212+ ( '$' , '=' ) |
213+ ( '*' , '=' ) |
214+ ( '^' , '=' ) |
215+ ( '~' , '=' ) |
216+ ( '|' , '=' ) |
217+ ( '|' , '|' ) |
218+ ( '/' , '*' )
219+ ) , _ => false } ) {
220+ css. push_str ( "/**/" )
221+ }
222+ // Skip whitespace when '\n' was previously written at the previous iteration.
223+ if !matches ! ( ( previous, component_value) , ( & Delim ( '\\' ) , & WhiteSpace ) ) {
224+ component_value. to_css_push ( css) ;
225+ }
226+ if component_value == & Delim ( '\\' ) {
227+ css. push_char ( '\n' ) ;
228+ }
204229 previous = component_value;
205230 } } }
206231 }
0 commit comments