Skip to content

Commit e66b66a

Browse files
committed
Initial impl of find_content_slot + block ifc child placement
Signed-off-by: Nico Burns <[email protected]>
1 parent 633a968 commit e66b66a

File tree

3 files changed

+128
-23
lines changed

3 files changed

+128
-23
lines changed

src/compute/block.rs

Lines changed: 53 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use crate::{
1414
};
1515

1616
#[cfg(feature = "float_layout")]
17-
use super::{FloatContext, FloatDirection};
17+
use super::{ContentSlot, FloatContext, FloatDirection};
1818
#[cfg(feature = "float_layout")]
1919
use crate::{Clear, Float};
2020

@@ -93,6 +93,13 @@ impl BlockContext<'_> {
9393
pos
9494
}
9595

96+
pub fn find_content_slot(&self, min_y: f32, clear: Clear, after: Option<usize>) -> ContentSlot {
97+
let mut slot = self.bfc.float_context.find_content_slot(min_y + self.y_offset, self.insets, clear, after);
98+
slot.y -= self.y_offset;
99+
slot.x -= self.insets[0];
100+
slot
101+
}
102+
96103
fn add_child_floated_content_height_contribution(&mut self, child_contribution: f32) {
97104
self.float_content_contribution = self.float_content_contribution.max(child_contribution);
98105
}
@@ -476,12 +483,15 @@ fn generate_item_list(
476483
if child_style.box_sizing() == BoxSizing::ContentBox { pb_sum } else { Size::ZERO };
477484

478485
let position = child_style.position();
486+
let overflow = child_style.overflow();
479487
let float = child_style.float();
480488

481489
let is_block = child_style.is_block();
482490
let is_table = child_style.is_table();
491+
let is_scroll_container = overflow.x.is_scroll_container() || overflow.y.is_scroll_container();
483492

484-
let is_in_same_bfc: bool = is_block && !is_table && position != Position::Absolute && float == Float::None;
493+
let is_in_same_bfc: bool =
494+
is_block && !is_table && position != Position::Absolute && float == Float::None && !is_scroll_container;
485495

486496
BlockItem {
487497
node_id: child_node_id,
@@ -507,7 +517,7 @@ fn generate_item_list(
507517
.maybe_resolve(node_inner_size, |val, basis| tree.calc(val, basis))
508518
.maybe_apply_aspect_ratio(aspect_ratio)
509519
.maybe_add(box_sizing_adjustment),
510-
overflow: child_style.overflow(),
520+
overflow,
511521
scrollbar_width: child_style.scrollbar_width(),
512522
position,
513523
inset: child_style.inset(),
@@ -669,18 +679,27 @@ fn perform_final_layout_on_in_flow_children(
669679

670680
// Handle non-floated boxes
671681

682+
let (stretch_width, float_avoiding_position) = if item.is_in_same_bfc {
683+
let stretch_width = container_inner_width - item_non_auto_x_margin_sum;
684+
let position = Point { x: 0.0, y: 0.0 };
685+
686+
(stretch_width, position)
687+
} else {
688+
let min_y = committed_y_offset + active_collapsible_margin_set.resolve();
689+
let slot = block_ctx.find_content_slot(min_y, item.clear, None);
690+
let stretch_width = slot.width - item_non_auto_x_margin_sum;
691+
692+
(stretch_width, Point { x: slot.x, y: slot.y })
693+
};
694+
672695
let known_dimensions = if item.is_table {
673696
Size::NONE
674697
} else {
675698
item.size
676699
.map_width(|width| {
677700
// TODO: Allow stretch-sizing to be conditional, as there are exceptions.
678701
// e.g. Table children of blocks do not stretch fit
679-
Some(
680-
width
681-
.unwrap_or(container_inner_width - item_non_auto_x_margin_sum)
682-
.maybe_clamp(item.min_size.width, item.max_size.width),
683-
)
702+
Some(width.unwrap_or(stretch_width).maybe_clamp(item.min_size.width, item.max_size.width))
684703
})
685704
.maybe_clamp(item.min_size, item.max_size)
686705
};
@@ -727,7 +746,7 @@ fn perform_final_layout_on_in_flow_children(
727746
// Expand auto margins to fill available space
728747
// Note: Vertical auto-margins for relatively positioned block items simply resolve to 0.
729748
// See: https://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width
730-
let free_x_space = f32_max(0.0, container_inner_width - final_size.width - item_non_auto_x_margin_sum);
749+
let free_x_space = f32_max(0.0, stretch_width - final_size.width);
731750
let x_axis_auto_margin_size = {
732751
let auto_margin_count = item_margin.left.is_none() as u8 + item_margin.right.is_none() as u8;
733752
if auto_margin_count > 0 {
@@ -760,27 +779,43 @@ fn perform_final_layout_on_in_flow_children(
760779

761780
item.computed_size = item_layout.size;
762781
item.can_be_collapsed_through = item_layout.margins_can_collapse_through;
763-
item.static_position = Point {
764-
x: resolved_content_box_inset.left,
765-
y: committed_y_offset + active_collapsible_margin_set.resolve(),
782+
item.static_position = if item.is_in_same_bfc {
783+
Point {
784+
x: resolved_content_box_inset.left,
785+
y: committed_y_offset + active_collapsible_margin_set.resolve(),
786+
}
787+
} else {
788+
// TODO: handle inset and margins
789+
Point { x: float_avoiding_position.x + resolved_content_box_inset.left, y: float_avoiding_position.y }
766790
};
767-
let mut location = Point {
768-
x: resolved_content_box_inset.left + inset_offset.x + resolved_margin.left,
769-
y: committed_y_offset + inset_offset.y + y_margin_offset,
791+
let mut location = if item.is_in_same_bfc {
792+
Point {
793+
x: resolved_content_box_inset.left + inset_offset.x + resolved_margin.left,
794+
y: committed_y_offset + inset_offset.y + y_margin_offset,
795+
}
796+
} else {
797+
// TODO: handle inset and margins
798+
Point {
799+
x: float_avoiding_position.x
800+
+ resolved_content_box_inset.left
801+
+ inset_offset.x
802+
+ resolved_margin.left,
803+
y: float_avoiding_position.y + inset_offset.y + y_margin_offset,
804+
}
770805
};
771806

772807
// Apply alignment
773808
let item_outer_width = item_layout.size.width + resolved_margin.horizontal_axis_sum();
774-
if item_outer_width < container_inner_width {
809+
if item_outer_width < stretch_width {
775810
match text_align {
776811
TextAlign::Auto => {
777812
// Do nothing
778813
}
779814
TextAlign::LegacyLeft => {
780815
// Do nothing. Left aligned by default.
781816
}
782-
TextAlign::LegacyRight => location.x += container_inner_width - item_outer_width,
783-
TextAlign::LegacyCenter => location.x += (container_inner_width - item_outer_width) / 2.0,
817+
TextAlign::LegacyRight => location.x += stretch_width - item_outer_width,
818+
TextAlign::LegacyCenter => location.x += (stretch_width - item_outer_width) / 2.0,
784819
}
785820
}
786821

src/compute/float.rs

Lines changed: 74 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
//!
2727
//! <https://www.w3.org/TR/CSS22/visuren.html#floats>
2828
29-
use core::ops::{Range, RangeInclusive};
29+
use core::ops::Range;
3030

3131
use crate::{AvailableSpace, Clear, Point, Size};
3232

@@ -50,6 +50,17 @@ pub enum FloatDirection {
5050
Right = 1,
5151
}
5252

53+
/// An empty "slot" that avoids floats that is suitable for non-floated content
54+
/// to be laid out into
55+
#[derive(Debug, Clone, Copy, Default)]
56+
pub struct ContentSlot {
57+
pub segment_id: Option<usize>,
58+
pub x: f32,
59+
pub y: f32,
60+
pub width: f32,
61+
pub height: f32,
62+
}
63+
5364
/// A floated box to place within the context
5465
#[derive(Debug, Clone, Copy, Default)]
5566
pub struct FloatedBox {
@@ -149,6 +160,16 @@ impl FloatContext {
149160
}
150161
}
151162

163+
pub fn find_content_slot(
164+
&self,
165+
min_y: f32,
166+
containing_block_insets: [f32; 2],
167+
clear: Clear,
168+
after: Option<usize>,
169+
) -> ContentSlot {
170+
self.placer.find_content_slot(min_y, containing_block_insets, clear, after)
171+
}
172+
152173
pub(crate) fn content_width(&self) -> f32 {
153174
match self.available_space {
154175
AvailableSpace::Definite(width) => width,
@@ -335,7 +356,7 @@ impl FloatPlacer {
335356
// segment below all existing segments. A new segment will always have space for
336357
// the float, so we can exit the loop at this point.
337358
let Some(start_segment) = self.segments.get(start_idx) else {
338-
break (None, None, 0.0);
359+
break (None, None, containing_block_insets[slot]);
339360
};
340361

341362
// Candidate start segment doesn't have (horizontal) space for the float:
@@ -476,7 +497,56 @@ impl FloatPlacer {
476497
PlacedFloatedBox { width: floated_box.width, height: floated_box.height, y: start_y, x_inset: placed_inset }
477498
}
478499

479-
fn place_non_floated_content(&mut self, min_y: f32, height: f32) -> (Point<f32>, Size<f32>) {
480-
todo!()
500+
fn find_content_slot(
501+
&self,
502+
min_y: f32,
503+
containing_block_insets: [f32; 2],
504+
clear: Clear,
505+
after: Option<usize>,
506+
) -> ContentSlot {
507+
// The min starting segment index
508+
let at_least = after.map(|idx| idx + 1).unwrap_or(0);
509+
510+
// Ensure that content respects "clear" and "after"
511+
let hwm = match clear {
512+
Clear::Left => {
513+
let left_end = self.last_placed_floats[0].end;
514+
at_least.max(left_end)
515+
}
516+
Clear::Right => {
517+
let right_end = self.last_placed_floats[1].end;
518+
at_least.max(right_end)
519+
}
520+
Clear::Both => {
521+
let left_end = self.last_placed_floats[0].end;
522+
let right_end = self.last_placed_floats[1].end;
523+
at_least.max(left_end).max(right_end)
524+
}
525+
Clear::None => at_least,
526+
};
527+
528+
let start_idx = self.segments[hwm..].iter().position(|segment| segment.y.end > min_y).map(|idx| idx + hwm);
529+
let start_idx = start_idx.unwrap_or(self.segments.len());
530+
let segment = self.segments.get(start_idx);
531+
match segment {
532+
Some(segment) => {
533+
let inset_left = segment.insets[0].max(containing_block_insets[0]);
534+
let inset_right = segment.insets[1].max(containing_block_insets[1]);
535+
ContentSlot {
536+
segment_id: Some(start_idx),
537+
x: inset_left,
538+
y: segment.y.start.max(min_y),
539+
width: self.bfc_width - inset_left - inset_right,
540+
height: f32::INFINITY,
541+
}
542+
}
543+
None => ContentSlot {
544+
segment_id: None,
545+
x: containing_block_insets[0],
546+
y: min_y,
547+
width: self.bfc_width - containing_block_insets[0] - containing_block_insets[1],
548+
height: f32::INFINITY,
549+
},
550+
}
481551
}
482552
}

src/compute/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ pub use self::flexbox::compute_flexbox_layout;
4848
pub use self::grid::compute_grid_layout;
4949

5050
#[cfg(feature = "float_layout")]
51-
pub use self::float::{FloatContext, FloatDirection, FloatedBox};
51+
pub use self::float::{ContentSlot, FloatContext, FloatDirection, FloatedBox};
5252

5353
use crate::geometry::{Line, Point, Size};
5454
use crate::style::{AvailableSpace, CoreStyle, Overflow};

0 commit comments

Comments
 (0)