1use crate::derives::*;
8pub use crate::logical_geometry::WritingModeProperty;
9use crate::parser::{Parse, ParserContext};
10use crate::properties::{LonghandId, PropertyDeclarationId, PropertyId};
11pub use crate::typed_om::{KeywordValue, ToTyped, TypedValue};
12use crate::values::generics::box_::{
13 BaselineShiftKeyword, GenericBaselineShift, GenericContainIntrinsicSize, GenericLineClamp,
14 GenericOverflowClipMargin, GenericPerspective, OverflowClipMarginBox,
15};
16use crate::values::specified::length::{LengthPercentage, NonNegativeLength};
17use crate::values::specified::{AllowQuirks, Integer, NonNegativeNumberOrPercentage};
18use crate::values::CustomIdent;
19use cssparser::Parser;
20use num_traits::FromPrimitive;
21use std::fmt::{self, Write};
22use style_traits::{CssWriter, KeywordsCollectFn, ParseError };
23use style_traits::{SpecifiedValueInfo, StyleParseErrorKind, ToCss};
24use thin_vec::ThinVec;
25
26#[cfg(not(feature = "servo"))]
27fn grid_enabled() -> bool {
28 true
29}
30
31#[cfg(feature = "servo")]
32fn grid_enabled() -> bool {
33 static_prefs::pref!("layout.grid.enabled")
34}
35
36#[inline]
37fn appearance_base_enabled(_context: &ParserContext) -> bool {
38 static_prefs::pref!("layout.css.appearance-base.enabled")
39}
40
41#[inline]
42fn appearance_base_select_enabled(_context: &ParserContext) -> bool {
43 static_prefs::pref!("dom.select.customizable_select.enabled")
44}
45
46pub type OverflowClipMargin = GenericOverflowClipMargin<NonNegativeLength>;
48
49impl Parse for OverflowClipMargin {
50 fn parse<'i>(
52 context: &ParserContext,
53 input: &mut Parser<'i, '_>,
54 ) -> Result<Self, ParseError<'i>> {
55 use crate::Zero;
56 let mut offset = None;
57 let mut visual_box = None;
58 loop {
59 if offset.is_none() {
60 offset = input
61 .try_parse(|i| NonNegativeLength::parse(context, i))
62 .ok();
63 }
64 if visual_box.is_none() {
65 visual_box = input.try_parse(OverflowClipMarginBox::parse).ok();
66 if visual_box.is_some() {
67 continue;
68 }
69 }
70 break;
71 }
72 if offset.is_none() && visual_box.is_none() {
73 return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
74 }
75 Ok(Self {
76 offset: offset.unwrap_or_else(NonNegativeLength::zero),
77 visual_box: visual_box.unwrap_or(OverflowClipMarginBox::PaddingBox),
78 })
79 }
80}
81
82#[allow(missing_docs)]
86#[derive(Clone, Copy, Debug, Eq, FromPrimitive, Hash, MallocSizeOf, PartialEq, ToCss, ToShmem)]
87#[repr(u8)]
88pub enum DisplayOutside {
89 None = 0,
90 Inline,
91 Block,
92 TableCaption,
93 InternalTable,
94 #[cfg(feature = "gecko")]
95 InternalRuby,
96}
97
98#[allow(missing_docs)]
99#[derive(Clone, Copy, Debug, Eq, FromPrimitive, Hash, MallocSizeOf, PartialEq, ToCss, ToShmem)]
100#[repr(u8)]
101pub enum DisplayInside {
102 None = 0,
103 Contents,
104 Flow,
105 FlowRoot,
106 Flex,
107 Grid,
108 Table,
109 TableRowGroup,
110 TableColumn,
111 TableColumnGroup,
112 TableHeaderGroup,
113 TableFooterGroup,
114 TableRow,
115 TableCell,
116 #[cfg(feature = "gecko")]
117 Ruby,
118 #[cfg(feature = "gecko")]
119 RubyBase,
120 #[cfg(feature = "gecko")]
121 RubyBaseContainer,
122 #[cfg(feature = "gecko")]
123 RubyText,
124 #[cfg(feature = "gecko")]
125 RubyTextContainer,
126 #[cfg(feature = "gecko")]
127 WebkitBox,
128}
129
130impl DisplayInside {
131 fn is_valid_for_list_item(self) -> bool {
132 match self {
133 DisplayInside::Flow => true,
134 #[cfg(feature = "gecko")]
135 DisplayInside::FlowRoot => true,
136 _ => false,
137 }
138 }
139
140 fn default_display_outside(self) -> DisplayOutside {
144 match self {
145 #[cfg(feature = "gecko")]
146 DisplayInside::Ruby => DisplayOutside::Inline,
147 _ => DisplayOutside::Block,
148 }
149 }
150}
151
152#[allow(missing_docs)]
153#[derive(
154 Clone,
155 Copy,
156 Debug,
157 Eq,
158 FromPrimitive,
159 Hash,
160 MallocSizeOf,
161 PartialEq,
162 ToComputedValue,
163 ToResolvedValue,
164 ToShmem,
165)]
166#[repr(C)]
167pub struct Display(u16);
168
169#[allow(missing_docs)]
171#[allow(non_upper_case_globals)]
172impl Display {
173 pub const LIST_ITEM_MASK: u16 = 0b1000000000000000;
175 pub const OUTSIDE_MASK: u16 = 0b0111111100000000;
176 pub const INSIDE_MASK: u16 = 0b0000000011111111;
177 pub const OUTSIDE_SHIFT: u16 = 8;
178
179 pub const None: Self =
182 Self(((DisplayOutside::None as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::None as u16);
183 pub const Contents: Self = Self(
184 ((DisplayOutside::None as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Contents as u16,
185 );
186 pub const Inline: Self =
187 Self(((DisplayOutside::Inline as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Flow as u16);
188 pub const InlineBlock: Self = Self(
189 ((DisplayOutside::Inline as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::FlowRoot as u16,
190 );
191 pub const Block: Self =
192 Self(((DisplayOutside::Block as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Flow as u16);
193 #[cfg(feature = "gecko")]
194 pub const FlowRoot: Self = Self(
195 ((DisplayOutside::Block as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::FlowRoot as u16,
196 );
197 pub const Flex: Self =
198 Self(((DisplayOutside::Block as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Flex as u16);
199 pub const InlineFlex: Self =
200 Self(((DisplayOutside::Inline as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Flex as u16);
201 pub const Grid: Self =
202 Self(((DisplayOutside::Block as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Grid as u16);
203 pub const InlineGrid: Self =
204 Self(((DisplayOutside::Inline as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Grid as u16);
205 pub const Table: Self =
206 Self(((DisplayOutside::Block as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Table as u16);
207 pub const InlineTable: Self = Self(
208 ((DisplayOutside::Inline as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Table as u16,
209 );
210 pub const TableCaption: Self = Self(
211 ((DisplayOutside::TableCaption as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Flow as u16,
212 );
213 #[cfg(feature = "gecko")]
214 pub const Ruby: Self =
215 Self(((DisplayOutside::Inline as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Ruby as u16);
216 #[cfg(feature = "gecko")]
217 pub const WebkitBox: Self = Self(
218 ((DisplayOutside::Block as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::WebkitBox as u16,
219 );
220 #[cfg(feature = "gecko")]
221 pub const WebkitInlineBox: Self = Self(
222 ((DisplayOutside::Inline as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::WebkitBox as u16,
223 );
224
225 pub const TableRowGroup: Self = Self(
228 ((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT)
229 | DisplayInside::TableRowGroup as u16,
230 );
231 pub const TableHeaderGroup: Self = Self(
232 ((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT)
233 | DisplayInside::TableHeaderGroup as u16,
234 );
235 pub const TableFooterGroup: Self = Self(
236 ((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT)
237 | DisplayInside::TableFooterGroup as u16,
238 );
239 pub const TableColumn: Self = Self(
240 ((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT)
241 | DisplayInside::TableColumn as u16,
242 );
243 pub const TableColumnGroup: Self = Self(
244 ((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT)
245 | DisplayInside::TableColumnGroup as u16,
246 );
247 pub const TableRow: Self = Self(
248 ((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT)
249 | DisplayInside::TableRow as u16,
250 );
251 pub const TableCell: Self = Self(
252 ((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT)
253 | DisplayInside::TableCell as u16,
254 );
255
256 #[cfg(feature = "gecko")]
258 pub const RubyBase: Self = Self(
259 ((DisplayOutside::InternalRuby as u16) << Self::OUTSIDE_SHIFT)
260 | DisplayInside::RubyBase as u16,
261 );
262 #[cfg(feature = "gecko")]
263 pub const RubyBaseContainer: Self = Self(
264 ((DisplayOutside::InternalRuby as u16) << Self::OUTSIDE_SHIFT)
265 | DisplayInside::RubyBaseContainer as u16,
266 );
267 #[cfg(feature = "gecko")]
268 pub const RubyText: Self = Self(
269 ((DisplayOutside::InternalRuby as u16) << Self::OUTSIDE_SHIFT)
270 | DisplayInside::RubyText as u16,
271 );
272 #[cfg(feature = "gecko")]
273 pub const RubyTextContainer: Self = Self(
274 ((DisplayOutside::InternalRuby as u16) << Self::OUTSIDE_SHIFT)
275 | DisplayInside::RubyTextContainer as u16,
276 );
277
278 #[inline]
280 const fn new(outside: DisplayOutside, inside: DisplayInside) -> Self {
281 Self((outside as u16) << Self::OUTSIDE_SHIFT | inside as u16)
282 }
283
284 #[inline]
286 fn from3(outside: DisplayOutside, inside: DisplayInside, list_item: bool) -> Self {
287 let v = Self::new(outside, inside);
288 if !list_item {
289 return v;
290 }
291 Self(v.0 | Self::LIST_ITEM_MASK)
292 }
293
294 #[inline]
296 pub fn inside(&self) -> DisplayInside {
297 DisplayInside::from_u16(self.0 & Self::INSIDE_MASK).unwrap()
298 }
299
300 #[inline]
302 pub fn outside(&self) -> DisplayOutside {
303 DisplayOutside::from_u16((self.0 & Self::OUTSIDE_MASK) >> Self::OUTSIDE_SHIFT).unwrap()
304 }
305
306 #[inline]
308 pub const fn to_u16(&self) -> u16 {
309 self.0
310 }
311
312 #[inline]
314 pub fn is_inline_flow(&self) -> bool {
315 self.outside() == DisplayOutside::Inline && self.inside() == DisplayInside::Flow
316 }
317
318 #[inline]
320 pub const fn is_list_item(&self) -> bool {
321 (self.0 & Self::LIST_ITEM_MASK) != 0
322 }
323
324 pub fn is_ruby_level_container(&self) -> bool {
326 match *self {
327 #[cfg(feature = "gecko")]
328 Display::RubyBaseContainer | Display::RubyTextContainer => true,
329 _ => false,
330 }
331 }
332
333 pub fn is_ruby_type(&self) -> bool {
335 match self.inside() {
336 #[cfg(feature = "gecko")]
337 DisplayInside::Ruby
338 | DisplayInside::RubyBase
339 | DisplayInside::RubyText
340 | DisplayInside::RubyBaseContainer
341 | DisplayInside::RubyTextContainer => true,
342 _ => false,
343 }
344 }
345}
346
347impl Display {
349 #[inline]
351 pub fn inline() -> Self {
352 Display::Inline
353 }
354
355 pub fn is_item_container(&self) -> bool {
360 match self.inside() {
361 DisplayInside::Flex => true,
362 DisplayInside::Grid => true,
363 _ => false,
364 }
365 }
366
367 pub fn is_line_participant(&self) -> bool {
371 if self.is_inline_flow() {
372 return true;
373 }
374 match *self {
375 #[cfg(feature = "gecko")]
376 Display::Contents | Display::Ruby | Display::RubyBaseContainer => true,
377 _ => false,
378 }
379 }
380
381 pub fn equivalent_block_display(&self, is_root_element: bool) -> Self {
385 if is_root_element && (self.is_contents() || self.is_list_item()) {
387 return Display::Block;
388 }
389
390 match self.outside() {
391 DisplayOutside::Inline => {
392 let inside = match self.inside() {
393 DisplayInside::FlowRoot => DisplayInside::Flow,
396 inside => inside,
397 };
398 Display::from3(DisplayOutside::Block, inside, self.is_list_item())
399 },
400 DisplayOutside::Block | DisplayOutside::None => *self,
401 _ => Display::Block,
402 }
403 }
404
405 #[cfg(feature = "gecko")]
408 pub fn inlinify(&self) -> Self {
409 match self.outside() {
410 DisplayOutside::Block => {
411 let inside = match self.inside() {
412 DisplayInside::Flow => DisplayInside::FlowRoot,
415 inside => inside,
416 };
417 Display::from3(DisplayOutside::Inline, inside, self.is_list_item())
418 },
419 _ => *self,
420 }
421 }
422
423 #[inline]
425 pub fn is_contents(&self) -> bool {
426 match *self {
427 Display::Contents => true,
428 _ => false,
429 }
430 }
431
432 #[inline]
434 pub fn is_none(&self) -> bool {
435 *self == Display::None
436 }
437}
438
439enum DisplayKeyword {
440 Full(Display),
441 Inside(DisplayInside),
442 Outside(DisplayOutside),
443 ListItem,
444}
445
446impl DisplayKeyword {
447 fn parse<'i>(input: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
448 use self::DisplayKeyword::*;
449 Ok(try_match_ident_ignore_ascii_case! { input,
450 "none" => Full(Display::None),
451 "contents" => Full(Display::Contents),
452 "inline-block" => Full(Display::InlineBlock),
453 "inline-table" => Full(Display::InlineTable),
454 "-webkit-flex" => Full(Display::Flex),
455 "inline-flex" | "-webkit-inline-flex" => Full(Display::InlineFlex),
456 "inline-grid" if grid_enabled() => Full(Display::InlineGrid),
457 "table-caption" => Full(Display::TableCaption),
458 "table-row-group" => Full(Display::TableRowGroup),
459 "table-header-group" => Full(Display::TableHeaderGroup),
460 "table-footer-group" => Full(Display::TableFooterGroup),
461 "table-column" => Full(Display::TableColumn),
462 "table-column-group" => Full(Display::TableColumnGroup),
463 "table-row" => Full(Display::TableRow),
464 "table-cell" => Full(Display::TableCell),
465 #[cfg(feature = "gecko")]
466 "ruby-base" => Full(Display::RubyBase),
467 #[cfg(feature = "gecko")]
468 "ruby-base-container" => Full(Display::RubyBaseContainer),
469 #[cfg(feature = "gecko")]
470 "ruby-text" => Full(Display::RubyText),
471 #[cfg(feature = "gecko")]
472 "ruby-text-container" => Full(Display::RubyTextContainer),
473 #[cfg(feature = "gecko")]
474 "-webkit-box" => Full(Display::WebkitBox),
475 #[cfg(feature = "gecko")]
476 "-webkit-inline-box" => Full(Display::WebkitInlineBox),
477
478 "block" => Outside(DisplayOutside::Block),
481 "inline" => Outside(DisplayOutside::Inline),
482
483 "list-item" => ListItem,
484
485 "flow" => Inside(DisplayInside::Flow),
488 "flex" => Inside(DisplayInside::Flex),
489 "flow-root" => Inside(DisplayInside::FlowRoot),
490 "table" => Inside(DisplayInside::Table),
491 "grid" if grid_enabled() => Inside(DisplayInside::Grid),
492 #[cfg(feature = "gecko")]
493 "ruby" => Inside(DisplayInside::Ruby),
494 })
495 }
496}
497
498impl ToCss for Display {
499 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
500 where
501 W: fmt::Write,
502 {
503 let outside = self.outside();
504 let inside = self.inside();
505 match *self {
506 Display::Block | Display::Inline => outside.to_css(dest),
507 Display::InlineBlock => dest.write_str("inline-block"),
508 #[cfg(feature = "gecko")]
509 Display::WebkitInlineBox => dest.write_str("-webkit-inline-box"),
510 Display::TableCaption => dest.write_str("table-caption"),
511 _ => match (outside, inside) {
512 (DisplayOutside::Inline, DisplayInside::Grid) => dest.write_str("inline-grid"),
513 (DisplayOutside::Inline, DisplayInside::Flex) => dest.write_str("inline-flex"),
514 (DisplayOutside::Inline, DisplayInside::Table) => dest.write_str("inline-table"),
515 #[cfg(feature = "gecko")]
516 (DisplayOutside::Block, DisplayInside::Ruby) => dest.write_str("block ruby"),
517 (_, inside) => {
518 if self.is_list_item() {
519 if outside != DisplayOutside::Block {
520 outside.to_css(dest)?;
521 dest.write_char(' ')?;
522 }
523 if inside != DisplayInside::Flow {
524 inside.to_css(dest)?;
525 dest.write_char(' ')?;
526 }
527 dest.write_str("list-item")
528 } else {
529 inside.to_css(dest)
530 }
531 },
532 },
533 }
534 }
535}
536
537impl ToTyped for Display {
538 fn to_typed(&self, dest: &mut ThinVec<TypedValue>) -> Result<(), ()> {
539 let outside = self.outside();
546 let inside = self.inside();
547
548 #[cfg(feature = "gecko")]
549 if outside == DisplayOutside::Block && inside == DisplayInside::Ruby {
550 return Err(());
551 }
552
553 if self.is_list_item()
554 && (outside != DisplayOutside::Block || inside != DisplayInside::Flow)
555 {
556 return Err(());
557 }
558
559 let keyword = self.to_css_cssstring();
560 debug_assert!(!AsRef::<[u8]>::as_ref(&keyword).contains(&b' '));
561
562 dest.push(TypedValue::Keyword(KeywordValue(keyword)));
563 return Ok(());
564 }
565}
566
567impl Parse for Display {
568 fn parse<'i, 't>(
569 _: &ParserContext,
570 input: &mut Parser<'i, 't>,
571 ) -> Result<Display, ParseError<'i>> {
572 let mut got_list_item = false;
573 let mut inside = None;
574 let mut outside = None;
575 match DisplayKeyword::parse(input)? {
576 DisplayKeyword::Full(d) => return Ok(d),
577 DisplayKeyword::Outside(o) => {
578 outside = Some(o);
579 },
580 DisplayKeyword::Inside(i) => {
581 inside = Some(i);
582 },
583 DisplayKeyword::ListItem => {
584 got_list_item = true;
585 },
586 };
587
588 while let Ok(kw) = input.try_parse(DisplayKeyword::parse) {
589 match kw {
590 DisplayKeyword::ListItem if !got_list_item => {
591 got_list_item = true;
592 },
593 DisplayKeyword::Outside(o) if outside.is_none() => {
594 outside = Some(o);
595 },
596 DisplayKeyword::Inside(i) if inside.is_none() => {
597 inside = Some(i);
598 },
599 _ => return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)),
600 }
601 }
602
603 let inside = inside.unwrap_or(DisplayInside::Flow);
604 let outside = outside.unwrap_or_else(|| inside.default_display_outside());
605 if got_list_item && !inside.is_valid_for_list_item() {
606 return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
607 }
608
609 return Ok(Display::from3(outside, inside, got_list_item));
610 }
611}
612
613impl SpecifiedValueInfo for Display {
614 fn collect_completion_keywords(f: KeywordsCollectFn) {
615 f(&[
616 "block",
617 "contents",
618 "flex",
619 "flow-root",
620 "flow-root list-item",
621 "grid",
622 "inline",
623 "inline-block",
624 "inline-flex",
625 "inline-grid",
626 "inline-table",
627 "inline list-item",
628 "inline flow-root list-item",
629 "list-item",
630 "none",
631 "block ruby",
632 "ruby",
633 "ruby-base",
634 "ruby-base-container",
635 "ruby-text",
636 "ruby-text-container",
637 "table",
638 "table-caption",
639 "table-cell",
640 "table-column",
641 "table-column-group",
642 "table-footer-group",
643 "table-header-group",
644 "table-row",
645 "table-row-group",
646 "-webkit-box",
647 "-webkit-inline-box",
648 ]);
649 }
650}
651
652pub type ContainIntrinsicSize = GenericContainIntrinsicSize<NonNegativeLength>;
654
655pub type LineClamp = GenericLineClamp<Integer>;
657
658pub type BaselineShift = GenericBaselineShift<LengthPercentage>;
660
661impl Parse for BaselineShift {
662 fn parse<'i, 't>(
663 context: &ParserContext,
664 input: &mut Parser<'i, 't>,
665 ) -> Result<Self, ParseError<'i>> {
666 if let Ok(lp) =
667 input.try_parse(|i| LengthPercentage::parse_quirky(context, i, AllowQuirks::Yes))
668 {
669 return Ok(BaselineShift::Length(lp));
670 }
671
672 Ok(BaselineShift::Keyword(BaselineShiftKeyword::parse(input)?))
673 }
674}
675
676#[derive(
679 Clone,
680 Copy,
681 Debug,
682 Eq,
683 FromPrimitive,
684 Hash,
685 MallocSizeOf,
686 Parse,
687 PartialEq,
688 SpecifiedValueInfo,
689 ToCss,
690 ToShmem,
691 ToComputedValue,
692 ToResolvedValue,
693 ToTyped,
694)]
695#[repr(u8)]
696pub enum DominantBaseline {
697 Auto,
701 #[parse(aliases = "text-after-edge")]
703 TextBottom,
704 Alphabetic,
706 Ideographic,
708 Middle,
712 Central,
714 Mathematical,
716 Hanging,
718 #[parse(aliases = "text-before-edge")]
720 TextTop,
721}
722
723#[derive(
726 Clone,
727 Copy,
728 Debug,
729 Eq,
730 FromPrimitive,
731 Hash,
732 MallocSizeOf,
733 Parse,
734 PartialEq,
735 SpecifiedValueInfo,
736 ToCss,
737 ToShmem,
738 ToComputedValue,
739 ToResolvedValue,
740 ToTyped,
741)]
742#[repr(u8)]
743pub enum AlignmentBaseline {
744 Baseline,
746 TextBottom,
748 #[cfg(feature = "gecko")]
750 Alphabetic,
751 #[cfg(feature = "gecko")]
753 Ideographic,
754 Middle,
758 #[cfg(feature = "gecko")]
760 Central,
761 #[cfg(feature = "gecko")]
763 Mathematical,
764 #[cfg(feature = "gecko")]
766 Hanging,
767 TextTop,
769 #[cfg(feature = "gecko")]
771 MozMiddleWithBaseline,
772}
773
774#[derive(
777 Clone,
778 Copy,
779 Debug,
780 Eq,
781 Hash,
782 MallocSizeOf,
783 Parse,
784 PartialEq,
785 SpecifiedValueInfo,
786 ToCss,
787 ToShmem,
788 ToComputedValue,
789 ToResolvedValue,
790 ToTyped,
791)]
792#[repr(u8)]
793pub enum BaselineSource {
794 Auto,
796 First,
798 Last,
800}
801
802impl BaselineSource {
803 pub fn parse_non_auto<'i>(input: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
805 Ok(try_match_ident_ignore_ascii_case! { input,
806 "first" => Self::First,
807 "last" => Self::Last,
808 })
809 }
810}
811
812#[allow(missing_docs)]
814#[derive(
815 Clone,
816 Copy,
817 Debug,
818 Deserialize,
819 Eq,
820 MallocSizeOf,
821 Parse,
822 PartialEq,
823 Serialize,
824 SpecifiedValueInfo,
825 ToComputedValue,
826 ToCss,
827 ToResolvedValue,
828 ToShmem,
829)]
830#[repr(u8)]
831pub enum ScrollSnapAxis {
832 X,
833 Y,
834 Block,
835 Inline,
836 Both,
837}
838
839#[allow(missing_docs)]
841#[derive(
842 Clone,
843 Copy,
844 Debug,
845 Deserialize,
846 Eq,
847 MallocSizeOf,
848 Parse,
849 PartialEq,
850 Serialize,
851 SpecifiedValueInfo,
852 ToComputedValue,
853 ToCss,
854 ToResolvedValue,
855 ToShmem,
856)]
857#[repr(u8)]
858pub enum ScrollSnapStrictness {
859 #[css(skip)]
860 None, Mandatory,
862 Proximity,
863}
864
865#[allow(missing_docs)]
867#[derive(
868 Clone,
869 Copy,
870 Debug,
871 Deserialize,
872 Eq,
873 MallocSizeOf,
874 PartialEq,
875 Serialize,
876 SpecifiedValueInfo,
877 ToComputedValue,
878 ToResolvedValue,
879 ToShmem,
880 ToTyped,
881)]
882#[repr(C)]
883#[typed(todo_derive_fields)]
884pub struct ScrollSnapType {
885 axis: ScrollSnapAxis,
886 strictness: ScrollSnapStrictness,
887}
888
889impl ScrollSnapType {
890 #[inline]
892 pub fn none() -> Self {
893 Self {
894 axis: ScrollSnapAxis::Both,
895 strictness: ScrollSnapStrictness::None,
896 }
897 }
898}
899
900impl Parse for ScrollSnapType {
901 fn parse<'i, 't>(
903 _context: &ParserContext,
904 input: &mut Parser<'i, 't>,
905 ) -> Result<Self, ParseError<'i>> {
906 if input
907 .try_parse(|input| input.expect_ident_matching("none"))
908 .is_ok()
909 {
910 return Ok(ScrollSnapType::none());
911 }
912
913 let axis = ScrollSnapAxis::parse(input)?;
914 let strictness = input
915 .try_parse(ScrollSnapStrictness::parse)
916 .unwrap_or(ScrollSnapStrictness::Proximity);
917 Ok(Self { axis, strictness })
918 }
919}
920
921impl ToCss for ScrollSnapType {
922 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
923 where
924 W: Write,
925 {
926 if self.strictness == ScrollSnapStrictness::None {
927 return dest.write_str("none");
928 }
929 self.axis.to_css(dest)?;
930 if self.strictness != ScrollSnapStrictness::Proximity {
931 dest.write_char(' ')?;
932 self.strictness.to_css(dest)?;
933 }
934 Ok(())
935 }
936}
937
938#[allow(missing_docs)]
940#[derive(
941 Clone,
942 Copy,
943 Debug,
944 Eq,
945 FromPrimitive,
946 Hash,
947 MallocSizeOf,
948 Parse,
949 PartialEq,
950 SpecifiedValueInfo,
951 ToComputedValue,
952 ToCss,
953 ToResolvedValue,
954 ToShmem,
955)]
956#[repr(u8)]
957pub enum ScrollSnapAlignKeyword {
958 None,
959 Start,
960 End,
961 Center,
962}
963
964#[allow(missing_docs)]
966#[derive(
967 Clone,
968 Copy,
969 Debug,
970 Eq,
971 MallocSizeOf,
972 PartialEq,
973 SpecifiedValueInfo,
974 ToComputedValue,
975 ToResolvedValue,
976 ToShmem,
977 ToTyped,
978)]
979#[repr(C)]
980#[typed(todo_derive_fields)]
981pub struct ScrollSnapAlign {
982 block: ScrollSnapAlignKeyword,
983 inline: ScrollSnapAlignKeyword,
984}
985
986impl ScrollSnapAlign {
987 #[inline]
989 pub fn none() -> Self {
990 ScrollSnapAlign {
991 block: ScrollSnapAlignKeyword::None,
992 inline: ScrollSnapAlignKeyword::None,
993 }
994 }
995}
996
997impl Parse for ScrollSnapAlign {
998 fn parse<'i, 't>(
1000 _context: &ParserContext,
1001 input: &mut Parser<'i, 't>,
1002 ) -> Result<ScrollSnapAlign, ParseError<'i>> {
1003 let block = ScrollSnapAlignKeyword::parse(input)?;
1004 let inline = input
1005 .try_parse(ScrollSnapAlignKeyword::parse)
1006 .unwrap_or(block);
1007 Ok(ScrollSnapAlign { block, inline })
1008 }
1009}
1010
1011impl ToCss for ScrollSnapAlign {
1012 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
1013 where
1014 W: Write,
1015 {
1016 self.block.to_css(dest)?;
1017 if self.block != self.inline {
1018 dest.write_char(' ')?;
1019 self.inline.to_css(dest)?;
1020 }
1021 Ok(())
1022 }
1023}
1024
1025#[allow(missing_docs)]
1026#[derive(
1027 Clone,
1028 Copy,
1029 Debug,
1030 Deserialize,
1031 Eq,
1032 MallocSizeOf,
1033 Parse,
1034 PartialEq,
1035 Serialize,
1036 SpecifiedValueInfo,
1037 ToComputedValue,
1038 ToCss,
1039 ToResolvedValue,
1040 ToShmem,
1041 ToTyped,
1042)]
1043#[repr(u8)]
1044pub enum ScrollSnapStop {
1045 Normal,
1046 Always,
1047}
1048
1049#[allow(missing_docs)]
1050#[derive(
1051 Clone,
1052 Copy,
1053 Debug,
1054 Deserialize,
1055 Eq,
1056 MallocSizeOf,
1057 Parse,
1058 PartialEq,
1059 Serialize,
1060 SpecifiedValueInfo,
1061 ToComputedValue,
1062 ToCss,
1063 ToResolvedValue,
1064 ToShmem,
1065 ToTyped,
1066)]
1067#[repr(u8)]
1068pub enum OverscrollBehavior {
1069 Auto,
1070 Contain,
1071 None,
1072}
1073
1074#[allow(missing_docs)]
1075#[derive(
1076 Clone,
1077 Copy,
1078 Debug,
1079 Deserialize,
1080 Eq,
1081 MallocSizeOf,
1082 Parse,
1083 PartialEq,
1084 Serialize,
1085 SpecifiedValueInfo,
1086 ToComputedValue,
1087 ToCss,
1088 ToResolvedValue,
1089 ToShmem,
1090 ToTyped,
1091)]
1092#[repr(u8)]
1093pub enum OverflowAnchor {
1094 Auto,
1095 None,
1096}
1097
1098#[derive(
1099 Clone,
1100 Debug,
1101 Default,
1102 MallocSizeOf,
1103 PartialEq,
1104 SpecifiedValueInfo,
1105 ToComputedValue,
1106 ToCss,
1107 ToResolvedValue,
1108 ToShmem,
1109 ToTyped,
1110)]
1111#[css(comma)]
1112#[repr(C)]
1113#[typed(no_multiple_values)]
1114pub struct WillChange {
1121 #[css(iterable, if_empty = "auto")]
1126 features: crate::OwnedSlice<CustomIdent>,
1127 #[css(skip)]
1130 pub bits: WillChangeBits,
1131}
1132
1133impl WillChange {
1134 #[inline]
1135 pub fn auto() -> Self {
1137 Self::default()
1138 }
1139}
1140
1141#[derive(
1143 Clone,
1144 Copy,
1145 Debug,
1146 Default,
1147 Eq,
1148 MallocSizeOf,
1149 PartialEq,
1150 SpecifiedValueInfo,
1151 ToComputedValue,
1152 ToResolvedValue,
1153 ToShmem,
1154)]
1155#[repr(C)]
1156pub struct WillChangeBits(u16);
1157bitflags! {
1158 impl WillChangeBits: u16 {
1159 const STACKING_CONTEXT_UNCONDITIONAL = 1 << 0;
1162 const TRANSFORM = 1 << 1;
1164 const SCROLL = 1 << 2;
1166 const CONTAIN = 1 << 3;
1168 const OPACITY = 1 << 4;
1170 const PERSPECTIVE = 1 << 5;
1172 const Z_INDEX = 1 << 6;
1174 const FIXPOS_CB_NON_SVG = 1 << 7;
1177 const POSITION = 1 << 8;
1179 const VIEW_TRANSITION_NAME = 1 << 9;
1181 const BACKDROP_ROOT = 1 << 10;
1184 }
1185}
1186
1187fn change_bits_for_longhand(longhand: LonghandId) -> WillChangeBits {
1188 match longhand {
1189 LonghandId::Opacity => WillChangeBits::OPACITY | WillChangeBits::BACKDROP_ROOT,
1190 LonghandId::Contain => WillChangeBits::CONTAIN,
1191 LonghandId::Perspective => WillChangeBits::PERSPECTIVE,
1192 LonghandId::Position => {
1193 WillChangeBits::STACKING_CONTEXT_UNCONDITIONAL | WillChangeBits::POSITION
1194 },
1195 LonghandId::ZIndex => WillChangeBits::Z_INDEX,
1196 LonghandId::Transform
1197 | LonghandId::TransformStyle
1198 | LonghandId::Translate
1199 | LonghandId::Rotate
1200 | LonghandId::Scale
1201 | LonghandId::OffsetPath => WillChangeBits::TRANSFORM,
1202 LonghandId::Filter | LonghandId::BackdropFilter => {
1203 WillChangeBits::STACKING_CONTEXT_UNCONDITIONAL
1204 | WillChangeBits::BACKDROP_ROOT
1205 | WillChangeBits::FIXPOS_CB_NON_SVG
1206 },
1207 LonghandId::ViewTransitionName => {
1208 WillChangeBits::VIEW_TRANSITION_NAME | WillChangeBits::BACKDROP_ROOT
1209 },
1210 LonghandId::MixBlendMode => {
1211 WillChangeBits::STACKING_CONTEXT_UNCONDITIONAL | WillChangeBits::BACKDROP_ROOT
1212 },
1213 LonghandId::Isolation | LonghandId::MaskImage => {
1214 WillChangeBits::STACKING_CONTEXT_UNCONDITIONAL
1215 },
1216 LonghandId::ClipPath => {
1217 WillChangeBits::STACKING_CONTEXT_UNCONDITIONAL | WillChangeBits::BACKDROP_ROOT
1218 },
1219 _ => WillChangeBits::empty(),
1220 }
1221}
1222
1223fn change_bits_for_maybe_property(ident: &str, context: &ParserContext) -> WillChangeBits {
1224 let id = match PropertyId::parse_ignoring_rule_type(ident, context) {
1225 Ok(id) => id,
1226 Err(..) => return WillChangeBits::empty(),
1227 };
1228
1229 match id.as_shorthand() {
1230 Ok(shorthand) => shorthand
1231 .longhands()
1232 .fold(WillChangeBits::empty(), |flags, p| {
1233 flags | change_bits_for_longhand(p)
1234 }),
1235 Err(PropertyDeclarationId::Longhand(longhand)) => change_bits_for_longhand(longhand),
1236 Err(PropertyDeclarationId::Custom(..)) => WillChangeBits::empty(),
1237 }
1238}
1239
1240impl Parse for WillChange {
1241 fn parse<'i, 't>(
1243 context: &ParserContext,
1244 input: &mut Parser<'i, 't>,
1245 ) -> Result<Self, ParseError<'i>> {
1246 if input
1247 .try_parse(|input| input.expect_ident_matching("auto"))
1248 .is_ok()
1249 {
1250 return Ok(Self::default());
1251 }
1252
1253 let mut bits = WillChangeBits::empty();
1254 let custom_idents = input.parse_comma_separated(|i| {
1255 let location = i.current_source_location();
1256 let parser_ident = i.expect_ident()?;
1257 let ident = CustomIdent::from_ident(
1258 location,
1259 parser_ident,
1260 &["will-change", "none", "all", "auto"],
1261 )?;
1262
1263 if context.in_ua_sheet() && ident.0 == atom!("-moz-fixed-pos-containing-block") {
1264 bits |= WillChangeBits::FIXPOS_CB_NON_SVG;
1265 } else if ident.0 == atom!("scroll-position") {
1266 bits |= WillChangeBits::SCROLL;
1267 } else {
1268 bits |= change_bits_for_maybe_property(&parser_ident, context);
1269 }
1270 Ok(ident)
1271 })?;
1272
1273 Ok(Self {
1274 features: custom_idents.into(),
1275 bits,
1276 })
1277 }
1278}
1279
1280#[derive(
1282 Clone,
1283 Copy,
1284 Debug,
1285 Eq,
1286 MallocSizeOf,
1287 Parse,
1288 PartialEq,
1289 SpecifiedValueInfo,
1290 ToComputedValue,
1291 ToCss,
1292 ToResolvedValue,
1293 ToShmem,
1294 ToTyped,
1295)]
1296#[css(bitflags(single = "none,auto,manipulation", mixed = "pan-x,pan-y,pinch-zoom"))]
1297#[repr(C)]
1298pub struct TouchAction(u8);
1299bitflags! {
1300 impl TouchAction: u8 {
1301 const NONE = 1 << 0;
1303 const AUTO = 1 << 1;
1305 const PAN_X = 1 << 2;
1307 const PAN_Y = 1 << 3;
1309 const MANIPULATION = 1 << 4;
1311 const PINCH_ZOOM = 1 << 5;
1313 }
1314}
1315
1316impl TouchAction {
1317 #[inline]
1318 pub fn auto() -> TouchAction {
1320 TouchAction::AUTO
1321 }
1322}
1323
1324#[derive(
1325 Clone,
1326 Copy,
1327 Debug,
1328 Eq,
1329 MallocSizeOf,
1330 Parse,
1331 PartialEq,
1332 SpecifiedValueInfo,
1333 ToComputedValue,
1334 ToCss,
1335 ToResolvedValue,
1336 ToShmem,
1337 ToTyped,
1338)]
1339#[css(bitflags(
1340 single = "none,strict,content",
1341 mixed = "size,layout,style,paint,inline-size",
1342 overlapping_bits
1343))]
1344#[repr(C)]
1345pub struct Contain(u8);
1347bitflags! {
1348 impl Contain: u8 {
1349 const NONE = 0;
1351 const INLINE_SIZE = 1 << 0;
1353 const BLOCK_SIZE = 1 << 1;
1355 const LAYOUT = 1 << 2;
1357 const STYLE = 1 << 3;
1359 const PAINT = 1 << 4;
1361 const SIZE = 1 << 5 | Contain::INLINE_SIZE.bits() | Contain::BLOCK_SIZE.bits();
1363 const CONTENT = 1 << 6 | Contain::LAYOUT.bits() | Contain::STYLE.bits() | Contain::PAINT.bits();
1365 const STRICT = 1 << 7 | Contain::LAYOUT.bits() | Contain::STYLE.bits() | Contain::PAINT.bits() | Contain::SIZE.bits();
1367 }
1368}
1369
1370impl Parse for ContainIntrinsicSize {
1371 fn parse<'i, 't>(
1373 context: &ParserContext,
1374 input: &mut Parser<'i, 't>,
1375 ) -> Result<Self, ParseError<'i>> {
1376 if let Ok(l) = input.try_parse(|i| NonNegativeLength::parse(context, i)) {
1377 return Ok(Self::Length(l));
1378 }
1379
1380 if input.try_parse(|i| i.expect_ident_matching("auto")).is_ok() {
1381 if input.try_parse(|i| i.expect_ident_matching("none")).is_ok() {
1382 return Ok(Self::AutoNone);
1383 }
1384
1385 let l = NonNegativeLength::parse(context, input)?;
1386 return Ok(Self::AutoLength(l));
1387 }
1388
1389 input.expect_ident_matching("none")?;
1390 Ok(Self::None)
1391 }
1392}
1393
1394impl Parse for LineClamp {
1395 fn parse<'i, 't>(
1397 context: &ParserContext,
1398 input: &mut Parser<'i, 't>,
1399 ) -> Result<Self, ParseError<'i>> {
1400 if let Ok(i) =
1401 input.try_parse(|i| crate::values::specified::PositiveInteger::parse(context, i))
1402 {
1403 return Ok(Self(i.0));
1404 }
1405 input.expect_ident_matching("none")?;
1406 Ok(Self::none())
1407 }
1408}
1409
1410#[derive(
1412 Clone,
1413 Copy,
1414 Debug,
1415 Deserialize,
1416 Eq,
1417 FromPrimitive,
1418 MallocSizeOf,
1419 Parse,
1420 PartialEq,
1421 Serialize,
1422 SpecifiedValueInfo,
1423 ToAnimatedValue,
1424 ToComputedValue,
1425 ToCss,
1426 ToResolvedValue,
1427 ToShmem,
1428 ToTyped,
1429)]
1430#[repr(u8)]
1431pub enum ContentVisibility {
1432 Auto,
1436 Hidden,
1438 Visible,
1440}
1441
1442#[derive(
1443 Clone,
1444 Copy,
1445 Debug,
1446 PartialEq,
1447 Eq,
1448 MallocSizeOf,
1449 SpecifiedValueInfo,
1450 ToComputedValue,
1451 ToCss,
1452 Parse,
1453 ToResolvedValue,
1454 ToShmem,
1455 ToTyped,
1456)]
1457#[css(bitflags(
1458 single = "normal",
1459 mixed = "size,inline-size,scroll-state",
1460 validate_mixed = "Self::validate_mixed_flags",
1461))]
1462#[repr(C)]
1463pub struct ContainerType(u8);
1470bitflags! {
1471 impl ContainerType: u8 {
1472 const NORMAL = 0;
1474 const INLINE_SIZE = 1 << 0;
1476 const SIZE = 1 << 1;
1478 const SCROLL_STATE = 1 << 2;
1480 }
1481}
1482
1483impl ContainerType {
1484 fn validate_mixed_flags(&self) -> bool {
1485 if self.contains(Self::SIZE | Self::INLINE_SIZE) {
1487 return false;
1488 }
1489 if self.contains(Self::SCROLL_STATE)
1490 && !static_prefs::pref!("layout.css.scroll-state.enabled")
1491 {
1492 return false;
1493 }
1494 true
1495 }
1496
1497 pub fn is_normal(self) -> bool {
1499 self == Self::NORMAL
1500 }
1501
1502 pub fn is_size_container_type(self) -> bool {
1504 self.intersects(Self::SIZE | Self::INLINE_SIZE)
1505 }
1506}
1507
1508#[repr(transparent)]
1510#[derive(
1511 Clone,
1512 Debug,
1513 MallocSizeOf,
1514 PartialEq,
1515 SpecifiedValueInfo,
1516 ToComputedValue,
1517 ToCss,
1518 ToResolvedValue,
1519 ToShmem,
1520 ToTyped,
1521)]
1522pub struct ContainerName(#[css(iterable, if_empty = "none")] pub crate::OwnedSlice<CustomIdent>);
1523
1524impl ContainerName {
1525 pub fn none() -> Self {
1527 Self(Default::default())
1528 }
1529
1530 pub fn is_none(&self) -> bool {
1532 self.0.is_empty()
1533 }
1534
1535 fn parse_internal<'i>(
1536 input: &mut Parser<'i, '_>,
1537 for_query: bool,
1538 ) -> Result<Self, ParseError<'i>> {
1539 let mut idents = vec![];
1540 let location = input.current_source_location();
1541 let first = input.expect_ident()?;
1542 if !for_query && first.eq_ignore_ascii_case("none") {
1543 return Ok(Self::none());
1544 }
1545 const DISALLOWED_CONTAINER_NAMES: &'static [&'static str] = &["none", "not", "or", "and"];
1546 idents.push(CustomIdent::from_ident(
1547 location,
1548 first,
1549 DISALLOWED_CONTAINER_NAMES,
1550 )?);
1551 if !for_query {
1552 while let Ok(name) =
1553 input.try_parse(|input| CustomIdent::parse(input, DISALLOWED_CONTAINER_NAMES))
1554 {
1555 idents.push(name);
1556 }
1557 }
1558 Ok(ContainerName(idents.into()))
1559 }
1560
1561 pub fn parse_for_query<'i, 't>(
1565 _: &ParserContext,
1566 input: &mut Parser<'i, 't>,
1567 ) -> Result<Self, ParseError<'i>> {
1568 Self::parse_internal(input, true)
1569 }
1570}
1571
1572impl Parse for ContainerName {
1573 fn parse<'i, 't>(
1574 _: &ParserContext,
1575 input: &mut Parser<'i, 't>,
1576 ) -> Result<Self, ParseError<'i>> {
1577 Self::parse_internal(input, false)
1578 }
1579}
1580
1581pub type Perspective = GenericPerspective<NonNegativeLength>;
1583
1584#[allow(missing_docs)]
1586#[derive(
1587 Clone,
1588 Copy,
1589 Debug,
1590 Deserialize,
1591 Eq,
1592 FromPrimitive,
1593 Hash,
1594 MallocSizeOf,
1595 Parse,
1596 PartialEq,
1597 Serialize,
1598 SpecifiedValueInfo,
1599 ToComputedValue,
1600 ToCss,
1601 ToResolvedValue,
1602 ToShmem,
1603 ToTyped,
1604)]
1605#[repr(u8)]
1606pub enum Float {
1607 Left,
1608 Right,
1609 None,
1610 InlineStart,
1612 InlineEnd,
1613}
1614
1615impl Float {
1616 pub fn is_floating(self) -> bool {
1618 self != Self::None
1619 }
1620}
1621
1622#[allow(missing_docs)]
1624#[derive(
1625 Clone,
1626 Copy,
1627 Debug,
1628 Deserialize,
1629 Eq,
1630 FromPrimitive,
1631 Hash,
1632 MallocSizeOf,
1633 Parse,
1634 PartialEq,
1635 Serialize,
1636 SpecifiedValueInfo,
1637 ToComputedValue,
1638 ToCss,
1639 ToResolvedValue,
1640 ToShmem,
1641 ToTyped,
1642)]
1643#[repr(u8)]
1644pub enum Clear {
1645 None,
1646 Left,
1647 Right,
1648 Both,
1649 InlineStart,
1651 InlineEnd,
1652}
1653
1654#[allow(missing_docs)]
1656#[derive(
1657 Clone,
1658 Copy,
1659 Debug,
1660 Deserialize,
1661 Eq,
1662 Hash,
1663 MallocSizeOf,
1664 Parse,
1665 PartialEq,
1666 Serialize,
1667 SpecifiedValueInfo,
1668 ToCss,
1669 ToShmem,
1670 ToTyped,
1671)]
1672pub enum Resize {
1673 None,
1674 Both,
1675 Horizontal,
1676 Vertical,
1677 Inline,
1679 Block,
1680}
1681
1682#[allow(missing_docs)]
1686#[derive(
1687 Clone,
1688 Copy,
1689 Debug,
1690 Eq,
1691 Hash,
1692 MallocSizeOf,
1693 Parse,
1694 PartialEq,
1695 SpecifiedValueInfo,
1696 ToCss,
1697 ToComputedValue,
1698 ToResolvedValue,
1699 ToShmem,
1700 ToTyped,
1701)]
1702#[repr(u8)]
1703pub enum Appearance {
1704 None,
1706 Auto,
1711 Searchfield,
1713 Textarea,
1715 Checkbox,
1717 Radio,
1719 Menulist,
1721 Listbox,
1723 Meter,
1725 ProgressBar,
1727 Button,
1729 Textfield,
1731 MenulistButton,
1733 #[parse(condition = "appearance_base_enabled")]
1735 Base,
1736 #[parse(condition = "appearance_base_select_enabled")]
1739 BaseSelect,
1740 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1742 Menupopup,
1743 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1745 MozMenulistArrowButton,
1746 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1748 NumberInput,
1749 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1751 PasswordInput,
1752 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1754 Range,
1755 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1757 ScrollbarHorizontal,
1758 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1759 ScrollbarVertical,
1760 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1764 ScrollbarbuttonUp,
1765 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1766 ScrollbarbuttonDown,
1767 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1768 ScrollbarbuttonLeft,
1769 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1770 ScrollbarbuttonRight,
1771 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1773 ScrollbarthumbHorizontal,
1774 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1775 ScrollbarthumbVertical,
1776 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1778 Scrollcorner,
1779 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1781 SpinnerUpbutton,
1782 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1784 SpinnerDownbutton,
1785 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1787 Toolbarbutton,
1788 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1790 Tooltip,
1791
1792 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1794 MozSidebar,
1795
1796 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1798 MozMacHelpButton,
1799
1800 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1804 MozMacWindow,
1805
1806 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1808 MozWindowButtonBox,
1809 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1810 MozWindowButtonClose,
1811 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1812 MozWindowButtonMaximize,
1813 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1814 MozWindowButtonMinimize,
1815 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1816 MozWindowButtonRestore,
1817 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1818 MozWindowTitlebar,
1819 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1820 MozWindowTitlebarMaximized,
1821 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1822 MozWindowDecorations,
1823
1824 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1825 MozMacDisclosureButtonClosed,
1826 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1827 MozMacDisclosureButtonOpen,
1828
1829 #[css(skip)]
1833 FocusOutline,
1834
1835 #[css(skip)]
1837 Count,
1838}
1839
1840#[allow(missing_docs)]
1844#[derive(
1845 Clone,
1846 Copy,
1847 Debug,
1848 Eq,
1849 Hash,
1850 MallocSizeOf,
1851 Parse,
1852 PartialEq,
1853 SpecifiedValueInfo,
1854 ToCss,
1855 ToComputedValue,
1856 ToResolvedValue,
1857 ToShmem,
1858 ToTyped,
1859)]
1860#[repr(u8)]
1861pub enum BreakBetween {
1862 Always,
1863 Auto,
1864 Page,
1865 Avoid,
1866 Left,
1867 Right,
1868}
1869
1870impl BreakBetween {
1871 #[cfg_attr(feature = "servo", allow(unused))]
1875 #[inline]
1876 pub(crate) fn parse_legacy<'i>(
1877 _: &ParserContext,
1878 input: &mut Parser<'i, '_>,
1879 ) -> Result<Self, ParseError<'i>> {
1880 let break_value = BreakBetween::parse(input)?;
1881 match break_value {
1882 BreakBetween::Always => Ok(BreakBetween::Page),
1883 BreakBetween::Auto | BreakBetween::Avoid | BreakBetween::Left | BreakBetween::Right => {
1884 Ok(break_value)
1885 },
1886 BreakBetween::Page => {
1887 Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
1888 },
1889 }
1890 }
1891
1892 #[cfg_attr(feature = "servo", allow(unused))]
1896 pub(crate) fn to_css_legacy<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
1897 where
1898 W: Write,
1899 {
1900 match *self {
1901 BreakBetween::Auto | BreakBetween::Avoid | BreakBetween::Left | BreakBetween::Right => {
1902 self.to_css(dest)
1903 },
1904 BreakBetween::Page => dest.write_str("always"),
1905 BreakBetween::Always => Ok(()),
1906 }
1907 }
1908}
1909
1910#[allow(missing_docs)]
1914#[derive(
1915 Clone,
1916 Copy,
1917 Debug,
1918 Eq,
1919 Hash,
1920 MallocSizeOf,
1921 Parse,
1922 PartialEq,
1923 SpecifiedValueInfo,
1924 ToCss,
1925 ToComputedValue,
1926 ToResolvedValue,
1927 ToShmem,
1928 ToTyped,
1929)]
1930#[repr(u8)]
1931pub enum BreakWithin {
1932 Auto,
1933 Avoid,
1934 AvoidPage,
1935 AvoidColumn,
1936}
1937
1938impl BreakWithin {
1939 #[cfg_attr(feature = "servo", allow(unused))]
1943 #[inline]
1944 pub(crate) fn parse_legacy<'i>(
1945 _: &ParserContext,
1946 input: &mut Parser<'i, '_>,
1947 ) -> Result<Self, ParseError<'i>> {
1948 let break_value = BreakWithin::parse(input)?;
1949 match break_value {
1950 BreakWithin::Auto | BreakWithin::Avoid => Ok(break_value),
1951 BreakWithin::AvoidPage | BreakWithin::AvoidColumn => {
1952 Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
1953 },
1954 }
1955 }
1956
1957 #[cfg_attr(feature = "servo", allow(unused))]
1961 pub(crate) fn to_css_legacy<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
1962 where
1963 W: Write,
1964 {
1965 match *self {
1966 BreakWithin::Auto | BreakWithin::Avoid => self.to_css(dest),
1967 BreakWithin::AvoidPage | BreakWithin::AvoidColumn => Ok(()),
1968 }
1969 }
1970}
1971
1972#[allow(missing_docs)]
1974#[derive(
1975 Clone,
1976 Copy,
1977 Debug,
1978 Eq,
1979 Hash,
1980 MallocSizeOf,
1981 PartialEq,
1982 SpecifiedValueInfo,
1983 ToCss,
1984 ToComputedValue,
1985 ToResolvedValue,
1986 ToShmem,
1987 ToTyped,
1988)]
1989#[repr(u8)]
1990pub enum Overflow {
1991 Visible,
1992 Hidden,
1993 Scroll,
1994 Auto,
1995 Clip,
1996}
1997
1998impl Parse for Overflow {
2001 fn parse<'i, 't>(
2002 _: &ParserContext,
2003 input: &mut Parser<'i, 't>,
2004 ) -> Result<Self, ParseError<'i>> {
2005 Ok(try_match_ident_ignore_ascii_case! { input,
2006 "visible" => Self::Visible,
2007 "hidden" => Self::Hidden,
2008 "scroll" => Self::Scroll,
2009 "auto" | "overlay" => Self::Auto,
2010 "clip" => Self::Clip,
2011 #[cfg(feature = "gecko")]
2012 "-moz-hidden-unscrollable" if static_prefs::pref!("layout.css.overflow-moz-hidden-unscrollable.enabled") => {
2013 Overflow::Clip
2014 },
2015 })
2016 }
2017}
2018
2019impl Overflow {
2020 #[inline]
2022 pub fn is_scrollable(&self) -> bool {
2023 matches!(*self, Self::Hidden | Self::Scroll | Self::Auto)
2024 }
2025 #[inline]
2028 pub fn to_scrollable(&self) -> Self {
2029 match *self {
2030 Self::Hidden | Self::Scroll | Self::Auto => *self,
2031 Self::Visible => Self::Auto,
2032 Self::Clip => Self::Hidden,
2033 }
2034 }
2035}
2036
2037#[derive(
2038 Clone,
2039 Copy,
2040 Debug,
2041 Eq,
2042 MallocSizeOf,
2043 Parse,
2044 PartialEq,
2045 SpecifiedValueInfo,
2046 ToComputedValue,
2047 ToCss,
2048 ToResolvedValue,
2049 ToShmem,
2050 ToTyped,
2051)]
2052#[repr(C)]
2053#[css(bitflags(
2054 single = "auto",
2055 mixed = "stable,both-edges",
2056 validate_mixed = "Self::has_stable"
2057))]
2058pub struct ScrollbarGutter(u8);
2061bitflags! {
2062 impl ScrollbarGutter: u8 {
2063 const AUTO = 0;
2065 const STABLE = 1 << 0;
2067 const BOTH_EDGES = 1 << 1;
2069 }
2070}
2071
2072impl ScrollbarGutter {
2073 #[inline]
2074 fn has_stable(&self) -> bool {
2075 self.intersects(Self::STABLE)
2076 }
2077}
2078
2079#[derive(
2081 Clone, Debug, MallocSizeOf, PartialEq, Parse, SpecifiedValueInfo, ToCss, ToShmem, ToTyped,
2082)]
2083#[allow(missing_docs)]
2084#[typed(todo_derive_fields)]
2085pub enum Zoom {
2086 Normal,
2087 #[parse(condition = "ParserContext::in_ua_sheet")]
2090 Document,
2091 Value(NonNegativeNumberOrPercentage),
2092}
2093
2094impl Zoom {
2095 #[inline]
2097 pub fn new_number(n: f32) -> Self {
2098 Self::Value(NonNegativeNumberOrPercentage::new_number(n))
2099 }
2100}
2101
2102pub use crate::values::generics::box_::PositionProperty;