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)]
166#[typed(todo_derive_fields)]
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 Parse for Display {
538 fn parse<'i, 't>(
539 _: &ParserContext,
540 input: &mut Parser<'i, 't>,
541 ) -> Result<Display, ParseError<'i>> {
542 let mut got_list_item = false;
543 let mut inside = None;
544 let mut outside = None;
545 match DisplayKeyword::parse(input)? {
546 DisplayKeyword::Full(d) => return Ok(d),
547 DisplayKeyword::Outside(o) => {
548 outside = Some(o);
549 },
550 DisplayKeyword::Inside(i) => {
551 inside = Some(i);
552 },
553 DisplayKeyword::ListItem => {
554 got_list_item = true;
555 },
556 };
557
558 while let Ok(kw) = input.try_parse(DisplayKeyword::parse) {
559 match kw {
560 DisplayKeyword::ListItem if !got_list_item => {
561 got_list_item = true;
562 },
563 DisplayKeyword::Outside(o) if outside.is_none() => {
564 outside = Some(o);
565 },
566 DisplayKeyword::Inside(i) if inside.is_none() => {
567 inside = Some(i);
568 },
569 _ => return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)),
570 }
571 }
572
573 let inside = inside.unwrap_or(DisplayInside::Flow);
574 let outside = outside.unwrap_or_else(|| inside.default_display_outside());
575 if got_list_item && !inside.is_valid_for_list_item() {
576 return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
577 }
578
579 return Ok(Display::from3(outside, inside, got_list_item));
580 }
581}
582
583impl SpecifiedValueInfo for Display {
584 fn collect_completion_keywords(f: KeywordsCollectFn) {
585 f(&[
586 "block",
587 "contents",
588 "flex",
589 "flow-root",
590 "flow-root list-item",
591 "grid",
592 "inline",
593 "inline-block",
594 "inline-flex",
595 "inline-grid",
596 "inline-table",
597 "inline list-item",
598 "inline flow-root list-item",
599 "list-item",
600 "none",
601 "block ruby",
602 "ruby",
603 "ruby-base",
604 "ruby-base-container",
605 "ruby-text",
606 "ruby-text-container",
607 "table",
608 "table-caption",
609 "table-cell",
610 "table-column",
611 "table-column-group",
612 "table-footer-group",
613 "table-header-group",
614 "table-row",
615 "table-row-group",
616 "-webkit-box",
617 "-webkit-inline-box",
618 ]);
619 }
620}
621
622pub type ContainIntrinsicSize = GenericContainIntrinsicSize<NonNegativeLength>;
624
625pub type LineClamp = GenericLineClamp<Integer>;
627
628pub type BaselineShift = GenericBaselineShift<LengthPercentage>;
630
631impl Parse for BaselineShift {
632 fn parse<'i, 't>(
633 context: &ParserContext,
634 input: &mut Parser<'i, 't>,
635 ) -> Result<Self, ParseError<'i>> {
636 if let Ok(lp) =
637 input.try_parse(|i| LengthPercentage::parse_quirky(context, i, AllowQuirks::Yes))
638 {
639 return Ok(BaselineShift::Length(lp));
640 }
641
642 Ok(BaselineShift::Keyword(BaselineShiftKeyword::parse(input)?))
643 }
644}
645
646#[derive(
649 Clone,
650 Copy,
651 Debug,
652 Eq,
653 FromPrimitive,
654 Hash,
655 MallocSizeOf,
656 Parse,
657 PartialEq,
658 SpecifiedValueInfo,
659 ToCss,
660 ToShmem,
661 ToComputedValue,
662 ToResolvedValue,
663 ToTyped,
664)]
665#[repr(u8)]
666pub enum DominantBaseline {
667 Auto,
671 #[parse(aliases = "text-after-edge")]
673 TextBottom,
674 Alphabetic,
676 Ideographic,
678 Middle,
682 Central,
684 Mathematical,
686 Hanging,
688 #[parse(aliases = "text-before-edge")]
690 TextTop,
691}
692
693#[derive(
696 Clone,
697 Copy,
698 Debug,
699 Eq,
700 FromPrimitive,
701 Hash,
702 MallocSizeOf,
703 Parse,
704 PartialEq,
705 SpecifiedValueInfo,
706 ToCss,
707 ToShmem,
708 ToComputedValue,
709 ToResolvedValue,
710 ToTyped,
711)]
712#[repr(u8)]
713pub enum AlignmentBaseline {
714 Baseline,
716 TextBottom,
718 #[css(skip)]
721 Alphabetic,
722 #[css(skip)]
725 Ideographic,
726 Middle,
730 #[css(skip)]
733 Central,
734 #[css(skip)]
737 Mathematical,
738 #[css(skip)]
741 Hanging,
742 TextTop,
744 #[cfg(feature = "gecko")]
746 MozMiddleWithBaseline,
747}
748
749#[derive(
752 Clone,
753 Copy,
754 Debug,
755 Eq,
756 Hash,
757 MallocSizeOf,
758 Parse,
759 PartialEq,
760 SpecifiedValueInfo,
761 ToCss,
762 ToShmem,
763 ToComputedValue,
764 ToResolvedValue,
765 ToTyped,
766)]
767#[repr(u8)]
768pub enum BaselineSource {
769 Auto,
771 First,
773 Last,
775}
776
777impl BaselineSource {
778 pub fn parse_non_auto<'i>(input: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
780 Ok(try_match_ident_ignore_ascii_case! { input,
781 "first" => Self::First,
782 "last" => Self::Last,
783 })
784 }
785}
786
787#[allow(missing_docs)]
789#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
790#[derive(
791 Clone,
792 Copy,
793 Debug,
794 Eq,
795 MallocSizeOf,
796 Parse,
797 PartialEq,
798 SpecifiedValueInfo,
799 ToComputedValue,
800 ToCss,
801 ToResolvedValue,
802 ToShmem,
803)]
804#[repr(u8)]
805pub enum ScrollSnapAxis {
806 X,
807 Y,
808 Block,
809 Inline,
810 Both,
811}
812
813#[allow(missing_docs)]
815#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
816#[derive(
817 Clone,
818 Copy,
819 Debug,
820 Eq,
821 MallocSizeOf,
822 Parse,
823 PartialEq,
824 SpecifiedValueInfo,
825 ToComputedValue,
826 ToCss,
827 ToResolvedValue,
828 ToShmem,
829)]
830#[repr(u8)]
831pub enum ScrollSnapStrictness {
832 #[css(skip)]
833 None, Mandatory,
835 Proximity,
836}
837
838#[allow(missing_docs)]
840#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
841#[derive(
842 Clone,
843 Copy,
844 Debug,
845 Eq,
846 MallocSizeOf,
847 PartialEq,
848 SpecifiedValueInfo,
849 ToComputedValue,
850 ToResolvedValue,
851 ToShmem,
852 ToTyped,
853)]
854#[repr(C)]
855#[typed(todo_derive_fields)]
856pub struct ScrollSnapType {
857 axis: ScrollSnapAxis,
858 strictness: ScrollSnapStrictness,
859}
860
861impl ScrollSnapType {
862 #[inline]
864 pub fn none() -> Self {
865 Self {
866 axis: ScrollSnapAxis::Both,
867 strictness: ScrollSnapStrictness::None,
868 }
869 }
870}
871
872impl Parse for ScrollSnapType {
873 fn parse<'i, 't>(
875 _context: &ParserContext,
876 input: &mut Parser<'i, 't>,
877 ) -> Result<Self, ParseError<'i>> {
878 if input
879 .try_parse(|input| input.expect_ident_matching("none"))
880 .is_ok()
881 {
882 return Ok(ScrollSnapType::none());
883 }
884
885 let axis = ScrollSnapAxis::parse(input)?;
886 let strictness = input
887 .try_parse(ScrollSnapStrictness::parse)
888 .unwrap_or(ScrollSnapStrictness::Proximity);
889 Ok(Self { axis, strictness })
890 }
891}
892
893impl ToCss for ScrollSnapType {
894 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
895 where
896 W: Write,
897 {
898 if self.strictness == ScrollSnapStrictness::None {
899 return dest.write_str("none");
900 }
901 self.axis.to_css(dest)?;
902 if self.strictness != ScrollSnapStrictness::Proximity {
903 dest.write_char(' ')?;
904 self.strictness.to_css(dest)?;
905 }
906 Ok(())
907 }
908}
909
910#[allow(missing_docs)]
912#[derive(
913 Clone,
914 Copy,
915 Debug,
916 Eq,
917 FromPrimitive,
918 Hash,
919 MallocSizeOf,
920 Parse,
921 PartialEq,
922 SpecifiedValueInfo,
923 ToComputedValue,
924 ToCss,
925 ToResolvedValue,
926 ToShmem,
927)]
928#[repr(u8)]
929pub enum ScrollSnapAlignKeyword {
930 None,
931 Start,
932 End,
933 Center,
934}
935
936#[allow(missing_docs)]
938#[derive(
939 Clone,
940 Copy,
941 Debug,
942 Eq,
943 MallocSizeOf,
944 PartialEq,
945 SpecifiedValueInfo,
946 ToComputedValue,
947 ToResolvedValue,
948 ToShmem,
949 ToTyped,
950)]
951#[repr(C)]
952#[typed(todo_derive_fields)]
953pub struct ScrollSnapAlign {
954 block: ScrollSnapAlignKeyword,
955 inline: ScrollSnapAlignKeyword,
956}
957
958impl ScrollSnapAlign {
959 #[inline]
961 pub fn none() -> Self {
962 ScrollSnapAlign {
963 block: ScrollSnapAlignKeyword::None,
964 inline: ScrollSnapAlignKeyword::None,
965 }
966 }
967}
968
969impl Parse for ScrollSnapAlign {
970 fn parse<'i, 't>(
972 _context: &ParserContext,
973 input: &mut Parser<'i, 't>,
974 ) -> Result<ScrollSnapAlign, ParseError<'i>> {
975 let block = ScrollSnapAlignKeyword::parse(input)?;
976 let inline = input
977 .try_parse(ScrollSnapAlignKeyword::parse)
978 .unwrap_or(block);
979 Ok(ScrollSnapAlign { block, inline })
980 }
981}
982
983impl ToCss for ScrollSnapAlign {
984 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
985 where
986 W: Write,
987 {
988 self.block.to_css(dest)?;
989 if self.block != self.inline {
990 dest.write_char(' ')?;
991 self.inline.to_css(dest)?;
992 }
993 Ok(())
994 }
995}
996
997#[allow(missing_docs)]
998#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
999#[derive(
1000 Clone,
1001 Copy,
1002 Debug,
1003 Eq,
1004 MallocSizeOf,
1005 Parse,
1006 PartialEq,
1007 SpecifiedValueInfo,
1008 ToComputedValue,
1009 ToCss,
1010 ToResolvedValue,
1011 ToShmem,
1012 ToTyped,
1013)]
1014#[repr(u8)]
1015pub enum ScrollSnapStop {
1016 Normal,
1017 Always,
1018}
1019
1020#[allow(missing_docs)]
1021#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
1022#[derive(
1023 Clone,
1024 Copy,
1025 Debug,
1026 Eq,
1027 MallocSizeOf,
1028 Parse,
1029 PartialEq,
1030 SpecifiedValueInfo,
1031 ToComputedValue,
1032 ToCss,
1033 ToResolvedValue,
1034 ToShmem,
1035 ToTyped,
1036)]
1037#[repr(u8)]
1038pub enum OverscrollBehavior {
1039 Auto,
1040 Contain,
1041 None,
1042}
1043
1044#[allow(missing_docs)]
1045#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
1046#[derive(
1047 Clone,
1048 Copy,
1049 Debug,
1050 Eq,
1051 MallocSizeOf,
1052 Parse,
1053 PartialEq,
1054 SpecifiedValueInfo,
1055 ToComputedValue,
1056 ToCss,
1057 ToResolvedValue,
1058 ToShmem,
1059 ToTyped,
1060)]
1061#[repr(u8)]
1062pub enum OverflowAnchor {
1063 Auto,
1064 None,
1065}
1066
1067#[derive(
1068 Clone,
1069 Debug,
1070 Default,
1071 MallocSizeOf,
1072 PartialEq,
1073 SpecifiedValueInfo,
1074 ToComputedValue,
1075 ToCss,
1076 ToResolvedValue,
1077 ToShmem,
1078 ToTyped,
1079)]
1080#[css(comma)]
1081#[repr(C)]
1082#[typed(todo_derive_fields)]
1083pub struct WillChange {
1090 #[css(iterable, if_empty = "auto")]
1095 features: crate::OwnedSlice<CustomIdent>,
1096 #[css(skip)]
1099 pub bits: WillChangeBits,
1100}
1101
1102impl WillChange {
1103 #[inline]
1104 pub fn auto() -> Self {
1106 Self::default()
1107 }
1108}
1109
1110#[derive(
1112 Clone,
1113 Copy,
1114 Debug,
1115 Default,
1116 Eq,
1117 MallocSizeOf,
1118 PartialEq,
1119 SpecifiedValueInfo,
1120 ToComputedValue,
1121 ToResolvedValue,
1122 ToShmem,
1123)]
1124#[repr(C)]
1125pub struct WillChangeBits(u16);
1126bitflags! {
1127 impl WillChangeBits: u16 {
1128 const STACKING_CONTEXT_UNCONDITIONAL = 1 << 0;
1131 const TRANSFORM = 1 << 1;
1133 const SCROLL = 1 << 2;
1135 const CONTAIN = 1 << 3;
1137 const OPACITY = 1 << 4;
1139 const PERSPECTIVE = 1 << 5;
1141 const Z_INDEX = 1 << 6;
1143 const FIXPOS_CB_NON_SVG = 1 << 7;
1146 const POSITION = 1 << 8;
1148 const VIEW_TRANSITION_NAME = 1 << 9;
1150 const BACKDROP_ROOT = 1 << 10;
1153 }
1154}
1155
1156fn change_bits_for_longhand(longhand: LonghandId) -> WillChangeBits {
1157 match longhand {
1158 LonghandId::Opacity => WillChangeBits::OPACITY | WillChangeBits::BACKDROP_ROOT,
1159 LonghandId::Contain => WillChangeBits::CONTAIN,
1160 LonghandId::Perspective => WillChangeBits::PERSPECTIVE,
1161 LonghandId::Position => {
1162 WillChangeBits::STACKING_CONTEXT_UNCONDITIONAL | WillChangeBits::POSITION
1163 },
1164 LonghandId::ZIndex => WillChangeBits::Z_INDEX,
1165 LonghandId::Transform
1166 | LonghandId::TransformStyle
1167 | LonghandId::Translate
1168 | LonghandId::Rotate
1169 | LonghandId::Scale
1170 | LonghandId::OffsetPath => WillChangeBits::TRANSFORM,
1171 LonghandId::Filter | LonghandId::BackdropFilter => {
1172 WillChangeBits::STACKING_CONTEXT_UNCONDITIONAL
1173 | WillChangeBits::BACKDROP_ROOT
1174 | WillChangeBits::FIXPOS_CB_NON_SVG
1175 },
1176 LonghandId::ViewTransitionName => {
1177 WillChangeBits::VIEW_TRANSITION_NAME | WillChangeBits::BACKDROP_ROOT
1178 },
1179 LonghandId::MixBlendMode => {
1180 WillChangeBits::STACKING_CONTEXT_UNCONDITIONAL | WillChangeBits::BACKDROP_ROOT
1181 },
1182 LonghandId::Isolation | LonghandId::MaskImage => {
1183 WillChangeBits::STACKING_CONTEXT_UNCONDITIONAL
1184 },
1185 LonghandId::ClipPath => {
1186 WillChangeBits::STACKING_CONTEXT_UNCONDITIONAL | WillChangeBits::BACKDROP_ROOT
1187 },
1188 _ => WillChangeBits::empty(),
1189 }
1190}
1191
1192fn change_bits_for_maybe_property(ident: &str, context: &ParserContext) -> WillChangeBits {
1193 let id = match PropertyId::parse_ignoring_rule_type(ident, context) {
1194 Ok(id) => id,
1195 Err(..) => return WillChangeBits::empty(),
1196 };
1197
1198 match id.as_shorthand() {
1199 Ok(shorthand) => shorthand
1200 .longhands()
1201 .fold(WillChangeBits::empty(), |flags, p| {
1202 flags | change_bits_for_longhand(p)
1203 }),
1204 Err(PropertyDeclarationId::Longhand(longhand)) => change_bits_for_longhand(longhand),
1205 Err(PropertyDeclarationId::Custom(..)) => WillChangeBits::empty(),
1206 }
1207}
1208
1209impl Parse for WillChange {
1210 fn parse<'i, 't>(
1212 context: &ParserContext,
1213 input: &mut Parser<'i, 't>,
1214 ) -> Result<Self, ParseError<'i>> {
1215 if input
1216 .try_parse(|input| input.expect_ident_matching("auto"))
1217 .is_ok()
1218 {
1219 return Ok(Self::default());
1220 }
1221
1222 let mut bits = WillChangeBits::empty();
1223 let custom_idents = input.parse_comma_separated(|i| {
1224 let location = i.current_source_location();
1225 let parser_ident = i.expect_ident()?;
1226 let ident = CustomIdent::from_ident(
1227 location,
1228 parser_ident,
1229 &["will-change", "none", "all", "auto"],
1230 )?;
1231
1232 if context.in_ua_sheet() && ident.0 == atom!("-moz-fixed-pos-containing-block") {
1233 bits |= WillChangeBits::FIXPOS_CB_NON_SVG;
1234 } else if ident.0 == atom!("scroll-position") {
1235 bits |= WillChangeBits::SCROLL;
1236 } else {
1237 bits |= change_bits_for_maybe_property(&parser_ident, context);
1238 }
1239 Ok(ident)
1240 })?;
1241
1242 Ok(Self {
1243 features: custom_idents.into(),
1244 bits,
1245 })
1246 }
1247}
1248
1249#[derive(
1251 Clone,
1252 Copy,
1253 Debug,
1254 Eq,
1255 MallocSizeOf,
1256 Parse,
1257 PartialEq,
1258 SpecifiedValueInfo,
1259 ToComputedValue,
1260 ToCss,
1261 ToResolvedValue,
1262 ToShmem,
1263 ToTyped,
1264)]
1265#[css(bitflags(single = "none,auto,manipulation", mixed = "pan-x,pan-y,pinch-zoom"))]
1266#[repr(C)]
1267pub struct TouchAction(u8);
1268bitflags! {
1269 impl TouchAction: u8 {
1270 const NONE = 1 << 0;
1272 const AUTO = 1 << 1;
1274 const PAN_X = 1 << 2;
1276 const PAN_Y = 1 << 3;
1278 const MANIPULATION = 1 << 4;
1280 const PINCH_ZOOM = 1 << 5;
1282 }
1283}
1284
1285impl TouchAction {
1286 #[inline]
1287 pub fn auto() -> TouchAction {
1289 TouchAction::AUTO
1290 }
1291}
1292
1293#[derive(
1294 Clone,
1295 Copy,
1296 Debug,
1297 Eq,
1298 MallocSizeOf,
1299 Parse,
1300 PartialEq,
1301 SpecifiedValueInfo,
1302 ToComputedValue,
1303 ToCss,
1304 ToResolvedValue,
1305 ToShmem,
1306 ToTyped,
1307)]
1308#[css(bitflags(
1309 single = "none,strict,content",
1310 mixed = "size,layout,style,paint,inline-size",
1311 overlapping_bits
1312))]
1313#[repr(C)]
1314pub struct Contain(u8);
1316bitflags! {
1317 impl Contain: u8 {
1318 const NONE = 0;
1320 const INLINE_SIZE = 1 << 0;
1322 const BLOCK_SIZE = 1 << 1;
1324 const LAYOUT = 1 << 2;
1326 const STYLE = 1 << 3;
1328 const PAINT = 1 << 4;
1330 const SIZE = 1 << 5 | Contain::INLINE_SIZE.bits() | Contain::BLOCK_SIZE.bits();
1332 const CONTENT = 1 << 6 | Contain::LAYOUT.bits() | Contain::STYLE.bits() | Contain::PAINT.bits();
1334 const STRICT = 1 << 7 | Contain::LAYOUT.bits() | Contain::STYLE.bits() | Contain::PAINT.bits() | Contain::SIZE.bits();
1336 }
1337}
1338
1339impl Parse for ContainIntrinsicSize {
1340 fn parse<'i, 't>(
1342 context: &ParserContext,
1343 input: &mut Parser<'i, 't>,
1344 ) -> Result<Self, ParseError<'i>> {
1345 if let Ok(l) = input.try_parse(|i| NonNegativeLength::parse(context, i)) {
1346 return Ok(Self::Length(l));
1347 }
1348
1349 if input.try_parse(|i| i.expect_ident_matching("auto")).is_ok() {
1350 if input.try_parse(|i| i.expect_ident_matching("none")).is_ok() {
1351 return Ok(Self::AutoNone);
1352 }
1353
1354 let l = NonNegativeLength::parse(context, input)?;
1355 return Ok(Self::AutoLength(l));
1356 }
1357
1358 input.expect_ident_matching("none")?;
1359 Ok(Self::None)
1360 }
1361}
1362
1363impl Parse for LineClamp {
1364 fn parse<'i, 't>(
1366 context: &ParserContext,
1367 input: &mut Parser<'i, 't>,
1368 ) -> Result<Self, ParseError<'i>> {
1369 if let Ok(i) =
1370 input.try_parse(|i| crate::values::specified::PositiveInteger::parse(context, i))
1371 {
1372 return Ok(Self(i.0));
1373 }
1374 input.expect_ident_matching("none")?;
1375 Ok(Self::none())
1376 }
1377}
1378
1379#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
1381#[derive(
1382 Clone,
1383 Copy,
1384 Debug,
1385 Eq,
1386 FromPrimitive,
1387 MallocSizeOf,
1388 Parse,
1389 PartialEq,
1390 SpecifiedValueInfo,
1391 ToAnimatedValue,
1392 ToComputedValue,
1393 ToCss,
1394 ToResolvedValue,
1395 ToShmem,
1396 ToTyped,
1397)]
1398#[repr(u8)]
1399pub enum ContentVisibility {
1400 Auto,
1404 Hidden,
1406 Visible,
1408}
1409
1410#[derive(
1411 Clone,
1412 Copy,
1413 Debug,
1414 PartialEq,
1415 Eq,
1416 MallocSizeOf,
1417 SpecifiedValueInfo,
1418 ToComputedValue,
1419 ToCss,
1420 Parse,
1421 ToResolvedValue,
1422 ToShmem,
1423 ToTyped,
1424)]
1425#[css(bitflags(
1426 single = "normal",
1427 mixed = "size,inline-size,scroll-state",
1428 validate_mixed = "Self::validate_mixed_flags",
1429))]
1430#[repr(C)]
1431pub struct ContainerType(u8);
1438bitflags! {
1439 impl ContainerType: u8 {
1440 const NORMAL = 0;
1442 const INLINE_SIZE = 1 << 0;
1444 const SIZE = 1 << 1;
1446 const SCROLL_STATE = 1 << 2;
1448 }
1449}
1450
1451impl ContainerType {
1452 fn validate_mixed_flags(&self) -> bool {
1453 if self.contains(Self::SIZE | Self::INLINE_SIZE) {
1455 return false;
1456 }
1457 if self.contains(Self::SCROLL_STATE)
1458 && !static_prefs::pref!("layout.css.scroll-state.enabled")
1459 {
1460 return false;
1461 }
1462 true
1463 }
1464
1465 pub fn is_normal(self) -> bool {
1467 self == Self::NORMAL
1468 }
1469
1470 pub fn is_size_container_type(self) -> bool {
1472 self.intersects(Self::SIZE | Self::INLINE_SIZE)
1473 }
1474}
1475
1476#[repr(transparent)]
1478#[derive(
1479 Clone,
1480 Debug,
1481 MallocSizeOf,
1482 PartialEq,
1483 SpecifiedValueInfo,
1484 ToComputedValue,
1485 ToCss,
1486 ToResolvedValue,
1487 ToShmem,
1488 ToTyped,
1489)]
1490pub struct ContainerName(#[css(iterable, if_empty = "none")] pub crate::OwnedSlice<CustomIdent>);
1491
1492impl ContainerName {
1493 pub fn none() -> Self {
1495 Self(Default::default())
1496 }
1497
1498 pub fn is_none(&self) -> bool {
1500 self.0.is_empty()
1501 }
1502
1503 fn parse_internal<'i>(
1504 input: &mut Parser<'i, '_>,
1505 for_query: bool,
1506 ) -> Result<Self, ParseError<'i>> {
1507 let mut idents = vec![];
1508 let location = input.current_source_location();
1509 let first = input.expect_ident()?;
1510 if !for_query && first.eq_ignore_ascii_case("none") {
1511 return Ok(Self::none());
1512 }
1513 const DISALLOWED_CONTAINER_NAMES: &'static [&'static str] = &["none", "not", "or", "and"];
1514 idents.push(CustomIdent::from_ident(
1515 location,
1516 first,
1517 DISALLOWED_CONTAINER_NAMES,
1518 )?);
1519 if !for_query {
1520 while let Ok(name) =
1521 input.try_parse(|input| CustomIdent::parse(input, DISALLOWED_CONTAINER_NAMES))
1522 {
1523 idents.push(name);
1524 }
1525 }
1526 Ok(ContainerName(idents.into()))
1527 }
1528
1529 pub fn parse_for_query<'i, 't>(
1533 _: &ParserContext,
1534 input: &mut Parser<'i, 't>,
1535 ) -> Result<Self, ParseError<'i>> {
1536 Self::parse_internal(input, true)
1537 }
1538}
1539
1540impl Parse for ContainerName {
1541 fn parse<'i, 't>(
1542 _: &ParserContext,
1543 input: &mut Parser<'i, 't>,
1544 ) -> Result<Self, ParseError<'i>> {
1545 Self::parse_internal(input, false)
1546 }
1547}
1548
1549pub type Perspective = GenericPerspective<NonNegativeLength>;
1551
1552#[allow(missing_docs)]
1554#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
1555#[derive(
1556 Clone,
1557 Copy,
1558 Debug,
1559 Eq,
1560 FromPrimitive,
1561 Hash,
1562 MallocSizeOf,
1563 Parse,
1564 PartialEq,
1565 SpecifiedValueInfo,
1566 ToComputedValue,
1567 ToCss,
1568 ToResolvedValue,
1569 ToShmem,
1570 ToTyped,
1571)]
1572#[repr(u8)]
1573pub enum Float {
1574 Left,
1575 Right,
1576 None,
1577 InlineStart,
1579 InlineEnd,
1580}
1581
1582impl Float {
1583 pub fn is_floating(self) -> bool {
1585 self != Self::None
1586 }
1587}
1588
1589#[allow(missing_docs)]
1591#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
1592#[derive(
1593 Clone,
1594 Copy,
1595 Debug,
1596 Eq,
1597 FromPrimitive,
1598 Hash,
1599 MallocSizeOf,
1600 Parse,
1601 PartialEq,
1602 SpecifiedValueInfo,
1603 ToComputedValue,
1604 ToCss,
1605 ToResolvedValue,
1606 ToShmem,
1607 ToTyped,
1608)]
1609#[repr(u8)]
1610pub enum Clear {
1611 None,
1612 Left,
1613 Right,
1614 Both,
1615 InlineStart,
1617 InlineEnd,
1618}
1619
1620#[allow(missing_docs)]
1622#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
1623#[derive(
1624 Clone,
1625 Copy,
1626 Debug,
1627 Eq,
1628 Hash,
1629 MallocSizeOf,
1630 Parse,
1631 PartialEq,
1632 SpecifiedValueInfo,
1633 ToCss,
1634 ToShmem,
1635 ToTyped,
1636)]
1637pub enum Resize {
1638 None,
1639 Both,
1640 Horizontal,
1641 Vertical,
1642 Inline,
1644 Block,
1645}
1646
1647#[allow(missing_docs)]
1651#[derive(
1652 Clone,
1653 Copy,
1654 Debug,
1655 Eq,
1656 Hash,
1657 MallocSizeOf,
1658 Parse,
1659 PartialEq,
1660 SpecifiedValueInfo,
1661 ToCss,
1662 ToComputedValue,
1663 ToResolvedValue,
1664 ToShmem,
1665 ToTyped,
1666)]
1667#[repr(u8)]
1668pub enum Appearance {
1669 None,
1671 Auto,
1676 Searchfield,
1678 Textarea,
1680 Checkbox,
1682 Radio,
1684 Menulist,
1686 Listbox,
1688 Meter,
1690 ProgressBar,
1692 Button,
1694 Textfield,
1696 MenulistButton,
1698 #[parse(condition = "appearance_base_enabled")]
1700 Base,
1701 #[parse(condition = "appearance_base_select_enabled")]
1704 BaseSelect,
1705 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1707 Menupopup,
1708 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1710 MozMenulistArrowButton,
1711 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1713 NumberInput,
1714 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1716 PasswordInput,
1717 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1719 Range,
1720 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1722 ScrollbarHorizontal,
1723 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1724 ScrollbarVertical,
1725 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1729 ScrollbarbuttonUp,
1730 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1731 ScrollbarbuttonDown,
1732 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1733 ScrollbarbuttonLeft,
1734 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1735 ScrollbarbuttonRight,
1736 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1738 ScrollbarthumbHorizontal,
1739 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1740 ScrollbarthumbVertical,
1741 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1743 Scrollcorner,
1744 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1746 SpinnerUpbutton,
1747 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1749 SpinnerDownbutton,
1750 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1752 Toolbarbutton,
1753 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1755 Tooltip,
1756
1757 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1759 MozSidebar,
1760
1761 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1763 MozMacHelpButton,
1764
1765 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1769 MozMacWindow,
1770
1771 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1773 MozWindowButtonBox,
1774 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1775 MozWindowButtonClose,
1776 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1777 MozWindowButtonMaximize,
1778 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1779 MozWindowButtonMinimize,
1780 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1781 MozWindowButtonRestore,
1782 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1783 MozWindowTitlebar,
1784 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1785 MozWindowTitlebarMaximized,
1786 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1787 MozWindowDecorations,
1788
1789 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1790 MozMacDisclosureButtonClosed,
1791 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1792 MozMacDisclosureButtonOpen,
1793
1794 #[css(skip)]
1798 FocusOutline,
1799
1800 #[css(skip)]
1802 Count,
1803}
1804
1805#[allow(missing_docs)]
1809#[derive(
1810 Clone,
1811 Copy,
1812 Debug,
1813 Eq,
1814 Hash,
1815 MallocSizeOf,
1816 Parse,
1817 PartialEq,
1818 SpecifiedValueInfo,
1819 ToCss,
1820 ToComputedValue,
1821 ToResolvedValue,
1822 ToShmem,
1823 ToTyped,
1824)]
1825#[repr(u8)]
1826pub enum BreakBetween {
1827 Always,
1828 Auto,
1829 Page,
1830 Avoid,
1831 Left,
1832 Right,
1833}
1834
1835impl BreakBetween {
1836 #[cfg_attr(feature = "servo", allow(unused))]
1840 #[inline]
1841 pub(crate) fn parse_legacy<'i>(
1842 _: &ParserContext,
1843 input: &mut Parser<'i, '_>,
1844 ) -> Result<Self, ParseError<'i>> {
1845 let break_value = BreakBetween::parse(input)?;
1846 match break_value {
1847 BreakBetween::Always => Ok(BreakBetween::Page),
1848 BreakBetween::Auto | BreakBetween::Avoid | BreakBetween::Left | BreakBetween::Right => {
1849 Ok(break_value)
1850 },
1851 BreakBetween::Page => {
1852 Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
1853 },
1854 }
1855 }
1856
1857 #[cfg_attr(feature = "servo", allow(unused))]
1861 pub(crate) fn to_css_legacy<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
1862 where
1863 W: Write,
1864 {
1865 match *self {
1866 BreakBetween::Auto | BreakBetween::Avoid | BreakBetween::Left | BreakBetween::Right => {
1867 self.to_css(dest)
1868 },
1869 BreakBetween::Page => dest.write_str("always"),
1870 BreakBetween::Always => Ok(()),
1871 }
1872 }
1873}
1874
1875#[allow(missing_docs)]
1879#[derive(
1880 Clone,
1881 Copy,
1882 Debug,
1883 Eq,
1884 Hash,
1885 MallocSizeOf,
1886 Parse,
1887 PartialEq,
1888 SpecifiedValueInfo,
1889 ToCss,
1890 ToComputedValue,
1891 ToResolvedValue,
1892 ToShmem,
1893 ToTyped,
1894)]
1895#[repr(u8)]
1896pub enum BreakWithin {
1897 Auto,
1898 Avoid,
1899 AvoidPage,
1900 AvoidColumn,
1901}
1902
1903impl BreakWithin {
1904 #[cfg_attr(feature = "servo", allow(unused))]
1908 #[inline]
1909 pub(crate) fn parse_legacy<'i>(
1910 _: &ParserContext,
1911 input: &mut Parser<'i, '_>,
1912 ) -> Result<Self, ParseError<'i>> {
1913 let break_value = BreakWithin::parse(input)?;
1914 match break_value {
1915 BreakWithin::Auto | BreakWithin::Avoid => Ok(break_value),
1916 BreakWithin::AvoidPage | BreakWithin::AvoidColumn => {
1917 Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
1918 },
1919 }
1920 }
1921
1922 #[cfg_attr(feature = "servo", allow(unused))]
1926 pub(crate) fn to_css_legacy<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
1927 where
1928 W: Write,
1929 {
1930 match *self {
1931 BreakWithin::Auto | BreakWithin::Avoid => self.to_css(dest),
1932 BreakWithin::AvoidPage | BreakWithin::AvoidColumn => Ok(()),
1933 }
1934 }
1935}
1936
1937#[allow(missing_docs)]
1939#[derive(
1940 Clone,
1941 Copy,
1942 Debug,
1943 Eq,
1944 Hash,
1945 MallocSizeOf,
1946 PartialEq,
1947 SpecifiedValueInfo,
1948 ToCss,
1949 ToComputedValue,
1950 ToResolvedValue,
1951 ToShmem,
1952 ToTyped,
1953)]
1954#[repr(u8)]
1955pub enum Overflow {
1956 Visible,
1957 Hidden,
1958 Scroll,
1959 Auto,
1960 Clip,
1961}
1962
1963impl Parse for Overflow {
1966 fn parse<'i, 't>(
1967 _: &ParserContext,
1968 input: &mut Parser<'i, 't>,
1969 ) -> Result<Self, ParseError<'i>> {
1970 Ok(try_match_ident_ignore_ascii_case! { input,
1971 "visible" => Self::Visible,
1972 "hidden" => Self::Hidden,
1973 "scroll" => Self::Scroll,
1974 "auto" | "overlay" => Self::Auto,
1975 "clip" => Self::Clip,
1976 #[cfg(feature = "gecko")]
1977 "-moz-hidden-unscrollable" if static_prefs::pref!("layout.css.overflow-moz-hidden-unscrollable.enabled") => {
1978 Overflow::Clip
1979 },
1980 })
1981 }
1982}
1983
1984impl Overflow {
1985 #[inline]
1987 pub fn is_scrollable(&self) -> bool {
1988 matches!(*self, Self::Hidden | Self::Scroll | Self::Auto)
1989 }
1990 #[inline]
1993 pub fn to_scrollable(&self) -> Self {
1994 match *self {
1995 Self::Hidden | Self::Scroll | Self::Auto => *self,
1996 Self::Visible => Self::Auto,
1997 Self::Clip => Self::Hidden,
1998 }
1999 }
2000}
2001
2002#[derive(
2003 Clone,
2004 Copy,
2005 Debug,
2006 Eq,
2007 MallocSizeOf,
2008 Parse,
2009 PartialEq,
2010 SpecifiedValueInfo,
2011 ToComputedValue,
2012 ToCss,
2013 ToResolvedValue,
2014 ToShmem,
2015 ToTyped,
2016)]
2017#[repr(C)]
2018#[css(bitflags(
2019 single = "auto",
2020 mixed = "stable,both-edges",
2021 validate_mixed = "Self::has_stable"
2022))]
2023pub struct ScrollbarGutter(u8);
2026bitflags! {
2027 impl ScrollbarGutter: u8 {
2028 const AUTO = 0;
2030 const STABLE = 1 << 0;
2032 const BOTH_EDGES = 1 << 1;
2034 }
2035}
2036
2037impl ScrollbarGutter {
2038 #[inline]
2039 fn has_stable(&self) -> bool {
2040 self.intersects(Self::STABLE)
2041 }
2042}
2043
2044#[derive(
2046 Clone, Copy, Debug, MallocSizeOf, PartialEq, Parse, SpecifiedValueInfo, ToCss, ToShmem, ToTyped,
2047)]
2048#[allow(missing_docs)]
2049#[typed(todo_derive_fields)]
2050pub enum Zoom {
2051 Normal,
2052 #[parse(condition = "ParserContext::in_ua_sheet")]
2055 Document,
2056 Value(NonNegativeNumberOrPercentage),
2057}
2058
2059impl Zoom {
2060 #[inline]
2062 pub fn new_number(n: f32) -> Self {
2063 Self::Value(NonNegativeNumberOrPercentage::new_number(n))
2064 }
2065}
2066
2067pub use crate::values::generics::box_::PositionProperty;