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