pub use bun_collections::SmallList;
pub trait ImageFallback: Sized {
fn get_image(&self) -> &crate::values::image::Image;
fn with_image(&self, arena: &bun_alloc::Arena, image: crate::values::image::Image) -> Self;
fn get_fallback(
&self,
arena: &bun_alloc::Arena,
kind: crate::values::color::ColorFallbackKind,
) -> Self;
fn get_necessary_fallbacks(
&self,
targets: &crate::targets::Targets,
) -> crate::values::color::ColorFallbackKind;
}
#[inline]
pub(crate) fn get_fallbacks<T: ImageFallback>(
this: &mut SmallList<T, 1>,
arena: &bun_alloc::Arena,
targets: &crate::targets::Targets,
) -> Vec<SmallList<T, 1>> {
fallbacks_gated::get_fallbacks_image(this, arena, targets)
}
pub use fallbacks_gated::{get_fallbacks_image, get_fallbacks_text_shadow};
pub mod fallbacks_gated {
use super::*;
use crate::css_parser as css;
use crate::properties::text::TextShadow;
pub fn get_fallbacks_image<T>(
this: &mut SmallList<T, 1>,
arena: &bun_alloc::Arena,
targets: &css::targets::Targets,
) -> Vec<SmallList<T, 1>>
where
T: super::ImageFallback,
{
use css::css_values::color::ColorFallbackKind;
let mut prefixes = css::VendorPrefix::default();
let mut fallbacks = ColorFallbackKind::default();
let mut res: Vec<SmallList<T, 1>> = Vec::new();
for item in this.slice() {
prefixes.insert(item.get_image().get_necessary_prefixes(targets));
fallbacks.insert(item.get_necessary_fallbacks(targets));
}
let rgb: Option<SmallList<T, 1>> = if fallbacks.contains(ColorFallbackKind::RGB) {
let len = this.len();
let mut shallow_clone = SmallList::<T, 1>::init_capacity(len);
for i in 0..len {
let out_val = this.r#mut(i).get_fallback(arena, ColorFallbackKind::RGB);
shallow_clone.append(out_val);
}
Some(shallow_clone)
} else {
None
};
let prefix_images: &SmallList<T, 1> = if let Some(ref r) = rgb { r } else { &*this };
if prefixes.contains(css::VendorPrefix::WEBKIT)
&& targets.browsers.is_some()
&& css::prefixes::Feature::is_webkit_gradient(&targets.browsers.unwrap())
{
let images = 'images: {
let mut images = SmallList::<T, 1>::default();
for item in prefix_images.slice() {
if let Some(img) = item.get_image().get_legacy_webkit(arena) {
images.append(item.with_image(arena, img));
}
}
break 'images images;
};
if !images.is_empty() {
res.push(images);
}
}
#[inline]
fn prefix_helper<T: ImageFallback>(
prefix: &'static str,
pfs: css::VendorPrefix,
pfi: &SmallList<T, 1>,
r: &mut Vec<SmallList<T, 1>>,
alloc: &bun_alloc::Arena,
) {
if pfs.contains(css::VendorPrefix::from_name_str(prefix)) {
let mut images = SmallList::<T, 1>::init_capacity(pfi.len());
for i in 0..pfi.len() {
let in_ = pfi.at(i);
let image = in_
.get_image()
.get_prefixed(alloc, css::VendorPrefix::from_name_str(prefix));
images.append(in_.with_image(alloc, image));
}
r.push(images);
}
}
prefix_helper("webkit", prefixes, prefix_images, &mut res, arena);
prefix_helper("moz", prefixes, prefix_images, &mut res, arena);
prefix_helper("o", prefixes, prefix_images, &mut res, arena);
if prefixes.contains(css::VendorPrefix::NONE) {
if let Some(r) = rgb {
res.push(r);
}
if fallbacks.contains(ColorFallbackKind::P3) {
let len = this.len();
let mut p3_images = SmallList::<T, 1>::init_capacity(len);
for i in 0..len {
let out_val = this.r#mut(i).get_fallback(arena, ColorFallbackKind::P3);
p3_images.append(out_val);
}
res.push(p3_images);
}
if fallbacks.contains(ColorFallbackKind::LAB) {
for item in this.slice_mut() {
let new = item.get_fallback(arena, ColorFallbackKind::LAB);
let old = core::mem::replace(item, new);
drop(old);
}
}
} else if let Some(the_last) = res.pop() {
let old = core::mem::replace(this, the_last);
drop(old);
}
res
}
pub fn get_fallbacks_text_shadow(
this: &mut SmallList<TextShadow, 1>,
arena: &bun_alloc::Arena,
targets: &css::targets::Targets,
) -> SmallList<SmallList<TextShadow, 1>, 2> {
let mut fallbacks = css::ColorFallbackKind::default();
for shadow in this.slice() {
fallbacks.insert(shadow.color.get_necessary_fallbacks(targets));
}
let mut res = SmallList::<SmallList<TextShadow, 1>, 2>::default();
if fallbacks.contains(css::ColorFallbackKind::RGB) {
let mut rgb = SmallList::<TextShadow, 1>::init_capacity(this.len());
for shadow in this.slice() {
let mut new_shadow = shadow.clone();
new_shadow.color = css::css_values::color::CssColor::CurrentColor;
new_shadow = new_shadow.deep_clone(arena);
new_shadow.color = shadow
.color
.to_rgb()
.unwrap_or_else(|| shadow.color.deep_clone(arena));
rgb.append_assume_capacity(new_shadow);
}
res.append(rgb);
}
if fallbacks.contains(css::ColorFallbackKind::P3) {
let mut p3 = SmallList::<TextShadow, 1>::init_capacity(this.len());
for shadow in this.slice() {
let mut new_shadow = shadow.clone();
new_shadow.color = css::css_values::color::CssColor::CurrentColor;
new_shadow = new_shadow.deep_clone(arena);
new_shadow.color = shadow
.color
.to_p3()
.unwrap_or_else(|| shadow.color.deep_clone(arena));
p3.append_assume_capacity(new_shadow);
}
res.append(p3);
}
if fallbacks.contains(css::ColorFallbackKind::LAB) {
for shadow in this.slice_mut() {
let Some(out) = shadow.color.to_lab() else {
continue;
};
let _ = core::mem::replace(&mut shadow.color, out);
}
}
res
}
}