mirror of
https://github.com/servo/servo.git
synced 2025-08-07 14:35:33 +01:00
Auto merge of #24528 - servo:background-color, r=nox
Layout 2020: run layout and paint background-color
This commit is contained in:
commit
4cdfe23cc8
22 changed files with 258 additions and 62 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -2477,6 +2477,7 @@ version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"app_units",
|
"app_units",
|
||||||
"atomic_refcell",
|
"atomic_refcell",
|
||||||
|
"cssparser",
|
||||||
"euclid",
|
"euclid",
|
||||||
"gfx",
|
"gfx",
|
||||||
"ipc-channel",
|
"ipc-channel",
|
||||||
|
|
|
@ -15,6 +15,7 @@ doctest = false
|
||||||
[dependencies]
|
[dependencies]
|
||||||
app_units = "0.7"
|
app_units = "0.7"
|
||||||
atomic_refcell = "0.1"
|
atomic_refcell = "0.1"
|
||||||
|
cssparser = "0.27"
|
||||||
euclid = "0.20"
|
euclid = "0.20"
|
||||||
gfx = {path = "../gfx"}
|
gfx = {path = "../gfx"}
|
||||||
ipc-channel = "0.12"
|
ipc-channel = "0.12"
|
||||||
|
|
106
components/layout_2020/display_list.rs
Normal file
106
components/layout_2020/display_list.rs
Normal 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(),
|
||||||
|
)
|
||||||
|
}
|
|
@ -210,7 +210,6 @@ where
|
||||||
self.handle_block_level_element(style.clone(), inside, contents, box_slot)
|
self.handle_block_level_element(style.clone(), inside, contents, box_slot)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
DisplayOutside::None => panic!(":("),
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -352,7 +351,6 @@ where
|
||||||
inline_box.last_fragment = true;
|
inline_box.last_fragment = true;
|
||||||
Arc::new(InlineLevelBox::InlineBox(inline_box))
|
Arc::new(InlineLevelBox::InlineBox(inline_box))
|
||||||
},
|
},
|
||||||
DisplayInside::None | DisplayInside::Contents => panic!(":("),
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
self.current_inline_level_boxes().push(box_.clone());
|
self.current_inline_level_boxes().push(box_.clone());
|
||||||
|
|
|
@ -122,7 +122,6 @@ impl InlineFormattingContext {
|
||||||
inline: match outside {
|
inline: match outside {
|
||||||
DisplayOutside::Inline => ifc.inline_position,
|
DisplayOutside::Inline => ifc.inline_position,
|
||||||
DisplayOutside::Block => Length::zero(),
|
DisplayOutside::Block => Length::zero(),
|
||||||
DisplayOutside::None => unreachable!(":("),
|
|
||||||
},
|
},
|
||||||
block: ifc.line_boxes.next_line_block_position,
|
block: ifc.line_boxes.next_line_block_position,
|
||||||
},
|
},
|
||||||
|
|
|
@ -27,7 +27,7 @@ mod float;
|
||||||
pub mod inline;
|
pub mod inline;
|
||||||
mod root;
|
mod root;
|
||||||
|
|
||||||
pub use root::BoxTreeRoot;
|
pub use root::{BoxTreeRoot, FragmentTreeRoot};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct BlockFormattingContext {
|
pub(crate) struct BlockFormattingContext {
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* 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::dom_traversal::{Contents, NodeExt};
|
||||||
use crate::flow::construct::ContainsFloats;
|
use crate::flow::construct::ContainsFloats;
|
||||||
use crate::flow::float::FloatBox;
|
use crate::flow::float::FloatBox;
|
||||||
|
@ -20,9 +21,11 @@ use servo_arc::Arc;
|
||||||
use style::context::SharedStyleContext;
|
use style::context::SharedStyleContext;
|
||||||
use style::properties::ComputedValues;
|
use style::properties::ComputedValues;
|
||||||
use style::values::computed::{Length, LengthOrAuto};
|
use style::values::computed::{Length, LengthOrAuto};
|
||||||
|
use style::Zero;
|
||||||
use style_traits::CSSPixel;
|
use style_traits::CSSPixel;
|
||||||
|
|
||||||
pub struct BoxTreeRoot(BlockFormattingContext);
|
pub struct BoxTreeRoot(BlockFormattingContext);
|
||||||
|
pub struct FragmentTreeRoot(Vec<Fragment>);
|
||||||
|
|
||||||
impl BoxTreeRoot {
|
impl BoxTreeRoot {
|
||||||
pub fn construct<'dom>(
|
pub fn construct<'dom>(
|
||||||
|
@ -95,7 +98,7 @@ fn construct_for_root_element<'dom>(
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BoxTreeRoot {
|
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 {
|
let initial_containing_block_size = Vec2 {
|
||||||
inline: Length::new(viewport.width),
|
inline: Length::new(viewport.width),
|
||||||
block: Length::new(viewport.height),
|
block: Length::new(viewport.height),
|
||||||
|
@ -125,6 +128,31 @@ impl BoxTreeRoot {
|
||||||
.par_iter()
|
.par_iter()
|
||||||
.map(|a| a.layout(&initial_containing_block)),
|
.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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use crate::style_ext::{Direction, WritingMode};
|
use crate::style_ext::{Direction, WritingMode};
|
||||||
|
use std::fmt;
|
||||||
use std::ops::{Add, AddAssign, Sub};
|
use std::ops::{Add, AddAssign, Sub};
|
||||||
use style::values::computed::{Length, LengthOrAuto, LengthPercentage, LengthPercentageOrAuto};
|
use style::values::computed::{Length, LengthOrAuto, LengthPercentage, LengthPercentageOrAuto};
|
||||||
use style::Zero;
|
use style::Zero;
|
||||||
|
@ -13,7 +14,7 @@ pub type Size<U> = euclid::Size2D<f32, U>;
|
||||||
pub type Rect<U> = euclid::Rect<f32, U>;
|
pub type Rect<U> = euclid::Rect<f32, U>;
|
||||||
|
|
||||||
pub(crate) mod physical {
|
pub(crate) mod physical {
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone)]
|
||||||
pub(crate) struct Vec2<T> {
|
pub(crate) struct Vec2<T> {
|
||||||
pub x: T,
|
pub x: T,
|
||||||
pub y: T,
|
pub y: T,
|
||||||
|
@ -35,7 +36,7 @@ pub(crate) mod physical {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) mod flow_relative {
|
pub(crate) mod flow_relative {
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone)]
|
||||||
pub(crate) struct Vec2<T> {
|
pub(crate) struct Vec2<T> {
|
||||||
pub inline: T,
|
pub inline: T,
|
||||||
pub block: 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>
|
impl<T> Add<&'_ physical::Vec2<T>> for &'_ physical::Vec2<T>
|
||||||
where
|
where
|
||||||
T: Add<Output = T> + Copy,
|
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()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ use style::Zero;
|
||||||
|
|
||||||
pub mod context;
|
pub mod context;
|
||||||
pub mod data;
|
pub mod data;
|
||||||
|
pub mod display_list;
|
||||||
mod dom_traversal;
|
mod dom_traversal;
|
||||||
mod element_data;
|
mod element_data;
|
||||||
mod flow;
|
mod flow;
|
||||||
|
@ -30,18 +31,17 @@ mod style_ext;
|
||||||
pub mod traversal;
|
pub mod traversal;
|
||||||
pub mod wrapper;
|
pub mod wrapper;
|
||||||
|
|
||||||
pub use flow::BoxTreeRoot;
|
pub use flow::{BoxTreeRoot, FragmentTreeRoot};
|
||||||
|
|
||||||
use crate::dom_traversal::{Contents, NodeExt};
|
use crate::dom_traversal::{Contents, NodeExt};
|
||||||
use crate::flow::{BlockFormattingContext, FlowChildren};
|
use crate::flow::{BlockFormattingContext, FlowChildren};
|
||||||
use crate::geom::flow_relative::Vec2;
|
use crate::geom::flow_relative::Vec2;
|
||||||
use crate::positioned::AbsolutelyPositionedFragment;
|
use crate::positioned::AbsolutelyPositionedFragment;
|
||||||
use crate::replaced::ReplacedContent;
|
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 servo_arc::Arc;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use style::context::SharedStyleContext;
|
use style::context::SharedStyleContext;
|
||||||
use style::values::specified::box_::DisplayInside;
|
|
||||||
|
|
||||||
/// https://drafts.csswg.org/css-display/#independent-formatting-context
|
/// https://drafts.csswg.org/css-display/#independent-formatting-context
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -73,7 +73,6 @@ impl IndependentFormattingContext {
|
||||||
non_replaced,
|
non_replaced,
|
||||||
))
|
))
|
||||||
},
|
},
|
||||||
DisplayInside::None | DisplayInside::Contents => panic!(":("),
|
|
||||||
},
|
},
|
||||||
Err(replaced) => IndependentFormattingContext::Replaced(replaced),
|
Err(replaced) => IndependentFormattingContext::Replaced(replaced),
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,14 +4,12 @@
|
||||||
|
|
||||||
use crate::geom::{flow_relative, physical};
|
use crate::geom::{flow_relative, physical};
|
||||||
use style::properties::ComputedValues;
|
use style::properties::ComputedValues;
|
||||||
use style::values::computed::{
|
use style::values::computed::{Length, LengthPercentage, LengthPercentageOrAuto, Size};
|
||||||
Display as PackedDisplay, 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::direction::T as Direction;
|
||||||
pub use style::computed_values::position::T as Position;
|
pub use style::computed_values::position::T as Position;
|
||||||
pub use style::computed_values::writing_mode::T as WritingMode;
|
pub use style::computed_values::writing_mode::T as WritingMode;
|
||||||
pub use style::values::specified::box_::{DisplayInside, DisplayOutside};
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Eq, PartialEq)]
|
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||||
pub(crate) enum Display {
|
pub(crate) enum Display {
|
||||||
|
@ -31,6 +29,18 @@ pub(crate) enum DisplayGeneratingBox {
|
||||||
// https://drafts.csswg.org/css-display-3/#layout-specific-display
|
// 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 {
|
pub(crate) trait ComputedValuesExt {
|
||||||
fn writing_mode(&self) -> (WritingMode, Direction);
|
fn writing_mode(&self) -> (WritingMode, Direction);
|
||||||
fn box_offsets(&self) -> flow_relative::Sides<LengthPercentageOrAuto>;
|
fn box_offsets(&self) -> flow_relative::Sides<LengthPercentageOrAuto>;
|
||||||
|
@ -105,18 +115,27 @@ impl ComputedValuesExt for ComputedValues {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<PackedDisplay> for Display {
|
impl From<stylo::Display> for Display {
|
||||||
fn from(packed_display: PackedDisplay) -> Self {
|
fn from(packed: stylo::Display) -> Self {
|
||||||
if packed_display == PackedDisplay::None {
|
let inside = match packed.inside() {
|
||||||
return Self::None;
|
stylo::DisplayInside::Flow => DisplayInside::Flow,
|
||||||
}
|
stylo::DisplayInside::FlowRoot => DisplayInside::FlowRoot,
|
||||||
if packed_display == PackedDisplay::Contents {
|
|
||||||
return Self::Contents;
|
// These should not be values of DisplayInside, but oh well
|
||||||
}
|
stylo::DisplayInside::None => return Display::None,
|
||||||
Self::GeneratingBox(DisplayGeneratingBox::OutsideInside {
|
stylo::DisplayInside::Contents => return Display::Contents,
|
||||||
outside: packed_display.outside(),
|
};
|
||||||
inside: packed_display.inside(),
|
let outside = match packed.outside() {
|
||||||
// list_item: packed_display.is_list_item(),
|
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(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,7 @@ use gfx_traits::{node_id_from_scroll_id, Epoch};
|
||||||
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
|
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
|
||||||
use ipc_channel::router::ROUTER;
|
use ipc_channel::router::ROUTER;
|
||||||
use layout::context::LayoutContext;
|
use layout::context::LayoutContext;
|
||||||
|
use layout::display_list::DisplayListBuilder;
|
||||||
use layout::query::{
|
use layout::query::{
|
||||||
process_content_box_request, process_content_boxes_request, LayoutRPCImpl, LayoutThreadData,
|
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.
|
/// The number of Web fonts that have been requested but not yet loaded.
|
||||||
outstanding_web_fonts: Arc<AtomicUsize>,
|
outstanding_web_fonts: Arc<AtomicUsize>,
|
||||||
|
|
||||||
/// The root box tree.
|
/// The root of the box tree.
|
||||||
box_tree_root: RefCell<Option<BoxTreeRoot>>,
|
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
|
/// The document-specific shared lock used for author-origin stylesheets
|
||||||
document_shared_lock: Option<SharedRwLock>,
|
document_shared_lock: Option<SharedRwLock>,
|
||||||
|
@ -497,6 +501,7 @@ impl LayoutThread {
|
||||||
_new_animations_receiver: new_animations_receiver,
|
_new_animations_receiver: new_animations_receiver,
|
||||||
outstanding_web_fonts: Arc::new(AtomicUsize::new(0)),
|
outstanding_web_fonts: Arc::new(AtomicUsize::new(0)),
|
||||||
box_tree_root: Default::default(),
|
box_tree_root: Default::default(),
|
||||||
|
fragment_tree_root: Default::default(),
|
||||||
document_shared_lock: None,
|
document_shared_lock: None,
|
||||||
epoch: Cell::new(Epoch(0)),
|
epoch: Cell::new(Epoch(0)),
|
||||||
viewport_size: Size2D::new(Au(0), Au(0)),
|
viewport_size: Size2D::new(Au(0), Au(0)),
|
||||||
|
@ -1084,7 +1089,12 @@ impl LayoutThread {
|
||||||
let shared = DomTraversal::<ServoLayoutElement>::shared_context(&traversal);
|
let shared = DomTraversal::<ServoLayoutElement>::shared_context(&traversal);
|
||||||
let box_tree =
|
let box_tree =
|
||||||
BoxTreeRoot::construct(shared, document.root_element().unwrap().as_node());
|
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.box_tree_root.borrow_mut() = Some(box_tree);
|
||||||
|
*self.fragment_tree_root.borrow_mut() = Some(fragment_tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
for element in elements_with_snapshot {
|
for element in elements_with_snapshot {
|
||||||
|
@ -1099,7 +1109,9 @@ impl LayoutThread {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform post-style recalculation layout passes.
|
// 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.first_reflow.set(false);
|
||||||
self.respond_to_query_if_necessary(&data.reflow_goal, &mut *rw_data, &mut layout_context);
|
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 author_guard = author_shared_lock.read();
|
||||||
let ua_or_user_guard = UA_STYLESHEETS.shared_lock.read();
|
let ua_or_user_guard = UA_STYLESHEETS.shared_lock.read();
|
||||||
let _guards = StylesheetGuards {
|
let _guards = StylesheetGuards {
|
||||||
|
@ -1229,12 +1244,13 @@ impl LayoutThread {
|
||||||
ua_or_user: &ua_or_user_guard,
|
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(
|
fn perform_post_style_recalc_layout_passes(
|
||||||
&self,
|
&self,
|
||||||
|
fragment_tree: &layout::FragmentTreeRoot,
|
||||||
reflow_goal: &ReflowGoal,
|
reflow_goal: &ReflowGoal,
|
||||||
document: Option<&ServoLayoutDocument>,
|
document: Option<&ServoLayoutDocument>,
|
||||||
) {
|
) {
|
||||||
|
@ -1252,16 +1268,13 @@ impl LayoutThread {
|
||||||
document.will_paint();
|
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.width.to_f32_px(),
|
||||||
self.viewport_size.height.to_f32_px(),
|
self.viewport_size.height.to_f32_px(),
|
||||||
);
|
));
|
||||||
|
let mut display_list = DisplayListBuilder::new(self.id.to_webrender(), viewport_size);
|
||||||
let viewport_size = webrender_api::units::LayoutSize::from_untyped(viewport_size);
|
let is_contentful =
|
||||||
|
fragment_tree.build_display_list(&mut display_list, self.id, viewport_size);
|
||||||
let display_list =
|
|
||||||
webrender_api::DisplayListBuilder::new(self.id.to_webrender(), viewport_size);
|
|
||||||
let is_contentful = false;
|
|
||||||
|
|
||||||
debug!("Layout done!");
|
debug!("Layout done!");
|
||||||
|
|
||||||
|
@ -1273,14 +1286,14 @@ impl LayoutThread {
|
||||||
// sending the display list to WebRender in order to set time related
|
// sending the display list to WebRender in order to set time related
|
||||||
// Progressive Web Metrics.
|
// Progressive Web Metrics.
|
||||||
self.paint_time_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();
|
let mut txn = webrender_api::Transaction::new();
|
||||||
txn.set_display_list(
|
txn.set_display_list(
|
||||||
webrender_api::Epoch(epoch.0),
|
webrender_api::Epoch(epoch.0),
|
||||||
None,
|
None,
|
||||||
viewport_size,
|
viewport_size,
|
||||||
display_list.finalize(),
|
display_list.wr.finalize(),
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
txn.generate_frame();
|
txn.generate_frame();
|
||||||
|
|
|
@ -24,7 +24,6 @@
|
||||||
"border-%s-color" % side_name, "Color",
|
"border-%s-color" % side_name, "Color",
|
||||||
"computed_value::T::currentcolor()",
|
"computed_value::T::currentcolor()",
|
||||||
engines="gecko servo-2013 servo-2020",
|
engines="gecko servo-2013 servo-2020",
|
||||||
servo_2020_pref="layout.2020.unimplemented",
|
|
||||||
alias=maybe_moz_logical_alias(engine, side, "-moz-border-%s-color"),
|
alias=maybe_moz_logical_alias(engine, side, "-moz-border-%s-color"),
|
||||||
spec=maybe_logical_spec(side, "color"),
|
spec=maybe_logical_spec(side, "color"),
|
||||||
animation_value_type="AnimatedColor",
|
animation_value_type="AnimatedColor",
|
||||||
|
@ -51,7 +50,6 @@
|
||||||
"BorderSideWidth",
|
"BorderSideWidth",
|
||||||
"crate::values::computed::NonNegativeLength::new(3.)",
|
"crate::values::computed::NonNegativeLength::new(3.)",
|
||||||
engines="gecko servo-2013 servo-2020",
|
engines="gecko servo-2013 servo-2020",
|
||||||
servo_2020_pref="layout.2020.unimplemented",
|
|
||||||
computed_type="crate::values::computed::NonNegativeLength",
|
computed_type="crate::values::computed::NonNegativeLength",
|
||||||
alias=maybe_moz_logical_alias(engine, side, "-moz-border-%s-width"),
|
alias=maybe_moz_logical_alias(engine, side, "-moz-border-%s-width"),
|
||||||
spec=maybe_logical_spec(side, "width"),
|
spec=maybe_logical_spec(side, "width"),
|
||||||
|
|
|
@ -63,7 +63,6 @@ ${helpers.predefined_type(
|
||||||
"Float",
|
"Float",
|
||||||
"computed::Float::None",
|
"computed::Float::None",
|
||||||
engines="gecko servo-2013 servo-2020",
|
engines="gecko servo-2013 servo-2020",
|
||||||
servo_2020_pref="layout.2020.unimplemented",
|
|
||||||
initial_specified_value="specified::Float::None",
|
initial_specified_value="specified::Float::None",
|
||||||
spec="https://drafts.csswg.org/css-box/#propdef-float",
|
spec="https://drafts.csswg.org/css-box/#propdef-float",
|
||||||
animation_value_type="discrete",
|
animation_value_type="discrete",
|
||||||
|
|
|
@ -29,6 +29,7 @@ ${helpers.single_keyword(
|
||||||
rl=horizontal-tb rl-tb=horizontal-tb \
|
rl=horizontal-tb rl-tb=horizontal-tb \
|
||||||
tb=vertical-rl tb-rl=vertical-rl",
|
tb=vertical-rl tb-rl=vertical-rl",
|
||||||
servo_2013_pref="layout.writing-mode.enabled",
|
servo_2013_pref="layout.writing-mode.enabled",
|
||||||
|
servo_2020_pref="layout.writing-mode.enabled",
|
||||||
animation_value_type="none",
|
animation_value_type="none",
|
||||||
spec="https://drafts.csswg.org/css-writing-modes/#propdef-writing-mode",
|
spec="https://drafts.csswg.org/css-writing-modes/#propdef-writing-mode",
|
||||||
servo_restyle_damage="rebuild_and_reflow",
|
servo_restyle_damage="rebuild_and_reflow",
|
||||||
|
@ -38,6 +39,7 @@ ${helpers.single_keyword(
|
||||||
"direction",
|
"direction",
|
||||||
"ltr rtl",
|
"ltr rtl",
|
||||||
engines="gecko servo-2013 servo-2020",
|
engines="gecko servo-2013 servo-2020",
|
||||||
|
servo_2020_pref="layout.2020.unimplemented",
|
||||||
animation_value_type="none",
|
animation_value_type="none",
|
||||||
spec="https://drafts.csswg.org/css-writing-modes/#propdef-direction",
|
spec="https://drafts.csswg.org/css-writing-modes/#propdef-direction",
|
||||||
needs_conversion=True,
|
needs_conversion=True,
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
"LengthPercentageOrAuto",
|
"LengthPercentageOrAuto",
|
||||||
"computed::LengthPercentageOrAuto::zero()",
|
"computed::LengthPercentageOrAuto::zero()",
|
||||||
engines="gecko servo-2013 servo-2020",
|
engines="gecko servo-2013 servo-2020",
|
||||||
servo_2020_pref="layout.2020.unimplemented",
|
|
||||||
alias=maybe_moz_logical_alias(engine, side, "-moz-margin-%s"),
|
alias=maybe_moz_logical_alias(engine, side, "-moz-margin-%s"),
|
||||||
allow_quirks="No" if side[1] else "Yes",
|
allow_quirks="No" if side[1] else "Yes",
|
||||||
animation_value_type="ComputedValue",
|
animation_value_type="ComputedValue",
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
"NonNegativeLengthPercentage",
|
"NonNegativeLengthPercentage",
|
||||||
"computed::NonNegativeLengthPercentage::zero()",
|
"computed::NonNegativeLengthPercentage::zero()",
|
||||||
engines="gecko servo-2013 servo-2020",
|
engines="gecko servo-2013 servo-2020",
|
||||||
servo_2020_pref="layout.2020.unimplemented",
|
|
||||||
alias=maybe_moz_logical_alias(engine, side, "-moz-padding-%s"),
|
alias=maybe_moz_logical_alias(engine, side, "-moz-padding-%s"),
|
||||||
animation_value_type="NonNegativeLengthPercentage",
|
animation_value_type="NonNegativeLengthPercentage",
|
||||||
logical=side[1],
|
logical=side[1],
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
"LengthPercentageOrAuto",
|
"LengthPercentageOrAuto",
|
||||||
"computed::LengthPercentageOrAuto::auto()",
|
"computed::LengthPercentageOrAuto::auto()",
|
||||||
engines="gecko servo-2013 servo-2020",
|
engines="gecko servo-2013 servo-2020",
|
||||||
servo_2020_pref="layout.2020.unimplemented",
|
|
||||||
spec="https://www.w3.org/TR/CSS2/visuren.html#propdef-%s" % side,
|
spec="https://www.w3.org/TR/CSS2/visuren.html#propdef-%s" % side,
|
||||||
animation_value_type="ComputedValue",
|
animation_value_type="ComputedValue",
|
||||||
allow_quirks="Yes",
|
allow_quirks="Yes",
|
||||||
|
@ -30,7 +29,6 @@
|
||||||
"LengthPercentageOrAuto",
|
"LengthPercentageOrAuto",
|
||||||
"computed::LengthPercentageOrAuto::auto()",
|
"computed::LengthPercentageOrAuto::auto()",
|
||||||
engines="gecko servo-2013 servo-2020",
|
engines="gecko servo-2013 servo-2020",
|
||||||
servo_2020_pref="layout.2020.unimplemented",
|
|
||||||
spec="https://drafts.csswg.org/css-logical-props/#propdef-inset-%s" % side,
|
spec="https://drafts.csswg.org/css-logical-props/#propdef-inset-%s" % side,
|
||||||
alias="offset-%s:layout.css.offset-logical-properties.enabled" % side,
|
alias="offset-%s:layout.css.offset-logical-properties.enabled" % side,
|
||||||
animation_value_type="ComputedValue",
|
animation_value_type="ComputedValue",
|
||||||
|
@ -278,7 +276,6 @@ ${helpers.predefined_type(
|
||||||
"Size",
|
"Size",
|
||||||
"computed::Size::auto()",
|
"computed::Size::auto()",
|
||||||
engines="gecko servo-2013 servo-2020",
|
engines="gecko servo-2013 servo-2020",
|
||||||
servo_2020_pref="layout.2020.unimplemented",
|
|
||||||
logical=logical,
|
logical=logical,
|
||||||
logical_group="size",
|
logical_group="size",
|
||||||
allow_quirks="No" if logical else "Yes",
|
allow_quirks="No" if logical else "Yes",
|
||||||
|
|
|
@ -9,7 +9,7 @@ ${helpers.four_sides_shorthand(
|
||||||
"border-color",
|
"border-color",
|
||||||
"border-%s-color",
|
"border-%s-color",
|
||||||
"specified::Color::parse",
|
"specified::Color::parse",
|
||||||
engines="gecko servo-2013",
|
engines="gecko servo-2013 servo-2020",
|
||||||
spec="https://drafts.csswg.org/css-backgrounds/#border-color",
|
spec="https://drafts.csswg.org/css-backgrounds/#border-color",
|
||||||
allow_quirks="Yes",
|
allow_quirks="Yes",
|
||||||
)}
|
)}
|
||||||
|
@ -18,14 +18,14 @@ ${helpers.four_sides_shorthand(
|
||||||
"border-style",
|
"border-style",
|
||||||
"border-%s-style",
|
"border-%s-style",
|
||||||
"specified::BorderStyle::parse",
|
"specified::BorderStyle::parse",
|
||||||
engines="gecko servo-2013",
|
engines="gecko servo-2013 servo-2020",
|
||||||
needs_context=False,
|
needs_context=False,
|
||||||
spec="https://drafts.csswg.org/css-backgrounds/#border-style",
|
spec="https://drafts.csswg.org/css-backgrounds/#border-style",
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<%helpers:shorthand
|
<%helpers:shorthand
|
||||||
name="border-width"
|
name="border-width"
|
||||||
engines="gecko servo-2013"
|
engines="gecko servo-2013 servo-2020"
|
||||||
sub_properties="${
|
sub_properties="${
|
||||||
' '.join('border-%s-width' % side
|
' '.join('border-%s-width' % side
|
||||||
for side in PHYSICAL_SIDES)}"
|
for side in PHYSICAL_SIDES)}"
|
||||||
|
|
|
@ -8,7 +8,7 @@ ${helpers.four_sides_shorthand(
|
||||||
"margin",
|
"margin",
|
||||||
"margin-%s",
|
"margin-%s",
|
||||||
"specified::LengthPercentageOrAuto::parse",
|
"specified::LengthPercentageOrAuto::parse",
|
||||||
engines="gecko servo-2013",
|
engines="gecko servo-2013 servo-2020",
|
||||||
spec="https://drafts.csswg.org/css-box/#propdef-margin",
|
spec="https://drafts.csswg.org/css-box/#propdef-margin",
|
||||||
allowed_in_page_rule=True,
|
allowed_in_page_rule=True,
|
||||||
allow_quirks="Yes",
|
allow_quirks="Yes",
|
||||||
|
@ -19,7 +19,7 @@ ${helpers.two_properties_shorthand(
|
||||||
"margin-block-start",
|
"margin-block-start",
|
||||||
"margin-block-end",
|
"margin-block-end",
|
||||||
"specified::LengthPercentageOrAuto::parse",
|
"specified::LengthPercentageOrAuto::parse",
|
||||||
engines="gecko servo-2013",
|
engines="gecko servo-2013 servo-2020",
|
||||||
spec="https://drafts.csswg.org/css-logical/#propdef-margin-block"
|
spec="https://drafts.csswg.org/css-logical/#propdef-margin-block"
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ ${helpers.two_properties_shorthand(
|
||||||
"margin-inline-start",
|
"margin-inline-start",
|
||||||
"margin-inline-end",
|
"margin-inline-end",
|
||||||
"specified::LengthPercentageOrAuto::parse",
|
"specified::LengthPercentageOrAuto::parse",
|
||||||
engines="gecko servo-2013",
|
engines="gecko servo-2013 servo-2020",
|
||||||
spec="https://drafts.csswg.org/css-logical/#propdef-margin-inline"
|
spec="https://drafts.csswg.org/css-logical/#propdef-margin-inline"
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ ${helpers.four_sides_shorthand(
|
||||||
"padding",
|
"padding",
|
||||||
"padding-%s",
|
"padding-%s",
|
||||||
"specified::NonNegativeLengthPercentage::parse",
|
"specified::NonNegativeLengthPercentage::parse",
|
||||||
engines="gecko servo-2013",
|
engines="gecko servo-2013 servo-2020",
|
||||||
spec="https://drafts.csswg.org/css-box-3/#propdef-padding",
|
spec="https://drafts.csswg.org/css-box-3/#propdef-padding",
|
||||||
allow_quirks="Yes",
|
allow_quirks="Yes",
|
||||||
)}
|
)}
|
||||||
|
@ -18,7 +18,7 @@ ${helpers.two_properties_shorthand(
|
||||||
"padding-block-start",
|
"padding-block-start",
|
||||||
"padding-block-end",
|
"padding-block-end",
|
||||||
"specified::NonNegativeLengthPercentage::parse",
|
"specified::NonNegativeLengthPercentage::parse",
|
||||||
engines="gecko servo-2013",
|
engines="gecko servo-2013 servo-2020",
|
||||||
spec="https://drafts.csswg.org/css-logical/#propdef-padding-block"
|
spec="https://drafts.csswg.org/css-logical/#propdef-padding-block"
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ ${helpers.two_properties_shorthand(
|
||||||
"padding-inline-start",
|
"padding-inline-start",
|
||||||
"padding-inline-end",
|
"padding-inline-end",
|
||||||
"specified::NonNegativeLengthPercentage::parse",
|
"specified::NonNegativeLengthPercentage::parse",
|
||||||
engines="gecko servo-2013",
|
engines="gecko servo-2013 servo-2020",
|
||||||
spec="https://drafts.csswg.org/css-logical/#propdef-padding-inline"
|
spec="https://drafts.csswg.org/css-logical/#propdef-padding-inline"
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
|
@ -611,7 +611,6 @@ impl Size {
|
||||||
Clone,
|
Clone,
|
||||||
ComputeSquaredDistance,
|
ComputeSquaredDistance,
|
||||||
Copy,
|
Copy,
|
||||||
Debug,
|
|
||||||
MallocSizeOf,
|
MallocSizeOf,
|
||||||
PartialEq,
|
PartialEq,
|
||||||
PartialOrd,
|
PartialOrd,
|
||||||
|
@ -623,6 +622,13 @@ impl Size {
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct CSSPixelLength(CSSFloat);
|
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 {
|
impl CSSPixelLength {
|
||||||
/// Return a new CSSPixelLength.
|
/// Return a new CSSPixelLength.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -619,7 +619,7 @@ impl Parse for Display {
|
||||||
// Now parse the single-keyword `display` values.
|
// Now parse the single-keyword `display` values.
|
||||||
Ok(try_match_ident_ignore_ascii_case! { input,
|
Ok(try_match_ident_ignore_ascii_case! { input,
|
||||||
"none" => Display::None,
|
"none" => Display::None,
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(any(feature = "servo-layout-2020", feature = "gecko"))]
|
||||||
"contents" => Display::Contents,
|
"contents" => Display::Contents,
|
||||||
"inline-block" => Display::InlineBlock,
|
"inline-block" => Display::InlineBlock,
|
||||||
#[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
|
#[cfg(any(feature = "servo-layout-2013", feature = "gecko"))]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue