44
55//! Generic types for color properties.
66
7+ use crate :: color:: ColorMixItemList ;
78use crate :: color:: { mix:: ColorInterpolationMethod , AbsoluteColor , ColorFunction } ;
89use crate :: derives:: * ;
910use crate :: values:: {
1011 computed:: ToComputedValue , specified:: percentage:: ToPercentage , ParseError , Parser ,
1112} ;
1213use std:: fmt:: { self , Write } ;
13- use style_traits:: { CssWriter , ToCss } ;
14+ use style_traits:: { owned_slice :: OwnedSlice , CssWriter , ToCss } ;
1415
1516/// This struct represents a combined color from a numeric color and
1617/// the current foreground color (currentcolor keyword).
@@ -78,8 +79,7 @@ pub struct GenericColorMixItem<Color, Percentage> {
7879#[ repr( C ) ]
7980pub struct GenericColorMix < Color , Percentage > {
8081 pub interpolation : ColorInterpolationMethod ,
81- pub left : GenericColorMixItem < Color , Percentage > ,
82- pub right : GenericColorMixItem < Color , Percentage > ,
82+ pub items : OwnedSlice < GenericColorMixItem < Color , Percentage > > ,
8383 pub flags : ColorMixFlags ,
8484}
8585
@@ -90,23 +90,6 @@ impl<Color: ToCss, Percentage: ToCss + ToPercentage> ToCss for ColorMix<Color, P
9090 where
9191 W : Write ,
9292 {
93- fn can_omit < Percentage : ToPercentage > (
94- a : & Percentage ,
95- b : & Percentage ,
96- is_left : bool ,
97- ) -> bool {
98- if a. is_calc ( ) {
99- return false ;
100- }
101- if a. to_percentage ( ) == 0.5 {
102- return b. to_percentage ( ) == 0.5 ;
103- }
104- if is_left {
105- return false ;
106- }
107- ( 1.0 - a. to_percentage ( ) - b. to_percentage ( ) ) . abs ( ) <= f32:: EPSILON
108- }
109-
11093 dest. write_str ( "color-mix(" ) ?;
11194
11295 // If the color interpolation method is oklab (which is now the default),
@@ -117,18 +100,51 @@ impl<Color: ToCss, Percentage: ToCss + ToPercentage> ToCss for ColorMix<Color, P
117100 dest. write_str ( ", " ) ?;
118101 }
119102
120- self . left . color . to_css ( dest) ?;
121- if !can_omit ( & self . left . percentage , & self . right . percentage , true ) {
122- dest. write_char ( ' ' ) ?;
123- self . left . percentage . to_css ( dest) ?;
124- }
103+ let uniform = self
104+ . items
105+ . split_first ( )
106+ . map ( |( first, rest) | {
107+ rest. iter ( )
108+ . all ( |item| item. percentage . to_percentage ( ) == first. percentage . to_percentage ( ) )
109+ } )
110+ . unwrap_or ( false ) ;
111+ let uniform_value = 1.0 / self . items . len ( ) as f32 ;
112+
113+ let is_pair = self . items . len ( ) == 2 ;
125114
126- dest. write_str ( ", " ) ?;
115+ for ( index, item) in self . items . iter ( ) . enumerate ( ) {
116+ if index != 0 {
117+ dest. write_str ( ", " ) ?;
118+ }
119+
120+ item. color . to_css ( dest) ?;
121+
122+ let omit = if is_pair {
123+ let can_omit = |a : & Percentage , b : & Percentage , is_left| {
124+ if a. is_calc ( ) {
125+ return false ;
126+ }
127+ if a. to_percentage ( ) == 0.5 {
128+ return b. to_percentage ( ) == 0.5 ;
129+ }
130+ if is_left {
131+ return false ;
132+ }
133+ ( 1.0 - a. to_percentage ( ) - b. to_percentage ( ) ) . abs ( ) <= f32:: EPSILON
134+ } ;
135+
136+ let other = & self . items [ 1 - index] . percentage ;
137+ can_omit ( & item. percentage , other, index == 0 )
138+ } else {
139+ !item. percentage . is_calc ( )
140+ && uniform
141+ && item. percentage . to_percentage ( ) == uniform_value
142+ } ;
127143
128- self . right . color . to_css ( dest ) ? ;
129- if ! can_omit ( & self . right . percentage , & self . left . percentage , false ) {
130- dest . write_char ( ' ' ) ?;
131- self . right . percentage . to_css ( dest ) ? ;
144+ if !omit {
145+ dest . write_char ( ' ' ) ? ;
146+ item . percentage . to_css ( dest ) ?;
147+ }
132148 }
133149
134150 dest. write_char ( ')' )
@@ -144,17 +160,15 @@ impl<Percentage> ColorMix<GenericColor<Percentage>, Percentage> {
144160 {
145161 use crate :: color:: mix;
146162
147- let left = self . left . color . as_absolute ( ) ?;
148- let right = self . right . color . as_absolute ( ) ?;
149-
150- Some ( mix:: mix_many (
151- self . interpolation ,
152- [
153- mix:: ColorMixItem :: new ( * left, self . left . percentage . to_percentage ( ) ) ,
154- mix:: ColorMixItem :: new ( * right, self . right . percentage . to_percentage ( ) ) ,
155- ] ,
156- self . flags ,
157- ) )
163+ let mut items = ColorMixItemList :: with_capacity ( self . items . len ( ) ) ;
164+ for item in self . items . iter ( ) {
165+ items. push ( mix:: ColorMixItem :: new (
166+ * item. color . as_absolute ( ) ?,
167+ item. percentage . to_percentage ( ) ,
168+ ) )
169+ }
170+
171+ Some ( mix:: mix_many ( self . interpolation , items, self . flags ) )
158172 }
159173}
160174
0 commit comments