Skip to content
Permalink
Browse files

Implement mini-traversal for absolute flow assign-height.

This only traverses absolute flows, nothing else.

+ Also, a separate mini-traversal for store overflow.
+ Store descendants with position 'absolute' and 'fixed' in BaseFlow.
+ Bubble up links to absolute and fixed descendants during Flow Construction.
+ Set Rawlink to the CB in absolute descendants.
+ store_overflow() now uses absolute descendants' overflows too.
+ Add reftests for 'absolute' and 'fixed' static y position.
+ Add reftests for overflow (they all fail now).
+ Put absolute flow display items under their CB's ClipDisplayItem.
+ Paint borders in Box_ before the actual box stuff (minor fix in lieu of paint-order).
  • Loading branch information...
pradeep90 committed Feb 20, 2014
1 parent c4d177a commit 75f1142107af9a96ea3a997048e03c0e37b51b1c

Large diffs are not rendered by default.

Oops, something went wrong.
@@ -605,12 +605,18 @@ impl Box {
specified(padding, content_box_width)
}

pub fn padding_box_size(&self) -> Size2D<Au> {
let border_box_size = self.border_box.get().size;
Size2D(border_box_size.width - self.border.get().left - self.border.get().right,
border_box_size.height - self.border.get().top - self.border.get().bottom)
}

pub fn border_and_padding_horiz(&self) -> Au {
self.border.get().left + self.border.get().right + self.padding.get().left
+ self.padding.get().right
}

pub fn border_and_padding_vertical(&self) -> Au {
pub fn border_and_padding_vert(&self) -> Au {
self.border.get().top + self.border.get().bottom + self.padding.get().top
+ self.padding.get().bottom
}
@@ -989,7 +995,7 @@ impl Box {
/// Arguments:
/// * `builder`: The display list builder, which manages the coordinate system and options.
/// * `dirty`: The dirty rectangle in the coordinate system of the owning flow.
/// * `origin`: The total offset from the display list root flow to the owning flow of this
/// * `flow_origin`: Position of the origin of the owning flow wrt the display list root flow.
/// box.
/// * `list`: The display list to which items should be appended.
///
@@ -1002,15 +1008,16 @@ impl Box {
&self,
builder: &DisplayListBuilder,
dirty: &Rect<Au>,
offset: Point2D<Au>,
flow_origin: Point2D<Au>,
flow: &Flow,
index: uint,
lists: &RefCell<DisplayListCollection<E>>) {
// Box position wrt to the owning flow.
let box_bounds = self.border_box.get();
let absolute_box_bounds = box_bounds.translate(&offset);
let absolute_box_bounds = box_bounds.translate(&flow_origin);
debug!("Box::build_display_list at rel={}, abs={}: {:s}",
box_bounds, absolute_box_bounds, self.debug_str());
debug!("Box::build_display_list: dirty={}, offset={}", *dirty, offset);
debug!("Box::build_display_list: dirty={}, flow_origin={}", *dirty, flow_origin);

if self.style().InheritedBox.get().visibility != visibility::visible {
return;
@@ -1023,10 +1030,15 @@ impl Box {
return;
}

self.paint_inline_background_border_if_applicable(index, lists, &absolute_box_bounds, &offset);
self.paint_inline_background_border_if_applicable(index, lists, &absolute_box_bounds, &flow_origin);
// Add the background to the list, if applicable.
self.paint_background_if_applicable(builder, index, lists, &absolute_box_bounds);

// Add a border, if applicable.
//
// TODO: Outlines.
self.paint_borders_if_applicable(index, lists, &absolute_box_bounds);

match self.specific {
UnscannedTextBox(_) => fail!("Shouldn't see unscanned boxes here."),
ScannedTextBox(ref text_box) => {
@@ -1221,15 +1233,11 @@ impl Box {
// iframe is actually going to be displayed.
match self.specific {
IframeBox(ref iframe_box) => {
self.finalize_position_and_size_of_iframe(iframe_box, offset, builder.ctx)
self.finalize_position_and_size_of_iframe(iframe_box, flow_origin, builder.ctx)
}
GenericBox | ImageBox(_) | ScannedTextBox(_) | UnscannedTextBox(_) => {}
}

// Add a border, if applicable.
//
// TODO: Outlines.
self.paint_borders_if_applicable(index, lists, &absolute_box_bounds);
}

/// Returns the *minimum width* and *preferred width* of this box as defined by CSS 2.1.
@@ -28,6 +28,8 @@ use layout::box_::{UnscannedTextBoxInfo};
use layout::context::LayoutContext;
use layout::floats::FloatKind;
use layout::flow::{Flow, MutableOwnedFlowUtils};
use layout::flow::{Descendants, AbsDescendants, FixedDescendants};
use layout::flow_list::{Rawlink};
use layout::inline::InlineFlow;
use layout::text::TextRunScanner;
use layout::util::{LayoutDataAccess, OpaqueNode};
@@ -59,9 +61,10 @@ pub enum ConstructionResult {
/// created nodes have their `ConstructionResult` set to.
NoConstructionResult,

/// This node contributed a flow at the proper position in the tree. Nothing more needs to be
/// done for this node.
FlowConstructionResult(~Flow),
/// This node contributed a flow at the proper position in the tree.
/// Nothing more needs to be done for this node. It has bubbled up fixed
/// and absolute descendant flows that have a CB above it.
FlowConstructionResult(~Flow, AbsDescendants, FixedDescendants),

/// This node contributed some object or objects that will be needed to construct a proper flow
/// later up the tree, but these objects have not yet found their home.
@@ -72,7 +75,7 @@ impl ConstructionResult {
fn destroy(&mut self) {
match *self {
NoConstructionResult => {}
FlowConstructionResult(ref mut flow) => flow.destroy(),
FlowConstructionResult(ref mut flow, _, _) => flow.destroy(),
ConstructionItemConstructionResult(ref mut item) => item.destroy(),
}
}
@@ -112,6 +115,12 @@ struct InlineBoxesConstructionResult {

/// Any boxes that succeed the {ib} splits.
boxes: ~[Box],

/// Any absolute descendants that we're bubbling up.
abs_descendants: AbsDescendants,

/// Any fixed descendants that we're bubbling up.
fixed_descendants: FixedDescendants,
}

/// Represents an {ib} split that has not yet found the containing block that it belongs to. This
@@ -155,7 +164,7 @@ impl InlineBlockSplit {
/// Methods on optional vectors.
///
/// TODO(pcwalton): I think this will no longer be necessary once Rust #8981 lands.
trait OptVector<T> {
pub trait OptVector<T> {
/// Turns this optional vector into an owned one. If the optional vector is `None`, then this
/// simply returns an empty owned vector.
fn to_vec(self) -> ~[T];
@@ -316,17 +325,27 @@ impl<'a> FlowConstructor<'a> {
}
}

/// Builds the children flows underneath a node with `display: block`. After this call,
/// other `BlockFlow`s or `InlineFlow`s will be populated underneath this node, depending on
/// whether {ib} splits needed to happen.
fn build_children_of_block_flow(&mut self, flow: &mut ~Flow, node: &ThreadSafeLayoutNode) {
/// Build block flow for current node using information from children nodes.
///
/// Consume results from children and combine them, handling {ib} splits.
/// Block flows and inline flows thus created will become the children of
/// this block flow.
/// Also, deal with the absolute and fixed descendants bubbled up by
/// children nodes.
fn build_block_flow_using_children(&mut self,
mut flow: ~Flow,
node: &ThreadSafeLayoutNode)
-> ConstructionResult {
// Gather up boxes for the inline flows we might need to create.
let mut opt_boxes_for_inline_flow = None;
let mut first_box = true;
// List of absolute descendants, in tree order.
let mut abs_descendants = Descendants::new();
let mut fixed_descendants = Descendants::new();
for kid in node.children() {
match kid.swap_out_construction_result() {
NoConstructionResult => {}
FlowConstructionResult(kid_flow) => {
FlowConstructionResult(kid_flow, kid_abs_descendants, kid_fixed_descendants) => {
// Strip ignorable whitespace from the start of this flow per CSS 2.1 §
// 9.2.1.1.
if first_box {
@@ -340,14 +359,19 @@ impl<'a> FlowConstructor<'a> {
opt_boxes_for_inline_flow.as_ref()
.map_default(0, |boxes| boxes.len()));
self.flush_inline_boxes_to_flow_if_necessary(&mut opt_boxes_for_inline_flow,
flow,
&mut flow,
node);
flow.add_new_child(kid_flow)
flow.add_new_child(kid_flow);
abs_descendants.push_descendants(kid_abs_descendants);
fixed_descendants.push_descendants(kid_fixed_descendants);

}
ConstructionItemConstructionResult(InlineBoxesConstructionItem(
InlineBoxesConstructionResult {
splits: opt_splits,
boxes: boxes
boxes: boxes,
abs_descendants: kid_abs_descendants,
fixed_descendants: kid_fixed_descendants,
})) => {
// Add any {ib} splits.
match opt_splits {
@@ -377,7 +401,7 @@ impl<'a> FlowConstructor<'a> {
|boxes| boxes.len()));
self.flush_inline_boxes_to_flow_if_necessary(
&mut opt_boxes_for_inline_flow,
flow,
&mut flow,
node);

// Push the flow generated by the {ib} split onto our list of
@@ -388,7 +412,9 @@ impl<'a> FlowConstructor<'a> {
}

// Add the boxes to the list we're maintaining.
opt_boxes_for_inline_flow.push_all_move(boxes)
opt_boxes_for_inline_flow.push_all_move(boxes);
abs_descendants.push_descendants(kid_abs_descendants);
fixed_descendants.push_descendants(kid_fixed_descendants);
}
ConstructionItemConstructionResult(WhitespaceConstructionItem(..)) => {
// Nothing to do here.
@@ -400,30 +426,45 @@ impl<'a> FlowConstructor<'a> {
// splits, after stripping ignorable whitespace.
strip_ignorable_whitespace_from_end(&mut opt_boxes_for_inline_flow);
self.flush_inline_boxes_to_flow_if_necessary(&mut opt_boxes_for_inline_flow,
flow,
&mut flow,
node);

// The flow is done. If it ended up with no kids, add the flow to the leaf set.
flow.finish(self.layout_context)
// The flow is done.
flow.finish(self.layout_context);
let is_positioned = flow.as_block().is_positioned();
let is_fixed_positioned = flow.as_block().is_fixed();
let is_absolutely_positioned = flow.as_block().is_absolutely_positioned();
if is_positioned {
// This is the CB for all the absolute descendants.
flow.set_abs_descendants(abs_descendants);
abs_descendants = Descendants::new();

if is_fixed_positioned {
// Send itself along with the other fixed descendants.
fixed_descendants.push(Rawlink::some(flow));
} else if is_absolutely_positioned {
// This is now the only absolute flow in the subtree which hasn't yet
// reached its CB.
abs_descendants.push(Rawlink::some(flow));
}
}
FlowConstructionResult(flow, abs_descendants, fixed_descendants)
}

/// Builds a flow for a node with `display: block`. This yields a `BlockFlow` with possibly
/// other `BlockFlow`s or `InlineFlow`s underneath it, depending on whether {ib} splits needed
/// to happen.
fn build_flow_for_block(&mut self, node: &ThreadSafeLayoutNode, positioning: position::T)
-> ~Flow {
let mut flow = ~BlockFlow::from_node(self, node, positioning) as ~Flow;
self.build_children_of_block_flow(&mut flow, node);
flow
fn build_flow_for_block(&mut self, node: &ThreadSafeLayoutNode) -> ConstructionResult {
let flow = ~BlockFlow::from_node(self, node) as ~Flow;
self.build_block_flow_using_children(flow, node)
}

/// Builds the flow for a node with `float: {left|right}`. This yields a float `BlockFlow` with
/// a `BlockFlow` underneath it.
fn build_flow_for_floated_block(&mut self, node: &ThreadSafeLayoutNode, float_kind: FloatKind)
-> ~Flow {
let mut flow = ~BlockFlow::float_from_node(self, node, float_kind) as ~Flow;
self.build_children_of_block_flow(&mut flow, node);
flow
-> ConstructionResult {
let flow = ~BlockFlow::float_from_node(self, node, float_kind) as ~Flow;
self.build_block_flow_using_children(flow, node)
}


@@ -434,24 +475,30 @@ impl<'a> FlowConstructor<'a> {
-> ConstructionResult {
let mut opt_inline_block_splits = None;
let mut opt_box_accumulator = None;
let mut abs_descendants = Descendants::new();
let mut fixed_descendants = Descendants::new();

// Concatenate all the boxes of our kids, creating {ib} splits as necessary.
for kid in node.children() {
match kid.swap_out_construction_result() {
NoConstructionResult => {}
FlowConstructionResult(flow) => {
FlowConstructionResult(flow, kid_abs_descendants, kid_fixed_descendants) => {
// {ib} split. Flush the accumulator to our new split and make a new
// accumulator to hold any subsequent boxes we come across.
let split = InlineBlockSplit {
predecessor_boxes: util::replace(&mut opt_box_accumulator, None).to_vec(),
flow: flow,
};
opt_inline_block_splits.push(split)
opt_inline_block_splits.push(split);
abs_descendants.push_descendants(kid_abs_descendants);
fixed_descendants.push_descendants(kid_fixed_descendants);
}
ConstructionItemConstructionResult(InlineBoxesConstructionItem(
InlineBoxesConstructionResult {
splits: opt_splits,
boxes: boxes
boxes: boxes,
abs_descendants: kid_abs_descendants,
fixed_descendants: kid_fixed_descendants,
})) => {

// Bubble up {ib} splits.
@@ -476,7 +523,9 @@ impl<'a> FlowConstructor<'a> {
}

// Push residual boxes.
opt_box_accumulator.push_all_move(boxes)
opt_box_accumulator.push_all_move(boxes);
abs_descendants.push_descendants(kid_abs_descendants);
fixed_descendants.push_descendants(kid_fixed_descendants);
}
ConstructionItemConstructionResult(WhitespaceConstructionItem(whitespace_node,
whitespace_style))
@@ -534,10 +583,14 @@ impl<'a> FlowConstructor<'a> {
}

// Finally, make a new construction result.
if opt_inline_block_splits.len() > 0 || opt_box_accumulator.len() > 0 {
if opt_inline_block_splits.len() > 0 || opt_box_accumulator.len() > 0
|| abs_descendants.len() > 0 {

let construction_item = InlineBoxesConstructionItem(InlineBoxesConstructionResult {
splits: opt_inline_block_splits,
boxes: opt_box_accumulator.to_vec(),
abs_descendants: abs_descendants,
fixed_descendants: fixed_descendants,
});
ConstructionItemConstructionResult(construction_item)
} else {
@@ -613,6 +666,8 @@ impl<'a> FlowConstructor<'a> {
boxes: ~[
Box::new(self, node)
],
abs_descendants: Descendants::new(),
fixed_descendants: Descendants::new(),
});
ConstructionItemConstructionResult(construction_item)
}
@@ -663,6 +718,10 @@ impl<'a> PostorderNodeMutTraversal for FlowConstructor<'a> {
}
}

(_, _, position::absolute) | (_, _, position::fixed) => {
node.set_flow_construction_result(self.build_flow_for_block(node))
}

// Inline items contribute inline box construction results.
(display::inline, float::none, _) => {
let construction_result = self.build_boxes_for_inline(node);
@@ -674,20 +733,15 @@ impl<'a> PostorderNodeMutTraversal for FlowConstructor<'a> {
// TODO(pcwalton): Make this only trigger for blocks and handle the other `display`
// properties separately.

(_, _, position::absolute) | (_, _, position::fixed) => {
let flow = self.build_flow_for_block(node, positioning);
node.set_flow_construction_result(FlowConstructionResult(flow))
}
(_, float::none, _) => {
let flow = self.build_flow_for_block(node, positioning);
node.set_flow_construction_result(FlowConstructionResult(flow))
node.set_flow_construction_result(self.build_flow_for_block(node))
}

// Floated flows contribute float flow construction results.
(_, float_value, _) => {
let float_kind = FloatKind::from_property(float_value);
let flow = self.build_flow_for_floated_block(node, float_kind);
node.set_flow_construction_result(FlowConstructionResult(flow))
node.set_flow_construction_result(
self.build_flow_for_floated_block(node, float_kind))
}
}

Oops, something went wrong.

5 comments on commit 75f1142

@bors-servo

This comment has been minimized.

Copy link
Contributor

replied Mar 3, 2014

saw approval from pcwalton
at pradeep90@75f1142

@bors-servo

This comment has been minimized.

Copy link
Contributor

replied Mar 3, 2014

merging pradeep90/servo/absolute-position = 75f1142 into auto

@bors-servo

This comment has been minimized.

Copy link
Contributor

replied Mar 3, 2014

pradeep90/servo/absolute-position = 75f1142 merged ok, testing candidate = ada9224

@bors-servo

This comment has been minimized.

Copy link
Contributor

replied Mar 3, 2014

fast-forwarding master to auto = ada9224

Please sign in to comment.
You can’t perform that action at this time.