auto merge of #1440 : ibnc/servo/position_fixed, r=larsbergstrom

Actually removing from the normal flow will come later. 

There are some fixes for the positioned box offsets, like actually parsing percentages and naming consistency.
This commit is contained in:
bors-servo 2014-01-16 15:13:59 -08:00
commit b5fcc6fe86
6 changed files with 225 additions and 28 deletions

View file

@ -55,9 +55,12 @@ pub struct BlockFlow {
/// The associated box.
box_: Option<Box>,
//TODO: is_fixed and is_root should be bit fields to conserve memory.
/// Whether this block flow is the root flow.
is_root: bool,
is_fixed: bool,
/// Additional floating flow members.
float: Option<~FloatedBlockInfo>
}
@ -68,15 +71,17 @@ impl BlockFlow {
base: base,
box_: None,
is_root: false,
is_fixed: false,
float: None
}
}
pub fn from_box(base: BaseFlow, box_: Box) -> BlockFlow {
pub fn from_box(base: BaseFlow, box_: Box, is_fixed: bool) -> BlockFlow {
BlockFlow {
base: base,
box_: Some(box_),
is_root: false,
is_fixed: is_fixed,
float: None
}
}
@ -86,6 +91,7 @@ impl BlockFlow {
base: base,
box_: Some(box_),
is_root: false,
is_fixed: false,
float: Some(~FloatedBlockInfo::new(float_type))
}
}
@ -95,6 +101,7 @@ impl BlockFlow {
base: base,
box_: None,
is_root: true,
is_fixed: false,
float: None
}
}
@ -104,6 +111,7 @@ impl BlockFlow {
base: base,
box_: None,
is_root: false,
is_fixed: false,
float: Some(~FloatedBlockInfo::new(float_type))
}
}
@ -353,11 +361,26 @@ impl BlockFlow {
margin.top = margin_top;
margin.bottom = margin_bottom;
position.origin.y = clearance + margin.top;
noncontent_height = box_.padding.get().top + box_.padding.get().bottom +
box_.border.get().top + box_.border.get().bottom;
position.size.height = height + noncontent_height;
let (y, h) = box_.get_y_coord_and_new_height_if_fixed(ctx.screen_size.size.height,
height, clearance + margin.top, self.is_fixed);
position.origin.y = y;
height = h;
if self.is_fixed {
for kid in self.base.child_iter() {
let child_node = flow::mut_base(*kid);
child_node.position.origin.y = position.origin.y + top_offset;
}
}
position.size.height = if self.is_fixed {
height
} else {
height + noncontent_height
};
noncontent_height = noncontent_height + clearance + margin.top + margin.bottom;
@ -365,7 +388,11 @@ impl BlockFlow {
box_.margin.set(margin);
}
self.base.position.size.height = height + noncontent_height;
self.base.position.size.height = if self.is_fixed {
height
} else {
height + noncontent_height
};
if inorder {
let extra_height = height - (cur_y - top_offset) + bottom_offset;
@ -482,9 +509,9 @@ impl BlockFlow {
for box_ in self.box_.iter() {
box_.build_display_list(builder, dirty, self.base.abs_position, (&*self) as &Flow, list)
}
// TODO: handle any out-of-flow elements
let this_position = self.base.abs_position;
for child in self.base.child_iter() {
let child_base = flow::mut_base(*child);
child_base.abs_position = this_position + child_base.position.origin;
@ -641,12 +668,19 @@ impl Flow for BlockFlow {
margin_bottom,
margin_left));
x_offset = box_.offset();
remaining_width = width;
let (x, w) = box_.get_x_coord_and_new_width_if_fixed(ctx.screen_size.size.width,
ctx.screen_size.size.height, width, box_.offset(), self.is_fixed);
x_offset = x;
remaining_width = w;
// The associated box is the border box of this flow.
let mut position_ref = box_.position.borrow_mut();
position_ref.get().origin.x = box_.margin.get().left;
if self.is_fixed {
position_ref.get().origin.x = x_offset + box_.margin.get().left;
x_offset = x_offset + box_.padding.get().left;
} else {
position_ref.get().origin.x = box_.margin.get().left;
}
let padding_and_borders = box_.padding.get().left + box_.padding.get().right +
box_.border.get().left + box_.border.get().right;
position_ref.get().size.width = remaining_width + padding_and_borders;

View file

@ -37,7 +37,7 @@ use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData, ToG
use layout::float_context::{ClearType, ClearLeft, ClearRight, ClearBoth};
use layout::flow::Flow;
use layout::flow;
use layout::model::{MaybeAuto, specified};
use layout::model::{MaybeAuto, Auto, specified};
use layout::util::OpaqueNode;
use layout::wrapper::LayoutNode;
@ -306,6 +306,71 @@ impl Box {
}
}
//TODO(ibnc) take into account padding.
pub fn get_y_coord_and_new_height_if_fixed(&self,
screen_height: Au,
mut height: Au,
mut y: Au,
is_fixed: bool)
-> (Au, Au) {
if is_fixed {
let position_offsets = self.position_offsets.get();
match (position_offsets.top, position_offsets.bottom) {
(Au(0), Au(0)) => {}
(Au(0), _) => {
y = screen_height - position_offsets.bottom - height;
}
(_, Au(0)) => {
y = position_offsets.top;
}
(_, _) => {
y = position_offsets.top;
match MaybeAuto::from_style(self.style().Box.height, Au(0)) {
Auto => {
height = screen_height - position_offsets.top - position_offsets.bottom;
}
_ => {}
}
}
}
}
return (y, height);
}
//TODO(ibnc) removing padding when width needs to be stretched.
pub fn get_x_coord_and_new_width_if_fixed(&self,
screen_width: Au,
screen_height: Au,
mut width: Au,
mut x: Au,
is_fixed: bool)
-> (Au, Au) {
if is_fixed {
self.compute_positioned_offsets(self.style(), screen_width, screen_height);
let position_offsets = self.position_offsets.get();
match (position_offsets.left, position_offsets.right) {
(Au(0), Au(0)) => {}
(_, Au(0)) => {
x = position_offsets.left;
}
(Au(0), _) => {
x = screen_width - position_offsets.right - width;
}
(_, _) => {
x = position_offsets.left;
match MaybeAuto::from_style(self.style().Box.width, Au(0)) {
Auto => {
width = screen_width - position_offsets.left - position_offsets.right;
}
_ => {}
}
}
}
}
return (x, width);
}
/// Transforms this box into another box of the given type, with the given size, preserving all
/// the other data.
pub fn transform(&self, size: Size2D<Au>, specific: SpecificBoxInfo) -> Box {
@ -375,12 +440,16 @@ impl Box {
style.Border.border_left_style)))
}
pub fn compute_positioned_offset(&self, style: &ComputedValues) {
pub fn compute_positioned_offsets(&self, style: &ComputedValues, containing_width: Au, containing_height: Au) {
self.position_offsets.set(SideOffsets2D::new(
MaybeAuto::from_style(style.PositionOffsets.top, Au::new(0)).specified_or_zero(),
MaybeAuto::from_style(style.PositionOffsets.right, Au::new(0)).specified_or_zero(),
MaybeAuto::from_style(style.PositionOffsets.bottom, Au::new(0)).specified_or_zero(),
MaybeAuto::from_style(style.PositionOffsets.left, Au::new(0)).specified_or_zero()));
MaybeAuto::from_style(style.PositionOffsets.top, containing_height)
.specified_or_zero(),
MaybeAuto::from_style(style.PositionOffsets.right, containing_width)
.specified_or_zero(),
MaybeAuto::from_style(style.PositionOffsets.bottom, containing_height)
.specified_or_zero(),
MaybeAuto::from_style(style.PositionOffsets.left, containing_width)
.specified_or_zero()));
}
/// Populates the box model padding parameters from the given computed style.

View file

@ -35,7 +35,7 @@ use layout::wrapper::{LayoutNode, PostorderNodeMutTraversal};
use script::dom::element::{HTMLIframeElementTypeId, HTMLImageElementTypeId};
use script::dom::node::{CommentNodeTypeId, DoctypeNodeTypeId, DocumentFragmentNodeTypeId};
use script::dom::node::{DocumentNodeTypeId, ElementNodeTypeId, TextNodeTypeId};
use style::computed_values::{display, float};
use style::computed_values::{display, position, float};
use std::cell::RefCell;
use std::util;
@ -344,10 +344,10 @@ impl<'fc> FlowConstructor<'fc> {
/// 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: LayoutNode) -> ~Flow {
fn build_flow_for_block(&mut self, node: LayoutNode, is_fixed: bool) -> ~Flow {
let base = BaseFlow::new(self.next_flow_id(), node);
let box_ = self.build_box_for_node(node);
let mut flow = ~BlockFlow::from_box(base, box_) as ~Flow;
let mut flow = ~BlockFlow::from_box(base, box_, is_fixed) as ~Flow;
self.build_children_of_block_flow(&mut flow, node);
flow
}
@ -363,6 +363,7 @@ impl<'fc> FlowConstructor<'fc> {
flow
}
/// Concatenates the boxes of kids, adding in our own borders/padding/margins if necessary.
/// Returns the `InlineBoxesConstructionResult`, if any. There will be no
/// `InlineBoxesConstructionResult` if this node consisted entirely of ignorable whitespace.
@ -504,47 +505,53 @@ impl<'a> PostorderNodeMutTraversal for FlowConstructor<'a> {
#[inline(always)]
fn process(&mut self, node: LayoutNode) -> bool {
// Get the `display` property for this node, and determine whether this node is floated.
let (display, float) = match node.type_id() {
let (display, float, position) = match node.type_id() {
ElementNodeTypeId(_) => {
let style = node.style().get();
(style.Box.display, style.Box.float)
(style.Box.display, style.Box.float, style.Box.position)
}
TextNodeTypeId => (display::inline, float::none),
TextNodeTypeId => (display::inline, float::none, position::static_),
CommentNodeTypeId |
DoctypeNodeTypeId |
DocumentFragmentNodeTypeId |
DocumentNodeTypeId(_) => (display::none, float::none),
DocumentNodeTypeId(_) => (display::none, float::none, position::static_),
};
debug!("building flow for node: {:?} {:?}", display, float);
// Switch on display and floatedness.
match (display, float) {
match (display, float, position) {
// `display: none` contributes no flow construction result. Nuke the flow construction
// results of children.
(display::none, _) => {
(display::none, _, _) => {
for child in node.children() {
child.set_flow_construction_result(NoConstructionResult)
}
}
// Inline items contribute inline box construction results.
(display::inline, float::none) => {
(display::inline, float::none, _) => {
let construction_result = self.build_boxes_for_inline(node);
node.set_flow_construction_result(construction_result)
}
// Block flows that are not floated contribute block flow construction results.
//
// TODO(pcwalton): Make this only trigger for blocks and handle the other `display`
// properties separately.
(_, float::none) => {
let flow = self.build_flow_for_block(node);
(_, _, position::fixed) => {
let flow = self.build_flow_for_block(node, true);
node.set_flow_construction_result(FlowConstructionResult(flow))
}
(_, float::none, _) => {
let flow = self.build_flow_for_block(node, false);
node.set_flow_construction_result(FlowConstructionResult(flow))
}
// Floated flows contribute float flow construction results.
(_, float_value) => {
(_, float_value, _) => {
let float_type = FloatType::from_property(float_value);
let flow = self.build_flow_for_floated_block(node, float_type);
node.set_flow_construction_result(FlowConstructionResult(flow))

View file

@ -21,3 +21,4 @@
== inline_text_align_a.html inline_text_align_b.html
== font_size_em.html font_size_em_ref.html
== font_size_percentage.html font_size_em_ref.html
== position_fixed_a.html position_fixed_b.html

View file

@ -0,0 +1,43 @@
<html>
<head>
<style>
.container {
display: block;
background: blue;
}
.fixed_block {
background: green;
position: fixed;
}
.positioned_fixed_block {
background: yellow;
position: fixed;
top: 50%;
right: 25px;
}
.sized_fixed_block {
background: red;
position: fixed;
height: 50px;
width: 50px;
left: 5px;
right: 10px;
top: 100px;
bottom: 30px;
}
.stretched_fixed_block {
position: fixed;
background: black;
top: 100px;
bottom: 30px;
}
</style>
</head>
<body>
<div class="container">
<div class="fixed_block"> fixed block </div>
<div class="positioned_fixed_block"> positioned fixed block </div>
<div class="sized_fixed_block"> sized fixed block </div>
</div>
</body>
</html>

View file

@ -0,0 +1,43 @@
<html>
<head>
<style>
.container {
display: block;
background: blue;
}
.fixed_block {
background: green;
position: fixed;
}
.positioned_fixed_block {
background: yellow;
position: fixed;
top: 50%;
right: 25px;
}
.sized_fixed_block {
background: red;
position: fixed;
height: 50px;
width: 50px;
left: 5px;
right: 10px;
top: 100px;
bottom: 30px;
}
.stretched_fixed_block {
position: fixed;
background: black;
top: 100px;
bottom: 30px;
}
</style>
</head>
<body>
<div class="container">
<div class="fixed_block"> fixed block </div>
<div class="positioned_fixed_block"> positioned fixed block </div>
<div class="sized_fixed_block"> sized fixed block </div>
</div>
</body>
</html>