1use crate::computed_value_flags::ComputedValueFlags;
9use crate::dom::TElement;
10use crate::logical_geometry::PhysicalSide;
11use crate::properties::longhands::display::computed_value::T as Display;
12use crate::properties::longhands::float::computed_value::T as Float;
13use crate::properties::longhands::position::computed_value::T as Position;
14#[cfg(feature = "gecko")]
15use crate::properties::longhands::{
16 contain::computed_value::T as Contain, container_type::computed_value::T as ContainerType,
17 content_visibility::computed_value::T as ContentVisibility,
18};
19#[cfg(feature = "gecko")]
20use crate::properties::LonghandId;
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().clone_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.clone_line_clamp();
170 if line_clamp.is_none() {
171 return;
172 }
173
174 let disp = box_style.clone_display();
175 if disp.inside() != DisplayInside::WebkitBox
176 || self.style.get_xul().clone__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().clone_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().clone_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.clone_display();
262
263 if !display.is_contents() {
264 if !self
265 .style
266 .get_text()
267 .clone_text_decoration_line()
268 .is_empty()
269 {
270 self.style
271 .add_flags(ComputedValueFlags::HAS_TEXT_DECORATION_LINES);
272 }
273
274 if self.style.get_effects().clone_opacity() == 0. {
275 self.style
276 .add_flags(ComputedValueFlags::IS_IN_OPACITY_ZERO_SUBTREE);
277 }
278 } else if self
279 .style
280 .get_parent_box()
281 .clone_display()
282 .is_item_container()
283 || self
284 .style
285 .get_parent_flags()
286 .contains(ComputedValueFlags::DISPLAY_CONTENTS_IN_ITEM_CONTAINER)
287 {
288 self.style
289 .add_flags(ComputedValueFlags::DISPLAY_CONTENTS_IN_ITEM_CONTAINER);
290 }
291
292 if self.style.pseudo.is_some_and(|p| p.is_first_line()) {
293 self.style
294 .add_flags(ComputedValueFlags::IS_IN_FIRST_LINE_SUBTREE);
295 }
296
297 if self.style.is_root_element {
298 self.style
299 .add_flags(ComputedValueFlags::IS_ROOT_ELEMENT_STYLE);
300 }
301
302 #[cfg(feature = "gecko")]
303 if box_style
304 .clone_effective_containment()
305 .contains(Contain::STYLE)
306 {
307 self.style
308 .add_flags(ComputedValueFlags::SELF_OR_ANCESTOR_HAS_CONTAIN_STYLE);
309 }
310
311 if box_style.clone_container_type().is_size_container_type() {
312 self.style
313 .add_flags(ComputedValueFlags::SELF_OR_ANCESTOR_HAS_SIZE_CONTAINER_TYPE);
314 }
315 }
316
317 #[cfg(feature = "gecko")]
324 pub fn adjust_for_text(&mut self) {
325 debug_assert!(!self.style.is_root_element);
326 self.adjust_for_text_combine_upright();
327 self.adjust_for_text_in_ruby();
328 self.set_bits();
329 }
330
331 #[cfg(feature = "gecko")]
342 fn adjust_for_text_combine_upright(&mut self) {
343 use crate::computed_values::text_combine_upright::T as TextCombineUpright;
344 use crate::computed_values::writing_mode::T as WritingMode;
345 use crate::logical_geometry;
346
347 let writing_mode = self.style.get_inherited_box().clone_writing_mode();
348 let text_combine_upright = self.style.get_inherited_text().clone_text_combine_upright();
349
350 if matches!(
351 writing_mode,
352 WritingMode::VerticalRl | WritingMode::VerticalLr
353 ) && text_combine_upright == TextCombineUpright::All
354 {
355 self.style.add_flags(ComputedValueFlags::IS_TEXT_COMBINED);
356 self.style
357 .mutate_inherited_box()
358 .set_writing_mode(WritingMode::HorizontalTb);
359 self.style.writing_mode =
360 logical_geometry::WritingMode::new(self.style.get_inherited_box());
361 }
362 }
363
364 #[cfg(feature = "gecko")]
371 fn adjust_for_text_in_ruby(&mut self) {
372 let parent_display = self.style.get_parent_box().clone_display();
373 if parent_display.is_ruby_type()
374 || self
375 .style
376 .get_parent_flags()
377 .contains(ComputedValueFlags::SHOULD_SUPPRESS_LINEBREAK)
378 {
379 self.style
380 .add_flags(ComputedValueFlags::SHOULD_SUPPRESS_LINEBREAK);
381 }
382 }
383
384 fn adjust_for_writing_mode(&mut self, layout_parent_style: &ComputedValues) {
398 let our_writing_mode = self.style.get_inherited_box().clone_writing_mode();
399 let parent_writing_mode = layout_parent_style.get_inherited_box().clone_writing_mode();
400
401 if our_writing_mode != parent_writing_mode
402 && self.style.get_box().clone_display() == Display::Inline
403 {
404 if cfg!(feature = "servo") {
407 self.style
408 .mutate_box()
409 .set_adjusted_display(Display::InlineBlock, false);
410 } else {
411 self.style.mutate_box().set_display(Display::InlineBlock);
412 }
413 }
414 }
415
416 fn adjust_for_overflow(&mut self) {
422 let overflow_x = self.style.get_box().clone_overflow_x();
423 let overflow_y = self.style.get_box().clone_overflow_y();
424 if overflow_x == overflow_y {
425 return; }
427
428 if overflow_x.is_scrollable() != overflow_y.is_scrollable() {
429 let box_style = self.style.mutate_box();
430 box_style.set_overflow_x(overflow_x.to_scrollable());
431 box_style.set_overflow_y(overflow_y.to_scrollable());
432 }
433 }
434
435 #[cfg(feature = "gecko")]
436 fn adjust_for_contain(&mut self) {
437 let box_style = self.style.get_box();
438 let container_type = box_style.clone_container_type();
439 let content_visibility = box_style.clone_content_visibility();
440 if !container_type.is_size_container_type()
441 && content_visibility == ContentVisibility::Visible
442 {
443 debug_assert_eq!(
444 box_style.clone_contain(),
445 box_style.clone_effective_containment()
446 );
447 return;
448 }
449 let old_contain = box_style.clone_contain();
450 let mut new_contain = old_contain;
451 match content_visibility {
452 ContentVisibility::Visible => {},
453 ContentVisibility::Auto => {
457 new_contain.insert(Contain::LAYOUT | Contain::PAINT | Contain::STYLE)
458 },
459 ContentVisibility::Hidden => new_contain
460 .insert(Contain::LAYOUT | Contain::PAINT | Contain::SIZE | Contain::STYLE),
461 }
462 if container_type.intersects(ContainerType::INLINE_SIZE) {
463 new_contain.insert(Contain::STYLE | Contain::INLINE_SIZE);
467 } else if container_type.intersects(ContainerType::SIZE) {
468 new_contain.insert(Contain::STYLE | Contain::SIZE);
472 }
473 if new_contain == old_contain {
474 debug_assert_eq!(
475 box_style.clone_contain(),
476 box_style.clone_effective_containment()
477 );
478 return;
479 }
480 self.style
481 .mutate_box()
482 .set_effective_containment(new_contain);
483 }
484
485 #[cfg(feature = "gecko")]
490 fn adjust_for_contain_intrinsic_size(&mut self) {
491 let content_visibility = self.style.get_box().clone_content_visibility();
492 if content_visibility != ContentVisibility::Auto {
493 return;
494 }
495
496 let pos = self.style.get_position();
497 let new_width = pos.clone_contain_intrinsic_width().add_auto_if_needed();
498 let new_height = pos.clone_contain_intrinsic_height().add_auto_if_needed();
499 if new_width.is_none() && new_height.is_none() {
500 return;
501 }
502
503 let pos = self.style.mutate_position();
504 if let Some(width) = new_width {
505 pos.set_contain_intrinsic_width(width);
506 }
507 if let Some(height) = new_height {
508 pos.set_contain_intrinsic_height(height);
509 }
510 }
511
512 #[cfg(feature = "gecko")]
518 fn adjust_for_prohibited_display_contents<E>(&mut self, element: Option<E>)
519 where
520 E: TElement,
521 {
522 if self.style.get_box().clone_display() != Display::Contents {
523 return;
524 }
525
526 if self.style.pseudo.is_some_and(|p| !p.is_element_backed()) {
528 self.style.mutate_box().set_display(Display::Inline);
529 return;
530 }
531
532 let element = match element {
533 Some(e) => e,
534 None => return,
535 };
536
537 if is_effective_display_none_for_display_contents(element) {
538 self.style.mutate_box().set_display(Display::None);
539 }
540 }
541
542 #[cfg(feature = "gecko")]
545 fn adjust_for_text_control_editing_root(&mut self) {
546 use crate::properties::longhands::white_space_collapse::computed_value::T as WhiteSpaceCollapse;
547 use crate::selector_parser::PseudoElement;
548
549 if self.style.pseudo != Some(&PseudoElement::MozTextControlEditingRoot) {
550 return;
551 }
552
553 let old_collapse = self.style.get_inherited_text().clone_white_space_collapse();
554 let new_collapse = match old_collapse {
555 WhiteSpaceCollapse::Preserve | WhiteSpaceCollapse::BreakSpaces => old_collapse,
556 WhiteSpaceCollapse::Collapse
557 | WhiteSpaceCollapse::PreserveSpaces
558 | WhiteSpaceCollapse::PreserveBreaks => WhiteSpaceCollapse::Preserve,
559 };
560 if new_collapse != old_collapse {
561 self.style
562 .mutate_inherited_text()
563 .set_white_space_collapse(new_collapse);
564 }
565 }
566
567 #[cfg(feature = "gecko")]
570 fn adjust_for_fieldset_content(&mut self) {
571 use crate::selector_parser::PseudoElement;
572 if self.style.pseudo != Some(&PseudoElement::MozFieldsetContent) {
573 return;
574 }
575 let parent_display = self.style.get_parent_box().clone_display();
576 debug_assert!(
577 !parent_display.is_contents(),
578 "How did we create a fieldset-content box with display: contents?"
579 );
580 let new_display = match parent_display {
581 Display::Flex | Display::InlineFlex => Some(Display::Flex),
582 Display::Grid | Display::InlineGrid => Some(Display::Grid),
583 _ => None,
584 };
585 if let Some(new_display) = new_display {
586 self.style.mutate_box().set_display(new_display);
587 }
588 }
589
590 fn adjust_for_table_text_align(&mut self) {
597 use crate::properties::longhands::text_align::computed_value::T as TextAlign;
598 if self.style.get_box().clone_display() != Display::Table {
599 return;
600 }
601
602 match self.style.get_inherited_text().clone_text_align() {
603 TextAlign::MozLeft | TextAlign::MozCenter | TextAlign::MozRight => {},
604 _ => return,
605 }
606
607 self.style
608 .mutate_inherited_text()
609 .set_text_align(TextAlign::Start)
610 }
611
612 #[cfg(feature = "gecko")]
613 fn should_suppress_linebreak<E>(&self, element: Option<E>) -> bool
614 where
615 E: TElement,
616 {
617 if self.style.is_floating() || self.style.is_absolutely_positioned() {
619 return false;
620 }
621 let parent_display = self.style.get_parent_box().clone_display();
622 if self
623 .style
624 .get_parent_flags()
625 .contains(ComputedValueFlags::SHOULD_SUPPRESS_LINEBREAK)
626 {
627 if parent_display.is_line_participant() || parent_display.is_contents() {
630 return true;
631 }
632 }
633 match self.style.get_box().clone_display() {
634 Display::RubyBase | Display::RubyText => true,
636 Display::RubyBaseContainer | Display::RubyTextContainer
645 if element.is_none_or(|e| e.is_html_element()) =>
646 {
647 false
648 },
649 _ => parent_display.is_ruby_type(),
653 }
654 }
655
656 #[cfg(feature = "gecko")]
662 fn adjust_for_ruby<E>(&mut self, element: Option<E>)
663 where
664 E: TElement,
665 {
666 use crate::properties::longhands::unicode_bidi::computed_value::T as UnicodeBidi;
667
668 let self_display = self.style.get_box().clone_display();
669 if self.should_suppress_linebreak(element) {
671 self.style
672 .add_flags(ComputedValueFlags::SHOULD_SUPPRESS_LINEBREAK);
673 if !self.skip_item_display_fixup(element) {
675 let inline_display = self_display.inlinify();
676 if self_display != inline_display {
677 self.style
678 .mutate_box()
679 .set_adjusted_display(inline_display, false);
680 }
681 }
682 }
683 if self_display.is_ruby_level_container() {
688 self.style.reset_border_struct();
689 self.style.reset_padding_struct();
690 }
691
692 if self_display.is_ruby_type() {
695 let new_value = match self.style.get_text().clone_unicode_bidi() {
696 UnicodeBidi::Normal | UnicodeBidi::Embed => Some(UnicodeBidi::Isolate),
697 UnicodeBidi::BidiOverride => Some(UnicodeBidi::IsolateOverride),
698 _ => None,
699 };
700 if let Some(new_value) = new_value {
701 self.style.mutate_text().set_unicode_bidi(new_value);
702 }
703 }
704 }
705
706 fn adjust_for_visited<E>(&mut self, element: Option<E>)
716 where
717 E: TElement,
718 {
719 if !self.style.has_visited_style() {
720 return;
721 }
722
723 let is_link_element = self.style.pseudo.is_none() && element.is_some_and(|e| e.is_link());
724
725 if !is_link_element {
726 return;
727 }
728
729 if element.unwrap().is_visited_link() {
730 self.style
731 .add_flags(ComputedValueFlags::IS_RELEVANT_LINK_VISITED);
732 } else {
733 self.style
735 .remove_flags(ComputedValueFlags::IS_RELEVANT_LINK_VISITED);
736 }
737 }
738
739 #[cfg(feature = "gecko")]
744 fn adjust_for_justify_items(&mut self) {
745 use crate::values::specified::align;
746 let justify_items = self.style.get_position().clone_justify_items();
747 if justify_items.specified != align::JustifyItems::legacy() {
748 return;
749 }
750
751 let parent_justify_items = self.style.get_parent_position().clone_justify_items();
752
753 if !parent_justify_items.computed.contains(AlignFlags::LEGACY) {
754 return;
755 }
756
757 if parent_justify_items.computed == justify_items.computed {
758 return;
759 }
760
761 self.style
762 .mutate_position()
763 .set_computed_justify_items(parent_justify_items.computed);
764 }
765
766 fn adjust_for_appearance<E>(&mut self, element: Option<E>)
771 where
772 E: TElement,
773 {
774 use crate::properties::longhands::appearance::computed_value::T as Appearance;
775 use crate::properties::longhands::line_height::computed_value::T as LineHeight;
776
777 let box_ = self.style.get_box();
778 let appearance = match box_.clone_appearance() {
779 Appearance::Auto => box_.clone__moz_default_appearance(),
780 a => a,
781 };
782
783 if appearance == Appearance::Menulist {
784 if self.style.get_font().clone_line_height() == LineHeight::normal() {
785 return;
786 }
787 if self.style.pseudo.is_some() {
788 return;
789 }
790 let is_html_select_element =
791 element.is_some_and(|e| e.is_html_element() && e.local_name() == &*atom!("select"));
792 if !is_html_select_element {
793 return;
794 }
795 self.style
796 .mutate_font()
797 .set_line_height(LineHeight::normal());
798 }
799 }
800
801 #[cfg(feature = "gecko")]
812 fn adjust_for_marker_pseudo(&mut self, author_specified_properties: &LonghandIdSet) {
813 use crate::values::computed::counters::Content;
814 use crate::values::computed::font::{FontFamily, FontSynthesis, FontSynthesisStyle};
815 use crate::values::computed::text::{LetterSpacing, WordSpacing};
816
817 let is_legacy_marker = self.style.pseudo.is_some_and(|p| p.is_marker())
818 && self.style.get_list().clone_list_style_type().is_bullet()
819 && self.style.get_counters().clone_content() == Content::Normal;
820 if !is_legacy_marker {
821 return;
822 }
823 if !author_specified_properties.contains(LonghandId::FontFamily) {
824 self.style
825 .mutate_font()
826 .set_font_family(FontFamily::moz_bullet().clone());
827
828 if !author_specified_properties.contains(LonghandId::FontSynthesisWeight) {
832 self.style
833 .mutate_font()
834 .set_font_synthesis_weight(FontSynthesis::None);
835 }
836 if !author_specified_properties.contains(LonghandId::FontSynthesisStyle) {
837 self.style
838 .mutate_font()
839 .set_font_synthesis_style(FontSynthesisStyle::None);
840 }
841 }
842 if !author_specified_properties.contains(LonghandId::LetterSpacing) {
843 self.style
844 .mutate_inherited_text()
845 .set_letter_spacing(LetterSpacing::normal());
846 }
847 if !author_specified_properties.contains(LonghandId::WordSpacing) {
848 self.style
849 .mutate_inherited_text()
850 .set_word_spacing(WordSpacing::normal());
851 }
852 }
853
854 fn adjust_for_try_tactic(&mut self, tactic: &PositionTryFallbacksTryTactic) {
862 debug_assert!(!tactic.is_empty());
863 let wm = self.style.writing_mode;
865 for tactic in tactic.iter() {
867 use PositionTryFallbacksTryTacticKeyword::*;
868 match tactic {
869 FlipBlock => {
870 self.flip_self_alignment(true);
871 self.flip_insets_and_margins(wm.is_vertical());
872 },
873 FlipInline => {
874 self.flip_self_alignment(false);
875 self.flip_insets_and_margins(wm.is_horizontal());
876 },
877 FlipX => {
878 self.flip_self_alignment(wm.is_vertical());
879 self.flip_insets_and_margins(true);
880 },
881 FlipY => {
882 self.flip_self_alignment(wm.is_horizontal());
883 self.flip_insets_and_margins(false);
884 },
885 FlipStart => {
886 self.flip_start();
887 },
888 }
889 self.apply_position_area_tactic(*tactic);
890 }
891 }
892
893 fn apply_position_area_tactic(&mut self, tactic: PositionTryFallbacksTryTacticKeyword) {
894 let pos = self.style.get_position();
895 let old = pos.clone_position_area();
896 let wm = self.style.writing_mode;
897 let new = old.with_tactic(wm, tactic);
898 if new == old {
899 return;
900 }
901 let pos = self.style.mutate_position();
902 pos.set_position_area(new);
903 }
904
905 fn swap_insets(&mut self, a_side: PhysicalSide, b_side: PhysicalSide) {
907 debug_assert_ne!(a_side, b_side);
908 let pos = self.style.mutate_position();
909 let mut a = pos.get_inset(a_side).clone();
910 a.try_tactic_adjustment(a_side, b_side);
911 let mut b = pos.get_inset(b_side).clone();
912 b.try_tactic_adjustment(b_side, a_side);
913 pos.set_inset(a_side, b);
914 pos.set_inset(b_side, a);
915 }
916
917 fn swap_margins(&mut self, a_side: PhysicalSide, b_side: PhysicalSide) {
918 debug_assert_ne!(a_side, b_side);
919 let margin = self.style.get_margin();
920 let mut a = margin.get_margin(a_side).clone();
921 a.try_tactic_adjustment(a_side, b_side);
922 let mut b = margin.get_margin(b_side).clone();
923 b.try_tactic_adjustment(b_side, a_side);
924 let margin = self.style.mutate_margin();
925 margin.set_margin(a_side, b);
926 margin.set_margin(b_side, a);
927 }
928
929 fn swap_sizes(&mut self, block_start: PhysicalSide, inline_start: PhysicalSide) {
930 let pos = self.style.mutate_position();
931 let mut min_width = pos.clone_min_width();
932 min_width.try_tactic_adjustment(inline_start, block_start);
933 let mut max_width = pos.clone_max_width();
934 max_width.try_tactic_adjustment(inline_start, block_start);
935 let mut width = pos.clone_width();
936 width.try_tactic_adjustment(inline_start, block_start);
937
938 let mut min_height = pos.clone_min_height();
939 min_height.try_tactic_adjustment(block_start, inline_start);
940 let mut max_height = pos.clone_max_height();
941 max_height.try_tactic_adjustment(block_start, inline_start);
942 let mut height = pos.clone_height();
943 height.try_tactic_adjustment(block_start, inline_start);
944
945 let pos = self.style.mutate_position();
946 pos.set_width(height);
947 pos.set_height(width);
948 pos.set_max_width(max_height);
949 pos.set_max_height(max_width);
950 pos.set_min_width(min_height);
951 pos.set_min_height(min_width);
952 }
953
954 fn flip_start(&mut self) {
955 let wm = self.style.writing_mode;
956 let bs = wm.block_start_physical_side();
957 let is = wm.inline_start_physical_side();
958 let be = wm.block_end_physical_side();
959 let ie = wm.inline_end_physical_side();
960 self.swap_sizes(bs, is);
961 self.swap_insets(bs, is);
962 self.swap_insets(ie, be);
963 self.swap_margins(bs, is);
964 self.swap_margins(ie, be);
965 self.flip_alignment_start();
966 }
967
968 fn flip_insets_and_margins(&mut self, horizontal: bool) {
969 if horizontal {
970 self.swap_insets(PhysicalSide::Left, PhysicalSide::Right);
971 self.swap_margins(PhysicalSide::Left, PhysicalSide::Right);
972 } else {
973 self.swap_insets(PhysicalSide::Top, PhysicalSide::Bottom);
974 self.swap_margins(PhysicalSide::Top, PhysicalSide::Bottom);
975 }
976 }
977
978 fn flip_alignment_start(&mut self) {
979 let pos = self.style.get_position();
980 let align = pos.clone_align_self();
981 let mut justify = pos.clone_justify_self();
982 if align == justify {
983 return;
984 }
985
986 if matches!(justify.value(), AlignFlags::LEFT | AlignFlags::RIGHT) {
989 let left = justify.value() == AlignFlags::LEFT;
990 let ltr = self.style.writing_mode.is_bidi_ltr();
991 justify = justify.with_value(if left == ltr {
992 AlignFlags::SELF_START
993 } else {
994 AlignFlags::SELF_END
995 });
996 }
997
998 let pos = self.style.mutate_position();
999 pos.set_align_self(justify);
1000 pos.set_justify_self(align);
1001 }
1002
1003 fn flip_self_alignment(&mut self, block: bool) {
1004 let pos = self.style.get_position();
1005 let cur = if block {
1006 pos.clone_align_self()
1007 } else {
1008 pos.clone_justify_self()
1009 };
1010 let flipped = cur.flip_position();
1011 if flipped == cur {
1012 return;
1013 }
1014 let pos = self.style.mutate_position();
1015 if block {
1016 pos.set_align_self(flipped);
1017 } else {
1018 pos.set_justify_self(flipped);
1019 }
1020 }
1021
1022 #[allow(unused_variables)]
1024 pub fn adjust<E>(
1025 &mut self,
1026 layout_parent_style: &ComputedValues,
1027 element: Option<E>,
1028 try_tactic: &PositionTryFallbacksTryTactic,
1029 author_specified_properties: &LonghandIdSet,
1030 ) where
1031 E: TElement,
1032 {
1033 if cfg!(debug_assertions) {
1034 if let Some(e) = element {
1035 if let Some(p) = e.implemented_pseudo_element() {
1036 debug_assert!(
1040 self.style.pseudo.is_some(),
1041 "Someone really messed up (no pseudo style for {e:?}, {p:?})"
1042 );
1043 }
1044 }
1045 }
1046 self.adjust_for_visited(element);
1056 #[cfg(feature = "gecko")]
1057 {
1058 self.adjust_for_prohibited_display_contents(element);
1059 self.adjust_for_fieldset_content();
1060 self.adjust_for_text_control_editing_root();
1061 }
1062 self.adjust_for_top_layer();
1063 self.blockify_if_necessary(layout_parent_style, element);
1064 #[cfg(feature = "gecko")]
1065 self.adjust_for_webkit_line_clamp();
1066 self.adjust_for_position();
1067 self.adjust_for_overflow();
1068 #[cfg(feature = "gecko")]
1069 {
1070 self.adjust_for_contain();
1071 self.adjust_for_contain_intrinsic_size();
1072 self.adjust_for_justify_items();
1073 }
1074 self.adjust_for_table_text_align();
1075 self.adjust_for_writing_mode(layout_parent_style);
1076 #[cfg(feature = "gecko")]
1077 self.adjust_for_ruby(element);
1078 self.adjust_for_appearance(element);
1079 #[cfg(feature = "gecko")]
1080 self.adjust_for_marker_pseudo(author_specified_properties);
1081 if !try_tactic.is_empty() {
1082 self.adjust_for_try_tactic(try_tactic);
1083 }
1084 self.set_bits();
1085 }
1086}