style/values/computed/
position.rs1use crate::values::computed::{
11 Context, Integer, LengthPercentage, NonNegativeNumber, Percentage, ToComputedValue,
12};
13use crate::values::generics::position::Position as GenericPosition;
14use crate::values::generics::position::PositionComponent as GenericPositionComponent;
15use crate::values::generics::position::PositionOrAuto as GenericPositionOrAuto;
16use crate::values::generics::position::ZIndex as GenericZIndex;
17use crate::values::generics::position::{
18 AnchorSideKeyword, GenericAnchorFunction, GenericAnchorSide,
19};
20use crate::values::generics::position::{AspectRatio as GenericAspectRatio, GenericInset};
21pub use crate::values::specified::position::{
22 AnchorName, AnchorScope, DashedIdentAndOrTryTactic, PositionAnchor, PositionArea,
23 PositionAreaKeyword, PositionAreaType, PositionTryFallbacks, PositionTryOrder,
24 PositionVisibility,
25};
26pub use crate::values::specified::position::{GridAutoFlow, GridTemplateAreas, MasonryAutoFlow};
27use crate::Zero;
28use std::fmt::{self, Write};
29use style_traits::{CssWriter, ToCss};
30
31pub type Position = GenericPosition<HorizontalPosition, VerticalPosition>;
33
34pub type PositionOrAuto = GenericPositionOrAuto<Position>;
36
37pub type HorizontalPosition = LengthPercentage;
39
40pub type VerticalPosition = LengthPercentage;
42
43pub type AnchorSide = GenericAnchorSide<Percentage>;
45
46impl AnchorSide {
47 pub fn keyword_and_percentage(&self) -> (AnchorSideKeyword, Percentage) {
49 match self {
50 Self::Percentage(p) => (AnchorSideKeyword::Start, *p),
51 Self::Keyword(k) => {
52 if matches!(k, AnchorSideKeyword::Center) {
53 (AnchorSideKeyword::Start, Percentage(0.5))
54 } else {
55 (*k, Percentage::zero())
56 }
57 },
58 }
59 }
60}
61
62pub type AnchorFunction = GenericAnchorFunction<Percentage, Inset>;
64
65#[cfg(feature = "gecko")]
66use crate::{
67 gecko_bindings::structs::AnchorPosOffsetResolutionParams,
68 logical_geometry::PhysicalSide,
69 values::{computed::Length, DashedIdent},
70};
71
72impl AnchorFunction {
73 #[cfg(feature = "gecko")]
75 pub fn resolve(
76 anchor_name: &DashedIdent,
77 anchor_side: &AnchorSide,
78 prop_side: PhysicalSide,
79 params: &AnchorPosOffsetResolutionParams,
80 ) -> Result<Length, ()> {
81 use crate::gecko_bindings::structs::Gecko_GetAnchorPosOffset;
82
83 let (keyword, percentage) = anchor_side.keyword_and_percentage();
84 let mut offset = Length::zero();
85 let valid = unsafe {
86 Gecko_GetAnchorPosOffset(
87 params,
88 anchor_name.0.as_ptr(),
89 prop_side as u8,
90 keyword as u8,
91 percentage.0,
92 &mut offset,
93 )
94 };
95
96 if !valid {
97 return Err(());
98 }
99
100 Ok(offset)
101 }
102}
103
104pub type Inset = GenericInset<Percentage, LengthPercentage>;
106
107impl Position {
108 #[inline]
110 pub fn center() -> Self {
111 Self::new(
112 LengthPercentage::new_percent(Percentage(0.5)),
113 LengthPercentage::new_percent(Percentage(0.5)),
114 )
115 }
116
117 #[inline]
119 pub fn zero() -> Self {
120 Self::new(LengthPercentage::zero(), LengthPercentage::zero())
121 }
122}
123
124impl ToCss for Position {
125 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
126 where
127 W: Write,
128 {
129 self.horizontal.to_css(dest)?;
130 dest.write_char(' ')?;
131 self.vertical.to_css(dest)
132 }
133}
134
135impl GenericPositionComponent for LengthPercentage {
136 fn is_center(&self) -> bool {
137 match self.to_percentage() {
138 Some(Percentage(per)) => per == 0.5,
139 _ => false,
140 }
141 }
142}
143
144#[inline]
145fn block_or_inline_to_inferred(keyword: PositionAreaKeyword) -> PositionAreaKeyword {
146 match keyword {
147 PositionAreaKeyword::BlockStart | PositionAreaKeyword::InlineStart => {
148 PositionAreaKeyword::Start
149 },
150 PositionAreaKeyword::BlockEnd | PositionAreaKeyword::InlineEnd => PositionAreaKeyword::End,
151 PositionAreaKeyword::SpanBlockStart | PositionAreaKeyword::SpanInlineStart => {
152 PositionAreaKeyword::SpanStart
153 },
154 PositionAreaKeyword::SpanBlockEnd | PositionAreaKeyword::SpanInlineEnd => {
155 PositionAreaKeyword::SpanEnd
156 },
157 PositionAreaKeyword::SelfBlockStart | PositionAreaKeyword::SelfInlineStart => {
158 PositionAreaKeyword::SelfStart
159 },
160 PositionAreaKeyword::SelfBlockEnd | PositionAreaKeyword::SelfInlineEnd => {
161 PositionAreaKeyword::SelfEnd
162 },
163 PositionAreaKeyword::SpanSelfBlockStart | PositionAreaKeyword::SpanSelfInlineStart => {
164 PositionAreaKeyword::SpanSelfStart
165 },
166 PositionAreaKeyword::SpanSelfBlockEnd | PositionAreaKeyword::SpanSelfInlineEnd => {
167 PositionAreaKeyword::SpanSelfEnd
168 },
169 other => other,
170 }
171}
172
173#[inline]
174fn inferred_to_block(keyword: PositionAreaKeyword) -> PositionAreaKeyword {
175 match keyword {
176 PositionAreaKeyword::Start => PositionAreaKeyword::BlockStart,
177 PositionAreaKeyword::End => PositionAreaKeyword::BlockEnd,
178 PositionAreaKeyword::SpanStart => PositionAreaKeyword::SpanBlockStart,
179 PositionAreaKeyword::SpanEnd => PositionAreaKeyword::SpanBlockEnd,
180 PositionAreaKeyword::SelfStart => PositionAreaKeyword::SelfBlockStart,
181 PositionAreaKeyword::SelfEnd => PositionAreaKeyword::SelfBlockEnd,
182 PositionAreaKeyword::SpanSelfStart => PositionAreaKeyword::SpanSelfBlockStart,
183 PositionAreaKeyword::SpanSelfEnd => PositionAreaKeyword::SpanSelfBlockEnd,
184 other => other,
185 }
186}
187
188#[inline]
189fn inferred_to_inline(keyword: PositionAreaKeyword) -> PositionAreaKeyword {
190 match keyword {
191 PositionAreaKeyword::Start => PositionAreaKeyword::InlineStart,
192 PositionAreaKeyword::End => PositionAreaKeyword::InlineEnd,
193 PositionAreaKeyword::SpanStart => PositionAreaKeyword::SpanInlineStart,
194 PositionAreaKeyword::SpanEnd => PositionAreaKeyword::SpanInlineEnd,
195 PositionAreaKeyword::SelfStart => PositionAreaKeyword::SelfInlineStart,
196 PositionAreaKeyword::SelfEnd => PositionAreaKeyword::SelfInlineEnd,
197 PositionAreaKeyword::SpanSelfStart => PositionAreaKeyword::SpanSelfInlineStart,
198 PositionAreaKeyword::SpanSelfEnd => PositionAreaKeyword::SpanSelfInlineEnd,
199 other => other,
200 }
201}
202
203impl ToComputedValue for PositionArea {
210 type ComputedValue = PositionArea;
211
212 fn to_computed_value(&self, _context: &Context) -> Self::ComputedValue {
213 let mut computed = self.clone();
214
215 let pair_type = self.get_type();
216
217 if pair_type == PositionAreaType::Logical || pair_type == PositionAreaType::SelfLogical {
218 if computed.second != PositionAreaKeyword::None {
219 computed.first = block_or_inline_to_inferred(computed.first);
220 computed.second = block_or_inline_to_inferred(computed.second);
221 }
222 } else if pair_type == PositionAreaType::Inferred
223 || pair_type == PositionAreaType::SelfInferred
224 {
225 if computed.second == PositionAreaKeyword::SpanAll {
226 computed.first = inferred_to_block(computed.first);
229 computed.second = PositionAreaKeyword::None;
230 } else if computed.first == PositionAreaKeyword::SpanAll {
231 computed.first = computed.second;
232 computed.first = inferred_to_inline(computed.first);
233 computed.second = PositionAreaKeyword::None;
234 }
235 }
236
237 if computed.first == computed.second {
238 computed.second = PositionAreaKeyword::None;
239 }
240
241 computed
242 }
243
244 fn from_computed_value(computed: &Self::ComputedValue) -> Self {
245 computed.clone()
246 }
247}
248
249pub type ZIndex = GenericZIndex<Integer>;
251
252pub type AspectRatio = GenericAspectRatio<NonNegativeNumber>;