Skip to content

Commit

Permalink
Implement box-sizing: content-box (#675)
Browse files Browse the repository at this point in the history
* Add BoxSizing style

* Scrape box-sizing style when generating tests

* Generate tests for both BoxSizing::BorderBox and BoxSizing::ContentBox

* BoxSizing::ContentBox for Flexbox layout

* BoxSizing::ContentBox for Block, root and leaf layout

* BoxSizing::ContentBox for Grid layout
  • Loading branch information
nicoburns committed Jul 16, 2024
1 parent 9ec0875 commit a497676
Show file tree
Hide file tree
Showing 1,017 changed files with 158,087 additions and 1,136 deletions.
25 changes: 19 additions & 6 deletions scripts/gentest/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,13 @@ async fn main() {
.iter()
.map(|(name, fixture_path, description)| {
debug!("generating test contents for {}", &name);
(name.clone(), fixture_path, generate_test(name, description))

let border_box_test = generate_test(format!("{name}__border_box"), &description["borderBoxData"]);
let content_box_test = generate_test(format!("{name}__content_box"), &description["contentBoxData"]);

let test_file_content = [border_box_test, content_box_test].map(|test| test.to_string()).join("\n\n");

(name.clone(), fixture_path, test_file_content)
})
.collect();

Expand Down Expand Up @@ -145,7 +151,7 @@ async fn main() {
let mut test_filename = test_path.join(&name);
test_filename.set_extension("rs");
debug!("writing {} to disk...", &name);
fs::write(test_filename, test_body.to_string()).unwrap();
fs::write(test_filename, test_body).unwrap();
}

info!("formatting the source directory");
Expand Down Expand Up @@ -179,10 +185,7 @@ async fn test_root_element(client: Client, name: String, fixture_path: impl AsRe
let url = format!("file://{}", fixture_path.display());

client.goto(&url).await.unwrap();
let description = client
.execute("return JSON.stringify(describeElement(document.getElementById('test-root')))", vec![])
.await
.unwrap();
let description = client.execute("return getTestData()", vec![]).await.unwrap();
let description_string = description.as_str().unwrap();
let description = serde_json::from_str(description_string).unwrap();
(name.to_string(), fixture_path.to_path_buf(), description)
Expand Down Expand Up @@ -213,6 +216,7 @@ fn generate_test(name: impl AsRef<str>, description: &Value) -> TokenStream {

quote!(
#[test]
#[allow(non_snake_case)]
fn #name() {
#[allow(unused_imports)]
use taffy::{tree::Layout, prelude::*, TaffyTree};
Expand Down Expand Up @@ -373,6 +377,14 @@ fn generate_node(ident: &str, node: &Value) -> TokenStream {
_ => quote!(),
};

let box_sizing = match style["boxSizing"] {
Value::String(ref value) => match value.as_ref() {
"content-box" => quote!(box_sizing: taffy::style::BoxSizing::ContentBox,),
_ => quote!(),
},
_ => quote!(),
};

let position = match style["position"] {
Value::String(ref value) => match value.as_ref() {
"absolute" => quote!(position: taffy::style::Position::Absolute,),
Expand Down Expand Up @@ -603,6 +615,7 @@ fn generate_node(ident: &str, node: &Value) -> TokenStream {

let style = quote!(taffy::style::Style {
#display
#box_sizing
#direction
#position
#flex_direction
Expand Down
11 changes: 11 additions & 0 deletions scripts/gentest/test_base_style.css
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ div, span, img {
border: 0 solid red;
margin: 0;
padding: 0;
}

div {
display: flex;
}

Expand All @@ -47,6 +50,14 @@ body > * {
color: green;
}

.border-box, .border-box * {
box-sizing: border-box;
}

.content-box, .content-box * {
box-sizing: content-box;
}

div {
background-color: #222;
}
Expand Down
12 changes: 12 additions & 0 deletions scripts/gentest/test_helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -200,9 +200,12 @@ function describeElement(e) {
let boundingRect = e.getBoundingClientRect();
let parentBoundingRect = e.parentNode.getBoundingClientRect();

const computedStyle = getComputedStyle(e);

return {
style: {
display: parseEnum(e.style.display),
boxSizing: parseEnum(computedStyle.boxSizing),

position: parseEnum(e.style.position),
direction: parseEnum(e.style.direction),
Expand Down Expand Up @@ -326,6 +329,15 @@ function describeElement(e) {
};
}

function getTestData() {
document.body.className = "border-box";
const borderBoxData = describeElement(document.getElementById('test-root'));
document.body.className = "content-box";
const contentBoxData = describeElement(document.getElementById('test-root'));

return JSON.stringify({ borderBoxData, contentBoxData });
}

// Useful when developing this script. Logs the parsed style to the console when any test fixture is opened in a browser.
window.onload = function () {
try {
Expand Down
77 changes: 66 additions & 11 deletions src/compute/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use crate::util::sys::f32_max;
use crate::util::sys::Vec;
use crate::util::MaybeMath;
use crate::util::{MaybeResolve, ResolveOrZero};
use crate::BoxSizing;

#[cfg(feature = "content_size")]
use super::common::content_size::compute_content_size_contribution;
Expand Down Expand Up @@ -63,13 +64,29 @@ pub fn compute_block_layout(tree: &mut impl LayoutPartialTree, node_id: NodeId,

// Pull these out earlier to avoid borrowing issues
let aspect_ratio = style.aspect_ratio;
let min_size = style.min_size.maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio);
let max_size = style.max_size.maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio);
let padding = style.padding.resolve_or_zero(parent_size.width);
let border = style.border.resolve_or_zero(parent_size.width);
let padding_border_size = (padding + border).sum_axes();
let box_sizing_adjustment =
if style.box_sizing == BoxSizing::ContentBox { padding_border_size } else { Size::ZERO };

let min_size = style
.min_size
.maybe_resolve(parent_size)
.maybe_apply_aspect_ratio(aspect_ratio)
.maybe_add(box_sizing_adjustment);
let max_size = style
.max_size
.maybe_resolve(parent_size)
.maybe_apply_aspect_ratio(aspect_ratio)
.maybe_add(box_sizing_adjustment);
let clamped_style_size = if inputs.sizing_mode == SizingMode::InherentSize {
style.size.maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio).maybe_clamp(min_size, max_size)
style
.size
.maybe_resolve(parent_size)
.maybe_apply_aspect_ratio(aspect_ratio)
.maybe_add(box_sizing_adjustment)
.maybe_clamp(min_size, max_size)
} else {
Size::NONE
};
Expand Down Expand Up @@ -106,9 +123,6 @@ fn compute_inner(tree: &mut impl LayoutPartialTree, node_id: NodeId, inputs: Lay
let raw_border = style.border;
let raw_margin = style.margin;
let aspect_ratio = style.aspect_ratio;
let size = style.size.maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio);
let min_size = style.min_size.maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio);
let max_size = style.max_size.maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio);
let padding = style.padding.resolve_or_zero(parent_size.width);
let border = style.border.resolve_or_zero(parent_size.width);

Expand All @@ -128,6 +142,21 @@ fn compute_inner(tree: &mut impl LayoutPartialTree, node_id: NodeId, inputs: Lay
let content_box_inset = padding_border + scrollbar_gutter;
let container_content_box_size = known_dimensions.maybe_sub(content_box_inset.sum_axes());

let box_sizing_adjustment =
if style.box_sizing == BoxSizing::ContentBox { padding_border_size } else { Size::ZERO };
let size =
style.size.maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio).maybe_add(box_sizing_adjustment);
let min_size = style
.min_size
.maybe_resolve(parent_size)
.maybe_apply_aspect_ratio(aspect_ratio)
.maybe_add(box_sizing_adjustment);
let max_size = style
.max_size
.maybe_resolve(parent_size)
.maybe_apply_aspect_ratio(aspect_ratio)
.maybe_add(box_sizing_adjustment);

// Determine margin collapsing behaviour
let own_margins_collapse_with_children = Line {
start: vertical_margins_are_collapsible.start
Expand Down Expand Up @@ -262,13 +291,28 @@ fn generate_item_list(
let aspect_ratio = child_style.aspect_ratio;
let padding = child_style.padding.resolve_or_zero(node_inner_size);
let border = child_style.border.resolve_or_zero(node_inner_size);
let pb_sum = (padding + border).sum_axes();
let box_sizing_adjustment =
if child_style.box_sizing == BoxSizing::ContentBox { pb_sum } else { Size::ZERO };
BlockItem {
node_id: child_node_id,
order: order as u32,

size: child_style.size.maybe_resolve(node_inner_size).maybe_apply_aspect_ratio(aspect_ratio),
min_size: child_style.min_size.maybe_resolve(node_inner_size).maybe_apply_aspect_ratio(aspect_ratio),
max_size: child_style.max_size.maybe_resolve(node_inner_size).maybe_apply_aspect_ratio(aspect_ratio),
size: child_style
.size
.maybe_resolve(node_inner_size)
.maybe_apply_aspect_ratio(aspect_ratio)
.maybe_add(box_sizing_adjustment),
min_size: child_style
.min_size
.maybe_resolve(node_inner_size)
.maybe_apply_aspect_ratio(aspect_ratio)
.maybe_add(box_sizing_adjustment),
max_size: child_style
.max_size
.maybe_resolve(node_inner_size)
.maybe_apply_aspect_ratio(aspect_ratio)
.maybe_add(box_sizing_adjustment),
overflow: child_style.overflow,
scrollbar_width: child_style.scrollbar_width,
position: child_style.position,
Expand Down Expand Up @@ -511,6 +555,8 @@ fn perform_absolute_layout_on_absolute_children(
let padding = child_style.padding.resolve_or_zero(Some(area_width));
let border = child_style.border.resolve_or_zero(Some(area_width));
let padding_border_sum = (padding + border).sum_axes();
let box_sizing_adjustment =
if child_style.box_sizing == BoxSizing::ContentBox { padding_border_sum } else { Size::ZERO };

// Resolve inset
let left = child_style.inset.left.maybe_resolve(area_width);
Expand All @@ -519,14 +565,23 @@ fn perform_absolute_layout_on_absolute_children(
let bottom = child_style.inset.bottom.maybe_resolve(area_height);

// Compute known dimensions from min/max/inherent size styles
let style_size = child_style.size.maybe_resolve(area_size).maybe_apply_aspect_ratio(aspect_ratio);
let style_size = child_style
.size
.maybe_resolve(area_size)
.maybe_apply_aspect_ratio(aspect_ratio)
.maybe_add(box_sizing_adjustment);
let min_size = child_style
.min_size
.maybe_resolve(area_size)
.maybe_apply_aspect_ratio(aspect_ratio)
.maybe_add(box_sizing_adjustment)
.or(padding_border_sum.map(Some))
.maybe_max(padding_border_sum);
let max_size = child_style.max_size.maybe_resolve(area_size).maybe_apply_aspect_ratio(aspect_ratio);
let max_size = child_style
.max_size
.maybe_resolve(area_size)
.maybe_apply_aspect_ratio(aspect_ratio)
.maybe_add(box_sizing_adjustment);
let mut known_dimensions = style_size.maybe_clamp(min_size, max_size);

// Fill in width from left/right and reapply aspect ratio if:
Expand Down
Loading

0 comments on commit a497676

Please sign in to comment.