aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/main/layout/construct.rs
diff options
context:
space:
mode:
authorJunyoung Cho <june0.cho@samsung.com>2014-03-20 20:01:08 +0900
committerJunyoung Cho <june0.cho@samsung.com>2014-03-24 16:14:27 +0900
commit008be170d4b2c01e60baeb5827c189f4c7ed0041 (patch)
treebf611fd6191f257892b20104a30f5a5f05bd8263 /src/components/main/layout/construct.rs
parente5333fca2da8b86ea11d43f04280187fd12b09f5 (diff)
downloadservo-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.rs272
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`