diff options
author | Junyoung Cho <june0.cho@samsung.com> | 2014-03-20 20:01:08 +0900 |
---|---|---|
committer | Junyoung Cho <june0.cho@samsung.com> | 2014-03-24 16:14:27 +0900 |
commit | 008be170d4b2c01e60baeb5827c189f4c7ed0041 (patch) | |
tree | bf611fd6191f257892b20104a30f5a5f05bd8263 /src/components/main/layout/construct.rs | |
parent | e5333fca2da8b86ea11d43f04280187fd12b09f5 (diff) | |
download | servo-008be170d4b2c01e60baeb5827c189f4c7ed0041.tar.gz servo-008be170d4b2c01e60baeb5827c189f4c7ed0041.zip |
Construct table-related flow and calculate fixed layout
Diffstat (limited to 'src/components/main/layout/construct.rs')
-rw-r--r-- | src/components/main/layout/construct.rs | 272 |
1 files changed, 245 insertions, 27 deletions
diff --git a/src/components/main/layout/construct.rs b/src/components/main/layout/construct.rs index 8ae7c06a2d1..857b7c82530 100644 --- a/src/components/main/layout/construct.rs +++ b/src/components/main/layout/construct.rs @@ -22,15 +22,23 @@ use css::node_style::StyledNode; use layout::block::BlockFlow; -use layout::box_::{Box, GenericBox, IframeBox, IframeBoxInfo, ImageBox, ImageBoxInfo}; +use layout::box_::{Box, GenericBox, IframeBox, IframeBoxInfo, ImageBox, ImageBoxInfo, TableBox}; +use layout::box_::{TableCellBox, TableColumnBox, TableColumnBoxInfo, TableRowBox, TableWrapperBox}; use layout::box_::{InlineInfo, InlineParentInfo, SpecificBoxInfo, UnscannedTextBox}; use layout::box_::{UnscannedTextBoxInfo}; use layout::context::LayoutContext; use layout::floats::FloatKind; -use layout::flow::{Flow, MutableOwnedFlowUtils}; +use layout::flow::{Flow, ImmutableFlowUtils, MutableOwnedFlowUtils}; use layout::flow::{Descendants, AbsDescendants, FixedDescendants}; use layout::flow_list::{Rawlink}; use layout::inline::InlineFlow; +use layout::table_wrapper::TableWrapperFlow; +use layout::table::TableFlow; +use layout::table_caption::TableCaptionFlow; +use layout::table_colgroup::TableColGroupFlow; +use layout::table_rowgroup::TableRowGroupFlow; +use layout::table_row::TableRowFlow; +use layout::table_cell::TableCellFlow; use layout::text::TextRunScanner; use layout::util::{LayoutDataAccess, OpaqueNode}; use layout::wrapper::{PostorderNodeMutTraversal, TLayoutNode, ThreadSafeLayoutNode}; @@ -39,6 +47,9 @@ use gfx::font_context::FontContext; use script::dom::bindings::codegen::InheritTypes::TextCast; use script::dom::bindings::js::JS; use script::dom::element::{HTMLIFrameElementTypeId, HTMLImageElementTypeId, HTMLObjectElementTypeId}; +use script::dom::element::{HTMLTableElementTypeId, HTMLTableSectionElementTypeId}; +use script::dom::element::{HTMLTableDataCellElementTypeId, HTMLTableHeaderCellElementTypeId}; +use script::dom::element::{HTMLTableColElementTypeId, HTMLTableRowElementTypeId}; use script::dom::node::{CommentNodeTypeId, DoctypeNodeTypeId, DocumentFragmentNodeTypeId}; use script::dom::node::{DocumentNodeTypeId, ElementNodeTypeId, ProcessingInstructionNodeTypeId}; use script::dom::node::{TextNodeTypeId}; @@ -89,6 +100,8 @@ enum ConstructionItem { InlineBoxesConstructionItem(InlineBoxesConstructionResult), /// Potentially ignorable whitespace. WhitespaceConstructionItem(OpaqueNode, Arc<ComputedValues>), + /// TableColumn Box + TableColumnBoxConstructionItem(Box), } impl ConstructionItem { @@ -102,6 +115,7 @@ impl ConstructionItem { } } WhitespaceConstructionItem(..) => {} + TableColumnBoxConstructionItem(_) => {} } } } @@ -288,6 +302,12 @@ impl<'a> FlowConstructor<'a> { let data = node.get_object_data(&self.layout_context.url); self.build_box_info_for_image(node, data) } + ElementNodeTypeId(HTMLTableElementTypeId) => TableWrapperBox, + ElementNodeTypeId(HTMLTableColElementTypeId) => TableColumnBox(TableColumnBoxInfo::new(node)), + ElementNodeTypeId(HTMLTableDataCellElementTypeId) | + ElementNodeTypeId(HTMLTableHeaderCellElementTypeId) => TableCellBox, + ElementNodeTypeId(HTMLTableRowElementTypeId) | + ElementNodeTypeId(HTMLTableSectionElementTypeId) => TableRowBox, TextNodeTypeId => UnscannedTextBox(UnscannedTextBoxInfo::new(node)), _ => GenericBox, } @@ -332,10 +352,10 @@ impl<'a> FlowConstructor<'a> { /// this block flow. /// Also, deal with the absolute and fixed descendants bubbled up by /// children nodes. - fn build_block_flow_using_children(&mut self, - mut flow: ~Flow, - node: &ThreadSafeLayoutNode) - -> ConstructionResult { + fn build_flow_using_children(&mut self, + mut flow: ~Flow, + node: &ThreadSafeLayoutNode) + -> ConstructionResult { // Gather up boxes for the inline flows we might need to create. let mut opt_boxes_for_inline_flow = None; let mut first_box = true; @@ -346,25 +366,29 @@ impl<'a> FlowConstructor<'a> { match kid.swap_out_construction_result() { NoConstructionResult => {} FlowConstructionResult(kid_flow, kid_abs_descendants, kid_fixed_descendants) => { - // Strip ignorable whitespace from the start of this flow per CSS 2.1 § - // 9.2.1.1. - if first_box { - strip_ignorable_whitespace_from_start(&mut opt_boxes_for_inline_flow); - first_box = false - } - - // Flush any inline boxes that we were gathering up. This allows us to handle - // {ib} splits. - debug!("flushing {} inline box(es) to flow A", - opt_boxes_for_inline_flow.as_ref() - .map_or(0, |boxes| boxes.len())); - self.flush_inline_boxes_to_flow_if_necessary(&mut opt_boxes_for_inline_flow, - &mut flow, - node); - flow.add_new_child(kid_flow); - abs_descendants.push_descendants(kid_abs_descendants); - fixed_descendants.push_descendants(kid_fixed_descendants); + // If kid_flow is TableCaptionFlow, kid_flow should be added under TableWrapperFlow. + if flow.is_table() && kid_flow.is_table_caption() { + kid.set_flow_construction_result(FlowConstructionResult(kid_flow, kid_abs_descendants, kid_fixed_descendants)) + } else { + // Strip ignorable whitespace from the start of this flow per CSS 2.1 § + // 9.2.1.1. + if flow.is_table_kind() || first_box { + strip_ignorable_whitespace_from_start(&mut opt_boxes_for_inline_flow); + first_box = false + } + // Flush any inline boxes that we were gathering up. This allows us to handle + // {ib} splits. + debug!("flushing {} inline box(es) to flow A", + opt_boxes_for_inline_flow.as_ref() + .map_or(0, |boxes| boxes.len())); + self.flush_inline_boxes_to_flow_if_necessary(&mut opt_boxes_for_inline_flow, + &mut flow, + node); + flow.add_new_child(kid_flow); + abs_descendants.push_descendants(kid_abs_descendants); + fixed_descendants.push_descendants(kid_fixed_descendants); + } } ConstructionItemConstructionResult(InlineBoxesConstructionItem( InlineBoxesConstructionResult { @@ -419,6 +443,10 @@ impl<'a> FlowConstructor<'a> { ConstructionItemConstructionResult(WhitespaceConstructionItem(..)) => { // Nothing to do here. } + ConstructionItemConstructionResult(TableColumnBoxConstructionItem(_)) => { + // TODO: Implement anonymous table objects for missing parents + // CSS 2.1 § 17.2.1, step 3-2 + } } } @@ -456,7 +484,7 @@ impl<'a> FlowConstructor<'a> { /// to happen. fn build_flow_for_block(&mut self, node: &ThreadSafeLayoutNode) -> ConstructionResult { let flow = ~BlockFlow::from_node(self, node) as ~Flow; - self.build_block_flow_using_children(flow, node) + self.build_flow_using_children(flow, node) } /// Builds the flow for a node with `float: {left|right}`. This yields a float `BlockFlow` with @@ -464,7 +492,7 @@ impl<'a> FlowConstructor<'a> { fn build_flow_for_floated_block(&mut self, node: &ThreadSafeLayoutNode, float_kind: FloatKind) -> ConstructionResult { let flow = ~BlockFlow::float_from_node(self, node, float_kind) as ~Flow; - self.build_block_flow_using_children(flow, node) + self.build_flow_using_children(flow, node) } @@ -536,6 +564,10 @@ impl<'a> FlowConstructor<'a> { whitespace_style, UnscannedTextBox(UnscannedTextBoxInfo::from_text(~" ")))) } + ConstructionItemConstructionResult(TableColumnBoxConstructionItem(_)) => { + // TODO: Implement anonymous table objects for missing parents + // CSS 2.1 § 17.2.1, step 3-2 + } } } @@ -613,7 +645,7 @@ impl<'a> FlowConstructor<'a> { let boxes_len = boxes.len(); parent_box.compute_borders(parent_box.style()); - for (i,box_) in boxes.iter().enumerate() { + for (i, box_) in boxes.iter().enumerate() { if box_.inline_info.with( |data| data.is_none() ) { box_.inline_info.set(Some(InlineInfo::new())); } @@ -684,6 +716,149 @@ impl<'a> FlowConstructor<'a> { self.build_boxes_for_replaced_inline_content(node) } } + + fn build_table_wrapper_flow_using_children(&mut self, + table_wrapper_flow: &mut ~Flow, + node: &ThreadSafeLayoutNode) + -> (Descendants, Descendants) { + // List of absolute descendants, in tree order. + let mut abs_descendants = Descendants::new(); + let mut fixed_descendants = Descendants::new(); + for kid in node.children() { + match kid.swap_out_construction_result() { + NoConstructionResult | ConstructionItemConstructionResult(_) => {} + FlowConstructionResult(kid_flow, kid_abs_descendants, kid_fixed_descendants) => { + // Only kid flows with table-caption are matched here. + assert!(kid_flow.is_table_caption()); + table_wrapper_flow.add_new_child(kid_flow); + abs_descendants.push_descendants(kid_abs_descendants); + fixed_descendants.push_descendants(kid_fixed_descendants); + } + } + } + (abs_descendants, fixed_descendants) + } + + /// 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) -> ConstructionResult { + let box_ = Box::new_from_specific_info(node, TableWrapperBox); + let mut wrapper_flow = ~TableWrapperFlow::from_node_and_box(node, box_) as ~Flow; + + let table_box_ = Box::new_from_specific_info(node, TableBox); + let table_flow = ~TableFlow::from_node_and_box(node, table_box_) as ~Flow; + + // We first populate the TableFlow with other flows than TableCaptionFlow. + // We then populate the TableWrapperFlow with TableCaptionFlow, and attach + // the TableFlow to the TableWrapperFlow + let construction_result = self.build_flow_using_children(table_flow, node); + let (mut abs_descendants, mut fixed_descendants) + = self.build_table_wrapper_flow_using_children(&mut wrapper_flow, node); + + // NOTE: The order of captions and table are not the same order as in the DOM tree. + // All caption blocks are placed before the table flow + match construction_result { + FlowConstructionResult(table_flow, table_abs_descendants, table_fixed_descendants) => { + wrapper_flow.add_new_child(table_flow); + abs_descendants.push_descendants(table_abs_descendants); + fixed_descendants.push_descendants(table_fixed_descendants); + } + _ => {} + } + + // The flow is done. + wrapper_flow.finish(self.layout_context); + let is_positioned = wrapper_flow.as_block().is_positioned(); + let is_fixed_positioned = wrapper_flow.as_block().is_fixed(); + let is_absolutely_positioned = wrapper_flow.as_block().is_absolutely_positioned(); + if is_positioned { + // This is the CB for all the absolute descendants. + wrapper_flow.set_abs_descendants(abs_descendants); + abs_descendants = Descendants::new(); + + if is_fixed_positioned { + // Send itself along with the other fixed descendants. + fixed_descendants.push(Rawlink::some(wrapper_flow)); + } else if is_absolutely_positioned { + // This is now the only absolute flow in the subtree which hasn't yet + // reached its CB. + abs_descendants.push(Rawlink::some(wrapper_flow)); + } + } + FlowConstructionResult(wrapper_flow, abs_descendants, fixed_descendants) + } + + /// Builds a flow for a node with `display: table-caption`. This yields a `TableCaptionFlow` + /// with possibly other `BlockFlow`s or `InlineFlow`s underneath it. + fn build_flow_for_table_caption(&mut self, node: &ThreadSafeLayoutNode) -> ConstructionResult { + let flow = ~TableCaptionFlow::from_node(self, node) as ~Flow; + self.build_flow_using_children(flow, node) + } + + /// Builds a flow for a node with `display: table-row-group`. This yields a `TableRowGroupFlow` + /// with possibly other `TableRowFlow`s underneath it. + fn build_flow_for_table_rowgroup(&mut self, node: &ThreadSafeLayoutNode) -> ConstructionResult { + let box_ = Box::new_from_specific_info(node, TableRowBox); + let flow = ~TableRowGroupFlow::from_node_and_box(node, box_) as ~Flow; + self.build_flow_using_children(flow, node) + } + + /// Builds a flow for a node with `display: table-row`. This yields a `TableRowFlow` with + /// possibly other `TableCellFlow`s underneath it. + fn build_flow_for_table_row(&mut self, node: &ThreadSafeLayoutNode) -> ConstructionResult { + let box_ = Box::new_from_specific_info(node, TableRowBox); + let flow = ~TableRowFlow::from_node_and_box(node, box_) as ~Flow; + self.build_flow_using_children(flow, node) + } + + /// Builds a flow for a node with `display: table-cell`. This yields a `TableCellFlow` with + /// possibly other `BlockFlow`s or `InlineFlow`s underneath it. + fn build_flow_for_table_cell(&mut self, node: &ThreadSafeLayoutNode) -> ConstructionResult { + let box_ = Box::new_from_specific_info(node, TableCellBox); + let flow = ~TableCellFlow::from_node_and_box(node, box_) as ~Flow; + self.build_flow_using_children(flow, node) + } + + /// Creates a box for a node with `display: table-column`. + fn build_boxes_for_table_column(&mut self, node: &ThreadSafeLayoutNode) -> ConstructionResult { + // CSS 2.1 § 17.2.1. Treat all child boxes of a `table-column` as `display: none`. + for kid in node.children() { + kid.set_flow_construction_result(NoConstructionResult) + } + + let specific = TableColumnBox(TableColumnBoxInfo::new(node)); + let construction_item = TableColumnBoxConstructionItem( + Box::new_from_specific_info(node, specific) + ); + ConstructionItemConstructionResult(construction_item) + } + + /// Builds a flow for a node with `display: table-column-group`. + /// This yields a `TableColGroupFlow`. + fn build_flow_for_table_colgroup(&mut self, node: &ThreadSafeLayoutNode) -> ConstructionResult { + let box_ = Box::new_from_specific_info(node, + TableColumnBox(TableColumnBoxInfo::new(node))); + let mut col_boxes = ~[]; + for kid in node.children() { + // CSS 2.1 § 17.2.1. Treat all non-column child boxes of `table-column-group` + // as `display: none`. + match kid.swap_out_construction_result() { + ConstructionItemConstructionResult(TableColumnBoxConstructionItem(box_)) => { + col_boxes.push(box_); + } + _ => {} + } + } + if col_boxes.is_empty() { + debug!("add TableColumnBox for empty colgroup"); + let specific = TableColumnBox(TableColumnBoxInfo::new(node)); + col_boxes.push( Box::new_from_specific_info(node, specific) ); + } + let mut flow = ~TableColGroupFlow::from_node_and_boxes(node, box_, col_boxes) as ~Flow; + flow.finish(self.layout_context); + + FlowConstructionResult(flow, Descendants::new(), Descendants::new()) + } } impl<'a> PostorderNodeMutTraversal for FlowConstructor<'a> { @@ -725,6 +900,12 @@ impl<'a> PostorderNodeMutTraversal for FlowConstructor<'a> { } } + // Table items contribute table flow construction results. + (display::table, _, _) => { + let construction_result = self.build_flow_for_table_wrapper(node); + node.set_flow_construction_result(construction_result) + } + // Absolutely positioned elements will have computed value of // `float` as 'none' and `display` as per the table. // Currently, for original `display` value of 'inline', the new @@ -739,6 +920,43 @@ impl<'a> PostorderNodeMutTraversal for FlowConstructor<'a> { node.set_flow_construction_result(construction_result) } + // Table items contribute table flow construction results. + (display::table_caption, _, _) => { + let construction_result = self.build_flow_for_table_caption(node); + node.set_flow_construction_result(construction_result) + } + + // Table items contribute table flow construction results. + (display::table_column_group, _, _) => { + let construction_result = self.build_flow_for_table_colgroup(node); + node.set_flow_construction_result(construction_result) + } + + // Table items contribute table flow construction results. + (display::table_column, _, _) => { + let construction_result = self.build_boxes_for_table_column(node); + node.set_flow_construction_result(construction_result) + } + + // Table items contribute table flow construction results. + (display::table_row_group, _, _) | (display::table_header_group, _, _) | + (display::table_footer_group, _, _) => { + let construction_result = self.build_flow_for_table_rowgroup(node); + node.set_flow_construction_result(construction_result) + } + + // Table items contribute table flow construction results. + (display::table_row, _, _) => { + let construction_result = self.build_flow_for_table_row(node); + node.set_flow_construction_result(construction_result) + } + + // Table items contribute table flow construction results. + (display::table_cell, _, _) => { + let construction_result = self.build_flow_for_table_cell(node); + node.set_flow_construction_result(construction_result) + } + // Block flows that are not floated contribute block flow construction results. // // TODO(pcwalton): Make this only trigger for blocks and handle the other `display` |