diff options
author | bors-servo <release+servo@mozilla.com> | 2014-05-27 18:16:09 -0400 |
---|---|---|
committer | bors-servo <release+servo@mozilla.com> | 2014-05-27 18:16:09 -0400 |
commit | 65d91e395002106ce263f5ccb188eb384963768a (patch) | |
tree | 33f21314ca6a43466500e2a5baf00f4d30eb0d01 | |
parent | 0886a36b5d5c1b08a128b62933f206f66561d7f6 (diff) | |
parent | a944e378eb33d05528971e19234761ed2aadbfdb (diff) | |
download | servo-65d91e395002106ce263f5ccb188eb384963768a.tar.gz servo-65d91e395002106ce263f5ccb188eb384963768a.zip |
auto merge of #2494 : bjz/servo/split-to-width, r=pcwalton
This will make removing the box splitting logic easier to implement. I am also using a `SplitInfo` struct for returning the split results, which should make the code more self-documenting. In the future the `TextRun` should not be returned, and `SplitInfo` should only require a single `CharIndex`, but one thing at a time...
@pcwalton r?
-rw-r--r-- | src/components/main/layout/box_.rs | 84 | ||||
-rw-r--r-- | src/components/main/layout/inline.rs | 51 |
2 files changed, 85 insertions, 50 deletions
diff --git a/src/components/main/layout/box_.rs b/src/components/main/layout/box_.rs index 125817264f1..a82699f0537 100644 --- a/src/components/main/layout/box_.rs +++ b/src/components/main/layout/box_.rs @@ -241,6 +241,23 @@ impl ScannedTextBoxInfo { } } +#[deriving(Show)] +pub struct SplitInfo { + // TODO(bjz): this should only need to be a single character index, but both values are + // currently needed for splitting in the `inline::try_append_*` functions. + pub range: Range<CharIndex>, + pub width: Au, +} + +impl SplitInfo { + fn new(range: Range<CharIndex>, info: &ScannedTextBoxInfo) -> SplitInfo { + SplitInfo { + range: range, + width: info.run.advance_for_range(&range), + } + } +} + /// Data for an unscanned text box. Unscanned text boxes are the results of flow construction that /// have not yet had their width determined. #[deriving(Clone)] @@ -1087,12 +1104,16 @@ impl Box { } } - /// Split box which includes new-line character. + /// Find the split of a box that includes a new-line character. /// - /// A return value of `None` indicates that the box could not be split. - /// Otherwise the split boxes are returned. The right boxe is optional due - /// to the possibility of it being whitespace. - pub fn split_by_new_line(&self) -> Option<(Box, Option<Box>)> { + /// A return value of `None` indicates that the box is not splittable. + /// Otherwise the split information is returned. The right information is + /// optional due to the possibility of it being whitespace. + // + // TODO(bjz): The text run should be removed in the future, but it is currently needed for + // the current method of box splitting in the `inline::try_append_*` functions. + pub fn find_split_info_by_new_line(&self) + -> Option<(SplitInfo, Option<SplitInfo>, Arc<owned::Box<TextRun>> /* TODO(bjz): remove */)> { match self.specific { GenericBox | IframeBox(_) | ImageBox(_) | TableBox | TableCellBox | TableRowBox | TableWrapperBox => None, @@ -1107,36 +1128,32 @@ impl Box { text_box_info.range.length() - (cur_new_line_pos + CharIndex(1))); // Left box is for left text of first founded new-line character. - let left_box = { - let new_text_box_info = ScannedTextBoxInfo::new(text_box_info.run.clone(), left_range); - let new_metrics = new_text_box_info.run.metrics_for_range(&left_range); - let mut new_box = self.transform(new_metrics.bounding_box.size, ScannedTextBox(new_text_box_info)); - new_box.new_line_pos = vec!(); - new_box - }; + let left_box = SplitInfo::new(left_range, text_box_info); // Right box is for right text of first founded new-line character. let right_box = if right_range.length() > CharIndex(0) { - let new_text_box_info = ScannedTextBoxInfo::new(text_box_info.run.clone(), right_range); - let new_metrics = new_text_box_info.run.metrics_for_range(&right_range); - let mut new_box = self.transform(new_metrics.bounding_box.size, ScannedTextBox(new_text_box_info)); - new_box.new_line_pos = new_line_pos; - Some(new_box) + Some(SplitInfo::new(right_range, text_box_info)) } else { None }; - Some((left_box, right_box)) + Some((left_box, right_box, text_box_info.run.clone())) } } } - /// Attempts to split this box so that its width is no more than `max_width`. + /// Attempts to find the split positions of a text box so that its width is + /// no more than `max_width`. /// /// A return value of `None` indicates that the box could not be split. - /// Otherwise the split boxes are returned. The left and right boxes are - /// optional due to the possibility of them being whitespace. - pub fn split_to_width(&self, max_width: Au, starts_line: bool) -> Option<(Option<Box>, Option<Box>)> { + /// Otherwise the information pertaining to the split is returned. The left + /// and right split information are both optional due to the possibility of + /// them being whitespace. + // + // TODO(bjz): The text run should be removed in the future, but it is currently needed for + // the current method of box splitting in the `inline::try_append_*` functions. + pub fn find_split_info_for_width(&self, start: CharIndex, max_width: Au, starts_line: bool) + -> Option<(Option<SplitInfo>, Option<SplitInfo>, Arc<owned::Box<TextRun>> /* TODO(bjz): remove */)> { match self.specific { GenericBox | IframeBox(_) | ImageBox(_) | TableBox | TableCellBox | TableRowBox | TableWrapperBox => None, @@ -1145,7 +1162,7 @@ impl Box { ScannedTextBox(ref text_box_info) => { let mut pieces_processed_count: uint = 0; let mut remaining_width: Au = max_width; - let mut left_range = Range::new(text_box_info.range.begin(), CharIndex(0)); + let mut left_range = Range::new(text_box_info.range.begin() + start, CharIndex(0)); let mut right_range: Option<Range<CharIndex>> = None; debug!("split_to_width: splitting text box (strlen={:u}, range={}, \ @@ -1217,25 +1234,14 @@ impl Box { if (pieces_processed_count == 1 || !left_is_some) && !starts_line { None } else { - let left_box = if left_is_some { - let new_text_box_info = ScannedTextBoxInfo::new(text_box_info.run.clone(), left_range); - let width = new_text_box_info.run.advance_for_range(&left_range); - let height = self.border_box.size.height; - let size = Size2D(width, height); - Some(self.transform(size, ScannedTextBox(new_text_box_info))) + let left = if left_is_some { + Some(SplitInfo::new(left_range, text_box_info)) } else { - None + None }; + let right = right_range.map(|right_range| SplitInfo::new(right_range, text_box_info)); - let right_box = right_range.map(|right_range| { - let new_text_box_info = ScannedTextBoxInfo::new(text_box_info.run.clone(), right_range); - let width = new_text_box_info.run.advance_for_range(&right_range); - let height = self.border_box.size.height; - let size = Size2D(width, height); - (self.transform(size, ScannedTextBox(new_text_box_info))) - }); - - Some((left_box, right_box)) + Some((left, right, text_box_info.run.clone())) } } } diff --git a/src/components/main/layout/inline.rs b/src/components/main/layout/inline.rs index 58e21329f95..4879bd8a5e7 100644 --- a/src/components/main/layout/inline.rs +++ b/src/components/main/layout/inline.rs @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use css::node_style::StyledNode; -use layout::box_::Box; +use layout::box_::{Box, ScannedTextBox, ScannedTextBoxInfo, SplitInfo}; use layout::context::LayoutContext; use layout::floats::{FloatLeft, Floats, PlacementInfo}; use layout::flow::{BaseFlow, FlowClass, Flow, InlineFlowClass}; @@ -419,18 +419,35 @@ impl LineboxScanner { fn try_append_to_line_by_new_line(&mut self, in_box: Box) -> bool { if in_box.new_line_pos.len() == 0 { - // In case of box does not include new-line character + debug!("LineboxScanner: Did not find a new-line character, so pushing the box to \ + the line without splitting."); self.push_box_to_line(in_box); true } else { - // In case of box includes new-line character - match in_box.split_by_new_line() { - Some((left_box, Some(right_box))) => { - self.push_box_to_line(left_box); - self.work_list.push_front(right_box); - }, - Some((left_box, None)) => { - self.push_box_to_line(left_box); + debug!("LineboxScanner: Found a new-line character, so splitting theline."); + match in_box.find_split_info_by_new_line() { + Some((left, right, run)) => { + // TODO(bjz): Remove box splitting + let split_box = |split: SplitInfo| { + let info = ScannedTextBoxInfo::new(run.clone(), split.range); + let specific = ScannedTextBox(info); + let size = Size2D(split.width, in_box.border_box.size.height); + in_box.transform(size, specific) + }; + + debug!("LineboxScanner: Pushing the box to the left of the new-line character \ + to the line."); + let mut left = split_box(left); + left.new_line_pos = vec!(); + self.push_box_to_line(left); + + for right in right.move_iter() { + debug!("LineboxScanner: Deferring the box to the right of the new-line \ + character to the line."); + let mut right = split_box(right); + right.new_line_pos = in_box.new_line_pos.clone(); + self.work_list.push_front(right); + } }, None => { error!("LineboxScanner: This split case makes no sense!") @@ -492,7 +509,19 @@ impl LineboxScanner { } let available_width = green_zone.width - self.pending_line.bounds.size.width; - match in_box.split_to_width(available_width, line_is_empty) { + let split = in_box.find_split_info_for_width(CharIndex(0), available_width, line_is_empty); + match split.map(|(left, right, run)| { + // TODO(bjz): Remove box splitting + let split_box = |split: SplitInfo| { + let info = ScannedTextBoxInfo::new(run.clone(), split.range); + let specific = ScannedTextBox(info); + let size = Size2D(split.width, in_box.border_box.size.height); + in_box.transform(size, specific) + }; + + (left.map(|x| { debug!("LineboxScanner: Left split {}", x); split_box(x) }), + right.map(|x| { debug!("LineboxScanner: Right split {}", x); split_box(x) })) + }) { None => { debug!("LineboxScanner: Tried to split unsplittable render box! Deferring to next \ line. {}", in_box); |