mirror of
https://github.com/servo/servo.git
synced 2025-07-23 07:13:52 +01:00
Sequentialize assign_block_size for flows that can be fragmented.
Fragmentation will be intertwined with block size calculation.
This commit is contained in:
parent
da2b4ab381
commit
9abbd1b5d1
9 changed files with 61 additions and 24 deletions
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 that’s 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,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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()
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 isn’t 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 isn’t useful for Gecko?
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue