Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Correctly paint the CSS canvas’ background #26414

Merged
merged 8 commits into from May 15, 2020

Rename BoxTreeRoot/FragmentTreeRoot to BoxTree/FragmentTree

  • Loading branch information
SimonSapin committed May 15, 2020
commit c43ab0c267a246b55f9b9ba05dbeb8c7bb25a9a3
@@ -29,7 +29,7 @@ mod float;
pub mod inline;
mod root;

pub use root::{BoxTreeRoot, FragmentTreeRoot};
pub use root::{BoxTree, FragmentTree};

#[derive(Debug, Serialize)]
pub(crate) struct BlockFormattingContext {
@@ -34,21 +34,33 @@ use style::values::computed::Length;
use style_traits::CSSPixel;

#[derive(Serialize)]
pub struct BoxTreeRoot(BlockFormattingContext);
pub struct BoxTree {
/// Contains typically exactly one block-level box, which was generated by the root element.
/// There may be zero if that element has `display: none`.
root: BlockFormattingContext,
}

#[derive(Serialize)]
pub struct FragmentTreeRoot {
/// The children of the root of the fragment tree.
children: Vec<ArcRefCell<Fragment>>,

/// The scrollable overflow of the root of the fragment tree.
pub struct FragmentTree {
/// Fragments at the top-level of the tree.
///
/// If the root element has `display: none`, there are zero fragments.
/// Otherwise, there is at least one:
///
/// * The first fragment is generated by the root element.
/// * There may be additional fragments generated by positioned boxes
/// that have the initial containing block.
root_fragments: Vec<ArcRefCell<Fragment>>,

/// The scrollable overflow rectangle for the entire tree
/// https://drafts.csswg.org/css-overflow/#scrollable
scrollable_overflow: PhysicalRect<Length>,

/// The containing block used in the layout of this fragment tree.
initial_containing_block: PhysicalRect<Length>,
}

impl BoxTreeRoot {
impl BoxTree {
pub fn construct<'dom, Node>(context: &LayoutContext, root_element: Node) -> Self
where
Node: 'dom + Copy + LayoutNode<'dom> + Send + Sync,
@@ -58,10 +70,12 @@ impl BoxTreeRoot {
// Zero box for `:root { display: none }`, one for the root element otherwise.
assert!(boxes.len() <= 1);

Self(BlockFormattingContext {
contains_floats: contains_floats == ContainsFloats::Yes,
contents: BlockContainer::BlockLevelBoxes(boxes),
})
Self {
root: BlockFormattingContext {
contains_floats: contains_floats == ContainsFloats::Yes,
contents: BlockContainer::BlockLevelBoxes(boxes),
},
}
}
}

@@ -135,12 +149,12 @@ fn construct_for_root_element<'dom>(
(contains_floats, vec![root_box])
}

impl BoxTreeRoot {
impl BoxTree {
pub fn layout(
&self,
layout_context: &LayoutContext,
viewport: euclid::Size2D<f32, CSSPixel>,
) -> FragmentTreeRoot {
) -> FragmentTree {
let style = ComputedValues::initial_values();

// FIXME: use the document’s mode:
@@ -160,61 +174,63 @@ impl BoxTreeRoot {
let dummy_tree_rank = 0;
let mut positioning_context =
PositioningContext::new_for_containing_block_for_all_descendants();
let independent_layout = self.0.layout(
let independent_layout = self.root.layout(
layout_context,
&mut positioning_context,
&(&initial_containing_block).into(),
dummy_tree_rank,
);

let mut children = independent_layout
let mut root_fragments = independent_layout
.fragments
.into_iter()
.map(|fragment| ArcRefCell::new(fragment))
.collect::<Vec<_>>();

// Zero box for `:root { display: none }`, one for the root element otherwise.
assert!(children.len() <= 1);
assert!(root_fragments.len() <= 1);

// There may be more fragments at the top-level
// (for positioned boxes whose containing is the initial containing block)
// but only if there was one fragment for the root element.
positioning_context.layout_initial_containing_block_children(
layout_context,
&initial_containing_block,
&mut children,
&mut root_fragments,
);

let scrollable_overflow = children.iter().fold(PhysicalRect::zero(), |acc, child| {
let child_overflow = child
.borrow()
.scrollable_overflow(&physical_containing_block);

// https://drafts.csswg.org/css-overflow/#scrolling-direction
// We want to clip scrollable overflow on box-start and inline-start
// sides of the scroll container.
//
// FIXME(mrobinson, bug 25564): This should take into account writing
// mode.
let child_overflow = PhysicalRect::new(
euclid::Point2D::zero(),
euclid::Size2D::new(
child_overflow.size.width + child_overflow.origin.x,
child_overflow.size.height + child_overflow.origin.y,
),
);
acc.union(&child_overflow)
});
let scrollable_overflow = root_fragments
.iter()
.fold(PhysicalRect::zero(), |acc, child| {
let child_overflow = child
.borrow()
.scrollable_overflow(&physical_containing_block);

// https://drafts.csswg.org/css-overflow/#scrolling-direction
// We want to clip scrollable overflow on box-start and inline-start
// sides of the scroll container.
//
// FIXME(mrobinson, bug 25564): This should take into account writing
// mode.
let child_overflow = PhysicalRect::new(
euclid::Point2D::zero(),
euclid::Size2D::new(
child_overflow.size.width + child_overflow.origin.x,
child_overflow.size.height + child_overflow.origin.y,
),
);
acc.union(&child_overflow)
});

FragmentTreeRoot {
children,
FragmentTree {
root_fragments,
scrollable_overflow,
initial_containing_block: physical_containing_block,
}
}
}

impl FragmentTreeRoot {
impl FragmentTree {
pub fn build_display_list(&self, builder: &mut crate::display_list::DisplayListBuilder) {
let mut stacking_context = StackingContext::create_root(&builder.wr);
{
@@ -228,7 +244,7 @@ impl FragmentTreeRoot {
),
};

for fragment in &self.children {
for fragment in &self.root_fragments {
fragment.borrow().build_stacking_context_tree(
fragment,
&mut stacking_context_builder,
@@ -245,7 +261,7 @@ impl FragmentTreeRoot {

pub fn print(&self) {
let mut print_tree = PrintTree::new("Fragment Tree".to_string());
for fragment in &self.children {
for fragment in &self.root_fragments {
fragment.borrow().print(&mut print_tree);
}
}
@@ -261,7 +277,7 @@ impl FragmentTreeRoot {
&self,
mut process_func: impl FnMut(&Fragment, &PhysicalRect<Length>) -> Option<T>,
) -> Option<T> {
self.children.iter().find_map(|child| {
self.root_fragments.iter().find_map(|child| {
child
.borrow()
.find(&self.initial_containing_block, &mut process_func)
@@ -5,7 +5,7 @@
//! Supports writing a trace file created during each layout scope
//! that can be viewed by an external tool to make layout debugging easier.

use crate::flow::{BoxTreeRoot, FragmentTreeRoot};
use crate::flow::{BoxTree, FragmentTree};
use serde_json::{to_string, to_value, Value};
use std::cell::RefCell;
use std::fs;
@@ -63,8 +63,8 @@ impl ScopeData {
}

struct State {
fragment_tree: Arc<FragmentTreeRoot>,
box_tree: Arc<BoxTreeRoot>,
fragment_tree: Arc<FragmentTree>,
box_tree: Arc<BoxTree>,
scope_stack: Vec<Box<ScopeData>>,
}

@@ -109,7 +109,7 @@ pub fn generate_unique_debug_id() -> u16 {

/// Begin a layout debug trace. If this has not been called,
/// creating debug scopes has no effect.
pub fn begin_trace(box_tree: Arc<BoxTreeRoot>, fragment_tree: Arc<FragmentTreeRoot>) {
pub fn begin_trace(box_tree: Arc<BoxTree>, fragment_tree: Arc<FragmentTree>) {
assert!(STATE_KEY.with(|ref r| r.borrow().is_none()));

STATE_KEY.with(|ref r| {
@@ -30,7 +30,7 @@ mod style_ext;
pub mod traversal;
pub mod wrapper;

pub use flow::{BoxTreeRoot, FragmentTreeRoot};
pub use flow::{BoxTree, FragmentTree};

use crate::geom::flow_relative::Vec2;
use style::properties::ComputedValues;
@@ -4,7 +4,7 @@

//! Utilities for querying the layout, as needed by the layout thread.
use crate::context::LayoutContext;
use crate::flow::FragmentTreeRoot;
use crate::flow::FragmentTree;
use crate::fragments::Fragment;
use app_units::Au;
use euclid::default::{Point2D, Rect};
@@ -166,14 +166,9 @@ impl LayoutRPC for LayoutRPCImpl {

pub fn process_content_box_request(
requested_node: OpaqueNode,
fragment_tree_root: Option<Arc<FragmentTreeRoot>>,
fragment_tree: Option<Arc<FragmentTree>>,
) -> Option<Rect<Au>> {
let fragment_tree_root = match fragment_tree_root {
Some(fragment_tree_root) => fragment_tree_root,
None => return None,
};

Some(fragment_tree_root.get_content_box_for_node(requested_node))
Some(fragment_tree?.get_content_box_for_node(requested_node))
}

pub fn process_content_boxes_request(_requested_node: OpaqueNode) -> Vec<Rect<Au>> {
@@ -182,14 +177,13 @@ pub fn process_content_boxes_request(_requested_node: OpaqueNode) -> Vec<Rect<Au

pub fn process_node_geometry_request(
requested_node: OpaqueNode,
fragment_tree_root: Option<Arc<FragmentTreeRoot>>,
fragment_tree: Option<Arc<FragmentTree>>,
) -> Rect<i32> {
let fragment_tree_root = match fragment_tree_root {
Some(fragment_tree_root) => fragment_tree_root,
None => return Rect::zero(),
};

fragment_tree_root.get_border_dimensions_for_node(requested_node)
if let Some(fragment_tree) = fragment_tree {
fragment_tree.get_border_dimensions_for_node(requested_node)
} else {
Rect::zero()
}
}

pub fn process_node_scroll_id_request<'dom>(
@@ -212,7 +206,7 @@ pub fn process_resolved_style_request<'dom>(
node: impl LayoutNode<'dom>,
pseudo: &Option<PseudoElement>,
property: &PropertyId,
fragment_tree_root: Option<Arc<FragmentTreeRoot>>,
fragment_tree: Option<Arc<FragmentTree>>,
) -> String {
if !node.as_element().unwrap().has_data() {
return process_resolved_style_request_for_unstyled_node(context, node, pseudo, property);
@@ -286,11 +280,11 @@ pub fn process_resolved_style_request<'dom>(
return computed_style();
}

let fragment_tree_root = match fragment_tree_root {
Some(fragment_tree_root) => fragment_tree_root,
let fragment_tree = match fragment_tree {
Some(fragment_tree) => fragment_tree,
None => return computed_style(),
};
fragment_tree_root
fragment_tree
.find(|fragment, containing_block| {
let box_fragment = match fragment {
Fragment::Box(ref box_fragment) if box_fragment.tag == node.opaque() => {
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.