mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +01:00
Position fixed displays out of normal flow.
This commit is contained in:
parent
f58fd54875
commit
084c7fb734
7 changed files with 202 additions and 19 deletions
|
@ -55,6 +55,7 @@ pub struct BlockFlow {
|
||||||
/// The associated box.
|
/// The associated box.
|
||||||
box_: Option<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.
|
/// Whether this block flow is the root flow.
|
||||||
is_root: bool,
|
is_root: bool,
|
||||||
|
|
||||||
|
@ -360,11 +361,26 @@ impl BlockFlow {
|
||||||
margin.top = margin_top;
|
margin.top = margin_top;
|
||||||
margin.bottom = margin_bottom;
|
margin.bottom = margin_bottom;
|
||||||
|
|
||||||
position.origin.y = clearance + margin.top;
|
|
||||||
|
|
||||||
noncontent_height = box_.padding.get().top + box_.padding.get().bottom +
|
noncontent_height = box_.padding.get().top + box_.padding.get().bottom +
|
||||||
box_.border.get().top + box_.border.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;
|
noncontent_height = noncontent_height + clearance + margin.top + margin.bottom;
|
||||||
|
|
||||||
|
@ -372,7 +388,11 @@ impl BlockFlow {
|
||||||
box_.margin.set(margin);
|
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 {
|
if inorder {
|
||||||
let extra_height = height - (cur_y - top_offset) + bottom_offset;
|
let extra_height = height - (cur_y - top_offset) + bottom_offset;
|
||||||
|
@ -489,9 +509,9 @@ impl BlockFlow {
|
||||||
for box_ in self.box_.iter() {
|
for box_ in self.box_.iter() {
|
||||||
box_.build_display_list(builder, dirty, self.base.abs_position, (&*self) as &Flow, list)
|
box_.build_display_list(builder, dirty, self.base.abs_position, (&*self) as &Flow, list)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: handle any out-of-flow elements
|
// TODO: handle any out-of-flow elements
|
||||||
let this_position = self.base.abs_position;
|
let this_position = self.base.abs_position;
|
||||||
|
|
||||||
for child in self.base.child_iter() {
|
for child in self.base.child_iter() {
|
||||||
let child_base = flow::mut_base(*child);
|
let child_base = flow::mut_base(*child);
|
||||||
child_base.abs_position = this_position + child_base.position.origin;
|
child_base.abs_position = this_position + child_base.position.origin;
|
||||||
|
@ -600,7 +620,7 @@ impl Flow for BlockFlow {
|
||||||
},
|
},
|
||||||
self.base.id);
|
self.base.id);
|
||||||
|
|
||||||
if self.is_root || self.is_fixed {
|
if self.is_root {
|
||||||
debug!("Setting root position");
|
debug!("Setting root position");
|
||||||
self.base.position.origin = Au::zero_point();
|
self.base.position.origin = Au::zero_point();
|
||||||
self.base.position.size.width = ctx.screen_size.size.width;
|
self.base.position.size.width = ctx.screen_size.size.width;
|
||||||
|
@ -648,12 +668,19 @@ impl Flow for BlockFlow {
|
||||||
margin_bottom,
|
margin_bottom,
|
||||||
margin_left));
|
margin_left));
|
||||||
|
|
||||||
x_offset = box_.offset();
|
let (x, w) = box_.get_x_coord_and_new_width_if_fixed(ctx.screen_size.size.width,
|
||||||
remaining_width = 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.
|
// The associated box is the border box of this flow.
|
||||||
let mut position_ref = box_.position.borrow_mut();
|
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 +
|
let padding_and_borders = box_.padding.get().left + box_.padding.get().right +
|
||||||
box_.border.get().left + box_.border.get().right;
|
box_.border.get().left + box_.border.get().right;
|
||||||
position_ref.get().size.width = remaining_width + padding_and_borders;
|
position_ref.get().size.width = remaining_width + padding_and_borders;
|
||||||
|
|
|
@ -37,7 +37,7 @@ use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData, ToG
|
||||||
use layout::float_context::{ClearType, ClearLeft, ClearRight, ClearBoth};
|
use layout::float_context::{ClearType, ClearLeft, ClearRight, ClearBoth};
|
||||||
use layout::flow::Flow;
|
use layout::flow::Flow;
|
||||||
use layout::flow;
|
use layout::flow;
|
||||||
use layout::model::{MaybeAuto, specified};
|
use layout::model::{MaybeAuto, Auto, specified};
|
||||||
use layout::util::OpaqueNode;
|
use layout::util::OpaqueNode;
|
||||||
use layout::wrapper::LayoutNode;
|
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
|
/// Transforms this box into another box of the given type, with the given size, preserving all
|
||||||
/// the other data.
|
/// the other data.
|
||||||
pub fn transform(&self, size: Size2D<Au>, specific: SpecificBoxInfo) -> Box {
|
pub fn transform(&self, size: Size2D<Au>, specific: SpecificBoxInfo) -> Box {
|
||||||
|
@ -375,12 +440,16 @@ impl Box {
|
||||||
style.Border.border_left_style)))
|
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(
|
self.position_offsets.set(SideOffsets2D::new(
|
||||||
MaybeAuto::from_style(style.PositionOffsets.top, Au::new(0)).specified_or_zero(),
|
MaybeAuto::from_style(style.PositionOffsets.top, containing_height)
|
||||||
MaybeAuto::from_style(style.PositionOffsets.right, Au::new(0)).specified_or_zero(),
|
.specified_or_zero(),
|
||||||
MaybeAuto::from_style(style.PositionOffsets.bottom, Au::new(0)).specified_or_zero(),
|
MaybeAuto::from_style(style.PositionOffsets.right, containing_width)
|
||||||
MaybeAuto::from_style(style.PositionOffsets.left, Au::new(0)).specified_or_zero()));
|
.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.
|
/// Populates the box model padding parameters from the given computed style.
|
||||||
|
|
|
@ -344,10 +344,10 @@ impl<'fc> FlowConstructor<'fc> {
|
||||||
/// 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: LayoutNode, is_fixed: bool) -> ~Flow: {
|
fn build_flow_for_block(&mut self, node: LayoutNode, is_fixed: bool) -> ~Flow {
|
||||||
let base = BaseFlow::new(self.next_flow_id(), node);
|
let base = BaseFlow::new(self.next_flow_id(), node);
|
||||||
let box_ = self.build_box_for_node(node);
|
let box_ = self.build_box_for_node(node);
|
||||||
let mut flow = ~BlockFlow::from_box(base, box_, is_fixed) as ~Flow:;
|
let mut flow = ~BlockFlow::from_box(base, box_, is_fixed) as ~Flow;
|
||||||
self.build_children_of_block_flow(&mut flow, node);
|
self.build_children_of_block_flow(&mut flow, node);
|
||||||
flow
|
flow
|
||||||
}
|
}
|
||||||
|
|
|
@ -378,7 +378,7 @@ impl LayoutTask {
|
||||||
};
|
};
|
||||||
flow.mark_as_root();
|
flow.mark_as_root();
|
||||||
flow
|
flow
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Performs layout constraint solving.
|
/// Performs layout constraint solving.
|
||||||
///
|
///
|
||||||
|
@ -399,7 +399,7 @@ impl LayoutTask {
|
||||||
// For now, this is an inorder traversal
|
// For now, this is an inorder traversal
|
||||||
// FIXME: prune this traversal as well
|
// FIXME: prune this traversal as well
|
||||||
let _ = layout_root.traverse_postorder(&mut
|
let _ = layout_root.traverse_postorder(&mut
|
||||||
AssignHeightsAndStoreOverflowTraversal(layout_context));
|
AssignHeightsAndStoreOverflowTraversal(layout_context));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The high-level routine that performs layout tasks.
|
/// The high-level routine that performs layout tasks.
|
||||||
|
|
|
@ -21,3 +21,4 @@
|
||||||
== 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
|
||||||
|
|
43
src/test/ref/position_fixed_a.html
Normal file
43
src/test/ref/position_fixed_a.html
Normal 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>
|
43
src/test/ref/position_fixed_b.html
Normal file
43
src/test/ref/position_fixed_b.html
Normal 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>
|
Loading…
Add table
Add a link
Reference in a new issue