diff options
author | bors-servo <release+servo@mozilla.com> | 2014-01-16 15:13:59 -0800 |
---|---|---|
committer | bors-servo <release+servo@mozilla.com> | 2014-01-16 15:13:59 -0800 |
commit | b5fcc6fe86d49db8d83a10ff6e3ffd1980db0cbd (patch) | |
tree | 71adf7f08f7d18513976b2cc6d8d2c992a29bc64 /src | |
parent | ecaaf4c145ee999f5f73160436d4f642ecbb9425 (diff) | |
parent | 084c7fb73460cf3b3e0a6a6cb2b064709d287c17 (diff) | |
download | servo-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.rs | 52 | ||||
-rw-r--r-- | src/components/main/layout/box_.rs | 81 | ||||
-rw-r--r-- | src/components/main/layout/construct.rs | 33 | ||||
-rw-r--r-- | src/test/ref/basic.list | 1 | ||||
-rw-r--r-- | src/test/ref/position_fixed_a.html | 43 | ||||
-rw-r--r-- | src/test/ref/position_fixed_b.html | 43 |
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> |