From 25c1c36b7fd5206c58dc64d1332bfd00432cd2d0 Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Tue, 14 May 2024 16:00:46 +0100 Subject: [PATCH] Initial taffy_stylo crate (flexbox only) --- Cargo.toml | 1 + taffy_stylo/Cargo.toml | 12 +++ taffy_stylo/src/arc.rs | 169 ++++++++++++++++++++++++++++++ taffy_stylo/src/borrowed.rs | 168 ++++++++++++++++++++++++++++++ taffy_stylo/src/lib.rs | 41 ++++++++ taffy_stylo/src/t2s.rs | 202 ++++++++++++++++++++++++++++++++++++ 6 files changed, 593 insertions(+) create mode 100644 taffy_stylo/Cargo.toml create mode 100644 taffy_stylo/src/arc.rs create mode 100644 taffy_stylo/src/borrowed.rs create mode 100644 taffy_stylo/src/lib.rs create mode 100644 taffy_stylo/src/t2s.rs diff --git a/Cargo.toml b/Cargo.toml index 5b4ceec66..1dfcb1eed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -101,4 +101,5 @@ members = [ "scripts/format-fixtures", "scripts/import-yoga-tests", "benches", + "taffy_stylo", ] diff --git a/taffy_stylo/Cargo.toml b/taffy_stylo/Cargo.toml new file mode 100644 index 000000000..a6877ee75 --- /dev/null +++ b/taffy_stylo/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "taffy_stylo" +version = "0.0.1" +edition = "2021" +license = "MIT OR Apache-2.0" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +taffy = { path = ".." } +style = { git = "https://github.com/servo/stylo", branch = "2024-05-31", features = ["servo"] } +servo_arc = { git = "https://github.com/servo/stylo", branch = "2024-05-31" } \ No newline at end of file diff --git a/taffy_stylo/src/arc.rs b/taffy_stylo/src/arc.rs new file mode 100644 index 000000000..cb9f2799c --- /dev/null +++ b/taffy_stylo/src/arc.rs @@ -0,0 +1,169 @@ +use crate::{stylo, t2s}; +use servo_arc::Arc; + +pub struct TaffyStyloStyle(pub Arc); + +impl From> for TaffyStyloStyle { + fn from(value: Arc) -> Self { + Self(Arc::clone(&value)) + } +} + +impl taffy::CoreStyle for TaffyStyloStyle { + #[inline] + fn box_generation_mode(&self) -> taffy::BoxGenerationMode { + t2s::box_generation_mode(self.0.get_box().display) + } + + #[inline] + fn is_block(&self) -> bool { + t2s::is_block(self.0.get_box().display) + } + + #[inline] + fn overflow(&self) -> taffy::Point { + let box_styles = self.0.get_box(); + taffy::Point { x: t2s::overflow(box_styles.overflow_x), y: t2s::overflow(box_styles.overflow_y) } + } + + #[inline] + fn scrollbar_width(&self) -> f32 { + 0.0 + } + + #[inline] + fn position(&self) -> taffy::Position { + t2s::position(self.0.get_box().position) + } + + #[inline] + fn inset(&self) -> taffy::Rect { + let position_styles = self.0.get_position(); + taffy::Rect { + left: t2s::length_percentage_auto(&position_styles.left), + right: t2s::length_percentage_auto(&position_styles.right), + top: t2s::length_percentage_auto(&position_styles.top), + bottom: t2s::length_percentage_auto(&position_styles.bottom), + } + } + + #[inline] + fn size(&self) -> taffy::Size { + let position_styles = self.0.get_position(); + taffy::Size { width: t2s::dimension(&position_styles.width), height: t2s::dimension(&position_styles.height) } + } + + #[inline] + fn min_size(&self) -> taffy::Size { + let position_styles = self.0.get_position(); + taffy::Size { + width: t2s::dimension(&position_styles.min_width), + height: t2s::dimension(&position_styles.min_height), + } + } + + #[inline] + fn max_size(&self) -> taffy::Size { + let position_styles = self.0.get_position(); + taffy::Size { + width: t2s::max_size_dimension(&position_styles.max_width), + height: t2s::max_size_dimension(&position_styles.max_height), + } + } + + #[inline] + fn aspect_ratio(&self) -> Option { + t2s::aspect_ratio(self.0.get_position().aspect_ratio) + } + + #[inline] + fn margin(&self) -> taffy::Rect { + let margin_styles = self.0.get_margin(); + taffy::Rect { + left: t2s::length_percentage_auto(&margin_styles.margin_left), + right: t2s::length_percentage_auto(&margin_styles.margin_right), + top: t2s::length_percentage_auto(&margin_styles.margin_top), + bottom: t2s::length_percentage_auto(&margin_styles.margin_bottom), + } + } + + #[inline] + fn padding(&self) -> taffy::Rect { + let padding_styles = self.0.get_padding(); + taffy::Rect { + left: t2s::length_percentage(&padding_styles.padding_left.0), + right: t2s::length_percentage(&padding_styles.padding_right.0), + top: t2s::length_percentage(&padding_styles.padding_top.0), + bottom: t2s::length_percentage(&padding_styles.padding_bottom.0), + } + } + + #[inline] + fn border(&self) -> taffy::Rect { + let border_styles = self.0.get_border(); + taffy::Rect { + left: taffy::LengthPercentage::Length(border_styles.border_left_width.to_f32_px()), + right: taffy::LengthPercentage::Length(border_styles.border_right_width.to_f32_px()), + top: taffy::LengthPercentage::Length(border_styles.border_top_width.to_f32_px()), + bottom: taffy::LengthPercentage::Length(border_styles.border_bottom_width.to_f32_px()), + } + } +} + +impl taffy::FlexboxContainerStyle for TaffyStyloStyle { + #[inline] + fn flex_direction(&self) -> taffy::FlexDirection { + t2s::flex_direction(self.0.get_position().flex_direction) + } + + #[inline] + fn flex_wrap(&self) -> taffy::FlexWrap { + t2s::flex_wrap(self.0.get_position().flex_wrap) + } + + #[inline] + fn gap(&self) -> taffy::Size { + let position_styles = self.0.get_position(); + taffy::Size { + width: t2s::gap(&position_styles.column_gap), + height: taffy::LengthPercentage::Length(0.0), // TODO: enable row_gap in stylo + } + } + + #[inline] + fn align_content(&self) -> Option { + t2s::align_content(self.0.get_position().align_content) + } + + #[inline] + fn align_items(&self) -> Option { + t2s::align_items(self.0.get_position().align_items) + } + + #[inline] + fn justify_content(&self) -> Option { + t2s::justify_content(self.0.get_position().justify_content) + } +} + +impl taffy::FlexboxItemStyle for TaffyStyloStyle { + #[inline] + fn flex_basis(&self) -> taffy::Dimension { + t2s::flex_basis(&self.0.get_position().flex_basis) + } + + #[inline] + fn flex_grow(&self) -> f32 { + self.0.get_position().flex_grow.0 + } + + #[inline] + fn flex_shrink(&self) -> f32 { + self.0.get_position().flex_shrink.0 + } + + #[inline] + fn align_self(&self) -> Option { + t2s::align_self(self.0.get_position().align_self) + } +} diff --git a/taffy_stylo/src/borrowed.rs b/taffy_stylo/src/borrowed.rs new file mode 100644 index 000000000..5dd32f491 --- /dev/null +++ b/taffy_stylo/src/borrowed.rs @@ -0,0 +1,168 @@ +use crate::{stylo, t2s}; + +pub struct TaffyStyloStyleRef<'a>(pub &'a stylo::ComputedValues); + +impl<'a> From<&'a stylo::ComputedValues> for TaffyStyloStyleRef<'a> { + fn from(value: &'a stylo::ComputedValues) -> Self { + Self(value) + } +} + +impl taffy::CoreStyle for TaffyStyloStyleRef<'_> { + #[inline] + fn box_generation_mode(&self) -> taffy::BoxGenerationMode { + t2s::box_generation_mode(self.0.get_box().display) + } + + #[inline] + fn is_block(&self) -> bool { + t2s::is_block(self.0.get_box().display) + } + + #[inline] + fn overflow(&self) -> taffy::Point { + let box_styles = self.0.get_box(); + taffy::Point { x: t2s::overflow(box_styles.overflow_x), y: t2s::overflow(box_styles.overflow_y) } + } + + #[inline] + fn scrollbar_width(&self) -> f32 { + 0.0 + } + + #[inline] + fn position(&self) -> taffy::Position { + t2s::position(self.0.get_box().position) + } + + #[inline] + fn inset(&self) -> taffy::Rect { + let position_styles = self.0.get_position(); + taffy::Rect { + left: t2s::length_percentage_auto(&position_styles.left), + right: t2s::length_percentage_auto(&position_styles.right), + top: t2s::length_percentage_auto(&position_styles.top), + bottom: t2s::length_percentage_auto(&position_styles.bottom), + } + } + + #[inline] + fn size(&self) -> taffy::Size { + let position_styles = self.0.get_position(); + taffy::Size { width: t2s::dimension(&position_styles.width), height: t2s::dimension(&position_styles.height) } + } + + #[inline] + fn min_size(&self) -> taffy::Size { + let position_styles = self.0.get_position(); + taffy::Size { + width: t2s::dimension(&position_styles.min_width), + height: t2s::dimension(&position_styles.min_height), + } + } + + #[inline] + fn max_size(&self) -> taffy::Size { + let position_styles = self.0.get_position(); + taffy::Size { + width: t2s::max_size_dimension(&position_styles.max_width), + height: t2s::max_size_dimension(&position_styles.max_height), + } + } + + #[inline] + fn aspect_ratio(&self) -> Option { + t2s::aspect_ratio(self.0.get_position().aspect_ratio) + } + + #[inline] + fn margin(&self) -> taffy::Rect { + let margin_styles = self.0.get_margin(); + taffy::Rect { + left: t2s::length_percentage_auto(&margin_styles.margin_left), + right: t2s::length_percentage_auto(&margin_styles.margin_right), + top: t2s::length_percentage_auto(&margin_styles.margin_top), + bottom: t2s::length_percentage_auto(&margin_styles.margin_bottom), + } + } + + #[inline] + fn padding(&self) -> taffy::Rect { + let padding_styles = self.0.get_padding(); + taffy::Rect { + left: t2s::length_percentage(&padding_styles.padding_left.0), + right: t2s::length_percentage(&padding_styles.padding_right.0), + top: t2s::length_percentage(&padding_styles.padding_top.0), + bottom: t2s::length_percentage(&padding_styles.padding_bottom.0), + } + } + + #[inline] + fn border(&self) -> taffy::Rect { + let border_styles = self.0.get_border(); + taffy::Rect { + left: taffy::LengthPercentage::Length(border_styles.border_left_width.to_f32_px()), + right: taffy::LengthPercentage::Length(border_styles.border_right_width.to_f32_px()), + top: taffy::LengthPercentage::Length(border_styles.border_top_width.to_f32_px()), + bottom: taffy::LengthPercentage::Length(border_styles.border_bottom_width.to_f32_px()), + } + } +} + +impl taffy::FlexboxContainerStyle for TaffyStyloStyleRef<'_> { + #[inline] + fn flex_direction(&self) -> taffy::FlexDirection { + t2s::flex_direction(self.0.get_position().flex_direction) + } + + #[inline] + fn flex_wrap(&self) -> taffy::FlexWrap { + t2s::flex_wrap(self.0.get_position().flex_wrap) + } + + #[inline] + fn gap(&self) -> taffy::Size { + let position_styles = self.0.get_position(); + taffy::Size { + width: t2s::gap(&position_styles.column_gap), + height: taffy::LengthPercentage::Length(0.0), // TODO: enable row_gap in stylo + } + } + + #[inline] + fn align_content(&self) -> Option { + t2s::align_content(self.0.get_position().align_content) + } + + #[inline] + fn align_items(&self) -> Option { + t2s::align_items(self.0.get_position().align_items) + } + + #[inline] + fn justify_content(&self) -> Option { + t2s::justify_content(self.0.get_position().justify_content) + } +} + +impl taffy::FlexboxItemStyle for TaffyStyloStyleRef<'_> { + #[inline] + fn flex_basis(&self) -> taffy::Dimension { + t2s::flex_basis(&self.0.get_position().flex_basis) + } + + #[inline] + fn flex_grow(&self) -> f32 { + self.0.get_position().flex_grow.0 + } + + #[inline] + fn flex_shrink(&self) -> f32 { + self.0.get_position().flex_shrink.0 + } + + #[inline] + fn align_self(&self) -> Option { + t2s::align_self(self.0.get_position().align_self) + } +} diff --git a/taffy_stylo/src/lib.rs b/taffy_stylo/src/lib.rs new file mode 100644 index 000000000..bffb2786f --- /dev/null +++ b/taffy_stylo/src/lib.rs @@ -0,0 +1,41 @@ +//! Conversion functions from Stylo types to Taffy types + +pub(crate) mod arc; +pub(crate) mod borrowed; +pub(crate) mod t2s; + +// Module of type aliases so we can refer to stylo types with nicer names +mod stylo { + pub(crate) use style::computed_values::align_content::T as AlignContent; + pub(crate) use style::computed_values::align_items::T as AlignItems; + pub(crate) use style::computed_values::align_self::T as AlignSelf; + pub(crate) use style::computed_values::flex_direction::T as FlexDirection; + pub(crate) use style::computed_values::flex_wrap::T as FlexWrap; + pub(crate) use style::computed_values::justify_content::T as JustifyContent; + // pub(crate) use style::computed_values::justify_items::T as JustifyItems; + // pub(crate) use style::computed_values::justify_self::T as JustifySelf; + pub(crate) use style::properties::longhands::aspect_ratio::computed_value::T as AspectRatio; + pub(crate) use style::properties::longhands::position::computed_value::T as Position; + // pub(crate) use style::properties::style_structs::{Margin, Padding}; + pub(crate) use style::values::computed::LengthPercentage; + pub(crate) use style::values::generics::flex::GenericFlexBasis; + pub(crate) use style::values::generics::length::GenericLengthPercentageOrAuto; + pub(crate) use style::values::generics::length::GenericLengthPercentageOrNormal; + pub(crate) use style::values::generics::length::GenericMaxSize; + pub(crate) use style::values::generics::length::GenericSize; + pub(crate) use style::values::generics::position::PreferredRatio; + pub(crate) use style::values::generics::NonNegative; + pub(crate) use style::values::specified::box_::Display; + pub(crate) use style::values::specified::box_::DisplayInside; + pub(crate) use style::values::specified::box_::DisplayOutside; + pub(crate) use style::values::specified::box_::Overflow; + pub(crate) type LengthPercentageAuto = GenericLengthPercentageOrAuto; + pub(crate) type Size = GenericSize>; + pub(crate) type MaxSize = GenericMaxSize>; + pub(crate) type FlexBasis = GenericFlexBasis; + pub(crate) type Gap = GenericLengthPercentageOrNormal>; + pub(crate) use style::properties::generated::ComputedValues; +} + +pub use arc::TaffyStyloStyle; +pub use borrowed::TaffyStyloStyleRef; diff --git a/taffy_stylo/src/t2s.rs b/taffy_stylo/src/t2s.rs new file mode 100644 index 000000000..46ae162fd --- /dev/null +++ b/taffy_stylo/src/t2s.rs @@ -0,0 +1,202 @@ +use super::stylo; + +#[inline] +pub(crate) fn length_percentage(val: &stylo::LengthPercentage) -> taffy::LengthPercentage { + if let Some(length) = val.to_length() { + taffy::LengthPercentage::Length(length.px()) + } else if let Some(val) = val.to_percentage() { + taffy::LengthPercentage::Percent(val.0) + } else { + // TODO: Support calc + taffy::LengthPercentage::Percent(0.0) + } +} + +#[inline] +pub(crate) fn length_percentage_auto(val: &stylo::LengthPercentageAuto) -> taffy::LengthPercentageAuto { + match val { + stylo::LengthPercentageAuto::Auto => taffy::LengthPercentageAuto::Auto, + stylo::LengthPercentageAuto::LengthPercentage(val) => length_percentage(val).into(), + } +} + +#[inline] +pub(crate) fn dimension(val: &stylo::Size) -> taffy::Dimension { + match val { + stylo::Size::LengthPercentage(val) => length_percentage(&val.0).into(), + stylo::Size::Auto => taffy::Dimension::Auto, + // TODO: implement other values in Taffy (and servo configuration of stylo) + // _ => taffy::Dimension::Auto, + } +} + +#[inline] +pub(crate) fn max_size_dimension(val: &stylo::MaxSize) -> taffy::Dimension { + match val { + stylo::MaxSize::LengthPercentage(val) => length_percentage(&val.0).into(), + stylo::MaxSize::None => taffy::Dimension::Auto, + // TODO: implement other values in Taffy (and servo configuration of stylo) + // _ => taffy::Dimension::Auto, + } +} + +#[inline] +pub(crate) fn is_block(input: stylo::Display) -> bool { + matches!(input.outside(), stylo::DisplayOutside::Block) + && matches!(input.inside(), stylo::DisplayInside::Flow | stylo::DisplayInside::FlowRoot) +} + +#[inline] +pub(crate) fn box_generation_mode(input: stylo::Display) -> taffy::BoxGenerationMode { + match input.inside() { + stylo::DisplayInside::None => taffy::BoxGenerationMode::None, + // stylo::DisplayInside::Contents => display = taffy::BoxGenerationMode::Contents, + _ => taffy::BoxGenerationMode::Normal, + } +} + +#[inline] +pub(crate) fn position(input: stylo::Position) -> taffy::Position { + match input { + // TODO: support position:static + stylo::Position::Relative => taffy::Position::Relative, + stylo::Position::Static => taffy::Position::Relative, + + // TODO: support position:fixed and sticky + stylo::Position::Absolute => taffy::Position::Absolute, + stylo::Position::Fixed => taffy::Position::Absolute, + stylo::Position::Sticky => taffy::Position::Absolute, + } +} + +#[inline] +pub(crate) fn overflow(input: stylo::Overflow) -> taffy::Overflow { + // TODO: Enable Overflow::Clip in servo configuration of stylo + match input { + stylo::Overflow::Visible => taffy::Overflow::Visible, + stylo::Overflow::Hidden => taffy::Overflow::Hidden, + stylo::Overflow::Scroll => taffy::Overflow::Scroll, + // TODO: Support Overflow::Auto in Taffy + stylo::Overflow::Auto => taffy::Overflow::Scroll, + } +} + +#[inline] +pub(crate) fn aspect_ratio(input: stylo::AspectRatio) -> Option { + match input.ratio { + stylo::PreferredRatio::None => None, + stylo::PreferredRatio::Ratio(val) => Some(val.0 .0 / val.1 .0), + } +} + +#[inline] +pub(crate) fn gap(input: &stylo::Gap) -> taffy::LengthPercentage { + match input { + // For Flexbox and CSS Grid the "normal" value is 0px. This may need to be updated + // if we ever implement multi-column layout. + stylo::Gap::Normal => taffy::LengthPercentage::Length(0.0), + stylo::Gap::LengthPercentage(val) => length_percentage(&val.0), + } +} + +#[inline] +pub(crate) fn flex_basis(input: &stylo::FlexBasis) -> taffy::Dimension { + // TODO: Support flex-basis: content in Taffy + match input { + stylo::FlexBasis::Content => taffy::Dimension::Auto, + stylo::FlexBasis::Size(size) => dimension(&size).into(), + } +} + +#[inline] +pub(crate) fn flex_direction(input: stylo::FlexDirection) -> taffy::FlexDirection { + match input { + stylo::FlexDirection::Row => taffy::FlexDirection::Row, + stylo::FlexDirection::RowReverse => taffy::FlexDirection::RowReverse, + stylo::FlexDirection::Column => taffy::FlexDirection::Column, + stylo::FlexDirection::ColumnReverse => taffy::FlexDirection::ColumnReverse, + } +} + +#[inline] +pub(crate) fn flex_wrap(input: stylo::FlexWrap) -> taffy::FlexWrap { + match input { + stylo::FlexWrap::Wrap => taffy::FlexWrap::Wrap, + stylo::FlexWrap::WrapReverse => taffy::FlexWrap::WrapReverse, + stylo::FlexWrap::Nowrap => taffy::FlexWrap::NoWrap, + } +} + +#[inline] +pub(crate) fn justify_content(input: stylo::JustifyContent) -> Option { + match input { + stylo::JustifyContent::Start => Some(taffy::JustifyContent::Start), + stylo::JustifyContent::End => Some(taffy::JustifyContent::End), + stylo::JustifyContent::FlexStart => Some(taffy::JustifyContent::FlexStart), + stylo::JustifyContent::FlexEnd => Some(taffy::JustifyContent::FlexEnd), + stylo::JustifyContent::Stretch => Some(taffy::JustifyContent::Stretch), + stylo::JustifyContent::Center => Some(taffy::JustifyContent::Center), + stylo::JustifyContent::SpaceBetween => Some(taffy::JustifyContent::SpaceBetween), + stylo::JustifyContent::SpaceAround => Some(taffy::JustifyContent::SpaceAround), + stylo::JustifyContent::SpaceEvenly => Some(taffy::JustifyContent::SpaceEvenly), + } +} + +#[inline] +pub(crate) fn align_content(input: stylo::AlignContent) -> Option { + match input { + stylo::AlignContent::Start => Some(taffy::AlignContent::Start), + stylo::AlignContent::End => Some(taffy::AlignContent::End), + stylo::AlignContent::FlexStart => Some(taffy::AlignContent::FlexStart), + stylo::AlignContent::FlexEnd => Some(taffy::AlignContent::FlexEnd), + stylo::AlignContent::Center => Some(taffy::AlignContent::Center), + stylo::AlignContent::Stretch => Some(taffy::AlignContent::Stretch), + stylo::AlignContent::SpaceBetween => Some(taffy::AlignContent::SpaceBetween), + stylo::AlignContent::SpaceAround => Some(taffy::AlignContent::SpaceAround), + stylo::AlignContent::SpaceEvenly => Some(taffy::AlignContent::SpaceEvenly), + } +} + +#[inline] +pub(crate) fn align_items(input: stylo::AlignItems) -> Option { + match input { + stylo::AlignItems::Stretch => Some(taffy::AlignItems::Stretch), + stylo::AlignItems::FlexStart => Some(taffy::AlignItems::FlexStart), + stylo::AlignItems::FlexEnd => Some(taffy::AlignItems::FlexEnd), + stylo::AlignItems::Center => Some(taffy::AlignItems::Center), + stylo::AlignItems::Baseline => Some(taffy::AlignItems::Baseline), + } +} + +#[inline] +pub(crate) fn align_self(input: stylo::AlignSelf) -> Option { + match input { + stylo::AlignSelf::Auto => None, + stylo::AlignSelf::Stretch => Some(taffy::AlignSelf::Stretch), + stylo::AlignSelf::FlexStart => Some(taffy::AlignSelf::FlexStart), + stylo::AlignSelf::FlexEnd => Some(taffy::AlignSelf::FlexEnd), + stylo::AlignSelf::Center => Some(taffy::AlignSelf::Center), + stylo::AlignSelf::Baseline => Some(taffy::AlignSelf::Baseline), + } +} + +// pub(crate) fn justify_items(input: stylo::JustifyItems) -> Option { +// match input { +// stylo::JustifyItems::Stretch => Some(taffy::JustifyItems::Stretch), +// stylo::JustifyItems::FlexStart => Some(taffy::JustifyItems::FlexStart), +// stylo::JustifyItems::FlexEnd => Some(taffy::JustifyItems::FlexEnd), +// stylo::JustifyItems::Center => Some(taffy::JustifyItems::Center), +// stylo::JustifyItems::Baseline => Some(taffy::JustifyItems::Baseline), +// } +// } + +// pub(crate) fn justify_self(input: stylo::JustifySelf) -> Option { +// match input { +// stylo::JustifySelf::Auto => None, +// stylo::JustifySelf::Stretch => Some(taffy::JustifySelf::Stretch), +// stylo::JustifySelf::FlexStart => Some(taffy::JustifySelf::FlexStart), +// stylo::JustifySelf::FlexEnd => Some(taffy::JustifySelf::FlexEnd), +// stylo::JustifySelf::Center => Some(taffy::JustifySelf::Center), +// stylo::JustifySelf::Baseline => Some(taffy::JustifySelf::Baseline), +// } +// }