Skip to content

Commit

Permalink
Auto merge of #24528 - servo:background-color, r=nox
Browse files Browse the repository at this point in the history
Layout 2020: run layout and paint background-color
  • Loading branch information
bors-servo committed Oct 24, 2019
2 parents dc8be8f + 59f6852 commit 4cdfe23
Show file tree
Hide file tree
Showing 22 changed files with 258 additions and 62 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions components/layout_2020/Cargo.toml
Expand Up @@ -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"
Expand Down
106 changes: 106 additions & 0 deletions components/layout_2020/display_list.rs
@@ -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(),
)
}
2 changes: 0 additions & 2 deletions components/layout_2020/flow/construct.rs
Expand Up @@ -210,7 +210,6 @@ where
self.handle_block_level_element(style.clone(), inside, contents, box_slot)
}
},
DisplayOutside::None => panic!(":("),
},
}
}
Expand Down Expand Up @@ -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());
Expand Down
1 change: 0 additions & 1 deletion components/layout_2020/flow/inline.rs
Expand Up @@ -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,
},
Expand Down
2 changes: 1 addition & 1 deletion components/layout_2020/flow/mod.rs
Expand Up @@ -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 {
Expand Down
32 changes: 30 additions & 2 deletions components/layout_2020/flow/root.rs
Expand Up @@ -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;
Expand All @@ -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>(
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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
}
}
36 changes: 34 additions & 2 deletions components/layout_2020/geom.rs
Expand Up @@ -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;
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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()),
}
}
}
7 changes: 3 additions & 4 deletions components/layout_2020/lib.rs
Expand Up @@ -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;
Expand All @@ -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)]
Expand Down Expand Up @@ -73,7 +73,6 @@ impl IndependentFormattingContext {
non_replaced,
))
},
DisplayInside::None | DisplayInside::Contents => panic!(":("),
},
Err(replaced) => IndependentFormattingContext::Replaced(replaced),
}
Expand Down
51 changes: 35 additions & 16 deletions components/layout_2020/style_ext.rs
Expand Up @@ -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 {
Expand All @@ -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>;
Expand Down Expand Up @@ -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(),
})
}
}
Expand Down

0 comments on commit 4cdfe23

Please sign in to comment.