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
/// possibly other `TableCaptionFlow`s or `TableFlow`s underneath it.
fn build_flow_for_table_wrapper(&mut self, node: &ThreadSafeLayoutNode,
float_value: float::T) -> ConstructionResult {
fn build_flow_for_table_wrapper(&mut self, node: &ThreadSafeLayoutNode, float_value: float::T)
-> ConstructionResult {
let fragment = Fragment::new_from_specific_info(node, SpecificFragmentInfo::TableWrapper);
let wrapper_flow = match float_value {
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
/// 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 {
Some(ref url) => {
Some(Fragment::new_from_specific_info(
@ -1012,11 +1017,17 @@ impl<'a> FlowConstructor<'a> {
let initial_fragment;
match node.style().get_list().list_style_position {
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;
}
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;
}
}
@ -1181,8 +1192,9 @@ impl<'a> PostorderNodeMutTraversal for FlowConstructor<'a> {
}
// List items contribute their own special flows.
(display::T::list_item, _, _) => {
node.set_flow_construction_result(self.build_flow_for_list_item(node))
(display::T::list_item, float_value, _) => {
node.set_flow_construction_result(self.build_flow_for_list_item(node,
float_value))
}
// Inline items that are absolutely-positioned contribute inline fragment construction

View file

@ -11,6 +11,7 @@ use block::BlockFlow;
use construct::FlowConstructor;
use context::LayoutContext;
use display_list_builder::ListItemFlowDisplayListBuilding;
use floats::FloatKind;
use flow::{Flow, FlowClass};
use fragment::{Fragment, FragmentBorderBoxIterator};
use wrapper::ThreadSafeLayoutNode;
@ -18,6 +19,7 @@ use wrapper::ThreadSafeLayoutNode;
use geom::{Point2D, Rect};
use gfx::display_list::DisplayList;
use servo_util::geometry::Au;
use servo_util::logical_geometry::LogicalRect;
use servo_util::opts;
use style::ComputedValues;
use style::computed_values::list_style_type;
@ -34,12 +36,17 @@ pub struct ListItemFlow {
}
impl ListItemFlow {
pub fn from_node_and_marker(constructor: &mut FlowConstructor,
pub fn from_node_marker_and_flotation(constructor: &mut FlowConstructor,
node: &ThreadSafeLayoutNode,
marker_fragment: Option<Fragment>)
marker_fragment: Option<Fragment>,
flotation: Option<FloatKind>)
-> 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,
}
}
@ -93,6 +100,10 @@ impl Flow for ListItemFlow {
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) {
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()
}
fn generated_containing_block_rect(&self) -> LogicalRect<Au> {
self.block_flow.generated_containing_block_rect()
}
fn iterate_through_fragment_border_boxes(&self,
iterator: &mut FragmentBorderBoxIterator,
stacking_context_position: &Point2D<Au>) {

View file

@ -15,6 +15,7 @@ use wrapper::ThreadSafeLayoutNode;
use geom::{Point2D, Rect};
use servo_util::geometry::Au;
use servo_util::logical_geometry::LogicalRect;
use std::fmt;
use style::ComputedValues;
use std::sync::Arc;
@ -86,6 +87,10 @@ impl Flow for TableCaptionFlow {
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,
iterator: &mut FragmentBorderBoxIterator,
stacking_context_position: &Point2D<Au>) {

View file

@ -17,6 +17,7 @@ use wrapper::ThreadSafeLayoutNode;
use geom::{Point2D, Rect};
use servo_util::geometry::Au;
use servo_util::logical_geometry::LogicalRect;
use std::fmt;
use style::{UnsignedIntegerAttribute, ComputedValues};
use std::sync::Arc;
@ -167,6 +168,10 @@ impl Flow for TableCellFlow {
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,
iterator: &mut FragmentBorderBoxIterator,
stacking_context_position: &Point2D<Au>) {

View file

@ -20,6 +20,7 @@ use wrapper::ThreadSafeLayoutNode;
use geom::{Point2D, Rect};
use servo_util::geometry::Au;
use servo_util::logical_geometry::LogicalRect;
use std::cmp::max;
use std::fmt;
use style::ComputedValues;
@ -320,6 +321,10 @@ impl Flow for TableRowFlow {
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,
iterator: &mut FragmentBorderBoxIterator,
stacking_context_position: &Point2D<Au>) {

View file

@ -17,6 +17,7 @@ use wrapper::ThreadSafeLayoutNode;
use geom::{Point2D, Rect};
use servo_util::geometry::Au;
use servo_util::logical_geometry::LogicalRect;
use std::fmt;
use style::ComputedValues;
use std::sync::Arc;
@ -155,6 +156,10 @@ impl Flow for TableRowGroupFlow {
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,
iterator: &mut FragmentBorderBoxIterator,
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
== mix_blend_mode_a.html mix_blend_mode_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>