1use crate::computed_value_flags::ComputedValueFlags;
9use crate::dom::TElement;
10use crate::logical_geometry::PhysicalSide;
11#[cfg(feature = "gecko")]
12use crate::properties::LonghandId;
13use crate::properties::longhands::display::computed_value::T as Display;
14use crate::properties::longhands::float::computed_value::T as Float;
15use crate::properties::longhands::position::computed_value::T as Position;
16#[cfg(feature = "gecko")]
17use crate::properties::longhands::{
18 contain::computed_value::T as Contain, container_type::computed_value::T as ContainerType,
19 content_visibility::computed_value::T as ContentVisibility,
20};
21use crate::properties::{ComputedValues, LonghandIdSet, StyleBuilder};
22use crate::values::computed::position::{
23 PositionTryFallbacksTryTactic, PositionTryFallbacksTryTacticKeyword, TryTacticAdjustment,
24};
25use crate::values::specified::align::AlignFlags;
26
27pub struct StyleAdjuster<'a, 'b: 'a> {
41 style: &'a mut StyleBuilder<'b>,
42}
43
44#[cfg(feature = "gecko")]
45fn is_topmost_svg_svg_element<E>(e: E) -> bool
46where
47 E: TElement,
48{
49 debug_assert!(e.is_svg_element());
50 if e.local_name() != &*atom!("svg") {
51 return false;
52 }
53
54 let parent = match e.traversal_parent() {
55 Some(n) => n,
56 None => return true,
57 };
58
59 if !parent.is_svg_element() {
60 return true;
61 }
62
63 parent.local_name() == &*atom!("foreignObject")
64}
65
66#[cfg(feature = "gecko")]
68fn is_effective_display_none_for_display_contents<E>(element: E) -> bool
69where
70 E: TElement,
71{
72 use crate::Atom;
73
74 const SPECIAL_HTML_ELEMENTS: [Atom; 16] = [
75 atom!("br"),
76 atom!("wbr"),
77 atom!("meter"),
78 atom!("progress"),
79 atom!("canvas"),
80 atom!("embed"),
81 atom!("object"),
82 atom!("audio"),
83 atom!("iframe"),
84 atom!("img"),
85 atom!("video"),
86 atom!("frame"),
87 atom!("frameset"),
88 atom!("input"),
89 atom!("textarea"),
90 atom!("select"),
91 ];
92
93 const SPECIAL_SVG_ELEMENTS: [Atom; 6] = [
99 atom!("svg"),
100 atom!("a"),
101 atom!("g"),
102 atom!("use"),
103 atom!("tspan"),
104 atom!("textPath"),
105 ];
106
107 if element.is_html_element() {
109 let local_name = element.local_name();
110 return SPECIAL_HTML_ELEMENTS
111 .iter()
112 .any(|name| &**name == local_name);
113 }
114
115 if element.is_svg_element() {
117 if is_topmost_svg_svg_element(element) {
118 return true;
119 }
120 let local_name = element.local_name();
121 return !SPECIAL_SVG_ELEMENTS
122 .iter()
123 .any(|name| &**name == local_name);
124 }
125
126 if element.is_mathml_element() {
128 return true;
129 }
130
131 false
132}
133
134impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
135 #[inline]
137 pub fn new(style: &'a mut StyleBuilder<'b>) -> Self {
138 StyleAdjuster { style }
139 }
140
141 fn adjust_for_top_layer(&mut self) {
147 if !self.style.in_top_layer() {
148 return;
149 }
150 if !self.style.is_absolutely_positioned() {
151 self.style.mutate_box().set_position(Position::Absolute);
152 }
153 if self.style.get_box().get_display().is_contents() {
154 self.style.mutate_box().set_display(Display::Block);
155 }
156 }
157
158 #[cfg(feature = "gecko")]
165 fn adjust_for_webkit_line_clamp(&mut self) {
166 use crate::properties::longhands::_moz_box_orient::computed_value::T as BoxOrient;
167 use crate::values::specified::box_::{DisplayInside, DisplayOutside};
168 let box_style = self.style.get_box();
169 let line_clamp = box_style.get_line_clamp();
170 if line_clamp.is_none() {
171 return;
172 }
173
174 let disp = *box_style.get_display();
175 if disp.inside() != DisplayInside::WebkitBox
176 || *self.style.get_xul().get__moz_box_orient() != BoxOrient::Vertical
177 {
178 return;
179 }
180 let new_display = if disp.outside() == DisplayOutside::Block {
181 Display::FlowRoot
182 } else {
183 debug_assert_eq!(disp.outside(), DisplayOutside::Inline);
184 Display::InlineBlock
185 };
186 self.style
187 .mutate_box()
188 .set_adjusted_display(new_display, false);
189 }
190
191 fn adjust_for_position(&mut self) {
197 if self.style.is_absolutely_positioned() && self.style.is_floating() {
198 self.style.mutate_box().set_float(Float::None);
199 }
200 }
201
202 fn skip_item_display_fixup<E>(&self, element: Option<E>) -> bool
205 where
206 E: TElement,
207 {
208 if let Some(pseudo) = self.style.pseudo {
209 return pseudo.skip_item_display_fixup();
210 }
211
212 element.is_some_and(|e| e.skip_item_display_fixup())
213 }
214
215 fn blockify_if_necessary<E>(&mut self, layout_parent_style: &ComputedValues, element: Option<E>)
222 where
223 E: TElement,
224 {
225 let mut blockify = false;
226 macro_rules! blockify_if {
227 ($if_what:expr) => {
228 if !blockify {
229 blockify = $if_what;
230 }
231 };
232 }
233
234 blockify_if!(self.style.is_root_element);
235 if !self.skip_item_display_fixup(element) {
236 let parent_display = *layout_parent_style.get_box().get_display();
237 blockify_if!(parent_display.is_item_container());
238 }
239
240 let is_item_or_root = blockify;
241
242 blockify_if!(self.style.is_floating());
243 blockify_if!(self.style.is_absolutely_positioned());
244
245 if !blockify {
246 return;
247 }
248
249 let display = *self.style.get_box().get_display();
250 let blockified_display = display.equivalent_block_display(self.style.is_root_element);
251 if display != blockified_display {
252 self.style
253 .mutate_box()
254 .set_adjusted_display(blockified_display, is_item_or_root);
255 }
256 }
257
258 fn set_bits(&mut self) {
260 let box_style = self.style.get_box();
261 let display = *box_style.get_display();
262
263 if !display.is_contents() {
264 if !self.style.get_text().get_text_decoration_line().is_empty() {
265 self.style
266 .add_flags(ComputedValueFlags::HAS_TEXT_DECORATION_LINES);
267 }
268
269 if *self.style.get_effects().get_opacity() == 0. {
270 self.style
271 .add_flags(ComputedValueFlags::IS_IN_OPACITY_ZERO_SUBTREE);
272 }
273 } else if self
274 .style
275 .get_parent_box()
276 .get_display()
277 .is_item_container()
278 || self
279 .style
280 .get_parent_flags()
281 .contains(ComputedValueFlags::DISPLAY_CONTENTS_IN_ITEM_CONTAINER)
282 {
283 self.style
284 .add_flags(ComputedValueFlags::DISPLAY_CONTENTS_IN_ITEM_CONTAINER);
285 }
286
287 if self.style.pseudo.is_some_and(|p| p.is_first_line()) {
288 self.style
289 .add_flags(ComputedValueFlags::IS_IN_FIRST_LINE_SUBTREE);
290 }
291
292 if self.style.is_root_element {
293 self.style
294 .add_flags(ComputedValueFlags::IS_ROOT_ELEMENT_STYLE);
295 }
296
297 #[cfg(feature = "gecko")]
298 if box_style
299 .get_effective_containment()
300 .contains(Contain::STYLE)
301 {
302 self.style
303 .add_flags(ComputedValueFlags::SELF_OR_ANCESTOR_HAS_CONTAIN_STYLE);
304 }
305
306 if box_style.get_container_type().is_size_container_type() {
307 self.style
308 .add_flags(ComputedValueFlags::SELF_OR_ANCESTOR_HAS_SIZE_CONTAINER_TYPE);
309 }
310 }
311
312 #[cfg(feature = "gecko")]
319 pub fn adjust_for_text(&mut self) {
320 debug_assert!(!self.style.is_root_element);
321 self.adjust_for_text_combine_upright();
322 self.adjust_for_text_in_ruby();
323 self.set_bits();
324 }
325
326 #[cfg(feature = "gecko")]
337 fn adjust_for_text_combine_upright(&mut self) {
338 use crate::computed_values::text_combine_upright::T as TextCombineUpright;
339 use crate::computed_values::writing_mode::T as WritingMode;
340 use crate::logical_geometry;
341
342 let writing_mode = *self.style.get_inherited_box().get_writing_mode();
343 let text_combine_upright = *self.style.get_inherited_text().get_text_combine_upright();
344
345 if matches!(
346 writing_mode,
347 WritingMode::VerticalRl | WritingMode::VerticalLr
348 ) && text_combine_upright == TextCombineUpright::All
349 {
350 self.style.add_flags(ComputedValueFlags::IS_TEXT_COMBINED);
351 self.style
352 .mutate_inherited_box()
353 .set_writing_mode(WritingMode::HorizontalTb);
354 self.style.writing_mode =
355 logical_geometry::WritingMode::new(self.style.get_inherited_box());
356 }
357 }
358
359 #[cfg(feature = "gecko")]
366 fn adjust_for_text_in_ruby(&mut self) {
367 let parent_display = *self.style.get_parent_box().get_display();
368 if parent_display.is_ruby_type()
369 || self
370 .style
371 .get_parent_flags()
372 .contains(ComputedValueFlags::SHOULD_SUPPRESS_LINEBREAK)
373 {
374 self.style
375 .add_flags(ComputedValueFlags::SHOULD_SUPPRESS_LINEBREAK);
376 }
377 }
378
379 fn adjust_for_writing_mode(&mut self, layout_parent_style: &ComputedValues) {
393 let our_writing_mode = *self.style.get_inherited_box().get_writing_mode();
394 let parent_writing_mode = *layout_parent_style.get_inherited_box().get_writing_mode();
395
396 if our_writing_mode != parent_writing_mode
397 && *self.style.get_box().get_display() == Display::Inline
398 {
399 if cfg!(feature = "servo") {
402 self.style
403 .mutate_box()
404 .set_adjusted_display(Display::InlineBlock, false);
405 } else {
406 self.style.mutate_box().set_display(Display::InlineBlock);
407 }
408 }
409 }
410
411 fn adjust_for_overflow(&mut self) {
417 let overflow_x = *self.style.get_box().get_overflow_x();
418 let overflow_y = *self.style.get_box().get_overflow_y();
419 if overflow_x == overflow_y {
420 return; }
422
423 if overflow_x.is_scrollable() != overflow_y.is_scrollable() {
424 let box_style = self.style.mutate_box();
425 box_style.set_overflow_x(overflow_x.to_scrollable());
426 box_style.set_overflow_y(overflow_y.to_scrollable());
427 }
428 }
429
430 #[cfg(feature = "gecko")]
431 fn adjust_for_contain(&mut self) {
432 let box_style = self.style.get_box();
433 let container_type = *box_style.get_container_type();
434 let content_visibility = *box_style.get_content_visibility();
435 if !container_type.is_size_container_type()
436 && content_visibility == ContentVisibility::Visible
437 {
438 debug_assert_eq!(
439 box_style.get_contain(),
440 box_style.get_effective_containment()
441 );
442 return;
443 }
444 let old_contain = *box_style.get_contain();
445 let mut new_contain = old_contain;
446 match content_visibility {
447 ContentVisibility::Visible => {},
448 ContentVisibility::Auto => {
452 new_contain.insert(Contain::LAYOUT | Contain::PAINT | Contain::STYLE)
453 },
454 ContentVisibility::Hidden => new_contain
455 .insert(Contain::LAYOUT | Contain::PAINT | Contain::SIZE | Contain::STYLE),
456 }
457 if container_type.intersects(ContainerType::INLINE_SIZE) {
458 new_contain.insert(Contain::STYLE | Contain::INLINE_SIZE);
462 } else if container_type.intersects(ContainerType::SIZE) {
463 new_contain.insert(Contain::STYLE | Contain::SIZE);
467 }
468 if new_contain == old_contain {
469 debug_assert_eq!(
470 box_style.get_contain(),
471 box_style.get_effective_containment()
472 );
473 return;
474 }
475 self.style
476 .mutate_box()
477 .set_effective_containment(new_contain);
478 }
479
480 #[cfg(feature = "gecko")]
485 fn adjust_for_contain_intrinsic_size(&mut self) {
486 let content_visibility = *self.style.get_box().get_content_visibility();
487 if content_visibility != ContentVisibility::Auto {
488 return;
489 }
490
491 let pos = self.style.get_position();
492 let new_width = pos.get_contain_intrinsic_width().add_auto_if_needed();
493 let new_height = pos.get_contain_intrinsic_height().add_auto_if_needed();
494 if new_width.is_none() && new_height.is_none() {
495 return;
496 }
497
498 let pos = self.style.mutate_position();
499 if let Some(width) = new_width {
500 pos.set_contain_intrinsic_width(width);
501 }
502 if let Some(height) = new_height {
503 pos.set_contain_intrinsic_height(height);
504 }
505 }
506
507 #[cfg(feature = "gecko")]
513 fn adjust_for_prohibited_display_contents<E>(&mut self, element: Option<E>)
514 where
515 E: TElement,
516 {
517 if *self.style.get_box().get_display() != Display::Contents {
518 return;
519 }
520
521 if self.style.pseudo.is_some_and(|p| !p.is_element_backed()) {
523 self.style.mutate_box().set_display(Display::Inline);
524 return;
525 }
526
527 let element = match element {
528 Some(e) => e,
529 None => return,
530 };
531
532 if is_effective_display_none_for_display_contents(element) {
533 self.style.mutate_box().set_display(Display::None);
534 }
535 }
536
537 #[cfg(feature = "gecko")]
540 fn adjust_for_text_control_editing_root(&mut self) {
541 use crate::properties::longhands::white_space_collapse::computed_value::T as WhiteSpaceCollapse;
542 use crate::selector_parser::PseudoElement;
543
544 if self.style.pseudo != Some(&PseudoElement::MozTextControlEditingRoot) {
545 return;
546 }
547
548 let old_collapse = *self.style.get_inherited_text().get_white_space_collapse();
549 let new_collapse = match old_collapse {
550 WhiteSpaceCollapse::Preserve | WhiteSpaceCollapse::BreakSpaces => old_collapse,
551 WhiteSpaceCollapse::Collapse
552 | WhiteSpaceCollapse::PreserveSpaces
553 | WhiteSpaceCollapse::PreserveBreaks => WhiteSpaceCollapse::Preserve,
554 };
555 if new_collapse != old_collapse {
556 self.style
557 .mutate_inherited_text()
558 .set_white_space_collapse(new_collapse);
559 }
560 }
561
562 #[cfg(feature = "gecko")]
565 fn adjust_for_fieldset_content(&mut self) {
566 use crate::selector_parser::PseudoElement;
567 if self.style.pseudo != Some(&PseudoElement::MozFieldsetContent) {
568 return;
569 }
570 let parent_display = *self.style.get_parent_box().get_display();
571 debug_assert!(
572 !parent_display.is_contents(),
573 "How did we create a fieldset-content box with display: contents?"
574 );
575 let new_display = match parent_display {
576 Display::Flex | Display::InlineFlex => Some(Display::Flex),
577 Display::Grid | Display::InlineGrid => Some(Display::Grid),
578 _ => None,
579 };
580 if let Some(new_display) = new_display {
581 self.style.mutate_box().set_display(new_display);
582 }
583 }
584
585 fn adjust_for_table_text_align(&mut self) {
592 use crate::properties::longhands::text_align::computed_value::T as TextAlign;
593 if *self.style.get_box().get_display() != Display::Table {
594 return;
595 }
596
597 match *self.style.get_inherited_text().get_text_align() {
598 TextAlign::MozLeft | TextAlign::MozCenter | TextAlign::MozRight => {},
599 _ => return,
600 }
601
602 self.style
603 .mutate_inherited_text()
604 .set_text_align(TextAlign::Start)
605 }
606
607 #[cfg(feature = "gecko")]
608 fn should_suppress_linebreak<E>(&self, element: Option<E>) -> bool
609 where
610 E: TElement,
611 {
612 if self.style.is_floating() || self.style.is_absolutely_positioned() {
614 return false;
615 }
616 let parent_display = *self.style.get_parent_box().get_display();
617 if self
618 .style
619 .get_parent_flags()
620 .contains(ComputedValueFlags::SHOULD_SUPPRESS_LINEBREAK)
621 {
622 if parent_display.is_line_participant() || parent_display.is_contents() {
625 return true;
626 }
627 }
628 match *self.style.get_box().get_display() {
629 Display::RubyBase | Display::RubyText => true,
631 Display::RubyBaseContainer | Display::RubyTextContainer
640 if element.is_none_or(|e| e.is_html_element()) =>
641 {
642 false
643 },
644 _ => parent_display.is_ruby_type(),
648 }
649 }
650
651 #[cfg(feature = "gecko")]
657 fn adjust_for_ruby<E>(&mut self, element: Option<E>)
658 where
659 E: TElement,
660 {
661 use crate::properties::longhands::unicode_bidi::computed_value::T as UnicodeBidi;
662
663 let self_display = *self.style.get_box().get_display();
664 if self.should_suppress_linebreak(element) {
666 self.style
667 .add_flags(ComputedValueFlags::SHOULD_SUPPRESS_LINEBREAK);
668 if !self.skip_item_display_fixup(element) {
670 let inline_display = self_display.inlinify();
671 if self_display != inline_display {
672 self.style
673 .mutate_box()
674 .set_adjusted_display(inline_display, false);
675 }
676 }
677 }
678 if self_display.is_ruby_level_container() {
683 self.style.reset_border_struct();
684 self.style.reset_padding_struct();
685 }
686
687 if self_display.is_ruby_type() {
690 let new_value = match *self.style.get_text().get_unicode_bidi() {
691 UnicodeBidi::Normal | UnicodeBidi::Embed => Some(UnicodeBidi::Isolate),
692 UnicodeBidi::BidiOverride => Some(UnicodeBidi::IsolateOverride),
693 _ => None,
694 };
695 if let Some(new_value) = new_value {
696 self.style.mutate_text().set_unicode_bidi(new_value);
697 }
698 }
699 }
700
701 fn adjust_for_visited<E>(&mut self, element: Option<E>)
711 where
712 E: TElement,
713 {
714 if !self.style.has_visited_style() {
715 return;
716 }
717
718 let is_link_element = self.style.pseudo.is_none() && element.is_some_and(|e| e.is_link());
719
720 if !is_link_element {
721 return;
722 }
723
724 if element.unwrap().is_visited_link() {
725 self.style
726 .add_flags(ComputedValueFlags::IS_RELEVANT_LINK_VISITED);
727 } else {
728 self.style
730 .remove_flags(ComputedValueFlags::IS_RELEVANT_LINK_VISITED);
731 }
732 }
733
734 #[cfg(feature = "gecko")]
739 fn adjust_for_justify_items(&mut self) {
740 use crate::values::specified::align;
741 let justify_items = *self.style.get_position().get_justify_items();
742 if justify_items.specified != align::JustifyItems::legacy() {
743 return;
744 }
745
746 let parent_justify_items = *self.style.get_parent_position().get_justify_items();
747
748 if !parent_justify_items.computed.contains(AlignFlags::LEGACY) {
749 return;
750 }
751
752 if parent_justify_items.computed == justify_items.computed {
753 return;
754 }
755
756 self.style
757 .mutate_position()
758 .set_computed_justify_items(parent_justify_items.computed);
759 }
760
761 fn adjust_for_appearance<E>(&mut self, element: Option<E>)
766 where
767 E: TElement,
768 {
769 use crate::properties::longhands::appearance::computed_value::T as Appearance;
770 use crate::properties::longhands::line_height::computed_value::T as LineHeight;
771
772 let box_ = self.style.get_box();
773 let appearance = match *box_.get_appearance() {
774 Appearance::Auto => *box_.get__moz_default_appearance(),
775 a => a,
776 };
777
778 if appearance == Appearance::Menulist {
779 if *self.style.get_font().get_line_height() == LineHeight::normal() {
780 return;
781 }
782 if self.style.pseudo.is_some() {
783 return;
784 }
785 let is_html_select_element =
786 element.is_some_and(|e| e.is_html_element() && e.local_name() == &*atom!("select"));
787 if !is_html_select_element {
788 return;
789 }
790 self.style
791 .mutate_font()
792 .set_line_height(LineHeight::normal());
793 }
794 }
795
796 #[cfg(feature = "gecko")]
807 fn adjust_for_marker_pseudo(&mut self, author_or_user_specified_properties: &LonghandIdSet) {
808 use crate::values::computed::counters::Content;
809 use crate::values::computed::font::{FontFamily, FontSynthesis, FontSynthesisStyle};
810 use crate::values::computed::text::{LetterSpacing, WordSpacing};
811
812 let is_legacy_marker = self.style.pseudo.is_some_and(|p| p.is_marker())
813 && self.style.get_list().get_list_style_type().is_bullet()
814 && matches!(self.style.get_counters().get_content(), Content::Normal);
815 if !is_legacy_marker {
816 return;
817 }
818 if !author_or_user_specified_properties.contains(LonghandId::FontFamily) {
819 self.style
820 .mutate_font()
821 .set_font_family(FontFamily::moz_bullet().clone());
822
823 if !author_or_user_specified_properties.contains(LonghandId::FontSynthesisWeight) {
827 self.style
828 .mutate_font()
829 .set_font_synthesis_weight(FontSynthesis::None);
830 }
831 if !author_or_user_specified_properties.contains(LonghandId::FontSynthesisStyle) {
832 self.style
833 .mutate_font()
834 .set_font_synthesis_style(FontSynthesisStyle::None);
835 }
836 }
837 if !author_or_user_specified_properties.contains(LonghandId::LetterSpacing) {
838 self.style
839 .mutate_inherited_text()
840 .set_letter_spacing(LetterSpacing::normal());
841 }
842 if !author_or_user_specified_properties.contains(LonghandId::WordSpacing) {
843 self.style
844 .mutate_inherited_text()
845 .set_word_spacing(WordSpacing::normal());
846 }
847 }
848
849 fn adjust_for_try_tactic(&mut self, tactic: &PositionTryFallbacksTryTactic) {
857 debug_assert!(!tactic.is_empty());
858 let wm = self.style.writing_mode;
860 for tactic in tactic.iter() {
862 use PositionTryFallbacksTryTacticKeyword::*;
863 match tactic {
864 FlipBlock => {
865 self.flip_self_alignment(true);
866 self.flip_insets_and_margins(wm.is_vertical());
867 },
868 FlipInline => {
869 self.flip_self_alignment(false);
870 self.flip_insets_and_margins(wm.is_horizontal());
871 },
872 FlipX => {
873 self.flip_self_alignment(wm.is_vertical());
874 self.flip_insets_and_margins(true);
875 },
876 FlipY => {
877 self.flip_self_alignment(wm.is_horizontal());
878 self.flip_insets_and_margins(false);
879 },
880 FlipStart => {
881 self.flip_start();
882 },
883 }
884 self.apply_position_area_tactic(*tactic);
885 }
886 }
887
888 fn apply_position_area_tactic(&mut self, tactic: PositionTryFallbacksTryTacticKeyword) {
889 let pos = self.style.get_position();
890 let old = *pos.get_position_area();
891 let wm = self.style.writing_mode;
892 let new = old.with_tactic(wm, tactic);
893 if new == old {
894 return;
895 }
896 let pos = self.style.mutate_position();
897 pos.set_position_area(new);
898 }
899
900 fn swap_insets(&mut self, a_side: PhysicalSide, b_side: PhysicalSide) {
902 debug_assert_ne!(a_side, b_side);
903 let pos = self.style.mutate_position();
904 let mut a = pos.get_inset(a_side).clone();
905 a.try_tactic_adjustment(a_side, b_side);
906 let mut b = pos.get_inset(b_side).clone();
907 b.try_tactic_adjustment(b_side, a_side);
908 pos.set_inset(a_side, b);
909 pos.set_inset(b_side, a);
910 }
911
912 fn swap_margins(&mut self, a_side: PhysicalSide, b_side: PhysicalSide) {
913 debug_assert_ne!(a_side, b_side);
914 let margin = self.style.get_margin();
915 let mut a = margin.get_margin(a_side).clone();
916 a.try_tactic_adjustment(a_side, b_side);
917 let mut b = margin.get_margin(b_side).clone();
918 b.try_tactic_adjustment(b_side, a_side);
919 let margin = self.style.mutate_margin();
920 margin.set_margin(a_side, b);
921 margin.set_margin(b_side, a);
922 }
923
924 fn swap_sizes(&mut self, block_start: PhysicalSide, inline_start: PhysicalSide) {
925 let pos = self.style.mutate_position();
926 let mut min_width = pos.slow_clone_min_width();
927 min_width.try_tactic_adjustment(inline_start, block_start);
928 let mut max_width = pos.slow_clone_max_width();
929 max_width.try_tactic_adjustment(inline_start, block_start);
930 let mut width = pos.slow_clone_width();
931 width.try_tactic_adjustment(inline_start, block_start);
932
933 let mut min_height = pos.slow_clone_min_height();
934 min_height.try_tactic_adjustment(block_start, inline_start);
935 let mut max_height = pos.slow_clone_max_height();
936 max_height.try_tactic_adjustment(block_start, inline_start);
937 let mut height = pos.slow_clone_height();
938 height.try_tactic_adjustment(block_start, inline_start);
939
940 let pos = self.style.mutate_position();
941 pos.set_width(height);
942 pos.set_height(width);
943 pos.set_max_width(max_height);
944 pos.set_max_height(max_width);
945 pos.set_min_width(min_height);
946 pos.set_min_height(min_width);
947 }
948
949 fn flip_start(&mut self) {
950 let wm = self.style.writing_mode;
951 let bs = wm.block_start_physical_side();
952 let is = wm.inline_start_physical_side();
953 let be = wm.block_end_physical_side();
954 let ie = wm.inline_end_physical_side();
955 self.swap_sizes(bs, is);
956 self.swap_insets(bs, is);
957 self.swap_insets(ie, be);
958 self.swap_margins(bs, is);
959 self.swap_margins(ie, be);
960 self.flip_alignment_start();
961 }
962
963 fn flip_insets_and_margins(&mut self, horizontal: bool) {
964 if horizontal {
965 self.swap_insets(PhysicalSide::Left, PhysicalSide::Right);
966 self.swap_margins(PhysicalSide::Left, PhysicalSide::Right);
967 } else {
968 self.swap_insets(PhysicalSide::Top, PhysicalSide::Bottom);
969 self.swap_margins(PhysicalSide::Top, PhysicalSide::Bottom);
970 }
971 }
972
973 fn flip_alignment_start(&mut self) {
974 let pos = self.style.get_position();
975 let align = *pos.get_align_self();
976 let mut justify = *pos.get_justify_self();
977 if align == justify {
978 return;
979 }
980
981 if matches!(justify.value(), AlignFlags::LEFT | AlignFlags::RIGHT) {
984 let left = justify.value() == AlignFlags::LEFT;
985 let ltr = self.style.writing_mode.is_bidi_ltr();
986 justify = justify.with_value(if left == ltr {
987 AlignFlags::SELF_START
988 } else {
989 AlignFlags::SELF_END
990 });
991 }
992
993 let pos = self.style.mutate_position();
994 pos.set_align_self(justify);
995 pos.set_justify_self(align);
996 }
997
998 fn flip_self_alignment(&mut self, block: bool) {
999 let pos = self.style.get_position();
1000 let cur = if block {
1001 *pos.get_align_self()
1002 } else {
1003 *pos.get_justify_self()
1004 };
1005 let flipped = cur.flip_position();
1006 if flipped == cur {
1007 return;
1008 }
1009 let pos = self.style.mutate_position();
1010 if block {
1011 pos.set_align_self(flipped);
1012 } else {
1013 pos.set_justify_self(flipped);
1014 }
1015 }
1016
1017 #[allow(unused_variables)]
1019 pub fn adjust<E>(
1020 &mut self,
1021 layout_parent_style: &ComputedValues,
1022 element: Option<E>,
1023 try_tactic: &PositionTryFallbacksTryTactic,
1024 author_or_user_specified_properties: &LonghandIdSet,
1025 ) where
1026 E: TElement,
1027 {
1028 if cfg!(debug_assertions)
1029 && let Some(e) = element
1030 && let Some(p) = e.implemented_pseudo_element()
1031 {
1032 debug_assert!(
1036 self.style.pseudo.is_some(),
1037 "Someone really messed up (no pseudo style for {e:?}, {p:?})"
1038 );
1039 }
1040 self.adjust_for_visited(element);
1050 #[cfg(feature = "gecko")]
1051 {
1052 self.adjust_for_prohibited_display_contents(element);
1053 self.adjust_for_fieldset_content();
1054 self.adjust_for_text_control_editing_root();
1055 }
1056 self.adjust_for_top_layer();
1057 self.blockify_if_necessary(layout_parent_style, element);
1058 #[cfg(feature = "gecko")]
1059 self.adjust_for_webkit_line_clamp();
1060 self.adjust_for_position();
1061 self.adjust_for_overflow();
1062 #[cfg(feature = "gecko")]
1063 {
1064 self.adjust_for_contain();
1065 self.adjust_for_contain_intrinsic_size();
1066 self.adjust_for_justify_items();
1067 }
1068 self.adjust_for_table_text_align();
1069 self.adjust_for_writing_mode(layout_parent_style);
1070 #[cfg(feature = "gecko")]
1071 self.adjust_for_ruby(element);
1072 self.adjust_for_appearance(element);
1073 #[cfg(feature = "gecko")]
1074 self.adjust_for_marker_pseudo(author_or_user_specified_properties);
1075 if !try_tactic.is_empty() {
1076 self.adjust_for_try_tactic(try_tactic);
1077 }
1078 self.set_bits();
1079 }
1080}