mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
Make layout_2020 be layout_2013
This commit is contained in:
parent
87e7e3d429
commit
4846d76e82
49 changed files with 34595 additions and 22 deletions
193
components/layout_2020/sequential.rs
Normal file
193
components/layout_2020/sequential.rs
Normal file
|
@ -0,0 +1,193 @@
|
|||
/* 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/. */
|
||||
|
||||
//! Implements sequential traversals over the DOM and flow trees.
|
||||
|
||||
use crate::context::LayoutContext;
|
||||
use crate::display_list::items::{self, CommonDisplayItem, DisplayItem, DisplayListSection};
|
||||
use crate::display_list::{DisplayListBuildState, StackingContextCollectionState};
|
||||
use crate::floats::SpeculatedFloatPlacement;
|
||||
use crate::flow::{Flow, FlowFlags, GetBaseFlow, ImmutableFlowUtils};
|
||||
use crate::fragment::{CoordinateSystem, FragmentBorderBoxIterator};
|
||||
use crate::generated_content::ResolveGeneratedContent;
|
||||
use crate::incremental::RelayoutMode;
|
||||
use crate::traversal::{AssignBSizes, AssignISizes, BubbleISizes, BuildDisplayList};
|
||||
use crate::traversal::{InorderFlowTraversal, PostorderFlowTraversal, PreorderFlowTraversal};
|
||||
use app_units::Au;
|
||||
use euclid::{Point2D, Rect, Size2D, Vector2D};
|
||||
use servo_config::opts;
|
||||
use style::servo::restyle_damage::ServoRestyleDamage;
|
||||
use webrender_api::units::LayoutPoint;
|
||||
|
||||
pub fn resolve_generated_content(root: &mut dyn Flow, layout_context: &LayoutContext) {
|
||||
ResolveGeneratedContent::new(&layout_context).traverse(root, 0);
|
||||
}
|
||||
|
||||
/// Run the main layout passes sequentially.
|
||||
pub fn reflow(root: &mut dyn Flow, layout_context: &LayoutContext, relayout_mode: RelayoutMode) {
|
||||
fn doit(
|
||||
flow: &mut dyn Flow,
|
||||
assign_inline_sizes: AssignISizes,
|
||||
assign_block_sizes: AssignBSizes,
|
||||
relayout_mode: RelayoutMode,
|
||||
) {
|
||||
// Force reflow children during this traversal. This is needed when we failed
|
||||
// the float speculation of a block formatting context and need to fix it.
|
||||
if relayout_mode == RelayoutMode::Force {
|
||||
flow.mut_base()
|
||||
.restyle_damage
|
||||
.insert(ServoRestyleDamage::REFLOW_OUT_OF_FLOW | ServoRestyleDamage::REFLOW);
|
||||
}
|
||||
|
||||
if assign_inline_sizes.should_process(flow) {
|
||||
assign_inline_sizes.process(flow);
|
||||
}
|
||||
|
||||
for kid in flow.mut_base().child_iter_mut() {
|
||||
doit(kid, assign_inline_sizes, assign_block_sizes, relayout_mode);
|
||||
}
|
||||
|
||||
if assign_block_sizes.should_process(flow) {
|
||||
assign_block_sizes.process(flow);
|
||||
}
|
||||
}
|
||||
|
||||
if opts::get().bubble_inline_sizes_separately {
|
||||
let bubble_inline_sizes = BubbleISizes {
|
||||
layout_context: &layout_context,
|
||||
};
|
||||
bubble_inline_sizes.traverse(root);
|
||||
}
|
||||
|
||||
let assign_inline_sizes = AssignISizes {
|
||||
layout_context: &layout_context,
|
||||
};
|
||||
let assign_block_sizes = AssignBSizes {
|
||||
layout_context: &layout_context,
|
||||
};
|
||||
|
||||
doit(root, assign_inline_sizes, assign_block_sizes, relayout_mode);
|
||||
}
|
||||
|
||||
pub fn build_display_list_for_subtree<'a>(
|
||||
flow_root: &mut dyn Flow,
|
||||
layout_context: &'a LayoutContext,
|
||||
background_color: webrender_api::ColorF,
|
||||
client_size: Size2D<Au>,
|
||||
) -> DisplayListBuildState<'a> {
|
||||
let mut state = StackingContextCollectionState::new(layout_context.id);
|
||||
flow_root.collect_stacking_contexts(&mut state);
|
||||
|
||||
let mut state = DisplayListBuildState::new(layout_context, state);
|
||||
|
||||
// Create a base rectangle for the page background based on the root
|
||||
// background color.
|
||||
let base = state.create_base_display_item(
|
||||
Rect::new(Point2D::new(Au::new(0), Au::new(0)), client_size),
|
||||
flow_root.as_block().fragment.node,
|
||||
None,
|
||||
DisplayListSection::BackgroundAndBorders,
|
||||
);
|
||||
state.add_display_item(DisplayItem::Rectangle(CommonDisplayItem::new(
|
||||
base,
|
||||
webrender_api::RectangleDisplayItem {
|
||||
color: background_color,
|
||||
common: items::empty_common_item_properties(),
|
||||
},
|
||||
)));
|
||||
|
||||
let mut build_display_list = BuildDisplayList { state: state };
|
||||
build_display_list.traverse(flow_root);
|
||||
build_display_list.state
|
||||
}
|
||||
|
||||
pub fn iterate_through_flow_tree_fragment_border_boxes(
|
||||
root: &mut dyn Flow,
|
||||
iterator: &mut dyn FragmentBorderBoxIterator,
|
||||
) {
|
||||
fn doit(
|
||||
flow: &mut dyn Flow,
|
||||
level: i32,
|
||||
iterator: &mut dyn FragmentBorderBoxIterator,
|
||||
stacking_context_position: &Point2D<Au>,
|
||||
) {
|
||||
flow.iterate_through_fragment_border_boxes(iterator, level, stacking_context_position);
|
||||
|
||||
for kid in flow.mut_base().child_iter_mut() {
|
||||
let mut stacking_context_position = *stacking_context_position;
|
||||
if kid.is_block_flow() && kid.as_block().fragment.establishes_stacking_context() {
|
||||
stacking_context_position =
|
||||
Point2D::new(kid.as_block().fragment.margin.inline_start, Au(0)) +
|
||||
kid.base().stacking_relative_position +
|
||||
stacking_context_position.to_vector();
|
||||
let relative_position = kid
|
||||
.as_block()
|
||||
.stacking_relative_border_box(CoordinateSystem::Own);
|
||||
if let Some(matrix) = kid.as_block().fragment.transform_matrix(&relative_position) {
|
||||
let transform_matrix = matrix.transform_point2d(&LayoutPoint::zero()).unwrap();
|
||||
stacking_context_position = stacking_context_position +
|
||||
Vector2D::new(
|
||||
Au::from_f32_px(transform_matrix.x),
|
||||
Au::from_f32_px(transform_matrix.y),
|
||||
)
|
||||
}
|
||||
}
|
||||
doit(kid, level + 1, iterator, &stacking_context_position);
|
||||
}
|
||||
}
|
||||
|
||||
doit(root, 0, iterator, &Point2D::zero());
|
||||
}
|
||||
|
||||
pub fn store_overflow(layout_context: &LayoutContext, flow: &mut dyn Flow) {
|
||||
if !flow
|
||||
.base()
|
||||
.restyle_damage
|
||||
.contains(ServoRestyleDamage::STORE_OVERFLOW)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for kid in flow.mut_base().child_iter_mut() {
|
||||
store_overflow(layout_context, kid);
|
||||
}
|
||||
|
||||
flow.store_overflow(layout_context);
|
||||
|
||||
flow.mut_base()
|
||||
.restyle_damage
|
||||
.remove(ServoRestyleDamage::STORE_OVERFLOW);
|
||||
}
|
||||
|
||||
/// Guesses how much inline size will be taken up by floats on the left and right sides of the
|
||||
/// given flow. This is needed to speculatively calculate the inline sizes of block formatting
|
||||
/// contexts. The speculation typically succeeds, but if it doesn't we have to lay it out again.
|
||||
pub fn guess_float_placement(flow: &mut dyn Flow) {
|
||||
if !flow
|
||||
.base()
|
||||
.restyle_damage
|
||||
.intersects(ServoRestyleDamage::REFLOW)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
let mut floats_in = SpeculatedFloatPlacement::compute_floats_in_for_first_child(flow);
|
||||
for kid in flow.mut_base().child_iter_mut() {
|
||||
if kid
|
||||
.base()
|
||||
.flags
|
||||
.contains(FlowFlags::IS_ABSOLUTELY_POSITIONED)
|
||||
{
|
||||
// Do not propagate floats in or out, but do propogate between kids.
|
||||
guess_float_placement(kid);
|
||||
} else {
|
||||
floats_in.compute_floats_in(kid);
|
||||
kid.mut_base().speculated_float_placement_in = floats_in;
|
||||
guess_float_placement(kid);
|
||||
floats_in = kid.base().speculated_float_placement_out;
|
||||
}
|
||||
}
|
||||
floats_in.compute_floats_out(flow);
|
||||
flow.mut_base().speculated_float_placement_out = floats_in
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue