use crate::color::mix::ColorInterpolationMethod;
use crate::color::AbsoluteColor;
use crate::values::specified::percentage::ToPercentage;
use std::fmt::{self, Write};
use style_traits::{CssWriter, ToCss};
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToAnimatedValue, ToShmem)]
#[repr(C)]
pub enum GenericColor<Percentage> {
Absolute(AbsoluteColor),
CurrentColor,
ColorMix(Box<GenericColorMix<Self, Percentage>>),
}
#[derive(Clone, Copy, Debug, Default, MallocSizeOf, PartialEq, ToShmem)]
#[repr(C)]
pub struct ColorMixFlags(u8);
bitflags! {
impl ColorMixFlags : u8 {
const NORMALIZE_WEIGHTS = 1 << 0;
const RESULT_IN_MODERN_SYNTAX = 1 << 1;
}
}
#[derive(
Clone,
Debug,
MallocSizeOf,
PartialEq,
ToAnimatedValue,
ToComputedValue,
ToResolvedValue,
ToShmem,
)]
#[allow(missing_docs)]
#[repr(C)]
pub struct GenericColorMix<Color, Percentage> {
pub interpolation: ColorInterpolationMethod,
pub left: Color,
pub left_percentage: Percentage,
pub right: Color,
pub right_percentage: Percentage,
pub flags: ColorMixFlags,
}
pub use self::GenericColorMix as ColorMix;
impl<Color: ToCss, Percentage: ToCss + ToPercentage> ToCss for ColorMix<Color, Percentage> {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
fn can_omit<Percentage: ToPercentage>(
percent: &Percentage,
other: &Percentage,
is_left: bool,
) -> bool {
if percent.is_calc() {
return false;
}
if percent.to_percentage() == 0.5 {
return other.to_percentage() == 0.5;
}
if is_left {
return false;
}
(1.0 - percent.to_percentage() - other.to_percentage()).abs() <= f32::EPSILON
}
dest.write_str("color-mix(")?;
self.interpolation.to_css(dest)?;
dest.write_str(", ")?;
self.left.to_css(dest)?;
if !can_omit(&self.left_percentage, &self.right_percentage, true) {
dest.write_char(' ')?;
self.left_percentage.to_css(dest)?;
}
dest.write_str(", ")?;
self.right.to_css(dest)?;
if !can_omit(&self.right_percentage, &self.left_percentage, false) {
dest.write_char(' ')?;
self.right_percentage.to_css(dest)?;
}
dest.write_char(')')
}
}
impl<Percentage> ColorMix<GenericColor<Percentage>, Percentage> {
pub fn mix_to_absolute(&self) -> Option<AbsoluteColor>
where
Percentage: ToPercentage,
{
let left = self.left.as_absolute()?;
let right = self.right.as_absolute()?;
Some(crate::color::mix::mix(
self.interpolation,
&left,
self.left_percentage.to_percentage(),
&right,
self.right_percentage.to_percentage(),
self.flags,
))
}
}
pub use self::GenericColor as Color;
impl<Percentage> Color<Percentage> {
pub fn as_absolute(&self) -> Option<&AbsoluteColor> {
match *self {
Self::Absolute(ref absolute) => Some(absolute),
_ => None,
}
}
pub fn currentcolor() -> Self {
Self::CurrentColor
}
pub fn is_currentcolor(&self) -> bool {
matches!(*self, Self::CurrentColor)
}
pub fn is_absolute(&self) -> bool {
matches!(*self, Self::Absolute(..))
}
}
#[derive(
Animate,
Clone,
ComputeSquaredDistance,
Copy,
Debug,
MallocSizeOf,
PartialEq,
Parse,
SpecifiedValueInfo,
ToAnimatedValue,
ToAnimatedZero,
ToComputedValue,
ToResolvedValue,
ToCss,
ToShmem,
)]
#[repr(C, u8)]
pub enum GenericColorOrAuto<C> {
Color(C),
Auto,
}
pub use self::GenericColorOrAuto as ColorOrAuto;
#[derive(
Animate,
Clone,
ComputeSquaredDistance,
Copy,
Debug,
MallocSizeOf,
PartialEq,
SpecifiedValueInfo,
ToAnimatedValue,
ToAnimatedZero,
ToComputedValue,
ToCss,
ToShmem,
)]
#[repr(transparent)]
pub struct GenericCaretColor<C>(pub GenericColorOrAuto<C>);
impl<C> GenericCaretColor<C> {
pub fn auto() -> Self {
GenericCaretColor(GenericColorOrAuto::Auto)
}
}
pub use self::GenericCaretColor as CaretColor;