mirror of
https://github.com/servo/servo.git
synced 2025-08-07 06:25:32 +01:00
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?
This commit is contained in:
commit
65d91e3950
2 changed files with 85 additions and 50 deletions
|
@ -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
|
/// Data for an unscanned text box. Unscanned text boxes are the results of flow construction that
|
||||||
/// have not yet had their width determined.
|
/// have not yet had their width determined.
|
||||||
#[deriving(Clone)]
|
#[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.
|
/// A return value of `None` indicates that the box is not splittable.
|
||||||
/// Otherwise the split boxes are returned. The right boxe is optional due
|
/// Otherwise the split information is returned. The right information is
|
||||||
/// to the possibility of it being whitespace.
|
/// optional due to the possibility of it being whitespace.
|
||||||
pub fn split_by_new_line(&self) -> Option<(Box, Option<Box>)> {
|
//
|
||||||
|
// 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 {
|
match self.specific {
|
||||||
GenericBox | IframeBox(_) | ImageBox(_) | TableBox | TableCellBox |
|
GenericBox | IframeBox(_) | ImageBox(_) | TableBox | TableCellBox |
|
||||||
TableRowBox | TableWrapperBox => None,
|
TableRowBox | TableWrapperBox => None,
|
||||||
|
@ -1107,36 +1128,32 @@ impl Box {
|
||||||
text_box_info.range.length() - (cur_new_line_pos + CharIndex(1)));
|
text_box_info.range.length() - (cur_new_line_pos + CharIndex(1)));
|
||||||
|
|
||||||
// Left box is for left text of first founded new-line character.
|
// Left box is for left text of first founded new-line character.
|
||||||
let left_box = {
|
let left_box = SplitInfo::new(left_range, text_box_info);
|
||||||
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
|
|
||||||
};
|
|
||||||
|
|
||||||
// Right box is for right text of first founded new-line character.
|
// Right box is for right text of first founded new-line character.
|
||||||
let right_box = if right_range.length() > CharIndex(0) {
|
let right_box = if right_range.length() > CharIndex(0) {
|
||||||
let new_text_box_info = ScannedTextBoxInfo::new(text_box_info.run.clone(), right_range);
|
Some(SplitInfo::new(right_range, text_box_info))
|
||||||
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)
|
|
||||||
} else {
|
} else {
|
||||||
None
|
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.
|
/// 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
|
/// Otherwise the information pertaining to the split is returned. The left
|
||||||
/// optional due to the possibility of them being whitespace.
|
/// and right split information are both optional due to the possibility of
|
||||||
pub fn split_to_width(&self, max_width: Au, starts_line: bool) -> Option<(Option<Box>, Option<Box>)> {
|
/// 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 {
|
match self.specific {
|
||||||
GenericBox | IframeBox(_) | ImageBox(_) | TableBox | TableCellBox |
|
GenericBox | IframeBox(_) | ImageBox(_) | TableBox | TableCellBox |
|
||||||
TableRowBox | TableWrapperBox => None,
|
TableRowBox | TableWrapperBox => None,
|
||||||
|
@ -1145,7 +1162,7 @@ impl Box {
|
||||||
ScannedTextBox(ref text_box_info) => {
|
ScannedTextBox(ref text_box_info) => {
|
||||||
let mut pieces_processed_count: uint = 0;
|
let mut pieces_processed_count: uint = 0;
|
||||||
let mut remaining_width: Au = max_width;
|
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;
|
let mut right_range: Option<Range<CharIndex>> = None;
|
||||||
|
|
||||||
debug!("split_to_width: splitting text box (strlen={:u}, range={}, \
|
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 {
|
if (pieces_processed_count == 1 || !left_is_some) && !starts_line {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
let left_box = if left_is_some {
|
let left = if left_is_some {
|
||||||
let new_text_box_info = ScannedTextBoxInfo::new(text_box_info.run.clone(), left_range);
|
Some(SplitInfo::new(left_range, text_box_info))
|
||||||
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)))
|
|
||||||
} else {
|
} 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| {
|
Some((left, right, text_box_info.run.clone()))
|
||||||
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))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use css::node_style::StyledNode;
|
use css::node_style::StyledNode;
|
||||||
use layout::box_::Box;
|
use layout::box_::{Box, ScannedTextBox, ScannedTextBoxInfo, SplitInfo};
|
||||||
use layout::context::LayoutContext;
|
use layout::context::LayoutContext;
|
||||||
use layout::floats::{FloatLeft, Floats, PlacementInfo};
|
use layout::floats::{FloatLeft, Floats, PlacementInfo};
|
||||||
use layout::flow::{BaseFlow, FlowClass, Flow, InlineFlowClass};
|
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 {
|
fn try_append_to_line_by_new_line(&mut self, in_box: Box) -> bool {
|
||||||
if in_box.new_line_pos.len() == 0 {
|
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);
|
self.push_box_to_line(in_box);
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
// In case of box includes new-line character
|
debug!("LineboxScanner: Found a new-line character, so splitting theline.");
|
||||||
match in_box.split_by_new_line() {
|
match in_box.find_split_info_by_new_line() {
|
||||||
Some((left_box, Some(right_box))) => {
|
Some((left, right, run)) => {
|
||||||
self.push_box_to_line(left_box);
|
// TODO(bjz): Remove box splitting
|
||||||
self.work_list.push_front(right_box);
|
let split_box = |split: SplitInfo| {
|
||||||
},
|
let info = ScannedTextBoxInfo::new(run.clone(), split.range);
|
||||||
Some((left_box, None)) => {
|
let specific = ScannedTextBox(info);
|
||||||
self.push_box_to_line(left_box);
|
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 => {
|
None => {
|
||||||
error!("LineboxScanner: This split case makes no sense!")
|
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;
|
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 => {
|
None => {
|
||||||
debug!("LineboxScanner: Tried to split unsplittable render box! Deferring to next \
|
debug!("LineboxScanner: Tried to split unsplittable render box! Deferring to next \
|
||||||
line. {}", in_box);
|
line. {}", in_box);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue