aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbors-servo <metajack+bors@gmail.com>2015-04-28 19:48:45 -0500
committerbors-servo <metajack+bors@gmail.com>2015-04-28 19:48:45 -0500
commit1e150140bd12624ad357e3168fb496079fb8ec7c (patch)
tree238b47e1dc4329095025773e9ff14d2d0f51d83f
parent0a4db7ae0f581a959863bd5159766795c6caf8d8 (diff)
parent544a02a25068a92dfd9e950eb3609713ad9599c7 (diff)
downloadservo-1e150140bd12624ad357e3168fb496079fb8ec7c.tar.gz
servo-1e150140bd12624ad357e3168fb496079fb8ec7c.zip
Auto merge of #5480 - SimonSapin:multicol, r=pcwalton
This add some properties to the style system and a new flow type, but the larger issues of dealing with fragmentation in the flow tree is still an open question. <!-- Reviewable:start --> [<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/5480) <!-- Reviewable:end -->
-rw-r--r--components/layout/block.rs34
-rw-r--r--components/layout/construct.rs65
-rw-r--r--components/layout/floats.rs8
-rw-r--r--components/layout/flow.rs7
-rw-r--r--components/layout/lib.rs1
-rw-r--r--components/layout/list_item.rs6
-rw-r--r--components/layout/multicol.rs110
-rw-r--r--components/layout/table.rs24
-rw-r--r--components/layout/table_caption.rs2
-rw-r--r--components/layout/table_cell.rs2
-rw-r--r--components/layout/table_row.rs2
-rw-r--r--components/layout/table_rowgroup.rs2
-rw-r--r--components/layout/table_wrapper.rs25
-rw-r--r--components/script/dom/webidls/CSSStyleDeclaration.webidl5
-rw-r--r--components/style/properties.mako.rs220
15 files changed, 388 insertions, 125 deletions
diff --git a/components/layout/block.rs b/components/layout/block.rs
index 4c50adb3e6a..c21d3123bc7 100644
--- a/components/layout/block.rs
+++ b/components/layout/block.rs
@@ -562,33 +562,20 @@ impl Encodable for BlockFlowFlags {
}
impl BlockFlow {
- pub fn from_node_and_fragment(node: &ThreadSafeLayoutNode, fragment: Fragment) -> BlockFlow {
+ pub fn from_node_and_fragment(node: &ThreadSafeLayoutNode,
+ fragment: Fragment,
+ float_kind: Option<FloatKind>)
+ -> BlockFlow {
let writing_mode = node.style().writing_mode;
BlockFlow {
- base: BaseFlow::new(Some((*node).clone()),
- writing_mode,
- ForceNonfloatedFlag::ForceNonfloated),
+ base: BaseFlow::new(Some((*node).clone()), writing_mode, match float_kind {
+ Some(_) => ForceNonfloatedFlag::FloatIfNecessary,
+ None => ForceNonfloatedFlag::ForceNonfloated,
+ }),
fragment: fragment,
inline_size_of_preceding_left_floats: Au(0),
inline_size_of_preceding_right_floats: Au(0),
- float: None,
- flags: BlockFlowFlags::empty(),
- }
- }
-
- pub fn float_from_node_and_fragment(node: &ThreadSafeLayoutNode,
- fragment: Fragment,
- float_kind: FloatKind)
- -> BlockFlow {
- let writing_mode = node.style().writing_mode;
- BlockFlow {
- base: BaseFlow::new(Some((*node).clone()),
- writing_mode,
- ForceNonfloatedFlag::FloatIfNecessary),
- fragment: fragment,
- inline_size_of_preceding_left_floats: Au(0),
- inline_size_of_preceding_right_floats: Au(0),
- float: Some(box FloatedBlockInfo::new(float_kind)),
+ float: float_kind.map(|kind| box FloatedBlockInfo::new(kind)),
flags: BlockFlowFlags::empty(),
}
}
@@ -1379,7 +1366,8 @@ impl BlockFlow {
FormattingContextType::Other
}
_ if style.get_box().overflow_x != overflow_x::T::visible ||
- style.get_box().overflow_y != overflow_y::T(overflow_x::T::visible) => {
+ style.get_box().overflow_y != overflow_y::T(overflow_x::T::visible) ||
+ style.is_multicol() => {
FormattingContextType::Block
}
_ => FormattingContextType::None,
diff --git a/components/layout/construct.rs b/components/layout/construct.rs
index f945e8bb526..6c4537e8b26 100644
--- a/components/layout/construct.rs
+++ b/components/layout/construct.rs
@@ -33,6 +33,7 @@ use fragment::{InlineBlockFragmentInfo, SpecificFragmentInfo};
use incremental::{RECONSTRUCT_FLOW, RestyleDamage};
use inline::InlineFlow;
use list_item::{ListItemFlow, ListStyleTypeContent};
+use multicol::MulticolFlow;
use opaque_node::OpaqueNodeMethods;
use parallel;
use table::TableFlow;
@@ -330,7 +331,7 @@ impl<'a> FlowConstructor<'a> {
if child.is_table() {
let fragment = Fragment::new(child_node, SpecificFragmentInfo::TableWrapper);
let mut new_child =
- FlowRef::new(box TableWrapperFlow::from_node_and_fragment(child_node, fragment));
+ FlowRef::new(box TableWrapperFlow::from_node_and_fragment(child_node, fragment, None));
new_child.add_new_child(child.clone());
child.finish();
*child = new_child
@@ -601,7 +602,7 @@ impl<'a> FlowConstructor<'a> {
///
/// FIXME(pcwalton): It is not clear to me that there isn't a cleaner way to handle
/// `<textarea>`.
- fn build_flow_for_block(&mut self, flow: FlowRef, node: &ThreadSafeLayoutNode)
+ fn build_flow_for_block_like(&mut self, flow: FlowRef, node: &ThreadSafeLayoutNode)
-> ConstructionResult {
let mut initial_fragments = LinkedList::new();
if node.get_pseudo_element_type() != PseudoElementType::Normal ||
@@ -653,21 +654,15 @@ impl<'a> FlowConstructor<'a> {
/// Builds a flow for a node with `display: block`. This yields a `BlockFlow` with possibly
/// other `BlockFlow`s or `InlineFlow`s underneath it, depending on whether {ib} splits needed
/// to happen.
- fn build_flow_for_nonfloated_block(&mut self, node: &ThreadSafeLayoutNode)
- -> ConstructionResult {
- let flow = box BlockFlow::from_node_and_fragment(node, self.build_fragment_for_block(node))
- as Box<Flow>;
- self.build_flow_for_block(FlowRef::new(flow), node)
- }
-
- /// Builds the flow for a node with `float: {left|right}`. This yields a float `BlockFlow` with
- /// a `BlockFlow` underneath it.
- fn build_flow_for_floated_block(&mut self, node: &ThreadSafeLayoutNode, float_kind: FloatKind)
- -> ConstructionResult {
+ fn build_flow_for_block(&mut self, node: &ThreadSafeLayoutNode, float_kind: Option<FloatKind>)
+ -> ConstructionResult {
let fragment = self.build_fragment_for_block(node);
- let flow = box BlockFlow::float_from_node_and_fragment(node, fragment, float_kind) as
- Box<Flow>;
- self.build_flow_for_block(FlowRef::new(flow), node)
+ let flow = if node.style().is_multicol() {
+ box MulticolFlow::from_node_and_fragment(node, fragment, float_kind) as Box<Flow>
+ } else {
+ box BlockFlow::from_node_and_fragment(node, fragment, float_kind) as Box<Flow>
+ };
+ self.build_flow_for_block_like(FlowRef::new(flow), node)
}
/// Concatenates the fragments of kids, adding in our own borders/padding/margins if necessary.
@@ -814,7 +809,7 @@ impl<'a> FlowConstructor<'a> {
fn build_fragment_for_inline_block(&mut self, node: &ThreadSafeLayoutNode)
-> ConstructionResult {
- let block_flow_result = self.build_flow_for_nonfloated_block(node);
+ let block_flow_result = self.build_flow_for_block(node, None);
let (block_flow, abs_descendants) = match block_flow_result {
ConstructionResult::Flow(block_flow, abs_descendants) => (block_flow, abs_descendants),
_ => unreachable!()
@@ -840,7 +835,7 @@ impl<'a> FlowConstructor<'a> {
/// hypothetical box is inline.
fn build_fragment_for_absolutely_positioned_inline(&mut self, node: &ThreadSafeLayoutNode)
-> ConstructionResult {
- let block_flow_result = self.build_flow_for_nonfloated_block(node);
+ let block_flow_result = self.build_flow_for_block(node, None);
let (block_flow, abs_descendants) = match block_flow_result {
ConstructionResult::Flow(block_flow, abs_descendants) => (block_flow, abs_descendants),
_ => unreachable!()
@@ -934,13 +929,8 @@ impl<'a> FlowConstructor<'a> {
fn build_flow_for_table_wrapper(&mut self, node: &ThreadSafeLayoutNode, float_value: float::T)
-> ConstructionResult {
let fragment = Fragment::new(node, SpecificFragmentInfo::TableWrapper);
- let wrapper_flow = match float_value {
- float::T::none => box TableWrapperFlow::from_node_and_fragment(node, fragment),
- _ => {
- let float_kind = FloatKind::from_property(float_value);
- box TableWrapperFlow::float_from_node_and_fragment(node, fragment, float_kind)
- }
- };
+ let wrapper_flow = box TableWrapperFlow::from_node_and_fragment(
+ node, fragment, FloatKind::from_property(float_value));
let mut wrapper_flow = FlowRef::new(wrapper_flow as Box<Flow>);
let table_fragment = Fragment::new(node, SpecificFragmentInfo::Table);
@@ -948,7 +938,7 @@ impl<'a> FlowConstructor<'a> {
let table_flow = FlowRef::new(table_flow as Box<Flow>);
// First populate the table flow with its children.
- let construction_result = self.build_flow_for_block(table_flow, node);
+ let construction_result = self.build_flow_for_block_like(table_flow, node);
let mut abs_descendants = Descendants::new();
let mut fixed_descendants = Descendants::new();
@@ -1003,7 +993,7 @@ impl<'a> FlowConstructor<'a> {
fn build_flow_for_table_caption(&mut self, node: &ThreadSafeLayoutNode) -> ConstructionResult {
let fragment = self.build_fragment_for_block(node);
let flow = box TableCaptionFlow::from_node_and_fragment(node, fragment) as Box<Flow>;
- self.build_flow_for_block(FlowRef::new(flow), node)
+ self.build_flow_for_block_like(FlowRef::new(flow), node)
}
/// Builds a flow for a node with `display: table-row-group`. This yields a `TableRowGroupFlow`
@@ -1013,7 +1003,7 @@ impl<'a> FlowConstructor<'a> {
let fragment = Fragment::new(node, SpecificFragmentInfo::TableRow);
let flow = box TableRowGroupFlow::from_node_and_fragment(node, fragment);
let flow = flow as Box<Flow>;
- self.build_flow_for_block(FlowRef::new(flow), node)
+ self.build_flow_for_block_like(FlowRef::new(flow), node)
}
/// Builds a flow for a node with `display: table-row`. This yields a `TableRowFlow` with
@@ -1021,7 +1011,7 @@ impl<'a> FlowConstructor<'a> {
fn build_flow_for_table_row(&mut self, node: &ThreadSafeLayoutNode) -> ConstructionResult {
let fragment = Fragment::new(node, SpecificFragmentInfo::TableRow);
let flow = box TableRowFlow::from_node_and_fragment(node, fragment) as Box<Flow>;
- self.build_flow_for_block(FlowRef::new(flow), node)
+ self.build_flow_for_block_like(FlowRef::new(flow), node)
}
/// Builds a flow for a node with `display: table-cell`. This yields a `TableCellFlow` with
@@ -1042,17 +1032,14 @@ impl<'a> FlowConstructor<'a> {
let flow = box TableCellFlow::from_node_fragment_and_visibility_flag(node, fragment, !hide)
as Box<Flow>;
- self.build_flow_for_block(FlowRef::new(flow), node)
+ self.build_flow_for_block_like(FlowRef::new(flow), node)
}
/// 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, flotation: float::T)
-> ConstructionResult {
- let flotation = match flotation {
- float::T::none => None,
- flotation => Some(FloatKind::from_property(flotation)),
- };
+ let flotation = FloatKind::from_property(flotation);
let marker_fragment = match node.style().get_list().list_style_image {
Some(ref url) => {
let image_info = box ImageFragmentInfo::new(node,
@@ -1289,7 +1276,7 @@ impl<'a> PostorderNodeMutTraversal for FlowConstructor<'a> {
// below.
(display::T::block, _, position::T::absolute) |
(_, _, position::T::fixed) => {
- let construction_result = self.build_flow_for_nonfloated_block(node);
+ let construction_result = self.build_flow_for_block(node, None);
self.set_flow_construction_result(node, construction_result)
}
@@ -1364,15 +1351,9 @@ impl<'a> PostorderNodeMutTraversal for FlowConstructor<'a> {
// TODO(pcwalton): Make this only trigger for blocks and handle the other `display`
// properties separately.
- (_, float::T::none, _) => {
- let construction_result = self.build_flow_for_nonfloated_block(node);
- self.set_flow_construction_result(node, construction_result)
- }
-
- // Floated flows contribute float flow construction results.
(_, float_value, _) => {
let float_kind = FloatKind::from_property(float_value);
- let construction_result = self.build_flow_for_floated_block(node, float_kind);
+ let construction_result = self.build_flow_for_block(node, float_kind);
self.set_flow_construction_result(node, construction_result)
}
}
diff --git a/components/layout/floats.rs b/components/layout/floats.rs
index 5f61760829b..a3f06e80667 100644
--- a/components/layout/floats.rs
+++ b/components/layout/floats.rs
@@ -19,11 +19,11 @@ pub enum FloatKind {
}
impl FloatKind {
- pub fn from_property(property: float::T) -> FloatKind {
+ pub fn from_property(property: float::T) -> Option<FloatKind> {
match property {
- float::T::none => panic!("can't create a float type from an unfloated property"),
- float::T::left => FloatKind::Left,
- float::T::right => FloatKind::Right,
+ float::T::none => None,
+ float::T::left => Some(FloatKind::Left),
+ float::T::right => Some(FloatKind::Right),
}
}
}
diff --git a/components/layout/flow.rs b/components/layout/flow.rs
index 5434676ad03..a745ca8010b 100644
--- a/components/layout/flow.rs
+++ b/components/layout/flow.rs
@@ -44,6 +44,7 @@ use table_colgroup::TableColGroupFlow;
use table_row::TableRowFlow;
use table_rowgroup::TableRowGroupFlow;
use table_wrapper::TableWrapperFlow;
+use multicol::MulticolFlow;
use wrapper::ThreadSafeLayoutNode;
use geom::{Point2D, Rect, Size2D};
@@ -158,6 +159,11 @@ pub trait Flow: fmt::Debug + Sync {
panic!("called as_table_cell() on a non-tablecell flow")
}
+ /// If this is a multicol flow, returns the underlying object. Fails otherwise.
+ fn as_multicol<'a>(&'a mut self) -> &'a mut MulticolFlow {
+ panic!("called as_multicol() on a non-multicol flow")
+ }
+
/// If this is a table cell flow, returns the underlying object, borrowed immutably. Fails
/// otherwise.
fn as_immutable_table_cell<'a>(&'a self) -> &'a TableCellFlow {
@@ -451,6 +457,7 @@ pub enum FlowClass {
TableRow,
TableCaption,
TableCell,
+ Multicol,
}
/// A top-down traversal.
diff --git a/components/layout/lib.rs b/components/layout/lib.rs
index 7fbbb2d3576..844689f0534 100644
--- a/components/layout/lib.rs
+++ b/components/layout/lib.rs
@@ -78,6 +78,7 @@ pub mod incremental;
pub mod inline;
pub mod list_item;
pub mod model;
+pub mod multicol;
pub mod opaque_node;
pub mod parallel;
pub mod sequential;
diff --git a/components/layout/list_item.rs b/components/layout/list_item.rs
index cec7b02f0a5..8bf3fee6880 100644
--- a/components/layout/list_item.rs
+++ b/components/layout/list_item.rs
@@ -45,11 +45,7 @@ impl ListItemFlow {
flotation: Option<FloatKind>)
-> ListItemFlow {
let mut this = ListItemFlow {
- block_flow: if let Some(flotation) = flotation {
- BlockFlow::float_from_node_and_fragment(node, main_fragment, flotation)
- } else {
- BlockFlow::from_node_and_fragment(node, main_fragment)
- },
+ block_flow: BlockFlow::from_node_and_fragment(node, main_fragment, flotation),
marker: marker_fragment,
};
diff --git a/components/layout/multicol.rs b/components/layout/multicol.rs
new file mode 100644
index 00000000000..e46ea8abf71
--- /dev/null
+++ b/components/layout/multicol.rs
@@ -0,0 +1,110 @@
+/* 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/. */
+
+//! CSS Multi-column layout http://dev.w3.org/csswg/css-multicol/
+
+#![deny(unsafe_code)]
+
+use block::BlockFlow;
+use context::LayoutContext;
+use floats::FloatKind;
+use flow::{FlowClass, Flow};
+use fragment::{Fragment, FragmentBorderBoxIterator};
+use wrapper::ThreadSafeLayoutNode;
+
+use geom::{Point2D, Rect};
+use util::geometry::Au;
+use util::logical_geometry::LogicalRect;
+use std::fmt;
+use style::properties::ComputedValues;
+use std::sync::Arc;
+
+pub struct MulticolFlow {
+ pub block_flow: BlockFlow,
+}
+
+impl MulticolFlow {
+ pub fn from_node_and_fragment(node: &ThreadSafeLayoutNode,
+ fragment: Fragment,
+ float_kind: Option<FloatKind>)
+ -> MulticolFlow {
+ MulticolFlow {
+ block_flow: BlockFlow::from_node_and_fragment(node, fragment, float_kind)
+ }
+ }
+}
+
+impl Flow for MulticolFlow {
+ fn class(&self) -> FlowClass {
+ FlowClass::Multicol
+ }
+
+ fn as_multicol<'a>(&'a mut self) -> &'a mut MulticolFlow {
+ self
+ }
+
+ fn as_block<'a>(&'a mut self) -> &'a mut BlockFlow {
+ &mut self.block_flow
+ }
+
+ fn bubble_inline_sizes(&mut self) {
+ // FIXME(SimonSapin) http://dev.w3.org/csswg/css-sizing/#multicol-intrinsic
+ self.block_flow.bubble_inline_sizes();
+ }
+
+ fn assign_inline_sizes(&mut self, ctx: &LayoutContext) {
+ debug!("assign_inline_sizes({}): assigning inline_size for flow", "multicol");
+ self.block_flow.assign_inline_sizes(ctx);
+ }
+
+ fn assign_block_size<'a>(&mut self, ctx: &'a LayoutContext<'a>) {
+ debug!("assign_block_size: assigning block_size for multicol");
+ self.block_flow.assign_block_size(ctx);
+ }
+
+ 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) {
+ debug!("build_display_list_multicol: same process as block flow");
+ self.block_flow.build_display_list(layout_context)
+ }
+
+ fn repair_style(&mut self, new_style: &Arc<ComputedValues>) {
+ self.block_flow.repair_style(new_style)
+ }
+
+ fn compute_overflow(&self) -> Rect<Au> {
+ 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>) {
+ self.block_flow.iterate_through_fragment_border_boxes(iterator, stacking_context_position)
+ }
+
+ fn mutate_fragments(&mut self, mutator: &mut FnMut(&mut Fragment)) {
+ self.block_flow.mutate_fragments(mutator)
+ }
+}
+
+impl fmt::Debug for MulticolFlow {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "MulticolFlow: {:?}", self.block_flow)
+ }
+}
diff --git a/components/layout/table.rs b/components/layout/table.rs
index eeb11d4a29a..d6ad3746054 100644
--- a/components/layout/table.rs
+++ b/components/layout/table.rs
@@ -10,7 +10,6 @@ use block::{self, BlockFlow, CandidateBSizeIterator, ISizeAndMarginsComputer};
use block::{ISizeConstraintInput, ISizeConstraintSolution};
use context::LayoutContext;
use display_list_builder::{BlockFlowDisplayListBuilding, BorderPaintingMode};
-use floats::FloatKind;
use flow::{self, Flow, FlowClass, IMPACTED_BY_LEFT_FLOATS, IMPACTED_BY_RIGHT_FLOATS};
use flow::{ImmutableFlowUtils};
use fragment::{Fragment, FragmentBorderBoxIterator};
@@ -66,28 +65,7 @@ impl TableFlow {
pub fn from_node_and_fragment(node: &ThreadSafeLayoutNode,
fragment: Fragment)
-> TableFlow {
- let mut block_flow = BlockFlow::from_node_and_fragment(node, fragment);
- let table_layout =
- if block_flow.fragment().style().get_table().table_layout == table_layout::T::fixed {
- TableLayout::Fixed
- } else {
- TableLayout::Auto
- };
- TableFlow {
- block_flow: block_flow,
- column_intrinsic_inline_sizes: Vec::new(),
- column_computed_inline_sizes: Vec::new(),
- collapsed_inline_direction_border_widths_for_table: Vec::new(),
- collapsed_block_direction_border_widths_for_table: Vec::new(),
- table_layout: table_layout
- }
- }
-
- pub fn float_from_node_and_fragment(node: &ThreadSafeLayoutNode,
- fragment: Fragment,
- float_kind: FloatKind)
- -> TableFlow {
- let mut block_flow = BlockFlow::float_from_node_and_fragment(node, fragment, float_kind);
+ let mut block_flow = BlockFlow::from_node_and_fragment(node, fragment, None);
let table_layout =
if block_flow.fragment().style().get_table().table_layout == table_layout::T::fixed {
TableLayout::Fixed
diff --git a/components/layout/table_caption.rs b/components/layout/table_caption.rs
index 26e63c9d1b4..a476889ce0a 100644
--- a/components/layout/table_caption.rs
+++ b/components/layout/table_caption.rs
@@ -28,7 +28,7 @@ impl TableCaptionFlow {
pub fn from_node_and_fragment(node: &ThreadSafeLayoutNode, fragment: Fragment)
-> TableCaptionFlow {
TableCaptionFlow {
- block_flow: BlockFlow::from_node_and_fragment(node, fragment)
+ block_flow: BlockFlow::from_node_and_fragment(node, fragment, None)
}
}
}
diff --git a/components/layout/table_cell.rs b/components/layout/table_cell.rs
index 6744fbc2106..8de69f0608d 100644
--- a/components/layout/table_cell.rs
+++ b/components/layout/table_cell.rs
@@ -52,7 +52,7 @@ impl TableCellFlow {
visible: bool)
-> TableCellFlow {
TableCellFlow {
- block_flow: BlockFlow::from_node_and_fragment(node, fragment),
+ block_flow: BlockFlow::from_node_and_fragment(node, fragment, None),
collapsed_borders: CollapsedBordersForCell::new(),
column_span: node.get_unsigned_integer_attribute(UnsignedIntegerAttribute::ColSpan)
.unwrap_or(1),
diff --git a/components/layout/table_row.rs b/components/layout/table_row.rs
index 3beeb1f7fe2..a453003e19e 100644
--- a/components/layout/table_row.rs
+++ b/components/layout/table_row.rs
@@ -79,7 +79,7 @@ impl TableRowFlow {
pub fn from_node_and_fragment(node: &ThreadSafeLayoutNode, fragment: Fragment)
-> TableRowFlow {
TableRowFlow {
- block_flow: BlockFlow::from_node_and_fragment(node, fragment),
+ block_flow: BlockFlow::from_node_and_fragment(node, fragment, None),
cell_intrinsic_inline_sizes: Vec::new(),
column_computed_inline_sizes: Vec::new(),
spacing: border_spacing::T {
diff --git a/components/layout/table_rowgroup.rs b/components/layout/table_rowgroup.rs
index e442f2b4c7b..8990b127da4 100644
--- a/components/layout/table_rowgroup.rs
+++ b/components/layout/table_rowgroup.rs
@@ -62,7 +62,7 @@ impl TableRowGroupFlow {
pub fn from_node_and_fragment(node: &ThreadSafeLayoutNode, fragment: Fragment)
-> TableRowGroupFlow {
TableRowGroupFlow {
- block_flow: BlockFlow::from_node_and_fragment(node, fragment),
+ block_flow: BlockFlow::from_node_and_fragment(node, fragment, None),
column_intrinsic_inline_sizes: Vec::new(),
column_computed_inline_sizes: Vec::new(),
spacing: border_spacing::T {
diff --git a/components/layout/table_wrapper.rs b/components/layout/table_wrapper.rs
index 5db3674341c..7369acbbf4c 100644
--- a/components/layout/table_wrapper.rs
+++ b/components/layout/table_wrapper.rs
@@ -56,9 +56,11 @@ pub struct TableWrapperFlow {
}
impl TableWrapperFlow {
- pub fn from_node_and_fragment(node: &ThreadSafeLayoutNode, fragment: Fragment)
+ pub fn from_node_and_fragment(node: &ThreadSafeLayoutNode,
+ fragment: Fragment,
+ float_kind: Option<FloatKind>)
-> TableWrapperFlow {
- let mut block_flow = BlockFlow::from_node_and_fragment(node, fragment);
+ let mut block_flow = BlockFlow::from_node_and_fragment(node, fragment, float_kind);
let table_layout = if block_flow.fragment().style().get_table().table_layout ==
table_layout::T::fixed {
TableLayout::Fixed
@@ -71,25 +73,6 @@ impl TableWrapperFlow {
table_layout: table_layout
}
}
-
- pub fn float_from_node_and_fragment(node: &ThreadSafeLayoutNode,
- fragment: Fragment,
- float_kind: FloatKind)
- -> TableWrapperFlow {
- let mut block_flow = BlockFlow::float_from_node_and_fragment(node, fragment, float_kind);
- let table_layout = if block_flow.fragment().style().get_table().table_layout ==
- table_layout::T::fixed {
- TableLayout::Fixed
- } else {
- TableLayout::Auto
- };
- TableWrapperFlow {
- block_flow: block_flow,
- column_intrinsic_inline_sizes: vec!(),
- table_layout: table_layout
- }
- }
-
fn border_padding_and_spacing(&mut self) -> (Au, Au) {
let (mut table_border_padding, mut spacing) = (Au(0), Au(0));
for kid in self.block_flow.base.child_iter() {
diff --git a/components/script/dom/webidls/CSSStyleDeclaration.webidl b/components/script/dom/webidls/CSSStyleDeclaration.webidl
index e937f4c41b2..8ed0805f432 100644
--- a/components/script/dom/webidls/CSSStyleDeclaration.webidl
+++ b/components/script/dom/webidls/CSSStyleDeclaration.webidl
@@ -187,6 +187,11 @@ partial interface CSSStyleDeclaration {
[TreatNullAs=EmptyString] attribute DOMString imageRendering;
+ [TreatNullAs=EmptyString] attribute DOMString columnCount;
+ [TreatNullAs=EmptyString] attribute DOMString columnWidth;
+ [TreatNullAs=EmptyString] attribute DOMString columns;
+ [TreatNullAs=EmptyString] attribute DOMString columnGap;
+
[TreatNullAs=EmptyString] attribute DOMString transition;
[TreatNullAs=EmptyString] attribute DOMString transitionDuration;
[TreatNullAs=EmptyString] attribute DOMString transitionTimingFunction;
diff --git a/components/style/properties.mako.rs b/components/style/properties.mako.rs
index 97720a5dcd6..8012bfc9683 100644
--- a/components/style/properties.mako.rs
+++ b/components/style/properties.mako.rs
@@ -60,11 +60,12 @@ class Longhand(object):
self.derived_from = [ to_rust_ident(name) for name in derived_from ]
class Shorthand(object):
- def __init__(self, name, sub_properties):
+ def __init__(self, name, sub_properties, experimental=False):
self.name = name
self.ident = to_rust_ident(name)
self.camel_case = to_camel_case(self.ident)
self.derived_from = None
+ self.experimental = experimental
self.sub_properties = [LONGHANDS_BY_NAME[s] for s in sub_properties]
class StyleStruct(object):
@@ -2177,6 +2178,167 @@ pub mod longhands {
// TODO(pcwalton): SVG-only values.
${single_keyword("pointer-events", "auto none")}
+
+ ${new_style_struct("Column", is_inherited=False)}
+
+ <%self:longhand name="column-width" experimental="True">
+ use values::computed::{ToComputedValue, Context};
+ use cssparser::ToCss;
+ use text_writer::{self, TextWriter};
+
+ #[derive(Clone, Copy, PartialEq)]
+ pub enum SpecifiedValue {
+ Auto,
+ Specified(specified::Length),
+ }
+
+ impl ToCss for SpecifiedValue {
+ fn to_css<W>(&self, dest: &mut W) -> text_writer::Result where W: TextWriter {
+ match *self {
+ SpecifiedValue::Auto => dest.write_str("auto"),
+ SpecifiedValue::Specified(l) => l.to_css(dest),
+ }
+ }
+ }
+
+ pub mod computed_value {
+ use util::geometry::Au;
+ pub type T = Option<Au>;
+ }
+
+ #[inline]
+ pub fn get_initial_value() -> computed_value::T {
+ None
+ }
+
+ impl ToComputedValue for SpecifiedValue {
+ type ComputedValue = computed_value::T;
+
+ #[inline]
+ fn to_computed_value(&self, context: &Context) -> computed_value::T {
+ match *self {
+ SpecifiedValue::Auto => None,
+ SpecifiedValue::Specified(l) => Some(l.to_computed_value(context))
+ }
+ }
+ }
+
+ pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
+ if input.try(|input| input.expect_ident_matching("auto")).is_ok() {
+ Ok(SpecifiedValue::Auto)
+ } else {
+ specified::Length::parse_non_negative(input).map(SpecifiedValue::Specified)
+ }
+ }
+ </%self:longhand>
+
+ <%self:longhand name="column-count" experimental="True">
+ use values::computed::{ToComputedValue, Context};
+ use cssparser::ToCss;
+ use text_writer::{self, TextWriter};
+
+ #[derive(Clone, Copy, PartialEq)]
+ pub enum SpecifiedValue {
+ Auto,
+ Specified(u32),
+ }
+
+ impl ToCss for SpecifiedValue {
+ fn to_css<W>(&self, dest: &mut W) -> text_writer::Result where W: TextWriter {
+ match *self {
+ SpecifiedValue::Auto => dest.write_str("auto"),
+ SpecifiedValue::Specified(count) => write!(dest, "{}", count),
+ }
+ }
+ }
+
+ pub mod computed_value {
+ pub type T = Option<u32>;
+ }
+
+ #[inline]
+ pub fn get_initial_value() -> computed_value::T {
+ None
+ }
+
+ impl ToComputedValue for SpecifiedValue {
+ type ComputedValue = computed_value::T;
+
+ #[inline]
+ fn to_computed_value(&self, _context: &Context) -> computed_value::T {
+ match *self {
+ SpecifiedValue::Auto => None,
+ SpecifiedValue::Specified(count) => Some(count)
+ }
+ }
+ }
+
+ pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
+ if input.try(|input| input.expect_ident_matching("auto")).is_ok() {
+ Ok(SpecifiedValue::Auto)
+ } else {
+ use std::u32;
+ let count = try!(input.expect_integer());
+ // Zero is invalid
+ if count <= 0 || count > (u32::MAX as i64) {
+ return Err(())
+ }
+ Ok(SpecifiedValue::Specified(count as u32))
+ }
+ }
+ </%self:longhand>
+
+ <%self:longhand name="column-gap" experimental="True">
+ use values::computed::{ToComputedValue, Context};
+ use cssparser::ToCss;
+ use text_writer::{self, TextWriter};
+
+ #[derive(Clone, Copy, PartialEq)]
+ pub enum SpecifiedValue {
+ Normal,
+ Specified(specified::Length),
+ }
+
+ impl ToCss for SpecifiedValue {
+ fn to_css<W>(&self, dest: &mut W) -> text_writer::Result where W: TextWriter {
+ match *self {
+ SpecifiedValue::Normal => dest.write_str("normal"),
+ SpecifiedValue::Specified(l) => l.to_css(dest),
+ }
+ }
+ }
+
+ pub mod computed_value {
+ use util::geometry::Au;
+ pub type T = Option<Au>;
+ }
+
+ #[inline]
+ pub fn get_initial_value() -> computed_value::T {
+ None
+ }
+
+ impl ToComputedValue for SpecifiedValue {
+ type ComputedValue = computed_value::T;
+
+ #[inline]
+ fn to_computed_value(&self, context: &Context) -> computed_value::T {
+ match *self {
+ SpecifiedValue::Normal => None,
+ SpecifiedValue::Specified(l) => Some(l.to_computed_value(context))
+ }
+ }
+ }
+
+ pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
+ if input.try(|input| input.expect_ident_matching("normal")).is_ok() {
+ Ok(SpecifiedValue::Normal)
+ } else {
+ specified::Length::parse_non_negative(input).map(SpecifiedValue::Specified)
+ }
+ }
+ </%self:longhand>
+
// Box-shadow, etc.
${new_style_struct("Effects", is_inherited=False)}
@@ -3952,9 +4114,9 @@ pub mod shorthands {
use parser::ParserContext;
use values::specified;
- <%def name="shorthand(name, sub_properties)">
+ <%def name="shorthand(name, sub_properties, experimental=False)">
<%
- shorthand = Shorthand(name, sub_properties.split())
+ shorthand = Shorthand(name, sub_properties.split(), experimental=experimental)
SHORTHANDS.append(shorthand)
%>
pub mod ${shorthand.ident} {
@@ -4439,6 +4601,47 @@ pub mod shorthands {
}
</%self:shorthand>
+ <%self:shorthand name="columns" sub_properties="column-count column-width" experimental="True">
+ use properties::longhands::{column_count, column_width};
+ let mut column_count = None;
+ let mut column_width = None;
+ let mut autos = 0;
+
+ loop {
+ if input.try(|input| input.expect_ident_matching("auto")).is_ok() {
+ // Leave the options to None, 'auto' is the initial value.
+ autos += 1;
+ continue
+ }
+
+ if column_count.is_none() {
+ if let Ok(value) = input.try(|input| column_count::parse(context, input)) {
+ column_count = Some(value);
+ continue
+ }
+ }
+
+ if column_width.is_none() {
+ if let Ok(value) = input.try(|input| column_width::parse(context, input)) {
+ column_width = Some(value);
+ continue
+ }
+ }
+
+ break
+ }
+
+ let values = autos + column_count.iter().len() + column_width.iter().len();
+ if values == 0 || values > 2 {
+ Err(())
+ } else {
+ Ok(Longhands {
+ column_count: column_count,
+ column_width: column_width,
+ })
+ }
+ </%self:shorthand>
+
<%self:shorthand name="overflow" sub_properties="overflow-x overflow-y">
use properties::longhands::{overflow_x, overflow_y};
@@ -4802,6 +5005,11 @@ impl PropertyDeclaration {
% endfor
% for shorthand in SHORTHANDS:
"${shorthand.name}" => {
+ % if shorthand.experimental:
+ if !::util::opts::experimental_enabled() {
+ return PropertyDeclarationParseResult::ExperimentalProperty
+ }
+ % endif
match input.try(CSSWideKeyword::parse) {
Ok(CSSWideKeyword::InheritKeyword) => {
% for sub_property in shorthand.sub_properties:
@@ -4987,6 +5195,12 @@ impl ComputedValues {
}
#[inline]
+ pub fn is_multicol(&self) -> bool {
+ let style = self.get_column();
+ style.column_count.is_some() || style.column_width.is_some()
+ }
+
+ #[inline]
pub fn get_font_arc(&self) -> Arc<style_structs::Font> {
self.font.clone()
}