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