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