From 1ca522c1ca901f48038b34b390b3cd5092c9307f Mon Sep 17 00:00:00 2001 From: Nico Burns Date: Sun, 7 Jul 2024 16:22:42 +1200 Subject: [PATCH] BoxSizing::ContentBox for Block, root and leaf layout --- src/compute/block.rs | 77 +++++++++++++++++++++++++++++++++++++------- src/compute/leaf.rs | 31 ++++++++++++------ src/compute/mod.rs | 18 +++++++++-- 3 files changed, 102 insertions(+), 24 deletions(-) diff --git a/src/compute/block.rs b/src/compute/block.rs index a57bac8e8..8070dab04 100644 --- a/src/compute/block.rs +++ b/src/compute/block.rs @@ -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; @@ -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 }; @@ -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); @@ -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 @@ -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, @@ -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); @@ -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: diff --git a/src/compute/leaf.rs b/src/compute/leaf.rs index c6bc177b7..117d4284f 100644 --- a/src/compute/leaf.rs +++ b/src/compute/leaf.rs @@ -8,6 +8,7 @@ use crate::util::debug::debug_log; use crate::util::sys::f32_max; use crate::util::MaybeMath; use crate::util::{MaybeResolve, ResolveOrZero}; +use crate::BoxSizing; use core::unreachable; /// Compute the size of a leaf node (node with no children) @@ -21,6 +22,15 @@ where { let LayoutInput { known_dimensions, parent_size, available_space, sizing_mode, run_mode, .. } = inputs; + // Note: both horizontal and vertical percentage padding/borders are resolved against the container's inline size (i.e. width). + // This is not a bug, but is how CSS is specified (see: https://developer.mozilla.org/en-US/docs/Web/CSS/padding#values) + let margin = style.margin.resolve_or_zero(parent_size.width); + let padding = style.padding.resolve_or_zero(parent_size.width); + let border = style.border.resolve_or_zero(parent_size.width); + let padding_border = padding + border; + let pb_sum = padding_border.sum_axes(); + let box_sizing_adjustment = if style.box_sizing == BoxSizing::ContentBox { pb_sum } else { Size::ZERO }; + // Resolve node's preferred/min/max sizes (width/heights) against the available space (percentages resolve to pixel values) // For ContentSize mode, we pretend that the node has no size styles as these should be ignored. let (node_size, node_min_size, node_max_size, aspect_ratio) = match sizing_mode { @@ -32,22 +42,23 @@ where } SizingMode::InherentSize => { let aspect_ratio = style.aspect_ratio; - let style_size = style.size.maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio); - let style_min_size = style.min_size.maybe_resolve(parent_size).maybe_apply_aspect_ratio(aspect_ratio); - let style_max_size = style.max_size.maybe_resolve(parent_size); + let style_size = style + .size + .maybe_resolve(parent_size) + .maybe_apply_aspect_ratio(aspect_ratio) + .maybe_add(box_sizing_adjustment); + let style_min_size = style + .min_size + .maybe_resolve(parent_size) + .maybe_apply_aspect_ratio(aspect_ratio) + .maybe_add(box_sizing_adjustment); + let style_max_size = style.max_size.maybe_resolve(parent_size).maybe_add(box_sizing_adjustment); let node_size = known_dimensions.or(style_size); (node_size, style_min_size, style_max_size, aspect_ratio) } }; - // Note: both horizontal and vertical percentage padding/borders are resolved against the container's inline size (i.e. width). - // This is not a bug, but is how CSS is specified (see: https://developer.mozilla.org/en-US/docs/Web/CSS/padding#values) - let margin = style.margin.resolve_or_zero(parent_size.width); - let padding = style.padding.resolve_or_zero(parent_size.width); - let border = style.border.resolve_or_zero(parent_size.width); - let padding_border = padding + border; - // Scrollbar gutters are reserved when the `overflow` property is set to `Overflow::Scroll`. // However, the axis are switched (transposed) because a node that scrolls vertically needs // *horizontal* space to be reserved for a scrollbar diff --git a/src/compute/mod.rs b/src/compute/mod.rs index 49ed09904..00d4a8cb9 100644 --- a/src/compute/mod.rs +++ b/src/compute/mod.rs @@ -52,7 +52,7 @@ use crate::tree::{ use crate::util::debug::{debug_log, debug_log_node, debug_pop_node, debug_push_node}; use crate::util::sys::round; use crate::util::ResolveOrZero; -use crate::{Display, MaybeMath, MaybeResolve}; +use crate::{BoxSizing, Display, MaybeMath, MaybeResolve}; /// Compute layout for the root node in the tree pub fn compute_root_layout(tree: &mut impl LayoutPartialTree, root: NodeId, available_space: Size) { @@ -67,15 +67,27 @@ pub fn compute_root_layout(tree: &mut impl LayoutPartialTree, root: NodeId, avai // Pull these out earlier to avoid borrowing issues let aspect_ratio = style.aspect_ratio; let margin = style.margin.resolve_or_zero(parent_size.width); - 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 = style .size .maybe_resolve(parent_size) .maybe_apply_aspect_ratio(aspect_ratio) + .maybe_add(box_sizing_adjustment) .maybe_clamp(min_size, max_size); // If both min and max in a given axis are set and max <= min then this determines the size in that axis