Sequentialize assign_block_size for flows that can be fragmented.

Fragmentation will be intertwined with block size calculation.
This commit is contained in:
Simon Sapin 2015-12-29 17:44:50 +00:00
parent da2b4ab381
commit 9abbd1b5d1
9 changed files with 61 additions and 24 deletions

View file

@ -18,7 +18,7 @@ use context::LayoutContext;
use data::{HAS_NEWLY_CONSTRUCTED_FLOW, PrivateLayoutData};
use flex::FlexFlow;
use floats::FloatKind;
use flow::{MutableFlowUtils, MutableOwnedFlowUtils};
use flow::{MutableFlowUtils, MutableOwnedFlowUtils, CAN_BE_FRAGMENTED};
use flow::{self, AbsoluteDescendants, Flow, IS_ABSOLUTELY_POSITIONED, ImmutableFlowUtils};
use flow_ref::{self, FlowRef};
use fragment::{CanvasFragmentInfo, ImageFragmentInfo, InlineAbsoluteFragmentInfo};
@ -1318,7 +1318,7 @@ impl<'a, 'ln, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode<'ln>>
return false
}
if node.in_fragmentation_container() {
if node.can_be_fragmented() || node.style().is_multicol() {
return false
}
@ -1616,7 +1616,13 @@ impl<'ln, ConcreteThreadSafeLayoutNode> NodeUtils for ConcreteThreadSafeLayoutNo
}
#[inline(always)]
fn set_flow_construction_result(self, result: ConstructionResult) {
fn set_flow_construction_result(self, mut result: ConstructionResult) {
if self.can_be_fragmented() {
if let ConstructionResult::Flow(ref mut flow, _) = result {
flow::mut_base(flow_ref::deref_mut(flow)).flags.insert(CAN_BE_FRAGMENTED);
}
}
let mut layout_data = self.mutate_layout_data().unwrap();
let dst = self.construction_result_mut(&mut *layout_data);

View file

@ -201,6 +201,27 @@ pub trait Flow: fmt::Debug + Sync + Send + 'static {
panic!("assign_block_size not yet implemented")
}
/// Like `assign_block_size`, but is recurses explicitly into descendants.
/// Fit as much content as possible within `available_block_size`.
/// If thats not all of it,
/// return an indication of where in the tree to break and start the next fragment.
///
/// FIXME: replace `()` in the return value with something meaningful.
///
/// The default is to make a flow "atomic": it can not be fragmented.
fn fragment<'a>(&mut self, ctx: &'a LayoutContext<'a>, _available_block_size: Au)
-> Option<()> {
fn recursive_assign_block_size<'a, F: ?Sized + Flow>
(flow: &mut F, ctx: &'a LayoutContext<'a>) {
for child in mut_base(flow).children.iter_mut() {
recursive_assign_block_size(child, ctx)
}
flow.assign_block_size(ctx);
}
recursive_assign_block_size(self, ctx);
None
}
/// If this is a float, places it. The default implementation does nothing.
fn place_float_if_applicable<'a>(&mut self, _: &'a LayoutContext<'a>) {}
@ -614,6 +635,9 @@ bitflags! {
static` and `position: relative` as well as absolutely-positioned flows with \
unconstrained positions in the block direction."]
const BLOCK_POSITION_IS_STATIC = 0b0100_0000_0000_0000_0000,
/// Whether any ancestor is a fragmentation container
const CAN_BE_FRAGMENTED = 0b1000_0000_0000_0000_0000,
}
}

View file

@ -11,7 +11,7 @@ use block::BlockFlow;
use context::LayoutContext;
use euclid::{Point2D, Rect};
use floats::FloatKind;
use flow::{Flow, FlowClass, OpaqueFlow};
use flow::{Flow, FlowClass, OpaqueFlow, mut_base};
use fragment::{Fragment, FragmentBorderBoxIterator};
use std::fmt;
use std::sync::Arc;
@ -60,6 +60,10 @@ impl Flow for MulticolFlow {
fn assign_block_size<'a>(&mut self, ctx: &'a LayoutContext<'a>) {
debug!("assign_block_size: assigning block_size for multicol");
let available_block_size = Au(0);
for child in mut_base(self).children.iter_mut() {
child.fragment(ctx, available_block_size);
}
self.block_flow.assign_block_size(ctx);
}

View file

@ -10,7 +10,7 @@
use construct::FlowConstructor;
use context::{LayoutContext, SharedLayoutContext};
use flow::{PostorderFlowTraversal, PreorderFlowTraversal};
use flow::{self, Flow};
use flow::{self, Flow, CAN_BE_FRAGMENTED};
use gfx::display_list::OpaqueNode;
use incremental::{BUBBLE_ISIZES, REFLOW, REFLOW_OUT_OF_FLOW, REPAINT, RestyleDamage};
use std::mem;
@ -194,7 +194,10 @@ impl<'a> PostorderFlowTraversal for AssignBSizesAndStoreOverflow<'a> {
#[inline]
fn should_process(&self, flow: &mut Flow) -> bool {
flow::base(flow).restyle_damage.intersects(REFLOW_OUT_OF_FLOW | REFLOW)
let base = flow::base(flow);
base.restyle_damage.intersects(REFLOW_OUT_OF_FLOW | REFLOW)
// The fragmentation countainer is responsible for calling Flow::fragment recursively
&& !base.flags.contains(CAN_BE_FRAGMENTED)
}
}

View file

@ -49,8 +49,8 @@ use script::dom::htmliframeelement::HTMLIFrameElement;
use script::dom::htmlimageelement::LayoutHTMLImageElementHelpers;
use script::dom::htmlinputelement::{HTMLInputElement, LayoutHTMLInputElementHelpers};
use script::dom::htmltextareaelement::{HTMLTextAreaElement, LayoutHTMLTextAreaElementHelpers};
use script::dom::node::{HAS_CHANGED, HAS_DIRTY_DESCENDANTS, IS_DIRTY};
use script::dom::node::{IN_FRAGMENTATION_CONTAINER, LayoutNodeHelpers, Node, OpaqueStyleAndLayoutData};
use script::dom::node::{CAN_BE_FRAGMENTED, HAS_CHANGED, HAS_DIRTY_DESCENDANTS, IS_DIRTY};
use script::dom::node::{LayoutNodeHelpers, Node, OpaqueStyleAndLayoutData};
use script::dom::text::Text;
use script::layout_interface::TrustedNodeAddress;
use selectors::matching::DeclarationBlock;
@ -226,12 +226,12 @@ impl<'ln> TNode<'ln> for ServoLayoutNode<'ln> {
self.node.set_flag(HAS_DIRTY_DESCENDANTS, value)
}
fn in_fragmentation_container(&self) -> bool {
unsafe { self.node.get_flag(IN_FRAGMENTATION_CONTAINER) }
fn can_be_fragmented(&self) -> bool {
unsafe { self.node.get_flag(CAN_BE_FRAGMENTED) }
}
unsafe fn set_in_fragmentation_container(&self, value: bool) {
self.node.set_flag(IN_FRAGMENTATION_CONTAINER, value)
unsafe fn set_can_be_fragmented(&self, value: bool) {
self.node.set_flag(CAN_BE_FRAGMENTED, value)
}
unsafe fn borrow_data_unchecked(&self) -> Option<*const PrivateStyleData> {
@ -761,7 +761,7 @@ pub trait ThreadSafeLayoutNode<'ln> : Clone + Copy + Sized {
}
}
fn in_fragmentation_container(&self) -> bool;
fn can_be_fragmented(&self) -> bool;
/// If this is a text node, generated content, or a form element, copies out
/// its content. Otherwise, panics.
@ -939,8 +939,8 @@ impl<'ln> ThreadSafeLayoutNode<'ln> for ServoThreadSafeLayoutNode<'ln> {
}
}
fn in_fragmentation_container(&self) -> bool {
self.node.in_fragmentation_container()
fn can_be_fragmented(&self) -> bool {
self.node.can_be_fragmented()
}
fn text_content(&self) -> TextContent {

View file

@ -146,7 +146,7 @@ bitflags! {
const SEQUENTIALLY_FOCUSABLE = 0x20,
/// Whether any ancestor is a fragmentation container
const IN_FRAGMENTATION_CONTAINER = 0x40
const CAN_BE_FRAGMENTED = 0x40
}
}

View file

@ -129,9 +129,9 @@ pub trait TNode<'ln> : Sized + Copy + Clone {
}
}
fn in_fragmentation_container(&self) -> bool;
fn can_be_fragmented(&self) -> bool;
unsafe fn set_in_fragmentation_container(&self, value: bool);
unsafe fn set_can_be_fragmented(&self, value: bool);
/// Borrows the PrivateStyleData without checks.
#[inline(always)]

View file

@ -701,10 +701,10 @@ pub trait MatchMethods<'ln> : TNode<'ln> {
// scope first.
self.set_restyle_damage(damage);
self.set_in_fragmentation_container(
parent.as_ref().map_or(false, |p| p.in_fragmentation_container()) ||
self.borrow_data().unwrap().style.as_ref().unwrap().is_multicol()
);
self.set_can_be_fragmented(parent.map_or(false, |p| {
p.can_be_fragmented() ||
parent_style.as_ref().unwrap().is_multicol()
}));
}
}
}

View file

@ -182,13 +182,13 @@ impl<'ln> TNode<'ln> for GeckoNode<'ln> {
unimplemented!()
}
fn in_fragmentation_container(&self) -> bool {
fn can_be_fragmented(&self) -> bool {
// FIXME(SimonSapin): Servo uses this to implement CSS multicol / fragmentation
// Maybe this isnt useful for Gecko?
false
}
unsafe fn set_in_fragmentation_container(&self, _value: bool) {
unsafe fn set_can_be_fragmented(&self, _value: bool) {
// FIXME(SimonSapin): Servo uses this to implement CSS multicol / fragmentation
// Maybe this isnt useful for Gecko?
}