layout: Implement ordered lists, CSS counters, and quotes per CSS 2.1

§ 12.3-12.5.

Only simple alphabetic and numeric counter styles are supported. (This
is most of them though.)

Although this PR adds a sequential pass to layout, I verified that on
pages that contain a reasonable number of ordered lists (Reddit
`/r/rust`), the time spent in generated content resolution is dwarfed by
the time spent in the parallelizable parts of layout. So I don't expect
this to negatively affect our parallelism expect perhaps in pathological
cases.
This commit is contained in:
Patrick Walton 2015-03-05 12:37:37 -08:00
parent 2df4dd9e09
commit f9cdd05d58
39 changed files with 1704 additions and 537 deletions

View file

@ -8,12 +8,13 @@
#![deny(unsafe_blocks)]
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 fragment::{CoordinateSystem, Fragment, FragmentBorderBoxIterator, GeneratedContentInfo};
use generated_content;
use incremental::RESOLVE_GENERATED_CONTENT;
use wrapper::ThreadSafeLayoutNode;
use geom::{Point2D, Rect};
@ -36,19 +37,33 @@ pub struct ListItemFlow {
}
impl ListItemFlow {
pub fn from_node_marker_and_flotation(constructor: &mut FlowConstructor,
node: &ThreadSafeLayoutNode,
marker_fragment: Option<Fragment>,
flotation: Option<FloatKind>)
-> ListItemFlow {
ListItemFlow {
pub fn from_node_fragments_and_flotation(node: &ThreadSafeLayoutNode,
main_fragment: Fragment,
marker_fragment: Option<Fragment>,
flotation: Option<FloatKind>)
-> ListItemFlow {
let mut this = ListItemFlow {
block_flow: if let Some(flotation) = flotation {
BlockFlow::float_from_node(constructor, node, flotation)
BlockFlow::float_from_node_and_fragment(node, main_fragment, flotation)
} else {
BlockFlow::from_node(constructor, node)
BlockFlow::from_node_and_fragment(node, main_fragment)
},
marker: marker_fragment,
};
if let Some(ref marker) = this.marker {
match marker.style().get_list().list_style_type {
list_style_type::T::disc |
list_style_type::T::none |
list_style_type::T::circle |
list_style_type::T::square |
list_style_type::T::disclosure_open |
list_style_type::T::disclosure_closed => {}
_ => this.block_flow.base.restyle_damage.insert(RESOLVE_GENERATED_CONTENT),
}
}
this
}
}
@ -134,24 +149,59 @@ impl Flow for ListItemFlow {
fn iterate_through_fragment_border_boxes(&self,
iterator: &mut FragmentBorderBoxIterator,
stacking_context_position: &Point2D<Au>) {
self.block_flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position)
self.block_flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position);
if let Some(ref marker) = self.marker {
if iterator.should_process(marker) {
iterator.process(
marker,
&marker.stacking_relative_border_box(&self.block_flow
.base
.stacking_relative_position,
&self.block_flow
.base
.absolute_position_info
.relative_containing_block_size,
self.block_flow
.base
.absolute_position_info
.relative_containing_block_mode,
CoordinateSystem::Parent)
.translate(stacking_context_position));
}
}
}
fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) {
self.block_flow.mutate_fragments(mutator);
if let Some(ref mut marker) = self.marker {
(*mutator)(marker)
}
}
}
/// Returns the static text to be used for the given value of the `list-style-type` property.
///
/// TODO(pcwalton): Return either a string or a counter descriptor, once we support counters.
pub fn static_text_for_list_style_type(list_style_type: list_style_type::T)
-> Option<&'static str> {
// Just to keep things simple, use a nonbreaking space (Unicode 0xa0) to provide the marker
// separation.
match list_style_type {
list_style_type::T::none => None,
list_style_type::T::disc => Some("\u{a0}"),
list_style_type::T::circle => Some("\u{a0}"),
list_style_type::T::square => Some("\u{a0}"),
list_style_type::T::disclosure_open => Some("\u{a0}"),
list_style_type::T::disclosure_closed => Some("\u{a0}"),
/// The kind of content that `list-style-type` results in.
pub enum ListStyleTypeContent {
None,
StaticText(char),
GeneratedContent(Box<GeneratedContentInfo>),
}
impl ListStyleTypeContent {
/// Returns the content to be used for the given value of the `list-style-type` property.
pub fn from_list_style_type(list_style_type: list_style_type::T) -> ListStyleTypeContent {
// Just to keep things simple, use a nonbreaking space (Unicode 0xa0) to provide the marker
// separation.
match list_style_type {
list_style_type::T::none => ListStyleTypeContent::None,
list_style_type::T::disc | list_style_type::T::circle | list_style_type::T::square |
list_style_type::T::disclosure_open | list_style_type::T::disclosure_closed => {
let text = generated_content::static_representation(list_style_type);
ListStyleTypeContent::StaticText(text)
}
_ => ListStyleTypeContent::GeneratedContent(box GeneratedContentInfo::ListItem),
}
}
}