22 * License, v. 2.0. If a copy of the MPL was not distributed with this
33 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
44
5+ use dtoa;
56use std:: ascii:: AsciiExt ;
67use std:: fmt:: { self , Write } ;
8+ use std:: str;
79
810use super :: Token ;
911
@@ -41,6 +43,123 @@ pub trait ToCss {
4143 }
4244}
4345
46+ const PRECISION_FOR_F32 : usize = 6 ;
47+
48+ fn dtoa_pretty < W > ( dest : & mut W , value : f32 , has_exp : & mut bool )
49+ -> fmt:: Result where W : fmt:: Write {
50+ let mut buf = [ b'\0' ; 40 ] ;
51+ // Put a leading zero at the beginning to capture any carry.
52+ buf[ 0 ] = b'0' ;
53+ let len = dtoa:: write ( & mut buf[ 1 ..] , value) . unwrap ( ) + 1 ;
54+ let sign = match buf[ 1 ] {
55+ s @ b'+' | s @ b'-' => {
56+ buf[ 1 ] = b'0' ;
57+ Some ( s)
58+ }
59+ _ => None ,
60+ } ;
61+ // Locate dot, exp, and the first non-zero digit.
62+ let mut pos_dot = None ;
63+ let mut pos_exp = None ;
64+ let mut prec_start = None ;
65+ for i in 1 ..len {
66+ if buf[ i] == b'.' {
67+ debug_assert ! ( pos_dot. is_none( ) ) ;
68+ pos_dot = Some ( i) ;
69+ } else if buf[ i] == b'e' {
70+ pos_exp = Some ( i) ;
71+ break ;
72+ } else if prec_start. is_none ( ) && buf[ i] != b'0' {
73+ debug_assert ! ( buf[ i] >= b'1' && buf[ i] <= b'9' ) ;
74+ prec_start = Some ( i) ;
75+ }
76+ }
77+ // If there is no non-zero digit at all, it is just zero.
78+ if prec_start. is_none ( ) {
79+ return dest. write_char ( '0' ) ;
80+ }
81+ let prec_start = prec_start. unwrap ( ) ;
82+ let coeff_end = pos_exp. unwrap_or ( len) ;
83+ let pos_dot = pos_dot. unwrap_or ( coeff_end) ;
84+ // Find the end position of the number within the given precision.
85+ let prec_end = {
86+ let end = prec_start + PRECISION_FOR_F32 ;
87+ if pos_dot > prec_start && pos_dot <= end {
88+ end + 1
89+ } else {
90+ end
91+ }
92+ } ;
93+ let mut new_coeff_end = coeff_end;
94+ if prec_end < coeff_end {
95+ // Round to the given precision.
96+ let next_char = buf[ prec_end] ;
97+ new_coeff_end = prec_end;
98+ if next_char >= b'5' {
99+ for i in ( 0 ..prec_end) . rev ( ) {
100+ if buf[ i] == b'.' {
101+ continue ;
102+ }
103+ if buf[ i] != b'9' {
104+ buf[ i] += 1 ;
105+ new_coeff_end = i + 1 ;
106+ break ;
107+ }
108+ buf[ i] = b'0' ;
109+ }
110+ }
111+ }
112+ if new_coeff_end < pos_dot {
113+ // If the precision isn't enough to reach the dot, set all digits
114+ // in-between to zero and keep the number until the dot.
115+ for i in new_coeff_end..pos_dot {
116+ buf[ i] = b'0' ;
117+ }
118+ new_coeff_end = pos_dot;
119+ } else {
120+ // Strip any trailing zeros.
121+ for i in ( 0 ..new_coeff_end) . rev ( ) {
122+ if buf[ i] != b'0' {
123+ if buf[ i] == b'.' {
124+ new_coeff_end = i;
125+ }
126+ break ;
127+ }
128+ new_coeff_end = i;
129+ }
130+ }
131+ // Move exponent part if necessary.
132+ let real_end = if let Some ( pos_exp) = pos_exp {
133+ if new_coeff_end != pos_exp {
134+ for i in 0 ..len - pos_exp {
135+ buf[ new_coeff_end + i] = buf[ pos_exp + i] ;
136+ }
137+ }
138+ * has_exp = true ;
139+ new_coeff_end + ( len - pos_exp)
140+ } else {
141+ new_coeff_end
142+ } ;
143+ // Add back the sign and strip the leading zero.
144+ let result = if let Some ( sign) = sign {
145+ if buf[ 1 ] == b'0' && buf[ 2 ] != b'.' {
146+ buf[ 1 ] = sign;
147+ & buf[ 1 ..real_end]
148+ } else {
149+ debug_assert ! ( buf[ 0 ] == b'0' ) ;
150+ buf[ 0 ] = sign;
151+ & buf[ 0 ..real_end]
152+ }
153+ } else {
154+ if buf[ 1 ] == b'0' && buf[ 2 ] != b'.' {
155+ & buf[ 2 ..real_end]
156+ } else {
157+ debug_assert ! ( buf[ 0 ] == b'0' ) ;
158+ & buf[ 1 ..real_end]
159+ }
160+ } ;
161+ dest. write_str ( str:: from_utf8 ( result) . unwrap ( ) )
162+ }
44163
45164#[ inline]
46165fn write_numeric < W > ( value : f32 , int_value : Option < i32 > , has_sign : bool , dest : & mut W )
@@ -50,14 +169,15 @@ fn write_numeric<W>(value: f32, int_value: Option<i32>, has_sign: bool, dest: &m
50169 dest. write_str ( "+" ) ?;
51170 }
52171
172+ let mut has_exp = false ;
53173 if value == 0.0 && value. is_sign_negative ( ) {
54174 // Negative zero. Work around #20596.
55175 dest. write_str ( "-0" ) ?
56176 } else {
57- write ! ( dest, "{}" , value ) ?
177+ dtoa_pretty ( dest, value , & mut has_exp ) ? ;
58178 }
59179
60- if int_value. is_none ( ) && value. fract ( ) == 0. {
180+ if int_value. is_none ( ) && value. fract ( ) == 0. && !has_exp {
61181 dest. write_str ( ".0" ) ?;
62182 }
63183 Ok ( ( ) )
0 commit comments