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::CustomIdent;
13use crate::values::generics::box_::{
14 BaselineShiftKeyword, BlockEllipsis, GenericBaselineShift, GenericContainIntrinsicSize,
15 GenericLineClamp, GenericOverflowClipMargin, GenericPerspective, GenericScrollbarInset,
16 MaxLines, OverflowClipMarginBox,
17};
18use crate::values::specified::length::{LengthPercentage, NonNegativeLength};
19use crate::values::specified::{AllowQuirks, NonNegativeNumberOrPercentage, PositiveInteger};
20use cssparser::Parser;
21use num_traits::FromPrimitive;
22use std::fmt::{self, Write};
23use style_traits::{CssWriter, KeywordsCollectFn, ParseError };
24use style_traits::{SpecifiedValueInfo, StyleParseErrorKind, ToCss};
25use thin_vec::ThinVec;
26
27#[inline]
28fn appearance_base_enabled(_context: &ParserContext) -> bool {
29 crate::pref!("layout.css.appearance-base.enabled")
30}
31
32#[inline]
33fn appearance_base_select_enabled(_context: &ParserContext) -> bool {
34 crate::pref!("dom.select.customizable_select.enabled")
35}
36
37#[derive(
38 Clone,
39 Copy,
40 Debug,
41 Eq,
42 MallocSizeOf,
43 PartialEq,
44 Parse,
45 ToCss,
46 SpecifiedValueInfo,
47 ToComputedValue,
48 ToResolvedValue,
49 ToShmem,
50 ToTyped,
51)]
52#[css(bitflags(
53 single = "none",
54 mixed = "block,block-start,block-end",
55 overlapping_bits
56))]
57#[repr(C)]
58pub struct MarginTrim(u8);
64bitflags! {
65 impl MarginTrim: u8 {
66 const NONE = 0;
68 const BLOCK_START = 1 << 0;
70 const BLOCK_END = 1 << 1;
72 const BLOCK = MarginTrim::BLOCK_START.bits() | MarginTrim::BLOCK_END.bits();
74 }
75}
76
77pub type OverflowClipMargin = GenericOverflowClipMargin<NonNegativeLength>;
79
80impl Parse for OverflowClipMargin {
81 fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
83 use crate::Zero;
84 let mut offset = None;
85 let mut visual_box = None;
86 loop {
87 if offset.is_none() {
88 offset = input
89 .try_parse(|i| NonNegativeLength::parse(context, i))
90 .ok();
91 }
92 if visual_box.is_none() {
93 visual_box = input.try_parse(OverflowClipMarginBox::parse).ok();
94 if visual_box.is_some() {
95 continue;
96 }
97 }
98 break;
99 }
100 if offset.is_none() && visual_box.is_none() {
101 return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
102 }
103 Ok(Self {
104 offset: offset.unwrap_or_else(NonNegativeLength::zero),
105 visual_box: visual_box.unwrap_or(OverflowClipMarginBox::PaddingBox),
106 })
107 }
108}
109
110pub type ScrollbarInset = GenericScrollbarInset<NonNegativeLength>;
112
113impl Parse for ScrollbarInset {
114 fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
116 let start = NonNegativeLength::parse(context, input)?;
117 let end = input
118 .try_parse(|i| NonNegativeLength::parse(context, i))
119 .unwrap_or_else(|_| start.clone());
120 Ok(Self { start, end })
121 }
122}
123
124#[inline]
125fn is_display_grid_lanes_enabled() -> bool {
126 static_prefs::pref!("layout.css.display-grid-lanes.enabled")
127}
128
129#[allow(missing_docs)]
133#[derive(Clone, Copy, Debug, Eq, FromPrimitive, Hash, MallocSizeOf, PartialEq, ToCss, ToShmem)]
134#[repr(u8)]
135pub enum DisplayOutside {
136 None = 0,
137 Inline,
138 Block,
139 TableCaption,
140 InternalTable,
141 #[cfg(feature = "gecko")]
142 InternalRuby,
143}
144
145#[allow(missing_docs)]
146#[derive(Clone, Copy, Debug, Eq, FromPrimitive, Hash, MallocSizeOf, PartialEq, ToCss, ToShmem)]
147#[repr(u8)]
148pub enum DisplayInside {
149 None = 0,
150 Contents,
151 Flow,
152 FlowRoot,
153 Flex,
154 Grid,
155 GridLanes,
156 Table,
157 TableRowGroup,
158 TableColumn,
159 TableColumnGroup,
160 TableHeaderGroup,
161 TableFooterGroup,
162 TableRow,
163 TableCell,
164 #[cfg(feature = "gecko")]
165 Ruby,
166 #[cfg(feature = "gecko")]
167 RubyBase,
168 #[cfg(feature = "gecko")]
169 RubyBaseContainer,
170 #[cfg(feature = "gecko")]
171 RubyText,
172 #[cfg(feature = "gecko")]
173 RubyTextContainer,
174 #[cfg(feature = "gecko")]
175 WebkitBox,
176}
177
178impl DisplayInside {
179 fn is_valid_for_list_item(self) -> bool {
180 match self {
181 DisplayInside::Flow => true,
182 #[cfg(feature = "gecko")]
183 DisplayInside::FlowRoot => true,
184 _ => false,
185 }
186 }
187
188 fn default_display_outside(self) -> DisplayOutside {
192 match self {
193 #[cfg(feature = "gecko")]
194 DisplayInside::Ruby => DisplayOutside::Inline,
195 _ => DisplayOutside::Block,
196 }
197 }
198}
199
200#[allow(missing_docs)]
201#[derive(
202 Clone,
203 Copy,
204 Debug,
205 Eq,
206 FromPrimitive,
207 Hash,
208 MallocSizeOf,
209 PartialEq,
210 ToAnimatedValue,
211 ToComputedValue,
212 ToResolvedValue,
213 ToShmem,
214)]
215#[repr(C)]
216pub struct Display(u16);
217
218#[allow(missing_docs)]
220#[allow(non_upper_case_globals)]
221impl Display {
222 pub const LIST_ITEM_MASK: u16 = 0b1000000000000000;
224 pub const OUTSIDE_MASK: u16 = 0b0111111100000000;
225 pub const INSIDE_MASK: u16 = 0b0000000011111111;
226 pub const OUTSIDE_SHIFT: u16 = 8;
227
228 pub const None: Self =
231 Self(((DisplayOutside::None as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::None as u16);
232 pub const Contents: Self = Self(
233 ((DisplayOutside::None as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Contents as u16,
234 );
235 pub const Inline: Self =
236 Self(((DisplayOutside::Inline as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Flow as u16);
237 pub const InlineBlock: Self = Self(
238 ((DisplayOutside::Inline as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::FlowRoot as u16,
239 );
240 pub const Block: Self =
241 Self(((DisplayOutside::Block as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Flow as u16);
242 #[cfg(feature = "gecko")]
243 pub const FlowRoot: Self = Self(
244 ((DisplayOutside::Block as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::FlowRoot as u16,
245 );
246 pub const Flex: Self =
247 Self(((DisplayOutside::Block as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Flex as u16);
248 pub const InlineFlex: Self =
249 Self(((DisplayOutside::Inline as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Flex as u16);
250 pub const Grid: Self =
251 Self(((DisplayOutside::Block as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Grid as u16);
252 pub const InlineGrid: Self =
253 Self(((DisplayOutside::Inline as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Grid as u16);
254 pub const GridLanes: Self = Self(
255 ((DisplayOutside::Block as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::GridLanes as u16,
256 );
257 pub const InlineGridLanes: Self = Self(
258 ((DisplayOutside::Inline as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::GridLanes as u16,
259 );
260 pub const Table: Self =
261 Self(((DisplayOutside::Block as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Table as u16);
262 pub const InlineTable: Self = Self(
263 ((DisplayOutside::Inline as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Table as u16,
264 );
265 pub const TableCaption: Self = Self(
266 ((DisplayOutside::TableCaption as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Flow as u16,
267 );
268 #[cfg(feature = "gecko")]
269 pub const Ruby: Self =
270 Self(((DisplayOutside::Inline as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Ruby as u16);
271 #[cfg(feature = "gecko")]
272 pub const WebkitBox: Self = Self(
273 ((DisplayOutside::Block as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::WebkitBox as u16,
274 );
275 #[cfg(feature = "gecko")]
276 pub const WebkitInlineBox: Self = Self(
277 ((DisplayOutside::Inline as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::WebkitBox as u16,
278 );
279
280 pub const TableRowGroup: Self = Self(
283 ((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT)
284 | DisplayInside::TableRowGroup as u16,
285 );
286 pub const TableHeaderGroup: Self = Self(
287 ((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT)
288 | DisplayInside::TableHeaderGroup as u16,
289 );
290 pub const TableFooterGroup: Self = Self(
291 ((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT)
292 | DisplayInside::TableFooterGroup as u16,
293 );
294 pub const TableColumn: Self = Self(
295 ((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT)
296 | DisplayInside::TableColumn as u16,
297 );
298 pub const TableColumnGroup: Self = Self(
299 ((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT)
300 | DisplayInside::TableColumnGroup as u16,
301 );
302 pub const TableRow: Self = Self(
303 ((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT)
304 | DisplayInside::TableRow as u16,
305 );
306 pub const TableCell: Self = Self(
307 ((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT)
308 | DisplayInside::TableCell as u16,
309 );
310
311 #[cfg(feature = "gecko")]
313 pub const RubyBase: Self = Self(
314 ((DisplayOutside::InternalRuby as u16) << Self::OUTSIDE_SHIFT)
315 | DisplayInside::RubyBase as u16,
316 );
317 #[cfg(feature = "gecko")]
318 pub const RubyBaseContainer: Self = Self(
319 ((DisplayOutside::InternalRuby as u16) << Self::OUTSIDE_SHIFT)
320 | DisplayInside::RubyBaseContainer as u16,
321 );
322 #[cfg(feature = "gecko")]
323 pub const RubyText: Self = Self(
324 ((DisplayOutside::InternalRuby as u16) << Self::OUTSIDE_SHIFT)
325 | DisplayInside::RubyText as u16,
326 );
327 #[cfg(feature = "gecko")]
328 pub const RubyTextContainer: Self = Self(
329 ((DisplayOutside::InternalRuby as u16) << Self::OUTSIDE_SHIFT)
330 | DisplayInside::RubyTextContainer as u16,
331 );
332
333 #[inline]
335 const fn new(outside: DisplayOutside, inside: DisplayInside) -> Self {
336 Self((outside as u16) << Self::OUTSIDE_SHIFT | inside as u16)
337 }
338
339 #[inline]
341 fn from3(outside: DisplayOutside, inside: DisplayInside, list_item: bool) -> Self {
342 let v = Self::new(outside, inside);
343 if !list_item {
344 return v;
345 }
346 Self(v.0 | Self::LIST_ITEM_MASK)
347 }
348
349 #[inline]
351 pub fn inside(&self) -> DisplayInside {
352 DisplayInside::from_u16(self.0 & Self::INSIDE_MASK).unwrap()
353 }
354
355 #[inline]
357 pub fn outside(&self) -> DisplayOutside {
358 DisplayOutside::from_u16((self.0 & Self::OUTSIDE_MASK) >> Self::OUTSIDE_SHIFT).unwrap()
359 }
360
361 #[inline]
363 pub const fn to_u16(&self) -> u16 {
364 self.0
365 }
366
367 #[inline]
369 pub fn is_inline_flow(&self) -> bool {
370 self.outside() == DisplayOutside::Inline && self.inside() == DisplayInside::Flow
371 }
372
373 #[inline]
375 pub const fn is_list_item(&self) -> bool {
376 (self.0 & Self::LIST_ITEM_MASK) != 0
377 }
378
379 pub fn is_ruby_level_container(&self) -> bool {
381 match *self {
382 #[cfg(feature = "gecko")]
383 Display::RubyBaseContainer | Display::RubyTextContainer => true,
384 _ => false,
385 }
386 }
387
388 pub fn is_ruby_type(&self) -> bool {
390 match self.inside() {
391 #[cfg(feature = "gecko")]
392 DisplayInside::Ruby
393 | DisplayInside::RubyBase
394 | DisplayInside::RubyText
395 | DisplayInside::RubyBaseContainer
396 | DisplayInside::RubyTextContainer => true,
397 _ => false,
398 }
399 }
400}
401
402impl Display {
404 #[inline]
406 pub fn inline() -> Self {
407 Display::Inline
408 }
409
410 pub fn is_item_container(&self) -> bool {
415 match self.inside() {
416 DisplayInside::Flex | DisplayInside::Grid | DisplayInside::GridLanes => true,
417 _ => false,
418 }
419 }
420
421 pub fn is_line_participant(&self) -> bool {
425 if self.is_inline_flow() {
426 return true;
427 }
428 match *self {
429 #[cfg(feature = "gecko")]
430 Display::Contents | Display::Ruby | Display::RubyBaseContainer => true,
431 _ => false,
432 }
433 }
434
435 pub fn equivalent_block_display(&self, is_root_element: bool) -> Self {
439 if is_root_element && (self.is_contents() || self.is_list_item()) {
441 return Display::Block;
442 }
443
444 match self.outside() {
445 DisplayOutside::Inline => {
446 let inside = match self.inside() {
447 DisplayInside::FlowRoot => DisplayInside::Flow,
450 inside => inside,
451 };
452 Display::from3(DisplayOutside::Block, inside, self.is_list_item())
453 },
454 DisplayOutside::Block | DisplayOutside::None => *self,
455 _ => Display::Block,
456 }
457 }
458
459 #[cfg(feature = "gecko")]
462 pub fn inlinify(&self) -> Self {
463 match self.outside() {
464 DisplayOutside::Block => {
465 let inside = match self.inside() {
466 DisplayInside::Flow => DisplayInside::FlowRoot,
469 inside => inside,
470 };
471 Display::from3(DisplayOutside::Inline, inside, self.is_list_item())
472 },
473 _ => *self,
474 }
475 }
476
477 #[inline]
479 pub fn is_contents(&self) -> bool {
480 match *self {
481 Display::Contents => true,
482 _ => false,
483 }
484 }
485
486 #[inline]
488 pub fn is_none(&self) -> bool {
489 *self == Display::None
490 }
491}
492
493enum DisplayKeyword {
494 Full(Display),
495 Inside(DisplayInside),
496 Outside(DisplayOutside),
497 ListItem,
498}
499
500impl DisplayKeyword {
501 fn parse(input: &mut Parser) -> Result<Self, ParseError> {
502 use self::DisplayKeyword::*;
503 Ok(try_match_ident_ignore_ascii_case! { input,
504 "none" => Full(Display::None),
505 "contents" => Full(Display::Contents),
506 "inline-block" => Full(Display::InlineBlock),
507 "inline-table" => Full(Display::InlineTable),
508 "-webkit-flex" => Full(Display::Flex),
509 "inline-flex" | "-webkit-inline-flex" => Full(Display::InlineFlex),
510 "inline-grid" => Full(Display::InlineGrid),
511 "inline-grid-lanes" if is_display_grid_lanes_enabled() => Full(Display::InlineGridLanes),
512 "table-caption" => Full(Display::TableCaption),
513 "table-row-group" => Full(Display::TableRowGroup),
514 "table-header-group" => Full(Display::TableHeaderGroup),
515 "table-footer-group" => Full(Display::TableFooterGroup),
516 "table-column" => Full(Display::TableColumn),
517 "table-column-group" => Full(Display::TableColumnGroup),
518 "table-row" => Full(Display::TableRow),
519 "table-cell" => Full(Display::TableCell),
520 #[cfg(feature = "gecko")]
521 "ruby-base" => Full(Display::RubyBase),
522 #[cfg(feature = "gecko")]
523 "ruby-base-container" => Full(Display::RubyBaseContainer),
524 #[cfg(feature = "gecko")]
525 "ruby-text" => Full(Display::RubyText),
526 #[cfg(feature = "gecko")]
527 "ruby-text-container" => Full(Display::RubyTextContainer),
528 #[cfg(feature = "gecko")]
529 "-webkit-box" => Full(Display::WebkitBox),
530 #[cfg(feature = "gecko")]
531 "-webkit-inline-box" => Full(Display::WebkitInlineBox),
532
533 "block" => Outside(DisplayOutside::Block),
536 "inline" => Outside(DisplayOutside::Inline),
537
538 "list-item" => ListItem,
539
540 "flow" => Inside(DisplayInside::Flow),
543 "flex" => Inside(DisplayInside::Flex),
544 "flow-root" => Inside(DisplayInside::FlowRoot),
545 "table" => Inside(DisplayInside::Table),
546 "grid" => Inside(DisplayInside::Grid),
547 "grid-lanes" if is_display_grid_lanes_enabled() => Inside(DisplayInside::GridLanes),
548 #[cfg(feature = "gecko")]
549 "ruby" => Inside(DisplayInside::Ruby),
550 })
551 }
552}
553
554impl ToCss for Display {
555 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
556 where
557 W: fmt::Write,
558 {
559 let outside = self.outside();
560 let inside = self.inside();
561 match *self {
562 Display::Block | Display::Inline => outside.to_css(dest),
563 Display::InlineBlock => dest.write_str("inline-block"),
564 #[cfg(feature = "gecko")]
565 Display::WebkitInlineBox => dest.write_str("-webkit-inline-box"),
566 Display::TableCaption => dest.write_str("table-caption"),
567 _ => match (outside, inside) {
568 (DisplayOutside::Inline, DisplayInside::Grid) => dest.write_str("inline-grid"),
569 (DisplayOutside::Inline, DisplayInside::GridLanes) => {
570 dest.write_str("inline-grid-lanes")
571 },
572 (DisplayOutside::Inline, DisplayInside::Flex) => dest.write_str("inline-flex"),
573 (DisplayOutside::Inline, DisplayInside::Table) => dest.write_str("inline-table"),
574 #[cfg(feature = "gecko")]
575 (DisplayOutside::Block, DisplayInside::Ruby) => dest.write_str("block ruby"),
576 (_, inside) => {
577 if self.is_list_item() {
578 if outside != DisplayOutside::Block {
579 outside.to_css(dest)?;
580 dest.write_char(' ')?;
581 }
582 if inside != DisplayInside::Flow {
583 inside.to_css(dest)?;
584 dest.write_char(' ')?;
585 }
586 dest.write_str("list-item")
587 } else {
588 inside.to_css(dest)
589 }
590 },
591 },
592 }
593 }
594}
595
596impl ToTyped for Display {
597 fn to_typed(&self, dest: &mut ThinVec<TypedValue>) -> Result<(), ()> {
598 let outside = self.outside();
605 let inside = self.inside();
606
607 #[cfg(feature = "gecko")]
608 if outside == DisplayOutside::Block && inside == DisplayInside::Ruby {
609 return Err(());
610 }
611
612 if self.is_list_item()
613 && (outside != DisplayOutside::Block || inside != DisplayInside::Flow)
614 {
615 return Err(());
616 }
617
618 let keyword = self.to_css_cssstring();
619 debug_assert!(!AsRef::<[u8]>::as_ref(&keyword).contains(&b' '));
620
621 dest.push(TypedValue::Keyword(KeywordValue(keyword)));
622 Ok(())
623 }
624}
625
626impl Parse for Display {
627 fn parse(_: &ParserContext, input: &mut Parser) -> Result<Display, ParseError> {
628 let mut got_list_item = false;
629 let mut inside = None;
630 let mut outside = None;
631 match DisplayKeyword::parse(input)? {
632 DisplayKeyword::Full(d) => return Ok(d),
633 DisplayKeyword::Outside(o) => {
634 outside = Some(o);
635 },
636 DisplayKeyword::Inside(i) => {
637 inside = Some(i);
638 },
639 DisplayKeyword::ListItem => {
640 got_list_item = true;
641 },
642 };
643
644 while let Ok(kw) = input.try_parse(DisplayKeyword::parse) {
645 match kw {
646 DisplayKeyword::ListItem if !got_list_item => {
647 got_list_item = true;
648 },
649 DisplayKeyword::Outside(o) if outside.is_none() => {
650 outside = Some(o);
651 },
652 DisplayKeyword::Inside(i) if inside.is_none() => {
653 inside = Some(i);
654 },
655 _ => return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError)),
656 }
657 }
658
659 let inside = inside.unwrap_or(DisplayInside::Flow);
660 let outside = outside.unwrap_or_else(|| inside.default_display_outside());
661 if got_list_item && !inside.is_valid_for_list_item() {
662 return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
663 }
664
665 Ok(Display::from3(outside, inside, got_list_item))
666 }
667}
668
669impl SpecifiedValueInfo for Display {
670 fn collect_completion_keywords(f: KeywordsCollectFn) {
671 f(&[
672 "block",
673 "contents",
674 "flex",
675 "flow-root",
676 "flow-root list-item",
677 "grid",
678 "grid-lanes",
679 "inline",
680 "inline-block",
681 "inline-flex",
682 "inline-grid",
683 "inline-grid-lanes",
684 "inline-table",
685 "inline list-item",
686 "inline flow-root list-item",
687 "list-item",
688 "none",
689 "block ruby",
690 "ruby",
691 "ruby-base",
692 "ruby-base-container",
693 "ruby-text",
694 "ruby-text-container",
695 "table",
696 "table-caption",
697 "table-cell",
698 "table-column",
699 "table-column-group",
700 "table-footer-group",
701 "table-header-group",
702 "table-row",
703 "table-row-group",
704 "-webkit-box",
705 "-webkit-inline-box",
706 ]);
707 }
708}
709
710pub type ContainIntrinsicSize = GenericContainIntrinsicSize<NonNegativeLength>;
712
713pub type LineClamp = GenericLineClamp<PositiveInteger>;
715
716pub type BaselineShift = GenericBaselineShift<LengthPercentage>;
718
719impl Parse for BaselineShift {
720 fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
721 if let Ok(lp) =
722 input.try_parse(|i| LengthPercentage::parse_quirky(context, i, AllowQuirks::Yes))
723 {
724 return Ok(BaselineShift::Length(lp));
725 }
726
727 Ok(BaselineShift::Keyword(BaselineShiftKeyword::parse(input)?))
728 }
729}
730
731#[derive(
734 Clone,
735 Copy,
736 Debug,
737 Eq,
738 FromPrimitive,
739 Hash,
740 MallocSizeOf,
741 Parse,
742 PartialEq,
743 SpecifiedValueInfo,
744 ToCss,
745 ToShmem,
746 ToComputedValue,
747 ToResolvedValue,
748 ToTyped,
749)]
750#[repr(u8)]
751pub enum DominantBaseline {
752 Auto,
756 #[parse(aliases = "text-after-edge")]
758 TextBottom,
759 Alphabetic,
761 Ideographic,
763 Middle,
767 Central,
769 Mathematical,
771 Hanging,
773 #[parse(aliases = "text-before-edge")]
775 TextTop,
776}
777
778#[derive(
781 Clone,
782 Copy,
783 Debug,
784 Eq,
785 FromPrimitive,
786 Hash,
787 MallocSizeOf,
788 Parse,
789 PartialEq,
790 SpecifiedValueInfo,
791 ToCss,
792 ToShmem,
793 ToComputedValue,
794 ToResolvedValue,
795 ToTyped,
796)]
797#[repr(u8)]
798pub enum AlignmentBaseline {
799 Baseline,
801 TextBottom,
803 #[cfg(feature = "gecko")]
805 Alphabetic,
806 #[cfg(feature = "gecko")]
808 Ideographic,
809 Middle,
813 #[cfg(feature = "gecko")]
815 Central,
816 #[cfg(feature = "gecko")]
818 Mathematical,
819 #[cfg(feature = "gecko")]
821 Hanging,
822 TextTop,
824 #[cfg(feature = "gecko")]
826 MozMiddleWithBaseline,
827}
828
829#[derive(
832 Clone,
833 Copy,
834 Debug,
835 Eq,
836 Hash,
837 MallocSizeOf,
838 Parse,
839 PartialEq,
840 SpecifiedValueInfo,
841 ToCss,
842 ToShmem,
843 ToComputedValue,
844 ToResolvedValue,
845 ToTyped,
846)]
847#[repr(u8)]
848pub enum BaselineSource {
849 Auto,
851 First,
853 Last,
855}
856
857impl BaselineSource {
858 pub fn parse_non_auto(input: &mut Parser) -> Result<Self, ParseError> {
860 Ok(try_match_ident_ignore_ascii_case! { input,
861 "first" => Self::First,
862 "last" => Self::Last,
863 })
864 }
865}
866
867#[allow(missing_docs)]
869#[derive(
870 Clone,
871 Copy,
872 Debug,
873 Deserialize,
874 Eq,
875 MallocSizeOf,
876 Parse,
877 PartialEq,
878 Serialize,
879 SpecifiedValueInfo,
880 ToComputedValue,
881 ToCss,
882 ToResolvedValue,
883 ToShmem,
884)]
885#[repr(u8)]
886pub enum ScrollSnapAxis {
887 X,
888 Y,
889 Block,
890 Inline,
891 Both,
892}
893
894#[allow(missing_docs)]
896#[derive(
897 Clone,
898 Copy,
899 Debug,
900 Deserialize,
901 Eq,
902 MallocSizeOf,
903 Parse,
904 PartialEq,
905 Serialize,
906 SpecifiedValueInfo,
907 ToComputedValue,
908 ToCss,
909 ToResolvedValue,
910 ToShmem,
911)]
912#[repr(u8)]
913pub enum ScrollSnapStrictness {
914 #[css(skip)]
915 None, Mandatory,
917 Proximity,
918}
919
920#[allow(missing_docs)]
922#[derive(
923 Clone,
924 Copy,
925 Debug,
926 Deserialize,
927 Eq,
928 MallocSizeOf,
929 PartialEq,
930 Serialize,
931 SpecifiedValueInfo,
932 ToComputedValue,
933 ToResolvedValue,
934 ToShmem,
935 ToTyped,
936)]
937#[repr(C)]
938#[typed(todo_derive_fields)]
939pub struct ScrollSnapType {
940 axis: ScrollSnapAxis,
941 strictness: ScrollSnapStrictness,
942}
943
944impl ScrollSnapType {
945 #[inline]
947 pub fn none() -> Self {
948 Self {
949 axis: ScrollSnapAxis::Both,
950 strictness: ScrollSnapStrictness::None,
951 }
952 }
953}
954
955impl Parse for ScrollSnapType {
956 fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
958 if input
959 .try_parse(|input| input.expect_ident_matching("none"))
960 .is_ok()
961 {
962 return Ok(ScrollSnapType::none());
963 }
964
965 let axis = ScrollSnapAxis::parse(input)?;
966 let strictness = input
967 .try_parse(ScrollSnapStrictness::parse)
968 .unwrap_or(ScrollSnapStrictness::Proximity);
969 Ok(Self { axis, strictness })
970 }
971}
972
973impl ToCss for ScrollSnapType {
974 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
975 where
976 W: Write,
977 {
978 if self.strictness == ScrollSnapStrictness::None {
979 return dest.write_str("none");
980 }
981 self.axis.to_css(dest)?;
982 if self.strictness != ScrollSnapStrictness::Proximity {
983 dest.write_char(' ')?;
984 self.strictness.to_css(dest)?;
985 }
986 Ok(())
987 }
988}
989
990#[allow(missing_docs)]
992#[derive(
993 Clone,
994 Copy,
995 Debug,
996 Eq,
997 FromPrimitive,
998 Hash,
999 MallocSizeOf,
1000 Parse,
1001 PartialEq,
1002 SpecifiedValueInfo,
1003 ToComputedValue,
1004 ToCss,
1005 ToResolvedValue,
1006 ToShmem,
1007)]
1008#[repr(u8)]
1009pub enum ScrollSnapAlignKeyword {
1010 None,
1011 Start,
1012 End,
1013 Center,
1014}
1015
1016#[allow(missing_docs)]
1018#[derive(
1019 Clone,
1020 Copy,
1021 Debug,
1022 Eq,
1023 MallocSizeOf,
1024 PartialEq,
1025 SpecifiedValueInfo,
1026 ToComputedValue,
1027 ToResolvedValue,
1028 ToShmem,
1029 ToTyped,
1030)]
1031#[repr(C)]
1032#[typed(todo_derive_fields)]
1033pub struct ScrollSnapAlign {
1034 block: ScrollSnapAlignKeyword,
1035 inline: ScrollSnapAlignKeyword,
1036}
1037
1038impl ScrollSnapAlign {
1039 #[inline]
1041 pub fn none() -> Self {
1042 ScrollSnapAlign {
1043 block: ScrollSnapAlignKeyword::None,
1044 inline: ScrollSnapAlignKeyword::None,
1045 }
1046 }
1047}
1048
1049impl Parse for ScrollSnapAlign {
1050 fn parse(_context: &ParserContext, input: &mut Parser) -> Result<ScrollSnapAlign, ParseError> {
1052 let block = ScrollSnapAlignKeyword::parse(input)?;
1053 let inline = input
1054 .try_parse(ScrollSnapAlignKeyword::parse)
1055 .unwrap_or(block);
1056 Ok(ScrollSnapAlign { block, inline })
1057 }
1058}
1059
1060impl ToCss for ScrollSnapAlign {
1061 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
1062 where
1063 W: Write,
1064 {
1065 self.block.to_css(dest)?;
1066 if self.block != self.inline {
1067 dest.write_char(' ')?;
1068 self.inline.to_css(dest)?;
1069 }
1070 Ok(())
1071 }
1072}
1073
1074#[allow(missing_docs)]
1075#[derive(
1076 Clone,
1077 Copy,
1078 Debug,
1079 Deserialize,
1080 Eq,
1081 MallocSizeOf,
1082 Parse,
1083 PartialEq,
1084 Serialize,
1085 SpecifiedValueInfo,
1086 ToComputedValue,
1087 ToCss,
1088 ToResolvedValue,
1089 ToShmem,
1090 ToTyped,
1091)]
1092#[repr(u8)]
1093pub enum ScrollSnapStop {
1094 Normal,
1095 Always,
1096}
1097
1098#[allow(missing_docs)]
1099#[derive(
1100 Clone,
1101 Copy,
1102 Debug,
1103 Deserialize,
1104 Eq,
1105 MallocSizeOf,
1106 Parse,
1107 PartialEq,
1108 Serialize,
1109 SpecifiedValueInfo,
1110 ToComputedValue,
1111 ToCss,
1112 ToResolvedValue,
1113 ToShmem,
1114 ToTyped,
1115)]
1116#[repr(u8)]
1117pub enum OverscrollBehavior {
1118 Auto,
1119 Contain,
1120 Chain,
1121 None,
1122}
1123
1124#[allow(missing_docs)]
1125#[derive(
1126 Clone,
1127 Copy,
1128 Debug,
1129 Deserialize,
1130 Eq,
1131 MallocSizeOf,
1132 Parse,
1133 PartialEq,
1134 Serialize,
1135 SpecifiedValueInfo,
1136 ToComputedValue,
1137 ToCss,
1138 ToResolvedValue,
1139 ToShmem,
1140 ToTyped,
1141)]
1142#[repr(u8)]
1143pub enum OverflowAnchor {
1144 Auto,
1145 None,
1146}
1147
1148#[derive(
1149 Clone,
1150 Debug,
1151 Default,
1152 MallocSizeOf,
1153 PartialEq,
1154 SpecifiedValueInfo,
1155 ToComputedValue,
1156 ToCss,
1157 ToResolvedValue,
1158 ToShmem,
1159 ToTyped,
1160)]
1161#[css(comma)]
1162#[repr(C)]
1163#[typed(no_multiple_values)]
1164pub struct WillChange {
1171 #[css(iterable, if_empty = "auto")]
1176 features: crate::OwnedSlice<CustomIdent>,
1177 #[css(skip)]
1180 pub bits: WillChangeBits,
1181}
1182
1183impl WillChange {
1184 #[inline]
1185 pub fn auto() -> Self {
1187 Self::default()
1188 }
1189}
1190
1191#[derive(
1193 Clone,
1194 Copy,
1195 Debug,
1196 Default,
1197 Eq,
1198 MallocSizeOf,
1199 PartialEq,
1200 SpecifiedValueInfo,
1201 ToComputedValue,
1202 ToResolvedValue,
1203 ToShmem,
1204)]
1205#[repr(C)]
1206pub struct WillChangeBits(u16);
1207bitflags! {
1208 impl WillChangeBits: u16 {
1209 const STACKING_CONTEXT_UNCONDITIONAL = 1 << 0;
1212 const TRANSFORM = 1 << 1;
1214 const SCROLL = 1 << 2;
1216 const CONTAIN = 1 << 3;
1218 const OPACITY = 1 << 4;
1220 const PERSPECTIVE = 1 << 5;
1222 const Z_INDEX = 1 << 6;
1224 const FIXPOS_CB_NON_SVG = 1 << 7;
1227 const POSITION = 1 << 8;
1229 const VIEW_TRANSITION_NAME = 1 << 9;
1231 const BACKDROP_ROOT = 1 << 10;
1234 }
1235}
1236
1237fn change_bits_for_longhand(longhand: LonghandId) -> WillChangeBits {
1238 match longhand {
1239 LonghandId::Opacity => WillChangeBits::OPACITY | WillChangeBits::BACKDROP_ROOT,
1240 LonghandId::Contain => WillChangeBits::CONTAIN,
1241 LonghandId::Perspective => WillChangeBits::PERSPECTIVE,
1242 LonghandId::Position => {
1243 WillChangeBits::STACKING_CONTEXT_UNCONDITIONAL | WillChangeBits::POSITION
1244 },
1245 LonghandId::ZIndex => WillChangeBits::Z_INDEX,
1246 LonghandId::Transform
1247 | LonghandId::TransformStyle
1248 | LonghandId::Translate
1249 | LonghandId::Rotate
1250 | LonghandId::Scale
1251 | LonghandId::OffsetPath => WillChangeBits::TRANSFORM,
1252 LonghandId::Filter | LonghandId::BackdropFilter => {
1253 WillChangeBits::STACKING_CONTEXT_UNCONDITIONAL
1254 | WillChangeBits::BACKDROP_ROOT
1255 | WillChangeBits::FIXPOS_CB_NON_SVG
1256 },
1257 LonghandId::ViewTransitionName => {
1258 WillChangeBits::VIEW_TRANSITION_NAME | WillChangeBits::BACKDROP_ROOT
1259 },
1260 LonghandId::MixBlendMode => {
1261 WillChangeBits::STACKING_CONTEXT_UNCONDITIONAL | WillChangeBits::BACKDROP_ROOT
1262 },
1263 LonghandId::Isolation | LonghandId::MaskImage => {
1264 WillChangeBits::STACKING_CONTEXT_UNCONDITIONAL
1265 },
1266 LonghandId::ClipPath => {
1267 WillChangeBits::STACKING_CONTEXT_UNCONDITIONAL | WillChangeBits::BACKDROP_ROOT
1268 },
1269 _ => WillChangeBits::empty(),
1270 }
1271}
1272
1273fn change_bits_for_maybe_property(ident: &str, context: &ParserContext) -> WillChangeBits {
1274 let id = match PropertyId::parse_ignoring_rule_type(ident, context) {
1275 Ok(id) => id,
1276 Err(..) => return WillChangeBits::empty(),
1277 };
1278
1279 match id.as_shorthand() {
1280 Ok(shorthand) => shorthand
1281 .longhands()
1282 .fold(WillChangeBits::empty(), |flags, p| {
1283 flags | change_bits_for_longhand(p)
1284 }),
1285 Err(PropertyDeclarationId::Longhand(longhand)) => change_bits_for_longhand(longhand),
1286 Err(PropertyDeclarationId::Custom(..)) => WillChangeBits::empty(),
1287 }
1288}
1289
1290impl Parse for WillChange {
1291 fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
1293 if input
1294 .try_parse(|input| input.expect_ident_matching("auto"))
1295 .is_ok()
1296 {
1297 return Ok(Self::default());
1298 }
1299
1300 let mut bits = WillChangeBits::empty();
1301 let custom_idents = input.parse_comma_separated(|i| {
1302 let parser_ident = i.expect_ident()?;
1303 let ident =
1304 CustomIdent::from_ident(parser_ident, &["will-change", "none", "all", "auto"])?;
1305
1306 if context.in_ua_sheet() && ident.0 == atom!("-moz-fixed-pos-containing-block") {
1307 bits |= WillChangeBits::FIXPOS_CB_NON_SVG;
1308 } else if ident.0 == atom!("scroll-position") {
1309 bits |= WillChangeBits::SCROLL;
1310 } else {
1311 bits |= change_bits_for_maybe_property(parser_ident, context);
1312 }
1313 Ok(ident)
1314 })?;
1315
1316 Ok(Self {
1317 features: custom_idents.into(),
1318 bits,
1319 })
1320 }
1321}
1322
1323#[derive(
1325 Clone,
1326 Copy,
1327 Debug,
1328 Eq,
1329 MallocSizeOf,
1330 Parse,
1331 PartialEq,
1332 SpecifiedValueInfo,
1333 ToComputedValue,
1334 ToCss,
1335 ToResolvedValue,
1336 ToShmem,
1337 ToTyped,
1338)]
1339#[css(bitflags(single = "none,auto,manipulation", mixed = "pan-x,pan-y,pinch-zoom"))]
1340#[repr(C)]
1341pub struct TouchAction(u8);
1342bitflags! {
1343 impl TouchAction: u8 {
1344 const NONE = 1 << 0;
1346 const AUTO = 1 << 1;
1348 const PAN_X = 1 << 2;
1350 const PAN_Y = 1 << 3;
1352 const MANIPULATION = 1 << 4;
1354 const PINCH_ZOOM = 1 << 5;
1356 }
1357}
1358
1359impl TouchAction {
1360 #[inline]
1361 pub fn auto() -> TouchAction {
1363 TouchAction::AUTO
1364 }
1365}
1366
1367#[derive(
1368 Clone,
1369 Copy,
1370 Debug,
1371 Eq,
1372 MallocSizeOf,
1373 Parse,
1374 PartialEq,
1375 SpecifiedValueInfo,
1376 ToComputedValue,
1377 ToCss,
1378 ToResolvedValue,
1379 ToShmem,
1380 ToTyped,
1381)]
1382#[css(bitflags(
1383 single = "none,strict,content",
1384 mixed = "size,layout,style,paint,inline-size",
1385 overlapping_bits
1386))]
1387#[repr(C)]
1388pub struct Contain(u8);
1390bitflags! {
1391 impl Contain: u8 {
1392 const NONE = 0;
1394 const INLINE_SIZE = 1 << 0;
1396 const BLOCK_SIZE = 1 << 1;
1398 const LAYOUT = 1 << 2;
1400 const STYLE = 1 << 3;
1402 const PAINT = 1 << 4;
1404 const SIZE = 1 << 5 | Contain::INLINE_SIZE.bits() | Contain::BLOCK_SIZE.bits();
1406 const CONTENT = 1 << 6 | Contain::LAYOUT.bits() | Contain::STYLE.bits() | Contain::PAINT.bits();
1408 const STRICT = 1 << 7 | Contain::LAYOUT.bits() | Contain::STYLE.bits() | Contain::PAINT.bits() | Contain::SIZE.bits();
1410 }
1411}
1412
1413impl Parse for ContainIntrinsicSize {
1414 fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
1416 if let Ok(l) = input.try_parse(|i| NonNegativeLength::parse(context, i)) {
1417 return Ok(Self::Length(l));
1418 }
1419
1420 if input.try_parse(|i| i.expect_ident_matching("auto")).is_ok() {
1421 if input.try_parse(|i| i.expect_ident_matching("none")).is_ok() {
1422 return Ok(Self::AutoNone);
1423 }
1424
1425 let l = NonNegativeLength::parse(context, input)?;
1426 return Ok(Self::AutoLength(l));
1427 }
1428
1429 input.expect_ident_matching("none")?;
1430 Ok(Self::None)
1431 }
1432}
1433
1434impl Parse for MaxLines<PositiveInteger> {
1435 fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
1436 let mut lines = None;
1437 let mut auto = false;
1438
1439 loop {
1440 if lines.is_none()
1441 && let Ok(value) = input.try_parse(|i| PositiveInteger::parse(context, i))
1442 {
1443 lines = Some(value);
1444 continue;
1445 }
1446
1447 if !auto && input.try_parse(|i| i.expect_ident_matching("auto")).is_ok() {
1448 auto = true;
1449 continue;
1450 }
1451
1452 break;
1453 }
1454
1455 match (lines, auto) {
1456 (Some(value), true) => Ok(MaxLines::lines(value, true)),
1457 (Some(value), false) => Ok(MaxLines::lines(value, false)),
1458 (None, true) => Ok(MaxLines::auto()),
1459 (None, false) => Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError)),
1460 }
1461 }
1462}
1463
1464impl Parse for LineClamp {
1465 fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
1466 if input.try_parse(|i| i.expect_ident_matching("none")).is_ok() {
1467 return Ok(Self::none());
1468 }
1469
1470 let mut max_lines = None;
1471 let mut block_ellipsis = None;
1472
1473 loop {
1474 if max_lines.is_none()
1475 && let Ok(value) = input.try_parse(|i| MaxLines::parse(context, i))
1476 {
1477 max_lines = Some(value);
1478 continue;
1479 }
1480 if block_ellipsis.is_none()
1481 && let Ok(value) = input.try_parse(|i| BlockEllipsis::parse(context, i))
1482 {
1483 block_ellipsis = Some(value);
1484 continue;
1485 }
1486
1487 break;
1488 }
1489
1490 if max_lines.is_none() && block_ellipsis.is_none() {
1491 return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
1492 }
1493
1494 let webkit_legacy = input
1495 .try_parse(|i| i.expect_ident_matching("-webkit-legacy"))
1496 .is_ok();
1497
1498 let block_ellipsis = block_ellipsis.unwrap_or(BlockEllipsis::Ellipsis);
1499 let max_lines = max_lines.unwrap_or_else(MaxLines::auto);
1500
1501 Ok(Self {
1502 max_lines,
1503 block_ellipsis,
1504 webkit_legacy,
1505 })
1506 }
1507}
1508
1509impl LineClamp {
1510 pub fn parse_legacy(context: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
1512 if let Ok(value) =
1513 input.try_parse(|i| crate::values::specified::PositiveInteger::parse(context, i))
1514 {
1515 return Ok(Self {
1516 max_lines: MaxLines::lines(value, false),
1517 block_ellipsis: BlockEllipsis::Ellipsis,
1518 webkit_legacy: true,
1519 });
1520 }
1521 input.expect_ident_matching("none")?;
1522 Ok(Self::none())
1523 }
1524
1525 #[cfg_attr(feature = "servo", allow(unused))]
1527 pub(crate) fn to_css_legacy<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
1528 where
1529 W: fmt::Write,
1530 {
1531 if self.is_none() {
1532 return dest.write_str("none");
1533 }
1534
1535 if !self.webkit_legacy || !self.block_ellipsis.is_ellipsis() {
1536 return Ok(());
1537 }
1538
1539 let Some(lines) = self.max_lines.lines_value() else {
1540 return Ok(());
1541 };
1542
1543 lines.to_css(dest)
1544 }
1545}
1546
1547#[derive(
1549 Clone,
1550 Copy,
1551 Debug,
1552 Deserialize,
1553 Eq,
1554 FromPrimitive,
1555 MallocSizeOf,
1556 Parse,
1557 PartialEq,
1558 Serialize,
1559 SpecifiedValueInfo,
1560 ToAnimatedValue,
1561 ToComputedValue,
1562 ToCss,
1563 ToResolvedValue,
1564 ToShmem,
1565 ToTyped,
1566)]
1567#[repr(u8)]
1568pub enum ContentVisibility {
1569 Auto,
1573 Hidden,
1575 Visible,
1577}
1578
1579#[derive(
1580 Clone,
1581 Copy,
1582 Debug,
1583 PartialEq,
1584 Eq,
1585 MallocSizeOf,
1586 SpecifiedValueInfo,
1587 ToComputedValue,
1588 ToCss,
1589 Parse,
1590 ToResolvedValue,
1591 ToShmem,
1592 ToTyped,
1593)]
1594#[css(bitflags(
1595 single = "normal",
1596 mixed = "size,inline-size,scroll-state",
1597 validate_mixed = "Self::validate_mixed_flags",
1598))]
1599#[repr(C)]
1600pub struct ContainerType(u8);
1607bitflags! {
1608 impl ContainerType: u8 {
1609 const NORMAL = 0;
1611 const INLINE_SIZE = 1 << 0;
1613 const SIZE = 1 << 1;
1615 const SCROLL_STATE = 1 << 2;
1617 }
1618}
1619
1620impl ContainerType {
1621 fn validate_mixed_flags(&self) -> bool {
1622 if self.contains(Self::SIZE | Self::INLINE_SIZE) {
1624 return false;
1625 }
1626 if self.contains(Self::SCROLL_STATE) && !crate::pref!("layout.css.scroll-state.enabled") {
1627 return false;
1628 }
1629 true
1630 }
1631
1632 pub fn is_normal(self) -> bool {
1634 self == Self::NORMAL
1635 }
1636
1637 pub fn is_size_container_type(self) -> bool {
1639 self.intersects(Self::SIZE | Self::INLINE_SIZE)
1640 }
1641}
1642
1643#[repr(transparent)]
1645#[derive(
1646 Clone,
1647 Debug,
1648 MallocSizeOf,
1649 PartialEq,
1650 SpecifiedValueInfo,
1651 ToComputedValue,
1652 ToCss,
1653 ToResolvedValue,
1654 ToShmem,
1655 ToTyped,
1656)]
1657pub struct ContainerName(#[css(iterable, if_empty = "none")] pub crate::OwnedSlice<CustomIdent>);
1658
1659impl ContainerName {
1660 pub fn none() -> Self {
1662 Self(Default::default())
1663 }
1664
1665 pub fn is_none(&self) -> bool {
1667 self.0.is_empty()
1668 }
1669
1670 fn parse_internal(input: &mut Parser, for_query: bool) -> Result<Self, ParseError> {
1671 let mut idents = vec![];
1672 let first = input.expect_ident()?;
1673 if !for_query && first.eq_ignore_ascii_case("none") {
1674 return Ok(Self::none());
1675 }
1676 const DISALLOWED_CONTAINER_NAMES: &[&str] = &["none", "not", "or", "and"];
1677 idents.push(CustomIdent::from_ident(first, DISALLOWED_CONTAINER_NAMES)?);
1678 if !for_query {
1679 while let Ok(name) =
1680 input.try_parse(|input| CustomIdent::parse(input, DISALLOWED_CONTAINER_NAMES))
1681 {
1682 idents.push(name);
1683 }
1684 }
1685 Ok(ContainerName(idents.into()))
1686 }
1687
1688 pub fn parse_for_query(_: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
1692 Self::parse_internal(input, true)
1693 }
1694}
1695
1696impl Parse for ContainerName {
1697 fn parse(_: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
1698 Self::parse_internal(input, false)
1699 }
1700}
1701
1702pub type Perspective = GenericPerspective<NonNegativeLength>;
1704
1705impl Perspective {
1706 pub(crate) fn parse_legacy(
1708 context: &ParserContext,
1709 input: &mut Parser,
1710 ) -> Result<Self, ParseError> {
1711 use crate::values::generics::NonNegative;
1712 use crate::values::specified::{AllowQuirks, Length};
1713 if let Ok(l) = input.try_parse(|input| {
1714 Length::parse_non_negative_quirky(context, input, AllowQuirks::Always)
1715 }) {
1716 return Ok(Self::Length(NonNegative(l)));
1717 }
1718 Self::parse(context, input)
1719 }
1720}
1721
1722#[allow(missing_docs)]
1724#[derive(
1725 Clone,
1726 Copy,
1727 Debug,
1728 Deserialize,
1729 Eq,
1730 FromPrimitive,
1731 Hash,
1732 MallocSizeOf,
1733 Parse,
1734 PartialEq,
1735 Serialize,
1736 SpecifiedValueInfo,
1737 ToComputedValue,
1738 ToCss,
1739 ToResolvedValue,
1740 ToShmem,
1741 ToTyped,
1742)]
1743#[repr(u8)]
1744pub enum Float {
1745 Left,
1746 Right,
1747 None,
1748 InlineStart,
1750 InlineEnd,
1751}
1752
1753impl Float {
1754 pub fn is_floating(self) -> bool {
1756 self != Self::None
1757 }
1758}
1759
1760#[allow(missing_docs)]
1762#[derive(
1763 Clone,
1764 Copy,
1765 Debug,
1766 Deserialize,
1767 Eq,
1768 FromPrimitive,
1769 Hash,
1770 MallocSizeOf,
1771 Parse,
1772 PartialEq,
1773 Serialize,
1774 SpecifiedValueInfo,
1775 ToComputedValue,
1776 ToCss,
1777 ToResolvedValue,
1778 ToShmem,
1779 ToTyped,
1780)]
1781#[repr(u8)]
1782pub enum Clear {
1783 None,
1784 Left,
1785 Right,
1786 Both,
1787 InlineStart,
1789 InlineEnd,
1790}
1791
1792#[allow(missing_docs)]
1794#[derive(
1795 Clone,
1796 Copy,
1797 Debug,
1798 Deserialize,
1799 Eq,
1800 Hash,
1801 MallocSizeOf,
1802 Parse,
1803 PartialEq,
1804 Serialize,
1805 SpecifiedValueInfo,
1806 ToCss,
1807 ToShmem,
1808 ToTyped,
1809)]
1810pub enum Resize {
1811 None,
1812 Both,
1813 Horizontal,
1814 Vertical,
1815 Inline,
1817 Block,
1818}
1819
1820#[allow(missing_docs)]
1824#[derive(
1825 Clone,
1826 Copy,
1827 Debug,
1828 Eq,
1829 Hash,
1830 MallocSizeOf,
1831 Parse,
1832 PartialEq,
1833 SpecifiedValueInfo,
1834 ToCss,
1835 ToComputedValue,
1836 ToResolvedValue,
1837 ToShmem,
1838 ToTyped,
1839)]
1840#[repr(u8)]
1841pub enum Appearance {
1842 None,
1844 Auto,
1849 Searchfield,
1851 Textarea,
1853 Checkbox,
1855 Radio,
1857 Menulist,
1859 Listbox,
1861 Meter,
1863 ProgressBar,
1865 Button,
1867 Textfield,
1869 MenulistButton,
1871 #[parse(condition = "appearance_base_enabled")]
1873 Base,
1874 #[parse(condition = "appearance_base_select_enabled")]
1877 BaseSelect,
1878 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1880 Menupopup,
1881 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1883 MozMenulistArrowButton,
1884 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1886 NumberInput,
1887 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1889 PasswordInput,
1890 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1892 Range,
1893 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1895 ScrollbarHorizontal,
1896 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1897 ScrollbarVertical,
1898 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1902 ScrollbarbuttonUp,
1903 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1904 ScrollbarbuttonDown,
1905 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1906 ScrollbarbuttonLeft,
1907 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1908 ScrollbarbuttonRight,
1909 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1911 ScrollbarthumbHorizontal,
1912 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1913 ScrollbarthumbVertical,
1914 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1916 Scrollcorner,
1917 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1919 SpinnerUpbutton,
1920 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1922 SpinnerDownbutton,
1923 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1925 Toolbarbutton,
1926 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1928 Tooltip,
1929
1930 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1932 MozSidebar,
1933
1934 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1936 MozMacHelpButton,
1937
1938 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1942 MozMacWindow,
1943
1944 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1946 MozWindowButtonBox,
1947 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1948 MozWindowButtonClose,
1949 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1950 MozWindowButtonMaximize,
1951 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1952 MozWindowButtonMinimize,
1953 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1954 MozWindowButtonRestore,
1955 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1956 MozWindowTitlebar,
1957 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1958 MozWindowTitlebarMaximized,
1959 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1960 MozWindowDecorations,
1961
1962 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1963 MozMacDisclosureButtonClosed,
1964 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1965 MozMacDisclosureButtonOpen,
1966
1967 #[css(skip)]
1971 FocusOutline,
1972
1973 #[css(skip)]
1975 Count,
1976}
1977
1978impl Appearance {
1979 #[cfg_attr(feature = "servo", allow(unused))]
1981 pub(crate) fn parse_legacy(
1982 context: &ParserContext,
1983 input: &mut Parser,
1984 ) -> Result<Self, ParseError> {
1985 Self::parse(context, input)
1987 }
1988}
1989
1990#[allow(missing_docs)]
1994#[derive(
1995 Clone,
1996 Copy,
1997 Debug,
1998 Eq,
1999 Hash,
2000 MallocSizeOf,
2001 Parse,
2002 PartialEq,
2003 SpecifiedValueInfo,
2004 ToCss,
2005 ToComputedValue,
2006 ToResolvedValue,
2007 ToShmem,
2008 ToTyped,
2009)]
2010#[repr(u8)]
2011pub enum BreakBetween {
2012 Always,
2013 Auto,
2014 Page,
2015 Avoid,
2016 Left,
2017 Right,
2018}
2019
2020impl BreakBetween {
2021 #[cfg_attr(feature = "servo", allow(unused))]
2025 #[inline]
2026 pub(crate) fn parse_legacy(_: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
2027 let break_value = BreakBetween::parse(input)?;
2028 match break_value {
2029 BreakBetween::Always => Ok(BreakBetween::Page),
2030 BreakBetween::Auto | BreakBetween::Avoid | BreakBetween::Left | BreakBetween::Right => {
2031 Ok(break_value)
2032 },
2033 BreakBetween::Page => Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError)),
2034 }
2035 }
2036
2037 #[cfg_attr(feature = "servo", allow(unused))]
2041 pub(crate) fn to_css_legacy<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
2042 where
2043 W: Write,
2044 {
2045 match *self {
2046 BreakBetween::Auto | BreakBetween::Avoid | BreakBetween::Left | BreakBetween::Right => {
2047 self.to_css(dest)
2048 },
2049 BreakBetween::Page => dest.write_str("always"),
2050 BreakBetween::Always => Ok(()),
2051 }
2052 }
2053}
2054
2055#[allow(missing_docs)]
2059#[derive(
2060 Clone,
2061 Copy,
2062 Debug,
2063 Eq,
2064 Hash,
2065 MallocSizeOf,
2066 Parse,
2067 PartialEq,
2068 SpecifiedValueInfo,
2069 ToCss,
2070 ToComputedValue,
2071 ToResolvedValue,
2072 ToShmem,
2073 ToTyped,
2074)]
2075#[repr(u8)]
2076pub enum BreakWithin {
2077 Auto,
2078 Avoid,
2079 AvoidPage,
2080 AvoidColumn,
2081}
2082
2083impl BreakWithin {
2084 #[cfg_attr(feature = "servo", allow(unused))]
2088 #[inline]
2089 pub(crate) fn parse_legacy(_: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
2090 let break_value = BreakWithin::parse(input)?;
2091 match break_value {
2092 BreakWithin::Auto | BreakWithin::Avoid => Ok(break_value),
2093 BreakWithin::AvoidPage | BreakWithin::AvoidColumn => {
2094 Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError))
2095 },
2096 }
2097 }
2098
2099 #[cfg_attr(feature = "servo", allow(unused))]
2103 pub(crate) fn to_css_legacy<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
2104 where
2105 W: Write,
2106 {
2107 match *self {
2108 BreakWithin::Auto | BreakWithin::Avoid => self.to_css(dest),
2109 BreakWithin::AvoidPage | BreakWithin::AvoidColumn => Ok(()),
2110 }
2111 }
2112}
2113
2114#[allow(missing_docs)]
2116#[derive(
2117 Clone,
2118 Copy,
2119 Debug,
2120 Eq,
2121 Hash,
2122 MallocSizeOf,
2123 PartialEq,
2124 SpecifiedValueInfo,
2125 ToCss,
2126 ToComputedValue,
2127 ToResolvedValue,
2128 ToShmem,
2129 ToTyped,
2130)]
2131#[repr(u8)]
2132pub enum Overflow {
2133 Visible,
2134 Hidden,
2135 Scroll,
2136 Auto,
2137 Clip,
2138}
2139
2140impl Parse for Overflow {
2143 fn parse(_: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
2144 Ok(try_match_ident_ignore_ascii_case! { input,
2145 "visible" => Self::Visible,
2146 "hidden" => Self::Hidden,
2147 "scroll" => Self::Scroll,
2148 "auto" | "overlay" => Self::Auto,
2149 "clip" => Self::Clip,
2150 "-moz-hidden-unscrollable" if crate::pref!("layout.css.overflow-moz-hidden-unscrollable.enabled") => {
2151 Overflow::Clip
2152 },
2153 })
2154 }
2155}
2156
2157impl Overflow {
2158 #[inline]
2160 pub fn is_scrollable(&self) -> bool {
2161 matches!(*self, Self::Hidden | Self::Scroll | Self::Auto)
2162 }
2163 #[inline]
2166 pub fn to_scrollable(&self) -> Self {
2167 match *self {
2168 Self::Hidden | Self::Scroll | Self::Auto => *self,
2169 Self::Visible => Self::Auto,
2170 Self::Clip => Self::Hidden,
2171 }
2172 }
2173}
2174
2175#[derive(
2176 Clone,
2177 Copy,
2178 Debug,
2179 Eq,
2180 MallocSizeOf,
2181 Parse,
2182 PartialEq,
2183 SpecifiedValueInfo,
2184 ToComputedValue,
2185 ToCss,
2186 ToResolvedValue,
2187 ToShmem,
2188 ToTyped,
2189)]
2190#[repr(C)]
2191#[css(bitflags(
2192 single = "auto",
2193 mixed = "stable,both-edges",
2194 validate_mixed = "Self::has_stable"
2195))]
2196pub struct ScrollbarGutter(u8);
2199bitflags! {
2200 impl ScrollbarGutter: u8 {
2201 const AUTO = 0;
2203 const STABLE = 1 << 0;
2205 const BOTH_EDGES = 1 << 1;
2207 }
2208}
2209
2210impl ScrollbarGutter {
2211 #[inline]
2212 fn has_stable(&self) -> bool {
2213 self.intersects(Self::STABLE)
2214 }
2215}
2216
2217#[derive(
2219 Clone, Debug, MallocSizeOf, PartialEq, Parse, SpecifiedValueInfo, ToCss, ToShmem, ToTyped,
2220)]
2221#[allow(missing_docs)]
2222#[typed(todo_derive_fields)]
2223pub enum Zoom {
2224 Normal,
2225 #[parse(condition = "ParserContext::in_ua_sheet")]
2228 Document,
2229 Value(NonNegativeNumberOrPercentage),
2230}
2231
2232impl Zoom {
2233 #[inline]
2235 pub fn new_number(n: f32) -> Self {
2236 Self::Value(NonNegativeNumberOrPercentage::new_number(n))
2237 }
2238}
2239
2240pub use crate::values::generics::box_::PositionProperty;
2241
2242#[allow(missing_docs)]
2244#[derive(
2245 Clone,
2246 Copy,
2247 Debug,
2248 Deserialize,
2249 Eq,
2250 FromPrimitive,
2251 Hash,
2252 MallocSizeOf,
2253 Parse,
2254 PartialEq,
2255 Serialize,
2256 SpecifiedValueInfo,
2257 ToComputedValue,
2258 ToCss,
2259 ToResolvedValue,
2260 ToShmem,
2261 ToTyped,
2262)]
2263#[repr(u8)]
2264pub enum TopLayer {
2265 None,
2266 Auto,
2267}
2268
2269#[allow(missing_docs)]
2271#[derive(
2272 Clone,
2273 Copy,
2274 Debug,
2275 Deserialize,
2276 Eq,
2277 FromPrimitive,
2278 Hash,
2279 MallocSizeOf,
2280 Parse,
2281 PartialEq,
2282 Serialize,
2283 SpecifiedValueInfo,
2284 ToComputedValue,
2285 ToCss,
2286 ToResolvedValue,
2287 ToShmem,
2288 ToTyped,
2289)]
2290#[repr(u8)]
2291pub enum ScrollBehavior {
2292 Auto,
2293 Smooth,
2294}
2295
2296#[allow(missing_docs)]
2298#[derive(
2299 Clone,
2300 Copy,
2301 Debug,
2302 Deserialize,
2303 Eq,
2304 FromPrimitive,
2305 Hash,
2306 MallocSizeOf,
2307 Parse,
2308 PartialEq,
2309 Serialize,
2310 SpecifiedValueInfo,
2311 ToComputedValue,
2312 ToCss,
2313 ToResolvedValue,
2314 ToShmem,
2315 ToTyped,
2316)]
2317#[repr(u8)]
2318pub enum Isolation {
2319 Auto,
2320 Isolate,
2321}
2322
2323#[allow(missing_docs)]
2325#[derive(
2326 Clone,
2327 Copy,
2328 Debug,
2329 Deserialize,
2330 Eq,
2331 FromPrimitive,
2332 Hash,
2333 MallocSizeOf,
2334 Parse,
2335 PartialEq,
2336 Serialize,
2337 SpecifiedValueInfo,
2338 ToComputedValue,
2339 ToCss,
2340 ToResolvedValue,
2341 ToShmem,
2342 ToTyped,
2343)]
2344#[repr(u8)]
2345pub enum BackfaceVisibility {
2346 Visible,
2347 Hidden,
2348}
2349
2350#[allow(missing_docs)]
2352#[derive(
2353 Clone,
2354 Copy,
2355 Debug,
2356 Deserialize,
2357 Eq,
2358 FromPrimitive,
2359 Hash,
2360 MallocSizeOf,
2361 Parse,
2362 PartialEq,
2363 Serialize,
2364 SpecifiedValueInfo,
2365 ToComputedValue,
2366 ToCss,
2367 ToResolvedValue,
2368 ToShmem,
2369 ToTyped,
2370)]
2371#[repr(u8)]
2372pub enum Orient {
2373 Inline,
2374 Block,
2375 Horizontal,
2376 Vertical,
2377}
2378
2379#[allow(missing_docs)]
2381#[derive(
2382 Clone,
2383 Copy,
2384 Debug,
2385 Deserialize,
2386 Eq,
2387 FromPrimitive,
2388 Hash,
2389 MallocSizeOf,
2390 Parse,
2391 PartialEq,
2392 Serialize,
2393 SpecifiedValueInfo,
2394 ToAnimatedValue,
2395 ToComputedValue,
2396 ToCss,
2397 ToResolvedValue,
2398 ToShmem,
2399 ToTyped,
2400)]
2401#[repr(u8)]
2402pub enum Visibility {
2403 Visible,
2404 Hidden,
2405 Collapse,
2406}
2407
2408#[allow(missing_docs)]
2410#[derive(
2411 Clone,
2412 Copy,
2413 Debug,
2414 Deserialize,
2415 Eq,
2416 FromPrimitive,
2417 Hash,
2418 MallocSizeOf,
2419 Parse,
2420 PartialEq,
2421 Serialize,
2422 SpecifiedValueInfo,
2423 ToComputedValue,
2424 ToCss,
2425 ToResolvedValue,
2426 ToShmem,
2427 ToTyped,
2428)]
2429#[repr(u8)]
2430pub enum BoxCollapse {
2431 Flex,
2432 Legacy,
2433}
2434
2435#[allow(missing_docs)]
2437#[derive(
2438 Clone,
2439 Copy,
2440 Debug,
2441 Deserialize,
2442 Eq,
2443 FromPrimitive,
2444 Hash,
2445 MallocSizeOf,
2446 Parse,
2447 PartialEq,
2448 Serialize,
2449 SpecifiedValueInfo,
2450 ToComputedValue,
2451 ToCss,
2452 ToResolvedValue,
2453 ToShmem,
2454 ToTyped,
2455)]
2456#[repr(u8)]
2457pub enum TextOrientation {
2458 Mixed,
2459 Upright,
2460 #[cfg_attr(feature = "gecko", parse(aliases = "sideways-right"))]
2461 Sideways,
2462}
2463
2464#[allow(missing_docs)]
2466#[derive(
2467 Clone,
2468 Copy,
2469 Debug,
2470 Deserialize,
2471 Eq,
2472 FromPrimitive,
2473 Hash,
2474 MallocSizeOf,
2475 Parse,
2476 PartialEq,
2477 Serialize,
2478 SpecifiedValueInfo,
2479 ToComputedValue,
2480 ToCss,
2481 ToResolvedValue,
2482 ToShmem,
2483 ToTyped,
2484)]
2485#[repr(u8)]
2486pub enum ImageOrientation {
2487 FromImage,
2488 None,
2489}
2490
2491#[allow(missing_docs)]
2493#[derive(
2494 Clone,
2495 Copy,
2496 Debug,
2497 Deserialize,
2498 Eq,
2499 FromPrimitive,
2500 Hash,
2501 MallocSizeOf,
2502 Parse,
2503 PartialEq,
2504 Serialize,
2505 SpecifiedValueInfo,
2506 ToComputedValue,
2507 ToCss,
2508 ToResolvedValue,
2509 ToShmem,
2510 ToTyped,
2511)]
2512#[repr(u8)]
2513pub enum BoxAlign {
2514 Stretch,
2515 Start,
2516 Center,
2517 Baseline,
2518 End,
2519}
2520
2521#[allow(missing_docs)]
2523#[derive(
2524 Clone,
2525 Copy,
2526 Debug,
2527 Deserialize,
2528 Eq,
2529 FromPrimitive,
2530 Hash,
2531 MallocSizeOf,
2532 Parse,
2533 PartialEq,
2534 Serialize,
2535 SpecifiedValueInfo,
2536 ToComputedValue,
2537 ToCss,
2538 ToResolvedValue,
2539 ToShmem,
2540 ToTyped,
2541)]
2542#[repr(u8)]
2543pub enum BoxDirection {
2544 Normal,
2545 Reverse,
2546}
2547
2548#[allow(missing_docs)]
2550#[derive(
2551 Clone,
2552 Copy,
2553 Debug,
2554 Deserialize,
2555 Eq,
2556 FromPrimitive,
2557 Hash,
2558 MallocSizeOf,
2559 Parse,
2560 PartialEq,
2561 Serialize,
2562 SpecifiedValueInfo,
2563 ToComputedValue,
2564 ToCss,
2565 ToResolvedValue,
2566 ToShmem,
2567 ToTyped,
2568)]
2569#[repr(u8)]
2570pub enum BoxOrient {
2571 #[cfg_attr(feature = "gecko", parse(aliases = "inline-axis"))]
2572 Horizontal,
2573 #[cfg_attr(feature = "gecko", parse(aliases = "block-axis"))]
2574 Vertical,
2575}
2576
2577#[allow(missing_docs)]
2579#[derive(
2580 Clone,
2581 Copy,
2582 Debug,
2583 Deserialize,
2584 Eq,
2585 FromPrimitive,
2586 Hash,
2587 MallocSizeOf,
2588 Parse,
2589 PartialEq,
2590 Serialize,
2591 SpecifiedValueInfo,
2592 ToComputedValue,
2593 ToCss,
2594 ToResolvedValue,
2595 ToShmem,
2596 ToTyped,
2597)]
2598#[repr(u8)]
2599pub enum BoxPack {
2600 Start,
2601 Center,
2602 End,
2603 Justify,
2604}
2605
2606#[allow(missing_docs)]
2608#[derive(
2609 Clone,
2610 Copy,
2611 Debug,
2612 Deserialize,
2613 Eq,
2614 FromPrimitive,
2615 Hash,
2616 MallocSizeOf,
2617 Parse,
2618 PartialEq,
2619 Serialize,
2620 SpecifiedValueInfo,
2621 ToComputedValue,
2622 ToCss,
2623 ToResolvedValue,
2624 ToShmem,
2625 ToTyped,
2626)]
2627#[repr(u8)]
2628pub enum DirectionProperty {
2629 Ltr,
2630 Rtl,
2631}