1use crate::parser::{Parse, ParserContext};
8use crate::properties::{LonghandId, PropertyDeclarationId, PropertyId};
9use crate::values::generics::box_::{
10 GenericContainIntrinsicSize, GenericLineClamp, GenericPerspective, GenericVerticalAlign,
11 VerticalAlignKeyword,
12};
13use crate::values::specified::length::{LengthPercentage, NonNegativeLength};
14use crate::values::specified::{AllowQuirks, Integer, NonNegativeNumberOrPercentage};
15use crate::values::CustomIdent;
16pub use crate::logical_geometry::WritingModeProperty;
17use cssparser::Parser;
18use num_traits::FromPrimitive;
19use std::fmt::{self, Write};
20use style_traits::{CssWriter, KeywordsCollectFn, ParseError};
21use style_traits::{SpecifiedValueInfo, StyleParseErrorKind, ToCss};
22
23#[cfg(not(feature = "servo"))]
24fn grid_enabled() -> bool {
25 true
26}
27
28#[cfg(feature = "servo")]
29fn grid_enabled() -> bool {
30 style_config::get_bool("layout.grid.enabled")
31}
32
33#[allow(missing_docs)]
37#[derive(Clone, Copy, Debug, Eq, FromPrimitive, Hash, MallocSizeOf, PartialEq, ToCss, ToShmem)]
38#[repr(u8)]
39pub enum DisplayOutside {
40 None = 0,
41 Inline,
42 Block,
43 TableCaption,
44 InternalTable,
45 #[cfg(feature = "gecko")]
46 InternalRuby,
47}
48
49#[allow(missing_docs)]
50#[derive(Clone, Copy, Debug, Eq, FromPrimitive, Hash, MallocSizeOf, PartialEq, ToCss, ToShmem)]
51#[repr(u8)]
52pub enum DisplayInside {
53 None = 0,
54 Contents,
55 Flow,
56 FlowRoot,
57 Flex,
58 Grid,
59 Table,
60 TableRowGroup,
61 TableColumn,
62 TableColumnGroup,
63 TableHeaderGroup,
64 TableFooterGroup,
65 TableRow,
66 TableCell,
67 #[cfg(feature = "gecko")]
68 Ruby,
69 #[cfg(feature = "gecko")]
70 RubyBase,
71 #[cfg(feature = "gecko")]
72 RubyBaseContainer,
73 #[cfg(feature = "gecko")]
74 RubyText,
75 #[cfg(feature = "gecko")]
76 RubyTextContainer,
77 #[cfg(feature = "gecko")]
78 WebkitBox,
79}
80
81impl DisplayInside {
82 fn is_valid_for_list_item(self) -> bool {
83 match self {
84 DisplayInside::Flow => true,
85 #[cfg(feature = "gecko")]
86 DisplayInside::FlowRoot => true,
87 _ => false,
88 }
89 }
90
91 fn default_display_outside(self) -> DisplayOutside {
95 match self {
96 #[cfg(feature = "gecko")]
97 DisplayInside::Ruby => DisplayOutside::Inline,
98 _ => DisplayOutside::Block,
99 }
100 }
101}
102
103#[allow(missing_docs)]
104#[derive(
105 Clone,
106 Copy,
107 Debug,
108 Eq,
109 FromPrimitive,
110 Hash,
111 MallocSizeOf,
112 PartialEq,
113 ToComputedValue,
114 ToResolvedValue,
115 ToShmem,
116)]
117#[repr(C)]
118pub struct Display(u16);
119
120#[allow(missing_docs)]
122#[allow(non_upper_case_globals)]
123impl Display {
124 pub const LIST_ITEM_MASK: u16 = 0b1000000000000000;
126 pub const OUTSIDE_MASK: u16 = 0b0111111100000000;
127 pub const INSIDE_MASK: u16 = 0b0000000011111111;
128 pub const OUTSIDE_SHIFT: u16 = 8;
129
130 pub const None: Self =
133 Self(((DisplayOutside::None as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::None as u16);
134 pub const Contents: Self = Self(
135 ((DisplayOutside::None as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Contents as u16,
136 );
137 pub const Inline: Self =
138 Self(((DisplayOutside::Inline as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Flow as u16);
139 pub const InlineBlock: Self = Self(
140 ((DisplayOutside::Inline as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::FlowRoot as u16,
141 );
142 pub const Block: Self =
143 Self(((DisplayOutside::Block as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Flow as u16);
144 #[cfg(feature = "gecko")]
145 pub const FlowRoot: Self = Self(
146 ((DisplayOutside::Block as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::FlowRoot as u16,
147 );
148 pub const Flex: Self =
149 Self(((DisplayOutside::Block as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Flex as u16);
150 pub const InlineFlex: Self =
151 Self(((DisplayOutside::Inline as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Flex as u16);
152 pub const Grid: Self =
153 Self(((DisplayOutside::Block as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Grid as u16);
154 pub const InlineGrid: Self =
155 Self(((DisplayOutside::Inline as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Grid as u16);
156 pub const Table: Self =
157 Self(((DisplayOutside::Block as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Table as u16);
158 pub const InlineTable: Self = Self(
159 ((DisplayOutside::Inline as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Table as u16,
160 );
161 pub const TableCaption: Self = Self(
162 ((DisplayOutside::TableCaption as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Flow as u16,
163 );
164 #[cfg(feature = "gecko")]
165 pub const Ruby: Self =
166 Self(((DisplayOutside::Inline as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Ruby as u16);
167 #[cfg(feature = "gecko")]
168 pub const WebkitBox: Self = Self(
169 ((DisplayOutside::Block as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::WebkitBox as u16,
170 );
171 #[cfg(feature = "gecko")]
172 pub const WebkitInlineBox: Self = Self(
173 ((DisplayOutside::Inline as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::WebkitBox as u16,
174 );
175
176 pub const TableRowGroup: Self = Self(
179 ((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT) |
180 DisplayInside::TableRowGroup as u16,
181 );
182 pub const TableHeaderGroup: Self = Self(
183 ((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT) |
184 DisplayInside::TableHeaderGroup as u16,
185 );
186 pub const TableFooterGroup: Self = Self(
187 ((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT) |
188 DisplayInside::TableFooterGroup as u16,
189 );
190 pub const TableColumn: Self = Self(
191 ((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT) |
192 DisplayInside::TableColumn as u16,
193 );
194 pub const TableColumnGroup: Self = Self(
195 ((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT) |
196 DisplayInside::TableColumnGroup as u16,
197 );
198 pub const TableRow: Self = Self(
199 ((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT) |
200 DisplayInside::TableRow as u16,
201 );
202 pub const TableCell: Self = Self(
203 ((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT) |
204 DisplayInside::TableCell as u16,
205 );
206
207 #[cfg(feature = "gecko")]
209 pub const RubyBase: Self = Self(
210 ((DisplayOutside::InternalRuby as u16) << Self::OUTSIDE_SHIFT) |
211 DisplayInside::RubyBase as u16,
212 );
213 #[cfg(feature = "gecko")]
214 pub const RubyBaseContainer: Self = Self(
215 ((DisplayOutside::InternalRuby as u16) << Self::OUTSIDE_SHIFT) |
216 DisplayInside::RubyBaseContainer as u16,
217 );
218 #[cfg(feature = "gecko")]
219 pub const RubyText: Self = Self(
220 ((DisplayOutside::InternalRuby as u16) << Self::OUTSIDE_SHIFT) |
221 DisplayInside::RubyText as u16,
222 );
223 #[cfg(feature = "gecko")]
224 pub const RubyTextContainer: Self = Self(
225 ((DisplayOutside::InternalRuby as u16) << Self::OUTSIDE_SHIFT) |
226 DisplayInside::RubyTextContainer as u16,
227 );
228
229 #[inline]
231 const fn new(outside: DisplayOutside, inside: DisplayInside) -> Self {
232 Self((outside as u16) << Self::OUTSIDE_SHIFT | inside as u16)
233 }
234
235 #[inline]
237 fn from3(outside: DisplayOutside, inside: DisplayInside, list_item: bool) -> Self {
238 let v = Self::new(outside, inside);
239 if !list_item {
240 return v;
241 }
242 Self(v.0 | Self::LIST_ITEM_MASK)
243 }
244
245 #[inline]
247 pub fn inside(&self) -> DisplayInside {
248 DisplayInside::from_u16(self.0 & Self::INSIDE_MASK).unwrap()
249 }
250
251 #[inline]
253 pub fn outside(&self) -> DisplayOutside {
254 DisplayOutside::from_u16((self.0 & Self::OUTSIDE_MASK) >> Self::OUTSIDE_SHIFT).unwrap()
255 }
256
257 #[inline]
259 pub const fn to_u16(&self) -> u16 {
260 self.0
261 }
262
263 #[inline]
265 pub fn is_inline_flow(&self) -> bool {
266 self.outside() == DisplayOutside::Inline && self.inside() == DisplayInside::Flow
267 }
268
269 #[inline]
271 pub const fn is_list_item(&self) -> bool {
272 (self.0 & Self::LIST_ITEM_MASK) != 0
273 }
274
275 pub fn is_ruby_level_container(&self) -> bool {
277 match *self {
278 #[cfg(feature = "gecko")]
279 Display::RubyBaseContainer | Display::RubyTextContainer => true,
280 _ => false,
281 }
282 }
283
284 pub fn is_ruby_type(&self) -> bool {
286 match self.inside() {
287 #[cfg(feature = "gecko")]
288 DisplayInside::Ruby |
289 DisplayInside::RubyBase |
290 DisplayInside::RubyText |
291 DisplayInside::RubyBaseContainer |
292 DisplayInside::RubyTextContainer => true,
293 _ => false,
294 }
295 }
296}
297
298impl Display {
300 #[inline]
302 pub fn inline() -> Self {
303 Display::Inline
304 }
305
306 pub fn is_item_container(&self) -> bool {
311 match self.inside() {
312 DisplayInside::Flex => true,
313 DisplayInside::Grid => true,
314 _ => false,
315 }
316 }
317
318 pub fn is_line_participant(&self) -> bool {
322 if self.is_inline_flow() {
323 return true;
324 }
325 match *self {
326 #[cfg(feature = "gecko")]
327 Display::Contents | Display::Ruby | Display::RubyBaseContainer => true,
328 _ => false,
329 }
330 }
331
332 pub fn equivalent_block_display(&self, _is_root_element: bool) -> Self {
336 {
337 if _is_root_element && (self.is_contents() || self.is_list_item()) {
339 return Display::Block;
340 }
341 }
342
343 match self.outside() {
344 DisplayOutside::Inline => {
345 let inside = match self.inside() {
346 DisplayInside::FlowRoot => DisplayInside::Flow,
349 inside => inside,
350 };
351 Display::from3(DisplayOutside::Block, inside, self.is_list_item())
352 },
353 DisplayOutside::Block | DisplayOutside::None => *self,
354 _ => Display::Block,
355 }
356 }
357
358 #[cfg(feature = "gecko")]
361 pub fn inlinify(&self) -> Self {
362 match self.outside() {
363 DisplayOutside::Block => {
364 let inside = match self.inside() {
365 DisplayInside::Flow => DisplayInside::FlowRoot,
368 inside => inside,
369 };
370 Display::from3(DisplayOutside::Inline, inside, self.is_list_item())
371 },
372 _ => *self,
373 }
374 }
375
376 #[inline]
378 pub fn is_contents(&self) -> bool {
379 match *self {
380 Display::Contents => true,
381 _ => false,
382 }
383 }
384
385 #[inline]
387 pub fn is_none(&self) -> bool {
388 *self == Display::None
389 }
390}
391
392enum DisplayKeyword {
393 Full(Display),
394 Inside(DisplayInside),
395 Outside(DisplayOutside),
396 ListItem,
397}
398
399impl DisplayKeyword {
400 fn parse<'i>(input: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
401 use self::DisplayKeyword::*;
402 Ok(try_match_ident_ignore_ascii_case! { input,
403 "none" => Full(Display::None),
404 "contents" => Full(Display::Contents),
405 "inline-block" => Full(Display::InlineBlock),
406 "inline-table" => Full(Display::InlineTable),
407 "-webkit-flex" => Full(Display::Flex),
408 "inline-flex" | "-webkit-inline-flex" => Full(Display::InlineFlex),
409 "inline-grid" if grid_enabled() => Full(Display::InlineGrid),
410 "table-caption" => Full(Display::TableCaption),
411 "table-row-group" => Full(Display::TableRowGroup),
412 "table-header-group" => Full(Display::TableHeaderGroup),
413 "table-footer-group" => Full(Display::TableFooterGroup),
414 "table-column" => Full(Display::TableColumn),
415 "table-column-group" => Full(Display::TableColumnGroup),
416 "table-row" => Full(Display::TableRow),
417 "table-cell" => Full(Display::TableCell),
418 #[cfg(feature = "gecko")]
419 "ruby-base" => Full(Display::RubyBase),
420 #[cfg(feature = "gecko")]
421 "ruby-base-container" => Full(Display::RubyBaseContainer),
422 #[cfg(feature = "gecko")]
423 "ruby-text" => Full(Display::RubyText),
424 #[cfg(feature = "gecko")]
425 "ruby-text-container" => Full(Display::RubyTextContainer),
426 #[cfg(feature = "gecko")]
427 "-webkit-box" => Full(Display::WebkitBox),
428 #[cfg(feature = "gecko")]
429 "-webkit-inline-box" => Full(Display::WebkitInlineBox),
430
431 "block" => Outside(DisplayOutside::Block),
434 "inline" => Outside(DisplayOutside::Inline),
435
436 "list-item" => ListItem,
437
438 "flow" => Inside(DisplayInside::Flow),
441 "flex" => Inside(DisplayInside::Flex),
442 "flow-root" => Inside(DisplayInside::FlowRoot),
443 "table" => Inside(DisplayInside::Table),
444 "grid" if grid_enabled() => Inside(DisplayInside::Grid),
445 #[cfg(feature = "gecko")]
446 "ruby" => Inside(DisplayInside::Ruby),
447 })
448 }
449}
450
451impl ToCss for Display {
452 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
453 where
454 W: fmt::Write,
455 {
456 let outside = self.outside();
457 let inside = self.inside();
458 match *self {
459 Display::Block | Display::Inline => outside.to_css(dest),
460 Display::InlineBlock => dest.write_str("inline-block"),
461 #[cfg(feature = "gecko")]
462 Display::WebkitInlineBox => dest.write_str("-webkit-inline-box"),
463 Display::TableCaption => dest.write_str("table-caption"),
464 _ => match (outside, inside) {
465 (DisplayOutside::Inline, DisplayInside::Grid) => dest.write_str("inline-grid"),
466 (DisplayOutside::Inline, DisplayInside::Flex) => dest.write_str("inline-flex"),
467 (DisplayOutside::Inline, DisplayInside::Table) => dest.write_str("inline-table"),
468 #[cfg(feature = "gecko")]
469 (DisplayOutside::Block, DisplayInside::Ruby) => dest.write_str("block ruby"),
470 (_, inside) => {
471 if self.is_list_item() {
472 if outside != DisplayOutside::Block {
473 outside.to_css(dest)?;
474 dest.write_char(' ')?;
475 }
476 if inside != DisplayInside::Flow {
477 inside.to_css(dest)?;
478 dest.write_char(' ')?;
479 }
480 dest.write_str("list-item")
481 } else {
482 inside.to_css(dest)
483 }
484 },
485 },
486 }
487 }
488}
489
490impl Parse for Display {
491 fn parse<'i, 't>(
492 _: &ParserContext,
493 input: &mut Parser<'i, 't>,
494 ) -> Result<Display, ParseError<'i>> {
495 let mut got_list_item = false;
496 let mut inside = None;
497 let mut outside = None;
498 match DisplayKeyword::parse(input)? {
499 DisplayKeyword::Full(d) => return Ok(d),
500 DisplayKeyword::Outside(o) => {
501 outside = Some(o);
502 },
503 DisplayKeyword::Inside(i) => {
504 inside = Some(i);
505 },
506 DisplayKeyword::ListItem => {
507 got_list_item = true;
508 },
509 };
510
511 while let Ok(kw) = input.try_parse(DisplayKeyword::parse) {
512 match kw {
513 DisplayKeyword::ListItem if !got_list_item => {
514 got_list_item = true;
515 },
516 DisplayKeyword::Outside(o) if outside.is_none() => {
517 outside = Some(o);
518 },
519 DisplayKeyword::Inside(i) if inside.is_none() => {
520 inside = Some(i);
521 },
522 _ => return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)),
523 }
524 }
525
526 let inside = inside.unwrap_or(DisplayInside::Flow);
527 let outside = outside.unwrap_or_else(|| inside.default_display_outside());
528 if got_list_item && !inside.is_valid_for_list_item() {
529 return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
530 }
531
532 return Ok(Display::from3(outside, inside, got_list_item));
533 }
534}
535
536impl SpecifiedValueInfo for Display {
537 fn collect_completion_keywords(f: KeywordsCollectFn) {
538 f(&[
539 "block",
540 "contents",
541 "flex",
542 "flow-root",
543 "flow-root list-item",
544 "grid",
545 "inline",
546 "inline-block",
547 "inline-flex",
548 "inline-grid",
549 "inline-table",
550 "inline list-item",
551 "inline flow-root list-item",
552 "list-item",
553 "none",
554 "block ruby",
555 "ruby",
556 "ruby-base",
557 "ruby-base-container",
558 "ruby-text",
559 "ruby-text-container",
560 "table",
561 "table-caption",
562 "table-cell",
563 "table-column",
564 "table-column-group",
565 "table-footer-group",
566 "table-header-group",
567 "table-row",
568 "table-row-group",
569 "-webkit-box",
570 "-webkit-inline-box",
571 ]);
572 }
573}
574
575pub type ContainIntrinsicSize = GenericContainIntrinsicSize<NonNegativeLength>;
577
578pub type LineClamp = GenericLineClamp<Integer>;
580
581pub type VerticalAlign = GenericVerticalAlign<LengthPercentage>;
583
584impl Parse for VerticalAlign {
585 fn parse<'i, 't>(
586 context: &ParserContext,
587 input: &mut Parser<'i, 't>,
588 ) -> Result<Self, ParseError<'i>> {
589 if let Ok(lp) =
590 input.try_parse(|i| LengthPercentage::parse_quirky(context, i, AllowQuirks::Yes))
591 {
592 return Ok(GenericVerticalAlign::Length(lp));
593 }
594
595 Ok(GenericVerticalAlign::Keyword(VerticalAlignKeyword::parse(
596 input,
597 )?))
598 }
599}
600
601#[derive(
604 Clone,
605 Copy,
606 Debug,
607 Eq,
608 Hash,
609 MallocSizeOf,
610 Parse,
611 PartialEq,
612 SpecifiedValueInfo,
613 ToCss,
614 ToShmem,
615 ToComputedValue,
616 ToResolvedValue,
617)]
618#[repr(u8)]
619pub enum BaselineSource {
620 Auto,
622 First,
624 Last,
626}
627
628#[allow(missing_docs)]
630#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
631#[derive(
632 Clone,
633 Copy,
634 Debug,
635 Eq,
636 MallocSizeOf,
637 Parse,
638 PartialEq,
639 SpecifiedValueInfo,
640 ToComputedValue,
641 ToCss,
642 ToResolvedValue,
643 ToShmem,
644)]
645#[repr(u8)]
646pub enum ScrollSnapAxis {
647 X,
648 Y,
649 Block,
650 Inline,
651 Both,
652}
653
654#[allow(missing_docs)]
656#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
657#[derive(
658 Clone,
659 Copy,
660 Debug,
661 Eq,
662 MallocSizeOf,
663 Parse,
664 PartialEq,
665 SpecifiedValueInfo,
666 ToComputedValue,
667 ToCss,
668 ToResolvedValue,
669 ToShmem,
670)]
671#[repr(u8)]
672pub enum ScrollSnapStrictness {
673 #[css(skip)]
674 None, Mandatory,
676 Proximity,
677}
678
679#[allow(missing_docs)]
681#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
682#[derive(
683 Clone,
684 Copy,
685 Debug,
686 Eq,
687 MallocSizeOf,
688 PartialEq,
689 SpecifiedValueInfo,
690 ToComputedValue,
691 ToResolvedValue,
692 ToShmem,
693)]
694#[repr(C)]
695pub struct ScrollSnapType {
696 axis: ScrollSnapAxis,
697 strictness: ScrollSnapStrictness,
698}
699
700impl ScrollSnapType {
701 #[inline]
703 pub fn none() -> Self {
704 Self {
705 axis: ScrollSnapAxis::Both,
706 strictness: ScrollSnapStrictness::None,
707 }
708 }
709}
710
711impl Parse for ScrollSnapType {
712 fn parse<'i, 't>(
714 _context: &ParserContext,
715 input: &mut Parser<'i, 't>,
716 ) -> Result<Self, ParseError<'i>> {
717 if input
718 .try_parse(|input| input.expect_ident_matching("none"))
719 .is_ok()
720 {
721 return Ok(ScrollSnapType::none());
722 }
723
724 let axis = ScrollSnapAxis::parse(input)?;
725 let strictness = input
726 .try_parse(ScrollSnapStrictness::parse)
727 .unwrap_or(ScrollSnapStrictness::Proximity);
728 Ok(Self { axis, strictness })
729 }
730}
731
732impl ToCss for ScrollSnapType {
733 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
734 where
735 W: Write,
736 {
737 if self.strictness == ScrollSnapStrictness::None {
738 return dest.write_str("none");
739 }
740 self.axis.to_css(dest)?;
741 if self.strictness != ScrollSnapStrictness::Proximity {
742 dest.write_char(' ')?;
743 self.strictness.to_css(dest)?;
744 }
745 Ok(())
746 }
747}
748
749#[allow(missing_docs)]
751#[derive(
752 Clone,
753 Copy,
754 Debug,
755 Eq,
756 FromPrimitive,
757 Hash,
758 MallocSizeOf,
759 Parse,
760 PartialEq,
761 SpecifiedValueInfo,
762 ToComputedValue,
763 ToCss,
764 ToResolvedValue,
765 ToShmem,
766)]
767#[repr(u8)]
768pub enum ScrollSnapAlignKeyword {
769 None,
770 Start,
771 End,
772 Center,
773}
774
775#[allow(missing_docs)]
777#[derive(
778 Clone,
779 Copy,
780 Debug,
781 Eq,
782 MallocSizeOf,
783 PartialEq,
784 SpecifiedValueInfo,
785 ToComputedValue,
786 ToResolvedValue,
787 ToShmem,
788)]
789#[repr(C)]
790pub struct ScrollSnapAlign {
791 block: ScrollSnapAlignKeyword,
792 inline: ScrollSnapAlignKeyword,
793}
794
795impl ScrollSnapAlign {
796 #[inline]
798 pub fn none() -> Self {
799 ScrollSnapAlign {
800 block: ScrollSnapAlignKeyword::None,
801 inline: ScrollSnapAlignKeyword::None,
802 }
803 }
804}
805
806impl Parse for ScrollSnapAlign {
807 fn parse<'i, 't>(
809 _context: &ParserContext,
810 input: &mut Parser<'i, 't>,
811 ) -> Result<ScrollSnapAlign, ParseError<'i>> {
812 let block = ScrollSnapAlignKeyword::parse(input)?;
813 let inline = input
814 .try_parse(ScrollSnapAlignKeyword::parse)
815 .unwrap_or(block);
816 Ok(ScrollSnapAlign { block, inline })
817 }
818}
819
820impl ToCss for ScrollSnapAlign {
821 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
822 where
823 W: Write,
824 {
825 self.block.to_css(dest)?;
826 if self.block != self.inline {
827 dest.write_char(' ')?;
828 self.inline.to_css(dest)?;
829 }
830 Ok(())
831 }
832}
833
834#[allow(missing_docs)]
835#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
836#[derive(
837 Clone,
838 Copy,
839 Debug,
840 Eq,
841 MallocSizeOf,
842 Parse,
843 PartialEq,
844 SpecifiedValueInfo,
845 ToComputedValue,
846 ToCss,
847 ToResolvedValue,
848 ToShmem,
849)]
850#[repr(u8)]
851pub enum ScrollSnapStop {
852 Normal,
853 Always,
854}
855
856#[allow(missing_docs)]
857#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
858#[derive(
859 Clone,
860 Copy,
861 Debug,
862 Eq,
863 MallocSizeOf,
864 Parse,
865 PartialEq,
866 SpecifiedValueInfo,
867 ToComputedValue,
868 ToCss,
869 ToResolvedValue,
870 ToShmem,
871)]
872#[repr(u8)]
873pub enum OverscrollBehavior {
874 Auto,
875 Contain,
876 None,
877}
878
879#[allow(missing_docs)]
880#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
881#[derive(
882 Clone,
883 Copy,
884 Debug,
885 Eq,
886 MallocSizeOf,
887 Parse,
888 PartialEq,
889 SpecifiedValueInfo,
890 ToComputedValue,
891 ToCss,
892 ToResolvedValue,
893 ToShmem,
894)]
895#[repr(u8)]
896pub enum OverflowAnchor {
897 Auto,
898 None,
899}
900
901#[allow(missing_docs)]
902#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
903#[derive(
904 Clone,
905 Copy,
906 Debug,
907 Eq,
908 MallocSizeOf,
909 Parse,
910 PartialEq,
911 SpecifiedValueInfo,
912 ToComputedValue,
913 ToCss,
914 ToResolvedValue,
915 ToShmem,
916)]
917#[repr(u8)]
918pub enum OverflowClipBox {
919 PaddingBox,
920 ContentBox,
921}
922
923#[derive(
924 Clone,
925 Debug,
926 Default,
927 MallocSizeOf,
928 PartialEq,
929 SpecifiedValueInfo,
930 ToComputedValue,
931 ToCss,
932 ToResolvedValue,
933 ToShmem,
934)]
935#[css(comma)]
936#[repr(C)]
937pub struct WillChange {
944 #[css(iterable, if_empty = "auto")]
949 features: crate::OwnedSlice<CustomIdent>,
950 #[css(skip)]
953 pub bits: WillChangeBits,
954}
955
956impl WillChange {
957 #[inline]
958 pub fn auto() -> Self {
960 Self::default()
961 }
962}
963
964#[derive(
966 Clone,
967 Copy,
968 Debug,
969 Default,
970 Eq,
971 MallocSizeOf,
972 PartialEq,
973 SpecifiedValueInfo,
974 ToComputedValue,
975 ToResolvedValue,
976 ToShmem,
977)]
978#[repr(C)]
979pub struct WillChangeBits(u16);
980bitflags! {
981 impl WillChangeBits: u16 {
982 const STACKING_CONTEXT_UNCONDITIONAL = 1 << 0;
985 const TRANSFORM = 1 << 1;
987 const SCROLL = 1 << 2;
989 const CONTAIN = 1 << 3;
991 const OPACITY = 1 << 4;
993 const PERSPECTIVE = 1 << 5;
995 const Z_INDEX = 1 << 6;
997 const FIXPOS_CB_NON_SVG = 1 << 7;
1000 const POSITION = 1 << 8;
1002 const VIEW_TRANSITION_NAME = 1 << 9;
1004 const BACKDROP_ROOT = 1 << 10;
1007 }
1008}
1009
1010fn change_bits_for_longhand(longhand: LonghandId) -> WillChangeBits {
1011 match longhand {
1012 LonghandId::Opacity => {
1013 WillChangeBits::OPACITY | WillChangeBits::BACKDROP_ROOT
1014 },
1015 LonghandId::Contain => WillChangeBits::CONTAIN,
1016 LonghandId::Perspective => WillChangeBits::PERSPECTIVE,
1017 LonghandId::Position => {
1018 WillChangeBits::STACKING_CONTEXT_UNCONDITIONAL | WillChangeBits::POSITION
1019 },
1020 LonghandId::ZIndex => WillChangeBits::Z_INDEX,
1021 LonghandId::Transform |
1022 LonghandId::TransformStyle |
1023 LonghandId::Translate |
1024 LonghandId::Rotate |
1025 LonghandId::Scale |
1026 LonghandId::OffsetPath => WillChangeBits::TRANSFORM,
1027 LonghandId::Filter | LonghandId::BackdropFilter => {
1028 WillChangeBits::STACKING_CONTEXT_UNCONDITIONAL |
1029 WillChangeBits::BACKDROP_ROOT |
1030 WillChangeBits::FIXPOS_CB_NON_SVG
1031 },
1032 LonghandId::ViewTransitionName => {
1033 WillChangeBits::VIEW_TRANSITION_NAME |
1034 WillChangeBits::BACKDROP_ROOT
1035 },
1036 LonghandId::MixBlendMode => {
1037 WillChangeBits::STACKING_CONTEXT_UNCONDITIONAL |
1038 WillChangeBits::BACKDROP_ROOT
1039 },
1040 LonghandId::Isolation |
1041 LonghandId::MaskImage => WillChangeBits::STACKING_CONTEXT_UNCONDITIONAL,
1042 LonghandId::ClipPath => {
1043 WillChangeBits::STACKING_CONTEXT_UNCONDITIONAL |
1044 WillChangeBits::BACKDROP_ROOT
1045 },
1046 _ => WillChangeBits::empty(),
1047 }
1048}
1049
1050fn change_bits_for_maybe_property(ident: &str, context: &ParserContext) -> WillChangeBits {
1051 let id = match PropertyId::parse_ignoring_rule_type(ident, context) {
1052 Ok(id) => id,
1053 Err(..) => return WillChangeBits::empty(),
1054 };
1055
1056 match id.as_shorthand() {
1057 Ok(shorthand) => shorthand
1058 .longhands()
1059 .fold(WillChangeBits::empty(), |flags, p| {
1060 flags | change_bits_for_longhand(p)
1061 }),
1062 Err(PropertyDeclarationId::Longhand(longhand)) => change_bits_for_longhand(longhand),
1063 Err(PropertyDeclarationId::Custom(..)) => WillChangeBits::empty(),
1064 }
1065}
1066
1067impl Parse for WillChange {
1068 fn parse<'i, 't>(
1070 context: &ParserContext,
1071 input: &mut Parser<'i, 't>,
1072 ) -> Result<Self, ParseError<'i>> {
1073 if input
1074 .try_parse(|input| input.expect_ident_matching("auto"))
1075 .is_ok()
1076 {
1077 return Ok(Self::default());
1078 }
1079
1080 let mut bits = WillChangeBits::empty();
1081 let custom_idents = input.parse_comma_separated(|i| {
1082 let location = i.current_source_location();
1083 let parser_ident = i.expect_ident()?;
1084 let ident = CustomIdent::from_ident(
1085 location,
1086 parser_ident,
1087 &["will-change", "none", "all", "auto"],
1088 )?;
1089
1090 if context.in_ua_sheet() && ident.0 == atom!("-moz-fixed-pos-containing-block") {
1091 bits |= WillChangeBits::FIXPOS_CB_NON_SVG;
1092 } else if ident.0 == atom!("scroll-position") {
1093 bits |= WillChangeBits::SCROLL;
1094 } else {
1095 bits |= change_bits_for_maybe_property(&parser_ident, context);
1096 }
1097 Ok(ident)
1098 })?;
1099
1100 Ok(Self {
1101 features: custom_idents.into(),
1102 bits,
1103 })
1104 }
1105}
1106
1107#[derive(
1109 Clone,
1110 Copy,
1111 Debug,
1112 Eq,
1113 MallocSizeOf,
1114 Parse,
1115 PartialEq,
1116 SpecifiedValueInfo,
1117 ToComputedValue,
1118 ToCss,
1119 ToResolvedValue,
1120 ToShmem,
1121)]
1122#[css(bitflags(single = "none,auto,manipulation", mixed = "pan-x,pan-y,pinch-zoom"))]
1123#[repr(C)]
1124pub struct TouchAction(u8);
1125bitflags! {
1126 impl TouchAction: u8 {
1127 const NONE = 1 << 0;
1129 const AUTO = 1 << 1;
1131 const PAN_X = 1 << 2;
1133 const PAN_Y = 1 << 3;
1135 const MANIPULATION = 1 << 4;
1137 const PINCH_ZOOM = 1 << 5;
1139 }
1140}
1141
1142impl TouchAction {
1143 #[inline]
1144 pub fn auto() -> TouchAction {
1146 TouchAction::AUTO
1147 }
1148}
1149
1150#[derive(
1151 Clone,
1152 Copy,
1153 Debug,
1154 Eq,
1155 MallocSizeOf,
1156 Parse,
1157 PartialEq,
1158 SpecifiedValueInfo,
1159 ToComputedValue,
1160 ToCss,
1161 ToResolvedValue,
1162 ToShmem,
1163)]
1164#[css(bitflags(
1165 single = "none,strict,content",
1166 mixed = "size,layout,style,paint,inline-size",
1167 overlapping_bits
1168))]
1169#[repr(C)]
1170pub struct Contain(u8);
1172bitflags! {
1173 impl Contain: u8 {
1174 const NONE = 0;
1176 const INLINE_SIZE = 1 << 0;
1178 const BLOCK_SIZE = 1 << 1;
1180 const LAYOUT = 1 << 2;
1182 const STYLE = 1 << 3;
1184 const PAINT = 1 << 4;
1186 const SIZE = 1 << 5 | Contain::INLINE_SIZE.bits() | Contain::BLOCK_SIZE.bits();
1188 const CONTENT = 1 << 6 | Contain::LAYOUT.bits() | Contain::STYLE.bits() | Contain::PAINT.bits();
1190 const STRICT = 1 << 7 | Contain::LAYOUT.bits() | Contain::STYLE.bits() | Contain::PAINT.bits() | Contain::SIZE.bits();
1192 }
1193}
1194
1195impl Parse for ContainIntrinsicSize {
1196 fn parse<'i, 't>(
1198 context: &ParserContext,
1199 input: &mut Parser<'i, 't>,
1200 ) -> Result<Self, ParseError<'i>> {
1201 if let Ok(l) = input.try_parse(|i| NonNegativeLength::parse(context, i)) {
1202 return Ok(Self::Length(l));
1203 }
1204
1205 if input.try_parse(|i| i.expect_ident_matching("auto")).is_ok() {
1206 if input.try_parse(|i| i.expect_ident_matching("none")).is_ok() {
1207 return Ok(Self::AutoNone);
1208 }
1209
1210 let l = NonNegativeLength::parse(context, input)?;
1211 return Ok(Self::AutoLength(l));
1212 }
1213
1214 input.expect_ident_matching("none")?;
1215 Ok(Self::None)
1216 }
1217}
1218
1219impl Parse for LineClamp {
1220 fn parse<'i, 't>(
1222 context: &ParserContext,
1223 input: &mut Parser<'i, 't>,
1224 ) -> Result<Self, ParseError<'i>> {
1225 if let Ok(i) =
1226 input.try_parse(|i| crate::values::specified::PositiveInteger::parse(context, i))
1227 {
1228 return Ok(Self(i.0));
1229 }
1230 input.expect_ident_matching("none")?;
1231 Ok(Self::none())
1232 }
1233}
1234
1235#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
1237#[derive(
1238 Clone,
1239 Copy,
1240 Debug,
1241 Eq,
1242 FromPrimitive,
1243 MallocSizeOf,
1244 Parse,
1245 PartialEq,
1246 SpecifiedValueInfo,
1247 ToAnimatedValue,
1248 ToComputedValue,
1249 ToCss,
1250 ToResolvedValue,
1251 ToShmem,
1252)]
1253#[repr(u8)]
1254pub enum ContentVisibility {
1255 Auto,
1259 Hidden,
1261 Visible,
1263}
1264
1265#[derive(
1266 Clone,
1267 Copy,
1268 Debug,
1269 PartialEq,
1270 Eq,
1271 MallocSizeOf,
1272 SpecifiedValueInfo,
1273 ToComputedValue,
1274 ToCss,
1275 Parse,
1276 ToResolvedValue,
1277 ToShmem,
1278)]
1279#[repr(u8)]
1280#[allow(missing_docs)]
1281pub enum ContainerType {
1283 Normal,
1285 InlineSize,
1287 Size,
1289}
1290
1291impl ContainerType {
1292 pub fn is_normal(self) -> bool {
1294 self == Self::Normal
1295 }
1296
1297 pub fn is_size_container_type(self) -> bool {
1299 !self.is_normal()
1300 }
1301}
1302
1303#[repr(transparent)]
1305#[derive(
1306 Clone,
1307 Debug,
1308 MallocSizeOf,
1309 PartialEq,
1310 SpecifiedValueInfo,
1311 ToComputedValue,
1312 ToCss,
1313 ToResolvedValue,
1314 ToShmem,
1315)]
1316pub struct ContainerName(#[css(iterable, if_empty = "none")] pub crate::OwnedSlice<CustomIdent>);
1317
1318impl ContainerName {
1319 pub fn none() -> Self {
1321 Self(Default::default())
1322 }
1323
1324 pub fn is_none(&self) -> bool {
1326 self.0.is_empty()
1327 }
1328
1329 fn parse_internal<'i>(
1330 input: &mut Parser<'i, '_>,
1331 for_query: bool,
1332 ) -> Result<Self, ParseError<'i>> {
1333 let mut idents = vec![];
1334 let location = input.current_source_location();
1335 let first = input.expect_ident()?;
1336 if !for_query && first.eq_ignore_ascii_case("none") {
1337 return Ok(Self::none());
1338 }
1339 const DISALLOWED_CONTAINER_NAMES: &'static [&'static str] = &["none", "not", "or", "and"];
1340 idents.push(CustomIdent::from_ident(
1341 location,
1342 first,
1343 DISALLOWED_CONTAINER_NAMES,
1344 )?);
1345 if !for_query {
1346 while let Ok(name) =
1347 input.try_parse(|input| CustomIdent::parse(input, DISALLOWED_CONTAINER_NAMES))
1348 {
1349 idents.push(name);
1350 }
1351 }
1352 Ok(ContainerName(idents.into()))
1353 }
1354
1355 pub fn parse_for_query<'i, 't>(
1359 _: &ParserContext,
1360 input: &mut Parser<'i, 't>,
1361 ) -> Result<Self, ParseError<'i>> {
1362 Self::parse_internal(input, true)
1363 }
1364}
1365
1366impl Parse for ContainerName {
1367 fn parse<'i, 't>(
1368 _: &ParserContext,
1369 input: &mut Parser<'i, 't>,
1370 ) -> Result<Self, ParseError<'i>> {
1371 Self::parse_internal(input, false)
1372 }
1373}
1374
1375pub type Perspective = GenericPerspective<NonNegativeLength>;
1377
1378#[allow(missing_docs)]
1380#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
1381#[derive(
1382 Clone,
1383 Copy,
1384 Debug,
1385 Eq,
1386 FromPrimitive,
1387 Hash,
1388 MallocSizeOf,
1389 Parse,
1390 PartialEq,
1391 SpecifiedValueInfo,
1392 ToComputedValue,
1393 ToCss,
1394 ToResolvedValue,
1395 ToShmem,
1396)]
1397#[repr(u8)]
1398pub enum Float {
1399 Left,
1400 Right,
1401 None,
1402 InlineStart,
1404 InlineEnd,
1405}
1406
1407impl Float {
1408 pub fn is_floating(self) -> bool {
1410 self != Self::None
1411 }
1412}
1413
1414#[allow(missing_docs)]
1416#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
1417#[derive(
1418 Clone,
1419 Copy,
1420 Debug,
1421 Eq,
1422 FromPrimitive,
1423 Hash,
1424 MallocSizeOf,
1425 Parse,
1426 PartialEq,
1427 SpecifiedValueInfo,
1428 ToComputedValue,
1429 ToCss,
1430 ToResolvedValue,
1431 ToShmem,
1432)]
1433#[repr(u8)]
1434pub enum Clear {
1435 None,
1436 Left,
1437 Right,
1438 Both,
1439 InlineStart,
1441 InlineEnd,
1442}
1443
1444#[allow(missing_docs)]
1446#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
1447#[derive(
1448 Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss, ToShmem,
1449)]
1450pub enum Resize {
1451 None,
1452 Both,
1453 Horizontal,
1454 Vertical,
1455 Inline,
1457 Block,
1458}
1459
1460#[allow(missing_docs)]
1464#[derive(
1465 Clone,
1466 Copy,
1467 Debug,
1468 Eq,
1469 Hash,
1470 MallocSizeOf,
1471 Parse,
1472 PartialEq,
1473 SpecifiedValueInfo,
1474 ToCss,
1475 ToComputedValue,
1476 ToResolvedValue,
1477 ToShmem,
1478)]
1479#[repr(u8)]
1480pub enum Appearance {
1481 None,
1483 Auto,
1488 Searchfield,
1490 Textarea,
1492 Checkbox,
1494 Radio,
1496 Menulist,
1498 Listbox,
1500 Meter,
1502 ProgressBar,
1504 Button,
1506 Textfield,
1508 MenulistButton,
1510 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1512 Menupopup,
1513 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1515 MozMenulistArrowButton,
1516 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1518 NumberInput,
1519 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1521 PasswordInput,
1522 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1524 Range,
1525 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1527 ScrollbarHorizontal,
1528 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1529 ScrollbarVertical,
1530 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1534 ScrollbarbuttonUp,
1535 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1536 ScrollbarbuttonDown,
1537 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1538 ScrollbarbuttonLeft,
1539 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1540 ScrollbarbuttonRight,
1541 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1543 ScrollbarthumbHorizontal,
1544 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1545 ScrollbarthumbVertical,
1546 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1548 Scrollcorner,
1549 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1551 SpinnerUpbutton,
1552 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1554 SpinnerDownbutton,
1555 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1557 Toolbarbutton,
1558 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1560 Tooltip,
1561
1562 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1564 MozSidebar,
1565
1566 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1568 MozMacHelpButton,
1569
1570 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1574 MozMacWindow,
1575
1576 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1578 MozWindowButtonBox,
1579 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1580 MozWindowButtonClose,
1581 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1582 MozWindowButtonMaximize,
1583 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1584 MozWindowButtonMinimize,
1585 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1586 MozWindowButtonRestore,
1587 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1588 MozWindowTitlebar,
1589 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1590 MozWindowTitlebarMaximized,
1591 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1592 MozWindowDecorations,
1593
1594 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1595 MozMacDisclosureButtonClosed,
1596 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1597 MozMacDisclosureButtonOpen,
1598
1599 #[css(skip)]
1603 FocusOutline,
1604
1605 #[css(skip)]
1607 Count,
1608}
1609
1610#[allow(missing_docs)]
1614#[derive(
1615 Clone,
1616 Copy,
1617 Debug,
1618 Eq,
1619 Hash,
1620 MallocSizeOf,
1621 Parse,
1622 PartialEq,
1623 SpecifiedValueInfo,
1624 ToCss,
1625 ToComputedValue,
1626 ToResolvedValue,
1627 ToShmem,
1628)]
1629#[repr(u8)]
1630pub enum BreakBetween {
1631 Always,
1632 Auto,
1633 Page,
1634 Avoid,
1635 Left,
1636 Right,
1637}
1638
1639impl BreakBetween {
1640 #[cfg_attr(feature = "servo", allow(unused))]
1644 #[inline]
1645 pub(crate) fn parse_legacy<'i>(
1646 _: &ParserContext,
1647 input: &mut Parser<'i, '_>,
1648 ) -> Result<Self, ParseError<'i>> {
1649 let break_value = BreakBetween::parse(input)?;
1650 match break_value {
1651 BreakBetween::Always => Ok(BreakBetween::Page),
1652 BreakBetween::Auto | BreakBetween::Avoid | BreakBetween::Left | BreakBetween::Right => {
1653 Ok(break_value)
1654 },
1655 BreakBetween::Page => {
1656 Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
1657 },
1658 }
1659 }
1660
1661 #[cfg_attr(feature = "servo", allow(unused))]
1665 pub(crate) fn to_css_legacy<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
1666 where
1667 W: Write,
1668 {
1669 match *self {
1670 BreakBetween::Auto | BreakBetween::Avoid | BreakBetween::Left | BreakBetween::Right => {
1671 self.to_css(dest)
1672 },
1673 BreakBetween::Page => dest.write_str("always"),
1674 BreakBetween::Always => Ok(()),
1675 }
1676 }
1677}
1678
1679#[allow(missing_docs)]
1683#[derive(
1684 Clone,
1685 Copy,
1686 Debug,
1687 Eq,
1688 Hash,
1689 MallocSizeOf,
1690 Parse,
1691 PartialEq,
1692 SpecifiedValueInfo,
1693 ToCss,
1694 ToComputedValue,
1695 ToResolvedValue,
1696 ToShmem,
1697)]
1698#[repr(u8)]
1699pub enum BreakWithin {
1700 Auto,
1701 Avoid,
1702 AvoidPage,
1703 AvoidColumn,
1704}
1705
1706impl BreakWithin {
1707 #[cfg_attr(feature = "servo", allow(unused))]
1711 #[inline]
1712 pub(crate) fn parse_legacy<'i>(
1713 _: &ParserContext,
1714 input: &mut Parser<'i, '_>,
1715 ) -> Result<Self, ParseError<'i>> {
1716 let break_value = BreakWithin::parse(input)?;
1717 match break_value {
1718 BreakWithin::Auto | BreakWithin::Avoid => Ok(break_value),
1719 BreakWithin::AvoidPage | BreakWithin::AvoidColumn => {
1720 Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
1721 },
1722 }
1723 }
1724
1725 #[cfg_attr(feature = "servo", allow(unused))]
1729 pub(crate) fn to_css_legacy<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
1730 where
1731 W: Write,
1732 {
1733 match *self {
1734 BreakWithin::Auto | BreakWithin::Avoid => self.to_css(dest),
1735 BreakWithin::AvoidPage | BreakWithin::AvoidColumn => Ok(()),
1736 }
1737 }
1738}
1739
1740#[allow(missing_docs)]
1742#[derive(
1743 Clone,
1744 Copy,
1745 Debug,
1746 Eq,
1747 Hash,
1748 MallocSizeOf,
1749 PartialEq,
1750 SpecifiedValueInfo,
1751 ToCss,
1752 ToComputedValue,
1753 ToResolvedValue,
1754 ToShmem,
1755)]
1756#[repr(u8)]
1757pub enum Overflow {
1758 Visible,
1759 Hidden,
1760 Scroll,
1761 Auto,
1762 Clip,
1763}
1764
1765impl Parse for Overflow {
1768 fn parse<'i, 't>(
1769 _: &ParserContext,
1770 input: &mut Parser<'i, 't>,
1771 ) -> Result<Self, ParseError<'i>> {
1772 Ok(try_match_ident_ignore_ascii_case! { input,
1773 "visible" => Self::Visible,
1774 "hidden" => Self::Hidden,
1775 "scroll" => Self::Scroll,
1776 "auto" | "overlay" => Self::Auto,
1777 "clip" => Self::Clip,
1778 #[cfg(feature = "gecko")]
1779 "-moz-hidden-unscrollable" if static_prefs::pref!("layout.css.overflow-moz-hidden-unscrollable.enabled") => {
1780 Overflow::Clip
1781 },
1782 })
1783 }
1784}
1785
1786impl Overflow {
1787 #[inline]
1789 pub fn is_scrollable(&self) -> bool {
1790 matches!(*self, Self::Hidden | Self::Scroll | Self::Auto)
1791 }
1792 #[inline]
1795 pub fn to_scrollable(&self) -> Self {
1796 match *self {
1797 Self::Hidden | Self::Scroll | Self::Auto => *self,
1798 Self::Visible => Self::Auto,
1799 Self::Clip => Self::Hidden,
1800 }
1801 }
1802}
1803
1804#[derive(
1805 Clone,
1806 Copy,
1807 Debug,
1808 Eq,
1809 MallocSizeOf,
1810 Parse,
1811 PartialEq,
1812 SpecifiedValueInfo,
1813 ToComputedValue,
1814 ToCss,
1815 ToResolvedValue,
1816 ToShmem,
1817)]
1818#[repr(C)]
1819#[css(bitflags(
1820 single = "auto",
1821 mixed = "stable,both-edges",
1822 validate_mixed = "Self::has_stable"
1823))]
1824pub struct ScrollbarGutter(u8);
1827bitflags! {
1828 impl ScrollbarGutter: u8 {
1829 const AUTO = 0;
1831 const STABLE = 1 << 0;
1833 const BOTH_EDGES = 1 << 1;
1835 }
1836}
1837
1838impl ScrollbarGutter {
1839 #[inline]
1840 fn has_stable(&self) -> bool {
1841 self.intersects(Self::STABLE)
1842 }
1843}
1844
1845#[derive(
1847 Clone, Copy, Debug, MallocSizeOf, PartialEq, Parse, SpecifiedValueInfo, ToCss, ToShmem,
1848)]
1849#[allow(missing_docs)]
1850pub enum Zoom {
1851 Normal,
1852 #[parse(condition = "ParserContext::in_ua_sheet")]
1855 Document,
1856 Value(NonNegativeNumberOrPercentage),
1857}
1858
1859impl Zoom {
1860 #[inline]
1862 pub fn new_number(n: f32) -> Self {
1863 Self::Value(NonNegativeNumberOrPercentage::new_number(n))
1864 }
1865}
1866
1867pub use crate::values::generics::box_::PositionProperty;