gioser

tawasuyu/taffy

A high performance rust-powered UI layout library

HTML 5364Rust 86Markdown 12TOML 91841 Sutichaykuna

Stylo integration (#693)

* Make return type of grid track list functions generic

* Initial taffy_stylo crate (flexbox only)

* Use blitz branch of stylo

* Implement grid type conversions in taffy_stylo

* Fix clippy lints

* Use stylo main

* Module rename / reorganisation

9915b967e9809dc57f210de8fe5f7510e66806d6 · ruwaq Nico Burns · (2 wata ñawpaq) · tayta 902c3229c · kay commitpi sach'ata qhaway

Semántico sayk'uy · 143

src/compute/grid/mod.rs

src/style/grid.rs

src/style/mod.rs

taffy_stylo/src/arc.rs

taffy_stylo/src/borrowed.rs

taffy_stylo/src/convert.rs

taffy_stylo/src/lib.rs

10 qillqakuna · +1033 −52

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/src/compute/grid/explicit_grid.rs b/src/compute/grid/explicit_grid.rs
index d0e0b3afb..5ee2bfa84 100644
--- a/src/compute/grid/explicit_grid.rs
+++ b/src/compute/grid/explicit_grid.rs
@@ -15,12 +15,10 @@ use num_traits::float::FloatCore;
 /// Compute the number of rows and columns in the explicit grid
 pub(crate) fn compute_explicit_grid_size_in_axis(
     style: &impl GridContainerStyle,
+    template: &[TrackSizingFunction],
     inner_container_size: Size<Option<f32>>,
     axis: AbsoluteAxis,
 ) -> u16 {
-    // Load the grid-template-rows or grid-template-columns definition (depending on the axis)
-    let template = style.grid_template_tracks(axis);
-
     // If template contains no tracks, then there are trivially zero explicit tracks
     if template.is_empty() {
         return 0;
@@ -294,8 +292,18 @@ mod test {
     fn explicit_grid_sizing_no_repeats() {
         let grid_style = (600.0, 600.0, 2, 4).into_grid();
         let preferred_size = grid_style.size.map(|s| s.into_option());
-        let width = compute_explicit_grid_size_in_axis(&grid_style, preferred_size, AbsoluteAxis::Horizontal);
-        let height = compute_explicit_grid_size_in_axis(&grid_style, preferred_size, AbsoluteAxis::Vertical);
+        let width = compute_explicit_grid_size_in_axis(
+            &grid_style,
+            &grid_style.grid_template_columns,
+            preferred_size,
+            AbsoluteAxis::Horizontal,
+        );
+        let height = compute_explicit_grid_size_in_axis(
+            &grid_style,
+            &grid_style.grid_template_rows,
+            preferred_size,
+            AbsoluteAxis::Vertical,
+        );
         assert_eq!(width, 2);
         assert_eq!(height, 4);
     }
@@ -311,8 +319,18 @@ mod test {
             ..Default::default()
         };
         let preferred_size = grid_style.size.map(|s| s.into_option());
-        let width = compute_explicit_grid_size_in_axis(&grid_style, preferred_size, AbsoluteAxis::Horizontal);
-        let height = compute_explicit_grid_size_in_axis(&grid_style, preferred_size, AbsoluteAxis::Vertical);
+        let width = compute_explicit_grid_size_in_axis(
+            &grid_style,
+            &grid_style.grid_template_columns,
+            preferred_size,
+            AbsoluteAxis::Horizontal,
+        );
+        let height = compute_explicit_grid_size_in_axis(
+            &grid_style,
+            &grid_style.grid_template_rows,
+            preferred_size,
+            AbsoluteAxis::Vertical,
+        );
         assert_eq!(width, 3);
         assert_eq!(height, 4);
     }
@@ -328,8 +346,18 @@ mod test {
             ..Default::default()
         };
         let preferred_size = grid_style.size.map(|s| s.into_option());
-        let width = compute_explicit_grid_size_in_axis(&grid_style, preferred_size, AbsoluteAxis::Horizontal);
-        let height = compute_explicit_grid_size_in_axis(&grid_style, preferred_size, AbsoluteAxis::Vertical);
+        let width = compute_explicit_grid_size_in_axis(
+            &grid_style,
+            &grid_style.grid_template_columns,
+            preferred_size,
+            AbsoluteAxis::Horizontal,
+        );
+        let height = compute_explicit_grid_size_in_axis(
+            &grid_style,
+            &grid_style.grid_template_rows,
+            preferred_size,
+            AbsoluteAxis::Vertical,
+        );
         assert_eq!(width, 3);
         assert_eq!(height, 4);
     }
@@ -345,8 +373,18 @@ mod test {
             ..Default::default()
         };
         let inner_container_size = Size { width: Some(120.0), height: Some(80.0) };
-        let width = compute_explicit_grid_size_in_axis(&grid_style, inner_container_size, AbsoluteAxis::Horizontal);
-        let height = compute_explicit_grid_size_in_axis(&grid_style, inner_container_size, AbsoluteAxis::Vertical);
+        let width = compute_explicit_grid_size_in_axis(
+            &grid_style,
+            &grid_style.grid_template_columns,
+            inner_container_size,
+            AbsoluteAxis::Horizontal,
+        );
+        let height = compute_explicit_grid_size_in_axis(
+            &grid_style,
+            &grid_style.grid_template_rows,
+            inner_container_size,
+            AbsoluteAxis::Vertical,
+        );
         assert_eq!(width, 3);
         assert_eq!(height, 4);
     }
@@ -362,8 +400,18 @@ mod test {
             ..Default::default()
         };
         let inner_container_size = Size { width: Some(140.0), height: Some(90.0) };
-        let width = compute_explicit_grid_size_in_axis(&grid_style, inner_container_size, AbsoluteAxis::Horizontal);
-        let height = compute_explicit_grid_size_in_axis(&grid_style, inner_container_size, AbsoluteAxis::Vertical);
+        let width = compute_explicit_grid_size_in_axis(
+            &grid_style,
+            &grid_style.grid_template_columns,
+            inner_container_size,
+            AbsoluteAxis::Horizontal,
+        );
+        let height = compute_explicit_grid_size_in_axis(
+            &grid_style,
+            &grid_style.grid_template_rows,
+            inner_container_size,
+            AbsoluteAxis::Vertical,
+        );
         assert_eq!(width, 4);
         assert_eq!(height, 5);
     }
@@ -379,8 +427,18 @@ mod test {
             ..Default::default()
         };
         let preferred_size = grid_style.size.map(|s| s.into_option());
-        let width = compute_explicit_grid_size_in_axis(&grid_style, preferred_size, AbsoluteAxis::Horizontal);
-        let height = compute_explicit_grid_size_in_axis(&grid_style, preferred_size, AbsoluteAxis::Vertical);
+        let width = compute_explicit_grid_size_in_axis(
+            &grid_style,
+            &grid_style.grid_template_columns,
+            preferred_size,
+            AbsoluteAxis::Horizontal,
+        );
+        let height = compute_explicit_grid_size_in_axis(
+            &grid_style,
+            &grid_style.grid_template_rows,
+            preferred_size,
+            AbsoluteAxis::Vertical,
+        );
         assert_eq!(width, 4); // 2 repetitions * 2 repeated tracks = 4 tracks in total
         assert_eq!(height, 6); // 3 repetitions * 2 repeated tracks = 4 tracks in total
     }
@@ -397,8 +455,18 @@ mod test {
             ..Default::default()
         };
         let preferred_size = grid_style.size.map(|s| s.into_option());
-        let width = compute_explicit_grid_size_in_axis(&grid_style, preferred_size, AbsoluteAxis::Horizontal);
-        let height = compute_explicit_grid_size_in_axis(&grid_style, preferred_size, AbsoluteAxis::Vertical);
+        let width = compute_explicit_grid_size_in_axis(
+            &grid_style,
+            &grid_style.grid_template_columns,
+            preferred_size,
+            AbsoluteAxis::Horizontal,
+        );
+        let height = compute_explicit_grid_size_in_axis(
+            &grid_style,
+            &grid_style.grid_template_rows,
+            preferred_size,
+            AbsoluteAxis::Vertical,
+        );
         assert_eq!(width, 2); // 2 tracks + 1 gap
         assert_eq!(height, 3); // 3 tracks + 2 gaps
     }
@@ -414,8 +482,18 @@ mod test {
             ..Default::default()
         };
         let preferred_size = grid_style.size.map(|s| s.into_option());
-        let width = compute_explicit_grid_size_in_axis(&grid_style, preferred_size, AbsoluteAxis::Horizontal);
-        let height = compute_explicit_grid_size_in_axis(&grid_style, preferred_size, AbsoluteAxis::Vertical);
+        let width = compute_explicit_grid_size_in_axis(
+            &grid_style,
+            &grid_style.grid_template_columns,
+            preferred_size,
+            AbsoluteAxis::Horizontal,
+        );
+        let height = compute_explicit_grid_size_in_axis(
+            &grid_style,
+            &grid_style.grid_template_rows,
+            preferred_size,
+            AbsoluteAxis::Vertical,
+        );
         assert_eq!(width, 3);
         assert_eq!(height, 1);
     }
@@ -432,8 +510,18 @@ mod test {
             ..Default::default()
         };
         let preferred_size = grid_style.size.map(|s| s.into_option());
-        let width = compute_explicit_grid_size_in_axis(&grid_style, preferred_size, AbsoluteAxis::Horizontal);
-        let height = compute_explicit_grid_size_in_axis(&grid_style, preferred_size, AbsoluteAxis::Vertical);
+        let width = compute_explicit_grid_size_in_axis(
+            &grid_style,
+            &grid_style.grid_template_columns,
+            preferred_size,
+            AbsoluteAxis::Horizontal,
+        );
+        let height = compute_explicit_grid_size_in_axis(
+            &grid_style,
+            &grid_style.grid_template_rows,
+            preferred_size,
+            AbsoluteAxis::Vertical,
+        );
         assert_eq!(width, 3); // 3 tracks + 2 gaps
         assert_eq!(height, 2); // 2 tracks + 1 gap
     }
@@ -450,8 +538,18 @@ mod test {
             ..Default::default()
         };
         let inner_container_size = Size { width: Some(100.0), height: Some(80.0) };
-        let width = compute_explicit_grid_size_in_axis(&grid_style, inner_container_size, AbsoluteAxis::Horizontal);
-        let height = compute_explicit_grid_size_in_axis(&grid_style, inner_container_size, AbsoluteAxis::Vertical);
+        let width = compute_explicit_grid_size_in_axis(
+            &grid_style,
+            &grid_style.grid_template_columns,
+            inner_container_size,
+            AbsoluteAxis::Horizontal,
+        );
+        let height = compute_explicit_grid_size_in_axis(
+            &grid_style,
+            &grid_style.grid_template_rows,
+            inner_container_size,
+            AbsoluteAxis::Vertical,
+        );
         assert_eq!(width, 5); // 40px horizontal padding
         assert_eq!(height, 4); // 20px vertical padding
     }
diff --git a/src/compute/grid/mod.rs b/src/compute/grid/mod.rs
index c15c98e7b..5bba6bdfb 100644
--- a/src/compute/grid/mod.rs
+++ b/src/compute/grid/mod.rs
@@ -1,5 +1,7 @@
 //! This module is a partial implementation of the CSS Grid Level 1 specification
 //! <https://www.w3.org/TR/css-grid-1>
+use core::borrow::Borrow;
+
 use crate::geometry::{AbsoluteAxis, AbstractAxis, InBothAbsAxis};
 use crate::geometry::{Line, Point, Rect, Size};
 use crate::style::{AlignItems, AlignSelf, AvailableSpace, Overflow, Position};
@@ -89,6 +91,13 @@ pub fn compute_grid_layout(tree: &mut impl LayoutGridContainer, node: NodeId, in
     let align_items = style.align_items();
     let justify_items = style.justify_items();
 
+    // Note: we avoid accessing the grid rows/columns methods more than once as this can
+    // cause an expensive-ish computation
+    let grid_template_columms = style.grid_template_columns();
+    let grid_template_rows = style.grid_template_rows();
+    let grid_auto_columms = style.grid_auto_columns();
+    let grid_auto_rows = style.grid_auto_rows();
+
     let constrained_available_space = known_dimensions
         .or(preferred_size)
         .map(|size| size.map(AvailableSpace::Definite))
@@ -137,10 +146,18 @@ pub fn compute_grid_layout(tree: &mut impl LayoutGridContainer, node: NodeId, in
         .maybe_sub(content_box_inset.sum_axes());
 
     // Exactly compute the number of rows and columns in the explicit grid.
-    let explicit_col_count =
-        compute_explicit_grid_size_in_axis(&style, auto_fit_container_size, AbsoluteAxis::Horizontal);
-    let explicit_row_count =
-        compute_explicit_grid_size_in_axis(&style, auto_fit_container_size, AbsoluteAxis::Vertical);
+    let explicit_col_count = compute_explicit_grid_size_in_axis(
+        &style,
+        grid_template_columms.borrow(),
+        auto_fit_container_size,
+        AbsoluteAxis::Horizontal,
+    );
+    let explicit_row_count = compute_explicit_grid_size_in_axis(
+        &style,
+        grid_template_rows.borrow(),
+        auto_fit_container_size,
+        AbsoluteAxis::Vertical,
+    );
 
     // 3. Implicit Grid: Estimate Track Counts
     // Estimate the number of rows and columns in the implicit grid (= the entire grid)
@@ -181,20 +198,24 @@ pub fn compute_grid_layout(tree: &mut impl LayoutGridContainer, node: NodeId, in
     initialize_grid_tracks(
         &mut columns,
         final_col_counts,
-        style.grid_template_columns(),
-        style.grid_auto_columns(),
+        grid_template_columms.borrow(),
+        grid_auto_columms.borrow(),
         style.gap().width,
         |column_index| cell_occupancy_matrix.column_is_occupied(column_index),
     );
     initialize_grid_tracks(
         &mut rows,
         final_row_counts,
-        style.grid_template_rows(),
-        style.grid_auto_rows(),
+        grid_template_rows.borrow(),
+        grid_auto_rows.borrow(),
         style.gap().height,
         |row_index| cell_occupancy_matrix.row_is_occupied(row_index),
     );
 
+    drop(grid_template_rows);
+    drop(grid_template_columms);
+    drop(grid_auto_rows);
+    drop(grid_auto_columms);
     drop(style);
 
     // 6. Track Sizing
diff --git a/src/style/grid.rs b/src/style/grid.rs
index d2597e69c..e13142794 100644
--- a/src/style/grid.rs
+++ b/src/style/grid.rs
@@ -4,31 +4,33 @@ use crate::compute::grid::{GridCoordinate, GridLine, OriginZeroLine};
 use crate::geometry::{AbsoluteAxis, AbstractAxis, Line, MinMax, Size};
 use crate::style_helpers::*;
 use crate::util::sys::GridTrackVec;
+use core::borrow::Borrow;
 use core::cmp::{max, min};
 use core::convert::Infallible;
 
 /// The set of styles required for a CSS Grid container
 pub trait GridContainerStyle: CoreStyle {
+    /// The type returned by grid_template_rows and grid_template_columns
+    type TemplateTrackList<'a>: Borrow<[TrackSizingFunction]>
+    where
+        Self: 'a;
+    /// The type returned by grid_auto_rows and grid_auto_columns
+    type AutoTrackList<'a>: Borrow<[NonRepeatedTrackSizingFunction]>
+    where
+        Self: 'a;
+
+    // FIXME: re-add default implemenations for grid_{template,auto}_{rows,columns} once the
+    // associated_type_defaults feature (https://github.com/rust-lang/rust/issues/29661) is stabilised.
+
     /// Defines the track sizing functions (heights) of the grid rows
-    #[inline(always)]
-    fn grid_template_rows(&self) -> &[TrackSizingFunction] {
-        &[]
-    }
+    fn grid_template_rows(&self) -> Self::TemplateTrackList<'_>;
     /// Defines the track sizing functions (widths) of the grid columns
-    #[inline(always)]
-    fn grid_template_columns(&self) -> &[TrackSizingFunction] {
-        &[]
-    }
+    fn grid_template_columns(&self) -> Self::TemplateTrackList<'_>;
     /// Defines the size of implicitly created rows
-    #[inline(always)]
-    fn grid_auto_rows(&self) -> &[NonRepeatedTrackSizingFunction] {
-        &[]
-    }
+    fn grid_auto_rows(&self) -> Self::AutoTrackList<'_>;
     /// Defined the size of implicitly created columns
-    #[inline(always)]
-    fn grid_auto_columns(&self) -> &[NonRepeatedTrackSizingFunction] {
-        &[]
-    }
+    fn grid_auto_columns(&self) -> Self::AutoTrackList<'_>;
+
     /// Controls how items get placed into the grid for auto-placed items
     #[inline(always)]
     fn grid_auto_flow(&self) -> GridAutoFlow {
@@ -66,7 +68,7 @@ pub trait GridContainerStyle: CoreStyle {
 
     /// Get a grid item's row or column placement depending on the axis passed
     #[inline(always)]
-    fn grid_template_tracks(&self, axis: AbsoluteAxis) -> &[TrackSizingFunction] {
+    fn grid_template_tracks(&self, axis: AbsoluteAxis) -> Self::TemplateTrackList<'_> {
         match axis {
             AbsoluteAxis::Horizontal => self.grid_template_columns(),
             AbsoluteAxis::Vertical => self.grid_template_rows(),
diff --git a/src/style/mod.rs b/src/style/mod.rs
index 9c35d202b..51563c0f2 100644
--- a/src/style/mod.rs
+++ b/src/style/mod.rs
@@ -777,6 +777,9 @@ impl<T: FlexboxItemStyle> FlexboxItemStyle for &'_ T {
 
 #[cfg(feature = "grid")]
 impl GridContainerStyle for Style {
+    type TemplateTrackList<'a> = &'a [TrackSizingFunction] where Self: 'a;
+    type AutoTrackList<'a> = &'a [NonRepeatedTrackSizingFunction] where Self: 'a;
+
     #[inline(always)]
     fn grid_template_rows(&self) -> &[TrackSizingFunction] {
         &self.grid_template_rows
@@ -821,20 +824,23 @@ impl GridContainerStyle for Style {
 
 #[cfg(feature = "grid")]
 impl<T: GridContainerStyle> GridContainerStyle for &'_ T {
+    type TemplateTrackList<'a> = T::TemplateTrackList<'a> where Self: 'a;
+    type AutoTrackList<'a> = T::AutoTrackList<'a> where Self: 'a;
+
     #[inline(always)]
-    fn grid_template_rows(&self) -> &[TrackSizingFunction] {
+    fn grid_template_rows(&self) -> Self::TemplateTrackList<'_> {
         (*self).grid_template_rows()
     }
     #[inline(always)]
-    fn grid_template_columns(&self) -> &[TrackSizingFunction] {
+    fn grid_template_columns(&self) -> Self::TemplateTrackList<'_> {
         (*self).grid_template_columns()
     }
     #[inline(always)]
-    fn grid_auto_rows(&self) -> &[NonRepeatedTrackSizingFunction] {
+    fn grid_auto_rows(&self) -> Self::AutoTrackList<'_> {
         (*self).grid_auto_rows()
     }
     #[inline(always)]
-    fn grid_auto_columns(&self) -> &[NonRepeatedTrackSizingFunction] {
+    fn grid_auto_columns(&self) -> Self::AutoTrackList<'_> {
         (*self).grid_auto_columns()
     }
     #[inline(always)]
diff --git a/taffy_stylo/Cargo.toml b/taffy_stylo/Cargo.toml
new file mode 100644
index 000000000..02a73c8c9
--- /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-07-16", features = ["servo"] }
+servo_arc = { git = "https://github.com/servo/stylo", branch = "2024-07-16" }
\ 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..50f12cece
--- /dev/null
+++ b/taffy_stylo/src/arc.rs
@@ -0,0 +1,261 @@
+use crate::convert;
+use servo_arc::Arc;
+use style::properties::generated::ComputedValues;
+
+pub struct TaffyStyloStyle(pub Arc<ComputedValues>);
+
+impl From<Arc<ComputedValues>> for TaffyStyloStyle {
+    fn from(value: Arc<ComputedValues>) -> Self {
+        Self(Arc::clone(&value))
+    }
+}
+
+impl taffy::CoreStyle for TaffyStyloStyle {
+    #[inline]
+    fn box_generation_mode(&self) -> taffy::BoxGenerationMode {
+        convert::box_generation_mode(self.0.get_box().display)
+    }
+
+    #[inline]
+    fn is_block(&self) -> bool {
+        convert::is_block(self.0.get_box().display)
+    }
+
+    #[inline]
+    fn box_sizing(&self) -> taffy::BoxSizing {
+        convert::box_sizing(self.0.get_position().box_sizing)
+    }
+
+    #[inline]
+    fn overflow(&self) -> taffy::Point<taffy::Overflow> {
+        let box_styles = self.0.get_box();
+        taffy::Point { x: convert::overflow(box_styles.overflow_x), y: convert::overflow(box_styles.overflow_y) }
+    }
+
+    #[inline]
+    fn scrollbar_width(&self) -> f32 {
+        0.0
+    }
+
+    #[inline]
+    fn position(&self) -> taffy::Position {
+        convert::position(self.0.get_box().position)
+    }
+
+    #[inline]
+    fn inset(&self) -> taffy::Rect<taffy::LengthPercentageAuto> {
+        let position_styles = self.0.get_position();
+        taffy::Rect {
+            left: convert::length_percentage_auto(&position_styles.left),
+            right: convert::length_percentage_auto(&position_styles.right),
+            top: convert::length_percentage_auto(&position_styles.top),
+            bottom: convert::length_percentage_auto(&position_styles.bottom),
+        }
+    }
+
+    #[inline]
+    fn size(&self) -> taffy::Size<taffy::Dimension> {
+        let position_styles = self.0.get_position();
+        taffy::Size {
+            width: convert::dimension(&position_styles.width),
+            height: convert::dimension(&position_styles.height),
+        }
+    }
+
+    #[inline]
+    fn min_size(&self) -> taffy::Size<taffy::Dimension> {
+        let position_styles = self.0.get_position();
+        taffy::Size {
+            width: convert::dimension(&position_styles.min_width),
+            height: convert::dimension(&position_styles.min_height),
+        }
+    }
+
+    #[inline]
+    fn max_size(&self) -> taffy::Size<taffy::Dimension> {
+        let position_styles = self.0.get_position();
+        taffy::Size {
+            width: convert::max_size_dimension(&position_styles.max_width),
+            height: convert::max_size_dimension(&position_styles.max_height),
+        }
+    }
+
+    #[inline]
+    fn aspect_ratio(&self) -> Option<f32> {
+        convert::aspect_ratio(self.0.get_position().aspect_ratio)
+    }
+
+    #[inline]
+    fn margin(&self) -> taffy::Rect<taffy::LengthPercentageAuto> {
+        let margin_styles = self.0.get_margin();
+        taffy::Rect {
+            left: convert::length_percentage_auto(&margin_styles.margin_left),
+            right: convert::length_percentage_auto(&margin_styles.margin_right),
+            top: convert::length_percentage_auto(&margin_styles.margin_top),
+            bottom: convert::length_percentage_auto(&margin_styles.margin_bottom),
+        }
+    }
+
+    #[inline]
+    fn padding(&self) -> taffy::Rect<taffy::LengthPercentage> {
+        let padding_styles = self.0.get_padding();
+        taffy::Rect {
+            left: convert::length_percentage(&padding_styles.padding_left.0),
+            right: convert::length_percentage(&padding_styles.padding_right.0),
+            top: convert::length_percentage(&padding_styles.padding_top.0),
+            bottom: convert::length_percentage(&padding_styles.padding_bottom.0),
+        }
+    }
+
+    #[inline]
+    fn border(&self) -> taffy::Rect<taffy::LengthPercentage> {
+        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 {
+        convert::flex_direction(self.0.get_position().flex_direction)
+    }
+
+    #[inline]
+    fn flex_wrap(&self) -> taffy::FlexWrap {
+        convert::flex_wrap(self.0.get_position().flex_wrap)
+    }
+
+    #[inline]
+    fn gap(&self) -> taffy::Size<taffy::LengthPercentage> {
+        let position_styles = self.0.get_position();
+        taffy::Size { width: convert::gap(&position_styles.column_gap), height: convert::gap(&position_styles.row_gap) }
+    }
+
+    #[inline]
+    fn align_content(&self) -> Option<taffy::AlignContent> {
+        convert::content_alignment(self.0.get_position().align_content.0)
+    }
+
+    #[inline]
+    fn align_items(&self) -> Option<taffy::AlignItems> {
+        convert::item_alignment(self.0.get_position().align_items.0)
+    }
+
+    #[inline]
+    fn justify_content(&self) -> Option<taffy::JustifyContent> {
+        convert::content_alignment(self.0.get_position().justify_content.0)
+    }
+}
+
+impl taffy::FlexboxItemStyle for TaffyStyloStyle {
+    #[inline]
+    fn flex_basis(&self) -> taffy::Dimension {
+        convert::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<taffy::AlignSelf> {
+        convert::item_alignment(self.0.get_position().align_self.0 .0)
+    }
+}
+
+impl taffy::GridContainerStyle for TaffyStyloStyle {
+    type TemplateTrackList<'a> = Vec<taffy::TrackSizingFunction> where Self: 'a;
+    type AutoTrackList<'a> = Vec<taffy::NonRepeatedTrackSizingFunction> where Self: 'a;
+
+    #[inline]
+    fn grid_template_rows(&self) -> Self::TemplateTrackList<'_> {
+        convert::grid_template_tracks(&self.0.get_position().grid_template_rows)
+    }
+
+    #[inline]
+    fn grid_template_columns(&self) -> Self::TemplateTrackList<'_> {
+        convert::grid_template_tracks(&self.0.get_position().grid_template_columns)
+    }
+
+    #[inline]
+    fn grid_auto_rows(&self) -> Self::AutoTrackList<'_> {
+        convert::grid_auto_tracks(&self.0.get_position().grid_auto_rows)
+    }
+
+    #[inline]
+    fn grid_auto_columns(&self) -> Self::AutoTrackList<'_> {
+        convert::grid_auto_tracks(&self.0.get_position().grid_auto_columns)
+    }
+
+    #[inline]
+    fn grid_auto_flow(&self) -> taffy::GridAutoFlow {
+        convert::grid_auto_flow(self.0.get_position().grid_auto_flow)
+    }
+
+    #[inline]
+    fn gap(&self) -> taffy::Size<taffy::LengthPercentage> {
+        let position_styles = self.0.get_position();
+        taffy::Size { width: convert::gap(&position_styles.column_gap), height: convert::gap(&position_styles.row_gap) }
+    }
+
+    #[inline]
+    fn align_content(&self) -> Option<taffy::AlignContent> {
+        convert::content_alignment(self.0.get_position().align_content.0)
+    }
+
+    #[inline]
+    fn justify_content(&self) -> Option<taffy::JustifyContent> {
+        convert::content_alignment(self.0.get_position().justify_content.0)
+    }
+
+    #[inline]
+    fn align_items(&self) -> Option<taffy::AlignItems> {
+        convert::item_alignment(self.0.get_position().align_items.0)
+    }
+
+    #[inline]
+    fn justify_items(&self) -> Option<taffy::AlignItems> {
+        convert::item_alignment(self.0.get_position().justify_items.computed.0)
+    }
+}
+
+impl taffy::GridItemStyle for TaffyStyloStyle {
+    #[inline]
+    fn grid_row(&self) -> taffy::Line<taffy::GridPlacement> {
+        let position_styles = self.0.get_position();
+        taffy::Line {
+            start: convert::grid_line(&position_styles.grid_row_start),
+            end: convert::grid_line(&position_styles.grid_row_end),
+        }
+    }
+
+    #[inline]
+    fn grid_column(&self) -> taffy::Line<taffy::GridPlacement> {
+        let position_styles = self.0.get_position();
+        taffy::Line {
+            start: convert::grid_line(&position_styles.grid_column_start),
+            end: convert::grid_line(&position_styles.grid_column_end),
+        }
+    }
+
+    #[inline]
+    fn align_self(&self) -> Option<taffy::AlignSelf> {
+        convert::item_alignment(self.0.get_position().align_self.0 .0)
+    }
+
+    #[inline]
+    fn justify_self(&self) -> Option<taffy::AlignSelf> {
+        convert::item_alignment(self.0.get_position().justify_self.0 .0)
+    }
+}
diff --git a/taffy_stylo/src/borrowed.rs b/taffy_stylo/src/borrowed.rs
new file mode 100644
index 000000000..d67753fe7
--- /dev/null
+++ b/taffy_stylo/src/borrowed.rs
@@ -0,0 +1,260 @@
+use crate::convert;
+use style::properties::generated::ComputedValues;
+
+pub struct TaffyStyloStyleRef<'a>(pub &'a ComputedValues);
+
+impl<'a> From<&'a ComputedValues> for TaffyStyloStyleRef<'a> {
+    fn from(value: &'a ComputedValues) -> Self {
+        Self(value)
+    }
+}
+
+impl taffy::CoreStyle for TaffyStyloStyleRef<'_> {
+    #[inline]
+    fn box_generation_mode(&self) -> taffy::BoxGenerationMode {
+        convert::box_generation_mode(self.0.get_box().display)
+    }
+
+    #[inline]
+    fn is_block(&self) -> bool {
+        convert::is_block(self.0.get_box().display)
+    }
+
+    #[inline]
+    fn box_sizing(&self) -> taffy::BoxSizing {
+        convert::box_sizing(self.0.get_position().box_sizing)
+    }
+
+    #[inline]
+    fn overflow(&self) -> taffy::Point<taffy::Overflow> {
+        let box_styles = self.0.get_box();
+        taffy::Point { x: convert::overflow(box_styles.overflow_x), y: convert::overflow(box_styles.overflow_y) }
+    }
+
+    #[inline]
+    fn scrollbar_width(&self) -> f32 {
+        0.0
+    }
+
+    #[inline]
+    fn position(&self) -> taffy::Position {
+        convert::position(self.0.get_box().position)
+    }
+
+    #[inline]
+    fn inset(&self) -> taffy::Rect<taffy::LengthPercentageAuto> {
+        let position_styles = self.0.get_position();
+        taffy::Rect {
+            left: convert::length_percentage_auto(&position_styles.left),
+            right: convert::length_percentage_auto(&position_styles.right),
+            top: convert::length_percentage_auto(&position_styles.top),
+            bottom: convert::length_percentage_auto(&position_styles.bottom),
+        }
+    }
+
+    #[inline]
+    fn size(&self) -> taffy::Size<taffy::Dimension> {
+        let position_styles = self.0.get_position();
+        taffy::Size {
+            width: convert::dimension(&position_styles.width),
+            height: convert::dimension(&position_styles.height),
+        }
+    }
+
+    #[inline]
+    fn min_size(&self) -> taffy::Size<taffy::Dimension> {
+        let position_styles = self.0.get_position();
+        taffy::Size {
+            width: convert::dimension(&position_styles.min_width),
+            height: convert::dimension(&position_styles.min_height),
+        }
+    }
+
+    #[inline]
+    fn max_size(&self) -> taffy::Size<taffy::Dimension> {
+        let position_styles = self.0.get_position();
+        taffy::Size {
+            width: convert::max_size_dimension(&position_styles.max_width),
+            height: convert::max_size_dimension(&position_styles.max_height),
+        }
+    }
+
+    #[inline]
+    fn aspect_ratio(&self) -> Option<f32> {
+        convert::aspect_ratio(self.0.get_position().aspect_ratio)
+    }
+
+    #[inline]
+    fn margin(&self) -> taffy::Rect<taffy::LengthPercentageAuto> {
+        let margin_styles = self.0.get_margin();
+        taffy::Rect {
+            left: convert::length_percentage_auto(&margin_styles.margin_left),
+            right: convert::length_percentage_auto(&margin_styles.margin_right),
+            top: convert::length_percentage_auto(&margin_styles.margin_top),
+            bottom: convert::length_percentage_auto(&margin_styles.margin_bottom),
+        }
+    }
+
+    #[inline]
+    fn padding(&self) -> taffy::Rect<taffy::LengthPercentage> {
+        let padding_styles = self.0.get_padding();
+        taffy::Rect {
+            left: convert::length_percentage(&padding_styles.padding_left.0),
+            right: convert::length_percentage(&padding_styles.padding_right.0),
+            top: convert::length_percentage(&padding_styles.padding_top.0),
+            bottom: convert::length_percentage(&padding_styles.padding_bottom.0),
+        }
+    }
+
+    #[inline]
+    fn border(&self) -> taffy::Rect<taffy::LengthPercentage> {
+        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 {
+        convert::flex_direction(self.0.get_position().flex_direction)
+    }
+
+    #[inline]
+    fn flex_wrap(&self) -> taffy::FlexWrap {
+        convert::flex_wrap(self.0.get_position().flex_wrap)
+    }
+
+    #[inline]
+    fn gap(&self) -> taffy::Size<taffy::LengthPercentage> {
+        let position_styles = self.0.get_position();
+        taffy::Size { width: convert::gap(&position_styles.column_gap), height: convert::gap(&position_styles.row_gap) }
+    }
+
+    #[inline]
+    fn align_content(&self) -> Option<taffy::AlignContent> {
+        convert::content_alignment(self.0.get_position().align_content.0)
+    }
+
+    #[inline]
+    fn align_items(&self) -> Option<taffy::AlignItems> {
+        convert::item_alignment(self.0.get_position().align_items.0)
+    }
+
+    #[inline]
+    fn justify_content(&self) -> Option<taffy::JustifyContent> {
+        convert::content_alignment(self.0.get_position().justify_content.0)
+    }
+}
+
+impl taffy::FlexboxItemStyle for TaffyStyloStyleRef<'_> {
+    #[inline]
+    fn flex_basis(&self) -> taffy::Dimension {
+        convert::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<taffy::AlignSelf> {
+        convert::item_alignment(self.0.get_position().align_self.0 .0)
+    }
+}
+
+impl taffy::GridContainerStyle for TaffyStyloStyleRef<'_> {
+    type TemplateTrackList<'a> = Vec<taffy::TrackSizingFunction> where Self: 'a;
+    type AutoTrackList<'a> = Vec<taffy::NonRepeatedTrackSizingFunction> where Self: 'a;
+
+    #[inline]
+    fn grid_template_rows(&self) -> Self::TemplateTrackList<'_> {
+        convert::grid_template_tracks(&self.0.get_position().grid_template_rows)
+    }
+
+    #[inline]
+    fn grid_template_columns(&self) -> Self::TemplateTrackList<'_> {
+        convert::grid_template_tracks(&self.0.get_position().grid_template_columns)
+    }
+
+    #[inline]
+    fn grid_auto_rows(&self) -> Self::AutoTrackList<'_> {
+        convert::grid_auto_tracks(&self.0.get_position().grid_auto_rows)
+    }
+
+    #[inline]
+    fn grid_auto_columns(&self) -> Self::AutoTrackList<'_> {
+        convert::grid_auto_tracks(&self.0.get_position().grid_auto_columns)
+    }
+
+    #[inline]
+    fn grid_auto_flow(&self) -> taffy::GridAutoFlow {
+        convert::grid_auto_flow(self.0.get_position().grid_auto_flow)
+    }
+
+    #[inline]
+    fn gap(&self) -> taffy::Size<taffy::LengthPercentage> {
+        let position_styles = self.0.get_position();
+        taffy::Size { width: convert::gap(&position_styles.column_gap), height: convert::gap(&position_styles.row_gap) }
+    }
+
+    #[inline]
+    fn align_content(&self) -> Option<taffy::AlignContent> {
+        convert::content_alignment(self.0.get_position().align_content.0)
+    }
+
+    #[inline]
+    fn justify_content(&self) -> Option<taffy::JustifyContent> {
+        convert::content_alignment(self.0.get_position().justify_content.0)
+    }
+
+    #[inline]
+    fn align_items(&self) -> Option<taffy::AlignItems> {
+        convert::item_alignment(self.0.get_position().align_items.0)
+    }
+
+    #[inline]
+    fn justify_items(&self) -> Option<taffy::AlignItems> {
+        convert::item_alignment(self.0.get_position().justify_items.computed.0)
+    }
+}
+
+impl taffy::GridItemStyle for TaffyStyloStyleRef<'_> {
+    #[inline]
+    fn grid_row(&self) -> taffy::Line<taffy::GridPlacement> {
+        let position_styles = self.0.get_position();
+        taffy::Line {
+            start: convert::grid_line(&position_styles.grid_row_start),
+            end: convert::grid_line(&position_styles.grid_row_end),
+        }
+    }
+
+    #[inline]
+    fn grid_column(&self) -> taffy::Line<taffy::GridPlacement> {
+        let position_styles = self.0.get_position();
+        taffy::Line {
+            start: convert::grid_line(&position_styles.grid_column_start),
+            end: convert::grid_line(&position_styles.grid_column_end),
+        }
+    }
+
+    #[inline]
+    fn align_self(&self) -> Option<taffy::AlignSelf> {
+        convert::item_alignment(self.0.get_position().align_self.0 .0)
+    }
+
+    #[inline]
+    fn justify_self(&self) -> Option<taffy::AlignSelf> {
+        convert::item_alignment(self.0.get_position().justify_self.0 .0)
+    }
+}
diff --git a/taffy_stylo/src/convert.rs b/taffy_stylo/src/convert.rs
new file mode 100644
index 000000000..66a7c6a03
--- /dev/null
+++ b/taffy_stylo/src/convert.rs
@@ -0,0 +1,312 @@
+// Module of type aliases so we can refer to stylo types with nicer names
+mod stylo {
+    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::grid_auto_flow::T as GridAutoFlow;
+    pub(crate) use style::properties::generated::longhands::box_sizing::computed_value::T as BoxSizing;
+    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::values::specified::align::AlignFlags;
+    pub(crate) use style::values::specified::align::ContentDistribution;
+    // pub(crate) use style::properties::style_structs::{Margin, Padding};
+    pub(crate) use style::values::computed::GridLine;
+    pub(crate) use style::values::computed::GridTemplateComponent;
+    pub(crate) use style::values::computed::ImplicitGridTracks;
+    pub(crate) use style::values::computed::LengthPercentage;
+    pub(crate) use style::values::generics::flex::GenericFlexBasis;
+    pub(crate) use style::values::generics::grid::RepeatCount;
+    pub(crate) use style::values::generics::grid::TrackBreadth;
+    pub(crate) use style::values::generics::grid::TrackListValue;
+    pub(crate) use style::values::generics::grid::TrackSize;
+    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) use style::values::specified::GenericGridTemplateComponent;
+    pub(crate) type LengthPercentageAuto = GenericLengthPercentageOrAuto<LengthPercentage>;
+    pub(crate) type Size = GenericSize<NonNegative<LengthPercentage>>;
+    pub(crate) type MaxSize = GenericMaxSize<NonNegative<LengthPercentage>>;
+    pub(crate) type FlexBasis = GenericFlexBasis<Size>;
+    pub(crate) type Gap = GenericLengthPercentageOrNormal<NonNegative<LengthPercentage>>;
+}
+
+#[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 box_sizing(input: stylo::BoxSizing) -> taffy::BoxSizing {
+    match input {
+        stylo::BoxSizing::BorderBox => taffy::BoxSizing::BorderBox,
+        stylo::BoxSizing::ContentBox => taffy::BoxSizing::ContentBox,
+    }
+}
+
+#[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<f32> {
+    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),
+    }
+}
+
+#[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 content_alignment(input: stylo::ContentDistribution) -> Option<taffy::AlignContent> {
+    match input.primary().value() {
+        stylo::AlignFlags::NORMAL => None,
+        stylo::AlignFlags::AUTO => None,
+        stylo::AlignFlags::START => Some(taffy::AlignContent::Start),
+        stylo::AlignFlags::END => Some(taffy::AlignContent::End),
+        stylo::AlignFlags::FLEX_START => Some(taffy::AlignContent::FlexStart),
+        stylo::AlignFlags::STRETCH => Some(taffy::AlignContent::Stretch),
+        stylo::AlignFlags::FLEX_END => Some(taffy::AlignContent::FlexEnd),
+        stylo::AlignFlags::CENTER => Some(taffy::AlignContent::Center),
+        stylo::AlignFlags::SPACE_BETWEEN => Some(taffy::AlignContent::SpaceBetween),
+        stylo::AlignFlags::SPACE_AROUND => Some(taffy::AlignContent::SpaceAround),
+        stylo::AlignFlags::SPACE_EVENLY => Some(taffy::AlignContent::SpaceEvenly),
+        // Should never be hit. But no real reason to panic here.
+        _ => None,
+    }
+}
+
+#[inline]
+pub(crate) fn item_alignment(input: stylo::AlignFlags) -> Option<taffy::AlignItems> {
+    match input.value() {
+        stylo::AlignFlags::NORMAL => None,
+        stylo::AlignFlags::AUTO => None,
+        stylo::AlignFlags::STRETCH => Some(taffy::AlignItems::Stretch),
+        stylo::AlignFlags::FLEX_START => Some(taffy::AlignItems::FlexStart),
+        stylo::AlignFlags::FLEX_END => Some(taffy::AlignItems::FlexEnd),
+        stylo::AlignFlags::START => Some(taffy::AlignItems::Start),
+        stylo::AlignFlags::END => Some(taffy::AlignItems::End),
+        stylo::AlignFlags::CENTER => Some(taffy::AlignItems::Center),
+        stylo::AlignFlags::BASELINE => Some(taffy::AlignItems::Baseline),
+        // Should never be hit. But no real reason to panic here.
+        _ => None,
+    }
+}
+
+#[inline]
+pub(crate) fn grid_auto_flow(input: stylo::GridAutoFlow) -> taffy::GridAutoFlow {
+    let is_row = input.contains(stylo::GridAutoFlow::ROW);
+    let is_dense = input.contains(stylo::GridAutoFlow::DENSE);
+
+    match (is_row, is_dense) {
+        (true, false) => taffy::GridAutoFlow::Row,
+        (true, true) => taffy::GridAutoFlow::RowDense,
+        (false, false) => taffy::GridAutoFlow::Column,
+        (false, true) => taffy::GridAutoFlow::ColumnDense,
+    }
+}
+
+#[inline]
+pub(crate) fn grid_line(input: &stylo::GridLine) -> taffy::GridPlacement {
+    if input.is_auto() {
+        taffy::GridPlacement::Auto
+    } else if input.is_span {
+        taffy::style_helpers::span(input.line_num.try_into().unwrap())
+    } else if input.line_num == 0 {
+        taffy::GridPlacement::Auto
+    } else {
+        taffy::style_helpers::line(input.line_num.try_into().unwrap())
+    }
+}
+
+#[inline]
+pub(crate) fn grid_template_tracks(input: &stylo::GridTemplateComponent) -> Vec<taffy::TrackSizingFunction> {
+    match input {
+        stylo::GenericGridTemplateComponent::None => Vec::new(),
+        stylo::GenericGridTemplateComponent::TrackList(list) => list
+            .values
+            .iter()
+            .map(|track| match track {
+                stylo::TrackListValue::TrackSize(size) => taffy::TrackSizingFunction::Single(track_size(size)),
+                stylo::TrackListValue::TrackRepeat(repeat) => taffy::TrackSizingFunction::Repeat(
+                    track_repeat(repeat.count),
+                    repeat.track_sizes.iter().map(track_size).collect(),
+                ),
+            })
+            .collect(),
+
+        // TODO: Implement subgrid and masonry
+        stylo::GenericGridTemplateComponent::Subgrid(_) => Vec::new(),
+        stylo::GenericGridTemplateComponent::Masonry => Vec::new(),
+    }
+}
+
+#[inline]
+pub(crate) fn grid_auto_tracks(input: &stylo::ImplicitGridTracks) -> Vec<taffy::NonRepeatedTrackSizingFunction> {
+    input.0.iter().map(track_size).collect()
+}
+
+#[inline]
+pub(crate) fn track_repeat(input: stylo::RepeatCount<i32>) -> taffy::GridTrackRepetition {
+    match input {
+        stylo::RepeatCount::Number(val) => taffy::GridTrackRepetition::Count(val.try_into().unwrap()),
+        stylo::RepeatCount::AutoFill => taffy::GridTrackRepetition::AutoFill,
+        stylo::RepeatCount::AutoFit => taffy::GridTrackRepetition::AutoFit,
+    }
+}
+
+#[inline]
+pub(crate) fn track_size(input: &stylo::TrackSize<stylo::LengthPercentage>) -> taffy::NonRepeatedTrackSizingFunction {
+    match input {
+        stylo::TrackSize::Breadth(breadth) => taffy::MinMax { min: min_track(breadth), max: max_track(breadth) },
+        stylo::TrackSize::Minmax(min, max) => taffy::MinMax { min: min_track(min), max: max_track(max) },
+        stylo::TrackSize::FitContent(limit) => taffy::MinMax {
+            min: taffy::MinTrackSizingFunction::Auto,
+            max: taffy::MaxTrackSizingFunction::FitContent(match limit {
+                stylo::TrackBreadth::Breadth(lp) => length_percentage(lp),
+
+                // Are these valid? Taffy doesn't support this in any case
+                stylo::TrackBreadth::Fr(_) => unreachable!(),
+                stylo::TrackBreadth::Auto => unreachable!(),
+                stylo::TrackBreadth::MinContent => unreachable!(),
+                stylo::TrackBreadth::MaxContent => unreachable!(),
+            }),
+        },
+    }
+}
+
+#[inline]
+pub(crate) fn min_track(input: &stylo::TrackBreadth<stylo::LengthPercentage>) -> taffy::MinTrackSizingFunction {
+    match input {
+        stylo::TrackBreadth::Breadth(lp) => taffy::MinTrackSizingFunction::Fixed(length_percentage(lp)),
+        stylo::TrackBreadth::Fr(_) => taffy::MinTrackSizingFunction::Auto,
+        stylo::TrackBreadth::Auto => taffy::MinTrackSizingFunction::Auto,
+        stylo::TrackBreadth::MinContent => taffy::MinTrackSizingFunction::MinContent,
+        stylo::TrackBreadth::MaxContent => taffy::MinTrackSizingFunction::MaxContent,
+    }
+}
+
+#[inline]
+pub(crate) fn max_track(input: &stylo::TrackBreadth<stylo::LengthPercentage>) -> taffy::MaxTrackSizingFunction {
+    match input {
+        stylo::TrackBreadth::Breadth(lp) => taffy::MaxTrackSizingFunction::Fixed(length_percentage(lp)),
+        stylo::TrackBreadth::Fr(val) => taffy::MaxTrackSizingFunction::Fraction(*val),
+        stylo::TrackBreadth::Auto => taffy::MaxTrackSizingFunction::Auto,
+        stylo::TrackBreadth::MinContent => taffy::MaxTrackSizingFunction::MinContent,
+        stylo::TrackBreadth::MaxContent => taffy::MaxTrackSizingFunction::MaxContent,
+    }
+}
diff --git a/taffy_stylo/src/lib.rs b/taffy_stylo/src/lib.rs
new file mode 100644
index 000000000..c85bb7472
--- /dev/null
+++ b/taffy_stylo/src/lib.rs
@@ -0,0 +1,8 @@
+//! Conversion functions from Stylo types to Taffy types
+
+pub(crate) mod arc;
+pub(crate) mod borrowed;
+pub(crate) mod convert;
+
+pub use arc::TaffyStyloStyle;
+pub use borrowed::TaffyStyloStyleRef;