mirror of
https://github.com/servo/servo.git
synced 2025-08-06 22:15:33 +01:00
auto merge of #2471 : bjz/servo/split-to-width, r=pcwalton
@pcwalton r?
This commit is contained in:
commit
614b1f2fe6
5 changed files with 121 additions and 87 deletions
|
@ -267,16 +267,6 @@ impl UnscannedTextBoxInfo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents the outcome of attempting to split a box.
|
|
||||||
pub enum SplitBoxResult {
|
|
||||||
CannotSplit,
|
|
||||||
// in general, when splitting the left or right side can
|
|
||||||
// be zero length, due to leading/trailing trimmable whitespace
|
|
||||||
SplitDidFit(Option<Box>, Option<Box>),
|
|
||||||
SplitDidNotFit(Option<Box>, Option<Box>)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// A box that represents a table column.
|
/// A box that represents a table column.
|
||||||
#[deriving(Clone)]
|
#[deriving(Clone)]
|
||||||
pub struct TableColumnBoxInfo {
|
pub struct TableColumnBoxInfo {
|
||||||
|
@ -1097,11 +1087,15 @@ impl Box {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Split box which includes new-line character
|
/// Split box which includes new-line character.
|
||||||
pub fn split_by_new_line(&self) -> SplitBoxResult {
|
///
|
||||||
|
/// 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>)> {
|
||||||
match self.specific {
|
match self.specific {
|
||||||
GenericBox | IframeBox(_) | ImageBox(_) | TableBox | TableCellBox |
|
GenericBox | IframeBox(_) | ImageBox(_) | TableBox | TableCellBox |
|
||||||
TableRowBox | TableWrapperBox => CannotSplit,
|
TableRowBox | TableWrapperBox => None,
|
||||||
TableColumnBox(_) => fail!("Table column boxes do not need to split"),
|
TableColumnBox(_) => fail!("Table column boxes do not need to split"),
|
||||||
UnscannedTextBox(_) => fail!("Unscanned text boxes should have been scanned by now!"),
|
UnscannedTextBox(_) => fail!("Unscanned text boxes should have been scanned by now!"),
|
||||||
ScannedTextBox(ref text_box_info) => {
|
ScannedTextBox(ref text_box_info) => {
|
||||||
|
@ -1118,7 +1112,7 @@ impl Box {
|
||||||
let new_metrics = new_text_box_info.run.metrics_for_range(&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));
|
let mut new_box = self.transform(new_metrics.bounding_box.size, ScannedTextBox(new_text_box_info));
|
||||||
new_box.new_line_pos = vec!();
|
new_box.new_line_pos = vec!();
|
||||||
Some(new_box)
|
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.
|
||||||
|
@ -1132,16 +1126,20 @@ impl Box {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
SplitDidFit(left_box, right_box)
|
Some((left_box, right_box))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempts to split this box so that its width is no more than `max_width`.
|
/// Attempts to split this box so that its width is no more than `max_width`.
|
||||||
pub fn split_to_width(&self, max_width: Au, starts_line: bool) -> SplitBoxResult {
|
///
|
||||||
|
/// 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>)> {
|
||||||
match self.specific {
|
match self.specific {
|
||||||
GenericBox | IframeBox(_) | ImageBox(_) | TableBox | TableCellBox |
|
GenericBox | IframeBox(_) | ImageBox(_) | TableBox | TableCellBox |
|
||||||
TableRowBox | TableWrapperBox => CannotSplit,
|
TableRowBox | TableWrapperBox => None,
|
||||||
TableColumnBox(_) => fail!("Table column boxes do not have width"),
|
TableColumnBox(_) => fail!("Table column boxes do not have width"),
|
||||||
UnscannedTextBox(_) => fail!("Unscanned text boxes should have been scanned by now!"),
|
UnscannedTextBox(_) => fail!("Unscanned text boxes should have been scanned by now!"),
|
||||||
ScannedTextBox(ref text_box_info) => {
|
ScannedTextBox(ref text_box_info) => {
|
||||||
|
@ -1214,28 +1212,30 @@ impl Box {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let left_box = if left_range.length() > CharIndex(0) {
|
let left_is_some = left_range.length() > CharIndex(0);
|
||||||
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);
|
if (pieces_processed_count == 1 || !left_is_some) && !starts_line {
|
||||||
let height = self.border_box.size.height;
|
|
||||||
let size = Size2D(width, height);
|
|
||||||
Some(self.transform(size, ScannedTextBox(new_text_box_info)))
|
|
||||||
} else {
|
|
||||||
None
|
None
|
||||||
};
|
|
||||||
|
|
||||||
let right_box = right_range.map_or(None, |right_range: Range<CharIndex>| {
|
|
||||||
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);
|
|
||||||
Some(self.transform(size, ScannedTextBox(new_text_box_info)))
|
|
||||||
});
|
|
||||||
|
|
||||||
if pieces_processed_count == 1 || left_box.is_none() {
|
|
||||||
SplitDidNotFit(left_box, right_box)
|
|
||||||
} else {
|
} else {
|
||||||
SplitDidFit(left_box, right_box)
|
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)))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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, CannotSplit, SplitDidFit, SplitDidNotFit};
|
use layout::box_::Box;
|
||||||
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};
|
||||||
|
@ -425,19 +425,16 @@ impl LineboxScanner {
|
||||||
} else {
|
} else {
|
||||||
// In case of box includes new-line character
|
// In case of box includes new-line character
|
||||||
match in_box.split_by_new_line() {
|
match in_box.split_by_new_line() {
|
||||||
SplitDidFit(left, right) => {
|
Some((left_box, Some(right_box))) => {
|
||||||
match (left, right) {
|
self.push_box_to_line(left_box);
|
||||||
(Some(left_box), Some(right_box)) => {
|
self.work_list.push_front(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);
|
||||||
(Some(left_box), None) => {
|
},
|
||||||
self.push_box_to_line(left_box);
|
None => {
|
||||||
}
|
error!("LineboxScanner: This split case makes no sense!")
|
||||||
_ => error!("LineboxScanner: This split case makes no sense!"),
|
},
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
@ -495,46 +492,35 @@ 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;
|
||||||
let split = in_box.split_to_width(available_width, line_is_empty);
|
match in_box.split_to_width(available_width, line_is_empty) {
|
||||||
let (left, right) = match (split, line_is_empty) {
|
None => {
|
||||||
(CannotSplit, _) => {
|
debug!("LineboxScanner: Tried to split unsplittable render box! Deferring to next \
|
||||||
debug!("LineboxScanner: Tried to split unsplittable render box! {}",
|
line. {}", in_box);
|
||||||
in_box);
|
|
||||||
self.work_list.push_front(in_box);
|
self.work_list.push_front(in_box);
|
||||||
return false
|
false
|
||||||
}
|
},
|
||||||
(SplitDidNotFit(_, _), false) => {
|
Some((Some(left_box), Some(right_box))) => {
|
||||||
debug!("LineboxScanner: case=split box didn't fit, not appending and deferring \
|
debug!("LineboxScanner: Line break found! Pushing left box to line and deferring \
|
||||||
original box.");
|
right box to next line.");
|
||||||
self.work_list.push_front(in_box);
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
(SplitDidFit(left, right), _) => {
|
|
||||||
debug!("LineboxScanner: case=split box did fit; deferring remainder box.");
|
|
||||||
(left, right)
|
|
||||||
// Fall through to push boxes to the line.
|
|
||||||
}
|
|
||||||
(SplitDidNotFit(left, right), true) => {
|
|
||||||
// TODO(eatkinson, issue #224): Signal that horizontal overflow happened?
|
|
||||||
debug!("LineboxScanner: case=split box didn't fit and line {:u} is empty, so \
|
|
||||||
overflowing and deferring remainder box.",
|
|
||||||
self.lines.len());
|
|
||||||
(left, right)
|
|
||||||
// Fall though to push boxes to the line.
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
match (left, right) {
|
|
||||||
(Some(left_box), Some(right_box)) => {
|
|
||||||
self.push_box_to_line(left_box);
|
self.push_box_to_line(left_box);
|
||||||
self.work_list.push_front(right_box);
|
self.work_list.push_front(right_box);
|
||||||
}
|
true
|
||||||
(Some(left_box), None) => self.push_box_to_line(left_box),
|
},
|
||||||
(None, Some(right_box)) => self.push_box_to_line(right_box),
|
Some((Some(left_box), None)) => {
|
||||||
(None, None) => error!("LineboxScanner: This split case makes no sense!"),
|
debug!("LineboxScanner: Pushing left box to line.");
|
||||||
|
self.push_box_to_line(left_box);
|
||||||
|
true
|
||||||
|
},
|
||||||
|
Some((None, Some(right_box))) => {
|
||||||
|
debug!("LineboxScanner: Pushing right box to line.");
|
||||||
|
self.push_box_to_line(right_box);
|
||||||
|
true
|
||||||
|
},
|
||||||
|
Some((None, None)) => {
|
||||||
|
error!("LineboxScanner: This split case makes no sense!");
|
||||||
|
true
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// An unconditional push
|
// An unconditional push
|
||||||
|
|
|
@ -73,3 +73,4 @@
|
||||||
== setattribute_id_restyle_a.html setattribute_id_restyle_b.html
|
== setattribute_id_restyle_a.html setattribute_id_restyle_b.html
|
||||||
== pseudo_element_a.html pseudo_element_b.html
|
== pseudo_element_a.html pseudo_element_b.html
|
||||||
== linebreak_simple_a.html linebreak_simple_b.html
|
== linebreak_simple_a.html linebreak_simple_b.html
|
||||||
|
== linebreak_inline_span_a.html linebreak_inline_span_b.html
|
||||||
|
|
24
src/test/ref/linebreak_inline_span_a.html
Normal file
24
src/test/ref/linebreak_inline_span_a.html
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style type="text/css">
|
||||||
|
* {
|
||||||
|
margin: 0px;
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<blockquote>
|
||||||
|
The <span>most terrifying</span> fact about the universe <span>is not that
|
||||||
|
it is hostile but that it is indifferent;</span> but if we can come to terms
|
||||||
|
with this indifference and accept the<span> challenges</span> of <span>life
|
||||||
|
<span>within</span></span> the boundaries of death - <span>however</span>
|
||||||
|
mutable man may be able to make them - our existence as a species can have
|
||||||
|
genuine meaning and fulfillment. However vast the darkness, we must supply
|
||||||
|
our own light.
|
||||||
|
<footer>
|
||||||
|
<cite>Stanley Kubrick</cite>
|
||||||
|
</footer>
|
||||||
|
</blockquote>
|
||||||
|
</body>
|
||||||
|
</html>
|
23
src/test/ref/linebreak_inline_span_b.html
Normal file
23
src/test/ref/linebreak_inline_span_b.html
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style type="text/css">
|
||||||
|
* {
|
||||||
|
margin: 0px;
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<blockquote>
|
||||||
|
The most terrifying fact about the universe is not that it is hostile but
|
||||||
|
that it is indifferent; but if we can come to terms with this indifference
|
||||||
|
and accept the challenges of life within the boundaries of death - however
|
||||||
|
mutable man may be able to make them - our existence as a species can have
|
||||||
|
genuine meaning and fulfillment. However vast the darkness, we must supply
|
||||||
|
our own light.
|
||||||
|
<footer>
|
||||||
|
<cite>Stanley Kubrick</cite>
|
||||||
|
</footer>
|
||||||
|
</blockquote>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Add table
Add a link
Reference in a new issue