Auto merge of #24528 - servo:background-color, r=nox

Layout 2020: run layout and paint background-color
This commit is contained in:
bors-servo 2019-10-24 05:58:39 -04:00 committed by GitHub
commit 4cdfe23cc8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 258 additions and 62 deletions

1
Cargo.lock generated
View file

@ -2477,6 +2477,7 @@ version = "0.0.1"
dependencies = [
"app_units",
"atomic_refcell",
"cssparser",
"euclid",
"gfx",
"ipc-channel",

View file

@ -15,6 +15,7 @@ doctest = false
[dependencies]
app_units = "0.7"
atomic_refcell = "0.1"
cssparser = "0.27"
euclid = "0.20"
gfx = {path = "../gfx"}
ipc-channel = "0.12"

View file

@ -0,0 +1,106 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::fragments::{BoxFragment, Fragment};
use crate::geom::physical::{Rect, Vec2};
use crate::style_ext::ComputedValuesExt;
use app_units::Au;
use style::values::computed::Length;
use webrender_api::CommonItemProperties;
pub struct DisplayListBuilder {
pipeline_id: webrender_api::PipelineId,
pub wr: webrender_api::DisplayListBuilder,
pub is_contentful: bool,
}
impl DisplayListBuilder {
pub fn new(
pipeline_id: webrender_api::PipelineId,
viewport_size: webrender_api::units::LayoutSize,
) -> Self {
Self {
pipeline_id,
is_contentful: false,
wr: webrender_api::DisplayListBuilder::new(pipeline_id, viewport_size),
}
}
}
/// Contentful paint, for the purpose of
/// https://w3c.github.io/paint-timing/#first-contentful-paint
/// (i.e. the display list contains items of type text,
/// image, non-white canvas or SVG). Used by metrics.
pub struct IsContentful(pub bool);
impl Fragment {
pub(crate) fn build_display_list(
&self,
builder: &mut DisplayListBuilder,
is_contentful: &mut IsContentful,
containing_block: &Rect<Length>,
) {
match self {
Fragment::Box(b) => b.build_display_list(builder, is_contentful, containing_block),
Fragment::Anonymous(a) => {
let rect = a
.rect
.to_physical(a.mode, containing_block)
.translate(&containing_block.top_left);
for child in &a.children {
child.build_display_list(builder, is_contentful, &rect)
}
},
Fragment::Text(_) => {
is_contentful.0 = true;
// FIXME
},
}
}
}
impl BoxFragment {
fn build_display_list(
&self,
builder: &mut DisplayListBuilder,
is_contentful: &mut IsContentful,
containing_block: &Rect<Length>,
) {
let background_color = self
.style
.resolve_color(self.style.clone_background_color());
if background_color.alpha > 0 {
let clip_rect = self
.border_rect()
.to_physical(self.style.writing_mode(), containing_block)
.translate(&containing_block.top_left)
.into();
let common = CommonItemProperties {
clip_rect,
clip_id: webrender_api::ClipId::root(builder.pipeline_id),
spatial_id: webrender_api::SpatialId::root_scroll_node(builder.pipeline_id),
hit_info: None,
// TODO(gw): Make use of the WR backface visibility functionality.
is_backface_visible: true,
};
builder.wr.push_rect(&common, rgba(background_color))
}
let content_rect = self
.content_rect
.to_physical(self.style.writing_mode(), containing_block)
.translate(&containing_block.top_left);
for child in &self.children {
child.build_display_list(builder, is_contentful, &content_rect)
}
}
}
fn rgba(rgba: cssparser::RGBA) -> webrender_api::ColorF {
webrender_api::ColorF::new(
rgba.red_f32(),
rgba.green_f32(),
rgba.blue_f32(),
rgba.alpha_f32(),
)
}

View file

@ -210,7 +210,6 @@ where
self.handle_block_level_element(style.clone(), inside, contents, box_slot)
}
},
DisplayOutside::None => panic!(":("),
},
}
}
@ -352,7 +351,6 @@ where
inline_box.last_fragment = true;
Arc::new(InlineLevelBox::InlineBox(inline_box))
},
DisplayInside::None | DisplayInside::Contents => panic!(":("),
},
};
self.current_inline_level_boxes().push(box_.clone());

View file

@ -122,7 +122,6 @@ impl InlineFormattingContext {
inline: match outside {
DisplayOutside::Inline => ifc.inline_position,
DisplayOutside::Block => Length::zero(),
DisplayOutside::None => unreachable!(":("),
},
block: ifc.line_boxes.next_line_block_position,
},

View file

@ -27,7 +27,7 @@ mod float;
pub mod inline;
mod root;
pub use root::BoxTreeRoot;
pub use root::{BoxTreeRoot, FragmentTreeRoot};
#[derive(Debug)]
pub(crate) struct BlockFormattingContext {

View file

@ -2,6 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::display_list::IsContentful;
use crate::dom_traversal::{Contents, NodeExt};
use crate::flow::construct::ContainsFloats;
use crate::flow::float::FloatBox;
@ -20,9 +21,11 @@ use servo_arc::Arc;
use style::context::SharedStyleContext;
use style::properties::ComputedValues;
use style::values::computed::{Length, LengthOrAuto};
use style::Zero;
use style_traits::CSSPixel;
pub struct BoxTreeRoot(BlockFormattingContext);
pub struct FragmentTreeRoot(Vec<Fragment>);
impl BoxTreeRoot {
pub fn construct<'dom>(
@ -95,7 +98,7 @@ fn construct_for_root_element<'dom>(
}
impl BoxTreeRoot {
fn layout(&self, viewport: geom::Size<CSSPixel>) -> Vec<Fragment> {
pub fn layout(&self, viewport: geom::Size<CSSPixel>) -> FragmentTreeRoot {
let initial_containing_block_size = Vec2 {
inline: Length::new(viewport.width),
block: Length::new(viewport.height),
@ -125,6 +128,31 @@ impl BoxTreeRoot {
.par_iter()
.map(|a| a.layout(&initial_containing_block)),
);
flow_children.fragments
FragmentTreeRoot(flow_children.fragments)
}
}
impl FragmentTreeRoot {
pub fn build_display_list(
&self,
builder: &mut crate::display_list::DisplayListBuilder,
pipeline_id: msg::constellation_msg::PipelineId,
viewport_size: webrender_api::units::LayoutSize,
) -> IsContentful {
let containing_block = geom::physical::Rect {
top_left: geom::physical::Vec2 {
x: Length::zero(),
y: Length::zero(),
},
size: geom::physical::Vec2 {
x: Length::new(viewport_size.width),
y: Length::new(viewport_size.height),
},
};
let mut is_contentful = IsContentful(false);
for fragment in &self.0 {
fragment.build_display_list(builder, &mut is_contentful, &containing_block)
}
is_contentful
}
}

View file

@ -3,6 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::style_ext::{Direction, WritingMode};
use std::fmt;
use std::ops::{Add, AddAssign, Sub};
use style::values::computed::{Length, LengthOrAuto, LengthPercentage, LengthPercentageOrAuto};
use style::Zero;
@ -13,7 +14,7 @@ pub type Size<U> = euclid::Size2D<f32, U>;
pub type Rect<U> = euclid::Rect<f32, U>;
pub(crate) mod physical {
#[derive(Clone, Debug)]
#[derive(Clone)]
pub(crate) struct Vec2<T> {
pub x: T,
pub y: T,
@ -35,7 +36,7 @@ pub(crate) mod physical {
}
pub(crate) mod flow_relative {
#[derive(Clone, Debug)]
#[derive(Clone)]
pub(crate) struct Vec2<T> {
pub inline: T,
pub block: T,
@ -56,6 +57,28 @@ pub(crate) mod flow_relative {
}
}
impl<T: fmt::Debug> fmt::Debug for physical::Vec2<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// Not using f.debug_struct on purpose here, to keep {:?} output somewhat compact
f.write_str("Vec2 { x: ")?;
self.x.fmt(f)?;
f.write_str(", y: ")?;
self.y.fmt(f)?;
f.write_str(" }")
}
}
impl<T: fmt::Debug> fmt::Debug for flow_relative::Vec2<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// Not using f.debug_struct on purpose here, to keep {:?} output somewhat compact
f.write_str("Vec2 { i: ")?;
self.inline.fmt(f)?;
f.write_str(", b: ")?;
self.block.fmt(f)?;
f.write_str(" }")
}
}
impl<T> Add<&'_ physical::Vec2<T>> for &'_ physical::Vec2<T>
where
T: Add<Output = T> + Copy,
@ -332,3 +355,12 @@ impl From<physical::Rect<Length>> for Rect<CSSPixel> {
}
}
}
impl From<physical::Rect<Length>> for webrender_api::units::LayoutRect {
fn from(r: physical::Rect<Length>) -> Self {
Rect {
origin: Point::new(r.top_left.x.px(), r.top_left.y.px()),
size: Size::new(r.size.x.px(), r.size.y.px()),
}
}
}

View file

@ -17,6 +17,7 @@ use style::Zero;
pub mod context;
pub mod data;
pub mod display_list;
mod dom_traversal;
mod element_data;
mod flow;
@ -30,18 +31,17 @@ mod style_ext;
pub mod traversal;
pub mod wrapper;
pub use flow::BoxTreeRoot;
pub use flow::{BoxTreeRoot, FragmentTreeRoot};
use crate::dom_traversal::{Contents, NodeExt};
use crate::flow::{BlockFormattingContext, FlowChildren};
use crate::geom::flow_relative::Vec2;
use crate::positioned::AbsolutelyPositionedFragment;
use crate::replaced::ReplacedContent;
use crate::style_ext::{ComputedValuesExt, Direction, Position, WritingMode};
use crate::style_ext::{ComputedValuesExt, Direction, DisplayInside, Position, WritingMode};
use servo_arc::Arc;
use std::convert::TryInto;
use style::context::SharedStyleContext;
use style::values::specified::box_::DisplayInside;
/// https://drafts.csswg.org/css-display/#independent-formatting-context
#[derive(Debug)]
@ -73,7 +73,6 @@ impl IndependentFormattingContext {
non_replaced,
))
},
DisplayInside::None | DisplayInside::Contents => panic!(":("),
},
Err(replaced) => IndependentFormattingContext::Replaced(replaced),
}

View file

@ -4,14 +4,12 @@
use crate::geom::{flow_relative, physical};
use style::properties::ComputedValues;
use style::values::computed::{
Display as PackedDisplay, Length, LengthPercentage, LengthPercentageOrAuto, Size,
};
use style::values::computed::{Length, LengthPercentage, LengthPercentageOrAuto, Size};
use style::values::specified::box_ as stylo;
pub use style::computed_values::direction::T as Direction;
pub use style::computed_values::position::T as Position;
pub use style::computed_values::writing_mode::T as WritingMode;
pub use style::values::specified::box_::{DisplayInside, DisplayOutside};
#[derive(Clone, Copy, Eq, PartialEq)]
pub(crate) enum Display {
@ -31,6 +29,18 @@ pub(crate) enum DisplayGeneratingBox {
// https://drafts.csswg.org/css-display-3/#layout-specific-display
}
#[derive(Clone, Copy, Eq, PartialEq)]
pub(crate) enum DisplayOutside {
Block,
Inline,
}
#[derive(Clone, Copy, Eq, PartialEq)]
pub(crate) enum DisplayInside {
Flow,
FlowRoot,
}
pub(crate) trait ComputedValuesExt {
fn writing_mode(&self) -> (WritingMode, Direction);
fn box_offsets(&self) -> flow_relative::Sides<LengthPercentageOrAuto>;
@ -105,18 +115,27 @@ impl ComputedValuesExt for ComputedValues {
}
}
impl From<PackedDisplay> for Display {
fn from(packed_display: PackedDisplay) -> Self {
if packed_display == PackedDisplay::None {
return Self::None;
}
if packed_display == PackedDisplay::Contents {
return Self::Contents;
}
Self::GeneratingBox(DisplayGeneratingBox::OutsideInside {
outside: packed_display.outside(),
inside: packed_display.inside(),
// list_item: packed_display.is_list_item(),
impl From<stylo::Display> for Display {
fn from(packed: stylo::Display) -> Self {
let inside = match packed.inside() {
stylo::DisplayInside::Flow => DisplayInside::Flow,
stylo::DisplayInside::FlowRoot => DisplayInside::FlowRoot,
// These should not be values of DisplayInside, but oh well
stylo::DisplayInside::None => return Display::None,
stylo::DisplayInside::Contents => return Display::Contents,
};
let outside = match packed.outside() {
stylo::DisplayOutside::Block => DisplayOutside::Block,
stylo::DisplayOutside::Inline => DisplayOutside::Inline,
// This should not be a value of DisplayInside, but oh well
stylo::DisplayOutside::None => return Display::None,
};
Display::GeneratingBox(DisplayGeneratingBox::OutsideInside {
outside,
inside,
// list_item: packed.is_list_item(),
})
}
}

View file

@ -35,6 +35,7 @@ use gfx_traits::{node_id_from_scroll_id, Epoch};
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
use ipc_channel::router::ROUTER;
use layout::context::LayoutContext;
use layout::display_list::DisplayListBuilder;
use layout::query::{
process_content_box_request, process_content_boxes_request, LayoutRPCImpl, LayoutThreadData,
};
@ -167,8 +168,11 @@ pub struct LayoutThread {
/// The number of Web fonts that have been requested but not yet loaded.
outstanding_web_fonts: Arc<AtomicUsize>,
/// The root box tree.
box_tree_root: RefCell<Option<BoxTreeRoot>>,
/// The root of the box tree.
box_tree_root: RefCell<Option<layout::BoxTreeRoot>>,
/// The root of the fragment tree.
fragment_tree_root: RefCell<Option<layout::FragmentTreeRoot>>,
/// The document-specific shared lock used for author-origin stylesheets
document_shared_lock: Option<SharedRwLock>,
@ -497,6 +501,7 @@ impl LayoutThread {
_new_animations_receiver: new_animations_receiver,
outstanding_web_fonts: Arc::new(AtomicUsize::new(0)),
box_tree_root: Default::default(),
fragment_tree_root: Default::default(),
document_shared_lock: None,
epoch: Cell::new(Epoch(0)),
viewport_size: Size2D::new(Au(0), Au(0)),
@ -1084,7 +1089,12 @@ impl LayoutThread {
let shared = DomTraversal::<ServoLayoutElement>::shared_context(&traversal);
let box_tree =
BoxTreeRoot::construct(shared, document.root_element().unwrap().as_node());
let fragment_tree = box_tree.layout(Size2D::new(
self.viewport_size.width.to_f32_px(),
self.viewport_size.height.to_f32_px(),
));
*self.box_tree_root.borrow_mut() = Some(box_tree);
*self.fragment_tree_root.borrow_mut() = Some(fragment_tree);
}
for element in elements_with_snapshot {
@ -1099,7 +1109,9 @@ impl LayoutThread {
}
// Perform post-style recalculation layout passes.
self.perform_post_style_recalc_layout_passes(&data.reflow_goal, Some(&document));
if let Some(root) = &*self.fragment_tree_root.borrow() {
self.perform_post_style_recalc_layout_passes(root, &data.reflow_goal, Some(&document));
}
self.first_reflow.set(false);
self.respond_to_query_if_necessary(&data.reflow_goal, &mut *rw_data, &mut layout_context);
@ -1221,7 +1233,10 @@ impl LayoutThread {
);
}
if let Some(author_shared_lock) = self.document_shared_lock.clone() {
if let Some(root) = &*self.fragment_tree_root.borrow() {
// Unwrap here should not panic since self.fragment_tree_root is only ever set to Some(_)
// in handle_reflow() where self.document_shared_lock is as well.
let author_shared_lock = self.document_shared_lock.clone().unwrap();
let author_guard = author_shared_lock.read();
let ua_or_user_guard = UA_STYLESHEETS.shared_lock.read();
let _guards = StylesheetGuards {
@ -1229,12 +1244,13 @@ impl LayoutThread {
ua_or_user: &ua_or_user_guard,
};
self.perform_post_style_recalc_layout_passes(&ReflowGoal::TickAnimations, None);
self.perform_post_style_recalc_layout_passes(root, &ReflowGoal::TickAnimations, None);
}
}
fn perform_post_style_recalc_layout_passes(
&self,
fragment_tree: &layout::FragmentTreeRoot,
reflow_goal: &ReflowGoal,
document: Option<&ServoLayoutDocument>,
) {
@ -1252,16 +1268,13 @@ impl LayoutThread {
document.will_paint();
}
let viewport_size = Size2D::new(
let viewport_size = webrender_api::units::LayoutSize::from_untyped(Size2D::new(
self.viewport_size.width.to_f32_px(),
self.viewport_size.height.to_f32_px(),
);
let viewport_size = webrender_api::units::LayoutSize::from_untyped(viewport_size);
let display_list =
webrender_api::DisplayListBuilder::new(self.id.to_webrender(), viewport_size);
let is_contentful = false;
));
let mut display_list = DisplayListBuilder::new(self.id.to_webrender(), viewport_size);
let is_contentful =
fragment_tree.build_display_list(&mut display_list, self.id, viewport_size);
debug!("Layout done!");
@ -1273,14 +1286,14 @@ impl LayoutThread {
// sending the display list to WebRender in order to set time related
// Progressive Web Metrics.
self.paint_time_metrics
.maybe_observe_paint_time(self, epoch, is_contentful);
.maybe_observe_paint_time(self, epoch, is_contentful.0);
let mut txn = webrender_api::Transaction::new();
txn.set_display_list(
webrender_api::Epoch(epoch.0),
None,
viewport_size,
display_list.finalize(),
display_list.wr.finalize(),
true,
);
txn.generate_frame();

View file

@ -24,7 +24,6 @@
"border-%s-color" % side_name, "Color",
"computed_value::T::currentcolor()",
engines="gecko servo-2013 servo-2020",
servo_2020_pref="layout.2020.unimplemented",
alias=maybe_moz_logical_alias(engine, side, "-moz-border-%s-color"),
spec=maybe_logical_spec(side, "color"),
animation_value_type="AnimatedColor",
@ -51,7 +50,6 @@
"BorderSideWidth",
"crate::values::computed::NonNegativeLength::new(3.)",
engines="gecko servo-2013 servo-2020",
servo_2020_pref="layout.2020.unimplemented",
computed_type="crate::values::computed::NonNegativeLength",
alias=maybe_moz_logical_alias(engine, side, "-moz-border-%s-width"),
spec=maybe_logical_spec(side, "width"),

View file

@ -63,7 +63,6 @@ ${helpers.predefined_type(
"Float",
"computed::Float::None",
engines="gecko servo-2013 servo-2020",
servo_2020_pref="layout.2020.unimplemented",
initial_specified_value="specified::Float::None",
spec="https://drafts.csswg.org/css-box/#propdef-float",
animation_value_type="discrete",

View file

@ -29,6 +29,7 @@ ${helpers.single_keyword(
rl=horizontal-tb rl-tb=horizontal-tb \
tb=vertical-rl tb-rl=vertical-rl",
servo_2013_pref="layout.writing-mode.enabled",
servo_2020_pref="layout.writing-mode.enabled",
animation_value_type="none",
spec="https://drafts.csswg.org/css-writing-modes/#propdef-writing-mode",
servo_restyle_damage="rebuild_and_reflow",
@ -38,6 +39,7 @@ ${helpers.single_keyword(
"direction",
"ltr rtl",
engines="gecko servo-2013 servo-2020",
servo_2020_pref="layout.2020.unimplemented",
animation_value_type="none",
spec="https://drafts.csswg.org/css-writing-modes/#propdef-direction",
needs_conversion=True,

View file

@ -17,7 +17,6 @@
"LengthPercentageOrAuto",
"computed::LengthPercentageOrAuto::zero()",
engines="gecko servo-2013 servo-2020",
servo_2020_pref="layout.2020.unimplemented",
alias=maybe_moz_logical_alias(engine, side, "-moz-margin-%s"),
allow_quirks="No" if side[1] else "Yes",
animation_value_type="ComputedValue",

View file

@ -17,7 +17,6 @@
"NonNegativeLengthPercentage",
"computed::NonNegativeLengthPercentage::zero()",
engines="gecko servo-2013 servo-2020",
servo_2020_pref="layout.2020.unimplemented",
alias=maybe_moz_logical_alias(engine, side, "-moz-padding-%s"),
animation_value_type="NonNegativeLengthPercentage",
logical=side[1],

View file

@ -15,7 +15,6 @@
"LengthPercentageOrAuto",
"computed::LengthPercentageOrAuto::auto()",
engines="gecko servo-2013 servo-2020",
servo_2020_pref="layout.2020.unimplemented",
spec="https://www.w3.org/TR/CSS2/visuren.html#propdef-%s" % side,
animation_value_type="ComputedValue",
allow_quirks="Yes",
@ -30,7 +29,6 @@
"LengthPercentageOrAuto",
"computed::LengthPercentageOrAuto::auto()",
engines="gecko servo-2013 servo-2020",
servo_2020_pref="layout.2020.unimplemented",
spec="https://drafts.csswg.org/css-logical-props/#propdef-inset-%s" % side,
alias="offset-%s:layout.css.offset-logical-properties.enabled" % side,
animation_value_type="ComputedValue",
@ -278,7 +276,6 @@ ${helpers.predefined_type(
"Size",
"computed::Size::auto()",
engines="gecko servo-2013 servo-2020",
servo_2020_pref="layout.2020.unimplemented",
logical=logical,
logical_group="size",
allow_quirks="No" if logical else "Yes",

View file

@ -9,7 +9,7 @@ ${helpers.four_sides_shorthand(
"border-color",
"border-%s-color",
"specified::Color::parse",
engines="gecko servo-2013",
engines="gecko servo-2013 servo-2020",
spec="https://drafts.csswg.org/css-backgrounds/#border-color",
allow_quirks="Yes",
)}
@ -18,14 +18,14 @@ ${helpers.four_sides_shorthand(
"border-style",
"border-%s-style",
"specified::BorderStyle::parse",
engines="gecko servo-2013",
engines="gecko servo-2013 servo-2020",
needs_context=False,
spec="https://drafts.csswg.org/css-backgrounds/#border-style",
)}
<%helpers:shorthand
name="border-width"
engines="gecko servo-2013"
engines="gecko servo-2013 servo-2020"
sub_properties="${
' '.join('border-%s-width' % side
for side in PHYSICAL_SIDES)}"

View file

@ -8,7 +8,7 @@ ${helpers.four_sides_shorthand(
"margin",
"margin-%s",
"specified::LengthPercentageOrAuto::parse",
engines="gecko servo-2013",
engines="gecko servo-2013 servo-2020",
spec="https://drafts.csswg.org/css-box/#propdef-margin",
allowed_in_page_rule=True,
allow_quirks="Yes",
@ -19,7 +19,7 @@ ${helpers.two_properties_shorthand(
"margin-block-start",
"margin-block-end",
"specified::LengthPercentageOrAuto::parse",
engines="gecko servo-2013",
engines="gecko servo-2013 servo-2020",
spec="https://drafts.csswg.org/css-logical/#propdef-margin-block"
)}
@ -28,7 +28,7 @@ ${helpers.two_properties_shorthand(
"margin-inline-start",
"margin-inline-end",
"specified::LengthPercentageOrAuto::parse",
engines="gecko servo-2013",
engines="gecko servo-2013 servo-2020",
spec="https://drafts.csswg.org/css-logical/#propdef-margin-inline"
)}

View file

@ -8,7 +8,7 @@ ${helpers.four_sides_shorthand(
"padding",
"padding-%s",
"specified::NonNegativeLengthPercentage::parse",
engines="gecko servo-2013",
engines="gecko servo-2013 servo-2020",
spec="https://drafts.csswg.org/css-box-3/#propdef-padding",
allow_quirks="Yes",
)}
@ -18,7 +18,7 @@ ${helpers.two_properties_shorthand(
"padding-block-start",
"padding-block-end",
"specified::NonNegativeLengthPercentage::parse",
engines="gecko servo-2013",
engines="gecko servo-2013 servo-2020",
spec="https://drafts.csswg.org/css-logical/#propdef-padding-block"
)}
@ -27,7 +27,7 @@ ${helpers.two_properties_shorthand(
"padding-inline-start",
"padding-inline-end",
"specified::NonNegativeLengthPercentage::parse",
engines="gecko servo-2013",
engines="gecko servo-2013 servo-2020",
spec="https://drafts.csswg.org/css-logical/#propdef-padding-inline"
)}

View file

@ -611,7 +611,6 @@ impl Size {
Clone,
ComputeSquaredDistance,
Copy,
Debug,
MallocSizeOf,
PartialEq,
PartialOrd,
@ -623,6 +622,13 @@ impl Size {
#[repr(C)]
pub struct CSSPixelLength(CSSFloat);
impl fmt::Debug for CSSPixelLength {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.fmt(f)?;
f.write_str(" px")
}
}
impl CSSPixelLength {
/// Return a new CSSPixelLength.
#[inline]

View file

@ -619,7 +619,7 @@ impl Parse for Display {
// Now parse the single-keyword `display` values.
Ok(try_match_ident_ignore_ascii_case! { input,
"none" => Display::None,
#[cfg(feature = "gecko")]
#[cfg(any(feature = "servo-layout-2020", feature = "gecko"))]
"contents" => Display::Contents,
"inline-block" => Display::InlineBlock,
#[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]