use crate::values::animated::{Animate, Procedure, ToAnimatedValue};
use crate::values::computed::font::FixedPoint;
use crate::values::computed::length::{LengthPercentage, NonNegativeLength};
use crate::values::computed::{Context, Integer, Number, ToComputedValue};
use crate::values::generics::box_::{
GenericContainIntrinsicSize, GenericLineClamp, GenericPerspective, GenericVerticalAlign,
};
use crate::values::specified::box_ as specified;
use std::fmt;
use style_traits::{CssWriter, ToCss};
pub use crate::values::specified::box_::{
Appearance, BaselineSource, BreakBetween, BreakWithin, Clear as SpecifiedClear, Contain,
ContainerName, ContainerType, ContentVisibility, Display, Float as SpecifiedFloat, Overflow,
OverflowAnchor, OverflowClipBox, OverscrollBehavior, ScrollSnapAlign, ScrollSnapAxis,
ScrollSnapStop, ScrollSnapStrictness, ScrollSnapType, ScrollbarGutter, TouchAction, WillChange,
};
pub type VerticalAlign = GenericVerticalAlign<LengthPercentage>;
pub type ContainIntrinsicSize = GenericContainIntrinsicSize<NonNegativeLength>;
impl ContainIntrinsicSize {
pub fn add_auto_if_needed(&self) -> Option<Self> {
Some(match *self {
Self::None => Self::AutoNone,
Self::Length(ref l) => Self::AutoLength(*l),
Self::AutoNone | Self::AutoLength(..) => return None,
})
}
}
pub type LineClamp = GenericLineClamp<Integer>;
impl Animate for LineClamp {
#[inline]
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
if self.is_none() != other.is_none() {
return Err(());
}
if self.is_none() {
return Ok(Self::none());
}
Ok(Self(self.0.animate(&other.0, procedure)?.max(1)))
}
}
pub type Perspective = GenericPerspective<NonNegativeLength>;
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(
Clone,
Copy,
Debug,
Eq,
FromPrimitive,
Hash,
MallocSizeOf,
Parse,
PartialEq,
SpecifiedValueInfo,
ToCss,
ToResolvedValue,
)]
#[repr(u8)]
pub enum Float {
Left,
Right,
None,
}
impl Float {
pub fn is_floating(self) -> bool {
self != Self::None
}
}
impl ToComputedValue for SpecifiedFloat {
type ComputedValue = Float;
#[inline]
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
let ltr = context.style().writing_mode.is_bidi_ltr();
match *self {
SpecifiedFloat::InlineStart => {
context
.rule_cache_conditions
.borrow_mut()
.set_writing_mode_dependency(context.builder.writing_mode);
if ltr {
Float::Left
} else {
Float::Right
}
},
SpecifiedFloat::InlineEnd => {
context
.rule_cache_conditions
.borrow_mut()
.set_writing_mode_dependency(context.builder.writing_mode);
if ltr {
Float::Right
} else {
Float::Left
}
},
SpecifiedFloat::Left => Float::Left,
SpecifiedFloat::Right => Float::Right,
SpecifiedFloat::None => Float::None,
}
}
#[inline]
fn from_computed_value(computed: &Self::ComputedValue) -> SpecifiedFloat {
match *computed {
Float::Left => SpecifiedFloat::Left,
Float::Right => SpecifiedFloat::Right,
Float::None => SpecifiedFloat::None,
}
}
}
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(
Clone,
Copy,
Debug,
Eq,
FromPrimitive,
Hash,
MallocSizeOf,
Parse,
PartialEq,
SpecifiedValueInfo,
ToCss,
ToResolvedValue,
)]
#[repr(u8)]
pub enum Clear {
None,
Left,
Right,
Both,
}
impl ToComputedValue for SpecifiedClear {
type ComputedValue = Clear;
#[inline]
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
let ltr = context.style().writing_mode.is_bidi_ltr();
match *self {
SpecifiedClear::InlineStart => {
context
.rule_cache_conditions
.borrow_mut()
.set_writing_mode_dependency(context.builder.writing_mode);
if ltr {
Clear::Left
} else {
Clear::Right
}
},
SpecifiedClear::InlineEnd => {
context
.rule_cache_conditions
.borrow_mut()
.set_writing_mode_dependency(context.builder.writing_mode);
if ltr {
Clear::Right
} else {
Clear::Left
}
},
SpecifiedClear::None => Clear::None,
SpecifiedClear::Left => Clear::Left,
SpecifiedClear::Right => Clear::Right,
SpecifiedClear::Both => Clear::Both,
}
}
#[inline]
fn from_computed_value(computed: &Self::ComputedValue) -> SpecifiedClear {
match *computed {
Clear::None => SpecifiedClear::None,
Clear::Left => SpecifiedClear::Left,
Clear::Right => SpecifiedClear::Right,
Clear::Both => SpecifiedClear::Both,
}
}
}
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq, ToCss, ToResolvedValue)]
#[repr(u8)]
pub enum Resize {
None,
Both,
Horizontal,
Vertical,
}
impl ToComputedValue for specified::Resize {
type ComputedValue = Resize;
#[inline]
fn to_computed_value(&self, context: &Context) -> Resize {
let is_vertical = context.style().writing_mode.is_vertical();
match self {
specified::Resize::Inline => {
context
.rule_cache_conditions
.borrow_mut()
.set_writing_mode_dependency(context.builder.writing_mode);
if is_vertical {
Resize::Vertical
} else {
Resize::Horizontal
}
},
specified::Resize::Block => {
context
.rule_cache_conditions
.borrow_mut()
.set_writing_mode_dependency(context.builder.writing_mode);
if is_vertical {
Resize::Horizontal
} else {
Resize::Vertical
}
},
specified::Resize::None => Resize::None,
specified::Resize::Both => Resize::Both,
specified::Resize::Horizontal => Resize::Horizontal,
specified::Resize::Vertical => Resize::Vertical,
}
}
#[inline]
fn from_computed_value(computed: &Resize) -> specified::Resize {
match computed {
Resize::None => specified::Resize::None,
Resize::Both => specified::Resize::Both,
Resize::Horizontal => specified::Resize::Horizontal,
Resize::Vertical => specified::Resize::Vertical,
}
}
}
pub const ZOOM_FRACTION_BITS: u16 = 6;
pub type ZoomFixedPoint = FixedPoint<u16, ZOOM_FRACTION_BITS>;
#[derive(
Clone,
ComputeSquaredDistance,
Copy,
Debug,
Hash,
MallocSizeOf,
PartialEq,
PartialOrd,
ToResolvedValue,
)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[repr(C)]
pub struct Zoom(ZoomFixedPoint);
impl ToComputedValue for specified::Zoom {
type ComputedValue = Zoom;
#[inline]
fn to_computed_value(&self, _: &Context) -> Self::ComputedValue {
let n = match *self {
Self::Normal => return Zoom::ONE,
Self::Document => return Zoom::DOCUMENT,
Self::Value(ref n) => n.0.to_number().get(),
};
if n == 0.0 {
return Zoom::ONE;
}
Zoom(ZoomFixedPoint::from_float(n))
}
#[inline]
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
Self::new_number(computed.value())
}
}
impl ToCss for Zoom {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: fmt::Write,
{
use std::fmt::Write;
if *self == Self::DOCUMENT {
return dest.write_str("document");
}
self.value().to_css(dest)
}
}
impl ToAnimatedValue for Zoom {
type AnimatedValue = Number;
#[inline]
fn to_animated_value(self, _: &crate::values::animated::Context) -> Self::AnimatedValue {
self.value()
}
#[inline]
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
Zoom(ZoomFixedPoint::from_float(animated.max(0.0)))
}
}
impl Zoom {
pub const ONE: Zoom = Zoom(ZoomFixedPoint {
value: 1 << ZOOM_FRACTION_BITS,
});
pub const DOCUMENT: Zoom = Zoom(ZoomFixedPoint { value: 0 });
#[inline]
pub fn is_one(self) -> bool {
self == Self::ONE
}
#[inline]
pub fn is_document(self) -> bool {
self == Self::DOCUMENT
}
#[inline]
pub fn inverted(&self) -> Option<Self> {
if self.0.value == 0 {
return None;
}
Some(Self(Self::ONE.0 / self.0))
}
#[inline]
pub fn value(&self) -> f32 {
self.0.to_float()
}
pub fn compute_effective(self, specified: Self) -> Self {
if specified == Self::DOCUMENT {
return Self::ONE;
}
if self == Self::ONE {
return specified;
}
if specified == Self::ONE {
return self;
}
Zoom(self.0 * specified.0)
}
#[inline]
pub fn zoom(self, value: f32) -> f32 {
if self == Self::ONE {
return value;
}
value * self.value()
}
#[inline]
pub fn unzoom(self, value: f32) -> f32 {
if self == Self::ONE {
return value;
}
value / self.value()
}
}