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 BaselineShiftKeyword, GenericBaselineShift, GenericContainIntrinsicSize, GenericLineClamp,
13 GenericOverflowClipMargin, GenericPerspective, OverflowClipMarginBox,
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 BaselineShift = GenericBaselineShift<LengthPercentage>;
619
620impl Parse for BaselineShift {
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(BaselineShift::Length(lp));
629 }
630
631 Ok(BaselineShift::Keyword(BaselineShiftKeyword::parse(input)?))
632 }
633}
634
635#[derive(
638 Clone,
639 Copy,
640 Debug,
641 Eq,
642 FromPrimitive,
643 Hash,
644 MallocSizeOf,
645 Parse,
646 PartialEq,
647 SpecifiedValueInfo,
648 ToCss,
649 ToShmem,
650 ToComputedValue,
651 ToResolvedValue,
652 ToTyped,
653)]
654#[repr(u8)]
655pub enum AlignmentBaseline {
656 Baseline,
658 TextBottom,
660 Middle,
670 TextTop,
678 #[cfg(feature = "gecko")]
680 MozMiddleWithBaseline,
681}
682
683#[derive(
686 Clone,
687 Copy,
688 Debug,
689 Eq,
690 Hash,
691 MallocSizeOf,
692 Parse,
693 PartialEq,
694 SpecifiedValueInfo,
695 ToCss,
696 ToShmem,
697 ToComputedValue,
698 ToResolvedValue,
699 ToTyped,
700)]
701#[repr(u8)]
702pub enum BaselineSource {
703 Auto,
705 First,
707 Last,
709}
710
711impl BaselineSource {
712 pub fn parse_non_auto<'i>(input: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
714 Ok(try_match_ident_ignore_ascii_case! { input,
715 "first" => Self::First,
716 "last" => Self::Last,
717 })
718 }
719}
720
721#[allow(missing_docs)]
723#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
724#[derive(
725 Clone,
726 Copy,
727 Debug,
728 Eq,
729 MallocSizeOf,
730 Parse,
731 PartialEq,
732 SpecifiedValueInfo,
733 ToComputedValue,
734 ToCss,
735 ToResolvedValue,
736 ToShmem,
737)]
738#[repr(u8)]
739pub enum ScrollSnapAxis {
740 X,
741 Y,
742 Block,
743 Inline,
744 Both,
745}
746
747#[allow(missing_docs)]
749#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
750#[derive(
751 Clone,
752 Copy,
753 Debug,
754 Eq,
755 MallocSizeOf,
756 Parse,
757 PartialEq,
758 SpecifiedValueInfo,
759 ToComputedValue,
760 ToCss,
761 ToResolvedValue,
762 ToShmem,
763)]
764#[repr(u8)]
765pub enum ScrollSnapStrictness {
766 #[css(skip)]
767 None, Mandatory,
769 Proximity,
770}
771
772#[allow(missing_docs)]
774#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
775#[derive(
776 Clone,
777 Copy,
778 Debug,
779 Eq,
780 MallocSizeOf,
781 PartialEq,
782 SpecifiedValueInfo,
783 ToComputedValue,
784 ToResolvedValue,
785 ToShmem,
786 ToTyped,
787)]
788#[repr(C)]
789pub struct ScrollSnapType {
790 axis: ScrollSnapAxis,
791 strictness: ScrollSnapStrictness,
792}
793
794impl ScrollSnapType {
795 #[inline]
797 pub fn none() -> Self {
798 Self {
799 axis: ScrollSnapAxis::Both,
800 strictness: ScrollSnapStrictness::None,
801 }
802 }
803}
804
805impl Parse for ScrollSnapType {
806 fn parse<'i, 't>(
808 _context: &ParserContext,
809 input: &mut Parser<'i, 't>,
810 ) -> Result<Self, ParseError<'i>> {
811 if input
812 .try_parse(|input| input.expect_ident_matching("none"))
813 .is_ok()
814 {
815 return Ok(ScrollSnapType::none());
816 }
817
818 let axis = ScrollSnapAxis::parse(input)?;
819 let strictness = input
820 .try_parse(ScrollSnapStrictness::parse)
821 .unwrap_or(ScrollSnapStrictness::Proximity);
822 Ok(Self { axis, strictness })
823 }
824}
825
826impl ToCss for ScrollSnapType {
827 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
828 where
829 W: Write,
830 {
831 if self.strictness == ScrollSnapStrictness::None {
832 return dest.write_str("none");
833 }
834 self.axis.to_css(dest)?;
835 if self.strictness != ScrollSnapStrictness::Proximity {
836 dest.write_char(' ')?;
837 self.strictness.to_css(dest)?;
838 }
839 Ok(())
840 }
841}
842
843#[allow(missing_docs)]
845#[derive(
846 Clone,
847 Copy,
848 Debug,
849 Eq,
850 FromPrimitive,
851 Hash,
852 MallocSizeOf,
853 Parse,
854 PartialEq,
855 SpecifiedValueInfo,
856 ToComputedValue,
857 ToCss,
858 ToResolvedValue,
859 ToShmem,
860)]
861#[repr(u8)]
862pub enum ScrollSnapAlignKeyword {
863 None,
864 Start,
865 End,
866 Center,
867}
868
869#[allow(missing_docs)]
871#[derive(
872 Clone,
873 Copy,
874 Debug,
875 Eq,
876 MallocSizeOf,
877 PartialEq,
878 SpecifiedValueInfo,
879 ToComputedValue,
880 ToResolvedValue,
881 ToShmem,
882 ToTyped,
883)]
884#[repr(C)]
885pub struct ScrollSnapAlign {
886 block: ScrollSnapAlignKeyword,
887 inline: ScrollSnapAlignKeyword,
888}
889
890impl ScrollSnapAlign {
891 #[inline]
893 pub fn none() -> Self {
894 ScrollSnapAlign {
895 block: ScrollSnapAlignKeyword::None,
896 inline: ScrollSnapAlignKeyword::None,
897 }
898 }
899}
900
901impl Parse for ScrollSnapAlign {
902 fn parse<'i, 't>(
904 _context: &ParserContext,
905 input: &mut Parser<'i, 't>,
906 ) -> Result<ScrollSnapAlign, ParseError<'i>> {
907 let block = ScrollSnapAlignKeyword::parse(input)?;
908 let inline = input
909 .try_parse(ScrollSnapAlignKeyword::parse)
910 .unwrap_or(block);
911 Ok(ScrollSnapAlign { block, inline })
912 }
913}
914
915impl ToCss for ScrollSnapAlign {
916 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
917 where
918 W: Write,
919 {
920 self.block.to_css(dest)?;
921 if self.block != self.inline {
922 dest.write_char(' ')?;
923 self.inline.to_css(dest)?;
924 }
925 Ok(())
926 }
927}
928
929#[allow(missing_docs)]
930#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
931#[derive(
932 Clone,
933 Copy,
934 Debug,
935 Eq,
936 MallocSizeOf,
937 Parse,
938 PartialEq,
939 SpecifiedValueInfo,
940 ToComputedValue,
941 ToCss,
942 ToResolvedValue,
943 ToShmem,
944 ToTyped,
945)]
946#[repr(u8)]
947pub enum ScrollSnapStop {
948 Normal,
949 Always,
950}
951
952#[allow(missing_docs)]
953#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
954#[derive(
955 Clone,
956 Copy,
957 Debug,
958 Eq,
959 MallocSizeOf,
960 Parse,
961 PartialEq,
962 SpecifiedValueInfo,
963 ToComputedValue,
964 ToCss,
965 ToResolvedValue,
966 ToShmem,
967 ToTyped,
968)]
969#[repr(u8)]
970pub enum OverscrollBehavior {
971 Auto,
972 Contain,
973 None,
974}
975
976#[allow(missing_docs)]
977#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
978#[derive(
979 Clone,
980 Copy,
981 Debug,
982 Eq,
983 MallocSizeOf,
984 Parse,
985 PartialEq,
986 SpecifiedValueInfo,
987 ToComputedValue,
988 ToCss,
989 ToResolvedValue,
990 ToShmem,
991 ToTyped,
992)]
993#[repr(u8)]
994pub enum OverflowAnchor {
995 Auto,
996 None,
997}
998
999#[derive(
1000 Clone,
1001 Debug,
1002 Default,
1003 MallocSizeOf,
1004 PartialEq,
1005 SpecifiedValueInfo,
1006 ToComputedValue,
1007 ToCss,
1008 ToResolvedValue,
1009 ToShmem,
1010 ToTyped,
1011)]
1012#[css(comma)]
1013#[repr(C)]
1014pub struct WillChange {
1021 #[css(iterable, if_empty = "auto")]
1026 features: crate::OwnedSlice<CustomIdent>,
1027 #[css(skip)]
1030 pub bits: WillChangeBits,
1031}
1032
1033impl WillChange {
1034 #[inline]
1035 pub fn auto() -> Self {
1037 Self::default()
1038 }
1039}
1040
1041#[derive(
1043 Clone,
1044 Copy,
1045 Debug,
1046 Default,
1047 Eq,
1048 MallocSizeOf,
1049 PartialEq,
1050 SpecifiedValueInfo,
1051 ToComputedValue,
1052 ToResolvedValue,
1053 ToShmem,
1054)]
1055#[repr(C)]
1056pub struct WillChangeBits(u16);
1057bitflags! {
1058 impl WillChangeBits: u16 {
1059 const STACKING_CONTEXT_UNCONDITIONAL = 1 << 0;
1062 const TRANSFORM = 1 << 1;
1064 const SCROLL = 1 << 2;
1066 const CONTAIN = 1 << 3;
1068 const OPACITY = 1 << 4;
1070 const PERSPECTIVE = 1 << 5;
1072 const Z_INDEX = 1 << 6;
1074 const FIXPOS_CB_NON_SVG = 1 << 7;
1077 const POSITION = 1 << 8;
1079 const VIEW_TRANSITION_NAME = 1 << 9;
1081 const BACKDROP_ROOT = 1 << 10;
1084 }
1085}
1086
1087fn change_bits_for_longhand(longhand: LonghandId) -> WillChangeBits {
1088 match longhand {
1089 LonghandId::Opacity => WillChangeBits::OPACITY | WillChangeBits::BACKDROP_ROOT,
1090 LonghandId::Contain => WillChangeBits::CONTAIN,
1091 LonghandId::Perspective => WillChangeBits::PERSPECTIVE,
1092 LonghandId::Position => {
1093 WillChangeBits::STACKING_CONTEXT_UNCONDITIONAL | WillChangeBits::POSITION
1094 },
1095 LonghandId::ZIndex => WillChangeBits::Z_INDEX,
1096 LonghandId::Transform
1097 | LonghandId::TransformStyle
1098 | LonghandId::Translate
1099 | LonghandId::Rotate
1100 | LonghandId::Scale
1101 | LonghandId::OffsetPath => WillChangeBits::TRANSFORM,
1102 LonghandId::Filter | LonghandId::BackdropFilter => {
1103 WillChangeBits::STACKING_CONTEXT_UNCONDITIONAL
1104 | WillChangeBits::BACKDROP_ROOT
1105 | WillChangeBits::FIXPOS_CB_NON_SVG
1106 },
1107 LonghandId::ViewTransitionName => {
1108 WillChangeBits::VIEW_TRANSITION_NAME | WillChangeBits::BACKDROP_ROOT
1109 },
1110 LonghandId::MixBlendMode => {
1111 WillChangeBits::STACKING_CONTEXT_UNCONDITIONAL | WillChangeBits::BACKDROP_ROOT
1112 },
1113 LonghandId::Isolation | LonghandId::MaskImage => {
1114 WillChangeBits::STACKING_CONTEXT_UNCONDITIONAL
1115 },
1116 LonghandId::ClipPath => {
1117 WillChangeBits::STACKING_CONTEXT_UNCONDITIONAL | WillChangeBits::BACKDROP_ROOT
1118 },
1119 _ => WillChangeBits::empty(),
1120 }
1121}
1122
1123fn change_bits_for_maybe_property(ident: &str, context: &ParserContext) -> WillChangeBits {
1124 let id = match PropertyId::parse_ignoring_rule_type(ident, context) {
1125 Ok(id) => id,
1126 Err(..) => return WillChangeBits::empty(),
1127 };
1128
1129 match id.as_shorthand() {
1130 Ok(shorthand) => shorthand
1131 .longhands()
1132 .fold(WillChangeBits::empty(), |flags, p| {
1133 flags | change_bits_for_longhand(p)
1134 }),
1135 Err(PropertyDeclarationId::Longhand(longhand)) => change_bits_for_longhand(longhand),
1136 Err(PropertyDeclarationId::Custom(..)) => WillChangeBits::empty(),
1137 }
1138}
1139
1140impl Parse for WillChange {
1141 fn parse<'i, 't>(
1143 context: &ParserContext,
1144 input: &mut Parser<'i, 't>,
1145 ) -> Result<Self, ParseError<'i>> {
1146 if input
1147 .try_parse(|input| input.expect_ident_matching("auto"))
1148 .is_ok()
1149 {
1150 return Ok(Self::default());
1151 }
1152
1153 let mut bits = WillChangeBits::empty();
1154 let custom_idents = input.parse_comma_separated(|i| {
1155 let location = i.current_source_location();
1156 let parser_ident = i.expect_ident()?;
1157 let ident = CustomIdent::from_ident(
1158 location,
1159 parser_ident,
1160 &["will-change", "none", "all", "auto"],
1161 )?;
1162
1163 if context.in_ua_sheet() && ident.0 == atom!("-moz-fixed-pos-containing-block") {
1164 bits |= WillChangeBits::FIXPOS_CB_NON_SVG;
1165 } else if ident.0 == atom!("scroll-position") {
1166 bits |= WillChangeBits::SCROLL;
1167 } else {
1168 bits |= change_bits_for_maybe_property(&parser_ident, context);
1169 }
1170 Ok(ident)
1171 })?;
1172
1173 Ok(Self {
1174 features: custom_idents.into(),
1175 bits,
1176 })
1177 }
1178}
1179
1180#[derive(
1182 Clone,
1183 Copy,
1184 Debug,
1185 Eq,
1186 MallocSizeOf,
1187 Parse,
1188 PartialEq,
1189 SpecifiedValueInfo,
1190 ToComputedValue,
1191 ToCss,
1192 ToResolvedValue,
1193 ToShmem,
1194 ToTyped,
1195)]
1196#[css(bitflags(single = "none,auto,manipulation", mixed = "pan-x,pan-y,pinch-zoom"))]
1197#[repr(C)]
1198pub struct TouchAction(u8);
1199bitflags! {
1200 impl TouchAction: u8 {
1201 const NONE = 1 << 0;
1203 const AUTO = 1 << 1;
1205 const PAN_X = 1 << 2;
1207 const PAN_Y = 1 << 3;
1209 const MANIPULATION = 1 << 4;
1211 const PINCH_ZOOM = 1 << 5;
1213 }
1214}
1215
1216impl TouchAction {
1217 #[inline]
1218 pub fn auto() -> TouchAction {
1220 TouchAction::AUTO
1221 }
1222}
1223
1224#[derive(
1225 Clone,
1226 Copy,
1227 Debug,
1228 Eq,
1229 MallocSizeOf,
1230 Parse,
1231 PartialEq,
1232 SpecifiedValueInfo,
1233 ToComputedValue,
1234 ToCss,
1235 ToResolvedValue,
1236 ToShmem,
1237 ToTyped,
1238)]
1239#[css(bitflags(
1240 single = "none,strict,content",
1241 mixed = "size,layout,style,paint,inline-size",
1242 overlapping_bits
1243))]
1244#[repr(C)]
1245pub struct Contain(u8);
1247bitflags! {
1248 impl Contain: u8 {
1249 const NONE = 0;
1251 const INLINE_SIZE = 1 << 0;
1253 const BLOCK_SIZE = 1 << 1;
1255 const LAYOUT = 1 << 2;
1257 const STYLE = 1 << 3;
1259 const PAINT = 1 << 4;
1261 const SIZE = 1 << 5 | Contain::INLINE_SIZE.bits() | Contain::BLOCK_SIZE.bits();
1263 const CONTENT = 1 << 6 | Contain::LAYOUT.bits() | Contain::STYLE.bits() | Contain::PAINT.bits();
1265 const STRICT = 1 << 7 | Contain::LAYOUT.bits() | Contain::STYLE.bits() | Contain::PAINT.bits() | Contain::SIZE.bits();
1267 }
1268}
1269
1270impl Parse for ContainIntrinsicSize {
1271 fn parse<'i, 't>(
1273 context: &ParserContext,
1274 input: &mut Parser<'i, 't>,
1275 ) -> Result<Self, ParseError<'i>> {
1276 if let Ok(l) = input.try_parse(|i| NonNegativeLength::parse(context, i)) {
1277 return Ok(Self::Length(l));
1278 }
1279
1280 if input.try_parse(|i| i.expect_ident_matching("auto")).is_ok() {
1281 if input.try_parse(|i| i.expect_ident_matching("none")).is_ok() {
1282 return Ok(Self::AutoNone);
1283 }
1284
1285 let l = NonNegativeLength::parse(context, input)?;
1286 return Ok(Self::AutoLength(l));
1287 }
1288
1289 input.expect_ident_matching("none")?;
1290 Ok(Self::None)
1291 }
1292}
1293
1294impl Parse for LineClamp {
1295 fn parse<'i, 't>(
1297 context: &ParserContext,
1298 input: &mut Parser<'i, 't>,
1299 ) -> Result<Self, ParseError<'i>> {
1300 if let Ok(i) =
1301 input.try_parse(|i| crate::values::specified::PositiveInteger::parse(context, i))
1302 {
1303 return Ok(Self(i.0));
1304 }
1305 input.expect_ident_matching("none")?;
1306 Ok(Self::none())
1307 }
1308}
1309
1310#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
1312#[derive(
1313 Clone,
1314 Copy,
1315 Debug,
1316 Eq,
1317 FromPrimitive,
1318 MallocSizeOf,
1319 Parse,
1320 PartialEq,
1321 SpecifiedValueInfo,
1322 ToAnimatedValue,
1323 ToComputedValue,
1324 ToCss,
1325 ToResolvedValue,
1326 ToShmem,
1327 ToTyped,
1328)]
1329#[repr(u8)]
1330pub enum ContentVisibility {
1331 Auto,
1335 Hidden,
1337 Visible,
1339}
1340
1341#[derive(
1342 Clone,
1343 Copy,
1344 Debug,
1345 PartialEq,
1346 Eq,
1347 MallocSizeOf,
1348 SpecifiedValueInfo,
1349 ToComputedValue,
1350 ToCss,
1351 Parse,
1352 ToResolvedValue,
1353 ToShmem,
1354 ToTyped,
1355)]
1356#[css(bitflags(
1357 single = "normal",
1358 mixed = "size,inline-size,scroll-state",
1359 validate_mixed = "Self::validate_mixed_flags",
1360))]
1361#[repr(C)]
1362pub struct ContainerType(u8);
1369bitflags! {
1370 impl ContainerType: u8 {
1371 const NORMAL = 0;
1373 const INLINE_SIZE = 1 << 0;
1375 const SIZE = 1 << 1;
1377 const SCROLL_STATE = 1 << 2;
1379 }
1380}
1381
1382impl ContainerType {
1383 fn validate_mixed_flags(&self) -> bool {
1384 if self.contains(Self::SIZE | Self::INLINE_SIZE) {
1386 return false;
1387 }
1388 if self.contains(Self::SCROLL_STATE)
1389 && !static_prefs::pref!("layout.css.scroll-state.enabled")
1390 {
1391 return false;
1392 }
1393 true
1394 }
1395
1396 pub fn is_normal(self) -> bool {
1398 self == Self::NORMAL
1399 }
1400
1401 pub fn is_size_container_type(self) -> bool {
1403 self.intersects(Self::SIZE | Self::INLINE_SIZE)
1404 }
1405}
1406
1407#[repr(transparent)]
1409#[derive(
1410 Clone,
1411 Debug,
1412 MallocSizeOf,
1413 PartialEq,
1414 SpecifiedValueInfo,
1415 ToComputedValue,
1416 ToCss,
1417 ToResolvedValue,
1418 ToShmem,
1419 ToTyped,
1420)]
1421pub struct ContainerName(#[css(iterable, if_empty = "none")] pub crate::OwnedSlice<CustomIdent>);
1422
1423impl ContainerName {
1424 pub fn none() -> Self {
1426 Self(Default::default())
1427 }
1428
1429 pub fn is_none(&self) -> bool {
1431 self.0.is_empty()
1432 }
1433
1434 fn parse_internal<'i>(
1435 input: &mut Parser<'i, '_>,
1436 for_query: bool,
1437 ) -> Result<Self, ParseError<'i>> {
1438 let mut idents = vec![];
1439 let location = input.current_source_location();
1440 let first = input.expect_ident()?;
1441 if !for_query && first.eq_ignore_ascii_case("none") {
1442 return Ok(Self::none());
1443 }
1444 const DISALLOWED_CONTAINER_NAMES: &'static [&'static str] = &["none", "not", "or", "and"];
1445 idents.push(CustomIdent::from_ident(
1446 location,
1447 first,
1448 DISALLOWED_CONTAINER_NAMES,
1449 )?);
1450 if !for_query {
1451 while let Ok(name) =
1452 input.try_parse(|input| CustomIdent::parse(input, DISALLOWED_CONTAINER_NAMES))
1453 {
1454 idents.push(name);
1455 }
1456 }
1457 Ok(ContainerName(idents.into()))
1458 }
1459
1460 pub fn parse_for_query<'i, 't>(
1464 _: &ParserContext,
1465 input: &mut Parser<'i, 't>,
1466 ) -> Result<Self, ParseError<'i>> {
1467 Self::parse_internal(input, true)
1468 }
1469}
1470
1471impl Parse for ContainerName {
1472 fn parse<'i, 't>(
1473 _: &ParserContext,
1474 input: &mut Parser<'i, 't>,
1475 ) -> Result<Self, ParseError<'i>> {
1476 Self::parse_internal(input, false)
1477 }
1478}
1479
1480pub type Perspective = GenericPerspective<NonNegativeLength>;
1482
1483#[allow(missing_docs)]
1485#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
1486#[derive(
1487 Clone,
1488 Copy,
1489 Debug,
1490 Eq,
1491 FromPrimitive,
1492 Hash,
1493 MallocSizeOf,
1494 Parse,
1495 PartialEq,
1496 SpecifiedValueInfo,
1497 ToComputedValue,
1498 ToCss,
1499 ToResolvedValue,
1500 ToShmem,
1501 ToTyped,
1502)]
1503#[repr(u8)]
1504pub enum Float {
1505 Left,
1506 Right,
1507 None,
1508 InlineStart,
1510 InlineEnd,
1511}
1512
1513impl Float {
1514 pub fn is_floating(self) -> bool {
1516 self != Self::None
1517 }
1518}
1519
1520#[allow(missing_docs)]
1522#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
1523#[derive(
1524 Clone,
1525 Copy,
1526 Debug,
1527 Eq,
1528 FromPrimitive,
1529 Hash,
1530 MallocSizeOf,
1531 Parse,
1532 PartialEq,
1533 SpecifiedValueInfo,
1534 ToComputedValue,
1535 ToCss,
1536 ToResolvedValue,
1537 ToShmem,
1538 ToTyped,
1539)]
1540#[repr(u8)]
1541pub enum Clear {
1542 None,
1543 Left,
1544 Right,
1545 Both,
1546 InlineStart,
1548 InlineEnd,
1549}
1550
1551#[allow(missing_docs)]
1553#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
1554#[derive(
1555 Clone,
1556 Copy,
1557 Debug,
1558 Eq,
1559 Hash,
1560 MallocSizeOf,
1561 Parse,
1562 PartialEq,
1563 SpecifiedValueInfo,
1564 ToCss,
1565 ToShmem,
1566 ToTyped,
1567)]
1568pub enum Resize {
1569 None,
1570 Both,
1571 Horizontal,
1572 Vertical,
1573 Inline,
1575 Block,
1576}
1577
1578#[allow(missing_docs)]
1582#[derive(
1583 Clone,
1584 Copy,
1585 Debug,
1586 Eq,
1587 Hash,
1588 MallocSizeOf,
1589 Parse,
1590 PartialEq,
1591 SpecifiedValueInfo,
1592 ToCss,
1593 ToComputedValue,
1594 ToResolvedValue,
1595 ToShmem,
1596 ToTyped,
1597)]
1598#[repr(u8)]
1599pub enum Appearance {
1600 None,
1602 Auto,
1607 Searchfield,
1609 Textarea,
1611 Checkbox,
1613 Radio,
1615 Menulist,
1617 Listbox,
1619 Meter,
1621 ProgressBar,
1623 Button,
1625 Textfield,
1627 MenulistButton,
1629 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1631 Menupopup,
1632 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1634 MozMenulistArrowButton,
1635 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1637 NumberInput,
1638 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1640 PasswordInput,
1641 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1643 Range,
1644 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1646 ScrollbarHorizontal,
1647 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1648 ScrollbarVertical,
1649 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1653 ScrollbarbuttonUp,
1654 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1655 ScrollbarbuttonDown,
1656 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1657 ScrollbarbuttonLeft,
1658 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1659 ScrollbarbuttonRight,
1660 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1662 ScrollbarthumbHorizontal,
1663 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1664 ScrollbarthumbVertical,
1665 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1667 Scrollcorner,
1668 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1670 SpinnerUpbutton,
1671 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1673 SpinnerDownbutton,
1674 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1676 Toolbarbutton,
1677 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1679 Tooltip,
1680
1681 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1683 MozSidebar,
1684
1685 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1687 MozMacHelpButton,
1688
1689 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1693 MozMacWindow,
1694
1695 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1697 MozWindowButtonBox,
1698 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1699 MozWindowButtonClose,
1700 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1701 MozWindowButtonMaximize,
1702 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1703 MozWindowButtonMinimize,
1704 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1705 MozWindowButtonRestore,
1706 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1707 MozWindowTitlebar,
1708 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1709 MozWindowTitlebarMaximized,
1710 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1711 MozWindowDecorations,
1712
1713 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1714 MozMacDisclosureButtonClosed,
1715 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1716 MozMacDisclosureButtonOpen,
1717
1718 #[css(skip)]
1722 FocusOutline,
1723
1724 #[css(skip)]
1726 Count,
1727}
1728
1729#[allow(missing_docs)]
1733#[derive(
1734 Clone,
1735 Copy,
1736 Debug,
1737 Eq,
1738 Hash,
1739 MallocSizeOf,
1740 Parse,
1741 PartialEq,
1742 SpecifiedValueInfo,
1743 ToCss,
1744 ToComputedValue,
1745 ToResolvedValue,
1746 ToShmem,
1747 ToTyped,
1748)]
1749#[repr(u8)]
1750pub enum BreakBetween {
1751 Always,
1752 Auto,
1753 Page,
1754 Avoid,
1755 Left,
1756 Right,
1757}
1758
1759impl BreakBetween {
1760 #[cfg_attr(feature = "servo", allow(unused))]
1764 #[inline]
1765 pub(crate) fn parse_legacy<'i>(
1766 _: &ParserContext,
1767 input: &mut Parser<'i, '_>,
1768 ) -> Result<Self, ParseError<'i>> {
1769 let break_value = BreakBetween::parse(input)?;
1770 match break_value {
1771 BreakBetween::Always => Ok(BreakBetween::Page),
1772 BreakBetween::Auto | BreakBetween::Avoid | BreakBetween::Left | BreakBetween::Right => {
1773 Ok(break_value)
1774 },
1775 BreakBetween::Page => {
1776 Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
1777 },
1778 }
1779 }
1780
1781 #[cfg_attr(feature = "servo", allow(unused))]
1785 pub(crate) fn to_css_legacy<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
1786 where
1787 W: Write,
1788 {
1789 match *self {
1790 BreakBetween::Auto | BreakBetween::Avoid | BreakBetween::Left | BreakBetween::Right => {
1791 self.to_css(dest)
1792 },
1793 BreakBetween::Page => dest.write_str("always"),
1794 BreakBetween::Always => Ok(()),
1795 }
1796 }
1797}
1798
1799#[allow(missing_docs)]
1803#[derive(
1804 Clone,
1805 Copy,
1806 Debug,
1807 Eq,
1808 Hash,
1809 MallocSizeOf,
1810 Parse,
1811 PartialEq,
1812 SpecifiedValueInfo,
1813 ToCss,
1814 ToComputedValue,
1815 ToResolvedValue,
1816 ToShmem,
1817 ToTyped,
1818)]
1819#[repr(u8)]
1820pub enum BreakWithin {
1821 Auto,
1822 Avoid,
1823 AvoidPage,
1824 AvoidColumn,
1825}
1826
1827impl BreakWithin {
1828 #[cfg_attr(feature = "servo", allow(unused))]
1832 #[inline]
1833 pub(crate) fn parse_legacy<'i>(
1834 _: &ParserContext,
1835 input: &mut Parser<'i, '_>,
1836 ) -> Result<Self, ParseError<'i>> {
1837 let break_value = BreakWithin::parse(input)?;
1838 match break_value {
1839 BreakWithin::Auto | BreakWithin::Avoid => Ok(break_value),
1840 BreakWithin::AvoidPage | BreakWithin::AvoidColumn => {
1841 Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
1842 },
1843 }
1844 }
1845
1846 #[cfg_attr(feature = "servo", allow(unused))]
1850 pub(crate) fn to_css_legacy<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
1851 where
1852 W: Write,
1853 {
1854 match *self {
1855 BreakWithin::Auto | BreakWithin::Avoid => self.to_css(dest),
1856 BreakWithin::AvoidPage | BreakWithin::AvoidColumn => Ok(()),
1857 }
1858 }
1859}
1860
1861#[allow(missing_docs)]
1863#[derive(
1864 Clone,
1865 Copy,
1866 Debug,
1867 Eq,
1868 Hash,
1869 MallocSizeOf,
1870 PartialEq,
1871 SpecifiedValueInfo,
1872 ToCss,
1873 ToComputedValue,
1874 ToResolvedValue,
1875 ToShmem,
1876 ToTyped,
1877)]
1878#[repr(u8)]
1879pub enum Overflow {
1880 Visible,
1881 Hidden,
1882 Scroll,
1883 Auto,
1884 Clip,
1885}
1886
1887impl Parse for Overflow {
1890 fn parse<'i, 't>(
1891 _: &ParserContext,
1892 input: &mut Parser<'i, 't>,
1893 ) -> Result<Self, ParseError<'i>> {
1894 Ok(try_match_ident_ignore_ascii_case! { input,
1895 "visible" => Self::Visible,
1896 "hidden" => Self::Hidden,
1897 "scroll" => Self::Scroll,
1898 "auto" | "overlay" => Self::Auto,
1899 "clip" => Self::Clip,
1900 #[cfg(feature = "gecko")]
1901 "-moz-hidden-unscrollable" if static_prefs::pref!("layout.css.overflow-moz-hidden-unscrollable.enabled") => {
1902 Overflow::Clip
1903 },
1904 })
1905 }
1906}
1907
1908impl Overflow {
1909 #[inline]
1911 pub fn is_scrollable(&self) -> bool {
1912 matches!(*self, Self::Hidden | Self::Scroll | Self::Auto)
1913 }
1914 #[inline]
1917 pub fn to_scrollable(&self) -> Self {
1918 match *self {
1919 Self::Hidden | Self::Scroll | Self::Auto => *self,
1920 Self::Visible => Self::Auto,
1921 Self::Clip => Self::Hidden,
1922 }
1923 }
1924}
1925
1926#[derive(
1927 Clone,
1928 Copy,
1929 Debug,
1930 Eq,
1931 MallocSizeOf,
1932 Parse,
1933 PartialEq,
1934 SpecifiedValueInfo,
1935 ToComputedValue,
1936 ToCss,
1937 ToResolvedValue,
1938 ToShmem,
1939 ToTyped,
1940)]
1941#[repr(C)]
1942#[css(bitflags(
1943 single = "auto",
1944 mixed = "stable,both-edges",
1945 validate_mixed = "Self::has_stable"
1946))]
1947pub struct ScrollbarGutter(u8);
1950bitflags! {
1951 impl ScrollbarGutter: u8 {
1952 const AUTO = 0;
1954 const STABLE = 1 << 0;
1956 const BOTH_EDGES = 1 << 1;
1958 }
1959}
1960
1961impl ScrollbarGutter {
1962 #[inline]
1963 fn has_stable(&self) -> bool {
1964 self.intersects(Self::STABLE)
1965 }
1966}
1967
1968#[derive(
1970 Clone, Copy, Debug, MallocSizeOf, PartialEq, Parse, SpecifiedValueInfo, ToCss, ToShmem, ToTyped,
1971)]
1972#[allow(missing_docs)]
1973pub enum Zoom {
1974 Normal,
1975 #[parse(condition = "ParserContext::in_ua_sheet")]
1978 Document,
1979 Value(NonNegativeNumberOrPercentage),
1980}
1981
1982impl Zoom {
1983 #[inline]
1985 pub fn new_number(n: f32) -> Self {
1986 Self::Value(NonNegativeNumberOrPercentage::new_number(n))
1987 }
1988}
1989
1990pub use crate::values::generics::box_::PositionProperty;