5
5
6
6
use crate :: {
7
7
color:: { add_alpha, fixup_hues_for_interpolate, split_alpha} ,
8
- AlphaColor , ColorSpace , ColorSpaceLayout , ColorSpaceTag , HueDirection , LinearSrgb , Missing ,
8
+ AlphaColor , ColorSpace , ColorSpaceLayout , ColorSpaceTag , Flags , HueDirection , LinearSrgb ,
9
+ Missing ,
9
10
} ;
10
11
use core:: hash:: { Hash , Hasher } ;
11
12
@@ -31,8 +32,9 @@ use core::hash::{Hash, Hasher};
31
32
pub struct DynamicColor {
32
33
/// The color space.
33
34
pub cs : ColorSpaceTag ,
34
- /// A bitmask of missing components.
35
- pub missing : Missing ,
35
+ /// The state of this color, tracking whether it has missing components and how it was
36
+ /// constructed. See the documentation of [`Flags`] for more information.
37
+ pub flags : Flags ,
36
38
/// The components.
37
39
///
38
40
/// The first three components are interpreted according to the
@@ -41,6 +43,12 @@ pub struct DynamicColor {
41
43
pub components : [ f32 ; 4 ] ,
42
44
}
43
45
46
+ // `DynamicColor` was carefully packed. Ensure its size doesn't accidentally change.
47
+ #[ cfg( test) ]
48
+ const _: ( ) = if size_of :: < DynamicColor > ( ) != 20 {
49
+ panic ! ( "`DynamicColor` size changed" ) ;
50
+ } ;
51
+
44
52
/// An intermediate struct used for interpolating between colors.
45
53
///
46
54
/// This is the return value of [`DynamicColor::interpolate`].
@@ -77,7 +85,7 @@ impl DynamicColor {
77
85
if let Some ( cs) = CS :: TAG {
78
86
Self {
79
87
cs,
80
- missing : Missing :: default ( ) ,
88
+ flags : Flags :: default ( ) ,
81
89
components : color. components ,
82
90
}
83
91
} else {
@@ -97,23 +105,23 @@ impl DynamicColor {
97
105
let ( opaque, alpha) = split_alpha ( self . components ) ;
98
106
let mut components = add_alpha ( self . cs . convert ( cs, opaque) , alpha) ;
99
107
// Reference: §12.2 of Color 4 spec
100
- let missing = if !self . missing . is_empty ( ) {
108
+ let missing = if !self . flags . missing ( ) . is_empty ( ) {
101
109
if self . cs . same_analogous ( cs) {
102
110
for ( i, component) in components. iter_mut ( ) . enumerate ( ) {
103
- if self . missing . contains ( i) {
111
+ if self . flags . missing ( ) . contains ( i) {
104
112
* component = 0.0 ;
105
113
}
106
114
}
107
- self . missing
115
+ self . flags . missing ( )
108
116
} else {
109
- let mut missing = self . missing & Missing :: single ( 3 ) ;
110
- if self . cs . h_missing ( self . missing ) {
117
+ let mut missing = self . flags . missing ( ) & Missing :: single ( 3 ) ;
118
+ if self . cs . h_missing ( self . flags . missing ( ) ) {
111
119
cs. set_h_missing ( & mut missing, & mut components) ;
112
120
}
113
- if self . cs . c_missing ( self . missing ) {
121
+ if self . cs . c_missing ( self . flags . missing ( ) ) {
114
122
cs. set_c_missing ( & mut missing, & mut components) ;
115
123
}
116
- if self . cs . l_missing ( self . missing ) {
124
+ if self . cs . l_missing ( self . flags . missing ( ) ) {
117
125
cs. set_l_missing ( & mut missing, & mut components) ;
118
126
}
119
127
missing
@@ -123,7 +131,7 @@ impl DynamicColor {
123
131
} ;
124
132
let mut result = Self {
125
133
cs,
126
- missing,
134
+ flags : Flags :: from_missing ( missing) ,
127
135
components,
128
136
} ;
129
137
result. powerless_to_missing ( ) ;
@@ -137,9 +145,9 @@ impl DynamicColor {
137
145
/// a corresponding component which is 0. This method restores that
138
146
/// invariant after manipulation which might invalidate it.
139
147
fn zero_missing_components ( mut self ) -> Self {
140
- if !self . missing . is_empty ( ) {
148
+ if !self . flags . missing ( ) . is_empty ( ) {
141
149
for ( i, component) in self . components . iter_mut ( ) . enumerate ( ) {
142
- if self . missing . contains ( i) {
150
+ if self . flags . missing ( ) . contains ( i) {
143
151
* component = 0.0 ;
144
152
}
145
153
}
@@ -153,13 +161,13 @@ impl DynamicColor {
153
161
/// will be ignored and the color returned unchanged.
154
162
#[ must_use]
155
163
pub const fn multiply_alpha ( self , rhs : f32 ) -> Self {
156
- if self . missing . contains ( 3 ) {
164
+ if self . flags . missing ( ) . contains ( 3 ) {
157
165
self
158
166
} else {
159
167
let ( opaque, alpha) = split_alpha ( self . components ) ;
160
168
Self {
161
169
cs : self . cs ,
162
- missing : self . missing ,
170
+ flags : Flags :: from_missing ( self . flags . missing ( ) ) ,
163
171
components : add_alpha ( opaque, alpha * rhs) ,
164
172
}
165
173
}
@@ -181,13 +189,13 @@ impl DynamicColor {
181
189
/// ```
182
190
#[ must_use]
183
191
pub const fn with_alpha ( self , alpha : f32 ) -> Self {
184
- if self . missing . contains ( 3 ) {
192
+ if self . flags . missing ( ) . contains ( 3 ) {
185
193
self
186
194
} else {
187
195
let ( opaque, _alpha) = split_alpha ( self . components ) ;
188
196
Self {
189
197
cs : self . cs ,
190
- missing : self . missing ,
198
+ flags : Flags :: from_missing ( self . flags . missing ( ) ) ,
191
199
components : add_alpha ( opaque, alpha) ,
192
200
}
193
201
}
@@ -200,9 +208,12 @@ impl DynamicColor {
200
208
pub fn scale_chroma ( self , scale : f32 ) -> Self {
201
209
let ( opaque, alpha) = split_alpha ( self . components ) ;
202
210
let components = self . cs . scale_chroma ( opaque, scale) ;
211
+
212
+ let mut flags = self . flags ;
213
+ flags. discard_name ( ) ;
203
214
Self {
204
215
cs : self . cs ,
205
- missing : self . missing ,
216
+ flags ,
206
217
components : add_alpha ( components, alpha) ,
207
218
}
208
219
. zero_missing_components ( )
@@ -219,15 +230,15 @@ impl DynamicColor {
219
230
let alpha = alpha. clamp ( 0. , 1. ) ;
220
231
Self {
221
232
cs : self . cs ,
222
- missing : self . missing ,
233
+ flags : self . flags ,
223
234
components : add_alpha ( components, alpha) ,
224
235
}
225
236
}
226
237
227
238
fn premultiply_split ( self ) -> ( [ f32 ; 3 ] , f32 ) {
228
239
// Reference: §12.3 of Color 4 spec
229
240
let ( opaque, alpha) = split_alpha ( self . components ) ;
230
- let premul = if alpha == 1.0 || self . missing . contains ( 3 ) {
241
+ let premul = if alpha == 1.0 || self . flags . missing ( ) . contains ( 3 ) {
231
242
opaque
232
243
} else {
233
244
self . cs . layout ( ) . scale ( opaque, alpha)
@@ -243,8 +254,9 @@ impl DynamicColor {
243
254
if self . cs . layout ( ) != ColorSpaceLayout :: Rectangular
244
255
&& self . components [ 1 ] < POWERLESS_EPSILON
245
256
{
246
- self . cs
247
- . set_h_missing ( & mut self . missing , & mut self . components ) ;
257
+ let mut missing = self . flags . missing ( ) ;
258
+ self . cs . set_h_missing ( & mut missing, & mut self . components ) ;
259
+ self . flags . set_missing ( missing) ;
248
260
}
249
261
}
250
262
@@ -262,12 +274,14 @@ impl DynamicColor {
262
274
) -> Interpolator {
263
275
let mut a = self . convert ( cs) ;
264
276
let mut b = other. convert ( cs) ;
265
- let missing = a. missing & b. missing ;
266
- if self . missing != other. missing {
277
+ let a_missing = a. flags . missing ( ) ;
278
+ let b_missing = b. flags . missing ( ) ;
279
+ let missing = a_missing & b_missing;
280
+ if a_missing != b_missing {
267
281
for i in 0 ..4 {
268
- if ( a . missing & !b . missing ) . contains ( i) {
282
+ if ( a_missing & !b_missing ) . contains ( i) {
269
283
a. components [ i] = b. components [ i] ;
270
- } else if ( !a . missing & b . missing ) . contains ( i) {
284
+ } else if ( !a_missing & b_missing ) . contains ( i) {
271
285
b. components [ i] = a. components [ i] ;
272
286
}
273
287
}
@@ -310,9 +324,12 @@ impl DynamicColor {
310
324
#[ must_use]
311
325
pub fn map ( self , f : impl Fn ( f32 , f32 , f32 , f32 ) -> [ f32 ; 4 ] ) -> Self {
312
326
let [ x, y, z, a] = self . components ;
327
+
328
+ let mut flags = self . flags ;
329
+ flags. discard_name ( ) ;
313
330
Self {
314
331
cs : self . cs ,
315
- missing : self . missing ,
332
+ flags ,
316
333
components : f ( x, y, z, a) ,
317
334
}
318
335
. zero_missing_components ( )
@@ -371,7 +388,7 @@ impl Hash for DynamicColor {
371
388
/// match behavior for Rust float types.
372
389
fn hash < H : Hasher > ( & self , state : & mut H ) {
373
390
self . cs . hash ( state) ;
374
- self . missing . hash ( state) ;
391
+ self . flags . hash ( state) ;
375
392
for c in self . components {
376
393
c. to_bits ( ) . hash ( state) ;
377
394
}
@@ -382,7 +399,7 @@ impl PartialEq for DynamicColor {
382
399
/// Equality is determined based on the bit representation.
383
400
fn eq ( & self , other : & Self ) -> bool {
384
401
self . cs == other. cs
385
- && self . missing == other. missing
402
+ && self . flags == other. flags
386
403
&& self . components [ 0 ] . to_bits ( ) == other. components [ 0 ] . to_bits ( )
387
404
&& self . components [ 1 ] . to_bits ( ) == other. components [ 1 ] . to_bits ( )
388
405
&& self . components [ 2 ] . to_bits ( ) == other. components [ 2 ] . to_bits ( )
@@ -410,7 +427,7 @@ impl Interpolator {
410
427
let components = add_alpha ( opaque, alpha) ;
411
428
DynamicColor {
412
429
cs : self . cs ,
413
- missing : self . missing ,
430
+ flags : Flags :: from_missing ( self . missing ) ,
414
431
components,
415
432
}
416
433
}
@@ -424,15 +441,15 @@ mod tests {
424
441
fn missing_alpha ( ) {
425
442
let c = parse_color ( "oklab(0.5 0.2 0 / none)" ) . unwrap ( ) ;
426
443
assert_eq ! ( 0. , c. components[ 3 ] ) ;
427
- assert_eq ! ( Missing :: single( 3 ) , c. missing) ;
444
+ assert_eq ! ( Missing :: single( 3 ) , c. flags . missing( ) ) ;
428
445
429
446
// Alpha is missing, so we shouldn't be able to get an alpha added.
430
447
let c2 = c. with_alpha ( 0.5 ) ;
431
448
assert_eq ! ( 0. , c2. components[ 3 ] ) ;
432
- assert_eq ! ( Missing :: single( 3 ) , c2. missing) ;
449
+ assert_eq ! ( Missing :: single( 3 ) , c2. flags . missing( ) ) ;
433
450
434
451
let c3 = c. multiply_alpha ( 0.2 ) ;
435
452
assert_eq ! ( 0. , c3. components[ 3 ] ) ;
436
- assert_eq ! ( Missing :: single( 3 ) , c3. missing) ;
453
+ assert_eq ! ( Missing :: single( 3 ) , c3. flags . missing( ) ) ;
437
454
}
438
455
}
0 commit comments