aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbors-servo <release+servo@mozilla.com>2014-05-27 18:16:09 -0400
committerbors-servo <release+servo@mozilla.com>2014-05-27 18:16:09 -0400
commit65d91e395002106ce263f5ccb188eb384963768a (patch)
tree33f21314ca6a43466500e2a5baf00f4d30eb0d01
parent0886a36b5d5c1b08a128b62933f206f66561d7f6 (diff)
parenta944e378eb33d05528971e19234761ed2aadbfdb (diff)
downloadservo-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_.rs84
-rw-r--r--src/components/main/layout/inline.rs51
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);