1#![allow(clippy::match_same_arms)]
20
21use crate::props::basic::length::{FloatValue, SizeMetric};
22use crate::props::basic::pixel::PixelValue;
23use crate::props::layout::{
24 display::LayoutDisplay,
25 dimensions::{LayoutHeight, LayoutWidth, LayoutMaxHeight, LayoutMaxWidth, LayoutMinHeight, LayoutMinWidth},
26 flex::{
27 LayoutAlignContent, LayoutAlignItems, LayoutAlignSelf, LayoutFlexDirection, LayoutFlexWrap,
28 LayoutJustifyContent,
29 },
30 grid::{LayoutGridAutoFlow, LayoutJustifySelf, LayoutJustifyItems},
31 overflow::LayoutOverflow,
32 position::LayoutPosition,
33 wrapping::{LayoutClear, LayoutWritingMode},
34 table::StyleBorderCollapse,
35};
36use crate::props::layout::display::LayoutFloat;
37use crate::props::layout::dimensions::LayoutBoxSizing;
38use crate::props::basic::font::{StyleFontStyle, StyleFontWeight};
39use crate::props::basic::color::ColorU;
40use crate::props::style::{StyleTextAlign, StyleVerticalAlign, StyleVisibility, StyleWhiteSpace, StyleDirection};
41use crate::props::style::border::BorderStyle;
42use crate::props::property::{CssProperty, CssPropertyType};
43use crate::css::CssPropertyValue;
44use alloc::boxed::Box;
45use alloc::vec::Vec;
46
47pub const U16_SENTINEL: u16 = 0xFFFF;
53pub const U16_SENTINEL_THRESHOLD: u16 = 0xFFF9;
55
56pub const I16_SENTINEL: i16 = 0x7FFF; pub const I16_AUTO: i16 = 0x7FFE; pub const I16_INHERIT: i16 = 0x7FFD; pub const I16_INITIAL: i16 = 0x7FFC; pub const I16_SENTINEL_THRESHOLD: i16 = 0x7FFC; pub const U32_SENTINEL: u32 = 0xFFFF_FFFF;
66pub const U32_AUTO: u32 = 0xFFFF_FFFE;
67pub const U32_NONE: u32 = 0xFFFF_FFFD;
68pub const U32_INHERIT: u32 = 0xFFFF_FFFC;
69pub const U32_INITIAL: u32 = 0xFFFF_FFFB;
70pub const U32_MIN_CONTENT: u32 = 0xFFFF_FFFA;
71pub const U32_MAX_CONTENT: u32 = 0xFFFF_FFF9;
72pub const U32_SENTINEL_THRESHOLD: u32 = 0xFFFF_FFF9;
74
75pub const DISPLAY_SHIFT: u32 = 0;
105pub const POSITION_SHIFT: u32 = 5;
106pub const FLOAT_SHIFT: u32 = 8;
107pub const OVERFLOW_X_SHIFT: u32 = 10;
108pub const OVERFLOW_Y_SHIFT: u32 = 13;
109pub const BOX_SIZING_SHIFT: u32 = 16;
110pub const FLEX_DIRECTION_SHIFT: u32 = 17;
111pub const FLEX_WRAP_SHIFT: u32 = 19;
112pub const JUSTIFY_CONTENT_SHIFT: u32 = 21;
113pub const ALIGN_ITEMS_SHIFT: u32 = 24;
114pub const ALIGN_CONTENT_SHIFT: u32 = 27;
115pub const WRITING_MODE_SHIFT: u32 = 30;
116pub const CLEAR_SHIFT: u32 = 32;
117pub const FONT_WEIGHT_SHIFT: u32 = 34;
118pub const FONT_STYLE_SHIFT: u32 = 38;
119pub const TEXT_ALIGN_SHIFT: u32 = 40;
120pub const VISIBILITY_SHIFT: u32 = 43;
121pub const WHITE_SPACE_SHIFT: u32 = 45;
122pub const DIRECTION_SHIFT: u32 = 48;
123pub const VERTICAL_ALIGN_SHIFT: u32 = 49;
124pub const BORDER_COLLAPSE_SHIFT: u32 = 52;
125
126pub const DISPLAY_MASK: u64 = 0x1F; pub const POSITION_MASK: u64 = 0x07; pub const FLOAT_MASK: u64 = 0x03; pub const OVERFLOW_MASK: u64 = 0x07; pub const BOX_SIZING_MASK: u64 = 0x01; pub const FLEX_DIR_MASK: u64 = 0x03; pub const FLEX_WRAP_MASK: u64 = 0x03; pub const JUSTIFY_MASK: u64 = 0x07; pub const ALIGN_MASK: u64 = 0x07; pub const WRITING_MODE_MASK: u64 = 0x03;pub const CLEAR_MASK: u64 = 0x03; pub const FONT_WEIGHT_MASK: u64 = 0x0F; pub const FONT_STYLE_MASK: u64 = 0x03; pub const TEXT_ALIGN_MASK: u64 = 0x07; pub const VISIBILITY_MASK: u64 = 0x03; pub const WHITE_SPACE_MASK: u64 = 0x07; pub const DIRECTION_MASK: u64 = 0x01; pub const VERTICAL_ALIGN_MASK: u64 = 0x07; pub const BORDER_COLLAPSE_MASK: u64 = 0x01; pub const ALIGN_SELF_SHIFT: u32 = 53;
148pub const JUSTIFY_SELF_SHIFT: u32 = 56;
149pub const GRID_AUTO_FLOW_SHIFT: u32 = 59;
150pub const JUSTIFY_ITEMS_SHIFT: u32 = 61;
151pub const ALIGN_SELF_MASK: u64 = 0x07; pub const JUSTIFY_SELF_MASK: u64 = 0x07; pub const GRID_AUTO_FLOW_MASK: u64 = 0x03; pub const JUSTIFY_ITEMS_MASK: u64 = 0x03; pub const TIER1_POPULATED_BIT: u64 = 1 << 63;
164
165#[inline]
173#[must_use] pub const fn layout_display_from_u8(v: u8) -> LayoutDisplay {
174 match v {
175 0 => LayoutDisplay::Block, 1 => LayoutDisplay::Inline,
177 2 => LayoutDisplay::InlineBlock,
178 3 => LayoutDisplay::Flex,
179 4 => LayoutDisplay::None,
180 5 => LayoutDisplay::InlineFlex,
181 6 => LayoutDisplay::Table,
182 7 => LayoutDisplay::InlineTable,
183 8 => LayoutDisplay::TableRowGroup,
184 9 => LayoutDisplay::TableHeaderGroup,
185 10 => LayoutDisplay::TableFooterGroup,
186 11 => LayoutDisplay::TableRow,
187 12 => LayoutDisplay::TableColumnGroup,
188 13 => LayoutDisplay::TableColumn,
189 14 => LayoutDisplay::TableCell,
190 15 => LayoutDisplay::TableCaption,
191 16 => LayoutDisplay::FlowRoot,
192 17 => LayoutDisplay::ListItem,
193 18 => LayoutDisplay::RunIn,
194 19 => LayoutDisplay::Marker,
195 20 => LayoutDisplay::Grid,
196 21 => LayoutDisplay::InlineGrid,
197 22 => LayoutDisplay::Contents,
198 _ => LayoutDisplay::Block, }
200}
201
202#[inline]
204#[must_use] pub const fn layout_display_to_u8(v: LayoutDisplay) -> u8 {
205 match v {
206 LayoutDisplay::Block => 0, LayoutDisplay::Inline => 1,
208 LayoutDisplay::InlineBlock => 2,
209 LayoutDisplay::Flex => 3,
210 LayoutDisplay::None => 4,
211 LayoutDisplay::InlineFlex => 5,
212 LayoutDisplay::Table => 6,
213 LayoutDisplay::InlineTable => 7,
214 LayoutDisplay::TableRowGroup => 8,
215 LayoutDisplay::TableHeaderGroup => 9,
216 LayoutDisplay::TableFooterGroup => 10,
217 LayoutDisplay::TableRow => 11,
218 LayoutDisplay::TableColumnGroup => 12,
219 LayoutDisplay::TableColumn => 13,
220 LayoutDisplay::TableCell => 14,
221 LayoutDisplay::TableCaption => 15,
222 LayoutDisplay::FlowRoot => 16,
223 LayoutDisplay::ListItem => 17,
224 LayoutDisplay::RunIn => 18,
225 LayoutDisplay::Marker => 19,
226 LayoutDisplay::Grid => 20,
227 LayoutDisplay::InlineGrid => 21,
228 LayoutDisplay::Contents => 22,
229 }
230}
231
232#[inline]
233#[must_use] pub const fn layout_position_from_u8(v: u8) -> LayoutPosition {
234 match v {
235 0 => LayoutPosition::Static,
236 1 => LayoutPosition::Relative,
237 2 => LayoutPosition::Absolute,
238 3 => LayoutPosition::Fixed,
239 4 => LayoutPosition::Sticky,
240 _ => LayoutPosition::Static,
241 }
242}
243
244#[inline]
245#[must_use] pub const fn layout_position_to_u8(v: LayoutPosition) -> u8 {
246 match v {
247 LayoutPosition::Static => 0,
248 LayoutPosition::Relative => 1,
249 LayoutPosition::Absolute => 2,
250 LayoutPosition::Fixed => 3,
251 LayoutPosition::Sticky => 4,
252 }
253}
254
255#[inline]
257#[must_use] pub const fn layout_float_from_u8(v: u8) -> LayoutFloat {
258 match v {
259 0 => LayoutFloat::None, 1 => LayoutFloat::Left,
261 2 => LayoutFloat::Right,
262 _ => LayoutFloat::None,
263 }
264}
265
266#[inline]
268#[must_use] pub const fn layout_float_to_u8(v: LayoutFloat) -> u8 {
269 match v {
270 LayoutFloat::None => 0,
271 LayoutFloat::Left => 1,
272 LayoutFloat::Right => 2,
273 }
274}
275
276#[inline]
278#[must_use] pub const fn layout_overflow_from_u8(v: u8) -> LayoutOverflow {
279 match v {
280 0 => LayoutOverflow::Visible, 1 => LayoutOverflow::Hidden,
282 2 => LayoutOverflow::Scroll,
283 3 => LayoutOverflow::Auto,
284 4 => LayoutOverflow::Clip,
285 _ => LayoutOverflow::Visible,
286 }
287}
288
289#[inline]
291#[must_use] pub const fn layout_overflow_to_u8(v: LayoutOverflow) -> u8 {
292 match v {
293 LayoutOverflow::Visible => 0, LayoutOverflow::Hidden => 1,
295 LayoutOverflow::Scroll => 2,
296 LayoutOverflow::Auto => 3,
297 LayoutOverflow::Clip => 4,
298 }
299}
300
301#[inline]
302#[must_use] pub const fn layout_box_sizing_from_u8(v: u8) -> LayoutBoxSizing {
303 match v {
304 0 => LayoutBoxSizing::ContentBox,
305 1 => LayoutBoxSizing::BorderBox,
306 _ => LayoutBoxSizing::ContentBox,
307 }
308}
309
310#[inline]
311#[must_use] pub const fn layout_box_sizing_to_u8(v: LayoutBoxSizing) -> u8 {
312 match v {
313 LayoutBoxSizing::ContentBox => 0,
314 LayoutBoxSizing::BorderBox => 1,
315 }
316}
317
318#[inline]
319#[must_use] pub const fn layout_flex_direction_from_u8(v: u8) -> LayoutFlexDirection {
320 match v {
321 0 => LayoutFlexDirection::Row,
322 1 => LayoutFlexDirection::RowReverse,
323 2 => LayoutFlexDirection::Column,
324 3 => LayoutFlexDirection::ColumnReverse,
325 _ => LayoutFlexDirection::Row,
326 }
327}
328
329#[inline]
330#[must_use] pub const fn layout_flex_direction_to_u8(v: LayoutFlexDirection) -> u8 {
331 match v {
332 LayoutFlexDirection::Row => 0,
333 LayoutFlexDirection::RowReverse => 1,
334 LayoutFlexDirection::Column => 2,
335 LayoutFlexDirection::ColumnReverse => 3,
336 }
337}
338
339#[inline]
341#[must_use] pub const fn layout_flex_wrap_from_u8(v: u8) -> LayoutFlexWrap {
342 match v {
343 0 => LayoutFlexWrap::NoWrap, 1 => LayoutFlexWrap::Wrap,
345 2 => LayoutFlexWrap::WrapReverse,
346 _ => LayoutFlexWrap::NoWrap,
347 }
348}
349
350#[inline]
351#[must_use] pub const fn layout_flex_wrap_to_u8(v: LayoutFlexWrap) -> u8 {
352 match v {
353 LayoutFlexWrap::NoWrap => 0,
354 LayoutFlexWrap::Wrap => 1,
355 LayoutFlexWrap::WrapReverse => 2,
356 }
357}
358
359#[inline]
360#[must_use] pub const fn layout_justify_content_from_u8(v: u8) -> LayoutJustifyContent {
361 match v {
362 0 => LayoutJustifyContent::FlexStart,
363 1 => LayoutJustifyContent::FlexEnd,
364 2 => LayoutJustifyContent::Start,
365 3 => LayoutJustifyContent::End,
366 4 => LayoutJustifyContent::Center,
367 5 => LayoutJustifyContent::SpaceBetween,
368 6 => LayoutJustifyContent::SpaceAround,
369 7 => LayoutJustifyContent::SpaceEvenly,
370 _ => LayoutJustifyContent::FlexStart,
371 }
372}
373
374#[inline]
375#[must_use] pub const fn layout_justify_content_to_u8(v: LayoutJustifyContent) -> u8 {
376 match v {
377 LayoutJustifyContent::FlexStart => 0,
378 LayoutJustifyContent::FlexEnd => 1,
379 LayoutJustifyContent::Start => 2,
380 LayoutJustifyContent::End => 3,
381 LayoutJustifyContent::Center => 4,
382 LayoutJustifyContent::SpaceBetween => 5,
383 LayoutJustifyContent::SpaceAround => 6,
384 LayoutJustifyContent::SpaceEvenly => 7,
385 }
386}
387
388#[inline]
389#[must_use] pub const fn layout_align_items_from_u8(v: u8) -> LayoutAlignItems {
390 match v {
391 0 => LayoutAlignItems::Stretch,
392 1 => LayoutAlignItems::Center,
393 2 => LayoutAlignItems::Start,
394 3 => LayoutAlignItems::End,
395 4 => LayoutAlignItems::Baseline,
396 _ => LayoutAlignItems::Stretch,
397 }
398}
399
400#[inline]
401#[must_use] pub const fn layout_align_items_to_u8(v: LayoutAlignItems) -> u8 {
402 match v {
403 LayoutAlignItems::Stretch => 0,
404 LayoutAlignItems::Center => 1,
405 LayoutAlignItems::Start => 2,
406 LayoutAlignItems::End => 3,
407 LayoutAlignItems::Baseline => 4,
408 }
409}
410
411#[inline]
412#[must_use] pub const fn layout_align_self_to_u8(v: LayoutAlignSelf) -> u8 {
413 match v {
414 LayoutAlignSelf::Auto => 0,
415 LayoutAlignSelf::Stretch => 1,
416 LayoutAlignSelf::Center => 2,
417 LayoutAlignSelf::Start => 3,
418 LayoutAlignSelf::End => 4,
419 LayoutAlignSelf::Baseline => 5,
420 }
421}
422
423#[inline]
424#[must_use] pub const fn layout_align_self_from_u8(v: u8) -> LayoutAlignSelf {
425 match v {
426 0 => LayoutAlignSelf::Auto,
427 1 => LayoutAlignSelf::Stretch,
428 2 => LayoutAlignSelf::Center,
429 3 => LayoutAlignSelf::Start,
430 4 => LayoutAlignSelf::End,
431 5 => LayoutAlignSelf::Baseline,
432 _ => LayoutAlignSelf::Auto,
433 }
434}
435
436#[inline]
437#[must_use] pub const fn layout_justify_self_to_u8(v: LayoutJustifySelf) -> u8 {
438 match v {
439 LayoutJustifySelf::Auto => 0,
440 LayoutJustifySelf::Start => 1,
441 LayoutJustifySelf::End => 2,
442 LayoutJustifySelf::Center => 3,
443 LayoutJustifySelf::Stretch => 4,
444 }
445}
446
447#[inline]
448#[must_use] pub const fn layout_justify_self_from_u8(v: u8) -> LayoutJustifySelf {
449 match v {
450 0 => LayoutJustifySelf::Auto,
451 1 => LayoutJustifySelf::Start,
452 2 => LayoutJustifySelf::End,
453 3 => LayoutJustifySelf::Center,
454 4 => LayoutJustifySelf::Stretch,
455 _ => LayoutJustifySelf::Auto,
456 }
457}
458
459#[inline]
466#[must_use] pub const fn layout_justify_items_to_u8(v: LayoutJustifyItems) -> u8 {
467 match v {
468 LayoutJustifyItems::Stretch => 0,
469 LayoutJustifyItems::Start => 1,
470 LayoutJustifyItems::End => 2,
471 LayoutJustifyItems::Center => 3,
472 }
473}
474
475#[inline]
476#[must_use] pub const fn layout_justify_items_from_u8(v: u8) -> LayoutJustifyItems {
477 match v {
478 0 => LayoutJustifyItems::Stretch,
479 1 => LayoutJustifyItems::Start,
480 2 => LayoutJustifyItems::End,
481 3 => LayoutJustifyItems::Center,
482 _ => LayoutJustifyItems::Stretch,
483 }
484}
485
486#[inline]
487#[must_use] pub const fn layout_grid_auto_flow_to_u8(v: LayoutGridAutoFlow) -> u8 {
488 match v {
489 LayoutGridAutoFlow::Row => 0,
490 LayoutGridAutoFlow::Column => 1,
491 LayoutGridAutoFlow::RowDense => 2,
492 LayoutGridAutoFlow::ColumnDense => 3,
493 }
494}
495
496#[inline]
497#[must_use] pub const fn layout_grid_auto_flow_from_u8(v: u8) -> LayoutGridAutoFlow {
498 match v {
499 0 => LayoutGridAutoFlow::Row,
500 1 => LayoutGridAutoFlow::Column,
501 2 => LayoutGridAutoFlow::RowDense,
502 3 => LayoutGridAutoFlow::ColumnDense,
503 _ => LayoutGridAutoFlow::Row,
504 }
505}
506
507#[inline]
508#[must_use] pub const fn layout_align_content_from_u8(v: u8) -> LayoutAlignContent {
509 match v {
510 0 => LayoutAlignContent::Stretch,
511 1 => LayoutAlignContent::Center,
512 2 => LayoutAlignContent::Start,
513 3 => LayoutAlignContent::End,
514 4 => LayoutAlignContent::SpaceBetween,
515 5 => LayoutAlignContent::SpaceAround,
516 _ => LayoutAlignContent::Stretch,
517 }
518}
519
520#[inline]
521#[must_use] pub const fn layout_align_content_to_u8(v: LayoutAlignContent) -> u8 {
522 match v {
523 LayoutAlignContent::Stretch => 0,
524 LayoutAlignContent::Center => 1,
525 LayoutAlignContent::Start => 2,
526 LayoutAlignContent::End => 3,
527 LayoutAlignContent::SpaceBetween => 4,
528 LayoutAlignContent::SpaceAround => 5,
529 }
530}
531
532#[inline]
533#[must_use] pub const fn layout_writing_mode_from_u8(v: u8) -> LayoutWritingMode {
534 match v {
535 0 => LayoutWritingMode::HorizontalTb,
536 1 => LayoutWritingMode::VerticalRl,
537 2 => LayoutWritingMode::VerticalLr,
538 _ => LayoutWritingMode::HorizontalTb,
539 }
540}
541
542#[inline]
543#[must_use] pub const fn layout_writing_mode_to_u8(v: LayoutWritingMode) -> u8 {
544 match v {
545 LayoutWritingMode::HorizontalTb => 0,
546 LayoutWritingMode::VerticalRl => 1,
547 LayoutWritingMode::VerticalLr => 2,
548 }
549}
550
551#[inline]
552#[must_use] pub const fn layout_clear_from_u8(v: u8) -> LayoutClear {
553 match v {
554 0 => LayoutClear::None,
555 1 => LayoutClear::Left,
556 2 => LayoutClear::Right,
557 3 => LayoutClear::Both,
558 _ => LayoutClear::None,
559 }
560}
561
562#[inline]
563#[must_use] pub const fn layout_clear_to_u8(v: LayoutClear) -> u8 {
564 match v {
565 LayoutClear::None => 0,
566 LayoutClear::Left => 1,
567 LayoutClear::Right => 2,
568 LayoutClear::Both => 3,
569 }
570}
571
572#[inline]
573#[must_use] pub const fn style_font_weight_from_u8(v: u8) -> StyleFontWeight {
575 match v {
576 0 => StyleFontWeight::Normal, 1 => StyleFontWeight::W100,
578 2 => StyleFontWeight::W200,
579 3 => StyleFontWeight::W300,
580 4 => StyleFontWeight::W500,
581 5 => StyleFontWeight::W600,
582 6 => StyleFontWeight::Bold, 7 => StyleFontWeight::W800,
584 8 => StyleFontWeight::W900,
585 9 => StyleFontWeight::Lighter,
586 10 => StyleFontWeight::Bolder,
587 _ => StyleFontWeight::Normal,
588 }
589}
590
591#[inline]
592#[must_use] pub const fn style_font_weight_to_u8(v: StyleFontWeight) -> u8 {
594 match v {
595 StyleFontWeight::Normal => 0, StyleFontWeight::W100 => 1,
597 StyleFontWeight::W200 => 2,
598 StyleFontWeight::W300 => 3,
599 StyleFontWeight::W500 => 4,
600 StyleFontWeight::W600 => 5,
601 StyleFontWeight::Bold => 6, StyleFontWeight::W800 => 7,
603 StyleFontWeight::W900 => 8,
604 StyleFontWeight::Lighter => 9,
605 StyleFontWeight::Bolder => 10,
606 }
607}
608
609#[inline]
610#[must_use] pub const fn style_font_style_from_u8(v: u8) -> StyleFontStyle {
611 match v {
612 0 => StyleFontStyle::Normal,
613 1 => StyleFontStyle::Italic,
614 2 => StyleFontStyle::Oblique,
615 _ => StyleFontStyle::Normal,
616 }
617}
618
619#[inline]
620#[must_use] pub const fn style_font_style_to_u8(v: StyleFontStyle) -> u8 {
621 match v {
622 StyleFontStyle::Normal => 0,
623 StyleFontStyle::Italic => 1,
624 StyleFontStyle::Oblique => 2,
625 }
626}
627
628#[inline]
629#[must_use] pub const fn style_text_align_from_u8(v: u8) -> StyleTextAlign {
630 match v {
635 0 => StyleTextAlign::Start,
636 1 => StyleTextAlign::Center,
637 2 => StyleTextAlign::Right,
638 3 => StyleTextAlign::Justify,
639 4 => StyleTextAlign::Left,
640 5 => StyleTextAlign::End,
641 _ => StyleTextAlign::Start,
642 }
643}
644
645#[inline]
646#[must_use] pub const fn style_text_align_to_u8(v: StyleTextAlign) -> u8 {
647 match v {
649 StyleTextAlign::Start => 0,
650 StyleTextAlign::Center => 1,
651 StyleTextAlign::Right => 2,
652 StyleTextAlign::Justify => 3,
653 StyleTextAlign::Left => 4,
654 StyleTextAlign::End => 5,
655 }
656}
657
658#[inline]
659#[must_use] pub const fn style_visibility_from_u8(v: u8) -> StyleVisibility {
660 match v {
661 0 => StyleVisibility::Visible,
662 1 => StyleVisibility::Hidden,
663 2 => StyleVisibility::Collapse,
664 _ => StyleVisibility::Visible,
665 }
666}
667
668#[inline]
669#[must_use] pub const fn style_visibility_to_u8(v: StyleVisibility) -> u8 {
670 match v {
671 StyleVisibility::Visible => 0,
672 StyleVisibility::Hidden => 1,
673 StyleVisibility::Collapse => 2,
674 }
675}
676
677#[inline]
678#[must_use] pub const fn style_white_space_from_u8(v: u8) -> StyleWhiteSpace {
679 match v {
680 0 => StyleWhiteSpace::Normal,
681 1 => StyleWhiteSpace::Pre,
682 2 => StyleWhiteSpace::Nowrap,
683 3 => StyleWhiteSpace::PreWrap,
684 4 => StyleWhiteSpace::PreLine,
685 5 => StyleWhiteSpace::BreakSpaces,
686 _ => StyleWhiteSpace::Normal,
687 }
688}
689
690#[inline]
691#[must_use] pub const fn style_white_space_to_u8(v: StyleWhiteSpace) -> u8 {
692 match v {
693 StyleWhiteSpace::Normal => 0,
694 StyleWhiteSpace::Pre => 1,
695 StyleWhiteSpace::Nowrap => 2,
696 StyleWhiteSpace::PreWrap => 3,
697 StyleWhiteSpace::PreLine => 4,
698 StyleWhiteSpace::BreakSpaces => 5,
699 }
700}
701
702#[inline]
703#[must_use] pub const fn style_direction_from_u8(v: u8) -> StyleDirection {
704 match v {
705 0 => StyleDirection::Ltr,
706 1 => StyleDirection::Rtl,
707 _ => StyleDirection::Ltr,
708 }
709}
710
711#[inline]
712#[must_use] pub const fn style_direction_to_u8(v: StyleDirection) -> u8 {
713 match v {
714 StyleDirection::Ltr => 0,
715 StyleDirection::Rtl => 1,
716 }
717}
718
719#[inline]
720#[must_use] pub const fn style_vertical_align_from_u8(v: u8) -> StyleVerticalAlign {
721 match v {
722 0 => StyleVerticalAlign::Baseline,
723 1 => StyleVerticalAlign::Top,
724 2 => StyleVerticalAlign::Middle,
725 3 => StyleVerticalAlign::Bottom,
726 4 => StyleVerticalAlign::Sub,
727 5 => StyleVerticalAlign::Superscript,
728 6 => StyleVerticalAlign::TextTop,
729 7 => StyleVerticalAlign::TextBottom,
730 _ => StyleVerticalAlign::Baseline,
731 }
732}
733
734#[inline]
735#[must_use] pub const fn style_vertical_align_to_u8(v: StyleVerticalAlign) -> u8 {
736 match v {
737 StyleVerticalAlign::Baseline => 0,
738 StyleVerticalAlign::Top => 1,
739 StyleVerticalAlign::Middle => 2,
740 StyleVerticalAlign::Bottom => 3,
741 StyleVerticalAlign::Sub => 4,
742 StyleVerticalAlign::Superscript => 5,
743 StyleVerticalAlign::TextTop => 6,
744 StyleVerticalAlign::TextBottom => 7,
745 StyleVerticalAlign::Percentage(_) | StyleVerticalAlign::Length(_) => 0,
749 }
750}
751
752#[inline]
753#[must_use] pub const fn border_collapse_from_u8(v: u8) -> StyleBorderCollapse {
754 match v {
755 0 => StyleBorderCollapse::Separate,
756 1 => StyleBorderCollapse::Collapse,
757 _ => StyleBorderCollapse::Separate,
758 }
759}
760
761#[inline]
762#[must_use] pub const fn border_collapse_to_u8(v: StyleBorderCollapse) -> u8 {
763 match v {
764 StyleBorderCollapse::Separate => 0,
765 StyleBorderCollapse::Collapse => 1,
766 }
767}
768
769#[inline]
770#[must_use] pub const fn border_style_from_u8(v: u8) -> BorderStyle {
771 match v {
772 0 => BorderStyle::None,
773 1 => BorderStyle::Solid,
774 2 => BorderStyle::Double,
775 3 => BorderStyle::Dotted,
776 4 => BorderStyle::Dashed,
777 5 => BorderStyle::Hidden,
778 6 => BorderStyle::Groove,
779 7 => BorderStyle::Ridge,
780 8 => BorderStyle::Inset,
781 9 => BorderStyle::Outset,
782 _ => BorderStyle::None,
783 }
784}
785
786#[inline]
787#[must_use] pub const fn border_style_to_u8(v: BorderStyle) -> u8 {
788 match v {
789 BorderStyle::None => 0,
790 BorderStyle::Solid => 1,
791 BorderStyle::Double => 2,
792 BorderStyle::Dotted => 3,
793 BorderStyle::Dashed => 4,
794 BorderStyle::Hidden => 5,
795 BorderStyle::Groove => 6,
796 BorderStyle::Ridge => 7,
797 BorderStyle::Inset => 8,
798 BorderStyle::Outset => 9,
799 }
800}
801
802#[inline]
804#[must_use] pub const fn encode_border_styles_packed(top: BorderStyle, right: BorderStyle, bottom: BorderStyle, left: BorderStyle) -> u16 {
805 (border_style_to_u8(top) as u16)
806 | ((border_style_to_u8(right) as u16) << 4)
807 | ((border_style_to_u8(bottom) as u16) << 8)
808 | ((border_style_to_u8(left) as u16) << 12)
809}
810
811#[inline]
813#[must_use] pub const fn decode_border_top_style(packed: u16) -> BorderStyle {
814 border_style_from_u8((packed & 0x0F) as u8)
815}
816
817#[inline]
819#[must_use] pub const fn decode_border_right_style(packed: u16) -> BorderStyle {
820 border_style_from_u8(((packed >> 4) & 0x0F) as u8)
821}
822
823#[inline]
825#[must_use] pub const fn decode_border_bottom_style(packed: u16) -> BorderStyle {
826 border_style_from_u8(((packed >> 8) & 0x0F) as u8)
827}
828
829#[inline]
831#[must_use] pub const fn decode_border_left_style(packed: u16) -> BorderStyle {
832 border_style_from_u8(((packed >> 12) & 0x0F) as u8)
833}
834
835#[inline]
837#[must_use] pub const fn encode_color_u32(c: &ColorU) -> u32 {
838 ((c.r as u32) << 24) | ((c.g as u32) << 16) | ((c.b as u32) << 8) | (c.a as u32)
839}
840
841#[inline]
847#[must_use] pub const fn decode_color_u32(v: u32) -> Option<ColorU> {
848 if v == 0 { return None; }
849 Some(ColorU {
850 r: ((v >> 24) & 0xFF) as u8,
851 g: ((v >> 16) & 0xFF) as u8,
852 b: ((v >> 8) & 0xFF) as u8,
853 a: (v & 0xFF) as u8,
854 })
855}
856
857#[inline]
863#[must_use] pub const fn encode_tier1(
864 display: LayoutDisplay,
865 position: LayoutPosition,
866 float: LayoutFloat,
867 overflow_x: LayoutOverflow,
868 overflow_y: LayoutOverflow,
869 box_sizing: LayoutBoxSizing,
870 flex_direction: LayoutFlexDirection,
871 flex_wrap: LayoutFlexWrap,
872 justify_content: LayoutJustifyContent,
873 align_items: LayoutAlignItems,
874 align_content: LayoutAlignContent,
875 writing_mode: LayoutWritingMode,
876 clear: LayoutClear,
877 font_weight: StyleFontWeight,
878 font_style: StyleFontStyle,
879 text_align: StyleTextAlign,
880 visibility: StyleVisibility,
881 white_space: StyleWhiteSpace,
882 direction: StyleDirection,
883 vertical_align: StyleVerticalAlign,
884 border_collapse: StyleBorderCollapse,
885) -> u64 {
886 let mut v: u64 = TIER1_POPULATED_BIT;
887 v |= (layout_display_to_u8(display) as u64) << DISPLAY_SHIFT;
888 v |= (layout_position_to_u8(position) as u64) << POSITION_SHIFT;
889 v |= (layout_float_to_u8(float) as u64) << FLOAT_SHIFT;
890 v |= (layout_overflow_to_u8(overflow_x) as u64) << OVERFLOW_X_SHIFT;
891 v |= (layout_overflow_to_u8(overflow_y) as u64) << OVERFLOW_Y_SHIFT;
892 v |= (layout_box_sizing_to_u8(box_sizing) as u64) << BOX_SIZING_SHIFT;
893 v |= (layout_flex_direction_to_u8(flex_direction) as u64) << FLEX_DIRECTION_SHIFT;
894 v |= (layout_flex_wrap_to_u8(flex_wrap) as u64) << FLEX_WRAP_SHIFT;
895 v |= (layout_justify_content_to_u8(justify_content) as u64) << JUSTIFY_CONTENT_SHIFT;
896 v |= (layout_align_items_to_u8(align_items) as u64) << ALIGN_ITEMS_SHIFT;
897 v |= (layout_align_content_to_u8(align_content) as u64) << ALIGN_CONTENT_SHIFT;
898 v |= (layout_writing_mode_to_u8(writing_mode) as u64) << WRITING_MODE_SHIFT;
899 v |= (layout_clear_to_u8(clear) as u64) << CLEAR_SHIFT;
900 v |= (style_font_weight_to_u8(font_weight) as u64) << FONT_WEIGHT_SHIFT;
901 v |= (style_font_style_to_u8(font_style) as u64) << FONT_STYLE_SHIFT;
902 v |= (style_text_align_to_u8(text_align) as u64) << TEXT_ALIGN_SHIFT;
903 v |= (style_visibility_to_u8(visibility) as u64) << VISIBILITY_SHIFT;
904 v |= (style_white_space_to_u8(white_space) as u64) << WHITE_SPACE_SHIFT;
905 v |= (style_direction_to_u8(direction) as u64) << DIRECTION_SHIFT;
906 v |= (style_vertical_align_to_u8(vertical_align) as u64) << VERTICAL_ALIGN_SHIFT;
907 v |= (border_collapse_to_u8(border_collapse) as u64) << BORDER_COLLAPSE_SHIFT;
908 v
909}
910
911#[inline]
915#[must_use] pub const fn decode_display(t1: u64) -> LayoutDisplay {
916 layout_display_from_u8(((t1 >> DISPLAY_SHIFT) & DISPLAY_MASK) as u8)
917}
918
919#[inline]
920#[must_use] pub const fn decode_position(t1: u64) -> LayoutPosition {
921 layout_position_from_u8(((t1 >> POSITION_SHIFT) & POSITION_MASK) as u8)
922}
923
924#[inline]
925#[must_use] pub const fn decode_float(t1: u64) -> LayoutFloat {
926 layout_float_from_u8(((t1 >> FLOAT_SHIFT) & FLOAT_MASK) as u8)
927}
928
929#[inline]
930#[must_use] pub const fn decode_overflow_x(t1: u64) -> LayoutOverflow {
931 layout_overflow_from_u8(((t1 >> OVERFLOW_X_SHIFT) & OVERFLOW_MASK) as u8)
932}
933
934#[inline]
935#[must_use] pub const fn decode_overflow_y(t1: u64) -> LayoutOverflow {
936 layout_overflow_from_u8(((t1 >> OVERFLOW_Y_SHIFT) & OVERFLOW_MASK) as u8)
937}
938
939#[inline]
940#[must_use] pub const fn decode_box_sizing(t1: u64) -> LayoutBoxSizing {
941 layout_box_sizing_from_u8(((t1 >> BOX_SIZING_SHIFT) & BOX_SIZING_MASK) as u8)
942}
943
944#[inline]
945#[must_use] pub const fn decode_flex_direction(t1: u64) -> LayoutFlexDirection {
946 layout_flex_direction_from_u8(((t1 >> FLEX_DIRECTION_SHIFT) & FLEX_DIR_MASK) as u8)
947}
948
949#[inline]
950#[must_use] pub const fn decode_flex_wrap(t1: u64) -> LayoutFlexWrap {
951 layout_flex_wrap_from_u8(((t1 >> FLEX_WRAP_SHIFT) & FLEX_WRAP_MASK) as u8)
952}
953
954#[inline]
955#[must_use] pub const fn decode_justify_content(t1: u64) -> LayoutJustifyContent {
956 layout_justify_content_from_u8(((t1 >> JUSTIFY_CONTENT_SHIFT) & JUSTIFY_MASK) as u8)
957}
958
959#[inline]
960#[must_use] pub const fn decode_align_items(t1: u64) -> LayoutAlignItems {
961 layout_align_items_from_u8(((t1 >> ALIGN_ITEMS_SHIFT) & ALIGN_MASK) as u8)
962}
963
964#[inline]
965#[must_use] pub const fn decode_align_content(t1: u64) -> LayoutAlignContent {
966 layout_align_content_from_u8(((t1 >> ALIGN_CONTENT_SHIFT) & ALIGN_MASK) as u8)
967}
968
969#[inline]
970#[must_use] pub const fn decode_writing_mode(t1: u64) -> LayoutWritingMode {
971 layout_writing_mode_from_u8(((t1 >> WRITING_MODE_SHIFT) & WRITING_MODE_MASK) as u8)
972}
973
974#[inline]
975#[must_use] pub const fn decode_clear(t1: u64) -> LayoutClear {
976 layout_clear_from_u8(((t1 >> CLEAR_SHIFT) & CLEAR_MASK) as u8)
977}
978
979#[inline]
980#[must_use] pub const fn decode_font_weight(t1: u64) -> StyleFontWeight {
981 style_font_weight_from_u8(((t1 >> FONT_WEIGHT_SHIFT) & FONT_WEIGHT_MASK) as u8)
982}
983
984#[inline]
985#[must_use] pub const fn decode_font_style(t1: u64) -> StyleFontStyle {
986 style_font_style_from_u8(((t1 >> FONT_STYLE_SHIFT) & FONT_STYLE_MASK) as u8)
987}
988
989#[inline]
990#[must_use] pub const fn decode_text_align(t1: u64) -> StyleTextAlign {
991 style_text_align_from_u8(((t1 >> TEXT_ALIGN_SHIFT) & TEXT_ALIGN_MASK) as u8)
992}
993
994#[inline]
995#[must_use] pub const fn decode_visibility(t1: u64) -> StyleVisibility {
996 style_visibility_from_u8(((t1 >> VISIBILITY_SHIFT) & VISIBILITY_MASK) as u8)
997}
998
999#[inline]
1000#[must_use] pub const fn decode_white_space(t1: u64) -> StyleWhiteSpace {
1001 style_white_space_from_u8(((t1 >> WHITE_SPACE_SHIFT) & WHITE_SPACE_MASK) as u8)
1002}
1003
1004#[inline]
1005#[must_use] pub const fn decode_direction(t1: u64) -> StyleDirection {
1006 style_direction_from_u8(((t1 >> DIRECTION_SHIFT) & DIRECTION_MASK) as u8)
1007}
1008
1009#[inline]
1010#[must_use] pub const fn decode_vertical_align(t1: u64) -> StyleVerticalAlign {
1011 style_vertical_align_from_u8(((t1 >> VERTICAL_ALIGN_SHIFT) & VERTICAL_ALIGN_MASK) as u8)
1012}
1013
1014#[inline]
1015#[must_use] pub const fn decode_border_collapse(t1: u64) -> StyleBorderCollapse {
1016 border_collapse_from_u8(((t1 >> BORDER_COLLAPSE_SHIFT) & BORDER_COLLAPSE_MASK) as u8)
1017}
1018
1019#[inline]
1021#[cfg(test)]
1022#[must_use] pub const fn tier1_is_populated(t1: u64) -> bool {
1023 (t1 & TIER1_POPULATED_BIT) != 0
1024}
1025
1026#[inline]
1041#[must_use] pub fn encode_pixel_value_u32(pv: &PixelValue) -> u32 {
1042 let metric = u32::from(size_metric_to_u8(pv.metric));
1043 let raw = pv.number.number; if !(-134_217_728..=134_217_727).contains(&raw) {
1046 return U32_SENTINEL; }
1048 let value_bits = i32::try_from(raw).unwrap_or(0).cast_unsigned() << 4;
1051 let packed = value_bits | metric;
1052 if packed >= U32_SENTINEL_THRESHOLD {
1057 return U32_SENTINEL;
1058 }
1059 packed
1060}
1061
1062#[inline]
1064#[must_use] pub const fn decode_pixel_value_u32(encoded: u32) -> Option<PixelValue> {
1065 if encoded >= U32_SENTINEL_THRESHOLD {
1066 return None; }
1068 let metric = size_metric_from_u8((encoded & 0xF) as u8);
1069 let value_bits = encoded.cast_signed() >> 4;
1071 let raw = value_bits as isize; Some(PixelValue {
1073 metric,
1074 number: FloatValue { number: raw },
1075 })
1076}
1077
1078#[inline]
1081#[must_use] pub fn encode_resolved_px_i16(px: f32) -> i16 {
1082 let scaled = crate::cast::f32_to_i32((px * 10.0).round());
1083 if scaled < -32768 || scaled > i32::from(I16_SENTINEL_THRESHOLD) - 1 {
1084 return I16_SENTINEL; }
1086 i16::try_from(scaled).unwrap_or(I16_SENTINEL)
1087}
1088
1089#[inline]
1091#[must_use] pub fn decode_resolved_px_i16(v: i16) -> Option<f32> {
1092 if v >= I16_SENTINEL_THRESHOLD {
1093 return None;
1094 }
1095 Some(f32::from(v) / 10.0)
1096}
1097
1098#[inline]
1101#[must_use] pub fn encode_flex_u16(value: f32) -> u16 {
1102 let scaled = crate::cast::f32_to_i32((value * 100.0).round());
1103 if scaled < 0 || scaled >= i32::from(U16_SENTINEL_THRESHOLD) {
1104 return U16_SENTINEL;
1105 }
1106 u16::try_from(scaled).unwrap_or(U16_SENTINEL)
1107}
1108
1109#[inline]
1111#[must_use] pub fn decode_flex_u16(v: u16) -> Option<f32> {
1112 if v >= U16_SENTINEL_THRESHOLD {
1113 return None;
1114 }
1115 Some(f32::from(v) / 100.0)
1116}
1117
1118#[inline]
1120#[must_use] pub const fn size_metric_to_u8(m: SizeMetric) -> u8 {
1121 match m {
1122 SizeMetric::Px => 0,
1123 SizeMetric::Pt => 1,
1124 SizeMetric::Em => 2,
1125 SizeMetric::Rem => 3,
1126 SizeMetric::In => 4,
1127 SizeMetric::Cm => 5,
1128 SizeMetric::Mm => 6,
1129 SizeMetric::Percent => 7,
1130 SizeMetric::Vw => 8,
1131 SizeMetric::Vh => 9,
1132 SizeMetric::Vmin => 10,
1133 SizeMetric::Vmax => 11,
1134 }
1135}
1136
1137#[inline]
1139#[must_use] pub const fn size_metric_from_u8(v: u8) -> SizeMetric {
1140 match v {
1141 0 => SizeMetric::Px,
1142 1 => SizeMetric::Pt,
1143 2 => SizeMetric::Em,
1144 3 => SizeMetric::Rem,
1145 4 => SizeMetric::In,
1146 5 => SizeMetric::Cm,
1147 6 => SizeMetric::Mm,
1148 7 => SizeMetric::Percent,
1149 8 => SizeMetric::Vw,
1150 9 => SizeMetric::Vh,
1151 10 => SizeMetric::Vmin,
1152 11 => SizeMetric::Vmax,
1153 _ => SizeMetric::Px,
1154 }
1155}
1156
1157#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1161#[repr(C)]
1162pub struct CompactNodeProps {
1163 pub width: u32,
1165 pub height: u32,
1166 pub min_width: u32,
1167 pub max_width: u32,
1168 pub min_height: u32,
1169 pub max_height: u32,
1170 pub flex_basis: u32,
1171 pub font_size: u32,
1172
1173 pub padding_top: i16,
1175 pub padding_right: i16,
1176 pub padding_bottom: i16,
1177 pub padding_left: i16,
1178 pub margin_top: i16,
1179 pub margin_right: i16,
1180 pub margin_bottom: i16,
1181 pub margin_left: i16,
1182 pub border_top_width: i16,
1183 pub border_right_width: i16,
1184 pub border_bottom_width: i16,
1185 pub border_left_width: i16,
1186 pub top: i16,
1187 pub right: i16,
1188 pub bottom: i16,
1189 pub left: i16,
1190
1191 pub flex_grow: u16,
1193 pub flex_shrink: u16,
1194
1195 pub row_gap: i16,
1197 pub column_gap: i16,
1198}
1199
1200#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1203#[repr(C)]
1204pub struct CompactNodePropsCold {
1205 pub border_top_color: u32,
1207 pub border_right_color: u32,
1208 pub border_bottom_color: u32,
1209 pub border_left_color: u32,
1210
1211 pub border_top_left_radius: i16,
1213 pub border_top_right_radius: i16,
1214 pub border_bottom_left_radius: i16,
1215 pub border_bottom_right_radius: i16,
1216
1217 pub z_index: i16, pub border_styles_packed: u16,
1221 pub border_spacing_h: i16,
1222 pub border_spacing_v: i16,
1223 pub tab_size: i16,
1224 pub grid_col_start: i16,
1226 pub grid_col_end: i16,
1228 pub grid_row_start: i16,
1230 pub grid_row_end: i16,
1232
1233 pub opacity: u8,
1236 pub hot_flags: u8,
1247 pub extra_flags: u8,
1261}
1262
1263pub const OPACITY_SENTINEL: u8 = 255;
1264pub const HOT_FLAG_HAS_TRANSFORM: u8 = 1 << 0;
1265pub const HOT_FLAG_HAS_TRANSFORM_ORIGIN: u8 = 1 << 1;
1266pub const HOT_FLAG_HAS_BOX_SHADOW: u8 = 1 << 2;
1267pub const HOT_FLAG_HAS_TEXT_DECORATION: u8 = 1 << 3;
1268pub const HOT_FLAG_SCROLLBAR_GUTTER_SHIFT: u8 = 4;
1269pub const HOT_FLAG_SCROLLBAR_GUTTER_MASK: u8 = 0b0011_0000;
1270pub const HOT_FLAG_HAS_BACKGROUND: u8 = 1 << 6;
1271pub const HOT_FLAG_HAS_CLIP_PATH: u8 = 1 << 7;
1272pub const EXTRA_FLAG_HAS_SCROLLBAR_CSS: u8 = 1 << 0;
1273pub const EXTRA_FLAG_HAS_COUNTER: u8 = 1 << 1;
1274pub const EXTRA_FLAG_HAS_BREAK: u8 = 1 << 2;
1275pub const EXTRA_FLAG_HAS_TEXT_ORIENTATION: u8 = 1 << 3;
1276pub const EXTRA_FLAG_HAS_TEXT_SHADOW: u8 = 1 << 4;
1277pub const EXTRA_FLAG_HAS_BACKDROP_FILTER: u8 = 1 << 5;
1278pub const EXTRA_FLAG_HAS_FILTER: u8 = 1 << 6;
1279pub const EXTRA_FLAG_HAS_MIX_BLEND_MODE: u8 = 1 << 7;
1280
1281pub const DOM_HAS_SHAPE_INSIDE: u32 = 1 << 0;
1288pub const DOM_HAS_SHAPE_OUTSIDE: u32 = 1 << 1;
1289pub const DOM_HAS_TEXT_JUSTIFY: u32 = 1 << 2;
1290pub const DOM_HAS_TEXT_INDENT: u32 = 1 << 3;
1291pub const DOM_HAS_COLUMN_COUNT: u32 = 1 << 4;
1292pub const DOM_HAS_COLUMN_GAP: u32 = 1 << 5;
1293pub const DOM_HAS_INITIAL_LETTER: u32 = 1 << 6;
1294pub const DOM_HAS_INITIAL_LETTER_ALIGN: u32 = 1 << 7;
1295pub const DOM_HAS_LINE_CLAMP: u32 = 1 << 8;
1296pub const DOM_HAS_HANGING_PUNCTUATION: u32 = 1 << 9;
1297pub const DOM_HAS_TEXT_COMBINE_UPRIGHT: u32 = 1 << 10;
1298pub const DOM_HAS_EXCLUSION_MARGIN: u32 = 1 << 11;
1299pub const DOM_HAS_HYPHENATION_LANGUAGE: u32 = 1 << 12;
1300pub const DOM_HAS_UNICODE_BIDI: u32 = 1 << 13;
1301pub const DOM_HAS_TEXT_BOX_TRIM: u32 = 1 << 14;
1302pub const DOM_HAS_HYPHENS: u32 = 1 << 15;
1303pub const DOM_HAS_WORD_BREAK: u32 = 1 << 16;
1304pub const DOM_HAS_OVERFLOW_WRAP: u32 = 1 << 17;
1305pub const DOM_HAS_LINE_BREAK: u32 = 1 << 18;
1306pub const DOM_HAS_TEXT_ALIGN_LAST: u32 = 1 << 19;
1307pub const DOM_HAS_LINE_HEIGHT: u32 = 1 << 20;
1308pub const DOM_HAS_COLUMN_WIDTH: u32 = 1 << 21;
1309pub const DOM_HAS_SHAPE_MARGIN: u32 = 1 << 22;
1310pub const SCROLLBAR_GUTTER_AUTO: u8 = 0;
1311pub const SCROLLBAR_GUTTER_STABLE: u8 = 1;
1312pub const SCROLLBAR_GUTTER_BOTH_EDGES: u8 = 2;
1313pub const SCROLLBAR_GUTTER_MIRROR: u8 = 3;
1314
1315impl Default for CompactNodeProps {
1316 fn default() -> Self {
1317 Self {
1318 width: U32_AUTO,
1320 height: U32_AUTO,
1321 min_width: U32_AUTO,
1322 max_width: U32_NONE,
1323 min_height: U32_AUTO,
1324 max_height: U32_NONE,
1325 flex_basis: U32_AUTO,
1326 font_size: U32_INITIAL,
1327 padding_top: 0,
1329 padding_right: 0,
1330 padding_bottom: 0,
1331 padding_left: 0,
1332 margin_top: 0,
1333 margin_right: 0,
1334 margin_bottom: 0,
1335 margin_left: 0,
1336 border_top_width: 0,
1337 border_right_width: 0,
1338 border_bottom_width: 0,
1339 border_left_width: 0,
1340 top: I16_AUTO,
1341 right: I16_AUTO,
1342 bottom: I16_AUTO,
1343 left: I16_AUTO,
1344 flex_grow: 0,
1346 flex_shrink: encode_flex_u16(1.0), row_gap: 0,
1350 column_gap: 0,
1351 }
1352 }
1353}
1354
1355impl Default for CompactNodePropsCold {
1356 fn default() -> Self {
1357 Self {
1358 border_top_color: 0,
1360 border_right_color: 0,
1361 border_bottom_color: 0,
1362 border_left_color: 0,
1363 border_top_left_radius: I16_SENTINEL,
1365 border_top_right_radius: I16_SENTINEL,
1366 border_bottom_left_radius: I16_SENTINEL,
1367 border_bottom_right_radius: I16_SENTINEL,
1368 z_index: I16_AUTO,
1370 border_styles_packed: 0, border_spacing_h: 0,
1372 border_spacing_v: 0,
1373 tab_size: I16_SENTINEL, grid_col_start: I16_AUTO,
1375 grid_col_end: I16_AUTO,
1376 grid_row_start: I16_AUTO,
1377 grid_row_end: I16_AUTO,
1378 opacity: OPACITY_SENTINEL,
1379 hot_flags: 0,
1380 extra_flags: 0,
1381 }
1382 }
1383}
1384
1385#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1391#[repr(C)]
1392pub struct CompactTextProps {
1393 pub text_color: u32, pub font_family_hash: u64, pub line_height: i16, pub letter_spacing: i16, pub word_spacing: i16, pub text_indent: i16, }
1400
1401impl Default for CompactTextProps {
1402 fn default() -> Self {
1403 Self {
1404 text_color: 0,
1405 font_family_hash: 0,
1406 line_height: I16_SENTINEL, letter_spacing: 0,
1408 word_spacing: 0,
1409 text_indent: 0,
1410 }
1411 }
1412}
1413
1414#[derive(Debug, Clone, PartialEq, Eq)]
1435pub struct CompactLayoutCache {
1436 pub tier1_enums: Vec<u64>,
1438 pub tier2_dims: Vec<CompactNodeProps>,
1440 pub tier2_cold: Vec<CompactNodePropsCold>,
1442 pub tier2b_text: Vec<CompactTextProps>,
1444 pub font_dirty_nodes: Vec<usize>,
1454 pub prev_font_hashes: Vec<u64>,
1460 pub font_hash_to_families: alloc::collections::BTreeMap<u64, crate::props::basic::font::StyleFontFamilyVec>,
1467 pub dom_declared_flags: u32,
1473}
1474
1475impl CompactLayoutCache {
1476 #[must_use] pub const fn empty() -> Self {
1478 Self {
1479 tier1_enums: Vec::new(),
1480 tier2_dims: Vec::new(),
1481 tier2_cold: Vec::new(),
1482 tier2b_text: Vec::new(),
1483 font_dirty_nodes: Vec::new(),
1484 prev_font_hashes: Vec::new(),
1485 font_hash_to_families: alloc::collections::BTreeMap::new(),
1486 dom_declared_flags: 0,
1487 }
1488 }
1489
1490 #[must_use] pub fn with_capacity(node_count: usize) -> Self {
1492 Self {
1493 tier1_enums: vec![0u64; node_count],
1494 tier2_dims: vec![CompactNodeProps::default(); node_count],
1495 tier2_cold: vec![CompactNodePropsCold::default(); node_count],
1496 tier2b_text: vec![CompactTextProps::default(); node_count],
1497 font_dirty_nodes: Vec::new(),
1498 prev_font_hashes: vec![0u64; node_count],
1499 font_hash_to_families: alloc::collections::BTreeMap::new(),
1500 dom_declared_flags: 0,
1501 }
1502 }
1503
1504 #[inline]
1506 #[must_use] pub const fn node_count(&self) -> usize {
1507 self.tier1_enums.len()
1508 }
1509
1510 #[inline]
1513 #[must_use] pub fn get_display(&self, node_idx: usize) -> LayoutDisplay {
1514 decode_display(self.tier1_enums[node_idx])
1515 }
1516
1517 #[inline]
1518 #[must_use] pub fn get_position(&self, node_idx: usize) -> LayoutPosition {
1519 decode_position(self.tier1_enums[node_idx])
1520 }
1521
1522 #[inline]
1523 #[must_use] pub fn get_float(&self, node_idx: usize) -> LayoutFloat {
1524 decode_float(self.tier1_enums[node_idx])
1525 }
1526
1527 #[inline]
1528 #[must_use] pub fn get_overflow_x(&self, node_idx: usize) -> LayoutOverflow {
1529 decode_overflow_x(self.tier1_enums[node_idx])
1530 }
1531
1532 #[inline]
1533 #[must_use] pub fn get_overflow_y(&self, node_idx: usize) -> LayoutOverflow {
1534 decode_overflow_y(self.tier1_enums[node_idx])
1535 }
1536
1537 #[inline]
1538 #[must_use] pub fn get_box_sizing(&self, node_idx: usize) -> LayoutBoxSizing {
1539 decode_box_sizing(self.tier1_enums[node_idx])
1540 }
1541
1542 #[inline]
1543 #[must_use] pub fn get_flex_direction(&self, node_idx: usize) -> LayoutFlexDirection {
1544 decode_flex_direction(self.tier1_enums[node_idx])
1545 }
1546
1547 #[inline]
1548 #[must_use] pub fn get_flex_wrap(&self, node_idx: usize) -> LayoutFlexWrap {
1549 decode_flex_wrap(self.tier1_enums[node_idx])
1550 }
1551
1552 #[inline]
1553 #[must_use] pub fn get_justify_content(&self, node_idx: usize) -> LayoutJustifyContent {
1554 decode_justify_content(self.tier1_enums[node_idx])
1555 }
1556
1557 #[inline]
1558 #[must_use] pub fn get_align_items(&self, node_idx: usize) -> LayoutAlignItems {
1559 decode_align_items(self.tier1_enums[node_idx])
1560 }
1561
1562 #[inline]
1563 #[must_use] pub fn get_align_content(&self, node_idx: usize) -> LayoutAlignContent {
1564 decode_align_content(self.tier1_enums[node_idx])
1565 }
1566
1567 #[inline]
1568 #[must_use] pub fn get_writing_mode(&self, node_idx: usize) -> LayoutWritingMode {
1569 decode_writing_mode(self.tier1_enums[node_idx])
1570 }
1571
1572 #[inline]
1573 #[must_use] pub fn get_clear(&self, node_idx: usize) -> LayoutClear {
1574 decode_clear(self.tier1_enums[node_idx])
1575 }
1576
1577 #[inline]
1578 #[must_use] pub fn get_font_weight(&self, node_idx: usize) -> StyleFontWeight {
1579 decode_font_weight(self.tier1_enums[node_idx])
1580 }
1581
1582 #[inline]
1583 #[must_use] pub fn get_font_style(&self, node_idx: usize) -> StyleFontStyle {
1584 decode_font_style(self.tier1_enums[node_idx])
1585 }
1586
1587 #[inline]
1588 #[must_use] pub fn get_text_align(&self, node_idx: usize) -> StyleTextAlign {
1589 decode_text_align(self.tier1_enums[node_idx])
1590 }
1591
1592 #[inline]
1593 #[must_use] pub fn get_visibility(&self, node_idx: usize) -> StyleVisibility {
1594 decode_visibility(self.tier1_enums[node_idx])
1595 }
1596
1597 #[inline]
1598 #[must_use] pub fn get_white_space(&self, node_idx: usize) -> StyleWhiteSpace {
1599 decode_white_space(self.tier1_enums[node_idx])
1600 }
1601
1602 #[inline]
1603 #[must_use] pub fn get_direction(&self, node_idx: usize) -> StyleDirection {
1604 decode_direction(self.tier1_enums[node_idx])
1605 }
1606
1607 #[inline]
1608 #[must_use] pub fn get_vertical_align(&self, node_idx: usize) -> StyleVerticalAlign {
1609 decode_vertical_align(self.tier1_enums[node_idx])
1610 }
1611
1612 #[inline]
1613 #[must_use] pub fn get_border_collapse(&self, node_idx: usize) -> StyleBorderCollapse {
1614 decode_border_collapse(self.tier1_enums[node_idx])
1615 }
1616
1617 #[inline]
1621 #[must_use] pub fn get_width_raw(&self, node_idx: usize) -> u32 {
1622 self.tier2_dims[node_idx].width
1623 }
1624
1625 #[inline]
1626 #[must_use] pub fn get_height_raw(&self, node_idx: usize) -> u32 {
1627 self.tier2_dims[node_idx].height
1628 }
1629
1630 #[inline]
1631 #[must_use] pub fn get_min_width_raw(&self, node_idx: usize) -> u32 {
1632 self.tier2_dims[node_idx].min_width
1633 }
1634
1635 #[inline]
1636 #[must_use] pub fn get_max_width_raw(&self, node_idx: usize) -> u32 {
1637 self.tier2_dims[node_idx].max_width
1638 }
1639
1640 #[inline]
1641 #[must_use] pub fn get_min_height_raw(&self, node_idx: usize) -> u32 {
1642 self.tier2_dims[node_idx].min_height
1643 }
1644
1645 #[inline]
1646 #[must_use] pub fn get_max_height_raw(&self, node_idx: usize) -> u32 {
1647 self.tier2_dims[node_idx].max_height
1648 }
1649
1650 #[inline]
1651 #[must_use] pub fn get_font_size_raw(&self, node_idx: usize) -> u32 {
1652 self.tier2_dims[node_idx].font_size
1653 }
1654
1655 #[inline]
1656 #[must_use] pub fn get_flex_basis_raw(&self, node_idx: usize) -> u32 {
1657 self.tier2_dims[node_idx].flex_basis
1658 }
1659
1660 #[inline]
1662 #[must_use] pub fn get_padding_top(&self, node_idx: usize) -> Option<f32> {
1663 decode_resolved_px_i16(self.tier2_dims[node_idx].padding_top)
1664 }
1665
1666 #[inline]
1667 #[must_use] pub fn get_padding_right(&self, node_idx: usize) -> Option<f32> {
1668 decode_resolved_px_i16(self.tier2_dims[node_idx].padding_right)
1669 }
1670
1671 #[inline]
1672 #[must_use] pub fn get_padding_bottom(&self, node_idx: usize) -> Option<f32> {
1673 decode_resolved_px_i16(self.tier2_dims[node_idx].padding_bottom)
1674 }
1675
1676 #[inline]
1677 #[must_use] pub fn get_padding_left(&self, node_idx: usize) -> Option<f32> {
1678 decode_resolved_px_i16(self.tier2_dims[node_idx].padding_left)
1679 }
1680
1681 #[inline]
1682 #[must_use] pub fn get_margin_top(&self, node_idx: usize) -> Option<f32> {
1683 let v = self.tier2_dims[node_idx].margin_top;
1684 if v == I16_AUTO { return None; } decode_resolved_px_i16(v)
1686 }
1687
1688 #[inline]
1689 #[must_use] pub fn get_margin_right(&self, node_idx: usize) -> Option<f32> {
1690 let v = self.tier2_dims[node_idx].margin_right;
1691 if v == I16_AUTO { return None; }
1692 decode_resolved_px_i16(v)
1693 }
1694
1695 #[inline]
1696 #[must_use] pub fn get_margin_bottom(&self, node_idx: usize) -> Option<f32> {
1697 let v = self.tier2_dims[node_idx].margin_bottom;
1698 if v == I16_AUTO { return None; }
1699 decode_resolved_px_i16(v)
1700 }
1701
1702 #[inline]
1703 #[must_use] pub fn get_margin_left(&self, node_idx: usize) -> Option<f32> {
1704 let v = self.tier2_dims[node_idx].margin_left;
1705 if v == I16_AUTO { return None; }
1706 decode_resolved_px_i16(v)
1707 }
1708
1709 #[inline]
1711 #[must_use] pub fn is_margin_top_auto(&self, node_idx: usize) -> bool {
1712 self.tier2_dims[node_idx].margin_top == I16_AUTO
1713 }
1714
1715 #[inline]
1716 #[must_use] pub fn is_margin_right_auto(&self, node_idx: usize) -> bool {
1717 self.tier2_dims[node_idx].margin_right == I16_AUTO
1718 }
1719
1720 #[inline]
1721 #[must_use] pub fn is_margin_bottom_auto(&self, node_idx: usize) -> bool {
1722 self.tier2_dims[node_idx].margin_bottom == I16_AUTO
1723 }
1724
1725 #[inline]
1726 #[must_use] pub fn is_margin_left_auto(&self, node_idx: usize) -> bool {
1727 self.tier2_dims[node_idx].margin_left == I16_AUTO
1728 }
1729
1730 #[inline]
1731 #[must_use] pub fn get_border_top_width(&self, node_idx: usize) -> Option<f32> {
1732 decode_resolved_px_i16(self.tier2_dims[node_idx].border_top_width)
1733 }
1734
1735 #[inline]
1736 #[must_use] pub fn get_border_right_width(&self, node_idx: usize) -> Option<f32> {
1737 decode_resolved_px_i16(self.tier2_dims[node_idx].border_right_width)
1738 }
1739
1740 #[inline]
1741 #[must_use] pub fn get_border_bottom_width(&self, node_idx: usize) -> Option<f32> {
1742 decode_resolved_px_i16(self.tier2_dims[node_idx].border_bottom_width)
1743 }
1744
1745 #[inline]
1746 #[must_use] pub fn get_border_left_width(&self, node_idx: usize) -> Option<f32> {
1747 decode_resolved_px_i16(self.tier2_dims[node_idx].border_left_width)
1748 }
1749
1750 #[inline]
1753 #[must_use] pub fn get_padding_top_raw(&self, node_idx: usize) -> i16 {
1754 self.tier2_dims[node_idx].padding_top
1755 }
1756
1757 #[inline]
1758 #[must_use] pub fn get_padding_right_raw(&self, node_idx: usize) -> i16 {
1759 self.tier2_dims[node_idx].padding_right
1760 }
1761
1762 #[inline]
1763 #[must_use] pub fn get_padding_bottom_raw(&self, node_idx: usize) -> i16 {
1764 self.tier2_dims[node_idx].padding_bottom
1765 }
1766
1767 #[inline]
1768 #[must_use] pub fn get_padding_left_raw(&self, node_idx: usize) -> i16 {
1769 self.tier2_dims[node_idx].padding_left
1770 }
1771
1772 #[inline]
1773 #[must_use] pub fn get_margin_top_raw(&self, node_idx: usize) -> i16 {
1774 self.tier2_dims[node_idx].margin_top
1775 }
1776
1777 #[inline]
1778 #[must_use] pub fn get_margin_right_raw(&self, node_idx: usize) -> i16 {
1779 self.tier2_dims[node_idx].margin_right
1780 }
1781
1782 #[inline]
1783 #[must_use] pub fn get_margin_bottom_raw(&self, node_idx: usize) -> i16 {
1784 self.tier2_dims[node_idx].margin_bottom
1785 }
1786
1787 #[inline]
1788 #[must_use] pub fn get_margin_left_raw(&self, node_idx: usize) -> i16 {
1789 self.tier2_dims[node_idx].margin_left
1790 }
1791
1792 #[inline]
1793 #[must_use] pub fn get_border_top_width_raw(&self, node_idx: usize) -> i16 {
1794 self.tier2_dims[node_idx].border_top_width
1795 }
1796
1797 #[inline]
1798 #[must_use] pub fn get_border_right_width_raw(&self, node_idx: usize) -> i16 {
1799 self.tier2_dims[node_idx].border_right_width
1800 }
1801
1802 #[inline]
1803 #[must_use] pub fn get_border_bottom_width_raw(&self, node_idx: usize) -> i16 {
1804 self.tier2_dims[node_idx].border_bottom_width
1805 }
1806
1807 #[inline]
1808 #[must_use] pub fn get_border_left_width_raw(&self, node_idx: usize) -> i16 {
1809 self.tier2_dims[node_idx].border_left_width
1810 }
1811
1812 #[inline]
1813 #[must_use] pub fn get_top(&self, node_idx: usize) -> i16 {
1814 self.tier2_dims[node_idx].top
1815 }
1816
1817 #[inline]
1818 #[must_use] pub fn get_right(&self, node_idx: usize) -> i16 {
1819 self.tier2_dims[node_idx].right
1820 }
1821
1822 #[inline]
1823 #[must_use] pub fn get_bottom(&self, node_idx: usize) -> i16 {
1824 self.tier2_dims[node_idx].bottom
1825 }
1826
1827 #[inline]
1828 #[must_use] pub fn get_left(&self, node_idx: usize) -> i16 {
1829 self.tier2_dims[node_idx].left
1830 }
1831
1832 #[inline]
1833 #[must_use] pub fn get_flex_grow(&self, node_idx: usize) -> Option<f32> {
1834 decode_flex_u16(self.tier2_dims[node_idx].flex_grow)
1835 }
1836
1837 #[inline]
1838 #[must_use] pub fn get_flex_shrink(&self, node_idx: usize) -> Option<f32> {
1839 decode_flex_u16(self.tier2_dims[node_idx].flex_shrink)
1840 }
1841
1842 #[inline]
1843 #[must_use] pub fn get_z_index(&self, node_idx: usize) -> i16 {
1844 self.tier2_cold[node_idx].z_index
1845 }
1846
1847 #[inline]
1850 #[must_use] pub fn get_border_top_color_raw(&self, node_idx: usize) -> u32 {
1851 self.tier2_cold[node_idx].border_top_color
1852 }
1853
1854 #[inline]
1855 #[must_use] pub fn get_border_right_color_raw(&self, node_idx: usize) -> u32 {
1856 self.tier2_cold[node_idx].border_right_color
1857 }
1858
1859 #[inline]
1860 #[must_use] pub fn get_border_bottom_color_raw(&self, node_idx: usize) -> u32 {
1861 self.tier2_cold[node_idx].border_bottom_color
1862 }
1863
1864 #[inline]
1865 #[must_use] pub fn get_border_left_color_raw(&self, node_idx: usize) -> u32 {
1866 self.tier2_cold[node_idx].border_left_color
1867 }
1868
1869 #[inline]
1872 #[must_use] pub fn get_border_styles_packed(&self, node_idx: usize) -> u16 {
1873 self.tier2_cold[node_idx].border_styles_packed
1874 }
1875
1876 #[inline]
1877 #[must_use] pub fn get_border_top_style(&self, node_idx: usize) -> BorderStyle {
1878 decode_border_top_style(self.tier2_cold[node_idx].border_styles_packed)
1879 }
1880
1881 #[inline]
1882 #[must_use] pub fn get_border_right_style(&self, node_idx: usize) -> BorderStyle {
1883 decode_border_right_style(self.tier2_cold[node_idx].border_styles_packed)
1884 }
1885
1886 #[inline]
1887 #[must_use] pub fn get_border_bottom_style(&self, node_idx: usize) -> BorderStyle {
1888 decode_border_bottom_style(self.tier2_cold[node_idx].border_styles_packed)
1889 }
1890
1891 #[inline]
1892 #[must_use] pub fn get_border_left_style(&self, node_idx: usize) -> BorderStyle {
1893 decode_border_left_style(self.tier2_cold[node_idx].border_styles_packed)
1894 }
1895
1896 #[inline]
1899 #[must_use] pub fn get_border_spacing_h_raw(&self, node_idx: usize) -> i16 {
1900 self.tier2_cold[node_idx].border_spacing_h
1901 }
1902
1903 #[inline]
1904 #[must_use] pub fn get_border_spacing_v_raw(&self, node_idx: usize) -> i16 {
1905 self.tier2_cold[node_idx].border_spacing_v
1906 }
1907
1908 #[inline]
1911 #[must_use] pub fn get_tab_size_raw(&self, node_idx: usize) -> i16 {
1912 self.tier2_cold[node_idx].tab_size
1913 }
1914
1915 #[inline]
1918 #[must_use] pub fn get_border_top_left_radius_raw(&self, node_idx: usize) -> i16 {
1919 self.tier2_cold[node_idx].border_top_left_radius
1920 }
1921
1922 #[inline]
1923 #[must_use] pub fn get_border_top_right_radius_raw(&self, node_idx: usize) -> i16 {
1924 self.tier2_cold[node_idx].border_top_right_radius
1925 }
1926
1927 #[inline]
1928 #[must_use] pub fn get_border_bottom_left_radius_raw(&self, node_idx: usize) -> i16 {
1929 self.tier2_cold[node_idx].border_bottom_left_radius
1930 }
1931
1932 #[inline]
1933 #[must_use] pub fn get_border_bottom_right_radius_raw(&self, node_idx: usize) -> i16 {
1934 self.tier2_cold[node_idx].border_bottom_right_radius
1935 }
1936
1937 #[inline]
1942 #[must_use] pub fn get_opacity_raw(&self, node_idx: usize) -> u8 {
1943 self.tier2_cold[node_idx].opacity
1944 }
1945
1946 #[inline]
1947 #[must_use] pub fn get_hot_flags(&self, node_idx: usize) -> u8 {
1948 self.tier2_cold[node_idx].hot_flags
1949 }
1950
1951 #[inline]
1952 #[must_use] pub fn has_transform(&self, node_idx: usize) -> bool {
1953 self.tier2_cold[node_idx].hot_flags & HOT_FLAG_HAS_TRANSFORM != 0
1954 }
1955
1956 #[inline]
1957 #[must_use] pub fn has_transform_origin(&self, node_idx: usize) -> bool {
1958 self.tier2_cold[node_idx].hot_flags & HOT_FLAG_HAS_TRANSFORM_ORIGIN != 0
1959 }
1960
1961 #[inline]
1962 #[must_use] pub fn has_box_shadow(&self, node_idx: usize) -> bool {
1963 self.tier2_cold[node_idx].hot_flags & HOT_FLAG_HAS_BOX_SHADOW != 0
1964 }
1965
1966 #[inline]
1967 #[must_use] pub fn has_text_decoration(&self, node_idx: usize) -> bool {
1968 self.tier2_cold[node_idx].hot_flags & HOT_FLAG_HAS_TEXT_DECORATION != 0
1969 }
1970
1971 #[inline]
1972 #[must_use] pub fn has_background(&self, node_idx: usize) -> bool {
1973 self.tier2_cold[node_idx].hot_flags & HOT_FLAG_HAS_BACKGROUND != 0
1974 }
1975
1976 #[inline]
1977 #[must_use] pub fn has_clip_path(&self, node_idx: usize) -> bool {
1978 self.tier2_cold[node_idx].hot_flags & HOT_FLAG_HAS_CLIP_PATH != 0
1979 }
1980
1981 #[inline]
1982 #[must_use] pub fn has_scrollbar_css(&self, node_idx: usize) -> bool {
1983 self.tier2_cold[node_idx].extra_flags & EXTRA_FLAG_HAS_SCROLLBAR_CSS != 0
1984 }
1985
1986 #[inline]
1987 #[must_use] pub fn has_counter(&self, node_idx: usize) -> bool {
1988 self.tier2_cold[node_idx].extra_flags & EXTRA_FLAG_HAS_COUNTER != 0
1989 }
1990
1991 #[inline]
1992 #[must_use] pub fn has_break(&self, node_idx: usize) -> bool {
1993 self.tier2_cold[node_idx].extra_flags & EXTRA_FLAG_HAS_BREAK != 0
1994 }
1995
1996 #[inline]
1997 #[must_use] pub fn has_text_orientation(&self, node_idx: usize) -> bool {
1998 self.tier2_cold[node_idx].extra_flags & EXTRA_FLAG_HAS_TEXT_ORIENTATION != 0
1999 }
2000
2001 #[inline]
2002 #[must_use] pub fn has_text_shadow(&self, node_idx: usize) -> bool {
2003 self.tier2_cold[node_idx].extra_flags & EXTRA_FLAG_HAS_TEXT_SHADOW != 0
2004 }
2005
2006 #[inline]
2007 #[must_use] pub fn has_backdrop_filter(&self, node_idx: usize) -> bool {
2008 self.tier2_cold[node_idx].extra_flags & EXTRA_FLAG_HAS_BACKDROP_FILTER != 0
2009 }
2010
2011 #[inline]
2012 #[must_use] pub fn has_filter(&self, node_idx: usize) -> bool {
2013 self.tier2_cold[node_idx].extra_flags & EXTRA_FLAG_HAS_FILTER != 0
2014 }
2015
2016 #[inline]
2017 #[must_use] pub fn has_mix_blend_mode(&self, node_idx: usize) -> bool {
2018 self.tier2_cold[node_idx].extra_flags & EXTRA_FLAG_HAS_MIX_BLEND_MODE != 0
2019 }
2020
2021 #[inline]
2024 #[must_use] pub const fn dom_declared(&self, flag: u32) -> bool {
2025 self.dom_declared_flags & flag != 0
2026 }
2027
2028 #[inline]
2030 #[must_use] pub fn get_scrollbar_gutter_bits(&self, node_idx: usize) -> u8 {
2031 (self.tier2_cold[node_idx].hot_flags & HOT_FLAG_SCROLLBAR_GUTTER_MASK)
2032 >> HOT_FLAG_SCROLLBAR_GUTTER_SHIFT
2033 }
2034
2035 #[inline]
2038 #[must_use] pub fn get_text_color_raw(&self, node_idx: usize) -> u32 {
2039 self.tier2b_text[node_idx].text_color
2040 }
2041
2042 #[inline]
2043 #[must_use] pub fn get_font_family_hash(&self, node_idx: usize) -> u64 {
2044 self.tier2b_text[node_idx].font_family_hash
2045 }
2046
2047 #[inline]
2048 #[must_use] pub fn get_line_height(&self, node_idx: usize) -> Option<f32> {
2049 decode_resolved_px_i16(self.tier2b_text[node_idx].line_height)
2050 }
2051
2052 #[inline]
2053 #[must_use] pub fn get_letter_spacing(&self, node_idx: usize) -> Option<f32> {
2054 decode_resolved_px_i16(self.tier2b_text[node_idx].letter_spacing)
2055 }
2056
2057 #[inline]
2058 #[must_use] pub fn get_word_spacing(&self, node_idx: usize) -> Option<f32> {
2059 decode_resolved_px_i16(self.tier2b_text[node_idx].word_spacing)
2060 }
2061
2062 #[inline]
2063 #[must_use] pub fn get_text_indent(&self, node_idx: usize) -> Option<f32> {
2064 decode_resolved_px_i16(self.tier2b_text[node_idx].text_indent)
2065 }
2066
2067}
2068
2069#[inline]
2079#[must_use] pub fn encode_css_pixel_as_i16(prop: &CssPropertyValue<PixelValue>) -> i16 {
2080 match prop {
2081 CssPropertyValue::Exact(pv) => {
2082 if pv.metric == SizeMetric::Px {
2083 encode_resolved_px_i16(pv.number.get())
2084 } else {
2085 I16_SENTINEL }
2087 }
2088 CssPropertyValue::Auto => I16_AUTO,
2089 CssPropertyValue::Initial => I16_INITIAL,
2090 CssPropertyValue::Inherit => I16_INHERIT,
2091 _ => I16_SENTINEL,
2092 }
2093}
2094
2095#[cfg(test)]
2096mod tests {
2097 use super::*;
2098
2099 #[test]
2100 fn test_tier1_roundtrip() {
2101 let t1 = encode_tier1(
2102 LayoutDisplay::Flex,
2103 LayoutPosition::Relative,
2104 LayoutFloat::Left,
2105 LayoutOverflow::Hidden,
2106 LayoutOverflow::Scroll,
2107 LayoutBoxSizing::BorderBox,
2108 LayoutFlexDirection::Column,
2109 LayoutFlexWrap::Wrap,
2110 LayoutJustifyContent::SpaceBetween,
2111 LayoutAlignItems::Center,
2112 LayoutAlignContent::End,
2113 LayoutWritingMode::VerticalRl,
2114 LayoutClear::Both,
2115 StyleFontWeight::Bold,
2116 StyleFontStyle::Italic,
2117 StyleTextAlign::Center,
2118 StyleVisibility::Hidden,
2119 StyleWhiteSpace::Pre,
2120 StyleDirection::Rtl,
2121 StyleVerticalAlign::Middle,
2122 StyleBorderCollapse::Collapse,
2123 );
2124
2125 assert!(tier1_is_populated(t1));
2126 assert_eq!(decode_display(t1), LayoutDisplay::Flex);
2127 assert_eq!(decode_position(t1), LayoutPosition::Relative);
2128 assert_eq!(decode_float(t1), LayoutFloat::Left);
2129 assert_eq!(decode_overflow_x(t1), LayoutOverflow::Hidden);
2130 assert_eq!(decode_overflow_y(t1), LayoutOverflow::Scroll);
2131 assert_eq!(decode_box_sizing(t1), LayoutBoxSizing::BorderBox);
2132 assert_eq!(decode_flex_direction(t1), LayoutFlexDirection::Column);
2133 assert_eq!(decode_flex_wrap(t1), LayoutFlexWrap::Wrap);
2134 assert_eq!(decode_justify_content(t1), LayoutJustifyContent::SpaceBetween);
2135 assert_eq!(decode_align_items(t1), LayoutAlignItems::Center);
2136 assert_eq!(decode_align_content(t1), LayoutAlignContent::End);
2137 assert_eq!(decode_writing_mode(t1), LayoutWritingMode::VerticalRl);
2138 assert_eq!(decode_clear(t1), LayoutClear::Both);
2139 assert_eq!(decode_font_weight(t1), StyleFontWeight::Bold);
2140 assert_eq!(decode_font_style(t1), StyleFontStyle::Italic);
2141 assert_eq!(decode_text_align(t1), StyleTextAlign::Center);
2142 assert_eq!(decode_visibility(t1), StyleVisibility::Hidden);
2143 assert_eq!(decode_white_space(t1), StyleWhiteSpace::Pre);
2144 assert_eq!(decode_direction(t1), StyleDirection::Rtl);
2145 assert_eq!(decode_vertical_align(t1), StyleVerticalAlign::Middle);
2146 assert_eq!(decode_border_collapse(t1), StyleBorderCollapse::Collapse);
2147 }
2148
2149 #[test]
2150 fn test_tier1_defaults() {
2151 let t1 = encode_tier1(
2152 LayoutDisplay::Block,
2153 LayoutPosition::Static,
2154 LayoutFloat::None,
2155 LayoutOverflow::Visible,
2156 LayoutOverflow::Visible,
2157 LayoutBoxSizing::ContentBox,
2158 LayoutFlexDirection::Row,
2159 LayoutFlexWrap::NoWrap,
2160 LayoutJustifyContent::FlexStart,
2161 LayoutAlignItems::Stretch,
2162 LayoutAlignContent::Stretch,
2163 LayoutWritingMode::HorizontalTb,
2164 LayoutClear::None,
2165 StyleFontWeight::Normal,
2166 StyleFontStyle::Normal,
2167 StyleTextAlign::Left,
2168 StyleVisibility::Visible,
2169 StyleWhiteSpace::Normal,
2170 StyleDirection::Ltr,
2171 StyleVerticalAlign::Baseline,
2172 StyleBorderCollapse::Separate,
2173 );
2174
2175 assert!(tier1_is_populated(t1));
2176 assert_eq!(decode_display(t1), LayoutDisplay::Block);
2177 assert_eq!(decode_position(t1), LayoutPosition::Static);
2178 }
2179
2180 #[test]
2181 fn test_pixel_value_u32_roundtrip() {
2182 let pv = PixelValue::px(123.456);
2183 let encoded = encode_pixel_value_u32(&pv);
2184 assert!(encoded < U32_SENTINEL_THRESHOLD);
2185 let decoded = decode_pixel_value_u32(encoded).unwrap();
2186 assert_eq!(decoded.metric, SizeMetric::Px);
2187 assert!((decoded.number.get() - 123.456).abs() < 0.002);
2189 }
2190
2191 #[test]
2192 fn test_pixel_value_u32_percent() {
2193 let pv = PixelValue {
2194 metric: SizeMetric::Percent,
2195 number: FloatValue::new(50.0),
2196 };
2197 let encoded = encode_pixel_value_u32(&pv);
2198 let decoded = decode_pixel_value_u32(encoded).unwrap();
2199 assert_eq!(decoded.metric, SizeMetric::Percent);
2200 assert!((decoded.number.get() - 50.0).abs() < 0.002);
2201 }
2202
2203 #[test]
2204 fn test_sentinel_values() {
2205 assert_eq!(decode_pixel_value_u32(U32_SENTINEL), None);
2206 assert_eq!(decode_pixel_value_u32(U32_AUTO), None);
2207 assert_eq!(decode_pixel_value_u32(U32_MIN_CONTENT), None);
2208 assert_eq!(decode_resolved_px_i16(I16_SENTINEL), None);
2209 assert_eq!(decode_resolved_px_i16(I16_AUTO), None);
2210 }
2211
2212 #[test]
2213 fn test_resolved_px_i16_roundtrip() {
2214 let px = 123.4f32;
2215 let encoded = encode_resolved_px_i16(px);
2216 let decoded = decode_resolved_px_i16(encoded).unwrap();
2217 assert!((decoded - 123.4).abs() < 0.11);
2218
2219 let px = -50.7f32;
2221 let encoded = encode_resolved_px_i16(px);
2222 let decoded = decode_resolved_px_i16(encoded).unwrap();
2223 assert!((decoded - (-50.7)).abs() < 0.11);
2224 }
2225
2226 #[test]
2227 fn test_flex_u16_roundtrip() {
2228 let v = 2.5f32;
2229 let encoded = encode_flex_u16(v);
2230 let decoded = decode_flex_u16(encoded).unwrap();
2231 assert!((decoded - 2.5).abs() < 0.011);
2232 }
2233
2234 #[test]
2235 fn test_compact_node_props_size() {
2236 assert_eq!(size_of::<CompactNodeProps>(), 72);
2239 }
2240
2241 #[test]
2242 fn test_compact_node_props_cold_size() {
2243 assert_eq!(size_of::<CompactNodePropsCold>(), 48);
2248 }
2249
2250 #[test]
2251 fn test_compact_text_props_size() {
2252 assert_eq!(size_of::<CompactTextProps>(), 24);
2253 }
2254
2255 #[test]
2272 fn test_justify_items_zero_is_stretch() {
2273 assert_eq!(layout_justify_items_from_u8(0), LayoutJustifyItems::Stretch);
2277 assert_eq!(layout_justify_items_to_u8(LayoutJustifyItems::Stretch), 0);
2278 }
2279
2280 #[test]
2281 fn test_tier1_enum_zero_sentinel_is_css_initial() {
2282 assert_eq!(layout_display_from_u8(0), LayoutDisplay::Block);
2283 assert_eq!(layout_position_from_u8(0), LayoutPosition::Static);
2284 assert_eq!(layout_float_from_u8(0), LayoutFloat::None);
2285 assert_eq!(layout_overflow_from_u8(0), LayoutOverflow::Visible);
2286 assert_eq!(layout_box_sizing_from_u8(0), LayoutBoxSizing::ContentBox);
2287 assert_eq!(layout_flex_direction_from_u8(0), LayoutFlexDirection::Row);
2288 assert_eq!(layout_flex_wrap_from_u8(0), LayoutFlexWrap::NoWrap);
2289 assert_eq!(layout_justify_content_from_u8(0), LayoutJustifyContent::FlexStart);
2290 assert_eq!(layout_align_items_from_u8(0), LayoutAlignItems::Stretch);
2291 assert_eq!(layout_align_content_from_u8(0), LayoutAlignContent::Stretch);
2292 assert_eq!(layout_align_self_from_u8(0), LayoutAlignSelf::Auto);
2293 assert_eq!(layout_justify_self_from_u8(0), LayoutJustifySelf::Auto);
2294 assert_eq!(layout_justify_items_from_u8(0), LayoutJustifyItems::Stretch);
2295 assert_eq!(layout_grid_auto_flow_from_u8(0), LayoutGridAutoFlow::Row);
2296 assert_eq!(layout_writing_mode_from_u8(0), LayoutWritingMode::HorizontalTb);
2297 assert_eq!(layout_clear_from_u8(0), LayoutClear::None);
2298 assert_eq!(style_font_weight_from_u8(0), StyleFontWeight::Normal);
2299 assert_eq!(style_font_style_from_u8(0), StyleFontStyle::Normal);
2300 assert_eq!(style_text_align_from_u8(0), StyleTextAlign::Start);
2303 assert_eq!(style_visibility_from_u8(0), StyleVisibility::Visible);
2304 assert_eq!(style_white_space_from_u8(0), StyleWhiteSpace::Normal);
2305 assert_eq!(style_direction_from_u8(0), StyleDirection::Ltr);
2306 assert_eq!(style_vertical_align_from_u8(0), StyleVerticalAlign::Baseline);
2307 assert_eq!(border_collapse_from_u8(0), StyleBorderCollapse::Separate);
2308 }
2309
2310 #[test]
2311 fn test_tier1_enum_initial_encodes_to_zero() {
2312 assert_eq!(layout_display_to_u8(LayoutDisplay::Block), 0);
2317 assert_eq!(layout_position_to_u8(LayoutPosition::Static), 0);
2318 assert_eq!(layout_float_to_u8(LayoutFloat::None), 0);
2319 assert_eq!(layout_overflow_to_u8(LayoutOverflow::Visible), 0);
2320 assert_eq!(layout_box_sizing_to_u8(LayoutBoxSizing::ContentBox), 0);
2321 assert_eq!(layout_flex_direction_to_u8(LayoutFlexDirection::Row), 0);
2322 assert_eq!(layout_flex_wrap_to_u8(LayoutFlexWrap::NoWrap), 0);
2323 assert_eq!(layout_justify_content_to_u8(LayoutJustifyContent::FlexStart), 0);
2324 assert_eq!(layout_align_items_to_u8(LayoutAlignItems::Stretch), 0);
2325 assert_eq!(layout_align_content_to_u8(LayoutAlignContent::Stretch), 0);
2326 assert_eq!(layout_align_self_to_u8(LayoutAlignSelf::Auto), 0);
2327 assert_eq!(layout_justify_self_to_u8(LayoutJustifySelf::Auto), 0);
2328 assert_eq!(layout_justify_items_to_u8(LayoutJustifyItems::Stretch), 0);
2329 assert_eq!(layout_grid_auto_flow_to_u8(LayoutGridAutoFlow::Row), 0);
2330 assert_eq!(layout_writing_mode_to_u8(LayoutWritingMode::HorizontalTb), 0);
2331 assert_eq!(layout_clear_to_u8(LayoutClear::None), 0);
2332 assert_eq!(style_font_weight_to_u8(StyleFontWeight::Normal), 0);
2333 assert_eq!(style_font_style_to_u8(StyleFontStyle::Normal), 0);
2334 assert_eq!(style_text_align_to_u8(StyleTextAlign::Left), 4);
2335 assert_eq!(style_visibility_to_u8(StyleVisibility::Visible), 0);
2336 assert_eq!(style_white_space_to_u8(StyleWhiteSpace::Normal), 0);
2337 assert_eq!(style_direction_to_u8(StyleDirection::Ltr), 0);
2338 assert_eq!(style_vertical_align_to_u8(StyleVerticalAlign::Baseline), 0);
2339 assert_eq!(border_collapse_to_u8(StyleBorderCollapse::Separate), 0);
2340 }
2341
2342 macro_rules! roundtrip_all {
2349 ($name:ident, $to:ident, $from:ident, [$($variant:expr),+ $(,)?]) => {
2350 #[test]
2351 fn $name() {
2352 for v in [$($variant),+] {
2353 let u = $to(v);
2354 let decoded = $from(u);
2355 assert_eq!(decoded, v, "{:?} != {:?} (via u8 = {})", decoded, v, u);
2356 }
2357 }
2358 };
2359 }
2360
2361 roundtrip_all!(rt_display, layout_display_to_u8, layout_display_from_u8, [
2362 LayoutDisplay::Block, LayoutDisplay::Inline, LayoutDisplay::InlineBlock,
2363 LayoutDisplay::Flex, LayoutDisplay::None, LayoutDisplay::InlineFlex,
2364 LayoutDisplay::Table, LayoutDisplay::InlineTable, LayoutDisplay::TableRowGroup,
2365 LayoutDisplay::TableHeaderGroup, LayoutDisplay::TableFooterGroup,
2366 LayoutDisplay::TableRow, LayoutDisplay::TableColumnGroup,
2367 LayoutDisplay::TableColumn, LayoutDisplay::TableCell,
2368 LayoutDisplay::TableCaption, LayoutDisplay::FlowRoot,
2369 LayoutDisplay::ListItem, LayoutDisplay::RunIn, LayoutDisplay::Marker,
2370 LayoutDisplay::Grid, LayoutDisplay::InlineGrid, LayoutDisplay::Contents,
2371 ]);
2372
2373 roundtrip_all!(rt_position, layout_position_to_u8, layout_position_from_u8, [
2374 LayoutPosition::Static, LayoutPosition::Relative, LayoutPosition::Absolute,
2375 LayoutPosition::Fixed, LayoutPosition::Sticky,
2376 ]);
2377
2378 roundtrip_all!(rt_float, layout_float_to_u8, layout_float_from_u8, [
2379 LayoutFloat::None, LayoutFloat::Left, LayoutFloat::Right,
2380 ]);
2381
2382 roundtrip_all!(rt_overflow, layout_overflow_to_u8, layout_overflow_from_u8, [
2383 LayoutOverflow::Visible, LayoutOverflow::Hidden, LayoutOverflow::Scroll,
2384 LayoutOverflow::Auto, LayoutOverflow::Clip,
2385 ]);
2386
2387 roundtrip_all!(rt_box_sizing, layout_box_sizing_to_u8, layout_box_sizing_from_u8, [
2388 LayoutBoxSizing::ContentBox, LayoutBoxSizing::BorderBox,
2389 ]);
2390
2391 roundtrip_all!(rt_flex_direction, layout_flex_direction_to_u8, layout_flex_direction_from_u8, [
2392 LayoutFlexDirection::Row, LayoutFlexDirection::RowReverse,
2393 LayoutFlexDirection::Column, LayoutFlexDirection::ColumnReverse,
2394 ]);
2395
2396 roundtrip_all!(rt_flex_wrap, layout_flex_wrap_to_u8, layout_flex_wrap_from_u8, [
2397 LayoutFlexWrap::NoWrap, LayoutFlexWrap::Wrap, LayoutFlexWrap::WrapReverse,
2398 ]);
2399
2400 roundtrip_all!(rt_justify_content, layout_justify_content_to_u8, layout_justify_content_from_u8, [
2401 LayoutJustifyContent::FlexStart, LayoutJustifyContent::FlexEnd,
2402 LayoutJustifyContent::Start, LayoutJustifyContent::End,
2403 LayoutJustifyContent::Center, LayoutJustifyContent::SpaceBetween,
2404 LayoutJustifyContent::SpaceAround, LayoutJustifyContent::SpaceEvenly,
2405 ]);
2406
2407 roundtrip_all!(rt_align_items, layout_align_items_to_u8, layout_align_items_from_u8, [
2408 LayoutAlignItems::Stretch, LayoutAlignItems::Center, LayoutAlignItems::Start,
2409 LayoutAlignItems::End, LayoutAlignItems::Baseline,
2410 ]);
2411
2412 roundtrip_all!(rt_align_self, layout_align_self_to_u8, layout_align_self_from_u8, [
2413 LayoutAlignSelf::Auto, LayoutAlignSelf::Stretch, LayoutAlignSelf::Center,
2414 LayoutAlignSelf::Start, LayoutAlignSelf::End, LayoutAlignSelf::Baseline,
2415 ]);
2416
2417 roundtrip_all!(rt_justify_self, layout_justify_self_to_u8, layout_justify_self_from_u8, [
2418 LayoutJustifySelf::Auto, LayoutJustifySelf::Start, LayoutJustifySelf::End,
2419 LayoutJustifySelf::Center, LayoutJustifySelf::Stretch,
2420 ]);
2421
2422 roundtrip_all!(rt_justify_items, layout_justify_items_to_u8, layout_justify_items_from_u8, [
2423 LayoutJustifyItems::Stretch, LayoutJustifyItems::Start,
2424 LayoutJustifyItems::End, LayoutJustifyItems::Center,
2425 ]);
2426
2427 roundtrip_all!(rt_grid_auto_flow, layout_grid_auto_flow_to_u8, layout_grid_auto_flow_from_u8, [
2428 LayoutGridAutoFlow::Row, LayoutGridAutoFlow::Column,
2429 LayoutGridAutoFlow::RowDense, LayoutGridAutoFlow::ColumnDense,
2430 ]);
2431
2432 roundtrip_all!(rt_align_content, layout_align_content_to_u8, layout_align_content_from_u8, [
2433 LayoutAlignContent::Stretch, LayoutAlignContent::Center,
2434 LayoutAlignContent::Start, LayoutAlignContent::End,
2435 LayoutAlignContent::SpaceBetween, LayoutAlignContent::SpaceAround,
2436 ]);
2437
2438 roundtrip_all!(rt_writing_mode, layout_writing_mode_to_u8, layout_writing_mode_from_u8, [
2439 LayoutWritingMode::HorizontalTb, LayoutWritingMode::VerticalRl,
2440 LayoutWritingMode::VerticalLr,
2441 ]);
2442
2443 roundtrip_all!(rt_clear, layout_clear_to_u8, layout_clear_from_u8, [
2444 LayoutClear::None, LayoutClear::Left, LayoutClear::Right, LayoutClear::Both,
2445 ]);
2446
2447 roundtrip_all!(rt_font_weight, style_font_weight_to_u8, style_font_weight_from_u8, [
2448 StyleFontWeight::Normal, StyleFontWeight::W100, StyleFontWeight::W200,
2449 StyleFontWeight::W300, StyleFontWeight::W500, StyleFontWeight::W600,
2450 StyleFontWeight::Bold, StyleFontWeight::W800, StyleFontWeight::W900,
2451 StyleFontWeight::Lighter, StyleFontWeight::Bolder,
2452 ]);
2453
2454 roundtrip_all!(rt_font_style, style_font_style_to_u8, style_font_style_from_u8, [
2455 StyleFontStyle::Normal, StyleFontStyle::Italic, StyleFontStyle::Oblique,
2456 ]);
2457
2458 roundtrip_all!(rt_text_align, style_text_align_to_u8, style_text_align_from_u8, [
2459 StyleTextAlign::Left, StyleTextAlign::Center, StyleTextAlign::Right,
2460 StyleTextAlign::Justify, StyleTextAlign::Start, StyleTextAlign::End,
2461 ]);
2462
2463 roundtrip_all!(rt_visibility, style_visibility_to_u8, style_visibility_from_u8, [
2464 StyleVisibility::Visible, StyleVisibility::Hidden, StyleVisibility::Collapse,
2465 ]);
2466
2467 roundtrip_all!(rt_white_space, style_white_space_to_u8, style_white_space_from_u8, [
2468 StyleWhiteSpace::Normal, StyleWhiteSpace::Pre, StyleWhiteSpace::Nowrap,
2469 StyleWhiteSpace::PreWrap, StyleWhiteSpace::PreLine, StyleWhiteSpace::BreakSpaces,
2470 ]);
2471
2472 roundtrip_all!(rt_direction, style_direction_to_u8, style_direction_from_u8, [
2473 StyleDirection::Ltr, StyleDirection::Rtl,
2474 ]);
2475
2476 roundtrip_all!(rt_vertical_align, style_vertical_align_to_u8, style_vertical_align_from_u8, [
2477 StyleVerticalAlign::Baseline, StyleVerticalAlign::Top, StyleVerticalAlign::Middle,
2478 StyleVerticalAlign::Bottom, StyleVerticalAlign::Sub, StyleVerticalAlign::Superscript,
2479 StyleVerticalAlign::TextTop, StyleVerticalAlign::TextBottom,
2480 ]);
2481
2482 roundtrip_all!(rt_border_collapse, border_collapse_to_u8, border_collapse_from_u8, [
2483 StyleBorderCollapse::Separate, StyleBorderCollapse::Collapse,
2484 ]);
2485
2486 #[test]
2495 fn test_encoded_u8_fits_in_tier1_mask() {
2496 fn assert_fits(name: &str, val: u8, mask: u64) {
2497 assert!(
2498 u64::from(val) & !mask == 0,
2499 "{name}: encoded u8 {val} overflows mask {mask:b}",
2500 );
2501 }
2502
2503 assert_fits("display", layout_display_to_u8(LayoutDisplay::Contents), DISPLAY_MASK);
2504 assert_fits("position", layout_position_to_u8(LayoutPosition::Sticky), POSITION_MASK);
2505 assert_fits("float", layout_float_to_u8(LayoutFloat::Right), FLOAT_MASK);
2506 assert_fits("overflow", layout_overflow_to_u8(LayoutOverflow::Clip), OVERFLOW_MASK);
2507 assert_fits("box_sizing", layout_box_sizing_to_u8(LayoutBoxSizing::BorderBox), BOX_SIZING_MASK);
2508 assert_fits("flex_direction", layout_flex_direction_to_u8(LayoutFlexDirection::ColumnReverse), FLEX_DIR_MASK);
2509 assert_fits("flex_wrap", layout_flex_wrap_to_u8(LayoutFlexWrap::WrapReverse), FLEX_WRAP_MASK);
2510 assert_fits("justify_content", layout_justify_content_to_u8(LayoutJustifyContent::SpaceEvenly), JUSTIFY_MASK);
2511 assert_fits("align_items", layout_align_items_to_u8(LayoutAlignItems::Baseline), ALIGN_MASK);
2512 assert_fits("align_self", layout_align_self_to_u8(LayoutAlignSelf::Baseline), ALIGN_SELF_MASK);
2513 assert_fits("justify_self", layout_justify_self_to_u8(LayoutJustifySelf::Stretch), JUSTIFY_SELF_MASK);
2514 assert_fits("justify_items", layout_justify_items_to_u8(LayoutJustifyItems::Center), JUSTIFY_ITEMS_MASK);
2515 assert_fits("grid_auto_flow", layout_grid_auto_flow_to_u8(LayoutGridAutoFlow::ColumnDense), GRID_AUTO_FLOW_MASK);
2516 assert_fits("align_content", layout_align_content_to_u8(LayoutAlignContent::SpaceAround), ALIGN_MASK);
2517 assert_fits("writing_mode", layout_writing_mode_to_u8(LayoutWritingMode::VerticalLr), WRITING_MODE_MASK);
2518 assert_fits("clear", layout_clear_to_u8(LayoutClear::Both), CLEAR_MASK);
2519 assert_fits("font_weight", style_font_weight_to_u8(StyleFontWeight::Bolder), FONT_WEIGHT_MASK);
2520 assert_fits("font_style", style_font_style_to_u8(StyleFontStyle::Oblique), FONT_STYLE_MASK);
2521 assert_fits("text_align", style_text_align_to_u8(StyleTextAlign::End), TEXT_ALIGN_MASK);
2522 assert_fits("visibility", style_visibility_to_u8(StyleVisibility::Collapse), VISIBILITY_MASK);
2523 assert_fits("white_space", style_white_space_to_u8(StyleWhiteSpace::BreakSpaces), WHITE_SPACE_MASK);
2524 assert_fits("direction", style_direction_to_u8(StyleDirection::Rtl), DIRECTION_MASK);
2525 assert_fits("vertical_align", style_vertical_align_to_u8(StyleVerticalAlign::TextBottom), VERTICAL_ALIGN_MASK);
2526 assert_fits("border_collapse", border_collapse_to_u8(StyleBorderCollapse::Collapse), BORDER_COLLAPSE_MASK);
2527 }
2528
2529 #[test]
2538 fn test_empty_tier1_decodes_to_initial_values() {
2539 let t1 = TIER1_POPULATED_BIT; assert!(tier1_is_populated(t1));
2541 assert_eq!(decode_display(t1), LayoutDisplay::Block);
2542 assert_eq!(decode_position(t1), LayoutPosition::Static);
2543 assert_eq!(decode_float(t1), LayoutFloat::None);
2544 assert_eq!(decode_overflow_x(t1), LayoutOverflow::Visible);
2545 assert_eq!(decode_overflow_y(t1), LayoutOverflow::Visible);
2546 assert_eq!(decode_box_sizing(t1), LayoutBoxSizing::ContentBox);
2547 assert_eq!(decode_flex_direction(t1), LayoutFlexDirection::Row);
2548 assert_eq!(decode_flex_wrap(t1), LayoutFlexWrap::NoWrap);
2549 assert_eq!(decode_justify_content(t1), LayoutJustifyContent::FlexStart);
2550 assert_eq!(decode_align_items(t1), LayoutAlignItems::Stretch);
2551 assert_eq!(decode_align_content(t1), LayoutAlignContent::Stretch);
2552 assert_eq!(decode_writing_mode(t1), LayoutWritingMode::HorizontalTb);
2553 assert_eq!(decode_clear(t1), LayoutClear::None);
2554 assert_eq!(decode_font_weight(t1), StyleFontWeight::Normal);
2555 assert_eq!(decode_font_style(t1), StyleFontStyle::Normal);
2556 assert_eq!(decode_text_align(t1), StyleTextAlign::Start);
2557 assert_eq!(decode_visibility(t1), StyleVisibility::Visible);
2558 assert_eq!(decode_white_space(t1), StyleWhiteSpace::Normal);
2559 assert_eq!(decode_direction(t1), StyleDirection::Ltr);
2560 assert_eq!(decode_vertical_align(t1), StyleVerticalAlign::Baseline);
2561 assert_eq!(decode_border_collapse(t1), StyleBorderCollapse::Separate);
2562 }
2563}
2564
2565#[cfg(test)]
2566#[allow(
2567 clippy::float_cmp,
2568 clippy::unreadable_literal,
2569 clippy::too_many_lines,
2570 clippy::cast_precision_loss
2571)]
2572mod autotest_generated {
2573 use super::*;
2574 use crate::props::basic::length::PercentageValue;
2575
2576 const ALL_DISPLAY: [LayoutDisplay; 23] = [
2581 LayoutDisplay::Block,
2582 LayoutDisplay::Inline,
2583 LayoutDisplay::InlineBlock,
2584 LayoutDisplay::Flex,
2585 LayoutDisplay::None,
2586 LayoutDisplay::InlineFlex,
2587 LayoutDisplay::Table,
2588 LayoutDisplay::InlineTable,
2589 LayoutDisplay::TableRowGroup,
2590 LayoutDisplay::TableHeaderGroup,
2591 LayoutDisplay::TableFooterGroup,
2592 LayoutDisplay::TableRow,
2593 LayoutDisplay::TableColumnGroup,
2594 LayoutDisplay::TableColumn,
2595 LayoutDisplay::TableCell,
2596 LayoutDisplay::TableCaption,
2597 LayoutDisplay::FlowRoot,
2598 LayoutDisplay::ListItem,
2599 LayoutDisplay::RunIn,
2600 LayoutDisplay::Marker,
2601 LayoutDisplay::Grid,
2602 LayoutDisplay::InlineGrid,
2603 LayoutDisplay::Contents,
2604 ];
2605
2606 const ALL_BORDER_STYLE: [BorderStyle; 10] = [
2607 BorderStyle::None,
2608 BorderStyle::Solid,
2609 BorderStyle::Double,
2610 BorderStyle::Dotted,
2611 BorderStyle::Dashed,
2612 BorderStyle::Hidden,
2613 BorderStyle::Groove,
2614 BorderStyle::Ridge,
2615 BorderStyle::Inset,
2616 BorderStyle::Outset,
2617 ];
2618
2619 const ALL_SIZE_METRIC: [SizeMetric; 12] = [
2620 SizeMetric::Px,
2621 SizeMetric::Pt,
2622 SizeMetric::Em,
2623 SizeMetric::Rem,
2624 SizeMetric::In,
2625 SizeMetric::Cm,
2626 SizeMetric::Mm,
2627 SizeMetric::Percent,
2628 SizeMetric::Vw,
2629 SizeMetric::Vh,
2630 SizeMetric::Vmin,
2631 SizeMetric::Vmax,
2632 ];
2633
2634 fn pv_raw(metric: SizeMetric, raw: isize) -> PixelValue {
2637 PixelValue {
2638 metric,
2639 number: FloatValue { number: raw },
2640 }
2641 }
2642
2643 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
2646 struct T1 {
2647 display: LayoutDisplay,
2648 position: LayoutPosition,
2649 float: LayoutFloat,
2650 overflow_x: LayoutOverflow,
2651 overflow_y: LayoutOverflow,
2652 box_sizing: LayoutBoxSizing,
2653 flex_direction: LayoutFlexDirection,
2654 flex_wrap: LayoutFlexWrap,
2655 justify_content: LayoutJustifyContent,
2656 align_items: LayoutAlignItems,
2657 align_content: LayoutAlignContent,
2658 writing_mode: LayoutWritingMode,
2659 clear: LayoutClear,
2660 font_weight: StyleFontWeight,
2661 font_style: StyleFontStyle,
2662 text_align: StyleTextAlign,
2663 visibility: StyleVisibility,
2664 white_space: StyleWhiteSpace,
2665 direction: StyleDirection,
2666 vertical_align: StyleVerticalAlign,
2667 border_collapse: StyleBorderCollapse,
2668 }
2669
2670 impl T1 {
2671 const fn initial() -> Self {
2673 Self {
2674 display: LayoutDisplay::Block,
2675 position: LayoutPosition::Static,
2676 float: LayoutFloat::None,
2677 overflow_x: LayoutOverflow::Visible,
2678 overflow_y: LayoutOverflow::Visible,
2679 box_sizing: LayoutBoxSizing::ContentBox,
2680 flex_direction: LayoutFlexDirection::Row,
2681 flex_wrap: LayoutFlexWrap::NoWrap,
2682 justify_content: LayoutJustifyContent::FlexStart,
2683 align_items: LayoutAlignItems::Stretch,
2684 align_content: LayoutAlignContent::Stretch,
2685 writing_mode: LayoutWritingMode::HorizontalTb,
2686 clear: LayoutClear::None,
2687 font_weight: StyleFontWeight::Normal,
2688 font_style: StyleFontStyle::Normal,
2689 text_align: StyleTextAlign::Start,
2690 visibility: StyleVisibility::Visible,
2691 white_space: StyleWhiteSpace::Normal,
2692 direction: StyleDirection::Ltr,
2693 vertical_align: StyleVerticalAlign::Baseline,
2694 border_collapse: StyleBorderCollapse::Separate,
2695 }
2696 }
2697
2698 const fn saturated() -> Self {
2701 Self {
2702 display: LayoutDisplay::Contents,
2703 position: LayoutPosition::Sticky,
2704 float: LayoutFloat::Right,
2705 overflow_x: LayoutOverflow::Clip,
2706 overflow_y: LayoutOverflow::Clip,
2707 box_sizing: LayoutBoxSizing::BorderBox,
2708 flex_direction: LayoutFlexDirection::ColumnReverse,
2709 flex_wrap: LayoutFlexWrap::WrapReverse,
2710 justify_content: LayoutJustifyContent::SpaceEvenly,
2711 align_items: LayoutAlignItems::Baseline,
2712 align_content: LayoutAlignContent::SpaceAround,
2713 writing_mode: LayoutWritingMode::VerticalLr,
2714 clear: LayoutClear::Both,
2715 font_weight: StyleFontWeight::Bolder,
2716 font_style: StyleFontStyle::Oblique,
2717 text_align: StyleTextAlign::End,
2718 visibility: StyleVisibility::Collapse,
2719 white_space: StyleWhiteSpace::BreakSpaces,
2720 direction: StyleDirection::Rtl,
2721 vertical_align: StyleVerticalAlign::TextBottom,
2722 border_collapse: StyleBorderCollapse::Collapse,
2723 }
2724 }
2725
2726 fn encode(self) -> u64 {
2727 encode_tier1(
2728 self.display,
2729 self.position,
2730 self.float,
2731 self.overflow_x,
2732 self.overflow_y,
2733 self.box_sizing,
2734 self.flex_direction,
2735 self.flex_wrap,
2736 self.justify_content,
2737 self.align_items,
2738 self.align_content,
2739 self.writing_mode,
2740 self.clear,
2741 self.font_weight,
2742 self.font_style,
2743 self.text_align,
2744 self.visibility,
2745 self.white_space,
2746 self.direction,
2747 self.vertical_align,
2748 self.border_collapse,
2749 )
2750 }
2751
2752 fn decode(t1: u64) -> Self {
2753 Self {
2754 display: decode_display(t1),
2755 position: decode_position(t1),
2756 float: decode_float(t1),
2757 overflow_x: decode_overflow_x(t1),
2758 overflow_y: decode_overflow_y(t1),
2759 box_sizing: decode_box_sizing(t1),
2760 flex_direction: decode_flex_direction(t1),
2761 flex_wrap: decode_flex_wrap(t1),
2762 justify_content: decode_justify_content(t1),
2763 align_items: decode_align_items(t1),
2764 align_content: decode_align_content(t1),
2765 writing_mode: decode_writing_mode(t1),
2766 clear: decode_clear(t1),
2767 font_weight: decode_font_weight(t1),
2768 font_style: decode_font_style(t1),
2769 text_align: decode_text_align(t1),
2770 visibility: decode_visibility(t1),
2771 white_space: decode_white_space(t1),
2772 direction: decode_direction(t1),
2773 vertical_align: decode_vertical_align(t1),
2774 border_collapse: decode_border_collapse(t1),
2775 }
2776 }
2777 }
2778
2779 fn assert_u8_fallback<T: PartialEq + core::fmt::Debug + Copy>(
2787 name: &str,
2788 decode: fn(u8) -> T,
2789 first_invalid: u8,
2790 initial: T,
2791 ) {
2792 for v in first_invalid..=u8::MAX {
2793 assert_eq!(
2794 decode(v),
2795 initial,
2796 "{name}: out-of-range byte {v} must fall back to the CSS initial value",
2797 );
2798 }
2799 }
2800
2801 #[test]
2802 fn out_of_range_u8_falls_back_to_css_initial_for_every_enum() {
2803 assert_u8_fallback("display", layout_display_from_u8, 23, LayoutDisplay::Block);
2804 assert_u8_fallback("position", layout_position_from_u8, 5, LayoutPosition::Static);
2805 assert_u8_fallback("float", layout_float_from_u8, 3, LayoutFloat::None);
2806 assert_u8_fallback("overflow", layout_overflow_from_u8, 5, LayoutOverflow::Visible);
2807 assert_u8_fallback(
2808 "box_sizing",
2809 layout_box_sizing_from_u8,
2810 2,
2811 LayoutBoxSizing::ContentBox,
2812 );
2813 assert_u8_fallback(
2814 "flex_direction",
2815 layout_flex_direction_from_u8,
2816 4,
2817 LayoutFlexDirection::Row,
2818 );
2819 assert_u8_fallback("flex_wrap", layout_flex_wrap_from_u8, 3, LayoutFlexWrap::NoWrap);
2820 assert_u8_fallback(
2821 "justify_content",
2822 layout_justify_content_from_u8,
2823 8,
2824 LayoutJustifyContent::FlexStart,
2825 );
2826 assert_u8_fallback(
2827 "align_items",
2828 layout_align_items_from_u8,
2829 5,
2830 LayoutAlignItems::Stretch,
2831 );
2832 assert_u8_fallback("align_self", layout_align_self_from_u8, 6, LayoutAlignSelf::Auto);
2833 assert_u8_fallback(
2834 "justify_self",
2835 layout_justify_self_from_u8,
2836 5,
2837 LayoutJustifySelf::Auto,
2838 );
2839 assert_u8_fallback(
2840 "justify_items",
2841 layout_justify_items_from_u8,
2842 4,
2843 LayoutJustifyItems::Stretch,
2844 );
2845 assert_u8_fallback(
2846 "grid_auto_flow",
2847 layout_grid_auto_flow_from_u8,
2848 4,
2849 LayoutGridAutoFlow::Row,
2850 );
2851 assert_u8_fallback(
2852 "align_content",
2853 layout_align_content_from_u8,
2854 6,
2855 LayoutAlignContent::Stretch,
2856 );
2857 assert_u8_fallback(
2858 "writing_mode",
2859 layout_writing_mode_from_u8,
2860 3,
2861 LayoutWritingMode::HorizontalTb,
2862 );
2863 assert_u8_fallback("clear", layout_clear_from_u8, 4, LayoutClear::None);
2864 assert_u8_fallback(
2865 "font_weight",
2866 style_font_weight_from_u8,
2867 11,
2868 StyleFontWeight::Normal,
2869 );
2870 assert_u8_fallback("font_style", style_font_style_from_u8, 3, StyleFontStyle::Normal);
2871 assert_u8_fallback("text_align", style_text_align_from_u8, 6, StyleTextAlign::Start);
2872 assert_u8_fallback(
2873 "visibility",
2874 style_visibility_from_u8,
2875 3,
2876 StyleVisibility::Visible,
2877 );
2878 assert_u8_fallback(
2879 "white_space",
2880 style_white_space_from_u8,
2881 6,
2882 StyleWhiteSpace::Normal,
2883 );
2884 assert_u8_fallback("direction", style_direction_from_u8, 2, StyleDirection::Ltr);
2885 assert_u8_fallback(
2886 "vertical_align",
2887 style_vertical_align_from_u8,
2888 8,
2889 StyleVerticalAlign::Baseline,
2890 );
2891 assert_u8_fallback(
2892 "border_collapse",
2893 border_collapse_from_u8,
2894 2,
2895 StyleBorderCollapse::Separate,
2896 );
2897 assert_u8_fallback("border_style", border_style_from_u8, 10, BorderStyle::None);
2898 assert_u8_fallback("size_metric", size_metric_from_u8, 12, SizeMetric::Px);
2899 }
2900
2901 #[test]
2902 fn display_documented_sentinel_31_decodes_to_block() {
2903 assert_eq!(layout_display_from_u8(31), LayoutDisplay::Block);
2908 assert_eq!(layout_display_from_u8(u8::MAX), LayoutDisplay::Block);
2909 }
2910
2911 #[test]
2912 fn every_variant_of_every_enum_fits_its_tier1_mask() {
2913 fn fits(name: &str, val: u8, mask: u64) {
2918 assert!(
2919 u64::from(val) & !mask == 0,
2920 "{name}: encoded u8 {val} does not fit mask {mask:#b}",
2921 );
2922 }
2923
2924 for v in ALL_DISPLAY {
2925 fits("display", layout_display_to_u8(v), DISPLAY_MASK);
2926 }
2927 for v in [
2928 LayoutPosition::Static,
2929 LayoutPosition::Relative,
2930 LayoutPosition::Absolute,
2931 LayoutPosition::Fixed,
2932 LayoutPosition::Sticky,
2933 ] {
2934 fits("position", layout_position_to_u8(v), POSITION_MASK);
2935 }
2936 for v in [LayoutFloat::None, LayoutFloat::Left, LayoutFloat::Right] {
2937 fits("float", layout_float_to_u8(v), FLOAT_MASK);
2938 }
2939 for v in [
2940 LayoutOverflow::Visible,
2941 LayoutOverflow::Hidden,
2942 LayoutOverflow::Scroll,
2943 LayoutOverflow::Auto,
2944 LayoutOverflow::Clip,
2945 ] {
2946 fits("overflow", layout_overflow_to_u8(v), OVERFLOW_MASK);
2947 }
2948 for v in [LayoutBoxSizing::ContentBox, LayoutBoxSizing::BorderBox] {
2949 fits("box_sizing", layout_box_sizing_to_u8(v), BOX_SIZING_MASK);
2950 }
2951 for v in [
2952 LayoutFlexDirection::Row,
2953 LayoutFlexDirection::RowReverse,
2954 LayoutFlexDirection::Column,
2955 LayoutFlexDirection::ColumnReverse,
2956 ] {
2957 fits("flex_direction", layout_flex_direction_to_u8(v), FLEX_DIR_MASK);
2958 }
2959 for v in [
2960 LayoutFlexWrap::NoWrap,
2961 LayoutFlexWrap::Wrap,
2962 LayoutFlexWrap::WrapReverse,
2963 ] {
2964 fits("flex_wrap", layout_flex_wrap_to_u8(v), FLEX_WRAP_MASK);
2965 }
2966 for v in [
2967 LayoutJustifyContent::FlexStart,
2968 LayoutJustifyContent::FlexEnd,
2969 LayoutJustifyContent::Start,
2970 LayoutJustifyContent::End,
2971 LayoutJustifyContent::Center,
2972 LayoutJustifyContent::SpaceBetween,
2973 LayoutJustifyContent::SpaceAround,
2974 LayoutJustifyContent::SpaceEvenly,
2975 ] {
2976 fits("justify_content", layout_justify_content_to_u8(v), JUSTIFY_MASK);
2977 }
2978 for v in [
2979 LayoutAlignItems::Stretch,
2980 LayoutAlignItems::Center,
2981 LayoutAlignItems::Start,
2982 LayoutAlignItems::End,
2983 LayoutAlignItems::Baseline,
2984 ] {
2985 fits("align_items", layout_align_items_to_u8(v), ALIGN_MASK);
2986 }
2987 for v in [
2988 LayoutAlignSelf::Auto,
2989 LayoutAlignSelf::Stretch,
2990 LayoutAlignSelf::Center,
2991 LayoutAlignSelf::Start,
2992 LayoutAlignSelf::End,
2993 LayoutAlignSelf::Baseline,
2994 ] {
2995 fits("align_self", layout_align_self_to_u8(v), ALIGN_SELF_MASK);
2996 }
2997 for v in [
2998 LayoutJustifySelf::Auto,
2999 LayoutJustifySelf::Start,
3000 LayoutJustifySelf::End,
3001 LayoutJustifySelf::Center,
3002 LayoutJustifySelf::Stretch,
3003 ] {
3004 fits("justify_self", layout_justify_self_to_u8(v), JUSTIFY_SELF_MASK);
3005 }
3006 for v in [
3007 LayoutJustifyItems::Stretch,
3008 LayoutJustifyItems::Start,
3009 LayoutJustifyItems::End,
3010 LayoutJustifyItems::Center,
3011 ] {
3012 fits("justify_items", layout_justify_items_to_u8(v), JUSTIFY_ITEMS_MASK);
3013 }
3014 for v in [
3015 LayoutGridAutoFlow::Row,
3016 LayoutGridAutoFlow::Column,
3017 LayoutGridAutoFlow::RowDense,
3018 LayoutGridAutoFlow::ColumnDense,
3019 ] {
3020 fits("grid_auto_flow", layout_grid_auto_flow_to_u8(v), GRID_AUTO_FLOW_MASK);
3021 }
3022 for v in [
3023 LayoutAlignContent::Stretch,
3024 LayoutAlignContent::Center,
3025 LayoutAlignContent::Start,
3026 LayoutAlignContent::End,
3027 LayoutAlignContent::SpaceBetween,
3028 LayoutAlignContent::SpaceAround,
3029 ] {
3030 fits("align_content", layout_align_content_to_u8(v), ALIGN_MASK);
3031 }
3032 for v in [
3033 LayoutWritingMode::HorizontalTb,
3034 LayoutWritingMode::VerticalRl,
3035 LayoutWritingMode::VerticalLr,
3036 ] {
3037 fits("writing_mode", layout_writing_mode_to_u8(v), WRITING_MODE_MASK);
3038 }
3039 for v in [
3040 LayoutClear::None,
3041 LayoutClear::Left,
3042 LayoutClear::Right,
3043 LayoutClear::Both,
3044 ] {
3045 fits("clear", layout_clear_to_u8(v), CLEAR_MASK);
3046 }
3047 for v in [
3048 StyleFontWeight::Normal,
3049 StyleFontWeight::W100,
3050 StyleFontWeight::W200,
3051 StyleFontWeight::W300,
3052 StyleFontWeight::W500,
3053 StyleFontWeight::W600,
3054 StyleFontWeight::Bold,
3055 StyleFontWeight::W800,
3056 StyleFontWeight::W900,
3057 StyleFontWeight::Lighter,
3058 StyleFontWeight::Bolder,
3059 ] {
3060 fits("font_weight", style_font_weight_to_u8(v), FONT_WEIGHT_MASK);
3061 }
3062 for v in [
3063 StyleFontStyle::Normal,
3064 StyleFontStyle::Italic,
3065 StyleFontStyle::Oblique,
3066 ] {
3067 fits("font_style", style_font_style_to_u8(v), FONT_STYLE_MASK);
3068 }
3069 for v in [
3070 StyleTextAlign::Left,
3071 StyleTextAlign::Center,
3072 StyleTextAlign::Right,
3073 StyleTextAlign::Justify,
3074 StyleTextAlign::Start,
3075 StyleTextAlign::End,
3076 ] {
3077 fits("text_align", style_text_align_to_u8(v), TEXT_ALIGN_MASK);
3078 }
3079 for v in [
3080 StyleVisibility::Visible,
3081 StyleVisibility::Hidden,
3082 StyleVisibility::Collapse,
3083 ] {
3084 fits("visibility", style_visibility_to_u8(v), VISIBILITY_MASK);
3085 }
3086 for v in [
3087 StyleWhiteSpace::Normal,
3088 StyleWhiteSpace::Pre,
3089 StyleWhiteSpace::Nowrap,
3090 StyleWhiteSpace::PreWrap,
3091 StyleWhiteSpace::PreLine,
3092 StyleWhiteSpace::BreakSpaces,
3093 ] {
3094 fits("white_space", style_white_space_to_u8(v), WHITE_SPACE_MASK);
3095 }
3096 for v in [StyleDirection::Ltr, StyleDirection::Rtl] {
3097 fits("direction", style_direction_to_u8(v), DIRECTION_MASK);
3098 }
3099 for v in [
3100 StyleVerticalAlign::Baseline,
3101 StyleVerticalAlign::Top,
3102 StyleVerticalAlign::Middle,
3103 StyleVerticalAlign::Bottom,
3104 StyleVerticalAlign::Sub,
3105 StyleVerticalAlign::Superscript,
3106 StyleVerticalAlign::TextTop,
3107 StyleVerticalAlign::TextBottom,
3108 StyleVerticalAlign::Percentage(PercentageValue::new(50.0)),
3109 StyleVerticalAlign::Length(PixelValue::px(4.0)),
3110 ] {
3111 fits("vertical_align", style_vertical_align_to_u8(v), VERTICAL_ALIGN_MASK);
3112 }
3113 for v in [StyleBorderCollapse::Separate, StyleBorderCollapse::Collapse] {
3114 fits("border_collapse", border_collapse_to_u8(v), BORDER_COLLAPSE_MASK);
3115 }
3116 for v in ALL_BORDER_STYLE {
3118 fits("border_style", border_style_to_u8(v), 0x0F);
3119 }
3120 for v in ALL_SIZE_METRIC {
3122 fits("size_metric", size_metric_to_u8(v), 0x0F);
3123 }
3124 }
3125
3126 #[test]
3127 fn vertical_align_percentage_and_length_collapse_to_baseline() {
3128 for v in [
3133 StyleVerticalAlign::Percentage(PercentageValue::new(0.0)),
3134 StyleVerticalAlign::Percentage(PercentageValue::new(-100.0)),
3135 StyleVerticalAlign::Percentage(PercentageValue::new(1e9)),
3136 StyleVerticalAlign::Length(PixelValue::px(0.0)),
3137 StyleVerticalAlign::Length(PixelValue::px(-1e9)),
3138 ] {
3139 assert_eq!(style_vertical_align_to_u8(v), 0);
3140 assert_eq!(
3141 style_vertical_align_from_u8(style_vertical_align_to_u8(v)),
3142 StyleVerticalAlign::Baseline,
3143 );
3144 }
3145
3146 let mut t = T1::initial();
3148 t.vertical_align = StyleVerticalAlign::Percentage(PercentageValue::new(150.0));
3149 t.border_collapse = StyleBorderCollapse::Collapse;
3150 let encoded = t.encode();
3151 assert_eq!(decode_vertical_align(encoded), StyleVerticalAlign::Baseline);
3152 assert_eq!(decode_border_collapse(encoded), StyleBorderCollapse::Collapse);
3153 }
3154
3155 #[test]
3160 fn tier1_each_field_at_max_does_not_leak_into_any_other_field() {
3161 let sat = T1::saturated();
3165 let mut cases: Vec<(&str, T1)> = Vec::new();
3166
3167 macro_rules! case {
3168 ($field:ident) => {{
3169 let mut t = T1::initial();
3170 t.$field = sat.$field;
3171 cases.push((stringify!($field), t));
3172 }};
3173 }
3174
3175 case!(display);
3176 case!(position);
3177 case!(float);
3178 case!(overflow_x);
3179 case!(overflow_y);
3180 case!(box_sizing);
3181 case!(flex_direction);
3182 case!(flex_wrap);
3183 case!(justify_content);
3184 case!(align_items);
3185 case!(align_content);
3186 case!(writing_mode);
3187 case!(clear);
3188 case!(font_weight);
3189 case!(font_style);
3190 case!(text_align);
3191 case!(visibility);
3192 case!(white_space);
3193 case!(direction);
3194 case!(vertical_align);
3195 case!(border_collapse);
3196
3197 assert_eq!(cases.len(), 21, "every tier1 field must be covered");
3198
3199 for (name, expected) in cases {
3200 let decoded = T1::decode(expected.encode());
3201 assert_eq!(
3202 decoded, expected,
3203 "{name} at its max variant leaked into another tier1 field",
3204 );
3205 }
3206 }
3207
3208 #[test]
3209 fn tier1_all_fields_saturated_roundtrips() {
3210 let sat = T1::saturated();
3211 assert_eq!(T1::decode(sat.encode()), sat);
3212 assert!(tier1_is_populated(sat.encode()));
3213 }
3214
3215 #[test]
3216 fn tier1_encode_never_touches_the_grid_bits_or_bits_above_63() {
3217 const GRID_WINDOW: u64 = 0x3FF << 53; for t in [T1::initial(), T1::saturated()] {
3225 let encoded = t.encode();
3226 assert_eq!(
3227 encoded & GRID_WINDOW,
3228 0,
3229 "encode_tier1 wrote into the grid bit window [62:53]",
3230 );
3231 assert_eq!(encoded & TIER1_POPULATED_BIT, TIER1_POPULATED_BIT);
3232 }
3233
3234 let base = T1::saturated().encode();
3236 let with_grid = base
3237 | ((u64::from(layout_align_self_to_u8(LayoutAlignSelf::Baseline))) << ALIGN_SELF_SHIFT)
3238 | ((u64::from(layout_justify_self_to_u8(LayoutJustifySelf::Stretch)))
3239 << JUSTIFY_SELF_SHIFT)
3240 | ((u64::from(layout_grid_auto_flow_to_u8(LayoutGridAutoFlow::ColumnDense)))
3241 << GRID_AUTO_FLOW_SHIFT)
3242 | ((u64::from(layout_justify_items_to_u8(LayoutJustifyItems::Center)))
3243 << JUSTIFY_ITEMS_SHIFT);
3244
3245 assert_eq!(T1::decode(with_grid), T1::saturated());
3246 assert_eq!(
3247 layout_align_self_from_u8(((with_grid >> ALIGN_SELF_SHIFT) & ALIGN_SELF_MASK) as u8),
3248 LayoutAlignSelf::Baseline,
3249 );
3250 assert_eq!(
3251 layout_justify_self_from_u8(
3252 ((with_grid >> JUSTIFY_SELF_SHIFT) & JUSTIFY_SELF_MASK) as u8
3253 ),
3254 LayoutJustifySelf::Stretch,
3255 );
3256 assert_eq!(
3257 layout_grid_auto_flow_from_u8(
3258 ((with_grid >> GRID_AUTO_FLOW_SHIFT) & GRID_AUTO_FLOW_MASK) as u8
3259 ),
3260 LayoutGridAutoFlow::ColumnDense,
3261 );
3262 assert_eq!(
3263 layout_justify_items_from_u8(
3264 ((with_grid >> JUSTIFY_ITEMS_SHIFT) & JUSTIFY_ITEMS_MASK) as u8
3265 ),
3266 LayoutJustifyItems::Center,
3267 );
3268 }
3269
3270 #[test]
3271 fn tier1_zero_is_unpopulated_but_still_decodes_to_css_initial() {
3272 assert!(!tier1_is_populated(0));
3276 assert_eq!(T1::decode(0), T1::initial());
3277 }
3278
3279 #[test]
3280 fn tier1_decodes_arbitrary_u64_deterministically_without_panic() {
3281 let m = u64::MAX;
3285 assert!(tier1_is_populated(m));
3286 assert_eq!(
3287 T1::decode(m),
3288 T1 {
3289 display: LayoutDisplay::Block, position: LayoutPosition::Static, float: LayoutFloat::None, overflow_x: LayoutOverflow::Visible, overflow_y: LayoutOverflow::Visible, box_sizing: LayoutBoxSizing::BorderBox, flex_direction: LayoutFlexDirection::ColumnReverse, flex_wrap: LayoutFlexWrap::NoWrap, justify_content: LayoutJustifyContent::SpaceEvenly, align_items: LayoutAlignItems::Stretch, align_content: LayoutAlignContent::Stretch, writing_mode: LayoutWritingMode::HorizontalTb, clear: LayoutClear::Both, font_weight: StyleFontWeight::Normal, font_style: StyleFontStyle::Normal, text_align: StyleTextAlign::Start, visibility: StyleVisibility::Visible, white_space: StyleWhiteSpace::Normal, direction: StyleDirection::Rtl, vertical_align: StyleVerticalAlign::TextBottom, border_collapse: StyleBorderCollapse::Collapse, },
3311 );
3312
3313 let mut x: u64 = 0x9E37_79B9_7F4A_7C15;
3315 for _ in 0..4096 {
3316 let _ = T1::decode(x);
3317 let _ = tier1_is_populated(x);
3318 x = x.wrapping_mul(6364136223846793005).wrapping_add(1442695040888963407);
3319 }
3320 for x in [0u64, 1, u64::MAX, 0xAAAA_AAAA_AAAA_AAAA, 0x5555_5555_5555_5555] {
3321 let _ = T1::decode(x);
3322 }
3323 }
3324
3325 #[test]
3330 fn border_styles_packed_roundtrip_for_all_10000_combinations() {
3331 for top in ALL_BORDER_STYLE {
3332 for right in ALL_BORDER_STYLE {
3333 for bottom in ALL_BORDER_STYLE {
3334 for left in ALL_BORDER_STYLE {
3335 let packed = encode_border_styles_packed(top, right, bottom, left);
3336 assert_eq!(decode_border_top_style(packed), top);
3337 assert_eq!(decode_border_right_style(packed), right);
3338 assert_eq!(decode_border_bottom_style(packed), bottom);
3339 assert_eq!(decode_border_left_style(packed), left);
3340 }
3341 }
3342 }
3343 }
3344 }
3345
3346 #[test]
3347 fn border_styles_packed_nibbles_do_not_alias() {
3348 let packed = encode_border_styles_packed(
3351 BorderStyle::Outset, BorderStyle::None,
3353 BorderStyle::None,
3354 BorderStyle::None,
3355 );
3356 assert_eq!(packed, 0x0009);
3357 assert_eq!(decode_border_top_style(packed), BorderStyle::Outset);
3358 assert_eq!(decode_border_right_style(packed), BorderStyle::None);
3359 assert_eq!(decode_border_bottom_style(packed), BorderStyle::None);
3360 assert_eq!(decode_border_left_style(packed), BorderStyle::None);
3361
3362 let packed = encode_border_styles_packed(
3363 BorderStyle::None,
3364 BorderStyle::None,
3365 BorderStyle::None,
3366 BorderStyle::Outset,
3367 );
3368 assert_eq!(packed, 0x9000);
3369 assert_eq!(decode_border_left_style(packed), BorderStyle::Outset);
3370 assert_eq!(decode_border_top_style(packed), BorderStyle::None);
3371 }
3372
3373 #[test]
3374 fn border_styles_packed_decodes_garbage_u16_without_panic() {
3375 for packed in [0u16, 0xFFFF, 0xAAAA, 0x5555, u16::MAX / 2] {
3378 let _ = decode_border_top_style(packed);
3379 let _ = decode_border_right_style(packed);
3380 let _ = decode_border_bottom_style(packed);
3381 let _ = decode_border_left_style(packed);
3382 }
3383 assert_eq!(decode_border_top_style(0xFFFF), BorderStyle::None);
3384 assert_eq!(decode_border_right_style(0xFFFF), BorderStyle::None);
3385 assert_eq!(decode_border_bottom_style(0xFFFF), BorderStyle::None);
3386 assert_eq!(decode_border_left_style(0xFFFF), BorderStyle::None);
3387 for packed in 0..=u16::MAX {
3389 let _ = decode_border_top_style(packed);
3390 let _ = decode_border_left_style(packed);
3391 }
3392 }
3393
3394 #[test]
3399 fn color_u32_channel_order_is_rrggbbaa() {
3400 let c = ColorU {
3401 r: 0x12,
3402 g: 0x34,
3403 b: 0x56,
3404 a: 0x78,
3405 };
3406 assert_eq!(encode_color_u32(&c), 0x1234_5678);
3407 assert_eq!(decode_color_u32(0x1234_5678), Some(c));
3408 }
3409
3410 #[test]
3411 fn color_u32_roundtrips_every_boundary_channel_combination() {
3412 for r in [0u8, 1, 127, 254, 255] {
3413 for g in [0u8, 1, 127, 254, 255] {
3414 for b in [0u8, 1, 127, 254, 255] {
3415 for a in [0u8, 1, 127, 254, 255] {
3416 let c = ColorU { r, g, b, a };
3417 let encoded = encode_color_u32(&c);
3418 if encoded == 0 {
3419 assert_eq!((r, g, b, a), (0, 0, 0, 0));
3421 assert_eq!(decode_color_u32(encoded), None);
3422 } else {
3423 assert_eq!(decode_color_u32(encoded), Some(c));
3424 }
3425 }
3426 }
3427 }
3428 }
3429 }
3430
3431 #[test]
3432 fn color_u32_transparent_black_is_the_documented_unset_collision() {
3433 let transparent_black = ColorU {
3436 r: 0,
3437 g: 0,
3438 b: 0,
3439 a: 0,
3440 };
3441 assert_eq!(encode_color_u32(&transparent_black), 0);
3442 assert_eq!(decode_color_u32(0), None);
3443
3444 let transparent_red = ColorU {
3446 r: 255,
3447 g: 0,
3448 b: 0,
3449 a: 0,
3450 };
3451 assert_eq!(encode_color_u32(&transparent_red), 0xFF00_0000);
3452 assert_eq!(decode_color_u32(0xFF00_0000), Some(transparent_red));
3453
3454 let almost = ColorU {
3456 r: 0,
3457 g: 0,
3458 b: 0,
3459 a: 1,
3460 };
3461 assert_eq!(decode_color_u32(encode_color_u32(&almost)), Some(almost));
3462 }
3463
3464 #[test]
3465 fn color_u32_max_decodes_to_opaque_white() {
3466 assert_eq!(
3467 decode_color_u32(u32::MAX),
3468 Some(ColorU {
3469 r: 255,
3470 g: 255,
3471 b: 255,
3472 a: 255
3473 }),
3474 );
3475 }
3476
3477 #[test]
3482 fn pixel_value_u32_sentinels_all_decode_to_none_and_are_distinct() {
3483 let sentinels = [
3484 U32_SENTINEL,
3485 U32_AUTO,
3486 U32_NONE,
3487 U32_INHERIT,
3488 U32_INITIAL,
3489 U32_MIN_CONTENT,
3490 U32_MAX_CONTENT,
3491 ];
3492 for (i, a) in sentinels.iter().enumerate() {
3493 assert!(
3494 *a >= U32_SENTINEL_THRESHOLD,
3495 "sentinel {a:#X} sits below the threshold and would decode as a value",
3496 );
3497 assert_eq!(decode_pixel_value_u32(*a), None);
3498 for b in &sentinels[i + 1..] {
3499 assert_ne!(a, b, "two u32 sentinels share a bit pattern");
3500 }
3501 }
3502 assert_eq!(decode_pixel_value_u32(U32_SENTINEL_THRESHOLD), None);
3504 assert!(decode_pixel_value_u32(U32_SENTINEL_THRESHOLD - 1).is_some());
3506 }
3507
3508 #[test]
3509 fn pixel_value_u32_roundtrips_at_the_28_bit_boundaries_for_every_metric() {
3510 for metric in ALL_SIZE_METRIC {
3512 for raw in [0isize, 1, -1, 1000, -1000, 134_217_727, -134_217_728] {
3513 let pv = pv_raw(metric, raw);
3514 let encoded = encode_pixel_value_u32(&pv);
3515
3516 if encoded >= U32_SENTINEL_THRESHOLD {
3519 continue;
3520 }
3521
3522 let decoded = decode_pixel_value_u32(encoded)
3523 .unwrap_or_else(|| panic!("{metric:?} raw {raw} decoded as a sentinel"));
3524 assert_eq!(decoded.metric, metric, "metric nibble lost for raw {raw}");
3525 assert_eq!(
3526 decoded.number.number(),
3527 raw,
3528 "{metric:?}: raw {raw} did not survive the round-trip",
3529 );
3530 }
3531 }
3532 }
3533
3534 #[test]
3535 fn pixel_value_u32_out_of_28_bit_range_returns_sentinel() {
3536 for metric in ALL_SIZE_METRIC {
3537 for raw in [
3538 134_217_728isize,
3539 -134_217_729,
3540 1_000_000_000,
3541 -1_000_000_000,
3542 isize::MAX,
3543 isize::MIN,
3544 ] {
3545 assert_eq!(
3546 encode_pixel_value_u32(&pv_raw(metric, raw)),
3547 U32_SENTINEL,
3548 "{metric:?}: raw {raw} is outside 28 bits and must escape to tier 3",
3549 );
3550 }
3551 }
3552 }
3553
3554 #[test]
3555 fn pixel_value_u32_decodes_every_low_bit_pattern_without_panic() {
3556 for nibble in 12u32..16 {
3558 let encoded = (1u32 << 4) | nibble;
3559 let decoded = decode_pixel_value_u32(encoded).unwrap();
3560 assert_eq!(decoded.metric, SizeMetric::Px);
3561 assert_eq!(decoded.number.number(), 1);
3562 }
3563 let neg = decode_pixel_value_u32(0x8000_0000).unwrap();
3565 assert_eq!(neg.metric, SizeMetric::Px);
3566 assert_eq!(neg.number.number(), -134_217_728);
3567 }
3568
3569 #[test]
3570 fn pixel_value_u32_negative_0_001_in_vh_vmin_vmax_collides_with_sentinels() {
3571 for metric in [SizeMetric::Vh, SizeMetric::Vmin, SizeMetric::Vmax] {
3594 let pv = pv_raw(metric, -1);
3595 let encoded = encode_pixel_value_u32(&pv);
3596 assert_eq!(encoded, U32_SENTINEL, "{metric:?}: raw -1 must escape to tier 3");
3597 assert_eq!(
3598 decode_pixel_value_u32(encoded),
3599 None,
3600 "{metric:?}: an escaped value decodes as None, never an aliased sentinel",
3601 );
3602 }
3603 }
3604
3605 #[test]
3610 fn resolved_px_i16_nan_and_infinity_are_defined_and_do_not_panic() {
3611 assert_eq!(encode_resolved_px_i16(f32::NAN), 0);
3613 assert_eq!(encode_resolved_px_i16(-f32::NAN), 0);
3614 assert_eq!(encode_resolved_px_i16(f32::INFINITY), I16_SENTINEL);
3615 assert_eq!(encode_resolved_px_i16(f32::NEG_INFINITY), I16_SENTINEL);
3616 assert_eq!(encode_resolved_px_i16(f32::MAX), I16_SENTINEL);
3617 assert_eq!(encode_resolved_px_i16(f32::MIN), I16_SENTINEL);
3618 assert_eq!(encode_resolved_px_i16(f32::MIN_POSITIVE), 0);
3620 assert_eq!(encode_resolved_px_i16(-0.0), 0);
3621 }
3622
3623 #[test]
3624 fn resolved_px_i16_saturates_exactly_at_the_documented_range() {
3625 assert_eq!(encode_resolved_px_i16(3276.3), 32763);
3627 assert_eq!(encode_resolved_px_i16(-3276.8), -32768);
3628
3629 assert_eq!(encode_resolved_px_i16(3276.4), I16_SENTINEL);
3631 assert_eq!(encode_resolved_px_i16(-3276.9), I16_SENTINEL);
3632 assert_eq!(encode_resolved_px_i16(1e9), I16_SENTINEL);
3633 assert_eq!(encode_resolved_px_i16(-1e9), I16_SENTINEL);
3634 }
3635
3636 #[test]
3637 fn resolved_px_i16_sentinels_decode_to_none_and_are_distinct() {
3638 let sentinels = [I16_SENTINEL, I16_AUTO, I16_INHERIT, I16_INITIAL];
3639 for (i, a) in sentinels.iter().enumerate() {
3640 assert!(*a >= I16_SENTINEL_THRESHOLD);
3641 assert_eq!(decode_resolved_px_i16(*a), None);
3642 for b in &sentinels[i + 1..] {
3643 assert_ne!(a, b, "two i16 sentinels share a bit pattern");
3644 }
3645 }
3646 assert_eq!(decode_resolved_px_i16(I16_SENTINEL_THRESHOLD), None);
3647 assert_eq!(decode_resolved_px_i16(I16_SENTINEL_THRESHOLD - 1), Some(3276.3));
3648 }
3649
3650 #[test]
3651 fn resolved_px_i16_every_non_sentinel_value_roundtrips() {
3652 for v in i16::MIN..I16_SENTINEL_THRESHOLD {
3656 let px = decode_resolved_px_i16(v)
3657 .unwrap_or_else(|| panic!("{v} is below the threshold but decoded as a sentinel"));
3658 assert_eq!(
3659 encode_resolved_px_i16(px),
3660 v,
3661 "i16 {v} decoded to {px} px which re-encodes to a different i16",
3662 );
3663 }
3664 }
3665
3666 #[test]
3671 fn flex_u16_nan_infinity_and_negatives_are_defined_and_do_not_panic() {
3672 assert_eq!(encode_flex_u16(f32::NAN), 0);
3673 assert_eq!(encode_flex_u16(f32::INFINITY), U16_SENTINEL);
3674 assert_eq!(encode_flex_u16(f32::NEG_INFINITY), U16_SENTINEL);
3675 assert_eq!(encode_flex_u16(f32::MAX), U16_SENTINEL);
3676 assert_eq!(encode_flex_u16(-1.0), U16_SENTINEL);
3678 assert_eq!(encode_flex_u16(-0.01), U16_SENTINEL);
3679 assert_eq!(encode_flex_u16(-0.0), 0);
3681 assert_eq!(encode_flex_u16(0.0), 0);
3682 }
3683
3684 #[test]
3685 fn flex_u16_saturates_exactly_at_the_documented_range() {
3686 assert_eq!(encode_flex_u16(655.27), 65527);
3688 assert_eq!(decode_flex_u16(65527), Some(655.27));
3689 assert_eq!(encode_flex_u16(655.28), 65528);
3691 assert_eq!(encode_flex_u16(655.29), U16_SENTINEL);
3692 assert_eq!(encode_flex_u16(1e9), U16_SENTINEL);
3693 }
3694
3695 #[test]
3696 fn flex_u16_sentinel_band_decodes_to_none() {
3697 for v in U16_SENTINEL_THRESHOLD..=u16::MAX {
3698 assert_eq!(decode_flex_u16(v), None, "u16 {v} is reserved and must decode as None");
3699 }
3700 assert_eq!(U16_SENTINEL, u16::MAX);
3701 assert!(decode_flex_u16(U16_SENTINEL_THRESHOLD - 1).is_some());
3702 }
3703
3704 #[test]
3705 fn flex_u16_every_non_sentinel_value_roundtrips() {
3706 for v in 0..U16_SENTINEL_THRESHOLD {
3707 let f = decode_flex_u16(v).unwrap_or_else(|| panic!("{v} decoded as a sentinel"));
3708 assert_eq!(encode_flex_u16(f), v, "u16 {v} → {f} → re-encoded differently");
3709 }
3710 }
3711
3712 #[test]
3717 fn css_pixel_as_i16_maps_every_keyword_to_its_own_sentinel() {
3718 assert_eq!(
3719 encode_css_pixel_as_i16(&CssPropertyValue::Auto),
3720 I16_AUTO,
3721 );
3722 assert_eq!(
3723 encode_css_pixel_as_i16(&CssPropertyValue::Initial),
3724 I16_INITIAL,
3725 );
3726 assert_eq!(
3727 encode_css_pixel_as_i16(&CssPropertyValue::Inherit),
3728 I16_INHERIT,
3729 );
3730 assert_eq!(
3732 encode_css_pixel_as_i16(&CssPropertyValue::<PixelValue>::None),
3733 I16_SENTINEL,
3734 );
3735 assert_eq!(
3736 encode_css_pixel_as_i16(&CssPropertyValue::<PixelValue>::Revert),
3737 I16_SENTINEL,
3738 );
3739 assert_eq!(
3740 encode_css_pixel_as_i16(&CssPropertyValue::<PixelValue>::Unset),
3741 I16_SENTINEL,
3742 );
3743 }
3744
3745 #[test]
3746 fn css_pixel_as_i16_only_takes_the_fast_path_for_absolute_px() {
3747 assert_eq!(
3750 encode_css_pixel_as_i16(&CssPropertyValue::Exact(PixelValue::px(12.5))),
3751 125,
3752 );
3753 for metric in ALL_SIZE_METRIC {
3754 if metric == SizeMetric::Px {
3755 continue;
3756 }
3757 assert_eq!(
3758 encode_css_pixel_as_i16(&CssPropertyValue::Exact(pv_raw(metric, 12_500))),
3759 I16_SENTINEL,
3760 "{metric:?} needs resolution context and must not be pre-resolved",
3761 );
3762 }
3763 }
3764
3765 #[test]
3766 fn css_pixel_as_i16_out_of_range_px_escapes_to_the_sentinel() {
3767 assert_eq!(
3768 encode_css_pixel_as_i16(&CssPropertyValue::Exact(PixelValue::px(1e6))),
3769 I16_SENTINEL,
3770 );
3771 assert_eq!(
3772 encode_css_pixel_as_i16(&CssPropertyValue::Exact(PixelValue::px(-1e6))),
3773 I16_SENTINEL,
3774 );
3775 for raw in [I16_SENTINEL, I16_AUTO, I16_INHERIT, I16_INITIAL] {
3778 let px = f32::from(raw) / 10.0;
3779 assert_eq!(
3780 encode_css_pixel_as_i16(&CssPropertyValue::Exact(PixelValue::px(px))),
3781 I16_SENTINEL,
3782 "{px} px must not silently encode as the keyword sentinel {raw}",
3783 );
3784 }
3785 }
3786
3787 #[test]
3792 fn empty_cache_is_the_neutral_element() {
3793 let c = CompactLayoutCache::empty();
3794 assert_eq!(c.node_count(), 0);
3795 assert!(c.tier1_enums.is_empty());
3796 assert!(c.tier2_dims.is_empty());
3797 assert!(c.tier2_cold.is_empty());
3798 assert!(c.tier2b_text.is_empty());
3799 assert!(c.font_dirty_nodes.is_empty());
3800 assert!(c.prev_font_hashes.is_empty());
3801 assert!(c.font_hash_to_families.is_empty());
3802 assert_eq!(c.dom_declared_flags, 0);
3803 assert_eq!(CompactLayoutCache::with_capacity(0), c);
3805 }
3806
3807 #[test]
3808 fn with_capacity_keeps_every_tier_the_same_length() {
3809 for n in [0usize, 1, 2, 3, 17, 1024] {
3810 let c = CompactLayoutCache::with_capacity(n);
3811 assert_eq!(c.node_count(), n);
3812 assert_eq!(c.tier1_enums.len(), n);
3813 assert_eq!(c.tier2_dims.len(), n);
3814 assert_eq!(c.tier2_cold.len(), n);
3815 assert_eq!(c.tier2b_text.len(), n);
3816 assert_eq!(c.prev_font_hashes.len(), n);
3817 assert!(c.font_dirty_nodes.is_empty());
3819 assert_eq!(c.dom_declared_flags, 0);
3820 }
3821 }
3822
3823 #[test]
3824 fn freshly_allocated_node_reads_back_every_css_initial_value() {
3825 let c = CompactLayoutCache::with_capacity(3);
3829 for i in 0..3 {
3830 assert_eq!(T1::decode(c.tier1_enums[i]), T1::initial());
3831 assert_eq!(c.get_display(i), LayoutDisplay::Block);
3832 assert_eq!(c.get_position(i), LayoutPosition::Static);
3833 assert_eq!(c.get_float(i), LayoutFloat::None);
3834 assert_eq!(c.get_overflow_x(i), LayoutOverflow::Visible);
3835 assert_eq!(c.get_overflow_y(i), LayoutOverflow::Visible);
3836 assert_eq!(c.get_box_sizing(i), LayoutBoxSizing::ContentBox);
3837 assert_eq!(c.get_flex_direction(i), LayoutFlexDirection::Row);
3838 assert_eq!(c.get_flex_wrap(i), LayoutFlexWrap::NoWrap);
3839 assert_eq!(c.get_justify_content(i), LayoutJustifyContent::FlexStart);
3840 assert_eq!(c.get_align_items(i), LayoutAlignItems::Stretch);
3841 assert_eq!(c.get_align_content(i), LayoutAlignContent::Stretch);
3842 assert_eq!(c.get_writing_mode(i), LayoutWritingMode::HorizontalTb);
3843 assert_eq!(c.get_clear(i), LayoutClear::None);
3844 assert_eq!(c.get_font_weight(i), StyleFontWeight::Normal);
3845 assert_eq!(c.get_font_style(i), StyleFontStyle::Normal);
3846 assert_eq!(c.get_text_align(i), StyleTextAlign::Start);
3847 assert_eq!(c.get_visibility(i), StyleVisibility::Visible);
3848 assert_eq!(c.get_white_space(i), StyleWhiteSpace::Normal);
3849 assert_eq!(c.get_direction(i), StyleDirection::Ltr);
3850 assert_eq!(c.get_vertical_align(i), StyleVerticalAlign::Baseline);
3851 assert_eq!(c.get_border_collapse(i), StyleBorderCollapse::Separate);
3852
3853 assert_eq!(c.get_width_raw(i), U32_AUTO);
3855 assert_eq!(c.get_height_raw(i), U32_AUTO);
3856 assert_eq!(c.get_min_width_raw(i), U32_AUTO);
3857 assert_eq!(c.get_min_height_raw(i), U32_AUTO);
3858 assert_eq!(c.get_max_width_raw(i), U32_NONE);
3859 assert_eq!(c.get_max_height_raw(i), U32_NONE);
3860 assert_eq!(c.get_flex_basis_raw(i), U32_AUTO);
3861 assert_eq!(c.get_font_size_raw(i), U32_INITIAL);
3862 assert_eq!(decode_pixel_value_u32(c.get_width_raw(i)), None);
3863 assert_eq!(decode_pixel_value_u32(c.get_font_size_raw(i)), None);
3864
3865 assert_eq!(c.get_padding_top(i), Some(0.0));
3867 assert_eq!(c.get_padding_right(i), Some(0.0));
3868 assert_eq!(c.get_padding_bottom(i), Some(0.0));
3869 assert_eq!(c.get_padding_left(i), Some(0.0));
3870 assert_eq!(c.get_border_top_width(i), Some(0.0));
3871 assert_eq!(c.get_border_left_width(i), Some(0.0));
3872 assert_eq!(c.get_margin_top(i), Some(0.0));
3874 assert_eq!(c.get_margin_left(i), Some(0.0));
3875 assert!(!c.is_margin_top_auto(i));
3876 assert!(!c.is_margin_right_auto(i));
3877 assert!(!c.is_margin_bottom_auto(i));
3878 assert!(!c.is_margin_left_auto(i));
3879 assert_eq!(c.get_top(i), I16_AUTO);
3881 assert_eq!(c.get_right(i), I16_AUTO);
3882 assert_eq!(c.get_bottom(i), I16_AUTO);
3883 assert_eq!(c.get_left(i), I16_AUTO);
3884
3885 assert_eq!(c.get_flex_grow(i), Some(0.0));
3887 assert_eq!(c.get_flex_shrink(i), Some(1.0));
3888
3889 assert_eq!(c.get_z_index(i), I16_AUTO);
3891 assert_eq!(c.get_border_styles_packed(i), 0);
3892 assert_eq!(c.get_border_top_style(i), BorderStyle::None);
3893 assert_eq!(c.get_border_right_style(i), BorderStyle::None);
3894 assert_eq!(c.get_border_bottom_style(i), BorderStyle::None);
3895 assert_eq!(c.get_border_left_style(i), BorderStyle::None);
3896 assert_eq!(c.get_border_top_color_raw(i), 0);
3897 assert_eq!(decode_color_u32(c.get_border_top_color_raw(i)), None);
3898 assert_eq!(c.get_border_top_left_radius_raw(i), I16_SENTINEL);
3899 assert_eq!(c.get_tab_size_raw(i), I16_SENTINEL);
3900 assert_eq!(c.get_border_spacing_h_raw(i), 0);
3901 assert_eq!(c.get_border_spacing_v_raw(i), 0);
3902 assert_eq!(c.get_opacity_raw(i), OPACITY_SENTINEL);
3903 assert_eq!(c.get_hot_flags(i), 0);
3904 assert_eq!(c.get_scrollbar_gutter_bits(i), SCROLLBAR_GUTTER_AUTO);
3905
3906 assert!(!c.has_transform(i));
3909 assert!(!c.has_transform_origin(i));
3910 assert!(!c.has_box_shadow(i));
3911 assert!(!c.has_text_decoration(i));
3912 assert!(!c.has_background(i));
3913 assert!(!c.has_clip_path(i));
3914 assert!(!c.has_scrollbar_css(i));
3915 assert!(!c.has_counter(i));
3916 assert!(!c.has_break(i));
3917 assert!(!c.has_text_orientation(i));
3918 assert!(!c.has_text_shadow(i));
3919 assert!(!c.has_backdrop_filter(i));
3920 assert!(!c.has_filter(i));
3921 assert!(!c.has_mix_blend_mode(i));
3922
3923 assert_eq!(c.get_text_color_raw(i), 0);
3925 assert_eq!(c.get_font_family_hash(i), 0);
3926 assert_eq!(c.get_line_height(i), None); assert_eq!(c.get_letter_spacing(i), Some(0.0));
3928 assert_eq!(c.get_word_spacing(i), Some(0.0));
3929 assert_eq!(c.get_text_indent(i), Some(0.0));
3930 }
3931 }
3932
3933 #[test]
3934 fn hot_flag_predicates_read_only_their_own_bit() {
3935 let flags = [
3936 ("transform", HOT_FLAG_HAS_TRANSFORM),
3937 ("transform_origin", HOT_FLAG_HAS_TRANSFORM_ORIGIN),
3938 ("box_shadow", HOT_FLAG_HAS_BOX_SHADOW),
3939 ("text_decoration", HOT_FLAG_HAS_TEXT_DECORATION),
3940 ("background", HOT_FLAG_HAS_BACKGROUND),
3941 ("clip_path", HOT_FLAG_HAS_CLIP_PATH),
3942 ];
3943
3944 for (name, bit) in flags {
3945 let mut c = CompactLayoutCache::with_capacity(1);
3946 c.tier2_cold[0].hot_flags = bit;
3947
3948 let observed = [
3949 ("transform", c.has_transform(0)),
3950 ("transform_origin", c.has_transform_origin(0)),
3951 ("box_shadow", c.has_box_shadow(0)),
3952 ("text_decoration", c.has_text_decoration(0)),
3953 ("background", c.has_background(0)),
3954 ("clip_path", c.has_clip_path(0)),
3955 ];
3956 for (other, is_set) in observed {
3957 assert_eq!(
3958 is_set,
3959 other == name,
3960 "hot_flags = {bit:#010b}: has_{other}() should be {}",
3961 other == name,
3962 );
3963 }
3964 assert_eq!(c.get_scrollbar_gutter_bits(0), SCROLLBAR_GUTTER_AUTO);
3966 }
3967
3968 let mut seen = 0u8;
3970 for (_, bit) in flags {
3971 assert_eq!(seen & bit, 0, "two hot flags share bit {bit:#010b}");
3972 assert_eq!(
3973 bit & HOT_FLAG_SCROLLBAR_GUTTER_MASK,
3974 0,
3975 "hot flag {bit:#010b} overlaps the scrollbar-gutter field",
3976 );
3977 seen |= bit;
3978 }
3979 }
3980
3981 #[test]
3982 fn scrollbar_gutter_bits_survive_a_fully_set_hot_flags_byte() {
3983 for gutter in [
3984 SCROLLBAR_GUTTER_AUTO,
3985 SCROLLBAR_GUTTER_STABLE,
3986 SCROLLBAR_GUTTER_BOTH_EDGES,
3987 SCROLLBAR_GUTTER_MIRROR,
3988 ] {
3989 let mut c = CompactLayoutCache::with_capacity(1);
3990 c.tier2_cold[0].hot_flags = HOT_FLAG_HAS_TRANSFORM
3993 | HOT_FLAG_HAS_TRANSFORM_ORIGIN
3994 | HOT_FLAG_HAS_BOX_SHADOW
3995 | HOT_FLAG_HAS_TEXT_DECORATION
3996 | HOT_FLAG_HAS_BACKGROUND
3997 | HOT_FLAG_HAS_CLIP_PATH
3998 | (gutter << HOT_FLAG_SCROLLBAR_GUTTER_SHIFT);
3999
4000 assert_eq!(c.get_scrollbar_gutter_bits(0), gutter);
4001 assert!(c.has_transform(0));
4002 assert!(c.has_clip_path(0));
4003 }
4004
4005 let mut c = CompactLayoutCache::with_capacity(1);
4007 c.tier2_cold[0].hot_flags = u8::MAX;
4008 assert_eq!(c.get_scrollbar_gutter_bits(0), SCROLLBAR_GUTTER_MIRROR);
4009 assert!(c.get_scrollbar_gutter_bits(0) <= 3);
4010 }
4011
4012 #[test]
4013 fn extra_flag_predicates_read_only_their_own_bit() {
4014 let flags = [
4015 ("scrollbar_css", EXTRA_FLAG_HAS_SCROLLBAR_CSS),
4016 ("counter", EXTRA_FLAG_HAS_COUNTER),
4017 ("break", EXTRA_FLAG_HAS_BREAK),
4018 ("text_orientation", EXTRA_FLAG_HAS_TEXT_ORIENTATION),
4019 ("text_shadow", EXTRA_FLAG_HAS_TEXT_SHADOW),
4020 ("backdrop_filter", EXTRA_FLAG_HAS_BACKDROP_FILTER),
4021 ("filter", EXTRA_FLAG_HAS_FILTER),
4022 ("mix_blend_mode", EXTRA_FLAG_HAS_MIX_BLEND_MODE),
4023 ];
4024
4025 let mut seen = 0u8;
4027 for (_, bit) in flags {
4028 assert_eq!(seen & bit, 0, "two extra flags share bit {bit:#010b}");
4029 seen |= bit;
4030 }
4031 assert_eq!(seen, u8::MAX);
4032
4033 for (name, bit) in flags {
4034 let mut c = CompactLayoutCache::with_capacity(1);
4035 c.tier2_cold[0].extra_flags = bit;
4036 let observed = [
4037 ("scrollbar_css", c.has_scrollbar_css(0)),
4038 ("counter", c.has_counter(0)),
4039 ("break", c.has_break(0)),
4040 ("text_orientation", c.has_text_orientation(0)),
4041 ("text_shadow", c.has_text_shadow(0)),
4042 ("backdrop_filter", c.has_backdrop_filter(0)),
4043 ("filter", c.has_filter(0)),
4044 ("mix_blend_mode", c.has_mix_blend_mode(0)),
4045 ];
4046 for (other, is_set) in observed {
4047 assert_eq!(
4048 is_set,
4049 other == name,
4050 "extra_flags = {bit:#010b}: has_{other}() should be {}",
4051 other == name,
4052 );
4053 }
4054 assert!(!c.has_transform(0));
4056 assert!(!c.has_background(0));
4057 }
4058 }
4059
4060 #[test]
4061 fn dom_declared_flags_are_distinct_and_queryable() {
4062 let flags = [
4063 DOM_HAS_SHAPE_INSIDE,
4064 DOM_HAS_SHAPE_OUTSIDE,
4065 DOM_HAS_TEXT_JUSTIFY,
4066 DOM_HAS_TEXT_INDENT,
4067 DOM_HAS_COLUMN_COUNT,
4068 DOM_HAS_COLUMN_GAP,
4069 DOM_HAS_INITIAL_LETTER,
4070 DOM_HAS_INITIAL_LETTER_ALIGN,
4071 DOM_HAS_LINE_CLAMP,
4072 DOM_HAS_HANGING_PUNCTUATION,
4073 DOM_HAS_TEXT_COMBINE_UPRIGHT,
4074 DOM_HAS_EXCLUSION_MARGIN,
4075 DOM_HAS_HYPHENATION_LANGUAGE,
4076 DOM_HAS_UNICODE_BIDI,
4077 DOM_HAS_TEXT_BOX_TRIM,
4078 DOM_HAS_HYPHENS,
4079 DOM_HAS_WORD_BREAK,
4080 DOM_HAS_OVERFLOW_WRAP,
4081 DOM_HAS_LINE_BREAK,
4082 DOM_HAS_TEXT_ALIGN_LAST,
4083 DOM_HAS_LINE_HEIGHT,
4084 DOM_HAS_COLUMN_WIDTH,
4085 DOM_HAS_SHAPE_MARGIN,
4086 ];
4087
4088 let mut seen = 0u32;
4089 for f in flags {
4090 assert_eq!(f.count_ones(), 1, "{f:#X} is not a single-bit flag");
4091 assert_eq!(seen & f, 0, "two DOM_HAS_* flags share bit {f:#X}");
4092 seen |= f;
4093 }
4094
4095 let mut c = CompactLayoutCache::empty();
4096 for f in flags {
4098 assert!(!c.dom_declared(f));
4099 }
4100 assert!(!c.dom_declared(0));
4101 assert!(!c.dom_declared(u32::MAX));
4102
4103 c.dom_declared_flags = DOM_HAS_LINE_HEIGHT;
4105 for f in flags {
4106 assert_eq!(c.dom_declared(f), f == DOM_HAS_LINE_HEIGHT);
4107 }
4108 assert!(!c.dom_declared(0), "an empty flag query must never report declared");
4109 assert!(c.dom_declared(u32::MAX));
4110
4111 c.dom_declared_flags = u32::MAX;
4113 for f in flags {
4114 assert!(c.dom_declared(f));
4115 }
4116 }
4117
4118 #[test]
4119 fn getters_at_the_last_valid_index_do_not_panic() {
4120 let c = CompactLayoutCache::with_capacity(4);
4121 let last = c.node_count() - 1;
4122 let _ = c.get_display(last);
4123 let _ = c.get_width_raw(last);
4124 let _ = c.get_padding_top(last);
4125 let _ = c.get_z_index(last);
4126 let _ = c.get_border_top_style(last);
4127 let _ = c.get_line_height(last);
4128 let _ = c.has_transform(last);
4129 }
4130
4131 #[test]
4132 #[should_panic(expected = "index out of bounds")]
4133 fn tier1_getter_on_an_empty_cache_panics_rather_than_reading_oob() {
4134 let c = CompactLayoutCache::empty();
4135 let _ = c.get_display(0);
4136 }
4137
4138 #[test]
4139 #[should_panic(expected = "index out of bounds")]
4140 fn tier2_getter_past_the_end_panics_rather_than_reading_oob() {
4141 let c = CompactLayoutCache::with_capacity(2);
4142 let _ = c.get_padding_top(2);
4143 }
4144
4145 #[test]
4146 #[should_panic(expected = "index out of bounds")]
4147 fn cold_tier_getter_at_usize_max_panics_rather_than_wrapping() {
4148 let c = CompactLayoutCache::with_capacity(1);
4151 let _ = c.get_z_index(usize::MAX);
4152 }
4153
4154 #[test]
4155 #[should_panic(expected = "index out of bounds")]
4156 fn text_tier_getter_past_the_end_panics_rather_than_reading_oob() {
4157 let c = CompactLayoutCache::with_capacity(1);
4158 let _ = c.get_font_family_hash(1);
4159 }
4160
4161 #[test]
4166 fn compact_structs_stay_within_their_documented_byte_budget() {
4167 assert_eq!(size_of::<CompactNodeProps>(), 72);
4171 assert_eq!(size_of::<CompactNodePropsCold>(), 48);
4172 assert_eq!(size_of::<CompactTextProps>(), 24);
4173 assert_eq!(size_of::<u64>(), 8);
4175 assert_eq!(align_of::<CompactNodeProps>(), 4);
4177 assert_eq!(align_of::<CompactNodePropsCold>(), 4);
4178 assert_eq!(align_of::<CompactTextProps>(), 8);
4179 }
4180}