mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
style: Implement 'inline list-item' and 'inline flow-root list-item' values for the 'display' property.
Differential Revision: https://phabricator.services.mozilla.com/D39832
This commit is contained in:
parent
07dad28e49
commit
2d29e6edd4
2 changed files with 84 additions and 90 deletions
|
@ -8,6 +8,8 @@
|
||||||
use crate::dom::TElement;
|
use crate::dom::TElement;
|
||||||
use crate::properties::computed_value_flags::ComputedValueFlags;
|
use crate::properties::computed_value_flags::ComputedValueFlags;
|
||||||
use crate::properties::longhands::display::computed_value::T as Display;
|
use crate::properties::longhands::display::computed_value::T as Display;
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
use crate::values::specified::box_::DisplayInside;
|
||||||
use crate::properties::longhands::float::computed_value::T as Float;
|
use crate::properties::longhands::float::computed_value::T as Float;
|
||||||
use crate::properties::longhands::overflow_x::computed_value::T as Overflow;
|
use crate::properties::longhands::overflow_x::computed_value::T as Overflow;
|
||||||
use crate::properties::longhands::position::computed_value::T as Position;
|
use crate::properties::longhands::position::computed_value::T as Position;
|
||||||
|
@ -175,7 +177,9 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
|
||||||
/// Apply the blockification rules based on the table in CSS 2.2 section 9.7.
|
/// Apply the blockification rules based on the table in CSS 2.2 section 9.7.
|
||||||
/// <https://drafts.csswg.org/css2/visuren.html#dis-pos-flo>
|
/// <https://drafts.csswg.org/css2/visuren.html#dis-pos-flo>
|
||||||
/// A ::marker pseudo-element with 'list-style-position:outside' needs to
|
/// A ::marker pseudo-element with 'list-style-position:outside' needs to
|
||||||
/// have its 'display' blockified.
|
/// have its 'display' blockified, unless the ::marker is for an inline
|
||||||
|
/// list-item (for which 'list-style-position:outside' behaves as 'inside').
|
||||||
|
/// https://drafts.csswg.org/css-lists-3/#list-style-position-property
|
||||||
fn blockify_if_necessary<E>(&mut self, layout_parent_style: &ComputedValues, element: Option<E>)
|
fn blockify_if_necessary<E>(&mut self, layout_parent_style: &ComputedValues, element: Option<E>)
|
||||||
where
|
where
|
||||||
E: TElement,
|
E: TElement,
|
||||||
|
@ -194,21 +198,19 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
|
||||||
let is_root = self.style.pseudo.is_none() && element.map_or(false, |e| e.is_root());
|
let is_root = self.style.pseudo.is_none() && element.map_or(false, |e| e.is_root());
|
||||||
blockify_if!(is_root);
|
blockify_if!(is_root);
|
||||||
if !self.skip_item_display_fixup(element) {
|
if !self.skip_item_display_fixup(element) {
|
||||||
blockify_if!(layout_parent_style
|
let parent_display = layout_parent_style.get_box().clone_display();
|
||||||
.get_box()
|
blockify_if!(parent_display.is_item_container());
|
||||||
.clone_display()
|
|
||||||
.is_item_container());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let is_item_or_root = blockify;
|
let is_item_or_root = blockify;
|
||||||
|
|
||||||
blockify_if!(self.style.floated());
|
blockify_if!(self.style.floated());
|
||||||
blockify_if!(self.style.out_of_flow_positioned());
|
blockify_if!(self.style.out_of_flow_positioned());
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
blockify_if!(
|
blockify_if!(
|
||||||
self.style.pseudo.map_or(false, |p| p.is_marker()) &&
|
self.style.pseudo.map_or(false, |p| p.is_marker()) &&
|
||||||
self.style.get_parent_list().clone_list_style_position() ==
|
self.style.get_parent_list().clone_list_style_position() == ListStylePosition::Outside &&
|
||||||
ListStylePosition::Outside
|
layout_parent_style.get_box().clone_display().inside() != DisplayInside::Inline);
|
||||||
);
|
|
||||||
|
|
||||||
if !blockify {
|
if !blockify {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -393,55 +393,66 @@ impl Display {
|
||||||
|
|
||||||
/// Convert this display into an equivalent block display.
|
/// Convert this display into an equivalent block display.
|
||||||
///
|
///
|
||||||
/// Also used for style adjustments.
|
/// Also used for :root style adjustments.
|
||||||
pub fn equivalent_block_display(&self, _is_root_element: bool) -> Self {
|
pub fn equivalent_block_display(&self, _is_root_element: bool) -> Self {
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
{
|
||||||
|
// Special handling for `contents` and `list-item`s on the root element.
|
||||||
|
if _is_root_element && (*self == Display::Contents || self.is_list_item()) {
|
||||||
|
return Display::Block;
|
||||||
|
}
|
||||||
|
match self.outside() {
|
||||||
|
DisplayOutside::Inline => {
|
||||||
|
let inside = match self.inside() {
|
||||||
|
DisplayInside::Inline | DisplayInside::FlowRoot => DisplayInside::Block,
|
||||||
|
// FIXME: we don't handle `block ruby` in layout yet, remove this when we do:
|
||||||
|
DisplayInside::Ruby => DisplayInside::Block,
|
||||||
|
inside => inside,
|
||||||
|
};
|
||||||
|
Display::from3(DisplayOutside::Block, inside, self.is_list_item())
|
||||||
|
},
|
||||||
|
DisplayOutside::Block | DisplayOutside::None => *self,
|
||||||
|
_ => Display::Block,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "gecko"))]
|
||||||
match *self {
|
match *self {
|
||||||
// Values that have a corresponding block-outside version.
|
// Values that have a corresponding block-outside version.
|
||||||
#[cfg(any(feature = "gecko", feature = "servo-layout-2013"))]
|
#[cfg(feature = "servo-layout-2013")]
|
||||||
Display::InlineTable => Display::Table,
|
Display::InlineTable => Display::Table,
|
||||||
#[cfg(any(feature = "gecko", feature = "servo-layout-2013"))]
|
#[cfg(feature = "servo-layout-2013")]
|
||||||
Display::InlineFlex => Display::Flex,
|
Display::InlineFlex => Display::Flex,
|
||||||
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
Display::InlineGrid => Display::Grid,
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
Display::WebkitInlineBox => Display::WebkitBox,
|
|
||||||
|
|
||||||
// Special handling for contents and list-item on the root
|
|
||||||
// element for Gecko.
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
Display::Contents | Display::ListItem if _is_root_element => Display::Block,
|
|
||||||
|
|
||||||
// These are not changed by blockification.
|
// These are not changed by blockification.
|
||||||
Display::None | Display::Block => *self,
|
Display::None | Display::Block => *self,
|
||||||
#[cfg(any(feature = "gecko", feature = "servo-layout-2013"))]
|
#[cfg(feature = "servo-layout-2013")]
|
||||||
Display::Flex | Display::ListItem | Display::Table => *self,
|
Display::Flex | Display::ListItem | Display::Table => *self,
|
||||||
|
|
||||||
#[cfg(feature = "gecko")]
|
|
||||||
Display::Contents | Display::FlowRoot | Display::Grid | Display::WebkitBox => *self,
|
|
||||||
|
|
||||||
// Everything else becomes block.
|
// Everything else becomes block.
|
||||||
_ => Display::Block,
|
_ => Display::Block,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert this display into an inline-outside display.
|
/// Convert this display into an equivalent inline-outside display.
|
||||||
///
|
/// https://drafts.csswg.org/css-display/#inlinify
|
||||||
/// Ideally it should implement spec: https://drafts.csswg.org/css-display/#inlinify
|
|
||||||
/// but the spec isn't stable enough, so we copy what Gecko does for now.
|
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
pub fn inlinify(&self) -> Self {
|
pub fn inlinify(&self) -> Self {
|
||||||
match *self {
|
match self.outside() {
|
||||||
Display::Block | Display::FlowRoot => Display::InlineBlock,
|
DisplayOutside::Block => {
|
||||||
Display::Table => Display::InlineTable,
|
let inside = match self.inside() {
|
||||||
Display::Flex => Display::InlineFlex,
|
DisplayInside::Block => DisplayInside::FlowRoot,
|
||||||
Display::Grid => Display::InlineGrid,
|
inside => inside,
|
||||||
// XXX bug 1105868 this should probably be InlineListItem:
|
};
|
||||||
Display::ListItem => Display::Inline,
|
Display::from3(DisplayOutside::Inline, inside, self.is_list_item())
|
||||||
Display::MozBox => Display::MozInlineBox,
|
},
|
||||||
Display::MozStack => Display::MozInlineStack,
|
DisplayOutside::XUL => {
|
||||||
Display::WebkitBox => Display::WebkitInlineBox,
|
match self.inside() {
|
||||||
other => other,
|
DisplayInside::MozBox => Display::MozInlineBox,
|
||||||
|
DisplayInside::MozStack => Display::MozInlineStack,
|
||||||
|
_ => *self,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => *self,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -496,8 +507,15 @@ impl ToCss for Display {
|
||||||
}
|
}
|
||||||
(_, inside) => {
|
(_, inside) => {
|
||||||
if self.is_list_item() {
|
if self.is_list_item() {
|
||||||
debug_assert_eq!(inside, DisplayInside::FlowRoot);
|
if outside != DisplayOutside::Block {
|
||||||
dest.write_str("flow-root list-item")
|
outside.to_css(dest)?;
|
||||||
|
dest.write_str(" ")?;
|
||||||
|
}
|
||||||
|
if inside != DisplayInside::Flow {
|
||||||
|
inside.to_css(dest)?;
|
||||||
|
dest.write_str(" ")?;
|
||||||
|
}
|
||||||
|
dest.write_str("list-item")
|
||||||
} else {
|
} else {
|
||||||
inside.to_css(dest)
|
inside.to_css(dest)
|
||||||
}
|
}
|
||||||
|
@ -547,35 +565,10 @@ fn parse_display_outside<'i, 't>(
|
||||||
Ok(try_match_ident_ignore_ascii_case! { input,
|
Ok(try_match_ident_ignore_ascii_case! { input,
|
||||||
"block" => DisplayOutside::Block,
|
"block" => DisplayOutside::Block,
|
||||||
"inline" => DisplayOutside::Inline,
|
"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:
|
// FIXME(bug 2056): not supported in layout yet:
|
||||||
//"run-in" => DisplayOutside::RunIn,
|
//"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
|
/// FIXME: this can be replaced with parse_display_outside once we
|
||||||
/// support all its values for `ruby`.
|
/// support all its values for `ruby`.
|
||||||
|
@ -637,18 +630,16 @@ impl Parse for Display {
|
||||||
if !got_list_item && is_valid_inside_for_list_item(&inside) {
|
if !got_list_item && is_valid_inside_for_list_item(&inside) {
|
||||||
got_list_item = input.try(parse_list_item).is_ok();
|
got_list_item = input.try(parse_list_item).is_ok();
|
||||||
}
|
}
|
||||||
let outside = if got_list_item {
|
let outside = match inside {
|
||||||
input.try(parse_display_outside_for_list_item)
|
// FIXME we don't handle `block ruby` in layout yet.
|
||||||
} else {
|
|
||||||
match inside {
|
|
||||||
Ok(DisplayInside::Ruby) => input.try(parse_display_outside_for_ruby),
|
Ok(DisplayInside::Ruby) => input.try(parse_display_outside_for_ruby),
|
||||||
_ => input.try(parse_display_outside),
|
_ => input.try(parse_display_outside),
|
||||||
}
|
|
||||||
};
|
};
|
||||||
if !got_list_item && is_valid_outside_for_list_item(&outside) {
|
if outside.is_ok() {
|
||||||
|
if !got_list_item && (inside.is_err() || is_valid_inside_for_list_item(&inside)) {
|
||||||
got_list_item = input.try(parse_list_item).is_ok();
|
got_list_item = input.try(parse_list_item).is_ok();
|
||||||
}
|
}
|
||||||
if outside.is_ok() && inside.is_err(){
|
if inside.is_err() {
|
||||||
inside = if got_list_item {
|
inside = if got_list_item {
|
||||||
input.try(parse_display_inside_for_list_item)
|
input.try(parse_display_inside_for_list_item)
|
||||||
} else {
|
} else {
|
||||||
|
@ -658,12 +649,11 @@ impl Parse for Display {
|
||||||
_ => input.try(parse_display_inside),
|
_ => input.try(parse_display_inside),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if !got_list_item &&
|
if !got_list_item && is_valid_inside_for_list_item(&inside) {
|
||||||
is_valid_outside_for_list_item(&outside) &&
|
|
||||||
is_valid_inside_for_list_item(&inside) {
|
|
||||||
got_list_item = input.try(parse_list_item).is_ok();
|
got_list_item = input.try(parse_list_item).is_ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if got_list_item || inside.is_ok() || outside.is_ok() {
|
if got_list_item || inside.is_ok() || outside.is_ok() {
|
||||||
let inside = inside.unwrap_or(DisplayInside::Flow);
|
let inside = inside.unwrap_or(DisplayInside::Flow);
|
||||||
let outside = outside.unwrap_or(
|
let outside = outside.unwrap_or(
|
||||||
|
@ -730,6 +720,8 @@ impl SpecifiedValueInfo for Display {
|
||||||
"inline-flex",
|
"inline-flex",
|
||||||
"inline-grid",
|
"inline-grid",
|
||||||
"inline-table",
|
"inline-table",
|
||||||
|
"inline list-item",
|
||||||
|
"inline flow-root list-item",
|
||||||
"list-item",
|
"list-item",
|
||||||
"none",
|
"none",
|
||||||
"ruby",
|
"ruby",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue