1use crate::derives::*;
8pub use crate::logical_geometry::WritingModeProperty;
9use crate::parser::{Parse, ParserContext};
10use crate::properties::{LonghandId, PropertyDeclarationId, PropertyId};
11pub use crate::typed_om::{KeywordValue, ToTyped, TypedValue};
12use crate::values::generics::box_::{
13 BaselineShiftKeyword, BlockEllipsis, GenericBaselineShift, GenericContainIntrinsicSize,
14 GenericLineClamp, GenericOverflowClipMargin, GenericPerspective, GenericScrollbarInset,
15 MaxLines, OverflowClipMarginBox,
16};
17use crate::values::specified::length::{LengthPercentage, NonNegativeLength};
18use crate::values::specified::{AllowQuirks, NonNegativeNumberOrPercentage, PositiveInteger};
19use crate::values::CustomIdent;
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 grid_enabled() -> bool {
29 crate::pref!("layout.grid.enabled", gecko = true)
30}
31
32#[inline]
33fn appearance_base_enabled(_context: &ParserContext) -> bool {
34 crate::pref!("layout.css.appearance-base.enabled")
35}
36
37#[inline]
38fn appearance_base_select_enabled(_context: &ParserContext) -> bool {
39 crate::pref!("dom.select.customizable_select.enabled")
40}
41
42#[derive(
43 Clone,
44 Copy,
45 Debug,
46 Eq,
47 MallocSizeOf,
48 PartialEq,
49 Parse,
50 ToCss,
51 SpecifiedValueInfo,
52 ToComputedValue,
53 ToResolvedValue,
54 ToShmem,
55 ToTyped,
56)]
57#[css(bitflags(
58 single = "none",
59 mixed = "block,block-start,block-end",
60 overlapping_bits
61))]
62#[repr(C)]
63pub struct MarginTrim(u8);
69bitflags! {
70 impl MarginTrim: u8 {
71 const NONE = 0;
73 const BLOCK_START = 1 << 0;
75 const BLOCK_END = 1 << 1;
77 const BLOCK = MarginTrim::BLOCK_START.bits() | MarginTrim::BLOCK_END.bits();
79 }
80}
81
82pub type OverflowClipMargin = GenericOverflowClipMargin<NonNegativeLength>;
84
85impl Parse for OverflowClipMargin {
86 fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
88 use crate::Zero;
89 let mut offset = None;
90 let mut visual_box = None;
91 loop {
92 if offset.is_none() {
93 offset = input
94 .try_parse(|i| NonNegativeLength::parse(context, i))
95 .ok();
96 }
97 if visual_box.is_none() {
98 visual_box = input.try_parse(OverflowClipMarginBox::parse).ok();
99 if visual_box.is_some() {
100 continue;
101 }
102 }
103 break;
104 }
105 if offset.is_none() && visual_box.is_none() {
106 return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
107 }
108 Ok(Self {
109 offset: offset.unwrap_or_else(NonNegativeLength::zero),
110 visual_box: visual_box.unwrap_or(OverflowClipMarginBox::PaddingBox),
111 })
112 }
113}
114
115pub type ScrollbarInset = GenericScrollbarInset<NonNegativeLength>;
117
118impl Parse for ScrollbarInset {
119 fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
121 let start = NonNegativeLength::parse(context, input)?;
122 let end = input
123 .try_parse(|i| NonNegativeLength::parse(context, i))
124 .unwrap_or_else(|_| start.clone());
125 Ok(Self { start, end })
126 }
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 Table,
156 TableRowGroup,
157 TableColumn,
158 TableColumnGroup,
159 TableHeaderGroup,
160 TableFooterGroup,
161 TableRow,
162 TableCell,
163 #[cfg(feature = "gecko")]
164 Ruby,
165 #[cfg(feature = "gecko")]
166 RubyBase,
167 #[cfg(feature = "gecko")]
168 RubyBaseContainer,
169 #[cfg(feature = "gecko")]
170 RubyText,
171 #[cfg(feature = "gecko")]
172 RubyTextContainer,
173 #[cfg(feature = "gecko")]
174 WebkitBox,
175}
176
177impl DisplayInside {
178 fn is_valid_for_list_item(self) -> bool {
179 match self {
180 DisplayInside::Flow => true,
181 #[cfg(feature = "gecko")]
182 DisplayInside::FlowRoot => true,
183 _ => false,
184 }
185 }
186
187 fn default_display_outside(self) -> DisplayOutside {
191 match self {
192 #[cfg(feature = "gecko")]
193 DisplayInside::Ruby => DisplayOutside::Inline,
194 _ => DisplayOutside::Block,
195 }
196 }
197}
198
199#[allow(missing_docs)]
200#[derive(
201 Clone,
202 Copy,
203 Debug,
204 Eq,
205 FromPrimitive,
206 Hash,
207 MallocSizeOf,
208 PartialEq,
209 ToAnimatedValue,
210 ToComputedValue,
211 ToResolvedValue,
212 ToShmem,
213)]
214#[repr(C)]
215pub struct Display(u16);
216
217#[allow(missing_docs)]
219#[allow(non_upper_case_globals)]
220impl Display {
221 pub const LIST_ITEM_MASK: u16 = 0b1000000000000000;
223 pub const OUTSIDE_MASK: u16 = 0b0111111100000000;
224 pub const INSIDE_MASK: u16 = 0b0000000011111111;
225 pub const OUTSIDE_SHIFT: u16 = 8;
226
227 pub const None: Self =
230 Self(((DisplayOutside::None as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::None as u16);
231 pub const Contents: Self = Self(
232 ((DisplayOutside::None as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Contents as u16,
233 );
234 pub const Inline: Self =
235 Self(((DisplayOutside::Inline as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Flow as u16);
236 pub const InlineBlock: Self = Self(
237 ((DisplayOutside::Inline as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::FlowRoot as u16,
238 );
239 pub const Block: Self =
240 Self(((DisplayOutside::Block as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Flow as u16);
241 #[cfg(feature = "gecko")]
242 pub const FlowRoot: Self = Self(
243 ((DisplayOutside::Block as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::FlowRoot as u16,
244 );
245 pub const Flex: Self =
246 Self(((DisplayOutside::Block as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Flex as u16);
247 pub const InlineFlex: Self =
248 Self(((DisplayOutside::Inline as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Flex as u16);
249 pub const Grid: Self =
250 Self(((DisplayOutside::Block as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Grid as u16);
251 pub const InlineGrid: Self =
252 Self(((DisplayOutside::Inline as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Grid as u16);
253 pub const Table: Self =
254 Self(((DisplayOutside::Block as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Table as u16);
255 pub const InlineTable: Self = Self(
256 ((DisplayOutside::Inline as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Table as u16,
257 );
258 pub const TableCaption: Self = Self(
259 ((DisplayOutside::TableCaption as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Flow as u16,
260 );
261 #[cfg(feature = "gecko")]
262 pub const Ruby: Self =
263 Self(((DisplayOutside::Inline as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::Ruby as u16);
264 #[cfg(feature = "gecko")]
265 pub const WebkitBox: Self = Self(
266 ((DisplayOutside::Block as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::WebkitBox as u16,
267 );
268 #[cfg(feature = "gecko")]
269 pub const WebkitInlineBox: Self = Self(
270 ((DisplayOutside::Inline as u16) << Self::OUTSIDE_SHIFT) | DisplayInside::WebkitBox as u16,
271 );
272
273 pub const TableRowGroup: Self = Self(
276 ((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT)
277 | DisplayInside::TableRowGroup as u16,
278 );
279 pub const TableHeaderGroup: Self = Self(
280 ((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT)
281 | DisplayInside::TableHeaderGroup as u16,
282 );
283 pub const TableFooterGroup: Self = Self(
284 ((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT)
285 | DisplayInside::TableFooterGroup as u16,
286 );
287 pub const TableColumn: Self = Self(
288 ((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT)
289 | DisplayInside::TableColumn as u16,
290 );
291 pub const TableColumnGroup: Self = Self(
292 ((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT)
293 | DisplayInside::TableColumnGroup as u16,
294 );
295 pub const TableRow: Self = Self(
296 ((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT)
297 | DisplayInside::TableRow as u16,
298 );
299 pub const TableCell: Self = Self(
300 ((DisplayOutside::InternalTable as u16) << Self::OUTSIDE_SHIFT)
301 | DisplayInside::TableCell as u16,
302 );
303
304 #[cfg(feature = "gecko")]
306 pub const RubyBase: Self = Self(
307 ((DisplayOutside::InternalRuby as u16) << Self::OUTSIDE_SHIFT)
308 | DisplayInside::RubyBase as u16,
309 );
310 #[cfg(feature = "gecko")]
311 pub const RubyBaseContainer: Self = Self(
312 ((DisplayOutside::InternalRuby as u16) << Self::OUTSIDE_SHIFT)
313 | DisplayInside::RubyBaseContainer as u16,
314 );
315 #[cfg(feature = "gecko")]
316 pub const RubyText: Self = Self(
317 ((DisplayOutside::InternalRuby as u16) << Self::OUTSIDE_SHIFT)
318 | DisplayInside::RubyText as u16,
319 );
320 #[cfg(feature = "gecko")]
321 pub const RubyTextContainer: Self = Self(
322 ((DisplayOutside::InternalRuby as u16) << Self::OUTSIDE_SHIFT)
323 | DisplayInside::RubyTextContainer as u16,
324 );
325
326 #[inline]
328 const fn new(outside: DisplayOutside, inside: DisplayInside) -> Self {
329 Self((outside as u16) << Self::OUTSIDE_SHIFT | inside as u16)
330 }
331
332 #[inline]
334 fn from3(outside: DisplayOutside, inside: DisplayInside, list_item: bool) -> Self {
335 let v = Self::new(outside, inside);
336 if !list_item {
337 return v;
338 }
339 Self(v.0 | Self::LIST_ITEM_MASK)
340 }
341
342 #[inline]
344 pub fn inside(&self) -> DisplayInside {
345 DisplayInside::from_u16(self.0 & Self::INSIDE_MASK).unwrap()
346 }
347
348 #[inline]
350 pub fn outside(&self) -> DisplayOutside {
351 DisplayOutside::from_u16((self.0 & Self::OUTSIDE_MASK) >> Self::OUTSIDE_SHIFT).unwrap()
352 }
353
354 #[inline]
356 pub const fn to_u16(&self) -> u16 {
357 self.0
358 }
359
360 #[inline]
362 pub fn is_inline_flow(&self) -> bool {
363 self.outside() == DisplayOutside::Inline && self.inside() == DisplayInside::Flow
364 }
365
366 #[inline]
368 pub const fn is_list_item(&self) -> bool {
369 (self.0 & Self::LIST_ITEM_MASK) != 0
370 }
371
372 pub fn is_ruby_level_container(&self) -> bool {
374 match *self {
375 #[cfg(feature = "gecko")]
376 Display::RubyBaseContainer | Display::RubyTextContainer => true,
377 _ => false,
378 }
379 }
380
381 pub fn is_ruby_type(&self) -> bool {
383 match self.inside() {
384 #[cfg(feature = "gecko")]
385 DisplayInside::Ruby
386 | DisplayInside::RubyBase
387 | DisplayInside::RubyText
388 | DisplayInside::RubyBaseContainer
389 | DisplayInside::RubyTextContainer => true,
390 _ => false,
391 }
392 }
393}
394
395impl Display {
397 #[inline]
399 pub fn inline() -> Self {
400 Display::Inline
401 }
402
403 pub fn is_item_container(&self) -> bool {
408 match self.inside() {
409 DisplayInside::Flex => true,
410 DisplayInside::Grid => true,
411 _ => false,
412 }
413 }
414
415 pub fn is_line_participant(&self) -> bool {
419 if self.is_inline_flow() {
420 return true;
421 }
422 match *self {
423 #[cfg(feature = "gecko")]
424 Display::Contents | Display::Ruby | Display::RubyBaseContainer => true,
425 _ => false,
426 }
427 }
428
429 pub fn equivalent_block_display(&self, is_root_element: bool) -> Self {
433 if is_root_element && (self.is_contents() || self.is_list_item()) {
435 return Display::Block;
436 }
437
438 match self.outside() {
439 DisplayOutside::Inline => {
440 let inside = match self.inside() {
441 DisplayInside::FlowRoot => DisplayInside::Flow,
444 inside => inside,
445 };
446 Display::from3(DisplayOutside::Block, inside, self.is_list_item())
447 },
448 DisplayOutside::Block | DisplayOutside::None => *self,
449 _ => Display::Block,
450 }
451 }
452
453 #[cfg(feature = "gecko")]
456 pub fn inlinify(&self) -> Self {
457 match self.outside() {
458 DisplayOutside::Block => {
459 let inside = match self.inside() {
460 DisplayInside::Flow => DisplayInside::FlowRoot,
463 inside => inside,
464 };
465 Display::from3(DisplayOutside::Inline, inside, self.is_list_item())
466 },
467 _ => *self,
468 }
469 }
470
471 #[inline]
473 pub fn is_contents(&self) -> bool {
474 match *self {
475 Display::Contents => true,
476 _ => false,
477 }
478 }
479
480 #[inline]
482 pub fn is_none(&self) -> bool {
483 *self == Display::None
484 }
485}
486
487enum DisplayKeyword {
488 Full(Display),
489 Inside(DisplayInside),
490 Outside(DisplayOutside),
491 ListItem,
492}
493
494impl DisplayKeyword {
495 fn parse(input: &mut Parser) -> Result<Self, ParseError> {
496 use self::DisplayKeyword::*;
497 Ok(try_match_ident_ignore_ascii_case! { input,
498 "none" => Full(Display::None),
499 "contents" => Full(Display::Contents),
500 "inline-block" => Full(Display::InlineBlock),
501 "inline-table" => Full(Display::InlineTable),
502 "-webkit-flex" => Full(Display::Flex),
503 "inline-flex" | "-webkit-inline-flex" => Full(Display::InlineFlex),
504 "inline-grid" if grid_enabled() => Full(Display::InlineGrid),
505 "table-caption" => Full(Display::TableCaption),
506 "table-row-group" => Full(Display::TableRowGroup),
507 "table-header-group" => Full(Display::TableHeaderGroup),
508 "table-footer-group" => Full(Display::TableFooterGroup),
509 "table-column" => Full(Display::TableColumn),
510 "table-column-group" => Full(Display::TableColumnGroup),
511 "table-row" => Full(Display::TableRow),
512 "table-cell" => Full(Display::TableCell),
513 #[cfg(feature = "gecko")]
514 "ruby-base" => Full(Display::RubyBase),
515 #[cfg(feature = "gecko")]
516 "ruby-base-container" => Full(Display::RubyBaseContainer),
517 #[cfg(feature = "gecko")]
518 "ruby-text" => Full(Display::RubyText),
519 #[cfg(feature = "gecko")]
520 "ruby-text-container" => Full(Display::RubyTextContainer),
521 #[cfg(feature = "gecko")]
522 "-webkit-box" => Full(Display::WebkitBox),
523 #[cfg(feature = "gecko")]
524 "-webkit-inline-box" => Full(Display::WebkitInlineBox),
525
526 "block" => Outside(DisplayOutside::Block),
529 "inline" => Outside(DisplayOutside::Inline),
530
531 "list-item" => ListItem,
532
533 "flow" => Inside(DisplayInside::Flow),
536 "flex" => Inside(DisplayInside::Flex),
537 "flow-root" => Inside(DisplayInside::FlowRoot),
538 "table" => Inside(DisplayInside::Table),
539 "grid" if grid_enabled() => Inside(DisplayInside::Grid),
540 #[cfg(feature = "gecko")]
541 "ruby" => Inside(DisplayInside::Ruby),
542 })
543 }
544}
545
546impl ToCss for Display {
547 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
548 where
549 W: fmt::Write,
550 {
551 let outside = self.outside();
552 let inside = self.inside();
553 match *self {
554 Display::Block | Display::Inline => outside.to_css(dest),
555 Display::InlineBlock => dest.write_str("inline-block"),
556 #[cfg(feature = "gecko")]
557 Display::WebkitInlineBox => dest.write_str("-webkit-inline-box"),
558 Display::TableCaption => dest.write_str("table-caption"),
559 _ => match (outside, inside) {
560 (DisplayOutside::Inline, DisplayInside::Grid) => dest.write_str("inline-grid"),
561 (DisplayOutside::Inline, DisplayInside::Flex) => dest.write_str("inline-flex"),
562 (DisplayOutside::Inline, DisplayInside::Table) => dest.write_str("inline-table"),
563 #[cfg(feature = "gecko")]
564 (DisplayOutside::Block, DisplayInside::Ruby) => dest.write_str("block ruby"),
565 (_, inside) => {
566 if self.is_list_item() {
567 if outside != DisplayOutside::Block {
568 outside.to_css(dest)?;
569 dest.write_char(' ')?;
570 }
571 if inside != DisplayInside::Flow {
572 inside.to_css(dest)?;
573 dest.write_char(' ')?;
574 }
575 dest.write_str("list-item")
576 } else {
577 inside.to_css(dest)
578 }
579 },
580 },
581 }
582 }
583}
584
585impl ToTyped for Display {
586 fn to_typed(&self, dest: &mut ThinVec<TypedValue>) -> Result<(), ()> {
587 let outside = self.outside();
594 let inside = self.inside();
595
596 #[cfg(feature = "gecko")]
597 if outside == DisplayOutside::Block && inside == DisplayInside::Ruby {
598 return Err(());
599 }
600
601 if self.is_list_item()
602 && (outside != DisplayOutside::Block || inside != DisplayInside::Flow)
603 {
604 return Err(());
605 }
606
607 let keyword = self.to_css_cssstring();
608 debug_assert!(!AsRef::<[u8]>::as_ref(&keyword).contains(&b' '));
609
610 dest.push(TypedValue::Keyword(KeywordValue(keyword)));
611 Ok(())
612 }
613}
614
615impl Parse for Display {
616 fn parse(_: &ParserContext, input: &mut Parser) -> Result<Display, ParseError> {
617 let mut got_list_item = false;
618 let mut inside = None;
619 let mut outside = None;
620 match DisplayKeyword::parse(input)? {
621 DisplayKeyword::Full(d) => return Ok(d),
622 DisplayKeyword::Outside(o) => {
623 outside = Some(o);
624 },
625 DisplayKeyword::Inside(i) => {
626 inside = Some(i);
627 },
628 DisplayKeyword::ListItem => {
629 got_list_item = true;
630 },
631 };
632
633 while let Ok(kw) = input.try_parse(DisplayKeyword::parse) {
634 match kw {
635 DisplayKeyword::ListItem if !got_list_item => {
636 got_list_item = true;
637 },
638 DisplayKeyword::Outside(o) if outside.is_none() => {
639 outside = Some(o);
640 },
641 DisplayKeyword::Inside(i) if inside.is_none() => {
642 inside = Some(i);
643 },
644 _ => return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError)),
645 }
646 }
647
648 let inside = inside.unwrap_or(DisplayInside::Flow);
649 let outside = outside.unwrap_or_else(|| inside.default_display_outside());
650 if got_list_item && !inside.is_valid_for_list_item() {
651 return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
652 }
653
654 Ok(Display::from3(outside, inside, got_list_item))
655 }
656}
657
658impl SpecifiedValueInfo for Display {
659 fn collect_completion_keywords(f: KeywordsCollectFn) {
660 f(&[
661 "block",
662 "contents",
663 "flex",
664 "flow-root",
665 "flow-root list-item",
666 "grid",
667 "inline",
668 "inline-block",
669 "inline-flex",
670 "inline-grid",
671 "inline-table",
672 "inline list-item",
673 "inline flow-root list-item",
674 "list-item",
675 "none",
676 "block ruby",
677 "ruby",
678 "ruby-base",
679 "ruby-base-container",
680 "ruby-text",
681 "ruby-text-container",
682 "table",
683 "table-caption",
684 "table-cell",
685 "table-column",
686 "table-column-group",
687 "table-footer-group",
688 "table-header-group",
689 "table-row",
690 "table-row-group",
691 "-webkit-box",
692 "-webkit-inline-box",
693 ]);
694 }
695}
696
697pub type ContainIntrinsicSize = GenericContainIntrinsicSize<NonNegativeLength>;
699
700pub type LineClamp = GenericLineClamp<PositiveInteger>;
702
703pub type BaselineShift = GenericBaselineShift<LengthPercentage>;
705
706impl Parse for BaselineShift {
707 fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
708 if let Ok(lp) =
709 input.try_parse(|i| LengthPercentage::parse_quirky(context, i, AllowQuirks::Yes))
710 {
711 return Ok(BaselineShift::Length(lp));
712 }
713
714 Ok(BaselineShift::Keyword(BaselineShiftKeyword::parse(input)?))
715 }
716}
717
718#[derive(
721 Clone,
722 Copy,
723 Debug,
724 Eq,
725 FromPrimitive,
726 Hash,
727 MallocSizeOf,
728 Parse,
729 PartialEq,
730 SpecifiedValueInfo,
731 ToCss,
732 ToShmem,
733 ToComputedValue,
734 ToResolvedValue,
735 ToTyped,
736)]
737#[repr(u8)]
738pub enum DominantBaseline {
739 Auto,
743 #[parse(aliases = "text-after-edge")]
745 TextBottom,
746 Alphabetic,
748 Ideographic,
750 Middle,
754 Central,
756 Mathematical,
758 Hanging,
760 #[parse(aliases = "text-before-edge")]
762 TextTop,
763}
764
765#[derive(
768 Clone,
769 Copy,
770 Debug,
771 Eq,
772 FromPrimitive,
773 Hash,
774 MallocSizeOf,
775 Parse,
776 PartialEq,
777 SpecifiedValueInfo,
778 ToCss,
779 ToShmem,
780 ToComputedValue,
781 ToResolvedValue,
782 ToTyped,
783)]
784#[repr(u8)]
785pub enum AlignmentBaseline {
786 Baseline,
788 TextBottom,
790 #[cfg(feature = "gecko")]
792 Alphabetic,
793 #[cfg(feature = "gecko")]
795 Ideographic,
796 Middle,
800 #[cfg(feature = "gecko")]
802 Central,
803 #[cfg(feature = "gecko")]
805 Mathematical,
806 #[cfg(feature = "gecko")]
808 Hanging,
809 TextTop,
811 #[cfg(feature = "gecko")]
813 MozMiddleWithBaseline,
814}
815
816#[derive(
819 Clone,
820 Copy,
821 Debug,
822 Eq,
823 Hash,
824 MallocSizeOf,
825 Parse,
826 PartialEq,
827 SpecifiedValueInfo,
828 ToCss,
829 ToShmem,
830 ToComputedValue,
831 ToResolvedValue,
832 ToTyped,
833)]
834#[repr(u8)]
835pub enum BaselineSource {
836 Auto,
838 First,
840 Last,
842}
843
844impl BaselineSource {
845 pub fn parse_non_auto(input: &mut Parser) -> Result<Self, ParseError> {
847 Ok(try_match_ident_ignore_ascii_case! { input,
848 "first" => Self::First,
849 "last" => Self::Last,
850 })
851 }
852}
853
854#[allow(missing_docs)]
856#[derive(
857 Clone,
858 Copy,
859 Debug,
860 Deserialize,
861 Eq,
862 MallocSizeOf,
863 Parse,
864 PartialEq,
865 Serialize,
866 SpecifiedValueInfo,
867 ToComputedValue,
868 ToCss,
869 ToResolvedValue,
870 ToShmem,
871)]
872#[repr(u8)]
873pub enum ScrollSnapAxis {
874 X,
875 Y,
876 Block,
877 Inline,
878 Both,
879}
880
881#[allow(missing_docs)]
883#[derive(
884 Clone,
885 Copy,
886 Debug,
887 Deserialize,
888 Eq,
889 MallocSizeOf,
890 Parse,
891 PartialEq,
892 Serialize,
893 SpecifiedValueInfo,
894 ToComputedValue,
895 ToCss,
896 ToResolvedValue,
897 ToShmem,
898)]
899#[repr(u8)]
900pub enum ScrollSnapStrictness {
901 #[css(skip)]
902 None, Mandatory,
904 Proximity,
905}
906
907#[allow(missing_docs)]
909#[derive(
910 Clone,
911 Copy,
912 Debug,
913 Deserialize,
914 Eq,
915 MallocSizeOf,
916 PartialEq,
917 Serialize,
918 SpecifiedValueInfo,
919 ToComputedValue,
920 ToResolvedValue,
921 ToShmem,
922 ToTyped,
923)]
924#[repr(C)]
925#[typed(todo_derive_fields)]
926pub struct ScrollSnapType {
927 axis: ScrollSnapAxis,
928 strictness: ScrollSnapStrictness,
929}
930
931impl ScrollSnapType {
932 #[inline]
934 pub fn none() -> Self {
935 Self {
936 axis: ScrollSnapAxis::Both,
937 strictness: ScrollSnapStrictness::None,
938 }
939 }
940}
941
942impl Parse for ScrollSnapType {
943 fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
945 if input
946 .try_parse(|input| input.expect_ident_matching("none"))
947 .is_ok()
948 {
949 return Ok(ScrollSnapType::none());
950 }
951
952 let axis = ScrollSnapAxis::parse(input)?;
953 let strictness = input
954 .try_parse(ScrollSnapStrictness::parse)
955 .unwrap_or(ScrollSnapStrictness::Proximity);
956 Ok(Self { axis, strictness })
957 }
958}
959
960impl ToCss for ScrollSnapType {
961 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
962 where
963 W: Write,
964 {
965 if self.strictness == ScrollSnapStrictness::None {
966 return dest.write_str("none");
967 }
968 self.axis.to_css(dest)?;
969 if self.strictness != ScrollSnapStrictness::Proximity {
970 dest.write_char(' ')?;
971 self.strictness.to_css(dest)?;
972 }
973 Ok(())
974 }
975}
976
977#[allow(missing_docs)]
979#[derive(
980 Clone,
981 Copy,
982 Debug,
983 Eq,
984 FromPrimitive,
985 Hash,
986 MallocSizeOf,
987 Parse,
988 PartialEq,
989 SpecifiedValueInfo,
990 ToComputedValue,
991 ToCss,
992 ToResolvedValue,
993 ToShmem,
994)]
995#[repr(u8)]
996pub enum ScrollSnapAlignKeyword {
997 None,
998 Start,
999 End,
1000 Center,
1001}
1002
1003#[allow(missing_docs)]
1005#[derive(
1006 Clone,
1007 Copy,
1008 Debug,
1009 Eq,
1010 MallocSizeOf,
1011 PartialEq,
1012 SpecifiedValueInfo,
1013 ToComputedValue,
1014 ToResolvedValue,
1015 ToShmem,
1016 ToTyped,
1017)]
1018#[repr(C)]
1019#[typed(todo_derive_fields)]
1020pub struct ScrollSnapAlign {
1021 block: ScrollSnapAlignKeyword,
1022 inline: ScrollSnapAlignKeyword,
1023}
1024
1025impl ScrollSnapAlign {
1026 #[inline]
1028 pub fn none() -> Self {
1029 ScrollSnapAlign {
1030 block: ScrollSnapAlignKeyword::None,
1031 inline: ScrollSnapAlignKeyword::None,
1032 }
1033 }
1034}
1035
1036impl Parse for ScrollSnapAlign {
1037 fn parse(_context: &ParserContext, input: &mut Parser) -> Result<ScrollSnapAlign, ParseError> {
1039 let block = ScrollSnapAlignKeyword::parse(input)?;
1040 let inline = input
1041 .try_parse(ScrollSnapAlignKeyword::parse)
1042 .unwrap_or(block);
1043 Ok(ScrollSnapAlign { block, inline })
1044 }
1045}
1046
1047impl ToCss for ScrollSnapAlign {
1048 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
1049 where
1050 W: Write,
1051 {
1052 self.block.to_css(dest)?;
1053 if self.block != self.inline {
1054 dest.write_char(' ')?;
1055 self.inline.to_css(dest)?;
1056 }
1057 Ok(())
1058 }
1059}
1060
1061#[allow(missing_docs)]
1062#[derive(
1063 Clone,
1064 Copy,
1065 Debug,
1066 Deserialize,
1067 Eq,
1068 MallocSizeOf,
1069 Parse,
1070 PartialEq,
1071 Serialize,
1072 SpecifiedValueInfo,
1073 ToComputedValue,
1074 ToCss,
1075 ToResolvedValue,
1076 ToShmem,
1077 ToTyped,
1078)]
1079#[repr(u8)]
1080pub enum ScrollSnapStop {
1081 Normal,
1082 Always,
1083}
1084
1085#[allow(missing_docs)]
1086#[derive(
1087 Clone,
1088 Copy,
1089 Debug,
1090 Deserialize,
1091 Eq,
1092 MallocSizeOf,
1093 Parse,
1094 PartialEq,
1095 Serialize,
1096 SpecifiedValueInfo,
1097 ToComputedValue,
1098 ToCss,
1099 ToResolvedValue,
1100 ToShmem,
1101 ToTyped,
1102)]
1103#[repr(u8)]
1104pub enum OverscrollBehavior {
1105 Auto,
1106 Contain,
1107 None,
1108}
1109
1110#[allow(missing_docs)]
1111#[derive(
1112 Clone,
1113 Copy,
1114 Debug,
1115 Deserialize,
1116 Eq,
1117 MallocSizeOf,
1118 Parse,
1119 PartialEq,
1120 Serialize,
1121 SpecifiedValueInfo,
1122 ToComputedValue,
1123 ToCss,
1124 ToResolvedValue,
1125 ToShmem,
1126 ToTyped,
1127)]
1128#[repr(u8)]
1129pub enum OverflowAnchor {
1130 Auto,
1131 None,
1132}
1133
1134#[derive(
1135 Clone,
1136 Debug,
1137 Default,
1138 MallocSizeOf,
1139 PartialEq,
1140 SpecifiedValueInfo,
1141 ToComputedValue,
1142 ToCss,
1143 ToResolvedValue,
1144 ToShmem,
1145 ToTyped,
1146)]
1147#[css(comma)]
1148#[repr(C)]
1149#[typed(no_multiple_values)]
1150pub struct WillChange {
1157 #[css(iterable, if_empty = "auto")]
1162 features: crate::OwnedSlice<CustomIdent>,
1163 #[css(skip)]
1166 pub bits: WillChangeBits,
1167}
1168
1169impl WillChange {
1170 #[inline]
1171 pub fn auto() -> Self {
1173 Self::default()
1174 }
1175}
1176
1177#[derive(
1179 Clone,
1180 Copy,
1181 Debug,
1182 Default,
1183 Eq,
1184 MallocSizeOf,
1185 PartialEq,
1186 SpecifiedValueInfo,
1187 ToComputedValue,
1188 ToResolvedValue,
1189 ToShmem,
1190)]
1191#[repr(C)]
1192pub struct WillChangeBits(u16);
1193bitflags! {
1194 impl WillChangeBits: u16 {
1195 const STACKING_CONTEXT_UNCONDITIONAL = 1 << 0;
1198 const TRANSFORM = 1 << 1;
1200 const SCROLL = 1 << 2;
1202 const CONTAIN = 1 << 3;
1204 const OPACITY = 1 << 4;
1206 const PERSPECTIVE = 1 << 5;
1208 const Z_INDEX = 1 << 6;
1210 const FIXPOS_CB_NON_SVG = 1 << 7;
1213 const POSITION = 1 << 8;
1215 const VIEW_TRANSITION_NAME = 1 << 9;
1217 const BACKDROP_ROOT = 1 << 10;
1220 }
1221}
1222
1223fn change_bits_for_longhand(longhand: LonghandId) -> WillChangeBits {
1224 match longhand {
1225 LonghandId::Opacity => WillChangeBits::OPACITY | WillChangeBits::BACKDROP_ROOT,
1226 LonghandId::Contain => WillChangeBits::CONTAIN,
1227 LonghandId::Perspective => WillChangeBits::PERSPECTIVE,
1228 LonghandId::Position => {
1229 WillChangeBits::STACKING_CONTEXT_UNCONDITIONAL | WillChangeBits::POSITION
1230 },
1231 LonghandId::ZIndex => WillChangeBits::Z_INDEX,
1232 LonghandId::Transform
1233 | LonghandId::TransformStyle
1234 | LonghandId::Translate
1235 | LonghandId::Rotate
1236 | LonghandId::Scale
1237 | LonghandId::OffsetPath => WillChangeBits::TRANSFORM,
1238 LonghandId::Filter | LonghandId::BackdropFilter => {
1239 WillChangeBits::STACKING_CONTEXT_UNCONDITIONAL
1240 | WillChangeBits::BACKDROP_ROOT
1241 | WillChangeBits::FIXPOS_CB_NON_SVG
1242 },
1243 LonghandId::ViewTransitionName => {
1244 WillChangeBits::VIEW_TRANSITION_NAME | WillChangeBits::BACKDROP_ROOT
1245 },
1246 LonghandId::MixBlendMode => {
1247 WillChangeBits::STACKING_CONTEXT_UNCONDITIONAL | WillChangeBits::BACKDROP_ROOT
1248 },
1249 LonghandId::Isolation | LonghandId::MaskImage => {
1250 WillChangeBits::STACKING_CONTEXT_UNCONDITIONAL
1251 },
1252 LonghandId::ClipPath => {
1253 WillChangeBits::STACKING_CONTEXT_UNCONDITIONAL | WillChangeBits::BACKDROP_ROOT
1254 },
1255 _ => WillChangeBits::empty(),
1256 }
1257}
1258
1259fn change_bits_for_maybe_property(ident: &str, context: &ParserContext) -> WillChangeBits {
1260 let id = match PropertyId::parse_ignoring_rule_type(ident, context) {
1261 Ok(id) => id,
1262 Err(..) => return WillChangeBits::empty(),
1263 };
1264
1265 match id.as_shorthand() {
1266 Ok(shorthand) => shorthand
1267 .longhands()
1268 .fold(WillChangeBits::empty(), |flags, p| {
1269 flags | change_bits_for_longhand(p)
1270 }),
1271 Err(PropertyDeclarationId::Longhand(longhand)) => change_bits_for_longhand(longhand),
1272 Err(PropertyDeclarationId::Custom(..)) => WillChangeBits::empty(),
1273 }
1274}
1275
1276impl Parse for WillChange {
1277 fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
1279 if input
1280 .try_parse(|input| input.expect_ident_matching("auto"))
1281 .is_ok()
1282 {
1283 return Ok(Self::default());
1284 }
1285
1286 let mut bits = WillChangeBits::empty();
1287 let custom_idents = input.parse_comma_separated(|i| {
1288 let parser_ident = i.expect_ident()?;
1289 let ident =
1290 CustomIdent::from_ident(parser_ident, &["will-change", "none", "all", "auto"])?;
1291
1292 if context.in_ua_sheet() && ident.0 == atom!("-moz-fixed-pos-containing-block") {
1293 bits |= WillChangeBits::FIXPOS_CB_NON_SVG;
1294 } else if ident.0 == atom!("scroll-position") {
1295 bits |= WillChangeBits::SCROLL;
1296 } else {
1297 bits |= change_bits_for_maybe_property(parser_ident, context);
1298 }
1299 Ok(ident)
1300 })?;
1301
1302 Ok(Self {
1303 features: custom_idents.into(),
1304 bits,
1305 })
1306 }
1307}
1308
1309#[derive(
1311 Clone,
1312 Copy,
1313 Debug,
1314 Eq,
1315 MallocSizeOf,
1316 Parse,
1317 PartialEq,
1318 SpecifiedValueInfo,
1319 ToComputedValue,
1320 ToCss,
1321 ToResolvedValue,
1322 ToShmem,
1323 ToTyped,
1324)]
1325#[css(bitflags(single = "none,auto,manipulation", mixed = "pan-x,pan-y,pinch-zoom"))]
1326#[repr(C)]
1327pub struct TouchAction(u8);
1328bitflags! {
1329 impl TouchAction: u8 {
1330 const NONE = 1 << 0;
1332 const AUTO = 1 << 1;
1334 const PAN_X = 1 << 2;
1336 const PAN_Y = 1 << 3;
1338 const MANIPULATION = 1 << 4;
1340 const PINCH_ZOOM = 1 << 5;
1342 }
1343}
1344
1345impl TouchAction {
1346 #[inline]
1347 pub fn auto() -> TouchAction {
1349 TouchAction::AUTO
1350 }
1351}
1352
1353#[derive(
1354 Clone,
1355 Copy,
1356 Debug,
1357 Eq,
1358 MallocSizeOf,
1359 Parse,
1360 PartialEq,
1361 SpecifiedValueInfo,
1362 ToComputedValue,
1363 ToCss,
1364 ToResolvedValue,
1365 ToShmem,
1366 ToTyped,
1367)]
1368#[css(bitflags(
1369 single = "none,strict,content",
1370 mixed = "size,layout,style,paint,inline-size",
1371 overlapping_bits
1372))]
1373#[repr(C)]
1374pub struct Contain(u8);
1376bitflags! {
1377 impl Contain: u8 {
1378 const NONE = 0;
1380 const INLINE_SIZE = 1 << 0;
1382 const BLOCK_SIZE = 1 << 1;
1384 const LAYOUT = 1 << 2;
1386 const STYLE = 1 << 3;
1388 const PAINT = 1 << 4;
1390 const SIZE = 1 << 5 | Contain::INLINE_SIZE.bits() | Contain::BLOCK_SIZE.bits();
1392 const CONTENT = 1 << 6 | Contain::LAYOUT.bits() | Contain::STYLE.bits() | Contain::PAINT.bits();
1394 const STRICT = 1 << 7 | Contain::LAYOUT.bits() | Contain::STYLE.bits() | Contain::PAINT.bits() | Contain::SIZE.bits();
1396 }
1397}
1398
1399impl Parse for ContainIntrinsicSize {
1400 fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
1402 if let Ok(l) = input.try_parse(|i| NonNegativeLength::parse(context, i)) {
1403 return Ok(Self::Length(l));
1404 }
1405
1406 if input.try_parse(|i| i.expect_ident_matching("auto")).is_ok() {
1407 if input.try_parse(|i| i.expect_ident_matching("none")).is_ok() {
1408 return Ok(Self::AutoNone);
1409 }
1410
1411 let l = NonNegativeLength::parse(context, input)?;
1412 return Ok(Self::AutoLength(l));
1413 }
1414
1415 input.expect_ident_matching("none")?;
1416 Ok(Self::None)
1417 }
1418}
1419
1420impl Parse for MaxLines<PositiveInteger> {
1421 fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
1422 let mut lines = None;
1423 let mut auto = false;
1424
1425 loop {
1426 if lines.is_none() {
1427 if let Ok(value) = input.try_parse(|i| PositiveInteger::parse(context, i)) {
1428 lines = Some(value);
1429 continue;
1430 }
1431 }
1432
1433 if !auto && input.try_parse(|i| i.expect_ident_matching("auto")).is_ok() {
1434 auto = true;
1435 continue;
1436 }
1437
1438 break;
1439 }
1440
1441 match (lines, auto) {
1442 (Some(value), true) => Ok(MaxLines::lines(value, true)),
1443 (Some(value), false) => Ok(MaxLines::lines(value, false)),
1444 (None, true) => Ok(MaxLines::auto()),
1445 (None, false) => Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError)),
1446 }
1447 }
1448}
1449
1450impl Parse for LineClamp {
1451 fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
1452 if input.try_parse(|i| i.expect_ident_matching("none")).is_ok() {
1453 return Ok(Self::none());
1454 }
1455
1456 let mut max_lines = None;
1457 let mut block_ellipsis = None;
1458
1459 loop {
1460 if max_lines.is_none() {
1461 if let Ok(value) = input.try_parse(|i| MaxLines::parse(context, i)) {
1462 max_lines = Some(value);
1463 continue;
1464 }
1465 }
1466 if block_ellipsis.is_none() {
1467 if let Ok(value) = input.try_parse(|i| BlockEllipsis::parse(context, i)) {
1468 block_ellipsis = Some(value);
1469 continue;
1470 }
1471 }
1472
1473 break;
1474 }
1475
1476 if max_lines.is_none() && block_ellipsis.is_none() {
1477 return Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError));
1478 }
1479
1480 let webkit_legacy = input
1481 .try_parse(|i| i.expect_ident_matching("-webkit-legacy"))
1482 .is_ok();
1483
1484 let block_ellipsis = block_ellipsis.unwrap_or(BlockEllipsis::Ellipsis);
1485 let max_lines = max_lines.unwrap_or_else(MaxLines::auto);
1486
1487 Ok(Self {
1488 max_lines,
1489 block_ellipsis,
1490 webkit_legacy,
1491 })
1492 }
1493}
1494
1495impl LineClamp {
1496 pub fn parse_legacy(context: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
1498 if let Ok(value) =
1499 input.try_parse(|i| crate::values::specified::PositiveInteger::parse(context, i))
1500 {
1501 return Ok(Self {
1502 max_lines: MaxLines::lines(value, false),
1503 block_ellipsis: BlockEllipsis::Ellipsis,
1504 webkit_legacy: true,
1505 });
1506 }
1507 input.expect_ident_matching("none")?;
1508 Ok(Self::none())
1509 }
1510
1511 #[cfg(feature = "gecko")]
1513 pub(crate) fn to_css_legacy<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
1514 where
1515 W: fmt::Write,
1516 {
1517 if self.is_none() {
1518 return dest.write_str("none");
1519 }
1520
1521 if !self.webkit_legacy || !self.block_ellipsis.is_ellipsis() {
1522 return Ok(());
1523 }
1524
1525 let Some(lines) = self.max_lines.lines_value() else {
1526 return Ok(());
1527 };
1528
1529 lines.to_css(dest)
1530 }
1531}
1532
1533#[derive(
1535 Clone,
1536 Copy,
1537 Debug,
1538 Deserialize,
1539 Eq,
1540 FromPrimitive,
1541 MallocSizeOf,
1542 Parse,
1543 PartialEq,
1544 Serialize,
1545 SpecifiedValueInfo,
1546 ToAnimatedValue,
1547 ToComputedValue,
1548 ToCss,
1549 ToResolvedValue,
1550 ToShmem,
1551 ToTyped,
1552)]
1553#[repr(u8)]
1554pub enum ContentVisibility {
1555 Auto,
1559 Hidden,
1561 Visible,
1563}
1564
1565#[derive(
1566 Clone,
1567 Copy,
1568 Debug,
1569 PartialEq,
1570 Eq,
1571 MallocSizeOf,
1572 SpecifiedValueInfo,
1573 ToComputedValue,
1574 ToCss,
1575 Parse,
1576 ToResolvedValue,
1577 ToShmem,
1578 ToTyped,
1579)]
1580#[css(bitflags(
1581 single = "normal",
1582 mixed = "size,inline-size,scroll-state",
1583 validate_mixed = "Self::validate_mixed_flags",
1584))]
1585#[repr(C)]
1586pub struct ContainerType(u8);
1593bitflags! {
1594 impl ContainerType: u8 {
1595 const NORMAL = 0;
1597 const INLINE_SIZE = 1 << 0;
1599 const SIZE = 1 << 1;
1601 const SCROLL_STATE = 1 << 2;
1603 }
1604}
1605
1606impl ContainerType {
1607 fn validate_mixed_flags(&self) -> bool {
1608 if self.contains(Self::SIZE | Self::INLINE_SIZE) {
1610 return false;
1611 }
1612 if self.contains(Self::SCROLL_STATE)
1613 && !crate::pref!("layout.css.scroll-state.enabled")
1614 {
1615 return false;
1616 }
1617 true
1618 }
1619
1620 pub fn is_normal(self) -> bool {
1622 self == Self::NORMAL
1623 }
1624
1625 pub fn is_size_container_type(self) -> bool {
1627 self.intersects(Self::SIZE | Self::INLINE_SIZE)
1628 }
1629}
1630
1631#[repr(transparent)]
1633#[derive(
1634 Clone,
1635 Debug,
1636 MallocSizeOf,
1637 PartialEq,
1638 SpecifiedValueInfo,
1639 ToComputedValue,
1640 ToCss,
1641 ToResolvedValue,
1642 ToShmem,
1643 ToTyped,
1644)]
1645pub struct ContainerName(#[css(iterable, if_empty = "none")] pub crate::OwnedSlice<CustomIdent>);
1646
1647impl ContainerName {
1648 pub fn none() -> Self {
1650 Self(Default::default())
1651 }
1652
1653 pub fn is_none(&self) -> bool {
1655 self.0.is_empty()
1656 }
1657
1658 fn parse_internal(input: &mut Parser, for_query: bool) -> Result<Self, ParseError> {
1659 let mut idents = vec![];
1660 let first = input.expect_ident()?;
1661 if !for_query && first.eq_ignore_ascii_case("none") {
1662 return Ok(Self::none());
1663 }
1664 const DISALLOWED_CONTAINER_NAMES: &[&str] = &["none", "not", "or", "and"];
1665 idents.push(CustomIdent::from_ident(first, DISALLOWED_CONTAINER_NAMES)?);
1666 if !for_query {
1667 while let Ok(name) =
1668 input.try_parse(|input| CustomIdent::parse(input, DISALLOWED_CONTAINER_NAMES))
1669 {
1670 idents.push(name);
1671 }
1672 }
1673 Ok(ContainerName(idents.into()))
1674 }
1675
1676 pub fn parse_for_query(_: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
1680 Self::parse_internal(input, true)
1681 }
1682}
1683
1684impl Parse for ContainerName {
1685 fn parse(_: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
1686 Self::parse_internal(input, false)
1687 }
1688}
1689
1690pub type Perspective = GenericPerspective<NonNegativeLength>;
1692
1693impl Perspective {
1694 pub(crate) fn parse_legacy(
1696 context: &ParserContext,
1697 input: &mut Parser,
1698 ) -> Result<Self, ParseError> {
1699 use crate::values::generics::NonNegative;
1700 use crate::values::specified::{AllowQuirks, Length};
1701 if let Ok(l) = input.try_parse(|input| {
1702 Length::parse_non_negative_quirky(context, input, AllowQuirks::Always)
1703 }) {
1704 return Ok(Self::Length(NonNegative(l)));
1705 }
1706 Self::parse(context, input)
1707 }
1708}
1709
1710#[allow(missing_docs)]
1712#[derive(
1713 Clone,
1714 Copy,
1715 Debug,
1716 Deserialize,
1717 Eq,
1718 FromPrimitive,
1719 Hash,
1720 MallocSizeOf,
1721 Parse,
1722 PartialEq,
1723 Serialize,
1724 SpecifiedValueInfo,
1725 ToComputedValue,
1726 ToCss,
1727 ToResolvedValue,
1728 ToShmem,
1729 ToTyped,
1730)]
1731#[repr(u8)]
1732pub enum Float {
1733 Left,
1734 Right,
1735 None,
1736 InlineStart,
1738 InlineEnd,
1739}
1740
1741impl Float {
1742 pub fn is_floating(self) -> bool {
1744 self != Self::None
1745 }
1746}
1747
1748#[allow(missing_docs)]
1750#[derive(
1751 Clone,
1752 Copy,
1753 Debug,
1754 Deserialize,
1755 Eq,
1756 FromPrimitive,
1757 Hash,
1758 MallocSizeOf,
1759 Parse,
1760 PartialEq,
1761 Serialize,
1762 SpecifiedValueInfo,
1763 ToComputedValue,
1764 ToCss,
1765 ToResolvedValue,
1766 ToShmem,
1767 ToTyped,
1768)]
1769#[repr(u8)]
1770pub enum Clear {
1771 None,
1772 Left,
1773 Right,
1774 Both,
1775 InlineStart,
1777 InlineEnd,
1778}
1779
1780#[allow(missing_docs)]
1782#[derive(
1783 Clone,
1784 Copy,
1785 Debug,
1786 Deserialize,
1787 Eq,
1788 Hash,
1789 MallocSizeOf,
1790 Parse,
1791 PartialEq,
1792 Serialize,
1793 SpecifiedValueInfo,
1794 ToCss,
1795 ToShmem,
1796 ToTyped,
1797)]
1798pub enum Resize {
1799 None,
1800 Both,
1801 Horizontal,
1802 Vertical,
1803 Inline,
1805 Block,
1806}
1807
1808#[allow(missing_docs)]
1812#[derive(
1813 Clone,
1814 Copy,
1815 Debug,
1816 Eq,
1817 Hash,
1818 MallocSizeOf,
1819 Parse,
1820 PartialEq,
1821 SpecifiedValueInfo,
1822 ToCss,
1823 ToComputedValue,
1824 ToResolvedValue,
1825 ToShmem,
1826 ToTyped,
1827)]
1828#[repr(u8)]
1829pub enum Appearance {
1830 None,
1832 Auto,
1837 Searchfield,
1839 Textarea,
1841 Checkbox,
1843 Radio,
1845 Menulist,
1847 Listbox,
1849 Meter,
1851 ProgressBar,
1853 Button,
1855 Textfield,
1857 MenulistButton,
1859 #[parse(condition = "appearance_base_enabled")]
1861 Base,
1862 #[parse(condition = "appearance_base_select_enabled")]
1865 BaseSelect,
1866 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1868 Menupopup,
1869 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1871 MozMenulistArrowButton,
1872 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1874 NumberInput,
1875 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1877 PasswordInput,
1878 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1880 Range,
1881 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1883 ScrollbarHorizontal,
1884 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1885 ScrollbarVertical,
1886 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1890 ScrollbarbuttonUp,
1891 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1892 ScrollbarbuttonDown,
1893 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1894 ScrollbarbuttonLeft,
1895 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1896 ScrollbarbuttonRight,
1897 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1899 ScrollbarthumbHorizontal,
1900 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1901 ScrollbarthumbVertical,
1902 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1904 Scrollcorner,
1905 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1907 SpinnerUpbutton,
1908 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1910 SpinnerDownbutton,
1911 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1913 Toolbarbutton,
1914 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1916 Tooltip,
1917
1918 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1920 MozSidebar,
1921
1922 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1924 MozMacHelpButton,
1925
1926 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1930 MozMacWindow,
1931
1932 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1934 MozWindowButtonBox,
1935 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1936 MozWindowButtonClose,
1937 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1938 MozWindowButtonMaximize,
1939 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1940 MozWindowButtonMinimize,
1941 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1942 MozWindowButtonRestore,
1943 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1944 MozWindowTitlebar,
1945 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1946 MozWindowTitlebarMaximized,
1947 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1948 MozWindowDecorations,
1949
1950 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1951 MozMacDisclosureButtonClosed,
1952 #[parse(condition = "ParserContext::chrome_rules_enabled")]
1953 MozMacDisclosureButtonOpen,
1954
1955 #[css(skip)]
1959 FocusOutline,
1960
1961 #[css(skip)]
1963 Count,
1964}
1965
1966impl Appearance {
1967 #[cfg_attr(feature = "servo", allow(unused))]
1969 pub(crate) fn parse_legacy(
1970 context: &ParserContext,
1971 input: &mut Parser,
1972 ) -> Result<Self, ParseError> {
1973 Self::parse(context, input)
1975 }
1976}
1977
1978#[allow(missing_docs)]
1982#[derive(
1983 Clone,
1984 Copy,
1985 Debug,
1986 Eq,
1987 Hash,
1988 MallocSizeOf,
1989 Parse,
1990 PartialEq,
1991 SpecifiedValueInfo,
1992 ToCss,
1993 ToComputedValue,
1994 ToResolvedValue,
1995 ToShmem,
1996 ToTyped,
1997)]
1998#[repr(u8)]
1999pub enum BreakBetween {
2000 Always,
2001 Auto,
2002 Page,
2003 Avoid,
2004 Left,
2005 Right,
2006}
2007
2008impl BreakBetween {
2009 #[cfg_attr(feature = "servo", allow(unused))]
2013 #[inline]
2014 pub(crate) fn parse_legacy(_: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
2015 let break_value = BreakBetween::parse(input)?;
2016 match break_value {
2017 BreakBetween::Always => Ok(BreakBetween::Page),
2018 BreakBetween::Auto | BreakBetween::Avoid | BreakBetween::Left | BreakBetween::Right => {
2019 Ok(break_value)
2020 },
2021 BreakBetween::Page => Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError)),
2022 }
2023 }
2024
2025 #[cfg_attr(feature = "servo", allow(unused))]
2029 pub(crate) fn to_css_legacy<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
2030 where
2031 W: Write,
2032 {
2033 match *self {
2034 BreakBetween::Auto | BreakBetween::Avoid | BreakBetween::Left | BreakBetween::Right => {
2035 self.to_css(dest)
2036 },
2037 BreakBetween::Page => dest.write_str("always"),
2038 BreakBetween::Always => Ok(()),
2039 }
2040 }
2041}
2042
2043#[allow(missing_docs)]
2047#[derive(
2048 Clone,
2049 Copy,
2050 Debug,
2051 Eq,
2052 Hash,
2053 MallocSizeOf,
2054 Parse,
2055 PartialEq,
2056 SpecifiedValueInfo,
2057 ToCss,
2058 ToComputedValue,
2059 ToResolvedValue,
2060 ToShmem,
2061 ToTyped,
2062)]
2063#[repr(u8)]
2064pub enum BreakWithin {
2065 Auto,
2066 Avoid,
2067 AvoidPage,
2068 AvoidColumn,
2069}
2070
2071impl BreakWithin {
2072 #[cfg_attr(feature = "servo", allow(unused))]
2076 #[inline]
2077 pub(crate) fn parse_legacy(_: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
2078 let break_value = BreakWithin::parse(input)?;
2079 match break_value {
2080 BreakWithin::Auto | BreakWithin::Avoid => Ok(break_value),
2081 BreakWithin::AvoidPage | BreakWithin::AvoidColumn => {
2082 Err(ParseError::custom(StyleParseErrorKind::UnspecifiedError))
2083 },
2084 }
2085 }
2086
2087 #[cfg_attr(feature = "servo", allow(unused))]
2091 pub(crate) fn to_css_legacy<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
2092 where
2093 W: Write,
2094 {
2095 match *self {
2096 BreakWithin::Auto | BreakWithin::Avoid => self.to_css(dest),
2097 BreakWithin::AvoidPage | BreakWithin::AvoidColumn => Ok(()),
2098 }
2099 }
2100}
2101
2102#[allow(missing_docs)]
2104#[derive(
2105 Clone,
2106 Copy,
2107 Debug,
2108 Eq,
2109 Hash,
2110 MallocSizeOf,
2111 PartialEq,
2112 SpecifiedValueInfo,
2113 ToCss,
2114 ToComputedValue,
2115 ToResolvedValue,
2116 ToShmem,
2117 ToTyped,
2118)]
2119#[repr(u8)]
2120pub enum Overflow {
2121 Visible,
2122 Hidden,
2123 Scroll,
2124 Auto,
2125 Clip,
2126}
2127
2128impl Parse for Overflow {
2131 fn parse(_: &ParserContext, input: &mut Parser) -> Result<Self, ParseError> {
2132 Ok(try_match_ident_ignore_ascii_case! { input,
2133 "visible" => Self::Visible,
2134 "hidden" => Self::Hidden,
2135 "scroll" => Self::Scroll,
2136 "auto" | "overlay" => Self::Auto,
2137 "clip" => Self::Clip,
2138 "-moz-hidden-unscrollable" if crate::pref!("layout.css.overflow-moz-hidden-unscrollable.enabled") => {
2139 Overflow::Clip
2140 },
2141 })
2142 }
2143}
2144
2145impl Overflow {
2146 #[inline]
2148 pub fn is_scrollable(&self) -> bool {
2149 matches!(*self, Self::Hidden | Self::Scroll | Self::Auto)
2150 }
2151 #[inline]
2154 pub fn to_scrollable(&self) -> Self {
2155 match *self {
2156 Self::Hidden | Self::Scroll | Self::Auto => *self,
2157 Self::Visible => Self::Auto,
2158 Self::Clip => Self::Hidden,
2159 }
2160 }
2161}
2162
2163#[derive(
2164 Clone,
2165 Copy,
2166 Debug,
2167 Eq,
2168 MallocSizeOf,
2169 Parse,
2170 PartialEq,
2171 SpecifiedValueInfo,
2172 ToComputedValue,
2173 ToCss,
2174 ToResolvedValue,
2175 ToShmem,
2176 ToTyped,
2177)]
2178#[repr(C)]
2179#[css(bitflags(
2180 single = "auto",
2181 mixed = "stable,both-edges",
2182 validate_mixed = "Self::has_stable"
2183))]
2184pub struct ScrollbarGutter(u8);
2187bitflags! {
2188 impl ScrollbarGutter: u8 {
2189 const AUTO = 0;
2191 const STABLE = 1 << 0;
2193 const BOTH_EDGES = 1 << 1;
2195 }
2196}
2197
2198impl ScrollbarGutter {
2199 #[inline]
2200 fn has_stable(&self) -> bool {
2201 self.intersects(Self::STABLE)
2202 }
2203}
2204
2205#[derive(
2207 Clone, Debug, MallocSizeOf, PartialEq, Parse, SpecifiedValueInfo, ToCss, ToShmem, ToTyped,
2208)]
2209#[allow(missing_docs)]
2210#[typed(todo_derive_fields)]
2211pub enum Zoom {
2212 Normal,
2213 #[parse(condition = "ParserContext::in_ua_sheet")]
2216 Document,
2217 Value(NonNegativeNumberOrPercentage),
2218}
2219
2220impl Zoom {
2221 #[inline]
2223 pub fn new_number(n: f32) -> Self {
2224 Self::Value(NonNegativeNumberOrPercentage::new_number(n))
2225 }
2226}
2227
2228pub use crate::values::generics::box_::PositionProperty;