mirror of
https://github.com/servo/servo.git
synced 2025-08-09 15:35:34 +01:00
style: Implement multi-keyword 'display' values for Gecko.
Differential Revision: https://phabricator.services.mozilla.com/D39764
This commit is contained in:
parent
cf7b0e13b6
commit
a9814ccb82
1 changed files with 567 additions and 107 deletions
|
@ -16,6 +16,7 @@ use crate::values::specified::{AllowQuirks, Number};
|
||||||
use crate::values::{CustomIdent, KeyframesName};
|
use crate::values::{CustomIdent, KeyframesName};
|
||||||
use crate::Atom;
|
use crate::Atom;
|
||||||
use cssparser::Parser;
|
use cssparser::Parser;
|
||||||
|
use num_traits::FromPrimitive;
|
||||||
use selectors::parser::SelectorParseErrorKind;
|
use selectors::parser::SelectorParseErrorKind;
|
||||||
use std::fmt::{self, Write};
|
use std::fmt::{self, Write};
|
||||||
use style_traits::{CssWriter, KeywordsCollectFn, ParseError};
|
use style_traits::{CssWriter, KeywordsCollectFn, ParseError};
|
||||||
|
@ -33,7 +34,7 @@ fn moz_box_display_values_enabled(context: &ParserContext) -> bool {
|
||||||
static_prefs::pref!("layout.css.xul-box-display-values.content.enabled")
|
static_prefs::pref!("layout.css.xul-box-display-values.content.enabled")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "gecko", feature = "servo-layout-2013"))]
|
#[cfg(feature = "servo-layout-2013")]
|
||||||
fn parse_unimplemented_in_servo_2020(_context: &ParserContext) -> bool {
|
fn parse_unimplemented_in_servo_2020(_context: &ParserContext) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -49,13 +50,82 @@ fn parse_unimplemented_in_servo_2020(_context: &ParserContext) -> bool {
|
||||||
/// Defines an element’s display type, which consists of
|
/// Defines an element’s display type, which consists of
|
||||||
/// the two basic qualities of how an element generates boxes
|
/// the two basic qualities of how an element generates boxes
|
||||||
/// <https://drafts.csswg.org/css-display/#propdef-display>
|
/// <https://drafts.csswg.org/css-display/#propdef-display>
|
||||||
///
|
#[allow(missing_docs)]
|
||||||
///
|
#[derive(
|
||||||
/// NOTE(emilio): Order is important in Gecko!
|
MallocSizeOf,
|
||||||
///
|
ToShmem,
|
||||||
/// If you change it, make sure to take a look at the
|
Clone,
|
||||||
/// FrameConstructionDataByDisplay stuff (both the XUL and non-XUL version), and
|
Copy,
|
||||||
/// ensure it's still correct!
|
Debug,
|
||||||
|
Eq,
|
||||||
|
FromPrimitive,
|
||||||
|
Hash,
|
||||||
|
PartialEq,
|
||||||
|
ToCss,
|
||||||
|
)]
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum DisplayOutside {
|
||||||
|
None = 0,
|
||||||
|
Inline,
|
||||||
|
Block,
|
||||||
|
TableCaption,
|
||||||
|
InternalTable,
|
||||||
|
InternalRuby,
|
||||||
|
XUL,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
#[derive(
|
||||||
|
MallocSizeOf,
|
||||||
|
ToShmem,
|
||||||
|
Clone,
|
||||||
|
Copy,
|
||||||
|
Debug,
|
||||||
|
Eq,
|
||||||
|
FromPrimitive,
|
||||||
|
Hash,
|
||||||
|
PartialEq,
|
||||||
|
ToCss,
|
||||||
|
)]
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum DisplayInside {
|
||||||
|
None = 0,
|
||||||
|
Contents,
|
||||||
|
Block,
|
||||||
|
FlowRoot,
|
||||||
|
Inline,
|
||||||
|
Flex,
|
||||||
|
Grid,
|
||||||
|
Table,
|
||||||
|
TableRowGroup,
|
||||||
|
TableColumn,
|
||||||
|
TableColumnGroup,
|
||||||
|
TableHeaderGroup,
|
||||||
|
TableFooterGroup,
|
||||||
|
TableRow,
|
||||||
|
TableCell,
|
||||||
|
Ruby,
|
||||||
|
RubyBase,
|
||||||
|
RubyBaseContainer,
|
||||||
|
RubyText,
|
||||||
|
RubyTextContainer,
|
||||||
|
WebkitBox,
|
||||||
|
MozBox,
|
||||||
|
MozInlineBox,
|
||||||
|
MozGrid,
|
||||||
|
MozInlineGrid,
|
||||||
|
MozGridGroup,
|
||||||
|
MozGridLine,
|
||||||
|
MozStack,
|
||||||
|
MozInlineStack,
|
||||||
|
MozDeck,
|
||||||
|
MozGroupbox,
|
||||||
|
MozPopup,
|
||||||
|
Flow, // only used for parsing, not computed value
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
#[derive(
|
#[derive(
|
||||||
Clone,
|
Clone,
|
||||||
|
@ -65,107 +135,209 @@ fn parse_unimplemented_in_servo_2020(_context: &ParserContext) -> bool {
|
||||||
FromPrimitive,
|
FromPrimitive,
|
||||||
Hash,
|
Hash,
|
||||||
MallocSizeOf,
|
MallocSizeOf,
|
||||||
|
PartialEq,
|
||||||
|
ToComputedValue,
|
||||||
|
ToResolvedValue,
|
||||||
|
ToShmem,
|
||||||
|
)]
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct Display(u16);
|
||||||
|
|
||||||
|
/// Gecko-only impl block for Display (shared stuff later in this file):
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
impl Display {
|
||||||
|
// Our u16 bits are used as follows: LOOOOOOOIIIIIIII
|
||||||
|
const LIST_ITEM_BIT : u16 = 0x8000; //^
|
||||||
|
const DISPLAY_OUTSIDE_BITS : u16 = 7; // ^^^^^^^
|
||||||
|
const DISPLAY_INSIDE_BITS : u16 = 8; // ^^^^^^^^
|
||||||
|
|
||||||
|
/// https://drafts.csswg.org/css-display/#the-display-properties
|
||||||
|
pub const None : Self = Self::new(DisplayOutside::None, DisplayInside::None);
|
||||||
|
pub const Contents : Self = Self::new(DisplayOutside::None, DisplayInside::Contents);
|
||||||
|
pub const Inline : Self = Self::new(DisplayOutside::Inline, DisplayInside::Inline);
|
||||||
|
pub const InlineBlock : Self = Self::new(DisplayOutside::Inline, DisplayInside::FlowRoot);
|
||||||
|
pub const Block : Self = Self::new(DisplayOutside::Block, DisplayInside::Block);
|
||||||
|
pub const FlowRoot : Self = Self::new(DisplayOutside::Block, DisplayInside::FlowRoot);
|
||||||
|
pub const Flex : Self = Self::new(DisplayOutside::Block, DisplayInside::Flex);
|
||||||
|
pub const InlineFlex : Self = Self::new(DisplayOutside::Inline, DisplayInside::Flex);
|
||||||
|
pub const Grid : Self = Self::new(DisplayOutside::Block, DisplayInside::Grid);
|
||||||
|
pub const InlineGrid : Self = Self::new(DisplayOutside::Inline, DisplayInside::Grid);
|
||||||
|
pub const Table : Self = Self::new(DisplayOutside::Block, DisplayInside::Table);
|
||||||
|
pub const InlineTable : Self = Self::new(DisplayOutside::Inline, DisplayInside::Table);
|
||||||
|
pub const TableCaption : Self = Self::new(DisplayOutside::TableCaption, DisplayInside::Block);
|
||||||
|
pub const Ruby : Self = Self::new(DisplayOutside::Inline, DisplayInside::Ruby);
|
||||||
|
pub const WebkitBox : Self = Self::new(DisplayOutside::Block, DisplayInside::WebkitBox);
|
||||||
|
pub const WebkitInlineBox : Self = Self::new(DisplayOutside::Inline, DisplayInside::WebkitBox);
|
||||||
|
pub const ListItem : Self = Self::new_list_item(DisplayOutside::Block, DisplayInside::Block);
|
||||||
|
|
||||||
|
/// Internal table boxes.
|
||||||
|
pub const TableRowGroup : Self = Self::new(DisplayOutside::InternalTable, DisplayInside::TableRowGroup);
|
||||||
|
pub const TableHeaderGroup : Self = Self::new(DisplayOutside::InternalTable, DisplayInside::TableHeaderGroup);
|
||||||
|
pub const TableFooterGroup : Self = Self::new(DisplayOutside::InternalTable, DisplayInside::TableFooterGroup);
|
||||||
|
pub const TableColumn : Self = Self::new(DisplayOutside::InternalTable, DisplayInside::TableColumn);
|
||||||
|
pub const TableColumnGroup : Self = Self::new(DisplayOutside::InternalTable, DisplayInside::TableColumnGroup);
|
||||||
|
pub const TableRow : Self = Self::new(DisplayOutside::InternalTable, DisplayInside::TableRow);
|
||||||
|
pub const TableCell : Self = Self::new(DisplayOutside::InternalTable, DisplayInside::TableCell);
|
||||||
|
|
||||||
|
/// Internal ruby boxes.
|
||||||
|
pub const RubyBase : Self = Self::new(DisplayOutside::InternalRuby, DisplayInside::RubyBase);
|
||||||
|
pub const RubyBaseContainer : Self = Self::new(DisplayOutside::InternalRuby, DisplayInside::RubyBaseContainer);
|
||||||
|
pub const RubyText : Self = Self::new(DisplayOutside::InternalRuby, DisplayInside::RubyText);
|
||||||
|
pub const RubyTextContainer : Self = Self::new(DisplayOutside::InternalRuby, DisplayInside::RubyTextContainer);
|
||||||
|
|
||||||
|
/// XUL boxes.
|
||||||
|
pub const MozBox : Self = Self::new(DisplayOutside::XUL, DisplayInside::MozBox);
|
||||||
|
pub const MozInlineBox : Self = Self::new(DisplayOutside::XUL, DisplayInside::MozInlineBox);
|
||||||
|
pub const MozGrid : Self = Self::new(DisplayOutside::XUL, DisplayInside::MozGrid);
|
||||||
|
pub const MozInlineGrid : Self = Self::new(DisplayOutside::XUL, DisplayInside::MozInlineGrid);
|
||||||
|
pub const MozGridGroup : Self = Self::new(DisplayOutside::XUL, DisplayInside::MozGridGroup);
|
||||||
|
pub const MozGridLine : Self = Self::new(DisplayOutside::XUL, DisplayInside::MozGridLine);
|
||||||
|
pub const MozStack : Self = Self::new(DisplayOutside::XUL, DisplayInside::MozStack);
|
||||||
|
pub const MozInlineStack : Self = Self::new(DisplayOutside::XUL, DisplayInside::MozInlineStack);
|
||||||
|
pub const MozDeck : Self = Self::new(DisplayOutside::XUL, DisplayInside::MozDeck);
|
||||||
|
pub const MozGroupbox : Self = Self::new(DisplayOutside::XUL, DisplayInside::MozGroupbox);
|
||||||
|
pub const MozPopup : Self = Self::new(DisplayOutside::XUL, DisplayInside::MozPopup);
|
||||||
|
|
||||||
|
/// Make a raw display value from <display-outside> and <display-inside> values.
|
||||||
|
#[inline]
|
||||||
|
const fn new(outside:DisplayOutside, inside:DisplayInside) -> Self {
|
||||||
|
let o : u16 = ((outside as u8) as u16) << Self::DISPLAY_INSIDE_BITS;
|
||||||
|
let i : u16 = (inside as u8) as u16;
|
||||||
|
Self(o | i)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Make a list-item display value from <display-outside> and <display-inside>.
|
||||||
|
#[inline]
|
||||||
|
const fn new_list_item(outside:DisplayOutside, inside:DisplayInside) -> Self {
|
||||||
|
let v = Self::new(outside, inside);
|
||||||
|
Self(v.0 | Self::LIST_ITEM_BIT)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Make a display enum value from <display-outside> and <display-inside> values.
|
||||||
|
/// We store `flow` as a synthetic `block` or `inline` inside-value to simplify
|
||||||
|
/// our layout code.
|
||||||
|
#[inline]
|
||||||
|
fn from3(outside:DisplayOutside, inside:DisplayInside, list_item:bool) -> Self {
|
||||||
|
let inside = match inside {
|
||||||
|
DisplayInside::Flow => match outside {
|
||||||
|
DisplayOutside::Inline => DisplayInside::Inline,
|
||||||
|
_ => DisplayInside::Block,
|
||||||
|
},
|
||||||
|
_ => inside,
|
||||||
|
};
|
||||||
|
let v = Self::new(outside, inside);
|
||||||
|
if !list_item {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
Self(v.0 | Self::LIST_ITEM_BIT)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Accessor for the <display-inside> value.
|
||||||
|
#[inline]
|
||||||
|
pub fn inside(&self) -> DisplayInside {
|
||||||
|
DisplayInside::from_u16(self.0 & ((1 << Self::DISPLAY_INSIDE_BITS) - 1)).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Accessor for the <display-outside> value.
|
||||||
|
#[inline]
|
||||||
|
pub fn outside(&self) -> DisplayOutside {
|
||||||
|
DisplayOutside::from_u16(
|
||||||
|
(self.0 >> Self::DISPLAY_INSIDE_BITS) & ((1 << Self::DISPLAY_OUTSIDE_BITS) - 1)
|
||||||
|
).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns whether this `display` value is some kind of list-item.
|
||||||
|
#[inline]
|
||||||
|
pub const fn is_list_item(&self) -> bool {
|
||||||
|
(self.0 & Self::LIST_ITEM_BIT) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns whether this `display` value is a ruby level container.
|
||||||
|
pub fn is_ruby_level_container(&self) -> bool {
|
||||||
|
matches!(
|
||||||
|
*self,
|
||||||
|
Display::RubyBaseContainer | Display::RubyTextContainer
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns whether this `display` value is one of the types for ruby.
|
||||||
|
pub fn is_ruby_type(&self) -> bool {
|
||||||
|
matches!(
|
||||||
|
*self,
|
||||||
|
Display::Ruby |
|
||||||
|
Display::RubyBase |
|
||||||
|
Display::RubyText |
|
||||||
|
Display::RubyBaseContainer |
|
||||||
|
Display::RubyTextContainer
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Servo version of Display only contains single-keyword values, and isn't
|
||||||
|
/// using outside/inside values at all.
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
#[derive(
|
||||||
|
Clone,
|
||||||
|
Copy,
|
||||||
|
Debug,
|
||||||
|
Deserialize,
|
||||||
|
Eq,
|
||||||
|
FromPrimitive,
|
||||||
|
Hash,
|
||||||
|
MallocSizeOf,
|
||||||
Parse,
|
Parse,
|
||||||
PartialEq,
|
PartialEq,
|
||||||
|
Serialize,
|
||||||
SpecifiedValueInfo,
|
SpecifiedValueInfo,
|
||||||
ToComputedValue,
|
ToComputedValue,
|
||||||
ToCss,
|
ToCss,
|
||||||
ToResolvedValue,
|
ToResolvedValue,
|
||||||
ToShmem,
|
ToShmem,
|
||||||
)]
|
)]
|
||||||
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
|
#[cfg(not(feature = "gecko"))]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
pub enum Display {
|
pub enum Display {
|
||||||
None = 0,
|
None = 0,
|
||||||
Block,
|
Block,
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
FlowRoot,
|
|
||||||
Inline,
|
Inline,
|
||||||
#[parse(condition = "parse_unimplemented_in_servo_2020")]
|
#[parse(condition = "parse_unimplemented_in_servo_2020")]
|
||||||
InlineBlock,
|
InlineBlock,
|
||||||
#[cfg(any(feature = "gecko", feature = "servo-layout-2013"))]
|
#[cfg(feature = "servo-layout-2013")]
|
||||||
ListItem,
|
ListItem,
|
||||||
#[cfg(any(feature = "gecko", feature = "servo-layout-2013"))]
|
#[cfg(feature = "servo-layout-2013")]
|
||||||
Table,
|
Table,
|
||||||
#[cfg(any(feature = "gecko", feature = "servo-layout-2013"))]
|
#[cfg(feature = "servo-layout-2013")]
|
||||||
InlineTable,
|
InlineTable,
|
||||||
#[cfg(any(feature = "gecko", feature = "servo-layout-2013"))]
|
#[cfg(feature = "servo-layout-2013")]
|
||||||
TableRowGroup,
|
TableRowGroup,
|
||||||
#[cfg(any(feature = "gecko", feature = "servo-layout-2013"))]
|
#[cfg(feature = "servo-layout-2013")]
|
||||||
TableColumn,
|
TableColumn,
|
||||||
#[cfg(any(feature = "gecko", feature = "servo-layout-2013"))]
|
#[cfg(feature = "servo-layout-2013")]
|
||||||
TableColumnGroup,
|
TableColumnGroup,
|
||||||
#[cfg(any(feature = "gecko", feature = "servo-layout-2013"))]
|
#[cfg(feature = "servo-layout-2013")]
|
||||||
TableHeaderGroup,
|
TableHeaderGroup,
|
||||||
#[cfg(any(feature = "gecko", feature = "servo-layout-2013"))]
|
#[cfg(feature = "servo-layout-2013")]
|
||||||
TableFooterGroup,
|
TableFooterGroup,
|
||||||
#[cfg(any(feature = "gecko", feature = "servo-layout-2013"))]
|
#[cfg(feature = "servo-layout-2013")]
|
||||||
TableRow,
|
TableRow,
|
||||||
#[cfg(any(feature = "gecko", feature = "servo-layout-2013"))]
|
#[cfg(feature = "servo-layout-2013")]
|
||||||
TableCell,
|
TableCell,
|
||||||
#[cfg(any(feature = "gecko", feature = "servo-layout-2013"))]
|
#[cfg(feature = "servo-layout-2013")]
|
||||||
TableCaption,
|
TableCaption,
|
||||||
#[cfg(any(feature = "gecko", feature = "servo-layout-2013"))]
|
#[cfg(feature = "servo-layout-2013")]
|
||||||
#[parse(aliases = "-webkit-flex")]
|
#[parse(aliases = "-webkit-flex")]
|
||||||
Flex,
|
Flex,
|
||||||
#[cfg(any(feature = "gecko", feature = "servo-layout-2013"))]
|
#[cfg(feature = "servo-layout-2013")]
|
||||||
#[parse(aliases = "-webkit-inline-flex")]
|
#[parse(aliases = "-webkit-inline-flex")]
|
||||||
InlineFlex,
|
InlineFlex,
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
Grid,
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
InlineGrid,
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
Ruby,
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
RubyBase,
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
RubyBaseContainer,
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
RubyText,
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
RubyTextContainer,
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
Contents,
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
WebkitBox,
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
WebkitInlineBox,
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
#[parse(condition = "moz_box_display_values_enabled")]
|
|
||||||
MozBox,
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
#[parse(condition = "moz_box_display_values_enabled")]
|
|
||||||
MozInlineBox,
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
#[parse(condition = "moz_display_values_enabled")]
|
|
||||||
MozGrid,
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
#[parse(condition = "moz_display_values_enabled")]
|
|
||||||
MozInlineGrid,
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
#[parse(condition = "moz_display_values_enabled")]
|
|
||||||
MozGridGroup,
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
#[parse(condition = "moz_display_values_enabled")]
|
|
||||||
MozGridLine,
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
#[parse(condition = "moz_display_values_enabled")]
|
|
||||||
MozStack,
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
#[parse(condition = "moz_display_values_enabled")]
|
|
||||||
MozInlineStack,
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
#[parse(condition = "moz_display_values_enabled")]
|
|
||||||
MozDeck,
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
#[parse(condition = "moz_display_values_enabled")]
|
|
||||||
MozGroupbox,
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
#[parse(condition = "moz_display_values_enabled")]
|
|
||||||
MozPopup,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Shared Display impl for both Gecko and Servo.
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
impl Display {
|
impl Display {
|
||||||
/// The initial display value.
|
/// The initial display value.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -185,17 +357,25 @@ impl Display {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether this "display" value is the display of a flex or
|
/// Returns whether this `display` value is the display of a flex or
|
||||||
/// grid container.
|
/// grid container.
|
||||||
///
|
///
|
||||||
/// This is used to implement various style fixups.
|
/// This is used to implement various style fixups.
|
||||||
pub fn is_item_container(&self) -> bool {
|
pub fn is_item_container(&self) -> bool {
|
||||||
match *self {
|
#[cfg(feature = "gecko")]
|
||||||
#[cfg(any(feature = "gecko", feature = "servo-layout-2013"))]
|
{
|
||||||
Display::Flex | Display::InlineFlex => true,
|
match self.inside() {
|
||||||
#[cfg(feature = "gecko")]
|
DisplayInside::Flex | DisplayInside::Grid => true,
|
||||||
Display::Grid | Display::InlineGrid => true,
|
_ => false,
|
||||||
_ => false,
|
}
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "gecko"))]
|
||||||
|
{
|
||||||
|
match *self {
|
||||||
|
#[cfg(feature = "servo-layout-2013")]
|
||||||
|
Display::Flex | Display::InlineFlex => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,29 +391,6 @@ impl Display {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether this "display" value is one of the types for
|
|
||||||
/// ruby.
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
pub fn is_ruby_type(&self) -> bool {
|
|
||||||
matches!(
|
|
||||||
*self,
|
|
||||||
Display::Ruby |
|
|
||||||
Display::RubyBase |
|
|
||||||
Display::RubyText |
|
|
||||||
Display::RubyBaseContainer |
|
|
||||||
Display::RubyTextContainer
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns whether this "display" value is a ruby level container.
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
pub fn is_ruby_level_container(&self) -> bool {
|
|
||||||
matches!(
|
|
||||||
*self,
|
|
||||||
Display::RubyBaseContainer | Display::RubyTextContainer
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Convert this display into an equivalent block display.
|
/// Convert this display into an equivalent block display.
|
||||||
///
|
///
|
||||||
/// Also used for style adjustments.
|
/// Also used for style adjustments.
|
||||||
|
@ -305,6 +462,309 @@ impl Display {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
impl ToCss for Display {
|
||||||
|
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
|
||||||
|
where
|
||||||
|
W: fmt::Write,
|
||||||
|
{
|
||||||
|
debug_assert_ne!(self.inside(), DisplayInside::Flow,
|
||||||
|
"`flow` never appears in `display` computed value");
|
||||||
|
let outside = self.outside();
|
||||||
|
let inside = match self.inside() {
|
||||||
|
DisplayInside::Block | DisplayInside::Inline => DisplayInside::Flow,
|
||||||
|
inside => inside,
|
||||||
|
};
|
||||||
|
match *self {
|
||||||
|
Display::Block | Display::Inline => outside.to_css(dest),
|
||||||
|
Display::InlineBlock => dest.write_str("inline-block"),
|
||||||
|
Display::WebkitInlineBox => dest.write_str("-webkit-inline-box"),
|
||||||
|
Display::MozInlineBox => dest.write_str("-moz-inline-box"),
|
||||||
|
Display::MozInlineGrid => dest.write_str("-moz-inline-grid"),
|
||||||
|
Display::MozInlineStack => dest.write_str("-moz-inline-stack"),
|
||||||
|
Display::TableCaption => dest.write_str("table-caption"),
|
||||||
|
Display::ListItem => dest.write_str("list-item"),
|
||||||
|
_ => match (outside, inside) {
|
||||||
|
(DisplayOutside::Inline, DisplayInside::Flex) |
|
||||||
|
(DisplayOutside::Inline, DisplayInside::Grid) |
|
||||||
|
(DisplayOutside::Inline, DisplayInside::Table) => {
|
||||||
|
dest.write_str("inline-")?;
|
||||||
|
inside.to_css(dest)
|
||||||
|
}
|
||||||
|
(DisplayOutside::Block, DisplayInside::Ruby) => {
|
||||||
|
dest.write_str("block ruby")
|
||||||
|
}
|
||||||
|
(_, inside) => {
|
||||||
|
if self.is_list_item() {
|
||||||
|
debug_assert_eq!(inside, DisplayInside::FlowRoot);
|
||||||
|
dest.write_str("flow-root list-item")
|
||||||
|
} else {
|
||||||
|
inside.to_css(dest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <display-inside> = flow | flow-root | table | flex | grid | ruby
|
||||||
|
/// https://drafts.csswg.org/css-display/#typedef-display-inside
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
fn parse_display_inside<'i, 't>(
|
||||||
|
input: &mut Parser<'i, 't>,
|
||||||
|
) -> Result<DisplayInside, ParseError<'i>> {
|
||||||
|
Ok(try_match_ident_ignore_ascii_case! { input,
|
||||||
|
"flow" => DisplayInside::Flow,
|
||||||
|
"flow-root" => DisplayInside::FlowRoot,
|
||||||
|
"table" => DisplayInside::Table,
|
||||||
|
"flex" => DisplayInside::Flex,
|
||||||
|
"grid" => DisplayInside::Grid,
|
||||||
|
"ruby" => DisplayInside::Ruby,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// FIXME: this can be replaced with parse_display_inside once we
|
||||||
|
/// support `block ruby`.
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
fn parse_display_inside_for_block<'i, 't>(
|
||||||
|
input: &mut Parser<'i, 't>,
|
||||||
|
) -> Result<DisplayInside, ParseError<'i>> {
|
||||||
|
Ok(try_match_ident_ignore_ascii_case! { input,
|
||||||
|
"flow" => DisplayInside::Flow,
|
||||||
|
"flow-root" => DisplayInside::FlowRoot,
|
||||||
|
"table" => DisplayInside::Table,
|
||||||
|
"flex" => DisplayInside::Flex,
|
||||||
|
"grid" => DisplayInside::Grid,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <display-outside> = block | inline | run-in
|
||||||
|
/// https://drafts.csswg.org/css-display/#typedef-display-outside
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
fn parse_display_outside<'i, 't>(
|
||||||
|
input: &mut Parser<'i, 't>,
|
||||||
|
) -> Result<DisplayOutside, ParseError<'i>> {
|
||||||
|
Ok(try_match_ident_ignore_ascii_case! { input,
|
||||||
|
"block" => DisplayOutside::Block,
|
||||||
|
"inline" => DisplayOutside::Inline,
|
||||||
|
// FIXME: not supported in layout yet:
|
||||||
|
//"run-in" => DisplayOutside::RunIn,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// FIXME: this can be replaced with parse_display_outside once we
|
||||||
|
/// support all its values for list items.
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
fn parse_display_outside_for_list_item<'i, 't>(
|
||||||
|
input: &mut Parser<'i, 't>,
|
||||||
|
) -> Result<DisplayOutside, ParseError<'i>> {
|
||||||
|
Ok(try_match_ident_ignore_ascii_case! { input,
|
||||||
|
"block" => DisplayOutside::Block,
|
||||||
|
// FIXME(bug 1105868): not supported in layout yet:
|
||||||
|
//"inline" => DisplayOutside::Inline,
|
||||||
|
// FIXME(bug 2056): not supported in layout yet:
|
||||||
|
//"run-in" => DisplayOutside::RunIn,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/// Test a <display-outside> Result for same values as above.
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
fn is_valid_outside_for_list_item<'i>(
|
||||||
|
outside: &Result<DisplayOutside, ParseError<'i>>,
|
||||||
|
) -> bool {
|
||||||
|
match outside {
|
||||||
|
Ok(DisplayOutside::Block) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// FIXME: this can be replaced with parse_display_outside once we
|
||||||
|
/// support all its values for `ruby`.
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
fn parse_display_outside_for_ruby<'i, 't>(
|
||||||
|
input: &mut Parser<'i, 't>,
|
||||||
|
) -> Result<DisplayOutside, ParseError<'i>> {
|
||||||
|
Ok(try_match_ident_ignore_ascii_case! { input,
|
||||||
|
"inline" => DisplayOutside::Inline,
|
||||||
|
// FIXME: not supported in layout yet:
|
||||||
|
//"block" => DisplayOutside::Block,
|
||||||
|
//"run-in" => DisplayOutside::RunIn,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// (flow | flow-root)?
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
fn parse_display_inside_for_list_item<'i, 't>(
|
||||||
|
input: &mut Parser<'i, 't>,
|
||||||
|
) -> Result<DisplayInside, ParseError<'i>> {
|
||||||
|
Ok(try_match_ident_ignore_ascii_case! { input,
|
||||||
|
"flow" => DisplayInside::Flow,
|
||||||
|
"flow-root" => DisplayInside::FlowRoot,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/// Test a <display-inside> Result for same values as above.
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
fn is_valid_inside_for_list_item<'i>(
|
||||||
|
inside: &Result<DisplayInside, ParseError<'i>>,
|
||||||
|
) -> bool {
|
||||||
|
matches!(inside, Ok(DisplayInside::Flow) | Ok(DisplayInside::FlowRoot))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse `list-item`.
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
fn parse_list_item<'i, 't>(
|
||||||
|
input: &mut Parser<'i, 't>,
|
||||||
|
) -> Result<(), ParseError<'i>> {
|
||||||
|
Ok(try_match_ident_ignore_ascii_case! { input,
|
||||||
|
"list-item" => (),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
impl Parse for Display {
|
||||||
|
fn parse<'i, 't>(
|
||||||
|
context: &ParserContext,
|
||||||
|
input: &mut Parser<'i, 't>,
|
||||||
|
) -> Result<Display, ParseError<'i>> {
|
||||||
|
// Parse all combinations of <display-inside/outside>? and `list-item`? first.
|
||||||
|
let mut got_list_item = input.try(parse_list_item).is_ok();
|
||||||
|
let mut inside = if got_list_item {
|
||||||
|
input.try(parse_display_inside_for_list_item)
|
||||||
|
} else {
|
||||||
|
input.try(parse_display_inside)
|
||||||
|
};
|
||||||
|
// <display-listitem> = <display-outside>? && [ flow | flow-root ]? && list-item
|
||||||
|
// https://drafts.csswg.org/css-display/#typedef-display-listitem
|
||||||
|
if !got_list_item && is_valid_inside_for_list_item(&inside) {
|
||||||
|
got_list_item = input.try(parse_list_item).is_ok();
|
||||||
|
}
|
||||||
|
let outside = if got_list_item {
|
||||||
|
input.try(parse_display_outside_for_list_item)
|
||||||
|
} else {
|
||||||
|
match inside {
|
||||||
|
Ok(DisplayInside::Ruby) => input.try(parse_display_outside_for_ruby),
|
||||||
|
_ => input.try(parse_display_outside),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if !got_list_item && is_valid_outside_for_list_item(&outside) {
|
||||||
|
got_list_item = input.try(parse_list_item).is_ok();
|
||||||
|
}
|
||||||
|
if outside.is_ok() && inside.is_err(){
|
||||||
|
inside = if got_list_item {
|
||||||
|
input.try(parse_display_inside_for_list_item)
|
||||||
|
} else {
|
||||||
|
match outside {
|
||||||
|
// FIXME we don't handle `block ruby` in layout yet.
|
||||||
|
Ok(DisplayOutside::Block) => input.try(parse_display_inside_for_block),
|
||||||
|
_ => input.try(parse_display_inside),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if !got_list_item &&
|
||||||
|
is_valid_outside_for_list_item(&outside) &&
|
||||||
|
is_valid_inside_for_list_item(&inside) {
|
||||||
|
got_list_item = input.try(parse_list_item).is_ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if got_list_item || inside.is_ok() || outside.is_ok() {
|
||||||
|
let inside = inside.unwrap_or(DisplayInside::Flow);
|
||||||
|
let outside = outside.unwrap_or(
|
||||||
|
match inside {
|
||||||
|
// "If <display-outside> is omitted, the element’s outside display type
|
||||||
|
// defaults to block — except for ruby, which defaults to inline."
|
||||||
|
// https://drafts.csswg.org/css-display/#inside-model
|
||||||
|
DisplayInside::Ruby => DisplayOutside::Inline,
|
||||||
|
_ => DisplayOutside::Block,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return Ok(Display::from3(outside, inside, got_list_item));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now parse the single-keyword `display` values.
|
||||||
|
Ok(try_match_ident_ignore_ascii_case! { input,
|
||||||
|
"none" => Display::None,
|
||||||
|
"contents" => Display::Contents,
|
||||||
|
"inline-block" => Display::InlineBlock,
|
||||||
|
"inline-table" => Display::InlineTable,
|
||||||
|
"inline-flex" => Display::InlineFlex,
|
||||||
|
"-webkit-flex" => Display::Flex,
|
||||||
|
"-webkit-inline-flex" => Display::InlineFlex,
|
||||||
|
"inline-grid" => Display::InlineGrid,
|
||||||
|
"table-caption" => Display::TableCaption,
|
||||||
|
"table-row-group" => Display::TableRowGroup,
|
||||||
|
"table-header-group" => Display::TableHeaderGroup,
|
||||||
|
"table-footer-group" => Display::TableFooterGroup,
|
||||||
|
"table-column" => Display::TableColumn,
|
||||||
|
"table-column-group" => Display::TableColumnGroup,
|
||||||
|
"table-row" => Display::TableRow,
|
||||||
|
"table-cell" => Display::TableCell,
|
||||||
|
"ruby-base" => Display::RubyBase,
|
||||||
|
"ruby-base-container" => Display::RubyBaseContainer,
|
||||||
|
"ruby-text" => Display::RubyText,
|
||||||
|
"ruby-text-container" => Display::RubyTextContainer,
|
||||||
|
"-webkit-box" => Display::WebkitBox,
|
||||||
|
"-webkit-inline-box" => Display::WebkitInlineBox,
|
||||||
|
"-moz-box" if moz_box_display_values_enabled(context) => Display::MozBox,
|
||||||
|
"-moz-inline-box" if moz_box_display_values_enabled(context) => Display::MozInlineBox,
|
||||||
|
"-moz-grid" if moz_display_values_enabled(context) => Display::MozGrid,
|
||||||
|
"-moz-inline-grid" if moz_display_values_enabled(context) => Display::MozInlineGrid,
|
||||||
|
"-moz-grid-group" if moz_display_values_enabled(context) => Display::MozGridGroup,
|
||||||
|
"-moz-grid-line" if moz_display_values_enabled(context) => Display::MozGridLine,
|
||||||
|
"-moz-stack" if moz_display_values_enabled(context) => Display::MozStack,
|
||||||
|
"-moz-inline-stack" if moz_display_values_enabled(context) => Display::MozInlineStack,
|
||||||
|
"-moz-deck" if moz_display_values_enabled(context) => Display::MozDeck,
|
||||||
|
"-moz-groupbox" if moz_display_values_enabled(context) => Display::MozGroupbox,
|
||||||
|
"-moz-popup" if moz_display_values_enabled(context) => Display::MozPopup,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
impl SpecifiedValueInfo for Display {
|
||||||
|
fn collect_completion_keywords(f: KeywordsCollectFn) {
|
||||||
|
f(&["block",
|
||||||
|
"contents",
|
||||||
|
"flex",
|
||||||
|
"flow-root",
|
||||||
|
"grid",
|
||||||
|
"inline",
|
||||||
|
"inline-block",
|
||||||
|
"inline-flex",
|
||||||
|
"inline-grid",
|
||||||
|
"inline-table",
|
||||||
|
"list-item",
|
||||||
|
"none",
|
||||||
|
"ruby",
|
||||||
|
"ruby-base",
|
||||||
|
"ruby-base-container",
|
||||||
|
"ruby-text",
|
||||||
|
"ruby-text-container",
|
||||||
|
"table",
|
||||||
|
"table-caption",
|
||||||
|
"table-cell",
|
||||||
|
"table-column",
|
||||||
|
"table-column-group",
|
||||||
|
"table-footer-group",
|
||||||
|
"table-header-group",
|
||||||
|
"table-row",
|
||||||
|
"table-row-group",
|
||||||
|
"-webkit-box",
|
||||||
|
"-webkit-inline-box",
|
||||||
|
"-webkit-flex",
|
||||||
|
"-webkit-inline-flex",
|
||||||
|
"-moz-box",
|
||||||
|
"-moz-inline-box",
|
||||||
|
"-moz-grid",
|
||||||
|
"-moz-inline-grid",
|
||||||
|
"-moz-grid-group",
|
||||||
|
"-moz-grid-line",
|
||||||
|
"-moz-stack",
|
||||||
|
"-moz-inline-stack",
|
||||||
|
"-moz-deck",
|
||||||
|
"-moz-popup",
|
||||||
|
"-moz-groupbox",
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A specified value for the `vertical-align` property.
|
/// A specified value for the `vertical-align` property.
|
||||||
pub type VerticalAlign = GenericVerticalAlign<LengthPercentage>;
|
pub type VerticalAlign = GenericVerticalAlign<LengthPercentage>;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue