1use crate::parser::{Parse, ParserContext};
8use crate::properties::{LonghandId, PropertyDeclarationId, PropertyId};
9use crate::values::generics::box_::{
10 GenericContainIntrinsicSize, GenericLineClamp, GenericPerspective, GenericVerticalAlign,
11 VerticalAlignKeyword,
12};
13use crate::values::specified::length::{LengthPercentage, NonNegativeLength};
14use crate::values::specified::{AllowQuirks, Integer, NonNegativeNumberOrPercentage};
15use crate::values::CustomIdent;
16pub use crate::logical_geometry::WritingModeProperty;
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)]
117#[repr(C)]
118pub struct Display(u16);
119
120#[allow(missing_docs)]
122#[allow(non_upper_case_globals)]
123impl Display {
124 pub const LIST_ITEM_MASK: u16 = 0b1000000000000000;
126 pub const OUTSIDE_MASK: u16 = 0b0111111100000000;
127 pub const INSIDE_MASK: u16 = 0b0000000011111111;
128 pub const OUTSIDE_SHIFT: u16 = 8;
129
130 pub const None: Self =
133 Self(((DisplayOutside::None as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::None as u16);
134 pub const Contents: Self = Self(
135 ((DisplayOutside::None as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Contents as u16,
136 );
137 pub const Inline: Self =
138 Self(((DisplayOutside::Inline as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Flow as u16);
139 pub const InlineBlock: Self = Self(
140 ((DisplayOutside::Inline as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::FlowRoot as u16,
141 );
142 pub const Block: Self =
143 Self(((DisplayOutside::Block as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Flow as u16);
144 #[cfg(feature = "gecko")]
145 pub const FlowRoot: Self = Self(
146 ((DisplayOutside::Block as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::FlowRoot as u16,
147 );
148 pub const Flex: Self =
149 Self(((DisplayOutside::Block as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Flex as u16);
150 pub const InlineFlex: Self =
151 Self(((DisplayOutside::Inline as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Flex as u16);
152 pub const Grid: Self =
153 Self(((DisplayOutside::Block as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Grid as u16);
154 pub const InlineGrid: Self =
155 Self(((DisplayOutside::Inline as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Grid as u16);
156 pub const Table: Self =
157 Self(((DisplayOutside::Block as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Table as u16);
158 pub const InlineTable: Self = Self(
159 ((DisplayOutside::Inline as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Table as u16,
160 );
161 pub const TableCaption: Self = Self(
162 ((DisplayOutside::TableCaption as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Flow as u16,
163 );
164 #[cfg(feature = "gecko")]
165 pub const Ruby: Self =
166 Self(((DisplayOutside::Inline as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Ruby as u16);
167 #[cfg(feature = "gecko")]
168 pub const WebkitBox: Self = Self(
169 ((DisplayOutside::Block as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::WebkitBox as u16,
170 );
171 #[cfg(feature = "gecko")]
172 pub const WebkitInlineBox: Self = Self(
173 ((DisplayOutside::Inline as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::WebkitBox as u16,
174 );
175
176 pub const TableRowGroup: Self = Self(
179 ((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT) |
180 DisplayInside::TableRowGroup as u16,
181 );
182 pub const TableHeaderGroup: Self = Self(
183 ((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT) |
184 DisplayInside::TableHeaderGroup as u16,
185 );
186 pub const TableFooterGroup: Self = Self(
187 ((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT) |
188 DisplayInside::TableFooterGroup as u16,
189 );
190 pub const TableColumn: Self = Self(
191 ((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT) |
192 DisplayInside::TableColumn as u16,
193 );
194 pub const TableColumnGroup: Self = Self(
195 ((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT) |
196 DisplayInside::TableColumnGroup as u16,
197 );
198 pub const TableRow: Self = Self(
199 ((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT) |
200 DisplayInside::TableRow as u16,
201 );
202 pub const TableCell: Self = Self(
203 ((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT) |
204 DisplayInside::TableCell as u16,
205 );
206
207 #[cfg(feature = "gecko")]
209 pub const RubyBase: Self = Self(
210 ((DisplayOutside::InternalRuby as u16) << Self::OUTSIDE_SHIFT) |
211 DisplayInside::RubyBase as u16,
212 );
213 #[cfg(feature = "gecko")]
214 pub const RubyBaseContainer: Self = Self(
215 ((DisplayOutside::InternalRuby as u16) << Self::OUTSIDE_SHIFT) |
216 DisplayInside::RubyBaseContainer as u16,
217 );
218 #[cfg(feature = "gecko")]
219 pub const RubyText: Self = Self(
220 ((DisplayOutside::InternalRuby as u16) << Self::OUTSIDE_SHIFT) |
221 DisplayInside::RubyText as u16,
222 );
223 #[cfg(feature = "gecko")]
224 pub const RubyTextContainer: Self = Self(
225 ((DisplayOutside::InternalRuby as u16) << Self::OUTSIDE_SHIFT) |
226 DisplayInside::RubyTextContainer as u16,
227 );
228
229 #[inline]
231 const fn new(outside: DisplayOutside, inside: DisplayInside) -> Self {
232 Self((outside as u16) << Self::OUTSIDE_SHIFT | inside as u16)
233 }
234
235 #[inline]
237 fn from3(outside: DisplayOutside, inside: DisplayInside, list_item: bool) -> Self {
238 let v = Self::new(outside, inside);
239 if !list_item {
240 return v;
241 }
242 Self(v.0 | Self::LIST_ITEM_MASK)
243 }
244
245 #[inline]
247 pub fn inside(&self) -> DisplayInside {
248 DisplayInside::from_u16(self.0 & Self::INSIDE_MASK).unwrap()
249 }
250
251 #[inline]
253 pub fn outside(&self) -> DisplayOutside {
254 DisplayOutside::from_u16((self.0 & Self::OUTSIDE_MASK) >> Self::OUTSIDE_SHIFT).unwrap()
255 }
256
257 #[inline]
259 pub const fn to_u16(&self) -> u16 {
260 self.0
261 }
262
263 #[inline]
265 pub fn is_inline_flow(&self) -> bool {
266 self.outside() == DisplayOutside::Inline && self.inside() == DisplayInside::Flow
267 }
268
269 #[inline]
271 pub const fn is_list_item(&self) -> bool {
272 (self.0 & Self::LIST_ITEM_MASK) != 0
273 }
274
275 pub fn is_ruby_level_container(&self) -> bool {
277 match *self {
278 #[cfg(feature = "gecko")]
279 Display::RubyBaseContainer | Display::RubyTextContainer => true,
280 _ => false,
281 }
282 }
283
284 pub fn is_ruby_type(&self) -> bool {
286 match self.inside() {
287 #[cfg(feature = "gecko")]
288 DisplayInside::Ruby |
289 DisplayInside::RubyBase |
290 DisplayInside::RubyText |
291 DisplayInside::RubyBaseContainer |
292 DisplayInside::RubyTextContainer => true,
293 _ => false,
294 }
295 }
296}
297
298impl Display {
300 #[inline]
302 pub fn inline() -> Self {
303 Display::Inline
304 }
305
306 pub fn is_item_container(&self) -> bool {
311 match self.inside() {
312 DisplayInside::Flex => true,
313 DisplayInside::Grid => true,
314 _ => false,
315 }
316 }
317
318 pub fn is_line_participant(&self) -> bool {
322 if self.is_inline_flow() {
323 return true;
324 }
325 match *self {
326 #[cfg(feature = "gecko")]
327 Display::Contents | Display::Ruby | Display::RubyBaseContainer => true,
328 _ => false,
329 }
330 }
331
332 pub fn equivalent_block_display(&self, _is_root_element: bool) -> Self {
336 {
337 if _is_root_element && (self.is_contents() || self.is_list_item()) {
339 return Display::Block;
340 }
341 }
342
343 match self.outside() {
344 DisplayOutside::Inline => {
345 let inside = match self.inside() {
346 DisplayInside::FlowRoot => DisplayInside::Flow,
349 inside => inside,
350 };
351 Display::from3(DisplayOutside::Block, inside, self.is_list_item())
352 },
353 DisplayOutside::Block | DisplayOutside::None => *self,
354 _ => Display::Block,
355 }
356 }
357
358 #[cfg(feature = "gecko")]
361 pub fn inlinify(&self) -> Self {
362 match self.outside() {
363 DisplayOutside::Block => {
364 let inside = match self.inside() {
365 DisplayInside::Flow => DisplayInside::FlowRoot,
368 inside => inside,
369 };
370 Display::from3(DisplayOutside::Inline, inside, self.is_list_item())
371 },
372 _ => *self,
373 }
374 }
375
376 #[inline]
378 pub fn is_contents(&self) -> bool {
379 match *self {
380 Display::Contents => true,
381 _ => false,
382 }
383 }
384
385 #[inline]
387 pub fn is_none(&self) -> bool {
388 *self == Display::None
389 }
390}
391
392enum DisplayKeyword {
393 Full(Display),
394 Inside(DisplayInside),
395 Outside(DisplayOutside),
396 ListItem,
397}
398
399impl DisplayKeyword {
400 fn parse<'i>(input: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
401 use self::DisplayKeyword::*;
402 Ok(try_match_ident_ignore_ascii_case! { input,
403 "none" => Full(Display::None),
404 "contents" => Full(Display::Contents),
405 "inline-block" => Full(Display::InlineBlock),
406 "inline-table" => Full(Display::InlineTable),
407 "-webkit-flex" => Full(Display::Flex),
408 "inline-flex" | "-webkit-inline-flex" => Full(Display::InlineFlex),
409 "inline-grid" if grid_enabled() => Full(Display::InlineGrid),
410 "table-caption" => Full(Display::TableCaption),
411 "table-row-group" => Full(Display::TableRowGroup),
412 "table-header-group" => Full(Display::TableHeaderGroup),
413 "table-footer-group" => Full(Display::TableFooterGroup),
414 "table-column" => Full(Display::TableColumn),
415 "table-column-group" => Full(Display::TableColumnGroup),
416 "table-row" => Full(Display::TableRow),
417 "table-cell" => Full(Display::TableCell),
418 #[cfg(feature = "gecko")]
419 "ruby-base" => Full(Display::RubyBase),
420 #[cfg(feature = "gecko")]
421 "ruby-base-container" => Full(Display::RubyBaseContainer),
422 #[cfg(feature = "gecko")]
423 "ruby-text" => Full(Display::RubyText),
424 #[cfg(feature = "gecko")]
425 "ruby-text-container" => Full(Display::RubyTextContainer),
426 #[cfg(feature = "gecko")]
427 "-webkit-box" => Full(Display::WebkitBox),
428 #[cfg(feature = "gecko")]
429 "-webkit-inline-box" => Full(Display::WebkitInlineBox),
430
431 "block" => Outside(DisplayOutside::Block),
434 "inline" => Outside(DisplayOutside::Inline),
435
436 "list-item" => ListItem,
437
438 "flow" => Inside(DisplayInside::Flow),
441 "flex" => Inside(DisplayInside::Flex),
442 "flow-root" => Inside(DisplayInside::FlowRoot),
443 "table" => Inside(DisplayInside::Table),
444 "grid" if grid_enabled() => Inside(DisplayInside::Grid),
445 #[cfg(feature = "gecko")]
446 "ruby" => Inside(DisplayInside::Ruby),
447 })
448 }
449}
450
451impl ToCss for Display {
452 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
453 where
454 W: fmt::Write,
455 {
456 let outside = self.outside();
457 let inside = self.inside();
458 match *self {
459 Display::Block | Display::Inline => outside.to_css(dest),
460 Display::InlineBlock => dest.write_str("inline-block"),
461 #[cfg(feature = "gecko")]
462 Display::WebkitInlineBox => dest.write_str("-webkit-inline-box"),
463 Display::TableCaption => dest.write_str("table-caption"),
464 _ => match (outside, inside) {
465 (DisplayOutside::Inline, DisplayInside::Grid) => dest.write_str("inline-grid"),
466 (DisplayOutside::Inline, DisplayInside::Flex) => dest.write_str("inline-flex"),
467 (DisplayOutside::Inline, DisplayInside::Table) => dest.write_str("inline-table"),
468 #[cfg(feature = "gecko")]
469 (DisplayOutside::Block, DisplayInside::Ruby) => dest.write_str("block ruby"),
470 (_, inside) => {
471 if self.is_list_item() {
472 if outside != DisplayOutside::Block {
473 outside.to_css(dest)?;
474 dest.write_char(' ')?;
475 }
476 if inside != DisplayInside::Flow {
477 inside.to_css(dest)?;
478 dest.write_char(' ')?;
479 }
480 dest.write_str("list-item")
481 } else {
482 inside.to_css(dest)
483 }
484 },
485 },
486 }
487 }
488}
489
490impl Parse for Display {
491 fn parse<'i, 't>(
492 _: &ParserContext,
493 input: &mut Parser<'i, 't>,
494 ) -> Result<Display, ParseError<'i>> {
495 let mut got_list_item = false;
496 let mut inside = None;
497 let mut outside = None;
498 match DisplayKeyword::parse(input)? {
499 DisplayKeyword::Full(d) => return Ok(d),
500 DisplayKeyword::Outside(o) => {
501 outside = Some(o);
502 },
503 DisplayKeyword::Inside(i) => {
504 inside = Some(i);
505 },
506 DisplayKeyword::ListItem => {
507 got_list_item = true;
508 },
509 };
510
511 while let Ok(kw) = input.try_parse(DisplayKeyword::parse) {
512 match kw {
513 DisplayKeyword::ListItem if !got_list_item => {
514 got_list_item = true;
515 },
516 DisplayKeyword::Outside(o) if outside.is_none() => {
517 outside = Some(o);
518 },
519 DisplayKeyword::Inside(i) if inside.is_none() => {
520 inside = Some(i);
521 },
522 _ => return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)),
523 }
524 }
525
526 let inside = inside.unwrap_or(DisplayInside::Flow);
527 let outside = outside.unwrap_or_else(|| inside.default_display_outside());
528 if got_list_item && !inside.is_valid_for_list_item() {
529 return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
530 }
531
532 return Ok(Display::from3(outside, inside, got_list_item));
533 }
534}
535
536impl SpecifiedValueInfo for Display {
537 fn collect_completion_keywords(f: KeywordsCollectFn) {
538 f(&[
539 "block",
540 "contents",
541 "flex",
542 "flow-root",
543 "flow-root list-item",
544 "grid",
545 "inline",
546 "inline-block",
547 "inline-flex",
548 "inline-grid",
549 "inline-table",
550 "inline list-item",
551 "inline flow-root list-item",
552 "list-item",
553 "none",
554 "block ruby",
555 "ruby",
556 "ruby-base",
557 "ruby-base-container",
558 "ruby-text",
559 "ruby-text-container",
560 "table",
561 "table-caption",
562 "table-cell",
563 "table-column",
564 "table-column-group",
565 "table-footer-group",
566 "table-header-group",
567 "table-row",
568 "table-row-group",
569 "-webkit-box",
570 "-webkit-inline-box",
571 ]);
572 }
573}
574
575pub type ContainIntrinsicSize = GenericContainIntrinsicSize<NonNegativeLength>;
577
578pub type LineClamp = GenericLineClamp<Integer>;
580
581pub type VerticalAlign = GenericVerticalAlign<LengthPercentage>;
583
584impl Parse for VerticalAlign {
585 fn parse<'i, 't>(
586 context: &ParserContext,
587 input: &mut Parser<'i, 't>,
588 ) -> Result<Self, ParseError<'i>> {
589 if let Ok(lp) =
590 input.try_parse(|i| LengthPercentage::parse_quirky(context, i, AllowQuirks::Yes))
591 {
592 return Ok(GenericVerticalAlign::Length(lp));
593 }
594
595 Ok(GenericVerticalAlign::Keyword(VerticalAlignKeyword::parse(
596 input,
597 )?))
598 }
599}
600
601#[derive(
604 Clone,
605 Copy,
606 Debug,
607 Eq,
608 Hash,
609 MallocSizeOf,
610 Parse,
611 PartialEq,
612 SpecifiedValueInfo,
613 ToCss,
614 ToShmem,
615 ToComputedValue,
616 ToResolvedValue,
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)]
694#[repr(C)]
695pub struct ScrollSnapType {
696 axis: ScrollSnapAxis,
697 strictness: ScrollSnapStrictness,
698}
699
700impl ScrollSnapType {
701 #[inline]
703 pub fn none() -> Self {
704 Self {
705 axis: ScrollSnapAxis::Both,
706 strictness: ScrollSnapStrictness::None,
707 }
708 }
709}
710
711impl Parse for ScrollSnapType {
712 fn parse<'i, 't>(
714 _context: &ParserContext,
715 input: &mut Parser<'i, 't>,
716 ) -> Result<Self, ParseError<'i>> {
717 if input
718 .try_parse(|input| input.expect_ident_matching("none"))
719 .is_ok()
720 {
721 return Ok(ScrollSnapType::none());
722 }
723
724 let axis = ScrollSnapAxis::parse(input)?;
725 let strictness = input
726 .try_parse(ScrollSnapStrictness::parse)
727 .unwrap_or(ScrollSnapStrictness::Proximity);
728 Ok(Self { axis, strictness })
729 }
730}
731
732impl ToCss for ScrollSnapType {
733 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
734 where
735 W: Write,
736 {
737 if self.strictness == ScrollSnapStrictness::None {
738 return dest.write_str("none");
739 }
740 self.axis.to_css(dest)?;
741 if self.strictness != ScrollSnapStrictness::Proximity {
742 dest.write_char(' ')?;
743 self.strictness.to_css(dest)?;
744 }
745 Ok(())
746 }
747}
748
749#[allow(missing_docs)]
751#[derive(
752 Clone,
753 Copy,
754 Debug,
755 Eq,
756 FromPrimitive,
757 Hash,
758 MallocSizeOf,
759 Parse,
760 PartialEq,
761 SpecifiedValueInfo,
762 ToComputedValue,
763 ToCss,
764 ToResolvedValue,
765 ToShmem,
766)]
767#[repr(u8)]
768pub enum ScrollSnapAlignKeyword {
769 None,
770 Start,
771 End,
772 Center,
773}
774
775#[allow(missing_docs)]
777#[derive(
778 Clone,
779 Copy,
780 Debug,
781 Eq,
782 MallocSizeOf,
783 PartialEq,
784 SpecifiedValueInfo,
785 ToComputedValue,
786 ToResolvedValue,
787 ToShmem,
788)]
789#[repr(C)]
790pub struct ScrollSnapAlign {
791 block: ScrollSnapAlignKeyword,
792 inline: ScrollSnapAlignKeyword,
793}
794
795impl ScrollSnapAlign {
796 #[inline]
798 pub fn none() -> Self {
799 ScrollSnapAlign {
800 block: ScrollSnapAlignKeyword::None,
801 inline: ScrollSnapAlignKeyword::None,
802 }
803 }
804}
805
806impl Parse for ScrollSnapAlign {
807 fn parse<'i, 't>(
809 _context: &ParserContext,
810 input: &mut Parser<'i, 't>,
811 ) -> Result<ScrollSnapAlign, ParseError<'i>> {
812 let block = ScrollSnapAlignKeyword::parse(input)?;
813 let inline = input
814 .try_parse(ScrollSnapAlignKeyword::parse)
815 .unwrap_or(block);
816 Ok(ScrollSnapAlign { block, inline })
817 }
818}
819
820impl ToCss for ScrollSnapAlign {
821 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
822 where
823 W: Write,
824 {
825 self.block.to_css(dest)?;
826 if self.block != self.inline {
827 dest.write_char(' ')?;
828 self.inline.to_css(dest)?;
829 }
830 Ok(())
831 }
832}
833
834#[allow(missing_docs)]
835#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
836#[derive(
837 Clone,
838 Copy,
839 Debug,
840 Eq,
841 MallocSizeOf,
842 Parse,
843 PartialEq,
844 SpecifiedValueInfo,
845 ToComputedValue,
846 ToCss,
847 ToResolvedValue,
848 ToShmem,
849)]
850#[repr(u8)]
851pub enum ScrollSnapStop {
852 Normal,
853 Always,
854}
855
856#[allow(missing_docs)]
857#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
858#[derive(
859 Clone,
860 Copy,
861 Debug,
862 Eq,
863 MallocSizeOf,
864 Parse,
865 PartialEq,
866 SpecifiedValueInfo,
867 ToComputedValue,
868 ToCss,
869 ToResolvedValue,
870 ToShmem,
871)]
872#[repr(u8)]
873pub enum OverscrollBehavior {
874 Auto,
875 Contain,
876 None,
877}
878
879#[allow(missing_docs)]
880#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
881#[derive(
882 Clone,
883 Copy,
884 Debug,
885 Eq,
886 MallocSizeOf,
887 Parse,
888 PartialEq,
889 SpecifiedValueInfo,
890 ToComputedValue,
891 ToCss,
892 ToResolvedValue,
893 ToShmem,
894)]
895#[repr(u8)]
896pub enum OverflowAnchor {
897 Auto,
898 None,
899}
900
901#[allow(missing_docs)]
902#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
903#[derive(
904 Clone,
905 Copy,
906 Debug,
907 Eq,
908 MallocSizeOf,
909 Parse,
910 PartialEq,
911 SpecifiedValueInfo,
912 ToComputedValue,
913 ToCss,
914 ToResolvedValue,
915 ToShmem,
916)]
917#[repr(u8)]
918pub enum OverflowClipBox {
919 PaddingBox,
920 ContentBox,
921}
922
923#[derive(
924 Clone,
925 Debug,
926 Default,
927 MallocSizeOf,
928 PartialEq,
929 SpecifiedValueInfo,
930 ToComputedValue,
931 ToCss,
932 ToResolvedValue,
933 ToShmem,
934)]
935#[css(comma)]
936#[repr(C)]
937pub struct WillChange {
944 #[css(iterable, if_empty = "auto")]
949 features: crate::OwnedSlice<CustomIdent>,
950 #[css(skip)]
953 pub bits: WillChangeBits,
954}
955
956impl WillChange {
957 #[inline]
958 pub fn auto() -> Self {
960 Self::default()
961 }
962}
963
964#[derive(
966 Clone,
967 Copy,
968 Debug,
969 Default,
970 Eq,
971 MallocSizeOf,
972 PartialEq,
973 SpecifiedValueInfo,
974 ToComputedValue,
975 ToResolvedValue,
976 ToShmem,
977)]
978#[repr(C)]
979pub struct WillChangeBits(u16);
980bitflags! {
981 impl WillChangeBits: u16 {
982 const STACKING_CONTEXT_UNCONDITIONAL = 1 << 0;
985 const TRANSFORM = 1 << 1;
987 const SCROLL = 1 << 2;
989 const CONTAIN = 1 << 3;
991 const OPACITY = 1 << 4;
993 const PERSPECTIVE = 1 << 5;
995 const Z_INDEX = 1 << 6;
997 const FIXPOS_CB_NON_SVG = 1 << 7;
1000 const POSITION = 1 << 8;
1002 const VIEW_TRANSITION_NAME = 1 << 9;
1004 }
1005}
1006
1007fn change_bits_for_longhand(longhand: LonghandId) -> WillChangeBits {
1008 match longhand {
1009 LonghandId::Opacity => WillChangeBits::OPACITY,
1010 LonghandId::Contain => WillChangeBits::CONTAIN,
1011 LonghandId::Perspective => WillChangeBits::PERSPECTIVE,
1012 LonghandId::Position => {
1013 WillChangeBits::STACKING_CONTEXT_UNCONDITIONAL | WillChangeBits::POSITION
1014 },
1015 LonghandId::ZIndex => WillChangeBits::Z_INDEX,
1016 LonghandId::Transform |
1017 LonghandId::TransformStyle |
1018 LonghandId::Translate |
1019 LonghandId::Rotate |
1020 LonghandId::Scale |
1021 LonghandId::OffsetPath => WillChangeBits::TRANSFORM,
1022 LonghandId::BackdropFilter | LonghandId::Filter => {
1023 WillChangeBits::STACKING_CONTEXT_UNCONDITIONAL | WillChangeBits::FIXPOS_CB_NON_SVG
1024 },
1025 LonghandId::ViewTransitionName => WillChangeBits::VIEW_TRANSITION_NAME,
1026 LonghandId::MixBlendMode |
1027 LonghandId::Isolation |
1028 LonghandId::MaskImage |
1029 LonghandId::ClipPath => WillChangeBits::STACKING_CONTEXT_UNCONDITIONAL,
1030 _ => WillChangeBits::empty(),
1031 }
1032}
1033
1034fn change_bits_for_maybe_property(ident: &str, context: &ParserContext) -> WillChangeBits {
1035 let id = match PropertyId::parse_ignoring_rule_type(ident, context) {
1036 Ok(id) => id,
1037 Err(..) => return WillChangeBits::empty(),
1038 };
1039
1040 match id.as_shorthand() {
1041 Ok(shorthand) => shorthand
1042 .longhands()
1043 .fold(WillChangeBits::empty(), |flags, p| {
1044 flags | change_bits_for_longhand(p)
1045 }),
1046 Err(PropertyDeclarationId::Longhand(longhand)) => change_bits_for_longhand(longhand),
1047 Err(PropertyDeclarationId::Custom(..)) => WillChangeBits::empty(),
1048 }
1049}
1050
1051impl Parse for WillChange {
1052 fn parse<'i, 't>(
1054 context: &ParserContext,
1055 input: &mut Parser<'i, 't>,
1056 ) -> Result<Self, ParseError<'i>> {
1057 if input
1058 .try_parse(|input| input.expect_ident_matching("auto"))
1059 .is_ok()
1060 {
1061 return Ok(Self::default());
1062 }
1063
1064 let mut bits = WillChangeBits::empty();
1065 let custom_idents = input.parse_comma_separated(|i| {
1066 let location = i.current_source_location();
1067 let parser_ident = i.expect_ident()?;
1068 let ident = CustomIdent::from_ident(
1069 location,
1070 parser_ident,
1071 &["will-change", "none", "all", "auto"],
1072 )?;
1073
1074 if context.in_ua_sheet() && ident.0 == atom!("-moz-fixed-pos-containing-block") {
1075 bits |= WillChangeBits::FIXPOS_CB_NON_SVG;
1076 } else if ident.0 == atom!("scroll-position") {
1077 bits |= WillChangeBits::SCROLL;
1078 } else {
1079 bits |= change_bits_for_maybe_property(&parser_ident, context);
1080 }
1081 Ok(ident)
1082 })?;
1083
1084 Ok(Self {
1085 features: custom_idents.into(),
1086 bits,
1087 })
1088 }
1089}
1090
1091#[derive(
1093 Clone,
1094 Copy,
1095 Debug,
1096 Eq,
1097 MallocSizeOf,
1098 Parse,
1099 PartialEq,
1100 SpecifiedValueInfo,
1101 ToComputedValue,
1102 ToCss,
1103 ToResolvedValue,
1104 ToShmem,
1105)]
1106#[css(bitflags(single = "none,auto,manipulation", mixed = "pan-x,pan-y,pinch-zoom"))]
1107#[repr(C)]
1108pub struct TouchAction(u8);
1109bitflags! {
1110 impl TouchAction: u8 {
1111 const NONE = 1 << 0;
1113 const AUTO = 1 << 1;
1115 const PAN_X = 1 << 2;
1117 const PAN_Y = 1 << 3;
1119 const MANIPULATION = 1 << 4;
1121 const PINCH_ZOOM = 1 << 5;
1123 }
1124}
1125
1126impl TouchAction {
1127 #[inline]
1128 pub fn auto() -> TouchAction {
1130 TouchAction::AUTO
1131 }
1132}
1133
1134#[derive(
1135 Clone,
1136 Copy,
1137 Debug,
1138 Eq,
1139 MallocSizeOf,
1140 Parse,
1141 PartialEq,
1142 SpecifiedValueInfo,
1143 ToComputedValue,
1144 ToCss,
1145 ToResolvedValue,
1146 ToShmem,
1147)]
1148#[css(bitflags(
1149 single = "none,strict,content",
1150 mixed = "size,layout,style,paint,inline-size",
1151 overlapping_bits
1152))]
1153#[repr(C)]
1154pub struct Contain(u8);
1156bitflags! {
1157 impl Contain: u8 {
1158 const NONE = 0;
1160 const INLINE_SIZE = 1 << 0;
1162 const BLOCK_SIZE = 1 << 1;
1164 const LAYOUT = 1 << 2;
1166 const STYLE = 1 << 3;
1168 const PAINT = 1 << 4;
1170 const SIZE = 1 << 5 | Contain::INLINE_SIZE.bits() | Contain::BLOCK_SIZE.bits();
1172 const CONTENT = 1 << 6 | Contain::LAYOUT.bits() | Contain::STYLE.bits() | Contain::PAINT.bits();
1174 const STRICT = 1 << 7 | Contain::LAYOUT.bits() | Contain::STYLE.bits() | Contain::PAINT.bits() | Contain::SIZE.bits();
1176 }
1177}
1178
1179impl Parse for ContainIntrinsicSize {
1180 fn parse<'i, 't>(
1182 context: &ParserContext,
1183 input: &mut Parser<'i, 't>,
1184 ) -> Result<Self, ParseError<'i>> {
1185 if let Ok(l) = input.try_parse(|i| NonNegativeLength::parse(context, i)) {
1186 return Ok(Self::Length(l));
1187 }
1188
1189 if input.try_parse(|i| i.expect_ident_matching("auto")).is_ok() {
1190 if input.try_parse(|i| i.expect_ident_matching("none")).is_ok() {
1191 return Ok(Self::AutoNone);
1192 }
1193
1194 let l = NonNegativeLength::parse(context, input)?;
1195 return Ok(Self::AutoLength(l));
1196 }
1197
1198 input.expect_ident_matching("none")?;
1199 Ok(Self::None)
1200 }
1201}
1202
1203impl Parse for LineClamp {
1204 fn parse<'i, 't>(
1206 context: &ParserContext,
1207 input: &mut Parser<'i, 't>,
1208 ) -> Result<Self, ParseError<'i>> {
1209 if let Ok(i) =
1210 input.try_parse(|i| crate::values::specified::PositiveInteger::parse(context, i))
1211 {
1212 return Ok(Self(i.0));
1213 }
1214 input.expect_ident_matching("none")?;
1215 Ok(Self::none())
1216 }
1217}
1218
1219#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
1221#[derive(
1222 Clone,
1223 Copy,
1224 Debug,
1225 Eq,
1226 FromPrimitive,
1227 MallocSizeOf,
1228 Parse,
1229 PartialEq,
1230 SpecifiedValueInfo,
1231 ToAnimatedValue,
1232 ToComputedValue,
1233 ToCss,
1234 ToResolvedValue,
1235 ToShmem,
1236)]
1237#[repr(u8)]
1238pub enum ContentVisibility {
1239 Auto,
1243 Hidden,
1245 Visible,
1247}
1248
1249#[derive(
1250 Clone,
1251 Copy,
1252 Debug,
1253 PartialEq,
1254 Eq,
1255 MallocSizeOf,
1256 SpecifiedValueInfo,
1257 ToComputedValue,
1258 ToCss,
1259 Parse,
1260 ToResolvedValue,
1261 ToShmem,
1262)]
1263#[repr(u8)]
1264#[allow(missing_docs)]
1265pub enum ContainerType {
1267 Normal,
1269 InlineSize,
1271 Size,
1273}
1274
1275impl ContainerType {
1276 pub fn is_normal(self) -> bool {
1278 self == Self::Normal
1279 }
1280
1281 pub fn is_size_container_type(self) -> bool {
1283 !self.is_normal()
1284 }
1285}
1286
1287#[repr(transparent)]
1289#[derive(
1290 Clone,
1291 Debug,
1292 MallocSizeOf,
1293 PartialEq,
1294 SpecifiedValueInfo,
1295 ToComputedValue,
1296 ToCss,
1297 ToResolvedValue,
1298 ToShmem,
1299)]
1300pub struct ContainerName(#[css(iterable, if_empty = "none")] pub crate::OwnedSlice<CustomIdent>);
1301
1302impl ContainerName {
1303 pub fn none() -> Self {
1305 Self(Default::default())
1306 }
1307
1308 pub fn is_none(&self) -> bool {
1310 self.0.is_empty()
1311 }
1312
1313 fn parse_internal<'i>(
1314 input: &mut Parser<'i, '_>,
1315 for_query: bool,
1316 ) -> Result<Self, ParseError<'i>> {
1317 let mut idents = vec![];
1318 let location = input.current_source_location();
1319 let first = input.expect_ident()?;
1320 if !for_query && first.eq_ignore_ascii_case("none") {
1321 return Ok(Self::none());
1322 }
1323 const DISALLOWED_CONTAINER_NAMES: &'static [&'static str] = &["none", "not", "or", "and"];
1324 idents.push(CustomIdent::from_ident(
1325 location,
1326 first,
1327 DISALLOWED_CONTAINER_NAMES,
1328 )?);
1329 if !for_query {
1330 while let Ok(name) =
1331 input.try_parse(|input| CustomIdent::parse(input, DISALLOWED_CONTAINER_NAMES))
1332 {
1333 idents.push(name);
1334 }
1335 }
1336 Ok(ContainerName(idents.into()))
1337 }
1338
1339 pub fn parse_for_query<'i, 't>(
1343 _: &ParserContext,
1344 input: &mut Parser<'i, 't>,
1345 ) -> Result<Self, ParseError<'i>> {
1346 Self::parse_internal(input, true)
1347 }
1348}
1349
1350impl Parse for ContainerName {
1351 fn parse<'i, 't>(
1352 _: &ParserContext,
1353 input: &mut Parser<'i, 't>,
1354 ) -> Result<Self, ParseError<'i>> {
1355 Self::parse_internal(input, false)
1356 }
1357}
1358
1359pub type Perspective = GenericPerspective<NonNegativeLength>;
1361
1362#[allow(missing_docs)]
1364#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
1365#[derive(
1366 Clone,
1367 Copy,
1368 Debug,
1369 Eq,
1370 FromPrimitive,
1371 Hash,
1372 MallocSizeOf,
1373 Parse,
1374 PartialEq,
1375 SpecifiedValueInfo,
1376 ToComputedValue,
1377 ToCss,
1378 ToResolvedValue,
1379 ToShmem,
1380)]
1381#[repr(u8)]
1382pub enum Float {
1383 Left,
1384 Right,
1385 None,
1386 InlineStart,
1388 InlineEnd,
1389}
1390
1391impl Float {
1392 pub fn is_floating(self) -> bool {
1394 self != Self::None
1395 }
1396}
1397
1398#[allow(missing_docs)]
1400#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
1401#[derive(
1402 Clone,
1403 Copy,
1404 Debug,
1405 Eq,
1406 FromPrimitive,
1407 Hash,
1408 MallocSizeOf,
1409 Parse,
1410 PartialEq,
1411 SpecifiedValueInfo,
1412 ToComputedValue,
1413 ToCss,
1414 ToResolvedValue,
1415 ToShmem,
1416)]
1417#[repr(u8)]
1418pub enum Clear {
1419 None,
1420 Left,
1421 Right,
1422 Both,
1423 InlineStart,
1425 InlineEnd,
1426}
1427
1428#[allow(missing_docs)]
1430#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
1431#[derive(
1432 Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss, ToShmem,
1433)]
1434pub enum Resize {
1435 None,
1436 Both,
1437 Horizontal,
1438 Vertical,
1439 Inline,
1441 Block,
1442}
1443
1444#[allow(missing_docs)]
1448#[derive(
1449 Clone,
1450 Copy,
1451 Debug,
1452 Eq,
1453 Hash,
1454 MallocSizeOf,
1455 Parse,
1456 PartialEq,
1457 SpecifiedValueInfo,
1458 ToCss,
1459 ToComputedValue,
1460 ToResolvedValue,
1461 ToShmem,
1462)]
1463#[repr(u8)]
1464pub enum Appearance {
1465 None,
1467 Auto,
1472 Searchfield,
1474 Textarea,
1476 Checkbox,
1478 Radio,
1480 Menulist,
1482 Listbox,
1484 Meter,
1486 ProgressBar,
1488 Button,
1490 Textfield,
1492 MenulistButton,
1494 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1496 Menupopup,
1497 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1499 Meterchunk,
1500 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1502 MozMenulistArrowButton,
1503 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1505 NumberInput,
1506 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1508 PasswordInput,
1509 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1511 Progresschunk,
1512 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1514 Range,
1515 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1516 RangeThumb,
1517 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1519 ScrollbarHorizontal,
1520 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1521 ScrollbarVertical,
1522 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1526 ScrollbarbuttonUp,
1527 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1528 ScrollbarbuttonDown,
1529 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1530 ScrollbarbuttonLeft,
1531 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1532 ScrollbarbuttonRight,
1533 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1535 ScrollbarthumbHorizontal,
1536 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1537 ScrollbarthumbVertical,
1538 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1540 Scrollcorner,
1541 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1543 Separator,
1544 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1546 SpinnerUpbutton,
1547 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1549 SpinnerDownbutton,
1550 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1552 Statusbar,
1553 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1555 Toolbarbutton,
1556 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1558 Tooltip,
1559
1560 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1562 MozSidebar,
1563
1564 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1566 MozMacHelpButton,
1567
1568 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1572 MozMacWindow,
1573
1574 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1576 MozWindowButtonBox,
1577 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1578 MozWindowButtonClose,
1579 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1580 MozWindowButtonMaximize,
1581 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1582 MozWindowButtonMinimize,
1583 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1584 MozWindowButtonRestore,
1585 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1586 MozWindowTitlebar,
1587 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1588 MozWindowTitlebarMaximized,
1589 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1590 MozWindowDecorations,
1591
1592 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1593 MozMacDisclosureButtonClosed,
1594 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1595 MozMacDisclosureButtonOpen,
1596
1597 #[css(skip)]
1601 FocusOutline,
1602
1603 #[css(skip)]
1605 Count,
1606}
1607
1608#[allow(missing_docs)]
1612#[derive(
1613 Clone,
1614 Copy,
1615 Debug,
1616 Eq,
1617 Hash,
1618 MallocSizeOf,
1619 Parse,
1620 PartialEq,
1621 SpecifiedValueInfo,
1622 ToCss,
1623 ToComputedValue,
1624 ToResolvedValue,
1625 ToShmem,
1626)]
1627#[repr(u8)]
1628pub enum BreakBetween {
1629 Always,
1630 Auto,
1631 Page,
1632 Avoid,
1633 Left,
1634 Right,
1635}
1636
1637impl BreakBetween {
1638 #[cfg_attr(feature = "servo", allow(unused))]
1642 #[inline]
1643 pub(crate) fn parse_legacy<'i>(
1644 _: &ParserContext,
1645 input: &mut Parser<'i, '_>,
1646 ) -> Result<Self, ParseError<'i>> {
1647 let break_value = BreakBetween::parse(input)?;
1648 match break_value {
1649 BreakBetween::Always => Ok(BreakBetween::Page),
1650 BreakBetween::Auto | BreakBetween::Avoid | BreakBetween::Left | BreakBetween::Right => {
1651 Ok(break_value)
1652 },
1653 BreakBetween::Page => {
1654 Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
1655 },
1656 }
1657 }
1658
1659 #[cfg_attr(feature = "servo", allow(unused))]
1663 pub(crate) fn to_css_legacy<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
1664 where
1665 W: Write,
1666 {
1667 match *self {
1668 BreakBetween::Auto | BreakBetween::Avoid | BreakBetween::Left | BreakBetween::Right => {
1669 self.to_css(dest)
1670 },
1671 BreakBetween::Page => dest.write_str("always"),
1672 BreakBetween::Always => Ok(()),
1673 }
1674 }
1675}
1676
1677#[allow(missing_docs)]
1681#[derive(
1682 Clone,
1683 Copy,
1684 Debug,
1685 Eq,
1686 Hash,
1687 MallocSizeOf,
1688 Parse,
1689 PartialEq,
1690 SpecifiedValueInfo,
1691 ToCss,
1692 ToComputedValue,
1693 ToResolvedValue,
1694 ToShmem,
1695)]
1696#[repr(u8)]
1697pub enum BreakWithin {
1698 Auto,
1699 Avoid,
1700 AvoidPage,
1701 AvoidColumn,
1702}
1703
1704impl BreakWithin {
1705 #[cfg_attr(feature = "servo", allow(unused))]
1709 #[inline]
1710 pub(crate) fn parse_legacy<'i>(
1711 _: &ParserContext,
1712 input: &mut Parser<'i, '_>,
1713 ) -> Result<Self, ParseError<'i>> {
1714 let break_value = BreakWithin::parse(input)?;
1715 match break_value {
1716 BreakWithin::Auto | BreakWithin::Avoid => Ok(break_value),
1717 BreakWithin::AvoidPage | BreakWithin::AvoidColumn => {
1718 Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
1719 },
1720 }
1721 }
1722
1723 #[cfg_attr(feature = "servo", allow(unused))]
1727 pub(crate) fn to_css_legacy<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
1728 where
1729 W: Write,
1730 {
1731 match *self {
1732 BreakWithin::Auto | BreakWithin::Avoid => self.to_css(dest),
1733 BreakWithin::AvoidPage | BreakWithin::AvoidColumn => Ok(()),
1734 }
1735 }
1736}
1737
1738#[allow(missing_docs)]
1740#[derive(
1741 Clone,
1742 Copy,
1743 Debug,
1744 Eq,
1745 Hash,
1746 MallocSizeOf,
1747 PartialEq,
1748 SpecifiedValueInfo,
1749 ToCss,
1750 ToComputedValue,
1751 ToResolvedValue,
1752 ToShmem,
1753)]
1754#[repr(u8)]
1755pub enum Overflow {
1756 Visible,
1757 Hidden,
1758 Scroll,
1759 Auto,
1760 Clip,
1761}
1762
1763impl Parse for Overflow {
1766 fn parse<'i, 't>(
1767 _: &ParserContext,
1768 input: &mut Parser<'i, 't>,
1769 ) -> Result<Self, ParseError<'i>> {
1770 Ok(try_match_ident_ignore_ascii_case! { input,
1771 "visible" => Self::Visible,
1772 "hidden" => Self::Hidden,
1773 "scroll" => Self::Scroll,
1774 "auto" | "overlay" => Self::Auto,
1775 "clip" => Self::Clip,
1776 #[cfg(feature = "gecko")]
1777 "-moz-hidden-unscrollable" if static_prefs::pref!("layout.css.overflow-moz-hidden-unscrollable.enabled") => {
1778 Overflow::Clip
1779 },
1780 })
1781 }
1782}
1783
1784impl Overflow {
1785 #[inline]
1787 pub fn is_scrollable(&self) -> bool {
1788 matches!(*self, Self::Hidden | Self::Scroll | Self::Auto)
1789 }
1790 #[inline]
1793 pub fn to_scrollable(&self) -> Self {
1794 match *self {
1795 Self::Hidden | Self::Scroll | Self::Auto => *self,
1796 Self::Visible => Self::Auto,
1797 Self::Clip => Self::Hidden,
1798 }
1799 }
1800}
1801
1802#[derive(
1803 Clone,
1804 Copy,
1805 Debug,
1806 Eq,
1807 MallocSizeOf,
1808 Parse,
1809 PartialEq,
1810 SpecifiedValueInfo,
1811 ToComputedValue,
1812 ToCss,
1813 ToResolvedValue,
1814 ToShmem,
1815)]
1816#[repr(C)]
1817#[css(bitflags(
1818 single = "auto",
1819 mixed = "stable,both-edges",
1820 validate_mixed = "Self::has_stable"
1821))]
1822pub struct ScrollbarGutter(u8);
1825bitflags! {
1826 impl ScrollbarGutter: u8 {
1827 const AUTO = 0;
1829 const STABLE = 1 << 0;
1831 const BOTH_EDGES = 1 << 1;
1833 }
1834}
1835
1836impl ScrollbarGutter {
1837 #[inline]
1838 fn has_stable(&self) -> bool {
1839 self.intersects(Self::STABLE)
1840 }
1841}
1842
1843#[derive(
1845 Clone, Copy, Debug, MallocSizeOf, PartialEq, Parse, SpecifiedValueInfo, ToCss, ToShmem,
1846)]
1847#[allow(missing_docs)]
1848pub enum Zoom {
1849 Normal,
1850 #[parse(condition = "ParserContext::in_ua_sheet")]
1853 Document,
1854 Value(NonNegativeNumberOrPercentage),
1855}
1856
1857impl Zoom {
1858 #[inline]
1860 pub fn new_number(n: f32) -> Self {
1861 Self::Value(NonNegativeNumberOrPercentage::new_number(n))
1862 }
1863}
1864
1865pub use crate::values::generics::box_::PositionProperty;