Skip to content

Commit cb69f33

Browse files
committed
Preserve image-set() fallback when needed
Fixes parcel-bundler#252
1 parent 41dfaa4 commit cb69f33

File tree

9 files changed

+175
-5
lines changed

9 files changed

+175
-5
lines changed

scripts/build-prefixes.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,8 @@ let mdnFeatures = {
245245
return [key, {version_added: false}];
246246
}
247247
})
248-
)
248+
),
249+
imageSet: mdn.css.types.image['image-set'].__compat.support
249250
};
250251

251252
for (let feature in mdnFeatures) {

src/compat.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ pub enum Feature {
4141
FontFamilySystemUi,
4242
FormValidation,
4343
Fullscreen,
44+
ImageSet,
4445
LabColors,
4546
LangList,
4647
LogicalBorderRadius,
@@ -2131,6 +2132,51 @@ impl Feature {
21312132
return false;
21322133
}
21332134
}
2135+
Feature::ImageSet => {
2136+
if let Some(version) = browsers.chrome {
2137+
if version < 1638400 {
2138+
return false;
2139+
}
2140+
}
2141+
if let Some(version) = browsers.edge {
2142+
if version < 5177344 {
2143+
return false;
2144+
}
2145+
}
2146+
if let Some(version) = browsers.firefox {
2147+
if version < 5767168 {
2148+
return false;
2149+
}
2150+
}
2151+
if let Some(version) = browsers.opera {
2152+
if version < 917504 {
2153+
return false;
2154+
}
2155+
}
2156+
if let Some(version) = browsers.safari {
2157+
if version < 393216 {
2158+
return false;
2159+
}
2160+
}
2161+
if let Some(version) = browsers.ios_saf {
2162+
if version < 393216 {
2163+
return false;
2164+
}
2165+
}
2166+
if let Some(version) = browsers.samsung {
2167+
if version < 66816 {
2168+
return false;
2169+
}
2170+
}
2171+
if let Some(version) = browsers.android {
2172+
if version < 263168 {
2173+
return false;
2174+
}
2175+
}
2176+
if browsers.ie.is_some() {
2177+
return false;
2178+
}
2179+
}
21342180
Feature::P3Colors | Feature::LangList => {
21352181
if let Some(version) = browsers.safari {
21362182
if version < 655616 {

src/lib.rs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12225,6 +12225,70 @@ mod tests {
1222512225
..Browsers::default()
1222612226
},
1222712227
);
12228+
12229+
for property in &[
12230+
"background",
12231+
"background-image",
12232+
"border-image-source",
12233+
"border-image",
12234+
"border-image-source",
12235+
"-webkit-mask-image",
12236+
"-webkit-mask",
12237+
"list-style-image",
12238+
"list-style",
12239+
] {
12240+
prefix_test(
12241+
&format!(
12242+
r#"
12243+
.foo {{
12244+
{}: url(foo.png);
12245+
{}: image-set(url("foo.png") 2x, url(bar.png) 1x);
12246+
}}
12247+
"#,
12248+
property, property
12249+
),
12250+
&format!(
12251+
indoc! {r#"
12252+
.foo {{
12253+
{}: url("foo.png");
12254+
{}: -webkit-image-set(url("foo.png") 2x, url("bar.png"));
12255+
{}: image-set("foo.png" 2x, "bar.png");
12256+
}}
12257+
"#},
12258+
property, property, property
12259+
),
12260+
Browsers {
12261+
ie: Some(11 << 16),
12262+
chrome: Some(95 << 16),
12263+
..Browsers::default()
12264+
},
12265+
);
12266+
12267+
prefix_test(
12268+
&format!(
12269+
r#"
12270+
.foo {{
12271+
{}: url(foo.png);
12272+
{}: image-set(url("foo.png") 2x, url(bar.png) 1x);
12273+
}}
12274+
"#,
12275+
property, property
12276+
),
12277+
&format!(
12278+
indoc! {r#"
12279+
.foo {{
12280+
{}: -webkit-image-set(url("foo.png") 2x, url("bar.png"));
12281+
{}: image-set("foo.png" 2x, "bar.png");
12282+
}}
12283+
"#},
12284+
property, property
12285+
),
12286+
Browsers {
12287+
chrome: Some(95 << 16),
12288+
..Browsers::default()
12289+
},
12290+
);
12291+
}
1222812292
}
1222912293

1223012294
#[test]

src/macros.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ pub(crate) use shorthand_property;
210210
macro_rules! shorthand_handler {
211211
(
212212
$name: ident -> $shorthand: ident$(<$l: lifetime>)? $(fallbacks: $shorthand_fallback: literal)?
213-
{ $( $key: ident: $prop: ident($type: ty $(, fallback: $fallback: literal)?), )+ }
213+
{ $( $key: ident: $prop: ident($type: ty $(, fallback: $fallback: literal)? $(, image: $image: literal)?), )+ }
214214
) => {
215215
#[derive(Default)]
216216
pub(crate) struct $name$(<$l>)? {
@@ -237,12 +237,23 @@ macro_rules! shorthand_handler {
237237
match property {
238238
$(
239239
Property::$prop(val) => {
240+
$(
241+
if $image && val.should_preserve_fallback(&self.$key, self.targets) {
242+
self.finalize(dest, context);
243+
}
244+
)?
240245
self.$key = Some(val.clone());
241246
self.has_any = true;
242247
},
243248
)+
244249
Property::$shorthand(val) => {
245250
$(
251+
$(
252+
if $image && val.$key.should_preserve_fallback(&self.$key, self.targets) {
253+
self.finalize(dest, context);
254+
}
255+
)?
256+
246257
self.$key = Some(val.$key.clone());
247258
)+
248259
self.has_any = true;

src/properties/background.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -780,6 +780,11 @@ impl<'i> PropertyHandler<'i> for BackgroundHandler<'i> {
780780
) -> bool {
781781
macro_rules! background_image {
782782
($val: ident) => {
783+
// If this is an image-set() and not all of our targets support it, preserve previous fallback.
784+
if Image::should_preserve_fallbacks(&$val, self.images.as_ref(), self.targets) {
785+
self.flush(dest);
786+
}
787+
783788
// Store prefixed properties. Clear if we hit an unprefixed property and we have
784789
// targets. In this case, the necessary prefixes will be generated.
785790
self.has_prefix = $val.iter().any(|x| x.has_vendor_prefix());

src/properties/border_image.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -384,12 +384,22 @@ impl<'i> PropertyHandler<'i> for BorderImageHandler<'i> {
384384
}
385385

386386
match property {
387-
BorderImageSource(val) => property!(source, val),
387+
BorderImageSource(val) => {
388+
if val.should_preserve_fallback(&self.source, self.targets) {
389+
self.flush(dest);
390+
}
391+
392+
property!(source, val);
393+
}
388394
BorderImageSlice(val) => property!(slice, val),
389395
BorderImageWidth(val) => property!(width, val),
390396
BorderImageOutset(val) => property!(outset, val),
391397
BorderImageRepeat(val) => property!(repeat, val),
392398
BorderImage(val, vp) => {
399+
if val.source.should_preserve_fallback(&self.source, self.targets) {
400+
self.flush(dest);
401+
}
402+
393403
self.set_border_image(val);
394404
self.vendor_prefix |= *vp;
395405
self.has_any = true;

src/properties/list.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ impl<'i> FallbackValues for ListStyle<'i> {
322322
}
323323

324324
shorthand_handler!(ListStyleHandler -> ListStyle<'i> fallbacks: true {
325+
image: ListStyleImage(Image<'i>, fallback: true, image: true),
325326
list_style_type: ListStyleType(ListStyleType<'i>),
326-
image: ListStyleImage(Image<'i>, fallback: true),
327327
position: ListStylePosition(ListStylePosition),
328328
});

src/properties/masking.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -615,7 +615,12 @@ impl<'i> PropertyHandler<'i> for MaskHandler<'i> {
615615
}
616616

617617
match property {
618-
Property::MaskImage(val, vp) => property!(images, val, vp),
618+
Property::MaskImage(val, vp) => {
619+
if Image::should_preserve_fallbacks(val, self.images.as_ref().map(|v| &v.0), context.targets) {
620+
self.finalize(dest, context)
621+
}
622+
property!(images, val, vp)
623+
}
619624
Property::MaskPosition(val, vp) => property!(positions, val, vp),
620625
Property::MaskSize(val, vp) => property!(sizes, val, vp),
621626
Property::MaskRepeat(val, vp) => property!(repeats, val, vp),
@@ -625,6 +630,9 @@ impl<'i> PropertyHandler<'i> for MaskHandler<'i> {
625630
Property::MaskMode(val) => self.modes = Some(val.clone()),
626631
Property::Mask(val, prefix) => {
627632
let images = val.iter().map(|b| b.image.clone()).collect();
633+
if Image::should_preserve_fallbacks(&images, self.images.as_ref().map(|v| &v.0), context.targets) {
634+
self.finalize(dest, context)
635+
}
628636
maybe_flush!(images, &images, prefix);
629637

630638
let positions = val.iter().map(|b| b.position.clone()).collect();

src/values/image.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
use super::color::ColorFallbackKind;
44
use super::gradient::*;
55
use super::resolution::Resolution;
6+
use crate::compat;
67
use crate::dependencies::{Dependency, UrlDependency};
78
use crate::error::{ParserError, PrinterError};
89
use crate::prefixes::{is_webkit_gradient, Feature};
@@ -99,6 +100,30 @@ impl<'i> Image<'i> {
99100
_ => self.clone(),
100101
}
101102
}
103+
104+
pub(crate) fn should_preserve_fallback(&self, fallback: &Option<Image>, targets: Option<Browsers>) -> bool {
105+
if let (Some(fallback), Some(targets)) = (&fallback, targets) {
106+
return !compat::Feature::ImageSet.is_compatible(targets)
107+
&& matches!(self, Image::ImageSet(..))
108+
&& !matches!(fallback, Image::ImageSet(..));
109+
}
110+
111+
false
112+
}
113+
114+
pub(crate) fn should_preserve_fallbacks(
115+
images: &SmallVec<[Image; 1]>,
116+
fallback: Option<&SmallVec<[Image; 1]>>,
117+
targets: Option<Browsers>,
118+
) -> bool {
119+
if let (Some(fallback), Some(targets)) = (&fallback, targets) {
120+
return !compat::Feature::ImageSet.is_compatible(targets)
121+
&& images.iter().any(|x| matches!(x, Image::ImageSet(..)))
122+
&& !fallback.iter().any(|x| matches!(x, Image::ImageSet(..)));
123+
}
124+
125+
false
126+
}
102127
}
103128

104129
pub(crate) trait ImageFallback<'i>: Sized {

0 commit comments

Comments
 (0)