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