layout: Implement floated list items.

This patch also makes Servo not crash when
`generated_containing_block_rect()` is called on a list item (as, for
example, GitHub does), and for good measure I added the fix to other
flows as well.
This commit is contained in:
Patrick Walton 2014-12-22 11:40:20 -08:00
parent c8e68fa45c
commit d891c677aa
9 changed files with 110 additions and 12 deletions

View file

@ -860,8 +860,8 @@ impl<'a> FlowConstructor<'a> {
/// Builds a flow for a node with `display: table`. This yields a `TableWrapperFlow` with /// Builds a flow for a node with `display: table`. This yields a `TableWrapperFlow` with
/// possibly other `TableCaptionFlow`s or `TableFlow`s underneath it. /// possibly other `TableCaptionFlow`s or `TableFlow`s underneath it.
fn build_flow_for_table_wrapper(&mut self, node: &ThreadSafeLayoutNode, fn build_flow_for_table_wrapper(&mut self, node: &ThreadSafeLayoutNode, float_value: float::T)
float_value: float::T) -> ConstructionResult { -> ConstructionResult {
let fragment = Fragment::new_from_specific_info(node, SpecificFragmentInfo::TableWrapper); let fragment = Fragment::new_from_specific_info(node, SpecificFragmentInfo::TableWrapper);
let wrapper_flow = match float_value { let wrapper_flow = match float_value {
float::T::none => box TableWrapperFlow::from_node_and_fragment(node, fragment), float::T::none => box TableWrapperFlow::from_node_and_fragment(node, fragment),
@ -974,7 +974,12 @@ impl<'a> FlowConstructor<'a> {
/// Builds a flow for a node with `display: list-item`. This yields a `ListItemFlow` with /// Builds a flow for a node with `display: list-item`. This yields a `ListItemFlow` with
/// possibly other `BlockFlow`s or `InlineFlow`s underneath it. /// possibly other `BlockFlow`s or `InlineFlow`s underneath it.
fn build_flow_for_list_item(&mut self, node: &ThreadSafeLayoutNode) -> ConstructionResult { fn build_flow_for_list_item(&mut self, node: &ThreadSafeLayoutNode, flotation: float::T)
-> ConstructionResult {
let flotation = match flotation {
float::T::none => None,
flotation => Some(FloatKind::from_property(flotation)),
};
let marker_fragment = match node.style().get_list().list_style_image { let marker_fragment = match node.style().get_list().list_style_image {
Some(ref url) => { Some(ref url) => {
Some(Fragment::new_from_specific_info( Some(Fragment::new_from_specific_info(
@ -1012,11 +1017,17 @@ impl<'a> FlowConstructor<'a> {
let initial_fragment; let initial_fragment;
match node.style().get_list().list_style_position { match node.style().get_list().list_style_position {
list_style_position::T::outside => { list_style_position::T::outside => {
flow = box ListItemFlow::from_node_and_marker(self, node, marker_fragment); flow = box ListItemFlow::from_node_marker_and_flotation(self,
node,
marker_fragment,
flotation);
initial_fragment = None; initial_fragment = None;
} }
list_style_position::T::inside => { list_style_position::T::inside => {
flow = box ListItemFlow::from_node_and_marker(self, node, None); flow = box ListItemFlow::from_node_marker_and_flotation(self,
node,
None,
flotation);
initial_fragment = marker_fragment; initial_fragment = marker_fragment;
} }
} }
@ -1181,8 +1192,9 @@ impl<'a> PostorderNodeMutTraversal for FlowConstructor<'a> {
} }
// List items contribute their own special flows. // List items contribute their own special flows.
(display::T::list_item, _, _) => { (display::T::list_item, float_value, _) => {
node.set_flow_construction_result(self.build_flow_for_list_item(node)) node.set_flow_construction_result(self.build_flow_for_list_item(node,
float_value))
} }
// Inline items that are absolutely-positioned contribute inline fragment construction // Inline items that are absolutely-positioned contribute inline fragment construction

View file

@ -11,6 +11,7 @@ use block::BlockFlow;
use construct::FlowConstructor; use construct::FlowConstructor;
use context::LayoutContext; use context::LayoutContext;
use display_list_builder::ListItemFlowDisplayListBuilding; use display_list_builder::ListItemFlowDisplayListBuilding;
use floats::FloatKind;
use flow::{Flow, FlowClass}; use flow::{Flow, FlowClass};
use fragment::{Fragment, FragmentBorderBoxIterator}; use fragment::{Fragment, FragmentBorderBoxIterator};
use wrapper::ThreadSafeLayoutNode; use wrapper::ThreadSafeLayoutNode;
@ -18,6 +19,7 @@ use wrapper::ThreadSafeLayoutNode;
use geom::{Point2D, Rect}; use geom::{Point2D, Rect};
use gfx::display_list::DisplayList; use gfx::display_list::DisplayList;
use servo_util::geometry::Au; use servo_util::geometry::Au;
use servo_util::logical_geometry::LogicalRect;
use servo_util::opts; use servo_util::opts;
use style::ComputedValues; use style::ComputedValues;
use style::computed_values::list_style_type; use style::computed_values::list_style_type;
@ -34,12 +36,17 @@ pub struct ListItemFlow {
} }
impl ListItemFlow { impl ListItemFlow {
pub fn from_node_and_marker(constructor: &mut FlowConstructor, pub fn from_node_marker_and_flotation(constructor: &mut FlowConstructor,
node: &ThreadSafeLayoutNode, node: &ThreadSafeLayoutNode,
marker_fragment: Option<Fragment>) marker_fragment: Option<Fragment>,
-> ListItemFlow { flotation: Option<FloatKind>)
-> ListItemFlow {
ListItemFlow { ListItemFlow {
block_flow: BlockFlow::from_node(constructor, node), block_flow: if let Some(flotation) = flotation {
BlockFlow::float_from_node(constructor, node, flotation)
} else {
BlockFlow::from_node(constructor, node)
},
marker: marker_fragment, marker: marker_fragment,
} }
} }
@ -93,6 +100,10 @@ impl Flow for ListItemFlow {
self.block_flow.compute_absolute_position() self.block_flow.compute_absolute_position()
} }
fn place_float_if_applicable<'a>(&mut self, layout_context: &'a LayoutContext<'a>) {
self.block_flow.place_float_if_applicable(layout_context)
}
fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) { fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) {
self.block_flow.update_late_computed_inline_position_if_necessary(inline_position) self.block_flow.update_late_computed_inline_position_if_necessary(inline_position)
} }
@ -116,6 +127,10 @@ impl Flow for ListItemFlow {
self.block_flow.compute_overflow() self.block_flow.compute_overflow()
} }
fn generated_containing_block_rect(&self) -> LogicalRect<Au> {
self.block_flow.generated_containing_block_rect()
}
fn iterate_through_fragment_border_boxes(&self, fn iterate_through_fragment_border_boxes(&self,
iterator: &mut FragmentBorderBoxIterator, iterator: &mut FragmentBorderBoxIterator,
stacking_context_position: &Point2D<Au>) { stacking_context_position: &Point2D<Au>) {

View file

@ -15,6 +15,7 @@ use wrapper::ThreadSafeLayoutNode;
use geom::{Point2D, Rect}; use geom::{Point2D, Rect};
use servo_util::geometry::Au; use servo_util::geometry::Au;
use servo_util::logical_geometry::LogicalRect;
use std::fmt; use std::fmt;
use style::ComputedValues; use style::ComputedValues;
use std::sync::Arc; use std::sync::Arc;
@ -86,6 +87,10 @@ impl Flow for TableCaptionFlow {
self.block_flow.compute_overflow() self.block_flow.compute_overflow()
} }
fn generated_containing_block_rect(&self) -> LogicalRect<Au> {
self.block_flow.generated_containing_block_rect()
}
fn iterate_through_fragment_border_boxes(&self, fn iterate_through_fragment_border_boxes(&self,
iterator: &mut FragmentBorderBoxIterator, iterator: &mut FragmentBorderBoxIterator,
stacking_context_position: &Point2D<Au>) { stacking_context_position: &Point2D<Au>) {

View file

@ -17,6 +17,7 @@ use wrapper::ThreadSafeLayoutNode;
use geom::{Point2D, Rect}; use geom::{Point2D, Rect};
use servo_util::geometry::Au; use servo_util::geometry::Au;
use servo_util::logical_geometry::LogicalRect;
use std::fmt; use std::fmt;
use style::{UnsignedIntegerAttribute, ComputedValues}; use style::{UnsignedIntegerAttribute, ComputedValues};
use std::sync::Arc; use std::sync::Arc;
@ -167,6 +168,10 @@ impl Flow for TableCellFlow {
self.block_flow.compute_overflow() self.block_flow.compute_overflow()
} }
fn generated_containing_block_rect(&self) -> LogicalRect<Au> {
self.block_flow.generated_containing_block_rect()
}
fn iterate_through_fragment_border_boxes(&self, fn iterate_through_fragment_border_boxes(&self,
iterator: &mut FragmentBorderBoxIterator, iterator: &mut FragmentBorderBoxIterator,
stacking_context_position: &Point2D<Au>) { stacking_context_position: &Point2D<Au>) {

View file

@ -20,6 +20,7 @@ use wrapper::ThreadSafeLayoutNode;
use geom::{Point2D, Rect}; use geom::{Point2D, Rect};
use servo_util::geometry::Au; use servo_util::geometry::Au;
use servo_util::logical_geometry::LogicalRect;
use std::cmp::max; use std::cmp::max;
use std::fmt; use std::fmt;
use style::ComputedValues; use style::ComputedValues;
@ -320,6 +321,10 @@ impl Flow for TableRowFlow {
self.block_flow.compute_overflow() self.block_flow.compute_overflow()
} }
fn generated_containing_block_rect(&self) -> LogicalRect<Au> {
self.block_flow.generated_containing_block_rect()
}
fn iterate_through_fragment_border_boxes(&self, fn iterate_through_fragment_border_boxes(&self,
iterator: &mut FragmentBorderBoxIterator, iterator: &mut FragmentBorderBoxIterator,
stacking_context_position: &Point2D<Au>) { stacking_context_position: &Point2D<Au>) {

View file

@ -17,6 +17,7 @@ use wrapper::ThreadSafeLayoutNode;
use geom::{Point2D, Rect}; use geom::{Point2D, Rect};
use servo_util::geometry::Au; use servo_util::geometry::Au;
use servo_util::logical_geometry::LogicalRect;
use std::fmt; use std::fmt;
use style::ComputedValues; use style::ComputedValues;
use std::sync::Arc; use std::sync::Arc;
@ -155,6 +156,10 @@ impl Flow for TableRowGroupFlow {
self.block_flow.compute_overflow() self.block_flow.compute_overflow()
} }
fn generated_containing_block_rect(&self) -> LogicalRect<Au> {
self.block_flow.generated_containing_block_rect()
}
fn iterate_through_fragment_border_boxes(&self, fn iterate_through_fragment_border_boxes(&self,
iterator: &mut FragmentBorderBoxIterator, iterator: &mut FragmentBorderBoxIterator,
stacking_context_position: &Point2D<Au>) { stacking_context_position: &Point2D<Au>) {

View file

@ -233,3 +233,4 @@ fragment=top != ../html/acid2.html acid2_ref.html
== filter_sepia_a.html filter_sepia_ref.html == filter_sepia_a.html filter_sepia_ref.html
== mix_blend_mode_a.html mix_blend_mode_ref.html == mix_blend_mode_a.html mix_blend_mode_ref.html
!= text_overflow_a.html text_overflow_ref.html != text_overflow_a.html text_overflow_ref.html
== floated_list_item_a.html floated_list_item_ref.html

View file

@ -0,0 +1,26 @@
<!DOCTYPE html>
<html>
<head>
<!-- Tests that list items can be floated. -->
<style>
ul div {
display: list-item;
float: left;
list-style: none;
margin: 0;
}
ul {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<ul>
<div>Foo</div>
<div>Bar</div>
<div>Baz</div>
</ul>
</body>
</html>

View file

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html>
<head>
<!-- Tests that list items can be floated. -->
<style>
ul div {
float: left;
margin: 0;
}
ul {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<ul>
<div>Foo</div>
<div>Bar</div>
<div>Baz</div>
</ul>
</body>
</html>