aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/main/layout/construct.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/main/layout/construct.rs')
-rw-r--r--src/components/main/layout/construct.rs134
1 files changed, 94 insertions, 40 deletions
diff --git a/src/components/main/layout/construct.rs b/src/components/main/layout/construct.rs
index d7da3a11592..745ee21c173 100644
--- a/src/components/main/layout/construct.rs
+++ b/src/components/main/layout/construct.rs
@@ -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))
}
}