diff options
author | Patrick Walton <pcwalton@mimiga.net> | 2014-12-09 12:12:50 -0800 |
---|---|---|
committer | Patrick Walton <pcwalton@mimiga.net> | 2014-12-15 16:25:06 -0800 |
commit | 3029fbab922d7137f6701b4445c1a2cb1f7c7bfb (patch) | |
tree | 4ef59997769c3187498fdfa2b6b2d5a65b0c9311 /components/layout/list_item.rs | |
parent | 7805fe19edf5353711f49a8ef1c988dc9f932bb7 (diff) | |
download | servo-3029fbab922d7137f6701b4445c1a2cb1f7c7bfb.tar.gz servo-3029fbab922d7137f6701b4445c1a2cb1f7c7bfb.zip |
layout: Implement basic lists and the CSS1 list properties.
The exact rendering is ill-spec'd. Some things are ugly (especially the
width and height of list style images) but they are infrequently used
and I believe this implementation matches the spec. Numeric lists are
not supported yet, since they will require a separate layout pass.
The implementation is a subclass of `BlockFlow`, on advice from Robert
O'Callahan.
Diffstat (limited to 'components/layout/list_item.rs')
-rw-r--r-- | components/layout/list_item.rs | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/components/layout/list_item.rs b/components/layout/list_item.rs new file mode 100644 index 00000000000..fbf40c7747c --- /dev/null +++ b/components/layout/list_item.rs @@ -0,0 +1,135 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +//! Layout for elements with a CSS `display` property of `list-item`. These elements consist of a +//! block and an extra inline fragment for the marker. + +#![deny(unsafe_blocks)] + +use block::BlockFlow; +use construct::FlowConstructor; +use context::LayoutContext; +use display_list_builder::ListItemFlowDisplayListBuilding; +use flow::{Flow, FlowClass, ListItemFlowClass}; +use fragment::{Fragment, FragmentBoundsIterator}; +use wrapper::ThreadSafeLayoutNode; + +use gfx::display_list::DisplayList; +use servo_util::geometry::Au; +use servo_util::opts; +use style::ComputedValues; +use style::computed_values::list_style_type; +use sync::Arc; + +/// A block with the CSS `display` property equal to `list-item`. +#[deriving(Show)] +pub struct ListItemFlow { + /// Data common to all block flows. + pub block_flow: BlockFlow, + /// The marker, if outside. (Markers that are inside are instead just fragments on the interior + /// `InlineFlow`.) + pub marker: Option<Fragment>, +} + +impl ListItemFlow { + pub fn from_node_and_marker(constructor: &mut FlowConstructor, + node: &ThreadSafeLayoutNode, + marker_fragment: Option<Fragment>) + -> ListItemFlow { + ListItemFlow { + block_flow: BlockFlow::from_node(constructor, node), + marker: marker_fragment, + } + } +} + +impl Flow for ListItemFlow { + fn class(&self) -> FlowClass { + ListItemFlowClass + } + + fn as_block<'a>(&'a mut self) -> &'a mut BlockFlow { + &mut self.block_flow + } + + fn bubble_inline_sizes(&mut self) { + // The marker contributes no intrinsic inline-size, so… + self.block_flow.bubble_inline_sizes() + } + + fn assign_inline_sizes(&mut self, layout_context: &LayoutContext) { + self.block_flow.assign_inline_sizes(layout_context); + + match self.marker { + None => {} + Some(ref mut marker) => { + // Do this now. There's no need to do this in bubble-widths, since markers do not + // contribute to the inline size of this flow. + let intrinsic_inline_sizes = marker.compute_intrinsic_inline_sizes(); + + marker.border_box.size.inline = + intrinsic_inline_sizes.content_intrinsic_sizes.preferred_inline_size; + marker.border_box.start.i = self.block_flow.fragment.border_box.start.i - + marker.border_box.size.inline; + } + } + } + + fn assign_block_size<'a>(&mut self, layout_context: &'a LayoutContext<'a>) { + self.block_flow.assign_block_size(layout_context); + + match self.marker { + None => {} + Some(ref mut marker) => { + marker.border_box.start.b = Au(0); + marker.border_box.size.block = marker.calculate_line_height(layout_context); + } + } + } + + fn compute_absolute_position(&mut self) { + self.block_flow.compute_absolute_position() + } + + 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) + } + + fn update_late_computed_block_position_if_necessary(&mut self, block_position: Au) { + self.block_flow.update_late_computed_block_position_if_necessary(block_position) + } + + fn build_display_list(&mut self, layout_context: &LayoutContext) { + self.build_display_list_for_list_item(box DisplayList::new(), layout_context); + if opts::get().validate_display_list_geometry { + self.block_flow.base.validate_display_list_geometry(); + } + } + + fn repair_style(&mut self, new_style: &Arc<ComputedValues>) { + self.block_flow.repair_style(new_style) + } + + fn iterate_through_fragment_bounds(&self, iterator: &mut FragmentBoundsIterator) { + self.block_flow.iterate_through_fragment_bounds(iterator); + } +} + +/// 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::none => None, + list_style_type::disc => Some("•\u00a0"), + list_style_type::circle => Some("◦\u00a0"), + list_style_type::square => Some("▪\u00a0"), + list_style_type::disclosure_open => Some("▾\u00a0"), + list_style_type::disclosure_closed => Some("‣\u00a0"), + } +} + |