1use std::collections::VecDeque;
10use std::fmt::Debug;
11use std::mem;
12use std::ops::Range;
13
14use app_units::{Au, MAX_AU, MIN_AU};
15use euclid::num::Zero;
16use malloc_size_of_derive::MallocSizeOf;
17use servo_arc::Arc;
18use style::computed_values::float::T as FloatProperty;
19use style::computed_values::position::T as Position;
20use style::logical_geometry::WritingMode;
21use style::properties::ComputedValues;
22use style::values::computed::Clear as StyleClear;
23
24use crate::context::LayoutContext;
25use crate::dom_traversal::{Contents, NodeAndStyleInfo};
26use crate::formatting_contexts::IndependentFormattingContext;
27use crate::fragment_tree::{BoxFragment, CollapsedMargin};
28use crate::geom::{LogicalRect, LogicalVec2, ToLogical};
29use crate::positioned::{PositioningContext, relative_adjustement};
30use crate::style_ext::{DisplayInside, PaddingBorderMargin};
31use crate::{ContainingBlock, PropagatedBoxTreeData};
32
33#[derive(Debug, MallocSizeOf)]
35pub(crate) struct FloatBox {
36 pub contents: IndependentFormattingContext,
38}
39
40#[derive(Clone, Copy, Debug)]
45pub struct ContainingBlockPositionInfo {
46 pub(crate) block_start: Au,
52 pub(crate) block_start_margins_not_collapsed: CollapsedMargin,
56 pub inline_start: Au,
60 pub inline_end: Au,
64}
65
66impl ContainingBlockPositionInfo {
67 pub fn new_with_inline_offsets(inline_start: Au, inline_end: Au) -> Self {
68 Self {
69 block_start: Au::zero(),
70 block_start_margins_not_collapsed: CollapsedMargin::zero(),
71 inline_start,
72 inline_end,
73 }
74 }
75}
76
77pub(crate) struct PlacementAmongFloats<'a> {
81 float_context: &'a FloatContext,
83 current_bands: VecDeque<FloatBand>,
85 next_band: FloatBand,
87 object_size: LogicalVec2<Au>,
89 ceiling: Au,
92 min_inline_start: Au,
95 max_inline_end: Au,
97}
98
99impl<'a> PlacementAmongFloats<'a> {
100 pub(crate) fn new(
101 float_context: &'a FloatContext,
102 ceiling: Au,
103 object_size: LogicalVec2<Au>,
104 pbm: &PaddingBorderMargin,
105 ) -> Self {
106 let mut ceiling_band = float_context.bands.find(ceiling).unwrap();
107 let (current_bands, next_band) = if ceiling == MAX_AU {
108 (VecDeque::new(), ceiling_band)
109 } else {
110 ceiling_band.top = ceiling;
111 let current_bands = VecDeque::from([ceiling_band]);
112 let next_band = float_context.bands.find_next(ceiling).unwrap();
113 (current_bands, next_band)
114 };
115 let min_inline_start = float_context.containing_block_info.inline_start +
116 pbm.margin.inline_start.auto_is(Au::zero);
117 let max_inline_end = (float_context.containing_block_info.inline_end -
118 pbm.margin.inline_end.auto_is(Au::zero))
119 .max(min_inline_start + object_size.inline);
120 PlacementAmongFloats {
121 float_context,
122 current_bands,
123 next_band,
124 object_size,
125 ceiling,
126 min_inline_start,
127 max_inline_end,
128 }
129 }
130
131 fn top_of_bands(&self) -> Option<Au> {
135 self.current_bands.front().map(|band| band.top)
136 }
137
138 fn current_bands_height(&self) -> Au {
140 if self.next_band.top == MAX_AU {
141 MAX_AU
143 } else {
144 let top = self
145 .top_of_bands()
146 .expect("Should have bands before reaching the end");
147 self.next_band.top - top
148 }
149 }
150
151 fn add_one_band(&mut self) {
154 assert!(self.next_band.top != MAX_AU);
155 self.current_bands.push_back(self.next_band);
156 self.next_band = self
157 .float_context
158 .bands
159 .find_next(self.next_band.top)
160 .unwrap();
161 }
162
163 fn accumulate_enough_bands_for_block_size(&mut self) {
166 while self.current_bands_height() < self.object_size.block {
167 self.add_one_band();
168 }
169 }
170
171 fn calculate_inline_start_and_end(&self) -> (Au, Au) {
174 let mut max_inline_start = self.min_inline_start;
175 let mut min_inline_end = self.max_inline_end;
176 for band in self.current_bands.iter() {
177 if let Some(inline_start) = band.inline_start {
178 max_inline_start.max_assign(inline_start);
179 }
180 if let Some(inline_end) = band.inline_end {
181 min_inline_end.min_assign(inline_end);
182 }
183 }
184 (max_inline_start, min_inline_end)
185 }
186
187 fn calculate_viable_inline_size(&self) -> Au {
189 let (inline_start, inline_end) = self.calculate_inline_start_and_end();
190 inline_end - inline_start
191 }
192
193 fn try_place_once(&mut self) -> Option<LogicalRect<Au>> {
194 assert!(!self.current_bands.is_empty());
195 self.accumulate_enough_bands_for_block_size();
196 let (inline_start, inline_end) = self.calculate_inline_start_and_end();
197 let available_inline_size = inline_end - inline_start;
198 if available_inline_size < self.object_size.inline {
199 return None;
200 }
201 Some(LogicalRect {
202 start_corner: LogicalVec2 {
203 inline: inline_start,
204 block: self.top_of_bands().unwrap(),
205 },
206 size: LogicalVec2 {
207 inline: available_inline_size,
208 block: self.current_bands_height(),
209 },
210 })
211 }
212
213 fn has_bands_or_at_end(&self) -> bool {
216 !self.current_bands.is_empty() || self.next_band.top == MAX_AU
217 }
218
219 fn pop_front_band_ensuring_has_bands_or_at_end(&mut self) {
220 self.current_bands.pop_front();
221 if !self.has_bands_or_at_end() {
222 self.add_one_band();
223 }
224 }
225
226 pub(crate) fn place(&mut self) -> LogicalRect<Au> {
228 debug_assert!(self.has_bands_or_at_end());
229 while !self.current_bands.is_empty() {
230 if let Some(result) = self.try_place_once() {
231 return result;
232 }
233 self.pop_front_band_ensuring_has_bands_or_at_end();
234 }
235 debug_assert!(self.has_bands_or_at_end());
236
237 LogicalRect {
240 start_corner: LogicalVec2 {
241 inline: self.min_inline_start,
242 block: self
243 .ceiling
244 .max(self.float_context.clear_inline_start_position)
245 .max(self.float_context.clear_inline_end_position),
246 },
247 size: LogicalVec2 {
248 inline: self.max_inline_end - self.min_inline_start,
249 block: MAX_AU,
250 },
251 }
252 }
253
254 pub(crate) fn try_to_expand_for_auto_block_size(
261 &mut self,
262 block_size_after_layout: Au,
263 size_from_placement: &LogicalVec2<Au>,
264 ) -> bool {
265 debug_assert!(self.has_bands_or_at_end());
266 debug_assert_eq!(size_from_placement.block, self.current_bands_height());
267 debug_assert_eq!(
268 size_from_placement.inline,
269 self.calculate_viable_inline_size()
270 );
271
272 if block_size_after_layout <= size_from_placement.block {
275 return true;
276 }
277
278 let old_num_bands = self.current_bands.len();
281 assert!(old_num_bands > 0);
282 while self.current_bands_height() < block_size_after_layout {
283 self.add_one_band();
284
285 let available_inline_size = self.calculate_viable_inline_size();
290 if available_inline_size < size_from_placement.inline {
291 if available_inline_size < self.object_size.inline {
295 self.next_band = self.current_bands[old_num_bands];
296 self.current_bands.truncate(old_num_bands);
297 self.pop_front_band_ensuring_has_bands_or_at_end();
298 }
299 return false;
300 }
301 }
302 true
303 }
304}
305
306#[derive(Clone, Debug)]
311pub struct FloatContext {
312 pub bands: FloatBandTree,
317 pub ceiling_from_floats: Au,
320 pub ceiling_from_non_floats: Au,
324 pub containing_block_info: ContainingBlockPositionInfo,
328 pub clear_inline_start_position: Au,
330 pub clear_inline_end_position: Au,
332}
333
334impl FloatContext {
335 pub fn new(max_inline_size: Au) -> Self {
338 let mut bands = FloatBandTree::new();
339 bands = bands.insert(FloatBand {
340 top: MIN_AU,
341 inline_start: None,
342 inline_end: None,
343 });
344 bands = bands.insert(FloatBand {
345 top: MAX_AU,
346 inline_start: None,
347 inline_end: None,
348 });
349 FloatContext {
350 bands,
351 ceiling_from_floats: Au::zero(),
352 ceiling_from_non_floats: Au::zero(),
353 containing_block_info: ContainingBlockPositionInfo::new_with_inline_offsets(
354 Au::zero(),
355 max_inline_size,
356 ),
357 clear_inline_start_position: Au::zero(),
358 clear_inline_end_position: Au::zero(),
359 }
360 }
361
362 pub fn set_ceiling_from_non_floats(&mut self, new_ceiling: Au) {
366 self.ceiling_from_non_floats = new_ceiling;
367 }
368
369 fn ceiling(&mut self) -> Au {
372 self.ceiling_from_floats.max(self.ceiling_from_non_floats)
373 }
374
375 pub(crate) fn place_object(&self, object: &PlacementInfo, ceiling: Au) -> LogicalVec2<Au> {
381 let ceiling = match object.clear {
382 Clear::None => ceiling,
383 Clear::InlineStart => ceiling.max(self.clear_inline_start_position),
384 Clear::InlineEnd => ceiling.max(self.clear_inline_end_position),
385 Clear::Both => ceiling
386 .max(self.clear_inline_start_position)
387 .max(self.clear_inline_end_position),
388 };
389
390 let mut first_band = self.bands.find(ceiling).unwrap();
392 while !first_band.object_fits(object, &self.containing_block_info) {
393 let next_band = self.bands.find_next(first_band.top).unwrap();
394 if next_band.top == MAX_AU {
395 break;
396 }
397 first_band = next_band;
398 }
399
400 match object.side {
402 FloatSide::InlineStart => {
403 let inline_start_object_edge = match first_band.inline_start {
404 Some(inline_start) => inline_start.max(self.containing_block_info.inline_start),
405 None => self.containing_block_info.inline_start,
406 };
407 LogicalVec2 {
408 inline: inline_start_object_edge,
409 block: first_band.top.max(ceiling),
410 }
411 },
412 FloatSide::InlineEnd => {
413 let inline_end_object_edge = match first_band.inline_end {
414 Some(inline_end) => inline_end.min(self.containing_block_info.inline_end),
415 None => self.containing_block_info.inline_end,
416 };
417 LogicalVec2 {
418 inline: inline_end_object_edge - object.size.inline,
419 block: first_band.top.max(ceiling),
420 }
421 },
422 }
423 }
424
425 pub fn add_float(&mut self, new_float: &PlacementInfo) -> LogicalVec2<Au> {
427 let ceiling = self.ceiling();
429 let new_float_origin = self.place_object(new_float, ceiling);
430 let new_float_extent = match new_float.side {
431 FloatSide::InlineStart => new_float_origin.inline + new_float.size.inline,
432 FloatSide::InlineEnd => new_float_origin.inline,
433 };
434
435 let new_float_rect = LogicalRect {
436 start_corner: new_float_origin,
437 size: LogicalVec2 {
442 inline: new_float.size.inline.max(Au::zero()),
443 block: new_float.size.block.max(Au::zero()),
444 },
445 };
446
447 match new_float.side {
449 FloatSide::InlineStart => {
450 self.clear_inline_start_position
451 .max_assign(new_float_rect.max_block_position());
452 },
453 FloatSide::InlineEnd => {
454 self.clear_inline_end_position
455 .max_assign(new_float_rect.max_block_position());
456 },
457 }
458
459 let mut first_band = self.bands.find(new_float_rect.start_corner.block).unwrap();
461 first_band.top = new_float_rect.start_corner.block;
462 self.bands = self.bands.insert(first_band);
463
464 let mut last_band = self
466 .bands
467 .find(new_float_rect.max_block_position())
468 .unwrap();
469 last_band.top = new_float_rect.max_block_position();
470 self.bands = self.bands.insert(last_band);
471
472 let block_range = new_float_rect.start_corner.block..new_float_rect.max_block_position();
474 self.bands = self
475 .bands
476 .set_range(&block_range, new_float.side, new_float_extent);
477
478 self.ceiling_from_floats
481 .max_assign(new_float_rect.start_corner.block);
482
483 new_float_rect.start_corner
484 }
485}
486
487#[derive(Clone, Copy, Debug, PartialEq)]
488pub enum Clear {
489 None,
490 InlineStart,
491 InlineEnd,
492 Both,
493}
494
495impl Clear {
496 pub(crate) fn from_style_and_container_writing_mode(
497 style: &ComputedValues,
498 container_writing_mode: WritingMode,
499 ) -> Self {
500 match style.get_box().clear {
501 StyleClear::None => Self::None,
502 StyleClear::Both => Self::Both,
503 StyleClear::InlineStart => Self::InlineStart,
504 StyleClear::InlineEnd => Self::InlineEnd,
505 StyleClear::Left if container_writing_mode.is_bidi_ltr() => Self::InlineStart,
506 StyleClear::Left => Self::InlineEnd,
507 StyleClear::Right if container_writing_mode.is_bidi_ltr() => Self::InlineEnd,
508 StyleClear::Right => Self::InlineStart,
509 }
510 }
511}
512
513#[derive(Clone, Debug)]
515pub struct PlacementInfo {
516 pub size: LogicalVec2<Au>,
518 pub side: FloatSide,
520 pub clear: Clear,
522}
523
524#[derive(Clone, Copy, Debug, PartialEq)]
528pub enum FloatSide {
529 InlineStart,
530 InlineEnd,
531}
532
533#[derive(Clone, Copy, Debug, PartialEq)]
536pub struct FloatBand {
537 pub top: Au,
539 pub inline_start: Option<Au>,
544 pub inline_end: Option<Au>,
549}
550
551impl FloatSide {
552 pub(crate) fn from_style_and_container_writing_mode(
553 style: &ComputedValues,
554 container_writing_mode: WritingMode,
555 ) -> Option<FloatSide> {
556 Some(match style.get_box().float {
557 FloatProperty::None => return None,
558 FloatProperty::InlineStart => Self::InlineStart,
559 FloatProperty::InlineEnd => Self::InlineEnd,
560 FloatProperty::Left if container_writing_mode.is_bidi_ltr() => Self::InlineStart,
561 FloatProperty::Left => Self::InlineEnd,
562 FloatProperty::Right if container_writing_mode.is_bidi_ltr() => Self::InlineEnd,
563 FloatProperty::Right => Self::InlineStart,
564 })
565 }
566}
567
568impl FloatBand {
569 fn object_fits(&self, object: &PlacementInfo, walls: &ContainingBlockPositionInfo) -> bool {
571 match object.side {
572 FloatSide::InlineStart => {
573 let candidate_inline_start = match self.inline_start {
575 None => walls.inline_start,
576 Some(inline_start) => inline_start.max(walls.inline_start),
577 };
578
579 if self.inline_start.is_some() &&
582 candidate_inline_start + object.size.inline > walls.inline_end
583 {
584 return false;
585 }
586
587 match self.inline_end {
590 None => true,
591 Some(inline_end) => object.size.inline <= inline_end - candidate_inline_start,
592 }
593 },
594
595 FloatSide::InlineEnd => {
596 let candidate_inline_end = match self.inline_end {
598 None => walls.inline_end,
599 Some(inline_end) => inline_end.min(walls.inline_end),
600 };
601
602 if self.inline_end.is_some() &&
605 candidate_inline_end - object.size.inline < walls.inline_start
606 {
607 return false;
608 }
609
610 match self.inline_start {
613 None => true,
614 Some(inline_start) => object.size.inline <= candidate_inline_end - inline_start,
615 }
616 },
617 }
618 }
619}
620
621#[derive(Clone, Debug)]
633pub struct FloatBandTree {
634 pub root: FloatBandLink,
635}
636
637#[derive(Clone, Debug)]
639pub struct FloatBandLink(pub Option<Arc<FloatBandNode>>);
640
641#[derive(Clone, Debug)]
643pub struct FloatBandNode {
644 pub band: FloatBand,
646 pub left: FloatBandLink,
648 pub right: FloatBandLink,
650 pub level: i32,
654}
655
656impl FloatBandTree {
657 pub fn new() -> FloatBandTree {
659 FloatBandTree {
660 root: FloatBandLink(None),
661 }
662 }
663
664 pub fn find(&self, block_position: Au) -> Option<FloatBand> {
666 self.root.find(block_position)
667 }
668
669 pub fn find_next(&self, block_position: Au) -> Option<FloatBand> {
671 self.root.find_next(block_position)
672 }
673
674 #[must_use]
677 pub fn set_range(&self, range: &Range<Au>, side: FloatSide, new_value: Au) -> FloatBandTree {
678 FloatBandTree {
679 root: FloatBandLink(
680 self.root
681 .0
682 .as_ref()
683 .map(|root| root.set_range(range, side, new_value)),
684 ),
685 }
686 }
687
688 #[must_use]
691 pub fn insert(&self, band: FloatBand) -> FloatBandTree {
692 FloatBandTree {
693 root: self.root.insert(band),
694 }
695 }
696}
697
698impl Default for FloatBandTree {
699 fn default() -> Self {
700 Self::new()
701 }
702}
703
704impl FloatBandNode {
705 fn new(band: FloatBand) -> FloatBandNode {
706 FloatBandNode {
707 band,
708 left: FloatBandLink(None),
709 right: FloatBandLink(None),
710 level: 1,
711 }
712 }
713
714 fn set_range(&self, range: &Range<Au>, side: FloatSide, new_value: Au) -> Arc<FloatBandNode> {
717 let mut new_band = self.band;
718 if self.band.top >= range.start && self.band.top < range.end {
719 match side {
720 FloatSide::InlineStart => {
721 new_band.inline_start = match new_band.inline_start {
722 Some(old_value) => Some(std::cmp::max(old_value, new_value)),
723 None => Some(new_value),
724 };
725 },
726 FloatSide::InlineEnd => {
727 new_band.inline_end = match new_band.inline_end {
728 Some(old_value) => Some(std::cmp::min(old_value, new_value)),
729 None => Some(new_value),
730 };
731 },
732 }
733 }
734
735 let new_left = match self.left.0 {
736 None => FloatBandLink(None),
737 Some(ref old_left) if range.start < new_band.top => {
738 FloatBandLink(Some(old_left.set_range(range, side, new_value)))
739 },
740 Some(ref old_left) => FloatBandLink(Some((*old_left).clone())),
741 };
742
743 let new_right = match self.right.0 {
744 None => FloatBandLink(None),
745 Some(ref old_right) if range.end > new_band.top => {
746 FloatBandLink(Some(old_right.set_range(range, side, new_value)))
747 },
748 Some(ref old_right) => FloatBandLink(Some((*old_right).clone())),
749 };
750
751 Arc::new(FloatBandNode {
752 band: new_band,
753 left: new_left,
754 right: new_right,
755 level: self.level,
756 })
757 }
758}
759
760impl FloatBandLink {
761 fn find(&self, block_position: Au) -> Option<FloatBand> {
763 let this = match self.0 {
764 None => return None,
765 Some(ref node) => node,
766 };
767
768 if block_position < this.band.top {
769 return this.left.find(block_position);
770 }
771
772 if let Some(band) = this.right.find(block_position) {
775 return Some(band);
776 }
777
778 Some(this.band)
779 }
780
781 fn find_next(&self, block_position: Au) -> Option<FloatBand> {
783 let this = match self.0 {
784 None => return None,
785 Some(ref node) => node,
786 };
787
788 if block_position >= this.band.top {
789 return this.right.find_next(block_position);
790 }
791
792 if let Some(band) = this.left.find_next(block_position) {
795 return Some(band);
796 }
797
798 Some(this.band)
799 }
800
801 fn insert(&self, band: FloatBand) -> FloatBandLink {
804 let mut this = match self.0 {
805 None => return FloatBandLink(Some(Arc::new(FloatBandNode::new(band)))),
806 Some(ref this) => (**this).clone(),
807 };
808
809 if band.top < this.band.top {
810 this.left = this.left.insert(band);
811 return FloatBandLink(Some(Arc::new(this))).skew().split();
812 }
813 if band.top > this.band.top {
814 this.right = this.right.insert(band);
815 return FloatBandLink(Some(Arc::new(this))).skew().split();
816 }
817
818 this.band = band;
819 FloatBandLink(Some(Arc::new(this)))
820 }
821
822 fn skew(&self) -> FloatBandLink {
831 if let Some(ref this) = self.0 {
832 if let Some(ref left) = this.left.0 {
833 if this.level == left.level {
834 return FloatBandLink(Some(Arc::new(FloatBandNode {
835 level: this.level,
836 left: left.left.clone(),
837 band: left.band,
838 right: FloatBandLink(Some(Arc::new(FloatBandNode {
839 level: this.level,
840 left: left.right.clone(),
841 band: this.band,
842 right: this.right.clone(),
843 }))),
844 })));
845 }
846 }
847 }
848
849 (*self).clone()
850 }
851
852 fn split(&self) -> FloatBandLink {
861 if let Some(ref this) = self.0 {
862 if let Some(ref right) = this.right.0 {
863 if let Some(ref right_right) = right.right.0 {
864 if this.level == right_right.level {
865 return FloatBandLink(Some(Arc::new(FloatBandNode {
866 level: this.level + 1,
867 left: FloatBandLink(Some(Arc::new(FloatBandNode {
868 level: this.level,
869 left: this.left.clone(),
870 band: this.band,
871 right: right.left.clone(),
872 }))),
873 band: right.band,
874 right: right.right.clone(),
875 })));
876 }
877 }
878 }
879 }
880
881 (*self).clone()
882 }
883}
884
885impl FloatBox {
886 pub fn construct(
888 context: &LayoutContext,
889 info: &NodeAndStyleInfo<'_>,
890 display_inside: DisplayInside,
891 contents: Contents,
892 propagated_data: PropagatedBoxTreeData,
893 ) -> Self {
894 Self {
895 contents: IndependentFormattingContext::construct(
896 context,
897 info,
898 display_inside,
899 contents,
900 propagated_data,
901 ),
902 }
903 }
904
905 pub fn layout(
909 &self,
910 layout_context: &LayoutContext,
911 positioning_context: &mut PositioningContext,
912 containing_block: &ContainingBlock,
913 ) -> BoxFragment {
914 positioning_context.layout_maybe_position_relative_fragment(
915 layout_context,
916 containing_block,
917 &self.contents.base,
918 |positioning_context| {
919 self.contents
920 .layout_float_or_atomic_inline(
921 layout_context,
922 positioning_context,
923 containing_block,
924 )
925 .fragment
926 },
927 )
928 }
929}
930
931#[derive(Clone)]
942pub(crate) struct SequentialLayoutState {
943 pub(crate) floats: FloatContext,
945 pub(crate) bfc_relative_block_position: Au,
952 pub(crate) current_margin: CollapsedMargin,
954}
955
956impl SequentialLayoutState {
957 pub(crate) fn new(max_inline_size: Au) -> SequentialLayoutState {
959 SequentialLayoutState {
960 floats: FloatContext::new(max_inline_size),
961 current_margin: CollapsedMargin::zero(),
962 bfc_relative_block_position: Au::zero(),
963 }
964 }
965
966 pub(crate) fn advance_block_position(&mut self, block_distance: Au) {
973 self.bfc_relative_block_position += block_distance;
974 self.floats
975 .set_ceiling_from_non_floats(self.bfc_relative_block_position);
976 }
977
978 pub(crate) fn replace_containing_block_position_info(
981 &mut self,
982 mut position_info: ContainingBlockPositionInfo,
983 ) -> ContainingBlockPositionInfo {
984 mem::swap(&mut position_info, &mut self.floats.containing_block_info);
985 position_info
986 }
987
988 pub(crate) fn current_block_position_including_margins(&self) -> Au {
991 self.bfc_relative_block_position + self.current_margin.solve()
992 }
993
994 pub(crate) fn collapse_margins(&mut self) {
1000 self.advance_block_position(self.current_margin.solve());
1001 self.current_margin = CollapsedMargin::zero();
1002 }
1003
1004 pub(crate) fn position_without_clearance(&self, block_start_margin: &CollapsedMargin) -> Au {
1007 self.bfc_relative_block_position + self.current_margin.adjoin(block_start_margin).solve()
1009 }
1010
1011 pub(crate) fn position_with_zero_clearance(&self, block_start_margin: &CollapsedMargin) -> Au {
1014 self.bfc_relative_block_position + self.current_margin.solve() + block_start_margin.solve()
1017 }
1018
1019 pub(crate) fn calculate_clear_position(
1022 &self,
1023 clear: Clear,
1024 block_start_margin: &CollapsedMargin,
1025 ) -> Option<Au> {
1026 if clear == Clear::None {
1027 return None;
1028 }
1029
1030 let hypothetical_block_position = self.position_without_clearance(block_start_margin);
1033
1034 let clear_position = match clear {
1037 Clear::None => unreachable!(),
1038 Clear::InlineStart => self.floats.clear_inline_start_position,
1039 Clear::InlineEnd => self.floats.clear_inline_end_position,
1040 Clear::Both => self
1041 .floats
1042 .clear_inline_start_position
1043 .max(self.floats.clear_inline_end_position),
1044 };
1045 if hypothetical_block_position >= clear_position {
1046 None
1047 } else {
1048 Some(clear_position)
1049 }
1050 }
1051
1052 pub(crate) fn calculate_clearance(
1061 &self,
1062 clear: Clear,
1063 block_start_margin: &CollapsedMargin,
1064 ) -> Option<Au> {
1065 self.calculate_clear_position(clear, block_start_margin)
1066 .map(|offset| offset - self.position_with_zero_clearance(block_start_margin))
1067 }
1068
1069 pub(crate) fn adjoin_assign(&mut self, margin: &CollapsedMargin) {
1071 self.current_margin.adjoin_assign(margin)
1072 }
1073
1074 pub(crate) fn current_containing_block_offset(&self) -> Au {
1076 self.floats.containing_block_info.block_start +
1077 self.floats
1078 .containing_block_info
1079 .block_start_margins_not_collapsed
1080 .solve()
1081 }
1082
1083 pub(crate) fn place_float_fragment(
1085 &mut self,
1086 box_fragment: &mut BoxFragment,
1087 containing_block: &ContainingBlock,
1088 margins_collapsing_with_parent_containing_block: CollapsedMargin,
1089 block_offset_from_containing_block_top: Au,
1090 ) {
1091 let block_start_of_containing_block_in_bfc = self.floats.containing_block_info.block_start +
1092 self.floats
1093 .containing_block_info
1094 .block_start_margins_not_collapsed
1095 .adjoin(&margins_collapsing_with_parent_containing_block)
1096 .solve();
1097
1098 self.floats.set_ceiling_from_non_floats(
1099 block_start_of_containing_block_in_bfc + block_offset_from_containing_block_top,
1100 );
1101
1102 let container_writing_mode = containing_block.style.writing_mode;
1103 let logical_float_size = box_fragment
1104 .content_rect
1105 .size
1106 .to_logical(container_writing_mode);
1107 let pbm_sums = box_fragment
1108 .padding_border_margin()
1109 .to_logical(container_writing_mode);
1110 let margin_box_start_corner = self.floats.add_float(&PlacementInfo {
1111 size: logical_float_size + pbm_sums.sum(),
1112 side: FloatSide::from_style_and_container_writing_mode(
1113 &box_fragment.style,
1114 container_writing_mode,
1115 )
1116 .expect("Float box wasn't floated!"),
1117 clear: Clear::from_style_and_container_writing_mode(
1118 &box_fragment.style,
1119 container_writing_mode,
1120 ),
1121 });
1122
1123 let relative_offset = match box_fragment.style.clone_position() {
1126 Position::Relative => relative_adjustement(&box_fragment.style, containing_block),
1127 _ => LogicalVec2::zero(),
1128 };
1129
1130 let new_position_in_bfc =
1133 margin_box_start_corner + pbm_sums.start_offset() + relative_offset;
1134
1135 let new_position_in_containing_block = LogicalVec2 {
1137 inline: new_position_in_bfc.inline - self.floats.containing_block_info.inline_start,
1138 block: new_position_in_bfc.block - block_start_of_containing_block_in_bfc,
1139 };
1140
1141 box_fragment.content_rect = LogicalRect {
1142 start_corner: new_position_in_containing_block,
1143 size: box_fragment
1144 .content_rect
1145 .size
1146 .to_logical(container_writing_mode),
1147 }
1148 .as_physical(Some(containing_block));
1149 }
1150}