diff options
author | bors-servo <release+servo@mozilla.com> | 2014-05-02 14:58:29 -0400 |
---|---|---|
committer | bors-servo <release+servo@mozilla.com> | 2014-05-02 14:58:29 -0400 |
commit | 1ab22d947008b90e01c565736d3d3953ad491648 (patch) | |
tree | e484ba5f8847f311cb25fd99b623991ce1391ca3 /src/components/main/layout/construct.rs | |
parent | 85393c69311bbe6dbb6f8ea8b28a6f0f6344fbe7 (diff) | |
parent | 27276c0305d6dc5079c536f4f27d23efbc56eb3e (diff) | |
download | servo-1ab22d947008b90e01c565736d3d3953ad491648.tar.gz servo-1ab22d947008b90e01c565736d3d3953ad491648.zip |
auto merge of #2174 : pcwalton/servo/reparallelize, r=SimonSapin
layout: Re-enable parallel layout by removing all `RefCell` instances from `Flow`s; in the process, remove `InlineInfo` in favor of the range-based design that was originally planned and halfway implemented.
Now, the DOM tree structure for inline flows is reflected not by a
series of arrays but instead by a flat list of ranges into the list of
boxes. As part of this, the `border` and `padding` fields, which were
incorrect in the case of inlines and necessitated separate
`noncontent_inline_foo` methods, have been merged into a single
`border_padding` field that is always guaranteed to be correct after
width assignment, even for inlines.
r? @SimonSapin and/or @larsbergstrom
Closes #1280
Closes #1926
Closes #1999
Closes #2013
Closes #2018
Diffstat (limited to 'src/components/main/layout/construct.rs')
-rw-r--r-- | src/components/main/layout/construct.rs | 439 |
1 files changed, 202 insertions, 237 deletions
diff --git a/src/components/main/layout/construct.rs b/src/components/main/layout/construct.rs index 77222b6b770..92059e44d18 100644 --- a/src/components/main/layout/construct.rs +++ b/src/components/main/layout/construct.rs @@ -23,15 +23,14 @@ use css::node_style::StyledNode; use layout::block::BlockFlow; use layout::box_::{Box, GenericBox, IframeBox, IframeBoxInfo, ImageBox, ImageBoxInfo}; -use layout::box_::{InlineInfo, InlineParentInfo, SpecificBoxInfo}; -use layout::box_::{TableBox, TableCellBox, TableColumnBox, TableColumnBoxInfo, TableRowBox}; -use layout::box_::{TableWrapperBox, UnscannedTextBox, UnscannedTextBoxInfo}; +use layout::box_::{SpecificBoxInfo, TableBox, TableCellBox, TableColumnBox, TableColumnBoxInfo}; +use layout::box_::{TableRowBox, TableWrapperBox, UnscannedTextBox, UnscannedTextBoxInfo}; use layout::context::LayoutContext; use layout::floats::FloatKind; use layout::flow::{Flow, ImmutableFlowUtils, MutableOwnedFlowUtils}; use layout::flow::{Descendants, AbsDescendants}; use layout::flow_list::{Rawlink}; -use layout::inline::InlineFlow; +use layout::inline::{InlineBoxes, InlineFlow}; use layout::table_wrapper::TableWrapperFlow; use layout::table::TableFlow; use layout::table_caption::TableCaptionFlow; @@ -57,13 +56,12 @@ use script::dom::node::{CommentNodeTypeId, DoctypeNodeTypeId, DocumentFragmentNo use script::dom::node::{DocumentNodeTypeId, ElementNodeTypeId, ProcessingInstructionNodeTypeId}; use script::dom::node::{TextNodeTypeId}; use script::dom::text::Text; -use servo_util::geometry::Au; use servo_util::namespace; -use servo_util::smallvec::SmallVec; +use servo_util::range::Range; +use servo_util::smallvec::{SmallVec, SmallVec0}; use servo_util::str::is_whitespace; use servo_util::url::{is_image_data, parse_url}; use std::mem; -use std::num::Zero; use style::ComputedValues; use style::computed_values::{display, position, float, white_space}; use sync::Arc; @@ -78,7 +76,7 @@ pub enum ConstructionResult { /// This node contributed a flow at the proper position in the tree. /// Nothing more needs to be done for this node. It has bubbled up fixed /// and absolute descendant flows that have a CB above it. - FlowConstructionResult(~Flow, AbsDescendants), + FlowConstructionResult(~Flow:Share, AbsDescendants), /// This node contributed some object or objects that will be needed to construct a proper flow /// later up the tree, but these objects have not yet found their home. @@ -131,7 +129,7 @@ pub struct InlineBoxesConstructionResult { pub splits: Option<~[InlineBlockSplit]>, /// Any boxes that succeed the {ib} splits. - pub boxes: ~[Box], + pub boxes: InlineBoxes, /// Any absolute descendants that we're bubbling up. pub abs_descendants: AbsDescendants, @@ -161,12 +159,10 @@ pub struct InlineBoxesConstructionResult { /// ]) pub struct InlineBlockSplit { /// The inline boxes that precede the flow. - /// - /// TODO(pcwalton): Small vector optimization. - pub predecessor_boxes: ~[Box], + pub predecessors: InlineBoxes, /// The flow that caused this {ib} split. - pub flow: ~Flow, + pub flow: ~Flow:Share, } impl InlineBlockSplit { @@ -238,6 +234,53 @@ impl<T> OptVector<T> for Option<~[T]> { } } +/// Holds inline boxes that we're gathering for children of an inline node. +struct InlineBoxAccumulator { + /// The list of boxes. + boxes: InlineBoxes, + + /// Whether we've created a range to enclose all the boxes. This will be true if the outer node + /// is an inline and false otherwise. + has_enclosing_range: bool, +} + +impl InlineBoxAccumulator { + fn new() -> InlineBoxAccumulator { + InlineBoxAccumulator { + boxes: InlineBoxes::new(), + has_enclosing_range: false, + } + } + + fn from_inline_node(node: &ThreadSafeLayoutNode) -> InlineBoxAccumulator { + let mut boxes = InlineBoxes::new(); + boxes.map.push(node.style().clone(), Range::new(0, 0)); + InlineBoxAccumulator { + boxes: boxes, + has_enclosing_range: true, + } + } + + fn finish(self) -> InlineBoxes { + let InlineBoxAccumulator { + boxes: mut boxes, + has_enclosing_range + } = self; + + if has_enclosing_range { + let len = boxes.len(); + boxes.map.get_mut(0).range.extend_to(len); + } + boxes + } +} + +enum WhitespaceStrippingMode { + NoWhitespaceStripping, + StripWhitespaceFromStart, + StripWhitespaceFromEnd, +} + /// An object that knows how to create flows. pub struct FlowConstructor<'a> { /// The layout context. @@ -327,15 +370,33 @@ impl<'a> FlowConstructor<'a> { /// otherwise. #[inline(always)] fn flush_inline_boxes_to_flow_or_list(&mut self, - boxes: ~[Box], - flow: &mut ~Flow, - flow_list: &mut ~[~Flow], + box_accumulator: InlineBoxAccumulator, + flow: &mut ~Flow:Share, + flow_list: &mut ~[~Flow:Share], + whitespace_stripping: WhitespaceStrippingMode, node: &ThreadSafeLayoutNode) { + let mut boxes = box_accumulator.finish(); if boxes.len() == 0 { return } - let mut inline_flow = ~InlineFlow::from_boxes((*node).clone(), boxes) as ~Flow; + match whitespace_stripping { + NoWhitespaceStripping => {} + StripWhitespaceFromStart => { + strip_ignorable_whitespace_from_start(&mut boxes); + if boxes.len() == 0 { + return + } + } + StripWhitespaceFromEnd => { + strip_ignorable_whitespace_from_end(&mut boxes); + if boxes.len() == 0 { + return + } + } + } + + let mut inline_flow = ~InlineFlow::from_boxes((*node).clone(), boxes) as ~Flow:Share; TextRunScanner::new().scan_for_runs(self.font_context(), inline_flow); inline_flow.finish(self.layout_context); @@ -346,25 +407,14 @@ impl<'a> FlowConstructor<'a> { } } - /// Creates an inline flow from a set of inline boxes, if present, and adds it as a child of - /// the given flow or pushes it onto the given flow list. - fn flush_inline_boxes_to_flow_or_list_if_necessary(&mut self, - opt_boxes: &mut Option<~[Box]>, - flow: &mut ~Flow, - flow_list: &mut ~[~Flow], - node: &ThreadSafeLayoutNode) { - let opt_boxes = mem::replace(opt_boxes, None); - if opt_boxes.len() > 0 { - self.flush_inline_boxes_to_flow_or_list(opt_boxes.to_vec(), flow, flow_list, node) - } - } - fn build_block_flow_using_children_construction_result(&mut self, - flow: &mut ~Flow, - consecutive_siblings: &mut ~[~Flow], + flow: &mut ~Flow:Share, + consecutive_siblings: + &mut ~[~Flow:Share], node: &ThreadSafeLayoutNode, kid: ThreadSafeLayoutNode, - opt_boxes_for_inline_flow: &mut Option<~[Box]>, + inline_box_accumulator: + &mut InlineBoxAccumulator, abs_descendants: &mut Descendants, first_box: &mut bool) { match kid.swap_out_construction_result() { @@ -381,20 +431,22 @@ impl<'a> FlowConstructor<'a> { } 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(opt_boxes_for_inline_flow); - *first_box = false - } + let whitespace_stripping = if flow.is_table_kind() || *first_box { + *first_box = false; + StripWhitespaceFromStart + } else { + NoWhitespaceStripping + }; // 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_or_list_if_necessary( - opt_boxes_for_inline_flow, + inline_box_accumulator.boxes.len()); + self.flush_inline_boxes_to_flow_or_list( + mem::replace(inline_box_accumulator, InlineBoxAccumulator::new()), flow, consecutive_siblings, + whitespace_stripping, node); if !consecutive_siblings.is_empty() { let consecutive_siblings = mem::replace(consecutive_siblings, ~[]); @@ -409,7 +461,7 @@ impl<'a> FlowConstructor<'a> { ConstructionItemConstructionResult(InlineBoxesConstructionItem( InlineBoxesConstructionResult { splits: opt_splits, - boxes: boxes, + boxes: successor_boxes, abs_descendants: kid_abs_descendants, })) => { // Add any {ib} splits. @@ -420,27 +472,29 @@ impl<'a> FlowConstructor<'a> { // Pull apart the {ib} split object and push its predecessor boxes // onto the list. let InlineBlockSplit { - predecessor_boxes: predecessor_boxes, + predecessors: predecessors, flow: kid_flow } = split; - opt_boxes_for_inline_flow.push_all_move(predecessor_boxes); + inline_box_accumulator.boxes.push_all(predecessors); // If this is the first box in flow, then strip ignorable // whitespace per CSS 2.1 § 9.2.1.1. - if *first_box { - strip_ignorable_whitespace_from_start( - opt_boxes_for_inline_flow); - *first_box = false - } + let whitespace_stripping = if *first_box { + *first_box = false; + StripWhitespaceFromStart + } else { + NoWhitespaceStripping + }; // Flush any inline boxes that we were gathering up. 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_or_list_if_necessary( - opt_boxes_for_inline_flow, + inline_box_accumulator.boxes.len()); + self.flush_inline_boxes_to_flow_or_list( + mem::replace(inline_box_accumulator, + InlineBoxAccumulator::new()), flow, consecutive_siblings, + whitespace_stripping, node); // Push the flow generated by the {ib} split onto our list of @@ -455,7 +509,7 @@ impl<'a> FlowConstructor<'a> { } // Add the boxes to the list we're maintaining. - opt_boxes_for_inline_flow.push_all_move(boxes); + inline_box_accumulator.boxes.push_all(successor_boxes); abs_descendants.push_descendants(kid_abs_descendants); } ConstructionItemConstructionResult(WhitespaceConstructionItem(..)) => { @@ -476,11 +530,11 @@ impl<'a> FlowConstructor<'a> { /// Also, deal with the absolute and fixed descendants bubbled up by /// children nodes. fn build_flow_using_children(&mut self, - mut flow: ~Flow, + mut flow: ~Flow:Share, 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 inline_box_accumulator = InlineBoxAccumulator::new(); let mut consecutive_siblings = ~[]; let mut first_box = true; @@ -491,23 +545,22 @@ impl<'a> FlowConstructor<'a> { self.process(&kid); } - self.build_block_flow_using_children_construction_result( - &mut flow, - &mut consecutive_siblings, - node, - kid, - &mut opt_boxes_for_inline_flow, - &mut abs_descendants, - &mut first_box); + self.build_block_flow_using_children_construction_result(&mut flow, + &mut consecutive_siblings, + node, + kid, + &mut inline_box_accumulator, + &mut abs_descendants, + &mut first_box); } // Perform a final flush of any inline boxes that we were gathering up to handle {ib} // splits, after stripping ignorable whitespace. - strip_ignorable_whitespace_from_end(&mut opt_boxes_for_inline_flow); - self.flush_inline_boxes_to_flow_or_list_if_necessary(&mut opt_boxes_for_inline_flow, - &mut flow, - &mut consecutive_siblings, - node); + self.flush_inline_boxes_to_flow_or_list(inline_box_accumulator, + &mut flow, + &mut consecutive_siblings, + StripWhitespaceFromEnd, + node); if !consecutive_siblings.is_empty() { self.generate_anonymous_missing_child(consecutive_siblings, &mut flow, node); } @@ -535,7 +588,7 @@ impl<'a> FlowConstructor<'a> { /// other `BlockFlow`s or `InlineFlow`s underneath it, depending on whether {ib} splits needed /// to happen. fn build_flow_for_block(&mut self, node: &ThreadSafeLayoutNode) -> ConstructionResult { - let flow = ~BlockFlow::from_node(self, node) as ~Flow; + let flow = ~BlockFlow::from_node(self, node) as ~Flow:Share; self.build_flow_using_children(flow, node) } @@ -543,7 +596,7 @@ impl<'a> FlowConstructor<'a> { /// a `BlockFlow` underneath it. 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; + let flow = ~BlockFlow::float_from_node(self, node, float_kind) as ~Flow:Share; self.build_flow_using_children(flow, node) } @@ -553,7 +606,7 @@ impl<'a> FlowConstructor<'a> { fn build_boxes_for_nonreplaced_inline_content(&mut self, node: &ThreadSafeLayoutNode) -> ConstructionResult { let mut opt_inline_block_splits = None; - let mut opt_box_accumulator = None; + let mut box_accumulator = InlineBoxAccumulator::from_inline_node(node); let mut abs_descendants = Descendants::new(); // Concatenate all the boxes of our kids, creating {ib} splits as necessary. @@ -567,7 +620,9 @@ impl<'a> FlowConstructor<'a> { // {ib} split. Flush the accumulator to our new split and make a new // accumulator to hold any subsequent boxes we come across. let split = InlineBlockSplit { - predecessor_boxes: mem::replace(&mut opt_box_accumulator, None).to_vec(), + predecessors: + mem::replace(&mut box_accumulator, + InlineBoxAccumulator::from_inline_node(node)).finish(), flow: flow, }; opt_inline_block_splits.push(split); @@ -576,7 +631,7 @@ impl<'a> FlowConstructor<'a> { ConstructionItemConstructionResult(InlineBoxesConstructionItem( InlineBoxesConstructionResult { splits: opt_splits, - boxes: boxes, + boxes: successors, abs_descendants: kid_abs_descendants, })) => { @@ -586,14 +641,16 @@ impl<'a> FlowConstructor<'a> { Some(splits) => { for split in splits.move_iter() { let InlineBlockSplit { - predecessor_boxes: boxes, + predecessors: predecessors, flow: kid_flow } = split; - opt_box_accumulator.push_all_move(boxes); + box_accumulator.boxes.push_all(predecessors); let split = InlineBlockSplit { - predecessor_boxes: mem::replace(&mut opt_box_accumulator, - None).to_vec(), + predecessors: + mem::replace(&mut box_accumulator, + InlineBoxAccumulator::from_inline_node(node)) + .finish(), flow: kid_flow, }; opt_inline_block_splits.push(split) @@ -602,17 +659,18 @@ impl<'a> FlowConstructor<'a> { } // Push residual boxes. - opt_box_accumulator.push_all_move(boxes); + box_accumulator.boxes.push_all(successors); abs_descendants.push_descendants(kid_abs_descendants); } ConstructionItemConstructionResult(WhitespaceConstructionItem(whitespace_node, whitespace_style)) => { // Instantiate the whitespace box. - opt_box_accumulator.push(Box::from_opaque_node_and_style( - whitespace_node, - whitespace_style, - UnscannedTextBox(UnscannedTextBoxInfo::from_text(~" ")))) + let box_info = UnscannedTextBox(UnscannedTextBoxInfo::from_text(~" ")); + let fragment = Box::from_opaque_node_and_style(whitespace_node, + whitespace_style.clone(), + box_info); + box_accumulator.boxes.push(fragment, whitespace_style) } ConstructionItemConstructionResult(TableColumnBoxConstructionItem(_)) => { // TODO: Implement anonymous table objects for missing parents @@ -621,56 +679,12 @@ impl<'a> FlowConstructor<'a> { } } - // fill inline info - match opt_inline_block_splits { - Some(ref splits) => { - match opt_box_accumulator { - Some(ref boxes) => { - // Both - let mut total: ~[&Box] = ~[]; - for split in splits.iter() { - for box_ in split.predecessor_boxes.iter() { - total.push(box_); - } - } - for box_ in boxes.iter() { - total.push(box_); - } - self.set_inline_info_for_inline_child(total, node); - - }, - None => { - let mut total: ~[&Box] = ~[]; - for split in splits.iter() { - for box_ in split.predecessor_boxes.iter() { - total.push(box_); - } - } - self.set_inline_info_for_inline_child(total, node); - } - } - }, - None => { - match opt_box_accumulator { - Some(ref boxes) => { - let mut total: ~[&Box] = ~[]; - for box_ in boxes.iter() { - total.push(box_); - } - self.set_inline_info_for_inline_child(total, node); - }, - None => {} - } - } - } - // Finally, make a new construction result. - if opt_inline_block_splits.len() > 0 || opt_box_accumulator.len() > 0 - || abs_descendants.len() > 0 { - + if opt_inline_block_splits.len() > 0 || box_accumulator.boxes.len() > 0 + || abs_descendants.len() > 0 { let construction_item = InlineBoxesConstructionItem(InlineBoxesConstructionResult { splits: opt_inline_block_splits, - boxes: opt_box_accumulator.to_vec(), + boxes: box_accumulator.finish(), abs_descendants: abs_descendants, }); ConstructionItemConstructionResult(construction_item) @@ -679,60 +693,6 @@ impl<'a> FlowConstructor<'a> { } } - // FIXME(#1999, pcwalton): Why does this function create a box only to throw it away??? - fn set_inline_info_for_inline_child(&mut self, - boxes: &[&Box], - parent_node: &ThreadSafeLayoutNode) { - let parent_box = Box::new(self, parent_node); - let font_style = parent_box.font_style(); - let font_group = self.font_context().get_resolved_font_for_style(&font_style); - let (font_ascent,font_descent) = { - let fg = font_group.borrow(); - let font = fg.fonts[0].borrow(); - (font.metrics.ascent,font.metrics.descent) - }; - - let boxes_len = boxes.len(); - parent_box.compute_borders(parent_box.style()); - - // FIXME(#2000, pcwalton): I suspect that `Au(0)` is not correct for the containing block - // width. - parent_box.compute_padding(parent_box.style(), Au(0)); - - for (i, box_) in boxes.iter().enumerate() { - let mut info = box_.inline_info.borrow_mut(); - if info.is_none() { - *info = Some(InlineInfo::new()); - } - - let mut border = *parent_box.border.borrow(); - let mut padding = *parent_box.padding.borrow(); - if i != 0 { - border.left = Zero::zero(); - padding.left = Zero::zero() - } - if i != (boxes_len - 1) { - border.right = Zero::zero(); - padding.right = Zero::zero() - } - - match &mut *info { - &Some(ref mut info) => { - // TODO(ksh8281): Compute margins. - info.parent_info.push(InlineParentInfo { - padding: padding, - border: border, - margin: Zero::zero(), - style: parent_box.style.clone(), - font_ascent: font_ascent, - font_descent: font_descent, - node: OpaqueNodeMethods::from_thread_safe_layout_node(parent_node), - }) - }, - &None => {} - } - } - } /// Creates an `InlineBoxesConstructionResult` for replaced content. Replaced content doesn't /// render its children, so this just nukes a child's boxes and creates a `Box`. fn build_boxes_for_replaced_inline_content(&mut self, node: &ThreadSafeLayoutNode) @@ -751,12 +711,12 @@ impl<'a> FlowConstructor<'a> { node.style().clone())) } - let mut opt_box_accumulator = None; - opt_box_accumulator.push(Box::new(self, node)); + let mut boxes = InlineBoxes::new(); + boxes.push(Box::new(self, node), node.style().clone()); let construction_item = InlineBoxesConstructionItem(InlineBoxesConstructionResult { splits: None, - boxes: opt_box_accumulator.to_vec(), + boxes: boxes, abs_descendants: Descendants::new(), }); ConstructionItemConstructionResult(construction_item) @@ -777,7 +737,7 @@ impl<'a> FlowConstructor<'a> { /// TableCaptionFlow is populated underneath TableWrapperFlow fn place_table_caption_under_table_wrapper(&mut self, - table_wrapper_flow: &mut ~Flow, + table_wrapper_flow: &mut ~Flow:Share, node: &ThreadSafeLayoutNode) { for kid in node.children() { match kid.swap_out_construction_result() { @@ -794,8 +754,8 @@ impl<'a> FlowConstructor<'a> { /// Generates an anonymous table flow according to CSS 2.1 § 17.2.1, step 2. /// If necessary, generate recursively another anonymous table flow. fn generate_anonymous_missing_child(&mut self, - child_flows: ~[~Flow], - flow: &mut ~Flow, + child_flows: ~[~Flow:Share], + flow: &mut ~Flow:Share, node: &ThreadSafeLayoutNode) { let mut anonymous_flow = flow.generate_missing_child_flow(node); let mut consecutive_siblings = ~[]; @@ -822,10 +782,10 @@ impl<'a> FlowConstructor<'a> { /// 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 mut wrapper_flow = ~TableWrapperFlow::from_node_and_box(node, box_) as ~Flow:Share; let table_box_ = Box::new_from_specific_info(node, TableBox); - let table_flow = ~TableFlow::from_node_and_box(node, table_box_) as ~Flow; + let table_flow = ~TableFlow::from_node_and_box(node, table_box_) as ~Flow:Share; // We first populate the TableFlow with other flows than TableCaptionFlow. // We then populate the TableWrapperFlow with TableCaptionFlow, and attach @@ -871,7 +831,7 @@ impl<'a> FlowConstructor<'a> { /// 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; + let flow = ~TableCaptionFlow::from_node(self, node) as ~Flow:Share; self.build_flow_using_children(flow, node) } @@ -879,7 +839,7 @@ impl<'a> FlowConstructor<'a> { /// 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; + let flow = ~TableRowGroupFlow::from_node_and_box(node, box_) as ~Flow:Share; self.build_flow_using_children(flow, node) } @@ -887,7 +847,7 @@ impl<'a> FlowConstructor<'a> { /// 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; + let flow = ~TableRowFlow::from_node_and_box(node, box_) as ~Flow:Share; self.build_flow_using_children(flow, node) } @@ -895,7 +855,7 @@ impl<'a> FlowConstructor<'a> { /// 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; + let flow = ~TableCellFlow::from_node_and_box(node, box_) as ~Flow:Share; self.build_flow_using_children(flow, node) } @@ -934,7 +894,8 @@ impl<'a> FlowConstructor<'a> { 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; + let mut flow = ~TableColGroupFlow::from_node_and_boxes(node, box_, col_boxes) as + ~Flow:Share; flow.finish(self.layout_context); FlowConstructionResult(flow, Descendants::new()) @@ -1200,52 +1161,56 @@ impl<'ln> ObjectElement for ThreadSafeLayoutNode<'ln> { } /// Strips ignorable whitespace from the start of a list of boxes. -fn strip_ignorable_whitespace_from_start(opt_boxes: &mut Option<~[Box]>) { - match mem::replace(opt_boxes, None) { - None => return, - Some(boxes) => { - // FIXME(pcwalton): This is slow because vector shift is broken. :( - let mut found_nonwhitespace = false; - let mut result = ~[]; - let mut last_removed_box: Option<Box> = None; - for box_ in boxes.move_iter() { - if !found_nonwhitespace && box_.is_whitespace_only() { - debug!("stripping ignorable whitespace from start"); - last_removed_box = Some(box_); - continue - } - - found_nonwhitespace = true; - match last_removed_box { - Some(ref last_removed_box) => { - box_.merge_noncontent_inline_left(last_removed_box); - }, - None => {} - } - last_removed_box = None; - result.push(box_) - } +fn strip_ignorable_whitespace_from_start(boxes: &mut InlineBoxes) { + if boxes.len() == 0 { + return + } - *opt_boxes = Some(result) + let InlineBoxes { + boxes: old_boxes, + map: mut map + } = mem::replace(boxes, InlineBoxes::new()); + + // FIXME(#2264, pcwalton): This is slow because vector shift is broken. :( + let mut found_nonwhitespace = false; + let mut new_boxes = SmallVec0::new(); + for fragment in old_boxes.iter() { + if !found_nonwhitespace && fragment.is_whitespace_only() { + debug!("stripping ignorable whitespace from start"); + continue } + + found_nonwhitespace = true; + new_boxes.push(fragment.clone()) + } + + map.fixup(old_boxes.as_slice(), new_boxes.as_slice()); + *boxes = InlineBoxes { + boxes: new_boxes, + map: map, } } /// Strips ignorable whitespace from the end of a list of boxes. -fn strip_ignorable_whitespace_from_end(opt_boxes: &mut Option<~[Box]>) { - match *opt_boxes { - None => {} - Some(ref mut boxes) => { - while boxes.len() > 0 && boxes.last().get_ref().is_whitespace_only() { - debug!("stripping ignorable whitespace from end"); - let box_ = boxes.pop().unwrap(); - if boxes.len() > 0 { - boxes[boxes.len() - 1].merge_noncontent_inline_right(&box_); - } - } - } +fn strip_ignorable_whitespace_from_end(boxes: &mut InlineBoxes) { + if boxes.len() == 0 { + return } - if opt_boxes.len() == 0 { - *opt_boxes = None + + let InlineBoxes { + boxes: old_boxes, + map: mut map + } = mem::replace(boxes, InlineBoxes::new()); + + let mut new_boxes = old_boxes.clone(); + while new_boxes.len() > 0 && new_boxes.as_slice().last().get_ref().is_whitespace_only() { + debug!("stripping ignorable whitespace from end"); + drop(new_boxes.pop()); + } + + map.fixup(old_boxes.as_slice(), new_boxes.as_slice()); + *boxes = InlineBoxes { + boxes: new_boxes, + map: map, } } |