aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorbors-servo <release+servo@mozilla.com>2014-01-16 15:13:59 -0800
committerbors-servo <release+servo@mozilla.com>2014-01-16 15:13:59 -0800
commitb5fcc6fe86d49db8d83a10ff6e3ffd1980db0cbd (patch)
tree71adf7f08f7d18513976b2cc6d8d2c992a29bc64 /src
parentecaaf4c145ee999f5f73160436d4f642ecbb9425 (diff)
parent084c7fb73460cf3b3e0a6a6cb2b064709d287c17 (diff)
downloadservo-b5fcc6fe86d49db8d83a10ff6e3ffd1980db0cbd.tar.gz
servo-b5fcc6fe86d49db8d83a10ff6e3ffd1980db0cbd.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/components/main/layout/block.rs52
-rw-r--r--src/components/main/layout/box_.rs81
-rw-r--r--src/components/main/layout/construct.rs33
-rw-r--r--src/test/ref/basic.list1
-rw-r--r--src/test/ref/position_fixed_a.html43
-rw-r--r--src/test/ref/position_fixed_b.html43
6 files changed, 225 insertions, 28 deletions
diff --git a/src/components/main/layout/block.rs b/src/components/main/layout/block.rs
index 0aa4cf42d56..a31b1a8fd03 100644
--- a/src/components/main/layout/block.rs
+++ b/src/components/main/layout/block.rs
@@ -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;
diff --git a/src/components/main/layout/box_.rs b/src/components/main/layout/box_.rs
index bd7ba5bd000..39cb0004df1 100644
--- a/src/components/main/layout/box_.rs
+++ b/src/components/main/layout/box_.rs
@@ -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.
diff --git a/src/components/main/layout/construct.rs b/src/components/main/layout/construct.rs
index 017dffecd0b..ee06fa20af7 100644
--- a/src/components/main/layout/construct.rs
+++ b/src/components/main/layout/construct.rs
@@ -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))
diff --git a/src/test/ref/basic.list b/src/test/ref/basic.list
index 732f6b1e14a..3ce729e74dc 100644
--- a/src/test/ref/basic.list
+++ b/src/test/ref/basic.list
@@ -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
diff --git a/src/test/ref/position_fixed_a.html b/src/test/ref/position_fixed_a.html
new file mode 100644
index 00000000000..1fe3fc1ec45
--- /dev/null
+++ b/src/test/ref/position_fixed_a.html
@@ -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>
diff --git a/src/test/ref/position_fixed_b.html b/src/test/ref/position_fixed_b.html
new file mode 100644
index 00000000000..1fe3fc1ec45
--- /dev/null
+++ b/src/test/ref/position_fixed_b.html
@@ -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>