aboutsummaryrefslogtreecommitdiffstats
path: root/components/layout/list_item.rs
diff options
context:
space:
mode:
authorPatrick Walton <pcwalton@mimiga.net>2014-12-09 12:12:50 -0800
committerPatrick Walton <pcwalton@mimiga.net>2014-12-15 16:25:06 -0800
commit3029fbab922d7137f6701b4445c1a2cb1f7c7bfb (patch)
tree4ef59997769c3187498fdfa2b6b2d5a65b0c9311 /components/layout/list_item.rs
parent7805fe19edf5353711f49a8ef1c988dc9f932bb7 (diff)
downloadservo-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.rs135
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"),
+ }
+}
+