1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
5 //! Specified types for box properties.
7 use crate::custom_properties::Name as CustomPropertyName;
8 use crate::parser::{Parse, ParserContext};
9 use crate::properties::{LonghandId, PropertyDeclarationId, PropertyFlags};
10 use crate::properties::{PropertyId, ShorthandId};
11 use crate::values::generics::box_::AnimationIterationCount as GenericAnimationIterationCount;
12 use crate::values::generics::box_::Perspective as GenericPerspective;
13 use crate::values::generics::box_::{GenericVerticalAlign, VerticalAlignKeyword};
14 use crate::values::specified::length::{LengthPercentage, NonNegativeLength};
15 use crate::values::specified::{AllowQuirks, Number};
16 use crate::values::{CustomIdent, KeyframesName};
18 use cssparser::Parser;
19 use num_traits::FromPrimitive;
20 use selectors::parser::SelectorParseErrorKind;
21 use std::fmt::{self, Write};
22 use style_traits::{CssWriter, KeywordsCollectFn, ParseError};
23 use style_traits::{SpecifiedValueInfo, StyleParseErrorKind, ToCss};
25 #[cfg(feature = "gecko")]
26 fn moz_display_values_enabled(context: &ParserContext) -> bool {
27 context.in_ua_or_chrome_sheet() ||
28 static_prefs::pref!("layout.css.xul-display-values.content.enabled")
31 #[cfg(feature = "gecko")]
32 fn moz_box_display_values_enabled(context: &ParserContext) -> bool {
33 context.in_ua_or_chrome_sheet() ||
34 static_prefs::pref!("layout.css.xul-box-display-values.content.enabled")
37 fn flexbox_enabled() -> bool {
38 #[cfg(feature = "servo-layout-2020")]
40 return servo_config::prefs::pref_map()
41 .get("layout.flexbox.enabled")
49 /// Defines an element’s display type, which consists of
50 /// the two basic qualities of how an element generates boxes
51 /// <https://drafts.csswg.org/css-display/#propdef-display>
52 #[allow(missing_docs)]
53 #[derive(Clone, Copy, Debug, Eq, FromPrimitive, Hash, MallocSizeOf, PartialEq, ToCss, ToShmem)]
55 pub enum DisplayOutside {
59 #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
61 #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
63 #[cfg(feature = "gecko")]
65 #[cfg(feature = "gecko")]
69 #[allow(missing_docs)]
70 #[derive(Clone, Copy, Debug, Eq, FromPrimitive, Hash, MallocSizeOf, PartialEq, ToCss, ToShmem)]
72 pub enum DisplayInside {
74 #[cfg(any(feature = "servo-layout-2020", feature = "gecko"))]
79 #[cfg(feature = "gecko")]
81 #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
83 #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
85 #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
87 #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
89 #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
91 #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
93 #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
95 #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
97 #[cfg(feature = "gecko")]
99 #[cfg(feature = "gecko")]
101 #[cfg(feature = "gecko")]
103 #[cfg(feature = "gecko")]
105 #[cfg(feature = "gecko")]
107 #[cfg(feature = "gecko")]
109 #[cfg(feature = "gecko")]
111 #[cfg(feature = "gecko")]
113 #[cfg(feature = "gecko")]
115 #[cfg(feature = "gecko")]
117 #[cfg(feature = "gecko")]
119 #[cfg(feature = "gecko")]
121 #[cfg(feature = "gecko")]
125 #[allow(missing_docs)]
140 pub struct Display(u16);
142 /// Gecko-only impl block for Display (shared stuff later in this file):
143 #[allow(missing_docs)]
144 #[allow(non_upper_case_globals)]
146 // Our u16 bits are used as follows: LOOOOOOOIIIIIIII
147 const LIST_ITEM_BIT: u16 = 0x8000; //^
148 const DISPLAY_OUTSIDE_BITS: u16 = 7; // ^^^^^^^
149 const DISPLAY_INSIDE_BITS: u16 = 8; // ^^^^^^^^
151 /// https://drafts.csswg.org/css-display/#the-display-properties
152 pub const None: Self = Self::new(DisplayOutside::None, DisplayInside::None);
153 #[cfg(any(feature = "servo-layout-2020", feature = "gecko"))]
154 pub const Contents: Self = Self::new(DisplayOutside::None, DisplayInside::Contents);
155 pub const Inline: Self = Self::new(DisplayOutside::Inline, DisplayInside::Flow);
156 pub const InlineBlock: Self = Self::new(DisplayOutside::Inline, DisplayInside::FlowRoot);
157 pub const Block: Self = Self::new(DisplayOutside::Block, DisplayInside::Flow);
158 #[cfg(feature = "gecko")]
159 pub const FlowRoot: Self = Self::new(DisplayOutside::Block, DisplayInside::FlowRoot);
160 pub const Flex: Self = Self::new(DisplayOutside::Block, DisplayInside::Flex);
161 pub const InlineFlex: Self = Self::new(DisplayOutside::Inline, DisplayInside::Flex);
162 #[cfg(feature = "gecko")]
163 pub const Grid: Self = Self::new(DisplayOutside::Block, DisplayInside::Grid);
164 #[cfg(feature = "gecko")]
165 pub const InlineGrid: Self = Self::new(DisplayOutside::Inline, DisplayInside::Grid);
166 #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
167 pub const Table: Self = Self::new(DisplayOutside::Block, DisplayInside::Table);
168 #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
169 pub const InlineTable: Self = Self::new(DisplayOutside::Inline, DisplayInside::Table);
170 #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
171 pub const TableCaption: Self = Self::new(DisplayOutside::TableCaption, DisplayInside::Flow);
172 #[cfg(feature = "gecko")]
173 pub const Ruby: Self = Self::new(DisplayOutside::Inline, DisplayInside::Ruby);
174 #[cfg(feature = "gecko")]
175 pub const WebkitBox: Self = Self::new(DisplayOutside::Block, DisplayInside::WebkitBox);
176 #[cfg(feature = "gecko")]
177 pub const WebkitInlineBox: Self = Self::new(DisplayOutside::Inline, DisplayInside::WebkitBox);
179 // Internal table boxes.
181 #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
182 pub const TableRowGroup: Self =
183 Self::new(DisplayOutside::InternalTable, DisplayInside::TableRowGroup);
185 #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
186 pub const TableHeaderGroup: Self = Self::new(
187 DisplayOutside::InternalTable,
188 DisplayInside::TableHeaderGroup,
191 #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
192 pub const TableFooterGroup: Self = Self::new(
193 DisplayOutside::InternalTable,
194 DisplayInside::TableFooterGroup,
197 #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
198 pub const TableColumn: Self =
199 Self::new(DisplayOutside::InternalTable, DisplayInside::TableColumn);
201 #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
202 pub const TableColumnGroup: Self = Self::new(
203 DisplayOutside::InternalTable,
204 DisplayInside::TableColumnGroup,
207 #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
208 pub const TableRow: Self = Self::new(DisplayOutside::InternalTable, DisplayInside::TableRow);
210 #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
211 pub const TableCell: Self = Self::new(DisplayOutside::InternalTable, DisplayInside::TableCell);
213 /// Internal ruby boxes.
214 #[cfg(feature = "gecko")]
215 pub const RubyBase: Self = Self::new(DisplayOutside::InternalRuby, DisplayInside::RubyBase);
216 #[cfg(feature = "gecko")]
217 pub const RubyBaseContainer: Self = Self::new(
218 DisplayOutside::InternalRuby,
219 DisplayInside::RubyBaseContainer,
221 #[cfg(feature = "gecko")]
222 pub const RubyText: Self = Self::new(DisplayOutside::InternalRuby, DisplayInside::RubyText);
223 #[cfg(feature = "gecko")]
224 pub const RubyTextContainer: Self = Self::new(
225 DisplayOutside::InternalRuby,
226 DisplayInside::RubyTextContainer,
230 #[cfg(feature = "gecko")]
231 pub const MozBox: Self = Self::new(DisplayOutside::Block, DisplayInside::MozBox);
232 #[cfg(feature = "gecko")]
233 pub const MozInlineBox: Self = Self::new(DisplayOutside::Inline, DisplayInside::MozBox);
234 #[cfg(feature = "gecko")]
235 pub const MozGrid: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozGrid);
236 #[cfg(feature = "gecko")]
237 pub const MozGridGroup: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozGridGroup);
238 #[cfg(feature = "gecko")]
239 pub const MozGridLine: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozGridLine);
240 #[cfg(feature = "gecko")]
241 pub const MozStack: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozStack);
242 #[cfg(feature = "gecko")]
243 pub const MozDeck: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozDeck);
244 #[cfg(feature = "gecko")]
245 pub const MozPopup: Self = Self::new(DisplayOutside::XUL, DisplayInside::MozPopup);
247 /// Make a raw display value from <display-outside> and <display-inside> values.
249 const fn new(outside: DisplayOutside, inside: DisplayInside) -> Self {
250 let o: u16 = ((outside as u8) as u16) << Self::DISPLAY_INSIDE_BITS;
251 let i: u16 = (inside as u8) as u16;
255 /// Make a display enum value from <display-outside> and <display-inside> values.
257 fn from3(outside: DisplayOutside, inside: DisplayInside, list_item: bool) -> Self {
258 let v = Self::new(outside, inside);
262 Self(v.0 | Self::LIST_ITEM_BIT)
265 /// Accessor for the <display-inside> value.
267 pub fn inside(&self) -> DisplayInside {
268 DisplayInside::from_u16(self.0 & ((1 << Self::DISPLAY_INSIDE_BITS) - 1)).unwrap()
271 /// Accessor for the <display-outside> value.
273 pub fn outside(&self) -> DisplayOutside {
274 DisplayOutside::from_u16(
275 (self.0 >> Self::DISPLAY_INSIDE_BITS) & ((1 << Self::DISPLAY_OUTSIDE_BITS) - 1),
280 /// Whether this is `display: inline` (or `inline list-item`).
282 pub fn is_inline_flow(&self) -> bool {
283 self.outside() == DisplayOutside::Inline && self.inside() == DisplayInside::Flow
286 /// Returns whether this `display` value is some kind of list-item.
288 pub const fn is_list_item(&self) -> bool {
289 (self.0 & Self::LIST_ITEM_BIT) != 0
292 /// Returns whether this `display` value is a ruby level container.
293 pub fn is_ruby_level_container(&self) -> bool {
295 #[cfg(feature = "gecko")]
296 Display::RubyBaseContainer | Display::RubyTextContainer => true,
301 /// Returns whether this `display` value is one of the types for ruby.
302 pub fn is_ruby_type(&self) -> bool {
303 match self.inside() {
304 #[cfg(feature = "gecko")]
305 DisplayInside::Ruby |
306 DisplayInside::RubyBase |
307 DisplayInside::RubyText |
308 DisplayInside::RubyBaseContainer |
309 DisplayInside::RubyTextContainer => true,
315 /// Shared Display impl for both Gecko and Servo.
316 #[allow(non_upper_case_globals)]
318 /// The initial display value.
320 pub fn inline() -> Self {
324 /// <https://drafts.csswg.org/css2/visuren.html#x13>
325 #[cfg(feature = "servo")]
327 pub fn is_atomic_inline_level(&self) -> bool {
329 Display::InlineBlock | Display::InlineFlex => true,
330 #[cfg(any(feature = "servo-layout-2013"))]
331 Display::InlineTable => true,
336 /// Returns whether this `display` value is the display of a flex or
339 /// This is used to implement various style fixups.
340 pub fn is_item_container(&self) -> bool {
341 match self.inside() {
342 DisplayInside::Flex => true,
343 #[cfg(feature = "gecko")]
344 DisplayInside::Grid => true,
349 /// Returns whether an element with this display type is a line
350 /// participant, which means it may lay its children on the same
352 pub fn is_line_participant(&self) -> bool {
354 Display::Inline => true,
355 #[cfg(feature = "gecko")]
356 Display::Contents | Display::Ruby | Display::RubyBaseContainer => true,
361 /// Convert this display into an equivalent block display.
363 /// Also used for :root style adjustments.
364 pub fn equivalent_block_display(&self, _is_root_element: bool) -> Self {
365 #[cfg(any(feature = "servo-layout-2020", feature = "gecko"))]
367 // Special handling for `contents` and `list-item`s on the root element.
368 if _is_root_element && (self.is_contents() || self.is_list_item()) {
369 return Display::Block;
373 match self.outside() {
374 DisplayOutside::Inline => {
375 let inside = match self.inside() {
376 // `inline-block` blockifies to `block` rather than
377 // `flow-root`, for legacy reasons.
378 DisplayInside::FlowRoot => DisplayInside::Flow,
381 Display::from3(DisplayOutside::Block, inside, self.is_list_item())
383 DisplayOutside::Block | DisplayOutside::None => *self,
384 #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
389 /// Convert this display into an equivalent inline-outside display.
390 /// https://drafts.csswg.org/css-display/#inlinify
391 #[cfg(feature = "gecko")]
392 pub fn inlinify(&self) -> Self {
393 match self.outside() {
394 DisplayOutside::Block => {
395 let inside = match self.inside() {
396 // `display: block` inlinifies to `display: inline-block`,
397 // rather than `inline`, for legacy reasons.
398 DisplayInside::Flow => DisplayInside::FlowRoot,
401 Display::from3(DisplayOutside::Inline, inside, self.is_list_item())
407 /// Returns true if the value is `Contents`
409 pub fn is_contents(&self) -> bool {
411 #[cfg(any(feature = "servo-layout-2020", feature = "gecko"))]
412 Display::Contents => true,
417 /// Returns true if the value is `None`
419 pub fn is_none(&self) -> bool {
420 *self == Display::None
424 impl ToCss for Display {
425 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
429 let outside = self.outside();
430 let inside = self.inside();
432 Display::Block | Display::Inline => outside.to_css(dest),
433 Display::InlineBlock => dest.write_str("inline-block"),
434 #[cfg(feature = "gecko")]
435 Display::WebkitInlineBox => dest.write_str("-webkit-inline-box"),
436 #[cfg(feature = "gecko")]
437 Display::MozInlineBox => dest.write_str("-moz-inline-box"),
438 #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
439 Display::TableCaption => dest.write_str("table-caption"),
440 _ => match (outside, inside) {
441 #[cfg(feature = "gecko")]
442 (DisplayOutside::Inline, DisplayInside::Grid) => dest.write_str("inline-grid"),
443 (DisplayOutside::Inline, DisplayInside::Flex) => dest.write_str("inline-flex"),
444 #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
445 (DisplayOutside::Inline, DisplayInside::Table) => dest.write_str("inline-table"),
446 #[cfg(feature = "gecko")]
447 (DisplayOutside::Block, DisplayInside::Ruby) => dest.write_str("block ruby"),
449 if self.is_list_item() {
450 if outside != DisplayOutside::Block {
451 outside.to_css(dest)?;
452 dest.write_str(" ")?;
454 if inside != DisplayInside::Flow {
455 inside.to_css(dest)?;
456 dest.write_str(" ")?;
458 dest.write_str("list-item")
468 /// <display-inside> = flow | flow-root | table | flex | grid | ruby
469 /// https://drafts.csswg.org/css-display/#typedef-display-inside
470 fn parse_display_inside<'i, 't>(
471 input: &mut Parser<'i, 't>,
472 ) -> Result<DisplayInside, ParseError<'i>> {
473 Ok(try_match_ident_ignore_ascii_case! { input,
474 "flow" => DisplayInside::Flow,
475 "flex" if flexbox_enabled() => DisplayInside::Flex,
476 #[cfg(any(feature = "servo-layout-2020", feature = "gecko"))]
477 "flow-root" => DisplayInside::FlowRoot,
478 #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
479 "table" => DisplayInside::Table,
480 #[cfg(feature = "gecko")]
481 "grid" => DisplayInside::Grid,
482 #[cfg(feature = "gecko")]
483 "ruby" => DisplayInside::Ruby,
487 /// <display-outside> = block | inline | run-in
488 /// https://drafts.csswg.org/css-display/#typedef-display-outside
489 fn parse_display_outside<'i, 't>(
490 input: &mut Parser<'i, 't>,
491 ) -> Result<DisplayOutside, ParseError<'i>> {
492 Ok(try_match_ident_ignore_ascii_case! { input,
493 "block" => DisplayOutside::Block,
494 "inline" => DisplayOutside::Inline,
495 // FIXME(bug 2056): not supported in layout yet:
496 //"run-in" => DisplayOutside::RunIn,
500 /// (flow | flow-root)?
501 fn parse_display_inside_for_list_item<'i, 't>(
502 input: &mut Parser<'i, 't>,
503 ) -> Result<DisplayInside, ParseError<'i>> {
504 Ok(try_match_ident_ignore_ascii_case! { input,
505 "flow" => DisplayInside::Flow,
506 #[cfg(feature = "gecko")]
507 "flow-root" => DisplayInside::FlowRoot,
510 /// Test a <display-inside> Result for same values as above.
511 fn is_valid_inside_for_list_item<'i>(inside: &Result<DisplayInside, ParseError<'i>>) -> bool {
513 Ok(DisplayInside::Flow) => true,
514 #[cfg(feature = "gecko")]
515 Ok(DisplayInside::FlowRoot) => true,
520 /// Parse `list-item`.
521 fn parse_list_item<'i, 't>(input: &mut Parser<'i, 't>) -> Result<(), ParseError<'i>> {
522 Ok(try_match_ident_ignore_ascii_case! { input,
527 impl Parse for Display {
528 #[allow(unused)] // `context` isn't used for servo-2020 for now
530 context: &ParserContext,
531 input: &mut Parser<'i, 't>,
532 ) -> Result<Display, ParseError<'i>> {
533 // Parse all combinations of <display-inside/outside>? and `list-item`? first.
534 let mut got_list_item = input.try_parse(parse_list_item).is_ok();
535 let mut inside = if got_list_item {
536 input.try_parse(parse_display_inside_for_list_item)
538 input.try_parse(parse_display_inside)
540 // <display-listitem> = <display-outside>? && [ flow | flow-root ]? && list-item
541 // https://drafts.csswg.org/css-display/#typedef-display-listitem
542 if !got_list_item && is_valid_inside_for_list_item(&inside) {
543 got_list_item = input.try_parse(parse_list_item).is_ok();
545 let outside = input.try_parse(parse_display_outside);
547 if !got_list_item && (inside.is_err() || is_valid_inside_for_list_item(&inside)) {
548 got_list_item = input.try_parse(parse_list_item).is_ok();
551 inside = if got_list_item {
552 input.try_parse(parse_display_inside_for_list_item)
554 input.try_parse(parse_display_inside)
556 if !got_list_item && is_valid_inside_for_list_item(&inside) {
557 got_list_item = input.try_parse(parse_list_item).is_ok();
561 if got_list_item || inside.is_ok() || outside.is_ok() {
562 let inside = inside.unwrap_or(DisplayInside::Flow);
563 let outside = outside.unwrap_or(match inside {
564 // "If <display-outside> is omitted, the element’s outside display type
565 // defaults to block — except for ruby, which defaults to inline."
566 // https://drafts.csswg.org/css-display/#inside-model
567 #[cfg(feature = "gecko")]
568 DisplayInside::Ruby => DisplayOutside::Inline,
569 _ => DisplayOutside::Block,
571 return Ok(Display::from3(outside, inside, got_list_item));
574 // Now parse the single-keyword `display` values.
575 Ok(try_match_ident_ignore_ascii_case! { input,
576 "none" => Display::None,
577 #[cfg(any(feature = "servo-layout-2020", feature = "gecko"))]
578 "contents" => Display::Contents,
579 "inline-block" => Display::InlineBlock,
580 #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
581 "inline-table" => Display::InlineTable,
582 "-webkit-flex" if flexbox_enabled() => Display::Flex,
583 "inline-flex" | "-webkit-inline-flex" if flexbox_enabled() => Display::InlineFlex,
584 #[cfg(feature = "gecko")]
585 "inline-grid" => Display::InlineGrid,
586 #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
587 "table-caption" => Display::TableCaption,
588 #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
589 "table-row-group" => Display::TableRowGroup,
590 #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
591 "table-header-group" => Display::TableHeaderGroup,
592 #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
593 "table-footer-group" => Display::TableFooterGroup,
594 #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
595 "table-column" => Display::TableColumn,
596 #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
597 "table-column-group" => Display::TableColumnGroup,
598 #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
599 "table-row" => Display::TableRow,
600 #[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
601 "table-cell" => Display::TableCell,
602 #[cfg(feature = "gecko")]
603 "ruby-base" => Display::RubyBase,
604 #[cfg(feature = "gecko")]
605 "ruby-base-container" => Display::RubyBaseContainer,
606 #[cfg(feature = "gecko")]
607 "ruby-text" => Display::RubyText,
608 #[cfg(feature = "gecko")]
609 "ruby-text-container" => Display::RubyTextContainer,
610 #[cfg(feature = "gecko")]
611 "-webkit-box" => Display::WebkitBox,
612 #[cfg(feature = "gecko")]
613 "-webkit-inline-box" => Display::WebkitInlineBox,
614 #[cfg(feature = "gecko")]
615 "-moz-box" if moz_box_display_values_enabled(context) => Display::MozBox,
616 #[cfg(feature = "gecko")]
617 "-moz-inline-box" if moz_box_display_values_enabled(context) => Display::MozInlineBox,
618 #[cfg(feature = "gecko")]
619 "-moz-grid" if moz_display_values_enabled(context) => Display::MozGrid,
620 #[cfg(feature = "gecko")]
621 "-moz-grid-group" if moz_display_values_enabled(context) => Display::MozGridGroup,
622 #[cfg(feature = "gecko")]
623 "-moz-grid-line" if moz_display_values_enabled(context) => Display::MozGridLine,
624 #[cfg(feature = "gecko")]
625 "-moz-stack" if moz_display_values_enabled(context) => Display::MozStack,
626 #[cfg(feature = "gecko")]
627 "-moz-deck" if moz_display_values_enabled(context) => Display::MozDeck,
628 #[cfg(feature = "gecko")]
629 "-moz-popup" if moz_display_values_enabled(context) => Display::MozPopup,
634 impl SpecifiedValueInfo for Display {
635 fn collect_completion_keywords(f: KeywordsCollectFn) {
641 "flow-root list-item",
649 "inline flow-root list-item",
655 "ruby-base-container",
657 "ruby-text-container",
662 "table-column-group",
663 "table-footer-group",
664 "table-header-group",
668 "-webkit-inline-box",
673 /// A specified value for the `vertical-align` property.
674 pub type VerticalAlign = GenericVerticalAlign<LengthPercentage>;
676 impl Parse for VerticalAlign {
678 context: &ParserContext,
679 input: &mut Parser<'i, 't>,
680 ) -> Result<Self, ParseError<'i>> {
682 input.try_parse(|i| LengthPercentage::parse_quirky(context, i, AllowQuirks::Yes))
684 return Ok(GenericVerticalAlign::Length(lp));
687 Ok(GenericVerticalAlign::Keyword(VerticalAlignKeyword::parse(
693 /// https://drafts.csswg.org/css-animations/#animation-iteration-count
694 pub type AnimationIterationCount = GenericAnimationIterationCount<Number>;
696 impl Parse for AnimationIterationCount {
698 context: &ParserContext,
699 input: &mut ::cssparser::Parser<'i, 't>,
700 ) -> Result<Self, ParseError<'i>> {
702 .try_parse(|input| input.expect_ident_matching("infinite"))
705 return Ok(GenericAnimationIterationCount::Infinite);
708 let number = Number::parse_non_negative(context, input)?;
709 Ok(GenericAnimationIterationCount::Number(number))
713 impl AnimationIterationCount {
714 /// Returns the value `1.0`.
716 pub fn one() -> Self {
717 GenericAnimationIterationCount::Number(Number::new(1.0))
721 /// A value for the `animation-name` property.
734 #[value_info(other_values = "none")]
735 pub struct AnimationName(pub Option<KeyframesName>);
738 /// Get the name of the animation as an `Atom`.
739 pub fn as_atom(&self) -> Option<&Atom> {
740 self.0.as_ref().map(|n| n.as_atom())
743 /// Returns the `none` value.
744 pub fn none() -> Self {
749 impl ToCss for AnimationName {
750 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
755 Some(ref name) => name.to_css(dest),
756 None => dest.write_str("none"),
761 impl Parse for AnimationName {
763 context: &ParserContext,
764 input: &mut Parser<'i, 't>,
765 ) -> Result<Self, ParseError<'i>> {
766 if let Ok(name) = input.try_parse(|input| KeyframesName::parse(context, input)) {
767 return Ok(AnimationName(Some(name)));
770 input.expect_ident_matching("none")?;
771 Ok(AnimationName(None))
775 /// https://drafts.csswg.org/css-scroll-snap-1/#snap-axis
776 #[allow(missing_docs)]
777 #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
793 pub enum ScrollSnapAxis {
801 /// https://drafts.csswg.org/css-scroll-snap-1/#snap-strictness
802 #[allow(missing_docs)]
803 #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
819 pub enum ScrollSnapStrictness {
821 None, // Used to represent scroll-snap-type: none. It's not parsed.
826 /// https://drafts.csswg.org/css-scroll-snap-1/#scroll-snap-type
827 #[allow(missing_docs)]
828 #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
842 pub struct ScrollSnapType {
843 axis: ScrollSnapAxis,
844 strictness: ScrollSnapStrictness,
847 impl ScrollSnapType {
850 pub fn none() -> Self {
852 axis: ScrollSnapAxis::Both,
853 strictness: ScrollSnapStrictness::None,
858 impl Parse for ScrollSnapType {
859 /// none | [ x | y | block | inline | both ] [ mandatory | proximity ]?
861 _context: &ParserContext,
862 input: &mut Parser<'i, 't>,
863 ) -> Result<Self, ParseError<'i>> {
865 .try_parse(|input| input.expect_ident_matching("none"))
868 return Ok(ScrollSnapType::none());
871 let axis = ScrollSnapAxis::parse(input)?;
872 let strictness = input
873 .try_parse(ScrollSnapStrictness::parse)
874 .unwrap_or(ScrollSnapStrictness::Proximity);
875 Ok(Self { axis, strictness })
879 impl ToCss for ScrollSnapType {
880 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
884 if self.strictness == ScrollSnapStrictness::None {
885 return dest.write_str("none");
887 self.axis.to_css(dest)?;
888 if self.strictness != ScrollSnapStrictness::Proximity {
889 dest.write_str(" ")?;
890 self.strictness.to_css(dest)?;
896 /// Specified value of scroll-snap-align keyword value.
897 #[allow(missing_docs)]
915 pub enum ScrollSnapAlignKeyword {
922 /// https://drafts.csswg.org/css-scroll-snap-1/#scroll-snap-align
923 #[allow(missing_docs)]
937 pub struct ScrollSnapAlign {
938 block: ScrollSnapAlignKeyword,
939 inline: ScrollSnapAlignKeyword,
942 impl ScrollSnapAlign {
945 pub fn none() -> Self {
947 block: ScrollSnapAlignKeyword::None,
948 inline: ScrollSnapAlignKeyword::None,
953 impl Parse for ScrollSnapAlign {
954 /// [ none | start | end | center ]{1,2}
956 _context: &ParserContext,
957 input: &mut Parser<'i, 't>,
958 ) -> Result<ScrollSnapAlign, ParseError<'i>> {
959 let block = ScrollSnapAlignKeyword::parse(input)?;
961 .try_parse(ScrollSnapAlignKeyword::parse)
963 Ok(ScrollSnapAlign { block, inline })
967 impl ToCss for ScrollSnapAlign {
968 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
972 self.block.to_css(dest)?;
973 if self.block != self.inline {
974 dest.write_str(" ")?;
975 self.inline.to_css(dest)?;
981 #[allow(missing_docs)]
982 #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
998 pub enum OverscrollBehavior {
1004 #[allow(missing_docs)]
1005 #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
1021 pub enum OverflowAnchor {
1026 #[allow(missing_docs)]
1027 #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
1043 pub enum OverflowClipBox {
1062 /// Provides a rendering hint to the user agent, stating what kinds of changes
1063 /// the author expects to perform on the element.
1065 /// `auto` is represented by an empty `features` list.
1067 /// <https://drafts.csswg.org/css-will-change/#will-change>
1068 pub struct WillChange {
1069 /// The features that are supposed to change.
1071 /// TODO(emilio): Consider using ArcSlice since we just clone them from the
1072 /// specified value? That'd save an allocation, which could be worth it.
1073 #[css(iterable, if_empty = "auto")]
1074 features: crate::OwnedSlice<CustomIdent>,
1075 /// A bitfield with the kind of change that the value will create, based
1076 /// on the above field.
1078 bits: WillChangeBits,
1083 /// Get default value of `will-change` as `auto`
1084 pub fn auto() -> Self {
1090 /// The change bits that we care about.
1091 #[derive(Default, MallocSizeOf, SpecifiedValueInfo, ToComputedValue, ToResolvedValue, ToShmem)]
1093 pub struct WillChangeBits: u8 {
1094 /// Whether the stacking context will change.
1095 const STACKING_CONTEXT = 1 << 0;
1096 /// Whether `transform` will change.
1097 const TRANSFORM = 1 << 1;
1098 /// Whether `scroll-position` will change.
1099 const SCROLL = 1 << 2;
1100 /// Whether `opacity` will change.
1101 const OPACITY = 1 << 3;
1102 /// Fixed pos containing block.
1103 const FIXPOS_CB = 1 << 4;
1104 /// Abs pos containing block.
1105 const ABSPOS_CB = 1 << 5;
1109 fn change_bits_for_longhand(longhand: LonghandId) -> WillChangeBits {
1110 let mut flags = match longhand {
1111 LonghandId::Opacity => WillChangeBits::OPACITY,
1112 LonghandId::Transform => WillChangeBits::TRANSFORM,
1113 #[cfg(feature = "gecko")]
1114 LonghandId::Translate | LonghandId::Rotate | LonghandId::Scale | LonghandId::OffsetPath => {
1115 WillChangeBits::TRANSFORM
1117 _ => WillChangeBits::empty(),
1120 let property_flags = longhand.flags();
1121 if property_flags.contains(PropertyFlags::CREATES_STACKING_CONTEXT) {
1122 flags |= WillChangeBits::STACKING_CONTEXT;
1124 if property_flags.contains(PropertyFlags::FIXPOS_CB) {
1125 flags |= WillChangeBits::FIXPOS_CB;
1127 if property_flags.contains(PropertyFlags::ABSPOS_CB) {
1128 flags |= WillChangeBits::ABSPOS_CB;
1133 fn change_bits_for_maybe_property(ident: &str, context: &ParserContext) -> WillChangeBits {
1134 let id = match PropertyId::parse_ignoring_rule_type(ident, context) {
1136 Err(..) => return WillChangeBits::empty(),
1139 match id.as_shorthand() {
1140 Ok(shorthand) => shorthand
1142 .fold(WillChangeBits::empty(), |flags, p| {
1143 flags | change_bits_for_longhand(p)
1145 Err(PropertyDeclarationId::Longhand(longhand)) => change_bits_for_longhand(longhand),
1146 Err(PropertyDeclarationId::Custom(..)) => WillChangeBits::empty(),
1150 impl Parse for WillChange {
1151 /// auto | <animateable-feature>#
1153 context: &ParserContext,
1154 input: &mut Parser<'i, 't>,
1155 ) -> Result<Self, ParseError<'i>> {
1157 .try_parse(|input| input.expect_ident_matching("auto"))
1160 return Ok(Self::default());
1163 let mut bits = WillChangeBits::empty();
1164 let custom_idents = input.parse_comma_separated(|i| {
1165 let location = i.current_source_location();
1166 let parser_ident = i.expect_ident()?;
1167 let ident = CustomIdent::from_ident(
1170 &["will-change", "none", "all", "auto"],
1173 if ident.0 == atom!("scroll-position") {
1174 bits |= WillChangeBits::SCROLL;
1176 bits |= change_bits_for_maybe_property(&parser_ident, context);
1182 features: custom_idents.into(),
1189 /// Values for the `touch-action` property.
1190 #[derive(MallocSizeOf, SpecifiedValueInfo, ToComputedValue, ToResolvedValue, ToShmem)]
1191 /// These constants match Gecko's `NS_STYLE_TOUCH_ACTION_*` constants.
1192 #[value_info(other_values = "auto,none,manipulation,pan-x,pan-y")]
1194 pub struct TouchAction: u8 {
1196 const NONE = 1 << 0;
1198 const AUTO = 1 << 1;
1200 const PAN_X = 1 << 2;
1202 const PAN_Y = 1 << 3;
1203 /// `manipulation` variant
1204 const MANIPULATION = 1 << 4;
1210 /// Get default `touch-action` as `auto`
1211 pub fn auto() -> TouchAction {
1216 impl ToCss for TouchAction {
1217 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
1222 TouchAction::NONE => dest.write_str("none"),
1223 TouchAction::AUTO => dest.write_str("auto"),
1224 TouchAction::MANIPULATION => dest.write_str("manipulation"),
1225 _ if self.contains(TouchAction::PAN_X | TouchAction::PAN_Y) => {
1226 dest.write_str("pan-x pan-y")
1228 _ if self.contains(TouchAction::PAN_X) => dest.write_str("pan-x"),
1229 _ if self.contains(TouchAction::PAN_Y) => dest.write_str("pan-y"),
1230 _ => panic!("invalid touch-action value"),
1235 impl Parse for TouchAction {
1237 _context: &ParserContext,
1238 input: &mut Parser<'i, 't>,
1239 ) -> Result<TouchAction, ParseError<'i>> {
1240 try_match_ident_ignore_ascii_case! { input,
1241 "auto" => Ok(TouchAction::AUTO),
1242 "none" => Ok(TouchAction::NONE),
1243 "manipulation" => Ok(TouchAction::MANIPULATION),
1245 if input.try_parse(|i| i.expect_ident_matching("pan-y")).is_ok() {
1246 Ok(TouchAction::PAN_X | TouchAction::PAN_Y)
1248 Ok(TouchAction::PAN_X)
1252 if input.try_parse(|i| i.expect_ident_matching("pan-x")).is_ok() {
1253 Ok(TouchAction::PAN_X | TouchAction::PAN_Y)
1255 Ok(TouchAction::PAN_Y)
1263 #[derive(MallocSizeOf, SpecifiedValueInfo, ToComputedValue, ToResolvedValue, ToShmem)]
1264 #[value_info(other_values = "none,strict,content,size,layout,paint")]
1266 /// Constants for contain: https://drafts.csswg.org/css-contain/#contain-property
1267 pub struct Contain: u8 {
1268 /// `none` variant, just for convenience.
1270 /// 'size' variant, turns on size containment
1271 const SIZE = 1 << 0;
1272 /// `layout` variant, turns on layout containment
1273 const LAYOUT = 1 << 1;
1274 /// `paint` variant, turns on paint containment
1275 const PAINT = 1 << 2;
1276 /// `strict` variant, turns on all types of containment
1277 const STRICT = 1 << 3;
1278 /// 'content' variant, turns on layout and paint containment
1279 const CONTENT = 1 << 4;
1280 /// variant with all the bits that contain: strict turns on
1281 const STRICT_BITS = Contain::LAYOUT.bits | Contain::PAINT.bits | Contain::SIZE.bits;
1282 /// variant with all the bits that contain: content turns on
1283 const CONTENT_BITS = Contain::LAYOUT.bits | Contain::PAINT.bits;
1287 impl ToCss for Contain {
1288 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
1292 if self.is_empty() {
1293 return dest.write_str("none");
1295 if self.contains(Contain::STRICT) {
1296 return dest.write_str("strict");
1298 if self.contains(Contain::CONTENT) {
1299 return dest.write_str("content");
1302 let mut has_any = false;
1303 macro_rules! maybe_write_value {
1304 ($ident:path => $str:expr) => {
1305 if self.contains($ident) {
1307 dest.write_str(" ")?;
1310 dest.write_str($str)?;
1314 maybe_write_value!(Contain::SIZE => "size");
1315 maybe_write_value!(Contain::LAYOUT => "layout");
1316 maybe_write_value!(Contain::PAINT => "paint");
1318 debug_assert!(has_any);
1323 impl Parse for Contain {
1324 /// none | strict | content | [ size || layout || paint ]
1326 _context: &ParserContext,
1327 input: &mut Parser<'i, 't>,
1328 ) -> Result<Contain, ParseError<'i>> {
1329 let mut result = Contain::empty();
1330 while let Ok(name) = input.try_parse(|i| i.expect_ident_cloned()) {
1331 let flag = match_ignore_ascii_case! { &name,
1332 "size" => Some(Contain::SIZE),
1333 "layout" => Some(Contain::LAYOUT),
1334 "paint" => Some(Contain::PAINT),
1335 "strict" if result.is_empty() => return Ok(Contain::STRICT | Contain::STRICT_BITS),
1336 "content" if result.is_empty() => return Ok(Contain::CONTENT | Contain::CONTENT_BITS),
1337 "none" if result.is_empty() => return Ok(result),
1341 let flag = match flag {
1342 Some(flag) if !result.contains(flag) => flag,
1345 input.new_custom_error(SelectorParseErrorKind::UnexpectedIdent(name))
1349 result.insert(flag);
1352 if !result.is_empty() {
1355 Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
1360 /// A specified value for the `perspective` property.
1361 pub type Perspective = GenericPerspective<NonNegativeLength>;
1363 /// A given transition property, that is either `All`, a longhand or shorthand
1364 /// property, or an unsupported or custom property.
1366 Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem,
1368 pub enum TransitionProperty {
1370 Shorthand(ShorthandId),
1371 /// A longhand transitionable property.
1372 Longhand(LonghandId),
1373 /// A custom property.
1374 Custom(CustomPropertyName),
1375 /// Unrecognized property which could be any non-transitionable, custom property, or
1376 /// unknown property.
1377 Unsupported(CustomIdent),
1380 impl ToCss for TransitionProperty {
1381 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
1385 use crate::values::serialize_atom_name;
1387 TransitionProperty::Shorthand(ref s) => s.to_css(dest),
1388 TransitionProperty::Longhand(ref l) => l.to_css(dest),
1389 TransitionProperty::Custom(ref name) => {
1390 dest.write_str("--")?;
1391 serialize_atom_name(name, dest)
1393 TransitionProperty::Unsupported(ref i) => i.to_css(dest),
1398 impl Parse for TransitionProperty {
1400 context: &ParserContext,
1401 input: &mut Parser<'i, 't>,
1402 ) -> Result<Self, ParseError<'i>> {
1403 let location = input.current_source_location();
1404 let ident = input.expect_ident()?;
1406 let id = match PropertyId::parse_ignoring_rule_type(&ident, context) {
1409 return Ok(TransitionProperty::Unsupported(CustomIdent::from_ident(
1417 Ok(match id.as_shorthand() {
1418 Ok(s) => TransitionProperty::Shorthand(s),
1419 Err(longhand_or_custom) => match longhand_or_custom {
1420 PropertyDeclarationId::Longhand(id) => TransitionProperty::Longhand(id),
1421 PropertyDeclarationId::Custom(custom) => TransitionProperty::Custom(custom.clone()),
1427 impl SpecifiedValueInfo for TransitionProperty {
1428 fn collect_completion_keywords(f: KeywordsCollectFn) {
1429 // `transition-property` can actually accept all properties and
1430 // arbitrary identifiers, but `all` is a special one we'd like
1436 impl TransitionProperty {
1439 pub fn all() -> Self {
1440 TransitionProperty::Shorthand(ShorthandId::All)
1443 /// Convert TransitionProperty to nsCSSPropertyID.
1444 #[cfg(feature = "gecko")]
1445 pub fn to_nscsspropertyid(
1447 ) -> Result<crate::gecko_bindings::structs::nsCSSPropertyID, ()> {
1449 TransitionProperty::Shorthand(ShorthandId::All) => {
1450 crate::gecko_bindings::structs::nsCSSPropertyID::eCSSPropertyExtra_all_properties
1452 TransitionProperty::Shorthand(ref id) => id.to_nscsspropertyid(),
1453 TransitionProperty::Longhand(ref id) => id.to_nscsspropertyid(),
1454 TransitionProperty::Custom(..) | TransitionProperty::Unsupported(..) => return Err(()),
1459 #[allow(missing_docs)]
1460 #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
1462 Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss, ToShmem,
1464 /// https://drafts.csswg.org/css-box/#propdef-float
1469 // https://drafts.csswg.org/css-logical-props/#float-clear
1474 #[allow(missing_docs)]
1475 #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
1477 Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss, ToShmem,
1479 /// https://drafts.csswg.org/css-box/#propdef-clear
1485 // https://drafts.csswg.org/css-logical-props/#float-clear
1490 /// https://drafts.csswg.org/css-ui/#propdef-resize
1491 #[allow(missing_docs)]
1492 #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
1494 Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss, ToShmem,
1501 // https://drafts.csswg.org/css-logical-1/#resize
1506 /// The value for the `appearance` property.
1508 /// https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-appearance
1509 #[allow(missing_docs)]
1526 pub enum Appearance {
1527 /// No appearance at all.
1529 /// Default appearance for the element.
1531 /// This value doesn't make sense for -moz-default-appearance, but we don't bother to guard
1532 /// against parsing it.
1534 /// A typical dialog button.
1536 /// Various arrows that go in buttons
1537 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1539 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1541 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1542 ButtonArrowPrevious,
1543 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1545 /// The focus outline box inside of a button.
1546 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1548 /// A dual toolbar button (e.g., a Back button with a dropdown)
1549 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1552 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1556 /// Menu Bar background
1557 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1559 /// <menu> and <menuitem> appearances
1560 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1562 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1564 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1566 /// For text on non-iconic menuitems only
1567 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1569 /// A dropdown list.
1571 /// The dropdown button(s) that open up a dropdown list.
1573 /// The text part of a dropdown list, to left of button.
1574 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1576 /// Menu Popup background.
1577 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1579 /// menu checkbox/radio appearances
1580 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1582 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1584 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1586 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1588 /// An image in the menu gutter, like in bookmarks or history.
1589 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1591 /// A horizontal meter bar.
1592 #[parse(aliases = "meterbar")]
1594 /// The meter bar's meter indicator.
1595 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1597 /// The "arrowed" part of the dropdown button that open up a dropdown list.
1598 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1599 MozMenulistArrowButton,
1600 /// For HTML's <input type=number>
1602 /// A horizontal progress bar.
1603 #[parse(aliases = "progressbar")]
1605 /// The progress bar's progress indicator
1606 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1608 /// A checkbox element.
1610 /// A radio element within a radio group.
1612 /// A generic container that always repaints on state changes. This is a
1613 /// hack to make XUL checkboxes and radio buttons work.
1614 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1616 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1618 /// The label part of a checkbox or radio button, used for painting a focus
1620 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1622 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1624 /// nsRangeFrame and its subparts
1626 RangeThumb, // FIXME: This should not be exposed to content.
1627 /// The resizer background area in a status bar for the resizer widget in
1628 /// the corner of a window.
1629 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1631 /// The resizer itself.
1632 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1635 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1637 /// A small scrollbar.
1638 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1640 /// The scrollbar slider
1641 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1642 ScrollbarHorizontal,
1643 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1645 /// A scrollbar button (up/down/left/right).
1646 /// Keep these in order (some code casts these values to `int` in order to
1647 /// compare them against each other).
1648 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1650 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1651 ScrollbarbuttonDown,
1652 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1653 ScrollbarbuttonLeft,
1654 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1655 ScrollbarbuttonRight,
1656 /// The scrollbar thumb.
1657 ScrollbarthumbHorizontal,
1658 ScrollbarthumbVertical,
1659 /// The scrollbar track.
1660 ScrollbartrackHorizontal,
1661 ScrollbartrackVertical,
1662 /// The scroll corner
1663 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1667 /// A separator. Can be horizontal or vertical.
1668 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1670 /// A spin control (up/down control for time/date pickers).
1671 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1673 /// The up button of a spin control.
1674 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1676 /// The down button of a spin control.
1677 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1679 /// The textfield of a spin control
1680 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1682 /// A splitter. Can be horizontal or vertical.
1683 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1685 /// A status bar in a main application window.
1686 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1688 /// A single pane of a status bar.
1689 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1691 /// A single tab in a tab widget.
1692 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1694 /// A single pane (inside the tabpanels container).
1695 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1697 /// The tab panels container.
1698 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1700 /// The tabs scroll arrows (left/right).
1701 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1703 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1704 TabScrollArrowForward,
1705 /// A multi-line text field, e.g. HTML <textarea>.
1706 #[parse(aliases = "textfield-multiline")]
1708 /// A single-line text field, e.g. HTML <input type=text>.
1710 /// A toolbar in an application window.
1711 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1713 /// A single toolbar button (with no associated dropdown).
1714 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1716 /// The dropdown portion of a toolbar button
1717 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1718 ToolbarbuttonDropdown,
1719 /// The gripper for a toolbar.
1720 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1722 /// The toolbox that contains the toolbars.
1723 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1726 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1728 /// A listbox or tree widget header
1729 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1731 /// An individual header cell
1732 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1734 /// The sort arrow for a header.
1735 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1736 Treeheadersortarrow,
1738 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1740 /// A tree widget branch line
1741 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1743 /// A tree widget twisty.
1744 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1746 /// Open tree widget twisty.
1747 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1750 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1752 /// Window and dialog backgrounds.
1753 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1755 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1759 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1760 MozWinCommunicationsToolbox,
1761 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1763 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1764 MozWinBrowsertabbarToolbox,
1766 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1768 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1769 MozWinBorderlessGlass,
1770 /// -moz-apperance style used in setting proper glass margins.
1771 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1774 /// Titlebar elements on the Mac.
1775 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1776 MozMacFullscreenButton,
1777 /// Mac help button.
1778 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1781 /// Windows themed window frame elements.
1782 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1784 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1785 MozWindowButtonBoxMaximized,
1786 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1787 MozWindowButtonClose,
1788 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1789 MozWindowButtonMaximize,
1790 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1791 MozWindowButtonMinimize,
1792 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1793 MozWindowButtonRestore,
1794 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1795 MozWindowFrameBottom,
1796 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1798 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1799 MozWindowFrameRight,
1800 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1802 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1803 MozWindowTitlebarMaximized,
1805 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1807 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1808 MozMacActiveSourceListSelection,
1809 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1810 MozMacDisclosureButtonClosed,
1811 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1812 MozMacDisclosureButtonOpen,
1813 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1815 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1816 MozMacSourceListSelection,
1817 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1819 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1820 MozMacVibrancyLight,
1821 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1822 MozMacVibrantTitlebarDark,
1823 #[parse(condition = "ParserContext::in_ua_or_chrome_sheet")]
1824 MozMacVibrantTitlebarLight,
1826 /// A non-disappearing scrollbar.
1828 ScrollbarNonDisappearing,
1830 /// A themed focus outline (for outline:auto).
1832 /// This isn't exposed to CSS at all, just here for convenience.
1836 /// A dummy variant that should be last to let the GTK widget do hackery.
1841 /// A kind of break between two boxes.
1843 /// https://drafts.csswg.org/css-break/#break-between
1844 #[allow(missing_docs)]
1861 pub enum BreakBetween {
1871 /// Parse a legacy break-between value for `page-break-*`.
1873 /// See https://drafts.csswg.org/css-break/#page-break-properties.
1875 pub fn parse_legacy<'i>(input: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
1876 let location = input.current_source_location();
1877 let ident = input.expect_ident()?;
1878 let break_value = match BreakBetween::from_ident(ident) {
1882 .new_custom_error(SelectorParseErrorKind::UnexpectedIdent(ident.clone())));
1886 BreakBetween::Always => Ok(BreakBetween::Page),
1887 BreakBetween::Auto | BreakBetween::Avoid | BreakBetween::Left | BreakBetween::Right => {
1890 BreakBetween::Page => {
1892 .new_custom_error(SelectorParseErrorKind::UnexpectedIdent(ident.clone())))
1897 /// Serialize a legacy break-between value for `page-break-*`.
1899 /// See https://drafts.csswg.org/css-break/#page-break-properties.
1900 pub fn to_css_legacy<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
1905 BreakBetween::Auto | BreakBetween::Avoid | BreakBetween::Left | BreakBetween::Right => {
1908 BreakBetween::Page => dest.write_str("always"),
1909 BreakBetween::Always => Ok(()),
1914 /// A kind of break within a box.
1916 /// https://drafts.csswg.org/css-break/#break-within
1917 #[allow(missing_docs)]
1934 pub enum BreakWithin {
1939 /// The value for the `overflow-x` / `overflow-y` properties.
1940 #[allow(missing_docs)]
1962 #[cfg(feature = "gecko")]
1963 MozHiddenUnscrollable,