1pub use crate::logical_geometry::WritingModeProperty;
8use crate::parser::{Parse, ParserContext};
9use crate::properties::{LonghandId, PropertyDeclarationId, PropertyId};
10use crate::values::generics::box_::{
11 GenericContainIntrinsicSize, GenericLineClamp, GenericPerspective, GenericVerticalAlign,
12 VerticalAlignKeyword,
13};
14use crate::values::specified::length::{LengthPercentage, NonNegativeLength};
15use crate::values::specified::{AllowQuirks, Integer, NonNegativeNumberOrPercentage};
16use crate::values::CustomIdent;
17use cssparser::Parser;
18use num_traits::FromPrimitive;
19use std::fmt::{self, Write};
20use style_traits::{CssWriter, KeywordsCollectFn, ParseError};
21use style_traits::{SpecifiedValueInfo, StyleParseErrorKind, ToCss};
22
23#[cfg(not(feature = "servo"))]
24fn grid_enabled() -> bool {
25 true
26}
27
28#[cfg(feature = "servo")]
29fn grid_enabled() -> bool {
30 style_config::get_bool("layout.grid.enabled")
31}
32
33#[allow(missing_docs)]
37#[derive(Clone, Copy, Debug, Eq, FromPrimitive, Hash, MallocSizeOf, PartialEq, ToCss, ToShmem)]
38#[repr(u8)]
39pub enum DisplayOutside {
40 None = 0,
41 Inline,
42 Block,
43 TableCaption,
44 InternalTable,
45 #[cfg(feature = "gecko")]
46 InternalRuby,
47}
48
49#[allow(missing_docs)]
50#[derive(Clone, Copy, Debug, Eq, FromPrimitive, Hash, MallocSizeOf, PartialEq, ToCss, ToShmem)]
51#[repr(u8)]
52pub enum DisplayInside {
53 None = 0,
54 Contents,
55 Flow,
56 FlowRoot,
57 Flex,
58 Grid,
59 Table,
60 TableRowGroup,
61 TableColumn,
62 TableColumnGroup,
63 TableHeaderGroup,
64 TableFooterGroup,
65 TableRow,
66 TableCell,
67 #[cfg(feature = "gecko")]
68 Ruby,
69 #[cfg(feature = "gecko")]
70 RubyBase,
71 #[cfg(feature = "gecko")]
72 RubyBaseContainer,
73 #[cfg(feature = "gecko")]
74 RubyText,
75 #[cfg(feature = "gecko")]
76 RubyTextContainer,
77 #[cfg(feature = "gecko")]
78 WebkitBox,
79}
80
81impl DisplayInside {
82 fn is_valid_for_list_item(self) -> bool {
83 match self {
84 DisplayInside::Flow => true,
85 #[cfg(feature = "gecko")]
86 DisplayInside::FlowRoot => true,
87 _ => false,
88 }
89 }
90
91 fn default_display_outside(self) -> DisplayOutside {
95 match self {
96 #[cfg(feature = "gecko")]
97 DisplayInside::Ruby => DisplayOutside::Inline,
98 _ => DisplayOutside::Block,
99 }
100 }
101}
102
103#[allow(missing_docs)]
104#[derive(
105 Clone,
106 Copy,
107 Debug,
108 Eq,
109 FromPrimitive,
110 Hash,
111 MallocSizeOf,
112 PartialEq,
113 ToComputedValue,
114 ToResolvedValue,
115 ToShmem,
116 ToTyped,
117)]
118#[repr(C)]
119pub struct Display(u16);
120
121#[allow(missing_docs)]
123#[allow(non_upper_case_globals)]
124impl Display {
125 pub const LIST_ITEM_MASK: u16 = 0b1000000000000000;
127 pub const OUTSIDE_MASK: u16 = 0b0111111100000000;
128 pub const INSIDE_MASK: u16 = 0b0000000011111111;
129 pub const OUTSIDE_SHIFT: u16 = 8;
130
131 pub const None: Self =
134 Self(((DisplayOutside::None as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::None as u16);
135 pub const Contents: Self = Self(
136 ((DisplayOutside::None as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Contents as u16,
137 );
138 pub const Inline: Self =
139 Self(((DisplayOutside::Inline as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Flow as u16);
140 pub const InlineBlock: Self = Self(
141 ((DisplayOutside::Inline as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::FlowRoot as u16,
142 );
143 pub const Block: Self =
144 Self(((DisplayOutside::Block as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Flow as u16);
145 #[cfg(feature = "gecko")]
146 pub const FlowRoot: Self = Self(
147 ((DisplayOutside::Block as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::FlowRoot as u16,
148 );
149 pub const Flex: Self =
150 Self(((DisplayOutside::Block as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Flex as u16);
151 pub const InlineFlex: Self =
152 Self(((DisplayOutside::Inline as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Flex as u16);
153 pub const Grid: Self =
154 Self(((DisplayOutside::Block as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Grid as u16);
155 pub const InlineGrid: Self =
156 Self(((DisplayOutside::Inline as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Grid as u16);
157 pub const Table: Self =
158 Self(((DisplayOutside::Block as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Table as u16);
159 pub const InlineTable: Self = Self(
160 ((DisplayOutside::Inline as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Table as u16,
161 );
162 pub const TableCaption: Self = Self(
163 ((DisplayOutside::TableCaption as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Flow as u16,
164 );
165 #[cfg(feature = "gecko")]
166 pub const Ruby: Self =
167 Self(((DisplayOutside::Inline as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Ruby as u16);
168 #[cfg(feature = "gecko")]
169 pub const WebkitBox: Self = Self(
170 ((DisplayOutside::Block as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::WebkitBox as u16,
171 );
172 #[cfg(feature = "gecko")]
173 pub const WebkitInlineBox: Self = Self(
174 ((DisplayOutside::Inline as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::WebkitBox as u16,
175 );
176
177 pub const TableRowGroup: Self = Self(
180 ((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT)
181 | DisplayInside::TableRowGroup as u16,
182 );
183 pub const TableHeaderGroup: Self = Self(
184 ((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT)
185 | DisplayInside::TableHeaderGroup as u16,
186 );
187 pub const TableFooterGroup: Self = Self(
188 ((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT)
189 | DisplayInside::TableFooterGroup as u16,
190 );
191 pub const TableColumn: Self = Self(
192 ((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT)
193 | DisplayInside::TableColumn as u16,
194 );
195 pub const TableColumnGroup: Self = Self(
196 ((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT)
197 | DisplayInside::TableColumnGroup as u16,
198 );
199 pub const TableRow: Self = Self(
200 ((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT)
201 | DisplayInside::TableRow as u16,
202 );
203 pub const TableCell: Self = Self(
204 ((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT)
205 | DisplayInside::TableCell as u16,
206 );
207
208 #[cfg(feature = "gecko")]
210 pub const RubyBase: Self = Self(
211 ((DisplayOutside::InternalRuby as u16) << Self::OUTSIDE_SHIFT)
212 | DisplayInside::RubyBase as u16,
213 );
214 #[cfg(feature = "gecko")]
215 pub const RubyBaseContainer: Self = Self(
216 ((DisplayOutside::InternalRuby as u16) << Self::OUTSIDE_SHIFT)
217 | DisplayInside::RubyBaseContainer as u16,
218 );
219 #[cfg(feature = "gecko")]
220 pub const RubyText: Self = Self(
221 ((DisplayOutside::InternalRuby as u16) << Self::OUTSIDE_SHIFT)
222 | DisplayInside::RubyText as u16,
223 );
224 #[cfg(feature = "gecko")]
225 pub const RubyTextContainer: Self = Self(
226 ((DisplayOutside::InternalRuby as u16) << Self::OUTSIDE_SHIFT)
227 | DisplayInside::RubyTextContainer as u16,
228 );
229
230 #[inline]
232 const fn new(outside: DisplayOutside, inside: DisplayInside) -> Self {
233 Self((outside as u16) << Self::OUTSIDE_SHIFT | inside as u16)
234 }
235
236 #[inline]
238 fn from3(outside: DisplayOutside, inside: DisplayInside, list_item: bool) -> Self {
239 let v = Self::new(outside, inside);
240 if !list_item {
241 return v;
242 }
243 Self(v.0 | Self::LIST_ITEM_MASK)
244 }
245
246 #[inline]
248 pub fn inside(&self) -> DisplayInside {
249 DisplayInside::from_u16(self.0 & Self::INSIDE_MASK).unwrap()
250 }
251
252 #[inline]
254 pub fn outside(&self) -> DisplayOutside {
255 DisplayOutside::from_u16((self.0 & Self::OUTSIDE_MASK) >> Self::OUTSIDE_SHIFT).unwrap()
256 }
257
258 #[inline]
260 pub const fn to_u16(&self) -> u16 {
261 self.0
262 }
263
264 #[inline]
266 pub fn is_inline_flow(&self) -> bool {
267 self.outside() == DisplayOutside::Inline && self.inside() == DisplayInside::Flow
268 }
269
270 #[inline]
272 pub const fn is_list_item(&self) -> bool {
273 (self.0 & Self::LIST_ITEM_MASK) != 0
274 }
275
276 pub fn is_ruby_level_container(&self) -> bool {
278 match *self {
279 #[cfg(feature = "gecko")]
280 Display::RubyBaseContainer | Display::RubyTextContainer => true,
281 _ => false,
282 }
283 }
284
285 pub fn is_ruby_type(&self) -> bool {
287 match self.inside() {
288 #[cfg(feature = "gecko")]
289 DisplayInside::Ruby
290 | DisplayInside::RubyBase
291 | DisplayInside::RubyText
292 | DisplayInside::RubyBaseContainer
293 | DisplayInside::RubyTextContainer => true,
294 _ => false,
295 }
296 }
297}
298
299impl Display {
301 #[inline]
303 pub fn inline() -> Self {
304 Display::Inline
305 }
306
307 pub fn is_item_container(&self) -> bool {
312 match self.inside() {
313 DisplayInside::Flex => true,
314 DisplayInside::Grid => true,
315 _ => false,
316 }
317 }
318
319 pub fn is_line_participant(&self) -> bool {
323 if self.is_inline_flow() {
324 return true;
325 }
326 match *self {
327 #[cfg(feature = "gecko")]
328 Display::Contents | Display::Ruby | Display::RubyBaseContainer => true,
329 _ => false,
330 }
331 }
332
333 pub fn equivalent_block_display(&self, is_root_element: bool) -> Self {
337 if is_root_element && (self.is_contents() || self.is_list_item()) {
339 return Display::Block;
340 }
341
342 match self.outside() {
343 DisplayOutside::Inline => {
344 let inside = match self.inside() {
345 DisplayInside::FlowRoot => DisplayInside::Flow,
348 inside => inside,
349 };
350 Display::from3(DisplayOutside::Block, inside, self.is_list_item())
351 },
352 DisplayOutside::Block | DisplayOutside::None => *self,
353 _ => Display::Block,
354 }
355 }
356
357 #[cfg(feature = "gecko")]
360 pub fn inlinify(&self) -> Self {
361 match self.outside() {
362 DisplayOutside::Block => {
363 let inside = match self.inside() {
364 DisplayInside::Flow => DisplayInside::FlowRoot,
367 inside => inside,
368 };
369 Display::from3(DisplayOutside::Inline, inside, self.is_list_item())
370 },
371 _ => *self,
372 }
373 }
374
375 #[inline]
377 pub fn is_contents(&self) -> bool {
378 match *self {
379 Display::Contents => true,
380 _ => false,
381 }
382 }
383
384 #[inline]
386 pub fn is_none(&self) -> bool {
387 *self == Display::None
388 }
389}
390
391enum DisplayKeyword {
392 Full(Display),
393 Inside(DisplayInside),
394 Outside(DisplayOutside),
395 ListItem,
396}
397
398impl DisplayKeyword {
399 fn parse<'i>(input: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
400 use self::DisplayKeyword::*;
401 Ok(try_match_ident_ignore_ascii_case! { input,
402 "none" => Full(Display::None),
403 "contents" => Full(Display::Contents),
404 "inline-block" => Full(Display::InlineBlock),
405 "inline-table" => Full(Display::InlineTable),
406 "-webkit-flex" => Full(Display::Flex),
407 "inline-flex" | "-webkit-inline-flex" => Full(Display::InlineFlex),
408 "inline-grid" if grid_enabled() => Full(Display::InlineGrid),
409 "table-caption" => Full(Display::TableCaption),
410 "table-row-group" => Full(Display::TableRowGroup),
411 "table-header-group" => Full(Display::TableHeaderGroup),
412 "table-footer-group" => Full(Display::TableFooterGroup),
413 "table-column" => Full(Display::TableColumn),
414 "table-column-group" => Full(Display::TableColumnGroup),
415 "table-row" => Full(Display::TableRow),
416 "table-cell" => Full(Display::TableCell),
417 #[cfg(feature = "gecko")]
418 "ruby-base" => Full(Display::RubyBase),
419 #[cfg(feature = "gecko")]
420 "ruby-base-container" => Full(Display::RubyBaseContainer),
421 #[cfg(feature = "gecko")]
422 "ruby-text" => Full(Display::RubyText),
423 #[cfg(feature = "gecko")]
424 "ruby-text-container" => Full(Display::RubyTextContainer),
425 #[cfg(feature = "gecko")]
426 "-webkit-box" => Full(Display::WebkitBox),
427 #[cfg(feature = "gecko")]
428 "-webkit-inline-box" => Full(Display::WebkitInlineBox),
429
430 "block" => Outside(DisplayOutside::Block),
433 "inline" => Outside(DisplayOutside::Inline),
434
435 "list-item" => ListItem,
436
437 "flow" => Inside(DisplayInside::Flow),
440 "flex" => Inside(DisplayInside::Flex),
441 "flow-root" => Inside(DisplayInside::FlowRoot),
442 "table" => Inside(DisplayInside::Table),
443 "grid" if grid_enabled() => Inside(DisplayInside::Grid),
444 #[cfg(feature = "gecko")]
445 "ruby" => Inside(DisplayInside::Ruby),
446 })
447 }
448}
449
450impl ToCss for Display {
451 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
452 where
453 W: fmt::Write,
454 {
455 let outside = self.outside();
456 let inside = self.inside();
457 match *self {
458 Display::Block | Display::Inline => outside.to_css(dest),
459 Display::InlineBlock => dest.write_str("inline-block"),
460 #[cfg(feature = "gecko")]
461 Display::WebkitInlineBox => dest.write_str("-webkit-inline-box"),
462 Display::TableCaption => dest.write_str("table-caption"),
463 _ => match (outside, inside) {
464 (DisplayOutside::Inline, DisplayInside::Grid) => dest.write_str("inline-grid"),
465 (DisplayOutside::Inline, DisplayInside::Flex) => dest.write_str("inline-flex"),
466 (DisplayOutside::Inline, DisplayInside::Table) => dest.write_str("inline-table"),
467 #[cfg(feature = "gecko")]
468 (DisplayOutside::Block, DisplayInside::Ruby) => dest.write_str("block ruby"),
469 (_, inside) => {
470 if self.is_list_item() {
471 if outside != DisplayOutside::Block {
472 outside.to_css(dest)?;
473 dest.write_char(' ')?;
474 }
475 if inside != DisplayInside::Flow {
476 inside.to_css(dest)?;
477 dest.write_char(' ')?;
478 }
479 dest.write_str("list-item")
480 } else {
481 inside.to_css(dest)
482 }
483 },
484 },
485 }
486 }
487}
488
489impl Parse for Display {
490 fn parse<'i, 't>(
491 _: &ParserContext,
492 input: &mut Parser<'i, 't>,
493 ) -> Result<Display, ParseError<'i>> {
494 let mut got_list_item = false;
495 let mut inside = None;
496 let mut outside = None;
497 match DisplayKeyword::parse(input)? {
498 DisplayKeyword::Full(d) => return Ok(d),
499 DisplayKeyword::Outside(o) => {
500 outside = Some(o);
501 },
502 DisplayKeyword::Inside(i) => {
503 inside = Some(i);
504 },
505 DisplayKeyword::ListItem => {
506 got_list_item = true;
507 },
508 };
509
510 while let Ok(kw) = input.try_parse(DisplayKeyword::parse) {
511 match kw {
512 DisplayKeyword::ListItem if !got_list_item => {
513 got_list_item = true;
514 },
515 DisplayKeyword::Outside(o) if outside.is_none() => {
516 outside = Some(o);
517 },
518 DisplayKeyword::Inside(i) if inside.is_none() => {
519 inside = Some(i);
520 },
521 _ => return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)),
522 }
523 }
524
525 let inside = inside.unwrap_or(DisplayInside::Flow);
526 let outside = outside.unwrap_or_else(|| inside.default_display_outside());
527 if got_list_item && !inside.is_valid_for_list_item() {
528 return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
529 }
530
531 return Ok(Display::from3(outside, inside, got_list_item));
532 }
533}
534
535impl SpecifiedValueInfo for Display {
536 fn collect_completion_keywords(f: KeywordsCollectFn) {
537 f(&[
538 "block",
539 "contents",
540 "flex",
541 "flow-root",
542 "flow-root list-item",
543 "grid",
544 "inline",
545 "inline-block",
546 "inline-flex",
547 "inline-grid",
548 "inline-table",
549 "inline list-item",
550 "inline flow-root list-item",
551 "list-item",
552 "none",
553 "block ruby",
554 "ruby",
555 "ruby-base",
556 "ruby-base-container",
557 "ruby-text",
558 "ruby-text-container",
559 "table",
560 "table-caption",
561 "table-cell",
562 "table-column",
563 "table-column-group",
564 "table-footer-group",
565 "table-header-group",
566 "table-row",
567 "table-row-group",
568 "-webkit-box",
569 "-webkit-inline-box",
570 ]);
571 }
572}
573
574pub type ContainIntrinsicSize = GenericContainIntrinsicSize<NonNegativeLength>;
576
577pub type LineClamp = GenericLineClamp<Integer>;
579
580pub type VerticalAlign = GenericVerticalAlign<LengthPercentage>;
582
583impl Parse for VerticalAlign {
584 fn parse<'i, 't>(
585 context: &ParserContext,
586 input: &mut Parser<'i, 't>,
587 ) -> Result<Self, ParseError<'i>> {
588 if let Ok(lp) =
589 input.try_parse(|i| LengthPercentage::parse_quirky(context, i, AllowQuirks::Yes))
590 {
591 return Ok(GenericVerticalAlign::Length(lp));
592 }
593
594 Ok(GenericVerticalAlign::Keyword(VerticalAlignKeyword::parse(
595 input,
596 )?))
597 }
598}
599
600#[derive(
603 Clone,
604 Copy,
605 Debug,
606 Eq,
607 Hash,
608 MallocSizeOf,
609 Parse,
610 PartialEq,
611 SpecifiedValueInfo,
612 ToCss,
613 ToShmem,
614 ToComputedValue,
615 ToResolvedValue,
616 ToTyped,
617)]
618#[repr(u8)]
619pub enum BaselineSource {
620 Auto,
622 First,
624 Last,
626}
627
628#[allow(missing_docs)]
630#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
631#[derive(
632 Clone,
633 Copy,
634 Debug,
635 Eq,
636 MallocSizeOf,
637 Parse,
638 PartialEq,
639 SpecifiedValueInfo,
640 ToComputedValue,
641 ToCss,
642 ToResolvedValue,
643 ToShmem,
644)]
645#[repr(u8)]
646pub enum ScrollSnapAxis {
647 X,
648 Y,
649 Block,
650 Inline,
651 Both,
652}
653
654#[allow(missing_docs)]
656#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
657#[derive(
658 Clone,
659 Copy,
660 Debug,
661 Eq,
662 MallocSizeOf,
663 Parse,
664 PartialEq,
665 SpecifiedValueInfo,
666 ToComputedValue,
667 ToCss,
668 ToResolvedValue,
669 ToShmem,
670)]
671#[repr(u8)]
672pub enum ScrollSnapStrictness {
673 #[css(skip)]
674 None, Mandatory,
676 Proximity,
677}
678
679#[allow(missing_docs)]
681#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
682#[derive(
683 Clone,
684 Copy,
685 Debug,
686 Eq,
687 MallocSizeOf,
688 PartialEq,
689 SpecifiedValueInfo,
690 ToComputedValue,
691 ToResolvedValue,
692 ToShmem,
693 ToTyped,
694)]
695#[repr(C)]
696pub struct ScrollSnapType {
697 axis: ScrollSnapAxis,
698 strictness: ScrollSnapStrictness,
699}
700
701impl ScrollSnapType {
702 #[inline]
704 pub fn none() -> Self {
705 Self {
706 axis: ScrollSnapAxis::Both,
707 strictness: ScrollSnapStrictness::None,
708 }
709 }
710}
711
712impl Parse for ScrollSnapType {
713 fn parse<'i, 't>(
715 _context: &ParserContext,
716 input: &mut Parser<'i, 't>,
717 ) -> Result<Self, ParseError<'i>> {
718 if input
719 .try_parse(|input| input.expect_ident_matching("none"))
720 .is_ok()
721 {
722 return Ok(ScrollSnapType::none());
723 }
724
725 let axis = ScrollSnapAxis::parse(input)?;
726 let strictness = input
727 .try_parse(ScrollSnapStrictness::parse)
728 .unwrap_or(ScrollSnapStrictness::Proximity);
729 Ok(Self { axis, strictness })
730 }
731}
732
733impl ToCss for ScrollSnapType {
734 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
735 where
736 W: Write,
737 {
738 if self.strictness == ScrollSnapStrictness::None {
739 return dest.write_str("none");
740 }
741 self.axis.to_css(dest)?;
742 if self.strictness != ScrollSnapStrictness::Proximity {
743 dest.write_char(' ')?;
744 self.strictness.to_css(dest)?;
745 }
746 Ok(())
747 }
748}
749
750#[allow(missing_docs)]
752#[derive(
753 Clone,
754 Copy,
755 Debug,
756 Eq,
757 FromPrimitive,
758 Hash,
759 MallocSizeOf,
760 Parse,
761 PartialEq,
762 SpecifiedValueInfo,
763 ToComputedValue,
764 ToCss,
765 ToResolvedValue,
766 ToShmem,
767)]
768#[repr(u8)]
769pub enum ScrollSnapAlignKeyword {
770 None,
771 Start,
772 End,
773 Center,
774}
775
776#[allow(missing_docs)]
778#[derive(
779 Clone,
780 Copy,
781 Debug,
782 Eq,
783 MallocSizeOf,
784 PartialEq,
785 SpecifiedValueInfo,
786 ToComputedValue,
787 ToResolvedValue,
788 ToShmem,
789 ToTyped,
790)]
791#[repr(C)]
792pub struct ScrollSnapAlign {
793 block: ScrollSnapAlignKeyword,
794 inline: ScrollSnapAlignKeyword,
795}
796
797impl ScrollSnapAlign {
798 #[inline]
800 pub fn none() -> Self {
801 ScrollSnapAlign {
802 block: ScrollSnapAlignKeyword::None,
803 inline: ScrollSnapAlignKeyword::None,
804 }
805 }
806}
807
808impl Parse for ScrollSnapAlign {
809 fn parse<'i, 't>(
811 _context: &ParserContext,
812 input: &mut Parser<'i, 't>,
813 ) -> Result<ScrollSnapAlign, ParseError<'i>> {
814 let block = ScrollSnapAlignKeyword::parse(input)?;
815 let inline = input
816 .try_parse(ScrollSnapAlignKeyword::parse)
817 .unwrap_or(block);
818 Ok(ScrollSnapAlign { block, inline })
819 }
820}
821
822impl ToCss for ScrollSnapAlign {
823 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
824 where
825 W: Write,
826 {
827 self.block.to_css(dest)?;
828 if self.block != self.inline {
829 dest.write_char(' ')?;
830 self.inline.to_css(dest)?;
831 }
832 Ok(())
833 }
834}
835
836#[allow(missing_docs)]
837#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
838#[derive(
839 Clone,
840 Copy,
841 Debug,
842 Eq,
843 MallocSizeOf,
844 Parse,
845 PartialEq,
846 SpecifiedValueInfo,
847 ToComputedValue,
848 ToCss,
849 ToResolvedValue,
850 ToShmem,
851 ToTyped,
852)]
853#[repr(u8)]
854pub enum ScrollSnapStop {
855 Normal,
856 Always,
857}
858
859#[allow(missing_docs)]
860#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
861#[derive(
862 Clone,
863 Copy,
864 Debug,
865 Eq,
866 MallocSizeOf,
867 Parse,
868 PartialEq,
869 SpecifiedValueInfo,
870 ToComputedValue,
871 ToCss,
872 ToResolvedValue,
873 ToShmem,
874 ToTyped,
875)]
876#[repr(u8)]
877pub enum OverscrollBehavior {
878 Auto,
879 Contain,
880 None,
881}
882
883#[allow(missing_docs)]
884#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
885#[derive(
886 Clone,
887 Copy,
888 Debug,
889 Eq,
890 MallocSizeOf,
891 Parse,
892 PartialEq,
893 SpecifiedValueInfo,
894 ToComputedValue,
895 ToCss,
896 ToResolvedValue,
897 ToShmem,
898 ToTyped,
899)]
900#[repr(u8)]
901pub enum OverflowAnchor {
902 Auto,
903 None,
904}
905
906#[allow(missing_docs)]
907#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
908#[derive(
909 Clone,
910 Copy,
911 Debug,
912 Eq,
913 MallocSizeOf,
914 Parse,
915 PartialEq,
916 SpecifiedValueInfo,
917 ToComputedValue,
918 ToCss,
919 ToResolvedValue,
920 ToShmem,
921 ToTyped,
922)]
923#[repr(u8)]
924pub enum OverflowClipBox {
925 PaddingBox,
926 ContentBox,
927}
928
929#[derive(
930 Clone,
931 Debug,
932 Default,
933 MallocSizeOf,
934 PartialEq,
935 SpecifiedValueInfo,
936 ToComputedValue,
937 ToCss,
938 ToResolvedValue,
939 ToShmem,
940 ToTyped,
941)]
942#[css(comma)]
943#[repr(C)]
944pub struct WillChange {
951 #[css(iterable, if_empty = "auto")]
956 features: crate::OwnedSlice<CustomIdent>,
957 #[css(skip)]
960 pub bits: WillChangeBits,
961}
962
963impl WillChange {
964 #[inline]
965 pub fn auto() -> Self {
967 Self::default()
968 }
969}
970
971#[derive(
973 Clone,
974 Copy,
975 Debug,
976 Default,
977 Eq,
978 MallocSizeOf,
979 PartialEq,
980 SpecifiedValueInfo,
981 ToComputedValue,
982 ToResolvedValue,
983 ToShmem,
984)]
985#[repr(C)]
986pub struct WillChangeBits(u16);
987bitflags! {
988 impl WillChangeBits: u16 {
989 const STACKING_CONTEXT_UNCONDITIONAL = 1 << 0;
992 const TRANSFORM = 1 << 1;
994 const SCROLL = 1 << 2;
996 const CONTAIN = 1 << 3;
998 const OPACITY = 1 << 4;
1000 const PERSPECTIVE = 1 << 5;
1002 const Z_INDEX = 1 << 6;
1004 const FIXPOS_CB_NON_SVG = 1 << 7;
1007 const POSITION = 1 << 8;
1009 const VIEW_TRANSITION_NAME = 1 << 9;
1011 const BACKDROP_ROOT = 1 << 10;
1014 }
1015}
1016
1017fn change_bits_for_longhand(longhand: LonghandId) -> WillChangeBits {
1018 match longhand {
1019 LonghandId::Opacity => WillChangeBits::OPACITY | WillChangeBits::BACKDROP_ROOT,
1020 LonghandId::Contain => WillChangeBits::CONTAIN,
1021 LonghandId::Perspective => WillChangeBits::PERSPECTIVE,
1022 LonghandId::Position => {
1023 WillChangeBits::STACKING_CONTEXT_UNCONDITIONAL | WillChangeBits::POSITION
1024 },
1025 LonghandId::ZIndex => WillChangeBits::Z_INDEX,
1026 LonghandId::Transform
1027 | LonghandId::TransformStyle
1028 | LonghandId::Translate
1029 | LonghandId::Rotate
1030 | LonghandId::Scale
1031 | LonghandId::OffsetPath => WillChangeBits::TRANSFORM,
1032 LonghandId::Filter | LonghandId::BackdropFilter => {
1033 WillChangeBits::STACKING_CONTEXT_UNCONDITIONAL
1034 | WillChangeBits::BACKDROP_ROOT
1035 | WillChangeBits::FIXPOS_CB_NON_SVG
1036 },
1037 LonghandId::ViewTransitionName => {
1038 WillChangeBits::VIEW_TRANSITION_NAME | WillChangeBits::BACKDROP_ROOT
1039 },
1040 LonghandId::MixBlendMode => {
1041 WillChangeBits::STACKING_CONTEXT_UNCONDITIONAL | WillChangeBits::BACKDROP_ROOT
1042 },
1043 LonghandId::Isolation | LonghandId::MaskImage => {
1044 WillChangeBits::STACKING_CONTEXT_UNCONDITIONAL
1045 },
1046 LonghandId::ClipPath => {
1047 WillChangeBits::STACKING_CONTEXT_UNCONDITIONAL | WillChangeBits::BACKDROP_ROOT
1048 },
1049 _ => WillChangeBits::empty(),
1050 }
1051}
1052
1053fn change_bits_for_maybe_property(ident: &str, context: &ParserContext) -> WillChangeBits {
1054 let id = match PropertyId::parse_ignoring_rule_type(ident, context) {
1055 Ok(id) => id,
1056 Err(..) => return WillChangeBits::empty(),
1057 };
1058
1059 match id.as_shorthand() {
1060 Ok(shorthand) => shorthand
1061 .longhands()
1062 .fold(WillChangeBits::empty(), |flags, p| {
1063 flags | change_bits_for_longhand(p)
1064 }),
1065 Err(PropertyDeclarationId::Longhand(longhand)) => change_bits_for_longhand(longhand),
1066 Err(PropertyDeclarationId::Custom(..)) => WillChangeBits::empty(),
1067 }
1068}
1069
1070impl Parse for WillChange {
1071 fn parse<'i, 't>(
1073 context: &ParserContext,
1074 input: &mut Parser<'i, 't>,
1075 ) -> Result<Self, ParseError<'i>> {
1076 if input
1077 .try_parse(|input| input.expect_ident_matching("auto"))
1078 .is_ok()
1079 {
1080 return Ok(Self::default());
1081 }
1082
1083 let mut bits = WillChangeBits::empty();
1084 let custom_idents = input.parse_comma_separated(|i| {
1085 let location = i.current_source_location();
1086 let parser_ident = i.expect_ident()?;
1087 let ident = CustomIdent::from_ident(
1088 location,
1089 parser_ident,
1090 &["will-change", "none", "all", "auto"],
1091 )?;
1092
1093 if context.in_ua_sheet() && ident.0 == atom!("-moz-fixed-pos-containing-block") {
1094 bits |= WillChangeBits::FIXPOS_CB_NON_SVG;
1095 } else if ident.0 == atom!("scroll-position") {
1096 bits |= WillChangeBits::SCROLL;
1097 } else {
1098 bits |= change_bits_for_maybe_property(&parser_ident, context);
1099 }
1100 Ok(ident)
1101 })?;
1102
1103 Ok(Self {
1104 features: custom_idents.into(),
1105 bits,
1106 })
1107 }
1108}
1109
1110#[derive(
1112 Clone,
1113 Copy,
1114 Debug,
1115 Eq,
1116 MallocSizeOf,
1117 Parse,
1118 PartialEq,
1119 SpecifiedValueInfo,
1120 ToComputedValue,
1121 ToCss,
1122 ToResolvedValue,
1123 ToShmem,
1124 ToTyped,
1125)]
1126#[css(bitflags(single = "none,auto,manipulation", mixed = "pan-x,pan-y,pinch-zoom"))]
1127#[repr(C)]
1128pub struct TouchAction(u8);
1129bitflags! {
1130 impl TouchAction: u8 {
1131 const NONE = 1 << 0;
1133 const AUTO = 1 << 1;
1135 const PAN_X = 1 << 2;
1137 const PAN_Y = 1 << 3;
1139 const MANIPULATION = 1 << 4;
1141 const PINCH_ZOOM = 1 << 5;
1143 }
1144}
1145
1146impl TouchAction {
1147 #[inline]
1148 pub fn auto() -> TouchAction {
1150 TouchAction::AUTO
1151 }
1152}
1153
1154#[derive(
1155 Clone,
1156 Copy,
1157 Debug,
1158 Eq,
1159 MallocSizeOf,
1160 Parse,
1161 PartialEq,
1162 SpecifiedValueInfo,
1163 ToComputedValue,
1164 ToCss,
1165 ToResolvedValue,
1166 ToShmem,
1167 ToTyped,
1168)]
1169#[css(bitflags(
1170 single = "none,strict,content",
1171 mixed = "size,layout,style,paint,inline-size",
1172 overlapping_bits
1173))]
1174#[repr(C)]
1175pub struct Contain(u8);
1177bitflags! {
1178 impl Contain: u8 {
1179 const NONE = 0;
1181 const INLINE_SIZE = 1 << 0;
1183 const BLOCK_SIZE = 1 << 1;
1185 const LAYOUT = 1 << 2;
1187 const STYLE = 1 << 3;
1189 const PAINT = 1 << 4;
1191 const SIZE = 1 << 5 | Contain::INLINE_SIZE.bits() | Contain::BLOCK_SIZE.bits();
1193 const CONTENT = 1 << 6 | Contain::LAYOUT.bits() | Contain::STYLE.bits() | Contain::PAINT.bits();
1195 const STRICT = 1 << 7 | Contain::LAYOUT.bits() | Contain::STYLE.bits() | Contain::PAINT.bits() | Contain::SIZE.bits();
1197 }
1198}
1199
1200impl Parse for ContainIntrinsicSize {
1201 fn parse<'i, 't>(
1203 context: &ParserContext,
1204 input: &mut Parser<'i, 't>,
1205 ) -> Result<Self, ParseError<'i>> {
1206 if let Ok(l) = input.try_parse(|i| NonNegativeLength::parse(context, i)) {
1207 return Ok(Self::Length(l));
1208 }
1209
1210 if input.try_parse(|i| i.expect_ident_matching("auto")).is_ok() {
1211 if input.try_parse(|i| i.expect_ident_matching("none")).is_ok() {
1212 return Ok(Self::AutoNone);
1213 }
1214
1215 let l = NonNegativeLength::parse(context, input)?;
1216 return Ok(Self::AutoLength(l));
1217 }
1218
1219 input.expect_ident_matching("none")?;
1220 Ok(Self::None)
1221 }
1222}
1223
1224impl Parse for LineClamp {
1225 fn parse<'i, 't>(
1227 context: &ParserContext,
1228 input: &mut Parser<'i, 't>,
1229 ) -> Result<Self, ParseError<'i>> {
1230 if let Ok(i) =
1231 input.try_parse(|i| crate::values::specified::PositiveInteger::parse(context, i))
1232 {
1233 return Ok(Self(i.0));
1234 }
1235 input.expect_ident_matching("none")?;
1236 Ok(Self::none())
1237 }
1238}
1239
1240#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
1242#[derive(
1243 Clone,
1244 Copy,
1245 Debug,
1246 Eq,
1247 FromPrimitive,
1248 MallocSizeOf,
1249 Parse,
1250 PartialEq,
1251 SpecifiedValueInfo,
1252 ToAnimatedValue,
1253 ToComputedValue,
1254 ToCss,
1255 ToResolvedValue,
1256 ToShmem,
1257 ToTyped,
1258)]
1259#[repr(u8)]
1260pub enum ContentVisibility {
1261 Auto,
1265 Hidden,
1267 Visible,
1269}
1270
1271#[derive(
1272 Clone,
1273 Copy,
1274 Debug,
1275 PartialEq,
1276 Eq,
1277 MallocSizeOf,
1278 SpecifiedValueInfo,
1279 ToComputedValue,
1280 ToCss,
1281 Parse,
1282 ToResolvedValue,
1283 ToShmem,
1284 ToTyped,
1285)]
1286#[css(bitflags(
1287 single = "normal",
1288 mixed = "size,inline-size,scroll-state",
1289 validate_mixed = "Self::validate_mixed_flags",
1290))]
1291#[repr(C)]
1292pub struct ContainerType(u8);
1299bitflags! {
1300 impl ContainerType: u8 {
1301 const NORMAL = 0;
1303 const INLINE_SIZE = 1 << 0;
1305 const SIZE = 1 << 1;
1307 const SCROLL_STATE = 1 << 2;
1309 }
1310}
1311
1312impl ContainerType {
1313 fn validate_mixed_flags(&self) -> bool {
1314 if self.contains(Self::SIZE | Self::INLINE_SIZE) {
1316 return false;
1317 }
1318 if self.contains(Self::SCROLL_STATE)
1319 && !static_prefs::pref!("layout.css.scroll-state.enabled")
1320 {
1321 return false;
1322 }
1323 true
1324 }
1325
1326 pub fn is_normal(self) -> bool {
1328 self == Self::NORMAL
1329 }
1330
1331 pub fn is_size_container_type(self) -> bool {
1333 self.intersects(Self::SIZE | Self::INLINE_SIZE)
1334 }
1335}
1336
1337#[repr(transparent)]
1339#[derive(
1340 Clone,
1341 Debug,
1342 MallocSizeOf,
1343 PartialEq,
1344 SpecifiedValueInfo,
1345 ToComputedValue,
1346 ToCss,
1347 ToResolvedValue,
1348 ToShmem,
1349 ToTyped,
1350)]
1351pub struct ContainerName(#[css(iterable, if_empty = "none")] pub crate::OwnedSlice<CustomIdent>);
1352
1353impl ContainerName {
1354 pub fn none() -> Self {
1356 Self(Default::default())
1357 }
1358
1359 pub fn is_none(&self) -> bool {
1361 self.0.is_empty()
1362 }
1363
1364 fn parse_internal<'i>(
1365 input: &mut Parser<'i, '_>,
1366 for_query: bool,
1367 ) -> Result<Self, ParseError<'i>> {
1368 let mut idents = vec![];
1369 let location = input.current_source_location();
1370 let first = input.expect_ident()?;
1371 if !for_query && first.eq_ignore_ascii_case("none") {
1372 return Ok(Self::none());
1373 }
1374 const DISALLOWED_CONTAINER_NAMES: &'static [&'static str] = &["none", "not", "or", "and"];
1375 idents.push(CustomIdent::from_ident(
1376 location,
1377 first,
1378 DISALLOWED_CONTAINER_NAMES,
1379 )?);
1380 if !for_query {
1381 while let Ok(name) =
1382 input.try_parse(|input| CustomIdent::parse(input, DISALLOWED_CONTAINER_NAMES))
1383 {
1384 idents.push(name);
1385 }
1386 }
1387 Ok(ContainerName(idents.into()))
1388 }
1389
1390 pub fn parse_for_query<'i, 't>(
1394 _: &ParserContext,
1395 input: &mut Parser<'i, 't>,
1396 ) -> Result<Self, ParseError<'i>> {
1397 Self::parse_internal(input, true)
1398 }
1399}
1400
1401impl Parse for ContainerName {
1402 fn parse<'i, 't>(
1403 _: &ParserContext,
1404 input: &mut Parser<'i, 't>,
1405 ) -> Result<Self, ParseError<'i>> {
1406 Self::parse_internal(input, false)
1407 }
1408}
1409
1410pub type Perspective = GenericPerspective<NonNegativeLength>;
1412
1413#[allow(missing_docs)]
1415#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
1416#[derive(
1417 Clone,
1418 Copy,
1419 Debug,
1420 Eq,
1421 FromPrimitive,
1422 Hash,
1423 MallocSizeOf,
1424 Parse,
1425 PartialEq,
1426 SpecifiedValueInfo,
1427 ToComputedValue,
1428 ToCss,
1429 ToResolvedValue,
1430 ToShmem,
1431 ToTyped,
1432)]
1433#[repr(u8)]
1434pub enum Float {
1435 Left,
1436 Right,
1437 None,
1438 InlineStart,
1440 InlineEnd,
1441}
1442
1443impl Float {
1444 pub fn is_floating(self) -> bool {
1446 self != Self::None
1447 }
1448}
1449
1450#[allow(missing_docs)]
1452#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
1453#[derive(
1454 Clone,
1455 Copy,
1456 Debug,
1457 Eq,
1458 FromPrimitive,
1459 Hash,
1460 MallocSizeOf,
1461 Parse,
1462 PartialEq,
1463 SpecifiedValueInfo,
1464 ToComputedValue,
1465 ToCss,
1466 ToResolvedValue,
1467 ToShmem,
1468 ToTyped,
1469)]
1470#[repr(u8)]
1471pub enum Clear {
1472 None,
1473 Left,
1474 Right,
1475 Both,
1476 InlineStart,
1478 InlineEnd,
1479}
1480
1481#[allow(missing_docs)]
1483#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
1484#[derive(
1485 Clone,
1486 Copy,
1487 Debug,
1488 Eq,
1489 Hash,
1490 MallocSizeOf,
1491 Parse,
1492 PartialEq,
1493 SpecifiedValueInfo,
1494 ToCss,
1495 ToShmem,
1496 ToTyped,
1497)]
1498pub enum Resize {
1499 None,
1500 Both,
1501 Horizontal,
1502 Vertical,
1503 Inline,
1505 Block,
1506}
1507
1508#[allow(missing_docs)]
1512#[derive(
1513 Clone,
1514 Copy,
1515 Debug,
1516 Eq,
1517 Hash,
1518 MallocSizeOf,
1519 Parse,
1520 PartialEq,
1521 SpecifiedValueInfo,
1522 ToCss,
1523 ToComputedValue,
1524 ToResolvedValue,
1525 ToShmem,
1526 ToTyped,
1527)]
1528#[repr(u8)]
1529pub enum Appearance {
1530 None,
1532 Auto,
1537 Searchfield,
1539 Textarea,
1541 Checkbox,
1543 Radio,
1545 Menulist,
1547 Listbox,
1549 Meter,
1551 ProgressBar,
1553 Button,
1555 Textfield,
1557 MenulistButton,
1559 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1561 Menupopup,
1562 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1564 MozMenulistArrowButton,
1565 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1567 NumberInput,
1568 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1570 PasswordInput,
1571 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1573 Range,
1574 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1576 ScrollbarHorizontal,
1577 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1578 ScrollbarVertical,
1579 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1583 ScrollbarbuttonUp,
1584 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1585 ScrollbarbuttonDown,
1586 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1587 ScrollbarbuttonLeft,
1588 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1589 ScrollbarbuttonRight,
1590 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1592 ScrollbarthumbHorizontal,
1593 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1594 ScrollbarthumbVertical,
1595 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1597 Scrollcorner,
1598 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1600 SpinnerUpbutton,
1601 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1603 SpinnerDownbutton,
1604 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1606 Toolbarbutton,
1607 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1609 Tooltip,
1610
1611 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1613 MozSidebar,
1614
1615 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1617 MozMacHelpButton,
1618
1619 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1623 MozMacWindow,
1624
1625 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1627 MozWindowButtonBox,
1628 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1629 MozWindowButtonClose,
1630 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1631 MozWindowButtonMaximize,
1632 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1633 MozWindowButtonMinimize,
1634 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1635 MozWindowButtonRestore,
1636 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1637 MozWindowTitlebar,
1638 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1639 MozWindowTitlebarMaximized,
1640 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1641 MozWindowDecorations,
1642
1643 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1644 MozMacDisclosureButtonClosed,
1645 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1646 MozMacDisclosureButtonOpen,
1647
1648 #[css(skip)]
1652 FocusOutline,
1653
1654 #[css(skip)]
1656 Count,
1657}
1658
1659#[allow(missing_docs)]
1663#[derive(
1664 Clone,
1665 Copy,
1666 Debug,
1667 Eq,
1668 Hash,
1669 MallocSizeOf,
1670 Parse,
1671 PartialEq,
1672 SpecifiedValueInfo,
1673 ToCss,
1674 ToComputedValue,
1675 ToResolvedValue,
1676 ToShmem,
1677 ToTyped,
1678)]
1679#[repr(u8)]
1680pub enum BreakBetween {
1681 Always,
1682 Auto,
1683 Page,
1684 Avoid,
1685 Left,
1686 Right,
1687}
1688
1689impl BreakBetween {
1690 #[cfg_attr(feature = "servo", allow(unused))]
1694 #[inline]
1695 pub(crate) fn parse_legacy<'i>(
1696 _: &ParserContext,
1697 input: &mut Parser<'i, '_>,
1698 ) -> Result<Self, ParseError<'i>> {
1699 let break_value = BreakBetween::parse(input)?;
1700 match break_value {
1701 BreakBetween::Always => Ok(BreakBetween::Page),
1702 BreakBetween::Auto | BreakBetween::Avoid | BreakBetween::Left | BreakBetween::Right => {
1703 Ok(break_value)
1704 },
1705 BreakBetween::Page => {
1706 Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
1707 },
1708 }
1709 }
1710
1711 #[cfg_attr(feature = "servo", allow(unused))]
1715 pub(crate) fn to_css_legacy<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
1716 where
1717 W: Write,
1718 {
1719 match *self {
1720 BreakBetween::Auto | BreakBetween::Avoid | BreakBetween::Left | BreakBetween::Right => {
1721 self.to_css(dest)
1722 },
1723 BreakBetween::Page => dest.write_str("always"),
1724 BreakBetween::Always => Ok(()),
1725 }
1726 }
1727}
1728
1729#[allow(missing_docs)]
1733#[derive(
1734 Clone,
1735 Copy,
1736 Debug,
1737 Eq,
1738 Hash,
1739 MallocSizeOf,
1740 Parse,
1741 PartialEq,
1742 SpecifiedValueInfo,
1743 ToCss,
1744 ToComputedValue,
1745 ToResolvedValue,
1746 ToShmem,
1747 ToTyped,
1748)]
1749#[repr(u8)]
1750pub enum BreakWithin {
1751 Auto,
1752 Avoid,
1753 AvoidPage,
1754 AvoidColumn,
1755}
1756
1757impl BreakWithin {
1758 #[cfg_attr(feature = "servo", allow(unused))]
1762 #[inline]
1763 pub(crate) fn parse_legacy<'i>(
1764 _: &ParserContext,
1765 input: &mut Parser<'i, '_>,
1766 ) -> Result<Self, ParseError<'i>> {
1767 let break_value = BreakWithin::parse(input)?;
1768 match break_value {
1769 BreakWithin::Auto | BreakWithin::Avoid => Ok(break_value),
1770 BreakWithin::AvoidPage | BreakWithin::AvoidColumn => {
1771 Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
1772 },
1773 }
1774 }
1775
1776 #[cfg_attr(feature = "servo", allow(unused))]
1780 pub(crate) fn to_css_legacy<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
1781 where
1782 W: Write,
1783 {
1784 match *self {
1785 BreakWithin::Auto | BreakWithin::Avoid => self.to_css(dest),
1786 BreakWithin::AvoidPage | BreakWithin::AvoidColumn => Ok(()),
1787 }
1788 }
1789}
1790
1791#[allow(missing_docs)]
1793#[derive(
1794 Clone,
1795 Copy,
1796 Debug,
1797 Eq,
1798 Hash,
1799 MallocSizeOf,
1800 PartialEq,
1801 SpecifiedValueInfo,
1802 ToCss,
1803 ToComputedValue,
1804 ToResolvedValue,
1805 ToShmem,
1806 ToTyped,
1807)]
1808#[repr(u8)]
1809pub enum Overflow {
1810 Visible,
1811 Hidden,
1812 Scroll,
1813 Auto,
1814 Clip,
1815}
1816
1817impl Parse for Overflow {
1820 fn parse<'i, 't>(
1821 _: &ParserContext,
1822 input: &mut Parser<'i, 't>,
1823 ) -> Result<Self, ParseError<'i>> {
1824 Ok(try_match_ident_ignore_ascii_case! { input,
1825 "visible" => Self::Visible,
1826 "hidden" => Self::Hidden,
1827 "scroll" => Self::Scroll,
1828 "auto" | "overlay" => Self::Auto,
1829 "clip" => Self::Clip,
1830 #[cfg(feature = "gecko")]
1831 "-moz-hidden-unscrollable" if static_prefs::pref!("layout.css.overflow-moz-hidden-unscrollable.enabled") => {
1832 Overflow::Clip
1833 },
1834 })
1835 }
1836}
1837
1838impl Overflow {
1839 #[inline]
1841 pub fn is_scrollable(&self) -> bool {
1842 matches!(*self, Self::Hidden | Self::Scroll | Self::Auto)
1843 }
1844 #[inline]
1847 pub fn to_scrollable(&self) -> Self {
1848 match *self {
1849 Self::Hidden | Self::Scroll | Self::Auto => *self,
1850 Self::Visible => Self::Auto,
1851 Self::Clip => Self::Hidden,
1852 }
1853 }
1854}
1855
1856#[derive(
1857 Clone,
1858 Copy,
1859 Debug,
1860 Eq,
1861 MallocSizeOf,
1862 Parse,
1863 PartialEq,
1864 SpecifiedValueInfo,
1865 ToComputedValue,
1866 ToCss,
1867 ToResolvedValue,
1868 ToShmem,
1869 ToTyped,
1870)]
1871#[repr(C)]
1872#[css(bitflags(
1873 single = "auto",
1874 mixed = "stable,both-edges",
1875 validate_mixed = "Self::has_stable"
1876))]
1877pub struct ScrollbarGutter(u8);
1880bitflags! {
1881 impl ScrollbarGutter: u8 {
1882 const AUTO = 0;
1884 const STABLE = 1 << 0;
1886 const BOTH_EDGES = 1 << 1;
1888 }
1889}
1890
1891impl ScrollbarGutter {
1892 #[inline]
1893 fn has_stable(&self) -> bool {
1894 self.intersects(Self::STABLE)
1895 }
1896}
1897
1898#[derive(
1900 Clone, Copy, Debug, MallocSizeOf, PartialEq, Parse, SpecifiedValueInfo, ToCss, ToShmem, ToTyped,
1901)]
1902#[allow(missing_docs)]
1903pub enum Zoom {
1904 Normal,
1905 #[parse(condition = "ParserContext::in_ua_sheet")]
1908 Document,
1909 Value(NonNegativeNumberOrPercentage),
1910}
1911
1912impl Zoom {
1913 #[inline]
1915 pub fn new_number(n: f32) -> Self {
1916 Self::Value(NonNegativeNumberOrPercentage::new_number(n))
1917 }
1918}
1919
1920pub use crate::values::generics::box_::PositionProperty;