mirror of
https://github.com/servo/servo.git
synced 2025-06-19 14:48:59 +01:00
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).
This commit is contained in:
parent
c4d177a354
commit
75f1142107
19 changed files with 1222 additions and 405 deletions
File diff suppressed because it is too large
Load diff
|
@ -605,12 +605,18 @@ impl Box {
|
||||||
specified(padding, content_box_width)
|
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 {
|
pub fn border_and_padding_horiz(&self) -> Au {
|
||||||
self.border.get().left + self.border.get().right + self.padding.get().left
|
self.border.get().left + self.border.get().right + self.padding.get().left
|
||||||
+ self.padding.get().right
|
+ 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.border.get().top + self.border.get().bottom + self.padding.get().top
|
||||||
+ self.padding.get().bottom
|
+ self.padding.get().bottom
|
||||||
}
|
}
|
||||||
|
@ -989,7 +995,7 @@ impl Box {
|
||||||
/// Arguments:
|
/// Arguments:
|
||||||
/// * `builder`: The display list builder, which manages the coordinate system and options.
|
/// * `builder`: The display list builder, which manages the coordinate system and options.
|
||||||
/// * `dirty`: The dirty rectangle in the coordinate system of the owning flow.
|
/// * `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.
|
/// box.
|
||||||
/// * `list`: The display list to which items should be appended.
|
/// * `list`: The display list to which items should be appended.
|
||||||
///
|
///
|
||||||
|
@ -1002,15 +1008,16 @@ impl Box {
|
||||||
&self,
|
&self,
|
||||||
builder: &DisplayListBuilder,
|
builder: &DisplayListBuilder,
|
||||||
dirty: &Rect<Au>,
|
dirty: &Rect<Au>,
|
||||||
offset: Point2D<Au>,
|
flow_origin: Point2D<Au>,
|
||||||
flow: &Flow,
|
flow: &Flow,
|
||||||
index: uint,
|
index: uint,
|
||||||
lists: &RefCell<DisplayListCollection<E>>) {
|
lists: &RefCell<DisplayListCollection<E>>) {
|
||||||
|
// Box position wrt to the owning flow.
|
||||||
let box_bounds = self.border_box.get();
|
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}",
|
debug!("Box::build_display_list at rel={}, abs={}: {:s}",
|
||||||
box_bounds, absolute_box_bounds, self.debug_str());
|
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 {
|
if self.style().InheritedBox.get().visibility != visibility::visible {
|
||||||
return;
|
return;
|
||||||
|
@ -1023,10 +1030,15 @@ impl Box {
|
||||||
return;
|
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.
|
// Add the background to the list, if applicable.
|
||||||
self.paint_background_if_applicable(builder, index, lists, &absolute_box_bounds);
|
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 {
|
match self.specific {
|
||||||
UnscannedTextBox(_) => fail!("Shouldn't see unscanned boxes here."),
|
UnscannedTextBox(_) => fail!("Shouldn't see unscanned boxes here."),
|
||||||
ScannedTextBox(ref text_box) => {
|
ScannedTextBox(ref text_box) => {
|
||||||
|
@ -1221,15 +1233,11 @@ impl Box {
|
||||||
// iframe is actually going to be displayed.
|
// iframe is actually going to be displayed.
|
||||||
match self.specific {
|
match self.specific {
|
||||||
IframeBox(ref iframe_box) => {
|
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(_) => {}
|
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.
|
/// 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::context::LayoutContext;
|
||||||
use layout::floats::FloatKind;
|
use layout::floats::FloatKind;
|
||||||
use layout::flow::{Flow, MutableOwnedFlowUtils};
|
use layout::flow::{Flow, MutableOwnedFlowUtils};
|
||||||
|
use layout::flow::{Descendants, AbsDescendants, FixedDescendants};
|
||||||
|
use layout::flow_list::{Rawlink};
|
||||||
use layout::inline::InlineFlow;
|
use layout::inline::InlineFlow;
|
||||||
use layout::text::TextRunScanner;
|
use layout::text::TextRunScanner;
|
||||||
use layout::util::{LayoutDataAccess, OpaqueNode};
|
use layout::util::{LayoutDataAccess, OpaqueNode};
|
||||||
|
@ -59,9 +61,10 @@ pub enum ConstructionResult {
|
||||||
/// created nodes have their `ConstructionResult` set to.
|
/// created nodes have their `ConstructionResult` set to.
|
||||||
NoConstructionResult,
|
NoConstructionResult,
|
||||||
|
|
||||||
/// This node contributed a flow at the proper position in the tree. Nothing more needs to be
|
/// This node contributed a flow at the proper position in the tree.
|
||||||
/// done for this node.
|
/// Nothing more needs to be done for this node. It has bubbled up fixed
|
||||||
FlowConstructionResult(~Flow),
|
/// 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
|
/// 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.
|
/// later up the tree, but these objects have not yet found their home.
|
||||||
|
@ -72,7 +75,7 @@ impl ConstructionResult {
|
||||||
fn destroy(&mut self) {
|
fn destroy(&mut self) {
|
||||||
match *self {
|
match *self {
|
||||||
NoConstructionResult => {}
|
NoConstructionResult => {}
|
||||||
FlowConstructionResult(ref mut flow) => flow.destroy(),
|
FlowConstructionResult(ref mut flow, _, _) => flow.destroy(),
|
||||||
ConstructionItemConstructionResult(ref mut item) => item.destroy(),
|
ConstructionItemConstructionResult(ref mut item) => item.destroy(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -112,6 +115,12 @@ struct InlineBoxesConstructionResult {
|
||||||
|
|
||||||
/// Any boxes that succeed the {ib} splits.
|
/// Any boxes that succeed the {ib} splits.
|
||||||
boxes: ~[Box],
|
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
|
/// 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.
|
/// Methods on optional vectors.
|
||||||
///
|
///
|
||||||
/// TODO(pcwalton): I think this will no longer be necessary once Rust #8981 lands.
|
/// 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
|
/// Turns this optional vector into an owned one. If the optional vector is `None`, then this
|
||||||
/// simply returns an empty owned vector.
|
/// simply returns an empty owned vector.
|
||||||
fn to_vec(self) -> ~[T];
|
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,
|
/// Build block flow for current node using information from children nodes.
|
||||||
/// other `BlockFlow`s or `InlineFlow`s will be populated underneath this node, depending on
|
///
|
||||||
/// whether {ib} splits needed to happen.
|
/// Consume results from children and combine them, handling {ib} splits.
|
||||||
fn build_children_of_block_flow(&mut self, flow: &mut ~Flow, node: &ThreadSafeLayoutNode) {
|
/// 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.
|
// Gather up boxes for the inline flows we might need to create.
|
||||||
let mut opt_boxes_for_inline_flow = None;
|
let mut opt_boxes_for_inline_flow = None;
|
||||||
let mut first_box = true;
|
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() {
|
for kid in node.children() {
|
||||||
match kid.swap_out_construction_result() {
|
match kid.swap_out_construction_result() {
|
||||||
NoConstructionResult => {}
|
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 §
|
// Strip ignorable whitespace from the start of this flow per CSS 2.1 §
|
||||||
// 9.2.1.1.
|
// 9.2.1.1.
|
||||||
if first_box {
|
if first_box {
|
||||||
|
@ -340,14 +359,19 @@ impl<'a> FlowConstructor<'a> {
|
||||||
opt_boxes_for_inline_flow.as_ref()
|
opt_boxes_for_inline_flow.as_ref()
|
||||||
.map_default(0, |boxes| boxes.len()));
|
.map_default(0, |boxes| boxes.len()));
|
||||||
self.flush_inline_boxes_to_flow_if_necessary(&mut opt_boxes_for_inline_flow,
|
self.flush_inline_boxes_to_flow_if_necessary(&mut opt_boxes_for_inline_flow,
|
||||||
flow,
|
&mut flow,
|
||||||
node);
|
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(
|
ConstructionItemConstructionResult(InlineBoxesConstructionItem(
|
||||||
InlineBoxesConstructionResult {
|
InlineBoxesConstructionResult {
|
||||||
splits: opt_splits,
|
splits: opt_splits,
|
||||||
boxes: boxes
|
boxes: boxes,
|
||||||
|
abs_descendants: kid_abs_descendants,
|
||||||
|
fixed_descendants: kid_fixed_descendants,
|
||||||
})) => {
|
})) => {
|
||||||
// Add any {ib} splits.
|
// Add any {ib} splits.
|
||||||
match opt_splits {
|
match opt_splits {
|
||||||
|
@ -377,7 +401,7 @@ impl<'a> FlowConstructor<'a> {
|
||||||
|boxes| boxes.len()));
|
|boxes| boxes.len()));
|
||||||
self.flush_inline_boxes_to_flow_if_necessary(
|
self.flush_inline_boxes_to_flow_if_necessary(
|
||||||
&mut opt_boxes_for_inline_flow,
|
&mut opt_boxes_for_inline_flow,
|
||||||
flow,
|
&mut flow,
|
||||||
node);
|
node);
|
||||||
|
|
||||||
// Push the flow generated by the {ib} split onto our list of
|
// 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.
|
// 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(..)) => {
|
ConstructionItemConstructionResult(WhitespaceConstructionItem(..)) => {
|
||||||
// Nothing to do here.
|
// Nothing to do here.
|
||||||
|
@ -400,30 +426,45 @@ impl<'a> FlowConstructor<'a> {
|
||||||
// splits, after stripping ignorable whitespace.
|
// splits, after stripping ignorable whitespace.
|
||||||
strip_ignorable_whitespace_from_end(&mut opt_boxes_for_inline_flow);
|
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,
|
self.flush_inline_boxes_to_flow_if_necessary(&mut opt_boxes_for_inline_flow,
|
||||||
flow,
|
&mut flow,
|
||||||
node);
|
node);
|
||||||
|
|
||||||
// The flow is done. If it ended up with no kids, add the flow to the leaf set.
|
// The flow is done.
|
||||||
flow.finish(self.layout_context)
|
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
|
/// 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
|
/// other `BlockFlow`s or `InlineFlow`s underneath it, depending on whether {ib} splits needed
|
||||||
/// to happen.
|
/// to happen.
|
||||||
fn build_flow_for_block(&mut self, node: &ThreadSafeLayoutNode, positioning: position::T)
|
fn build_flow_for_block(&mut self, node: &ThreadSafeLayoutNode) -> ConstructionResult {
|
||||||
-> ~Flow {
|
let flow = ~BlockFlow::from_node(self, node) as ~Flow;
|
||||||
let mut flow = ~BlockFlow::from_node(self, node, positioning) as ~Flow;
|
self.build_block_flow_using_children(flow, node)
|
||||||
self.build_children_of_block_flow(&mut flow, node);
|
|
||||||
flow
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds the flow for a node with `float: {left|right}`. This yields a float `BlockFlow` with
|
/// Builds the flow for a node with `float: {left|right}`. This yields a float `BlockFlow` with
|
||||||
/// a `BlockFlow` underneath it.
|
/// a `BlockFlow` underneath it.
|
||||||
fn build_flow_for_floated_block(&mut self, node: &ThreadSafeLayoutNode, float_kind: FloatKind)
|
fn build_flow_for_floated_block(&mut self, node: &ThreadSafeLayoutNode, float_kind: FloatKind)
|
||||||
-> ~Flow {
|
-> ConstructionResult {
|
||||||
let mut flow = ~BlockFlow::float_from_node(self, node, float_kind) as ~Flow;
|
let flow = ~BlockFlow::float_from_node(self, node, float_kind) as ~Flow;
|
||||||
self.build_children_of_block_flow(&mut flow, node);
|
self.build_block_flow_using_children(flow, node)
|
||||||
flow
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -434,24 +475,30 @@ impl<'a> FlowConstructor<'a> {
|
||||||
-> ConstructionResult {
|
-> ConstructionResult {
|
||||||
let mut opt_inline_block_splits = None;
|
let mut opt_inline_block_splits = None;
|
||||||
let mut opt_box_accumulator = 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.
|
// Concatenate all the boxes of our kids, creating {ib} splits as necessary.
|
||||||
for kid in node.children() {
|
for kid in node.children() {
|
||||||
match kid.swap_out_construction_result() {
|
match kid.swap_out_construction_result() {
|
||||||
NoConstructionResult => {}
|
NoConstructionResult => {}
|
||||||
FlowConstructionResult(flow) => {
|
FlowConstructionResult(flow, kid_abs_descendants, kid_fixed_descendants) => {
|
||||||
// {ib} split. Flush the accumulator to our new split and make a new
|
// {ib} split. Flush the accumulator to our new split and make a new
|
||||||
// accumulator to hold any subsequent boxes we come across.
|
// accumulator to hold any subsequent boxes we come across.
|
||||||
let split = InlineBlockSplit {
|
let split = InlineBlockSplit {
|
||||||
predecessor_boxes: util::replace(&mut opt_box_accumulator, None).to_vec(),
|
predecessor_boxes: util::replace(&mut opt_box_accumulator, None).to_vec(),
|
||||||
flow: flow,
|
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(
|
ConstructionItemConstructionResult(InlineBoxesConstructionItem(
|
||||||
InlineBoxesConstructionResult {
|
InlineBoxesConstructionResult {
|
||||||
splits: opt_splits,
|
splits: opt_splits,
|
||||||
boxes: boxes
|
boxes: boxes,
|
||||||
|
abs_descendants: kid_abs_descendants,
|
||||||
|
fixed_descendants: kid_fixed_descendants,
|
||||||
})) => {
|
})) => {
|
||||||
|
|
||||||
// Bubble up {ib} splits.
|
// Bubble up {ib} splits.
|
||||||
|
@ -476,7 +523,9 @@ impl<'a> FlowConstructor<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Push residual boxes.
|
// 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,
|
ConstructionItemConstructionResult(WhitespaceConstructionItem(whitespace_node,
|
||||||
whitespace_style))
|
whitespace_style))
|
||||||
|
@ -534,10 +583,14 @@ impl<'a> FlowConstructor<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally, make a new construction result.
|
// 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 {
|
let construction_item = InlineBoxesConstructionItem(InlineBoxesConstructionResult {
|
||||||
splits: opt_inline_block_splits,
|
splits: opt_inline_block_splits,
|
||||||
boxes: opt_box_accumulator.to_vec(),
|
boxes: opt_box_accumulator.to_vec(),
|
||||||
|
abs_descendants: abs_descendants,
|
||||||
|
fixed_descendants: fixed_descendants,
|
||||||
});
|
});
|
||||||
ConstructionItemConstructionResult(construction_item)
|
ConstructionItemConstructionResult(construction_item)
|
||||||
} else {
|
} else {
|
||||||
|
@ -613,6 +666,8 @@ impl<'a> FlowConstructor<'a> {
|
||||||
boxes: ~[
|
boxes: ~[
|
||||||
Box::new(self, node)
|
Box::new(self, node)
|
||||||
],
|
],
|
||||||
|
abs_descendants: Descendants::new(),
|
||||||
|
fixed_descendants: Descendants::new(),
|
||||||
});
|
});
|
||||||
ConstructionItemConstructionResult(construction_item)
|
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.
|
// Inline items contribute inline box construction results.
|
||||||
(display::inline, float::none, _) => {
|
(display::inline, float::none, _) => {
|
||||||
let construction_result = self.build_boxes_for_inline(node);
|
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`
|
// TODO(pcwalton): Make this only trigger for blocks and handle the other `display`
|
||||||
// properties separately.
|
// properties separately.
|
||||||
|
|
||||||
(_, _, position::absolute) | (_, _, position::fixed) => {
|
|
||||||
let flow = self.build_flow_for_block(node, positioning);
|
|
||||||
node.set_flow_construction_result(FlowConstructionResult(flow))
|
|
||||||
}
|
|
||||||
(_, float::none, _) => {
|
(_, float::none, _) => {
|
||||||
let flow = self.build_flow_for_block(node, positioning);
|
node.set_flow_construction_result(self.build_flow_for_block(node))
|
||||||
node.set_flow_construction_result(FlowConstructionResult(flow))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Floated flows contribute float flow construction results.
|
// Floated flows contribute float flow construction results.
|
||||||
(_, float_value, _) => {
|
(_, float_value, _) => {
|
||||||
let float_kind = FloatKind::from_property(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(
|
||||||
node.set_flow_construction_result(FlowConstructionResult(flow))
|
self.build_flow_for_floated_block(node, float_kind))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@ use css::node_style::StyledNode;
|
||||||
use layout::block::{BlockFlow};
|
use layout::block::{BlockFlow};
|
||||||
use layout::box_::Box;
|
use layout::box_::Box;
|
||||||
use layout::context::LayoutContext;
|
use layout::context::LayoutContext;
|
||||||
|
use layout::construct::OptVector;
|
||||||
use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData};
|
use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData};
|
||||||
use layout::floats::Floats;
|
use layout::floats::Floats;
|
||||||
use layout::incremental::RestyleDamage;
|
use layout::incremental::RestyleDamage;
|
||||||
|
@ -45,12 +46,15 @@ use geom::rect::Rect;
|
||||||
use gfx::display_list::{ClipDisplayItemClass, DisplayListCollection, DisplayList};
|
use gfx::display_list::{ClipDisplayItemClass, DisplayListCollection, DisplayList};
|
||||||
use layout::display_list_builder::ToGfxColor;
|
use layout::display_list_builder::ToGfxColor;
|
||||||
use gfx::color::Color;
|
use gfx::color::Color;
|
||||||
|
use servo_util::smallvec::{SmallVec, SmallVec0};
|
||||||
use servo_util::geometry::Au;
|
use servo_util::geometry::Au;
|
||||||
use std::cast;
|
use std::cast;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::sync::atomics::Relaxed;
|
use std::sync::atomics::Relaxed;
|
||||||
|
use std::vec::VecMutIterator;
|
||||||
|
use std::iter::Zip;
|
||||||
use style::ComputedValues;
|
use style::ComputedValues;
|
||||||
use style::computed_values::text_align;
|
use style::computed_values::{text_align, position};
|
||||||
|
|
||||||
/// Virtual methods that make up a float context.
|
/// Virtual methods that make up a float context.
|
||||||
///
|
///
|
||||||
|
@ -116,6 +120,63 @@ pub trait Flow {
|
||||||
/// Marks this flow as the root flow. The default implementation is a no-op.
|
/// Marks this flow as the root flow. The default implementation is a no-op.
|
||||||
fn mark_as_root(&mut self) {}
|
fn mark_as_root(&mut self) {}
|
||||||
|
|
||||||
|
// Note that the following functions are mostly called using static method
|
||||||
|
// dispatch, so it's ok to have them in this trait. Plus, they have
|
||||||
|
// different behaviour for different types of Flow, so they can't go into
|
||||||
|
// the Immutable / Mutable Flow Utils traits without additional casts.
|
||||||
|
|
||||||
|
/// Return true if store overflow is delayed for this flow.
|
||||||
|
///
|
||||||
|
/// Currently happens only for absolutely positioned flows.
|
||||||
|
fn is_store_overflow_delayed(&mut self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_root(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_float(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The 'position' property of this flow.
|
||||||
|
fn positioning(&self) -> position::T {
|
||||||
|
position::static_
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return true if this flow has position 'fixed'.
|
||||||
|
fn is_fixed(&self) -> bool {
|
||||||
|
self.positioning() == position::fixed
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_positioned(&self) -> bool {
|
||||||
|
self.is_relatively_positioned() || self.is_absolutely_positioned()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_relatively_positioned(&self) -> bool {
|
||||||
|
self.positioning() == position::relative
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_absolutely_positioned(&self) -> bool {
|
||||||
|
self.positioning() == position::absolute || self.is_fixed()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return true if this is the root of an Absolute flow tree.
|
||||||
|
fn is_root_of_absolute_flow_tree(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the dimensions of the CB generated _by_ this flow for absolute descendants.
|
||||||
|
fn generated_cb_size(&self) -> Size2D<Au> {
|
||||||
|
fail!("generated_cb_size not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return position of the CB generated by this flow from the start of this flow.
|
||||||
|
fn generated_cb_position(&self) -> Point2D<Au> {
|
||||||
|
fail!("this is not the CB-generating flow you're looking for")
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a debugging string describing this flow.
|
/// Returns a debugging string describing this flow.
|
||||||
fn debug_str(&self) -> ~str {
|
fn debug_str(&self) -> ~str {
|
||||||
~"???"
|
~"???"
|
||||||
|
@ -231,6 +292,16 @@ pub trait MutableOwnedFlowUtils {
|
||||||
/// properly computed. (This is not, however, a memory safety problem.)
|
/// properly computed. (This is not, however, a memory safety problem.)
|
||||||
fn finish(&mut self, context: &mut LayoutContext);
|
fn finish(&mut self, context: &mut LayoutContext);
|
||||||
|
|
||||||
|
/// Set absolute descendants for this flow.
|
||||||
|
///
|
||||||
|
/// Set this flow as the Containing Block for all the absolute descendants.
|
||||||
|
fn set_abs_descendants(&mut self, abs_descendants: AbsDescendants);
|
||||||
|
|
||||||
|
/// Set fixed descendants for this flow.
|
||||||
|
///
|
||||||
|
/// Set yourself as the Containing Block for all the fixed descendants.
|
||||||
|
fn set_fixed_descendants(&mut self, fixed_descendants: AbsDescendants);
|
||||||
|
|
||||||
/// Destroys the flow.
|
/// Destroys the flow.
|
||||||
fn destroy(&mut self);
|
fn destroy(&mut self);
|
||||||
}
|
}
|
||||||
|
@ -484,6 +555,61 @@ impl FlowFlags {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The Descendants of a flow.
|
||||||
|
///
|
||||||
|
/// Also, details about their position wrt this flow.
|
||||||
|
/// FIXME: This should use @pcwalton's reference counting scheme (Coming Soon).
|
||||||
|
pub struct Descendants {
|
||||||
|
/// Links to every Descendant.
|
||||||
|
descendant_links: SmallVec0<Rawlink>,
|
||||||
|
/// Static y offsets of all descendants from the start of this flow box.
|
||||||
|
static_y_offsets: SmallVec0<Au>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Descendants {
|
||||||
|
pub fn new() -> Descendants {
|
||||||
|
Descendants {
|
||||||
|
descendant_links: SmallVec0::new(),
|
||||||
|
static_y_offsets: SmallVec0::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn len(&self) -> uint {
|
||||||
|
self.descendant_links.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push(&mut self, given_descendant: Rawlink) {
|
||||||
|
self.descendant_links.push(given_descendant);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Push the given descendants on to the existing descendants.
|
||||||
|
///
|
||||||
|
/// Ignore any static y offsets, because they are None before layout.
|
||||||
|
pub fn push_descendants(&mut self, mut given_descendants: Descendants) {
|
||||||
|
for elem in given_descendants.descendant_links.move_iter() {
|
||||||
|
self.descendant_links.push(elem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return an iterator over the descendant flows.
|
||||||
|
pub fn iter<'a>(&'a mut self) -> DescendantIter<'a> {
|
||||||
|
self.descendant_links.mut_slice_from(0).mut_iter()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return an iterator over (descendant, static y offset).
|
||||||
|
pub fn iter_with_offset<'a>(&'a mut self) -> DescendantOffsetIter<'a> {
|
||||||
|
self.descendant_links.mut_slice_from(0).mut_iter().zip(
|
||||||
|
self.static_y_offsets.mut_slice_from(0).mut_iter())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type AbsDescendants = Descendants;
|
||||||
|
pub type FixedDescendants = Descendants;
|
||||||
|
|
||||||
|
type DescendantIter<'a> = VecMutIterator<'a, Rawlink>;
|
||||||
|
|
||||||
|
type DescendantOffsetIter<'a> = Zip<VecMutIterator<'a, Rawlink>, VecMutIterator<'a, Au>>;
|
||||||
|
|
||||||
/// Data common to all flows.
|
/// Data common to all flows.
|
||||||
pub struct BaseFlow {
|
pub struct BaseFlow {
|
||||||
restyle_damage: RestyleDamage,
|
restyle_damage: RestyleDamage,
|
||||||
|
@ -526,6 +652,22 @@ pub struct BaseFlow {
|
||||||
/// The position of this flow in page coordinates, computed during display list construction.
|
/// The position of this flow in page coordinates, computed during display list construction.
|
||||||
abs_position: Point2D<Au>,
|
abs_position: Point2D<Au>,
|
||||||
|
|
||||||
|
/// Details about descendants with position 'absolute' for which we are
|
||||||
|
/// the CB. This is in tree order. This includes any direct children.
|
||||||
|
abs_descendants: AbsDescendants,
|
||||||
|
/// Details about descendants with position 'fixed'.
|
||||||
|
/// TODO: Optimize this, because this will be set only for the root.
|
||||||
|
fixed_descendants: FixedDescendants,
|
||||||
|
|
||||||
|
/// Offset wrt the nearest positioned ancestor - aka the Containing Block
|
||||||
|
/// for any absolutely positioned elements.
|
||||||
|
absolute_static_x_offset: Au,
|
||||||
|
/// Offset wrt the Initial Containing Block.
|
||||||
|
fixed_static_x_offset: Au,
|
||||||
|
|
||||||
|
/// Reference to the Containing Block, if this flow is absolutely positioned.
|
||||||
|
absolute_cb: Rawlink,
|
||||||
|
|
||||||
/// Whether this flow has been destroyed.
|
/// Whether this flow has been destroyed.
|
||||||
///
|
///
|
||||||
/// TODO(pcwalton): Pack this into the flags? Need to be careful because manipulation of this
|
/// TODO(pcwalton): Pack this into the flags? Need to be careful because manipulation of this
|
||||||
|
@ -582,6 +724,11 @@ impl BaseFlow {
|
||||||
floats: Floats::new(),
|
floats: Floats::new(),
|
||||||
num_floats: 0,
|
num_floats: 0,
|
||||||
abs_position: Point2D(Au::new(0), Au::new(0)),
|
abs_position: Point2D(Au::new(0), Au::new(0)),
|
||||||
|
abs_descendants: Descendants::new(),
|
||||||
|
fixed_descendants: Descendants::new(),
|
||||||
|
absolute_static_x_offset: Au::new(0),
|
||||||
|
fixed_static_x_offset: Au::new(0),
|
||||||
|
absolute_cb: Rawlink::none(),
|
||||||
|
|
||||||
destroyed: false,
|
destroyed: false,
|
||||||
|
|
||||||
|
@ -716,25 +863,53 @@ impl<'a> MutableFlowUtils for &'a mut Flow {
|
||||||
/// Calculate and set overflow for current flow.
|
/// Calculate and set overflow for current flow.
|
||||||
///
|
///
|
||||||
/// CSS Section 11.1
|
/// CSS Section 11.1
|
||||||
/// This is ideally the union of all flows for which we define the
|
/// This is the union of rectangles of the flows for which we define the
|
||||||
/// Containing Block.
|
/// Containing Block.
|
||||||
///
|
///
|
||||||
/// Assumption: This is called in a bottom-up traversal, so kids' overflows have
|
/// Assumption: This is called in a bottom-up traversal, so kids' overflows have
|
||||||
/// already been set.
|
/// already been set.
|
||||||
/// So, currently this is a union of the overflows of all kids and our own
|
/// Assumption: Absolute descendants have had their overflow calculated.
|
||||||
/// flow rectangle.
|
|
||||||
/// FIXME: Handle the overflow of absolute flow descendants, because their
|
|
||||||
/// assign-heights happen after the normal
|
|
||||||
/// assign-height-and-store-overflow traversal
|
|
||||||
fn store_overflow(self, _: &mut LayoutContext) {
|
fn store_overflow(self, _: &mut LayoutContext) {
|
||||||
let my_position = mut_base(self).position;
|
let my_position = mut_base(self).position;
|
||||||
let mut overflow = my_position;
|
let mut overflow = my_position;
|
||||||
for kid in mut_base(self).child_iter() {
|
|
||||||
|
if self.is_block_container() {
|
||||||
|
for kid in child_iter(self) {
|
||||||
|
if kid.is_store_overflow_delayed() {
|
||||||
|
// Absolute flows will be handled by their CB. If we are
|
||||||
|
// their CB, they will show up in `abs_descendants`.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
let mut kid_overflow = base(kid).overflow;
|
let mut kid_overflow = base(kid).overflow;
|
||||||
kid_overflow = kid_overflow.translate(&my_position.origin);
|
kid_overflow = kid_overflow.translate(&my_position.origin);
|
||||||
overflow = overflow.union(&kid_overflow)
|
overflow = overflow.union(&kid_overflow)
|
||||||
}
|
}
|
||||||
mut_base(self).overflow = overflow
|
|
||||||
|
for descendant_link in mut_base(self).abs_descendants.iter() {
|
||||||
|
match descendant_link.resolve() {
|
||||||
|
Some(flow) => {
|
||||||
|
let mut kid_overflow = base(flow).overflow;
|
||||||
|
kid_overflow = kid_overflow.translate(&my_position.origin);
|
||||||
|
overflow = overflow.union(&kid_overflow)
|
||||||
|
}
|
||||||
|
None => fail!("empty Rawlink to a descendant")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.is_root() {
|
||||||
|
for fixed_descendant_link in mut_base(self).fixed_descendants.iter() {
|
||||||
|
match fixed_descendant_link.resolve() {
|
||||||
|
Some(flow) => {
|
||||||
|
let mut kid_overflow = base(flow).overflow;
|
||||||
|
kid_overflow = kid_overflow.translate(&my_position.origin);
|
||||||
|
overflow = overflow.union(&kid_overflow)
|
||||||
|
}
|
||||||
|
None => fail!("empty Rawlink to a descendant")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mut_base(self).overflow = overflow;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Push display items for current flow and its children onto `list`.
|
/// Push display items for current flow and its children onto `list`.
|
||||||
|
@ -773,23 +948,21 @@ impl<'a> MutableFlowUtils for &'a mut Flow {
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.is_block_container() {
|
if self.is_block_container() {
|
||||||
|
let block = self.as_block();
|
||||||
let mut child_lists = DisplayListCollection::new();
|
let mut child_lists = DisplayListCollection::new();
|
||||||
child_lists.add_list(DisplayList::new());
|
child_lists.add_list(DisplayList::new());
|
||||||
let child_lists = RefCell::new(child_lists);
|
let child_lists = RefCell::new(child_lists);
|
||||||
let is_positioned = self.as_block().is_positioned();
|
|
||||||
let container_block_size;
|
let container_block_size;
|
||||||
let abs_cb_position;
|
let abs_cb_position;
|
||||||
let flow_pos = base(self).abs_position;
|
// TODO(pradeep): Move this into a generated CB function and stuff in Flow.
|
||||||
match self.as_block().box_ {
|
match block.box_ {
|
||||||
Some(ref box_) => {
|
Some(ref box_) => {
|
||||||
// FIXME: This should be the size of the content box (which is the
|
// FIXME: This should be the size of the content box (which is the
|
||||||
// Containing Block formed by a BlockFlow), not the border box.
|
// Containing Block formed by a BlockFlow), not the border box.
|
||||||
container_block_size = box_.border_box.get().size;
|
container_block_size = box_.border_box.get().size;
|
||||||
|
|
||||||
abs_cb_position = if is_positioned {
|
abs_cb_position = if block.is_positioned() {
|
||||||
let padding_box_pos = flow_pos + box_.border_box.get().origin
|
block.base.abs_position + block.generated_cb_position()
|
||||||
+ Point2D(box_.border.get().left, box_.border.get().top);
|
|
||||||
padding_box_pos
|
|
||||||
} else {
|
} else {
|
||||||
absolute_cb_abs_position
|
absolute_cb_abs_position
|
||||||
};
|
};
|
||||||
|
@ -797,12 +970,48 @@ impl<'a> MutableFlowUtils for &'a mut Flow {
|
||||||
None => fail!("Flow: block container should have a box_")
|
None => fail!("Flow: block container should have a box_")
|
||||||
}
|
}
|
||||||
|
|
||||||
for kid in child_iter(self) {
|
for kid in block.base.child_iter() {
|
||||||
|
if kid.is_absolutely_positioned() {
|
||||||
|
// All absolute flows will be handled by their CB.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
kid.build_display_lists(builder, &container_block_size,
|
kid.build_display_lists(builder, &container_block_size,
|
||||||
abs_cb_position,
|
abs_cb_position,
|
||||||
dirty, 0u, &child_lists);
|
dirty, 0u, &child_lists);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Maybe we should handle position 'absolute' and 'fixed'
|
||||||
|
// descendants before normal descendants just in case there is a
|
||||||
|
// problem when display-list building is parallel and both the
|
||||||
|
// original parent and this flow access the same absolute flow.
|
||||||
|
// Note that this can only be done once we have paint order
|
||||||
|
// working cos currently the later boxes paint over the absolute
|
||||||
|
// and fixed boxes :|
|
||||||
|
for abs_descendant_link in block.base.abs_descendants.iter() {
|
||||||
|
match abs_descendant_link.resolve() {
|
||||||
|
Some(flow) => {
|
||||||
|
// TODO(pradeep): Send in your abs_position directly.
|
||||||
|
flow.build_display_lists(builder, &container_block_size,
|
||||||
|
abs_cb_position,
|
||||||
|
dirty, 0u, &child_lists);
|
||||||
|
}
|
||||||
|
None => fail!("empty Rawlink to a descendant")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if block.is_root() {
|
||||||
|
for fixed_descendant_link in block.base.fixed_descendants.iter() {
|
||||||
|
match fixed_descendant_link.resolve() {
|
||||||
|
Some(flow) => {
|
||||||
|
flow.build_display_lists(builder, &container_block_size,
|
||||||
|
abs_cb_position,
|
||||||
|
dirty, 0u, &child_lists);
|
||||||
|
}
|
||||||
|
None => fail!("empty Rawlink to a descendant")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut child_lists = Some(child_lists.unwrap());
|
let mut child_lists = Some(child_lists.unwrap());
|
||||||
// Find parent ClipDisplayItemClass and push all child display items
|
// Find parent ClipDisplayItemClass and push all child display items
|
||||||
// under it
|
// under it
|
||||||
|
@ -863,6 +1072,51 @@ impl MutableOwnedFlowUtils for ~Flow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set absolute descendants for this flow.
|
||||||
|
///
|
||||||
|
/// Set yourself as the Containing Block for all the absolute descendants.
|
||||||
|
///
|
||||||
|
/// Assumption: This is called in a bottom-up traversal, so that nothing
|
||||||
|
/// else is accessing the descendant flows.
|
||||||
|
fn set_abs_descendants(&mut self, abs_descendants: AbsDescendants) {
|
||||||
|
let self_link = Rawlink::some(*self);
|
||||||
|
let block = self.as_block();
|
||||||
|
block.base.abs_descendants = abs_descendants;
|
||||||
|
|
||||||
|
for descendant_link in block.base.abs_descendants.iter() {
|
||||||
|
match descendant_link.resolve() {
|
||||||
|
Some(flow) => {
|
||||||
|
let base = mut_base(flow);
|
||||||
|
base.absolute_cb = self_link.clone();
|
||||||
|
}
|
||||||
|
None => fail!("empty Rawlink to a descendant")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set fixed descendants for this flow.
|
||||||
|
///
|
||||||
|
/// Set yourself as the Containing Block for all the fixed descendants.
|
||||||
|
///
|
||||||
|
/// Assumption: This is called in a bottom-up traversal, so that nothing
|
||||||
|
/// else is accessing the descendant flows.
|
||||||
|
/// Assumption: This is the root flow.
|
||||||
|
fn set_fixed_descendants(&mut self, fixed_descendants: FixedDescendants) {
|
||||||
|
let self_link = Rawlink::some(*self);
|
||||||
|
let block = self.as_block();
|
||||||
|
block.base.fixed_descendants = fixed_descendants;
|
||||||
|
|
||||||
|
for descendant_link in block.base.fixed_descendants.iter() {
|
||||||
|
match descendant_link.resolve() {
|
||||||
|
Some(flow) => {
|
||||||
|
let base = mut_base(flow);
|
||||||
|
base.absolute_cb = self_link.clone();
|
||||||
|
}
|
||||||
|
None => fail!("empty Rawlink to a descendant")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Destroys the flow.
|
/// Destroys the flow.
|
||||||
fn destroy(&mut self) {
|
fn destroy(&mut self) {
|
||||||
let self_borrowed: &mut Flow = *self;
|
let self_borrowed: &mut Flow = *self;
|
||||||
|
|
|
@ -19,6 +19,10 @@ pub struct Rawlink {
|
||||||
priv obj: *mut (),
|
priv obj: *mut (),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Doubly-linked list of Flows.
|
||||||
|
///
|
||||||
|
/// The forward links are strong references.
|
||||||
|
/// The backward links are weak references.
|
||||||
pub struct FlowList {
|
pub struct FlowList {
|
||||||
priv length: uint,
|
priv length: uint,
|
||||||
priv list_head: Link,
|
priv list_head: Link,
|
||||||
|
@ -51,7 +55,7 @@ impl Rawlink {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Like Option::Some for Rawlink
|
/// Like Option::Some for Rawlink
|
||||||
fn some(n: &mut Flow) -> Rawlink {
|
pub fn some(n: &mut Flow) -> Rawlink {
|
||||||
unsafe { cast::transmute(n) }
|
unsafe { cast::transmute(n) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,7 +69,7 @@ impl Rawlink {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve(&mut self) -> Option<&mut Flow> {
|
pub fn resolve(&mut self) -> Option<&mut Flow> {
|
||||||
if self.obj.is_null() {
|
if self.obj.is_null() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -212,7 +212,11 @@ impl<'a> PostorderFlowTraversal for AssignHeightsAndStoreOverflowTraversal<'a> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn process(&mut self, flow: &mut Flow) -> bool {
|
fn process(&mut self, flow: &mut Flow) -> bool {
|
||||||
flow.assign_height(self.layout_context);
|
flow.assign_height(self.layout_context);
|
||||||
|
// Skip store-overflow for absolutely positioned flows. That will be
|
||||||
|
// done in a separate traversal.
|
||||||
|
if !flow.is_store_overflow_delayed() {
|
||||||
flow.store_overflow(self.layout_context);
|
flow.store_overflow(self.layout_context);
|
||||||
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -427,7 +431,17 @@ impl LayoutTask {
|
||||||
None => fail!("no layout data for root node"),
|
None => fail!("no layout data for root node"),
|
||||||
};
|
};
|
||||||
let mut flow = match result {
|
let mut flow = match result {
|
||||||
FlowConstructionResult(flow) => flow,
|
FlowConstructionResult(mut flow, abs_descendants, fixed_descendants) => {
|
||||||
|
// Note: Assuming that the root has display 'static' (as per
|
||||||
|
// CSS Section 9.3.1). Otherwise, if it were absolutely
|
||||||
|
// positioned, it would return a reference to itself in
|
||||||
|
// `abs_descendants` and would lead to a circular reference.
|
||||||
|
// Set Root as CB for any remaining absolute descendants.
|
||||||
|
flow.set_abs_descendants(abs_descendants);
|
||||||
|
// Set Root as CB for all fixed descendants.
|
||||||
|
flow.set_fixed_descendants(fixed_descendants);
|
||||||
|
flow
|
||||||
|
}
|
||||||
_ => fail!("Flow construction didn't result in a flow at the root of the tree!"),
|
_ => fail!("Flow construction didn't result in a flow at the root of the tree!"),
|
||||||
};
|
};
|
||||||
flow.mark_as_root();
|
flow.mark_as_root();
|
||||||
|
|
|
@ -21,13 +21,11 @@
|
||||||
# inline_text_align_a.html inline_text_align_b.html
|
# inline_text_align_a.html inline_text_align_b.html
|
||||||
== font_size_em.html font_size_em_ref.html
|
== font_size_em.html font_size_em_ref.html
|
||||||
== font_size_percentage.html font_size_em_ref.html
|
== font_size_percentage.html font_size_em_ref.html
|
||||||
== position_fixed_a.html position_fixed_b.html
|
|
||||||
== img_size_a.html img_size_b.html
|
== img_size_a.html img_size_b.html
|
||||||
== img_dynamic_remove.html img_dynamic_remove_ref.html
|
== img_dynamic_remove.html img_dynamic_remove_ref.html
|
||||||
== upper_id_attr.html upper_id_attr_ref.html
|
== upper_id_attr.html upper_id_attr_ref.html
|
||||||
# inline_border_a.html inline_border_b.html
|
# inline_border_a.html inline_border_b.html
|
||||||
== anon_block_inherit_a.html anon_block_inherit_b.html
|
== anon_block_inherit_a.html anon_block_inherit_b.html
|
||||||
== position_relative_a.html position_relative_b.html
|
|
||||||
== attr_exists_selector.html attr_exists_selector_ref.html
|
== attr_exists_selector.html attr_exists_selector_ref.html
|
||||||
== data_img_a.html data_img_b.html
|
== data_img_a.html data_img_b.html
|
||||||
== background_style_attr.html background_ref.html
|
== background_style_attr.html background_ref.html
|
||||||
|
@ -36,3 +34,13 @@
|
||||||
# == simple_iframe.html simple_iframe_ref.html -- disabled due to iframe crashiness
|
# == simple_iframe.html simple_iframe_ref.html -- disabled due to iframe crashiness
|
||||||
== object_element_a.html object_element_b.html
|
== object_element_a.html object_element_b.html
|
||||||
== height_compute_reset.html height_compute.html
|
== height_compute_reset.html height_compute.html
|
||||||
|
# Positioning tests
|
||||||
|
== position_abs_cb_with_non_cb_kid_a.html position_abs_cb_with_non_cb_kid_b.html
|
||||||
|
== position_abs_height_width_a.html position_abs_height_width_b.html
|
||||||
|
== position_abs_left_a.html position_abs_left_b.html
|
||||||
|
== position_abs_static_y_a.html position_abs_static_y_b.html
|
||||||
|
== position_abs_width_percentage_a.html position_abs_width_percentage_b.html
|
||||||
|
== position_fixed_a.html position_fixed_b.html
|
||||||
|
== position_fixed_simple_a.html position_fixed_simple_b.html
|
||||||
|
== position_fixed_static_y_a.html position_fixed_static_y_b.html
|
||||||
|
== position_relative_a.html position_relative_b.html
|
||||||
|
|
32
src/test/ref/overflow_position_abs_inside_normal_a.html
Normal file
32
src/test/ref/overflow_position_abs_inside_normal_a.html
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
<html>
|
||||||
|
<title>
|
||||||
|
`overflow: hidden` on #second has no effect on #abs because its CB is #first.
|
||||||
|
</title>
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
#first {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
#second {
|
||||||
|
height: 100px;
|
||||||
|
width: 100px;
|
||||||
|
background: red;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
#abs {
|
||||||
|
position: absolute;
|
||||||
|
height: 200px;
|
||||||
|
width: 200px;
|
||||||
|
background: green;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="first">
|
||||||
|
<div id="second">
|
||||||
|
<div id="abs">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
17
src/test/ref/overflow_position_abs_inside_normal_b.html
Normal file
17
src/test/ref/overflow_position_abs_inside_normal_b.html
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<html>
|
||||||
|
<title>
|
||||||
|
`overflow: hidden` on #second has no effect on #abs because its CB is #first.
|
||||||
|
</title>
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
#first {
|
||||||
|
height: 200px;
|
||||||
|
width: 200px;
|
||||||
|
background: green;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="first"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
24
src/test/ref/overflow_position_abs_simple_a.html
Normal file
24
src/test/ref/overflow_position_abs_simple_a.html
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
#first {
|
||||||
|
height: 100px;
|
||||||
|
width: 100px;
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
#second {
|
||||||
|
position: absolute;
|
||||||
|
height: 100px;
|
||||||
|
width: 200px;
|
||||||
|
background: green;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="first">
|
||||||
|
<div id="second">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
15
src/test/ref/overflow_position_abs_simple_b.html
Normal file
15
src/test/ref/overflow_position_abs_simple_b.html
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
#first {
|
||||||
|
height: 100px;
|
||||||
|
width: 100px;
|
||||||
|
background: green;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="first">
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
22
src/test/ref/overflow_simple_a.html
Normal file
22
src/test/ref/overflow_simple_a.html
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
#first {
|
||||||
|
height: 100px;
|
||||||
|
width: 100px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
#second {
|
||||||
|
height: 100px;
|
||||||
|
width: 200px;
|
||||||
|
background: green;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="first">
|
||||||
|
<div id="second">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
15
src/test/ref/overflow_simple_b.html
Normal file
15
src/test/ref/overflow_simple_b.html
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
#first {
|
||||||
|
height: 100px;
|
||||||
|
width: 100px;
|
||||||
|
background: green;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="first">
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
38
src/test/ref/position_abs_cb_with_non_cb_kid_a.html
Normal file
38
src/test/ref/position_abs_cb_with_non_cb_kid_a.html
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
<html>
|
||||||
|
<title>Absolute Containing Blocks with an absolute child and a non-CB child which contains an absolute flow.</title>
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
.cb {
|
||||||
|
position: relative;
|
||||||
|
width: 90px;
|
||||||
|
height: 90px;
|
||||||
|
border: solid 1px;
|
||||||
|
}
|
||||||
|
#second {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
}
|
||||||
|
#abs {
|
||||||
|
position: absolute;
|
||||||
|
left: 30px;
|
||||||
|
right: 30px;
|
||||||
|
height: 20px;
|
||||||
|
background: green;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="first-cb" class="cb">
|
||||||
|
<div id="second">
|
||||||
|
</div>
|
||||||
|
<div id="abs">
|
||||||
|
</div>
|
||||||
|
<div id="non-cb-2">
|
||||||
|
<div id="second">
|
||||||
|
</div>
|
||||||
|
<div id="abs">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
32
src/test/ref/position_abs_cb_with_non_cb_kid_b.html
Normal file
32
src/test/ref/position_abs_cb_with_non_cb_kid_b.html
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
#first {
|
||||||
|
width: 90px;
|
||||||
|
height: 90px;
|
||||||
|
border: solid 1px;
|
||||||
|
}
|
||||||
|
.row {
|
||||||
|
width: 90px;
|
||||||
|
height: 30px;
|
||||||
|
}
|
||||||
|
.center {
|
||||||
|
margin-left: 30px;
|
||||||
|
height: 20px;
|
||||||
|
width: 30px;
|
||||||
|
background: green;
|
||||||
|
}
|
||||||
|
#row2 {
|
||||||
|
height: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="first">
|
||||||
|
<div class="row"></div>
|
||||||
|
<div class="center"></div>
|
||||||
|
<div class="row" id="row2"></div>
|
||||||
|
<div class="center"></div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
31
src/test/ref/position_abs_static_y_a.html
Normal file
31
src/test/ref/position_abs_static_y_a.html
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
#first {
|
||||||
|
position: relative;
|
||||||
|
width: 90px;
|
||||||
|
height: 90px;
|
||||||
|
border: solid 1px;
|
||||||
|
}
|
||||||
|
#second {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
}
|
||||||
|
#abs {
|
||||||
|
position: absolute;
|
||||||
|
left: 30px;
|
||||||
|
right: 30px;
|
||||||
|
height: 20px;
|
||||||
|
background: green;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="first">
|
||||||
|
<div id="second">
|
||||||
|
</div>
|
||||||
|
<div id="abs">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
28
src/test/ref/position_abs_static_y_b.html
Normal file
28
src/test/ref/position_abs_static_y_b.html
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
#first {
|
||||||
|
width: 90px;
|
||||||
|
height: 90px;
|
||||||
|
border: solid 1px;
|
||||||
|
}
|
||||||
|
.row {
|
||||||
|
width: 90px;
|
||||||
|
height: 30px;
|
||||||
|
}
|
||||||
|
.center {
|
||||||
|
margin-left: 30px;
|
||||||
|
height: 20px;
|
||||||
|
width: 30px;
|
||||||
|
background: green;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="first">
|
||||||
|
<div class="row"></div>
|
||||||
|
<div class="center">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
40
src/test/ref/position_fixed_static_y_a.html
Normal file
40
src/test/ref/position_fixed_static_y_a.html
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
html, body {
|
||||||
|
margin-left: 0px;
|
||||||
|
margin-right: 0px;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
margin-top: 100px;
|
||||||
|
}
|
||||||
|
#first {
|
||||||
|
position: relative;
|
||||||
|
width: 90px;
|
||||||
|
height: 90px;
|
||||||
|
border: solid 1px;
|
||||||
|
}
|
||||||
|
#second {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
}
|
||||||
|
#fixed {
|
||||||
|
position: fixed;
|
||||||
|
left: 30px;
|
||||||
|
right: 30px;
|
||||||
|
width: 100px;
|
||||||
|
height: 20px;
|
||||||
|
background: green;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="first">
|
||||||
|
<div id="second">
|
||||||
|
</div>
|
||||||
|
<!-- This should be at its static y position (inside #first, after #second) -->
|
||||||
|
<div id="fixed">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
35
src/test/ref/position_fixed_static_y_b.html
Normal file
35
src/test/ref/position_fixed_static_y_b.html
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
html, body {
|
||||||
|
margin-left: 0px;
|
||||||
|
margin-right: 0px;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
margin-top: 100px;
|
||||||
|
}
|
||||||
|
#first {
|
||||||
|
width: 90px;
|
||||||
|
height: 90px;
|
||||||
|
border: solid 1px;
|
||||||
|
}
|
||||||
|
.row {
|
||||||
|
width: 90px;
|
||||||
|
height: 30px;
|
||||||
|
}
|
||||||
|
.center {
|
||||||
|
margin-left: 29px;
|
||||||
|
height: 20px;
|
||||||
|
width: 100px;
|
||||||
|
background: green;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="first">
|
||||||
|
<div class="row"></div>
|
||||||
|
<div class="center">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Add table
Add a link
Reference in a new issue